[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": ".gitconfig\n.git-credentials\n\n# Ignore iOS Framework binarie\nFrameworks/\n\n# Ignore OpenSSL and Boost build files for iOS\n\n.gitk\n.config/git/gitk\n\n**/.vs/\n**/project.lock.json\n\nCasablanca*/Build_iOS/OpenSSL-for-iPhone/\nCasablanca*/Build_iOS/boostoniphone/\nCasablanca*/Build_iOS/openssl/\nCasablanca*/Build_iOS/boost.framework/\nCasablanca*/Build_iOS/build.ios/\nCasablanca*/Build_iOS/ios-cmake/\n\n#nuget packages\nExternal/Packages/*\n\n#mobile\nExternal/sdk.mobile\n\n# Xcode - from github\n## User settings\nxcuserdata\n\n## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)\n*.xcscmblueprint\n*.xccheckout\n\n## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)\nbuild/\nDerivedData/\n*.moved-aside\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\n\n# Mac\n\n.DS_Store\n\n# VS temp files\n**/*.sln.ide/\n**/*.opensdf\n**/*.sdf\n**/*.suo\n**/*.opendb\n**/*.VC.db\n**/*.user\n**/ipch/\n**/Generated Files/\n**/AppPackages/*\n**/*.orig\n**/pingme.txt\n**/*.cache\n**/dlldata.c\n**/*_i.c\n**/*_p.c\n**/*.metaproj\n**/*.metaproj.tmp\n**/*.opendb\n**/*.coveragexml\n\n**/Durango/\n**/Gaming.Xbox.Desktop.x64/\n**/Gaming.Xbox.XboxOne.x64/\n**/Gaming.Xbox.Scarlett.x64/\n**/XboxOne.x64/\nSamples/**/bin/\nSamples/**/Debug/\nSamples/**/Release/\nSamples/**/Profile/\nSamples/**/Lib/\nSamples/**/.workspace/\nSource/**/bin/\nSource/**/gen/\nSource/**/Debug/\nSource/**/Release/\nArchive/**/Debug/\nArchive/**/Release/\nArchive/**/Durango/\nArchive/**/Lib/\nArchive/**/*.winmd\nBuild/**/Debug/\nBuild/**/Release/\nExternal/**/lib/\n!External/xal/External/OneDS/lib/\nExternal/**/bin/\nExternal/**/Debug/\nExternal/**/Release/\ntests/**/bin/\ntests/**/Debug/\ntests/**/Release/\nTools/**/bin/\nTools/**/obj/\n**/*.classpath\nAPIExplorer.Win32.PrebuiltBins.sln\n\n**/local.properties\n\n**/.workspace/\n\n#Doxygen temp files\nDocs/xblsdk_cpp/\nDocs/xblsdk_winrt/\nDocs/External/\nDocs/xim_cpp/\n\n# Unit Test\nFakesAssemblies/\nTestResults/\n\n# Build objects\n\nCasablanca/Intermediate/\nObj/\nBinaries/\nDebug/\nRelease/\nARM/\nBuilt/\nBins/\n\n# Allow files in our /Build folder\n!/Build\n!/Casablanca\n\n\n**/.vs/\n\nxbox-live-samples/\nTests/StressUnitTest/\n*.pdb\n\nMaven/\noutput/\nClockSkew.json\n\n.idea\n*.iml\n.externalNativeBuild\n\n**/XblEvents*.json\n**/XblEvents*.dir\n\nTests/AndroidTestApp/MavenBinary/*\nTests/APIExplorer/XDK/Kits/DirectXTK/Src/Shaders/Compiled/*\n\nMicrosoft.Xbox.Services.*.sln.log\nMicrosoft.Xbox.Services.*.sln.out\n**/apirunner-log.txt\n\n# Android and Android Studio files\n**/.idea\n**/*.iml\n**/.cxx\n**/local.properties\n**/.gradle/*\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"External/Xal/External/libHttpClient\"]\n\tpath = External/Xal/External/libHttpClient\n\turl = https://github.com/microsoft/libHttpClient\n[submodule \"External/rapidjson\"]\n\tpath = External/rapidjson\n\turl = https://github.com/jasonsandlin/rapidjson\n"
  },
  {
    "path": "Build/GetXsapiAndroidBinaryDir.cmake",
    "content": "cmake_minimum_required(VERSION 3.6)\n\nfunction(GET_XSAPI_ANDROID_BINARY_DIR PATH_TO_ROOT OUT_BINARY_DIR)\n    string(TOLOWER \"${CMAKE_BUILD_TYPE}\" PATH_FLAVOR)\n    set(${OUT_BINARY_DIR} \"${PATH_TO_ROOT}/Built/Android/${ANDROID_ABI}/${PATH_FLAVOR}\" PARENT_SCOPE)\nendfunction()\n"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C/Microsoft.Xbox.Services.141.GDK.C.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{60139F62-BF37-4F11-BD93-5FBF4E92100C}</ProjectGuid>\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <XsapiImpl>true</XsapiImpl>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug'\">\n    <TargetName>Microsoft.Xbox.Services.141.GDK.C.$(Configuration)</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <TargetName>Microsoft.Xbox.Services.141.GDK.C</TargetName>\n  </PropertyGroup>\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove(xsapi.gdk.props))\" />\n  <Import Project=\"$(XsapiSourceRoot)\\xsapi.staticlib.props\" />\n  <Import Project=\"$(XsapiSourceRoot)\\Build\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems\" Label=\"Shared\" />\n  <Import Project=\"$(XsapiSourceRoot)\\Build\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems\" Label=\"Shared\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/Microsoft.Xbox.Services.141.GDK.C.Thunks.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{e538394b-68cb-4597-87ad-7b6841cc1278}</ProjectGuid>\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <XsapiLibBuildFromSource>true</XsapiLibBuildFromSource>\n    <LibHttpClientBuildFromSource>true</LibHttpClientBuildFromSource>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug'\">\n    <TargetName>Microsoft.Xbox.Services.141.GDK.C.Thunks.$(Configuration)</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <TargetName>Microsoft.Xbox.Services.141.GDK.C.Thunks</TargetName>\n  </PropertyGroup>\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove(xsapi.gdk.props))\" />\n  <Import Project=\"$(XsapiSourceRoot)\\xsapi.staticlib.props\" />\n  <ItemGroup>\n    <ClCompile Include=\"dll\\dllmain.cpp\" />\n    <ClCompile Include=\"dll\\pch.cpp\" >\n      <PrecompiledHeader>Create</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"dll\\Microsoft.Xbox.Services.141.GDK.C.Thunks.def\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"dll\\pch.h\" />\n  </ItemGroup>\n  <ItemDefinitionGroup>\n    <Link>\n      <AdditionalDependencies>%(XboxExtensionsDependencies)Appnotify.lib;crypt32.lib;xgameruntime.lib;WINHTTP.LIB;RUNTIMEOBJECT.LIB;ADVAPI32.LIB;ole32.lib;</AdditionalDependencies>\n      <ModuleDefinitionFile>$(ProjectDir)dll\\Microsoft.Xbox.Services.141.GDK.C.Thunks.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/Microsoft.Xbox.Services.141.GDK.C.Thunks.vcxproj.filters",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"dll\\dllmain.cpp\" />\n    <ClCompile Include=\"dll\\pch.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"dll\\Microsoft.Xbox.Services.141.GDK.C.Thunks.def\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"dll\\pch.h\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/dll/Microsoft.Xbox.Services.141.GDK.C.Thunks.def",
    "content": "LIBRARY Microsoft.Xbox.Services.141.GDK.C.Thunks.dll\nEXPORTS\n    XblAchievementsGetAchievementAsync\n    XblAchievementsGetAchievementResult\n    XblAchievementsGetAchievementsForTitleIdAsync\n    XblAchievementsGetAchievementsForTitleIdResult\n    XblAchievementsResultCloseHandle\n    XblAchievementsResultDuplicateHandle\n    XblAchievementsResultGetAchievements\n    XblAchievementsResultGetNextAsync\n    XblAchievementsResultGetNextResult\n    XblAchievementsResultHasNext\n    XblAchievementsUpdateAchievementAsync\n    XblAchievementsUpdateAchievementForTitleIdAsync\n    XblAddServiceCallRoutedHandler\n    XblCleanupAsync\n    XblContextCloseHandle\n    XblContextCreateHandle\n    XblContextDuplicateHandle\n    XblContextGetUser\n    XblContextGetXboxUserId\n    XblContextSettingsGetHttpRetryDelay\n    XblContextSettingsGetHttpTimeoutWindow\n    XblContextSettingsGetLongHttpTimeout\n    XblContextSettingsGetUseCrossPlatformQosServers\n    XblContextSettingsGetWebsocketTimeoutWindow\n    XblContextSettingsSetHttpRetryDelay\n    XblContextSettingsSetHttpTimeoutWindow\n    XblContextSettingsSetLongHttpTimeout\n    XblContextSettingsSetUseCrossPlatformQosServers\n    XblContextSettingsSetWebsocketTimeoutWindow\n    XblDisableAssertsForXboxLiveThrottlingInDevSandboxes\n    XblEventsWriteInGameEvent\n    XblFormatSecureDeviceAddress\n    XblGetAsyncQueue\n    XblGetErrorCondition\n    XblGetScid\n    XblHttpCallCloseHandle\n    XblHttpCallCreate\n    XblHttpCallDuplicateHandle\n    XblHttpCallGetHeader\n    XblHttpCallGetHeaderAtIndex\n    XblHttpCallGetNetworkErrorCode\n    XblHttpCallGetNumHeaders\n    XblHttpCallGetPlatformNetworkErrorMessage\n    XblHttpCallGetRequestUrl\n    XblHttpCallGetResponseBodyBytes\n    XblHttpCallGetResponseBodyBytesSize\n    XblHttpCallGetResponseString\n    XblHttpCallGetStatusCode\n    XblHttpCallPerformAsync\n    XblHttpCallRequestSetHeader\n    XblHttpCallRequestSetLongHttpCall\n    XblHttpCallRequestSetRequestBodyBytes\n    XblHttpCallRequestSetRequestBodyString\n    XblHttpCallRequestSetRetryAllowed\n    XblHttpCallRequestSetRetryCacheId\n    XblHttpCallSetTracing\n    XblInitialize\n    XblLeaderboardGetLeaderboardAsync\n    XblLeaderboardGetLeaderboardResult\n    XblLeaderboardGetLeaderboardResultSize\n    XblLeaderboardResultGetNextAsync\n    XblLeaderboardResultGetNextResult\n    XblLeaderboardResultGetNextResultSize\n    XblMatchmakingCreateMatchTicketAsync\n    XblMatchmakingCreateMatchTicketResult\n    XblMatchmakingDeleteMatchTicketAsync\n    XblMatchmakingGetHopperStatisticsAsync\n    XblMatchmakingGetHopperStatisticsResult\n    XblMatchmakingGetHopperStatisticsResultSize\n    XblMatchmakingGetMatchTicketDetailsAsync\n    XblMatchmakingGetMatchTicketDetailsResult\n    XblMatchmakingGetMatchTicketDetailsResultSize\n    XblMemGetFunctions\n    XblMemSetFunctions\n    XblMultiplayerActivityDeleteActivityAsync\n    XblMultiplayerActivityFlushRecentPlayersAsync\n    XblMultiplayerActivityGetActivityAsync\n    XblMultiplayerActivityGetActivityResult\n    XblMultiplayerActivityGetActivityResultSize\n    XblMultiplayerActivitySendInvitesAsync\n    XblMultiplayerActivitySetActivityAsync\n    XblMultiplayerActivityUpdateRecentPlayers\n    XblMultiplayerAddConnectionIdChangedHandler\n    XblMultiplayerAddSessionChangedHandler\n    XblMultiplayerAddSubscriptionLostHandler\n    XblMultiplayerClearActivityAsync\n    XblMultiplayerCreateSearchHandleAsync\n    XblMultiplayerCreateSearchHandleResult\n    XblMultiplayerDeleteSearchHandleAsync\n    XblMultiplayerEventArgsFindMatchCompleted\n    XblMultiplayerEventArgsMember\n    XblMultiplayerEventArgsMembers\n    XblMultiplayerEventArgsMembersCount\n    XblMultiplayerEventArgsPerformQoSMeasurements\n    XblMultiplayerEventArgsPropertiesJson\n    XblMultiplayerEventArgsTournamentGameSessionReady\n    XblMultiplayerEventArgsTournamentRegistrationStateChanged\n    XblMultiplayerEventArgsXuid\n    XblMultiplayerGetActivitiesForSocialGroupAsync\n    XblMultiplayerGetActivitiesForSocialGroupResult\n    XblMultiplayerGetActivitiesForSocialGroupResultCount\n    XblMultiplayerGetActivitiesForUsersAsync\n    XblMultiplayerGetActivitiesForUsersResult\n    XblMultiplayerGetActivitiesForUsersResultCount\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize\n    XblMultiplayerGetActivitiesWithPropertiesForUsersAsync\n    XblMultiplayerGetActivitiesWithPropertiesForUsersResult\n    XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize\n    XblMultiplayerGetSearchHandlesAsync\n    XblMultiplayerGetSearchHandlesResult\n    XblMultiplayerGetSearchHandlesResultCount\n    XblMultiplayerGetSessionAsync\n    XblMultiplayerGetSessionByHandleAsync\n    XblMultiplayerGetSessionByHandleResult\n    XblMultiplayerGetSessionResult\n    XblMultiplayerManagerAutoFillMembersDuringMatchmaking\n    XblMultiplayerManagerCancelMatch\n    XblMultiplayerManagerDoWork\n    XblMultiplayerManagerEstimatedMatchWaitTime\n    XblMultiplayerManagerFindMatch\n    XblMultiplayerManagerGameSessionActive\n    XblMultiplayerManagerGameSessionConstants\n    XblMultiplayerManagerGameSessionCorrelationId\n    XblMultiplayerManagerGameSessionHost\n    XblMultiplayerManagerGameSessionIsHost\n    XblMultiplayerManagerGameSessionMembers\n    XblMultiplayerManagerGameSessionMembersCount\n    XblMultiplayerManagerGameSessionPropertiesJson\n    XblMultiplayerManagerGameSessionSessionReference\n    XblMultiplayerManagerGameSessionSetProperties\n    XblMultiplayerManagerGameSessionSetSynchronizedHost\n    XblMultiplayerManagerGameSessionSetSynchronizedProperties\n    XblMultiplayerManagerInitialize\n    XblMultiplayerManagerJoinability\n    XblMultiplayerManagerJoinGame\n    XblMultiplayerManagerJoinGameFromLobby\n    XblMultiplayerManagerJoinLobby\n    XblMultiplayerManagerLeaveGame\n    XblMultiplayerManagerLobbySessionAddLocalUser\n    XblMultiplayerManagerLobbySessionConstants\n    XblMultiplayerManagerLobbySessionCorrelationId\n    XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties\n    XblMultiplayerManagerLobbySessionHost\n    XblMultiplayerManagerLobbySessionInviteFriends\n    XblMultiplayerManagerLobbySessionInviteUsers\n    XblMultiplayerManagerLobbySessionIsHost\n    XblMultiplayerManagerLobbySessionLastTournamentTeamResult\n    XblMultiplayerManagerLobbySessionLocalMembers\n    XblMultiplayerManagerLobbySessionLocalMembersCount\n    XblMultiplayerManagerLobbySessionMembers\n    XblMultiplayerManagerLobbySessionMembersCount\n    XblMultiplayerManagerLobbySessionPropertiesJson\n    XblMultiplayerManagerLobbySessionRemoveLocalUser\n    XblMultiplayerManagerLobbySessionSessionReference\n    XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress\n    XblMultiplayerManagerLobbySessionSetLocalMemberProperties\n    XblMultiplayerManagerLobbySessionSetProperties\n    XblMultiplayerManagerLobbySessionSetSynchronizedHost\n    XblMultiplayerManagerLobbySessionSetSynchronizedProperties\n    XblMultiplayerManagerMatchStatus\n    XblMultiplayerManagerMemberAreMembersOnSameDevice\n    XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\n    XblMultiplayerManagerSetJoinability\n    XblMultiplayerManagerSetQosMeasurements\n    XblMultiplayerQuerySessionsAsync\n    XblMultiplayerQuerySessionsResult\n    XblMultiplayerQuerySessionsResultCount\n    XblMultiplayerRemoveConnectionIdChangedHandler\n    XblMultiplayerRemoveSessionChangedHandler\n    XblMultiplayerRemoveSubscriptionLostHandler\n    XblMultiplayerSearchHandleCloseHandle\n    XblMultiplayerSearchHandleDuplicateHandle\n    XblMultiplayerSearchHandleGetCreationTime\n    XblMultiplayerSearchHandleGetCustomSessionPropertiesJson\n    XblMultiplayerSearchHandleGetId\n    XblMultiplayerSearchHandleGetJoinRestriction\n    XblMultiplayerSearchHandleGetMemberCounts\n    XblMultiplayerSearchHandleGetNumberAttributes\n    XblMultiplayerSearchHandleGetSessionClosed\n    XblMultiplayerSearchHandleGetSessionOwnerXuids\n    XblMultiplayerSearchHandleGetSessionReference\n    XblMultiplayerSearchHandleGetStringAttributes\n    XblMultiplayerSearchHandleGetTags\n    XblMultiplayerSearchHandleGetVisibility\n    XblMultiplayerSendInvitesAsync\n    XblMultiplayerSendInvitesResult\n    XblMultiplayerSessionAddMemberReservation\n    XblMultiplayerSessionArbitrationServer\n    XblMultiplayerSessionArbitrationStatus\n    XblMultiplayerSessionCloseHandle\n    XblMultiplayerSessionCompare\n    XblMultiplayerSessionConstantsSetArbitrationTimeouts\n    XblMultiplayerSessionConstantsSetCapabilities\n    XblMultiplayerSessionConstantsSetCloudComputePackageJson\n    XblMultiplayerSessionConstantsSetMaxMembersInSession\n    XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson\n    XblMultiplayerSessionConstantsSetMemberInitialization\n    XblMultiplayerSessionConstantsSetPeerToHostRequirements\n    XblMultiplayerSessionConstantsSetPeerToPeerRequirements\n    XblMultiplayerSessionConstantsSetQosConnectivityMetrics\n    XblMultiplayerSessionConstantsSetTimeouts\n    XblMultiplayerSessionConstantsSetVisibility\n    XblMultiplayerSessionCreateHandle\n    XblMultiplayerSessionCurrentUser\n    XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson\n    XblMultiplayerSessionCurrentUserSetCustomPropertyJson\n    XblMultiplayerSessionCurrentUserSetEncounters\n    XblMultiplayerSessionCurrentUserSetGroups\n    XblMultiplayerSessionCurrentUserSetMembersInGroup\n    XblMultiplayerSessionCurrentUserSetQosMeasurements\n    XblMultiplayerSessionCurrentUserSetRoles\n    XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64\n    XblMultiplayerSessionCurrentUserSetServerQosMeasurements\n    XblMultiplayerSessionCurrentUserSetStatus\n    XblMultiplayerSessionDeleteCustomPropertyJson\n    XblMultiplayerSessionDuplicateHandle\n    XblMultiplayerSessionEtag\n    XblMultiplayerSessionGetInfo\n    XblMultiplayerSessionGetInitializationInfo\n    XblMultiplayerSessionGetMember\n    XblMultiplayerSessionGetRoleByName\n    XblMultiplayerSessionHostCandidates\n    XblMultiplayerSessionJoin\n    XblMultiplayerSessionLeave\n    XblMultiplayerSessionMatchmakingServer\n    XblMultiplayerSessionMembers\n    XblMultiplayerSessionMembersAccepted\n    XblMultiplayerSessionPropertiesSetJoinRestriction\n    XblMultiplayerSessionPropertiesSetKeywords\n    XblMultiplayerSessionPropertiesSetReadRestriction\n    XblMultiplayerSessionPropertiesSetTurnCollection\n    XblMultiplayerSessionRawServersJson\n    XblMultiplayerSessionReferenceCreate\n    XblMultiplayerSessionReferenceIsValid\n    XblMultiplayerSessionReferenceParseFromUriPath\n    XblMultiplayerSessionReferenceToUriPath\n    XblMultiplayerSessionRoleTypes\n    XblMultiplayerSessionSessionConstants\n    XblMultiplayerSessionSessionProperties\n    XblMultiplayerSessionSessionReference\n    XblMultiplayerSessionSetAllocateCloudCompute\n    XblMultiplayerSessionSetClosed\n    XblMultiplayerSessionSetCustomPropertyJson\n    XblMultiplayerSessionSetHostDeviceToken\n    XblMultiplayerSessionSetInitializationSucceeded\n    XblMultiplayerSessionSetLocked\n    XblMultiplayerSessionSetMatchmakingResubmit\n    XblMultiplayerSessionSetMatchmakingServerConnectionPath\n    XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson\n    XblMultiplayerSessionSetMutableRoleSettings\n    XblMultiplayerSessionSetRawServersJson\n    XblMultiplayerSessionSetServerConnectionStringCandidates\n    XblMultiplayerSessionSetSessionChangeSubscription\n    XblMultiplayerSessionSubscribedChangeTypes\n    XblMultiplayerSessionTimeOfSession\n    XblMultiplayerSessionTournamentsServer\n    XblMultiplayerSessionWriteStatus\n    XblMultiplayerSetActivityAsync\n    XblMultiplayerSetSubscriptionsEnabled\n    XblMultiplayerSetTransferHandleAsync\n    XblMultiplayerSetTransferHandleResult\n    XblMultiplayerSubscriptionsEnabled\n    XblMultiplayerWriteSessionAsync\n    XblMultiplayerWriteSessionByHandleAsync\n    XblMultiplayerWriteSessionByHandleResult\n    XblMultiplayerWriteSessionResult\n    XblPresenceAddDevicePresenceChangedHandler\n    XblPresenceAddTitlePresenceChangedHandler\n    XblPresenceGetPresenceAsync\n    XblPresenceGetPresenceForMultipleUsersAsync\n    XblPresenceGetPresenceForMultipleUsersResult\n    XblPresenceGetPresenceForMultipleUsersResultCount\n    XblPresenceGetPresenceForSocialGroupAsync\n    XblPresenceGetPresenceForSocialGroupResult\n    XblPresenceGetPresenceForSocialGroupResultCount\n    XblPresenceGetPresenceResult\n    XblPresenceRecordCloseHandle\n    XblPresenceRecordDuplicateHandle\n    XblPresenceRecordGetDeviceRecords\n    XblPresenceRecordGetUserState\n    XblPresenceRecordGetXuid\n    XblPresenceRemoveDevicePresenceChangedHandler\n    XblPresenceRemoveTitlePresenceChangedHandler\n    XblPresenceSetPresenceAsync\n    XblPresenceSubscribeToDevicePresenceChange\n    XblPresenceSubscribeToTitlePresenceChange\n    XblPresenceUnsubscribeFromDevicePresenceChange\n    XblPresenceUnsubscribeFromTitlePresenceChange\n    XblPrivacyBatchCheckPermissionAsync\n    XblPrivacyBatchCheckPermissionResult\n    XblPrivacyBatchCheckPermissionResultSize\n    XblPrivacyCheckPermissionAsync\n    XblPrivacyCheckPermissionForAnonymousUserAsync\n    XblPrivacyCheckPermissionForAnonymousUserResult\n    XblPrivacyCheckPermissionForAnonymousUserResultSize\n    XblPrivacyCheckPermissionResult\n    XblPrivacyCheckPermissionResultSize\n    XblPrivacyGetAvoidListAsync\n    XblPrivacyGetAvoidListResult\n    XblPrivacyGetAvoidListResultCount\n    XblPrivacyGetMuteListAsync\n    XblPrivacyGetMuteListResult\n    XblPrivacyGetMuteListResultCount\n    XblProfileGetUserProfileAsync\n    XblProfileGetUserProfileResult\n    XblProfileGetUserProfilesAsync\n    XblProfileGetUserProfilesForSocialGroupAsync\n    XblProfileGetUserProfilesForSocialGroupResult\n    XblProfileGetUserProfilesForSocialGroupResultCount\n    XblProfileGetUserProfilesResult\n    XblProfileGetUserProfilesResultCount\n    XblRealTimeActivityActivate\n    XblRealTimeActivityAddConnectionStateChangeHandler\n    XblRealTimeActivityAddResyncHandler\n    XblRealTimeActivityAddSubscriptionErrorHandler\n    XblRealTimeActivityDeactivate\n    XblRealTimeActivityRemoveConnectionStateChangeHandler\n    XblRealTimeActivityRemoveResyncHandler\n    XblRealTimeActivityRemoveSubscriptionErrorHandler\n    XblRealTimeActivitySubscriptionGetId\n    XblRealTimeActivitySubscriptionGetState\n    XblRemoveServiceCallRoutedHandler\n    XblSetOverrideConfiguration\n    XblSocialAddSocialRelationshipChangedHandler\n    XblSocialGetSocialRelationshipsAsync\n    XblSocialGetSocialRelationshipsResult\n    XblSocialManagerAddLocalUser\n    XblSocialManagerCreateSocialUserGroupFromFilters\n    XblSocialManagerCreateSocialUserGroupFromList\n    XblSocialManagerDestroySocialUserGroup\n    XblSocialManagerDoWork\n    XblSocialManagerGetLocalUserCount\n    XblSocialManagerGetLocalUsers\n    XblSocialManagerPresenceRecordIsUserPlayingTitle\n    XblSocialManagerRemoveLocalUser\n    XblSocialManagerSetRichPresencePollingStatus\n    XblSocialManagerUpdateSocialUserGroup\n    XblSocialManagerUserGroupGetFilters\n    XblSocialManagerUserGroupGetLocalUser\n    XblSocialManagerUserGroupGetType\n    XblSocialManagerUserGroupGetUsers\n    XblSocialManagerUserGroupGetUsersTrackedByGroup\n    XblSocialRelationshipResultCloseHandle\n    XblSocialRelationshipResultDuplicateHandle\n    XblSocialRelationshipResultGetNextAsync\n    XblSocialRelationshipResultGetNextResult\n    XblSocialRelationshipResultGetRelationships\n    XblSocialRelationshipResultGetTotalCount\n    XblSocialRelationshipResultHasNext\n    XblSocialRemoveSocialRelationshipChangedHandler\n    XblSocialSubmitBatchReputationFeedbackAsync\n    XblSocialSubmitReputationFeedbackAsync\n    XblSocialSubscribeToSocialRelationshipChange\n    XblSocialUnsubscribeFromSocialRelationshipChange\n    XblStringVerifyStringAsync\n    XblStringVerifyStringResult\n    XblStringVerifyStringResultSize\n    XblStringVerifyStringsAsync\n    XblStringVerifyStringsResult\n    XblStringVerifyStringsResultSize\n    XblTitleManagedStatsDeleteStatsAsync\n    XblTitleManagedStatsUpdateStatsAsync\n    XblTitleManagedStatsWriteAsync\n    XblTitleStorageBlobMetadataResultCloseHandle\n    XblTitleStorageBlobMetadataResultDuplicateHandle\n    XblTitleStorageBlobMetadataResultGetItems\n    XblTitleStorageBlobMetadataResultGetNextAsync\n    XblTitleStorageBlobMetadataResultGetNextResult\n    XblTitleStorageBlobMetadataResultHasNext\n    XblTitleStorageDeleteBlobAsync\n    XblTitleStorageDownloadBlobAsync\n    XblTitleStorageDownloadBlobResult\n    XblTitleStorageGetBlobMetadataAsync\n    XblTitleStorageGetBlobMetadataResult\n    XblTitleStorageGetQuotaAsync\n    XblTitleStorageGetQuotaResult\n    XblTitleStorageUploadBlobAsync\n    XblTitleStorageUploadBlobResult\n    XblUserStatisticsAddStatisticChangedHandler\n    XblUserStatisticsGetMultipleUserStatisticsAsync\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize\n    XblUserStatisticsGetMultipleUserStatisticsResult\n    XblUserStatisticsGetMultipleUserStatisticsResultSize\n    XblUserStatisticsGetSingleUserStatisticAsync\n    XblUserStatisticsGetSingleUserStatisticResult\n    XblUserStatisticsGetSingleUserStatisticResultSize\n    XblUserStatisticsGetSingleUserStatisticsAsync\n    XblUserStatisticsGetSingleUserStatisticsResult\n    XblUserStatisticsGetSingleUserStatisticsResultSize\n    XblUserStatisticsRemoveStatisticChangedHandler\n    XblUserStatisticsSubscribeToStatisticChange\n    XblUserStatisticsUnsubscribeFromStatisticChange\n\n    XblWrapper_XblInitialize"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/dll/dllmain.cpp",
    "content": "#include \"pch.h\"\n#include <Xal/xal.h>\n#include <xsapi-c/services_c.h>\n#include <XGameRuntimeInit.h>\n\nextern \"C\"\n{\nBOOL APIENTRY DllMain(HMODULE /* hModule */, DWORD ul_reason_for_call, LPVOID /* lpReserved */)\n{\n    switch (ul_reason_for_call)\n    {\n    case DLL_PROCESS_ATTACH:\n    case DLL_THREAD_ATTACH:\n    case DLL_THREAD_DETACH:\n    case DLL_PROCESS_DETACH:\n        break;\n    }\n    return TRUE;\n}\n\nXBL_DLLEXPORT HRESULT XBL_CALLING_CONV XblWrapper_XblInitialize(\n    _In_z_ const char* scid,\n    _In_ XTaskQueueHandle internalWorkQueue\n) noexcept\n{\n    XGameRuntimeInitialize();\n\n    // xal must be initialized to be used by xsapi\n    XalInitArgs xalInitArgs = { };\n    XalInitialize(&xalInitArgs, internalWorkQueue);\n\n    XblInitArgs xblInitArgs = { };\n    xblInitArgs.scid = scid;\n    xblInitArgs.queue = internalWorkQueue;\n\n    return XblInitialize(&xblInitArgs);\n}\n}"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/dll/pch.cpp",
    "content": "#include \"pch.h\"\n"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/dll/pch.h",
    "content": "#pragma once\n\n#include <WinSDKVer.h>\n#define _WIN32_WINNT 0x0A00\n#include <SDKDDKVer.h>\n\n// Use the C++ standard templated min/max\n#define NOMINMAX\n\n// DirectX apps don't need GDI\n#define NODRAWTEXT\n#define NOGDI\n#define NOBITMAP\n\n// Include <mcx.h> if you need this\n#define NOMCX\n\n// Include <winsvc.h> if you need this\n#define NOSERVICE\n\n// WinHelp is deprecated\n#define NOHELP\n\n#include <windows.h>\n\n#if HC_PLATFORM_IS_MICROSOFT\n\n#define XBL_DLLEXPORT __declspec(dllexport)\n#define XBL_CALLING_CONV __stdcall\n\n#else\n\n#define XBL_DLLEXPORT\n#define XBL_CALLING_CONV\n\n#endif"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/generator/ThunksGenerator/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/generator/ThunksGenerator/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text.RegularExpressions;\n\nnamespace ThunksGenerator\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            var thunksDefFile = new FileInfo(\"../../../../dll/Microsoft.Xbox.Services.141.GDK.C.Thunks.def\");\n            Console.WriteLine(thunksDefFile.FullName);\n            string xsapiReproFolder = thunksDefFile.Directory.Parent.Parent.Parent.FullName;\n\n            string cHeadersFolder = Path.Combine(xsapiReproFolder, @\"Include\\xsapi-c\\\");\n            var headerFiles = Directory.EnumerateFiles(cHeadersFolder, \"*.h\", SearchOption.AllDirectories);\n\n            Console.WriteLine(\"Finding apis\");\n            List<string> fns = new List<string>();\n            foreach (string curHeader in headerFiles)\n            {\n                ProcessHeader(curHeader, fns);\n            }\n\n            fns.Sort();\n\n            Console.WriteLine($\"Writing apis to {thunksDefFile.FullName}\");\n            string content = \"LIBRARY Microsoft.Xbox.Services.141.GDK.C.Thunks.dll\\n\";\n            content += \"EXPORTS\\n\";\n            foreach (string fn in fns)\n            {\n                string apiName = fn.Substring(0, fn.Length - 1);\n                content += \"    \" + apiName + \"\\n\";\n            }\n            content += \"\\n    XblWrapper_XblInitialize\";\n            File.WriteAllText(thunksDefFile.FullName, content);\n        }\n\n        static void ProcessHeader(string curHeader, List<string> fns)\n        {\n            System.IO.StreamReader file = new System.IO.StreamReader(curHeader);\n            while (true)\n            {\n                string line = file.ReadLine();\n                if (line == null)\n                    break;\n\n                if (line.Contains(\"STDAPI\"))\n                {\n                    line = line.Replace(\"STDAPI \", \"\");\n                    line = line.Replace(\") XBL_NOEXCEPT\", \"\");\n                    Regex regex = new Regex(\"STDAPI_(.+) \");\n                    line = regex.Replace(line, \"\");\n                    if (line.Contains(\")\"))\n                    {\n                        // Remove all the handlers\n                        line = string.Empty;\n                    }\n                    int index = line.IndexOf(\"(\");\n                    if (index > 0)\n                        line = line.Substring(0, index + 1);\n\n                    if (!string.IsNullOrWhiteSpace(line))\n                    {\n                        line = line.Trim();\n                        fns.Add(line);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/generator/ThunksGenerator/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"ThunksGenerator\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"ThunksGenerator\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2020\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"21c651d1-61d7-46c5-bd23-128e40329aa5\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.141.GDK.C.Thunks/generator/ThunksGenerator/ThunksGenerator.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{21C651D1-61D7-46C5-BD23-128E40329AA5}</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>ThunksGenerator</RootNamespace>\n    <AssemblyName>ThunksGenerator</AssemblyName>\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <Deterministic>true</Deterministic>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.142.GDK.C/Microsoft.Xbox.Services.142.GDK.C.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{60139F62-BF37-4F11-BD93-5FBF4E92100C}</ProjectGuid>\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <XsapiImpl>true</XsapiImpl>\n    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug'\">\n    <TargetName>Microsoft.Xbox.Services.142.GDK.C.$(Configuration)</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <TargetName>Microsoft.Xbox.Services.142.GDK.C</TargetName>\n  </PropertyGroup>\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove(xsapi.gdk.props))\" />\n  <Import Project=\"$(XsapiSourceRoot)\\xsapi.staticlib.props\" />\n  <Import Project=\"$(XsapiSourceRoot)\\Build\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems\" Label=\"Shared\" />\n  <Import Project=\"$(XsapiSourceRoot)\\Build\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems\" Label=\"Shared\" />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <ClCompile>\n      <AdditionalOptions>/Zi %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <ClCompile>\n      <AdditionalOptions>/Zi %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.Common/Microsoft.Xbox.Services.Common.vcxitems",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <MSBuildAllProjects Condition=\"'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'\">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>\n    <HasSharedItems>true</HasSharedItems>\n    <ItemsProjectGuid>{cf3350e5-00a2-4647-a996-baf7542b0327}</ItemsProjectGuid>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)'=='StaticLibrary'\">_NO_ASYNCRTIMP;_NO_PPLXIMP;_NO_XSAPIIMP;XBL_API_NONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(ConfigurationType)'=='DynamicLibrary'\">_XSAPIIMP_EXPORT;XBL_API_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\Cpp;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Clubs;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Notification;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TCUI;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Shared;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\WinRT;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\System;\n        $(MSBuildThisFileDirectory)..\\..\\Source\\System\\WinRT;\n        %(AdditionalIncludeDirectories)\n      </AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectCapability Include=\"SourceItemsFromImports\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprestsdk_impl.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\astreambuf.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\asyncrt_utils.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\base_uri.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\containerstream.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\asyncrt_utils.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\base64.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\basic_types.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\cpprest_compat.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_client_msg.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_helpers.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_helpers.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_msg.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\json.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\json_parsing.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\json_serialization.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\nosal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\SafeInt3.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri_builder.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri_parser.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri_parser.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\web_utilities.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\http_headers.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\http_msg.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\json.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\producerconsumerstream.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\streams.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\uri.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\uri_builder.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\details\\pplx.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\details\\threadpool.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplx.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxcancellation_token.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxinterface.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxtasks.110.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxtasks.140.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxtasks.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\threadpool.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\achievements.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\errors.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\http_call.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\http_call_request_message.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\achievements.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\errors.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\events.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\http_call.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\http_call_request_message.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\leaderboard.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\matchmaking.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\mem.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\multiplayer.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\multiplayer_manager.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\notification.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\presence.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\privacy.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\profile.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\public_utils.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\real_time_activity.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\service_call_logging_config.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\social.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\social_manager.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\string_verify.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\system.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\title_storage.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\user_statistics.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_live_app_config.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_live_context.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_live_context_settings.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_service_call_routed_event_args.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\leaderboard.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\matchmaking.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\mem.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\multiplayer.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\multiplayer_manager.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\notification_helper.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\presence.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\privacy.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\profile.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\real_time_activity.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\services.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\service_call_logging_config.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\social.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\social_manager.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\string_verify.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\system.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\title_storage.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\types.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\user_statistics.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_live_app_config.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_live_context.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_live_context_settings.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_service_call_routed_event_args.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\achievements_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\achievements_manager_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\errors_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\events_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\game_invite_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\http_call_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\leaderboard_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\matchmaking_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\multiplayer_activity_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\multiplayer_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\multiplayer_manager_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\notification_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\pal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\platform_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\presence_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\privacy_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\profile_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\real_time_activity_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\services_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\social_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\social_manager_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\string_verify_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\title_managed_statistics_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\title_storage_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\types_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\user_statistics_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\xbox_live_context_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\xbox_live_context_settings_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\xbox_live_global_c.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\Manager\\achievements_manager_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\Cpp\\pch.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\pch_common.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_settings_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\matchmaking_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\privacy_service_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_connection.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_manager.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_subscription.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\peoplehub_service.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_graph.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_user_group.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\profile_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\title_managed_statistics_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify\\string_service_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\async_helpers.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\build_version.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\enum_traits.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\errors_legacy.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\fault_injection.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\global_state.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\asyncrt_utils.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\base_uri.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\asyncrt_utils.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\basic_types.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\cpprest_compat.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\nosal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri_builder.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri_parser.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri_parser.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\uri.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\uri_builder.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_request_message_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_wrapper_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_headers.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_utils.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_errors.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_mem.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_types.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_hc_output.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\perf_tester.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\public_utils_legacy.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\ref_counter.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\service_call_routed_handler.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\shared_macros.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\string_array.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\uri_impl.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\user.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\web_socket.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xbox_live_app_config_internal.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_json_utils.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_utils.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\System\\client_operation.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\System\\local_storage.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_constants.dat\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_subscription.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievement_service_internal.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\Manager\\achievements_manager_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\Manager\\achievements_manager_internal.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\Cpp\\pch.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_settings.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_global_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_column.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_row.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\hopper_statistics_response.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\matchmaking_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\match_ticket_details_response.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_info.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_client_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_client_pending_reader.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_client_pending_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_event_args.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_event_queue.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_game_client.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_game_session.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_lobby_client.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_lobby_session.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_local_user.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_local_user_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager_utils.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_match_client.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_member.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_session_writer.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_activity_handle_post_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_activity_query_post_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_invite_handle_post_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_query_search_handle_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_search_handle_details.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_search_handle_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_serializers.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_session.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_session_member.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_session_reference.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_subscription.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_transfer_handle_post_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\device_presence_change_subscription.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_device_record.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_record.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_title_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_user_batch_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\title_presence_change_subscription.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\permission_check_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\privacy_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\privacy_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_connection.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\peoplehub_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_graph.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_user_group.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\profile_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\profile_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\reputation_feedback_request.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\reputation_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_relationship_change_subscription.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_relationship_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\requested_statistics.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\service_configuration_statistic.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\statistic.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\statistic_change_subscription.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\title_managed_statistics_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\title_managed_statistics_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify\\string_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify\\verify_string_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_blob_metadata_result.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_service.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\async_helpers.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\errors.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\fault_injection.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\global_state.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_request_message.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_wrapper_internal.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_utils.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_mem.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_entry.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_hc_output.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_output.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\public_utils_legacy.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\ref_counter.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\service_call_routed_handler.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\user.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\utils_locales.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\web_socket.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xbox_live_app_config.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_json_utils.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_utils.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\System\\local_storage.cpp\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.Common/Microsoft.Xbox.Services.Common.vcxitems.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Include\">\n      <UniqueIdentifier>{a406adf2-c55d-4dda-9078-40715f2340f8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\xsapi-c\">\n      <UniqueIdentifier>{df1d4c6b-2405-4205-853b-d6a74d02a8d6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\xsapi-cpp\">\n      <UniqueIdentifier>{3bad286c-8e6c-4279-8fdd-8cf021ffac05}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\">\n      <UniqueIdentifier>{cf5cf662-fb8f-428f-a1b9-0b6632f1112d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\">\n      <UniqueIdentifier>{2973c22a-1e58-4f23-b9d3-b8d37dac8eb7}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Shared\">\n      <UniqueIdentifier>{a5cc23d7-d8f1-40a6-83a4-cc1a4a322f85}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\System\">\n      <UniqueIdentifier>{4caaf7af-cdaf-4799-927f-54ed23a9403e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\xsapi-cpp\\impl\">\n      <UniqueIdentifier>{1b81eaa4-c07b-453d-a413-f63bec7e4989}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\cpprestinclude\">\n      <UniqueIdentifier>{a067c625-5007-4b3f-af24-28c1dc6e06b8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\cpprestinclude\\cpprest\">\n      <UniqueIdentifier>{7a7c2dc9-30fe-48e3-b99d-546b987a1902}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\cpprestinclude\\pplx\">\n      <UniqueIdentifier>{ae9acc62-cd7b-4a6f-914c-dae1b6e5fe5e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\cpprestinclude\\pplx\\details\">\n      <UniqueIdentifier>{2f1e64b7-6471-4901-bc8c-cbca627e53fd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\\cpprestinclude\\cpprest\\details\">\n      <UniqueIdentifier>{537c4093-465f-40cd-acb8-f7c88e561389}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Achievements\">\n      <UniqueIdentifier>{84c91bfd-7d59-4ea9-b6ca-dfdeadae3dad}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Common\">\n      <UniqueIdentifier>{32a525db-8eb2-4265-8044-605b4e2a59b2}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Leaderboard\">\n      <UniqueIdentifier>{2df84b4c-09ea-4757-855d-d838b00cd0b1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Matchmaking\">\n      <UniqueIdentifier>{376dffea-8ca7-498b-8779-ce2cf762c84f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Multiplayer\">\n      <UniqueIdentifier>{29d52a87-80be-445c-a447-3bf4e232fb64}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\MultiplayerActivity\">\n      <UniqueIdentifier>{4f01071d-6a71-405c-90e2-d8e88e335625}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Presence\">\n      <UniqueIdentifier>{420eb5db-c38b-4936-a465-06dde3ab0570}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Privacy\">\n      <UniqueIdentifier>{b9ce0a0e-799b-4570-b36d-df5691b38434}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\RealTimeActivityManager\">\n      <UniqueIdentifier>{25e21202-08d9-49b7-80ca-f265b8297f15}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Social\">\n      <UniqueIdentifier>{2de0f5c8-d34e-4261-9380-19b5475e0672}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Stats\">\n      <UniqueIdentifier>{c67122a4-c2a6-44df-9145-d2600e70ba8a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\StringVerify\">\n      <UniqueIdentifier>{9a02f6ba-2a95-404d-b2a0-55cc395fd788}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\TitleStorage\">\n      <UniqueIdentifier>{61611672-3a9c-4e60-90e7-61f29510918c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Achievements\\Manager\">\n      <UniqueIdentifier>{0d3e06c3-440d-441b-b3cb-c3f02eae8ec5}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Common\\Cpp\">\n      <UniqueIdentifier>{17ebfdba-54f7-442c-851f-3ae11db585e5}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Multiplayer\\Manager\">\n      <UniqueIdentifier>{dcb2c672-4ee9-46df-9eb0-f4dfdb0638a2}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Social\\Manager\">\n      <UniqueIdentifier>{a5780ccd-5941-47bb-8f3d-5925e7d49b98}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Shared\\HookedUri\">\n      <UniqueIdentifier>{1aaa9d6c-c806-4d77-bd9b-209ea4bab896}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Shared\\HookedUri\\details\">\n      <UniqueIdentifier>{a67e3ff0-7b8a-4756-b0a8-a5ae2c85d0ee}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Shared\\Logger\">\n      <UniqueIdentifier>{862cb430-0f45-4462-a242-1a0e1c42e8ce}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\achievements_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\achievements_manager_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\errors_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\events_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\game_invite_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\http_call_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\leaderboard_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\matchmaking_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\multiplayer_activity_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\multiplayer_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\multiplayer_manager_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\notification_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\pal.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\platform_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\presence_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\privacy_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\profile_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\real_time_activity_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\services_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\social_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\social_manager_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\string_verify_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\title_managed_statistics_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\title_storage_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\types_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\user_statistics_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\xbox_live_context_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\xbox_live_context_settings_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-c\\xbox_live_global_c.h\">\n      <Filter>Include\\xsapi-c</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\achievements.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\errors.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\http_call.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\http_call_request_message.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\leaderboard.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\matchmaking.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\mem.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\multiplayer.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\multiplayer_manager.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\notification_helper.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\presence.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\privacy.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\profile.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\real_time_activity.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\service_call_logging_config.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\services.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\social.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\social_manager.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\string_verify.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\system.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\title_storage.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\types.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\user_statistics.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_live_app_config.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_live_context.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_live_context_settings.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\xbox_service_call_routed_event_args.h\">\n      <Filter>Include\\xsapi-cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\achievements.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\errors.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\events.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\http_call.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\http_call_request_message.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\leaderboard.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\matchmaking.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\mem.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\multiplayer.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\multiplayer_manager.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\notification.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\presence.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\privacy.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\profile.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\public_utils.h\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\real_time_activity.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\service_call_logging_config.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\social.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\social_manager.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\string_verify.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\system.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\title_storage.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\user_statistics.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_live_app_config.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_live_context.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_live_context_settings.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\xsapi-cpp\\impl\\xbox_service_call_routed_event_args.hpp\">\n      <Filter>Include\\xsapi-cpp\\impl</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprestsdk_impl.h\">\n      <Filter>Include\\cpprestinclude</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplx.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxcancellation_token.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxinterface.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxtasks.110.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxtasks.140.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\pplxtasks.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\threadpool.h\">\n      <Filter>Include\\cpprestinclude\\pplx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\details\\pplx.hpp\">\n      <Filter>Include\\cpprestinclude\\pplx\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\pplx\\details\\threadpool.hpp\">\n      <Filter>Include\\cpprestinclude\\pplx\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\astreambuf.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\asyncrt_utils.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\base_uri.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\containerstream.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\http_headers.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\http_msg.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\json.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\producerconsumerstream.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\streams.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\uri.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\uri_builder.h\">\n      <Filter>Include\\cpprestinclude\\cpprest</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\asyncrt_utils.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\base64.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\basic_types.h\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\cpprest_compat.h\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_client_msg.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_helpers.h\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_helpers.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_msg.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\json.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\json_parsing.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\json_serialization.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\nosal.h\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\SafeInt3.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri_builder.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri_parser.h\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\uri_parser.hpp\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\web_utilities.h\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\Manager\\achievements_manager_internal.h\">\n      <Filter>Source\\Services\\Achievements\\Manager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_internal.h\">\n      <Filter>Source\\Services\\Achievements</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\pch_common.h\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_internal.h\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_settings_internal.h\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\Cpp\\pch.h\">\n      <Filter>Source\\Services\\Common\\Cpp</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_internal.h\">\n      <Filter>Source\\Services\\Leaderboard</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\matchmaking_internal.h\">\n      <Filter>Source\\Services\\Matchmaking</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_internal.h\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager_internal.h\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_internal.h\">\n      <Filter>Source\\Services\\MultiplayerActivity</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_internal.h\">\n      <Filter>Source\\Services\\TitleStorage</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify\\string_service_internal.h\">\n      <Filter>Source\\Services\\StringVerify</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\title_managed_statistics_internal.h\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_internal.h\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\profile_internal.h\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_internal.h\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\peoplehub_service.h\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_graph.h\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_internal.h\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_user_group.h\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_connection.h\">\n      <Filter>Source\\Services\\RealTimeActivityManager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_manager.h\">\n      <Filter>Source\\Services\\RealTimeActivityManager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_subscription.h\">\n      <Filter>Source\\Services\\RealTimeActivityManager</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\privacy_service_internal.h\">\n      <Filter>Source\\Services\\Privacy</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_internal.h\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\asyncrt_utils.hpp\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\basic_types.h\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\cpprest_compat.h\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\nosal.h\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri.hpp\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri_builder.hpp\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri_parser.h\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\details\\uri_parser.hpp\">\n      <Filter>Source\\Shared\\HookedUri\\details</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\asyncrt_utils.h\">\n      <Filter>Source\\Shared\\HookedUri</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\base_uri.h\">\n      <Filter>Source\\Shared\\HookedUri</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\uri.h\">\n      <Filter>Source\\Shared\\HookedUri</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\HookedUri\\uri_builder.h\">\n      <Filter>Source\\Shared\\HookedUri</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log.h\">\n      <Filter>Source\\Shared\\Logger</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_hc_output.h\">\n      <Filter>Source\\Shared\\Logger</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\async_helpers.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\build_version.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\enum_traits.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\errors_legacy.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\fault_injection.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\global_state.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_request_message_internal.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_wrapper_internal.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_headers.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_utils.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_errors.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_mem.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_types.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\perf_tester.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\public_utils_legacy.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\ref_counter.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\service_call_routed_handler.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\shared_macros.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\string_array.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\uri_impl.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\user.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\web_socket.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xbox_live_app_config_internal.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_json_utils.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_utils.h\">\n      <Filter>Source\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\System\\client_operation.h\">\n      <Filter>Source\\System</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\System\\local_storage.h\">\n      <Filter>Source\\System</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"$(MSBuildThisFileDirectory)..\\..\\Include\\cpprestinclude\\cpprest\\details\\http_constants.dat\">\n      <Filter>Include\\cpprestinclude\\cpprest\\details</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\Manager\\achievements_manager_api.cpp\">\n      <Filter>Source\\Services\\Achievements\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\Manager\\achievements_manager_internal.cpp\">\n      <Filter>Source\\Services\\Achievements\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievement_service_internal.cpp\">\n      <Filter>Source\\Services\\Achievements</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_api.cpp\">\n      <Filter>Source\\Services\\Achievements</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_result.cpp\">\n      <Filter>Source\\Services\\Achievements</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Achievements\\achievements_subscription.cpp\">\n      <Filter>Source\\Services\\Achievements</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context.cpp\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_api.cpp\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_context_settings.cpp\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\xbox_live_global_api.cpp\">\n      <Filter>Source\\Services\\Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Common\\Cpp\\pch.cpp\">\n      <Filter>Source\\Services\\Common\\Cpp</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_column.cpp\">\n      <Filter>Source\\Services\\Leaderboard</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_result.cpp\">\n      <Filter>Source\\Services\\Leaderboard</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_row.cpp\">\n      <Filter>Source\\Services\\Leaderboard</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Leaderboard\\leaderboard_service.cpp\">\n      <Filter>Source\\Services\\Leaderboard</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\hopper_statistics_response.cpp\">\n      <Filter>Source\\Services\\Matchmaking</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\match_ticket_details_response.cpp\">\n      <Filter>Source\\Services\\Matchmaking</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Matchmaking\\matchmaking_service.cpp\">\n      <Filter>Source\\Services\\Matchmaking</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_activity_handle_post_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_activity_query_post_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_api.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_invite_handle_post_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_query_search_handle_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_search_handle_details.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_search_handle_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_serializers.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_service.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_session.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_session_member.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_session_reference.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_subscription.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\multiplayer_transfer_handle_post_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_client_manager.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_client_pending_reader.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_client_pending_request.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_event_args.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_event_queue.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_game_client.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_game_session.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_lobby_client.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_lobby_session.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_local_user.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_local_user_manager.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager_api.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_manager_utils.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_match_client.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_member.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Multiplayer\\Manager\\multiplayer_session_writer.cpp\">\n      <Filter>Source\\Services\\Multiplayer\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_api.cpp\">\n      <Filter>Source\\Services\\MultiplayerActivity</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_info.cpp\">\n      <Filter>Source\\Services\\MultiplayerActivity</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\MultiplayerActivity\\multiplayer_activity_service.cpp\">\n      <Filter>Source\\Services\\MultiplayerActivity</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_api.cpp\">\n      <Filter>Source\\Services\\TitleStorage</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_blob_metadata_result.cpp\">\n      <Filter>Source\\Services\\TitleStorage</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\TitleStorage\\title_storage_service.cpp\">\n      <Filter>Source\\Services\\TitleStorage</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify\\string_service.cpp\">\n      <Filter>Source\\Services\\StringVerify</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\StringVerify\\verify_string_result.cpp\">\n      <Filter>Source\\Services\\StringVerify</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\requested_statistics.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\service_configuration_statistic.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\statistic.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\statistic_change_subscription.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\title_managed_statistics_api.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\title_managed_statistics_service.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_api.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_result.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Stats\\user_statistics_service.cpp\">\n      <Filter>Source\\Services\\Stats</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\profile_api.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\profile_service.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\reputation_feedback_request.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\reputation_service.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_api.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_relationship_change_subscription.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_relationship_result.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\social_service.cpp\">\n      <Filter>Source\\Services\\Social</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\peoplehub_service.cpp\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_graph.cpp\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager.cpp\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_api.cpp\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Social\\Manager\\social_manager_user_group.cpp\">\n      <Filter>Source\\Services\\Social\\Manager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_api.cpp\">\n      <Filter>Source\\Services\\RealTimeActivityManager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_connection.cpp\">\n      <Filter>Source\\Services\\RealTimeActivityManager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\RealTimeActivityManager\\real_time_activity_manager.cpp\">\n      <Filter>Source\\Services\\RealTimeActivityManager</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\permission_check_result.cpp\">\n      <Filter>Source\\Services\\Privacy</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\privacy_api.cpp\">\n      <Filter>Source\\Services\\Privacy</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Privacy\\privacy_service.cpp\">\n      <Filter>Source\\Services\\Privacy</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\device_presence_change_subscription.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_api.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_device_record.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_record.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_service.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_title_request.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\presence_user_batch_request.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Presence\\title_presence_change_subscription.cpp\">\n      <Filter>Source\\Services\\Presence</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log.cpp\">\n      <Filter>Source\\Shared\\Logger</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_entry.cpp\">\n      <Filter>Source\\Shared\\Logger</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_hc_output.cpp\">\n      <Filter>Source\\Shared\\Logger</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\Logger\\log_output.cpp\">\n      <Filter>Source\\Shared\\Logger</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\async_helpers.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\errors.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\fault_injection.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\global_state.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_api.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_request_message.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_call_wrapper_internal.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\http_utils.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\internal_mem.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\public_utils_legacy.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\ref_counter.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\service_call_routed_handler.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\user.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\utils_locales.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\web_socket.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xbox_live_app_config.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_json_utils.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Shared\\xsapi_utils.cpp\">\n      <Filter>Source\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\System\\local_storage.cpp\">\n      <Filter>Source\\System</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.GDK/Microsoft.Xbox.Services.GDK.vcxitems",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <MSBuildAllProjects Condition=\"'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'\">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>\n    <HasSharedItems>true</HasSharedItems>\n    <ItemsProjectGuid>{1e320494-894e-4feb-90ca-df4fe20499f4}</ItemsProjectGuid>\n  </PropertyGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>XSAPI_NO_PPL=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ProjectCapability Include=\"SourceItemsFromImports\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_api.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_etw.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_gdk.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_etw.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_gdk.h\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.GDK/Microsoft.Xbox.Services.GDK.vcxitems.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source\">\n      <UniqueIdentifier>{a7468e1e-9c65-4f1a-97db-702dd3013d46}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Shared\">\n      <UniqueIdentifier>{83fa3d12-617a-48df-9de0-edffcc78503e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Shared\\WinRT\">\n      <UniqueIdentifier>{7758f7f5-95ff-453a-a531-200c4dec6794}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\">\n      <UniqueIdentifier>{b451b690-ab47-47b5-a948-e9a544907b98}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source\\Services\\Events\">\n      <UniqueIdentifier>{4593c653-a41d-403c-90d3-098726781331}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_api.cpp\">\n      <Filter>Source\\Services\\Events</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_gdk.cpp\">\n      <Filter>Source\\Services\\Events</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_etw.cpp\">\n      <Filter>Source\\Services\\Events</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service.h\">\n      <Filter>Source\\Services\\Events</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_gdk.h\">\n      <Filter>Source\\Services\\Events</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)..\\..\\Source\\Services\\Events\\events_service_etw.h\">\n      <Filter>Source\\Services\\Events</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Build/Microsoft.Xbox.Services.Win32.C.Dll.def",
    "content": "LIBRARY xsapi\nEXPORTS\n    HCAddCallRoutedHandler\n    HCAddWebSocketRoutedHandler\n    HCCleanup\n    HCCleanupAsync\n    HCGetHttpCallPerformFunction\n    HCGetLibVersion\n    HCGetWebSocketConnectResult\n    HCGetWebSocketFunctions\n    HCGetWebSocketSendMessageResult\n    HCHttpCallCloseHandle\n    HCHttpCallCreate\n    HCHttpCallDuplicateHandle\n    HCHttpCallGetContext\n    HCHttpCallGetId\n    HCHttpCallGetRequestUrl\n    HCHttpCallPerformAsync\n    HCHttpCallRequestGetHeader\n    HCHttpCallRequestGetHeaderAtIndex\n    HCHttpCallRequestGetNumHeaders\n    HCHttpCallRequestGetRequestBodyBytes\n    HCHttpCallRequestGetRequestBodyReadFunction\n    HCHttpCallRequestGetRequestBodyString\n    HCHttpCallRequestGetRetryAllowed\n    HCHttpCallRequestGetRetryCacheId\n    HCHttpCallRequestGetRetryDelay\n    HCHttpCallRequestGetTimeout\n    HCHttpCallRequestGetTimeoutWindow\n    HCHttpCallRequestGetUrl\n    HCHttpCallRequestSetHeader\n    HCHttpCallRequestSetRequestBodyBytes\n    HCHttpCallRequestSetRequestBodyReadFunction\n    HCHttpCallRequestSetRequestBodyString\n    HCHttpCallRequestSetRetryAllowed\n    HCHttpCallRequestSetRetryCacheId\n    HCHttpCallRequestSetRetryDelay\n    HCHttpCallRequestSetSSLValidation\n    HCHttpCallRequestSetTimeout\n    HCHttpCallRequestSetTimeoutWindow\n    HCHttpCallRequestSetUrl\n    HCHttpCallResponseAppendResponseBodyBytes\n    HCHttpCallResponseGetHeader\n    HCHttpCallResponseGetHeaderAtIndex\n    HCHttpCallResponseGetNetworkErrorCode\n    HCHttpCallResponseGetNumHeaders\n    HCHttpCallResponseGetPlatformNetworkErrorMessage\n    HCHttpCallResponseGetResponseBodyBytes\n    HCHttpCallResponseGetResponseBodyBytesSize\n    HCHttpCallResponseGetResponseBodyWriteFunction\n    HCHttpCallResponseGetResponseString\n    HCHttpCallResponseGetStatusCode\n    HCHttpCallResponseSetHeader\n    HCHttpCallResponseSetHeaderWithLength\n    HCHttpCallResponseSetNetworkErrorCode\n    HCHttpCallResponseSetPlatformNetworkErrorMessage\n    HCHttpCallResponseSetResponseBodyBytes\n    HCHttpCallResponseSetResponseBodyWriteFunction\n    HCHttpCallResponseSetStatusCode\n    HCHttpCallSetContext\n    HCHttpCallSetTracing\n    HCInitialize\n    HCIsInitialized\n    HCMemGetFunctions\n    HCMemSetFunctions\n    HCMockAddMock\n    HCMockCallCloseHandle\n    HCMockCallCreate\n    HCMockCallDuplicateHandle\n    HCMockClearMocks\n    HCMockRemoveMock\n    HCMockResponseSetHeader\n    HCMockResponseSetNetworkErrorCode\n    HCMockResponseSetResponseBodyBytes\n    HCMockResponseSetStatusCode\n    HCMockSetMockMatchedCallback\n    HCRemoveCallRoutedHandler\n    HCRemoveWebSocketRoutedHandler\n    HCSetGlobalProxy\n    HCSetHttpCallPerformFunction\n    HCSettingsGetTraceLevel\n    HCSettingsSetTraceLevel\n    HCSetWebSocketFunctions\n    HCTraceImplMessage\n    HCTraceImplMessage_v\n    HCTraceImplScopeId\n    HCTraceSetClientCallback\n    HCTraceSetEtwEnabled\n    HCTraceSetPlatformCallbacks\n    HCTraceSetTraceToDebugger\n    HCWebSocketCloseHandle\n    HCWebSocketConnectAsync\n    HCWebSocketCreate\n    HCWebSocketDisconnect\n    HCWebSocketDuplicateHandle\n    HCWebSocketGetBinaryMessageFragmentEventFunction\n    HCWebSocketGetEventFunctions\n    HCWebSocketGetHeader\n    HCWebSocketGetHeaderAtIndex\n    HCWebSocketGetNumHeaders\n    HCWebSocketGetProxyUri\n    HCWebSocketSendBinaryMessageAsync\n    HCWebSocketSendMessageAsync\n    HCWebSocketSetBinaryMessageFragmentEventFunction\n    HCWebSocketSetHeader\n    HCWebSocketSetMaxReceiveBufferSize\n    HCWebSocketSetProxyDecryptsHttps\n    HCWebSocketSetProxyUri\n    XalAddUserWithUiAsync\n    XalAddUserWithUiResult\n    XalCheckUcsConsentForAllUsers\n    XalCleanupAsync\n    XalCleanupResult\n    XalCompareUsers\n    XalFindUserByLocalId\n    XalGetDeviceUser\n    XalGetDeviceUserIsPresent\n    XalGetMaxUsers\n    XalGetSandbox\n    XalGetSandboxSize\n    XalGetTitleId\n    XalInitialize\n    XalMemGetFunctions\n    XalMemSetFunctions\n    XalPlatformCryptoSetCallbacks\n    XalPlatformDateTimeSetCallbacks\n    XalPlatformRemoteConnectCancelPrompt\n    XalPlatformRemoteConnectClearEventHandlers\n    XalPlatformRemoteConnectSetEventHandlers\n    XalPlatformStorageClearComplete\n    XalPlatformStorageClearEventHandlers\n    XalPlatformStorageReadComplete\n    XalPlatformStorageSetEventHandlers\n    XalPlatformStorageWriteComplete\n    XalPlatformWebClearEventHandler\n    XalPlatformWebSetEventHandler\n    XalPlatformWebShowUrlComplete\n    XalSignOutUserAsync\n    XalSignOutUserAsyncIsPresent\n    XalSignOutUserResult\n    XalTryAddDefaultUserSilentlyAsync\n    XalTryAddDefaultUserSilentlyResult\n    XalTryAddUserByIdAsync\n    XalTryAddUserByIdResult\n    XalUserCheckPrivilege\n    XalUserCheckUcsConsent\n    XalUserCloseHandle\n    XalUserCloseSignoutDeferral\n    XalUserDuplicateHandle\n    XalUserGetAgeGroup\n    XalUserGetGamerPictureAsync\n    XalUserGetGamerPictureResult\n    XalUserGetGamerPictureResultSize\n    XalUserGetGamertag\n    XalUserGetGamertagSize\n    XalUserGetId\n    XalUserGetLocalId\n    XalUserGetSignoutDeferral\n    XalUserGetState\n    XalUserGetTokenAndSignatureSilentlyAsync\n    XalUserGetTokenAndSignatureSilentlyResult\n    XalUserGetTokenAndSignatureSilentlyResultSize\n    XalUserIsDevice\n    XalUserIsGuest\n    XalUserManageUcsConsentWithUiAsync\n    XalUserManageUcsConsentWithUiResult\n    XalUserRegisterChangeEventHandler\n    XalUserResolveIssueWithUiAsync\n    XalUserResolveIssueWithUiResult\n    XalUserResolvePrivilegeWithUiIsPresent\n    XalUserResolveUserPrivilegeWithUiAsync\n    XalUserResolveUserPrivilegeWithUiResult\n    XalUserUnregisterChangeEventHandler\n    XAsyncBegin\n    XAsyncCancel\n    XAsyncComplete\n    XAsyncGetResult\n    XAsyncGetResultSize\n    XAsyncGetStatus\n    XAsyncRun\n    XAsyncSchedule\n    XblAchievementsAddAchievementProgressChangeHandler\n    XblAchievementsGetAchievementAsync\n    XblAchievementsGetAchievementResult\n    XblAchievementsGetAchievementsForTitleIdAsync\n    XblAchievementsGetAchievementsForTitleIdResult\n    XblAchievementsManagerAddLocalUser\n    XblAchievementsManagerDoWork\n    XblAchievementsManagerGetAchievement\n    XblAchievementsManagerGetAchievements\n    XblAchievementsManagerGetAchievementsByState\n    XblAchievementsManagerIsUserInitialized\n    XblAchievementsManagerRemoveLocalUser\n    XblAchievementsManagerResultCloseHandle\n    XblAchievementsManagerResultDuplicateHandle\n    XblAchievementsManagerResultGetAchievements\n    XblAchievementsManagerUpdateAchievement\n    XblAchievementsRemoveAchievementProgressChangeHandler\n    XblAchievementsResultCloseHandle\n    XblAchievementsResultDuplicateHandle\n    XblAchievementsResultGetAchievements\n    XblAchievementsResultGetNextAsync\n    XblAchievementsResultGetNextResult\n    XblAchievementsResultHasNext\n    XblAchievementsUpdateAchievementAsync\n    XblAchievementsUpdateAchievementForTitleIdAsync\n    XblAchievementUnlockAddNotificationHandler\n    XblAchievementUnlockRemoveNotificationHandler\n    XblAddServiceCallRoutedHandler\n    XblCleanupAsync\n    XblContextCloseHandle\n    XblContextCreateHandle\n    XblContextDuplicateHandle\n    XblContextGetUser\n    XblContextGetXboxUserId\n    XblContextSettingsGetHttpRetryDelay\n    XblContextSettingsGetHttpTimeoutWindow\n    XblContextSettingsGetLongHttpTimeout\n    XblContextSettingsGetUseCrossPlatformQosServers\n    XblContextSettingsGetWebsocketTimeoutWindow\n    XblContextSettingsSetHttpRetryDelay\n    XblContextSettingsSetHttpTimeoutWindow\n    XblContextSettingsSetLongHttpTimeout\n    XblContextSettingsSetUseCrossPlatformQosServers\n    XblContextSettingsSetWebsocketTimeoutWindow\n    XblDisableAssertsForXboxLiveThrottlingInDevSandboxes\n    XblEventsSetMaxFileSize\n    XblEventsSetStorageAllotment\n    XblEventsWriteInGameEvent\n    XblFormatSecureDeviceAddress\n    XblGameInviteAddNotificationHandler\n    XblGameInviteRemoveNotificationHandler\n    XblGetAsyncQueue\n    XblGetErrorCondition\n    XblGetScid\n    XblHttpCallCloseHandle\n    XblHttpCallCreate\n    XblHttpCallDuplicateHandle\n    XblHttpCallGetHeader\n    XblHttpCallGetHeaderAtIndex\n    XblHttpCallGetNetworkErrorCode\n    XblHttpCallGetNumHeaders\n    XblHttpCallGetPlatformNetworkErrorMessage\n    XblHttpCallGetRequestUrl\n    XblHttpCallGetResponseBodyBytes\n    XblHttpCallGetResponseBodyBytesSize\n    XblHttpCallGetResponseString\n    XblHttpCallGetStatusCode\n    XblHttpCallPerformAsync\n    XblHttpCallRequestSetHeader\n    XblHttpCallRequestSetLongHttpCall\n    XblHttpCallRequestSetRequestBodyBytes\n    XblHttpCallRequestSetRequestBodyString\n    XblHttpCallRequestSetRetryAllowed\n    XblHttpCallRequestSetRetryCacheId\n    XblHttpCallSetTracing\n    XblInitialize\n    XblLeaderboardGetLeaderboardAsync\n    XblLeaderboardGetLeaderboardResult\n    XblLeaderboardGetLeaderboardResultSize\n    XblLeaderboardResultGetNextAsync\n    XblLeaderboardResultGetNextResult\n    XblLeaderboardResultGetNextResultSize\n    XblLocalStorageClearComplete\n    XblLocalStorageReadComplete\n    XblLocalStorageSetHandlers\n    XblLocalStorageWriteComplete\n    XblMatchmakingCreateMatchTicketAsync\n    XblMatchmakingCreateMatchTicketResult\n    XblMatchmakingDeleteMatchTicketAsync\n    XblMatchmakingGetHopperStatisticsAsync\n    XblMatchmakingGetHopperStatisticsResult\n    XblMatchmakingGetHopperStatisticsResultSize\n    XblMatchmakingGetMatchTicketDetailsAsync\n    XblMatchmakingGetMatchTicketDetailsResult\n    XblMatchmakingGetMatchTicketDetailsResultSize\n    XblMemGetFunctions\n    XblMemSetFunctions\n    XblMultiplayerActivityAddInviteHandler\n    XblMultiplayerActivityDeleteActivityAsync\n    XblMultiplayerActivityFlushRecentPlayersAsync\n    XblMultiplayerActivityGetActivityAsync\n    XblMultiplayerActivityGetActivityResult\n    XblMultiplayerActivityGetActivityResultSize\n    XblMultiplayerActivityRemoveInviteHandler\n    XblMultiplayerActivitySendInvitesAsync\n    XblMultiplayerActivitySetActivityAsync\n    XblMultiplayerActivityUpdateRecentPlayers\n    XblMultiplayerAddConnectionIdChangedHandler\n    XblMultiplayerAddSessionChangedHandler\n    XblMultiplayerAddSubscriptionLostHandler\n    XblMultiplayerClearActivityAsync\n    XblMultiplayerCreateSearchHandleAsync\n    XblMultiplayerCreateSearchHandleResult\n    XblMultiplayerDeleteSearchHandleAsync\n    XblMultiplayerEventArgsFindMatchCompleted\n    XblMultiplayerEventArgsMember\n    XblMultiplayerEventArgsMembers\n    XblMultiplayerEventArgsMembersCount\n    XblMultiplayerEventArgsPerformQoSMeasurements\n    XblMultiplayerEventArgsPropertiesJson\n    XblMultiplayerEventArgsXuid\n    XblMultiplayerGetActivitiesForSocialGroupAsync\n    XblMultiplayerGetActivitiesForSocialGroupResult\n    XblMultiplayerGetActivitiesForSocialGroupResultCount\n    XblMultiplayerGetActivitiesForUsersAsync\n    XblMultiplayerGetActivitiesForUsersResult\n    XblMultiplayerGetActivitiesForUsersResultCount\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize\n    XblMultiplayerGetActivitiesWithPropertiesForUsersAsync\n    XblMultiplayerGetActivitiesWithPropertiesForUsersResult\n    XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize\n    XblMultiplayerGetSearchHandlesAsync\n    XblMultiplayerGetSearchHandlesResult\n    XblMultiplayerGetSearchHandlesResultCount\n    XblMultiplayerGetSessionAsync\n    XblMultiplayerGetSessionByHandleAsync\n    XblMultiplayerGetSessionByHandleResult\n    XblMultiplayerGetSessionResult\n    XblMultiplayerManagerAutoFillMembersDuringMatchmaking\n    XblMultiplayerManagerCancelMatch\n    XblMultiplayerManagerDoWork\n    XblMultiplayerManagerEstimatedMatchWaitTime\n    XblMultiplayerManagerFindMatch\n    XblMultiplayerManagerGameSessionActive\n    XblMultiplayerManagerGameSessionConstants\n    XblMultiplayerManagerGameSessionCorrelationId\n    XblMultiplayerManagerGameSessionHost\n    XblMultiplayerManagerGameSessionIsHost\n    XblMultiplayerManagerGameSessionMembers\n    XblMultiplayerManagerGameSessionMembersCount\n    XblMultiplayerManagerGameSessionPropertiesJson\n    XblMultiplayerManagerGameSessionSessionReference\n    XblMultiplayerManagerGameSessionSetProperties\n    XblMultiplayerManagerGameSessionSetSynchronizedHost\n    XblMultiplayerManagerGameSessionSetSynchronizedProperties\n    XblMultiplayerManagerInitialize\n    XblMultiplayerManagerJoinability\n    XblMultiplayerManagerJoinGame\n    XblMultiplayerManagerJoinGameFromLobby\n    XblMultiplayerManagerJoinLobby\n    XblMultiplayerManagerLeaveGame\n    XblMultiplayerManagerLobbySessionAddLocalUser\n    XblMultiplayerManagerLobbySessionConstants\n    XblMultiplayerManagerLobbySessionCorrelationId\n    XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties\n    XblMultiplayerManagerLobbySessionHost\n    XblMultiplayerManagerLobbySessionInviteFriends\n    XblMultiplayerManagerLobbySessionInviteUsers\n    XblMultiplayerManagerLobbySessionIsHost\n    XblMultiplayerManagerLobbySessionLocalMembers\n    XblMultiplayerManagerLobbySessionLocalMembersCount\n    XblMultiplayerManagerLobbySessionMembers\n    XblMultiplayerManagerLobbySessionMembersCount\n    XblMultiplayerManagerLobbySessionPropertiesJson\n    XblMultiplayerManagerLobbySessionRemoveLocalUser\n    XblMultiplayerManagerLobbySessionSessionReference\n    XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress\n    XblMultiplayerManagerLobbySessionSetLocalMemberProperties\n    XblMultiplayerManagerLobbySessionSetProperties\n    XblMultiplayerManagerLobbySessionSetSynchronizedHost\n    XblMultiplayerManagerLobbySessionSetSynchronizedProperties\n    XblMultiplayerManagerMatchStatus\n    XblMultiplayerManagerMemberAreMembersOnSameDevice\n    XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\n    XblMultiplayerManagerSetJoinability\n    XblMultiplayerManagerSetQosMeasurements\n    XblMultiplayerQuerySessionsAsync\n    XblMultiplayerQuerySessionsResult\n    XblMultiplayerQuerySessionsResultCount\n    XblMultiplayerRemoveConnectionIdChangedHandler\n    XblMultiplayerRemoveSessionChangedHandler\n    XblMultiplayerRemoveSubscriptionLostHandler\n    XblMultiplayerSearchHandleCloseHandle\n    XblMultiplayerSearchHandleDuplicateHandle\n    XblMultiplayerSearchHandleGetCreationTime\n    XblMultiplayerSearchHandleGetCustomSessionPropertiesJson\n    XblMultiplayerSearchHandleGetId\n    XblMultiplayerSearchHandleGetJoinRestriction\n    XblMultiplayerSearchHandleGetMemberCounts\n    XblMultiplayerSearchHandleGetNumberAttributes\n    XblMultiplayerSearchHandleGetSessionClosed\n    XblMultiplayerSearchHandleGetSessionOwnerXuids\n    XblMultiplayerSearchHandleGetSessionReference\n    XblMultiplayerSearchHandleGetStringAttributes\n    XblMultiplayerSearchHandleGetTags\n    XblMultiplayerSearchHandleGetVisibility\n    XblMultiplayerSendInvitesAsync\n    XblMultiplayerSendInvitesResult\n    XblMultiplayerSessionAddMemberReservation\n    XblMultiplayerSessionCloseHandle\n    XblMultiplayerSessionCompare\n    XblMultiplayerSessionConstantsSetCapabilities\n    XblMultiplayerSessionConstantsSetCloudComputePackageJson\n    XblMultiplayerSessionConstantsSetMaxMembersInSession\n    XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson\n    XblMultiplayerSessionConstantsSetMemberInitialization\n    XblMultiplayerSessionConstantsSetPeerToHostRequirements\n    XblMultiplayerSessionConstantsSetPeerToPeerRequirements\n    XblMultiplayerSessionConstantsSetQosConnectivityMetrics\n    XblMultiplayerSessionConstantsSetTimeouts\n    XblMultiplayerSessionConstantsSetVisibility\n    XblMultiplayerSessionCreateHandle\n    XblMultiplayerSessionCurrentUser\n    XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson\n    XblMultiplayerSessionCurrentUserSetCustomPropertyJson\n    XblMultiplayerSessionCurrentUserSetEncounters\n    XblMultiplayerSessionCurrentUserSetGroups\n    XblMultiplayerSessionCurrentUserSetMembersInGroup\n    XblMultiplayerSessionCurrentUserSetQosMeasurements\n    XblMultiplayerSessionCurrentUserSetRoles\n    XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64\n    XblMultiplayerSessionCurrentUserSetServerQosMeasurements\n    XblMultiplayerSessionCurrentUserSetStatus\n    XblMultiplayerSessionDeleteCustomPropertyJson\n    XblMultiplayerSessionDuplicateHandle\n    XblMultiplayerSessionEtag\n    XblMultiplayerSessionGetInfo\n    XblMultiplayerSessionGetInitializationInfo\n    XblMultiplayerSessionGetMember\n    XblMultiplayerSessionGetRoleByName\n    XblMultiplayerSessionHostCandidates\n    XblMultiplayerSessionJoin\n    XblMultiplayerSessionLeave\n    XblMultiplayerSessionMatchmakingServer\n    XblMultiplayerSessionMembers\n    XblMultiplayerSessionMembersAccepted\n    XblMultiplayerSessionPropertiesSetJoinRestriction\n    XblMultiplayerSessionPropertiesSetKeywords\n    XblMultiplayerSessionPropertiesSetReadRestriction\n    XblMultiplayerSessionPropertiesSetTurnCollection\n    XblMultiplayerSessionRawServersJson\n    XblMultiplayerSessionReferenceCreate\n    XblMultiplayerSessionReferenceIsValid\n    XblMultiplayerSessionReferenceParseFromUriPath\n    XblMultiplayerSessionReferenceToUriPath\n    XblMultiplayerSessionRoleTypes\n    XblMultiplayerSessionSessionConstants\n    XblMultiplayerSessionSessionProperties\n    XblMultiplayerSessionSessionReference\n    XblMultiplayerSessionSetAllocateCloudCompute\n    XblMultiplayerSessionSetClosed\n    XblMultiplayerSessionSetCustomPropertyJson\n    XblMultiplayerSessionSetHostDeviceToken\n    XblMultiplayerSessionSetInitializationSucceeded\n    XblMultiplayerSessionSetLocked\n    XblMultiplayerSessionSetMatchmakingResubmit\n    XblMultiplayerSessionSetMatchmakingServerConnectionPath\n    XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson\n    XblMultiplayerSessionSetMutableRoleSettings\n    XblMultiplayerSessionSetRawServersJson\n    XblMultiplayerSessionSetServerConnectionStringCandidates\n    XblMultiplayerSessionSetSessionChangeSubscription\n    XblMultiplayerSessionSubscribedChangeTypes\n    XblMultiplayerSessionTimeOfSession\n    XblMultiplayerSessionWriteStatus\n    XblMultiplayerSetActivityAsync\n    XblMultiplayerSetSubscriptionsEnabled\n    XblMultiplayerSetTransferHandleAsync\n    XblMultiplayerSetTransferHandleResult\n    XblMultiplayerSubscriptionsEnabled\n    XblMultiplayerWriteSessionAsync\n    XblMultiplayerWriteSessionByHandleAsync\n    XblMultiplayerWriteSessionByHandleResult\n    XblMultiplayerWriteSessionResult\n    XblPresenceAddDevicePresenceChangedHandler\n    XblPresenceAddTitlePresenceChangedHandler\n    XblPresenceGetPresenceAsync\n    XblPresenceGetPresenceForMultipleUsersAsync\n    XblPresenceGetPresenceForMultipleUsersResult\n    XblPresenceGetPresenceForMultipleUsersResultCount\n    XblPresenceGetPresenceForSocialGroupAsync\n    XblPresenceGetPresenceForSocialGroupResult\n    XblPresenceGetPresenceForSocialGroupResultCount\n    XblPresenceGetPresenceResult\n    XblPresenceRecordCloseHandle\n    XblPresenceRecordDuplicateHandle\n    XblPresenceRecordGetDeviceRecords\n    XblPresenceRecordGetUserState\n    XblPresenceRecordGetXuid\n    XblPresenceRemoveDevicePresenceChangedHandler\n    XblPresenceRemoveTitlePresenceChangedHandler\n    XblPresenceSetPresenceAsync\n    XblPresenceStopTrackingAdditionalTitles\n    XblPresenceStopTrackingUsers\n    XblPresenceTrackAdditionalTitles\n    XblPresenceTrackUsers\n    XblPrivacyBatchCheckPermissionAsync\n    XblPrivacyBatchCheckPermissionResult\n    XblPrivacyBatchCheckPermissionResultSize\n    XblPrivacyCheckPermissionAsync\n    XblPrivacyCheckPermissionForAnonymousUserAsync\n    XblPrivacyCheckPermissionForAnonymousUserResult\n    XblPrivacyCheckPermissionForAnonymousUserResultSize\n    XblPrivacyCheckPermissionResult\n    XblPrivacyCheckPermissionResultSize\n    XblPrivacyGetAvoidListAsync\n    XblPrivacyGetAvoidListResult\n    XblPrivacyGetAvoidListResultCount\n    XblPrivacyGetMuteListAsync\n    XblPrivacyGetMuteListResult\n    XblPrivacyGetMuteListResultCount\n    XblProfileGetUserProfileAsync\n    XblProfileGetUserProfileResult\n    XblProfileGetUserProfilesAsync\n    XblProfileGetUserProfilesForSocialGroupAsync\n    XblProfileGetUserProfilesForSocialGroupResult\n    XblProfileGetUserProfilesForSocialGroupResultCount\n    XblProfileGetUserProfilesResult\n    XblProfileGetUserProfilesResultCount\n    XblRealTimeActivityAddConnectionStateChangeHandler\n    XblRealTimeActivityAddResyncHandler\n    XblRealTimeActivityRemoveConnectionStateChangeHandler\n    XblRealTimeActivityRemoveResyncHandler\n    XblRemoveServiceCallRoutedHandler\n    XblSetOverrideConfiguration\n    XblSetOverrideLocale\n    XblSocialAddSocialRelationshipChangedHandler\n    XblSocialGetSocialRelationshipsAsync\n    XblSocialGetSocialRelationshipsResult\n    XblSocialManagerAddLocalUser\n    XblSocialManagerCreateSocialUserGroupFromFilters\n    XblSocialManagerCreateSocialUserGroupFromList\n    XblSocialManagerDestroySocialUserGroup\n    XblSocialManagerDoWork\n    XblSocialManagerGetLocalUserCount\n    XblSocialManagerGetLocalUsers\n    XblSocialManagerPresenceRecordIsUserPlayingTitle\n    XblSocialManagerRemoveLocalUser\n    XblSocialManagerSetRichPresencePollingStatus\n    XblSocialManagerUpdateSocialUserGroup\n    XblSocialManagerUserGroupGetFilters\n    XblSocialManagerUserGroupGetLocalUser\n    XblSocialManagerUserGroupGetType\n    XblSocialManagerUserGroupGetUsers\n    XblSocialManagerUserGroupGetUsersTrackedByGroup\n    XblSocialRelationshipResultCloseHandle\n    XblSocialRelationshipResultDuplicateHandle\n    XblSocialRelationshipResultGetNextAsync\n    XblSocialRelationshipResultGetNextResult\n    XblSocialRelationshipResultGetRelationships\n    XblSocialRelationshipResultGetTotalCount\n    XblSocialRelationshipResultHasNext\n    XblSocialRemoveSocialRelationshipChangedHandler\n    XblSocialSubmitBatchReputationFeedbackAsync\n    XblSocialSubmitReputationFeedbackAsync\n    XblStringVerifyStringAsync\n    XblStringVerifyStringResult\n    XblStringVerifyStringResultSize\n    XblStringVerifyStringsAsync\n    XblStringVerifyStringsResult\n    XblStringVerifyStringsResultSize\n    XblTitleManagedStatsDeleteStatsAsync\n    XblTitleManagedStatsUpdateStatsAsync\n    XblTitleManagedStatsWriteAsync\n    XblTitleStorageBlobMetadataResultCloseHandle\n    XblTitleStorageBlobMetadataResultDuplicateHandle\n    XblTitleStorageBlobMetadataResultGetItems\n    XblTitleStorageBlobMetadataResultGetNextAsync\n    XblTitleStorageBlobMetadataResultGetNextResult\n    XblTitleStorageBlobMetadataResultHasNext\n    XblTitleStorageDeleteBlobAsync\n    XblTitleStorageDownloadBlobAsync\n    XblTitleStorageDownloadBlobResult\n    XblTitleStorageGetBlobMetadataAsync\n    XblTitleStorageGetBlobMetadataResult\n    XblTitleStorageGetQuotaAsync\n    XblTitleStorageGetQuotaResult\n    XblTitleStorageUploadBlobAsync\n    XblTitleStorageUploadBlobResult\n    XblUserStatisticsAddStatisticChangedHandler\n    XblUserStatisticsGetMultipleUserStatisticsAsync\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize\n    XblUserStatisticsGetMultipleUserStatisticsResult\n    XblUserStatisticsGetMultipleUserStatisticsResultSize\n    XblUserStatisticsGetSingleUserStatisticAsync\n    XblUserStatisticsGetSingleUserStatisticResult\n    XblUserStatisticsGetSingleUserStatisticResultSize\n    XblUserStatisticsGetSingleUserStatisticsAsync\n    XblUserStatisticsGetSingleUserStatisticsResult\n    XblUserStatisticsGetSingleUserStatisticsResultSize\n    XblUserStatisticsRemoveStatisticChangedHandler\n    XblUserStatisticsStopTrackingStatistics\n    XblUserStatisticsStopTrackingUsers\n    XblUserStatisticsTrackStatistics\n    XTaskQueueCloseHandle\n    XTaskQueueCreate\n    XTaskQueueCreateComposite\n    XTaskQueueDispatch\n    XTaskQueueDuplicateHandle\n    XTaskQueueGetCurrentProcessTaskQueue\n    XTaskQueueGetPort\n    XTaskQueueRegisterMonitor\n    XTaskQueueRegisterWaiter\n    XTaskQueueSetCurrentProcessTaskQueue\n    XTaskQueueSubmitCallback\n    XTaskQueueSubmitDelayedCallback\n    XTaskQueueTerminate\n    XTaskQueueUnregisterMonitor\n    XTaskQueueUnregisterWaiter\n"
  },
  {
    "path": "Build/xsapi.gdk.bwoi.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!--\n  ****************************************************************************************************\n  Properties for Gaming.*.x64\n  ****************************************************************************************************\n  -->\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true'\">\n    <DurangoXdkInstallPath>$(GameDK)</DurangoXdkInstallPath>\n    <GamingWindowsSDKDir>$(GameDKLatest)WindowsSDK\\</GamingWindowsSDKDir>\n  </PropertyGroup>\n\n  <!--\n  ****************************************************************************************************\n  _PlatformFolder build (MSBuild 15 / VS 2017 only)\n  ****************************************************************************************************\n  -->\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Xbox.XboxOne.x64' and '$(VisualStudioVersion)' == '15.0')\">\n    <_PlatformFolder>$(GameDKLatest)GXDK\\VS2017\\flatDeployment\\Common7\\IDE\\VC\\VCTargets\\Platforms\\$(Platform)\\</_PlatformFolder>\n    <DefaultXdkEditionRootVS2017>$(_PlatformFolder)</DefaultXdkEditionRootVS2017>\n    <XdkEditionRootVS2017>$(_PlatformFolder)</XdkEditionRootVS2017>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Xbox.Scarlett.x64' and '$(VisualStudioVersion)' == '15.0')\">\n    <_PlatformFolder>$(GameDKLatest)GXDK\\VS2017\\flatDeployment\\Common7\\IDE\\VC\\VCTargets\\Platforms\\$(Platform)\\</_PlatformFolder>\n    <DefaultXdkEditionRootVS2017>$(_PlatformFolder)</DefaultXdkEditionRootVS2017>\n    <XdkEditionRootVS2017>$(_PlatformFolder)</XdkEditionRootVS2017>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Desktop.x64' and '$(VisualStudioVersion)' == '15.0')\">\n    <_PlatformFolder>$(GameDKLatest)GRDK\\VS2017\\flatDeployment\\Common7\\IDE\\VC\\VCTargets\\Platforms\\$(Platform)\\</_PlatformFolder>\n    <DefaultXdkEditionRootVS2017>$(_PlatformFolder)</DefaultXdkEditionRootVS2017>\n    <XdkEditionRootVS2017>$(_PlatformFolder)</XdkEditionRootVS2017>\n  </PropertyGroup>\n\n  <!--\n  ****************************************************************************************************\n  VCTargetsPath redirection (VS 2019)\n  For VS 2019, we have to copy the contents of \n\tC:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Microsoft\\VC\\v160  \n  to a temp location, then xcopy in the files from \n\tC:\\Program Files (x86)\\Microsoft GDK\\200400\\GXDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\v160 \n  and \n    C:\\Program Files (x86)\\Microsoft GDK\\200400\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\v160\n  and do the same for the v150 for v141 downlevel\n  ****************************************************************************************************\n  -->\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true'\">\n    <_AlternativeVCTargetsPath160>$(GDKMSBuildForVS2019)v160\\</_AlternativeVCTargetsPath160>\n    <_AlternativeVCTargetsPath150>$(GDKMSBuildForVS2019)v150\\</_AlternativeVCTargetsPath150>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Xbox.XboxOne.x64' and '$(VisualStudioVersion)' == '16.0')\">\n    <VCTargetsPath>$(_AlternativeVCTargetsPath160)</VCTargetsPath>\n    <VCTargetsPath15 Condition=\"'$(_AlternativeVCTargetsPath150)'!=''\">$(_AlternativeVCTargetsPath150)</VCTargetsPath15>\n    <VCTargetsPath16>$(_AlternativeVCTargetsPath160)</VCTargetsPath16>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Xbox.Scarlett.x64' and '$(VisualStudioVersion)' == '16.0')\">\n    <VCTargetsPath>$(_AlternativeVCTargetsPath160)</VCTargetsPath>\n    <VCTargetsPath15 Condition=\"'$(_AlternativeVCTargetsPath150)'!=''\">$(_AlternativeVCTargetsPath150)</VCTargetsPath15>\n    <VCTargetsPath16>$(_AlternativeVCTargetsPath160)</VCTargetsPath16>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Desktop.x64' and '$(VisualStudioVersion)' == '16.0')\">\n    <VCTargetsPath>$(_AlternativeVCTargetsPath160)</VCTargetsPath>\n    <VCTargetsPath15 Condition=\"'$(_AlternativeVCTargetsPath150)'!=''\">$(_AlternativeVCTargetsPath150)</VCTargetsPath15>\n    <VCTargetsPath16>$(_AlternativeVCTargetsPath160)</VCTargetsPath16>\n  </PropertyGroup>\n\n  <!--\n  ****************************************************************************************************\n  VCTargetsPath redirection (VS 2022)\n  For VS 2022, we have to copy the contents of \n  C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\MSBuild\\Microsoft\\VC\\v160  \n  to a temp location, then xcopy in the files from \n  C:\\Program Files (x86)\\Microsoft GDK\\211000\\GXDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\v160 \n  and \n    C:\\Program Files (x86)\\Microsoft GDK\\211000\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\v160\n  and do the same for the v150 for v141 downlevel\n  ****************************************************************************************************\n  -->\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true'\">\n    <_AlternativeVCTargetsPath160>$(GDKMSBuildForVS2019)v160\\</_AlternativeVCTargetsPath160>\n    <_AlternativeVCTargetsPath150>$(GDKMSBuildForVS2019)v150\\</_AlternativeVCTargetsPath150>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Xbox.XboxOne.x64' and '$(VisualStudioVersion)' == '17.0')\">\n    <VCTargetsPath>$(_AlternativeVCTargetsPath160)</VCTargetsPath>\n    <VCTargetsPath15 Condition=\"'$(_AlternativeVCTargetsPath150)'!=''\">$(_AlternativeVCTargetsPath150)</VCTargetsPath15>\n    <VCTargetsPath16>$(_AlternativeVCTargetsPath160)</VCTargetsPath16>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Xbox.Scarlett.x64' and '$(VisualStudioVersion)' == '17.0')\">\n    <VCTargetsPath>$(_AlternativeVCTargetsPath160)</VCTargetsPath>\n    <VCTargetsPath15 Condition=\"'$(_AlternativeVCTargetsPath150)'!=''\">$(_AlternativeVCTargetsPath150)</VCTargetsPath15>\n    <VCTargetsPath16>$(_AlternativeVCTargetsPath160)</VCTargetsPath16>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(GDKUseBWOI)' == 'true' and ('$(Platform)' == 'Gaming.Desktop.x64' and '$(VisualStudioVersion)' == '17.0')\">\n    <VCTargetsPath>$(_AlternativeVCTargetsPath160)</VCTargetsPath>\n    <VCTargetsPath15 Condition=\"'$(_AlternativeVCTargetsPath150)'!=''\">$(_AlternativeVCTargetsPath150)</VCTargetsPath15>\n    <VCTargetsPath16>$(_AlternativeVCTargetsPath160)</VCTargetsPath16>\n  </PropertyGroup>\n\n  <!--\n  ****************************************************************************************************\n  Debugging\n   Condition=\"'$(GDKUseBWOI)' == 'true' and '$(GDKUseBWOIDebug)' == 'true'\"\n  ****************************************************************************************************\n  -->\n  <Target Name=\"XblGDKBWOIDebug\" BeforeTargets=\"InitializeBuildStatus\">\n    <Message Importance=\"High\" Text=\"XblBuildDebug\" />\n    <Message Importance=\"High\" Text=\"    ProjectName                  = '$(ProjectName)'\" />\n    <Message Importance=\"High\" Text=\"    Configuration                = '$(Configuration)'\" />\n    <Message Importance=\"High\" Text=\"    Platform                     = '$(Platform)'\" />\n    <Message Importance=\"High\" Text=\"    ConfigurationType            = '$(ConfigurationType)'\" />\n    <Message Importance=\"High\" Text=\"    PlatformToolset              = '$(PlatformToolset)'\" />\n    <Message Importance=\"High\" Text=\" \" />\n    <Message Importance=\"High\" Text=\"    GameDKLatest                 = '$(GameDKLatest)'\" />\n    <Message Importance=\"High\" Text=\"    _PlatformFolder              = '$(_PlatformFolder)'\" />\n    <Message Importance=\"High\" Text=\"    DefaultXdkEditionRootVS2017  = '$(DefaultXdkEditionRootVS2017)'\" />\n    <Message Importance=\"High\" Text=\"    XdkEditionRootVS2017         = '$(XdkEditionRootVS2017)'\" />\n    <Message Importance=\"High\" Text=\"    VCTargetsPath                = '$(VCTargetsPath)'\" />\n    <Message Importance=\"High\" Text=\"    VCTargetsPath15              = '$(VCTargetsPath15)'\" />\n    <Message Importance=\"High\" Text=\"    VCTargetsPath16              = '$(VCTargetsPath16)'\" />\n    <Message Importance=\"High\" Text=\"    DurangoXdkInstallPath        = '$(DurangoXdkInstallPath)'\" />\n    <Message Importance=\"High\" Text=\"    GamingWindowsSDKDir          = '$(GamingWindowsSDKDir)'\" />\n    <Message Importance=\"High\" Text=\"    LibraryPath          \t      = '$(LibraryPath)'\" />\n    <Message Importance=\"High\" Text=\"    IncludePath                  = '$(IncludePath)'\" />\n    <Message Importance=\"High\" Text=\"    ExecutablePath               = '$(ExecutablePath)'\" />\n    <Message Importance=\"High\" Text=\" \" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "Build/xsapi.gdk.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!-- This file is a replacement for Microsoft.Cpp.Default.Props and Microsoft.Cpp.props for Cpp projects targeting GDK -->\n  <Import Project=\"..\\xsapi.paths.props\" />\n  <!--Bring in LHC build config-->\n  <!--Order is important here. We have to define default platform toolset before importing libHttpClient.GDK.props as it will set to v100 as default-->\n  <PropertyGroup>\n    <PlatformToolset Condition=\"'$(PlatformToolset)' == '' and $(VisualStudioVersion)==15\">v141</PlatformToolset>\n    <!--Spectre mitigation breaks the GDK BWOI builds so conditionally disable that-->\n    <SpectreMitigation Condition=\"'$(GDKUseBWOI)'=='true'\">false</SpectreMitigation>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiSourceRoot)\\External\\Xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props\" />\n  <!--Overrides to LHC build config-->\n  <PropertyGroup>\n    <OutDir>$(XsapiOutDir)</OutDir>\n    <IntDir>$(XsapiIntDir)</IntDir>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Build/xsapi.win32.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!-- This file is a replacement for Microsoft.Cpp.Default.Props and Microsoft.Cpp.props for Cpp projects targeting Win32 -->\n  <Import Project=\"..\\xsapi.paths.props\" />\n  <!--Bring in LHC build config-->\n  <!--Order is important here. We have to define default platform toolset before importing libHttpClient.Win32.props as it will set to v100 as default-->\n  <PropertyGroup>\n    <PlatformToolset Condition=\"'$(PlatformToolset)' == '' and $(VisualStudioVersion)==15\">v141</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiSourceRoot)\\External\\Xal\\External\\libHttpClient\\Build\\libHttpClient.Win32.props\" />\n  <!--Overrides to LHC build config-->\n  <PropertyGroup>\n    <OutDir>$(XsapiOutDir)</OutDir>\n    <IntDir>$(XsapiIntDir)</IntDir>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guidelines\n\nThere are many different ways in which you can contribute! Please submit issues, questions, bug reports, feature requests, bug fixes, improvements, and new features.\n\n### Report bugs and request features\n\nIssues and feature requests are submitted through the project's [issue tracker](../issues) section on GitHub. Please use the following guidelines when you submit issues and feature requests:\n\n*   Make sure the issue is not already reported by searching through the list of issues\n*   Provide a detailed description of the issue including the following information:\n    *   Which feature the issue appears in\n    *   Under what circumstances the issue appears\n    *   What is the desired behavior\n    *   What is breaking\n    *   What is the impact (things like loss or corruption of data, compromising security, disruption of service etc.)\n    *   Any code that will be helpful to reproduce the issue\n\n### Create bug fixes and features\n\nPlease submit any changes as a Pull Request against the development branch. Make sure to write a detailed message describing the changes in the Pull Request. This will help us quickly determine what changes (if any) need to be made for it to be ready for integration.\n\n_Note: Please keep in mind that not all requests will be approved. Requests are reviewed by the team on a regular basis and will be updated with the status at each review. If your request is accepted you will receive information about the next steps and when the request will be integrated in the development branch. If your request is rejected you will receive information about the reasons why it was rejected._  \n\n### Contribution guidelines\n\nBefore you start working on bug fixes and features it is good idea to discuss those broadly with the community. You can use the [issue tracker](../issues) for this purpose. Before submitting your changes make sure you followed the guidelines below:\n\n*   You have properly documented any new functionality\n*   For any new functionality you have written complete unit tests\n*   You have run all unit tests and they pass\n*   In order to speed up the process of accepting your contributions, you should try to make your checkins as small as possible, avoid any unnecessary deltas and the need to rebase."
  },
  {
    "path": "Custom.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <Choose>\n    <When Condition=\"'$(OutputSubDir)' != ''\" />  <!-- don't override one already defined -->\n\n    <Otherwise>\n      <PropertyGroup>\n        <OutputSubDir>$(MSBuildProjectName)</OutputSubDir>\n      </PropertyGroup>\n    </Otherwise>\n  </Choose>\n\n  <PropertyGroup>\n    <VS_AndroidHome Condition=\"'$(VS_AndroidHome)' == ''\">$(Registry:HKEY_LOCAL_MACHINE\\SOFTWARE\\Android SDK Tools@Path)</VS_AndroidHome>\n    <VS_AndroidHome Condition=\"'$(VS_AndroidHome)' == ''\">$(Registry:HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Android SDK Tools@Path)</VS_AndroidHome>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "Directory.Packages.props",
    "content": "<Project>\n  <PropertyGroup>\n    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageVersion Include=\"Microsoft.Toolkit.Wpf.UI.Controls.WebView\" Version=\"6.1.2\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "External/Xal/README",
    "content": "This repository only contains the public headers for the Xbox Authentication Library (XAL), the same headers shipped as part of the GDK. Full source for XAL is not publicly available at this time. \n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <httpClient/async.h>\n#include <Xal/xal_types.h>\n#include <Xal/xal_user.h>\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// User model\n//-----------------------------------------------------------------------------\n\n/// <summary>\n/// Initializes Xal, must be called before any other Xal functions (except\n/// XalMemSetFunctions, XalMemGetFunctions and XalPlatform*SetHandler).\n/// </summary>\n/// <param name=\"args\">The initialization arguments for Xal,\n/// <see cref=\"XalInitArgs\" />.</param>\n/// <param name=\"internalWorkQueue\">The async queue Xal should use for internal\n/// only work such as telemetry and asynchronous init work. Only the work side\n/// of the queue will be used.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Depending on the platform, some of the platform event handlers defined in\n/// xal_platform.h may be required, in which case they should be set before\n/// calling this function. If any required event handlers are missing\n/// XalInitialize will fail with E_XAL_MISSINGPLATFORMEVENTHANDLER.\n///\n/// It is never an error to set a platform event handler that is not required.\n/// </remarks>\nSTDAPI XalInitialize(\n    _In_ XalInitArgs const* args,\n    _In_opt_ XTaskQueueHandle internalWorkQueue\n) noexcept;\n\n/// <summary>\n/// Cleans up Xal, after this function returns Xal will be in the same state as\n/// if XalInit was never called.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This functions should only be called when all user handles have been closed\n/// and there are no outstanding asynchronous operations.\n/// </remarks>\nSTDAPI XalCleanupAsync(\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a successful XalCleanupAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalCleanupResult(\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the maximum number of users that can be added at the same time on the\n/// current platform.\n/// </summary>\n/// <param name=\"maxUsers\">The maximum number of concurrent users.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\nSTDAPI XalGetMaxUsers(\n    _Out_ uint32_t* maxUsers\n) noexcept;\n\n/// <summary>\n/// Get the Xbox Live title ID that Xal was initialized with. Must be called\n/// after XalInitialize.\n/// </summary>\n/// <param name=\"titleId\">The Xbox Live title ID.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\nSTDAPI XalGetTitleId(\n    _Out_ uint32_t* titleId\n) noexcept;\n\n/// <summary>\n/// Get the size of the buffer needed to store the Xbox Live sandbox string.\n/// </summary>\n/// <returns>The size of the sandbox string including the null terminator.</returns>\nSTDAPI_(size_t) XalGetSandboxSize() noexcept;\n\n/// <summary>\n/// Get the Xbox Live sandbox that Xal was initialized with. Must be called after\n/// XalInitialize.\n/// </summary>\n/// <param name=\"sandboxSize\">The size in bytes of the sandbox buffer.\n/// Should be the value returned by XalGetSandboxSize.</param>\n/// <param name=\"sandbox\">The buffer the sandbox will be written to.</param>\n/// <param name=\"sandboxUsed\">The number of bytes used in the buffer including\n/// the null terminator.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\nSTDAPI XalGetSandbox(\n    _In_ size_t sandboxSize,\n    _Out_writes_(sandboxSize) char* sandbox,\n    _Out_opt_ size_t* sandboxUsed\n) noexcept;\n\n/// <summary>\n/// Attempts to add a user without showing any ui.\n/// </summary>\n/// <param name=\"userIdentifier\">Client provided identifier for the user.\n/// </param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// userIdentifier will be stored in the user and passed to all XalPlatform*\n/// callbacks related to this user.\n/// </remarks>\nSTDAPI XalTryAddDefaultUserSilentlyAsync(\n    _In_ uint32_t userIdentifier,\n    _In_ XAsyncBlock* async\n) noexcept;\n/// <summary>\n/// Get the result of a successful XalTryAddDefaultUserSilentlyAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"newUser\">The user that was just added.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// If the operations failed, newUser will be NULL.\n/// </remarks>\nSTDAPI XalTryAddDefaultUserSilentlyResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XalUserHandle* newUser\n) noexcept;\n\n/// <summary>\n/// Attempts to add a user with the given Xbox user id.\n/// </summary>\n/// <param name=\"userIdentifier\">Client provided identifier for the user.\n/// </param>\n/// <param name=\"xboxUserId\">The Xbox user id.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This function may show ui to the user.\n///\n/// userIdentifier will be stored in the user and passed to all XalPlatform*\n/// callbacks related to this user.\n/// </remarks>\nSTDAPI XalTryAddUserByIdAsync(\n    _In_ uint32_t userIdentifier,\n    _In_ uint64_t xboxUserId,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a successful XalTryAddUserByIdAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"newUser\">The user that was just added.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// If the operations failed, newUser will be NULL.\n/// </remarks>\nSTDAPI XalTryAddUserByIdResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XalUserHandle* newUser\n) noexcept;\n\n/// <summary>\n/// Attempts to add a user.\n/// </summary>\n/// <param name=\"userIdentifier\">Client provided identifier for the user.\n/// </param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This function will show ui to the user.\n///\n/// userIdentifier will be stored in the user and passed to all XalPlatform*\n/// callbacks related to this user.\n/// </remarks>\nSTDAPI XalAddUserWithUiAsync(\n    _In_ uint32_t userIdentifier,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a successful XalAddUserWithUiAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"newUser\">The user that was just added.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// If the operations failed, newUser will be NULL.\n/// </remarks>\nSTDAPI XalAddUserWithUiResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XalUserHandle* newUser\n) noexcept;\n\n/// <summary>\n/// Checks if the current platform supports retrieving a device user handle.\n/// </summary>\n/// <returns>True if device user present, false if not.</returns>\nSTDAPI_(bool) XalGetDeviceUserIsPresent() noexcept;\n\n/// <summary>\n/// Returns a user which represents the device itself.\n/// </summary>\n/// <param name=\"deviceUser\">The user object.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\n/// <remarks>\n/// This user handle will have had XalUserDuplicateHandle called on it. Be sure\n/// to call XalUserCloseHandle once it is no longer needed.\n/// </remarks>\nSTDAPI XalGetDeviceUser(\n    _Out_ XalUserHandle* deviceUser\n) noexcept;\n\n/// <summary>\n/// Checks if the user can be signed out on the current platform.\n/// </summary>\n/// <returns>True if user can be signed out, false if user can't.</returns>\nSTDAPI_(bool) XalSignOutUserAsyncIsPresent() noexcept;\n\n/// <summary>\n/// Signs out a user from the device.\n/// </summary>\n/// <param name=\"user\">The user to remove.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// User sign out may not be present on all platforms, on platforms where it is\n/// missing this function will return E_XAL_FEATURENOTPRESENT. To query if user\n/// sign out is available see <see cref=\"XalSignOutUserAsyncIsPresent\"/>.\n///\n/// On some platforms this call may fail to sign out the user if there is no\n/// internet connectivity, if that happens the user will not be removed from the\n/// user set and will still be fully signed in.\n///\n/// On platforms that use the web ui hooks\n/// (see <see cref=\"XalPlatformWebShowUrlEventHandler\"/>) this function will\n/// invoke the hook.\n/// </remarks>\nSTDAPI XalSignOutUserAsync(\n    _In_ XalUserHandle user,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a given XalSignOutUserAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalSignOutUserResult(\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Tries to find a user for the given local id.\n/// </summary>\n/// <param name=\"localId\">The local id it to look up.</param>\n/// <param name=\"user\">The user object.</param>\n/// <returns>Result code for this API operation. Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\n/// <remarks>\n/// If no user can be found matching the local id, E_XAL_USERNOTFOUND is returned.\n/// </remarks>\nSTDAPI XalFindUserByLocalId(\n    _In_ XalUserLocalId localId,\n    _Out_ XalUserHandle* user\n) noexcept;\n\n/// <summary>\n/// Checks if the given consent is opted in by all the users in the user set.\n/// </summary>\n/// <param name=\"consentModelName\">The UCS consent model name.</param>\n/// <param name=\"canOptIn\">True if all the users in the user set are opted in.</param>\n/// <returns>Result code for this API operation. Possible values are S_OK,\n/// E_XAL_NOTINITIALIZED, E_XAL_UNLISTEDCONSENT, or E_FAIL.</returns>\nSTDAPI XalCheckUcsConsentForAllUsers(\n    _In_z_ char const* consentModelName,\n    _Out_ bool* canOptIn\n) noexcept;\n\n}\n\n// Back compat apis\n#if XAL_ENABLE_BACK_COMPAT_SHIMS\n/// <summary>\n/// Attempts to add a user without showing any ui.\n/// </summary>\n/// <param name=\"userContext\">Must be null.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This version of the api is deprecated, consider the variant taking a\n/// uint32_t userIdentifier instead.\n/// </remarks>\ninline\nHRESULT XalTryAddDefaultUserSilentlyAsync(\n    _In_opt_ nullptr_t /*userContext*/,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XalTryAddDefaultUserSilentlyAsync(0u, async);\n}\n\n/// <summary>\n/// Attempts to add a user.\n/// </summary>\n/// <param name=\"userContext\">Must be null.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This version of the api is deprecated, consider the variant taking a\n/// uint32_t userIdentifier instead.\n///\n/// This function will show ui to the user.\n/// </remarks>\ninline\nHRESULT XalAddUserWithUiAsync(\n    _In_opt_ nullptr_t /*userContext*/,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XalAddUserWithUiAsync(0u, async);\n}\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include <Xal/xal_gsdk_impl.h>\n#elif HC_PLATFORM == HC_PLATFORM_XDK\n#include <Xal/xal_xdk_ext.h>\n#endif\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_android.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <jni.h>\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Important Information About Xal For Android\n//------------------------------------------------------------------------------\n//\n// Xal on Android has several hard requirements for how it is used with JNI.\n// Xal functions may fail if these requirements are not met.\n//\n// First and foremost, XalInitialize must be called from a thread which\n// originated from Java. If this does not happen, Xal will not be able to load\n// any of the java classes its Android implementation depends on.\n//\n// Xal also expects the client to be responsible for attaching and detaching\n// threads to the Java Virtual Machine. Any thread Xal is running on for\n// Android should be attached to the Java VM. This is done to save the cost of\n// repeatedly attaching and detaching to the Java VM.\n// The recommended pattern for threads that may need to do JNI calls, including\n// the ones that Xal will be run on, is to attach when the thread starts and\n// detach just before the thread terminates.\n//\n// Xal is configured to work with JNI_VERSION_1_6. Therefore this should be the\n// return value of the JNI_OnLoad value exported by the native library which\n// consumes Xal. More information about JNI_OnLoad can be found in the JNI\n// invocation documentation.\n\n//------------------------------------------------------------------------------\n// Android types\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Struct that encapsulates the Android specific settings for Xal.\n/// </summary>\ntypedef struct XalAndroidArgs\n{\n    /// <summary>\n    /// MSA client id\n    /// </summary>\n    _Field_z_ char const* clientId;\n\n    /// <summary>\n    /// Xbox Live title id\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// Xbox Live sandbox\n    /// </summary>\n    _Field_z_ char const* sandbox;\n\n    /// <summary>\n    /// A bool indicating whether Xal can send diagnostic telemetry.\n    /// Setting this to true indicates to Xal that it does not have user consent\n    /// to report data about any crashes or errors it encounters during use.\n    /// If this variable is set to false, Xal assumes it can report this data.\n    /// </summary>\n    bool disableDiagnosticTelemetry;\n\n    /// <summary>\n    /// A correlation vector string for XAL to use as a base. XAL will extend\n    /// this prior to using it. This argument is optional.\n    /// </summary>\n    _Field_z_ char const* correlationVector;\n\n    /// <summary>\n    /// Xal configuration flags.\n    /// </summary>\n    uint32_t flags;\n\n    /// <summary>\n    /// The JavaVM for the application consuming Xal.\n    /// </summary>\n    JavaVM* javaVM;\n\n    /// <summary>\n    /// The Android App context for the application consuming Xal.\n    /// </summary>\n    jobject appContext;\n\n    /// <summary>\n    /// The number of consents present in the ThirdPartyConsents array.\n    /// </summary>\n    uint32_t thirdPartyConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to access Xbox Live services.\n    /// </summary>\n    _Field_size_(thirdPartyConsentCount) char const** thirdPartyConsents;\n\n    /// <summary>\n    /// The Android App custom redirect URI.\n    /// </summary>\n    _Field_z_ char const* redirectUri;\n\n    /// <summary>\n    /// The number of consents present in the ucsConsents array\n    /// </summary>\n    uint32_t ucsConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to UCS\n    /// </summary>\n    _Field_size_(ucsConsentCount) char const** ucsConsents;\n\n} XalAndroidArgs;\n\ntypedef XalAndroidArgs XalInitArgs;\n\n#define XAL_PLATFORM \"Android\"\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_apple.h",
    "content": "#pragma once\n\n#include <httpClient/config.h>\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Apple types\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Struct that encapsulates the Apple specific arguments for Xal.\n/// </summary>\ntypedef struct XalAppleArgs\n{\n    /// <summary>\n    /// MSA client id\n    /// </summary>\n    _Field_z_ char const* clientId;\n\n    /// <summary>\n    /// Xbox Live title id\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// Xbox Live sandbox\n    /// </summary>\n    _Field_z_ char const* sandbox;\n\n    /// <summary>\n    /// A bool indicating whether Xal can send diagnostic telemetry.\n    /// Setting this to true indicates to Xal that it does not have user consent\n    /// to report data about any crashes or errors it encounters during use.\n    /// If this variable is set to false, Xal assumes it can report this data.\n    /// </summary>\n    bool disableDiagnosticTelemetry;\n\n    /// <summary>\n    /// A correlation vector string for XAL to use as a base. XAL will extend\n    /// this prior to using it. This argument is optional.\n    /// </summary>\n    _Field_z_ char const* correlationVector;\n\n    /// <summary>\n    /// Xal configuration flags.\n    /// </summary>\n    uint32_t flags;\n\n    /// <summary>\n    /// The number of consents present in the ThirdPartyConsents array.\n    /// </summary>\n    uint32_t thirdPartyConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to access Xbox Live services.\n    /// </summary>\n    _Field_size_(thirdPartyConsentCount) char const** thirdPartyConsents;\n\n    /// <summary>\n    /// The app custom redirect URI. (Optional on macOS).\n    /// </summary>\n    _Field_z_ char const* redirectUri;\n\n    /// <summary>\n    /// The number of consents present in the ucsConsents array\n    /// </summary>\n    uint32_t ucsConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to UCS\n    /// </summary>\n    _Field_size_(ucsConsentCount) char const** ucsConsents;\n} XalAppleArgs;\n\ntypedef XalAppleArgs XalInitArgs;\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n#define XAL_PLATFORM \"iOS\"\n#elif HC_PLATFORM == HC_PLATFORM_MAC\n#define XAL_PLATFORM \"macOS\"\n#endif\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_generic.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Generic types\n//------------------------------------------------------------------------------\n\ntypedef struct XalGenericDeviceInfo\n{\n    _Field_z_ char const* deviceType;\n    _Field_z_ char const* osVersion;\n    _Field_z_ char const* deviceId;\n} XalGenericDeviceInfo;\n\n// TODO collapse the 2 structs? the only thing missing from this one is the\n// device type, or remove dupes from this struct and ignore it unless telemetry\n// is enabled?\ntypedef struct XalGenericTelemetryInfo\n{\n    _Field_z_ char const* appId; // TODO do we want to just use the titleId here? or the msa app id?\n    _Field_z_ char const* appVer;\n    _Field_z_ char const* osName; // TODO use the device type?\n    _Field_z_ char const* osVersion; // TODO dupe\n    _Field_z_ char const* osLocale;\n    _Field_z_ char const* deviceClass; // TODO use the device type?\n    _Field_z_ char const* deviceId; // TODO dupe\n} XalGenericTelemetryInfo;\n\n/// <summary>\n/// Struct that encapsulates the extra information Xal needs.\n/// </summary>\ntypedef struct XalGenericArgs\n{\n    /// <summary>\n    /// MSA client id\n    /// </summary>\n    _Field_z_ char const* clientId;\n\n    /// <summary>\n    /// Xbox Live title id\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// Xbox Live sandbox\n    /// </summary>\n    _Field_z_ char const* sandbox;\n\n    /// <summary>\n    /// A bool indicating whether Xal can send diagnostic telemetry.\n    /// Setting this to true indicates to Xal that it does not have user consent\n    /// to report data about any crashes or errors it encounters during use.\n    /// If this variable is set to false, Xal assumes it can report this data.\n    /// </summary>\n    bool disableDiagnosticTelemetry;\n\n    /// <summary>\n    /// A correlation vector string for XAL to use as a base. XAL will extend\n    /// this prior to using it. This argument is optional.\n    /// </summary>\n    _Field_z_ char const* correlationVector;\n\n    /// <summary>\n    /// Reserved for future use.\n    /// </summary>\n    uint32_t flags;\n\n    /// <summary>\n    /// The maximum number of users that can be signed in at the same time.\n    /// </summary>\n    uint32_t maxSignedInUsers;\n\n    /// <summary>\n    /// The number of consents present in the ThirdPartyConsents array.\n    /// </summary>\n    uint32_t thirdPartyConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to access Xbox Live services.\n    /// </summary>\n    _Field_size_(thirdPartyConsentCount) char const** thirdPartyConsents;\n\n    /// <summary>\n    /// Custom redirect URI.\n    /// </summary>\n    _Field_z_ char const* redirectUri;\n\n    /// <summary>\n    /// The number of consents present in the ucsConsents array\n    /// </summary>\n    uint32_t ucsConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to UCS\n    /// </summary>\n    _Field_size_(ucsConsentCount) char const** ucsConsents;\n\n    bool useRemoteAuth;\n\n    XalGenericDeviceInfo deviceInfo;\n    XalGenericTelemetryInfo telemetryInfo;\n} XalGenericArgs;\n\ntypedef XalGenericArgs XalInitArgs;\n\n#define XAL_PLATFORM \"Generic\"\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_gsdk.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <stdint.h>\n#include <XGameErr.h>\n#include <XUser.h>\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// GDK types\n//------------------------------------------------------------------------------\n\n#define XAL_OS_ERRORS 1\n#define XAL_OS_IMPL 1\n\ntypedef XUserHandle XalUserHandle;\n\ntypedef XUserLocalId XalUserLocalId;\n\n/// <summary>\n/// Struct that encapsulates the GDK specific arguments for Xal.\n/// </summary>\ntypedef struct XalGsdkArgs {} XalGsdkArgs;\n\ntypedef XalGsdkArgs XalInitArgs;\n\ntypedef XUserChangeEvent XalUserChangeType;\n\nXUserChangeEvent const XalUserChange_SignedInAgain = XUserChangeEvent::SignedInAgain;\nXUserChangeEvent const XalUserChange_SigningOut = XUserChangeEvent::SigningOut;\nXUserChangeEvent const XalUserChange_SignedOut = XUserChangeEvent::SignedOut;\nXUserChangeEvent const XalUserChange_Gamertag = XUserChangeEvent::Gamertag;\nXUserChangeEvent const XalUserChange_GamerPicture = XUserChangeEvent::GamerPicture;\nXUserChangeEvent const XalUserChange_Privileges = XUserChangeEvent::Privileges;\n\ntypedef XUserChangeEventCallback XalUserChangeEventHandler;\n\ntypedef XUserSignOutDeferralHandle XalSignoutDeferralHandle;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_gsdk_impl.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <atomic>\n#include <stdint.h>\n#include <XGame.h>\n#include <XSystem.h>\n#include <XUser.h>\n\nextern \"C\"\n{\n\nstatic_assert(XalUserState_SignedIn == static_cast<uint32_t>(XUserState::SignedIn), \"Xal / GDK mismatch\");\nstatic_assert(XalUserState_SigningOut == static_cast<uint32_t>(XUserState::SigningOut), \"Xal / GDK mismatch\");\nstatic_assert(XalUserState_SignedOut == static_cast<uint32_t>(XUserState::SignedOut), \"Xal / GDK mismatch\");\n\nstatic_assert(XalGamerPictureSize_Small == static_cast<uint32_t>(XUserGamerPictureSize::Small), \"Xal / GDK mismatch\");\nstatic_assert(XalGamerPictureSize_Medium == static_cast<uint32_t>(XUserGamerPictureSize::Medium), \"Xal / GDK mismatch\");\nstatic_assert(XalGamerPictureSize_Large == static_cast<uint32_t>(XUserGamerPictureSize::Large), \"Xal / GDK mismatch\");\nstatic_assert(XalGamerPictureSize_ExtraLarge == static_cast<uint32_t>(XUserGamerPictureSize::ExtraLarge), \"Xal / GDK mismatch\");\n\nstatic_assert(XalAgeGroup_Unknown == static_cast<uint32_t>(XUserAgeGroup::Unknown), \"Xal / GDK mismatch\");\nstatic_assert(XalAgeGroup_Child == static_cast<uint32_t>(XUserAgeGroup::Child), \"Xal / GDK mismatch\");\nstatic_assert(XalAgeGroup_Teen == static_cast<uint32_t>(XUserAgeGroup::Teen), \"Xal / GDK mismatch\");\nstatic_assert(XalAgeGroup_Adult == static_cast<uint32_t>(XUserAgeGroup::Adult), \"Xal / GDK mismatch\");\n\nstatic_assert(XalPrivilegeCheckDenyReasons_None == static_cast<uint32_t>(XUserPrivilegeDenyReason::None), \"Xal / GDK mismatch\");\nstatic_assert(XalPrivilegeCheckDenyReasons_PurchaseRequired == static_cast<uint32_t>(XUserPrivilegeDenyReason::PurchaseRequired), \"Xal / GDK mismatch\");\nstatic_assert(XalPrivilegeCheckDenyReasons_Restricted == static_cast<uint32_t>(XUserPrivilegeDenyReason::Restricted), \"Xal / GDK mismatch\");\nstatic_assert(XalPrivilegeCheckDenyReasons_Banned == static_cast<uint32_t>(XUserPrivilegeDenyReason::Banned), \"Xal / GDK mismatch\");\nstatic_assert(XalPrivilegeCheckDenyReasons_Unknown == static_cast<uint32_t>(XUserPrivilegeDenyReason::Unknown), \"Xal / GDK mismatch\");\n\n//------------------------------------------------------------------------------\n// xal.h\n//------------------------------------------------------------------------------\n\ninline\nHRESULT XalInitialize(\n    _In_ XalInitArgs const* /*args*/,\n    _In_opt_ XTaskQueueHandle /*internalWorkQueue*/\n) noexcept\n{\n    return S_OK;\n}\n\ninline\nHRESULT XalCleanupAsync(\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    HRESULT hr = XAsyncBegin(async, nullptr, &XalCleanupAsync, \"XalCleanupAsync\", [](\n        _In_ XAsyncOp op,\n        _In_ XAsyncProviderData const* data\n    )\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            XAsyncComplete(data->async, S_OK, 0);\n        }\n        return S_OK;\n    });\n\n    if (SUCCEEDED(hr))\n    {\n        hr = XAsyncSchedule(async, 0);\n    }\n    return hr;\n}\n\ninline\nHRESULT XalCleanupResult(\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XAsyncGetStatus(async, false);\n}\n\ninline\nHRESULT XalGetMaxUsers(\n    _Out_ uint32_t* maxUsers\n) noexcept\n{\n    return XUserGetMaxUsers(maxUsers);\n}\n\ninline\nHRESULT XalGetTitleId(\n    _Out_ uint32_t* titleId\n) noexcept\n{\n    return XGameGetXboxTitleId(titleId);\n}\n\ninline\nsize_t XalGetSandboxSize() noexcept\n{\n    return XSystemXboxLiveSandboxIdMaxBytes;\n}\n\ninline\nHRESULT XalGetSandbox(\n    _In_ size_t sandboxSize,\n    _Out_writes_(sandboxSize) char* sandbox,\n    _Out_opt_ size_t* sandboxUsed\n) noexcept\n{\n    return XSystemGetXboxLiveSandboxId(sandboxSize, sandbox, sandboxUsed);\n}\n\ninline\nHRESULT XalTryAddDefaultUserSilentlyAsync(\n    _In_ uint32_t /*userIdentifier*/, // user identifier is not used on GameCore\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserAddAsync(XUserAddOptions::AddDefaultUserSilently, async);\n}\n\ninline\nHRESULT XalTryAddDefaultUserSilentlyResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XalUserHandle* newUser\n) noexcept\n{\n    return XUserAddResult(async, newUser);\n}\n\ninline\nHRESULT XalAddUserWithUiAsync(\n    _In_ uint32_t /*userIdentifier*/, // user identifier is not used on GameCore\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserAddAsync(XUserAddOptions::None, async);\n}\n\ninline\nHRESULT XalAddUserWithUiResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XalUserHandle* newUser\n) noexcept\n{\n    return XUserAddResult(async, newUser);\n}\n\ninline\nbool XalGetDeviceUserIsPresent() noexcept\n{\n    return false;\n}\n\ninline\nHRESULT XalGetDeviceUser(\n    _Out_ XalUserHandle* /*deviceUser*/\n) noexcept\n{\n    return E_NOT_SUPPORTED;\n}\n\ninline\nbool XalSignOutUserAsyncIsPresent() noexcept\n{\n    return false;\n}\n\ninline\nHRESULT XalSignOutUserAsync(\n    _In_ XalUserHandle /*user*/,\n    _In_ XAsyncBlock* /*async*/\n) noexcept\n{\n    return E_NOT_SUPPORTED;\n}\n\ninline\nHRESULT XalSignOutUserResult(\n    _In_ XAsyncBlock* /*async*/\n) noexcept\n{\n    return E_NOT_SUPPORTED;\n}\n\ninline\nHRESULT XalFindUserByLocalId(\n    _In_ XalUserLocalId localId,\n    _Out_ XalUserHandle* user\n) noexcept\n{\n    return XUserFindUserByLocalId(localId, user);\n}\n\n//------------------------------------------------------------------------------\n// xal_user.h\n//------------------------------------------------------------------------------\n\ninline\nHRESULT XalUserDuplicateHandle(\n    _In_ XalUserHandle user,\n    _Out_ XalUserHandle* duplicatedUser\n) noexcept\n{\n    return XUserDuplicateHandle(user, duplicatedUser);\n}\n\ninline\nvoid XalUserCloseHandle(\n    _In_ XalUserHandle user\n) noexcept\n{\n    XUserCloseHandle(user);\n}\n\ninline\nint32_t XalCompareUsers(\n    _In_ XalUserHandle user1,\n    _In_ XalUserHandle user2\n) noexcept\n{\n    return XUserCompare(user1, user2);\n}\n\ninline\nHRESULT XalUserGetId(\n    _In_ XalUserHandle user,\n    _Out_ uint64_t* id\n) noexcept\n{\n    return XUserGetId(user, id);\n}\n\ninline\nHRESULT XalUserGetLocalId(\n    _In_ XalUserHandle user,\n    _Out_ XalUserLocalId* localId\n) noexcept\n{\n    HRESULT hr = XUserGetLocalId(user, localId);\n    return hr;\n}\n\ninline\nbool XalUserIsDevice(\n    _In_ XalUserHandle /*user*/\n) noexcept\n{\n    return false;\n}\n\ninline\nbool XalUserIsGuest(\n    _In_ XalUserHandle user\n) noexcept\n{\n    bool isGuest = false;\n    XUserGetIsGuest(user, &isGuest);\n    return isGuest;\n}\n\ninline\nHRESULT XalUserGetState(\n    _In_ XalUserHandle user,\n    _Out_ XalUserState* state\n) noexcept\n{\n    HRESULT hr = XUserGetState(user, reinterpret_cast<XUserState*>(state));\n    return hr;\n}\n\ninline\nsize_t XalUserGetGamertagSize(\n    _In_ XalUserHandle /*user*/,\n    _In_ XalGamertagComponent component\n) noexcept\n{\n    switch (component)\n    {\n        case XalGamertagComponent_Classic:\n            return XUserGamertagComponentClassicMaxBytes;\n        case XalGamertagComponent_Modern:\n            return XUserGamertagComponentModernMaxBytes;\n        case XalGamertagComponent_ModernSuffix:\n            return XUserGamertagComponentModernSuffixMaxBytes;\n        case XalGamertagComponent_UniqueModern:\n            return XUserGamertagComponentUniqueModernMaxBytes;\n        default:\n            return 0;\n    }\n}\n\ninline\nHRESULT XalUserGetGamertag(\n    _In_ XalUserHandle user,\n    _In_ XalGamertagComponent component,\n    _In_ size_t gamertagSize,\n    _Out_writes_(gamertagSize) char* gamertag,\n    _Out_opt_ size_t* gamertagUsed\n) noexcept\n{\n    return XUserGetGamertag(user, static_cast<XUserGamertagComponent>(component), gamertagSize, gamertag, gamertagUsed);\n}\n\ninline\nHRESULT XalUserGetGamerPictureAsync(\n    _In_ XalUserHandle user,\n    _In_ XalGamerPictureSize pictureSize,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserGetGamerPictureAsync(user, static_cast<XUserGamerPictureSize>(pictureSize), async);\n}\n\ninline\nHRESULT XalUserGetGamerPictureResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept\n{\n    return XUserGetGamerPictureResultSize(async, bufferSize);\n}\n\ninline\nHRESULT XalUserGetGamerPictureResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_(bufferSize) void* buffer\n) noexcept\n{\n    return XUserGetGamerPictureResult(async, bufferSize, buffer, nullptr);\n}\n\ninline\nHRESULT XalUserGetAgeGroup(\n    _In_ XalUserHandle user,\n    _Out_ XalAgeGroup* ageGroup\n) noexcept\n{\n    HRESULT hr = XUserGetAgeGroup(user, reinterpret_cast<XUserAgeGroup*>(ageGroup));\n    return hr;\n}\n\ninline\nHRESULT XalUserCheckPrivilege(\n    _In_ XalUserHandle user,\n    _In_ XalPrivilege privilege,\n    _Out_ bool* hasPrivilege,\n    _Out_opt_ XalPrivilegeCheckDenyReasons* reasons\n) noexcept\n{\n    HRESULT hr = XUserCheckPrivilege(\n        user,\n        XUserPrivilegeOptions::None,\n        static_cast<XUserPrivilege>(privilege),\n        hasPrivilege,\n        reinterpret_cast<XUserPrivilegeDenyReason*>(reasons)\n    );\n\n    return hr;\n}\n\ninline\nbool XalUserResolvePrivilegeWithUiIsPresent() noexcept\n{\n    return true;\n}\n\ninline\nHRESULT XalUserResolveUserPrivilegeWithUiAsync(\n    _In_ XalUserHandle user,\n    _In_ XalPrivilege privilege,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserResolvePrivilegeWithUiAsync(\n        user,\n        XUserPrivilegeOptions::None,\n        static_cast<XUserPrivilege>(privilege),\n        async\n    );\n}\n\ninline\nHRESULT XalUserResolveUserPrivilegeWithUiResult(\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserResolvePrivilegeWithUiResult(async);\n}\n\ninline\nHRESULT XalUserGetTokenAndSignatureSilentlyAsync(\n    _In_ XalUserHandle user,\n    _In_ XalUserGetTokenAndSignatureArgs const* args,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    static_assert(sizeof(XalHttpHeader) == sizeof(XUserGetTokenAndSignatureHttpHeader), \"Xal / GDK mismatch\");\n\n    XUserGetTokenAndSignatureOptions opts = XUserGetTokenAndSignatureOptions::None;\n    if (args->forceRefresh)\n    {\n        opts |= XUserGetTokenAndSignatureOptions::ForceRefresh;\n    }\n    if (args->allUsers)\n    {\n        opts |= XUserGetTokenAndSignatureOptions::AllUsers;\n    }\n\n    return XUserGetTokenAndSignatureAsync(\n        user,\n        opts,\n        args->method,\n        args->url,\n        args->headerCount,\n        reinterpret_cast<const XUserGetTokenAndSignatureHttpHeader*>(args->headers),\n        args->bodySize,\n        args->body,\n        async\n    );\n}\n\ninline\nHRESULT XalUserGetTokenAndSignatureSilentlyResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept\n{\n    return XUserGetTokenAndSignatureResultSize(async, bufferSize);\n}\n\ninline\nHRESULT XalUserGetTokenAndSignatureSilentlyResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XalUserGetTokenAndSignatureData** result,\n    _Out_opt_ size_t* bufferUsed\n) noexcept\n{\n    static_assert(sizeof(XalUserGetTokenAndSignatureData) == sizeof(XUserGetTokenAndSignatureData), \"Xal / GDK mismatch\");\n\n    return XUserGetTokenAndSignatureResult(\n        async,\n        bufferSize,\n        buffer,\n        reinterpret_cast<XUserGetTokenAndSignatureData**>(result),\n        bufferUsed\n    );\n}\n\ninline\nHRESULT XalUserResolveIssueWithUiAsync(\n    _In_ XalUserHandle user,\n    _In_opt_z_ char const* url,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserResolveIssueWithUiAsync(user, url, async);\n}\n\ninline\nHRESULT XalUserResolveIssueWithUiResult(\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    return XUserResolveIssueWithUiResult(async);\n}\n\ninline\nHRESULT XalUserRegisterChangeEventHandler(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_opt_ void* context,\n    _In_ XalUserChangeEventHandler* handler,\n    _Out_ XalRegistrationToken* token\n) noexcept\n{\n    static_assert(sizeof(XalRegistrationToken) == sizeof(XTaskQueueRegistrationToken), \"Xal / GDK mismatch\");\n    static_assert(sizeof(XalRegistrationToken::token) == sizeof(XTaskQueueRegistrationToken::token), \"Xal / GDK mismatch\");\n\n    return XUserRegisterForChangeEvent(\n        queue,\n        context,\n        handler,\n        reinterpret_cast<XTaskQueueRegistrationToken*>(token)\n    );\n}\n\ninline\nvoid XalUserUnregisterChangeEventHandler(\n    _In_ XalRegistrationToken token\n) noexcept\n{\n    XTaskQueueRegistrationToken gdkToken{ token.token };\n    XUserUnregisterForChangeEvent(gdkToken, true);\n}\n\ninline\nHRESULT XalUserGetSignoutDeferral(\n    _Out_ XalSignoutDeferralHandle* deferral\n) noexcept\n{\n    return XUserGetSignOutDeferral(deferral);\n}\n\ninline\nvoid XalUserCloseSignoutDeferral(\n    _In_ XalSignoutDeferralHandle deferral\n) noexcept\n{\n    XUserCloseSignOutDeferralHandle(deferral);\n}\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_internal_marketing.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n// Attention: This file is intended for internal uses only.\n// Its use is not recommended and not supported.\n\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n//-----------------------------------------------------------------------------\n// Marketing State\n//-----------------------------------------------------------------------------\n\n/// <summary>\n/// Enum defining the various marketing states.\n/// </summary>\ntypedef enum XalMarketingState\n{\n    /// <summary>Existing user</summary>\n    XalMarketingState_ExistingUser = 0,\n    /// <summary>User went through account creation</summary>\n    XalMarketingState_NewUser = 1,\n    /// <summary>User went through account creation and saw the first party marketing notice</summary>\n    XalMarketingState_NewUserFirstPartyNotice = 2,\n} XalMarketingState;\n\nSTDAPI XalUserGetMarketingState(\n    _In_ XalUserHandle user,\n    _Out_ XalMarketingState* marketingState\n) noexcept;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_internal_telemetry.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n// Attention: This file is intended for internal uses only.\n// Its use is not recommended and not supported.\n\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// Telemetry\n//-----------------------------------------------------------------------------\n\n/// <summary>\n/// Controls if the event is to be uploaded immediately or can be batched.\n/// </summary>\n/// <remarks>\n/// This is a copy of MAE::EventLatency and should be kept in sync with it.\n/// </remarks>\ntypedef enum XalTelemetryLatency\n{\n    XalTelemetryLatency_Unspecified = -1,\n    XalTelemetryLatency_Off = 0,\n    XalTelemetryLatency_Normal = 0x0100,\n    XalTelemetryLatency_CostDeferred = 0x0200,\n    XalTelemetryLatency_Realtime = 0x0300,\n    XalTelemetryLatency_Max = 0x0400,\n} XalTelemetryLatency;\n\n/// <summary>\n/// Controls the priority of keeping the event in case 1DS needs to evict some.\n/// </summary>\n/// <remarks>\n/// This is a copy of MAE::EventPersistence and should be kept in sync with it.\n/// </remarks>\ntypedef enum XalTelemetryPersistence\n{\n    XalTelemetryPersistence_Normal = 0x00,\n    XalTelemetryPersistence_Critical = 0x01,\n    XalTelemetryPersistence_DoNotStoreOnDisk = 0x02,\n} XalTelemetryPersistence;\n\n/// <summary>\n/// Controls the sampling rate of the event.\n/// </summary>\ntypedef enum XalTelemetrySampleRate\n{\n    XalTelemetrySampleRate_Unspecified = 0,\n    XalTelemetrySampleRate_NoSampling = 1,\n    XalTelemetrySampleRate_10_percent = 2,\n    XalTelemetrySampleRate_0_percent = 3,\n} XalTelemetrySampleRate;\n\n/// <summary>\n/// Describes the type of a ticket.\n/// </summary>\ntypedef enum XalTelemetryTicketType\n{\n    //XalTelemetryTicketType_Unspecified = 0,   // currently unsupported\n    //XalTelemetryTicketType_MsaUser = 0x01,    // currently unsupported\n    //XalTelemetryTicketType_MsaDevice = 0x02,  // currently unsupported\n    XalTelemetryTicketType_XauthUser = 0x03,\n    XalTelemetryTicketType_XauthDevice = 0x04\n} XalTelemetryTicketType;\n\n/// <summary>\n/// Describes a ticket that should be included with a telemetry event.\n/// </summary>\ntypedef struct XalTelemetryTicket\n{\n    /// <summary>\n    /// The url for the ticket audience.\n    /// </summary>\n    _Field_z_ char const* Url;\n\n    /// <summary>\n    /// The ticket id.\n    /// </summary>\n    uint32_t Id;\n\n    /// <summary>\n    /// The type of ticket.\n    /// </summary>\n    XalTelemetryTicketType Type;\n} XalTelemetryTicket;\n\n/// <summary>\n/// A method to write a telemetry event and send it to vortex.\n/// </summary>\n/// <param name=\"user\">The user to send this event for.</param>\n/// <param name=\"iKey\">The game's iKey.</param>\n/// <param name=\"eventNameWithProvider\">The null terminated event name string. This will be the \n/// full name of the event with the provider prefix.</param>\n/// <param name=\"data\">The null terminated event data string. The string should\n/// be properly formatted JSON.</param>\n/// <param name=\"ticketCount\">The number of tickets to send with the event.</param>\n/// <param name=\"tickets\">Information about the tickets to send.</param>\n/// <param name=\"latency\">The 1DS latency for this event.</param>\n/// <param name=\"persistence\">The 1DS persistence for this event.</param>\n/// <param name=\"sampleRate\">The 1DS sampleRate for this event.</param>\nSTDAPI XalTelemetryWriteEvent(\n    _In_ XalUserHandle user,\n    _In_z_ char const* iKey,\n    _In_z_ char const* eventNameWithProvider,\n    _In_z_ char const* data,\n    _In_ uint32_t ticketCount,\n    _In_reads_(ticketCount) XalTelemetryTicket* tickets,\n    _In_ XalTelemetryLatency latency,\n    _In_ XalTelemetryPersistence persistence,\n    _In_ XalTelemetrySampleRate sampleRate\n) noexcept;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_internal_types.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n// Attention: This file is intended for internal uses only.\n// Its use is not recommended and not supported.\n\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Xal init flags\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Flag that instructs Xal to attempt to use cached MSA refresh tokens from Xsapi to\n/// silently sign existing users in. Do not use this flag unless you have been\n/// instructed to do so.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Android and iOS device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_MIGRATE_XSAPI_USER_TOKENS = 1u;\n\n/// <summary>\n/// Flag that instructs Xal that your app is set up for FOCI token sharing and to attempt\n/// to use FOCI SSO. If your app is not set up for FOCI do not set this flag.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Win32, Android, iOS, Mac, and generic device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_USE_FOCI = 1u << 24;\n\n/// <summary>\n/// Flag that provides a hint to Xal that your app is allowed to sign out the user on the\n/// UWP platform. Note that setting this does not give your app permission to sign\n/// out the user, but only acts as clue for Xal that you have that permission.\n/// </summary>\n/// <remarks>\n/// This flag is supported on UWP device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_ALLOW_UWP_SIGNOUT = 1u << 25;\n\n/// <summary>\n/// Flag to disable SSO browser usage on platforms where a secure browser exists.\n/// This flag is provided for testing purposes only.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Android and iOS device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_USE_IN_PROC_BROWSER = 1u << 27;\n\n/// <summary>\n/// Flag to tell XAL to use file storage for token storage on Win32 platforms instead of the Windows\n/// Credential Manager. Using this flag will break many SSO scenarios.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Win32 device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_WIN32_USE_FILE_STORAGE = 1u << 28;\n\n/// <summary>\n/// Flag to instruct Xal to use the beta Xbox service cloud.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Win32, Android, iOS, Mac, and generic device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_USE_BETA_SERVICES_FLAG = 1u << 29;\n\n/// <summary>\n/// Flag to instruct Xal to use the 1st party auth flow.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Win32, UWP, Android, iOS, Mac, and generic device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_TITLE_TYPE_FIRST_PARTY_FLAG = 1u << 31;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_internal_web_account.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n// Attention: This file is intended for internal uses only.\n// Its use is not recommended and not supported.\n\n#include <httpClient/async.h>\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// User properties\n\n/// <summary>\n/// Returns the size of the buffer needed to store the web account ID string.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\nSTDAPI_(size_t) XalUserGetWebAccountIdSize(\n    _In_ XalUserHandle user\n) noexcept;\n\n/// <summary>\n/// Returns the web account ID of the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"webAccountIdSize\">The size in bytes of the webAccountId buffer.\n/// Should be the value returned by XalUserGetWebAccountIdSize.</param>\n/// <param name=\"webAccountId\">The buffer the web account ID will be written to.\n/// </param>\n/// <param name=\"webAccountIdUsed\">The number of bytes used in the buffer\n/// including the null terminator.</param>\nSTDAPI XalUserGetWebAccountId(\n    _In_ XalUserHandle user,\n    _In_ size_t webAccountIdSize,\n    _Out_writes_(webAccountIdSize) char* webAccountId,\n    _Out_opt_ size_t* webAccountIdUsed\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Get web account token\n\n/// <summary>\n/// Struct that represents a parameter that has a key and a value for web account APIs.\n/// </summary>\ntypedef struct XalWebAccountParameter\n{\n    /// <summary>Parameter name.</summary>\n    _Field_z_ char const* name;\n\n    /// <summary>Parameter value.</summary>\n    _Field_z_ char const* value;\n} XalWebAccountParameter;\n\n/// <summary>\n/// Struct that encapsulates the arguments for XalUserGetWebAccountTokenSilentlyAsync.\n/// </summary>\n/// <remarks>\n/// Xal will copy the data before XalUserGetWebAccountTokenSilentlyAsync returns.\n/// </remarks>\ntypedef struct XalUserGetWebAccountTokenArgs\n{\n    /// <summary>\n    /// The token scope string being requested.\n    /// </summary>\n    _Field_z_ char const* Scope;\n\n    /// <summary>\n    /// Ignore cached tokens.\n    /// </summary>\n    /// <remarks>\n    /// This flag should only be set if an http request using a previously\n    /// fetched token failed with a 401 error. In that case the entire call\n    /// should be retried after getting a new token using this flag.\n    /// </remarks>\n    bool ForceRefresh;\n\n    /// <summary>\n    /// The number of request parameters that will be added to the token request.\n    /// </summary>\n    uint32_t parameterCount;\n\n    /// <summary>\n    /// The array of request parameters that will be added to the token request.\n    /// </summary>\n    _Field_size_(parameterCount) XalWebAccountParameter const* requestParameters;\n} XalUserGetWebAccountTokenArgs;\n\n/// <summary>\n/// Gets a token with the specified scope for the user without showing UI.\n/// </summary>\n/// <param name=\"user\">The user the token is for.</param>\n/// <param name=\"args\">The requested token details.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <see cref=\"XalUserGetWebAccountTokenArgs\" />.\nSTDAPI XalUserGetWebAccountTokenSilentlyAsync(\n    _In_ XalUserHandle user,\n    _In_ XalUserGetWebAccountTokenArgs const* args,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Gets the size in bytes of the web account token result buffer.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size in bytes for the result buffer.</param>\nSTDAPI XalUserGetWebAccountTokenSilentlyResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept;\n\n/// <summary>\n/// Gets the results of a successful XalUserGetWebAccountTokenSilentlyAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the buffer for the result object.\n/// </param>\n/// <param name=\"result\">The result token.</param>\nSTDAPI XalUserGetWebAccountTokenSilentlyResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_z_(bufferSize) char* result\n) noexcept;\n\n/// <summary>\n/// Gets a token with the specified scope for the user showing UI if necessary.\n/// </summary>\n/// <param name=\"user\">The user the token is for.</param>\n/// <param name=\"args\">The requested token details.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <see cref=\"XalUserGetWebAccountTokenArgs\" />.\nSTDAPI XalUserGetWebAccountTokenWithUiAsync(\n    _In_ XalUserHandle user,\n    _In_ XalUserGetWebAccountTokenArgs const* args,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Gets the size in bytes of the web account token result buffer.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size in bytes for the result buffer.</param>\nSTDAPI XalUserGetWebAccountTokenWithUiResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept;\n\n/// <summary>\n/// Gets the results of a successful XalUserGetWebAccountTokenWithUiAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the buffer for the result object.\n/// </param>\n/// <param name=\"result\">The result token.</param>\nSTDAPI XalUserGetWebAccountTokenWithUiResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_z_(bufferSize) char* result\n) noexcept;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_platform.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <httpClient/async.h>\n#include <Xal/xal_platform_types.h>\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// Hooks for platform specific behaviour\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// Memory (optional on all platforms)\n\n/// <summary>\n/// Sets the memory hook functions to allow callers to route memory allocations\n/// to their own memory manager. This must be called before XalInitialize and\n/// cannot be called again until after XalCleanup and all XAL_USER_HANDLEs have\n/// been closed.\n///\n/// This method allows the application to install custom memory allocation\n/// routines in order to service all requests for new memory buffers instead of\n/// using default allocation routines.\n///\n/// The <paramref name=\"memAllocFunc\" /> and <paramref name=\"memFreeFunc\" />\n/// parameters can be null pointers to restore the default routines. Both\n/// callback pointers must be null or both must be non-null. Mixing custom and\n/// default routines is not permitted and will cause the function to fail.\n/// </summary>\n/// <param name=\"memAllocFunc\">A pointer to the custom allocation callback to\n/// use, or a null pointer to restore the default.</param>\n/// <param name=\"memFreeFunc\">A pointer to the custom freeing callback to use,\n/// or a null pointer to restore the default.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalMemSetFunctions(\n    _In_opt_ XalMemAllocFunc* memAllocFunc,\n    _In_opt_ XalMemFreeFunc* memFreeFunc\n) noexcept;\n\n/// <summary>\n/// Gets the memory hook functions to allow callers to route memory allocations\n/// to their own memory manager. This method allows the application get the\n/// default memory allocation routines. This can be used along with\n/// XalMemSetFunctions to monitor all memory allocations.\n/// </summary>\n/// <param name=\"memAllocFunc\">Set to the current allocation callback. Returns\n/// the default routine if not previously set.</param>\n/// <param name=\"memFreeFunc\">Set to the to the current memory free callback.\n/// Returns the default routine if not previously set.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalMemGetFunctions(\n    _Out_ XalMemAllocFunc** memAllocFunc,\n    _Out_ XalMemFreeFunc** memFreeFunc\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Web view (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Registers the show url event handler.\n/// </summary>\n/// <param name=\"queue\">The async queue the callback should be invoked on.\n/// </param>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"handler\">The event handler,\n/// <see cref=\"XalPlatformWebShowUrlEventHandler\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\nSTDAPI XalPlatformWebSetEventHandler(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_opt_ void* context,\n    _In_ XalPlatformWebShowUrlEventHandler2* handler\n) noexcept;\n\n/// <summary>\n/// Clears the show url event handler.\n/// </summary>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize or after XalCleanupAsync completes.\n/// </remarks>\nSTDAPI XalPlatformWebClearEventHandler() noexcept;\n\n/// <summary>\n/// Completes a show url operation.\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <param name=\"url\">The full url for the final redirection.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This should only be called in response to a show url event, once the web\n/// view is redirected to the final url or if an error occurs and the operation\n/// cannot be completed.\n/// <see cref=\"XalPlatformWebShowUrlEventHandler\"/>\n/// </remarks>\nSTDAPI XalPlatformWebShowUrlComplete(\n    _In_ XalPlatformOperation operation,\n    _In_ XalPlatformOperationResult result,\n    _In_opt_z_ char const* url\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Storage (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Sets the storage event handlers.\n/// </summary>\n/// <param name=\"queue\">The async queue the callbacks should be invoked on.\n/// </param>\n/// <param name=\"handlers\">The event handlers,\n/// <see cref=\"XalPlatformStorageEventHandlers\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\nSTDAPI XalPlatformStorageSetEventHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XalPlatformStorageEventHandlers2* handlers\n) noexcept;\n\n/// <summary>\n/// Clears the storage event handlers.\n/// </summary>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize or after XalCleanupAsync completes.\n/// </remarks>\nSTDAPI XalPlatformStorageClearEventHandlers() noexcept;\n\n/// <summary>\n/// Completes write to storage operation.\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This should only be called in response to a write to storage event, once\n/// the write is completed or if an error occurs and the operation cannot be\n/// completed <see cref=\"XalPlatformStorageWriteEventHandler\"/>.\n/// </remarks>\nSTDAPI XalPlatformStorageWriteComplete(\n    _In_ XalPlatformOperation operation,\n    _In_ XalPlatformOperationResult result\n) noexcept;\n\n/// <summary>\n/// Completes read from storage operation.\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <param name=\"dataSize\">The size (in bytes) of the data.</param>\n/// <param name=\"data\">The data read.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This should only be called in response to a read from storage event, once\n/// the read is completed or if an error occurs and the operation cannot be\n/// completed <see cref=\"XalPlatformStorageReadEventHandler\"/>.\n///\n/// If the requested key cannot be found, the operation should be completed\n/// with XalClientOperationResult_Success, data = nullptr and dataSize = 0.\n/// </remarks>\nSTDAPI XalPlatformStorageReadComplete(\n    _In_ XalPlatformOperation operation,\n    _In_ XalPlatformOperationResult result,\n    _In_ size_t dataSize,\n    _In_reads_bytes_opt_(dataSize) void const* data\n) noexcept;\n\n/// <summary>\n/// Completes clear from storage operation.\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This should only be called in response to a clear from storage event, once\n/// the data is cleared or if an error occurs and the operation cannot be\n/// completed <see cref=\"XalPlatformStorageClearEventHandler\"/>.\n/// </remarks>\nSTDAPI XalPlatformStorageClearComplete(\n    _In_ XalPlatformOperation operation,\n    _In_ XalPlatformOperationResult result\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Remote Connect (only used in generic mode, when configured for it)\n\n/// <summary>\n/// Sets the remote connect event handlers.\n/// </summary>\n/// <param name=\"queue\">The async queue the callbacks should be invoked on.\n/// </param>\n/// <param name=\"handlers\">The event handlers,\n/// <see cref=\"XalPlatformRemoteConnectEventHandlers\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\nSTDAPI XalPlatformRemoteConnectSetEventHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XalPlatformRemoteConnectEventHandlers3* handlers\n) noexcept;\n\n/// <summary>\n/// Clears the remote connect event handlers.\n/// </summary>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize or after XalCleanupAsync completes.\n/// </remarks>\nSTDAPI XalPlatformRemoteConnectClearEventHandlers() noexcept;\n\n/// <summary>\n/// Signal to Xal that the remote connect prompt has been dismissed by the user.\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This should be called after a XalPlatformRemoteConnectShowPromptEventHandler\n/// if the user dismisses the prompt. The whole remote connect process will be\n/// cancelled and the starting AddUserAsync operation will complete with\n/// E_ABORT. The XalPlatformRemoteConnectClosePromptEventHandler will be called\n/// as normal.\n/// </remarks>\nSTDAPI XalPlatformRemoteConnectCancelPrompt(\n    _In_ XalPlatformOperation operation\n) noexcept;\n\n//------------------------------------------------------------------------------\n// Crypto (only used in generic mode)\n\n/// <summary>\n/// Sets the crypto callbacks.\n/// </summary>\n/// <param name=\"callbacks\">The callbacks,\n/// <see cref=\"XalPlatformCryptoCallbacks\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\nSTDAPI XalPlatformCryptoSetCallbacks(\n    _In_ XalPlatformCryptoCallbacks* callbacks\n) noexcept;\n\n//------------------------------------------------------------------------------\n// Date & Time (only used in generic mode)\n\n/// <summary>\n/// Sets the date/time callbacks.\n/// </summary>\n/// <param name=\"callbacks\">The callbacks,\n/// <see cref=\"XalPlatformDateTimeCallbacks\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\nSTDAPI XalPlatformDateTimeSetCallbacks(\n    _In_ XalPlatformDateTimeCallbacks* callbacks\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Spop Prompt (only used in generic mode, when configured for it)\n\n/// <summary>\n/// Sets the SPOP prompt event handler.\n/// </summary>\n/// <param name=\"handler\">The event handler,\n/// <see cref=\"XalPlatformSpopPromptEventHandler\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\n\nSTDAPI XalPlatformSpopPromptSetEventHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XalPlatformSpopPromptEventHandler* handler,\n    _In_opt_ void* context\n) noexcept;\n\n/// <summary>\n/// Clears the SPOP event handlers.\n/// </summary>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize or after XalCleanupAsync completes.\n/// </remarks>\nSTDAPI XalPlatformSpopPromptClearEventHandler() noexcept;\n\n/// <summary>\n/// Signal to Xal that the user finished interacting with the SPOP prompt.\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the user interaction.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This should be called after a XalPlatformSpopPromptEventHandler when the\n/// user makes a choice or if a failure occurs.\n/// </remarks>\nSTDAPI XalPlatformSpopPromptComplete(\n    _In_ XalPlatformOperation operation,\n    _In_ XalSpopOperationResult result\n) noexcept;\n\n}\n\n// Back compat hooks\n#if XAL_ENABLE_BACK_COMPAT_SHIMS\n//-----------------------------------------------------------------------------\n// Web view (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Registers the show url event handler.\n/// </summary>\n/// <param name=\"queue\">The async queue the callback should be invoked on.\n/// </param>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"handler\">The event handler,\n/// <see cref=\"XalPlatformWebShowUrlEventHandler\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\ninline\nHRESULT XalPlatformWebSetEventHandler(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_opt_ void* context,\n    _In_ XalPlatformWebShowUrlEventHandler* handler\n) noexcept\n{\n    static struct WebShowUrlHandler\n    {\n        XalPlatformWebShowUrlEventHandler* handler;\n        void* context;\n    } s_handlers{};\n\n    s_handlers.handler = handler;\n    s_handlers.context = context;\n\n    XalPlatformWebShowUrlEventHandler2* trampoline = [](\n        void* ctx,\n        uint32_t /*cuid*/,\n        XalPlatformOperation op,\n        char const* sUrl,\n        char const* fUrl,\n        XalShowUrlType t,\n        uint32_t /*requestHeaderCount*/,\n        XalHttpHeader const* /*requestHeaders*/\n    )\n    {\n        auto handler = static_cast<WebShowUrlHandler*>(ctx);\n        handler->handler(handler->context, nullptr, op, sUrl, fUrl, t);\n    };\n\n    return XalPlatformWebSetEventHandler(queue, &s_handlers, trampoline);\n}\n\n//-----------------------------------------------------------------------------\n// Storage (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Sets the storage event handlers.\n/// </summary>\n/// <param name=\"queue\">The async queue the callbacks should be invoked on.\n/// </param>\n/// <param name=\"handlers\">The event handlers,\n/// <see cref=\"XalPlatformStorageEventHandlers\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\ninline\nHRESULT XalPlatformStorageSetEventHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XalPlatformStorageEventHandlers* handlers\n) noexcept\n{\n    static XalPlatformStorageEventHandlers s_handlers{};\n\n    s_handlers = *handlers;\n\n    XalPlatformStorageEventHandlers2 trampolines = {};\n    trampolines.write = [](void* ctx, uint32_t /*cuid*/, XalPlatformOperation op, char const* key, size_t size, void const* data)\n    {\n        auto handlers = static_cast<XalPlatformStorageEventHandlers*>(ctx);\n        handlers->write(handlers->context, nullptr, op, key, size, data);\n    };\n    trampolines.read = [](void* ctx, uint32_t /*cuid*/, XalPlatformOperation op, char const* key)\n    {\n        auto handlers = static_cast<XalPlatformStorageEventHandlers*>(ctx);\n        handlers->read(handlers->context, nullptr, op, key);\n    };\n    trampolines.clear = [](void* ctx, uint32_t /*cuid*/, XalPlatformOperation op, char const* key)\n    {\n        auto handlers = static_cast<XalPlatformStorageEventHandlers*>(ctx);\n        handlers->clear(handlers->context, nullptr, op, key);\n    };\n    trampolines.context = &s_handlers;\n\n    return XalPlatformStorageSetEventHandlers(queue, &trampolines);\n}\n\n//-----------------------------------------------------------------------------\n// Remote Connect (only used in generic mode, when configured for it)\n\n/// <summary>\n/// Sets the remote connect event handlers.\n/// </summary>\n/// <param name=\"queue\">The async queue the callbacks should be invoked on.\n/// </param>\n/// <param name=\"handlers\">The event handlers,\n/// <see cref=\"XalPlatformRemoteConnectEventHandlers\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\ninline\nHRESULT XalPlatformRemoteConnectSetEventHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XalPlatformRemoteConnectEventHandlers2* handlers\n) noexcept\n{\n    static XalPlatformRemoteConnectEventHandlers2 s_handlers{};\n\n    s_handlers = *handlers;\n\n    XalPlatformRemoteConnectEventHandlers3 trampolines = {};\n    trampolines.show = [](void* ctx, uint32_t cuid, XalPlatformOperation op, char const* url, char const* code, size_t /*qrCodeSize*/, void const* /*qrCode*/)\n    {\n        auto handlers = static_cast<XalPlatformRemoteConnectEventHandlers2*>(ctx);\n        handlers->show(handlers->context, cuid, op, url, code);\n    };\n    trampolines.close = [](void* ctx, uint32_t cuid, XalPlatformOperation op)\n    {\n        auto handlers = static_cast<XalPlatformRemoteConnectEventHandlers2*>(ctx);\n        handlers->close(handlers->context, cuid, op);\n    };\n    trampolines.context = &s_handlers;\n\n    return XalPlatformRemoteConnectSetEventHandlers(queue, &trampolines);\n}\n\n/// <summary>\n/// Sets the remote connect event handlers.\n/// </summary>\n/// <param name=\"queue\">The async queue the callbacks should be invoked on.\n/// </param>\n/// <param name=\"handlers\">The event handlers,\n/// <see cref=\"XalPlatformRemoteConnectEventHandlers\"/>.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XalInitialize.\n/// </remarks>\ninline\nHRESULT XalPlatformRemoteConnectSetEventHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XalPlatformRemoteConnectEventHandlers* handlers\n) noexcept\n{\n    static XalPlatformRemoteConnectEventHandlers s_handlers{};\n\n    s_handlers = *handlers;\n\n    XalPlatformRemoteConnectEventHandlers3 trampolines = {};\n    trampolines.show = [](void* ctx, uint32_t /*cuid*/, XalPlatformOperation op, char const* url, char const* code, size_t /*qrCodeSize*/, void const* /*qrCode*/)\n    {\n        auto handlers = static_cast<XalPlatformRemoteConnectEventHandlers*>(ctx);\n        handlers->show(handlers->context, nullptr, op, url, code);\n    };\n    trampolines.close = [](void* ctx, uint32_t /*cuid*/, XalPlatformOperation op)\n    {\n        auto handlers = static_cast<XalPlatformRemoteConnectEventHandlers*>(ctx);\n        handlers->close(handlers->context, nullptr, op);\n    };\n    trampolines.context = &s_handlers;\n\n    return XalPlatformRemoteConnectSetEventHandlers(queue, &trampolines);\n}\n#endif\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_platform_types.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// Types for for platform hooks\n//-----------------------------------------------------------------------------\n\n/// <summary>\n/// Handle to an operation Xal requested the client to perform.\n/// </summary>\ntypedef struct XalPlatformOperationToken* XalPlatformOperation;\n\n/// <summary>\n/// Enum defining the results of a client operation.\n/// </summary>\ntypedef enum XalPlatformOperationResult\n{\n    /// <summary>\n    /// Successful client operation.\n    /// </summary>\n    XalPlatformOperationResult_Success = 0,\n    /// <summary>\n    /// Failed client operation.\n    /// </summary>\n    XalPlatformOperationResult_Failure = 1,\n    /// <summary>\n    /// Canceled client operation.\n    /// </summary>\n    XalPlatformOperationResult_Canceled = 2,\n} XalPlatformOperationResult;\n\n/// <summary>\n/// Enum defining the possible reasons a platform web event might occur.\n/// </summary>\ntypedef enum XalShowUrlType\n{\n    /// <summary>\n    /// The client should show the URL in a shared system browser if\n    /// one is present, otherwise the client should use an embedded browser.\n    /// </summary>\n    XalShowUrlType_Normal = 0,\n    /// <summary>\n    /// This case is deprecated and no longer used. Cookie removal is now\n    /// signaled exclusively using\n    /// XalShowUrlType_CookieRemovalSkipIfSharedCredentials.\n    /// </summary>\n    /// <remarks>\n    /// Formerly, this value indicated that the browser was being raised for the\n    /// purposes of deleting cookies from both shared and embedded browsers.\n    /// </remarks>\n    XalShowUrlType_CookieRemoval_DEPRECATED = 1,\n    /// <summary>\n    /// The browser is being raised for the purposes of deleting\n    /// cookies. If the client is using a shared system browser, this call\n    /// should be ignored and the client should immediately call\n    /// XalPlatformWebShowUrlComplete passing in success, and forwarding the\n    /// received final URL back into Xal. If an embedded browser is being used,\n    /// the cookies should be cleared without showing UI if possible. If silent\n    /// cookie-clearing is impossible, the URL should be loaded as normal.\n    /// </summary>\n    XalShowUrlType_CookieRemovalSkipIfSharedCredentials = 2,\n    /// <summary>\n    /// This is a web flow which does not rely on cookies. The client\n    /// may use a shared system browser or an embedded browser depending on\n    /// whichever browser would give the best user experience. If headers are\n    /// required for the web request, this will be the show type asked for. If\n    /// this is the case, an embedded browser might be required so those\n    /// request headers can be set.\n    /// </summary>\n    XalShowUrlType_NonAuthFlow = 3,\n} XalShowUrlType;\n\n/// <summary>\n/// The userIdentifier value Xal will use for data that is not specific to a\n/// single user.\n/// </summary>\nuint32_t const XAL_NO_USER_IDENTIFIER = static_cast<uint32_t>(-1);\n\n//-----------------------------------------------------------------------------\n// Memory (optional on all platforms)\n\n/// <summary>\n/// A callback invoked every time a new memory buffer must be dynamically\n/// allocated by the library. This callback is optionally installed by calling\n/// XalMemSetFunctions.\n///\n/// The callback must allocate and return a pointer to a contiguous block of\n/// memory of the specified size that will remain valid until the app's\n/// corresponding XalMemFreeFunc callback is invoked to release it.\n///\n/// Every non-null pointer returned by this method will be subsequently passed\n/// to the corresponding XalMemFreeFunc callback once the memory is no longer\n/// needed.\n/// </summary>\n/// <param name=\"size\">The size of the allocation to be made. This value will\n/// never be zero.</param>\n/// <param name=\"tag\">An opaque identifier representing the internal category\n/// of memory being allocated.</param>\n/// <returns>A pointer to an allocated block of memory of the specified size, or\n/// a null pointer if allocation failed.</returns>\ntypedef _Ret_maybenull_ _Post_writable_byte_size_(size) void* XalMemAllocFunc(size_t size, uint32_t tag);\n\n/// <summary>\n/// A callback invoked every time a previously allocated memory buffer is no\n/// longer needed by the library and can be freed. This callback is optionally\n/// installed by calling XalMemSetFunctions.\n///\n/// The callback is invoked whenever the library has finished using a memory\n/// buffer previously returned by the app's corresponding XalMemAllocFunc such\n/// that the application can free the memory buffer.\n/// </summary>\n/// <param name=\"pointer\">The pointer to the memory buffer previously allocated.\n/// This value will never be a null pointer.</param>\n/// <param name=\"tag\">An opaque identifier representing the internal category\n/// of memory being allocated.</param>\n/// <returns></returns>\ntypedef void XalMemFreeFunc(_In_ _Post_invalid_ void* pointer, uint32_t tag);\n\n//-----------------------------------------------------------------------------\n// Web view (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Show url event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"startUrl\">The url to navigate to.</param>\n/// <param name=\"finalUrl\">The url that indicates the web flow is\n/// complete.</param>\n/// <param name=\"showUrlType\">Enum indicating the type of flow occurring. This\n/// flag dictates what correct behavior for the client is expected to be.\n/// </param>\n/// <param name=\"requestHeaderCount\">The number of request headers present in\n/// the requestHeaders array.</param>\n/// <param name=\"requestHeaders\">Request headers that must be added to the web\n/// session request for the best user experience.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when Xal needs to show a web flow to the user, the\n/// client should navigate to startUrl and wait for a redirect to finalUrl. Once\n/// the redirect to finalUrl occurs the client should close the web ui and invoke\n/// XalPlatformWebShowUrlComplete passing the full redirect url.\n///\n/// This handler is optional for Android and iOS platforms. If it is not set on\n/// these platforms, Xal will provide default browser behavior. On UWP, and XDK\n/// platforms, this handler is ignored.\n///\n/// Depending on the value of showUrlType and the type of browser the client is\n/// using, different behavior is expected. See the definition for\n/// XalShowUrlType for more information.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformWebShowUrlEventHandler2)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* startUrl,\n    _In_z_ char const* finalUrl,\n    _In_ XalShowUrlType showUrlType,\n    _In_ uint32_t requestHeaderCount,\n    _In_reads_(requestHeaderCount) XalHttpHeader const* requestHeaders\n);\n\n//-----------------------------------------------------------------------------\n// Storage (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Write to storage event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"key\">Identifies the data being written.</param>\n/// <param name=\"dataSize\">The size (in bytes) of the data.</param>\n/// <param name=\"data\">The data to write.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when Xal needs to write data to storage, the client\n/// should write the data and when done invoke XalPlatformStorageWriteComplete.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformStorageWriteEventHandler2)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* key,\n    _In_ size_t dataSize,\n    _In_reads_bytes_(dataSize) void const* data\n);\n\n/// <summary>\n/// Read from storage event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"key\">Identifies the data being read.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when Xal needs to read data from storage, the client\n/// should read the data and when done invoke XalPlatformStorageReadComplete.\n/// If the key is not found, the client should complete with\n/// XalPlatformOperationResult_Success and no data.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformStorageReadEventHandler2)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* key\n);\n\n/// <summary>\n/// Clear from storage event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"key\">Identifies the data being cleared.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when Xal needs to clear data from storage, the client\n/// should clear the data and when done invoke XalPlatformStorageClearComplete.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformStorageClearEventHandler2)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* key\n);\n\n/// <summary>\n/// Struct encapsulating the storage event handlers.\n/// </summary>\n/// <remarks>\n/// All 3 handlers must be set at the same time.\n/// </remarks>\ntypedef struct XalPlatformStorageEventHandlers2\n{\n    /// <summary>\n    /// Write to storage handler.\n    /// </summary>\n    XalPlatformStorageWriteEventHandler2* write;\n\n    /// <summary>\n    /// Read from storage handler.\n    /// </summary>\n    XalPlatformStorageReadEventHandler2* read;\n\n    /// <summary>\n    /// Clear from storage handler.\n    /// </summary>\n    XalPlatformStorageClearEventHandler2* clear;\n\n    /// <summary>\n    /// Optional pointer to data used by the event handlers.\n    /// </summary>\n    void* context;\n} XalPlatformStorageEventHandlers2;\n\n//-----------------------------------------------------------------------------\n// Remote Connect (only used in generic mode, when configured for it)\n\n/// <summary>\n/// Show prompt for remote connect authentication event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"url\">The url to show in the prompt.</param>\n/// <param name=\"code\">The code to show in the prompt.</param>\n/// <param name=\"qrCodeSize\">Size of the qrCode buffer</param>\n/// <param name=\"qrCode\">A pointer to a buffer containing the QR code for the url as PNG.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when Xal needs to prompt the user to perform the\n/// remote connect authentication process.\n/// The prompt ui should be displayed until\n/// XalPlatformRemoteConnectClosePromptEventHandler is called or it is dismissed\n/// by the user.\n///\n/// Game should still render the URL and code that it got back in case the user can’t scan\n/// the QR code. The QR code will also not contain the code embedded into it.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformRemoteConnectShowPromptEventHandler3)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* url,\n    _In_z_ char const* code,\n    _In_ size_t qrCodeSize,\n    _In_reads_bytes_(qrCodeSize) void const* qrCode\n);\n\n/// <summary>\n/// Close prompt for remote authentication event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when the remote connect authentication process has been\n/// completed and the prompt is no longer necessary.\n/// This event will always be called with the same operation as a previous\n/// XalPlatformRemoteConnectShowPromptEventHandler event.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformRemoteConnectClosePromptEventHandler3)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation\n);\n\n/// <summary>\n/// Struct encapsulating the remote connect event handlers.\n/// </summary>\n/// <remarks>\n/// Both handlers must be set at the same time.\n/// </remarks>\ntypedef struct XalPlatformRemoteConnectEventHandlers3\n{\n    /// <summary>\n    /// Show the prompt handler.\n    /// </summary>\n    XalPlatformRemoteConnectShowPromptEventHandler3* show;\n\n    /// <summary>\n    /// Close the prompt handler.\n    /// </summary>\n    XalPlatformRemoteConnectClosePromptEventHandler3* close;\n\n    /// <summary>\n    /// Optional pointer to data used by the event handlers.\n    /// </summary>\n    void* context;\n} XalPlatformRemoteConnectEventHandlers3;\n\n//------------------------------------------------------------------------------\n// Crypto (only used in generic mode)\n\n/// <summary>\n/// Struct representing a UUID.\n/// </summary>\n/// <remarks>\n/// UUIDs should conform to RFC4122 (https://tools.ietf.org/html/rfc4122).\n/// </remarks>\ntypedef struct XalUuid\n{\n    /// <summary>\n    /// Stores the time_low field.\n    /// </summary>\n    uint32_t data1;\n    /// <summary>\n    /// Stores the time_mid field.\n    /// </summary>\n    uint16_t data2;\n    /// <summary>\n    /// Stores the time_hi_and_version field.\n    /// </summary>\n    uint16_t data3;\n    /// <summary>\n    /// Stores the clock_seq_hi_and_reserved field [0], clock_seq_low field [1], and node fields [2-7].\n    /// </summary>\n    uint8_t data4[8];\n} XalUuid;\n\n/// <summary>\n/// Generate UUID callback.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the callback.\n/// </param>\n/// <param name=\"newUuid\">The new UUID.</param>\n/// <returns>The results of the client operation.</returns>\n/// <remarks>\n/// This callback is invoked when Xal needs a new UUID.\n///\n/// This callback will be invoked on a thread Xal is running on.\n/// </remarks>\ntypedef XalPlatformOperationResult (XalPlatformCryptoGenerateUuidCallback)(\n    _In_opt_ void* context,\n    _Out_ XalUuid* newUuid\n);\n\n/// <summary>\n/// Generate random bytes callback.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the callback.\n/// </param>\n/// <param name=\"bufferSize\">The number of random bytes needed.</param>\n/// <param name=\"buffer\">The buffer the random data should be written to.\n/// </param>\n/// <returns>The results of the client operation.</returns>\n/// <remarks>\n/// This callback is invoked when Xal needs random data, which should be\n/// generated using the platform cryptographic RNG.\n///\n/// This callback will be invoked on a thread Xal is running on.\n/// </remarks>\ntypedef XalPlatformOperationResult (XalPlatformCryptoGenerateRandomBytesCallback)(\n    _In_opt_ void* context,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_(bufferSize) uint8_t* buffer\n);\n\n/// <summary>\n/// Struct encapsulating the crypto callbacks.\n/// </summary>\n/// <remarks>\n/// Both callbacks must be set at the same time.\n/// </remarks>\ntypedef struct XalPlatformCryptoCallbacks\n{\n    /// <summary>\n    /// The UUID callback to be invoked.\n    /// </summary>\n    XalPlatformCryptoGenerateUuidCallback* uuid;\n    /// <summary>\n    /// The random bytes callback to be invoked.\n    /// </summary>\n    XalPlatformCryptoGenerateRandomBytesCallback* random;\n    /// <summary>\n    /// Optional pointer to data used by the callback.\n    /// </summary>\n    void* context;\n} XalPlatformCryptoCallbacks;\n\n//------------------------------------------------------------------------------\n// Date & Time (only used in generic mode)\n\n/// <summary>\n/// Generate Unix timestamp callback.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the callback.\n/// </param>\n/// <param name=\"secondsFromUnixEpoch\">Number of seconds from the Unix Epoch\n/// (1970-01-01T00:00:00Z) in the UTC timezone.</param>\n/// <param name=\"subsecondsMilliseconds\">The fraction of second, in\n/// milliseconds.</param>\n/// <returns>The results of the client operation.</returns>\n/// <remarks>\n/// This callback is invoked when Xal needs a timestamp.\n/// The subsecond value is optional and can be set to 0.\n///\n/// This callback will be invoked on a thread Xal is running on.\n/// </remarks>\ntypedef XalPlatformOperationResult (XalPlatformDateTimeGetUtcTimestampCallback)(\n    _In_opt_ void* context,\n    _Out_ int64_t* secondsFromUnixEpoch,\n    _Out_ uint32_t* subsecondMilliseconds\n);\n\n/// <summary>\n/// Convert a Unix timestamp into date/time components.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the callback.\n/// </param>\n/// <param name=\"secondsFromUnixEpoch\">Number of seconds from the Unix Epoch\n/// (1970-01-01T00:00:00Z) in the UTC timezone.</param>\n/// <param name=\"components\">The resulting date/time components.</param>\n/// <returns>The results of the client operation.</returns>\n/// <remarks>\n/// This callback is invoked when Xal needs to convert a timestamp into a date,\n/// the date produced should be in the UTC timezone.\n///\n/// This callback will be invoked on a thread Xal is running on.\n/// </remarks>\ntypedef XalPlatformOperationResult (XalPlatformDateTimeTimestampToComponentsCallback)(\n    _In_opt_ void* context,\n    _In_ int64_t secondsFromUnixEpoch,\n    _Out_ XalTimestampComponents* components\n);\n\n/// <summary>\n/// Convert a date/time components into a Unix timestamp.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the callback.\n/// </param>\n/// <param name=\"components\">The date/time components.</param>\n/// <param name=\"secondsFromUnixEpoch\">Number of seconds from the Unix Epoch\n/// (1970-01-01T00:00:00Z) in the UTC timezone.</param>\n/// <returns>The results of the client operation.</returns>\n/// <remarks>\n/// This callback is invoked when Xal needs to convert a date into a timestamp,\n/// the date is always in the UTC timezone.\n///\n/// This callback will be invoked on a thread Xal is running on.\n/// </remarks>\ntypedef XalPlatformOperationResult(XalPlatformDateTimeComponentsToTimestampCallback)(\n    _In_opt_ void* context,\n    _In_ XalTimestampComponents const* components,\n    _Out_ int64_t* secondsFromUnixEpoch\n);\n\n/// <summary>\n/// Struct encapsulating the date/time callbacks.\n/// </summary>\n/// <remarks>\n/// All 3 callbacks must be set at the same time.\n/// </remarks>\nstruct XalPlatformDateTimeCallbacks\n{\n    /// <summary>\n    /// The get utc timestamp callback to be invoked.\n    /// </summary>\n    XalPlatformDateTimeGetUtcTimestampCallback* timestamp;\n    /// <summary>\n    /// The timestamp to components callback to be invoked.\n    /// </summary>\n    XalPlatformDateTimeTimestampToComponentsCallback* timestampToComponents;\n    /// <summary>\n    /// The components to timestamp callback to be invoked.\n    /// </summary>\n    XalPlatformDateTimeComponentsToTimestampCallback* componentsToTimestamp;\n    /// <summary>\n    /// Optional pointer to data used by the callback.\n    /// </summary>\n    void* context;\n};\n\n//-----------------------------------------------------------------------------\n// Spop Prompt (only used in generic mode, when configured for it)\n\n/// <summary>\n/// Show prompt for SPOP operation event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"modernGamertag\">Modern gamertag</param>\n/// <param name=\"modernGamertagSuffix\">Modern gamertag suffix if there is one.</param>\n/// <returns></returns>\n/// <remarks>\n/// This event is raised when the user is already signed in on a different\n/// device and therefore hits an SPOP veto. Xal needs to prompt the user to\n/// decide whether they want to sign-out the other session and sign-in on the\n/// current device. This will only occur as a response to a call to\n/// XalAddUserWithUiAsync that resulted in an SPOP veto.\n///\n/// The modern gamertag suffix might be null for certain users.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformSpopPromptEventHandler)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* modernGamertag,\n    _In_opt_z_ char const* modernGamertagSuffix\n);\n\n/// <summary>\n/// Enum defining the results of a client operation.\n/// </summary>\ntypedef enum XalSpopOperationResult\n{\n    /// <summary>\n    /// User agreed to sign-out the existing session, and sign-in on the current device\n    /// </summary>\n    XalSpopOperationResult_SignInHere = 0,\n    /// <summary>\n    /// User selected a \"switch account\" option\n    /// </summary>\n    XalSpopOperationResult_SwitchAccount = 1,\n    /// <summary>\n    /// Canceled client operation.\n    /// </summary>\n    XalSpopOperationResult_Canceled = 2,\n    /// <summary>\n    /// Unrecoverable failure in client operation.\n    /// </summary>\n    XalSpopOperationResult_Failure = 3,\n} XalSpopOperationResult;\n\n}\n\n// Back compat handlers\n#if XAL_ENABLE_BACK_COMPAT_SHIMS\n//-----------------------------------------------------------------------------\n// Web view (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Show url event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userContext\">Always null.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"startUrl\">The url to navigate to.</param>\n/// <param name=\"finalUrl\">The url that indicates the web flow is\n/// complete.</param>\n/// <param name=\"showUrlType\">Enum indicating the type of flow occurring. This\n/// flag dictates what correct behavior for the client is expected to be.\n/// </param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformWebShowUrlEventHandler2.\n///\n/// This event is raised when Xal needs to show a web flow to the user, the\n/// client should navigate to startUrl and wait for a redirect to finalUrl. Once\n/// the redirect to finalUrl occurs the client should close the web ui and invoke\n/// XalPlatformWebShowUrlComplete passing the full redirect url.\n///\n/// This handler is optional for Android and iOS platforms. If it is not set on\n/// these platforms, Xal will provide default browser behavior. On UWP, and XDK\n/// platforms, this handler is ignored.\n///\n/// Depending on the value of showUrlType and the type of browser the client is\n/// using, different behavior is expected. See the definition for\n/// XalShowUrlType for more information.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformWebShowUrlEventHandler)(\n    _In_opt_ void* context,\n    _In_opt_ void* userContext,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* startUrl,\n    _In_z_ char const* finalUrl,\n    _In_ XalShowUrlType showUrlType\n);\n\n//-----------------------------------------------------------------------------\n// Storage (ignored on OneCore platforms, optional on iOS and Android)\n\n/// <summary>\n/// Write to storage event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userContext\">Always null.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"key\">Identifies the data being written.</param>\n/// <param name=\"dataSize\">The size (in bytes) of the data.</param>\n/// <param name=\"data\">The data to write.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformStorageWriteEventHandler2.\n///\n/// This event is raised when Xal needs to write data to storage, the client\n/// should write the data and when done invoke XalPlatformStorageWriteComplete.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformStorageWriteEventHandler)(\n    _In_opt_ void* context,\n    _In_opt_ void* userContext,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* key,\n    _In_ size_t dataSize,\n    _In_reads_bytes_(dataSize) void const* data\n);\n\n/// <summary>\n/// Read from storage event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userContext\">Always null.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"key\">Identifies the data being read.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformStorageReadEventHandler2.\n///\n/// This event is raised when Xal needs to read data from storage, the client\n/// should read the data and when done invoke XalPlatformStorageReadComplete.\n/// If the key is not found, the client should complete with\n/// XalPlatformOperationResult_Success and no data.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformStorageReadEventHandler)(\n    _In_opt_ void* context,\n    _In_opt_ void* userContext,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* key\n);\n\n/// <summary>\n/// Clear from storage event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userContext\">Always null.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"key\">Identifies the data being cleared.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformStorageClearEventHandler2.\n///\n/// This event is raised when Xal needs to clear data from storage, the client\n/// should clear the data and when done invoke XalPlatformStorageClearComplete.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformStorageClearEventHandler)(\n    _In_opt_ void* context,\n    _In_opt_ void* userContext,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* key\n);\n\n/// <summary>\n/// Struct encapsulating the storage event handlers.\n/// </summary>\n/// <remarks>\n/// This version of the api is deprecated, please switch to\n/// XalPlatformStorageEventHandlers2.\n///\n/// All 3 handlers must be set at the same time.\n/// </remarks>\ntypedef struct XalPlatformStorageEventHandlers\n{\n    /// <summary>\n    /// Write to storage handler.\n    /// </summary>\n    XalPlatformStorageWriteEventHandler* write;\n\n    /// <summary>\n    /// Read from storage handler.\n    /// </summary>\n    XalPlatformStorageReadEventHandler* read;\n\n    /// <summary>\n    /// Clear from storage handler.\n    /// </summary>\n    XalPlatformStorageClearEventHandler* clear;\n\n    /// <summary>\n    /// Optional pointer to data used by the event handlers.\n    /// </summary>\n    void* context;\n} XalPlatformStorageEventHandlers;\n\n//-----------------------------------------------------------------------------\n// Remote Connect (only used in generic mode, when configured for it)\n\n/// <summary>\n/// Show prompt for remote connect authentication event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"url\">The url to show in the prompt.</param>\n/// <param name=\"code\">The code to show in the prompt.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformRemoteConnectShowPromptEventHandler3.\n///\n/// This event is raised when Xal needs to prompt the user to perform the\n/// remote connect authentication process.\n/// The prompt ui should be displayed until\n/// XalPlatformRemoteConnectClosePromptEventHandler is called or it is dismissed\n/// by the user.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformRemoteConnectShowPromptEventHandler2)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* url,\n    _In_z_ char const* code\n);\n\n/// <summary>\n/// Close prompt for remote authentication event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userIdentifier\">The user identifier that was passed to Xal when\n/// the user was added.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformRemoteConnectClosePromptEventHandler3.\n///\n/// This event is raised when the remote connect authentication process has been\n/// completed and the prompt is no longer necessary.\n/// This event will always be called with the same operation as a previous\n/// XalPlatformRemoteConnectShowPromptEventHandler event.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformRemoteConnectClosePromptEventHandler2)(\n    _In_opt_ void* context,\n    _In_ uint32_t userIdentifier,\n    _In_ XalPlatformOperation operation\n);\n\n/// <summary>\n/// Struct encapsulating the remote connect event handlers.\n/// </summary>\n/// <remarks>\n/// This version of the api is deprecated, please switch to\n/// XalPlatformRemoteConnectEventHandlers3.\n///\n/// Both handlers must be set at the same time.\n/// </remarks>\ntypedef struct XalPlatformRemoteConnectEventHandlers2\n{\n    /// <summary>\n    /// Show the prompt handler.\n    /// </summary>\n    XalPlatformRemoteConnectShowPromptEventHandler2* show;\n\n    /// <summary>\n    /// Close the prompt handler.\n    /// </summary>\n    XalPlatformRemoteConnectClosePromptEventHandler2* close;\n\n    /// <summary>\n    /// Optional pointer to data used by the event handlers.\n    /// </summary>\n    void* context;\n} XalPlatformRemoteConnectEventHandlers2;\n\n/// <summary>\n/// Show prompt for remote connect authentication event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userContext\">Always null.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"url\">The url to show in the prompt.</param>\n/// <param name=\"code\">The code to show in the prompt.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformRemoteConnectShowPromptEventHandler2.\n///\n/// This event is raised when Xal needs to prompt the user to perform the\n/// remote connect authentication process.\n/// The prompt ui should be displayed until\n/// XalPlatformRemoteConnectClosePromptEventHandler is called or it is dismissed\n/// by the user.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformRemoteConnectShowPromptEventHandler)(\n    _In_opt_ void* context,\n    _In_opt_ void* userContext,\n    _In_ XalPlatformOperation operation,\n    _In_z_ char const* url,\n    _In_z_ char const* code\n);\n\n/// <summary>\n/// Close prompt for remote authentication event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userContext\">Always null.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <returns></returns>\n/// <remarks>\n/// This version of the handler is deprecated, please switch to\n/// XalPlatformRemoteConnectClosePromptEventHandler2.\n///\n/// This event is raised when the remote connect authentication process has been\n/// completed and the prompt is no longer necessary.\n/// This event will always be called with the same operation as a previous\n/// XalPlatformRemoteConnectShowPromptEventHandler event.\n///\n/// All arguments are owned by the caller (except context).\n/// </remarks>\ntypedef void (XalPlatformRemoteConnectClosePromptEventHandler)(\n    _In_opt_ void* context,\n    _In_opt_ void* userContext,\n    _In_ XalPlatformOperation operation\n);\n\n/// <summary>\n/// Struct encapsulating the remote connect event handlers.\n/// </summary>\n/// <remarks>\n/// This version of the api is deprecated, please switch to\n/// XalPlatformRemoteConnectEventHandlers2.\n///\n/// Both handlers must be set at the same time.\n/// </remarks>\ntypedef struct XalPlatformRemoteConnectEventHandlers\n{\n    /// <summary>\n    /// Show the prompt handler.\n    /// </summary>\n    XalPlatformRemoteConnectShowPromptEventHandler* show;\n\n    /// <summary>\n    /// Close the prompt handler.\n    /// </summary>\n    XalPlatformRemoteConnectClosePromptEventHandler* close;\n\n    /// <summary>\n    /// Optional pointer to data used by the event handlers.\n    /// </summary>\n    void* context;\n} XalPlatformRemoteConnectEventHandlers;\n\n#endif\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_types.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <stdint.h>\n\n#include <httpClient/pal.h>\n\n#if HC_PLATFORM_HEADER_OVERRIDE\n#ifdef XAL_PLATFORM_TYPES_PATH\n#include XAL_PLATFORM_TYPES_PATH\n#else\n#error Platform header override is enabled but XAL_PLATFORM_TYPES_PATH is undefined\n#endif\n#elif HC_PLATFORM == HC_PLATFORM_WIN32\n#include <Xal/xal_win32.h>\n#elif HC_PLATFORM == HC_PLATFORM_UWP\n#include <Xal/xal_uwp.h>\n#elif HC_PLATFORM == HC_PLATFORM_XDK\n#include <Xal/xal_xdk.h>\n#elif HC_PLATFORM == HC_PLATFORM_GDK\n#include <Xal/xal_gsdk.h>\n#elif HC_PLATFORM == HC_PLATFORM_ANDROID\n#include <Xal/xal_android.h>\n#elif HC_PLATFORM_IS_APPLE\n#include <Xal/xal_apple.h>\n#elif HC_PLATFORM_IS_EXTERNAL\n#include <Xal/xal_generic.h>\n#else\n#error Xal does not recognize this platform, do you need to set HC_PLATFORM = HC_PLATFORM_GENERIC?\n#endif\n\n#ifndef XAL_OS_IMPL\n#define XAL_OS_IMPL 0\n#endif\n\n#ifndef XAL_ENABLE_BACK_COMPAT_SHIMS\n#define XAL_ENABLE_BACK_COMPAT_SHIMS 1\n#endif\n\n#ifndef XAL_OS_ERRORS\n#define XAL_OS_ERRORS 0\n#endif\n\n#ifndef XAL_CUSTOM_ALLOCATOR\n#define XAL_CUSTOM_ALLOCATOR 1\n#endif\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Results\n//------------------------------------------------------------------------------\n\n#define E_XAL_NOTINITIALIZED                MAKE_E_HC(0x5100L) // 0x89235100\n#define E_XAL_ALREADYINITIALIZED            MAKE_E_HC(0x5101L) // 0x89235101\n#define E_XAL_USERSETNOTEMPTY               MAKE_E_HC(0x5102L) // 0x89235102\n#define E_XAL_USERSETFULL                   MAKE_E_HC(0x5103L) // 0x89235103\n#define E_XAL_USERSIGNEDOUT                 MAKE_E_HC(0x5104L) // 0x89235104\n#define E_XAL_DUPLICATEDUSER                MAKE_E_HC(0x5105L) // 0x89235105\n#define E_XAL_NETWORK                       MAKE_E_HC(0x5106L) // 0x89235106\n#define E_XAL_CLIENTERROR                   MAKE_E_HC(0x5107L) // 0x89235107\n#define E_XAL_UIREQUIRED                    MAKE_E_HC(0x5108L) // 0x89235108\n#define E_XAL_HANDLERALREADYREGISTERED      MAKE_E_HC(0x5109L) // 0x89235109\n#define E_XAL_UNEXPECTEDUSERSIGNEDIN        MAKE_E_HC(0x510AL) // 0x8923510A\n#define E_XAL_NOTATTACHEDTOJVM              MAKE_E_HC(0x510BL) // 0x8923510B\n#define E_XAL_DEVICEUSER                    MAKE_E_HC(0x510CL) // 0x8923510C\n#define E_XAL_DEFERRALNOTAVAILABLE          MAKE_E_HC(0x510DL) // 0x8923510D\n#define E_XAL_MISSINGPLATFORMEVENTHANDLER   MAKE_E_HC(0x510EL) // 0x8923510E\n#define E_XAL_USERNOTFOUND                  MAKE_E_HC(0x510FL) // 0x8923510F\n#define E_XAL_NOTOKENREQUIRED               MAKE_E_HC(0x5110L) // 0x89235110\n#define E_XAL_NODEFAULTUSER                 MAKE_E_HC(0x5111L) // 0x89235111\n#define E_XAL_FAILEDTORESOLVE               MAKE_E_HC(0x5112L) // 0x89235112\n#define E_XAL_NOACCOUNTPROVIDER             MAKE_E_HC(0x5113L) // 0x89235113\n#define E_XAL_MISMATCHEDTITLEANDCLIENTIDS   MAKE_E_HC(0x5114L) // 0x89235114\n#define E_XAL_INVALIDAPPCONFIGURATION       MAKE_E_HC(0x5115L) // 0x89235115\n#define E_XAL_MALFORMEDCLIENTID             MAKE_E_HC(0x5116L) // 0x89235116\n#define E_XAL_MISSINGCLIENTID               MAKE_E_HC(0x5117L) // 0x89235117\n#define E_XAL_MISSINGTITLEID                MAKE_E_HC(0x5118L) // 0x89235118\n#define E_XAL_CONTENT_ISOLATION             MAKE_E_HC(0x5119L) // 0x89235119\n#define E_XAL_SANDBOX_NOT_ALLOWED           MAKE_E_HC(0x511AL) // 0x8923511A\n#define E_XAL_GAMEWINDOWNOTFOREGROUND       MAKE_E_HC(0x511BL) // 0x8923511B\n#define E_XAL_UNLISTEDCONSENT               MAKE_E_HC(0x511CL) // 0x8923511C\n#define E_XAL_CONSENTNOTAPPLICABLE          MAKE_E_HC(0x511DL) // 0x8923511D\n#define E_XAL_NO_SIGNED_IN_USER_FOUND       MAKE_E_HC(0x511EL) // 0x8923511E\n\n// E_XAL_INTERNAL_* values should never be returned to callers of XAL.\n#define E_XAL_INTERNAL_SWITCHUSER           MAKE_E_HC(0x5171L) // 0x89235171\n#define E_XAL_INTERNAL_NOUSERFOUND          MAKE_E_HC(0x5172L) // 0x89235172\n#define E_XAL_INTERNAL_TOOMANYCACHEDUSERS   MAKE_E_HC(0x5173L) // 0x89235173\n#define E_XAL_INTERNAL_BADUSERTOKEN         MAKE_E_HC(0x5174L) // 0x89235174\n#define E_XAL_INTERNAL_BADDEVICEIDENTITY    MAKE_E_HC(0x5175L) // 0x89235175\n#define E_XAL_INTERNAL_UNAUTHORIZED         MAKE_E_HC(0x5176L) // 0x89235176\n#define E_XAL_INTERNAL_NODISPLAYCLAIMSFOUND MAKE_E_HC(0x5177L) // 0x89235177\n\n// GDK has system definitions for some error values\n#if XAL_OS_ERRORS\n#undef E_XAL_USERSETFULL\n#undef E_XAL_USERSIGNEDOUT\n#undef E_XAL_UIREQUIRED\n#undef E_XAL_DEFERRALNOTAVAILABLE\n#undef E_XAL_USERNOTFOUND\n#undef E_XAL_NOTOKENREQUIRED\n#undef E_XAL_NODEFAULTUSER\n#undef E_XAL_FAILEDTORESOLVE\n#undef E_XAL_MISMATCHEDTITLEANDCLIENTIDS\n#undef E_XAL_INVALIDAPPCONFIGURATION\n#undef E_XAL_MALFORMEDCLIENTID\n#undef E_XAL_MISSINGCLIENTID\n#undef E_XAL_MISSINGTITLEID\n#undef E_XAL_CONTENT_ISOLATION\n#undef E_XAL_SANDBOX_NOT_ALLOWED\n#undef E_XAL_GAMEWINDOWNOTFOREGROUND\n\n#define E_XAL_USERSETFULL                   E_GAMEUSER_MAX_USERS_ADDED                      // 0x89245100\n#define E_XAL_USERSIGNEDOUT                 E_GAMEUSER_SIGNED_OUT                           // 0x89245101\n#define E_XAL_UIREQUIRED                    E_GAMEUSER_RESOLVE_USER_ISSUE_REQUIRED          // 0x89245102\n#define E_XAL_DEFERRALNOTAVAILABLE          E_GAMEUSER_DEFERRAL_NOT_AVAILABLE               // 0x89245103\n#define E_XAL_USERNOTFOUND                  E_GAMEUSER_USER_NOT_FOUND                       // 0x89245104\n#define E_XAL_NOTOKENREQUIRED               E_GAMEUSER_NO_TOKEN_REQUIRED                    // 0x89245105\n#define E_XAL_NODEFAULTUSER                 E_GAMEUSER_NO_DEFAULT_USER                      // 0x89245106\n#define E_XAL_FAILEDTORESOLVE               E_GAMEUSER_FAILED_TO_RESOLVE                    // 0x89245107\n#define E_XAL_MISSINGTITLEID                E_GAMEUSER_NO_TITLE_ID                          // 0x89245108\n#define E_XAL_INVALIDAPPCONFIGURATION       E_GAMEUSER_INVALID_APP_CONFIGURATION            // 0x89245112\n#define E_XAL_MALFORMEDCLIENTID             E_GAMEUSER_MALFORMED_MSAAPPID                   // 0x89245113\n#define E_XAL_MISMATCHEDTITLEANDCLIENTIDS   E_GAMEUSER_INCONSISTENT_MSAAPPID_AND_TITLEID    // 0x89245114\n#define E_XAL_MISSINGCLIENTID               E_GAMEUSER_NO_MSAAPPID                          // 0x89245115\n#define E_XAL_CONTENT_ISOLATION             XO_E_CONTENT_ISOLATION                          // 0x8015DC12\n#define E_XAL_SANDBOX_NOT_ALLOWED           XO_E_SANDBOX_NOT_ALLOWED                        // 0x8015DC19\n#define E_XAL_GAMEWINDOWNOTFOREGROUND       E_GAMERUNTIME_WINDOW_NOT_FOREGROUND             // 0x89240103\n#endif\n\n//------------------------------------------------------------------------------\n// Xal init flags\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Flag to instruct Xal to use MPOP behavior when adding users. MPOP behavior\n/// allows Xal to rely on cached Xtokens when adding users so refreshing is not\n/// required. This lowers the time it takes for add user calls to finish\n/// because less network traffic is needed, but it implies that SPOP vetoes\n/// will not be checked prior to returning a user.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Win32, Android, iOS, Mac, and generic device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_USE_MPOP_BEHAVIOR = 1u << 2;\n\n/// <summary>\n/// Flag to instruct Xal to use the modern Gamertag features during sign up.\n/// </summary>\n/// <remarks>\n/// This flag is supported on Win32, UWP, Android, iOS, Mac, and generic device types.\n/// </remarks>\nuint32_t const XAL_INIT_OPTION_REQUEST_MODERN_GAMERTAG_FLOW = 1u << 26;\n\n//------------------------------------------------------------------------------\n// Privileges\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Enum defining the values for Xbox Live privileges\n/// </summary>\ntypedef enum XalPrivilege\n{\n    /// <summary>The user can play with people outside of Xbox Live</summary>\n    XalPrivilege_CrossPlay              = 185,\n    /// <summary>Create/join/participate in Clubs</summary>\n    XalPrivilege_Clubs                  = 188,\n    /// <summary>Create/join non interactive multiplayer sessions</summary>\n    XalPrivilege_Sessions               = 189,\n    /// <summary>Broadcast live gameplay</summary>\n    XalPrivilege_BroadCast              = 190,\n    /// <summary>Change settings to show real name</summary>\n    XalPrivilege_ManageProfilePrivacy   = 196,\n    /// <summary>Upload GameDVR</summary>\n    XalPrivilege_GameDvr                = 198,\n    /// <summary>Join parties</summary>\n    XalPrivilege_MultiplayerParties     = 203,\n    /// <summary>Use Voice Chat in game or in parties</summary>\n    XalPrivilege_CommsInGameVoice       = 205,\n    /// <summary>Allocate cloud compute resources for their session</summary>\n    XalPrivilege_CloudManageSession     = 207,\n    /// <summary>Join cloud compute sessions</summary>\n    XalPrivilege_CloudJoinSession       = 208,\n    /// <summary>Save games on the cloud</summary>\n    XalPrivilege_CloudSavedGames        = 209,\n    /// <summary>Share progress to social networks</summary>\n    XalPrivilege_SocialNetworkSharing   = 220,\n    /// <summary>Access user generated content in game</summary>\n    XalPrivilege_Ugc                    = 247,\n    /// <summary>Use real time voice and text communication with users in their friends list</summary>\n    XalPrivilege_CommsFriendsOnly       = 251,\n    /// <summary>Use real time voice and text communication with all users</summary>\n    XalPrivilege_Comms                  = 252,\n    /// <summary>Join multiplayer sessions</summary>\n    XalPrivilege_Multiplayer            = 254,\n    /// <summary>Add friends / people to follow</summary>\n    XalPrivilege_AddFriends             = 255,\n} XalPrivilege;\n\n//------------------------------------------------------------------------------\n// User api types\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Handle to a user object. All operations on a user object are threadsafe.\n/// </summary>\n/// <remarks>\n/// User objects returned by Xal as out parameters already have had their\n/// reference count incremented, so XalUserRelease should be called when the\n/// caller is done with them.\n/// User objects passed as arguments to callbacks did not have their reference\n/// count incremented, the callback should call XalUserDuplicateHandle if they\n/// wish to hold onto the object (and XalUserCloseHandle when they are done).\n/// </remarks>\n#if !XAL_OS_IMPL\ntypedef struct XalUser* XalUserHandle;\n#else\n// XalUserHandle is defined in the platform specific header.\n// That header is included at the top of this file\n#endif\n\n/// <summary>\n/// Struct holding local user ID data.\n/// </summary>\n#if !XAL_OS_IMPL\ntypedef struct XalUserLocalId\n{\n    /// <summary>The local user ID</summary>\n    uint64_t value;\n} XalUserLocalId;\n#else\n// XalUserLocalId is defined in the platform specific header.\n// That header is included at the top of this file\n#endif\n\n/// <summary>\n/// Enum defining the possible states for a user object.\n/// </summary>\ntypedef enum XalUserState\n{\n    /// <summary>XAL signed in state</summary>\n    XalUserState_SignedIn = 0,\n    /// <summary>XAL signing out state</summary>\n    XalUserState_SigningOut = 1,\n    /// <summary>XAL signed out state</summary>\n    XalUserState_SignedOut = 2,\n} XalUserState;\n\n/// <summary>\n/// Enum defining the possible gamer picture sizes.\n/// </summary>\ntypedef enum XalGamerPictureSize\n{\n    /// <summary>64x64</summary>\n    XalGamerPictureSize_Small = 0,\n    /// <summary>208x208</summary>\n    XalGamerPictureSize_Medium = 1,\n    /// <summary>424x424</summary>\n    XalGamerPictureSize_Large = 2,\n    /// <summary>1080x1080</summary>\n    XalGamerPictureSize_ExtraLarge = 3,\n} XalGamerPictureSize;\n\n/// <summary>\n/// Enum defining the possible consent states.\n/// </summary>\n/// <remarks>\n/// The different states provide additional information for the client to adapt\n/// the UX, but only Opted In can be used as a positive signal, the rest should\n/// all be treated as Opted Out.\n/// </remarks>\ntypedef enum XalConsentState\n{\n    /// <summary>Unkown consent state due to query failure</summary>\n    /// <remarks>Should treat as Opted Out</remarks>\n    XalConsentState_QueryFailure = 0,\n    /// <summary>Model does not exist or does not apply for user</summary>\n    /// <remarks>Should treat as Opted Out</remarks>\n    XalConsentState_NotApplicable = 1,\n    /// <summary>User has been opted out</summary>\n    XalConsentState_OptedOut = 2,\n    /// <summary>User has been opted in</summary>\n    XalConsentState_OptedIn = 3,\n} XalConsentState;\n\n/// <summary>\n/// Enum defining the various gamertag components.\n/// </summary>\ntypedef enum XalGamertagComponent\n{\n    /// <summary>The classic gamertag</summary>\n    XalGamertagComponent_Classic = 0,\n    /// <summary>The modern gamertag without the suffix</summary>\n    XalGamertagComponent_Modern = 1,\n    /// <summary>The modern gamertag suffix if the user has one (otherwise empty)</summary>\n    XalGamertagComponent_ModernSuffix = 2,\n    /// <summary>The combined modern gamertag with the suffix (if the suffix exists)</summary>\n    XalGamertagComponent_UniqueModern = 3,\n} XalGamertagComponent;\n\n/// <summary>\n/// Enum defining the various age groups.\n/// </summary>\ntypedef enum XalAgeGroup\n{\n    /// <summary>Unknown age group</summary>\n    XalAgeGroup_Unknown = 0,\n    /// <summary>Child age group</summary>\n    XalAgeGroup_Child = 1,\n    /// <summary>Teen age group</summary>\n    XalAgeGroup_Teen = 2,\n    /// <summary>Adult age group</summary>\n    XalAgeGroup_Adult = 3,\n} XalAgeGroup;\n\n/// <summary>\n/// Enum defining the various reasons for a privilege being denied.\n/// </summary>\ntypedef enum XalPrivilegeCheckDenyReasons\n{\n    /// <summary>None</summary>\n    XalPrivilegeCheckDenyReasons_None = 0,\n    /// <summary>Purchase required</summary>\n    XalPrivilegeCheckDenyReasons_PurchaseRequired = 1,\n    /// <summary>Restricted</summary>\n    XalPrivilegeCheckDenyReasons_Restricted = 2,\n    /// <summary>Banned</summary>\n    XalPrivilegeCheckDenyReasons_Banned = 3,\n\n    /// <summary>Unknown</summary>\n    XalPrivilegeCheckDenyReasons_Unknown = 0xFFFFFFFF\n} XalPrivilegeCheckDenyReasons;\n\n//-----------------------------------------------------------------------------\n// Get token and signature\n\n/// <summary>\n/// Struct that represents an HTTP header.\n/// </summary>\ntypedef struct XalHttpHeader\n{\n    /// <summary>HTTP header name</summary>\n    _Field_z_ char const* name;\n\n    /// <summary>HTTP header value</summary>\n    _Field_z_ char const* value;\n} XalHttpHeader;\n\n/// <summary>\n/// Struct that encapsulates the arguments for\n/// XalUserGetTokenAndSignatureSilentlyAsync.\n/// </summary>\n/// <remarks>\n/// Xal will copy the data before XalUserGetTokenAndSignatureSilentlyAsync\n/// returns.\n/// </remarks>\ntypedef struct XalUserGetTokenAndSignatureArgs\n{\n    /// <summary>\n    /// The method for the request\n    /// </summary>\n    _Field_z_ char const* method;\n\n    /// <summary>\n    /// The url to get the token and to signature for (fully escaped).\n    /// </summary>\n    _Field_z_ char const* url;\n\n    /// <summary>\n    /// The number of headers that will be added to the HTTP request.\n    /// </summary>\n    uint32_t headerCount;\n\n    /// <summary>\n    /// The array of headers that will be added to the HTTP request.\n    /// </summary>\n    _Field_size_(headerCount) XalHttpHeader const* headers;\n\n    /// <summary>\n    /// The size of the request body in bytes.\n    /// </summary>\n    size_t bodySize;\n\n    /// <summary>\n    /// The request body.\n    /// </summary>\n    _Field_size_bytes_(bodySize) uint8_t const* body;\n\n    /// <summary>\n    /// Ignore cached tokens.\n    /// </summary>\n    /// <remarks>\n    /// This flag should only be set if an http request using a token and\n    /// signature failed with a 401 error. In that case the entire call should\n    /// be retried after getting a new token and signature using this flag.\n    /// </remarks>\n    bool forceRefresh;\n\n    /// <summary>\n    /// Get a token for all users.\n    /// </summary>\n    bool allUsers;\n\n    /// <summary>\n    /// Get a token with or without TitleIdentity.\n    /// </summary>\n    bool ignoreTitleIdentity;\n} XalUserGetTokenAndSignatureArgs;\n\n/// <summary>\n/// Struct that encapsulates the results for\n/// XalUserGetTokenAndSignatureSilentlyAsync.\n/// </summary>\ntypedef struct XalUserGetTokenAndSignatureData\n{\n    /// <summary>\n    /// The size of the Token string in bytes including the null terminator.\n    /// </summary>\n    size_t tokenSize;\n\n    /// <summary>\n    /// The size of the Signature string in bytes including the null terminator.\n    /// </summary>\n    size_t signatureSize;\n\n    /// <summary>\n    /// The token for the request, if necessary, as a null terminated string.\n    /// </summary>\n    _Field_size_opt_(tokenSize) _Null_terminated_ char const* token;\n\n    /// <summary>\n    /// The signature for the request, if necessary, as a null terminated\n    /// string.\n    /// </summary>\n    _Field_size_opt_(signatureSize) _Null_terminated_ char const* signature;\n} XalUserGetTokenAndSignatureData;\n\n//-----------------------------------------------------------------------------\n// Events\n\n/// <summary>\n/// Enum describing the possible types of changes to a user's details.\n/// </summary>\n#if !XAL_OS_IMPL\ntypedef enum XalUserChangeType\n{\n    /// <summary>Changed to signed in</summary>\n    XalUserChange_SignedInAgain = 0,\n    /// <summary>Changed to signing out</summary>\n    XalUserChange_SigningOut = 1,\n    /// <summary>Changed to signed out</summary>\n    XalUserChange_SignedOut = 2,\n    /// <summary>Changed gamertag</summary>\n    XalUserChange_Gamertag = 3,\n    /// <summary>Changed gamer picture</summary>\n    XalUserChange_GamerPicture = 4,\n    /// <summary>Changed privileges</summary>\n    XalUserChange_Privileges = 5,\n} XalUserChangeType;\n#else\n// XalUserChangeType is defined in the platform specific header.\n// That header is included at the top of this file\n#endif\n\n/// <summary>\n/// A token returned when registering a callback to identify the registration. This token\n/// is later used to unregister the callback.\n/// </summary>\nstruct XalRegistrationToken\n{\n    /// <summary>The registration token</summary>\n    uint64_t token;\n};\n\n/// <summary>\n/// Handle to a deferral object.\n/// </summary>\n#if !XAL_OS_IMPL\ntypedef struct XalSignoutDeferral* XalSignoutDeferralHandle;\n#else\n// XalSignoutDeferralHandle is defined in the platform specific header.\n// That header is included at the top of this file\n#endif\n\n//------------------------------------------------------------------------------\n// Date & time\n\n/// <summary>\n/// This struct represents a date.\n/// </summary>\n/// <remarks>\n/// The date is always in the Gregorian calendar and in the UTC timezone.\n/// </remarks>\ntypedef struct XalTimestampComponents\n{\n    /// <summary>\n    /// The year.\n    /// </summary>\n    uint16_t year;\n\n    /// <summary>\n    /// The month [1, 12].\n    /// </summary>\n    uint8_t month;\n\n    /// <summary>\n    /// The day of the month [1, 31].\n    /// </summary>\n    uint8_t day;\n\n    /// <summary>\n    /// The hour in the day [0, 24).\n    /// </summary>\n    uint8_t hour;\n\n    /// <summary>\n    /// The minute in the hour [0, 60).\n    /// </summary>\n    uint8_t minute;\n\n    /// <summary>\n    /// The second in the minute [0, 60).\n    /// </summary>\n    uint8_t second;\n} XalTimestampComponents;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_user.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <httpClient/async.h>\n#include <Xal/xal_types.h>\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// User Api\n//-----------------------------------------------------------------------------\n\n/// <summary>\n/// Increments the reference count on the user object.\n/// </summary>\n/// <param name=\"user\">The user handle.</param>\n/// <param name=\"duplicatedUser\">The new user handle.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\nSTDAPI XalUserDuplicateHandle(\n    _In_ XalUserHandle user,\n    _Out_ XalUserHandle* duplicatedUser\n) noexcept;\n\n/// <summary>\n/// Decrements the reference count on the user object.\n/// </summary>\n/// <param name=\"user\">The user object</param>\n/// <returns></returns>\nSTDAPI_(void) XalUserCloseHandle(\n    _In_ XalUserHandle user\n) noexcept;\n\n/// <summary>\n/// Compares 2 user handler.\n/// </summary>\n/// <param name=\"user1\">The first user.</param>\n/// <param name=\"user2\">The second user.</param>\n/// <returns>\n/// 0 if the two handles refer to the same xbox live identity, -1 if user1\n/// identity is \"less\" than user2, 1 if user1 identity \"greater\" than user2.\n/// </returns>\n/// <remarks>\n/// User identity ordering is arbitrary, but sutiable for sorting.\n/// </remarks>\nSTDAPI_(int32_t) XalCompareUsers(\n    _In_ XalUserHandle user1,\n    _In_ XalUserHandle user2\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// User properties\n\n/// <summary>\n/// Returns the Xbox Live User ID (XUID) of the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"id\">The Xbox Live User ID (XUID) of the user.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\nSTDAPI XalUserGetId( // TODO any valid error scenarios? local users, consent\n    _In_ XalUserHandle user,\n    _Out_ uint64_t* id\n) noexcept;\n\n/// <summary>\n/// Gets the local id of the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"localId\">The local id of the user.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\nSTDAPI XalUserGetLocalId(\n    _In_ XalUserHandle user,\n    _Out_ XalUserLocalId* localId\n) noexcept;\n\n/// <summary>\n/// Returns a boolean indicating if the user is the device user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <returns></returns>\nSTDAPI_(bool) XalUserIsDevice(\n    _In_ XalUserHandle user\n) noexcept;\n\n/// <summary>\n/// Returns a boolean indicating if the user is a guest.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <returns></returns>\nSTDAPI_(bool) XalUserIsGuest(\n    _In_ XalUserHandle user\n) noexcept;\n\n/// <summary>\n/// Returns the sign-in state of the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"state\">The sign-in state of the user</param>\n/// <see cref=\"XalUserState\" />.\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserGetState(\n    _In_ XalUserHandle user,\n    _Out_ XalUserState* state\n) noexcept;\n\n/// <summary>\n/// Returns the size of the buffer needed to store the gamertag string.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"component\">The component of the gamertag to get the size of.</param>\n/// <returns>The size of the buffer needed to store the gamertag string</returns>\n/// <remark>\n/// If XalGamertagComponent_Modern or XalGamertagComponent_UniqueModern are\n/// specified but not available on the platform, this function will execute for\n/// XalGamertagComponent_Classic instead. XalGamertagComponent_Suffix will be\n/// empty if the modern components are unavailable.\n/// </remark>\nSTDAPI_(size_t) XalUserGetGamertagSize(\n    _In_ XalUserHandle user,\n    _In_ XalGamertagComponent component\n) noexcept;\n\n/// <summary>\n/// Returns the gamertag of the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"component\">The component of the gamertag to get.</param>\n/// <param name=\"gamertagSize\">The size in bytes of the gamertag buffer.\n/// Should be the value returned by XalUserGetGamertagSize.</param>\n/// <param name=\"gamertag\">The buffer the gamertag will be written to.</param>\n/// <param name=\"gamertagUsed\">The number of bytes used in the buffer including\n/// the null terminator.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remark>\n/// If XalGamertagComponent_Modern or XalGamertagComponent_UniqueModern are\n/// specified but not available on the platform, this function will execute for\n/// XalGamertagComponent_Classic instead. XalGamertagComponent_Suffix will be\n/// empty if the modern components are unavailable.\n/// </remark>\nSTDAPI XalUserGetGamertag(\n    _In_ XalUserHandle user,\n    _In_ XalGamertagComponent component,\n    _In_ size_t gamertagSize,\n    _Out_writes_(gamertagSize) char* gamertag,\n    _Out_opt_ size_t* gamertagUsed\n) noexcept;\n\n/// <summary>\n/// Gets the gamer picture for the user as a png in memory buffer.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"pictureSize\">The size wanted.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK or E_FAIL.</returns>\nSTDAPI XalUserGetGamerPictureAsync(\n    _In_ XalUserHandle user,\n    _In_ XalGamerPictureSize pictureSize,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Gets the size in bytes of gamer picture buffer.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size in bytes for the result buffer.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserGetGamerPictureResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept;\n\n/// <summary>\n/// Gets the results of a successful XalUserGetGamerPictureAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the gamer picture buffer.</param>\n/// <param name=\"buffer\">The gamer picture png data.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserGetGamerPictureResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_(bufferSize) void* buffer\n) noexcept;\n\n/// <summary>\n/// Returns the age group of the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"ageGroup\">The age group.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\nSTDAPI XalUserGetAgeGroup(\n    _In_ XalUserHandle user,\n    _Out_ XalAgeGroup* ageGroup\n) noexcept;\n\n/// <summary>\n/// Checks if the user has the given privilege.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"privilege\">The privilege to check.</param>\n/// <param name=\"hasPrivilege\">true if the user has the privilege, false\n/// otherwise.</param>\n/// <param name=\"reasons\">Bitmask of the various reasons why the user could be\n/// denied a privilege. If the user has the privilege it will always be\n/// XAL_PRIVILEGE_CHECK_DENY_REASON_NONE.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\nSTDAPI XalUserCheckPrivilege(\n    _In_ XalUserHandle user,\n    _In_ XalPrivilege privilege,\n    _Out_ bool* hasPrivilege,\n    _Out_opt_ XalPrivilegeCheckDenyReasons* reasons\n) noexcept;\n\n/// <summary>\n/// Checks if the current platform supports resolving missing privileges.\n/// </summary>\n/// <returns></returns>\nSTDAPI_(bool) XalUserResolvePrivilegeWithUiIsPresent() noexcept;\n\n/// <summary>\n/// Shows ui explaining why the user is missing the given privilege and\n/// allows acquiring it.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"privilege\">The privilege to check.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserResolveUserPrivilegeWithUiAsync(\n    _In_ XalUserHandle user,\n    _In_ XalPrivilege privilege,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a given XalUserResolveUserPrivilegeWithUiAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserResolveUserPrivilegeWithUiResult(\n    _In_ XAsyncBlock* async\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Get token and signature\n\n/// <summary>\n/// Gets the appropriate token and signature for an HTTP request.\n/// </summary>\n/// <param name=\"user\">The user the token and signature are for.</param>\n/// <param name=\"args\">The HTTP request details.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <see cref=\"XalUserGetTokenAndSignatureArgs\" />.\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserGetTokenAndSignatureSilentlyAsync(\n    _In_ XalUserHandle user,\n    _In_ XalUserGetTokenAndSignatureArgs const* args,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Gets the size in bytes of the token and signature buffers.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size in bytes for the result buffer.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserGetTokenAndSignatureSilentlyResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept;\n\n/// <summary>\n/// Gets the results of a successful XalUserGetTokenAndSignatureSilentlyAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the buffer for the result object.</param>\n/// <param name=\"buffer\">Byte buffer used for result value and its fields.</param>\n/// <param name=\"result\">Pointer to the result object.</param>\n/// <param name=\"bufferUsed\">The number of bytes in the provided buffer that were used.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// result is a pointer within buffer and does not need to be freed separately.\n/// </remarks>\nSTDAPI XalUserGetTokenAndSignatureSilentlyResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XalUserGetTokenAndSignatureData** result,\n    _Out_opt_ size_t* bufferUsed\n) noexcept;\n\n/// <summary>\n/// This function will show the ui required to resolve certain errors in\n/// XalUserGetTokenAndSignatureSilentlyAsync.\n/// </summary>\n/// <param name=\"user\">The user the token and signature are for.</param>\n/// <param name=\"url\">The url of the request that failed.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This function should only be called after a call to\n/// XalUserGetTokenAndSignatureSilentlyAsync fails with E_XAL_UIREQUIRED.\n/// </remarks>\nSTDAPI XalUserResolveIssueWithUiAsync(\n    _In_ XalUserHandle user,\n    _In_opt_z_ char const* url,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a given XalUserResolveIssueWithUiAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserResolveIssueWithUiResult(\n    _In_ XAsyncBlock* async\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// UCS consent\n\n/// <summary>\n/// Checks the state of the given UCS consent for the user.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"consentModelName\">The UCS consent model name.</param>\n/// <param name=\"consentState\">The state of the consent.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserCheckUcsConsent(\n    _In_ XalUserHandle user,\n    _In_z_ char const* consentModelName,\n    _Out_ XalConsentState* consentState\n) noexcept;\n\n/// <summary>\n/// Shows ui explaining why the user is missing the given privilege and\n/// allows acquiring it.\n/// </summary>\n/// <param name=\"user\">The user object.</param>\n/// <param name=\"consentModelName\">The UCS consent model name.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserManageUcsConsentWithUiAsync(\n    _In_ XalUserHandle user,\n    _In_z_ char const* consentModelName,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n/// <summary>\n/// Get the result of a given XalUserManageUcsConsentWithUiAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"consentState\">The state of the consent.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalUserManageUcsConsentWithUiResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XalConsentState* consentState\n) noexcept;\n\n//-----------------------------------------------------------------------------\n// Events\n\n/// <summary>\n/// User detail change event handler.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.\n/// </param>\n/// <param name=\"userId\">The local id of the user that changed.</param>\n/// <param name=\"change\">The type of change.</param>\n/// <returns></returns>\n#if !XAL_OS_IMPL\ntypedef void (XalUserChangeEventHandler)(\n    _In_opt_ void* context,\n    _In_ XalUserLocalId userId,\n    _In_ XalUserChangeType change\n);\n#else\n// XalUserChangeEventHandler is defined in the platform specific header.\n// That header is included in xal_types.h\n#endif\n\n/// <summary>\n/// Register the event handler for user detail changes.\n/// </summary>\n/// <param name=\"queue\">The async queue the callback should be invoked on.</param>\n/// <param name=\"context\">Optional pointer to data used by the event handler.</param>\n/// <param name=\"handler\">The event handler, <see cref=\"XalUserChangeEventHandler\"/>.</param>\n/// <param name=\"token\">The token for unregistering this callback</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_XAL_NOTINITIALIZED, or E_FAIL.</returns>\nSTDAPI XalUserRegisterChangeEventHandler(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_opt_ void* context,\n    _In_ XalUserChangeEventHandler* handler,\n    _Out_ XalRegistrationToken* token\n) noexcept;\n\n/// <summary>\n/// Unregisters a previously registered callback.\n/// </summary>\n/// <param name=\"token\">The token returned from\n/// XalUserRegisterChangeEventHandler.</param>\n/// <returns></returns>\nSTDAPI_(void) XalUserUnregisterChangeEventHandler(\n    _In_ XalRegistrationToken token\n) noexcept;\n\n/// <summary>\n/// Get a signout deferral.\n/// </summary>\n/// <param name=\"deferral\">The deferral handle.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// May only be called from within a XalUserChangeEventHandler during a\n/// XalUserChange_SigningOut event. The signout process will be halted until\n/// the deferral handle is closed (or a timeout is reached).\n///\n/// May fail with E_XAL_DEFERRALNOTAVAILABLE.\n/// </remarks>\nSTDAPI XalUserGetSignoutDeferral(\n    _Out_ XalSignoutDeferralHandle* deferral\n) noexcept;\n\n/// <summary>\n/// Closes a signout deferral.\n/// </summary>\n/// <param name=\"deferral\">The deferral handle.</param>\n/// <returns></returns>\nSTDAPI_(void) XalUserCloseSignoutDeferral(\n    _In_ XalSignoutDeferralHandle deferral\n) noexcept;\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_uwp.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Uwp types\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Struct that encapsulates the Uwp specific arguments for Xal.\n/// </summary>\ntypedef struct XalUwpArgs\n{\n    /// <summary>\n    /// Xbox Live title id.\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// The package family name.\n    /// </summary>\n    _Field_z_ char const* packageFamilyName;\n\n    /// <summary>\n    /// A correlation vector string for XAL to use as a base. XAL will extend\n    /// this prior to using it. This argument is optional.\n    /// </summary>\n    _Field_z_ char const* correlationVector;\n\n    /// <summary>\n    /// Xal configuration flags.\n    /// </summary>\n    uint32_t flags;\n\n    /// <summary>\n    /// The user that launched the application, as provided by Application::OnLaunched()\n    /// </summary>\n    /// <remarks>\n    /// If left null, Xal will bring up the User Picker on Xbox when signing in with UI.\n    /// This field has no effect on the PC sign in flow.\n    /// </remarks>\n    Windows::System::User^ launchUser;\n\n    /// <summary>\n    /// The hwnd of the window that launched the sign in request\n    /// </summary>\n    /// <remarks>\n    /// If a centennial build, this is required for identifying the main window that\n    /// launched a sign in request. Otherwise this is unused.\n    /// </remarks>\n    HWND mainWindow;\n\n    /// <summary>\n    /// Optional Cobrand ID for MSA\n    /// </summary>\n    _Field_z_ char const* cobrandId;\n} XalUwpArgs;\n\ntypedef XalUwpArgs XalInitArgs;\n\n#define XAL_PLATFORM \"UWP\"\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_uwp_user.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <Xal/xal_types.h>\n#include <Xal/xal_user.h>\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Uwp user functions\n//------------------------------------------------------------------------------\nSTDAPI XalUserGetPlatformWebAccount(\n    _In_ XalUserHandle user,\n    _Out_ Windows::Security::Credentials::WebAccount^* webAccount\n) noexcept;\n\n/// <summary>\n/// Adds the given system user.\n/// </summary>\n/// <param name=\"user\">The system user.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XalAddUwpSystemUserSilentAsync(\n    _In_ Windows::System::User^ user,\n    _In_ XAsyncBlock* async\n) noexcept;\n\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_version.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\nextern \"C\"\n{\n\n//-----------------------------------------------------------------------------\n// Version\n//-----------------------------------------------------------------------------\n\n/// <summary>\n/// The macro definition of the current library version. It is a '.' delimited\n/// string where the fields have the following meanings. They are in order from\n/// left to right:\n/// YYYY Release year\n/// MM Release month\n/// YYYYMMDD Date string describing the date the build was created\n/// rrr QFE number (000 indicates base release)\n/// </summary>\n#define XAL_VERSION \"2025.07.20250718.000\"\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_win32.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Win32 types\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Struct that encapsulates the Win32 specific arguments for Xal.\n/// </summary>\ntypedef struct XalWin32Args\n{\n    /// <summary>\n    /// MSA client id.\n    /// </summary>\n    _Field_z_ char const* clientId;\n\n    /// <summary>\n    /// Xbox Live title id.\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// Xbox Live sandbox.\n    /// </summary>\n    /// <remarks>\n    /// If Xal detects a sandbox key in the registry it will use that value and\n    /// ignore the value passed in here.\n    /// </remarks>\n    _Field_z_ char const* sandbox;\n\n    /// <summary>\n    /// A bool indicating whether Xal can send diagnostic telemetry.\n    /// Setting this to true indicates to Xal that it does not have user consent\n    /// to report data about any crashes or errors it encounters during use.\n    /// If this variable is set to false, Xal assumes it can report this data.\n    /// </summary>\n    bool disableDiagnosticTelemetry;\n\n    /// <summary>\n    /// A correlation vector string for XAL to use as a base. XAL will extend\n    /// this prior to using it. This argument is optional.\n    /// </summary>\n    _Field_z_ char const* correlationVector;\n\n    /// <summary>\n    /// Xal configuration flags.\n    /// </summary>\n    uint32_t flags;\n\n    /// <summary>\n    /// The number of consents present in the ThirdPartyConsents array.\n    /// </summary>\n    uint32_t thirdPartyConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to access Xbox Live services.\n    /// </summary>\n    _Field_size_(thirdPartyConsentCount) char const** thirdPartyConsents;\n\n    /// <summary>\n    /// Win32 optional custom redirect URI.\n    /// </summary>\n    _Field_z_ char const* redirectUri;\n\n    /// <summary>\n    /// The number of consents present in the ucsConsents array\n    /// </summary>\n    uint32_t ucsConsentCount;\n\n    /// <summary>\n    /// An optional list of consent requests to UCS\n    /// </summary>\n    _Field_size_(ucsConsentCount) char const** ucsConsents;\n} XalWin32Args;\n\ntypedef XalWin32Args XalInitArgs;\n\n#define XAL_PLATFORM \"Win32\"\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_xdk.h",
    "content": "#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\nextern \"C\"\n{\n\n//------------------------------------------------------------------------------\n// Xdk types\n//------------------------------------------------------------------------------\n\n/// <summary>\n/// Struct that encapsulates the Xdk specific arguments for Xal.\n/// </summary>\ntypedef struct XalXdkArgs {} XalXdkArgs;\n\ntypedef XalXdkArgs XalInitArgs;\n\n#define XAL_PLATFORM \"XDK\"\n\n}\n"
  },
  {
    "path": "External/Xal/Source/Xal/Include/Xal/xal_xdk_ext.h",
    "content": "#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Returns the system user associated with the user handle.\n/// </summary>\n/// <param name=\"user\">The user handle.</param>\n/// <param name=\"systemUser\">The associated system user.</param>\nSTDAPI XalUserToXboxSystemUser(\n    _In_ XalUserHandle user,\n    _Out_ Windows::Xbox::System::IUser^* systemUser\n) noexcept;\n\n/// <summary>\n/// Add the given system user as a Xal user.\n/// </summary>\n/// <param name=\"systemUser\">The system user.</param>\n/// <param name=\"user\">The new user handle.</param>\nSTDAPI XalAddXboxSystemUser(\n    _In_ Windows::Xbox::System::IUser^ systemUser,\n    _Out_ XalUserHandle* user\n) noexcept;\n\n}\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/astreambuf.h",
    "content": "#if !XSAPI_NO_PPL\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n/***\n * Copyright (C) Microsoft. All rights reserved.\n * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n *\n * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n *\n * Asynchronous I/O: stream buffer. This is an extension to the PPL concurrency features and therefore\n * lives in the Concurrency namespace.\n *\n * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n *\n * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n ****/\n#pragma once\n\n#include \"cpprest/asyncrt_utils.h\"\n#include \"cpprest/details/basic_types.h\"\n#include \"pplx/pplxtasks.h\"\n#include <atomic>\n#include <cstring>\n#include <ios>\n#include <math.h>\n#include <memory>\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX\nnamespace Concurrency // since namespace pplx = Concurrency\n#else\nnamespace pplx\n#endif\n{\nnamespace details\n{\ntemplate<class F, class T = bool>\npplx::task<T> _do_while(F func)\n{\n    pplx::task<T> first = func();\n    return first.then([=](bool guard) -> pplx::task<T> {\n        if (guard)\n            return pplx::details::_do_while<F, T>(func);\n        else\n            return first;\n    });\n}\n} // namespace details\n}\n\nnamespace Concurrency\n{\n/// Library for asynchronous streams.\nnamespace streams\n{\n/// <summary>\n/// Extending the standard char_traits type with one that adds values and types\n/// that are unique to \"C++ REST SDK\" streams.\n/// </summary>\n/// <typeparam name=\"_CharType\">\n/// The data type of the basic element of the stream.\n/// </typeparam>\ntemplate<typename _CharType>\nstruct char_traits : std::char_traits<_CharType>\n{\n    /// <summary>\n    /// Some synchronous functions will return this value if the operation\n    /// requires an asynchronous call in a given situation.\n    /// </summary>\n    /// <returns>An <c>int_type</c> value which implies that an asynchronous call is required.</returns>\n    static typename std::char_traits<_CharType>::int_type requires_async()\n    {\n        return std::char_traits<_CharType>::eof() - 1;\n    }\n};\n#if !defined(_WIN32)\ntemplate<>\nstruct char_traits<unsigned char> : private std::char_traits<char>\n{\npublic:\n    typedef unsigned char char_type;\n\n    using std::char_traits<char>::eof;\n    using std::char_traits<char>::int_type;\n    using std::char_traits<char>::off_type;\n    using std::char_traits<char>::pos_type;\n\n    static size_t length(const unsigned char* str)\n    {\n        return std::char_traits<char>::length(reinterpret_cast<const char*>(str));\n    }\n\n    static void assign(unsigned char& left, const unsigned char& right) { left = right; }\n    static unsigned char* assign(unsigned char* left, size_t n, unsigned char value)\n    {\n        return reinterpret_cast<unsigned char*>(\n            std::char_traits<char>::assign(reinterpret_cast<char*>(left), n, static_cast<char>(value)));\n    }\n\n    static unsigned char* copy(unsigned char* left, const unsigned char* right, size_t n)\n    {\n        return reinterpret_cast<unsigned char*>(\n            std::char_traits<char>::copy(reinterpret_cast<char*>(left), reinterpret_cast<const char*>(right), n));\n    }\n\n    static unsigned char* move(unsigned char* left, const unsigned char* right, size_t n)\n    {\n        return reinterpret_cast<unsigned char*>(\n            std::char_traits<char>::move(reinterpret_cast<char*>(left), reinterpret_cast<const char*>(right), n));\n    }\n\n    static int_type requires_async() { return eof() - 1; }\n};\n#endif\n\nnamespace details\n{\n/// <summary>\n/// Stream buffer base class.\n/// </summary>\ntemplate<typename _CharType>\nclass basic_streambuf\n{\npublic:\n    typedef _CharType char_type;\n    typedef ::concurrency::streams::char_traits<_CharType> traits;\n\n    typedef typename traits::int_type int_type;\n    typedef typename traits::pos_type pos_type;\n    typedef typename traits::off_type off_type;\n\n    /// <summary>\n    /// Virtual constructor for stream buffers.\n    /// </summary>\n    virtual ~basic_streambuf() {}\n\n    /// <summary>\n    /// <c>can_read</c> is used to determine whether a stream buffer will support read operations (get).\n    /// </summary>\n    virtual bool can_read() const = 0;\n\n    /// <summary>\n    /// <c>can_write</c> is used to determine whether a stream buffer will support write operations (put).\n    /// </summary>\n    virtual bool can_write() const = 0;\n\n    /// <summary>\n    /// <c>can_seek<c/> is used to determine whether a stream buffer supports seeking.\n    /// </summary>\n    virtual bool can_seek() const = 0;\n\n    /// <summary>\n    /// <c>has_size<c/> is used to determine whether a stream buffer supports size().\n    /// </summary>\n    virtual bool has_size() const = 0;\n\n    /// <summary>\n    /// <c>is_eof</c> is used to determine whether a read head has reached the end of the buffer.\n    /// </summary>\n    virtual bool is_eof() const = 0;\n\n    /// <summary>\n    /// Gets the stream buffer size, if one has been set.\n    /// </summary>\n    /// <param name=\"direction\">The direction of buffering (in or out)</param>\n    /// <returns>The size of the internal buffer (for the given direction).</returns>\n    /// <remarks>An implementation that does not support buffering will always return 0.</remarks>\n    virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0;\n\n    /// <summary>\n    /// Sets the stream buffer implementation to buffer or not buffer.\n    /// </summary>\n    /// <param name=\"size\">The size to use for internal buffering, 0 if no buffering should be done.</param>\n    /// <param name=\"direction\">The direction of buffering (in or out)</param>\n    /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it\n    /// will not have any effect on what is returned by subsequent calls to <see cref=\"::buffer_size method\"\n    /// />.</remarks>\n    virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0;\n\n    /// <summary>\n    /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available\n    /// to be consumed without blocking. May be used in conjunction with <cref=\"::sbumpc method\"/> to read data without\n    /// incurring the overhead of using tasks.\n    /// </summary>\n    virtual size_t in_avail() const = 0;\n\n    /// <summary>\n    /// Checks if the stream buffer is open.\n    /// </summary>\n    /// <remarks>No separation is made between open for reading and open for writing.</remarks>\n    virtual bool is_open() const = 0;\n\n    /// <summary>\n    /// Closes the stream buffer, preventing further read or write operations.\n    /// </summary>\n    /// <param name=\"mode\">The I/O mode (in or out) to close for.</param>\n    virtual pplx::task<void> close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out)) = 0;\n\n    /// <summary>\n    /// Closes the stream buffer with an exception.\n    /// </summary>\n    /// <param name=\"mode\">The I/O mode (in or out) to close for.</param>\n    /// <param name=\"eptr\">Pointer to the exception.</param>\n    virtual pplx::task<void> close(std::ios_base::openmode mode, std::exception_ptr eptr) = 0;\n\n    /// <summary>\n    /// Writes a single character to the stream.\n    /// </summary>\n    /// <param name=\"ch\">The character to write</param>\n    /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the write operation\n    /// fails.</returns>\n    virtual pplx::task<int_type> putc(_CharType ch) = 0;\n\n    /// <summary>\n    /// Writes a number of characters to the stream.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be written.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    /// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>\n    virtual pplx::task<size_t> putn(const _CharType* ptr, size_t count) = 0;\n\n    /// <summary>\n    /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until\n    /// the returned task completes.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be written.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    /// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>\n    virtual pplx::task<size_t> putn_nocopy(const _CharType* ptr, size_t count) = 0;\n\n    /// <summary>\n    /// Reads a single character from the stream and advances the read position.\n    /// </summary>\n    /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the read fails.</returns>\n    virtual pplx::task<int_type> bumpc() = 0;\n\n    /// <summary>\n    /// Reads a single character from the stream and advances the read position.\n    /// </summary>\n    /// <returns>The value of the character. <c>-1</c> if the read fails. <c>-2</c> if an asynchronous read is\n    /// required</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>\n    virtual int_type sbumpc() = 0;\n\n    /// <summary>\n    /// Reads a single character from the stream without advancing the read position.\n    /// </summary>\n    /// <returns>A <c>task</c> that holds the value of the byte. This value is EOF if the read fails.</returns>\n    virtual pplx::task<int_type> getc() = 0;\n\n    /// <summary>\n    /// Reads a single character from the stream without advancing the read position.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails. <see cref=\"::requires_async method\" /> if an\n    /// asynchronous read is required</returns> <remarks>This is a synchronous operation, but is guaranteed to never\n    /// block.</remarks>\n    virtual int_type sgetc() = 0;\n\n    /// <summary>\n    /// Advances the read position, then returns the next character without advancing again.\n    /// </summary>\n    /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the read fails.</returns>\n    virtual pplx::task<int_type> nextc() = 0;\n\n    /// <summary>\n    /// Retreats the read position, then returns the current character without advancing.\n    /// </summary>\n    /// <returns>A <c>task</c> that holds the value of the character. This value is EOF if the read fails,\n    /// <c>requires_async</c> if an asynchronous read is required</returns>\n    virtual pplx::task<int_type> ungetc() = 0;\n\n    /// <summary>\n    /// Reads up to a given number of characters from the stream.\n    /// </summary>\n    /// <param name=\"ptr\">The address of the target memory area.</param>\n    /// <param name=\"count\">The maximum number of characters to read.</param>\n    /// <returns>A <c>task</c> that holds the number of characters read. This value is O if the end of the stream is\n    /// reached.</returns>\n    virtual pplx::task<size_t> getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0;\n\n    /// <summary>\n    /// Copies up to a given number of characters from the stream, synchronously.\n    /// </summary>\n    /// <param name=\"ptr\">The address of the target memory area.</param>\n    /// <param name=\"count\">The maximum number of characters to read.</param>\n    /// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is\n    /// required.</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>\n    virtual size_t scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0;\n\n    /// <summary>\n    /// Gets the current read or write position in the stream.\n    /// </summary>\n    /// <param name=\"direction\">The I/O direction to seek (see remarks)</param>\n    /// <returns>The current position. EOF if the operation fails.</returns>\n    /// <remarks>Some streams may have separate write and read cursors.\n    ///          For such streams, the direction parameter defines whether to move the read or the write\n    ///          cursor.</remarks>\n    virtual pos_type getpos(std::ios_base::openmode direction) const = 0;\n\n    /// <summary>\n    /// Gets the size of the stream, if known. Calls to <c>has_size</c> will determine whether\n    /// the result of <c>size</c> can be relied on.\n    /// </summary>\n    virtual utility::size64_t size() const = 0;\n\n    /// <summary>\n    /// Seeks to the given position.\n    /// </summary>\n    /// <param name=\"pos\">The offset from the beginning of the stream.</param>\n    /// <param name=\"direction\">The I/O direction to seek (see remarks).</param>\n    /// <returns>The position. EOF if the operation fails.</returns>\n    /// <remarks>Some streams may have separate write and read cursors. For such streams, the direction parameter\n    /// defines whether to move the read or the write cursor.</remarks>\n    virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0;\n\n    /// <summary>\n    /// Seeks to a position given by a relative offset.\n    /// </summary>\n    /// <param name=\"offset\">The relative position to seek to</param>\n    /// <param name=\"way\">The starting point (beginning, end, current) for the seek.</param>\n    /// <param name=\"mode\">The I/O direction to seek (see remarks)</param>\n    /// <returns>The position. EOF if the operation fails.</returns>\n    /// <remarks>Some streams may have separate write and read cursors.\n    ///          For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>\n    virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0;\n\n    /// <summary>\n    /// For output streams, flush any internally buffered data to the underlying medium.\n    /// </summary>\n    /// <returns>A <c>task</c> that returns <c>true</c> if the sync succeeds, <c>false</c> if not.</returns>\n    virtual pplx::task<void> sync() = 0;\n\n    //\n    // Efficient read and write.\n    //\n    // The following routines are intended to be used for more efficient, copy-free, reading and\n    // writing of data from/to the stream. Rather than having the caller provide a buffer into which\n    // data is written or from which it is read, the stream buffer provides a pointer directly to the\n    // internal data blocks that it is using. Since not all stream buffers use internal data structures\n    // to copy data, the functions may not be supported by all. An application that wishes to use this\n    // functionality should therefore first try them and check for failure to support. If there is\n    // such failure, the application should fall back on the copying interfaces (putn / getn)\n    //\n\n    /// <summary>\n    /// Allocates a contiguous memory block and returns it.\n    /// </summary>\n    /// <param name=\"count\">The number of characters to allocate.</param>\n    /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support\n    /// alloc/commit.</returns>\n    virtual _CharType* alloc(_In_ size_t count) = 0;\n\n    /// <summary>\n    /// Submits a block already allocated by the stream buffer.\n    /// </summary>\n    /// <param name=\"count\">The number of characters to be committed.</param>\n    virtual void commit(_In_ size_t count) = 0;\n\n    /// <summary>\n    /// Gets a pointer to the next already allocated contiguous block of data.\n    /// </summary>\n    /// <param name=\"ptr\">A reference to a pointer variable that will hold the address of the block on success.</param>\n    /// <param name=\"count\">The number of contiguous characters available at the address in 'ptr'.</param>\n    /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>\n    /// <remarks>\n    /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that\n    /// there is no block to return immediately or that the stream buffer does not support the operation.\n    /// The stream buffer may not de-allocate the block until <see cref=\"::release method\" /> is called.\n    /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;\n    /// a subsequent read will not succeed.\n    /// </remarks>\n    virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) = 0;\n\n    /// <summary>\n    /// Releases a block of data acquired using <see cref=\"::acquire method\"/>. This frees the stream buffer to\n    /// de-allocate the memory, if it so desires. Move the read position ahead by the count.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be released.</param>\n    /// <param name=\"count\">The number of characters that were read.</param>\n    virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0;\n\n    /// <summary>\n    /// Retrieves the stream buffer exception_ptr if it has been set.\n    /// </summary>\n    /// <returns>Pointer to the exception, if it has been set; otherwise, <c>nullptr</c> will be returned</returns>\n    virtual std::exception_ptr exception() const = 0;\n};\n\ntemplate<typename _CharType>\nclass streambuf_state_manager : public basic_streambuf<_CharType>,\n                                public std::enable_shared_from_this<streambuf_state_manager<_CharType>>\n{\npublic:\n    typedef typename details::basic_streambuf<_CharType>::traits traits;\n    typedef typename details::basic_streambuf<_CharType>::int_type int_type;\n    typedef typename details::basic_streambuf<_CharType>::pos_type pos_type;\n    typedef typename details::basic_streambuf<_CharType>::off_type off_type;\n\n    /// <summary>\n    /// <c>can_read</c> is used to determine whether a stream buffer will support read operations (get).\n    /// </summary>\n    virtual bool can_read() const { return m_stream_can_read; }\n\n    /// <summary>\n    /// <c>can_write</c> is used to determine whether a stream buffer will support write operations (put).\n    /// </summary>\n    virtual bool can_write() const { return m_stream_can_write; }\n\n    /// <summary>\n    /// Checks if the stream buffer is open.\n    /// </summary>\n    /// <remarks>No separation is made between open for reading and open for writing.</remarks>\n    virtual bool is_open() const { return can_read() || can_write(); }\n\n    /// <summary>\n    /// Closes the stream buffer, preventing further read or write operations.\n    /// </summary>\n    /// <param name=\"mode\">The I/O mode (in or out) to close for.</param>\n    virtual pplx::task<void> close(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)\n    {\n        pplx::task<void> closeOp = pplx::task_from_result();\n\n        if (mode & std::ios_base::in && can_read())\n        {\n            closeOp = _close_read();\n        }\n\n        // After the flush_internal task completed, \"this\" object may have been destroyed,\n        // accessing the members is invalid, use shared_from_this to avoid access violation exception.\n        auto this_ptr = std::static_pointer_cast<streambuf_state_manager>(this->shared_from_this());\n\n        if (mode & std::ios_base::out && can_write())\n        {\n            if (closeOp.is_done())\n                closeOp = closeOp && _close_write().then([this_ptr] {}); // passing down exceptions from closeOp\n            else\n                closeOp = closeOp.then([this_ptr] { return this_ptr->_close_write().then([this_ptr] {}); });\n        }\n\n        return closeOp;\n    }\n\n    /// <summary>\n    /// Closes the stream buffer with an exception.\n    /// </summary>\n    /// <param name=\"mode\">The I/O mode (in or out) to close for.</param>\n    /// <param name=\"eptr\">Pointer to the exception.</param>\n    virtual pplx::task<void> close(std::ios_base::openmode mode, std::exception_ptr eptr)\n    {\n        if (m_currentException == nullptr) m_currentException = eptr;\n        return close(mode);\n    }\n\n    /// <summary>\n    /// <c>is_eof</c> is used to determine whether a read head has reached the end of the buffer.\n    /// </summary>\n    virtual bool is_eof() const { return m_stream_read_eof; }\n\n    /// <summary>\n    /// Writes a single character to the stream.\n    /// </summary>\n    /// <param name=\"ch\">The character to write</param>\n    /// <returns>The value of the character. EOF if the write operation fails</returns>\n    virtual pplx::task<int_type> putc(_CharType ch)\n    {\n        if (!can_write()) return create_exception_checked_value_task<int_type>(traits::eof());\n\n        return create_exception_checked_task<int_type>(_putc(ch), [](int_type) {\n            return false; // no EOF for write\n        });\n    }\n\n    /// <summary>\n    /// Writes a number of characters to the stream.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be written.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    /// <returns>The number of characters actually written, either 'count' or 0.</returns>\n    CASABLANCA_DEPRECATED(\"This API in some cases performs a copy. It is deprecated and will be removed in a future \"\n                          \"release. Use putn_nocopy instead.\")\n    virtual pplx::task<size_t> putn(const _CharType* ptr, size_t count)\n    {\n        if (!can_write()) return create_exception_checked_value_task<size_t>(0);\n        if (count == 0) return pplx::task_from_result<size_t>(0);\n\n        return create_exception_checked_task<size_t>(_putn(ptr, count, true), [](size_t) {\n            return false; // no EOF for write\n        });\n    }\n\n    /// <summary>\n    /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until\n    /// the returned task completes.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be written.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    /// <returns>A <c>task</c> that holds the number of characters actually written, either 'count' or 0.</returns>\n    virtual pplx::task<size_t> putn_nocopy(const _CharType* ptr, size_t count)\n    {\n        if (!can_write()) return create_exception_checked_value_task<size_t>(0);\n        if (count == 0) return pplx::task_from_result<size_t>(0);\n\n        return create_exception_checked_task<size_t>(_putn(ptr, count), [](size_t) {\n            return false; // no EOF for write\n        });\n    }\n\n    /// <summary>\n    /// Reads a single character from the stream and advances the read position.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails.</returns>\n    virtual pplx::task<int_type> bumpc()\n    {\n        if (!can_read())\n            return create_exception_checked_value_task<int_type>(streambuf_state_manager<_CharType>::traits::eof());\n\n        return create_exception_checked_task<int_type>(\n            _bumpc(), [](int_type val) { return val == streambuf_state_manager<_CharType>::traits::eof(); });\n    }\n\n    /// <summary>\n    /// Reads a single character from the stream and advances the read position.\n    /// </summary>\n    /// <returns>The value of the character. <c>-1</c> if the read fails. <c>-2</c> if an asynchronous read is\n    /// required</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>\n    virtual int_type sbumpc()\n    {\n        if (!(m_currentException == nullptr)) std::rethrow_exception(m_currentException);\n        if (!can_read()) return traits::eof();\n        return check_sync_read_eof(_sbumpc());\n    }\n\n    /// <summary>\n    /// Reads a single character from the stream without advancing the read position.\n    /// </summary>\n    /// <returns>The value of the byte. EOF if the read fails.</returns>\n    virtual pplx::task<int_type> getc()\n    {\n        if (!can_read()) return create_exception_checked_value_task<int_type>(traits::eof());\n\n        return create_exception_checked_task<int_type>(\n            _getc(), [](int_type val) { return val == streambuf_state_manager<_CharType>::traits::eof(); });\n    }\n\n    /// <summary>\n    /// Reads a single character from the stream without advancing the read position.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails. <see cref=\"::requires_async method\" /> if an\n    /// asynchronous read is required</returns> <remarks>This is a synchronous operation, but is guaranteed to never\n    /// block.</remarks>\n    virtual int_type sgetc()\n    {\n        if (!(m_currentException == nullptr)) std::rethrow_exception(m_currentException);\n        if (!can_read()) return traits::eof();\n        return check_sync_read_eof(_sgetc());\n    }\n\n    /// <summary>\n    /// Advances the read position, then returns the next character without advancing again.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails.</returns>\n    virtual pplx::task<int_type> nextc()\n    {\n        if (!can_read()) return create_exception_checked_value_task<int_type>(traits::eof());\n\n        return create_exception_checked_task<int_type>(\n            _nextc(), [](int_type val) { return val == streambuf_state_manager<_CharType>::traits::eof(); });\n    }\n\n    /// <summary>\n    /// Retreats the read position, then returns the current character without advancing.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails. <see cref=\"::requires_async method\" /> if an\n    /// asynchronous read is required</returns>\n    virtual pplx::task<int_type> ungetc()\n    {\n        if (!can_read()) return create_exception_checked_value_task<int_type>(traits::eof());\n\n        return create_exception_checked_task<int_type>(_ungetc(), [](int_type) { return false; });\n    }\n\n    /// <summary>\n    /// Reads up to a given number of characters from the stream.\n    /// </summary>\n    /// <param name=\"ptr\">The address of the target memory area.</param>\n    /// <param name=\"count\">The maximum number of characters to read.</param>\n    /// <returns>The number of characters read. O if the end of the stream is reached.</returns>\n    virtual pplx::task<size_t> getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count)\n    {\n        if (!can_read()) return create_exception_checked_value_task<size_t>(0);\n        if (count == 0) return pplx::task_from_result<size_t>(0);\n\n        return create_exception_checked_task<size_t>(_getn(ptr, count), [](size_t val) { return val == 0; });\n    }\n\n    /// <summary>\n    /// Copies up to a given number of characters from the stream, synchronously.\n    /// </summary>\n    /// <param name=\"ptr\">The address of the target memory area.</param>\n    /// <param name=\"count\">The maximum number of characters to read.</param>\n    /// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is\n    /// required.</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>\n    virtual size_t scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count)\n    {\n        if (!(m_currentException == nullptr)) std::rethrow_exception(m_currentException);\n        if (!can_read()) return 0;\n\n        return _scopy(ptr, count);\n    }\n\n    /// <summary>\n    /// For output streams, flush any internally buffered data to the underlying medium.\n    /// </summary>\n    /// <returns><c>true</c> if the flush succeeds, <c>false</c> if not</returns>\n    virtual pplx::task<void> sync()\n    {\n        if (!can_write())\n        {\n            if (m_currentException == nullptr)\n                return pplx::task_from_result();\n            else\n                return pplx::task_from_exception<void>(m_currentException);\n        }\n        return create_exception_checked_task<bool>(_sync(), [](bool) { return false; }).then([](bool) {});\n    }\n\n    /// <summary>\n    /// Retrieves the stream buffer exception_ptr if it has been set.\n    /// </summary>\n    /// <returns>Pointer to the exception, if it has been set; otherwise, <c>nullptr</c> will be returned.</returns>\n    virtual std::exception_ptr exception() const { return m_currentException; }\n\n    /// <summary>\n    /// Allocates a contiguous memory block and returns it.\n    /// </summary>\n    /// <param name=\"count\">The number of characters to allocate.</param>\n    /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support\n    /// alloc/commit.</returns> <remarks>This is intended as an advanced API to be used only when it is important to\n    /// avoid extra copies.</remarks>\n    _CharType* alloc(size_t count)\n    {\n        if (m_alloced)\n            throw std::logic_error(\n                \"The buffer is already allocated, this maybe caused by overlap of stream read or write\");\n\n        _CharType* alloc_result = _alloc(count);\n\n        if (alloc_result) m_alloced = true;\n\n        return alloc_result;\n    }\n\n    /// <summary>\n    /// Submits a block already allocated by the stream buffer.\n    /// </summary>\n    /// <param name=\"count\">The number of characters to be committed.</param>\n    /// <remarks>This is intended as an advanced API to be used only when it is important to avoid extra\n    /// copies.</remarks>\n    void commit(size_t count)\n    {\n        if (!m_alloced) throw std::logic_error(\"The buffer needs to allocate first\");\n\n        _commit(count);\n        m_alloced = false;\n    }\n\npublic:\n    virtual bool can_seek() const = 0;\n    virtual bool has_size() const = 0;\n    virtual utility::size64_t size() const { return 0; }\n    virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const = 0;\n    virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in) = 0;\n    virtual size_t in_avail() const = 0;\n    virtual pos_type getpos(std::ios_base::openmode direction) const = 0;\n    virtual pos_type seekpos(pos_type pos, std::ios_base::openmode direction) = 0;\n    virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode) = 0;\n    virtual bool acquire(_Out_writes_(count) _CharType*& ptr, _In_ size_t& count) = 0;\n    virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0;\n\nprotected:\n    virtual pplx::task<int_type> _putc(_CharType ch) = 0;\n\n    // This API is only needed for file streams and until we remove the deprecated stream buffer putn overload.\n    virtual pplx::task<size_t> _putn(const _CharType* ptr, size_t count, bool)\n    {\n        // Default to no copy, only the file streams API overloads and performs a copy.\n        return _putn(ptr, count);\n    }\n    virtual pplx::task<size_t> _putn(const _CharType* ptr, size_t count) = 0;\n\n    virtual pplx::task<int_type> _bumpc() = 0;\n    virtual int_type _sbumpc() = 0;\n    virtual pplx::task<int_type> _getc() = 0;\n    virtual int_type _sgetc() = 0;\n    virtual pplx::task<int_type> _nextc() = 0;\n    virtual pplx::task<int_type> _ungetc() = 0;\n    virtual pplx::task<size_t> _getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0;\n    virtual size_t _scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count) = 0;\n    virtual pplx::task<bool> _sync() = 0;\n    virtual _CharType* _alloc(size_t count) = 0;\n    virtual void _commit(size_t count) = 0;\n\n    /// <summary>\n    /// The real read head close operation, implementation should override it if there is any resource to be released.\n    /// </summary>\n    virtual pplx::task<void> _close_read()\n    {\n        m_stream_can_read = false;\n        return pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// The real write head close operation, implementation should override it if there is any resource to be released.\n    /// </summary>\n    virtual pplx::task<void> _close_write()\n    {\n        m_stream_can_write = false;\n        return pplx::task_from_result();\n    }\n\nprotected:\n    streambuf_state_manager(std::ios_base::openmode mode)\n    {\n        m_stream_can_read = (mode & std::ios_base::in) != 0;\n        m_stream_can_write = (mode & std::ios_base::out) != 0;\n        m_stream_read_eof = false;\n        m_alloced = false;\n    }\n\n    std::exception_ptr m_currentException;\n    // The in/out mode for the buffer\n    std::atomic<bool> m_stream_can_read;\n    std::atomic<bool> m_stream_can_write;\n    std::atomic<bool> m_stream_read_eof;\n    std::atomic<bool> m_alloced;\n\nprivate:\n    template<typename _CharType1>\n    pplx::task<_CharType1> create_exception_checked_value_task(const _CharType1& val) const\n    {\n        if (this->exception() == nullptr)\n            return pplx::task_from_result<_CharType1>(static_cast<_CharType1>(val));\n        else\n            return pplx::task_from_exception<_CharType1>(this->exception());\n    }\n\n    // Set exception and eof states for async read\n    template<typename _CharType1>\n    pplx::task<_CharType1> create_exception_checked_task(pplx::task<_CharType1> result,\n                                                         std::function<bool(_CharType1)> eof_test,\n                                                         std::ios_base::openmode mode = std::ios_base::in |\n                                                                                        std::ios_base::out)\n    {\n        auto thisPointer = this->shared_from_this();\n\n        auto func1 = [=](pplx::task<_CharType1> t1) -> pplx::task<_CharType1> {\n            try\n            {\n                thisPointer->m_stream_read_eof = eof_test(t1.get());\n            }\n            catch (...)\n            {\n                thisPointer->close(mode, std::current_exception()).get();\n                return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options());\n            }\n            if (thisPointer->m_stream_read_eof && !(thisPointer->exception() == nullptr))\n                return pplx::task_from_exception<_CharType1>(thisPointer->exception(), pplx::task_options());\n            return t1;\n        };\n\n        if (result.is_done())\n        {\n            // If the data is already available, we should avoid scheduling a continuation, so we do it inline.\n            return func1(result);\n        }\n        else\n        {\n            return result.then(func1);\n        }\n    }\n\n    // Set eof states for sync read\n    int_type check_sync_read_eof(int_type ch)\n    {\n        m_stream_read_eof = ch == traits::eof();\n        return ch;\n    }\n};\n\n} // namespace details\n\n// Forward declarations\ntemplate<typename _CharType>\nclass basic_istream;\ntemplate<typename _CharType>\nclass basic_ostream;\n\n/// <summary>\n/// Reference-counted stream buffer.\n/// </summary>\n/// <typeparam name=\"_CharType\">\n/// The data type of the basic element of the <c>streambuf.</c>\n/// </typeparam>\n/// <typeparam name=\"_CharType2\">\n/// The data type of the basic element of the <c>streambuf.</c>\n/// </typeparam>\ntemplate<typename _CharType>\nclass streambuf : public details::basic_streambuf<_CharType>\n{\npublic:\n    typedef typename details::basic_streambuf<_CharType>::traits traits;\n    typedef typename details::basic_streambuf<_CharType>::int_type int_type;\n    typedef typename details::basic_streambuf<_CharType>::pos_type pos_type;\n    typedef typename details::basic_streambuf<_CharType>::off_type off_type;\n    typedef typename details::basic_streambuf<_CharType>::char_type char_type;\n\n    template<typename _CharType2>\n    friend class streambuf;\n\n    /// <summary>\n    /// Constructor.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the concrete stream buffer implementation.</param>\n    streambuf(_In_ const std::shared_ptr<details::basic_streambuf<_CharType>>& ptr) : m_buffer(ptr) {}\n\n    /// <summary>\n    /// Default constructor.\n    /// </summary>\n    streambuf() {}\n\n    /// <summary>\n    /// Converter Constructor.\n    /// </summary>\n    /// <typeparam name=\"AlterCharType\">\n    /// The data type of the basic element of the source <c>streambuf</c>.\n    /// </typeparam>\n    /// <param name=\"other\">The source buffer to be converted.</param>\n    template<typename AlterCharType>\n    streambuf(const streambuf<AlterCharType>& other)\n        : m_buffer(std::static_pointer_cast<details::basic_streambuf<_CharType>>(\n              std::static_pointer_cast<void>(other.m_buffer)))\n    {\n        static_assert(std::is_same<pos_type, typename details::basic_streambuf<AlterCharType>::pos_type>::value &&\n                          std::is_same<off_type, typename details::basic_streambuf<AlterCharType>::off_type>::value &&\n                          std::is_integral<_CharType>::value && std::is_integral<AlterCharType>::value &&\n                          std::is_integral<int_type>::value &&\n                          std::is_integral<typename details::basic_streambuf<AlterCharType>::int_type>::value &&\n                          sizeof(_CharType) == sizeof(AlterCharType) &&\n                          sizeof(int_type) == sizeof(typename details::basic_streambuf<AlterCharType>::int_type),\n                      \"incompatible stream character types\");\n    }\n\n    /// <summary>\n    /// Constructs an input stream head for this stream buffer.\n    /// </summary>\n    /// <returns><c>basic_istream</c>.</returns>\n    concurrency::streams::basic_istream<_CharType> create_istream() const\n    {\n        if (!can_read()) throw std::runtime_error(\"stream buffer not set up for input of data\");\n        return concurrency::streams::basic_istream<_CharType>(*this);\n    }\n\n    /// <summary>\n    /// Constructs an output stream for this stream buffer.\n    /// </summary>\n    /// <returns>basic_ostream</returns>\n    concurrency::streams::basic_ostream<_CharType> create_ostream() const\n    {\n        if (!can_write()) throw std::runtime_error(\"stream buffer not set up for output of data\");\n        return concurrency::streams::basic_ostream<_CharType>(*this);\n    }\n\n    /// <summary>\n    /// Checks if the stream buffer has been initialized or not.\n    /// </summary>\n    operator bool() const { return (bool)m_buffer; }\n\n    /// <summary>\n    /// Destructor\n    /// </summary>\n    virtual ~streambuf() {}\n\n    const std::shared_ptr<details::basic_streambuf<_CharType>>& get_base() const\n    {\n        if (!m_buffer)\n        {\n            throw std::invalid_argument(\"Invalid streambuf object\");\n        }\n\n        return m_buffer;\n    }\n\n    /// <summary>\n    /// <c>can_read</c> is used to determine whether a stream buffer will support read operations (get).\n    /// </summary>\n    virtual bool can_read() const { return get_base()->can_read(); }\n\n    /// <summary>\n    /// <c>can_write</c> is used to determine whether a stream buffer will support write operations (put).\n    /// </summary>\n    virtual bool can_write() const { return get_base()->can_write(); }\n\n    /// <summary>\n    /// <c>can_seek</c> is used to determine whether a stream buffer supports seeking.\n    /// </summary>\n    /// <returns>True if seeking is supported, false otherwise.</returns>\n    virtual bool can_seek() const { return get_base()->can_seek(); }\n\n    /// <summary>\n    /// <c>has_size</c> is used to determine whether a stream buffer supports size().\n    /// </summary>\n    /// <returns>True if the <c>size</c> API is supported, false otherwise.</returns>\n    virtual bool has_size() const { return get_base()->has_size(); }\n\n    /// <summary>\n    /// Gets the total number of characters in the stream buffer, if known. Calls to <c>has_size</c> will determine\n    /// whether the result of <c>size</c> can be relied on.\n    /// </summary>\n    /// <returns>The total number of characters in the stream buffer.</returns>\n    virtual utility::size64_t size() const { return get_base()->size(); }\n\n    /// <summary>\n    /// Gets the stream buffer size, if one has been set.\n    /// </summary>\n    /// <param name=\"direction\">The direction of buffering (in or out)</param>\n    /// <returns>The size of the internal buffer (for the given direction).</returns>\n    /// <remarks>An implementation that does not support buffering will always return 0.</remarks>\n    virtual size_t buffer_size(std::ios_base::openmode direction = std::ios_base::in) const\n    {\n        return get_base()->buffer_size(direction);\n    }\n\n    /// <summary>\n    /// Sets the stream buffer implementation to buffer or not buffer.\n    /// </summary>\n    /// <param name=\"size\">The size to use for internal buffering, 0 if no buffering should be done.</param>\n    /// <param name=\"direction\">The direction of buffering (in or out)</param>\n    /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it\n    /// will not have any effect on what is returned by subsequent calls to <see cref=\"::buffer_size method\"\n    /// />.</remarks>\n    virtual void set_buffer_size(size_t size, std::ios_base::openmode direction = std::ios_base::in)\n    {\n        get_base()->set_buffer_size(size, direction);\n    }\n\n    /// <summary>\n    /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available\n    /// to be consumed without blocking. May be used in conjunction with <cref=\"::sbumpc method\"/> to read data without\n    /// incurring the overhead of using tasks.\n    /// </summary>\n    /// <returns>Number of characters that are ready to read.</returns>\n    virtual size_t in_avail() const { return get_base()->in_avail(); }\n\n    /// <summary>\n    /// Checks if the stream buffer is open.\n    /// </summary>\n    /// <remarks>No separation is made between open for reading and open for writing.</remarks>\n    /// <returns>True if the stream buffer is open for reading or writing, false otherwise.</returns>\n    virtual bool is_open() const { return get_base()->is_open(); }\n\n    /// <summary>\n    /// <c>is_eof</c> is used to determine whether a read head has reached the end of the buffer.\n    /// </summary>\n    /// <returns>True if at the end of the buffer, false otherwise.</returns>\n    virtual bool is_eof() const { return get_base()->is_eof(); }\n\n    /// <summary>\n    /// Closes the stream buffer, preventing further read or write operations.\n    /// </summary>\n    /// <param name=\"mode\">The I/O mode (in or out) to close for.</param>\n    virtual pplx::task<void> close(std::ios_base::openmode mode = (std::ios_base::in | std::ios_base::out))\n    {\n        // We preserve the check here to workaround a Dev10 compiler crash\n        auto buffer = get_base();\n        return buffer ? buffer->close(mode) : pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// Closes the stream buffer with an exception.\n    /// </summary>\n    /// <param name=\"mode\">The I/O mode (in or out) to close for.</param>\n    /// <param name=\"eptr\">Pointer to the exception.</param>\n    virtual pplx::task<void> close(std::ios_base::openmode mode, std::exception_ptr eptr)\n    {\n        // We preserve the check here to workaround a Dev10 compiler crash\n        auto buffer = get_base();\n        return buffer ? buffer->close(mode, eptr) : pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// Writes a single character to the stream.\n    /// </summary>\n    /// <param name=\"ch\">The character to write</param>\n    /// <returns>The value of the character. EOF if the write operation fails</returns>\n    virtual pplx::task<int_type> putc(_CharType ch) { return get_base()->putc(ch); }\n\n    /// <summary>\n    /// Allocates a contiguous memory block and returns it.\n    /// </summary>\n    /// <param name=\"count\">The number of characters to allocate.</param>\n    /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support\n    /// alloc/commit.</returns>\n    virtual _CharType* alloc(size_t count) { return get_base()->alloc(count); }\n\n    /// <summary>\n    /// Submits a block already allocated by the stream buffer.\n    /// </summary>\n    /// <param name=\"count\">The number of characters to be committed.</param>\n    virtual void commit(size_t count) { get_base()->commit(count); }\n\n    /// <summary>\n    /// Gets a pointer to the next already allocated contiguous block of data.\n    /// </summary>\n    /// <param name=\"ptr\">A reference to a pointer variable that will hold the address of the block on success.</param>\n    /// <param name=\"count\">The number of contiguous characters available at the address in 'ptr'.</param>\n    /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>\n    /// <remarks>\n    /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that\n    /// there is no block to return immediately or that the stream buffer does not support the operation.\n    /// The stream buffer may not de-allocate the block until <see cref=\"::release method\" /> is called.\n    /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;\n    /// a subsequent read will not succeed.\n    /// </remarks>\n    virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count)\n    {\n        ptr = nullptr;\n        count = 0;\n        return get_base()->acquire(ptr, count);\n    }\n\n    /// <summary>\n    /// Releases a block of data acquired using <see cref=\"::acquire method\"/>. This frees the stream buffer to\n    /// de-allocate the memory, if it so desires. Move the read position ahead by the count.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be released.</param>\n    /// <param name=\"count\">The number of characters that were read.</param>\n    virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) { get_base()->release(ptr, count); }\n\n    /// <summary>\n    /// Writes a number of characters to the stream.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be written.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    /// <returns>The number of characters actually written, either 'count' or 0.</returns>\n    CASABLANCA_DEPRECATED(\"This API in some cases performs a copy. It is deprecated and will be removed in a future \"\n                          \"release. Use putn_nocopy instead.\")\n    virtual pplx::task<size_t> putn(const _CharType* ptr, size_t count) { return get_base()->putn(ptr, count); }\n\n    /// <summary>\n    /// Writes a number of characters to the stream. Note: callers must make sure the data to be written is valid until\n    /// the returned task completes.\n    /// </summary>\n    /// <param name=\"ptr\">A pointer to the block of data to be written.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    /// <returns>The number of characters actually written, either 'count' or 0.</returns>\n    virtual pplx::task<size_t> putn_nocopy(const _CharType* ptr, size_t count)\n    {\n        return get_base()->putn_nocopy(ptr, count);\n    }\n\n    /// <summary>\n    /// Reads a single character from the stream and advances the read position.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails.</returns>\n    virtual pplx::task<int_type> bumpc() { return get_base()->bumpc(); }\n\n    /// <summary>\n    /// Reads a single character from the stream and advances the read position.\n    /// </summary>\n    /// <returns>The value of the character. <c>-1</c> if the read fails. <c>-2</c> if an asynchronous read is\n    /// required</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>\n    virtual typename details::basic_streambuf<_CharType>::int_type sbumpc() { return get_base()->sbumpc(); }\n\n    /// <summary>\n    /// Reads a single character from the stream without advancing the read position.\n    /// </summary>\n    /// <returns>The value of the byte. EOF if the read fails.</returns>\n    virtual pplx::task<int_type> getc() { return get_base()->getc(); }\n\n    /// <summary>\n    /// Reads a single character from the stream without advancing the read position.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails. <see cref=\"::requires_async method\" /> if an\n    /// asynchronous read is required</returns> <remarks>This is a synchronous operation, but is guaranteed to never\n    /// block.</remarks>\n    virtual typename details::basic_streambuf<_CharType>::int_type sgetc() { return get_base()->sgetc(); }\n\n    /// <summary>\n    /// Advances the read position, then returns the next character without advancing again.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails.</returns>\n    pplx::task<int_type> nextc() { return get_base()->nextc(); }\n\n    /// <summary>\n    /// Retreats the read position, then returns the current character without advancing.\n    /// </summary>\n    /// <returns>The value of the character. EOF if the read fails. <see cref=\"::requires_async method\" /> if an\n    /// asynchronous read is required</returns>\n    pplx::task<int_type> ungetc() { return get_base()->ungetc(); }\n\n    /// <summary>\n    /// Reads up to a given number of characters from the stream.\n    /// </summary>\n    /// <param name=\"ptr\">The address of the target memory area.</param>\n    /// <param name=\"count\">The maximum number of characters to read.</param>\n    /// <returns>The number of characters read. O if the end of the stream is reached.</returns>\n    virtual pplx::task<size_t> getn(_Out_writes_(count) _CharType* ptr, _In_ size_t count)\n    {\n        return get_base()->getn(ptr, count);\n    }\n\n    /// <summary>\n    /// Copies up to a given number of characters from the stream, synchronously.\n    /// </summary>\n    /// <param name=\"ptr\">The address of the target memory area.</param>\n    /// <param name=\"count\">The maximum number of characters to read.</param>\n    /// <returns>The number of characters copied. O if the end of the stream is reached or an asynchronous read is\n    /// required.</returns> <remarks>This is a synchronous operation, but is guaranteed to never block.</remarks>\n    virtual size_t scopy(_Out_writes_(count) _CharType* ptr, _In_ size_t count)\n    {\n        return get_base()->scopy(ptr, count);\n    }\n\n    /// <summary>\n    /// Gets the current read or write position in the stream.\n    /// </summary>\n    /// <param name=\"direction\">The I/O direction to seek (see remarks)</param>\n    /// <returns>The current position. EOF if the operation fails.</returns>\n    /// <remarks>Some streams may have separate write and read cursors.\n    ///          For such streams, the direction parameter defines whether to move the read or the write\n    ///          cursor.</remarks>\n    virtual typename details::basic_streambuf<_CharType>::pos_type getpos(std::ios_base::openmode direction) const\n    {\n        return get_base()->getpos(direction);\n    }\n\n    /// <summary>\n    /// Seeks to the given position.\n    /// </summary>\n    /// <param name=\"pos\">The offset from the beginning of the stream.</param>\n    /// <param name=\"direction\">The I/O direction to seek (see remarks).</param>\n    /// <returns>The position. EOF if the operation fails.</returns>\n    /// <remarks>Some streams may have separate write and read cursors. For such streams, the direction parameter\n    /// defines whether to move the read or the write cursor.</remarks>\n    virtual typename details::basic_streambuf<_CharType>::pos_type seekpos(\n        typename details::basic_streambuf<_CharType>::pos_type pos, std::ios_base::openmode direction)\n    {\n        return get_base()->seekpos(pos, direction);\n    }\n\n    /// <summary>\n    /// Seeks to a position given by a relative offset.\n    /// </summary>\n    /// <param name=\"offset\">The relative position to seek to</param>\n    /// <param name=\"way\">The starting point (beginning, end, current) for the seek.</param>\n    /// <param name=\"mode\">The I/O direction to seek (see remarks)</param>\n    /// <returns>The position. EOF if the operation fails.</returns>\n    /// <remarks>Some streams may have separate write and read cursors.\n    ///          For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>\n    virtual typename details::basic_streambuf<_CharType>::pos_type seekoff(\n        typename details::basic_streambuf<_CharType>::off_type offset,\n        std::ios_base::seekdir way,\n        std::ios_base::openmode mode)\n    {\n        return get_base()->seekoff(offset, way, mode);\n    }\n\n    /// <summary>\n    /// For output streams, flush any internally buffered data to the underlying medium.\n    /// </summary>\n    /// <returns><c>true</c> if the flush succeeds, <c>false</c> if not</returns>\n    virtual pplx::task<void> sync() { return get_base()->sync(); }\n\n    /// <summary>\n    /// Retrieves the stream buffer exception_ptr if it has been set.\n    /// </summary>\n    /// <returns>Pointer to the exception, if it has been set; otherwise, <c>nullptr</c> will be returned</returns>\n    virtual std::exception_ptr exception() const { return get_base()->exception(); }\n\nprivate:\n    std::shared_ptr<details::basic_streambuf<_CharType>> m_buffer;\n};\n\n} // namespace streams\n} // namespace Concurrency\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n#endif // !XSAPI_NO_PPL"
  },
  {
    "path": "Include/cpprestinclude/cpprest/asyncrt_utils.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Various common utilities.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <string>\n#include <vector>\n#include <cstdint>\n#include <system_error>\n#include <random>\n#include <locale.h>\n\n#include \"cpprest/details/basic_types.h\"\n\n#if !defined(_WIN32) || (_MSC_VER >= 1700)\n#include <chrono>\n#endif\n\n#ifndef _WIN32\n#include <sys/time.h>\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n\n/// Various utilities for string conversions and date and time manipulation.\nnamespace utility\n{\n\n// Left over from VS2010 support, remains to avoid breaking.\ntypedef std::chrono::seconds seconds;\n\n/// Functions for converting to/from std::chrono::seconds to xml string.\nnamespace timespan\n{\n    /// <summary>\n    /// Converts a timespan/interval in seconds to xml duration string as specified by\n    /// http://www.w3.org/TR/xmlschema-2/#duration\n    /// </summary>\n    _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs);\n\n    /// <summary>\n    /// Converts an xml duration to timespan/interval in seconds\n    /// http://www.w3.org/TR/xmlschema-2/#duration\n    /// </summary>\n    _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t &timespanString);\n}\n\n/// Functions for Unicode string conversions.\nnamespace conversions\n{\n    /// <summary>\n    /// Converts a UTF-16 string to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"w\">A two byte character UTF-16 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    _ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w);\n\n    /// <summary>\n    /// Converts a UTF-8 string to a UTF-16\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    _ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s);\n\n    /// <summary>\n    /// Converts a ASCII (us-ascii) string to a UTF-16 string.\n    /// </summary>\n    /// <param name=\"s\">A single byte character us-ascii string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    _ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string &s);\n\n    /// <summary>\n    /// Converts a Latin1 (iso-8859-1) string to a UTF-16 string.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    _ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string &s);\n\n    /// <summary>\n    /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    _ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string &s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A two byte character UTF-16 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A two byte character UTF-16 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s);\n\n    /// <summary>\n    /// Converts to a UTF-16 from string.\n    /// </summary>\n    /// <param name=\"value\">A single byte character UTF-8 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string &value);\n\n    /// <summary>\n    /// Converts to a UTF-16 from string.\n    /// </summary>\n    /// <param name=\"value\">A two byte character UTF-16 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    _ASYNCRTIMP utf16string __cdecl to_utf16string(utf16string value);\n\n    /// <summary>\n    /// Converts to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"value\">A single byte character UTF-8 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    _ASYNCRTIMP std::string __cdecl to_utf8string(std::string value);\n\n    /// <summary>\n    /// Converts to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"value\">A two byte character UTF-16 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    _ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string &value);\n\n    /// <summary>\n    /// Encode the given byte array into a base64 string\n    /// </summary>\n    _ASYNCRTIMP utility::string_t __cdecl to_base64(const unsigned char* data, size_t dataSize);\n\n    /// <summary>\n    /// Encode the given byte array into a base64 string\n    /// </summary>\n    _ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector<unsigned char>& data);\n\n    /// <summary>\n    /// Encode the given 8-byte integer into a base64 string\n    /// </summary>\n    _ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data);\n\n    /// <summary>\n    /// Decode the given base64 string to a byte array\n    /// </summary>\n    _ASYNCRTIMP std::vector<unsigned char> __cdecl from_base64(const utility::string_t& str);\n\n    template <typename Source>\n    utility::string_t print_string(const Source &val, const std::locale &loc)\n    {\n        utility::ostringstream_t oss;\n        oss.imbue(loc);\n        oss << val;\n        if (oss.bad())\n        {\n            throw std::bad_cast();\n        }\n        return oss.str();\n    }\n\n    template <typename Source>\n    utility::string_t print_string(const Source &val)\n    {\n        return print_string(val, std::locale());\n    }\n\n    inline utility::string_t print_string(const utility::string_t &val)\n    {\n        return val;\n    }\n\n    template <typename Target>\n    Target scan_string(const utility::string_t &str, const std::locale &loc)\n    {\n        Target t;\n        utility::istringstream_t iss(str);\n        iss.imbue(loc);\n        iss >> t;\n        if (iss.bad())\n        {\n            throw std::bad_cast();\n        }\n        return t;\n    }\n\n    template <typename Target>\n    Target scan_string(const utility::string_t &str)\n    {\n        return scan_string<Target>(str, std::locale());\n    }\n\n    inline utility::string_t scan_string(const utility::string_t &str)\n    {\n        return str;\n    }\n}\n\nnamespace details\n{\n    /// <summary>\n    /// Cross platform RAII container for setting thread local locale.\n    /// </summary>\n    class scoped_c_thread_locale\n    {\n    public:\n        _ASYNCRTIMP scoped_c_thread_locale();\n        _ASYNCRTIMP ~scoped_c_thread_locale();\n\n#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(PAVO) // CodePlex 269\n#ifdef _WIN32\n        typedef _locale_t xplat_locale;\n#else\n        typedef locale_t xplat_locale;\n#endif\n\n        static _ASYNCRTIMP xplat_locale __cdecl c_locale();\n#endif\n    private:\n#ifdef _WIN32\n        std::string m_prevLocale;\n        int m_prevThreadSetting;\n#elif !(defined(ANDROID) || defined(__ANDROID__) || defined(PAVO))\n        locale_t m_prevLocale;\n#endif\n        scoped_c_thread_locale(const scoped_c_thread_locale &);\n        scoped_c_thread_locale & operator=(const scoped_c_thread_locale &);\n    };\n\n    /// <summary>\n    /// Our own implementation of alpha numeric instead of std::isalnum to avoid\n    /// taking global lock for performance reasons.\n    /// </summary>\n    inline bool __cdecl is_alnum(char ch)\n    {\n        return (ch >= '0' && ch <= '9')\n            || (ch >= 'A' && ch <= 'Z')\n            || (ch >= 'a' && ch <= 'z');\n    }\n\n    /// <summary>\n    /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates\n    /// and therefore not be compatible with Dev10.\n    /// </summary>\n    template <typename _Type>\n    std::unique_ptr<_Type> make_unique() {\n        return std::unique_ptr<_Type>(new _Type());\n    }\n\n    template <typename _Type, typename _Arg1>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));\n    }\n\n    template <typename _Type, typename _Arg1, typename _Arg2>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2)));\n    }\n\n    template <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3)));\n    }\n\n    template <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4)));\n    }\n\n    /// <summary>\n    /// Cross platform utility function for performing case insensitive string comparision.\n    /// </summary>\n    /// <param name=\"left\">First string to compare.</param>\n    /// <param name=\"right\">Second strong to compare.</param>\n    /// <returns>true if the strings are equivalent, false otherwise</returns>\n    inline bool str_icmp(const utility::string_t &left, const utility::string_t &right)\n    {\n#ifdef _WIN32\n        return _wcsicmp(left.c_str(), right.c_str()) == 0;\n#else\n        return strcasecmp(left.c_str(), right.c_str());\n#endif\n    }\n\n#ifdef _WIN32\n\n/// <summary>\n/// Category error type for Windows OS errors.\n/// </summary>\nclass windows_category_impl : public std::error_category\n{\npublic:\n    virtual const char *name() const CPPREST_NOEXCEPT { return \"windows\"; }\n\n    _ASYNCRTIMP virtual std::string message(int errorCode) const CPPREST_NOEXCEPT;\n\n    _ASYNCRTIMP virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT;\n};\n\n/// <summary>\n/// Gets the one global instance of the windows error category.\n/// </summary>\n/// <returns>An error category instance.</returns>\n_ASYNCRTIMP const std::error_category & __cdecl windows_category();\n\n#else\n\n/// <summary>\n/// Gets the one global instance of the linux error category.\n/// </summary>\n/// </returns>An error category instance.</returns>\n_ASYNCRTIMP const std::error_category & __cdecl linux_category();\n\n#endif\n\n/// <summary>\n/// Gets the one global instance of the current platform's error category.\n/// </summary>\n_ASYNCRTIMP const std::error_category & __cdecl platform_category();\n\n/// <summary>\n/// Creates an instance of std::system_error from a OS error code.\n/// </summary>\ninline std::system_error __cdecl create_system_error(unsigned long errorCode)\n{\n    std::error_code code((int)errorCode, platform_category());\n    return std::system_error(code, code.message());\n}\n\n/// <summary>\n/// Creates a std::error_code from a OS error code.\n/// </summary>\ninline std::error_code __cdecl create_error_code(unsigned long errorCode)\n{\n    return std::error_code((int)errorCode, platform_category());\n}\n\n/// <summary>\n/// Creates the corresponding error message from a OS error code.\n/// </summary>\ninline utility::string_t __cdecl create_error_message(unsigned long errorCode)\n{\n    return utility::conversions::to_string_t(create_error_code(errorCode).message());\n}\n\n}\n\nclass datetime\n{\npublic:\n    typedef uint64_t interval_type;\n\n    /// <summary>\n    /// Defines the supported date and time string formats.\n    /// </summary>\n    enum date_format { RFC_1123, ISO_8601 };\n\n    /// <summary>\n    /// Returns the current UTC time.\n    /// </summary>\n    static _ASYNCRTIMP datetime __cdecl utc_now();\n\n    /// <summary>\n    /// An invalid UTC timestamp value.\n    /// </summary>\n    enum:interval_type { utc_timestamp_invalid = static_cast<interval_type>(-1) };\n\n    /// <summary>\n    /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.\n    /// If time is before epoch, utc_timestamp_invalid is returned.\n    /// </summary>\n    static interval_type utc_timestamp()\n    {\n        const auto seconds = utc_now().to_interval() / _secondTicks;\n        if (seconds >= 11644473600LL)\n        {\n            return seconds - 11644473600LL;\n        }\n        else\n        {\n            return utc_timestamp_invalid;\n        }\n    }\n\n    datetime() : m_interval(0)\n    {\n    }\n\n    /// <summary>\n    /// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.\n    /// </summary>\n    /// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>\n    static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);\n\n    /// <summary>\n    /// Returns a string representation of the <c>datetime</c>.\n    /// </summary>\n    _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const;\n\n    /// <summary>\n    /// Returns the integral time value.\n    /// </summary>\n    interval_type to_interval() const\n    {\n        return m_interval;\n    }\n\n    datetime operator- (interval_type value) const\n    {\n        return datetime(m_interval - value);\n    }\n\n    datetime operator+ (interval_type value) const\n    {\n        return datetime(m_interval + value);\n    }\n\n    bool operator== (datetime dt) const\n    {\n        return m_interval == dt.m_interval;\n    }\n\n    bool operator!= (const datetime& dt) const\n    {\n        return !(*this == dt);\n    }\n\n    static interval_type from_milliseconds(unsigned int milliseconds)\n    {\n        return milliseconds*_msTicks;\n    }\n\n    static interval_type from_seconds(unsigned int seconds)\n    {\n        return seconds*_secondTicks;\n    }\n\n    static interval_type from_minutes(unsigned int minutes)\n    {\n        return minutes*_minuteTicks;\n    }\n\n    static interval_type from_hours(unsigned int hours)\n    {\n        return hours*_hourTicks;\n    }\n\n    static interval_type from_days(unsigned int days)\n    {\n        return days*_dayTicks;\n    }\n\n    bool is_initialized() const\n    {\n        return m_interval != 0;\n    }\n\nprivate:\n\n    friend int operator- (datetime t1, datetime t2);\n\n    static const interval_type _msTicks = static_cast<interval_type>(10000);\n    static const interval_type _secondTicks = 1000*_msTicks;\n    static const interval_type _minuteTicks = 60*_secondTicks;\n    static const interval_type _hourTicks   = 60*60*_secondTicks;\n    static const interval_type _dayTicks    = 24*60*60*_secondTicks;\n\n\n#ifdef _WIN32\n    // void* to avoid pulling in windows.h\n    static _ASYNCRTIMP bool __cdecl system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt);\n#else\n    static datetime timeval_to_datetime(const timeval &time);\n#endif\n\n    // Private constructor. Use static methods to create an instance.\n    datetime(interval_type interval) : m_interval(interval)\n    {\n    }\n\n    // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.\n    interval_type m_interval;\n};\n\n#ifndef _WIN32\n\n// temporary workaround for the fact that\n// utf16char is not fully supported in GCC\nclass cmp\n{\npublic:\n\n    static int icmp(std::string left, std::string right)\n    {\n        size_t i;\n        for (i = 0; i < left.size(); ++i)\n        {\n            if (i == right.size()) return 1;\n\n            auto l = cmp::tolower(left[i]);\n            auto r = cmp::tolower(right[i]);\n            if (l > r) return 1;\n            if (l < r) return -1;\n        }\n        if (i < right.size()) return -1;\n        return 0;\n    }\n\nprivate:\n    static char tolower(char c)\n    {\n        if (c >= 'A' && c <= 'Z')\n            return static_cast<char>(c - 'A' + 'a');\n        return c;\n    }\n};\n\n#endif\n\ninline int operator- (datetime t1, datetime t2)\n{\n    auto diff = (t1.m_interval - t2.m_interval);\n\n    // Round it down to seconds\n    diff /= 10 * 1000 * 1000;\n\n    return static_cast<int>(diff);\n}\n\n/// <summary>\n/// Nonce string generator class.\n/// </summary>\nclass nonce_generator\n{\npublic:\n\n    /// <summary>\n    /// Define default nonce length.\n    /// </summary>\n    enum { default_length = 32 };\n\n    /// <summary>\n    /// Nonce generator constructor.\n    /// </summary>\n    /// <param name=\"length\">Length of the generated nonce string.</param>\n    nonce_generator(int length=default_length) :\n        m_random(static_cast<unsigned int>(utility::datetime::utc_timestamp())),\n        m_length(length)\n    {}\n\n    /// <summary>\n    /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).\n    /// Length of the generated string is set by length().\n    /// </summary>\n    /// <returns>The generated nonce string.</returns>\n    _ASYNCRTIMP utility::string_t generate();\n\n    /// <summary>\n    /// Get length of generated nonce string.\n    /// </summary>\n    /// <returns>Nonce string length.</returns>\n    int length() const { return m_length; }\n\n    /// <summary>\n    /// Set length of the generated nonce string.\n    /// </summary>\n    /// <param name=\"length\">Lenght of nonce string.</param>\n    void set_length(int length) { m_length = length; }\n\nprivate:\n    static const utility::char_t* c_allowed_chars;\n    std::mt19937 m_random;\n    int m_length;\n};\n\n} // namespace utility;\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/base_uri.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Protocol independent support for URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n#include <vector>\n#include <functional>\n\n#include \"cpprest/asyncrt_utils.h\"\n#include \"cpprest/details/basic_types.h\"\n\nnamespace web {\n\n    namespace details\n    {\n        struct uri_components\n        {\n            uri_components() : m_path(_XPLATSTR(\"/\")), m_port(-1)\n            {}\n\n            uri_components(const uri_components &other) :\n                m_scheme(other.m_scheme),\n                m_host(other.m_host),\n                m_user_info(other.m_user_info),\n                m_path(other.m_path),\n                m_query(other.m_query),\n                m_fragment(other.m_fragment),\n                m_port(other.m_port)\n            {}\n\n            uri_components & operator=(const uri_components &other)\n            {\n                if (this != &other)\n                {\n                    m_scheme = other.m_scheme;\n                    m_host = other.m_host;\n                    m_user_info = other.m_user_info;\n                    m_path = other.m_path;\n                    m_query = other.m_query;\n                    m_fragment = other.m_fragment;\n                    m_port = other.m_port;\n                }\n                return *this;\n            }\n\n            uri_components(uri_components &&other) CPPREST_NOEXCEPT :\n                m_scheme(std::move(other.m_scheme)),\n                m_host(std::move(other.m_host)),\n                m_user_info(std::move(other.m_user_info)),\n                m_path(std::move(other.m_path)),\n                m_query(std::move(other.m_query)),\n                m_fragment(std::move(other.m_fragment)),\n                m_port(other.m_port)\n            {}\n\n            uri_components & operator=(uri_components &&other) CPPREST_NOEXCEPT\n            {\n                if (this != &other)\n                {\n                    m_scheme = std::move(other.m_scheme);\n                    m_host = std::move(other.m_host);\n                    m_user_info = std::move(other.m_user_info);\n                    m_path = std::move(other.m_path);\n                    m_query = std::move(other.m_query);\n                    m_fragment = std::move(other.m_fragment);\n                    m_port = other.m_port;\n                }\n                return *this;\n            }\n\n            _ASYNCRTIMP utility::string_t join();\n\n            utility::string_t m_scheme;\n            utility::string_t m_host;\n            utility::string_t m_user_info;\n            utility::string_t m_path;\n            utility::string_t m_query;\n            utility::string_t m_fragment;\n            int m_port;\n        };\n    }\n\n    /// <summary>\n    /// A single exception type to represent errors in parsing, encoding, and decoding URIs.\n    /// </summary>\n    class uri_exception : public std::exception\n    {\n    public:\n\n        uri_exception(std::string msg) : m_msg(std::move(msg)) {}\n\n        ~uri_exception() CPPREST_NOEXCEPT {}\n\n        const char* what() const CPPREST_NOEXCEPT\n        {\n            return m_msg.c_str();\n        }\n\n    private:\n        std::string m_msg;\n    };\n\n    /// <summary>\n    /// A flexible, protocol independent URI implementation.\n    ///\n    /// URI instances are immutable. Querying the various fields on an emtpy URI will return empty strings. Querying\n    /// various diagnostic members on an empty URI will return false.\n    /// </summary>\n    /// <remarks>\n    /// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references\n    /// ('/path?query#frag').\n    ///\n    /// This implementation does not provide any scheme-specific handling -- an example of this\n    /// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid\n    /// http-uri -- that is, it's syntactically correct but does not conform to the requirements\n    /// of the http scheme (http requires a host).\n    /// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide\n    /// extra capability for validating and canonicalizing a URI according to scheme, and would\n    /// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics.\n    ///\n    /// One issue with implementing a scheme-independent URI facility is that of comparing for equality.\n    /// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is --\n    /// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme\n    /// to it's default port, we don't have a way to know these are equal. This is just one of a class of\n    /// issues with regard to scheme-specific behavior.\n    /// </remarks>\n    class uri\n    {\n    public:\n\n        /// <summary>\n        /// The various components of a URI. This enum is used to indicate which\n        /// URI component is being encoded to the encode_uri_component. This allows\n        /// specific encoding to be performed.\n        ///\n        /// Scheme and port don't allow '%' so they don't need to be encoded.\n        /// </summary>\n        class components\n        {\n        public:\n            enum component\n            {\n                user_info,\n                host,\n                path,\n                query,\n                fragment,\n                full_uri\n            };\n        };\n\n        /// <summary>\n        /// Encodes a URI component according to RFC 3986.\n        /// Note if a full URI is specified instead of an individual URI component all\n        /// characters not in the unreserved set are escaped.\n        /// </summary>\n        /// <param name=\"raw\">The URI as a string.</param>\n        /// <returns>The encoded string.</returns>\n        _ASYNCRTIMP static utility::string_t __cdecl encode_uri(const utility::string_t &raw, uri::components::component = components::full_uri);\n\n        /// <summary>\n        /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their\n        /// hexadecimal representation.\n        /// </summary>\n        /// <param name=\"utf8data\">The UTF-8 string data.</param>\n        /// <returns>The encoded string.</returns>\n        _ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t &utf8data);\n\n        /// <summary>\n        /// Decodes an encoded string.\n        /// </summary>\n        /// <param name=\"encoded\">The URI as a string.</param>\n        /// <returns>The decoded string.</returns>\n        _ASYNCRTIMP static utility::string_t __cdecl decode(const utility::string_t &encoded);\n\n        /// <summary>\n        /// Splits a path into its hierarchical components.\n        /// </summary>\n        /// <param name=\"path\">The path as a string</param>\n        /// <returns>A <c>std::vector&lt;utility::string_t&gt;</c> containing the segments in the path.</returns>\n        _ASYNCRTIMP static std::vector<utility::string_t> __cdecl split_path(const utility::string_t &path);\n\n        /// <summary>\n        /// Splits a query into its key-value components.\n        /// </summary>\n        /// <param name=\"query\">The query string</param>\n        /// <returns>A <c>std::map&lt;utility::string_t, utility::string_t&gt;</c> containing the key-value components of the query.</returns>\n        _ASYNCRTIMP static std::map<utility::string_t, utility::string_t> __cdecl split_query(const utility::string_t &query);\n\n        /// <summary>\n        /// Validates a string as a URI.\n        /// </summary>\n        /// <param name=\"uri_string\">The URI string to be validated.</param>\n        /// <returns><c>true</c> if the given string represents a valid URI, <c>false</c> otherwise.</returns>\n        _ASYNCRTIMP static bool __cdecl validate(const utility::string_t &uri_string);\n\n        /// <summary>\n        /// Creates an empty uri\n        /// </summary>\n        uri() { m_uri = _XPLATSTR(\"/\");};\n\n        /// <summary>\n        /// Creates a URI from the given URI components.\n        /// </summary>\n        /// <param name=\"components\">A URI components object to create the URI instance.</param>\n        _ASYNCRTIMP uri(const details::uri_components &components);\n\n        /// <summary>\n        /// Creates a URI from the given encoded string. This will throw an exception if the string\n        /// does not contain a valid URI. Use uri::validate if processing user-input.\n        /// </summary>\n        /// <param name=\"uri_string\">A pointer to an encoded string to create the URI instance.</param>\n        _ASYNCRTIMP uri(const utility::char_t *uri_string);\n\n        /// <summary>\n        /// Creates a URI from the given encoded string. This will throw an exception if the string\n        /// does not contain a valid URI. Use uri::validate if processing user-input.\n        /// </summary>\n        /// <param name=\"uri_string\">An encoded URI string to create the URI instance.</param>\n        _ASYNCRTIMP uri(const utility::string_t &uri_string);\n\n        /// <summary>\n        /// Copy constructor.\n        /// </summary>\n        uri(const uri &other) :\n            m_uri(other.m_uri),\n            m_components(other.m_components)\n        {}\n\n        /// <summary>\n        /// Copy assignment operator.\n        /// </summary>\n        uri & operator=(const uri &other)\n        {\n            if (this != &other)\n            {\n                m_uri = other.m_uri;\n                m_components = other.m_components;\n            }\n            return *this;\n        }\n\n        /// <summary>\n        /// Move constructor.\n        /// </summary>\n        uri(uri &&other) CPPREST_NOEXCEPT :\n            m_uri(std::move(other.m_uri)),\n            m_components(std::move(other.m_components))\n        {}\n\n        /// <summary>\n        /// Move assignment operator\n        /// </summary>\n        uri & operator=(uri &&other) CPPREST_NOEXCEPT\n        {\n            if (this != &other)\n            {\n                m_uri = std::move(other.m_uri);\n                m_components = std::move(other.m_components);\n            }\n            return *this;\n        }\n\n        /// <summary>\n        /// Get the scheme component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI scheme as a string.</returns>\n        const utility::string_t &scheme() const { return m_components.m_scheme; }\n\n        /// <summary>\n        /// Get the user information component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI user information as a string.</returns>\n        const utility::string_t &user_info() const { return m_components.m_user_info; }\n\n        /// <summary>\n        /// Get the host component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI host as a string.</returns>\n        const utility::string_t &host() const { return m_components.m_host; }\n\n        /// <summary>\n        /// Get the port component of the URI. Returns -1 if no port is specified.\n        /// </summary>\n        /// <returns>The URI port as an integer.</returns>\n        int port() const { return m_components.m_port; }\n\n        /// <summary>\n        /// Get the path component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI path as a string.</returns>\n        const utility::string_t &path() const { return m_components.m_path; }\n\n        /// <summary>\n        /// Get the query component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI query as a string.</returns>\n        const utility::string_t &query() const { return m_components.m_query; }\n\n        /// <summary>\n        /// Get the fragment component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI fragment as a string.</returns>\n        const utility::string_t &fragment() const { return m_components.m_fragment; }\n\n        /// <summary>\n        /// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions.\n        /// </summary>\n        /// <returns>The new uri object with the same authority.</returns>\n        _ASYNCRTIMP uri authority() const;\n\n        /// <summary>\n        /// Gets the path, query, and fragment portion of this uri, which may be empty.\n        /// </summary>\n        /// <returns>The new URI object with the path, query and fragment portion of this URI.</returns>\n        _ASYNCRTIMP uri resource() const;\n\n        /// <summary>\n        /// An empty URI specifies no components, and serves as a default value\n        /// </summary>\n        bool is_empty() const\n        {\n            return this->m_uri.empty() || this->m_uri == _XPLATSTR(\"/\");\n        }\n\n        /// <summary>\n        /// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine.\n        /// </summary>\n        /// <remarks>\n        /// Examples include \"locahost\", or ip addresses in the loopback range (127.0.0.0/24).\n        /// </remarks>\n        /// <returns><c>true</c> if this URI references the local host, <c>false</c> otherwise.</returns>\n        bool is_host_loopback() const\n        {\n            return !is_empty() && ((host() == _XPLATSTR(\"localhost\")) || (host().size() > 4 && host().substr(0,4) == _XPLATSTR(\"127.\")));\n        }\n\n        /// <summary>\n        /// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +)\n        /// </summary>\n        /// <example>\n        /// http://*:80\n        /// </example>\n        bool is_host_wildcard() const\n        {\n            return !is_empty() && (this->host() == _XPLATSTR(\"*\") || this->host() == _XPLATSTR(\"+\"));\n        }\n\n        /// <summary>\n        /// A portable URI is one with a hostname that can be resolved globally (used from another machine).\n        /// </summary>\n        /// <returns><c>true</c> if this URI can be resolved globally (used from another machine), <c>false</c> otherwise.</returns>\n        /// <remarks>\n        /// The hostname \"localhost\" is a reserved name that is guaranteed to resolve to the local machine,\n        /// and cannot be used for inter-machine communication. Likewise the hostnames \"*\" and \"+\" on Windows\n        /// represent wildcards, and do not map to a resolvable address.\n        /// </remarks>\n        bool is_host_portable() const\n        {\n            return !(is_empty() || is_host_loopback() || is_host_wildcard());\n        }\n\n        /// <summary>\n        /// A default port is one where the port is unspecified, and will be determined by the operating system.\n        /// The choice of default port may be dictated by the scheme (http -> 80) or not.\n        /// </summary>\n        /// <returns><c>true</c> if this URI instance has a default port, <c>false</c> otherwise.</returns>\n        bool is_port_default() const\n        {\n            return !is_empty() && this->port() == 0;\n        }\n\n        /// <summary>\n        /// An \"authority\" URI is one with only a scheme, optional userinfo, hostname, and (optional) port.\n        /// </summary>\n        /// <returns><c>true</c> if this is an \"authority\" URI, <c>false</c> otherwise.</returns>\n        bool is_authority() const\n        {\n            return !is_empty() && is_path_empty() && query().empty() && fragment().empty();\n        }\n\n        /// <summary>\n        /// Returns whether the other URI has the same authority as this one\n        /// </summary>\n        /// <param name=\"other\">The URI to compare the authority with.</param>\n        /// <returns><c>true</c> if both the URI's have the same authority, <c>false</c> otherwise.</returns>\n        bool has_same_authority(const uri &other) const\n        {\n            return !is_empty() && this->authority() == other.authority();\n        }\n\n        /// <summary>\n        /// Returns whether the path portion of this URI is empty\n        /// </summary>\n        /// <returns><c>true</c> if the path portion of this URI is empty, <c>false</c> otherwise.</returns>\n        bool is_path_empty() const\n        {\n            return path().empty() || path() == _XPLATSTR(\"/\");\n        }\n\n        /// <summary>\n        /// Returns the full (encoded) URI as a string.\n        /// </summary>\n         /// <returns>The full encoded URI string.</returns>\n        utility::string_t to_string() const\n        {\n            return m_uri;\n        }\n\n        _ASYNCRTIMP bool operator == (const uri &other) const;\n\n        bool operator < (const uri &other) const\n        {\n            return m_uri < other.m_uri;\n        }\n\n        bool operator != (const uri &other) const\n        {\n            return !(this->operator == (other));\n        }\n\n    private:\n        friend class uri_builder;\n\n        // Encodes all characters not in given set determined by given function.\n        _ASYNCRTIMP static utility::string_t __cdecl encode_impl(const utility::string_t &raw, const std::function<bool __cdecl(int)>& should_encode);\n\n        utility::string_t m_uri;\n        details::uri_components m_components;\n    };\n\n} // namespace web\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/containerstream.h",
    "content": "#if !XSAPI_NO_PPL\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* This file defines a basic STL-container-based stream buffer. Reading from the buffer will not remove any data\n* from it and seeking is thus supported.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#include <vector>\n#include <queue>\n#include <algorithm>\n#include <iterator>\n\n#include \"pplx/pplxtasks.h\"\n#include \"cpprest/astreambuf.h\"\n#include \"cpprest/streams.h\"\n\nnamespace Concurrency { namespace streams {\n\n    // Forward declarations\n\n    template<typename _CollectionType> class container_buffer;\n\n    namespace details {\n\n    /// <summary>\n    /// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading\n    /// sequences of characters.\n    /// The class itself should not be used in application code, it is used by the stream definitions farther down in the header file.\n    /// </summary>\n    /// <remarks> When closed, neither writing nor reading is supported any longer. <c>basic_container_buffer</c> does not support simultaneous use of the buffer\n    /// for reading and writing.</remarks>\n    template<typename _CollectionType>\n    class basic_container_buffer : public streams::details::streambuf_state_manager<typename _CollectionType::value_type>\n    {\n    public:\n        typedef typename _CollectionType::value_type _CharType;\n        typedef typename basic_streambuf<_CharType>::traits traits;\n        typedef typename basic_streambuf<_CharType>::int_type int_type;\n        typedef typename basic_streambuf<_CharType>::pos_type pos_type;\n        typedef typename basic_streambuf<_CharType>::off_type off_type;\n\n        /// <summary>\n        /// Returns the underlying data container\n        /// </summary>\n        _CollectionType& collection()\n        {\n            return m_data;\n        }\n\n        /// <summary>\n        /// Destructor\n        /// </summary>\n        virtual ~basic_container_buffer()\n        {\n            // Invoke the synchronous versions since we need to\n            // purge the request queue before deleting the buffer\n            this->_close_read();\n            this->_close_write();\n        }\n\n\n    protected:\n        /// <summary>\n        /// can_seek is used to determine whether a stream buffer supports seeking.\n        /// </summary>\n        virtual bool can_seek() const { return this->is_open(); }\n\n        /// <summary>\n        /// <c>has_size<c/> is used to determine whether a stream buffer supports size().\n        /// </summary>\n        virtual bool has_size() const { return this->is_open(); }\n\n        /// <summary>\n        /// Gets the size of the stream, if known. Calls to <c>has_size</c> will determine whether\n        /// the result of <c>size</c> can be relied on.\n        /// </summary>\n        virtual utility::size64_t size() const\n        {\n            return utility::size64_t(m_data.size());\n        }\n\n        /// <summary>\n        /// Get the stream buffer size, if one has been set.\n        /// </summary>\n        /// <param name=\"direction\">The direction of buffering (in or out)</param>\n        /// <remarks>An implementation that does not support buffering will always return '0'.</remarks>\n        virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const\n        {\n            return 0;\n        }\n\n        /// <summary>\n        /// Sets the stream buffer implementation to buffer or not buffer.\n        /// </summary>\n        /// <param name=\"size\">The size to use for internal buffering, 0 if no buffering should be done.</param>\n        /// <param name=\"direction\">The direction of buffering (in or out)</param>\n        /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to <see cref=\"::buffer_size method\" />.</remarks>\n        virtual void set_buffer_size(size_t , std::ios_base::openmode = std::ios_base::in)\n        {\n            return;\n        }\n\n        /// <summary>\n        /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available\n        /// to be consumed without blocking. May be used in conjunction with <cref=\"::sbumpc method\"/> to read data without\n        /// incurring the overhead of using tasks.\n        /// </summary>\n        virtual size_t in_avail() const\n        {\n            // See the comment in seek around the restriction that we do not allow read head to\n            // seek beyond the current write_end.\n            _ASSERTE(m_current_position <= m_data.size());\n\n            msl::safeint3::SafeInt<size_t> readhead(m_current_position);\n            msl::safeint3::SafeInt<size_t> writeend(m_data.size());\n            return (size_t)(writeend - readhead);\n        }\n\n        virtual pplx::task<bool> _sync()\n        {\n            return pplx::task_from_result(true);\n        }\n\n        virtual pplx::task<int_type> _putc(_CharType ch)\n        {\n            int_type retVal = (this->write(&ch, 1) == 1) ? static_cast<int_type>(ch) : traits::eof();\n            return pplx::task_from_result<int_type>(retVal);\n        }\n\n        virtual pplx::task<size_t> _putn(const _CharType *ptr, size_t count)\n        {\n            return pplx::task_from_result<size_t>(this->write(ptr, count));\n        }\n\n        /// <summary>\n        /// Allocates a contiguous memory block and returns it.\n        /// </summary>\n        /// <param name=\"count\">The number of characters to allocate.</param>\n        /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit.</returns>\n        _CharType* _alloc(size_t count)\n        {\n            if (!this->can_write()) return nullptr;\n\n            // Allocate space\n            resize_for_write(m_current_position+count);\n\n            // Let the caller copy the data\n            return (_CharType*)&m_data[m_current_position];\n        }\n\n        /// <summary>\n        /// Submits a block already allocated by the stream buffer.\n        /// </summary>\n        /// <param name=\"count\">The number of characters to be committed.</param>\n        void _commit(size_t actual )\n        {\n            // Update the write position and satisfy any pending reads\n            update_current_position(m_current_position+actual);\n        }\n\n        /// <summary>\n        /// Gets a pointer to the next already allocated contiguous block of data.\n        /// </summary>\n        /// <param name=\"ptr\">A reference to a pointer variable that will hold the address of the block on success.</param>\n        /// <param name=\"count\">The number of contiguous characters available at the address in 'ptr.'</param>\n        /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>\n        /// <remarks>\n        /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that\n        /// there is no block to return immediately or that the stream buffer does not support the operation.\n        /// The stream buffer may not de-allocate the block until <see cref=\"::release method\" /> is called.\n        /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;\n        /// a subsequent read will not succeed.\n        /// </remarks>\n        virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count)\n        {\n            ptr = nullptr;\n            count = 0;\n\n            if (!this->can_read()) return false;\n\n            count = in_avail();\n\n            if (count > 0)\n            {\n                ptr = (_CharType*)&m_data[m_current_position];\n                return true;\n            }\n            else\n            {\n                // Can only be open for read OR write, not both. If there is no data then\n                // we have reached the end of the stream so indicate such with true.\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Releases a block of data acquired using <see cref=\"::acquire method\"/>. This frees the stream buffer to de-allocate the\n        /// memory, if it so desires. Move the read position ahead by the count.\n        /// </summary>\n        /// <param name=\"ptr\">A pointer to the block of data to be released.</param>\n        /// <param name=\"count\">The number of characters that were read.</param>\n        virtual void release(_Out_writes_opt_ (count) _CharType *ptr, _In_ size_t count)\n        {\n            if (ptr != nullptr)\n                update_current_position(m_current_position + count);\n        }\n\n        virtual pplx::task<size_t> _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)\n        {\n            return pplx::task_from_result(this->read(ptr, count));\n        }\n\n        size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)\n        {\n            return this->read(ptr, count);\n        }\n\n        virtual size_t _scopy(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)\n        {\n            return this->read(ptr, count, false);\n        }\n\n        virtual pplx::task<int_type> _bumpc()\n        {\n            return pplx::task_from_result(this->read_byte(true));\n        }\n\n        virtual int_type _sbumpc()\n        {\n            return this->read_byte(true);\n        }\n\n        virtual pplx::task<int_type> _getc()\n        {\n            return pplx::task_from_result(this->read_byte(false));\n        }\n\n        int_type _sgetc()\n        {\n            return this->read_byte(false);\n        }\n\n        virtual pplx::task<int_type> _nextc()\n        {\n            this->read_byte(true);\n            return pplx::task_from_result(this->read_byte(false));\n        }\n\n        virtual pplx::task<int_type> _ungetc()\n        {\n            auto pos = seekoff(-1, std::ios_base::cur, std::ios_base::in);\n            if ( pos == (pos_type)traits::eof())\n                return pplx::task_from_result(traits::eof());\n            return this->getc();\n        }\n\n        /// <summary>\n        /// Gets the current read or write position in the stream.\n        /// </summary>\n        /// <param name=\"direction\">The I/O direction to seek (see remarks)</param>\n        /// <returns>The current position. EOF if the operation fails.</returns>\n        /// <remarks>Some streams may have separate write and read cursors.\n        ///          For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>\n        virtual pos_type getpos(std::ios_base::openmode mode) const\n        {\n            if ( ((mode & std::ios_base::in) && !this->can_read()) ||\n                 ((mode & std::ios_base::out) && !this->can_write()))\n                 return static_cast<pos_type>(traits::eof());\n\n            return static_cast<pos_type>(m_current_position);\n        }\n\n        /// <summary>\n        /// Seeks to the given position.\n        /// </summary>\n        /// <param name=\"pos\">The offset from the beginning of the stream.</param>\n        /// <param name=\"direction\">The I/O direction to seek (see remarks).</param>\n        /// <returns>The position. EOF if the operation fails.</returns>\n        /// <remarks>Some streams may have separate write and read cursors. For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>\n        virtual pos_type seekpos(pos_type position, std::ios_base::openmode mode)\n        {\n            pos_type beg(0);\n\n            // In order to support relative seeking from the end position we need to fix an end position.\n            // Technically, there is no end for the stream buffer as new writes would just expand the buffer.\n            // For now, we assume that the current write_end is the end of the buffer. We use this artificial\n            // end to restrict the read head from seeking beyond what is available.\n\n            pos_type end(m_data.size());\n\n            if (position >= beg)\n            {\n                auto pos = static_cast<size_t>(position);\n\n                // Read head\n                if ((mode & std::ios_base::in) && this->can_read())\n                {\n                    if (position <= end)\n                    {\n                        // We do not allow reads to seek beyond the end or before the start position.\n                        update_current_position(pos);\n                        return static_cast<pos_type>(m_current_position);\n                    }\n                }\n\n                // Write head\n                if ((mode & std::ios_base::out) && this->can_write())\n                {\n                    // Allocate space\n                    resize_for_write(pos);\n\n                    // Nothing to really copy\n\n                    // Update write head and satisfy read requests if any\n                    update_current_position(pos);\n\n                    return static_cast<pos_type>(m_current_position);\n                }\n            }\n\n            return static_cast<pos_type>(traits::eof());\n        }\n\n        /// <summary>\n        /// Seeks to a position given by a relative offset.\n        /// </summary>\n        /// <param name=\"offset\">The relative position to seek to</param>\n        /// <param name=\"way\">The starting point (beginning, end, current) for the seek.</param>\n        /// <param name=\"mode\">The I/O direction to seek (see remarks)</param>\n        /// <returns>The position. EOF if the operation fails.</returns>\n        /// <remarks>Some streams may have separate write and read cursors.\n        ///          For such streams, the mode parameter defines whether to move the read or the write cursor.</remarks>\n        virtual pos_type seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode)\n        {\n            pos_type beg = 0;\n            pos_type cur = static_cast<pos_type>(m_current_position);\n            pos_type end = static_cast<pos_type>(m_data.size());\n\n            switch ( way )\n            {\n            case std::ios_base::beg:\n                return seekpos(beg + offset, mode);\n\n            case std::ios_base::cur:\n                return seekpos(cur + offset, mode);\n\n            case std::ios_base::end:\n                return seekpos(end + offset, mode);\n\n            default:\n                return static_cast<pos_type>(traits::eof());\n            }\n        }\n\n    private:\n        template<typename _CollectionType1> friend class streams::container_buffer;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        basic_container_buffer(std::ios_base::openmode mode)\n            : streambuf_state_manager<typename _CollectionType::value_type>(mode),\n              m_current_position(0)\n        {\n            validate_mode(mode);\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        basic_container_buffer(_CollectionType data, std::ios_base::openmode mode)\n            : streambuf_state_manager<typename _CollectionType::value_type>(mode),\n              m_data(std::move(data)),\n              m_current_position((mode & std::ios_base::in) ? 0 : m_data.size())\n        {\n            validate_mode(mode);\n        }\n\n        static void validate_mode(std::ios_base::openmode mode)\n        {\n            // Disallow simultaneous use of the stream buffer for writing and reading.\n            if ((mode & std::ios_base::in) && (mode & std::ios_base::out))\n                throw std::invalid_argument(\"this combination of modes on container stream not supported\");\n        }\n\n        /// <summary>\n        /// Determine if the request can be satisfied.\n        /// </summary>\n        bool can_satisfy(size_t)\n        {\n            // We can always satisfy a read, at least partially, unless the\n            // read position is at the very end of the buffer.\n            return (in_avail() > 0);\n        }\n\n        /// <summary>\n        /// Reads a byte from the stream and returns it as int_type.\n        /// Note: This routine shall only be called if can_satisfy() returned true.\n        /// </summary>\n        int_type read_byte(bool advance = true)\n        {\n            _CharType value;\n            auto read_size = this->read(&value, 1, advance);\n            return read_size == 1 ? static_cast<int_type>(value) : traits::eof();\n        }\n\n        /// <summary>\n        /// Reads up to count characters into ptr and returns the count of characters copied.\n        /// The return value (actual characters copied) could be <= count.\n        /// Note: This routine shall only be called if can_satisfy() returned true.\n        /// </summary>\n        size_t read(_Out_writes_ (count) _CharType *ptr, _In_ size_t count, bool advance = true)\n        {\n            if (!can_satisfy(count))\n                return 0;\n\n            msl::safeint3::SafeInt<size_t> request_size(count);\n            msl::safeint3::SafeInt<size_t> read_size = request_size.Min(in_avail());\n\n            size_t newPos = m_current_position + read_size;\n\n            auto readBegin = std::begin(m_data) + m_current_position;\n            auto readEnd = std::begin(m_data) + newPos;\n\n#ifdef _WIN32\n            // Avoid warning C4996: Use checked iterators under SECURE_SCL\n            std::copy(readBegin, readEnd, stdext::checked_array_iterator<_CharType *>(ptr, count));\n#else\n            std::copy(readBegin, readEnd, ptr);\n#endif // _WIN32\n\n            if (advance)\n            {\n                update_current_position(newPos);\n            }\n\n            return (size_t) read_size;\n        }\n\n        /// <summary>\n        /// Write count characters from the ptr into the stream buffer\n        /// </summary>\n        size_t write(const _CharType *ptr, size_t count)\n        {\n            if (!this->can_write() || (count == 0)) return 0;\n\n            auto newSize = m_current_position + count;\n\n            // Allocate space\n            resize_for_write(newSize);\n\n            // Copy the data\n            std::copy(ptr, ptr + count, std::begin(m_data) + m_current_position);\n\n            // Update write head and satisfy pending reads if any\n            update_current_position(newSize);\n\n            return count;\n        }\n\n        /// <summary>\n        /// Resize the underlying container to match the new write head\n        /// </summary>\n        void resize_for_write(size_t newPos)\n        {\n            // Resize the container if required\n            if (newPos > m_data.size())\n            {\n                m_data.resize(newPos);\n            }\n        }\n\n        /// <summary>\n        /// Updates the write head to the new position\n        /// </summary>\n        void update_current_position(size_t newPos)\n        {\n            // The new write head\n            m_current_position = newPos;\n            _ASSERTE(m_current_position <= m_data.size());\n        }\n\n        // The actual data store\n        _CollectionType m_data;\n\n        // Read/write head\n        size_t m_current_position;\n    };\n\n    } // namespace details\n\n    /// <summary>\n    /// The basic_container_buffer class serves as a memory-based steam buffer that supports writing or reading\n    /// sequences of characters. Note that it cannot be used as a consumer producer buffer.\n    /// </summary>\n    /// <typeparam name=\"_CollectionType\">\n    /// The type of the container.\n    /// </typeparam>\n    /// <remarks>\n    /// This is a reference-counted version of <c>basic_container_buffer</c>.\n    /// </remarks>\n    template<typename _CollectionType>\n    class container_buffer : public streambuf<typename _CollectionType::value_type>\n    {\n    public:\n        typedef typename _CollectionType::value_type char_type;\n\n        /// <summary>\n        /// Creates a container_buffer given a collection, copying its data into the buffer.\n        /// </summary>\n        /// <param name=\"data\">The collection that is the starting point for the buffer</param>\n        /// <param name=\"mode\">The I/O mode that the buffer should use (in / out)</param>\n        container_buffer(_CollectionType data, std::ios_base::openmode mode = std::ios_base::in)\n            : streambuf<typename _CollectionType::value_type>(\n                std::shared_ptr<details::basic_container_buffer<_CollectionType>>(new streams::details::basic_container_buffer<_CollectionType>(std::move(data), mode)))\n        {\n        }\n\n        /// <summary>\n        /// Creates a container_buffer starting from an empty collection.\n        /// </summary>\n        /// <param name=\"mode\">The I/O mode that the buffer should use (in / out)</param>\n        container_buffer(std::ios_base::openmode mode = std::ios_base::out)\n            : streambuf<typename _CollectionType::value_type>(\n                std::shared_ptr<details::basic_container_buffer<_CollectionType>>(new details::basic_container_buffer<_CollectionType>(mode)))\n        {\n        }\n\n        _CollectionType& collection() const\n        {\n            auto listBuf = static_cast<details::basic_container_buffer<_CollectionType> *>(this->get_base().get());\n            return listBuf->collection();\n        }\n    };\n\n    /// <summary>\n    /// A static class to allow users to create input and out streams based off STL\n    /// collections. The sole purpose of this class to avoid users from having to know\n    /// anything about stream buffers.\n    /// </summary>\n    /// <typeparam name=\"_CollectionType\">The type of the STL collection.</typeparam>\n    template<typename _CollectionType>\n    class container_stream\n    {\n    public:\n\n        typedef typename _CollectionType::value_type char_type;\n        typedef container_buffer<_CollectionType> buffer_type;\n\n        /// <summary>\n        /// Creates an input stream given an STL container.\n        /// </summary>\n        /// </param name=\"data\">STL container to back the input stream.</param>\n        /// <returns>An input stream.</returns>\n        static concurrency::streams::basic_istream<char_type> open_istream(_CollectionType data)\n        {\n            return concurrency::streams::basic_istream<char_type>(buffer_type(std::move(data), std::ios_base::in));\n        }\n\n        /// <summary>\n        /// Creates an output stream using an STL container as the storage.\n        /// </summary>\n        /// <returns>An output stream.</returns>\n        static concurrency::streams::basic_ostream<char_type> open_ostream()\n        {\n            return concurrency::streams::basic_ostream<char_type>(buffer_type(std::ios_base::out));\n        }\n    };\n\n    /// <summary>\n    /// The stringstream allows an input stream to be constructed from std::string or std::wstring\n    /// For output streams the underlying string container could be retrieved using <c>buf-&gt;collection().</c>\n    /// </summary>\n    typedef container_stream<std::basic_string<char>> stringstream;\n    typedef stringstream::buffer_type stringstreambuf;\n\n    typedef container_stream<utility::string_t> wstringstream;\n    typedef wstringstream::buffer_type wstringstreambuf;\n\n    /// <summary>\n    /// The <c>bytestream</c> is a static class that allows an input stream to be constructed from any STL container.\n    /// </summary>\n    class bytestream\n    {\n    public:\n\n        /// <summary>\n        /// Creates a single byte character input stream given an STL container.\n        /// </summary>\n        /// <typeparam name=\"_CollectionType\">The type of the STL collection.</typeparam>\n        /// <param name=\"data\">STL container to back the input stream.</param>\n        /// <returns>An single byte character input stream.</returns>\n        template<typename _CollectionType>\n        static concurrency::streams::istream open_istream(_CollectionType data)\n        {\n            return concurrency::streams::istream(streams::container_buffer<_CollectionType>(std::move(data), std::ios_base::in));\n        }\n\n        /// <summary>\n        /// Creates a single byte character output stream using an STL container as storage.\n        /// </summary>\n        /// <typeparam name=\"_CollectionType\">The type of the STL collection.</typeparam>\n        /// <returns>A single byte character output stream.</returns>\n        template<typename _CollectionType>\n        static concurrency::streams::ostream open_ostream()\n        {\n            return concurrency::streams::ostream(streams::container_buffer<_CollectionType>());\n        }\n};\n\n\n}} // namespaces\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n#endif // !XSAPI_NO_PPL\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/SafeInt3.hpp",
    "content": "/*-----------------------------------------------------------------------------------------------------------\nSafeInt.hpp\nVersion 3.0.18p\n\nThis software is licensed under the Microsoft Public License (Ms-PL).\nFor more information about Microsoft open source licenses, refer to\nhttp://www.microsoft.com/opensource/licenses.mspx\n\nThis license governs use of the accompanying software. If you use the software, you accept this license.\nIf you do not accept the license, do not use the software.\n\nDefinitions\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here\nas under U.S. copyright law. A \"contribution\" is the original software, or any additions or changes to\nthe software. A \"contributor\" is any person that distributes its contribution under this license.\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\nGrant of Rights\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations\nin section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to\nreproduce its contribution, prepare derivative works of its contribution, and distribute its contribution\nor any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in\nsection 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed\npatents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution\nin the software or derivative works of the contribution in the software.\n\nConditions and Limitations\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo,\n    or trademarks.\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the\n    software, your patent license from such contributor to the software ends automatically.\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and\n    attribution notices that are present in the software.\n(D) If you distribute any portion of the software in source code form, you may do so only under this license\n    by including a complete copy of this license with your distribution. If you distribute any portion of the\n    software in compiled or object code form, you may only do so under a license that complies with this license.\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties,\n    guarantees, or conditions. You may have additional consumer rights under your local laws which this license\n    cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties\n    of merchantability, fitness for a particular purpose and non-infringement.\n\n\nCopyright (c) Microsoft Corporation.  All rights reserved.\n\nThis header implements an integer handling class designed to catch\nunsafe integer operations\n\nThis header compiles properly at Wall on Visual Studio, -Wall on gcc, and -Weverything on clang.\n\nPlease read the leading comments before using the class.\n---------------------------------------------------------------*/\n#pragma once\n\n// It is a bit tricky to sort out what compiler we are actually using,\n// do this once here, and avoid cluttering the code\n#define VISUAL_STUDIO_COMPILER 0\n#define CLANG_COMPILER 1\n#define GCC_COMPILER 2\n#define UNKNOWN_COMPILER -1\n\n// Clang will sometimes pretend to be Visual Studio\n// and does pretend to be gcc. Check it first, as nothing else pretends to be clang\n#if defined __clang__\n#define SAFEINT_COMPILER CLANG_COMPILER\n#elif defined __GNUC__\n#define SAFEINT_COMPILER GCC_COMPILER\n#elif defined _MSC_VER\n#define SAFEINT_COMPILER VISUAL_STUDIO_COMPILER\n#else\n#define SAFEINT_COMPILER UNKNOWN_COMPILER\n#endif\n\n// Enable compiling with /Wall under VC\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n#pragma warning( push )\n// Disable warnings coming from headers\n#pragma warning( disable:4987 4820 4987 4820 )\n\n#endif\n\n// Need this for ptrdiff_t on some compilers\n#include <cstddef>\n#include <cstdlib>\n\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER && defined _M_AMD64\n    #include <intrin.h>\n    #define SAFEINT_USE_INTRINSICS 1\n#else\n    #define SAFEINT_USE_INTRINSICS 0\n#endif\n\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n#pragma warning( pop )\n#endif\n\n// Various things needed for GCC\n#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER\n\n#define NEEDS_INT_DEFINED\n\n#if !defined NULL\n#define NULL 0\n#endif\n\n// GCC warning suppression\n#if SAFEINT_COMPILER == GCC_COMPILER\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wunused-local-typedefs\"\n#endif\n\n#include <stdint.h>\n\n// clang only\n#if SAFEINT_COMPILER == CLANG_COMPILER\n\n#if __has_feature(cxx_nullptr)\n   #define NEEDS_NULLPTR_DEFINED 0\n#endif\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wc++11-long-long\"\n#pragma clang diagnostic ignored \"-Wold-style-cast\"\n#pragma clang diagnostic ignored \"-Wunused-local-typedef\"\n#endif\n\n#endif\n\n// If the user made a choice, respect it #if !defined\n#if !defined NEEDS_NULLPTR_DEFINED\n    // Visual Studio 2010 and higher support this\n    #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n        #if (_MSC_VER < 1600)\n        #define NEEDS_NULLPTR_DEFINED 1\n        #else\n        #define NEEDS_NULLPTR_DEFINED 0\n        #endif\n    #else\n    // Let everything else trigger based on whether we use c++11 or above\n    #if __cplusplus >= 201103L\n        #define NEEDS_NULLPTR_DEFINED 0\n        #else\n        #define NEEDS_NULLPTR_DEFINED 1\n        #endif\n    #endif\n#endif\n\n#if NEEDS_NULLPTR_DEFINED\n#define nullptr NULL\n#endif\n\n#ifndef C_ASSERT\n#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]\n#endif\n\n// Let's test some assumptions\n// We're assuming two's complement negative numbers\nC_ASSERT( -1 == static_cast<int>(0xffffffff) );\n\n/************* Compiler Options *****************************************************************************************************\n\nSafeInt supports several compile-time options that can change the behavior of the class.\n\nCompiler options:\nSAFEINT_WARN_64BIT_PORTABILITY     - this re-enables various warnings that happen when /Wp64 is used. Enabling this option is not\n                                     recommended.\nNEEDS_INT_DEFINED                  - if your compiler does not support __int8, __int16, __int32 and __int64, you can enable this.\nSAFEINT_ASSERT_ON_EXCEPTION        - it is often easier to stop on an assert and figure out a problem than to try and figure out\n                                     how you landed in the catch block.\nSafeIntDefaultExceptionHandler     - if you'd like to replace the exception handlers SafeInt provides, define your replacement and\n                                     define this. Note - two built in (Windows-specific) options exist:\n                                     - SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an exception\n                                     - SAFEINT_RAISE_EXCEPTION - throws Win32 exceptions, which can be caught\nSAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to completely fail\n                                     to compile, define this.\nANSI_CONVERSIONS                   - This changes the class to use default comparison behavior, which may be unsafe. Enabling this\n                                     option is not recommended.\nSAFEINT_DISABLE_BINARY_ASSERT      - binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do\n                                     this, the default is to assert. Set this if you prefer not to assert under these conditions.\nSIZE_T_CAST_NEEDED                 - some compilers complain if there is not a cast to size_t, others complain if there is one.\n                                     This lets you not have your compiler complain.\nSAFEINT_DISABLE_SHIFT_ASSERT       - Set this option if you don't want to assert when shifting more bits than the type has. Enabling\n                                     this option is not recommended.\n\n************************************************************************************************************************************/\n\n/*\n*  The SafeInt class is designed to have as low an overhead as possible\n*  while still ensuring that all integer operations are conducted safely.\n*  Nearly every operator has been overloaded, with a very few exceptions.\n*\n*  A usability-safety trade-off has been made to help ensure safety. This\n*  requires that every operation return either a SafeInt or a bool. If we\n*  allowed an operator to return a base integer type T, then the following\n*  can happen:\n*\n*  char i = SafeInt<char>(32) * 2 + SafeInt<char>(16) * 4;\n*\n*  The * operators take precedence, get overloaded, return a char, and then\n*  you have:\n*\n*  char i = (char)64 + (char)64; //overflow!\n*\n*  This situation would mean that safety would depend on usage, which isn't\n*  acceptable.\n*\n*  One key operator that is missing is an implicit cast to type T. The reason for\n*  this is that if there is an implicit cast operator, then we end up with\n*  an ambiguous compile-time precedence. Because of this amiguity, there\n*  are two methods that are provided:\n*\n*  Casting operators for every native integer type\n*  Version 3 note - it now compiles correctly for size_t without warnings\n*\n*  SafeInt::Ptr()   - returns the address of the internal integer\n*  Note - the '&' (address of) operator has been overloaded and returns\n*         the address of the internal integer.\n*\n*  The SafeInt class should be used in any circumstances where ensuring\n*  integrity of the calculations is more important than performance. See Performance\n*  Notes below for additional information.\n*\n*  Many of the conditionals will optimize out or be inlined for a release\n*  build (especially with /Ox), but it does have significantly more overhead,\n*  especially for signed numbers. If you do not _require_ negative numbers, use\n*  unsigned integer types - certain types of problems cannot occur, and this class\n*  performs most efficiently.\n*\n*  Here's an example of when the class should ideally be used -\n*\n*  void* AllocateMemForStructs(int StructSize, int HowMany)\n*  {\n*     SafeInt<unsigned long> s(StructSize);\n*\n*     s *= HowMany;\n*\n*     return malloc(s);\n*\n*  }\n*\n*  Here's when it should NOT be used:\n*\n*  void foo()\n*  {\n*    int i;\n*\n*    for(i = 0; i < 0xffff; i++)\n*      ....\n*  }\n*\n*  Error handling - a SafeInt class will throw exceptions if something\n*  objectionable happens. The exceptions are SafeIntException classes,\n*  which contain an enum as a code.\n*\n*  Typical usage might be:\n*\n*  bool foo()\n*  {\n*    SafeInt<unsigned long> s; //note that s == 0 unless set\n*\n*    try{\n*      s *= 23;\n*      ....\n*    }\n*    catch(SafeIntException err)\n*    {\n*       //handle errors here\n*    }\n*  }\n*\n*  Update for 3.0 - the exception class is now a template parameter.\n*  You can replace the exception class with any exception class you like. This is accomplished by:\n*  1) Create a class that has the following interface:\n*\n    template <> class YourSafeIntExceptionHandler < YourException >\n    {\n    public:\n        static __declspec(noreturn) void __stdcall SafeIntOnOverflow()\n        {\n            throw YourException( YourSafeIntArithmeticOverflowError );\n        }\n\n        static __declspec(noreturn) void __stdcall SafeIntOnDivZero()\n        {\n            throw YourException( YourSafeIntDivideByZeroError );\n        }\n    };\n*\n*  Note that you don't have to throw C++ exceptions, you can throw Win32 exceptions, or do\n*  anything you like, just don't return from the call back into the code.\n*\n*  2) Either explicitly declare SafeInts like so:\n*     SafeInt< int, YourSafeIntExceptionHandler > si;\n*  or\n*     #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler\n*\n*  Performance:\n*\n*  Due to the highly nested nature of this class, you can expect relatively poor\n*  performance in unoptimized code. In tests of optimized code vs. correct inline checks\n*  in native code, this class has been found to take approximately 8% more CPU time (this varies),\n*  most of which is due to exception handling. Solutions:\n*\n*  1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1\n*     (optimize for size) does not work as well.\n*  2) If that 8% hit is really a serious problem, walk through the code and inline the\n*     exact same checks as the class uses.\n*  3) Some operations are more difficult than others - avoid using signed integers, and if\n*     possible keep them all the same size. 64-bit integers are also expensive. Mixing\n*     different integer sizes and types may prove expensive. Be aware that literals are\n*     actually ints. For best performance, cast literals to the type desired.\n*\n*\n*  Performance update\n*  The current version of SafeInt uses template specialization to force the compiler to invoke only the\n*  operator implementation needed for any given pair of types. This will dramatically improve the perf\n*  of debug builds.\n*\n*  3.0 update - not only have we maintained the specialization, there were some cases that were overly complex,\n*  and using some additional cases (e.g. signed __int64 and unsigned __int64) resulted in some simplification.\n*  Additionally, there was a lot of work done to better optimize the 64-bit multiplication.\n*\n*  Binary Operators\n*\n*  All of the binary operators have certain assumptions built into the class design.\n*  This is to ensure correctness. Notes on each class of operator follow:\n*\n*  Arithmetic Operators (*,/,+,-,%)\n*  There are three possible variants:\n*  SafeInt< T, E > op SafeInt< T, E >\n*  SafeInt< T, E > op U\n*  U op SafeInt< T, E >\n*\n*  The SafeInt< T, E > op SafeInt< U, E > variant is explicitly not supported, and if you try to do\n*  this the compiler with throw the following error:\n*\n*  error C2593: 'operator *' is ambiguous\n*\n*  This is because the arithmetic operators are required to return a SafeInt of some type.\n*  The compiler cannot know whether you'd prefer to get a type T or a type U returned. If\n*  you need to do this, you need to extract the value contained within one of the two using\n*  the casting operator. For example:\n*\n*  SafeInt< T, E > t, result;\n*  SafeInt< U, E > u;\n*\n*  result = t * (U)u;\n*\n*  Comparison Operators\n*  Because each of these operators return type bool, mixing SafeInts of differing types is\n*  allowed.\n*\n*  Shift Operators\n*  Shift operators always return the type on the left hand side of the operator. Mixed type\n*  operations are allowed because the return type is always known.\n*\n*  Boolean Operators\n*  Like comparison operators, these overloads always return type bool, and mixed-type SafeInts\n*  are allowed. Additionally, specific overloads exist for type bool on both sides of the\n*  operator.\n*\n*  Binary Operators\n*  Mixed-type operations are discouraged, however some provision has been made in order to\n*  enable things like:\n*\n*  SafeInt<char> c = 2;\n*\n*  if(c & 0x02)\n*    ...\n*\n*  The \"0x02\" is actually an int, and it needs to work.\n*  In the case of binary operations on integers smaller than 32-bit, or of mixed type, corner\n*  cases do exist where you could get unexpected results. In any case where SafeInt returns a different\n*  result than the underlying operator, it will call assert(). You should examine your code and cast things\n*  properly so that you are not programming with side effects.\n*\n*  Documented issues:\n*\n*  This header compiles correctly at /W4 using VC++ 8 (Version 14.00.50727.42) and later.\n*  As of this writing, I believe it will also work for VC 7.1, but not for VC 7.0 or below.\n*  If you need a version that will work with lower level compilers, try version 1.0.7. None\n*  of them work with Visual C++ 6, and gcc didn't work very well, either, though this hasn't\n*  been tried recently.\n*\n*  It is strongly recommended that any code doing integer manipulation be compiled at /W4\n*  - there are a number of warnings which pertain to integer manipulation enabled that are\n*  not enabled at /W3 (default for VC++)\n*\n*  Perf note - postfix operators are slightly more costly than prefix operators.\n*  Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++\n*\n*  The comparison operator behavior in this class varies from the ANSI definition, which is\n*  arguably broken. As an example, consider the following:\n*\n*  unsigned int l = 0xffffffff;\n*  char c = -1;\n*\n*  if(c == l)\n*    printf(\"Why is -1 equal to 4 billion???\\n\");\n*\n*  The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets\n*  cast again to an unsigned int, losing the true value. This behavior is despite the fact that\n*  an __int64 exists, and the following code will yield a different (and intuitively correct)\n*  answer:\n*\n*  if((__int64)c == (__int64)l))\n*    printf(\"Why is -1 equal to 4 billion???\\n\");\n*  else\n*    printf(\"Why doesn't the compiler upcast to 64-bits when needed?\\n\");\n*\n*  Note that combinations with smaller integers won't display the problem - if you\n*  changed \"unsigned int\" above to \"unsigned short\", you'd get the right answer.\n*\n*  If you prefer to retain the ANSI standard behavior insert\n*  #define ANSI_CONVERSIONS\n*  into your source. Behavior differences occur in the following cases:\n*  8, 16, and 32-bit signed int, unsigned 32-bit int\n*  any signed int, unsigned 64-bit int\n*  Note - the signed int must be negative to show the problem\n*\n*\n*  Revision history:\n*\n*  Oct 12, 2003 - Created\n*  Author - David LeBlanc - dleblanc@microsoft.com\n*\n*  Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson\n*  Dec 28, 2003 - 1.0\n*                 added support for mixed-type operations\n*                 thanks to vikramh\n*                 also fixed broken __int64 multiplication section\n*                 added extended support for mixed-type operations where possible\n*  Jan 28, 2004 - 1.0.1\n*                 changed WCHAR to wchar_t\n*                 fixed a construct in two mixed-type assignment overloads that was\n*                 not compiling on some compilers\n*                 Also changed name of private method to comply with standards on\n*                 reserved names\n*                 Thanks to Niels Dekker for the input\n*  Feb 12, 2004 - 1.0.2\n*                 Minor changes to remove dependency on Windows headers\n*                 Consistently used __int16, __int32 and __int64 to ensure\n*                 portability\n*  May 10, 2004 - 1.0.3\n*                 Corrected bug in one case of GreaterThan\n*  July 22, 2004 - 1.0.4\n*                 Tightened logic in addition check (saving 2 instructions)\n*                 Pulled error handler out into function to enable user-defined replacement\n*                 Made internal type of SafeIntException an enum (as per Niels' suggestion)\n*                 Added casts for base integer types (as per Scott Meyers' suggestion)\n*                 Updated usage information - see important new perf notes.\n*                 Cleaned up several const issues (more thanks to Niels)\n*\n*  Oct 1, 2004 - 1.0.5\n*                 Added support for SEH exceptions instead of C++ exceptions - Win32 only\n*                 Made handlers for DIV0 and overflows individually overridable\n*                 Commented out the destructor - major perf gains here\n*                 Added cast operator for type long, since long != __int32\n*                  Corrected a couple of missing const modifiers\n*                 Fixed broken >= and <= operators for type U op SafeInt< T, E >\n*  Nov 5, 2004 - 1.0.6\n*                 Implemented new logic in binary operators to resolve issues with\n*                 implicit casts\n*                 Fixed casting operator because char != signed char\n*                 Defined __int32 as int instead of long\n*                 Removed unsafe SafeInt::Value method\n*                 Re-implemented casting operator as a result of removing Value method\n*  Dec 1, 2004 - 1.0.7\n*                 Implemented specialized operators for pointer arithmetic\n*                 Created overloads for cases of U op= SafeInt. What you do with U\n*                 after that may be dangerous.\n*                 Fixed bug in corner case of MixedSizeModulus\n*                 Fixed bug in MixedSizeMultiply and MixedSizeDivision with input of 0\n*                 Added throw() decorations\n*\n*  Apr 12, 2005 - 2.0\n*                 Extensive revisions to leverage template specialization.\n*  April, 2007    Extensive revisions for version 3.0\n*  Nov 22, 2009   Forked from MS internal code\n*                 Changes needed to support gcc compiler - many thanks to Niels Dekker\n*                 for determining not just the issues, but also suggesting fixes.\n*                 Also updating some of the header internals to be the same as the upcoming Visual Studio version.\n*\n*  Jan 16, 2010   64-bit gcc has long == __int64, which means that many of the existing 64-bit\n*                 templates are over-specialized. This forces a redefinition of all the 64-bit\n*                 multiplication routines to use pointers instead of references for return\n*                 values. Also, let's use some intrinsics for x64 Microsoft compiler to\n*                 reduce code size, and hopefully improve efficiency.\n*\n*  June 21, 2014  Better support for clang, higher warning levels supported for all 3 primary supported\n                  compilers (Visual Studio, clang, gcc).\n                  Also started to converge the code base such that the public CodePlex version will\n                  be a drop-in replacement for the Visual Studio version.\n\n*  Note about code style - throughout this class, casts will be written using C-style (T),\n*  not C++ style static_cast< T >. This is because the class is nearly always dealing with integer\n*  types, and in this case static_cast and a C cast are equivalent. Given the large number of casts,\n*  the code is a little more readable this way. In the event a cast is needed where static_cast couldn't\n*  be substituted, we'll use the new templatized cast to make it explicit what the operation is doing.\n*\n************************************************************************************************************\n* Version 3.0 changes:\n*\n* 1) The exception type thrown is now replacable, and you can throw your own exception types. This should help\n*    those using well-developed exception classes.\n* 2) The 64-bit multiplication code has had a lot of perf work done, and should be faster than 2.0.\n* 3) There is now limited floating point support. You can initialize a SafeInt with a floating point type,\n*    and you can cast it out (or assign) to a float as well.\n* 4) There is now an Align method. I noticed people use this a lot, and rarely check errors, so now you have one.\n*\n* Another major improvement is the addition of external functions - if you just want to check an operation, this can now happen:\n* All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially handy\n* for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for 64-bit.\n*\n* inline bool SafeCast( const T From, U& To ) throw()\n* inline bool SafeEquals( const T t, const U u ) throw()\n* inline bool SafeNotEquals( const T t, const U u ) throw()\n* inline bool SafeGreaterThan( const T t, const U u ) throw()\n* inline bool SafeGreaterThanEquals( const T t, const U u ) throw()\n* inline bool SafeLessThan( const T t, const U u ) throw()\n* inline bool SafeLessThanEquals( const T t, const U u ) throw()\n* inline bool SafeModulus( const T& t, const U& u, T& result ) throw()\n* inline bool SafeMultiply( T t, U u, T& result ) throw()\n* inline bool SafeDivide( T t, U u, T& result ) throw()\n* inline bool SafeAdd( T t, U u, T& result ) throw()\n* inline bool SafeSubtract( T t, U u, T& result ) throw()\n*\n*/\n\n//use these if the compiler does not support _intXX\n#ifdef NEEDS_INT_DEFINED\n#define __int8  char\n#define __int16 short\n#define __int32 int\n#define __int64 long long\n#endif\n\nnamespace msl\n{\n\nnamespace safeint3\n{\n\n// catch these to handle errors\n// Currently implemented code values:\n// ERROR_ARITHMETIC_OVERFLOW\n// EXCEPTION_INT_DIVIDE_BY_ZERO\nenum SafeIntError\n{\n    SafeIntNoError = 0,\n    SafeIntArithmeticOverflow,\n    SafeIntDivideByZero\n};\n\n} // safeint3\n} // msl\n\n\n/*\n* Error handler classes\n* Using classes to deal with exceptions is going to allow the most\n* flexibility, and we can mix different error handlers in the same project\n* or even the same file. It isn't advisable to do this in the same function\n* because a SafeInt< int, MyExceptionHandler > isn't the same thing as\n* SafeInt< int, YourExceptionHander >.\n* If for some reason you have to translate between the two, cast one of them back to its\n* native type.\n*\n* To use your own exception class with SafeInt, first create your exception class,\n* which may look something like the SafeIntException class below. The second step is to\n* create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero.\n* For example:\n*\n* template <> class SafeIntExceptionHandler < YourExceptionClass >\n* {\n*     static __declspec(noreturn) void __stdcall SafeIntOnOverflow()\n*     {\n*         throw YourExceptionClass( EXCEPTION_INT_OVERFLOW );\n*     }\n*\n*     static __declspec(noreturn) void __stdcall SafeIntOnDivZero()\n*     {\n*         throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO );\n*     }\n* };\n*\n* typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler\n* You'd then declare your SafeInt objects like this:\n* SafeInt< int, YourSafeIntExceptionHandler >\n*\n* Unfortunately, there is no such thing as partial template specialization in typedef\n* statements, so you have three options if you find this cumbersome:\n*\n* 1) Create a holder class:\n*\n* template < typename T >\n* class MySafeInt\n* {\n*   public:\n*   SafeInt< T, MyExceptionClass> si;\n* };\n*\n* You'd then declare an instance like so:\n* MySafeInt< int > i;\n*\n* You'd lose handy things like initialization - it would have to be initialized as:\n*\n* i.si = 0;\n*\n* 2) You could create a typedef for every int type you deal with:\n*\n* typedef SafeInt< int, MyExceptionClass > MySafeInt;\n* typedef SafeInt< char, MyExceptionClass > MySafeChar;\n*\n* and so on. The second approach is probably more usable, and will just drop into code\n* better, which is the original intent of the SafeInt class.\n*\n* 3) If you're going to consistently use a different class to handle your exceptions,\n*    you can override the default typedef like so:\n*\n*    #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler\n*\n*    Overall, this is probably the best approach.\n* */\n\n// On the Microsoft compiler, violating a throw() annotation is a silent error.\n// Other compilers might turn these into exceptions, and some users may want to not have throw() enabled.\n// In addition, some error handlers may not throw C++ exceptions, which makes everything no throw.\n#if defined SAFEINT_REMOVE_NOTHROW\n#define SAFEINT_NOTHROW\n#else\n#define SAFEINT_NOTHROW throw()\n#endif\n\nnamespace msl\n{\n\nnamespace safeint3\n{\n\n// If you would like to use your own custom assert\n// Define SAFEINT_ASSERT\n#if !defined SAFEINT_ASSERT\n#include <assert.h>\n#define SAFEINT_ASSERT(x) assert(x)\n#endif\n\n#if defined SAFEINT_ASSERT_ON_EXCEPTION\n\tinline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); }\n#else\n\tinline void SafeIntExceptionAssert() SAFEINT_NOTHROW {}\n#endif\n\n#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER\n    #define SAFEINT_NORETURN __attribute__((noreturn))\n    #define SAFEINT_STDCALL\n    #define SAFEINT_VISIBLE __attribute__ ((__visibility__(\"default\")))\n    #define SAFEINT_WEAK __attribute__ ((weak))\n#else\n    #define SAFEINT_NORETURN __declspec(noreturn)\n    #define SAFEINT_STDCALL __stdcall\n    #define SAFEINT_VISIBLE\n    #define SAFEINT_WEAK\n#endif\n\nclass SAFEINT_VISIBLE SafeIntException\n{\npublic:\n    SafeIntException() SAFEINT_NOTHROW { m_code = SafeIntNoError; }\n    SafeIntException( SafeIntError code ) SAFEINT_NOTHROW\n    {\n        m_code = code;\n    }\n    SafeIntError m_code;\n};\n\nnamespace SafeIntInternal\n{\n    // Visual Studio version of SafeInt provides for two possible error\n    // handlers:\n    // SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined\n    // SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers, \n    //                                       exits the app with a crash\n    template < typename E > class SafeIntExceptionHandler;\n\n    template <> class SafeIntExceptionHandler < SafeIntException >\n    {\n    public:\n\n        static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow()\n        {\n            SafeIntExceptionAssert();\n            throw SafeIntException( SafeIntArithmeticOverflow );\n        }\n\n        static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero()\n        {\n            SafeIntExceptionAssert();\n            throw SafeIntException( SafeIntDivideByZero );\n        }\n    };\n\n#if !defined _CRT_SECURE_INVALID_PARAMETER\n\t// Calling fail fast is somewhat more robust than calling abort, \n\t// but abort is the closest we can manage without Visual Studio support\n\t// Need the header for abort()\n\t#include <stdlib.h>\n\t#define _CRT_SECURE_INVALID_PARAMETER(msg) abort()\n#endif\n\n   class SafeInt_InvalidParameter\n   {\n   public:\n       static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW\n       {\n           SafeIntExceptionAssert();\n           _CRT_SECURE_INVALID_PARAMETER(\"SafeInt Arithmetic Overflow\");\n       }\n\n       static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW\n       {\n           SafeIntExceptionAssert();\n           _CRT_SECURE_INVALID_PARAMETER(\"SafeInt Divide By Zero\");\n       }\n   };\n\n#if defined _WINDOWS_ \n\n    class SafeIntWin32ExceptionHandler \n    {\n    public:\n        static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW\n        {\n            SafeIntExceptionAssert();\n\t\t\tRaiseException( static_cast<DWORD>(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0);\n        }\n\n        static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW\n        {\n            SafeIntExceptionAssert();\n\t\t\tRaiseException( static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0);\n        }\n    };\n\n#endif\n\n} // namespace SafeIntInternal\n\n// both of these have cross-platform support\ntypedef SafeIntInternal::SafeIntExceptionHandler < SafeIntException > CPlusPlusExceptionHandler;\ntypedef SafeIntInternal::SafeInt_InvalidParameter InvalidParameterExceptionHandler;\n\n// This exception handler is no longer recommended, but is left here in order not to break existing users\n#if defined _WINDOWS_ \ntypedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler;\n#endif\n\n// For Visual Studio compatibility\n#if defined VISUAL_STUDIO_SAFEINT_COMPAT \n    typedef CPlusPlusExceptionHandler  SafeIntErrorPolicy_SafeIntException;\n    typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter;\n#endif\n\n// If the user hasn't defined a default exception handler,\n// define one now, depending on whether they would like Win32 or C++ exceptions\n\n// This library will use conditional noexcept soon, but not in this release\n// Some users might mix exception handlers, which is not advised, but is supported\n#if !defined SafeIntDefaultExceptionHandler\n    #if defined SAFEINT_RAISE_EXCEPTION\n        #if !defined _WINDOWS_\n        #error Include windows.h in order to use Win32 exceptions\n        #endif\n\n        #define SafeIntDefaultExceptionHandler Win32ExceptionHandler\n    #elif defined SAFEINT_FAILFAST\n        #define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler\n    #else\n        #define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler\n\t\t#if !defined SAFEINT_EXCEPTION_HANDLER_CPP\n\t\t#define SAFEINT_EXCEPTION_HANDLER_CPP 1\n\t\t#endif\n    #endif\n#endif\n\n#if !defined SAFEINT_EXCEPTION_HANDLER_CPP\n#define SAFEINT_EXCEPTION_HANDLER_CPP 0\n#endif\n\n// If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast, \n// or abort, then all methods become no throw. Some teams track throw() annotations closely,\n// and the following option provides for this.\n#if SAFEINT_EXCEPTION_HANDLER_CPP\n#define SAFEINT_CPP_THROW\n#else\n#define SAFEINT_CPP_THROW SAFEINT_NOTHROW\n#endif\n\n// Turns out we can fool the compiler into not seeing compile-time constants with\n// a simple template specialization\ntemplate < int method > class CompileConst;\ntemplate <> class CompileConst<true> { public: static bool Value() SAFEINT_NOTHROW { return true; } };\ntemplate <> class CompileConst<false> { public: static bool Value() SAFEINT_NOTHROW { return false; } };\n\n// The following template magic is because we're now not allowed\n// to cast a float to an enum. This means that if we happen to assign\n// an enum to a SafeInt of some type, it won't compile, unless we prevent\n//              isFloat = ( (T)( (float)1.1 ) > (T)1 )\n// from compiling in the case of an enum, which is the point of the specialization\n// that follows.\n\n// If we have support for std<typetraits>, then we can do this easily, and detect enums as well\ntemplate < typename T > class NumericType;\n\n#if defined _LIBCPP_TYPE_TRAITS || defined _TYPE_TRAITS_\n// Continue to special case bool\ntemplate <> class NumericType<bool>             { public: enum{ isBool = true,  isFloat = false, isInt = false }; };\ntemplate < typename T > class NumericType\n{\n    public: \n        enum\n        { \n            isBool = false, // We specialized out a bool  \n            isFloat = std::is_floating_point<T>::value,\n            // If it is an enum, then consider it an int type\n            // This does allow someone to make a SafeInt from an enum type, which is not recommended,\n            // but it also allows someone to add an enum value to a SafeInt, which is handy.\n            isInt = std::is_integral<T>::value || std::is_enum<T>::value\n        };\n};\n\n#else\n\ntemplate <> class NumericType<bool>             { public: enum{ isBool = true,  isFloat = false, isInt = false }; };\ntemplate <> class NumericType<char>             { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<unsigned char>    { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<signed char>      { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<short>            { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<unsigned short>   { public: enum{ isBool = false, isFloat = false, isInt = true }; };\n#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED\ntemplate <> class NumericType<wchar_t>          { public: enum{ isBool = false, isFloat = false, isInt = true }; };\n#endif\ntemplate <> class NumericType<int>              { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<unsigned int>     { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<long>             { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<unsigned long>    { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<__int64>          { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<unsigned __int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };\ntemplate <> class NumericType<float>            { public: enum{ isBool = false, isFloat = true,  isInt = false }; };\ntemplate <> class NumericType<double>           { public: enum{ isBool = false, isFloat = true,  isInt = false }; };\ntemplate <> class NumericType<long double>      { public: enum{ isBool = false, isFloat = true,  isInt = false }; };\n// Catch-all for anything not supported\ntemplate < typename T > class NumericType       \n{ \npublic: \n    // We have some unknown type, which could be an enum. For parity with the code that uses <type_traits>,\n    // We can try a static_cast<int> - it if compiles, then it might be an enum, and should work.\n    // If it is something else that just happens to have a constructor that takes an int, and a casting operator,\n    // then it is possible something will go wrong, and for best results, cast it directly to an int before letting it\n    // interact with a SafeInt\n\n    enum\n    { \n        isBool = false, \n        isFloat = false, \n        isInt = static_cast<int>( static_cast<T>(0) ) == 0\n    }; \n};\n#endif // type traits\n\n// Use this to avoid compile-time const truncation warnings\ntemplate < int fSigned, int bits > class SafeIntMinMax;\n\ntemplate <> class SafeIntMinMax< true,   8 > { public: const static signed __int8  min = (-0x7f - 1);\n                                                const static signed __int8  max = 0x7f; };\ntemplate <> class SafeIntMinMax< true,  16 > { public: const static __int16 min = ( -0x7fff - 1 );\n                                                const static __int16 max = 0x7fff; };\ntemplate <> class SafeIntMinMax< true,  32 > { public: const static __int32 min = ( -0x7fffffff -1 );\n                                                const static __int32 max = 0x7fffffff; };\ntemplate <> class SafeIntMinMax< true,  64 > { public: const static __int64 min = static_cast<__int64>(0x8000000000000000LL);\n                                                const static __int64 max = 0x7fffffffffffffffLL; };\n\ntemplate <> class SafeIntMinMax< false,  8 > { public: const static unsigned __int8  min = 0;\n                                                const static unsigned __int8  max = 0xff; };\ntemplate <> class SafeIntMinMax< false, 16 > { public: const static unsigned __int16 min = 0;\n                                                const static unsigned __int16 max = 0xffff; };\ntemplate <> class SafeIntMinMax< false, 32 > { public: const static unsigned __int32 min = 0;\n                                                const static unsigned __int32 max = 0xffffffff; };\ntemplate <> class SafeIntMinMax< false, 64 > { public: const static unsigned __int64 min = 0;\n                                                const static unsigned __int64 max = 0xffffffffffffffffULL; };\n\ntemplate < typename T > class IntTraits\n{\npublic:\n    C_ASSERT( NumericType<T>::isInt );\n    enum\n    {\n        isSigned  = ( (T)(-1) < 0 ),\n        is64Bit   = ( sizeof(T) == 8 ),\n        is32Bit   = ( sizeof(T) == 4 ),\n        is16Bit   = ( sizeof(T) == 2 ),\n        is8Bit    = ( sizeof(T) == 1 ),\n        isLT32Bit = ( sizeof(T) < 4 ),\n        isLT64Bit = ( sizeof(T) < 8 ),\n        isInt8    = ( sizeof(T) == 1 && isSigned ),\n        isUint8   = ( sizeof(T) == 1 && !isSigned ),\n        isInt16   = ( sizeof(T) == 2 && isSigned ),\n        isUint16  = ( sizeof(T) == 2 && !isSigned ),\n        isInt32   = ( sizeof(T) == 4 && isSigned ),\n        isUint32  = ( sizeof(T) == 4 && !isSigned ),\n        isInt64   = ( sizeof(T) == 8 && isSigned ),\n        isUint64  = ( sizeof(T) == 8 && !isSigned ),\n        bitCount  = ( sizeof(T)*8 ),\n        isBool    = ( (T)2 == (T)1 )\n    };\n\n    // On version 13.10 enums cannot define __int64 values\n    // so we'll use const statics instead!\n    // These must be cast to deal with the possibility of a SafeInt being given an enum as an argument\n    const static T maxInt = static_cast<T>(SafeIntMinMax< isSigned, bitCount >::max);\n    const static T minInt = static_cast<T>(SafeIntMinMax< isSigned, bitCount >::min);\n};\n\ntemplate < typename T >\nconst T IntTraits< T >::maxInt;\ntemplate < typename T >\nconst T IntTraits< T >::minInt;\n\ntemplate < typename T, typename U > class SafeIntCompare\n{\npublic:\n    enum\n    {\n        isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned),\n        isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned),\n        isLikeSigned = ((bool)(IntTraits< T >::isSigned) == (bool)(IntTraits< U >::isSigned)),\n        isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) ||\n                    (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))),\n        isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit),\n        isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit)\n    };\n};\n\n//all of the arithmetic operators can be solved by the same code within\n//each of these regions without resorting to compile-time constant conditionals\n//most operators collapse the problem into less than the 22 zones, but this is used\n//as the first cut\n//using this also helps ensure that we handle all of the possible cases correctly\n\ntemplate < typename T, typename U > class IntRegion\n{\npublic:\n    enum\n    {\n        //unsigned-unsigned zone\n        IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit,\n        IntZone_Uint32_UintLT64   = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,\n        IntZone_UintLT32_Uint32   = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,\n        IntZone_Uint64_Uint       = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit,\n        IntZone_UintLT64_Uint64    = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,\n        //unsigned-signed\n        IntZone_UintLT32_IntLT32  = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,\n        IntZone_Uint32_IntLT64    = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,\n        IntZone_UintLT32_Int32    = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32,\n        IntZone_Uint64_Int        = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,\n        IntZone_UintLT64_Int64    = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64,\n        IntZone_Uint64_Int64      = IntTraits< T >::isUint64 && IntTraits< U >::isInt64,\n        //signed-signed\n        IntZone_IntLT32_IntLT32   = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit,\n        IntZone_Int32_IntLT64     = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,\n        IntZone_IntLT32_Int32     = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,\n        IntZone_Int64_Int64       = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64,\n        IntZone_Int64_Int         = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit,\n        IntZone_IntLT64_Int64     = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,\n        //signed-unsigned\n        IntZone_IntLT32_UintLT32  = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,\n        IntZone_Int32_UintLT32    = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit,\n        IntZone_IntLT64_Uint32    = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32,\n        IntZone_Int64_UintLT64    = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,\n        IntZone_Int_Uint64        = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit,\n        IntZone_Int64_Uint64      = IntTraits< T >::isInt64 && IntTraits< U >::isUint64\n    };\n};\n\n\n// In all of the following functions, we have two versions\n// One for SafeInt, which throws C++ (or possibly SEH) exceptions\n// The non-throwing versions are for use by the helper functions that return success and failure.\n// Some of the non-throwing functions are not used, but are maintained for completeness.\n\n// There's no real alternative to duplicating logic, but keeping the two versions\n// immediately next to one another will help reduce problems\n\n\n// useful function to help with getting the magnitude of a negative number\nenum AbsMethod\n{\n    AbsMethodInt,\n    AbsMethodInt64,\n    AbsMethodNoop\n};\n\ntemplate < typename T >\nclass GetAbsMethod\n{\npublic:\n    enum\n    {\n        method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt :\n                 IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop\n    };\n};\n\n// let's go ahead and hard-code a dependency on the\n// representation of negative numbers to keep compilers from getting overly\n// happy with optimizing away things like -MIN_INT.\ntemplate < typename T, int > class AbsValueHelper;\n\ntemplate < typename T > class AbsValueHelper < T, AbsMethodInt>\n{\npublic:\n    static unsigned __int32 Abs( T t ) SAFEINT_NOTHROW\n    {\n        SAFEINT_ASSERT( t < 0 );\n        return ~(unsigned __int32)t + 1;\n    }\n};\n\ntemplate < typename T > class AbsValueHelper < T, AbsMethodInt64 >\n{\npublic:\n    static unsigned __int64 Abs( T t ) SAFEINT_NOTHROW\n    {\n        SAFEINT_ASSERT( t < 0 );\n        return ~(unsigned __int64)t + 1;\n    }\n};\n\ntemplate < typename T > class AbsValueHelper < T, AbsMethodNoop >\n{\npublic:\n    static T Abs( T t ) SAFEINT_NOTHROW\n    {\n        // Why are you calling Abs on an unsigned number ???\n        SAFEINT_ASSERT( false );\n        return t;\n    }\n};\n\ntemplate < typename T, bool > class NegationHelper;\n// Previous versions had an assert that the type being negated was 32-bit or higher\n// In retrospect, this seems like something to just document\n// Negation will normally upcast to int\n// For example -(unsigned short)0xffff == (int)0xffff0001\n// This class will retain the type, and will truncate, which may not be what\n// you wanted\n// If you want normal operator casting behavior, do this:\n// SafeInt<unsigned short> ss = 0xffff;\n// then:\n// -(SafeInt<int>(ss))\n// will then emit a signed int with the correct value and bitfield\n\ntemplate < typename T > class NegationHelper <T, true> // Signed\n{\npublic:\n    template <typename E>\n    static T NegativeThrow( T t ) SAFEINT_CPP_THROW\n    {\n        // corner case\n        if( t != IntTraits< T >::minInt )\n        {\n            // cast prevents unneeded checks in the case of small ints\n            return -t;\n        }\n        E::SafeIntOnOverflow();\n    }\n\n    static bool Negative( T t, T& ret ) SAFEINT_NOTHROW\n    {\n        // corner case\n        if( t != IntTraits< T >::minInt )\n        {\n            // cast prevents unneeded checks in the case of small ints\n            ret = -t;\n            return true;\n        }\n        return false;\n    }\n};\n\n// Helper classes to work keep compilers from\n// optimizing away negation\ntemplate < typename T > class SignedNegation;\n\ntemplate <>\nclass SignedNegation <signed __int32>\n{\npublic:\n    static signed __int32 Value(unsigned __int64 in) SAFEINT_NOTHROW\n    {\n        return (signed __int32)(~(unsigned __int32)in + 1);\n    }\n\n    static signed __int32 Value(unsigned __int32 in) SAFEINT_NOTHROW\n    {\n        return (signed __int32)(~in + 1);\n    }\n};\n\ntemplate <>\nclass SignedNegation <signed __int64>\n{\npublic:\n    static signed __int64 Value(unsigned __int64 in) SAFEINT_NOTHROW\n    {\n        return (signed __int64)(~in + 1);\n    }\n};\n\ntemplate < typename T > class NegationHelper <T, false> // unsigned\n{\npublic:\n    template <typename E>\n    static T NegativeThrow( T t ) SAFEINT_CPP_THROW\n    {\n#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION\n        C_ASSERT( sizeof(T) == 0 );\n#endif\n\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n#pragma warning(push)\n//this avoids warnings from the unary '-' operator being applied to unsigned numbers\n#pragma warning(disable:4146)\n#endif\n        // Note - this could be quenched on gcc\n        // by doing something like:\n        // return (T)-((__int64)t);\n        // but it seems like you would want a warning when doing this.\n        return (T)-t;\n\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n#pragma warning(pop)\n#endif\n    }\n\n    static bool Negative( T t, T& ret ) SAFEINT_NOTHROW\n    {\n        if( IntTraits<T>::isLT32Bit )\n        {\n            // See above\n            SAFEINT_ASSERT( false );\n        }\n#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION\n        C_ASSERT( sizeof(T) == 0 );\n#endif\n        // Do it this way to avoid warning\n        ret = -t;\n        return true;\n    }\n};\n\n//core logic to determine casting behavior\nenum CastMethod\n{\n    CastOK = 0,\n    CastCheckLTZero,\n    CastCheckGTMax,\n    CastCheckSafeIntMinMaxUnsigned,\n    CastCheckSafeIntMinMaxSigned,\n    CastToFloat,\n    CastFromFloat,\n    CastToBool,\n    CastFromBool\n};\n\n\ntemplate < typename ToType, typename FromType >\nclass GetCastMethod\n{\npublic:\n    enum\n    {\n        method =  ( IntTraits< FromType >::isBool &&\n                     !IntTraits< ToType >::isBool )                    ? CastFromBool :\n\n                 ( !IntTraits< FromType >::isBool &&\n                     IntTraits< ToType >::isBool )                     ? CastToBool :\n\n                 ( SafeIntCompare< ToType, FromType >::isCastOK )      ? CastOK :\n\n                 ( ( IntTraits< ToType >::isSigned &&\n                        !IntTraits< FromType >::isSigned &&\n                        sizeof( FromType ) >= sizeof( ToType ) ) ||\n                   ( SafeIntCompare< ToType, FromType >::isBothUnsigned &&\n                        sizeof( FromType ) > sizeof( ToType ) ) )      ? CastCheckGTMax :\n\n                 ( !IntTraits< ToType >::isSigned &&\n                     IntTraits< FromType >::isSigned &&\n                     sizeof( ToType ) >= sizeof( FromType ) )          ? CastCheckLTZero :\n\n                 ( !IntTraits< ToType >::isSigned )                    ? CastCheckSafeIntMinMaxUnsigned\n                                                                       : CastCheckSafeIntMinMaxSigned\n    };\n};\n\ntemplate < typename FromType > class GetCastMethod < float, FromType >\n{\npublic:\n    enum{ method = CastOK };\n};\n\ntemplate < typename FromType > class GetCastMethod < double, FromType >\n{\npublic:\n    enum{ method = CastOK };\n};\n\ntemplate < typename FromType > class GetCastMethod < long double, FromType >\n{\npublic:\n    enum{ method = CastOK };\n};\n\ntemplate < typename ToType > class GetCastMethod < ToType, float >\n{\npublic:\n    enum{ method = CastFromFloat };\n};\n\ntemplate < typename ToType > class GetCastMethod < ToType, double >\n{\npublic:\n    enum{ method = CastFromFloat };\n};\n\ntemplate < typename ToType > class GetCastMethod < ToType, long double >\n{\npublic:\n    enum{ method = CastFromFloat };\n};\n\ntemplate < typename T, typename U, int > class SafeCastHelper;\n\ntemplate < typename T, typename U > class SafeCastHelper < T, U, CastOK >\n{\npublic:\n    static bool Cast( U u, T& t ) SAFEINT_NOTHROW\n    {\n        t = (T)u;\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW\n    {\n        t = (T)u;\n    }\n};\n\n// special case floats and doubles\n// tolerate loss of precision\ntemplate < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat >\n{\npublic:\n    static bool Cast( U u, T& t ) SAFEINT_NOTHROW\n    {\n        if( u <= (U)IntTraits< T >::maxInt &&\n            u >= (U)IntTraits< T >::minInt )\n        {\n            t = (T)u;\n            return true;\n        }\n        return false;\n    }\n\n    template < typename E >\n    static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW\n    {\n        if( u <= (U)IntTraits< T >::maxInt &&\n            u >= (U)IntTraits< T >::minInt )\n        {\n            t = (T)u;\n            return;\n        }\n        E::SafeIntOnOverflow();\n    }\n};\n\n// Match on any method where a bool is cast to type T\ntemplate < typename T > class SafeCastHelper < T, bool, CastFromBool >\n{\npublic:\n    static bool Cast( bool b, T& t ) SAFEINT_NOTHROW\n    {\n        t = (T)( b ? 1 : 0 );\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW\n    {\n        t = (T)( b ? 1 : 0 );\n    }\n};\n\ntemplate < typename T > class SafeCastHelper < bool, T, CastToBool >\n{\npublic:\n    static bool Cast( T t, bool& b ) SAFEINT_NOTHROW\n    {\n        b = !!t;\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW\n    {\n        b = !!t;\n    }\n};\n\ntemplate < typename T, typename U > class SafeCastHelper < T, U, CastCheckLTZero >\n{\npublic:\n    static bool Cast( U u, T& t ) SAFEINT_NOTHROW\n    {\n        if( u < 0 )\n            return false;\n\n        t = (T)u;\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW\n    {\n        if( u < 0 )\n            E::SafeIntOnOverflow();\n\n        t = (T)u;\n    }\n};\n\ntemplate < typename T, typename U > class SafeCastHelper < T, U, CastCheckGTMax >\n{\npublic:\n    static bool Cast( U u, T& t ) SAFEINT_NOTHROW\n    {\n        if( u > (U)IntTraits< T >::maxInt )\n            return false;\n\n        t = (T)u;\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW\n    {\n        if( u > (U)IntTraits< T >::maxInt )\n            E::SafeIntOnOverflow();\n\n        t = (T)u;\n    }\n};\n\ntemplate < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxUnsigned >\n{\npublic:\n    static bool Cast( U u, T& t ) SAFEINT_NOTHROW\n    {\n        // U is signed - T could be either signed or unsigned\n        if( u > IntTraits< T >::maxInt || u < 0 )\n            return false;\n\n        t = (T)u;\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW\n    {\n        // U is signed - T could be either signed or unsigned\n        if( u > IntTraits< T >::maxInt || u < 0 )\n            E::SafeIntOnOverflow();\n\n        t = (T)u;\n    }\n};\n\ntemplate < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxSigned >\n{\npublic:\n    static bool Cast( U u, T& t ) SAFEINT_NOTHROW\n    {\n        // T, U are signed\n        if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt )\n            return false;\n\n        t = (T)u;\n        return true;\n    }\n\n    template < typename E >\n    static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW\n    {\n        //T, U are signed\n        if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt )\n            E::SafeIntOnOverflow();\n\n        t = (T)u;\n    }\n};\n\n//core logic to determine whether a comparison is valid, or needs special treatment\nenum ComparisonMethod\n{\n    ComparisonMethod_Ok = 0,\n    ComparisonMethod_CastInt,\n    ComparisonMethod_CastInt64,\n    ComparisonMethod_UnsignedT,\n    ComparisonMethod_UnsignedU\n};\n\n    // Note - the standard is arguably broken in the case of some integer\n    // conversion operations\n    // For example, signed char a = -1 = 0xff\n    //              unsigned int b = 0xffffffff\n    // If you then test if a < b, a value-preserving cast\n    // is made, and you're essentially testing\n    // (unsigned int)a < b == false\n    //\n    // I do not think this makes sense - if you perform\n    // a cast to an __int64, which can clearly preserve both value and signedness\n    // then you get a different and intuitively correct answer\n    // IMHO, -1 should be less than 4 billion\n    // If you prefer to retain the ANSI standard behavior\n    // insert #define ANSI_CONVERSIONS into your source\n    // Behavior differences occur in the following cases:\n    // 8, 16, and 32-bit signed int, unsigned 32-bit int\n    // any signed int, unsigned 64-bit int\n    // Note - the signed int must be negative to show the problem\n\ntemplate < typename T, typename U >\nclass ValidComparison\n{\npublic:\n    enum\n    {\n#ifdef ANSI_CONVERSIONS\n        method = ComparisonMethod_Ok\n#else\n        method = ( ( SafeIntCompare< T, U >::isLikeSigned )                              ? ComparisonMethod_Ok :\n                 ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) ||\n                   ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) )  ? ComparisonMethod_CastInt :\n                 ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) ||\n                   ( IntTraits< U >::isSigned && sizeof(T) < 8 ) )                   ? ComparisonMethod_CastInt64 :\n                 ( !IntTraits< T >::isSigned )                                       ? ComparisonMethod_UnsignedT :\n                                                                                       ComparisonMethod_UnsignedU )\n#endif\n    };\n};\n\ntemplate <typename T, typename U, int state> class EqualityTest;\n\ntemplate < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >\n{\npublic:\n    static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( t == u ); }\n};\n\ntemplate < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >\n{\npublic:\n    static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t == (int)u ); }\n};\n\ntemplate < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >\n{\npublic:\n    static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t == (__int64)u ); }\n};\n\ntemplate < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >\n{\npublic:\n    static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW\n    {\n        //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller\n        if( u < 0 )\n            return false;\n\n        //else safe to cast to type T\n        return ( t == (T)u );\n    }\n};\n\ntemplate < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>\n{\npublic:\n    static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW\n    {\n        //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller\n        if( t < 0 )\n            return false;\n\n        //else safe to cast to type U\n        return ( (U)t == u );\n    }\n};\n\ntemplate <typename T, typename U, int state> class GreaterThanTest;\n\ntemplate < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >\n{\npublic:\n    static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( t > u ); }\n};\n\ntemplate < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >\n{\npublic:\n    static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t > (int)u ); }\n};\n\ntemplate < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >\n{\npublic:\n    static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t > (__int64)u ); }\n};\n\ntemplate < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >\n{\npublic:\n    static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW\n    {\n        // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller\n        if( u < 0 )\n            return true;\n\n        // else safe to cast to type T\n        return ( t > (T)u );\n    }\n};\n\ntemplate < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >\n{\npublic:\n    static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW\n    {\n        // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller\n        if( t < 0 )\n            return false;\n\n        // else safe to cast to type U\n        return ( (U)t > u );\n    }\n};\n\n// Modulus is simpler than comparison, but follows much the same logic\n// using this set of functions, it can't fail except in a div 0 situation\ntemplate <typename T, typename U, int method > class ModulusHelper;\n\ntemplate <typename T, typename U> class ModulusHelper <T, U, ComparisonMethod_Ok>\n{\npublic:\n    static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if(u == 0)\n            return SafeIntDivideByZero;\n\n        //trap corner case\n        if( CompileConst< IntTraits< U >::isSigned >::Value() )\n        {\n            // Some compilers don't notice that this only compiles when u is signed\n            // Add cast to make them happy\n            if( u == (U)-1 )\n            {\n                result = 0;\n                return SafeIntNoError;\n            }\n        }\n\n        result = (T)(t % u);\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if(u == 0)\n            E::SafeIntOnDivZero();\n\n        //trap corner case\n        if( CompileConst< IntTraits< U >::isSigned >::Value() )\n        {\n            if( u == (U)-1 )\n            {\n                result = 0;\n                return;\n            }\n        }\n\n        result = (T)(t % u);\n    }\n};\n\ntemplate <typename T, typename U> class ModulusHelper <T, U, ComparisonMethod_CastInt>\n{\npublic:\n    static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if(u == 0)\n            return SafeIntDivideByZero;\n\n        //trap corner case\n        if( CompileConst< IntTraits< U >::isSigned >::Value() )\n        {\n            if( u == (U)-1 )\n            {\n                result = 0;\n                return SafeIntNoError;\n            }\n        }\n\n        result = (T)(t % u);\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if(u == 0)\n            E::SafeIntOnDivZero();\n\n        //trap corner case\n        if( CompileConst< IntTraits< U >::isSigned >::Value() )\n        {\n            if( u == (U)-1 )\n            {\n                result = 0;\n                return;\n            }\n        }\n\n        result = (T)(t % u);\n    }\n};\n\ntemplate < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_CastInt64>\n{\npublic:\n    static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if(u == 0)\n            return SafeIntDivideByZero;\n\n        //trap corner case\n        if( CompileConst< IntTraits< U >::isSigned >::Value() )\n        {\n            if( u == (U)-1 )\n            {\n                result = 0;\n                return SafeIntNoError;\n            }\n        }\n\n        result = (T)((__int64)t % (__int64)u);\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if(u == 0)\n            E::SafeIntOnDivZero();\n\n        if( CompileConst< IntTraits< U >::isSigned >::Value() )\n        {\n            if( u == (U)-1 )\n            {\n                result = 0;\n                return;\n            }\n        }\n\n        result = (T)((__int64)t % (__int64)u);\n    }\n};\n\n// T is unsigned __int64, U is any signed int\ntemplate < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedT>\n{\npublic:\n    static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if(u == 0)\n            return SafeIntDivideByZero;\n\n        // u could be negative - if so, need to convert to positive\n        // casts below are always safe due to the way modulus works\n        if(u < 0)\n            result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs(u));\n        else\n            result = (T)(t % u);\n\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if(u == 0)\n            E::SafeIntOnDivZero();\n\n        // u could be negative - if so, need to convert to positive\n        if(u < 0)\n            result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ));\n        else\n            result = (T)(t % u);\n    }\n};\n\n// U is unsigned __int64, T any signed int\ntemplate < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedU>\n{\npublic:\n    static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if(u == 0)\n            return SafeIntDivideByZero;\n\n        //t could be negative - if so, need to convert to positive\n        if(t < 0)\n            result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1 );\n        else\n            result = (T)((T)t % u);\n\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if(u == 0)\n            E::SafeIntOnDivZero();\n\n        //t could be negative - if so, need to convert to positive\n        if(t < 0)\n            result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1);\n        else\n            result = (T)( (T)t % u );\n    }\n};\n\n//core logic to determine method to check multiplication\nenum MultiplicationState\n{\n    MultiplicationState_CastInt = 0,  // One or both signed, smaller than 32-bit\n    MultiplicationState_CastInt64,    // One or both signed, smaller than 64-bit\n    MultiplicationState_CastUint,     // Both are unsigned, smaller than 32-bit\n    MultiplicationState_CastUint64,   // Both are unsigned, both 32-bit or smaller\n    MultiplicationState_Uint64Uint,   // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller\n    MultiplicationState_Uint64Uint64, // Both are unsigned int64\n    MultiplicationState_Uint64Int,    // lhs is unsigned int64, rhs int32\n    MultiplicationState_Uint64Int64,  // lhs is unsigned int64, rhs signed int64\n    MultiplicationState_UintUint64,   // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit\n    MultiplicationState_UintInt64,    // lhs unsigned 32-bit or less, rhs int64\n    MultiplicationState_Int64Uint,    // lhs int64, rhs unsigned int32\n    MultiplicationState_Int64Int64,   // lhs int64, rhs int64\n    MultiplicationState_Int64Int,     // lhs int64, rhs int32\n    MultiplicationState_IntUint64,    // lhs int, rhs unsigned int64\n    MultiplicationState_IntInt64,     // lhs int, rhs int64\n    MultiplicationState_Int64Uint64,  // lhs int64, rhs uint64\n    MultiplicationState_Error\n};\n\ntemplate < typename T, typename U >\nclass MultiplicationMethod\n{\npublic:\n    enum\n    {\n                 // unsigned-unsigned\n        method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32  ? MultiplicationState_CastUint :\n                 (IntRegion< T,U >::IntZone_Uint32_UintLT64 ||\n                  IntRegion< T,U >::IntZone_UintLT32_Uint32)   ? MultiplicationState_CastUint64 :\n                  SafeIntCompare< T,U >::isBothUnsigned &&\n                  IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 :\n                 (IntRegion< T,U >::IntZone_Uint64_Uint)       ? MultiplicationState_Uint64Uint :\n                 (IntRegion< T,U >::IntZone_UintLT64_Uint64)   ? MultiplicationState_UintUint64 :\n                 // unsigned-signed\n                 (IntRegion< T,U >::IntZone_UintLT32_IntLT32)  ? MultiplicationState_CastInt :\n                 (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_UintLT32_Int32)    ? MultiplicationState_CastInt64 :\n                 (IntRegion< T,U >::IntZone_Uint64_Int)        ? MultiplicationState_Uint64Int :\n                 (IntRegion< T,U >::IntZone_UintLT64_Int64)    ? MultiplicationState_UintInt64 :\n                 (IntRegion< T,U >::IntZone_Uint64_Int64)      ? MultiplicationState_Uint64Int64 :\n                 // signed-signed\n                 (IntRegion< T,U >::IntZone_IntLT32_IntLT32)   ? MultiplicationState_CastInt :\n                 (IntRegion< T,U >::IntZone_Int32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_IntLT32_Int32)     ? MultiplicationState_CastInt64 :\n                 (IntRegion< T,U >::IntZone_Int64_Int64)       ? MultiplicationState_Int64Int64 :\n                 (IntRegion< T,U >::IntZone_Int64_Int)         ? MultiplicationState_Int64Int :\n                 (IntRegion< T,U >::IntZone_IntLT64_Int64)     ? MultiplicationState_IntInt64 :\n                 // signed-unsigned\n                 (IntRegion< T,U >::IntZone_IntLT32_UintLT32)  ? MultiplicationState_CastInt :\n                 (IntRegion< T,U >::IntZone_Int32_UintLT32 ||\n                  IntRegion< T,U >::IntZone_IntLT64_Uint32)    ? MultiplicationState_CastInt64 :\n                 (IntRegion< T,U >::IntZone_Int64_UintLT64)    ? MultiplicationState_Int64Uint :\n                 (IntRegion< T,U >::IntZone_Int_Uint64)        ? MultiplicationState_IntUint64 :\n                 (IntRegion< T,U >::IntZone_Int64_Uint64       ? MultiplicationState_Int64Uint64 :\n                  MultiplicationState_Error ) )\n    };\n};\n\ntemplate <typename T, typename U, int state> class MultiplicationHelper;\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt>\n{\npublic:\n    //accepts signed, both less than 32-bit\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        int tmp = t * u;\n\n        if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt )\n            return false;\n\n        ret = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        int tmp = t * u;\n\n        if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt )\n            E::SafeIntOnOverflow();\n\n        ret = (T)tmp;\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint >\n{\npublic:\n    //accepts unsigned, both less than 32-bit\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        unsigned int tmp = (unsigned int)(t * u);\n\n        if( tmp > IntTraits< T >::maxInt )\n            return false;\n\n        ret = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        unsigned int tmp = (unsigned int)( t * u );\n\n        if( tmp > IntTraits< T >::maxInt )\n            E::SafeIntOnOverflow();\n\n        ret = (T)tmp;\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt64>\n{\npublic:\n    //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        __int64 tmp = (__int64)t * (__int64)u;\n\n        if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt)\n            return false;\n\n        ret = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        __int64 tmp = (__int64)t * (__int64)u;\n\n        if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt)\n            E::SafeIntOnOverflow();\n\n        ret = (T)tmp;\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint64>\n{\npublic:\n    //both unsigned where at least one argument is 32-bit, and both are 32-bit or less\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;\n\n        if(tmp > (unsigned __int64)IntTraits< T >::maxInt)\n            return false;\n\n        ret = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;\n\n        if(tmp > (unsigned __int64)IntTraits< T >::maxInt)\n            E::SafeIntOnOverflow();\n\n        ret = (T)tmp;\n    }\n};\n\n// T = left arg and return type\n// U = right arg\ntemplate < typename T, typename U > class LargeIntRegMultiply;\n\n#if SAFEINT_USE_INTRINSICS\n// As usual, unsigned is easy\ninline bool IntrinsicMultiplyUint64( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW\n{\n    unsigned __int64 ulHigh = 0;\n    *pRet = _umul128(a , b, &ulHigh);\n    return ulHigh == 0;\n}\n\n// Signed, is not so easy\ninline bool IntrinsicMultiplyInt64( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW\n{\n    __int64 llHigh = 0;\n    *pRet = _mul128(a , b, &llHigh);\n\n    // Now we need to figure out what we expect\n    // If llHigh is 0, then treat *pRet as unsigned\n    // If llHigh is < 0, then treat *pRet as signed\n\n    if( (a ^ b) < 0 )\n    {\n        // Negative result expected\n        if( llHigh == -1 && *pRet < 0 ||\n            llHigh == 0 && *pRet == 0 )\n        {\n            // Everything is within range\n            return true;\n        }\n    }\n    else\n    {\n        // Result should be positive\n        // Check for overflow\n        if( llHigh == 0 && (unsigned __int64)*pRet <= IntTraits< signed __int64 >::maxInt )\n            return true;\n    }\n    return false;\n}\n\n#endif\n\ntemplate<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 >\n{\npublic:\n    static bool RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyUint64( a, b, pRet );\n#else\n        unsigned __int32 aHigh, aLow, bHigh, bLow;\n\n        // Consider that a*b can be broken up into:\n        // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)\n        // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)\n        // Note - same approach applies for 128 bit math on a 64-bit system\n\n        aHigh = (unsigned __int32)(a >> 32);\n        aLow  = (unsigned __int32)a;\n        bHigh = (unsigned __int32)(b >> 32);\n        bLow  = (unsigned __int32)b;\n\n        *pRet = 0;\n\n        if(aHigh == 0)\n        {\n            if(bHigh != 0)\n            {\n                *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh;\n            }\n        }\n        else if(bHigh == 0)\n        {\n            if(aHigh != 0)\n            {\n                *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow;\n            }\n        }\n        else\n        {\n            return false;\n        }\n\n        if(*pRet != 0)\n        {\n            unsigned __int64 tmp;\n\n            if((unsigned __int32)(*pRet >> 32) != 0)\n                return false;\n\n            *pRet <<= 32;\n            tmp = (unsigned __int64)aLow * (unsigned __int64)bLow;\n            *pRet += tmp;\n\n            if(*pRet < tmp)\n                return false;\n\n            return true;\n        }\n\n        *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow;\n        return true;\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_CPP_THROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyUint64( a, b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        unsigned __int32 aHigh, aLow, bHigh, bLow;\n\n        // Consider that a*b can be broken up into:\n        // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)\n        // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)\n        // Note - same approach applies for 128 bit math on a 64-bit system\n\n        aHigh = (unsigned __int32)(a >> 32);\n        aLow  = (unsigned __int32)a;\n        bHigh = (unsigned __int32)(b >> 32);\n        bLow  = (unsigned __int32)b;\n\n        *pRet = 0;\n\n        if(aHigh == 0)\n        {\n            if(bHigh != 0)\n            {\n                *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh;\n            }\n        }\n        else if(bHigh == 0)\n        {\n            if(aHigh != 0)\n            {\n                *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow;\n            }\n        }\n        else\n        {\n            E::SafeIntOnOverflow();\n        }\n\n        if(*pRet != 0)\n        {\n            unsigned __int64 tmp;\n\n            if((unsigned __int32)(*pRet >> 32) != 0)\n                E::SafeIntOnOverflow();\n\n            *pRet <<= 32;\n            tmp = (unsigned __int64)aLow * (unsigned __int64)bLow;\n            *pRet += tmp;\n\n            if(*pRet < tmp)\n                E::SafeIntOnOverflow();\n\n            return;\n        }\n\n        *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow;\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 >\n{\npublic:\n    static bool RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet );\n#else\n        unsigned __int32 aHigh, aLow;\n\n        // Consider that a*b can be broken up into:\n        // (aHigh * 2^32 + aLow) * b\n        // => (aHigh * b * 2^32) + (aLow * b)\n\n        aHigh = (unsigned __int32)(a >> 32);\n        aLow  = (unsigned __int32)a;\n\n        *pRet = 0;\n\n        if(aHigh != 0)\n        {\n            *pRet = (unsigned __int64)aHigh * (unsigned __int64)b;\n\n            unsigned __int64 tmp;\n\n            if((unsigned __int32)(*pRet >> 32) != 0)\n                return false;\n\n            *pRet <<= 32;\n            tmp = (unsigned __int64)aLow * (unsigned __int64)b;\n            *pRet += tmp;\n\n            if(*pRet < tmp)\n                return false;\n\n            return true;\n        }\n\n        *pRet = (unsigned __int64)aLow * (unsigned __int64)b;\n        return true;\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        unsigned __int32 aHigh, aLow;\n\n        // Consider that a*b can be broken up into:\n        // (aHigh * 2^32 + aLow) * b\n        // => (aHigh * b * 2^32) + (aLow * b)\n\n        aHigh = (unsigned __int32)(a >> 32);\n        aLow  = (unsigned __int32)a;\n\n        *pRet = 0;\n\n        if(aHigh != 0)\n        {\n            *pRet = (unsigned __int64)aHigh * (unsigned __int64)b;\n\n            unsigned __int64 tmp;\n\n            if((unsigned __int32)(*pRet >> 32) != 0)\n                E::SafeIntOnOverflow();\n\n            *pRet <<= 32;\n            tmp = (unsigned __int64)aLow * (unsigned __int64)b;\n            *pRet += tmp;\n\n            if(*pRet < tmp)\n                E::SafeIntOnOverflow();\n\n            return;\n        }\n\n        *pRet = (unsigned __int64)aLow * (unsigned __int64)b;\n        return;\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< unsigned __int64, signed __int32 >\n{\npublic:\n    // Intrinsic not needed\n    static bool RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW\n    {\n        if( b < 0 && a != 0 )\n            return false;\n\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet );\n#else\n        return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply(a, (unsigned __int32)b, pRet);\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW\n    {\n        if( b < 0 && a != 0 )\n            E::SafeIntOnOverflow();\n\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( a, (unsigned __int32)b, pRet );\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< unsigned __int64, signed __int64 >\n{\npublic:\n    static bool RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_NOTHROW\n    {\n        if( b < 0 && a != 0 )\n            return false;\n\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet );\n#else\n        return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply(a, (unsigned __int64)b, pRet);\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW\n    {\n        if( b < 0 && a != 0 )\n            E::SafeIntOnOverflow();\n\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet );\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< signed __int32, unsigned __int64 >\n{\npublic:\n    // Devolves into ordinary 64-bit calculation\n    static bool RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW\n    {\n        unsigned __int32 bHigh, bLow;\n        bool fIsNegative = false;\n\n        // Consider that a*b can be broken up into:\n        // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)\n        // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)\n        // aHigh == 0 implies:\n        // ( aLow * bHigh * 2^32 ) + ( aLow + bLow )\n        // If the first part is != 0, fail\n\n        bHigh = (unsigned __int32)(b >> 32);\n        bLow  = (unsigned __int32)b;\n\n        *pRet = 0;\n\n        if(bHigh != 0 && a != 0)\n            return false;\n\n        if( a < 0 )\n        {\n\n            a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);\n            fIsNegative = true;\n        }\n\n        unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;\n\n        if( !fIsNegative )\n        {\n            if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt )\n            {\n                *pRet = (signed __int32)tmp;\n                return true;\n            }\n        }\n        else\n        {\n            if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 )\n            {\n                *pRet = SignedNegation< signed __int32 >::Value( tmp );\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW\n    {\n        unsigned __int32 bHigh, bLow;\n        bool fIsNegative = false;\n\n        // Consider that a*b can be broken up into:\n        // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)\n        // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)\n\n        bHigh = (unsigned __int32)(b >> 32);\n        bLow  = (unsigned __int32)b;\n\n        *pRet = 0;\n\n        if(bHigh != 0 && a != 0)\n            E::SafeIntOnOverflow();\n\n        if( a < 0 )\n        {\n            a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);\n            fIsNegative = true;\n        }\n\n        unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;\n\n        if( !fIsNegative )\n        {\n            if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt )\n            {\n                *pRet = (signed __int32)tmp;\n                return;\n            }\n        }\n        else\n        {\n            if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 )\n            {\n                *pRet = SignedNegation< signed __int32 >::Value( tmp );\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< unsigned __int32, unsigned __int64 >\n{\npublic:\n    // Becomes ordinary 64-bit multiplication, intrinsic not needed\n    static bool RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW\n    {\n        // Consider that a*b can be broken up into:\n        // (bHigh * 2^32 + bLow) * a\n        // => (bHigh * a * 2^32) + (bLow * a)\n        // In this case, the result must fit into 32-bits\n        // If bHigh != 0 && a != 0, immediate error.\n\n        if( (unsigned __int32)(b >> 32) != 0 && a != 0 )\n            return false;\n\n        unsigned __int64 tmp = b * (unsigned __int64)a;\n\n        if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow\n            return false;\n\n        *pRet = (unsigned __int32)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW\n    {\n        if( (unsigned __int32)(b >> 32) != 0 && a != 0 )\n            E::SafeIntOnOverflow();\n\n        unsigned __int64 tmp = b * (unsigned __int64)a;\n\n        if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow\n            E::SafeIntOnOverflow();\n\n        *pRet = (unsigned __int32)tmp;\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< unsigned __int32, signed __int64 >\n{\npublic:\n    static bool RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW\n    {\n        if( b < 0 && a != 0 )\n            return false;\n        return LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( a, (unsigned __int64)b, pRet );\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW\n    {\n        if( b < 0 && a != 0 )\n            E::SafeIntOnOverflow();\n\n        LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet );\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< signed __int64, signed __int64 >\n{\npublic:\n    static bool RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyInt64( a, b, pRet );\n#else\n        bool aNegative = false;\n        bool bNegative = false;\n\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n        __int64 b1 = b;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        if( b1 < 0 )\n        {\n            bNegative = true;\n            b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);\n        }\n\n        if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ) )\n        {\n            // The unsigned multiplication didn't overflow\n            if( aNegative ^ bNegative )\n            {\n                // Result must be negative\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n                {\n                    *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                    return true;\n                }\n            }\n            else\n            {\n                // Result must be positive\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n                {\n                    *pRet = (signed __int64)tmp;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyInt64( a, b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        bool aNegative = false;\n        bool bNegative = false;\n\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n        __int64 b1 = b;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        if( b1 < 0 )\n        {\n            bNegative = true;\n            b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);\n        }\n\n        LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, (unsigned __int64)b1, &tmp );\n\n        // The unsigned multiplication didn't overflow or we'd be in the exception handler\n        if( aNegative ^ bNegative )\n        {\n            // Result must be negative\n            if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n            {\n                *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                return;\n            }\n        }\n        else\n        {\n            // Result must be positive\n            if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n            {\n                *pRet = (signed __int64)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< signed __int64, unsigned __int32 >\n{\npublic:\n    static bool RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet );\n#else\n        bool aNegative = false;\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, b, &tmp ) )\n        {\n            // The unsigned multiplication didn't overflow\n            if( aNegative )\n            {\n                // Result must be negative\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n                {\n                    *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                    return true;\n                }\n            }\n            else\n            {\n                // Result must be positive\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n                {\n                    *pRet = (signed __int64)tmp;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        bool aNegative = false;\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, b, &tmp );\n\n        // The unsigned multiplication didn't overflow\n        if( aNegative )\n        {\n            // Result must be negative\n            if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n            {\n                *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                return;\n            }\n        }\n        else\n        {\n            // Result must be positive\n            if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n            {\n                *pRet = (signed __int64)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< signed __int64, signed __int32 >\n{\npublic:\n    static bool RegMultiply( const signed __int64& a, signed __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet );\n#else\n        bool aNegative = false;\n        bool bNegative = false;\n\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n        __int64 b1 = b;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        if( b1 < 0 )\n        {\n            bNegative = true;\n            b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);\n        }\n\n        if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, &tmp ) )\n        {\n            // The unsigned multiplication didn't overflow\n            if( aNegative ^ bNegative )\n            {\n                // Result must be negative\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n                {\n                    *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                    return true;\n                }\n            }\n            else\n            {\n                // Result must be positive\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n                {\n                    *pRet = (signed __int64)tmp;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( signed __int64 a, signed __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) )\n            E::SafeIntOnOverflow();\n#else\n        bool aNegative = false;\n        bool bNegative = false;\n\n        unsigned __int64 tmp;\n\n        if( a < 0 )\n        {\n            aNegative = true;\n            a = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a);\n        }\n\n        if( b < 0 )\n        {\n            bNegative = true;\n            b = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(b);\n        }\n\n        LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a, (unsigned __int32)b, &tmp );\n\n        // The unsigned multiplication didn't overflow\n        if( aNegative ^ bNegative )\n        {\n            // Result must be negative\n            if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n            {\n                *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                return;\n            }\n        }\n        else\n        {\n            // Result must be positive\n            if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n            {\n                *pRet = (signed __int64)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< signed __int32, signed __int64 >\n{\npublic:\n    static bool RegMultiply( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        __int64 tmp;\n\n        if( IntrinsicMultiplyInt64( a, b, &tmp ) )\n        {\n            if( tmp > IntTraits< signed __int32 >::maxInt ||\n                tmp < IntTraits< signed __int32 >::minInt )\n            {\n                return false;\n            }\n\n            *pRet = (__int32)tmp;\n            return true;\n        }\n        return false;\n#else\n        bool aNegative = false;\n        bool bNegative = false;\n\n        unsigned __int32 tmp;\n        __int64 b1 = b;\n\n        if( a < 0 )\n        {\n            aNegative = true;\n            a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);\n        }\n\n        if( b1 < 0 )\n        {\n            bNegative = true;\n            b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);\n        }\n\n        if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, &tmp ) )\n        {\n            // The unsigned multiplication didn't overflow\n            if( aNegative ^ bNegative )\n            {\n                // Result must be negative\n                if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt )\n                {\n                    *pRet = SignedNegation< signed __int32 >::Value( tmp );\n                    return true;\n                }\n            }\n            else\n            {\n                // Result must be positive\n                if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt )\n                {\n                    *pRet = (signed __int32)tmp;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n#endif\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW\n    {\n#if SAFEINT_USE_INTRINSICS\n        __int64 tmp;\n\n        if( IntrinsicMultiplyInt64( a, b, &tmp ) )\n        {\n            if( tmp > IntTraits< signed __int32 >::maxInt ||\n                tmp < IntTraits< signed __int32 >::minInt )\n            {\n                E::SafeIntOnOverflow();\n            }\n\n            *pRet = (__int32)tmp;\n            return;\n        }\n        E::SafeIntOnOverflow();\n#else\n        bool aNegative = false;\n        bool bNegative = false;\n\n        unsigned __int32 tmp;\n        signed __int64 b2 = b;\n\n        if( a < 0 )\n        {\n            aNegative = true;\n            a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);\n        }\n\n        if( b < 0 )\n        {\n            bNegative = true;\n            b2 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b2);\n        }\n\n        LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)a, (unsigned __int64)b2, &tmp );\n\n        // The unsigned multiplication didn't overflow\n        if( aNegative ^ bNegative )\n        {\n            // Result must be negative\n            if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt )\n            {\n                *pRet = SignedNegation< signed __int32 >::Value( tmp );\n                return;\n            }\n        }\n        else\n        {\n            // Result must be positive\n            if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt )\n            {\n                *pRet = (signed __int32)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n#endif\n    }\n};\n\ntemplate<> class LargeIntRegMultiply< signed __int64, unsigned __int64 >\n{\npublic:\n    // Leave this one as-is - will call unsigned intrinsic internally\n    static bool RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW\n    {\n        bool aNegative = false;\n\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) )\n        {\n            // The unsigned multiplication didn't overflow\n            if( aNegative )\n            {\n                // Result must be negative\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n                {\n                    *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                    return true;\n                }\n            }\n            else\n            {\n                // Result must be positive\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n                {\n                    *pRet = (signed __int64)tmp;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void RegMultiplyThrow( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW\n    {\n        bool aNegative = false;\n        unsigned __int64 tmp;\n        __int64 a1 = a;\n\n        if( a1 < 0 )\n        {\n            aNegative = true;\n            a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);\n        }\n\n        if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) )\n        {\n            // The unsigned multiplication didn't overflow\n            if( aNegative )\n            {\n                // Result must be negative\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )\n                {\n                    *pRet = SignedNegation< signed __int64 >::Value( tmp );\n                    return;\n                }\n            }\n            else\n            {\n                // Result must be positive\n                if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )\n                {\n                    *pRet = (signed __int64)tmp;\n                    return;\n                }\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\n// In all of the following functions where LargeIntRegMultiply methods are called,\n// we need to properly transition types. The methods need __int64, __int32, etc.\n// but the variables being passed to us could be long long, long int, or long, depending on\n// the compiler. Microsoft compiler knows that long long is the same type as __int64, but gcc doesn't\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint64 >\n{\npublic:\n    // T, U are unsigned __int64\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 && IntTraits<U>::isUint64 );\n        unsigned __int64 t1 = t;\n        unsigned __int64 u1 = u;\n        return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast<unsigned __int64*>(&ret) );\n    }\n\n    template < typename E >\n    static void MultiplyThrow(const unsigned __int64& t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 && IntTraits<U>::isUint64 );\n        unsigned __int64 t1 = t;\n        unsigned __int64 u1 = u;\n        LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast<unsigned __int64*>(&ret) );\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint >\n{\npublic:\n    // T is unsigned __int64\n    // U is any unsigned int 32-bit or less\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 );\n        unsigned __int64 t1 = t;\n        return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast<unsigned __int64*>(&ret) );\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 );\n        unsigned __int64 t1 = t;\n        LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast<unsigned __int64*>(&ret) );\n    }\n};\n\n// converse of the previous function\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintUint64 >\n{\npublic:\n    // T is any unsigned int up to 32-bit\n    // U is unsigned __int64\n    static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<U>::isUint64 );\n        unsigned __int64 u1 = u;\n        unsigned __int32 tmp;\n\n        if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( t, u1, &tmp ) &&\n            SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) )\n        {\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<U>::isUint64 );\n        unsigned __int64 u1 = u;\n        unsigned __int32 tmp;\n\n        LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( t, u1, &tmp );\n        SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret);\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int >\n{\npublic:\n    // T is unsigned __int64\n    // U is any signed int, up to 64-bit\n    static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 );\n        unsigned __int64 t1 = t;\n        return LargeIntRegMultiply< unsigned __int64, signed __int32 >::RegMultiply(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret));\n    }\n\n    template < typename E >\n    static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 );\n        unsigned __int64 t1 = t;\n        LargeIntRegMultiply< unsigned __int64, signed __int32 >::template RegMultiplyThrow< E >(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret));\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int64 >\n{\npublic:\n    // T is unsigned __int64\n    // U is __int64\n    static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 && IntTraits<U>::isInt64 );\n        unsigned __int64 t1 = t;\n        __int64          u1 = u;\n        return LargeIntRegMultiply< unsigned __int64, __int64 >::RegMultiply(t1, u1, reinterpret_cast< unsigned __int64* >(&ret));\n    }\n\n    template < typename E >\n    static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isUint64 && IntTraits<U>::isInt64 );\n        unsigned __int64 t1 = t;\n        __int64          u1 = u;\n        LargeIntRegMultiply< unsigned __int64, __int64 >::template RegMultiplyThrow< E >(t1, u1, reinterpret_cast< unsigned __int64* >(&ret));\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintInt64 >\n{\npublic:\n    // T is unsigned up to 32-bit\n    // U is __int64\n    static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<U>::isInt64 );\n        __int64          u1 = u;\n        unsigned __int32 tmp;\n\n        if( LargeIntRegMultiply< unsigned __int32, __int64 >::RegMultiply( (unsigned __int32)t, u1, &tmp ) &&\n            SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) )\n        {\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<U>::isInt64 );\n        __int64          u1 = u;\n        unsigned __int32 tmp;\n\n        LargeIntRegMultiply< unsigned __int32, __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)t, u1, &tmp );\n        SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret);\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint >\n{\npublic:\n    // T is __int64\n    // U is unsigned up to 32-bit\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 );\n        __int64          t1 = t;\n        return LargeIntRegMultiply< __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) );\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 );\n        __int64          t1 = t;\n        LargeIntRegMultiply< __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) );\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int64 >\n{\npublic:\n    // T, U are __int64\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 && IntTraits<U>::isInt64 );\n        __int64          t1 = t;\n        __int64          u1 = u;\n        return LargeIntRegMultiply< __int64, __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) );\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 && IntTraits<U>::isInt64 );\n        __int64          t1 = t;\n        __int64          u1 = u;\n        LargeIntRegMultiply< __int64, __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret));\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int >\n{\npublic:\n    // T is __int64\n    // U is signed up to 32-bit\n    static bool Multiply( const T& t, U u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 );\n        __int64          t1 = t;\n        return LargeIntRegMultiply< __int64, __int32 >::RegMultiply( t1, (__int32)u, reinterpret_cast< __int64* >(&ret));\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const __int64& t, U u, T& ret ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 );\n        __int64          t1 = t;\n        LargeIntRegMultiply< __int64, __int32 >::template RegMultiplyThrow< E >(t1, (__int32)u, reinterpret_cast< __int64* >(&ret));\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntUint64 >\n{\npublic:\n    // T is signed up to 32-bit\n    // U is unsigned __int64\n    static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<U>::isUint64 );\n        unsigned __int64 u1 = u;\n        __int32 tmp;\n\n        if( LargeIntRegMultiply< __int32, unsigned __int64 >::RegMultiply( (__int32)t, u1, &tmp ) &&\n            SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) )\n        {\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void MultiplyThrow(T t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<U>::isUint64 );\n        unsigned __int64 u1 = u;\n        __int32 tmp;\n\n        LargeIntRegMultiply< __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp );\n        SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret );\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint64>\n{\npublic:\n    // T is __int64\n    // U is unsigned __int64\n    static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 && IntTraits<U>::isUint64 );\n        __int64          t1 = t;\n        unsigned __int64 u1 = u;\n        return LargeIntRegMultiply< __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) );\n    }\n\n    template < typename E >\n    static void MultiplyThrow( const __int64& t, const unsigned __int64& u, T& ret ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<T>::isInt64 && IntTraits<U>::isUint64 );\n        __int64          t1 = t;\n        unsigned __int64 u1 = u;\n        LargeIntRegMultiply< __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret) );\n    }\n};\n\ntemplate < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntInt64>\n{\npublic:\n    // T is signed, up to 32-bit\n    // U is __int64\n    static bool Multiply( T t, const U& u, T& ret ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits<U>::isInt64 );\n        __int64 u1 = u;\n        __int32 tmp;\n\n        if( LargeIntRegMultiply< __int32, __int64 >::RegMultiply( (__int32)t, u1, &tmp ) &&\n            SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) )\n        {\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void MultiplyThrow(T t, const U& u, T& ret) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits<U>::isInt64 );\n        __int64 u1 = u;\n        __int32 tmp;\n\n        LargeIntRegMultiply< __int32, __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp );\n        SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret );\n    }\n};\n\nenum DivisionState\n{\n    DivisionState_OK,\n    DivisionState_UnsignedSigned,\n    DivisionState_SignedUnsigned32,\n    DivisionState_SignedUnsigned64,\n    DivisionState_SignedUnsigned,\n    DivisionState_SignedSigned\n};\n\ntemplate < typename T, typename U > class DivisionMethod\n{\npublic:\n    enum\n    {\n        method = (SafeIntCompare< T, U >::isBothUnsigned                     ? DivisionState_OK :\n                 (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned :\n                 (IntTraits< T >::isSigned &&\n                    IntTraits< U >::isUint32 &&\n                    IntTraits< T >::isLT64Bit)                           ? DivisionState_SignedUnsigned32 :\n                 (IntTraits< T >::isSigned && IntTraits< U >::isUint64)  ? DivisionState_SignedUnsigned64 :\n                 (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned :\n                                                                           DivisionState_SignedSigned)\n    };\n};\n\ntemplate < typename T, typename U, int state > class DivisionHelper;\n\ntemplate < typename T, typename U > class DivisionHelper< T, U, DivisionState_OK >\n{\npublic:\n    static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if( u == 0 )\n            return SafeIntDivideByZero;\n\n        if( t == 0 )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        result = (T)( t/u );\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if( u == 0 )\n            E::SafeIntOnDivZero();\n\n        if( t == 0 )\n        {\n            result = 0;\n            return;\n        }\n\n        result = (T)( t/u );\n    }\n};\n\ntemplate < typename T, typename U > class DivisionHelper< T, U, DivisionState_UnsignedSigned>\n{\npublic:\n    static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n\n        if( u == 0 )\n            return SafeIntDivideByZero;\n\n        if( t == 0 )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        if( u > 0 )\n        {\n            result = (T)( t/u );\n            return SafeIntNoError;\n        }\n\n        // it is always an error to try and divide an unsigned number by a negative signed number\n        // unless u is bigger than t\n        if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        return SafeIntArithmeticOverflow;\n    }\n\n    template < typename E >\n    static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n\n        if( u == 0 )\n            E::SafeIntOnDivZero();\n\n        if( t == 0 )\n        {\n            result = 0;\n            return;\n        }\n\n        if( u > 0 )\n        {\n            result = (T)( t/u );\n            return;\n        }\n\n        // it is always an error to try and divide an unsigned number by a negative signed number\n        // unless u is bigger than t\n        if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t )\n        {\n            result = 0;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned32 >\n{\npublic:\n    static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if( u == 0 )\n            return SafeIntDivideByZero;\n\n        if( t == 0 )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        // Test for t > 0\n        // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors\n        // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional\n\n        if( t > 0 )\n            result = (T)( t/u );\n        else\n            result = (T)( (__int64)t/(__int64)u );\n\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if( u == 0 )\n        {\n            E::SafeIntOnDivZero();\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return;\n        }\n\n        // Test for t > 0\n        // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors\n        // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional\n\n        if( t > 0 )\n            result = (T)( t/u );\n        else\n            result = (T)( (__int64)t/(__int64)u );\n    }\n};\n\ntemplate < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned64 >\n{\npublic:\n    static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits< U >::isUint64 );\n\n        if( u == 0 )\n        {\n            return SafeIntDivideByZero;\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        if( u <= (unsigned __int64)IntTraits< T >::maxInt )\n        {\n            // Else u can safely be cast to T\n            if( CompileConst< sizeof( T ) < sizeof( __int64 )>::Value() )\n                result = (T)( (int)t/(int)u );\n            else\n                result = (T)((__int64)t/(__int64)u);\n        }\n        else // Corner case\n        if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt )\n        {\n            // Min int divided by it's own magnitude is -1\n            result = -1;\n        }\n        else\n        {\n            result = 0;\n        }\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void DivideThrow( const T& t, const unsigned __int64& u, T& result ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits< U >::isUint64 );\n\n        if( u == 0 )\n        {\n            E::SafeIntOnDivZero();\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return;\n        }\n\n        if( u <= (unsigned __int64)IntTraits< T >::maxInt )\n        {\n            // Else u can safely be cast to T\n            if( CompileConst< sizeof( T ) < sizeof( __int64 ) >::Value() )\n                result = (T)( (int)t/(int)u );\n            else\n                result = (T)((__int64)t/(__int64)u);\n        }\n        else // Corner case\n        if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt )\n        {\n            // Min int divided by it's own magnitude is -1\n            result = -1;\n        }\n        else\n        {\n            result = 0;\n        }\n    }\n};\n\ntemplate < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned>\n{\npublic:\n    // T is any signed, U is unsigned and smaller than 32-bit\n    // In this case, standard operator casting is correct\n    static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if( u == 0 )\n        {\n            return SafeIntDivideByZero;\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        result = (T)( t/u );\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if( u == 0 )\n        {\n            E::SafeIntOnDivZero();\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return;\n        }\n\n        result = (T)( t/u );\n    }\n};\n\ntemplate < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedSigned>\n{\npublic:\n    static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n    {\n        if( u == 0 )\n        {\n            return SafeIntDivideByZero;\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return SafeIntNoError;\n        }\n\n        // Must test for corner case\n        if( t == IntTraits< T >::minInt && u == (U)-1 )\n            return SafeIntArithmeticOverflow;\n\n        result = (T)( t/u );\n        return SafeIntNoError;\n    }\n\n    template < typename E >\n    static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW\n    {\n        if(u == 0)\n        {\n            E::SafeIntOnDivZero();\n        }\n\n        if( t == 0 )\n        {\n            result = 0;\n            return;\n        }\n\n        // Must test for corner case\n        if( t == IntTraits< T >::minInt && u == (U)-1 )\n            E::SafeIntOnOverflow();\n\n        result = (T)( t/u );\n    }\n};\n\nenum AdditionState\n{\n    AdditionState_CastIntCheckMax,\n    AdditionState_CastUintCheckOverflow,\n    AdditionState_CastUintCheckOverflowMax,\n    AdditionState_CastUint64CheckOverflow,\n    AdditionState_CastUint64CheckOverflowMax,\n    AdditionState_CastIntCheckSafeIntMinMax,\n    AdditionState_CastInt64CheckSafeIntMinMax,\n    AdditionState_CastInt64CheckMax,\n    AdditionState_CastUint64CheckSafeIntMinMax,\n    AdditionState_CastUint64CheckSafeIntMinMax2,\n    AdditionState_CastInt64CheckOverflow,\n    AdditionState_CastInt64CheckOverflowSafeIntMinMax,\n    AdditionState_CastInt64CheckOverflowMax,\n    AdditionState_ManualCheckInt64Uint64,\n    AdditionState_ManualCheck,\n    AdditionState_Error\n};\n\ntemplate< typename T, typename U >\nclass AdditionMethod\n{\npublic:\n    enum\n    {\n                 //unsigned-unsigned\n        method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32  ? AdditionState_CastIntCheckMax :\n                 (IntRegion< T,U >::IntZone_Uint32_UintLT64)   ? AdditionState_CastUintCheckOverflow :\n                 (IntRegion< T,U >::IntZone_UintLT32_Uint32)   ? AdditionState_CastUintCheckOverflowMax :\n                 (IntRegion< T,U >::IntZone_Uint64_Uint)       ? AdditionState_CastUint64CheckOverflow :\n                 (IntRegion< T,U >::IntZone_UintLT64_Uint64)   ? AdditionState_CastUint64CheckOverflowMax :\n                 //unsigned-signed\n                 (IntRegion< T,U >::IntZone_UintLT32_IntLT32)  ? AdditionState_CastIntCheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_UintLT32_Int32)    ? AdditionState_CastInt64CheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Uint64_Int ||\n                  IntRegion< T,U >::IntZone_Uint64_Int64)      ? AdditionState_CastUint64CheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_UintLT64_Int64)    ? AdditionState_CastUint64CheckSafeIntMinMax2 :\n                 //signed-signed\n                 (IntRegion< T,U >::IntZone_IntLT32_IntLT32)   ? AdditionState_CastIntCheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Int32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_IntLT32_Int32)     ? AdditionState_CastInt64CheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Int64_Int ||\n                  IntRegion< T,U >::IntZone_Int64_Int64)       ? AdditionState_CastInt64CheckOverflow :\n                 (IntRegion< T,U >::IntZone_IntLT64_Int64)     ? AdditionState_CastInt64CheckOverflowSafeIntMinMax :\n                 //signed-unsigned\n                 (IntRegion< T,U >::IntZone_IntLT32_UintLT32)  ? AdditionState_CastIntCheckMax :\n                 (IntRegion< T,U >::IntZone_Int32_UintLT32 ||\n                  IntRegion< T,U >::IntZone_IntLT64_Uint32)    ? AdditionState_CastInt64CheckMax :\n                 (IntRegion< T,U >::IntZone_Int64_UintLT64)    ? AdditionState_CastInt64CheckOverflowMax :\n                 (IntRegion< T,U >::IntZone_Int64_Uint64)      ? AdditionState_ManualCheckInt64Uint64 :\n                 (IntRegion< T,U >::IntZone_Int_Uint64)        ? AdditionState_ManualCheck :\n                  AdditionState_Error)\n    };\n};\n\ntemplate < typename T, typename U, int method > class AdditionHelper;\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckMax >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        //16-bit or less unsigned addition\n        __int32 tmp = lhs + rhs;\n\n        if( tmp <= (__int32)IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        //16-bit or less unsigned addition\n        __int32 tmp = lhs + rhs;\n\n        if( tmp <= (__int32)IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflow >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // 32-bit or less - both are unsigned\n        unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;\n\n        //we added didn't get smaller\n        if( tmp >= lhs )\n        {\n            result = (T)tmp;\n            return true;\n        }\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // 32-bit or less - both are unsigned\n        unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;\n\n        //we added didn't get smaller\n        if( tmp >= lhs )\n        {\n            result = (T)tmp;\n            return;\n        }\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflowMax>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // 32-bit or less - both are unsigned\n        unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;\n\n        // We added and it didn't get smaller or exceed maxInt\n        if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        //32-bit or less - both are unsigned\n        unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;\n\n        // We added and it didn't get smaller or exceed maxInt\n        if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflow>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs unsigned __int64, rhs unsigned\n        unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n        // We added and it didn't get smaller\n        if(tmp >= lhs)\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs unsigned __int64, rhs unsigned\n        unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n        // We added and it didn't get smaller\n        if(tmp >= lhs)\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflowMax >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        //lhs unsigned __int64, rhs unsigned\n        unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n        // We added and it didn't get smaller\n        if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        //lhs unsigned __int64, rhs unsigned\n        unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n        // We added and it didn't get smaller\n        if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckSafeIntMinMax >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // 16-bit or less - one or both are signed\n        __int32 tmp = lhs + rhs;\n\n        if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // 16-bit or less - one or both are signed\n        __int32 tmp = lhs + rhs;\n\n        if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckSafeIntMinMax >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // 32-bit or less - one or both are signed\n        __int64 tmp = (__int64)lhs + (__int64)rhs;\n\n        if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // 32-bit or less - one or both are signed\n        __int64 tmp = (__int64)lhs + (__int64)rhs;\n\n        if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckMax >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // 32-bit or less - lhs signed, rhs unsigned\n        __int64 tmp = (__int64)lhs + (__int64)rhs;\n\n        if( tmp <= IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // 32-bit or less - lhs signed, rhs unsigned\n        __int64 tmp = (__int64)lhs + (__int64)rhs;\n\n        if( tmp <= IntTraits< T >::maxInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax >\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is unsigned __int64, rhs signed\n        unsigned __int64 tmp;\n\n        if( rhs < 0 )\n        {\n            // So we're effectively subtracting\n            tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );\n\n            if( tmp <= lhs )\n            {\n                result = lhs - tmp;\n                return true;\n            }\n        }\n        else\n        {\n            // now we know that rhs can be safely cast into an unsigned __int64\n            tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n            // We added and it did not become smaller\n            if( tmp >= lhs )\n            {\n                result = (T)tmp;\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is unsigned __int64, rhs signed\n        unsigned __int64 tmp;\n\n        if( rhs < 0 )\n        {\n            // So we're effectively subtracting\n            tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );\n\n            if( tmp <= lhs )\n            {\n                result = lhs - tmp;\n                return;\n            }\n        }\n        else\n        {\n            // now we know that rhs can be safely cast into an unsigned __int64\n            tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n            // We added and it did not become smaller\n            if( tmp >= lhs )\n            {\n                result = (T)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax2>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is unsigned and < 64-bit, rhs signed __int64\n        if( rhs < 0 )\n        {\n            if( lhs >= ~(unsigned __int64)( rhs ) + 1 )//negation is safe, since rhs is 64-bit\n            {\n                result = (T)( lhs + rhs );\n                return true;\n            }\n        }\n        else\n        {\n            // now we know that rhs can be safely cast into an unsigned __int64\n            unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n            // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff\n            // it is not possible for the operation above to overflow, so just check max\n            if( tmp <= IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is unsigned and < 64-bit, rhs signed __int64\n        if( rhs < 0 )\n        {\n            if( lhs >= ~(unsigned __int64)( rhs ) + 1) //negation is safe, since rhs is 64-bit\n            {\n                result = (T)( lhs + rhs );\n                return;\n            }\n        }\n        else\n        {\n            // now we know that rhs can be safely cast into an unsigned __int64\n            unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n            // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff\n            // it is not possible for the operation above to overflow, so just check max\n            if( tmp <= IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return;\n            }\n        }\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflow>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is signed __int64, rhs signed\n        __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs);\n\n        if( lhs >= 0 )\n        {\n            // mixed sign cannot overflow\n            if( rhs >= 0 && tmp < lhs )\n                return false;\n        }\n        else\n        {\n            // lhs negative\n            if( rhs < 0 && tmp > lhs )\n                return false;\n        }\n\n        result = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is signed __int64, rhs signed\n        __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs);\n\n        if( lhs >= 0 )\n        {\n            // mixed sign cannot overflow\n            if( rhs >= 0 && tmp < lhs )\n                E::SafeIntOnOverflow();\n        }\n        else\n        {\n            // lhs negative\n            if( rhs < 0 && tmp > lhs )\n                E::SafeIntOnOverflow();\n        }\n\n        result = (T)tmp;\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowSafeIntMinMax>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        //rhs is signed __int64, lhs signed\n        __int64 tmp;\n\n        if( AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::Addition( (__int64)lhs, (__int64)rhs, tmp ) &&\n            tmp <= IntTraits< T >::maxInt &&\n            tmp >= IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        //rhs is signed __int64, lhs signed\n        __int64 tmp;\n\n        AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::AdditionThrow< E >( (__int64)lhs, (__int64)rhs, tmp );\n\n        if( tmp <= IntTraits< T >::maxInt &&\n            tmp >= IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowMax>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        //lhs is signed __int64, rhs unsigned < 64-bit\n        unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n        if( (__int64)tmp >= lhs )\n        {\n            result = (T)(__int64)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is signed __int64, rhs unsigned < 64-bit\n        // Some compilers get optimization-happy, let's thwart them\n\n        unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;\n\n        if( (__int64)tmp >= lhs )\n        {\n            result = (T)(__int64)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheckInt64Uint64 >\n{\npublic:\n    static bool Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );\n        // rhs is unsigned __int64, lhs __int64\n        // cast everything to unsigned, perform addition, then\n        // cast back for check - this is done to stop optimizers from removing the code\n        unsigned __int64 tmp = (unsigned __int64)lhs + rhs;\n\n        if( (__int64)tmp >= lhs )\n        {\n            result = (__int64)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );\n        // rhs is unsigned __int64, lhs __int64\n        unsigned __int64 tmp = (unsigned __int64)lhs + rhs;\n\n        if( (__int64)tmp >= lhs )\n        {\n            result = (__int64)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheck>\n{\npublic:\n    static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // rhs is unsigned __int64, lhs signed, 32-bit or less\n        if( (unsigned __int32)( rhs >> 32 ) == 0 )\n        {\n            // Now it just happens to work out that the standard behavior does what we want\n            // Adding explicit casts to show exactly what's happening here\n            // Note - this is tweaked to keep optimizers from tossing out the code.\n            unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs;\n\n            if( (__int32)tmp >= lhs && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( (__int32)tmp, result ) )\n                return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // rhs is unsigned __int64, lhs signed, 32-bit or less\n\n        if( (unsigned __int32)( rhs >> 32 ) == 0 )\n        {\n            // Now it just happens to work out that the standard behavior does what we want\n            // Adding explicit casts to show exactly what's happening here\n            unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs;\n\n            if( (__int32)tmp >= lhs )\n            {\n                SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( (__int32)tmp, result );\n                return;\n            }\n        }\n        E::SafeIntOnOverflow();\n    }\n};\n\nenum SubtractionState\n{\n    SubtractionState_BothUnsigned,\n    SubtractionState_CastIntCheckSafeIntMinMax,\n    SubtractionState_CastIntCheckMin,\n    SubtractionState_CastInt64CheckSafeIntMinMax,\n    SubtractionState_CastInt64CheckMin,\n    SubtractionState_Uint64Int,\n    SubtractionState_UintInt64,\n    SubtractionState_Int64Int,\n    SubtractionState_IntInt64,\n    SubtractionState_Int64Uint,\n    SubtractionState_IntUint64,\n    SubtractionState_Int64Uint64,\n    // states for SubtractionMethod2\n    SubtractionState_BothUnsigned2,\n    SubtractionState_CastIntCheckSafeIntMinMax2,\n    SubtractionState_CastInt64CheckSafeIntMinMax2,\n    SubtractionState_Uint64Int2,\n    SubtractionState_UintInt642,\n    SubtractionState_Int64Int2,\n    SubtractionState_IntInt642,\n    SubtractionState_Int64Uint2,\n    SubtractionState_IntUint642,\n    SubtractionState_Int64Uint642,\n    SubtractionState_Error\n};\n\ntemplate < typename T, typename U > class SubtractionMethod\n{\npublic:\n    enum\n    {\n                 // unsigned-unsigned\n        method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||\n                 (IntRegion< T,U >::IntZone_Uint32_UintLT64)   ||\n                 (IntRegion< T,U >::IntZone_UintLT32_Uint32)   ||\n                 (IntRegion< T,U >::IntZone_Uint64_Uint)       ||\n                 (IntRegion< T,U >::IntZone_UintLT64_Uint64))      ? SubtractionState_BothUnsigned :\n                 // unsigned-signed\n                 (IntRegion< T,U >::IntZone_UintLT32_IntLT32)      ? SubtractionState_CastIntCheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_UintLT32_Int32)        ? SubtractionState_CastInt64CheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Uint64_Int ||\n                  IntRegion< T,U >::IntZone_Uint64_Int64)          ? SubtractionState_Uint64Int :\n                 (IntRegion< T,U >::IntZone_UintLT64_Int64)        ? SubtractionState_UintInt64 :\n                 // signed-signed\n                 (IntRegion< T,U >::IntZone_IntLT32_IntLT32)       ? SubtractionState_CastIntCheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Int32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_IntLT32_Int32)         ? SubtractionState_CastInt64CheckSafeIntMinMax :\n                 (IntRegion< T,U >::IntZone_Int64_Int ||\n                  IntRegion< T,U >::IntZone_Int64_Int64)           ? SubtractionState_Int64Int :\n                 (IntRegion< T,U >::IntZone_IntLT64_Int64)         ? SubtractionState_IntInt64 :\n                 // signed-unsigned\n                 (IntRegion< T,U >::IntZone_IntLT32_UintLT32)      ? SubtractionState_CastIntCheckMin :\n                 (IntRegion< T,U >::IntZone_Int32_UintLT32 ||\n                  IntRegion< T,U >::IntZone_IntLT64_Uint32)        ? SubtractionState_CastInt64CheckMin :\n                 (IntRegion< T,U >::IntZone_Int64_UintLT64)        ? SubtractionState_Int64Uint :\n                 (IntRegion< T,U >::IntZone_Int_Uint64)            ? SubtractionState_IntUint64 :\n                 (IntRegion< T,U >::IntZone_Int64_Uint64)          ? SubtractionState_Int64Uint64 :\n                  SubtractionState_Error)\n    };\n};\n\n// this is for the case of U - SafeInt< T, E >\ntemplate < typename T, typename U > class SubtractionMethod2\n{\npublic:\n    enum\n    {\n                 // unsigned-unsigned\n        method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||\n                 (IntRegion< T,U >::IntZone_Uint32_UintLT64)   ||\n                 (IntRegion< T,U >::IntZone_UintLT32_Uint32)   ||\n                 (IntRegion< T,U >::IntZone_Uint64_Uint)       ||\n                 (IntRegion< T,U >::IntZone_UintLT64_Uint64))     ? SubtractionState_BothUnsigned2 :\n                 // unsigned-signed\n                 (IntRegion< T,U >::IntZone_UintLT32_IntLT32)     ? SubtractionState_CastIntCheckSafeIntMinMax2 :\n                 (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_UintLT32_Int32)       ? SubtractionState_CastInt64CheckSafeIntMinMax2 :\n                 (IntRegion< T,U >::IntZone_Uint64_Int ||\n                  IntRegion< T,U >::IntZone_Uint64_Int64)         ? SubtractionState_Uint64Int2 :\n                 (IntRegion< T,U >::IntZone_UintLT64_Int64)       ? SubtractionState_UintInt642 :\n                 // signed-signed\n                 (IntRegion< T,U >::IntZone_IntLT32_IntLT32)      ? SubtractionState_CastIntCheckSafeIntMinMax2 :\n                 (IntRegion< T,U >::IntZone_Int32_IntLT64 ||\n                  IntRegion< T,U >::IntZone_IntLT32_Int32)        ? SubtractionState_CastInt64CheckSafeIntMinMax2 :\n                 (IntRegion< T,U >::IntZone_Int64_Int ||\n                  IntRegion< T,U >::IntZone_Int64_Int64)          ? SubtractionState_Int64Int2 :\n                 (IntRegion< T,U >::IntZone_IntLT64_Int64)        ? SubtractionState_IntInt642 :\n                 // signed-unsigned\n                 (IntRegion< T,U >::IntZone_IntLT32_UintLT32)     ? SubtractionState_CastIntCheckSafeIntMinMax2 :\n                 (IntRegion< T,U >::IntZone_Int32_UintLT32 ||\n                  IntRegion< T,U >::IntZone_IntLT64_Uint32)       ? SubtractionState_CastInt64CheckSafeIntMinMax2 :\n                 (IntRegion< T,U >::IntZone_Int64_UintLT64)       ? SubtractionState_Int64Uint2 :\n                 (IntRegion< T,U >::IntZone_Int_Uint64)           ? SubtractionState_IntUint642 :\n                 (IntRegion< T,U >::IntZone_Int64_Uint64)         ? SubtractionState_Int64Uint642 :\n                                                                    SubtractionState_Error)\n    };\n};\n\ntemplate < typename T, typename U, int method > class SubtractionHelper;\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both are unsigned - easy case\n        if( rhs <= lhs )\n        {\n            result = (T)( lhs - rhs );\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both are unsigned - easy case\n        if( rhs <= lhs )\n        {\n            result = (T)( lhs - rhs );\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned2 >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, U& result ) SAFEINT_NOTHROW\n    {\n        // both are unsigned - easy case\n        // Except we do have to check for overflow - lhs could be larger than result can hold\n        if( rhs <= lhs )\n        {\n            T tmp = (T)(lhs - rhs);\n            return SafeCastHelper< U, T, GetCastMethod<U, T>::method>::Cast( tmp, result);\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, U& result ) SAFEINT_CPP_THROW\n    {\n        // both are unsigned - easy case\n        if( rhs <= lhs )\n        {\n            T tmp = (T)(lhs - rhs);\n            SafeCastHelper< U, T, GetCastMethod<U, T>::method >::template CastThrow<E>( tmp, result);\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckSafeIntMinMax >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both values are 16-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int32 tmp = lhs - rhs;\n\n        if( SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ) )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both values are 16-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int32 tmp = lhs - rhs;\n\n        SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result );\n    }\n};\n\ntemplate <typename U, typename T> class SubtractionHelper< U, T, SubtractionState_CastIntCheckSafeIntMinMax2 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both values are 16-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int32 tmp = lhs - rhs;\n\n        return SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result );\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both values are 16-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int32 tmp = lhs - rhs;\n\n        SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result );\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckMin >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both values are 16-bit or less\n        // rhs is unsigned - check only minimum\n        __int32 tmp = lhs - rhs;\n\n        if( tmp >= (__int32)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both values are 16-bit or less\n        // rhs is unsigned - check only minimum\n        __int32 tmp = lhs - rhs;\n\n        if( tmp >= (__int32)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckSafeIntMinMax >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both values are 32-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int64 tmp = (__int64)lhs - (__int64)rhs;\n\n        return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result );\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both values are 32-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int64 tmp = (__int64)lhs - (__int64)rhs;\n\n        SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result );\n    }\n};\n\ntemplate <typename U, typename T> class SubtractionHelper< U, T, SubtractionState_CastInt64CheckSafeIntMinMax2 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both values are 32-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int64 tmp = (__int64)lhs - (__int64)rhs;\n\n        return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result );\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both values are 32-bit or less\n        // rhs is signed, so could end up increasing or decreasing\n        __int64 tmp = (__int64)lhs - (__int64)rhs;\n\n        SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result );\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckMin >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // both values are 32-bit or less\n        // rhs is unsigned - check only minimum\n        __int64 tmp = (__int64)lhs - (__int64)rhs;\n\n        if( tmp >= (__int64)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // both values are 32-bit or less\n        // rhs is unsigned - check only minimum\n        __int64 tmp = (__int64)lhs - (__int64)rhs;\n\n        if( tmp >= (__int64)IntTraits< T >::minInt )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Uint64Int >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is an unsigned __int64, rhs signed\n        // must first see if rhs is positive or negative\n        if( rhs >= 0 )\n        {\n            if( (unsigned __int64)rhs <= lhs )\n            {\n                result = (T)( lhs - (unsigned __int64)rhs );\n                return true;\n            }\n        }\n        else\n        {\n            T tmp = lhs;\n            // we're now effectively adding\n            result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );\n\n            if(result >= tmp)\n                return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is an unsigned __int64, rhs signed\n        // must first see if rhs is positive or negative\n        if( rhs >= 0 )\n        {\n            if( (unsigned __int64)rhs <= lhs )\n            {\n                result = (T)( lhs - (unsigned __int64)rhs );\n                return;\n            }\n        }\n        else\n        {\n            T tmp = lhs;\n            // we're now effectively adding\n            result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );\n\n            if(result >= tmp)\n                return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Uint64Int2 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // U is unsigned __int64, T is signed\n        if( rhs < 0 )\n        {\n            // treat this as addition\n            unsigned __int64 tmp;\n\n            tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs );\n\n            // must check for addition overflow and max\n            if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return true;\n            }\n        }\n        else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works\n        {\n            // result is negative\n            // implies that lhs must fit into T, and result cannot overflow\n            // Also allows us to drop to 32-bit math, which is faster on a 32-bit system\n            result = (T)lhs - (T)rhs;\n            return true;\n        }\n        else\n        {\n            // result is positive\n            unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;\n\n            if( tmp <= IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // U is unsigned __int64, T is signed\n        if( rhs < 0 )\n        {\n            // treat this as addition\n            unsigned __int64 tmp;\n\n            tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs );\n\n            // must check for addition overflow and max\n            if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return;\n            }\n        }\n        else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works\n        {\n            // result is negative\n            // implies that lhs must fit into T, and result cannot overflow\n            // Also allows us to drop to 32-bit math, which is faster on a 32-bit system\n            result = (T)lhs - (T)rhs;\n            return;\n        }\n        else\n        {\n            // result is positive\n            unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;\n\n            if( tmp <= IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_UintInt64 >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is an unsigned int32 or smaller, rhs signed __int64\n        // must first see if rhs is positive or negative\n        if( rhs >= 0 )\n        {\n            if( (unsigned __int64)rhs <= lhs )\n            {\n                result = (T)( lhs - (T)rhs );\n                return true;\n            }\n        }\n        else\n        {\n            // we're now effectively adding\n            // since lhs is 32-bit, and rhs cannot exceed 2^63\n            // this addition cannot overflow\n            unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe\n\n            // but we could exceed MaxInt\n            if(tmp <= IntTraits< T >::maxInt)\n            {\n                result = (T)tmp;\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is an unsigned int32 or smaller, rhs signed __int64\n        // must first see if rhs is positive or negative\n        if( rhs >= 0 )\n        {\n            if( (unsigned __int64)rhs <= lhs )\n            {\n                result = (T)( lhs - (T)rhs );\n                return;\n            }\n        }\n        else\n        {\n            // we're now effectively adding\n            // since lhs is 32-bit, and rhs cannot exceed 2^63\n            // this addition cannot overflow\n            unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe\n\n            // but we could exceed MaxInt\n            if(tmp <= IntTraits< T >::maxInt)\n            {\n                result = (T)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate <typename U, typename T> class SubtractionHelper< U, T, SubtractionState_UintInt642 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // U unsigned 32-bit or less, T __int64\n        if( rhs >= 0 )\n        {\n            // overflow not possible\n            result = (T)( (__int64)lhs - rhs );\n            return true;\n        }\n        else\n        {\n            // we effectively have an addition\n            // which cannot overflow internally\n            unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );\n\n            if( tmp <= (unsigned __int64)IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // U unsigned 32-bit or less, T __int64\n        if( rhs >= 0 )\n        {\n            // overflow not possible\n            result = (T)( (__int64)lhs - rhs );\n            return;\n        }\n        else\n        {\n            // we effectively have an addition\n            // which cannot overflow internally\n            unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );\n\n            if( tmp <= (unsigned __int64)IntTraits< T >::maxInt )\n            {\n                result = (T)tmp;\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Int >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is an __int64, rhs signed (up to 64-bit)\n        // we have essentially 4 cases:\n        //\n        // 1) lhs positive, rhs positive - overflow not possible\n        // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error\n        // 3) lhs negative, rhs positive - check result <= lhs\n        // 4) lhs negative, rhs negative - overflow not possible\n\n        __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);\n\n        // Note - ideally, we can order these so that true conditionals\n        // lead to success, which enables better pipelining\n        // It isn't practical here\n        if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2\n            ( rhs >= 0 && tmp > lhs ) )             // condition 3\n        {\n            return false;\n        }\n\n        result = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is an __int64, rhs signed (up to 64-bit)\n        // we have essentially 4 cases:\n        //\n        // 1) lhs positive, rhs positive - overflow not possible\n        // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error\n        // 3) lhs negative, rhs positive - check result <= lhs\n        // 4) lhs negative, rhs negative - overflow not possible\n\n        __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);\n\n        // Note - ideally, we can order these so that true conditionals\n        // lead to success, which enables better pipelining\n        // It isn't practical here\n        if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2\n            ( rhs >= 0 && tmp > lhs ) )             // condition 3\n        {\n            E::SafeIntOnOverflow();\n        }\n\n        result = (T)tmp;\n    }\n};\n\ntemplate < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Int2 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs __int64, rhs any signed int (including __int64)\n        __int64 tmp = lhs - rhs;\n\n        // we have essentially 4 cases:\n        //\n        // 1) lhs positive, rhs positive - overflow not possible in tmp\n        // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error\n        // 3) lhs negative, rhs positive - check result <= lhs\n        // 4) lhs negative, rhs negative - overflow not possible in tmp\n\n        if( lhs >= 0 )\n        {\n            // if both positive, overflow to negative not possible\n            // which is why we'll explicitly check maxInt, and not call SafeCast\n            if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) ||\n                ( rhs < 0 && tmp < lhs ) )\n            {\n                return false;\n            }\n        }\n        else\n        {\n            // lhs negative\n            if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) ||\n                ( rhs >=0 && tmp > lhs ) )\n            {\n                return false;\n            }\n        }\n\n        result = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs __int64, rhs any signed int (including __int64)\n        __int64 tmp = lhs - rhs;\n\n        // we have essentially 4 cases:\n        //\n        // 1) lhs positive, rhs positive - overflow not possible in tmp\n        // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error\n        // 3) lhs negative, rhs positive - check result <= lhs\n        // 4) lhs negative, rhs negative - overflow not possible in tmp\n\n        if( lhs >= 0 )\n        {\n            // if both positive, overflow to negative not possible\n            // which is why we'll explicitly check maxInt, and not call SafeCast\n            if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp > IntTraits< T >::maxInt ) ||\n                ( rhs < 0 && tmp < lhs ) )\n            {\n                E::SafeIntOnOverflow();\n            }\n        }\n        else\n        {\n            // lhs negative\n            if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp < IntTraits< T >::minInt) ||\n                ( rhs >=0 && tmp > lhs ) )\n            {\n                E::SafeIntOnOverflow();\n            }\n        }\n\n        result = (T)tmp;\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntInt64 >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is a 32-bit int or less, rhs __int64\n        // we have essentially 4 cases:\n        //\n        // lhs positive, rhs positive - rhs could be larger than lhs can represent\n        // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int\n        // lhs negative, rhs positive - check tmp <= lhs and tmp < min int\n        // lhs negative, rhs negative - addition cannot internally overflow, check against max\n\n        __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);\n\n        if( lhs >= 0 )\n        {\n            // first case\n            if( rhs >= 0 )\n            {\n                if( tmp >= IntTraits< T >::minInt )\n                {\n                    result = (T)tmp;\n                    return true;\n                }\n            }\n            else\n            {\n                // second case\n                if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n                {\n                    result = (T)tmp;\n                    return true;\n                }\n            }\n        }\n        else\n        {\n            // lhs < 0\n            // third case\n            if( rhs >= 0 )\n            {\n                if( tmp <= lhs && tmp >= IntTraits< T >::minInt )\n                {\n                    result = (T)tmp;\n                    return true;\n                }\n            }\n            else\n            {\n                // fourth case\n                if( tmp <= IntTraits< T >::maxInt )\n                {\n                    result = (T)tmp;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is a 32-bit int or less, rhs __int64\n        // we have essentially 4 cases:\n        //\n        // lhs positive, rhs positive - rhs could be larger than lhs can represent\n        // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int\n        // lhs negative, rhs positive - check tmp <= lhs and tmp < min int\n        // lhs negative, rhs negative - addition cannot internally overflow, check against max\n\n        __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);\n\n        if( lhs >= 0 )\n        {\n            // first case\n            if( rhs >= 0 )\n            {\n                if( tmp >= IntTraits< T >::minInt )\n                {\n                    result = (T)tmp;\n                    return;\n                }\n            }\n            else\n            {\n                // second case\n                if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )\n                {\n                    result = (T)tmp;\n                    return;\n                }\n            }\n        }\n        else\n        {\n            // lhs < 0\n            // third case\n            if( rhs >= 0 )\n            {\n                if( tmp <= lhs && tmp >= IntTraits< T >::minInt )\n                {\n                    result = (T)tmp;\n                    return;\n                }\n            }\n            else\n            {\n                // fourth case\n                if( tmp <= IntTraits< T >::maxInt )\n                {\n                    result = (T)tmp;\n                    return;\n                }\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntInt642 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is any signed int32 or smaller, rhs is int64\n        __int64 tmp = (__int64)lhs - rhs;\n\n        if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||\n            ( rhs > 0 && tmp > lhs ) )\n        {\n            return false;\n            //else OK\n        }\n\n        result = (T)tmp;\n        return true;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is any signed int32 or smaller, rhs is int64\n        __int64 tmp = (__int64)lhs - rhs;\n\n        if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||\n            ( rhs > 0 && tmp > lhs ) )\n        {\n            E::SafeIntOnOverflow();\n            //else OK\n        }\n\n        result = (T)tmp;\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is a 64-bit int, rhs unsigned int32 or smaller\n        // perform test as unsigned to prevent unwanted optimizations\n        unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;\n\n        if( (__int64)tmp <= lhs )\n        {\n            result = (T)(__int64)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is a 64-bit int, rhs unsigned int32 or smaller\n        // perform test as unsigned to prevent unwanted optimizations\n        unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;\n\n        if( (__int64)tmp <= lhs )\n        {\n            result = (T)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint2 >\n{\npublic:\n    // lhs is __int64, rhs is unsigned 32-bit or smaller\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // Do this as unsigned to prevent unwanted optimizations\n        unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;\n\n        if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt )\n        {\n            result = (T)(__int64)tmp;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // Do this as unsigned to prevent unwanted optimizations\n        unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;\n\n        if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt )\n        {\n            result = (T)(__int64)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntUint64 >\n{\npublic:\n    static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // lhs is any signed int, rhs unsigned int64\n        // check against available range\n\n        // We need the absolute value of IntTraits< T >::minInt\n        // This will give it to us without extraneous compiler warnings\n        const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;\n\n        if( lhs < 0 )\n        {\n            if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) )\n            {\n                result = (T)( lhs - rhs );\n                return true;\n            }\n        }\n        else\n        {\n            if( rhs <= AbsMinIntT + (unsigned __int64)lhs )\n            {\n                result = (T)( lhs - rhs );\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // lhs is any signed int, rhs unsigned int64\n        // check against available range\n\n        // We need the absolute value of IntTraits< T >::minInt\n        // This will give it to us without extraneous compiler warnings\n        const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;\n\n        if( lhs < 0 )\n        {\n            if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) )\n            {\n                result = (T)( lhs - rhs );\n                return;\n            }\n        }\n        else\n        {\n            if( rhs <= AbsMinIntT + (unsigned __int64)lhs )\n            {\n                result = (T)( lhs - rhs );\n                return;\n            }\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntUint642 >\n{\npublic:\n    static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        // We run into upcasting problems on comparison - needs 2 checks\n        if( lhs >= 0 && (T)lhs >= rhs )\n        {\n            result = (T)((U)lhs - (U)rhs);\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        // We run into upcasting problems on comparison - needs 2 checks\n        if( lhs >= 0 && (T)lhs >= rhs )\n        {\n            result = (T)((U)lhs - (U)rhs);\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n\n};\n\ntemplate < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint64 >\n{\npublic:\n    static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );\n        // if we subtract, and it gets larger, there's a problem\n        // Perform test as unsigned to prevent unwanted optimizations\n        unsigned __int64 tmp = (unsigned __int64)lhs - rhs;\n\n        if( (__int64)tmp <= lhs )\n        {\n            result = (__int64)tmp;\n            return true;\n        }\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );\n        // if we subtract, and it gets larger, there's a problem\n        // Perform test as unsigned to prevent unwanted optimizations\n        unsigned __int64 tmp = (unsigned __int64)lhs - rhs;\n\n        if( (__int64)tmp <= lhs )\n        {\n            result = (__int64)tmp;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n\n};\n\ntemplate < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint642 >\n{\npublic:\n    // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it\n    // get smaller. If rhs > lhs, then it would also go negative, which is the other case\n    static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 );\n        if( lhs >= 0 && (unsigned __int64)lhs >= rhs )\n        {\n            result = (unsigned __int64)lhs - rhs;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename E >\n    static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 );\n        if( lhs >= 0 && (unsigned __int64)lhs >= rhs )\n        {\n            result = (unsigned __int64)lhs - rhs;\n            return;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n\n};\n\nenum BinaryState\n{\n    BinaryState_OK,\n    BinaryState_Int8,\n    BinaryState_Int16,\n    BinaryState_Int32\n};\n\ntemplate < typename T, typename U > class BinaryMethod\n{\npublic:\n    enum\n    {\n        // If both operands are unsigned OR\n        //    return type is smaller than rhs OR\n        //    return type is larger and rhs is unsigned\n        // Then binary operations won't produce unexpected results\n        method = ( sizeof( T ) <= sizeof( U ) ||\n                 SafeIntCompare< T, U >::isBothUnsigned ||\n                 !IntTraits< U >::isSigned )          ? BinaryState_OK :\n                 IntTraits< U >::isInt8               ? BinaryState_Int8 :\n                 IntTraits< U >::isInt16              ? BinaryState_Int16\n                                                      : BinaryState_Int32\n    };\n};\n\n#ifdef SAFEINT_DISABLE_BINARY_ASSERT\n#define BinaryAssert(x)\n#else\n#define BinaryAssert(x) SAFEINT_ASSERT(x)\n#endif\n\ntemplate < typename T, typename U, int method > class BinaryAndHelper;\n\ntemplate < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >\n{\npublic:\n    static T And( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs & rhs ); }\n};\n\ntemplate < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >\n{\npublic:\n    static T And( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        // cast forces sign extension to be zeros\n        BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) );\n        return (T)( lhs & (unsigned __int8)rhs );\n    }\n};\n\ntemplate < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >\n{\npublic:\n    static T And( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        //cast forces sign extension to be zeros\n        BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) );\n        return (T)( lhs & (unsigned __int16)rhs );\n    }\n};\n\ntemplate < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >\n{\npublic:\n    static T And( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        //cast forces sign extension to be zeros\n        BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) );\n        return (T)( lhs & (unsigned __int32)rhs );\n    }\n};\n\ntemplate < typename T, typename U, int method > class BinaryOrHelper;\n\ntemplate < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >\n{\npublic:\n    static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs | rhs ); }\n};\n\ntemplate < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >\n{\npublic:\n    static T Or( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        //cast forces sign extension to be zeros\n        BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) );\n        return (T)( lhs | (unsigned __int8)rhs );\n    }\n};\n\ntemplate < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >\n{\npublic:\n    static T Or( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        //cast forces sign extension to be zeros\n        BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) );\n        return (T)( lhs | (unsigned __int16)rhs );\n    }\n};\n\ntemplate < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >\n{\npublic:\n    static T Or( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        //cast forces sign extension to be zeros\n        BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) );\n        return (T)( lhs | (unsigned __int32)rhs );\n    }\n};\n\ntemplate <typename T, typename U, int method > class BinaryXorHelper;\n\ntemplate < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >\n{\npublic:\n    static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs ^ rhs ); }\n};\n\ntemplate < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >\n{\npublic:\n    static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        // cast forces sign extension to be zeros\n        BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) );\n        return (T)( lhs ^ (unsigned __int8)rhs );\n    }\n};\n\ntemplate < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >\n{\npublic:\n    static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        // cast forces sign extension to be zeros\n        BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) );\n        return (T)( lhs ^ (unsigned __int16)rhs );\n    }\n};\n\ntemplate < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >\n{\npublic:\n    static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW\n    {\n        // cast forces sign extension to be zeros\n        BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) );\n        return (T)( lhs ^ (unsigned __int32)rhs );\n    }\n};\n\n/*****************  External functions ****************************************/\n\n// External functions that can be used where you only need to check one operation\n// non-class helper function so that you can check for a cast's validity\n// and handle errors how you like\ntemplate < typename T, typename U >\ninline bool SafeCast( const T From, U& To ) SAFEINT_NOTHROW\n{\n    return SafeCastHelper< U, T, GetCastMethod< U, T >::method >::Cast( From, To );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeEquals( const T t, const U u ) SAFEINT_NOTHROW\n{\n    return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeNotEquals( const T t, const U u ) SAFEINT_NOTHROW\n{\n    return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeGreaterThan( const T t, const U u ) SAFEINT_NOTHROW\n{\n    return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeGreaterThanEquals( const T t, const U u ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeLessThan( const T t, const U u ) SAFEINT_NOTHROW\n{\n    return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeLessThanEquals( const T t, const U u ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeModulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW\n{\n    return ( ModulusHelper< T, U, ValidComparison< T, U >::method >::Modulus( t, u, result ) == SafeIntNoError );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeMultiply( T t, U u, T& result ) SAFEINT_NOTHROW\n{\n    return MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::Multiply( t, u, result );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeDivide( T t, U u, T& result ) SAFEINT_NOTHROW\n{\n    return ( DivisionHelper< T, U, DivisionMethod< T, U >::method >::Divide( t, u, result ) == SafeIntNoError );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeAdd( T t, U u, T& result ) SAFEINT_NOTHROW\n{\n    return AdditionHelper< T, U, AdditionMethod< T, U >::method >::Addition( t, u, result );\n}\n\ntemplate < typename T, typename U >\ninline bool SafeSubtract( T t, U u, T& result ) SAFEINT_NOTHROW\n{\n    return SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::Subtract( t, u, result );\n}\n\n/*****************  end external functions ************************************/\n\n// Main SafeInt class\n// Assumes exceptions can be thrown\ntemplate < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeInt\n{\npublic:\n    SafeInt() SAFEINT_NOTHROW\n    {\n        C_ASSERT( NumericType< T >::isInt );\n        m_int = 0;\n    }\n\n    // Having a constructor for every type of int\n    // avoids having the compiler evade our checks when doing implicit casts -\n    // e.g., SafeInt<char> s = 0x7fffffff;\n    SafeInt( const T& i ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( NumericType< T >::isInt );\n        //always safe\n        m_int = i;\n    }\n\n    // provide explicit boolean converter\n    SafeInt( bool b ) SAFEINT_NOTHROW\n    {\n        C_ASSERT( NumericType< T >::isInt );\n        m_int = (T)( b ? 1 : 0 );\n    }\n\n    template < typename U >\n    SafeInt(const SafeInt< U, E >& u) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( NumericType< T >::isInt );\n        *this = SafeInt< T, E >( (U)u );\n    }\n\n    template < typename U >\n    SafeInt( const U& i ) SAFEINT_CPP_THROW\n    {\n        C_ASSERT( NumericType< T >::isInt );\n        // SafeCast will throw exceptions if i won't fit in type T\n        SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( i, m_int );\n    }\n\n    // The destructor is intentionally commented out - no destructor\n    // vs. a do-nothing destructor makes a huge difference in\n    // inlining characteristics. It wasn't doing anything anyway.\n    // ~SafeInt(){};\n\n\n    // now start overloading operators\n    // assignment operator\n    // constructors exist for all int types and will ensure safety\n\n    template < typename U >\n    SafeInt< T, E >& operator =( const U& rhs ) SAFEINT_CPP_THROW\n    {\n        // use constructor to test size\n        // constructor is optimized to do minimal checking based\n        // on whether T can contain U\n        // note - do not change this\n        *this = SafeInt< T, E >( rhs );\n        return *this;\n    }\n\n    SafeInt< T, E >& operator =( const T& rhs ) SAFEINT_NOTHROW\n    {\n        m_int = rhs;\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs ) SAFEINT_CPP_THROW\n    {\n        SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( rhs.Ref(), m_int );\n        return *this;\n    }\n\n    SafeInt< T, E >& operator =( const SafeInt< T, E >& rhs ) SAFEINT_NOTHROW\n    {\n        m_int = rhs.m_int;\n        return *this;\n    }\n\n    // Casting operators\n\n    operator bool() const SAFEINT_NOTHROW\n    {\n        return !!m_int;\n    }\n\n    operator char() const SAFEINT_CPP_THROW\n    {\n        char val;\n        SafeCastHelper< char, T, GetCastMethod< char, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator signed char() const SAFEINT_CPP_THROW\n    {\n        signed char val;\n        SafeCastHelper< signed char, T, GetCastMethod< signed char, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator unsigned char() const SAFEINT_CPP_THROW\n    {\n        unsigned char val;\n        SafeCastHelper< unsigned char, T, GetCastMethod< unsigned char, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator __int16() const SAFEINT_CPP_THROW\n    {\n        __int16 val;\n        SafeCastHelper< __int16, T, GetCastMethod< __int16, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator unsigned __int16() const SAFEINT_CPP_THROW\n    {\n        unsigned __int16 val;\n        SafeCastHelper< unsigned __int16, T, GetCastMethod< unsigned __int16, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator __int32() const SAFEINT_CPP_THROW\n    {\n        __int32 val;\n        SafeCastHelper< __int32, T, GetCastMethod< __int32, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator unsigned __int32() const SAFEINT_CPP_THROW\n    {\n        unsigned __int32 val;\n        SafeCastHelper< unsigned __int32, T, GetCastMethod< unsigned __int32, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    // The compiler knows that int == __int32\n    // but not that long == __int32\n    operator long() const SAFEINT_CPP_THROW\n    {\n        long val;\n        SafeCastHelper< long, T, GetCastMethod< long, T >::method >::template CastThrow< E >( m_int, val );\n        return  val;\n    }\n\n    operator unsigned long() const SAFEINT_CPP_THROW\n    {\n        unsigned long val;\n        SafeCastHelper< unsigned long, T, GetCastMethod< unsigned long, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator __int64() const SAFEINT_CPP_THROW\n    {\n        __int64 val;\n        SafeCastHelper< __int64, T, GetCastMethod< __int64, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator unsigned __int64() const SAFEINT_CPP_THROW\n    {\n        unsigned __int64 val;\n        SafeCastHelper< unsigned __int64, T, GetCastMethod< unsigned __int64, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED\n    operator wchar_t() const SAFEINT_CPP_THROW\n    {\n        wchar_t val;\n        SafeCastHelper< wchar_t, T, GetCastMethod< wchar_t, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n#endif\n\n#ifdef SIZE_T_CAST_NEEDED\n    // We also need an explicit cast to size_t, or the compiler will complain\n    // Apparently, only SOME compilers complain, and cl 14.00.50727.42 isn't one of them\n    // Leave here in case we decide to backport this to an earlier compiler\n    operator size_t() const SAFEINT_CPP_THROW\n    {\n        size_t val;\n        SafeCastHelper< size_t, T, GetCastMethod< size_t, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n#endif\n\n    // Also provide a cast operator for floating point types\n    operator float() const SAFEINT_CPP_THROW\n    {\n        float val;\n        SafeCastHelper< float, T, GetCastMethod< float, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    operator double() const SAFEINT_CPP_THROW\n    {\n        double val;\n        SafeCastHelper< double, T, GetCastMethod< double, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n    operator long double() const SAFEINT_CPP_THROW\n    {\n        long double val;\n        SafeCastHelper< long double, T, GetCastMethod< long double, T >::method >::template CastThrow< E >( m_int, val );\n        return val;\n    }\n\n    // If you need a pointer to the data\n    // this could be dangerous, but allows you to correctly pass\n    // instances of this class to APIs that take a pointer to an integer\n    // also see overloaded address-of operator below\n    T* Ptr() SAFEINT_NOTHROW { return &m_int; }\n    const T* Ptr() const SAFEINT_NOTHROW { return &m_int; }\n    const T& Ref() const SAFEINT_NOTHROW { return m_int; }\n\n    // Or if SafeInt< T, E >::Ptr() is inconvenient, use the overload\n    // operator &\n    // This allows you to do unsafe things!\n    // It is meant to allow you to more easily\n    // pass a SafeInt into things like ReadFile\n    T* operator &() SAFEINT_NOTHROW { return &m_int; }\n    const T* operator &() const SAFEINT_NOTHROW { return &m_int; }\n\n    // Unary operators\n    bool operator !() const SAFEINT_NOTHROW { return (!m_int) ? true : false; }\n\n    // operator + (unary)\n    // note - normally, the '+' and '-' operators will upcast to a signed int\n    // for T < 32 bits. This class changes behavior to preserve type\n    const SafeInt< T, E >& operator +() const SAFEINT_NOTHROW { return *this; }\n\n    //unary  -\n\n    SafeInt< T, E > operator -() const SAFEINT_CPP_THROW\n    {\n        // Note - unsigned still performs the bitwise manipulation\n        // will warn at level 2 or higher if the value is 32-bit or larger\n        return SafeInt<T, E>(NegationHelper<T, IntTraits<T>::isSigned>::template NegativeThrow<E>(m_int));\n    }\n\n    // prefix increment operator\n    SafeInt< T, E >& operator ++() SAFEINT_CPP_THROW\n    {\n        if( m_int != IntTraits< T >::maxInt )\n        {\n            ++m_int;\n            return *this;\n        }\n        E::SafeIntOnOverflow();\n    }\n\n    // prefix decrement operator\n    SafeInt< T, E >& operator --() SAFEINT_CPP_THROW\n    {\n        if( m_int != IntTraits< T >::minInt )\n        {\n            --m_int;\n            return *this;\n        }\n        E::SafeIntOnOverflow();\n    }\n\n    // note that postfix operators have inherently worse perf\n    // characteristics\n\n    // postfix increment operator\n    SafeInt< T, E > operator ++( int )  SAFEINT_CPP_THROW // dummy arg to comply with spec\n    {\n        if( m_int != IntTraits< T >::maxInt )\n        {\n            SafeInt< T, E > tmp( m_int );\n\n            m_int++;\n            return tmp;\n        }\n        E::SafeIntOnOverflow();\n    }\n\n    // postfix decrement operator\n    SafeInt< T, E > operator --( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec\n    {\n        if( m_int != IntTraits< T >::minInt )\n        {\n            SafeInt< T, E > tmp( m_int );\n            m_int--;\n            return tmp;\n        }\n        E::SafeIntOnOverflow();\n    }\n\n    // One's complement\n    // Note - this operator will normally change size to an int\n    // cast in return improves perf and maintains type\n    SafeInt< T, E > operator ~() const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)~m_int ); }\n\n    // Binary operators\n    //\n    // arithmetic binary operators\n    // % modulus\n    // * multiplication\n    // / division\n    // + addition\n    // - subtraction\n    //\n    // For each of the arithmetic operators, you will need to\n    // use them as follows:\n    //\n    // SafeInt<char> c = 2;\n    // SafeInt<int>  i = 3;\n    //\n    // SafeInt<int> i2 = i op (char)c;\n    // OR\n    // SafeInt<char> i2 = (int)i op c;\n    //\n    // The base problem is that if the lhs and rhs inputs are different SafeInt types\n    // it is not possible in this implementation to determine what type of SafeInt\n    // should be returned. You have to let the class know which of the two inputs\n    // need to be the return type by forcing the other value to the base integer type.\n    //\n    // Note - as per feedback from Scott Meyers, I'm exploring how to get around this.\n    // 3.0 update - I'm still thinking about this. It can be done with template metaprogramming,\n    // but it is tricky, and there's a perf vs. correctness tradeoff where the right answer\n    // is situational.\n    //\n    // The case of:\n    //\n    // SafeInt< T, E > i, j, k;\n    // i = j op k;\n    //\n    // works just fine and no unboxing is needed because the return type is not ambiguous.\n\n    // Modulus\n    // Modulus has some convenient properties -\n    // first, the magnitude of the return can never be\n    // larger than the lhs operand, and it must be the same sign\n    // as well. It does, however, suffer from the same promotion\n    // problems as comparisons, division and other operations\n    template < typename U >\n    SafeInt< T, E > operator %( U rhs ) const SAFEINT_CPP_THROW\n    {\n        T result;\n        ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, result );\n        return SafeInt< T, E >( result );\n    }\n\n    SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW\n    {\n        T result;\n        ModulusHelper< T, T, ValidComparison< T, T >::method >::template ModulusThrow< E >( m_int, rhs, result );\n        return SafeInt< T, E >( result );\n    }\n\n    // Modulus assignment\n    template < typename U >\n    SafeInt< T, E >& operator %=( U rhs ) SAFEINT_CPP_THROW\n    {\n        ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator %=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n    {\n        ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, (U)rhs, m_int );\n        return *this;\n    }\n\n    // Multiplication\n    template < typename U >\n    SafeInt< T, E > operator *( U rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    // Multiplication assignment\n    SafeInt< T, E >& operator *=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n    {\n        MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator *=( U rhs ) SAFEINT_CPP_THROW\n    {\n        MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator *=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n    {\n        MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs.Ref(), m_int );\n        return *this;\n    }\n\n    // Division\n    template < typename U >\n    SafeInt< T, E > operator /( U rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    // Division assignment\n    SafeInt< T, E >& operator /=( SafeInt< T, E > i ) SAFEINT_CPP_THROW\n    {\n        DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)i, m_int );\n        return *this;\n    }\n\n    template < typename U > SafeInt< T, E >& operator /=( U i ) SAFEINT_CPP_THROW\n    {\n        DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, i, m_int );\n        return *this;\n    }\n\n    template < typename U > SafeInt< T, E >& operator /=( SafeInt< U, E > i )\n    {\n        DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, (U)i, m_int );\n        return *this;\n    }\n\n    // For addition and subtraction\n\n    // Addition\n    SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    template < typename U >\n    SafeInt< T, E > operator +( U rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    //addition assignment\n    SafeInt< T, E >& operator +=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n    {\n        AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator +=( U rhs ) SAFEINT_CPP_THROW\n    {\n        AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator +=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n    {\n        AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, (U)rhs, m_int );\n        return *this;\n    }\n\n    // Subtraction\n    template < typename U >\n    SafeInt< T, E > operator -( U rhs ) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    SafeInt< T, E > operator -(SafeInt< T, E > rhs) const SAFEINT_CPP_THROW\n    {\n        T ret( 0 );\n        SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, ret );\n        return SafeInt< T, E >( ret );\n    }\n\n    // Subtraction assignment\n    SafeInt< T, E >& operator -=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n    {\n        SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator -=( U rhs ) SAFEINT_CPP_THROW\n    {\n        SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, m_int );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator -=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n    {\n        SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, (U)rhs, m_int );\n        return *this;\n    }\n\n    // Shift operators\n    // Note - shift operators ALWAYS return the same type as the lhs\n    // specific version for SafeInt< T, E > not needed -\n    // code path is exactly the same as for SafeInt< U, E > as rhs\n\n    // Left shift\n    // Also, shifting > bitcount is undefined - trap in debug\n#ifdef SAFEINT_DISABLE_SHIFT_ASSERT\n    #define ShiftAssert(x)\n#else\n    #define ShiftAssert(x) SAFEINT_ASSERT(x)\n#endif\n\n    template < typename U >\n    SafeInt< T, E > operator <<( U bits ) const SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );\n        ShiftAssert( bits < (int)IntTraits< T >::bitCount );\n\n        return SafeInt< T, E >( (T)( m_int << bits ) );\n    }\n\n    template < typename U >\n    SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );\n        ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount );\n\n        return SafeInt< T, E >( (T)( m_int << (U)bits ) );\n    }\n\n    // Left shift assignment\n\n    template < typename U >\n    SafeInt< T, E >& operator <<=( U bits ) SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );\n        ShiftAssert( bits < (int)IntTraits< T >::bitCount );\n\n        m_int <<= bits;\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );\n        ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount );\n\n        m_int <<= (U)bits;\n        return *this;\n    }\n\n    // Right shift\n    template < typename U >\n    SafeInt< T, E > operator >>( U bits ) const SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );\n        ShiftAssert( bits < (int)IntTraits< T >::bitCount );\n\n        return SafeInt< T, E >( (T)( m_int >> bits ) );\n    }\n\n    template < typename U >\n    SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );\n        ShiftAssert( bits < (int)IntTraits< T >::bitCount );\n\n        return SafeInt< T, E >( (T)(m_int >> (U)bits) );\n    }\n\n    // Right shift assignment\n    template < typename U >\n    SafeInt< T, E >& operator >>=( U bits ) SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );\n        ShiftAssert( bits < (int)IntTraits< T >::bitCount );\n\n        m_int >>= bits;\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) SAFEINT_NOTHROW\n    {\n        ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );\n        ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount );\n\n        m_int >>= (U)bits;\n        return *this;\n    }\n\n    // Bitwise operators\n    // This only makes sense if we're dealing with the same type and size\n    // demand a type T, or something that fits into a type T\n\n    // Bitwise &\n    SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW\n    {\n        return SafeInt< T, E >( m_int & (T)rhs );\n    }\n\n    template < typename U >\n    SafeInt< T, E > operator &( U rhs ) const SAFEINT_NOTHROW\n    {\n        // we want to avoid setting bits by surprise\n        // consider the case of lhs = int, value = 0xffffffff\n        //                      rhs = char, value = 0xff\n        //\n        // programmer intent is to get only the lower 8 bits\n        // normal behavior is to upcast both sides to an int\n        // which then sign extends rhs, setting all the bits\n\n        // If you land in the assert, this is because the bitwise operator\n        // was causing unexpected behavior. Fix is to properly cast your inputs\n        // so that it works like you meant, not unexpectedly\n\n        return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ) );\n    }\n\n    // Bitwise & assignment\n    SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n    {\n        m_int &= (T)rhs;\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator &=( U rhs ) SAFEINT_NOTHROW\n    {\n        m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n    {\n        m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, (U)rhs );\n        return *this;\n    }\n\n    // XOR\n    SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW\n    {\n        return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) );\n    }\n\n    template < typename U >\n    SafeInt< T, E > operator ^( U rhs ) const SAFEINT_NOTHROW\n    {\n        // If you land in the assert, this is because the bitwise operator\n        // was causing unexpected behavior. Fix is to properly cast your inputs\n        // so that it works like you meant, not unexpectedly\n\n        return SafeInt< T, E >( BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ) );\n    }\n\n    // XOR assignment\n    SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n    {\n        m_int ^= (T)rhs;\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator ^=( U rhs ) SAFEINT_NOTHROW\n    {\n        m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n    {\n        m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, (U)rhs );\n        return *this;\n    }\n\n    // bitwise OR\n    SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW\n    {\n        return SafeInt< T, E >( (T)( m_int | (T)rhs ) );\n    }\n\n    template < typename U >\n    SafeInt< T, E > operator |( U rhs ) const SAFEINT_NOTHROW\n    {\n        return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ) );\n    }\n\n    // bitwise OR assignment\n    SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n    {\n        m_int |= (T)rhs;\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator |=( U rhs ) SAFEINT_NOTHROW\n    {\n        m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs );\n        return *this;\n    }\n\n    template < typename U >\n    SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n    {\n        m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, (U)rhs );\n        return *this;\n    }\n\n    // Miscellaneous helper functions\n    SafeInt< T, E > Min( SafeInt< T, E > test, const T floor = IntTraits< T >::minInt ) const SAFEINT_NOTHROW\n    {\n        T tmp = test < m_int ? (T)test : m_int;\n        return tmp < floor ? floor : tmp;\n    }\n\n    SafeInt< T, E > Max( SafeInt< T, E > test, const T upper = IntTraits< T >::maxInt ) const SAFEINT_NOTHROW\n    {\n        T tmp = test > m_int ? (T)test : m_int;\n        return tmp > upper ? upper : tmp;\n    }\n\n    void Swap( SafeInt< T, E >& with ) SAFEINT_NOTHROW\n    {\n        T temp( m_int );\n        m_int = with.m_int;\n        with.m_int = temp;\n    }\n\n    static SafeInt< T, E > SafeAtoI( const char* input ) SAFEINT_CPP_THROW\n    {\n        return SafeTtoI( input );\n    }\n\n    static SafeInt< T, E > SafeWtoI( const wchar_t* input )\n    {\n        return SafeTtoI( input );\n    }\n\n    enum alignBits\n    {\n        align2 = 1,\n        align4 = 2,\n        align8 = 3,\n        align16 = 4,\n        align32 = 5,\n        align64 = 6,\n        align128 = 7,\n        align256 = 8\n    };\n\n    template < alignBits bits >\n    const SafeInt< T, E >& Align() SAFEINT_CPP_THROW\n    {\n        // Zero is always aligned\n        if( m_int == 0 )\n            return *this;\n\n        // We don't support aligning negative numbers at this time\n        // Can't align unsigned numbers on bitCount (e.g., 8 bits = 256, unsigned char max = 255)\n        // or signed numbers on bitCount-1 (e.g., 7 bits = 128, signed char max = 127).\n        // Also makes no sense to try to align on negative or no bits.\n\n        ShiftAssert( ( ( IntTraits<T>::isSigned && bits < (int)IntTraits< T >::bitCount - 1 )\n                    || ( !IntTraits<T>::isSigned && bits < (int)IntTraits< T >::bitCount ) ) &&\n                    bits >= 0 && ( !IntTraits<T>::isSigned || m_int > 0 ) );\n\n        const T AlignValue = ( (T)1 << bits ) - 1;\n\n        m_int = (T)( ( m_int + AlignValue ) & ~AlignValue );\n\n        if( m_int <= 0 )\n            E::SafeIntOnOverflow();\n\n        return *this;\n    }\n\n    // Commonly needed alignments:\n    const SafeInt< T, E >& Align2()  { return Align< align2 >(); }\n    const SafeInt< T, E >& Align4()  { return Align< align4 >(); }\n    const SafeInt< T, E >& Align8()  { return Align< align8 >(); }\n    const SafeInt< T, E >& Align16() { return Align< align16 >(); }\n    const SafeInt< T, E >& Align32() { return Align< align32 >(); }\n    const SafeInt< T, E >& Align64() { return Align< align64 >(); }\nprivate:\n\n    // This is almost certainly not the best optimized version of atoi,\n    // but it does not display a typical bug where it isn't possible to set MinInt\n    // and it won't allow you to overflow your integer.\n    // This is here because it is useful, and it is an example of what\n    // can be done easily with SafeInt.\n    template < typename U >\n    static SafeInt< T, E > SafeTtoI( U* input ) SAFEINT_CPP_THROW\n    {\n        U* tmp  = input;\n        SafeInt< T, E > s;\n        bool negative = false;\n\n        // Bad input, or empty string\n        if( input == nullptr || input[0] == 0 )\n            E::SafeIntOnOverflow();\n\n        switch( *tmp )\n        {\n        case '-':\n            tmp++;\n            negative = true;\n            break;\n        case '+':\n            tmp++;\n            break;\n        }\n\n        while( *tmp != 0 )\n        {\n            if( *tmp < '0' || *tmp > '9' )\n                break;\n\n            if( (T)s != 0 )\n                s *= (T)10;\n\n            if( !negative )\n                s += (T)( *tmp - '0' );\n            else\n                s -= (T)( *tmp - '0' );\n\n            tmp++;\n        }\n\n        return s;\n    }\n\n    T m_int;\n};\n\n// Helper function used to subtract pointers.\n// Used to squelch warnings\ntemplate <typename P>\nSafeInt<ptrdiff_t, SafeIntDefaultExceptionHandler> SafePtrDiff(const P* p1, const P* p2) SAFEINT_CPP_THROW\n{\n    return SafeInt<ptrdiff_t, SafeIntDefaultExceptionHandler>( p1 - p2 );\n}\n\n// Comparison operators\n\n//Less than\ntemplate < typename T, typename U, typename E >\nbool operator <( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator <( SafeInt<T, E> lhs, U rhs ) SAFEINT_NOTHROW\n{\n\treturn GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, (U)lhs );\n}\n\n// Greater than\ntemplate < typename T, typename U, typename E >\nbool operator >( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator >( SafeInt<T, E> lhs, U rhs ) SAFEINT_NOTHROW\n{\n\treturn GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs );\n}\n\n// Greater than or equal\ntemplate < typename T, typename U, typename E >\nbool operator >=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator >=( SafeInt<T, E> lhs, U rhs ) SAFEINT_NOTHROW\n{\n\treturn !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( (U)rhs, (T)lhs );\n}\n\n// Less than or equal\ntemplate < typename T, typename U, typename E >\nbool operator <=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator <=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs );\n}\n\n// equality\n// explicit overload for bool\ntemplate < typename T, typename E >\nbool operator ==( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return lhs == ( (T)rhs == 0 ? false : true );\n}\n\ntemplate < typename T, typename E >\nbool operator ==( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW\n{\n    return rhs == ( (T)lhs == 0 ? false : true );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator ==( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals((T)rhs, lhs);\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator ==( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW\n{\n    return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, (U)rhs );\n}\n\n//not equals\ntemplate < typename T, typename U, typename E >\nbool operator !=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)rhs, lhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator !=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW\n{\n    return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs );\n}\n\ntemplate < typename T, typename U, typename E >\nbool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( lhs, rhs );\n}\n\n\ntemplate < typename T, typename E >\nbool operator !=( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return ( (T)rhs == 0 ? false : true ) != lhs;\n}\n\ntemplate < typename T, typename E >\nbool operator !=( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW\n{\n    return ( (T)lhs == 0 ? false : true ) != rhs;\n}\n\n\ntemplate < typename T, typename U, typename E, int method > class ModulusSimpleCaseHelper;\n\ntemplate < typename T, typename E, int method > class ModulusSignedCaseHelper;\n\ntemplate < typename T, typename E > class ModulusSignedCaseHelper < T, E, true >\n{\npublic:\n    static bool SignedCase( SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_NOTHROW\n    {\n        if( (T)rhs == (T)-1 )\n        {\n            result = 0;\n            return true;\n        }\n        return false;\n    }\n};\n\ntemplate < typename T, typename E > class ModulusSignedCaseHelper < T, E, false >\n{\npublic:\n    static bool SignedCase( SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW\n    {\n        return false;\n    }\n};\n\ntemplate < typename T, typename U, typename E >\nclass ModulusSimpleCaseHelper < T, U, E, true >\n{\npublic:\n    static bool ModulusSimpleCase( U lhs, SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_CPP_THROW\n    {\n        if( rhs != 0 )\n        {\n            if( ModulusSignedCaseHelper< T, E, IntTraits< T >::isSigned >::SignedCase( rhs, result ) )\n            return true;\n\n            result = SafeInt< T, E >( (T)( lhs % (T)rhs ) );\n            return true;\n        }\n\n        E::SafeIntOnDivZero();\n    }\n};\n\ntemplate< typename T, typename U, typename E >\nclass ModulusSimpleCaseHelper < T, U, E, false >\n{\npublic:\n    static bool ModulusSimpleCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW\n    {\n        return false;\n    }\n};\n\n// Modulus\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n{\n    // Value of return depends on sign of lhs\n    // This one may not be safe - bounds check in constructor\n    // if lhs is negative and rhs is unsigned, this will throw an exception.\n\n    // Fast-track the simple case\n    // same size and same sign\n    SafeInt< T, E > result;\n\n    if( ModulusSimpleCaseHelper< T, U, E,\n        sizeof(T) == sizeof(U) && (bool)IntTraits< T >::isSigned == (bool)IntTraits< U >::isSigned >::ModulusSimpleCase( lhs, rhs, result ) )\n        return result;\n\n    return SafeInt< T, E >( ( SafeInt< U, E >( lhs ) % (T)rhs ) );\n}\n\n// Multiplication\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( (T)rhs, lhs, ret );\n    return SafeInt< T, E >(ret);\n}\n\ntemplate < typename T, typename U, typename E, int method > class DivisionNegativeCornerCaseHelper;\n\ntemplate < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, true >\n{\npublic:\n    static bool NegativeCornerCase( U lhs, SafeInt< T, E > rhs, SafeInt<T, E>& result ) SAFEINT_CPP_THROW\n    {\n        // Problem case - normal casting behavior changes meaning\n        // flip rhs to positive\n        // any operator casts now do the right thing\n        U tmp;\n\n        if( CompileConst< sizeof(T) == 4 >::Value() )\n            tmp = lhs/(U)( ~(unsigned __int32)(T)rhs + 1 );\n        else\n            tmp = lhs/(U)( ~(unsigned __int64)(T)rhs + 1 );\n\n        if( tmp <= (U)IntTraits< T >::maxInt )\n        {\n            result = SafeInt< T, E >( (T)(~(unsigned __int64)tmp + 1) );\n            return true;\n        }\n\n        // Corner case\n        T maxT = IntTraits< T >::maxInt;\n        if( tmp == (U)maxT + 1 )\n        {\n            T minT = IntTraits< T >::minInt;\n            result = SafeInt< T, E >( minT );\n            return true;\n        }\n\n        E::SafeIntOnOverflow();\n    }\n};\n\ntemplate < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, false >\n{\npublic:\n    static bool NegativeCornerCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt<T, E>& /*result*/ ) SAFEINT_NOTHROW\n    {\n        return false;\n    }\n};\n\ntemplate < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper;\n\ntemplate < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, true >\n{\npublic:\n    static bool DivisionCornerCase1( U lhs, SafeInt< T, E > rhs, SafeInt<T, E>& result ) SAFEINT_CPP_THROW\n    {\n        if( (T)rhs > 0 )\n        {\n            result = SafeInt< T, E >( lhs/(T)rhs );\n            return true;\n        }\n\n        // Now rhs is either negative, or zero\n        if( (T)rhs != 0 )\n        {\n            if( DivisionNegativeCornerCaseHelper< T, U, E, sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) >::NegativeCornerCase( lhs, rhs, result ) )\n                return true;\n\n            result = SafeInt< T, E >(lhs/(T)rhs);\n            return true;\n        }\n\n        E::SafeIntOnDivZero();\n    }\n};\n\ntemplate < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, false >\n{\npublic:\n    static bool DivisionCornerCase1( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt<T, E>& /*result*/ ) SAFEINT_NOTHROW\n    {\n        return false;\n    }\n};\n\ntemplate < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper2;\n\ntemplate < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, true >\n{\npublic:\n    static bool DivisionCornerCase2( U lhs, SafeInt< T, E > rhs, SafeInt<T, E>& result ) SAFEINT_CPP_THROW\n    {\n        if( lhs == IntTraits< U >::minInt && (T)rhs == -1 )\n        {\n            // corner case of a corner case - lhs = min int, rhs = -1,\n            // but rhs is the return type, so in essence, we can return -lhs\n            // if rhs is a larger type than lhs\n            // If types are wrong, throws\n\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n#pragma warning(push)\n//cast truncates constant value\n#pragma warning(disable:4310)\n#endif\n\n            if( CompileConst<sizeof( U ) < sizeof( T )>::Value() )\n                result = SafeInt< T, E >( (T)( -(T)IntTraits< U >::minInt ) );\n            else\n                E::SafeIntOnOverflow();\n\n#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER\n#pragma warning(pop)\n#endif\n\n            return true;\n        }\n\n        return false;\n    }\n};\n\ntemplate < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, false >\n{\npublic:\n    static bool DivisionCornerCase2( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt<T, E>& /*result*/ ) SAFEINT_NOTHROW\n    {\n        return false;\n    }\n};\n\n// Division\ntemplate < typename T, typename U, typename E > SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n{\n    // Corner case - has to be handled seperately\n    SafeInt< T, E > result;\n    if( DivisionCornerCaseHelper< T, U, E, (int)DivisionMethod< U, T >::method == (int)DivisionState_UnsignedSigned >::DivisionCornerCase1( lhs, rhs, result ) )\n        return result;\n\n    if( DivisionCornerCaseHelper2< T, U, E, SafeIntCompare< T, U >::isBothSigned >::DivisionCornerCase2( lhs, rhs, result ) )\n        return result;\n\n    // Otherwise normal logic works with addition of bounds check when casting from U->T\n    U ret;\n    DivisionHelper< U, T, DivisionMethod< U, T >::method >::template DivideThrow< E >( lhs, (T)rhs, ret );\n    return SafeInt< T, E >( ret );\n}\n\n// Addition\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( (T)rhs, lhs, ret );\n    return SafeInt< T, E >( ret );\n}\n\n// Subtraction\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    SubtractionHelper< U, T, SubtractionMethod2< U, T >::method >::template SubtractThrow< E >( lhs, rhs.Ref(), ret );\n\n    return SafeInt< T, E >( ret );\n}\n\n// Overrides designed to deal with cases where a SafeInt is assigned out\n// to a normal int - this at least makes the last operation safe\n// +=\ntemplate < typename T, typename U, typename E >\nT& operator +=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( lhs, (U)rhs, ret );\n    lhs = ret;\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator -=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( lhs, (U)rhs, ret );\n    lhs = ret;\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator *=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( lhs, (U)rhs, ret );\n    lhs = ret;\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator /=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( lhs, (U)rhs, ret );\n    lhs = ret;\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator %=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    T ret( 0 );\n    ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( lhs, (U)rhs, ret );\n    lhs = ret;\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator &=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    lhs = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( lhs, (U)rhs );\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator ^=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    lhs = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( lhs, (U)rhs );\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator |=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    lhs = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( lhs, (U)rhs );\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator <<=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs );\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW\n{\n    lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs );\n    return lhs;\n}\n\n// Specific pointer overrides\n// Note - this function makes no attempt to ensure\n// that the resulting pointer is still in the buffer, only\n// that no int overflows happened on the way to getting the new pointer\ntemplate < typename T, typename U, typename E >\nT*& operator +=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    // Cast the pointer to a number so we can do arithmetic\n    SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs );\n    // Check first that rhs is valid for the type of ptrdiff_t\n    // and that multiplying by sizeof( T ) doesn't overflow a ptrdiff_t\n    // Next, we need to add 2 SafeInts of different types, so unbox the ptr_diff\n    // Finally, cast the number back to a pointer of the correct type\n    lhs = reinterpret_cast< T* >( (size_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator -=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW\n{\n    // Cast the pointer to a number so we can do arithmetic\n    SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs );\n    // See above for comments\n    lhs = reinterpret_cast< T* >( (size_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );\n    return lhs;\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator *=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator /=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator %=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator &=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator ^=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator |=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator <<=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\ntemplate < typename T, typename U, typename E >\nT*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW\n{\n    // This operator explicitly not supported\n    C_ASSERT( sizeof(T) == 0 );\n    return (lhs = NULL);\n}\n\n// Shift operators\n// NOTE - shift operators always return the type of the lhs argument\n\n// Left shift\ntemplate < typename T, typename U, typename E >\nSafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW\n{\n    ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 );\n    ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount );\n\n    return SafeInt< U, E >( (U)( lhs << (T)bits ) );\n}\n\n// Right shift\ntemplate < typename T, typename U, typename E >\nSafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW\n{\n    ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 );\n    ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount );\n\n    return SafeInt< U, E >( (U)( lhs >> (T)bits ) );\n}\n\n// Bitwise operators\n// This only makes sense if we're dealing with the same type and size\n// demand a type T, or something that fits into a type T.\n\n// Bitwise &\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( (T)rhs, lhs ) );\n}\n\n// Bitwise XOR\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return SafeInt< T, E >(BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( (T)rhs, lhs ) );\n}\n\n// Bitwise OR\ntemplate < typename T, typename U, typename E >\nSafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW\n{\n    return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( (T)rhs, lhs ) );\n}\n\n#if SAFEINT_COMPILER == GCC_COMPILER\n#pragma GCC diagnostic pop\n#endif\n\n#if SAFEINT_COMPILER == CLANG_COMPILER\n#pragma clang diagnostic pop\n#endif\n\n} // utilities\n} // safeint3\n\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/asyncrt_utils.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Utilities\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#if defined(_WIN32)\n#if HC_PLATFORM != HC_PLATFORM_XDK\n#include <winhttp.h>\n#endif\n#else // _WIN32\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-local-typedef\"\n#endif\n// TODO 1808 #include <boost/date_time/posix_time/posix_time.hpp>\n// #include <boost/date_time/posix_time/posix_time_io.hpp>\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n#endif // _WIN32\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#pragma warning( disable : 26498 ) // ignore eof warning \n#pragma warning( disable : 26812 )  // enum instead of enum class\n#pragma warning( disable : 4365 )  \n#endif\n\n// Could use C++ standard library if not __GLIBCXX__,\n// For testing purposes we just the handwritten on all platforms.\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n#include <codecvt>\n#endif\n\nusing namespace web;\nusing namespace utility;\nusing namespace utility::conversions;\n\n\nnamespace utility\n{\n\nnamespace details\n{\n\n#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(PAVO)\nstd::once_flag g_c_localeFlag;\nstd::unique_ptr<scoped_c_thread_locale::xplat_locale, void(*)(scoped_c_thread_locale::xplat_locale *)> g_c_locale(nullptr, [](scoped_c_thread_locale::xplat_locale *){});\nscoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale()\n{\n    std::call_once(g_c_localeFlag, [&]()\n    {\n        scoped_c_thread_locale::xplat_locale *clocale = new scoped_c_thread_locale::xplat_locale();\n#ifdef _WIN32\n        if (clocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to create 'C' locale.\");\n        }\n        *clocale = _create_locale(LC_ALL, \"C\");\n        if (clocale == nullptr || *clocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to create 'C' locale.\");\n        }\n        auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale)\n        {\n            _free_locale(*clocale);\n            delete clocale;\n        };\n#else\n        *clocale = newlocale(LC_ALL, \"C\", nullptr);\n        if (clocale == nullptr || *clocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to create 'C' locale.\");\n        }\n        auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale)\n        {\n            freelocale(*clocale);\n            delete clocale;\n        };\n#endif\n        g_c_locale = std::unique_ptr<scoped_c_thread_locale::xplat_locale, void(*)(scoped_c_thread_locale::xplat_locale *)>(clocale, deleter);\n    });\n    return *g_c_locale;\n}\n#endif\n\n#ifdef _WIN32\nscoped_c_thread_locale::scoped_c_thread_locale()\n    : m_prevLocale(), m_prevThreadSetting(-1)\n{\n    char *prevLocale = setlocale(LC_ALL, nullptr);\n    if (prevLocale == nullptr)\n    {\n        throw std::runtime_error(\"Unable to retrieve current locale.\");\n    }\n\n    if (std::strcmp(prevLocale, \"C\") != 0)\n    {\n        m_prevLocale = prevLocale;\n        m_prevThreadSetting = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);\n        if (m_prevThreadSetting == -1)\n        {\n            throw std::runtime_error(\"Unable to enable per thread locale.\");\n        }\n        if (setlocale(LC_ALL, \"C\") == nullptr)\n        {\n             _configthreadlocale(m_prevThreadSetting);\n             throw std::runtime_error(\"Unable to set locale\");\n        }\n    }\n}\n\nscoped_c_thread_locale::~scoped_c_thread_locale()\n{\n    if (m_prevThreadSetting != -1)\n    {\n        setlocale(LC_ALL, m_prevLocale.c_str());\n        _configthreadlocale(m_prevThreadSetting);\n    }\n}\n#elif (defined(ANDROID) || defined(__ANDROID__) || defined(PAVO))\nscoped_c_thread_locale::scoped_c_thread_locale() {}\nscoped_c_thread_locale::~scoped_c_thread_locale() {}\n#else\nscoped_c_thread_locale::scoped_c_thread_locale()\n    : m_prevLocale(nullptr)\n{\n    char *prevLocale = setlocale(LC_ALL, nullptr);\n    if (prevLocale == nullptr)\n    {\n        throw std::runtime_error(\"Unable to retrieve current locale.\");\n    }\n\n    if (std::strcmp(prevLocale, \"C\") != 0)\n    {\n        m_prevLocale = uselocale(c_locale());\n        if (m_prevLocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to set locale\");\n        }\n    }\n}\n\nscoped_c_thread_locale::~scoped_c_thread_locale()\n{\n    if (m_prevLocale != nullptr)\n    {\n        uselocale(m_prevLocale);\n    }\n}\n#endif\n}\n\nnamespace details\n{\n\nconst std::error_category & __cdecl platform_category()\n{\n#ifdef _WIN32\n    return windows_category();\n#else\n    return linux_category();\n#endif\n}\n\n#ifdef _WIN32\n\n// Remove once VS 2013 is no longer supported.\n#if _MSC_VER < 1900\nstatic details::windows_category_impl instance;\n#endif\nconst std::error_category & __cdecl windows_category()\n{\n#if _MSC_VER >= 1900\n    static details::windows_category_impl instance;\n#endif\n    return instance;\n}\n\nstd::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT\n{\n    const size_t buffer_size = 4096;\n    DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;\n    LPCVOID lpSource = NULL;\n\n#if !defined(__cplusplus_winrt)\n    if (errorCode >= 12000)\n    {\n        dwFlags = FORMAT_MESSAGE_FROM_HMODULE;\n        lpSource = GetModuleHandleA(\"winhttp.dll\"); // this handle DOES NOT need to be freed\n    }\n#endif\n\n    std::wstring buffer;\n    buffer.resize(buffer_size);\n\n    const auto result = ::FormatMessageW(\n        dwFlags,\n        lpSource,\n        errorCode,\n        0,\n        &buffer[0],\n        buffer_size,\n        NULL);\n    if (result == 0)\n    {\n        std::ostringstream os;\n        os << \"Unable to get an error message for error code: \" << errorCode << \".\";\n        return os.str();\n    }\n\n    return utility::conversions::to_utf8string(buffer);\n}\n\nstd::error_condition windows_category_impl::default_error_condition(int errorCode) const CPPREST_NOEXCEPT\n{\n    // First see if the STL implementation can handle the mapping for common cases.\n    const std::error_condition errCondition = std::system_category().default_error_condition(errorCode);\n    const std::string errConditionMsg = errCondition.message();\n    if(_stricmp(errConditionMsg.c_str(), \"unknown error\") != 0)\n    {\n        return errCondition;\n    }\n\n    switch(errorCode)\n    {\n#ifndef __cplusplus_winrt\n    case ERROR_WINHTTP_TIMEOUT:\n        return std::errc::timed_out;\n    case ERROR_WINHTTP_CANNOT_CONNECT:\n        return std::errc::host_unreachable;\n    case ERROR_WINHTTP_CONNECTION_ERROR:\n        return std::errc::connection_aborted;\n#endif\n    case INET_E_RESOURCE_NOT_FOUND:\n    case INET_E_CANNOT_CONNECT:\n        return std::errc::host_unreachable;\n    case INET_E_CONNECTION_TIMEOUT:\n        return std::errc::timed_out;\n    case INET_E_DOWNLOAD_FAILURE:\n        return std::errc::connection_aborted;\n    default:\n        break;\n    }\n\n    return std::error_condition(errorCode, *this);\n}\n\n#else\n\nconst std::error_category & __cdecl linux_category()\n{\n    // On Linux we are using boost error codes which have the exact same\n    // mapping and are equivalent with std::generic_category error codes.\n    return std::generic_category();\n}\n\n#endif\n\n}\n\n#define LOW_3BITS 0x7\n#define LOW_4BITS 0xF\n#define LOW_5BITS 0x1F\n#define LOW_6BITS 0x3F\n#define BIT4 0x8\n#define BIT5 0x10\n#define BIT6 0x20\n#define BIT7 0x40\n#define BIT8 0x80\n#define L_SURROGATE_START 0xDC00\n#define L_SURROGATE_END 0xDFFF\n#define H_SURROGATE_START 0xD800\n#define H_SURROGATE_END 0xDBFF\n#define SURROGATE_PAIR_START 0x10000\n\nutf16string __cdecl conversions::utf8_to_utf16(const std::string &s)\n{\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n    std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n    return conversion.from_bytes(s);\n#else\n    utf16string dest;\n    // Save repeated heap allocations, use less than source string size assuming some\n    // of the characters are not just ASCII and collapse.\n    dest.reserve(static_cast<size_t>(static_cast<double>(s.size()) * .70));\n    \n    for (auto src = s.begin(); src != s.end(); ++src)\n    {\n        if ((*src & BIT8) == 0) // single byte character, 0x0 to 0x7F\n        {\n            dest.push_back(utf16string::value_type(*src));\n        }\n        else\n        {\n            unsigned char numContBytes = 0;\n            uint32_t codePoint;\n            if ((*src & BIT7) == 0)\n            {\n                throw std::range_error(\"UTF-8 string character can never start with 10xxxxxx\");\n            }\n            else if ((*src & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF\n            {\n                codePoint = *src & LOW_5BITS;\n                numContBytes = 1;\n            }\n            else if ((*src & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF\n            {\n                codePoint = *src & LOW_4BITS;\n                numContBytes = 2;\n            }\n            else if ((*src & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF\n            {\n                codePoint = *src & LOW_3BITS;\n                numContBytes = 3;\n            }\n            else\n            {\n                throw std::range_error(\"UTF-8 string has invalid Unicode code point\");\n            }\n\n            for (unsigned char i = 0; i < numContBytes; ++i)\n            {\n                if (++src == s.end())\n                {\n                    throw std::range_error(\"UTF-8 string is missing bytes in character\");\n                }\n                if ((*src & BIT8) == 0 || (*src & BIT7) != 0)\n                {\n                    throw std::range_error(\"UTF-8 continuation byte is missing leading byte\");\n                }\n                codePoint <<= 6;\n                codePoint |= *src & LOW_6BITS;\n            }\n\n            if (codePoint >= SURROGATE_PAIR_START)\n            {\n                // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs.\n                //  - 0x10000 is subtracted from the code point\n                //  - high surrogate is 0xD800 added to the top ten bits\n                //  - low surrogate is 0xDC00 added to the low ten bits\n                codePoint -= SURROGATE_PAIR_START;\n                dest.push_back(utf16string::value_type((codePoint >> 10) | H_SURROGATE_START));\n                dest.push_back(utf16string::value_type((codePoint & 0x3FF) | L_SURROGATE_START));\n            }\n            else\n            {\n                // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value.\n                // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode\n                // them if encountered.\n                dest.push_back(utf16string::value_type(codePoint));\n            }\n        }\n    }\n    return dest;\n#endif\n}\n\nstd::string __cdecl conversions::utf16_to_utf8(const utf16string &w)\n{\n #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n     std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n     return conversion.to_bytes(w);\n #else\n    std::string dest;\n    dest.reserve(w.size());\n    for (auto src = w.begin(); src != w.end(); ++src)\n    {\n        // Check for high surrogate.\n        if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END)\n        {\n            const auto highSurrogate = *src++;\n            if (src == w.end())\n            {\n                throw std::range_error(\"UTF-16 string is missing low surrogate\");\n            }\n            const auto lowSurrogate = *src;\n            if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END)\n            {\n                throw std::range_error(\"UTF-16 string has invalid low surrogate\");\n            }\n\n            // To get from surrogate pair to Unicode code point:\n            // - subract 0xD800 from high surrogate, this forms top ten bits\n            // - subract 0xDC00 from low surrogate, this forms low ten bits\n            // - add 0x10000\n            // Leaves a code point in U+10000 to U+10FFFF range.\n            uint32_t codePoint = highSurrogate - H_SURROGATE_START;\n            codePoint <<= 10;\n            codePoint |= lowSurrogate - L_SURROGATE_START;\n            codePoint += SURROGATE_PAIR_START;\n\n            // 4 bytes need using 21 bits\n            dest.push_back(char((codePoint >> 18) | 0xF0));                 // leading 3 bits\n            dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8));   // next 6 bits\n            dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8));    // next 6 bits\n            dest.push_back(char((codePoint & LOW_6BITS) | BIT8));           // trailing 6 bits\n        }\n        else\n        {\n            if (*src <= 0x7F) // single byte character\n            {\n                dest.push_back(static_cast<char>(*src));\n            }\n            else if (*src <= 0x7FF) // 2 bytes needed (11 bits used)\n            {\n                dest.push_back(char((*src >> 6) | 0xC0));               // leading 5 bits\n                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n            }\n            else // 3 bytes needed (16 bits used)\n            {\n                dest.push_back(char((*src >> 12) | 0xE0));              // leading 4 bits\n                dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits\n                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n            }\n        }\n    }\n\n    return dest;\n #endif\n}\n\nutf16string __cdecl conversions::usascii_to_utf16(const std::string &s)\n{\n    // Ascii is a subset of UTF-8 so just convert to UTF-16\n    return utf8_to_utf16(s);\n}\n\nutf16string __cdecl conversions::latin1_to_utf16(const std::string &s)\n{\n    // Latin1 is the first 256 code points in Unicode.\n    // In UTF-16 encoding each of these is represented as exactly the numeric code point.\n    utf16string dest;\n    dest.resize(s.size());\n    for (size_t i = 0; i < s.size(); ++i)\n    {\n        dest[i] = utf16char(static_cast<unsigned char>(s[i]));\n    }\n    return dest;\n}\n\nutf8string __cdecl conversions::latin1_to_utf8(const std::string &s)\n{\n    return utf16_to_utf8(latin1_to_utf16(s));\n}\n\nutility::string_t __cdecl conversions::to_string_t(utf16string &&s)\n{\n#ifdef _UTF16_STRINGS\n    return std::move(s);\n#else\n    return utf16_to_utf8(std::move(s));\n#endif\n}\n\nutility::string_t __cdecl conversions::to_string_t(std::string &&s)\n{\n#ifdef _UTF16_STRINGS\n    return utf8_to_utf16(std::move(s));\n#else\n    return std::move(s);\n#endif\n}\n\nutility::string_t __cdecl conversions::to_string_t(const utf16string &s)\n{\n#ifdef _UTF16_STRINGS\n    return s;\n#else\n    return utf16_to_utf8(s);\n#endif\n}\n\nutility::string_t __cdecl conversions::to_string_t(const std::string &s)\n{\n#ifdef _UTF16_STRINGS\n    return utf8_to_utf16(s);\n#else\n    return s;\n#endif\n}\n\nstd::string __cdecl conversions::to_utf8string(std::string value) { return value; }\n\nstd::string __cdecl conversions::to_utf8string(const utf16string &value) { return utf16_to_utf8(value); }\n\nutf16string __cdecl conversions::to_utf16string(const std::string &value) { return utf8_to_utf16(value); }\n\nutf16string __cdecl conversions::to_utf16string(utf16string value) { return value; }\n\n#ifndef _WIN32\ndatetime datetime::timeval_to_datetime(const timeval &time)\n{\n    const uint64_t epoch_offset = 11644473600LL; // diff between windows and unix epochs (seconds)\n    uint64_t result = epoch_offset + time.tv_sec;\n    result *= _secondTicks; // convert to 10e-7\n    result += time.tv_usec * 10; // convert and add microseconds, 10e-6 to 10e-7\n    return datetime(result);\n}\n#endif\n\nstatic bool is_digit(utility::char_t c) { return c >= _XPLATSTR('0') && c <= _XPLATSTR('9'); }\n\ndatetime __cdecl datetime::utc_now()\n{\n#ifdef _WIN32\n    ULARGE_INTEGER largeInt;\n    FILETIME fileTime;\n    GetSystemTimeAsFileTime(&fileTime);\n\n    largeInt.LowPart = fileTime.dwLowDateTime;\n    largeInt.HighPart = fileTime.dwHighDateTime;\n\n    return datetime(largeInt.QuadPart);\n#else //LINUX\n    timeval time {};\n    gettimeofday(&time, nullptr);\n    return timeval_to_datetime(time);\n#endif\n}\n\nutility::string_t datetime::to_string(date_format format) const\n{\n#ifdef _WIN32\n    int status;\n\n    ULARGE_INTEGER largeInt;\n    largeInt.QuadPart = m_interval;\n\n    FILETIME ft;\n    ft.dwHighDateTime = largeInt.HighPart;\n    ft.dwLowDateTime = largeInt.LowPart;\n\n    SYSTEMTIME systemTime;\n    if (!FileTimeToSystemTime((const FILETIME *)&ft, &systemTime))\n    {\n        throw utility::details::create_system_error(GetLastError());\n    }\n\n    std::wostringstream outStream;\n    outStream.imbue(std::locale::classic());\n\n    if (format == RFC_1123)\n    {\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        TCHAR dateStr[18] = {0};\n        status = GetDateFormat(LOCALE_INVARIANT, 0, &systemTime, __TEXT(\"ddd',' dd MMM yyyy\"), dateStr, sizeof(dateStr) / sizeof(TCHAR));\n#else\n        wchar_t dateStr[18] = {0};\n        status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L\"ddd',' dd MMM yyyy\", dateStr, sizeof(dateStr) / sizeof(wchar_t), NULL);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        TCHAR timeStr[10] = {0};\n        status = GetTimeFormat(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, __TEXT(\"HH':'mm':'ss\"), timeStr, sizeof(timeStr) / sizeof(TCHAR));\n#else\n        wchar_t timeStr[10] = {0};\n        status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, sizeof(timeStr) / sizeof(wchar_t));\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        outStream << dateStr << \" \" << timeStr << \" \" << \"GMT\";\n    }\n    else if (format == ISO_8601)\n    {\n        const size_t buffSize = 64;\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        TCHAR dateStr[buffSize] = {0};\n        status = GetDateFormat(LOCALE_INVARIANT, 0, &systemTime, __TEXT(\"yyyy-MM-dd\"), dateStr, buffSize);\n#else\n        wchar_t dateStr[buffSize] = {0};\n        status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L\"yyyy-MM-dd\", dateStr, buffSize, NULL);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        TCHAR timeStr[buffSize] = {0};\n        status = GetTimeFormat(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, __TEXT(\"HH':'mm':'ss\"), timeStr, buffSize);\n#else\n        wchar_t timeStr[buffSize] = {0};\n        status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, buffSize);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        outStream << dateStr << \"T\" << timeStr;\n        uint64_t frac_sec = largeInt.QuadPart % _secondTicks;\n        if (frac_sec > 0)\n        {\n            // Append fractional second, which is a 7-digit value with no trailing zeros\n            // This way, '1200' becomes '00012'\n            char buf[9] = { 0 };\n            sprintf_s(buf, sizeof(buf), \".%07ld\", (long int)frac_sec);\n            // trim trailing zeros\n            for (int i = 7; buf[i] == '0'; i--) buf[i] = '\\0';\n            outStream << buf;\n        }\n        outStream << \"Z\";\n    }\n\n    return outStream.str();\n#else //LINUX\n    uint64_t input = m_interval;\n    uint64_t frac_sec = input % _secondTicks;\n    input /= _secondTicks; // convert to seconds\n    time_t time = (time_t)input - (time_t)11644473600LL;// diff between windows and unix epochs (seconds)\n\n    struct tm datetime;\n#if defined(PAVO)\n    gmtime_s(&time, &datetime);\n#else\n    gmtime_r(&time, &datetime);\n#endif // PAVO\n\n    const int max_dt_length = 64;\n    char output[max_dt_length+1] = {0};\n\n    if (format != RFC_1123 && frac_sec > 0)\n    {\n        // Append fractional second, which is a 7-digit value with no trailing zeros\n        // This way, '1200' becomes '00012'\n        char buf[9] = { 0 };\n        snprintf(buf, sizeof(buf), \".%07ld\", (long int)frac_sec);\n        // trim trailing zeros\n        for (int i = 7; buf[i] == '0'; i--) buf[i] = '\\0';\n        // format the datetime into a separate buffer\n        char datetime_str[max_dt_length+1] = {0};\n        strftime(datetime_str, sizeof(datetime_str), \"%Y-%m-%dT%H:%M:%S\", &datetime);\n        // now print this buffer into the output buffer\n        snprintf(output, sizeof(output), \"%s%sZ\", datetime_str, buf);\n    }\n    else\n    {\n        strftime(output, sizeof(output),\n            format == RFC_1123 ? \"%a, %d %b %Y %H:%M:%S GMT\" : \"%Y-%m-%dT%H:%M:%SZ\",\n            &datetime);\n    }\n\n    return std::string(output);\n#endif\n}\n\n#ifdef _WIN32\nbool __cdecl datetime::system_type_to_datetime(void* pvsysTime, uint64_t seconds, datetime * pdt)\n{\n    SYSTEMTIME* psysTime = (SYSTEMTIME*)pvsysTime;\n    FILETIME fileTime;\n\n    if (SystemTimeToFileTime(psysTime, &fileTime))\n    {\n        ULARGE_INTEGER largeInt;\n        largeInt.LowPart = fileTime.dwLowDateTime;\n        largeInt.HighPart = fileTime.dwHighDateTime;\n\n        // Add hundredths of nanoseconds\n        largeInt.QuadPart += seconds;\n\n        *pdt = datetime(largeInt.QuadPart);\n        return true;\n    }\n    return false;\n}\n#endif\n\n// Take a string that represents a fractional second and return the number of ticks\n// This is equivalent to doing atof on the string and multiplying by 10000000,\n// but does not lose precision\ntemplate<typename StringIterator>\nuint64_t timeticks_from_second(StringIterator begin, StringIterator end)\n{\n    int size = (int)(end - begin);\n    _ASSERTE(begin[0] == _T('.'));\n    uint64_t ufrac_second = 0;\n    for (int i = 1; i <= 7; ++i)\n    {\n        ufrac_second *= 10;\n        int add = i < size ? begin[i] - _T('0') : 0;\n        ufrac_second += add;\n    }\n    return ufrac_second;\n}\n\nvoid extract_fractional_second(const utility::string_t& dateString, utility::string_t& resultString, uint64_t& ufrac_second)\n{\n    resultString = dateString;\n    // First, the string must be strictly longer than 2 characters, and the trailing character must be 'Z'\n    if (resultString.size() > 2 && resultString[resultString.size() - 1] == _T('Z'))\n    {\n        // Second, find the last non-digit by scanning the string backwards\n        auto last_non_digit = std::find_if_not(resultString.rbegin() + 1, resultString.rend(), is_digit);\n        if (last_non_digit < resultString.rend() - 1)\n        {\n            // Finally, make sure the last non-digit is a dot:\n            auto last_dot = last_non_digit.base() - 1;\n            if (*last_dot == _T('.'))\n            {\n                // Got it! Now extract the fractional second\n                auto last_before_Z = std::end(resultString) - 1;\n                ufrac_second = timeticks_from_second(last_dot, last_before_Z);\n                // And erase it from the string\n                resultString.erase(last_dot, last_before_Z);\n            }\n        }\n    }\n}\n\ndatetime __cdecl datetime::from_string(const utility::string_t& dateString, date_format format)\n{\n    // avoid floating point math to preserve precision\n    uint64_t ufrac_second = 0;\n\n#ifdef _WIN32\n    datetime result;\n    if (format == RFC_1123)\n    {\n        SYSTEMTIME sysTime = {0};\n\n        std::wstring month(3, L'\\0');\n        std::wstring unused(3, L'\\0');\n\n        const wchar_t * formatString = L\"%3c, %2d %3c %4d %2d:%2d:%2d %3c\";\n        auto n = swscanf_s(dateString.c_str(), formatString,\n            unused.data(), unused.size(),\n            &sysTime.wDay,\n            month.data(), month.size(),\n            &sysTime.wYear,\n            &sysTime.wHour,\n            &sysTime.wMinute,\n            &sysTime.wSecond,\n            unused.data(), unused.size());\n\n        if (n == 8)\n        {\n            std::wstring monthnames[12] = {L\"Jan\", L\"Feb\", L\"Mar\", L\"Apr\", L\"May\", L\"Jun\", L\"Jul\", L\"Aug\", L\"Sep\", L\"Oct\", L\"Nov\", L\"Dec\"};\n            auto loc = std::find_if(monthnames, monthnames+12, [&month](const std::wstring& m) { return m == month;});\n\n            if (loc != monthnames+12)\n            {\n                sysTime.wMonth = (short) ((loc - monthnames) + 1);\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (format == ISO_8601)\n    {\n        // Unlike FILETIME, SYSTEMTIME does not have enough precision to hold seconds in 100 nanosecond\n        // increments. Therefore, start with seconds and milliseconds set to 0, then add them separately\n\n        // Try to extract the fractional second from the timestamp\n        utility::string_t input;\n        extract_fractional_second(dateString, input, ufrac_second);\n        {\n            SYSTEMTIME sysTime = { 0 };\n            const wchar_t * formatString = L\"%4d-%2d-%2dT%2d:%2d:%2dZ\";\n            auto n = swscanf_s(input.c_str(), formatString,\n                &sysTime.wYear,\n                &sysTime.wMonth,\n                &sysTime.wDay,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond);\n\n            if (n == 3 || n == 6)\n            {\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n        {\n            SYSTEMTIME sysTime = {0};\n            DWORD date = 0;\n\n            const wchar_t * formatString = L\"%8dT%2d:%2d:%2dZ\";\n            auto n = swscanf_s(input.c_str(), formatString,\n                &date,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond);\n\n            if (n == 1 || n == 4)\n            {\n                sysTime.wDay = date % 100;\n                date /= 100;\n                sysTime.wMonth = date % 100;\n                date /= 100;\n                sysTime.wYear = (WORD)date;\n\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n        {\n            SYSTEMTIME sysTime = {0};\n            GetSystemTime(&sysTime);    // Fill date portion with today's information\n            sysTime.wSecond = 0;\n            sysTime.wMilliseconds = 0;\n\n            const wchar_t * formatString = L\"%2d:%2d:%2dZ\";\n            auto n = swscanf_s(input.c_str(), formatString,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond);\n\n            if (n == 3)\n            {\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n    }\n\n    return datetime();\n#else\n    std::string input(dateString);\n\n    struct tm output = tm();\n\n    if (format == RFC_1123)\n    {\n        strptime(input.data(), \"%a, %d %b %Y %H:%M:%S GMT\", &output);\n    }\n    else\n    {\n        // Try to extract the fractional second from the timestamp\n        utility::string_t input;\n        extract_fractional_second(dateString, input, ufrac_second);\n\n        auto result = strptime(input.data(), \"%Y-%m-%dT%H:%M:%SZ\", &output);\n\n        if (result == nullptr)\n        {\n            result = strptime(input.data(), \"%Y%m%dT%H:%M:%SZ\", &output);\n        }\n        if (result == nullptr)\n        {\n            // Fill the date portion with the epoch,\n            // strptime will do the rest\n            memset(&output, 0, sizeof(struct tm));\n            output.tm_year = 70;\n            output.tm_mon = 1;\n            output.tm_mday = 1;\n            result = strptime(input.data(), \"%H:%M:%SZ\", &output);\n        }\n        if (result == nullptr)\n        {\n            result = strptime(input.data(), \"%Y-%m-%d\", &output);\n        }\n        if (result == nullptr)\n        {\n            result = strptime(input.data(), \"%Y%m%d\", &output);\n        }\n        if (result == nullptr)\n        {\n            return datetime();\n        }\n    }\n\n#if (defined(ANDROID) || defined(__ANDROID__))\n    // HACK: The (nonportable?) POSIX function timegm is not available in\n    //       bionic. As a workaround[1][2], we set the C library timezone to\n    //       UTC, call mktime, then set the timezone back. However, the C\n    //       environment is fundamentally a shared global resource and thread-\n    //       unsafe. We can protect our usage here, however any other code might\n    //       manipulate the environment at the same time.\n    //\n    // [1] http://linux.die.net/man/3/timegm\n    // [2] http://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html\n    time_t time;\n\n    static std::mutex env_var_lock;\n    {\n        std::lock_guard<std::mutex> lock(env_var_lock);\n        std::string prev_env;\n        auto prev_env_cstr = getenv(\"TZ\");\n        if (prev_env_cstr != nullptr)\n        {\n            prev_env = prev_env_cstr;\n        }\n        setenv(\"TZ\", \"UTC\", 1);\n\n        time = mktime(&output);\n\n        if (prev_env_cstr)\n        {\n            setenv(\"TZ\", prev_env.c_str(), 1);\n        }\n        else\n        {\n            unsetenv(\"TZ\");\n        }\n        tzset();\n    }\n#else\n    time_t time = timegm(&output);\n#endif\n    struct timeval tv = timeval();\n    tv.tv_sec = time;\n    auto result = timeval_to_datetime(tv);\n\n    // fractional seconds are already in correct format so just add them.\n    result = result + ufrac_second;\n    return result;\n#endif\n}\n\n/// <summary>\n/// Converts a timespan/interval in seconds to xml duration string as specified by\n/// http://www.w3.org/TR/xmlschema-2/#duration\n/// </summary>\nutility::string_t __cdecl timespan::seconds_to_xml_duration(utility::seconds durationSecs)\n{\n    auto numSecs = durationSecs.count();\n\n    // Find the number of minutes\n    auto numMins =  numSecs / 60;\n    if (numMins > 0)\n    {\n        numSecs = numSecs % 60;\n    }\n\n    // Hours\n    auto numHours = numMins / 60;\n    if (numHours > 0)\n    {\n        numMins = numMins % 60;\n    }\n\n    // Days\n    auto numDays = numHours / 24;\n    if (numDays > 0)\n    {\n        numHours = numHours % 24;\n    }\n\n    // The format is:\n    // PdaysDThoursHminutesMsecondsS\n    utility::ostringstream_t oss;\n    oss.imbue(std::locale::classic());\n\n    oss << _XPLATSTR(\"P\");\n    if (numDays > 0)\n    {\n        oss << numDays << _XPLATSTR(\"D\");\n    }\n\n    oss << _XPLATSTR(\"T\");\n\n    if (numHours > 0)\n    {\n        oss << numHours << _XPLATSTR(\"H\");\n    }\n\n    if (numMins > 0)\n    {\n        oss << numMins << _XPLATSTR(\"M\");\n    }\n\n    if (numSecs > 0)\n    {\n        oss << numSecs << _XPLATSTR(\"S\");\n    }\n\n    return oss.str();\n}\n\nutility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string_t &timespanString)\n{\n    // The format is:\n    // PnDTnHnMnS\n    // if n == 0 then the field could be omitted\n    // The final S could be omitted\n\n    int64_t numSecs = 0;\n\n    utility::istringstream_t is(timespanString);\n    is.imbue(std::locale::classic());\n    auto eof = std::char_traits<utility::char_t>::eof();\n\n    std::basic_istream<utility::char_t>::int_type c;\n    c = is.get(); // P\n\n    while (c != eof)\n    {\n        int val = 0;\n        c = is.get();\n\n        while (is_digit((utility::char_t)c))\n        {\n            val = val * 10 + (c - L'0');\n            c = is.get();\n\n            if (c == '.')\n            {\n                // decimal point is not handled\n                do { c = is.get(); } while(is_digit((utility::char_t)c));\n            }\n        }\n\n        if (c == L'D') numSecs += static_cast<int64_t>(val) * 24 * 3600; // days\n        if (c == L'H') numSecs += static_cast<int64_t>(val) * 3600; // Hours\n        if (c == L'M') numSecs += static_cast<int64_t>(val) * 60; // Minutes\n        if (c == L'S' || c == eof)\n        {\n            numSecs += val; // seconds\n            break;\n        }\n    }\n\n    return utility::seconds(numSecs);\n}\n\nconst utility::char_t * nonce_generator::c_allowed_chars = _XPLATSTR(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\");\n\nutility::string_t nonce_generator::generate()\n{\n    std::uniform_int_distribution<> distr(0, static_cast<int>(ustrlen(c_allowed_chars) - 1));\n    utility::string_t result;\n    result.reserve(length());\n    std::generate_n(std::back_inserter(result), length(), [&]() { return c_allowed_chars[distr(m_random)]; } );\n    return result;\n}\n\n\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/base64.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\nusing namespace web;\nusing namespace utility;\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 28020 ) // ignore expression validation\n#pragma warning( disable : 4365 )  \n#endif\n\nstd::vector<unsigned char> _from_base64(const utility::string_t& str);\nutility::string_t _to_base64(const unsigned char *ptr, size_t size);\n\nstd::vector<unsigned char> __cdecl conversions::from_base64(const utility::string_t& str)\n{\n    return _from_base64(str);\n}\n\nutility::string_t __cdecl conversions::to_base64(const unsigned char* data, size_t dataSize)\n{\n    return _to_base64(data, dataSize);\n}\n\nutility::string_t __cdecl conversions::to_base64(const std::vector<unsigned char>& input)\n{\n    if (input.size() == 0)\n    {\n        // return empty string\n        return utility::string_t();\n    }\n\n    return _to_base64(&input[0], input.size());\n}\n\nutility::string_t __cdecl conversions::to_base64(uint64_t input)\n{\n    return _to_base64(reinterpret_cast<const unsigned char*>(&input), sizeof(input));\n}\n\nstatic const char* _base64_enctbl = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nconst std::array<unsigned char, 128> _base64_dectbl =\n   {{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,\n       52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255, 254, 255, 255,\n      255,  0,    1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,\n       15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,\n      255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,\n       41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255 }};\n\nstruct _triple_byte\n{\n    unsigned char _1_1 : 2;\n    unsigned char _0   : 6;\n    unsigned char _2_1 : 4;\n    unsigned char _1_2 : 4;\n    unsigned char _3   : 6;\n    unsigned char _2_2 : 2;\n};\n\n//\n// A note on the implementation of BASE64 encoding and decoding:\n//\n// This is a fairly basic and naive implementation; there is probably a lot of room for\n// performance improvement, as well as for adding options such as support for URI-safe base64,\n// ignoring CRLF, relaxed validation rules, etc. The decoder is currently pretty strict.\n//\n\n#ifdef __GNUC__\n// gcc is concerned about the bitfield uses in the code, something we simply need to ignore.\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#endif\nstd::vector<unsigned char> _from_base64(const utility::string_t& input)\n{\n    std::vector<unsigned char> result;\n\n    if ( input.empty() )\n        return result;\n\n    size_t padding = 0;\n\n    // Validation\n    {\n        auto size = input.size();\n\n        if ( (size % 4) != 0 )\n        {\n            throw std::runtime_error(\"length of base64 string is not an even multiple of 4\");\n        }\n\n        for (auto iter = input.begin(); iter != input.end(); ++iter,--size)\n        {\n            const size_t ch_sz = static_cast<size_t>(*iter);\n            if ( ch_sz >= _base64_dectbl.size() || _base64_dectbl[ch_sz] == 255 )\n            {\n                throw std::runtime_error(\"invalid character found in base64 string\");\n            }\n            if ( _base64_dectbl[ch_sz] == 254 )\n            {\n                padding++;\n                // padding only at the end\n                if ( size > 2 )\n                {\n                    throw std::runtime_error(\"invalid padding character found in base64 string\");\n                }\n                if ( size == 2 )\n                {\n                    const size_t ch2_sz = static_cast<size_t>(*(iter+1));\n                    if ( ch2_sz >= _base64_dectbl.size() || _base64_dectbl[ch2_sz] != 254 )\n                    {\n                        throw std::runtime_error(\"invalid padding character found in base64 string\");\n                    }\n                }\n            }\n        }\n    }\n\n\n    auto size = input.size();\n    const utility::char_t* ptr = &input[0];\n\n    auto outsz = (size / 4)*3;\n    outsz -= padding;\n\n    result.resize(outsz);\n\n    size_t idx = 0;\n    for (; size > 4; ++idx )\n    {\n        unsigned char target[3];\n        memset(target, 0, sizeof(target));\n        _triple_byte* record = reinterpret_cast<_triple_byte*>(target);\n\n        unsigned char val0 = _base64_dectbl[ptr[0]];\n        unsigned char val1 = _base64_dectbl[ptr[1]];\n        unsigned char val2 = _base64_dectbl[ptr[2]];\n        unsigned char val3 = _base64_dectbl[ptr[3]];\n\n        record->_0   = val0;\n        record->_1_1 = val1 >> 4;\n        result[idx] = target[0];\n\n        record->_1_2 = val1 & 0xF;\n        record->_2_1 = val2 >> 2;\n        result[++idx] = target[1];\n\n        record->_2_2 = val2 & 0x3;\n        record->_3   = val3 & 0x3F;\n        result[++idx] = target[2];\n\n        ptr += 4;\n        size -= 4;\n    }\n\n    // Handle the last four bytes separately, to avoid having the conditional statements\n    // in all the iterations (a performance issue).\n\n    {\n        unsigned char target[3];\n        memset(target, 0, sizeof(target));\n        _triple_byte* record = reinterpret_cast<_triple_byte*>(target);\n\n        unsigned char val0 = _base64_dectbl[ptr[0]];\n        unsigned char val1 = _base64_dectbl[ptr[1]];\n        unsigned char val2 = _base64_dectbl[ptr[2]];\n        unsigned char val3 = _base64_dectbl[ptr[3]];\n\n        record->_0   = val0;\n        record->_1_1 = val1 >> 4;\n        result[idx] = target[0];\n\n        record->_1_2 = val1 & 0xF;\n        if ( val2 != 254 )\n        {\n            record->_2_1 = val2 >> 2;\n            result[++idx] = target[1];\n        }\n        else\n        {\n            // There shouldn't be any information (ones) in the unused bits,\n            if ( record->_1_2 != 0 )\n            {\n                throw std::runtime_error(\"Invalid end of base64 string\");\n            }\n                return result;\n        }\n\n        record->_2_2 = val2 & 0x3;\n        if ( val3 != 254 )\n        {\n            record->_3   = val3 & 0x3F;\n            result[++idx] = target[2];\n        }\n        else\n        {\n            // There shouldn't be any information (ones) in the unused bits.\n            if ( record->_2_2 != 0 )\n            {\n                throw std::runtime_error(\"Invalid end of base64 string\");\n            }\n                return result;\n        }\n    }\n\n    return result;\n}\n\nutility::string_t _to_base64(const unsigned char *ptr, size_t size)\n{\n    utility::string_t result;\n\n    for (; size >= 3; )\n    {\n        const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);\n        unsigned char idx0 = record->_0;\n        unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;\n        unsigned char idx2 = (record->_2_1 << 2) | record->_2_2;\n        unsigned char idx3 = record->_3;\n        result.push_back(utility::char_t(_base64_enctbl[idx0]));\n        result.push_back(utility::char_t(_base64_enctbl[idx1]));\n        result.push_back(utility::char_t(_base64_enctbl[idx2]));\n        result.push_back(utility::char_t(_base64_enctbl[idx3]));\n        size -= 3;\n        ptr += 3;\n    }\n    switch(size)\n    {\n        case 1:\n        {\n            const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);\n            unsigned char idx0 = record->_0;\n            unsigned char idx1 = (record->_1_1 << 4);\n            result.push_back(utility::char_t(_base64_enctbl[idx0]));\n            result.push_back(utility::char_t(_base64_enctbl[idx1]));\n            result.push_back('=');\n            result.push_back('=');\n            break;\n        }\n        case 2:\n        {\n            const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);\n            unsigned char idx0 = record->_0;\n            unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;\n            unsigned char idx2 = (record->_2_1 << 2);\n            result.push_back(utility::char_t(_base64_enctbl[idx0]));\n            result.push_back(utility::char_t(_base64_enctbl[idx1]));\n            result.push_back(utility::char_t(_base64_enctbl[idx2]));\n            result.push_back('=');\n            break;\n        }\n    }\n    return result;\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/basic_types.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Platform-dependent type definitions\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <string>\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include \"cpprest/details/cpprest_compat.h\"\n\n#ifndef _WIN32\n# define __STDC_LIMIT_MACROS\n# include <stdint.h>\n#else\n#include <cstdint>\n#endif\n\n#include \"cpprest/details/SafeInt3.hpp\"\n\nnamespace utility\n{\n\n#ifdef _WIN32\n#define _UTF16_STRINGS\n#endif\n\n// We should be using a 64-bit size type for most situations that do\n// not involve specifying the size of a memory allocation or buffer.\ntypedef uint64_t size64_t;\n\n#ifdef _UTF16_STRINGS\n//\n// On Windows, all strings are wide\n//\ntypedef wchar_t char_t ;\ntypedef std::wstring string_t;\n#define _XPLATSTR(x) L ## x\ntypedef std::wostringstream ostringstream_t;\ntypedef std::wofstream ofstream_t;\ntypedef std::wostream ostream_t;\ntypedef std::wistream istream_t;\ntypedef std::wifstream ifstream_t;\ntypedef std::wistringstream istringstream_t;\ntypedef std::wstringstream stringstream_t;\n#define ucout std::wcout\n#define ucin std::wcin\n#define ucerr std::wcerr\n#define ustrlen wcslen\n#else\n//\n// On POSIX platforms, all strings are narrow\n//\ntypedef char char_t;\ntypedef std::string string_t;\n#define _XPLATSTR(x) x\ntypedef std::ostringstream ostringstream_t;\ntypedef std::ofstream ofstream_t;\ntypedef std::ostream ostream_t;\ntypedef std::istream istream_t;\ntypedef std::ifstream ifstream_t;\ntypedef std::istringstream istringstream_t;\ntypedef std::stringstream stringstream_t;\n#define ucout std::cout\n#define ucin std::cin\n#define ucerr std::cerr\n#define ustrlen strlen\n#endif // endif _UTF16_STRINGS\n\n#ifndef _TURN_OFF_PLATFORM_STRING\n#define U(x) _XPLATSTR(x)\n#endif // !_TURN_OFF_PLATFORM_STRING\n\n}// namespace utility\n\ntypedef char utf8char;\ntypedef std::string utf8string;\ntypedef std::stringstream utf8stringstream;\ntypedef std::ostringstream utf8ostringstream;\ntypedef std::ostream utf8ostream;\ntypedef std::istream utf8istream;\ntypedef std::istringstream utf8istringstream;\n\n#ifdef _UTF16_STRINGS\ntypedef wchar_t utf16char;\ntypedef std::wstring utf16string;\ntypedef std::wstringstream utf16stringstream;\ntypedef std::wostringstream utf16ostringstream;\ntypedef std::wostream utf16ostream;\ntypedef std::wistream utf16istream;\ntypedef std::wistringstream utf16istringstream;\n#else\ntypedef char16_t utf16char;\ntypedef std::u16string utf16string;\ntypedef std::basic_stringstream<utf16char> utf16stringstream;\ntypedef std::basic_ostringstream<utf16char> utf16ostringstream;\ntypedef std::basic_ostream<utf16char> utf16ostream;\ntypedef std::basic_istream<utf16char> utf16istream;\ntypedef std::basic_istringstream<utf16char> utf16istringstream;\n#endif\n\n\n#if defined(_WIN32)\n// Include on everything except Windows Desktop ARM, unless explicitly excluded.\n#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)\n#if defined(WINAPI_FAMILY)\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM)\n#define CPPREST_EXCLUDE_WEBSOCKETS\n#endif\n#else\n#if defined(_M_ARM)\n#define CPPREST_EXCLUDE_WEBSOCKETS\n#endif\n#endif\n#endif\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/cpprest_compat.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Standard macros and definitions.\n* This header has minimal dependency on windows headers and is safe for use in the public API\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#if defined(_WIN32) // Settings specific to Windows\n\n#if _MSC_VER >= 1900\n#define CPPREST_NOEXCEPT noexcept\n#else\n#define CPPREST_NOEXCEPT\n#endif\n\n#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)\n\n#include <sal.h>\n\n#else // End settings specific to Windows\n\n// Settings common to all but Windows\n\n#define __declspec(x) __attribute__ ((x))\n#define dllimport\n#define novtable /* no novtable equivalent */\n#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false)\n#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x\n#define CPPREST_NOEXCEPT noexcept\n\n#include <assert.h>\n#define _ASSERTE(x) assert(x)\n\n// No SAL on non Windows platforms\n#include \"cpprest/details/nosal.h\"\n\n#if not defined __cdecl\n#if defined cdecl\n#define __cdecl __attribute__ ((cdecl))\n#else\n#define __cdecl\n#endif\n\n#if defined(__ANDROID__)\n// This is needed to disable the use of __thread inside the boost library.\n// Android does not support thread local storage -- if boost is included\n// without this macro defined, it will create references to __tls_get_addr\n// which (while able to link) will not be available at runtime and prevent\n// the .so from loading.\n#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION\n#endif\n\n#ifdef __clang__\n#include <cstdio>\n#endif\n\n#endif // defined(__APPLE__)\n\n#endif\n\n\n#ifdef _NO_ASYNCRTIMP\n#define _ASYNCRTIMP\n#else\n#ifdef _ASYNCRT_EXPORT\n#define _ASYNCRTIMP __declspec(dllexport)\n#else\n#define _ASYNCRTIMP __declspec(dllimport)\n#endif\n#endif\n\n#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS\n#define CASABLANCA_DEPRECATED(x)\n#else\n#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/http_client_msg.hpp",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: Request and reply message definitions (client side).\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n\nnamespace web { namespace http\n{\n\nuri details::_http_request::relative_uri() const\n{\n    // If the listener path is empty, then just return the request URI.\n    if(m_listener_path.empty() || m_listener_path == _XPLATSTR(\"/\"))\n    {\n        return m_uri.resource();\n    }\n\n    utility::string_t prefix = uri::decode(m_listener_path);\n    utility::string_t path = uri::decode(m_uri.resource().to_string());\n    if(path.empty())\n    {\n        path = _XPLATSTR(\"/\");\n    }\n\n    auto pos = path.find(prefix);\n    if (pos == 0)\n    {\n        return uri(uri::encode_uri(path.erase(0, prefix.length())));\n    }\n    else\n    {\n        throw http_exception(_XPLATSTR(\"Error: request was not prefixed with listener uri\"));\n    }\n}\n\nuri details::_http_request::absolute_uri() const\n{\n    if (m_base_uri.is_empty())\n    {\n        return m_uri;\n    }\n    else\n    {\n        return uri_builder(m_base_uri).append(m_uri).to_uri();\n    }\n}\n\nvoid details::_http_request::set_request_uri(const uri& relative)\n{\n    m_uri = relative;\n}\n\nutility::string_t details::_http_request::to_string() const\n{\n    utility::ostringstream_t buffer;\n    buffer.imbue(std::locale::classic());\n    buffer << m_method << _XPLATSTR(\" \") << (this->m_uri.is_empty() ? _XPLATSTR(\"/\") : this->m_uri.to_string()) << _XPLATSTR(\" HTTP/1.1\\r\\n\");\n    buffer << http_msg_base::to_string();\n    return buffer.str();\n}\n\nvoid details::_http_request::_record_body_data_for_retry(const concurrency::streams::istream &stream)\n{\n    CASABLANCA_UNREFERENCED_PARAMETER(stream);\n    if (!m_bodyTextRecorded && !m_bodyVectorRecorded)\n    {\n        m_onlySetBodyUsingStream = true;\n    }\n}\n\nvoid details::_http_request::_record_body_data_for_retry(const std::vector<unsigned char> &body_data)\n{\n    m_bodyVector = body_data;\n    m_bodyVectorRecorded = true;\n}\n\nvoid details::_http_request::_record_body_data_for_retry(const utf8string &body_text, const utf8string &content_type)\n{\n    m_bodyText = body_text;\n    m_contentType = content_type;\n    m_bodyTextRecorded = true;\n}\n\nbool details::_http_request::_reset_body_for_retry()\n{\n    if (m_onlySetBodyUsingStream)\n    {\n        return false;\n    }\n\n    if (m_bodyTextRecorded)\n    {\n        set_body(concurrency::streams::bytestream::open_istream(m_bodyText), m_bodyText.size(), m_contentType);\n    }\n    else if (m_bodyVectorRecorded)\n    {\n        set_body(concurrency::streams::bytestream::open_istream(m_bodyVector), m_bodyVector.size(), \"application/octet-stream\");\n    }\n\n    return true;\n}\n\nutility::string_t details::_http_response::to_string() const\n{\n    // If the user didn't explicitly set a reason phrase then we should have it default\n    // if they used one of the standard known status codes.\n    auto reason_phrase = m_reason_phrase;\n    if(reason_phrase.empty())\n    {\n        static http_status_to_phrase idToPhraseMap[] = {\n#define _PHRASES\n#define DAT(a,b,c) {status_codes::a, c},\n#include \"cpprest/details/http_constants.dat\"\n#undef _PHRASES\n#undef DAT\n        };\n\n        for( auto iter = std::begin(idToPhraseMap); iter != std::end(idToPhraseMap); ++iter)\n        {\n            if( iter->id == status_code() )\n            {\n                reason_phrase = iter->phrase;\n                break;\n            }\n        }\n    }\n\n    utility::ostringstream_t buffer;\n    buffer.imbue(std::locale::classic());\n    buffer << _XPLATSTR(\"HTTP/1.1 \") << m_status_code << _XPLATSTR(\" \") << reason_phrase << _XPLATSTR(\"\\r\\n\");\n\n    buffer << http_msg_base::to_string();\n    return buffer.str();\n}\n\n}} // namespace web::http\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n\n#endif // !XSAPI_NO_PPL\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/http_helpers.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Implementation Details of the http.h layer of messaging\n*\n* Functions and types for interoperating with http.h from modern C++\n*   This file includes windows definitions and should not be included in a public header\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#include \"cpprest/details/basic_types.h\"\n\nnamespace web { namespace http\n{\nnamespace details\n{\n\n    /// <summary>\n    /// Helper function to get the default HTTP reason phrase for a status code.\n    /// </summary>\n    utility::string_t get_default_reason_phrase(status_code code);\n\n    // simple helper functions to trim whitespace.\n    _ASYNCRTIMP void __cdecl trim_whitespace(utility::string_t &str);\n\n    bool validate_method(const utility::string_t& method);\n\n    namespace chunked_encoding\n    {\n        // Transfer-Encoding: chunked support\n        static const size_t additional_encoding_space = 12;\n        static const size_t data_offset               = additional_encoding_space-2;\n\n        // Add the data necessary for properly sending data with transfer-encoding: chunked.\n        //\n        // There are up to 12 additional bytes needed for each chunk:\n        //\n        // The last chunk requires 5 bytes, and is fixed.\n        // All other chunks require up to 8 bytes for the length, and four for the two CRLF\n        // delimiters.\n        //\n        _ASYNCRTIMP size_t __cdecl add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t *data, _In_ size_t buffer_size, size_t bytes_read);\n    }\n\n}}}\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/http_helpers.hpp",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Implementation Details of the http.h layer of messaging\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\nusing namespace web;\nusing namespace utility::conversions;\n\nnamespace web { namespace http\n{\nnamespace details\n{\n\n// Remove once VS 2013 is no longer supported.\n#if defined(_WIN32) && _MSC_VER < 1900\nstatic const http_status_to_phrase idToPhraseMap [] = {\n#define _PHRASES\n#define DAT(a,b,c) {status_codes::a, c},\n#include \"cpprest/details/http_constants.dat\"\n#undef _PHRASES\n#undef DAT\n};\n#endif\nutility::string_t get_default_reason_phrase(status_code code)\n{\n#if !defined(_WIN32) || _MSC_VER >= 1900\n    // Future improvement: why is this stored as an array of structs instead of a map\n    // indexed on the status code for faster lookup?\n    // Not a big deal because it is uncommon to not include a reason phrase.\n    static const http_status_to_phrase idToPhraseMap [] = {\n#define _PHRASES\n#define DAT(a,b,c) {status_codes::a, c},\n#include \"cpprest/details/http_constants.dat\"\n#undef _PHRASES\n#undef DAT\n    };\n#endif\n\n    utility::string_t phrase;\n    for (const auto &elm : idToPhraseMap)\n    {\n        if (elm.id == code)\n        {\n            phrase = elm.phrase;\n            break;\n        }\n    }\n    return phrase;\n}\n\nstatic void ltrim_whitespace(utility::string_t &str)\n{\n    size_t index;\n    for (index = 0; index < str.size() && isspace(str[index]); ++index);\n    str.erase(0, index);\n}\nstatic void rtrim_whitespace(utility::string_t &str)\n{\n    size_t index;\n    for (index = str.size(); index > 0 && isspace(str[index - 1]); --index);\n    str.erase(index);\n}\nvoid trim_whitespace(utility::string_t &str)\n{\n    ltrim_whitespace(str);\n    rtrim_whitespace(str);\n}\n\nsize_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t *data, _In_ size_t buffer_size, size_t bytes_read)\n{\n    size_t offset = 0;\n\n    if (buffer_size < bytes_read + http::details::chunked_encoding::additional_encoding_space)\n    {\n        throw http_exception(_XPLATSTR(\"Insufficient buffer size.\"));\n    }\n\n    if (bytes_read == 0)\n    {\n        offset = 7;\n        data[7] = '0';\n        data[8] = '\\r';  data[9] = '\\n'; // The end of the size.\n        data[10] = '\\r'; data[11] = '\\n'; // The end of the message.\n    }\n    else\n    {\n        char buffer[9];\n#ifdef _WIN32\n#pragma warning(suppress: 4777)\n        sprintf_s(buffer, sizeof(buffer), \"%8IX\", bytes_read);\n#else\n        snprintf(buffer, sizeof(buffer), \"%8zX\", bytes_read);\n#endif\n        memcpy(&data[0], buffer, 8);\n        while (data[offset] == ' ') ++offset;\n        data[8] = '\\r'; data[9] = '\\n'; // The end of the size.\n        data[10 + bytes_read] = '\\r'; data[11 + bytes_read] = '\\n'; // The end of the chunk.\n    }\n\n    return offset;\n}\n\n#if (!defined(_WIN32) || defined(__cplusplus_winrt))\nconst std::array<bool,128> valid_chars =\n{{\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //16-31\n    0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, //32-47\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, //48-63\n    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //64-79\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //80-95\n    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //96-111\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 //112-127\n    }};\n\n// Checks if the method contains any invalid characters\nbool validate_method(const utility::string_t& method)\n{\n    for (const auto &ch : method)\n    {\n        size_t ch_sz = static_cast<size_t>(ch);\n        if (ch_sz >= 128)\n            return false;\n\n        if (!valid_chars[ch_sz])\n            return false;\n    }\n\n    return true;\n}\n#endif\n\n} // namespace details\n}} // namespace web::http\n#endif // !XSAPI_NO_PPL\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/http_msg.hpp",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: Request and reply message definitions.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include \"cpprest/details/http_helpers.h\"\n#include \"cpprest/producerconsumerstream.h\"\n#include <limits>\n\nusing namespace web;\nusing namespace concurrency;\nusing namespace utility::conversions;\nusing namespace http::details;\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n\nnamespace web { namespace http\n{\n\n#define CRLF _XPLATSTR(\"\\r\\n\")\n\nutility::string_t http_headers::content_type() const\n{\n    utility::string_t result;\n    match(http::header_names::content_type, result);\n    return result;\n}\n\n\n\n/// Helper functions to convert a series of bytes from a charset to utf-8 or utf-16.\n/// These APIs deal with checking for and handling byte order marker (BOM).\nnamespace {\n    enum endianness\n    {\n        little_endian,\n        big_endian,\n        unknown\n    };\n    endianness check_byte_order_mark(const utf16string &str)\n    {\n        if (str.empty())\n        {\n            return unknown;\n        }\n        const unsigned char *src = reinterpret_cast<const unsigned char *>(str.data());\n\n        // little endian\n        if (src[0] == 0xFF && src[1] == 0xFE)\n        {\n            return little_endian;\n        }\n\n        // big endian\n        else if (src[0] == 0xFE && src[1] == 0xFF)\n        {\n            return big_endian;\n        }\n\n        return unknown;\n    }\n\n    std::string convert_utf16le_to_utf8(utf16string src, bool erase_bom)\n    {\n        if (erase_bom && !src.empty())\n        {\n            src.erase(0, 1);\n        }\n        return utf16_to_utf8(std::move(src));\n    }\n\n    utility::string_t convert_utf16le_to_string_t(utf16string src, bool erase_bom)\n    {\n        if (erase_bom && !src.empty())\n        {\n            src.erase(0, 1);\n        }\n    #ifdef _UTF16_STRINGS\n        return src;\n    #else\n        return utf16_to_utf8(std::move(src));\n    #endif\n    }\n\n    // Helper function to change endian ness from big endian to little endian\n    utf16string big_endian_to_little_endian(utf16string src, bool erase_bom)\n    {\n        if (erase_bom && !src.empty())\n        {\n            src.erase(0, 1);\n        }\n        if (src.empty())\n        {\n            return src;\n        }\n\n        const size_t size = src.size();\n        for (size_t i = 0; i < size; ++i)\n        {\n            utf16char ch = src[i];\n            src[i] = static_cast<utf16char>(ch << 8);\n            src[i] = static_cast<utf16char>(src[i] | ch >> 8);\n        }\n\n        return src;\n    }\n\n    std::string convert_utf16be_to_utf8(utf16string src, bool erase_bom)\n    {\n        return utf16_to_utf8(big_endian_to_little_endian(std::move(src), erase_bom));\n    }\n\n    utf16string convert_utf16be_to_utf16le(utf16string src, bool erase_bom)\n    {\n        return big_endian_to_little_endian(std::move(src), erase_bom);\n    }\n\n    utility::string_t convert_utf16be_to_string_t(utf16string src, bool erase_bom)\n    {\n    #ifdef _UTF16_STRINGS\n        return convert_utf16be_to_utf16le(std::move(src), erase_bom);\n    #else\n        return convert_utf16be_to_utf8(std::move(src), erase_bom);\n    #endif\n    }\n\n    std::string convert_utf16_to_utf8(utf16string src)\n    {\n        const endianness endian = check_byte_order_mark(src);\n        switch (endian)\n        {\n        case little_endian:\n            return convert_utf16le_to_utf8(std::move(src), true);\n        case big_endian:\n            return convert_utf16be_to_utf8(std::move(src), true);\n        case unknown:\n            // unknown defaults to big endian.\n            return convert_utf16be_to_utf8(std::move(src), false);\n        }\n        __assume(0);\n    }\n\n    utf16string convert_utf16_to_utf16(utf16string src)\n    {\n        const endianness endian = check_byte_order_mark(src);\n        switch (endian)\n        {\n        case little_endian:\n            src.erase(0, 1);\n            return src;\n        case big_endian:\n            return convert_utf16be_to_utf16le(std::move(src), true);\n        case unknown:\n            // unknown defaults to big endian.\n            return convert_utf16be_to_utf16le(std::move(src), false);\n        }\n        __assume(0);\n    }\n    utility::string_t convert_utf16_to_string_t(utf16string src)\n    {\n    #ifdef _UTF16_STRINGS\n        return convert_utf16_to_utf16(std::move(src));\n    #else\n        return convert_utf16_to_utf8(std::move(src));\n    #endif\n    }\n}\n\nvoid http_headers::set_content_type(utility::string_t type)\n{\n    m_headers[http::header_names::content_type] = std::move(type);\n}\n\nutility::string_t http_headers::cache_control() const\n{\n    utility::string_t result;\n    match(http::header_names::cache_control, result);\n    return result;\n}\n\nvoid http_headers::set_cache_control(utility::string_t control)\n{\n    add(http::header_names::cache_control, std::move(control));\n}\n\nutility::string_t http_headers::date() const\n{\n    utility::string_t result;\n    match(http::header_names::date, result);\n    return result;\n}\n\nvoid http_headers::set_date(const utility::datetime& date)\n{\n    m_headers[http::header_names::date] = date.to_string(utility::datetime::RFC_1123);\n}\n\nutility::size64_t http_headers::content_length() const\n{\n    utility::size64_t length = 0;\n    match(http::header_names::content_length, length);\n    return length;\n}\n\nvoid http_headers::set_content_length(utility::size64_t length)\n{\n    m_headers[http::header_names::content_length] = utility::conversions::print_string(length, std::locale::classic());\n}\n\nnamespace details {\n\nutility::string_t flatten_http_headers(const http_headers &headers)\n{\n    utility::string_t flattened_headers;\n    for (auto iter = headers.begin(); iter != headers.end(); ++iter)\n    {\n        flattened_headers.append(iter->first);\n        flattened_headers.push_back(':');\n        flattened_headers.append(iter->second);\n        flattened_headers.append(CRLF);\n    }\n    return flattened_headers;\n}\n\n#if defined(_WIN32)\nvoid parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers)\n{\n    utf16char *context = nullptr;\n    utf16char *line = wcstok_s(headersStr, CRLF, &context);\n    while (line != nullptr)\n    {\n        const utility::string_t header_line(line);\n        const size_t colonIndex = header_line.find_first_of(_XPLATSTR(\":\"));\n        if (colonIndex != utility::string_t::npos)\n        {\n            utility::string_t key = header_line.substr(0, colonIndex);\n            utility::string_t value = header_line.substr(colonIndex + 1, header_line.length() - colonIndex - 1);\n            http::details::trim_whitespace(key);\n            http::details::trim_whitespace(value);\n            headers.add(key, value);\n        }\n        line = wcstok_s(nullptr, CRLF, &context);\n    }\n}\n#endif\n\n}\n\nstatic const utility::char_t * stream_was_set_explicitly = _XPLATSTR(\"A stream was set on the message and extraction is not possible\");\nstatic const utility::char_t * unsupported_charset = _XPLATSTR(\"Charset must be iso-8859-1, utf-8, utf-16, utf-16le, or utf-16be to be extracted.\");\n\nhttp_msg_base::http_msg_base()\n    : m_headers(),\n      m_default_outstream(false)\n{\n}\n\nvoid http_msg_base::_prepare_to_receive_data()\n{\n    // See if the user specified an outstream\n    if (!outstream())\n    {\n        // The user did not specify an outstream.\n        // We will create one...\n        concurrency::streams::producer_consumer_buffer<uint8_t> buf;\n        set_outstream(buf.create_ostream(), true);\n\n        // Since we are creating the streambuffer, set the input stream\n        // so that the user can retrieve the data.\n        set_instream(buf.create_istream());\n    }\n\n    // If the user did specify an outstream we leave the instream\n    // as invalid. It is assumed that user either has a read head\n    // to the out streambuffer or the data is streamed into a container\n    // or media (like file) that the user can read from...\n}\n\nsize_t http_msg_base::_get_content_length()\n{\n    // An invalid response_stream indicates that there is no body\n    if ((bool)instream())\n    {\n        size_t content_length = 0;\n        utility::string_t transfer_encoding;\n\n        bool has_cnt_length = headers().match(header_names::content_length, content_length);\n        bool has_xfr_encode = headers().match(header_names::transfer_encoding, transfer_encoding);\n\n        if (has_xfr_encode)\n        {\n            return SIZE_MAX;\n        }\n\n        if (has_cnt_length)\n        {\n            return content_length;\n        }\n\n        // Neither is set. Assume transfer-encoding for now (until we have the ability to determine\n        // the length of the stream).\n        headers().add(header_names::transfer_encoding, _XPLATSTR(\"chunked\"));\n        return SIZE_MAX;\n    }\n\n    return 0;\n}\n\n// Helper function to inline continuation if possible.\nstruct inline_continuation\n{\n    inline_continuation(pplx::task<void> &prev, const std::function<void(pplx::task<void>)> &next) : m_prev(prev), m_next(next) {}\n    ~inline_continuation()\n    {\n        if (m_prev.is_done())\n        {\n            m_next(m_prev);\n        }\n        else\n        {\n            m_prev.then(m_next);\n        }\n    }\n    pplx::task<void> & m_prev;\n    std::function<void(pplx::task<void>)> m_next;\nprivate:\n    inline_continuation(const inline_continuation &);\n    inline_continuation &operator=(const inline_continuation &);\n};\n\nvoid http_msg_base::_complete(utility::size64_t body_size, const std::exception_ptr &exceptionPtr)\n{\n    const auto &completionEvent = _get_data_available();\n    auto closeTask = pplx::task_from_result();\n\n    if (exceptionPtr == std::exception_ptr())\n    {\n        if (m_default_outstream)\n        {\n            closeTask = outstream().close();\n        }\n\n        inline_continuation(closeTask, [completionEvent, body_size](pplx::task<void> t)\n        {\n            try\n            {\n                t.get();\n                completionEvent.set(body_size);\n            }\n            catch (...)\n            {\n                // If close throws an exception report back to user.\n                completionEvent.set_exception(std::current_exception());\n                pplx::create_task(completionEvent).then([](pplx::task<utility::size64_t> t)\n                {\n                    try { t.get(); }\n                    catch (...) {}\n                });\n            }\n        });\n    }\n    else\n    {\n        if (outstream().is_valid())\n        {\n            closeTask = outstream().close(exceptionPtr);\n        }\n\n        inline_continuation(closeTask, [completionEvent, exceptionPtr](pplx::task<void> t)\n        {\n            // If closing stream throws an exception ignore since we already have an error.\n            try { t.get(); }\n            catch (...) {}\n            completionEvent.set_exception(exceptionPtr);\n            pplx::create_task(completionEvent).then([](pplx::task<utility::size64_t> t)\n            {\n                try { t.get(); }\n                catch (...) {}\n            });\n        });\n    }\n}\n\nstatic bool is_content_type_one_of(const utility::string_t *first, const utility::string_t *last, const utility::string_t &value)\n{\n    while (first != last)\n    {\n        if (utility::details::str_icmp(*first, value))\n        {\n            return true;\n        }\n        ++first;\n    }\n    return false;\n}\n\n// Remove once VS 2013 is no longer supported.\n#if defined(_WIN32) && _MSC_VER < 1900\n// Not referring to mime_types to avoid static initialization order fiasco.\nstatic const utility::string_t textual_types [] = {\n    U(\"message/http\"),\n    U(\"application/json\"),\n    U(\"application/xml\"),\n    U(\"application/atom+xml\"),\n    U(\"application/http\"),\n    U(\"application/x-www-form-urlencoded\")\n};\n#endif\n\n/// <summary>\n/// Determines whether or not the given content type is 'textual' according the feature specifications.\n/// </summary>\nstatic bool is_content_type_textual(const utility::string_t &content_type)\n{\n#if !defined(_WIN32) || _MSC_VER >= 1900\n    static const utility::string_t textual_types [] = {\n        mime_types::message_http,\n        mime_types::application_json,\n        mime_types::application_xml,\n        mime_types::application_atom_xml,\n        mime_types::application_http,\n        mime_types::application_x_www_form_urlencoded\n    };\n#endif\n\n    if (content_type.size() >= 4 && utility::details::str_icmp(content_type.substr(0, 4), _XPLATSTR(\"text\")))\n    {\n        return true;\n    }\n    return (is_content_type_one_of(std::begin(textual_types), std::end(textual_types), content_type));\n}\n\n// Remove once VS 2013 is no longer supported.\n#if defined(_WIN32) && _MSC_VER < 1900\n// Not referring to mime_types to avoid static initialization order fiasco.\nstatic const utility::string_t json_types [] = {\n    U(\"application/json\"),\n    U(\"application/x-json\"),\n    U(\"text/json\"),\n    U(\"text/x-json\"),\n    U(\"text/javascript\"),\n    U(\"text/x-javascript\"),\n    U(\"application/javascript\"),\n    U(\"application/x-javascript\")\n};\n#endif\n\n/// <summary>\n/// Determines whether or not the given content type is JSON according the feature specifications.\n/// </summary>\nstatic bool is_content_type_json(const utility::string_t &content_type)\n{\n#if !defined(_WIN32) || _MSC_VER >= 1900\n    static const utility::string_t json_types [] = {\n        mime_types::application_json,\n        mime_types::application_xjson,\n        mime_types::text_json,\n        mime_types::text_xjson,\n        mime_types::text_javascript,\n        mime_types::text_xjavascript,\n        mime_types::application_javascript,\n        mime_types::application_xjavascript\n    };\n#endif\n\n    return (is_content_type_one_of(std::begin(json_types), std::end(json_types), content_type));\n}\n\n/// <summary>\n/// Gets the default charset for given content type. If the MIME type is not textual or recognized Latin1 will be returned.\n/// </summary>\nstatic utility::string_t get_default_charset(const utility::string_t &content_type)\n{\n    // We are defaulting everything to Latin1 except JSON which is utf-8.\n    if (is_content_type_json(content_type))\n    {\n        return charset_types::utf8;\n    }\n    else\n    {\n        return charset_types::latin1;\n    }\n}\n\n\n/// <summary>\n/// Parses the given Content-Type header value to get out actual content type and charset.\n/// If the charset isn't specified the default charset for the content type will be set.\n/// </summary>\nstatic void parse_content_type_and_charset(const utility::string_t &content_type, utility::string_t &content, utility::string_t &charset)\n{\n    const size_t semi_colon_index = content_type.find_first_of(_XPLATSTR(\";\"));\n\n    // No charset specified.\n    if (semi_colon_index == utility::string_t::npos)\n    {\n        content = content_type;\n        trim_whitespace(content);\n        charset = get_default_charset(content);\n        return;\n    }\n\n    // Split into content type and second part which could be charset.\n    content = content_type.substr(0, semi_colon_index);\n    trim_whitespace(content);\n    utility::string_t possible_charset = content_type.substr(semi_colon_index + 1);\n    trim_whitespace(possible_charset);\n    const size_t equals_index = possible_charset.find_first_of(_XPLATSTR(\"=\"));\n\n    // No charset specified.\n    if (equals_index == utility::string_t::npos)\n    {\n        charset = get_default_charset(content);\n        return;\n    }\n\n    // Split and make sure 'charset'\n    utility::string_t charset_key = possible_charset.substr(0, equals_index);\n    trim_whitespace(charset_key);\n    if (!utility::details::str_icmp(charset_key, _XPLATSTR(\"charset\")))\n    {\n        charset = get_default_charset(content);\n        return;\n    }\n    charset = possible_charset.substr(equals_index + 1);\n    // Remove the redundant ';' at the end of charset.\n    while (charset.back() == ';')\n    {\n        charset.pop_back();\n    }\n    trim_whitespace(charset);\n    if (charset.front() == _XPLATSTR('\"') && charset.back() == _XPLATSTR('\"'))\n    {\n        charset = charset.substr(1, charset.size() - 2);\n        trim_whitespace(charset);\n    }\n}\n\nutility::string_t details::http_msg_base::parse_and_check_content_type(bool ignore_content_type, const std::function<bool(const utility::string_t &)> &check_content_type)\n{\n    if (!instream())\n    {\n        throw http_exception(stream_was_set_explicitly);\n    }\n\n    utility::string_t content, charset = charset_types::utf8;\n    if (!ignore_content_type)\n    {\n        parse_content_type_and_charset(headers().content_type(), content, charset);\n\n        // If no Content-Type or empty body then just return an empty string.\n        if (content.empty() || instream().streambuf().in_avail() == 0)\n        {\n            return utility::string_t();\n        }\n\n        if (!check_content_type(content))\n        {\n            return utility::string_t(); \n        }\n    }\n    return charset;\n}\n\nutf8string details::http_msg_base::extract_utf8string(bool ignore_content_type)\n{\n    const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual);\n    if (charset.empty())\n    {\n        return utf8string();\n    }\n    auto buf_r = instream().streambuf();\n\n    // Perform the correct character set conversion if one is necessary.\n    if (utility::details::str_icmp(charset, charset_types::utf8)\n        || utility::details::str_icmp(charset, charset_types::usascii)\n        || utility::details::str_icmp(charset, charset_types::ascii))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return body;\n    }\n\n    // Latin1\n    else if (utility::details::str_icmp(charset, charset_types::latin1))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return latin1_to_utf8(std::move(body));\n    }\n\n    // utf-16\n    else if (utility::details::str_icmp(charset, charset_types::utf16))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16_to_utf8(std::move(body));\n    }\n\n    // utf-16le\n    else if (utility::details::str_icmp(charset, charset_types::utf16le))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return utility::conversions::utf16_to_utf8(std::move(body));\n    }\n\n    // utf-16be\n    else if (utility::details::str_icmp(charset, charset_types::utf16be))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16be_to_utf8(std::move(body), false);\n    }\n\n    else\n    {\n        throw http_exception(unsupported_charset);\n    }\n}\n\nutf16string details::http_msg_base::extract_utf16string(bool ignore_content_type)\n{\n    const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual);\n    if (charset.empty())\n    {\n        return utf16string();\n    }\n    auto buf_r = instream().streambuf();\n\n    // Perform the correct character set conversion if one is necessary.\n    if (utility::details::str_icmp(charset, charset_types::utf16le))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return body;\n    }\n\n    // utf-8, ascii\n    else if (utility::details::str_icmp(charset, charset_types::utf8)\n        || utility::details::str_icmp(charset, charset_types::usascii)\n        || utility::details::str_icmp(charset, charset_types::ascii))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return utility::conversions::utf8_to_utf16(std::move(body));\n    }\n\n    // Latin1\n    else if (utility::details::str_icmp(charset, charset_types::latin1))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return latin1_to_utf16(std::move(body));\n    }\n\n    // utf-16\n    else if (utility::details::str_icmp(charset, charset_types::utf16))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16_to_utf16(std::move(body));\n    }\n\n    // utf-16be\n    else if (utility::details::str_icmp(charset, charset_types::utf16be))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16be_to_utf16le(std::move(body), false);\n    }\n\n    else\n    {\n        throw http_exception(unsupported_charset);\n    }\n}\n\nutility::string_t details::http_msg_base::extract_string(bool ignore_content_type)\n{\n    const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_textual);\n    if (charset.empty())\n    {\n        return utility::string_t();\n    }\n    auto buf_r = instream().streambuf();\n\n    // Perform the correct character set conversion if one is necessary.\n    if (utility::details::str_icmp(charset, charset_types::usascii)\n            || utility::details::str_icmp(charset, charset_types::ascii))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return to_string_t(std::move(body));\n    }\n\n    // Latin1\n    if(utility::details::str_icmp(charset, charset_types::latin1))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        // Could optimize for linux in the future if a latin1_to_utf8 function was written.\n        return to_string_t(latin1_to_utf16(std::move(body)));\n    }\n\n    // utf-8.\n    else if(utility::details::str_icmp(charset, charset_types::utf8))\n    {\n        std::string body;\n        body.resize((std::string::size_type)buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return to_string_t(std::move(body));\n    }\n\n    // utf-16.\n    else if(utility::details::str_icmp(charset, charset_types::utf16))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16_to_string_t(std::move(body));\n    }\n\n    // utf-16le\n    else if(utility::details::str_icmp(charset, charset_types::utf16le))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16le_to_string_t(std::move(body), false);\n    }\n\n    // utf-16be\n    else if(utility::details::str_icmp(charset, charset_types::utf16be))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return convert_utf16be_to_string_t(std::move(body), false);\n    }\n\n    else\n    {\n        throw http_exception(unsupported_charset);\n    }\n}\n\njson::value details::http_msg_base::_extract_json(bool ignore_content_type)\n{\n    const auto &charset = parse_and_check_content_type(ignore_content_type, is_content_type_json);\n    if (charset.empty())\n    {\n        return json::value(extract_string(ignore_content_type));\n    }\n    auto buf_r = instream().streambuf();\n\n    // Latin1\n    if(utility::details::str_icmp(charset, charset_types::latin1))\n    {\n        std::string body;\n        body.resize(buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        // On Linux could optimize in the future if a latin1_to_utf8 function is written.\n        return json::value::parse(to_string_t(latin1_to_utf16(std::move(body))));\n    }\n\n    // utf-8, usascii and ascii\n    else if(utility::details::str_icmp(charset, charset_types::utf8)\n            || utility::details::str_icmp(charset, charset_types::usascii)\n            || utility::details::str_icmp(charset, charset_types::ascii))\n    {\n        std::string body;\n        body.resize(buf_r.in_avail());\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size()).get(); // There is no risk of blocking.\n        return json::value::parse(to_string_t(std::move(body)));\n    }\n\n    // utf-16.\n    else if(utility::details::str_icmp(charset, charset_types::utf16))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return json::value::parse(convert_utf16_to_string_t(std::move(body)));\n    }\n\n    // utf-16le\n    else if(utility::details::str_icmp(charset, charset_types::utf16le))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return json::value::parse(convert_utf16le_to_string_t(std::move(body), false));\n    }\n\n    // utf-16be\n    else if(utility::details::str_icmp(charset, charset_types::utf16be))\n    {\n        utf16string body;\n        body.resize(buf_r.in_avail() / sizeof(utf16string::value_type));\n        buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), body.size() * sizeof(utf16string::value_type)); // There is no risk of blocking.\n        return json::value::parse(convert_utf16be_to_string_t(std::move(body), false));\n    }\n\n    else\n    {\n        throw http_exception(unsupported_charset);\n    }\n}\n\nstd::vector<uint8_t> details::http_msg_base::_extract_vector()\n{\n    if (!instream())\n    {\n        throw http_exception(stream_was_set_explicitly);\n    }\n\n    std::vector<uint8_t> body;\n    auto buf_r = instream().streambuf();\n    const size_t size = buf_r.in_avail();\n    body.resize(size);\n    buf_r.getn(const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(body.data())), size).get(); // There is no risk of blocking.\n\n    return body;\n}\n\n// Helper function to convert message body without extracting.\nstatic utility::string_t convert_body_to_string_t(const utility::string_t &content_type, concurrency::streams::istream instream)\n{\n    if (!instream)\n    {\n        // The instream is not yet set\n        return utility::string_t();\n    }\n\n    concurrency::streams::streambuf<uint8_t>  streambuf = instream.streambuf();\n\n    _ASSERTE((bool)streambuf);\n    _ASSERTE(streambuf.is_open());\n    _ASSERTE(streambuf.can_read());\n\n    utility::string_t content, charset;\n    parse_content_type_and_charset(content_type, content, charset);\n\n    // Content-Type must have textual type.\n    if(!is_content_type_textual(content) || streambuf.in_avail() == 0)\n    {\n        return utility::string_t();\n    }\n\n    // Latin1\n    if(utility::details::str_icmp(charset, charset_types::latin1))\n    {\n        std::string body;\n        body.resize(streambuf.in_avail());\n        if(streambuf.scopy((unsigned char *)&body[0], body.size()) == 0) return utility::string_t();\n        return to_string_t(latin1_to_utf16(std::move(body)));\n    }\n\n    // utf-8.\n    else if(utility::details::str_icmp(charset, charset_types::utf8))\n    {\n        std::string body;\n        body.resize(streambuf.in_avail());\n        if(streambuf.scopy((unsigned char *)&body[0], body.size()) == 0) return utility::string_t();\n        return to_string_t(std::move(body));\n    }\n\n    // utf-16.\n    else if(utility::details::str_icmp(charset, charset_types::utf16))\n    {\n        utf16string body;\n        body.resize(streambuf.in_avail() / sizeof(utf16string::value_type));\n        if(streambuf.scopy((unsigned char *)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) return utility::string_t();\n        return convert_utf16_to_string_t(std::move(body));\n    }\n\n    // utf-16le\n    else if(utility::details::str_icmp(charset, charset_types::utf16le))\n    {\n        utf16string body;\n        body.resize(streambuf.in_avail() / sizeof(utf16string::value_type));\n        if(streambuf.scopy((unsigned char *)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) return utility::string_t();\n        return convert_utf16le_to_string_t(std::move(body), false);\n    }\n\n    // utf-16be\n    else if(utility::details::str_icmp(charset, charset_types::utf16be))\n    {\n        utf16string body;\n        body.resize(streambuf.in_avail() / sizeof(utf16string::value_type));\n        if(streambuf.scopy((unsigned char *)&body[0], body.size() * sizeof(utf16string::value_type)) == 0) return utility::string_t();\n        return convert_utf16be_to_string_t(std::move(body), false);\n    }\n\n    else\n    {\n        return utility::string_t();\n    }\n}\n\n//\n// Helper function to generate a wstring from given http_headers and message body.\n//\nstatic utility::string_t http_headers_body_to_string(const http_headers &headers, concurrency::streams::istream instream)\n{\n    utility::ostringstream_t buffer;\n    buffer.imbue(std::locale::classic());\n\n    for (const auto &header : headers)\n    {\n        buffer << header.first << _XPLATSTR(\": \") << header.second << CRLF;\n    }\n    buffer << CRLF;\n\n    utility::string_t content_type;\n    if(headers.match(http::header_names::content_type, content_type))\n    {\n        buffer << convert_body_to_string_t(content_type, instream);\n    }\n\n    return buffer.str();\n}\n\nutility::string_t details::http_msg_base::to_string() const\n{\n    return http_headers_body_to_string(m_headers, instream());\n}\n\nstatic void set_content_type_if_not_present(http::http_headers &headers, const utility::string_t &content_type)\n{\n    utility::string_t temp;\n    if(!headers.match(http::header_names::content_type, temp))\n    {\n        headers.add(http::header_names::content_type, content_type);\n    }\n}\n\nvoid details::http_msg_base::set_body(const streams::istream &instream, const utf8string &contentType)\n{\n    set_content_type_if_not_present(\n            headers(),\n#ifdef _UTF16_STRINGS\n            utility::conversions::utf8_to_utf16(contentType));\n#else\n            contentType);\n#endif\n    set_instream(instream);\n}\n\nvoid details::http_msg_base::set_body(const streams::istream &instream, const utf16string &contentType)\n{\n    set_content_type_if_not_present(\n            headers(),\n#ifdef _UTF16_STRINGS\n            contentType);\n#else\n            utility::conversions::utf16_to_utf8(contentType));\n#endif\n    set_instream(instream);\n}\n\nvoid details::http_msg_base::set_body(const streams::istream &instream, utility::size64_t contentLength, const utf8string &contentType)\n{\n    headers().set_content_length(contentLength);\n    set_body(instream, contentType);\n    m_data_available.set(contentLength);\n}\n\nvoid details::http_msg_base::set_body(const concurrency::streams::istream &instream, utility::size64_t contentLength, const utf16string &contentType)\n{\n    headers().set_content_length(contentLength);\n    set_body(instream, contentType);\n    m_data_available.set(contentLength);\n}\n\ndetails::_http_request::_http_request(http::method mtd)\n  : m_method(std::move(mtd)),\n    m_initiated_response(0),\n    m_server_context(),\n    m_cancellationToken(pplx::cancellation_token::none()),\n    m_bodyTextRecorded(false),\n    m_bodyVectorRecorded(false),\n    m_onlySetBodyUsingStream(false)\n{\n    if(m_method.empty())\n    {\n        throw std::invalid_argument(\"Invalid HTTP method specified. Method can't be an empty string.\");\n    }\n}\n\ndetails::_http_request::_http_request(std::unique_ptr<http::details::_http_server_context> server_context)\n  : m_initiated_response(0),\n    m_server_context(std::move(server_context)),\n    m_cancellationToken(pplx::cancellation_token::none()),\n    m_bodyTextRecorded(false),\n    m_bodyVectorRecorded(false),\n    m_onlySetBodyUsingStream(false)\n{\n}\n\n#define _METHODS\n#define DAT(a,b) const method methods::a = b;\n#include \"cpprest/details/http_constants.dat\"\n#undef _METHODS\n#undef DAT\n\n#define _HEADER_NAMES\n#define DAT(a,b) const utility::string_t header_names::a = _XPLATSTR(b);\n#include \"cpprest/details/http_constants.dat\"\n#undef _HEADER_NAMES\n#undef DAT\n\n#define _MIME_TYPES\n#define DAT(a,b) const utility::string_t mime_types::a = _XPLATSTR(b);\n#include \"cpprest/details/http_constants.dat\"\n#undef _MIME_TYPES\n#undef DAT\n\n#define _CHARSET_TYPES\n#define DAT(a,b) const utility::string_t charset_types::a = _XPLATSTR(b);\n#include \"cpprest/details/http_constants.dat\"\n#undef _CHARSET_TYPES\n#undef DAT\n\n// This is necessary for Linux because of a bug in GCC 4.7\n#ifndef _WIN32\n#define _PHRASES\n#define DAT(a,b,c) const status_code status_codes::a;\n#include \"cpprest/details/http_constants.dat\"\n#undef _PHRASES\n#undef DAT\n#endif\n}} // namespace web::http\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n\n#endif // !XSAPI_NO_PPL\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/json.hpp",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: JSON parser and writer\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\nusing namespace web;\n\nbool json::details::g_keep_json_object_unsorted = false;\nvoid json::keep_object_element_order(bool keep_order)\n{\n    json::details::g_keep_json_object_unsorted = keep_order;\n}\n\nutility::ostream_t& web::json::operator << (utility::ostream_t &os, const web::json::value &val)\n{\n    val.serialize(os);\n    return os;\n}\n\nutility::istream_t& web::json::operator >> (utility::istream_t &is, json::value &val)\n{\n    val = json::value::parse(is);\n    return is;\n}\n\nweb::json::value::value() :\n    m_value(utility::details::make_unique<web::json::details::_Null>())\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Null)\n#endif\n    { }\n\nweb::json::value::value(int32_t value) :\n    m_value(utility::details::make_unique<web::json::details::_Number>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Number)\n#endif\n    { }\n\nweb::json::value::value(uint32_t value) :\n    m_value(utility::details::make_unique<web::json::details::_Number>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Number)\n#endif\n    { }\n\nweb::json::value::value(int64_t value) :\n    m_value(utility::details::make_unique<web::json::details::_Number>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Number)\n#endif\n    { }\n\nweb::json::value::value(uint64_t value) :\n    m_value(utility::details::make_unique<web::json::details::_Number>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Number)\n#endif\n    { }\n\nweb::json::value::value(double value) :\n    m_value(utility::details::make_unique<web::json::details::_Number>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Number)\n#endif\n    { }\n\nweb::json::value::value(bool value) :\n    m_value(utility::details::make_unique<web::json::details::_Boolean>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::Boolean)\n#endif\n    { }\n\nweb::json::value::value(utility::string_t value) :\n    m_value(utility::details::make_unique<web::json::details::_String>(std::move(value)))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::String)\n#endif\n    { }\n\nweb::json::value::value(utility::string_t value, bool has_escape_chars) :\nm_value(utility::details::make_unique<web::json::details::_String>(std::move(value), has_escape_chars))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n, m_kind(value::String)\n#endif\n{ }\n\nweb::json::value::value(const utility::char_t* value) :\n    m_value(utility::details::make_unique<web::json::details::_String>(value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(value::String)\n#endif\n    { }\n\nweb::json::value::value(const utility::char_t* value, bool has_escape_chars) :\nm_value(utility::details::make_unique<web::json::details::_String>(utility::string_t(value), has_escape_chars))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n, m_kind(value::String)\n#endif\n{ }\n\nweb::json::value::value(const value &other) :\n    m_value(other.m_value->_copy_value())\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(other.m_kind)\n#endif\n    { }\n\nweb::json::value &web::json::value::operator=(const value &other)\n{\n    if(this != &other)\n    {\n        m_value = std::unique_ptr<details::_Value>(other.m_value->_copy_value());\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        m_kind = other.m_kind;\n#endif\n    }\n    return *this;\n}\n\nweb::json::value::value(value &&other) CPPREST_NOEXCEPT :\n    m_value(std::move(other.m_value))\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n    ,m_kind(other.m_kind)\n#endif\n{}\n\nweb::json::value &web::json::value::operator=(web::json::value &&other) CPPREST_NOEXCEPT\n{\n    if(this != &other)\n    {\n        m_value.swap(other.m_value);\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        m_kind = other.m_kind;\n#endif\n    }\n    return *this;\n}\n\nweb::json::value web::json::value::null()\n{\n    return web::json::value();\n}\n\nweb::json::value web::json::value::number(double value)\n{\n    return web::json::value(value);\n}\n\nweb::json::value web::json::value::number(int32_t value)\n{\n    return web::json::value(value);\n}\n\nweb::json::value web::json::value::number(uint32_t value)\n{\n    return web::json::value(value);\n}\n\nweb::json::value web::json::value::number(int64_t value)\n{\n    return web::json::value(value);\n}\n\nweb::json::value web::json::value::number(uint64_t value)\n{\n    return web::json::value(value);\n}\n\nweb::json::value web::json::value::boolean(bool value)\n{\n    return web::json::value(value);\n}\n\nweb::json::value web::json::value::string(utility::string_t value)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(std::move(value));\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::String\n#endif\n            );\n}\n\nweb::json::value web::json::value::string(utility::string_t value, bool has_escape_chars)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(std::move(value), has_escape_chars);\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::String\n#endif\n            );\n}\n\n#ifdef _WIN32\nweb::json::value web::json::value::string(const std::string &value)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(utility::conversions::to_utf16string(value));\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::String\n#endif\n            );\n}\n#endif\n\nweb::json::value web::json::value::object(bool keep_order)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Object>(keep_order);\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::Object\n#endif\n            );\n}\n\nweb::json::value web::json::value::object(std::vector<std::pair<::utility::string_t, value>> fields, bool keep_order)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Object>(std::move(fields), keep_order);\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::Object\n#endif\n            );\n}\n\nweb::json::value web::json::value::array()\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>();\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::Array\n#endif\n            );\n}\n\nweb::json::value web::json::value::array(size_t size)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(size);\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::Array\n#endif\n            );\n}\n\nweb::json::value web::json::value::array(std::vector<value> elements)\n{\n    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(std::move(elements));\n    return web::json::value(std::move(ptr)\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            ,value::Array\n#endif\n            );\n}\n\nconst web::json::number& web::json::value::as_number() const\n{\n    return m_value->as_number();\n}\n\ndouble web::json::value::as_double() const\n{\n    return m_value->as_double();\n}\n\nint web::json::value::as_integer() const\n{\n    return m_value->as_integer();\n}\n\nbool web::json::value::as_bool() const\n{\n    return m_value->as_bool();\n}\n\njson::array& web::json::value::as_array()\n{\n    return m_value->as_array();\n}\n\nconst json::array& web::json::value::as_array() const\n{\n    return m_value->as_array();\n}\n\njson::object& web::json::value::as_object()\n{\n    return m_value->as_object();\n}\n\nconst json::object& web::json::value::as_object() const\n{\n    return m_value->as_object();\n}\n\nbool web::json::number::is_int32() const\n{\n    switch (m_type)\n    {\n    case signed_type : return m_intval >= (-2147483647-1) && m_intval <= 2147483647;\n    case unsigned_type : return m_uintval <= 0x7FFFFFFF;\n    case double_type :\n    default :\n        return false;\n    }\n}\n\nbool web::json::number::is_uint32() const\n{\n    switch (m_type)\n    {\n    case signed_type : return m_intval >= 0 && m_intval <= 0xFFFFFFFF;\n    case unsigned_type : return m_uintval <= 0xFFFFFFFF;\n    case double_type :\n    default :\n        return false;\n    }\n}\n\nbool web::json::number::is_int64() const\n{\n    switch (m_type)\n    {\n    case signed_type : return true;\n    case unsigned_type : return m_uintval <= 0xffffffffffffffff;\n    case double_type :\n    default :\n        return false;\n    }\n}\n\nbool web::json::details::_String::has_escape_chars(const _String &str)\n{\n    return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x)\n    {\n        if (x <= 31) { return true; }\n        if (x == '\"') { return true; }\n        if (x == '\\\\') { return true; }\n        return false;\n    });\n}\n\nweb::json::value::value_type json::value::type() const { return m_value->type(); }\n\nbool json::value::is_integer() const\n{\n    if(!is_number())\n    {\n        return false;\n    }\n    return m_value->is_integer();\n}\n\nbool json::value::is_double() const\n{\n    if(!is_number())\n    {\n        return false;\n    }\n    return m_value->is_double();\n}\n\njson::value& web::json::details::_Object::index(const utility::string_t &key)\n{\n    return m_object[key];\n}\n\nbool web::json::details::_Object::has_field(const utility::string_t &key) const\n{\n    return m_object.find(key) != m_object.end();\n}\n\nutility::string_t json::value::to_string() const\n{\n#ifndef _WIN32\n    utility::details::scoped_c_thread_locale locale;\n#endif\n    return m_value->to_string();\n}\n\nbool json::value::operator==(const json::value &other) const\n{\n    if (this->m_value.get() == other.m_value.get())\n        return true;\n    if (this->type() != other.type())\n        return false;\n\n    switch(this->type())\n    {\n    case Null:\n        return true;\n    case Number:\n        return this->as_number() == other.as_number();\n    case Boolean:\n        return this->as_bool() == other.as_bool();\n    case String:\n        return this->as_string() == other.as_string();\n    case Object:\n        return static_cast<const json::details::_Object*>(this->m_value.get())->is_equal(static_cast<const json::details::_Object*>(other.m_value.get()));\n    case Array:\n        return static_cast<const json::details::_Array*>(this->m_value.get())->is_equal(static_cast<const json::details::_Array*>(other.m_value.get()));\n    }\n    __assume(0);\n}\n\nvoid web::json::value::erase(size_t index)\n{\n    return this->as_array().erase(index);\n}\n\nvoid web::json::value::erase(const utility::string_t &key)\n{\n    return this->as_object().erase(key);\n}\n\n// at() overloads\nweb::json::value& web::json::value::at(size_t index)\n{\n    return this->as_array().at(index);\n}\n\nconst web::json::value& web::json::value::at(size_t index) const\n{\n    return this->as_array().at(index);\n}\n\nweb::json::value& web::json::value::at(const utility::string_t& key)\n{\n    return this->as_object().at(key);\n}\n\nconst web::json::value& web::json::value::at(const utility::string_t& key) const\n{\n    return this->as_object().at(key);\n}\n\nweb::json::value& web::json::value::operator [] (const utility::string_t &key)\n{\n    if ( this->is_null() )\n    {\n        m_value.reset(new web::json::details::_Object(details::g_keep_json_object_unsorted));\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        m_kind = value::Object;\n#endif\n    }\n    return m_value->index(key);\n}\n\nweb::json::value& web::json::value::operator[](size_t index)\n{\n    if ( this->is_null() )\n    {\n        m_value.reset(new web::json::details::_Array());\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        m_kind = value::Array;\n#endif\n    }\n    return m_value->index(index);\n}\n\n// Remove once VS 2013 is no longer supported.\n#if defined(_WIN32) && _MSC_VER < 1900\nstatic web::json::details::json_error_category_impl instance;\n#endif\nconst web::json::details::json_error_category_impl& web::json::details::json_error_category()\n{\n#if !defined(_WIN32) || _MSC_VER >= 1900\n    static web::json::details::json_error_category_impl instance;\n#endif\n    return instance;\n}\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/json_parsing.hpp",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: JSON parser\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <cstdlib>\n#include <array>\n\n#if defined(_MSC_VER)\n#pragma warning(disable : 4127) // allow expressions like while(true) pass\n#pragma warning( disable : 4365 )  \n#pragma warning( disable : 4061 )  \n#endif\n\nusing namespace web;\nusing namespace web::json;\nusing namespace utility::conversions;\n\nstd::array<signed char,128> _hexval = {{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n                                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n                                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n                                          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,\n                                         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n                                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n                                         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n                                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }};\n\nnamespace web {\nnamespace json\n{\nnamespace details\n{\n\n//\n// JSON Parsing\n//\n\ntemplate <typename Token>\n#if defined(_WIN32)\n    __declspec(noreturn)\n#else\n    __attribute__((noreturn))\n#endif\nvoid CreateException(const Token &tk, const utility::string_t &message)\n{\n    utility::ostringstream_t os;\n    os << _XPLATSTR(\"* Line \") << tk.start.m_line << _XPLATSTR(\", Column \") << tk.start.m_column << _XPLATSTR(\" Syntax error: \") << message;\n    utility::string_t osStr = os.str();\n    throw web::json::json_exception(osStr.c_str());\n}\n\ntemplate <typename Token>\nvoid SetErrorCode(Token &tk, json_error jsonErrorCode)\n{\n    tk.m_error = std::error_code(jsonErrorCode, json_error_category());\n}\n\ntemplate <typename CharType>\nclass JSON_Parser\n{\npublic:\n    JSON_Parser()\n        : m_currentLine(1),\n          m_currentColumn(1),\n          m_currentParsingDepth(0)\n    { }\n\n    struct Location\n    {\n        size_t m_line;\n        size_t m_column;\n    };\n\n    struct Token\n    {\n        enum Kind\n        {\n            TKN_EOF,\n\n            TKN_OpenBrace,\n            TKN_CloseBrace,\n            TKN_OpenBracket,\n            TKN_CloseBracket,\n            TKN_Comma,\n            TKN_Colon,\n            TKN_StringLiteral,\n            TKN_NumberLiteral,\n            TKN_IntegerLiteral,\n            TKN_BooleanLiteral,\n            TKN_NullLiteral,\n            TKN_Comment\n        };\n\n        Token() : kind(TKN_EOF) {}\n\n        Kind kind;\n        std::basic_string<CharType> string_val;\n\n        typename JSON_Parser<CharType>::Location start{};\n\n        union\n        {\n            double double_val;\n            int64_t int64_val;\n            uint64_t uint64_val;\n            bool boolean_val;\n            bool has_unescape_symbol;\n        };\n\n        bool signed_number{ false };\n\n        std::error_code m_error;\n    };\n\n    void GetNextToken(Token &);\n\n    web::json::value ParseValue(typename JSON_Parser<CharType>::Token &first)\n    {\n#ifndef _WIN32\n        utility::details::scoped_c_thread_locale locale;\n#endif\n\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        auto _value = _ParseValue(first);\n        auto type = _value->type();\n        return web::json::value(std::move(_value), type);\n#else\n        return web::json::value(_ParseValue(first));\n#endif\n    }\n\nprotected:\n    typedef typename std::char_traits<CharType>::int_type int_type;\n    virtual int_type NextCharacter() = 0;\n    virtual int_type PeekCharacter() = 0;\n\n    virtual bool CompleteComment(Token &token);\n    virtual bool CompleteStringLiteral(Token &token);\n    bool handle_unescape_char(Token &token);\n\nprivate:\n\n    bool CompleteNumberLiteral(CharType first, Token &token);\n    bool ParseInt64(CharType first, uint64_t& value);\n    bool CompleteKeywordTrue(Token &token);\n    bool CompleteKeywordFalse(Token &token);\n    bool CompleteKeywordNull(Token &token);\n    std::unique_ptr<web::json::details::_Value> _ParseValue(typename JSON_Parser<CharType>::Token &first);\n    std::unique_ptr<web::json::details::_Value> _ParseObject(typename JSON_Parser<CharType>::Token &tkn);\n    std::unique_ptr<web::json::details::_Value> _ParseArray(typename JSON_Parser<CharType>::Token &tkn);\n\n    JSON_Parser& operator=(const JSON_Parser&);\n\n    int_type EatWhitespace();\n\n    void CreateToken(typename JSON_Parser<CharType>::Token& tk, typename Token::Kind kind, Location &start)\n    {\n        tk.kind = kind;\n        tk.start = start;\n        tk.string_val.clear();\n    }\n\n    void CreateToken(typename JSON_Parser<CharType>::Token& tk, typename Token::Kind kind)\n    {\n        tk.kind = kind;\n        tk.start.m_line = m_currentLine;\n        tk.start.m_column = m_currentColumn;\n        tk.string_val.clear();\n    }\n\nprotected:\n\n    size_t m_currentLine;\n    size_t m_currentColumn;\n    size_t m_currentParsingDepth;\n\n// The DEBUG macro is defined in XCode but we don't in our CMakeList\n// so for now we will keep the same on debug and release. In the future\n// this can be increase on release if necessary.\n#if defined(__APPLE__)\n    static const size_t maxParsingDepth = 32;\n#else\n    static const size_t maxParsingDepth = 128;\n#endif\n};\n\n// Replace with template alias once VS 2012 support is removed.\ntemplate <typename CharType>\ntypename std::char_traits<CharType>::int_type eof()\n{\n    return std::char_traits<CharType>::eof();\n}\n\ntemplate <typename CharType>\nclass JSON_StreamParser : public JSON_Parser<CharType>\n    {\npublic:\n    JSON_StreamParser(std::basic_istream<CharType> &stream)\n        : m_streambuf(stream.rdbuf())\n    {\n    }\n\nprotected:\n\n    virtual typename JSON_Parser<CharType>::int_type NextCharacter();\n    virtual typename JSON_Parser<CharType>::int_type PeekCharacter();\n\nprivate:\n    typename std::basic_streambuf<CharType, std::char_traits<CharType>>* m_streambuf;\n};\n\ntemplate <typename CharType>\nclass JSON_StringParser : public JSON_Parser<CharType>\n{\npublic:\n    JSON_StringParser(const std::basic_string<CharType>& string)\n        : m_position(&string[0])\n    {\n        m_startpos = m_position;\n        m_endpos = m_position+string.size();\n    }\n\nprotected:\n\n    virtual typename JSON_Parser<CharType>::int_type NextCharacter();\n    virtual typename JSON_Parser<CharType>::int_type PeekCharacter();\n\n    virtual bool CompleteComment(typename JSON_Parser<CharType>::Token &token);\n    virtual bool CompleteStringLiteral(typename JSON_Parser<CharType>::Token &token);\n\nprivate:\n    bool finish_parsing_string_with_unescape_char(typename JSON_Parser<CharType>::Token &token);\n    const CharType* m_position;\n    const CharType* m_startpos;\n    const CharType* m_endpos;\n};\n\n\ntemplate <typename CharType>\ntypename JSON_Parser<CharType>::int_type JSON_StreamParser<CharType>::NextCharacter()\n{\n    auto ch = m_streambuf->sbumpc();\n\n    if (ch == '\\n')\n    {\n        this->m_currentLine += 1;\n        this->m_currentColumn = 0;\n    }\n    else\n    {\n        this->m_currentColumn += 1;\n    }\n\n    return ch;\n}\n\ntemplate <typename CharType>\ntypename JSON_Parser<CharType>::int_type JSON_StreamParser<CharType>::PeekCharacter()\n{\n    return m_streambuf->sgetc();\n}\n\ntemplate <typename CharType>\ntypename JSON_Parser<CharType>::int_type JSON_StringParser<CharType>::NextCharacter()\n{\n    if (m_position == m_endpos)\n        return eof<CharType>();\n\n    CharType ch = *m_position;\n    m_position += 1;\n\n    if ( ch == '\\n' )\n    {\n        this->m_currentLine += 1;\n        this->m_currentColumn = 0;\n    }\n    else\n    {\n        this->m_currentColumn += 1;\n    }\n\n    return ch;\n}\n\ntemplate <typename CharType>\ntypename JSON_Parser<CharType>::int_type JSON_StringParser<CharType>::PeekCharacter()\n{\n    if ( m_position == m_endpos ) return eof<CharType>();\n\n    return *m_position;\n}\n\n//\n// Consume whitespace characters and return the first non-space character or EOF\n//\ntemplate <typename CharType>\ntypename JSON_Parser<CharType>::int_type JSON_Parser<CharType>::EatWhitespace()\n{\n   auto ch = NextCharacter();\n\n   while ( ch != eof<CharType>() && iswspace(static_cast<wint_t>(ch)))\n   {\n       ch = NextCharacter();\n   }\n\n   return ch;\n}\n\ntemplate <typename CharType>\nbool JSON_Parser<CharType>::CompleteKeywordTrue(Token &token)\n{\n    if (NextCharacter() != 'r')\n        return false;\n    if (NextCharacter() != 'u')\n        return false;\n    if (NextCharacter() != 'e')\n        return false;\n    token.kind = Token::TKN_BooleanLiteral;\n    token.boolean_val = true;\n    return true;\n}\n\ntemplate <typename CharType>\nbool JSON_Parser<CharType>::CompleteKeywordFalse(Token &token)\n{\n    if (NextCharacter() != 'a')\n        return false;\n    if (NextCharacter() != 'l')\n        return false;\n    if (NextCharacter() != 's')\n        return false;\n    if (NextCharacter() != 'e')\n        return false;\n    token.kind = Token::TKN_BooleanLiteral;\n    token.boolean_val = false;\n    return true;\n}\n\ntemplate <typename CharType>\nbool JSON_Parser<CharType>::CompleteKeywordNull(Token &token)\n{\n    if (NextCharacter() != 'u')\n        return false;\n    if (NextCharacter() != 'l')\n        return false;\n    if (NextCharacter() != 'l')\n        return false;\n    token.kind = Token::TKN_NullLiteral;\n    return true;\n}\n\n// Returns false only on overflow\ntemplate <typename CharType>\ninline bool JSON_Parser<CharType>::ParseInt64(CharType first, uint64_t& value)\n{\n    value = static_cast<uint64_t>(first) - '0';\n    auto ch = PeekCharacter();\n    while (ch >= '0' && ch <= '9')\n    {\n        unsigned int next_digit = (unsigned int)(ch - '0');\n        if (value > (ULLONG_MAX / 10) || (value == ULLONG_MAX/10 && next_digit > ULLONG_MAX%10))\n            return false;\n\n        NextCharacter();\n\n        value *= 10;\n        value += next_digit;\n        ch = PeekCharacter();\n    }\n    return true;\n}\n\n// This namespace hides the x-plat helper functions\nnamespace\n{\n#if defined(_WIN32)\n    static int print_llu(char* ptr, size_t n, uint64_t val64)\n    {\n        return _snprintf_s_l(ptr, n, _TRUNCATE, \"%I64u\", utility::details::scoped_c_thread_locale::c_locale(), val64);\n    }\n\n    static int print_llu(wchar_t* ptr, size_t n, uint64_t val64)\n    {\n        return _snwprintf_s_l(ptr, n, _TRUNCATE, L\"%I64u\", utility::details::scoped_c_thread_locale::c_locale(), val64);\n    }\n    static double anystod(const char* str)\n    {\n        return _strtod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale());\n    }\n    static double anystod(const wchar_t* str)\n    {\n        return _wcstod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale());\n    }\n#else\n    static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long long val64)\n    {\n        return snprintf(ptr, n, \"%llu\", val64);\n    }\n    static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long val64)\n    {\n        return snprintf(ptr, n, \"%lu\", val64);\n    }\n    static double __attribute__((__unused__)) anystod(const char* str)\n    {\n        return strtod(str, nullptr);\n    }\n    static double __attribute__((__unused__)) anystod(const wchar_t* str)\n    {\n        return wcstod(str, nullptr);\n    }\n#endif\n}\n\ntemplate <typename CharType>\nbool JSON_Parser<CharType>::CompleteNumberLiteral(CharType first, Token &token)\n{\n    bool minus_sign;\n\n    if (first == '-')\n    {\n        minus_sign = true;\n\n        // Safe to cast because the check after this if/else statement will cover EOF.\n        first = static_cast<CharType>(NextCharacter());\n    }\n    else\n    {\n        minus_sign = false;\n    }\n\n    if (first < '0' || first > '9')\n        return false;\n\n    auto ch = PeekCharacter();\n\n    //Check for two (or more) zeros at the beginning\n    if (first == '0' && ch == '0')\n        return false;\n\n    // Parse the number assuming its integer\n    uint64_t val64;\n    bool complete = ParseInt64(first, val64);\n\n    ch = PeekCharacter();\n    if (complete && ch!='.' && ch!='E' && ch!='e')\n    {\n        if (minus_sign)\n        {\n            if (val64 > static_cast<uint64_t>(1) << 63 )\n            {\n                // It is negative and cannot be represented in int64, so we resort to double\n                token.double_val = 0 - static_cast<double>(val64);\n                token.signed_number = true;\n                token.kind = JSON_Parser<CharType>::Token::TKN_NumberLiteral;\n                return true;\n            }\n\n            // It is negative, but fits into int64\n            token.int64_val = 0 - static_cast<int64_t>(val64);\n            token.kind = JSON_Parser<CharType>::Token::TKN_IntegerLiteral;\n            token.signed_number = true;\n            return true;\n        }\n\n        // It is positive so we use unsigned int64\n        token.uint64_val = val64;\n        token.kind = JSON_Parser<CharType>::Token::TKN_IntegerLiteral;\n        token.signed_number = false;\n        return true;\n    }\n\n    // Magic number 5 leaves room for decimal point, null terminator, etc (in most cases)\n    ::std::vector<CharType> buf(::std::numeric_limits<uint64_t>::digits10 + 5);\n    int count = print_llu(buf.data(), buf.size(), val64);\n    _ASSERTE(count >= 0);\n    _ASSERTE((size_t)count < buf.size());\n    // Resize to cut off the null terminator\n    buf.resize(count);\n\n    bool decimal = false;\n\n    while (ch != eof<CharType>())\n    {\n        // Digit encountered?\n        if (ch >= '0' && ch <= '9')\n        {\n            buf.push_back(static_cast<CharType>(ch));\n            NextCharacter();\n            ch = PeekCharacter();\n        }\n\n        // Decimal dot?\n        else if (ch == '.')\n        {\n            if (decimal)\n                return false;\n\n            decimal = true;\n            buf.push_back(static_cast<CharType>(ch));\n\n            NextCharacter();\n            ch = PeekCharacter();\n\n            // Check that the following char is a digit\n            if (ch < '0' || ch > '9')\n            return false;\n\n            buf.push_back(static_cast<CharType>(ch));\n            NextCharacter();\n            ch = PeekCharacter();\n        }\n\n        // Exponent?\n        else if (ch == 'E' || ch == 'e')\n        {\n            buf.push_back(static_cast<CharType>(ch));\n            NextCharacter();\n            ch = PeekCharacter();\n\n            // Check for the exponent sign\n            if (ch == '+')\n            {\n                buf.push_back(static_cast<CharType>(ch));\n                NextCharacter();\n                ch = PeekCharacter();\n            }\n            else if (ch == '-')\n            {\n                buf.push_back(static_cast<CharType>(ch));\n                NextCharacter();\n                ch = PeekCharacter();\n            }\n\n            // First number of the exponent\n            if (ch >= '0' && ch <= '9')\n            {\n                buf.push_back(static_cast<CharType>(ch));\n                NextCharacter();\n                ch = PeekCharacter();\n            }\n            else return false;\n\n            // The rest of the exponent\n            while (ch >= '0' && ch <= '9')\n            {\n                buf.push_back(static_cast<CharType>(ch));\n                NextCharacter();\n                ch = PeekCharacter();\n            }\n\n            // The peeked character is not a number, so we can break from the loop and construct the number\n            break;\n        }\n        else\n        {\n            // Not expected number character?\n            break;\n        }\n    };\n\n    buf.push_back('\\0');\n    token.double_val = anystod(buf.data());\n    if (minus_sign)\n    {\n        token.double_val = -token.double_val;\n    }\n    token.kind = (JSON_Parser<CharType>::Token::TKN_NumberLiteral);\n\n    return true;\n}\n\ntemplate <typename CharType>\nbool JSON_Parser<CharType>::CompleteComment(Token &token)\n{\n    // We already found a '/' character as the first of a token -- what kind of comment is it?\n\n    auto ch = NextCharacter();\n\n    if ( ch == eof<CharType>() || (ch != '/' && ch != '*') )\n        return false;\n\n    if ( ch == '/' )\n    {\n        // Line comment -- look for a newline or EOF to terminate.\n\n        ch = NextCharacter();\n\n        while ( ch != eof<CharType>() && ch != '\\n')\n        {\n            ch = NextCharacter();\n        }\n    }\n    else\n    {\n        // Block comment -- look for a terminating \"*/\" sequence.\n\n        ch = NextCharacter();\n\n        while ( true )\n        {\n            if ( ch == eof<CharType>())\n                return false;\n\n            if ( ch == '*' )\n            {\n                auto ch1 = PeekCharacter();\n\n                if ( ch1 == eof<CharType>())\n                    return false;\n\n                if ( ch1 == '/' )\n                {\n                    // Consume the character\n                    NextCharacter();\n                    break;\n                }\n\n                ch = ch1;\n            }\n\n            ch = NextCharacter();\n        }\n    }\n\n    token.kind = Token::TKN_Comment;\n\n    return true;\n}\n\ntemplate <typename CharType>\nbool JSON_StringParser<CharType>::CompleteComment(typename JSON_Parser<CharType>::Token &token)\n{\n    // This function is specialized for the string parser, since we can be slightly more\n    // efficient in copying data from the input to the token: do a memcpy() rather than\n    // one character at a time.\n\n    auto ch = JSON_StringParser<CharType>::NextCharacter();\n\n    if ( ch == eof<CharType>() || (ch != '/' && ch != '*') )\n        return false;\n\n    if ( ch == '/' )\n    {\n        // Line comment -- look for a newline or EOF to terminate.\n\n        ch = JSON_StringParser<CharType>::NextCharacter();\n\n        while ( ch != eof<CharType>() && ch != '\\n')\n        {\n            ch = JSON_StringParser<CharType>::NextCharacter();\n        }\n    }\n    else\n    {\n        // Block comment -- look for a terminating \"*/\" sequence.\n\n        ch = JSON_StringParser<CharType>::NextCharacter();\n\n        while ( true )\n        {\n            if ( ch == eof<CharType>())\n                return false;\n\n            if ( ch == '*' )\n            {\n                ch = JSON_StringParser<CharType>::PeekCharacter();\n\n                if ( ch == eof<CharType>())\n                    return false;\n\n                if ( ch == '/' )\n                {\n                    // Consume the character\n                    JSON_StringParser<CharType>::NextCharacter();\n                    break;\n                }\n\n            }\n\n            ch = JSON_StringParser<CharType>::NextCharacter();\n        }\n    }\n\n    token.kind = JSON_Parser<CharType>::Token::TKN_Comment;\n\n    return true;\n}\n\nvoid convert_append_unicode_code_unit(JSON_Parser<wchar_t>::Token &token, utf16char value)\n{\n    token.string_val.push_back(value);\n}\nvoid convert_append_unicode_code_unit(JSON_Parser<char>::Token &token, utf16char value)\n{\n    utf16string utf16(reinterpret_cast<utf16char *>(&value), 1);\n    token.string_val.append(::utility::conversions::utf16_to_utf8(utf16));\n}\n\ntemplate <typename CharType>\ninline bool JSON_Parser<CharType>::handle_unescape_char(Token &token)\n{\n    token.has_unescape_symbol = true;\n\n    // This function converts unescaped character pairs (e.g. \"\\t\") into their ASCII or Unicode representations (e.g. tab sign)\n    // Also it handles \\u + 4 hexadecimal digits\n    auto ch = NextCharacter();\n    switch (ch)\n    {\n        case '\\\"':\n            token.string_val.push_back('\\\"');\n            return true;\n        case '\\\\':\n            token.string_val.push_back('\\\\');\n            return true;\n        case '/':\n            token.string_val.push_back('/');\n            return true;\n        case 'b':\n            token.string_val.push_back('\\b');\n            return true;\n        case 'f':\n            token.string_val.push_back('\\f');\n            return true;\n        case 'r':\n            token.string_val.push_back('\\r');\n            return true;\n        case 'n':\n            token.string_val.push_back('\\n');\n            return true;\n        case 't':\n            token.string_val.push_back('\\t');\n            return true;\n        case 'u':\n        {\n            // A four-hexdigit Unicode character.\n            // Transform into a 16 bit code point.\n            int decoded = 0;\n            for (int i = 0; i < 4; ++i)\n            {\n                ch = NextCharacter();\n                int ch_int = static_cast<int>(ch);\n                if (ch_int < 0 || ch_int > 127)\n                    return false;\n#ifdef _WIN32\n                const int isxdigitResult = _isxdigit_l(ch_int, utility::details::scoped_c_thread_locale::c_locale());\n#else\n                const int isxdigitResult = isxdigit(ch_int);\n#endif\n                if (!isxdigitResult)\n                    return false;\n\n                int val = _hexval[static_cast<size_t>(ch_int)];\n                _ASSERTE(val != -1);\n\n                // Add the input char to the decoded number\n                decoded |= (val << (4 * (3 - i)));\n            }\n\n            // Construct the character based on the decoded number\n\t\t\tconvert_append_unicode_code_unit(token, static_cast<utf16char>(decoded));\n\n            return true;\n        }\n        default:\n            return false;\n    }\n}\n\ntemplate <typename CharType>\nbool JSON_Parser<CharType>::CompleteStringLiteral(Token &token)\n{\n    token.has_unescape_symbol = false;\n    auto ch = NextCharacter();\n    while ( ch != '\"' )\n    {\n        if ( ch == '\\\\' )\n        {\n            handle_unescape_char(token);\n        }\n        else if (ch >= CharType(0x0) && ch < CharType(0x20))\n        {\n            return false;\n        }\n        else\n        {\n            if (ch == eof<CharType>())\n                return false;\n\n            token.string_val.push_back(static_cast<CharType>(ch));\n        }\n        ch = NextCharacter();\n    }\n\n    if ( ch == '\"' )\n    {\n        token.kind = Token::TKN_StringLiteral;\n    }\n    else\n    {\n        return false;\n    }\n\n    return true;\n}\n\ntemplate <typename CharType>\nbool JSON_StringParser<CharType>::CompleteStringLiteral(typename JSON_Parser<CharType>::Token &token)\n{\n    // This function is specialized for the string parser, since we can be slightly more\n    // efficient in copying data from the input to the token: do a memcpy() rather than\n    // one character at a time.\n\n    auto start = m_position;\n    token.has_unescape_symbol = false;\n\n    auto ch = JSON_StringParser<CharType>::NextCharacter();\n\n    while (ch != '\"')\n    {\n        if (ch == eof<CharType>())\n            return false;\n\n        if (ch == '\\\\')\n        {\n            const size_t numChars = m_position - start - 1;\n            const size_t prevSize = token.string_val.size();\n            token.string_val.resize(prevSize + numChars);\n            memcpy(const_cast<CharType *>(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType));\n\n            if (!JSON_StringParser<CharType>::handle_unescape_char(token))\n            {\n                return false;\n            }\n\n            // Reset start position and continue.\n            start = m_position;\n        }\n        else if (ch >= CharType(0x0) && ch < CharType(0x20))\n        {\n            return false;\n        }\n\n        ch = JSON_StringParser<CharType>::NextCharacter();\n    }\n\n    const size_t numChars = m_position - start - 1;\n    const size_t prevSize = token.string_val.size();\n    token.string_val.resize(prevSize + numChars);\n    memcpy(const_cast<CharType *>(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType));\n\n    token.kind = JSON_Parser<CharType>::Token::TKN_StringLiteral;\n\n    return true;\n}\n\ntemplate <typename CharType>\nvoid JSON_Parser<CharType>::GetNextToken(typename JSON_Parser<CharType>::Token& result)\n{\ntry_again:\n    auto ch = EatWhitespace();\n\n    CreateToken(result, Token::TKN_EOF);\n\n    if (ch == eof<CharType>()) return;\n\n    switch (ch)\n    {\n    case '{':\n    case '[':\n        {\n            if(++m_currentParsingDepth > JSON_Parser<CharType>::maxParsingDepth)\n            {\n                SetErrorCode(result, json_error::nesting);\n                break;\n            }\n\n            typename JSON_Parser<CharType>::Token::Kind tk = ch == '{' ? Token::TKN_OpenBrace : Token::TKN_OpenBracket;\n            CreateToken(result, tk, result.start);\n            break;\n        }\n    case '}':\n    case ']':\n        {\n            if((signed int)(--m_currentParsingDepth) < 0)\n            {\n                SetErrorCode(result, json_error::mismatched_brances);\n                break;\n            }\n\n            typename JSON_Parser<CharType>::Token::Kind tk = ch == '}' ? Token::TKN_CloseBrace : Token::TKN_CloseBracket;\n            CreateToken(result, tk, result.start);\n            break;\n        }\n    case ',':\n        CreateToken(result, Token::TKN_Comma, result.start);\n        break;\n\n    case ':':\n        CreateToken(result, Token::TKN_Colon, result.start);\n        break;\n\n    case 't':\n        if (!CompleteKeywordTrue(result))\n        {\n            SetErrorCode(result, json_error::malformed_literal);\n        }\n        break;\n    case 'f':\n        if (!CompleteKeywordFalse(result))\n        {\n            SetErrorCode(result, json_error::malformed_literal);\n        }\n        break;\n    case 'n':\n        if (!CompleteKeywordNull(result))\n        {\n            SetErrorCode(result, json_error::malformed_literal);\n        }\n        break;\n    case '/':\n        if (!CompleteComment(result))\n        {\n            SetErrorCode(result, json_error::malformed_comment);\n            break;\n        }\n        // For now, we're ignoring comments.\n        goto try_again;\n    case '\"':\n        if (!CompleteStringLiteral(result))\n        {\n            SetErrorCode(result, json_error::malformed_string_literal);\n        }\n        break;\n\n    case '-':\n    case '0':\n    case '1':\n    case '2':\n    case '3':\n    case '4':\n    case '5':\n    case '6':\n    case '7':\n    case '8':\n    case '9':\n        if (!CompleteNumberLiteral(static_cast<CharType>(ch), result))\n        {\n            SetErrorCode(result, json_error::malformed_numeric_literal);\n        }\n        break;\n    default:\n        SetErrorCode(result, json_error::malformed_token);\n        break;\n    }\n}\n\ntemplate <typename CharType>\nstd::unique_ptr<web::json::details::_Value> JSON_Parser<CharType>::_ParseObject(typename JSON_Parser<CharType>::Token &tkn)\n{\n    auto obj = utility::details::make_unique<web::json::details::_Object>(g_keep_json_object_unsorted);\n    auto& elems = obj->m_object.m_elements;\n\n    GetNextToken(tkn);\n    if (tkn.m_error) goto error;\n\n    if (tkn.kind != JSON_Parser<CharType>::Token::TKN_CloseBrace)\n    {\n        while (true)\n        {\n            // State 1: New field or end of object, looking for field name or closing brace\n            std::basic_string<CharType> fieldName;\n            switch (tkn.kind)\n            {\n            case JSON_Parser<CharType>::Token::TKN_StringLiteral:\n                fieldName = std::move(tkn.string_val);\n                break;\n            default:\n                goto error;\n            }\n\n            GetNextToken(tkn);\n            if (tkn.m_error) goto error;\n\n            // State 2: Looking for a colon.\n            if (tkn.kind != JSON_Parser<CharType>::Token::TKN_Colon) goto done;\n\n            GetNextToken(tkn);\n            if (tkn.m_error) goto error;\n\n            // State 3: Looking for an expression.\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n            auto fieldValue = _ParseValue(tkn);\n            auto type = fieldValue->type();\n            elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), json::value(std::move(fieldValue), type));\n#else\n            elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), json::value(_ParseValue(tkn)));\n#endif\n            if (tkn.m_error) goto error;\n\n            // State 4: Looking for a comma or a closing brace\n            switch (tkn.kind)\n            {\n            case JSON_Parser<CharType>::Token::TKN_Comma:\n                GetNextToken(tkn);\n                if (tkn.m_error) goto error;\n                break;\n            case JSON_Parser<CharType>::Token::TKN_CloseBrace:\n                goto done;\n            default:\n                goto error;\n            }\n        }\n    }\n\ndone:\n    GetNextToken(tkn);\n    if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n\n    if (!g_keep_json_object_unsorted) {\n        ::std::sort(elems.begin(), elems.end(), json::object::compare_pairs);\n    }\n\n    return std::move(obj);\n\nerror:\n    if (!tkn.m_error)\n    {\n        SetErrorCode(tkn, json_error::malformed_object_literal);\n    }\n    return utility::details::make_unique<web::json::details::_Null>();\n}\n\ntemplate <typename CharType>\nstd::unique_ptr<web::json::details::_Value> JSON_Parser<CharType>::_ParseArray(typename JSON_Parser<CharType>::Token &tkn)\n{\n    GetNextToken(tkn);\n    if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n\n    auto result = utility::details::make_unique<web::json::details::_Array>();\n\n    if (tkn.kind != JSON_Parser<CharType>::Token::TKN_CloseBracket)\n    {\n        while (true)\n        {\n            // State 1: Looking for an expression.\n            result->m_array.m_elements.emplace_back(ParseValue(tkn));\n            if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n\n            // State 4: Looking for a comma or a closing bracket\n            switch (tkn.kind)\n            {\n            case JSON_Parser<CharType>::Token::TKN_Comma:\n                GetNextToken(tkn);\n                if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n                break;\n            case JSON_Parser<CharType>::Token::TKN_CloseBracket:\n                GetNextToken(tkn);\n                if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n                return std::move(result);\n            default:\n                SetErrorCode(tkn, json_error::malformed_array_literal);\n                return utility::details::make_unique<web::json::details::_Null>();\n            }\n        }\n    }\n\n    GetNextToken(tkn);\n    if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n\n    return std::move(result);\n}\n\ntemplate <typename CharType>\nstd::unique_ptr<web::json::details::_Value> JSON_Parser<CharType>::_ParseValue(typename JSON_Parser<CharType>::Token &tkn)\n{\n    switch (tkn.kind)\n    {\n        case JSON_Parser<CharType>::Token::TKN_OpenBrace:\n            {\n                return _ParseObject(tkn);\n            }\n        case JSON_Parser<CharType>::Token::TKN_OpenBracket:\n            {\n                return _ParseArray(tkn);\n            }\n        case JSON_Parser<CharType>::Token::TKN_StringLiteral:\n            {\n                auto value = utility::details::make_unique<web::json::details::_String>(std::move(tkn.string_val), tkn.has_unescape_symbol);\n                GetNextToken(tkn);\n                if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n                return std::move(value);\n            }\n        case JSON_Parser<CharType>::Token::TKN_IntegerLiteral:\n            {\n                std::unique_ptr<web::json::details::_Number> value;\n                if (tkn.signed_number)\n                    value = utility::details::make_unique<web::json::details::_Number>(tkn.int64_val);\n                else\n                    value = utility::details::make_unique<web::json::details::_Number>(tkn.uint64_val);\n\n                GetNextToken(tkn);\n                if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n                return std::move(value);\n            }\n        case JSON_Parser<CharType>::Token::TKN_NumberLiteral:\n            {\n                auto value = utility::details::make_unique<web::json::details::_Number>(tkn.double_val);\n                GetNextToken(tkn);\n                if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n                return std::move(value);\n            }\n        case JSON_Parser<CharType>::Token::TKN_BooleanLiteral:\n            {\n                auto value = utility::details::make_unique<web::json::details::_Boolean>(tkn.boolean_val);\n                GetNextToken(tkn);\n                if (tkn.m_error) return utility::details::make_unique<web::json::details::_Null>();\n                return std::move(value);\n            }\n        case JSON_Parser<CharType>::Token::TKN_NullLiteral:\n            {\n                GetNextToken(tkn);\n                // Returning a null value whether or not an error occurred.\n                return utility::details::make_unique<web::json::details::_Null>();\n            }\n        default:\n            {\n                SetErrorCode(tkn, json_error::malformed_token);\n                return utility::details::make_unique<web::json::details::_Null>();\n            }\n    }\n}\n\n}}}\n\nstatic web::json::value _parse_stream(utility::istream_t &stream)\n{\n    web::json::details::JSON_StreamParser<utility::char_t> parser(stream);\n    web::json::details::JSON_Parser<utility::char_t>::Token tkn;\n\n    parser.GetNextToken(tkn);\n    if (tkn.m_error)\n    {\n        web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message()));\n    }\n\n    auto value = parser.ParseValue(tkn);\n    if (tkn.m_error)\n    {\n        web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message()));\n    }\n    else if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)\n    {\n        web::json::details::CreateException(tkn, _XPLATSTR(\"Left-over characters in stream after parsing a JSON value\"));\n    }\n    return value;\n}\n\nstatic web::json::value _parse_stream(utility::istream_t &stream, std::error_code& error)\n{\n    web::json::details::JSON_StreamParser<utility::char_t> parser(stream);\n    web::json::details::JSON_Parser<utility::char_t>::Token tkn;\n\n    parser.GetNextToken(tkn);\n    if (tkn.m_error)\n    {\n        error = std::move(tkn.m_error);\n        return web::json::value();\n    }\n\n    auto returnObject = parser.ParseValue(tkn);\n    if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)\n    {\n        web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream);\n    }\n\n    error = std::move(tkn.m_error);\n    return returnObject;\n}\n\n#ifdef _WIN32\nstatic web::json::value _parse_narrow_stream(std::istream &stream)\n{\n    web::json::details::JSON_StreamParser<char> parser(stream);\n    web::json::details::JSON_StreamParser<char>::Token tkn;\n\n    parser.GetNextToken(tkn);\n    if (tkn.m_error)\n    {\n        web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message()));\n    }\n\n    auto value = parser.ParseValue(tkn);\n    if (tkn.m_error)\n    {\n        web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message()));\n    }\n    else if (tkn.kind != web::json::details::JSON_Parser<char>::Token::TKN_EOF)\n    {\n        web::json::details::CreateException(tkn, _XPLATSTR(\"Left-over characters in stream after parsing a JSON value\"));\n    }\n    return value;\n}\n\nstatic web::json::value _parse_narrow_stream(std::istream &stream, std::error_code& error)\n{\n    web::json::details::JSON_StreamParser<char> parser(stream);\n    web::json::details::JSON_StreamParser<char>::Token tkn;\n\n    parser.GetNextToken(tkn);\n    if (tkn.m_error)\n    {\n        error = std::move(tkn.m_error);\n        return web::json::value();\n    }\n\n    auto returnObject = parser.ParseValue(tkn);\n    if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)\n    {\n        returnObject = web::json::value();\n        web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream);\n    }\n\n    error = std::move(tkn.m_error);\n    return returnObject;\n}\n#endif\n\nweb::json::value web::json::value::parse(const utility::string_t& str)\n{\n    web::json::details::JSON_StringParser<utility::char_t> parser(str);\n    web::json::details::JSON_Parser<utility::char_t>::Token tkn;\n\n    parser.GetNextToken(tkn);\n    if (tkn.m_error)\n    {\n        web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message()));\n    }\n\n    auto value = parser.ParseValue(tkn);\n    if (tkn.m_error)\n    {\n        web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message()));\n    }\n    else if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)\n    {\n        web::json::details::CreateException(tkn, _XPLATSTR(\"Left-over characters in stream after parsing a JSON value\"));\n    }\n    return value;\n}\n\nweb::json::value web::json::value::parse(const utility::string_t& str, std::error_code& error)\n{\n    web::json::details::JSON_StringParser<utility::char_t> parser(str);\n    web::json::details::JSON_Parser<utility::char_t>::Token tkn;\n\n    parser.GetNextToken(tkn);\n    if (tkn.m_error)\n    {\n        error = std::move(tkn.m_error);\n        return web::json::value();\n    }\n\n    auto returnObject = parser.ParseValue(tkn);\n    if (tkn.kind != web::json::details::JSON_Parser<utility::char_t>::Token::TKN_EOF)\n    {\n        returnObject = web::json::value();\n        web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream);\n    }\n\n    error = std::move(tkn.m_error);\n    return returnObject;\n}\n\nweb::json::value web::json::value::parse(utility::istream_t &stream)\n{\n    return _parse_stream(stream);\n}\n\nweb::json::value web::json::value::parse(utility::istream_t &stream, std::error_code& error)\n{\n    return _parse_stream(stream, error);\n}\n\n#ifdef _WIN32\nweb::json::value web::json::value::parse(std::istream& stream)\n{\n    return _parse_narrow_stream(stream);\n}\n\nweb::json::value web::json::value::parse(std::istream& stream, std::error_code& error)\n{\n    return _parse_narrow_stream(stream, error);\n}\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/json_serialization.hpp",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: JSON parser and writer\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <stdio.h>\n#include <array>\n\n#ifndef _WIN32\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n#endif\n\nusing namespace web;\nusing namespace web::json;\nusing namespace utility::conversions;\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 4365 )  \n#endif\n\n//\n// JSON Serialization\n//\n\n#ifdef _WIN32\nvoid web::json::value::serialize(std::ostream& stream) const\n{\n    // This has better performance than writing directly to stream.\n    std::string str;\n    m_value->serialize_impl(str);\n    stream << str;\n}\nvoid web::json::value::format(std::basic_string<wchar_t> &string) const\n{\n    m_value->format(string);\n}\n#endif\n\nvoid web::json::value::serialize(utility::ostream_t &stream) const\n{\n#ifndef _WIN32\n    utility::details::scoped_c_thread_locale locale;\n#endif\n\n    // This has better performance than writing directly to stream.\n    utility::string_t str;\n    m_value->serialize_impl(str);\n    stream << str;\n}\n\nvoid web::json::value::format(std::basic_string<char>& string) const\n{\n    m_value->format(string);\n}\n\ntemplate<typename CharType>\nvoid web::json::details::append_escape_string(std::basic_string<CharType>& str, const std::basic_string<CharType>& escaped)\n{\n    for (const auto &ch : escaped)\n    {\n        switch (ch)\n        {\n            case '\\\"':\n                str += '\\\\';\n                str += '\\\"';\n                break;\n            case '\\\\':\n                str += '\\\\';\n                str += '\\\\';\n                break;\n            case '\\b':\n                str += '\\\\';\n                str += 'b';\n                break;\n            case '\\f':\n                str += '\\\\';\n                str += 'f';\n                break;\n            case '\\r':\n                str += '\\\\';\n                str += 'r';\n                break;\n            case '\\n':\n                str += '\\\\';\n                str += 'n';\n                break;\n            case '\\t':\n                str += '\\\\';\n                str += 't';\n                break;\n            default:\n\n                // If a control character then must unicode escaped.\n                if (ch >= 0 && ch <= 0x1F)\n                {\n                    static const std::array<CharType, 16> intToHex = { { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } };\n                    str += '\\\\';\n                    str += 'u';\n                    str += '0';\n                    str += '0';\n                    str += intToHex[(ch & 0xF0) >> 4];\n                    str += intToHex[ch & 0x0F];\n                }\n                else\n                {\n                    str += ch;\n                }\n        }\n    }\n}\n\nvoid web::json::details::format_string(const utility::string_t& key, utility::string_t& str)\n{\n    str.push_back('\"');\n    append_escape_string(str, key);\n    str.push_back('\"');\n}\n\n#ifdef _WIN32\nvoid web::json::details::format_string(const utility::string_t& key, std::string& str)\n{\n    str.push_back('\"');\n    append_escape_string(str, utility::conversions::to_utf8string(key));\n    str.push_back('\"');\n}\n#endif\n\nvoid web::json::details::_String::format(std::basic_string<char>& str) const\n{\n    str.push_back('\"');\n\n    if(m_has_escape_char)\n    {\n        append_escape_string(str, utility::conversions::to_utf8string(m_string));\n    }\n    else\n    {\n        str.append(utility::conversions::to_utf8string(m_string));\n    }\n\n    str.push_back('\"');\n}\n\nvoid web::json::details::_Number::format(std::basic_string<char>& stream) const\n{\n    if(m_number.m_type != number::type::double_type)\n    {\n        // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.\n        const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;\n        char tempBuffer[tempSize];\n\n#ifdef _WIN32\n        // This can be improved performance-wise if we implement our own routine\n        if (m_number.m_type == number::type::signed_type)\n            _i64toa_s(m_number.m_intval, tempBuffer, tempSize, 10);\n        else\n            _ui64toa_s(m_number.m_uintval, tempBuffer, tempSize, 10);\n\n        const auto numChars = strnlen_s(tempBuffer, tempSize);\n#else\n        int numChars;\n        if (m_number.m_type == number::type::signed_type)\n            numChars = snprintf(tempBuffer, tempSize, \"%\" PRId64, m_number.m_intval);\n        else\n            numChars = snprintf(tempBuffer, tempSize, \"%\" PRIu64, m_number.m_uintval);\n#endif\n        stream.append(tempBuffer, numChars);\n    }\n    else\n    {\n        // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator\n        const size_t tempSize = std::numeric_limits<double>::digits10 + 10;\n        char tempBuffer[tempSize];\n#ifdef _WIN32\n        const auto numChars = _sprintf_s_l(\n            tempBuffer,\n            tempSize,\n            \"%.*g\",\n            utility::details::scoped_c_thread_locale::c_locale(),\n            std::numeric_limits<double>::digits10 + 2,\n            m_number.m_value);\n#else\n        const auto numChars = snprintf(tempBuffer, tempSize, \"%.*g\", std::numeric_limits<double>::digits10 + 2, m_number.m_value);\n#endif\n        stream.append(tempBuffer, numChars);\n    }\n}\n\n#ifdef _WIN32\n\nvoid web::json::details::_String::format(std::basic_string<wchar_t>& str) const\n{\n    str.push_back(L'\"');\n\n    if(m_has_escape_char)\n    {\n        append_escape_string(str, m_string);\n    }\n    else\n    {\n        str.append(m_string);\n    }\n\n    str.push_back(L'\"');\n}\n\nvoid web::json::details::_Number::format(std::basic_string<wchar_t>& stream) const\n{\n    if(m_number.m_type != number::type::double_type)\n    {\n        // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.\n        const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;\n        wchar_t tempBuffer[tempSize];\n\n        if (m_number.m_type == number::type::signed_type)\n            _i64tow_s(m_number.m_intval, tempBuffer, tempSize, 10);\n        else\n            _ui64tow_s(m_number.m_uintval, tempBuffer, tempSize, 10);\n\n        stream.append(tempBuffer, wcsnlen_s(tempBuffer, tempSize));\n    }\n    else\n    {\n        // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator\n        const size_t tempSize = std::numeric_limits<double>::digits10 + 10;\n        wchar_t tempBuffer[tempSize];\n        const int numChars = _swprintf_s_l(\n            tempBuffer,\n            tempSize,\n            L\"%.*g\",\n            utility::details::scoped_c_thread_locale::c_locale(),\n            std::numeric_limits<double>::digits10 + 2,\n            m_number.m_value);\n        stream.append(tempBuffer, numChars);\n    }\n}\n\n#endif\n\nconst utility::string_t & web::json::details::_String::as_string() const\n{\n    return m_string;\n}\n\nconst utility::string_t & web::json::value::as_string() const\n{\n    return m_value->as_string();\n}\n\nutility::string_t json::value::serialize() const\n{\n#ifndef _WIN32\n    utility::details::scoped_c_thread_locale locale;\n#endif\n    return m_value->to_string();\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/nosal.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n***/\n\n#pragma once\n// selected MS SAL annotations\n\n#ifdef _In_\n#undef _In_\n#endif\n#define _In_\n\n#ifdef _Inout_\n#undef _Inout_\n#endif\n#define _Inout_\n\n#ifdef _Out_\n#undef _Out_\n#endif\n#define _Out_\n\n#ifdef _In_z_\n#undef _In_z_\n#endif\n#define _In_z_\n\n#ifdef _Out_z_\n#undef _Out_z_\n#endif\n#define _Out_z_\n\n#ifdef _Inout_z_\n#undef _Inout_z_\n#endif\n#define _Inout_z_\n\n#ifdef _In_opt_\n#undef _In_opt_\n#endif\n#define _In_opt_\n\n#ifdef _Out_opt_\n#undef _Out_opt_\n#endif\n#define _Out_opt_\n\n#ifdef _Inout_opt_\n#undef _Inout_opt_\n#endif\n#define _Inout_opt_\n\n#ifdef _Out_writes_\n#undef _Out_writes_\n#endif\n#define _Out_writes_(x)\n\n#ifdef _Out_writes_opt_\n#undef _Out_writes_opt_\n#endif\n#define _Out_writes_opt_(x)\n\n#ifdef _In_reads_\n#undef _In_reads_\n#endif\n#define _In_reads_(x)\n\n#ifdef _Inout_updates_bytes_\n#undef _Inout_updates_bytes_\n#endif\n#define _Inout_updates_bytes_(x)"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/uri.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Protocol independent support for URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\nusing namespace utility::conversions;\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#pragma warning( disable : 26812 )  // enum instead of enum class\n#pragma warning( disable : 4365 )  \n#endif\n\nnamespace web { namespace details\n{\nutility::string_t uri_components::join()\n{\n    // canonicalize components first\n\n    // convert scheme to lowercase\n    std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [](utility::char_t c) {\n        return (utility::char_t)tolower(c);\n    });\n\n    // convert host to lowercase\n    std::transform(m_host.begin(), m_host.end(), m_host.begin(), [](utility::char_t c) {\n        return (utility::char_t)tolower(c);\n    });\n\n    // canonicalize the path to have a leading slash if it's a full uri\n    if (!m_host.empty() && m_path.empty())\n    {\n        m_path = _XPLATSTR(\"/\");\n    }\n    else if (!m_host.empty() && m_path[0] != _XPLATSTR('/'))\n    {\n        m_path.insert(m_path.begin(), 1, _XPLATSTR('/'));\n    }\n\n    utility::string_t ret;\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800))\n    if (!m_scheme.empty())\n    {\n        ret.append(m_scheme).append({ _XPLATSTR(':') });\n    }\n\n    if (!m_host.empty())\n    {\n        ret.append(_XPLATSTR(\"//\"));\n\n        if (!m_user_info.empty())\n        {\n            ret.append(m_user_info).append({ _XPLATSTR('@') });\n        }\n\n        ret.append(m_host);\n\n        if (m_port > 0)\n        {\n            ret.append({ _XPLATSTR(':') }).append(utility::conversions::print_string(m_port, std::locale::classic()));\n        }\n    }\n\n    if (!m_path.empty())\n    {\n        // only add the leading slash when the host is present\n        if (!m_host.empty() && m_path.front() != _XPLATSTR('/'))\n        {\n            ret.append({ _XPLATSTR('/') });\n        }\n\n        ret.append(m_path);\n    }\n\n    if (!m_query.empty())\n    {\n        ret.append({ _XPLATSTR('?') }).append(m_query);\n    }\n\n    if (!m_fragment.empty())\n    {\n        ret.append({ _XPLATSTR('#') }).append(m_fragment);\n    }\n\n    return ret;\n#else\n    utility::ostringstream_t os;\n    os.imbue(std::locale::classic());\n\n    if (!m_scheme.empty())\n    {\n        os << m_scheme << _XPLATSTR(':');\n    }\n\n    if (!m_host.empty())\n    {\n        os << _XPLATSTR(\"//\");\n\n        if (!m_user_info.empty())\n        {\n            os << m_user_info << _XPLATSTR('@');\n        }\n\n        os << m_host;\n\n        if (m_port > 0)\n        {\n            os << _XPLATSTR(':') << m_port;\n        }\n    }\n\n    if (!m_path.empty())\n    {\n        // only add the leading slash when the host is present\n        if (!m_host.empty() && m_path.front() != _XPLATSTR('/'))\n        {\n            os << _XPLATSTR('/');\n        }\n        os << m_path;\n    }\n\n    if (!m_query.empty())\n    {\n        os << _XPLATSTR('?') << m_query;\n    }\n\n    if (!m_fragment.empty())\n    {\n        os << _XPLATSTR('#') << m_fragment;\n    }\n\n    return os.str();\n#endif\n}\n}\n\nusing namespace details;\n\nuri::uri(const details::uri_components &components) : m_components(components)\n{\n    m_uri = m_components.join();\n    if (!details::uri_parser::validate(m_uri))\n    {\n        throw uri_exception(\"provided uri is invalid: \" + utility::conversions::to_utf8string(m_uri));\n    }\n}\n\nuri::uri(const utility::string_t &uri_string)\n{\n    if (!details::uri_parser::parse(uri_string, m_components))\n    {\n        throw uri_exception(\"provided uri is invalid: \" + utility::conversions::to_utf8string(uri_string));\n    }\n    m_uri = m_components.join();\n}\n\nuri::uri(const utility::char_t *uri_string): m_uri(uri_string)\n{\n    if (!details::uri_parser::parse(uri_string, m_components))\n    {\n        throw uri_exception(\"provided uri is invalid: \" + utility::conversions::to_utf8string(uri_string));\n    }\n    m_uri = m_components.join();\n}\n\nutility::string_t uri::encode_impl(const utility::string_t &raw, const std::function<bool(int)>& should_encode)\n{\n    const utility::char_t * const hex = _XPLATSTR(\"0123456789ABCDEF\");\n    utility::string_t encoded;\n    std::string utf8raw = to_utf8string(raw);\n    for (auto iter = utf8raw.begin(); iter != utf8raw.end(); ++iter)\n    {\n        // for utf8 encoded string, char ASCII can be greater than 127.\n        int ch = static_cast<unsigned char>(*iter);\n        // ch should be same under both utf8 and utf16.\n        if(should_encode(ch))\n        {\n            encoded.push_back(_XPLATSTR('%'));\n            encoded.push_back(hex[(ch >> 4) & 0xF]);\n            encoded.push_back(hex[ch & 0xF]);\n        }\n        else\n        {\n            // ASCII don't need to be encoded, which should be same on both utf8 and utf16.\n            encoded.push_back((utility::char_t)ch);\n        }\n    }\n    return encoded;\n}\n\n/// <summary>\n/// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their\n/// hexadecimal representation.\n/// </summary>\nutility::string_t uri::encode_data_string(const utility::string_t &raw)\n{\n    return uri::encode_impl(raw, [](int ch) -> bool\n    {\n        return !uri_parser::is_unreserved(ch);\n    });\n}\n\nutility::string_t uri::encode_uri(const utility::string_t &raw, uri::components::component component)\n{\n    // Note: we also encode the '+' character because some non-standard implementations\n    // encode the space character as a '+' instead of %20. To better interoperate we encode\n    // '+' to avoid any confusion and be mistaken as a space.\n    switch(component)\n    {\n    case components::user_info:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_user_info_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::host:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            // No encoding of ASCII characters in host name (RFC 3986 3.2.2)\n            return ch > 127;\n        });\n    case components::path:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_path_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::query:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_query_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::fragment:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_fragment_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::full_uri:\n    default:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_unreserved(ch) && !uri_parser::is_reserved(ch);\n        });\n    };\n}\n\n/// <summary>\n/// Helper function to convert a hex character digit to a decimal character value.\n/// Throws an exception if not a valid hex digit.\n/// </summary>\nstatic int hex_char_digit_to_decimal_char(int hex)\n{\n    int decimal;\n    if(hex >= '0' && hex <= '9')\n    {\n        decimal = hex - '0';\n    }\n    else if(hex >= 'A' && hex <= 'F')\n    {\n        decimal = 10 + (hex - 'A');\n    }\n    else if(hex >= 'a' && hex <= 'f')\n    {\n        decimal = 10 + (hex - 'a');\n    }\n    else\n    {\n        throw uri_exception(\"Invalid hexadecimal digit\");\n    }\n    return decimal;\n}\n\nutility::string_t uri::decode(const utility::string_t &encoded)\n{\n    std::string utf8raw;\n    for(auto iter = encoded.begin(); iter != encoded.end(); ++iter)\n    {\n        if(*iter == _XPLATSTR('%'))\n        {\n            if(++iter == encoded.end())\n            {\n                throw uri_exception(\"Invalid URI string, two hexadecimal digits must follow '%'\");\n            }\n            int decimal_value = hex_char_digit_to_decimal_char(static_cast<int>(*iter)) << 4;\n            if(++iter == encoded.end())\n            {\n                throw uri_exception(\"Invalid URI string, two hexadecimal digits must follow '%'\");\n            }\n            decimal_value += hex_char_digit_to_decimal_char(static_cast<int>(*iter));\n\n            utf8raw.push_back(static_cast<char>(decimal_value));\n        }\n        else\n        {\n            // encoded string has to be ASCII.\n            utf8raw.push_back(reinterpret_cast<const char &>(*iter));\n        }\n    }\n    return to_string_t(utf8raw);\n}\n\nstd::vector<utility::string_t> uri::split_path(const utility::string_t &path)\n{\n    std::vector<utility::string_t> results;\n    utility::istringstream_t iss(path);\n    iss.imbue(std::locale::classic());\n    utility::string_t s;\n\n    while (std::getline(iss, s, _XPLATSTR('/')))\n    {\n        if (!s.empty())\n        {\n            results.push_back(s);\n        }\n    }\n\n    return results;\n}\n\nstd::map<utility::string_t, utility::string_t> uri::split_query(const utility::string_t &query)\n{\n    std::map<utility::string_t, utility::string_t> results;\n\n    // Split into key value pairs separated by '&'.\n    size_t prev_amp_index = 0;\n    while(prev_amp_index != utility::string_t::npos)\n    {\n        size_t amp_index = query.find_first_of(_XPLATSTR('&'), prev_amp_index);\n        if (amp_index == utility::string_t::npos)\n            amp_index = query.find_first_of(_XPLATSTR(';'), prev_amp_index);\n\n        utility::string_t key_value_pair = query.substr(\n            prev_amp_index,\n            amp_index == utility::string_t::npos ? query.size() - prev_amp_index : amp_index - prev_amp_index);\n        prev_amp_index = amp_index == utility::string_t::npos ? utility::string_t::npos : amp_index + 1;\n\n        size_t equals_index = key_value_pair.find_first_of(_XPLATSTR('='));\n        if(equals_index == utility::string_t::npos)\n        {\n            continue;\n        }\n        else if (equals_index == 0)\n        {\n            utility::string_t value(key_value_pair.begin() + equals_index + 1, key_value_pair.end());\n            results[_XPLATSTR(\"\")] = value;\n        }\n        else\n        {\n            utility::string_t key(key_value_pair.begin(), key_value_pair.begin() + equals_index);\n            utility::string_t value(key_value_pair.begin() + equals_index + 1, key_value_pair.end());\n        results[key] = value;\n    }\n    }\n\n    return results;\n}\n\nbool uri::validate(const utility::string_t &uri_string)\n{\n    return uri_parser::validate(uri_string);\n}\n\nuri uri::authority() const\n{\n    return uri_builder().set_scheme(this->scheme()).set_host(this->host()).set_port(this->port()).set_user_info(this->user_info()).to_uri();\n}\n\nuri uri::resource() const\n{\n    return uri_builder().set_path(this->path()).set_query(this->query()).set_fragment(this->fragment()).to_uri();\n}\n\nbool uri::operator == (const uri &other) const\n{\n    // Each individual URI component must be decoded before performing comparison.\n    // TFS # 375865\n\n    if (this->is_empty() && other.is_empty())\n    {\n        return true;\n    }\n    else if (this->is_empty() || other.is_empty())\n    {\n        return false;\n    }\n    else if (this->scheme() != other.scheme())\n    {\n        // scheme is canonicalized to lowercase\n        return false;\n    }\n    else if(uri::decode(this->user_info()) != uri::decode(other.user_info()))\n    {\n        return false;\n    }\n    else if (uri::decode(this->host()) != uri::decode(other.host()))\n    {\n        // host is canonicalized to lowercase\n        return false;\n    }\n    else if (this->port() != other.port())\n    {\n        return false;\n    }\n    else if (uri::decode(this->path()) != uri::decode(other.path()))\n    {\n        return false;\n    }\n    else if (uri::decode(this->query()) != uri::decode(other.query()))\n    {\n        return false;\n    }\n    else if (uri::decode(this->fragment()) != uri::decode(other.fragment()))\n    {\n        return false;\n    }\n\n    return true;\n}\n\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/uri_builder.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Builder for constructing URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\nnamespace web\n{\n\nnamespace http\n{\n    // URI class has been moved from web::http namespace to web namespace.\n    // The below using declarations ensure we don't break existing code.\n    // Please use the web::uri class going forward.\n    using web::uri;\n    using web::uri_builder;\n}\n\nuri_builder &uri_builder::append_path(const utility::string_t &path, bool is_encode)\n{\n    if(path.empty() || path == _XPLATSTR(\"/\"))\n    {\n        return *this;\n    }\n\n    auto encoded_path = is_encode ? uri::encode_uri(path, uri::components::path) : path;\n    auto thisPath = this->path();\n    if(thisPath.empty() || thisPath == _XPLATSTR(\"/\"))\n    {\n        if(encoded_path.front() != _XPLATSTR('/'))\n        {\n            set_path(_XPLATSTR(\"/\") + encoded_path);\n        }\n        else\n        {\n            set_path(encoded_path);\n        }\n    }\n    else if(thisPath.back() == _XPLATSTR('/') && encoded_path.front() == _XPLATSTR('/'))\n    {\n        thisPath.pop_back();\n        set_path(thisPath + encoded_path);\n    }\n    else if(thisPath.back() != _XPLATSTR('/') && encoded_path.front() != _XPLATSTR('/'))\n    {\n        set_path(thisPath + _XPLATSTR(\"/\") + encoded_path);\n    }\n    else\n    {\n        // Only one slash.\n        set_path(thisPath + encoded_path);\n    }\n    return *this;\n}\n\nuri_builder &uri_builder::append_query(const utility::string_t &query, bool is_encode)\n{\n    if(query.empty())\n    {\n        return *this;\n    }\n\n    auto encoded_query = is_encode ? uri::encode_uri(query, uri::components::query) : query;\n    auto thisQuery = this->query();\n    if (thisQuery.empty())\n    {\n        this->set_query(encoded_query);\n    }\n    else if(thisQuery.back() == _XPLATSTR('&') && encoded_query.front() == _XPLATSTR('&'))\n    {\n        thisQuery.pop_back();\n        this->set_query(thisQuery + encoded_query);\n    }\n    else if(thisQuery.back() != _XPLATSTR('&') && encoded_query.front() != _XPLATSTR('&'))\n    {\n        this->set_query(thisQuery + _XPLATSTR(\"&\") + encoded_query);\n    }\n    else\n    {\n        // Only one ampersand.\n        this->set_query(thisQuery + encoded_query);\n    }\n    return *this;\n}\n\nuri_builder &uri_builder::append(const http::uri &relative_uri)\n{\n    append_path(relative_uri.path());\n    append_query(relative_uri.query());\n    this->set_fragment(this->fragment() + relative_uri.fragment());\n    return *this;\n}\n\nutility::string_t uri_builder::to_string()\n{\n    return to_uri().to_string();\n}\n\nuri uri_builder::to_uri()\n{\n    return uri(m_uri);\n}\n\nbool uri_builder::is_valid()\n{\n    return uri::validate(m_uri.join());\n}\n\n} // namespace web\n\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/uri_parser.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* URI parsing implementation\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <string>\n\nnamespace web { namespace details\n{\n    namespace uri_parser\n    {\n\n        /// <summary>\n        /// Parses the uri, attempting to determine its validity.\n        ///\n        /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query')\n        /// </summary>\n        bool validate(const utility::string_t &encoded_string);\n\n        /// <summary>\n        /// Parses the uri, setting each provided string to the value of that component. Components\n        /// that are not part of the provided text are set to the empty string. Component strings\n        /// DO NOT contain their beginning or ending delimiters.\n        ///\n        /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query')\n        /// </summary>\n        bool parse(const utility::string_t &encoded_string, uri_components &components);\n\n        /// <summary>\n        /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include:\n        /// - A-Z\n        /// - a-z\n        /// - 0-9\n        /// - '-' (hyphen)\n        /// - '.' (period)\n        /// - '_' (underscore)\n        /// - '~' (tilde)\n        /// </summary>\n        inline bool is_unreserved(int c)\n        {\n            return ::utility::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~';\n        }\n\n        /// <summary>\n        /// General delimiters serve as the delimiters between different uri components.\n        /// General delimiters include:\n        /// - All of these :/?#[]@\n        /// </summary>\n        inline bool is_gen_delim(int c)\n        {\n            return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@';\n        }\n\n        /// <summary>\n        /// Subdelimiters are those characters that may have a defined meaning within component\n        /// of a uri for a particular scheme. They do not serve as delimiters in any case between\n        /// uri segments. sub_delimiters include:\n        /// - All of these !$&amp;'()*+,;=\n        /// </summary>\n        inline bool is_sub_delim(int c)\n        {\n            switch (c)\n            {\n            case '!':\n            case '$':\n            case '&':\n            case '\\'':\n            case '(':\n            case ')':\n            case '*':\n            case '+':\n            case ',':\n            case ';':\n            case '=':\n                return true;\n            default:\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Reserved characters includes the general delimiters and sub delimiters. Some characters\n        /// are neither reserved nor unreserved, and must be percent-encoded.\n        /// </summary>\n        inline bool is_reserved(int c)\n        {\n            return is_gen_delim(c) || is_sub_delim(c);\n        }\n\n        /// <summary>\n        /// Legal characters in the scheme portion include:\n        /// - Any alphanumeric character\n        /// - '+' (plus)\n        /// - '-' (hyphen)\n        /// - '.' (period)\n        ///\n        /// Note that the scheme must BEGIN with an alpha character.\n        /// </summary>\n        inline bool is_scheme_character(int c)\n        {\n            return ::utility::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.';\n        }\n\n        /// <summary>\n        /// Legal characters in the user information portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        /// </summary>\n        inline bool is_user_info_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':';\n        }\n\n        /// <summary>\n        /// Legal characters in the host portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        /// - '[' (open bracket)\n        /// - ']' (close bracket)\n        /// </summary>\n        inline bool is_host_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':' || c == '[' || c == ']';\n        }\n\n        /// <summary>\n        /// Legal characters in the authority portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        ///\n        /// Note that we don't currently support:\n        /// - IPv6 addresses (requires '[]')\n        /// </summary>\n        inline bool is_authority_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':';\n        }\n\n        /// <summary>\n        /// Legal characters in the path portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        /// - '@' (ampersand)\n        /// </summary>\n        inline bool is_path_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@';\n        }\n\n        /// <summary>\n        /// Legal characters in the query portion include:\n        /// - Any path character\n        /// - '?' (question mark)\n        /// </summary>\n        inline bool is_query_character(int c)\n        {\n            return is_path_character(c) || c == '?';\n        }\n\n        /// <summary>\n        /// Legal characters in the fragment portion include:\n        /// - Any path character\n        /// - '?' (question mark)\n        /// </summary>\n        inline bool is_fragment_character(int c)\n        {\n            // this is intentional, they have the same set of legal characters\n            return is_query_character(c);\n        }\n\n        /// <summary>\n        /// Parses the uri, setting the given pointers to locations inside the given buffer.\n        /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri\n        /// </summary>\n        bool inner_parse(\n            const utility::char_t *encoded,\n            const utility::char_t **scheme_begin, const utility::char_t **scheme_end,\n            const utility::char_t **uinfo_begin, const utility::char_t **uinfo_end,\n            const utility::char_t **host_begin, const utility::char_t **host_end,\n            _Out_ int *port,\n            const utility::char_t **path_begin, const utility::char_t **path_end,\n            const utility::char_t **query_begin, const utility::char_t **query_end,\n            const utility::char_t **fragment_begin, const utility::char_t **fragment_end);\n    }\n}}\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/uri_parser.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* URI parsing implementation\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <locale>\n\nnamespace web { namespace details { namespace uri_parser\n{\n\nbool validate(const utility::string_t &encoded_string)\n{\n    const utility::char_t *scheme_begin = nullptr;\n    const utility::char_t *scheme_end = nullptr;\n    const utility::char_t *uinfo_begin = nullptr;\n    const utility::char_t *uinfo_end = nullptr;\n    const utility::char_t *host_begin = nullptr;\n    const utility::char_t *host_end = nullptr;\n    int port_ptr = 0;\n    const utility::char_t *path_begin = nullptr;\n    const utility::char_t *path_end = nullptr;\n    const utility::char_t *query_begin = nullptr;\n    const utility::char_t *query_end = nullptr;\n    const utility::char_t *fragment_begin = nullptr;\n    const utility::char_t *fragment_end = nullptr;\n\n    // perform a parse, but don't copy out the data\n    return inner_parse(\n        encoded_string.c_str(),\n        &scheme_begin,\n        &scheme_end,\n        &uinfo_begin,\n        &uinfo_end,\n        &host_begin,\n        &host_end,\n        &port_ptr,\n        &path_begin,\n        &path_end,\n        &query_begin,\n        &query_end,\n        &fragment_begin,\n        &fragment_end);\n}\n\nbool parse(const utility::string_t &encoded_string, uri_components &components)\n{\n    const utility::char_t *scheme_begin = nullptr;\n    const utility::char_t *scheme_end = nullptr;\n    const utility::char_t *host_begin = nullptr;\n    const utility::char_t *host_end = nullptr;\n    const utility::char_t *uinfo_begin = nullptr;\n    const utility::char_t *uinfo_end = nullptr;\n    int port_ptr = 0;\n    const utility::char_t *path_begin = nullptr;\n    const utility::char_t *path_end = nullptr;\n    const utility::char_t *query_begin = nullptr;\n    const utility::char_t *query_end = nullptr;\n    const utility::char_t *fragment_begin = nullptr;\n    const utility::char_t *fragment_end = nullptr;\n\n    if (inner_parse(\n        encoded_string.c_str(),\n        &scheme_begin,\n        &scheme_end,\n        &uinfo_begin,\n        &uinfo_end,\n        &host_begin,\n        &host_end,\n        &port_ptr,\n        &path_begin,\n        &path_end,\n        &query_begin,\n        &query_end,\n        &fragment_begin,\n        &fragment_end))\n    {\n        if (scheme_begin)\n        {\n            components.m_scheme.assign(scheme_begin, scheme_end);\n\n            // convert scheme to lowercase\n            std::transform(components.m_scheme.begin(), components.m_scheme.end(), components.m_scheme.begin(), [](utility::char_t c) {\n                return (utility::char_t)tolower(c);\n            });\n        }\n        else\n        {\n            components.m_scheme.clear();\n        }\n\n        if (uinfo_begin)\n        {\n            components.m_user_info.assign(uinfo_begin, uinfo_end);\n        }\n\n        if (host_begin)\n        {\n            components.m_host.assign(host_begin, host_end);\n\n            // convert host to lowercase\n            std::transform(components.m_host.begin(), components.m_host.end(), components.m_host.begin(), [](utility::char_t c) {\n                return (utility::char_t)tolower(c);\n            });\n        }\n        else\n        {\n            components.m_host.clear();\n        }\n\n        if (port_ptr)\n        {\n            components.m_port = port_ptr;\n        }\n        else\n        {\n            components.m_port = 0;\n        }\n\n        if (path_begin)\n        {\n            components.m_path.assign(path_begin, path_end);\n        }\n        else\n        {\n            // default path to begin with a slash for easy comparison\n            components.m_path = _XPLATSTR(\"/\");\n        }\n\n        if (query_begin)\n        {\n            components.m_query.assign(query_begin, query_end);\n        }\n        else\n        {\n            components.m_query.clear();\n        }\n\n        if (fragment_begin)\n        {\n            components.m_fragment.assign(fragment_begin, fragment_end);\n        }\n        else\n        {\n            components.m_fragment.clear();\n        }\n\n        return true;\n    }\n    else\n    {\n        return false;\n    }\n}\n\nbool inner_parse(\n            const utility::char_t *encoded,\n            const utility::char_t **scheme_begin, const utility::char_t **scheme_end,\n            const utility::char_t **uinfo_begin, const utility::char_t **uinfo_end,\n            const utility::char_t **host_begin, const utility::char_t **host_end,\n            _Out_ int *port,\n            const utility::char_t **path_begin, const utility::char_t **path_end,\n            const utility::char_t **query_begin, const utility::char_t **query_end,\n            const utility::char_t **fragment_begin, const utility::char_t **fragment_end)\n{\n    *scheme_begin = nullptr;\n    *scheme_end = nullptr;\n    *uinfo_begin = nullptr;\n    *uinfo_end = nullptr;\n    *host_begin = nullptr;\n    *host_end = nullptr;\n    *port = 0;\n    *path_begin = nullptr;\n    *path_end = nullptr;\n    *query_begin = nullptr;\n    *query_end = nullptr;\n    *fragment_begin = nullptr;\n    *fragment_end = nullptr;\n\n    const utility::char_t *p = encoded;\n\n    // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference\n    // Absolute: 'http://host.com'\n    // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2'\n    // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash\n\n    bool is_relative_reference = true;\n    const utility::char_t *p2 = p;\n    for (;*p2 != _XPLATSTR('/') && *p2 != _XPLATSTR('\\0'); p2++)\n    {\n        if (*p2 == _XPLATSTR(':'))\n        {\n            // found a colon, the first portion is a scheme\n            is_relative_reference = false;\n            break;\n        }\n    }\n\n    if (!is_relative_reference)\n    {\n        // the first character of a scheme must be a letter\n        if (!isalpha(*p))\n        {\n            return false;\n        }\n\n        // start parsing the scheme, it's always delimited by a colon (must be present)\n        *scheme_begin = p++;\n        for (;*p != ':'; p++)\n        {\n            if (!is_scheme_character(*p))\n            {\n                return false;\n            }\n        }\n        *scheme_end = p;\n\n        // skip over the colon\n        p++;\n    }\n\n    // if we see two slashes next, then we're going to parse the authority portion\n    // later on we'll break up the authority into the port and host\n    const utility::char_t *authority_begin = nullptr;\n    const utility::char_t *authority_end = nullptr;\n    if (*p == _XPLATSTR('/') && p[1] == _XPLATSTR('/'))\n    {\n        // skip over the slashes\n        p += 2;\n        authority_begin = p;\n\n        // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment)\n        // or by EOS. The authority could be empty ('file:///C:\\file_name.txt')\n        for (;*p != _XPLATSTR('/') && *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\\0'); p++)\n        {\n            // We're NOT currently supporting IPv6, IPvFuture or username/password in authority\n            if (!is_authority_character(*p))\n            {\n                return false;\n            }\n        }\n        authority_end = p;\n\n        // now lets see if we have a port specified -- by working back from the end\n        if (authority_begin != authority_end)\n        {\n            // the port is made up of all digits\n            const utility::char_t *port_begin = authority_end - 1;\n            for (;isdigit(*port_begin) && port_begin != authority_begin; port_begin--)\n            { }\n\n            if (*port_begin == _XPLATSTR(':'))\n            {\n                // has a port\n                *host_begin = authority_begin;\n                *host_end = port_begin;\n\n                //skip the colon\n                port_begin++;\n\n                *port = utility::conversions::scan_string<int>(utility::string_t(port_begin, authority_end), std::locale::classic());\n            }\n            else\n            {\n                // no port\n                *host_begin = authority_begin;\n                *host_end = authority_end;\n            }\n\n            // look for a user_info component\n            const utility::char_t *u_end = *host_begin;\n            for (;is_user_info_character(*u_end) && u_end != *host_end; u_end++)\n            { }\n\n            if (*u_end == _XPLATSTR('@'))\n            {\n                *host_begin = u_end+1;\n                *uinfo_begin = authority_begin;\n                *uinfo_end = u_end;\n            }\n            else\n            {\n                uinfo_end = uinfo_begin = nullptr;\n            }\n        }\n    }\n\n    // if we see a path character or a slash, then the\n    // if we see a slash, or any other legal path character, parse the path next\n    if (*p == _XPLATSTR('/') || is_path_character(*p))\n    {\n        *path_begin = p;\n\n        // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS\n        for (;*p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\\0'); p++)\n        {\n            if (!is_path_character(*p))\n            {\n                return false;\n            }\n        }\n        *path_end = p;\n    }\n\n    // if we see a ?, then the query is next\n    if (*p == _XPLATSTR('?'))\n    {\n        // skip over the question mark\n        p++;\n        *query_begin = p;\n\n        // the query is delimited by a '#' (fragment) or EOS\n        for (;*p != _XPLATSTR('#') && *p != _XPLATSTR('\\0'); p++)\n        {\n            if (!is_query_character(*p))\n            {\n                return false;\n            }\n        }\n        *query_end = p;\n    }\n\n    // if we see a #, then the fragment is next\n    if (*p == _XPLATSTR('#'))\n    {\n        // skip over the hash mark\n        p++;\n        *fragment_begin = p;\n\n        // the fragment is delimited by EOS\n        for (;*p != _XPLATSTR('\\0'); p++)\n        {\n            if (!is_fragment_character(*p))\n            {\n                return false;\n            }\n        }\n        *fragment_end = p;\n    }\n\n    return true;\n}\n\n}}}\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/details/web_utilities.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* utility classes used by the different web:: clients\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#include \"cpprest/asyncrt_utils.h\"\n\nnamespace web\n{\n\nnamespace http { namespace client { namespace details {\nclass winhttp_client;\nclass winrt_client;\nclass asio_context;\n}}}\nnamespace websockets { namespace client { namespace details {\nclass winrt_callback_client;\nclass wspp_callback_client;\n}}}\n\nnamespace details\n{\n\nclass zero_memory_deleter\n{\npublic:\n    _ASYNCRTIMP void operator()(::utility::string_t *data) const;\n};\ntypedef std::unique_ptr<::utility::string_t, zero_memory_deleter> plaintext_string;\n\n#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)\n#if defined(__cplusplus_winrt)\nclass winrt_encryption\n{\npublic:\n    winrt_encryption() {}\n    _ASYNCRTIMP winrt_encryption(const std::wstring &data);\n    _ASYNCRTIMP plaintext_string decrypt() const;\nprivate:\n    ::pplx::task<Windows::Storage::Streams::IBuffer ^> m_buffer;\n};\n#else\nclass win32_encryption\n{\npublic:\n    win32_encryption() {}\n    _ASYNCRTIMP win32_encryption(const std::wstring &data);\n    _ASYNCRTIMP ~win32_encryption();\n    _ASYNCRTIMP plaintext_string decrypt() const;\nprivate:\n    std::vector<char> m_buffer;\n    size_t m_numCharacters;\n};\n#endif\n#endif\n}\n\n/// <summary>\n/// Represents a set of user credentials (user name and password) to be used\n/// for authentication.\n/// </summary>\nclass credentials\n{\npublic:\n    /// <summary>\n    /// Constructs an empty set of credentials without a user name or password.\n    /// </summary>\n    credentials() {}\n\n    /// <summary>\n    /// Constructs credentials from given user name and password.\n    /// </summary>\n    /// <param name=\"username\">User name as a string.</param>\n    /// <param name=\"password\">Password as a string.</param>\n    credentials(utility::string_t username, const utility::string_t & password) :\n        m_username(std::move(username)),\n        m_password(password)\n    {}\n\n    /// <summary>\n    /// The user name associated with the credentials.\n    /// </summary>\n    /// <returns>A string containing the user name.</returns>\n    const utility::string_t &username() const { return m_username; }\n\n    /// <summary>\n    /// The password for the user name associated with the credentials.\n    /// </summary>\n    /// <returns>A string containing the password.</returns>\n    CASABLANCA_DEPRECATED(\"This API is deprecated for security reasons to avoid unnecessary password copies stored in plaintext.\")\n        utility::string_t password() const\n    {\n#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)\n        return utility::string_t(*m_password.decrypt());\n#else\n        return m_password;\n#endif\n    }\n\n    /// <summary>\n    /// Checks if credentials have been set\n    /// </summary>\n    /// <returns><c>true</c> if user name and password is set, <c>false</c> otherwise.</returns>\n    bool is_set() const { return !m_username.empty(); }\n\nprivate:\n    friend class http::client::details::winhttp_client;\n    friend class http::client::details::winrt_client;\n    friend class http::client::details::asio_context;\n    friend class websockets::client::details::winrt_callback_client;\n    friend class websockets::client::details::wspp_callback_client;\n\n    details::plaintext_string decrypt() const\n    {\n        // Encryption APIs not supported on XP\n#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)\n        return m_password.decrypt();\n#else\n        return details::plaintext_string(new ::utility::string_t(m_password));\n#endif\n    }\n\n    ::utility::string_t m_username;\n\n#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)\n#if defined(__cplusplus_winrt)\n    details::winrt_encryption m_password;\n#else\n    details::win32_encryption m_password;\n#endif\n#else\n    ::utility::string_t m_password;\n#endif\n};\n\n/// <summary>\n/// web_proxy represents the concept of the web proxy, which can be auto-discovered,\n/// disabled, or specified explicitly by the user.\n/// </summary>\nclass web_proxy\n{\n    enum web_proxy_mode_internal{ use_default_, use_auto_discovery_, disabled_, user_provided_ };\npublic:\n    enum web_proxy_mode{ use_default = use_default_, use_auto_discovery = use_auto_discovery_, disabled  = disabled_};\n\n    /// <summary>\n    /// Constructs a proxy with the default settings.\n    /// </summary>\n    web_proxy() : m_address(_XPLATSTR(\"\")), m_mode(use_default_) {}\n\n    /// <summary>\n    /// Creates a proxy with specified mode.\n    /// </summary>\n    /// <param name=\"mode\">Mode to use.</param>\n    web_proxy( web_proxy_mode mode ) : m_address(_XPLATSTR(\"\")), m_mode(static_cast<web_proxy_mode_internal>(mode)) {}\n\n    /// <summary>\n    /// Creates a proxy explicitly with provided address.\n    /// </summary>\n    /// <param name=\"address\">Proxy URI to use.</param>\n    web_proxy( uri address ) : m_address(address), m_mode(user_provided_) {}\n\n    /// <summary>\n    /// Gets this proxy's URI address. Returns an empty URI if not explicitly set by user.\n    /// </summary>\n    /// <returns>A reference to this proxy's URI.</returns>\n    const uri& address() const { return m_address; }\n\n    /// <summary>\n    /// Gets the credentials used for authentication with this proxy.\n    /// </summary>\n    /// <returns>Credentials to for this proxy.</returns>\n    const web::credentials& credentials() const { return m_credentials; }\n\n    /// <summary>\n    /// Sets the credentials to use for authentication with this proxy.\n    /// </summary>\n    /// <param name=\"cred\">Credentials to use for this proxy.</param>\n    void set_credentials(web::credentials cred) {\n        if( m_mode == disabled_ )\n        {\n            throw std::invalid_argument(\"Cannot attach credentials to a disabled proxy\");\n        }\n        m_credentials = std::move(cred);\n    }\n\n    /// <summary>\n    /// Checks if this proxy was constructed with default settings.\n    /// </summary>\n    /// <returns>True if default, false otherwise.</returns>\n    bool is_default() const { return m_mode == use_default_; }\n\n    /// <summary>\n    /// Checks if using a proxy is disabled.\n    /// </summary>\n    /// <returns>True if disabled, false otherwise.</returns>\n    bool is_disabled() const { return m_mode == disabled_; }\n\n    /// <summary>\n    /// Checks if the auto discovery protocol, WPAD, is to be used.\n    /// </summary>\n    /// <returns>True if auto discovery enabled, false otherwise.</returns>\n    bool is_auto_discovery() const { return m_mode == use_auto_discovery_; }\n\n    /// <summary>\n    /// Checks if a proxy address is explicitly specified by the user.\n    /// </summary>\n    /// <returns>True if a proxy address was explicitly specified, false otherwise.</returns>\n    bool is_specified() const { return m_mode == user_provided_; }\n\nprivate:\n    web::uri m_address;\n    web_proxy_mode_internal m_mode;\n    web::credentials m_credentials;\n};\n\n}\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/http_headers.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n#include <vector>\n#include <system_error>\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n\nnamespace web { namespace http {\n\n/// <summary>\n/// Represents HTTP headers, acts like a map.\n/// </summary>\nclass http_headers\n{\npublic:\n    struct _case_insensitive_cmp\n    {\n        bool operator()(const utility::string_t &str1, const utility::string_t &str2) const\n        {\n#ifdef _WIN32\n            return _wcsicmp(str1.c_str(), str2.c_str()) < 0;\n#else\n            return utility::cmp::icmp(str1, str2) < 0;\n#endif\n        }\n    };\n\n    /// <summary>\n    /// STL-style typedefs\n    /// </summary>\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::key_type key_type;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::key_compare key_compare;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::allocator_type allocator_type;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::size_type size_type;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::difference_type difference_type;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::pointer pointer;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_pointer const_pointer;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::reference reference;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_reference const_reference;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::iterator iterator;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_iterator const_iterator;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::reverse_iterator reverse_iterator;\n    typedef std::map<utility::string_t, utility::string_t, _case_insensitive_cmp>::const_reverse_iterator const_reverse_iterator;\n\n    /// <summary>\n    /// Constructs an empty set of HTTP headers.\n    /// </summary>\n    http_headers() {}\n\n    /// <summary>\n    /// Copy constructor.\n    /// </summary>\n    /// <param name=\"other\">An <c>http_headers</c> object to copy from.</param>\n    http_headers(const http_headers &other) : m_headers(other.m_headers) {}\n\n    /// <summary>\n    /// Assignment operator.\n    /// </summary>\n    /// <param name=\"other\">An <c>http_headers</c> object to copy from.</param>\n    http_headers &operator=(const http_headers &other)\n    {\n        if(this != &other)\n        {\n            m_headers = other.m_headers;\n        }\n        return *this;\n    }\n\n    /// <summary>\n    /// Move constructor.\n    /// </summary>\n    /// <param name=\"other\">An <c>http_headers</c> object to move.</param>\n    http_headers(http_headers &&other) noexcept : m_headers(std::move(other.m_headers)) {}\n\n    /// <summary>\n    /// Move assignment operator.\n    /// </summary>\n    /// <param name=\"other\">An <c>http_headers</c> object to move.</param>\n    http_headers &operator=(http_headers &&other) noexcept\n    {\n        if(this != &other)\n        {\n            m_headers = std::move(other.m_headers);\n        }\n        return *this;\n    }\n\n    /// <summary>\n    /// Adds a header field using the '&lt;&lt;' operator.\n    /// </summary>\n    /// <param name=\"name\">The name of the header field.</param>\n    /// <param name=\"value\">The value of the header field.</param>\n    /// <remarks>If the header field exists, the value will be combined as comma separated string.</remarks>\n    template<typename _t1>\n    void add(const key_type& name, const _t1& value)\n    {\n        if (has(name))\n        {\n            m_headers[name].append(_XPLATSTR(\", \")).append(utility::conversions::print_string(value));\n        }\n        else\n        {\n            m_headers[name] = utility::conversions::print_string(value);\n        }\n    }\n\n    /// <summary>\n    /// Removes a header field.\n    /// </summary>\n    /// <param name=\"name\">The name of the header field.</param>\n    void remove(const key_type& name)\n    {\n        m_headers.erase(name);\n    }\n\n    /// <summary>\n    /// Removes all elements from the headers.\n    /// </summary>\n    void clear() { m_headers.clear(); }\n\n    /// <summary>\n    /// Checks if there is a header with the given key.\n    /// </summary>\n    /// <param name=\"name\">The name of the header field.</param>\n    /// <returns><c>true</c> if there is a header with the given name, <c>false</c> otherwise.</returns>\n    bool has(const key_type& name) const { return m_headers.find(name) != m_headers.end(); }\n\n    /// <summary>\n    /// Returns the number of header fields.\n    /// </summary>\n    /// <returns>Number of header fields.</returns>\n    size_type size() const { return m_headers.size(); }\n\n    /// <summary>\n    /// Tests to see if there are any header fields.\n    /// </summary>\n    /// <returns><c>true</c> if there are no headers, <c>false</c> otherwise.</returns>\n    bool empty() const { return m_headers.empty(); }\n\n    /// <summary>\n    /// Returns a reference to header field with given name, if there is no header field one is inserted.\n    /// </summary>\n    utility::string_t & operator[](const key_type &name) { return m_headers[name]; }\n\n    /// <summary>\n    /// Checks if a header field exists with given name and returns an iterator if found. Otherwise\n    /// and iterator to end is returned.\n    /// </summary>\n    /// <param name=\"name\">The name of the header field.</param>\n    /// <returns>An iterator to where the HTTP header is found.</returns>\n    iterator find(const key_type &name) { return m_headers.find(name); }\n    const_iterator find(const key_type &name) const { return m_headers.find(name); }\n\n    /// <summary>\n    /// Attempts to match a header field with the given name using the '>>' operator.\n    /// </summary>\n    /// <param name=\"name\">The name of the header field.</param>\n    /// <param name=\"value\">The value of the header field.</param>\n    /// <returns><c>true</c> if header field was found and successfully stored in value parameter.</returns>\n    template<typename _t1>\n    bool match(const key_type &name, _t1 &value) const\n    {\n        auto iter = m_headers.find(name);\n        if (iter != m_headers.end())\n        {\n            // Check to see if doesn't have a value.\n            if(iter->second.empty())\n            {\n                bind_impl(iter->second, value);\n                return true;\n            }\n            return bind_impl(iter->second, value);\n        }\n        else\n        {\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Returns an iterator referring to the first header field.\n    /// </summary>\n    /// <returns>An iterator to the beginning of the HTTP headers</returns>\n    iterator begin() { return m_headers.begin(); }\n    const_iterator begin() const { return m_headers.begin(); }\n\n    /// <summary>\n    /// Returns an iterator referring to the past-the-end header field.\n    /// </summary>\n    /// <returns>An iterator to the element past the end of the HTTP headers.</returns>\n    iterator end() { return m_headers.end(); }\n    const_iterator end() const { return m_headers.end(); }\n\n    /// <summary>\n    /// Gets the content length of the message.\n    /// </summary>\n    /// <returns>The length of the content.</returns>\n    _ASYNCRTIMP utility::size64_t content_length() const;\n\n    /// <summary>\n    /// Sets the content length of the message.\n    /// </summary>\n    /// <param name=\"length\">The length of the content.</param>\n    _ASYNCRTIMP void set_content_length(utility::size64_t length);\n\n    /// <summary>\n    /// Gets the content type of the message.\n    /// </summary>\n    /// <returns>The content type of the body.</returns>\n    _ASYNCRTIMP utility::string_t content_type() const;\n\n    /// <summary>\n    /// Sets the content type of the message.\n    /// </summary>\n    /// <param name=\"type\">The content type of the body.</param>\n    _ASYNCRTIMP void set_content_type(utility::string_t type);\n\n    /// <summary>\n    /// Gets the cache control header of the message.\n    /// </summary>\n    /// <returns>The cache control header value.</returns>\n    _ASYNCRTIMP utility::string_t cache_control() const;\n\n    /// <summary>\n    /// Sets the cache control header of the message.\n    /// </summary>\n    /// <param name=\"control\">The cache control header value.</param>\n    _ASYNCRTIMP void set_cache_control(utility::string_t control);\n\n    /// <summary>\n    /// Gets the date header of the message.\n    /// </summary>\n    /// <returns>The date header value.</returns>\n    _ASYNCRTIMP utility::string_t date() const;\n\n    /// <summary>\n    /// Sets the date header of the message.\n    /// </summary>\n    /// <param name=\"date\">The date header value.</param>\n    _ASYNCRTIMP void set_date(const utility::datetime& date);\n\nprivate:\n\n    template<typename _t>\n    bool bind_impl(const key_type &text, _t &ref) const\n    {\n        utility::istringstream_t iss(text);\n        iss.imbue(std::locale::classic());\n        iss >> ref;\n        if (iss.fail() || !iss.eof())\n        {\n            return false;\n        }\n\n        return true;\n    }\n\n    bool bind_impl(const key_type &text, ::utility::string_t &ref) const\n    {\n        ref = text;\n        return true;\n    }\n\n    // Headers are stored in a map with case insensitive key.\n    std::map<utility::string_t, utility::string_t, _case_insensitive_cmp> m_headers;\n};\n\nnamespace details {\n\n    /// <summary>\n    /// Serialize the http_headers into name:value pairs separated by a carriage return and line feed.\n    /// </summary>\n    utility::string_t flatten_http_headers(const http_headers &headers);\n#if defined(_WIN32)\n    /// <summary>\n    /// Parses a string containing Http headers.\n    /// </summary>\n    void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers);\n#endif\n}\n\n}}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/http_msg.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: Request and reply message definitions.\n*\n* For the latest on this and related APIs, please see http://casablanca.codeplex.com.\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n#include <vector>\n#include <system_error>\n\n#if !XSAPI_NO_PPL\n#include \"pplx/pplxtasks.h\"\n#endif // !XSAPI_NO_PPL\n#include \"cpprest/json.h\"\n#include \"cpprest/uri.h\"\n#include \"cpprest/http_headers.h\"\n#include \"cpprest/details/cpprest_compat.h\"\n#include \"cpprest/asyncrt_utils.h\"\n#include \"cpprest/streams.h\"\n#include \"cpprest/containerstream.h\"\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#define HTTPMSG_UTF16(x) L##x // avoids'to_utf16string' identifier not found build error\n#else\n#define HTTPMSG_UTF16(x) utility::conversions::to_utf16string(x)\n#endif    \n\nnamespace web\n{\nnamespace http\n{\n\n#if !XSAPI_NO_PPL\n// URI class has been moved from web::http namespace to web namespace.\n// The below using declarations ensure we don't break existing code.\n// Please use the web::uri class going forward.\nusing web::uri;\nusing web::uri_builder;\n\nnamespace client\n{\n    class http_client;\n}\n\n/// <summary>\n/// Predefined method strings for the standard HTTP methods mentioned in the\n/// HTTP 1.1 specification.\n/// </summary>\ntypedef utility::string_t method;\n\n/// <summary>\n/// Common HTTP methods.\n/// </summary>\nclass methods\n{\npublic:\n#define _METHODS\n#define DAT(a,b) _ASYNCRTIMP const static method a;\n#include \"cpprest/details/http_constants.dat\"\n#undef _METHODS\n#undef DAT\n};\n#endif // !XSAPI_NO_PPL\n\ntypedef unsigned short status_code;\n\n/// <summary>\n/// Predefined values for all of the standard HTTP 1.1 response status codes.\n/// </summary>\nclass status_codes\n{\npublic:\n#define _PHRASES\n#define DAT(a,b,c) const static status_code a=b;\n#include \"cpprest/details/http_constants.dat\"\n#undef _PHRASES\n#undef DAT\n};\n\n#if !XSAPI_NO_PPL\nnamespace details {\n\n/// <summary>\n/// Constants for MIME types.\n/// </summary>\nclass mime_types\n{\npublic:\n#define _MIME_TYPES\n#define DAT(a,b) _ASYNCRTIMP const static utility::string_t a;\n#include \"cpprest/details/http_constants.dat\"\n#undef _MIME_TYPES\n#undef DAT\n};\n\n/// <summary>\n/// Constants for charset types.\n/// </summary>\nclass charset_types\n{\npublic:\n#define _CHARSET_TYPES\n#define DAT(a,b) _ASYNCRTIMP const static utility::string_t a;\n#include \"cpprest/details/http_constants.dat\"\n#undef _CHARSET_TYPES\n#undef DAT\n};\n\n}\n\n/// Message direction\nnamespace message_direction\n{\n    /// <summary>\n    /// Enumeration used to denote the direction of a message: a request with a body is\n    /// an upload, a response with a body is a download.\n    /// </summary>\n    enum direction {\n        upload,\n        download\n    };\n}\n\ntypedef utility::string_t reason_phrase;\ntypedef std::function<void(message_direction::direction, utility::size64_t)> progress_handler;\n\nstruct http_status_to_phrase\n{\n    unsigned short id;\n    reason_phrase phrase;\n};\n\n/// <summary>\n/// Constants for the HTTP headers mentioned in RFC 2616.\n/// </summary>\nclass header_names\n{\npublic:\n#define _HEADER_NAMES\n#define DAT(a,b) _ASYNCRTIMP const static utility::string_t a;\n#include \"cpprest/details/http_constants.dat\"\n#undef _HEADER_NAMES\n#undef DAT\n};\n\n/// <summary>\n/// Represents an HTTP error. This class holds an error message and an optional error code.\n/// </summary>\nclass http_exception : public std::exception\n{\npublic:\n\n    /// <summary>\n    /// Creates an <c>http_exception</c> with just a string message and no error code.\n    /// </summary>\n    /// <param name=\"whatArg\">Error message string.</param>\n    http_exception(const utility::string_t &whatArg)\n        : m_msg(utility::conversions::to_utf8string(whatArg)) {}\n\n#ifdef _WIN32\n    /// <summary>\n    /// Creates an <c>http_exception</c> with just a string message and no error code.\n    /// </summary>\n    /// <param name=\"whatArg\">Error message string.</param>\n    http_exception(std::string whatArg) : m_msg(std::move(whatArg)) {}\n#endif\n\n    /// <summary>\n    /// Creates an <c>http_exception</c> with from a error code using the current platform error category.\n    /// The message of the error code will be used as the what() string message.\n    /// </summary>\n    /// <param name=\"errorCode\">Error code value.</param>\n    http_exception(int errorCode)\n        : m_errorCode(utility::details::create_error_code(errorCode))\n    {\n        m_msg = m_errorCode.message();\n    }\n\n    /// <summary>\n    /// Creates an <c>http_exception</c> with from a error code using the current platform error category.\n    /// </summary>\n    /// <param name=\"errorCode\">Error code value.</param>\n    /// <param name=\"whatArg\">Message to use in what() string.</param>\n    http_exception(int errorCode, const utility::string_t &whatArg)\n        : m_errorCode(utility::details::create_error_code(errorCode)),\n          m_msg(utility::conversions::to_utf8string(whatArg))\n    {}\n\n#ifdef _WIN32\n    /// <summary>\n    /// Creates an <c>http_exception</c> with from a error code using the current platform error category.\n    /// </summary>\n    /// <param name=\"errorCode\">Error code value.</param>\n    /// <param name=\"whatArg\">Message to use in what() string.</param>\n    http_exception(int errorCode, std::string whatArg) :\n        m_errorCode(utility::details::create_error_code(errorCode)),\n        m_msg(std::move(whatArg))\n    {}\n#endif\n\n    /// <summary>\n    /// Creates an <c>http_exception</c> with from a error code and category. The message of the error code will be used\n    /// as the <c>what</c> string message.\n    /// </summary>\n    /// <param name=\"errorCode\">Error code value.</param>\n    /// <param name=\"cat\">Error category for the code.</param>\n    http_exception(int errorCode, const std::error_category &cat) : m_errorCode(std::error_code(errorCode, cat))\n    {\n        m_msg = m_errorCode.message();\n    }\n\n    /// <summary>\n    /// Gets a string identifying the cause of the exception.\n    /// </summary>\n    /// <returns>A null terminated character string.</returns>\n    const char* what() const CPPREST_NOEXCEPT\n    {\n        return m_msg.c_str();\n    }\n\n    /// <summary>\n    /// Retrieves the underlying error code causing this exception.\n    /// </summary>\n    /// <returns>A std::error_code.</returns>\n    const std::error_code & error_code() const\n    {\n        return m_errorCode;\n    }\n\nprivate:\n    std::error_code m_errorCode;\n    std::string m_msg;\n};\n\nnamespace details\n{\n\n/// <summary>\n/// Base class for HTTP messages.\n/// This class is to store common functionality so it isn't duplicated on\n/// both the request and response side.\n/// </summary>\nclass http_msg_base\n{\npublic:\n\n    friend class http::client::http_client;\n\n    _ASYNCRTIMP http_msg_base();\n\n    virtual ~http_msg_base() {}\n\n    http_headers &headers() { return m_headers; }\n\n    _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, const utf8string &contentType);\n    _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, const utf16string &contentType);\n    _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, utility::size64_t contentLength, const utf8string &contentType);\n    _ASYNCRTIMP void set_body(const concurrency::streams::istream &instream, utility::size64_t contentLength, const utf16string &contentType);\n\n    /// <summary>\n    /// Helper function for extract functions. Parses the Content-Type header and check to make sure it matches,\n    /// throws an exception if not.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true ignores the Content-Type header value.</param>\n    /// <param name=\"check_content_type\">Function to verify additional information on Content-Type.</param>\n    /// <returns>A string containing the charset, an empty string if no Content-Type header is empty.</returns>\n    utility::string_t parse_and_check_content_type(bool ignore_content_type, const std::function<bool(const utility::string_t&)> &check_content_type);\n\n    _ASYNCRTIMP utf8string extract_utf8string(bool ignore_content_type = false);\n    _ASYNCRTIMP utf16string extract_utf16string(bool ignore_content_type = false);\n    _ASYNCRTIMP utility::string_t extract_string(bool ignore_content_type = false);\n\n    _ASYNCRTIMP json::value _extract_json(bool ignore_content_type = false);\n    _ASYNCRTIMP std::vector<unsigned char> _extract_vector();\n\n    virtual _ASYNCRTIMP utility::string_t to_string() const;\n\n    /// <summary>\n    /// Completes this message\n    /// </summary>\n    virtual _ASYNCRTIMP void _complete(utility::size64_t bodySize, const std::exception_ptr &exceptionPtr = std::exception_ptr());\n\n    /// <summary>\n    /// Set the stream through which the message body could be read\n    /// </summary>\n    void set_instream(const concurrency::streams::istream &instream)  { m_inStream = instream; }\n\n    /// <summary>\n    /// Get the stream through which the message body could be read\n    /// </summary>\n    const concurrency::streams::istream & instream() const { return m_inStream; }\n\n    /// <summary>\n    /// Set the stream through which the message body could be written\n    /// </summary>\n    void set_outstream(const concurrency::streams::ostream &outstream, bool is_default)  { m_outStream = outstream; m_default_outstream = is_default; }\n\n    /// <summary>\n    /// Get the stream through which the message body could be written\n    /// </summary>\n    const concurrency::streams::ostream & outstream() const { return m_outStream; }\n\n    const pplx::task_completion_event<utility::size64_t> & _get_data_available() const { return m_data_available; }\n\n    /// <summary>\n    /// Prepare the message with an output stream to receive network data\n    /// </summary>\n    _ASYNCRTIMP void _prepare_to_receive_data();\n\n    /// <summary>\n    /// Determine the content length\n    /// </summary>\n    /// <returns>\n    /// size_t::max if there is content with unknown length (transfer_encoding:chunked)\n    /// 0           if there is no content\n    /// length      if there is content with known length\n    /// </returns>\n    /// <remarks>\n    /// This routine should only be called after a msg (request/response) has been\n    /// completely constructed.\n    /// </remarks>\n    _ASYNCRTIMP size_t _get_content_length();\n\nprotected:\n\n    /// <summary>\n    /// Stream to read the message body.\n    /// By default this is an invalid stream. The user could set the instream on\n    /// a request by calling set_request_stream(...). This would also be set when\n    /// set_body() is called - a stream from the body is constructed and set.\n    /// Even in the presense of msg body this stream could be invalid. An example\n    /// would be when the user sets an ostream for the response. With that API the\n    /// user does not provide the ability to read the msg body.\n    /// Thus m_instream is valid when there is a msg body and it can actually be read\n    /// </summary>\n    concurrency::streams::istream m_inStream;\n\n    /// <summary>\n    /// stream to write the msg body\n    /// By default this is an invalid stream. The user could set this on the response\n    /// (for http_client). In all the other cases we would construct one to transfer\n    /// the data from the network into the message body.\n    /// </summary>\n    concurrency::streams::ostream m_outStream;\n\n    http_headers m_headers;\n    bool m_default_outstream;\n\n    /// <summary> The TCE is used to signal the availability of the message body. </summary>\n    pplx::task_completion_event<utility::size64_t> m_data_available;\n};\n\n/// <summary>\n/// Base structure for associating internal server information\n/// with an HTTP request/response.\n/// </summary>\nclass _http_server_context\n{\npublic:\n    _http_server_context() {}\n    virtual ~_http_server_context() {}\nprivate:\n};\n\n/// <summary>\n/// Internal representation of an HTTP response.\n/// </summary>\nclass _http_response final : public http::details::http_msg_base\n{\npublic:\n    _http_response() : m_status_code((std::numeric_limits<uint16_t>::max)()) { }\n\n    _http_response(http::status_code code) : m_status_code(code) {}\n\n    http::status_code status_code() const { return m_status_code; }\n\n    void set_status_code(http::status_code code) { m_status_code = code; }\n\n    const http::reason_phrase & reason_phrase() const { return m_reason_phrase; }\n\n    void set_reason_phrase(const http::reason_phrase &reason) { m_reason_phrase = reason; }\n\n    _ASYNCRTIMP utility::string_t to_string() const;\n\n    _http_server_context * _get_server_context() const { return m_server_context.get(); }\n\n    void _set_server_context(std::unique_ptr<details::_http_server_context> server_context) { m_server_context = std::move(server_context); }\n\nprivate:\n    std::unique_ptr<_http_server_context> m_server_context;\n\n    http::status_code m_status_code;\n    http::reason_phrase m_reason_phrase;\n};\n\n} // namespace details\n\n\n/// <summary>\n/// Represents an HTTP response.\n/// </summary>\nclass http_response\n{\npublic:\n\n    /// <summary>\n    /// Constructs a response with an empty status code, no headers, and no body.\n    /// </summary>\n    /// <returns>A new HTTP response.</returns>\n    http_response() : _m_impl(std::make_shared<details::_http_response>()) { }\n\n    /// <summary>\n    /// Constructs a response with given status code, no headers, and no body.\n    /// </summary>\n    /// <param name=\"code\">HTTP status code to use in response.</param>\n    /// <returns>A new HTTP response.</returns>\n    http_response(http::status_code code)\n        : _m_impl(std::make_shared<details::_http_response>(code)) { }\n\n    /// <summary>\n    /// Gets the status code of the response message.\n    /// </summary>\n    /// <returns>status code.</returns>\n    http::status_code status_code() const { return _m_impl->status_code(); }\n\n    /// <summary>\n    /// Sets the status code of the response message.\n    /// </summary>\n    /// <param name=\"code\">Status code to set.</param>\n    /// <remarks>\n    /// This will overwrite any previously set status code.\n    /// </remarks>\n    void set_status_code(http::status_code code) const { _m_impl->set_status_code(code); }\n\n    /// <summary>\n    /// Gets the reason phrase of the response message.\n    /// If no reason phrase is set it will default to the standard one corresponding to the status code.\n    /// </summary>\n    /// <returns>Reason phrase.</returns>\n    const http::reason_phrase & reason_phrase() const { return _m_impl->reason_phrase(); }\n\n    /// <summary>\n    /// Sets the reason phrase of the response message.\n    /// If no reason phrase is set it will default to the standard one corresponding to the status code.\n    /// </summary>\n    /// <param name=\"reason\">The reason phrase to set.</param>\n    void set_reason_phrase(const http::reason_phrase &reason) const { _m_impl->set_reason_phrase(reason); }\n\n    /// <summary>\n    /// Gets the headers of the response message.\n    /// </summary>\n    /// <returns>HTTP headers for this response.</returns>\n    /// <remarks>\n    /// Use the http_headers::add method to fill in desired headers.\n    /// </remarks>\n    http_headers &headers() { return _m_impl->headers(); }\n\n    /// <summary>\n    /// Gets a const reference to the headers of the response message.\n    /// </summary>\n    /// <returns>HTTP headers for this response.</returns>\n    const http_headers &headers() const { return _m_impl->headers(); }\n\n    /// <summary>\n    /// Generates a string representation of the message, including the body when possible.\n    /// Mainly this should be used for debugging purposes as it has to copy the\n    /// message body and doesn't have excellent performance.\n    /// </summary>\n    /// <returns>A string representation of this HTTP request.</returns>\n    /// <remarks>Note this function is synchronous and doesn't wait for the\n    /// entire message body to arrive. If the message body has arrived by the time this\n    /// function is called and it is has a textual Content-Type it will be included.\n    /// Otherwise just the headers will be present.</remarks>\n    utility::string_t to_string() const { return _m_impl->to_string(); }\n\n    /// <summary>\n    /// Extracts the body of the response message as a string value, checking that the content type is a MIME text type.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes text.</param>\n    /// <returns>String containing body of the message.</returns>\n    pplx::task<utility::string_t> extract_string(bool ignore_content_type = false) const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_string(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extracts the body of the response message as a UTF-8 string value, checking that the content type is a MIME text type.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes text.</param>\n    /// <returns>String containing body of the message.</returns>\n    pplx::task<utf8string> extract_utf8string(bool ignore_content_type = false) const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf8string(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extracts the body of the response message as a UTF-16 string value, checking that the content type is a MIME text type.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes text.</param>\n    /// <returns>String containing body of the message.</returns>\n    pplx::task<utf16string> extract_utf16string(bool ignore_content_type = false) const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf16string(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extracts the body of the response message into a json value, checking that the content type is application/json.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes json.</param>\n    /// <returns>JSON value from the body of this message.</returns>\n    pplx::task<json::value> extract_json(bool ignore_content_type = false) const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->_extract_json(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extracts the body of the response message into a vector of bytes.\n    /// </summary>\n    /// <returns>The body of the message as a vector of bytes.</returns>\n    pplx::task<std::vector<unsigned char>> extract_vector() const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl](utility::size64_t) { return impl->_extract_vector(); });\n    }\n\n    /// <summary>\n    /// Sets the body of the message to a textual string and set the \"Content-Type\" header. Assumes\n    /// the character encoding of the string is UTF-8.\n    /// </summary>\n    /// <param name=\"body_text\">String containing body text.</param>\n    /// <param name=\"content_type\">MIME type to set the \"Content-Type\" header to. Default to \"text/plain; charset=utf-8\".</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data and \"Content-Type\" header.\n    /// </remarks>\n    void set_body(utf8string &&body_text, const utf8string &content_type = utf8string(\"text/plain; charset=utf-8\"))\n    {\n        const auto length = body_text.size();\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream<std::string>(std::move(body_text)), length, content_type);\n    }\n\n    /// <summary>\n    /// Sets the body of the message to a textual string and set the \"Content-Type\" header. Assumes\n    /// the character encoding of the string is UTF-8.\n    /// </summary>\n    /// <param name=\"body_text\">String containing body text.</param>\n    /// <param name=\"content_type\">MIME type to set the \"Content-Type\" header to. Default to \"text/plain; charset=utf-8\".</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data and \"Content-Type\" header.\n    /// </remarks>\n    void set_body(const utf8string &body_text, const utf8string &content_type = utf8string(\"text/plain; charset=utf-8\"))\n    {\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream<std::string>(body_text), body_text.size(), content_type);\n    }\n\n    /// <summary>\n    /// Sets the body of the message to a textual string and set the \"Content-Type\" header. Assumes\n    /// the character encoding of the string is UTF-16 will perform conversion to UTF-8.\n    /// </summary>\n    /// <param name=\"body_text\">String containing body text.</param>\n    /// <param name=\"content_type\">MIME type to set the \"Content-Type\" header to. Default to \"text/plain\".</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data and \"Content-Type\" header.\n    /// </remarks>\n    void set_body(const utf16string &body_text, utf16string content_type = HTTPMSG_UTF16(\"text/plain\"))\n    {\n        if (content_type.find(::utility::conversions::to_utf16string(\"charset=\")) != content_type.npos)\n        {\n            throw std::invalid_argument(\"content_type can't contain a 'charset'.\");\n        }\n\n        auto utf8body = utility::conversions::utf16_to_utf8(body_text);\n        auto length = utf8body.size();\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream<std::string>(\n                      std::move(utf8body)),\n                      length,\n                      std::move(content_type.append(::utility::conversions::to_utf16string(\"; charset=utf-8\"))));\n    }\n\n    /// <summary>\n    /// Sets the body of the message to contain json value. If the 'Content-Type'\n    /// header hasn't already been set it will be set to 'application/json'.\n    /// </summary>\n    /// <param name=\"body_text\">json value.</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data.\n    /// </remarks>\n    void set_body(const json::value &body_data)\n    {\n        auto body_text = utility::conversions::to_utf8string(body_data.serialize());\n        auto length = body_text.size();\n        set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), length, _XPLATSTR(\"application/json\"));\n    }\n\n    /// <summary>\n    /// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'\n    /// header hasn't already been set it will be set to 'application/octet-stream'.\n    /// </summary>\n    /// <param name=\"body_data\">Vector containing body data.</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data.\n    /// </remarks>\n    void set_body(std::vector<unsigned char> &&body_data)\n    {\n        auto length = body_data.size();\n        set_body(concurrency::streams::bytestream::open_istream(std::move(body_data)), length);\n    }\n\n    /// <summary>\n    /// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'\n    /// header hasn't already been set it will be set to 'application/octet-stream'.\n    /// </summary>\n    /// <param name=\"body_data\">Vector containing body data.</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data.\n    /// </remarks>\n    void set_body(const std::vector<unsigned char> &body_data)\n    {\n        set_body(concurrency::streams::bytestream::open_istream(body_data), body_data.size());\n    }\n\n    /// <summary>\n    /// Defines a stream that will be relied on to provide the body of the HTTP message when it is\n    /// sent.\n    /// </summary>\n    /// <param name=\"stream\">A readable, open asynchronous stream.</param>\n    /// <param name=\"content_type\">A string holding the MIME type of the message body.</param>\n    /// <remarks>\n    /// This cannot be used in conjunction with any other means of setting the body of the request.\n    /// The stream will not be read until the message is sent.\n    /// </remarks>\n    void set_body(const concurrency::streams::istream &stream, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\"))\n    {\n        _m_impl->set_body(stream, content_type);\n    }\n\n    /// <summary>\n    /// Defines a stream that will be relied on to provide the body of the HTTP message when it is\n    /// sent.\n    /// </summary>\n    /// <param name=\"stream\">A readable, open asynchronous stream.</param>\n    /// <param name=\"content_length\">The size of the data to be sent in the body.</param>\n    /// <param name=\"content_type\">A string holding the MIME type of the message body.</param>\n    /// <remarks>\n    /// This cannot be used in conjunction with any other means of setting the body of the request.\n    /// The stream will not be read until the message is sent.\n    /// </remarks>\n    void set_body(const concurrency::streams::istream &stream, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\"))\n    {\n        _m_impl->set_body(stream, content_length, content_type);\n    }\n\n    /// <summary>\n    /// Produces a stream which the caller may use to retrieve data from an incoming request.\n    /// </summary>\n    /// <returns>A readable, open asynchronous stream.</returns>\n    /// <remarks>\n    /// This cannot be used in conjunction with any other means of getting the body of the request.\n    /// It is not necessary to wait until the message has been sent before starting to write to the\n    /// stream, but it is advisable to do so, since it will allow the network I/O to start earlier\n    /// and the work of sending data can be overlapped with the production of more data.\n    /// </remarks>\n    concurrency::streams::istream body() const\n    {\n        return _m_impl->instream();\n    }\n\n    /// <summary>\n    /// Signals the user (client) when all the data for this response message has been received.\n    /// </summary>\n    /// <returns>A <c>task</c> which is completed when all of the response body has been received.</returns>\n    pplx::task<http::http_response> content_ready() const\n    {\n        http_response resp = *this;\n        return pplx::create_task(_m_impl->_get_data_available()).then([resp](utility::size64_t) mutable { return resp; });\n    }\n\n    std::shared_ptr<http::details::_http_response> _get_impl() const { return _m_impl; }\n\n    http::details::_http_server_context * _get_server_context() const { return _m_impl->_get_server_context(); }\n    void _set_server_context(std::unique_ptr<http::details::_http_server_context> server_context) { _m_impl->_set_server_context(std::move(server_context)); }\n\nprivate:\n\n    std::shared_ptr<http::details::_http_response> _m_impl;\n};\n\nnamespace details {\n/// <summary>\n/// Internal representation of an HTTP request message.\n/// </summary>\nclass _http_request final : public http::details::http_msg_base, public std::enable_shared_from_this<_http_request>\n{\npublic:\n\n    _ASYNCRTIMP _http_request(http::method mtd);\n\n    _ASYNCRTIMP _http_request(std::unique_ptr<http::details::_http_server_context> server_context);\n\n    virtual ~_http_request() {}\n\n    http::method &method() { return m_method; }\n\n    uri &request_uri() { return m_uri; }\n\n    _ASYNCRTIMP uri absolute_uri() const;\n\n    _ASYNCRTIMP uri relative_uri() const;\n\n    _ASYNCRTIMP void set_request_uri(const uri&);\n\n    const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; }\n\n    void set_cancellation_token(const pplx::cancellation_token &token)\n    {\n        m_cancellationToken = token;\n    }\n\n    _ASYNCRTIMP utility::string_t to_string() const;\n\n    _ASYNCRTIMP pplx::task<void> reply(const http_response &response);\n\n    pplx::task<http_response> get_response()\n    {\n        return pplx::task<http_response>(m_response);\n    }\n\n    _ASYNCRTIMP pplx::task<void> _reply_if_not_already(http::status_code status);\n\n    void set_response_stream(const concurrency::streams::ostream &stream)\n    {\n        m_response_stream = stream;\n    }\n\n    void set_progress_handler(const progress_handler &handler)\n    {\n        m_progress_handler = std::make_shared<progress_handler>(handler);\n    }\n\n    const concurrency::streams::ostream & _response_stream() const { return m_response_stream; }\n\n    const std::shared_ptr<progress_handler> & _progress_handler() const { return m_progress_handler; }\n\n    http::details::_http_server_context * _get_server_context() const { return m_server_context.get(); }\n\n    void _set_server_context(std::unique_ptr<http::details::_http_server_context> server_context) { m_server_context = std::move(server_context); }\n\n    void _set_listener_path(const utility::string_t &path) { m_listener_path = path; }\n\n    void _set_base_uri(const http::uri &base_uri) { m_base_uri = base_uri; }\n\n    _ASYNCRTIMP void _record_body_data_for_retry(const concurrency::streams::istream &stream);\n\n    _ASYNCRTIMP void _record_body_data_for_retry(const std::vector<unsigned char> &body_data);\n\n    _ASYNCRTIMP void _record_body_data_for_retry(const utf8string &body_text, const utf8string &content_type);\n\n    _ASYNCRTIMP bool _reset_body_for_retry();\n\nprivate:\n\n    // Actual initiates sending the response, without checking if a response has already been sent.\n    pplx::task<void> _reply_impl(http_response response);\n\n    http::method m_method;\n\n    // Tracks whether or not a response has already been started for this message.\n    pplx::details::atomic_long m_initiated_response;\n\n    std::unique_ptr<http::details::_http_server_context> m_server_context;\n\n    pplx::cancellation_token m_cancellationToken;\n\n    http::uri m_base_uri;\n    http::uri m_uri;\n    utility::string_t m_listener_path;\n\n    concurrency::streams::ostream m_response_stream;\n\n    std::shared_ptr<progress_handler> m_progress_handler;\n\n    pplx::task_completion_event<http_response> m_response;\n\n    bool m_bodyTextRecorded;\n    bool m_bodyVectorRecorded;\n    bool m_onlySetBodyUsingStream;\n    utf8string m_bodyText;\n    utf8string m_contentType;\n    std::vector<unsigned char> m_bodyVector;\n};\n\n\n}  // namespace details\n\n/// <summary>\n/// Represents an HTTP request.\n/// </summary>\nclass http_request\n{\npublic:\n    /// <summary>\n    /// Constructs a new HTTP request with the 'GET' method.\n    /// </summary>\n    http_request()\n        : _m_impl(std::make_shared<http::details::_http_request>(methods::GET)) {}\n\n    /// <summary>\n    /// Constructs a new HTTP request with the given request method.\n    /// </summary>\n    /// <param name=\"mtd\">Request method.</param>\n    http_request(http::method mtd)\n        : _m_impl(std::make_shared<http::details::_http_request>(std::move(mtd))) {}\n\n    /// <summary>\n    /// Destructor frees any held resources.\n    /// </summary>\n    ~http_request() {}\n\n    /// <summary>\n    /// Get the method (GET/PUT/POST/DELETE) of the request message.\n    /// </summary>\n    /// <returns>Request method of this HTTP request.</returns>\n    const http::method &method() const { return _m_impl->method(); }\n\n    /// <summary>\n    /// Get the method (GET/PUT/POST/DELETE) of the request message.\n    /// </summary>\n    /// <param name=\"method\">Request method of this HTTP request.</param>\n    void set_method(const http::method &method) const { _m_impl->method() = method; }\n\n    /// <summary>\n    /// Get the underling URI of the request message.\n    /// </summary>\n    /// <returns>The uri of this message.</returns>\n    const uri & request_uri() const { return _m_impl->request_uri(); }\n\n    /// <summary>\n    /// Set the underling URI of the request message.\n    /// </summary>\n    /// <param name=\"uri\">The uri for this message.</param>\n    void set_request_uri(const uri& uri) { return _m_impl->set_request_uri(uri); }\n\n    /// <summary>\n    /// Gets a reference the URI path, query, and fragment part of this request message.\n    /// This will be appended to the base URI specified at construction of the http_client.\n    /// </summary>\n    /// <returns>A string.</returns>\n    /// <remarks>When the request is the one passed to a listener's handler, the\n    /// relative URI is the request URI less the listener's path. In all other circumstances,\n    /// request_uri() and relative_uri() will return the same value.\n    /// </remarks>\n    uri relative_uri() const { return _m_impl->relative_uri(); }\n\n    /// <summary>\n    /// Get an absolute URI with scheme, host, port, path, query, and fragment part of\n    /// the request message.\n    /// </summary>\n    /// <remarks>Absolute URI is only valid after this http_request object has been passed\n    /// to http_client::request().\n    /// </remarks>\n    uri absolute_uri() const { return _m_impl->absolute_uri(); }\n\n    /// <summary>\n    /// Gets a reference to the headers of the response message.\n    /// </summary>\n    /// <returns>HTTP headers for this response.</returns>\n    /// <remarks>\n    /// Use the http_headers::add to fill in desired headers.\n    /// </remarks>\n    http_headers &headers() { return _m_impl->headers(); }\n\n    /// <summary>\n    /// Gets a const reference to the headers of the response message.\n    /// </summary>\n    /// <returns>HTTP headers for this response.</returns>\n    /// <remarks>\n    /// Use the http_headers::add to fill in desired headers.\n    /// </remarks>\n    const http_headers &headers() const { return _m_impl->headers(); }\n\n    /// <summary>\n    /// Extract the body of the request message as a string value, checking that the content type is a MIME text type.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes UTF-8.</param>\n    /// <returns>String containing body of the message.</returns>\n    pplx::task<utility::string_t> extract_string(bool ignore_content_type = false)\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_string(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extract the body of the request message as a UTF-8 string value, checking that the content type is a MIME text type.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes UTF-8.</param>\n    /// <returns>String containing body of the message.</returns>\n    pplx::task<utf8string> extract_utf8string(bool ignore_content_type = false)\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf8string(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extract the body of the request message as a UTF-16 string value, checking that the content type is a MIME text type.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes UTF-16.</param>\n    /// <returns>String containing body of the message.</returns>\n    pplx::task<utf16string> extract_utf16string(bool ignore_content_type = false)\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->extract_utf16string(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extracts the body of the request message into a json value, checking that the content type is application/json.\n    /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.\n    /// </summary>\n    /// <param name=\"ignore_content_type\">If true, ignores the Content-Type header and assumes UTF-8.</param>\n    /// <returns>JSON value from the body of this message.</returns>\n    pplx::task<json::value> extract_json(bool ignore_content_type = false) const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl, ignore_content_type](utility::size64_t) { return impl->_extract_json(ignore_content_type); });\n    }\n\n    /// <summary>\n    /// Extract the body of the response message into a vector of bytes. Extracting a vector can be done on\n    /// </summary>\n    /// <returns>The body of the message as a vector of bytes.</returns>\n    pplx::task<std::vector<unsigned char>> extract_vector() const\n    {\n        auto impl = _m_impl;\n        return pplx::create_task(_m_impl->_get_data_available()).then([impl](utility::size64_t) { return impl->_extract_vector(); });\n    }\n\n    /// <summary>\n    /// Sets the body of the message to a textual string and set the \"Content-Type\" header. Assumes\n    /// the character encoding of the string is UTF-8.\n    /// </summary>\n    /// <param name=\"body_text\">String containing body text.</param>\n    /// <param name=\"content_type\">MIME type to set the \"Content-Type\" header to. Default to \"text/plain; charset=utf-8\".</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data and \"Content-Type\" header.\n    /// </remarks>\n    void set_body(utf8string &&body_text, const utf8string &content_type = utf8string(\"text/plain; charset=utf-8\"))\n    {\n        const auto length = body_text.size();\n        _m_impl->_record_body_data_for_retry(body_text, content_type);\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream<std::string>(std::move(body_text)), length, content_type);\n    }\n\n    /// <summary>\n    /// Sets the body of the message to a textual string and set the \"Content-Type\" header. Assumes\n    /// the character encoding of the string is UTF-8.\n    /// </summary>\n    /// <param name=\"body_text\">String containing body text.</param>\n    /// <param name=\"content_type\">MIME type to set the \"Content-Type\" header to. Default to \"text/plain; charset=utf-8\".</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data and \"Content-Type\" header.\n    /// </remarks>\n    void set_body(const utf8string &body_text, const utf8string &content_type = utf8string(\"text/plain; charset=utf-8\"))\n    {\n        _m_impl->_record_body_data_for_retry(body_text, content_type);\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream<std::string>(body_text), body_text.size(), content_type);\n    }\n\n    /// <summary>\n    /// Sets the body of the message to a textual string and set the \"Content-Type\" header. Assumes\n    /// the character encoding of the string is UTF-16 will perform conversion to UTF-8.\n    /// </summary>\n    /// <param name=\"body_text\">String containing body text.</param>\n    /// <param name=\"content_type\">MIME type to set the \"Content-Type\" header to. Default to \"text/plain\".</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data and \"Content-Type\" header.\n    /// </remarks>\n    void set_body(const utf16string &body_text, utf16string content_type = HTTPMSG_UTF16(\"text/plain\"))\n    {\n        if(content_type.find(::utility::conversions::to_utf16string(\"charset=\")) != content_type.npos)\n        {\n            throw std::invalid_argument(\"content_type can't contain a 'charset'.\");\n        }\n\n        auto utf8body = utility::conversions::utf16_to_utf8(body_text);\n        auto length = utf8body.size();\n        auto contextTypeAppended = content_type.append(::utility::conversions::to_utf16string(\"; charset=utf-8\"));\n        _m_impl->_record_body_data_for_retry(utf8body, utility::conversions::utf16_to_utf8(contextTypeAppended));\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream(\n                      std::move(utf8body)),\n                      length,\n                      std::move(contextTypeAppended));\n    }\n\n    /// <summary>\n    /// Sets the body of the message to contain json value. If the 'Content-Type'\n    /// header hasn't already been set it will be set to 'application/json'.\n    /// </summary>\n    /// <param name=\"body_data\">json value.</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data.\n    /// </remarks>\n    void set_body(const json::value &body_data)\n    {\n        auto body_text = utility::conversions::to_utf8string(body_data.serialize());\n        auto length = body_text.size();\n        utf8string contentType = \"application/json\";\n        _m_impl->_record_body_data_for_retry(body_text, contentType);\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_text)), length, contentType);\n    }\n\n    /// <summary>\n    /// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'\n    /// header hasn't already been set it will be set to 'application/octet-stream'.\n    /// </summary>\n    /// <param name=\"body_data\">Vector containing body data.</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data.\n    /// </remarks>\n    void set_body(std::vector<unsigned char> &&body_data)\n    {\n        auto length = body_data.size();\n        _m_impl->_record_body_data_for_retry(body_data);\n        _m_impl->set_body(concurrency::streams::bytestream::open_istream(std::move(body_data)), length, _XPLATSTR(\"application/octet-stream\"));\n    }\n\n    /// <summary>\n    /// Sets the body of the message to the contents of a byte vector. If the 'Content-Type'\n    /// header hasn't already been set it will be set to 'application/octet-stream'.\n    /// </summary>\n    /// <param name=\"body_data\">Vector containing body data.</param>\n    /// <remarks>\n    /// This will overwrite any previously set body data.\n    /// </remarks>\n    void set_body(const std::vector<unsigned char> &body_data)\n    {\n        _m_impl->_record_body_data_for_retry(body_data);\n        set_body(concurrency::streams::bytestream::open_istream(body_data), body_data.size());\n    }\n\n    /// <summary>\n    /// Defines a stream that will be relied on to provide the body of the HTTP message when it is\n    /// sent.\n    /// </summary>\n    /// <param name=\"stream\">A readable, open asynchronous stream.</param>\n    /// <param name=\"content_type\">A string holding the MIME type of the message body.</param>\n    /// <remarks>\n    /// This cannot be used in conjunction with any other means of setting the body of the request.\n    /// The stream will not be read until the message is sent.\n    /// </remarks>\n    void set_body(const concurrency::streams::istream &stream, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\"))\n    {\n        _m_impl->_record_body_data_for_retry(stream);\n        _m_impl->set_body(stream, content_type);\n    }\n\n    /// <summary>\n    /// Defines a stream that will be relied on to provide the body of the HTTP message when it is\n    /// sent.\n    /// </summary>\n    /// <param name=\"stream\">A readable, open asynchronous stream.</param>\n    /// <param name=\"content_length\">The size of the data to be sent in the body.</param>\n    /// <param name=\"content_type\">A string holding the MIME type of the message body.</param>\n    /// <remarks>\n    /// This cannot be used in conjunction with any other means of setting the body of the request.\n    /// The stream will not be read until the message is sent.\n    /// </remarks>\n    void set_body(const concurrency::streams::istream &stream, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\"))\n    {\n        _m_impl->_record_body_data_for_retry(stream);\n        _m_impl->set_body(stream, content_length, content_type);\n    }\n\n    /// <summary>\n    /// Produces a stream which the caller may use to retrieve data from an incoming request.\n    /// </summary>\n    /// <returns>A readable, open asynchronous stream.</returns>\n    /// <remarks>\n    /// This cannot be used in conjunction with any other means of getting the body of the request.\n    /// It is not necessary to wait until the message has been sent before starting to write to the\n    /// stream, but it is advisable to do so, since it will allow the network I/O to start earlier\n    /// and the work of sending data can be overlapped with the production of more data.\n    /// </remarks>\n    concurrency::streams::istream body() const\n    {\n        return _m_impl->instream();\n    }\n\n    /// <summary>\n    /// Defines a stream that will be relied on to hold the body of the HTTP response message that\n    /// results from the request.\n    /// </summary>\n    /// <param name=\"stream\">A writable, open asynchronous stream.</param>\n    /// <remarks>\n    /// If this function is called, the body of the response should not be accessed in any other\n    /// way.\n    /// </remarks>\n    void set_response_stream(const concurrency::streams::ostream &stream)\n    {\n        return _m_impl->set_response_stream(stream);\n    }\n\n    /// <summary>\n    /// Defines a callback function that will be invoked for every chunk of data uploaded or downloaded\n    /// as part of the request.\n    /// </summary>\n    /// <param name=\"handler\">A function representing the progress handler. It's parameters are:\n    ///    up:       a <c>message_direction::direction</c> value  indicating the direction of the message\n    ///              that is being reported.\n    ///    progress: the number of bytes that have been processed so far.\n    /// </param>\n    /// <remarks>\n    ///   This function will be called at least once for upload and at least once for\n    ///   the download body, unless there is some exception generated. An HTTP message with an error\n    ///   code is not an exception. This means, that even if there is no body, the progress handler\n    ///   will be called.\n    ///\n    ///   Setting the chunk size on the http_client does not guarantee that the client will be using\n    ///   exactly that increment for uploading and downloading data.\n    ///\n    ///   The handler will be called only once for each combination of argument values, in order. Depending\n    ///   on how a service responds, some download values may come before all upload values have been\n    ///   reported.\n    ///\n    ///   The progress handler will be called on the thread processing the request. This means that\n    ///   the implementation of the handler must take care not to block the thread or do anything\n    ///   that takes significant amounts of time. In particular, do not do any kind of I/O from within\n    ///   the handler, do not update user interfaces, and to not acquire any locks. If such activities\n    ///   are necessary, it is the handler's responsibility to execute that work on a separate thread.\n    /// </remarks>\n    void set_progress_handler(const progress_handler &handler)\n    {\n        return _m_impl->set_progress_handler(handler);\n    }\n\n    /// <summary>\n    /// Asynchronously responses to this HTTP request.\n    /// </summary>\n    /// <param name=\"response\">Response to send.</param>\n    /// <returns>An asynchronous operation that is completed once response is sent.</returns>\n    pplx::task<void> reply(const http_response &response) const { return _m_impl->reply(response); }\n\n    /// <summary>\n    /// Asynchronously responses to this HTTP request.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <returns>An asynchronous operation that is completed once response is sent.</returns>\n    pplx::task<void> reply(http::status_code status) const\n    {\n        return reply(http_response(status));\n    }\n\n    /// <summary>\n    /// Responds to this HTTP request.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <param name=\"body_data\">Json value to use in the response body.</param>\n    /// <returns>An asynchronous operation that is completed once response is sent.</returns>\n    pplx::task<void> reply(http::status_code status, const json::value &body_data) const\n    {\n        http_response response(status);\n        response.set_body(body_data);\n        return reply(response);\n    }\n\n    /// <summary>\n    /// Responds to this HTTP request with a string.\n    /// Assumes the character encoding of the string is UTF-8.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <param name=\"body_data\">UTF-8 string containing the text to use in the response body.</param>\n    /// <param name=\"content_type\">Content type of the body.</param>\n    /// <returns>An asynchronous operation that is completed once response is sent.</returns>\n    /// <remarks>\n    ///  Callers of this function do NOT need to block waiting for the response to be\n    /// sent to before the body data is destroyed or goes out of scope.\n    /// </remarks>\n    pplx::task<void> reply(http::status_code status, utf8string &&body_data, const utf8string &content_type = \"text/plain; charset=utf-8\") const\n    {\n        http_response response(status);\n        response.set_body(std::move(body_data), content_type);\n        return reply(response);\n    }\n\n    /// <summary>\n    /// Responds to this HTTP request with a string.\n    /// Assumes the character encoding of the string is UTF-8.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <param name=\"body_data\">UTF-8 string containing the text to use in the response body.</param>\n    /// <param name=\"content_type\">Content type of the body.</param>\n    /// <returns>An asynchronous operation that is completed once response is sent.</returns>\n    /// <remarks>\n    //  Callers of this function do NOT need to block waiting for the response to be\n    /// sent to before the body data is destroyed or goes out of scope.\n    /// </remarks>\n    pplx::task<void> reply(http::status_code status, const utf8string &body_data, const utf8string &content_type = \"text/plain; charset=utf-8\") const\n    {\n        http_response response(status);\n        response.set_body(body_data, content_type);\n        return reply(response);\n    }\n\n    /// <summary>\n    /// Responds to this HTTP request with a string. Assumes the character encoding\n    /// of the string is UTF-16 will perform conversion to UTF-8.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <param name=\"body_data\">UTF-16 string containing the text to use in the response body.</param>\n    /// <param name=\"content_type\">Content type of the body.</param>\n    /// <returns>An asynchronous operation that is completed once response is sent.</returns>\n    /// <remarks>\n    //  Callers of this function do NOT need to block waiting for the response to be\n    /// sent to before the body data is destroyed or goes out of scope.\n    /// </remarks>\n    pplx::task<void> reply(http::status_code status, const utf16string &body_data, const utf16string &content_type = HTTPMSG_UTF16(\"text/plain\")) const\n    {\n        http_response response(status);\n        response.set_body(body_data, content_type);\n        return reply(response);\n    }\n\n    /// <summary>\n    /// Responds to this HTTP request.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <param name=\"content_type\">A string holding the MIME type of the message body.</param>\n    /// <param name=\"body\">An asynchronous stream representing the body data.</param>\n    /// <returns>A task that is completed once a response from the request is received.</returns>\n    pplx::task<void> reply(status_code status, const concurrency::streams::istream &body, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\")) const\n    {\n        http_response response(status);\n        response.set_body(body, content_type);\n        return reply(response);\n    }\n\n    /// <summary>\n    /// Responds to this HTTP request.\n    /// </summary>\n    /// <param name=\"status\">Response status code.</param>\n    /// <param name=\"content_length\">The size of the data to be sent in the body..</param>\n    /// <param name=\"content_type\">A string holding the MIME type of the message body.</param>\n    /// <param name=\"body\">An asynchronous stream representing the body data.</param>\n    /// <returns>A task that is completed once a response from the request is received.</returns>\n    pplx::task<void> reply(status_code status, const concurrency::streams::istream &body, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\")) const\n    {\n        http_response response(status);\n        response.set_body(body, content_length, content_type);\n        return reply(response);\n    }\n\n    /// <summary>\n    /// Signals the user (listener) when all the data for this request message has been received.\n    /// </summary>\n    /// <returns>A <c>task</c> which is completed when all of the response body has been received</returns>\n    pplx::task<http_request> content_ready() const\n    {\n        http_request req = *this;\n        return pplx::create_task(_m_impl->_get_data_available()).then([req](utility::size64_t) mutable { return req; });\n    }\n\n    /// <summary>\n    /// Gets a task representing the response that will eventually be sent.\n    /// </summary>\n    /// <returns>A task that is completed once response is sent.</returns>\n    pplx::task<http_response> get_response() const\n    {\n        return _m_impl->get_response();\n    }\n\n    /// <summary>\n    /// Generates a string representation of the message, including the body when possible.\n    /// Mainly this should be used for debugging purposes as it has to copy the\n    /// message body and doesn't have excellent performance.\n    /// </summary>\n    /// <returns>A string representation of this HTTP request.</returns>\n    /// <remarks>Note this function is synchronous and doesn't wait for the\n    /// entire message body to arrive. If the message body has arrived by the time this\n    /// function is called and it is has a textual Content-Type it will be included.\n    /// Otherwise just the headers will be present.</remarks>\n    utility::string_t to_string() const { return _m_impl->to_string(); }\n\n    /// <summary>\n    /// Sends a response if one has not already been sent.\n    /// </summary>\n    pplx::task<void> _reply_if_not_already(status_code status) { return _m_impl->_reply_if_not_already(status); }\n\n    /// <summary>\n    /// Gets the server context associated with this HTTP message.\n    /// </summary>\n    http::details::_http_server_context * _get_server_context() const { return _m_impl->_get_server_context(); }\n\n    /// <summary>\n    /// These are used for the initial creation of the HTTP request.\n    /// </summary>\n    static http_request _create_request(std::unique_ptr<http::details::_http_server_context> server_context) { return http_request(std::move(server_context)); }\n    void _set_server_context(std::unique_ptr<http::details::_http_server_context> server_context) { _m_impl->_set_server_context(std::move(server_context)); }\n\n    void _set_listener_path(const utility::string_t &path) { _m_impl->_set_listener_path(path); }\n\n    const std::shared_ptr<http::details::_http_request> & _get_impl() const { return _m_impl; }\n\n    void _set_cancellation_token(const pplx::cancellation_token &token)\n    {\n        _m_impl->set_cancellation_token(token);\n    }\n\n    const pplx::cancellation_token & _cancellation_token() const\n    {\n        return _m_impl->cancellation_token();\n    }\n\n    void _set_base_uri(const http::uri &base_uri)\n    {\n        _m_impl->_set_base_uri(base_uri);\n    }\n\n    void _set_body_internal(const concurrency::streams::istream &stream, const utility::string_t &content_type = _XPLATSTR(\"application/octet-stream\"))\n    {\n        _m_impl->set_body(stream, content_type);\n    }\n\n    bool _reset_body_for_retry()\n    {\n        return _m_impl->_reset_body_for_retry();\n    }\n\nprivate:\n    friend class http::details::_http_request;\n    friend class http::client::http_client;\n\n    http_request(std::unique_ptr<http::details::_http_server_context> server_context) : _m_impl(std::make_shared<details::_http_request>(std::move(server_context))) {}\n\n    std::shared_ptr<http::details::_http_request> _m_impl;\n};\n\nnamespace client {\nclass http_pipeline;\n}\n\n/// <summary>\n/// HTTP client handler class, used to represent an HTTP pipeline stage.\n/// </summary>\n/// <remarks>\n/// When a request goes out, it passes through a series of stages, customizable by\n/// the application and/or libraries. The default stage will interact with lower-level\n/// communication layers to actually send the message on the network. When creating a client\n/// instance, an application may add pipeline stages in front of the already existing\n/// stages. Each stage has a reference to the next stage available in the <seealso cref=\"http_pipeline_stage::next_stage()\"/>\n/// value.\n/// </remarks>\nclass http_pipeline_stage : public std::enable_shared_from_this<http_pipeline_stage>\n{\npublic:\n\n    http_pipeline_stage() {};\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800))\n    http_pipeline_stage & operator=(const http_pipeline_stage &) = delete;\n    http_pipeline_stage(const http_pipeline_stage &) = delete;\n#endif\n\n    virtual ~http_pipeline_stage() {};\n\n    /// <summary>\n    /// Runs this stage against the given request and passes onto the next stage.\n    /// </summary>\n    /// <param name=\"request\">The HTTP request.</param>\n    /// <returns>A task of the HTTP response.</returns>\n    virtual pplx::task<http_response> propagate(http_request request) = 0;\n\nprotected:\n\n    /// <summary>\n    /// Gets the next stage in the pipeline.\n    /// </summary>\n    /// <returns>A shared pointer to a pipeline stage.</returns>\n    const std::shared_ptr<http_pipeline_stage> & next_stage() const\n    {\n        return m_next_stage;\n    }\n\n    /// <summary>\n    /// Gets a shared pointer to this pipeline stage.\n    /// </summary>\n    /// <returns>A shared pointer to a pipeline stage.</returns>\n    CASABLANCA_DEPRECATED(\"This api is redundant. Use 'shared_from_this()' directly instead.\")\n    std::shared_ptr<http_pipeline_stage> current_stage()\n    {\n        return this->shared_from_this();\n    }\n\nprivate:\n    friend class ::web::http::client::http_pipeline;\n\n    void set_next_stage(const std::shared_ptr<http_pipeline_stage> &next)\n    {\n        m_next_stage = next;\n    }\n\n    std::shared_ptr<http_pipeline_stage> m_next_stage;\n\n};\n#endif // !XSAPI_NO_PPL\n\n}}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/json.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* HTTP Library: JSON parser and writer\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#ifndef _CASA_JSON_H\n#define _CASA_JSON_H\n\n#include <memory>\n#include <string>\n#include <sstream>\n#include <vector>\n#include <unordered_map>\n#include <cstdint>\n#include \"cpprest/details/basic_types.h\"\n#include \"cpprest/asyncrt_utils.h\"\n\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning (push)\n#pragma warning(disable : 4266)\n#pragma warning(disable : 26812)  // enum instead of enum class\n#endif\n\nnamespace web\n{\n/// Library for parsing and serializing JSON values to and from C++ types.\nnamespace json\n{\n    // Various forward declarations.\n    namespace details\n    {\n        class _Value;\n        class _Number;\n        class _Null;\n        class _Boolean;\n        class _String;\n        class _Object;\n        class _Array;\n        template <typename CharType> class JSON_Parser;\n    }\n\n    namespace details\n    {\n        extern bool g_keep_json_object_unsorted;\n    }\n\n    /// <summary>\n    /// Preserve the order of the name/value pairs when parsing a JSON object.\n    /// The default is false, which can yield better performance.\n    /// </summary>\n    /// <param name=\"keep_order\"><c>true</c> if ordering should be preserved when parsing, <c>false</c> otherwise.</param>\n    /// <remarks>Note this is a global setting and affects all JSON parsing done.</remarks>\n    void _ASYNCRTIMP __cdecl keep_object_element_order(bool keep_order);\n\n#ifdef _WIN32\n#ifdef _DEBUG\n#define ENABLE_JSON_VALUE_VISUALIZER\n#endif\n#endif\n\n    class number;\n    class array;\n    class object;\n\n    /// <summary>\n    /// A JSON value represented as a C++ class.\n    /// </summary>\n    class value\n    {\n    public:\n        /// <summary>\n        /// This enumeration represents the various kinds of JSON values.\n        /// </summary>\n        enum value_type\n        {\n            /// Number value\n            Number,\n            /// Boolean value\n            Boolean,\n            /// String value\n            String,\n            /// Object value\n            Object,\n            /// Array value\n            Array,\n            /// Null value\n            Null\n        };\n\n        /// <summary>\n        /// Constructor creating a null value\n        /// </summary>\n        _ASYNCRTIMP value();\n\n        /// <summary>\n        /// Constructor creating a JSON number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        _ASYNCRTIMP value(int32_t value);\n\n        /// <summary>\n        /// Constructor creating a JSON number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        _ASYNCRTIMP value(uint32_t value);\n\n        /// <summary>\n        /// Constructor creating a JSON number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        _ASYNCRTIMP value(int64_t value);\n\n        /// <summary>\n        /// Constructor creating a JSON number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        _ASYNCRTIMP value(uint64_t value);\n\n        /// <summary>\n        /// Constructor creating a JSON number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        _ASYNCRTIMP value(double value);\n\n        /// <summary>\n        /// Constructor creating a JSON Boolean value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        _ASYNCRTIMP explicit value(bool value);\n\n        /// <summary>\n        /// Constructor creating a JSON string value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from, a C++ STL string of the platform-native character width</param>\n        /// <remarks>\n        /// This constructor has O(n) performance because it tries to determine if\n        /// specified string has characters that should be properly escaped in JSON.\n        /// </remarks>\n        _ASYNCRTIMP explicit value(utility::string_t value);\n        \n        /// <summary>\n        /// Constructor creating a JSON string value specifying if the string contains characters to escape\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from, a C++ STL string of the platform-native character width</param>\n        /// <param name=\"has_escape_chars\">Whether <paramref name=\"value\" /> contains characters\n        /// that should be escaped in JSON value</param>\n        /// <remarks>\n        /// This constructor has O(1) performance.\n        /// </remarks>\n        _ASYNCRTIMP explicit value(utility::string_t value, bool has_escape_chars);\n       \n        /// <summary>\n        /// Constructor creating a JSON string value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from, a C++ STL string of the platform-native character width</param>\n        /// <remarks>\n        /// <para>\n        /// This constructor has O(n) performance because it tries to determine if\n        /// specified string has characters that should be properly escaped in JSON.\n        /// </para>\n        /// <para>\n        /// This constructor exists in order to avoid string literals matching another constructor,\n        /// as is very likely. For example, conversion to bool does not require a user-defined conversion,\n        /// and will therefore match first, which means that the JSON value turns up as a boolean.\n        /// </para>\n        /// </remarks>\n        _ASYNCRTIMP explicit value(const utility::char_t* value);\n\n        /// <summary>\n        /// Constructor creating a JSON string value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from, a C++ STL string of the platform-native character width</param>\n        /// <param name=\"has_escape_chars\">Whether <paramref name=\"value\" /> contains characters</param>\n        /// <remarks>\n        /// <para>\n        /// This overload has O(1) performance.\n        /// </para>\n        /// <para>\n        /// This constructor exists in order to avoid string literals matching another constructor,\n        /// as is very likely. For example, conversion to bool does not require a user-defined conversion,\n        /// and will therefore match first, which means that the JSON value turns up as a boolean.\n        /// </para>\n        /// </remarks>\n        _ASYNCRTIMP explicit value(const utility::char_t* value, bool has_escape_chars);\n\n        /// <summary>\n        /// Copy constructor\n        /// </summary>\n        _ASYNCRTIMP value(const value &);\n\n        /// <summary>\n        /// Move constructor\n        /// </summary>\n        _ASYNCRTIMP value(value &&) CPPREST_NOEXCEPT ;\n\n        /// <summary>\n        /// Assignment operator.\n        /// </summary>\n        /// <returns>The JSON value object that contains the result of the assignment.</returns>\n        _ASYNCRTIMP value &operator=(const value &);\n\n        /// <summary>\n        /// Move assignment operator.\n        /// </summary>\n        /// <returns>The JSON value object that contains the result of the assignment.</returns>\n        _ASYNCRTIMP value &operator=(value &&) CPPREST_NOEXCEPT ;\n\n        // Static factories\n\n        /// <summary>\n        /// Creates a null value\n        /// </summary>\n        /// <returns>A JSON null value</returns>\n        static _ASYNCRTIMP value __cdecl null();\n\n        /// <summary>\n        /// Creates a number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON number value</returns>\n        static _ASYNCRTIMP value __cdecl number(double value);\n\n        /// <summary>\n        /// Creates a number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON number value</returns>\n        static _ASYNCRTIMP value __cdecl number(int32_t value);\n\n        /// <summary>\n        /// Creates a number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON number value</returns>\n        static _ASYNCRTIMP value __cdecl number(uint32_t value);\n\n        /// <summary>\n        /// Creates a number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON number value</returns>\n        static _ASYNCRTIMP value __cdecl number(int64_t value);\n\n        /// <summary>\n        /// Creates a number value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON number value</returns>\n        static _ASYNCRTIMP value __cdecl number(uint64_t value);\n\n        /// <summary>\n        /// Creates a Boolean value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON Boolean value</returns>\n        static _ASYNCRTIMP value __cdecl boolean(bool value);\n\n        /// <summary>\n        /// Creates a string value\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <returns>A JSON string value</returns>\n        /// <remarks>\n        /// This overload has O(n) performance because it tries to determine if\n        /// specified string has characters that should be properly escaped in JSON.\n        /// </remarks>\n        static _ASYNCRTIMP value __cdecl string(utility::string_t value);\n\n        /// <summary>\n        /// Creates a string value specifying if the string contains characters to escape\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from</param>\n        /// <param name=\"has_escape_chars\">Whether <paramref name=\"value\" /> contains characters\n        /// that should be escaped in JSON value</param>\n        /// <returns>A JSON string value</returns>\n        /// <remarks>\n        /// This overload has O(1) performance.\n        /// </remarks>\n        static _ASYNCRTIMP value __cdecl string(utility::string_t value, bool has_escape_chars);\n\n#ifdef _WIN32\nprivate:\n        // Only used internally by JSON parser.\n        static _ASYNCRTIMP value __cdecl string(const std::string &value);\npublic:\n#endif\n\n        /// <summary>\n        /// Creates an object value\n        /// </summary>\n        /// <param name=\"keep_order\">Whether to preserve the original order of the fields</param>\n        /// <returns>An empty JSON object value</returns>\n        static _ASYNCRTIMP json::value __cdecl object(bool keep_order = false);\n\n        /// <summary>\n        /// Creates an object value from a collection of field/values\n        /// </summary>\n        /// <param name=\"fields\">Field names associated with JSON values</param>\n        /// <param name=\"keep_order\">Whether to preserve the original order of the fields</param>\n        /// <returns>A non-empty JSON object value</returns>\n        static _ASYNCRTIMP json::value __cdecl object(std::vector<std::pair<::utility::string_t, value>> fields, bool keep_order = false);\n\n        /// <summary>\n        /// Creates an empty JSON array\n        /// </summary>\n        /// <returns>An empty JSON array value</returns>\n        static _ASYNCRTIMP json::value __cdecl array();\n\n        /// <summary>\n        /// Creates a JSON array\n        /// </summary>\n        /// <param name=\"size\">The initial number of elements of the JSON value</param>\n        /// <returns>A JSON array value</returns>\n        static _ASYNCRTIMP json::value __cdecl array(size_t size);\n\n        /// <summary>\n        /// Creates a JSON array\n        /// </summary>\n        /// <param name=\"elements\">A vector of JSON values</param>\n        /// <returns>A JSON array value</returns>\n        static _ASYNCRTIMP json::value __cdecl array(std::vector<value> elements);\n\n        /// <summary>\n        /// Accesses the type of JSON value the current value instance is\n        /// </summary>\n        /// <returns>The value's type</returns>\n        _ASYNCRTIMP json::value::value_type type() const;\n\n        /// <summary>\n        /// Is the current value a null value?\n        /// </summary>\n        /// <returns><c>true</c> if the value is a null value, <c>false</c> otherwise</returns>\n        bool is_null() const { return type() == Null; };\n\n        /// <summary>\n        /// Is the current value a number value?\n        /// </summary>\n        /// <returns><c>true</c> if the value is a number value, <c>false</c> otherwise</returns>\n        bool is_number() const { return type() == Number; }\n\n        /// <summary>\n        /// Is the current value represented as an integer number value?\n        /// </summary>\n        /// <remarks>\n        /// Note that if a json value is a number but represented as a double it can still\n        /// be retrieved as a integer using as_integer(), however the value will be truncated.\n        /// </remarks>\n        /// <returns><c>true</c> if the value is an integer value, <c>false</c> otherwise.</returns>\n        _ASYNCRTIMP bool is_integer() const;\n\n        /// <summary>\n        /// Is the current value represented as an double number value?\n        /// </summary>\n        /// <remarks>\n        /// Note that if a json value is a number but represented as a int it can still\n        /// be retrieved as a double using as_double().\n        /// </remarks>\n        /// <returns><c>true</c> if the value is an double value, <c>false</c> otherwise.</returns>\n        _ASYNCRTIMP bool is_double() const;\n\n        /// <summary>\n        /// Is the current value a Boolean value?\n        /// </summary>\n        /// <returns><c>true</c> if the value is a Boolean value, <c>false</c> otherwise</returns>\n        bool is_boolean() const { return type() == Boolean; }\n\n        /// <summary>\n        /// Is the current value a string value?\n        /// </summary>\n        /// <returns><c>true</c> if the value is a string value, <c>false</c> otherwise</returns>\n        bool is_string() const { return type() == String; }\n\n        /// <summary>\n        /// Is the current value an array?\n        /// </summary>\n        /// <returns><c>true</c> if the value is an array, <c>false</c> otherwise</returns>\n        bool is_array() const { return type() == Array; }\n\n        /// <summary>\n        /// Is the current value an object?\n        /// </summary>\n        /// <returns><c>true</c> if the value is an object, <c>false</c> otherwise</returns>\n        bool is_object() const { return type() == Object; }\n\n        /// <summary>\n        /// Gets the number of children of the value.\n        /// </summary>\n        /// <returns>The number of children. 0 for all non-composites.</returns>\n        size_t size() const;\n\n        /// <summary>\n        /// Parses a string and construct a JSON value.\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from, a C++ STL double-byte string</param>\n        _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value);\n\n        /// <summary>\n        /// Attempts to parse a string and construct a JSON value.\n        /// </summary>\n        /// <param name=\"value\">The C++ value to create a JSON value from, a C++ STL double-byte string</param>\n        /// <param name=\"errorCode\">If parsing fails, the error code is greater than 0</param>\n        /// <returns>The parsed object. Returns web::json::value::null if failed</returns>\n        _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value, std::error_code &errorCode);\n\n        /// <summary>\n        /// Serializes the current JSON value to a C++ string.\n        /// </summary>\n        /// <returns>A string representation of the value</returns>\n        _ASYNCRTIMP utility::string_t serialize() const;\n\n        /// <summary>\n        /// Serializes the current JSON value to a C++ string.\n        /// </summary>\n        /// <returns>A string representation of the value</returns>\n        CASABLANCA_DEPRECATED(\"This API is deprecated and has been renamed to avoid confusion with as_string(), use ::web::json::value::serialize() instead.\")\n        _ASYNCRTIMP utility::string_t to_string() const;\n\n        /// <summary>\n        /// Parses a JSON value from the contents of an input stream using the native platform character width.\n        /// </summary>\n        /// <param name=\"input\">The stream to read the JSON value from</param>\n        /// <returns>The JSON value object created from the input stream.</returns>\n        _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input);\n\n        /// <summary>\n        /// Parses a JSON value from the contents of an input stream using the native platform character width.\n        /// </summary>\n        /// <param name=\"input\">The stream to read the JSON value from</param>\n        /// <param name=\"errorCode\">If parsing fails, the error code is greater than 0</param>\n        /// <returns>The parsed object. Returns web::json::value::null if failed</returns>\n        _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input, std::error_code &errorCode);\n\n        /// <summary>\n        /// Writes the current JSON value to a stream with the native platform character width.\n        /// </summary>\n        /// <param name=\"stream\">The stream that the JSON string representation should be written to.</param>\n        _ASYNCRTIMP void serialize(utility::ostream_t &stream) const;\n\n#ifdef _WIN32\n        /// <summary>\n        /// Parses a JSON value from the contents of a single-byte (UTF8) stream.\n        /// </summary>\n        /// <param name=\"stream\">The stream to read the JSON value from</param>\n        _ASYNCRTIMP static value __cdecl parse(std::istream& stream);\n\n        /// <summary>\n        /// Parses a JSON value from the contents of a single-byte (UTF8) stream.\n        /// </summary>\n        /// <param name=\"stream\">The stream to read the JSON value from</param>\n        /// <param name=\"errorCode\">If parsing fails, the error code is greater than 0</param>\n        /// <returns>The parsed object. Returns web::json::value::null if failed</returns>\n        _ASYNCRTIMP static value __cdecl parse(std::istream& stream, std::error_code& error);\n\n        /// <summary>\n        /// Serializes the content of the value into a single-byte (UTF8) stream.\n        /// </summary>\n        /// <param name=\"stream\">The stream that the JSON string representation should be written to.</param>\n        _ASYNCRTIMP void serialize(std::ostream& stream) const;\n#endif\n\n        /// <summary>\n        /// Converts the JSON value to a C++ double, if and only if it is a number value.\n        /// Throws json_exception if the value is not a number\n        /// </summary>\n        /// <returns>A double representation of the value</returns>\n        _ASYNCRTIMP double as_double() const;\n\n        /// <summary>\n        /// Converts the JSON value to a C++ integer, if and only if it is a number value.\n        /// Throws json_exception if the value is not a number\n        /// </summary>\n        /// <returns>An integer representation of the value</returns>\n        _ASYNCRTIMP int as_integer() const;\n\n        /// <summary>\n        /// Converts the JSON value to a number class, if and only if it is a number value.\n        /// Throws json_exception if the value is not a number\n        /// </summary>\n        /// <returns>An instance of number class</returns>\n        _ASYNCRTIMP const json::number& as_number() const;\n\n        /// <summary>\n        /// Converts the JSON value to a C++ bool, if and only if it is a Boolean value.\n        /// </summary>\n        /// <returns>A C++ bool representation of the value</returns>\n        _ASYNCRTIMP bool as_bool() const;\n\n        /// <summary>\n        /// Converts the JSON value to a json array, if and only if it is an array value.\n        /// </summary>\n        /// <remarks>The returned <c>json::array</c> should have the same or shorter lifetime as <c>this</c></remarks>\n        /// <returns>An array representation of the value</returns>\n        _ASYNCRTIMP json::array& as_array();\n\n        /// <summary>\n        /// Converts the JSON value to a json array, if and only if it is an array value.\n        /// </summary>\n        /// <remarks>The returned <c>json::array</c> should have the same or shorter lifetime as <c>this</c></remarks>\n        /// <returns>An array representation of the value</returns>\n        _ASYNCRTIMP const json::array& as_array() const;\n\n        /// <summary>\n        /// Converts the JSON value to a json object, if and only if it is an object value.\n        /// </summary>\n        /// <returns>An object representation of the value</returns>\n        _ASYNCRTIMP json::object& as_object();\n\n        /// <summary>\n        /// Converts the JSON value to a json object, if and only if it is an object value.\n        /// </summary>\n        /// <returns>An object representation of the value</returns>\n        _ASYNCRTIMP const json::object& as_object() const;\n\n        /// <summary>\n        /// Converts the JSON value to a C++ STL string, if and only if it is a string value.\n        /// </summary>\n        /// <returns>A C++ STL string representation of the value</returns>\n        _ASYNCRTIMP const utility::string_t& as_string() const;\n\n        /// <summary>\n        /// Compares two JSON values for equality.\n        /// </summary>\n        /// <param name=\"other\">The JSON value to compare with.</param>\n        /// <returns>True iff the values are equal.</returns>\n        _ASYNCRTIMP bool operator==(const value& other) const;\n\n        /// <summary>\n        /// Compares two JSON values for inequality.\n        /// </summary>\n        /// <param name=\"other\">The JSON value to compare with.</param>\n        /// <returns>True iff the values are unequal.</returns>\n        bool operator!=(const value& other) const\n        {\n            return !((*this) == other);\n        }\n\n        /// <summary>\n        /// Tests for the presence of a field.\n        /// </summary>\n        /// <param name=\"key\">The name of the field</param>\n        /// <returns>True if the field exists, false otherwise.</returns>\n        bool has_field(const utility::string_t &key) const;\n\n        /// <summary>\n        /// Accesses a field of a JSON object.\n        /// </summary>\n        /// <param name=\"key\">The name of the field</param>\n        /// <returns>The value kept in the field; null if the field does not exist</returns>\n        CASABLANCA_DEPRECATED(\"This API is deprecated and will be removed in a future release, use json::value::at() instead.\")\n        value get(const utility::string_t &key) const;\n\n        /// <summary>\n        /// Erases an element of a JSON array. Throws if index is out of bounds.\n        /// </summary>\n        /// <param name=\"index\">The index of the element to erase in the JSON array.</param>\n        _ASYNCRTIMP void erase(size_t index);\n\n        /// <summary>\n        /// Erases an element of a JSON object. Throws if the key doesn't exist.\n        /// </summary>\n        /// <param name=\"key\">The key of the element to erase in the JSON object.</param>\n        _ASYNCRTIMP void erase(const utility::string_t &key);\n\n        /// <summary>\n        /// Accesses an element of a JSON array. Throws when index out of bounds.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array.</param>\n        /// <returns>A reference to the value.</returns>\n        _ASYNCRTIMP json::value& at(size_t index);\n\n        /// <summary>\n        /// Accesses an element of a JSON array. Throws when index out of bounds.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array.</param>\n        /// <returns>A reference to the value.</returns>\n        _ASYNCRTIMP const json::value& at(size_t index) const;\n\n        /// <summary>\n        /// Accesses an element of a JSON object. If the key doesn't exist, this method throws.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        /// <returns>If the key exists, a reference to the value.</returns>\n        _ASYNCRTIMP json::value& at(const utility::string_t& key);\n\n        /// <summary>\n        /// Accesses an element of a JSON object. If the key doesn't exist, this method throws.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        /// <returns>If the key exists, a reference to the value.</returns>\n        _ASYNCRTIMP const json::value& at(const utility::string_t& key) const;\n\n        /// <summary>\n        /// Accesses a field of a JSON object.\n        /// </summary>\n        /// <param name=\"key\">The name of the field</param>\n        /// <returns>A reference to the value kept in the field.</returns>\n        _ASYNCRTIMP value & operator [] (const utility::string_t &key);\n\n#ifdef _WIN32\nprivate:\n        // Only used internally by JSON parser\n        _ASYNCRTIMP value & operator [] (const std::string &key)\n        {\n            // JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid\n            return operator[](utility::conversions::to_string_t(key));\n        }\npublic:\n#endif\n\n        /// <summary>\n        /// Accesses an element of a JSON array.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array</param>\n        /// <returns>The value kept at the array index; null if outside the boundaries of the array</returns>\n        CASABLANCA_DEPRECATED(\"This API is deprecated and will be removed in a future release, use json::value::at() instead.\")\n        value get(size_t index) const;\n\n        /// <summary>\n        /// Accesses an element of a JSON array.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array.</param>\n        /// <returns>A reference to the value kept in the field.</returns>\n        _ASYNCRTIMP value & operator [] (size_t index);\n\n    private:\n        friend class web::json::details::_Object;\n        friend class web::json::details::_Array;\n        template<typename CharType> friend class web::json::details::JSON_Parser;\n\n#ifdef _WIN32\n        /// <summary>\n        /// Writes the current JSON value as a double-byte string to a string instance.\n        /// </summary>\n        /// <param name=\"string\">The string that the JSON representation should be written to.</param>\n        _ASYNCRTIMP void format(std::basic_string<utf16char> &string) const;\n#endif\n        /// <summary>\n        /// Serializes the content of the value into a string instance in UTF8 format\n        /// </summary>\n        /// <param name=\"string\">The string that the JSON representation should be written to</param>\n        _ASYNCRTIMP void format(std::basic_string<char>& string) const;\n\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        explicit value(std::unique_ptr<details::_Value> v, value_type kind) : m_value(std::move(v)), m_kind(kind)\n#else\n        explicit value(std::unique_ptr<details::_Value> v) : m_value(std::move(v))\n#endif\n        {}\n\n        std::unique_ptr<details::_Value> m_value;\n#ifdef ENABLE_JSON_VALUE_VISUALIZER\n        value_type m_kind;\n#endif\n    };\n\n    /// <summary>\n    /// A single exception type to represent errors in parsing, converting, and accessing\n    /// elements of JSON values.\n    /// </summary>\n    class json_exception : public std::exception\n    {\n    private:\n        std::string _message;\n    public:\n        json_exception(const utility::char_t * const &message) : _message(utility::conversions::to_utf8string(message)) { }\n\n        // Must be narrow string because it derives from std::exception\n        const char* what() const CPPREST_NOEXCEPT\n        {\n            return _message.c_str();\n        }\n    };\n\n    namespace details\n    {\n        enum json_error\n        {\n            left_over_character_in_stream = 1,\n            malformed_array_literal,\n            malformed_comment,\n            malformed_literal,\n            malformed_object_literal,\n            malformed_numeric_literal,\n            malformed_string_literal,\n            malformed_token,\n            mismatched_brances,\n            nesting,\n            unexpected_token\n        };\n\n        class json_error_category_impl : public std::error_category\n        {\n        public:\n            virtual const char* name() const CPPREST_NOEXCEPT override\n            {\n                return \"json\";\n            }\n\n            virtual std::string message(int ev) const override\n            {\n                switch (ev)\n                {\n                case json_error::left_over_character_in_stream:\n                    return \"Left-over characters in stream after parsing a JSON value\";\n                case json_error::malformed_array_literal:\n                    return \"Malformed array literal\";\n                case json_error::malformed_comment:\n                    return \"Malformed comment\";\n                case json_error::malformed_literal:\n                    return \"Malformed literal\";\n                case json_error::malformed_object_literal:\n                    return \"Malformed object literal\";\n                case json_error::malformed_numeric_literal:\n                    return \"Malformed numeric literal\";\n                case json_error::malformed_string_literal:\n                    return \"Malformed string literal\";\n                case json_error::malformed_token:\n                    return \"Malformed token\";\n                case json_error::mismatched_brances:\n                    return \"Mismatched braces\";\n                case json_error::nesting:\n                    return \"Nesting too deep\";\n                case json_error::unexpected_token:\n                    return \"Unexpected token\";\n                default:\n                    return \"Unknown json error\";\n                }\n            }\n        };\n\n        const json_error_category_impl& json_error_category();\n    }\n\n    /// <summary>\n    /// A JSON array represented as a C++ class.\n    /// </summary>\n    class array\n    {\n        typedef std::vector<json::value> storage_type;\n\n    public:\n        typedef storage_type::iterator iterator;\n        typedef storage_type::const_iterator const_iterator;\n        typedef storage_type::reverse_iterator reverse_iterator;\n        typedef storage_type::const_reverse_iterator const_reverse_iterator;\n        typedef storage_type::size_type size_type;\n\n    private:\n        array() : m_elements() { }\n        array(size_type size) : m_elements(size) { }\n        array(storage_type elements) : m_elements(std::move(elements)) { }\n\n    public:\n        /// <summary>\n        /// Gets the beginning iterator element of the array\n        /// </summary>\n        /// <returns>An <c>iterator</c> to the beginning of the JSON array.</returns>\n        iterator begin()\n        {\n            return m_elements.begin();\n        }\n\n        /// <summary>\n        /// Gets the beginning const iterator element of the array.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the beginning of the JSON array.</returns>\n        const_iterator begin() const\n        {\n            return m_elements.cbegin();\n        }\n\n        /// <summary>\n        /// Gets the end iterator element of the array\n        /// </summary>\n        /// <returns>An <c>iterator</c> to the end of the JSON array.</returns>\n        iterator end()\n        {\n            return m_elements.end();\n        }\n\n        /// <summary>\n        /// Gets the end const iterator element of the array.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the end of the JSON array.</returns>\n        const_iterator end() const\n        {\n            return m_elements.cend();\n        }\n\n        /// <summary>\n        /// Gets the beginning reverse iterator element of the array\n        /// </summary>\n        /// <returns>An <c>reverse_iterator</c> to the beginning of the JSON array.</returns>\n        reverse_iterator rbegin()\n        {\n            return m_elements.rbegin();\n        }\n\n        /// <summary>\n        /// Gets the beginning const reverse iterator element of the array\n        /// </summary>\n        /// <returns>An <c>const_reverse_iterator</c> to the beginning of the JSON array.</returns>\n        const_reverse_iterator rbegin() const\n        {\n            return m_elements.rbegin();\n        }\n\n        /// <summary>\n        /// Gets the end reverse iterator element of the array\n        /// </summary>\n        /// <returns>An <c>reverse_iterator</c> to the end of the JSON array.</returns>\n        reverse_iterator rend()\n        {\n            return m_elements.rend();\n        }\n\n        /// <summary>\n        /// Gets the end const reverse iterator element of the array\n        /// </summary>\n        /// <returns>An <c>const_reverse_iterator</c> to the end of the JSON array.</returns>\n        const_reverse_iterator rend() const\n        {\n            return m_elements.crend();\n        }\n\n        /// <summary>\n        /// Gets the beginning const iterator element of the array.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the beginning of the JSON array.</returns>\n        const_iterator cbegin() const\n        {\n            return m_elements.cbegin();\n        }\n\n        /// <summary>\n        /// Gets the end const iterator element of the array.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the end of the JSON array.</returns>\n        const_iterator cend() const\n        {\n            return m_elements.cend();\n        }\n\n        /// <summary>\n        /// Gets the beginning const reverse iterator element of the array.\n        /// </summary>\n        /// <returns>A <c>const_reverse_iterator</c> to the beginning of the JSON array.</returns>\n        const_reverse_iterator crbegin() const\n        {\n            return m_elements.crbegin();\n        }\n\n        /// <summary>\n        /// Gets the end const reverse iterator element of the array.\n        /// </summary>\n        /// <returns>A <c>const_reverse_iterator</c> to the end of the JSON array.</returns>\n        const_reverse_iterator crend() const\n        {\n            return m_elements.crend();\n        }\n\n        /// <summary>\n        /// Deletes an element of the JSON array.\n        /// </summary>\n        /// <param name=\"position\">A const_iterator to the element to delete.</param>\n        /// <returns>Iterator to the new location of the element following the erased element.</returns>\n        /// <remarks>GCC doesn't support erase with const_iterator on vector yet. In the future this should be changed.</remarks>\n        iterator erase(iterator position)\n        {\n            return m_elements.erase(position);\n        }\n\n        /// <summary>\n        /// Deletes the element at an index of the JSON array.\n        /// </summary>\n        /// <param name=\"index\">The index of the element to delete.</param>\n        void erase(size_type index)\n        {\n            if (index >= m_elements.size())\n            {\n                throw json_exception(_XPLATSTR(\"index out of bounds\"));\n            }\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning(push)\n#pragma warning(disable: 4365)\n#endif\n            m_elements.erase(m_elements.begin() + static_cast<std::vector<json::value>::size_type>(index));\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning( pop ) \n#endif\n        }\n\n        /// <summary>\n        /// Accesses an element of a JSON array. Throws when index out of bounds.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array.</param>\n        /// <returns>A reference to the value kept in the field.</returns>\n        json::value& at(size_type index)\n        {\n            if (index >= m_elements.size())\n                throw json_exception(_XPLATSTR(\"index out of bounds\"));\n\n            return m_elements[index];\n        }\n\n        /// <summary>\n        /// Accesses an element of a JSON array. Throws when index out of bounds.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array.</param>\n        /// <returns>A reference to the value kept in the field.</returns>\n        const json::value& at(size_type index) const\n        {\n            if (index >= m_elements.size())\n                throw json_exception(_XPLATSTR(\"index out of bounds\"));\n\n            return m_elements[index];\n        }\n\n        /// <summary>\n        /// Accesses an element of a JSON array.\n        /// </summary>\n        /// <param name=\"index\">The index of an element in the JSON array.</param>\n        /// <returns>A reference to the value kept in the field.</returns>\n        json::value& operator[](size_type index)\n        {\n            msl::safeint3::SafeInt<size_type> nMinSize(index);\n            nMinSize += 1;\n            msl::safeint3::SafeInt<size_type> nlastSize(m_elements.size());\n            if (nlastSize < nMinSize)\n                m_elements.resize(nMinSize);\n\n            return m_elements[index];\n        }\n\n        /// <summary>\n        /// Gets the number of elements of the array.\n        /// </summary>\n        /// <returns>The number of elements.</returns>\n        size_type size() const\n        {\n            return m_elements.size();\n        }\n\n    private:\n        storage_type m_elements;\n\n        friend class details::_Array;\n        template<typename CharType> friend class json::details::JSON_Parser;\n    };\n\n    /// <summary>\n    /// A JSON object represented as a C++ class.\n    /// </summary>\n    class object\n    {\n        typedef std::vector<std::pair<utility::string_t, json::value>> storage_type;\n\n    public:\n        typedef storage_type::iterator iterator;\n        typedef storage_type::const_iterator const_iterator;\n        typedef storage_type::reverse_iterator reverse_iterator;\n        typedef storage_type::const_reverse_iterator const_reverse_iterator;\n        typedef storage_type::size_type size_type;\n\n    private:\n        object(bool keep_order = false) : m_elements(), m_keep_order(keep_order) { }\n        object(storage_type elements, bool keep_order = false) : m_elements(std::move(elements)), m_keep_order(keep_order)\n        {\n            if (!keep_order) {\n                sort(m_elements.begin(), m_elements.end(), compare_pairs);\n            }\n        }\n\n    public:\n        /// <summary>\n        /// Gets the beginning iterator element of the object\n        /// </summary>\n        /// <returns>An <c>iterator</c> to the beginning of the JSON object.</returns>\n        iterator begin()\n        {\n            return m_elements.begin();\n        }\n\n        /// <summary>\n        /// Gets the beginning const iterator element of the object.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the beginning of the JSON object.</returns>\n        const_iterator begin() const\n        {\n            return m_elements.cbegin();\n        }\n\n        /// <summary>\n        /// Gets the end iterator element of the object\n        /// </summary>\n        /// <returns>An <c>iterator</c> to the end of the JSON object.</returns>\n        iterator end()\n        {\n            return m_elements.end();\n        }\n\n        /// <summary>\n        /// Gets the end const iterator element of the object.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the end of the JSON object.</returns>\n        const_iterator end() const\n        {\n            return m_elements.cend();\n        }\n\n        /// <summary>\n        /// Gets the beginning reverse iterator element of the object\n        /// </summary>\n        /// <returns>An <c>reverse_iterator</c> to the beginning of the JSON object.</returns>\n        reverse_iterator rbegin()\n        {\n            return m_elements.rbegin();\n        }\n\n        /// <summary>\n        /// Gets the beginning const reverse iterator element of the object\n        /// </summary>\n        /// <returns>An <c>const_reverse_iterator</c> to the beginning of the JSON object.</returns>\n        const_reverse_iterator rbegin() const\n        {\n            return m_elements.rbegin();\n        }\n\n        /// <summary>\n        /// Gets the end reverse iterator element of the object\n        /// </summary>\n        /// <returns>An <c>reverse_iterator</c> to the end of the JSON object.</returns>\n        reverse_iterator rend()\n        {\n            return m_elements.rend();\n        }\n\n        /// <summary>\n        /// Gets the end const reverse iterator element of the object\n        /// </summary>\n        /// <returns>An <c>const_reverse_iterator</c> to the end of the JSON object.</returns>\n        const_reverse_iterator rend() const\n        {\n            return m_elements.crend();\n        }\n\n        /// <summary>\n        /// Gets the beginning const iterator element of the object.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the beginning of the JSON object.</returns>\n        const_iterator cbegin() const\n        {\n            return m_elements.cbegin();\n        }\n\n        /// <summary>\n        /// Gets the end const iterator element of the object.\n        /// </summary>\n        /// <returns>A <c>const_iterator</c> to the end of the JSON object.</returns>\n        const_iterator cend() const\n        {\n            return m_elements.cend();\n        }\n\n        /// <summary>\n        /// Gets the beginning const reverse iterator element of the object.\n        /// </summary>\n        /// <returns>A <c>const_reverse_iterator</c> to the beginning of the JSON object.</returns>\n        const_reverse_iterator crbegin() const\n        {\n            return m_elements.crbegin();\n        }\n\n        /// <summary>\n        /// Gets the end const reverse iterator element of the object.\n        /// </summary>\n        /// <returns>A <c>const_reverse_iterator</c> to the end of the JSON object.</returns>\n        const_reverse_iterator crend() const\n        {\n            return m_elements.crend();\n        }\n\n        /// <summary>\n        /// Deletes an element of the JSON object.\n        /// </summary>\n        /// <param name=\"position\">A const_iterator to the element to delete.</param>\n        /// <returns>Iterator to the new location of the element following the erased element.</returns>\n        /// <remarks>GCC doesn't support erase with const_iterator on vector yet. In the future this should be changed.</remarks>\n        iterator erase(iterator position)\n        {\n            return m_elements.erase(position);\n        }\n\n        /// <summary>\n        /// Deletes an element of the JSON object. If the key doesn't exist, this method throws.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        void erase(const utility::string_t &key)\n        {\n            auto iter = find_by_key(key);\n            if (iter == m_elements.end())\n            {\n                throw web::json::json_exception(_XPLATSTR(\"Key not found\"));\n            }\n\n            m_elements.erase(iter);\n        }\n\n        /// <summary>\n        /// Accesses an element of a JSON object. If the key doesn't exist, this method throws.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        /// <returns>If the key exists, a reference to the value kept in the field.</returns>\n        json::value& at(const utility::string_t& key)\n        {\n            auto iter = find_by_key(key);\n            if (iter == m_elements.end())\n            {\n                throw web::json::json_exception(_XPLATSTR(\"Key not found\"));\n            }\n\n            return iter->second;\n        }\n\n        /// <summary>\n        /// Accesses an element of a JSON object. If the key doesn't exist, this method throws.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        /// <returns>If the key exists, a reference to the value kept in the field.</returns>\n        const json::value& at(const utility::string_t& key) const\n        {\n            auto iter = find_by_key(key);\n            if (iter == m_elements.end())\n            {\n                throw web::json::json_exception(_XPLATSTR(\"Key not found\"));\n            }\n\n            return iter->second;\n        }\n\n        /// <summary>\n        /// Accesses an element of a JSON object.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        /// <returns>If the key exists, a reference to the value kept in the field, otherwise a newly created null value that will be stored for the given key.</returns>\n        json::value& operator[](const utility::string_t& key)\n        {\n            auto iter = find_insert_location(key);\n\n            if (iter == m_elements.end() || key != iter->first)\n            {\n                return m_elements.insert(iter, std::pair<utility::string_t, value>(key, value()))->second;\n            }\n\n            return iter->second;\n        }\n\n        /// <summary>\n        /// Gets an iterator to an element of a JSON object.\n        /// </summary>\n        /// <param name=\"key\">The key of an element in the JSON object.</param>\n        /// <returns>A const iterator to the value kept in the field.</returns>\n        const_iterator find(const utility::string_t& key) const\n        {\n            return find_by_key(key);\n        }\n\n        /// <summary>\n        /// Gets the number of elements of the object.\n        /// </summary>\n        /// <returns>The number of elements.</returns>\n        size_type size() const\n        {\n            return m_elements.size();\n        }\n\n        /// <summary>\n        /// Checks if there are any elements in the JSON object.\n        /// </summary>\n        /// <returns>True iff empty.</returns>\n        bool empty() const\n        {\n            return m_elements.empty();\n        }\n    private:\n\n        static bool compare_pairs(const std::pair<utility::string_t, value>& p1, const std::pair<utility::string_t, value>& p2)\n        {\n            return p1.first < p2.first;\n        }\n        static bool compare_with_key(const std::pair<utility::string_t, value>& p1, const utility::string_t& key)\n        {\n            return p1.first < key;\n        }\n\n        storage_type::iterator find_insert_location(const utility::string_t &key)\n        {\n            if (m_keep_order)\n            {\n                return std::find_if(m_elements.begin(), m_elements.end(),\n                    [&key](const std::pair<utility::string_t, value>& p) {\n                    return p.first == key;\n                });\n            }\n            else\n            {\n                return std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key);\n            }\n        }\n\n        storage_type::const_iterator find_by_key(const utility::string_t& key) const\n        {\n            if (m_keep_order)\n            {\n                return std::find_if(m_elements.begin(), m_elements.end(),\n                    [&key](const std::pair<utility::string_t, value>& p) {\n                    return p.first == key;\n                });\n            }\n            else\n            {\n                auto iter = std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key);\n                if (iter != m_elements.end() && key != iter->first)\n                {\n                    return m_elements.end();\n                }\n                return iter;\n            }\n        }\n\n        storage_type::iterator find_by_key(const utility::string_t& key)\n        {\n            auto iter = find_insert_location(key);\n            if (iter != m_elements.end() && key != iter->first)\n            {\n                return m_elements.end();\n            }\n            return iter;\n        }\n\n        storage_type m_elements;\n        bool m_keep_order;\n        friend class details::_Object;\n\n        template<typename CharType> friend class json::details::JSON_Parser;\n   };\n\n    /// <summary>\n    /// A JSON number represented as a C++ class.\n    /// </summary>\n    class number\n    {\n        // Note that these constructors make sure that only negative integers are stored as signed int64 (while others convert to unsigned int64).\n        // This helps handling number objects e.g. comparing two numbers.\n\n        number(double value)  : m_value(value), m_type(double_type) { }\n        number(int32_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) { }\n        number(uint32_t value) : m_intval(value), m_type(unsigned_type) { }\n        number(int64_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) { }\n        number(uint64_t value) : m_uintval(value), m_type(unsigned_type) { }\n\n    public:\n\n        /// <summary>\n        /// Does the number fit into int32?\n        /// </summary>\n        /// <returns><c>true</c> if the number fits into int32, <c>false</c> otherwise</returns>\n        _ASYNCRTIMP bool is_int32() const;\n\n        /// <summary>\n        /// Does the number fit into unsigned int32?\n        /// </summary>\n        /// <returns><c>true</c> if the number fits into unsigned int32, <c>false</c> otherwise</returns>\n        _ASYNCRTIMP bool is_uint32() const;\n\n        /// <summary>\n        /// Does the number fit into int64?\n        /// </summary>\n        /// <returns><c>true</c> if the number fits into int64, <c>false</c> otherwise</returns>\n        _ASYNCRTIMP bool is_int64() const;\n\n        /// <summary>\n        /// Does the number fit into unsigned int64?\n        /// </summary>\n        /// <returns><c>true</c> if the number fits into unsigned int64, <c>false</c> otherwise</returns>\n        bool is_uint64() const\n        {\n            switch (m_type)\n            {\n            case signed_type : return m_intval >= 0;\n            case unsigned_type : return true;\n            case double_type :\n            default :\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Converts the JSON number to a C++ double.\n        /// </summary>\n        /// <returns>A double representation of the number</returns>\n        double to_double() const\n        {\n            switch (m_type)\n            {\n            case double_type : return m_value;\n            case signed_type : return static_cast<double>(m_intval);\n            case unsigned_type : return static_cast<double>(m_uintval);\n            default : return false;\n            }\n        }\n\n        /// <summary>\n        /// Converts the JSON number to int32.\n        /// </summary>\n        /// <returns>An int32 representation of the number</returns>\n        int32_t to_int32() const\n        {\n            if (m_type == double_type)\n                return static_cast<int32_t>(m_value);\n            else\n                return static_cast<int32_t>(m_intval);\n        }\n\n        /// <summary>\n        /// Converts the JSON number to unsigned int32.\n        /// </summary>\n        /// <returns>An usigned int32 representation of the number</returns>\n        uint32_t to_uint32() const\n        {\n            if (m_type == double_type)\n                return static_cast<uint32_t>(m_value);\n            else\n                return static_cast<uint32_t>(m_intval);\n        }\n\n        /// <summary>\n        /// Converts the JSON number to int64.\n        /// </summary>\n        /// <returns>An int64 representation of the number</returns>\n        int64_t to_int64() const\n        {\n            if (m_type == double_type)\n                return static_cast<int64_t>(m_value);\n            else\n                return static_cast<int64_t>(m_intval);\n        }\n\n        /// <summary>\n        /// Converts the JSON number to unsigned int64.\n        /// </summary>\n        /// <returns>An unsigned int64 representation of the number</returns>\n        uint64_t to_uint64() const\n        {\n            if (m_type == double_type)\n                return static_cast<uint64_t>(m_value);\n            else\n                return static_cast<uint64_t>(m_intval);\n        }\n\n        /// <summary>\n        /// Is the number represented internally as an integral type?\n        /// </summary>\n        /// <returns><c>true</c> if the number is represented as an integral type, <c>false</c> otherwise</returns>\n        bool is_integral() const\n        {\n            return m_type != double_type;\n        }\n\n        /// <summary>\n        /// Compares two JSON numbers for equality.\n        /// </summary>\n        /// <param name=\"other\">The JSON number to compare with.</param>\n        /// <returns>True iff the numbers are equal.</returns>\n        bool operator==(const number &other) const\n        {\n            if (m_type != other.m_type)\n                return false;\n\n            switch (m_type)\n            {\n            case json::number::type::signed_type :\n                return m_intval == other.m_intval;\n            case json::number::type::unsigned_type :\n                return m_uintval == other.m_uintval;\n            case json::number::type::double_type :\n                return m_value == other.m_value;\n            }\n            __assume(0);\n        }\n\n    private:\n        union\n        {\n            int64_t m_intval;\n            uint64_t m_uintval;\n            double  m_value;\n        };\n\n        enum type\n        {\n            signed_type=0, unsigned_type, double_type\n        } m_type;\n\n        friend class details::_Number;\n    };\n\n    namespace details\n    {\n        class _Value\n        {\n        public:\n            virtual std::unique_ptr<_Value> _copy_value() = 0;\n\n            virtual bool has_field(const utility::string_t &) const { return false; }\n            virtual value get_field(const utility::string_t &) const { throw json_exception(_XPLATSTR(\"not an object\")); }\n            virtual value get_element(array::size_type) const { throw json_exception(_XPLATSTR(\"not an array\")); }\n\n            virtual value &index(const utility::string_t &) { throw json_exception(_XPLATSTR(\"not an object\")); }\n            virtual value &index(array::size_type) { throw json_exception(_XPLATSTR(\"not an array\")); }\n\n            virtual const value &cnst_index(const utility::string_t &) const { throw json_exception(_XPLATSTR(\"not an object\")); }\n            virtual const value &cnst_index(array::size_type) const { throw json_exception(_XPLATSTR(\"not an array\")); }\n\n            // Common function used for serialization to strings and streams.\n            virtual void serialize_impl(std::string& str) const\n            {\n                format(str);\n            }\n#ifdef _WIN32\n            virtual void serialize_impl(std::wstring& str) const\n            {\n                format(str);\n            }\n#endif\n\n            virtual utility::string_t to_string() const\n            {\n                utility::string_t str;\n                serialize_impl(str);\n                return str;\n            }\n\n            virtual json::value::value_type type() const { return json::value::Null; }\n\n            virtual bool is_integer() const { throw json_exception(_XPLATSTR(\"not a number\")); }\n            virtual bool is_double() const { throw json_exception(_XPLATSTR(\"not a number\")); }\n\n            virtual const json::number& as_number() { throw json_exception(_XPLATSTR(\"not a number\")); }\n            virtual double as_double() const { throw json_exception(_XPLATSTR(\"not a number\")); }\n            virtual int as_integer() const { throw json_exception(_XPLATSTR(\"not a number\")); }\n            virtual bool as_bool() const { throw json_exception(_XPLATSTR(\"not a boolean\")); }\n            virtual json::array& as_array() { throw json_exception(_XPLATSTR(\"not an array\")); }\n            virtual const json::array& as_array() const { throw json_exception(_XPLATSTR(\"not an array\")); }\n            virtual json::object& as_object() { throw json_exception(_XPLATSTR(\"not an object\")); }\n            virtual const json::object& as_object() const { throw json_exception(_XPLATSTR(\"not an object\")); }\n            virtual const utility::string_t& as_string() const { throw json_exception(_XPLATSTR(\"not a string\")); }\n\n            virtual size_t size() const { return 0; }\n\n            virtual ~_Value() {}\n\n        protected:\n            _Value() {}\n\n            virtual void format(std::basic_string<char>& stream) const\n            {\n                stream.append(\"null\");\n            }\n#ifdef _WIN32\n            virtual void format(std::basic_string<wchar_t>& stream) const\n            {\n                stream.append(L\"null\");\n            }\n#endif\n        private:\n\n            friend class web::json::value;\n        };\n\n        class _Null : public _Value\n        {\n        public:\n            virtual std::unique_ptr<_Value> _copy_value()\n            {\n                return utility::details::make_unique<_Null>();\n            }\n            virtual json::value::value_type type() const { return json::value::Null; }\n        };\n\n        class _Number : public _Value\n        {\n        public:\n            _Number(double value)  : m_number(value) { }\n            _Number(int32_t value) : m_number(value) { }\n            _Number(uint32_t value) : m_number(value) { }\n            _Number(int64_t value) : m_number(value) { }\n            _Number(uint64_t value) : m_number(value) { }\n\n            virtual std::unique_ptr<_Value> _copy_value()\n            {\n                return utility::details::make_unique<_Number>(*this);\n            }\n\n            virtual json::value::value_type type() const { return json::value::Number; }\n\n            virtual bool is_integer() const { return m_number.is_integral(); }\n            virtual bool is_double() const { return !m_number.is_integral(); }\n\n            virtual double as_double() const\n            {\n                return m_number.to_double();\n            }\n\n            virtual int as_integer() const\n            {\n                return m_number.to_int32();\n            }\n\n            virtual const number& as_number() { return m_number; }\n\n        protected:\n            virtual void format(std::basic_string<char>& stream) const ;\n#ifdef _WIN32\n            virtual void format(std::basic_string<wchar_t>& stream) const;\n#endif\n        private:\n            template<typename CharType> friend class json::details::JSON_Parser;\n\n            json::number m_number;\n        };\n\n        class _Boolean : public _Value\n        {\n        public:\n            _Boolean(bool value) : m_value(value) { }\n\n            virtual std::unique_ptr<_Value> _copy_value()\n            {\n                return utility::details::make_unique<_Boolean>(*this);\n            }\n\n            virtual json::value::value_type type() const { return json::value::Boolean; }\n\n            virtual bool as_bool() const { return m_value; }\n\n        protected:\n            virtual void format(std::basic_string<char>& stream) const\n            {\n                stream.append(m_value ? \"true\" : \"false\");\n            }\n\n#ifdef _WIN32\n            virtual void format(std::basic_string<wchar_t>& stream) const\n            {\n                stream.append(m_value ? L\"true\" : L\"false\");\n            }\n#endif\n        private:\n            template<typename CharType> friend class json::details::JSON_Parser;\n            bool m_value;\n        };\n\n        class _String : public _Value\n        {\n        public:\n\n            _String(utility::string_t value) : m_string(std::move(value))\n            {\n                m_has_escape_char = has_escape_chars(*this);\n            }\n            _String(utility::string_t value, bool escaped_chars)\n                : m_string(std::move(value)),\n                  m_has_escape_char(escaped_chars)\n            { }\n\n#ifdef _WIN32\n            _String(std::string &&value) : m_string(utility::conversions::to_utf16string(std::move(value)))\n            {\n                m_has_escape_char = has_escape_chars(*this);\n            }\n            _String(std::string &&value, bool escape_chars)\n                : m_string(utility::conversions::to_utf16string(std::move(value))),\n                  m_has_escape_char(escape_chars)\n            { }\n#endif\n\n            virtual std::unique_ptr<_Value> _copy_value()\n            {\n                return utility::details::make_unique<_String>(*this);\n            }\n\n            virtual json::value::value_type type() const { return json::value::String; }\n\n            virtual const utility::string_t & as_string() const;\n\n            virtual void serialize_impl(std::string& str) const\n            {\n                 serialize_impl_char_type(str);\n            }\n#ifdef _WIN32\n            virtual void serialize_impl(std::wstring& str) const\n            {\n                serialize_impl_char_type(str);\n            }\n#endif\n\n        protected:\n            virtual void format(std::basic_string<char>& str) const;\n#ifdef _WIN32\n            virtual void format(std::basic_string<wchar_t>& str) const;\n#endif\n\n        private:\n            friend class _Object;\n            friend class _Array;\n\n            size_t get_reserve_size() const\n            {\n                return m_string.size() + 2;\n            }\n\n            template <typename CharType>\n            void serialize_impl_char_type(std::basic_string<CharType>& str) const\n            {\n                // To avoid repeated allocations reserve some space all up front.\n                // size of string + 2 for quotes\n                str.reserve(get_reserve_size());\n                format(str);\n            }\n\n            std::string as_utf8_string() const;\n            utf16string as_utf16_string() const;\n\n            utility::string_t m_string;\n\n            // There are significant performance gains that can be made by knowning whether\n            // or not a character that requires escaping is present.\n            bool m_has_escape_char;\n            static bool has_escape_chars(const _String &str);\n        };\n\n        template<typename CharType>\n        _ASYNCRTIMP void append_escape_string(std::basic_string<CharType>& str, const std::basic_string<CharType>& escaped);\n\n        void format_string(const utility::string_t& key, utility::string_t& str);\n\n#ifdef _WIN32\n        void format_string(const utility::string_t& key, std::string& str);\n#endif\n\n        class _Object : public _Value\n        {\n        public:\n\n            _Object(bool keep_order) : m_object(keep_order) { }\n            _Object(object::storage_type fields, bool keep_order) : m_object(std::move(fields), keep_order) { }\n\n            virtual std::unique_ptr<_Value> _copy_value()\n            {\n                return utility::details::make_unique<_Object>(*this);\n            }\n\n            virtual json::object& as_object() { return m_object; }\n\n            virtual const json::object& as_object() const { return m_object; }\n\n            virtual json::value::value_type type() const { return json::value::Object; }\n\n            virtual bool has_field(const utility::string_t &) const;\n\n            virtual json::value &index(const utility::string_t &key);\n\n            bool is_equal(const _Object* other) const\n            {\n                if (m_object.size() != other->m_object.size())\n                    return false;\n\n                return std::equal(std::begin(m_object), std::end(m_object), std::begin(other->m_object));\n            }\n\n            virtual void serialize_impl(std::string& str) const\n            {\n                // To avoid repeated allocations reserve some space all up front.\n                str.reserve(get_reserve_size());\n                format(str);\n            }\n#ifdef _WIN32\n            virtual void serialize_impl(std::wstring& str) const\n            {\n                // To avoid repeated allocations reserve some space all up front.\n                str.reserve(get_reserve_size());\n                format(str);\n            }\n#endif\n            size_t size() const { return m_object.size(); }\n\n        protected:\n            virtual void format(std::basic_string<char>& str) const\n            {\n                format_impl(str);\n            }\n#ifdef _WIN32\n            virtual void format(std::basic_string<wchar_t>& str) const\n            {\n                format_impl(str);\n            }\n#endif\n\n        private:\n            json::object m_object;\n\n            template<typename CharType> friend class json::details::JSON_Parser;\n\n            template<typename CharType>\n            void format_impl(std::basic_string<CharType>& str) const\n            {\n                str.push_back('{');\n                if(!m_object.empty())\n                {\n                    auto lastElement = m_object.end() - 1;\n                    for (auto iter = m_object.begin(); iter != lastElement; ++iter)\n                    {\n                        format_string(iter->first, str);\n                        str.push_back(':');\n                        iter->second.format(str);\n                        str.push_back(',');\n                    }\n                    format_string(lastElement->first, str);\n                    str.push_back(':');\n                    lastElement->second.format(str);\n                }\n                str.push_back('}');\n            }\n\n            size_t get_reserve_size() const\n            {\n                // This is a heuristic we can tune more in the future:\n                // Basically size of string plus\n                // sum size of value if an object, array, or string.\n                size_t reserveSize = 2; // For brackets {}\n                for(auto iter = m_object.begin(); iter != m_object.end(); ++iter)\n                {\n                    reserveSize += iter->first.length() + 2;    // 2 for quotes\n                    size_t valueSize = iter->second.size() * 20; // Multipler by each object/array element\n                    if(valueSize == 0)\n                    {\n                        if(iter->second.type() == json::value::String)\n                        {\n                            valueSize = static_cast<_String *>(iter->second.m_value.get())->get_reserve_size();\n                        }\n                        else\n                        {\n                            valueSize = 5; // true, false, or null\n                        }\n                    }\n                    reserveSize += valueSize;\n                }\n                return reserveSize;\n            }\n        };\n\n        class _Array : public _Value\n        {\n        public:\n            _Array() {}\n            _Array(array::size_type size) : m_array(size) {}\n            _Array(array::storage_type elements) : m_array(std::move(elements)) { }\n\n            virtual std::unique_ptr<_Value> _copy_value()\n            {\n                return utility::details::make_unique<_Array>(*this);\n            }\n\n            virtual json::value::value_type type() const { return json::value::Array; }\n\n            virtual json::array& as_array() { return m_array; }\n            virtual const json::array& as_array() const { return m_array; }\n\n            virtual json::value &index(json::array::size_type index)\n            {\n                return m_array[index];\n            }\n\n            bool is_equal(const _Array* other) const\n            {\n                if ( m_array.size() != other->m_array.size())\n                    return false;\n\n                auto iterT  = m_array.cbegin();\n                auto iterO  = other->m_array.cbegin();\n                auto iterTe = m_array.cend();\n                auto iterOe = other->m_array.cend();\n\n                for (; iterT != iterTe && iterO != iterOe; ++iterT, ++iterO)\n                {\n                    if ( *iterT != *iterO )\n                        return false;\n                }\n\n                return true;\n            }\n\n            virtual void serialize_impl(std::string& str) const\n            {\n                // To avoid repeated allocations reserve some space all up front.\n                str.reserve(get_reserve_size());\n                format(str);\n            }\n#ifdef _WIN32\n            virtual void serialize_impl(std::wstring& str) const\n            {\n                // To avoid repeated allocations reserve some space all up front.\n                str.reserve(get_reserve_size());\n                format(str);\n            }\n#endif\n            size_t size() const { return m_array.size(); }\n\n        protected:\n            virtual void format(std::basic_string<char>& str) const\n            {\n                format_impl(str);\n            }\n#ifdef _WIN32\n            virtual void format(std::basic_string<wchar_t>& str) const\n            {\n                format_impl(str);\n            }\n#endif\n        private:\n            json::array m_array;\n\n            template<typename CharType> friend class json::details::JSON_Parser;\n\n            template<typename CharType>\n            void format_impl(std::basic_string<CharType>& str) const\n            {\n                str.push_back('[');\n                if(!m_array.m_elements.empty())\n                {\n                    auto lastElement = m_array.m_elements.end() - 1;\n                    for (auto iter = m_array.m_elements.begin(); iter != lastElement; ++iter)\n                    {\n                        iter->format(str);\n                        str.push_back(',');\n                    }\n                    lastElement->format(str);\n                }\n                str.push_back(']');\n            }\n\n            size_t get_reserve_size() const\n            {\n                // This is a heuristic we can tune more in the future:\n                // Basically sum size of each value if an object, array, or string by a multiplier.\n                size_t reserveSize = 2; // For brackets []\n                for(auto iter = m_array.cbegin(); iter != m_array.cend(); ++iter)\n                {\n                    size_t valueSize = iter->size() * 20; // Per each nested array/object\n\n                    if(valueSize == 0)\n                        valueSize = 5; // true, false, or null\n\n                    reserveSize += valueSize;\n                }\n                return reserveSize;\n            }\n        };\n    } // namespace details\n\n    /// <summary>\n    /// Gets the number of children of the value.\n    /// </summary>\n    /// <returns>The number of children. 0 for all non-composites.</returns>\n    inline size_t json::value::size() const\n    {\n        return m_value->size();\n    }\n\n    /// <summary>\n    /// Test for the presence of a field.\n    /// </summary>\n    /// <param name=\"key\">The name of the field</param>\n    /// <returns>True if the field exists, false otherwise.</returns>\n    inline bool json::value::has_field(const utility::string_t& key) const\n    {\n        return m_value->has_field(key);\n    }\n\n    /// <summary>\n    /// Access a field of a JSON object.\n    /// </summary>\n    /// <param name=\"key\">The name of the field</param>\n    /// <returns>The value kept in the field; null if the field does not exist</returns>\n    inline json::value json::value::get(const utility::string_t& key) const\n    {\n        return m_value->get_field(key);\n    }\n\n    /// <summary>\n    /// Access an element of a JSON array.\n    /// </summary>\n    /// <param name=\"index\">The index of an element in the JSON array</param>\n    /// <returns>The value kept at the array index; null if outside the boundaries of the array</returns>\n    inline json::value json::value::get(size_t index) const\n    {\n        return m_value->get_element(index);\n    }\n\n    /// <summary>\n    /// A standard <c>std::ostream</c> operator to facilitate writing JSON values to streams.\n    /// </summary>\n    /// <param name=\"os\">The output stream to write the JSON value to.</param>\n    /// <param name=\"val\">The JSON value to be written to the stream.</param>\n    /// <returns>The output stream object</returns>\n    _ASYNCRTIMP utility::ostream_t& __cdecl operator << (utility::ostream_t &os, const json::value &val);\n\n    /// <summary>\n    /// A standard <c>std::istream</c> operator to facilitate reading JSON values from streams.\n    /// </summary>\n    /// <param name=\"is\">The input stream to read the JSON value from.</param>\n    /// <param name=\"val\">The JSON value object read from the stream.</param>\n    /// <returns>The input stream object.</returns>\n    _ASYNCRTIMP utility::istream_t& __cdecl operator >> (utility::istream_t &is, json::value &val);\n}}\n\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning (pop)\n#endif\n\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/producerconsumerstream.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* This file defines a basic memory-based stream buffer, which allows consumer / producer pairs to communicate\n* data via a buffer.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#ifndef _CASA_PRODUCER_CONSUMER_STREAMS_H\n#define _CASA_PRODUCER_CONSUMER_STREAMS_H\n\n#include <vector>\n#include <queue>\n#include <algorithm>\n#include <iterator>\n\n#include \"pplx/pplxtasks.h\"\n#include \"cpprest/astreambuf.h\"\n\nnamespace Concurrency { namespace streams {\n\n    namespace details {\n\n        /// <summary>\n        /// The basic_producer_consumer_buffer class serves as a memory-based steam buffer that supports both writing and reading\n        /// sequences of characters. It can be used as a consumer/producer buffer.\n        /// </summary>\n        template<typename _CharType>\n        class basic_producer_consumer_buffer : public streams::details::streambuf_state_manager<_CharType>\n        {\n        public:\n            typedef typename ::concurrency::streams::char_traits<_CharType> traits;\n            typedef typename basic_streambuf<_CharType>::int_type int_type;\n            typedef typename basic_streambuf<_CharType>::pos_type pos_type;\n            typedef typename basic_streambuf<_CharType>::off_type off_type;\n\n            /// <summary>\n            /// Constructor\n            /// </summary>\n            basic_producer_consumer_buffer(size_t alloc_size)\n                : streambuf_state_manager<_CharType>(std::ios_base::out | std::ios_base::in),\n                m_alloc_size(alloc_size),\n                m_allocBlock(nullptr),\n                m_total(0), m_total_read(0), m_total_written(0),\n                m_synced(0)\n            {\n            }\n\n            /// <summary>\n            /// Destructor\n            /// </summary>\n            virtual ~basic_producer_consumer_buffer()\n            {\n                // Note: there is no need to call 'wait()' on the result of close(),\n                // since we happen to know that close() will return without actually\n                // doing anything asynchronously. Should the implementation of _close_write()\n                // change in that regard, this logic may also have to change.\n                (void)this->_close_read();\n                (void)this->_close_write();\n\n                _ASSERTE(m_requests.empty());\n                m_blocks.clear();\n            }\n\n            /// <summary>\n            /// <c>can_seek<c/> is used to determine whether a stream buffer supports seeking.\n            /// </summary>\n            virtual bool can_seek() const { return false; }\n\n            /// <summary>\n            /// <c>has_size<c/> is used to determine whether a stream buffer supports size().\n            /// </summary>\n            virtual bool has_size() const { return false; }\n\n            /// <summary>\n            /// Get the stream buffer size, if one has been set.\n            /// </summary>\n            /// <param name=\"direction\">The direction of buffering (in or out)</param>\n            /// <remarks>An implementation that does not support buffering will always return '0'.</remarks>\n            virtual size_t buffer_size(std::ios_base::openmode = std::ios_base::in) const\n            {\n                return 0;\n            }\n\n            /// <summary>\n            /// Sets the stream buffer implementation to buffer or not buffer.\n            /// </summary>\n            /// <param name=\"size\">The size to use for internal buffering, 0 if no buffering should be done.</param>\n            /// <param name=\"direction\">The direction of buffering (in or out)</param>\n            /// <remarks>An implementation that does not support buffering will silently ignore calls to this function and it will not have any effect on what is returned by subsequent calls to <see cref=\"::buffer_size method\" />.</remarks>\n            virtual void set_buffer_size(size_t , std::ios_base::openmode = std::ios_base::in)\n            {\n                return;\n            }\n\n            /// <summary>\n            /// For any input stream, <c>in_avail</c> returns the number of characters that are immediately available\n            /// to be consumed without blocking. May be used in conjunction with <cref=\"::sbumpc method\"/> to read data without\n            /// incurring the overhead of using tasks.\n            /// </summary>\n            virtual size_t in_avail() const { return m_total; }\n\n\n            /// <summary>\n            /// Gets the current read or write position in the stream.\n            /// </summary>\n            /// <param name=\"direction\">The I/O direction to seek (see remarks)</param>\n            /// <returns>The current position. EOF if the operation fails.</returns>\n            /// <remarks>Some streams may have separate write and read cursors.\n            ///          For such streams, the direction parameter defines whether to move the read or the write cursor.</remarks>\n            virtual pos_type getpos(std::ios_base::openmode mode) const\n            {\n                if ( ((mode & std::ios_base::in) && !this->can_read()) ||\n                     ((mode & std::ios_base::out) && !this->can_write()))\n                     return static_cast<pos_type>(traits::eof());\n\n                if (mode == std::ios_base::in)\n                    return (pos_type)m_total_read;\n                else if (mode == std::ios_base::out)\n                    return (pos_type)m_total_written;\n                else\n                    return (pos_type)traits::eof();\n            }\n\n            // Seeking is not supported\n            virtual pos_type seekpos(pos_type, std::ios_base::openmode) { return (pos_type)traits::eof(); }\n            virtual pos_type seekoff(off_type , std::ios_base::seekdir , std::ios_base::openmode ) { return (pos_type)traits::eof(); }\n\n            /// <summary>\n            /// Allocates a contiguous memory block and returns it.\n            /// </summary>\n            /// <param name=\"count\">The number of characters to allocate.</param>\n            /// <returns>A pointer to a block to write to, null if the stream buffer implementation does not support alloc/commit.</returns>\n            virtual _CharType* _alloc(size_t count)\n            {\n                if (!this->can_write())\n                {\n                    return nullptr;\n                }\n\n                // We always allocate a new block even if the count could be satisfied by\n                // the current write block. While this does lead to wasted space it allows for\n                // easier book keeping\n\n                _ASSERTE(!m_allocBlock);\n                m_allocBlock = std::make_shared<_block>(count);\n                return m_allocBlock->wbegin();\n            }\n\n            /// <summary>\n            /// Submits a block already allocated by the stream buffer.\n            /// </summary>\n            /// <param name=\"count\">The number of characters to be committed.</param>\n            virtual void _commit(size_t count)\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n\n                // The count does not reflect the actual size of the block.\n                // Since we do not allow any more writes to this block it would suffice.\n                // If we ever change the algorithm to reuse blocks then this needs to be revisited.\n\n                _ASSERTE((bool)m_allocBlock);\n                m_allocBlock->update_write_head(count);\n                m_blocks.push_back(m_allocBlock);\n                m_allocBlock = nullptr;\n\n                update_write_head(count);\n            }\n\n            /// <summary>\n            /// Gets a pointer to the next already allocated contiguous block of data.\n            /// </summary>\n            /// <param name=\"ptr\">A reference to a pointer variable that will hold the address of the block on success.</param>\n            /// <param name=\"count\">The number of contiguous characters available at the address in 'ptr.'</param>\n            /// <returns><c>true</c> if the operation succeeded, <c>false</c> otherwise.</returns>\n            /// <remarks>\n            /// A return of false does not necessarily indicate that a subsequent read operation would fail, only that\n            /// there is no block to return immediately or that the stream buffer does not support the operation.\n            /// The stream buffer may not de-allocate the block until <see cref=\"::release method\" /> is called.\n            /// If the end of the stream is reached, the function will return <c>true</c>, a null pointer, and a count of zero;\n            /// a subsequent read will not succeed.\n            /// </remarks>\n            virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count)\n            {\n                count = 0;\n                ptr = nullptr;\n\n                if (!this->can_read()) return false;\n\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n\n                if (m_blocks.empty())\n                {\n                    // If the write head has been closed then have reached the end of the\n                    // stream (return true), otherwise more data could be written later (return false).\n                    return !this->can_write();\n                }\n                else\n                {\n                    auto block = m_blocks.front();\n\n                    count = block->rd_chars_left();\n                    ptr = block->rbegin();\n\n                    _ASSERTE(ptr != nullptr);\n                    return true;\n                }\n            }\n\n            /// <summary>\n            /// Releases a block of data acquired using <see cref=\"::acquire method\"/>. This frees the stream buffer to de-allocate the\n            /// memory, if it so desires. Move the read position ahead by the count.\n            /// </summary>\n            /// <param name=\"ptr\">A pointer to the block of data to be released.</param>\n            /// <param name=\"count\">The number of characters that were read.</param>\n            virtual void release(_Out_writes_opt_ (count) _CharType *ptr, _In_ size_t count)\n            {\n                if (ptr == nullptr) return;\n\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n                auto block = m_blocks.front();\n\n                _ASSERTE(block->rd_chars_left() >= count);\n                block->m_read += count;\n\n                update_read_head(count);\n            }\n\n        protected:\n\n            virtual pplx::task<bool> _sync()\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n\n                m_synced = in_avail();\n\n                fulfill_outstanding();\n\n                return pplx::task_from_result(true);\n            }\n\n            virtual pplx::task<int_type> _putc(_CharType ch)\n            {\n                return pplx::task_from_result((this->write(&ch, 1) == 1) ? static_cast<int_type>(ch) : traits::eof());\n            }\n\n            virtual pplx::task<size_t> _putn(const _CharType *ptr, size_t count)\n            {\n                return pplx::task_from_result<size_t>(this->write(ptr, count));\n            }\n\n\n            virtual pplx::task<size_t> _getn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)\n            {\n                pplx::task_completion_event<size_t> tce;\n                enqueue_request(_request(count, [this, ptr, count, tce]()\n                {\n                    // VS 2010 resolves read to a global function.  Explicit\n                    // invocation through the \"this\" pointer fixes the issue.\n                    tce.set(this->read(ptr, count));\n                }));\n                return pplx::create_task(tce);\n            }\n\n            virtual size_t _sgetn(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n                return can_satisfy(count) ? this->read(ptr, count) : (size_t)traits::requires_async();\n            }\n\n            virtual size_t _scopy(_Out_writes_ (count) _CharType *ptr, _In_ size_t count)\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n                return can_satisfy(count) ? this->read(ptr, count, false) : (size_t)traits::requires_async();\n            }\n\n            virtual pplx::task<int_type> _bumpc()\n            {\n                pplx::task_completion_event<int_type> tce;\n                enqueue_request(_request(1, [this, tce]()\n                {\n                    tce.set(this->read_byte(true));\n                }));\n                return pplx::create_task(tce);\n            }\n\n            virtual int_type _sbumpc()\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n                return can_satisfy(1) ? this->read_byte(true) : traits::requires_async();\n            }\n\n            virtual pplx::task<int_type> _getc()\n            {\n                pplx::task_completion_event<int_type> tce;\n                enqueue_request(_request(1, [this, tce]()\n                {\n                    tce.set(this->read_byte(false));\n                }));\n                return pplx::create_task(tce);\n            }\n\n            int_type _sgetc()\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n                return can_satisfy(1) ? this->read_byte(false) : traits::requires_async();\n            }\n\n            virtual pplx::task<int_type> _nextc()\n            {\n                pplx::task_completion_event<int_type> tce;\n                enqueue_request(_request(1, [this, tce]()\n                {\n                    this->read_byte(true);\n                    tce.set(this->read_byte(false));\n                }));\n                return pplx::create_task(tce);\n            }\n\n            virtual pplx::task<int_type> _ungetc()\n            {\n                return pplx::task_from_result<int_type>(traits::eof());\n            }\n\n        private:\n\n            /// <summary>\n            /// Close the stream buffer for writing\n            /// </summary>\n            pplx::task<void> _close_write()\n            {\n                // First indicate that there could be no more writes.\n                // Fulfill outstanding relies on that to flush all the\n                // read requests.\n                this->m_stream_can_write = false;\n\n                {\n                    pplx::extensibility::scoped_critical_section_t l(this->m_lock);\n\n                    // This runs on the thread that called close.\n                    this->fulfill_outstanding();\n                }\n\n                return pplx::task_from_result();\n            }\n\n            /// <summary>\n            /// Updates the write head by an offset specified by count\n            /// </summary>\n            /// <remarks>This should be called with the lock held</remarks>\n            void update_write_head(size_t count)\n            {\n                m_total += count;\n                m_total_written += count;\n                fulfill_outstanding();\n            }\n\n            /// <summary>\n            /// Writes count characters from ptr into the stream buffer\n            /// </summary>\n            size_t write(const _CharType *ptr, size_t count)\n            {\n                if (!this->can_write() || (count == 0)) return 0;\n\n                // If no one is going to read, why bother?\n                // Just pretend to be writing!\n                if (!this->can_read()) return count;\n\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n\n                // Allocate a new block if necessary\n                if ( m_blocks.empty() || m_blocks.back()->wr_chars_left() < count )\n                {\n                    msl::safeint3::SafeInt<size_t> alloc = m_alloc_size.Max(count);\n                    m_blocks.push_back(std::make_shared<_block>(alloc));\n                }\n\n                // The block at the back is always the write head\n                auto last = m_blocks.back();\n                auto countWritten = last->write(ptr, count);\n                _ASSERTE(countWritten == count);\n\n                update_write_head(countWritten);\n                return countWritten;\n            }\n\n            /// <summary>\n            /// Fulfill pending requests\n            /// </summary>\n            /// <remarks>This should be called with the lock held</remarks>\n            void fulfill_outstanding()\n            {\n                while ( !m_requests.empty() )\n                {\n                    auto req = m_requests.front();\n\n                    // If we cannot satisfy the request then we need\n                    // to wait for the producer to write data\n                    if (!can_satisfy(req.size())) return;\n\n                    // We have enough data to satisfy this request\n                    req.complete();\n\n                    // Remove it from the request queue\n                    m_requests.pop();\n                }\n            }\n\n            /// <summary>\n            /// Represents a memory block\n            /// </summary>\n            class _block\n            {\n            public:\n                _block(size_t size)\n                    : m_read(0), m_pos(0), m_size(size), m_data(new _CharType[size])\n                {\n                }\n\n                ~_block()\n                {\n                    delete [] m_data;\n                }\n\n                // Read head\n                size_t m_read;\n\n                // Write head\n                size_t m_pos;\n\n                // Allocation size (of m_data)\n                size_t m_size;\n\n                // The data store\n                _CharType * m_data;\n\n                // Pointer to the read head\n                _CharType * rbegin()\n                {\n                    return m_data + m_read;\n                }\n\n                // Pointer to the write head\n                _CharType * wbegin()\n                {\n                    return m_data + m_pos;\n                }\n\n                // Read up to count characters from the block\n                size_t read(_Out_writes_ (count) _CharType * dest, _In_ size_t count, bool advance = true)\n                {\n                    msl::safeint3::SafeInt<size_t> avail(rd_chars_left());\n                    auto countRead = static_cast<size_t>(avail.Min(count));\n\n                    _CharType * beg = rbegin();\n                    _CharType * end = rbegin() + countRead;\n\n#ifdef _WIN32\n                    // Avoid warning C4996: Use checked iterators under SECURE_SCL\n                    std::copy(beg, end, stdext::checked_array_iterator<_CharType *>(dest, count));\n#else\n                    std::copy(beg, end, dest);\n#endif // _WIN32\n\n                    if (advance)\n                    {\n                        m_read += countRead;\n                    }\n\n                    return countRead;\n                }\n\n                // Write count characters into the block\n                size_t write(const _CharType * src, size_t count)\n                {\n                    msl::safeint3::SafeInt<size_t> avail(wr_chars_left());\n                    auto countWritten = static_cast<size_t>(avail.Min(count));\n\n                    const _CharType * srcEnd = src + countWritten;\n\n#ifdef _WIN32\n                    // Avoid warning C4996: Use checked iterators under SECURE_SCL\n                    std::copy(src, srcEnd, stdext::checked_array_iterator<_CharType *>(wbegin(), static_cast<size_t>(avail)));\n#else\n                    std::copy(src, srcEnd, wbegin());\n#endif // _WIN32\n\n                    update_write_head(countWritten);\n                    return countWritten;\n                }\n\n                void update_write_head(size_t count)\n                {\n                    m_pos += count;\n                }\n\n                size_t rd_chars_left() const { return m_pos-m_read; }\n                size_t wr_chars_left() const { return m_size-m_pos; }\n\n            private:\n\n                // Copy is not supported\n                _block(const _block&);\n                _block& operator=(const _block&);\n            };\n\n            /// <summary>\n            /// Represents a request on the stream buffer - typically reads\n            /// </summary>\n            class _request\n            {\n            public:\n\n                typedef std::function<void()> func_type;\n                _request(size_t count, const func_type& func)\n                    : m_func(func), m_count(count)\n                {\n                }\n\n                void complete()\n                {\n                    m_func();\n                }\n\n                size_t size() const\n                {\n                    return m_count;\n                }\n\n            private:\n\n                func_type m_func;\n                size_t m_count;\n            };\n\n            void enqueue_request(_request req)\n            {\n                pplx::extensibility::scoped_critical_section_t l(m_lock);\n\n                if (can_satisfy(req.size()))\n                {\n                    // We can immediately fulfill the request.\n                    req.complete();\n                }\n                else\n                {\n                    // We must wait for data to arrive.\n                    m_requests.push(req);\n                }\n            }\n\n            /// <summary>\n            /// Determine if the request can be satisfied.\n            /// </summary>\n            bool can_satisfy(size_t count)\n            {\n                return (m_synced > 0) || (this->in_avail() >= count) || !this->can_write();\n            }\n\n            /// <summary>\n            /// Reads a byte from the stream and returns it as int_type.\n            /// Note: This routine shall only be called if can_satisfy() returned true.\n            /// </summary>\n            /// <remarks>This should be called with the lock held</remarks>\n            int_type read_byte(bool advance = true)\n            {\n                _CharType value;\n                auto read_size = this->read(&value, 1, advance);\n                return read_size == 1 ? static_cast<int_type>(value) : traits::eof();\n            }\n\n            /// <summary>\n            /// Reads up to count characters into ptr and returns the count of characters copied.\n            /// The return value (actual characters copied) could be <= count.\n            /// Note: This routine shall only be called if can_satisfy() returned true.\n            /// </summary>\n            /// <remarks>This should be called with the lock held</remarks>\n            size_t read(_Out_writes_ (count) _CharType *ptr, _In_ size_t count, bool advance = true)\n            {\n                _ASSERTE(can_satisfy(count));\n\n                size_t read = 0;\n\n                for (auto iter = begin(m_blocks); iter != std::end(m_blocks); ++iter)\n                {\n                    auto block = *iter;\n                    auto read_from_block = block->read(ptr + read, count - read, advance);\n\n                    read += read_from_block;\n\n                    _ASSERTE(count >= read);\n                    if (read == count) break;\n                }\n\n                if (advance)\n                {\n                    update_read_head(read);\n                }\n\n                return read;\n            }\n\n            /// <summary>\n            /// Updates the read head by the specified offset\n            /// </summary>\n            /// <remarks>This should be called with the lock held</remarks>\n            void update_read_head(size_t count)\n            {\n                m_total -= count;\n                m_total_read += count;\n\n                if ( m_synced > 0 )\n                    m_synced = (m_synced > count) ? (m_synced-count) : 0;\n\n                // The block at the front is always the read head.\n                // Purge empty blocks so that the block at the front reflects the read head\n                while (!m_blocks.empty())\n                {\n                    // If front block is not empty - we are done\n                    if (m_blocks.front()->rd_chars_left() > 0) break;\n\n                    // The block has no more data to be read. Relase the block\n                    m_blocks.pop_front();\n                }\n            }\n\n            // The in/out mode for the buffer\n            std::ios_base::openmode m_mode{};\n\n            // Default block size\n            msl::safeint3::SafeInt<size_t> m_alloc_size;\n\n            // Block used for alloc/commit\n            std::shared_ptr<_block> m_allocBlock;\n\n            // Total available data\n            size_t m_total;\n\n            size_t m_total_read;\n            size_t m_total_written;\n\n            // Keeps track of the number of chars that have been flushed but still\n            // remain to be consumed by a read operation.\n            size_t m_synced;\n\n            // The producer-consumer buffer is intended to be used concurrently by a reader\n            // and a writer, who are not coordinating their accesses to the buffer (coordination\n            // being what the buffer is for in the first place). Thus, we have to protect\n            // against some of the internal data elements against concurrent accesses\n            // and the possibility of inconsistent states. A simple non-recursive lock\n            // should be sufficient for those purposes.\n            pplx::extensibility::critical_section_t m_lock;\n\n            // Memory blocks\n            std::deque<std::shared_ptr<_block>> m_blocks;\n\n            // Queue of requests\n            std::queue<_request> m_requests;\n        };\n\n    } // namespace details\n\n    /// <summary>\n    /// The producer_consumer_buffer class serves as a memory-based steam buffer that supports both writing and reading\n    /// sequences of bytes. It can be used as a consumer/producer buffer.\n    /// </summary>\n    /// <typeparam name=\"_CharType\">\n    /// The data type of the basic element of the <c>producer_consumer_buffer</c>.\n    /// </typeparam>\n    /// <remarks>\n    /// This is a reference-counted version of basic_producer_consumer_buffer.</remarks>\n    template<typename _CharType>\n    class producer_consumer_buffer : public streambuf<_CharType>\n    {\n    public:\n        typedef _CharType char_type;\n\n        /// <summary>\n        /// Create a producer_consumer_buffer.\n        /// </summary>\n        /// <param name=\"alloc_size\">The internal default block size.</param>\n        producer_consumer_buffer(size_t alloc_size = 512)\n            : streambuf<_CharType>(std::make_shared<details::basic_producer_consumer_buffer<_CharType>>(alloc_size))\n        {\n        }\n    };\n\n}} // namespaces\n\n#endif"
  },
  {
    "path": "Include/cpprestinclude/cpprest/streams.h",
    "content": "#if !XSAPI_NO_PPL\n/***\n * Copyright (C) Microsoft. All rights reserved.\n * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n *\n * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n *\n * Asynchronous I/O: streams API, used for formatted input and output, based on unformatted I/O using stream buffers\n *\n * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n *\n * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n ****/\n#pragma once\n\n#ifndef CASA_STREAMS_H\n#define CASA_STREAMS_H\n\n#include \"cpprest/astreambuf.h\"\n#include <iosfwd>\n#include <cstdio>\n\nnamespace Concurrency\n{\nnamespace streams\n{\ntemplate<typename CharType>\nclass basic_ostream;\ntemplate<typename CharType>\nclass basic_istream;\n\nnamespace details\n{\ntemplate<typename CharType>\nclass basic_ostream_helper\n{\npublic:\n    basic_ostream_helper(streams::streambuf<CharType> buffer) : m_buffer(buffer) {}\n\n    ~basic_ostream_helper() {}\n\nprivate:\n    template<typename CharType1>\n    friend class streams::basic_ostream;\n\n    concurrency::streams::streambuf<CharType> m_buffer;\n};\n\ntemplate<typename CharType>\nclass basic_istream_helper\n{\npublic:\n    basic_istream_helper(streams::streambuf<CharType> buffer) : m_buffer(buffer) {}\n\n    ~basic_istream_helper() {}\n\nprivate:\n    template<typename CharType1>\n    friend class streams::basic_istream;\n\n    concurrency::streams::streambuf<CharType> m_buffer;\n};\n\ntemplate<typename CharType>\nstruct Value2StringFormatter\n{\n    template<typename T>\n    static std::basic_string<CharType> format(const T& val)\n    {\n        std::basic_ostringstream<CharType> ss;\n        ss << val;\n        return ss.str();\n    }\n};\n\ntemplate<>\nstruct Value2StringFormatter<uint8_t>\n{\n    template<typename T>\n    static std::basic_string<uint8_t> format(const T& val)\n    {\n        std::basic_ostringstream<char> ss;\n        ss << val;\n        return reinterpret_cast<const uint8_t*>(ss.str().c_str());\n    }\n\n    static std::basic_string<uint8_t> format(const utf16string& val)\n    {\n        return format(utility::conversions::utf16_to_utf8(val));\n    }\n};\n\nstatic const char* _in_stream_msg = \"stream not set up for input of data\";\nstatic const char* _in_streambuf_msg = \"stream buffer not set up for input of data\";\nstatic const char* _out_stream_msg = \"stream not set up for output of data\";\nstatic const char* _out_streambuf_msg = \"stream buffer not set up for output of data\";\n} // namespace details\n\n/// <summary>\n/// Base interface for all asynchronous output streams.\n/// </summary>\ntemplate<typename CharType>\nclass basic_ostream\n{\npublic:\n    typedef char_traits<CharType> traits;\n    typedef typename traits::int_type int_type;\n    typedef typename traits::pos_type pos_type;\n    typedef typename traits::off_type off_type;\n\n    /// <summary>\n    /// Default constructor\n    /// </summary>\n    basic_ostream() {}\n\n    /// <summary>\n    /// Copy constructor\n    /// </summary>\n    /// <param name=\"other\">The source object</param>\n    basic_ostream(const basic_ostream& other) : m_helper(other.m_helper) {}\n\n    /// <summary>\n    /// Assignment operator\n    /// </summary>\n    /// <param name=\"other\">The source object</param>\n    /// <returns>A reference to the stream object that contains the result of the assignment.</returns>\n    basic_ostream& operator=(const basic_ostream& other)\n    {\n        m_helper = other.m_helper;\n        return *this;\n    }\n\n    /// <summary>\n    /// Constructor\n    /// </summary>\n    /// <param name=\"buffer\">A stream buffer.</param>\n    basic_ostream(streams::streambuf<CharType> buffer)\n        : m_helper(std::make_shared<details::basic_ostream_helper<CharType>>(buffer))\n    {\n        _verify_and_throw(details::_out_streambuf_msg);\n    }\n\n    /// <summary>\n    /// Close the stream, preventing further write operations.\n    /// </summary>\n    pplx::task<void> close() const\n    {\n        return is_valid() ? helper()->m_buffer.close(std::ios_base::out) : pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// Close the stream with exception, preventing further write operations.\n    /// </summary>\n    /// <param name=\"eptr\">Pointer to the exception.</param>\n    pplx::task<void> close(std::exception_ptr eptr) const\n    {\n        return is_valid() ? helper()->m_buffer.close(std::ios_base::out, eptr) : pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// Put a single character into the stream.\n    /// </summary>\n    /// <param name=\"ch\">A character</param>\n    pplx::task<int_type> write(CharType ch) const\n    {\n        pplx::task<int_type> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n        return helper()->m_buffer.putc(ch);\n    }\n\n    /// <summary>\n    /// Write a single value of \"blittable\" type T into the stream.\n    /// </summary>\n    /// <param name=\"value\">A value of type T.</param>\n    /// <remarks>\n    /// This is not a replacement for a proper binary serialization solution, but it may\n    /// form the foundation for one. Writing data bit-wise to a stream is a primitive\n    /// operation of binary serialization.\n    /// Currently, no attention is paid to byte order. All data is written in the platform's\n    /// native byte order, which means little-endian on all platforms that have been tested.\n    /// This function is only available for streams using a single-byte character size.\n    /// </remarks>\n    template<typename T>\n    CASABLANCA_DEPRECATED(\n        \"Unsafe API that will be removed in future releases, use one of the other write overloads instead.\")\n    pplx::task<size_t> write(T value) const\n    {\n        static_assert(sizeof(CharType) == 1, \"binary write is only supported for single-byte streams\");\n        static_assert(std::is_trivial<T>::value, \"unsafe to use with non-trivial types\");\n\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n\n        auto copy = std::make_shared<T>(std::move(value));\n        return helper()\n            ->m_buffer.putn_nocopy((CharType*)copy.get(), sizeof(T))\n            .then([copy](pplx::task<size_t> op) -> size_t { return op.get(); });\n    }\n\n    /// <summary>\n    /// Write a number of characters from a given stream buffer into the stream.\n    /// </summary>\n    /// <param name=\"source\">A source stream buffer.</param>\n    /// <param name=\"count\">The number of characters to write.</param>\n    pplx::task<size_t> write(streams::streambuf<CharType> source, size_t count) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n        if (!source.can_read())\n            return pplx::task_from_exception<size_t>(\n                std::make_exception_ptr(std::runtime_error(\"source buffer not set up for input of data\")));\n\n        if (count == 0) return pplx::task_from_result((size_t)0);\n\n        auto buffer = helper()->m_buffer;\n        auto data = buffer.alloc(count);\n\n        if (data != nullptr)\n        {\n            auto post_read = [buffer](pplx::task<size_t> op) -> pplx::task<size_t> {\n                auto b = buffer;\n                b.commit(op.get());\n                return op;\n            };\n            return source.getn(data, count).then(post_read);\n        }\n        else\n        {\n            size_t available = 0;\n\n            const bool acquired = source.acquire(data, available);\n            if (available >= count)\n            {\n                auto post_write = [source, data](pplx::task<size_t> op) -> pplx::task<size_t> {\n                    auto s = source;\n                    s.release(data, op.get());\n                    return op;\n                };\n                return buffer.putn_nocopy(data, count).then(post_write);\n            }\n            else\n            {\n                // Always have to release if acquire returned true.\n                if (acquired)\n                {\n                    source.release(data, 0);\n                }\n\n                std::shared_ptr<CharType> buf(new CharType[count], [](CharType* buf) { delete[] buf; });\n\n                auto post_write = [buf](pplx::task<size_t> op) -> pplx::task<size_t> { return op; };\n                auto post_read = [buf, post_write, buffer](pplx::task<size_t> op) -> pplx::task<size_t> {\n                    auto b = buffer;\n                    return b.putn_nocopy(buf.get(), op.get()).then(post_write);\n                };\n\n                return source.getn(buf.get(), count).then(post_read);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Write the specified string to the output stream.\n    /// </summary>\n    /// <param name=\"str\">Input string.</param>\n    pplx::task<size_t> print(const std::basic_string<CharType>& str) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n\n        if (str.empty())\n        {\n            return pplx::task_from_result<size_t>(0);\n        }\n        else\n        {\n            auto sharedStr = std::make_shared<std::basic_string<CharType>>(str);\n            return helper()->m_buffer.putn_nocopy(sharedStr->c_str(), sharedStr->size()).then([sharedStr](size_t size) {\n                return size;\n            });\n        }\n    }\n\n    /// <summary>\n    /// Write a value of type <c>T</c> to the output stream.\n    /// </summary>\n    /// <typeparam name=\"T\">\n    /// The data type of the object to be written to the stream\n    /// </typeparam>\n    /// <param name=\"val\">Input object.</param>\n    template<typename T>\n    pplx::task<size_t> print(const T& val) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n        // TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy\n        // by putting the string on the heap before calling the print string overload.\n        return print(details::Value2StringFormatter<CharType>::format(val));\n    }\n\n    /// <summary>\n    /// Write a value of type <c>T</c> to the output stream and append a newline character.\n    /// </summary>\n    /// <typeparam name=\"T\">\n    /// The data type of the object to be written to the stream\n    /// </typeparam>\n    /// <param name=\"val\">Input object.</param>\n    template<typename T>\n    pplx::task<size_t> print_line(const T& val) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n        auto str = details::Value2StringFormatter<CharType>::format(val);\n        str.push_back(CharType('\\n'));\n        return print(str);\n    }\n\n    /// <summary>\n    /// Flush any buffered output data.\n    /// </summary>\n    pplx::task<void> flush() const\n    {\n        pplx::task<void> result;\n        if (!_verify_and_return_task(details::_out_stream_msg, result)) return result;\n        return helper()->m_buffer.sync();\n    }\n\n    /// <summary>\n    /// Seeks to the specified write position.\n    /// </summary>\n    /// <param name=\"pos\">An offset relative to the beginning of the stream.</param>\n    /// <returns>The new position in the stream.</returns>\n    pos_type seek(pos_type pos) const\n    {\n        _verify_and_throw(details::_out_stream_msg);\n        return helper()->m_buffer.seekpos(pos, std::ios_base::out);\n    }\n\n    /// <summary>\n    /// Seeks to the specified write position.\n    /// </summary>\n    /// <param name=\"off\">An offset relative to the beginning, current write position, or the end of the stream.</param>\n    /// <param name=\"way\">The starting point (beginning, current, end) for the seek.</param>\n    /// <returns>The new position in the stream.</returns>\n    pos_type seek(off_type off, std::ios_base::seekdir way) const\n    {\n        _verify_and_throw(details::_out_stream_msg);\n        return helper()->m_buffer.seekoff(off, way, std::ios_base::out);\n    }\n\n    /// <summary>\n    /// Get the current write position, i.e. the offset from the beginning of the stream.\n    /// </summary>\n    /// <returns>The current write position.</returns>\n    pos_type tell() const\n    {\n        _verify_and_throw(details::_out_stream_msg);\n        return helper()->m_buffer.getpos(std::ios_base::out);\n    }\n\n    /// <summary>\n    /// <c>can_seek<c/> is used to determine whether the stream supports seeking.\n    /// </summary>\n    /// <returns><c>true</c> if the stream supports seeking, <c>false</c> otherwise.</returns>\n    bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); }\n\n    /// <summary>\n    /// Test whether the stream has been initialized with a valid stream buffer.\n    /// </summary>\n    /// <returns><c>true</c> if the stream has been initialized with a valid stream buffer, <c>false</c>\n    /// otherwise.</returns>\n    bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); }\n\n    /// <summary>\n    /// Test whether the stream has been initialized or not.\n    /// </summary>\n    operator bool() const { return is_valid(); }\n\n    /// <summary>\n    /// Test whether the stream is open for writing.\n    /// </summary>\n    /// <returns><c>true</c> if the stream is open for writing, <c>false</c> otherwise.</returns>\n    bool is_open() const { return is_valid() && m_helper->m_buffer.can_write(); }\n\n    /// <summary>\n    /// Get the underlying stream buffer.\n    /// </summary>\n    /// <returns>The underlying stream buffer.</returns>\n    concurrency::streams::streambuf<CharType> streambuf() const { return helper()->m_buffer; }\n\nprotected:\n    void set_helper(std::shared_ptr<details::basic_ostream_helper<CharType>> helper) { m_helper = helper; }\n\nprivate:\n    template<typename T>\n    bool _verify_and_return_task(const char* msg, pplx::task<T>& tsk) const\n    {\n        auto buffer = helper()->m_buffer;\n        if (!(buffer.exception() == nullptr))\n        {\n            tsk = pplx::task_from_exception<T>(buffer.exception());\n            return false;\n        }\n        if (!buffer.can_write())\n        {\n            tsk = pplx::task_from_exception<T>(std::make_exception_ptr(std::runtime_error(msg)));\n            return false;\n        }\n        return true;\n    }\n\n    void _verify_and_throw(const char* msg) const\n    {\n        auto buffer = helper()->m_buffer;\n        if (!(buffer.exception() == nullptr)) std::rethrow_exception(buffer.exception());\n        if (!buffer.can_write()) throw std::runtime_error(msg);\n    }\n\n    std::shared_ptr<details::basic_ostream_helper<CharType>> helper() const\n    {\n        if (!m_helper) throw std::logic_error(\"uninitialized stream object\");\n        return m_helper;\n    }\n\n    std::shared_ptr<details::basic_ostream_helper<CharType>> m_helper;\n};\n\ntemplate<typename int_type>\nstruct _type_parser_integral_traits\n{\n    typedef std::false_type _is_integral;\n    typedef std::false_type _is_unsigned;\n};\n\n#ifdef _WIN32\n#define _INT_TRAIT(_t, _low, _high)                                                                                    \\\n    template<>                                                                                                         \\\n    struct _type_parser_integral_traits<_t>                                                                            \\\n    {                                                                                                                  \\\n        typedef std::true_type _is_integral;                                                                           \\\n        typedef std::false_type _is_unsigned;                                                                          \\\n        static const int64_t _min = _low;                                                                              \\\n        static const int64_t _max = _high;                                                                             \\\n    };\n#define _UINT_TRAIT(_t, _low, _high)                                                                                   \\\n    template<>                                                                                                         \\\n    struct _type_parser_integral_traits<_t>                                                                            \\\n    {                                                                                                                  \\\n        typedef std::true_type _is_integral;                                                                           \\\n        typedef std::true_type _is_unsigned;                                                                           \\\n        static const uint64_t _max = _high;                                                                            \\\n    };\n\n_INT_TRAIT(char, INT8_MIN, INT8_MAX)\n_INT_TRAIT(signed char, INT8_MIN, INT8_MAX)\n_INT_TRAIT(short, INT16_MIN, INT16_MAX)\n#if defined(_NATIVE_WCHAR_T_DEFINED)\n_INT_TRAIT(wchar_t, WCHAR_MIN, WCHAR_MAX)\n#endif\n_INT_TRAIT(int, INT32_MIN, INT32_MAX)\n_INT_TRAIT(long, LONG_MIN, LONG_MAX)\n_INT_TRAIT(long long, LLONG_MIN, LLONG_MAX)\n_UINT_TRAIT(unsigned char, UINT8_MIN, UINT8_MAX)\n_UINT_TRAIT(unsigned short, UINT16_MIN, UINT16_MAX)\n_UINT_TRAIT(unsigned int, UINT32_MIN, UINT32_MAX)\n_UINT_TRAIT(unsigned long, ULONG_MIN, ULONG_MAX)\n_UINT_TRAIT(unsigned long long, ULLONG_MIN, ULLONG_MAX)\n#else\n#define _INT_TRAIT(_t)                                                                                                 \\\n    template<>                                                                                                         \\\n    struct _type_parser_integral_traits<_t>                                                                            \\\n    {                                                                                                                  \\\n        typedef std::true_type _is_integral;                                                                           \\\n        typedef std::false_type _is_unsigned;                                                                          \\\n        static const int64_t _min = (std::numeric_limits<_t>::min)();                                                  \\\n        static const int64_t _max = (std::numeric_limits<_t>::max)();                                                  \\\n    };\n#define _UINT_TRAIT(_t)                                                                                                \\\n    template<>                                                                                                         \\\n    struct _type_parser_integral_traits<_t>                                                                            \\\n    {                                                                                                                  \\\n        typedef std::true_type _is_integral;                                                                           \\\n        typedef std::true_type _is_unsigned;                                                                           \\\n        static const uint64_t _max = (std::numeric_limits<_t>::max)();                                                 \\\n    };\n\n_INT_TRAIT(char)\n_INT_TRAIT(signed char)\n_INT_TRAIT(short)\n_INT_TRAIT(utf16char)\n_INT_TRAIT(int)\n_INT_TRAIT(long)\n_INT_TRAIT(long long)\n_UINT_TRAIT(unsigned char)\n_UINT_TRAIT(unsigned short)\n_UINT_TRAIT(unsigned int)\n_UINT_TRAIT(unsigned long)\n_UINT_TRAIT(unsigned long long)\n#endif\n\ntemplate<typename CharType>\nclass _type_parser_base\n{\npublic:\n    typedef char_traits<CharType> traits;\n    typedef typename traits::int_type int_type;\n\n    _type_parser_base() {}\n\nprotected:\n    // Aid in parsing input: skipping whitespace characters.\n    static pplx::task<void> _skip_whitespace(streams::streambuf<CharType> buffer);\n\n    // Aid in parsing input: peek at a character at a time, call type-specific code to examine, extract value when done.\n    // <remark>AcceptFunctor should model std::function<bool(std::shared_ptr<X>, int_type)></remark>\n    // <remark>ExtractFunctor should model std::function<pplx::task<ReturnType>(std::shared_ptr<X>)></remark>\n    template<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>\n    static pplx::task<ReturnType> _parse_input(streams::streambuf<CharType> buffer,\n                                               AcceptFunctor accept_character,\n                                               ExtractFunctor extract);\n};\n\n/// <summary>\n/// Class used to handle asynchronous parsing for basic_istream::extract. To support new\n/// types create a new template specialization and implement the parse function.\n/// </summary>\ntemplate<typename CharType, typename T>\nclass type_parser\n{\npublic:\n    static pplx::task<T> parse(streams::streambuf<CharType> buffer)\n    {\n        typedef typename _type_parser_integral_traits<T>::_is_integral ii;\n        typedef typename _type_parser_integral_traits<T>::_is_unsigned ui;\n\n        static_assert(ii::value || !ui::value, \"type is not supported for extraction from a stream\");\n\n        return _parse(buffer, ii {}, ui {});\n    }\n\nprivate:\n    static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::false_type, std::false_type)\n    {\n        _parse_floating_point(buffer);\n    }\n\n    static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::true_type, std::false_type)\n    {\n        return type_parser<CharType, int64_t>::parse(buffer).then([](pplx::task<int64_t> op) -> T {\n            int64_t val = op.get();\n            if (val <= _type_parser_integral_traits<T>::_max && val >= _type_parser_integral_traits<T>::_min)\n                return (T)val;\n            else\n                throw std::range_error(\"input out of range for target type\");\n        });\n    }\n\n    static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::true_type, std::true_type)\n    {\n        return type_parser<CharType, uint64_t>::parse(buffer).then([](pplx::task<uint64_t> op) -> T {\n            uint64_t val = op.get();\n            if (val <= _type_parser_integral_traits<T>::_max)\n                return (T)val;\n            else\n                throw std::range_error(\"input out of range for target type\");\n        });\n    }\n};\n\n/// <summary>\n/// Base interface for all asynchronous input streams.\n/// </summary>\ntemplate<typename CharType>\nclass basic_istream\n{\npublic:\n    typedef char_traits<CharType> traits;\n    typedef typename traits::int_type int_type;\n    typedef typename traits::pos_type pos_type;\n    typedef typename traits::off_type off_type;\n\n    /// <summary>\n    /// Default constructor\n    /// </summary>\n    basic_istream() {}\n\n    /// <summary>\n    /// Constructor\n    /// </summary>\n    /// <typeparam name=\"CharType\">\n    /// The data type of the basic element of the stream.\n    /// </typeparam>\n    /// <param name=\"buffer\">A stream buffer.</param>\n    template<class AlterCharType>\n    basic_istream(streams::streambuf<AlterCharType> buffer)\n        : m_helper(std::make_shared<details::basic_istream_helper<CharType>>(std::move(buffer)))\n    {\n        _verify_and_throw(details::_in_streambuf_msg);\n    }\n\n    /// <summary>\n    /// Copy constructor\n    /// </summary>\n    /// <param name=\"other\">The source object</param>\n    basic_istream(const basic_istream& other) : m_helper(other.m_helper) {}\n\n    /// <summary>\n    /// Assignment operator\n    /// </summary>\n    /// <param name=\"other\">The source object</param>\n    /// <returns>A reference to the stream object that contains the result of the assignment.</returns>\n    basic_istream& operator=(const basic_istream& other)\n    {\n        m_helper = other.m_helper;\n        return *this;\n    }\n\n    /// <summary>\n    /// Close the stream, preventing further read operations.\n    /// </summary>\n    pplx::task<void> close() const\n    {\n        return is_valid() ? helper()->m_buffer.close(std::ios_base::in) : pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// Close the stream with exception, preventing further read operations.\n    /// </summary>\n    /// <param name=\"eptr\">Pointer to the exception.</param>\n    pplx::task<void> close(std::exception_ptr eptr) const\n    {\n        return is_valid() ? m_helper->m_buffer.close(std::ios_base::in, eptr) : pplx::task_from_result();\n    }\n\n    /// <summary>\n    /// Tests whether last read cause the stream reach EOF.\n    /// </summary>\n    /// <returns>True if the read head has reached the end of the stream, false otherwise.</returns>\n    bool is_eof() const { return is_valid() ? m_helper->m_buffer.is_eof() : false; }\n\n    /// <summary>\n    /// Get the next character and return it as an int_type. Advance the read position.\n    /// </summary>\n    /// <returns>A <c>task</c> that holds the next character as an <c>int_type</c> on successful completion.</returns>\n    pplx::task<int_type> read() const\n    {\n        pplx::task<int_type> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n        return helper()->m_buffer.bumpc();\n    }\n\n    /// <summary>\n    /// Read a single value of \"blittable\" type T from the stream.\n    /// </summary>\n    /// <returns>A value of type T.</returns>\n    /// <remarks>\n    /// This is not a replacement for a proper binary serialization solution, but it may\n    /// form the foundation for one. Reading data bit-wise to a stream is a primitive\n    /// operation of binary serialization.\n    /// Currently, no attention is paid to byte order. All data is read in the platform's\n    /// native byte order, which means little-endian on all platforms that have been tested.\n    /// This function is only available for streams using a single-byte character size.\n    /// </remarks>\n    template<typename T>\n    CASABLANCA_DEPRECATED(\n        \"Unsafe API that will be removed in future releases, use one of the other read overloads instead.\")\n    pplx::task<T> read() const\n    {\n        static_assert(sizeof(CharType) == 1, \"binary read is only supported for single-byte streams\");\n        static_assert(std::is_trivial<T>::value, \"unsafe to use with non-trivial types\");\n\n        pplx::task<T> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n\n        auto copy = std::make_shared<T>();\n        return helper()->m_buffer.getn((CharType*)copy.get(), sizeof(T)).then([copy](pplx::task<size_t>) -> T {\n            return std::move(*copy);\n        });\n    }\n\n    /// <summary>\n    /// Reads up to <c>count</c> characters and place into the provided buffer.\n    /// </summary>\n    /// <param name=\"target\">An async stream buffer supporting write operations.</param>\n    /// <param name=\"count\">The maximum number of characters to read</param>\n    /// <returns>A <c>task</c> that holds the number of characters read. This number is 0 if the end of the stream is\n    /// reached.</returns>\n    pplx::task<size_t> read(streams::streambuf<CharType> target, size_t count) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n        if (!target.can_write())\n            return pplx::task_from_exception<size_t>(\n                std::make_exception_ptr(std::runtime_error(\"target not set up for output of data\")));\n\n        // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.\n        auto buffer = helper()->m_buffer;\n\n        auto data = target.alloc(count);\n\n        if (data != nullptr)\n        {\n            auto post_read = [target](pplx::task<size_t> op) -> pplx::task<size_t> {\n                auto t = target;\n                t.commit(op.get());\n                return op;\n            };\n            return buffer.getn(data, count).then(post_read);\n        }\n        else\n        {\n            size_t available = 0;\n\n            const bool acquired = buffer.acquire(data, available);\n            if (available >= count)\n            {\n                auto post_write = [buffer, data](pplx::task<size_t> op) -> pplx::task<size_t> {\n                    auto b = buffer;\n                    b.release(data, op.get());\n                    return op;\n                };\n                return target.putn_nocopy(data, count).then(post_write);\n            }\n            else\n            {\n                // Always have to release if acquire returned true.\n                if (acquired)\n                {\n                    buffer.release(data, 0);\n                }\n\n                std::shared_ptr<CharType> buf(new CharType[count], [](CharType* buf) { delete[] buf; });\n\n                auto post_write = [buf](pplx::task<size_t> op) -> pplx::task<size_t> { return op; };\n                auto post_read = [buf, target, post_write](pplx::task<size_t> op) -> pplx::task<size_t> {\n                    auto trg = target;\n                    return trg.putn_nocopy(buf.get(), op.get()).then(post_write);\n                };\n\n                return helper()->m_buffer.getn(buf.get(), count).then(post_read);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Get the next character and return it as an int_type. Do not advance the read position.\n    /// </summary>\n    /// <returns>A <c>task</c> that holds the character, widened to an integer. This character is EOF when the peek\n    /// operation fails.</returns>\n    pplx::task<int_type> peek() const\n    {\n        pplx::task<int_type> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n        return helper()->m_buffer.getc();\n    }\n\n    /// <summary>\n    /// Read characters until a delimiter or EOF is found, and place them into the target.\n    /// Proceed past the delimiter, but don't include it in the target buffer.\n    /// </summary>\n    /// <param name=\"target\">An async stream buffer supporting write operations.</param>\n    /// <param name=\"delim\">The delimiting character to stop the read at.</param>\n    /// <returns>A <c>task</c> that holds the number of characters read.</returns>\n    pplx::task<size_t> read_to_delim(streams::streambuf<CharType> target, int_type delim) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n        if (!target.can_write())\n            return pplx::task_from_exception<size_t>(\n                std::make_exception_ptr(std::runtime_error(\"target not set up for output of data\")));\n\n        // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.\n        auto buffer = helper()->m_buffer;\n\n        int_type req_async = traits::requires_async();\n\n        std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>();\n\n        auto flush = [=]() mutable {\n            return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable {\n                _locals->total += wrote;\n                _locals->write_pos = 0;\n                return target.sync();\n            });\n        };\n\n        auto update = [=](int_type ch) mutable {\n            if (ch == traits::eof()) return false;\n            if (ch == delim) return false;\n\n            _locals->outbuf[_locals->write_pos] = static_cast<CharType>(ch);\n            _locals->write_pos += 1;\n\n            if (_locals->is_full())\n            {\n                // Flushing synchronously because performance is terrible if we\n                // schedule an empty task. This isn't on a user's thread.\n                flush().get();\n            }\n\n            return true;\n        };\n\n        auto loop = pplx::details::_do_while([=]() mutable -> pplx::task<bool> {\n            while (buffer.in_avail() > 0)\n            {\n                int_type ch = buffer.sbumpc();\n\n                if (ch == req_async)\n                {\n                    break;\n                }\n\n                if (!update(ch))\n                {\n                    return pplx::task_from_result(false);\n                }\n            }\n            return buffer.bumpc().then(update);\n        });\n\n        return loop.then([=](bool) mutable { return flush().then([=] { return _locals->total; }); });\n    }\n\n    /// <summary>\n    /// Read until reaching a newline character. The newline is not included in the target.\n    /// </summary>\n    /// <param name=\"target\">An asynchronous stream buffer supporting write operations.</param>\n    /// <returns>A <c>task</c> that holds the number of characters read. This number is 0 if the end of the stream is\n    /// reached.</returns>\n    pplx::task<size_t> read_line(streams::streambuf<CharType> target) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n        if (!target.can_write())\n            return pplx::task_from_exception<size_t>(\n                std::make_exception_ptr(std::runtime_error(\"target not set up for receiving data\")));\n\n        // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.\n        concurrency::streams::streambuf<CharType> buffer = helper()->m_buffer;\n\n        int_type req_async = traits::requires_async();\n\n        std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>();\n\n        auto flush = [=]() mutable {\n            return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable {\n                _locals->total += wrote;\n                _locals->write_pos = 0;\n                return target.sync();\n            });\n        };\n\n        auto update = [=](int_type ch) mutable {\n            if (ch == traits::eof()) return false;\n            if (ch == '\\n') return false;\n            if (ch == '\\r')\n            {\n                _locals->saw_CR = true;\n                return true;\n            }\n\n            _locals->outbuf[_locals->write_pos] = static_cast<CharType>(ch);\n            _locals->write_pos += 1;\n\n            if (_locals->is_full())\n            {\n                // Flushing synchronously because performance is terrible if we\n                // schedule an empty task. This isn't on a user's thread.\n                flush().wait();\n            }\n\n            return true;\n        };\n\n        auto update_after_cr = [=](int_type ch) mutable -> pplx::task<bool> {\n            if (ch == traits::eof()) return pplx::task_from_result(false);\n            if (ch == '\\n')\n            {\n                return buffer.bumpc().then([](int_type) { return false; });\n            }\n            return pplx::task_from_result(false);\n        };\n\n        auto loop = pplx::details::_do_while([=]() mutable -> pplx::task<bool> {\n            while (buffer.in_avail() > 0)\n            {\n                int_type ch;\n\n                if (_locals->saw_CR)\n                {\n                    ch = buffer.sgetc();\n                    if (ch == '\\n') buffer.sbumpc();\n                    return pplx::task_from_result(false);\n                }\n\n                ch = buffer.sbumpc();\n\n                if (ch == req_async) break;\n\n                if (!update(ch))\n                {\n                    return pplx::task_from_result(false);\n                }\n            }\n\n            if (_locals->saw_CR)\n            {\n                return buffer.getc().then(update_after_cr);\n            }\n            return buffer.bumpc().then(update);\n        });\n\n        return loop.then([=](bool) mutable { return flush().then([=] { return _locals->total; }); });\n    }\n\n    /// <summary>\n    /// Read until reaching the end of the stream.\n    /// </summary>\n    /// <param name=\"target\">An asynchronous stream buffer supporting write operations.</param>\n    /// <returns>The number of characters read.</returns>\n    pplx::task<size_t> read_to_end(streams::streambuf<CharType> target) const\n    {\n        pplx::task<size_t> result;\n        if (!_verify_and_return_task(\"stream not set up for output of data\", result)) return result;\n        if (!target.can_write())\n            return pplx::task_from_exception<size_t>(\n                std::make_exception_ptr(std::runtime_error(\"source buffer not set up for input of data\")));\n\n        auto l_buffer = helper()->m_buffer;\n        auto l_buf_size = this->buf_size;\n        std::shared_ptr<_read_helper> l_locals = std::make_shared<_read_helper>();\n\n        auto copy_to_target = [l_locals, target, l_buffer, l_buf_size]() mutable -> pplx::task<bool> {\n            // We need to capture these, because the object itself may go away\n            // before we're done processing the data.\n            // auto locs = _locals;\n            // auto trg = target;\n\n            return l_buffer.getn(l_locals->outbuf, l_buf_size).then([=](size_t rd) mutable -> pplx::task<bool> {\n                if (rd == 0) return pplx::task_from_result(false);\n\n                // Must be nested to capture rd\n                return target.putn_nocopy(l_locals->outbuf, rd)\n                    .then([target, l_locals, rd](size_t wr) mutable -> pplx::task<bool> {\n                        l_locals->total += wr;\n\n                        if (rd != wr)\n                            // Number of bytes written is less than number of bytes received.\n                            throw std::runtime_error(\"failed to write all bytes\");\n\n                        return target.sync().then([]() { return true; });\n                    });\n            });\n        };\n\n        auto loop = pplx::details::_do_while(copy_to_target);\n\n        return loop.then([=](bool) mutable -> size_t { return l_locals->total; });\n    }\n\n    /// <summary>\n    /// Seeks to the specified write position.\n    /// </summary>\n    /// <param name=\"pos\">An offset relative to the beginning of the stream.</param>\n    /// <returns>The new position in the stream.</returns>\n    pos_type seek(pos_type pos) const\n    {\n        _verify_and_throw(details::_in_stream_msg);\n        return helper()->m_buffer.seekpos(pos, std::ios_base::in);\n    }\n\n    /// <summary>\n    /// Seeks to the specified write position.\n    /// </summary>\n    /// <param name=\"off\">An offset relative to the beginning, current write position, or the end of the stream.</param>\n    /// <param name=\"way\">The starting point (beginning, current, end) for the seek.</param>\n    /// <returns>The new position in the stream.</returns>\n    pos_type seek(off_type off, std::ios_base::seekdir way) const\n    {\n        _verify_and_throw(details::_in_stream_msg);\n        return helper()->m_buffer.seekoff(off, way, std::ios_base::in);\n    }\n\n    /// <summary>\n    /// Get the current write position, i.e. the offset from the beginning of the stream.\n    /// </summary>\n    /// <returns>The current write position.</returns>\n    pos_type tell() const\n    {\n        _verify_and_throw(details::_in_stream_msg);\n        return helper()->m_buffer.getpos(std::ios_base::in);\n    }\n\n    /// <summary>\n    /// <c>can_seek<c/> is used to determine whether the stream supports seeking.\n    /// </summary>\n    /// <returns><c>true</c> if the stream supports seeking, <c>false</c> otherwise.</returns>\n    bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); }\n\n    /// <summary>\n    /// Test whether the stream has been initialized with a valid stream buffer.\n    /// </summary>\n    bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); }\n\n    /// <summary>\n    /// Test whether the stream has been initialized or not.\n    /// </summary>\n    operator bool() const { return is_valid(); }\n\n    /// <summary>\n    /// Test whether the stream is open for writing.\n    /// </summary>\n    /// <returns><c>true</c> if the stream is open for writing, <c>false</c> otherwise.</returns>\n    bool is_open() const { return is_valid() && m_helper->m_buffer.can_read(); }\n\n    /// <summary>\n    /// Get the underlying stream buffer.\n    /// </summary>\n    concurrency::streams::streambuf<CharType> streambuf() const { return helper()->m_buffer; }\n\n    /// <summary>\n    /// Read a value of type <c>T</c> from the stream.\n    /// </summary>\n    /// <remarks>\n    /// Supports the C++ primitive types. Can be expanded to additional types\n    /// by adding template specializations for <c>type_parser</c>.\n    /// </remarks>\n    /// <typeparam name=\"T\">\n    /// The data type of the element to be read from the stream.\n    /// </typeparam>\n    /// <returns>A <c>task</c> that holds the element read from the stream.</returns>\n    template<typename T>\n    pplx::task<T> extract() const\n    {\n        pplx::task<T> result;\n        if (!_verify_and_return_task(details::_in_stream_msg, result)) return result;\n        return type_parser<CharType, T>::parse(helper()->m_buffer);\n    }\n\nprivate:\n    template<typename T>\n    bool _verify_and_return_task(const char* msg, pplx::task<T>& tsk) const\n    {\n        auto buffer = helper()->m_buffer;\n        if (!(buffer.exception() == nullptr))\n        {\n            tsk = pplx::task_from_exception<T>(buffer.exception());\n            return false;\n        }\n        if (!buffer.can_read())\n        {\n            tsk = pplx::task_from_exception<T>(std::make_exception_ptr(std::runtime_error(msg)));\n            return false;\n        }\n        return true;\n    }\n\n    void _verify_and_throw(const char* msg) const\n    {\n        auto buffer = helper()->m_buffer;\n        if (!(buffer.exception() == nullptr)) std::rethrow_exception(buffer.exception());\n        if (!buffer.can_read()) throw std::runtime_error(msg);\n    }\n\n    std::shared_ptr<details::basic_istream_helper<CharType>> helper() const\n    {\n        if (!m_helper) throw std::logic_error(\"uninitialized stream object\");\n        return m_helper;\n    }\n\n    static const size_t buf_size = 16 * 1024;\n\n    struct _read_helper\n    {\n        size_t total;\n        CharType outbuf[buf_size];\n        size_t write_pos;\n        bool saw_CR;\n\n        bool is_full() const { return write_pos == buf_size; }\n\n        _read_helper() : total(0), write_pos(0), saw_CR(false) {}\n    };\n\n    std::shared_ptr<details::basic_istream_helper<CharType>> m_helper;\n};\n\ntypedef basic_ostream<uint8_t> ostream;\ntypedef basic_istream<uint8_t> istream;\n\ntypedef basic_ostream<utf16char> wostream;\ntypedef basic_istream<utf16char> wistream;\n\ntemplate<typename CharType>\npplx::task<void> _type_parser_base<CharType>::_skip_whitespace(streams::streambuf<CharType> buffer)\n{\n    int_type req_async = traits::requires_async();\n\n    auto update = [=](int_type ch) mutable {\n        if (isspace(ch))\n        {\n            if (buffer.sbumpc() == req_async)\n            {\n                // Synchronously because performance is terrible if we\n                // schedule an empty task. This isn't on a user's thread.\n                buffer.nextc().wait();\n            }\n            return true;\n        }\n\n        return false;\n    };\n\n    auto loop = pplx::details::_do_while([=]() mutable -> pplx::task<bool> {\n        while (buffer.in_avail() > 0)\n        {\n            int_type ch = buffer.sgetc();\n\n            if (ch == req_async) break;\n\n            if (!update(ch))\n            {\n                return pplx::task_from_result(false);\n            }\n        }\n        return buffer.getc().then(update);\n    });\n\n    return loop.then([=](pplx::task<bool> op) { op.wait(); });\n}\n\ntemplate<typename CharType>\ntemplate<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>\npplx::task<ReturnType> _type_parser_base<CharType>::_parse_input(concurrency::streams::streambuf<CharType> buffer,\n                                                                 AcceptFunctor accept_character,\n                                                                 ExtractFunctor extract)\n{\n    std::shared_ptr<StateType> state = std::make_shared<StateType>();\n\n    auto update = [=](pplx::task<int_type> op) -> pplx::task<bool> {\n        int_type ch = op.get();\n        if (ch == traits::eof()) return pplx::task_from_result(false);\n        bool accepted = accept_character(state, ch);\n        if (!accepted) return pplx::task_from_result(false);\n        // We peeked earlier, so now we must advance the position.\n        concurrency::streams::streambuf<CharType> buf = buffer;\n        return buf.bumpc().then([](int_type) { return true; });\n    };\n\n    auto peek_char = [=]() -> pplx::task<bool> {\n        concurrency::streams::streambuf<CharType> buf = buffer;\n\n        // If task results are immediately available, there's little need to use \".then(),\"\n        // so optimize for prompt values.\n\n        auto get_op = buf.getc();\n        while (get_op.is_done())\n        {\n            auto condition = update(get_op);\n            if (!condition.is_done() || !condition.get()) return condition;\n\n            get_op = buf.getc();\n        }\n\n        return get_op.then(update);\n    };\n\n    auto finish = [=](pplx::task<bool> op) -> pplx::task<ReturnType> {\n        op.wait();\n        pplx::task<ReturnType> result = extract(state);\n        return result;\n    };\n\n    return _skip_whitespace(buffer).then([=](pplx::task<void> op) -> pplx::task<ReturnType> {\n        op.wait();\n        return pplx::details::_do_while(peek_char).then(finish);\n    });\n}\n\ntemplate<typename CharType>\nclass type_parser<CharType, std::basic_string<CharType>> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<std::string> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<std::basic_string<CharType>, std::string>(\n            buffer, _accept_char, _extract_result);\n    }\n\nprivate:\n    static bool _accept_char(std::shared_ptr<std::basic_string<CharType>> state, int_type ch)\n    {\n        if (ch == traits::eof() || isspace(ch)) return false;\n        state->push_back(CharType(ch));\n        return true;\n    }\n    static pplx::task<std::basic_string<CharType>> _extract_result(std::shared_ptr<std::basic_string<CharType>> state)\n    {\n        return pplx::task_from_result(*state);\n    }\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, int64_t> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<int64_t> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<_int64_state, int64_t>(buffer, _accept_char, _extract_result);\n    }\n\nprivate:\n    struct _int64_state\n    {\n        _int64_state() : result(0), correct(false), minus(0) {}\n\n        int64_t result;\n        bool correct;\n        char minus; // 0 -- no sign, 1 -- plus, 2 -- minus\n    };\n\n    static bool _accept_char(std::shared_ptr<_int64_state> state, int_type ch)\n    {\n        if (ch == traits::eof()) return false;\n        if (state->minus == 0)\n        {\n            // OK to find a sign.\n            if (!::isdigit(ch) && ch != int_type('+') && ch != int_type('-')) return false;\n        }\n        else\n        {\n            if (!::isdigit(ch)) return false;\n        }\n\n        // At least one digit was found.\n        state->correct = true;\n\n        if (ch == int_type('+'))\n        {\n            state->minus = 1;\n        }\n        else if (ch == int_type('-'))\n        {\n            state->minus = 2;\n        }\n        else\n        {\n            if (state->minus == 0) state->minus = 1;\n\n            // Shift the existing value by 10, then add the new value.\n            bool positive = state->result >= 0;\n\n            state->result *= 10;\n            state->result += int64_t(ch - int_type('0'));\n\n            if ((state->result >= 0) != positive)\n            {\n                state->correct = false;\n                return false;\n            }\n        }\n        return true;\n    }\n\n    static pplx::task<int64_t> _extract_result(std::shared_ptr<_int64_state> state)\n    {\n        if (!state->correct) throw std::range_error(\"integer value is too large to fit in 64 bits\");\n\n        int64_t result = (state->minus == 2) ? -state->result : state->result;\n        return pplx::task_from_result<int64_t>(result);\n    }\n};\n\ntemplate<typename FloatingPoint>\nstruct _double_state\n{\n    _double_state()\n        : result(0)\n        , minus(0)\n        , after_comma(0)\n        , exponent(false)\n        , exponent_number(0)\n        , exponent_minus(0)\n        , complete(false)\n        , p_exception_string()\n    {\n    }\n\n    FloatingPoint result;\n    char minus; // 0 -- no sign, 1 -- plus, 2 -- minus\n    int after_comma;\n    bool exponent;\n    int exponent_number;\n    char exponent_minus; // 0 -- no sign, 1 -- plus, 2 -- minus\n    bool complete;\n    std::string p_exception_string;\n};\n\ntemplate<typename FloatingPoint, typename int_type>\nstatic std::string create_exception_message(int_type ch, bool exponent)\n{\n    std::string result;\n    if (exponent)\n    {\n        result.assign(\"Invalid character 'X' in exponent\");\n    }\n    else\n    {\n        result.assign(\"Invalid character 'X'\");\n    }\n\n    result[19] = static_cast<char>(ch);\n    return result;\n}\n\ntemplate<typename FloatingPoint, typename int_type>\nstatic bool _accept_char(std::shared_ptr<_double_state<FloatingPoint>> state, int_type ch)\n{\n    if (state->minus == 0)\n    {\n        if (!::isdigit(ch) && ch != int_type('.') && ch != int_type('+') && ch != int_type('-'))\n        {\n            if (!state->complete)\n                state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, false);\n            return false;\n        }\n    }\n    else\n    {\n        if (!state->exponent && !::isdigit(ch) && ch != int_type('.') && ch != int_type('E') && ch != int_type('e'))\n        {\n            if (!state->complete)\n                state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, false);\n            return false;\n        }\n\n        if (state->exponent && !::isdigit(ch) && ch != int_type('+') && ch != int_type('-'))\n        {\n            if (!state->complete)\n                state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, true);\n            return false;\n        }\n    }\n\n    switch (ch)\n    {\n        case int_type('+'):\n            state->complete = false;\n            if (state->exponent)\n            {\n                if (state->exponent_minus != 0)\n                {\n                    state->p_exception_string = \"The exponent sign already set\";\n                    return false;\n                }\n                state->exponent_minus = 1;\n            }\n            else\n            {\n                state->minus = 1;\n            }\n            break;\n        case int_type('-'):\n            state->complete = false;\n            if (state->exponent)\n            {\n                if (state->exponent_minus != 0)\n                {\n                    state->p_exception_string = \"The exponent sign already set\";\n                    return false;\n                }\n\n                state->exponent_minus = 2;\n            }\n            else\n            {\n                state->minus = 2;\n            }\n            break;\n        case int_type('.'):\n            state->complete = false;\n            if (state->after_comma > 0) return false;\n\n            state->after_comma = 1;\n            break;\n        case int_type('E'):\n        case int_type('e'):\n            state->complete = false;\n            if (state->exponent) return false;\n            state->exponent_number = 0;\n            state->exponent = true;\n            break;\n        default:\n            state->complete = true;\n            if (!state->exponent)\n            {\n                if (state->minus == 0) state->minus = 1;\n\n                state->result *= 10;\n                state->result += int64_t(ch - int_type('0'));\n\n                if (state->after_comma > 0) state->after_comma++;\n            }\n            else\n            {\n                if (state->exponent_minus == 0) state->exponent_minus = 1;\n                state->exponent_number *= 10;\n                state->exponent_number += int64_t(ch - int_type('0'));\n            }\n    }\n    return true;\n}\n\ntemplate<typename FloatingPoint>\nstatic pplx::task<FloatingPoint> _extract_result(std::shared_ptr<_double_state<FloatingPoint>> state)\n{\n    if (state->p_exception_string.length() > 0) throw std::runtime_error(state->p_exception_string.c_str());\n\n    if (!state->complete && state->exponent) throw std::runtime_error(\"Incomplete exponent\");\n\n    FloatingPoint result = static_cast<FloatingPoint>((state->minus == 2) ? -state->result : state->result);\n    if (state->exponent_minus == 2) state->exponent_number = 0 - state->exponent_number;\n\n    if (state->after_comma > 0) state->exponent_number -= state->after_comma - 1;\n\n    if (state->exponent_number >= 0)\n    {\n        result *= static_cast<FloatingPoint>(\n            std::pow(static_cast<FloatingPoint>(10.0), static_cast<FloatingPoint>(state->exponent_number)));\n\n#pragma push_macro(\"max\")\n#undef max\n\n        if (result > std::numeric_limits<FloatingPoint>::max() || result < -std::numeric_limits<FloatingPoint>::max())\n            throw std::overflow_error(\"The value is too big\");\n#pragma pop_macro(\"max\")\n    }\n    else\n    {\n        bool is_zero = (result == 0);\n\n        result /= static_cast<FloatingPoint>(\n            std::pow(static_cast<FloatingPoint>(10.0), static_cast<FloatingPoint>(-state->exponent_number)));\n\n        if (!is_zero && result > -std::numeric_limits<FloatingPoint>::denorm_min() &&\n            result < std::numeric_limits<FloatingPoint>::denorm_min())\n            throw std::underflow_error(\"The value is too small\");\n    }\n\n    return pplx::task_from_result<FloatingPoint>(result);\n}\n\ntemplate<typename CharType>\nclass type_parser<CharType, double> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<double> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<_double_state<double>, double>(\n            buffer, _accept_char<double, int_type>, _extract_result<double>);\n    }\n\nprotected:\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, float> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<float> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<_double_state<float>, float>(\n            buffer, _accept_char<float, int_type>, _extract_result<float>);\n    }\n\nprotected:\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, uint64_t> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<uint64_t> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<_uint64_state, uint64_t>(buffer, _accept_char, _extract_result);\n    }\n\nprivate:\n    struct _uint64_state\n    {\n        _uint64_state() : result(0), correct(false) {}\n        uint64_t result;\n        bool correct;\n    };\n\n    static bool _accept_char(std::shared_ptr<_uint64_state> state, int_type ch)\n    {\n        if (!::isdigit(ch)) return false;\n\n        // At least one digit was found.\n        state->correct = true;\n\n        // Shift the existing value by 10, then add the new value.\n        state->result *= 10;\n        state->result += uint64_t(ch - int_type('0'));\n\n        return true;\n    }\n\n    static pplx::task<uint64_t> _extract_result(std::shared_ptr<_uint64_state> state)\n    {\n        if (!state->correct) throw std::range_error(\"integer value is too large to fit in 64 bits\");\n        return pplx::task_from_result(state->result);\n    }\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, bool> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<bool> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<_bool_state, bool>(buffer, _accept_char, _extract_result);\n    }\n\nprivate:\n    struct _bool_state\n    {\n        _bool_state() : state(0) {}\n        // { 0 -- not started, 1 -- 't', 2 -- 'tr', 3 -- 'tru', 4 -- 'f', 5 -- 'fa', 6 -- 'fal', 7 -- 'fals', 8 --\n        // 'true', 9 -- 'false' }\n        short state;\n    };\n\n    static bool _accept_char(std::shared_ptr<_bool_state> state, int_type ch)\n    {\n        switch (state->state)\n        {\n            case 0:\n                if (ch == int_type('t'))\n                    state->state = 1;\n                else if (ch == int_type('f'))\n                    state->state = 4;\n                else if (ch == int_type('1'))\n                    state->state = 8;\n                else if (ch == int_type('0'))\n                    state->state = 9;\n                else\n                    return false;\n                break;\n            case 1:\n                if (ch == int_type('r'))\n                    state->state = 2;\n                else\n                    return false;\n                break;\n            case 2:\n                if (ch == int_type('u'))\n                    state->state = 3;\n                else\n                    return false;\n                break;\n            case 3:\n                if (ch == int_type('e'))\n                    state->state = 8;\n                else\n                    return false;\n                break;\n            case 4:\n                if (ch == int_type('a'))\n                    state->state = 5;\n                else\n                    return false;\n                break;\n            case 5:\n                if (ch == int_type('l'))\n                    state->state = 6;\n                else\n                    return false;\n                break;\n            case 6:\n                if (ch == int_type('s'))\n                    state->state = 7;\n                else\n                    return false;\n                break;\n            case 7:\n                if (ch == int_type('e'))\n                    state->state = 9;\n                else\n                    return false;\n                break;\n            case 8:\n            case 9: return false;\n        }\n        return true;\n    }\n    static pplx::task<bool> _extract_result(std::shared_ptr<_bool_state> state)\n    {\n        bool correct = (state->state == 8 || state->state == 9);\n        if (!correct)\n        {\n            std::runtime_error exc(\"cannot parse as Boolean value\");\n            throw exc;\n        }\n        return pplx::task_from_result(state->state == 8);\n    }\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, signed char> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<signed char> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::_skip_whitespace(buffer).then([=](pplx::task<void> op) -> pplx::task<signed char> {\n            op.wait();\n            return type_parser<CharType, signed char>::_get_char(buffer);\n        });\n    }\n\nprivate:\n    static pplx::task<signed char> _get_char(streams::streambuf<CharType> buffer)\n    {\n        concurrency::streams::streambuf<CharType> buf = buffer;\n        return buf.bumpc().then([=](pplx::task<int_type> op) -> signed char {\n            int_type val = op.get();\n            if (val == traits::eof()) throw std::runtime_error(\"reached end-of-stream while constructing a value\");\n            return static_cast<signed char>(val);\n        });\n    }\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, unsigned char> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<unsigned char> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::_skip_whitespace(buffer).then([=](pplx::task<void> op) -> pplx::task<unsigned char> {\n            op.wait();\n            return type_parser<CharType, unsigned char>::_get_char(buffer);\n        });\n    }\n\nprivate:\n    static pplx::task<unsigned char> _get_char(streams::streambuf<CharType> buffer)\n    {\n        concurrency::streams::streambuf<CharType> buf = buffer;\n        return buf.bumpc().then([=](pplx::task<int_type> op) -> unsigned char {\n            int_type val = op.get();\n            if (val == traits::eof()) throw std::runtime_error(\"reached end-of-stream while constructing a value\");\n            return static_cast<unsigned char>(val);\n        });\n    }\n};\n\ntemplate<typename CharType>\nclass type_parser<CharType, char> : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<char> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::_skip_whitespace(buffer).then([=](pplx::task<void> op) -> pplx::task<char> {\n            op.wait();\n            return _get_char(buffer);\n        });\n    }\n\nprivate:\n    static pplx::task<char> _get_char(streams::streambuf<CharType> buffer)\n    {\n        concurrency::streams::streambuf<CharType> buf = buffer;\n        return buf.bumpc().then([=](pplx::task<int_type> op) -> char {\n            int_type val = op.get();\n            if (val == traits::eof()) throw std::runtime_error(\"reached end-of-stream while constructing a value\");\n            return char(val);\n        });\n    }\n};\n\n#ifdef _WIN32\ntemplate<class CharType>\nclass type_parser<CharType, std::enable_if_t<sizeof(CharType) == 1, std::basic_string<wchar_t>>>\n    : public _type_parser_base<CharType>\n{\n    typedef _type_parser_base<CharType> base;\n\npublic:\n    typedef typename base::traits traits;\n    typedef typename base::int_type int_type;\n\n    static pplx::task<std::wstring> parse(streams::streambuf<CharType> buffer)\n    {\n        return base::template _parse_input<std::basic_string<char>, std::basic_string<wchar_t>>(\n            buffer, _accept_char, _extract_result);\n    }\n\nprivate:\n    static bool _accept_char(const std::shared_ptr<std::basic_string<char>>& state, int_type ch)\n    {\n        if (ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;\n        state->push_back(char(ch));\n        return true;\n    }\n    static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)\n    {\n        return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));\n    }\n};\n#endif //_WIN32\n\n} // namespace streams\n} // namespace Concurrency\n\n#endif\n#endif // !XSAPI_NO_PPL\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/uri.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Protocol independent support for URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#ifndef _CASA_URI_H\n#define _CASA_URI_H\n\n#include \"cpprest/base_uri.h\"\n#include \"cpprest/uri_builder.h\"\n\n#endif\n\n\n"
  },
  {
    "path": "Include/cpprestinclude/cpprest/uri_builder.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Builder style class for creating URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include \"cpprest/base_uri.h\"\n#include \"cpprest/details/uri_parser.h\"\n\nnamespace web\n{\n    /// <summary>\n    /// Builder for constructing URIs incrementally.\n    /// </summary>\n    class uri_builder\n    {\n    public:\n\n        /// <summary>\n        /// Creates a builder with an initially empty URI.\n        /// </summary>\n        uri_builder() {}\n\n        /// <summary>\n        /// Creates a builder with a existing URI object.\n        /// </summary>\n        /// <param name=\"uri_str\">Encoded string containing the URI.</param>\n        uri_builder(const uri &uri_str): m_uri(uri_str.m_components) {}\n\n        /// <summary>\n        /// Get the scheme component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI scheme as a string.</returns>\n        const utility::string_t &scheme() const { return m_uri.m_scheme; }\n\n        /// <summary>\n        /// Get the user information component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI user information as a string.</returns>\n        const utility::string_t &user_info() const { return m_uri.m_user_info; }\n\n        /// <summary>\n        /// Get the host component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI host as a string.</returns>\n        const utility::string_t &host() const { return m_uri.m_host; }\n\n        /// <summary>\n        /// Get the port component of the URI. Returns -1 if no port is specified.\n        /// </summary>\n        /// <returns>The URI port as an integer.</returns>\n        int port() const { return m_uri.m_port; }\n\n        /// <summary>\n        /// Get the path component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI path as a string.</returns>\n        const utility::string_t &path() const { return m_uri.m_path; }\n\n        /// <summary>\n        /// Get the query component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI query as a string.</returns>\n        const utility::string_t &query() const { return m_uri.m_query; }\n\n        /// <summary>\n        /// Get the fragment component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI fragment as a string.</returns>\n        const utility::string_t &fragment() const { return m_uri.m_fragment; }\n\n        /// <summary>\n        /// Set the scheme of the URI.\n        /// </summary>\n        /// <param name=\"scheme\">Uri scheme.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_scheme(const utility::string_t &scheme)\n        {\n            m_uri.m_scheme = scheme;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the user info component of the URI.\n        /// </summary>\n        /// <param name=\"user_info\">User info as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_user_info(const utility::string_t &user_info, bool do_encoding = false)\n        {\n            m_uri.m_user_info = do_encoding ? uri::encode_uri(user_info, uri::components::user_info) : user_info;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the host component of the URI.\n        /// </summary>\n        /// <param name=\"host\">Host as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_host(const utility::string_t &host, bool do_encoding = false)\n        {\n            m_uri.m_host = do_encoding ? uri::encode_uri(host, uri::components::host) : host;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the port component of the URI.\n        /// </summary>\n        /// <param name=\"port\">Port as an integer.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_port(int port)\n        {\n            m_uri.m_port = port;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the port component of the URI.\n        /// </summary>\n        /// <param name=\"port\">Port as a string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        /// <remarks>When string can't be converted to an integer the port is left unchanged.</remarks>\n        uri_builder & set_port(const utility::string_t &port)\n        {\n            utility::istringstream_t portStream(port);\n            int port_tmp;\n            portStream >> port_tmp;\n            if(portStream.fail() || portStream.bad())\n            {\n                throw std::invalid_argument(\"invalid port argument, must be non empty string containing integer value\");\n            }\n            m_uri.m_port = port_tmp;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the path component of the URI.\n        /// </summary>\n        /// <param name=\"path\">Path as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_path(const utility::string_t &path, bool do_encoding = false)\n        {\n            m_uri.m_path = do_encoding ? uri::encode_uri(path, uri::components::path) : path;\n            return *this;\n        }\n\n\n        /// <summary>\n        /// Set the query component of the URI.\n        /// </summary>\n        /// <param name=\"query\">Query as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_query(const utility::string_t &query, bool do_encoding = false)\n        {\n            m_uri.m_query = do_encoding ? uri::encode_uri(query, uri::components::query) : query;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the fragment component of the URI.\n        /// </summary>\n        /// <param name=\"fragment\">Fragment as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_fragment(const utility::string_t &fragment, bool do_encoding = false)\n        {\n            m_uri.m_fragment = do_encoding ? uri::encode_uri(fragment, uri::components::fragment) : fragment;\n            return *this;\n        }\n\n        /// <summary>\n        /// Clears all components of the underlying URI in this uri_builder.\n        /// </summary>\n        void clear()\n        {\n            m_uri = details::uri_components();\n        }\n\n        /// <summary>\n        /// Appends another path to the path of this uri_builder.\n        /// </summary>\n        /// <param name=\"path\">Path to append as a already encoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        _ASYNCRTIMP uri_builder &append_path(const utility::string_t &path, bool do_encoding = false);\n\n        /// <summary>\n        /// Appends another query to the query of this uri_builder.\n        /// </summary>\n        /// <param name=\"query\">Query to append as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        _ASYNCRTIMP uri_builder &append_query(const utility::string_t &query, bool do_encoding = false);\n\n        /// <summary>\n        /// Appends an relative uri (Path, Query and fragment) at the end of the current uri.\n        /// </summary>\n        /// <param name=\"relative_uri\">The relative uri to append.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        _ASYNCRTIMP uri_builder &append(const uri &relative_uri);\n\n        /// <summary>\n        /// Appends another query to the query of this uri_builder, encoding it first. This overload is useful when building a query segment of\n        /// the form \"element=10\", where the right hand side of the query is stored as a type other than a string, for instance, an integral type.\n        /// </summary>\n        /// <param name=\"name\">The name portion of the query string</param>\n        /// <param name=\"value\">The value portion of the query string</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        template<typename T>\n        uri_builder &append_query(const utility::string_t &name, const T &value, bool do_encoding = true)\n        {\n            auto encodedName = name;\n            auto encodedValue = ::utility::conversions::print_string(value, std::locale::classic());\n\n            if (do_encoding)\n            {\n                auto encodingCheck = [](int ch)\n                {\n                    switch (ch)\n                    {\n                        // Encode '&', ';', and '=' since they are used\n                        // as delimiters in query component.\n                    case '&':\n                    case ';':\n                    case '=':\n                    case '%':\n                    case '+':\n                        return true;\n                    default:\n                        return !::web::details::uri_parser::is_query_character(ch);\n                    }\n                };\n                encodedName = uri::encode_impl(encodedName, encodingCheck);\n                encodedValue = uri::encode_impl(encodedValue, encodingCheck);\n            }\n\n            auto encodedQuery = encodedName;\n            encodedQuery.append(_XPLATSTR(\"=\"));\n            encodedQuery.append(encodedValue);\n            // The query key value pair was already encoded by us or the user separately.\n            return append_query(encodedQuery, false);\n        }\n\n        /// <summary>\n        /// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is invalid.\n        /// </summary>\n        /// <returns>The created URI as a string.</returns>\n        _ASYNCRTIMP utility::string_t to_string();\n\n        /// <summary>\n        /// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is invalid.\n        /// </summary>\n        /// <returns>The create URI as a URI class instance.</returns>\n        _ASYNCRTIMP uri to_uri();\n\n        /// <summary>\n        /// Validate the generated URI from all existing components of this uri_builder.\n        /// </summary>\n        /// <returns>Whether the URI is valid.</returns>\n        _ASYNCRTIMP bool is_valid();\n\n    private:\n        details::uri_components m_uri;\n    };\n} // namespace web\n"
  },
  {
    "path": "Include/cpprestinclude/cpprestsdk_impl.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"cpprest/details/asyncrt_utils.hpp\"\n#include \"cpprest/details/json_parsing.hpp\"\n#include \"cpprest/details/json_serialization.hpp\"\n#include \"cpprest/details/json.hpp\"\n#include \"cpprest/details/uri.hpp\"\n#include \"cpprest/details/uri_builder.hpp\"\n#include \"cpprest/details/uri_parser.hpp\"\n#include \"cpprest/details/http_msg.hpp\"\n#include \"cpprest/details/http_helpers.hpp\"\n#include \"cpprest/details/base64.hpp\"\n#include \"cpprest/details/http_client_msg.hpp\"\n\n#if !XSAPI_NO_PPL\n    #include \"pplx/details/pplx.hpp\"\n    #if HC_PLATFORM == HC_PLATFORM_ANDROID\n        #include \"pplx/details/pplxlinux.hpp\"\n        #include \"pplx/details/threadpool.hpp\"\n    #elif HC_PLATFORM == HC_PLATFORM_IOS\n        #include \"pplx/details/pplxapple.hpp\"\n    #elif HC_PLATFORM_IS_MICROSOFT\n        #include \"pplx/details/pplxwin.hpp\"\n    #endif\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/details/pplx.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library implementation (common code across platforms)\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX\n\n#include \"pplx/pplx.h\"\n\n// Disable false alarm code analyze warning\n#if defined(_MSC_VER)\n#pragma warning (disable : 26165 26110)\n#endif\n\nnamespace pplx\n{\n\n\nnamespace details\n{\n    /// <summary>\n    /// Spin lock to allow for locks to be used in global scope\n    /// </summary>\n    class _Spin_lock\n    {\n    public:\n\n        _Spin_lock()\n            : _M_lock(0)\n        {\n        }\n\n        void lock()\n        {\n            if ( details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l )\n            {\n                do\n                {\n                    pplx::details::platform::YieldExecution();\n\n                } while ( details::atomic_compare_exchange(_M_lock, 1l, 0l) != 0l );\n            }\n        }\n\n        void unlock()\n        {\n            // fence for release semantics\n            details::atomic_exchange(_M_lock, 0l);\n        }\n\n    private:\n        atomic_long _M_lock;\n    };\n\n    typedef ::pplx::scoped_lock<_Spin_lock> _Scoped_spin_lock;\n} // namespace details\n\nstatic struct _pplx_g_sched_t\n{\n    typedef std::shared_ptr<pplx::scheduler_interface> sched_ptr;\n\n    _pplx_g_sched_t()\n    {\n        m_state = post_ctor;\n    }\n\n    ~_pplx_g_sched_t()\n    {\n        m_state = post_dtor;\n    }\n\n    sched_ptr get_scheduler()\n    {\n        switch (m_state)\n        {\n        case post_ctor:\n            // This is the 99.9% case.\n\n            if (!m_scheduler)\n            {\n                ::pplx::details::_Scoped_spin_lock lock(m_spinlock);\n                if (!m_scheduler)\n                {\n                    m_scheduler = std::make_shared< ::pplx::default_scheduler_t>();\n                }\n            }\n\n            return m_scheduler;\n        default:\n            // This case means the global m_scheduler is not available.\n            // We spin off an individual scheduler instead.\n            return std::make_shared< ::pplx::default_scheduler_t>();\n        }\n    }\n\n    void set_scheduler(sched_ptr scheduler)\n    {\n        if (m_state == pre_ctor || m_state == post_dtor) {\n            throw invalid_operation(\"Scheduler cannot be initialized now\");\n        }\n\n        ::pplx::details::_Scoped_spin_lock lock(m_spinlock);\n\n        if (m_scheduler != nullptr)\n        {\n            throw invalid_operation(\"Scheduler is already initialized\");\n        }\n\n        m_scheduler = std::move(scheduler);\n    }\n\n    enum\n    {\n        pre_ctor = 0,\n        post_ctor = 1,\n        post_dtor = 2\n    } m_state;\n\nprivate:\n    pplx::details::_Spin_lock m_spinlock;\n    sched_ptr m_scheduler;\n} _pplx_g_sched;\n\n_PPLXIMP std::shared_ptr<pplx::scheduler_interface> _pplx_cdecl get_ambient_scheduler()\n{\n    return _pplx_g_sched.get_scheduler();\n}\n\n_PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler)\n{\n    _pplx_g_sched.set_scheduler(std::move(_Scheduler));\n}\n\n} // namespace pplx\n\n#endif\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/details/pplxapple.hpp",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n *\n * Apple-specific pplx implementations\n *\n * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n ****/\n\n#pragma once\n\n#include <errno.h>\n#include <sys/time.h>\n#include <pthread.h>\n#include <dispatch/dispatch.h>\n#include <libkern/OSAtomic.h>\n#include \"pplx/pplx.h\"\n\n// DEVNOTE:\n// The use of mutexes is suboptimal for synchronization of task execution.\n// Given that scheduler implementations should use GCD queues, there are potentially better mechanisms available to coordinate tasks (such as dispatch groups).\n\nnamespace pplx\n{\n\nnamespace details {\n\n    namespace platform\n    {\n        _PPLXIMP long GetCurrentThreadId()\n        {\n            pthread_t threadId = pthread_self();\n            return (long)threadId;\n        }\n\n        void YieldExecution()\n        {\n            sleep(0);\n        }\n\n    } // namespace platform\n\n    void apple_scheduler::schedule( TaskProc_t proc, void* param)\n    {\n        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);\n        dispatch_async_f(queue, param, proc);\n    }\n\n} // namespace details\n\n} // pplx\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/details/pplxlinux.hpp",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library - Linux version\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include \"pplx/pplx.h\"\n#include \"pplx/threadpool.h\"\n#include \"sys/syscall.h\"\n\n#ifdef _WIN32\n#error \"ERROR: This file should only be included in non-windows Build\"\n#endif\n\nnamespace pplx\n{\n\nnamespace details {\n\n    namespace platform\n    {\n        _PPLXIMP long GetCurrentThreadId()\n        {\n            return reinterpret_cast<long>(reinterpret_cast<void*>(pthread_self()));\n        }\n\n        _PPLXIMP void YieldExecution()\n        {\n            std::this_thread::yield();\n        }\n    }\n\n    _PPLXIMP void linux_scheduler::schedule(TaskProc_t proc, void* param)\n    {\n        crossplat::threadpool::shared_instance().service().post(std::bind(proc, param));\n    }\n\n} // namespace details\n\n} // namespace pplx"
  },
  {
    "path": "Include/cpprestinclude/pplx/details/pplxwin.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Windows specific implementation of PPL constructs\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX\n\n#include \"pplx/pplxwin.h\"\n\n// Disable false alarm code analysis warning\n#pragma warning (disable : 26165 26110)\nnamespace pplx\n{\nnamespace details\n{\n    namespace platform\n    {\n        _PPLXIMP long __cdecl GetCurrentThreadId()\n        {\n            return (long)(::GetCurrentThreadId());\n        }\n\n        _PPLXIMP void __cdecl YieldExecution()\n        {\n            YieldProcessor();\n        }\n\n        _PPLXIMP size_t __cdecl CaptureCallstack(void **stackData, size_t skipFrames, size_t captureFrames)\n        {\n            (stackData);\n            (skipFrames);\n            (captureFrames);\n\n            size_t capturedFrames = 0;\n            // RtlCaptureSTackBackTrace is not available in MSDK, so we only call it under Desktop or _DEBUG MSDK.\n            //  For MSDK unsupported version, we will return zero frame number.\n#if !defined(__cplusplus_winrt)\n            capturedFrames = RtlCaptureStackBackTrace(static_cast<DWORD>(skipFrames + 1), static_cast<DWORD>(captureFrames), stackData, nullptr);\n#endif\n            return capturedFrames;\n        }\n\n#if defined(__cplusplus_winrt)\n        volatile long s_asyncId = 0;\n\n        _PPLXIMP unsigned int __cdecl GetNextAsyncId()\n        {\n            return static_cast<unsigned int>(_InterlockedIncrement(&s_asyncId));\n        }\n\n#endif // defined(__cplusplus_winrt)\n\n        void InitializeCriticalSection(LPCRITICAL_SECTION _cs)\n        {\n#ifndef __cplusplus_winrt\n            // InitializeCriticalSection can cause STATUS_NO_MEMORY see C28125\n            __try {\n                ::InitializeCriticalSection(_cs);\n            }\n            __except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)\n            {\n                throw ::std::bad_alloc();\n            }\n#else\n            InitializeCriticalSectionEx(_cs, 0, 0);\n#endif // !__cplusplus_winrt\n        }\n\n    }\n\n    //\n    // Event implementation\n    //\n    _PPLXIMP event_impl::event_impl()\n    {\n        static_assert(sizeof(HANDLE) <= sizeof(_M_impl), \"HANDLE version mismatch\");\n\n#ifndef __cplusplus_winrt\n        _M_impl = CreateEvent(NULL, true, false, NULL);\n#else\n        _M_impl = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);\n#endif // !__cplusplus_winrt\n\n        if( _M_impl != NULL )\n        {\n            ResetEvent(static_cast<HANDLE>(_M_impl));\n        }\n    }\n\n    _PPLXIMP event_impl::~event_impl()\n    {\n        CloseHandle(static_cast<HANDLE>(_M_impl));\n    }\n\n    _PPLXIMP void event_impl::set()\n    {\n        SetEvent(static_cast<HANDLE>(_M_impl));\n    }\n\n    _PPLXIMP void event_impl::reset()\n    {\n        ResetEvent(static_cast<HANDLE>(_M_impl));\n    }\n\n    _PPLXIMP unsigned int event_impl::wait(unsigned int timeout)\n    {\n        DWORD waitTime = (timeout == event_impl::timeout_infinite) ?  INFINITE : (DWORD)timeout;\n        DWORD status = WaitForSingleObjectEx(static_cast<HANDLE>(_M_impl), waitTime, 0);\n        _ASSERTE((status == WAIT_OBJECT_0) || (waitTime != INFINITE));\n\n        return (status == WAIT_OBJECT_0) ? 0 : event_impl::timeout_infinite;\n    }\n\n    //\n    // critical_section implementation\n    //\n    // TFS# 612702 -- this implementation is unnecessarily recursive. See bug for details.\n    _PPLXIMP critical_section_impl::critical_section_impl()\n    {\n        static_assert(sizeof(CRITICAL_SECTION) <= sizeof(_M_impl), \"CRITICAL_SECTION version mismatch\");\n\n        platform::InitializeCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));\n    }\n\n    _PPLXIMP critical_section_impl::~critical_section_impl()\n    {\n        DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));\n    }\n\n    _PPLXIMP void critical_section_impl::lock()\n    {\n        EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));\n    }\n\n    _PPLXIMP void critical_section_impl::unlock()\n    {\n        LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&_M_impl));\n    }\n\n#if _WIN32_WINNT >= _WIN32_WINNT_VISTA\n    //\n    // reader_writer_lock implementation\n    //\n    _PPLXIMP reader_writer_lock_impl::reader_writer_lock_impl()\n        : m_locked_exclusive(false)\n    {\n        static_assert(sizeof(SRWLOCK) <= sizeof(_M_impl), \"SRWLOCK version mismatch\");\n        InitializeSRWLock(reinterpret_cast<PSRWLOCK>(&_M_impl));\n    }\n\n    _PPLXIMP void reader_writer_lock_impl::lock()\n    {\n        AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&_M_impl));\n        m_locked_exclusive = true;\n    }\n\n    _PPLXIMP void reader_writer_lock_impl::lock_read()\n    {\n        AcquireSRWLockShared(reinterpret_cast<PSRWLOCK>(&_M_impl));\n    }\n\n    _PPLXIMP void reader_writer_lock_impl::unlock()\n    {\n        if(m_locked_exclusive)\n        {\n            m_locked_exclusive = false;\n            ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&_M_impl));\n        }\n        else\n        {\n            ReleaseSRWLockShared(reinterpret_cast<PSRWLOCK>(&_M_impl));\n        }\n    }\n#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA\n\n    //\n    // scheduler implementation\n    //\n#if defined(__cplusplus_winrt) && !TV_API\n    _PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param)\n    {\n        auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([proc, param](Windows::Foundation::IAsyncAction ^ )\n        {\n            proc(param);\n        });\n\n        Windows::System::Threading::ThreadPool::RunAsync(workItemHandler);\n    }\n#else\n\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n     struct _Scheduler_Param\n    {\n        TaskProc_t m_proc;\n        void * m_param;\n\n        _Scheduler_Param(TaskProc_t proc, _In_ void * param)\n            : m_proc(proc), m_param(param)\n        {\n        }\n\n        static DWORD CALLBACK DefaultWorkCallback(LPVOID lpParameter)\n        {\n            auto schedulerParam = (_Scheduler_Param *)(lpParameter);\n\n            schedulerParam->m_proc(schedulerParam->m_param);\n\n            delete schedulerParam;\n\n            return 1;\n        }\n    };\n\n    _PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param)\n    {\n        auto schedulerParam = new _Scheduler_Param(proc, param);\n        auto work = QueueUserWorkItem(_Scheduler_Param::DefaultWorkCallback, schedulerParam, WT_EXECUTELONGFUNCTION);\n\n        if (!work)\n        {\n            delete schedulerParam;\n            throw utility::details::create_system_error(GetLastError());\n        }\n    }\n#else\n    struct _Scheduler_Param\n    {\n        TaskProc_t m_proc;\n        void * m_param;\n\n        _Scheduler_Param(TaskProc_t proc, _In_ void * param)\n            : m_proc(proc), m_param(param)\n        {\n        }\n\n        static void CALLBACK DefaultWorkCallback(PTP_CALLBACK_INSTANCE, PVOID pContext, PTP_WORK)\n        {\n            auto schedulerParam = (_Scheduler_Param *)(pContext);\n\n            schedulerParam->m_proc(schedulerParam->m_param);\n\n            delete schedulerParam;\n        }\n    };\n\n    _PPLXIMP void windows_scheduler::schedule( TaskProc_t proc, _In_ void* param)\n    {\n        auto schedulerParam = new _Scheduler_Param(proc, param);\n        auto work = CreateThreadpoolWork(_Scheduler_Param::DefaultWorkCallback, schedulerParam, NULL);\n\n        if (work == nullptr)\n        {\n            delete schedulerParam;\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        SubmitThreadpoolWork(work);\n        CloseThreadpoolWork(work);\n    }\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n\n#endif\n} // namespace details\n\n} // namespace pplx\n\n#endif"
  },
  {
    "path": "Include/cpprestinclude/pplx/details/threadpool.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n**/\n#include \"pplx/threadpool.h\"\n#if defined(__ANDROID__)\n#include <android/log.h>\n#include <jni.h>\n#endif\n\nnamespace crossplat\n{\n#if (defined(ANDROID) || defined(__ANDROID__))\n// This pointer will be 0-initialized by default (at load time).\nstd::atomic<JavaVM*> JVM;\n\nstatic void abort_if_no_jvm()\n{\n    if (JVM == nullptr)\n    {\n        __android_log_print(ANDROID_LOG_ERROR, \"CPPRESTSDK\", \"%s\", \"The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android\");\n        std::abort();\n    }\n}\n\nJNIEnv* get_jvm_env()\n{\n    abort_if_no_jvm();\n    JNIEnv* env = nullptr;\n    auto result = JVM.load()->AttachCurrentThread(&env, nullptr);\n    if (result != JNI_OK)\n    {\n        throw std::runtime_error(\"Could not attach to JVM\");\n    }\n\n    return env;\n}\n\nthreadpool& threadpool::shared_instance()\n{\n    abort_if_no_jvm();\n    static threadpool s_shared(40);\n    return s_shared;\n}\n\n#else\n\n// initialize the static shared threadpool\nthreadpool& threadpool::shared_instance()\n{\n    static threadpool s_shared(40);\n    return s_shared;\n}\n\n#endif\n\n}\n\n#if defined(__ANDROID__)\nvoid cpprest_init(JavaVM* vm) {\n    crossplat::JVM = vm;\n}\n#endif\n\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplx.h",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved. \n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#ifndef _PPLX_H\n#define _PPLX_H\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX\n#error This file must not be included for Visual Studio 12 or later\n#endif\n\n#ifndef _WIN32\n#if defined(_WIN32) || defined(__cplusplus_winrt)\n#define _WIN32\n#endif\n#endif // _WIN32\n\n#ifdef _NO_PPLXIMP\n#define _PPLXIMP\n#else\n#ifdef _PPLX_EXPORT\n#define _PPLXIMP __declspec(dllexport)\n#else\n#define _PPLXIMP __declspec(dllimport)\n#endif\n#endif\n\n#include \"cpprest/details/cpprest_compat.h\"\n\n// Use PPLx\n#ifdef _WIN32\n#include \"pplx/pplxwin.h\"\n#elif defined(__APPLE__)\n#undef _PPLXIMP\n#define _PPLXIMP\n#include \"pplx/pplxlinux.h\"\n#else\n#include \"pplx/pplxlinux.h\"\n#endif // _WIN32\n\n// Common implementation across all the non-concrt versions\n#include \"pplx/pplxcancellation_token.h\"\n#include <functional>\n\n// conditional expression is constant\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 4127)\n#endif\n\n#pragma pack(push,_CRT_PACKING)\n\n/// <summary>\n///     The <c>pplx</c> namespace provides classes and functions that give you access to the Concurrency Runtime,\n///     a concurrent programming framework for C++. For more information, see <see cref=\"Concurrency Runtime\"/>.\n/// </summary>\n/**/\nnamespace pplx\n{\n\n/// <summary>\n/// Sets the ambient scheduler to be used by the PPL constructs.\n/// </summary>\n_PPLXIMP void _pplx_cdecl set_ambient_scheduler(std::shared_ptr<pplx::scheduler_interface> _Scheduler);\n\n/// <summary>\n/// Gets the ambient scheduler to be used by the PPL constructs\n/// </summary>\n_PPLXIMP std::shared_ptr<pplx::scheduler_interface> _pplx_cdecl get_ambient_scheduler();\n\nnamespace details\n{\n    //\n    // An internal exception that is used for cancellation. Users do not \"see\" this exception except through the\n    // resulting stack unwind. This exception should never be intercepted by user code. It is intended\n    // for use by the runtime only.\n    //\n    class _Interruption_exception : public std::exception\n    {\n    public:\n        _Interruption_exception(){}\n    };\n\n    template<typename _T>\n    struct _AutoDeleter\n    {\n        _AutoDeleter(_T *_PPtr) : _Ptr(_PPtr) {}\n        ~_AutoDeleter () { delete _Ptr; } \n        _T *_Ptr;\n    };\n\n    struct _TaskProcHandle\n    {\n        _TaskProcHandle()\n        {\n        }\n\n        virtual ~_TaskProcHandle() {}\n        virtual void invoke() const = 0;\n\n        static void _pplx_cdecl _RunChoreBridge(void * _Parameter)\n        {\n            auto _PTaskHandle = static_cast<_TaskProcHandle *>(_Parameter);\n            _AutoDeleter<_TaskProcHandle> _AutoDeleter(_PTaskHandle);\n            _PTaskHandle->invoke();\n        }\n    };\n\n    enum _TaskInliningMode\n    {\n        // Disable inline scheduling\n        _NoInline = 0,\n        // Let runtime decide whether to do inline scheduling or not\n        _DefaultAutoInline = 16,\n        // Always do inline scheduling\n        _ForceInline = -1,\n    };\n\n    // This is an abstraction that is built on top of the scheduler to provide these additional functionalities\n    // - Ability to wait on a work item\n    // - Ability to cancel a work item\n    // - Ability to inline work on invocation of RunAndWait\n    class _TaskCollectionImpl \n    {\n    public:\n\n        typedef _TaskProcHandle _TaskProcHandle_t;\n\n        _TaskCollectionImpl(scheduler_ptr _PScheduler) \n            : _M_pScheduler(_PScheduler)\n        {\n        }\n\n        void _ScheduleTask(_TaskProcHandle_t* _PTaskHandle, _TaskInliningMode _InliningMode)\n        {\n            if (_InliningMode == _ForceInline)\n            {\n                _TaskProcHandle_t::_RunChoreBridge(_PTaskHandle);\n            }\n            else\n            {\n                _M_pScheduler->schedule(_TaskProcHandle_t::_RunChoreBridge, _PTaskHandle);\n            }\n        }\n\n        void _Cancel()\n        {\n            // No cancellation support\n        }\n\n        void _RunAndWait()\n        {\n            // No inlining support yet\n            _Wait();\n        }\n\n        void _Wait()\n        {\n            _M_Completed.wait();\n        }\n\n        void _Complete()\n        {\n            _M_Completed.set();\n        }\n\n        scheduler_ptr _GetScheduler() const\n        {\n            return _M_pScheduler;\n        }\n\n        // Fire and forget\n        static void _RunTask(TaskProc_t _Proc, void * _Parameter, _TaskInliningMode _InliningMode)\n        {\n            if (_InliningMode == _ForceInline)\n            {\n                _Proc(_Parameter);\n            }\n            else\n            {\n                // Schedule the work on the ambient scheduler\n                get_ambient_scheduler()->schedule(_Proc, _Parameter);\n            }\n        }\n\n        static bool _pplx_cdecl _Is_cancellation_requested()\n        {\n            // We do not yet have the ability to determine the current task. So return false always\n            return false;\n        }\n    private:\n\n        extensibility::event_t _M_Completed;\n        scheduler_ptr _M_pScheduler;\n    };\n\n    // For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the\n    // lambda.\n    struct _Task_generator_oversubscriber  {};\n\n    typedef _TaskCollectionImpl _TaskCollection_t;\n    typedef _TaskInliningMode _TaskInliningMode_t;\n    typedef _Task_generator_oversubscriber _Task_generator_oversubscriber_t;\n\n} // namespace details\n\n} // namespace pplx\n\n#pragma pack(pop)\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n#endif // _PPLX_H\n#endif // !XSAPI_NO_PPL"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxcancellation_token.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library : cancellation_token\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#ifndef _PPLX_H\n#error This header must not be included directly\n#endif\n\n#ifndef _PPLXCANCELLATION_TOKEN_H\n#define _PPLXCANCELLATION_TOKEN_H\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX\n#error This file must not be included for Visual Studio 12 or later\n#endif\n\n#include <cstdlib>\n#include <string>\n#include \"pplx/pplxinterface.h\"\n\n#pragma pack(push,_CRT_PACKING)\n// All header files are required to be protected from the macro new\n#pragma push_macro(\"new\")\n#undef new\n\nnamespace pplx\n{\n\n/// <summary>\n///     This class describes an exception thrown by the PPL tasks layer in order to force the current task\n///     to cancel. It is also thrown by the <c>get()</c> method on <see cref=\"task Class\">task</see>, for a\n///     canceled task.\n/// </summary>\n/// <seealso cref=\"task::get Method\"/>\n/// <seealso cref=\"cancel_current_task Method\"/>\n/**/\nclass task_canceled : public std::exception\n{\nprivate:\n    std::string _message;\n\npublic:\n    /// <summary>\n    ///     Constructs a <c>task_canceled</c> object.\n    /// </summary>\n    /// <param name=\"_Message\">\n    ///     A descriptive message of the error.\n    /// </param>\n    /**/\n    explicit task_canceled(_In_z_ const char * _Message) throw()\n        : _message(_Message)\n    {\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task_canceled</c> object.\n    /// </summary>\n    /**/\n    task_canceled() throw()\n        : exception()\n    {\n    }\n\n    ~task_canceled() throw () {}\n\n    const char* what() const CPPREST_NOEXCEPT\n    {\n        return _message.c_str();\n    }\n};\n\n/// <summary>\n///     This class describes an exception thrown when an invalid operation is performed that is not more accurately\n///     described by another exception type thrown by the Concurrency Runtime.\n/// </summary>\n/// <remarks>\n///     The various methods which throw this exception will generally document under what circumstances they will throw it.\n/// </remarks>\n/**/\nclass invalid_operation : public std::exception\n{\nprivate:\n    std::string _message;\n\npublic:\n    /// <summary>\n    ///     Constructs an <c>invalid_operation</c> object.\n    /// </summary>\n    /// <param name=\"_Message\">\n    ///     A descriptive message of the error.\n    /// </param>\n    /**/\n    invalid_operation(_In_z_ const char * _Message) throw()\n        : _message(_Message)\n    {\n    }\n\n    /// <summary>\n    ///     Constructs an <c>invalid_operation</c> object.\n    /// </summary>\n    /**/\n    invalid_operation() throw()\n        : exception()\n    {\n    }\n    \n    ~invalid_operation() throw () {}\n\n    const char* what() const CPPREST_NOEXCEPT\n    {\n        return _message.c_str();\n    }\n};\n\nnamespace details\n{\n\n    // Base class for all reference counted objects\n    class _RefCounter\n    {\n    public:\n\n        virtual ~_RefCounter()\n        {\n            _ASSERTE(_M_refCount == 0);\n        }\n\n        // Acquires a reference\n        // Returns the new reference count.\n        long _Reference()\n        {\n            long _Refcount = atomic_increment(_M_refCount);\n\n            // 0 - 1 transition is illegal\n            _ASSERTE(_Refcount > 1);\n            return _Refcount;\n        }\n\n        // Releases the reference\n        // Returns the new reference count\n        long _Release()\n        {\n            long _Refcount = atomic_decrement(_M_refCount);\n            _ASSERTE(_Refcount >= 0);\n\n            if (_Refcount == 0)\n            {\n                _Destroy();\n            }\n\n            return _Refcount;\n        }\n\n    protected:\n\n        // Allow derived classes to provide their own deleter\n        virtual void _Destroy()\n        {\n            delete this;\n        }\n\n        // Only allow instantiation through derived class\n        _RefCounter(long _InitialCount = 1) : _M_refCount(_InitialCount)\n        {\n            _ASSERTE(_M_refCount > 0);\n        }\n\n        // Reference count\n        atomic_long _M_refCount;\n    };\n\n    class _CancellationTokenState;\n\n    class _CancellationTokenRegistration : public _RefCounter\n    {\n    private:\n\n        static const long _STATE_CLEAR = 0;\n        static const long _STATE_DEFER_DELETE = 1;\n        static const long _STATE_SYNCHRONIZE = 2;\n        static const long _STATE_CALLED = 3;\n\n    public:\n\n        _CancellationTokenRegistration(long _InitialRefs = 1) :\n            _RefCounter(_InitialRefs),\n            _M_state(_STATE_CALLED),\n            _M_pTokenState(NULL)\n        {\n        }\n\n        _CancellationTokenState *_GetToken() const\n        {\n            return _M_pTokenState;\n        }\n\n    protected:\n\n        virtual ~_CancellationTokenRegistration()\n        {\n            _ASSERTE(_M_state != _STATE_CLEAR);\n        }\n\n        virtual void _Exec() = 0;\n\n    private:\n\n        friend class _CancellationTokenState;\n\n        void _Invoke()\n        {\n            long tid = ::pplx::details::platform::GetCurrentThreadId();\n            _ASSERTE((tid & 0x3) == 0); // If this ever fires, we need a different encoding for this.\n\n            long result = atomic_compare_exchange(_M_state, tid, _STATE_CLEAR);\n\n            if (result == _STATE_CLEAR)\n            {\n                _Exec();\n\n                result = atomic_compare_exchange(_M_state, _STATE_CALLED, tid);\n\n                if (result == _STATE_SYNCHRONIZE)\n                {\n                    _M_pSyncBlock->set();\n                }\n            }\n            _Release();\n        }\n\n        atomic_long _M_state;\n        extensibility::event_t *_M_pSyncBlock;\n        _CancellationTokenState *_M_pTokenState;\n    };\n\n    template<typename _Function>\n    class _CancellationTokenCallback : public _CancellationTokenRegistration\n    {\n    public:\n\n        _CancellationTokenCallback(const _Function& _Func) :\n            _M_function(_Func)\n        {\n        }\n\n    protected:\n\n        virtual void _Exec()\n        {\n            _M_function();\n        }\n\n    private:\n\n        _Function _M_function;\n    };\n\n    class CancellationTokenRegistration_TaskProc : public _CancellationTokenRegistration\n    {\n    public:\n\n        CancellationTokenRegistration_TaskProc(TaskProc_t proc, _In_ void *pData, int initialRefs) :\n            _CancellationTokenRegistration(initialRefs), m_proc(proc), m_pData(pData)\n        {\n        }\n\n    protected:\n\n        virtual void _Exec()\n        {\n            m_proc(m_pData);\n        }\n\n    private:\n\n        TaskProc_t m_proc;\n        void *m_pData;\n\n    };\n\n    // The base implementation of a cancellation token.\n    class _CancellationTokenState : public _RefCounter\n    {\n    protected:\n            class TokenRegistrationContainer\n        {\n        private:\n            typedef struct _Node {\n                _CancellationTokenRegistration* _M_token;\n                _Node *_M_next;\n            } Node;\n\n        public:\n            TokenRegistrationContainer() : _M_begin(nullptr), _M_last(nullptr)\n            {\n            }\n\n            ~TokenRegistrationContainer()\n            {\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 6001)\n#endif\n                auto node = _M_begin;\n                while (node != nullptr) \n                {\n                    Node* tmp = node;\n                    node = node->_M_next;\n                    ::free(tmp);\n                }\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n            }\n\n            void swap(TokenRegistrationContainer& list)\n            {\n                std::swap(list._M_begin, _M_begin);\n                std::swap(list._M_last, _M_last);\n            }\n\n            bool empty()\n            {\n                return _M_begin == nullptr;\n            }\n\n            template<typename T>\n            void for_each(T lambda)\n            {\n                Node* node = _M_begin;\n\n                while (node != nullptr) \n                {\n                    lambda(node->_M_token);\n                    node = node->_M_next;\n                }\n            }\n\n            void push_back(_CancellationTokenRegistration* token)\n            {\n                Node* node = reinterpret_cast<Node*>(::malloc(sizeof(Node)));\n                if (node == nullptr)\n                {\n                    throw ::std::bad_alloc();\n                }\n\n                node->_M_token = token;\n                node->_M_next = nullptr;\n\n                if (_M_begin == nullptr) \n                {\n                    _M_begin = node;\n                }\n                else\n                {\n                    _M_last->_M_next = node;\n                }\n\n                _M_last = node;\n            }\n\n            void remove(_CancellationTokenRegistration* token)\n            {\n                Node* node = _M_begin;\n                Node* prev = nullptr;\n\n                while (node != nullptr) \n                {\n                    if (node->_M_token == token) {\n                        if (prev == nullptr)\n                        {\n                            _M_begin = node->_M_next;\n                        }\n                        else\n                        {\n                            prev->_M_next = node->_M_next;\n                        }\n\n                        if (node->_M_next == nullptr)\n                        {\n                            _M_last = prev;\n                        }\n\n                        ::free(node);\n                        break;\n                    }\n                    \n                    prev = node;\n                    node = node->_M_next;\n                }\n            }\n\n        private:\n            Node *_M_begin;\n            Node *_M_last;\n        };\n\n    public:\n\n        static _CancellationTokenState * _NewTokenState()\n        {\n            return new _CancellationTokenState();\n        }\n \n        static _CancellationTokenState *_None()\n        {\n            return reinterpret_cast<_CancellationTokenState *>(2);\n        }\n\n        static bool _IsValid(_In_opt_ _CancellationTokenState *_PToken)\n        {\n            return (_PToken != NULL && _PToken != _None());\n        }\n        \n        _CancellationTokenState() :\n            _M_stateFlag(0)\n        {\n        }\n\n        ~_CancellationTokenState()\n        {\n            TokenRegistrationContainer rundownList;\n            {\n                extensibility::scoped_critical_section_t _Lock(_M_listLock);\n                _M_registrations.swap(rundownList);\n            }\n\n            rundownList.for_each([](_CancellationTokenRegistration * pRegistration)\n            {\n                pRegistration->_M_state = _CancellationTokenRegistration::_STATE_SYNCHRONIZE;\n                pRegistration->_Release();\n            });\n        }\n\n        bool _IsCanceled() const\n        {\n            return (_M_stateFlag != 0);\n        }\n\n        void _Cancel()\n        {\n            if (atomic_compare_exchange(_M_stateFlag, 1l, 0l) == 0)\n            {\n                TokenRegistrationContainer rundownList;\n                {\n                    extensibility::scoped_critical_section_t _Lock(_M_listLock);\n                    _M_registrations.swap(rundownList);\n                }\n\n                rundownList.for_each([](_CancellationTokenRegistration * pRegistration)\n                {\n                    pRegistration->_Invoke();\n                });\n\n                _M_stateFlag = 2;\n                _M_cancelComplete.set();\n            }\n        }\n\n        _CancellationTokenRegistration *_RegisterCallback(TaskProc_t _PCallback, _In_ void *_PData, int _InitialRefs = 1)\n        {\n            _CancellationTokenRegistration *pRegistration = new CancellationTokenRegistration_TaskProc(_PCallback, _PData, _InitialRefs);\n            _RegisterCallback(pRegistration);\n            return pRegistration;\n        }\n\n        void _RegisterCallback(_In_ _CancellationTokenRegistration *_PRegistration)\n        {\n            _PRegistration->_M_state = _CancellationTokenRegistration::_STATE_CLEAR;\n            _PRegistration->_Reference();\n            _PRegistration->_M_pTokenState = this;\n\n            bool invoke = true;\n\n            if (!_IsCanceled())\n            {\n                extensibility::scoped_critical_section_t _Lock(_M_listLock);\n\n                if (!_IsCanceled())\n                {\n                    invoke = false;\n                    _M_registrations.push_back(_PRegistration);\n                }\n            }\n\n            if (invoke)\n            {\n                _PRegistration->_Invoke();\n            }\n        }\n\n        void _DeregisterCallback(_In_ _CancellationTokenRegistration *_PRegistration)\n        {\n            bool synchronize = false;\n\n            {\n                extensibility::scoped_critical_section_t _Lock(_M_listLock);\n\n                //\n                // If a cancellation has occurred, the registration list is guaranteed to be empty if we've observed it under the auspices of the\n                // lock.  In this case, we must synchronize with the cancelling thread to guarantee that the cancellation is finished by the time\n                // we return from this method.\n                //\n                if (!_M_registrations.empty())\n                {\n                    _M_registrations.remove(_PRegistration);\n                    _PRegistration->_M_state = _CancellationTokenRegistration::_STATE_SYNCHRONIZE;\n                    _PRegistration->_Release();\n                }\n                else\n                {\n                    synchronize = true;\n                }\n            }\n\n            // \n            // If the list is empty, we are in one of several situations:\n            //\n            // - The callback has already been made         --> do nothing\n            // - The callback is about to be made           --> flag it so it doesn't happen and return\n            // - The callback is in progress elsewhere      --> synchronize with it\n            // - The callback is in progress on this thread --> do nothing\n            //\n            if (synchronize)\n            {\n                long result = atomic_compare_exchange(\n                    _PRegistration->_M_state, \n                    _CancellationTokenRegistration::_STATE_DEFER_DELETE, \n                    _CancellationTokenRegistration::_STATE_CLEAR\n                    );\n\n                switch(result)\n                {\n                    case _CancellationTokenRegistration::_STATE_CLEAR:\n                    case _CancellationTokenRegistration::_STATE_CALLED:\n                        break;\n                    case _CancellationTokenRegistration::_STATE_DEFER_DELETE:\n                    case _CancellationTokenRegistration::_STATE_SYNCHRONIZE:\n                        _ASSERTE(false);\n                        break;\n                    default:\n                    {\n                        long tid = result;\n                        if (tid == ::pplx::details::platform::GetCurrentThreadId())\n                        {\n                            //\n                            // It is entirely legal for a caller to Deregister during a callback instead of having to provide their own synchronization\n                            // mechanism between the two.  In this case, we do *NOT* need to explicitly synchronize with the callback as doing so would\n                            // deadlock.  If the call happens during, skip any extra synchronization.\n                            //\n                            break;\n                        }\n\n                        extensibility::event_t ev;\n                        _PRegistration->_M_pSyncBlock = &ev;\n\n                        long result_1 = atomic_exchange(_PRegistration->_M_state, _CancellationTokenRegistration::_STATE_SYNCHRONIZE);\n\n                        if (result_1 != _CancellationTokenRegistration::_STATE_CALLED)\n                        {\n                            _PRegistration->_M_pSyncBlock->wait(::pplx::extensibility::event_t::timeout_infinite);\n                        }\n\n                        break;\n                    }\n                }\n            }\n        }\n\n    private:\n\n        // The flag for the token state (whether it is canceled or not)\n        atomic_long _M_stateFlag;\n\n        // Notification of completion of cancellation of this token.\n        extensibility::event_t _M_cancelComplete; // Hmm.. where do we wait for it??\n\n        // Lock to protect the registrations list\n        extensibility::critical_section_t _M_listLock;\n\n        // The protected list of registrations\n        TokenRegistrationContainer _M_registrations;\n    };\n\n} // namespace details\n\nclass cancellation_token_source;\nclass cancellation_token;\n\n\n/// <summary>\n///     The <c>cancellation_token_registration</c> class represents a callback notification from a <c>cancellation_token</c>.  When the <c>register</c>\n///     method on a <c>cancellation_token</c> is used to receive notification of when cancellation occurs, a <c>cancellation_token_registration</c>\n///     object is returned as a handle to the callback so that the caller can request a specific callback no longer be made through use of\n///     the <c>deregister</c> method. \n/// </summary>\nclass cancellation_token_registration\n{\npublic:\n\n    cancellation_token_registration() :\n        _M_pRegistration(NULL)\n    {\n    }\n\n    ~cancellation_token_registration()\n    {\n        _Clear();\n    }\n\n    cancellation_token_registration(const cancellation_token_registration& _Src)\n    {\n        _Assign(_Src._M_pRegistration);\n    }\n\n    cancellation_token_registration(cancellation_token_registration&& _Src)\n    {\n        _Move(_Src._M_pRegistration);\n    }\n\n    cancellation_token_registration& operator=(const cancellation_token_registration& _Src)\n    {\n        if (this != &_Src)\n        {\n            _Clear();\n            _Assign(_Src._M_pRegistration);\n        }\n        return *this;\n    }\n\n    cancellation_token_registration& operator=(cancellation_token_registration&& _Src)\n    {\n        if (this != &_Src)\n        {\n            _Clear();\n            _Move(_Src._M_pRegistration);\n        }\n        return *this;\n    }\n\n    bool operator==(const cancellation_token_registration& _Rhs) const\n    {\n        return _M_pRegistration == _Rhs._M_pRegistration;\n    }\n\n    bool operator!=(const cancellation_token_registration& _Rhs) const\n    {\n        return !(operator==(_Rhs));\n    }\n\nprivate:\n\n    friend class cancellation_token;\n    \n    cancellation_token_registration(_In_ details::_CancellationTokenRegistration *_PRegistration) :\n        _M_pRegistration(_PRegistration)\n    {\n    }\n\n    void _Clear()\n    {\n        if (_M_pRegistration != NULL)\n        {\n            _M_pRegistration->_Release();\n        }\n        _M_pRegistration = NULL;\n    }\n\n    void _Assign(_In_ details::_CancellationTokenRegistration *_PRegistration)\n    {\n        if (_PRegistration != NULL)\n        {\n            _PRegistration->_Reference();\n        }\n        _M_pRegistration = _PRegistration;\n    }\n\n    void _Move(_In_ details::_CancellationTokenRegistration *&_PRegistration)\n    {\n        _M_pRegistration = _PRegistration;\n        _PRegistration = NULL;\n    }\n\n    details::_CancellationTokenRegistration *_M_pRegistration;\n};\n\n\n/// <summary>\n///     The <c>cancellation_token</c> class represents the ability to determine whether some operation has been requested to cancel.  A given token can\n///     be associated with a <c>task_group</c>, <c>structured_task_group</c>, or <c>task</c> to provide implicit cancellation.  It can also be polled for\n///     cancellation or have a callback registered for if and when the associated <c>cancellation_token_source</c> is canceled.\n/// </summary>\nclass cancellation_token\n{\npublic:\n\n    typedef details::_CancellationTokenState * _ImplType;\n\n    /// <summary>\n    ///     Returns a cancellation token which can never be subject to cancellation.\n    /// </summary>\n    /// <returns>\n    ///     A cancellation token that cannot be canceled.\n    /// </returns>\n    static cancellation_token none()\n    {\n        return cancellation_token();\n    }\n\n    cancellation_token(const cancellation_token& _Src)\n    {\n        _Assign(_Src._M_Impl);\n    }\n\n    cancellation_token(cancellation_token&& _Src)\n    {\n        _Move(_Src._M_Impl);\n    }\n\n    cancellation_token& operator=(const cancellation_token& _Src)\n    {\n        if (this != &_Src)\n        {\n            _Clear();\n            _Assign(_Src._M_Impl);\n        }\n        return *this;\n    }\n\n    cancellation_token& operator=(cancellation_token&& _Src)\n    {\n        if (this != &_Src)\n        {\n            _Clear();\n            _Move(_Src._M_Impl);\n        }\n        return *this;\n    }\n\n    bool operator==(const cancellation_token& _Src) const\n    {\n        return _M_Impl == _Src._M_Impl;\n    }\n\n    bool operator!=(const cancellation_token& _Src) const\n    {\n        return !(operator==(_Src));\n    }\n\n    ~cancellation_token()\n    {\n        _Clear();\n    }\n\n    /// <summary>\n    ///     Returns an indication of whether this token can be canceled or not.\n    /// </summary>\n    /// <returns>\n    ///     An indication of whether this token can be canceled or not.\n    /// </returns>\n    bool is_cancelable() const\n    {\n        return (_M_Impl != NULL);\n    }\n\n    /// <summary>\n    /// Returns <c>true</c> if the token has been canceled.\n    /// </summary>\n    /// <returns>\n    /// The value <c>true</c> if the token has been canceled; otherwise, the value <c>false</c>.\n    /// </returns>\n    bool is_canceled() const\n    {\n        return (_M_Impl != NULL && _M_Impl->_IsCanceled());\n    }\n\n    /// <summary>\n    ///     Registers a callback function with the token.  If and when the token is canceled, the callback will be made.  Note that if the token\n    ///     is already canceled at the point where this method is called, the callback will be made immediately and synchronously.  \n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be called back when this <c>cancellation_token</c> is canceled.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The function object that will be called back when this <c>cancellation_token</c> is canceled.\n    /// </param>\n    /// <returns>\n    ///     A <c>cancellation_token_registration</c> object which can be utilized in the <c>deregister</c> method to deregister a previously registered\n    ///     callback and prevent it from being made. The method will throw an <see cref=\"invalid_operation Class\">invalid_operation </see> exception if\n    ///     it is called on a <c>cancellation_token</c> object that was created using the <see cref=\"cancellation_token::none Method\">cancellation_token::none </see>\n    ///     method.\n    /// </returns>\n    template<typename _Function>\n    ::pplx::cancellation_token_registration register_callback(const _Function& _Func) const\n    {\n        if (_M_Impl == NULL)\n        {\n            // A callback cannot be registered if the token does not have an associated source.\n            throw invalid_operation();\n        }\n#if defined(_MSC_VER)\n#pragma warning(suppress: 28197)\n#endif\n        details::_CancellationTokenCallback<_Function> *_PCallback = new details::_CancellationTokenCallback<_Function>(_Func);\n        _M_Impl->_RegisterCallback(_PCallback);\n        return cancellation_token_registration(_PCallback);\n    }\n\n    /// <summary>\n    ///     Removes a callback previously registered via the <c>register</c> method based on the <c>cancellation_token_registration</c> object returned\n    ///     at the time of registration.\n    /// </summary>\n    /// <param name=\"_Registration\">\n    ///     The <c>cancellation_token_registration</c> object corresponding to the callback to be deregistered.  This token must have been previously\n    ///     returned from a call to the <c>register</c> method.\n    /// </param>\n    void deregister_callback(const cancellation_token_registration& _Registration) const\n    {\n        _M_Impl->_DeregisterCallback(_Registration._M_pRegistration);\n    }\n\n    _ImplType _GetImpl() const\n    {\n        return _M_Impl;\n    }\n\n    _ImplType _GetImplValue() const\n    {\n        return (_M_Impl == NULL) ? ::pplx::details::_CancellationTokenState::_None() : _M_Impl;\n    }\n\n    static cancellation_token _FromImpl(_ImplType _Impl)\n    {\n        return cancellation_token(_Impl);\n    }\n\nprivate:\n\n    friend class cancellation_token_source;\n\n    _ImplType _M_Impl;\n\n    void _Clear()\n    {\n        if (_M_Impl != NULL)\n        {\n            _M_Impl->_Release();\n        }\n        _M_Impl = NULL;\n    }\n\n    void _Assign(_ImplType _Impl)\n    {\n        if (_Impl != NULL)\n        {\n            _Impl->_Reference();\n        }\n        _M_Impl = _Impl;\n    }\n\n    void _Move(_ImplType &_Impl)\n    {\n        _M_Impl = _Impl;\n        _Impl = NULL;\n    }\n\n    cancellation_token() :\n        _M_Impl(NULL)\n    {\n    }\n\n    cancellation_token(_ImplType _Impl) :\n        _M_Impl(_Impl)\n    {\n        if (_M_Impl == ::pplx::details::_CancellationTokenState::_None())\n        {\n            _M_Impl = NULL;\n        }\n\n        if (_M_Impl != NULL)\n        {\n            _M_Impl->_Reference();\n        }\n    }\n};\n\n/// <summary>\n///     The <c>cancellation_token_source</c> class represents the ability to cancel some cancelable operation.\n/// </summary>\nclass cancellation_token_source\n{\npublic:\n\n    typedef ::pplx::details::_CancellationTokenState * _ImplType;\n\n    /// <summary>\n    ///     Constructs a new <c>cancellation_token_source</c>.  The source can be used to flag cancellation of some cancelable operation.\n    /// </summary>\n    cancellation_token_source()\n    { \n        _M_Impl = new ::pplx::details::_CancellationTokenState;\n    }\n\n    cancellation_token_source(const cancellation_token_source& _Src)\n    {\n        _Assign(_Src._M_Impl);\n    }\n\n    cancellation_token_source(cancellation_token_source&& _Src)\n    {\n        _Move(_Src._M_Impl);\n    }\n\n    cancellation_token_source& operator=(const cancellation_token_source& _Src)\n    {\n        if (this != &_Src)\n        {\n            _Clear();\n            _Assign(_Src._M_Impl);\n        }\n        return *this;\n    }\n\n    cancellation_token_source& operator=(cancellation_token_source&& _Src)\n    {\n        if (this != &_Src)\n        {\n            _Clear();\n            _Move(_Src._M_Impl);\n        }\n        return *this;\n    }\n\n    bool operator==(const cancellation_token_source& _Src) const\n    {\n        return _M_Impl == _Src._M_Impl;\n    }\n\n    bool operator!=(const cancellation_token_source& _Src) const\n    {\n        return !(operator==(_Src));\n    }\n\n    ~cancellation_token_source()\n    {\n        if (_M_Impl != NULL)\n        {\n            _M_Impl->_Release();\n        }\n    }\n\n    /// <summary>\n    ///     Returns a cancellation token associated with this source.  The returned token can be polled for cancellation\n    ///     or provide a callback if and when cancellation occurs.\n    /// </summary>\n    /// <returns>\n    ///     A cancellation token associated with this source.\n    /// </returns>\n    cancellation_token get_token() const\n    {\n        return cancellation_token(_M_Impl);\n    }\n\n    /// <summary>\n    ///     Creates a <c>cancellation_token_source</c> which is canceled when the provided token is canceled.\n    /// </summary>\n    /// <param name=\"_Src\">\n    ///     A token whose cancellation will cause cancellation of the returned token source.  Note that the returned token source can also be canceled\n    ///     independently of the source contained in this parameter.\n    /// </param>\n    /// <returns>\n    ///     A <c>cancellation_token_source</c> which is canceled when the token provided by the <paramref name=\"_Src\"/> parameter is canceled.\n    /// </returns>\n    static cancellation_token_source create_linked_source(cancellation_token& _Src) \n    {\n        cancellation_token_source newSource;\n        _Src.register_callback( [newSource](){ newSource.cancel(); } );\n        return newSource;\n    }\n\n    /// <summary>\n    ///     Creates a <c>cancellation_token_source</c> which is canceled when one of a series of tokens represented by an STL iterator\n    ///     pair is canceled.\n    /// </summary>\n    /// <param name=\"_Begin\">\n    ///     The STL iterator corresponding to the beginning of the range of tokens to listen for cancellation of.\n    /// </param>\n    /// <param name=\"_End\">\n    ///     The STL iterator corresponding to the ending of the range of tokens to listen for cancellation of.\n    /// </param>\n    /// <returns>\n    ///     A <c>cancellation_token_source</c> which is canceled when any of the tokens provided by the range described by the STL iterators\n    ///     contained in the <paramref name=\"_Begin\"/> and <paramref name=\"_End\"/> parameters is canceled.\n    /// </returns>\n    template<typename _Iter>\n    static cancellation_token_source create_linked_source(_Iter _Begin, _Iter _End)\n    {\n        cancellation_token_source newSource;\n        for (_Iter _It = _Begin; _It != _End; ++_It)\n        {\n            _It->register_callback( [newSource](){ newSource.cancel(); } );\n        }\n        return newSource;\n    }\n\n    /// <summary>\n    ///     Cancels the token.  Any <c>task_group</c>, <c>structured_task_group</c>, or <c>task</c> which utilizes the token will be \n    ///     canceled upon this call and throw an exception at the next interruption point.\n    /// </summary>\n    void cancel() const\n    {\n        _M_Impl->_Cancel();\n    }\n\n    _ImplType _GetImpl() const\n    {\n        return _M_Impl;\n    }\n\n    static cancellation_token_source _FromImpl(_ImplType _Impl)\n    {\n        return cancellation_token_source(_Impl);\n    }\n\nprivate:\n\n    _ImplType _M_Impl;\n\n    void _Clear()\n    {\n        if (_M_Impl != NULL)\n        {\n            _M_Impl->_Release();\n        }\n        _M_Impl = NULL;\n    }\n\n    void _Assign(_ImplType _Impl)\n    {\n        if (_Impl != NULL)\n        {\n            _Impl->_Reference();\n        }\n        _M_Impl = _Impl;\n    }\n\n    void _Move(_ImplType &_Impl)\n    {\n        _M_Impl = _Impl;\n        _Impl = NULL;\n    }\n\n    cancellation_token_source(_ImplType _Impl) :\n        _M_Impl(_Impl)\n    {\n        if (_M_Impl == ::pplx::details::_CancellationTokenState::_None())\n        {\n            _M_Impl = NULL;\n        }\n\n        if (_M_Impl != NULL)\n        {\n            _M_Impl->_Reference();\n        }\n    }\n};\n\n} // namespace pplx\n\n#pragma pop_macro(\"new\")\n#pragma pack(pop)\n\n#endif // _PPLXCANCELLATION_TOKEN_H\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxinterface.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* PPL interfaces\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#ifndef _PPLXINTERFACE_H\n#define _PPLXINTERFACE_H\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX\n#error This file must not be included for Visual Studio 12 or later\n#endif\n\n#if defined(_CRTBLD)\n#elif defined(_WIN32)\n#if (_MSC_VER >= 1700)\n#define _USE_REAL_ATOMICS\n#endif\n#else // GCC compiler\n#define _USE_REAL_ATOMICS\n#endif\n\n#include <memory>\n#ifdef _USE_REAL_ATOMICS\n#include <atomic>\n#endif\n\n#define _pplx_cdecl __cdecl\n\nnamespace pplx\n{\n\n/// <summary>\n///     An elementary abstraction for a task, defined as <c>void (__cdecl * TaskProc_t)(void *)</c>. A <c>TaskProc</c> is called to\n///     invoke the body of a task.\n/// </summary>\n/**/\ntypedef void (_pplx_cdecl * TaskProc_t)(void *);\n\n/// <summary>\n///     Scheduler Interface\n/// </summary>\nstruct __declspec(novtable) scheduler_interface\n{\n    virtual void schedule( TaskProc_t, _In_ void* ) = 0;\n\n    virtual ~scheduler_interface() {}\n};\n\n/// <summary>\n///     Represents a pointer to a scheduler. This class exists to allow the\n///     the specification of a shared lifetime by using shared_ptr or just\n///     a plain reference by using raw pointer.\n/// </summary>\nstruct scheduler_ptr\n{\n    /// <summary>\n    /// Creates a scheduler pointer from shared_ptr to scheduler\n    /// </summary>\n    explicit scheduler_ptr(std::shared_ptr<scheduler_interface> scheduler) : m_sharedScheduler(std::move(scheduler))\n    {\n        m_scheduler = m_sharedScheduler.get();\n    }\n\n    /// <summary>\n    /// Creates a scheduler pointer from raw pointer to scheduler\n    /// </summary>\n    explicit scheduler_ptr(_In_opt_ scheduler_interface * pScheduler) : m_scheduler(pScheduler)\n    {\n    }\n\n    /// <summary>\n    /// Behave like a pointer\n    /// </summary>\n    scheduler_interface *operator->() const\n    {\n        return get();\n    }\n\n    /// <summary>\n    ///  Returns the raw pointer to the scheduler\n    /// </summary>\n    scheduler_interface * get() const\n    {\n        return m_scheduler;\n    }\n\n    /// <summary>\n    /// Test whether the scheduler pointer is non-null\n    /// </summary>\n    operator bool() const { return get() != nullptr; }\n\nprivate:\n\n    std::shared_ptr<scheduler_interface> m_sharedScheduler;\n    scheduler_interface * m_scheduler;\n};\n\n\n/// <summary>\n///     Describes the execution status of a <c>task_group</c> or <c>structured_task_group</c> object.  A value of this type is returned\n///     by numerous methods that wait on tasks scheduled to a task group to complete.\n/// </summary>\n/// <seealso cref=\"task_group Class\"/>\n/// <seealso cref=\"task_group::wait Method\"/>\n/// <seealso cref=\"task_group::run_and_wait Method\"/>\n/// <seealso cref=\"structured_task_group Class\"/>\n/// <seealso cref=\"structured_task_group::wait Method\"/>\n/// <seealso cref=\"structured_task_group::run_and_wait Method\"/>\n/**/\nenum task_group_status\n{\n    /// <summary>\n    ///     The tasks queued to the <c>task_group</c> object have not completed.  Note that this value is not presently returned by\n    ///     the Concurrency Runtime.\n    /// </summary>\n    /**/\n    not_complete,\n\n    /// <summary>\n    ///     The tasks queued to the <c>task_group</c> or <c>structured_task_group</c> object completed successfully.\n    /// </summary>\n    /**/\n    completed,\n\n    /// <summary>\n    ///     The <c>task_group</c> or <c>structured_task_group</c> object was canceled.  One or more tasks may not have executed.\n    /// </summary>\n    /**/\n    canceled\n};\n\nnamespace details\n{\n/// <summary>\n///     Atomics\n/// </summary>\n#ifdef _USE_REAL_ATOMICS\ntypedef std::atomic<long> atomic_long;\ntypedef std::atomic<size_t> atomic_size_t;\n\ntemplate<typename _T>\n_T atomic_compare_exchange(std::atomic<_T>& _Target, _T _Exchange, _T _Comparand)\n{\n    _T _Result = _Comparand;\n    _Target.compare_exchange_strong(_Result, _Exchange);\n    return _Result;\n}\n\ntemplate<typename _T>\n_T atomic_exchange(std::atomic<_T>& _Target, _T _Value)\n{\n    return _Target.exchange(_Value);\n}\n\ntemplate<typename _T>\n_T atomic_increment(std::atomic<_T>& _Target)\n{\n    return _Target.fetch_add(1) + 1;\n}\n\ntemplate<typename _T>\n_T atomic_decrement(std::atomic<_T>& _Target)\n{\n    return _Target.fetch_sub(1) - 1;\n}\n\ntemplate<typename _T>\n_T atomic_add(std::atomic<_T>& _Target, _T value)\n{\n    return _Target.fetch_add(value) + value;\n}\n\n#else // not _USE_REAL_ATOMICS\n\ntypedef long volatile atomic_long;\ntypedef size_t volatile atomic_size_t;\n\ntemplate<class T>\ninline T atomic_exchange(T volatile& _Target, T _Value)\n{\n    return _InterlockedExchange(&_Target, _Value);\n}\n\ninline long atomic_increment(long volatile & _Target)\n{\n    return _InterlockedIncrement(&_Target);\n}\n\ninline long atomic_add(long volatile & _Target, long value)\n{\n    return _InterlockedExchangeAdd(&_Target, value) + value;\n}\n\ninline size_t atomic_increment(size_t volatile & _Target)\n{\n#if (defined(_M_IX86) || defined(_M_ARM))\n    return static_cast<size_t>(_InterlockedIncrement(reinterpret_cast<long volatile *>(&_Target)));\n#else\n    return static_cast<size_t>(_InterlockedIncrement64(reinterpret_cast<__int64 volatile *>(&_Target)));\n#endif\n}\n\ninline long atomic_decrement(long volatile & _Target)\n{\n    return _InterlockedDecrement(&_Target);\n}\n\ninline size_t atomic_decrement(size_t volatile & _Target)\n{\n#if (defined(_M_IX86) || defined(_M_ARM))\n    return static_cast<size_t>(_InterlockedDecrement(reinterpret_cast<long volatile *>(&_Target)));\n#else\n    return static_cast<size_t>(_InterlockedDecrement64(reinterpret_cast<__int64 volatile *>(&_Target)));\n#endif\n}\n\ninline long atomic_compare_exchange(long volatile & _Target, long _Exchange, long _Comparand)\n{\n    return _InterlockedCompareExchange(&_Target, _Exchange, _Comparand);\n}\n\ninline size_t atomic_compare_exchange(size_t volatile & _Target, size_t _Exchange, size_t _Comparand)\n{\n#if (defined(_M_IX86) || defined(_M_ARM))\n    return static_cast<size_t>(_InterlockedCompareExchange(reinterpret_cast<long volatile *>(_Target), static_cast<long>(_Exchange), static_cast<long>(_Comparand)));\n#else\n    return static_cast<size_t>(_InterlockedCompareExchange64(reinterpret_cast<__int64 volatile *>(_Target), static_cast<__int64>(_Exchange), static_cast<__int64>(_Comparand)));\n#endif\n}\n#endif // _USE_REAL_ATOMICS\n\n}} // namespace pplx\n\n#endif // _PPLXINTERFACE_H\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxlinux.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Linux specific pplx implementations\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n\n#if (defined(_MSC_VER))\n#error This file must not be included for Visual Studio\n#endif\n\n#ifndef _WIN32\n\n#include <signal.h>\n#include \"pthread.h\"\n#include \"cpprest/details/cpprest_compat.h\"\n\n//todo1808\n//#if defined(__APPLE__)\n//#include <dispatch/dispatch.h>\n//#include <boost/thread/mutex.hpp>\n//#include <boost/thread/condition_variable.hpp>\n//#else\n#include <mutex>   \n#include <condition_variable>\n//#endif\n\n#include \"pplx/pplxinterface.h\"\n\n\nnamespace pplx\n{\n    // todo1808\n// #if defined(__APPLE__)\n//    namespace cpprest_synchronization = ::boost;\n// #else\n    namespace cpprest_synchronization = ::std;\n// #endif\nnamespace details\n{\nnamespace platform\n{\n    /// <summary>\n    /// Returns a unique identifier for the execution thread where this routine in invoked\n    /// </summary>\n    _PPLXIMP long _pplx_cdecl GetCurrentThreadId();\n\n    /// <summary>\n    /// Yields the execution of the current execution thread - typically when spin-waiting\n    /// </summary>\n    _PPLXIMP void _pplx_cdecl YieldExecution();\n\n    /// <summary>\n    /// Caputeres the callstack\n    /// </summary>\n    __declspec(noinline) inline static size_t CaptureCallstack(void **, size_t, size_t)\n    {\n        return 0;\n    }\n}\n\n    /// <summary>\n    /// Manual reset event\n    /// </summary>\n    class event_impl\n     {\n    private:\n        cpprest_synchronization::mutex _lock;\n        cpprest_synchronization::condition_variable _condition;\n        bool _signaled;\n    public:\n\n        static const unsigned int timeout_infinite = 0xFFFFFFFF;\n\n        event_impl()\n            : _signaled(false) \n        {\n        }\n\n        void set()\n        {\n            cpprest_synchronization::lock_guard<cpprest_synchronization::mutex> lock(_lock);\n            _signaled = true;\n            _condition.notify_all();\n        }\n\n        void reset()\n        {\n            cpprest_synchronization::lock_guard<cpprest_synchronization::mutex> lock(_lock);\n            _signaled = false;\n        }\n\n        unsigned int wait(unsigned int timeout)\n        {\n            cpprest_synchronization::unique_lock<cpprest_synchronization::mutex> lock(_lock);\n            if (timeout == event_impl::timeout_infinite)\n            {\n                _condition.wait(lock, [this]() -> bool { return _signaled; });\n                return 0;\n            }\n            else\n            {\n                cpprest_synchronization::chrono::milliseconds period(timeout);\n                auto status = _condition.wait_for(lock, period, [this]() -> bool { return _signaled; });\n                _ASSERTE(status == _signaled);\n                // Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite\n                // Note: this must be consistent with the behavior of the Windows version, which is based on WaitForSingleObjectEx\n                return status ? 0: event_impl::timeout_infinite;\n            }\n        }\n\n        unsigned int wait()\n        {\n            return wait(event_impl::timeout_infinite);\n        }\n    };\n\n    /// <summary>\n    /// Reader writer lock\n    /// </summary>\n    class reader_writer_lock_impl\n    {\n    private:\n\n        pthread_rwlock_t _M_reader_writer_lock;\n\n    public:\n\n        class scoped_lock_read\n        {\n        public:\n            explicit scoped_lock_read(reader_writer_lock_impl &_Reader_writer_lock) : _M_reader_writer_lock(_Reader_writer_lock)\n            {\n                _M_reader_writer_lock.lock_read();\n            }\n\n            ~scoped_lock_read()\n            {\n                _M_reader_writer_lock.unlock();\n            }\n\n        private:\n            reader_writer_lock_impl& _M_reader_writer_lock;\n            scoped_lock_read(const scoped_lock_read&);                    // no copy constructor\n            scoped_lock_read const & operator=(const scoped_lock_read&);  // no assignment operator\n        };\n\n        reader_writer_lock_impl()\n        {\n            pthread_rwlock_init(&_M_reader_writer_lock, nullptr);\n        }\n\n        ~reader_writer_lock_impl()\n        {\n            pthread_rwlock_destroy(&_M_reader_writer_lock);\n        }\n\n        void lock()\n        {\n            pthread_rwlock_wrlock(&_M_reader_writer_lock);\n        }\n\n        void lock_read()\n        {\n            pthread_rwlock_rdlock(&_M_reader_writer_lock);\n        }\n\n        void unlock()\n        {\n            pthread_rwlock_unlock(&_M_reader_writer_lock);\n        }\n    };\n\n    /// <summary>\n    /// Recursive mutex\n    /// </summary>\n    class recursive_lock_impl\n    {\n    public:\n\n        recursive_lock_impl()\n            : _M_owner(-1), _M_recursionCount(0)\n        {\n        }\n\n        ~recursive_lock_impl()\n        {\n            _ASSERTE(_M_owner == -1);\n            _ASSERTE(_M_recursionCount == 0);\n        }\n\n        void lock()\n        {\n            auto id = ::pplx::details::platform::GetCurrentThreadId();\n\n            if ( _M_owner == id )\n            {\n                _M_recursionCount++;\n            }\n            else\n            {\n                _M_cs.lock();\n                _M_owner = id;\n                _M_recursionCount = 1;\n            }            \n        }\n\n        void unlock()\n        {\n            _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId());\n            _ASSERTE(_M_recursionCount >= 1);\n\n            _M_recursionCount--;\n\n            if ( _M_recursionCount == 0 )\n            {\n                _M_owner = -1;\n                _M_cs.unlock();\n            }           \n        }\n\n    private:\n        cpprest_synchronization::mutex _M_cs;\n        volatile long _M_owner;\n        long _M_recursionCount;\n    };\n\n#if defined(__APPLE__)\n    class apple_scheduler : public pplx::scheduler_interface\n#else\n    class linux_scheduler : public pplx::scheduler_interface\n#endif\n    {\n    public:\n        _PPLXIMP virtual void schedule( TaskProc_t proc, _In_ void* param);\n    };\n\n} // namespace details\n\n/// <summary>\n///  A generic RAII wrapper for locks that implements the critical_section interface\n///  cpprest_synchronization::lock_guard\n/// </summary>\ntemplate<class _Lock>\nclass scoped_lock\n{\npublic:\n    explicit scoped_lock(_Lock& _Critical_section) : _M_critical_section(_Critical_section)\n    {\n        _M_critical_section.lock();\n    }\n\n    ~scoped_lock()\n    {\n        _M_critical_section.unlock();\n    }\n\nprivate:\n    _Lock& _M_critical_section;\n\n    scoped_lock(const scoped_lock&);                    // no copy constructor\n    scoped_lock const & operator=(const scoped_lock&);  // no assignment operator\n};\n\n// The extensibility namespace contains the type definitions that are used internally\nnamespace extensibility\n{\n    typedef ::pplx::details::event_impl event_t;\n\n    typedef cpprest_synchronization::mutex critical_section_t;\n    typedef scoped_lock<critical_section_t> scoped_critical_section_t;\n\n    typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;\n    typedef scoped_lock<reader_writer_lock_t> scoped_rw_lock_t;\n    typedef ::pplx::extensibility::reader_writer_lock_t::scoped_lock_read scoped_read_lock_t;\n\n    typedef ::pplx::details::recursive_lock_impl recursive_lock_t;\n    typedef scoped_lock<recursive_lock_t> scoped_recursive_lock_t;\n}\n\n/// <summary>\n/// Default scheduler type\n/// </summary>\n#if defined(__APPLE__)\n    typedef details::apple_scheduler default_scheduler_t;\n#else\n    typedef details::linux_scheduler default_scheduler_t;\n#endif\n    \nnamespace details\n{\n    /// <summary>\n    /// Terminate the process due to unhandled exception\n    /// </summary>\n    #ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION\n    #define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \\\n        raise(SIGTRAP); \\\n        std::terminate(); \\\n    } while(false)\n    #endif //_REPORT_PPLTASK_UNOBSERVED_EXCEPTION\n}\n\n//see: http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html\n// this is critical to inline\n__attribute__ ((always_inline))\ninline void* _ReturnAddress() { return __builtin_return_address(0); }\n\n} // namespace pplx\n\n#endif // !_WIN32\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxtasks.110.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved. \n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library - PPLx Tasks\n*\n* For the latest on this and related APIs, please see http://casablanca.codeplex.com.\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#ifndef _PPLXTASKS_H\n#define _PPLXTASKS_H\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX\n#include <ppltasks.h>\nnamespace pplx = Concurrency;\n#if (_MSC_VER >= 1900)\n#include <concrt.h>\nnamespace Concurrency {\n    namespace extensibility {\n        typedef ::std::condition_variable condition_variable_t;\n        typedef ::std::mutex critical_section_t;\n        typedef ::std::unique_lock< ::std::mutex> scoped_critical_section_t;\n\n        typedef ::Concurrency::event event_t;\n        typedef ::Concurrency::reader_writer_lock reader_writer_lock_t;\n        typedef ::Concurrency::reader_writer_lock::scoped_lock scoped_rw_lock_t;\n        typedef ::Concurrency::reader_writer_lock::scoped_lock_read scoped_read_lock_t;\n\n        typedef ::Concurrency::details::_ReentrantBlockingLock recursive_lock_t;\n        typedef recursive_lock_t::_Scoped_lock scoped_recursive_lock_t;\n    }\n}\n#endif // _MSC_VER >= 1900\n#else\n\n#include \"pplx/pplx.h\"\n\n#if defined(__ANDROID__)\n#include <jni.h>\nvoid cpprest_init(JavaVM*);\n#endif\n\n// Cannot build using a compiler that is older than dev10 SP1\n#if defined(_MSC_VER)\n#if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/\n#error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks\n#endif /*IFSTRIP=IGN*/\n#endif /* defined(_MSC_VER) */\n\n#include <functional>\n#include <vector>\n#include <utility>\n#include <exception>\n#include <algorithm>\n\n#if defined(_MSC_VER)\n#if defined(__cplusplus_winrt)\n#include <windows.h>\n#include <ctxtcall.h>\n#include <agile.h>\n#include <winapifamily.h>\n#ifndef _UITHREADCTXT_SUPPORT\n\n#ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/\n\n// It is safe to include winapifamily as WINAPI_FAMILY was defined by the user\n#include <winapifamily.h>\n\n#if WINAPI_FAMILY == WINAPI_FAMILY_APP\n    // UI thread context support is not required for desktop and Windows Store apps\n    #define _UITHREADCTXT_SUPPORT 0\n#elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP\n    // UI thread context support is not required for desktop and Windows Store apps\n    #define _UITHREADCTXT_SUPPORT 0\n#else  /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */\n    #define _UITHREADCTXT_SUPPORT 1\n#endif  /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */\n\n#else  /* WINAPI_FAMILY */\n    // Not supported without a WINAPI_FAMILY setting.\n    #define _UITHREADCTXT_SUPPORT 0\n#endif  /* WINAPI_FAMILY */\n\n#endif  /* _UITHREADCTXT_SUPPORT */\n\n#if _UITHREADCTXT_SUPPORT\n    #include <uithreadctxt.h>\n#endif  /* _UITHREADCTXT_SUPPORT */\n\n    #pragma detect_mismatch(\"_PPLTASKS_WITH_WINRT\", \"1\")\n#else /* defined(__cplusplus_winrt) */\n    #pragma detect_mismatch(\"_PPLTASKS_WITH_WINRT\", \"0\")\n#endif /* defined(__cplusplus_winrt) */\n#endif /* defined(_MSC_VER) */\n\n#ifdef _DEBUG\n    #define _DBG_ONLY(X) X\n#else\n    #define _DBG_ONLY(X)\n#endif // #ifdef _DEBUG\n\n// std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11.\n#ifdef _MSC_VER\n#if _MSC_VER < 1700 /*IFSTRIP=IGN*/\nnamespace std\n{\n    template<class _E> exception_ptr make_exception_ptr(_E _Except)\n    {\n        return copy_exception(_Except);\n    }\n}\n#endif /* _MSC_VER < 1700 */\n#ifndef _PPLTASK_ASYNC_LOGGING\n    #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)\n        #define _PPLTASK_ASYNC_LOGGING 1  // Only enable async logging under dev12 winrt\n    #else\n        #define _PPLTASK_ASYNC_LOGGING 0\n    #endif\n#endif /* !_PPLTASK_ASYNC_LOGGING */\n#endif /* _MSC_VER */\n\n#pragma pack(push,_CRT_PACKING)\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 28197)\n#pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation\n#pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming\n#endif /* defined(_MSC_VER) */\n\n// All CRT public header files are required to be protected from the macro new\n#pragma push_macro(\"new\")\n#undef new\n\n// stuff ported from Dev11 CRT\n// NOTE: this doesn't actually match std::declval. it behaves differently for void!\n// so don't blindly change it to std::declval.\nnamespace stdx\n{\n    template<class _T>\n    _T&& declval();\n}\n\n/// <summary>\n///     The <c>pplx</c> namespace provides classes and functions that give you access to the Concurrency Runtime,\n///     a concurrent programming framework for C++. For more information, see <see cref=\"Concurrency Runtime\"/>.\n/// </summary>\n/**/\nnamespace pplx\n{\n/// <summary>\n///     A type that represents the terminal state of a task. Valid values are <c>completed</c> and <c>canceled</c>.\n/// </summary>\n/// <seealso cref=\"task Class\"/>\n/**/\ntypedef task_group_status task_status;\n\ntemplate <typename _Type> class task;\ntemplate <> class task<void>;\n\n// In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h.  In retail builds, default to only one frame.\n#ifndef PPL_TASK_SAVE_FRAME_COUNT\n#ifdef _DEBUG\n#define PPL_TASK_SAVE_FRAME_COUNT 10\n#else\n#define PPL_TASK_SAVE_FRAME_COUNT 1\n#endif\n#endif\n\n/// <summary>\n/// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified, \n/// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured.\n/// </summary>\n/// <ramarks>\n/// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress()\n/// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself.\n/// </remarks>\n#if PPL_TASK_SAVE_FRAME_COUNT > 1\n#if defined(__cplusplus_winrt) && !defined(_DEBUG)\n#pragma message (\"WARNING: Redefinning PPL_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!\")\n#define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())\n#else\n#define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT)\n#endif\n#else\n#define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())\n#endif\n\n\n/// <summary>\n///     Returns an indication of whether the task that is currently executing has received a request to cancel its\n///     execution. Cancellation is requested on a task if the task was created with a cancellation token, and\n///     the token source associated with that token is canceled.\n/// </summary>\n/// <returns>\n///     <c>true</c> if the currently executing task has received a request for cancellation, <c>false</c> otherwise.\n/// </returns>\n/// <remarks>\n///     If you call this method in the body of a task and it returns <c>true</c>, you must respond with a call to\n///     <see cref=\"cancel_current_task Function\">cancel_current_task</see> to acknowledge the cancellation request,\n///     after performing any cleanup you need. This will abort the execution of the task and cause it to enter into\n///     the <c>canceled</c> state. If you do not respond and continue execution, or return instead of calling\n///     <c>cancel_current_task</c>, the task will enter the <c>completed</c> state when it is done.\n///     state.\n///     <para>A task is not cancellable if it was created without a cancellation token.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"cancellation_token_source Class\"/>\n/// <seealso cref=\"cancellation_token Class\"/>\n/// <seealso cref=\"cancel_current_task Function\"/>\n/**/\ninline bool _pplx_cdecl is_task_cancellation_requested()\n{\n    return ::pplx::details::_TaskCollection_t::_Is_cancellation_requested();\n}\n\n/// <summary>\n///     Cancels the currently executing task. This function can be called from within the body of a task to abort the\n///     task's execution and cause it to enter the <c>canceled</c> state. While it may be used in response to\n///     the <see cref=\"is_task_cancellation_requested Function\">is_task_cancellation_requested</see> function, you may\n///     also use it by itself, to initiate cancellation of the task that is currently executing.\n///     <para>It is not a supported scenario to call this function if you are not within the body of a <c>task</c>.\n///     Doing so will result in undefined behavior such as a crash or a hang in your application.</para>\n/// </summary>\n/// <seealso cref=\"task Class\"/>\n/**/\ninline __declspec(noreturn) void _pplx_cdecl cancel_current_task()\n{\n    throw task_canceled();\n}\n\nnamespace details\n{\n    /// <summary>\n    ///     Callstack container, which is used to capture and preserve callstacks in ppltasks.\n    ///     Members of this class is examined by vc debugger, thus there will be no public access methods.\n    ///     Please note that names of this class should be kept stable for debugger examining.\n    /// </summary>\n    class _TaskCreationCallstack\n    {\n    private:\n        // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame;\n        // otherwise, _M_Frame will store all the callstack frames.\n        void* _M_SingleFrame;\n        std::vector<void *> _M_frames;\n    public:\n        _TaskCreationCallstack()\n        {\n            _M_SingleFrame = nullptr;\n        }\n\n        // Store one frame of callstack. This function works for both Debug / Release CRT.\n        static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame)\n        {\n            _TaskCreationCallstack _csc;\n            _csc._M_SingleFrame = _SingleFrame;\n            return _csc;\n        }\n\n        // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT.\n        __declspec(noinline)\n        static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames)\n        {\n            _TaskCreationCallstack _csc;\n            _csc._M_frames.resize(_CaptureFrames);\n            // skip 2 frames to make sure callstack starts from user code \n            _csc._M_frames.resize(::pplx::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames));\n            return _csc;\n        }\n    };\n    typedef unsigned char _Unit_type;\n\n    struct _TypeSelectorNoAsync {};\n    struct _TypeSelectorAsyncOperationOrTask {};\n    struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { };\n    struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { };\n    struct _TypeSelectorAsyncAction {};\n    struct _TypeSelectorAsyncActionWithProgress {};\n    struct _TypeSelectorAsyncOperationWithProgress {};\n\n    template<typename _Ty>\n    struct _NormalizeVoidToUnitType\n    {\n        typedef _Ty _Type;\n    };\n\n    template<>\n    struct _NormalizeVoidToUnitType<void>\n    {\n        typedef _Unit_type _Type;\n    };\n\n    template<typename _T>\n    struct _IsUnwrappedAsyncSelector\n    {\n        static const bool _Value = true;\n    };\n\n    template<>\n    struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync>\n    {\n        static const bool _Value = false;\n    };\n\n    template <typename _Ty>\n    struct _UnwrapTaskType\n    {\n        typedef _Ty _Type;\n    };\n\n    template <typename _Ty>\n    struct _UnwrapTaskType<task<_Ty>>\n    {\n        typedef _Ty _Type;\n    };\n\n    template <typename _T>\n    _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>);\n\n    _TypeSelectorNoAsync _AsyncOperationKindSelector(...);\n\n#if defined(__cplusplus_winrt)\n    template <typename _Type>\n    struct _Unhat\n    {\n        typedef _Type _Value;\n    };\n\n    template <typename _Type>\n    struct _Unhat<_Type^>\n    {\n        typedef _Type _Value;\n    };\n\n    value struct _NonUserType { public: int _Dummy; };\n\n    template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>\n    struct _ValueTypeOrRefType\n    {\n        typedef _NonUserType _Value;\n    };\n\n    template <typename _Type>\n    struct _ValueTypeOrRefType<_Type, true>\n    {\n        typedef _Type _Value;\n    };\n\n    template <typename _T1, typename _T2>\n    _T2 _ProgressTypeSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1,_T2>^);\n\n    template <typename _T1>\n    _T1 _ProgressTypeSelector(Windows::Foundation::IAsyncActionWithProgress<_T1>^);\n\n    template <typename _Type>\n    struct _GetProgressType\n    {\n        typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value;\n    };\n\n    template <typename _Type>\n    struct _IsIAsyncInfo\n    {\n        static const bool _Value = __is_base_of(Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value);\n    };\n\n    template <typename _T>\n    _TypeSelectorAsyncOperation _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperation<_T>^);\n\n    _TypeSelectorAsyncAction _AsyncOperationKindSelector(Windows::Foundation::IAsyncAction^);\n\n    template <typename _T1, typename _T2>\n    _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>^);\n\n    template <typename _T>\n    _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncActionWithProgress<_T>^);\n\n    template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value>\n    struct _TaskTypeTraits\n    {\n        typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;\n        typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;\n        typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;\n\n        static const bool _IsAsyncTask = _IsAsync;\n        static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;\n    };\n\n    template<typename _Type>\n    struct _TaskTypeTraits<_Type, true >\n    {\n        typedef decltype(((_Type)nullptr)->GetResults()) _TaskRetType;\n        typedef _TaskRetType _NormalizedTaskRetType;\n        typedef decltype(_AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind;\n\n        static const bool _IsAsyncTask = true;\n        static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;\n    };\n\n#else  /* defined (__cplusplus_winrt) */\n    template <typename _Type>\n    struct _IsIAsyncInfo\n    {\n        static const bool _Value = false;\n    };\n\n    template <typename _Type, bool _IsAsync = false>\n    struct _TaskTypeTraits\n    {\n        typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;\n        typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;\n        typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;\n\n        static const bool _IsAsyncTask = false;\n        static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;\n    };\n#endif  /* defined (__cplusplus_winrt) */\n\n    template <typename _Function> auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)(_Func); return std::true_type(); }\n    template <typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }\n\n    template <>\n    struct _TaskTypeTraits<void>\n    {\n        typedef void _TaskRetType;\n        typedef _TypeSelectorNoAsync _AsyncKind;\n        typedef _Unit_type _NormalizedTaskRetType;\n\n        static const bool _IsAsyncTask = false;\n        static const bool _IsUnwrappedTaskOrAsync = false;\n    };\n\n    template<typename _Type>\n    task<_Type> _To_task(_Type t);\n    \n    template<typename _Func>\n    task<void> _To_task_void(_Func f);\n    \n    struct _BadContinuationParamType{};\n\n    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)));\n    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t));\n    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, ...) -> _BadContinuationParamType;\n\n    template <typename _Function, typename _Type> auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type());\n    template <typename _Function, typename _Type> std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...);\n\n    template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)));\n    template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func());\n\n    template <typename _Function> auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)), std::true_type());\n    template <typename _Function> std::false_type _VoidIsTaskHelper(_Function _Func, int, ...);\n\n    template<typename _Function, typename _ExpectedParameterType>\n    struct _FunctionTypeTraits\n    {\n        typedef decltype(_ReturnTypeHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _FuncRetType;\n        static_assert(!std::is_same<_FuncRetType,_BadContinuationParamType>::value, \"incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)\");\n\n        typedef decltype(_IsTaskHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _Takes_task;\n    };\n\n    template<typename _Function>\n    struct _FunctionTypeTraits<_Function, void>\n    {\n        typedef decltype(_VoidReturnTypeHelper(stdx::declval<_Function>(), 0, 0)) _FuncRetType;\n        typedef decltype(_VoidIsTaskHelper(stdx::declval<_Function>(), 0, 0)) _Takes_task;\n    };\n\n    template<typename _Function, typename _ReturnType>\n    struct _ContinuationTypeTraits\n    {\n        typedef task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType> _TaskOfType;\n    };\n\n    // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is\n    // declared, the constructor may or may not perform unwrapping. For eg.\n    //\n    //  This declaration SHOULD NOT cause unwrapping\n    //    task<task<void>> t1([]() -> task<void> {\n    //        task<void> t2([]() {});\n    //        return t2;\n    //    });\n    //\n    // This declaration SHOULD cause unwrapping\n    //    task<void>> t1([]() -> task<void> {\n    //        task<void> t2([]() {});\n    //        return t2;\n    //    });\n    // If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal rules apply.\n    template <typename _TaskType, typename _FuncRetType>\n    struct _InitFunctorTypeTraits\n    {\n        typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind;\n        static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask;\n        static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync;\n    };\n\n    template<typename T>\n    struct _InitFunctorTypeTraits<T, T>\n    {\n        typedef _TypeSelectorNoAsync _AsyncKind;\n        static const bool _IsAsyncTask = false;\n        static const bool _IsUnwrappedTaskOrAsync = false;\n    };\n\n    /// <summary>\n    ///     Helper object used for LWT invocation.\n    /// </summary>\n    struct _TaskProcThunk\n    {\n        _TaskProcThunk(const std::function<void ()> & _Callback) :\n            _M_func(_Callback)\n        {\n        }\n\n        static void _pplx_cdecl _Bridge(void *_PData)\n        {\n            _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData);\n            _Holder _ThunkHolder(_PThunk);\n            _PThunk->_M_func();\n        }\n    private:\n\n        // RAII holder\n        struct _Holder\n        {\n            _Holder(_TaskProcThunk * _PThunk) : _M_pThunk(_PThunk)\n            {\n            }\n\n            ~_Holder()\n            {\n                delete _M_pThunk;\n            }\n\n            _TaskProcThunk * _M_pThunk;\n\n        private:\n            _Holder& operator=(const _Holder&);\n        };\n\n        std::function<void()> _M_func;\n        _TaskProcThunk& operator=(const _TaskProcThunk&);\n    };\n\n    /// <summary>\n    ///     Schedule a functor with automatic inlining. Note that this is \"fire and forget\" scheduling, which cannot be\n    ///     waited on or canceled after scheduling.\n    ///     This schedule method will perform automatic inlining base on <paramref value=\"_InliningMode\"/>.\n    /// </summary>\n    /// <param name=\"_Func\">\n    ///     The user functor need to be scheduled.\n    /// </param>\n    /// <param name=\"_InliningMode\">\n    ///     The inlining scheduling policy for current functor.\n    /// </param>\n    static void _ScheduleFuncWithAutoInline(const std::function<void ()> & _Func, _TaskInliningMode_t _InliningMode)\n    {\n        _TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode);\n    }\n\n    class _ContextCallback\n    {\n        typedef std::function<void(void)> _CallbackFunction;\n\n#if defined (__cplusplus_winrt)\n\n    public:\n\n        static _ContextCallback _CaptureCurrent()\n        {\n            _ContextCallback _Context;\n            _Context._Capture();\n            return _Context;\n        }\n\n        ~_ContextCallback()\n        {\n            _Reset();\n        }\n\n        _ContextCallback(bool _DeferCapture = false)\n        {\n            if (_DeferCapture)\n            {\n                _M_context._M_captureMethod = _S_captureDeferred;\n            }\n            else\n            {\n                _M_context._M_pContextCallback = nullptr;\n            }\n        }\n\n        // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).\n        void _Resolve(bool _CaptureCurrent)\n        {\n            if(_M_context._M_captureMethod == _S_captureDeferred)\n            {\n                _M_context._M_pContextCallback = nullptr;\n\n                if (_CaptureCurrent)\n                {\n                    if (_IsCurrentOriginSTA())\n                    {\n                        _Capture();\n                    }\n#if _UITHREADCTXT_SUPPORT\n                    else\n                    {\n                        // This method will fail if not called from the UI thread.\n                        HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback);\n                        if (FAILED(_Hr))\n                        {\n                            _M_context._M_pContextCallback = nullptr;\n                        }\n                    }\n#endif  /* _UITHREADCTXT_SUPPORT */\n                }\n            }\n        }\n\n        void _Capture()\n        {\n            HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback));\n            if (FAILED(_Hr))\n            {\n                _M_context._M_pContextCallback = nullptr;\n            }\n        }\n\n        _ContextCallback(const _ContextCallback& _Src)\n        {\n            _Assign(_Src._M_context._M_pContextCallback);\n        }\n\n        _ContextCallback(_ContextCallback&& _Src)\n        {\n            _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;\n            _Src._M_context._M_pContextCallback = nullptr;\n        }\n\n        _ContextCallback& operator=(const _ContextCallback& _Src)\n        {\n            if (this != &_Src)\n            {\n                _Reset();\n                _Assign(_Src._M_context._M_pContextCallback);\n            }\n            return *this;\n        }\n\n        _ContextCallback& operator=(_ContextCallback&& _Src)\n        {\n            if (this != &_Src)\n            {\n                _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;\n                _Src._M_context._M_pContextCallback = nullptr;\n            }\n            return *this;\n        }\n\n        bool _HasCapturedContext() const\n        {\n            _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred);\n            return (_M_context._M_pContextCallback != nullptr);\n        }\n\n        void _CallInContext(_CallbackFunction _Func) const\n        {\n            if (!_HasCapturedContext())\n            {\n                _Func();\n            }\n            else\n            {\n                ComCallData callData;\n                ZeroMemory(&callData, sizeof(callData));\n                callData.pUserDefined = reinterpret_cast<void *>(&_Func);\n\n                HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);\n                if (FAILED(_Hr))\n                {\n                    throw ::Platform::Exception::CreateException(_Hr);\n                }\n            }\n        }\n\n        bool operator==(const _ContextCallback& _Rhs) const\n        {\n            return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback);\n        }\n\n        bool operator!=(const _ContextCallback& _Rhs) const\n        {\n            return !(operator==(_Rhs));\n        }\n\n    private:\n       void _Reset()\n        {\n            if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)\n            {\n                _M_context._M_pContextCallback->Release();\n            }\n        }\n\n        void _Assign(IContextCallback *_PContextCallback)\n        {\n            _M_context._M_pContextCallback = _PContextCallback;\n            if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)\n            {\n                _M_context._M_pContextCallback->AddRef();\n            }\n        }\n\n        static HRESULT __stdcall _Bridge(ComCallData *_PParam)\n        {\n            _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined);\n            (*pFunc)();\n            return S_OK;\n        }\n\n        // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)\n        static bool _IsCurrentOriginSTA()\n        {\n            APTTYPE _AptType;\n            APTTYPEQUALIFIER _AptTypeQualifier;\n\n            HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);\n            if (SUCCEEDED(hr))\n            {\n                // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether\n                // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in\n                // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,\n                // since variables used within a neutral apartment are expected to be apartment neutral.\n                switch(_AptType)\n                {\n                    case APTTYPE_MAINSTA:\n                    case APTTYPE_STA:\n                        return true;\n                    default:\n                        break;\n                }\n            }\n            return false;\n        }\n\n        union\n        {\n            IContextCallback *_M_pContextCallback;\n            size_t _M_captureMethod;\n        } _M_context;\n\n        static const size_t _S_captureDeferred = 1;\n#else  /* defined (__cplusplus_winrt) */\n    public:\n\n        static _ContextCallback _CaptureCurrent()\n        {\n            return _ContextCallback();\n        }\n\n        _ContextCallback(bool = false)\n        {\n        }\n\n        _ContextCallback(const _ContextCallback&)\n        {\n        }\n\n        _ContextCallback(_ContextCallback&&)\n        {\n        }\n\n        _ContextCallback& operator=(const _ContextCallback&)\n        {\n            return *this;\n        }\n\n        _ContextCallback& operator=(_ContextCallback&&)\n        {\n            return *this;\n        }\n\n        bool _HasCapturedContext() const\n        {\n            return false;\n        }\n\n        void _Resolve(bool) const\n        {\n        }\n\n        void _CallInContext(_CallbackFunction _Func) const\n        {\n            _Func();\n        }\n\n        bool operator==(const _ContextCallback&) const\n        {\n            return true;\n        }\n\n        bool operator!=(const _ContextCallback&) const\n        {\n            return false;\n        }\n\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n    template<typename _Type>\n    struct _ResultHolder\n    {\n        void Set(const _Type& _type)\n        {\n            _Result = _type;\n        }\n\n        _Type Get()\n        {\n            return _Result;\n        }\n\n        _Type _Result;\n    };\n\n#if defined (__cplusplus_winrt)\n\n    template<typename _Type>\n    struct _ResultHolder<_Type^>\n    {\n        void Set(_Type^ const & _type)\n        {\n           _M_Result = _type;\n        }\n\n        _Type^ Get()\n        {\n            return _M_Result.Get();\n        }\n    private:\n        // ::Platform::Agile handle specialization of all hats\n        // including ::Platform::String and ::Platform::Array\n        ::Platform::Agile<_Type^> _M_Result;\n    };\n\n    //\n    // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.\n    //\n    template<typename _Type>\n    struct _ResultHolder<std::vector<_Type^>>\n    {\n        void Set(const std::vector<_Type^>& _type)\n        {\n            _Result.reserve(_type.size());\n\n            for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask)\n            {\n                _Result.emplace_back(*_PTask);\n            }\n        }\n\n        std::vector<_Type^> Get()\n        {\n            // Return vectory<T^> with the objects that are marshaled in the proper appartment\n            std::vector<_Type^> _Return;\n            _Return.reserve(_Result.size());\n\n            for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask)\n            {\n                _Return.push_back(_PTask->Get()); // Platform::Agile will marshal the object to appropriate appartment if neccessary\n            }\n\n            return _Return;\n        }\n\n        std::vector< ::Platform::Agile<_Type^> > _Result;\n    };\n\n    template<typename _Type>\n    struct _ResultHolder<std::pair<_Type^, void*> >\n    {\n        void Set(const std::pair<_Type^, size_t>& _type)\n        {\n            _M_Result = _type;\n        }\n\n        std::pair<_Type^, size_t> Get()\n        {\n            return std::make_pair(_M_Result.first.Get(), _M_Result.second);\n        }\n    private:\n        std::pair< ::Platform::Agile<_Type^>, size_t> _M_Result;\n    };\n\n#endif  /* defined (__cplusplus_winrt) */\n\n    // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.\n    // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception\n    // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.\n    struct _ExceptionHolder\n    {\n    private:\n        void ReportUnhandledError()\n        {\n#if _MSC_VER >= 1800 && defined(__cplusplus_winrt)\n            if (_M_winRTException != nullptr)\n            {\n                ::Platform::Details::ReportUnhandledError(_M_winRTException);\n            }\n#endif  /* defined (__cplusplus_winrt) */\n        }\n    public:\n        explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack &_stackTrace) :\n        _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace)\n#if defined (__cplusplus_winrt)\n            , _M_winRTException(nullptr)\n#endif  /* defined (__cplusplus_winrt) */\n        {\n        }\n\n#if defined (__cplusplus_winrt)\n        explicit _ExceptionHolder(::Platform::Exception^ _E, const _TaskCreationCallstack &_stackTrace) :\n        _M_exceptionObserved(0),  _M_winRTException(_E), _M_stackTrace(_stackTrace)\n        {\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        __declspec(noinline)\n        ~_ExceptionHolder()\n        {\n            if (_M_exceptionObserved == 0)\n            {\n                // If you are trapped here, it means an exception thrown in task chain didn't get handled.\n                // Please add task-based continuation to handle all exceptions coming from tasks.\n                // this->_M_stackTrace keeps the creation callstack of the task generates this exception.\n                _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();\n            }\n        }\n\n        void _RethrowUserException()\n        {\n            if (_M_exceptionObserved == 0)\n            {\n                atomic_exchange(_M_exceptionObserved, 1l);\n            }\n\n#if defined (__cplusplus_winrt)\n            if (_M_winRTException != nullptr)\n            {\n                throw _M_winRTException;\n            }\n#endif  /* defined (__cplusplus_winrt) */\n            std::rethrow_exception(_M_stdException);\n        }\n\n        // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that\n        // are unobserved when the exception holder is destructed will terminate the process.\n        atomic_long _M_exceptionObserved;\n\n        // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.\n        std::exception_ptr _M_stdException;\n#if defined (__cplusplus_winrt)\n        ::Platform::Exception^ _M_winRTException;\n#endif  /* defined (__cplusplus_winrt) */\n\n        // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,\n        // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call\n        // is to task_completion_event::set_exception, the set_exception method was the source of the exception.\n        // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.\n        _TaskCreationCallstack _M_stackTrace;\n\n    };\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Base converter class for converting asynchronous interfaces to IAsyncOperation\n    /// </summary>\n    template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result>\n    ref struct _AsyncInfoImpl abstract : Windows::Foundation::IAsyncOperation<_Result>\n    {\n    internal:\n        // The async action, action with progress or operation with progress that this stub forwards to.\n        ::Platform::Agile<_AsyncOperationType> _M_asyncInfo;\n\n        Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ _M_CompletedHandler;\n\n        _AsyncInfoImpl( _AsyncOperationType _AsyncInfo ) : _M_asyncInfo(_AsyncInfo) {}\n\n    public:\n        virtual void Cancel() { _M_asyncInfo.Get()->Cancel(); }\n        virtual void Close() { _M_asyncInfo.Get()->Close(); }\n\n        virtual property Windows::Foundation::HResult ErrorCode\n        {\n            Windows::Foundation::HResult get()\n            {\n                return _M_asyncInfo.Get()->ErrorCode;\n            }\n        }\n\n        virtual property UINT Id\n        {\n            UINT get()\n            {\n                return _M_asyncInfo.Get()->Id;\n            }\n        }\n\n        virtual property Windows::Foundation::AsyncStatus Status\n        {\n            Windows::Foundation::AsyncStatus get()\n            {\n                return _M_asyncInfo.Get()->Status;\n            }\n        }\n\n        virtual _Result GetResults() { throw std::runtime_error(\"derived class must implement\"); }\n\n        virtual property Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ Completed\n        {\n            Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ get()\n            {\n                return _M_CompletedHandler;\n            }\n\n            void set(Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ value)\n            {\n                _M_CompletedHandler = value;\n                _M_asyncInfo.Get()->Completed = ref new _CompletionHandlerType([&](_AsyncOperationType, Windows::Foundation::AsyncStatus status) {\n                    _M_CompletedHandler->Invoke(this, status);\n                });\n            }\n        }\n    };\n\n    /// <summary>\n    ///     Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>\n    /// </summary>\n    template<typename _Result, typename _Progress>\n    ref struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed :\n        _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,\n                      Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,\n                      _Result>\n    {\n    internal:\n        _IAsyncOperationWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^ _Operation) :\n            _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,\n                          Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,\n                          _Result>(_Operation) {}\n\n    public:\n        virtual _Result GetResults() override { return _M_asyncInfo.Get()->GetResults(); }\n    };\n\n    /// <summary>\n    ///     Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type>\n    /// </summary>\n    ref struct _IAsyncActionToAsyncOperationConverter sealed :\n        _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,\n                      Windows::Foundation::AsyncActionCompletedHandler,\n                      details::_Unit_type>\n    {\n    internal:\n        _IAsyncActionToAsyncOperationConverter(Windows::Foundation::IAsyncAction^ _Operation) :\n            _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,\n                          Windows::Foundation::AsyncActionCompletedHandler,\n                          details::_Unit_type>(_Operation) {}\n\n    public:\n        virtual details::_Unit_type GetResults() override\n        {\n            // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.\n            _M_asyncInfo.Get()->GetResults();\n            return details::_Unit_type();\n        }\n    };\n\n    /// <summary>\n    ///     Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type>\n    /// </summary>\n    template<typename _Progress>\n    ref struct _IAsyncActionWithProgressToAsyncOperationConverter sealed :\n        _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,\n                      Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,\n                      details::_Unit_type>\n    {\n    internal:\n        _IAsyncActionWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ _Action) :\n            _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,\n                          Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,\n                          details::_Unit_type>(_Action) {}\n    public:\n        virtual details::_Unit_type GetResults() override\n        {\n            // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.\n            _M_asyncInfo.Get()->GetResults();\n            return details::_Unit_type();\n        }\n    };\n#endif  /* defined (__cplusplus_winrt) */\n} // namespace details\n\n/// <summary>\n///     The <c>task_continuation_context</c> class allows you to specify where you would like a continuation to be executed.\n///     It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's\n///     execution context is determined by the runtime, and not configurable.\n/// </summary>\n/// <seealso cref=\"task Class\"/>\n/**/\nclass task_continuation_context : public details::_ContextCallback\n{\npublic:\n\n    /// <summary>\n    ///     Creates the default task continuation context.\n    /// </summary>\n    /// <returns>\n    ///     The default continuation context.\n    /// </returns>\n    /// <remarks>\n    ///     The default context is used if you don't specifiy a continuation context when you call the <c>then</c> method. In Windows\n    ///     applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where\n    ///     task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an\n    ///     apartment aware task is the apartment where <c>then</c> is invoked.\n    ///     <para>An apartment aware task is a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such\n    ///     a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in\n    ///     that STA.</para>\n    ///     <para>A continuation on a non-apartment aware task will execute in a context the Runtime chooses.</para>\n    /// </remarks>\n    /**/\n    static task_continuation_context use_default()\n    {\n#if defined (__cplusplus_winrt)\n        // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()\n        return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle\n#else  /* defined (__cplusplus_winrt) */\n        return task_continuation_context();\n#endif  /* defined (__cplusplus_winrt) */\n    }\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Creates a task continuation context which allows the Runtime to choose the execution context for a continuation.\n    /// </summary>\n    /// <returns>\n    ///     A task continuation context that represents an arbitrary location.\n    /// </returns>\n    /// <remarks>\n    ///     When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task\n    ///     is apartment aware.\n    ///     <para><c>use_arbitrary</c> can be used to turn off the default behavior for a continuation on an apartment\n    ///     aware task created in an STA. </para>\n    ///     <para>This method is only available to Windows Store apps.</para>\n    /// </remarks>\n    /**/\n    static task_continuation_context use_arbitrary()\n    {\n        task_continuation_context _Arbitrary(true);\n        _Arbitrary._Resolve(false);\n        return _Arbitrary;\n    }\n\n    /// <summary>\n    ///     Returns a task continuation context object that represents the current execution context.\n    /// </summary>\n    /// <returns>\n    ///     The current execution context.\n    /// </returns>\n    /// <remarks>\n    ///     This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment.\n    ///     <para>The value returned by <c>use_current</c> can be used to indicate to the Runtime that the continuation should execute in\n    ///     the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is\n    ///     a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such a task. </para>\n    ///     <para>This method is only available to Windows Store apps.</para>\n    /// </remarks>\n    /**/\n    static task_continuation_context use_current()\n    {\n        task_continuation_context _Current(true);\n        _Current._Resolve(true);\n        return _Current;\n    }\n#endif  /* defined (__cplusplus_winrt) */\n\nprivate:\n\n    task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture)\n    {\n    }\n};\n\nclass task_options;\nnamespace details\n{\n    struct _Internal_task_options\n    {\n        bool _M_hasPresetCreationCallstack;\n        _TaskCreationCallstack _M_presetCreationCallstack;\n\n        void _set_creation_callstack(const _TaskCreationCallstack &_callstack)\n        {\n            _M_hasPresetCreationCallstack = true;\n            _M_presetCreationCallstack = _callstack;\n        }\n        _Internal_task_options()\n        {\n            _M_hasPresetCreationCallstack = false;\n        }\n    };\n\n    inline _Internal_task_options &_get_internal_task_options(task_options &options);\n    inline const _Internal_task_options &_get_internal_task_options(const task_options &options);\n}\n/// <summary>\n///     Represents the allowed options for creating a task\n/// </summary>\nclass task_options\n{\npublic:\n\n\n    /// <summary>\n    ///     Default list of task creation options\n    /// </summary>\n    task_options()\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a cancellation token\n    /// </summary>\n    task_options(cancellation_token _Token)\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(_Token),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(true),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a continuation context. This is valid only for continuations (then)\n    /// </summary>\n    task_options(task_continuation_context _ContinuationContext)\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(_ContinuationContext),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a cancellation token and a continuation context. This is valid only for continuations (then)\n    /// </summary>\n    task_options(cancellation_token _Token, task_continuation_context _ContinuationContext)\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(_Token),\n          _M_ContinuationContext(_ContinuationContext),\n          _M_HasCancellationToken(true),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a scheduler with shared lifetime\n    /// </summary>\n    template<typename _SchedType>\n    task_options(std::shared_ptr<_SchedType> _Scheduler)\n        : _M_Scheduler(std::move(_Scheduler)),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(true)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a scheduler reference\n    /// </summary>\n    task_options(scheduler_interface& _Scheduler)\n        : _M_Scheduler(&_Scheduler),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(true)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a scheduler\n    /// </summary>\n    task_options(scheduler_ptr _Scheduler)\n        : _M_Scheduler(std::move(_Scheduler)),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(true)\n    {\n    }\n\n    /// <summary>\n    ///     Task option copy constructor\n    /// </summary>\n    task_options(const task_options& _TaskOptions)\n        : _M_Scheduler(_TaskOptions.get_scheduler()),\n          _M_CancellationToken(_TaskOptions.get_cancellation_token()),\n          _M_ContinuationContext(_TaskOptions.get_continuation_context()),\n          _M_HasCancellationToken(_TaskOptions.has_cancellation_token()),\n          _M_HasScheduler(_TaskOptions.has_scheduler())        \n    {\n    }\n\n    /// <summary>\n    ///     Sets the given token in the options\n    /// </summary>\n    void set_cancellation_token(cancellation_token _Token)\n    {\n        _M_CancellationToken = _Token;\n       _M_HasCancellationToken = true;\n    }\n\n    /// <summary>\n    ///     Sets the given continuation context in the options\n    /// </summary>\n    void set_continuation_context(task_continuation_context _ContinuationContext)\n    {\n        _M_ContinuationContext = _ContinuationContext;\n    }\n\n    /// <summary>\n    ///     Indicates whether a cancellation token was specified by the user\n    /// </summary>\n    bool has_cancellation_token() const\n    {\n        return _M_HasCancellationToken;\n    }\n\n    /// <summary>\n    ///     Returns the cancellation token\n    /// </summary>\n    cancellation_token get_cancellation_token() const\n    {\n        return _M_CancellationToken;\n    }\n\n    /// <summary>\n    ///     Returns the continuation context\n    /// </summary>\n    task_continuation_context get_continuation_context() const\n    {\n        return _M_ContinuationContext;\n    }\n\n    /// <summary>\n    ///     Indicates whether a scheduler n was specified by the user\n    /// </summary>\n    bool has_scheduler() const\n    {\n        return _M_HasScheduler;\n    }\n\n    /// <summary>\n    ///     Returns the scheduler\n    /// </summary>\n    scheduler_ptr get_scheduler() const\n    {\n        return _M_Scheduler;\n    }\n\nprivate:\n\n    task_options const& operator=(task_options const& _Right);\n    friend details::_Internal_task_options &details::_get_internal_task_options(task_options &);\n    friend const details::_Internal_task_options &details::_get_internal_task_options(const task_options &);\n\n    scheduler_ptr _M_Scheduler;\n    cancellation_token _M_CancellationToken;\n    task_continuation_context _M_ContinuationContext;\n    details::_Internal_task_options _M_InternalTaskOptions;\n    bool _M_HasCancellationToken;\n    bool _M_HasScheduler;\n};\n\nnamespace details\n{\n    inline _Internal_task_options & _get_internal_task_options(task_options &options)\n    {\n        return options._M_InternalTaskOptions;\n    }\n    inline const _Internal_task_options & _get_internal_task_options(const task_options &options)\n    {\n        return options._M_InternalTaskOptions;\n    }\n\n    struct _Task_impl_base;\n    template<typename _ReturnType> struct _Task_impl;\n\n    template<typename _ReturnType>\n    struct _Task_ptr\n    {\n        typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type;\n        static _Type _Make(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); }\n    };\n\n    typedef _TaskCollection_t::_TaskProcHandle_t _UnrealizedChore_t;\n    typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base;\n\n    // The weak-typed base task handler for continuation tasks.\n    struct _ContinuationTaskHandleBase : _UnrealizedChore_t\n    {\n        _ContinuationTaskHandleBase * _M_next;\n        task_continuation_context _M_continuationContext;\n        bool _M_isTaskBasedContinuation;\n\n        // This field gives inlining scheduling policy for current chore.\n        _TaskInliningMode_t _M_inliningMode;\n        \n        virtual _Task_ptr_base _GetTaskImplBase() const = 0;\n\n        _ContinuationTaskHandleBase() : \n            _M_next(nullptr), _M_continuationContext(task_continuation_context::use_default()), _M_isTaskBasedContinuation(false), _M_inliningMode(details::_NoInline)\n        {\n        }\n\n        virtual ~_ContinuationTaskHandleBase() {}\n    };\n\n#if _PPLTASK_ASYNC_LOGGING\n    // GUID used for identifying causality logs from PPLTask\n    const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE);\n\n    __declspec(selectany) volatile long _isCausalitySupported = 0;\n\n    inline bool _IsCausalitySupported()\n    {\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)\n        if (_isCausalitySupported == 0)\n        {\n            long _causality = 1;\n            OSVERSIONINFOEX _osvi = {};\n            _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\n\n            // The Causality is supported on Windows version higher than Windows 8\n            _osvi.dwMajorVersion = 6;\n            _osvi.dwMinorVersion = 3;\n\n            DWORDLONG _conditionMask = 0;\n            VER_SET_CONDITION( _conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );\n            VER_SET_CONDITION( _conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );\n\n            if ( ::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask)) \n            {\n                _causality = 2;\n            }\n\n            _isCausalitySupported = _causality;\n            return _causality == 2;\n        }\n\n        return _isCausalitySupported == 2 ? true : false;\n#else\n        return true;\n#endif\n    }\n\n    // Stateful logger rests inside task_impl_base. \n    struct _TaskEventLogger\n    {\n        _Task_impl_base *_M_task;\n        bool _M_scheduled;\n        bool _M_taskPostEventStarted;\n\n        // Log before scheduling task\n        void _LogScheduleTask(bool _isContinuation)\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, \n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), \n                    _isContinuation ? \"pplx::PPLTask::ScheduleContinuationTask\" : \"pplx::PPLTask::ScheduleTask\", 0);\n                _M_scheduled = true;\n            } \n        }\n\n        // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state.\n        void _LogCancelTask()\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel);\n\n            } \n        }\n\n        // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run\n        void _LogTaskCompleted();\n\n        // Log when task body (which includes user lambda and other scheduling code) begin to run\n        void _LogTaskExecutionStarted() { }\n\n        // Log when task body finish executing\n        void _LogTaskExecutionCompleted()\n        {\n            if (_M_taskPostEventStarted && details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);\n            }\n        }\n\n        // Log right before user lambda being invoked\n        void _LogWorkItemStarted()\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);\n            }\n        }\n\n        // Log right after user lambda being invoked\n        void _LogWorkItemCompleted()\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);\n\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);\n                _M_taskPostEventStarted = true;\n            }\n        }\n        \n        _TaskEventLogger(_Task_impl_base *_task): _M_task(_task)\n        {\n            _M_scheduled = false;\n            _M_taskPostEventStarted = false;\n        }\n    };\n\n    // Exception safe logger for user lambda\n    struct _TaskWorkItemRAIILogger\n    {\n        _TaskEventLogger &_M_logger;\n        _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger): _M_logger(_taskHandleLogger)\n        {\n            _M_logger._LogWorkItemStarted();\n        }\n\n        ~_TaskWorkItemRAIILogger()\n        {\n            _M_logger._LogWorkItemCompleted();\n        }\n        _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned\n    };\n\n#else\n    inline void _LogCancelTask(_Task_impl_base *) {}\n    struct _TaskEventLogger\n    {\n        void _LogScheduleTask(bool) {}\n        void _LogCancelTask() {}\n        void _LogWorkItemStarted() {}\n        void _LogWorkItemCompleted() {}\n        void _LogTaskExecutionStarted() {}\n        void _LogTaskExecutionCompleted() {}\n        void _LogTaskCompleted() {}\n        _TaskEventLogger(_Task_impl_base *) {}\n    };\n    struct _TaskWorkItemRAIILogger\n    {\n        _TaskWorkItemRAIILogger(_TaskEventLogger &) {}\n    };\n#endif\n\n    /// <summary>\n    ///     The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler\n    ///     to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks.\n    ///     For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore_t, and for continuation tasks, it will be derived from\n    ///     _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled.\n    /// </summary>\n    /// <typeparam name=\"_ReturnType\">\n    ///     The result type of the _Task_impl.\n    /// </typeparam>\n    /// <typeparam name=\"_DerivedTaskHandle\">\n    ///     The derived task handle class. The <c>operator ()</c> needs to be implemented.\n    /// </typeparam>\n    /// <typeparam name=\"_BaseTaskHandle\">\n    ///     The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore_t or _ContinuationTaskHandleBase.\n    /// </typeparam>\n    template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle>\n    struct _PPLTaskHandle : _BaseTaskHandle\n    {\n        _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask)\n        {\n        }\n\n        virtual ~_PPLTaskHandle() \n        {\n            // Here is the sink of all task completion code paths\n            _M_pTask->_M_taskEventLogger._LogTaskCompleted();\n        }\n\n        virtual void invoke() const\n        {\n            // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled\n            // by the runtime.\n            _ASSERTE((bool)_M_pTask);\n            if (!_M_pTask->_TransitionedToStarted())\n            {\n                static_cast<const _DerivedTaskHandle *>(this)->_SyncCancelAndPropagateException();\n                return;\n            }\n\n            _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted();\n            try\n            {\n                // All derived task handle must implement this contract function.\n                static_cast<const _DerivedTaskHandle *>(this)->_Perform();\n            }\n            catch(const task_canceled &)\n            {\n                _M_pTask->_Cancel(true);\n            }\n            catch(const _Interruption_exception &)\n            {\n                _M_pTask->_Cancel(true);\n            }\n#if defined (__cplusplus_winrt)\n            catch(::Platform::Exception^ _E)\n            {\n                _M_pTask->_CancelWithException(_E);\n            }\n#endif  /* defined (__cplusplus_winrt) */\n            catch(...)\n            {\n                _M_pTask->_CancelWithException(std::current_exception());\n            }\n            _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted();\n        }\n\n        // Cast _M_pTask pointer to \"type-less\" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.\n        // The return value should be automatically optimized by R-value ref.\n        _Task_ptr_base _GetTaskImplBase() const\n        {\n            return _M_pTask;\n        }\n\n        typename _Task_ptr<_ReturnType>::_Type _M_pTask;\n    private:\n        _PPLTaskHandle const & operator=(_PPLTaskHandle const&);    // no assignment operator\n    };\n\n    /// <summary>\n    ///     The base implementation of a first-class task. This class contains all the non-type specific\n    ///     implementation details of the task.\n    /// </summary>\n    /**/\n    struct _Task_impl_base\n    {\n        enum _TaskInternalState\n        {\n            // Tracks the state of the task, rather than the task collection on which the task is scheduled\n            _Created,\n            _Started,\n            _PendingCancel,\n            _Completed,\n            _Canceled\n        };\n// _M_taskEventLogger - 'this' : used in base member initializer list\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 4355)\n#endif\n        _Task_impl_base(_CancellationTokenState * _PTokenState, scheduler_ptr _Scheduler_arg) \n                          : _M_TaskState(_Created),\n                            _M_fFromAsync(false), _M_fUnwrappedTask(false),\n                            _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg),\n                            _M_taskEventLogger(this)                           \n        {\n            // Set cancelation token\n            _M_pTokenState = _PTokenState;\n            _ASSERTE(_M_pTokenState != nullptr);\n            if (_M_pTokenState != _CancellationTokenState::_None())\n                _M_pTokenState->_Reference();\n        }\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n        virtual ~_Task_impl_base()\n        {\n            _ASSERTE(_M_pTokenState != nullptr);\n            if (_M_pTokenState != _CancellationTokenState::_None())\n            {\n                _M_pTokenState->_Release();\n            }\n        }\n\n        task_status _Wait()\n        {\n            bool _DoWait = true;\n\n#if defined (__cplusplus_winrt)\n            if (_IsNonBlockingThread())\n            {\n                // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal\n                // if task has not been completed.\n                if (!_IsCompleted() && !_IsCanceled())\n                {\n                    throw invalid_operation(\"Illegal to wait on a task in a Windows Runtime STA\");\n                }\n                else\n                {\n                    // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation\n                    // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM\n                    // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which\n                    // task based continuations are wont to do), waiting on the task group results in on the chore that is making this\n                    // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on\n                    // if it has finished execution (which means now we are on the inline synchronous callback).\n                    _DoWait = false;\n                }\n            }\n#endif  /* defined (__cplusplus_winrt) */\n            if (_DoWait)\n            {\n                // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The\n                // async operation will take place on a thread in the appropriate apartment Simply wait for the completed\n                // event to be set.\n                if (_M_fFromAsync)\n                {\n                    _M_TaskCollection._Wait();\n                }\n                else\n                {\n                    // Wait on the task collection to complete. The task collection is guaranteed to still be\n                    // valid since the task must be still within scope so that the _Task_impl_base destructor\n                    // has not yet been called. This call to _Wait potentially inlines execution of work.\n                    try\n                    {\n                        // Invoking wait on a task collection resets the state of the task collection. This means that\n                        // if the task collection itself were canceled, or had encountered an exception, only the first\n                        // call to wait will receive this status. However, both cancellation and exceptions flowing through\n                        // tasks set state in the task impl itself.\n\n                        // When it returns cancelled, either work chore or the cancel thread should already have set task's state\n                        // properly -- cancelled state or completed state (because there was no interruption point).\n                        // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.\n                        _M_TaskCollection._RunAndWait();\n                    }\n                    catch(details::_Interruption_exception&)\n                    {\n                        // The _TaskCollection will never be an interruption point since it has a none token.\n                        _ASSERTE(false);\n                    }\n                    catch(task_canceled&)\n                    {\n                        // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task\n                        // must be called from code that is executed within the task (throwing it from parallel work created by and waited\n                        // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen\n                        // the exception and canceled the task. Swallow the exception here.\n                        _ASSERTE(_IsCanceled());\n                    }\n#if defined (__cplusplus_winrt)\n                    catch(::Platform::Exception^ _E)\n                    {\n                        // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.\n                        if(!_HasUserException())\n                        {\n                            _CancelWithException(_E);\n                        }\n                        // Rethrow will mark the exception as observed.\n                        _M_exceptionHolder->_RethrowUserException();\n                    }\n#endif  /* defined (__cplusplus_winrt) */\n                    catch(...)\n                    {\n                        // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.\n                        if(!_HasUserException())\n                        {\n                            _CancelWithException(std::current_exception());\n                        }\n                        // Rethrow will mark the exception as observed.\n                        _M_exceptionHolder->_RethrowUserException();\n                    }\n\n                    // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task\n                    // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must\n                    // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;\n                    // however, this takes the tact of simply waiting upon the completion signal.\n                    if (_M_fUnwrappedTask)\n                    {\n                        _M_TaskCollection._Wait();\n                    }\n                }\n            }\n\n            if (_HasUserException())\n            {\n                _M_exceptionHolder->_RethrowUserException();\n            }\n            else if (_IsCanceled())\n            {\n                return canceled;\n            }\n            _ASSERTE(_IsCompleted());\n            return completed;\n        }\n\n        /// <summary>\n        ///     Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state.\n        /// </summary>\n        /// <param name=\"_SynchronousCancel\">\n        ///     Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task\n        ///     was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at\n        ///     the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could\n        ///     be executing the task, that is the task could execute concurrently while the cancellation is in progress.\n        /// </param>\n        /// <param name=\"_UserException\">\n        ///     Whether an exception other than the internal runtime cancellation exceptions caused this cancellation.\n        /// </param>\n        /// <param name=\"_PropagatedFromAncestor\">\n        ///     Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when\n        ///     _UserException is set to true.\n        /// </param>\n        /// <param name=\"_ExHolder\">\n        ///     The exception holder that represents the exception. Only valid when _UserException is set to true.\n        /// </param>\n        virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0;\n\n        bool _Cancel(bool _SynchronousCancel)\n        {\n            // Send in a dummy value for exception. It is not used when the first parameter is false.\n            return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder);\n        }\n\n        bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor)\n        {\n            // This task was canceled because an ancestor task encountered an exception.\n            return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder);\n        }\n\n#if defined (__cplusplus_winrt)\n        bool _CancelWithException(::Platform::Exception^ _Exception)\n        {\n            // This task was canceled because the task body encountered an exception.\n            _ASSERTE(!_HasUserException());\n            return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        bool _CancelWithException(const std::exception_ptr& _Exception)\n        {\n            // This task was canceled because the task body encountered an exception.\n            _ASSERTE(!_HasUserException());\n            return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));\n        }\n\n        void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr)\n        {\n            _ASSERTE(details::_CancellationTokenState::_IsValid(_M_pTokenState));\n\n            auto _CancellationCallback = [_WeakPtr](){\n                // Taking ownership of the task prevents dead lock during destruction\n                // if the destructor waits for the cancellations to be finished\n                auto _task = _WeakPtr.lock();\n                if (_task != nullptr)\n                    _task->_Cancel(false);\n            };\n\n            _M_pRegistration = new details::_CancellationTokenCallback<decltype(_CancellationCallback)>(_CancellationCallback);\n            _M_pTokenState->_RegisterCallback(_M_pRegistration);\n        }\n\n        void _DeregisterCancellation()\n        {\n            if (_M_pRegistration != nullptr)\n            {\n                _M_pTokenState->_DeregisterCallback(_M_pRegistration);\n                _M_pRegistration->_Release();\n                _M_pRegistration = nullptr;\n            }\n        }\n\n        bool _IsCreated()\n        {\n            return (_M_TaskState == _Created);\n        }\n\n        bool _IsStarted()\n        {\n            return (_M_TaskState == _Started);\n        }\n\n        bool _IsPendingCancel()\n        {\n            return (_M_TaskState == _PendingCancel);\n        }\n\n        bool _IsCompleted()\n        {\n            return (_M_TaskState == _Completed);\n        }\n\n        bool _IsCanceled()\n        {\n            return (_M_TaskState == _Canceled);\n        }\n\n        bool _HasUserException()\n        {\n            return static_cast<bool>(_M_exceptionHolder);\n        }\n\n        const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder()\n        {\n            _ASSERTE(_HasUserException());\n            return _M_exceptionHolder;\n        }\n\n        bool _IsApartmentAware()\n        {\n            return _M_fFromAsync;\n        }\n\n        void _SetAsync(bool _Async = true)\n        {\n            _M_fFromAsync = _Async;\n        }\n\n        _TaskCreationCallstack _GetTaskCreationCallstack()\n        {\n            return _M_pTaskCreationCallstack;\n        }\n\n        void _SetTaskCreationCallstack(const _TaskCreationCallstack &_Callstack)\n        {\n            _M_pTaskCreationCallstack = _Callstack;\n        }\n\n        /// <summary>\n        ///     Helper function to schedule the task on the Task Collection.\n        /// </summary>\n        /// <param name=\"_PTaskHandle\">\n        ///     The task chore handle that need to be executed.\n        /// </param>\n        /// <param name=\"_InliningMode\">\n        ///     The inlining scheduling policy for current _PTaskHandle.\n        /// </param>\n        void _ScheduleTask(_UnrealizedChore_t * _PTaskHandle, _TaskInliningMode_t _InliningMode)\n        {\n            try\n            {\n                _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode);\n            }\n            catch(const task_canceled &)\n            {\n                // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task\n                // must be called from code that is executed within the task (throwing it from parallel work created by and waited\n                // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen\n                // the exception and canceled the task. Swallow the exception here.\n                _ASSERTE(_IsCanceled());\n            }\n            catch(const _Interruption_exception &)\n            {\n                // The _TaskCollection will never be an interruption point since it has a none token.\n                _ASSERTE(false);\n            }\n            catch(...)\n            {\n                // The exception could have come from two places:\n                //   1. From the chore body, so it already should have been caught and canceled.\n                //      In this case swallow the exception.\n                //   2. From trying to actually schedule the task on the scheduler.\n                //      In this case cancel the task with the current exception, otherwise the\n                //      task will never be signaled leading to deadlock when waiting on the task.\n                if (!_HasUserException())\n                {\n                    _CancelWithException(std::current_exception());\n                }\n            }\n        }\n\n        /// <summary>\n        ///     Function executes a continuation. This function is recorded by a parent task implementation\n        ///     when a continuation is created in order to execute later.\n        /// </summary>\n        /// <param name=\"_PTaskHandle\">\n        ///     The continuation task chore handle that need to be executed.\n        /// </param>\n        /**/\n        void _RunContinuation(_ContinuationTaskHandleBase * _PTaskHandle)\n        {\n            _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase();\n            if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation)\n            {\n                if (_HasUserException())\n                {\n                    // If the ancestor encountered an exception, transfer the exception to the continuation\n                    // This traverses down the tree to propagate the exception.\n                    _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true);\n                }\n                else\n                {\n                    // If the ancestor was canceled, then your own execution should be canceled.\n                    // This traverses down the tree to cancel it.\n                    _ImplBase->_Cancel(true);\n                }\n            }\n            else\n            {\n                // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled\n                // (with or without a user exception).\n                _ASSERTE(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation);\n                _ASSERTE(!_ImplBase->_IsCanceled());\n                return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);\n            }\n\n            // If the handle is not scheduled, we need to manually delete it.\n            delete _PTaskHandle;\n        }\n\n        // Schedule a continuation to run\n        void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle)\n        {\n            \n            _M_taskEventLogger._LogScheduleTask(true);\n            // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)\n            if (_PTaskHandle->_M_continuationContext._HasCapturedContext())\n            {\n                // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,\n                // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce\n                // the cost of marshaling.\n                // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.\n                if (_PTaskHandle->_M_inliningMode != details::_ForceInline)\n                {\n                    _PTaskHandle->_M_inliningMode = details::_DefaultAutoInline;\n                }\n                _ScheduleFuncWithAutoInline([_PTaskHandle]() {\n                    // Note that we cannot directly capture \"this\" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.\n                    // Because \"this\" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.\n                    auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase();\n                    if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext)\n                    {\n                        _TaskImplPtr->_ScheduleTask(_PTaskHandle, details::_ForceInline);\n                    }\n                    else\n                    {\n                        //\n                        // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle\n                        // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:\n                        //\n                        // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into\n                        // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will\n                        // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).\n                        //\n                        try\n                        {\n                            // Dev10 compiler needs this!\n                            auto _PTaskHandle1 = _PTaskHandle;\n                            _PTaskHandle->_M_continuationContext._CallInContext( [_PTaskHandle1, _TaskImplPtr](){\n                                _TaskImplPtr->_ScheduleTask(_PTaskHandle1, details::_ForceInline);\n                            });\n                        }\n#if defined (__cplusplus_winrt)\n                        catch(::Platform::Exception^ _E)\n                        {\n                            _TaskImplPtr->_CancelWithException(_E);\n                        }\n#endif  /* defined (__cplusplus_winrt) */\n                        catch(...)\n                        {\n                            _TaskImplPtr->_CancelWithException(std::current_exception());\n                        }\n                    }\n                }, _PTaskHandle->_M_inliningMode);\n            }\n            else\n            {\n                _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode);\n            }\n        }\n\n        /// <summary>\n        ///     Schedule the actual continuation. This will either schedule the function on the continuation task's implementation\n        ///     if the task has completed or append it to a list of functions to execute when the task actually does complete.\n        /// </summary>\n        /// <typeparam name=\"_FuncInputType\">\n        ///     The input type of the task.\n        /// </typeparam>\n        /// <typeparam name=\"_FuncOutputType\">\n        ///     The output type of the task.\n        /// </typeparam>\n        /**/\n        void _ScheduleContinuation(_ContinuationTaskHandleBase * _PTaskHandle)\n        {\n            enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing;\n\n            // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.\n            // Otherwise, add it to the list of pending continuations\n            {\n                ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n                if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))\n                {\n                    _Do = _Schedule;\n                }\n                else if (_IsCanceled())\n                {\n                    if (_HasUserException())\n                    {\n                        _Do = _CancelWithException;\n                    }\n                    else\n                    {\n                        _Do = _Cancel;\n                    }\n                }\n                else\n                {\n                    // chain itself on the continuation chain.\n                    _PTaskHandle->_M_next = _M_Continuations;\n                    _M_Continuations = _PTaskHandle;\n                }\n            }\n\n            // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of\n            // async tasks may execute inline.\n            switch (_Do)\n            {\n                case _Schedule:\n                {\n                    _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle);\n                    break;\n                }\n                case _Cancel:\n                {\n                    // If the ancestor was canceled, then your own execution should be canceled.\n                    // This traverses down the tree to cancel it.\n                    _PTaskHandle->_GetTaskImplBase()->_Cancel(true);\n\n                    delete _PTaskHandle;\n                    break;\n                }\n                case _CancelWithException:\n                {\n                    // If the ancestor encountered an exception, transfer the exception to the continuation\n                    // This traverses down the tree to propagate the exception.\n                    _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true);\n\n                    delete _PTaskHandle;\n                    break;\n                }\n                case _Nothing:\n                default:\n                    // In this case, we have inserted continuation to continuation chain,\n                    // nothing more need to be done, just leave.\n                    break;\n            }\n        }\n\n        void _RunTaskContinuations()\n        {\n            // The link list can no longer be modified at this point,\n            // since all following up continuations will be scheduled by themselves.\n            _ContinuationList _Cur = _M_Continuations, _Next;\n            _M_Continuations = nullptr;\n            while (_Cur)\n            {\n                // Current node might be deleted after running,\n                // so we must fetch the next first.\n                _Next = _Cur->_M_next;\n                _RunContinuation(_Cur);\n                _Cur = _Next;\n            }\n        }\n\n#if defined (__cplusplus_winrt)\n        static bool  _IsNonBlockingThread()\n        {\n            APTTYPE _AptType;\n            APTTYPEQUALIFIER _AptTypeQualifier;\n\n            HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);\n            //\n            // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.\n            //\n            if (SUCCEEDED(hr))\n            {\n                switch(_AptType)\n                {\n                case APTTYPE_STA:\n                case APTTYPE_MAINSTA:\n                    return true;\n                    break;\n                case APTTYPE_NA:\n                    switch(_AptTypeQualifier)\n                    {\n                    // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed\n                    // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting\n                    // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the\n                    // thread out of circulation for a while.\n                    case APTTYPEQUALIFIER_NA_ON_STA:\n                    case APTTYPEQUALIFIER_NA_ON_MAINSTA:\n                        return true;\n                        break;\n                    }\n                    break;\n                }\n            }\n\n#if _UITHREADCTXT_SUPPORT\n            // This method is used to throw an exepection in _Wait() if called within STA.  We\n            // want the same behavior if _Wait is called on the UI thread.\n            if (SUCCEEDED(CaptureUiThreadContext(nullptr)))\n            {\n                return true;\n            }\n#endif  /* _UITHREADCTXT_SUPPORT */\n\n            return false;\n        }\n\n        template<typename _ReturnType, typename>\n        static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask,\n                               Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)\n        {\n            // This method is invoked either when a task is created from an existing async operation or\n            // when a lambda that creates an async operation executes.\n\n            // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on\n            // the IAsyncInfo object will be released when all ^references to the operation go out of scope.\n\n            // This assertion uses the existence of taskcollection to determine if the task was created from an event.\n            // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection\n            // when a custom scheduler is used.\n            // _ASSERTE((!_OuterTask->_M_TaskCollection._IsCreated() || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled());\n\n            // Pass the shared_ptr by value into the lambda instead of using 'this'.\n            _AsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType>(\n              [_OuterTask](Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _Operation, Windows::Foundation::AsyncStatus _Status) mutable\n            {\n                if (_Status == Windows::Foundation::AsyncStatus::Canceled)\n                {\n                    _OuterTask->_Cancel(true);\n                }\n                else if (_Status == Windows::Foundation::AsyncStatus::Error)\n                {\n                    _OuterTask->_CancelWithException(::Platform::Exception::ReCreateException(static_cast<int>(_Operation->ErrorCode.Value)));\n                }\n                else\n                {\n                    _ASSERTE(_Status == Windows::Foundation::AsyncStatus::Completed);\n                    _OuterTask->_FinalizeAndRunContinuations(_Operation->GetResults());\n                }\n\n                // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could\n                // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold\n                // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from\n                // it using the Windows Runtime Async APIs causes a sharing violation.\n                // Using const_cast is the workaround for failed mutable keywords\n                const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset();\n             });\n            _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        template<typename _ReturnType, typename _InternalReturnType>\n        static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask)\n        {\n            _ASSERTE(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled());\n                       \n            //\n            // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the\n            // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation\n            // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent\n            // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless\n            // of whether or not the _OuterTask task is canceled.\n            //\n            _UnwrappedTask._Then([_OuterTask] (task<_InternalReturnType> _AncestorTask) {\n\n                if (_AncestorTask._GetImpl()->_IsCompleted())\n                {\n                    _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult());\n                }\n                else\n                {\n                    _ASSERTE(_AncestorTask._GetImpl()->_IsCanceled());\n                    if (_AncestorTask._GetImpl()->_HasUserException())\n                    {\n                        // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.\n                        // Instead, it is the enclosing task.\n                        _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false);\n                    }\n                    else\n                    {\n                        _OuterTask->_Cancel(true);\n                    }\n                }\n            }, nullptr, details::_DefaultAutoInline);\n\n        }\n\n        scheduler_ptr _GetScheduler() const\n        {\n            return _M_TaskCollection._GetScheduler();\n        }\n\n        // Tracks the internal state of the task\n        volatile _TaskInternalState _M_TaskState;\n        // Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this task returns an\n        // async operation or async action that is unwrapped by the runtime.\n        bool _M_fFromAsync;\n        // Set to true when a continuation unwraps a task or async operation.\n        bool _M_fUnwrappedTask;\n\n        // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.\n        // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception\n        // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.\n        std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;\n\n        ::pplx::extensibility::critical_section_t _M_ContinuationsCritSec;\n\n        // The cancellation token state.\n        _CancellationTokenState * _M_pTokenState;\n\n        // The registration on the token.\n        _CancellationTokenRegistration * _M_pRegistration;\n\n        typedef _ContinuationTaskHandleBase * _ContinuationList;\n        _ContinuationList _M_Continuations;\n\n        // The async task collection wrapper\n        ::pplx::details::_TaskCollection_t _M_TaskCollection;\n\n        // Callstack for function call (constructor or .then) that created this task impl.\n        _TaskCreationCallstack _M_pTaskCreationCallstack;\n\n        _TaskEventLogger _M_taskEventLogger;\n   private:\n        // Must not be copied by value:\n        _Task_impl_base(const _Task_impl_base&);\n        _Task_impl_base const & operator=(_Task_impl_base const&);\n    };\n\n#if _PPLTASK_ASYNC_LOGGING\n    inline void _TaskEventLogger::_LogTaskCompleted()\n    {\n        if (_M_scheduled)\n        {\n            ::Windows::Foundation::AsyncStatus _State;\n            if (_M_task->_IsCompleted())\n                _State = ::Windows::Foundation::AsyncStatus::Completed;\n            else if (_M_task->_HasUserException())\n                _State = ::Windows::Foundation::AsyncStatus::Error;\n            else\n                _State = ::Windows::Foundation::AsyncStatus::Canceled;\n\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), _State);\n            }\n        }\n    }\n#endif\n    \n    /// <summary>\n    ///     The implementation of a first-class task. This structure contains the task group used to execute\n    ///     the task function and handles the scheduling. The _Task_impl is created as a shared_ptr\n    ///     member of the the public task class, so its destruction is handled automatically.\n    /// </summary>\n    /// <typeparam name=\"_ReturnType\">\n    ///     The result type of this task.\n    /// </typeparam>\n    /**/\n    template<typename _ReturnType>\n    struct _Task_impl : public _Task_impl_base\n    {\n#if defined (__cplusplus_winrt)\n        typedef Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value> _AsyncOperationType;\n#endif // defined(__cplusplus_winrt)\n        _Task_impl(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg)\n            : _Task_impl_base(_Ct, _Scheduler_arg)\n        {\n#if defined (__cplusplus_winrt)\n            _M_unwrapped_async_op = nullptr;\n#endif  /* defined (__cplusplus_winrt) */\n        }\n\n        virtual ~_Task_impl()\n        {\n            // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause\n            // a partially initialized _Task_impl to be in the list of registrations for a cancellation token.\n            _DeregisterCancellation();\n        }\n\n        virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder_arg)\n        {\n            bool _RunContinuations = false;\n            {\n                ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n                if (_UserException)\n                {\n                    _ASSERTE(_SynchronousCancel && !_IsCompleted());\n                    // If the state is _Canceled, the exception has to be coming from an ancestor.\n                    _ASSERTE(!_IsCanceled() || _PropagatedFromAncestor);\n\n                    // We should not be canceled with an exception more than once.\n                    _ASSERTE(!_HasUserException());\n\n                    // Mark _PropagatedFromAncestor as used.\n                    (void)_PropagatedFromAncestor;\n\n                    if (_M_TaskState == _Canceled)\n                    {\n                        // If the task has finished cancelling there should not be any continuation records in the array.\n                        return false;\n                    }\n                    else\n                    {\n                        _ASSERTE(_M_TaskState != _Completed);\n                        _M_exceptionHolder = _ExceptionHolder_arg;\n                    }\n                }\n                else\n                {\n                    // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel\n                    // which is to say, cancellation is already initiated, so return early.\n                    if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel))\n                    {\n                        _ASSERTE(!_IsCompleted() || !_HasUserException());\n                        return false;\n                    }\n                    _ASSERTE(!_SynchronousCancel || !_HasUserException());\n                }\n\n                if (_SynchronousCancel)\n                {\n                    // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()\n                    _M_TaskState = _Canceled;                    \n                    // Cancellation completes the task, so all dependent tasks must be run to cancel them\n                    // They are canceled when they begin running (see _RunContinuation) and see that their\n                    // ancestor has been canceled.\n                    _RunContinuations = true;\n                }\n                else\n                {\n                    _ASSERTE(!_UserException);\n\n                    if (_IsStarted())\n                    {\n#if defined (__cplusplus_winrt)\n                        if (_M_unwrapped_async_op != nullptr)\n                        {\n                            // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.\n                            _M_unwrapped_async_op->Cancel();\n                        }\n#endif  /* defined (__cplusplus_winrt) */\n                        _M_TaskCollection._Cancel();\n                    }\n\n                    // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).\n                    // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from\n                    // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.\n                    _M_TaskState = _PendingCancel;\n\n                    _M_taskEventLogger._LogCancelTask();\n                }\n\n                \n            }\n\n            // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.\n            if (_RunContinuations)\n            {\n                _M_TaskCollection._Complete();\n\n                if (_M_Continuations)\n                {\n                    // Scheduling cancellation with automatic inlining.\n                    _ScheduleFuncWithAutoInline([=](){ _RunTaskContinuations(); }, details::_DefaultAutoInline);\n                }\n            }\n            return true;\n        }\n\n        void _FinalizeAndRunContinuations(_ReturnType _Result)\n        {\n            _M_Result.Set(_Result);\n\n            {\n                //\n                // Hold this lock to ensure continuations being concurrently either get added\n                // to the _M_Continuations vector or wait for the result\n                //\n                ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n\n                // A task could still be in the _Created state if it was created with a task_completion_event.\n                // It could also be in the _Canceled state for the same reason.\n                _ASSERTE(!_HasUserException() && !_IsCompleted());\n                if (_IsCanceled())\n                {\n                    return;\n                }\n\n                // Always transition to \"completed\" state, even in the face of unacknowledged pending cancellation\n                _M_TaskState = _Completed;\n            }\n            _M_TaskCollection._Complete();\n            _RunTaskContinuations();\n        }\n\n        //\n        // This method is invoked when the starts executing. The task returns early if this method returns true.\n        //\n        bool _TransitionedToStarted()\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n            // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here.\n            _ASSERTE(!_IsCanceled());\n            if (_IsPendingCancel())\n                return false;\n\n            _ASSERTE(_IsCreated());\n            _M_TaskState = _Started;\n            return true;\n        }\n\n#if defined (__cplusplus_winrt)\n        void _SetUnwrappedAsyncOp(_AsyncOperationType^ _AsyncOp)\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n            // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.\n            if (_IsPendingCancel())\n            {\n                _ASSERTE(!_IsCanceled());\n                _AsyncOp->Cancel();\n            }\n            else\n            {\n                _M_unwrapped_async_op = _AsyncOp;\n            }\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        // Return true if the task has reached a terminal state\n        bool _IsDone()\n        {     \n            return _IsCompleted() || _IsCanceled();\n        }\n\n        _ReturnType _GetResult()\n        {\n            return _M_Result.Get();\n        }\n\n        _ResultHolder<_ReturnType>                 _M_Result;        // this means that the result type must have a public default ctor.\n#if defined (__cplusplus_winrt)\n        _AsyncOperationType^                        _M_unwrapped_async_op;\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n    template<typename _ResultType>\n    struct _Task_completion_event_impl\n    {\n    private:\n        _Task_completion_event_impl(const _Task_completion_event_impl&);\n        _Task_completion_event_impl& operator=(const _Task_completion_event_impl&);\n\n    public:\n\n        typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList;\n\n        _Task_completion_event_impl() :\n            _M_fHasValue(false), _M_fIsCanceled(false)\n        {\n        }\n\n        bool _HasUserException()\n        {\n            return _M_exceptionHolder != nullptr;\n        }\n\n        ~_Task_completion_event_impl()\n        {\n            for( auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt )\n            {\n                _ASSERTE(!_M_fHasValue && !_M_fIsCanceled);\n                // Cancel the tasks since the event was never signaled or canceled.\n                (*_TaskIt)->_Cancel(true);\n            }\n        }\n\n        // We need to protect the loop over the array, so concurrent_vector would not have helped\n        _TaskList                           _M_tasks;\n        ::pplx::extensibility::critical_section_t             _M_taskListCritSec;\n        _ResultHolder<_ResultType>         _M_value;\n        std::shared_ptr<_ExceptionHolder>   _M_exceptionHolder;\n        bool                                _M_fHasValue;\n        bool                                _M_fIsCanceled;\n    };\n\n    // Utility method for dealing with void functions\n    inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function<void(void)>& _Func)\n    {\n        return [=]() -> _Unit_type { _Func(); return _Unit_type(); };\n    }\n\n    template <typename _Type>\n    std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func)\n    {\n        return [=](_Unit_type) -> _Type { return _Func(); };\n    }\n\n    template <typename _Type>\n    std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function<void(_Type)>& _Func)\n    {\n        return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); };\n    }\n\n    inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function<void(void)>& _Func)\n    {\n        return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); };\n    }\n} // namespace details\n\n/// <summary>\n///     The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,\n///     or start a task in response to an external event.\n/// </summary>\n/// <typeparam name=\"_ResultType\">\n///     The result type of this <c>task_completion_event</c> class.\n/// </typeparam>\n/// <remarks>\n///     Use a task created from a task completion event when your scenario requires you to create a task that will complete, and\n///     thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must\n///     have the same type as the task you create, and calling the set method on the task completion event with a value of that type\n///     will cause the associated task to complete, and provide that value as a result to its continuations.\n///     <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>\n///     <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/**/\ntemplate<typename _ResultType>\nclass task_completion_event\n{\npublic:\n    /// <summary>\n    ///     Constructs a <c>task_completion_event</c> object.\n    /// </summary>\n    /**/\n    task_completion_event() \n        : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>()) \n    {\n    }\n\n    /// <summary>\n    ///     Sets the task completion event.\n    /// </summary>\n    /// <param name=\"_Result\">\n    ///     The result to set this event with.\n    /// </param>\n    /// <returns>\n    ///     The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.\n    /// </returns>\n    /// <remarks>\n    ///     In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the\n    ///     task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the\n    ///     tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have\n    ///     a <typeparamref name=\"_ResultType\"/> other than <c>void</c> will pass the value <paramref value=\"_Result\"/> to their continuations.\n    /// </remarks>\n    /**/\n    bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.\n        if (_IsTriggered())\n        {\n            return false;\n        }\n\n        _TaskList _Tasks;\n        bool _RunContinuations = false;\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n\n            if (!_IsTriggered())\n            {\n                _M_Impl->_M_value.Set(_Result);\n                _M_Impl->_M_fHasValue = true;\n\n                _Tasks.swap(_M_Impl->_M_tasks);\n                _RunContinuations = true;\n            }\n        }\n\n        if (_RunContinuations)\n        {\n            for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )\n            {\n                // If current task was cancelled by a cancellation_token, it would be in cancel pending state.\n                if ((*_TaskIt)->_IsPendingCancel())\n                    (*_TaskIt)->_Cancel(true);\n                else\n                {\n                    // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all\n                    // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we\n                    // need to run continuations after the lock is released.\n                    (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());\n                }\n            }\n            if (_M_Impl->_HasUserException())\n            {\n                _M_Impl->_M_exceptionHolder.reset();\n            }\n            return true;\n        }\n\n        return false;\n    }\n\n    template<typename _E>\n    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result\n    bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.\n        return _Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Propagates an exception to all tasks associated with this event.\n    /// </summary>\n    /// <param>\n    ///     The exception_ptr that indicates the exception to set this event with.\n    /// </param>\n    /**/\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.\n        return _Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has\n    ///     not already been set.\n    /// </summary>\n    bool _Cancel() const\n    {\n        // Cancel with the stored exception if one exists.\n        return _CancelInternal();\n    }\n\n    /// <summary>\n    ///     Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled\n    ///     with the same exception.\n    /// </summary>\n    template<typename _ExHolderType>\n    bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const\n    {\n        bool _Canceled;\n        if(_StoreException(_ExHolder, _SetExceptionAddressHint))\n        {\n            _Canceled = _CancelInternal();\n            _ASSERTE(_Canceled);\n        }\n        else\n        {\n            _Canceled = false;\n        }\n        return _Canceled;\n    }\n\n    /// <summary>\n    ///     Internal method that stores an exception in the task completion event. This is used internally by when_any.\n    ///     Note, this does not cancel the task completion event. A task completion event with a stored exception\n    ///     can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.\n    /// </summary>\n    template<typename _ExHolderType>\n    bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const\n    {\n        ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n        if (!_IsTriggered() && !_M_Impl->_HasUserException())\n        {\n            // Create the exception holder only if we have ensured there we will be successful in setting it onto the\n            // task completion event. Failing to do so will result in an unobserved task exception.\n            _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint);\n            return true;\n        }\n        return false;\n    }\n\n    /// <summary>\n    ///     Tests whether current event has been either Set, or Canceled.\n    /// </summary>\n    bool _IsTriggered() const\n    {\n        return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled;\n    }\n\nprivate:\n\n    static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, const details::_TaskCreationCallstack&)\n    {\n        return _ExHolder;\n    }\n\n    static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint)\n    {\n        return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint);\n    }\n\n\n    template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask\n    template <typename T> friend class task_completion_event;\n\n    typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList;\n\n    /// <summary>\n    ///    Cancels the task_completion_event.\n    /// </summary>\n    bool _CancelInternal() const\n    {\n        // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal\n        // will never be invoked if the task completion event has been set.\n        _ASSERTE(!_M_Impl->_M_fHasValue);\n        if (_M_Impl->_M_fIsCanceled)\n        {\n            return false;\n        }\n\n        _TaskList _Tasks;\n        bool _Cancel = false;\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n            _ASSERTE(!_M_Impl->_M_fHasValue);\n            if (!_M_Impl->_M_fIsCanceled)\n            {\n                _M_Impl->_M_fIsCanceled = true;\n                _Tasks.swap(_M_Impl->_M_tasks);\n                _Cancel = true;\n            }\n        }\n\n        bool _UserException = _M_Impl->_HasUserException();\n\n        if (_Cancel)\n        {\n            for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )\n            {\n                // Need to call this after the lock is released. See comments in set().\n                if (_UserException)\n                {\n                    (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);\n                }\n                else\n                {\n                    (*_TaskIt)->_Cancel(true);\n                }\n            }\n        }\n        return _Cancel;\n    }\n\n    /// <summary>\n    ///     Register a task with this event. This function is called when a task is constructed using\n    ///     a task_completion_event.\n    /// </summary>\n    void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam)\n    {\n        ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n\n        //If an exception was already set on this event, then cancel the task with the stored exception.\n        if(_M_Impl->_HasUserException())\n        {\n            _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);\n        }\n        else if (_M_Impl->_M_fHasValue)\n        {\n            _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());\n        }\n        else\n        {\n            _M_Impl->_M_tasks.push_back(_TaskParam);\n        }\n    }\n\n    std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl;\n};\n\n/// <summary>\n///     The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,\n///     or start a task in response to an external event.\n/// </summary>\n/// <remarks>\n///     Use a task created from a task completion event when your scenario requires you to create a task that will complete, and\n///     thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must\n///     have the same type as the task you create, and calling the set method on the task completion event with a value of that type\n///     will cause the associated task to complete, and provide that value as a result to its continuations.\n///     <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>\n///     <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/**/\ntemplate<>\nclass task_completion_event<void>\n{\npublic:\n    /// <summary>\n    ///     Sets the task completion event.\n    /// </summary>\n    /// <returns>\n    ///     The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.\n    /// </returns>\n    /// <remarks>\n    ///     In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the\n    ///     task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the\n    ///     tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have\n    ///     a <typeparamref name=\"_ResultType\"/> other than <c>void</c> will pass the value <paramref value=\"_Result\"/> to their continuations.\n    /// </remarks>\n    /**/\n    bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        return _M_unitEvent.set(details::_Unit_type());\n    }\n\n    template<typename _E>\n    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result\n    bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Propagates an exception to all tasks associated with this event.\n    /// </summary>\n    /// <param>\n    ///     The exception_ptr that indicates the exception to set this event with.\n    /// </param>\n    /**/\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK intrinsic gives us the expected result\n    bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.\n        return _M_unitEvent._Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Cancel the task_completion_event. Any task created using this event will be marked as canceled if it has\n    ///     not already been set.\n    /// </summary>\n    void _Cancel() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        _M_unitEvent._Cancel();\n    }\n\n    /// <summary>\n    ///     Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled\n    ///     with the same exception.\n    /// </summary>\n    void _Cancel(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const\n    {\n        _M_unitEvent._Cancel(_ExHolder);\n    }\n\n    /// <summary>\n    ///     Method that stores an exception in the task completion event. This is used internally by when_any.\n    ///     Note, this does not cancel the task completion event. A task completion event with a stored exception\n    ///     can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.\n    /// </summary>\n    bool _StoreException(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const\n    {\n        return _M_unitEvent._StoreException(_ExHolder);\n    }\n\n    /// <summary>\n    ///     Test whether current event has been either Set, or Canceled.\n    /// </summary>\n    bool _IsTriggered() const\n    {\n        return _M_unitEvent._IsTriggered();\n    }\n\nprivate:\n    template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask\n\n    /// <summary>\n    ///     Register a task with this event. This function is called when a task is constructed using\n    ///     a task_completion_event.\n    /// </summary>\n    void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam)\n    {\n        _M_unitEvent._RegisterTask(_TaskParam);\n    }\n\n    // The void event contains an event a dummy type so common code can be used for events with void and non-void results.\n    task_completion_event<details::_Unit_type> _M_unitEvent;\n};\n\nnamespace details\n{\n    //\n    // Compile-time validation helpers\n    //\n\n    // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.\n    //\n    // Anything callable is fine\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int,int,int,int) -> decltype(_Param(), std::true_type());\n\n#if defined (__cplusplus_winrt)\n    // Anything that has GetResults is fine: this covers all async operations\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int, int, int,...) -> decltype(_Param->GetResults(), std::true_type());\n#endif\n\n    // Allow parameters with set: this covers task_completion_event\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type());\n\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type());\n\n    // All else is invalid\n    template<typename _ReturnType, typename _Ty>\n    std::false_type _IsValidTaskCtor(_Ty _Param, ...);\n\n    template<typename _ReturnType, typename _Ty>\n    void _ValidateTaskConstructorArgs(_Ty _Param)\n    {\n        static_assert(std::is_same<decltype(_IsValidTaskCtor<_ReturnType>(_Param,0,0,0,0)),std::true_type>::value,\n#if defined (__cplusplus_winrt)\n            \"incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event\"\n#else  /* defined (__cplusplus_winrt) */\n            \"incorrect argument for task constructor; can be a callable object or a task_completion_event\"\n#endif  /* defined (__cplusplus_winrt) */\n            );\n#if defined (__cplusplus_winrt)\n        static_assert(!(std::is_same<_Ty,_ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value),\n            \"incorrect template argument for task; consider using the return type of the async operation\");\n#endif  /* defined (__cplusplus_winrt) */\n    }\n\n#if defined (__cplusplus_winrt)\n    // Helpers for create_async validation\n    //\n    // A parameter lambda taking no arguments is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type());\n\n    // A parameter lambda taking an cancellation_token argument is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> decltype(_Param(cancellation_token::none()), std::true_type());\n\n    // A parameter lambda taking a progress report argument is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());\n\n    // A parameter lambda taking a progress report and a cancellation_token argument is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type());\n\n    // All else is invalid\n    template<typename _Ty>\n    static std::false_type _IsValidCreateAsync(_Ty _Param, ...);\n#endif  /* defined (__cplusplus_winrt) */\n}\n/// <summary>\n///     A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a\n///     non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'.\n/// </summary>\ntemplate<typename _InpType, typename _OutType>\nclass _Continuation_func_transformer\n{\npublic:\n    static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func)\n    {\n        return _Func;\n    }\n};\n\ntemplate<typename _OutType>\nclass _Continuation_func_transformer<void, _OutType>\n{\npublic:\n    static auto _Perform(std::function<_OutType(void)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))\n    {\n        return details::_MakeUnitToTFunc<_OutType>(_Func);\n    }\n};\n\ntemplate<typename _InType>\nclass _Continuation_func_transformer<_InType, void>\n{\npublic:\n    static auto _Perform(std::function<void(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))\n    {\n        return details::_MakeTToUnitFunc<_InType>(_Func);\n    }\n};\n\ntemplate<>\nclass _Continuation_func_transformer<void, void>\n{\npublic:\n    static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))\n    {\n        return details::_MakeUnitToUnitFunc(_Func);\n    }\n};\n\n// A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used\n// to substitute for void). This is to minimize the special handling required for 'void'.\ntemplate<typename _RetType>\nclass _Init_func_transformer\n{\npublic:\n    static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func)\n    {\n        return _Func;\n    }\n};\n\ntemplate<>\nclass _Init_func_transformer<void>\n{\npublic:\n    static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))\n    {\n        return details::_MakeVoidToUnitFunc(_Func);\n    }\n};\n\n/// <summary>\n///     The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,\n///     and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces\n///     a result of type <typeparamref name=\"_ResultType\"/> on successful completion. Tasks of type <c>task&lt;void&gt;</c> produce no result.\n///     A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using\n///     continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The result type of this task.\n/// </typeparam>\n/// <remarks>\n///     For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.\n/// </remarks>\n/**/\ntemplate<typename _ReturnType>\nclass task\n{\npublic:\n    /// <summary>\n    ///     The type of the result an object of this class produces.\n    /// </summary>\n    /**/\n    typedef _ReturnType result_type;\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task() : _M_Impl(nullptr)\n    {\n        // The default constructor should create a task with a nullptr impl. This is a signal that the\n        // task is not usable and should throw if any wait(), get() or then() APIs are used.\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <typeparam name=\"_Ty\">\n    ///     The type of the parameter from which the task is to be constructed.\n    /// </typeparam>\n    /// <param name=\"_Param\">\n    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>\n    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function\n    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,\n    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.\n    /// </param>\n    /// <param name=\"_Token\">\n    ///     The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives\n    ///     the token <c>cancellation_token::none()</c>.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Ty>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    explicit task(_Ty _Param)\n    {\n        task_options _TaskOptions;\n        details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);\n\n        _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());\n        // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.\n        _SetTaskCreationCallstack(_CAPTURE_CALLSTACK());\n\n        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <typeparam name=\"_Ty\">\n    ///     The type of the parameter from which the task is to be constructed.\n    /// </typeparam>\n    /// <param name=\"_Param\">\n    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>\n    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function\n    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,\n    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.\n    /// </param>\n    /// <param name=\"_TaskOptions\">\n    ///     The task options include cancellation token, scheduler etc\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Ty>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    explicit task(_Ty _Param, const task_options &_TaskOptions)\n    {\n        details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);\n\n        _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());\n        // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.\n        _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());\n        \n        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(const task& _Other): _M_Impl(_Other._M_Impl) {}\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(task&& _Other): _M_Impl(std::move(_Other._M_Impl)) {}\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(const task& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_Impl = _Other._M_Impl;\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(task&& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_Impl = std::move(_Other._M_Impl);\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        task_options _TaskOptions;\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_TaskOptions\">\n    ///     The task options include cancellation token, scheduler and continuation context. By default the former 3\n    ///     options are inherited from the antecedent task\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_CancellationToken\">\n    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit\n    ///     the token of its antecedent task.\n    /// </param>\n    /// <param name=\"_ContinuationContext\">\n    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a Windows Store\n    ///     style app. For more information, see <see cref=\"task_continuation_context Class\">task_continuation_context</see>\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        task_options _TaskOptions(_CancellationToken, _ContinuationContext);\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks\n    ///     dependencies are satisfied, and it has not already been picked up for execution by a background worker.\n    /// </summary>\n    /// <returns>\n    ///     A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception\n    ///     during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.\n    /// </returns>\n    /**/\n    task_status wait() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"wait() cannot be called on a default constructed task.\");\n        }\n\n        return _M_Impl->_Wait();\n    }\n\n    /// <summary>\n    ///     Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to\n    ///     finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.\n    /// </summary>\n    /// <returns>\n    ///     The result of the task.\n    /// </returns>\n    /// <remarks>\n    ///     If the task is canceled, a call to <c>get</c> will throw a <see cref=\"task_canceled Class\">task_canceled</see> exception. If the task\n    ///     encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.\n    /// </remarks>\n    /**/\n    _ReturnType get() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"get() cannot be called on a default constructed task.\");\n        }\n\n        if (_M_Impl->_Wait() == canceled)\n        {\n            throw task_canceled();  \n        }\n\n        return _M_Impl->_GetResult();\n    }\n\n    /// <summary>\n    ///     Determines if the task is completed.\n    /// </summary>\n    /// <returns>\n    ///     True if the task has completed, false otherwise.\n    /// </returns>\n    /// <remarks>\n    ///     The function returns true if the task is completed or canceled (with or without user exception).\n    /// </remarks>\n    bool is_done() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"is_done() cannot be called on a default constructed task.\");\n        }\n\n        return _M_Impl->_IsDone();\n    }\n\n    /// <summary>\n    ///     Returns the scheduler for this task\n    /// </summary>\n    /// <returns>\n    ///     A pointer to the scheduler\n    /// </returns>\n    scheduler_ptr scheduler() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"scheduler() cannot be called on a default constructed task.\");\n        }\n\n        return _M_Impl->_GetScheduler();\n    }\n\n    /// <summary>\n    ///     Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool is_apartment_aware() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"is_apartment_aware() cannot be called on a default constructed task.\");\n        }\n        return _M_Impl->_IsApartmentAware();\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent the same internal task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator==(const task<_ReturnType>& _Rhs) const\n    {\n        return (_M_Impl == _Rhs._M_Impl);\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent different internal tasks.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator!=(const task<_ReturnType>& _Rhs) const\n    {\n        return !operator==(_Rhs);\n    }\n\n    /// <summary>\n    ///     Create an underlying task implementation.\n    /// </summary>\n    void _CreateImpl(details::_CancellationTokenState * _Ct, scheduler_ptr _Scheduler)\n    {\n        _ASSERTE(_Ct != nullptr);\n        _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct, _Scheduler);\n        if (_Ct != details::_CancellationTokenState::_None())\n        {\n            _M_Impl->_RegisterCancellation(_M_Impl);\n        }\n    }\n\n    /// <summary>\n    ///     Return the underlying implementation for this task.\n    /// </summary>\n    const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const\n    {\n        return _M_Impl;\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion.\n    /// </summary>\n    void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl)\n    {\n        _ASSERTE(!_M_Impl);\n        _M_Impl = _Impl;\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion using a move instead of a copy.\n    /// </summary>\n    void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl)\n    {\n        _ASSERTE(!_M_Impl);\n        _M_Impl = std::move(_Impl);\n    }\n\n    /// <summary>\n    ///     Sets a property determining whether the task is apartment aware.\n    /// </summary>\n    void _SetAsync(bool _Async = true)\n    {\n        _GetImpl()->_SetAsync(_Async);\n    }\n\n    /// <summary>\n    ///     Sets a field in the task impl to the return callstack for calls to the task constructors and the then method.\n    /// </summary>\n    void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)\n    {\n        _GetImpl()->_SetTaskCreationCallstack(_callstack);\n    }\n\n    /// <summary>\n    ///     An internal version of then that takes additional flags and always execute the continuation inline by default.\n    ///     When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline.\n    ///     This function is Used for runtime internal continuations only.\n    /// </summary>\n    template<typename _Function>\n    auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState, \n        details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        // inherit from antecedent\n        auto _Scheduler = _GetImpl()->_GetScheduler();\n\n        return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);\n    }\n\nprivate:\n    template <typename T> friend class task;\n\n     \n    // The task handle type used to construct an 'initial task' - a task with no dependents.\n    template <typename _InternalReturnType, typename _Function, typename _TypeSelection>\n    struct _InitialTaskHandle : \n        details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>\n    {\n        _Function _M_function;\n        _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _func)\n            : details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>::_PPLTaskHandle(_TaskImpl)\n            , _M_function(_func)\n        {\n        }\n\n        virtual ~_InitialTaskHandle() {}\n\n        template <typename _Func>\n        auto _LogWorkItemAndInvokeUserLambda(_Func && _func) const -> decltype(_func())\n        {\n            details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);\n            CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);\n            return _func();\n        }\n\n        void _Perform() const\n        {\n            _Init(_TypeSelection());\n        }\n\n        void _SyncCancelAndPropagateException() const\n        {\n            this->_M_pTask->_Cancel(true);\n        }\n\n        //\n        // Overload 0: returns _InternalReturnType\n        //\n        // This is the most basic task with no unwrapping\n        //\n        void _Init(details::_TypeSelectorNoAsync) const\n        {\n            this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function)));\n        }\n\n        //\n        // Overload 1: returns IAsyncOperation<_InternalReturnType>^ (only uder /ZW)\n        //                   or\n        //             returns task<_InternalReturnType>\n        //\n        // This is task whose functor returns an async operation or a task which will be unwrapped for continuation\n        // Depending on the output type, the right _AsyncInit gets invoked\n        //\n        void _Init(details::_TypeSelectorAsyncOperationOrTask) const\n        {\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function));\n        }\n\n#if defined (__cplusplus_winrt)\n        //\n        // Overload 2: returns IAsyncAction^\n        //\n        // This is task whose functor returns an async action which will be unwrapped for continuation\n        //\n        void _Init(details::_TypeSelectorAsyncAction) const\n        {\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function)));\n        }\n\n        //\n        // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>^\n        //\n        // This is task whose functor returns an async operation with progress which will be unwrapped for continuation\n        //\n        void _Init(details::_TypeSelectorAsyncOperationWithProgress) const\n        {\n            typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask,\n                    ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType,_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));\n        }\n\n        //\n        // Overload 4: returns IAsyncActionWithProgress<_ProgressType>^\n        //\n        // This is task whose functor returns an async action with progress which will be unwrapped for continuation\n        //\n        void _Init(details::_TypeSelectorAsyncActionWithProgress) const\n        {\n            typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, \n                ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));\n        }\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n\n    /// <summary>\n    ///     The task handle type used to create a 'continuation task'.\n    /// </summary>\n    template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection>\n    struct _ContinuationTaskHandle :\n        details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,\n        _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>\n    {\n        typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;\n\n        typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;\n        _Function _M_function;\n\n        _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,\n            const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,\n            const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode)\n                : details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,\n                    _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>\n                    ::_PPLTaskHandle(_ContinuationImpl)\n                , _M_ancestorTaskImpl(_AncestorImpl)\n                , _M_function(_Func)\n        {\n            this->_M_isTaskBasedContinuation = _IsTaskBased::value;\n            this->_M_continuationContext = _Context;\n            this->_M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware());\n            this->_M_inliningMode = _InliningMode;\n        }\n\n        virtual ~_ContinuationTaskHandle() {}\n\n        template <typename _Func, typename _Arg>\n        auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value) const -> decltype(_func(std::forward<_Arg>(_value)))\n        {\n            details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);\n            CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);\n            return _func(std::forward<_Arg>(_value));\n        }\n\n        void _Perform() const\n        {\n            _Continue(_IsTaskBased(), _TypeSelection());\n        }\n\n        void _SyncCancelAndPropagateException() const\n        {\n            if (_M_ancestorTaskImpl->_HasUserException())\n            {\n                // If the ancestor encountered an exception, transfer the exception to the continuation\n                // This traverses down the tree to propagate the exception.\n                this->_M_pTask->_CancelWithExceptionHolder(_M_ancestorTaskImpl->_GetExceptionHolder(), true);\n            }\n            else\n            {\n                // If the ancestor was canceled, then your own execution should be canceled.\n                // This traverses down the tree to cancel it.\n                this->_M_pTask->_Cancel(true);\n            }\n        }\n\n        //\n        // Overload 0-0: _InternalReturnType -> _TaskType\n        //\n        // This is a straight task continuation which simply invokes its target with the ancestor's completion argument\n        //\n        void _Continue(std::false_type, details::_TypeSelectorNoAsync) const\n        {\n            this->_M_pTask->_FinalizeAndRunContinuations(\n                _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()));\n        }\n\n        //\n        // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>^ (only uder /ZW)\n        //               or\n        //               _InternalReturnType -> task<_TaskType>\n        //\n        // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation\n        // Depending on the output type, the right _AsyncInit gets invoked\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncOperationOrTask) const\n        {\n            typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask, \n                _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())\n            );\n        }\n\n#if defined (__cplusplus_winrt)\n        //\n        // Overload 0-2: _InternalReturnType -> IAsyncAction^\n        //\n        // This is a straight task continuation which returns an async action which will be unwrapped for continuation\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const\n        {\n            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask,\n                ref new details::_IAsyncActionToAsyncOperationConverter(\n                    _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())));\n        }\n\n        //\n        // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^\n        //\n        // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const\n        {\n            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());\n            typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask,\n                ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(_OpWithProgress));\n        }\n\n        //\n        // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>^\n        //\n        // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const\n        {\n            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());\n            typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask,\n                ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_OpWithProgress));\n        }\n\n#endif  /* defined (__cplusplus_winrt) */\n\n        //\n        // Overload 1-0: task<_InternalReturnType> -> _TaskType\n        //\n        // This is an exception handling type of continuation which takes the task rather than the task's result.\n        //\n        void _Continue(std::true_type, details::_TypeSelectorNoAsync) const\n        {\n            typedef task<_InternalReturnType> _FuncInputType;\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n            this->_M_pTask->_FinalizeAndRunContinuations(\n                _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask)));\n        }\n\n        //\n        // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^\n        //                                            or\n        //                                            task<_TaskType>\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async operation or a task which will be unwrapped\n        // for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncOperationOrTask) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask, \n                _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)));\n        }\n\n#if defined (__cplusplus_winrt)\n\n        //\n        // Overload 1-2: task<_InternalReturnType> -> IAsyncAction^\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async action which will be unwrapped for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,\n                ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));\n        }\n\n        //\n        // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async operation with progress which will be unwrapped\n        // for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n\n            typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,\n                    ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(\n                    _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));\n        }\n\n        //\n        // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>^\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async operation with progress which will be unwrapped\n        // for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n\n            typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,\n                    ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(\n                    _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));\n        }\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n    /// <summary>\n    ///     Initializes a task using a lambda, function pointer or function object.\n    /// </summary>\n    template<typename _InternalReturnType, typename _Function>\n    void _TaskInitWithFunctor(const _Function& _Func)\n    {\n        typedef typename details::_InitFunctorTypeTraits<_InternalReturnType, decltype(_Func())> _Async_type_traits;\n\n        _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask;\n        _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;\n        _M_Impl->_M_taskEventLogger._LogScheduleTask(false);\n        _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), details::_NoInline);\n    }\n\n    /// <summary>\n    ///     Initializes a task using a task completion event.\n    /// </summary>\n    void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event)\n    {\n        _Event._RegisterTask(_M_Impl);\n    }\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Initializes a task using an asynchronous operation IAsyncOperation<T>^\n    /// </summary>\n    void _TaskInitAsyncOp(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)\n    {\n        _M_Impl->_M_fFromAsync = true;\n\n        // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit\n        // returns a completion could execute concurrently and the task must be fully initialized before that happens.\n        _M_Impl->_M_TaskState = details::_Task_impl_base::_Started;\n        // Pass the shared pointer into _AsyncInit for storage in the Async Callback.\n        details::_Task_impl_base::_AsyncInit<_ReturnType, _ReturnType>(_M_Impl, _AsyncOp);\n    }\n\n    /// <summary>\n    ///     Initializes a task using an asynchronous operation IAsyncOperation<T>^\n    /// </summary>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)\n    {\n        _TaskInitAsyncOp(_AsyncOp);\n    }\n\n    /// <summary>\n    ///     Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress<T, P>^\n    /// </summary>\n    template<typename _Progress>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperationWithProgress<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>^ _AsyncOp)\n    {\n        _TaskInitAsyncOp(ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>(_AsyncOp));\n    }\n#endif  /* defined (__cplusplus_winrt) */\n\n    /// <summary>\n    ///     Initializes a task using a callable object.\n    /// </summary>\n    template<typename _Function>\n    void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)\n    {\n        _TaskInitWithFunctor<_ReturnType, _Function>(_Func);\n    }\n\n    /// <summary>\n    ///     Initializes a task using a non-callable object.\n    /// </summary>\n    template<typename _Ty>\n    void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type)\n    {\n        _TaskInitNoFunctor(_Param);\n    }\n\n    template<typename _InternalReturnType, typename _Function>\n    auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"then() cannot be called on a default constructed task.\");\n        }\n\n        details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n        auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler();\n        auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack();\n        return _ThenImpl<_InternalReturnType, _Function>(_Func, _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack);\n    }\n\n    /// <summary>\n    ///     The one and only implementation of then for void and non-void tasks.\n    /// </summary>\n    template<typename _InternalReturnType, typename _Function>\n    auto _ThenImpl(const _Function& _Func, details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack,\n        details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"then() cannot be called on a default constructed task.\");\n        }\n\n        typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits;\n        typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits;\n        typedef typename _Async_type_traits::_TaskRetType _TaskType;\n\n        //\n        // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a\n        // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user\n        // explicitly passes the same token.\n        //\n        if (_PTokenState == nullptr)\n        {\n            if (_Function_type_traits::_Takes_task::value)\n            {\n                _PTokenState = details::_CancellationTokenState::_None();\n            }\n            else\n            {\n                _PTokenState = _GetImpl()->_M_pTokenState;\n            }\n        }\n\n        task<_TaskType> _ContinuationTask;\n        _ContinuationTask._CreateImpl(_PTokenState, _Scheduler);\n\n        _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask);\n        _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;\n        _ContinuationTask._SetTaskCreationCallstack(_CreationStack);\n\n        _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>(\n            _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode));\n\n        return _ContinuationTask;\n    }\n\n    // The underlying implementation for this task\n    typename details::_Task_ptr<_ReturnType>::_Type _M_Impl;\n};\n\n/// <summary>\n///     The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,\n///     and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces\n///     a result of type <typeparamref name=\"_ResultType\"/> on successful completion. Tasks of type <c>task&lt;void&gt;</c> produce no result.\n///     A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using\n///     continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.\n/// </summary>\n/// <remarks>\n///     For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.\n/// </remarks>\n/**/\ntemplate<>\nclass task<void>\n{\npublic:\n    /// <summary>\n    ///     The type of the result an object of this class produces.\n    /// </summary>\n    /**/\n    typedef void result_type;\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task() : _M_unitTask()\n    {\n        // The default constructor should create a task with a nullptr impl. This is a signal that the\n        // task is not usable and should throw if any wait(), get() or then() APIs are used.\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <typeparam name=\"_Ty\">\n    ///     The type of the parameter from which the task is to be constructed.\n    /// </typeparam>\n    /// <param name=\"_Param\">\n    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>\n    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function\n    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,\n    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Ty>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    explicit task(_Ty _Param, const task_options& _TaskOptions = task_options())\n    {\n        details::_ValidateTaskConstructorArgs<void,_Ty>(_Param);\n\n        _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());\n        // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.\n        _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());\n\n        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(const task& _Other): _M_unitTask(_Other._M_unitTask){}\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {}\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(const task& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_unitTask = _Other._M_unitTask;\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(task&& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_unitTask = std::move(_Other._M_unitTask);\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_CancellationToken\">\n    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit\n    ///     the token of its antecedent task.\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType\n    {\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_CancellationToken\">\n    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit\n    ///     the token of its antecedent task.\n    /// </param>\n    /// <param name=\"_ContinuationContext\">\n    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a Windows Store\n    ///     style app. For more information, see <see cref=\"task_continuation_context Class\">task_continuation_context</see>\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType\n    {\n        task_options _TaskOptions(_CancellationToken, _ContinuationContext);\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks\n    ///     dependencies are satisfied, and it has not already been picked up for execution by a background worker.\n    /// </summary>\n    /// <returns>\n    ///     A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception\n    ///     during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.\n    /// </returns>\n    /**/\n    task_status wait() const\n    {\n        return _M_unitTask.wait();\n    }\n\n    /// <summary>\n    ///     Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to\n    ///     finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.\n    /// </summary>\n    /// <remarks>\n    ///     If the task is canceled, a call to <c>get</c> will throw a <see cref=\"task_canceled Class\">task_canceled</see> exception. If the task\n    ///     encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.\n    /// </remarks>\n    /**/\n    void get() const\n    {\n        _M_unitTask.get();\n    }\n\n    /// <summary>\n    ///     Determines if the task is completed.\n    /// </summary>\n    /// <returns>\n    ///     True if the task has completed, false otherwise.\n    /// </returns>\n    /// <remarks>\n    ///     The function returns true if the task is completed or canceled (with or without user exception).\n    /// </remarks>\n    bool is_done() const\n    {\n        return _M_unitTask.is_done();\n    }\n\n    /// <summary>\n    ///     Returns the scheduler for this task\n    /// </summary>\n    /// <returns>\n    ///     A pointer to the scheduler\n    /// </returns>\n    scheduler_ptr scheduler() const\n    {\n        return _M_unitTask.scheduler();\n    }\n\n    /// <summary>\n    ///     Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool is_apartment_aware() const\n    {\n        return _M_unitTask.is_apartment_aware();\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent the same internal task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator==(const task<void>& _Rhs) const\n    {\n        return (_M_unitTask == _Rhs._M_unitTask);\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent different internal tasks.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator!=(const task<void>& _Rhs) const\n    {\n        return !operator==(_Rhs);\n    }\n\n    /// <summary>\n    ///     Create an underlying task implementation.\n    /// </summary>\n    void _CreateImpl(details::_CancellationTokenState * _Ct, scheduler_ptr _Scheduler)\n    {\n        _M_unitTask._CreateImpl(_Ct, _Scheduler);\n    }\n\n    /// <summary>\n    ///     Return the underlying implementation for this task.\n    /// </summary>\n    const details::_Task_ptr<details::_Unit_type>::_Type & _GetImpl() const\n    {\n        return _M_unitTask._M_Impl;\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion.\n    /// </summary>\n    void _SetImpl(const details::_Task_ptr<details::_Unit_type>::_Type & _Impl)\n    {\n        _M_unitTask._SetImpl(_Impl);\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion using a move instead of a copy.\n    /// </summary>\n    void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl)\n    {\n        _M_unitTask._SetImpl(std::move(_Impl));\n    }\n\n    /// <summary>\n    ///     Sets a property determining whether the task is apartment aware.\n    /// </summary>\n    void _SetAsync(bool _Async = true)\n    {\n        _M_unitTask._SetAsync(_Async);\n    }\n\n    /// <summary>\n    ///     Sets a field in the task impl to the return callstack for calls to the task constructors and the then method.\n    /// </summary>\n    void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)\n    {\n        _M_unitTask._SetTaskCreationCallstack(_callstack);\n    }\n\n    /// <summary>\n    ///     An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only.\n    /// </summary>\n    template<typename _Function>\n    auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState, \n        details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType\n    {\n        // inherit from antecedent\n        auto _Scheduler = _GetImpl()->_GetScheduler();\n\n        return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);\n    }\n\nprivate:\n    template <typename T> friend class task;\n    template <typename T> friend class task_completion_event;\n\n    /// <summary>\n    ///     Initializes a task using a task completion event.\n    /// </summary>\n    void _TaskInitNoFunctor(task_completion_event<void>& _Event)\n    {\n        _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent);\n    }\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Initializes a task using an asynchronous action IAsyncAction^\n    /// </summary>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncAction^ _AsyncAction)\n    {\n         _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionToAsyncOperationConverter(_AsyncAction));\n    }\n\n    /// <summary>\n    ///     Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>^\n    /// </summary>\n    template<typename _P>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncActionWithProgress<_P>^ _AsyncActionWithProgress)\n    {\n        _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>(_AsyncActionWithProgress));\n    }\n#endif  /* defined (__cplusplus_winrt) */\n\n    /// <summary>\n    ///     Initializes a task using a callable object.\n    /// </summary>\n    template<typename _Function>\n    void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)\n    {\n        _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func);\n    }\n\n    /// <summary>\n    ///     Initializes a task using a non-callable object.\n    /// </summary>\n    template<typename _T>\n    void _TaskInitMaybeFunctor(_T & _Param, std::false_type)\n    {\n        _TaskInitNoFunctor(_Param);\n    }\n\n    // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.\n    task<details::_Unit_type> _M_unitTask;\n};\n\nnamespace details\n{\n    /// <summary>\n    ///   The following type traits are used for the create_task function.\n    /// </summary>\n\n#if defined (__cplusplus_winrt)\n    // Unwrap functions for asyncOperations\n    template<typename _Ty>\n    _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperation<_Ty>^);\n\n    void _GetUnwrappedType(Windows::Foundation::IAsyncAction^);\n\n    template<typename _Ty, typename _Progress>\n    _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>^);\n\n    template<typename _Progress>\n    void _GetUnwrappedType(Windows::Foundation::IAsyncActionWithProgress<_Progress>^);\n#endif  /* defined (__cplusplus_winrt) */\n\n    // Unwrap task<T>\n    template<typename _Ty>\n    _Ty _GetUnwrappedType(task<_Ty>);\n\n    // Unwrap all supportted types\n    template<typename _Ty>\n    auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg));\n    // fallback\n    template<typename _Ty>\n    _Ty _GetUnwrappedReturnType(_Ty, ...);\n\n    /// <summary>\n    ///   <c>_GetTaskType</c> functions will retrieve task type <c>T</c> in <c>task[T](Arg)</c>,\n    ///   for given constructor argument <c>Arg</c> and its property \"callable\".\n    ///   It will automatically unwrap argument to get the final return type if necessary.\n    /// </summary>\n\n    // Non-Callable\n    template<typename _Ty>\n    _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type);\n\n    // Non-Callable\n    template<typename _Ty>\n    auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc));\n\n    // Callable\n    template<typename _Ty>\n    auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0));\n\n    // Special callable returns void\n    void _GetTaskType(std::function<void()>, std::true_type);\n    struct _BadArgType{};\n\n    template<typename _Ty>\n    auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0)));\n\n    template<typename _Ty>\n    _BadArgType _FilterValidTaskType(_Ty _Param, ...);\n\n    template<typename _Ty>\n    struct _TaskTypeFromParam\n    {\n        typedef decltype(_FilterValidTaskType(stdx::declval<_Ty>(), 0)) _Type;\n    };\n} // namespace details\n\n/// <summary>\n///     Creates a PPL <see cref=\"task Class\">task</see> object. <c>create_task</c> can be used anywhere you would have used a task constructor.\n///     It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.\n/// </summary>\n/// <typeparam name=\"_Ty\">\n///     The type of the parameter from which the task is to be constructed.\n/// </typeparam>\n/// <param name=\"_Param\">\n///     The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>\n///     object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.\n/// </param>\n/// <returns>\n///     A new task of type <c>T</c>, that is inferred from <paramref name=\"_Param\"/>.\n/// </returns>\n/// <remarks>\n///     The first overload behaves like a task constructor that takes a single parameter.\n///     <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not\n///     allowed to pass in a different <c>task</c> object as the first parameter.</para>\n///     <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name=\"_Param\"/> is a <c>task_completion_event&lt;T&gt;</c>,\n///     a <c>task&lt;T&gt;</c>, or a functor that returns either type <c>T</c> or <c>task&lt;T&gt;</c>, the type of the created task is <c>task&lt;T&gt;</c>.</para>\n///     <para>In a Windows Store app, if <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncOperation&lt;T&gt;^ or\n///     Windows::Foundation::IAsyncOperationWithProgress&lt;T,P&gt;^, or a functor that returns either of those types, the created task will be of type <c>task&lt;T&gt;</c>.\n///     If <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress&lt;P&gt;^, or a functor\n///     that returns either of those types, the created task will have type <c>task&lt;void&gt;</c>.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _Ty>\n__declspec(noinline)\nauto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task<typename details::_TaskTypeFromParam<_Ty>::_Type>\n{\n    static_assert(!std::is_same<typename details::_TaskTypeFromParam<_Ty>::_Type,details::_BadArgType>::value,\n#if defined (__cplusplus_winrt)\n            \"incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event\"\n#else  /* defined (__cplusplus_winrt) */\n            \"incorrect argument for create_task; can be a callable object or a task_completion_event\"\n#endif  /* defined (__cplusplus_winrt) */\n    );\n    details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n    task<typename details::_TaskTypeFromParam<_Ty>::_Type> _CreatedTask(_Param, _TaskOptions);\n    return _CreatedTask;\n}\n\n/// <summary>\n///     Creates a PPL <see cref=\"task Class\">task</see> object. <c>create_task</c> can be used anywhere you would have used a task constructor.\n///     It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.\n/// </summary>\n/// <typeparam name=\"_Ty\">\n///     The type of the parameter from which the task is to be constructed.\n/// </typeparam>\n/// <param name=\"_Param\">\n///     The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>\n///     object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.\n/// </param>\n/// <param name=\"_Token\">\n///     The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task.\n/// </param>\n/// <returns>\n///     A new task of type <c>T</c>, that is inferred from <paramref name=\"_Param\"/>.\n/// </returns>\n/// <remarks>\n///     The first overload behaves like a task constructor that takes a single parameter.\n///     <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not\n///     allowed to pass in a different <c>task</c> object as the first parameter.</para>\n///     <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name=\"_Param\"/> is a <c>task_completion_event&lt;T&gt;</c>,\n///     a <c>task&lt;T&gt;</c>, or a functor that returns either type <c>T</c> or <c>task&lt;T&gt;</c>, the type of the created task is <c>task&lt;T&gt;</c>.</para>\n///     <para>In a Windows Store app, if <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncOperation&lt;T&gt;^ or\n///     Windows::Foundation::IAsyncOperationWithProgress&lt;T,P&gt;^, or a functor that returns either of those types, the created task will be of type <c>task&lt;T&gt;</c>.\n///     If <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress&lt;P&gt;^, or a functor\n///     that returns either of those types, the created task will have type <c>task&lt;void&gt;</c>.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\n__declspec(noinline)\ntask<_ReturnType> create_task(const task<_ReturnType>& _Task)\n{\n    task<_ReturnType> _CreatedTask(_Task);\n    return _CreatedTask;\n}\n\n#if defined (__cplusplus_winrt)\nnamespace details\n{\n    template<typename _T>\n    task<_T> _To_task_helper(Windows::Foundation::IAsyncOperation<_T>^ op)\n    {\n        return task<_T>(op);\n    }\n\n    template<typename _T, typename _Progress>\n    task<_T> _To_task_helper(Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>^ op)\n    {\n        return task<_T>(op);\n    }\n\n    inline task<void> _To_task_helper(Windows::Foundation::IAsyncAction^ op)\n    {\n        return task<void>(op);\n    }\n\n    template<typename _Progress>\n    task<void> _To_task_helper(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ op)\n    {\n        return task<void>(op);\n    }\n\n    template<typename _ProgressType>\n    class _ProgressDispatcherBase\n    {\n    public:\n\n        virtual ~_ProgressDispatcherBase()\n        {\n        }\n\n        virtual void _Report(const _ProgressType& _Val) = 0;\n    };\n\n    template<typename _ProgressType, typename _ClassPtrType>\n    class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType>\n    {\n    public:\n\n        virtual ~_ProgressDispatcher()\n        {\n        }\n\n        _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)\n        {\n        }\n\n        virtual void _Report(const _ProgressType& _Val)\n        {\n            _M_ptr->_FireProgress(_Val);\n        }\n\n    private:\n\n        _ClassPtrType _M_ptr;\n    };\n    class _ProgressReporterCtorArgType{};\n} // namespace details\n\n/// <summary>\n///     The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound\n///     to a particular asynchronous action or operation.\n/// </summary>\n/// <typeparam name=\"_ProgressType\">\n///     The payload type of each progress notification reported through the progress reporter.\n/// </typeparam>\n/// <remarks>\n///     This type is only available to Windows Store apps.\n/// </remarks>\n/// <seealso cref=\"create_async Function\"/>\n/**/\ntemplate<typename _ProgressType>\nclass progress_reporter\n{\n    typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType;\n\npublic:\n\n    /// <summary>\n    ///     Sends a progress report to the asynchronous action or operation to which this progress reporter is bound.\n    /// </summary>\n    /// <param name=\"_Val\">\n    ///     The payload to report through a progress notification.\n    /// </param>\n    /**/\n    void report(const _ProgressType& _Val) const\n    {\n        _M_dispatcher->_Report(_Val);\n    }\n\n    template<typename _ClassPtrType>\n    static progress_reporter _CreateReporter(_ClassPtrType _Ptr)\n    {\n        progress_reporter _Reporter;\n        details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr);\n        _Reporter._M_dispatcher = _PtrType(_PDispatcher);\n        return _Reporter;\n    }\n    progress_reporter() {}\n\nprivate:\n    progress_reporter(details::_ProgressReporterCtorArgType);\n\n    _PtrType _M_dispatcher;\n};\n\nnamespace details\n{\n    //\n    // maps internal definitions for AsyncStatus and defines states that are not client visible\n    //\n    enum _AsyncStatusInternal\n    {\n        _AsyncCreated = -1,  // externally invisible\n        // client visible states (must match AsyncStatus exactly)\n        _AsyncStarted = 0,   // Windows::Foundation::AsyncStatus::Started,\n        _AsyncCompleted = 1, // Windows::Foundation::AsyncStatus::Completed,\n        _AsyncCanceled = 2, // Windows::Foundation::AsyncStatus::Canceled,\n        _AsyncError = 3,     // Windows::Foundation::AsyncStatus::Error,\n        // non-client visible internal states\n        _AsyncCancelPending,\n        _AsyncClosed,\n        _AsyncUndefined\n    };\n\n    //\n    // designates whether the \"GetResults\" method returns a single result (after complete fires) or multiple results\n    // (which are progressively consumable between Start state and before Close is called)\n    //\n    enum _AsyncResultType\n    {\n        SingleResult    = 0x0001,\n        MultipleResults = 0x0002\n    };\n\n    // ***************************************************************************\n    // Template type traits and helpers for async production APIs:\n    //\n\n    struct _ZeroArgumentFunctor { };\n    struct _OneArgumentFunctor { };\n    struct _TwoArgumentFunctor { };\n\n    // ****************************************\n    // CLASS TYPES:\n\n    // ********************\n    // TWO ARGUMENTS:\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    // ********************\n    // ONE ARGUMENT:\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    void _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1) const);\n\n    // ********************\n    // ZERO ARGUMENT:\n\n    // void arg:\n    template<typename _Class, typename _ReturnType>\n    void _Arg1ClassHelperThunk(_ReturnType (_Class::*)() const);\n\n    // void arg:\n    template<typename _Class, typename _ReturnType>\n    void _Arg2ClassHelperThunk(_ReturnType (_Class::*)() const);\n\n    // void arg:\n    template<typename _Class, typename _ReturnType>\n    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)() const);\n\n    template<typename _Class, typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)() const);\n\n    // ****************************************\n    // POINTER TYPES:\n\n    // ********************\n    // TWO ARGUMENTS:\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    // ********************\n    // ONE ARGUMENT:\n\n    template<typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));\n\n    // ********************\n    // ZERO ARGUMENT:\n\n    template<typename _ReturnType>\n    void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());\n\n    template<typename _ReturnType>\n    void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());\n\n    template<typename _ReturnType>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());\n\n    template<typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());\n\n    template<typename _T>\n    struct _FunctorArguments\n    {\n        static const size_t _Count = 0;\n    };\n\n    template<>\n    struct _FunctorArguments<_OneArgumentFunctor>\n    {\n        static const size_t _Count = 1;\n    };\n\n    template<>\n    struct _FunctorArguments<_TwoArgumentFunctor>\n    {\n        static const size_t _Count = 2;\n    };\n\n    template<typename _T>\n    struct _FunctorTypeTraits\n    {\n        typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;\n        static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;\n\n        typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType;\n        typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type;\n        typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type;\n    };\n\n    template<typename _T>\n    struct _FunctorTypeTraits<_T *>\n    {\n        typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType;\n        static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;\n\n        typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType;\n        typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type;\n        typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type;\n    };\n\n    template<typename _T>\n    struct _ProgressTypeTraits\n    {\n        static const bool _TakesProgress = false;\n        typedef void _ProgressType;\n    };\n\n    template<typename _T>\n    struct _ProgressTypeTraits<progress_reporter<_T>>\n    {\n        static const bool _TakesProgress = true;\n        typedef typename _T _ProgressType;\n    };\n\n\n    template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount>\n    struct _CAFunctorOptions\n    {\n        static const bool _TakesProgress = false;\n        static const bool _TakesToken = false;\n        typedef void _ProgressType;\n    };\n\n    template<typename _T>\n    struct _CAFunctorOptions<_T, 1>\n    {\n    private:\n\n        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;\n\n    public:\n\n        static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;\n        static const bool _TakesToken = !_TakesProgress;\n        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;\n    };\n\n    template<typename _T>\n    struct _CAFunctorOptions<_T, 2>\n    {\n    private:\n\n        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;\n\n    public:\n\n        static const bool _TakesProgress = true;\n        static const bool _TakesToken = true;\n        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;\n    };\n\n    ref class _Zip\n    {\n    };\n\n    // ***************************************************************************\n    // Async Operation Task Generators\n    //\n\n    //\n    // Functor returns an IAsyncInfo - result needs to be wrapped in a task:\n    //\n    template<typename _AsyncSelector, typename _ReturnType>\n    struct _SelectorTaskGenerator\n    {\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(), _taskOptinos);\n        }\n\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(_Cts.get_token()), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(_Progress), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(_Progress, _Cts.get_token()), _taskOptinos);\n        }\n    };\n\n    template<typename _AsyncSelector>\n    struct _SelectorTaskGenerator<_AsyncSelector, void>\n    {\n        template<typename _Function>\n        static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(), _taskOptinos);\n        }\n\n        template<typename _Function>\n        static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(_Cts.get_token()), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(_Progress), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(_Progress, _Cts.get_token()), _taskOptinos);\n        }\n    };\n\n    //\n    // Functor returns a result - it needs to be wrapped in a task:\n    //\n    template<typename _ReturnType>\n    struct _SelectorTaskGenerator<_TypeSelectorNoAsync, _ReturnType>\n    {\n\n#pragma warning(push)\n#pragma warning(disable: 4702)\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func();\n            }, _taskOptinos);\n        }\n#pragma warning(pop)\n\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func(_Cts.get_token());\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func(_Progress);\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func(_Progress, _Cts.get_token());\n            }, _taskOptinos);\n        }\n    };\n\n    template<>\n    struct _SelectorTaskGenerator<_TypeSelectorNoAsync, void>\n    {\n        template<typename _Function>\n        static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func();\n            }, _taskOptinos);\n        }\n\n        template<typename _Function>\n        static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func(_Cts.get_token());\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func(_Progress);\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func(_Progress, _Cts.get_token());\n            }, _taskOptinos);\n        }\n    };\n\n    //\n    // Functor returns a task - the task can directly be returned:\n    //\n    template<typename _ReturnType>\n    struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, _ReturnType>\n    {\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func();\n        }\n\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Cts.get_token());\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress, _Cts.get_token());\n        }\n    };\n\n    template<>\n    struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, void>\n    {\n        template<typename _Function>\n        static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func();\n        }\n\n        template<typename _Function>\n        static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Cts.get_token());\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress, _Cts.get_token());\n        }\n    };\n\n    template<typename _Generator, bool _TakesToken, bool TakesProgress>\n    struct _TaskGenerator\n    {\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, false, false>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_0(_Func, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, true, false>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, false, true>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);\n        }\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, true, true>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);\n        }\n    };\n\n    // ***************************************************************************\n    // Async Operation Attributes Classes\n    //\n    // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in\n    // a single container. An attribute class must define:\n    //\n    // Mandatory:\n    // -------------------------\n    //\n    // _AsyncBaseType           : The Windows Runtime interface which is being implemented.\n    // _CompletionDelegateType  : The Windows Runtime completion delegate type for the interface.\n    // _ProgressDelegateType    : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.\n    // _ReturnType              : The return type of the async construct (void for actions / non-void for operations)\n    //\n    // _TakesProgress           : An indication as to whether or not\n    //\n    // _Generate_Task           : A function adapting the user's function into what's necessary to produce the appropriate task\n    //\n    // Optional:\n    // -------------------------\n    //\n\n    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress>\n    struct _AsyncAttributes\n    {\n    };\n\n    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true>\n    {\n        typedef typename Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType;\n        typedef typename Windows::Foundation::AsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType;\n        typedef typename _ReturnType _ReturnType;\n        typedef typename _ProgressType _ProgressType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;\n\n        static const bool _TakesProgress = true;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>\n    {\n        typedef typename Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType;\n        typedef _Zip _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType;\n        typedef typename _ReturnType _ReturnType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;\n\n        static const bool _TakesProgress = false;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>\n    {\n        typedef typename Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType;\n        typedef typename Windows::Foundation::AsyncActionProgressHandler<_ProgressType> _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType;\n        typedef void _ReturnType;\n        typedef typename _ProgressType _ProgressType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;\n\n        static const bool _TakesProgress = true;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>\n    {\n        typedef typename Windows::Foundation::IAsyncAction _AsyncBaseType;\n        typedef _Zip _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncActionCompletedHandler _CompletionDelegateType;\n        typedef void _ReturnType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;\n\n        static const bool _TakesProgress = false;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function>\n    struct _AsyncLambdaTypeTraits\n    {\n        typedef typename _FunctorTypeTraits<_Function>::_ReturnType _ReturnType;\n        typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;\n        typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;\n\n        static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;\n        static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;\n\n        typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;\n        typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;\n    };\n\n    // ***************************************************************************\n    // AsyncInfo (and completion) Layer:\n    //\n\n    //\n    // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)\n    //\n    template < typename _Attributes, _AsyncResultType resultType = SingleResult >\n    ref class _AsyncInfoBase abstract : _Attributes::_AsyncBaseType\n    {\n    internal:\n\n        _AsyncInfoBase() : \n            _M_currentStatus(_AsyncStatusInternal::_AsyncCreated), \n            _M_errorCode(S_OK),\n            _M_completeDelegate(nullptr),\n            _M_CompleteDelegateAssigned(0),\n            _M_CallbackMade(0)\n        {\n            _M_id = ::pplx::details::platform::GetNextAsyncId();\n        }\n\n    public:\n        virtual typename _Attributes::_ReturnType GetResults()\n        {\n            throw ::Platform::Exception::CreateException(E_UNEXPECTED);\n        }\n\n        virtual property unsigned int Id\n        {\n            unsigned int get()\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                return _M_id;\n            }\n\n            void set(unsigned int id)\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                if (id == 0)\n                {\n                    throw ::Platform::Exception::CreateException(E_INVALIDARG);\n                }\n                else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n                }\n\n                _M_id = id;\n            }\n        }\n\n        virtual property Windows::Foundation::AsyncStatus Status\n        {\n            Windows::Foundation::AsyncStatus get()\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                _AsyncStatusInternal _Current = _M_currentStatus;\n\n                //\n                // Map our internal cancel pending to cancelled. This way \"pending cancelled\" looks to the outside as \"cancelled\" but\n                // can still transition to \"completed\" if the operation completes without acknowledging the cancellation request\n                //\n                switch(_Current)\n                {\n                    case _AsyncCancelPending:\n                        _Current = _AsyncCanceled;\n                        break;\n                    case _AsyncCreated:\n                        _Current = _AsyncStarted;\n                        break;\n                    default:\n                        break;\n                }\n\n                return static_cast<Windows::Foundation::AsyncStatus>(_Current);\n            }\n        }\n\n        virtual property Windows::Foundation::HResult ErrorCode\n        {\n            Windows::Foundation::HResult get()\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                Windows::Foundation::HResult _Hr;\n                _Hr.Value = _M_errorCode;\n                return _Hr;\n            }\n        }\n\n        virtual property typename _Attributes::_ProgressDelegateType^ Progress\n        {\n            typename typename _Attributes::_ProgressDelegateType^ get()\n            {\n                return _GetOnProgress();\n            }\n\n            void set(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)\n            {\n                _PutOnProgress(_ProgressHandler);\n            }\n        }\n\n        virtual void Cancel()\n        {\n            if (_TransitionToState(_AsyncCancelPending))\n            {\n                _OnCancel();\n            }\n        }\n\n        virtual void Close()\n        {\n            if (_TransitionToState(_AsyncClosed))\n            {\n                _OnClose();\n            }\n            else\n            {\n                if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);\n                }\n            }\n        }\n\n        virtual property typename _Attributes::_CompletionDelegateType^ Completed\n        {\n            typename _Attributes::_CompletionDelegateType^ get()\n            {\n                _CheckValidStateForDelegateCall();\n                return _M_completeDelegate;\n            }\n\n            void set(typename _Attributes::_CompletionDelegateType^ _CompleteHandler)\n            {\n                _CheckValidStateForDelegateCall();\n                // this delegate property is \"write once\"\n                if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1)\n                {\n                    _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();\n                    _M_completeDelegate = _CompleteHandler;\n                    // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below\n                    // as perceived from _FireCompletion on another thread.\n                    MemoryBarrier();\n                    if (_IsTerminalState())\n                    {\n                        _FireCompletion();\n                    }\n                }\n                else\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_DELEGATE_ASSIGNMENT);\n                }\n            }\n        }\n\n\n    protected private:\n\n        // _Start - this is not externally visible since async operations \"hot start\" before returning to the caller\n        void _Start()\n        {\n            if (_TransitionToState(_AsyncStarted))\n            {\n                _OnStart();\n            }\n            else\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);\n            }\n        }\n\n\n        void _FireCompletion()\n        {\n            _TryTransitionToCompleted();\n\n            // we guarantee that completion can only ever be fired once\n            if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)\n            {\n                _M_completeDelegateContext._CallInContext([=] {\n                    _M_completeDelegate((_Attributes::_AsyncBaseType^)this, this->Status);\n                    _M_completeDelegate = nullptr;\n                });\n            }\n        }\n\n        virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress()\n        {\n            throw ::Platform::Exception::CreateException(E_UNEXPECTED);\n        }\n\n        virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)\n        {\n            throw ::Platform::Exception::CreateException(E_UNEXPECTED);\n        }\n\n        bool _TryTransitionToCompleted()\n        {\n            return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);\n        }\n\n        bool _TryTransitionToCancelled()\n        {\n            return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);\n        }\n\n        bool _TryTransitionToError(const HRESULT error)\n        {\n            _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);\n            return _TransitionToState(_AsyncStatusInternal::_AsyncError);\n        }\n\n        // This method checks to see if the delegate properties can be\n        // modified in the current state and generates the appropriate\n        // error hr in the case of violation.\n        inline void _CheckValidStateForDelegateCall()\n        {\n            if (_M_currentStatus == _AsyncClosed)\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n            }\n        }\n\n        // This method checks to see if results can be collected in the\n        // current state and generates the appropriate error hr in\n        // the case of a violation.\n        inline void _CheckValidStateForResultsCall()\n        {\n            _AsyncStatusInternal _Current = _M_currentStatus;\n\n            if (_Current == _AsyncError)\n            {\n                throw ::Platform::Exception::CreateException(_M_errorCode);\n            }\n#pragma warning(push)\n#pragma warning(disable: 4127) // Conditional expression is constant\n            // single result illegal before transition to Completed or Cancelled state\n            if (resultType == SingleResult)\n#pragma warning(pop)\n            {\n                if (_Current != _AsyncCompleted)\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n                }\n            }\n            // multiple results can be called after Start has been called and before/after Completed\n            else if (_Current != _AsyncStarted &&\n                     _Current != _AsyncCancelPending &&\n                     _Current != _AsyncCanceled &&\n                     _Current != _AsyncCompleted)\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n            }\n        }\n\n        // This method can be called by derived classes periodically to determine\n        // whether the asynchronous operation should continue processing or should\n        // be halted.\n        inline bool _ContinueAsyncOperation()\n        {\n            return (_M_currentStatus == _AsyncStarted);\n        }\n\n        // These two methods are used to allow the async worker implementation do work on\n        // state transitions. No real \"work\" should be done in these methods. In other words\n        // they should not block for a long time on UI timescales.\n        virtual void _OnStart() = 0;\n        virtual void _OnClose() = 0;\n        virtual void _OnCancel() = 0;\n\n    private:\n\n        // This method is used to check if calls to the AsyncInfo properties\n        // (id, status, errorcode) are legal in the current state. It also\n        // generates the appropriate error hr to return in the case of an\n        // illegal call.\n        inline void _CheckValidStateForAsyncInfoCall()\n        {\n            _AsyncStatusInternal _Current = _M_currentStatus;\n            if (_Current == _AsyncClosed)\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n            }\n            else if (_Current == _AsyncCreated)\n            {\n                throw ::Platform::Exception::CreateException(E_ASYNC_OPERATION_NOT_STARTED);\n            }\n\n        }\n\n        inline bool _TransitionToState(const _AsyncStatusInternal _NewState)\n        {\n            _AsyncStatusInternal _Current = _M_currentStatus;\n\n            // This enforces the valid state transitions of the asynchronous worker object\n            // state machine.\n            switch(_NewState)\n            {\n            case _AsyncStatusInternal::_AsyncStarted:\n                if (_Current != _AsyncCreated)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncCompleted:\n                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncCancelPending:\n                if (_Current != _AsyncStarted)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncCanceled:\n                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncError:\n                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncClosed:\n                if (!_IsTerminalState(_Current))\n                {\n                    return false;\n                }\n                break;\n            default:\n                return false;\n                break;\n            }\n\n            // attempt the transition to the new state\n            // Note: if currentStatus_ == _Current, then there was no intervening write\n            // by the async work object and the swap succeeded.\n            _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(\n                    _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus),\n                                                _NewState,\n                                                static_cast<LONG>(_Current)));\n\n            // ICE returns the former state, if the returned state and the\n            // state we captured at the beginning of this method are the same,\n            // the swap succeeded.\n            return (_RetState == _Current);\n        }\n\n        inline bool _IsTerminalState()\n        {\n            return _IsTerminalState(_M_currentStatus);\n        }\n\n        inline bool _IsTerminalState(_AsyncStatusInternal status)\n        {\n            return (status == _AsyncError ||\n                    status == _AsyncCanceled ||\n                    status == _AsyncCompleted ||\n                    status == _AsyncClosed);\n        }\n\n    private:\n\n        _ContextCallback        _M_completeDelegateContext;\n        typename _Attributes::_CompletionDelegateType^  volatile _M_completeDelegate;\n        _AsyncStatusInternal volatile                   _M_currentStatus;\n        HRESULT volatile                                _M_errorCode;\n        unsigned int                                    _M_id;\n        long volatile                                   _M_CompleteDelegateAssigned;\n        long volatile                                   _M_CallbackMade;\n    };\n\n    // ***************************************************************************\n    // Progress Layer (optional):\n    //\n\n    template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >\n    ref class _AsyncProgressBase abstract : _AsyncInfoBase<_Attributes, _ResultType>\n    {\n    };\n\n    template< typename _Attributes, _AsyncResultType _ResultType>\n    ref class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : _AsyncInfoBase<_Attributes, _ResultType>\n    {\n    internal:\n\n        _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),\n            _M_progressDelegate(nullptr)\n        {\n        }\n\n        virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress() override\n        {\n            _CheckValidStateForDelegateCall();\n            return _M_progressDelegate;\n        }\n\n        virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) override\n        {\n            _CheckValidStateForDelegateCall();\n            _M_progressDelegate = _ProgressHandler;\n            _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();\n        }\n\n        void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue)\n        {\n            if (_M_progressDelegate != nullptr)\n            {\n                _M_progressDelegateContext._CallInContext([=] {\n                    _M_progressDelegate((_Attributes::_AsyncBaseType^)this, _ProgressValue);\n                });\n            }\n        }\n\n    private:\n\n        _ContextCallback _M_progressDelegateContext;\n        typename _Attributes::_ProgressDelegateType^ _M_progressDelegate;\n    };\n\n    template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>\n    ref class _AsyncBaseProgressLayer abstract : _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>\n    {\n    };\n\n    // ***************************************************************************\n    // Task Adaptation Layer:\n    //\n\n    //\n    // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.\n    //\n    template<typename _Attributes, typename _ReturnType>\n    ref class _AsyncTaskThunkBase abstract : _AsyncBaseProgressLayer<_Attributes>\n    {\n    public:\n\n        virtual _ReturnType GetResults() override\n        {\n            _CheckValidStateForResultsCall();\n            return _M_task.get();\n        }\n\n    internal:\n\n        typedef task<_ReturnType> _TaskType;\n\n        _AsyncTaskThunkBase(const _TaskType& _Task)\n            : _M_task(_Task)\n        {\n        }\n\n        _AsyncTaskThunkBase()\n        {\n        }\n\n    protected:\n\n        virtual void _OnStart() override\n        {\n            _M_task.then( [=](_TaskType _Antecedent) {\n                try\n                {\n                    _Antecedent.get();\n                }\n                catch(task_canceled&)\n                {\n                    _TryTransitionToCancelled();\n                }\n                catch(::Platform::Exception^ _Ex)\n                {\n                    _TryTransitionToError(_Ex->HResult);\n                }\n                catch(...)\n                {\n                    _TryTransitionToError(E_FAIL);\n                }\n                _FireCompletion();\n            });\n        }\n\n    internal:\n\n        _TaskType _M_task;\n        cancellation_token_source _M_cts;\n    };\n\n    template<typename _Attributes>\n    ref class _AsyncTaskThunk : _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType>\n    {\n    internal:\n\n        _AsyncTaskThunk(const _TaskType& _Task) :\n            _AsyncTaskThunkBase(_Task)\n        {\n        }\n\n        _AsyncTaskThunk()\n        {\n        }\n\n    protected:\n\n        virtual void _OnClose() override\n        {\n        }\n\n        virtual void _OnCancel() override\n        {\n            _M_cts.cancel();\n        }\n    };\n\n    // ***************************************************************************\n    // Async Creation Layer:\n    //\n    template<typename _Function>\n    ref class _AsyncTaskGeneratorThunk sealed : _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>\n    {\n    internal:\n\n        typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;\n        typedef typename _AsyncTaskThunk<_Attributes> _Base;\n        typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;\n\n        _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack)\n        {\n            // Virtual call here is safe as the class is declared 'sealed'\n            _Start();\n        }\n\n    protected:\n\n        //\n        // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,\n        // let the base thunk handle everything.\n        //\n\n        virtual void _OnStart() override\n        {\n            //\n            // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,\n            // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.\n            //\n            _M_task = _Attributes::_Generate_Task(_M_func, this, _M_cts, _M_creationCallstack);\n            _Base::_OnStart();\n        }\n\n        virtual void _OnCancel() override\n        {\n            _Base::_OnCancel();\n        }\n\n    private:\n        _TaskCreationCallstack _M_creationCallstack;\n        _Function _M_func;\n    };\n} // namespace details\n\n/// <summary>\n///     Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of <c>create_async</c> is\n///     one of either <c>IAsyncAction^</c>, <c>IAsyncActionWithProgress&lt;TProgress&gt;^</c>, <c>IAsyncOperation&lt;TResult&gt;^</c>, or\n///     <c>IAsyncOperationWithProgress&lt;TResult, TProgress&gt;^</c> based on the signature of the lambda passed to the method.\n/// </summary>\n/// <param name=\"_Func\">\n///     The lambda or function object from which to create a Windows Runtime asynchronous construct.\n/// </param>\n/// <returns>\n///     An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress&lt;TProgress&gt;^, IAsyncOperation&lt;TResult&gt;^, or an\n///     IAsyncOperationWithProgress&lt;TResult, TProgress&gt;^. The interface returned depends on the signature of the lambda passed into the function.\n/// </returns>\n/// <remarks>\n///     The return type of the lambda determines whether the construct is an action or an operation.\n///     <para>Lambdas that return void cause the creation of actions. Lambdas that return a result of type <c>TResult</c> cause the creation of\n///     operations of TResult.</para>\n///     <para>The lambda may also return a <c>task&lt;TResult&gt;</c> which encapsulates the aysnchronous work within itself or is the continuation of\n///     a chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since the tasks are the ones that\n///     execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by <c>create_async</c>.\n///     This implies that a lambda that returns a task&lt;void&gt; will cause the creation of actions, and a lambda that returns a task&lt;TResult&gt; will\n///     cause the creation of operations of TResult.</para>\n///     <para>The lambda may take either zero, one or two arguments. The valid arguments are <c>progress_reporter&lt;TProgress&gt;</c> and\n///     <c>cancellation_token</c>, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without\n///     the capability for progress reporting. A lambda that takes a progress_reporter&lt;TProgress&gt; will cause <c>create_async</c> to return an asynchronous\n///     construct which reports progress of type TProgress each time the <c>report</c> method of the progress_reporter object is called. A lambda that\n///     takes a cancellation_token may use that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the\n///     asynchronous construct causes cancellation of those tasks.</para>\n///     <para>If the body of the lambda or function object returns a result (and not a task&lt;TResult&gt;), the lamdba will be executed\n///     asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The <c>IAsyncInfo::Cancel</c> method will\n///     cause cancellation of the implicit task.</para>\n///     <para>If the body of the lambda returns a task, the lamba executes inline, and by declaring the lambda to take an argument of type\n///     <c>cancellation_token</c> you can trigger cancellation of any tasks you create within the lambda by passing that token in when you create them.\n///     You may also use the <c>register_callback</c> method on the token to cause the Runtime to invoke a callback when you call <c>IAsyncInfo::Cancel</c> on\n///     the async operation or action produced..</para>\n///     <para>This function is only available to Windows Store apps.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"progress_reporter Class\"/>\n/// <seealso cref=\"cancelation_token Class\"/>\n/**/\ntemplate<typename _Function>\n__declspec(noinline)\ndetails::_AsyncTaskGeneratorThunk<_Function> ^create_async(const _Function& _Func)\n{\n    static_assert(std::is_same<decltype(details::_IsValidCreateAsync(_Func,0,0,0,0)),std::true_type>::value,\n        \"argument to create_async must be a callable object taking zero, one or two arguments\");\n    return ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func, _CAPTURE_CALLSTACK());\n}\n\n#endif  /* defined (__cplusplus_winrt) */\n\nnamespace details\n{\n    // Helper struct for when_all operators to know when tasks have completed\n    template<typename _Type>\n    struct _RunAllParam\n    {\n        _RunAllParam() : _M_completeCount(0), _M_numTasks(0)\n        {\n        }\n\n        void _Resize(size_t _Len, bool _SkipVector = false)\n        {\n            _M_numTasks = _Len;\n            if (!_SkipVector)\n            {\n                _M_vector._Result.resize(_Len);\n            }\n        }\n\n        task_completion_event<_Unit_type>       _M_completed;\n        _ResultHolder<std::vector<_Type> >      _M_vector;\n        _ResultHolder<_Type>                    _M_mergeVal;\n        atomic_size_t                           _M_completeCount;\n        size_t                                  _M_numTasks;\n    };\n\n    template<typename _Type>\n    struct _RunAllParam<std::vector<_Type> >\n    {\n        _RunAllParam() : _M_completeCount(0), _M_numTasks(0)\n        {\n        }\n\n        void _Resize(size_t _Len, bool _SkipVector = false)\n        {\n            _M_numTasks = _Len;\n            \n            if (!_SkipVector)\n            {\n                _M_vector.resize(_Len);\n            }\n        }\n\n        task_completion_event<_Unit_type>       _M_completed;\n        std::vector<_ResultHolder<std::vector<_Type> > >  _M_vector;\n        atomic_size_t                           _M_completeCount;\n        size_t                                  _M_numTasks;\n    };\n\n    // Helper struct specialization for void\n    template<>\n    struct _RunAllParam<_Unit_type>\n    {\n        _RunAllParam() : _M_completeCount(0), _M_numTasks(0)\n        {\n        }\n\n        void _Resize(size_t _Len)\n        {\n            _M_numTasks = _Len;\n        }\n\n        task_completion_event<_Unit_type> _M_completed;\n        atomic_size_t _M_completeCount;\n        size_t _M_numTasks;\n    };\n\n    inline void _JoinAllTokens_Add(const cancellation_token_source& _MergedSrc, _CancellationTokenState *_PJoinedTokenState)\n    {\n        if (_PJoinedTokenState != nullptr && _PJoinedTokenState != _CancellationTokenState::_None())\n        {\n            cancellation_token _T = cancellation_token::_FromImpl(_PJoinedTokenState);\n            _T.register_callback( [=](){\n                _MergedSrc.cancel();\n                });\n        }\n    }\n\n    template<typename _ElementType, typename _Function, typename _TaskType>\n    void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task)\n    {\n        if (_Task._GetImpl()->_IsCompleted())\n        {\n            _Func();\n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                // Inline execute its direct continuation, the _ReturnTask\n                _PParam->_M_completed.set(_Unit_type());\n                // It's safe to delete it since all usage of _PParam in _ReturnTask has been finished.\n                delete _PParam;\n            }\n        }\n        else\n        {\n            _ASSERTE(_Task._GetImpl()->_IsCanceled());\n            if (_Task._GetImpl()->_HasUserException())\n            {\n                // _Cancel will return false if the TCE is already canceled with or without exception\n                _PParam->_M_completed._Cancel(_Task._GetImpl()->_GetExceptionHolder());\n            }\n            else\n            {\n                _PParam->_M_completed._Cancel();\n            }\n\n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                delete _PParam;\n            }\n        }\n    }\n\n    template<typename _ElementType, typename _Iterator>\n    struct _WhenAllImpl\n    {\n        static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n\n            auto _PParam = new _RunAllParam<_ElementType>();\n            cancellation_token_source _MergedSource;\n\n            // Step1: Create task completion event.\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_MergedSource.get_token());\n            task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);\n            // The return task must be created before step 3 to enforce inline execution.\n            auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {\n                return _PParam->_M_vector.Get();\n            }, nullptr);\n\n            // Step2: Combine and check tokens, and count elements in range.\n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_MergedSource, _PTokenState);\n                _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));\n            }\n            else\n            {\n                size_t _TaskNum = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    _TaskNum++;\n                    _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);\n                }\n                _PParam->_Resize(_TaskNum);\n            }\n\n            // Step3: Check states of previous tasks.\n            if( _Begin == _End )\n            {\n                _PParam->_M_completed.set(_Unit_type());\n                delete _PParam;\n            }\n            else\n            {\n                size_t _Index = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    if (_PTask->is_apartment_aware())\n                    {\n                        _ReturnTask._SetAsync();\n                    }\n\n                    _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {\n\n                        auto _PParamCopy = _PParam;\n                        auto _IndexCopy = _Index;\n                        auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){\n                            _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult();\n                        };\n\n                        _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n                    }, _CancellationTokenState::_None()); \n\n                    _Index++;\n                }\n            }\n\n            return _ReturnTask;\n        }\n    };\n\n    template<typename _ElementType, typename _Iterator>\n    struct _WhenAllImpl<std::vector<_ElementType>, _Iterator>\n    {\n        static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n\n            auto _PParam = new _RunAllParam<std::vector<_ElementType>>();\n            cancellation_token_source _MergedSource;\n\n            // Step1: Create task completion event.\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_MergedSource.get_token());\n            task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);\n            // The return task must be created before step 3 to enforce inline execution.\n            auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {\n                _ASSERTE(_PParam->_M_completeCount ==  _PParam->_M_numTasks);\n                std::vector<_ElementType> _Result;\n                for(size_t _I = 0; _I < _PParam->_M_numTasks; _I++)\n                {\n                    const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get();\n                    _Result.insert(_Result.end(), _Vec.begin(), _Vec.end());\n                }\n                return _Result;\n            }, nullptr);\n\n            // Step2: Combine and check tokens, and count elements in range.\n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_MergedSource, _PTokenState);\n                _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));\n            }\n            else\n            {\n                size_t _TaskNum = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    _TaskNum++;\n                    _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);\n                }\n                _PParam->_Resize(_TaskNum);\n            }\n\n            // Step3: Check states of previous tasks.\n            if( _Begin == _End )\n            {\n                _PParam->_M_completed.set(_Unit_type());\n                delete _PParam;\n            }\n            else\n            {\n                size_t _Index = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    if (_PTask->is_apartment_aware())\n                    {\n                        _ReturnTask._SetAsync();\n                    }\n\n                    _PTask->_Then([_PParam, _Index](task<std::vector<_ElementType>> _ResultTask) {\n\n                        auto _PParamCopy = _PParam;\n                        auto _IndexCopy = _Index;\n                        auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() {\n                            _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult());\n                        };\n\n                        _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n                    }, _CancellationTokenState::_None());\n\n                    _Index++;\n                }\n            }\n\n            return  _ReturnTask;\n        }\n    };\n\n    template<typename _Iterator>\n    struct _WhenAllImpl<void, _Iterator>\n    {\n        static task<void> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n\n            auto _PParam = new _RunAllParam<_Unit_type>();\n            cancellation_token_source _MergedSource;\n\n            // Step1: Create task completion event.\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_MergedSource.get_token());\n            task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);\n            // The return task must be created before step 3 to enforce inline execution.\n            auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) {\n            }, nullptr);\n\n            // Step2: Combine and check tokens, and count elements in range.\n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_MergedSource, _PTokenState);\n                _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));\n            }\n            else\n            {\n                size_t _TaskNum = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    _TaskNum++;\n                    _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);\n                }\n                _PParam->_Resize(_TaskNum);\n            }\n\n            // Step3: Check states of previous tasks.\n            if( _Begin == _End )\n            {\n                _PParam->_M_completed.set(_Unit_type());\n                delete _PParam;\n            }\n            else\n            {\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    if (_PTask->is_apartment_aware())\n                    {\n                        _ReturnTask._SetAsync();\n                    }\n\n                    _PTask->_Then([_PParam](task<void> _ResultTask) {\n                        auto _Func = [](){};\n                        _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n                    }, _CancellationTokenState::_None());\n                }\n            }\n\n            return _ReturnTask;\n        }\n    };\n\n    template<typename _ReturnType>\n    task<std::vector<_ReturnType>> _WhenAllVectorAndValue(const task<std::vector<_ReturnType>>& _VectorTask, const task<_ReturnType>& _ValueTask,\n                                                          bool _OutputVectorFirst)\n    {\n        auto _PParam = new _RunAllParam<_ReturnType>();\n        cancellation_token_source _MergedSource;\n\n        // Step1: Create task completion event.\n        task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());\n        // The return task must be created before step 3 to enforce inline execution.\n        auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ReturnType> {\n            _ASSERTE(_PParam->_M_completeCount == 2);\n            auto _Result = _PParam->_M_vector.Get(); // copy by value\n            auto _mergeVal = _PParam->_M_mergeVal.Get();\n\n            if (_OutputVectorFirst == true)\n            {                \n                _Result.push_back(_mergeVal);\n            }\n            else\n            {\n                _Result.insert(_Result.begin(), _mergeVal);\n            }\n            return _Result;\n        }, nullptr);\n\n        // Step2: Combine and check tokens.\n        _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState);\n        _JoinAllTokens_Add(_MergedSource, _ValueTask._GetImpl()->_M_pTokenState);\n\n        // Step3: Check states of previous tasks.\n        _PParam->_Resize(2, true);\n\n        if (_VectorTask.is_apartment_aware() || _ValueTask.is_apartment_aware())\n        {\n            _ReturnTask._SetAsync();\n        }\n        _VectorTask._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {\n            auto _PParamCopy = _PParam;\n            auto _Func = [_PParamCopy, &_ResultTask]() {\n                auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();\n                _PParamCopy->_M_vector.Set(_ResultLocal);\n            };\n\n            _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n        }, _CancellationTokenState::_None());\n        _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) {\n            auto _PParamCopy = _PParam;\n            auto _Func = [_PParamCopy, &_ResultTask]() {\n                auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();\n                _PParamCopy->_M_mergeVal.Set(_ResultLocal);\n            };\n\n            _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n        }, _CancellationTokenState::_None());\n\n        return _ReturnTask;\n    }\n} // namespace details\n\n/// <summary>\n///     Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_Iterator\">\n///     The type of the input iterator.\n/// </typeparam>\n/// <param name=\"_Begin\">\n///     The position of the first element in the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_End\">\n///     The position of the first element beyond the range of elements to be combined into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate <typename _Iterator>\nauto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options()) \n    -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))\n{\n    typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;\n    return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs};\n    return when_all(_PTasks, _PTasks+2);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)\n{\n    return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)\n{\n    task<std::vector<_ReturnType>> _PTasks[2] = {_Lhs, _Rhs};\n    return when_all(_PTasks, _PTasks+2);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ninline task<void> operator&&(const task<void> & _Lhs, const task<void> & _Rhs)\n{\n    task<void> _PTasks[2] = {_Lhs, _Rhs};\n    return when_all(_PTasks, _PTasks+2);\n}\n\nnamespace details\n{\n    // Helper struct for when_any operators to know when tasks have completed\n    template <typename _CompletionType>\n    struct _RunAnyParam\n    {\n        _RunAnyParam() : _M_exceptionRelatedToken(nullptr), _M_completeCount(0), _M_numTasks(0), _M_fHasExplicitToken(false)\n        {\n        }\n        ~_RunAnyParam()\n        {\n            if (_CancellationTokenState::_IsValid(_M_exceptionRelatedToken))\n                _M_exceptionRelatedToken->_Release();\n        }\n        task_completion_event<_CompletionType>      _M_Completed;\n        cancellation_token_source                   _M_cancellationSource;\n        _CancellationTokenState *                   _M_exceptionRelatedToken;\n        atomic_size_t                               _M_completeCount;\n        size_t                                      _M_numTasks;\n        bool                                        _M_fHasExplicitToken;\n    };\n\n    template<typename _CompletionType, typename _Function, typename _TaskType>\n    void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task)\n    {\n        bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != _CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled();\n        if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled)\n        {\n            _Func();\n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                delete _PParam;\n            }\n        }\n        else\n        {\n            _ASSERTE(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled);\n            if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled)\n            {\n                if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder()))\n                {\n                    // This can only enter once.\n                    _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState;\n                    _ASSERTE(_PParam->_M_exceptionRelatedToken);\n                    // Deref token will be done in the _PParam destructor.\n                    if (_PParam->_M_exceptionRelatedToken != _CancellationTokenState::_None())\n                    {\n                        _PParam->_M_exceptionRelatedToken->_Reference();\n                    }\n                }\n            }\n            \n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                // If no one has be completed so far, we need to make some final cancellation decision.\n                if (!_PParam->_M_Completed._IsTriggered())\n                {\n                    // If we already explicit token, we can skip the token join part.\n                    if (!_PParam->_M_fHasExplicitToken)\n                    {\n                        if (_PParam->_M_exceptionRelatedToken)\n                        {\n                            _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken);\n                        }\n                        else\n                        {\n                            // If haven't captured any exception token yet, there was no exception for all those tasks,\n                            // so just pick a random token (current one) for normal cancellation.\n                            _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState);\n                        }\n                    }\n                    // Do exception cancellation or normal cancellation based on whether it has stored exception.\n                    _PParam->_M_Completed._Cancel();\n                }\n                delete _PParam;\n            }\n        }\n    }\n\n    template<typename _ElementType, typename _Iterator>\n    struct _WhenAnyImpl\n    {\n        static task<std::pair<_ElementType, size_t>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            if( _Begin == _End )\n            {\n                throw invalid_operation(\"when_any(begin, end) cannot be called on an empty container.\");\n            }\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n            auto _PParam = new _RunAnyParam<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>>();\n            \n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);\n                _PParam->_M_fHasExplicitToken = true;\n            }\n            \n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());\n            task<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options); \n\n            // Keep a copy ref to the token source\n            auto _CancellationSource = _PParam->_M_cancellationSource;\n\n            _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));\n            size_t _Index = 0;\n            for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n            {\n                if (_PTask->is_apartment_aware())\n                {\n                    _Any_tasks_completed._SetAsync();\n                }\n\n                _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {\n                    auto _PParamCopy = _PParam; // Dev10\n                    auto _IndexCopy = _Index; // Dev10\n                    auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {\n                        _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy),  _ResultTask._GetImpl()->_M_pTokenState));\n                    };\n\n                    _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n                }, _CancellationTokenState::_None());\n\n                _Index++;\n            }\n\n            // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.\n            return _Any_tasks_completed._Then([=](std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *> _Result) -> std::pair<_ElementType, size_t> {\n                _ASSERTE(_Result.second);\n                if (!_PTokenState)\n                {\n                    _JoinAllTokens_Add(_CancellationSource, _Result.second);\n                }\n                return _Result.first;\n            }, nullptr);\n        }\n    };\n\n    template<typename _Iterator>\n    struct _WhenAnyImpl<void, _Iterator>\n    {\n        static task<size_t> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            if( _Begin == _End )\n            {\n                throw invalid_operation(\"when_any(begin, end) cannot be called on an empty container.\");\n            }\n\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n            auto _PParam = new _RunAnyParam<std::pair<size_t, _CancellationTokenState *>>();\n            \n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);\n                _PParam->_M_fHasExplicitToken = true;\n            }\n\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());\n            task<std::pair<size_t, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);\n\n            // Keep a copy ref to the token source\n            auto _CancellationSource = _PParam->_M_cancellationSource;\n\n            _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));\n            size_t _Index = 0;\n            for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n            {\n                if (_PTask->is_apartment_aware())\n                {\n                    _Any_tasks_completed._SetAsync();\n                }\n\n                _PTask->_Then([_PParam, _Index](task<void> _ResultTask) {\n                    auto _PParamCopy = _PParam; // Dev10\n                    auto _IndexCopy = _Index; // Dev10\n                    auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {\n                        _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState));\n                    };\n                    _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n                }, _CancellationTokenState::_None());\n\n                _Index++;\n            }\n\n            // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.\n            return _Any_tasks_completed._Then([=](std::pair<size_t, _CancellationTokenState *> _Result) -> size_t {\n                _ASSERTE(_Result.second);\n                if (!_PTokenState)\n                {\n                    _JoinAllTokens_Add(_CancellationSource, _Result.second);\n                }\n                return _Result.first;\n            }, nullptr);\n        }\n    };\n} // namespace details\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_Iterator\">\n///     The type of the input iterator.\n/// </typeparam>\n/// <param name=\"_Begin\">\n///     The position of the first element in the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_End\">\n///     The position of the first element beyond the range of elements to be combined into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::pair&lt;T, size_t&gt;&gt;></c>, where the first element of the pair is the result\n///     of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c>\n///     the output is a <c>task&lt;size_t&gt;</c>, where the result is the index of the completing task.\n/// </returns>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _Iterator>\nauto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())\n    -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))\n{\n    typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;\n    return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_Iterator\">\n///     The type of the input iterator.\n/// </typeparam>\n/// <param name=\"_Begin\">\n///     The position of the first element in the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_End\">\n///     The position of the first element beyond the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_CancellationToken\">\n///     The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting\n///     task will receive the cancellation token of the task that causes it to complete.\n/// </param>\n/// <returns>\n///     A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::pair&lt;T, size_t&gt;&gt;></c>, where the first element of the pair is the result\n///     of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c>\n///     the output is a <c>task&lt;size_t&gt;</c>, where the result is the index of the completing task.\n/// </returns>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _Iterator>\nauto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken)\n    -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))\n{\n    typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;\n    return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when either of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, size_t>>();\n\n    task<std::pair<_ReturnType, size_t>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());\n    // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,\n    // So that _PParam can be used before it getting deleted.\n    auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret) -> _ReturnType {\n        _ASSERTE(_Ret.second);\n        _JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast<details::_CancellationTokenState *>(_Ret.second));\n        return _Ret.first;\n    }, nullptr);\n\n    if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())\n    {\n        _ReturnTask._SetAsync();\n    }\n\n    _PParam->_M_numTasks = 2;\n    auto _Continuation = [_PParam](task<_ReturnType> _ResultTask) {\n        //  Dev10 compiler bug\n        auto _PParamCopy = _PParam;\n        auto _Func = [&_ResultTask, _PParamCopy]() {\n            _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast<size_t>(_ResultTask._GetImpl()->_M_pTokenState)));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    };\n\n    _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());\n    _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());\n\n    return _ReturnTask;\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator||(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    auto _PParam = new details::_RunAnyParam<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>>();\n\n    task<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());\n\n    // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,\n    // So that _PParam can be used before it getting deleted.\n    auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *> _Ret) -> std::vector<_ReturnType> {\n        _ASSERTE(_Ret.second);\n        _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);\n        return _Ret.first;\n    }, nullptr);\n\n    if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())\n    {\n        _ReturnTask._SetAsync();\n    }\n\n    _PParam->_M_numTasks = 2;\n    _Lhs._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {\n        //  Dev10 compiler bug\n        auto _PParamCopy = _PParam;\n        auto _Func = [&_ResultTask, _PParamCopy]() {\n            auto _Result = _ResultTask._GetImpl()->_GetResult();\n            _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    }, details::_CancellationTokenState::_None());\n\n    \n    _Rhs._Then([_PParam](task<_ReturnType> _ResultTask) \n    {\n        auto _PParamCopy = _PParam;\n        auto _Func = [&_ResultTask, _PParamCopy]() {\n            auto _Result = _ResultTask._GetImpl()->_GetResult();\n\n            std::vector<_ReturnType> _Vec;\n            _Vec.push_back(_Result);\n            _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    }, details::_CancellationTokenState::_None());\n\n    return _ReturnTask;\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)\n{\n    return _Rhs || _Lhs;\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ninline task<void> operator||(const task<void> & _Lhs, const task<void> & _Rhs)\n{\n    auto _PParam = new details::_RunAnyParam<std::pair<details::_Unit_type, details::_CancellationTokenState *>>();\n\n    task<std::pair<details::_Unit_type, details::_CancellationTokenState *>> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());\n    // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,\n    // So that _PParam can be used before it getting deleted.\n    auto _ReturnTask = _Any_task_completed._Then([=](std::pair<details::_Unit_type, details::_CancellationTokenState *> _Ret) { \n        _ASSERTE(_Ret.second);\n        details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);\n    }, nullptr);\n\n    if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())\n    {\n        _ReturnTask._SetAsync();\n    }\n\n    _PParam->_M_numTasks = 2;\n    auto _Continuation = [_PParam](task<void> _ResultTask) mutable {\n        //  Dev10 compiler needs this.\n        auto _PParam1 = _PParam;\n        auto _Func = [&_ResultTask, _PParam1]() {\n            _PParam1->_M_Completed.set(std::make_pair(details::_Unit_type(), _ResultTask._GetImpl()->_M_pTokenState));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    };\n\n    _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());\n    _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());\n\n    return _ReturnTask;\n}\n\ntemplate<typename _Ty>\ntask<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_options())\n{\n    task_completion_event<_Ty> _Tce;\n    _Tce.set(_Param);\n    return create_task(_Tce, _TaskOptions);\n}\n\n// Work around VS 2010 compiler bug\n#if _MSC_VER == 1600\ninline task<bool> task_from_result(bool _Param)\n{\n    task_completion_event<bool> _Tce;\n    _Tce.set(_Param);\n    return create_task(_Tce, task_options());\n}\n#endif\ninline task<void> task_from_result(const task_options& _TaskOptions = task_options())\n{\n    task_completion_event<void> _Tce;\n    _Tce.set();\n    return create_task(_Tce, _TaskOptions);\n}\n\ntemplate<typename _TaskType, typename _ExType>\ntask<_TaskType> task_from_exception(_ExType _Exception, const task_options& _TaskOptions = task_options())\n{\n    task_completion_event<_TaskType> _Tce;\n    _Tce.set_exception(_Exception);\n    return create_task(_Tce, _TaskOptions);\n}\n\nnamespace details\n{\n    /// <summary>\n    /// A convenient extension to Concurrency: loop until a condition is no longer met\n    /// </summary>\n    /// <param name=\"func\">\n    ///   A function representing the body of the loop. It will be invoked at least once and \n    ///   then repetitively as long as it returns true.\n    /// </param>\n    inline\n    task<bool> do_while(std::function<task<bool>(void)> func)\n    {\n        task<bool> first = func();\n        return first.then([=](bool guard) -> task<bool> {\n            if (guard)\n                return do_while(func);\n            else\n                return first;\n            });\n    }\n\n} // namespace details\n\n} // namespace Concurrency\n\n#pragma pop_macro(\"new\")\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n#pragma pack(pop)\n\n#endif // (defined(_MSC_VER) && (_MSC_VER >= 1800))\n\n#ifndef _CONCRT_H\n#ifndef _LWRCASE_CNCRRNCY\n#define _LWRCASE_CNCRRNCY\n// Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace\n// is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist.\nnamespace Concurrency {}\nnamespace concurrency = Concurrency;\n#endif\n#endif\n\n#endif // _PPLXTASKS_H\n"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxtasks.140.h",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved. \n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library - PPLx Tasks\n*\n* For the latest on this and related APIs, please see http://casablanca.codeplex.com.\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#ifndef _PPLXTASKS_H\n#define _PPLXTASKS_H\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX\n#include <ppltasks.h>\nnamespace pplx = Concurrency;\n#if (_MSC_VER >= 1900)\n#if HC_PLATFORM != HC_PLATFORM_GDK\n#include <concrt.h>\n#endif\nnamespace Concurrency {\n    namespace extensibility {\n        typedef ::std::condition_variable condition_variable_t;\n        typedef ::std::mutex critical_section_t;\n        typedef ::std::unique_lock< ::std::mutex> scoped_critical_section_t;\n\n#if HC_PLATFORM != HC_PLATFORM_GDK\n        typedef ::Concurrency::event event_t;\n        typedef ::Concurrency::reader_writer_lock reader_writer_lock_t;\n        typedef ::Concurrency::reader_writer_lock::scoped_lock scoped_rw_lock_t;\n        typedef ::Concurrency::reader_writer_lock::scoped_lock_read scoped_read_lock_t;\n\n        typedef ::Concurrency::details::_ReentrantBlockingLock recursive_lock_t;\n        typedef recursive_lock_t::_Scoped_lock scoped_recursive_lock_t;\n#endif\n    }\n}\n#endif // _MSC_VER >= 1900\n#else\n\n#include \"pplx/pplx.h\"\n\n#if defined(__ANDROID__)\n#include <jni.h>\nvoid cpprest_init(JavaVM*);\n#endif\n\n// Cannot build using a compiler that is older than dev10 SP1\n#if defined(_MSC_VER)\n#if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/\n#error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks\n#endif /*IFSTRIP=IGN*/\n#endif /* defined(_MSC_VER) */\n\n#include <functional>\n#include <vector>\n#include <utility>\n#include <exception>\n#include <algorithm>\n\n#if defined(_MSC_VER)\n#if defined(__cplusplus_winrt)\n#include <windows.h>\n#include <ctxtcall.h>\n#include <agile.h>\n#include <winapifamily.h>\n#ifndef _UITHREADCTXT_SUPPORT\n\n#ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/\n\n// It is safe to include winapifamily as WINAPI_FAMILY was defined by the user\n#include <winapifamily.h>\n\n#if WINAPI_FAMILY == WINAPI_FAMILY_APP\n    // UI thread context support is not required for desktop and Windows Store apps\n    #define _UITHREADCTXT_SUPPORT 0\n#elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP\n    // UI thread context support is not required for desktop and Windows Store apps\n    #define _UITHREADCTXT_SUPPORT 0\n#else  /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */\n    #define _UITHREADCTXT_SUPPORT 1\n#endif  /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */\n\n#else  /* WINAPI_FAMILY */\n    // Not supported without a WINAPI_FAMILY setting.\n    #define _UITHREADCTXT_SUPPORT 0\n#endif  /* WINAPI_FAMILY */\n\n#endif  /* _UITHREADCTXT_SUPPORT */\n\n#if _UITHREADCTXT_SUPPORT\n    #include <uithreadctxt.h>\n#endif  /* _UITHREADCTXT_SUPPORT */\n\n    #pragma detect_mismatch(\"_PPLTASKS_WITH_WINRT\", \"1\")\n#else /* defined(__cplusplus_winrt) */\n    #pragma detect_mismatch(\"_PPLTASKS_WITH_WINRT\", \"0\")\n#endif /* defined(__cplusplus_winrt) */\n#endif /* defined(_MSC_VER) */\n\n#ifdef _DEBUG\n    #define _DBG_ONLY(X) X\n#else\n    #define _DBG_ONLY(X)\n#endif // #ifdef _DEBUG\n\n// std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11.\n#ifdef _MSC_VER\n#if _MSC_VER < 1700 /*IFSTRIP=IGN*/\nnamespace std\n{\n    template<class _E> exception_ptr make_exception_ptr(_E _Except)\n    {\n        return copy_exception(_Except);\n    }\n}\n#endif /* _MSC_VER < 1700 */\n#ifndef _PPLTASK_ASYNC_LOGGING\n    #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)\n        #define _PPLTASK_ASYNC_LOGGING 1  // Only enable async logging under dev12 winrt\n    #else\n        #define _PPLTASK_ASYNC_LOGGING 0\n    #endif\n#endif /* !_PPLTASK_ASYNC_LOGGING */\n#endif /* _MSC_VER */\n\n#pragma pack(push,_CRT_PACKING)\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 28197)\n#pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation\n#pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming\n#endif /* defined(_MSC_VER) */\n\n// All CRT public header files are required to be protected from the macro new\n#pragma push_macro(\"new\")\n#undef new\n\n// stuff ported from Dev11 CRT\n// NOTE: this doesn't actually match std::declval. it behaves differently for void!\n// so don't blindly change it to std::declval.\nnamespace stdx\n{\n    template<class _T>\n    _T&& declval();\n}\n\n/// <summary>\n///     The <c>pplx</c> namespace provides classes and functions that give you access to the Concurrency Runtime,\n///     a concurrent programming framework for C++. For more information, see <see cref=\"Concurrency Runtime\"/>.\n/// </summary>\n/**/\nnamespace pplx\n{\n/// <summary>\n///     A type that represents the terminal state of a task. Valid values are <c>completed</c> and <c>canceled</c>.\n/// </summary>\n/// <seealso cref=\"task Class\"/>\n/**/\ntypedef task_group_status task_status;\n\ntemplate <typename _Type> class task;\ntemplate <> class task<void>;\n\n// In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h.  In retail builds, default to only one frame.\n#ifndef PPL_TASK_SAVE_FRAME_COUNT\n#ifdef _DEBUG\n#define PPL_TASK_SAVE_FRAME_COUNT 10\n#else\n#define PPL_TASK_SAVE_FRAME_COUNT 1\n#endif\n#endif\n\n/// <summary>\n/// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified, \n/// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured.\n/// </summary>\n/// <ramarks>\n/// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress()\n/// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself.\n/// </remarks>\n#if PPL_TASK_SAVE_FRAME_COUNT > 1\n#if defined(__cplusplus_winrt) && !defined(_DEBUG)\n#pragma message (\"WARNING: Redefinning PPL_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!\")\n#define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())\n#else\n#define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT)\n#endif\n#else\n#define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())\n#endif\n\n\n/// <summary>\n///     Returns an indication of whether the task that is currently executing has received a request to cancel its\n///     execution. Cancellation is requested on a task if the task was created with a cancellation token, and\n///     the token source associated with that token is canceled.\n/// </summary>\n/// <returns>\n///     <c>true</c> if the currently executing task has received a request for cancellation, <c>false</c> otherwise.\n/// </returns>\n/// <remarks>\n///     If you call this method in the body of a task and it returns <c>true</c>, you must respond with a call to\n///     <see cref=\"cancel_current_task Function\">cancel_current_task</see> to acknowledge the cancellation request,\n///     after performing any cleanup you need. This will abort the execution of the task and cause it to enter into\n///     the <c>canceled</c> state. If you do not respond and continue execution, or return instead of calling\n///     <c>cancel_current_task</c>, the task will enter the <c>completed</c> state when it is done.\n///     state.\n///     <para>A task is not cancellable if it was created without a cancellation token.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"cancellation_token_source Class\"/>\n/// <seealso cref=\"cancellation_token Class\"/>\n/// <seealso cref=\"cancel_current_task Function\"/>\n/**/\ninline bool _pplx_cdecl is_task_cancellation_requested()\n{\n    return ::pplx::details::_TaskCollection_t::_Is_cancellation_requested();\n}\n\n/// <summary>\n///     Cancels the currently executing task. This function can be called from within the body of a task to abort the\n///     task's execution and cause it to enter the <c>canceled</c> state. While it may be used in response to\n///     the <see cref=\"is_task_cancellation_requested Function\">is_task_cancellation_requested</see> function, you may\n///     also use it by itself, to initiate cancellation of the task that is currently executing.\n///     <para>It is not a supported scenario to call this function if you are not within the body of a <c>task</c>.\n///     Doing so will result in undefined behavior such as a crash or a hang in your application.</para>\n/// </summary>\n/// <seealso cref=\"task Class\"/>\n/**/\ninline __declspec(noreturn) void _pplx_cdecl cancel_current_task()\n{\n    throw task_canceled();\n}\n\nnamespace details\n{\n    /// <summary>\n    ///     Callstack container, which is used to capture and preserve callstacks in ppltasks.\n    ///     Members of this class is examined by vc debugger, thus there will be no public access methods.\n    ///     Please note that names of this class should be kept stable for debugger examining.\n    /// </summary>\n    class _TaskCreationCallstack\n    {\n    private:\n        // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame;\n        // otherwise, _M_Frame will store all the callstack frames.\n        void* _M_SingleFrame;\n        std::vector<void *> _M_frames;\n    public:\n        _TaskCreationCallstack()\n        {\n            _M_SingleFrame = nullptr;\n        }\n\n        // Store one frame of callstack. This function works for both Debug / Release CRT.\n        static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame)\n        {\n            _TaskCreationCallstack _csc;\n            _csc._M_SingleFrame = _SingleFrame;\n            return _csc;\n        }\n\n        // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT.\n        __declspec(noinline)\n        static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames)\n        {\n            _TaskCreationCallstack _csc;\n            _csc._M_frames.resize(_CaptureFrames);\n            // skip 2 frames to make sure callstack starts from user code \n            _csc._M_frames.resize(::pplx::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames));\n            return _csc;\n        }\n    };\n    typedef unsigned char _Unit_type;\n\n    struct _TypeSelectorNoAsync {};\n    struct _TypeSelectorAsyncOperationOrTask {};\n    struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { };\n    struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { };\n    struct _TypeSelectorAsyncAction {};\n    struct _TypeSelectorAsyncActionWithProgress {};\n    struct _TypeSelectorAsyncOperationWithProgress {};\n\n    template<typename _Ty>\n    struct _NormalizeVoidToUnitType\n    {\n        typedef _Ty _Type;\n    };\n\n    template<>\n    struct _NormalizeVoidToUnitType<void>\n    {\n        typedef _Unit_type _Type;\n    };\n\n    template<typename _T>\n    struct _IsUnwrappedAsyncSelector\n    {\n        static const bool _Value = true;\n    };\n\n    template<>\n    struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync>\n    {\n        static const bool _Value = false;\n    };\n\n    template <typename _Ty>\n    struct _UnwrapTaskType\n    {\n        typedef _Ty _Type;\n    };\n\n    template <typename _Ty>\n    struct _UnwrapTaskType<task<_Ty>>\n    {\n        typedef _Ty _Type;\n    };\n\n    template <typename _T>\n    _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>);\n\n    _TypeSelectorNoAsync _AsyncOperationKindSelector(...);\n\n#if defined(__cplusplus_winrt)\n    template <typename _Type>\n    struct _Unhat\n    {\n        typedef _Type _Value;\n    };\n\n    template <typename _Type>\n    struct _Unhat<_Type^>\n    {\n        typedef _Type _Value;\n    };\n\n    value struct _NonUserType { public: int _Dummy; };\n\n    template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>\n    struct _ValueTypeOrRefType\n    {\n        typedef _NonUserType _Value;\n    };\n\n    template <typename _Type>\n    struct _ValueTypeOrRefType<_Type, true>\n    {\n        typedef _Type _Value;\n    };\n\n    template <typename _T1, typename _T2>\n    _T2 _ProgressTypeSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1,_T2>^);\n\n    template <typename _T1>\n    _T1 _ProgressTypeSelector(Windows::Foundation::IAsyncActionWithProgress<_T1>^);\n\n    template <typename _Type>\n    struct _GetProgressType\n    {\n        typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value;\n    };\n\n    template <typename _Type>\n    struct _IsIAsyncInfo\n    {\n        static const bool _Value = __is_base_of(Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value);\n    };\n\n    template <typename _T>\n    _TypeSelectorAsyncOperation _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperation<_T>^);\n\n    _TypeSelectorAsyncAction _AsyncOperationKindSelector(Windows::Foundation::IAsyncAction^);\n\n    template <typename _T1, typename _T2>\n    _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>^);\n\n    template <typename _T>\n    _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncActionWithProgress<_T>^);\n\n    template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value>\n    struct _TaskTypeTraits\n    {\n        typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;\n        typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;\n        typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;\n\n        static const bool _IsAsyncTask = _IsAsync;\n        static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;\n    };\n\n    template<typename _Type>\n    struct _TaskTypeTraits<_Type, true >\n    {\n        typedef decltype(((_Type)nullptr)->GetResults()) _TaskRetType;\n        typedef _TaskRetType _NormalizedTaskRetType;\n        typedef decltype(_AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind;\n\n        static const bool _IsAsyncTask = true;\n        static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;\n    };\n\n#else  /* defined (__cplusplus_winrt) */\n    template <typename _Type>\n    struct _IsIAsyncInfo\n    {\n        static const bool _Value = false;\n    };\n\n    template <typename _Type, bool _IsAsync = false>\n    struct _TaskTypeTraits\n    {\n        typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;\n        typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;\n        typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;\n\n        static const bool _IsAsyncTask = false;\n        static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;\n    };\n#endif  /* defined (__cplusplus_winrt) */\n\n    template <typename _Function> auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)(_Func); return std::true_type(); }\n    template <typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }\n\n    template <>\n    struct _TaskTypeTraits<void>\n    {\n        typedef void _TaskRetType;\n        typedef _TypeSelectorNoAsync _AsyncKind;\n        typedef _Unit_type _NormalizedTaskRetType;\n\n        static const bool _IsAsyncTask = false;\n        static const bool _IsUnwrappedTaskOrAsync = false;\n    };\n\n    template<typename _Type>\n    task<_Type> _To_task(_Type t);\n    \n    template<typename _Func>\n    task<void> _To_task_void(_Func f);\n    \n    struct _BadContinuationParamType{};\n\n    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)));\n    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t));\n    template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, ...) -> _BadContinuationParamType;\n\n    template <typename _Function, typename _Type> auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type());\n    template <typename _Function, typename _Type> std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...);\n\n    template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)));\n    template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func());\n\n    template <typename _Function> auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)), std::true_type());\n    template <typename _Function> std::false_type _VoidIsTaskHelper(_Function _Func, int, ...);\n\n    template<typename _Function, typename _ExpectedParameterType>\n    struct _FunctionTypeTraits\n    {\n        typedef decltype(_ReturnTypeHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _FuncRetType;\n        static_assert(!std::is_same<_FuncRetType,_BadContinuationParamType>::value, \"incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)\");\n\n        typedef decltype(_IsTaskHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _Takes_task;\n    };\n\n    template<typename _Function>\n    struct _FunctionTypeTraits<_Function, void>\n    {\n        typedef decltype(_VoidReturnTypeHelper(stdx::declval<_Function>(), 0, 0)) _FuncRetType;\n        typedef decltype(_VoidIsTaskHelper(stdx::declval<_Function>(), 0, 0)) _Takes_task;\n    };\n\n    template<typename _Function, typename _ReturnType>\n    struct _ContinuationTypeTraits\n    {\n        typedef task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType> _TaskOfType;\n    };\n\n    // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is\n    // declared, the constructor may or may not perform unwrapping. For eg.\n    //\n    //  This declaration SHOULD NOT cause unwrapping\n    //    task<task<void>> t1([]() -> task<void> {\n    //        task<void> t2([]() {});\n    //        return t2;\n    //    });\n    //\n    // This declaration SHOULD cause unwrapping\n    //    task<void>> t1([]() -> task<void> {\n    //        task<void> t2([]() {});\n    //        return t2;\n    //    });\n    // If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal rules apply.\n    template <typename _TaskType, typename _FuncRetType>\n    struct _InitFunctorTypeTraits\n    {\n        typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind;\n        static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask;\n        static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync;\n    };\n\n    template<typename T>\n    struct _InitFunctorTypeTraits<T, T>\n    {\n        typedef _TypeSelectorNoAsync _AsyncKind;\n        static const bool _IsAsyncTask = false;\n        static const bool _IsUnwrappedTaskOrAsync = false;\n    };\n\n    /// <summary>\n    ///     Helper object used for LWT invocation.\n    /// </summary>\n    struct _TaskProcThunk\n    {\n        _TaskProcThunk(const std::function<void ()> & _Callback) :\n            _M_func(_Callback)\n        {\n        }\n\n        static void _pplx_cdecl _Bridge(void *_PData)\n        {\n            _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData);\n            _Holder _ThunkHolder(_PThunk);\n            _PThunk->_M_func();\n        }\n    private:\n\n        // RAII holder\n        struct _Holder\n        {\n            _Holder(_TaskProcThunk * _PThunk) : _M_pThunk(_PThunk)\n            {\n            }\n\n            ~_Holder()\n            {\n                delete _M_pThunk;\n            }\n\n            _TaskProcThunk * _M_pThunk;\n\n        private:\n            _Holder& operator=(const _Holder&);\n        };\n\n        std::function<void()> _M_func;\n        _TaskProcThunk& operator=(const _TaskProcThunk&);\n    };\n\n    /// <summary>\n    ///     Schedule a functor with automatic inlining. Note that this is \"fire and forget\" scheduling, which cannot be\n    ///     waited on or canceled after scheduling.\n    ///     This schedule method will perform automatic inlining base on <paramref value=\"_InliningMode\"/>.\n    /// </summary>\n    /// <param name=\"_Func\">\n    ///     The user functor need to be scheduled.\n    /// </param>\n    /// <param name=\"_InliningMode\">\n    ///     The inlining scheduling policy for current functor.\n    /// </param>\n    static void _ScheduleFuncWithAutoInline(const std::function<void ()> & _Func, _TaskInliningMode_t _InliningMode)\n    {\n        _TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode);\n    }\n\n    class _ContextCallback\n    {\n        typedef std::function<void(void)> _CallbackFunction;\n\n#if defined (__cplusplus_winrt)\n\n    public:\n\n        static _ContextCallback _CaptureCurrent()\n        {\n            _ContextCallback _Context;\n            _Context._Capture();\n            return _Context;\n        }\n\n        ~_ContextCallback()\n        {\n            _Reset();\n        }\n\n        _ContextCallback(bool _DeferCapture = false)\n        {\n            if (_DeferCapture)\n            {\n                _M_context._M_captureMethod = _S_captureDeferred;\n            }\n            else\n            {\n                _M_context._M_pContextCallback = nullptr;\n            }\n        }\n\n        // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).\n        void _Resolve(bool _CaptureCurrent)\n        {\n            if(_M_context._M_captureMethod == _S_captureDeferred)\n            {\n                _M_context._M_pContextCallback = nullptr;\n\n                if (_CaptureCurrent)\n                {\n                    if (_IsCurrentOriginSTA())\n                    {\n                        _Capture();\n                    }\n#if _UITHREADCTXT_SUPPORT\n                    else\n                    {\n                        // This method will fail if not called from the UI thread.\n                        HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback);\n                        if (FAILED(_Hr))\n                        {\n                            _M_context._M_pContextCallback = nullptr;\n                        }\n                    }\n#endif  /* _UITHREADCTXT_SUPPORT */\n                }\n            }\n        }\n\n        void _Capture()\n        {\n            HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback));\n            if (FAILED(_Hr))\n            {\n                _M_context._M_pContextCallback = nullptr;\n            }\n        }\n\n        _ContextCallback(const _ContextCallback& _Src)\n        {\n            _Assign(_Src._M_context._M_pContextCallback);\n        }\n\n        _ContextCallback(_ContextCallback&& _Src)\n        {\n            _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;\n            _Src._M_context._M_pContextCallback = nullptr;\n        }\n\n        _ContextCallback& operator=(const _ContextCallback& _Src)\n        {\n            if (this != &_Src)\n            {\n                _Reset();\n                _Assign(_Src._M_context._M_pContextCallback);\n            }\n            return *this;\n        }\n\n        _ContextCallback& operator=(_ContextCallback&& _Src)\n        {\n            if (this != &_Src)\n            {\n                _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;\n                _Src._M_context._M_pContextCallback = nullptr;\n            }\n            return *this;\n        }\n\n        bool _HasCapturedContext() const\n        {\n            _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred);\n            return (_M_context._M_pContextCallback != nullptr);\n        }\n\n        void _CallInContext(_CallbackFunction _Func) const\n        {\n            if (!_HasCapturedContext())\n            {\n                _Func();\n            }\n            else\n            {\n                ComCallData callData;\n                ZeroMemory(&callData, sizeof(callData));\n                callData.pUserDefined = reinterpret_cast<void *>(&_Func);\n\n                HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);\n                if (FAILED(_Hr))\n                {\n                    throw ::Platform::Exception::CreateException(_Hr);\n                }\n            }\n        }\n\n        bool operator==(const _ContextCallback& _Rhs) const\n        {\n            return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback);\n        }\n\n        bool operator!=(const _ContextCallback& _Rhs) const\n        {\n            return !(operator==(_Rhs));\n        }\n\n    private:\n       void _Reset()\n        {\n            if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)\n            {\n                _M_context._M_pContextCallback->Release();\n            }\n        }\n\n        void _Assign(IContextCallback *_PContextCallback)\n        {\n            _M_context._M_pContextCallback = _PContextCallback;\n            if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)\n            {\n                _M_context._M_pContextCallback->AddRef();\n            }\n        }\n\n        static HRESULT __stdcall _Bridge(ComCallData *_PParam)\n        {\n            _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined);\n            (*pFunc)();\n            return S_OK;\n        }\n\n        // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)\n        static bool _IsCurrentOriginSTA()\n        {\n            APTTYPE _AptType;\n            APTTYPEQUALIFIER _AptTypeQualifier;\n\n            HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);\n            if (SUCCEEDED(hr))\n            {\n                // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether\n                // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in\n                // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,\n                // since variables used within a neutral apartment are expected to be apartment neutral.\n                switch(_AptType)\n                {\n                    case APTTYPE_MAINSTA:\n                    case APTTYPE_STA:\n                        return true;\n                    default:\n                        break;\n                }\n            }\n            return false;\n        }\n\n        union\n        {\n            IContextCallback *_M_pContextCallback;\n            size_t _M_captureMethod;\n        } _M_context;\n\n        static const size_t _S_captureDeferred = 1;\n#else  /* defined (__cplusplus_winrt) */\n    public:\n\n        static _ContextCallback _CaptureCurrent()\n        {\n            return _ContextCallback();\n        }\n\n        _ContextCallback(bool = false)\n        {\n        }\n\n        _ContextCallback(const _ContextCallback&)\n        {\n        }\n\n        _ContextCallback(_ContextCallback&&)\n        {\n        }\n\n        _ContextCallback& operator=(const _ContextCallback&)\n        {\n            return *this;\n        }\n\n        _ContextCallback& operator=(_ContextCallback&&)\n        {\n            return *this;\n        }\n\n        bool _HasCapturedContext() const\n        {\n            return false;\n        }\n\n        void _Resolve(bool) const\n        {\n        }\n\n        void _CallInContext(_CallbackFunction _Func) const\n        {\n            _Func();\n        }\n\n        bool operator==(const _ContextCallback&) const\n        {\n            return true;\n        }\n\n        bool operator!=(const _ContextCallback&) const\n        {\n            return false;\n        }\n\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n    template<typename _Type>\n    struct _ResultHolder\n    {\n        void Set(const _Type& _type)\n        {\n            _Result = _type;\n        }\n\n        _Type Get()\n        {\n            return _Result;\n        }\n\n        _Type _Result;\n    };\n\n#if defined (__cplusplus_winrt)\n\n    template<typename _Type>\n    struct _ResultHolder<_Type^>\n    {\n        void Set(_Type^ const & _type)\n        {\n           _M_Result = _type;\n        }\n\n        _Type^ Get()\n        {\n            return _M_Result.Get();\n        }\n    private:\n        // ::Platform::Agile handle specialization of all hats\n        // including ::Platform::String and ::Platform::Array\n        ::Platform::Agile<_Type^> _M_Result;\n    };\n\n    //\n    // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.\n    //\n    template<typename _Type>\n    struct _ResultHolder<std::vector<_Type^>>\n    {\n        void Set(const std::vector<_Type^>& _type)\n        {\n            _Result.reserve(_type.size());\n\n            for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask)\n            {\n                _Result.emplace_back(*_PTask);\n            }\n        }\n\n        std::vector<_Type^> Get()\n        {\n            // Return vectory<T^> with the objects that are marshaled in the proper appartment\n            std::vector<_Type^> _Return;\n            _Return.reserve(_Result.size());\n\n            for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask)\n            {\n                _Return.push_back(_PTask->Get()); // Platform::Agile will marshal the object to appropriate appartment if neccessary\n            }\n\n            return _Return;\n        }\n\n        std::vector< ::Platform::Agile<_Type^> > _Result;\n    };\n\n    template<typename _Type>\n    struct _ResultHolder<std::pair<_Type^, void*> >\n    {\n        void Set(const std::pair<_Type^, size_t>& _type)\n        {\n            _M_Result = _type;\n        }\n\n        std::pair<_Type^, size_t> Get()\n        {\n            return std::make_pair(_M_Result.first.Get(), _M_Result.second);\n        }\n    private:\n        std::pair< ::Platform::Agile<_Type^>, size_t> _M_Result;\n    };\n\n#endif  /* defined (__cplusplus_winrt) */\n\n    // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.\n    // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception\n    // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.\n    struct _ExceptionHolder\n    {\n    private:\n        void ReportUnhandledError()\n        {\n#if _MSC_VER >= 1800 && defined(__cplusplus_winrt)\n            if (_M_winRTException != nullptr)\n            {\n                ::Platform::Details::ReportUnhandledError(_M_winRTException);\n            }\n#endif  /* defined (__cplusplus_winrt) */\n        }\n    public:\n        explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack &_stackTrace) :\n        _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace)\n#if defined (__cplusplus_winrt)\n            , _M_winRTException(nullptr)\n#endif  /* defined (__cplusplus_winrt) */\n        {\n        }\n\n#if defined (__cplusplus_winrt)\n        explicit _ExceptionHolder(::Platform::Exception^ _E, const _TaskCreationCallstack &_stackTrace) :\n        _M_exceptionObserved(0),  _M_winRTException(_E), _M_stackTrace(_stackTrace)\n        {\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        __declspec(noinline)\n        ~_ExceptionHolder()\n        {\n            if (_M_exceptionObserved == 0)\n            {\n                // If you are trapped here, it means an exception thrown in task chain didn't get handled.\n                // Please add task-based continuation to handle all exceptions coming from tasks.\n                // this->_M_stackTrace keeps the creation callstack of the task generates this exception.\n                _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();\n            }\n        }\n\n        void _RethrowUserException()\n        {\n            if (_M_exceptionObserved == 0)\n            {\n                atomic_exchange(_M_exceptionObserved, 1l);\n            }\n\n#if defined (__cplusplus_winrt)\n            if (_M_winRTException != nullptr)\n            {\n                throw _M_winRTException;\n            }\n#endif  /* defined (__cplusplus_winrt) */\n            std::rethrow_exception(_M_stdException);\n        }\n\n        // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that\n        // are unobserved when the exception holder is destructed will terminate the process.\n        atomic_long _M_exceptionObserved;\n\n        // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.\n        std::exception_ptr _M_stdException;\n#if defined (__cplusplus_winrt)\n        ::Platform::Exception^ _M_winRTException;\n#endif  /* defined (__cplusplus_winrt) */\n\n        // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,\n        // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call\n        // is to task_completion_event::set_exception, the set_exception method was the source of the exception.\n        // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.\n        _TaskCreationCallstack _M_stackTrace;\n\n    };\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Base converter class for converting asynchronous interfaces to IAsyncOperation\n    /// </summary>\n    template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result>\n    ref struct _AsyncInfoImpl abstract : Windows::Foundation::IAsyncOperation<_Result>\n    {\n    internal:\n        // The async action, action with progress or operation with progress that this stub forwards to.\n        ::Platform::Agile<_AsyncOperationType> _M_asyncInfo;\n\n        Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ _M_CompletedHandler;\n\n        _AsyncInfoImpl( _AsyncOperationType _AsyncInfo ) : _M_asyncInfo(_AsyncInfo) {}\n\n    public:\n        virtual void Cancel() { _M_asyncInfo.Get()->Cancel(); }\n        virtual void Close() { _M_asyncInfo.Get()->Close(); }\n\n        virtual property Windows::Foundation::HResult ErrorCode\n        {\n            Windows::Foundation::HResult get()\n            {\n                return _M_asyncInfo.Get()->ErrorCode;\n            }\n        }\n\n        virtual property UINT Id\n        {\n            UINT get()\n            {\n                return _M_asyncInfo.Get()->Id;\n            }\n        }\n\n        virtual property Windows::Foundation::AsyncStatus Status\n        {\n            Windows::Foundation::AsyncStatus get()\n            {\n                return _M_asyncInfo.Get()->Status;\n            }\n        }\n\n        virtual _Result GetResults() { throw std::runtime_error(\"derived class must implement\"); }\n\n        virtual property Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ Completed\n        {\n            Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ get()\n            {\n                return _M_CompletedHandler;\n            }\n\n            void set(Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ value)\n            {\n                _M_CompletedHandler = value;\n                _M_asyncInfo.Get()->Completed = ref new _CompletionHandlerType([&](_AsyncOperationType, Windows::Foundation::AsyncStatus status) {\n                    _M_CompletedHandler->Invoke(this, status);\n                });\n            }\n        }\n    };\n\n    /// <summary>\n    ///     Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>\n    /// </summary>\n    template<typename _Result, typename _Progress>\n    ref struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed :\n        _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,\n                      Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,\n                      _Result>\n    {\n    internal:\n        _IAsyncOperationWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^ _Operation) :\n            _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,\n                          Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,\n                          _Result>(_Operation) {}\n\n    public:\n        virtual _Result GetResults() override { return _M_asyncInfo.Get()->GetResults(); }\n    };\n\n    /// <summary>\n    ///     Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type>\n    /// </summary>\n    ref struct _IAsyncActionToAsyncOperationConverter sealed :\n        _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,\n                      Windows::Foundation::AsyncActionCompletedHandler,\n                      details::_Unit_type>\n    {\n    internal:\n        _IAsyncActionToAsyncOperationConverter(Windows::Foundation::IAsyncAction^ _Operation) :\n            _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,\n                          Windows::Foundation::AsyncActionCompletedHandler,\n                          details::_Unit_type>(_Operation) {}\n\n    public:\n        virtual details::_Unit_type GetResults() override\n        {\n            // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.\n            _M_asyncInfo.Get()->GetResults();\n            return details::_Unit_type();\n        }\n    };\n\n    /// <summary>\n    ///     Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type>\n    /// </summary>\n    template<typename _Progress>\n    ref struct _IAsyncActionWithProgressToAsyncOperationConverter sealed :\n        _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,\n                      Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,\n                      details::_Unit_type>\n    {\n    internal:\n        _IAsyncActionWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ _Action) :\n            _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,\n                          Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,\n                          details::_Unit_type>(_Action) {}\n    public:\n        virtual details::_Unit_type GetResults() override\n        {\n            // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.\n            _M_asyncInfo.Get()->GetResults();\n            return details::_Unit_type();\n        }\n    };\n#endif  /* defined (__cplusplus_winrt) */\n} // namespace details\n\n/// <summary>\n///     The <c>task_continuation_context</c> class allows you to specify where you would like a continuation to be executed.\n///     It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's\n///     execution context is determined by the runtime, and not configurable.\n/// </summary>\n/// <seealso cref=\"task Class\"/>\n/**/\nclass task_continuation_context : public details::_ContextCallback\n{\npublic:\n\n    /// <summary>\n    ///     Creates the default task continuation context.\n    /// </summary>\n    /// <returns>\n    ///     The default continuation context.\n    /// </returns>\n    /// <remarks>\n    ///     The default context is used if you don't specifiy a continuation context when you call the <c>then</c> method. In Windows\n    ///     applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where\n    ///     task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an\n    ///     apartment aware task is the apartment where <c>then</c> is invoked.\n    ///     <para>An apartment aware task is a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such\n    ///     a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in\n    ///     that STA.</para>\n    ///     <para>A continuation on a non-apartment aware task will execute in a context the Runtime chooses.</para>\n    /// </remarks>\n    /**/\n    static task_continuation_context use_default()\n    {\n#if defined (__cplusplus_winrt)\n        // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()\n        return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle\n#else  /* defined (__cplusplus_winrt) */\n        return task_continuation_context();\n#endif  /* defined (__cplusplus_winrt) */\n    }\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Creates a task continuation context which allows the Runtime to choose the execution context for a continuation.\n    /// </summary>\n    /// <returns>\n    ///     A task continuation context that represents an arbitrary location.\n    /// </returns>\n    /// <remarks>\n    ///     When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task\n    ///     is apartment aware.\n    ///     <para><c>use_arbitrary</c> can be used to turn off the default behavior for a continuation on an apartment\n    ///     aware task created in an STA. </para>\n    ///     <para>This method is only available to Windows Store apps.</para>\n    /// </remarks>\n    /**/\n    static task_continuation_context use_arbitrary()\n    {\n        task_continuation_context _Arbitrary(true);\n        _Arbitrary._Resolve(false);\n        return _Arbitrary;\n    }\n\n    /// <summary>\n    ///     Returns a task continuation context object that represents the current execution context.\n    /// </summary>\n    /// <returns>\n    ///     The current execution context.\n    /// </returns>\n    /// <remarks>\n    ///     This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment.\n    ///     <para>The value returned by <c>use_current</c> can be used to indicate to the Runtime that the continuation should execute in\n    ///     the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is\n    ///     a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such a task. </para>\n    ///     <para>This method is only available to Windows Store apps.</para>\n    /// </remarks>\n    /**/\n    static task_continuation_context use_current()\n    {\n        task_continuation_context _Current(true);\n        _Current._Resolve(true);\n        return _Current;\n    }\n#endif  /* defined (__cplusplus_winrt) */\n\nprivate:\n\n    task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture)\n    {\n    }\n};\n\nclass task_options;\nnamespace details\n{\n    struct _Internal_task_options\n    {\n        bool _M_hasPresetCreationCallstack;\n        _TaskCreationCallstack _M_presetCreationCallstack;\n\n        void _set_creation_callstack(const _TaskCreationCallstack &_callstack)\n        {\n            _M_hasPresetCreationCallstack = true;\n            _M_presetCreationCallstack = _callstack;\n        }\n        _Internal_task_options()\n        {\n            _M_hasPresetCreationCallstack = false;\n        }\n    };\n\n    inline _Internal_task_options &_get_internal_task_options(task_options &options);\n    inline const _Internal_task_options &_get_internal_task_options(const task_options &options);\n}\n/// <summary>\n///     Represents the allowed options for creating a task\n/// </summary>\nclass task_options\n{\npublic:\n\n\n    /// <summary>\n    ///     Default list of task creation options\n    /// </summary>\n    task_options()\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a cancellation token\n    /// </summary>\n    task_options(cancellation_token _Token)\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(_Token),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(true),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a continuation context. This is valid only for continuations (then)\n    /// </summary>\n    task_options(task_continuation_context _ContinuationContext)\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(_ContinuationContext),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a cancellation token and a continuation context. This is valid only for continuations (then)\n    /// </summary>\n    task_options(cancellation_token _Token, task_continuation_context _ContinuationContext)\n        : _M_Scheduler(get_ambient_scheduler()),\n          _M_CancellationToken(_Token),\n          _M_ContinuationContext(_ContinuationContext),\n          _M_HasCancellationToken(true),\n          _M_HasScheduler(false)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a scheduler with shared lifetime\n    /// </summary>\n    template<typename _SchedType>\n    task_options(std::shared_ptr<_SchedType> _Scheduler)\n        : _M_Scheduler(std::move(_Scheduler)),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(true)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a scheduler reference\n    /// </summary>\n    task_options(scheduler_interface& _Scheduler)\n        : _M_Scheduler(&_Scheduler),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(true)\n    {\n    }\n\n    /// <summary>\n    ///     Task option that specify a scheduler\n    /// </summary>\n    task_options(scheduler_ptr _Scheduler)\n        : _M_Scheduler(std::move(_Scheduler)),\n          _M_CancellationToken(cancellation_token::none()),\n          _M_ContinuationContext(task_continuation_context::use_default()),\n          _M_HasCancellationToken(false),\n          _M_HasScheduler(true)\n    {\n    }\n\n    /// <summary>\n    ///     Task option copy constructor\n    /// </summary>\n    task_options(const task_options& _TaskOptions)\n        : _M_Scheduler(_TaskOptions.get_scheduler()),\n          _M_CancellationToken(_TaskOptions.get_cancellation_token()),\n          _M_ContinuationContext(_TaskOptions.get_continuation_context()),\n          _M_HasCancellationToken(_TaskOptions.has_cancellation_token()),\n          _M_HasScheduler(_TaskOptions.has_scheduler())        \n    {\n    }\n\n    /// <summary>\n    ///     Sets the given token in the options\n    /// </summary>\n    void set_cancellation_token(cancellation_token _Token)\n    {\n        _M_CancellationToken = _Token;\n       _M_HasCancellationToken = true;\n    }\n\n    /// <summary>\n    ///     Sets the given continuation context in the options\n    /// </summary>\n    void set_continuation_context(task_continuation_context _ContinuationContext)\n    {\n        _M_ContinuationContext = _ContinuationContext;\n    }\n\n    /// <summary>\n    ///     Indicates whether a cancellation token was specified by the user\n    /// </summary>\n    bool has_cancellation_token() const\n    {\n        return _M_HasCancellationToken;\n    }\n\n    /// <summary>\n    ///     Returns the cancellation token\n    /// </summary>\n    cancellation_token get_cancellation_token() const\n    {\n        return _M_CancellationToken;\n    }\n\n    /// <summary>\n    ///     Returns the continuation context\n    /// </summary>\n    task_continuation_context get_continuation_context() const\n    {\n        return _M_ContinuationContext;\n    }\n\n    /// <summary>\n    ///     Indicates whether a scheduler n was specified by the user\n    /// </summary>\n    bool has_scheduler() const\n    {\n        return _M_HasScheduler;\n    }\n\n    /// <summary>\n    ///     Returns the scheduler\n    /// </summary>\n    scheduler_ptr get_scheduler() const\n    {\n        return _M_Scheduler;\n    }\n\nprivate:\n\n    task_options const& operator=(task_options const& _Right);\n    friend details::_Internal_task_options &details::_get_internal_task_options(task_options &);\n    friend const details::_Internal_task_options &details::_get_internal_task_options(const task_options &);\n\n    scheduler_ptr _M_Scheduler;\n    cancellation_token _M_CancellationToken;\n    task_continuation_context _M_ContinuationContext;\n    details::_Internal_task_options _M_InternalTaskOptions;\n    bool _M_HasCancellationToken;\n    bool _M_HasScheduler;\n};\n\nnamespace details\n{\n    inline _Internal_task_options & _get_internal_task_options(task_options &options)\n    {\n        return options._M_InternalTaskOptions;\n    }\n    inline const _Internal_task_options & _get_internal_task_options(const task_options &options)\n    {\n        return options._M_InternalTaskOptions;\n    }\n\n    struct _Task_impl_base;\n    template<typename _ReturnType> struct _Task_impl;\n\n    template<typename _ReturnType>\n    struct _Task_ptr\n    {\n        typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type;\n        static _Type _Make(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); }\n    };\n\n    typedef _TaskCollection_t::_TaskProcHandle_t _UnrealizedChore_t;\n    typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base;\n\n    // The weak-typed base task handler for continuation tasks.\n    struct _ContinuationTaskHandleBase : _UnrealizedChore_t\n    {\n        _ContinuationTaskHandleBase * _M_next;\n        task_continuation_context _M_continuationContext;\n        bool _M_isTaskBasedContinuation;\n\n        // This field gives inlining scheduling policy for current chore.\n        _TaskInliningMode_t _M_inliningMode;\n        \n        virtual _Task_ptr_base _GetTaskImplBase() const = 0;\n\n        _ContinuationTaskHandleBase() : \n            _M_next(nullptr), _M_continuationContext(task_continuation_context::use_default()), _M_isTaskBasedContinuation(false), _M_inliningMode(details::_NoInline)\n        {\n        }\n\n        virtual ~_ContinuationTaskHandleBase() {}\n    };\n\n#if _PPLTASK_ASYNC_LOGGING\n    // GUID used for identifying causality logs from PPLTask\n    const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE);\n\n    __declspec(selectany) volatile long _isCausalitySupported = 0;\n\n    inline bool _IsCausalitySupported()\n    {\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)\n        if (_isCausalitySupported == 0)\n        {\n            long _causality = 1;\n            OSVERSIONINFOEX _osvi = {};\n            _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\n\n            // The Causality is supported on Windows version higher than Windows 8\n            _osvi.dwMajorVersion = 6;\n            _osvi.dwMinorVersion = 3;\n\n            DWORDLONG _conditionMask = 0;\n            VER_SET_CONDITION( _conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );\n            VER_SET_CONDITION( _conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );\n\n            if ( ::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask)) \n            {\n                _causality = 2;\n            }\n\n            _isCausalitySupported = _causality;\n            return _causality == 2;\n        }\n\n        return _isCausalitySupported == 2 ? true : false;\n#else\n        return true;\n#endif\n    }\n\n    // Stateful logger rests inside task_impl_base. \n    struct _TaskEventLogger\n    {\n        _Task_impl_base *_M_task;\n        bool _M_scheduled;\n        bool _M_taskPostEventStarted;\n\n        // Log before scheduling task\n        void _LogScheduleTask(bool _isContinuation)\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, \n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), \n                    _isContinuation ? \"pplx::PPLTask::ScheduleContinuationTask\" : \"pplx::PPLTask::ScheduleTask\", 0);\n                _M_scheduled = true;\n            } \n        }\n\n        // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state.\n        void _LogCancelTask()\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel);\n\n            } \n        }\n\n        // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run\n        void _LogTaskCompleted();\n\n        // Log when task body (which includes user lambda and other scheduling code) begin to run\n        void _LogTaskExecutionStarted() { }\n\n        // Log when task body finish executing\n        void _LogTaskExecutionCompleted()\n        {\n            if (_M_taskPostEventStarted && details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);\n            }\n        }\n\n        // Log right before user lambda being invoked\n        void _LogWorkItemStarted()\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);\n            }\n        }\n\n        // Log right after user lambda being invoked\n        void _LogWorkItemCompleted()\n        {\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);\n\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);\n                _M_taskPostEventStarted = true;\n            }\n        }\n        \n        _TaskEventLogger(_Task_impl_base *_task): _M_task(_task)\n        {\n            _M_scheduled = false;\n            _M_taskPostEventStarted = false;\n        }\n    };\n\n    // Exception safe logger for user lambda\n    struct _TaskWorkItemRAIILogger\n    {\n        _TaskEventLogger &_M_logger;\n        _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger): _M_logger(_taskHandleLogger)\n        {\n            _M_logger._LogWorkItemStarted();\n        }\n\n        ~_TaskWorkItemRAIILogger()\n        {\n            _M_logger._LogWorkItemCompleted();\n        }\n        _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned\n    };\n\n#else\n    inline void _LogCancelTask(_Task_impl_base *) {}\n    struct _TaskEventLogger\n    {\n        void _LogScheduleTask(bool) {}\n        void _LogCancelTask() {}\n        void _LogWorkItemStarted() {}\n        void _LogWorkItemCompleted() {}\n        void _LogTaskExecutionStarted() {}\n        void _LogTaskExecutionCompleted() {}\n        void _LogTaskCompleted() {}\n        _TaskEventLogger(_Task_impl_base *) {}\n    };\n    struct _TaskWorkItemRAIILogger\n    {\n        _TaskWorkItemRAIILogger(_TaskEventLogger &) {}\n    };\n#endif\n\n    /// <summary>\n    ///     The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler\n    ///     to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks.\n    ///     For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore_t, and for continuation tasks, it will be derived from\n    ///     _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled.\n    /// </summary>\n    /// <typeparam name=\"_ReturnType\">\n    ///     The result type of the _Task_impl.\n    /// </typeparam>\n    /// <typeparam name=\"_DerivedTaskHandle\">\n    ///     The derived task handle class. The <c>operator ()</c> needs to be implemented.\n    /// </typeparam>\n    /// <typeparam name=\"_BaseTaskHandle\">\n    ///     The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore_t or _ContinuationTaskHandleBase.\n    /// </typeparam>\n    template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle>\n    struct _PPLTaskHandle : _BaseTaskHandle\n    {\n        _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask)\n        {\n        }\n\n        virtual ~_PPLTaskHandle() \n        {\n            // Here is the sink of all task completion code paths\n            _M_pTask->_M_taskEventLogger._LogTaskCompleted();\n        }\n\n        virtual void invoke() const\n        {\n            // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled\n            // by the runtime.\n            _ASSERTE((bool)_M_pTask);\n            if (!_M_pTask->_TransitionedToStarted())\n            {\n                static_cast<const _DerivedTaskHandle *>(this)->_SyncCancelAndPropagateException();\n                return;\n            }\n\n            _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted();\n            try\n            {\n                // All derived task handle must implement this contract function.\n                static_cast<const _DerivedTaskHandle *>(this)->_Perform();\n            }\n            catch(const task_canceled &)\n            {\n                _M_pTask->_Cancel(true);\n            }\n            catch(const _Interruption_exception &)\n            {\n                _M_pTask->_Cancel(true);\n            }\n#if defined (__cplusplus_winrt)\n            catch(::Platform::Exception^ _E)\n            {\n                _M_pTask->_CancelWithException(_E);\n            }\n#endif  /* defined (__cplusplus_winrt) */\n            catch(...)\n            {\n                _M_pTask->_CancelWithException(std::current_exception());\n            }\n            _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted();\n        }\n\n        // Cast _M_pTask pointer to \"type-less\" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.\n        // The return value should be automatically optimized by R-value ref.\n        _Task_ptr_base _GetTaskImplBase() const\n        {\n            return _M_pTask;\n        }\n\n        typename _Task_ptr<_ReturnType>::_Type _M_pTask;\n    private:\n        _PPLTaskHandle const & operator=(_PPLTaskHandle const&);    // no assignment operator\n    };\n\n    /// <summary>\n    ///     The base implementation of a first-class task. This class contains all the non-type specific\n    ///     implementation details of the task.\n    /// </summary>\n    /**/\n    struct _Task_impl_base\n    {\n        enum _TaskInternalState\n        {\n            // Tracks the state of the task, rather than the task collection on which the task is scheduled\n            _Created,\n            _Started,\n            _PendingCancel,\n            _Completed,\n            _Canceled\n        };\n// _M_taskEventLogger - 'this' : used in base member initializer list\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 4355)\n#endif\n        _Task_impl_base(_CancellationTokenState * _PTokenState, scheduler_ptr _Scheduler_arg) \n                          : _M_TaskState(_Created),\n                            _M_fFromAsync(false), _M_fUnwrappedTask(false),\n                            _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg),\n                            _M_taskEventLogger(this)                           \n        {\n            // Set cancelation token\n            _M_pTokenState = _PTokenState;\n            _ASSERTE(_M_pTokenState != nullptr);\n            if (_M_pTokenState != _CancellationTokenState::_None())\n                _M_pTokenState->_Reference();\n        }\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n        virtual ~_Task_impl_base()\n        {\n            _ASSERTE(_M_pTokenState != nullptr);\n            if (_M_pTokenState != _CancellationTokenState::_None())\n            {\n                _M_pTokenState->_Release();\n            }\n        }\n\n        task_status _Wait()\n        {\n            bool _DoWait = true;\n\n#if defined (__cplusplus_winrt)\n            if (_IsNonBlockingThread())\n            {\n                // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal\n                // if task has not been completed.\n                if (!_IsCompleted() && !_IsCanceled())\n                {\n                    throw invalid_operation(\"Illegal to wait on a task in a Windows Runtime STA\");\n                }\n                else\n                {\n                    // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation\n                    // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM\n                    // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which\n                    // task based continuations are wont to do), waiting on the task group results in on the chore that is making this\n                    // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on\n                    // if it has finished execution (which means now we are on the inline synchronous callback).\n                    _DoWait = false;\n                }\n            }\n#endif  /* defined (__cplusplus_winrt) */\n            if (_DoWait)\n            {\n                // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The\n                // async operation will take place on a thread in the appropriate apartment Simply wait for the completed\n                // event to be set.\n                if (_M_fFromAsync)\n                {\n                    _M_TaskCollection._Wait();\n                }\n                else\n                {\n                    // Wait on the task collection to complete. The task collection is guaranteed to still be\n                    // valid since the task must be still within scope so that the _Task_impl_base destructor\n                    // has not yet been called. This call to _Wait potentially inlines execution of work.\n                    try\n                    {\n                        // Invoking wait on a task collection resets the state of the task collection. This means that\n                        // if the task collection itself were canceled, or had encountered an exception, only the first\n                        // call to wait will receive this status. However, both cancellation and exceptions flowing through\n                        // tasks set state in the task impl itself.\n\n                        // When it returns cancelled, either work chore or the cancel thread should already have set task's state\n                        // properly -- cancelled state or completed state (because there was no interruption point).\n                        // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.\n                        _M_TaskCollection._RunAndWait();\n                    }\n                    catch(details::_Interruption_exception&)\n                    {\n                        // The _TaskCollection will never be an interruption point since it has a none token.\n                        _ASSERTE(false);\n                    }\n                    catch(task_canceled&)\n                    {\n                        // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task\n                        // must be called from code that is executed within the task (throwing it from parallel work created by and waited\n                        // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen\n                        // the exception and canceled the task. Swallow the exception here.\n                        _ASSERTE(_IsCanceled());\n                    }\n#if defined (__cplusplus_winrt)\n                    catch(::Platform::Exception^ _E)\n                    {\n                        // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.\n                        if(!_HasUserException())\n                        {\n                            _CancelWithException(_E);\n                        }\n                        // Rethrow will mark the exception as observed.\n                        _M_exceptionHolder->_RethrowUserException();\n                    }\n#endif  /* defined (__cplusplus_winrt) */\n                    catch(...)\n                    {\n                        // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.\n                        if(!_HasUserException())\n                        {\n                            _CancelWithException(std::current_exception());\n                        }\n                        // Rethrow will mark the exception as observed.\n                        _M_exceptionHolder->_RethrowUserException();\n                    }\n\n                    // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task\n                    // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must\n                    // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;\n                    // however, this takes the tact of simply waiting upon the completion signal.\n                    if (_M_fUnwrappedTask)\n                    {\n                        _M_TaskCollection._Wait();\n                    }\n                }\n            }\n\n            if (_HasUserException())\n            {\n                _M_exceptionHolder->_RethrowUserException();\n            }\n            else if (_IsCanceled())\n            {\n                return canceled;\n            }\n            _ASSERTE(_IsCompleted());\n            return completed;\n        }\n\n        /// <summary>\n        ///     Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state.\n        /// </summary>\n        /// <param name=\"_SynchronousCancel\">\n        ///     Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task\n        ///     was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at\n        ///     the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could\n        ///     be executing the task, that is the task could execute concurrently while the cancellation is in progress.\n        /// </param>\n        /// <param name=\"_UserException\">\n        ///     Whether an exception other than the internal runtime cancellation exceptions caused this cancellation.\n        /// </param>\n        /// <param name=\"_PropagatedFromAncestor\">\n        ///     Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when\n        ///     _UserException is set to true.\n        /// </param>\n        /// <param name=\"_ExHolder\">\n        ///     The exception holder that represents the exception. Only valid when _UserException is set to true.\n        /// </param>\n        virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0;\n\n        bool _Cancel(bool _SynchronousCancel)\n        {\n            // Send in a dummy value for exception. It is not used when the first parameter is false.\n            return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder);\n        }\n\n        bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor)\n        {\n            // This task was canceled because an ancestor task encountered an exception.\n            return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder);\n        }\n\n#if defined (__cplusplus_winrt)\n        bool _CancelWithException(::Platform::Exception^ _Exception)\n        {\n            // This task was canceled because the task body encountered an exception.\n            _ASSERTE(!_HasUserException());\n            return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        bool _CancelWithException(const std::exception_ptr& _Exception)\n        {\n            // This task was canceled because the task body encountered an exception.\n            _ASSERTE(!_HasUserException());\n            return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));\n        }\n\n        void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr)\n        {\n            _ASSERTE(details::_CancellationTokenState::_IsValid(_M_pTokenState));\n\n            auto _CancellationCallback = [_WeakPtr](){\n                // Taking ownership of the task prevents dead lock during destruction\n                // if the destructor waits for the cancellations to be finished\n                auto _task = _WeakPtr.lock();\n                if (_task != nullptr)\n                    _task->_Cancel(false);\n            };\n\n            _M_pRegistration = new details::_CancellationTokenCallback<decltype(_CancellationCallback)>(_CancellationCallback);\n            _M_pTokenState->_RegisterCallback(_M_pRegistration);\n        }\n\n        void _DeregisterCancellation()\n        {\n            if (_M_pRegistration != nullptr)\n            {\n                _M_pTokenState->_DeregisterCallback(_M_pRegistration);\n                _M_pRegistration->_Release();\n                _M_pRegistration = nullptr;\n            }\n        }\n\n        bool _IsCreated()\n        {\n            return (_M_TaskState == _Created);\n        }\n\n        bool _IsStarted()\n        {\n            return (_M_TaskState == _Started);\n        }\n\n        bool _IsPendingCancel()\n        {\n            return (_M_TaskState == _PendingCancel);\n        }\n\n        bool _IsCompleted()\n        {\n            return (_M_TaskState == _Completed);\n        }\n\n        bool _IsCanceled()\n        {\n            return (_M_TaskState == _Canceled);\n        }\n\n        bool _HasUserException()\n        {\n            return static_cast<bool>(_M_exceptionHolder);\n        }\n\n        const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder()\n        {\n            _ASSERTE(_HasUserException());\n            return _M_exceptionHolder;\n        }\n\n        bool _IsApartmentAware()\n        {\n            return _M_fFromAsync;\n        }\n\n        void _SetAsync(bool _Async = true)\n        {\n            _M_fFromAsync = _Async;\n        }\n\n        _TaskCreationCallstack _GetTaskCreationCallstack()\n        {\n            return _M_pTaskCreationCallstack;\n        }\n\n        void _SetTaskCreationCallstack(const _TaskCreationCallstack &_Callstack)\n        {\n            _M_pTaskCreationCallstack = _Callstack;\n        }\n\n        /// <summary>\n        ///     Helper function to schedule the task on the Task Collection.\n        /// </summary>\n        /// <param name=\"_PTaskHandle\">\n        ///     The task chore handle that need to be executed.\n        /// </param>\n        /// <param name=\"_InliningMode\">\n        ///     The inlining scheduling policy for current _PTaskHandle.\n        /// </param>\n        void _ScheduleTask(_UnrealizedChore_t * _PTaskHandle, _TaskInliningMode_t _InliningMode)\n        {\n            try\n            {\n                _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode);\n            }\n            catch(const task_canceled &)\n            {\n                // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task\n                // must be called from code that is executed within the task (throwing it from parallel work created by and waited\n                // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen\n                // the exception and canceled the task. Swallow the exception here.\n                _ASSERTE(_IsCanceled());\n            }\n            catch(const _Interruption_exception &)\n            {\n                // The _TaskCollection will never be an interruption point since it has a none token.\n                _ASSERTE(false);\n            }\n            catch(...)\n            {\n                // The exception could have come from two places:\n                //   1. From the chore body, so it already should have been caught and canceled.\n                //      In this case swallow the exception.\n                //   2. From trying to actually schedule the task on the scheduler.\n                //      In this case cancel the task with the current exception, otherwise the\n                //      task will never be signaled leading to deadlock when waiting on the task.\n                if (!_HasUserException())\n                {\n                    _CancelWithException(std::current_exception());\n                }\n            }\n        }\n\n        /// <summary>\n        ///     Function executes a continuation. This function is recorded by a parent task implementation\n        ///     when a continuation is created in order to execute later.\n        /// </summary>\n        /// <param name=\"_PTaskHandle\">\n        ///     The continuation task chore handle that need to be executed.\n        /// </param>\n        /**/\n        void _RunContinuation(_ContinuationTaskHandleBase * _PTaskHandle)\n        {\n            _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase();\n            if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation)\n            {\n                if (_HasUserException())\n                {\n                    // If the ancestor encountered an exception, transfer the exception to the continuation\n                    // This traverses down the tree to propagate the exception.\n                    _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true);\n                }\n                else\n                {\n                    // If the ancestor was canceled, then your own execution should be canceled.\n                    // This traverses down the tree to cancel it.\n                    _ImplBase->_Cancel(true);\n                }\n            }\n            else\n            {\n                // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled\n                // (with or without a user exception).\n                _ASSERTE(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation);\n                _ASSERTE(!_ImplBase->_IsCanceled());\n                return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);\n            }\n\n            // If the handle is not scheduled, we need to manually delete it.\n            delete _PTaskHandle;\n        }\n\n        // Schedule a continuation to run\n        void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle)\n        {\n            \n            _M_taskEventLogger._LogScheduleTask(true);\n            // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)\n            if (_PTaskHandle->_M_continuationContext._HasCapturedContext())\n            {\n                // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,\n                // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce\n                // the cost of marshaling.\n                // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.\n                if (_PTaskHandle->_M_inliningMode != details::_ForceInline)\n                {\n                    _PTaskHandle->_M_inliningMode = details::_DefaultAutoInline;\n                }\n                _ScheduleFuncWithAutoInline([_PTaskHandle]() {\n                    // Note that we cannot directly capture \"this\" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.\n                    // Because \"this\" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.\n                    auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase();\n                    if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext)\n                    {\n                        _TaskImplPtr->_ScheduleTask(_PTaskHandle, details::_ForceInline);\n                    }\n                    else\n                    {\n                        //\n                        // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle\n                        // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:\n                        //\n                        // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into\n                        // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will\n                        // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).\n                        //\n                        try\n                        {\n                            // Dev10 compiler needs this!\n                            auto _PTaskHandle1 = _PTaskHandle;\n                            _PTaskHandle->_M_continuationContext._CallInContext( [_PTaskHandle1, _TaskImplPtr](){\n                                _TaskImplPtr->_ScheduleTask(_PTaskHandle1, details::_ForceInline);\n                            });\n                        }\n#if defined (__cplusplus_winrt)\n                        catch(::Platform::Exception^ _E)\n                        {\n                            _TaskImplPtr->_CancelWithException(_E);\n                        }\n#endif  /* defined (__cplusplus_winrt) */\n                        catch(...)\n                        {\n                            _TaskImplPtr->_CancelWithException(std::current_exception());\n                        }\n                    }\n                }, _PTaskHandle->_M_inliningMode);\n            }\n            else\n            {\n                _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode);\n            }\n        }\n\n        /// <summary>\n        ///     Schedule the actual continuation. This will either schedule the function on the continuation task's implementation\n        ///     if the task has completed or append it to a list of functions to execute when the task actually does complete.\n        /// </summary>\n        /// <typeparam name=\"_FuncInputType\">\n        ///     The input type of the task.\n        /// </typeparam>\n        /// <typeparam name=\"_FuncOutputType\">\n        ///     The output type of the task.\n        /// </typeparam>\n        /**/\n        void _ScheduleContinuation(_ContinuationTaskHandleBase * _PTaskHandle)\n        {\n            enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing;\n\n            // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.\n            // Otherwise, add it to the list of pending continuations\n            {\n                ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n                if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))\n                {\n                    _Do = _Schedule;\n                }\n                else if (_IsCanceled())\n                {\n                    if (_HasUserException())\n                    {\n                        _Do = _CancelWithException;\n                    }\n                    else\n                    {\n                        _Do = _Cancel;\n                    }\n                }\n                else\n                {\n                    // chain itself on the continuation chain.\n                    _PTaskHandle->_M_next = _M_Continuations;\n                    _M_Continuations = _PTaskHandle;\n                }\n            }\n\n            // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of\n            // async tasks may execute inline.\n            switch (_Do)\n            {\n                case _Schedule:\n                {\n                    _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle);\n                    break;\n                }\n                case _Cancel:\n                {\n                    // If the ancestor was canceled, then your own execution should be canceled.\n                    // This traverses down the tree to cancel it.\n                    _PTaskHandle->_GetTaskImplBase()->_Cancel(true);\n\n                    delete _PTaskHandle;\n                    break;\n                }\n                case _CancelWithException:\n                {\n                    // If the ancestor encountered an exception, transfer the exception to the continuation\n                    // This traverses down the tree to propagate the exception.\n                    _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true);\n\n                    delete _PTaskHandle;\n                    break;\n                }\n                case _Nothing:\n                default:\n                    // In this case, we have inserted continuation to continuation chain,\n                    // nothing more need to be done, just leave.\n                    break;\n            }\n        }\n\n        void _RunTaskContinuations()\n        {\n            // The link list can no longer be modified at this point,\n            // since all following up continuations will be scheduled by themselves.\n            _ContinuationList _Cur = _M_Continuations, _Next;\n            _M_Continuations = nullptr;\n            while (_Cur)\n            {\n                // Current node might be deleted after running,\n                // so we must fetch the next first.\n                _Next = _Cur->_M_next;\n                _RunContinuation(_Cur);\n                _Cur = _Next;\n            }\n        }\n\n#if defined (__cplusplus_winrt)\n        static bool  _IsNonBlockingThread()\n        {\n            APTTYPE _AptType;\n            APTTYPEQUALIFIER _AptTypeQualifier;\n\n            HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);\n            //\n            // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.\n            //\n            if (SUCCEEDED(hr))\n            {\n                switch(_AptType)\n                {\n                case APTTYPE_STA:\n                case APTTYPE_MAINSTA:\n                    return true;\n                    break;\n                case APTTYPE_NA:\n                    switch(_AptTypeQualifier)\n                    {\n                    // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed\n                    // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting\n                    // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the\n                    // thread out of circulation for a while.\n                    case APTTYPEQUALIFIER_NA_ON_STA:\n                    case APTTYPEQUALIFIER_NA_ON_MAINSTA:\n                        return true;\n                        break;\n                    }\n                    break;\n                }\n            }\n\n#if _UITHREADCTXT_SUPPORT\n            // This method is used to throw an exepection in _Wait() if called within STA.  We\n            // want the same behavior if _Wait is called on the UI thread.\n            if (SUCCEEDED(CaptureUiThreadContext(nullptr)))\n            {\n                return true;\n            }\n#endif  /* _UITHREADCTXT_SUPPORT */\n\n            return false;\n        }\n\n        template<typename _ReturnType, typename>\n        static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask,\n                               Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)\n        {\n            // This method is invoked either when a task is created from an existing async operation or\n            // when a lambda that creates an async operation executes.\n\n            // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on\n            // the IAsyncInfo object will be released when all ^references to the operation go out of scope.\n\n            // This assertion uses the existence of taskcollection to determine if the task was created from an event.\n            // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection\n            // when a custom scheduler is used.\n            // _ASSERTE((!_OuterTask->_M_TaskCollection._IsCreated() || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled());\n\n            // Pass the shared_ptr by value into the lambda instead of using 'this'.\n            _AsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType>(\n              [_OuterTask](Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _Operation, Windows::Foundation::AsyncStatus _Status) mutable\n            {\n                if (_Status == Windows::Foundation::AsyncStatus::Canceled)\n                {\n                    _OuterTask->_Cancel(true);\n                }\n                else if (_Status == Windows::Foundation::AsyncStatus::Error)\n                {\n                    _OuterTask->_CancelWithException(::Platform::Exception::ReCreateException(static_cast<int>(_Operation->ErrorCode.Value)));\n                }\n                else\n                {\n                    _ASSERTE(_Status == Windows::Foundation::AsyncStatus::Completed);\n                    _OuterTask->_FinalizeAndRunContinuations(_Operation->GetResults());\n                }\n\n                // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could\n                // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold\n                // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from\n                // it using the Windows Runtime Async APIs causes a sharing violation.\n                // Using const_cast is the workaround for failed mutable keywords\n                const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset();\n             });\n            _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        template<typename _ReturnType, typename _InternalReturnType>\n        static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask)\n        {\n            _ASSERTE(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled());\n                       \n            //\n            // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the\n            // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation\n            // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent\n            // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless\n            // of whether or not the _OuterTask task is canceled.\n            //\n            _UnwrappedTask._Then([_OuterTask] (task<_InternalReturnType> _AncestorTask) {\n\n                if (_AncestorTask._GetImpl()->_IsCompleted())\n                {\n                    _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult());\n                }\n                else\n                {\n                    _ASSERTE(_AncestorTask._GetImpl()->_IsCanceled());\n                    if (_AncestorTask._GetImpl()->_HasUserException())\n                    {\n                        // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.\n                        // Instead, it is the enclosing task.\n                        _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false);\n                    }\n                    else\n                    {\n                        _OuterTask->_Cancel(true);\n                    }\n                }\n            }, nullptr, details::_DefaultAutoInline);\n\n        }\n\n        scheduler_ptr _GetScheduler() const\n        {\n            return _M_TaskCollection._GetScheduler();\n        }\n\n        // Tracks the internal state of the task\n        volatile _TaskInternalState _M_TaskState;\n        // Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this task returns an\n        // async operation or async action that is unwrapped by the runtime.\n        bool _M_fFromAsync;\n        // Set to true when a continuation unwraps a task or async operation.\n        bool _M_fUnwrappedTask;\n\n        // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.\n        // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception\n        // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.\n        std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;\n\n        ::pplx::extensibility::critical_section_t _M_ContinuationsCritSec;\n\n        // The cancellation token state.\n        _CancellationTokenState * _M_pTokenState;\n\n        // The registration on the token.\n        _CancellationTokenRegistration * _M_pRegistration;\n\n        typedef _ContinuationTaskHandleBase * _ContinuationList;\n        _ContinuationList _M_Continuations;\n\n        // The async task collection wrapper\n        ::pplx::details::_TaskCollection_t _M_TaskCollection;\n\n        // Callstack for function call (constructor or .then) that created this task impl.\n        _TaskCreationCallstack _M_pTaskCreationCallstack;\n\n        _TaskEventLogger _M_taskEventLogger;\n   private:\n        // Must not be copied by value:\n        _Task_impl_base(const _Task_impl_base&);\n        _Task_impl_base const & operator=(_Task_impl_base const&);\n    };\n\n#if _PPLTASK_ASYNC_LOGGING\n    inline void _TaskEventLogger::_LogTaskCompleted()\n    {\n        if (_M_scheduled)\n        {\n            ::Windows::Foundation::AsyncStatus _State;\n            if (_M_task->_IsCompleted())\n                _State = ::Windows::Foundation::AsyncStatus::Completed;\n            else if (_M_task->_HasUserException())\n                _State = ::Windows::Foundation::AsyncStatus::Error;\n            else\n                _State = ::Windows::Foundation::AsyncStatus::Canceled;\n\n            if (details::_IsCausalitySupported())\n            {\n                ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,\n                    _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), _State);\n            }\n        }\n    }\n#endif\n    \n    /// <summary>\n    ///     The implementation of a first-class task. This structure contains the task group used to execute\n    ///     the task function and handles the scheduling. The _Task_impl is created as a shared_ptr\n    ///     member of the the public task class, so its destruction is handled automatically.\n    /// </summary>\n    /// <typeparam name=\"_ReturnType\">\n    ///     The result type of this task.\n    /// </typeparam>\n    /**/\n    template<typename _ReturnType>\n    struct _Task_impl : public _Task_impl_base\n    {\n#if defined (__cplusplus_winrt)\n        typedef Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value> _AsyncOperationType;\n#endif // defined(__cplusplus_winrt)\n        _Task_impl(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg)\n            : _Task_impl_base(_Ct, _Scheduler_arg)\n        {\n#if defined (__cplusplus_winrt)\n            _M_unwrapped_async_op = nullptr;\n#endif  /* defined (__cplusplus_winrt) */\n        }\n\n        virtual ~_Task_impl()\n        {\n            // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause\n            // a partially initialized _Task_impl to be in the list of registrations for a cancellation token.\n            _DeregisterCancellation();\n        }\n\n        virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder_arg)\n        {\n            bool _RunContinuations = false;\n            {\n                ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n                if (_UserException)\n                {\n                    _ASSERTE(_SynchronousCancel && !_IsCompleted());\n                    // If the state is _Canceled, the exception has to be coming from an ancestor.\n                    _ASSERTE(!_IsCanceled() || _PropagatedFromAncestor);\n\n                    // We should not be canceled with an exception more than once.\n                    _ASSERTE(!_HasUserException());\n\n                    // Mark _PropagatedFromAncestor as used.\n                    (void)_PropagatedFromAncestor;\n\n                    if (_M_TaskState == _Canceled)\n                    {\n                        // If the task has finished cancelling there should not be any continuation records in the array.\n                        return false;\n                    }\n                    else\n                    {\n                        _ASSERTE(_M_TaskState != _Completed);\n                        _M_exceptionHolder = _ExceptionHolder_arg;\n                    }\n                }\n                else\n                {\n                    // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel\n                    // which is to say, cancellation is already initiated, so return early.\n                    if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel))\n                    {\n                        _ASSERTE(!_IsCompleted() || !_HasUserException());\n                        return false;\n                    }\n                    _ASSERTE(!_SynchronousCancel || !_HasUserException());\n                }\n\n                if (_SynchronousCancel)\n                {\n                    // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()\n                    _M_TaskState = _Canceled;                    \n                    // Cancellation completes the task, so all dependent tasks must be run to cancel them\n                    // They are canceled when they begin running (see _RunContinuation) and see that their\n                    // ancestor has been canceled.\n                    _RunContinuations = true;\n                }\n                else\n                {\n                    _ASSERTE(!_UserException);\n\n                    if (_IsStarted())\n                    {\n#if defined (__cplusplus_winrt)\n                        if (_M_unwrapped_async_op != nullptr)\n                        {\n                            // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.\n                            _M_unwrapped_async_op->Cancel();\n                        }\n#endif  /* defined (__cplusplus_winrt) */\n                        _M_TaskCollection._Cancel();\n                    }\n\n                    // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).\n                    // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from\n                    // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.\n                    _M_TaskState = _PendingCancel;\n\n                    _M_taskEventLogger._LogCancelTask();\n                }\n\n                \n            }\n\n            // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.\n            if (_RunContinuations)\n            {\n                _M_TaskCollection._Complete();\n\n                if (_M_Continuations)\n                {\n                    // Scheduling cancellation with automatic inlining.\n                    _ScheduleFuncWithAutoInline([=](){ _RunTaskContinuations(); }, details::_DefaultAutoInline);\n                }\n            }\n            return true;\n        }\n\n        void _FinalizeAndRunContinuations(_ReturnType _Result)\n        {\n            _M_Result.Set(_Result);\n\n            {\n                //\n                // Hold this lock to ensure continuations being concurrently either get added\n                // to the _M_Continuations vector or wait for the result\n                //\n                ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n\n                // A task could still be in the _Created state if it was created with a task_completion_event.\n                // It could also be in the _Canceled state for the same reason.\n                _ASSERTE(!_HasUserException() && !_IsCompleted());\n                if (_IsCanceled())\n                {\n                    return;\n                }\n\n                // Always transition to \"completed\" state, even in the face of unacknowledged pending cancellation\n                _M_TaskState = _Completed;\n            }\n            _M_TaskCollection._Complete();\n            _RunTaskContinuations();\n        }\n\n        //\n        // This method is invoked when the starts executing. The task returns early if this method returns true.\n        //\n        bool _TransitionedToStarted()\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n            // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here.\n            _ASSERTE(!_IsCanceled());\n            if (_IsPendingCancel())\n                return false;\n\n            _ASSERTE(_IsCreated());\n            _M_TaskState = _Started;\n            return true;\n        }\n\n#if defined (__cplusplus_winrt)\n        void _SetUnwrappedAsyncOp(_AsyncOperationType^ _AsyncOp)\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);\n            // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.\n            if (_IsPendingCancel())\n            {\n                _ASSERTE(!_IsCanceled());\n                _AsyncOp->Cancel();\n            }\n            else\n            {\n                _M_unwrapped_async_op = _AsyncOp;\n            }\n        }\n#endif  /* defined (__cplusplus_winrt) */\n\n        // Return true if the task has reached a terminal state\n        bool _IsDone()\n        {     \n            return _IsCompleted() || _IsCanceled();\n        }\n\n        _ReturnType _GetResult()\n        {\n            return _M_Result.Get();\n        }\n\n        _ResultHolder<_ReturnType>                 _M_Result;        // this means that the result type must have a public default ctor.\n#if defined (__cplusplus_winrt)\n        _AsyncOperationType^                        _M_unwrapped_async_op;\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n    template<typename _ResultType>\n    struct _Task_completion_event_impl\n    {\n    private:\n        _Task_completion_event_impl(const _Task_completion_event_impl&);\n        _Task_completion_event_impl& operator=(const _Task_completion_event_impl&);\n\n    public:\n\n        typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList;\n\n        _Task_completion_event_impl() :\n            _M_fHasValue(false), _M_fIsCanceled(false)\n        {\n        }\n\n        bool _HasUserException()\n        {\n            return _M_exceptionHolder != nullptr;\n        }\n\n        ~_Task_completion_event_impl()\n        {\n            for( auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt )\n            {\n                _ASSERTE(!_M_fHasValue && !_M_fIsCanceled);\n                // Cancel the tasks since the event was never signaled or canceled.\n                (*_TaskIt)->_Cancel(true);\n            }\n        }\n\n        // We need to protect the loop over the array, so concurrent_vector would not have helped\n        _TaskList                           _M_tasks;\n        ::pplx::extensibility::critical_section_t             _M_taskListCritSec;\n        _ResultHolder<_ResultType>         _M_value;\n        std::shared_ptr<_ExceptionHolder>   _M_exceptionHolder;\n        bool                                _M_fHasValue;\n        bool                                _M_fIsCanceled;\n    };\n\n    // Utility method for dealing with void functions\n    inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function<void(void)>& _Func)\n    {\n        return [=]() -> _Unit_type { _Func(); return _Unit_type(); };\n    }\n\n    template <typename _Type>\n    std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func)\n    {\n        return [=](_Unit_type) -> _Type { return _Func(); };\n    }\n\n    template <typename _Type>\n    std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function<void(_Type)>& _Func)\n    {\n        return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); };\n    }\n\n    inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function<void(void)>& _Func)\n    {\n        return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); };\n    }\n} // namespace details\n\n/// <summary>\n///     The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,\n///     or start a task in response to an external event.\n/// </summary>\n/// <typeparam name=\"_ResultType\">\n///     The result type of this <c>task_completion_event</c> class.\n/// </typeparam>\n/// <remarks>\n///     Use a task created from a task completion event when your scenario requires you to create a task that will complete, and\n///     thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must\n///     have the same type as the task you create, and calling the set method on the task completion event with a value of that type\n///     will cause the associated task to complete, and provide that value as a result to its continuations.\n///     <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>\n///     <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/**/\ntemplate<typename _ResultType>\nclass task_completion_event\n{\npublic:\n    /// <summary>\n    ///     Constructs a <c>task_completion_event</c> object.\n    /// </summary>\n    /**/\n    task_completion_event() \n        : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>()) \n    {\n    }\n\n    /// <summary>\n    ///     Sets the task completion event.\n    /// </summary>\n    /// <param name=\"_Result\">\n    ///     The result to set this event with.\n    /// </param>\n    /// <returns>\n    ///     The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.\n    /// </returns>\n    /// <remarks>\n    ///     In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the\n    ///     task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the\n    ///     tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have\n    ///     a <typeparamref name=\"_ResultType\"/> other than <c>void</c> will pass the value <paramref value=\"_Result\"/> to their continuations.\n    /// </remarks>\n    /**/\n    bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.\n        if (_IsTriggered())\n        {\n            return false;\n        }\n\n        _TaskList _Tasks;\n        bool _RunContinuations = false;\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n\n            if (!_IsTriggered())\n            {\n                _M_Impl->_M_value.Set(_Result);\n                _M_Impl->_M_fHasValue = true;\n\n                _Tasks.swap(_M_Impl->_M_tasks);\n                _RunContinuations = true;\n            }\n        }\n\n        if (_RunContinuations)\n        {\n            for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )\n            {\n                // If current task was cancelled by a cancellation_token, it would be in cancel pending state.\n                if ((*_TaskIt)->_IsPendingCancel())\n                    (*_TaskIt)->_Cancel(true);\n                else\n                {\n                    // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all\n                    // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we\n                    // need to run continuations after the lock is released.\n                    (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());\n                }\n            }\n            if (_M_Impl->_HasUserException())\n            {\n                _M_Impl->_M_exceptionHolder.reset();\n            }\n            return true;\n        }\n\n        return false;\n    }\n\n    template<typename _E>\n    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result\n    bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.\n        return _Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Propagates an exception to all tasks associated with this event.\n    /// </summary>\n    /// <param>\n    ///     The exception_ptr that indicates the exception to set this event with.\n    /// </param>\n    /**/\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.\n        return _Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has\n    ///     not already been set.\n    /// </summary>\n    bool _Cancel() const\n    {\n        // Cancel with the stored exception if one exists.\n        return _CancelInternal();\n    }\n\n    /// <summary>\n    ///     Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled\n    ///     with the same exception.\n    /// </summary>\n    template<typename _ExHolderType>\n    bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const\n    {\n        bool _Canceled;\n        if(_StoreException(_ExHolder, _SetExceptionAddressHint))\n        {\n            _Canceled = _CancelInternal();\n            _ASSERTE(_Canceled);\n        }\n        else\n        {\n            _Canceled = false;\n        }\n        return _Canceled;\n    }\n\n    /// <summary>\n    ///     Internal method that stores an exception in the task completion event. This is used internally by when_any.\n    ///     Note, this does not cancel the task completion event. A task completion event with a stored exception\n    ///     can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.\n    /// </summary>\n    template<typename _ExHolderType>\n    bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const\n    {\n        ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n        if (!_IsTriggered() && !_M_Impl->_HasUserException())\n        {\n            // Create the exception holder only if we have ensured there we will be successful in setting it onto the\n            // task completion event. Failing to do so will result in an unobserved task exception.\n            _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint);\n            return true;\n        }\n        return false;\n    }\n\n    /// <summary>\n    ///     Tests whether current event has been either Set, or Canceled.\n    /// </summary>\n    bool _IsTriggered() const\n    {\n        return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled;\n    }\n\nprivate:\n\n    static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, const details::_TaskCreationCallstack&)\n    {\n        return _ExHolder;\n    }\n\n    static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint)\n    {\n        return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint);\n    }\n\n\n    template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask\n    template <typename T> friend class task_completion_event;\n\n    typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList;\n\n    /// <summary>\n    ///    Cancels the task_completion_event.\n    /// </summary>\n    bool _CancelInternal() const\n    {\n        // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal\n        // will never be invoked if the task completion event has been set.\n        _ASSERTE(!_M_Impl->_M_fHasValue);\n        if (_M_Impl->_M_fIsCanceled)\n        {\n            return false;\n        }\n\n        _TaskList _Tasks;\n        bool _Cancel = false;\n        {\n            ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n            _ASSERTE(!_M_Impl->_M_fHasValue);\n            if (!_M_Impl->_M_fIsCanceled)\n            {\n                _M_Impl->_M_fIsCanceled = true;\n                _Tasks.swap(_M_Impl->_M_tasks);\n                _Cancel = true;\n            }\n        }\n\n        bool _UserException = _M_Impl->_HasUserException();\n\n        if (_Cancel)\n        {\n            for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )\n            {\n                // Need to call this after the lock is released. See comments in set().\n                if (_UserException)\n                {\n                    (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);\n                }\n                else\n                {\n                    (*_TaskIt)->_Cancel(true);\n                }\n            }\n        }\n        return _Cancel;\n    }\n\n    /// <summary>\n    ///     Register a task with this event. This function is called when a task is constructed using\n    ///     a task_completion_event.\n    /// </summary>\n    void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam)\n    {\n        ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);\n\n        //If an exception was already set on this event, then cancel the task with the stored exception.\n        if(_M_Impl->_HasUserException())\n        {\n            _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);\n        }\n        else if (_M_Impl->_M_fHasValue)\n        {\n            _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());\n        }\n        else\n        {\n            _M_Impl->_M_tasks.push_back(_TaskParam);\n        }\n    }\n\n    std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl;\n};\n\n/// <summary>\n///     The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,\n///     or start a task in response to an external event.\n/// </summary>\n/// <remarks>\n///     Use a task created from a task completion event when your scenario requires you to create a task that will complete, and\n///     thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must\n///     have the same type as the task you create, and calling the set method on the task completion event with a value of that type\n///     will cause the associated task to complete, and provide that value as a result to its continuations.\n///     <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>\n///     <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/**/\ntemplate<>\nclass task_completion_event<void>\n{\npublic:\n    /// <summary>\n    ///     Sets the task completion event.\n    /// </summary>\n    /// <returns>\n    ///     The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.\n    /// </returns>\n    /// <remarks>\n    ///     In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the\n    ///     task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the\n    ///     tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have\n    ///     a <typeparamref name=\"_ResultType\"/> other than <c>void</c> will pass the value <paramref value=\"_Result\"/> to their continuations.\n    /// </remarks>\n    /**/\n    bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        return _M_unitEvent.set(details::_Unit_type());\n    }\n\n    template<typename _E>\n    __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result\n    bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Propagates an exception to all tasks associated with this event.\n    /// </summary>\n    /// <param>\n    ///     The exception_ptr that indicates the exception to set this event with.\n    /// </param>\n    /**/\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK intrinsic gives us the expected result\n    bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.\n        return _M_unitEvent._Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());\n    }\n\n    /// <summary>\n    ///     Cancel the task_completion_event. Any task created using this event will be marked as canceled if it has\n    ///     not already been set.\n    /// </summary>\n    void _Cancel() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas\n    {\n        _M_unitEvent._Cancel();\n    }\n\n    /// <summary>\n    ///     Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled\n    ///     with the same exception.\n    /// </summary>\n    void _Cancel(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const\n    {\n        _M_unitEvent._Cancel(_ExHolder);\n    }\n\n    /// <summary>\n    ///     Method that stores an exception in the task completion event. This is used internally by when_any.\n    ///     Note, this does not cancel the task completion event. A task completion event with a stored exception\n    ///     can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.\n    /// </summary>\n    bool _StoreException(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const\n    {\n        return _M_unitEvent._StoreException(_ExHolder);\n    }\n\n    /// <summary>\n    ///     Test whether current event has been either Set, or Canceled.\n    /// </summary>\n    bool _IsTriggered() const\n    {\n        return _M_unitEvent._IsTriggered();\n    }\n\nprivate:\n    template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask\n\n    /// <summary>\n    ///     Register a task with this event. This function is called when a task is constructed using\n    ///     a task_completion_event.\n    /// </summary>\n    void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam)\n    {\n        _M_unitEvent._RegisterTask(_TaskParam);\n    }\n\n    // The void event contains an event a dummy type so common code can be used for events with void and non-void results.\n    task_completion_event<details::_Unit_type> _M_unitEvent;\n};\n\nnamespace details\n{\n    //\n    // Compile-time validation helpers\n    //\n\n    // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.\n    //\n    // Anything callable is fine\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int,int,int,int) -> decltype(_Param(), std::true_type());\n\n#if defined (__cplusplus_winrt)\n    // Anything that has GetResults is fine: this covers all async operations\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int, int, int,...) -> decltype(_Param->GetResults(), std::true_type());\n#endif\n\n    // Allow parameters with set: this covers task_completion_event\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type());\n\n    template<typename _ReturnType, typename _Ty>\n    auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type());\n\n    // All else is invalid\n    template<typename _ReturnType, typename _Ty>\n    std::false_type _IsValidTaskCtor(_Ty _Param, ...);\n\n    template<typename _ReturnType, typename _Ty>\n    void _ValidateTaskConstructorArgs(_Ty _Param)\n    {\n        static_assert(std::is_same<decltype(_IsValidTaskCtor<_ReturnType>(_Param,0,0,0,0)),std::true_type>::value,\n#if defined (__cplusplus_winrt)\n            \"incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event\"\n#else  /* defined (__cplusplus_winrt) */\n            \"incorrect argument for task constructor; can be a callable object or a task_completion_event\"\n#endif  /* defined (__cplusplus_winrt) */\n            );\n#if defined (__cplusplus_winrt)\n        static_assert(!(std::is_same<_Ty,_ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value),\n            \"incorrect template argument for task; consider using the return type of the async operation\");\n#endif  /* defined (__cplusplus_winrt) */\n    }\n\n#if defined (__cplusplus_winrt)\n    // Helpers for create_async validation\n    //\n    // A parameter lambda taking no arguments is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type());\n\n    // A parameter lambda taking an cancellation_token argument is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> decltype(_Param(cancellation_token::none()), std::true_type());\n\n    // A parameter lambda taking a progress report argument is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());\n\n    // A parameter lambda taking a progress report and a cancellation_token argument is valid\n    template<typename _Ty>\n    static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type());\n\n    // All else is invalid\n    template<typename _Ty>\n    static std::false_type _IsValidCreateAsync(_Ty _Param, ...);\n#endif  /* defined (__cplusplus_winrt) */\n}\n/// <summary>\n///     A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a\n///     non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'.\n/// </summary>\ntemplate<typename _InpType, typename _OutType>\nclass _Continuation_func_transformer\n{\npublic:\n    static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func)\n    {\n        return _Func;\n    }\n};\n\ntemplate<typename _OutType>\nclass _Continuation_func_transformer<void, _OutType>\n{\npublic:\n    static auto _Perform(std::function<_OutType(void)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))\n    {\n        return details::_MakeUnitToTFunc<_OutType>(_Func);\n    }\n};\n\ntemplate<typename _InType>\nclass _Continuation_func_transformer<_InType, void>\n{\npublic:\n    static auto _Perform(std::function<void(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))\n    {\n        return details::_MakeTToUnitFunc<_InType>(_Func);\n    }\n};\n\ntemplate<>\nclass _Continuation_func_transformer<void, void>\n{\npublic:\n    static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))\n    {\n        return details::_MakeUnitToUnitFunc(_Func);\n    }\n};\n\n// A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used\n// to substitute for void). This is to minimize the special handling required for 'void'.\ntemplate<typename _RetType>\nclass _Init_func_transformer\n{\npublic:\n    static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func)\n    {\n        return _Func;\n    }\n};\n\ntemplate<>\nclass _Init_func_transformer<void>\n{\npublic:\n    static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))\n    {\n        return details::_MakeVoidToUnitFunc(_Func);\n    }\n};\n\n/// <summary>\n///     The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,\n///     and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces\n///     a result of type <typeparamref name=\"_ResultType\"/> on successful completion. Tasks of type <c>task&lt;void&gt;</c> produce no result.\n///     A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using\n///     continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The result type of this task.\n/// </typeparam>\n/// <remarks>\n///     For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.\n/// </remarks>\n/**/\ntemplate<typename _ReturnType>\nclass task\n{\npublic:\n    /// <summary>\n    ///     The type of the result an object of this class produces.\n    /// </summary>\n    /**/\n    typedef _ReturnType result_type;\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task() : _M_Impl(nullptr)\n    {\n        // The default constructor should create a task with a nullptr impl. This is a signal that the\n        // task is not usable and should throw if any wait(), get() or then() APIs are used.\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <typeparam name=\"_Ty\">\n    ///     The type of the parameter from which the task is to be constructed.\n    /// </typeparam>\n    /// <param name=\"_Param\">\n    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>\n    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function\n    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,\n    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.\n    /// </param>\n    /// <param name=\"_Token\">\n    ///     The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives\n    ///     the token <c>cancellation_token::none()</c>.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Ty>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    explicit task(_Ty _Param)\n    {\n        task_options _TaskOptions;\n        details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);\n\n        _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());\n        // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.\n        _SetTaskCreationCallstack(_CAPTURE_CALLSTACK());\n\n        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <typeparam name=\"_Ty\">\n    ///     The type of the parameter from which the task is to be constructed.\n    /// </typeparam>\n    /// <param name=\"_Param\">\n    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>\n    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function\n    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,\n    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.\n    /// </param>\n    /// <param name=\"_TaskOptions\">\n    ///     The task options include cancellation token, scheduler etc\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Ty>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    explicit task(_Ty _Param, const task_options &_TaskOptions)\n    {\n        details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);\n\n        _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());\n        // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.\n        _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());\n        \n        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(const task& _Other): _M_Impl(_Other._M_Impl) {}\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(task&& _Other): _M_Impl(std::move(_Other._M_Impl)) {}\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(const task& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_Impl = _Other._M_Impl;\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(task&& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_Impl = std::move(_Other._M_Impl);\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        task_options _TaskOptions;\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_TaskOptions\">\n    ///     The task options include cancellation token, scheduler and continuation context. By default the former 3\n    ///     options are inherited from the antecedent task\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_CancellationToken\">\n    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit\n    ///     the token of its antecedent task.\n    /// </param>\n    /// <param name=\"_ContinuationContext\">\n    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a Windows Store\n    ///     style app. For more information, see <see cref=\"task_continuation_context Class\">task_continuation_context</see>\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        task_options _TaskOptions(_CancellationToken, _ContinuationContext);\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks\n    ///     dependencies are satisfied, and it has not already been picked up for execution by a background worker.\n    /// </summary>\n    /// <returns>\n    ///     A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception\n    ///     during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.\n    /// </returns>\n    /**/\n    task_status wait() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"wait() cannot be called on a default constructed task.\");\n        }\n\n        return _M_Impl->_Wait();\n    }\n\n    /// <summary>\n    ///     Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to\n    ///     finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.\n    /// </summary>\n    /// <returns>\n    ///     The result of the task.\n    /// </returns>\n    /// <remarks>\n    ///     If the task is canceled, a call to <c>get</c> will throw a <see cref=\"task_canceled Class\">task_canceled</see> exception. If the task\n    ///     encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.\n    /// </remarks>\n    /**/\n    _ReturnType get() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"get() cannot be called on a default constructed task.\");\n        }\n\n        if (_M_Impl->_Wait() == canceled)\n        {\n            throw task_canceled();  \n        }\n\n        return _M_Impl->_GetResult();\n    }\n\n    /// <summary>\n    ///     Determines if the task is completed.\n    /// </summary>\n    /// <returns>\n    ///     True if the task has completed, false otherwise.\n    /// </returns>\n    /// <remarks>\n    ///     The function returns true if the task is completed or canceled (with or without user exception).\n    /// </remarks>\n    bool is_done() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"is_done() cannot be called on a default constructed task.\");\n        }\n\n        return _M_Impl->_IsDone();\n    }\n\n    /// <summary>\n    ///     Returns the scheduler for this task\n    /// </summary>\n    /// <returns>\n    ///     A pointer to the scheduler\n    /// </returns>\n    scheduler_ptr scheduler() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"scheduler() cannot be called on a default constructed task.\");\n        }\n\n        return _M_Impl->_GetScheduler();\n    }\n\n    /// <summary>\n    ///     Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool is_apartment_aware() const\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"is_apartment_aware() cannot be called on a default constructed task.\");\n        }\n        return _M_Impl->_IsApartmentAware();\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent the same internal task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator==(const task<_ReturnType>& _Rhs) const\n    {\n        return (_M_Impl == _Rhs._M_Impl);\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent different internal tasks.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator!=(const task<_ReturnType>& _Rhs) const\n    {\n        return !operator==(_Rhs);\n    }\n\n    /// <summary>\n    ///     Create an underlying task implementation.\n    /// </summary>\n    void _CreateImpl(details::_CancellationTokenState * _Ct, scheduler_ptr _Scheduler)\n    {\n        _ASSERTE(_Ct != nullptr);\n        _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct, _Scheduler);\n        if (_Ct != details::_CancellationTokenState::_None())\n        {\n            _M_Impl->_RegisterCancellation(_M_Impl);\n        }\n    }\n\n    /// <summary>\n    ///     Return the underlying implementation for this task.\n    /// </summary>\n    const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const\n    {\n        return _M_Impl;\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion.\n    /// </summary>\n    void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl)\n    {\n        _ASSERTE(!_M_Impl);\n        _M_Impl = _Impl;\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion using a move instead of a copy.\n    /// </summary>\n    void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl)\n    {\n        _ASSERTE(!_M_Impl);\n        _M_Impl = std::move(_Impl);\n    }\n\n    /// <summary>\n    ///     Sets a property determining whether the task is apartment aware.\n    /// </summary>\n    void _SetAsync(bool _Async = true)\n    {\n        _GetImpl()->_SetAsync(_Async);\n    }\n\n    /// <summary>\n    ///     Sets a field in the task impl to the return callstack for calls to the task constructors and the then method.\n    /// </summary>\n    void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)\n    {\n        _GetImpl()->_SetTaskCreationCallstack(_callstack);\n    }\n\n    /// <summary>\n    ///     An internal version of then that takes additional flags and always execute the continuation inline by default.\n    ///     When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline.\n    ///     This function is Used for runtime internal continuations only.\n    /// </summary>\n    template<typename _Function>\n    auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState, \n        details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType\n    {\n        // inherit from antecedent\n        auto _Scheduler = _GetImpl()->_GetScheduler();\n\n        return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);\n    }\n\nprivate:\n    template <typename T> friend class task;\n\n     \n    // The task handle type used to construct an 'initial task' - a task with no dependents.\n    template <typename _InternalReturnType, typename _Function, typename _TypeSelection>\n    struct _InitialTaskHandle : \n        details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>\n    {\n        _Function _M_function;\n        _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _func)\n            : details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>::_PPLTaskHandle(_TaskImpl)\n            , _M_function(_func)\n        {\n        }\n\n        virtual ~_InitialTaskHandle() {}\n\n        template <typename _Func>\n        auto _LogWorkItemAndInvokeUserLambda(_Func && _func) const -> decltype(_func())\n        {\n            details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);\n            CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);\n            return _func();\n        }\n\n        void _Perform() const\n        {\n            _Init(_TypeSelection());\n        }\n\n        void _SyncCancelAndPropagateException() const\n        {\n            this->_M_pTask->_Cancel(true);\n        }\n\n        //\n        // Overload 0: returns _InternalReturnType\n        //\n        // This is the most basic task with no unwrapping\n        //\n        void _Init(details::_TypeSelectorNoAsync) const\n        {\n            this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function)));\n        }\n\n        //\n        // Overload 1: returns IAsyncOperation<_InternalReturnType>^ (only uder /ZW)\n        //                   or\n        //             returns task<_InternalReturnType>\n        //\n        // This is task whose functor returns an async operation or a task which will be unwrapped for continuation\n        // Depending on the output type, the right _AsyncInit gets invoked\n        //\n        void _Init(details::_TypeSelectorAsyncOperationOrTask) const\n        {\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function));\n        }\n\n#if defined (__cplusplus_winrt)\n        //\n        // Overload 2: returns IAsyncAction^\n        //\n        // This is task whose functor returns an async action which will be unwrapped for continuation\n        //\n        void _Init(details::_TypeSelectorAsyncAction) const\n        {\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function)));\n        }\n\n        //\n        // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>^\n        //\n        // This is task whose functor returns an async operation with progress which will be unwrapped for continuation\n        //\n        void _Init(details::_TypeSelectorAsyncOperationWithProgress) const\n        {\n            typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask,\n                    ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType,_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));\n        }\n\n        //\n        // Overload 4: returns IAsyncActionWithProgress<_ProgressType>^\n        //\n        // This is task whose functor returns an async action with progress which will be unwrapped for continuation\n        //\n        void _Init(details::_TypeSelectorAsyncActionWithProgress) const\n        {\n            typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, \n                ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));\n        }\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n\n    /// <summary>\n    ///     The task handle type used to create a 'continuation task'.\n    /// </summary>\n    template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection>\n    struct _ContinuationTaskHandle :\n        details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,\n        _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>\n    {\n        typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;\n\n        typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;\n        _Function _M_function;\n\n        _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,\n            const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,\n            const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode)\n                : details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,\n                    _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>\n                    ::_PPLTaskHandle(_ContinuationImpl)\n                , _M_ancestorTaskImpl(_AncestorImpl)\n                , _M_function(_Func)\n        {\n            this->_M_isTaskBasedContinuation = _IsTaskBased::value;\n            this->_M_continuationContext = _Context;\n            this->_M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware());\n            this->_M_inliningMode = _InliningMode;\n        }\n\n        virtual ~_ContinuationTaskHandle() {}\n\n        template <typename _Func, typename _Arg>\n        auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value) const -> decltype(_func(std::forward<_Arg>(_value)))\n        {\n            details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);\n            CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);\n            return _func(std::forward<_Arg>(_value));\n        }\n\n        void _Perform() const\n        {\n            _Continue(_IsTaskBased(), _TypeSelection());\n        }\n\n        void _SyncCancelAndPropagateException() const\n        {\n            if (_M_ancestorTaskImpl->_HasUserException())\n            {\n                // If the ancestor encountered an exception, transfer the exception to the continuation\n                // This traverses down the tree to propagate the exception.\n                this->_M_pTask->_CancelWithExceptionHolder(_M_ancestorTaskImpl->_GetExceptionHolder(), true);\n            }\n            else\n            {\n                // If the ancestor was canceled, then your own execution should be canceled.\n                // This traverses down the tree to cancel it.\n                this->_M_pTask->_Cancel(true);\n            }\n        }\n\n        //\n        // Overload 0-0: _InternalReturnType -> _TaskType\n        //\n        // This is a straight task continuation which simply invokes its target with the ancestor's completion argument\n        //\n        void _Continue(std::false_type, details::_TypeSelectorNoAsync) const\n        {\n            this->_M_pTask->_FinalizeAndRunContinuations(\n                _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()));\n        }\n\n        //\n        // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>^ (only uder /ZW)\n        //               or\n        //               _InternalReturnType -> task<_TaskType>\n        //\n        // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation\n        // Depending on the output type, the right _AsyncInit gets invoked\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncOperationOrTask) const\n        {\n            typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask, \n                _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())\n            );\n        }\n\n#if defined (__cplusplus_winrt)\n        //\n        // Overload 0-2: _InternalReturnType -> IAsyncAction^\n        //\n        // This is a straight task continuation which returns an async action which will be unwrapped for continuation\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const\n        {\n            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask,\n                ref new details::_IAsyncActionToAsyncOperationConverter(\n                    _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())));\n        }\n\n        //\n        // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^\n        //\n        // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const\n        {\n            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());\n            typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask,\n                ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(_OpWithProgress));\n        }\n\n        //\n        // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>^\n        //\n        // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation\n        //\n        void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const\n        {\n            typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;\n\n            auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());\n            typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(\n                this->_M_pTask,\n                ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_OpWithProgress));\n        }\n\n#endif  /* defined (__cplusplus_winrt) */\n\n        //\n        // Overload 1-0: task<_InternalReturnType> -> _TaskType\n        //\n        // This is an exception handling type of continuation which takes the task rather than the task's result.\n        //\n        void _Continue(std::true_type, details::_TypeSelectorNoAsync) const\n        {\n            typedef task<_InternalReturnType> _FuncInputType;\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n            this->_M_pTask->_FinalizeAndRunContinuations(\n                _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask)));\n        }\n\n        //\n        // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^\n        //                                            or\n        //                                            task<_TaskType>\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async operation or a task which will be unwrapped\n        // for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncOperationOrTask) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask, \n                _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)));\n        }\n\n#if defined (__cplusplus_winrt)\n\n        //\n        // Overload 1-2: task<_InternalReturnType> -> IAsyncAction^\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async action which will be unwrapped for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,\n                ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));\n        }\n\n        //\n        // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async operation with progress which will be unwrapped\n        // for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n\n            typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,\n                    ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(\n                    _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));\n        }\n\n        //\n        // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>^\n        //\n        // This is an exception handling type of continuation which takes the task rather than\n        // the task's result. It also returns an async operation with progress which will be unwrapped\n        // for continuation\n        //\n        void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const\n        {\n            // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.\n            task<_InternalReturnType> _ResultTask;\n            _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));\n\n            typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;\n\n            details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,\n                    ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(\n                    _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));\n        }\n#endif  /* defined (__cplusplus_winrt) */\n    };\n\n    /// <summary>\n    ///     Initializes a task using a lambda, function pointer or function object.\n    /// </summary>\n    template<typename _InternalReturnType, typename _Function>\n    void _TaskInitWithFunctor(const _Function& _Func)\n    {\n        typedef typename details::_InitFunctorTypeTraits<_InternalReturnType, decltype(_Func())> _Async_type_traits;\n\n        _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask;\n        _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;\n        _M_Impl->_M_taskEventLogger._LogScheduleTask(false);\n        _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), details::_NoInline);\n    }\n\n    /// <summary>\n    ///     Initializes a task using a task completion event.\n    /// </summary>\n    void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event)\n    {\n        _Event._RegisterTask(_M_Impl);\n    }\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Initializes a task using an asynchronous operation IAsyncOperation<T>^\n    /// </summary>\n    void _TaskInitAsyncOp(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)\n    {\n        _M_Impl->_M_fFromAsync = true;\n\n        // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit\n        // returns a completion could execute concurrently and the task must be fully initialized before that happens.\n        _M_Impl->_M_TaskState = details::_Task_impl_base::_Started;\n        // Pass the shared pointer into _AsyncInit for storage in the Async Callback.\n        details::_Task_impl_base::_AsyncInit<_ReturnType, _ReturnType>(_M_Impl, _AsyncOp);\n    }\n\n    /// <summary>\n    ///     Initializes a task using an asynchronous operation IAsyncOperation<T>^\n    /// </summary>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)\n    {\n        _TaskInitAsyncOp(_AsyncOp);\n    }\n\n    /// <summary>\n    ///     Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress<T, P>^\n    /// </summary>\n    template<typename _Progress>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperationWithProgress<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>^ _AsyncOp)\n    {\n        _TaskInitAsyncOp(ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>(_AsyncOp));\n    }\n#endif  /* defined (__cplusplus_winrt) */\n\n    /// <summary>\n    ///     Initializes a task using a callable object.\n    /// </summary>\n    template<typename _Function>\n    void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)\n    {\n        _TaskInitWithFunctor<_ReturnType, _Function>(_Func);\n    }\n\n    /// <summary>\n    ///     Initializes a task using a non-callable object.\n    /// </summary>\n    template<typename _Ty>\n    void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type)\n    {\n        _TaskInitNoFunctor(_Param);\n    }\n\n    template<typename _InternalReturnType, typename _Function>\n    auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"then() cannot be called on a default constructed task.\");\n        }\n\n        details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n        auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler();\n        auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack();\n        return _ThenImpl<_InternalReturnType, _Function>(_Func, _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack);\n    }\n\n    /// <summary>\n    ///     The one and only implementation of then for void and non-void tasks.\n    /// </summary>\n    template<typename _InternalReturnType, typename _Function>\n    auto _ThenImpl(const _Function& _Func, details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack,\n        details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType\n    {\n        if (!_M_Impl)\n        {\n            throw invalid_operation(\"then() cannot be called on a default constructed task.\");\n        }\n\n        typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits;\n        typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits;\n        typedef typename _Async_type_traits::_TaskRetType _TaskType;\n\n        //\n        // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a\n        // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user\n        // explicitly passes the same token.\n        //\n        if (_PTokenState == nullptr)\n        {\n            if (_Function_type_traits::_Takes_task::value)\n            {\n                _PTokenState = details::_CancellationTokenState::_None();\n            }\n            else\n            {\n                _PTokenState = _GetImpl()->_M_pTokenState;\n            }\n        }\n\n        task<_TaskType> _ContinuationTask;\n        _ContinuationTask._CreateImpl(_PTokenState, _Scheduler);\n\n        _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask);\n        _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;\n        _ContinuationTask._SetTaskCreationCallstack(_CreationStack);\n\n        _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>(\n            _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode));\n\n        return _ContinuationTask;\n    }\n\n    // The underlying implementation for this task\n    typename details::_Task_ptr<_ReturnType>::_Type _M_Impl;\n};\n\n/// <summary>\n///     The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,\n///     and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces\n///     a result of type <typeparamref name=\"_ResultType\"/> on successful completion. Tasks of type <c>task&lt;void&gt;</c> produce no result.\n///     A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using\n///     continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.\n/// </summary>\n/// <remarks>\n///     For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.\n/// </remarks>\n/**/\ntemplate<>\nclass task<void>\n{\npublic:\n    /// <summary>\n    ///     The type of the result an object of this class produces.\n    /// </summary>\n    /**/\n    typedef void result_type;\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task() : _M_unitTask()\n    {\n        // The default constructor should create a task with a nullptr impl. This is a signal that the\n        // task is not usable and should throw if any wait(), get() or then() APIs are used.\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <typeparam name=\"_Ty\">\n    ///     The type of the parameter from which the task is to be constructed.\n    /// </typeparam>\n    /// <param name=\"_Param\">\n    ///     The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event&lt;result_type&gt;</c>\n    ///     object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function\n    ///     object should be a type equivalent to <c>std::function&lt;X(void)&gt;</c>, where X can be a variable of type <c>result_type</c>,\n    ///     <c>task&lt;result_type&gt;</c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Ty>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    explicit task(_Ty _Param, const task_options& _TaskOptions = task_options())\n    {\n        details::_ValidateTaskConstructorArgs<void,_Ty>(_Param);\n\n        _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());\n        // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.\n        _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());\n\n        _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));\n    }\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(const task& _Other): _M_unitTask(_Other._M_unitTask){}\n\n    /// <summary>\n    ///     Constructs a <c>task</c> object.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.\n    ///     A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>\n    ///     will throw an <see cref=\"invalid_argument Class\">invalid_argument</see> exception when called on a default constructed task.\n    ///     <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task\n    ///     completion event is set.</para>\n    ///     <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the\n    ///     <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>\n    ///     <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface\n    ///     reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created\n    ///     from a lamda that returns a <c>task&lt;result_type&gt;</c> reach their terminal state when the inner task reaches its terminal state,\n    ///     and not when the lamda returns.</para>\n    ///     <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads\n    ///     without the need for locks.</para>\n    ///     <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available\n    ///     to Windows Store apps.</para>\n    ///     <para>For more information, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {}\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(const task& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_unitTask = _Other._M_unitTask;\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Replaces the contents of one <c>task</c> object with another.\n    /// </summary>\n    /// <param name=\"_Other\">\n    ///     The source <c>task</c> object.\n    /// </param>\n    /// <remarks>\n    ///     As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same\n    ///     actual task as <paramref name=\"_Other\"/> does.\n    /// </remarks>\n    /**/\n    task& operator=(task&& _Other)\n    {\n        if (this != &_Other)\n        {\n            _M_unitTask = std::move(_Other._M_unitTask);\n        }\n        return *this;\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_CancellationToken\">\n    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit\n    ///     the token of its antecedent task.\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType\n    {\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Adds a continuation task to this task.\n    /// </summary>\n    /// <typeparam name=\"_Function\">\n    ///     The type of the function object that will be invoked by this task.\n    /// </typeparam>\n    /// <param name=\"_Func\">\n    ///     The continuation function to execute when this task completes. This continuation function must take as input\n    ///     a variable of either <c>result_type</c> or <c>task&lt;result_type&gt;</c>, where <c>result_type</c> is the type\n    ///     of the result this task produces.\n    /// </param>\n    /// <param name=\"_CancellationToken\">\n    ///     The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit\n    ///     the token of its antecedent task.\n    /// </param>\n    /// <param name=\"_ContinuationContext\">\n    ///     A variable that specifies where the continuation should execute. This variable is only useful when used in a Windows Store\n    ///     style app. For more information, see <see cref=\"task_continuation_context Class\">task_continuation_context</see>\n    /// </param>\n    /// <returns>\n    ///     The newly created continuation task. The result type of the returned task is determined by what <paramref name=\"_Func\"/> returns.\n    /// </returns>\n    /// <remarks>\n    ///     The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available\n    ///     to Windows Store apps.\n    ///     <para>For more information on how to use task continuations to compose asynchronous work, see <see cref=\"Task Parallelism (Concurrency Runtime)\"/>.</para>\n    /// </remarks>\n    /**/\n    template<typename _Function>\n    __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result\n    auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType\n    {\n        task_options _TaskOptions(_CancellationToken, _ContinuationContext);\n        details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n        return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);\n    }\n\n    /// <summary>\n    ///     Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks\n    ///     dependencies are satisfied, and it has not already been picked up for execution by a background worker.\n    /// </summary>\n    /// <returns>\n    ///     A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception\n    ///     during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.\n    /// </returns>\n    /**/\n    task_status wait() const\n    {\n        return _M_unitTask.wait();\n    }\n\n    /// <summary>\n    ///     Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to\n    ///     finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.\n    /// </summary>\n    /// <remarks>\n    ///     If the task is canceled, a call to <c>get</c> will throw a <see cref=\"task_canceled Class\">task_canceled</see> exception. If the task\n    ///     encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.\n    /// </remarks>\n    /**/\n    void get() const\n    {\n        _M_unitTask.get();\n    }\n\n    /// <summary>\n    ///     Determines if the task is completed.\n    /// </summary>\n    /// <returns>\n    ///     True if the task has completed, false otherwise.\n    /// </returns>\n    /// <remarks>\n    ///     The function returns true if the task is completed or canceled (with or without user exception).\n    /// </remarks>\n    bool is_done() const\n    {\n        return _M_unitTask.is_done();\n    }\n\n    /// <summary>\n    ///     Returns the scheduler for this task\n    /// </summary>\n    /// <returns>\n    ///     A pointer to the scheduler\n    /// </returns>\n    scheduler_ptr scheduler() const\n    {\n        return _M_unitTask.scheduler();\n    }\n\n    /// <summary>\n    ///     Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool is_apartment_aware() const\n    {\n        return _M_unitTask.is_apartment_aware();\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent the same internal task.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator==(const task<void>& _Rhs) const\n    {\n        return (_M_unitTask == _Rhs._M_unitTask);\n    }\n\n    /// <summary>\n    ///     Determines whether two <c>task</c> objects represent different internal tasks.\n    /// </summary>\n    /// <returns>\n    ///     <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.\n    /// </returns>\n    /**/\n    bool operator!=(const task<void>& _Rhs) const\n    {\n        return !operator==(_Rhs);\n    }\n\n    /// <summary>\n    ///     Create an underlying task implementation.\n    /// </summary>\n    void _CreateImpl(details::_CancellationTokenState * _Ct, scheduler_ptr _Scheduler)\n    {\n        _M_unitTask._CreateImpl(_Ct, _Scheduler);\n    }\n\n    /// <summary>\n    ///     Return the underlying implementation for this task.\n    /// </summary>\n    const details::_Task_ptr<details::_Unit_type>::_Type & _GetImpl() const\n    {\n        return _M_unitTask._M_Impl;\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion.\n    /// </summary>\n    void _SetImpl(const details::_Task_ptr<details::_Unit_type>::_Type & _Impl)\n    {\n        _M_unitTask._SetImpl(_Impl);\n    }\n\n    /// <summary>\n    ///     Set the implementation of the task to be the supplied implementaion using a move instead of a copy.\n    /// </summary>\n    void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl)\n    {\n        _M_unitTask._SetImpl(std::move(_Impl));\n    }\n\n    /// <summary>\n    ///     Sets a property determining whether the task is apartment aware.\n    /// </summary>\n    void _SetAsync(bool _Async = true)\n    {\n        _M_unitTask._SetAsync(_Async);\n    }\n\n    /// <summary>\n    ///     Sets a field in the task impl to the return callstack for calls to the task constructors and the then method.\n    /// </summary>\n    void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)\n    {\n        _M_unitTask._SetTaskCreationCallstack(_callstack);\n    }\n\n    /// <summary>\n    ///     An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only.\n    /// </summary>\n    template<typename _Function>\n    auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState, \n        details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType\n    {\n        // inherit from antecedent\n        auto _Scheduler = _GetImpl()->_GetScheduler();\n\n        return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);\n    }\n\nprivate:\n    template <typename T> friend class task;\n    template <typename T> friend class task_completion_event;\n\n    /// <summary>\n    ///     Initializes a task using a task completion event.\n    /// </summary>\n    void _TaskInitNoFunctor(task_completion_event<void>& _Event)\n    {\n        _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent);\n    }\n\n#if defined (__cplusplus_winrt)\n    /// <summary>\n    ///     Initializes a task using an asynchronous action IAsyncAction^\n    /// </summary>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncAction^ _AsyncAction)\n    {\n         _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionToAsyncOperationConverter(_AsyncAction));\n    }\n\n    /// <summary>\n    ///     Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>^\n    /// </summary>\n    template<typename _P>\n    void _TaskInitNoFunctor(Windows::Foundation::IAsyncActionWithProgress<_P>^ _AsyncActionWithProgress)\n    {\n        _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>(_AsyncActionWithProgress));\n    }\n#endif  /* defined (__cplusplus_winrt) */\n\n    /// <summary>\n    ///     Initializes a task using a callable object.\n    /// </summary>\n    template<typename _Function>\n    void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)\n    {\n        _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func);\n    }\n\n    /// <summary>\n    ///     Initializes a task using a non-callable object.\n    /// </summary>\n    template<typename _T>\n    void _TaskInitMaybeFunctor(_T & _Param, std::false_type)\n    {\n        _TaskInitNoFunctor(_Param);\n    }\n\n    // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.\n    task<details::_Unit_type> _M_unitTask;\n};\n\nnamespace details\n{\n    /// <summary>\n    ///   The following type traits are used for the create_task function.\n    /// </summary>\n\n#if defined (__cplusplus_winrt)\n    // Unwrap functions for asyncOperations\n    template<typename _Ty>\n    _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperation<_Ty>^);\n\n    void _GetUnwrappedType(Windows::Foundation::IAsyncAction^);\n\n    template<typename _Ty, typename _Progress>\n    _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>^);\n\n    template<typename _Progress>\n    void _GetUnwrappedType(Windows::Foundation::IAsyncActionWithProgress<_Progress>^);\n#endif  /* defined (__cplusplus_winrt) */\n\n    // Unwrap task<T>\n    template<typename _Ty>\n    _Ty _GetUnwrappedType(task<_Ty>);\n\n    // Unwrap all supportted types\n    template<typename _Ty>\n    auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg));\n    // fallback\n    template<typename _Ty>\n    _Ty _GetUnwrappedReturnType(_Ty, ...);\n\n    /// <summary>\n    ///   <c>_GetTaskType</c> functions will retrieve task type <c>T</c> in <c>task[T](Arg)</c>,\n    ///   for given constructor argument <c>Arg</c> and its property \"callable\".\n    ///   It will automatically unwrap argument to get the final return type if necessary.\n    /// </summary>\n\n    // Non-Callable\n    template<typename _Ty>\n    _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type);\n\n    // Non-Callable\n    template<typename _Ty>\n    auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc));\n\n    // Callable\n    template<typename _Ty>\n    auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0));\n\n    // Special callable returns void\n    void _GetTaskType(std::function<void()>, std::true_type);\n    struct _BadArgType{};\n\n    template<typename _Ty>\n    auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0)));\n\n    template<typename _Ty>\n    _BadArgType _FilterValidTaskType(_Ty _Param, ...);\n\n    template<typename _Ty>\n    struct _TaskTypeFromParam\n    {\n        typedef decltype(_FilterValidTaskType(stdx::declval<_Ty>(), 0)) _Type;\n    };\n} // namespace details\n\n/// <summary>\n///     Creates a PPL <see cref=\"task Class\">task</see> object. <c>create_task</c> can be used anywhere you would have used a task constructor.\n///     It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.\n/// </summary>\n/// <typeparam name=\"_Ty\">\n///     The type of the parameter from which the task is to be constructed.\n/// </typeparam>\n/// <param name=\"_Param\">\n///     The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>\n///     object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.\n/// </param>\n/// <returns>\n///     A new task of type <c>T</c>, that is inferred from <paramref name=\"_Param\"/>.\n/// </returns>\n/// <remarks>\n///     The first overload behaves like a task constructor that takes a single parameter.\n///     <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not\n///     allowed to pass in a different <c>task</c> object as the first parameter.</para>\n///     <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name=\"_Param\"/> is a <c>task_completion_event&lt;T&gt;</c>,\n///     a <c>task&lt;T&gt;</c>, or a functor that returns either type <c>T</c> or <c>task&lt;T&gt;</c>, the type of the created task is <c>task&lt;T&gt;</c>.</para>\n///     <para>In a Windows Store app, if <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncOperation&lt;T&gt;^ or\n///     Windows::Foundation::IAsyncOperationWithProgress&lt;T,P&gt;^, or a functor that returns either of those types, the created task will be of type <c>task&lt;T&gt;</c>.\n///     If <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress&lt;P&gt;^, or a functor\n///     that returns either of those types, the created task will have type <c>task&lt;void&gt;</c>.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _Ty>\n__declspec(noinline)\nauto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task<typename details::_TaskTypeFromParam<_Ty>::_Type>\n{\n    static_assert(!std::is_same<typename details::_TaskTypeFromParam<_Ty>::_Type,details::_BadArgType>::value,\n#if defined (__cplusplus_winrt)\n            \"incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event\"\n#else  /* defined (__cplusplus_winrt) */\n            \"incorrect argument for create_task; can be a callable object or a task_completion_event\"\n#endif  /* defined (__cplusplus_winrt) */\n    );\n    details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());\n    task<typename details::_TaskTypeFromParam<_Ty>::_Type> _CreatedTask(_Param, _TaskOptions);\n    return _CreatedTask;\n}\n\n/// <summary>\n///     Creates a PPL <see cref=\"task Class\">task</see> object. <c>create_task</c> can be used anywhere you would have used a task constructor.\n///     It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.\n/// </summary>\n/// <typeparam name=\"_Ty\">\n///     The type of the parameter from which the task is to be constructed.\n/// </typeparam>\n/// <param name=\"_Param\">\n///     The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>\n///     object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.\n/// </param>\n/// <param name=\"_Token\">\n///     The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task.\n/// </param>\n/// <returns>\n///     A new task of type <c>T</c>, that is inferred from <paramref name=\"_Param\"/>.\n/// </returns>\n/// <remarks>\n///     The first overload behaves like a task constructor that takes a single parameter.\n///     <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not\n///     allowed to pass in a different <c>task</c> object as the first parameter.</para>\n///     <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name=\"_Param\"/> is a <c>task_completion_event&lt;T&gt;</c>,\n///     a <c>task&lt;T&gt;</c>, or a functor that returns either type <c>T</c> or <c>task&lt;T&gt;</c>, the type of the created task is <c>task&lt;T&gt;</c>.</para>\n///     <para>In a Windows Store app, if <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncOperation&lt;T&gt;^ or\n///     Windows::Foundation::IAsyncOperationWithProgress&lt;T,P&gt;^, or a functor that returns either of those types, the created task will be of type <c>task&lt;T&gt;</c>.\n///     If <paramref name=\"_Param\"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress&lt;P&gt;^, or a functor\n///     that returns either of those types, the created task will have type <c>task&lt;void&gt;</c>.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\n__declspec(noinline)\ntask<_ReturnType> create_task(const task<_ReturnType>& _Task)\n{\n    task<_ReturnType> _CreatedTask(_Task);\n    return _CreatedTask;\n}\n\n#if defined (__cplusplus_winrt)\nnamespace details\n{\n    template<typename _T>\n    task<_T> _To_task_helper(Windows::Foundation::IAsyncOperation<_T>^ op)\n    {\n        return task<_T>(op);\n    }\n\n    template<typename _T, typename _Progress>\n    task<_T> _To_task_helper(Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>^ op)\n    {\n        return task<_T>(op);\n    }\n\n    inline task<void> _To_task_helper(Windows::Foundation::IAsyncAction^ op)\n    {\n        return task<void>(op);\n    }\n\n    template<typename _Progress>\n    task<void> _To_task_helper(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ op)\n    {\n        return task<void>(op);\n    }\n\n    template<typename _ProgressType>\n    class _ProgressDispatcherBase\n    {\n    public:\n\n        virtual ~_ProgressDispatcherBase()\n        {\n        }\n\n        virtual void _Report(const _ProgressType& _Val) = 0;\n    };\n\n    template<typename _ProgressType, typename _ClassPtrType>\n    class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType>\n    {\n    public:\n\n        virtual ~_ProgressDispatcher()\n        {\n        }\n\n        _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)\n        {\n        }\n\n        virtual void _Report(const _ProgressType& _Val)\n        {\n            _M_ptr->_FireProgress(_Val);\n        }\n\n    private:\n\n        _ClassPtrType _M_ptr;\n    };\n    class _ProgressReporterCtorArgType{};\n} // namespace details\n\n/// <summary>\n///     The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound\n///     to a particular asynchronous action or operation.\n/// </summary>\n/// <typeparam name=\"_ProgressType\">\n///     The payload type of each progress notification reported through the progress reporter.\n/// </typeparam>\n/// <remarks>\n///     This type is only available to Windows Store apps.\n/// </remarks>\n/// <seealso cref=\"create_async Function\"/>\n/**/\ntemplate<typename _ProgressType>\nclass progress_reporter\n{\n    typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType;\n\npublic:\n\n    /// <summary>\n    ///     Sends a progress report to the asynchronous action or operation to which this progress reporter is bound.\n    /// </summary>\n    /// <param name=\"_Val\">\n    ///     The payload to report through a progress notification.\n    /// </param>\n    /**/\n    void report(const _ProgressType& _Val) const\n    {\n        _M_dispatcher->_Report(_Val);\n    }\n\n    template<typename _ClassPtrType>\n    static progress_reporter _CreateReporter(_ClassPtrType _Ptr)\n    {\n        progress_reporter _Reporter;\n        details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr);\n        _Reporter._M_dispatcher = _PtrType(_PDispatcher);\n        return _Reporter;\n    }\n    progress_reporter() {}\n\nprivate:\n    progress_reporter(details::_ProgressReporterCtorArgType);\n\n    _PtrType _M_dispatcher;\n};\n\nnamespace details\n{\n    //\n    // maps internal definitions for AsyncStatus and defines states that are not client visible\n    //\n    enum _AsyncStatusInternal\n    {\n        _AsyncCreated = -1,  // externally invisible\n        // client visible states (must match AsyncStatus exactly)\n        _AsyncStarted = 0,   // Windows::Foundation::AsyncStatus::Started,\n        _AsyncCompleted = 1, // Windows::Foundation::AsyncStatus::Completed,\n        _AsyncCanceled = 2, // Windows::Foundation::AsyncStatus::Canceled,\n        _AsyncError = 3,     // Windows::Foundation::AsyncStatus::Error,\n        // non-client visible internal states\n        _AsyncCancelPending,\n        _AsyncClosed,\n        _AsyncUndefined\n    };\n\n    //\n    // designates whether the \"GetResults\" method returns a single result (after complete fires) or multiple results\n    // (which are progressively consumable between Start state and before Close is called)\n    //\n    enum _AsyncResultType\n    {\n        SingleResult    = 0x0001,\n        MultipleResults = 0x0002\n    };\n\n    // ***************************************************************************\n    // Template type traits and helpers for async production APIs:\n    //\n\n    struct _ZeroArgumentFunctor { };\n    struct _OneArgumentFunctor { };\n    struct _TwoArgumentFunctor { };\n\n    // ****************************************\n    // CLASS TYPES:\n\n    // ********************\n    // TWO ARGUMENTS:\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1, _Arg2) const);\n\n    // ********************\n    // ONE ARGUMENT:\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);\n\n    // non-void arg:\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    void _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);\n\n    template<typename _Class, typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1) const);\n\n    // ********************\n    // ZERO ARGUMENT:\n\n    // void arg:\n    template<typename _Class, typename _ReturnType>\n    void _Arg1ClassHelperThunk(_ReturnType (_Class::*)() const);\n\n    // void arg:\n    template<typename _Class, typename _ReturnType>\n    void _Arg2ClassHelperThunk(_ReturnType (_Class::*)() const);\n\n    // void arg:\n    template<typename _Class, typename _ReturnType>\n    _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)() const);\n\n    template<typename _Class, typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)() const);\n\n    // ****************************************\n    // POINTER TYPES:\n\n    // ********************\n    // TWO ARGUMENTS:\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    template<typename _ReturnType, typename _Arg1, typename _Arg2>\n    _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));\n\n    // ********************\n    // ONE ARGUMENT:\n\n    template<typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));\n\n    template<typename _ReturnType, typename _Arg1>\n    _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));\n\n    // ********************\n    // ZERO ARGUMENT:\n\n    template<typename _ReturnType>\n    void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());\n\n    template<typename _ReturnType>\n    void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());\n\n    template<typename _ReturnType>\n    void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());\n\n    template<typename _ReturnType>\n    void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());\n\n    template<typename _ReturnType>\n    _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());\n\n    template<typename _ReturnType>\n    _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());\n\n    template<typename _T>\n    struct _FunctorArguments\n    {\n        static const size_t _Count = 0;\n    };\n\n    template<>\n    struct _FunctorArguments<_OneArgumentFunctor>\n    {\n        static const size_t _Count = 1;\n    };\n\n    template<>\n    struct _FunctorArguments<_TwoArgumentFunctor>\n    {\n        static const size_t _Count = 2;\n    };\n\n    template<typename _T>\n    struct _FunctorTypeTraits\n    {\n        typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;\n        static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;\n\n        typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType;\n        typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type;\n        typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type;\n    };\n\n    template<typename _T>\n    struct _FunctorTypeTraits<_T *>\n    {\n        typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType;\n        static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;\n\n        typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType;\n        typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type;\n        typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type;\n    };\n\n    template<typename _T>\n    struct _ProgressTypeTraits\n    {\n        static const bool _TakesProgress = false;\n        typedef void _ProgressType;\n    };\n\n    template<typename _T>\n    struct _ProgressTypeTraits<progress_reporter<_T>>\n    {\n        static const bool _TakesProgress = true;\n        typedef typename _T _ProgressType;\n    };\n\n\n    template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount>\n    struct _CAFunctorOptions\n    {\n        static const bool _TakesProgress = false;\n        static const bool _TakesToken = false;\n        typedef void _ProgressType;\n    };\n\n    template<typename _T>\n    struct _CAFunctorOptions<_T, 1>\n    {\n    private:\n\n        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;\n\n    public:\n\n        static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;\n        static const bool _TakesToken = !_TakesProgress;\n        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;\n    };\n\n    template<typename _T>\n    struct _CAFunctorOptions<_T, 2>\n    {\n    private:\n\n        typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;\n\n    public:\n\n        static const bool _TakesProgress = true;\n        static const bool _TakesToken = true;\n        typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;\n    };\n\n    ref class _Zip\n    {\n    };\n\n    // ***************************************************************************\n    // Async Operation Task Generators\n    //\n\n    //\n    // Functor returns an IAsyncInfo - result needs to be wrapped in a task:\n    //\n    template<typename _AsyncSelector, typename _ReturnType>\n    struct _SelectorTaskGenerator\n    {\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(), _taskOptinos);\n        }\n\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(_Cts.get_token()), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(_Progress), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>(_Func(_Progress, _Cts.get_token()), _taskOptinos);\n        }\n    };\n\n    template<typename _AsyncSelector>\n    struct _SelectorTaskGenerator<_AsyncSelector, void>\n    {\n        template<typename _Function>\n        static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(), _taskOptinos);\n        }\n\n        template<typename _Function>\n        static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(_Cts.get_token()), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(_Progress), _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>(_Func(_Progress, _Cts.get_token()), _taskOptinos);\n        }\n    };\n\n    //\n    // Functor returns a result - it needs to be wrapped in a task:\n    //\n    template<typename _ReturnType>\n    struct _SelectorTaskGenerator<_TypeSelectorNoAsync, _ReturnType>\n    {\n\n#pragma warning(push)\n#pragma warning(disable: 4702)\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func();\n            }, _taskOptinos);\n        }\n#pragma warning(pop)\n\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func(_Cts.get_token());\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func(_Progress);\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<_ReturnType>( [=]() -> _ReturnType {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                return _Func(_Progress, _Cts.get_token());\n            }, _taskOptinos);\n        }\n    };\n\n    template<>\n    struct _SelectorTaskGenerator<_TypeSelectorNoAsync, void>\n    {\n        template<typename _Function>\n        static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func();\n            }, _taskOptinos);\n        }\n\n        template<typename _Function>\n        static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func(_Cts.get_token());\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func(_Progress);\n            }, _taskOptinos);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            task_options _taskOptinos(_Cts.get_token());\n            details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);\n            return task<void>( [=]() {\n                _Task_generator_oversubscriber_t _Oversubscriber;\n                (_Oversubscriber);\n                _Func(_Progress, _Cts.get_token());\n            }, _taskOptinos);\n        }\n    };\n\n    //\n    // Functor returns a task - the task can directly be returned:\n    //\n    template<typename _ReturnType>\n    struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, _ReturnType>\n    {\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func();\n        }\n\n        template<typename _Function>\n        static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Cts.get_token());\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress, _Cts.get_token());\n        }\n    };\n\n    template<>\n    struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, void>\n    {\n        template<typename _Function>\n        static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func();\n        }\n\n        template<typename _Function>\n        static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Cts.get_token());\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress);\n        }\n\n        template<typename _Function, typename _ProgressObject>\n        static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _Func(_Progress, _Cts.get_token());\n        }\n    };\n\n    template<typename _Generator, bool _TakesToken, bool TakesProgress>\n    struct _TaskGenerator\n    {\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, false, false>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_0(_Func, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, true, false>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, false, true>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);\n        }\n    };\n\n    template<typename _Generator>\n    struct _TaskGenerator<_Generator, true, true>\n    {\n        template<typename _Function, typename _ClassPtr, typename _ProgressType>\n        static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n            -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))\n        {\n            return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);\n        }\n    };\n\n    // ***************************************************************************\n    // Async Operation Attributes Classes\n    //\n    // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in\n    // a single container. An attribute class must define:\n    //\n    // Mandatory:\n    // -------------------------\n    //\n    // _AsyncBaseType           : The Windows Runtime interface which is being implemented.\n    // _CompletionDelegateType  : The Windows Runtime completion delegate type for the interface.\n    // _ProgressDelegateType    : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.\n    // _ReturnType              : The return type of the async construct (void for actions / non-void for operations)\n    //\n    // _TakesProgress           : An indication as to whether or not\n    //\n    // _Generate_Task           : A function adapting the user's function into what's necessary to produce the appropriate task\n    //\n    // Optional:\n    // -------------------------\n    //\n\n    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress>\n    struct _AsyncAttributes\n    {\n    };\n\n    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true>\n    {\n        typedef typename Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType;\n        typedef typename Windows::Foundation::AsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType;\n        typedef typename _ReturnType _ReturnType;\n        typedef typename _ProgressType _ProgressType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;\n\n        static const bool _TakesProgress = true;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>\n    {\n        typedef typename Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType;\n        typedef _Zip _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType;\n        typedef typename _ReturnType _ReturnType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;\n\n        static const bool _TakesProgress = false;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>\n    {\n        typedef typename Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType;\n        typedef typename Windows::Foundation::AsyncActionProgressHandler<_ProgressType> _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType;\n        typedef void _ReturnType;\n        typedef typename _ProgressType _ProgressType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;\n\n        static const bool _TakesProgress = true;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>\n    struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>\n    {\n        typedef typename Windows::Foundation::IAsyncAction _AsyncBaseType;\n        typedef _Zip _ProgressDelegateType;\n        typedef typename Windows::Foundation::AsyncActionCompletedHandler _CompletionDelegateType;\n        typedef void _ReturnType;\n        typedef typename _TaskTraits::_AsyncKind _AsyncKind;\n        typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;\n        typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;\n\n        static const bool _TakesProgress = false;\n        static const bool _TakesToken = _TakesToken;\n\n        template<typename _Function, typename _ClassPtr>\n        static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)\n        {\n            return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);\n        }\n    };\n\n    template<typename _Function>\n    struct _AsyncLambdaTypeTraits\n    {\n        typedef typename _FunctorTypeTraits<_Function>::_ReturnType _ReturnType;\n        typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;\n        typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;\n\n        static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;\n        static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;\n\n        typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;\n        typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;\n    };\n\n    // ***************************************************************************\n    // AsyncInfo (and completion) Layer:\n    //\n\n    //\n    // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)\n    //\n    template < typename _Attributes, _AsyncResultType resultType = SingleResult >\n    ref class _AsyncInfoBase abstract : _Attributes::_AsyncBaseType\n    {\n    internal:\n\n        _AsyncInfoBase() : \n            _M_currentStatus(_AsyncStatusInternal::_AsyncCreated), \n            _M_errorCode(S_OK),\n            _M_completeDelegate(nullptr),\n            _M_CompleteDelegateAssigned(0),\n            _M_CallbackMade(0)\n        {\n            _M_id = ::pplx::details::platform::GetNextAsyncId();\n        }\n\n    public:\n        virtual typename _Attributes::_ReturnType GetResults()\n        {\n            throw ::Platform::Exception::CreateException(E_UNEXPECTED);\n        }\n\n        virtual property unsigned int Id\n        {\n            unsigned int get()\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                return _M_id;\n            }\n\n            void set(unsigned int id)\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                if (id == 0)\n                {\n                    throw ::Platform::Exception::CreateException(E_INVALIDARG);\n                }\n                else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n                }\n\n                _M_id = id;\n            }\n        }\n\n        virtual property Windows::Foundation::AsyncStatus Status\n        {\n            Windows::Foundation::AsyncStatus get()\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                _AsyncStatusInternal _Current = _M_currentStatus;\n\n                //\n                // Map our internal cancel pending to cancelled. This way \"pending cancelled\" looks to the outside as \"cancelled\" but\n                // can still transition to \"completed\" if the operation completes without acknowledging the cancellation request\n                //\n                switch(_Current)\n                {\n                    case _AsyncCancelPending:\n                        _Current = _AsyncCanceled;\n                        break;\n                    case _AsyncCreated:\n                        _Current = _AsyncStarted;\n                        break;\n                    default:\n                        break;\n                }\n\n                return static_cast<Windows::Foundation::AsyncStatus>(_Current);\n            }\n        }\n\n        virtual property Windows::Foundation::HResult ErrorCode\n        {\n            Windows::Foundation::HResult get()\n            {\n                _CheckValidStateForAsyncInfoCall();\n\n                Windows::Foundation::HResult _Hr;\n                _Hr.Value = _M_errorCode;\n                return _Hr;\n            }\n        }\n\n        virtual property typename _Attributes::_ProgressDelegateType^ Progress\n        {\n            typename typename _Attributes::_ProgressDelegateType^ get()\n            {\n                return _GetOnProgress();\n            }\n\n            void set(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)\n            {\n                _PutOnProgress(_ProgressHandler);\n            }\n        }\n\n        virtual void Cancel()\n        {\n            if (_TransitionToState(_AsyncCancelPending))\n            {\n                _OnCancel();\n            }\n        }\n\n        virtual void Close()\n        {\n            if (_TransitionToState(_AsyncClosed))\n            {\n                _OnClose();\n            }\n            else\n            {\n                if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);\n                }\n            }\n        }\n\n        virtual property typename _Attributes::_CompletionDelegateType^ Completed\n        {\n            typename _Attributes::_CompletionDelegateType^ get()\n            {\n                _CheckValidStateForDelegateCall();\n                return _M_completeDelegate;\n            }\n\n            void set(typename _Attributes::_CompletionDelegateType^ _CompleteHandler)\n            {\n                _CheckValidStateForDelegateCall();\n                // this delegate property is \"write once\"\n                if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1)\n                {\n                    _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();\n                    _M_completeDelegate = _CompleteHandler;\n                    // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below\n                    // as perceived from _FireCompletion on another thread.\n                    MemoryBarrier();\n                    if (_IsTerminalState())\n                    {\n                        _FireCompletion();\n                    }\n                }\n                else\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_DELEGATE_ASSIGNMENT);\n                }\n            }\n        }\n\n\n    protected private:\n\n        // _Start - this is not externally visible since async operations \"hot start\" before returning to the caller\n        void _Start()\n        {\n            if (_TransitionToState(_AsyncStarted))\n            {\n                _OnStart();\n            }\n            else\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);\n            }\n        }\n\n\n        void _FireCompletion()\n        {\n            _TryTransitionToCompleted();\n\n            // we guarantee that completion can only ever be fired once\n            if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)\n            {\n                _M_completeDelegateContext._CallInContext([=] {\n                    _M_completeDelegate((_Attributes::_AsyncBaseType^)this, this->Status);\n                    _M_completeDelegate = nullptr;\n                });\n            }\n        }\n\n        virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress()\n        {\n            throw ::Platform::Exception::CreateException(E_UNEXPECTED);\n        }\n\n        virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)\n        {\n            throw ::Platform::Exception::CreateException(E_UNEXPECTED);\n        }\n\n        bool _TryTransitionToCompleted()\n        {\n            return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);\n        }\n\n        bool _TryTransitionToCancelled()\n        {\n            return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);\n        }\n\n        bool _TryTransitionToError(const HRESULT error)\n        {\n            _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);\n            return _TransitionToState(_AsyncStatusInternal::_AsyncError);\n        }\n\n        // This method checks to see if the delegate properties can be\n        // modified in the current state and generates the appropriate\n        // error hr in the case of violation.\n        inline void _CheckValidStateForDelegateCall()\n        {\n            if (_M_currentStatus == _AsyncClosed)\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n            }\n        }\n\n        // This method checks to see if results can be collected in the\n        // current state and generates the appropriate error hr in\n        // the case of a violation.\n        inline void _CheckValidStateForResultsCall()\n        {\n            _AsyncStatusInternal _Current = _M_currentStatus;\n\n            if (_Current == _AsyncError)\n            {\n                throw ::Platform::Exception::CreateException(_M_errorCode);\n            }\n#pragma warning(push)\n#pragma warning(disable: 4127) // Conditional expression is constant\n            // single result illegal before transition to Completed or Cancelled state\n            if (resultType == SingleResult)\n#pragma warning(pop)\n            {\n                if (_Current != _AsyncCompleted)\n                {\n                    throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n                }\n            }\n            // multiple results can be called after Start has been called and before/after Completed\n            else if (_Current != _AsyncStarted &&\n                     _Current != _AsyncCancelPending &&\n                     _Current != _AsyncCanceled &&\n                     _Current != _AsyncCompleted)\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n            }\n        }\n\n        // This method can be called by derived classes periodically to determine\n        // whether the asynchronous operation should continue processing or should\n        // be halted.\n        inline bool _ContinueAsyncOperation()\n        {\n            return (_M_currentStatus == _AsyncStarted);\n        }\n\n        // These two methods are used to allow the async worker implementation do work on\n        // state transitions. No real \"work\" should be done in these methods. In other words\n        // they should not block for a long time on UI timescales.\n        virtual void _OnStart() = 0;\n        virtual void _OnClose() = 0;\n        virtual void _OnCancel() = 0;\n\n    private:\n\n        // This method is used to check if calls to the AsyncInfo properties\n        // (id, status, errorcode) are legal in the current state. It also\n        // generates the appropriate error hr to return in the case of an\n        // illegal call.\n        inline void _CheckValidStateForAsyncInfoCall()\n        {\n            _AsyncStatusInternal _Current = _M_currentStatus;\n            if (_Current == _AsyncClosed)\n            {\n                throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);\n            }\n            else if (_Current == _AsyncCreated)\n            {\n                throw ::Platform::Exception::CreateException(E_ASYNC_OPERATION_NOT_STARTED);\n            }\n\n        }\n\n        inline bool _TransitionToState(const _AsyncStatusInternal _NewState)\n        {\n            _AsyncStatusInternal _Current = _M_currentStatus;\n\n            // This enforces the valid state transitions of the asynchronous worker object\n            // state machine.\n            switch(_NewState)\n            {\n            case _AsyncStatusInternal::_AsyncStarted:\n                if (_Current != _AsyncCreated)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncCompleted:\n                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncCancelPending:\n                if (_Current != _AsyncStarted)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncCanceled:\n                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncError:\n                if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)\n                {\n                    return false;\n                }\n                break;\n            case _AsyncStatusInternal::_AsyncClosed:\n                if (!_IsTerminalState(_Current))\n                {\n                    return false;\n                }\n                break;\n            default:\n                return false;\n                break;\n            }\n\n            // attempt the transition to the new state\n            // Note: if currentStatus_ == _Current, then there was no intervening write\n            // by the async work object and the swap succeeded.\n            _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(\n                    _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus),\n                                                _NewState,\n                                                static_cast<LONG>(_Current)));\n\n            // ICE returns the former state, if the returned state and the\n            // state we captured at the beginning of this method are the same,\n            // the swap succeeded.\n            return (_RetState == _Current);\n        }\n\n        inline bool _IsTerminalState()\n        {\n            return _IsTerminalState(_M_currentStatus);\n        }\n\n        inline bool _IsTerminalState(_AsyncStatusInternal status)\n        {\n            return (status == _AsyncError ||\n                    status == _AsyncCanceled ||\n                    status == _AsyncCompleted ||\n                    status == _AsyncClosed);\n        }\n\n    private:\n\n        _ContextCallback        _M_completeDelegateContext;\n        typename _Attributes::_CompletionDelegateType^  volatile _M_completeDelegate;\n        _AsyncStatusInternal volatile                   _M_currentStatus;\n        HRESULT volatile                                _M_errorCode;\n        unsigned int                                    _M_id;\n        long volatile                                   _M_CompleteDelegateAssigned;\n        long volatile                                   _M_CallbackMade;\n    };\n\n    // ***************************************************************************\n    // Progress Layer (optional):\n    //\n\n    template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >\n    ref class _AsyncProgressBase abstract : _AsyncInfoBase<_Attributes, _ResultType>\n    {\n    };\n\n    template< typename _Attributes, _AsyncResultType _ResultType>\n    ref class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : _AsyncInfoBase<_Attributes, _ResultType>\n    {\n    internal:\n\n        _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),\n            _M_progressDelegate(nullptr)\n        {\n        }\n\n        virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress() override\n        {\n            _CheckValidStateForDelegateCall();\n            return _M_progressDelegate;\n        }\n\n        virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) override\n        {\n            _CheckValidStateForDelegateCall();\n            _M_progressDelegate = _ProgressHandler;\n            _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();\n        }\n\n        void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue)\n        {\n            if (_M_progressDelegate != nullptr)\n            {\n                _M_progressDelegateContext._CallInContext([=] {\n                    _M_progressDelegate((_Attributes::_AsyncBaseType^)this, _ProgressValue);\n                });\n            }\n        }\n\n    private:\n\n        _ContextCallback _M_progressDelegateContext;\n        typename _Attributes::_ProgressDelegateType^ _M_progressDelegate;\n    };\n\n    template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>\n    ref class _AsyncBaseProgressLayer abstract : _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>\n    {\n    };\n\n    // ***************************************************************************\n    // Task Adaptation Layer:\n    //\n\n    //\n    // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.\n    //\n    template<typename _Attributes, typename _ReturnType>\n    ref class _AsyncTaskThunkBase abstract : _AsyncBaseProgressLayer<_Attributes>\n    {\n    public:\n\n        virtual _ReturnType GetResults() override\n        {\n            _CheckValidStateForResultsCall();\n            return _M_task.get();\n        }\n\n    internal:\n\n        typedef task<_ReturnType> _TaskType;\n\n        _AsyncTaskThunkBase(const _TaskType& _Task)\n            : _M_task(_Task)\n        {\n        }\n\n        _AsyncTaskThunkBase()\n        {\n        }\n\n    protected:\n\n        virtual void _OnStart() override\n        {\n            _M_task.then( [=](_TaskType _Antecedent) {\n                try\n                {\n                    _Antecedent.get();\n                }\n                catch(task_canceled&)\n                {\n                    _TryTransitionToCancelled();\n                }\n                catch(::Platform::Exception^ _Ex)\n                {\n                    _TryTransitionToError(_Ex->HResult);\n                }\n                catch(...)\n                {\n                    _TryTransitionToError(E_FAIL);\n                }\n                _FireCompletion();\n            });\n        }\n\n    internal:\n\n        _TaskType _M_task;\n        cancellation_token_source _M_cts;\n    };\n\n    template<typename _Attributes>\n    ref class _AsyncTaskThunk : _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType>\n    {\n    internal:\n\n        _AsyncTaskThunk(const _TaskType& _Task) :\n            _AsyncTaskThunkBase(_Task)\n        {\n        }\n\n        _AsyncTaskThunk()\n        {\n        }\n\n    protected:\n\n        virtual void _OnClose() override\n        {\n        }\n\n        virtual void _OnCancel() override\n        {\n            _M_cts.cancel();\n        }\n    };\n\n    // ***************************************************************************\n    // Async Creation Layer:\n    //\n    template<typename _Function>\n    ref class _AsyncTaskGeneratorThunk sealed : _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>\n    {\n    internal:\n\n        typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;\n        typedef typename _AsyncTaskThunk<_Attributes> _Base;\n        typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;\n\n        _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack)\n        {\n            // Virtual call here is safe as the class is declared 'sealed'\n            _Start();\n        }\n\n    protected:\n\n        //\n        // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,\n        // let the base thunk handle everything.\n        //\n\n        virtual void _OnStart() override\n        {\n            //\n            // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,\n            // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.\n            //\n            _M_task = _Attributes::_Generate_Task(_M_func, this, _M_cts, _M_creationCallstack);\n            _Base::_OnStart();\n        }\n\n        virtual void _OnCancel() override\n        {\n            _Base::_OnCancel();\n        }\n\n    private:\n        _TaskCreationCallstack _M_creationCallstack;\n        _Function _M_func;\n    };\n} // namespace details\n\n/// <summary>\n///     Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of <c>create_async</c> is\n///     one of either <c>IAsyncAction^</c>, <c>IAsyncActionWithProgress&lt;TProgress&gt;^</c>, <c>IAsyncOperation&lt;TResult&gt;^</c>, or\n///     <c>IAsyncOperationWithProgress&lt;TResult, TProgress&gt;^</c> based on the signature of the lambda passed to the method.\n/// </summary>\n/// <param name=\"_Func\">\n///     The lambda or function object from which to create a Windows Runtime asynchronous construct.\n/// </param>\n/// <returns>\n///     An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress&lt;TProgress&gt;^, IAsyncOperation&lt;TResult&gt;^, or an\n///     IAsyncOperationWithProgress&lt;TResult, TProgress&gt;^. The interface returned depends on the signature of the lambda passed into the function.\n/// </returns>\n/// <remarks>\n///     The return type of the lambda determines whether the construct is an action or an operation.\n///     <para>Lambdas that return void cause the creation of actions. Lambdas that return a result of type <c>TResult</c> cause the creation of\n///     operations of TResult.</para>\n///     <para>The lambda may also return a <c>task&lt;TResult&gt;</c> which encapsulates the aysnchronous work within itself or is the continuation of\n///     a chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since the tasks are the ones that\n///     execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by <c>create_async</c>.\n///     This implies that a lambda that returns a task&lt;void&gt; will cause the creation of actions, and a lambda that returns a task&lt;TResult&gt; will\n///     cause the creation of operations of TResult.</para>\n///     <para>The lambda may take either zero, one or two arguments. The valid arguments are <c>progress_reporter&lt;TProgress&gt;</c> and\n///     <c>cancellation_token</c>, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without\n///     the capability for progress reporting. A lambda that takes a progress_reporter&lt;TProgress&gt; will cause <c>create_async</c> to return an asynchronous\n///     construct which reports progress of type TProgress each time the <c>report</c> method of the progress_reporter object is called. A lambda that\n///     takes a cancellation_token may use that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the\n///     asynchronous construct causes cancellation of those tasks.</para>\n///     <para>If the body of the lambda or function object returns a result (and not a task&lt;TResult&gt;), the lamdba will be executed\n///     asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The <c>IAsyncInfo::Cancel</c> method will\n///     cause cancellation of the implicit task.</para>\n///     <para>If the body of the lambda returns a task, the lamba executes inline, and by declaring the lambda to take an argument of type\n///     <c>cancellation_token</c> you can trigger cancellation of any tasks you create within the lambda by passing that token in when you create them.\n///     You may also use the <c>register_callback</c> method on the token to cause the Runtime to invoke a callback when you call <c>IAsyncInfo::Cancel</c> on\n///     the async operation or action produced..</para>\n///     <para>This function is only available to Windows Store apps.</para>\n/// </remarks>\n/// <seealso cref=\"task Class\"/>\n/// <seealso cref=\"progress_reporter Class\"/>\n/// <seealso cref=\"cancelation_token Class\"/>\n/**/\ntemplate<typename _Function>\n__declspec(noinline)\ndetails::_AsyncTaskGeneratorThunk<_Function> ^create_async(const _Function& _Func)\n{\n    static_assert(std::is_same<decltype(details::_IsValidCreateAsync(_Func,0,0,0,0)),std::true_type>::value,\n        \"argument to create_async must be a callable object taking zero, one or two arguments\");\n    return ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func, _CAPTURE_CALLSTACK());\n}\n\n#endif  /* defined (__cplusplus_winrt) */\n\nnamespace details\n{\n    // Helper struct for when_all operators to know when tasks have completed\n    template<typename _Type>\n    struct _RunAllParam\n    {\n        _RunAllParam() : _M_completeCount(0), _M_numTasks(0)\n        {\n        }\n\n        void _Resize(size_t _Len, bool _SkipVector = false)\n        {\n            _M_numTasks = _Len;\n            if (!_SkipVector)\n            {\n                _M_vector._Result.resize(_Len);\n            }\n        }\n\n        task_completion_event<_Unit_type>       _M_completed;\n        _ResultHolder<std::vector<_Type> >      _M_vector;\n        _ResultHolder<_Type>                    _M_mergeVal;\n        atomic_size_t                           _M_completeCount;\n        size_t                                  _M_numTasks;\n    };\n\n    template<typename _Type>\n    struct _RunAllParam<std::vector<_Type> >\n    {\n        _RunAllParam() : _M_completeCount(0), _M_numTasks(0)\n        {\n        }\n\n        void _Resize(size_t _Len, bool _SkipVector = false)\n        {\n            _M_numTasks = _Len;\n            \n            if (!_SkipVector)\n            {\n                _M_vector.resize(_Len);\n            }\n        }\n\n        task_completion_event<_Unit_type>       _M_completed;\n        std::vector<_ResultHolder<std::vector<_Type> > >  _M_vector;\n        atomic_size_t                           _M_completeCount;\n        size_t                                  _M_numTasks;\n    };\n\n    // Helper struct specialization for void\n    template<>\n    struct _RunAllParam<_Unit_type>\n    {\n        _RunAllParam() : _M_completeCount(0), _M_numTasks(0)\n        {\n        }\n\n        void _Resize(size_t _Len)\n        {\n            _M_numTasks = _Len;\n        }\n\n        task_completion_event<_Unit_type> _M_completed;\n        atomic_size_t _M_completeCount;\n        size_t _M_numTasks;\n    };\n\n    inline void _JoinAllTokens_Add(const cancellation_token_source& _MergedSrc, _CancellationTokenState *_PJoinedTokenState)\n    {\n        if (_PJoinedTokenState != nullptr && _PJoinedTokenState != _CancellationTokenState::_None())\n        {\n            cancellation_token _T = cancellation_token::_FromImpl(_PJoinedTokenState);\n            _T.register_callback( [=](){\n                _MergedSrc.cancel();\n                });\n        }\n    }\n\n    template<typename _ElementType, typename _Function, typename _TaskType>\n    void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task)\n    {\n        if (_Task._GetImpl()->_IsCompleted())\n        {\n            _Func();\n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                // Inline execute its direct continuation, the _ReturnTask\n                _PParam->_M_completed.set(_Unit_type());\n                // It's safe to delete it since all usage of _PParam in _ReturnTask has been finished.\n                delete _PParam;\n            }\n        }\n        else\n        {\n            _ASSERTE(_Task._GetImpl()->_IsCanceled());\n            if (_Task._GetImpl()->_HasUserException())\n            {\n                // _Cancel will return false if the TCE is already canceled with or without exception\n                _PParam->_M_completed._Cancel(_Task._GetImpl()->_GetExceptionHolder());\n            }\n            else\n            {\n                _PParam->_M_completed._Cancel();\n            }\n\n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                delete _PParam;\n            }\n        }\n    }\n\n    template<typename _ElementType, typename _Iterator>\n    struct _WhenAllImpl\n    {\n        static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n\n            auto _PParam = new _RunAllParam<_ElementType>();\n            cancellation_token_source _MergedSource;\n\n            // Step1: Create task completion event.\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_MergedSource.get_token());\n            task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);\n            // The return task must be created before step 3 to enforce inline execution.\n            auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {\n                return _PParam->_M_vector.Get();\n            }, nullptr);\n\n            // Step2: Combine and check tokens, and count elements in range.\n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_MergedSource, _PTokenState);\n                _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));\n            }\n            else\n            {\n                size_t _TaskNum = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    _TaskNum++;\n                    _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);\n                }\n                _PParam->_Resize(_TaskNum);\n            }\n\n            // Step3: Check states of previous tasks.\n            if( _Begin == _End )\n            {\n                _PParam->_M_completed.set(_Unit_type());\n                delete _PParam;\n            }\n            else\n            {\n                size_t _Index = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    if (_PTask->is_apartment_aware())\n                    {\n                        _ReturnTask._SetAsync();\n                    }\n\n                    _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {\n\n                        auto _PParamCopy = _PParam;\n                        auto _IndexCopy = _Index;\n                        auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){\n                            _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult();\n                        };\n\n                        _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n                    }, _CancellationTokenState::_None()); \n\n                    _Index++;\n                }\n            }\n\n            return _ReturnTask;\n        }\n    };\n\n    template<typename _ElementType, typename _Iterator>\n    struct _WhenAllImpl<std::vector<_ElementType>, _Iterator>\n    {\n        static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n\n            auto _PParam = new _RunAllParam<std::vector<_ElementType>>();\n            cancellation_token_source _MergedSource;\n\n            // Step1: Create task completion event.\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_MergedSource.get_token());\n            task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);\n            // The return task must be created before step 3 to enforce inline execution.\n            auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {\n                _ASSERTE(_PParam->_M_completeCount ==  _PParam->_M_numTasks);\n                std::vector<_ElementType> _Result;\n                for(size_t _I = 0; _I < _PParam->_M_numTasks; _I++)\n                {\n                    const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get();\n                    _Result.insert(_Result.end(), _Vec.begin(), _Vec.end());\n                }\n                return _Result;\n            }, nullptr);\n\n            // Step2: Combine and check tokens, and count elements in range.\n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_MergedSource, _PTokenState);\n                _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));\n            }\n            else\n            {\n                size_t _TaskNum = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    _TaskNum++;\n                    _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);\n                }\n                _PParam->_Resize(_TaskNum);\n            }\n\n            // Step3: Check states of previous tasks.\n            if( _Begin == _End )\n            {\n                _PParam->_M_completed.set(_Unit_type());\n                delete _PParam;\n            }\n            else\n            {\n                size_t _Index = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    if (_PTask->is_apartment_aware())\n                    {\n                        _ReturnTask._SetAsync();\n                    }\n\n                    _PTask->_Then([_PParam, _Index](task<std::vector<_ElementType>> _ResultTask) {\n\n                        auto _PParamCopy = _PParam;\n                        auto _IndexCopy = _Index;\n                        auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() {\n                            _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult());\n                        };\n\n                        _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n                    }, _CancellationTokenState::_None());\n\n                    _Index++;\n                }\n            }\n\n            return  _ReturnTask;\n        }\n    };\n\n    template<typename _Iterator>\n    struct _WhenAllImpl<void, _Iterator>\n    {\n        static task<void> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n\n            auto _PParam = new _RunAllParam<_Unit_type>();\n            cancellation_token_source _MergedSource;\n\n            // Step1: Create task completion event.\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_MergedSource.get_token());\n            task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);\n            // The return task must be created before step 3 to enforce inline execution.\n            auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) {\n            }, nullptr);\n\n            // Step2: Combine and check tokens, and count elements in range.\n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_MergedSource, _PTokenState);\n                _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));\n            }\n            else\n            {\n                size_t _TaskNum = 0;\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    _TaskNum++;\n                    _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);\n                }\n                _PParam->_Resize(_TaskNum);\n            }\n\n            // Step3: Check states of previous tasks.\n            if( _Begin == _End )\n            {\n                _PParam->_M_completed.set(_Unit_type());\n                delete _PParam;\n            }\n            else\n            {\n                for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n                {\n                    if (_PTask->is_apartment_aware())\n                    {\n                        _ReturnTask._SetAsync();\n                    }\n\n                    _PTask->_Then([_PParam](task<void> _ResultTask) {\n                        auto _Func = [](){};\n                        _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n                    }, _CancellationTokenState::_None());\n                }\n            }\n\n            return _ReturnTask;\n        }\n    };\n\n    template<typename _ReturnType>\n    task<std::vector<_ReturnType>> _WhenAllVectorAndValue(const task<std::vector<_ReturnType>>& _VectorTask, const task<_ReturnType>& _ValueTask,\n                                                          bool _OutputVectorFirst)\n    {\n        auto _PParam = new _RunAllParam<_ReturnType>();\n        cancellation_token_source _MergedSource;\n\n        // Step1: Create task completion event.\n        task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());\n        // The return task must be created before step 3 to enforce inline execution.\n        auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ReturnType> {\n            _ASSERTE(_PParam->_M_completeCount == 2);\n            auto _Result = _PParam->_M_vector.Get(); // copy by value\n            auto _mergeVal = _PParam->_M_mergeVal.Get();\n\n            if (_OutputVectorFirst == true)\n            {                \n                _Result.push_back(_mergeVal);\n            }\n            else\n            {\n                _Result.insert(_Result.begin(), _mergeVal);\n            }\n            return _Result;\n        }, nullptr);\n\n        // Step2: Combine and check tokens.\n        _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState);\n        _JoinAllTokens_Add(_MergedSource, _ValueTask._GetImpl()->_M_pTokenState);\n\n        // Step3: Check states of previous tasks.\n        _PParam->_Resize(2, true);\n\n        if (_VectorTask.is_apartment_aware() || _ValueTask.is_apartment_aware())\n        {\n            _ReturnTask._SetAsync();\n        }\n        _VectorTask._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {\n            auto _PParamCopy = _PParam;\n            auto _Func = [_PParamCopy, &_ResultTask]() {\n                auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();\n                _PParamCopy->_M_vector.Set(_ResultLocal);\n            };\n\n            _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n        }, _CancellationTokenState::_None());\n        _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) {\n            auto _PParamCopy = _PParam;\n            auto _Func = [_PParamCopy, &_ResultTask]() {\n                auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();\n                _PParamCopy->_M_mergeVal.Set(_ResultLocal);\n            };\n\n            _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);\n        }, _CancellationTokenState::_None());\n\n        return _ReturnTask;\n    }\n} // namespace details\n\n/// <summary>\n///     Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_Iterator\">\n///     The type of the input iterator.\n/// </typeparam>\n/// <param name=\"_Begin\">\n///     The position of the first element in the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_End\">\n///     The position of the first element beyond the range of elements to be combined into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate <typename _Iterator>\nauto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options()) \n    -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))\n{\n    typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;\n    return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs};\n    return when_all(_PTasks, _PTasks+2);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)\n{\n    return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)\n{\n    task<std::vector<_ReturnType>> _PTasks[2] = {_Lhs, _Rhs};\n    return when_all(_PTasks, _PTasks+2);\n}\n\n/// <summary>\n///     Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;&gt;</c>. If the input tasks are of type <c>void</c> the output\n///     task will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA &amp;&amp; taskB &amp;&amp; taskC, which are combined in pairs, the &amp;&amp; operator\n///     produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if either one or both of the tasks are of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>.</para>\n/// </returns>\n/// <remarks>\n///     If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,\n///     if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ninline task<void> operator&&(const task<void> & _Lhs, const task<void> & _Rhs)\n{\n    task<void> _PTasks[2] = {_Lhs, _Rhs};\n    return when_all(_PTasks, _PTasks+2);\n}\n\nnamespace details\n{\n    // Helper struct for when_any operators to know when tasks have completed\n    template <typename _CompletionType>\n    struct _RunAnyParam\n    {\n        _RunAnyParam() : _M_exceptionRelatedToken(nullptr), _M_completeCount(0), _M_numTasks(0), _M_fHasExplicitToken(false)\n        {\n        }\n        ~_RunAnyParam()\n        {\n            if (_CancellationTokenState::_IsValid(_M_exceptionRelatedToken))\n                _M_exceptionRelatedToken->_Release();\n        }\n        task_completion_event<_CompletionType>      _M_Completed;\n        cancellation_token_source                   _M_cancellationSource;\n        _CancellationTokenState *                   _M_exceptionRelatedToken;\n        atomic_size_t                               _M_completeCount;\n        size_t                                      _M_numTasks;\n        bool                                        _M_fHasExplicitToken;\n    };\n\n    template<typename _CompletionType, typename _Function, typename _TaskType>\n    void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task)\n    {\n        bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != _CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled();\n        if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled)\n        {\n            _Func();\n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                delete _PParam;\n            }\n        }\n        else\n        {\n            _ASSERTE(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled);\n            if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled)\n            {\n                if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder()))\n                {\n                    // This can only enter once.\n                    _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState;\n                    _ASSERTE(_PParam->_M_exceptionRelatedToken);\n                    // Deref token will be done in the _PParam destructor.\n                    if (_PParam->_M_exceptionRelatedToken != _CancellationTokenState::_None())\n                    {\n                        _PParam->_M_exceptionRelatedToken->_Reference();\n                    }\n                }\n            }\n            \n            if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)\n            {\n                // If no one has be completed so far, we need to make some final cancellation decision.\n                if (!_PParam->_M_Completed._IsTriggered())\n                {\n                    // If we already explicit token, we can skip the token join part.\n                    if (!_PParam->_M_fHasExplicitToken)\n                    {\n                        if (_PParam->_M_exceptionRelatedToken)\n                        {\n                            _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken);\n                        }\n                        else\n                        {\n                            // If haven't captured any exception token yet, there was no exception for all those tasks,\n                            // so just pick a random token (current one) for normal cancellation.\n                            _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState);\n                        }\n                    }\n                    // Do exception cancellation or normal cancellation based on whether it has stored exception.\n                    _PParam->_M_Completed._Cancel();\n                }\n                delete _PParam;\n            }\n        }\n    }\n\n    template<typename _ElementType, typename _Iterator>\n    struct _WhenAnyImpl\n    {\n        static task<std::pair<_ElementType, size_t>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            if( _Begin == _End )\n            {\n                throw invalid_operation(\"when_any(begin, end) cannot be called on an empty container.\");\n            }\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n            auto _PParam = new _RunAnyParam<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>>();\n            \n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);\n                _PParam->_M_fHasExplicitToken = true;\n            }\n            \n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());\n            task<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options); \n\n            // Keep a copy ref to the token source\n            auto _CancellationSource = _PParam->_M_cancellationSource;\n\n            _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));\n            size_t _Index = 0;\n            for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n            {\n                if (_PTask->is_apartment_aware())\n                {\n                    _Any_tasks_completed._SetAsync();\n                }\n\n                _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {\n                    auto _PParamCopy = _PParam; // Dev10\n                    auto _IndexCopy = _Index; // Dev10\n                    auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {\n                        _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy),  _ResultTask._GetImpl()->_M_pTokenState));\n                    };\n\n                    _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n                }, _CancellationTokenState::_None());\n\n                _Index++;\n            }\n\n            // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.\n            return _Any_tasks_completed._Then([=](std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *> _Result) -> std::pair<_ElementType, size_t> {\n                _ASSERTE(_Result.second);\n                if (!_PTokenState)\n                {\n                    _JoinAllTokens_Add(_CancellationSource, _Result.second);\n                }\n                return _Result.first;\n            }, nullptr);\n        }\n    };\n\n    template<typename _Iterator>\n    struct _WhenAnyImpl<void, _Iterator>\n    {\n        static task<size_t> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)\n        {\n            if( _Begin == _End )\n            {\n                throw invalid_operation(\"when_any(begin, end) cannot be called on an empty container.\");\n            }\n\n            _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;\n            auto _PParam = new _RunAnyParam<std::pair<size_t, _CancellationTokenState *>>();\n            \n            if (_PTokenState)\n            {\n                _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);\n                _PParam->_M_fHasExplicitToken = true;\n            }\n\n            task_options _Options(_TaskOptions);\n            _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());\n            task<std::pair<size_t, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);\n\n            // Keep a copy ref to the token source\n            auto _CancellationSource = _PParam->_M_cancellationSource;\n\n            _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));\n            size_t _Index = 0;\n            for (auto _PTask = _Begin; _PTask != _End; ++_PTask)\n            {\n                if (_PTask->is_apartment_aware())\n                {\n                    _Any_tasks_completed._SetAsync();\n                }\n\n                _PTask->_Then([_PParam, _Index](task<void> _ResultTask) {\n                    auto _PParamCopy = _PParam; // Dev10\n                    auto _IndexCopy = _Index; // Dev10\n                    auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {\n                        _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState));\n                    };\n                    _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n                }, _CancellationTokenState::_None());\n\n                _Index++;\n            }\n\n            // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.\n            return _Any_tasks_completed._Then([=](std::pair<size_t, _CancellationTokenState *> _Result) -> size_t {\n                _ASSERTE(_Result.second);\n                if (!_PTokenState)\n                {\n                    _JoinAllTokens_Add(_CancellationSource, _Result.second);\n                }\n                return _Result.first;\n            }, nullptr);\n        }\n    };\n} // namespace details\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_Iterator\">\n///     The type of the input iterator.\n/// </typeparam>\n/// <param name=\"_Begin\">\n///     The position of the first element in the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_End\">\n///     The position of the first element beyond the range of elements to be combined into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::pair&lt;T, size_t&gt;&gt;></c>, where the first element of the pair is the result\n///     of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c>\n///     the output is a <c>task&lt;size_t&gt;</c>, where the result is the index of the completing task.\n/// </returns>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _Iterator>\nauto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())\n    -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))\n{\n    typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;\n    return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_Iterator\">\n///     The type of the input iterator.\n/// </typeparam>\n/// <param name=\"_Begin\">\n///     The position of the first element in the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_End\">\n///     The position of the first element beyond the range of elements to be combined into the resulting task.\n/// </param>\n/// <param name=\"_CancellationToken\">\n///     The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting\n///     task will receive the cancellation token of the task that causes it to complete.\n/// </param>\n/// <returns>\n///     A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::pair&lt;T, size_t&gt;&gt;></c>, where the first element of the pair is the result\n///     of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c>\n///     the output is a <c>task&lt;size_t&gt;</c>, where the result is the index of the completing task.\n/// </returns>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _Iterator>\nauto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken)\n    -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))\n{\n    typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;\n    return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when either of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, size_t>>();\n\n    task<std::pair<_ReturnType, size_t>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());\n    // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,\n    // So that _PParam can be used before it getting deleted.\n    auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret) -> _ReturnType {\n        _ASSERTE(_Ret.second);\n        _JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast<details::_CancellationTokenState *>(_Ret.second));\n        return _Ret.first;\n    }, nullptr);\n\n    if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())\n    {\n        _ReturnTask._SetAsync();\n    }\n\n    _PParam->_M_numTasks = 2;\n    auto _Continuation = [_PParam](task<_ReturnType> _ResultTask) {\n        //  Dev10 compiler bug\n        auto _PParamCopy = _PParam;\n        auto _Func = [&_ResultTask, _PParamCopy]() {\n            _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast<size_t>(_ResultTask._GetImpl()->_M_pTokenState)));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    };\n\n    _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());\n    _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());\n\n    return _ReturnTask;\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator||(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)\n{\n    auto _PParam = new details::_RunAnyParam<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>>();\n\n    task<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());\n\n    // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,\n    // So that _PParam can be used before it getting deleted.\n    auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *> _Ret) -> std::vector<_ReturnType> {\n        _ASSERTE(_Ret.second);\n        _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);\n        return _Ret.first;\n    }, nullptr);\n\n    if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())\n    {\n        _ReturnTask._SetAsync();\n    }\n\n    _PParam->_M_numTasks = 2;\n    _Lhs._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {\n        //  Dev10 compiler bug\n        auto _PParamCopy = _PParam;\n        auto _Func = [&_ResultTask, _PParamCopy]() {\n            auto _Result = _ResultTask._GetImpl()->_GetResult();\n            _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    }, details::_CancellationTokenState::_None());\n\n    \n    _Rhs._Then([_PParam](task<_ReturnType> _ResultTask) \n    {\n        auto _PParamCopy = _PParam;\n        auto _Func = [&_ResultTask, _PParamCopy]() {\n            auto _Result = _ResultTask._GetImpl()->_GetResult();\n\n            std::vector<_ReturnType> _Vec;\n            _Vec.push_back(_Result);\n            _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    }, details::_CancellationTokenState::_None());\n\n    return _ReturnTask;\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ntemplate<typename _ReturnType>\ntask<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)\n{\n    return _Rhs || _Lhs;\n}\n\n/// <summary>\n///     Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.\n/// </summary>\n/// <typeparam name=\"_ReturnType\">\n///     The type of the returned task.\n/// </typeparam>\n/// <param name=\"_Lhs\">\n///     The first task to combine into the resulting task.\n/// </param>\n/// <param name=\"_Rhs\">\n///     The second task to combine into the resulting task.\n/// </param>\n/// <returns>\n///     A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,\n///     the output of this function will be a <c>task&lt;std::vector&lt;T&gt;</c>. If the input tasks are of type <c>void</c> the output task\n///     will also be a <c>task&lt;void&gt;</c>.\n///     <para> To allow for a construct of the sort taskA || taskB &amp;&amp; taskC, which are combined in pairs, with &amp;&amp; taking precedence\n///     over ||, the operator|| produces a <c>task&lt;std::vector&lt;T&gt;&gt;</c> if one of the tasks is of type <c>task&lt;std::vector&lt;T&gt;&gt;</c>\n///     and the other one is of type <c>task&lt;T&gt;.</c></para>\n/// </returns>\n/// <remarks>\n///     If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,\n///     if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.\n/// </remarks>\n/// <seealso cref=\"Task Parallelism (Concurrency Runtime)\"/>\n/**/\ninline task<void> operator||(const task<void> & _Lhs, const task<void> & _Rhs)\n{\n    auto _PParam = new details::_RunAnyParam<std::pair<details::_Unit_type, details::_CancellationTokenState *>>();\n\n    task<std::pair<details::_Unit_type, details::_CancellationTokenState *>> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());\n    // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,\n    // So that _PParam can be used before it getting deleted.\n    auto _ReturnTask = _Any_task_completed._Then([=](std::pair<details::_Unit_type, details::_CancellationTokenState *> _Ret) { \n        _ASSERTE(_Ret.second);\n        details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);\n    }, nullptr);\n\n    if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())\n    {\n        _ReturnTask._SetAsync();\n    }\n\n    _PParam->_M_numTasks = 2;\n    auto _Continuation = [_PParam](task<void> _ResultTask) mutable {\n        //  Dev10 compiler needs this.\n        auto _PParam1 = _PParam;\n        auto _Func = [&_ResultTask, _PParam1]() {\n            _PParam1->_M_Completed.set(std::make_pair(details::_Unit_type(), _ResultTask._GetImpl()->_M_pTokenState));\n        };\n        _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);\n    };\n\n    _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());\n    _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());\n\n    return _ReturnTask;\n}\n\ntemplate<typename _Ty>\ntask<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_options())\n{\n    task_completion_event<_Ty> _Tce;\n    _Tce.set(_Param);\n    return create_task(_Tce, _TaskOptions);\n}\n\n// Work around VS 2010 compiler bug\n#if _MSC_VER == 1600\ninline task<bool> task_from_result(bool _Param)\n{\n    task_completion_event<bool> _Tce;\n    _Tce.set(_Param);\n    return create_task(_Tce, task_options());\n}\n#endif\ninline task<void> task_from_result(const task_options& _TaskOptions = task_options())\n{\n    task_completion_event<void> _Tce;\n    _Tce.set();\n    return create_task(_Tce, _TaskOptions);\n}\n\ntemplate<typename _TaskType, typename _ExType>\ntask<_TaskType> task_from_exception(_ExType _Exception, const task_options& _TaskOptions = task_options())\n{\n    task_completion_event<_TaskType> _Tce;\n    _Tce.set_exception(_Exception);\n    return create_task(_Tce, _TaskOptions);\n}\n\nnamespace details\n{\n    /// <summary>\n    /// A convenient extension to Concurrency: loop until a condition is no longer met\n    /// </summary>\n    /// <param name=\"func\">\n    ///   A function representing the body of the loop. It will be invoked at least once and \n    ///   then repetitively as long as it returns true.\n    /// </param>\n    inline\n    task<bool> do_while(std::function<task<bool>(void)> func)\n    {\n        task<bool> first = func();\n        return first.then([=](bool guard) -> task<bool> {\n            if (guard)\n                return do_while(func);\n            else\n                return first;\n            });\n    }\n\n} // namespace details\n\n} // namespace Concurrency\n\n#pragma pop_macro(\"new\")\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n#pragma pack(pop)\n\n#endif // (defined(_MSC_VER) && (_MSC_VER >= 1800))\n\n#ifndef _CONCRT_H\n#ifndef _LWRCASE_CNCRRNCY\n#define _LWRCASE_CNCRRNCY\n// Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace\n// is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist.\nnamespace Concurrency {}\nnamespace concurrency = Concurrency;\n#endif\n#endif\n\n#endif // _PPLXTASKS_H\n#endif // !XSAPI_NO_PPL"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxtasks.h",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved. \n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Parallel Patterns Library - PPLx Tasks\n*\n* For the latest on this and related APIs, please see http://casablanca.codeplex.com.\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800))\n#include \"pplxtasks.140.h\"\n#else\n#include \"pplxtasks.110.h\"\n#endif\n#endif"
  },
  {
    "path": "Include/cpprestinclude/pplx/pplxwin.h",
    "content": "#if !XSAPI_NO_PPL\n/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved. \n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Windows specific pplx implementations\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX\n\n#include \"cpprest/details/cpprest_compat.h\"\n#include \"pplx/pplxinterface.h\"\n\nnamespace pplx\n{\n\nnamespace details\n{\n    namespace platform\n    {\n        /// <summary>\n        /// Returns a unique identifier for the execution thread where this routine in invoked\n        /// </summary>\n        _PPLXIMP long __cdecl GetCurrentThreadId();\n\n        /// <summary>\n        /// Yields the execution of the current execution thread - typically when spin-waiting\n        /// </summary>\n        _PPLXIMP void __cdecl YieldExecution();\n\n        /// <summary>\n        /// Captures the callstack\n        /// </summary>\n        __declspec(noinline) _PPLXIMP size_t __cdecl CaptureCallstack(void **, size_t, size_t);\n\n#if defined(__cplusplus_winrt)\n        /// <summary>\n        // Internal API which retrieves the next async id.\n        /// </summary>\n        _PPLXIMP unsigned int __cdecl GetNextAsyncId();\n#endif\n    }\n\n    /// <summary>\n    /// Manual reset event\n    /// </summary>\n    class event_impl\n    {\n    public:\n\n        static const unsigned int timeout_infinite = 0xFFFFFFFF;\n\n        _PPLXIMP event_impl();\n\n        _PPLXIMP ~event_impl();\n\n        _PPLXIMP void set();\n\n        _PPLXIMP void reset();\n\n        _PPLXIMP unsigned int wait(unsigned int timeout);\n\n        unsigned int wait()\n        {\n            return wait(event_impl::timeout_infinite);\n        }\n\n    private:\n        // Windows events\n        void * _M_impl;\n\n        event_impl(const event_impl&);                  // no copy constructor\n        event_impl const & operator=(const event_impl&); // no assignment operator\n    };\n\n    /// <summary>\n    /// Mutex - lock for mutual exclusion\n    /// </summary>\n    class critical_section_impl\n    {\n    public:\n\n        _PPLXIMP critical_section_impl();\n\n        _PPLXIMP ~critical_section_impl();\n\n        _PPLXIMP void lock();\n\n        _PPLXIMP void unlock();\n\n    private:\n\n        typedef void * _PPLX_BUFFER;\n\n        // Windows critical section\n        _PPLX_BUFFER _M_impl[8];\n\n        critical_section_impl(const critical_section_impl&);                  // no copy constructor\n        critical_section_impl const & operator=(const critical_section_impl&); // no assignment operator\n    };\n\n#if _WIN32_WINNT >= _WIN32_WINNT_VISTA \n    /// <summary>\n    /// Reader writer lock\n    /// </summary>\n    class reader_writer_lock_impl\n    {\n    public:\n\n        class scoped_lock_read\n        {\n        public:\n            explicit scoped_lock_read(reader_writer_lock_impl &_Reader_writer_lock) : _M_reader_writer_lock(_Reader_writer_lock)\n            {\n                _M_reader_writer_lock.lock_read();\n            }\n\n            ~scoped_lock_read()\n            {\n                _M_reader_writer_lock.unlock();\n            }\n\n        private:\n            reader_writer_lock_impl& _M_reader_writer_lock;\n            scoped_lock_read(const scoped_lock_read&);                    // no copy constructor\n            scoped_lock_read const & operator=(const scoped_lock_read&);  // no assignment operator\n        };\n\n        _PPLXIMP reader_writer_lock_impl();\n\n        _PPLXIMP void lock();\n\n        _PPLXIMP void lock_read();\n\n        _PPLXIMP void unlock();\n\n    private:\n\n        // Windows slim reader writer lock\n        void * _M_impl;\n\n        // Slim reader writer lock doesn't have a general 'unlock' method.\n        // We need to track how it was acquired and release accordingly.\n        // true - lock exclusive\n        // false - lock shared\n        bool m_locked_exclusive;\n    };  \n#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA \n\n    /// <summary>\n    /// Recursive mutex\n    /// </summary>\n    class recursive_lock_impl\n    {\n    public:\n\n        recursive_lock_impl()\n            : _M_owner(-1), _M_recursionCount(0)\n        {\n        }\n\n        ~recursive_lock_impl()\n        {\n            _ASSERTE(_M_owner == -1);\n            _ASSERTE(_M_recursionCount == 0);\n        }\n\n        void recursive_lock_impl::lock()\n        {\n            auto id = ::pplx::details::platform::GetCurrentThreadId();\n\n            if ( _M_owner == id )\n            {\n                _M_recursionCount++;\n            }\n            else\n            {\n                _M_cs.lock();\n                _M_owner = id;\n                _M_recursionCount = 1;\n            }            \n        }\n\n        void recursive_lock_impl::unlock()\n        {\n            _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId());\n            _ASSERTE(_M_recursionCount >= 1);\n\n            _M_recursionCount--;\n\n            if ( _M_recursionCount == 0 )\n            {\n                _M_owner = -1;\n                _M_cs.unlock();\n            }           \n        }\n\n    private:\n        pplx::details::critical_section_impl _M_cs;\n        long _M_recursionCount;\n        volatile long _M_owner;\n    };\n\n    class windows_scheduler : public pplx::scheduler_interface\n    {\n    public:\n        _PPLXIMP virtual void schedule( TaskProc_t proc, _In_ void* param);\n    };\n\n} // namespace details\n\n/// <summary>\n///  A generic RAII wrapper for locks that implement the critical_section interface\n///  std::lock_guard\n/// </summary>\ntemplate<class _Lock>\nclass scoped_lock\n{\npublic:\n    explicit scoped_lock(_Lock& _Critical_section) : _M_critical_section(_Critical_section)\n    {\n        _M_critical_section.lock();\n    }\n\n    ~scoped_lock()\n    {\n        _M_critical_section.unlock();\n    }\n\nprivate:\n    _Lock& _M_critical_section;\n\n    scoped_lock(const scoped_lock&);                    // no copy constructor\n    scoped_lock const & operator=(const scoped_lock&);  // no assignment operator\n};\n\n// The extensibility namespace contains the type definitions that are used internally\nnamespace extensibility\n{\n    typedef ::pplx::details::event_impl event_t;\n\n    typedef ::pplx::details::critical_section_impl critical_section_t;\n    typedef scoped_lock<critical_section_t> scoped_critical_section_t;\n\n#if _WIN32_WINNT >= _WIN32_WINNT_VISTA \n    typedef ::pplx::details::reader_writer_lock_impl reader_writer_lock_t;\n    typedef scoped_lock<reader_writer_lock_t> scoped_rw_lock_t;\n    typedef reader_writer_lock_t::scoped_lock_read scoped_read_lock_t;  \n#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA \n\n\n    typedef ::pplx::details::recursive_lock_impl recursive_lock_t;\n    typedef scoped_lock<recursive_lock_t> scoped_recursive_lock_t;\n}\n\n/// <summary>\n/// Default scheduler type\n/// </summary>\ntypedef details::windows_scheduler default_scheduler_t;\n\nnamespace details\n{\n    /// <summary>\n    /// Terminate the process due to unhandled exception\n    /// </summary>\n\n    #ifndef _REPORT_PPLTASK_UNOBSERVED_EXCEPTION\n    #define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \\\n        __debugbreak(); \\\n        std::terminate(); \\\n    } while(false)\n    #endif // _REPORT_PPLTASK_UNOBSERVED_EXCEPTION\n\n} // namespace details\n\n} // namespace pplx\n\n#endif\n#endif // !XSAPI_NO_PPL"
  },
  {
    "path": "Include/cpprestinclude/pplx/threadpool.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved. \n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n* \n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n*\n* Simple Linux implementation of a static thread pool.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n***/\n#pragma once\n#if defined(__clang__)\n#include <pthread.h>\n#endif\n#include <vector>\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic ignored \"-Wunreachable-code\"\n#pragma clang diagnostic ignored \"-Winfinite-recursion\"\n#endif\n#ifdef ASIO_STANDALONE\n#include <asio.hpp>\n#endif\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\n#if (defined(ANDROID) || defined(__ANDROID__))\n#include <atomic>\n#include <jni.h>\n#include \"pplx/pplx.h\"\n#include \"asio/io_service.hpp\"\n#endif\n\nnamespace crossplat {\n\n#if (defined(ANDROID) || defined(__ANDROID__))\n// IDEA: Break this section into a separate android/jni header\nextern std::atomic<JavaVM*> JVM;\nJNIEnv* get_jvm_env();\n\nstruct java_local_ref_deleter\n{\n    void operator()(jobject lref) const\n    {\n        crossplat::get_jvm_env()->DeleteLocalRef(lref);\n    }\n};\n\ntemplate<class T>\nusing java_local_ref = std::unique_ptr<typename std::remove_pointer<T>::type, java_local_ref_deleter>;\n#endif\n\nclass threadpool\n{\npublic:\n\n    threadpool(size_t n)\n      : m_service(n),\n        m_work(m_service)\n    {\n        for (size_t i = 0; i < n; i++)\n            add_thread();\n    }\n\n    static threadpool& shared_instance();\n\n    ~threadpool()\n    {\n        m_service.stop();\n        for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter)\n        {\n            pthread_t t = *iter;\n            void* res;\n            pthread_join(t, &res);\n        }\n    }\n\n    template<typename T>\n    void schedule(T task)\n    {\n        m_service.post(task);\n    }\n\n    asio::io_service& service()\n    {\n        return m_service;\n    }\n\nprivate:\n    struct _cancel_thread { };\n\n    void add_thread()\n    {\n        pthread_t t;\n        auto result = pthread_create(&t, nullptr, &thread_start, this);\n        if (result == 0)\n            m_threads.push_back(t);\n    }\n\n    void remove_thread()\n    {\n        schedule([]() -> void { throw _cancel_thread(); });\n    }\n\n#if (defined(ANDROID) || defined(__ANDROID__))\n    static void detach_from_java(void*)\n    {\n        JVM.load()->DetachCurrentThread();\n    }\n#endif\n\n    static void* thread_start(void *arg)\n    {\n#if (defined(ANDROID) || defined(__ANDROID__))\n        // Calling get_jvm_env() here forces the thread to be attached.\n        get_jvm_env();\n        pthread_cleanup_push(detach_from_java, nullptr);\n#endif\n        threadpool* _this = reinterpret_cast<threadpool*>(arg);\n        try\n        {\n            _this->m_service.run();\n        }\n        catch (const _cancel_thread&)\n        {\n            // thread was cancelled\n        }\n        catch (...)\n        {\n            // Something bad happened\n#if (defined(ANDROID) || defined(__ANDROID__))\n            // Reach into the depths of the 'droid!\n            // NOTE: Uses internals of the bionic library\n            // Written against android ndk r9d, 7/26/2014\n            __pthread_cleanup_pop(&__cleanup, true);\n            throw;\n#endif\n        }\n#if (defined(ANDROID) || defined(__ANDROID__))\n        pthread_cleanup_pop(true);\n#endif\n        return arg;\n    }\n\n    std::vector<pthread_t> m_threads;\n    asio::io_service m_service;\n    asio::io_service::work m_work;\n};\n\n}\n"
  },
  {
    "path": "Include/xsapi-c/achievements_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Enumeration values that indicate the achievement type.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\n/// <argof><see cref=\"XblAchievementsGetAchievementsForTitleIdAsync\"/></argof>\nenum class XblAchievementType : uint32_t\n{\n    /// <summary>\n    /// The achievement type is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Gets all achievements regardless of type.\n    /// </summary>\n    All,\n\n    /// <summary>\n    /// A persistent achievement that may be unlocked at any time.  \n    /// Persistent achievements can give Gamerscore as a reward.\n    /// </summary>\n    Persistent,\n\n    /// <summary>\n    /// A challenge achievement that may only be unlocked within a certain time period.  \n    /// Challenge achievements can't give Gamerscore as a reward.\n    /// </summary>\n    Challenge\n};\n\n/// <summary>\n/// Enumeration values that indicate the achievement sort order.\n/// </summary>\n/// <argof><see cref=\"XblAchievementsGetAchievementsForTitleIdAsync\"/></argof>\nenum class XblAchievementOrderBy : uint32_t\n{\n    /// <summary>\n    /// Default order does not guarantee sort order.\n    /// </summary>\n    DefaultOrder,\n\n    /// <summary>\n    /// Sort by title id.\n    /// </summary>\n    TitleId,\n\n    /// <summary>\n    /// Sort by achievement unlock time.\n    /// </summary>\n    UnlockTime\n};\n\n/// <summary>\n/// Enumeration values that indicate the state of a player's progress towards unlocking an achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\nenum class XblAchievementProgressState : uint32_t\n{\n    /// <summary>\n    /// Achievement progress is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Achievement has been earned.\n    /// </summary>\n    Achieved,\n\n    /// <summary>\n    /// Achievement progress has not been started.\n    /// </summary>\n    NotStarted,\n\n    /// <summary>\n    /// Achievement progress has started.\n    /// </summary>\n    InProgress\n};\n\n/// <summary>\n/// Enumeration values that indicate the media asset type associated with the achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievementMediaAsset\"/></memof>\nenum class XblAchievementMediaAssetType : uint32_t\n{\n    /// <summary>\n    /// The media asset type is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// An icon media asset.\n    /// </summary>\n    Icon,\n\n    /// <summary>\n    /// An art media asset.\n    /// </summary>\n    Art\n};\n\n/// <summary>\n/// Enumeration values that indicate the participation type for an achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\nenum class XblAchievementParticipationType : uint32_t\n{\n    /// <summary>\n    /// The participation type is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// An achievement that can be earned as an individual participant.\n    /// </summary>\n    Individual,\n\n    /// <summary>\n    /// An achievement that can be earned as a group participant.\n    /// </summary>\n    Group\n};\n\n/// <summary>\n/// Enumeration values that indicate the reward type for an achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievementReward\"/></memof>\nenum class XblAchievementRewardType : uint32_t\n{\n    /// <summary>\n    /// The reward type is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// A Gamerscore reward.\n    /// </summary>\n    Gamerscore,\n\n    /// <summary>\n    /// An in-app reward, defined and delivered by the title.\n    /// </summary>\n    InApp,\n\n    /// <summary>\n    /// A digital art reward.\n    /// </summary>\n    Art\n};\n\n/// <summary>\n/// Enumeration values that indicate the rarity category for an achievement.\n/// </summary>\nenum class XblAchievementRarityCategory : uint32_t\n{\n    /// <summary>\n    /// The rarity is incalculable (e.g. no one has played the title yet, denominator is 0).\n    /// </summary>\n    Unset = 0,\n\n    /// <summary>\n    /// The number of global users that have unlocked this achievement is between 0 - 10.9.\n    /// </summary>\n    Rare = 1,\n\n    /// <summary>\n    /// The number of global users that have unlocked this achievement is between 11.0 - 100.0.\n    /// </summary>\n    Common = 2\n};\n\n/// <summary>\n/// Represents the association between a title and achievements.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\ntypedef struct XblAchievementTitleAssociation\n{\n    /// <summary>\n    /// The UTF-8 encoded localized name of the title.\n    /// </summary>\n    _Field_z_ const char* name;\n\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    uint32_t titleId;\n} XblAchievementTitleAssociation;\n\n/// <summary>\n/// Represents requirements for unlocking the achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievementProgression\"/></memof>\ntypedef struct XblAchievementRequirement\n{\n    /// <summary>\n    /// The UTF-8 encoded achievement requirement ID.\n    /// </summary>\n    _Field_z_ const char* id;\n\n    /// <summary>\n    /// A UTF-8 encoded value that indicates the current progress of the player towards meeting the requirement.\n    /// </summary>\n    _Field_z_ const char* currentProgressValue;\n\n    /// <summary>\n    /// The UTF-8 encoded target progress value that the player must reach in order to meet \n    /// the requirement.\n    /// </summary>\n    _Field_z_ const char* targetProgressValue;\n} XblAchievementRequirement;\n\n/// <summary>\n/// Represents progress details about the achievement, including requirements.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\ntypedef struct XblAchievementProgression\n{\n    /// <summary>\n    /// The actions and conditions that are required to unlock the achievement.\n    /// </summary>\n    XblAchievementRequirement* requirements;\n\n    /// <summary>\n    /// The size of **requirements**.\n    /// </summary>\n    size_t requirementsCount;\n\n    /// <summary>\n    /// The timestamp when the achievement was first unlocked.\n    /// </summary>\n    time_t timeUnlocked;\n} XblAchievementProgression;\n\n/// <summary>\n/// Represents an interval of time during which an achievement can be unlocked.\n/// </summary>\n/// <remarks>\n/// This class is only used when the achievement_type enumeration is set to challenge.\n/// </remarks>\n/// <memof><see cref=\"XblAchievement\"/></memof>\ntypedef struct XblAchievementTimeWindow\n{\n    /// <summary>\n    /// The start date and time of the achievement time window.\n    /// </summary>\n    time_t startDate;\n\n    /// <summary>\n    /// The end date and time of the achievement time window.\n    /// </summary>\n    time_t endDate;\n} XblAchievementTimeWindow;\n\n/// <summary>\n/// Represents a media asset for an achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievementReward\"/></memof>\n/// <memof><see cref=\"XblAchievement\"/></memof>\ntypedef struct XblAchievementMediaAsset\n{\n    /// <summary>\n    /// The UTF-8 encoded name of the media asset, such as \"tile01\".\n    /// </summary>\n    _Field_z_ const char* name;\n\n    /// <summary>\n    /// The type of media asset.\n    /// </summary>\n    XblAchievementMediaAssetType mediaAssetType;\n\n    /// <summary>\n    /// The UTF-8 encoded URL of the media asset.\n    /// </summary>\n    _Field_z_ const char* url;\n} XblAchievementMediaAsset;\n\n/// <summary>\n/// Represents a reward that is associated with the achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\ntypedef struct XblAchievementReward\n{\n    /// <summary>\n    /// The UTF-8 encoded localized reward name.\n    /// </summary>\n    _Field_z_ const char* name;\n\n    /// <summary>\n    /// The UTF-8 encoded description of the reward.\n    /// </summary>\n    _Field_z_ const char* description;\n\n    /// <summary>\n    /// The UTF-8 encoded title-defined reward value (data type and content varies by reward type).\n    /// </summary>\n    _Field_z_ const char* value;\n\n    /// <summary>\n    /// The reward type.\n    /// </summary>\n    XblAchievementRewardType rewardType;\n\n    /// <summary>\n    /// The UTF-8 encoded property type of the reward value string.\n    /// </summary>\n    _Field_z_ const char* valueType;\n\n    /// <summary>\n    /// The media asset associated with the reward.  \n    /// If the reward type is gamerscore, this will be nullptr.  \n    /// If the reward type is in_app, this will be a media asset.  \n    /// If the reward type is art, this may be a media asset or nullptr.\n    /// </summary>\n    XblAchievementMediaAsset* mediaAsset;\n} XblAchievementReward;\n\n/// <summary>\n/// An entry for XblAchievementProgressChangeEventArgs representing a progress update for a single achievement.\n/// </summary>\ntypedef struct XblAchievementProgressChangeEntry\n{\n    /// <summary>\n    /// The UTF-8 encoded achievement ID. Represents a uint.\n    /// </summary>\n    _Field_z_ const char* achievementId;\n\n    /// <summary>\n    /// The state of a user's progress towards the earning of the achievement.\n    /// </summary>\n    XblAchievementProgressState progressState;\n\n    /// <summary>\n    /// The progression object containing progress details about the achievement, \n    /// including requirements.\n    /// </summary>\n    XblAchievementProgression progression;\n} XblAchievementProgressChangeEntry;\n\n/// <summary>\n/// Event arguments for achievement progress changes.\n/// </summary>\ntypedef struct XblAchievementProgressChangeEventArgs\n{\n    /// <summary>\n    /// Array of objects detailing the progress changes of each achievement that has been updated. \n    /// </summary>\n    XblAchievementProgressChangeEntry* updatedAchievementEntries;\n\n    /// <summary>\n    /// The count of **updatedAchievementEntries**.\n    /// </summary>\n    size_t entryCount;\n} XblAchievementProgressChangeEventArgs;\n\n/// <summary>\n/// Represents an achievement, a system-wide mechanism for directing and \n/// rewarding users' in-game actions consistently across all games.\n/// </summary>\n/// <argof><see cref=\"XblAchievementsResultGetAchievements\"/></argof>\ntypedef struct XblAchievement\n{\n    /// <summary>\n    /// The UTF-8 encoded achievement ID. Represents a uint.\n    /// </summary>\n    _Field_z_ const char* id;\n\n    /// <summary>\n    /// The Service Configuration ID (SCID) that is associated with the achievement. The SCID is considered case sensitive so paste it directly from the Partner Center\n    /// </summary>\n    _Field_z_ const char* serviceConfigurationId;\n\n    /// <summary>\n    /// The UTF-8 encoded localized achievement name.\n    /// </summary>\n    _Field_z_ const char* name;\n\n    /// <summary>\n    /// The game/app titles associated with the achievement.\n    /// </summary>\n    XblAchievementTitleAssociation* titleAssociations;\n\n    /// <summary>\n    /// The size of **titleAssociations**.\n    /// </summary>\n    size_t titleAssociationsCount;\n\n    /// <summary>\n    /// The state of a user's progress towards the earning of the achievement.\n    /// </summary>\n    XblAchievementProgressState progressState;\n\n    /// <summary>\n    /// The progression object containing progress details about the achievement, including requirements.\n    /// </summary>\n    XblAchievementProgression progression;\n\n    /// <summary>\n    /// The media assets associated with the achievement, such as image IDs.\n    /// </summary>\n    XblAchievementMediaAsset* mediaAssets;\n\n    /// <summary>\n    /// The size of **mediaAssets**.\n    /// </summary>\n    size_t mediaAssetsCount;\n\n    /// <summary>\n    /// The UTF-8 encoded collection of platforms that the achievement is available on.\n    /// </summary>\n    _Field_z_ const char** platformsAvailableOn;\n\n    /// <summary>\n    /// The size of **platformsAvailableOn**.\n    /// </summary>\n    size_t platformsAvailableOnCount;\n\n    /// <summary>\n    /// Whether or not the achievement is secret.\n    /// </summary>\n    bool isSecret;\n\n    /// <summary>\n    /// The UTF-8 encoded description of the unlocked achievement.\n    /// </summary>\n    _Field_z_ const char* unlockedDescription;\n\n    /// <summary>\n    /// The UTF-8 encoded description of the locked achievement.\n    /// </summary>\n    _Field_z_ const char* lockedDescription;\n\n    /// <summary>\n    /// The UTF-8 encoded product_id the achievement was released with.  \n    /// This is a globally unique identifier that may correspond to an application, downloadable content, etc.\n    /// </summary>\n    _Field_z_ const char* productId;\n\n    /// <summary>\n    /// The type of achievement, such as a challenge achievement.\n    /// </summary>\n    XblAchievementType type;\n\n    /// <summary>\n    /// The participation type for the achievement, such as group or individual.\n    /// </summary>\n    XblAchievementParticipationType participationType;\n\n    /// <summary>\n    /// The time window during which the achievement is available.  Applies to Challenges.\n    /// </summary>\n    XblAchievementTimeWindow available;\n\n    /// <summary>\n    /// The collection of rewards that the player earns when the achievement is unlocked.\n    /// </summary>\n    XblAchievementReward* rewards;\n\n    /// <summary>\n    /// The size of **rewards**.\n    /// </summary>\n    size_t rewardsCount;\n\n    /// <summary>\n    /// The estimated time that the achievement takes to be earned.\n    /// </summary>\n    uint64_t estimatedUnlockTime;\n\n    /// <summary>\n    /// A UTF-8 encoded deep link for clients that enables the title to launch at a desired \n    /// starting point for the achievement.\n    /// </summary>\n    _Field_z_ const char* deepLink;\n\n    /// <summary>\n    /// A value that indicates whether or not the achievement is revoked by enforcement.\n    /// </summary>\n    bool isRevoked;\n} XblAchievement;\n\n\n/// <summary>\n/// Represents an Achievement Unlock notification received from the notification service.\n/// </summary>\ntypedef struct XblAchievementUnlockEvent\n{    \n    /// <summary>\n    /// The name of the achievement in the locale of the DeviceEndpoint to which it's being sent (current char limit: 44).\n    /// </summary>\n    _Field_z_ const char* achievementName;\n\n    /// <summary>\n    /// The description of the achievement in the locale of the DeviceEndpoint to which it's being sent.\n    /// </summary>\n    _Field_z_ const char* achievementDescription;\n\n    /// <summary>\n    /// The URL to the image associated to the achievement (max length: 2048).\n    /// </summary>\n    _Field_z_ const char* achievementIcon;\n\n    /// <summary>\n    /// The UTF-8 encoded achievement ID.\n    /// </summary>\n    _Field_z_ const char* achievementId;\n\n    /// <summary>\n    /// The amount of gamerscore earned for unlocking the achievement (can be 0 - challenges cannot have gamerscore).\n    /// </summary>\n    uint64_t gamerscore;\n\n    /// <summary>\n    /// The base 10 ID of the title the achievement is defined for.\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// The person's Xbox user identifier.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// The deep link set on the achievement.\n    /// </summary>\n    _Field_z_ const char* deepLink;\n\n    /// <summary>\n    /// The ratio of the count of users who have unlocked the achievement / the total number unique users of that title expressed as a fractional value &gt;= 0.0 and &lt;= 1.0 rounded to 2 decimal places.\n    /// </summary>\n    float rarityPercentage;\n\n    /// <summary>\n    /// \"Rare\" or \"Common\" - where Rare achievements are those with a rarityPercentage &lt;= 9% (or 0.9) and \"Common\" is everything else. (This string is not localized).\n    /// </summary>\n    XblAchievementRarityCategory rarityCategory;\n\n    /// <summary>\n    /// The timestamp when the achievement was first unlocked for this user.\n    /// </summary>\n    time_t timeUnlocked;\n    \n} XblAchievementUnlockEvent;\n\n\n/// <summary>\n/// A handle to an achievement result.\n/// </summary>\n/// <remarks>\n/// This handle is used by other APIs to get the achievement objects and to get the \n/// next page of achievements from the service if there is one.  \n/// The handle must be closed using <see cref=\"XblAchievementsResultCloseHandle\"/> \n/// when the result is no longer needed.\n/// </remarks>\n/// <memof><see cref=\"XblAchievementsResultGetAchievements\"/></memof>\n/// <memof><see cref=\"XblAchievementsResultHasNext\"/></memof>\n/// <memof><see cref=\"XblAchievementsResultGetNextAsync\"/></memof>\n/// <memof><see cref=\"XblAchievementsResultGetNextResult\"/></memof>\n/// <memof><see cref=\"XblAchievementsGetAchievementsForTitleIdResult\"/></memof>\n/// <memof><see cref=\"XblAchievementsGetAchievementResult\"/></memof>\n/// <memof><see cref=\"XblAchievementsResultDuplicateHandle\"/></memof>\n/// <memof><see cref=\"XblAchievementsResultCloseHandle\"/></memof>\ntypedef struct XblAchievementsResult* XblAchievementsResultHandle;\n\n/// <summary>\n/// Get a list of XblAchievement objects.\n/// </summary>\n/// <param name=\"resultHandle\">Achievement result handle.</param>\n/// <param name=\"achievements\">Pointer to an array of XblAchievement objects.  \n/// The memory for the returned pointer will remain valid for the life of the \n/// XblAchievementsResultHandle object until it is closed.</param>\n/// <param name=\"achievementsCount\">The count of objects in the returned array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The returned array of XblAchievement objects is freed when all outstanding handles \n/// to the object have been closed with <see cref=\"XblAchievementsResultCloseHandle\"/>.\n/// </remarks>\nSTDAPI XblAchievementsResultGetAchievements(\n    _In_ XblAchievementsResultHandle resultHandle,\n    _Out_ const XblAchievement** achievements,\n    _Out_ size_t* achievementsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Checks if there are more pages of achievements to retrieve from the service.\n/// </summary>\n/// <param name=\"resultHandle\">Achievement result handle.</param>\n/// <param name=\"hasNext\">Passes back true if there are more results to retrieve, false otherwise.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsResultHasNext(\n    _In_ XblAchievementsResultHandle resultHandle,\n    _Out_ bool* hasNext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of next page of achievements for a player of the specified title.\n/// </summary>\n/// <param name=\"resultHandle\">Handle to the achievement result.</param>\n/// <param name=\"maxItems\">The maximum number of items that the result can contain.  \n/// Pass 0 to attempt to retrieve all items.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XblAchievementsResultGetNextResult\"/> inside the AsyncBlock callback \n/// or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>V2 GET /users/xuid({xuid})/achievements</rest>\nSTDAPI XblAchievementsResultGetNextAsync(\n    _In_ XblAchievementsResultHandle resultHandle,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get XblAchievementsResultHandle from an XblAchievementsResultGetNextAsync call.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblAchievementsResultGetNextAsync.</param>\n/// <param name=\"result\">\n/// Returns the next achievement result handle.  \n/// Note that this is a separate handle than the one passed to the XblAchievementsResultGetNextAsync API.  \n/// Each result handle must be closed separately.\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblAchievementsResultHandle* result\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the first page of achievements for a player of the specified title.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"titleId\">The title ID.</param>\n/// <param name=\"type\">The achievement type to retrieve.</param>\n/// <param name=\"unlockedOnly\">Indicates whether to return unlocked achievements only.</param>\n/// <param name=\"orderBy\">Controls how the list of achievements is ordered.</param>\n/// <param name=\"skipItems\">The number of achievements to skip.</param>\n/// <param name=\"maxItems\">The maximum number of achievements the result can contain.  \n/// Pass 0 to attempt to retrieve all items.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XblAchievementsGetAchievementsForTitleIdResult\"/> inside the AsyncBlock callback \n/// or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>V2 GET /users/xuid({xuid})/achievements</rest>\nSTDAPI XblAchievementsGetAchievementsForTitleIdAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t titleId,\n    _In_ XblAchievementType type,\n    _In_ bool unlockedOnly,\n    _In_ XblAchievementOrderBy orderBy,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get XblAchievementsResultHandle from an XblAchievementsGetAchievementsForTitleIdAsync call.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblAchievementsGetAchievementsForTitleIdAsync.</param>\n/// <param name=\"result\">Achievement result handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Use <see cref=\"XblAchievementsResultGetAchievements\"/> to get the list.\n/// </remarks>\nSTDAPI XblAchievementsGetAchievementsForTitleIdResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblAchievementsResultHandle* result\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Allow achievement progress to be updated and achievements to be unlocked.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"achievementId\">The UTF-8 encoded achievement ID as defined by XDP or Dev Center.</param>\n/// <param name=\"percentComplete\">The completion percentage of the achievement to indicate progress.  \n/// Valid values are from 1 to 100. Set to 100 to unlock the achievement.  \n/// Progress will be set by the server to the highest value sent</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This API will work even when offline on PC and Xbox One. Offline updates will be \n/// posted by the system when connection is re-established even if the title isn't running.  \n/// The result of the asynchronous operation can be obtained by calling <see cref=\"XAsyncGetStatus\"/> \n/// inside the AsyncBlock callback or after the AsyncBlock is complete.  \n///\n/// If the achievement has already been unlocked or the progress value is less than or \n/// equal to what is currently recorded on the server, then XAsyncGetStatus() inside the callback \n/// will return HTTP_E_STATUS_NOT_MODIFIED (0x80190130L).\n/// </remarks>\n/// <rest>V2 POST /users/xuid({xuid})/achievements/{scid}/update</rest>\nSTDAPI XblAchievementsUpdateAchievementAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Allow achievement progress to be updated and achievements to be unlocked.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"titleId\">The title ID.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"achievementId\">The UTF-8 encoded achievement ID as defined by XDP or Dev Center.</param>\n/// <param name=\"percentComplete\">The completion percentage of the achievement to indicate progress.  \n/// Valid values are from 1 to 100. Set to 100 to unlock the achievement.  \n/// Progress will be set by the server to the highest value sent.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This API will work even when offline on PC and Xbox One.  \n/// Offline updates will be posted by the system when connection is re-established even if the title isn't running.  \n/// The result of the asynchronous operation can be obtained by calling <see cref=\"XAsyncGetStatus\"/> \n/// inside the AsyncBlock callback or after the AsyncBlock is complete.\n/// If this unexpectedly fails, ensure the SCID is correctly in the XblInitArgs as it is case-sensitive.\n/// </remarks>\n/// <rest>V2 POST /users/xuid({xuid})/achievements/{scid}/update</rest>\nSTDAPI XblAchievementsUpdateAchievementForTitleIdAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ const uint32_t titleId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets an achievement for a player with a specific achievement ID.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"achievementId\">The UTF-8 encoded unique identifier of the Achievement as defined by XDP or Dev Center.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If multiple achievements are required, use the batch API instead: <see cref=\"XblAchievementsGetAchievementsForTitleIdAsync\"/> \n/// To get the result, call <see cref=\"XblAchievementsGetAchievementResult\"/> inside the AsyncBlock callback \n/// or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>V2 GET /users/xuid({xuid})/achievements/{scid}/{achievementId}</rest>\nSTDAPI XblAchievementsGetAchievementAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* achievementId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result handle from an XblAchievementsGetAchievementAsync call.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblAchievementsGetAchievementAsync.</param>\n/// <param name=\"result\">The achievement result handle.  \n/// This handle is used by other APIs to get the achievement objects \n/// and to get the next page of achievements from the service if there is one.  \n/// The handle must be closed using <see cref=\"XblAchievementsResultCloseHandle\"/> when the result is no longer needed.\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsGetAchievementResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblAchievementsResultHandle* result\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates a XblAchievementsResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblAchievementsResultHandle to duplicate.</param>\n/// <param name=\"duplicatedHandle\">The duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsResultDuplicateHandle(\n    _In_ XblAchievementsResultHandle handle,\n    _Out_ XblAchievementsResultHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Closes the XblAchievementsResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblAchievementsResultHandle to close.</param>\n/// <returns></returns>\n/// <remarks>\n/// When all outstanding handles have been closed, the memory associated with the achievement result will be freed.\n/// </remarks>\nSTDAPI_(void) XblAchievementsResultCloseHandle(\n    _In_ XblAchievementsResultHandle handle\n) XBL_NOEXCEPT;\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n/// <summary>\n/// Handle for Function handling achievement unlock events.\n/// </summary>\n/// <param name=\"args\">An achievement unlock event.</param>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns></returns>\n/// <remarks>The lifetime of the XblAchievementUnlockEvent object is limited to the callback.</remarks>\ntypedef void CALLBACK XblAchievementUnlockHandler(\n    _In_ const XblAchievementUnlockEvent* args,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for achievement unlock notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"handlerContext\">Caller context to be passed the handler.</param>\n/// <returns>An XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblAchievementUnlockAddNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblAchievementUnlockHandler* handler,\n    _In_opt_ void* handlerContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for achievement unlock notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"functionContext\">The XblFunctionContext that was returned when the event handler was registered. </param>\n/// <returns></returns>\nSTDAPI_(void) XblAchievementUnlockRemoveNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext functionContext\n) XBL_NOEXCEPT;\n#endif\n\n/// <summary>\n/// A callback invoked when a progress is made on an achievement.\n/// </summary>\n/// <param name=\"eventArgs\">The arguments associated with the change in achievement state.\n/// The fields of the struct are only valid during the callback.</param>\n/// <param name=\"context\">Context provided by when the handler is added.</param>\n/// <returns></returns>\n/// <remarks>\n/// For the callback to work properly, you must be subscribed to achievement progress changes for at least one user.\n/// </remarks>\ntypedef void CALLBACK XblAchievementsProgressChangeHandler(\n    _In_ const XblAchievementProgressChangeEventArgs* eventArgs,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for achievement progress change notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"handlerContext\">Client context pointer to be passed back to the handler.</param>\n/// <returns>A XblFunctionContext used to remove the handler.</returns>\n/// <remarks>\n/// Call <see cref=\"XblAchievementsRemoveAchievementProgressChangeHandler\"/> to un-register event handler.\n/// </remarks>\nSTDAPI_(XblFunctionContext) XblAchievementsAddAchievementProgressChangeHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblAchievementsProgressChangeHandler handler,\n    _In_opt_ void* handlerContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Removes an event handler for achievement progress change notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"functionContext\">XblFunctionContext for the handler to remove.</param>\n/// <returns></returns>\n/// <remarks>\n/// <prereq/>\n/// Call this API only if <see cref=\"XblAchievementsAddAchievementProgressChangeHandler\"/> was used to register an event handler.\n/// </remarks>\nSTDAPI XblAchievementsRemoveAchievementProgressChangeHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext functionContext\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/achievements_manager_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n    #error C++11 required\n#endif\n\n#pragma once\n\n#include \"pal.h\"\n#include \"achievements_c.h\"\n\nextern \"C\"\n{   \n\n/// <summary>\n/// Enumeration values that specify the order we display the results in.\n/// </summary>\nenum class XblAchievementsManagerSortOrder : uint32_t\n{\n    /// <summary>\n    /// Unsorted sort order will skip the sort operation.\n    /// </summary>\n    Unsorted = 0,\n    \n    /// <summary>\n    /// Elements in the response are in ascending order of the field specified by XblAchievementsManagerSortValue.\n    /// </summary>\n    Ascending = 1,\n    \n    /// <summary>\n    /// Elements in the response are in descending order of the field specified by XblAchievementsManagerSortValue.\n    /// </summary>\n    Descending = 2\n};\n\n/// <summary>\n/// Defines values used to indicate event types for an achievement. \n/// </summary>\nenum class XblAchievementsManagerEventType : uint32_t\n{\n    /// <summary>\n    /// Indicates that a local user was added and has been initialized.\n    /// </summary>\n    LocalUserInitialStateSynced = 0,\n\n    /// <summary>\n    /// Indicates the achievement was unlocked.\n    /// </summary>\n    AchievementUnlocked = 1,\n    \n    /// <summary>\n    /// Indicates progress has been made on (a requirement of) an achievement.\n    /// </summary>\n    AchievementProgressUpdated = 2\n};\n\n/// <summary>\n/// An achievement event that will be returned from <see cref=\"XblAchievementsManagerDoWork\"/>.\n/// </summary>\ntypedef struct XblAchievementsManagerEvent\n{\n    /// <summary>\n    /// Current state of progress for an achievement for AchievementUnlocked and\n    /// AchievementProgressUpdated events. The values of this struct are not \n    /// populated for LocalUserInitialStateSynced events.\n    /// </summary>\n    XblAchievementProgressChangeEntry progressInfo;\n\n    /// <summary>\n    /// The ID for the user that has made progress on an achievement.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// Type of the event triggered.\n    /// </summary>\n    XblAchievementsManagerEventType eventType;\n} XblAchievementsManagerEvent;\n\n/// <summary>\n/// A handle to an achievement manager result.\n/// </summary>\n/// <remarks>\n/// This handle is used by other APIs to get the achievement objects and to get the \n/// next page of achievements from the service if there is one.  \n/// The handle must be closed using <see cref=\"XblAchievementsManagerResultCloseHandle\"/> \n/// when the result is no longer needed.\n/// </remarks>\n/// <memof><see cref=\"XblAchievementsManagerResultGetAchievements\"/></memof>\n/// <memof><see cref=\"XblAchievementsManagerResultDuplicateHandle\"/></memof>\n/// <memof><see cref=\"XblAchievementsManagerResultCloseHandle\"/></memof>\ntypedef struct XblAchievementsManagerResult* XblAchievementsManagerResultHandle;\n\n/// <summary>\n/// Get a list of XblAchievement objects.\n/// </summary>\n/// <param name=\"resultHandle\">Achievement result handle.</param>\n/// <param name=\"achievements\">Pointer to an array of XblAchievement objects.  \n/// The memory for the returned pointer will remain valid for the life of the \n/// XblAchievementsManagerResultHandle object until it is closed.</param>\n/// <param name=\"achievementsCount\">The count of objects in the returned array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The returned array of XblAchievement objects is freed when all outstanding handles \n/// to the object have been closed with <see cref=\"XblAchievementsManagerResultCloseHandle\"/>.\n/// However the data might become stale.\n/// </remarks>\nSTDAPI XblAchievementsManagerResultGetAchievements(\n    _In_ XblAchievementsManagerResultHandle resultHandle,\n    _Out_ const XblAchievement** achievements,\n    _Out_ uint64_t* achievementsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates a XblAchievementsManagerResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblAchievementsManagerResultHandle to duplicate.</param>\n/// <param name=\"duplicatedHandle\">The duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsManagerResultDuplicateHandle(\n    _In_ XblAchievementsManagerResultHandle handle,\n    _Out_ XblAchievementsManagerResultHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Closes the XblAchievementsManagerResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblAchievementsManagerResultHandle to close.</param>\n/// <returns></returns>\n/// <remarks>\n/// When all outstanding handles have been closed, the memory associated with the achievement result will be freed.\n/// </remarks>\nSTDAPI_(void) XblAchievementsManagerResultCloseHandle(\n    _In_ XblAchievementsManagerResultHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Generate a local cache of achievements for a user.\n/// </summary>\n/// <param name=\"user\">Xbox Live User to fetch achievements for.</param>\n/// <param name=\"queue\">Queue to be used for background operation for this user (Optional).</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsManagerAddLocalUser(\n    _In_ XblUserHandle user, \n    _In_opt_ XTaskQueueHandle queue\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Immediately remove the local cache of achievements for a user.\n/// </summary>\n/// <param name=\"user\">Xbox Live User to clear the cache for.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsManagerRemoveLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Checks whether a specific user has had its initial state synced.\n/// </summary>\n/// <param name=\"xboxUserId\">Xbox Live User to check.</param>\n/// <returns>HRESULT return code for this API operation. If the user is not \n/// initialized, this function will return E_FAIL.</returns>\nSTDAPI XblAchievementsManagerIsUserInitialized(\n    _In_ uint64_t xboxUserId\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Called whenever the title wants to update the state of achievements and get list of change events.\n/// </summary>\n/// <param name=\"achievementsEvents\">Passes back a pointer to the array of achievement events that have occurred since the last call to XblAchievementsManagerDoWork.</param>\n/// <param name=\"achievementsEventsCount\">Passes back the number of events in the achievement events array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Must be called every frame for data to be up to date.  \n/// The array of achievement events that is sent back is only valid until the next call to <see cref=\"XblAchievementsManagerDoWork\"/>.  \n/// Make sure to check if there were achievement events sent back.  \n/// If the achievement events array is null, no results.  \n/// If the achievement events count is 0, no results.  \n/// If there were achievement events sent back then handle each <see cref=\"XblAchievementsManagerEvent\"/> \n/// by their respective <see cref=\"XblAchievementsManagerEventType\"/>.\n/// </remarks>\nSTDAPI XblAchievementsManagerDoWork(\n    _Outptr_result_maybenull_ const XblAchievementsManagerEvent** achievementsEvents,\n    _Out_ size_t* achievementsEventsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the current local state of an achievement for a local player with a specific achievement ID.\n/// </summary>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"achievementId\">The UTF-8 encoded unique identifier of the Achievement as defined by Dev Center.</param>\n/// <param name=\"achievementResult\">The handle to the result of AchievementsManager API calls. \n/// This handle is used by other APIs to get the achievement objects matching the \n/// API that was called. \n/// The handle must be closed using <see cref=\"XblAchievementsManagerResultCloseHandle\"/> when\n/// the result is no longer needed.\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsManagerGetAchievement(\n    _In_ uint64_t xboxUserId,\n    _In_ const char* achievementId,\n    _Outptr_result_maybenull_ XblAchievementsManagerResultHandle* achievementResult\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets a list of all achievements for a player.\n/// </summary>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"sortField\">\n/// The field to sort the list of achievements on.\n/// </param>\n/// <param name=\"sortOrder\">The direction by which to sort the list of achievements.</param>\n/// <param name=\"achievementsResult\">The handle to the result of AchievementsManager API calls. \n/// This handle is used by other APIs to get the achievement objects matching the \n/// API that was called. \n/// The handle must be closed using <see cref=\"XblAchievementsManagerResultCloseHandle\"/> when\n/// the result is no longer needed.\n/// </param>\n/// <remarks>\n/// Passing in XblAchievementOrderBy::TitleId for sortField yields the same results \n/// as passing in XblAchievementOrderBy::DefaultOrder since all achievements tracked \n/// by achievement manager will have the same TitleId.\n/// </remarks>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsManagerGetAchievements(\n    _In_ uint64_t xboxUserId,\n    _In_ XblAchievementOrderBy sortField,\n    _In_ XblAchievementsManagerSortOrder sortOrder,\n    _Outptr_result_maybenull_ XblAchievementsManagerResultHandle* achievementsResult\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets a list of achievements in a specific progress state for a player.\n/// </summary>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"sortField\">\n/// The field to sort the list of achievements on. TitleId will behave\n/// the same as DefaultOrder, as AchievementsManager only handles one title\n/// at a time.\n/// </param>\n/// <param name=\"sortOrder\">The direction by which to sort the list of achievements.</param>\n/// <param name=\"achievementState\">The achievement state to include in the results.</param>\n/// <param name=\"achievementsResult\">The handle to the result of AchievementsManager API calls. \n/// This handle is used by other APIs to get the achievement objects matching the \n/// API that was called. \n/// The handle must be closed using <see cref=\"XblAchievementsManagerResultCloseHandle\"/> when\n/// the result is no longer needed.\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblAchievementsManagerGetAchievementsByState(\n    _In_ uint64_t xboxUserId,\n    _In_ XblAchievementOrderBy sortField,\n    _In_ XblAchievementsManagerSortOrder sortOrder,\n    _In_ XblAchievementProgressState achievementState,\n    _Outptr_result_maybenull_ XblAchievementsManagerResultHandle* achievementsResult\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Allow achievement progress to be updated and achievements to be unlocked.\n/// </summary>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n/// <param name=\"achievementId\">The UTF-8 encoded achievement ID as defined by Dev Center.</param>\n/// <param name=\"currentProgress\">The completion percentage of the achievement to indicate progress.  \n/// Valid values are from 1 to 100. Set to 100 to unlock the achievement.  \n/// Progress will be set by the server to the highest value sent</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This API will work even when offline on PC and Xbox consoles. Offline updates will be \n/// posted by the system when connection is re-established even if the title isn't running.  \n/// Note that in order for this API to work offline, the title must have previously \n/// called <see cref=\"XblAchievementsManagerAddLocalUser\"/> for the user while online otherwise this API \n/// will return an error.  If this is not desired, consider calling \n/// <see cref=\"XblAchievementsUpdateAchievementAsync\"/> if this API fails to handle 'offline during init' scenarios.\n/// \n/// The result of the operation will not be represented locally immediately. The\n/// earliest the update will be reflected will be after the next frame's call to\n/// DoWork. Once the change is reflected, the array returned by DoWork \n/// will contain a <see cref=\"XblAchievementsManagerEvent\" /> of with\n/// an event type of AchievementProgressUpdated, and potentially an \n/// additional event of type AchievementUnlocked if the new progress\n/// resulted in unlocking the achievement.\n///\n/// If the achievement has already been unlocked or the progress value is less than or \n/// equal to what is cached from the server, this function will return E_NOT_VALID_STATE \n/// or E_INVALIDARG respectively. \n///\n/// Only title based achievements may be updated with this function. Event based \n/// achievements cannot be updated with this function. \n/// </remarks>\n/// <rest>V2 POST /users/xuid({xuid})/achievements/{scid}/update</rest>\nSTDAPI XblAchievementsManagerUpdateAchievement(\n    _In_ uint64_t xboxUserId, \n    _In_ const char* achievementId, \n    _In_ uint8_t currentProgress\n) XBL_NOEXCEPT;\n\n} //end extern \"C\"\n\n\n"
  },
  {
    "path": "Include/xsapi-c/errors_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n    #error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Enumeration values that define the Xbox Live API error conditions.\n/// </summary>\n/// <remarks>\n/// A best practice is to test the returned HRESULT against these error conditions using <see cref=\"XblGetErrorCondition\"/>.\n/// </remarks>\nenum class XblErrorCondition : uint32_t\n{\n    /// <summary>\n    /// No error.\n    /// </summary>\n    NoError = 0,\n\n    /// <summary>\n    /// A generic error condition.\n    /// </summary>\n    GenericError,\n\n    /// <summary>\n    /// An error condition related to an object being out of range.\n    /// </summary>\n    GenericOutOfRange,\n\n    /// <summary>\n    /// An error condition related to attempting to authenticate.\n    /// </summary>\n    Auth,\n\n    /// <summary>\n    /// An error condition related to network connectivity.\n    /// </summary>\n    Network,\n\n    /// <summary>\n    /// An error condition related to an HTTP method call.\n    /// </summary>\n    HttpGeneric,\n\n    /// <summary>\n    /// The requested resource was not modified.\n    /// </summary>\n    Http304NotModified,\n\n    /// <summary>\n    /// The requested resource was not found.\n    /// </summary>\n    Http404NotFound,\n\n    /// <summary>\n    /// The precondition given in one or more of the request-header fields evaluated\n    /// to false when it was tested on the server.\n    /// </summary>\n    Http412PreconditionFailed,\n\n    /// <summary>\n    /// Client is sending too many requests\n    /// </summary>\n    Http429TooManyRequests,\n    \n    /// <summary>\n    /// The service timed out while attempting to process the request.\n    /// </summary>\n    HttpServiceTimeout,\n\n    /// <summary>\n    /// An error related to real time activity.\n    /// </summary>\n    Rta\n};\n\n/// <summary>\n/// Groups HRESULT values returned from Xbl APIs in to error condition buckets that are actionable.\n/// </summary>\n/// <param name=\"hr\">HRESULT value returned from an Xbl API.</param>\n/// <returns>The corresponding XblErrorCondition.</returns>\nSTDAPI_(XblErrorCondition) XblGetErrorCondition(\n    _In_ HRESULT hr\n    ) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/events_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\n#ifdef XSAPI_EVENTS_SERVICE\n\nextern \"C\"\n{\n\n/// <summary>\n/// Write an in-game event that includes \"dimensions\" and \"measurement\" data fields.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"eventName\">Event name. Must be contain only alphanumeric characters.</param>\n/// <param name=\"dimensionsJson\">Dimensions data fields.</param>\n/// <param name=\"measurementsJson\">Measurement data fields.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Dimensions include event fields with a finite number of defined numeric or string values.  \n/// Examples of dimensions: map id, difficulty level, character or weapon class, game mode, boolean settings, etc.  \n///\n/// Measurements include event fields that represent scalar numeric metrics.  \n/// Examples of measurements: score, time, counters, position, etc.  \n///\n/// Example: for an in-game event that tracks the highest match score for a particular difficulty level:  \n/// The difficulty level should be included in dimensions, and the score should be included in measurements.  \n///\n/// The name of the event, and the names of the event fields (both dimensions and measurements), must match \n/// the names declared in the title's service configuration.  The names are case insensitive.  \n/// If the API writes an event with a name that does not match a name in the service configuration, the \n/// service drops the event with no notification.  \n///\n/// When using the GDK PC version, a GRTS runtime with the XGameEvent feature must be installed or this will E_NOTIMPL.\n/// </remarks>\nSTDAPI XblEventsWriteInGameEvent(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* eventName,\n    _In_opt_z_ const char* dimensionsJson,\n    _In_opt_z_ const char* measurementsJson\n) XBL_NOEXCEPT;\n\n#ifdef XSAPI_INTERNAL_EVENTS_SERVICE\n\n/// <summary>\n/// Set the maximum amount of disk space that Xsapi can use to store the events pending retry and upload before \n/// it starts deleting the oldest files.\n/// </summary>\n/// <param name=\"storageAllotmentInBytes\">Maximum storage space (in bytes) that will be used to store pending events.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When the maximum storage space is exceeded, the oldest file will be silently deleted.  \n/// Note that this is a global setting and will apply to all Xbox Live contexts.  \n/// The default value is approximately 20MB.\n/// </remarks>\nSTDAPI XblEventsSetStorageAllotment(\n    uint64_t storageAllotmentInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set the maximum file size for pending events files.\n/// </summary>\n/// <param name=\"maxFileSizeInByes\">The maximum size (in bytes) for pending events files.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The files will be read into memory all at once.  \n/// Note that this is a global setting and will apply to all Xbox Live contexts.  \n/// The default value is 128KB.\n/// </remarks>\nSTDAPI XblEventsSetMaxFileSize(\n    uint64_t maxFileSizeInByes\n) XBL_NOEXCEPT;\n\n#endif // XSAPI_INTERNAL_EVENTS_SERVICE\n}\n\n#endif // XSAPI_EVENTS_SERVICE"
  },
  {
    "path": "Include/xsapi-c/game_invite_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n#include \"multiplayer_c.h\"\n#include \"real_time_activity_c.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\nextern \"C\"\n{\n/// <summary>\n/// Contains information about received game invite notifications.\n/// </summary>\ntypedef struct XblGameInviteNotificationEventArgs\n{\n    /// <summary>\n    /// The Xbox user ID of the player.\n    /// </summary>\n    uint64_t invitedXboxUserId;\n\n    /// <summary>\n    /// The Xbox user ID of the player.\n    /// </summary>\n    uint64_t senderXboxUserId;\n\n    /// <summary>\n    /// The UTF-8 encoded gamertag of the player.\n    /// </summary>\n    char senderGamertag[XBL_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded modern gamertag for the player.  \n    /// Not guaranteed to be unique.\n    /// </summary>\n    char senderModernGamertag[XBL_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded suffix appended to modern gamertag to ensure uniqueness.  \n    /// May be empty in some cases.\n    /// </summary>\n    char senderModernGamertagSuffix[XBL_MODERN_GAMERTAG_SUFFIX_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded unique modern gamertag and suffix.  \n    /// Format will be \"modernGamertag#suffix\".  \n    /// Guaranteed to be no more than 16 rendered characters.\n    /// </summary>\n    char senderUniqueModernGamertag[XBL_UNIQUE_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// Invite Handle ID.  \n    /// The memory for the returned string pointer only remains valid inside the XblGameInviteHandler, \n    /// so deep copy the string if you need to refer to it outside the handler.\n    /// </summary>\n    _Field_z_ const char* inviteHandleId;\n\n    /// <summary>\n    /// Invite Protocol.  \n    /// The memory for the returned string pointer only remains valid inside the XblGameInviteHandler,\n    /// so deep copy the string if you need to refer to it outside the handler.\n    /// </summary>\n    _Field_z_ const char* inviteProtocol;\n\n    /// <summary>\n    /// Invite Context.  \n    /// The memory for the returned string pointer only remains valid inside the XblGameInviteHandler,\n    /// so deep copy the string if you need to refer to it outside the handler.\n    /// </summary>\n    _Field_z_ const char* inviteContext;\n\n    /// <summary>\n    /// Sender Image URL.  \n    /// The memory for the returned string pointer only remains valid inside the XblGameInviteHandler,\n    /// so deep copy the string if you need to refer to it outside the handler.\n    /// </summary>\n    _Field_z_ const char* senderImageUrl;\n\n    /// <summary>\n    /// Expiration Date.\n    /// </summary>\n    time_t expiration;\n\n    /// <summary>\n    /// Multiplayer Session Reference.\n    /// </summary>\n    XblMultiplayerSessionReference sessionReference;\n\n} XblGameInviteNotificationEventArgs;\n\n/// <summary>\n/// Handle for Function handling Game Invite Event Notifications.\n/// </summary>\n/// <param name=\"args\">The game invite notifications that are passed in.</param>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns></returns>\n/// <remarks>The lifetime of the XblGameInviteNotifcationEventArgs object is limited to the callback.</remarks>\ntypedef void CALLBACK XblGameInviteHandler(\n    _In_ const XblGameInviteNotificationEventArgs* args,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers the title to receive notifications for game invites.  \n/// Call XblGameInviteRegisterForEventResult() to get the result.\n/// DEPRECATED. Calling this API is no longer required and it will be removed in a future release. Registration with appropriate\n/// service endpoints is done automatically by XSAPI as <see cref=\"XblGameInviteHandler\"/> are added and removed.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblGameInviteRegisterForEventAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a XblGameInviteRegisterForEventAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"subscriptionHandle\">Handle for the subscription to be registered.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblGameInviteRegisterForEventResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters the title to stop receiving notifications for game invites.\n/// DEPRECATED. Calling this API is no longer required and it will be removed in a future release. Registration with appropriate\n/// service endpoints is done automatically by XSAPI as <see cref=\"XblGameInviteHandler\"/> are added and removed.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"subscriptionHandle\">Handle for the subscription to be unregistered.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>E_FAIL will be returned if this API before a Game Invite has been registered.</remarks>\nSTDAPI_XBL_DEPRECATED XblGameInviteUnregisterForEventAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Registers an event handler for game invite notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns>An XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblGameInviteAddNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblGameInviteHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for game invite notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns></returns>\nSTDAPI_(void) XblGameInviteRemoveNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n} // end extern C\n#endif"
  },
  {
    "path": "Include/xsapi-c/http_call_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Defines the response body type when reading the results of an HTTP call.\n/// </summary>\nenum class XblHttpCallResponseBodyType : uint32_t\n{\n    /// <summary>\n    /// Read results as string.\n    /// </summary>\n    String,\n\n    /// <summary>\n    /// Read results as vector.\n    /// </summary>\n    Vector\n};\n\n/// <summary>\n/// A handle to an HTTP call.\n/// </summary>\ntypedef struct XblHttpCall* XblHttpCallHandle;\n\n// Http APIs\n//\n\n/// <summary>\n/// Creates an HTTP call handle.\n/// </summary>\n/// <param name=\"xblContext\">Xbox Live context that provides user context for authorizing the call.</param>\n/// <param name=\"method\">UTF-8 encoded method for the HTTP call.</param>\n/// <param name=\"url\">UTF-8 encoded URL for the HTTP call.</param>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// First create an HTTP handle using XblHttpCallCreate().  \n/// Then call XblHttpCallRequestSet*() to prepare the XblHttpCallHandle.  \n/// Then call XblHttpCallPerformAsync() to perform HTTP call using the XblHttpCallHandle.  \n/// This call is asynchronous, so the work will be done on a background thread and will return via the callback.  \n///\n/// The perform call is asynchronous, so the work will be done on a background thread which calls \n/// XTaskQueueDispatch( ..., XTaskQueuePort::Work ).  \n///\n/// The results will return to the callback on the thread that calls \n/// XTaskQueueDispatch( ..., XTaskQueuePort::Completion ), then get the result of the HTTP call by calling \n/// XblHttpCallResponseGet*() to get the HTTP response of the XblHttpCallHandle.  \n/// \n/// When the XblHttpCallHandle is no longer needed, call <see cref=\"XblHttpCallCloseHandle\"/> to free the \n/// memory associated with the XblHttpCallHandle.\n/// </remarks>\nSTDAPI XblHttpCallCreate(\n    _In_ XblContextHandle xblContext,\n    _In_z_ const char* method,\n    _In_z_ const char* url,\n    _Out_ XblHttpCallHandle* call\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Perform an HTTP call using the XblHttpCallHandle.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"type\">The response body type to read the results of this HTTP call.  \n/// Note: this does not influence the content-type header, which must be \n/// supplied by calling <see cref=\"XblHttpCallRequestSetHeader\"/>.</param>\n/// <param name=\"asyncBlock\">The XAsyncBlock that defines the async operation.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.</returns>\n/// <remarks>\n/// First create a HTTP handle using XblHttpCallCreate().  \n/// Then call XblHttpCallRequestSet*() to prepare the XblHttpCallHandle.  \n/// Then call XblHttpCallPerformAsync() to perform HTTP call using the XblHttpCallHandle.  \n/// This call is asynchronous, so the work will be done on a background thread and will return via the callback.  \n///\n/// The perform call is asynchronous, so the work will be done on a background thread which calls \n/// XTaskQueueDispatch( ..., XTaskQueuePort::Work ).  \n///\n/// The results will return to the callback on the thread that calls \n/// XTaskQueueDispatch( ..., XTaskQueuePort::Completion ), then get the result of the HTTP call by calling \n/// XblHttpCallResponseGet*() to get the HTTP response of the XblHttpCallHandle.  \n/// \n/// When the XblHttpCallHandle is no longer needed, call XblHttpCallCloseHandle() to free the \n/// memory associated with the XblHttpCallHandle.  \n///\n/// XblHttpCallPerformAsync can only be called once.  Create new XblHttpCallHandle to repeat the call.\n/// </remarks>\nSTDAPI XblHttpCallPerformAsync(\n    _In_ XblHttpCallHandle call,\n    _In_ XblHttpCallResponseBodyType type,\n    _Inout_ XAsyncBlock* asyncBlock\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates the XblHttpCallHandle object.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"duplicateHandle\">The duplicated handle.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// Use XblHttpCallCloseHandle to close it.\n/// </remarks>\nSTDAPI XblHttpCallDuplicateHandle(\n    _In_ XblHttpCallHandle call,\n    _Out_ XblHttpCallHandle* duplicateHandle\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Decrements the reference count on the call object.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <returns></returns>\n/// <remarks>\n/// When the XblHttpCallHandle ref count is 0, XblHttpCallCloseHandle() will \n/// free the memory associated with the XblHttpCallHandle.\n/// </remarks>\nSTDAPI_(void) XblHttpCallCloseHandle(\n    _In_ XblHttpCallHandle call\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Enables or disables tracing for this specific HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"traceCall\">Trace this call.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// Defaults to true.\n/// </remarks>\nSTDAPI XblHttpCallSetTracing(\n    _In_ XblHttpCallHandle call,\n    _In_ bool traceCall\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the request url for the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"url\">The UTF-8 encoded url body string of the HTTP call.  \n/// The memory for the returned string pointer remains valid for the life of \n/// the XblHttpCallHandle object until XblHttpCallCloseHandle() is called on it.</param>\n/// <returns>Result code for this API operation.</returns>\nSTDAPI XblHttpCallGetRequestUrl(\n    _In_ XblHttpCallHandle call,\n    _Out_ const char** url\n    ) XBL_NOEXCEPT;\n\n/////////////////////////////////////////////////////////////////////////////////////////\n// HttpCallRequest Set APIs\n//\n\n/// <summary>\n/// Set the request body bytes of the HTTP call.\n/// </summary> \n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"requestBodyBytes\">The request body bytes of the HTTP call.</param>\n/// <param name=\"requestBodySize\">The length in bytes of the body being set.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.</returns>\n/// <remarks>\n/// This must be called prior to calling <see cref=\"XblHttpCallPerformAsync\"/>.\n/// </remarks>\nSTDAPI XblHttpCallRequestSetRequestBodyBytes(\n    _In_ XblHttpCallHandle call,\n    _In_reads_bytes_(requestBodySize) const uint8_t* requestBodyBytes,\n    _In_ uint32_t requestBodySize\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set the request body string of the HTTP call.\n/// </summary> \n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"requestBodyString\">The UTF-8 encoded request body string of the HTTP call.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.</returns>\n/// <remarks>\n/// This must be called prior to calling <see cref=\"XblHttpCallPerformAsync\"/>.\n/// </remarks>\nSTDAPI XblHttpCallRequestSetRequestBodyString(\n    _In_ XblHttpCallHandle call,\n    _In_z_ const char* requestBodyString\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set a request header for the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"headerName\">UTF-8 encoded request header name for the HTTP call.</param>\n/// <param name=\"headerValue\">UTF-8 encoded request header value for the HTTP call.</param>\n/// <param name=\"allowTracing\">Set to false to skip tracing this request header, for example if it contains private information.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.</returns>\n/// <remarks>\n/// This must be called prior to calling <see cref=\"XblHttpCallPerformAsync\"/>.\n/// </remarks>\nSTDAPI XblHttpCallRequestSetHeader(\n    _In_ XblHttpCallHandle call,\n    _In_z_ const char* headerName,\n    _In_z_ const char* headerValue,\n    _In_ bool allowTracing\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets if retry is allowed for this HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call. \n/// Pass nullptr to set the default for future calls.</param>\n/// <param name=\"retryAllowed\">If retry is allowed for this HTTP call.</param>\n/// <returns>Result code for this API operation. Possible values are S_OK, or E_FAIL.</returns>\n/// <remarks>\n/// Defaults to true.  \n/// This must be called prior to calling <see cref=\"XblHttpCallPerformAsync\"/>.\n/// </remarks>\nSTDAPI XblHttpCallRequestSetRetryAllowed(\n    _In_ XblHttpCallHandle call,\n    _In_ bool retryAllowed\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// ID number of this REST endpoint used to cache the Retry-After header for fast fail.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.  \n/// Pass nullptr to set the default for future calls.</param>\n/// <param name=\"retryAfterCacheId\">ID number of this REST endpoint used to cache the Retry-After header for fast fail.  1-1000 are reserved for XSAPI.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This must be called prior to calling <see cref=\"XblHttpCallPerformAsync\"/>.\n/// </remarks>\nSTDAPI XblHttpCallRequestSetRetryCacheId(\n    _In_ XblHttpCallHandle call,\n    _In_ uint32_t retryAfterCacheId\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets a flag which defines the HTTP call as long or not.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.  \n/// Pass nullptr to set the default for future calls.</param>\n/// <param name=\"longHttpCall\">The boolean to set the HTTP call to long or not.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, or E_FAIL.</returns>\n/// <remarks>\n/// Defaults to false.  \n/// This must be called prior to calling <see cref=\"XblHttpCallPerformAsync\"/>.\n/// </remarks>\nSTDAPI XblHttpCallRequestSetLongHttpCall(\n    _In_ XblHttpCallHandle call,\n    _In_ bool longHttpCall\n    ) XBL_NOEXCEPT;\n\n/////////////////////////////////////////////////////////////////////////////////////////\n// HttpCallResponse Get APIs\n// \n\n/// <summary>\n/// Get the response body string of the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"responseString\">\n/// The UTF-8 encoded response body string of the HTTP call.  \n/// The memory for the returned string pointer remains valid for the life of the XblHttpCallHandle object \n/// until XblHttpCallCloseHandle() is called on it.\n/// </param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.  \n/// This will only be valid if the responsetype passed to PerformAsync was String.\n/// </remarks>\nSTDAPI XblHttpCallGetResponseString(\n    _In_ XblHttpCallHandle call,\n    _Out_ const char** responseString\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the response body buffer size of the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"bufferSize\">The response body buffer size of the HTTP call.</param>\n/// <returns>Result code for this API operation. Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.  \n/// This will only be valid if the responsetype passed to PerformAsync was Vector.\n/// </remarks>\nSTDAPI XblHttpCallGetResponseBodyBytesSize(\n    _In_ XblHttpCallHandle call,\n    _Out_ size_t* bufferSize\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the response body buffer of the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"bufferSize\">The response body buffer size being passed in.</param>\n/// <param name=\"buffer\">The buffer to be written to.</param>\n/// <param name=\"bufferUsed\">The actual number of bytes written to the buffer.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.  \n/// This will only be valid if the responsetype passed to PerformAsync was Vector.\n/// </remarks>\nSTDAPI XblHttpCallGetResponseBodyBytes(\n    _In_ XblHttpCallHandle call,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) uint8_t* buffer,\n    _Out_opt_ size_t* bufferUsed\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the HTTP status code of the HTTP call response.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"statusCode\">the HTTP status code of the HTTP call response.</param>\n/// <returns>Result code for this API operation.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.\n/// </remarks>\nSTDAPI XblHttpCallGetStatusCode(\n    _In_ XblHttpCallHandle call,\n    _Out_ uint32_t* statusCode\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the network error code of the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"networkErrorCode\">The network error code of the HTTP call. Possible values are S_OK, or E_FAIL.</param>\n/// <param name=\"platformNetworkErrorCode\">The platform specific network error code of the HTTP call to be used for tracing / debugging.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.\n/// </remarks>\nSTDAPI XblHttpCallGetNetworkErrorCode(\n    _In_ XblHttpCallHandle call,\n    _Out_ HRESULT* networkErrorCode,\n    _Out_ uint32_t* platformNetworkErrorCode\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the platform network error message of the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"platformNetworkErrorMessage\">The platform specific network error message of the HTTP call to be used for tracing / debugging.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.\n/// </remarks>\nSTDAPI XblHttpCallGetPlatformNetworkErrorMessage(\n    _In_ XblHttpCallHandle call,\n    _Out_ const char** platformNetworkErrorMessage\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get a response header for the HTTP call for a given header name.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"headerName\">UTF-8 encoded response header name for the HTTP call.  \n/// The memory for the returned string pointer remains valid for the life of \n/// the XblHttpCallHandle object until XblHttpCallCloseHandle() is called on it.</param>\n/// <param name=\"headerValue\">UTF-8 encoded response header value for the HTTP call.  \n/// Returns nullptr if the header doesn't exist.  \n/// The memory for the returned string pointer remains valid for the life of \n/// the XblHttpCallHandle object until XblHttpCallCloseHandle() is called on it.</param>\n/// <returns>Result code for this API operation. Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.\n/// </remarks>\nSTDAPI XblHttpCallGetHeader(\n    _In_ XblHttpCallHandle call,\n    _In_z_ const char* headerName,\n    _Out_ const char** headerValue\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the number of response headers in the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"numHeaders\">The number of response headers in the HTTP call.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.\n/// </remarks>\nSTDAPI XblHttpCallGetNumHeaders(\n    _In_ XblHttpCallHandle call,\n    _Out_ uint32_t* numHeaders\n    ) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the response headers at specific zero based index in the HTTP call.\n/// </summary>\n/// <param name=\"call\">The handle of the HTTP call.</param>\n/// <param name=\"headerIndex\">Specific zero based index of the response header.</param>\n/// <param name=\"headerName\">UTF-8 encoded response header name for the HTTP call.  \n/// The memory for the returned string pointer remains valid for the life of \n/// the XblHttpCallHandle object until XblHttpCallCloseHandle() is called on it.</param>\n/// <param name=\"headerValue\">UTF-8 encoded response header value for the HTTP call.  \n/// The memory for the returned string pointer remains valid for the life of \n/// the XblHttpCallHandle object until XblHttpCallCloseHandle() is called on it.</param>\n/// <returns>Result code for this API operation.  Possible values are S_OK, E_INVALIDARG, or E_FAIL.</returns>\n/// <remarks>\n/// This can only be called after calling <see cref=\"XblHttpCallPerformAsync\"/> when the HTTP task is completed.  \n/// Use <see cref=\"XblHttpCallGetNumHeaders\"/> to know how many response headers there are in the HTTP call.\n/// </remarks>\nSTDAPI XblHttpCallGetHeaderAtIndex(\n    _In_ XblHttpCallHandle call,\n    _In_ uint32_t headerIndex,\n    _Out_ const char** headerName,\n    _Out_ const char** headerValue\n    ) XBL_NOEXCEPT;\n}"
  },
  {
    "path": "Include/xsapi-c/leaderboard_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n    \n/// <summary>\n/// Enumerates the data type of a leaderboard statistic.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardColumn\"/></memof>\nenum class XblLeaderboardStatType : uint32_t\n{\n    /// <summary>\n    /// Unsigned 64 bit integer.\n    /// </summary>\n    Uint64,\n\n    /// <summary>\n    /// Boolean.\n    /// </summary>\n    Boolean,\n\n    /// <summary>\n    /// Double.\n    /// </summary>\n    Double,\n\n    /// <summary>\n    /// String.\n    /// </summary>\n    String,\n\n    /// <summary>\n    /// Unknown.\n    /// </summary>\n    Other\n};\n\n/// <summary> \n/// The order to sort the leaderboard in.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardQuery\"/></memof>\nenum class XblLeaderboardSortOrder : uint32_t\n{\n    /// <summary> \n    /// Sorting the leaderboard highest to lowest.\n    /// </summary>\n    Descending,\n\n    /// <summary> \n    /// Sorting the leaderboard lowest to highest.\n    /// </summary>\n    Ascending\n};\n\n/// <summary> \n/// Predefined Xbox Live social groups.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardQuery\"/></memof>\nenum class XblSocialGroupType : uint32_t\n{\n    /// <summary> \n    /// No social group.\n    /// </summary>\n    None,\n\n    /// <summary> \n    /// Social group for the people followed.\n    /// </summary>\n    People,\n\n    /// <summary> \n    /// Social group for the people tagged as favorites.\n    /// </summary>\n    Favorites\n};\n\n/// <summary>\n/// Enum used to specify the type of leaderboard in a Leaderboard query.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardQuery\"/></memof>\nenum class XblLeaderboardQueryType : uint32_t\n{\n    /// <summary>\n    /// A leaderboard based an event based user stat.\n    /// </summary>\n    UserStatBacked = 0,\n\n    /// <summary>\n    /// A global leaderboard backed by a title managed stat.\n    /// </summary>\n    TitleManagedStatBackedGlobal = 1,\n\n    /// <summary>\n    /// A social leaderboard backed by a title managed stat.\n    /// </summary>\n    TitleManagedStatBackedSocial = 2,\n};\n\n\n/// <summary>\n/// Represents a column in a collection of leaderboard items.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardResult\"/></memof>\ntypedef struct XblLeaderboardColumn \n{\n    /// <summary>\n    /// The UTF-8 encoded name the statistic displayed in the column.\n    /// </summary>\n    _Field_z_ const char* statName;\n\n    /// <summary>\n    /// The property type of the statistic in the column.\n    /// </summary>\n    XblLeaderboardStatType statType;\n\n} XblLeaderboardColumn;\n\n/// <summary>\n/// Represents a row in a collection of leaderboard items.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardResult\"/></memof>\ntypedef struct XblLeaderboardRow \n{\n    /// <summary>\n    /// The UTF-8 encoded gamertag of the player.\n    /// </summary>\n    _Field_z_ char gamertag[XBL_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded modern gamertag for the player.  \n    /// Not guaranteed to be unique.\n    /// </summary>\n    char modernGamertag[XBL_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded suffix appended to modern gamertag to ensure uniqueness.  \n    /// May be empty in some cases.\n    /// </summary>\n    char modernGamertagSuffix[XBL_MODERN_GAMERTAG_SUFFIX_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded unique modern gamertag and suffix. Format will be \"modernGamertag#suffix\".  \n    /// Guaranteed to be no more than 16 rendered characters.\n    /// </summary>\n    char uniqueModernGamertag[XBL_UNIQUE_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The Xbox user ID of the player.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// The percentile rank of the player.\n    /// </summary>\n    double percentile;\n\n    /// <summary>\n    /// The rank of the player.\n    /// </summary>\n    uint32_t rank;\n\n    /// <summary>\n    /// The global rank of the player. If globalrank is 0, then the user has no global rank.\n    /// </summary>\n    uint32_t globalRank;\n\n    /// <summary>\n    /// UTF-8 encoded JSON values for each column in the leaderboard row for the player.\n    /// </summary>\n    _Field_z_ const char** columnValues;\n\n    /// <summary>\n    /// The count of string in socialNetworks array.\n    /// </summary>\n    size_t columnValuesCount;\n\n} XblLeaderboardRow;\n\n/// <summary>\n/// Represents the parameters for submitting a leaderboard query using event-based or title-based stats.\n/// </summary>\n/// <memof><see cref=\"XblLeaderboardResult\"/></memof>\n/// <argof><see cref=\"XblLeaderboardGetLeaderboardAsync\"/></argof>\ntypedef struct XblLeaderboardQuery\n{\n    /// <summary>\n    /// Optional Xbox user ID of the requesting user.  \n    /// If doing a global leaderboard, then set to 0.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// The UTF-8 encoded service configuration ID (SCID) of the title.\n    /// </summary>\n    _Field_z_ char scid[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// Optional UTF-8 encoded leaderboard name to get a leaderboard for.\n    /// Set to nullptr if querying a social leaderboard or a title managed stat backed leaderboard.\n    /// </summary>\n    _Field_z_ const char* leaderboardName;\n\n    /// <summary>\n    /// Optional UTF-8 encoded statistic name to get a leaderboard for.\n    /// Used when querying a social leaderboard or title managed stat backed leaderboard.\n    /// </summary>\n    _Field_z_ const char* statName;\n\n    /// <summary>\n    /// Optional the social group of users to get leaderboard results.  \n    /// For example, to get a \"friends only\" leaderboard.  \n    /// Set to XblSocialGroupType_None to get a global leaderboard.\n    /// </summary>\n    XblSocialGroupType socialGroup;\n\n    /// <summary>\n    /// Optional UTF-8 encoded array of names of stats for the additional columns.\n    /// </summary>\n    _Field_z_ const char** additionalColumnleaderboardNames;\n\n    /// <summary>\n    /// Optional count of additionalColumnleaderboardNames passed in.\n    /// </summary>\n    size_t additionalColumnleaderboardNamesCount;\n\n    /// <summary>\n    /// Set sort order for the resulting leaderboard.\n    /// </summary>\n    XblLeaderboardSortOrder order;\n\n    /// <summary>\n    /// Set maximum items that the resulting leaderboard will contain.  \n    /// Set to 0 to let the service return the default number of max items.\n    /// </summary>\n    uint32_t maxItems;\n\n    /// <summary>\n    /// Set the resulting leaderboard will start with the \n    /// user that requested the leaderboard.  \n    /// Set to 0 to not skip to a user.\n    /// </summary>\n    uint64_t skipToXboxUserId;\n\n    /// <summary>\n    /// Set which rank the resulting leaderboard will start at.  \n    /// Set 0 to not skip to a specific rank.\n    /// </summary>\n    uint32_t skipResultToRank;\n\n    /// <summary>\n    /// The UTF-8 encoded continuationToken used to get the next set of leaderboard data.\n    /// </summary>\n    _Field_z_ const char* continuationToken;\n\n    /// <summary>\n    /// The type of leaderboard to query for.\n    /// </summary>\n    XblLeaderboardQueryType queryType;\n} XblLeaderboardQuery;\n\n/// <summary>\n/// Represents the results of a leaderboard request.\n/// </summary>\n/// <argof><see cref=\"XblLeaderboardGetLeaderboardResult\"/></argof>\n/// <argof><see cref=\"XblLeaderboardResultGetNextAsync\"/></argof>\n/// <argof><see cref=\"XblLeaderboardResultGetNextResult\"/></argof>\ntypedef struct XblLeaderboardResult \n{\n    /// <summary>\n    /// The total number of rows in the leaderboard results.\n    /// </summary>\n    uint32_t totalRowCount;\n\n    /// <summary>\n    /// The collection of columns in the leaderboard results.\n    /// </summary>\n    XblLeaderboardColumn* columns;\n\n    /// <summary>\n    /// The number of **columns**.\n    /// </summary>\n    size_t columnsCount;\n\n    /// <summary>\n    /// The collection of rows in the leaderboard results.\n    /// </summary>\n    XblLeaderboardRow* rows;\n\n    /// <summary>\n    /// The number of **rows**.\n    /// </summary>\n    size_t rowsCount;\n\n    /// <summary>\n    /// Indicates whether there is a next page of results.\n    /// </summary>\n    bool hasNext;\n\n    /// <summary>\n    /// The next query.  \n    /// Internal use only.\n    /// </summary>\n    XblLeaderboardQuery nextQuery;\n} XblLeaderboardResult;\n\n/// <summary>\n/// Get a leaderboard for a title using event-based or title-based stats.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"leaderboardQuery\">The query parameters of the leaderboard request.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>V4 GET https://leaderboards.xboxlive.com/users/xuid({xuid})/scids/{scid}/stats/{statname}/people/{all|favorites}[?sort=descending|ascending]&amp;skipToUser={skipToUser} </rest>\nSTDAPI XblLeaderboardGetLeaderboardAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblLeaderboardQuery leaderboardQuery,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblLeaderboardGetLeaderboardAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the user statistics result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblLeaderboardGetLeaderboardResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblLeaderboardGetLeaderboardAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblLeaderboardGetLeaderboardResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer to write result into.</param>\n/// <param name=\"ptrToBuffer\">Strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblLeaderboardGetLeaderboardResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblLeaderboardResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of next page of the leaderboard for a player of the specified title.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"leaderboardResult\">The leaderboard result from a previous call to XblLeaderboardGetLeaderboardResult.</param>\n/// <param name=\"maxItems\">The maximum number of items that the result can contain.  \n/// Pass 0 to attempt to retrieve all items.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XblLeaderboardResultGetNextResult\"/> inside the AsyncBlock callback\n/// or after the AsyncBlock is complete.\n/// </remarks>\nSTDAPI XblLeaderboardResultGetNextAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblLeaderboardResult* leaderboardResult,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblLeaderboardResultGetNextAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the user statistics result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblLeaderboardResultGetNextResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblLeaderboardResultGetNextAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblLeaderboardResultGetNextResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer to write result into.</param>\n/// <param name=\"ptrToBuffer\">Strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblLeaderboardResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblLeaderboardResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n} // end extern c\n"
  },
  {
    "path": "Include/xsapi-c/matchmaking_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n#include \"multiplayer_c.h\"\n\nextern \"C\"\n{\n/// <summary>\n/// Defines values used to indicate whether a match ticket is for a new\n/// game session or an existing session.\n/// </summary>\nenum class XblPreserveSessionMode : uint32_t\n{\n    /// <summary>\n    /// The server returned an unrecognized response.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Always use an existing game session.  \n    /// This is for matching more players for a game session \n    /// that is already created or in progress.\n    /// </summary>\n    Always,\n\n    /// <summary>\n    /// Never use an existing game session.  \n    /// This is for matching players for a new game session.\n    /// </summary>\n    Never\n};\n\n/// <summary>\n/// Defines values used to indicate the status of the match request.\n/// </summary>\nenum class XblTicketStatus : uint32_t\n{\n    /// <summary>\n    /// The status of the match request has not been returned by the server yet\n    /// or the server returned an unrecognized response.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Matchmaking has not found a match and the search\n    /// request has expired according to its give up duration.\n    /// </summary>\n    Expired,\n\n    /// <summary>\n    /// Matchmaking has not found a match yet and it is\n    /// still searching.\n    /// </summary>\n    Searching,\n\n    /// <summary>\n    /// Matchmaking has found a match and the ticket contains a\n    /// reference to the session that is to be created.\n    /// </summary>\n    Found,\n\n    /// <summary>\n    /// Matchmaking has been canceled for this ticket.\n    /// </summary>\n    Canceled\n};\n\n/// <summary>\n/// Contains information about server response to a create match ticket request.\n/// </summary>\ntypedef struct XblCreateMatchTicketResponse \n{\n    /// <summary>\n    /// Ticket ID of a match request.\n    /// </summary>\n    _Field_z_ char matchTicketId[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    int64_t estimatedWaitTime;\n\n} XblCreateMatchTicketResponse;\n\n/// <summary>\n/// Represents a server response to a request for match ticket details.\n/// </summary>\ntypedef struct XblMatchTicketDetailsResponse \n{\n    /// <summary>\n    /// Status of a match request.\n    /// </summary>\n    XblTicketStatus matchStatus;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    int64_t estimatedWaitTime;\n\n    /// <summary>\n    /// An enum value to specify whether the match should preserve the session on which the match has been requested.\n    /// </summary>\n    XblPreserveSessionMode preserveSession;\n\n    /// <summary>\n    /// The session on which the match was requested.\n    /// </summary>\n    XblMultiplayerSessionReference ticketSession;\n        \n    /// <summary>\n    /// The session on which a match request has been found.\n    /// </summary>\n    XblMultiplayerSessionReference targetSession;\n\n    /// <summary>\n    /// The attributes of a match request.\n    /// </summary>\n    char* ticketAttributes;\n\n} XblMatchTicketDetailsResponse;\n\n\n/// <summary>\n/// Represents a server response to a hopper statistics request.\n/// </summary>\ntypedef struct XblHopperStatisticsResponse \n{\n    /// <summary>\n    /// Name of the hopper in which a match was requested.\n    /// </summary>\n    _Field_z_ char* hopperName;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    int64_t estimatedWaitTime;\n\n    /// <summary>\n    /// The number of players in the hopper waiting to be matched.\n    /// </summary>\n    uint32_t playersWaitingToMatch;\n\n} XblHopperStatisticsResponse;\n\n/// <summary>\n/// Sends a matchmaking request to the server and returns the match ticket with a ticket id.  \n/// Call XblMatchmakingCreateMatchTicketResult upon completion to get the result.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"ticketSessionReference\">The multiplayer session to use for the match.</param>\n/// <param name=\"matchmakingServiceConfigurationId\">The service configuration ID for the match.</param>\n/// <param name=\"hopperName\">The name of the hopper.</param>\n/// <param name=\"ticketTimeout\">The maximum time to wait for players to join the session.</param>\n/// <param name=\"preserveSession\">Indicates if the session should be preserved.</param>\n/// <param name=\"ticketAttributesJson\">The ticket attributes for the session. (Optional)</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>Calls V103 POST /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}</rest>\n/// <remarks>\n/// The match ticket object contains server returned information such as ticket id and wait\n/// time, and also contains copies of the title specified data from the ticket data object.\n/// </remarks>\nSTDAPI XblMatchmakingCreateMatchTicketAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblMultiplayerSessionReference ticketSessionReference,\n    _In_ const char* matchmakingServiceConfigurationId,\n    _In_ const char* hopperName,\n    _In_ const uint64_t ticketTimeout,\n    _In_ XblPreserveSessionMode preserveSession,\n    _In_ const char* ticketAttributesJson,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblMatchmakingCreateMatchTicketAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultPtr\">A caller allocated struct to be filled with the match ticket results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMatchmakingCreateMatchTicketResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ XblCreateMatchTicketResponse* resultPtr\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Deletes a the match ticket on the server.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"hopperName\">The name of the hopper where the match ticket is located.</param>\n/// <param name=\"ticketId\">The id of the ticket to delete on the server.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>Calls V103 DELETE /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/tickets/{ticketId}</rest>\nSTDAPI XblMatchmakingDeleteMatchTicketAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* serviceConfigurationId,\n    _In_ const char* hopperName,\n    _In_ const char* ticketId,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the properties of a match ticket from the server.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"hopperName\">The name of the hopper where the match ticket is located.</param>\n/// <param name=\"ticketId\">The ticket id of the match ticket to retrieve.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>Calls V103 GET /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/tickets/{ticketId}</rest>\nSTDAPI XblMatchmakingGetMatchTicketDetailsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* serviceConfigurationId,\n    _In_ const char* hopperName,\n    _In_ const char* ticketId,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblMatchmakingGetMatchTicketDetailsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the Create Match Ticket result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMatchmakingGetMatchTicketDetailsResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblMatchmakingGetMatchTicketDetailsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.\n/// Use <see cref=\"XblMatchmakingGetMatchTicketDetailsResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer to write result into.</param>\n/// <param name=\"ptrToBuffer\">Strongly typed pointer that points into buffer.  \n/// This is a pointer within buffer and should not be freed separately.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMatchmakingGetMatchTicketDetailsResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMatchTicketDetailsResponse** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets statistics about a hopper such as how many players are in it.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"hopperName\">The name of the hopper to query stats for.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>Calls V103 GET /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/stats</rest>\nSTDAPI XblMatchmakingGetHopperStatisticsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* serviceConfigurationId,\n    _In_ const char* hopperName,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblMatchmakingGetHopperStatisticsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the Create Match Ticket result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMatchmakingGetHopperStatisticsResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblMatchmakingGetHopperStatisticsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.\n/// Use <see cref=\"XblMatchmakingGetHopperStatisticsResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer to write result into.</param>\n/// <param name=\"ptrToBuffer\">Strongly typed pointer that points into buffer.  \n/// This is a pointer within buffer and should not be freed separately.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMatchmakingGetHopperStatisticsResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblHopperStatisticsResponse** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n} // end extern c"
  },
  {
    "path": "Include/xsapi-c/multiplayer_activity_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\n#include \"xsapi-c/pal.h\"\n\nextern \"C\"\n{\n\n/// <summary>\n/// Enumerates the platforms on which a title can be activated.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerActivityInfo\"/></memof>\n/// <argof><see cref=\"XblMultiplayerActivitySetActivityAsync\"/></argof>\nenum class XblMultiplayerActivityPlatform : uint32_t\n{\n    /// <summary>\n    /// Unknown device.\n    /// </summary>\n    Unknown = 0,\n\n    /// <summary>\n    /// Xbox One device.\n    /// </summary>\n    XboxOne = 1,\n\n    /// <summary>\n    /// Windows OneCore (Universal Windows Platform [UWP] and {% term projname %} on PC).\n    /// </summary>\n    WindowsOneCore = 2,\n\n    /// <summary>\n    /// Win32-based device.\n    /// </summary>\n    Win32 = 3,\n\n    /// <summary>\n    /// {% term scarlett %} device.\n    /// </summary>\n    Scarlett = 4,\n\n    /// <summary>\n    /// iOS device.\n    /// </summary>\n    iOS = 20,\n\n    /// <summary>\n    /// Android device.\n    /// </summary>\n    Android = 30,\n\n    /// <summary>\n    /// Nintendo device.\n    /// </summary>\n    Nintendo = 40,\n\n    /// <summary>\n    /// PlayStation device.\n    /// </summary>\n    PlayStation = 50,\n\n    /// <summary>\n    /// Activity is joinable on all platforms supported by the title.\n    /// </summary>\n    All = 60\n};\n\n/// <summary>\n/// Enumerates who can join a player's current activity.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerActivityInfo\"/></memof>\n/// <argof><see cref=\"XblMultiplayerActivitySetActivityAsync\"/></argof>\n/// <remarks>\n/// To see how this enumeration is used, see \"Setting an activity\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>.\n/// </remarks>\nenum class XblMultiplayerActivityJoinRestriction : uint32_t\n{\n    /// <summary>\n    /// Everyone.\n    /// </summary>\n    Public = 0,\n\n    /// <summary>\n    /// Only invited players.\n    /// </summary>\n    InviteOnly = 1,\n\n    /// <summary>\n    /// Only followed players.\n    /// </summary>\n    Followed = 2\n};\n\n/// <summary>\n/// Enumerates types of recent player encounters.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerActivityRecentPlayerUpdate\"/></memof>\n/// <remarks>\n/// To see how this enumeration is used, see \"Setting an activity\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>.\n/// </remarks>\nenum class XblMultiplayerActivityEncounterType : uint32_t\n{\n    /// <summary>\n    /// No inherent meaning. The title interprets this value as appropriate.\n    /// </summary>\n    Default = 0,\n\n    /// <summary>\n    /// Teammate.\n    /// </summary>\n    Teammate = 1,\n\n    /// <summary>\n    /// Opponent.\n    /// </summary>\n    Opponent = 2\n};\n\n/// <summary>\n/// Information about a player's activity while playing a title.\n/// </summary>\n/// <argof><see cref=\"XblMultiplayerActivityGetActivityResult\"/></argof>\n/// <argof><see cref=\"XblMultiplayerActivitySetActivityAsync\"/></argof>\n/// <remarks>\n/// To see how this enumeration is used, see \"Setting an activity\" and \"Getting activities\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>.\n/// </remarks>\ntypedef struct XblMultiplayerActivityInfo\n{\n    /// <summary>\n    /// The Xbox user ID to which the activity info belongs.\n    /// </summary>\n    uint64_t xuid;\n\n    /// <summary>\n    /// The connection string passed to the connecting client to join a game;\n    /// typically contains information such as the server IP address.\n    /// When querying activities, this field is populated only if the activity is public\n    /// or the player is following the caller.\n    /// </summary>\n    _Field_z_ const char* connectionString;\n\n    /// <summary>\n    /// Specifies who can join the player's current activity.\n    /// </summary>\n    XblMultiplayerActivityJoinRestriction joinRestriction;\n\n    /// <summary>\n    /// The maximum number of players who can join the player's current activity.  \n    /// A value of 0 indicates that no players can join.\n    /// </summary>\n    size_t maxPlayers;\n\n    /// <summary>\n    /// The number of players already playing with the player in a multiplayer activity.  \n    /// A value of 0 indicates that no other players are currently playing.\n    /// </summary>\n    size_t currentPlayers;\n\n    /// <summary>\n    /// A unique identifier to group all users playing as part of the same activity.  \n    /// The title sets this identifier when it creates the activity.\n    /// </summary>\n    _Field_z_ const char* groupId;\n\n    /// <summary>\n    /// The platform on which the activity is happening.\n    /// When setting an activity, the platform is automatically inferred; this field is ignored.\n    /// </summary>\n    XblMultiplayerActivityPlatform platform;\n} XblMultiplayerActivityInfo;\n\n/// <summary>\n/// Describes a recent player encounter.\n/// </summary>\n/// <argof><see cref=\"XblMultiplayerActivityUpdateRecentPlayers\"/></argof>\n/// <remarks>\n/// To see how this enumeration is used, see \"Updating recent players\" in \n/// the <see href=\"live-mpa-client-how-to.md#recent-players\">Recent players</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>.\n/// </remarks>\ntypedef struct XblMultiplayerActivityRecentPlayerUpdate\n{\n    /// <summary>\n    /// Xbox user ID of the encountered user.\n    /// </summary>\n    uint64_t xuid;\n\n    /// <summary>\n    /// The type of encounter.\n    /// </summary>\n    XblMultiplayerActivityEncounterType encounterType;\n} XblMultiplayerActivityRecentPlayerUpdate;\n\n/// <summary>\n/// Appends to a player's list of recent players.  \n/// If an encountered user is already in the list, it updates the existing recent-player entry.\n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"updates\">List of <see cref=\"XblMultiplayerActivityRecentPlayerUpdate\"/> objects to append to the recent players list.</param>\n/// <param name=\"updatesCount\">Size of the `updates` array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This call is unidirectional; it only affects the caller's recent-players list. <br/><br/>\n/// Recent-player updates are batched and uploaded by XSAPI by using the background queue provided during `XblInitialize`. <br/><br/>\n/// To force an immediate flush, call <see cref=\"XblMultiplayerActivityFlushRecentPlayersAsync\"/>.\n/// </remarks>\nSTDAPI XblMultiplayerActivityUpdateRecentPlayers(\n    _In_ XblContextHandle xblContext,\n    _In_reads_(updatesCount) const XblMultiplayerActivityRecentPlayerUpdate* updates,\n    _In_ size_t updatesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Immediately writes any pending recent-players updates to {% term xbox-live %}.  \n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Calling this API is optional; updates are periodically uploaded from a background task queue. <br/><br/>\n/// When this API is used, the upload happens on the task queue supplied in this call. <br/><br/>\n/// To get the result of the asynchronous operation, call <see cref=\"XAsyncGetStatus\"/> \n/// inside the `XAsyncBlock` callback or after `XAsyncBlock` is complete. <br/><br/>\n/// To see how this enumeration is used, see the \n/// <see href=\"live-mpa-client-how-to.md#recent-players\">Recent players</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>.\n/// </remarks>\n/// <rest>Calls POST /titles/{titleId}/recentplayers</rest>\nSTDAPI XblMultiplayerActivityFlushRecentPlayersAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets or updates the multiplayer activity for a local user.  \n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"activityInfo\">Information about the activity. \n/// The `maxPlayers` and `currentPlayers` fields are optional; they are ignored if set to 0. \n/// The value of the `platform` field is ignored; XSAPI automatically sets the activity \n/// on the appropriate local platform.</param>\n/// <param name=\"allowCrossPlatformJoin\">\n/// True if the activity should be joinable on other platforms supported by the title.\n/// </param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When a title starts or joins a multiplayer experience, it should create an \n/// activity. Doing this lets both the shell and other players in your title \n/// see the player's activity. Your title can let other players join the game \n/// in progress. If a player wants to join an activity for your title and it is not \n/// running, it is activated and the connection string is passed to it. <br/><br/>\n/// To see how this function is used, see \"Setting an activity\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>.\n/// </remarks>\n/// <rest>Calls PUT /titles/{titleId}/users/{xuid}/activites</rest>\nSTDAPI XblMultiplayerActivitySetActivityAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerActivityInfo* activityInfo,\n    _In_ bool allowCrossPlatformJoin,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the multiplayer activity for a set of users. You can query at most 30 users with each call.\n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"xuids\">List of Xbox user IDs for whom to get multiplayer activity.</param>\n/// <param name=\"xuidsCount\">Size of the `xuids` array.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XblMultiplayerActivityGetActivityResultSize\"/> and \n/// <see cref=\"XblMultiplayerActivityGetActivityResult\"/> inside the `XAsyncBlock` callback or \n/// after the async operation is complete. <br/><br/>\n/// To see how this function is used, see \"Getting activities\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\n/// <rest>Calls POST /titles/{titleId}/activities/query</rest>\nSTDAPI XblMultiplayerActivityGetActivityAsync(\n    _In_ XblContextHandle xblContext,\n    _In_reads_(xuidsCount) const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the buffer size needed to store the results of a get activity call.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes for the result buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To see how this function is used, see \"Getting activities\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerActivityGetActivityAsync\"/>\n/// <seealso cref=\"XblMultiplayerActivityGetActivityResult\"/>\nSTDAPI XblMultiplayerActivityGetActivityResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the results for a successful get activity call.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"bufferSize\">The size of the result buffer.  \n/// Use <see cref=\"XblMultiplayerActivityGetActivityResultSize\"/> to get the required buffer size.</param>\n/// <param name=\"buffer\">A caller-allocated byte buffer that receives the result.</param>\n/// <param name=\"ptrToBufferResults\">Strongly typed array of <see cref=\"XblMultiplayerActivityInfo\"/> that \n/// points into `buffer`. Do not free this array. Its lifecycle is tied to `buffer`.\n/// </param>\n/// <param name=\"resultCount\">The number of entries in the `ptrToBufferResults` array.</param>\n/// <param name=\"bufferUsed\">The number of bytes in `buffer` that were used.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the size of the buffer that you need to store the results, call the\n/// <see cref=\"XblMultiplayerActivityGetActivityResultSize\"/> function. <br/><br/>\n/// To see how this function is used, see \"Getting activities\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\nSTDAPI XblMultiplayerActivityGetActivityResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMultiplayerActivityInfo** ptrToBufferResults,\n    _Out_ size_t* resultCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Clears the multiplayer activity for the local user.\n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Titles should delete the activity for a user as soon as they leave the multiplayer activity. <br/><br/>\n/// If the title does not delete a user's activity, it is automatically cleared by a presence check. <br/><br/>\n/// To get the result of the asynchronous operation, call <see cref=\"XAsyncGetStatus\"/> \n/// inside the `XAsyncBlock` callback or after `XAsyncBlock` is complete. <br/><br/>\n/// To see how this function is used, see \"Deleting an activity\" in \n/// the <see href=\"live-mpa-client-how-to.md#activities\">Activities</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\n/// <rest>Calls DELETE /titles/{titleId}/users/{xuid}/activites</rest>\nSTDAPI XblMultiplayerActivityDeleteActivityAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sends invites to Xbox user IDs to join the caller's current activity.\n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"xuids\">List of Xbox user IDs to invite.</param>\n/// <param name=\"xuidsCount\">Size of the `xuids` array.</param>\n/// <param name=\"allowCrossPlatformJoin\">If the title is configured for cross-platform invites, \n/// setting this parameter to true sends an invite to all platform endpoints that the title supports.  \n/// If set to false, the invite is sent to the sender's platform platform only.  \n/// If cross-platform invites are not configured, the invite is always sent to the sender's platform only.</param>\n/// <param name=\"connectionString\">(Optional) Connection string that the peer uses to join the game.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result of the asynchronous operation, call <see cref=\"XAsyncGetStatus\"/> \n/// inside the `XAsyncBlock` callback or after `XAsyncBlock` is complete. <br/><br/>\n/// To see how this function is used, see \"Sending invites\" in \n/// the <see href=\"live-mpa-client-how-to.md#invites\">Invites</see> section \n/// of <see href=\"live-mpa-client-how-to.md\">Example code for Multiplayer Activity</see>. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\n/// <rest>Calls POST /titles/{titleId}/invites</rest>\nSTDAPI XblMultiplayerActivitySendInvitesAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_ bool allowCrossPlatformJoin,\n    _In_opt_z_ const char* connectionString,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n/// <summary>\n/// Describes multiplayer activity invites.\n/// </summary>\n/// <argof><see cref=\"XblMultiplayerActivityInviteHandler\"/></argof>\n/// <remarks>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\ntypedef struct XblMultiplayerActivityInviteData\n{\n    /// <summary>\n    /// The Xbox user ID of the invited user.\n    /// </summary>\n    uint64_t invitedXuid;\n\n    /// <summary>\n    /// The Xbox user ID of the user sending the invite.\n    /// </summary>\n    uint64_t senderXuid;\n\n    /// <summary>\n    /// URL of the sender's gamerpic.\n    /// </summary>\n    _Field_z_ const char* senderImageUrl;\n\n    /// <summary>\n    /// The UTF-8 encoded gamertag of the player.\n    /// </summary>\n    char senderGamertag[XBL_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded modern gamertag of the player.\n    /// Not guaranteed to be unique.\n    /// </summary>\n    char senderModernGamertag[XBL_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded suffix appended to the modern gamertag to ensure uniqueness.\n    /// Can be empty in some cases.\n    /// </summary>\n    char senderModernGamertagSuffix[XBL_MODERN_GAMERTAG_SUFFIX_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded unique modern gamertag and suffix.\n    /// Format is \"modernGamertag#suffix\".\n    /// Guaranteed to be no more than 16 rendered characters.\n    /// </summary>\n    char senderUniqueModernGamertag[XBL_UNIQUE_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The name of the title for which the invite is being sent.\n    /// </summary>\n    _Field_z_ const char* titleName;\n\n    /// <summary>\n    /// URL of the title image used in the invite.\n    /// </summary>\n    _Field_z_ const char* titleImageUrl;\n\n    /// <summary>\n    /// Connection string to pass to the connecting client so that it can join a game.\n    /// Typically contains information such as the server IP address.\n    /// </summary>\n    _Field_z_ const char* connectionString;\n\n    /// <summary>\n    /// Expiration time.\n    /// </summary>\n    time_t expirationTime;\n} XblMultiplayerActivityInviteData;\n\n/// <summary>\n/// Event handler for multiplayer activity invites.\n/// </summary>\n/// <param name=\"data\">Data needed by the invitee to respond to a game invite.</param>\n/// <param name=\"context\">Client context provided when the handler was added.</param>\n/// <returns></returns>\n/// <remarks>\n/// The lifetime of the <see cref=\"XblMultiplayerActivityInviteData\"/> object is limited to the callback. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\ntypedef void CALLBACK XblMultiplayerActivityInviteHandler(\n    _In_ const XblMultiplayerActivityInviteData* data,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for multiplayer activity invites.\n/// </summary>\n/// <param name=\"xblContextHandle\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context to be passed to the handler.</param>\n/// <returns>An `XblFunctionContext` object that can be used to unregister the event handler.</returns>\n/// <remarks>\n/// To unregister an event handler for multiplayer activity invites, call the\n/// <see cref=\"XblMultiplayerActivityRemoveInviteHandler\"/> function. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\nSTDAPI_(XblFunctionContext) XblMultiplayerActivityAddInviteHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblMultiplayerActivityInviteHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for multiplayer activity invites.\n/// </summary>\n/// <param name=\"xblContextHandle\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"token\">The `XblFunctionContext` object that was returned when the event handler was registered.</param>\n/// <returns></returns>\n/// <remarks>\n/// To register an event handler for multiplayer activity invites, call the\n/// <see cref=\"XblMultiplayerActivityAddInviteHandler\"/> function. <br/><br/>\n/// For more information about multiplayer activities, see\n/// <see href=\"live-mpa-activities.md\">Activities</see>.\n/// </remarks>\nSTDAPI XblMultiplayerActivityRemoveInviteHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n#endif\n}"
  },
  {
    "path": "Include/xsapi-c/multiplayer_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n    #error C++11 required\n#endif\n\n#pragma once\n\n#include \"pal.h\"\n\nextern \"C\"\n{\n\n/// <summary>\n/// Defines values that indicate the state of a tournament game.\n/// DEPRECATED. This enumeration will be removed in a future release.\n/// </summary>\n/// <memof><see cref=\"XblTournamentGameResultWithRank\"/></memof>\nenum class XblTournamentGameResult : uint32_t\n{\n    /// <summary>\n    /// No game.\n    /// </summary>\n    NoContest,\n\n    /// <summary>\n    /// Win.\n    /// </summary>\n    Win,\n\n    /// <summary>\n    /// Loss.\n    /// </summary>\n    Loss,\n\n    /// <summary>\n    /// Draw.\n    /// </summary>\n    Draw,\n\n    /// <summary>\n    /// Rank.\n    /// </summary>\n    Rank,\n\n    /// <summary>\n    /// Didn't show up.\n    /// </summary>\n    NoShow,\n};\n\n/// <summary>\n/// Defines values that indicate the arbitration state of a tournament game.\n/// DEPRECATED. This enumeration will be removed in a future release.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerArbitrationServer\"/></memof>\nenum class XblTournamentArbitrationState : uint32_t\n{\n    /// <summary>\n    /// No arbitration state is set.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Results were fully uploaded and complete.\n    /// </summary>\n    Completed,\n\n    /// <summary>\n    /// The match was canceled, such as in the case of forfeiting.\n    /// </summary>\n    Canceled,\n\n    /// <summary>\n    /// The match began, but no players or servers reported results before the arbitration deadline.\n    /// </summary>\n    NoResults,\n\n    /// <summary>\n    /// Some results were received, and results were compiled based on the incomplete data.\n    /// </summary>\n    PartialResults\n};\n\n/// <summary>\n/// Defines values that indicate the source for a tournament game state.\n/// DEPRECATED. This enumeration will be removed in a future release.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerArbitrationServer\"/></memof>\n/// <memof><see cref=\"XblMultiplayerTournamentsServer\"/></memof>\nenum class XblTournamentGameResultSource : uint32_t\n{\n    /// <summary>\n    /// No game result source.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Game result is determined by client arbitration.\n    /// </summary>\n    Arbitration,\n\n    /// <summary>\n    /// Game result is determined by game servers.\n    /// </summary>\n    Server,\n\n    /// <summary>\n    /// Game result is adjusted by tournament administrator.\n    /// </summary>\n    Adjusted,\n};\n\n/// <summary>\n/// Defines values that indicate the status of a tournament game result.\n/// DEPRECATED. This enumeration will be removed in a future release.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionMember\"/></memof>\n/// <seealso cref=\"XblMultiplayerSessionConstants\"/>\nenum class XblTournamentArbitrationStatus : uint32_t\n{\n    /// <summary>\n    /// The system time is before the arbitration start time (`ArbitrationStartTime`), which is also the start time for the match.\n    /// </summary>\n    Waiting,\n\n    /// <summary>\n    /// The system time is after the arbitration start time (`ArbitrationStartTime`), and at least one player has become active.\n    /// </summary>\n    InProgress,\n\n    /// <summary>\n    /// The player reported results, so the player's role in the arbitration process is now done.  \n    /// Occurs when arbitration succeeds, after the arbitration forfeit time (`ArbitrationStartTime` \n    /// plus the `ForfeitTimeout` delta) if no players have joined, or after arbitration time-out \n    /// (`ArbitrationStartTime` plus the `ArbitrationTimeout` delta).\n    /// </summary>\n    Complete,\n\n    /// <summary>\n    /// The player has become active at least once and is now participating in the match.\n    /// </summary>\n    Playing,\n\n    /// <summary>\n    /// The player was not able to upload results before arbitration time-out (`ArbitrationStartTime` plus the `ArbitrationTimeout` delta).\n    /// </summary>\n    Incomplete,\n\n    /// <summary>\n    /// The system time is after the arbitration start time (`ArbitrationStartTime`), but the player is not yet active.\n    /// </summary>\n    Joining\n};\n\n/// <summary>\n/// Defines values that indicate the team session registration state for a tournament.\n/// DEPRECATED. This enumeration will be removed in a future release.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerTournamentsServer\"/></memof>\nenum class XblTournamentRegistrationState : uint32_t\n{\n    /// <summary>\n    /// The team registration state is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Registration was successfully received by the Tournament service and will be eventually processed.\n    /// </summary>\n    Pending,\n\n    /// <summary>\n    /// Registration for the team was withdrawn.\n    /// </summary>\n    Withdrawn,\n\n    /// <summary>\n    /// Registration could not be performed for the team.\n    /// </summary>\n    Rejected,\n\n    /// <summary>\n    /// Registration has been confirmed by the Tournament service.\n    /// </summary>\n    Registered,\n\n    /// <summary>\n    /// The team completed its participation in the tournament.\n    /// </summary>\n    Completed\n};\n\n/// <summary>\n/// Defines values that indicate reasons why the team is under selected tournament registration state.\n/// DEPRECATED. It will be removed in a future release\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerTournamentsServer\"/></memof>\nenum class XblTournamentRegistrationReason : uint32_t\n{\n    /// <summary>\n    /// The reason is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// The registration for this tournament is closed.\n    /// </summary>\n    RegistrationClosed,\n\n    /// <summary>\n    /// One of the team members is already registered for this tournament.\n    /// </summary>\n    MemberAlreadyRegistered,\n\n    /// <summary>\n    /// The tournament has reached its team registration limit.\n    /// </summary>\n    TournamentFull,\n\n    /// <summary>\n    /// The team has been eliminated from the tournament.\n    /// </summary>\n    TeamEliminated,\n\n    /// <summary>\n    /// The tournament is completed.\n    /// </summary>\n    TournamentCompleted\n};\n\n/// <summary>\n/// Defines values that indicate the visibility or accessibility of a session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerActivityDetails\"/></memof>\n/// <memof><see cref=\"XblMultiplayerSessionConstants\"/></memof>\n/// <memof><see cref=\"XblMultiplayerSessionInitArgs\"/></memof>\n/// <memof><see cref=\"XblMultiplayerSessionQuery\"/></memof>\n/// <memof><see cref=\"XblMultiplayerSessionQueryResult\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSearchHandleGetVisibility\"/></argof>\n/// <argof><see cref=\"XblMultiplayerSessionConstantsSetVisibility\"/></argof>\n/// <remarks>\n/// For more information,\n/// see <see href=\"live-game-session-visibility-joinability.md\">Game session visibility and joinability</see>\n/// and the <see href=\"live-mpsd-details.md#visibility-and-joinability\">Visibility and joinability</see> section \n/// of <see href=\"live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks> \nenum class XblMultiplayerSessionVisibility : uint32_t\n{\n    /// <summary>\n    /// The status is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Ignore the session visibility filter.\n    /// </summary>\n    Any,\n\n    /// <summary>\n    /// The session is private and is not visible to players who aren't in the session.  \n    /// Attempting to join causes the service to return HTTP_E_STATUS_FORBIDDEN (403).\n    /// </summary>\n    PrivateSession,\n\n    /// <summary>\n    /// The session is visible to players who aren't in the session, but the session is \n    /// read-only to them and they can't join.  \n    /// Attempting to join causes the service to return HTTP_E_STATUS_BAD_REQUEST (400).\n    /// </summary>\n    Visible,\n\n    /// <summary>\n    /// The session is full and cannot be joined by anyone.  \n    /// Attempting to join causes the service to return HTTP_E_STATUS_BAD_REQUEST (400).\n    /// </summary>\n    Full,\n\n    /// <summary>\n    /// The session is open and can be joined by anyone.\n    /// </summary>\n    Open\n};\n\n/// <summary>\n/// Defines values that indicate the initialization stage of a session during managed initialization.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionInitializationInfo\"/></memof>\n/// <remarks>\n/// For more information about managed initialization, see the \"Managed initialization\" section \n/// of <see href=\"live-matchmaking-target-session.md\">Target session initialization and QoS</see>.\n/// </remarks>\nenum class XblMultiplayerInitializationStage : uint32_t\n{\n    /// <summary>\n    /// Stage not known.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Stage not set.\n    /// </summary>\n    None,\n\n    /// <summary> \n    /// Joining stage. Typically, matchmaking creates a session and adds users to the session.\n    /// The client has until the joining timeout to join the session during this stage.\n    /// </summary>\n    Joining,\n\n    /// <summary>\n    /// Measuring stage. Quality of Service (QoS) measurement happens during this stage.\n    /// If the title is manually managing QoS, the title handles this stage.\n    /// Otherwise, the {% term xbox-live-party %} system handles this stage\n    /// when calling `RegisterGameSession` or `RegisterMatchSession`.\n    /// </summary>\n    Measuring,\n\n    /// <summary>\n    /// Evaluating stage. If `externalEvaluation` is false, this stage is skipped.\n    /// Otherwise, the title does its own evaluation.\n    /// </summary>\n    Evaluating,\n\n    /// <summary>\n    /// Failed stage. If the first initialization episode didn't succeed, the session can't be initialized.\n    /// </summary>\n    Failed\n};\n\n/// <summary>\n/// Defines values that indicate the type of metric used to measure matchmaking Quality of Service (QoS) for a session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerPeerToHostRequirements\"/></memof>\n/// <remarks>\n/// For more information, see <see href=\"live-matchmaking-target-session.md\">Target session initialization and QoS</see>.\n/// </remarks>\nenum class XblMultiplayerMetrics : uint32_t\n{\n    /// <summary>\n    /// Unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Upstream (peer-to-host) bandwidth.\n    /// </summary>\n    BandwidthUp,\n\n    /// <summary>\n    /// Downstream (host-to-peer) bandwidth.\n    /// </summary>\n    BandwidthDown,\n\n    /// <summary>\n    /// Combined bandwidth.\n    /// </summary>\n    Bandwidth,\n\n    /// <summary>\n    /// Upstream (peer-to-host) latency.\n    /// </summary>\n    Latency\n};\n\n/// <summary>\n/// Defines values that indicate the current network address translation (NAT) settings for\n/// a console connecting to {% term xbox-live %}.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionMember\"/></memof>\nenum class XblNetworkAddressTranslationSetting : uint32_t\n{\n    /// <summary>\n    /// The server returned an unrecognized response.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Can connect with any consoles regardless of their NAT settings.\n    /// </summary>\n    Open,\n\n    /// <summary>\n    /// Can connect only with consoles that use Moderate or Open settings.\n    /// </summary>\n    Moderate,\n\n    /// <summary>\n    /// Can connect only with consoles that use Open NAT settings.\n    /// </summary>\n    Strict\n};\n\n/// <summary>\n/// Defines values that indicate why Quality of Service (QoS) measurement failed during session initialization.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionMember\"/></memof>\n/// <argof><see cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/></argof>\n/// <remarks>\n/// For more information, see <see href=\"live-matchmaking-target-session.md\">Target session initialization and QoS</see>.\n/// </remarks>\nenum class XblMultiplayerMeasurementFailure : uint32_t\n{\n    /// <summary>\n    /// Unknown measurement failure.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// No measurement failure.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Measurement timed out.\n    /// </summary>\n    Timeout,\n\n    /// <summary>\n    /// Measurement of latency failed.\n    /// </summary>\n    Latency,\n\n    /// <summary>\n    /// Measurement of upstream (peer-to-host) bandwidth failed.\n    /// </summary>\n    BandwidthUp,\n\n    /// <summary>\n    /// Measurement of downstream (host-to-peer) bandwidth failed.\n    /// </summary>\n    BandwidthDown,\n\n    /// <summary>\n    /// Measurement failed for this player failed because measurement failed for another player in the group.\n    /// </summary>\n    Group,\n\n    /// <summary>\n    /// Measurement failed due to a network error; for example, the player was unreachable.\n    /// </summary>\n    Network,\n\n    /// <summary>\n    /// Measurement failed because the initialization episode failed.\n    /// This likely happened because not enough users were in the session.\n    /// </summary>\n    Episode\n};\n\n/// <summary>\n/// Defines values that indicate the current status of a session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionQueryResult\"/></memof>\n/// <remarks>\n/// For more information, see\n/// the <see href=\"live-mpsd-details.md#session-user-states\">Session user states</see> section \n/// of <see href=\"live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks>\nenum class XblMultiplayerSessionStatus : uint32_t\n{\n    /// <summary>\n    /// The server returned an unrecognized response.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// At least one player is active in the session.\n    /// </summary>\n    Active,\n\n    /// <summary>\n    /// No players are active in the session or all players left the session.\n    /// </summary>\n    Inactive,\n\n    /// <summary>\n    /// One or more players have not accepted the session invite.\n    /// </summary>\n    Reserved\n};\n\n/// <summary>\n/// Defines values that indicate restrictions on the users who can join a session.\n/// </summary>\nenum class XblMultiplayerSessionRestriction : uint32_t\n{\n    /// <summary>\n    /// Unknown restriction type.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// No restrictions.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Only players whose token `DeviceId` values match the `DeviceId` of a player \n    /// who is already in the session and active.\n    /// </summary>\n    Local,\n\n    /// <summary>\n    /// Only local players (as defined for `Local`) and players who are followed by an \n    /// existing (not reserved) member of the session can join without a reservation.\n    /// </summary>\n    Followed\n};\n\n/// <summary>\n/// Defines values that indicate the status of a matchmaking request for a session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerMatchmakingServer\"/></memof>\nenum class XblMatchmakingStatus : uint32_t\n{\n    /// <summary>\n    /// The server returned an unrecognized response.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// The matchmaking search is not specified.  \n    /// This status is optional and requires the `clientMatchmaking` capability.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// The matchmaking search is still searching.\n    /// </summary>\n    Searching,\n\n    /// <summary>\n    /// The matchmaking search has expired.\n    /// </summary>\n    Expired,\n\n    /// <summary>\n    /// The matchmaking search found a session.\n    /// </summary>\n    Found,\n\n    /// <summary>\n    /// The matchmaking search was canceled.\n    /// </summary>\n    Canceled\n};\n\n/// <summary>\n/// Defines values that indicate the status of a member of a session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerManagerMember\"/></memof>\n/// <memof><see cref=\"XblMultiplayerSessionMember\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSessionCurrentUserSetStatus\"/></argof>\nenum class XblMultiplayerSessionMemberStatus : uint32_t\n{\n    /// <summary>\n    /// The member is reserved for a specific Xbox user ID.  \n    /// The specified member must join the session to fill the reservation.  \n    /// If a reserved member doesn't join before the end of `JoinTimeout` (in \n    /// the <see cref=\"XblMultiplayerMemberInitialization\"/> structure), the member is removed from the session.\n    /// </summary>\n    Reserved,\n\n    /// <summary>\n    /// The member is inactive in the current title.  \n    /// The member may be active in another title, as specified by `ActiveTitleId` in \n    /// the <see cref=\"XblMultiplayerSessionMember\"/> structure.  \n    /// If an inactive member doesn't mark themselves as active before the end of `MemberInactiveTimeout` \n    /// (in the <see cref=\"XblMultiplayerSessionConstants\"/> structure), the member is removed from the session.\n    /// </summary>\n    Inactive,\n\n    /// <summary>\n    /// When the shell launches the title to start a multiplayer game, the member is marked as ready.  \n    /// If a ready member doesn't mark themselves as active before the end of `MemberReadyTimeout` (in \n    /// the <see cref=\"XblMultiplayerSessionConstants\"/> structure), the member is marked as inactive.\n    /// </summary>\n    Ready,\n\n    /// <summary>\n    /// The member is active in the current title.\n    /// </summary>\n    Active\n};\n\n/// <summary>\n/// Defines values that indicate the mode used when creating or writing to a multiplayer session.\n/// </summary>\n/// <argof><see cref=\"XblMultiplayerWriteSessionAsync\"/></argof>\n/// <argof><see cref=\"XblMultiplayerWriteSessionByHandleAsync\"/></argof>\nenum class XblMultiplayerSessionWriteMode : uint32_t\n{\n    /// <summary>\n    /// Create a multiplayer session.  \n    /// Fails if the session already exists.\n    /// </summary>\n    CreateNew,\n\n    /// <summary>\n    /// Either update or create a session.  \n    /// Doesn't care whether the session exists.\n    /// </summary>\n    UpdateOrCreateNew,\n\n    /// <summary>\n    /// Updates an existing multiplayer session.  \n    /// Fails if the session doesn't exist.\n    /// </summary>\n    UpdateExisting,\n\n    /// <summary>\n    /// Updates an existing multiplayer session.  \n    /// Fails with HTTP_E_STATUS_PRECOND_FAILED (HTTP status 412) if the ETag on the local session doesn't match the ETag on the server.  \n    /// Fails if the session does not exist.\n    /// </summary>\n    SynchronizedUpdate,\n};\n\n/// <summary>\n/// Defines values that indicate the write status of a multiplayer session.\n/// </summary>\nenum class XblWriteSessionStatus : uint32_t\n{\n    /// <summary>\n    /// Unknown write result.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// User does not have permission to write to the session (HTTP status 403).\n    /// </summary>\n    AccessDenied,\n\n    /// <summary>\n    /// The write operation created the session (HTTP status 201).\n    /// </summary>\n    Created,\n\n    /// <summary>\n    /// A conflict occurred during the write operation (HTTP status 409).\n    /// </summary>\n    Conflict,\n\n    /// <summary>\n    /// The session was not found (HTTP status 404).\n    /// </summary>\n    HandleNotFound,\n\n    /// <summary>\n    /// The session was updated by another user (HTTP status 412).\n    /// </summary>\n    OutOfSync,\n\n    /// <summary>\n    /// The session was deleted successfully (HTTP status 204).\n    /// </summary>\n    SessionDeleted,\n\n    /// <summary>\n    /// The session was updated successfully (HTTP status 200).\n    /// </summary>\n    Updated\n};\n\n/// <summary>\n/// Defines values that indicate change types for a multiplayer session.\n/// </summary>\n/// <argof><see cref=\"XblMultiplayerSessionSetSessionChangeSubscription\"/></argof>\nenum class XblMultiplayerSessionChangeTypes : uint32_t\n{\n    /// <summary>\n    /// None.\n    /// </summary>\n    None = 0x0000,\n\n    /// <summary>\n    /// Changes to anything in the session.\n    /// </summary>\n    Everything = 0x0001,\n\n    /// <summary>\n    /// Changes to the host device token.\n    /// </summary>\n    HostDeviceTokenChange = 0x0002,\n\n    /// <summary>\n    /// Changes to the stage of initialization.\n    /// </summary>\n    InitializationStateChange = 0x0004,\n\n    /// <summary>\n    /// Changes to the matchmaking status, such as match found or match expired.\n    /// </summary>\n    MatchmakingStatusChange = 0x0008,\n\n    /// <summary>\n    /// A member joined the session.\n    /// </summary>\n    MemberListChange = 0x0010,\n\n    /// <summary>\n    /// A member left the session.\n    /// </summary>\n    MemberStatusChange = 0x0020,\n\n    /// <summary>\n    /// Changes to the joinability (<see cref=\"XblMultiplayerJoinability\"/>) of the session.\n    /// </summary>\n    SessionJoinabilityChange = 0x0040,\n\n    /// <summary>\n    /// Changes in the custom properties of the session.\n    /// </summary>\n    CustomPropertyChange = 0x0080,\n\n    /// <summary>\n    /// Changes in the custom properties of any of the members.\n    /// </summary>\n    MemberCustomPropertyChange = 0x0100,\n\n    /// <summary>\n    /// Changes in tournament server properties, such as next game, last game, or registration.\n    /// DEPRECATED. This value will be removed in a future release.\n    /// </summary>\n    TournamentPropertyChange = 0x0200,\n\n    /// <summary>\n    /// Changes in arbitration server properties, such as game results.\n    /// DEPRECATED. This value will be removed in a future release.\n    /// </summary>\n    ArbitrationPropertyChange = 0x0400\n};\n\nDEFINE_ENUM_FLAG_OPERATORS(XblMultiplayerSessionChangeTypes);\n\n/// <summary>\n/// Defines values that indicate which multiplayer role settings are mutable.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerRoleType\"/></memof>\n/// <remarks>\n/// Only the session owner can modify role settings and only those that are set \n/// in `XblMultiplayerRoleType::MutableRoleSettings`.  \n/// You can set `XblMutableRoleSettings` in the session template.\n/// </remarks>\nenum class XblMutableRoleSettings : uint32_t\n{\n    /// <summary>\n    /// None of the role settings are mutable.\n    /// </summary>\n    None = 0x0,\n\n    /// <summary>\n    /// Allows you to set the maximum number of players that can fill the role.\n    /// </summary>\n    Max = 0x1,\n\n    /// <summary>\n    /// Allows you to set the target number of players that should fill the role.\n    /// </summary>\n    Target = 0x2\n};\n\nDEFINE_ENUM_FLAG_OPERATORS(XblMutableRoleSettings);\n\n#define XBL_TOURNAMENT_REFERENCE_DEFINITION_NAME_MAX_LENGTH     100\n#define XBL_TOURNAMENT_REFERENCE_ORGANIZER_LENGTH               100\n\n/// <summary>\n/// Represents a reference to a tournament reference.\n/// DEPRECATED. This structure will be removed in a future release.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerTournamentsServer\"/></memof>\ntypedef struct XBL_DEPRECATED XblTournamentReference \n{\n    /// <summary>\n    /// The definition name of the tournament.\n    /// </summary>\n    _Null_terminated_ char DefinitionName[XBL_TOURNAMENT_REFERENCE_DEFINITION_NAME_MAX_LENGTH];\n\n    /// <summary>\n    /// The tournament ID specific to the tournament.\n    /// </summary>\n    _Null_terminated_ char TournamentId[XBL_GUID_LENGTH];\n\n    /// <summary>\n    /// The name of the tournament organizer.\n    /// </summary>\n    _Null_terminated_ char Organizer[XBL_TOURNAMENT_REFERENCE_ORGANIZER_LENGTH];\n\n    /// <summary>\n    /// The service configuration ID specific to the tournament.\n    /// </summary>\n    _Null_terminated_ char Scid[XBL_SCID_LENGTH];\n} XblTournamentReference;\n\n\n/// <summary>\n/// Represents the result of a multiplayer game.\n/// DEPRECATED. This structure will be removed in a future release.\n/// </summary>\ntypedef struct XBL_DEPRECATED XblTournamentGameResultWithRank\n{\n    /// <summary>\n    /// The result for the team.\n    /// </summary>\n    XblTournamentGameResult Result;\n\n    /// <summary>\n    /// The ranking of the result. Applies only when `Result` is `XblTournamentGameResult::Rank`.\n    /// </summary>\n    uint64_t Ranking;\n} XblTournamentGameResultWithRank;\n\n/// <summary>\n/// Represents a team result for a multiplayer game.\n/// DEPRECATED. This structure will be removed in a future release.\n/// </summary>\ntypedef struct XBL_DEPRECATED XblTournamentTeamResult\n{\n    /// <summary>\n    /// Name of the team.\n    /// </summary>\n    const char* Team;\n\n    XBL_WARNING_PUSH\n    XBL_WARNING_DISABLE_DEPRECATED\n    /// <summary>\n    /// The game result.\n    /// </summary>\n    XblTournamentGameResultWithRank GameResult;\n    XBL_WARNING_POP\n\n} XblTournamentTeamResult;\n\n/// <summary>\n/// Represents requirements for each connection between a host candidate and session members.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionConstants\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSessionConstantsSetPeerToHostRequirements\"/></argof>\n/// <remarks>\n/// For more information, see <see href=\"live-matchmaking-target-session.md\">Target session initialization and QoS</see>.\n/// </remarks>\ntypedef struct XblMultiplayerPeerToHostRequirements\n{\n    /// <summary>\n    /// The maximum latency, in milliseconds, of the upstream (peer-to-host) connection.\n    /// </summary>\n    uint64_t LatencyMaximum;\n\n    /// <summary>\n    /// The minimum bandwidth, in kilobits per second, of the downstream (host-to-peer) connection.\n    /// </summary>\n    uint64_t BandwidthDownMinimumInKbps;\n\n    /// <summary>\n    /// The minimum bandwidth, in kilobits per second, of the upstream (peer-to-host) connection.\n    /// </summary>\n    uint64_t BandwidthUpMinimumInKbps;\n\n    /// <summary>\n    /// The metric used to select the host.\n    /// </summary>\n    XblMultiplayerMetrics HostSelectionMetric;\n} XblMultiplayerPeerToHostRequirements;\n\n/// <summary>\n/// Represents requirements for a connection between session members.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionConstants\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSessionConstantsSetPeerToPeerRequirements\"/></argof>\ntypedef struct XblMultiplayerPeerToPeerRequirements\n{\n    /// <summary>\n    /// The maximum latency, in milliseconds, for the peer-to-peer connection.\n    /// </summary>\n    uint64_t LatencyMaximum;\n\n    /// <summary>\n    /// The minimum bandwidth, in kilobits per second, for the peer-to-peer connection.\n    /// </summary>\n    uint64_t BandwidthMinimumInKbps;\n} XblMultiplayerPeerToPeerRequirements;\n\n/// <summary>\n/// Represents requirements for a new Multiplayer service session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionConstants\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSessionConstantsSetMemberInitialization\"/></argof>\ntypedef struct XblMultiplayerMemberInitialization\n{\n    /// <summary>\n    /// Maximum time, in milliseconds, for the joining stage of the Quality of Service (QoS) process.\n    /// </summary>\n    uint64_t JoinTimeout;\n\n    /// <summary>\n    /// Maximum time, in milliseconds, for the measurement stage of the QoS process.\n    /// </summary>\n    uint64_t MeasurementTimeout;\n\n    /// <summary>\n    /// Maximum time, in milliseconds, for the evaluation stage of the QoS process.\n    /// </summary>\n    uint64_t EvaluationTimeout;\n\n    /// <summary>\n    /// When set to true, indicates that the title performs the evaluation stage.\n    /// </summary>\n    bool ExternalEvaluation;\n\n    /// <summary>\n    /// Minimum number of members for the session. Defaults to 2. Must be between 1 and `maxMemberCount`.  \n    /// Applies only to the joining stage.\n    /// </summary>\n    uint32_t MembersNeededToStart;\n} XblMultiplayerMemberInitialization;\n\n/// <summary>\n/// Represents the capabilities of a Multiplayer service session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerSessionConstants\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSessionConstantsSetCapabilities\"/></argof>\n/// <remarks>\n/// Session capabilities are optional Boolean values that are set in the session template.  \n/// If no capabilities are needed, an empty `SessionCapabilities` object should be in the template \n/// to prevent capabilities from being specified at session creation, unless the title \n/// requires dynamic session capabilities.<br/><br/>\n/// For more information, see the <see href=\"live-mpsd-details.md#session-capabilities\">Session capabilities</see> \n/// section of <see href=\"live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks>\ntypedef struct XblMultiplayerSessionCapabilities\n{\n    /// <summary>\n    /// Indicates whether a session can enable metrics and session members can set `secureDeviceAddress`.\n    /// If false, the session can't enable any metrics, and session members can't set `secureDeviceAddress`.\n    /// </summary>\n    bool Connectivity;\n\n    /// <summary>\n    /// If true, team capability is set on the session for a tournament.\n    /// DEPRECATED. This member will be removed in a future release.\n    /// </summary>\n    XBL_DEPRECATED bool Team;\n\n    /// <summary>\n    /// If true, arbitration capability is set on the session for a tournament.\n    /// DEPRECATED. This member will be removed in a future release.\n    /// </summary>\n    XBL_DEPRECATED bool Arbitration;\n\n    /// <summary>\n    /// If false (the default value), active users are required to remain online playing the title.\n    /// If they don't, they are demoted to inactive status.  \n    /// Set this flag to true to enable session members to stay active indefinitely.\n    /// </summary>\n    bool SuppressPresenceActivityCheck;\n\n    /// <summary>\n    /// Indicates whether the session represents actual gameplay rather than time in setup or \n    /// a menu, such a lobby or during matchmaking.  \n    /// If true, the session is in gameplay mode.\n    /// </summary>\n    bool Gameplay;\n\n    /// <summary>\n    /// If true, the session can host 101 to 1000 users, which affects other session features.\n    /// If false, the session can host 1 to 100 users. For more information, see \n    /// the <see href=\"live-mpsd-details.md#session-size\">Session size</see> section \n    /// of <see href=\"live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n    /// </summary>\n    bool Large;\n\n    /// <summary>\n    /// If true, a connection is required for a member to be marked as active. To enable session notifications \n    /// and detect disconnections, this member must be set to true. For more information, see \n    /// the <see href=\"live-mpsd-how-tos.md#sfmscn\">Subscribe for MPSD session change notifications</see> section \n    /// of <see href=\"live-mpsd-how-tos.md\">Multiplayer tasks</see>.\n    /// </summary>\n    bool ConnectionRequiredForActiveMembers;\n\n    /// <summary>\n    /// If true, the session supports calls from platforms without strong title identity.  \n    /// This capability can't be set on large sessions.\n    /// </summary>\n    bool UserAuthorizationStyle;\n\n    /// <summary>\n    /// If true, the session supports crossplay between {% term platform_windows %} PC and Xbox.\n    /// </summary>\n    bool Crossplay;\n\n    /// <summary>\n    /// If true, the session can be linked to a search handle for searching.\n    /// </summary>\n    bool Searchable;\n\n    /// <summary>\n    /// If true, the session has owners. For a session to be searchable when `UserAuthorizationStyle` is \n    /// true, the session must have owners.\n    /// </summary>\n    bool HasOwners;\n} XblMultiplayerSessionCapabilities;\n\n/// <summary>\n/// Represents constants for a multiplayer session.\n/// </summary>\n/// <remarks>\n/// Session constants are set by the creator or by the session template only when a session is created.\n/// </remarks>\ntypedef struct XblMultiplayerSessionConstants\n{\n    /// <summary>\n    /// The maximum number of members in the session.\n    /// </summary>\n    uint32_t MaxMembersInSession;\n\n    /// <summary>\n    /// The visibility of the session.\n    /// </summary>\n    XblMultiplayerSessionVisibility Visibility;\n\n    /// <summary>\n    /// A collection of Xbox user IDs indicating who initiated the session. (Optional)\n    /// </summary>\n    uint64_t* InitiatorXuids;\n\n    /// <summary>\n    /// The number of entries in the `InitiatorXuids` array.\n    /// </summary>\n    size_t InitiatorXuidsCount;\n\n    /// <summary>\n    /// Any custom constants for the session, specified in a JSON string.  \n    /// These constants can't be changed after the session is created. (Optional)\n    /// </summary>\n    const char* CustomJson;\n\n    /// <summary>\n    /// The Cloud Compute package constants for the session, specified in a JSON string.  \n    /// These constants can't be changed after the session is created. (Optional)\n    /// </summary>\n    const char* SessionCloudComputePackageConstantsJson;\n\n    /// <summary>\n    /// Maximum time, in milliseconds, for a member with a reservation to join the session. \n    /// If the member doesn't join within this time, the reservation is removed.\n    /// </summary>\n    uint64_t MemberReservedTimeout;\n\n    /// <summary>\n    /// Maximum time, in milliseconds, for an inactive member to become active. \n    /// If an inactive member doesn't become active within this time, the member is removed from the session.\n    /// </summary>\n    uint64_t MemberInactiveTimeout;\n\n    /// <summary>\n    /// Maximum time, in milliseconds, for a member who is marked as ready to become active. \n    /// When the shell launches the title to start a multiplayer game, the member is marked as ready.\n    /// If a member who is marked as ready doesn't become active within this time, the member becomes inactive.  \n    /// </summary>\n    uint64_t MemberReadyTimeout;\n\n    /// <summary>\n    /// Maximum time, in milliseconds, that the session can remain empty. \n    /// If no members join the session within this time, the session is deleted.\n    /// </summary>\n    uint64_t SessionEmptyTimeout;\n\n    /// <summary>\n    /// Delta, in milliseconds, from start time that represents the time at which results are finalized.  \n    /// If no one (client or server) has reported at this time, we declare the match results incomplete.\n    /// DEPRECATED. This member will be removed in a future release.\n    /// </summary>\n    XBL_DEPRECATED uint64_t ArbitrationTimeout;\n\n    /// <summary>\n    /// Delta, in milliseconds, from start time that represents the time at which, if the session has \n    /// no active users, the match is canceled.\n    /// DEPRECATED. This member will be removed in a future release.\n    /// </summary>\n    XBL_DEPRECATED uint64_t ForfeitTimeout;\n\n    /// <summary>\n    /// If true, indicates that the title wants latency measured to help determine connectivity.  \n    /// Requires `capabilities.connectivity` to be true.\n    /// </summary>\n    bool EnableMetricsLatency;\n\n    /// <summary>\n    /// If true, indicates that the title wants downstream (host-to-peer) bandwidth measured to help \n    /// determine connectivity. Requires `capabilities.connectivity` to be true.\n    /// </summary>\n    bool EnableMetricsBandwidthDown;\n\n    /// <summary>\n    /// If true, indicates that the title wants upstream (peer-to-host) bandwidth measured to help \n    /// determine connectivity. Requires `capabilities.connectivity` to be true.\n    /// </summary>\n    bool EnableMetricsBandwidthUp;\n\n    /// <summary>\n    /// If true, indicates that the title wants a custom measurement to help determine connectivity.  \n    /// Requires `capabilities.connectivity` to be true.\n    /// </summary>\n    bool EnableMetricsCustom;\n\n    /// <summary>\n    /// If set, the session expects the client system or title to perform initialization after session creation.  \n    /// Timeouts and initialization stages are automatically tracked by the session, including \n    /// initial Quality of Service (QoS) measurements if any metrics are set.\n    /// </summary>\n    XblMultiplayerMemberInitialization* MemberInitialization;\n\n    /// <summary>\n    /// QoS requirements for a connection between session members.\n    /// </summary>\n    XblMultiplayerPeerToPeerRequirements PeerToPeerRequirements;\n\n    /// <summary>\n    /// QoS requirements for a connection between a host candidate and session members.\n    /// </summary>\n    XblMultiplayerPeerToHostRequirements PeerToHostRequirements;\n\n    /// <summary>\n    /// The set of potential server connection strings that should be evaluated.\n    /// </summary>\n    const char* MeasurementServerAddressesJson;\n\n    /// <summary>\n    /// Indicates whether the matchmaking status fields can be written to.\n    /// </summary>\n    bool ClientMatchmakingCapable;\n\n    /// <summary>\n    /// The capabilities of the session.\n    /// </summary>\n    XblMultiplayerSessionCapabilities SessionCapabilities;\n} XblMultiplayerSessionConstants;\n\n#define XBL_MULTIPLAYER_DEVICE_TOKEN_MAX_LENGTH             40 \n#define XBL_MULTIPLAYER_SESSION_TEMPLATE_NAME_MAX_LENGTH    100\n#define XBL_MULTIPLAYER_SESSION_NAME_MAX_LENGTH             XBL_MULTIPLAYER_SESSION_TEMPLATE_NAME_MAX_LENGTH\n\n/// <summary>\n/// Represents a handle ID of a multiplayer session.\n/// </summary>\n/// <argof><see cref=\"XblMultiplayerSetTransferHandleResult\"/></argof>\n/// <remarks>\n/// Multiplayer Session Directory (MPSD) can create various handles that refer to a session.  \n/// They are immutable and can only be created, read, and deleted.\n/// Note that this handle ID references to a service side object.\n/// </remarks>\ntypedef struct XblMultiplayerSessionHandleId\n{\n    /// <summary>\n    /// The ID of the handle that MSPD created.\n    /// </summary>\n    _Null_terminated_ char value[XBL_GUID_LENGTH];\n} XblMultiplayerSessionHandleId;\n\n/// <summary>\n/// Represents a reference to a multiplayer session.\n/// </summary>\ntypedef struct XblMultiplayerSessionReference\n{\n    /// <summary>\n    /// The service configuration ID (SCID) specific to the title.\n    /// </summary>\n    _Null_terminated_ char Scid[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// The name of the template for the session.\n    /// </summary>\n    _Null_terminated_ char SessionTemplateName[XBL_MULTIPLAYER_SESSION_TEMPLATE_NAME_MAX_LENGTH];\n\n    /// <summary>\n    /// The name of the session.\n    /// </summary>\n    _Null_terminated_ char SessionName[XBL_MULTIPLAYER_SESSION_NAME_MAX_LENGTH];\n} XblMultiplayerSessionReference;\n\n#define XBL_MULTIPLAYER_SESSION_REFERENCE_URI_MAX_LENGTH  (44 + XBL_SCID_LENGTH + XBL_MULTIPLAYER_SESSION_TEMPLATE_NAME_MAX_LENGTH + XBL_MULTIPLAYER_SESSION_NAME_MAX_LENGTH)\n\n/// <summary>\n/// Represents a URI path representation of a session reference.  \n/// </summary>\n/// <remarks>\n/// The format of the URI path \n/// is `/serviceconfigs/{scid}/sessiontemplates/{session-template-name}/sessions/{session-name}`, where \n/// `{scid}` is the service configuration ID specific to the title.\n/// </remarks>\n/// <argof><see cref=\"XblMultiplayerSessionReferenceToUriPath\"/></argof>\ntypedef struct XblMultiplayerSessionReferenceUri\n{\n    /// <summary>\n    /// The URI path.\n    /// </summary>\n    _Null_terminated_ char value[XBL_MULTIPLAYER_SESSION_REFERENCE_URI_MAX_LENGTH];\n} XblMultiplayerSessionReferenceUri;\n\n/// <summary>\n/// Creates an <see cref=\"XblMultiplayerSessionReference\"/> object from a service configuration ID (SCID), session \n/// template name, and session name.\n/// </summary>\n/// <param name=\"scid\">The SCID that the session is a part of. The SCID is case-sensitive, so paste it directly \n/// from Partner Center.</param>\n/// <param name=\"sessionTemplateName\">The name of the session template.</param>\n/// <param name=\"sessionName\">The name of the session.</param>\n/// <returns>A reference to the multiplayer session.</returns>\nSTDAPI_(XblMultiplayerSessionReference) XblMultiplayerSessionReferenceCreate(\n    _In_z_ const char* scid,\n    _In_z_ const char* sessionTemplateName,\n    _In_z_ const char* sessionName\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Returns the session reference parsed from a URI.\n/// </summary>\n/// <param name=\"path\">The URI path.</param>\n/// <param name=\"sessionReference\">Passes back the session reference.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionReferenceParseFromUriPath(\n    _In_ const char* path,\n    _Out_ XblMultiplayerSessionReference* sessionReference\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Returns the URI path representation of a session reference.\n/// </summary>\n/// <param name=\"sessionReference\">A session reference.</param>\n/// <param name=\"sessionReferenceUri\">Passes back the URI representation of the session reference.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionReferenceToUriPath(\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _Out_ XblMultiplayerSessionReferenceUri* sessionReferenceUri\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Verifies whether an <see cref=\"XblMultiplayerSessionReference\"/> object is well formed.\n/// </summary>\n/// <param name=\"sessionReference\">The session reference.</param>\n/// <returns>Returns true if session is well formed, false if session is not well formed.</returns>\n/// <remarks>\n/// An <see cref=\"XblMultiplayerSessionReference\"/> object is considered to be well formed if none \n/// of the fields are empty strings.\n/// </remarks>\nSTDAPI_(bool) XblMultiplayerSessionReferenceIsValid(\n    _In_ const XblMultiplayerSessionReference* sessionReference\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Represents the matchmaking server that supports a multiplayer session.\n/// </summary>\ntypedef struct XblMultiplayerMatchmakingServer\n{\n    /// <summary>\n    /// The status of the matchmaking server.\n    /// </summary>\n    XblMatchmakingStatus Status;\n\n    /// <summary>\n    /// The status details, if any, of the matchmaking server.\n    /// </summary>\n    const char* StatusDetails;\n\n    /// <summary>\n    /// The typical wait time, in seconds.\n    /// </summary>\n    uint32_t TypicalWaitInSeconds;\n\n    /// <summary>\n    /// A reference to the target session.\n    /// </summary>\n    XblMultiplayerSessionReference TargetSessionRef;\n} XblMultiplayerMatchmakingServer;\n\n/// <summary>\n/// Represents the arbitration server that supports a multiplayer session.\n/// DEPRECATED. This structure will be removed in a future release.\n/// </summary>\ntypedef struct XBL_DEPRECATED XblMultiplayerArbitrationServer\n{\n    /// <summary>\n    /// The start time of the match. This time is also when arbitration starts.\n    /// </summary>\n    time_t ArbitrationStartTime;\n\n    /// <summary>\n    /// The state of the result.\n    /// </summary>\n    XblTournamentArbitrationState ResultState;\n\n    /// <summary>\n    /// The source of the result.\n    /// </summary>\n    XblTournamentGameResultSource ResultSource;\n\n    /// <summary>\n    /// A value from 0 through 100 that indicates the confidence level of the result.\n    /// </summary>\n    uint32_t ResultConfidenceLevel;\n\n    XBL_WARNING_PUSH\n    XBL_WARNING_DISABLE_DEPRECATED\n    /// <summary>\n    /// The results of the game.\n    /// </summary>\n    XblTournamentTeamResult* Results;\n    XBL_WARNING_POP\n\n    /// <summary>\n    /// The number of results.\n    /// </summary>\n    size_t ResultsCount;\n} XblMultiplayerArbitrationServer;\n\n/// <summary>\n/// Represents a team in a tournament.\n/// DEPRECATED. This structure will be removed in a future release.\n/// </summary>\ntypedef struct XBL_DEPRECATED XblMultiplayerTournamentTeam\n{\n    /// <summary>\n    /// ID of the team.\n    /// </summary>\n    const char* TeamId;\n\n    /// <summary>\n    /// Session reference of the session the team is in.\n    /// </summary>\n    XblMultiplayerSessionReference TeamSessionReference;\n} XblMultiplayerTournamentTeam;\n\n/// <summary>\n/// Represents the tournament server that supports a multiplayer session.\n/// DEPRECATED. This structure will be removed in a future release.\n/// </summary>\ntypedef struct XBL_DEPRECATED XblMultiplayerTournamentsServer \n{\n    XBL_WARNING_PUSH\n    XBL_WARNING_DISABLE_DEPRECATED\n    /// <summary>\n    /// The tournament reference.\n    /// </summary>\n    XblTournamentReference TournamentReference;\n    XBL_WARNING_POP\n\n    XBL_WARNING_PUSH\n    XBL_WARNING_DISABLE_DEPRECATED\n    /// <summary>\n    /// The teams in the tournament.\n    /// </summary>\n    XblMultiplayerTournamentTeam* Teams;\n    XBL_WARNING_POP\n\n    /// <summary>\n    /// The number of teams in the tournament.\n    /// </summary>\n    size_t TeamsCount;\n\n    /// <summary>\n    /// The registration state of the team.\n    /// </summary>\n    XblTournamentRegistrationState RegistrationState;\n\n    /// <summary>\n    /// The reason for the registration state.\n    /// </summary>\n    XblTournamentRegistrationReason RegistrationReason;\n\n    /// <summary>\n    /// The start time of the next game in the tournament.\n    /// </summary>\n    time_t NextGameStartTime;\n\n    /// <summary>\n    /// The session reference of the next game in the tournament.\n    /// </summary>\n    XblMultiplayerSessionReference NextGameSessionReference;\n\n    /// <summary>\n    /// The end time of the last game in the tournament.\n    /// </summary>\n    time_t LastGameEndTime;\n\n    XBL_WARNING_PUSH\n    XBL_WARNING_DISABLE_DEPRECATED\n    /// <summary>\n    /// The result of the last game in the tournament.\n    /// </summary>\n    XblTournamentTeamResult LastTeamResult;\n    XBL_WARNING_POP\n\n    /// <summary>\n    /// The source of the result of the last game in the tournament.\n    /// </summary>\n    XblTournamentGameResultSource LastGameResultSource;\n} XblMultiplayerTournamentsServer;\n\n/// <summary>\n/// Represents a category of roles for a multiplayer session.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerRole\"/></memof>\n/// <argof><see cref=\"XblMultiplayerSessionRoleTypes\"/></argof>\n/// <remarks>\n/// For more information, see <see href=\"live-multiplayer-roles.md\">Multiplayer roles</see>.\n/// </remarks>\ntypedef struct XblMultiplayerRoleType\n{\n    /// <summary>\n    /// Name of the role type.\n    /// </summary>\n    const char* Name;\n\n    /// <summary>\n    /// If true, only the owner of the session can assign this role to members.\n    /// </summary>\n    bool OwnerManaged;\n\n    /// <summary>\n    /// The settings (for roles in this role type) that can be modified throughout the life of the session.  \n    /// Exclude role settings to lock them.\n    /// </summary>\n    XblMutableRoleSettings MutableRoleSettings;\n\n    /// <summary>\n    /// A collection of roles for this role type.\n    /// </summary>\n    struct XblMultiplayerRole* Roles;\n\n    /// <summary>\n    /// The number of roles in the `Roles` array.\n    /// </summary>\n    size_t RoleCount;\n} XblMultiplayerRoleType;\n\n/// <summary>\n/// Represents role info for a multiplayer role.\n/// </summary>\ntypedef struct XblMultiplayerRole\n{\n    /// <summary>\n    /// The role type that this role belongs too.\n    /// </summary>\n    XblMultiplayerRoleType* RoleType;\n\n    /// <summary>\n    /// Name of the role.  \n    /// Unique with a role type.\n    /// </summary>\n    const char* Name;\n\n    /// <summary>\n    /// Member xbox_user_ids currently assigned for this role.\n    /// </summary>\n    uint64_t* MemberXuids;\n\n    /// <summary>\n    /// Number of slots occupied for this role.\n    /// </summary>\n    uint32_t MemberCount;\n\n    /// <summary>\n    /// Number of target slots assigned for this role.\n    /// </summary>\n    uint32_t TargetCount;\n\n    /// <summary>\n    /// Maximum number of slots available for this role.\n    /// </summary>\n    uint32_t MaxMemberCount;\n} XblMultiplayerRole;\n\n/// <summary>\n/// Represents a session member's role in the session.\n/// </summary>\ntypedef struct XblMultiplayerSessionMemberRole\n{\n    /// <summary>\n    /// Role type this role belongs to.\n    /// </summary>\n    const char* roleTypeName;\n\n    /// <summary>\n    /// Name of the role.\n    /// </summary>\n    const char* roleName;\n} XblMultiplayerSessionMemberRole;\n\n/// <summary>\n/// Represents a users current multiplayer activity, along with some details about the corresponding session.\n/// </summary>\ntypedef struct XblMultiplayerActivityDetails\n{\n    /// <summary>\n    /// Session reference containing identifying information for the session.\n    /// </summary>\n    XblMultiplayerSessionReference SessionReference;\n\n    /// <summary>\n    /// HandleId corresponding to this activity.\n    /// </summary>\n    char HandleId[XBL_GUID_LENGTH];\n\n    /// <summary>\n    /// TitleId that should be launched in order to join this activity.\n    /// </summary>\n    uint32_t TitleId;\n\n    /// <summary>\n    /// The visibility state of the session. Whether other users can see, or join, etc.\n    /// </summary>\n    XblMultiplayerSessionVisibility Visibility;\n\n    /// <summary>\n    /// The join restriction of the session, which applies if visibility is \"open\".\n    /// </summary>\n    XblMultiplayerSessionRestriction JoinRestriction;\n\n    /// <summary>\n    /// Indicates whether the session is temporarily closed for joining.\n    /// </summary>\n    bool Closed;\n\n    /// <summary>\n    /// Xbox User ID of the member whose activity this is.\n    /// </summary>\n    uint64_t OwnerXuid;\n\n    /// <summary>\n    /// Number of total slots.\n    /// </summary>\n    uint32_t MaxMembersCount;\n\n    /// <summary>\n    /// Number of slots occupied.\n    /// </summary>\n    uint32_t MembersCount;\n\n    /// <summary>\n    /// String containing custom session properties JSON blob.\n    /// </summary>\n    const char* CustomSessionPropertiesJson;\n} XblMultiplayerActivityDetails;\n\n/// <summary>\n/// Token that represents a unique device participating in the session.  \n/// It's a case-insensitive string that can be used for equality comparisons.\n/// </summary>\ntypedef struct XblDeviceToken\n{\n    /// <summary>\n    /// The unique device.\n    /// </summary>\n    _Null_terminated_ char Value[XBL_MULTIPLAYER_DEVICE_TOKEN_MAX_LENGTH];\n} XblDeviceToken;\n\n/// <summary>\n/// Represents a read only reference to member in a multiplayer session.\n/// </summary>\ntypedef struct XblMultiplayerSessionMember\n{\n    /// <summary>\n    /// Id for this member.  \n    /// Unique within the context of the session which this member is part of.\n    /// </summary>\n    uint32_t MemberId;\n\n    /// <summary>\n    /// Id of this members' team in a tournament.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    XBL_DEPRECATED const char* TeamId;\n\n    /// <summary>\n    /// Initial team assignment from SmartMatch.\n    /// </summary>\n    const char* InitialTeam;\n\n    /// <summary>\n    /// Arbitration Status of a member in a tournament.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    XBL_DEPRECATED XblTournamentArbitrationStatus ArbitrationStatus;\n\n    /// <summary>\n    /// Xbox User ID of the member.  \n    /// Only known if the member has accepted.\n    /// </summary>\n    uint64_t Xuid;\n\n    /// <summary>\n    /// JSON string that specify the custom constants for the member.\n    /// </summary>\n    const char* CustomConstantsJson;\n\n    /// <summary>\n    /// The base64 encoded secure device address of the member. (Optional)\n    /// </summary>\n    const char* SecureDeviceBaseAddress64;\n\n    /// <summary>\n    /// An array of roles for this member. (Optional)\n    /// </summary>\n    const XblMultiplayerSessionMemberRole* Roles;\n\n    /// <summary>\n    /// Number of entries in the Roles array.\n    /// </summary>\n    size_t RolesCount;\n\n    /// <summary>\n    /// JSON string that specify the custom properties for the member.\n    /// </summary>\n    const char* CustomPropertiesJson;\n\n    /// <summary>\n    /// The Gamertag of the member. (Optional)  \n    /// Only known if the member has accepted.\n    /// </summary>\n    char Gamertag[XBL_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The status of this member.\n    /// </summary>\n    XblMultiplayerSessionMemberStatus Status;\n\n    /// <summary>\n    /// Only true if this member is ready for turn.\n    /// </summary>\n    bool IsTurnAvailable;\n\n    /// <summary>\n    /// Indicates if this MultiplayerSessionMember is for the current user.\n    /// </summary>\n    bool IsCurrentUser;\n\n    /// <summary>\n    /// Indicates to run QoS initialization for this user.  \n    /// Defaults to false.  \n    /// Ignored if there is not a \"memberInitialization\" section for the session.\n    /// </summary>\n    bool InitializeRequested;\n\n    /// <summary>\n    /// When match adds a user to a session, it can provide some context around how and why they were matched into the session.  \n    /// This is a copy of the user's serverMeasurements from the matchmaking session.\n    /// </summary>\n    const char* MatchmakingResultServerMeasurementsJson;\n\n    /// <summary>\n    /// QoS measurements by game-server connection string.  \n    /// Like all fields, \"serverMeasurements\" must be updated as a whole, so it should be set once when measurement is complete.  \n    /// If empty, it means that none of the measurements completed within the \"serverMeasurementTimeout\".\n    /// </summary>\n    const char* ServerMeasurementsJson;\n\n    /// <summary>\n    /// A collection of memberIds in my group.  \n    /// If a \"initializationGroup\" list is set, the member's own index will always be added if it isn't already present.  \n    /// During managed initialization, if any members in the list fail, this member will also fail.\n    /// </summary>\n    const uint32_t* MembersInGroupIds;\n\n    /// <summary>\n    /// The number of entries in the MembersInGroupIds array.\n    /// </summary>\n    size_t MembersInGroupCount;\n\n    /// <summary>\n    /// QoS measurements by secure device address.  \n    /// Like all fields, \"measurements\" must be updated as a whole.  \n    /// It should be set once when measurement is complete, not incrementally.  \n    /// If a \"measurements\" object is set, it can't contain an entry for the member's own address.\n    /// </summary>\n    const char* QosMeasurementsJson;\n\n    /// <summary>\n    /// This is set when the member uploads a secure device address.  \n    /// It's a case-insensitive string that can be used for equality comparisons.\n    /// </summary>\n    XblDeviceToken DeviceToken;\n\n    /// <summary>\n    /// This is the device's NAT setting when the member uploads a secure device address.\n    /// </summary>\n    XblNetworkAddressTranslationSetting Nat;\n\n    /// <summary>\n    /// If the member is active, this is the title ID in which they are active.\n    /// </summary>\n    uint32_t ActiveTitleId;\n\n    /// <summary>\n    /// This value is only useful to read when the title is manually managing their own QoS.  \n    /// If the \"memberInitialization\" section is set and the member was added with \"initialize\":true, \n    /// this is set to the initialization episode that the member will participate in otherwise it is 0.  \n    /// Users join sessions in batches.  \n    /// The initialization episode number indicates a set of users that QoS needs to be performed against.  \n    /// Initialization episode 1 is a special value used for the members added to a new session at create time.\n    /// </summary>\n    uint32_t InitializationEpisode;\n\n    /// <summary>\n    /// The time the user joined the session.  \n    /// If \"reserved\" is true, this is the time the reservation was made.\n    /// </summary>\n    time_t JoinTime;\n\n    /// <summary>\n    /// The cause of why the initialization failed, or XblMultiplayerMeasurementFailure::None if there was no failure.  \n    /// Set when transitioning out of the \"joining\" or \"measuring\" stage if this member doesn't pass.\n    /// </summary>\n    XblMultiplayerMeasurementFailure InitializationFailureCause;\n\n    /// <summary>\n    /// An array of group names for the current user indicating which groups that user was part of during a multiplayer session.\n    /// </summary>\n    const char** Groups;\n\n    /// <summary>\n    /// The number of items in the Groups array.\n    /// </summary>\n    size_t GroupsCount;\n\n    /// <summary>\n    /// Gets a list of group names for the current user indicating which groups that user encountered during a multiplayer session.\n    /// </summary>\n    const char** Encounters;\n\n    /// <summary>\n    /// The number of items in the Groups array.\n    /// </summary>\n    size_t EncountersCount;\n\n    /// <summary>\n    /// The tournament team session reference.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    XBL_DEPRECATED XblMultiplayerSessionReference TournamentTeamSessionReference;\n\n    /// <summary>\n    /// Internal use only.\n    /// </summary>\n    void* Internal;\n} XblMultiplayerSessionMember;\n\n/// <summary>\n/// A set of properties associated with this session.  \n/// Any player can modify these properties.\n/// </summary>\ntypedef struct XblMultiplayerSessionProperties\n{\n    /// <summary>\n    /// A collection of keywords associated with the session (Optional, might be empty).\n    /// </summary>\n    const char** Keywords;\n\n    /// <summary>\n    /// The number of keywords.\n    /// </summary>\n    size_t KeywordCount;\n\n    /// <summary>\n    /// Restricts who can join \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)  \n    /// Defaults to \"none\".  \n    /// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.  \n    /// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can join without a reservation.\n    /// </summary>\n    XblMultiplayerSessionRestriction JoinRestriction;\n\n    /// <summary>\n    /// Restricts who can read \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)  \n    /// Defaults to \"none\".  \n    /// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.  \n    /// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can read without a reservation.  \n    /// The read restriction applies to sessions with \"open\" or \"visible\" visibility and determines who can read the session without an invite.  \n    /// The read restriction must be at least as accessible as the join restriction, i.e. 'joinRestriction' can't be set to \"followed\" without also setting 'readRestriction'.\"\n    /// </summary>\n    XblMultiplayerSessionRestriction ReadRestriction;\n\n    /// <summary>\n    /// A collection of session MemberIds indicating whose turn it is.\n    /// </summary>\n    uint32_t* TurnCollection;\n\n    /// <summary>\n    /// The number of entries in the TurnCollection array.\n    /// </summary>\n    size_t TurnCollectionCount;\n\n    /// <summary>\n    /// A JSON string representing the target session constants.\n    /// </summary>\n    const char* MatchmakingTargetSessionConstantsJson;\n\n    /// <summary>\n    /// JSON string that specify the custom properties for the session.  \n    /// These can be changed anytime.  \n    /// When changing, call multiplayer_service::write_session to write the changes to the service.\n    /// </summary>\n    const char* SessionCustomPropertiesJson;\n\n    /// <summary>\n    /// Force a specific connection string to be used.  \n    /// This is useful for session in progress join scenarios.\n    /// </summary>\n    const char* MatchmakingServerConnectionString;\n\n    /// <summary>\n    /// The ordered list of connection strings that the session could use to connect to a game server.  \n    /// Generally titles should use the first on the list, but sophisticated titles could use \n    /// a custom mechanism for choosing one of the others (e.g. based on load).\n    /// </summary>\n    const char** ServerConnectionStringCandidates;\n\n    /// <summary>\n    /// The number of entries in the ServerConnectionStringCandidates array.\n    /// </summary>\n    size_t ServerConnectionStringCandidatesCount;\n\n    /// <summary>\n    /// Session MemberIds of owners of the session.\n    /// </summary>\n    uint32_t* SessionOwnerMemberIds;\n\n    /// <summary>\n    /// The number of entries in the SessionOwnerMemberIds array.\n    /// </summary>\n    size_t SessionOwnerMemberIdsCount;\n\n    /// <summary>\n    /// Device token of the host.  \n    /// Must match the \"deviceToken\" of at least one member, otherwise this field is deleted.  \n    /// If \"peerToHostRequirements\" is set and \"host\" is set, the measurement stage assumes the given host is the correct host and only measures metrics to that host.\n    /// </summary>\n    XblDeviceToken HostDeviceToken;\n\n    /// <summary>\n    /// Controls whether a session is joinable, independent of visibility, join restriction, and available space in the session.  \n    /// Does not affect reservations.  \n    /// Defaults to false.\n    /// </summary>\n    bool Closed;\n\n    /// <summary>\n    /// If true, it would allow the members of the session to be locked, such that if a user leaves they are able to \n    /// come back into the session but no other user could take that spot. Defaults to false.\n    /// </summary>\n    bool Locked;\n\n    /// <summary>\n    /// Setting to true by a client triggers a Xbox Live Compute allocation attempt by MPSD.  \n    /// Defaults to false.\n    /// </summary>\n    bool AllocateCloudCompute;\n\n    /// <summary>\n    /// True if the match that was found didn't work out and needs to be resubmitted.  \n    /// Set to false to signal that the match did work, and the matchmaking service can release the session.\n    /// </summary>\n    bool MatchmakingResubmit;\n} XblMultiplayerSessionProperties;\n\n/// <summary>\n/// Basic info about a local multiplayer session.\n/// </summary>\ntypedef struct XblMultiplayerSessionInfo\n{\n    /// <summary>\n    /// The contract version of the session.\n    /// </summary>\n    uint32_t ContractVersion;\n\n    /// <summary>\n    /// The branch of the session used to scope change numbers.\n    /// </summary>\n    char Branch[XBL_GUID_LENGTH];\n\n    /// <summary>\n    /// The change number of the session.\n    /// </summary>\n    uint64_t ChangeNumber;\n\n    /// <summary>\n    /// A unique ID to the session used to query trace logs for entries that relate to the session.\n    /// </summary>\n    char CorrelationId[XBL_GUID_LENGTH];\n\n    /// <summary>\n    /// The time that the session began.\n    /// </summary>\n    time_t StartTime;\n\n    /// <summary>\n    /// If any timeouts are in progress, this is the date when the next timer will fire.\n    /// </summary>\n    time_t NextTimer;\n\n    /// <summary>\n    /// A unique search handle ID to the session.\n    /// </summary>\n    char SearchHandleId[XBL_GUID_LENGTH];\n} XblMultiplayerSessionInfo;\n\n/// <summary>\n/// Present during member initialization.\n/// </summary>\ntypedef struct XblMultiplayerSessionInitializationInfo\n{\n    /// <summary>\n    /// The 'stage' goes from \"joining\" to \"measuring\" to \"evaluating\".  \n    /// If episode #1 fails, then 'stage' is set to \"failed\" and the session cannot be initialized.  \n    /// Otherwise, when an initialization episode completes, the 'initializing' object is removed.  \n    /// If 'autoEvaluate' is set, \"evaluating\" is skipped. If neither 'metrics' nor 'measurementServerAddresses' is set, \"measuring\" is skipped.\n    /// </summary>\n    XblMultiplayerInitializationStage Stage;\n\n    /// <summary>\n    /// The time with the initialization stage started.\n    /// </summary>\n    time_t StageStartTime;\n\n    /// <summary>\n    /// If member_initialization set and Initialize is true on the member, then the member gets assigned to an InitializingEpisode.  \n    /// An episode is a set of users that need to have QoS metrics applied to them.  \n    /// Will be 0 when the InitializingEpisode is not set.  \n    /// This value is only useful when manually managing QoS.\n    /// </summary>\n    uint32_t Episode;\n} XblMultiplayerSessionInitializationInfo;\n\n/// <summary>\n/// Arguments passed to the event handler when a session change occurs.\n/// </summary>\ntypedef struct XblMultiplayerSessionChangeEventArgs\n{\n    /// <summary>\n    /// The session that triggered this event.\n    /// </summary>\n    XblMultiplayerSessionReference SessionReference;\n\n    /// <summary>\n    /// The branch of the session used to scope change numbers.\n    /// </summary>\n    char Branch[XBL_GUID_LENGTH];\n\n    /// <summary>\n    /// The change number of the session.\n    /// </summary>\n    uint64_t ChangeNumber;\n} XblMultiplayerSessionChangeEventArgs;\n\n/// <summary>\n/// Queries the visible multiplayer sessions based on the configuration of this request.\n/// </summary>\ntypedef struct XblMultiplayerSessionQuery\n{\n    /// <summary>\n    /// The service configuration id that the session is a part of.\n    /// </summary>\n    char Scid[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// The maximum number of items to return.\n    /// </summary>\n    uint32_t MaxItems;\n\n    /// <summary>\n    /// Include private sessions to the result.\n    /// </summary>\n    bool IncludePrivateSessions;\n\n    /// <summary>\n    /// Include sessions that the user hasn't accepted.  \n    /// Must specify xboxUserIdFilter to use.\n    /// </summary>\n    bool IncludeReservations;\n\n    /// <summary>\n    /// Include inactive sessions to the result.  \n    /// Must specify xboxUserIdFilter to use.\n    /// </summary>\n    bool IncludeInactiveSessions;\n\n    /// <summary>\n    /// Filter result to just sessions these Xbox User IDs in it. (Optional)  \n    /// You must specify at least one Xuid filter OR a keyword filter.\n    /// </summary>\n    uint64_t* XuidFilters;\n\n    /// <summary>\n    /// The number of Xuids in the XuidsFilters array.\n    /// </summary>\n    size_t XuidFiltersCount;\n\n    /// <summary>\n    /// Filter result to just sessions with this keyword. (Optional)  \n    /// You must specify at least one Xuid filter OR a keyword filter.\n    /// </summary>\n    const char* KeywordFilter;\n\n    /// <summary>\n    /// The name of the template for the multiplayer session to filter on.\n    /// </summary>\n    char SessionTemplateNameFilter[XBL_MULTIPLAYER_SESSION_TEMPLATE_NAME_MAX_LENGTH];\n\n    /// <summary>\n    /// Filter result to just sessions with the specified visibility.\n    /// </summary>\n    XblMultiplayerSessionVisibility VisibilityFilter;\n\n    /// <summary>\n    /// Filter result to just sessions with this major version or less of the contract.  \n    /// Use 0 to ignore.\n    /// </summary>\n    uint32_t ContractVersionFilter;\n} XblMultiplayerSessionQuery;\n\n/// <summary>\n/// Session information returned from a XblMultiplayerQuerySessionsAsync call.\n/// </summary>\ntypedef struct XblMultiplayerSessionQueryResult\n{\n    /// <summary>\n    /// The time that the session began.\n    /// </summary>\n    time_t StartTime;\n\n    /// <summary>\n    /// Session reference for the session.\n    /// </summary>\n    XblMultiplayerSessionReference SessionReference;\n\n    /// <summary>\n    /// The current status of the session.\n    /// </summary>\n    XblMultiplayerSessionStatus Status;\n\n    /// <summary>\n    /// The visibility state of the session.  \n    /// Whether other users can see, or join, etc.\n    /// </summary>\n    XblMultiplayerSessionVisibility Visibility;\n\n    /// <summary>\n    /// Indicates if it is my turn.\n    /// </summary>\n    bool IsMyTurn;\n\n    /// <summary>\n    /// Xbox User ID of the member.\n    /// </summary>\n    uint64_t Xuid;\n\n    /// <summary>\n    /// Approximate number of non-reserved members.\n    /// </summary>\n    uint32_t AcceptedMemberCount;\n\n    /// <summary>\n    /// Join restriction for the session.\n    /// </summary>\n    XblMultiplayerSessionRestriction JoinRestriction;\n} XblMultiplayerSessionQueryResult;\n\n/// <summary>\n/// A handle to an search details object that is associated with a MPSD sessions.  \n/// The object has filterable and queryable attributes about the session.\n/// </summary>\ntypedef struct XblMultiplayerSearchHandleDetails* XblMultiplayerSearchHandle;\n\n#define XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH 100\n\n/// <summary>\n/// A searchable tag that can be attached to a multiplayer session search handle when it is created.  \n/// Tags must be alphanumeric and start with a letter.  \n/// They're case-insensitive.\n/// </summary>\ntypedef struct XblMultiplayerSessionTag\n{\n    /// <summary>\n    /// The multiplayer search handle.\n    /// </summary>\n    char value[XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH];\n} XblMultiplayerSessionTag;\n\n/// <summary>\n/// An associative attribute that can be attached to a multiplayer session search handle when it is created.  \n/// Attribute names be lower-case alphanumeric, and start with a letter.\n/// </summary>\ntypedef struct XblMultiplayerSessionStringAttribute\n{\n    /// <summary>\n    /// Name of the attribute.\n    /// </summary>\n    char name[XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH];\n\n    /// <summary>\n    /// Attribute value.\n    /// </summary>\n    char value[XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH];\n} XblMultiplayerSessionStringAttribute;\n\n/// <summary>\n/// An associative attribute that can be attached to a multiplayer session search handle when it is created.\n/// Attribute names be lower-case alphanumeric, and start with a letter.\n/// </summary>\ntypedef struct XblMultiplayerSessionNumberAttribute\n{\n    /// <summary>\n    /// Name of the attribute.\n    /// Attribute names be lower-case alphanumeric, and start with a letter.\n    /// </summary>\n    char name[XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH];\n\n    /// <summary>\n    /// Attribute value.\n    /// </summary>\n    double value;\n} XblMultiplayerSessionNumberAttribute;\n\n/// <summary>\n/// Handle to a local multiplayer session.  \n/// This handle will be used to query and change the local session object.  \n/// Anytime the changes made to the local session object will not be reflected in the multiplayer service\n/// until a subsequent call to <see cref=\"XblMultiplayerWriteSessionAsync\"/>.\n/// </summary>\ntypedef struct XblMultiplayerSession* XblMultiplayerSessionHandle;\n\n/// <summary>\n/// Optional args when creating a new local multiplayer session.\n/// </summary>\ntypedef struct XblMultiplayerSessionInitArgs\n{\n    /// <summary>\n    /// The maximum number of members in this session.  \n    /// This value can only be set if the maximum is not specified in the title's multiplayer session template.  \n    /// If the maximum is specified in the title's multiplayer session template, then set to 0 to ignore this parameter.\n    /// </summary>\n    uint32_t MaxMembersInSession;\n\n    /// <summary>\n    /// The visibility of this session.\n    /// </summary>\n    XblMultiplayerSessionVisibility Visibility;\n\n    /// <summary>\n    /// A collection of Xbox User IDs indicating who initiated the session. (Optional)\n    /// </summary>\n    const uint64_t* InitiatorXuids;\n\n    /// <summary>\n    /// The number of Xuids in the Initiator XuidsArray.\n    /// </summary>\n    size_t InitiatorXuidsCount;\n\n    /// <summary>\n    /// JSON that specifies the custom constants for the session.These can not be changed after the session is created. (Optional)\n    /// </summary>\n    _Null_terminated_ const char* CustomJson;\n} XblMultiplayerSessionInitArgs;\n\n/// <summary>\n/// Creates a new local multiplayer session.\n/// </summary>\n/// <param name=\"xuid\">The Xbox User ID of the user who is creating this session.</param>\n/// <param name=\"sessionReference\">A reference that uniquely identifies the session.</param>\n/// <param name=\"initArgs\">Additional args used to initialize the session. Must also include the sessionReference if these are included.</param>\n/// <returns>Handle to a local multiplayer session.</returns>\n/// <remarks>\n/// You must call <see cref=\"XblMultiplayerWriteSessionAsync\"/> after this to write batched local changes to the service.  \n/// If this is called without XblMultiplayerWriteSessionAsync, this will only create a local session object, but does not commit it to the service.  \n/// When the local session object is no longer needed, call <see cref=\"XblMultiplayerSessionCloseHandle\"/>.\n/// </remarks>\nSTDAPI_(XblMultiplayerSessionHandle) XblMultiplayerSessionCreateHandle(\n    _In_ uint64_t xuid,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n    _In_opt_ const XblMultiplayerSessionInitArgs* initArgs\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Increments the reference count to a local session object.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"duplicatedHandle\">Passes back the duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionDuplicateHandle(\n    _In_ XblMultiplayerSessionHandle handle,\n    _Out_ XblMultiplayerSessionHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Decrements the reference count to a local session object.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionCloseHandle(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Arbitration status of a tournament.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>Returns the status of a tournament.</returns>\nSTDAPI_XBL_DEPRECATED_(XblTournamentArbitrationStatus) XblMultiplayerSessionArbitrationStatus(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// The time when the server returned the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The time when the server returned the session.</returns>\n/// <remarks>\n/// Note that this is not part of the remote session state, it only indicates when the local session was created.\n/// </remarks>\nSTDAPI_(time_t) XblMultiplayerSessionTimeOfSession(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the info about session initialization.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The initialization info used to create the session.</returns>\n/// <remarks>\n/// If the session is not doing member initialization, nullptr will be returned.\n/// </remarks>\nSTDAPI_(const XblMultiplayerSessionInitializationInfo*) XblMultiplayerSessionGetInitializationInfo(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Returns an OR'd set of XblMultiplayerSessionChangeTypes values representing the aspects of the session \n/// that the current xboxlivecontext is subscribed to, of XblMultiplayerSessionChangeTypes::None if there is none.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>An OR'd set of XblMultiplayerSessionChangeTypes values representing the aspects of the session.</returns>\nSTDAPI_(XblMultiplayerSessionChangeTypes) XblMultiplayerSessionSubscribedChangeTypes(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Host candidates are an ordered list of device tokens, ordered by preference as specified by XblMultiplayerMetrics\n/// in the session constants.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"deviceTokens\">Passes back a pointer to the array of candidate device tokens.  \n/// The memory for the pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"deviceTokensCount\">Passes back the size of the deviceTokens array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionHostCandidates(\n    _In_ XblMultiplayerSessionHandle handle,\n    _Out_ const XblDeviceToken** deviceTokens,\n    _Out_ size_t* deviceTokensCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// The uniquely identifying information for the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>A pointer to the multiplayer session reference.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nSTDAPI_(const XblMultiplayerSessionReference*) XblMultiplayerSessionSessionReference(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A set of constants associated with this session.  \n/// These can only be set when creating the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>A pointer to the constant values used in the multiplayer session.</returns>\nSTDAPI_(const XblMultiplayerSessionConstants*) XblMultiplayerSessionSessionConstants(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the maximum number of members in this session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"maxMembersInSession\">Value to set for max members.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionConstantsSetMaxMembersInSession(\n    _In_ XblMultiplayerSessionHandle handle,\n    uint32_t maxMembersInSession\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the visibility of this session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"visibility\">New visibility value.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionConstantsSetVisibility(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerSessionVisibility visibility\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the timeouts for the session.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"memberReservedTimeout\">The timeout for a member reservation, in milliseconds.  \n/// A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n/// <param name=\"memberInactiveTimeout\">The timeout for a member to be considered inactive, in milliseconds.  \n/// A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n/// <param name=\"memberReadyTimeout\">The timeout for a member to be considered ready, in milliseconds.  \n/// A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n/// <param name=\"sessionEmptyTimeout\">The timeout for an empty session, in milliseconds.  \n/// A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionConstantsSetTimeouts(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ uint64_t memberReservedTimeout,\n    _In_ uint64_t memberInactiveTimeout,\n    _In_ uint64_t memberReadyTimeout,\n    _In_ uint64_t sessionEmptyTimeout\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the arbitration timeouts for the session.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"arbitrationTimeout\">The timeout for arbitration, in milliseconds representing the point at which results are finalized.</param>\n/// <param name=\"forfeitTimeout\">The timeout for forfeit, in milliseconds representing the point at which, \n/// if the session has no active users, the match is canceled.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblMultiplayerSessionConstantsSetArbitrationTimeouts(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ uint64_t arbitrationTimeout,\n    _In_ uint64_t forfeitTimeout\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Enables or disables connectivity metrics for the session.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"enableLatencyMetric\">True to enable the measuring of latency, and false to disable latency measurement.</param>\n/// <param name=\"enableBandwidthDownMetric\">True to enable the measuring of bandwidth down, and false to disable bandwidth down measurement.</param>\n/// <param name=\"enableBandwidthUpMetric\">True to enable the measuring of bandwidth up, and false to disable bandwidth up measurement.</param>\n/// <param name=\"enableCustomMetric\">True to enable custom metrics, and false to disable them.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// For ones that are enabled, they must be sufficient to satisfy the QoS requirements.\n/// </remarks>\nSTDAPI XblMultiplayerSessionConstantsSetQosConnectivityMetrics(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ bool enableLatencyMetric,\n    _In_ bool enableBandwidthDownMetric,\n    _In_ bool enableBandwidthUpMetric,\n    _In_ bool enableCustomMetric\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// If a 'memberInitialization' object is set, the session expects the client system or title to perform \n/// initialization following session creation and/or as new members join the session.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"memberInitialization\">Object specifying member initialization parameters.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The timeouts and initialization stages are automatically tracked by the session, including QoS measurements if any metrics are set.  \n/// These timeouts override the session's reservation and ready timeouts for members that have 'initializationEpisode' set.\n/// </remarks>\nSTDAPI XblMultiplayerSessionConstantsSetMemberInitialization(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerMemberInitialization memberInitialization\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// These thresholds apply to each pairwise connection for all members in a session.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"requirements\">Object specifying the peer to peer requirements for the session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionConstantsSetPeerToPeerRequirements(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerPeerToPeerRequirements requirements\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// These thresholds apply to each connection from a host candidate.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"requirements\">Object specifying the peer to host requirements for the session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionConstantsSetPeerToHostRequirements(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerPeerToHostRequirements requirements\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// The set of potential server connection strings that should be evaluated.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"measurementServerAddressesJson\">The Json that represent the measurement server addresses.  \n/// Example JSON:\n/// {\n///   \"server farm a\": {\n///     \"secureDeviceAddress\": \"r5Y=\" // Base-64 encoded secure-device-address\n///   },  \n///   \"datacenter b\" : {\n///     \"secureDeviceAddress\": \"rwY=\"\n///   }\n/// }\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const char* measurementServerAddressesJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the capabilities constants for the session.  \n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"capabilities\">A collection of MultiplayerSessionCapabilities flags that apply to the MultiplayerSessionConstant's capabilities JSON object.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionConstantsSetCapabilities(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerSessionCapabilities capabilities\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// This can only be set when creating a new session.  \n/// Can only be specified if the 'cloudCompute' capability is set.  \n/// Enables clients to request that a cloud compute instance be allocated on behalf of the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"sessionCloudComputePackageConstantsJson\">Cloud compute instance to be allocated on behalf of the session.  \n/// Example Json:\n/// {\n///   \"crossSandbox\": true, // True if the cloud compute resources are provisioned to be sandbox-agnostic, false if they are provisioned per-sandbox.\n///   \"titleId\" : \"4567\", //The title ID and GSI set of the cloud compute package to allocate.\n///   \"gsiSet\" : \"128ce92a-45d0-4319-8a7e-bd8e940114ec\"\n/// }\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionConstantsSetCloudComputePackageJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const char* sessionCloudComputePackageConstantsJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the properties associated with the session.  \n/// Any player can modify these properties.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>A pointer to the set of properties associated with this session.</returns>\nSTDAPI_(const XblMultiplayerSessionProperties*) XblMultiplayerSessionSessionProperties(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A collection of keywords associated with the session. (Optional, might be empty)\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"keywords\">The keywords to associate with the session. Overwrites existing keywords.</param>\n/// <param name=\"keywordsCount\">The size of the keywords array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionPropertiesSetKeywords(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const char** keywords,\n    _In_ size_t keywordsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Restricts who can join \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"joinRestriction\">New join restriction value.</param>\n/// <returns></returns>\n/// <remarks>\n/// Defaults to \"none\".  \n/// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.  \n/// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can join without a reservation.\n/// </remarks>\nSTDAPI_(void) XblMultiplayerSessionPropertiesSetJoinRestriction(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerSessionRestriction joinRestriction\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Restricts who can read \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"readRestriction\">New read restriction value.</param>\n/// <returns></returns>\n/// <remarks>\n/// Defaults to \"none\".  \n/// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.  \n/// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can read without a reservation.\n/// </remarks>\nSTDAPI_(void) XblMultiplayerSessionPropertiesSetReadRestriction(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerSessionRestriction readRestriction\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the collection of session MemberIds indicating whose turn it is.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"turnCollectionMemberIds\">Collection of MemberIds whose turn it is.</param>\n/// <param name=\"turnCollectionMemberIdsCount\">The size of the turnCollectionMemberIds array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionPropertiesSetTurnCollection(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const uint32_t* turnCollectionMemberIds,\n    _In_ size_t turnCollectionMemberIdsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A set of role types associated with this session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"roleTypes\">Passes back a pointer to an array of roleTypes.  \n/// The memory for the pointer remains valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"roleTypesCount\">Passes back the number of roles types in the roleTypes array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionRoleTypes(\n    _In_ XblMultiplayerSessionHandle handle,\n    _Out_ const XblMultiplayerRoleType** roleTypes,\n    _Out_ size_t* roleTypesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Fetches the XblMultiplayerRole object by role type name and role name.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"roleTypeName\">Name of the role type the role belongs to.</param>\n/// <param name=\"roleName\">Name of the role.</param>\n/// <param name=\"role\">Passes back a pointer to the role object with info about the role.  \n/// The memory for the pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.  \n/// If no such role exists, nullptr will be passed back.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Note that newly created sessions will not have role info populated until the XblMultiplayerWriteSessionAsync is called.\n/// </remarks>\nSTDAPI XblMultiplayerSessionGetRoleByName(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* roleTypeName,\n    _In_z_ const char* roleName,\n    _Out_ const XblMultiplayerRole** role\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the max member count and/or target member counts for a role.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"roleTypeName\">Name of the role type for the role being modified.</param>\n/// <param name=\"roleName\">Name of the role to modify.</param>\n/// <param name=\"maxMemberCount\">The maximum number of members that can have the role.</param>\n/// <param name=\"targetMemberCount\">The target number of members for the role.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Only the session owner can modify role settings and only those that are mutable (see XblMultiplayerRoleType.MutableRoleSettings).  \n/// In your session template, you also need to set 'hasOwners' capability and 'ownerManaged' to true for the specific role type \n/// that you want to modify.\n/// </remarks>\nSTDAPI XblMultiplayerSessionSetMutableRoleSettings(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* roleTypeName,\n    _In_z_ const char* roleName,\n    _In_opt_ uint32_t* maxMemberCount,\n    _In_opt_ uint32_t* targetMemberCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the collection of members that are in the session or entering the session together.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"members\">Passes back a pointer to array of session member objects.\n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"membersCount\">Passes back the size of the returned array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call XblMultiplayerSessionJoin or XblMultiplayerSessionLeave to add or remove yourself from this list.  \n/// Call XblMultiplayerSessionAddMemberReservation to add a reservation for another user on this list.\n/// </remarks>\nSTDAPI XblMultiplayerSessionMembers(\n    _In_ XblMultiplayerSessionHandle handle,\n    _Out_ const XblMultiplayerSessionMember** members,\n    _Out_ size_t* membersCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the session member with a specified MemberId.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"memberId\">The Id of the member to fetch.</param>\n/// <returns>A pointer to a member in a multiplayer session. (Read Only)  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\n/// <remarks>\n/// If there is no member with the specified Id, nullptr is returned.\n/// </remarks>\nSTDAPI_(const XblMultiplayerSessionMember*) XblMultiplayerSessionGetMember(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ uint32_t memberId\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A multiplayer session server that contains properties associated with a target session reference.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The matchmaking server supporting the multiplayer session.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nSTDAPI_(const XblMultiplayerMatchmakingServer*) XblMultiplayerSessionMatchmakingServer(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A tournament session servers that contains properties associated with a tournament reference.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The tournament server supporting the multiplayer session.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\nSTDAPI_XBL_DEPRECATED_(const XblMultiplayerTournamentsServer*) XblMultiplayerSessionTournamentsServer(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\nXBL_WARNING_POP\n\n/// <summary>\n/// An arbitration server that contains properties associated with a tournament games results.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The arbitration server supporting the multiplayer session.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\nSTDAPI_XBL_DEPRECATED_(const XblMultiplayerArbitrationServer*) XblMultiplayerSessionArbitrationServer(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\nXBL_WARNING_POP\n\n/// <summary>\n/// The number of members that have accepted and are added to the session and are no longer pending.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The number of members that have accepted.</returns>\nSTDAPI_(uint32_t) XblMultiplayerSessionMembersAccepted(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A JSON string containing a collection of servers for this multiplayer session.  \n/// This Json object has the info that is parsed to create the XblMultiplayerArbitrationServer, \n/// XblMultiplayerMatchmakingServer, and XblMultiplayerTournamentsServer objects.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The JSON string containing a collection of servers for this multiplayer session.\n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nSTDAPI_(const char*) XblMultiplayerSessionRawServersJson(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the JSON string containing a collection of servers for this multiplayer session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"rawServersJson\">Json describing the session servers.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionSetRawServersJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* rawServersJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// The ETag returned with this session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The ETag.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nSTDAPI_(const char*) XblMultiplayerSessionEtag(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Returns the current User in the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The current User in the session.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\n/// <remarks>\n/// A nullptr will be returned if there is no current user in the session.\n/// </remarks>\nSTDAPI_(const XblMultiplayerSessionMember*) XblMultiplayerSessionCurrentUser(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets some basic info about the session.  \n/// Represents the info in the root of the MPSD session document.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>A pointer to the basic info about the local multiplayer session.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</returns>\nSTDAPI_(const XblMultiplayerSessionInfo*) XblMultiplayerSessionGetInfo(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// After call XblMultiplayerWriteSessionAsync, the status of the write.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>The write status of the Multiplayer session.</returns>\nSTDAPI_(XblWriteSessionStatus) XblMultiplayerSessionWriteStatus(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Add a new member reservation on the session for the specified xuid and member constants.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"xuid\">The xuid to add a reservation for.</param>\n/// <param name=\"memberCustomConstantsJson\">The custom constants to set for this member.  \n/// This is the only time the member's constants can be set. (Optional)</param>\n/// <param name=\"initializeRequested\">True if the system should perform managed initialization, and false otherwise.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionAddMemberReservation(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ uint64_t xuid,\n    _In_opt_z_ const char* memberCustomConstantsJson,\n    _In_ bool initializeRequested\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Joins the local user to the session, sets the user to active.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"memberCustomConstantsJson\">The custom constants to set for this member.  \n/// This is the only time the member's constants can be set.</param>\n/// <param name=\"initializeRequested\">True if the system should perform managed initialization, and false otherwise.</param>\n/// <param name=\"joinWithActiveStatus\">True if player should join with active status.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionJoin(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_opt_z_ const char* memberCustomConstantsJson,\n    _In_ bool initializeRequested,\n    _In_ bool joinWithActiveStatus\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// This can only be set when creating a new session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"initializationSucceeded\">True if initialization succeeded, and false otherwise.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionSetInitializationSucceeded(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ bool initializationSucceeded\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the device token of the host.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"hostDeviceToken\">The host device token.</param>\n/// <returns></returns>\n/// <remarks>\n/// If \"peerToHostRequirements\" is set and this is set, the measurement stage assumes the given host is the correct host and only measures metrics to that host.\n/// Note that host device tokens are generated from a session member's secure device address, so ensure that the secure device address is set\n/// (see <see cref=\"XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64\"/>) for the desired host prior to calling this method.\n/// </remarks>\nSTDAPI_(void) XblMultiplayerSessionSetHostDeviceToken(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblDeviceToken hostDeviceToken\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Forces a specific server connection string to be used, useful in preserveSession=always cases.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"serverConnectionPath\">The server connection path.  \n/// Setting this path can be useful when the session is preserved.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionSetMatchmakingServerConnectionPath(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* serverConnectionPath\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// If set to true, makes the session \"closed\", meaning that new users will not be able to join unless they already have a reservation.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"closed\">True if the session should be closed, false otherwise.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionSetClosed(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ bool closed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets if a session is locked or not.  \n/// If locked, members that leave the session will be able to come back into the session, allowing no additional users to take that spot.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"locked\">Set true, if the session should be lock, false otherwise.</param>\n/// <returns></returns>\n/// <remarks>\n/// If the session is locked, it must also be set to closed.\n/// </remarks>\nSTDAPI_(void) XblMultiplayerSessionSetLocked(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ bool locked\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// If this property is set an allocation of the 'cloudComputePackage' will be attempted.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"allocateCloudCompute\">True if a cloud compute package should be allocated and false otherwise.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionSetAllocateCloudCompute(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ bool allocateCloudCompute\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets if a match needs to be resubmitted or not.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"matchResubmit\">Set true, if the match that was found didn't work out and needs to be resubmitted.  \n/// Set false, if the match did work and the matchmaking service can release the session. </param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSessionSetMatchmakingResubmit(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ bool matchResubmit\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// The ordered list of case-insensitive connection strings that the session could use to connect to a game server.  \n/// Generally titles should use the first on the list, but sophisticated titles could use \n/// a custom mechanism for choosing one of the others (e.g. based on load).\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"serverConnectionStringCandidates\">The collection of connection paths.</param>\n/// <param name=\"serverConnectionStringCandidatesCount\">The size of the candidates array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionSetServerConnectionStringCandidates(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_reads_(serverConnectionStringCandidatesCount) const char** serverConnectionStringCandidates,\n    _In_ size_t serverConnectionStringCandidatesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the set of session changes that this client will be subscribed to.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"changeTypes\">Or'd set of XblMultiplayerSessionChangeType enum values representing the change types to subscribe to.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Set to MultiplayerSessionChangeTypes::None to clear the subscription.\n/// </remarks>\nSTDAPI XblMultiplayerSessionSetSessionChangeSubscription(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerSessionChangeTypes changeTypes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Call if the user who either created or got the session leaves the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the session is deleted as a result of this action, a 204 response will be returned.\n/// </remarks>\nSTDAPI XblMultiplayerSessionLeave(\n    _In_ XblMultiplayerSessionHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set the current user to active or inactive.  \n/// The member must first be joined to the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"status\">Indicates the current user status.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// You cannot set the user to reserved or ready in this manner.  \n/// Use <see cref=\"XblMultiplayerSessionAddMemberReservation\"/> to add a member reservation.\n/// </remarks>\nSTDAPI XblMultiplayerSessionCurrentUserSetStatus(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ XblMultiplayerSessionMemberStatus status\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set the base64 encoded secure device address of the member.  \n/// The member must first be joined to the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"value\">Indicates the value of the current user's secure device address encoded in base64.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// On platforms that don't have a secure device address, call XblFormatSecureDeviceAddress \n/// to generate a value that can be used by this function. Note that setting a secure device address is required\n/// to manually set a session host.\n/// </remarks>\nSTDAPI XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const char* value\n) XBL_NOEXCEPT;\n\n#if HC_PLATFORM != HC_PLATFORM_XDK && HC_PLATFORM != HC_PLATFORM_UWP\n/// <summary>\n/// A formatted secure device address.\n/// </summary>\ntypedef struct XblFormattedSecureDeviceAddress\n{\n    /// <summary>\n    /// The secure device address.\n    /// </summary>\n    char value[4096];\n} XblFormattedSecureDeviceAddress;\n\n/// <summary>\n/// Formats a secure device address given a unique device id for platforms that don't support SDAs.\n/// </summary>\n/// <param name=\"deviceId\">A unique id to represent this device for the lifetime of the local game process/instance.</param>\n/// <param name=\"address\">Passes back the formatted secure device address.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Formats the deviceId string according to the following recommendation:  \n///\n///     Generate 16 random bytes(e.g., a GUID) to be used for the lifetime of the local game process/instance\n///     to uniquely represent the device.  Format the 'secureDeviceAddress' to be a string with the prefix \"AAAAAAAA\"\n///     (8 capital letter As) followed by the 32 character hexadecimal representation of the random bytes(upper \n///     or lower case letters don't matter, nor does the byte order if the bytes are an actual structured GUID).  \n///     For example, \"AAAAAAAA00112233445566778899AABBCCDDEEFF\".  \n///\n/// Call XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64 using the formatted SDA to set the SDA for the user.\n/// </remarks>\nSTDAPI XblFormatSecureDeviceAddress(\n    _In_ const char* deviceId,\n    _Inout_ XblFormattedSecureDeviceAddress* address\n) XBL_NOEXCEPT;\n#endif\n\n/// <summary>\n/// Set the role info of the local member.  \n/// The member must first be joined to the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"roles\">Indicates a collection of roles for the user.</param>\n/// <param name=\"rolesCount\">The size of the role array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetRoles(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const XblMultiplayerSessionMemberRole* roles,\n    _In_ size_t rolesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set a collection of members in the group.  \n/// The member must first be joined to the session.\n/// </summary>\n/// <param name=\"session\">Handle to the multiplayer session.</param>\n/// <param name=\"memberIds\">Array of memberIds that are in the local users group.</param>\n/// <param name=\"memberIdsCount\">Size of the memberIds array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetMembersInGroup(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_reads_(memberIdsCount) uint32_t* memberIds,\n    _In_ size_t memberIdsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets a string vector of group names for the current user indicating which groups that user was part of during a multiplayer session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"groups\">Array of group names.</param>\n/// <param name=\"groupsCount\">Size of the groups array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetGroups(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_reads_(groupsCount) const char** groups,\n    _In_ size_t groupsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets a list of group names for the current user indicating which groups that user encountered during a multiplayer session.  \n/// An encounter is a brief interaction with another group.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"encounters\">Array of encounter strings.</param>\n/// <param name=\"encountersCount\">Size of the encounters array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetEncounters(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_reads_(encountersCount) const char** encounters,\n    _In_ size_t encountersCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets a collection of XblMultiplayerQosMeasurements for the members.  \n/// This is only useful when the title is manually managing QoS. (If the platform is automatically performing QoS, this does not need to be called)\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"measurements\">Json representing the QoS measurements of members.  \n/// Example Json:\n/// {\n///   \"e69c43a8\": { // Device token of peer\n///     \"latency\": 5953,  // Milliseconds\n///     \"bandwidthDown\" : 19342,  // Kilobits per second\n///     \"bandwidthUp\" : 944,  // Kilobits per second\n///     \"custom\" : { }\n///   },\n///   ... // additional device tokens\n/// }\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetQosMeasurements(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* measurements\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets measurements JSON for the servers.  \n/// This is only useful when the title is manually managing QoS. (If the platform is automatically performing QoS, this does not need to be called)\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"measurements\">The JSON that represents the server measurements.  \n/// Example Json:\n/// {\n///   \"server farm a\": {\n///     \"latency\": 233  // Milliseconds\n///   }\n/// }\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetServerQosMeasurements(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* measurements\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set a custom property on the current user to the specified JSON string.  \n/// The member must first be joined to the session.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"name\">The name of the property to set.</param>\n/// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserSetCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Delete a custom property on the current user.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"name\">The name of the property to delete.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* name\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the properties of the matchmaking.  \n/// This should only be set by a client acting as a matchmaking service.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"matchmakingTargetSessionConstantsJson\">A JSON string representing the target session constants.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_ const char* matchmakingTargetSessionConstantsJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set a session custom property to the specified JSON string.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"name\">The name of the property to set.</param>\n/// <param name=\"valueJson\">\n/// The JSON value to assign to the property. This must be a valid JSON string.\n/// Examples include \"\\\"JsonString\\\"\", \"{\\\"name\\\":\\\"A\\\"}\", or \"true\".\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionSetCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Deletes a session custom property.\n/// </summary>\n/// <param name=\"handle\">Handle to the multiplayer session.</param>\n/// <param name=\"name\">The name of the property to delete.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSessionDeleteCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle handle,\n    _In_z_ const char* name\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Checks the deltas between 2 sessions and returns an Or'ed MultiplayerSessionChangeType.  \n/// Useful to compare a session object passed to XblMultiplayerWriteSessionAsync with the session object returned.\n/// </summary>\n/// <param name=\"currentSessionHandle\">A session to compare to the other.</param>\n/// <param name=\"oldSessionHandle\">A session to compare to the other.</param>\n/// <returns>The Or'ed change types for a multiplayer session.</returns>\nSTDAPI_(XblMultiplayerSessionChangeTypes) XblMultiplayerSessionCompare(\n    _In_ XblMultiplayerSessionHandle currentSessionHandle,\n    _In_ XblMultiplayerSessionHandle oldSessionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Increments the reference count to a local search handle details object.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"duplicatedHandle\">Passes back the duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleDuplicateHandle(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSearchHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Decrements the reference count to a local search handle details object.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerSearchHandleCloseHandle(\n    _In_ XblMultiplayerSearchHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the session reference for the session the search handle is associated with.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"sessionRef\">Passes back the associated session reference.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetSessionReference(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSessionReference* sessionRef\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the Id for the search handle object.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"id\">Passes back a search handle Id.  \n/// The memory for the pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetId(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const char** id\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get a pointer to an array of Xuids who own the session associated with the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"xuids\">Passes back a pointer to array of xuids.  \n/// The memory for the pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"xuidsCount\">Passes back the count of xuids in the array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetSessionOwnerXuids(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const uint64_t** xuids,\n    _Out_ size_t* xuidsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get a pointer to an array of tags attached with the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"tags\">Passes back a pointer to array of tags.  \n/// The memory for the pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"tagsCount\">Passes back the count of tags in the array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetTags(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const XblMultiplayerSessionTag** tags,\n    _Out_ size_t* tagsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get a pointer to an array of attributes attached with the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"attributes\">Passes back a pointer to array of attributes.  \n/// The memory for the pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"attributesCount\">Passes back the count of attributes in the array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetStringAttributes(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const XblMultiplayerSessionStringAttribute** attributes,\n    _Out_ size_t* attributesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get a pointer to an array of attributes attached with the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"attributes\">Passes back a pointer to array of attributes.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <param name=\"attributesCount\">Passes back the count of attributes in the attributes array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetNumberAttributes(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const XblMultiplayerSessionNumberAttribute** attributes,\n    _Out_ size_t* attributesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get visibility of the session associated with the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"visibility\">Passes back the visibility of the associated session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetVisibility(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSessionVisibility* visibility\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get join restriction of the session associated with the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"joinRestriction\">Passes back the join restriction of the associated session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetJoinRestriction(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSessionRestriction* joinRestriction\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get whether or not the session associated with the search handle is temporarily closed for joining.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"closed\">Passes back whether the session is closed or not.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetSessionClosed(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ bool* closed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the current and max number of members in the associated session.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"maxMembers\">Passes back the max members allowed in session.</param>\n/// <param name=\"currentMembers\">Passes back the current number of members in session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetMemberCounts(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_opt_ size_t* maxMembers,\n    _Out_opt_ size_t* currentMembers\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the creation time of the search handle.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"creationTime\">Passes back the time the search handle was created in MPSD (not the local object).</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetCreationTime(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ time_t* creationTime\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the custom session properties for the associated session.\n/// </summary>\n/// <param name=\"handle\">Handle to the search handle details.</param>\n/// <param name=\"customPropertiesJson\">Passes back the custom properties JSON string.  \n/// The memory for the returned pointer will remain valid for the life of the XblMultiplayerSessionHandle object until it is closed.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSearchHandleGetCustomSessionPropertiesJson(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const char** customPropertiesJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Writes a new or updated multiplayer session to the service.  \n/// The session must have a valid session reference.  \n/// If it was not created with one, use XblMultiplayerWriteSessionByHandleAsync instead.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"multiplayerSession\">A MultiplayerSession object that has been modified with the changes to write.</param>\n/// <param name=\"writeMode\">The type of write operation.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// In the async callback, call XblMultiplayerWriteSessionResult() to get a XblMultiplayerSessionHandle handle.\n/// Use that handle to call XblMultiplayerSessionWriteStatus() to get the write status.\n/// The call to XblMultiplayerWriteSessionAsync() will only fail if the args passed to it are invalid or in very rare \n/// cases where it could not start the async task.\n/// </remarks>\n/// <rest>Calls V105 PUT /serviceconfigs/{serviceConfigurationId}/sessionTemplates/{sessiontemplateName}/sessions/{sessionName}</rest>\nSTDAPI XblMultiplayerWriteSessionAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionHandle multiplayerSession,\n    _In_ XblMultiplayerSessionWriteMode writeMode,\n    _Inout_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a XblMultiplayerWriteSessionAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handle\">Passes back a handle to a new instance of a local multiplayer session object.\n/// The XblMultiplayerSessionHandle must be released by the caller by calling <see cref=\"XblMultiplayerSessionCloseHandle\"/>.\n/// Use XblMultiplayerSession* APIs to get session data from the handle.\n/// If the updated session object is not needed, passing nullptr will cause the new multiplayer\n/// session object to be cleaned up immediately.\n/// </param>\n/// <returns>HRESULT return code for this API operation.  \n/// It will be a failure HRESULT if there was a network error or failure HTTP status code unless its a 412 (Precondition Failed).\n/// A 412 returns success since the service also returns latest session state, so you must call XblMultiplayerSessionWriteStatus() to get the \n/// write status and call XblMultiplayerSession* APIs to get session data from the handle.\n/// </returns>\n/// <remarks>\n/// Note that if you leave a session that you are the last member of and the sessionEmptyTimeout \n/// is equal to 0, then the session will be deleted immediately.\n/// Call XblMultiplayerSessionWriteStatus() to get the write status.\n/// </remarks>\nSTDAPI XblMultiplayerWriteSessionResult(\n    _Inout_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Writes a new or updated multiplayer session to the service, using the specified handle to the session.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"multiplayerSession\">A MultiplayerSession object that has been modified with the changes to write.</param>\n/// <param name=\"writeMode\">The type of write operation.</param>\n/// <param name=\"handleId\">The ID of the handle that should be used when writing the session.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// A handle is a service-side pointer to a session.  The handle ID is a GUID identifier of the handle.  \n/// Callers will usually get the handleId either from another player's XblMultiplayerActivityDetails via \n/// the XblMultiplayerGetActivitiesForUsersAsync() API, or from an invite.  \n///\n/// Use this method only if your multiplayer session object doesn't have a valid XblMultiplayerSessionReference, as\n/// a handle's lifetime may be shorter than that of the session it points to.\n/// </remarks>\nSTDAPI XblMultiplayerWriteSessionByHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionHandle multiplayerSession,\n    _In_ XblMultiplayerSessionWriteMode writeMode,\n    _In_ const char* handleId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a XblMultiplayerWriteSessionAsync operation.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handle\">Passes back a handle to a new instance of a local multiplayer session object.  \n/// It must be release by the caller with <see cref=\"XblMultiplayerSessionCloseHandle\"/>.  \n/// If the updated session object is not needed, passing nullptr will cause the new multiplayer session object to be cleaned up immediately.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Note that if you leave a session that you are the last member of and the sessionEmptyTimeout\n/// is equal to 0, then the session will be deleted immediately and a nullptr will be returned.\n/// </remarks>\nSTDAPI XblMultiplayerWriteSessionByHandleResult(\n    _Inout_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets an existing session object with all its attributes from the server.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"sessionReference\">A XblMultiplayerSessionReference object containing identifying information for the session.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>Calls V102 GET /serviceconfigs/{serviceConfigurationId}/sessionTemplates/{sessiontemplateName}/sessions/{sessionName}</rest>\nSTDAPI XblMultiplayerGetSessionAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of an XblMultiplayerGetSessionResult call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handle\">Passes back a handle to a new instance of a local multiplayer session object.\n/// It must be release by the caller with <see cref=\"XblMultiplayerSessionCloseHandle\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the session does not exist, this API will return __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND) and a null\n/// XblMultiplayerSessionHandle.\n/// </remarks>\nSTDAPI XblMultiplayerGetSessionResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets a session object with all its attributes from the server, given a session handle id.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"handleId\">A multiplayer handle id, which uniquely identifies the session.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// A handle is a service-side pointer to a session. The handleId is a GUID identifier of the handle.  \n/// Callers will usually get the handleId either from another player's XblMultiplayerActivityDetails, or from an invite.\n/// </remarks>\n/// <rest>Calls GET /handles/{handleId}/session</rest>\nSTDAPI XblMultiplayerGetSessionByHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* handleId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of an XblMultiplayerGetSessionByHandleAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handle\">Passes back a handle to a new instance of a local multiplayer session object.  \n/// It must be release by the caller with <see cref=\"XblMultiplayerSessionCloseHandle\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the session does not exist, this API will return __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND) and a null\n/// XblMultiplayerSessionHandle.\n/// </remarks>\nSTDAPI XblMultiplayerGetSessionByHandleResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieve a list of sessions with various filters.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"sessionQuery\">A session query object that defines the parameters for the query.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>Calls V102 GET /serviceconfigs/{scid}/sessions or /serviceconfigs/{scid}/sessiontemplates/{session-template-name}/sessions</rest>\nSTDAPI XblMultiplayerQuerySessionsAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionQuery* sessionQuery,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the number of sessions that matched a session query.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"sessionCount\">Passes back the number of matching sessions.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerQuerySessionsResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* sessionCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the results of a session query.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"sessionCount\">The number of sessions that matched the query.\n/// Use <see cref=\"XblMultiplayerQuerySessionsResultCount\"/> to get the count required.</param>\n/// <param name=\"sessions\">A caller allocated array to pass back the session query results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerQuerySessionsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t sessionCount,\n    _Out_writes_(sessionCount) XblMultiplayerSessionQueryResult* sessions\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the passed session as the user's current activity, which will be displayed in Xbox dashboard user experiences\n/// (e.g. friends and gamercard) as associated with the currently running title.  \n/// If the session is joinable, it may also be displayed as such in those user experiences.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"sessionReference\">An XblMultiplayerSessionReference for the session of the activity.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSetActivityAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Clears the user's current activity session for the specified serviceConfigurationId.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"scid\">The Service Configuration ID (SCID) in which to clear activity. The SCID is considered case sensitive so paste it directly from the Partner Center</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerClearActivityAsync(\n    _In_ XblContextHandle xblContext,\n    _In_z_ const char* scid,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// The access rights the caller has to the origin session are extended to the target session.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"targetSessionReference\">Target XblMultiplayerSessionReference for the session you want to extend the access rights for.</param>\n/// <param name=\"originSessionReference\">Origin XblMultiplayerSessionReference for the session that grants access to the target session.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// For example, in a title with a lobby session and a game session, the title could put a transfer handle \n/// linking the lobby to the game inside the lobby session.  \n/// Users invited to the lobby can use the handle to join the game session as well.  \n/// The transfer handle is deleted once the target session is deleted.\n/// </remarks>\nSTDAPI XblMultiplayerSetTransferHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionReference targetSessionReference,\n    _In_ XblMultiplayerSessionReference originSessionReference,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a XblMultiplayerSetTransferHandleAsync operation.  \n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handleId\">Passes back the multiplayer session handle ID.  \n/// This handle holds the unique ID for a MPSD transfer handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSetTransferHandleResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandleId* handleId\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Create a search handle associated with an existing session.  \n/// This makes the session queryable.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"sessionRef\">Session reference to create a search handle for.</param>\n/// <param name=\"tags\">Optional set of tags to attach to search handle.</param>\n/// <param name=\"tagsCount\">Count of tags.</param>\n/// <param name=\"numberAttributes\">Optional attributes to attach to search handle.</param>\n/// <param name=\"numberAttributesCount\">Count of number attributes.</param>\n/// <param name=\"stringAttributes\">Optional attributes to attach to search handle.</param>\n/// <param name=\"stringAttributesCount\">Count of string attributes.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerCreateSearchHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionReference* sessionRef,\n    _In_reads_opt_(tagsCount) const XblMultiplayerSessionTag* tags,\n    _In_ size_t tagsCount,\n    _In_reads_opt_(numberAttributesCount) const XblMultiplayerSessionNumberAttribute* numberAttributes,\n    _In_ size_t numberAttributesCount,\n    _In_reads_opt_(stringAttributesCount) const XblMultiplayerSessionStringAttribute* stringAttributes,\n    _In_ size_t stringAttributesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result from an XblMultiplayerCreateSearchHandleAsync.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handle\">Passes back a handle to the local search handle object.  \n/// If this parameter is null, the local search handle object will be freed immediately.  \n/// Note that this does not destroy the search handle on the MPSD service side, that must be done with XblMultiplayerDeleteSearchHandleAsync.  \n/// If this is non-null, the handle must later be closed with <see cref=\"XblMultiplayerSearchHandleCloseHandle\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerCreateSearchHandleResult(\n    _In_ XAsyncBlock* async,\n    _Out_opt_ XblMultiplayerSearchHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Delete a search handle from the MPSD service.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"handleId\">Id of the search handle to delete.  \n/// Obtained from either the search handle or session handle.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Note that this will not destroy local search handle objects; the lifetime of those objects is still managed by XblMultiplayerSearchHandleCloseHandle.  \n/// Once the search handle object is deleted from service, the associated session will no longer be searchable.\n/// </remarks>\nSTDAPI XblMultiplayerDeleteSearchHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* handleId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Search for sessions by their associated search handles.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"scid\">The Service Configuration ID (SCID) within which to query for search handles. The SCID is considered case sensitive so paste it directly from the Partner Center</param>\n/// <param name=\"sessionTemplateName\">The name of the template to query for search handles.</param>\n/// <param name=\"orderByAttribute\">This specifies the attribute to sort the search handles by. Pass empty string to default to ordering by 'Timestamp asc'.</param>\n/// <param name=\"orderAscending\">Pass true to order ascending, false to order descending.</param>\n/// <param name=\"searchFilter\">The query string to get the search handles for.</param>\n/// <param name=\"socialGroup\">The social group to get the search handles for.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// **Filtering search handles:**  \n/// \n/// The query syntax is an OData like syntax with only the following operators supported EQ, NE, GE, GT, LE and LT along with the logical operators of AND and OR.  \n/// \n///     Example 1:\n///     To filter for search handles for a specific XboxUserId use\n///         \"MemberXuids/any(d:d eq '12345678')\" or \"OwnerXuids/any(d:d eq '12345678')\"\n///     \n///     Example 2:\n///     To filter for search handles for a title defined string metadata use\n///         \"Strings/stringMetadataType eq 'value'\"\n///     \n///     Example 3:\n///     To filter for search handles for a title defined numbers metadata AND a tag type value use\n///         \"Numbers/numberMetadataType eq 53 AND Tags/tagType eq 'value'\"\n/// \n/// **Empty filter and social group:**\n/// \n/// Since searchFilter and socialGroup are optional, please make sure to pass in a nullptr if they aren't needed/used. Passing in an empty string \"\" will **not** work.\n/// </remarks>\nSTDAPI XblMultiplayerGetSearchHandlesAsync(\n    _In_ XblContextHandle xblContext,\n    _In_z_ const char* scid,\n    _In_z_ const char* sessionTemplateName,\n    _In_opt_z_ const char* orderByAttribute,\n    _In_ bool orderAscending,\n    _In_opt_z_ const char* searchFilter,\n    _In_opt_z_ const char* socialGroup,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the number of search handles returned from an XblMultiplayerGetSearchHandlesAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"searchHandleCount\">Passes back the number of search results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetSearchHandlesResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* searchHandleCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get handles to the local search handle objects returned from XblMultiplayerGetSearchHandlesAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"searchHandles\">A caller allocated array to pass back the search handle results.  \n/// Each handle must later be closed with <see cref=\"XblMultiplayerSearchHandleCloseHandle\"/>.</param>\n/// <param name=\"searchHandlesCount\">Size of search handles array.  \n/// Use <see cref=\"XblMultiplayerGetSearchHandlesResultCount\"/> to get the count required.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetSearchHandlesResult(\n    _In_ XAsyncBlock* async,\n    _Out_writes_(searchHandlesCount) XblMultiplayerSearchHandle* searchHandles,\n    _In_ size_t searchHandlesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A handle that corresponds to an outstanding invite that has been sent.\n/// </summary>\ntypedef struct XblMultiplayerInviteHandle\n{\n    /// <summary>\n    /// The outstanding invite GUID.\n    /// </summary>\n    _Null_terminated_ char Data[XBL_GUID_LENGTH];\n} XblMultiplayerInviteHandle;\n\n/// <summary>\n/// Invites the specified users to a session.  \n/// This will result in a notification being shown to each invited user using standard invite text.  \n/// If a user accepts that notification the title will be activated.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"sessionReference\">An XblMultiplayerSessionReference object representing the session the target users will be invited to.</param>\n/// <param name=\"xuids\">The list of xbox user IDs who will be invited.</param>\n/// <param name=\"xuidsCount\">Size of the xuids array.</param>\n/// <param name=\"titleId\">The ID of the title that the invited user will activate in order to join the session.</param>\n/// <param name=\"contextStringId\">The custom context string ID.  \n/// This string ID is defined during Xbox Live ingestion to identify the invitation text that is additional to the standard invitation text.  \n/// The ID string must be prefixed with \"///\".  \n/// Pass nullptr if you don't want a custom string added to the invite.</param>\n/// <param name=\"customActivationContext\">The activation context string. A game defined string that is passed to the invited game client and interpreted as desired. (Optional)</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSendInvitesAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_ uint32_t titleId,\n    _In_opt_z_ const char* contextStringId,\n    _In_opt_z_ const char* customActivationContext,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Invites the specified users to a session.  \n/// This will result in a notification being shown to each invited user using standard invite text.  \n/// If a user accepts that notification the title will be activated.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"handlesCount\">The number of handles in the handles array. Size should be equal to the number of invites requested.</param>\n/// <param name=\"handles\">A caller allocated array to pass back the invite handle results.\n/// The handle ID strings corresponding to the invites that have been sent.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerSendInvitesResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t handlesCount,\n    _Out_writes_(handlesCount) XblMultiplayerInviteHandle* handles\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// DEPRECATED - Call <see cref=\"XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync\"/>, which also \n/// populates `CustomSessionProperties` in the result.<br/>  \n/// Queries for the current activity for a social group of players associated with a particular \"owner\" player.  \n/// </summary>\n/// <param name=\"xboxLiveContext\">{% term xbox-live %} context for the local player.</param>\n/// <param name=\"scid\">The service configuration identifier (SCID) within which to query for activities. \n/// The SCID is case-sensitive, so paste it directly from Partner Center.</param>\n/// <param name=\"socialGroupOwnerXuid\">The player whose social group will be used for the query.</param>\n/// <param name=\"socialGroup\">The social group (such as \"people\" or \"favorites\") to use to get the list of users.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// No paging or continuation is available. The Multiplayer service limits the number of items returned to 100.\n/// </remarks>\nSTDAPI XblMultiplayerGetActivitiesForSocialGroupAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* scid,\n    _In_ uint64_t socialGroupOwnerXuid,\n    _In_ const char* socialGroup,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Queries for the current activity for a social group of players associated with a particular \"owner\" player.  \n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local player.</param>\n/// <param name=\"scid\">The service configuration identifier (SCID) within which to query for activities. \n/// The SCID is case-sensitive, so paste it directly from Partner Center.</param>\n/// <param name=\"socialGroupOwnerXuid\">The player whose social group will be used for the query.</param>\n/// <param name=\"socialGroup\">The social group (such as \"people\" or \"favorites\") to use to get the list of users.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// No paging or continuation is available. The Multiplayer service limits the number of items returned to 100.\n/// </remarks>\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* scid,\n    _In_ uint64_t socialGroupOwnerXuid,\n    _In_ const char* socialGroup,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the number of <see cref=\"XblMultiplayerActivityDetails\"/> objects returned.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"activityCount\">The number of activity objects returned.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesForSocialGroupResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* activityCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a call to <see cref=\"XblMultiplayerGetActivitiesForSocialGroupAsync\"/>.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"activityCount\">The number of activity objects returned.</param>\n/// <param name=\"activities\">A caller-allocated array for the activity objects returned.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t activityCount,\n    _Out_writes_(activityCount) XblMultiplayerActivityDetails* activities\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the size of <see cref=\"XblMultiplayerActivityDetails\"/> objects returned.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the multiplayer activity details.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a call to <see cref=\"XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync\"/>.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided `buffer`.</param>\n/// <param name=\"buffer\">A caller-allocated byte buffer to write results into.</param>\n/// <param name=\"ptrToBuffer\">Strongly typed pointer to `buffer`.\n/// Do not free; its lifecycle is tied to `buffer`.</param>\n/// <param name=\"ptrToBufferCount\">Number of entries in `buffer`.</param>\n/// <param name=\"bufferUsed\">Number of bytes actually written to `buffer`.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMultiplayerActivityDetails** ptrToBuffer,\n    _Out_ size_t* ptrToBufferCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// DEPRECATED - Call <see cref=\"XblMultiplayerGetActivitiesWithPropertiesForUsersAsync\"/>, which also \n/// populates `CustomSessionProperties` in the result.<br/>  \n/// Queries for the current activity for a set of players specified by Xbox user ID.  \n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"scid\">The service configuration identifier (SCID) within which to query for activities. \n/// The SCID is case-sensitive, so paste it directly from Partner Center.</param>\n/// <param name=\"xuids\">The list of Xbox user IDs to find activities for.</param>\n/// <param name=\"xuidsCount\">The size of the `xuids` array.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// No paging or continuation is available. The Multiplayer service limits the number of items returned to 100.\n/// </remarks>\nSTDAPI XblMultiplayerGetActivitiesForUsersAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* scid,\n    _In_reads_(xuidsCount) const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Queries for the current activity for a set of players specified by Xbox user ID.  \n/// </summary>\n/// <param name=\"xblContext\">{% term xbox-live %} context for the local user.</param>\n/// <param name=\"scid\">The service configuration identifier (SCID) within which to query for activities. \n/// The SCID is case-sensitive, so paste it directly from Partner Center.</param>\n/// <param name=\"xuids\">The list of Xbox user IDs to find activities for.</param>\n/// <param name=\"xuidsCount\">The size of the `xuids` array.</param>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// No paging or continuation is available. The Multiplayer service limits the number of items returned to 100.\n/// </remarks>\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* scid,\n    _In_reads_(xuidsCount) const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the number of <see cref=\"XblMultiplayerActivityDetails\"/> objects returned.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"activityCount\">The number of activity objects returned.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesForUsersResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* activityCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a call to <see cref=\"XblMultiplayerGetActivitiesForUsersAsync\"/>.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"activityCount\">The number of activity objects returned.</param>\n/// <param name=\"activities\">A caller-allocated array for the activity objects returned.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesForUsersResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t activityCount,\n    _Out_writes_(activityCount) XblMultiplayerActivityDetails* activities\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the size of <see cref=\"XblMultiplayerActivityDetails\"/> objects returned.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Returns the size in bytes required to store the result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the result of a call to <see cref=\"XblMultiplayerGetActivitiesWithPropertiesForUsersAsync\"/>.\n/// </summary>\n/// <param name=\"async\">The `XAsyncBlock` for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided `buffer`.</param>\n/// <param name=\"buffer\">A caller-allocated byte buffer to write results into.</param>\n/// <param name=\"ptrToBuffer\">Strongly typed pointer to `buffer`.\n/// Do not free; its lifecycle is tied to `buffer`.</param>\n/// <param name=\"ptrToBufferCount\">Number of entries in `buffer`.</param>\n/// <param name=\"bufferUsed\">Number of bytes actually written to `buffer`.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForUsersResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMultiplayerActivityDetails** ptrToBuffer,\n    _Out_ size_t* ptrToBufferCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Explicitly starts or stops the multiplayer service connectivity via RTA. Enabling the RTA subscription enables:\n/// 1. Callbacks when the local Users's sessions change, using the MultiplayerSession object. Handlers are added\n/// with <see cref=\"XblMultiplayerAddSessionChangedHandler\"/>.\n/// 2. Automatic removal of members from sessions when the RTA connection underlying this multiplayer subscription is broken.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"subscriptionsEnabled\">True to enable subscriptions and false to stop them.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This method immediately enables the RTA connection, but the in order to receive session changed callbacks, the session\n/// must be written again after enabling subscriptions.\n/// </remarks>\nSTDAPI XblMultiplayerSetSubscriptionsEnabled(\n    _In_ XblContextHandle xblContext,\n    _In_ bool subscriptionsEnabled\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates whether multiplayer subscriptions are currently enabled. Note that subscriptions can be enabled/disabled\n/// explicitly using <see cref=\"XblMultiplayerSetSubscriptionsEnabled\"/>, but they will also be enabled automatically\n/// if a session changed handler is added.\n/// </summary>\n/// <param name=\"xblHandle\">Xbox live context for the local user.</param>\n/// <returns>Returns true if enabled, false if not enabled.</returns>\nSTDAPI_(bool) XblMultiplayerSubscriptionsEnabled(\n    _In_ XblContextHandle xblHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A callback method to be called when a session changes.\n/// </summary>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <param name=\"args\">Arguments to be passed the handler.</param>\n/// <returns></returns>\ntypedef void CALLBACK XblMultiplayerSessionChangedHandler(\n    _In_opt_ void* context,\n    _In_ XblMultiplayerSessionChangeEventArgs args\n);\n\n/// <summary>\n/// Registers an event handler for notifications when a multiplayer session changes. If the RTA subscription has not\n/// been explicitly enabled with <see cref=\"XblMultiplayerSetSubscriptionsEnabled\" />, adding session changed handlers will\n/// enable it automatically. Use the returned XblFunctionContext to unregister the handler.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns>The function context token that was registered for the event.</returns>\nSTDAPI_(XblFunctionContext) XblMultiplayerAddSessionChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for multiplayer session change notifications.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerRemoveSessionChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A callback method to be called when a rta subscription is lost.\n/// </summary>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns></returns>\ntypedef void CALLBACK XblMultiplayerSessionSubscriptionLostHandler(\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for notifications when a multiplayer subscription is lost.  \n/// Use the returned XblFunctionContext to unregister the handler.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns>The function context token that was registered for the event.</returns>\nSTDAPI_(XblFunctionContext) XblMultiplayerAddSubscriptionLostHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionSubscriptionLostHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for multiplayer subscription lost notifications.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerRemoveSubscriptionLostHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A callback method to be called when the multiplayer connection id changes.\n/// </summary>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns></returns>\ntypedef void CALLBACK XblMultiplayerConnectionIdChangedHandler(\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for notifications when the multiplayer connection id changes.  \n/// Use the returned XblFunctionContext to unregister the handler.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context to be passed the handler.</param>\n/// <returns>The function context token that was registered for the event.</returns>\nSTDAPI_(XblFunctionContext) XblMultiplayerAddConnectionIdChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerConnectionIdChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for multiplayer connection id changed notifications.\n/// </summary>\n/// <param name=\"xblContext\">Xbox live context for the local user.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerRemoveConnectionIdChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/multiplayer_manager_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n    #error C++11 required\n#endif\n\n#pragma once\n\n#include \"multiplayer_c.h\"\n\nextern \"C\"\n{\n\n/// <summary>\n/// Defines values used to indicate who can join your lobby.\n/// </summary>\nenum class XblMultiplayerJoinability : uint32_t\n{\n    /// <summary>\n    /// Joinability not set or no lobby exists yet.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Default value. The lobby is joinable by users who are followed by an existing member of the session.\n    /// </summary>\n    JoinableByFriends,\n\n    /// <summary>\n    /// The lobby is joinable only via an invite.\n    /// </summary>\n    InviteOnly,\n\n    /// <summary>\n    /// This option will close the lobby only when a game is in progress.  \n    /// All other times, it will keep the lobby open for InviteOnly so invitees can join when no game is in progress.\n    /// </summary>\n    DisableWhileGameInProgress,\n\n    /// <summary>\n    /// This option will close the lobby immediately.\n    /// </summary>\n    Closed\n};\n\n/// <summary>\n/// Defines values used to indicate status for the matchmaking stages.\n/// </summary>\nenum class XblMultiplayerMatchStatus : uint32_t\n{\n    /// <summary>\n    /// Indicates no matchmaking search has been started.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Indicates that a match ticket was submitted for matchmaking.\n    /// </summary>\n    SubmittingMatchTicket,\n\n    /// <summary>\n    /// Indicates that matchmaking is still searching.\n    /// </summary>\n    Searching,\n\n    /// <summary>\n    /// Indicates that matchmaking search has found a match.\n    /// </summary>\n    Found,\n\n    /// <summary> \n    /// Joining initialization stage.  \n    /// Matchmaking creates the game session and adds users to it.  \n    /// The client has up to the joining timeout to join the session during this phase.\n    /// </summary>\n    Joining,\n\n    /// <summary> \n    /// Waiting for remote clients to join the game session.  \n    /// The client has up to the joining timeout to join the session during this phase.\n    /// </summary>\n    WaitingForRemoteClientsToJoin,\n\n    /// <summary>\n    /// Measuring initialization stage.  \n    /// Stage where QoS measurement happens.  \n    /// The client has up to the measurement timeout to upload qos measurements to the service during this phase.\n    /// </summary>\n    Measuring,\n\n    /// <summary>\n    /// Uploading QoS measurement results to the service.  \n    /// The client has up to the measurement timeout to upload qos measurements to the service during this phase.\n    /// </summary>\n    UploadingQosMeasurements,\n\n    /// <summary>\n    /// Waiting for remote clients to upload QoS measurement results to the service.  \n    /// The client has up to the measurement timeout to upload qos measurements to the service during this phase.\n    /// </summary>\n    WaitingForRemoteClientsToUploadQos,\n\n    /// <summary>\n    /// Evaluating initialization stage.  \n    /// If auto evaluate is true, then this stage is skipped.  \n    /// Otherwise the title will do its own evaluation.\n    /// </summary>\n    Evaluating,\n\n    /// <summary>\n    /// Match was found and QoS measurement was successful.\n    /// </summary>\n    Completed,\n\n    /// <summary>\n    /// If the match that was found was not successful and is resubmitting.\n    /// </summary>\n    Resubmitting,\n\n    /// <summary>\n    /// Indicates that matchmaking search has expired.\n    /// </summary>\n    Expired,\n\n    /// <summary>\n    /// Indicates that matchmaking is in the process of canceling the search.\n    /// </summary>\n    Canceling,\n\n    /// <summary>\n    /// Indicates that matchmaking search has been canceled.\n    /// </summary>\n    Canceled,\n\n    /// <summary>\n    /// Failed initialization stage.  \n    /// The initialization failed.\n    /// </summary>\n    Failed,\n};\n\n/// <summary>\n/// Defines values used to indicate event types for a multiplayer lobby or game.  \n/// The XblMultiplayerEventArgsHandle can be used to get additional information \n/// about the event depending on the event type.\n/// </summary>\nenum class XblMultiplayerEventType : uint32_t\n{\n    /// <summary>\n    /// Indicates the user was added.  \n    /// You can call XblMultiplayerEventArgsXuid to get the xuid of the added user.\n    /// </summary>\n    UserAdded,\n\n    /// <summary>\n    /// Indicates the user was removed.  \n    /// You can call XblMultiplayerEventArgsXuid to get the xuid of the added user.\n    /// </summary>\n    UserRemoved,\n\n    /// <summary>\n    /// Indicates a new member has joined the session.  \n    /// You can call XblMultiplayerEventArgsMembersCount, XblMultiplayerEventArgsMembers\n    /// to get the members who joined.\n    /// </summary>\n    MemberJoined,\n\n    /// <summary>\n    /// Indicates a member has left the session.  \n    /// You can call XblMultiplayerEventArgsMembersCount, XblMultiplayerEventArgsMembers\n    /// to get the members who left.\n    /// </summary>\n    MemberLeft,\n\n    /// <summary>\n    /// Indicates a member property has changed.  \n    /// You can call XblMultiplayerEventArgsMember, XblMultiplayerEventArgsPropertiesJson\n    /// to get the properties that changed and the member.\n    /// </summary>\n    MemberPropertyChanged,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerManagerLobbySessionSetLocalMemberProperties() or \n    /// XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties() operation has completed.  \n    /// Upon completion, the game can view the XblMultiplayerEvent::Result to see if the write succeeded.  \n    /// A game can write local member properties by calling the XblMultiplayerManagerLobbySessionSetLocalMemberProperties() operation.\n    /// </summary>\n    LocalMemberPropertyWriteCompleted,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress() operation has completed.  \n    /// Upon completion, the game can view the XblMultiplayerEvent::Result to see if the write succeeded.  \n    /// A game can write local member properties by calling the XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress() operation.\n    /// </summary>\n    LocalMemberConnectionAddressWriteCompleted,\n\n    /// <summary>\n    /// Indicates a session (lobby or game) property has changed.  \n    /// You can call XblMultiplayerEventArgsPropertiesJson for the changed properties.\n    /// </summary>\n    SessionPropertyChanged,\n\n    /// <summary>\n    /// Indicates that the set property operation has completed.  \n    /// Upon completion, the game can view the XblMultiplayerEvent::Result to see if the write succeeded.  \n    /// A game can write synchronized properties by calling the XblMultiplayerManagerLobbySessionSetProperties() or \n    /// XblMultiplayerManagerGameSessionSetProperties() operation.\n    /// </summary>\n    SessionPropertyWriteCompleted,\n\n    /// <summary>\n    /// Indicates that the set synchronized property operation has completed.  \n    /// Upon completion, the game can view the XblMultiplayerEvent::Result to see if the write succeeded.  \n    /// A game can write synchronized properties by calling the XblMultiplayerManagerGameSessionSetSynchronizedProperties() operation.\n    /// </summary>\n    SessionSynchronizedPropertyWriteCompleted,\n\n    /// <summary>\n    /// Indicates host has changed.  \n    /// You can call XblMultiplayerEventArgsMember for the new host.\n    /// </summary>\n    HostChanged,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerManagerLobbySessionSetSynchronizedHost() operation has completed.  \n    /// Upon completion, the game can view the XblMultiplayerEvent::Result to see if the write succeeded.  \n    /// A game can write synchronized host by calling the XblMultiplayerManagerLobbySessionSetSynchronizedHost() operation.\n    /// </summary>\n    SynchronizedHostWriteCompleted,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerJoinability value has changed.  \n    /// A game can change the state by calling the XblMultiplayerManagerSetJoinability() operation.\n    /// </summary>\n    JoinabilityStateChanged,\n\n    /// <summary>\n    /// Fired when a match has been found, and the client has joined the target game session.  \n    /// When this event occurs, title should provide QOS measurement results (via XblMultiplayerSessionCurrentUserSetQosMeasurements) \n    /// between itself and a list of remote clients.  \n    /// Note: If your title does not require QoS (based on the session template), this event will not be triggered.  \n    /// You can call XblMultiplayerEventArgsPerformQoSMeasurements for the measurements.\n    /// </summary>\n    PerformQosMeasurements,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerManagerFindMatch() operation has completed.  \n    /// You can call XblMultiplayerEventArgsFindMatchCompleted for more information.\n    /// </summary>\n    FindMatchCompleted,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerManagerJoinGame() operation has completed.  \n    /// Once the join succeeds, the member is now part of the game session, and can use \n    /// data in the session to connect to other game members.\n    /// </summary>\n    JoinGameCompleted,\n\n    /// <summary>\n    /// Indicates that the XblMultiplayerManagerLeaveGame() operation has completed.  \n    /// After receiving this event, the game session object will be set to null.  \n    /// You can join another game by calling XblMultiplayerManagerJoinGame() or XblMultiplayerManagerJoinGameFromLobby().\n    /// </summary>\n    LeaveGameCompleted,\n\n    /// <summary>\n    /// Indicates that the <see cref=\"XblMultiplayerManagerJoinLobby\"/> operation has completed.  \n    /// Once the join succeeds, the member is now part of the lobby session, \n    /// and can use data in the session to connect to other lobby members.  \n    /// You can call XblMultiplayerEventArgsXuid for the xuid.\n    /// </summary>\n    JoinLobbyCompleted,\n\n    /// <summary>\n    /// Fired when the title's connection to MPSD using the real-time activity service is lost.  \n    /// When this event occurs, the title should shut down the multiplayer.\n    /// </summary>\n    ClientDisconnectedFromMultiplayerService,\n\n    /// <summary>\n    /// Indicates that the invite API operation has been completed.\n    /// </summary>\n    /// <remarks>\n    /// On Xbox, receiving this event does not necessarily mean an invite has been sent successfully. \n    /// You will receive this event as long as the game invite UI flow was successfully invoked, \n    /// even if the user cancelled the UI flow without sending an invite, or the invite failed to submit to the service for various reasons. \n    /// </remarks>\n    InviteSent,\n\n    /// <summary>\n    /// Only applicable if you are using Xbox Live Tournaments.  \n    /// Triggered when the tournament's team registration state changes.  \n    /// You can call XblMultiplayerEventArgsTournamentRegistrationStateChanged for more information.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    TournamentRegistrationStateChanged,\n\n    /// <summary>\n    /// Only applicable if you are using Xbox Live Tournaments.  \n    /// Triggered when a new game has been scheduled.  \n    /// You can call XblMultiplayerEventArgsTournamentGameSessionReady for more information.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    TournamentGameSessionReady,\n\n    /// <summary>\n    /// Only applicable if you are using Xbox Live Tournaments.  \n    /// Triggered when arbitration is complete and game results have been written to the game session.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    ArbitrationComplete\n};\n\n/// <summary>\n/// Defines values used to indicate types for multiplayer sessions.\n/// </summary>\nenum class XblMultiplayerSessionType : uint32_t\n{\n    /// <summary>\n    /// The session type is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Indicates multiplayer lobby session.\n    /// </summary>\n    LobbySession,\n\n    /// <summary>\n    /// Indicates multiplayer game session.\n    /// </summary>\n    GameSession,\n\n    /// <summary>\n    /// Indicates multiplayer match session.\n    /// </summary>\n    MatchSession\n};\n\n\n/// <summary>\n/// Represents a reference to a member in a multiplayer game.\n/// </summary>\n/// <remarks>\n/// The member objects are created and owned by MultiplayerManager.  \n/// The fields of returned XblMultiplayerManagerMember objects are only valid until XblMultiplayerManagerDoWork is called again.\n/// </remarks>\ntypedef struct XblMultiplayerManagerMember\n{\n    /// <summary>\n    /// Id for the member.\n    /// </summary>\n    uint32_t MemberId;\n\n    /// <summary>\n    /// Only applicable if you are using Xbox Live Tournaments.  \n    /// Id of this members' team in a tournament.\n    /// DEPRECATED. It will be removed in a future release\n    /// </summary>\n    XBL_DEPRECATED _Field_z_ const char* TeamId;\n\n    /// <summary> \n    /// Only applicable if you are using Team rules with Smart Match.  \n    /// Initial team assignment suggested by Smart Match.\n    /// </summary> \n    _Field_z_ const char* InitialTeam;\n\n    /// <summary>\n    /// Xbox User ID of the member.\n    /// </summary>\n    uint64_t Xuid;\n\n    /// <summary>\n    /// The Gamertag of the member.  This is only to be used for debugging purposes as this gamertag may be out of date.  \n    /// It is recommended you use social manager's XblSocialManagerCreateSocialUserGroupFromList\n    /// or the profile APIs such as XblProfileGetUserProfileAsync to get this information.\n    /// </summary>\n    _Field_z_ const char* DebugGamertag;\n\n    /// <summary>\n    /// Indicates if this member is playing on the local device.\n    /// </summary>\n    bool IsLocal;\n\n    /// <summary>\n    /// Indicates if this member is part of the lobby.\n    /// </summary>\n    bool IsInLobby;\n\n    /// <summary>\n    /// Indicates if this member is part of the game.\n    /// </summary>\n    bool IsInGame;\n\n    /// <summary>\n    /// The status of this member.\n    /// </summary>\n    XblMultiplayerSessionMemberStatus Status;\n\n    /// <summary>\n    /// The address used for network connection.  \n    /// This can be used for secure socket connection.\n    /// </summary>\n    _Field_z_ const char* ConnectionAddress;\n\n    /// <summary>\n    /// JSON value that specify the custom properties of the member.\n    /// </summary>\n    _Field_z_ const char* PropertiesJson;\n\n    /// <summary>\n    /// Token that uniquely identifies a device. Used for setting host and QoS measurements.\n    /// </summary>\n    _Field_z_ const char* DeviceToken;\n} XblMultiplayerManagerMember;\n\n/// <summary>\n/// Determines whether two members are on the same device.\n/// </summary>\n/// <param name=\"first\">The first member.</param>\n/// <param name=\"second\">The second member.</param>\n/// <returns>Returns true if both members are on the same device, false if both members are not on the same device.</returns>\n/// <remarks>This function compares the device tokens of both members. If the device tokens match, both members are on the same device. \n/// For more information, see <see cref=\"XblDeviceToken\"/>.</remarks>\nSTDAPI_(bool) XblMultiplayerManagerMemberAreMembersOnSameDevice(\n    _In_ const XblMultiplayerManagerMember* first,\n    _In_ const XblMultiplayerManagerMember* second\n) XBL_NOEXCEPT;\n\n\n/// <summary>\n/// A handle to multiplayer event arguments that can be used to retrieve additional information for a multiplayer event, depending on the type of event.\n/// </summary>\n/// <memof><see cref=\"XblMultiplayerEvent\"/></memof>\n/// <argof><see cref=\"XblMultiplayerEventArgsXuid\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsMembersCount\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsMembers\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsMember\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsPropertiesJson\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsTournamentRegistrationStateChanged\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsTournamentGameSessionReady\"/></argof>\n/// <argof><see cref=\"XblMultiplayerEventArgsPerformQoSMeasurements\"/></argof>\ntypedef struct XblMultiplayerEventArgs* XblMultiplayerEventArgsHandle;\n\n/// <summary>\n/// A multiplayer event that is returned from <see cref=\"XblMultiplayerManagerDoWork\"/>.\n/// </summary>\ntypedef struct XblMultiplayerEvent\n{\n    /// <summary>\n    /// The error code indicating the result of the operation.\n    /// </summary>\n    HRESULT Result;\n\n    /// <summary>\n    /// Call-specific debug information if the API operation fails.  \n    /// The debug information is not localized; use only for debugging purposes.\n    /// </summary>\n    _Field_z_ const char* ErrorMessage;\n\n    /// <summary>\n    /// A pointer to the application-defined data passed into the initiating method.\n    /// </summary>\n    void* Context;\n\n    /// <summary>\n    /// The type of the event triggered.\n    /// </summary>\n    XblMultiplayerEventType EventType;\n\n    /// <summary>\n    /// A handle to the event arguments for the multiplayer event.\n    /// </summary>\n    XblMultiplayerEventArgsHandle EventArgsHandle;\n\n    /// <summary>\n    /// The multiplayer session type this event was triggered for.  \n    /// Depending upon the session type, you can then retrieve the latest lobby or game session.\n    /// </summary>\n    XblMultiplayerSessionType SessionType;\n} XblMultiplayerEvent;\n\n/// <summary>\n/// A connection address/device token pair to run QoS measurements on.\n/// </summary>\ntypedef struct XblMultiplayerConnectionAddressDeviceTokenPair\n{\n    /// <summary>\n    /// The connection address.\n    /// </summary>\n    _Field_z_ const char* connectionAddress;\n\n    /// <summary>\n    /// The connection device token.\n    /// </summary>\n    _Field_z_ XblDeviceToken deviceToken;\n} XblMultiplayerConnectionAddressDeviceTokenPair;\n\n/// <summary>\n/// Event arguments returned for `XblMultiplayerEventType::PerformQosMeasurements` events.\n/// </summary>\ntypedef struct XblMultiplayerPerformQoSMeasurementsArgs\n{\n    /// <summary>\n    /// An array of remote clients to perform QoS measurements on.\n    /// </summary>\n    const XblMultiplayerConnectionAddressDeviceTokenPair* remoteClients;\n\n    /// <summary>\n    /// The size of the `remoteClients` array.\n    /// </summary>\n    size_t remoteClientsSize;\n} XblMultiplayerPerformQoSMeasurementsArgs;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType::UserAdded`, `XblMultiplayerEventType::UserRemoved`,\n/// and `XblMultiplayerEventType::JoinLobbyCompleted` events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"xuid\">The applicable Xbox User ID, depending on the multiplayer event:\n/// <para>`XblMultiplayerEventType::UserAdded` - The Xbox User ID of the member that was added.</para>\n/// <para>`XblMultiplayerEventType::UserRemoved` - The Xbox User ID of the member that was removed.</para>\n/// <para>`XblMultiplayerEventType::JoinLobbyCompleted` - The Xbox User ID of the member that was invited.</para>\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call this function to get more information about multiplayer events returned by <see cref=\"XblMultiplayerManagerDoWork\"/> \n/// for which the `EventType` member of the <see cref=\"XblMultiplayerEvent\"/> for a multiplayer event is set to either \n/// `XblMultiplayerEventType::UserAdded`, `XblMultiplayerEventType::UserRemoved`, or `XblMultiplayerEventType::JoinLobbyCompleted`.\n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMember\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembers\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPerformQosMeasurements\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\n/// <seealso cref=\"XblMultiplayerManagerJoinLobby\"/>\nSTDAPI XblMultiplayerEventArgsXuid(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ uint64_t* xuid\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType::MemberJoined` and `XblMultiplayerEventType::MemberLeft` events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"memberCount\">The size of the `members` caller-allocated array for <see cref=\"XblMultiplayerEventArgsMembers\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call this function before you call the <see cref=\"XblMultiplayerEventArgsMembers\"/> function, to return \n/// the size of the array you must allocate for the `members` parameter of the <see cref=\"XblMultiplayerEventArgsMembers\"/> function. \n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMember\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembers\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPerformQosMeasurements\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsXuid\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\nSTDAPI XblMultiplayerEventArgsMembersCount(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ size_t* memberCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType::MemberJoined` and `XblMultiplayerEventType::MemberLeft` events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"membersCount\">The size of the `members` array.</param>\n/// <param name=\"members\">A caller-allocated array that passes back a list of members, depending on the multiplayer event:  \n/// <para>`XblMultiplayerEventType::MemberJoined` - A list of members that joined the game.</para>\n/// <para>`XblMultiplayerEventType::MemberLeft` - A list of members that left the game.</para>\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call the <see cref=\"XblMultiplayerEventArgsMembersCount\"/> function before you call this function, to return \n/// the size of the array you must allocate for the `members` parameter of this function.\n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMember\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPerformQosMeasurements\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsXuid\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\nSTDAPI XblMultiplayerEventArgsMembers(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _In_ size_t membersCount,\n    _Out_writes_(membersCount) XblMultiplayerManagerMember* members\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType::HostChanged` and `XblMultiplayerEventType::MemberPropertyChanged` events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"member\">The applicable member, depending on the multiplayer event:\n/// <para>`XblMultiplayerEventType::HostChanged` - The new host member. If an existing host leaves, there is no new host member to return \n/// in this parameter. In this case, this function returns `HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)`.</para>\n/// <para>`XblMultiplayerEventType::MemberPropertyChanged` - The member whose property changed.</para>\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call this function to get more information about multiplayer events returned by <see cref=\"XblMultiplayerManagerDoWork\"/> \n/// for which the `EventType` member of the <see cref=\"XblMultiplayerEvent\"/> for a multiplayer event is set to either \n/// `XblMultiplayerEventType::HostChanged` or `XblMultiplayerEventType::MemberPropertyChanged`.\n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembers\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPerformQosMeasurements\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsXuid\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\nSTDAPI XblMultiplayerEventArgsMember(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ XblMultiplayerManagerMember* member\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType::MemberPropertyChanged` \n/// and `XblMultiplayerEventType::SessionPropertyChanged` events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"properties\">A pointer to a JSON string, depending on the multiplayer event:\n/// <para>`XblMultiplayerEventType::MemberPropertyChanged` - The JSON string of the member property that changed.</para>\n/// <para>`XblMultiplayerEventType::SessionPropertyChanged` - The JSON string of the session property that changed.</para>\n/// <para>The memory for the pointer remains valid for the life of the `XblMultiplayerEventArgsHandle` object, until the handle is closed.</para>\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call this function to get more information about multiplayer events returned by <see cref=\"XblMultiplayerManagerDoWork\"/> \n/// for which the `EventType` member of the <see cref=\"XblMultiplayerEvent\"/> for a multiplayer event is set to either \n/// `XblMultiplayerEventType::MemberPropertyChanged` or `XblMultiplayerEventType::SessionPropertyChanged`.\n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMember\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembers\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPerformQosMeasurements\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsXuid\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\nSTDAPI XblMultiplayerEventArgsPropertiesJson(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ const char** properties\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType.FindMatchCompleted` multiplayer events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"matchStatus\">A caller-allocated structure that describes the current matchmaking status.</param>\n/// <param name=\"initializationFailureCause\">A caller-allocated structure that passes back the cause of why \n/// the initialization failed, or `XblMultiplayerMeasurementFailure::None` if there was no failure.   \n/// This value is set when transitioning out of the `XblMultiplayerMatchStatus::Joining` or \n/// `XblMultiplayerMatchStatus::Measuring` initialization stages, if this member doesn't pass the initializaton stage.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call this function to get more information about multiplayer events returned by <see cref=\"XblMultiplayerManagerDoWork\"/> \n/// for which the `EventType` member of the <see cref=\"XblMultiplayerEvent\"/> for a multiplayer event is set to \n/// `XblMultiplayerEventType.FindMatchCompleted`.\n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsMember\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembers\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPerformQosMeasurements\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsXuid\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\nSTDAPI XblMultiplayerEventArgsFindMatchCompleted(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_opt_ XblMultiplayerMatchStatus* matchStatus,\n    _Out_opt_ XblMultiplayerMeasurementFailure* initializationFailureCause\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for XblMultiplayerEventType::TournamentRegistrationStateChanged events.\n/// </summary>\n/// <param name=\"argsHandle\">The event args handle from the XblMultiplayerEvent.</param>\n/// <param name=\"registrationState\">A caller allocated struct that passes back the tournament team registration state.</param>\n/// <param name=\"registrationReason\">A caller allocated struct that passes back the tournament team registration reason for the certain registration states.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblMultiplayerEventArgsTournamentRegistrationStateChanged(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_opt_ XblTournamentRegistrationState* registrationState,\n    _Out_opt_ XblTournamentRegistrationReason* registrationReason\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for XblMultiplayerEventType::TournamentGameSessionReady events.\n/// </summary>\n/// <param name=\"argsHandle\">The event args handle from the XblMultiplayerEvent.</param>\n/// <param name=\"startTime\">Passes back the game's start time for the tournament.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblMultiplayerEventArgsTournamentGameSessionReady(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ time_t* startTime\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves additional information for `XblMultiplayerEventType::PerformQosMeasurements` events.\n/// </summary>\n/// <param name=\"argsHandle\">The event arguments handle for the multiplayer event.</param>\n/// <param name=\"performQoSMeasurementsArgs\">A caller-allocated structure that passes back the remote clients for which QoS information is needed.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>Call this function to get more information about multiplayer events returned by <see cref=\"XblMultiplayerManagerDoWork\"/> \n/// for which the `EventType` member of the <see cref=\"XblMultiplayerEvent\"/> for a multiplayer event is set to \n/// `XblMultiplayerEventType::PerformQosMeasurements`.\n/// <para>The event arguments handle for a multiplayer event can be retrieved from the `EventArgsHandle` member of \n/// the <see cref=\"XblMultiplayerEvent\"/> structure for that multiplayer event.</para>\n/// <para>For more information about multiplayer events, see \n/// <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.</para></remarks>\n/// <seealso cref=\"XblMultiplayerEventArgsFindMatchCompleted\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMember\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembers\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerEventArgsXuid\"/>\n/// <seealso cref=\"XblMultiplayerEventType\"/>\nSTDAPI XblMultiplayerEventArgsPerformQoSMeasurements(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ XblMultiplayerPerformQoSMeasurementsArgs* performQoSMeasurementsArgs\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Initializes Multiplayer Manager (MPM).\n/// </summary>\n/// <param name=\"lobbySessionTemplateName\">The name of the session template for the lobby session to be based on.</param>\n/// <param name=\"asyncQueue\">The task queue where all Multiplayer Manager work should be scheduled.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function initializes the lobby session with which Multiplayer Manager (MPM) interacts, based on a session template configured for the title. \n/// You must call this function before calling other MPM functions, otherwise errors may occur. For more information about \n/// configuring session templates, see <see href=\"live-configure-the-multiplayer-service.md\">Configuring the Multiplayer service</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerDoWork\"/>\nSTDAPI XblMultiplayerManagerInitialize(\n    _In_z_ const char* lobbySessionTemplateName,\n    _In_opt_ XTaskQueueHandle asyncQueue\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Maintains game state updates between the title and Multiplayer Manager (MPM).\n/// </summary>\n/// <param name=\"multiplayerEvents\">An array of multiplayer events for the game to handle. \n/// This is set to null if no multiplayer events occur during this update.</param>\n/// <param name=\"multiplayerEventsCount\">The size of the `multiplayerEvents` array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sends and receives game state updates between the title and Multiplayer Manager (MPM), returning an array \n/// of <see cref=\"XblMultiplayerEvent\"/> structures that represent significant multiplayer events, such as remote players \n/// joining or leaving. You must call this function on a regular and frequent basis, such as once per frame, so that MPM can \n/// properly maintain game state. For more information, see <see href=\"live-multiplayer-manager-overview.md\">Multiplayer Manager overview</see>.  \n/// <para>The multiplayer events returned by this function are owned by MPM, and remain valid only until `XblMultiplayerManagerDoWork` is called again. \n/// In addition, the title must be thread-safe when calling `XblMultiplayerManagerDoWork`, because game state changes at the time this function is called.\n/// For example, if you're iterating through the list of members on a thread other than the one from which you're calling this function,\n/// the list may change when this function is called.</para> \n/// </remarks>\nSTDAPI XblMultiplayerManagerDoWork(\n    _Deref_out_opt_ const XblMultiplayerEvent** multiplayerEvents,\n    _Out_ size_t* multiplayerEventsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the correlation handle for the lobby session. \n/// </summary>\n/// <param name=\"correlationId\">Passes back the correlation handle for the lobby session, \n/// or null if a lobby session doesn't exist. The memory for the returned pointer remains \n/// valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function retrieves the correlation handle for the lobby session in Multiplayer Manager (MPM). The correlation handle serves as \n/// an alias for the lobby session, allowing a game to refer to a lobby session by using only the correlation handle. \n/// The correlation handle can be used to query trace logs for entries that relate to the lobby session.\n/// For more information, see <see href=\"live-multiplayer-concepts.md\">Multiplayer concepts overview</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSessionReference\"/>\nSTDAPI XblMultiplayerManagerLobbySessionCorrelationId(\n    _Out_ XblGuid* correlationId\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the session reference for the lobby session.  \n/// </summary>\n/// <param name=\"sessionReference\">Passes back a pointer to the session reference for the lobby session, \n/// or null if a lobby session doesn't exist. The memory for the returned pointer remains valid until \n/// the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function retrieves a pointer to the session reference for the lobby session, if the lobby session exists in \n/// Multiplayer Manager. The session reference contains the service configuration ID (SCID),\n/// session template, and session name for the lobby session, and uniquely identifies \n/// the lobby session in Multiplayer Session Directory (MPSD). For more information about session references, see \n/// <see href=\"live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionCorrelationId\"/>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSessionReference\"/>\nSTDAPI XblMultiplayerManagerLobbySessionSessionReference(\n    _Out_ XblMultiplayerSessionReference* sessionReference\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the number of local members in the lobby session.  \n/// </summary>\n/// <returns>The number of members in the lobby session that are local to the device.</returns>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionLocalMembers\"/>\nSTDAPI_(size_t) XblMultiplayerManagerLobbySessionLocalMembersCount() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves member information for the local members in the lobby session.\n/// </summary>\n/// <param name=\"localMembersCount\">The size of the `localMembers` array.  \n/// The required size can be obtained by calling <see cref=\"XblMultiplayerManagerLobbySessionLocalMembersCount\"/>.</param>\n/// <param name=\"localMembers\">A caller-allocated <see cref=\"XblMultiplayerManagerMember\"/> array to write into.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function returns member information for each member in the lobby session that is local to the device.\n/// You can also call the <see cref=\"XblMultiplayerManagerLobbySessionMembers\"/> function to return member \n/// information for all members in the lobby session.\n/// <para>The member information returned by this function is valid only until <see cref=\"XblMultiplayerManagerDoWork\"/> is called again.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionMembersCount\"/>\nSTDAPI XblMultiplayerManagerLobbySessionLocalMembers(\n    _In_ size_t localMembersCount,\n    _Out_writes_(localMembersCount) XblMultiplayerManagerMember* localMembers\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the number of members in the lobby session.  \n/// </summary>\n/// <returns>The number of members that are in the lobby session.</returns>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionLocalMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionMembers\"/>\nSTDAPI_(size_t) XblMultiplayerManagerLobbySessionMembersCount() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves member information for the members in the lobby session.\n/// </summary>\n/// <param name=\"membersCount\">The size of the `members` array.  \n/// The required size can be obtained by calling <see cref=\"XblMultiplayerManagerLobbySessionMembersCount\"/>.</param>\n/// <param name=\"members\">A caller-allocated <see cref=\"XblMultiplayerManagerMember\"/> array to write into.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function returns member information for each member in the lobby session.\n/// You can also call the <see cref=\"XblMultiplayerManagerLobbySessionLocalMembers\"/> function to return member \n/// information for each member in the lobby session that is local to the device.\n/// <para>The member information returned by this function is valid only until <see cref=\"XblMultiplayerManagerDoWork\"/> is called again.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionLocalMembersCount\"/>\nSTDAPI XblMultiplayerManagerLobbySessionMembers(\n    _In_ size_t membersCount,\n    _Out_writes_(membersCount) XblMultiplayerManagerMember* members\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves member information for the host member in the lobby session.  \n/// </summary>\n/// <param name=\"hostMember\">A caller-allocated structure to be populated with member information for the host member.</param>\n/// <returns>HRESULT return code for this API operation.  \n/// Returns `__HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER)` if a host member doesn't exist.</returns>\n/// <remarks>\n/// This function retrieves member information about the member that represents the host for a lobby session.\n/// If a lobby session doesn't exist, or if a host member doesn't exist for the lobby session, the function \n/// returns `__HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER)`. The host member is defined as the user with the lowest\n/// index on the host device. \n/// <para>The information returned by this function is valid only until <see cref=\"XblMultiplayerManagerDoWork\"/> is called again.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionIsHost\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionLocalMembers\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionMembers\"/>\nSTDAPI XblMultiplayerManagerLobbySessionHost(\n    _Out_ XblMultiplayerManagerMember* hostMember\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the custom properties for the lobby session, as a JSON string.  \n/// </summary>\n/// <returns>A JSON string that specifies the custom properties for the lobby session, or null if a lobby session doesn't exist.  \n/// The memory for the returned pointer remains valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</returns>\n/// <remarks>\n/// This function retrieves the custom properties for the lobby session, represented as a JSON string. These custom properties \n/// can be changed at any time. If custom properties are shared between devices, or may be updated by several devices \n/// at the same time, use the <see cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedProperties\"/> function to change custom properties.\n/// Otherwise, you can use the <see cref=\"XblMultiplayerManagerLobbySessionSetProperties\"/> function to change custom properties.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionPropertiesJson\"/>\nSTDAPI_(const char*) XblMultiplayerManagerLobbySessionPropertiesJson() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the session constants associated with the lobby session.\n/// </summary>\n/// <returns>A pointer to the session constants for the lobby session, or null if a lobby session doesn't exist.  \n/// The memory for the returned pointer remains valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</returns>\n/// <remarks>\n/// This function retrieves a pointer to the session constants for a lobby session, if the lobby session exists \n/// in Multiplayer Manager. The session constants contain constants, such as session visibility \n/// and session capabilities, defined by the session template used for the lobby session. Unlike session properties, \n/// session constants can only be set through the session template, and are set at the time the lobby session is created.\n/// For more information about session constants, see <see href=\"concepts/live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSessionReference\"/>\nSTDAPI_(const XblMultiplayerSessionConstants*) XblMultiplayerManagerLobbySessionConstants() XBL_NOEXCEPT;\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\n/// <summary>\n/// The known last team result of the tournament.\n/// Only applicable if you are using Xbox Live Tournaments.\n/// </summary>\n/// <returns>A pointer to the team's result for the multiplayer game.  \n/// The pointer returned remains valid until the next call to XblMultiplayerManagerDoWork.</returns>\nSTDAPI_XBL_DEPRECATED_(const XblTournamentTeamResult*) XblMultiplayerManagerLobbySessionLastTournamentTeamResult() XBL_NOEXCEPT;\nXBL_WARNING_POP\n\n/// <summary>\n/// Joins an Xbox user to the lobby session.  \n/// </summary>\n/// <param name=\"user\">The user handle of the user joining the lobby session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function creates a new lobby session and adds the Xbox user specified in <paramref name=\"user\"/> to the session.\n/// Subsequent users are added to the newly-hosted lobby session as secondary users. You can send \n/// invites, set session properties, and access members of the lobby session only after the first \n/// local user is added to the lobby session. \n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::JoinLobbyCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// <para>When attempting to join a lobby session, the service returns `HTTP_E_STATUS_BAD_REQUEST` if the server is full.</para>\n/// <para>After joining, you can set the properties for the lobby session by calling  \n/// <see cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedProperties\"/>, or you can set the host for the lobby session by\n/// calling <see cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedHost\"/> if the lobby session doesn't already have a host.</para>\n/// <para>You can also send an invite to another user by calling either \n/// <see cref=\"XblMultiplayerManagerLobbySessionInviteUsers\"/> or <see cref=\"XblMultiplayerManagerLobbySessionInviteFriends\"/>.\n/// If you don't need a lobby session, and if you haven't added local users by calling this function, \n/// you can instead call <see cref=\"XblMultiplayerManagerJoinGame\"/> and specify the list of users to join the game.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinability\"/>\n/// <seealso cref=\"XblMultiplayerManagerJoinGameFromLobby\"/>\nSTDAPI XblMultiplayerManagerLobbySessionAddLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Removes the local user from both the lobby session and game session.  \n/// </summary>\n/// <param name=\"user\">The local user to be removed.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If there are no local users remaining after this function is called, the title cannot \n/// perform any further multiplayer operations. Changes are batched and written to the service \n/// when <see cref=\"XblMultiplayerManagerDoWork\"/> is called.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to \n/// `XblMultiplayerEventType::UserRemoved`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// <para>After leaving, you can join a different game by calling either <see cref=\"XblMultiplayerManagerJoinGame\"/> or\n/// <see cref=\"XblMultiplayerManagerJoinGameFromLobby\"/>, or you can re-add the \n/// local user by calling <see cref=\"XblMultiplayerManagerLobbySessionAddLocalUser\"/>.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinLobby\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionInviteFriends\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionInviteUsers\"/>\nSTDAPI XblMultiplayerManagerLobbySessionRemoveLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Set a custom property for a local member to the specified JSON string.\n/// </summary>\n/// <param name=\"user\">The user you want to set the property for.</param>\n/// <param name=\"name\">The name of the property to set.</param>\n/// <param name=\"valueJson\">Optional. The JSON value to assign to the property.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the value, represented as a JSON string, of a custom property for a local member in \n/// the lobby session. Custom properties can be changed at any time. Changes are batched and written to the \n/// service when <see cref=\"XblMultiplayerManagerDoWork\"/> is called.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set \n/// to `XblMultiplayerEventType::LocalMemberPropertyWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para> \n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSetSynchronizedHost\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\nSTDAPI XblMultiplayerManagerLobbySessionSetLocalMemberProperties(\n    _In_ XblUserHandle user,\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Deletes a custom property from a local member of the lobby session.\n/// </summary>\n/// <param name=\"user\">The user handle of the local member.</param>\n/// <param name=\"name\">The name of the custom property to delete.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function deletes a custom property from a local member of the lobby session. Custom properties \n/// can be changed at any time. Changes are batched and written to the service when <see cref=\"XblMultiplayerManagerDoWork\"/> is called.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to \n/// `XblMultiplayerEventType::LocalMemberPropertyWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetLocalMemberProperties\"/>\nSTDAPI XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(\n    _In_ XblUserHandle user,\n    _In_z_ const char* name,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the connection address for the local member.  \n/// </summary>\n/// <param name=\"user\">The user you want to set the property for.</param>\n/// <param name=\"connectionAddress\">The network connection address to set.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the network connection address of a local member in the lobby session. You can use \n/// the connection address for network and secure socket connections to that local member. Changes are batched \n/// and written to the service when <see cref=\"XblMultiplayerManagerDoWork\"/> is called.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set \n/// to `XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para> \n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetLocalMemberProperties\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\nSTDAPI XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n    _In_ XblUserHandle user,\n    _In_z_ const char* connectionAddress,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates whether the specified user is the host for the lobby session.\n/// </summary>\n/// <param name=\"xuid\">The Xbox User ID (XUID) of the user.</param>\n/// <returns>Returns true if the XUID is the host of the lobby session; otherwise, false.</returns>\n/// <remarks>\n/// This function returns false if a lobby session doesn't exist, or if \n/// the Xbox User ID (XUID) specified in `xuid` isn't the host for the lobby session. You can \n/// retrieve the host for a lobby session by calling <see cref=\"XblMultiplayerManagerLobbySessionHost\"/>.\n/// For more information, see <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedHost\"/>\nSTDAPI_(bool) XblMultiplayerManagerLobbySessionIsHost(\n    _In_ uint64_t xuid\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the value of a custom property for the lobby session.\n/// </summary>\n/// <param name=\"name\">The name of the custom property to set.</param>\n/// <param name=\"valueJson\">The value to assign to the property, as a JSON string.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the value, represented as a JSON string, of a custom property for the lobby session. Custom properties \n/// can be changed at any time. Changes are batched and written to the service when <see cref=\"XblMultiplayerManagerDoWork\"/> is called.\n/// If custom properties are shared between devices, or may be updated by several devices \n/// at the same time, use the <see cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedProperties\"/> function to change custom properties.\n/// Otherwise, you can use this function to change custom properties.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::SessionPropertyWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para> \n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedHost\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\nSTDAPI XblMultiplayerManagerLobbySessionSetProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the value of a custom property for the lobby session, using `XblMultiplayerSessionWriteMode::SynchronizedUpdate`.\n/// </summary>\n/// <param name=\"name\">The name of the custom property to set.</param>\n/// <param name=\"valueJson\">The value to assign to the property, as a JSON string.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the value, represented as a JSON string, of a custom property for the lobby session. Custom properties \n/// can be changed at any time. If custom properties are shared between devices, or may be updated by several devices \n/// at the same time, use this function to ensure atomicity and resolve any conflicts between devices while changing the values of those custom properties. \n/// If a custom property isn't shared across devices, use the <see cref=\"XblMultiplayerManagerLobbySessionSetProperties\"/> function instead \n/// to change the value of that custom property.\n/// <para>The service may reject the request to change the custom property if a race condition occurs due to a conflict.\n/// If the request is rejected, the service returns `HTTP_E_STATUS_PRECOND_FAILED`. If a conflict occurs, re-evaluate the need to \n/// change the custom property and, if needed, call this function again to re-submit the request.</para>\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para> \n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedHost\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\nSTDAPI XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the host for the lobby session, using `XblMultiplayerSessionWriteMode::SynchronizedUpdate`.\n/// </summary>\n/// <param name=\"deviceToken\">The device token of the host.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the host for the lobby session. Use this function to ensure atomicity and resolve any conflicts between devices \n/// trying to set the host at the same time. \n/// <para>The service may reject the request to set the host if a race condition occurs due to a conflict.\n/// If the request is rejected, the service returns `HTTP_E_STATUS_PRECOND_FAILED`. If a conflict occurs, re-evaluate the need to \n/// change the host and, if needed, call this function again to re-submit the request.</para>\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::SynchronizedHostWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// Note that host device tokens are generated from a session member's secure device address, so ensure that the secure device address is set for the \n/// desired host prior to calling this method.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedProperties\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress\"/>\nSTDAPI XblMultiplayerManagerLobbySessionSetSynchronizedHost(\n    _In_ const char* deviceToken,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n#if HC_PLATFORM_IS_MICROSOFT\n/// <summary>\n/// Displays the standard Xbox UI, allowing the user to select friends or recent players and invite them to the game.\n/// </summary>\n/// <param name=\"requestingUser\">The user who is sending the invite.</param>\n/// <param name=\"contextStringId\">Optional. The custom context string ID, a string that is defined \n/// during Xbox Live ingestion, to identify the custom invitation text \n/// that is added to the standard invitation text.  The ID string must be prefixed with \n/// three slash characters (\"///\").</param>\n/// <param name=\"customActivationContext\">Optional. The activation context string, a game-defined string \n/// that is passed to the invited game client and interpreted as desired by the game.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If this function is invoked, Multiplayer Manager sends invites to the selected players when the user \n/// confirms the player selection in the standard Xbox UI. If a selected player accepts the invite, the title is notified. \n/// For GDK-based games, the title is notified by invoking the callback function specified \n/// when the <see cref=\"XGameInviteRegisterForEvent\"/> function was invoked. \n/// For games based on other platforms, the title is activated.\n/// For more information, see <see href=\"live-invites-receive.md\">Receiving invites</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinLobby\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionAddLocalUser\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionInviteUsers\"/>\nSTDAPI XblMultiplayerManagerLobbySessionInviteFriends(\n    _In_ XblUserHandle requestingUser,\n    _In_opt_z_ const char* contextStringId,\n    _In_opt_z_ const char* customActivationContext\n) XBL_NOEXCEPT;\n#endif\n\n/// <summary>\n/// Invites the specified users to the game without displaying additional UI.  \n/// </summary>\n/// <param name=\"user\">The user who is sending the invite.</param>\n/// <param name=\"xuids\">The array of Xbox User IDs (XUIDs) to be invited.</param>\n/// <param name=\"xuidsCount\">The size of the `xuids` array.</param>\n/// <param name=\"contextStringId\">Optional. The custom context string ID, a string that is defined \n/// during Xbox Live ingestion, to identify the custom invitation text \n/// that is added to the standard invitation text.  The ID string must be prefixed with \n/// three slash characters (\"///\").</param>\n/// <param name=\"customActivationContext\">Optional. The activation context string, a game-defined string \n/// that is passed to the invited game client and interpreted as desired by the game.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Multiplayer Manager sends invites to the selected players when this function is invoked. If a selected \n/// player accepts the invite, the title is notified. \n/// For GDK-based games, the title is notified by invoking the callback function specified \n/// when the <see cref=\"XGameInviteRegisterForEvent\"/> function was invoked. \n/// For games based on other platforms, the title is activated. \n/// For more information, see <see href=\"live-invites-receive.md\">Receiving invites</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinLobby\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionAddLocalUser\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionInviteFriends\"/>\nSTDAPI XblMultiplayerManagerLobbySessionInviteUsers(\n    _In_ XblUserHandle user,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_opt_z_ const char* contextStringId,\n    _In_opt_z_ const char* customActivationContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates whether there is an active game session.\n/// </summary>\n/// <returns>Returns true if a game session exists for the lobby session in Multiplayer Manager; otherwise, false.</returns>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionCorrelationId\"/>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSessionReference\"/>\nSTDAPI_(bool) XblMultiplayerManagerGameSessionActive() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the correlation handle for the game session. \n/// </summary>\n/// <returns>The correlation handle for the game session, or null if a game session doesn't exist.  \n/// The memory for the returned pointer remains valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</returns>\n/// <remarks>\n/// This function retrieves the correlation handle for the game session. The correlation handle serves as \n/// an alias for the game session, allowing a game to refer to a game session by using only the correlation handle. \n/// The correlation handle can be used to query trace logs for entries that relate to the game session.\n/// For more information, see <see href=\"live-multiplayer-concepts.md\">Multiplayer concepts overview</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSessionReference\"/>\nSTDAPI_(const char*) XblMultiplayerManagerGameSessionCorrelationId() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the session reference for the game session.  \n/// </summary>\n/// <returns>A pointer to the session reference for the game session, or null if a game session doesn't exist.  \n/// The memory for the returned pointer remains valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</returns>\n/// <remarks>\n/// This function retrieves a pointer to the session reference for a game session, if the game session exists for \n/// the lobby session in Multiplayer Manager. The session reference contains the service configuration ID (SCID),\n/// session template, and session name for the game session, and uniquely identifies \n/// the game session in Multiplayer Session Directory (MPSD). For more information about session references, see \n/// <see href=\"concepts/live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionCorrelationId\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSessionReference\"/>\nSTDAPI_(const XblMultiplayerSessionReference*) XblMultiplayerManagerGameSessionSessionReference() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the number of members in the game session.  \n/// </summary>\n/// <returns>The number of members that are in the game session.</returns>\n/// <remarks>\n/// When a friend accepts a game invite, the corresponding member is added to the lobby and the game session members list. \n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionMembersCount\"/>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionMembers\"/>\nSTDAPI_(size_t) XblMultiplayerManagerGameSessionMembersCount() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves member information for the members in the game session.\n/// </summary>\n/// <param name=\"membersCount\">The size of the `members` array.  \n/// The required size can be obtained by calling <see cref=\"XblMultiplayerManagerGameSessionMembersCount\"/>.</param>\n/// <param name=\"members\">A caller-allocated <see cref=\"XblMultiplayerManagerMember\"/> array to write into.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function returns member information for each member in a game session.\n/// <para>The member information returned by this function is valid only until <see cref=\"XblMultiplayerManagerDoWork\"/> is called again.</para>\n/// </remarks>\nSTDAPI XblMultiplayerManagerGameSessionMembers(\n    _In_ size_t membersCount,\n    _Out_writes_(membersCount) XblMultiplayerManagerMember* members\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves member information for the host member in the game session.  \n/// </summary>\n/// <param name=\"hostMember\">A caller-allocated structure to be populated with member information for the host member.</param>\n/// <returns>HRESULT return code for this API operation.  \n/// Returns `__HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER)` if a host member doesn't exist.</returns>\n/// <remarks>\n/// This function retrieves member information about the member that represents the host for a game session.\n/// If a game session doesn't exist, or if a host member doesn't exist for the game session, the function \n/// returns `__HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER)`. The host member is defined as the user with the lowest\n/// index on the host device. \n/// <para>The information returned by this function is valid only until <see cref=\"XblMultiplayerManagerDoWork\"/> is called again.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionMembers\"/>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionIsHost\"/>\nSTDAPI XblMultiplayerManagerGameSessionHost(\n    _Out_ XblMultiplayerManagerMember* hostMember\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the custom properties for the game session, as a JSON string.  \n/// </summary>\n/// <returns>A JSON string that specifies the custom properties for the game session, or null if a game session doesn't exist.  \n/// The memory for the returned pointer remains valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</returns>\n/// <remarks>\n/// This function retrieves the custom properties for the game session, represented as a JSON string. These custom properties \n/// can be changed at any time. If custom properties are shared between devices, or may be updated by several devices \n/// at the same time, use the <see cref=\"XblMultiplayerManagerGameSessionSetSynchronizedProperties\"/> function to change custom properties.\n/// Otherwise, you can use the <see cref=\"XblMultiplayerManagerGameSessionSetProperties\"/> function to change custom properties.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionPropertiesJson\"/>\nSTDAPI_(const char*) XblMultiplayerManagerGameSessionPropertiesJson() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the session constants associated with the game session.\n/// </summary>\n/// <returns>A pointer to the session constants for the game session, or null if a game session doesn't exist.  \n/// The memory for the returned pointer remains valid until the next call to <see cref=\"XblMultiplayerManagerDoWork\"/>.</returns>\n/// <remarks>\n/// This function retrieves a pointer to the session constants for a game session, if the game session exists for \n/// the lobby session in Multiplayer Manager. The session constants contain constants, such as session visibility \n/// and session capabilities, defined by the session template used for the game session. Unlike session properties, \n/// session constants can only be set through the session template, and are set at the time the game session is created.\n/// For more information about session constants, see <see href=\"concepts/live-mpsd-details.md\">Multiplayer Session advanced topics</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionPropertiesJson\"/>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSessionReference\"/>\nSTDAPI_(const XblMultiplayerSessionConstants*) XblMultiplayerManagerGameSessionConstants() XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates whether the specified user is the host for the game session.\n/// </summary>\n/// <param name=\"xuid\">The Xbox User ID (XUID) of the user.</param>\n/// <returns>Returns true if the XUID is the host of the game session; otherwise, false.</returns>\n/// <remarks>\n/// This function returns false if a game session doesn't exist for the lobby session, or if \n/// the Xbox User ID (XUID) specified in `xuid` isn't the host for the game session. You can \n/// retrieve the host for a game session by calling <see cref=\"XblMultiplayerManagerGameSessionHost\"/>.\n/// For more information, see <see href=\"live-multiplayer-manager-api-overview.md\">Multiplayer Manager API overview</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSetSynchronizedHost\"/>\nSTDAPI_(bool) XblMultiplayerManagerGameSessionIsHost(\n    _In_ uint64_t xuid\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the value of a custom property for the game session.\n/// </summary>\n/// <param name=\"name\">The name of the custom property to set.</param>\n/// <param name=\"valueJson\">The value to assign to the property, as a JSON string.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the value, represented as a JSON string, of a custom property for the game session. Custom properties \n/// can be changed at any time. Changes are batched and written to the service when <see cref=\"XblMultiplayerManagerDoWork\"/> is called.\n/// If custom properties are shared between devices, or may be updated by several devices \n/// at the same time, use the <see cref=\"XblMultiplayerManagerGameSessionSetSynchronizedProperties\"/> function to change custom properties.\n/// Otherwise, you can use this function to change custom properties.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSetSynchronizedHost\"/>\nSTDAPI XblMultiplayerManagerGameSessionSetProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the value of a custom property for the game session, using `XblMultiplayerSessionWriteMode::SynchronizedUpdate`.\n/// </summary>\n/// <param name=\"name\">The name of the custom property to set.</param>\n/// <param name=\"valueJson\">The value to assign to the property, as a JSON string.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the value, represented as a JSON string, of a custom property for the game session. Custom properties \n/// can be changed at any time. If custom properties are shared between devices, or may be updated by several devices \n/// at the same time, use this function to ensure atomicity and resolve any conflicts between devices while changing the values of those custom properties. \n/// If a custom property isn't shared across devices, use the <see cref=\"XblMultiplayerManagerGameSessionSetProperties\"/> function instead \n/// to change the value of that custom property.\n/// <para>The service may reject the request to change the custom property if a race condition occurs due to a conflict.\n/// If the request is rejected, the service returns `HTTP_E_STATUS_PRECOND_FAILED`. If a conflict occurs, re-evaluate the need to \n/// change the custom property and, if needed, call this function again to re-submit the request.</para>\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para> \n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSetSynchronizedHost\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\nSTDAPI XblMultiplayerManagerGameSessionSetSynchronizedProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the host for the game session, using `XblMultiplayerSessionWriteMode::SynchronizedUpdate`.\n/// </summary>\n/// <param name=\"deviceToken\">The device token of the host.</param>\n/// <param name=\"context\">Optional. The application-defined data to correlate the <see cref=\"XblMultiplayerEvent\"/> to the initiating call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function sets the host for the game session. Use this function to ensure atomicity and resolve any conflicts between devices \n/// trying to set the host at the same time. \n/// <para>The service may reject the request to set the host if a race condition occurs due to a conflict.\n/// If the request is rejected, the service returns `HTTP_E_STATUS_PRECOND_FAILED`. If a conflict occurs, re-evaluate the need to \n/// change the host and, if needed, call this function again to re-submit the request.</para>\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::SynchronizedHostWriteCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// Note that host device tokens are generated from a session member's secure device address, so ensure that the secure device address is set for the \n/// desired host prior to calling this method.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerGameSessionSetSynchronizedProperties\"/>\n/// <seealso cref=\"XblMultiplayerEvent\"/>\n/// <seealso cref=\"XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress\"/>\nSTDAPI XblMultiplayerManagerGameSessionSetSynchronizedHost(\n    _In_ const char* deviceToken,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Joins an Xbox user to a lobby session.  \n/// </summary>\n/// <param name=\"handleId\">The activity handle for the lobby session.</param>\n/// <param name=\"user\">The user handle of the user joining the lobby session.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function joins the Xbox user specified in <em>user</em> to the lobby session specified in <em>handleId</em>. \n/// The activity handle for the lobby session is typically retrieved either from a game invite or from the `HandleId` value \n/// of another user's <see cref=\"XblMultiplayerActivityDetails\"/>, by calling <see cref=\"XblMultiplayerGetActivitiesForUsersAsync\"/>. \n/// For more information about multiplayer activities, see <see href=\"live-mpa-activities.md\">Activities</see>.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::JoinLobbyCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// <para>When attempting to join a lobby session, the service returns `HTTP_E_STATUS_BAD_REQUEST` if the server is full.</para>\n/// <para>After joining, you can set the properties for the lobby session by calling  \n/// <see cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedProperties\"/>, or you can set the host for the lobby session by\n/// calling <see cref=\"XblMultiplayerManagerLobbySessionSetSynchronizedHost\"/> if the lobby session doesn't already have a host.</para>\n/// <para>You can also send an invite to another user by calling either \n/// <see cref=\"XblMultiplayerManagerLobbySessionInviteUsers\"/> or <see cref=\"XblMultiplayerManagerLobbySessionInviteFriends\"/>.\n/// If you don't need a lobby session, and if you haven't added local users by calling <see cref=\"XblMultiplayerManagerLobbySessionAddLocalUser\"/>, \n/// you can instead call <see cref=\"XblMultiplayerManagerJoinGame\"/> and specify the list of users to join the game.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinability\"/>\n/// <seealso cref=\"XblMultiplayerManagerJoinGameFromLobby\"/>\nSTDAPI XblMultiplayerManagerJoinLobby(\n    _In_z_ const char* handleId,\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Creates a new game session for the lobby session, or joins an existing game session if one exists for the lobby session.\n/// </summary>\n/// <param name=\"sessionTemplateName\">The name of the session template for the game session to be based on.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function creates a new game session and adds the current members of the lobby session to the game session, \n/// if a game session doesn't already exist. If a new user joins the lobby session after a game session is already \n/// created, this function finds the existing game session in Multiplayer Session Directory (MPSD) by using a \n/// transfer handle in the lobby session, and then adds the new user to the game session using that transfer handle.\n/// For more information, see <see href=\"live-multiplayer-concepts.md\">Multiplayer concepts overview</see>.\n/// If a lobby session doesn't exist, likely because <see cref=\"XblMultiplayerManagerInitialize\"/> wasn't called before \n/// calling this function, an error occurs. An error also occurs if matchmaking is in progress. \n/// This function does not migrate existing lobby session properties to the game session.  \n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::JoinGameCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// <para>When attempting to join a lobby session, the service returns `HTTP_E_STATUS_BAD_REQUEST` if the server is full.</para>\n/// <para>After joining, you can set the properties for the game session by calling  \n/// <see cref=\"XblMultiplayerManagerGameSessionSetProperties\"/> or <see cref=\"XblMultiplayerManagerGameSessionSetSynchronizedProperties\"/>, \n/// or you can set the host for the game session by calling <see cref=\"XblMultiplayerManagerGameSessionSetSynchronizedHost\"/>.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinability\"/>\n/// <seealso cref=\"XblMultiplayerManagerJoinGame\"/>\n/// <seealso cref=\"XblMultiplayerManagerJoinLobby\"/>\nSTDAPI XblMultiplayerManagerJoinGameFromLobby(\n    _In_z_ const char* sessionTemplateName\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Joins a game session, using the globally unique session name.  \n/// </summary>\n/// <param name=\"sessionName\">The globally unique session name for the game session.</param>\n/// <param name=\"sessionTemplateName\">The name of the session template for the game session to be based on.</param>\n/// <param name=\"xuids\">An array of Xbox User IDs (XUIDs) that represents the users you want to be part of the game.</param>\n/// <param name=\"xuidsCount\">The number of elements in the array specified for `xuids`.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function joins a list of Xbox users, specified in `xuids`, to the game session identified by the globally \n/// unique session name specified in `sessionName.` You can get the globally unique session name from the results of the title's third-party matchmaking, \n/// and you should call this function for all clients that need to join the game.\n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::JoinGameCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// <para>When attempting to join a game session, the service returns `HTTP_E_STATUS_BAD_REQUEST` if the server is full.</para>\n/// <para>After joining, you can set the properties for the game session by calling  \n/// <see cref=\"XblMultiplayerManagerGameSessionSetProperties\"/> or <see cref=\"XblMultiplayerManagerGameSessionSetSynchronizedProperties\"/>, \n/// or you can set the host for the game session by calling <see cref=\"XblMultiplayerManagerGameSessionSetSynchronizedHost\"/>.</para>\n/// </remarks>\nSTDAPI XblMultiplayerManagerJoinGame(\n    _In_z_ const char* sessionName,\n    _In_z_ const char* sessionTemplateName,\n    _In_opt_ const uint64_t* xuids,\n    _In_ size_t xuidsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Leaves the game session, returning the Xbox user and all other local users to the lobby session.\n/// </summary>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function removes the Xbox user from the game session and returns the user back to the lobby session. The game session is set to null, \n/// and all local users are also removed from the game session and returned to the lobby session. Any matchmaking request in progress is \n/// canceled when this function is called.  \n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::LeaveGameCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// <para>After leaving, you can join a different game by calling either <see cref=\"XblMultiplayerManagerJoinGame\"/> or\n/// <see cref=\"XblMultiplayerManagerJoinGameFromLobby\"/>.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerJoinGame\"/>\n/// <seealso cref=\"XblMultiplayerManagerJoinLobby\"/>\nSTDAPI XblMultiplayerManagerLeaveGame() XBL_NOEXCEPT;\n\n/// <summary>\n/// Submits a matchmaking request to the server.\n/// </summary>\n/// <param name=\"hopperName\">The name of the hopper for this request.</param>\n/// <param name=\"attributesJson\">Optional. The attributes of the match ticket for this request, as a JSON string.</param>\n/// <param name=\"timeoutInSeconds\">The maximum time, in seconds, to wait for users to join the match.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This function submits a matchmaking request for the lobby session to Multiplayer Manager (MPM). Before you can use this function, \n/// you must first configure hoppers in the service configuration for your title. A hopper defines the rules that SmartMatch uses \n/// to match players. \n/// For more information about hoppers, see <see href=\"live-matchmaking-overview.md\">Matchmaking overview</see>.\n/// If a lobby session doesn't exist, likely because <see cref=\"XblMultiplayerManagerInitialize\"/> wasn't called, or if local users weren't added\n/// to the lobby session before calling this function, an error occurs. An error also occurs if matchmaking is already in progress. \n/// <para>The result of this function is delivered as a multiplayer event with an event type set to `XblMultiplayerEventType::FindMatchCompleted`. \n/// You can call <see cref=\"XblMultiplayerManagerDoWork\"/> to retrieve multiplayer events.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerEstimatedMatchWaitTime\"/>\nSTDAPI XblMultiplayerManagerFindMatch(\n    _In_z_ const char* hopperName,\n    _In_opt_z_ const char* attributesJson,\n    _In_ uint32_t timeoutInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Cancels the match request on the server, if one exists.\n/// </summary>\n/// <returns></returns>\n/// <remarks>\n/// This function cancels a previously submitted match ticket. This function is ignored if the status of the match ticket \n/// is set to `XblMultiplayerMatchStatus::None`, `XblMultiplayerMatchStatus::Expired`, `XblMultiplayerMatchStatus::Canceled`, or \n/// `XblMultiplayerMatchStatus::Failed`, or if a different host submitted the match ticket.\n/// <para>If this function is called, the status of the match ticket is set to `XblMultiplayerMatchStatus::Canceling` until \n/// the match ticket is canceled on the server.</para> \n/// <para>For more information about match tickets, see <see href=\"live-multiplayer-concepts.md\">Multiplayer concepts overview</see>.</para>\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerFindMatch\"/>\n/// <seealso cref=\"XblMultiplayerManagerMatchStatus\"/>\nSTDAPI_(void) XblMultiplayerManagerCancelMatch() XBL_NOEXCEPT;\n\n/// <summary>\n/// Provides the current status of matchmaking.\n/// </summary>\n/// <returns>The current status of matchmaking. 'XblMultiplayerMatchStatus::None' if no matchmaking is in progress.</returns>\nSTDAPI_(XblMultiplayerMatchStatus) XblMultiplayerManagerMatchStatus() XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the estimated wait time, in seconds, to complete a matchmaking request in progress.\n/// </summary>\n/// <returns>The estimated wait time, in seconds.</returns>\n/// <remarks>\n/// Call this function only after the <see cref=\"XblMultiplayerManagerFindMatch\"/> function has been called \n/// to submit a matchmaking request. The matchmaking request uses SmartMatch to find an existing game that has enough open \n/// player slots for all the members in the lobby session. If a matchmaking request isn't in progress, \n/// this function returns zero (0) seconds. For more information about finding a multiplayer game, \n/// see <see href=\"live-play-multiplayer-with-matchmaking.md\">Enable finding a multiplayer game by using SmartMatch using Multiplayer Manager</see>.\n/// </remarks>\n/// <seealso cref=\"XblMultiplayerManagerFindMatch\"/>\nSTDAPI_(uint32_t) XblMultiplayerManagerEstimatedMatchWaitTime() XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates whether the game should auto-fill open slots during gameplay.\n/// </summary>\n/// <returns>Returns true if the game should auto-fill open slots during gameplay; otherwise, false.</returns>\n/// <remarks>Call the <see cref=\"XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\"/> function to discover  \n/// whether the game should use matchmaking to auto-fill open slots during gameplay. You can also call \n/// the <see cref=\"XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\"/> function to specify whether the game \n/// should auto-fill open slots during gameplay. For more information about matchmaking, \n/// see <see href=\"live-matchmaking-overview.md\">Matchmaking overview</see>.</remarks>\nSTDAPI_(bool) XblMultiplayerManagerAutoFillMembersDuringMatchmaking() XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets if matchmaking should auto fill open slots during gameplay.  \n/// This can be changed anytime.\n/// </summary>\n/// <param name=\"autoFillMembers\">Set true, to search for members during matchmaking if the game has open slots.  \n/// Set false, to not allow auto fill.</param>\n/// <returns></returns>\nSTDAPI_(void) XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking(\n    _In_ bool autoFillMembers\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets json representing QoS measurements between the current user and a list of remote clients.  \n/// This is only used when the title is manually managing QoS.\n/// </summary>\n/// <param name=\"measurementsJson\">\n/// Json representing the QoS measurements.  \n/// Example Json:\n/// \"e69c43a8\": {               // remote client deviceToken\n///   \"latency\": 5953,          // Milliseconds\n///   \"bandwidthDown\" : 19342,  // Kilobits per second\n///   \"bandwidthUp\" : 944,      // Kilobits per second\n///   \"custom\" : { }\n/// },\n/// ...                         // additional remote client entries\n/// </param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblMultiplayerManagerSetQosMeasurements(\n    _In_z_ const char* measurementsJson\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates which users can join your lobby session.\n/// </summary>\n/// <returns>The joinability setting for your lobby session.</returns>\nSTDAPI_(XblMultiplayerJoinability) XblMultiplayerManagerJoinability() XBL_NOEXCEPT;\n\n/// <summary>\n/// Restricts who can join the game.\n/// </summary>\n/// <param name=\"joinability\">The joinability value you want to set.</param>\n/// <param name=\"context\">The application-defined data to correlate the XblMultiplayerEvent to the initiating call. (Optional)</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Defaults to JoinableByFriends, meaning only local users and users who are followed \n/// by an existing member of the lobby can join without an invite.  \n/// The result is delivered via XblMultiplayerEvent of type JoinabilityStateChanged\n/// through XblMultiplayerManagerDoWork().  \n/// Changes are batched and written to the service on the next XblMultiplayerManagerDoWork.  \n/// All session properties and members contain updated response returned from the server upon \n/// calling XblMultiplayerManagerDoWork.\n/// </remarks>\nSTDAPI XblMultiplayerManagerSetJoinability(\n    _In_ XblMultiplayerJoinability joinability,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/notification_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\nextern \"C\"\n{\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\n/// <summary>\n/// Sets the device/registration token received from GNS or APNS and subscribes the title to push notifications.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"asyncBlock\">Caller allocated AsyncBlock.</param>\n/// <param name=\"deviceToken\">The device/registration token received from GNS/APNS</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblNotificationSubscribeToNotificationsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ const char* deviceToken\n) XBL_NOEXCEPT;\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_UWP\n/// <summary>\n/// Unsubscribes the title from push notifications.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"asyncBlock\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblNotificationUnsubscribeFromNotificationsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n#endif\n}"
  },
  {
    "path": "Include/xsapi-c/pal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n    #error C++11 required\n#endif\n\n#pragma once\n\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning(disable: 4062)\n#endif\n\n#include \"httpClient/pal.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    #include <grdk.h>\n    #if !(_GRDK_YY == 19 && _GRDK_MM_NUM == 5) // GPEA GDK doesn't have XGameEventWrite API\n        #define XSAPI_BUILD_WITH_1910_GRTS 1\n    #endif\n#endif\n\n// Events/Notifications services\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || defined(XSAPI_UNIT_TESTS))\n    #ifndef XSAPI_EVENTS_SERVICE\n        #define XSAPI_EVENTS_SERVICE 1\n    #endif\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_GDK && XSAPI_BUILD_WITH_1910_GRTS\n    #ifndef XSAPI_GRTS_EVENTS_SERVICE\n        #define XSAPI_GRTS_EVENTS_SERVICE 1\n    #endif\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT && HC_PLATFORM != HC_PLATFORM_WIN32 && !XSAPI_BUILD_WITH_1910_GRTS\n    #ifndef XSAPI_WRL_EVENTS_SERVICE\n        #define XSAPI_WRL_EVENTS_SERVICE 1\n    #endif\n#endif\n\n#if !defined(XSAPI_GRTS_EVENTS_SERVICE) && !defined(XSAPI_WRL_EVENTS_SERVICE)\n    #ifndef XSAPI_INTERNAL_EVENTS_SERVICE\n        #define XSAPI_INTERNAL_EVENTS_SERVICE 1\n    #endif\n#endif\n\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_GDK || defined(XSAPI_UNIT_TESTS))\n    #ifndef XSAPI_NOTIFICATION_SERVICE\n        #define XSAPI_NOTIFICATION_SERVICE 1\n    #endif\n#endif\n\n// WinRT APIs\n#ifdef XSAPI_UNIT_TESTS\n    #define XSAPI_WINRT 1\n#endif\n\nextern \"C\"\n{\n\n#if HC_PLATFORM_IS_MICROSOFT\n    #ifndef _WIN32_WINNT_WIN10\n    #define _WIN32_WINNT_WIN10 0x0A00\n    #endif\n#endif\n\n#if !HC_PLATFORM_IS_MICROSOFT\n    #ifdef _In_\n    #undef _In_\n    #endif\n    #define _In_\n\n    #ifdef _Ret_maybenull_\n    #undef _Ret_maybenull_\n    #endif\n    #define _Ret_maybenull_\n\n    #ifdef _Post_writable_byte_size_\n    #undef _Post_writable_byte_size_\n    #endif\n    #define _Post_writable_byte_size_(X)\n\n    #ifdef _Outptr_result_maybenull_\n    #undef _Outptr_result_maybenull_\n    #endif\n    #define _Outptr_result_maybenull_\n\n    #ifndef ANYSIZE_ARRAY\n    #define ANYSIZE_ARRAY 1\n    #endif\n\n    #ifndef FIELD_OFFSET\n    #define FIELD_OFFSET(type, field)    ((long)(long)&(((type *)0)->field))\n    #endif\n\n    #ifndef UNREFERENCED_PARAMETER\n    #define UNREFERENCED_PARAMETER(P)   (P)\n    #endif\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT\n    #if _MSC_VER >= 1900\n        #define XBL_DEPRECATED __declspec(deprecated)\n    #else\n        #define XBL_DEPRECATED\n    #endif\n    #define STDAPI_XBL_DEPRECATED           EXTERN_C XBL_DEPRECATED HRESULT STDAPICALLTYPE\n    #define STDAPI_XBL_DEPRECATED_(type)    EXTERN_C XBL_DEPRECATED type STDAPICALLTYPE\n\n    #define XBL_WARNING_PUSH __pragma(warning(push))\n    #define XBL_WARNING_DISABLE_DEPRECATED __pragma(warning(disable:4996))\n    #define XBL_WARNING_POP __pragma(warning(pop))\n#else\n    #define XBL_DEPRECATED\n    #define STDAPI_XBL_DEPRECATED           EXTERN_C XBL_DEPRECATED HRESULT STDAPIVCALLTYPE\n    #define STDAPI_XBL_DEPRECATED_(type)    EXTERN_C XBL_DEPRECATED type STDAPIVCALLTYPE\n\n    #define XBL_WARNING_PUSH\n    #define XBL_WARNING_DISABLE_DEPRECATED\n    #define XBL_WARNING_POP\n#endif\n\n#ifndef _T\n    #if HC_PLATFORM_IS_MICROSOFT\n        #define _T(x) L ## x\n    #else\n        #define _T(x) x\n    #endif\n#endif\n\n#ifndef XBL_CALLING_CONV\n    #define XBL_CALLING_CONV __cdecl\n#endif\n\n#ifdef __cplusplus\n#define XBL_NOEXCEPT noexcept\n#else\n#define XBL_NOEXCEPT\n#endif\n\n} // end extern \"C\"\n"
  },
  {
    "path": "Include/xsapi-c/platform_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Handle to an operation XSAPI requested the client to perform.\n/// </summary>\ntypedef struct XblClientOperation* XblClientOperationHandle;\n\n/// <summary>\n/// Enum defining the results of a client operation.\n/// </summary>\nenum class XblClientOperationResult : uint32_t\n{\n    /// <summary>\n    /// Client completed the requested operation sucessfully.\n    /// </summary>\n    Success,\n\n    /// <summary>\n    /// Client was not able to complete the requested operation for any reason.\n    /// </summary>\n    Failure\n};\n\n//-----------------------------------------------------------------------------\n// Types related to custom storage hooks. Local storage is needed on Win32,\n// iOS, and Android platforms but default implementations are provided.\n\n/// <summary>\n/// Write mode for a local storage write operation.\n/// </summary>\nenum class XblLocalStorageWriteMode : uint32_t\n{\n    /// <summary>\n    /// Appends new data to the end of any existing data.\n    /// </summary>\n    Append,\n\n    /// <summary>\n    /// Overwrite any existing data.\n    /// </summary>\n    Truncate\n};\n\n/// <summary>\n/// Invoked by XSAPI to request the client to perform a local storage write operation.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"user\">The user for which the data is being written.</param>\n/// <param name=\"mode\">The mode to be used for the write operation.</param>\n/// <param name=\"key\">Identifies the data being written.</param>\n/// <param name=\"dataSize\">The size (in bytes) of the data.</param>\n/// <param name=\"data\">The data to write.</param>\n/// <returns></returns>\n/// <remarks>\n/// When the operation is complete, XblLocalStorageWriteComplete should be called.  \n/// Apart from context, all parameters are owned by XSAPI and are guaranteed to be valid\n/// until the operation is complete.\n/// </remarks>\ntypedef void (*XblLocalStorageWriteHandler)(\n    _In_opt_ void* context,\n    _In_ XblClientOperationHandle operation,\n    _In_ XblUserHandle user,\n    _In_ XblLocalStorageWriteMode mode,\n    _In_z_ char const* key,\n    _In_ size_t dataSize,\n    _In_reads_bytes_(dataSize) void const* data\n);\n\n/// <summary>\n/// Invoked by XSAPI to request the client to perform a local storage read operation.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"user\">The user for which XSAPI is requesting the read.</param>\n/// <param name=\"key\">Identifies the data being read.</param>\n/// <returns></returns>\n/// <remarks>\n/// When the operation is complete, XblLocalStorageReadComplete should be called.  \n/// Apart from context, all parameters are owned by XSAPI and are guaranteed to be valid\n/// until the operation is complete.  \n/// If the requested key is not found, the client should complete with \n/// XblClientOperationResult::Success and no data.\n/// </remarks>\ntypedef void (*XblLocalStorageReadHandler)(\n    _In_opt_ void* context,\n    _In_ XblClientOperationHandle operation,\n    _In_ XblUserHandle user,\n    _In_z_ const char* key\n);\n\n/// <summary>\n/// Invoked by XSAPI to request the client to perform a local storage clear operation.\n/// </summary>\n/// <param name=\"context\">Optional pointer to data used by the event handler.</param>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"user\">The user for which XSAPI is requesting the clear.</param>\n/// <param name=\"key\">Identifies the data being read.</param>\n/// <returns></returns>\n/// <remarks>\n/// When the operation is complete, XblLocalStorageClearComplete should be called.  \n/// Apart from context, all parameters are owned by XSAPI and are guaranteed to be valid\n/// until the operation is complete.\n/// </remarks>\ntypedef void (*XblLocalStorageClearHandler)(\n    _In_opt_ void* context,\n    _In_ XblClientOperationHandle operation,\n    _In_ XblUserHandle user,\n    _In_z_ const char* key\n);\n\n#ifdef XSAPI_INTERNAL_EVENTS_SERVICE\n\n/// <summary>\n/// Completes a local storage write operation.\n/// <see cref=\"XblLocalStorageWriteHandler\"/>\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <param name=\"dataSize\">The new size (in bytes) of the data associated with the requested key.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Should only be called by clients after completing (or failing to complete) a requested write operation.\n/// </remarks>\nSTDAPI XblLocalStorageWriteComplete(\n    _In_ XblClientOperationHandle operation,\n    _In_ XblClientOperationResult result,\n    _In_ size_t dataSize\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Completes a local storage read operation.\n/// <see cref=\"XblLocalStorageReadHandler\"/>\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <param name=\"dataSize\">The size (in bytes) of the data.</param>\n/// <param name=\"data\">The data read.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Should only be called by clients after completing (or failing to complete) a requested read operation.  \n/// If the requested key cannot be found, the operation should be completed with \n/// XblClientOperationResult::Success and dataSize of 0.\n/// </remarks>\nSTDAPI XblLocalStorageReadComplete(\n    _In_ XblClientOperationHandle operation,\n    _In_ XblClientOperationResult result,\n    _In_ size_t dataSize,\n    _In_reads_bytes_opt_(dataSize) void const* data\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Completes a local storage clear operation.\n/// <see cref=\"XblLocalStorageClearHandler\"/>\n/// </summary>\n/// <param name=\"operation\">The handle for this operation.</param>\n/// <param name=\"result\">The result of the operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Should only be called by clients after completing (or failing to complete) a requested clear operation.  \n/// If the requested key cannot be found, the operation should be completed with XblClientOperationResult::Success.\n/// </remarks>\nSTDAPI XblLocalStorageClearComplete(\n    _In_ XblClientOperationHandle operation,\n    _In_ XblClientOperationResult result\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the storage handlers.\n/// </summary>\n/// <param name=\"queue\">The async queue the callbacks should be invoked on.</param>\n/// <param name=\"writeHandler\">Handler to be invoked when XSAPI needs to write to local storage.</param>\n/// <param name=\"readHandler\">Handler to be invoked when XSAPI needs to read from local storage.</param>\n/// <param name=\"clearHandler\">Handler to be invoked when XSAPI needs to clear local storage.</param>\n/// <param name=\"context\">Client context to be passed back to the handlers.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Must be called before XblInitialize and all three handlers must be set together.\n/// </remarks>\nSTDAPI XblLocalStorageSetHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XblLocalStorageWriteHandler writeHandler,\n    _In_ XblLocalStorageReadHandler readHandler,\n    _In_ XblLocalStorageClearHandler clearHandler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n#endif\n\n}"
  },
  {
    "path": "Include/xsapi-c/presence_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\n#include \"real_time_activity_c.h\"\n\nextern \"C\"\n{\n\n/// <summary>\n/// Defines values used to indicate the device type associate with an XblSocialManagerPresenceTitleRecord.\n/// </summary>\n/// <memof><see cref=\"XblPresenceDeviceRecord\"/></memof>\n/// <memof><see cref=\"XblPresenceQueryFilters\"/></memof>\n/// <argof><see cref=\"XblPresenceDevicePresenceChangedHandler\"/></argof>\nenum class XblPresenceDeviceType : uint32_t\n{\n    /// <summary>\n    /// Unknown device.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Windows Phone device.\n    /// </summary>\n    WindowsPhone,\n\n    /// <summary>\n    /// Windows Phone 7 device.\n    /// </summary>\n    WindowsPhone7,\n\n    /// <summary>\n    /// Web device, like Xbox.com.\n    /// </summary>\n    Web,\n\n    /// <summary>\n    /// Xbox360 device.\n    /// </summary>\n    Xbox360,\n\n    /// <summary>\n    /// PC Games for Windows Live.\n    /// </summary>\n    PC,\n\n    /// <summary>\n    /// Xbox Live for Windows device.\n    /// </summary>\n    Windows8,\n\n    /// <summary>\n    /// Xbox One device.\n    /// </summary>\n    XboxOne,\n\n    /// <summary>\n    /// Windows One Core devices.\n    /// </summary>\n    WindowsOneCore,\n\n    /// <summary>\n    /// Windows One Core Mobile devices.\n    /// </summary>\n    WindowsOneCoreMobile,\n\n    /// <summary>\n    /// iOS device.\n    /// </summary>\n    iOS,\n\n    /// <summary>\n    /// Android device.\n    /// </summary>\n    Android,\n\n    /// <summary>\n    /// AppleTV device.\n    /// </summary>\n    AppleTV,\n\n    /// <summary>\n    /// Nintendo device.\n    /// </summary>\n    Nintendo,\n\n    /// <summary>\n    /// PlayStation device.\n    /// </summary>\n    PlayStation,\n\n    /// <summary>\n    /// Win32 based device.\n    /// </summary>\n    Win32,\n\n    /// <summary>\n    /// Scarlett device.\n    /// </summary>\n    Scarlett\n};\n\n/// <summary>\n/// Defines values used to indicate the state of the user with regard to the presence service.\n/// </summary>\n/// <argof><see cref=\"XblPresenceRecordGetUserState\"/></argof>\nenum class XblPresenceUserState : uint32_t\n{\n    /// <summary>\n    /// The state is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// User is signed in to Xbox Live and active in a title.\n    /// </summary>\n    Online,\n\n    /// <summary>\n    /// User is signed-in to Xbox Live, but inactive in all titles.\n    /// </summary>\n    Away,\n\n    /// <summary>\n    /// User is not signed in to Xbox Live.\n    /// </summary>\n    Offline\n};\n\n/// <summary>\n/// Defines values used to indicate the states of the screen view of presence information.\n/// </summary>\n/// <memof><see cref=\"XblPresenceTitleRecord\"/></memof>\nenum class XblPresenceTitleViewState : uint32_t\n{\n    /// <summary>\n    /// Unknown view state.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// The title's view is using the full screen.\n    /// </summary>\n    FullScreen,\n\n    /// <summary>\n    /// The title's view is using part of the screen with another application snapped.\n    /// </summary>\n    Filled,\n\n    /// <summary>\n    /// The title's view is snapped with another application using a part of the screen.\n    /// </summary>\n    Snapped,\n\n    /// <summary>\n    /// The title's running in the background and is not visible.\n    /// </summary>\n    Background\n};\n\n/// <summary>\n/// Defines values used to set the level of presence detail return from the service.  \n/// Choosing proper detail level could help the performance of the API.\n/// </summary>\n/// <memof><see cref=\"XblPresenceQueryFilters\"/></memof>\nenum class XblPresenceDetailLevel : uint32_t\n{\n    /// <summary>\n    /// Default detail level.\n    /// </summary>\n    Default,\n\n    /// <summary>\n    /// User detail level. User presence info only, no device, title or rich presence info.\n    /// </summary>\n    User,\n\n    /// <summary>\n    /// Device detail level. User and device presence info only, no title or rich presence info.\n    /// </summary>\n    Device,\n\n    /// <summary>\n    /// Title detail level. User, device and title presence info only, no rich presence info.\n    /// </summary>\n    Title,\n\n    /// <summary>\n    /// All detail possible. User, device, title and rich presence info will be provided.\n    /// </summary>\n    All\n};\n\n/// <summary>\n/// Defines values used to indicate the media id types for media presence data.\n/// </summary>\nenum class XblPresenceMediaIdType : uint32_t\n{\n    /// <summary>\n    /// Unknown media Id.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Bing media Id.\n    /// </summary>\n    Bing,\n\n    /// <summary>\n    /// MediaProvider media Id.\n    /// </summary>\n    MediaProvider\n};\n\n/// <summary>\n/// Defines values used to indicate the title presence state for a user.\n/// </summary>\n/// <argof><see cref=\"XblPresenceTitlePresenceChangedHandler\"/></argof>\nenum class XblPresenceTitleState : uint32_t\n{\n    /// <summary>\n    /// Indicates this is a Unknown state.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Indicates the user started playing the title.\n    /// </summary>\n    Started,\n\n    /// <summary>\n    /// Indicates the user ended playing the title.\n    /// </summary>\n    Ended\n};\n\n/// <summary>\n/// Defines values representing the streaming provider.\n/// </summary>\n/// <memof><see cref=\"XblPresenceBroadcastRecord\"/></memof>\nenum class XblPresenceBroadcastProvider : uint32_t\n{\n    /// <summary>\n    /// Unknown streaming provider.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Streaming using Twitch.\n    /// </summary>\n    Twitch\n};\n\n/// <summary>\n/// The handle to an xbl presence record.\n/// </summary>\ntypedef struct XblPresenceRecord* XblPresenceRecordHandle;\n\n/// <summary>\n/// Defines values representing the xbl presence device record.\n/// </summary>\n/// <argof><see cref=\"XblPresenceRecordGetDeviceRecords\"/></argof>\ntypedef struct XblPresenceDeviceRecord\n{\n    /// <summary>\n    /// The device type associated with this record.\n    /// </summary>\n    XblPresenceDeviceType deviceType;\n\n    /// <summary>\n    /// The records containing title presence data.\n    /// </summary>\n    const struct XblPresenceTitleRecord* titleRecords;\n\n    /// <summary>\n    /// The number of title records in the titleRecords array.\n    /// </summary>\n    size_t titleRecordsCount;\n} XblPresenceDeviceRecord;\n\n/// <summary>\n/// Defines values representing the xbl presence title record.\n/// </summary>\n/// <memof><see cref=\"XblPresenceDeviceRecord\"/></memof>\ntypedef struct XblPresenceTitleRecord\n{\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// The title name.\n    /// </summary>\n    _Field_z_ const char* titleName;\n\n    /// <summary>\n    /// Time when the record was last updated.\n    /// </summary>\n    time_t lastModified;\n\n    /// <summary>\n    /// The active state for the title.\n    /// </summary>\n    bool titleActive;\n\n    /// <summary>\n    /// The formatted and localized presence string.\n    /// </summary>\n    _Field_z_ const char* richPresenceString;\n\n    /// <summary>\n    /// The title view state.\n    /// </summary>\n    XblPresenceTitleViewState viewState;\n\n    /// <summary>\n    /// The broadcast information of what the user is broadcasting.\n    /// </summary>\n    struct XblPresenceBroadcastRecord* broadcastRecord;\n} XblPresenceTitleRecord;\n\n/// <summary>\n/// The broadcast information of what the user is broadcasting.\n/// </summary>\n/// <memof><see cref=\"XblPresenceTitleRecord\"/></memof>\ntypedef struct XblPresenceBroadcastRecord\n{\n    /// <summary>\n    /// Id for this broadcast as defined by the broadcasting service.\n    /// </summary>\n    _Field_z_ const char* broadcastId;\n\n    /// <summary>\n    /// The GUID uniquely identifying the broadcasting session.\n    /// </summary>\n    char session[XBL_GUID_LENGTH];\n\n    /// <summary>\n    /// The streaming provider.\n    /// </summary>\n    XblPresenceBroadcastProvider provider;\n\n    /// <summary>\n    /// Approximate number of current viewers.\n    /// </summary>\n    uint32_t viewerCount;\n\n    /// <summary>\n    /// Time the broadcast was started.\n    /// </summary>\n    time_t startTime;\n} XblPresenceBroadcastRecord;\n\n/// <summary>\n/// Ids needed to set Rich Presence.\n/// </summary>\n/// <argof><see cref=\"XblPresenceSetPresenceAsync\"/></argof>\ntypedef struct XblPresenceRichPresenceIds\n{\n    /// <summary>\n    /// ID of the service configuration containing the presence strings.\n    /// </summary>\n    char scid[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// The ID of a presence string that is defined in the service configuration.  \n    /// For example, PresenceId = \"1\" could equal \"Playing {0} on {1}\" in the service configuration.  \n    /// The service configuration might map token 0 to Maps and token 1 to MapId.\n    /// </summary>\n    _Field_z_ const char* presenceId;\n\n    /// <summary>\n    /// The IDs of the strings to replace the format string tokens found in the presence string.  \n    /// These strings are also defined in the service configuration.  \n    /// The ID values in the collection map to the strings associated with the token arguments found in the PresenceId.  \n    /// For example let's say this vector view contained the values \"4\" and \"1\" and PresenceId = \"1\" equals \"Playing {0} on {1}\" in the service configuration.  \n    /// The service configuration might map Token 0 = Maps, where MapId = \"4\" equals \"Hometown\".  \n    /// The service configuration might map Token 1 = Difficulty, where DifficultyId = \"1\" equals \"Casual\".\n    /// </summary>\n    const char** presenceTokenIds;\n\n    /// <summary>\n    /// The number of Ids in the presenceTokenIds array.\n    /// </summary>\n    size_t presenceTokenIdsCount;\n} XblPresenceRichPresenceIds;\n\n/// <summary>\n/// Struct passed to presence APIs to filter the presence records returned.\n/// </summary>\n/// <remarks>\n/// If the filters are not provided, defaults will be used:<br/>\n///   - Returns records for all possible titles on all devices.<br/>\n///   - Defaults to XblPresenceDetailLevel::Default which is equivalent to XblPresenceDetailLevel::Title (get basic title level information).<br/>\n///   - Does not filter out users who are offline or broadcasting.<br/>\n/// </remarks>\n/// <argof><see cref=\"XblPresenceGetPresenceForMultipleUsersAsync\"/></argof>\n/// <argof><see cref=\"XblPresenceGetPresenceForSocialGroupAsync\"/></argof>\ntypedef struct XblPresenceQueryFilters\n{\n    /// <summary>\n    /// Array of device types. If this field is null, defaults to all possible deviceTypes.\n    /// </summary>\n    const XblPresenceDeviceType* deviceTypes;\n\n    /// <summary>\n    /// Size of the deviceTypes array.\n    /// </summary>\n    size_t deviceTypesCount;\n\n    /// <summary>\n    /// List of titleIds for filtering the result. If the input is an empty vector, defaults to all possible titles.\n    /// </summary>\n    const uint32_t* titleIds;\n\n    /// <summary>\n    /// Size of the titleIds array.\n    /// </summary>\n    size_t titleIdsCount;\n\n    /// <summary>\n    /// Detail level of the result. Defaults to XblPresenceDetailLevel::Title which get basic title level information.\n    /// To get rich presence info, set to XblPresenceDetailLevel::All\n    /// </summary>\n    XblPresenceDetailLevel detailLevel;\n\n    /// <summary>\n    /// If true, API will filter out records for users that are offline.\n    /// </summary>\n    bool onlineOnly;\n\n    /// <summary>\n    /// If true, API will filter out records for users that are not broadcasting.\n    /// </summary>\n    bool broadcastingOnly;\n} XblPresenceQueryFilters;\n\n/// <summary>\n/// Get the Xuid for the user a presence record is associated with.\n/// </summary>\n/// <param name=\"handle\">Handle for the presence record returned from a GetPresence API.</param>\n/// <param name=\"xuid\">Passes back the Xuid the record is associated with.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceRecordGetXuid(\n    _In_ XblPresenceRecordHandle handle,\n    _Out_ uint64_t* xuid\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the global presence state for a presence record.\n/// </summary>\n/// <param name=\"handle\">Handle for the presence record returned from a GetPresence API.</param>\n/// <param name=\"userState\">A caller allocated struct that passes back the presence state of the record.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceRecordGetUserState(\n    _In_ XblPresenceRecordHandle handle,\n    _Out_ XblPresenceUserState* userState\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the device presence records associated with a returned presence record.\n/// </summary>\n/// <param name=\"handle\">Handle for the presence record returned from a GetPresence API.</param>\n/// <param name=\"deviceRecords\">Passes back a pointer to an array of device presence records.  \n/// The memory for the returned pointer array remains valid for the life of the XblPresenceRecordHandle object until it is closed.</param>\n/// <param name=\"deviceRecordsCount\">Passes back the size of the returned array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceRecordGetDeviceRecords(\n    _In_ XblPresenceRecordHandle handle,\n    _Out_ const XblPresenceDeviceRecord** deviceRecords,\n    _Out_ size_t* deviceRecordsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates a XblPresenceRecordHandle.\n/// </summary>\n/// <param name=\"handle\">The presence record handle.</param>\n/// <param name=\"duplicatedHandle\">Passe back the duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceRecordDuplicateHandle(\n    _In_ XblPresenceRecordHandle handle,\n    _Out_ XblPresenceRecordHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Closes a XblPresenceRecordHandle.\n/// </summary>\n/// <param name=\"handle\">The presence record handle.</param>\n/// <returns></returns>\n/// <remarks>\n/// When all outstanding handles have been closed, XblPresenceRecordCloseHandle will free the memory \n/// associated with the presence record handle.\n/// </remarks>\nSTDAPI_(void) XblPresenceRecordCloseHandle(\n    _In_ XblPresenceRecordHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets presence info for the current user context.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"isUserActiveInTitle\">Indicates if the current user context is currently active or inactive in the title.  \n/// The application can choose to set this based on an amount of inactivity.</param>\n/// <param name=\"richPresenceIds\">Optional pointer to struct which controls the rich presence strings.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceSetPresenceAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ bool isUserActiveInTitle,\n    _In_opt_ XblPresenceRichPresenceIds* richPresenceIds,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets presence info for a specific Xbox User Id.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xuid\">The Xbox User ID of the user to get presence for.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If presence info is needed for multiple users, use the batch API instead: <see cref=\"XblPresenceGetPresenceForMultipleUsersAsync\"/> \n/// </remarks>\nSTDAPI XblPresenceGetPresenceAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result for an XblPresenceGetPresenceAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"presenceRecordHandle\">Returned handle to a presence record.  \n/// The associated presence record must be released with <see cref=\"XblPresenceRecordCloseHandle\"/> \n/// when it is no longer needed.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceGetPresenceResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblPresenceRecordHandle* presenceRecordHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets presence info for multiple users.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xuids\">The Xbox User IDs of the users to get presence for.</param>\n/// <param name=\"xuidsCount\">Size of the xuids array.</param>\n/// <param name=\"filters\">Optional filters struct to filter results.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceGetPresenceForMultipleUsersAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_opt_ XblPresenceQueryFilters* filters,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result count for an XblPresenceGetPresenceForMultipleUsersAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultCount\">Passes back the number of presence records.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceGetPresenceForMultipleUsersResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result for an XblPresenceGetPresenceForMultipleUsers call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"presenceRecordHandles\">A caller allocated array that passes back the record handles result.  \n/// Each handle will need to be released with <see cref=\"XblPresenceRecordCloseHandle\"/> when they are no longer needed.</param>\n/// <param name=\"presenceRecordHandlesCount\">Size of the handles array.  \n/// Use <see cref=\"XblPresenceGetPresenceForMultipleUsersResultCount\"/> to get the count required.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceGetPresenceForMultipleUsersResult(\n    _In_ XAsyncBlock* async,\n    _Out_writes_(presenceRecordHandlesCount) XblPresenceRecordHandle* presenceRecordHandles,\n    _In_ size_t presenceRecordHandlesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets presence info for a specific group of users.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"socialGroupName\">The name of the group of users to get presence for.\n/// This can be either \"Favorites\" to retrieve information about favorites, \"People\" to retrieve information about mutual friends and people a user follows, or \"Friends\" to retrieve information about mutual friends.</param>\n/// <param name=\"socialGroupOwnerXuid\">The user whose group should be targeted. If the input is null, current user will be used.</param>\n/// <param name=\"filters\">Optional filters struct to filter results.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To retrieve the result of calling XblPresenceGetPresenceForSocialGroupAsync, call [XblPresenceGetPresenceForSocialGroupResult](xblpresencegetpresenceforsocialgroupresult.md).  \n/// To retrieve the required buffer size to hold the results of calling XblPresenceGetPresenceForSocialGroupAsync, call [XblPresenceGetPresenceForSocialGroupResultCount](xblpresencegetpresenceforsocialgroupresultcount.md). \n/// </remarks>\nSTDAPI XblPresenceGetPresenceForSocialGroupAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_z_ const char* socialGroupName,\n    _In_opt_ uint64_t* socialGroupOwnerXuid,\n    _In_opt_ XblPresenceQueryFilters* filters,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result count for an XblPresenceGetPresenceForSocialGroupAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultCount\">Passes back the number of presence records.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceGetPresenceForSocialGroupResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result for an XblPresenceGetPresenceForSocialGroup call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"presenceRecordHandles\">A caller allocated array that passes back the record handles result.  \n/// Each handle will need to be released with <see cref=\"XblPresenceRecordCloseHandle\"/> when they are no longer needed.</param>\n/// <param name=\"presenceRecordHandlesCount\">Size of the handles array.  \n/// Use <see cref=\"XblPresenceGetPresenceForSocialGroupResultCount\"/> to get the count required.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceGetPresenceForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblPresenceRecordHandle* presenceRecordHandles,\n    _In_ size_t presenceRecordHandlesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Subscribes to device presence change notifications.\n/// DEPRECATED. This API continues to work, however it will be removed in a future release.\n/// Individual RTA subscription will be managed automatically by XSAPI as users are tracked with <see cref=\"XblPresenceTrackUsers\"/>.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xuid\">The Xbox User ID of the person of the subscription.</param>\n/// <param name=\"subscriptionHandle\">Passes back the subscription handle that will be used to unsubscribe.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblPresenceSubscribeToDevicePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unsubscribes a previously created device presence change subscription.\n/// DEPRECATED. This API continues to work, however it will be removed in a future release.\n/// Individual RTA subscription will be managed automatically by XSAPI as users are untracked with <see cref=\"XblPresenceStopTrackingUsers\"/>.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"subscriptionHandle\">The RTA subscription handle created with <see cref=\"XblPresenceSubscribeToDevicePresenceChange\"/>.  \n/// This will cause the underlying object to be cleaned up,and will invalidate the subscription handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblPresenceUnsubscribeFromDevicePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Subscribes to title presence change notifications.\n/// DEPRECATED. This API will be removed in a future release. Individual RTA subscription will be managed automatically by XSAPI as\n/// titles are tracked with <see cref=\"XblPresenceTrackAdditionalTitles\"/>.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xuid\">The Xbox User ID of the person of the subscription.</param>\n/// <param name=\"titleId\">The title ID.</param>\n/// <param name=\"subscriptionHandle\">Passes back the RTA subscription handle that will be used to unsubscribe.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblPresenceSubscribeToTitlePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _In_ uint32_t titleId,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unsubscribes a previously created title presence change subscription.\n/// DEPRECATED. This API will be removed in a future release. Individual RTA subscription will be managed automatically by XSAPI as\n/// titles are untracked with <see cref=\"XblPresenceStopTrackingAdditionalTitles\"/>.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"subscriptionHandle\">Handle for the subscription created with <see cref=\"XblPresenceSubscribeToTitlePresenceChange\"/>.  \n/// This will cause the underlying object to be cleaned up,and will invalidate the subscription handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblPresenceUnsubscribeFromTitlePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Event handler for device presence change notifications.\n/// </summary>\n/// <param name=\"context\">Caller context that will be passed back to the handler.</param>\n/// <param name=\"xuid\">The XboxUserID of the User whose device presence changed.</param>\n/// <param name=\"deviceType\">The associated device type.</param>\n/// <param name=\"isUserLoggedOnDevice\">Boolean for if user is logged on device.</param>\n/// <returns></returns>\n/// <argof><see cref=\"XblPresenceAddDevicePresenceChangedHandler\"/></argof>\ntypedef void CALLBACK XblPresenceDevicePresenceChangedHandler(\n    _In_opt_ void* context,\n    _In_ uint64_t xuid,\n    _In_ XblPresenceDeviceType deviceType,\n    _In_ bool isUserLoggedOnDevice\n);\n\n/// <summary>\n/// Registers an event handler for device presence change notifications. Notifications will\n/// only be received for the Users configured with <see cref=\"XblPresenceTrackUsers\"/>.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context that will be passed back to the handler.</param>\n/// <returns> An XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblPresenceAddDevicePresenceChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblPresenceDevicePresenceChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for device presence change notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceRemoveDevicePresenceChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Event handler for title presence change notifications.\n/// </summary>\n/// <param name=\"context\">Caller context that will be passed back to the handler.</param>\n/// <param name=\"xuid\">The XboxUserID of the User whose title presence changed.</param>\n/// <param name=\"titleId\">The title ID.</param>\n/// <param name=\"titleState\">The title presence state for the user.</param>\n/// <returns></returns>\n/// <argof><see cref=\"XblPresenceAddTitlePresenceChangedHandler\"/></argof>\ntypedef void CALLBACK XblPresenceTitlePresenceChangedHandler(\n    _In_opt_ void* context,\n    _In_ uint64_t xuid,\n    _In_ uint32_t titleId,\n    _In_ XblPresenceTitleState titleState\n);\n\n/// <summary>\n/// Registers an event handler for title presence change notifications. Notifications will\n/// only be received for the Users and Titles configured with <see cref=\"XblPresenceTrackUsers\"/> and <see cref=\"XblPresenceTrackAdditionalTitles\"/>\n/// respectively.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context that will be passed back to the handler.</param>\n/// <returns> An XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblPresenceAddTitlePresenceChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblPresenceTitlePresenceChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for title presence change notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceRemoveTitlePresenceChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the list of users for whom real-time device and title presence updates will be tracked.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xuids\">Array of XboxUserIDs to append to the existing list of tracked Users.</param>\n/// <param name=\"xuidsCount\">Length of xuids array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Updates will be delivered via XblPresenceDevicePresenceChangedHandlers and XblPresenceTitlePresenceChangedHandlers.\n/// Note that the set of tracked users can be updated independent from the handlers.\n/// </remarks>\nSTDAPI XblPresenceTrackUsers(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the list of users for whom real-time device and title presence updates will be tracked.\n/// Presence updates for the specified Users will no longer be received.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xuids\">Array of XboxUserIDs to remove from the list of tracked Users.</param>\n/// <param name=\"xuidsCount\">Length of xuids array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceStopTrackingUsers(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the list of titles for which real-time title presence will be tracked. To receive title\n/// presence updates for titles other than the current title, they must be added using this API.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"titleIds\">Array of title IDs to append to the existing list of tracked titles. Note that\n/// the current title will be tracked by default.</param>\n/// <param name=\"titleIdsCount\">Length of the titleIds array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Updates will be delivered via XblPresenceTitlePresenceChangedHandlers.\n/// Note that the set of tracked titles can be updated independent from the handlers.\n/// </remarks>\nSTDAPI XblPresenceTrackAdditionalTitles(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint32_t* titleIds,\n    _In_ size_t titleIdsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the list of titles for which real-time title presence will be tracked.\n/// Title presence updates for the specified titles will no longer be received.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"titleIds\">Array of title IDs to remove from the list of tracked titles.</param>\n/// <param name=\"titleIdsCount\">Length of the titleIds array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPresenceStopTrackingAdditionalTitles(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint32_t* titleIds,\n    _In_ size_t titleIdsCount\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/privacy_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// All of the things protected by the Privacy Engine.\n/// </summary>\n/// <memof><see cref=\"XblPermissionDenyReasonDetails\"/></memof>\nenum class XblPrivacySetting : uint32_t\n{\n    /// <summary>\n    /// Unrecognized privacy setting (not one of the below values).\n    /// </summary>\n    Unknown = 0,\n\n    /// <summary>\n    /// List of friends.\n    /// </summary>\n    ShareFriendList = 1,\n\n    /// <summary>\n    /// Played game history.\n    /// </summary>\n    ShareGameHistory = 2,\n\n    /// <summary>\n    /// Messaging and Voice chat.\n    /// </summary>\n    CommunicateUsingTextAndVoice = 3,\n\n    /// <summary>\n    /// Online status.\n    /// </summary>\n    SharePresence = 4,\n\n    /// <summary>\n    /// User Profile.\n    /// </summary>\n    ShareProfile = 5,\n\n    /// <summary>\n    /// Video and Music Status.\n    /// </summary>\n    ShareVideoAndMusicStatus = 6,\n\n    /// <summary>\n    /// Video Communication.\n    /// </summary>\n    CommunicateUsingVideo = 7,\n\n    /// <summary>\n    /// Voice Data Collection.\n    /// </summary>\n    CollectVoiceData = 8,\n\n    /// <summary>\n    /// Share Xbox Music Activity.\n    /// </summary>\n    ShareXboxMusicActivity = 9,\n\n    /// <summary>\n    /// Fitness Data.\n    /// </summary>\n    ShareExerciseInfo = 11,\n\n    /// <summary>\n    /// Share identity - Real Name, aka MSA Name.\n    /// </summary>\n    ShareIdentity = 12,\n\n    /// <summary>\n    /// Real Identity Data for in game use.\n    /// </summary>\n    ShareIdentityInGame = 13,\n\n    /// <summary>\n    /// Game DVR.\n    /// </summary>\n    ShareRecordedGameSessions = 14,\n\n    /// <summary>\n    /// Allow Microsoft to collect data about Live TV watching.\n    /// </summary>\n    CollectLiveTvData = 15,\n\n    /// <summary>\n    /// Allow Microsoft to collect data about Xbox Video watching.\n    /// </summary>\n    CollectXboxVideoData = 16,\n\n    /// <summary>\n    /// Allow other users to view real identity via \"transitive real name\".\n    /// </summary>\n    ShareIdentityTransitively = 17,\n\n    /// <summary>\n    /// Allow other users to view the owner's video viewing history.\n    /// </summary>\n    ShareVideoHistory = 18,\n\n    /// <summary>\n    /// Allow other users to view the owner's music history.\n    /// </summary>\n    ShareMusicHistory = 19,\n\n    /// <summary>\n    /// Allow the user to view user created content of other users.  \n    /// This is a parental control on the owner, not a privacy setting that affects other users.\n    /// </summary>\n    AllowUserCreatedContentViewing = 20,\n\n    /// <summary>\n    /// Allow the user to view the profiles of other users.  \n    /// This is a parental control on the owner, not a privacy setting that affects other users.\n    /// </summary>\n    AllowProfileViewing = 21,\n\n    /// <summary>\n    /// Sometimes called the 'Cloaked' bit.\n    /// </summary>\n    ShowRealTimeActivity = 22,\n\n    /// <summary>\n    /// Allow full voice data (identifiable to user) to be collected on Xbox One.\n    /// </summary>\n    CollectVoiceDataXboxOneFull = 23,\n\n    /// <summary>\n    /// Enforcement setting to prevent a user from sharing identity.\n    /// </summary>\n    CanShareIdentity = 24,\n\n    /// <summary>\n    /// Allow other users to share owner's Xbox LIVE content to external social networks.\n    /// </summary>\n    ShareContentToExternalNetworks = 25,\n\n    /// <summary>\n    /// Allow voice search data to be collected on Xbox One.\n    /// </summary>\n    CollectVoiceSearchData = 26,\n\n    /// <summary>\n    /// Allow other users to see the public clubs that the user has joined.\n    /// </summary>\n    ShareClubMembership = 27,\n\n    /// <summary>\n    /// Allow voice data collection from game chats.\n    /// </summary>\n    CollectVoiceGameChatData = 28,\n\n    /// <summary>\n    /// Allow other users to view items posted by the owner on their activity feed.\n    /// </summary>\n    ShareActivityFeed = 29,\n\n    /// <summary>\n    /// Augments the existing communications settings to allow communications with \n    /// user on platforms other than Xbox Live.\n    /// </summary>\n    CommunicateDuringCrossNetworkPlay = 30,\n};\n\n/// <summary>\n/// Controls user's privileges.\n/// </summary>\n/// <memof><see cref=\"XblPermissionDenyReasonDetails\"/></memof>\nenum class XblPrivilege : uint32_t\n{\n    /// <summary>\n    /// Unrecognized privilege (not one of the below values).\n    /// </summary>\n    Unknown = 0,\n\n    /// <summary>\n    /// Controls the ability of the user to view the profile (bio, motto, etc) of other users.\n    /// </summary>\n    AllowIngameVoiceCommunications = 205,\n\n    /// <summary>\n    /// Controls the ability of the user to communicate with other users via video.\n    /// </summary>\n    AllowVideoCommunications = 235,\n\n    /// <summary>\n    /// Controls the ability of the user to view the profile (bio, motto, etc) of other users.\n    /// </summary>\n    AllowProfileViewing = 249,\n\n    /// <summary>\n    /// Controls the ability of the user to communicate with other users.\n    /// </summary>\n    AllowCommunications = 252,\n\n    /// <summary>\n    /// Controls the ability of the user to join parties with other users.\n    /// </summary>\n    AllowMultiplayer = 254,\n\n    /// <summary>\n    /// Controls the ability of the user to add friends.\n    /// </summary>\n    AllowAddFriend = 255\n};\n\n/// <summary>\n/// Actions that a client can check permission for.\n/// </summary>\n/// <remarks>\n/// Permission may be restricted by either a missing privilege of the caller or \n/// a privacy restriction of the target.\n/// </remarks>\n/// <argof><see cref=\"XblPrivacyCheckPermissionAsync\"/></argof>\n/// <argof><see cref=\"XblPrivacyCheckPermissionForAnonymousUserAsync\"/></argof>\n/// <argof><see cref=\"XblPrivacyBatchCheckPermissionAsync\"/></argof>\n/// <memof><see cref=\"XblPermissionCheckResult\"/></memof>\nenum class XblPermission : uint32_t\n{\n    /// <summary>\n    /// Unrecognized permission (not one of the below values).\n    /// </summary>\n    Unknown = 0,\n\n    /// <summary>\n    /// Check whether or not the user can send a message with text content or an invitation to the target user.\n    /// This value does not change if the player has muted the target user.  Use CommunicateUsingVoice instead.\n    /// This value will be false if for example you have set your comms to friends only and the target is not a friend.\n    /// This value will be false if for example if the target user has blocked you.\n    /// This value will be false if for example you have set your comms settings to Blocked.\n    /// </summary>\n    CommunicateUsingText = 1000,\n\n    /// <summary>\n    /// Check whether or not the user can communicate using video with the target user.\n    /// </summary>\n    CommunicateUsingVideo = 1001,\n    \n    /// <summary>\n    /// Check whether or not the user can communicate using voice with the target user.\n    /// This will be false if the player has muted the target user.\n    /// </summary>\n    CommunicateUsingVoice = 1002,\n\n    /// <summary>\n    /// Check whether or not the user can view the profile of the target user.\n    /// </summary>\n    ViewTargetProfile = 1004,\n\n    /// <summary>\n    /// Check whether or not the user can view the game history of the target user.\n    /// </summary>\n    ViewTargetGameHistory = 1005,\n\n    /// <summary>\n    /// Check whether or not the user can view the detailed video watching history of the target user.\n    /// </summary>\n    ViewTargetVideoHistory = 1006,\n\n    /// <summary>\n    /// Check whether or not the user can view the detailed music listening history of the target user.\n    /// </summary>\n    ViewTargetMusicHistory = 1007,\n\n    /// <summary>\n    /// Check whether or not the user can view the exercise info of the target user.\n    /// </summary>\n    ViewTargetExerciseInfo = 1009,\n\n    /// <summary>\n    /// Check whether or not the user can view the online status of the target user.\n    /// </summary>\n    ViewTargetPresence = 1011,\n\n    /// <summary>\n    /// Check whether or not the user can view the details of the targets video status (extended online presence).\n    /// </summary>\n    ViewTargetVideoStatus = 1012,\n\n    /// <summary>\n    /// Check whether or not the user can view the details of the targets music status (extended online presence).\n    /// </summary>\n    ViewTargetMusicStatus = 1013,\n\n    /// <summary>\n    /// Check whether or not a user can play multiplayer with the target user.\n    /// </summary>\n    PlayMultiplayer = 1014,\n\n    /// <summary>\n    /// Check whether or not the user can view user created content produced by target user.\n    /// </summary>\n    ViewTargetUserCreatedContent = 1018,\n\n    /// <summary>\n    /// Check whether or not the user can broadcast sessions on Twitch.\n    /// </summary>\n    BroadcastWithTwitch = 1019,\n\n    /// <summary>\n    /// Check whether or not the user can write a comment on an object owned by the target.\n    /// </summary>\n    WriteComment = 1022,\n\n    /// <summary>\n    /// Check whether or not the user can share an item owned by the target.\n    /// </summary>\n    ShareItem = 1024,\n\n    /// <summary>\n    /// Check whether or not the user can share an item owned by the target to external social networks.\n    /// </summary>\n    ShareTargetContentToExternalNetworks = 1025,\n};\n\n/// <summary>\n/// This describes the various ways that we expose to a requestor why a permission check may fail.\n/// </summary>\n/// <memof>  * <see cref=\"XblPermissionDenyReasonDetails\"/></memof>\nenum class XblPermissionDenyReason : uint32_t\n{\n    /// <summary>\n    /// Permission was denied, but either no reason was given or the privacy service threw an \n    /// unexpected error.\n    /// </summary>\n    Unknown = 0,\n\n    /// <summary>\n    /// The request was processed successfully, but the requestor is not allowed to perform the action.  \n    /// No reason is given.\n    /// </summary>\n    NotAllowed = 2,\n\n    /// <summary>\n    /// The requestor was missing a privilege necessary for the action.\n    /// </summary>\n    MissingPrivilege = 3,\n\n    /// <summary>\n    /// A privilege value for the requestor has a restriction that doesn't allow interaction with the target.  \n    /// For instance, a parental control only allows interaction with friends and the target isn't a friend.\n    /// </summary>\n    PrivilegeRestrictsTarget = 4,\n\n    /// <summary>\n    /// The requestor has blocked the target user.\n    /// </summary>\n    BlockListRestrictsTarget = 5,\n\n    /// <summary>\n    /// The requestor has muted the target user.\n    /// </summary>\n    MuteListRestrictsTarget = 7,\n\n    /// <summary>\n    /// A privacy value for the requestor has a restriction that doesn't allow interaction with the target.  \n    /// For instance, a parental control only allows interaction with friends and the target isn't a friend.\n    /// </summary>\n    PrivacySettingRestrictsTarget = 9,\n\n    /// <summary>\n    /// The target is a cross-network user, but cross-network privacy settings indicated only friends are allowed.  \n    /// Cross-network friends are (currently) only managed at the title level, so the title must validate \n    /// that the user are friends.\n    /// </summary>\n    CrossNetworkUserMustBeFriend = 12\n};\n\n/// <summary>\n/// Represents the different classes of non-Xbox Live users that we can check permissions for.\n/// </summary>\n/// <argof><see cref=\"XblPrivacyCheckPermissionForAnonymousUserAsync\"/></argof>\n/// <argof><see cref=\"XblPrivacyBatchCheckPermissionAsync\"/></argof>\n/// <memof><see cref=\"XblPermissionCheckResult\"/></memof>\nenum class XblAnonymousUserType : uint32_t\n{\n    /// <summary>\n    /// Invalid XblAnonymousUserType. Returned if service returns unrecognized XblAnonymousUserType\n    /// </summary>\n    Unknown = 0,\n\n    /// <summary>\n    /// A non Xbox Live user.\n    /// </summary>\n    CrossNetworkUser,\n\n    /// <summary>\n    /// A non Xbox Live user that a title recognizes as an in-game friend.\n    /// </summary>\n    CrossNetworkFriend\n};\n\n/// <summary>\n/// This struct gives details about why permission is denied.\n/// </summary>\n/// <memof>  * <see cref=\"XblPermissionCheckResult\"/></memof>\ntypedef struct XblPermissionDenyReasonDetails\n{\n    /// <summary>\n    /// Reason why permission was denied.  \n    /// Additional detail maybe found in restrictedPrivilege or \n    /// restrictedPrivacySetting depending on what the reason is.\n    /// </summary>\n    XblPermissionDenyReason reason;\n\n    /// <summary>\n    /// Active when the deny reason is either XblPermissionDenyReason::MissingPrivilege or \n    /// XblPermissionDenyReason::PrivilegeRestrictsTarget.  \n    /// Unknown otherwise.\n    /// </summary>\n    XblPrivilege restrictedPrivilege;\n\n    /// <summary>\n    /// Active when the deny reason is XblPermissionDenyReason::PrivacySettingRestrictsTarget.  \n    /// Unknown otherwise.\n    /// </summary>\n    XblPrivacySetting restrictedPrivacySetting;\n} XblPermissionDenyReasonDetails;\n\n/// <summary>\n/// Struct describing the result of a permission check request.\n/// </summary>\n/// <argof><see cref=\"XblPrivacyCheckPermissionResult\"/></argof>\n/// <argof><see cref=\"XblPrivacyCheckPermissionForAnonymousUserResult\"/></argof>\n/// <argof><see cref=\"XblPrivacyBatchCheckPermissionResult\"/></argof>\ntypedef struct XblPermissionCheckResult\n{\n    /// <summary>\n    /// Value indicating whether or not permission to take the requested action is granted.\n    /// </summary>\n    bool isAllowed;\n\n    /// <summary>\n    /// Target Xuid for the permission check request.  \n    /// Will be 0 if the permission check was for an anonymous user.\n    /// </summary>\n    uint64_t targetXuid;\n\n    /// <summary>\n    /// The class of anonymous user the permission check was for.  \n    /// Will be XblAnonymousUserType::Unknown if the permission check was for an Xbox Live user.\n    /// </summary>\n    XblAnonymousUserType targetUserType;\n\n    /// <summary>\n    /// The permission that was requested.\n    /// </summary>\n    XblPermission permissionRequested;\n\n    /// <summary>\n    /// Array of reasons why permission was denied.  \n    /// Null when isAllowed is true.\n    /// </summary>\n    XblPermissionDenyReasonDetails* reasons;\n\n    /// <summary>\n    /// Number of entries in the reasons array.\n    /// </summary>\n    size_t reasonsCount;\n} XblPermissionCheckResult;\n\n/// <summary>\n/// Get the list of Xuids the calling user should avoid during multiplayer matchmaking.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblPrivacyGetAvoidListResultCount\"/> and <see cref=\"XblPrivacyGetAvoidListResult\"/> \n/// upon completion to get the result.\n/// </remarks>\nSTDAPI XblPrivacyGetAvoidListAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result count for an XblPrivacyGetAvoidListAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"xuidCount\">Passes back the number of Xuids in the avoid list.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyGetAvoidListResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* xuidCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result for an XblPrivacyGetAvoidListAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"xuidCount\">Size of the xuids array.\n/// Use <see cref=\"XblPrivacyGetAvoidListResultCount\"/> to get the count required.</param>\n/// <param name=\"xuids\">A caller allocated array that passes back the avoid list xuids result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyGetAvoidListResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t xuidCount,\n    _Out_writes_(xuidCount) uint64_t* xuids\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Check a single permission with a single target user.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"permissionToCheck\">The permission to check.</param>\n/// <param name=\"targetXuid\">The target user's Xuid for validation.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If multiple permissions and/or target users are needed, use the batch API instead: <see cref=\"XblPrivacyBatchCheckPermissionAsync\"/>\n/// Call <see cref=\"XblPrivacyCheckPermissionResultSize\"/> and <see cref=\"XblPrivacyCheckPermissionResult\"/> \n/// upon completion to get the result.\n/// </remarks>\nSTDAPI XblPrivacyCheckPermissionAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblPermission permissionToCheck,\n    _In_ uint64_t targetXuid,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblPrivacyCheckPermissionAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes bakc the size in bytes required to store the permission check result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyCheckPermissionResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblPrivacyCheckPermissionAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.\n/// Use <see cref=\"XblPrivacyCheckPermissionResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the permission results.</param>\n/// <param name=\"ptrToBuffer\">Passes back a strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyCheckPermissionResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblPermissionCheckResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Check a single permission for class of anonymous users.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"permissionToCheck\">The permission to check.</param>\n/// <param name=\"userType\">The class of anonymous user to check permission for.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblPrivacyCheckPermissionResultSize\"/> and <see cref=\"XblPrivacyCheckPermissionResult\"/> \n/// upon completion to get the result.\n/// </remarks>\nSTDAPI XblPrivacyCheckPermissionForAnonymousUserAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblPermission permissionToCheck,\n    _In_ XblAnonymousUserType userType,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblPrivacyCheckPermissionForAnonymousUserAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the permission check result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyCheckPermissionForAnonymousUserResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblPrivacyCheckPermissionForAnonymousUserAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblPrivacyCheckPermissionForAnonymousUserResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the permission results.</param>\n/// <param name=\"ptrToBuffer\">Passes back a strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyCheckPermissionForAnonymousUserResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblPermissionCheckResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Check multiple permissions with multiple target users.  \n/// Each permission will be checked against each target user.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"permissionsToCheck\">Array of permissions to check.</param>\n/// <param name=\"permissionsCount\">Number of entries in the permissions array.</param>\n/// <param name=\"targetXuids\">Array of target Xuids to check permissions against.</param>\n/// <param name=\"xuidsCount\">Number of entries in the xuids array.</param>\n/// <param name=\"targetAnonymousUserTypes\">Array of anonymous user types to check permissions against.</param>\n/// <param name=\"targetAnonymousUserTypesCount\">Number of entries in the user types array.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblPrivacyBatchCheckPermissionResultSize\"/> and <see cref=\"XblPrivacyBatchCheckPermissionResult\"/> \n/// upon completion to get result.\n/// </remarks>\nSTDAPI XblPrivacyBatchCheckPermissionAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_reads_(permissionsCount) XblPermission* permissionsToCheck,\n    _In_ size_t permissionsCount,\n    _In_reads_(xuidsCount) uint64_t* targetXuids,\n    _In_ size_t xuidsCount,\n    _In_reads_(targetAnonymousUserTypesCount) XblAnonymousUserType* targetAnonymousUserTypes,\n    _In_ size_t targetAnonymousUserTypesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblPrivacyBatchCheckPermissionAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the permission check results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyBatchCheckPermissionResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the results for an XblPrivacyBatchCheckPermissionAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblPrivacyBatchCheckPermissionResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the permission result.</param>\n/// <param name=\"ptrToBufferResults\">Passes back a strongly typed array of XblPermissionCheckResult that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"ptrToBufferCount\">Passes back the number of entries in the ptrToBufferResults array.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyBatchCheckPermissionResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblPermissionCheckResult** ptrToBufferResults,\n    _Out_ size_t* ptrToBufferCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the list of Xuids that the calling user should not hear (mute) during multiplayer matchmaking.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblPrivacyGetMuteListResultCount\"/> and <see cref=\"XblPrivacyGetMuteListResult\"/> \n/// upon completion to get result.\n/// </remarks>\nSTDAPI XblPrivacyGetMuteListAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result count for an XblPrivacyGetMuteListAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"xuidCount\">Passes back the number of Xuids in the mute list.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyGetMuteListResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* xuidCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get result for an XblPrivacyGetMuteListAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"xuidCount\">Size of the xuids array.\n/// Use <see cref=\"XblPrivacyGetMuteListResultCount\"/> to get the count required.</param>\n/// <param name=\"xuids\">A caller allocated array that passes back the mute list xuids result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblPrivacyGetMuteListResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t xuidCount,\n    _Out_writes_(xuidCount) uint64_t* xuids\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/profile_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary> \n/// Represents a user's Xbox Live profile.\n/// </summary>\n/// <argof><see cref=\"XblProfileGetUserProfileResult\"/></argof>\n/// <argof><see cref=\"XblProfileGetUserProfilesResult\"/></argof>\n/// <argof><see cref=\"XblProfileGetUserProfilesForSocialGroupResult\"/></argof>\ntypedef struct XblUserProfile\n{\n    /// <summary>\n    /// The user's Xbox user ID.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// The UTF-8 encoded user's display name to be used in application UI. This will always be the user's gamertag and identical to the gameDisplayName field.\n    /// </summary>\n    char appDisplayName[XBL_DISPLAY_NAME_CHAR_SIZE];\n\n    /// <summary>\n    /// UTF-8 encoded Uri for the user's gamer pic.  This will always be identical to the gameDisplayPictureResizeUri field.\n    /// The Uri is a resizable Uri. It can be used to specify one of the following sizes and formats by appending &apos;&amp;format={format}&amp;w={width}&amp;h={height}:<br/>\n    /// Format: png<br/>\n    /// Width   Height<br/>\n    /// 64      64<br/>\n    /// 208     208<br/>\n    /// 424     424<br/>\n    /// </summary>\n    char appDisplayPictureResizeUri[XBL_DISPLAY_PIC_URL_RAW_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded user's display name to be used in application UI. This will always be the user's gamertag and identical to the appDisplayName field.\n    /// </summary>\n    char gameDisplayName[XBL_DISPLAY_NAME_CHAR_SIZE];\n\n    /// <summary>\n    /// UTF-8 encoded Uri for the user's gamer pic.  This will always be identical to the appDisplayPictureResizeUri field.\n    /// The Uri is a resizable Uri. It can be used to specify one of the following sizes and formats by appending &apos;&amp;format={format}&amp;w={width}&amp;h={height}:<br/>\n    /// Format: png<br/>\n    /// Width   Height<br/>\n    /// 64      64<br/>\n    /// 208     208<br/>\n    /// 424     424<br/>\n    /// </summary>\n    char gameDisplayPictureResizeUri[XBL_DISPLAY_PIC_URL_RAW_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded user's Gamerscore.\n    /// </summary>\n    char gamerscore[XBL_GAMERSCORE_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded user's classic gamertag.\n    /// This field only uses ASCII characters and does not include a suffix.\n    /// </summary>\n    char gamertag[XBL_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded modern gamertag for the user.  \n    /// This field uses specific ranges of UTF-8 characters and does not include a suffix.\n    /// Not guaranteed to be unique.\n    /// </summary>\n    char modernGamertag[XBL_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded numeric suffix appended to modern gamertag to ensure uniqueness.  \n    /// May be empty in some cases.\n    /// </summary>\n    char modernGamertagSuffix[XBL_MODERN_GAMERTAG_SUFFIX_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded unique modern gamertag and numeric suffix.  \n    /// Format will be \"modernGamertag#suffix\".  \n    /// Guaranteed to be no more than 16 rendered characters.\n    /// </summary>\n    char uniqueModernGamertag[XBL_UNIQUE_MODERN_GAMERTAG_CHAR_SIZE];\n} XblUserProfile;\n\n/// <summary>\n/// Gets a user profile for a specific Xbox user.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the user to get the profile for.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If profiles are needed for multiple users, use the batch API instead: <see cref=\"XblProfileGetUserProfilesAsync\"/> \n/// To get the result, call <see cref=\"XblProfileGetUserProfileResult\"/> \n/// inside the AsyncBlock callback or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>Calls V2 GET /users/batch/profile/settings</rest>\nSTDAPI XblProfileGetUserProfileAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for a completed XblProfileGetUserProfileAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblProfileGetUserProfileAsync.</param>\n/// <param name=\"profile\">A caller allocated profile object to write result to.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblProfileGetUserProfileResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblUserProfile* profile\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets one or more user profiles for a collection of specified Xbox users.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserIds\">C-style array of Xbox User IDs of the users to get profiles for.</param>\n/// <param name=\"xboxUserIdsCount\">The number of Xbox User IDs in the array.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, first call <see cref=\"XblProfileGetUserProfilesResultCount\"/> to \n/// get the count of returned profiles and then call <see cref=\"XblProfileGetUserProfilesResult\"/> \n/// inside the AsyncBlock callback or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>Calls V2 GET /users/batch/profile/settings</rest>\nSTDAPI XblProfileGetUserProfilesAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the number of profiles from a completed get XblProfileGetUserProfilesAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblProfileGetUserProfilesAsync.</param>\n/// <param name=\"profileCount\">Passes back the number of profiles.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblProfileGetUserProfilesResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* profileCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for a completed XblProfileGetUserProfilesAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblProfileGetUserProfilesAsync.</param>\n/// <param name=\"profilesCount\">The size of the caller allocated profiles array.  \n/// Use <see cref=\"XblProfileGetUserProfilesResultCount\"/> to get the count required.</param>\n/// <param name=\"profiles\">A caller allocated array that passes back the user profile results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblProfileGetUserProfilesResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t profilesCount,\n    _Out_writes_(profilesCount) XblUserProfile* profiles\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets profiles for users in a specified social group.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"socialGroup\">The UTF-8 encoded name of the social group of users to search. Options are \"Favorites\" and \"People\".</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, first call <see cref=\"XblProfileGetUserProfilesForSocialGroupResultCount\"/> to \n/// get the count of returned profiles and then call <see cref=\"XblProfileGetUserProfilesForSocialGroupResult\"/> \n/// inside the AsyncBlock callback or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>Calls V2 GET /users/{userId}/profile/settings/people/{socialGroup}</rest>\nSTDAPI XblProfileGetUserProfilesForSocialGroupAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* socialGroup,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the number of profiles from a completed XblProfileGetUserProfilesForSocialGroupAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblProfileGetUserProfilesForSocialGroupAsync.</param>\n/// <param name=\"profileCount\">Passes back the number of profiles.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblProfileGetUserProfilesForSocialGroupResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* profileCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for a completed XblProfileGetUserProfilesForSocialGroupAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblProfileGetUserProfilesForSocialGroupAsync.</param>\n/// <param name=\"profilesCount\">The size of the caller allocated profiles array.  \n/// Use <see cref=\"XblProfileGetUserProfilesForSocialGroupResultCount\"/> to get the count required.</param>\n/// <param name=\"profiles\">A caller allocated array that passes back the social group user profile results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblProfileGetUserProfilesForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t profilesCount,\n    _Out_writes_(profilesCount) XblUserProfile* profiles\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/real_time_activity_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Enumeration for the possible states of a statistic subscription request\n/// to the real-time activity service.\n/// </summary>\nenum class XblRealTimeActivitySubscriptionState : uint32_t\n{\n    /// <summary>\n    /// The subscription state is unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Waiting for the server to respond to the subscription request.\n    /// </summary>\n    PendingSubscribe,\n\n    /// <summary>\n    /// Subscription confirmed.\n    /// </summary>\n    Subscribed,\n\n    /// <summary>\n    /// Waiting for the server to respond to the unsubscribe request.\n    /// </summary>\n    PendingUnsubscribe,\n\n    /// <summary>\n    /// Unsubscribe confirmed.\n    /// </summary>\n    Closed\n};\n\n/// <summary>\n/// Enumeration for the possible connection states of the connection\n/// to the real-time activity service.\n/// </summary>\nenum class XblRealTimeActivityConnectionState : uint32_t\n{\n    /// <summary>\n    /// Currently connected to the real-time activity service.\n    /// </summary>\n    Connected,\n\n    /// <summary>\n    /// Currently connecting to the real-time activity service.\n    /// </summary>\n    Connecting,\n\n    /// <summary>\n    /// Currently disconnected from the real-time activity service.\n    /// </summary>\n    Disconnected\n};\n\n/// <summary>\n/// Subscription handle.\n/// </summary>\ntypedef struct XblRealTimeActivitySubscription* XblRealTimeActivitySubscriptionHandle;\n\n/// <summary>\n/// Get the state of the subscription.\n/// DEPRECATED. The state of RTA subscriptions is no longer exposed publicly. XblRealTimeActivitySubscriptionState::Unknown\n/// will always be returned.\n/// </summary>\n/// <param name=\"subscriptionHandle\">Subscription handle returned from a subscribe API.</param>\n/// <param name=\"state\">Passes back the current state of the subscription.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblRealTimeActivitySubscriptionGetState(\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    _Out_ XblRealTimeActivitySubscriptionState* state\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the unique ID for the subscription.\n/// DEPRECATED. The state of RTA subscriptions is no longer exposed publicly. This API will return a unique\n/// client side ID, but it is in no way related to the ID assigned by the RTA service.\n/// </summary>\n/// <param name=\"subscriptionHandle\">Subscription handle returned from a subscribe API.</param>\n/// <param name=\"id\">Passes back the ID for the subscription.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblRealTimeActivitySubscriptionGetId(\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    _Out_ uint32_t* id\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Forces XSAPI to open a WebSocket connection to the Xbox Live real-time activity service.\n/// DEPRECATED. Calling this API is no longer required. The WebSocket connection will be made automatically by \n/// XSAPI as necessary. This API will be removed in a future release.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblRealTimeActivityActivate(\n    _In_ XblContextHandle xboxLiveContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Indicates that a client real-time activity session is complete. If there are no remaining real-time service\n/// activations, the WebSocket connection will be cleaned up along with remaining subscriptions.\n/// DEPRECATED. Calling this API is no longer required. The WebSocket connection will be cleaned up automatically\n/// by XSAPI when it is no longer needed. This API will be removed in a future release.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblRealTimeActivityDeactivate(\n    _In_ XblContextHandle xboxLiveContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Handler function for when the client service loses or gains connectivity to the real time activity service.\n/// </summary>\n/// <param name=\"context\">Caller context that will be passed back to the handler function.</param>\n/// <param name=\"connectionState\">State of the connection.</param>\n/// <returns></returns>\ntypedef void CALLBACK XblRealTimeActivityConnectionStateChangeHandler(\n    _In_opt_ void* context,\n    _In_ XblRealTimeActivityConnectionState connectionState\n);\n\n/// <summary>\n/// Registers a handler function to receive a notification that is sent when the client service\n/// loses or gains connectivity to the real time activity service.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context that will be passed back to the handler function.</param>\n/// <returns>An XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblRealTimeActivityAddConnectionStateChangeHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivityConnectionStateChangeHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for real time activity connectivity state changes.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblRealTimeActivityRemoveConnectionStateChangeHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Handler function for when there is an error in the real time activity service.\n/// </summary>\n/// <param name=\"context\">Caller context that will be passed back to the handler function.</param>\n/// <param name=\"subscription\">Subscription handle.</param>\n/// <param name=\"subscriptionError\">The HRESULT error code.</param>\n/// <returns></returns>\ntypedef void CALLBACK XblRealTimeActivitySubscriptionErrorHandler(\n    _In_opt_ void* context,\n    _In_ XblRealTimeActivitySubscriptionHandle subscription,\n    _In_ HRESULT subscriptionError\n);\n\n/// <summary>\n/// Registers a handler function to receive a notification that is sent when there is an\n/// error in the real time activity service.\n/// DEPRECATED. RTA service errors will now be handled by XSAPI internally and callback will no longer be invoked.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context that will be passed back to the handler function.</param>\n/// <returns>A XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_XBL_DEPRECATED_(XblFunctionContext) XblRealTimeActivityAddSubscriptionErrorHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivitySubscriptionErrorHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for real time activity error notifications.\n/// DEPRECATED. RTA service errors will now be handled by XSAPI internally and callback will no longer be invoked.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblRealTimeActivityRemoveSubscriptionErrorHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Handler function for when there is a resync message from the real time activity service.\n/// </summary>\n/// <param name=\"context\">Caller context that will be passed back to the handler function.</param>\n/// <returns></returns>\ntypedef void CALLBACK XblRealTimeActivityResyncHandler(\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers a handler function to receive a notification that is sent when there is a\n/// resync message from the real time activity service.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"context\">Caller context that will be passed back to the handler function.</param>\n/// <returns>A XblFunctionContext object that can be used to unregister the event handler.</returns>\n/// <remarks>\n/// This message indicates that data may have been lost and to resync all data by calling\n/// corresponding REST API's. Wherever possible, XSAPI will automatically resync the subscription and\n/// invoke the corresponding handler. For multiplayer session changed subscriptions, titles must resync\n/// their own sessions.\n/// </remarks>\nSTDAPI_(XblFunctionContext) XblRealTimeActivityAddResyncHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivityResyncHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for real time activity resync notifications.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox Live context handle.</param>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblRealTimeActivityRemoveResyncHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/services_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\n#include <httpClient/httpClient.h>\n#include <xsapi-c/types_c.h>\n#include <xsapi-c/pal.h>\n#include <xsapi-c/errors_c.h>\n#include <xsapi-c/xbox_live_global_c.h>\n#include <xsapi-c/platform_c.h>\n#include <xsapi-c/xbox_live_context_settings_c.h>\n#include <xsapi-c/xbox_live_context_c.h>\n#include <xsapi-c/presence_c.h>\n#include <xsapi-c/profile_c.h>\n#include <xsapi-c/social_c.h>\n#include <xsapi-c/social_manager_c.h>\n#include <xsapi-c/string_verify_c.h>\n#include <xsapi-c/achievements_c.h>\n#include <xsapi-c/achievements_manager_c.h>\n#include <xsapi-c/multiplayer_c.h>\n#include <xsapi-c/multiplayer_activity_c.h>\n#include <xsapi-c/multiplayer_manager_c.h>\n#include <xsapi-c/matchmaking_c.h>\n#include <xsapi-c/privacy_c.h>\n#include <xsapi-c/title_managed_statistics_c.h>\n#include <xsapi-c/user_statistics_c.h>\n#include <xsapi-c/events_c.h>\n#include <xsapi-c/real_time_activity_c.h>\n#include <xsapi-c/leaderboard_c.h>\n#include <xsapi-c/http_call_c.h>\n#include <xsapi-c/title_storage_c.h>\n#include <xsapi-c/game_invite_c.h>\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#include <xsapi-c/notification_c.h>\n#endif"
  },
  {
    "path": "Include/xsapi-c/social_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\n#include \"real_time_activity_c.h\"\n#include \"multiplayer_c.h\"\n\nextern \"C\"\n{\n\n/// <summary>\n/// Defines the relationship filters available for social groups.\n/// </summary>\n/// <argof><see cref=\"XblSocialGetSocialRelationshipsAsync\"/></argof>\nenum class XblSocialRelationshipFilter : uint32_t\n{\n    /// <summary>\n    /// All the people on the user's people list.\n    /// </summary>\n    All,\n\n    /// <summary>\n    /// Filters to only the people on the user's people list that have the attribute \"Favorite\" associated with them.\n    /// </summary>\n    Favorite,\n\n    /// <summary>\n    /// Filters to only the people on the user's people list that are also legacy Xbox Live friends.\n    /// </summary>\n    LegacyXboxLiveFriends\n};\n\n/// <summary>\n/// Defines values used to identify the type of reputation feedback.\n/// </summary>\n/// <argof><see cref=\"XblSocialSubmitReputationFeedbackAsync\"/></argof>\n/// <memof><see cref=\"XblReputationFeedbackItem\"/></memof>\nenum class XblReputationFeedbackType : uint32_t\n{\n    /// <summary>\n    /// Titles that are able to automatically determine that a user kills a teammate \n    /// may send this feedback without user intervention.\n    /// </summary>\n    FairPlayKillsTeammates,\n\n    /// <summary>\n    /// Titles that are able to automatically determine that a user is cheating \n    /// may send this feedback without user intervention.\n    /// </summary>\n    FairPlayCheater,\n\n    /// <summary>\n    /// Titles that are able to automatically determine that a user has tampered \n    /// with on-disk content may send this feedback without user intervention.\n    /// </summary>\n    FairPlayTampering,\n\n    /// <summary>\n    /// Titles that are able to automatically determine that a user quit a game early \n    /// may send this feedback without user intervention.\n    /// </summary>\n    FairPlayQuitter,\n\n    /// <summary>\n    /// When a user is voted out of a game (kicked), titles \n    /// may send this feedback without user intervention.\n    /// </summary>\n    FairPlayKicked,\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate video communications \n    /// may send this feedback.\n    /// </summary>\n    CommunicationsInappropriateVideo,\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate voice communications \n    /// may send this feedback.\n    /// </summary>\n    CommunicationsAbusiveVoice,\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate user generated content \n    /// may send this feedback.\n    /// </summary>\n    InappropriateUserGeneratedContent,\n\n    /// <summary>\n    /// Titles that allow users to vote on a most valuable player at the end of a multiplayer session \n    /// may send this feedback.\n    /// </summary>\n    PositiveSkilledPlayer,\n\n    /// <summary>\n    /// Titles that allow users to submit positive feedback on helpful fellow players \n    /// may send this feedback.\n    /// </summary>\n    PositiveHelpfulPlayer,\n\n    /// <summary>\n    /// Titles that allow users to submit positive feedback on shared user generated content \n    /// may send this feedback.\n    /// </summary>\n    PositiveHighQualityUserGeneratedContent,\n\n    /// <summary>\n    /// Titles that allow users to report phishing message may send this feedback.\n    /// </summary>\n    CommsPhishing,\n\n    /// <summary>\n    /// Titles that allow users to report communication based on a picture \n    /// may send this feedback.\n    /// </summary>\n    CommsPictureMessage,\n\n    /// <summary>\n    /// Titles that allow users to report spam messages may send this feedback.\n    /// </summary>\n    CommsSpam,\n\n    /// <summary>\n    /// Titles that allow users to report text messages may send this feedback.\n    /// </summary>\n    CommsTextMessage,\n\n    /// <summary>\n    /// Titles that allow users to report voice messages may send this feedback.\n    /// </summary>\n    CommsVoiceMessage,\n\n    /// <summary>\n    /// Titles that allow users to report voice messages may send this feedback.\n    /// </summary>\n    FairPlayConsoleBanRequest,\n\n    /// <summary>\n    /// Titles that allow users to report if a user stands idle on purpose in a game, \n    /// usually round after round, may send this feedback.\n    /// </summary>\n    FairPlayIdler,\n\n    /// <summary>\n    /// Titles that report a recommendation to ban a user from Xbox Live may send this feedback.\n    /// </summary>\n    FairPlayUserBanRequest,\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate gamer picture may send this feedback.\n    /// </summary>\n    UserContentGamerpic,\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate biography and other personal information \n    /// may send this feedback.\n    /// </summary>\n    UserContentPersonalInfo,\n\n    /// <summary>\n    /// Titles that allow users to report unsporting behavior may send this feedback.\n    /// </summary>\n    FairPlayUnsporting,\n\n    /// <summary>\n    /// Titles that allow users to report leaderboard cheating may send this feedback.\n    /// </summary>\n    FairPlayLeaderboardCheater\n};\n\n/// <summary>\n/// Defines values used to identify the type of social notification.\n/// </summary>\n/// <memof><see cref=\"XblSocialRelationshipChangeEventArgs\"/></memof>\nenum class XblSocialNotificationType : uint32_t\n{\n    /// <summary>\n    /// Unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// User(s) were added.\n    /// </summary>\n    Added,\n\n    /// <summary>\n    /// User(s) data changed.\n    /// </summary>\n    Changed,\n\n    /// <summary>\n    /// User(s) were removed.\n    /// </summary>\n    Removed,\n\n    /// <summary>\n    /// The number of pending incoming friend requests has changed.\n    /// </summary>\n    IncomingFriendRequestCountChanged\n};\n\n/// <summary>\n/// Represents the relationship between the user and another Xbox user.\n/// </summary>\n/// <argof><see cref=\"XblSocialRelationshipResultGetRelationships\"/></argof>\ntypedef struct XblSocialRelationship\n{\n    /// <summary>\n    /// The person's Xbox user identifier.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// Indicates whether the person is one that the user cares about more.  \n    /// Since users can have a very large number of people in their people list, favorite people \n    /// should be prioritized first in experiences and shown before others that are not favorites.\n    /// </summary>\n    bool isFavorite;\n\n    /// <summary>\n    /// Indicates whether there exists a mutual follower/following relation between a user and another Xbox User \n    /// </summary>\n    bool isFriend;\n\n    /// <summary>\n    /// Does not reflect a follower/following relationship, is currently kept for backwards compatibility purposes.\n    /// The value of this field is determined by the value of 'isFriend' within a XblSocialRelationship\n    /// </summary>\n    bool isFollowingCaller;\n\n    /// <summary>\n    /// A UTF-8 encoded collection of strings indicating which social networks \n    /// this person has a relationship with.\n    /// </summary>\n    _Field_z_ const char** socialNetworks;\n\n    /// <summary>\n    /// The count of social networks strings in the socialNetworks array.\n    /// </summary>\n    size_t socialNetworksCount;\n} XblSocialRelationship;\n\n/// <summary>\n/// Event arguments for a social relationship change.\n/// </summary>\ntypedef struct XblSocialRelationshipChangeEventArgs\n{\n    /// <summary>\n    /// The Xbox user ID for the user who's social graph changes are being listed for.\n    /// </summary>\n    uint64_t callerXboxUserId;\n\n    /// <summary>\n    /// The type of notification change.\n    /// </summary>\n    XblSocialNotificationType socialNotification;\n\n    /// <summary>\n    /// The Xbox user ids who the event is for.\n    /// </summary>\n    uint64_t* xboxUserIds;\n\n    /// <summary>\n    /// The number of strings in the xboxUserIds array.\n    /// </summary>\n    size_t xboxUserIdsCount;\n} XblSocialRelationshipChangeEventArgs;\n\ntypedef struct XblSocialFriendRequestCountChangedEventArgs\n{\n    /// <summary>\n    /// The Xbox user ID for the user who's social graph changes are being listed for.\n    /// </summary>\n    uint64_t callerXboxUserId;\n\n    /// <summary>\n    /// Current number of pending incoming friend requests.\n    /// </summary>\n    size_t incomingFriendRequestCount;\n} XblSocialFriendRequestCountChangedEventArgs;\n\n/// <summary>\n/// A handle to a social relationship result.\n/// </summary>\n/// <remarks>\n/// This handle is used by other APIs to get the social relationship objects and to get \n/// the next page of results from the service if there is one.  \n/// The handle must be closed using <see cref=\"XblSocialRelationshipResultCloseHandle\"/> when the result is no longer needed.\n/// </remarks>\ntypedef struct XblSocialRelationshipResult* XblSocialRelationshipResultHandle;\n\n/// <summary>\n/// Gets a list of people that the caller is socially connected to.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User Id to get the social relationships for.</param>\n/// <param name=\"socialRelationshipFilter\">Controls how the list is filtered.</param>\n/// <param name=\"startIndex\">Controls the starting index of the results list.</param>\n/// <param name=\"maxItems\">The maximum number of items that the results list can contain.  \n/// Pass 0 to attempt to retrieve all items.</param>\n/// <param name=\"async\">Caller allocated <see cref=\"XAsyncBlock\"/>.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblSocialGetSocialRelationshipsResult\"/> to get the result.\n/// </remarks>\n/// <rest>V1 GET /users/{ownerId}/people?view={view}&amp;startIndex={startIndex}&amp;maxItems={maxItems}</rest>\nSTDAPI XblSocialGetSocialRelationshipsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ XblSocialRelationshipFilter socialRelationshipFilter,\n    _In_ size_t startIndex,\n    _In_ size_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result handle from an XblSocialGetSocialRelationshipsAsync API call.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that was passed to <see cref=\"XblSocialGetSocialRelationshipsAsync\"/>.</param>\n/// <param name=\"handle\">Passes back an XblSocialRelationshipResultHandle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When no longer using the XblSocialRelationshipResultHandle, make sure to call <see cref=\"XblSocialRelationshipResultCloseHandle\"/>.  \n/// When all outstanding handles have been closed, the memory associated with the social relationship's results list will be freed.  \n/// After calling this API, make sure to call <see cref=\"XblSocialRelationshipResultGetRelationships\"/> to get the results list to iterate over.  \n/// Then call <see cref=\"XblSocialRelationshipResultHasNext\"/> to check if there are additional pages of results.\n/// </remarks>\nSTDAPI XblSocialGetSocialRelationshipsResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblSocialRelationshipResultHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get a list of the XblSocialRelationship objects from an XblSocialRelationshipResultHandle.\n/// </summary>\n/// <param name=\"resultHandle\">Social relationship result handle.</param>\n/// <param name=\"relationships\">Passes back a pointer to an array of XblSocialRelationship objects.  \n/// The memory for the returned pointer remains valid for the life of the XblSocialRelationshipResultHandle object until it is closed.</param>\n/// <param name=\"relationshipsCount\">Passes back the number of items in the relationships array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When no longer using the XblSocialRelationshipResultHandle, make sure to call <see cref=\"XblSocialRelationshipResultCloseHandle\"/>.  \n/// When all outstanding handles have been closed, the memory associated with the social relationship's results list will be freed.\n/// </remarks>\nSTDAPI XblSocialRelationshipResultGetRelationships(\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _Out_ const XblSocialRelationship** relationships,\n    _Out_ size_t* relationshipsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Checks if there are more pages of social relationships to retrieve from the service.\n/// </summary>\n/// <param name=\"resultHandle\">The XblSocialRelationshipResultHandle from XblSocialGetSocialRelationshipsResult.</param>\n/// <param name=\"hasNext\">Passes back true if there are more results to retrieve, false otherwise.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the result has a next page, then call <see cref=\"XblSocialRelationshipResultGetNextAsync\"/> to retrieve the next page of items.\n/// </remarks>\nSTDAPI XblSocialRelationshipResultHasNext(\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _Out_ bool* hasNext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the total number of results for an XblSocialRelationshipResultHandle.\n/// </summary>\n/// <param name=\"resultHandle\">The XblSocialRelationshipResultHandle from <see cref=\"XblSocialGetSocialRelationshipsResult\"/>.</param>\n/// <param name=\"totalCount\">Passes back the total number of results for the query.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Note that this is only the total number of results requested by <see cref=\"XblSocialGetSocialRelationshipsAsync\"/> \n/// and may be different from the maximum number of result items.\n/// </remarks>\nSTDAPI XblSocialRelationshipResultGetTotalCount(\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _Out_ size_t* totalCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the next page of a list of people that the caller is socially connected to.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"resultHandle\">Social relationship result handle from a previous call to XblSocialGetSocialRelationshipsAsync.</param>\n/// <param name=\"maxItems\">Controls the number of XblSocialRelationship objects to get. 0 will return as many as possible.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call this API after finding more results from <see cref=\"XblSocialRelationshipResultHasNext\"/>.  \n/// After calling this API, make sure to call <see cref=\"XblSocialRelationshipResultGetNextResult\"/> to get the result.\n/// </remarks>\nSTDAPI XblSocialRelationshipResultGetNextAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _In_ size_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result from an XblSocialRelationshipResultGetNextAsync API call.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to <see cref=\"XblSocialRelationshipResultGetNextAsync\"/>.</param>\n/// <param name=\"handle\">Passes back a XblSocialRelationshipResultHandle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When no longer using the XblSocialRelationshipResultHandle, make sure to call <see cref=\"XblSocialRelationshipResultCloseHandle\"/>.  \n/// When all outstanding handles have been closed, the memory associated with the social relationship's results list will be freed.  \n/// After calling this API, make sure to call <see cref=\"XblSocialRelationshipResultGetRelationships\"/> to get the results list to iterate over.  \n/// Then call <see cref=\"XblSocialRelationshipResultHasNext\"/> to see if there are more results.\n/// </remarks>\nSTDAPI XblSocialRelationshipResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblSocialRelationshipResultHandle* handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates the XblSocialRelationshipResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblSocialRelationshipResultHandle to duplicate.</param>\n/// <param name=\"duplicatedHandle\">Passes back the duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When no longer using the XblSocialRelationshipResultHandle, make sure to call <see cref=\"XblSocialRelationshipResultCloseHandle\"/>.\n/// </remarks>\nSTDAPI XblSocialRelationshipResultDuplicateHandle(\n    _In_ XblSocialRelationshipResultHandle handle,\n    _Out_ XblSocialRelationshipResultHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Closes the XblSocialRelationshipResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblSocialRelationshipResultHandle to close.</param>\n/// <returns></returns>\n/// <remarks>\n/// When all outstanding handles have been closed, the memory associated with the social relationship's results list will be freed.\n/// </remarks>\nSTDAPI_(void) XblSocialRelationshipResultCloseHandle(\n    _In_ XblSocialRelationshipResultHandle handle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Subscribes to the social service for people changed events.\n/// DEPRECATED. Calling this API is no longer required and it will be removed in a future release. RTA subscription will be managed \n/// automatically by XSAPI as `XblSocialRelationshipChangedHandler` are added and removed.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player requesting the subscription.</param>\n/// <param name=\"subscriptionHandle\">Passes back a handle to the subscription which is used to un-subscribe.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblSocialUnsubscribeFromSocialRelationshipChange\"/> to un-subscribe.\n/// </remarks>\nSTDAPI_XBL_DEPRECATED XblSocialSubscribeToSocialRelationshipChange(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Un-subscribes a previously created social relationship change subscription.\n/// DEPRECATED. Calling this API is no longer required and it will be removed in a future release. RTA subscription will be managed \n/// automatically by XSAPI as `XblSocialRelationshipChangedHandler` are added and removed.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"subscriptionHandle\">The subscription handle to unsubscribe.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call this API only if <see cref=\"XblSocialSubscribeToSocialRelationshipChange\"/> was used to subscribe to social relationship changes.\n/// </remarks>\nSTDAPI_XBL_DEPRECATED XblSocialUnsubscribeFromSocialRelationshipChange(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A callback invoked when a social relationship changes.\n/// </summary>\n/// <param name=\"eventArgs\">The arguments associated with the relationship change.\n/// The fields of the struct are only valid during the callback.</param>\n/// <param name=\"context\">Context provided by when the handler is added.</param>\n/// <returns></returns>\n/// <remarks>\n/// For the callback to work properly, you must be subscribed to social relationship changes for at least one user.\n/// </remarks>\ntypedef void\n(STDAPIVCALLTYPE* XblSocialRelationshipChangedHandler)(\n    _In_ const XblSocialRelationshipChangeEventArgs* eventArgs,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for notifications of social relationship changes caused by the registering user.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"handlerContext\">Client context pointer to be passed back to the handler.</param>\n/// <returns>A XblFunctionContext used to remove the handler.</returns>\n/// <remarks>\n/// This handler triggers only if the user changes the relationship with another user.\n/// This handler does not trigger if another user changes the relationship with the user.\n///\n/// Call <see cref=\"XblSocialRemoveSocialRelationshipChangedHandler\"/> to un-register event handler.\n/// </remarks>\nSTDAPI_(XblFunctionContext) XblSocialAddSocialRelationshipChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblSocialRelationshipChangedHandler handler,\n    _In_opt_ void* handlerContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Removes a social relationship change handler.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"handlerFunctionContext\">Context for the handler to remove.</param>\n/// <returns></returns>\n/// <remarks>\n/// <prereq/>\n/// Call this API only if <see cref=\"XblSocialAddSocialRelationshipChangedHandler\"/> was used to register an event handler.\n/// </remarks>\nSTDAPI XblSocialRemoveSocialRelationshipChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext handlerFunctionContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// A callback invoked the number of incoming friend requests for a user changes. \n/// </summary>\n/// <param name=\"eventArgs\">The arguments associated with the change.\n/// The fields of the struct are only valid during the callback.</param>\n/// <param name=\"context\">Context provided by when the handler is added.</param>\n/// <returns></returns>\ntypedef void\n(STDAPIVCALLTYPE* XblSocialIncomingFriendRequestCountChangedHandler)(\n    _In_ const XblSocialFriendRequestCountChangedEventArgs* eventArgs,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for notifications of incoming friend requests for the registering user.\n/// This callback is only useful for developers trying to build social experiences on non-Windows platforms.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"handlerContext\">Client context pointer to be passed back to the handler.</param>\n/// <param name=\"handlerFunctionContext\">Token to be populated and later used to remove the handler.</param>\n/// <returns></returns>\n/// <remarks></remarks>\nSTDAPI XblSocialAddFriendRequestCountChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblSocialIncomingFriendRequestCountChangedHandler handler,\n    _In_opt_ void* handlerContext,\n    _Out_ XblFunctionContext* handlerFunctionContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Removes a friend request count change handler.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"handlerFunctionContext\">Context for the handler to remove.</param>\n/// <returns></returns>\n/// <remarks>\n/// <prereq/>\n/// Call this API only if <see cref=\"XblSocialAddFriendRequestCountChangedHandler\"/> was used to register an event handler.\n/// </remarks>\nSTDAPI XblSocialRemoveFriendRequestCountChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext handlerFunctionContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Represents the parameters for submitting reputation feedback on a user.\n/// </summary>\n/// <argof><see cref=\"XblSocialSubmitBatchReputationFeedbackAsync\"/></argof>\ntypedef struct XblReputationFeedbackItem\n{\n    /// <summary>\n    /// The Xbox User ID of the user that reputation feedback is being submitted on.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// The reputation feedback type being submitted.\n    /// </summary>\n    XblReputationFeedbackType feedbackType;\n\n    /// <summary>\n    /// Multiplayer session reference describing the MPSD session this feedback relates to. (Optional)\n    /// </summary>\n    XblMultiplayerSessionReference* sessionReference;\n\n    /// <summary>\n    /// UTF-8 encoded user supplied text added to explain the reason for the feedback.\n    /// </summary>\n    _Field_z_ const char* reasonMessage;\n\n    /// <summary>\n    /// The UTF-8 encoded id of a resource that can be used as evidence for the feedback.  \n    /// Example: the Id of a video file.\n    /// </summary>\n    _Field_z_ const char* evidenceResourceId;\n} XblReputationFeedbackItem;\n\n/// <summary>\n/// Submits reputation feedback on the specified user.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the user that reputation feedback is being submitted on.</param>\n/// <param name=\"reputationFeedbackType\">The reputation feedback type being submitted.</param>\n/// <param name=\"sessionReference\">Multiplayer session reference describing the MPSD session this feedback relates to. (Optional)</param>\n/// <param name=\"reasonMessage\">User supplied text in UTF-8 encoded added to explain the reason for the feedback. (Optional)</param>\n/// <param name=\"evidenceResourceId\">The UTF-8 encoded id of a resource that can be used as evidence for the feedback.  \n/// Example: the Id of a video file. (Optional)</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Make sure to call <see cref=\"XAsyncGetStatus\"/> to get the result.\n/// </remarks>\n/// <rest>V100 POST /users/xuid({xuid})/feedback</rest>\nSTDAPI XblSocialSubmitReputationFeedbackAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ XblReputationFeedbackType reputationFeedbackType,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n    _In_z_ const char* reasonMessage,\n    _In_opt_z_ const char* evidenceResourceId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Submits reputation feedback on the specified user.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"feedbackItems\">An array of XblReputationFeedbackItem objects to submit reputation feedback on.</param>\n/// <param name=\"feedbackItemsCount\">The count of items in the feedbackItems array.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Make sure to call <see cref=\"XAsyncGetStatus\"/> to get the result.\n/// </remarks>\n/// <rest>V101 POST /users/batchfeedback</rest>\nSTDAPI XblSocialSubmitBatchReputationFeedbackAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const XblReputationFeedbackItem* feedbackItems,\n    _In_ size_t feedbackItemsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/social_manager_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n#include <xsapi-c/presence_c.h>\n\nextern \"C\"\n{\n\n#define XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST 100\n\n/// <summary>\n/// Controls how much information is exposed in each xbox_live_social_graph_user.  \n/// Detail level can only be set on construction of social_manager.\n/// </summary>\n/// <argof><see cref=\"XblSocialManagerAddLocalUser\"/></argof>\nenum class XblSocialManagerExtraDetailLevel : uint32_t\n{\n    /// <summary>\n    /// Only get default PeopleHub information (presence, profile).\n    /// </summary>\n    NoExtraDetail,\n\n    /// <summary>\n    /// Add extra detail for the title history for the users.\n    /// </summary>\n    TitleHistoryLevel = 0x1,\n\n    /// <summary>\n    /// Add extra detail for the preferred color for the users.\n    /// </summary>\n    PreferredColorLevel = 0x2,\n\n    /// <summary>\n    /// Add all extra detail.\n    /// </summary>\n    All = 0x3,\n};\n\nDEFINE_ENUM_FLAG_OPERATORS(XblSocialManagerExtraDetailLevel);\n\n/// <summary>\n/// The filter level of information.  \n/// Title will only show users associated with a particular title.\n/// </summary>\n/// <argof><see cref=\"XblSocialManagerUserGroupGetFilters\"/></argof>\n/// <argof><see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/></argof>\nenum class XblPresenceFilter : uint32_t\n{\n    /// <summary>\n    /// Unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Is currently playing current title and is online.\n    /// </summary>\n    TitleOnline,\n\n    /// <summary>\n    /// Has played this title and is offline.\n    /// </summary>\n    /// <remarks>\n    /// This filter option requires <see cref=\"XblSocialManagerExtraDetailLevel\"/>::TitleHistoryLevel to be set in <see cref=\"XblSocialManagerAddLocalUser\"/>\n    /// </remarks>\n    TitleOffline,\n\n    /// <summary>\n    /// Has played this title, is online but not currently playing this title.\n    /// </summary>\n    /// <remarks>\n    /// This filter option requires <see cref=\"XblSocialManagerExtraDetailLevel\"/>::TitleHistoryLevel to be set in <see cref=\"XblSocialManagerAddLocalUser\"/>\n    /// </remarks>\n    TitleOnlineOutsideTitle,\n\n    /// <summary>\n    /// Everyone currently online.\n    /// </summary>\n    AllOnline,\n\n    /// <summary>\n    /// Everyone currently offline.\n    /// </summary>\n    AllOffline,\n\n    /// <summary>\n    /// Everyone who has played or is playing the title.\n    /// </summary>\n    /// <remarks>\n    /// This filter option requires <see cref=\"XblSocialManagerExtraDetailLevel\"/>::TitleHistoryLevel to be set in <see cref=\"XblSocialManagerAddLocalUser\"/>\n    /// </remarks>\n    AllTitle,\n\n    /// <summary>\n    /// Everyone.\n    /// </summary>\n    All\n};\n\n/// <summary>\n/// The types of possible social manager events.\n/// </summary>\n/// <memof><see cref=\"XblSocialManagerEvent\"/></memof>\nenum class XblSocialManagerEventType : uint32_t\n{\n    /// <summary>\n    /// Fired when one or more users are added to social graph. Users are added to the graph if they are tracked\n    /// by a list group or if they are followed by the local user.\n    /// </summary>\n    UsersAddedToSocialGraph,\n\n    /// <summary>\n    /// Fired when one or more users are removed from social graph. User's will be removed from the social graph if\n    /// they aren't followed by the local user, nor are they tracked by any list groups.\n    /// </summary>\n    UsersRemovedFromSocialGraph,\n\n    /// <summary>\n    /// Users presence record has changed. This event implies that the set of users tracked by filter groups\n    /// may have changed (i.e. if the group was created with an XblPresenceFilter).\n    /// </summary>\n    PresenceChanged,\n\n    /// <summary>\n    /// Users profile information has changed.\n    /// </summary>\n    ProfilesChanged,\n\n    /// <summary>\n    /// Relationship to users has changed. This event implies that the set of users tracked by filter groups\n    /// may have changed (i.e. if the group was created with an XblRelationshipFilter).\n    /// </summary>\n    SocialRelationshipsChanged,\n\n    /// <summary>\n    /// Fired when the initial social graph has been loaded for a local user.\n    /// </summary>\n    LocalUserAdded,\n\n    /// <summary>\n    /// Fired when all users tracked by a social group are in social graph.\n    /// </summary>\n    SocialUserGroupLoaded,\n\n    /// <summary>\n    /// After updating a list based user group with <see cref=\"XblSocialManagerUpdateSocialUserGroup\"/>, this event\n    /// is fired to indicate all of the new users are in the social graph. If they are not already part of the graph,\n    /// the new users will be added. Note that this event doesn't apply for filter based user groups.\n    /// </summary>\n    SocialUserGroupUpdated,\n\n    /// <summary>\n    /// Unknown.\n    /// </summary>\n    UnknownEvent\n};\n\n/// <summary>\n/// Possible relationship types to filter by.\n/// </summary>\n/// <argof><see cref=\"XblSocialManagerUserGroupGetFilters\"/></argof>\n/// <argof><see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/></argof>\nenum class XblRelationshipFilter : uint32_t\n{\n    /// <summary>\n    /// Unknown.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Friends of the user (user is following).\n    /// </summary>\n    Friends,\n\n    /// <summary>\n    /// Favorites of the user.\n    /// </summary>\n    Favorite\n};\n\n/// <summary>\n/// Identifies type of social user group created.\n/// </summary>\n/// <argof><see cref=\"XblSocialManagerUserGroupGetType\"/></argof>\nenum class XblSocialUserGroupType : uint32_t\n{\n    /// <summary>\n    /// Social user group based off of filters.\n    /// </summary>\n    FilterType,\n\n    /// <summary>\n    /// Social user group based off of list of users.\n    /// </summary>\n    UserListType\n};\n\n/// <summary>\n/// Data about whether the user has played the title.\n/// </summary>\n/// <memof><see cref=\"XblSocialManagerUser\"/></memof>\ntypedef struct XblTitleHistory\n{\n    /// <summary>\n    /// Whether the user has played this title.\n    /// </summary>\n    bool hasUserPlayed;\n\n    /// <summary>\n    /// The last time the user had played.\n    /// </summary>\n    /// <remarks>\n    /// Do not use both this and lastTimeUserPlayedText.\n    /// For playtime within the past 14 days, this will be accurate for the date and fuzzily accurate for the time. \n    /// For playtime older than 14 days, this will only be accurate to the year and month, up to a year ago. The date will be returned as the 1st of the month, \n    /// but the play time could have occurred anywhere within that month.\n    /// </remarks>\n    time_t lastTimeUserPlayed;\n\n    /// <summary>\n    /// The last time the user had played in a standardized plaintext format (e.g. \"a few minutes ago\" or \"x hours/days/months ago\" or \"this/last month\").\n    /// </summary>\n    /// <remarks>\n    /// Do not use both this and lastTimeUserPlayed.\n    /// </remarks>\n    char lastTimeUserPlayedText[XBL_LAST_TIME_PLAYED_CHAR_SIZE];\n} XblTitleHistory;\n\n/// <summary>\n/// Preferred color for the user. Set via the shell.\n/// </summary>\n/// <memof><see cref=\"XblSocialManagerUser\"/></memof>\ntypedef struct XblPreferredColor\n{\n    /// <summary>\n    /// UTF-8 encoded user's primary color.\n    /// </summary>\n    char primaryColor[XBL_COLOR_CHAR_SIZE];\n\n    /// <summary>\n    /// UTF-8 encoded user's secondary color.\n    /// </summary>\n    char secondaryColor[XBL_COLOR_CHAR_SIZE];\n\n    /// <summary>\n    /// UTF-8 encoded user's tertiary color.\n    /// </summary>\n    char tertiaryColor[XBL_COLOR_CHAR_SIZE];\n} XblPreferredColor;\n\n/// <summary>\n/// Social manager version of the presence title record.  \n/// Gives information about different titles presence information.\n/// </summary>\n/// <memof><see cref=\"XblSocialManagerPresenceRecord\"/></memof>\ntypedef struct XblSocialManagerPresenceTitleRecord\n{\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    uint32_t titleId;\n\n    /// <summary>\n    /// The title name.\n    /// </summary>\n    char titleName[XBL_TITLE_NAME_CHAR_SIZE];\n\n    /// <summary>\n    /// The active state for the title.\n    /// </summary>\n    bool isTitleActive;\n\n    /// <summary>\n    /// The UTF-8 encoded formatted and localized presence string.\n    /// </summary>\n    char presenceText[XBL_RICH_PRESENCE_CHAR_SIZE];\n\n    /// <summary>\n    /// The active state for the title.\n    /// </summary>\n    bool isBroadcasting;\n\n    /// <summary>\n    /// Device type.\n    /// </summary>\n    XblPresenceDeviceType deviceType;\n\n    /// <summary>\n    /// Whether or not this is the primary presence record.\n    /// </summary>\n    bool isPrimary;\n} XblSocialManagerPresenceTitleRecord;\n\n#define XBL_NUM_PRESENCE_RECORDS 6\n\n/// <summary>\n/// Social manager presence record. Shows information on users current presence status and stores title records.\n/// </summary>\n/// <argof><see cref=\"XblSocialManagerPresenceRecordIsUserPlayingTitle\"/></argof>\n/// <memof><see cref=\"XblSocialManagerUser\"/></memof>\ntypedef struct XblSocialManagerPresenceRecord\n{\n    /// <summary>\n    /// The user's presence state.\n    /// </summary>\n    XblPresenceUserState userState;\n\n    /// <summary>\n    /// Collection of presence title record objects returned by a request.\n    /// </summary>\n    XblSocialManagerPresenceTitleRecord presenceTitleRecords[XBL_NUM_PRESENCE_RECORDS];\n\n    /// <summary>\n    /// Number of valid presence records in presenceTitleRecords array.\n    /// </summary>\n    uint32_t presenceTitleRecordCount;\n} XblSocialManagerPresenceRecord;\n\n/// <summary>\n/// Xbox Social User that contains profile, presence, preferred color, and title history data.\n/// </summary>\n/// <memof><see cref=\"XblSocialManagerEvent\"/></memof>\ntypedef struct XblSocialManagerUser\n{\n    /// <summary>\n    /// The xbox user id.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// Whether they are a favorite.\n    /// </summary>\n    bool isFavorite;\n\n    /// <summary>\n    /// Indicates whether there exists a mutual follower/following relation between a user and another user\n    /// </summary>\n    bool isFriend;\n\n    /// <summary>\n    /// No longer indicates whether a calling user is following a given user. Kept for backwards compatibility purposes.\n    /// The value of this field is determined by the value of 'isFriend'\n    /// </summary>\n    bool isFollowingUser;\n\n    /// <summary>\n    /// No longer indicates whether a calling user is followed by given user. Kept for backwards compatibility purposes.\n    /// The value of this field is determined by the value of 'isFriend'\n    /// </summary>\n    bool isFollowedByCaller;\n\n    /// <summary>\n    /// The UTF-8 encoded display name.\n    /// Many batch operations performed by XblSocialManager will not return a displayName for players. Use gamerTag or modernGamerTag instead\n    /// </summary>\n    char displayName[XBL_DISPLAY_NAME_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded real name.\n    /// </summary>\n    char realName[XBL_REAL_NAME_CHAR_SIZE];\n\n    /// <summary>\n    /// The UTF-8 encoded display picture uri.\n    /// </summary>\n    char displayPicUrlRaw[XBL_DISPLAY_PIC_URL_RAW_CHAR_SIZE];\n\n    /// <summary>\n    /// Whether to use the players avatar.\n    /// </summary>\n    bool useAvatar;\n\n    /// <summary>\n    /// UTF-8 encoded player's gamerscore.\n    /// </summary>\n    char gamerscore[XBL_GAMERSCORE_CHAR_SIZE];\n\n    /// <summary>\n    /// UTF-8 encoded player's gamertag.\n    /// </summary>\n    char gamertag[XBL_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// Modern gamertag for the player. Not guaranteed to be unique.\n    /// </summary>\n    char modernGamertag[XBL_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// Suffix appended to modern gamertag to ensure uniqueness.  May be empty in some cases.\n    /// </summary>\n    char modernGamertagSuffix[XBL_MODERN_GAMERTAG_SUFFIX_CHAR_SIZE];\n\n    /// <summary>\n    /// Combined modern gamertag and suffix. Format will be \"MGT#suffix\".  \n    /// Guaranteed to be no more than 16 rendered characters.\n    /// </summary>\n    char uniqueModernGamertag[XBL_UNIQUE_MODERN_GAMERTAG_CHAR_SIZE];\n\n    /// <summary>\n    /// Users presence record.\n    /// </summary>\n    XblSocialManagerPresenceRecord presenceRecord;\n\n    /// <summary>\n    /// Title history for the user.\n    /// </summary>\n    XblTitleHistory titleHistory;\n\n    /// <summary>\n    /// Preferred color for the user.\n    /// </summary>\n    XblPreferredColor preferredColor;\n} XblSocialManagerUser;\n\n/// <summary>\n/// A handle to a social manager user group.\n/// </summary>\ntypedef struct XblSocialManagerUserGroup* XblSocialManagerUserGroupHandle;\n\n#define XBL_SOCIAL_MANAGER_MAX_AFFECTED_USERS_PER_EVENT 10\n\n/// <summary>\n/// An event that something in the social graph has changed.\n/// </summary>\n/// <argof><see cref=\"XblSocialManagerDoWork\"/></argof>\ntypedef struct XblSocialManagerEvent\n{\n    /// <summary>\n    /// The user whose graph got changed.\n    /// </summary>\n    XblUserHandle user;\n\n    /// <summary>\n    /// The type of event this is.\n    /// </summary>\n    XblSocialManagerEventType eventType;\n\n    /// <summary>\n    /// Error that occurred, or S_OK.\n    /// </summary>\n    HRESULT hr;\n\n    /// <summary>\n    /// The user group that was loaded for XblSocialManagerEventType::SocialUserGroupLoaded or updated.  \n    /// For XblSocialManagerEventType::SocialUserGroupUpdated. Will be null for other types of events.\n    /// </summary>\n    XblSocialManagerUserGroupHandle groupAffected;\n\n    /// <summary>\n    /// The users affected. Returned pointers valid until the next XblSocialManagerDoWork call.\n    /// </summary>\n    XblSocialManagerUser* usersAffected[XBL_SOCIAL_MANAGER_MAX_AFFECTED_USERS_PER_EVENT];\n\n} XblSocialManagerEvent;\n\n/// <summary>\n/// Query whether the user associated with the provided presence record is playing a given title id.\n/// </summary>\n/// <param name=\"presenceRecord\">A presence record returned from another social manager API.</param>\n/// <param name=\"titleId\">Title ID to query about.</param>\n/// <returns>True if the user is playing the title and false otherwise.</returns>\nSTDAPI_(bool) XblSocialManagerPresenceRecordIsUserPlayingTitle(\n    _In_ const XblSocialManagerPresenceRecord* presenceRecord,\n    _In_ uint32_t titleId\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the type of a Social Manager user group.\n/// </summary>\n/// <param name=\"group\">The group handle.</param>\n/// <param name=\"type\">Passes back the group type.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call this API after calling either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// The XblSocialManagerUserGroupHandle is returned by the <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded\n/// event in <see cref=\"XblSocialManagerDoWork\"/>.\n/// </remarks>\nSTDAPI XblSocialManagerUserGroupGetType(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _Out_ XblSocialUserGroupType* type\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets local user the group is associated with.\n/// </summary>\n/// <param name=\"group\">The group handle.</param>\n/// <param name=\"localUser\">Passes back the local user handle.  \n/// This user handle does not need to be closed.  \n/// It remains valid for as long as the user is added to the social manager.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call this API after calling either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// The XblSocialManagerUserGroupHandle is returned by the <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded event \n/// in <see cref=\"XblSocialManagerDoWork\"/>.\n/// </remarks>\nSTDAPI XblSocialManagerUserGroupGetLocalUser(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _Out_ XblUserHandle* localUser\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the filters for a filter group.\n/// </summary>\n/// <param name=\"group\">The group handle.</param>\n/// <param name=\"presenceFilter\">Passes back the presence filter.</param>\n/// <param name=\"relationshipFilter\">Passes back the relationship filter.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the group is not a filter group, E_UNEXPECTED will be returned.  \n/// Call this API after either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// The XblSocialManagerUserGroupHandle is returned by the <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded \n/// event in <see cref=\"XblSocialManagerDoWork\"/>.<br/>\n/// </remarks>\nSTDAPI XblSocialManagerUserGroupGetFilters(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _Out_opt_ XblPresenceFilter* presenceFilter,\n    _Out_opt_ XblRelationshipFilter* relationshipFilter\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// An array of pointers to internally owned XblSocialManagerUsers.\n/// </summary>\n/// <remarks>\n/// This will be returned from <see cref=\"XblSocialManagerUserGroupGetUsers\"/> and the array may change \n/// with each call to <see cref=\"XblSocialManagerDoWork\"/>.\n/// </remarks>\ntypedef const XblSocialManagerUser* const* XblSocialManagerUserPtrArray;\n\n/// <summary>\n/// Gets an XblSocialManagerUserPtrArray of the users tracked by the user group.\n/// </summary>\n/// <param name=\"group\">The group handle from which to get users.</param>\n/// <param name=\"users\">Passes back a pointer to an array of XblSocialManagerUser objects.  \n/// The memory for the returned pointer remains valid until the next time <see cref=\"XblSocialManagerDoWork\"/> is called.</param>\n/// <param name=\"usersCount\">Passes back the size of the users array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The XblSocialManagerUserPtrArray is only guaranteed to be valid until the next call to <see cref=\"XblSocialManagerDoWork\"/>.  \n/// If the user objects are needed beyond the scope of the next <see cref=\"XblSocialManagerDoWork\"/> call, \n/// they are statically sized and trivially copyable.  \n/// Call this API after calling either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// Wait for <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded event in <see cref=\"XblSocialManagerDoWork\"/>.  Prior to this the group will be empty.\n/// </remarks>\nSTDAPI XblSocialManagerUserGroupGetUsers(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _Outptr_result_maybenull_ XblSocialManagerUserPtrArray* users,\n    _Out_ size_t* usersCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets a pointer to an XSAPI owned array of xuids tracked by the group.\n/// </summary>\n/// <param name=\"group\">The group from which to get users.</param>\n/// <param name=\"trackedUsers\">Passes back a pointer to tracked xuids array.  \n/// The memory for the returned pointer remains valid until the next time <see cref=\"XblSocialManagerDoWork\"/> is called.</param>\n/// <param name=\"trackedUsersCount\">Passes back the size of the tracked users array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// For list-based groups, the set of tracked users is static (i.e. the list of xuids provided when the group is created), \n/// but for filter-based groups, the set tracked users changes as the local user's relationships change.  \n/// Call this API after calling either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// Wait for <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded event in <see cref=\"XblSocialManagerDoWork\"/>.  Prior to this the group will be empty.\n/// </remarks>\nSTDAPI XblSocialManagerUserGroupGetUsersTrackedByGroup(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _Outptr_result_maybenull_ const uint64_t** trackedUsers,\n    _Out_ size_t* trackedUsersCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Create a social graph for the specified local user.\n/// </summary>\n/// <param name=\"user\">Xbox Live User to create a graph for.</param>\n/// <param name=\"extraLevelDetail\">The level of verbosity that should be in the service calls for this user.</param>\n/// <param name=\"queue\">Queue to be used for background operation for this user (Optional).\n/// Note: Using XTaskQueueDispatchMode::Immediate for this queue may cause poor performance. </param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The result of a local user being added will be triggered through \n/// the <see cref=\"XblSocialManagerEventType\"/>::LocalUserAdded event in <see cref=\"XblSocialManagerDoWork\"/>.  \n/// To remove the social graph for the specified local user, call <see cref=\"XblSocialManagerRemoveLocalUser\"/>.\n/// </remarks>\nSTDAPI XblSocialManagerAddLocalUser(\n    _In_ XblUserHandle user,\n    _In_ XblSocialManagerExtraDetailLevel extraLevelDetail,\n    _In_opt_ XTaskQueueHandle queue\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Immediately removes a social graph for the specified local user.\n/// </summary>\n/// <param name=\"user\">Xbox Live User to remove.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// When a user is removed, their social graph and user groups will be destroyed as well.  \n/// There will be no future events associated with the user after they are removed.  \n/// Call this API only if <see cref=\"XblSocialManagerAddLocalUser\"/> was used to create a social graph for a local user.\n/// </remarks>\nSTDAPI XblSocialManagerRemoveLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Called whenever the title wants to update the social graph and get list of change events.\n/// </summary>\n/// <param name=\"socialEvents\">Passes back a pointer to the array of social events that have occurred since the last call to XblSocialManagerDoWork.  \n/// This array is only valid until the next call to XblSocialManagerDoWork.  \n/// The internal array will automatically be cleaned up when XblCleanup is called.</param>\n/// <param name=\"socialEventsCount\">Passes back the number of events in the social events array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Must be called every frame for data to be up to date.  \n/// The array of social events that is sent back is only valid until the next call to <see cref=\"XblSocialManagerDoWork\"/>.  \n/// Make sure to check if there were social events sent back.  \n/// If the social events array is null, no results.  \n/// If the social events count is 0, no results.  \n/// If there were social events sent back then handle each <see cref=\"XblSocialManagerEvent\"/> \n/// by their respective <see cref=\"XblSocialManagerEventType\"/>.\n/// </remarks>\nSTDAPI XblSocialManagerDoWork(\n    _Outptr_result_maybenull_ const XblSocialManagerEvent** socialEvents,\n    _Out_ size_t* socialEventsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Constructs a XblSocialManagerUserGroup, which is a collection of users with social information.\n/// </summary>\n/// <param name=\"user\">Xbox Live User the group is associated with.</param>\n/// <param name=\"presenceFilter\">The restriction of users based on their presence and title activity.</param>\n/// <param name=\"relationshipFilter\">The restriction of users based on their relationship to the calling user.</param>\n/// <param name=\"group\">Passes back a handle to the created group.  \n/// This group can be later be cleaned up with XblSocialManagerDestroySocialUserGroup. The group will also be cleaned up \n/// (invalidating the returned handle) if the associated user is removed from Social Manager.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Wait for <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded event in <see cref=\"XblSocialManagerDoWork\"/>.  Prior to this the group will be empty.\n/// </remarks>\nSTDAPI XblSocialManagerCreateSocialUserGroupFromFilters(\n    _In_ XblUserHandle user,\n    _In_ XblPresenceFilter presenceFilter,\n    _In_ XblRelationshipFilter relationshipFilter,\n    _Outptr_result_maybenull_ XblSocialManagerUserGroupHandle* group\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Constructs a social XblSocialManagerUserGroup, which is a collection of users with social information.\n/// </summary>\n/// <param name=\"user\">Xbox Live User.</param>\n/// <param name=\"xboxUserIdList\">List of users to populate the Xbox Social User Group with.  \n/// The list cannot exceed XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST.</param>\n/// <param name=\"xboxUserIdListCount\">The number of items in the xboxUserIdList.</param>\n/// <param name=\"group\">Passes back a handle to the created group.\n/// This group may later be cleaned up with XblSocialManagerDestroySocialUserGroup. The group will also be cleaned up \n/// (invalidating the returned handle) if the associated user is removed from Social Manager.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Wait for <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded event in <see cref=\"XblSocialManagerDoWork\"/>.  Prior to this the group will be empty.\n/// </remarks>\nSTDAPI XblSocialManagerCreateSocialUserGroupFromList(\n    _In_ XblUserHandle user,\n    _In_ uint64_t* xboxUserIdList,\n    _In_ size_t xboxUserIdListCount,\n    _Outptr_result_maybenull_ XblSocialManagerUserGroupHandle* group\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Destroys a created Social User Group.\n/// </summary>\n/// <param name=\"group\">The Social User Group to destroy and stop tracking.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This will stop updaing the Xbox Social User Group and remove tracking for any users the XblSocialManagerUserGroup holds.  \n/// Call this API after calling either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// The XblSocialManagerUserGroupHandle is returned by the <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded event \n/// in <see cref=\"XblSocialManagerDoWork\"/>.\n/// </remarks>\nSTDAPI XblSocialManagerDestroySocialUserGroup(\n    _In_ XblSocialManagerUserGroupHandle group\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the number of local users currently tracked by SocialManager.\n/// </summary>\n/// <returns>The number of local users currently tracked by SocialManager.</returns>\n/// <remarks>\n/// To add local users to be tracked, call <see cref=\"XblSocialManagerAddLocalUser\"/>.  \n/// To remove local users from being tracked, call <see cref=\"XblSocialManagerRemoveLocalUser\"/>.  \n/// This function must be called before calling <see cref=\"XblSocialManagerGetLocalUsers\"/>.\n/// </remarks>\nSTDAPI_(size_t) XblSocialManagerGetLocalUserCount() XBL_NOEXCEPT;\n\n/// <summary>\n/// Returns user handles for all users tracked by SocialManager.\n/// </summary>\n/// <param name=\"usersCount\">The size of the user handle array.</param>\n/// <param name=\"users\">Passes back a pointer to an array to populate with local users.  \n/// This array is only valid until the next call to XblSocialManagerDoWork.  \n/// The user handles returned are not duplicated copies so do not call close on them.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Duplicate handle is not called before returning the handles, so if the user \n/// is needed after removing it from SocialManager, duplicate handle must be called.  \n/// Make sure to have created a social graph for at least one local user by calling <see cref=\"XblSocialManagerAddLocalUser\"/>.  \n/// Also, call <see cref=\"XblSocialManagerGetLocalUserCount\"/> to get the number of local users currently tracked.\n/// </remarks>\nSTDAPI XblSocialManagerGetLocalUsers(\n    _In_ size_t usersCount,\n    _Out_writes_(usersCount) XblUserHandle* users\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Updates specified social user group to new group of users.\n/// </summary>\n/// <param name=\"group\">The xbox social user group to update.</param>\n/// <param name=\"users\">New list of users to track. Note that this replaces the existing list of tracked users.  \n/// The list cannot exceed XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST.</param>\n/// <param name=\"usersCount\">Number of items in the users array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Does a diff to see which users have been added or removed.  \n/// The result of a user group being updated will be triggered through the \n/// <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupUpdated event in <see cref=\"XblSocialManagerDoWork\"/>.  \n/// Call this API after calling either <see cref=\"XblSocialManagerCreateSocialUserGroupFromFilters\"/>\n/// or <see cref=\"XblSocialManagerCreateSocialUserGroupFromList\"/> to create an XblSocialManagerUserGroup.  \n/// The XblSocialManagerUserGroupHandle is returned by the <see cref=\"XblSocialManagerEventType\"/>::SocialUserGroupLoaded\n/// event in <see cref=\"XblSocialManagerDoWork\"/>.\n/// </remarks>\nSTDAPI XblSocialManagerUpdateSocialUserGroup(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _In_ uint64_t* users,\n    _In_ size_t usersCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Whether to enable social manager to poll every 30 seconds from the presence service.\n/// </summary>\n/// <param name=\"user\">Xbox Live User to enable polling for.</param>\n/// <param name=\"shouldEnablePolling\">Whether or not polling should enabled.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblSocialManagerSetRichPresencePollingStatus(\n    _In_ XblUserHandle user,\n    _In_ bool shouldEnablePolling\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/string_verify_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Enumeration values that indicate the result code from string verification.\n/// </summary>\n/// <remarks>\n/// These values are defined on the service side and should not be modified.\n/// </remarks>\n/// <argof><see cref=\"XblVerifyStringResult\"/></argof>\nenum class XblVerifyStringResultCode\n{\n    /// <summary>\n    /// No issues were found with the string.\n    /// </summary>\n    Success,\n\n    /// <summary>\n    /// The string contains offensive content.\n    /// </summary>\n    Offensive,\n\n    /// <summary>\n    /// The string is too long to verify.\n    /// </summary>\n    TooLong,\n\n    /// <summary>\n    /// An unknown error was encountered during string verification.\n    /// </summary>\n    UnknownError\n};\n\n/// <summary>\n/// Contains information about the results of a string verification.\n/// </summary>\n/// <argof><see cref=\"XblStringVerifyStringResult\"/></argof>\n/// <argof><see cref=\"XblStringVerifyStringsResult\"/></argof>\ntypedef struct XblVerifyStringResult\n{\n    /// <summary>\n    /// The result code for the string verification.\n    /// </summary>\n    XblVerifyStringResultCode resultCode;\n\n    /// <summary>\n    /// Contains the first offending substring if the\n    /// resultCode is XblVerifyStringResultCode::Offensive.\n    /// </summary>\n    char* firstOffendingSubstring;\n} XblVerifyStringResult;\n\n/// <summary>\n/// Verifies if a string contains acceptable text for use with Xbox Live.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"stringToVerify\">The string to verify.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblStringVerifyStringResultSize\"/> to retrieve size of buffer needed for result.  \n/// Call <see cref=\"XblStringVerifyStringResult\"/> to retrieve the size of the results.\n/// </remarks>\nSTDAPI XblStringVerifyStringAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* stringToVerify,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblStringVerifyStringAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the XblVerifyStringResult result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblStringVerifyStringResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblStringVerifyStringAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblStringVerifyStringResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the verify string result.</param>\n/// <param name=\"ptrToBuffer\">Passes back a strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblStringVerifyStringResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblVerifyStringResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Verifies a collection of strings to see if each string contains acceptable text for use with Xbox Live.\n/// </summary>\n/// <param name=\"xboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"stringsToVerify\">The string to verify.</param>\n/// <param name=\"stringsCount\">The number of strings being verified.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblStringVerifyStringsResultSize\"/> to retrieve size of buffer needed for result.  \n/// Call <see cref=\"XblStringVerifyStringsResult\"/> to retrieve the size of the results.\n///</remarks>\nSTDAPI XblStringVerifyStringsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char** stringsToVerify,\n    _In_ const uint64_t stringsCount,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblStringVerifyStringsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the XblVerifyStringResult results.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblStringVerifyStringsResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblStringVerifyStringsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Call <see cref=\"XblStringVerifyStringsResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the verify strings result.</param>\n/// <param name=\"ptrToBufferStrings\">Passes back a strongly typed array of XblVerifyStringResult that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"stringsCount\">Passes back the number of XblVerifyStringResult results.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblStringVerifyStringsResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblVerifyStringResult** ptrToBufferStrings,\n    _Out_ size_t* stringsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n} // end extern C"
  },
  {
    "path": "Include/xsapi-c/title_managed_statistics_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Enumeration values that indicate the Title Managed Stat type.\n/// </summary>\n/// <memof><see cref=\"XblTitleManagedStatistic\"/></memof>\nenum class XblTitleManagedStatType : uint32_t\n{\n    /// <summary>\n    /// Sets the type of Title Managed Stat to a Number.\n    /// </summary>\n    Number,\n\n    /// <summary>\n    /// Sets the type of Title Managed Stat to a String.\n    /// </summary>\n    String\n};\n\n/// <summary>\n/// Contains information about a Title Managed statistic.\n/// </summary>\n/// <argof><see cref=\"XblTitleManagedStatsWriteAsync\"/></argof>\ntypedef struct XblTitleManagedStatistic\n{\n    /// <summary>\n    /// The name of the statistic (case insensitive).\n    /// </summary>\n    _Field_z_ const char* statisticName;\n\n    /// <summary>\n    /// The type of the statistic.\n    /// </summary>\n    XblTitleManagedStatType statisticType;\n\n    /// <summary>\n    /// The value of the double statistic. Backed by a JSON number value, which can \n    /// lead to precision issues when storing 64-bit fixed point values.\n    /// </summary>\n    double numberValue;\n\n    /// <summary>\n    /// The value of the string statistic.\n    /// </summary>\n    _Field_z_ const char* stringValue;\n} XblTitleManagedStatistic;\n\n/// <summary>\n/// Completely update the calling user's stats.  \n/// This call wipes out all existing stats (any stats not referenced in the provided array will be removed).\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserId\">User whose stats are being updated (can only be the local user).</param>\n/// <param name=\"statistics\">A list of XblTitleManagedStatistic to submit.</param>\n/// <param name=\"statisticsCount\">Number of items in the statistics array.</param>\n/// <param name=\"async\">Used for async call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XAsyncGetStatus\"/> inside \n/// the AsyncBlock callback or after the AsyncBlock is complete.  \n/// If the call fails for any reason, it is the responsibility of the game to re-submit the request.\n/// </remarks>\nSTDAPI XblTitleManagedStatsWriteAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_ const XblTitleManagedStatistic* statistics,\n    _In_ size_t statisticsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Partially update the calling user's stats.  \n/// Stats will only be overwritten if they already exist (any stats not referenced will remain unchanged).\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"statistics\">A list of XblTitleManagedStatistic to submit.</param>\n/// <param name=\"statisticsCount\">Number of items in the statistics array.</param>\n/// <param name=\"async\">Used for async call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Note that stat names are case insensitive.  \n/// To get the result, call <see cref=\"XAsyncGetStatus\"/> inside \n/// the AsyncBlock callback or after the AsyncBlock is complete.  \n/// If the call fails for any reason, it is the responsibility of the game to re-submit the request.\n/// </remarks>\nSTDAPI XblTitleManagedStatsUpdateStatsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const XblTitleManagedStatistic* statistics,\n    _In_ size_t statisticsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Delete stats for the calling user (any stats not referenced will remain unchanged).\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"statisticNames\">A list of names of statistics to delete.  \n/// If there isn't an existing statistic matching a provided name, no changes will be made for that statistic.</param>\n/// <param name=\"statisticNamesCount\">Number of items in the statisticNames array.</param>\n/// <param name=\"async\">Used for async call.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Note that stat names are case insensitive.  \n/// To get the result, call <see cref=\"XAsyncGetStatus\"/> inside \n/// the AsyncBlock callback or after the AsyncBlock is complete.  \n/// If the call fails for any reason, it is the responsibility of the game to re-submit the request.\n/// </remarks>\nSTDAPI XblTitleManagedStatsDeleteStatsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/title_storage_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n#define XBL_TITLE_STORAGE_MIN_UPLOAD_BLOCK_SIZE 1024\n#define XBL_TITLE_STORAGE_MAX_UPLOAD_BLOCK_SIZE (4 * 1024 * 1024)\n#define XBL_TITLE_STORAGE_DEFAULT_UPLOAD_BLOCK_SIZE (256 * 1024)\n#define XBL_TITLE_STORAGE_MIN_DOWNLOAD_BLOCK_SIZE 1024\n#define XBL_TITLE_STORAGE_DEFAULT_DOWNLOAD_BLOCK_SIZE (1024 * 1024)\n\n#define XBL_TITLE_STORAGE_BLOB_PATH_MAX_LENGTH (257 * 3)\n#define XBL_TITLE_STORAGE_BLOB_DISPLAY_NAME_MAX_LENGTH (129 * 3)\n#define XBL_TITLE_STORAGE_BLOB_ETAG_MAX_LENGTH (18 * 3) \n\n/// <summary>\n/// Defines values used to indicate title storage type.\n/// </summary>\nenum class XblTitleStorageType : uint32_t\n{\n    /// <summary>\n    /// Per-user data storage such as game state or game settings that can be only be accessed by Xbox consoles.  \n    /// User restrictions can be configured to public or owner only in the service configuration.\n    /// </summary>\n    TrustedPlatformStorage,\n\n    /// <summary>\n    /// Global data storage.  This storage type is only writable via title configuration sites or Xbox Live developer tools.  \n    /// Any platform may read from this storage type.  Data could be rosters, maps, challenges, art resources, etc.\n    /// </summary>\n    GlobalStorage,\n\n    /// <summary>\n    /// Per-user data storage such as game state or game settings that can be accessed by Xbox consoles, Windows 10, and mobile devices.  \n    /// User restrictions can be configured to public or owner only in the service configuration.\n    /// </summary>\n    Universal\n};\n\n/// <summary>\n/// Defines values used to indicate title storage blob type.\n/// </summary>\nenum class XblTitleStorageBlobType : uint32_t\n{\n    /// <summary>\n    /// Unknown blob type.\n    /// </summary>\n    Unknown,\n\n    /// <summary>\n    /// Binary blob type.\n    /// </summary>\n    Binary,\n\n    /// <summary>\n    /// JSON blob type.\n    /// </summary>\n    Json,\n\n    /// <summary>\n    /// Config blob type.\n    /// </summary>\n    Config\n};\n\n/// <summary>\n/// Defines values used to indicate the ETag match condition used when downloading, uploading or deleting title storage data.\n/// </summary>\nenum class XblTitleStorageETagMatchCondition : uint32_t\n{\n    /// <summary>\n    /// There is no match condition.\n    /// </summary>\n    NotUsed,\n\n    /// <summary>\n    /// Perform the request if the Etag value specified matches the service value.\n    /// </summary>\n    IfMatch,\n\n    /// <summary>\n    /// Perform the request if the Etag value specified does not match the service value.\n    /// </summary>\n    IfNotMatch\n};\n\n/// <summary>\n/// Metadata about a blob.\n/// </summary>\ntypedef struct XblTitleStorageBlobMetadata\n{\n    /// <summary>\n    /// Blob path is a unique string that conforms to a SubPath\\file format (example: \"foo\\bar\\blob.txt\").\n    /// </summary>\n    _Null_terminated_ char blobPath[XBL_TITLE_STORAGE_BLOB_PATH_MAX_LENGTH];\n\n    /// <summary>\n    /// Type of blob data. Possible values are: Binary, Json, and Config.\n    /// </summary>\n    XblTitleStorageBlobType blobType;\n\n    /// <summary>\n    /// Type of storage.\n    /// </summary>\n    XblTitleStorageType storageType;\n\n    /// <summary>\n    /// [optional] Friendly display name to show in app UI.\n    /// </summary>\n    _Null_terminated_ char displayName[XBL_TITLE_STORAGE_BLOB_DISPLAY_NAME_MAX_LENGTH];\n\n    /// <summary>\n    /// ETag for the file used in read and write requests.\n    /// </summary>\n    _Null_terminated_ char eTag[XBL_TITLE_STORAGE_BLOB_ETAG_MAX_LENGTH];\n\n    /// <summary>\n    /// [optional] Timestamp assigned by the client.\n    /// </summary>\n    time_t clientTimestamp;\n\n    /// <summary>\n    /// Gets the number of bytes of the blob data.\n    /// </summary>\n    size_t length;\n\n    /// <summary>\n    /// The service configuration ID of the title\n    /// </summary>\n    _Null_terminated_ char serviceConfigurationId[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// The Xbox User ID of the player this file belongs to.  \n    /// This value will be null for Global and Session files.\n    /// </summary>\n    uint64_t xboxUserId;\n} XblTitleStorageBlobMetadata;\n\n/// <summary>\n/// A handle that represents metadata about blob data returned from the cloud.\n/// </summary>\ntypedef struct XblTitleStorageBlobMetadataResult* XblTitleStorageBlobMetadataResultHandle;\n\n/// <summary>\n/// Get a list of XblTitleStorageBlobMetadata objects.\n/// </summary>\n/// <param name=\"resultHandle\">Title storage blob metadata result handle.</param>\n/// <param name=\"items\">Passes back a pointer to an array of XblTitleStorageBlobMetadata objects.  \n/// The memory for the returned pointer remains valid for the life of \n/// the XblTitleStorageBlobMetadataResultHandle object until it is closed.</param>\n/// <param name=\"itemsCount\">Passes back the number of objects in the items array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This memory of the list is freed when the XblTitleStorageBlobMetadataResultHandle is closed \n/// with <see cref=\"XblTitleStorageBlobMetadataResultCloseHandle\"/>.\n/// </remarks>\nSTDAPI XblTitleStorageBlobMetadataResultGetItems(\n    _In_ XblTitleStorageBlobMetadataResultHandle resultHandle,\n    _Out_ const XblTitleStorageBlobMetadata** items,\n    _Out_ size_t* itemsCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Checks if there are more pages of XblTitleStorageBlobMetadata to retrieve from the service.\n/// </summary>\n/// <param name=\"resultHandle\">Title storage blob metadata result handle.</param>\n/// <param name=\"hasNext\">Passes back true if there are more results to retrieve, false otherwise.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To retrieve the next page of items, call <see cref=\"XblTitleStorageBlobMetadataResultGetNextAsync\"/>.\n/// </remarks>\nSTDAPI XblTitleStorageBlobMetadataResultHasNext(\n    _In_ XblTitleStorageBlobMetadataResultHandle resultHandle,\n    _Out_ bool* hasNext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Retrieves the next page of XblTitleStorageBlobMetadata objects.\n/// </summary>\n/// <param name=\"resultHandle\">Title storage blob metadata result handle.</param>\n/// <param name=\"maxItems\">The maximum number of items the result can contain. Pass 0 to attempt to retrieve all items.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XblTitleStorageBlobMetadataResultGetNextResult\"/> inside \n/// the AsyncBlock callback or after the AsyncBlock is complete.\n/// </remarks>\nSTDAPI XblTitleStorageBlobMetadataResultGetNextAsync(\n    _In_ XblTitleStorageBlobMetadataResultHandle resultHandle,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for a completed XblTitleStorageBlobMetadataResultGetNextAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblTitleStorageBlobMetadataResultGetNextAsync.</param>\n/// <param name=\"result\">Passes back the next XblTitleStorageBlobMetadataResultHandle.  \n/// Note that this is a separate handle than the one passed to the XblTitleStorageBlobMetadataResultGetNextAsync API.  \n/// Each result handle must be closed separately.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblTitleStorageBlobMetadataResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadataResultHandle* result\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates a XblTitleStorageBlobMetadataResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblTitleStorageBlobMetadataResultHandle to duplicate.</param>\n/// <param name=\"duplicatedHandle\">Passes back the duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblTitleStorageBlobMetadataResultDuplicateHandle(\n    _In_ XblTitleStorageBlobMetadataResultHandle handle,\n    _Out_ XblTitleStorageBlobMetadataResultHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Closes the XblTitleStorageBlobMetadataResultHandle.\n/// </summary>\n/// <param name=\"handle\">The XblTitleStorageBlobMetadataResultHandle to close.</param>\n/// <returns></returns>\n/// <remarks>\n/// When all outstanding handles have been closed, the memory associated with the title storage blob metadata result will be freed.\n/// </remarks>\nSTDAPI_(void) XblTitleStorageBlobMetadataResultCloseHandle(\n    _In_ XblTitleStorageBlobMetadataResultHandle handle\n) XBL_NOEXCEPT;\n    \n/// <summary>\n/// Gets title storage quota information for the specified service configuration and storage type.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"storageType\">The storage type to get quota information for.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// For TrustedPlatform storage types, the request will be made for the calling user's Xbox user Id.  \n/// To get the result, call XblTitleStorageGetQuotaResult inside the AsyncBlock callback\n/// or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}</rest>\n/// <rest>V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}</rest>\n/// <rest>V1 GET json/users/xuid({xuid})/scids/{scid}</rest>\n/// <rest>V1 GET global/scids/{scid}</rest>\nSTDAPI XblTitleStorageGetQuotaAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ XblTitleStorageType storageType,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for a completed XblTitleStorageGetQuotaAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblTitleStorageGetQuotaAsync.</param>\n/// <param name=\"usedBytes\">Passes back the number of bytes used in title storage of type StorageType.</param>\n/// <param name=\"quotaBytes\">Passes back the maximum number of bytes that can be used in title storage of type StorageType.  \n/// Note that this is a soft limit and the used bytes may actually exceed this value.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblTitleStorageGetQuotaResult(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* usedBytes,\n    _Out_ size_t* quotaBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets a list of blob metadata objects under a given path for the specified service configuration, storage type and storage ID.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"storageType\">The storage type to get blob metadata objects for.</param>\n/// <param name=\"blobPath\">The root path to enumerate.  Results will be for blobs contained in this path and all subpaths. (Optional)</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the title storage to enumerate. Ignored when enumerating GlobalStorage, so passing 0 is acceptable. (Optional)</param>\n/// <param name=\"skipItems\">The number of items to skip before returning results. (Optional)</param>\n/// <param name=\"maxItems\">The maximum number of items to return. Pass 0 to attempt to retrieve all items. (Optional)</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call XblTitleStorageGetBlobMetadataResult inside the AsyncBlock callback\n/// or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path}?maxItems={maxItems}[skipItems={skipItems}]</rest>\n/// <rest>V1 GET json/users/xuid({xuid})/scids/{scid}/data/{path}?maxItems={maxItems}[skipItems={skipItems}]</rest>\n/// <rest>V1 GET global/scids/{scid}/data/{path}?maxItems={maxItems}[skipItems={skipItems}]</rest>\nSTDAPI XblTitleStorageGetBlobMetadataAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ XblTitleStorageType storageType,\n    _In_z_ const char* blobPath,\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n    \n/// <summary>\n/// Get the result for a completed XblTitleStorageGetBlobMetadataAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblTitleStorageGetBlobMetadataAsync.</param>\n/// <param name=\"result\">Passes back the title storage blob metadata result handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblTitleStorageGetBlobMetadataResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadataResultHandle* result\n) XBL_NOEXCEPT;\n    \n/// <summary>\n/// Deletes a blob from title storage.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"blobMetadata\">The blob metadata for the title storage blob to delete.</param>\n/// <param name=\"deleteOnlyIfEtagMatches\">Specifies whether or not to have the delete operation check that the ETag matches before deleting the blob.</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The result of the asynchronous operation can be obtained by calling <see cref=\"XAsyncGetStatus\"/>\n/// inside the AsyncBlock callback or after the AsyncBlock is complete.\n/// </remarks>\n/// <rest>V1 DELETE trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 DELETE json/users/xuid({xuid})/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 DELETE sessions/{sessionId}/scids/{scid}/data/{path},{type}</rest>\nSTDAPI XblTitleStorageDeleteBlobAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ bool deleteOnlyIfEtagMatches,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Downloads blob data from title storage.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"blobMetadata\">The blob metadata for the title storage blob to download.</param>\n/// <param name=\"blobBuffer\">A caller allocated buffer that passes back the downloaded blob data.  \n/// This buffer needs to be large enough to store the blob being downloaded.  \n/// If necessary, the length required for the buffer can be retrieved by getting the blob metadata.</param>\n/// <param name=\"blobBufferCount\">The length of blobBuffer.</param>\n/// <param name=\"etagMatchCondition\">The ETag match condition used to determine if the blob should be downloaded.</param>\n/// <param name=\"selectQuery\">ConfigStorage filter string or JSONStorage json property name string to filter. (Optional)</param>\n/// <param name=\"preferredDownloadBlockSize\">The preferred download block size in bytes for binary blobs. Pass 0 to use the default size. (Optional)</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// To get the result, call <see cref=\"XblTitleStorageDownloadBlobResult\"/> inside the AsyncBlock callback\n/// or after the AsyncBlock is complete.  \n/// This method will return E_NOT_SUFFICIENT_BUFFER (0x8007007A) if the blobBuffer doesn't have enough capacity to hold the blob data.\n/// </remarks>\n/// <rest>V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 GET json/users/xuid({xuid})/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 GET global/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 GET sessions/{sessionId}/scids/{scid}/data/{path},{type}</rest>\nSTDAPI XblTitleStorageDownloadBlobAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _Out_writes_(blobBufferCount) uint8_t* blobBuffer,\n    _In_ size_t blobBufferCount,\n    _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n    _In_opt_z_ const char* selectQuery,\n    _In_ size_t preferredDownloadBlockSize,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for a completed XblTitleStorageDownloadBlobAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblTitleStorageDownloadBlobAsync.</param>\n/// <param name=\"blobMetadata\">A caller allocated XblTitleStorageBlobMetadata that passes back the downloaded blob metadata.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblTitleStorageDownloadBlobResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadata* blobMetadata\n) XBL_NOEXCEPT;\n    \n/// <summary>\n/// Uploads blob data to title storage.\n/// </summary>\n/// <param name=\"xboxLiveContext\">An xbox live context handle created with XblContextCreateHandle.</param>\n/// <param name=\"blobMetadata\">Contains properties required to upload the buffer to title storage.  \n/// Uploads require a service configuration Id, blob path, blob type and storage type at a minimum.</param>\n/// <param name=\"blobBuffer\">The buffer containing the blob data to upload.  \n/// This buffer must be available for the duration of the async operation.  \n/// Clients should not modify the buffer while an upload is in progress.</param>\n/// <param name=\"blobBufferCount\">The length of blobBuffer.</param>\n/// <param name=\"etagMatchCondition\">The ETag match condition used to determine if the blob data should be uploaded.</param>\n/// <param name=\"preferredUploadBlockSize\">The preferred upload block size in bytes for binary blobs.  \n/// Binary blobs will be uploaded in multiple chunks of this size if they exceed it.  \n/// Larger sizes are preferred by the service.  \n/// If timeouts occur, the app should retry with a smaller size.  \n/// Block size must be within the 1K to 4MB range.  \n/// This method will use a default size if this parameter is not within the acceptable range.  \n/// The current minimum size is 1024 bytes, maximum size is 4194304 bytes and the default size is 262144 bytes. (Optional)</param>\n/// <param name=\"async\">Caller allocated AsyncBlock.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <rest>V1 PUT json/users/xuid({xuid})/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 PUT global/scids/{scid}/data/{path},{type}</rest>\n/// <rest>V1 PUT sessions/{sessionId}/scids/{scid}/data/{path},{type}</rest>\nSTDAPI XblTitleStorageUploadBlobAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ const uint8_t* blobBuffer,\n    _In_ size_t blobBufferCount,\n    _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n    _In_ size_t preferredUploadBlockSize,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n    \n/// <summary>\n/// Get the result for a completed XblTitleStorageUploadBlobAsync operation.\n/// </summary>\n/// <param name=\"async\">The same AsyncBlock that passed to XblTitleStorageUploadBlobAsync.</param>\n/// <param name=\"blobMetadata\">A caller allocated XblTitleStorageBlobMetadata that passes back the uploaded blob metadata.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblTitleStorageUploadBlobResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadata* blobMetadata\n) XBL_NOEXCEPT;\n    \n}\n"
  },
  {
    "path": "Include/xsapi-c/types_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include <stdint.h>\n#include \"pal.h\"\n#include \"Xal/xal_types.h\"\n\nextern \"C\"\n{\n\n// Xbox live error codes.\n// FACILITY_XBOX + 0x5200 + offset\n#define E_XBL_RUNTIME_ERROR                     _HRESULT_TYPEDEF_(0x89235200)\n#define E_XBL_RTA_GENERIC_ERROR                 _HRESULT_TYPEDEF_(0x89235201)\n#define E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED    _HRESULT_TYPEDEF_(0x89235202)\n#define E_XBL_RTA_ACCESS_DENIED                 _HRESULT_TYPEDEF_(0x89235203)\n#define E_XBL_AUTH_UNKNOWN_ERROR                _HRESULT_TYPEDEF_(0x89235204)\n#define E_XBL_AUTH_RUNTIME_ERROR                _HRESULT_TYPEDEF_(0x89235205)\n#define E_XBL_AUTH_NO_TOKEN                     _HRESULT_TYPEDEF_(0x89235206)\n#define E_XBL_ALREADY_INITIALIZED               _HRESULT_TYPEDEF_(0x89235207)\n#define E_XBL_NOT_INITIALIZED                   _HRESULT_TYPEDEF_(0x89235208)\n#define E_XBL_RTA_NOT_ACTIVATED                 _HRESULT_TYPEDEF_(0x89235209)\n\n// Xbox live size constants\n#define XBL_COLOR_CHAR_SIZE                     (7 * 3)\n#define XBL_DISPLAY_NAME_CHAR_SIZE              (30 * 3)\n#define XBL_DISPLAY_PIC_URL_RAW_CHAR_SIZE       (225 * 3)\n#define XBL_GAMERSCORE_CHAR_SIZE                (16 * 3)\n#define XBL_GAMERTAG_CHAR_SIZE                  (16 * 3)\n#define XBL_MODERN_GAMERTAG_CHAR_SIZE           (((12 + 12) * 4) + 1) // 12 characters + 12 diacritic, 4 bytes each, plus 1 byte null terminator\n#define XBL_MODERN_GAMERTAG_SUFFIX_CHAR_SIZE    (14 + 1) // 14 alphanumeric characters + null terminator\n#define XBL_UNIQUE_MODERN_GAMERTAG_CHAR_SIZE    (XBL_MODERN_GAMERTAG_CHAR_SIZE + 1 + 3 ) // modern gamertag + '#' + max suffix size for cases when MGT display length is 12. Null terminator already accoutned for in MGT\n#define XBL_REAL_NAME_CHAR_SIZE                 (255 * 3)\n#define XBL_RICH_PRESENCE_CHAR_SIZE             (100 * 3)\n#define XBL_TITLE_NAME_CHAR_SIZE                (100 * 3)\n#define XBL_XBOX_USER_ID_CHAR_SIZE              (21 * 3)\n#define XBL_LAST_TIME_PLAYED_CHAR_SIZE          (25 * 3)\n\n#define XBL_GUID_LENGTH                         40\n#define XBL_SCID_LENGTH                         XBL_GUID_LENGTH\n\n/// <summary>\n/// Handle to the underlying user used to create an Xbox Live context.\n/// </summary>\n#if HC_PLATFORM == HC_PLATFORM_GDK\ntypedef XUserHandle XblUserHandle;\n#else\ntypedef XalUserHandle XblUserHandle;\n#endif\n\n/// <summary>\n/// A context token returned when registering a callback/handler to identify the registration.  \n/// This context token is later used to unregister the callback/handler.\n/// A value of 0 indicates and invalid handler token.\n/// </summary>\ntypedef int32_t XblFunctionContext;\n\n/// <summary>\n/// Handle to an Xbox live context.  \n/// Needed to interact with Xbox live services.\n/// </summary>\ntypedef struct XblContext* XblContextHandle;\n\n/// <summary>\n/// Generic Guid struct.  \n/// Used by various Xbox live services.\n/// </summary>\ntypedef struct XblGuid\n{\n    /// <summary>\n    /// The stored Guid.\n    /// </summary>\n    _Null_terminated_ char value[XBL_GUID_LENGTH];\n} XblGuid;\n\n}\n"
  },
  {
    "path": "Include/xsapi-c/user_statistics_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n#error C++11 required\n#endif\n\n#include \"real_time_activity_c.h\"\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Contains information about a user statistic.\n/// </summary>\n/// <memof><see cref=\"XblServiceConfigurationStatistic\"/></memof>\n/// <memof><see cref=\"XblStatisticChangeEventArgs\"/></memof>\ntypedef struct XblStatistic\n{\n    /// <summary>\n    /// The name of the statistic.\n    /// </summary>\n    _Field_z_ const char* statisticName;\n\n    /// <summary>\n    /// The type of the statistic.\n    /// </summary>\n    _Field_z_ const char* statisticType;\n\n    /// <summary>\n    /// The value of the statistic.\n    /// </summary>\n    _Field_z_ const char* value;\n} XblStatistic;\n\n/// <summary>\n/// Contains statistical information from a service configuration.\n/// </summary>\n/// <memof><see cref=\"XblUserStatisticsResult\"/></memof>\ntypedef struct XblServiceConfigurationStatistic\n{\n    /// <summary>\n    /// The service configuration ID (SCID) associated with the leaderboard.\n    /// </summary>\n    _Null_terminated_ char serviceConfigurationId[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// A collection of statistics used in leaderboards.\n    /// </summary>\n    XblStatistic* statistics;\n\n    /// <summary>\n    /// The size of **statistics**.\n    /// </summary>\n    uint32_t statisticsCount;\n} XblServiceConfigurationStatistic;\n\n/// <summary>\n/// Represents the results of a user statistic query.\n/// </summary>\n/// <argof><see cref=\"XblUserStatisticsGetSingleUserStatisticResult\"/></argof>\n/// <argof><see cref=\"XblUserStatisticsGetSingleUserStatisticsResult\"/></argof>\n/// <argof><see cref=\"XblUserStatisticsGetMultipleUserStatisticsResult\"/></argof>\n/// <argof><see cref=\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult\"/></argof>\ntypedef struct XblUserStatisticsResult\n{\n    /// <summary>\n    /// The Xbox User ID for the user in a statistic.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// A collection of statistics from a service configuration.\n    /// </summary>\n    XblServiceConfigurationStatistic* serviceConfigStatistics;\n\n    /// <summary>\n    /// The size of **serviceConfigStatistics**.\n    /// </summary>\n    uint32_t serviceConfigStatisticsCount;\n} XblUserStatisticsResult;\n\n/// <summary>\n/// Represents the results of a user statistic query.\n/// </summary>\n/// <argof><see cref=\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\"/></argof>\ntypedef struct XblRequestedStatistics\n{\n    /// <summary>\n    /// The service configuration ID in use.\n    /// </summary>\n    _Null_terminated_ char serviceConfigurationId[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// A collection of statistics.\n    /// </summary>\n    _Field_z_ const char** statistics;\n\n    /// <summary>\n    /// The size of **statistics**.\n    /// </summary>\n    uint32_t statisticsCount;\n} XblRequestedStatistics;\n\n/// <summary>\n/// Contains information about a change to a subscribed statistic.\n/// </summary>\n/// <argof><see cref=\"XblStatisticChangedHandler\"/></argof>\ntypedef struct XblStatisticChangeEventArgs\n{\n    /// <summary>\n    /// The Xbox user ID used to create the subscription.\n    /// </summary>\n    uint64_t xboxUserId;\n\n    /// <summary>\n    /// The service configuration ID used to create the subscription.\n    /// </summary>\n    _Null_terminated_ char serviceConfigurationId[XBL_SCID_LENGTH];\n\n    /// <summary>\n    /// The statistic with an updated value.\n    /// </summary>\n    XblStatistic latestStatistic;\n} XblStatisticChangeEventArgs;\n\n/// <summary>\n/// Get a specified statistic for a specified user.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player to get statistics for.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"statisticName\">The name of the statistic to return.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If multiple statistics are required for a single user, use this batch API instead: <see cref=\"XblUserStatisticsGetSingleUserStatisticsAsync\"/>\n/// If statistics are needed for multiple users, use this batch API: <see cref=\"XblUserStatisticsGetMultipleUserStatisticsAsync\"/>\n/// Call <see cref=\"XblUserStatisticsGetSingleUserStatisticResultSize\"/> and <see cref=\"XblUserStatisticsGetSingleUserStatisticResult\"/> \n/// upon completion to get the result.\n/// </remarks>\n/// <rest>V1 GET /users/xuid({xuid})/scids/{scid}/stats/{statname1}</rest>\nSTDAPI XblUserStatisticsGetSingleUserStatisticAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* statisticName,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblUserStatisticsGetSingleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes bakc the size in bytes required to store the user statistics result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsGetSingleUserStatisticResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblUserStatisticsGetSingleUserStatisticAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblUserStatisticsGetSingleUserStatisticResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the single user statistic.</param>\n/// <param name=\"ptrToBuffer\">Passes back a strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsGetSingleUserStatisticResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get specified statistics for a single user.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player to get statistics for.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"statisticNames\">A collection of statistic names to lookup.</param>\n/// <param name=\"statisticNamesCount\">The number of statistic names.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblUserStatisticsGetSingleUserStatisticsResultSize\"/> and <see cref=\"XblUserStatisticsGetSingleUserStatisticsResult\"/>\n/// upon completion to get the result. Only statistics with values are returned.  \n/// For example, if you ask for 3 statistic names and only 2 have values, \n/// only 2 statistics are returned by the service.\n/// </remarks>\n/// <rest>V1 GET /users/xuid({xuid})/scids/{scid}/stats/{statname1},...,{statnameN}</rest>\nSTDAPI XblUserStatisticsGetSingleUserStatisticsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblUserStatisticsGetSingleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the user statistics result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsGetSingleUserStatisticsResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblUserStatisticsGetSingleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblUserStatisticsGetSingleUserStatisticsResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the single user statistics.</param>\n/// <param name=\"ptrToBuffer\">Passes back a strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsGetSingleUserStatisticsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get statistics for multiple users.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserIds\">A list of the user Xbox user IDs to get stats for.</param>\n/// <param name=\"xboxUserIdsCount\">The number of Xbox user IDs.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"statisticNames\">A collection of statistic names to lookup.</param>\n/// <param name=\"statisticNamesCount\">The number of statistic names.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblUserStatisticsGetMultipleUserStatisticsResultSize\"/> and <see cref=\"XblUserStatisticsGetMultipleUserStatisticsResult\"/>\n/// upon completion to get the result. Only statistics with values are returned.  \n/// For example, if you ask for 3 statistic names and only 2 have values, \n/// only 2 statistics are returned by the service.\n/// </remarks>\n/// <rest>V1 POST /batch</rest>\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblUserStatisticsGetMultipleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the user statistics result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks></remarks>\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblUserStatisticsGetMultipleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblUserStatisticsGetMultipleUserStatisticsResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the multiple user statistics.</param>\n/// <param name=\"ptrToBuffer\">Passes back a strongly typed pointer that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"resultsCount\">Passes back the number of user statistics results.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks></remarks>\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** ptrToBuffer,\n    _Out_ size_t* resultsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get statistics for users across different Service configurations.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserIds\">A list of the user Xbox user ID to get stats for.</param>\n/// <param name=\"xboxUserIdsCount\">A list of the user Xbox user ID to get stats for.</param>\n/// <param name=\"requestedServiceConfigurationStatisticsCollection\">A list of the service config IDs and its associated array of statistics.</param>\n/// <param name=\"requestedServiceConfigurationStatisticsCollectionCount\">The number of the service config IDs and its associated array of statistics.</param>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Call <see cref=\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize\"/> \n/// and <see cref=\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult\"/> \n/// upon completion to get the result. Only statistics with values are returned.  \n/// For example, if you ask for 3 statistic names and only 2 have values, \n/// only 2 statistics are returned by the service.\n/// </remarks>\n/// <rest>V1 POST /batch</rest>\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t* xboxUserIds,\n    _In_ uint32_t xboxUserIdsCount,\n    _In_ const XblRequestedStatistics* requestedServiceConfigurationStatisticsCollection,\n    _In_ uint32_t requestedServiceConfigurationStatisticsCollectionCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result size for an XblUserStatisticsGetMultipleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">Passes back the size in bytes required to store the user statistics result.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the result for an XblUserStatisticsGetMultipleUserStatisticsAsync call.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.  \n/// Use <see cref=\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize\"/> to get the size required.</param>\n/// <param name=\"buffer\">A caller allocated byte buffer that passes back the multiple user statistics.</param>\n/// <param name=\"ptrToBufferResults\">Passes back a strongly typed array of XblUserStatisticsResult that points into buffer.  \n/// Do not free this as its lifecycle is tied to buffer.</param>\n/// <param name=\"resultsCount\">Passes back the number of results.</param>\n/// <param name=\"bufferUsed\">Passes back the number of bytes written to the buffer.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** ptrToBufferResults,\n    _Out_ size_t* resultsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Subscribes to statistic update notifications via the StatisticChanged event.\n/// DEPRECATED. This continues to work, however it will be removed in a future release. \n/// Individual RTA subscription will be managed automatically by XSAPI as statistics are tracked with <see cref=\"XblUserStatisticsTrackStatistics\"/>.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserId\">The Xbox User ID of the player requesting the subscription.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"statisticName\">The name of the statistic to subscribe to.</param>\n/// <param name=\"subscriptionHandle\">Passes back an XblRealTimeActivitySubscriptionHandle object that contains the state of the subscription.  \n/// You can register an event handler for statistic changes by calling XblUserStatisticsAddStatisticChangedHandler().</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblUserStatisticsSubscribeToStatisticChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* statisticName,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unsubscribes a previously created statistic change subscription.\n/// DEPRECATED. This continues to work, however it will be removed in a future release. \n/// Individual RTA subscription will be managed automatically by XSAPI as statistics are untracked with <see cref=\"XblUserStatisticsStopTrackingStatistics\"/>\n/// or <see cref=\"XblUserStatisticsStopTrackingUsers\"/>\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"subscriptionHandle\">The subscription object to unsubscribe.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI_XBL_DEPRECATED XblUserStatisticsUnsubscribeFromStatisticChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Event handler for statistic change notifications.\n/// </summary>\n/// <param name=\"statisticChangeEventArgs\">Contains information about a change to a subscribed statistic.</param>\n/// <param name=\"context\">Caller context that will be passed back to the handler.</param>\n/// <returns></returns>\n/// <argof><see cref=\"XblUserStatisticsAddStatisticChangedHandler\"/></argof>\ntypedef void CALLBACK XblStatisticChangedHandler(\n    _In_ XblStatisticChangeEventArgs statisticChangeEventArgs,\n    _In_ void* context\n);\n\n/// <summary>\n/// Registers an event handler for statistic change notifications.\n/// Event handlers receive a XblStatisticChangeEventArgs object.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"handler\">The callback function that receives notifications.</param>\n/// <param name=\"handlerContext\">Client context pointer to be passed back to the handler.</param>\n/// <returns>A XblFunctionContext object that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblUserStatisticsAddStatisticChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblStatisticChangedHandler handler,\n    _In_opt_ void* handlerContext\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters an event handler for statistic change notifications.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"context\">The function_context object that was returned when the event handler was registered.</param>\n/// <returns></returns>\nSTDAPI_(void) XblUserStatisticsRemoveStatisticChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the set of stats that will be tracked real-time. This call will have no affect on stats\n/// that were already being tracked.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserIds\">Array of XboxUserIDs for whom to track the provided stats.</param>\n/// <param name=\"xboxUserIdsCount\">Length of xboxUserIds array.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"statisticNames\">Array of statistic names for which real-time updates will be received.</param>\n/// <param name=\"statisticNamesCount\">Length of statisticNames array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Updates will be delivered via XblStatisticChangedHandlers.\n/// Note that the set of tracked stats can be updated independent from the handlers.\n/// </remarks>\nSTDAPI XblUserStatisticsTrackStatistics(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the set of stats that will be tracked real-time. Updates will no longer be received\n/// for the provided stats and users.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserIds\">Array of XboxUserIDs for whom to stop tracking the provided stats.</param>\n/// <param name=\"xboxUserIdsCount\">Length of xboxUserIds array.</param>\n/// <param name=\"serviceConfigurationId\">The Service Configuration ID (SCID) for the title. The SCID is considered case sensitive so paste it directly from the Partner Center.</param>\n/// <param name=\"statisticNames\">Array of statistic names for which real-time updates are no longer needed.</param>\n/// <param name=\"statisticNamesCount\">Length of statisticNames array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsStopTrackingStatistics(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Configures the set of stats that will be tracked real-time. The API will cancel all real-time\n/// stat updates for the provided users.\n/// </summary>\n/// <param name=\"xblContextHandle\">Xbox live context for the local user.</param>\n/// <param name=\"xboxUserIds\">Array of XboxUserIDs for whom to stop tracking the all stats.</param>\n/// <param name=\"xboxUserIdsCount\">Length of xboxUserIds array.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblUserStatisticsStopTrackingUsers(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount\n) XBL_NOEXCEPT;\n\n} // end extern c\n"
  },
  {
    "path": "Include/xsapi-c/xbox_live_context_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Creates an XblContextHandle used to access Xbox Live services.\n/// </summary>\n/// <param name=\"user\">The user associated with this Xbox Live context.</param>\n/// <param name=\"context\">Passes back the Xbox Live context handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblContextCreateHandle(\n    _In_ XblUserHandle user,\n    _Out_ XblContextHandle* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Duplicates the XblContextHandle.\n/// </summary>\n/// <param name=\"xboxLiveContextHandle\">The Xbox Live context handle.</param>\n/// <param name=\"duplicatedHandle\">Passes back the duplicated handle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Use this method rather than creating a new context with the same user \n/// if the XblContextHandle is needed by multiple components with independent lifespans.\n/// </remarks>\nSTDAPI XblContextDuplicateHandle(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _Out_ XblContextHandle* duplicatedHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Closes the XblContextHandle.\n/// </summary>\n/// <param name=\"xboxLiveContextHandle\">The Xbox Live context handle.</param>\n/// <returns></returns>\n/// <remarks>\n/// When all outstanding handles have been closed, XblContextCloseHandle() \n/// will free the memory associated with the handle.\n/// </remarks>\nSTDAPI_(void) XblContextCloseHandle(\n    _In_ XblContextHandle xboxLiveContextHandle\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the XblContextHandle associated with this context.\n/// </summary>\n/// <param name=\"context\">The Xbox Live context handle.</param>\n/// <param name=\"user\">Passes back the Xbox Live user handle.  \n/// XSAPI will call XalUserDuplicateHandle before returning the handle, \n/// so it is the responsibility of the caller to later call XalUserCloseHandle.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblContextGetUser(\n    _In_ XblContextHandle context,\n    _Out_ XblUserHandle* user\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the Xbox user ID of the user associated with the context.\n/// </summary>\n/// <param name=\"context\">The Xbox Live context handle.</param>\n/// <param name=\"xboxUserId\">Passes back the xbox user ID.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblContextGetXboxUserId(\n    _In_ XblContextHandle context,\n    _Out_ uint64_t* xboxUserId\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/xbox_live_context_settings_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n\nextern \"C\"\n{\n\n/// <summary>\n/// Gets the connect, send, and receive timeouts for HTTP socket operations of long calls such as Title Storage calls.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"timeoutInSeconds\">Passes back the timeout for long HTTP calls in seconds.  \n/// Default is 5 minutes (300 seconds).  </param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Calls that take longer than the given timeout are aborted.\n/// </remarks>\nSTDAPI XblContextSettingsGetLongHttpTimeout(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* timeoutInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the connect, send, and receive timeouts for HTTP socket operations of long calls such as Title Storage calls.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"timeoutInSeconds\">The timeout for long HTTP calls in seconds.  \n/// Default is 5 minutes (300 seconds).</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Calls that take longer than the given timeout are aborted.  \n/// Take care when setting this to smaller values as some calls like Title Storage may take a few minutes to complete.\n/// </remarks>\nSTDAPI XblContextSettingsSetLongHttpTimeout(\n    _In_ XblContextHandle context,\n    _In_ uint32_t timeoutInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the HTTP retry delay in seconds.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"delayInSeconds\">Passes back the retry delay in seconds.  \n/// Retries are delayed using an exponential back off.  \n/// By default, it will delay 2 seconds then the next retry will delay 4 seconds, then 8 seconds, \n/// and so on up to a max of 1 min until either the call succeeds or the http_timeout_window \n/// is reached, at which point the call will fail.  \n/// The delay is also jittered between the current and next delay to spread out service load.  \n/// The default for http_timeout_window is 20 seconds and can be changed using XblContextSettingsSetHttpTimeoutWindow.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the service returns an HTTP error with a \"Retry-After\" header, then all future calls to that API will \n/// immediately fail with the original error without contacting the service until the \"Retry-After\" time has been reached.  \n/// <br/>\n/// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:<br/>\n/// 408 (Request Timeout)<br/>\n/// 429 (Too Many Requests)<br/>\n/// 500 (Internal Server Error)<br/>\n/// 502 (Bad Gateway)<br/>\n/// 503 (Service Unavailable)<br/>\n/// 504 (Gateway Timeout)<br/>\n/// </remarks>\nSTDAPI XblContextSettingsGetHttpRetryDelay(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* delayInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the HTTP retry delay in seconds.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"delayInSeconds\">The retry delay in seconds.  \n/// Retries are delayed using an exponential back off.  \n/// By default, it will delay 2 seconds then the next retry will delay 4 seconds, then 8 seconds, \n/// and so on up to a max of 1 min until either the call succeeds or the http_timeout_window \n/// is reached, at which point the call will fail.  \n/// The delay is also jittered between the current and next delay to spread out service load.  \n/// The default for http_timeout_window is 20 seconds and can be changed using XblContextSettingsSetHttpTimeoutWindow.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If the service returns an HTTP error with a \"Retry-After\" header, then all future calls to that API will \n/// immediately fail with the original error without contacting the service until the \"Retry-After\" time has been reached.  \n/// <br/>\n/// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:<br/>\n/// 408 (Request Timeout)<br/>\n/// 429 (Too Many Requests)<br/>\n/// 500 (Internal Server Error)<br/>\n/// 502 (Bad Gateway)<br/>\n/// 503 (Service Unavailable)<br/>\n/// 504 (Gateway Timeout)<br/>\n/// </remarks>\nSTDAPI XblContextSettingsSetHttpRetryDelay(\n    _In_ XblContextHandle context,\n    _In_ uint32_t delayInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the HTTP timeout window in seconds.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"timeoutWindowInSeconds\">Passes back the timeout window in seconds.  \n/// The default is 20 seconds.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This controls how long to spend attempting to retry idempotent service calls before failing.<br/>\n/// <br/>\n/// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:<br/>\n/// 408 (Request Timeout)<br/>\n/// 429 (Too Many Requests)<br/>\n/// 500 (Internal Server Error)<br/>\n/// 502 (Bad Gateway)<br/>\n/// 503 (Service Unavailable)<br/>\n/// 504 (Gateway Timeout)<br/>\n/// </remarks>\nSTDAPI XblContextSettingsGetHttpTimeoutWindow(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* timeoutWindowInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the HTTP timeout window in seconds.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"timeoutWindowInSeconds\">The timeout window in seconds.  \n/// The default is 20 seconds.  \n/// Set to 0 to turn off retry.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This controls how long to spend attempting to retry idempotent service calls before failing.<br/>\n/// <br/>\n/// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:<br/>\n/// 408 (Request Timeout)<br/>\n/// 429 (Too Many Requests)<br/>\n/// 500 (Internal Server Error)<br/>\n/// 502 (Bad Gateway)<br/>\n/// 503 (Service Unavailable)<br/>\n/// 504 (Gateway Timeout)<br/>\n/// </remarks>\nSTDAPI XblContextSettingsSetHttpTimeoutWindow(\n    _In_ XblContextHandle context,\n    _In_ uint32_t timeoutWindowInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the web socket timeout window in seconds.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"timeoutWindowInSeconds\">Passes back the timeout window in seconds.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblContextSettingsGetWebsocketTimeoutWindow(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* timeoutWindowInSeconds\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Sets the web socket timeout window in seconds.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"timeoutWindowInSeconds\">The timeout window in seconds.  \n/// Default is 300 seconds.  \n/// Set to 0 to turn off retry.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Controls how long to spend attempting to retry establishing a web socket connection before failing.\n/// </remarks>\nSTDAPI XblContextSettingsSetWebsocketTimeoutWindow(\n    _In_ XblContextHandle context,\n    _In_ uint32_t timeoutWindowInSeconds\n) XBL_NOEXCEPT;\n\n// TODO these probably should be moved somewhere else, they aren't really related to context settings\n/// <summary>\n/// Gets whether to use the xplatqos server for QoS calls.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"value\">Passes back true if the cross platform QoS servers should be used, false otherwise.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblContextSettingsGetUseCrossPlatformQosServers(\n    _In_ XblContextHandle context,\n    _Out_ bool* value\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Controls whether we use cross platform qos endpoints or not.  \n/// In some case if you are shipping with TV_API enabled, you want to be able to choose.\n/// </summary>\n/// <param name=\"context\">Xbox live context that the settings are associated with.</param>\n/// <param name=\"value\">True if the cross platform QoS servers should be used, false otherwise.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblContextSettingsSetUseCrossPlatformQosServers(\n    _In_ XblContextHandle context,\n    _In_ bool value\n) XBL_NOEXCEPT;\n\n}"
  },
  {
    "path": "Include/xsapi-c/xbox_live_global_c.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#if !defined(__cplusplus)\n   #error C++11 required\n#endif\n\n#pragma once\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning(disable: 4265)\n#pragma warning(disable: 4266)\n#pragma warning(disable: 4062)\n#endif\n\n#if (!defined(HC_LINK_STATIC) || HC_LINK_STATIC == 0) && HC_PLATFORM_IS_APPLE\n#include <HttpClient/XAsync.h>\n#else\n#include <XAsync.h>\n#endif\n\nextern \"C\"\n{\n\n/////////////////////////////////////////////////////////////////////////////////////////\n// Memory APIs\n//\n\n/// <summary>\n/// A callback invoked every time a new memory buffer must be dynamically allocated by the library.  \n/// This callback is optionally installed by calling XblMemSetFunctions().\n/// </summary>\n/// <param name=\"size\">The size of the allocation to be made.  \n/// This value will never be zero.</param>\n/// <param name=\"memoryType\">An opaque identifier representing the \n/// internal category of memory being allocated.</param>\n/// <returns>A pointer to an allocated block of memory of the specified size, \n/// or a null pointer if allocation failed.</returns>\n/// <remarks>\n/// The callback must allocate and return a pointer to a contiguous block of memory of the \n/// specified size that will remain valid until the app's corresponding XblMemFreeFunction \n/// callback is invoked to release it.  \n/// Every non-null pointer returned by this method will be subsequently passed to the corresponding \n/// XblMemFreeFunction callback once the memory is no longer needed.\n/// </remarks>\ntypedef _Ret_maybenull_ _Post_writable_byte_size_(size) void*\n(STDAPIVCALLTYPE* XblMemAllocFunction)(\n    _In_ size_t size,\n    _In_ HCMemoryType memoryType\n);\n\n/// <summary>\n/// A callback invoked every time a previously allocated memory buffer is no longer needed by \n/// the library and can be freed.  \n/// This callback is optionally installed by calling XblMemSetFunctions().\n/// </summary>\n/// <param name=\"pointer\">The pointer to the memory buffer previously allocated.  \n/// This value will never be a null pointer.</param>\n/// <param name=\"memoryType\">An opaque identifier representing the internal category of \n/// memory being allocated.</param>\n/// <returns></returns>\n/// <remarks>\n/// The callback is invoked whenever the library has finished using a memory buffer previously \n/// returned by the app's corresponding XblMemAllocFunction such that the application can free the\n/// memory buffer.\n/// </remarks>\ntypedef void (STDAPIVCALLTYPE* XblMemFreeFunction)(\n    _In_ _Post_invalid_ void* pointer,\n    _In_ HCMemoryType memoryType\n);\n\n/// <summary>\n/// Optionally sets the memory hook functions to allow callers to control route memory \n/// allocations to their own memory manager.\n/// </summary>\n/// <param name=\"memAllocFunc\">A pointer to the custom allocation callback to use, or a null \n/// pointer to restore the default.</param>\n/// <param name=\"memFreeFunc\">A pointer to the custom freeing callback to use, or a null \n/// pointer to restore the default.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This must be called before XblInitialize() and can not be called again until XblCleanup().  \n/// This method allows the application to install custom memory allocation routines in order \n/// to service all requests for new memory buffers instead of using default allocation routines.  \n/// The <paramref name=\"memAllocFunc\"/> and <paramref name=\"memFreeFunc\"/> parameters can be null\n/// pointers to restore the default routines.  \n/// Both callback pointers must be null or both must be non-null.  \n/// Mixing custom and default routines is not permitted.\n/// </remarks>\nSTDAPI XblMemSetFunctions(\n    _In_opt_ XblMemAllocFunction memAllocFunc,\n    _In_opt_ XblMemFreeFunction memFreeFunc\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the memory hook functions to allow callers to control route memory allocations to their \n/// own memory manager.\n/// </summary>\n/// <param name=\"memAllocFunc\">Set to the current allocation callback.  \n/// Returns the default routine if not previously set.</param>\n/// <param name=\"memFreeFunc\">Set to the current memory free callback.  \n/// Returns the default routine if not previously set.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This method allows the application get the default memory allocation routines.  \n/// This can be used along with XblMemSetFunctions() to monitor all memory allocations.\n/// </remarks>\nSTDAPI XblMemGetFunctions(\n    _Out_ XblMemAllocFunction* memAllocFunc,\n    _Out_ XblMemFreeFunction* memFreeFunc\n) XBL_NOEXCEPT;\n\n/////////////////////////////////////////////////////////////////////////////////////////\n// Global APIs\n//\n\n/// <summary>\n/// Defines values representing the Xbox Live initialization arguments.\n/// </summary>\ntypedef struct XblInitArgs\n{\n    /// <summary>\n    /// Queue used for XSAPI internal asynchronous work (telemetry, rta, etc.).  \n    /// This field if optional - if not provided, a threadpool based queue will be used.\n    /// </summary>\n    XTaskQueueHandle queue;\n\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP)\n\n    /// <summary>\n    /// The Service Configuration ID (SCID) for the app.\n    /// You can find it on Partner Center in the Game Setup page under Identity details.\n    /// This string is considered case sensitive so paste it directly from the Partner Center\n    /// </summary>\n    _Field_z_ const char* scid;\n\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n\n    /// <summary>\n    /// A required reference to the application's Java VM.\n    /// </summary>\n    JavaVM* javaVM;\n\n    /// <summary>\n    /// A required reference to an instance of the application's context \n    /// provided by JNI.\n    /// </summary>\n    jobject applicationContext;\n\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n\n    /// <summary>\n    /// An optional reference to the iOS APNS environment.  \n    /// This field is required if the app is integrating with notifications.\n    /// </summary>\n    _Field_z_ const char* apnsEnvironment;\n\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n\n    /// <summary>\n    /// Local storage location for XSAPI.  \n    /// Used to cache data platform events in the event that they cannot be uploaded due to connectivity problems.  \n    /// This field is required and if custom local storage hooks are not set with \n    /// XblLocalStorageSetHandlers, otherwise it will be ignored.\n    /// </summary>\n    _Field_z_ const char* localStoragePath;\n\n#endif\n\n#if HC_PLATFORM_IS_EXTERNAL\n\n    /// <summary>\n    /// The id of the app.\n    /// </summary>\n    _Field_z_ char const* appId;\n\n    /// <summary>\n    /// App version.\n    /// </summary>\n    _Field_z_ char const* appVer;\n\n    /// <summary>\n    /// The os the app is running on.\n    /// </summary>\n    _Field_z_ char const* osName;\n\n    /// <summary>\n    /// The version of the os.\n    /// </summary>\n    _Field_z_ char const* osVersion;\n\n    /// <summary>\n    /// The locale the os is using.\n    /// </summary>\n    _Field_z_ char const* osLocale;\n\n    /// <summary>\n    /// The device type the app is running on.\n    /// </summary>\n    _Field_z_ char const* deviceClass;\n\n    /// <summary>\n    /// The id of the device.\n    /// </summary>\n    _Field_z_ char const* deviceId;\n\n#endif\n} XblInitArgs;\n\n/// <summary>\n/// Initializes the library instance.\n/// </summary>\n/// <param name=\"args\">Platform-specific args for XblInitialize.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This must be called before any other Xbl* method, except for XblMemSetFunctions() and XblMemGetFunctions().  \n/// Should have a corresponding call to XblCleanup().\n/// </remarks>\nSTDAPI XblInitialize(_In_ const XblInitArgs* args) XBL_NOEXCEPT;\n\n/// <summary>\n/// Immediately reclaims all resources associated with the library.\n/// </summary>\n/// <param name=\"async\">The AsyncBlock for this operation.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// If you called XblMemSetFunctions(), call this before shutting down your app's memory manager.  \n/// It is the responsibility of the game to wait for any outstanding Async calls to complete before calling XblCleanup.  \n/// If there are background async tasks started by XSAPI pending, this API will wait for them to complete.\n/// </remarks>\nSTDAPI XblCleanupAsync(\n    XAsyncBlock* async\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Gets the async queue that is used for XSAPI's internal asynchronous operations.\n/// </summary>\n/// <returns>Returns the async queue being used.</returns>\n/// <remarks>\n/// Note that this queue will be derived from the queue passed in during XblInitialize, not the exact same one.  \n/// Xsapi will call XTaskQueueDuplicateHandle before returning the queue, so XTaskQueueCloseHandle must be called\n/// later by callers.\n/// </remarks>\nSTDAPI_(XTaskQueueHandle) XblGetAsyncQueue() XBL_NOEXCEPT;\n\n/// <summary>\n/// Get the service configuration Id for the application.  \n/// This is set during XblInitialize.\n/// </summary>\n/// <param name=\"scid\">The service configuration Id for the app.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// This string will be valid until XblCleanup is called.\n/// </remarks>\nSTDAPI XblGetScid(\n    _Out_ const char** scid\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Defines the config settings value that is passed to the below API's.\n/// </summary>\nenum class XblConfigSetting : uint32_t\n{\n    /// <summary>\n    /// Only passed to the below API's to warn code reviewers that there's an outstanding Xbox Live calling \n    /// pattern issue that needs to be addressed.\n    /// </summary>\n    ThisCodeNeedsToBeChanged\n};\n\n/// <summary>\n/// Disables asserts for Xbox Live throttling in dev sandboxes.\n/// </summary>\n/// <param name=\"setting\">The config settings value to be passed down.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// The asserts will not fire in RETAIL sandbox, and this setting has no affect in RETAIL sandboxes.  \n/// It is best practice to not call this API, and instead adjust the calling pattern but this is provided \n/// as a temporary way to get unblocked while in early stages of game development.\n/// </remarks>\nSTDAPI_(void) XblDisableAssertsForXboxLiveThrottlingInDevSandboxes(\n    _In_ XblConfigSetting setting\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// For advanced scenarios where a common Service Configuration ID (SCID) and title Id are needed for cross platform experiences.\n/// </summary>\n/// <param name=\"overrideScid\">Override Service Configuration ID (SCID) to be used by multiplayer manager. This SCID is considered case sensitive so paste it directly from the Partner Center</param>\n/// <param name=\"overrideTitleId\">Override title Id to be used by multiplayer manager.</param>\n/// <returns>HRESULT return code for this API operation.</returns>\n/// <remarks>\n/// Currently only used by multiplayer manager to enable cross platform multiplayer scenarios.\n/// </remarks>\nSTDAPI XblSetOverrideConfiguration(\n    _In_ const char* overrideScid,\n    _In_ uint32_t overrideTitleId\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// To override the locale used across XSAPI. If not set, the default is to use the OS locale\n/// </summary>\n/// <param name=\"overrideLocale\">Override locale to be used</param>\n/// <returns>HRESULT return code for this API operation.</returns>\nSTDAPI XblSetOverrideLocale(\n    _In_ char const* overrideLocale\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Contains information about a service call.\n/// </summary>\ntypedef struct XblServiceCallRoutedArgs\n{\n    /// <summary>\n    /// Handle for the service call.\n    /// </summary>\n    HCCallHandle call;\n\n    /// <summary>\n    /// The number of responses in this session.\n    /// </summary>\n    uint64_t responseCount;\n\n    /// <summary>\n    /// Returns the a full response log formatted message of all the properties in XblServiceCallRoutedArgs.\n    /// </summary>\n    const char* fullResponseFormatted;\n} XblServiceCallRoutedArgs;\n\n/// <summary>\n/// A callback that will be synchronously invoked each time an HTTP call fails but will be automatically be retried.\n/// </summary>\n/// <param name=\"args\">Contains information about the HTTP call that failed.  \n/// The fields are only valid until the callback returns.</param>\n/// <param name=\"context\">Client context pass when the handler was added.</param>\n/// <returns></returns>\n/// <remarks>\n/// Can be used to track intermittent failures similar to fiddler.\n/// </remarks>\ntypedef void\n(STDAPIVCALLTYPE* XblCallRoutedHandler)(\n    _In_ XblServiceCallRoutedArgs args,\n    _In_opt_ void* context\n);\n\n/// <summary>\n/// Registers for all service call notifications.\n/// </summary>\n/// <param name=\"handler\">The event handler function to call.</param>\n/// <param name=\"context\">Caller context to be passed back to the handler.</param>\n/// <returns>A XblFunctionContext that can be used to unregister the event handler.</returns>\nSTDAPI_(XblFunctionContext) XblAddServiceCallRoutedHandler(\n    _In_ XblCallRoutedHandler handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Unregisters from all service call notifications.\n/// </summary>\n/// <param name=\"token\">The XblFunctionContext object that was returned when the event handler was registered.</param>\n/// <returns></returns>\nSTDAPI_(void) XblRemoveServiceCallRoutedHandler(\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT;\n\n/// <summary>\n/// Internal use only.\n/// </summary>\nenum class XblApiType\n{\n    /// <summary>\n    /// Using C API.\n    /// </summary>\n    XblCApi,\n\n    /// <summary>\n    /// Using C++ API.\n    /// </summary>\n    XblCPPApi\n};\n\n/// <summary>\n/// Internal method.\n/// </summary>\n/// <param name=\"apiType\">The internal API type.</param>\n/// <returns></returns>\nvoid XblSetApiType(\n    _In_ XblApiType apiType\n) XBL_NOEXCEPT;\n\n}\n"
  },
  {
    "path": "Include/xsapi-cpp/achievements.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xbox_live_app_config.h\"\n#include \"xsapi-cpp/system.h\"\n#include \"xsapi-c/achievements_c.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n\n    /// <summary>\n    /// Contains classes and enumerations that let you retrieve\n    /// information about player achievements from Xbox Live.\n    /// </summary>\n    namespace achievements {\n\n    class achievement_service_internal;\n\n/// <summary>Enumeration values that indicate the achievement type.</summary>\nenum class achievement_type\n{\n    /// <summary>The achievement type is unknown.</summary>\n    unknown,\n\n    /// <summary>Used as a request input parameter.\n    /// All means to get all achievements regardless of type.</summary>\n    all,\n\n    /// <summary>A persistent achievement that may be unlocked at any time.\n    /// Persistent achievements can give Gamerscore as a reward.</summary>\n    persistent,\n\n    /// <summary>A challenge achievement that may only be unlocked within a certain time period.\n    /// Challenge achievements can't give Gamerscore as a reward.</summary>\n    challenge\n};\n\n/// <summary>Enumeration values that indicate the achievement sort order.</summary>\nenum class achievement_order_by\n{\n    /// <summary>Default order does not guarantee sort order.</summary>\n    default_order,\n\n    /// <summary>Sort by title id.</summary>\n    title_id,\n\n    /// <summary>Sort by achievement unlock time.</summary>\n    unlock_time\n};\n\n/// <summary>Enumeration values that indicate the state of a player's progress towards unlocking an achievement.</summary>\nenum class achievement_progress_state\n{\n    /// <summary>Achievement progress is unknown.</summary>\n    unknown,\n\n    /// <summary>Achievement has been earned.</summary>\n    achieved,\n\n    /// <summary>Achievement progress has not been started.</summary>\n    not_started,\n\n    /// <summary>Achievement progress has started.</summary>\n    in_progress\n};\n\n/// <summary>\n/// Enumeration values that indicate the media asset type associated with\n/// the achievement.\n/// </summary>\nenum class achievement_media_asset_type\n{\n    /// <summary>The media asset type is unknown.</summary>\n    unknown,\n\n    /// <summary>An icon media asset.</summary>\n    icon,\n\n    /// <summary>An art media asset.</summary>\n    art\n};\n\n/// <summary>Enumeration values that indicate the participation type for an achievement.</summary>\nenum class achievement_participation_type\n{\n    /// <summary>The participation type is unknown.</summary>\n    unknown,\n\n    /// <summary>An achievement that can be earned as an individual participant.</summary>\n    individual,\n\n    /// <summary>An achievement that can be earned as a group participant.</summary>\n    group\n};\n\n/// <summary>Enumeration values that indicate the reward type for an achievement.</summary>\nenum class achievement_reward_type\n{\n    /// <summary>The reward type is unknown.</summary>\n    unknown,\n\n    /// <summary>A Gamerscore reward.</summary>\n    gamerscore,\n\n    /// <summary>An in-app reward, defined and delivered by the title.</summary>\n    in_app,\n\n    /// <summary>A digital art reward.</summary>\n    art\n};\n\n\n/// <summary>\n/// Represents the association between a title and achievements.\n/// </summary>\nclass achievement_title_association\n{\npublic:\n    /// <summary>\n    /// The localized name of the title.\n    /// </summary>\n    inline const string_t& name() const;\n\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    inline achievement_title_association(const XblAchievementTitleAssociation& association);\n\nprivate:\n    string_t m_name;\n    uint32_t m_titleId;\n};\n\n/// <summary>\n/// Represents requirements for unlocking the achievement.\n/// </summary>\nclass achievement_requirement\n{\npublic:\n    /// <summary>\n    /// The achievement requirement ID.\n    /// </summary>\n    inline const string_t& id() const;\n\n    /// <summary>\n    /// A value that indicates the current progress of the player towards meeting\n    /// the requirement.\n    /// </summary>\n    inline const string_t& current_progress_value() const;\n\n    /// <summary>\n    /// The target progress value that the player must reach in order to meet\n    /// the requirement.\n    /// </summary>\n    inline const string_t& target_progress_value() const;\n    \n    inline achievement_requirement(const XblAchievementRequirement& requirement);\n\nprivate:\n    string_t m_id;\n    string_t m_currentProgressValue;\n    string_t m_targetProgressValue;\n};\n\n/// <summary>\n/// Represents progress details about the achievement, including requirements.\n/// </summary>\nclass achievement_progression\n{\npublic:\n    /// <summary>\n    /// The actions and conditions that are required to unlock the achievement.\n    /// </summary>\n    inline const std::vector<achievement_requirement>& requirements() const;\n\n    /// <summary>\n    /// The timestamp when the achievement was first unlocked.\n    /// </summary>\n    inline const utility::datetime& time_unlocked() const;\n\n    inline achievement_progression(const XblAchievementProgression& progression);\n\nprivate:\n    std::vector<achievement_requirement> m_requirements;\n    utility::datetime m_timeUnlocked;\n};\n\n/// <summary>\n/// Represents an interval of time during which an achievement can be unlocked. \n/// This class is only used when the achievement_type enumeration is set to challenge.\n/// </summary>\nclass achievement_time_window\n{\npublic:\n    /// <summary>\n    /// The start date and time of the achievement time window.\n    /// </summary>\n    inline const utility::datetime& start_date() const;\n\n    /// <summary>\n    /// The end date and time of the achievement time window.\n    /// </summary>\n    inline const utility::datetime& end_date() const;\n    \n    inline achievement_time_window(const XblAchievementTimeWindow& timeWindow);\n\nprivate:\n    utility::datetime m_startDate;\n    utility::datetime m_endDate;\n};\n\n/// <summary>\n/// Represents a media asset for an achievement.\n/// </summary>\nclass achievement_media_asset\n{\npublic:\n    /// <summary>\n    /// The name of the media asset, such as \"tile01\".\n    /// </summary>\n    inline const string_t& name() const;\n\n    /// <summary>\n    /// The type of media asset.\n    /// </summary>\n    inline achievement_media_asset_type media_asset_type() const;\n\n    /// <summary>\n    /// The URL of the media asset.\n    /// </summary>\n    inline const web::uri& url() const;\n\n    inline achievement_media_asset(const XblAchievementMediaAsset* mediaAsset);\n\nprivate:\n    string_t m_name;\n    achievement_media_asset_type m_type{ achievement_media_asset_type::unknown };\n    web::uri m_url;\n};\n\n#if !XSAPI_NO_PPL\n/// <summary>\n/// Represents a reward that is associated with the achievement.\n/// </summary>\nclass achievement_reward\n{\npublic:\n    /// <summary>\n    /// The localized reward name.\n    /// </summary>\n    inline const string_t& name() const;\n\n    /// <summary>\n    /// The description of the reward.\n    /// </summary>\n    inline const string_t& description() const;\n\n    /// <summary>\n    /// The title-defined reward value (data type and content varies by reward type).\n    /// </summary>\n    inline const string_t& value() const;\n\n    /// <summary>\n    /// The reward type.\n    /// </summary>\n    inline achievement_reward_type reward_type() const;\n\n    /// <summary>\n    /// The property type of the reward value string.\n    /// </summary>\n    inline const string_t& value_type() const;\n\n    /// <summary>\n    /// The media asset associated with the reward.\n    /// If the reward type is gamerscore, this will be nullptr.\n    /// If the reward type is in_app, this will be a media asset.\n    /// If the reward type is art, this may be a media asset or nullptr.\n    /// </summary>\n    inline const achievement_media_asset& media_asset() const;\n\n    inline achievement_reward(const XblAchievementReward& reward);\n\nprivate:\n    string_t m_name;\n    string_t m_description;\n    string_t m_value;\n    achievement_reward_type m_rewardType;\n    string_t m_valueType;\n    achievement_media_asset m_mediaAsset;\n};\n\n\n/// <summary>\n/// Represents an achievement, a system-wide mechanism for directing and\n/// rewarding users' in-game actions consistently across all games.\n/// </summary>\nclass achievement\n{\npublic:\n    /// <summary>\n    /// The achievement ID. Can be a uint or a guid.\n    /// </summary>\n    inline string_t id() const;\n\n    /// <summary>\n    /// The ID of the service configuration set associated with the achievement.\n    /// </summary>\n    inline string_t service_configuration_id() const;\n\n    /// <summary>\n    /// The localized achievement name.\n    /// </summary>\n    inline string_t name() const;\n\n    /// <summary>\n    /// The game/app titles associated with the achievement.\n    /// </summary>\n    inline std::vector<achievement_title_association> title_associations() const;\n\n    /// <summary>\n    /// The state of a user's progress towards the earning of the achievement.\n    /// </summary>\n    inline achievement_progress_state progress_state() const;\n\n    /// <summary>\n    /// The progression object containing progress details about the achievement,\n    /// including requirements.\n    /// </summary>\n    inline achievement_progression progression() const;\n\n    /// <summary>\n    /// The media assets associated with the achievement, such as image IDs.\n    /// </summary>\n    inline std::vector<achievement_media_asset> media_assets() const;\n\n    /// <summary>\n    /// The collection of platforms that the achievement is available on.\n    /// </summary>\n    inline std::vector<string_t> platforms_available_on() const;\n\n    /// <summary>\n    /// Whether or not the achievement is secret.\n    /// </summary>\n    inline bool is_secret() const;\n\n    /// <summary>\n    /// The description of the unlocked achievement.\n    /// </summary>\n    inline string_t unlocked_description() const;\n\n    /// <summary>\n    /// The description of the locked achievement.\n    /// </summary>\n    inline string_t locked_description() const;\n\n    /// <summary>\n    /// The product_id the achievement was released with. This is a globally unique identifier that\n    /// may correspond to an application, downloadable content, etc.\n    /// </summary>\n    inline string_t product_id() const;\n\n    /// <summary>\n    /// The type of achievement, such as a challenge achievement.\n    /// </summary>\n    inline achievement_type type() const;\n\n    /// <summary>\n    /// The participation type for the achievement, such as group or individual.\n    /// </summary>\n    inline achievement_participation_type participation_type() const;\n\n    /// <summary>\n    /// The time window during which the achievement is available. Applies to Challenges.\n    /// </summary>\n    inline achievement_time_window available() const;\n\n    /// <summary>\n    /// The collection of rewards that the player earns when the achievement is unlocked.\n    /// </summary>\n    inline std::vector<achievement_reward> rewards() const;\n\n    /// <summary>\n    /// The estimated time that the achievement takes to be earned.\n    /// </summary>\n    inline std::chrono::seconds estimated_unlock_time() const;\n\n    /// <summary>\n    /// A deeplink for clients that enables the title to launch at a desired starting point\n    /// for the achievement.\n    /// </summary>\n    inline string_t deep_link() const;\n\n    /// <summary>\n    /// A value that indicates whether or not the achievement is revoked by enforcement.\n    /// </summary>\n    inline bool is_revoked() const;\n\n    achievement() = default;\n    inline achievement(XblAchievementsResultHandle handle, const XblAchievement* achievement);\n    inline achievement(const achievement& other);\n    inline achievement& operator=(achievement other);\n    inline ~achievement();\n\nprivate:\n    XblAchievementsResultHandle m_handle{ nullptr };\n    const XblAchievement* m_achievement{ nullptr };\n};\n\n/// <summary>\n/// Represents a collection of Achievement class objects returned by a request.\n/// </summary>\nclass achievements_result\n{\npublic:\n    /// <summary>\n    /// The collection of achievement objects returned by a request.\n    /// </summary>\n    inline std::vector<achievement> items() const;\n\n    /// <summary>\n    /// Returns a boolean value that indicates if there are more pages of achievements to retrieve.\n    /// </summary>\n    /// <returns>True if there are more pages, otherwise false.</returns>\n    inline bool has_next() const;\n\n    /// <summary>\n    /// Returns an achievements_result object that contains the next page of achievements.\n    /// </summary>\n    /// <param name=\"maxItems\">The maximum number of items that the result can contain.  Pass 0 to attempt\n    /// to retrieve all items.</param>\n    /// <returns>An achievements_result object that contains a list of achievement objects.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// This method calls V2 GET /users/xuid({xuid})/achievements.\n    /// </remarks>\n    inline pplx::task<xbox::services::xbox_live_result<achievements_result>> get_next(\n        _In_ uint32_t maxItems\n    );\n\n    achievements_result() = default;\n    inline achievements_result(XblAchievementsResultHandle handle);\n    inline achievements_result(const achievements_result& other);\n    inline achievements_result& operator=(achievements_result other);\n    inline ~achievements_result();\n\nprivate:\n    XblAchievementsResultHandle m_handle{ nullptr };\n};\n\n/// <summary>\n/// Represents an endpoint that you can use to access the Achievement service.\n/// </summary>\nclass achievement_service\n{\npublic:\n    /// <summary>\n    /// Allow achievement progress to be updated and achievements to be unlocked.\n    /// This API will work even when offline. On PC and Xbox One, updates will be \n    /// posted by the system when connection is re-established even if the title isn't running.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n    /// <param name=\"achievementId\">The achievement ID as defined by XDP or Dev Center.</param>\n    /// <param name=\"percentComplete\">The completion percentage of the achievement to indicate progress.\n    /// Valid values are from 1 to 100. Set to 100 to unlock the achievement.\n    /// Progress will be set by the server to the highest value sent</param>\n    /// <remarks>\n    /// Returns a task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// This method calls V2 POST /users/xuid({xuid})/achievements/{scid}/update\n    /// </remarks>\n    inline pplx::task<xbox::services::xbox_live_result<void>> update_achievement(\n        _In_ const string_t& xboxUserId,\n        _In_ const string_t& achievementId,\n        _In_ uint32_t percentComplete\n        );\n\n    /// <summary>\n    /// Allow achievement progress to be updated and achievements to be unlocked.\n    /// This API will work even when offline. On PC and Xbox One, updates will be \n    /// posted by the system when connection is re-established even if the title isn't running.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n    /// <param name=\"titleId\">The title ID.</param>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) for the title.</param>\n    /// <param name=\"achievementId\">The achievement ID as defined by XDP or Dev Center.</param>\n    /// <param name=\"percentComplete\">The completion percentage of the achievement to indicate progress.\n    /// Valid values are from 1 to 100. Set to 100 to unlock the achievement.\n    /// Progress will be set by the server to the highest value sent</param>\n    /// <remarks>\n    /// Returns a task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// This method calls V2 POST /users/xuid({xuid})/achievements/{scid}/update\n    /// </remarks>\n    inline pplx::task<xbox::services::xbox_live_result<void>> update_achievement(\n        _In_ const string_t& xboxUserId,\n        _In_ uint32_t titleId,\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& achievementId,\n        _In_ uint32_t percentComplete\n        );\n\n    /// <summary>\n    /// Returns an achievements_result object containing the first page of achievements\n    /// for a player of the specified title.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n    /// <param name=\"titleId\">The title ID.</param>\n    /// <param name=\"type\">The achievement type to retrieve.</param>\n    /// <param name=\"unlockedOnly\">Indicates whether to return unlocked achievements only.</param>\n    /// <param name=\"orderby\">Controls how the list of achievements is ordered.</param>\n    /// <param name=\"skipItems\">The number of achievements to skip.</param>\n    /// <param name=\"maxItems\">The maximum number of achievements the result can contain.  Pass 0 to attempt\n    /// to retrieve all items.</param>\n    /// <returns>An AchievementsResult object that contains a list of Achievement objects.</returns>\n    /// <remarks>\n    /// Returns a task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// See achievements_result:get_next to page in the next set of results.\n    ///\n    /// This method calls V2 GET /users/xuid({xuid})/achievements\n    /// </remarks>\n    inline pplx::task<xbox::services::xbox_live_result<achievements_result>> get_achievements_for_title_id(\n        _In_ const string_t& xboxUserId,\n        _In_ uint32_t titleId,\n        _In_ achievement_type type,\n        _In_ bool unlockedOnly,\n        _In_ achievement_order_by orderBy,\n        _In_ uint32_t skipItems,\n        _In_ uint32_t maxItems\n        );\n\n    /// <summary>\n    /// Returns a specific achievement object for a specified player.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player.</param>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) for the title.</param>\n    /// <param name=\"achievementId\">The unique identifier of the Achievement as defined by XDP or Dev Center.</param>\n    /// <returns>The requested achievement object if it exists.\n    /// If the achievement does not exist, the method returns xbox_live_error_code::runtime_error .</returns>\n    /// <remarks>\n    /// Returns a task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// This method calls V2 GET /users/xuid({xuid})/achievements/{scid}/{achievementId}.\n    /// </remarks>\n    inline pplx::task<xbox::services::xbox_live_result<achievement>> get_achievement(\n        _In_ const string_t& xboxUserId,\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& achievementId\n        );\n\n    inline achievement_service(const achievement_service& other);\n    inline achievement_service& operator=(achievement_service other);\n    inline ~achievement_service();\n\nprivate:\n    inline achievement_service(XblContextHandle xblContextHandle);\n\n    XblContextHandle m_xblContextHandle;\n\n    friend xbox_live_context;\n};\n#endif // !XSAPI_NO_PPL\n\n}}}\n\n#if !XSAPI_NO_PPL\n#include \"impl/achievements.hpp\"\n#endif\n"
  },
  {
    "path": "Include/xsapi-cpp/errors.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <system_error>\n\n#ifndef _NOEXCEPT\n#define _NOEXCEPT noexcept\n#endif\n\nnamespace xbox {\n    /// <summary>\n    /// Contains classes, enumerations, and namespaces used to indicate error conditions for Xbox Live service components.\n    /// </summary>\n    namespace services {\n            /// <summary>\n            /// Enumeration values that define the Xbox Live API error conditions.\n            /// </summary>\n            /// <remarks>\n            /// A best practice is to test the returned std::error_code against these error conditions.\n            /// For more detail about std::error_code vs std::error_condition, see \n            /// http://en.cppreference.com/w/cpp/error/error_condition \n            /// </remarks>\n            /// <example>\n            /// For example:\n            /// <code>\n            /// if( result.err() == xbox::services::xbox_live_error_condition::auth )\n            /// { \n            ///     // ...\n            /// } \n            /// </code>\n            /// or\n            /// <code>\n            /// switch (result.err().default_error_condition().value())\n            /// {\n            ///   case xbox::services::xbox_live_error_condition::auth:\n            ///     // ...\n            ///     break;\n            /// }\n            /// </code>\n            /// </example>\n            enum class xbox_live_error_condition\n            {\n                /// <summary>\n                /// No error.\n                /// </summary>\n                no_error = 0,\n\n                /// <summary>\n                /// A generic error condition.\n                /// </summary>\n                generic_error,\n\n                /// <summary>\n                /// An error condition related to an object being out of range.\n                /// </summary>\n                generic_out_of_range,\n\n                /// <summary>\n                /// An error condition related to attempting to authenticate.\n                /// </summary>\n                auth,\n\n                /// <summary>\n                /// An error condition related to network connectivity.\n                /// </summary>\n                network,\n\n                /// <summary>\n                /// An error condition related to an HTTP method call.\n                /// </summary>\n                http,\n\n                /// <summary>\n                /// The requested resource was not found.\n                /// </summary>\n                http_404_not_found,\n\n                /// <summary>\n                /// The precondition given in one or more of the request-header fields evaluated\n                /// to false when it was tested on the server.\n                /// </summary>\n                http_412_precondition_failed,\n\n                /// <summary>\n                /// Client is sending too many requests\n                /// </summary>\n                http_429_too_many_requests,\n\n                /// <summary>\n                /// The service timed out while attempting to process the request.\n                /// </summary>\n                http_service_timeout,\n                \n                /// <summary>\n                /// An error related to real time activity.\n                /// </summary>\n                rta\n            };\n\n            /// <summary>\n            /// These are XSAPI specific error codes.\n            /// Only the HTTP codes and errors that are commonly seen when calling Xbox LIVE are called out with guidance about the cause.\n            /// The best practice to test for and react to using the xbox_live_error_condition enum instead of these error codes.\n            /// </summary>\n            enum class xbox_live_error_code\n            {\n                /// <summary>\n                /// <b>0</b>\n                /// No error\n                /// </summary>\n                no_error = 0,\n\n                //////////////////////////////////////////////////////////////////////////\n                // HTTP errors\n                //////////////////////////////////////////////////////////////////////////\n\n                /// <summary>\n                /// The 204 response indicates that the content data was not found.\n                /// This code is returned when you are trying to access or write to a session that has been deleted.\n                /// </summary>\n                http_status_204_resource_data_not_found = 204,\n\n                /// <summary>\n                /// <b>0x8019012C</b>\n                /// The 300 response indicates there are multiple choices.  Not returned by Xbox Live services\n                /// </summary>\n                http_status_300_multiple_choices = 300,\n\n                /// <summary>\n                /// <b>0x8019012D</b>\n                /// The 301 response indicates that the request should be directed at a new URI\n                /// </summary>\n                http_status_301_moved_permanently = 301,\n\n                /// <summary>\n                /// <b>0x8019012E</b>\n                /// The 302 response indicates found.\n                /// </summary>\n                http_status_302_found = 302,\n\n                /// <summary>\n                /// <b>0x8019012F</b>\n                /// The 303 response indicates see other.  Not returned by Xbox Live services\n                /// </summary>\n                http_status_303_see_other = 303,\n\n                /// <summary>\n                /// <b>0x80190130</b>\n                /// The 304 response indicates resource has not been modified.\n                /// </summary>\n                http_status_304_not_modified = 304,\n\n                /// <summary>\n                /// <b>0x80190131</b>\n                /// The 305 response indicates you must a use proxy.  Not typically returned by Xbox Live services\n                /// </summary>\n                http_status_305_use_proxy = 305,\n\n                /// <summary>\n                /// <b>0x80190133</b>\n                /// The 307 response indicates a temporary redirect.\n                /// </summary>\n                http_status_307_temporary_redirect = 307,\n\n                /// <summary>\n                /// <b>0x80190190</b>\n                /// The request could not be understood by the server due to malformed syntax. \n                /// The client should not repeat this request without modification.\n                ///\n                /// This code is returned by the following methods:\n                /// Social services\n                /// GetUserProfileAsync:\n                /// The list of XUIDs returned from a leaderboard read operation and passed to this method has failed\n                /// due to one or more invalid XUID values.\n                ///\n                /// Data services\n                /// GetSingleUserStatisticsAsync: \n                /// Corresponds to a general HTTP error code: HTTP 400 Bad Request.\n                ///\n                /// Server Platform services\n                /// AllocateClusterAsync: \n                /// Matchmaking request failure, typically due to QoS (where the requirement is all-or-nothing).\n                ///\n                /// Marketplace services\n                /// GetCatalogItemDetailsAsync: \n                /// The Details service can only support 10 CatalogItems per request (MAX_DETAILS_ITEMS).\n                /// BrowseCatalogAsync: Typically an error of setting maxItems too large. The catalog service only supports a max of \n                /// 25 items per call.\n                /// </summary>\n                http_status_400_bad_request = 400,\n\n                /// <summary>\n                /// <b>0x80190191</b>\n                /// The 401 response typically indicates that authorization has been refused for provided credentials.\n                /// This code is returned when the user(s) or the device is not authorized to access the requested data \n                /// or perform the requested action.\n                /// </summary>\n                http_status_401_unauthorized = 401,\n\n                /// <summary>\n                /// <b>0x80190192</b>\n                /// 402 Payment Required\n                /// </summary>\n                http_status_402_payment_required = 402,\n\n                /// <summary>\n                /// <b>0x80190193</b>\n                /// Corresponds to general HTTP error code HTTP 403 - Forbidden.\n                /// The server understood the request but is refusing to fulfill. Authorization will not resolve the issue\n                /// and the request should not be repeated.\n                ///\n                /// General\n                /// This is typically a service configuration issue or a malformed HTTP request. To resolve, make sure that \n                /// your service configuration is correct, that your console is in the right sandbox, and that you are using \n                /// the correct title id and SCID. Using fiddler to examine the failing HTTP request will often help root cause the issue.\n                ///\n                /// Multiplayer services\n                /// The user doesn't have multiplayer privileges, or the session is private/reserved and the user isn't a member.\n                /// </summary>\n                http_status_403_forbidden = 403,\n\n                /// <summary>\n                /// <b>0x80190194</b>\n                /// This typically indicates that the server has not found anything matching the provided URI.\n                /// The root cause of the 404 will depend on the API you are using. \n                /// For example many of the \"Get Leaderboard\" \n                /// APIs return a 404 error if you request a stat that does not exist, or if the leader board is empty, \n                /// CreateSessionAsync returns a 404 error if you call it with an invalid Session Template name, and \n                /// GetPartyViewAsync fails with a 404 if the multiplayer session times out. Using fiddler to examine the failing \n                /// HTTP request will often help root cause the issue.\n                /// </summary>\n                http_status_404_not_found = 404,\n\n                /// <summary>\n                /// <b>0x80190195</b>\n                /// The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. \n                /// For example, the request is a POST where a PUT is needed.\n                /// </summary>\n                http_status_405_method_not_allowed = 405,\n\n                /// <summary>\n                /// <b>0x80190196</b>\n                /// The resource identified by the request is only capable for generating response entities which have \n                /// content characteristics not acceptable according to the accept headers sent in the Request.\n                /// </summary>\n                http_status_406_not_acceptable = 406,\n\n                /// <summary>\n                /// <b>0x80190197</b>\n                /// This code is similar to HTTP 401 (Unauthorized), but indicates that the client must first \n                /// authenticate itself with the proxy.\n                /// </summary>\n                http_status_407_proxy_authentication_required = 407,\n\n                /// <summary>\n                /// <b>0x80190198</b>\n                /// The client did not produce a request within the time the server was prepared to wait. The client MAY \n                /// repeat the request without modifications at a later time.\n                /// </summary>\n                http_status_408_request_timeout = 408,\n\n                /// <summary>\n                /// <b>0x80190199</b>\n                /// This typically indicates that the request could not be completed due to a conflict with the current \n                /// state of the resource. This code is only allowed in situations where it is expected that a user might \n                /// be able to resolve the conflict and re-submit the request.\n                ///\n                /// Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being \n                /// used and the entity being PUT included changes to a resource which conflict with those made by an earlier \n                /// (third-party) request, the server might use the 409 response to indicate that it can't complete the request. \n                /// In this case, the response entity would likely contain a list of the differences between the two versions in a \n                /// format defined by the Response-ContentType.\n                ///\n                /// Multiplayer services:\n                /// Incorrect session or matchmaking query syntax or re-setting properties that are already pre-defined in the session template.\n                /// The session couldn't be updated because the request is incompatible with the session. For example:\n                /// Constants in the request conflict with constants in the session or session template.\n                /// Members other than the caller are added to, or removed, from a large session.\n                /// </summary>\n                http_status_409_conflict = 409,\n\n                /// <summary>\n                /// <b>0x8019019A</b>\n                /// This typically indicates that the requested resource is no longer available at the server and no forwarding address \n                /// is known. The expectation is that this condition is considered to be permanent.\n                /// </summary>\n                http_status_410_gone = 410,\n\n                /// <summary>\n                /// <b>0x8019019B</b>\n                /// The server refuses to accept the request without a defined Content-Length. The client MAY repeat the request if it \n                /// adds a valid Content-Length header field containing the length of the message-body in the request.\n                /// </summary>\n                http_status_411_length_required = 411,\n\n                /// <summary>\n                /// <b>0x8019019C</b>\n                /// The precondition given in one or more of the request-header fields evaluated to false when it was tested on the \n                /// server. This response code allows the client to place preconditions on the current resource meta information \n                /// (header field data) to prevent the requested method from being applied to a resource other than the one intended.\n                /// \n                /// Multiplayer services\n                /// The If-Match header, or (other than on a GET) the If-None-Match header couldn't be satisfied.\n                /// The If-Match header couldn't be satisfied on a PUT or DELETE to an existing session. The current state of the session \n                /// is returned along with the current ETag.\n                /// </summary>\n                http_status_412_precondition_failed = 412,\n\n                /// <summary>\n                /// <b>0x8019019D</b>\n                /// The server is refusing to process a request because the request entity is larger than the server is willing, or able, \n                /// to process. The server MAY close the connection to prevent the client from continuing with the request.\n                /// </summary>\n                http_status_413_request_entity_too_large = 413,\n\n                /// <summary>\n                /// <b>0x8019019E</b>\n                /// The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. \n                /// This rare condition is only likely to occur when a client has improperly converted a POST Request to a GET Request with long query information.\n                /// </summary>\n                http_status_414_request_uri_too_long = 414,\n\n                /// <summary>\n                /// <b>0x8019019F</b>\n                /// The server is refusing to service the request because the entity of the request is in a format not supported by the \n                /// requested resource for the requested method.\n                /// </summary>\n                http_status_415_unsupported_media_type = 415,\n\n                /// <summary>\n                /// <b>0x801901A0</b>\n                /// A server SHOULD return a response with this status code if a requested included in a Range request-header field, and none of \n                /// the range-specifier values in this field overlap the current extent of the selected resource, and the request did not \n                /// include an If-Range request-header field.\n                /// </summary>\n                http_status_416_requested_range_not_satisfiable = 416,\n                \n                /// <summary>\n                /// <b>0x801901A1</b>\n                /// Expect-request header failure\n                /// </summary>\n                http_status_417_expectation_failed = 417,\n\n                /// <summary>\n                /// <b>0x801901A5</b>\n                /// The request was misdirected \n                /// </summary>\n                http_status_421_misdirected_request = 421,\n\n                /// <summary>\n                /// <b>0x801901A6</b>\n                /// The request was not processable\n                /// </summary>\n                http_status_422_unprocessable_entity = 422,\n\n                /// <summary>\n                /// <b>0x801901A7</b>\n                /// The resource was locked \n                /// </summary>\n                http_status_423_locked = 423,\n\n                /// <summary>\n                /// <b>0x801901A8</b>\n                /// The request failed due to dependency\n                /// </summary>\n                http_status_424_failed_dependency = 424,\n\n                /// <summary>\n                /// <b>0x801901AA</b>\n                /// The client should upgrade to later protocol\n                /// </summary>\n                http_status_426_upgrade_required = 426,\n\n                /// <summary>\n                /// <b>0x801901AC</b>\n                /// The server requires a precondition\n                /// </summary>\n                http_status_428_precondition_required = 428,\n\n                /// <summary>\n                /// <b>0x801901AD</b>\n                /// Client is sending too many requests\n                /// </summary>\n                http_status_429_too_many_requests = 429,\n\n                /// <summary>\n                /// <b>0x801901AF</b>\n                /// The request headers are too large\n                /// </summary>\n                http_status_431_request_header_fields_too_large = 431,\n\n                /// <summary>\n                /// <b>0x801901C1</b>\n                /// The request should be retried after doing the appropriate action\n                /// </summary>\n                http_status_449_retry_with = 449,\n\n                /// <summary>\n                /// <b>0x801901C3</b>\n                /// The request was unavailable for legal reasons\n                /// </summary>\n                http_status_451_unavailable_for_legal_reasons = 451,\n\n                /// <summary>\n                /// <b>0x801901F4</b>\n                /// Corresponds to HTTP 500 Internal Server Error.This error can occur when invalid parameters are provided to the web service \n                /// via a RESTful API call, or if the web service encounters a crash or other unexpected error state. Using fiddler to examine \n                /// the failing HTTP request will often help root cause the issue.\n                /// </summary>\n                http_status_500_internal_server_error = 500,\n\n                /// <summary>\n                /// <b>0x801901F5</b>\n                /// The requested service is not implemented.\n                /// </summary>\n                http_status_501_not_implemented = 501,\n\n                /// <summary>\n                /// <b>0x801901F6</b>\n                /// The request got an invalid response to the gateway\n                /// </summary>\n                http_status_502_bad_gateway = 502,\n\n                /// <summary>\n                /// <b>0x801901F7</b>\n                /// The requested service is not available.\n                /// </summary>\n                http_status_503_service_unavailable = 503,\n\n                /// <summary>\n                /// <b>0x801901F8</b>\n                /// The HTTP gateway has timed out.\n                /// </summary>\n                http_status_504_gateway_timeout = 504,\n\n                /// <summary>\n                /// <b>0x801901F9</b>\n                /// This version of HTTP is not supported by the endpoint.\n                /// </summary>\n                http_status_505_http_version_not_supported = 505,\n\n                /// <summary>\n                /// <b>0x801901FA</b>\n                /// Internal configuration error\n                /// </summary>\n                http_status_506_variant_also_negotiates = 506,\n\n                /// <summary>\n                /// <b>0x801901FB</b>\n                /// The service was unable complete the request due to storage\n                /// </summary>\n                http_status_507_insufficient_storage = 507,\n\n                /// <summary>\n                /// <b>0x801901FC</b>\n                /// The service detected an infinite loop while processing\n                /// </summary>\n                http_status_508_loop_detected = 508,\n\n                /// <summary>\n                /// <b>0x801901FE</b>\n                /// The request requires more extensions to complete\n                /// </summary>\n                http_status_510_not_extended = 510,\n\n                /// <summary>\n                /// <b>0x801901FF</b>\n                /// The client needs to authenticate to gain network access.  Not used by Xbox Live services.\n                /// </summary>\n                http_status_511_network_authentication_required = 511,\n\n                //////////////////////////////////////////////////////////////////////////\n                // Errors from exception enabled components such as Casablanca\n                //////////////////////////////////////////////////////////////////////////\n                /// <summary>\n                /// <b>0x8007000e</b>\n                /// xbox_live_error_code 1000\n                /// Bad alloc\n                /// </summary>\n                bad_alloc = 1000,\n\n                /// <summary>\n                /// <b>0x80004002</b>\n                /// xbox_live_error_code 1001\n                /// Bad cast\n                /// </summary>\n                bad_cast,\n\n                /// <summary>\n                /// <b>0x80070057</b>\n                /// xbox_live_error_code 1002\n                /// Invalid argument\n                /// </summary>\n                invalid_argument,\n\n                /// <summary>\n                /// <b>0x8000000b</b>\n                /// xbox_live_error_code 1003\n                /// Out of range\n                /// </summary>\n                out_of_range,\n\n                /// <summary>\n                /// <b>0x80070018</b>\n                /// xbox_live_error_code 1004\n                /// Length error\n                /// </summary>\n                length_error,\n\n                /// <summary>\n                /// <b>0x8000000b</b>\n                /// xbox_live_error_code 1005\n                /// Range error\n                /// </summary>\n                range_error,\n\n                /// <summary>\n                /// <b>0x8000ffff</b>\n                /// xbox_live_error_code 1006\n                /// Logic error\n                /// </summary>\n                logic_error,\n\n                /// <summary>\n                /// <b>0x89235200</b>\n                /// xbox_live_error_code 1007\n                /// Runtime error\n                /// </summary>\n                runtime_error,\n\n                /// <summary>\n                /// <b>0x83750007</b>\n                /// xbox_live_error_code 1008\n                /// JSON error\n                /// </summary>\n                json_error,\n\n                /// <summary>\n                /// <b>0x83750005</b>\n                /// xbox_live_error_code 1009\n                /// Websocket error\n                /// </summary>\n                websocket_error,\n\n                /// <summary>\n                /// <b>0x83750005</b>\n                /// xbox_live_error_code 1010\n                /// URI error\n                /// </summary>\n                uri_error,\n\n                /// <summary>\n                /// <b>0x80004005</b>\n                /// xbox_live_error_code 1011\n                /// Generic error\n                /// </summary>\n                generic_error,\n\n                //////////////////////////////////////////////////////////////////////////\n                // RTA errors\n                //////////////////////////////////////////////////////////////////////////\n                /// <summary>\n                /// <b>0x89235201</b>\n                /// xbox_live_error_code 1500\n                /// RTA generic error\n                /// </summary>\n                rta_generic_error = 1500,\n\n                /// <summary>\n                /// <b>0x89235202</b>\n                /// xbox_live_error_code 1501\n                /// RTA subscription limit reached\n                /// </summary>\n                rta_subscription_limit_reached,\n\n                /// <summary>\n                /// <b>0x89235203</b>\n                /// xbox_live_error_code 1502\n                /// RTA access denied\n                /// </summary>\n                rta_access_denied,\n\n                /// <summary>\n                /// <b>0x89235209</b>\n                /// xbox_live_error_code 1503\n                /// RTA not activated\n                /// </summary>\n                rta_not_activated,\n\n                //////////////////////////////////////////////////////////////////////////\n                // Auth errors\n                //////////////////////////////////////////////////////////////////////////\n\n                /// <summary>\n                /// <b>0x89235204</b>\n                /// xbox_live_error_code 2000\n                /// Unknown auth error\n                /// </summary>\n                auth_unknown_error = 2000,\n\n                /// <summary>\n                /// <b>0x8086000c</b>\n                /// xbox_live_error_code 2001\n                /// User interaction required\n                /// </summary>\n                auth_user_interaction_required,\n\n                /// <summary>\n                /// <b>0x80070525</b>\n                /// xbox_live_error_code 2002\n                /// User interaction required\n                /// </summary>\n                auth_user_switched,\n\n                /// <summary>\n                /// <b>0x80070525</b>\n                /// xbox_live_error_code 2003\n                /// User cancelled\n                /// </summary>\n                auth_user_cancel,\n\n                /// <summary>\n                /// <b>0x80070525</b>\n                /// xbox_live_error_code 2004\n                /// User not signed in\n                /// </summary>\n                auth_user_not_signed_in,\n\n                /// <summary>\n                /// <b>0x89235205</b>\n                /// xbox_live_error_code 2005\n                /// Auth runtime error\n                /// </summary>\n                auth_runtime_error,\n\n                /// <summary>\n                /// <b>0x89235206</b>\n                /// xbox_live_error_code 2006\n                /// Auth no token error\n                /// </summary>\n                auth_no_token_error,\n\n                //////////////////////////////////////////////////////////////////////////\n                // Xbox Live SDK errors\n                //////////////////////////////////////////////////////////////////////////\n                /// <summary>\n                /// <b>0x8007064a</b>\n                /// xbox_live_error_code 3000\n                /// Could not read the xboxservices.config.  Ensure it is deployed in the package at\n                /// Windows::ApplicationModel::Package::Current->InstalledLocation + \"\\xboxservices.config\"\n                /// </summary>\n                invalid_config = 3000,\n\n                /// <summary>\n                /// <b>0x80004001</b>\n                /// xbox_live_error_code 3001\n                /// API is not supported\n                /// </summary>\n                unsupported = 3001,\n\n                //////////////////////////////////////////////////////////////////////////\n                // xbox live auth errors\n                //////////////////////////////////////////////////////////////////////////\n                /// <summary>\n                /// <b>0x80072EE2</b>\n                /// This error is typically returned by Xbox::Services APIs, GetTokenAndSignatureAsync, \n                /// and CheckLicense. It indicates that the Internet connection or a server response was \n                /// interrupted; possibly the result of a incorrectly configured NSAL. Pending requests \n                /// should be retried when this error is encountered.\n                /// </summary>\n                HR_ERROR_INTERNET_TIMEOUT = (int)0x80072EE2,\n\n                /// <summary>\n                /// <b>0x87DD0003</b>\n                /// XASD returned an unexpected response.\n                /// </summary>\n                AM_E_XASD_UNEXPECTED = (int)0x87DD0003,\n\n                /// <summary>\n                /// <b>0x87DD0004</b>\n                /// XASU returned an unexpected response.\n                /// </summary>\n                AM_E_XASU_UNEXPECTED = (int)0x87DD0004,\n\n                /// <summary>\n                /// <b>0x87DD0005</b>\n                /// XAST returned an unexpected response.\n                /// Cause: Your NSAL configuration is set up correctly for your service, however the \n                /// Relying Party certificate is not yet trusted by Xbox Live.\n                ///\n                /// Resolution : Relying Party configuration on XDP and provide the Relying Party \n                /// certificate in the XSTS token certificate for your endpoint.\n                /// If you are using the NSAL.json file, double check that the Relying Party name is \n                /// correct in the 'target' field of your NSAL.json file on the console and ensure that \n                /// the certificate has been specified in XDP.\n                ///\n                /// If you are developing a UWP title and performing service configuration in XDP, then\n                /// you may have not completed the Application ID binding step correctly.  For more\n                /// information, please see the \"Troubleshooting Sign-in\" article in the Xbox Live documentation.\n                /// </summary>\n                AM_E_XAST_UNEXPECTED = (int)0x87DD0005,\n\n                /// <summary>\n                /// <b>0x87DD0006</b>\n                /// Cause : Your NSAL configuration is set up correctly for your service, however the \n                /// Relying Party certificate is not yet trusted by Xbox Live.\n                /// \n                /// Resolution : Relying Party configuration on XDP and provide the Relying Party \n                /// certificate in the XSTS token certificate for your endpoint.\n                /// If you are using the NSAL.json file, double check that the Relying Party name is \n                /// correct in the 'target' field of your NSAL.json file on the console and ensure \n                /// that the certificate has been specified in XDP.\n                /// </summary>\n                AM_E_XSTS_UNEXPECTED = (int)0x87DD0006,\n\n                /// <summary>\n                /// <b>0x87DD0007</b>\n                /// XDevice returned an unexpected response.\n                /// </summary>\n                AM_E_XDEVICE_UNEXPECTED = (int)0x87DD0007,\n\n                /// <summary>\n                /// <b>0x87DD0008</b>\n                /// The console is not authorized to enable development mode.\n                /// </summary>\n                AM_E_DEVMODE_NOT_AUTHORIZED = (int)0x87DD0008,\n\n                /// <summary>\n                /// <b>0x87DD0009</b>\n                /// The operation was not authorized.\n                /// Cause: The user is not authorized to get an XSTS token with the current TitleID or \n                /// SandboxID setup on the console for the provided URL.\n                /// \n                /// Resolution:\n                /// Ensure that your console is in the proper SandboxID for the TitleID you are using.\n                /// See this forum thread for instructions on changing your SandboxID and which SandboxID \n                /// to use for samples.\n                ///\n                /// Ensure that the test account you are using is partitioned to a group in XDP that has \n                /// access to the TitleID and SandboxID for your title(Note that all accounts are able to \n                /// access the samples while in the sample SandboxID).\n                /// </summary>\n                AM_E_NOT_AUTHORIZED = (int)0x87DD0009,\n\n                /// <summary>\n                /// <b>0x87DD000A</b>\n                /// The operation was forbidden. The server responded with a 403, and a more detailed error is not available.\n                /// </summary>\n                AM_E_FORBIDDEN = (int)0x87DD000A,\n\n                /// <summary>\n                /// <b>0x87DD000B</b>\n                /// The URL specified does not match a known target.\n                ///\n                /// Cause: \n                /// The URL you are attempting to get a token for was not found within your NSAL configuration.\n                /// \n                /// Resolution:\n                /// Ensure that the Relying Party and server name are properly set up as an endpoint \n                /// on your console and in your NSAL.\n                ///\n                /// Try calling a known Xbox Service such as https ://social.xboxlive.com/users/xuid(user's xuid)/people \n                /// to ensure that you can get tokens for the Xbox services. If you are using the NSAL.json file, make sure \n                /// that the 'target' field in the file has your Relying Party name ending with '/' and \n                /// that the server name is set up correctly.\n                /// </summary>\n                AM_E_UNKNOWN_TARGET = (int)0x87DD000B,\n\n                /// <summary>\n                /// <b>0x87DD000C</b>\n                /// There were problems with the JSON data downloaded from the server.\n                /// </summary>\n                AM_E_INVALID_NSAL_DATA = (int)0x87DD000C,\n\n                /// <summary>\n                /// <b>0x87DD000D</b>\n                /// The title has not yet been successfully authenticated.\n                /// Cause: This will be returned when a title token is required, but has not been cached. For example, \n                /// attempting to retrieve an X token with title claims will fail with this error if AuthenticateTitle \n                /// hasn't been called successfully.\n                /// \n                /// Resolution: Check your TitleID, SOCID, and SandboxID, or check your title's configuration on XDP.\n                /// </summary>\n                AM_E_TITLE_NOT_AUTHENTICATED = (int)0x87DD000D,\n\n                /// <summary>\n                /// <b>0x87DD000E</b>\n                /// XAST returned 401 when attempting to retrieve the T token.  Double-check that your device is set to the\n                /// proper development sandbox and that the user has access to the sandbox.\n                ///\n                /// For more information, please see the \"Troubleshooting Sign-in\" article in the Xbox Live documentation.\n                /// </summary>\n                AM_E_TITLE_NOT_AUTHORIZED = (int)0x87DD000E,\n\n                /// <summary>\n                /// <b>0x87DD0011</b>\n                /// The user hash value for the specified user hasn't been recorded, so a valid token can't be generated.\n                /// </summary>\n                AM_E_USER_HASH_MISSING = (int)0x87DD0011,\n\n                /// <summary>\n                /// <b>0x87DD0013</b>\n                /// The Authentication Manager can't find the user for which an authentication token is being retrieved. \n                /// One possible scenario is that the User signed out, but the title still has a reference to the User object.\n                /// </summary>\n                AM_E_USER_NOT_FOUND = (int)0x87DD0013,\n\n                /// <summary>\n                /// <b>0x87DD0015</b>\n                /// The environment configured or specified is not valid.\n                /// </summary>\n                AM_E_INVALID_ENVIRONMENT = (int)0x87DD0015,\n\n                /// <summary>\n                /// <b>0x87DD0016</b>\n                /// The XASD authentication server has timed out.\n                /// </summary>\n                AM_E_XASD_TIMEOUT = (int)0x87DD0016,\n\n                /// <summary>\n                /// <b>0x87DD0017</b>\n                /// The XASU authentication server has timed out.\n                /// </summary>\n                AM_E_XASU_TIMEOUT = (int)0x87DD0017,\n\n                /// <summary>\n                /// <b>0x87DD0018</b>\n                /// The XAST authentication server has timed out.\n                /// </summary>\n                AM_E_XAST_TIMEOUT = (int)0x87DD0018,\n\n                /// <summary>\n                /// <b>0x87DD0019</b>\n                /// The XSTS authentication server has timed out.\n                /// </summary>\n                AM_E_XSTS_TIMEOUT = (int)0x87DD0019,\n\n                /// <summary>\n                /// <b>0x87DD001A</b>\n                /// Title authentication failed because a connection to Xbox Live is required, by policy, and none is present.\n                /// </summary>\n                AM_E_LIVE_CONNECTION_REQUIRED = (int)0x87DD001A,\n\n                /// <summary>\n                /// <b>0x87dd001e</b>\n                /// There is no network connection.\n                /// </summary>\n                AM_E_NO_NETWORK = (int)0x87dd001e,\n\n                /// <summary>\n                /// <b>0x87dd0020</b>\n                /// The Network Security Authorization List(NSAL) returned an unexpected response.\n                /// </summary>\n                AM_E_XTITLE_UNEXPECTED = (int)0x87dd0020,\n\n                /// <summary>\n                /// <b>0x87dd0021</b>\n                /// The endpoint does not require an authorization token, but the application is attempting to \n                /// retrieve a token via GetTokenAndSignatureAsync.\n                /// </summary>\n                AM_E_NO_TOKEN_REQUIRED = (int)0x87dd0021,\n\n                /// <summary>\n                /// <b>0x87dd0022</b>\n                /// Timeouts were received from the various authorization servers.\n                /// </summary>\n                AM_E_XTITLE_TIMEOUT = (int)0x87dd0022,\n\n                /// <summary>\n                /// <b>0x8015DC00</b>\n                /// Developer mode is not authorized for the client device.\n                /// </summary>\n                XO_E_DEVMODE_NOT_AUTHORIZED = (int)0x8015DC00,\n\n                /// <summary>\n                /// <b>0x8015DC01</b>\n                /// A system update is required before this action can be performed.\n                /// </summary>\n                XO_E_SYSTEM_UPDATE_REQUIRED = (int)0x8015DC01,\n\n                /// <summary>\n                /// <b>0x8015DC02</b>\n                /// A content update is required before this action can be performed.\n                /// </summary>\n                XO_E_CONTENT_UPDATE_REQUIRED = (int)0x8015DC02,\n\n                /// <summary>\n                /// <b>0x8015DC03</b>\n                /// The device or user was banned.\n                /// </summary>\n                XO_E_ENFORCEMENT_BAN = (int)0x8015DC03,\n\n                /// <summary>\n                /// <b>0x8015DC04</b>\n                /// The device or user was banned.\n                /// </summary>\n                XO_E_THIRD_PARTY_BAN = (int)0x8015DC04,\n\n                /// <summary>\n                /// <b>0x8015DC05</b>\n                /// Access to this resource has been parentally restricted.\n                /// </summary>\n                XO_E_ACCOUNT_PARENTALLY_RESTRICTED = (int)0x8015DC05,\n\n                /// <summary>\n                /// <b>0x8015DC08</b>\n                /// Access to this resource requires that the account billing information\n                /// is updated.\n                /// </summary>\n                XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED = (int)0x8015DC08,\n\n                /// <summary>\n                /// <b>0x8015DC0A</b>\n                /// The user has not accepted the terms of use for this resource.\n                /// </summary>\n                XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED = (int)0x8015DC0A,\n\n                /// <summary>\n                /// <b>0x8015DC0B</b>\n                /// This resource is not available in the country associated with the user.\n                /// </summary>\n                XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED = (int)0x8015DC0B,\n\n                /// <summary>\n                /// <b>0x8015DC0C</b>\n                /// Access to this resource requires age verification.\n                /// </summary>\n                XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED = (int)0x8015DC0C,\n                \n                /// <summary>\n                /// <b>0x8015DC0D</b>\n                /// </summary>\n                XO_E_ACCOUNT_CURFEW = (int)0x8015DC0D,\n                \n                /// <summary>\n                /// <b>0x8015DC0E</b>\n                /// </summary>\n                XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY = (int)0x8015DC0E,\n\n                /// <summary>\n                /// <b>0x8015DC0F</b>\n                /// </summary>\n                XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED = (int)0x8015DC0F,\n\n                /// <summary>\n                /// <b>0x8015DC09</b>\n                /// </summary>\n                XO_E_ACCOUNT_CREATION_REQUIRED = (int)0x8015DC09,\n\n                /// <summary>\n                /// <b>0x8015DC10</b>\n                /// </summary>\n                XO_E_ACCOUNT_MAINTENANCE_REQUIRED = (int)0x8015DC10,\n\n                /// <summary>\n                /// <b>0x8015DC11</b>\n                /// The call was blocked because there was a conflict with the sandbox, console, application, or \n                /// your account.Verify your account, console and title settings in XDP, and check the current \n                /// Sandbox on the device.\n                /// </summary>\n                XO_E_ACCOUNT_TYPE_NOT_ALLOWED = (int)0x8015DC11,\n\n                /// <summary>\n                /// <b>0x8015DC12</b>\n                /// Your device does not have access to the Sandbox it is set to, or the account you are signed \n                /// in with does not have access to the Sandbox.Check that you are using the correct Sandbox.\n                ///\n                /// Note: All XDK samples use XDKS.1 SandboxID, which allow all user accounts to access and run \n                /// the samples.SandboxID's are case sensitive- Not matching the case of your SandboxID exactly may \n                /// result in errors. If you are still having issues running the sample, please work with your \n                /// Developer Account Manager and provide a fiddler trace to help with troubleshooting.\n                ///\n                /// For more information on handling this error, please see the \"Troubleshooting Sign-in\" article\n                /// in the Xbox Live documentation\n                /// </summary>\n                XO_E_CONTENT_ISOLATION = (int)0x8015DC12,\n\n                /// <summary>\n                /// <b>0x8015DC13</b>\n                /// </summary>\n                XO_E_ACCOUNT_NAME_CHANGE_REQUIRED = (int)0x8015DC13,\n\n                /// <summary>\n                /// <b>0x8015DC14</b>\n                /// </summary>\n                XO_E_DEVICE_CHALLENGE_REQUIRED = (int)0x8015DC14,\n\n                /// <summary>\n                /// <b>0x8015DC16</b>\n                /// The account was signed in on another device.\n                /// </summary>\n                XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED = (int)0x8015DC16,\n\n                /// <summary>\n                /// <b>0x8015DC17</b>\n                /// </summary>\n                XO_E_PIN_CHALLENGE_REQUIRED = (int)0x8015DC17,\n\n                /// <summary>\n                /// <b>0x8015DC18</b>\n                /// </summary>\n                XO_E_RETAIL_ACCOUNT_NOT_ALLOWED = (int)0x8015DC18,\n                \n                /// <summary>\n                /// <b>0x8015DC19</b>\n                /// The current sandbox is not allowed to access the SCID.  Please ensure that your current\n                /// sandbox is set to your development sandbox.  If you are running on a Windows 10 PC, then\n                /// you can change your current sandbox using the SwitchSandbox.cmd script in the Xbox Live SDK\n                /// tools directory.  If you are using an Xbox One, you can switch the sandbox using Xbox One\n                /// Manager.\n                ///\n                /// For more information on handling this error, please see the \"Troubleshooting Sign-in\" article\n                /// in the Xbox Live documentation.\n                /// </summary>\n                XO_E_SANDBOX_NOT_ALLOWED = (int)0x8015DC19,\n\n                /// <summary>\n                /// <b>0x8015DC1A</b>\n                /// </summary>\n                XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER = (int)0x8015DC1A,\n\n                /// <summary>\n                /// <b>0x8015DC1B</b>\n                /// </summary>\n                XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED = (int)0x8015DC1B,\n\n                /// <summary>\n                /// <b>0x8015DC1C</b>\n                /// </summary>\n                XO_E_CONTENT_NOT_AUTHORIZED = (int)0x8015DC1C,\n\n                //////////////////////////////////////////////////////////////////////////\n                // Generic errors\n                //////////////////////////////////////////////////////////////////////////\n\n                /// <summary>\n                /// <b>0x800C0002</b>\n                /// The URL is invalid.\n                /// </summary>\n                HR_INET_E_INVALID_URL = (int)0x800C0002,\n\n                /// <summary>\n                /// <b>0x800C0003</b>\n                /// No session.\n                /// </summary>\n                HR_INET_E_NO_SESSION = (int)0x800C0003,\n\n                /// <summary>\n                /// <b>0x800C0004</b>\n                /// WinINet cannot connect to the requested resource.\n                /// </summary>\n                HR_INET_E_CANNOT_CONNECT = (int)0x800C0004,\n\n                /// <summary>\n                /// <b>0x800C0005</b>\n                /// The requested resource was not found.\n                /// </summary>\n                HR_INET_E_RESOURCE_NOT_FOUND = (int)0x800C0005,\n\n                /// <summary>\n                /// <b>0x800C0006</b>\n                /// The requested resource was not found.\n                /// </summary>\n                HR_INET_E_OBJECT_NOT_FOUND = (int)0x800C0006,\n\n                /// <summary>\n                /// <b>0x800C0007</b>\n                /// The requested resource was not found.\n                /// </summary>\n                HR_INET_E_DATA_NOT_AVAILABLE = (int)0x800C0007,\n\n                /// <summary>\n                /// <b>0x800C0008</b>\n                /// Operation restricted by the current inability to discover or join the multiplayer session, or \n                /// the player does not have the multiplayer privilege.\n                /// </summary>\n                HR_INET_E_DOWNLOAD_FAILURE = (int)0x800C0008,\n\n                /// <summary>\n                /// <b>0x800C0009</b>\n                /// Authentication is required to access this resource.\n                /// </summary>\n                HR_INET_E_AUTHENTICATION_REQUIRED = (int)0x800C0009,\n\n                /// <summary>\n                /// <b>0x800C000A</b>\n                /// No valid media\n                /// </summary>\n                HR_INET_E_NO_VALID_MEDIA = (int)0x800C000A,\n\n                /// <summary>\n                /// <b>0x800C000B</b>\n                /// The connection has timed out.\n                /// </summary>\n                HR_INET_E_CONNECTION_TIMEOUT = (int)0x800C000B,\n\n                /// <summary>\n                /// <b>0x800C000C</b>\n                /// Invalid request\n                /// </summary>\n                HR_INET_E_INVALID_REQUEST = (int)0x800C000C,\n\n                /// <summary>\n                /// <b>0x800C000D</b>\n                /// The requested protocol is unknown.\n                /// </summary>\n                HR_INET_E_UNKNOWN_PROTOCOL = (int)0x800C000D,\n\n                /// <summary>\n                /// <b>0x800C000E</b>\n                /// Security problem\n                /// </summary>\n                HR_INET_E_SECURITY_PROBLEM = (int)0x800C000E,\n\n                /// <summary>\n                /// <b>0x800C000F</b>\n                /// Cannot load data\n                /// </summary>\n                HR_INET_E_CANNOT_LOAD_DATA = (int)0x800C000F,\n\n                /// <summary>\n                /// <b>0x800C0010</b>\n                /// Cannot instantiate object\n                /// </summary>\n                HR_INET_E_CANNOT_INSTANTIATE_OBJECT = (int)0x800C0010,\n\n                /// <summary>\n                /// <b>0x800C0019</b>\n                /// The certificate presented for the request is invalid.\n                /// </summary>\n                HR_INET_E_INVALID_CERTIFICATE = (int)0x800C0019,\n\n                /// <summary>\n                /// <b>0x800C0014</b>\n                /// The redirect to a different endpoint has failed.\n                /// </summary>\n                HR_INET_E_REDIRECT_FAILED = (int)0x800C0014,\n\n                /// <summary>\n                /// <b>0x800C0015</b>\n                /// A resource request has been directed to a directory rather than an individual resource.\n                /// </summary>\n                HR_INET_E_REDIRECT_TO_DIR = (int)0x800C0015,\n\n                /// <summary>\n                /// <b>0x800704cf</b>\n                /// The network location cannot be reached.\n                /// </summary>\n                HR_ERROR_NETWORK_UNREACHABLE = (int)0x800704cf,\n\n                /// <summary>\n                /// <b>0x89235007</b>\n                /// The network has not been initialized.\n                /// </summary>\n                HR_HC_NETWORK_NOT_INTIALIZED = (int)0x89235007\n            };\n\n            /// <summary>\n            /// Category error type for XSAPI error codes.\n            /// </summary>\n            class xbox_services_error_code_category_impl : public std::error_category\n            {\n            public:\n                /// <summary>\n                /// Gets the error category name.\n                /// </summary>\n                /// <returns>A string identifying the category.</returns>\n                inline const char* name() const _NOEXCEPT override { return \"XBL\"; }\n\n                /// <summary>\n                /// Converts an error value into a string that describes the error.\n                /// </summary>\n                /// <returns>A string that describes the error.</returns>\n                inline std::string message(_In_ int errorCode) const _NOEXCEPT override;\n            };\n\n            /// <summary>\n            /// Category error type for XSAPI error conditions.\n            /// </summary>\n            class xbox_services_error_condition_category_impl : public std::error_category\n            {\n            public:\n                /// <summary>\n                /// Gets the error category name.\n                /// </summary>\n                /// <returns>A string identifying the category.</returns>\n                inline const char* name() const _NOEXCEPT override { return \"XBL CONDITION\"; }\n\n                /// <summary>\n                /// Converts an error value into a string that describes the error.\n                /// </summary>\n                /// <returns>A string that describes the error.</returns>\n                inline std::string message(_In_ int errorCode) const _NOEXCEPT override;\n\n                /// <summary>\n                /// Used to establish equivalence between arbitrary error_codes in\n                /// the current category with arbitrary error_conditions.\n                /// </summary>\n                /// <param name=\"arbitraryErrorCode\">An error code.</param>\n                /// <param name=\"xboxLiveErrorCondition\">An error condition.</param>\n                /// <returns>True if the error code and the error condition are related; otherwise false.</returns>\n                inline bool equivalent(\n                    _In_ const std::error_code& arbitraryErrorCode,\n                    _In_ int xboxLiveErrorCondition) const _NOEXCEPT override;\n            };\n\n            /// <summary>\n            /// Gets the one global instance of the error code category.\n            /// </summary>\n            /// <returns>An error category instance.</returns>\n            const xbox_services_error_code_category_impl& xbox_services_error_code_category();\n\n            /// <summary>\n            /// Gets the one global instance of the error condition category.\n            /// </summary>\n            /// <returns>An error category instance.</returns>\n            const xbox_services_error_condition_category_impl& xbox_services_error_condition_category();\n    }\n};\n\n\n#if !HC_PLATFORM_IS_MICROSOFT\n    NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n    inline std::error_code make_error_code(xbox::services::xbox_live_error_code e)\n    {\n        return std::error_code(static_cast<int>(e), xbox::services::xbox_services_error_code_category());\n    }\n\n    inline std::error_condition make_error_condition(xbox::services::xbox_live_error_condition e)\n    {\n        return std::error_condition(static_cast<int>(e), xbox::services::xbox_services_error_condition_category());\n    }\n    NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n#endif\n\n\nnamespace std\n{\n    inline std::error_code make_error_code(xbox::services::xbox_live_error_code e)\n    {\n        return std::error_code(static_cast<int>(e), xbox::services::xbox_services_error_code_category());\n    }\n\n    inline std::error_condition make_error_condition(xbox::services::xbox_live_error_condition e)\n    {\n        return std::error_condition(static_cast<int>(e), xbox::services::xbox_services_error_condition_category());\n    }\n\n    template <>\n    struct is_error_code_enum<xbox::services::xbox_live_error_code> : public true_type{};\n\n    template <>\n    struct is_error_condition_enum<xbox::services::xbox_live_error_condition> : public true_type{};\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\ntemplate<typename T>\nclass xbox_live_result\n{\npublic:\n    xbox_live_result();\n    xbox_live_result(_In_ T payload);\n    xbox_live_result(_In_ std::error_code errorCode, _In_ std::string errorMessage = std::string());\n    xbox_live_result(_In_ T payload, _In_ std::error_code errorCode, _In_ std::string errorMessage = std::string());\n\n    xbox_live_result(_In_ const xbox_live_result&);\n    xbox_live_result& operator=(_In_ const xbox_live_result&);\n    xbox_live_result(_In_ xbox_live_result&& other) noexcept;\n    xbox_live_result& operator=(_In_ xbox_live_result&& other) noexcept;\n\n    /// <summary>\n    /// The payload of the result.  It may be empty if there was an error\n    /// </summary>\n    T& payload();\n\n    /// <summary>\n    /// The payload of the result.  It may be empty if there was an error\n    /// </summary>\n    const T& payload() const;\n\n    /// <summary>\n    /// Sets the payload.\n    /// </summary>\n    void set_payload(T payload);\n\n    /// <summary>\n    /// The error returned by the operation.\n    /// To test for and potentially react to in your code, use the values in xbox_error_condition\n    /// To see the specific error value returned by the operation, use err_code().value() but testing for these values is discouraged.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition\n    /// </summary>\n    const std::error_code& err() const;\n\n    /// <summary>\n    /// Sets the error.\n    /// To test for and potentially react to in your code, use the values in xbox_error_condition\n    /// To see the specific error value returned by the operation, use err_code().value() but testing for these values is discouraged.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition\n    /// </summary>\n    void _Set_err(std::error_code errc);\n\n    /// <summary>\n    /// Returns call specific debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    const std::string& err_message() const;\n\n    /// <summary>\n    /// Sets error code debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    void _Set_err_message(std::string errMessage);\n\nprivate:\n    T m_payload{};\n    std::error_code m_errorCode{};\n    std::string m_errorMessage;\n};\n\ntemplate<>\nclass xbox_live_result <void>\n{\npublic:\n    xbox_live_result()\n        : m_errorMessage(std::string())\n    {\n        m_errorCode = std::make_error_code(xbox_live_error_code::no_error);\n    }\n\n    xbox_live_result(_In_ std::error_code errorCode, _In_ std::string errorMessage = std::string()) :\n        m_errorCode(std::move(errorCode)),\n        m_errorMessage(std::move(errorMessage))\n    {\n    }\n\n    xbox_live_result(_In_ const xbox_live_result& other)\n    {\n        *this = other;\n    }\n\n    xbox_live_result& operator=(_In_ const xbox_live_result& other)\n    {\n        m_errorCode = other.m_errorCode;\n        m_errorMessage = other.m_errorMessage;\n        return *this;\n    }\n\n    xbox_live_result(_In_ xbox_live_result&& other) noexcept\n    {\n        *this = std::move(other);\n    }\n\n    xbox_live_result& operator=(_In_ xbox_live_result&& other) noexcept\n    {\n        if (this != &other)\n        {\n            m_errorCode = std::move(other.m_errorCode);\n            m_errorMessage = std::move(other.m_errorMessage);\n        }\n\n        return *this;\n    }\n\n    /// <summary>\n    /// The error returned by the operation.\n    /// To test for and potentially react to in your code, use the values in xbox_error_condition\n    /// To see the specific error value returned by the operation, use err_code().value() but testing for these values is discouraged.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition\n    /// </summary>\n    const std::error_code& err() const\n    {\n        return m_errorCode;\n    }\n\n    /// <summary>\n    /// Returns call specific debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    const std::string& err_message() const\n    {\n        return m_errorMessage;\n    }\n\n    /// <summary>\n    /// Returns call specific debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    void _Set_err(std::error_code errCode)\n    {\n        m_errorCode = std::move(errCode);\n    }\n\n    /// <summary>\n    /// Sets error code debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    void _Set_err_message(std::string errMessage)\n    {\n        m_errorMessage = std::move(errMessage);\n    }\n\nprivate:\n    std::error_code m_errorCode;\n    std::string m_errorMessage;\n};\n\ntemplate<typename T>\nxbox_live_result<T>::xbox_live_result() :\n    m_errorMessage(std::string())\n{\n    m_errorCode = std::make_error_code(xbox_live_error_code::no_error);\n}\n\ntemplate<typename T>\nxbox_live_result<T>::xbox_live_result(_In_ T payload) :\n    m_payload(std::move(payload)),\n    m_errorMessage(std::string())\n{\n    m_errorCode = std::make_error_code(xbox_live_error_code::no_error);\n}\n\ntemplate<typename T>\nxbox_live_result<T>::xbox_live_result(\n    _In_ std::error_code errorCode,\n    _In_ std::string errorMessage\n    ) :\n    m_errorCode(std::move(errorCode)),\n    m_errorMessage(std::move(errorMessage))\n{\n}\n\ntemplate<typename T>\nxbox_live_result<T>::xbox_live_result(\n    _In_ T payload,\n    _In_ std::error_code errorCode,\n    _In_ std::string errorMessage\n    ) :\n    m_payload(std::move(payload)),\n    m_errorCode(std::move(errorCode)),\n    m_errorMessage(std::move(errorMessage))\n{\n}\n\ntemplate<typename T>\nT& xbox_live_result<T>::payload()\n{\n    return m_payload;\n}\n\ntemplate<typename T>\nconst T& xbox_live_result<T>::payload() const\n{\n    return m_payload;\n}\n\ntemplate<typename T>\nvoid xbox_live_result<T>::set_payload(T payload)\n{\n    m_payload = std::move(payload);\n}\n\ntemplate<typename T>\nconst std::error_code& xbox_live_result<T>::err() const\n{\n    return m_errorCode;\n}\n\ntemplate<typename T>\nvoid xbox_live_result<T>::_Set_err(std::error_code errCode)\n{\n    m_errorCode = std::move(errCode);\n}\n\ntemplate<typename T>\nconst std::string& xbox_live_result<T>::err_message() const\n{\n    return m_errorMessage;\n}\n\ntemplate<typename T>\nvoid xbox_live_result<T>::_Set_err_message(std::string errorMsg)\n{\n    m_errorMessage = std::move(errorMsg);\n}\n\ntemplate<typename T>\nxbox_live_result<T>::xbox_live_result(\n    _In_ const xbox_live_result& other\n) :\n    m_payload{ other.m_payload },\n    m_errorCode{ other.m_errorCode },\n    m_errorMessage{ other.m_errorMessage }\n{\n}\n\ntemplate<typename T>\nxbox_live_result<T>&\nxbox_live_result<T>::operator=(_In_ const xbox_live_result& other)\n{\n    m_payload = other.m_payload;\n    m_errorCode = other.m_errorCode;\n    m_errorMessage = other.m_errorMessage;\n    return *this;\n}\n\ntemplate<typename T>\nxbox_live_result<T>::xbox_live_result(\n    _In_ xbox_live_result&& other\n) noexcept :\n    m_payload{ std::move(other.m_payload) },\n    m_errorCode{ other.m_errorCode },\n    m_errorMessage{ std::move(other.m_errorMessage) }\n{\n}\n\ntemplate<typename T>\nxbox_live_result<T>& xbox_live_result<T>::operator=(_In_ xbox_live_result&& other) noexcept\n{\n    if (this != &other)\n    {\n        m_payload = std::move(other.m_payload);\n        m_errorCode = std::move(other.m_errorCode);\n        m_errorMessage = std::move(other.m_errorMessage);\n    }\n\n    return *this;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/errors.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/events.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#ifdef XSAPI_EVENTS_SERVICE\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass xbox_live_context;\n\nnamespace events\n{\n\n/// <summary>\n/// Represents a service class that provides APIs that you can use to write in-game events.\n/// </summary>\nclass events_service : public std::enable_shared_from_this<events_service>\n{\npublic:\n    /// <summary>\n    /// Write a simple in-game event without providing any data fields.\n    /// </summary>\n    /// <param name=\"eventName\">Event name</param>\n    /// <remarks>\n    /// The name of the event must match the event name declared in the title's service configuration.\n    /// The names are case insensitive.\n    /// If the API writes an event with a name that does not match a name in the service configuration, the\n    /// service drops the event with no notification.\n    /// </remarks>\n    inline xbox_live_result<void> write_in_game_event(_In_ const string_t& eventName);\n\n    /// <summary>\n    /// Write an in-game event that includes \"dimensions\" and \"measurement\" data fields.\n    ///\n    /// Dimensions include event fields with a finite number of defined numeric or string values.\n    /// Examples of dimensions: map id, difficulty level, character or weapon class, game mode, boolean settings, etc.\n    /// \n    /// Measurements include event fields that represent scalar numeric metrics.\n    /// Examples of measurements: score, time, counters, position, etc.\n    ///\n    /// Example: for an in-game event that tracks the highest match score for a particular difficulty level: \n    /// The difficulty level should be included in dimensions, and the score should be included in measurements.\n    /// </summary>\n    /// <param name=\"eventName\">Event name</param>\n    /// <param name=\"dimensions\">Dimensions data fields</param>\n    /// <param name=\"measurements\">Measurement data fields</param>\n    /// <remarks>\n    /// The name of the event, and the names of the event fields (both dimensions and measurements), must match\n    /// the names declared in the title's service configuration. The names are case insensitive.\n    /// If the API writes an event with a name that does not match a name in the service configuration, the\n    /// service drops the event with no notification.\n    /// </remarks>\n    inline xbox_live_result<void> write_in_game_event(\n        _In_ const string_t& eventName,\n        _In_ const web::json::value& dimensions,\n        _In_ const web::json::value& measurement\n        );\n\n    inline events_service(const events_service& other);\n    inline events_service& operator=(events_service other);\n    inline ~events_service();\n\nprivate:\n    inline events_service(_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_xblContext;\n\n    friend xbox_live_context;\n};\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/events.hpp\"\n\n#endif"
  },
  {
    "path": "Include/xsapi-cpp/http_call.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n#include \"xsapi-c/http_call_c.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM_IS_APPLE\n#pragma clang diagnostic ignored \"-Woverloaded-virtual\"\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_BEGIN\nref class XboxLiveUser;\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_END\n#else\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\nclass xbox_live_user;\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass xbox_live_context_settings;\n\n/// <summary>\n/// Enumerates the type of structured data contained in the http response body.\n/// </summary>\nenum class http_call_response_body_type\n{\n    /// <summary>\n    /// The response body consists of a string.\n    /// </summary>\n    string_body,\n\n    /// <summary>\n    /// The response body consists of a vector of bytes.\n    /// </summary>\n    vector_body,\n\n    /// <summary>\n    /// The response body consists of a JavaScript Object Notation (JSON) object.\n    /// </summary>\n    json_body\n};\n\n// Forward declare\nenum class xbox_live_api;\n\n\n/// <summary>\n/// Represents an http response from the Xbox Live service.\n/// </summary>\nclass http_call_response\n{\npublic:\n#ifndef DEFAULT_MOVE_ENABLED\n    inline http_call_response(http_call_response&& other);\n    inline http_call_response& operator=(http_call_response&& other);\n#endif\n    inline http_call_response(\n        _In_ XblHttpCallHandle call,\n        _In_ XblHttpCallResponseBodyType type\n    );\n\n    /// <summary>\n    /// Gets the body type of the response.\n    /// </summary>\n    inline http_call_response_body_type body_type() const;\n\n    /// <summary>\n    /// Gets the response body of the response as a string.\n    /// </summary>\n    inline string_t response_body_string();\n\n    /// <summary>\n    /// Gets the response body of the response as a JSON value.\n    /// </summary>\n    inline web::json::value response_body_json();\n\n    /// <summary>\n    /// Gets the response body of the response as a byte vector.\n    /// </summary>\n    inline std::vector<unsigned char> response_body_vector();\n\n    /// <summary>\n    /// Gets the http headers of the response.\n    /// </summary>\n    inline web::http::http_headers response_headers();\n\n    /// <summary>\n    /// Gets the http status of the response.\n    /// </summary>\n    inline uint32_t http_status();\n\n    /// <summary>\n    /// Gets the error code of the response.\n    /// </summary>\n    inline std::error_code err_code();\n\n    /// <summary>\n    /// Gets the error message of the response.\n    /// </summary>\n    inline std::string err_message();\n\n    /// <summary>\n    /// Gets the eTag of the response.\n    /// </summary>\n    inline string_t e_tag() const;\n\n    /// <summary>\n    /// Gets the response date of the response.\n    /// </summary>\n    inline string_t response_date() const;\n\n    /// <summary>\n    /// Gets the \"retry after\" value found in the response.\n    /// </summary>\n    inline std::chrono::seconds retry_after() const;\n\n\tinline http_call_response(const http_call_response&);\n\tinline http_call_response& operator=(http_call_response other);\n    inline ~http_call_response();\n\nprivate:\n    XblHttpCallHandle m_handle;\n    http_call_response_body_type m_bodyType;\n    string_t m_responseBodyString;\n    web::json::value m_responseBodyJson;\n    std::vector<unsigned char> m_responseBodyVector;\n    web::http::http_headers m_responseHeaders;\n    uint32_t m_httpStatus;\n    std::error_code m_errorCode;\n    std::string m_errMessage;\n\n\tinline http_call_response() = delete;\n};\n\n\nclass http_call\n{\npublic:\n    inline http_call(\n        _In_ XblHttpCallHandle callHandle,\n        _In_ string_t httpMethod,\n        _In_ string_t serverName,\n        _In_ web::uri pathQueryFragment\n    );\n\n#if !XSAPI_NO_PPL\n    /// <summary>\n    /// Attach the Xbox Live token, sign the request, send the request to the service, and return the response.\n    /// </summary>\n    inline pplx::task<std::shared_ptr<http_call_response>> get_response_with_auth(\n        _In_ http_call_response_body_type httpCallResponseBodyType = http_call_response_body_type::json_body\n    );\n\n    inline pplx::task<std::shared_ptr<http_call_response>> get_response_with_auth(\n        _In_ XalUserHandle user,\n        _In_ http_call_response_body_type httpCallResponseBodyType = http_call_response_body_type::json_body,\n        _In_ bool allUsersAuthRequired = false\n    );\n\n    /// <summary>\n    /// Send the request without authentication and get the response.\n    /// </summary>\n    inline pplx::task< std::shared_ptr<http_call_response> > get_response(\n        _In_ http_call_response_body_type httpCallResponseBodyType\n    );\n#endif // !XSAPI_NO_PPL\n\n    /// <summary>\n    /// Sets the request body using a string.\n    /// </summary>\n    inline void set_request_body(_In_ const string_t& value);\n\n    /// <summary>\n    /// Sets the request body using a JSON value.\n    /// </summary>\n    inline void set_request_body(_In_ const web::json::value& value);\n\n    /// <summary>\n    /// Sets the request body using a byte array value.\n    /// </summary>\n    inline void set_request_body(_In_ const std::vector<uint8_t>& value);\n\n    /// <summary>\n    /// Sets a custom header.\n    /// </summary>\n    inline void set_custom_header(\n        _In_ const string_t& headerName,\n        _In_ const string_t& headerValue);\n\n    /// <summary>\n    /// Sets if this is a long http call, and should use the long_http_timeout setting.\n    /// </summary>\n    inline void set_long_http_call(_In_ bool value);\n\n    /// <summary>\n    /// Gets if this is a long http call, and should use the long_http_timeout setting.\n    /// </summary>\n    inline bool long_http_call() const;\n\n    /// <summary>\n    /// Sets if retry is allowed during this call.\n    /// </summary>\n    inline void set_retry_allowed(_In_ bool value);\n\n    /// <summary>\n    /// Get if retry is allowed during this call.\n    /// </summary>\n    inline bool retry_allowed() const;\n\n    /// <summary>\n    /// Sets the content type header value for this call.\n    /// </summary>\n    inline void set_content_type_header_value(_In_ const string_t& value);\n\n    /// <summary>\n    /// Gets the content type header value for this call.\n    /// </summary>\n    inline string_t content_type_header_value() const;\n\n    /// <summary>\n    /// Sets the Xbox Live contract version header value for this call.\n    /// </summary>\n    inline void set_xbox_contract_version_header_value(_In_ const string_t& value);\n\n    /// <summary>\n    /// Gets the Xbox Live contract version header value for this call.\n    /// </summary>\n    inline string_t xbox_contract_version_header_value() const;\n\n    /// <summary>\n    /// Gets the server name for this call.\n    /// </summary>\n    inline string_t server_name() const;\n\n    /// <summary>\n    /// Gets the path for this call.\n    /// </summary>\n    inline const web::uri& path_query_fragment() const;\n\n    /// <summary>\n    /// Gets the http method for this call.\n    /// </summary>\n    inline string_t http_method() const;\n\n    /// <summary>\n    /// Sets a flag indicating if default headers should be added or not.\n    /// </summary>\n    inline void set_add_default_headers(_In_ bool value);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline bool add_default_headers() const;\n\n    inline ~http_call();\n\nprivate:\n    XblHttpCallHandle m_callHandle;\n    string_t m_httpMethod;\n    string_t m_serverName;\n    web::uri m_pathQueryFragment;\n    bool m_longHttpCall;\n    bool m_retryAllowed;\n};\n\ninline std::shared_ptr<http_call> create_xbox_live_http_call(\n    _In_ const std::shared_ptr<xbox_live_context_settings>& xboxLiveContextSettings,\n    _In_ const string_t& httpMethod,\n    _In_ const string_t& serverName,\n    _In_ const web::uri& pathQueryFragment\n);\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/http_call.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/http_call_request_message.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n/// <summary>\n/// Enumerates the type of data contained in the http request body.\n/// </summary>\nenum http_request_message_type\n{\n    /// <summary>\n    /// No message.\n    /// </summary>\n    empty_message,\n\n    /// <summary>\n    /// The message is of type string.\n    /// </summary>\n    string_message,\n\n    /// <summary>\n    /// The message is of type vector, and acts as a memory buffer.\n    /// </summary>\n    vector_message\n};\n\n/// <summary>\n/// Represents an http request message.\n/// </summary>\nclass http_call_request_message\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline http_call_request_message();\n\n    /// <summary>\n    /// The http request message if it is a string type.\n    /// </summary>\n    inline const string_t& request_message_string() const;\n\n    /// <summary>\n    /// The http request message if it is a buffer.\n    /// </summary>\n    inline const std::vector<unsigned char>& request_message_vector() const;\n\n    /// <summary>\n    /// The type of message.\n    /// </summary>\n    inline http_request_message_type get_http_request_message_type() const;\n\nprivate:\n    std::vector<unsigned char> m_requestMessageVector;\n    string_t m_requestMessageString;\n    http_request_message_type m_httpRequestMessageType;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/http_call_request_message.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/impl/achievements.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_BEGIN\n\nachievement_title_association::achievement_title_association(\n    const XblAchievementTitleAssociation& association\n) :\n    m_titleId{ association.titleId }\n{\n    m_name = Utils::StringTFromUtf8(association.name);\n}\n\nconst string_t& achievement_title_association::name() const\n{\n    return m_name;\n}\n\nuint32_t achievement_title_association::title_id() const\n{\n    return m_titleId;\n}\n\nachievement_requirement::achievement_requirement(\n    const XblAchievementRequirement& requirement\n)\n{\n    m_id = Utils::StringTFromUtf8(requirement.id);\n    m_currentProgressValue = Utils::StringTFromUtf8(requirement.currentProgressValue);\n    m_targetProgressValue = Utils::StringTFromUtf8(requirement.targetProgressValue);\n}\n\nconst string_t& achievement_requirement::id() const\n{\n    return m_id;\n}\n\nconst string_t& achievement_requirement::current_progress_value() const\n{\n    return m_currentProgressValue;\n}\n\nconst string_t& achievement_requirement::target_progress_value() const\n{\n    return m_targetProgressValue;\n}\n\nachievement_progression::achievement_progression(\n    const XblAchievementProgression& progression\n)\n{\n    for (size_t i = 0; i < progression.requirementsCount; ++i)\n    {\n        m_requirements.push_back(achievement_requirement{ progression.requirements[i] });\n    }\n    m_timeUnlocked = Utils::DatetimeFromTimeT(progression.timeUnlocked);\n}\n\nconst std::vector<achievement_requirement>& achievement_progression::requirements() const\n{\n    return m_requirements;\n}\n\nconst utility::datetime& achievement_progression::time_unlocked() const\n{\n    return m_timeUnlocked;\n}\n\nachievement_time_window::achievement_time_window(\n    const XblAchievementTimeWindow& timeWindow\n) :\n    m_startDate{ Utils::DatetimeFromTimeT(timeWindow.startDate) },\n    m_endDate{ Utils::DatetimeFromTimeT(timeWindow.endDate) }\n{\n}\n\nconst utility::datetime& achievement_time_window::start_date() const\n{\n    return m_startDate;\n}\n\nconst utility::datetime& achievement_time_window::end_date() const\n{\n    return m_endDate;\n}\n\nachievement_media_asset::achievement_media_asset(\n    const XblAchievementMediaAsset* mediaAsset\n)\n{\n    if (mediaAsset)\n    {\n        m_type = static_cast<achievement_media_asset_type>(mediaAsset->mediaAssetType);\n        if (mediaAsset->name)\n        {\n            m_name = Utils::StringTFromUtf8(mediaAsset->name);\n        }\n        if (mediaAsset->url)\n        {\n            m_url = Utils::StringTFromUtf8(mediaAsset->url);\n        }\n    }\n}\n\nconst string_t& achievement_media_asset::name() const\n{\n    return m_name;\n}\n\nachievement_media_asset_type achievement_media_asset::media_asset_type() const\n{\n    return m_type;\n}\n\nconst web::uri& achievement_media_asset::url() const\n{\n    return m_url;\n}\n\nachievement_reward::achievement_reward(\n    const XblAchievementReward& reward\n) :\n    m_name{ Utils::StringTFromUtf8(reward.name) },\n    m_description{ Utils::StringTFromUtf8(reward.description) },\n    m_value{ Utils::StringTFromUtf8(reward.value) },\n    m_rewardType{ static_cast<achievement_reward_type>(reward.rewardType) },\n    m_valueType{ Utils::StringTFromUtf8(reward.valueType) },\n    m_mediaAsset{ reward.mediaAsset }\n{\n}\n\nconst string_t& achievement_reward::name() const\n{\n    return m_name;\n}\n\nconst string_t& achievement_reward::description() const\n{\n    return m_description;\n}\n\nconst string_t& achievement_reward::value() const\n{\n    return m_value;\n}\n\nachievement_reward_type achievement_reward::reward_type() const\n{\n    return m_rewardType;\n}\n\nconst string_t& achievement_reward::value_type() const\n{\n    return m_valueType;\n}\n\nconst achievement_media_asset& achievement_reward::media_asset() const\n{\n    return m_mediaAsset;\n}\n\nachievement::achievement(\n    XblAchievementsResultHandle handle, \n    const XblAchievement* achievement\n) :\n    m_achievement{ achievement }\n{\n    XblAchievementsResultDuplicateHandle(handle, &m_handle);\n}\n\nachievement::achievement(const achievement& other)\n    : m_achievement{ other.m_achievement }\n{\n    XblAchievementsResultDuplicateHandle(other.m_handle, &m_handle);\n}\n\nachievement& achievement::operator=(achievement other)\n{\n    std::swap(m_handle, other.m_handle);\n    m_achievement = other.m_achievement;\n    return *this;\n}\n\nachievement::~achievement()\n{\n    XblAchievementsResultCloseHandle(m_handle);\n}\n\nstring_t achievement::id() const\n{\n    return Utils::StringTFromUtf8(m_achievement->id);\n}\n\nstring_t achievement::service_configuration_id() const\n{\n    return Utils::StringTFromUtf8(m_achievement->serviceConfigurationId);\n}\n\nstring_t achievement::name() const\n{\n    return Utils::StringTFromUtf8(m_achievement->name);\n}\n\nstd::vector<achievement_title_association> achievement::title_associations() const\n{\n    std::vector<achievement_title_association> titleAssociations;\n    for (size_t i = 0; i < m_achievement->titleAssociationsCount; ++i)\n    {\n        titleAssociations.push_back(achievement_title_association{ m_achievement->titleAssociations[i] });\n    }\n    return titleAssociations;\n}\n\nachievement_progress_state achievement::progress_state() const\n{\n    return static_cast<achievement_progress_state>(m_achievement->progressState);\n}\n\nachievement_progression achievement::progression() const\n{\n    return achievement_progression{ m_achievement->progression };\n}\n\nstd::vector<achievement_media_asset> achievement::media_assets() const\n{\n    std::vector<achievement_media_asset> mediaAssets;\n    for (size_t i = 0; i < m_achievement->mediaAssetsCount; ++i)\n    {\n        mediaAssets.push_back(achievement_media_asset{ &m_achievement->mediaAssets[i] });\n    }\n    return mediaAssets;\n}\n\nstd::vector<string_t> achievement::platforms_available_on() const\n{\n    return Utils::StringTVectorFromCStringArray(m_achievement->platformsAvailableOn, m_achievement->platformsAvailableOnCount);\n}\n\nbool achievement::is_secret() const\n{\n    return m_achievement->isSecret;\n}\n\nstring_t achievement::unlocked_description() const\n{\n    return Utils::StringTFromUtf8(m_achievement->unlockedDescription);\n}\n\nstring_t achievement::locked_description() const\n{\n    return Utils::StringTFromUtf8(m_achievement->lockedDescription);\n}\n\nstring_t achievement::product_id() const\n{\n    return Utils::StringTFromUtf8(m_achievement->productId);\n}\n\nachievement_type achievement::type() const\n{\n    return static_cast<achievement_type>(m_achievement->type);\n}\n\nachievement_participation_type achievement::participation_type() const\n{\n    return static_cast<achievement_participation_type>(m_achievement->participationType);\n}\n\nachievement_time_window achievement::available() const\n{\n    return achievement_time_window{ m_achievement->available };\n}\n\nstd::vector<achievement_reward> achievement::rewards() const\n{\n    std::vector<achievement_reward> rewards;\n    for (size_t i = 0; i < m_achievement->rewardsCount; ++i)\n    {\n        rewards.push_back(achievement_reward{ m_achievement->rewards[i] });\n    }\n    return rewards;\n}\n\nstd::chrono::seconds achievement::estimated_unlock_time() const\n{\n    return std::chrono::seconds{ m_achievement->estimatedUnlockTime };\n}\n\nstring_t achievement::deep_link() const\n{\n    return Utils::StringTFromUtf8(m_achievement->deepLink);\n}\n\nbool achievement::is_revoked() const\n{\n    return m_achievement->isRevoked;\n}\n\nachievements_result::achievements_result(XblAchievementsResultHandle handle)\n{\n    if (handle != nullptr)\n    {\n        XblAchievementsResultDuplicateHandle(handle, &m_handle);\n    }\n}\n\nachievements_result::achievements_result(const achievements_result& other)\n{\n    if (other.m_handle != nullptr)\n    {\n        XblAchievementsResultDuplicateHandle(other.m_handle, &m_handle);\n    }\n}\n\nachievements_result& achievements_result::operator=(achievements_result other)\n{\n    std::swap(m_handle, other.m_handle);\n    return *this;\n}\n\nachievements_result::~achievements_result()\n{\n    XblAchievementsResultCloseHandle(m_handle);\n}\n\nstd::vector<achievement> achievements_result::items() const\n{\n    std::vector<achievement> achievementsVector;\n\n    const XblAchievement* achievements;\n    size_t achievementsCount;\n    HRESULT hr = XblAchievementsResultGetAchievements(m_handle, &achievements, &achievementsCount);\n    if (SUCCEEDED(hr))\n    {\n        for (size_t i = 0; i < achievementsCount; ++i)\n        {\n            achievementsVector.push_back(achievement{ m_handle, achievements + i });\n        }\n    }\n    return achievementsVector;\n}\n\nbool achievements_result::has_next() const\n{\n    bool hasNext{ false };\n    XblAchievementsResultHasNext(m_handle, &hasNext);\n    return hasNext;\n}\n\npplx::task<xbox::services::xbox_live_result<achievements_result>> achievements_result::get_next(\n    _In_ uint32_t maxItems\n)\n{\n    auto asyncWrapper = new AsyncWrapper<achievements_result>(\n        [](XAsyncBlock* async, achievements_result& result)\n    {\n        XblAchievementsResultHandle resultHandle;\n        auto hr = XblAchievementsResultGetNextResult(async, &resultHandle);\n        if (SUCCEEDED(hr))\n        {\n            result = achievements_result{ resultHandle };\n            XblAchievementsResultCloseHandle(resultHandle);\n        }\n        return hr;\n    });\n\n    auto hr = XblAchievementsResultGetNextAsync(m_handle, maxItems, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\n\nachievement_service::achievement_service(XblContextHandle xblContextHandle)\n{\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n}\n\nachievement_service::achievement_service(const achievement_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContextHandle, &m_xblContextHandle);\n}\n\nachievement_service& achievement_service::operator=(achievement_service other)\n{\n    std::swap(m_xblContextHandle, other.m_xblContextHandle);\n    return *this;\n}\n\nachievement_service::~achievement_service()\n{\n    XblContextCloseHandle(m_xblContextHandle);\n}\n\npplx::task<xbox::services::xbox_live_result<void>> achievement_service::update_achievement(\n    _In_ const string_t& xboxUserId,\n    _In_ const string_t& achievementId,\n    _In_ uint32_t percentComplete\n)\n{\n    auto xblContext = m_xblContextHandle;\n\n    auto asyncWrapper = new AsyncWrapper<void>();\n\n    HRESULT hr = XblAchievementsUpdateAchievementAsync(\n        xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        Utils::StringFromStringT(achievementId).c_str(),\n        percentComplete,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n\n}\n\npplx::task<xbox::services::xbox_live_result<void>> achievement_service::update_achievement(\n    _In_ const string_t& xboxUserId,\n    _In_ uint32_t titleId,\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& achievementId,\n    _In_ uint32_t percentComplete\n)\n{\n    auto xblContext = m_xblContextHandle;\n\n    auto asyncWrapper = new AsyncWrapper<void>();\n\n    HRESULT hr = XblAchievementsUpdateAchievementForTitleIdAsync(\n        xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        titleId,\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(achievementId).c_str(),\n        percentComplete,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n\n}\n\npplx::task<xbox::services::xbox_live_result<achievements_result>> achievement_service::get_achievements_for_title_id(\n    _In_ const string_t& xboxUserId,\n    _In_ uint32_t titleId,\n    _In_ achievement_type type,\n    _In_ bool unlockedOnly,\n    _In_ achievement_order_by orderBy,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems\n)\n{\n    auto xblContext = m_xblContextHandle;\n\n    auto asyncWrapper = new AsyncWrapper<achievements_result>(\n        [](XAsyncBlock* async, achievements_result& result)\n        {\n            XblAchievementsResultHandle resultHandle;\n            HRESULT hr = XblAchievementsGetAchievementsForTitleIdResult(async, &resultHandle);\n            if (SUCCEEDED(hr))\n            {\n                result = achievements_result(resultHandle);\n            }\n            return hr;\n        });\n\n    HRESULT hr = XblAchievementsGetAchievementsForTitleIdAsync(\n        xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        titleId,\n        static_cast<XblAchievementType>(type),\n        unlockedOnly,\n        static_cast<XblAchievementOrderBy>(orderBy),\n        skipItems,\n        maxItems,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox::services::xbox_live_result<achievement>> achievement_service::get_achievement(\n    _In_ const string_t& xboxUserId,\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& achievementId\n)\n{\n    auto xblContext = m_xblContextHandle;\n\n    auto asyncWrapper = new AsyncWrapper<achievement>(\n        [](XAsyncBlock* async, achievement result)\n        {\n            XblAchievementsResultHandle resultHandle;\n            HRESULT hr = XblAchievementsGetAchievementResult(async, &resultHandle);\n            if (SUCCEEDED(hr))\n            {\n                const XblAchievement* achievements = nullptr;\n                size_t achievementsCount = 0;\n                hr = XblAchievementsResultGetAchievements(resultHandle, &achievements, &achievementsCount);\n                if (SUCCEEDED(hr))\n                {\n                    result = achievement(resultHandle, achievements);\n                }\n            }\n            return hr;\n        });\n\n    HRESULT hr = XblAchievementsGetAchievementAsync(\n        xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(achievementId).c_str(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/errors.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include <sstream>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nstatic xbox_services_error_code_category_impl s_error_code_category_instance;\n\ninline const xbox_services_error_code_category_impl& xbox_services_error_code_category()\n{\n    return s_error_code_category_instance;\n}\n\nstatic xbox_services_error_condition_category_impl s_error_condition_category_instance;\n\ninline const xbox_services_error_condition_category_impl& xbox_services_error_condition_category()\n{\n    return s_error_condition_category_instance;\n}\n\ninline std::string xbox_services_error_code_category_impl::message(_In_ int errorCode) const _NOEXCEPT\n{\n    xbox_live_error_code code = static_cast<xbox_live_error_code>(errorCode);\n    switch (code)\n    {\n        case xbox_live_error_code::no_error: return \"No error\";\n        case xbox_live_error_code::bad_alloc: return \"bad_alloc\";\n        case xbox_live_error_code::bad_cast: return \"bad_cast\";\n        case xbox_live_error_code::invalid_argument: return \"invalid_argument\";\n        case xbox_live_error_code::out_of_range: return \"out_of_range\";\n        case xbox_live_error_code::length_error: return \"length_error\";\n        case xbox_live_error_code::range_error: return \"range_error\";\n        case xbox_live_error_code::logic_error: return \"logic_error\";\n        case xbox_live_error_code::runtime_error: return \"runtime_error\";\n        case xbox_live_error_code::json_error: return \"json_error\";\n        case xbox_live_error_code::websocket_error: return \"websocket_error\";\n        case xbox_live_error_code::uri_error: return \"uri_error\";\n        case xbox_live_error_code::generic_error: return \"generic_error\";\n\n        case xbox_live_error_code::rta_generic_error: return \"rta_generic_error\";\n        case xbox_live_error_code::rta_access_denied: return \"rta_access_denied\";\n        case xbox_live_error_code::rta_subscription_limit_reached: return \"rta_subscription_limit_reached\";\n\n        case xbox_live_error_code::auth_user_interaction_required: return \"auth_user_interaction_required\";\n        case xbox_live_error_code::auth_user_switched: return \"auth_user_switched\";\n        case xbox_live_error_code::auth_user_cancel: return \"auth_user_cancel\";\n        case xbox_live_error_code::auth_unknown_error: return \"auth_unknown_error\";\n        case xbox_live_error_code::auth_user_not_signed_in: return \"auth_user_not_signed_in\";\n        case xbox_live_error_code::auth_runtime_error: return \"auth_runtime_error\";\n        case xbox_live_error_code::auth_no_token_error: return \"auth_no_token_error\";\n\n        case xbox_live_error_code::invalid_config: return \"invalid_config\";\n        case xbox_live_error_code::unsupported: return \"unsupported\";\n\n        case xbox_live_error_code::HR_ERROR_INTERNET_TIMEOUT: return \"ERROR_INTERNET_TIMEOUT\";\n        case xbox_live_error_code::AM_E_XASD_UNEXPECTED: return \"AM_E_XASD_UNEXPECTED\";\n        case xbox_live_error_code::AM_E_XASU_UNEXPECTED: return \"AM_E_XASU_UNEXPECTED\";\n        case xbox_live_error_code::AM_E_XAST_UNEXPECTED: return \"AM_E_XAST_UNEXPECTED\";\n        case xbox_live_error_code::AM_E_XSTS_UNEXPECTED: return \"AM_E_XSTS_UNEXPECTED\";\n        case xbox_live_error_code::AM_E_XDEVICE_UNEXPECTED: return \"AM_E_XDEVICE_UNEXPECTED\";\n        case xbox_live_error_code::AM_E_DEVMODE_NOT_AUTHORIZED: return \"AM_E_DEVMODE_NOT_AUTHORIZED\";\n        case xbox_live_error_code::AM_E_NOT_AUTHORIZED: return \"AM_E_NOT_AUTHORIZED\";\n        case xbox_live_error_code::AM_E_FORBIDDEN: return \"AM_E_FORBIDDEN\";\n        case xbox_live_error_code::AM_E_UNKNOWN_TARGET: return \"AM_E_UNKNOWN_TARGET\";\n        case xbox_live_error_code::AM_E_INVALID_NSAL_DATA: return \"AM_E_INVALID_NSAL_DATA\";\n        case xbox_live_error_code::AM_E_TITLE_NOT_AUTHENTICATED: return \"AM_E_TITLE_NOT_AUTHENTICATED\";\n        case xbox_live_error_code::AM_E_TITLE_NOT_AUTHORIZED: return \"AM_E_TITLE_NOT_AUTHORIZED\";\n        case xbox_live_error_code::AM_E_USER_HASH_MISSING: return \"AM_E_USER_HASH_MISSING\";\n        case xbox_live_error_code::AM_E_USER_NOT_FOUND: return \"AM_E_USER_NOT_FOUND\";\n        case xbox_live_error_code::AM_E_INVALID_ENVIRONMENT: return \"AM_E_INVALID_ENVIRONMENT\";\n        case xbox_live_error_code::AM_E_XASD_TIMEOUT: return \"AM_E_XASD_TIMEOUT\";\n        case xbox_live_error_code::AM_E_XASU_TIMEOUT: return \"AM_E_XASU_TIMEOUT\";\n        case xbox_live_error_code::AM_E_XAST_TIMEOUT: return \"AM_E_XAST_TIMEOUT\";\n        case xbox_live_error_code::AM_E_XSTS_TIMEOUT: return \"AM_E_XSTS_TIMEOUT\";\n        case xbox_live_error_code::AM_E_LIVE_CONNECTION_REQUIRED: return \"AM_E_LIVE_CONNECTION_REQUIRED\";\n        case xbox_live_error_code::AM_E_NO_NETWORK: return \"AM_E_NO_NETWORK\";\n        case xbox_live_error_code::AM_E_XTITLE_UNEXPECTED: return \"AM_E_XTITLE_UNEXPECTED\";\n        case xbox_live_error_code::AM_E_NO_TOKEN_REQUIRED: return \"AM_E_NO_TOKEN_REQUIRED\";\n        case xbox_live_error_code::AM_E_XTITLE_TIMEOUT: return \"AM_E_XTITLE_TIMEOUT\";\n        case xbox_live_error_code::XO_E_DEVMODE_NOT_AUTHORIZED: return \"XO_E_DEVMODE_NOT_AUTHORIZED\";\n        case xbox_live_error_code::XO_E_SYSTEM_UPDATE_REQUIRED: return \"XO_E_SYSTEM_UPDATE_REQUIRED\";\n        case xbox_live_error_code::XO_E_CONTENT_UPDATE_REQUIRED: return \"XO_E_CONTENT_UPDATE_REQUIRED\";\n        case xbox_live_error_code::XO_E_ENFORCEMENT_BAN: return \"XO_E_ENFORCEMENT_BAN\";\n        case xbox_live_error_code::XO_E_THIRD_PARTY_BAN: return \"XO_E_THIRD_PARTY_BAN\";\n        case xbox_live_error_code::XO_E_ACCOUNT_PARENTALLY_RESTRICTED: return \"XO_E_ACCOUNT_PARENTALLY_RESTRICTED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED: return \"XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED: return \"XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED: return \"XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED: return \"XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_CURFEW: return \"XO_E_ACCOUNT_CURFEW\";\n        case xbox_live_error_code::XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY: return \"XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY\";\n        case xbox_live_error_code::XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED: return \"XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_MAINTENANCE_REQUIRED: return \"XO_E_ACCOUNT_MAINTENANCE_REQUIRED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_TYPE_NOT_ALLOWED: return \"XO_E_ACCOUNT_TYPE_NOT_ALLOWED\";\n        case xbox_live_error_code::XO_E_CONTENT_ISOLATION: return \"XO_E_CONTENT_ISOLATION\";\n        case xbox_live_error_code::XO_E_ACCOUNT_NAME_CHANGE_REQUIRED: return \"XO_E_ACCOUNT_NAME_CHANGE_REQUIRED\";\n        case xbox_live_error_code::XO_E_DEVICE_CHALLENGE_REQUIRED: return \"XO_E_DEVICE_CHALLENGE_REQUIRED\";\n        case xbox_live_error_code::XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED: return \"XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED\";\n        case xbox_live_error_code::XO_E_PIN_CHALLENGE_REQUIRED: return \"XO_E_PIN_CHALLENGE_REQUIRED\";\n        case xbox_live_error_code::XO_E_RETAIL_ACCOUNT_NOT_ALLOWED: return \"XO_E_RETAIL_ACCOUNT_NOT_ALLOWED\";\n        case xbox_live_error_code::XO_E_SANDBOX_NOT_ALLOWED: return \"XO_E_SANDBOX_NOT_ALLOWED\";\n        case xbox_live_error_code::XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER: return \"XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER\";\n        case xbox_live_error_code::XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED: return \"XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED\";\n        case xbox_live_error_code::XO_E_CONTENT_NOT_AUTHORIZED: return \"XO_E_CONTENT_NOT_AUTHORIZED\";\n\n        case xbox_live_error_code::http_status_204_resource_data_not_found: return \"204 - ResourceDataNotFound\"; \n        case xbox_live_error_code::http_status_400_bad_request: return \"400 - BadRequest\";\n        case xbox_live_error_code::http_status_401_unauthorized: return \"401 - Unauthorized\";\n        case xbox_live_error_code::http_status_403_forbidden: return \"403 - Forbidden\";\n        case xbox_live_error_code::http_status_404_not_found: return \"404 - NotFound\";\n        case xbox_live_error_code::http_status_405_method_not_allowed: return \"405 - MethodNotAllowed\";\n        case xbox_live_error_code::http_status_406_not_acceptable: return \"406 - NotAcceptable\";\n        case xbox_live_error_code::http_status_407_proxy_authentication_required: return \"407 - ProxyAuthenticationRequired\";\n        case xbox_live_error_code::http_status_408_request_timeout: return \"408 - RequestTimeout\";\n        case xbox_live_error_code::http_status_409_conflict: return \"409 - Conflict\";\n        case xbox_live_error_code::http_status_410_gone: return \"410 - Gone\";\n        case xbox_live_error_code::http_status_411_length_required: return \"411 - LengthRequired\";\n        case xbox_live_error_code::http_status_412_precondition_failed: return \"412 - PreconditionFailed\";\n        case xbox_live_error_code::http_status_413_request_entity_too_large: return \"413 - RequestEntityTooLarge\";\n        case xbox_live_error_code::http_status_414_request_uri_too_long: return \"414 - RequestUriTooLong\";\n        case xbox_live_error_code::http_status_415_unsupported_media_type: return \"415 - UnsupportedMediaType\";\n        case xbox_live_error_code::http_status_416_requested_range_not_satisfiable: return \"416 - RequestedRangeNotSatisfiable\";\n        case xbox_live_error_code::http_status_417_expectation_failed: return \"417 - Expectation Failed\";\n        case xbox_live_error_code::http_status_421_misdirected_request: return \"421 - Misdirected Request\";\n        case xbox_live_error_code::http_status_422_unprocessable_entity: return \"422 - Unprocessable Entity\";\n        case xbox_live_error_code::http_status_423_locked: return \"423 - Locked\";\n        case xbox_live_error_code::http_status_424_failed_dependency: return \"424 - Failed Dependency\";\n        case xbox_live_error_code::http_status_426_upgrade_required: return \"426 - Upgrade Required\";\n        case xbox_live_error_code::http_status_428_precondition_required: return \"428 - Precondition Required\";\n        case xbox_live_error_code::http_status_429_too_many_requests: return \"429 - TooManyRequests\";\n        case xbox_live_error_code::http_status_431_request_header_fields_too_large: return \"431 - Request Header Fields Too Large\";\n        case xbox_live_error_code::http_status_451_unavailable_for_legal_reasons: return \"451 - Unavailable For Legal Reasons\";\n        case xbox_live_error_code::http_status_500_internal_server_error: return \"500 - InternalServerError\";\n        case xbox_live_error_code::http_status_501_not_implemented: return \"501 - Not Implemented\";\n        case xbox_live_error_code::http_status_502_bad_gateway: return \"502 - Bad Gateway\";\n        case xbox_live_error_code::http_status_503_service_unavailable: return \"503 - ServiceUnavailable\";\n        case xbox_live_error_code::http_status_504_gateway_timeout: return \"504 - GatewayTimeout\";\n        case xbox_live_error_code::http_status_505_http_version_not_supported: return \"505 - HttpVersionNotSupported\";\n        case xbox_live_error_code::http_status_506_variant_also_negotiates: return \"506 - Variant Also Negotiates\";\n        case xbox_live_error_code::http_status_507_insufficient_storage: return \"507 - Insufficient Storage\";\n        case xbox_live_error_code::http_status_508_loop_detected: return \"508 - Loop Detected\";\n        case xbox_live_error_code::http_status_510_not_extended: return \"510 - Not Extended\";\n        case xbox_live_error_code::http_status_511_network_authentication_required: return \"511 - Network Authentication Required\";\n\n        case xbox_live_error_code::HR_INET_E_INVALID_URL: return \"INET_E_INVALID_URL\";\n        case xbox_live_error_code::HR_INET_E_NO_SESSION: return \"INET_E_NO_SESSION\";\n        case xbox_live_error_code::HR_INET_E_CANNOT_CONNECT: return \"INET_E_CANNOT_CONNECT\";\n        case xbox_live_error_code::HR_INET_E_RESOURCE_NOT_FOUND: return \"INET_E_RESOURCE_NOT_FOUND\";\n        case xbox_live_error_code::HR_INET_E_OBJECT_NOT_FOUND: return \"INET_E_OBJECT_NOT_FOUND\";\n        case xbox_live_error_code::HR_INET_E_DATA_NOT_AVAILABLE: return \"INET_E_DATA_NOT_AVAILABLE\";\n        case xbox_live_error_code::HR_INET_E_DOWNLOAD_FAILURE: return \"INET_E_DOWNLOAD_FAILURE\";\n        case xbox_live_error_code::HR_INET_E_AUTHENTICATION_REQUIRED: return \"INET_E_AUTHENTICATION_REQUIRED\";\n        case xbox_live_error_code::HR_INET_E_NO_VALID_MEDIA: return \"INET_E_NO_VALID_MEDIA\";\n        case xbox_live_error_code::HR_INET_E_CONNECTION_TIMEOUT: return \"INET_E_CONNECTION_TIMEOUT\";\n        case xbox_live_error_code::HR_INET_E_INVALID_REQUEST: return \"INET_E_INVALID_REQUEST\";\n        case xbox_live_error_code::HR_INET_E_UNKNOWN_PROTOCOL: return \"INET_E_UNKNOWN_PROTOCOL\";\n        case xbox_live_error_code::HR_INET_E_SECURITY_PROBLEM: return \"INET_E_SECURITY_PROBLEM\";\n        case xbox_live_error_code::HR_INET_E_CANNOT_LOAD_DATA: return \"INET_E_CANNOT_LOAD_DATA\";\n        case xbox_live_error_code::HR_INET_E_CANNOT_INSTANTIATE_OBJECT: return \"INET_E_CANNOT_INSTANTIATE_OBJECT\";\n        case xbox_live_error_code::HR_INET_E_INVALID_CERTIFICATE: return \"INET_E_INVALID_CERTIFICATE\";\n        case xbox_live_error_code::HR_INET_E_REDIRECT_FAILED: return \"INET_E_REDIRECT_FAILED\";\n        case xbox_live_error_code::HR_INET_E_REDIRECT_TO_DIR: return \"INET_E_REDIRECT_TO_DIR\";\n        case xbox_live_error_code::HR_ERROR_NETWORK_UNREACHABLE: return \"ERROR_NETWORK_UNREACHABLE\";\n\n        default:\n        {\n            std::stringstream msg;\n            msg << \"Unknown error: 0x\" << std::hex << errorCode;\n            return msg.str();\n        }\n    }\n}\n\ninline std::string xbox_services_error_condition_category_impl::message(_In_ int errorCode) const _NOEXCEPT\n{\n    xbox_live_error_condition code = static_cast<xbox_live_error_condition>(errorCode);\n\n    switch (code)\n    {\n        case xbox_live_error_condition::no_error: return \"No error\";\n        case xbox_live_error_condition::generic_error: return \"Generic Error\";\n        case xbox_live_error_condition::generic_out_of_range: return \"Out of Range\";\n        case xbox_live_error_condition::auth: return \"Authorization Error\";\n        case xbox_live_error_condition::http: return \"HTTP\";\n        case xbox_live_error_condition::http_404_not_found: return \"404 - Not Found\";\n        case xbox_live_error_condition::http_412_precondition_failed: return \"412 - PreconditionFailed\";\n        case xbox_live_error_condition::http_429_too_many_requests: return \"429- Too Many Requests\";\n        case xbox_live_error_condition::http_service_timeout: return \"Service Timeout\";\n        case xbox_live_error_condition::network: return \"Network Error\";\n        case xbox_live_error_condition::rta: return \"Real Time Activity\";\n        \n        default:\n        {\n            std::stringstream msg;\n            msg << \"Unknown error: 0x\" << std::hex << errorCode;\n            return msg.str();\n        }\n    }\n}\n\ninline bool xbox_services_error_condition_category_impl::equivalent(\n    _In_ const std::error_code& arbitraryErrorCode,\n    _In_ int xboxLiveErrorCondition) const _NOEXCEPT\n{\n    if (arbitraryErrorCode.category() != xbox_services_error_code_category())\n    {\n        return false;\n    }\n\n    xbox_live_error_code code = static_cast<xbox_live_error_code>(arbitraryErrorCode.value());\n    xbox_live_error_condition condition = static_cast<xbox_live_error_condition>(xboxLiveErrorCondition);\n\n    // range 0x80860000 - 0x8086FFFF is reserved for other OnlineId error code\n    // put is under auth_msa error condition\n    if ((arbitraryErrorCode.value() & 0x80860000) == 0x80860000)\n    {\n        return condition == xbox_live_error_condition::auth;\n    }\n\n    switch (code)\n    {\n        case xbox_live_error_code::no_error:\n            return (condition == xbox_live_error_condition::no_error);\n\n        case xbox_live_error_code::http_status_404_not_found:\n            return (condition == xbox_live_error_condition::http_404_not_found ||\n                    condition == xbox_live_error_condition::http);\n\n        case xbox_live_error_code::http_status_412_precondition_failed:\n            return (condition == xbox_live_error_condition::http_412_precondition_failed ||\n                    condition == xbox_live_error_condition::http);\n\n        case xbox_live_error_code::http_status_408_request_timeout:\n        case xbox_live_error_code::http_status_503_service_unavailable:\n        case xbox_live_error_code::http_status_504_gateway_timeout:\n            return (condition == xbox_live_error_condition::http_service_timeout ||\n                    condition == xbox_live_error_condition::http);\n\n        case xbox_live_error_code::http_status_429_too_many_requests:\n            return (condition == xbox_live_error_condition::http_429_too_many_requests ||\n                    condition == xbox_live_error_condition::http);\n\n        case xbox_live_error_code::http_status_500_internal_server_error:\n            return (condition == xbox_live_error_condition::http);\n\n        case xbox_live_error_code::http_status_204_resource_data_not_found:\n        case xbox_live_error_code::http_status_400_bad_request:\n        case xbox_live_error_code::http_status_401_unauthorized:\n        case xbox_live_error_code::http_status_402_payment_required:\n        case xbox_live_error_code::http_status_403_forbidden:\n        case xbox_live_error_code::http_status_405_method_not_allowed:\n        case xbox_live_error_code::http_status_406_not_acceptable:\n        case xbox_live_error_code::http_status_407_proxy_authentication_required:\n        case xbox_live_error_code::http_status_409_conflict:\n        case xbox_live_error_code::http_status_410_gone:\n        case xbox_live_error_code::http_status_411_length_required:\n        case xbox_live_error_code::http_status_413_request_entity_too_large:\n        case xbox_live_error_code::http_status_414_request_uri_too_long:\n        case xbox_live_error_code::http_status_415_unsupported_media_type:\n        case xbox_live_error_code::http_status_416_requested_range_not_satisfiable:\n        case xbox_live_error_code::http_status_417_expectation_failed:\n        case xbox_live_error_code::http_status_421_misdirected_request:\n        case xbox_live_error_code::http_status_422_unprocessable_entity:\n        case xbox_live_error_code::http_status_423_locked:\n        case xbox_live_error_code::http_status_424_failed_dependency:\n        case xbox_live_error_code::http_status_426_upgrade_required:\n        case xbox_live_error_code::http_status_428_precondition_required:\n        case xbox_live_error_code::http_status_431_request_header_fields_too_large:\n        case xbox_live_error_code::http_status_449_retry_with:\n        case xbox_live_error_code::http_status_451_unavailable_for_legal_reasons:\n        case xbox_live_error_code::http_status_501_not_implemented:\n        case xbox_live_error_code::http_status_502_bad_gateway:\n        case xbox_live_error_code::http_status_505_http_version_not_supported:\n        case xbox_live_error_code::http_status_506_variant_also_negotiates:\n        case xbox_live_error_code::http_status_507_insufficient_storage:\n        case xbox_live_error_code::http_status_508_loop_detected:\n        case xbox_live_error_code::http_status_510_not_extended:\n        case xbox_live_error_code::http_status_511_network_authentication_required:\n            return (condition == xbox_live_error_condition::http);\n\n        case xbox_live_error_code::auth_user_interaction_required:\n        case xbox_live_error_code::auth_user_switched:\n        case xbox_live_error_code::auth_unknown_error:\n        case xbox_live_error_code::auth_user_cancel:\n        case xbox_live_error_code::auth_user_not_signed_in:\n        case xbox_live_error_code::auth_runtime_error:\n        case xbox_live_error_code::auth_no_token_error:\n            return condition == xbox_live_error_condition::auth;\n\n        case xbox_live_error_code::invalid_config:\n        case xbox_live_error_code::unsupported:\n            return condition == xbox_live_error_condition::generic_error;\n\n        case xbox_live_error_code::AM_E_XASD_UNEXPECTED:\n        case xbox_live_error_code::AM_E_XASU_UNEXPECTED:\n        case xbox_live_error_code::AM_E_XAST_UNEXPECTED:\n        case xbox_live_error_code::AM_E_XSTS_UNEXPECTED:\n        case xbox_live_error_code::AM_E_XDEVICE_UNEXPECTED:\n        case xbox_live_error_code::AM_E_DEVMODE_NOT_AUTHORIZED:\n        case xbox_live_error_code::AM_E_NOT_AUTHORIZED:\n        case xbox_live_error_code::AM_E_FORBIDDEN:\n        case xbox_live_error_code::AM_E_UNKNOWN_TARGET:\n        case xbox_live_error_code::AM_E_INVALID_NSAL_DATA:\n        case xbox_live_error_code::AM_E_TITLE_NOT_AUTHENTICATED:\n        case xbox_live_error_code::AM_E_TITLE_NOT_AUTHORIZED:\n        case xbox_live_error_code::AM_E_USER_HASH_MISSING:\n        case xbox_live_error_code::AM_E_USER_NOT_FOUND:\n        case xbox_live_error_code::AM_E_INVALID_ENVIRONMENT:\n        case xbox_live_error_code::AM_E_XASD_TIMEOUT:\n        case xbox_live_error_code::AM_E_XASU_TIMEOUT:\n        case xbox_live_error_code::AM_E_XAST_TIMEOUT:\n        case xbox_live_error_code::AM_E_XSTS_TIMEOUT:\n        case xbox_live_error_code::AM_E_LIVE_CONNECTION_REQUIRED:\n        case xbox_live_error_code::AM_E_NO_NETWORK:\n        case xbox_live_error_code::AM_E_XTITLE_UNEXPECTED:\n        case xbox_live_error_code::AM_E_NO_TOKEN_REQUIRED:\n        case xbox_live_error_code::AM_E_XTITLE_TIMEOUT:\n        case xbox_live_error_code::XO_E_DEVMODE_NOT_AUTHORIZED:\n        case xbox_live_error_code::XO_E_SYSTEM_UPDATE_REQUIRED:\n        case xbox_live_error_code::XO_E_CONTENT_UPDATE_REQUIRED:\n        case xbox_live_error_code::XO_E_ENFORCEMENT_BAN:\n        case xbox_live_error_code::XO_E_THIRD_PARTY_BAN:\n        case xbox_live_error_code::XO_E_ACCOUNT_PARENTALLY_RESTRICTED:\n        case xbox_live_error_code::XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED:\n        case xbox_live_error_code::XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED:\n        case xbox_live_error_code::XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED:\n        case xbox_live_error_code::XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED:\n        case xbox_live_error_code::XO_E_ACCOUNT_CURFEW:\n        case xbox_live_error_code::XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY:\n        case xbox_live_error_code::XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED:\n        case xbox_live_error_code::XO_E_ACCOUNT_MAINTENANCE_REQUIRED:\n        case xbox_live_error_code::XO_E_ACCOUNT_TYPE_NOT_ALLOWED:\n        case xbox_live_error_code::XO_E_CONTENT_ISOLATION:\n        case xbox_live_error_code::XO_E_ACCOUNT_NAME_CHANGE_REQUIRED:\n        case xbox_live_error_code::XO_E_DEVICE_CHALLENGE_REQUIRED:\n        case xbox_live_error_code::XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED:\n        case xbox_live_error_code::XO_E_PIN_CHALLENGE_REQUIRED:\n        case xbox_live_error_code::XO_E_RETAIL_ACCOUNT_NOT_ALLOWED:\n        case xbox_live_error_code::XO_E_SANDBOX_NOT_ALLOWED:\n        case xbox_live_error_code::XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER:\n        case xbox_live_error_code::XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED:\n        case xbox_live_error_code::XO_E_CONTENT_NOT_AUTHORIZED:\n        case xbox_live_error_code::HR_ERROR_INTERNET_TIMEOUT:\n            return (condition == xbox_live_error_condition::auth);\n\n        case xbox_live_error_code::HR_INET_E_INVALID_URL:\n        case xbox_live_error_code::HR_INET_E_NO_SESSION:\n        case xbox_live_error_code::HR_INET_E_CANNOT_CONNECT:\n        case xbox_live_error_code::HR_INET_E_RESOURCE_NOT_FOUND:\n        case xbox_live_error_code::HR_INET_E_OBJECT_NOT_FOUND:\n        case xbox_live_error_code::HR_INET_E_DATA_NOT_AVAILABLE:\n        case xbox_live_error_code::HR_INET_E_DOWNLOAD_FAILURE:\n        case xbox_live_error_code::HR_INET_E_AUTHENTICATION_REQUIRED:\n        case xbox_live_error_code::HR_INET_E_NO_VALID_MEDIA:\n        case xbox_live_error_code::HR_INET_E_CONNECTION_TIMEOUT:\n        case xbox_live_error_code::HR_INET_E_INVALID_REQUEST:\n        case xbox_live_error_code::HR_INET_E_UNKNOWN_PROTOCOL:\n        case xbox_live_error_code::HR_INET_E_SECURITY_PROBLEM:\n        case xbox_live_error_code::HR_INET_E_CANNOT_LOAD_DATA:\n        case xbox_live_error_code::HR_INET_E_CANNOT_INSTANTIATE_OBJECT:\n        case xbox_live_error_code::HR_INET_E_INVALID_CERTIFICATE:\n        case xbox_live_error_code::HR_INET_E_REDIRECT_FAILED:\n        case xbox_live_error_code::HR_INET_E_REDIRECT_TO_DIR:\n        case xbox_live_error_code::HR_ERROR_NETWORK_UNREACHABLE:\n            return (condition == xbox_live_error_condition::network);\n\n        case xbox_live_error_code::out_of_range:\n            return (condition == xbox_live_error_condition::generic_out_of_range ||\n                condition == xbox_live_error_condition::generic_error);\n\n        case xbox_live_error_code::bad_alloc:\n        case xbox_live_error_code::bad_cast:\n        case xbox_live_error_code::invalid_argument:\n        case xbox_live_error_code::json_error:\n        case xbox_live_error_code::length_error:\n        case xbox_live_error_code::range_error:\n        case xbox_live_error_code::logic_error:\n        case xbox_live_error_code::runtime_error:\n        case xbox_live_error_code::uri_error:\n        case xbox_live_error_code::rta_generic_error:\n        case xbox_live_error_code::rta_access_denied:\n        case xbox_live_error_code::rta_subscription_limit_reached:\n        case xbox_live_error_code::generic_error:\n        default:\n            return (condition == xbox_live_error_condition::generic_error);\n        \n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/events.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n#include \"xsapi-c/events_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nevents_service::events_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nevents_service::events_service(const events_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nevents_service& events_service::operator=(events_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nevents_service::~events_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\nxbox_live_result<void> events_service::write_in_game_event(\n    _In_ const string_t& eventName\n)\n{\n    return xbox_live_result<void>(Utils::ConvertHr(XblEventsWriteInGameEvent(m_xblContext, Utils::StringFromStringT(eventName).data(), nullptr, nullptr)));\n}\n\nxbox_live_result<void> events_service::write_in_game_event(\n    _In_ const string_t& eventName,\n    _In_ const web::json::value& dimensionsJson,\n    _In_ const web::json::value& measurementJson\n)\n{\n    return xbox_live_result<void>(Utils::ConvertHr(XblEventsWriteInGameEvent(\n        m_xblContext,\n        Utils::StringFromStringT(eventName).data(),\n        Utils::StringFromStringT(dimensionsJson.serialize()).data(),\n        Utils::StringFromStringT(measurementJson.serialize()).data()\n    )));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/http_call.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n#include \"../xbox_live_context_settings.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\nhttp_call_response::http_call_response(\n    _In_ XblHttpCallHandle call,\n    _In_ XblHttpCallResponseBodyType type\n)\n{\n    XblHttpCallDuplicateHandle(call, &m_handle);\n    m_bodyType = static_cast<http_call_response_body_type>(type);\n}\n\nhttp_call_response_body_type http_call_response::body_type() const\n{\n    return m_bodyType;\n}\n\nstring_t http_call_response::response_body_string()\n{\n    if (m_responseBodyString != string_t())\n    {\n        return m_responseBodyString;\n    }\n\n    const char* responseString;\n    HRESULT hr = XblHttpCallGetResponseString(m_handle, &responseString);\n    if (FAILED(hr))\n    {\n        return string_t();\n    }\n\n    m_responseBodyString = Utils::StringTFromUtf8(responseString);\n    return m_responseBodyString;\n}\n\nweb::json::value http_call_response::response_body_json()\n{\n    auto str = response_body_string();\n    m_responseBodyJson = web::json::value::parse(str);\n    return m_responseBodyJson;\n}\n\nstd::vector<unsigned char> http_call_response::response_body_vector()\n{\n    if (!m_responseBodyVector.empty())\n    {\n        return m_responseBodyVector;\n    }\n\n    size_t bufferSize;\n    HRESULT hr = XblHttpCallGetResponseBodyBytesSize(m_handle, &bufferSize);\n    if (FAILED(hr))\n    {\n        return {};\n    }\n\n    uint8_t* buffer = new uint8_t[bufferSize];\n    size_t bufferUsed;\n    hr = XblHttpCallGetResponseBodyBytes(m_handle, bufferSize, buffer, &bufferUsed);\n    if (FAILED(hr))\n    {\n        return {};\n    }\n\n    auto bufferInput = std::vector<uint8_t>(buffer, buffer + bufferUsed);\n    m_responseBodyVector = std::vector<unsigned char>(bufferUsed);\n    std::transform(bufferInput.begin(), bufferInput.end(), m_responseBodyVector.begin(),\n        [](uint8_t c)\n    {\n        return static_cast<unsigned char>(c);\n    });\n\n    return m_responseBodyVector;\n}\n\nweb::http::http_headers http_call_response::response_headers()\n{\n    if (!m_responseHeaders.empty())\n    {\n        return m_responseHeaders;\n    }\n\n    uint32_t numHeader;\n    HRESULT hr = XblHttpCallGetNumHeaders(m_handle, &numHeader);\n    if (FAILED(hr))\n    {\n        return web::http::http_headers();\n    }\n\n    const char* headerName;\n    const char* headerValue;\n    auto headers = web::http::http_headers();\n    for (auto i = 0u; i < numHeader; i++)\n    {\n        hr = XblHttpCallGetHeaderAtIndex(m_handle, i, &headerName, &headerValue);\n        if (SUCCEEDED(hr))\n        {\n            headers.add(Utils::StringTFromUtf8(headerName), Utils::StringTFromUtf8(headerValue));\n        }\n    }\n\n    m_responseHeaders = headers;\n    return headers;\n}\n\nuint32_t http_call_response::http_status()\n{\n    uint32_t statusCode;\n    HRESULT hr = XblHttpCallGetStatusCode(m_handle, &statusCode);\n    if (FAILED(hr))\n    {\n        return 0;\n    }\n\n    m_httpStatus = statusCode;\n    return m_httpStatus;\n}\n\nstd::error_code http_call_response::err_code()\n{\n    if (m_errorCode == std::error_code())\n    {\n        return m_errorCode;\n    }\n\n    HRESULT networkErrorCode;\n    uint32_t platformNetworkErrorCode;\n\n    HRESULT hr = XblHttpCallGetNetworkErrorCode(m_handle, &networkErrorCode, &platformNetworkErrorCode);\n    if (FAILED(hr))\n    {\n        return std::make_error_code(Utils::ConvertHrToXblErrorCode(hr));\n    }\n\n    m_errorCode = std::make_error_code(Utils::ConvertHrToXblErrorCode(networkErrorCode));\n    return m_errorCode;\n}\n\nstd::string http_call_response::err_message()\n{\n    if (m_errMessage != std::string())\n    {\n        return m_errMessage;\n    }\n\n    const char* errorMessage;\n    HRESULT hr = XblHttpCallGetPlatformNetworkErrorMessage(m_handle, &errorMessage);\n    if (FAILED(hr))\n    {\n        return std::string();\n    }\n\n    m_errMessage = std::string(errorMessage);\n    return m_errMessage;\n}\n\nstring_t http_call_response::e_tag() const\n{\n    // return default value because there is no matching method\n    return string_t();\n}\n\nstring_t http_call_response::response_date() const\n{\n    // return default value because there is no matching method\n    return string_t();\n}\n\nstd::chrono::seconds http_call_response::retry_after() const\n{\n    // return default value because there is no matching method\n    return std::chrono::seconds();\n}\n\nhttp_call_response::http_call_response(const http_call_response& other)\n    : m_bodyType(other.m_bodyType),\n    m_responseBodyString(other.m_responseBodyString),\n    m_responseBodyJson(other.m_responseBodyJson),\n    m_responseBodyVector(other.m_responseBodyVector),\n    m_responseHeaders(other.m_responseHeaders),\n    m_httpStatus(other.m_httpStatus),\n    m_errorCode(other.m_errorCode),\n    m_errMessage(other.m_errMessage)\n{\n    XblHttpCallDuplicateHandle(other.m_handle, &m_handle);\n}\n\nhttp_call_response& http_call_response::operator=(http_call_response other)\n{\n    std::swap(m_handle, other.m_handle);\n    m_responseBodyString = other.m_responseBodyString;\n    m_responseBodyJson = other.m_responseBodyJson;\n    m_responseBodyVector = other.m_responseBodyVector;\n    m_httpStatus = other.m_httpStatus;\n    m_responseHeaders = other.m_responseHeaders;\n    m_errorCode = other.m_errorCode;\n    m_errMessage = other.m_errMessage;\n\n    return *this;\n}\n\nhttp_call_response::~http_call_response()\n{\n    XblHttpCallCloseHandle(m_handle);\n}\n\nhttp_call::http_call(\n    _In_ XblHttpCallHandle callHandle,\n    _In_ string_t httpMethod,\n    _In_ string_t serverName,\n    _In_ web::uri pathQueryFragment\n) :\n    m_callHandle(std::move(callHandle)),\n    m_httpMethod(std::move(httpMethod)),\n    m_serverName(std::move(serverName)),\n    m_pathQueryFragment(std::move(pathQueryFragment))\n{\n}\n\n#if !XSAPI_NO_PPL\npplx::task<std::shared_ptr<http_call_response>> http_call::get_response_with_auth(\n    _In_ http_call_response_body_type httpCallResponseBodyType\n)\n{\n    XblHttpCallHandle xblHttpCall = m_callHandle;\n\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<http_call_response>>(\n        [xblHttpCall, httpCallResponseBodyType](\n            _In_ XAsyncBlock* async, \n            _In_ std::shared_ptr<http_call_response>& result)\n    {\n        HRESULT hr = XAsyncGetStatus(async, false);\n        if (SUCCEEDED(hr))\n        {\n            result = std::make_shared<http_call_response>(xblHttpCall, static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType));\n        }\n        return hr;\n    });\n\n    auto hr = XblHttpCallPerformAsync(\n        m_callHandle,\n        static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType),\n        &asyncWrapper->async\n    );\n\n    pplx::task_completion_event<std::shared_ptr<http_call_response>> taskCompletionEvent;\n\n    auto response = asyncWrapper->Task(hr).then([taskCompletionEvent](xbox_live_result<std::shared_ptr<http_call_response>> result) {\n        taskCompletionEvent.set(result.payload());\n    });\n    return pplx::task<std::shared_ptr<http_call_response>>(taskCompletionEvent);\n}\n\npplx::task<std::shared_ptr<http_call_response>> http_call::get_response_with_auth(\n    _In_ XalUserHandle user,\n    _In_ http_call_response_body_type httpCallResponseBodyType,\n    _In_ bool allUsersAuthRequired\n)\n{\n    UNREFERENCED_PARAMETER(user);\n    UNREFERENCED_PARAMETER(allUsersAuthRequired);\n\n    auto xblHttpCall = m_callHandle;\n\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<http_call_response>>(\n        [xblHttpCall, httpCallResponseBodyType](XAsyncBlock* async, std::shared_ptr<http_call_response>& response)\n    {\n        HRESULT hr = XAsyncGetStatus(async, false);\n        if (SUCCEEDED(hr))\n        {\n            response = std::make_shared<http_call_response>(xblHttpCall, static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType));\n        }\n        return hr;\n    });\n\n    auto hr = XblHttpCallPerformAsync(\n        m_callHandle,\n        static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType),\n        &asyncWrapper->async\n    );\n\n    pplx::task_completion_event<std::shared_ptr<http_call_response>> taskCompletionEvent;\n\n    auto response = asyncWrapper->Task(hr).then([taskCompletionEvent](xbox_live_result<std::shared_ptr<http_call_response>> result) {\n        taskCompletionEvent.set(result.payload());\n    });\n    return pplx::task<std::shared_ptr<http_call_response>>(taskCompletionEvent);\n}\n\npplx::task<std::shared_ptr<http_call_response>> http_call::get_response(\n    _In_ http_call_response_body_type httpCallResponseBodyType\n)\n{\n    // no matching function\n    UNREFERENCED_PARAMETER(httpCallResponseBodyType);\n    return pplx::task<std::shared_ptr<http_call_response>>();\n}\n#endif // !XSAPI_NO_PPL\n\nvoid http_call::set_request_body(\n    _In_ const string_t& value\n)\n{\n    auto convertedValue = Utils::StringFromStringT(value);\n    XblHttpCallRequestSetRequestBodyString(m_callHandle, convertedValue.c_str());\n}\n\nvoid http_call::set_request_body( _In_ const web::json::value& value )\n{\n    auto convertedValue = Utils::StringFromStringT(value.serialize());\n    XblHttpCallRequestSetRequestBodyString(m_callHandle, convertedValue.c_str());\n}\n\nvoid http_call::set_request_body(\n    _In_ const std::vector<uint8_t>& value\n)\n{\n    uint8_t* buffer{ nullptr };\n    auto neededSize = value.size();\n    std::copy(value.begin(), value.end(), buffer);\n    XblHttpCallRequestSetRequestBodyBytes(m_callHandle, buffer, static_cast<uint32_t>(neededSize));\n}\n\n\nvoid http_call::set_custom_header(\n    _In_ const string_t& Name,\n    _In_ const string_t& Value\n)\n{\n    const auto headerName = Utils::StringFromStringT(Name);\n    const auto headerValue = Utils::StringFromStringT(Value);\n\n    XblHttpCallRequestSetHeader(\n        m_callHandle, \n        headerName.c_str(),\n        headerValue.c_str(),\n        false\n    );\n}\n\nvoid http_call::set_long_http_call(\n    _In_ bool value\n)\n{\n    XblHttpCallRequestSetLongHttpCall(m_callHandle, value);\n    m_longHttpCall = value;\n}\n\nbool http_call::long_http_call() const\n{\n    return m_longHttpCall;\n}\n\nvoid http_call::set_retry_allowed(\n    _In_ bool value\n)\n{\n    XblHttpCallRequestSetLongHttpCall(m_callHandle, value);\n    m_retryAllowed = value;\n}\n\nbool http_call::retry_allowed() const\n{\n    return m_retryAllowed;\n}\n\nvoid http_call::set_content_type_header_value(\n    _In_ const string_t& value\n)\n{\n    XblHttpCallRequestSetHeader(m_callHandle, \"Content-Type\", Utils::StringFromStringT(value).c_str(), true);\n}\n\nstring_t http_call::content_type_header_value() const\n{\n    //no matching method\n    return string_t();\n}\n\nvoid http_call::set_xbox_contract_version_header_value(\n    _In_ const string_t& value\n)\n{\n    XblHttpCallRequestSetHeader(m_callHandle, \"x-xbl-contract-version\", Utils::StringFromStringT(value).c_str(), true);\n}\n\nstring_t http_call::xbox_contract_version_header_value() const\n{\n    //no matching method\n    return string_t();\n}\n\nstring_t http_call::server_name() const\n{\n    return m_serverName;\n}\n\nconst web::uri& http_call::path_query_fragment() const\n{\n    return m_pathQueryFragment;\n}\n\nstring_t http_call::http_method() const\n{\n    return m_httpMethod;\n}\n\nvoid http_call::set_add_default_headers(\n    _In_ bool value\n)\n{\n    UNREFERENCED_PARAMETER(value);\n    //no matching method\n}\n\nbool http_call::add_default_headers() const\n{\n    //no matching method\n    return false;\n}\n\nhttp_call::~http_call()\n{\n    XblHttpCallCloseHandle(m_callHandle);\n}\n\nstd::shared_ptr<http_call> create_xbox_live_http_call(\n    _In_ const std::shared_ptr<xbox_live_context_settings>& xboxLiveContextSettings,\n    _In_ const string_t& httpMethod,\n    _In_ const string_t& serverName,\n    _In_ const web::uri& pathQueryFragment\n)\n{\n    // access context handle via friend function\n    auto xblContext = xboxLiveContextSettings->m_xblContextHandle;\n\n    auto httpMethod_c = Utils::StringFromStringT(httpMethod);\n\n    auto fullUrl = serverName;\n    if (!pathQueryFragment.is_empty())\n    {\n        fullUrl += pathQueryFragment.to_string();\n    }\n    auto fullUrl_c = Utils::StringFromStringT(fullUrl);\n\n    XblHttpCallHandle callHandle;\n\n    HRESULT hr = XblHttpCallCreate(xblContext, httpMethod_c.c_str(), fullUrl_c.c_str(), &callHandle);\n    if (FAILED(hr))\n    {\n        return nullptr;\n    }\n\n    return std::make_shared<http_call>(callHandle, httpMethod, serverName, pathQueryFragment);\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/http_call_request_message.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nhttp_call_request_message::http_call_request_message()\n    : m_httpRequestMessageType(http_request_message_type::empty_message)\n{\n}\n\nconst string_t& http_call_request_message::request_message_string() const\n{\n    return m_requestMessageString;\n}\n\nconst std::vector<unsigned char>& http_call_request_message::request_message_vector() const\n{\n    return m_requestMessageVector;\n}\n\nhttp_request_message_type http_call_request_message::get_http_request_message_type() const\n{\n    return m_httpRequestMessageType;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/leaderboard.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-cpp/social.h\"\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN\n\nleaderboard_column::leaderboard_column(\n    std::shared_ptr<char> buffer, \n    const XblLeaderboardColumn& leaderboardColumn\n) : \n    m_buffer(buffer),\n    m_leaderboardColumn(leaderboardColumn)\n{ }\n\nstring_t leaderboard_column::stat_name() const\n{\n    return Utils::StringTFromUtf8(m_leaderboardColumn.statName);\n}\n\nleaderboard_stat_type leaderboard_column::stat_type() const\n{\n    return static_cast<leaderboard_stat_type>(m_leaderboardColumn.statType);\n}\n\nleaderboard_row::leaderboard_row(\n    std::shared_ptr<char> buffer,\n    const XblLeaderboardRow& leaderboardRow\n) :\n    m_buffer(buffer),\n    m_leaderboardRow(leaderboardRow)\n{ }\n\nstring_t leaderboard_row::gamertag() const\n{\n    return Utils::StringTFromUtf8(m_leaderboardRow.gamertag);\n}\n\nstring_t leaderboard_row::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_leaderboardRow.xboxUserId);\n}\n\ndouble leaderboard_row::percentile() const\n{\n    return m_leaderboardRow.percentile;\n}\n\nuint32_t leaderboard_row::rank() const\n{\n    return m_leaderboardRow.rank;\n}\n\nstd::vector<string_t> leaderboard_row::column_values() const\n{\n    return Utils::StringTVectorFromCStringArray(m_leaderboardRow.columnValues, m_leaderboardRow.columnValuesCount);\n}\n\nleaderboard_result::leaderboard_result(\n    std::shared_ptr<char> buffer,\n    const XblContextHandle& xblContext\n    ) : \n    m_buffer(buffer),\n    m_leaderboardResult(*reinterpret_cast<XblLeaderboardResult*>(m_buffer.get())),\n    m_xblContext(xblContext)\n{\n    for (uint32_t i = 0; i < m_leaderboardResult.columnsCount; i++)\n    {\n        m_columns.push_back(leaderboard_column(m_buffer, m_leaderboardResult.columns[i]));\n    }\n\n    for (uint32_t i = 0; i < m_leaderboardResult.rowsCount; i++)\n    {\n        m_rows.push_back(leaderboard_row(m_buffer, m_leaderboardResult.rows[i]));\n    }\n}\n\nuint32_t leaderboard_result::total_row_count() const\n{\n    return m_leaderboardResult.totalRowCount;\n}\n\nconst std::vector<leaderboard_column>& leaderboard_result::columns() const\n{\n    return m_columns;\n}\n\nconst std::vector<leaderboard_row>& leaderboard_result::rows() const\n{\n    return m_rows;\n}\n\nbool leaderboard_result::has_next() const\n{\n    return m_leaderboardResult.hasNext;\n}\n\n#if !defined(XBOX_LIVE_CREATORS_SDK)\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_result::get_next(_In_ uint32_t maxItems)\n{\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardResultGetNextResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardResultGetNextResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n    \n    auto hr = XblLeaderboardResultGetNextAsync(\n        m_xblContext,\n        &m_leaderboardResult,\n        maxItems,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nleaderboard_service::leaderboard_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nleaderboard_service::leaderboard_service(const leaderboard_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nleaderboard_service& leaderboard_service::operator=(leaderboard_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nleaderboard_service::~leaderboard_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\nXblSocialGroupType \nleaderboard_service::XblSocialGroupTypeFromString(string_t socialGroup)\n{\n    XblSocialGroupType group = XblSocialGroupType::None;\n    if (Utils::Stricmp(socialGroup, xbox::services::social::social_group_constants::people()) == 0 || \n        Utils::Stricmp(socialGroup, _T(\"all\")) == 0)\n    {\n        group = XblSocialGroupType::People;\n    }\n    else if (Utils::Stricmp(socialGroup, xbox::services::social::social_group_constants::favorite()) == 0)\n    {\n        group = XblSocialGroupType::Favorites;\n    }\n    return group;\n}\n\nXblLeaderboardSortOrder \nleaderboard_service::XblLeaderboardSortOrderFromString(string_t sortOrder)\n{\n    XblLeaderboardSortOrder order = XblLeaderboardSortOrder::Descending;\n    if (Utils::Stricmp(sortOrder, _T(\"ascending\")) == 0)\n    {\n        order = XblLeaderboardSortOrder::Ascending;\n    }\n    return order;\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard(\n    _In_ const string_t& scid,\n    _In_ const string_t& name,\n    _In_ const std::vector<string_t>& additionalColumnNames\n)\n{\n    auto leaderboardName = Utils::StringFromStringT(name);\n    UTF8StringArrayRef additionalColumnleaderboardNames{ additionalColumnNames };\n\n    XblLeaderboardQuery query = {};\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.leaderboardName = leaderboardName.c_str();\n    query.additionalColumnleaderboardNames = additionalColumnleaderboardNames.Data();\n    query.additionalColumnleaderboardNamesCount = additionalColumnleaderboardNames.Size();\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard(\n    _In_ const string_t& scid,\n    _In_ const string_t& name,\n    _In_ const string_t& xuid,\n    _In_ const string_t& socialGroup,\n    _In_ uint32_t maxItems,\n    _In_ const std::vector<string_t>& additionalColumnNames\n)\n{\n    auto leaderboardName = Utils::StringFromStringT(name);\n    UTF8StringArrayRef additionalColumnleaderboardNames{ additionalColumnNames };\n\n    XblLeaderboardQuery query = {};\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.leaderboardName = leaderboardName.c_str();\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.maxItems = maxItems;\n    query.additionalColumnleaderboardNames = additionalColumnleaderboardNames.Data();\n    query.additionalColumnleaderboardNamesCount = (uint32_t)additionalColumnleaderboardNames.Size();\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard(\n    _In_ const string_t& scid,\n    _In_ const string_t& name,\n    _In_ uint32_t skipToRank,\n    _In_ uint32_t maxItems,\n    _In_ const std::vector<string_t>& additionalColumnNames\n)\n{\n    auto leaderboardName = Utils::StringFromStringT(name);\n    UTF8StringArrayRef additionalColumnleaderboardNames{ additionalColumnNames };\n\n    XblLeaderboardQuery query = {};\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.leaderboardName = leaderboardName.c_str();\n    query.skipResultToRank = skipToRank;\n    query.maxItems = maxItems;\n    query.additionalColumnleaderboardNames = additionalColumnleaderboardNames.Data();\n    query.additionalColumnleaderboardNamesCount = additionalColumnleaderboardNames.Size();\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard(\n    _In_ const string_t& scid,\n    _In_ const string_t& name,\n    _In_ uint32_t skipToRank,\n    _In_ const string_t& xuid,\n    _In_ const string_t& socialGroup,\n    _In_ uint32_t maxItems,\n    _In_ const std::vector<string_t>& additionalColumnNames\n)\n{\n    auto leaderboardName = Utils::StringFromStringT(name);\n    UTF8StringArrayRef additionalColumnleaderboardNames{ additionalColumnNames };\n\n    XblLeaderboardQuery query = {};\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.leaderboardName = leaderboardName.c_str();\n    query.skipResultToRank = skipToRank;\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.maxItems = maxItems;\n    query.additionalColumnleaderboardNames = additionalColumnleaderboardNames.Data();\n    query.additionalColumnleaderboardNamesCount = (uint32_t)additionalColumnleaderboardNames.Size();\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard_skip_to_xuid(\n    _In_ const string_t& scid,\n    _In_ const string_t& name,\n    _In_ const string_t& skipToXuid,\n    _In_ uint32_t maxItems,\n    _In_ const std::vector<string_t>& additionalColumnNames\n)\n{\n    auto leaderboardName = Utils::StringFromStringT(name);\n    UTF8StringArrayRef additionalColumnleaderboardNames{ additionalColumnNames };\n\n    XblLeaderboardQuery query = {};\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.leaderboardName = leaderboardName.c_str();\n    query.skipToXboxUserId = Utils::Uint64FromStringT(skipToXuid);\n    query.maxItems = maxItems;\n    query.additionalColumnleaderboardNames = additionalColumnleaderboardNames.Data();\n    query.additionalColumnleaderboardNamesCount = additionalColumnleaderboardNames.Size();\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard_skip_to_xuid(\n    _In_ const string_t& scid,\n    _In_ const string_t& name,\n    _In_ const string_t& xuid,\n    _In_ const string_t& socialGroup,\n    _In_ const string_t& skipToXuid,\n    _In_ uint32_t maxItems,\n    _In_ const std::vector<string_t>& additionalColumnNames\n)\n{\n    auto leaderboardName = Utils::StringFromStringT(name);\n    UTF8StringArrayRef additionalColumnleaderboardNames{ additionalColumnNames };\n\n    XblLeaderboardQuery query = {};\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.leaderboardName = leaderboardName.c_str();\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.skipToXboxUserId = Utils::Uint64FromStringT(skipToXuid);\n    query.maxItems = maxItems;\n    query.additionalColumnleaderboardNames = additionalColumnleaderboardNames.Data();\n    query.additionalColumnleaderboardNamesCount = (uint32_t)additionalColumnleaderboardNames.Size();\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard_for_social_group(\n    _In_ const string_t& xuid,\n    _In_ const string_t& scid,\n    _In_ const string_t& statName,\n    _In_ const string_t& socialGroup,\n    _In_ uint32_t maxItems\n)\n{\n    auto statNameCpp = Utils::StringFromStringT(statName);\n\n    XblLeaderboardQuery query = {};\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.statName = statNameCpp.c_str();\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.maxItems = maxItems;\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard_for_social_group(\n    _In_ const string_t& xuid,\n    _In_ const string_t& scid,\n    _In_ const string_t& statName,\n    _In_ const string_t& socialGroup,\n    _In_ const string_t& sortOrder,\n    _In_ uint32_t maxItems\n)\n{\n    auto statNameCpp = Utils::StringFromStringT(statName);\n\n    XblLeaderboardQuery query = {};\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.statName = statNameCpp.c_str();\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.order = XblLeaderboardSortOrderFromString(sortOrder);\n    query.maxItems = maxItems;\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard_for_social_group_skip_to_rank(\n    _In_ const string_t& xuid,\n    _In_ const string_t& scid,\n    _In_ const string_t& statName,\n    _In_ const string_t& socialGroup,\n    _In_ uint32_t skipToRank,\n    _In_ const string_t& sortOrder,\n    _In_ uint32_t maxItems\n)\n{\n    auto statNameCpp = Utils::StringFromStringT(statName);\n\n    XblLeaderboardQuery query = {};\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.statName = statNameCpp.c_str();\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.skipResultToRank = skipToRank;\n    query.order = XblLeaderboardSortOrderFromString(sortOrder);\n    query.maxItems = maxItems;\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<leaderboard_result>> leaderboard_service::get_leaderboard_for_social_group_skip_to_xuid(\n    _In_ const string_t& xuid,\n    _In_ const string_t& scid,\n    _In_ const string_t& statName,\n    _In_ const string_t& socialGroup,\n    _In_ const string_t& skipToXuid,\n    _In_ const string_t& sortOrder,\n    _In_ uint32_t maxItems\n)\n{\n    auto statNameCpp = Utils::StringFromStringT(statName);\n\n    XblLeaderboardQuery query = {};\n    query.xboxUserId = Utils::Uint64FromStringT(xuid);\n    Utils::Utf8FromCharT(scid.c_str(), query.scid, XBL_SCID_LENGTH);\n    query.statName = statNameCpp.c_str();\n    query.socialGroup = XblSocialGroupTypeFromString(socialGroup);\n    query.skipToXboxUserId = Utils::Uint64FromStringT(skipToXuid);\n    query.order = XblLeaderboardSortOrderFromString(sortOrder);\n    query.maxItems = maxItems;\n\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<leaderboard_result>(\n        [xblContext](XAsyncBlock* async, leaderboard_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblLeaderboardGetLeaderboardResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblLeaderboardResult* resultPtr;\n            hr = XblLeaderboardGetLeaderboardResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = leaderboard_result(buffer, xblContext);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblLeaderboardGetLeaderboardAsync(\n        m_xblContext,\n        query,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n#endif // !defined(XBOX_LIVE_CREATORS_SDK)\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/matchmaking.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN\nmatch_ticket_details_response::match_ticket_details_response() :\n    m_buffer(),\n    m_matchTicketDetailsResponse()\n{\n}\n\nmatch_ticket_details_response::match_ticket_details_response(std::shared_ptr<char> buffer) :\n    m_buffer(buffer),\n    m_matchTicketDetailsResponse(*reinterpret_cast<XblMatchTicketDetailsResponse*>(m_buffer.get()))\n{\n}\n\nticket_status\nmatch_ticket_details_response::match_status() const\n{\n    return static_cast<ticket_status>(m_matchTicketDetailsResponse.matchStatus);\n}\n\nstd::chrono::seconds\nmatch_ticket_details_response::estimated_wait_time() const\n{\n    return std::chrono::seconds(m_matchTicketDetailsResponse.estimatedWaitTime);\n}\n\npreserve_session_mode\nmatch_ticket_details_response::preserve_session() const\n{\n    return static_cast<preserve_session_mode>(m_matchTicketDetailsResponse.preserveSession);\n}\n\nxbox::services::multiplayer::multiplayer_session_reference\nmatch_ticket_details_response::ticket_session() const\n{\n    return xbox::services::multiplayer::multiplayer_session_reference(\n        Utils::StringTFromUtf8(m_matchTicketDetailsResponse.ticketSession.Scid),\n        Utils::StringTFromUtf8(m_matchTicketDetailsResponse.ticketSession.SessionTemplateName),\n        Utils::StringTFromUtf8(m_matchTicketDetailsResponse.ticketSession.SessionName));\n}\n\nxbox::services::multiplayer::multiplayer_session_reference\nmatch_ticket_details_response::target_session() const\n{\n    return xbox::services::multiplayer::multiplayer_session_reference (\n        Utils::StringTFromUtf8(m_matchTicketDetailsResponse.targetSession.Scid),\n        Utils::StringTFromUtf8(m_matchTicketDetailsResponse.targetSession.SessionTemplateName),\n        Utils::StringTFromUtf8(m_matchTicketDetailsResponse.targetSession.SessionName));\n}\n\nweb::json::value\nmatch_ticket_details_response::ticket_attributes() const\n{\n    return web::json::value(Utils::StringTFromUtf8(m_matchTicketDetailsResponse.ticketAttributes));\n}\n\nticket_status match_ticket_details_response::convert_string_to_ticket_status(\n    _In_ const string_t& value\n)\n{\n    ticket_status ticketStatus = ticket_status::unknown;\n    if (!value.empty())\n    {\n        if (Utils::Stricmp(value, _T(\"expired\")) == 0)\n        {\n            ticketStatus = ticket_status::expired;\n        }\n        else if (Utils::Stricmp(value, _T(\"searching\")) == 0)\n        {\n            ticketStatus = ticket_status::searching;\n        }\n        else if (Utils::Stricmp(value, _T(\"found\")) == 0)\n        {\n            ticketStatus = ticket_status::found;\n        }\n        else if (Utils::Stricmp(value, _T(\"canceled\")) == 0)\n        {\n            ticketStatus = ticket_status::canceled;\n        }\n    }\n\n    return ticketStatus;\n}\n\npreserve_session_mode match_ticket_details_response::convert_string_to_preserve_session_mode(\n    _In_ const string_t& value\n)\n{\n    preserve_session_mode preserve_session_mode = preserve_session_mode::unknown;\n    if (!value.empty())\n    {\n        if (Utils::Stricmp(value, _T(\"always\")) == 0)\n        {\n            preserve_session_mode = preserve_session_mode::always;\n        }\n        else if (Utils::Stricmp(value, _T(\"never\")) == 0)\n        {\n            preserve_session_mode = preserve_session_mode::never;\n        }\n    }\n    return preserve_session_mode;\n}\n\n\nhopper_statistics_response::hopper_statistics_response() :\n    m_buffer(),\n    m_hopperStatisticsResponse()\n{\n}\n\nhopper_statistics_response::hopper_statistics_response(std::shared_ptr<char> buffer) :\n    m_buffer(buffer),\n    m_hopperStatisticsResponse(*reinterpret_cast<XblHopperStatisticsResponse*>(m_buffer.get()))\n{\n}\n\n/// <summary>\n/// Name of the hopper in which a match was requested.\n/// </summary>\nstring_t\nhopper_statistics_response::hopper_name() const\n{\n    return Utils::StringTFromUtf8(m_hopperStatisticsResponse.hopperName);\n}\n\n/// <summary>\n/// Estimated wait time for a match request to be matched with other players.\n/// </summary>\nstd::chrono::seconds hopper_statistics_response::estimated_wait_time() const\n{\n    return std::chrono::seconds(m_hopperStatisticsResponse.estimatedWaitTime);\n}\n\n/// <summary>\n/// The number of players in the hopper waiting to be matched.\n/// </summary>\nuint32_t hopper_statistics_response::players_waiting_to_match() const\n{\n    return m_hopperStatisticsResponse.playersWaitingToMatch;\n}\n\ncreate_match_ticket_response::create_match_ticket_response():\n    m_createMatchTicketResponse{  }\n{\n}\n\ncreate_match_ticket_response::create_match_ticket_response(\n    XblCreateMatchTicketResponse response\n) :\n    m_createMatchTicketResponse(response)\n{\n}\n\nstring_t\ncreate_match_ticket_response::match_ticket_id() const\n{\n    return Utils::StringTFromUtf8(m_createMatchTicketResponse.matchTicketId);\n}\n\nstd::chrono::seconds\ncreate_match_ticket_response::estimated_wait_time() const\n{\n    return std::chrono::seconds(m_createMatchTicketResponse.estimatedWaitTime);\n}\n\nmatchmaking_service::matchmaking_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nmatchmaking_service::matchmaking_service(const matchmaking_service& other) \n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nmatchmaking_service& matchmaking_service::operator=(matchmaking_service other) \n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nmatchmaking_service::~matchmaking_service() \n{\n    XblContextCloseHandle(m_xblContext);\n}\n\npplx::task<xbox_live_result<create_match_ticket_response>> matchmaking_service::create_match_ticket(\n    _In_ const xbox::services::multiplayer::multiplayer_session_reference& ticketSessionReference,\n    _In_ const string_t& matchmakingServiceConfigurationId,\n    _In_ const string_t& hopperName,\n    _In_ const std::chrono::seconds& ticketTimeout,\n    _In_ preserve_session_mode preserveSession,\n    _In_ const web::json::value& ticketAttributesJson\n) \n{\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<create_match_ticket_response>(\n        [](XAsyncBlock* async, create_match_ticket_response& result) \n    {\n        XblCreateMatchTicketResponse resultResponse;\n        auto hr = XblMatchmakingCreateMatchTicketResult(async, &resultResponse);\n        if (SUCCEEDED(hr)) \n        {\n            result = create_match_ticket_response(resultResponse);\n        }\n        return hr;\n    });\n\n    XblMultiplayerSessionReference _ticketSessionReference;\n    Utils::Utf8FromCharT(ticketSessionReference.service_configuration_id().data(), _ticketSessionReference.Scid, sizeof(_ticketSessionReference.Scid));\n    Utils::Utf8FromCharT(ticketSessionReference.session_template_name().data(), _ticketSessionReference.SessionTemplateName, sizeof(_ticketSessionReference.SessionTemplateName));\n    Utils::Utf8FromCharT(ticketSessionReference.session_name().data(), _ticketSessionReference.SessionName, sizeof(_ticketSessionReference.SessionName));\n\n    auto hr = XblMatchmakingCreateMatchTicketAsync(\n        xblContext,\n        _ticketSessionReference,\n        Utils::StringFromStringT(matchmakingServiceConfigurationId).c_str(),\n        Utils::StringFromStringT(hopperName).c_str(),\n        ticketTimeout.count(),\n        static_cast<XblPreserveSessionMode>(preserveSession),\n        Utils::StringFromStringT(ticketAttributesJson.serialize()).c_str(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<void>> matchmaking_service::delete_match_ticket(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& hopperName,\n    _In_ const string_t& ticketId\n) \n{\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblMatchmakingDeleteMatchTicketAsync(\n        xblContext,\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(hopperName).c_str(),\n        Utils::StringFromStringT(ticketId).c_str(),\n        &asyncWrapper->async);\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<match_ticket_details_response>> matchmaking_service::get_match_ticket_details(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& hopperName,\n    _In_ const string_t& ticketId\n) \n{\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<match_ticket_details_response>(\n        [](XAsyncBlock* async, match_ticket_details_response& result)\n    {\n        size_t bufferSize;\n        auto hr = XblMatchmakingGetMatchTicketDetailsResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblMatchTicketDetailsResponse* resultPtr;\n            hr = XblMatchmakingGetMatchTicketDetailsResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr)) \n            {\n                result = match_ticket_details_response(buffer);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMatchmakingGetMatchTicketDetailsAsync(\n        xblContext,\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(hopperName).c_str(),\n        Utils::StringFromStringT(ticketId).c_str(),\n        &asyncWrapper->async);\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<hopper_statistics_response>>  matchmaking_service::get_hopper_statistics(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& hopperName\n) \n{\n    auto xblContext = m_xblContext;\n\n    auto asyncWrapper = new AsyncWrapper<hopper_statistics_response>(\n        [](XAsyncBlock* async, hopper_statistics_response& result)\n    {\n        size_t bufferSize;\n        auto hr = XblMatchmakingGetHopperStatisticsResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblHopperStatisticsResponse* resultPtr;\n            hr = XblMatchmakingGetHopperStatisticsResult(async, bufferSize, buffer.get(), &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr)) \n            {\n                result = hopper_statistics_response(buffer);\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMatchmakingGetHopperStatisticsAsync(\n        xblContext,\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(hopperName).c_str(),\n        &asyncWrapper->async);\n\n    return asyncWrapper->Task(hr);\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/mem.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"xsapi-c/xbox_live_global_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\n_Ret_maybenull_ _Post_writable_byte_size_(dwSize)\nvoid* xsapi_memory::mem_alloc(\n    _In_ size_t dwSize\n)\n{\n    XblMemAllocFunction allocHook{ nullptr };\n    XblMemFreeFunction freeHook{ nullptr };\n\n    HRESULT hr = XblMemGetFunctions(&allocHook, &freeHook);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    try\n    {\n        return allocHook(dwSize, 0);\n    }\n    catch (...)\n    {\n        return nullptr;\n    }\n}\n\nvoid xsapi_memory::mem_free(\n    _In_opt_ void* pAddress\n)\n{\n    XblMemAllocFunction allocHook{ nullptr };\n    XblMemFreeFunction freeHook{ nullptr };\n\n    HRESULT hr = XblMemGetFunctions(&allocHook, &freeHook);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    try\n    {\n        freeHook(pAddress, 0);\n    }\n    catch (...)\n    {\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/multiplayer.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n#include \"xsapi-c/multiplayer_manager_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nmultiplayer_peer_to_host_requirements::multiplayer_peer_to_host_requirements(\n    _In_ const XblMultiplayerPeerToHostRequirements& requirements\n) \n    : m_requirements(requirements)\n{\n}\n\nstd::chrono::milliseconds multiplayer_peer_to_host_requirements::latency_maximum() const\n{\n    return std::chrono::milliseconds(m_requirements.LatencyMaximum);\n}\n\nuint64_t multiplayer_peer_to_host_requirements::bandwidth_down_minimum_in_kilobits_per_second() const\n{\n    return m_requirements.BandwidthDownMinimumInKbps;\n}\n\nuint64_t multiplayer_peer_to_host_requirements::bandwidth_up_minimum_in_kilobits_per_second() const\n{\n    return m_requirements.BandwidthUpMinimumInKbps;\n}\n\nmultiplay_metrics multiplayer_peer_to_host_requirements::host_selection_metric() const\n{\n    return static_cast<multiplay_metrics>(m_requirements.HostSelectionMetric);\n}\n\nmultiplayer_peer_to_peer_requirements::multiplayer_peer_to_peer_requirements(\n    _In_ const XblMultiplayerPeerToPeerRequirements& requirements\n) \n    : m_requirements(requirements)\n{\n}\n\nuint64_t multiplayer_peer_to_peer_requirements::bandwidth_minimum_in_kilobits_per_second() const\n{\n    return m_requirements.BandwidthMinimumInKbps;\n}\n\nstd::chrono::milliseconds multiplayer_peer_to_peer_requirements::latency_maximum() const\n{\n    return std::chrono::milliseconds(m_requirements.LatencyMaximum);\n}\n\nmultiplayer_member_initialization::multiplayer_member_initialization(\n    _In_opt_ const XblMultiplayerMemberInitialization* memberInitialization\n)\n    : m_initializationSet(memberInitialization != nullptr)\n{\n    if (m_initializationSet)\n    {\n        m_memberInitialization = *memberInitialization;\n    }\n}\n\nbool multiplayer_member_initialization::member_initialization_set() const\n{\n    return m_initializationSet;\n}\n\nstd::chrono::milliseconds multiplayer_member_initialization::join_timeout() const\n{\n    return std::chrono::milliseconds(m_memberInitialization.JoinTimeout);\n}\n\nstd::chrono::milliseconds multiplayer_member_initialization::measurement_timeout() const\n{\n    return std::chrono::milliseconds(m_memberInitialization.MeasurementTimeout);\n}\n\nstd::chrono::milliseconds multiplayer_member_initialization::evaluation_timeout() const\n{\n    return std::chrono::milliseconds(m_memberInitialization.EvaluationTimeout);\n}\n\nbool multiplayer_member_initialization::external_evaluation() const\n{\n    return m_memberInitialization.ExternalEvaluation;\n}\n\nuint32_t multiplayer_member_initialization::members_need_to_start() const\n{\n    return m_memberInitialization.MembersNeededToStart;\n}\n\nmultiplayer_session_capabilities::multiplayer_session_capabilities()\n{\n    m_capabilities = XblMultiplayerSessionCapabilities{};\n}\n\nbool multiplayer_session_capabilities::connectivity() const\n{\n    return m_capabilities.Connectivity;\n}\n\nvoid multiplayer_session_capabilities::set_connectivity(_In_ bool connectivity)\n{\n    m_capabilities.Connectivity = connectivity;\n}\n\nbool multiplayer_session_capabilities::suppress_presence_activity_check() const\n{\n    return m_capabilities.SuppressPresenceActivityCheck;\n}\n\nvoid multiplayer_session_capabilities::set_suppress_presence_activity_check(_In_ bool suppressPresenceActivityCheck)\n{\n    m_capabilities.SuppressPresenceActivityCheck = suppressPresenceActivityCheck;\n}\n\nbool multiplayer_session_capabilities::gameplay() const\n{\n    return m_capabilities.Gameplay;\n}\n\nvoid multiplayer_session_capabilities::set_gameplay(_In_ bool gameplay)\n{\n    m_capabilities.Gameplay = gameplay;\n}\n\nbool multiplayer_session_capabilities::large() const\n{\n    return m_capabilities.Large;\n}\n\nvoid multiplayer_session_capabilities::set_large(_In_ bool large)\n{\n    m_capabilities.Large = large;\n}\n\nbool multiplayer_session_capabilities::connection_required_for_active_members() const\n{\n    return m_capabilities.ConnectionRequiredForActiveMembers;\n}\n\nvoid multiplayer_session_capabilities::set_connection_required_for_active_members(_In_ bool connectionRequired)\n{\n    m_capabilities.ConnectionRequiredForActiveMembers = connectionRequired;\n}\n\nbool multiplayer_session_capabilities::user_authorization_style() const\n{\n    return m_capabilities.UserAuthorizationStyle;\n}\n\nvoid multiplayer_session_capabilities::set_user_authorization_style(_In_ bool userAuthorizationStyle)\n{\n    m_capabilities.UserAuthorizationStyle = userAuthorizationStyle;\n}\n\nbool multiplayer_session_capabilities::crossplay() const\n{\n    return m_capabilities.Crossplay;\n}\n\nvoid multiplayer_session_capabilities::set_crossplay(_In_ bool crossplay)\n{\n    m_capabilities.Crossplay = crossplay;\n}\n\nbool multiplayer_session_capabilities::searchable() const\n{\n    return m_capabilities.Searchable;\n}\n\nvoid multiplayer_session_capabilities::set_searchable(_In_ bool searchable)\n{\n    m_capabilities.Searchable = searchable;\n}\n\nbool multiplayer_session_capabilities::has_owners() const\n{\n    return m_capabilities.HasOwners;\n}\n\nvoid multiplayer_session_capabilities::set_has_owners(_In_ bool hasOwners)\n{\n    m_capabilities.HasOwners = hasOwners;\n}\n\nmultiplayer_quality_of_service_measurements::multiplayer_quality_of_service_measurements(\n    _In_ const string_t& memberDeviceToken,\n    _In_ std::chrono::milliseconds latency,\n    _In_ uint64_t bandwidthDownInKilobitsPerSecond,\n    _In_ uint64_t bandwidthUpInKilobitsPerSecond,\n    _In_ const string_t& customJson\n)\n    : m_memberDeviceToken(memberDeviceToken),\n    m_latency(latency),\n    m_bandwidthDown(bandwidthDownInKilobitsPerSecond),\n    m_bandwidthUp(bandwidthUpInKilobitsPerSecond)\n{\n    try\n    {\n        m_customJson = web::json::value::parse(customJson);\n        m_measurementsJson[_T(\"latency\")] = static_cast<int64_t>(m_latency.count());\n        m_measurementsJson[_T(\"bandwidthDown\")] = m_bandwidthDown;\n        m_measurementsJson[_T(\"bandwidthUp\")] = m_bandwidthUp;\n        m_measurementsJson[_T(\"custom\")] = m_customJson;\n    }\n    catch (web::json::json_exception) {}\n}\n\nmultiplayer_quality_of_service_measurements::multiplayer_quality_of_service_measurements(\n    _In_ const string_t& memberDeviceToken,\n    _In_ const web::json::value& measurementsJson\n)\n    : m_memberDeviceToken(memberDeviceToken)\n    , m_measurementsJson(measurementsJson)\n\n{\n    m_latency = std::chrono::milliseconds(Utils::ExtractJsonUint64(m_measurementsJson, _T(\"latency\")));\n    m_bandwidthDown = Utils::ExtractJsonUint64(m_measurementsJson, _T(\"bandwidthDown\"));\n    m_bandwidthUp = Utils::ExtractJsonUint64(m_measurementsJson, _T(\"bandwidthUp\"));\n    m_customJson = Utils::ExtractJsonField(m_measurementsJson, _T(\"custom\"), false);\n}\n\nconst string_t& multiplayer_quality_of_service_measurements::member_device_token() const\n{\n    return m_memberDeviceToken;\n}\n\nconst std::chrono::milliseconds& multiplayer_quality_of_service_measurements::latency() const\n{\n    return m_latency;\n}\n\nuint64_t multiplayer_quality_of_service_measurements::bandwidth_down_in_kilobits_per_second() const\n{\n    return m_bandwidthDown;\n}\n\nuint64_t multiplayer_quality_of_service_measurements::bandwidth_up_in_kilobits_per_second() const\n{\n    return m_bandwidthUp;\n}\n\nconst web::json::value& multiplayer_quality_of_service_measurements::custom_json() const\n{\n    return m_customJson;\n}\n\nmultiplayer_session_constants::multiplayer_session_constants(_In_ XblMultiplayerSessionHandle sessionHandle)\n{\n    XblMultiplayerSessionDuplicateHandle(sessionHandle, &m_sessionHandle);\n    m_constants = XblMultiplayerSessionSessionConstants(m_sessionHandle);\n}\n\nmultiplayer_session_constants::multiplayer_session_constants(bool isLobbySession) : m_sessionHandle(nullptr)\n{\n    if (isLobbySession)\n    {\n        m_constants = XblMultiplayerManagerLobbySessionConstants();\n    }\n    else // MPM game session\n    {\n        m_constants = XblMultiplayerManagerGameSessionConstants();\n    }\n}\n\nmultiplayer_session_constants::~multiplayer_session_constants()\n{\n    if (m_sessionHandle != nullptr)\n    {\n        XblMultiplayerSessionCloseHandle(m_sessionHandle);\n    }\n}\n\nuint32_t multiplayer_session_constants::max_members_in_session() const\n{\n    return m_constants->MaxMembersInSession;\n}\n\nvoid multiplayer_session_constants::set_max_members_in_session(_In_ uint32_t maxMembersInSession)\n{\n    if (m_sessionHandle != nullptr)\n    {\n        XblMultiplayerSessionConstantsSetMaxMembersInSession(m_sessionHandle, maxMembersInSession);\n    }\n}\n\nmultiplayer_session_visibility multiplayer_session_constants::visibility() const\n{\n    return static_cast<multiplayer_session_visibility>(m_constants->Visibility);\n}\n\nvoid multiplayer_session_constants::set_visibility(_In_ multiplayer_session_visibility visibility)\n{\n    if (m_sessionHandle != nullptr)\n    {\n        XblMultiplayerSessionConstantsSetVisibility(m_sessionHandle, static_cast<XblMultiplayerSessionVisibility>(visibility));\n    }\n}\n\nstd::vector<string_t> multiplayer_session_constants::initiator_xbox_user_ids() const\n{\n    return Utils::XuidStringVectorFromXuidArray(m_constants->InitiatorXuids, m_constants->InitiatorXuidsCount);\n}\n\nweb::json::value multiplayer_session_constants::session_custom_constants_json() const\n{\n    return Utils::ParseJson(m_constants->CustomJson);\n}\n\nweb::json::value multiplayer_session_constants::session_cloud_compute_package_constants_json() const\n{\n    return Utils::ParseJson(m_constants->SessionCloudComputePackageConstantsJson);\n}\n\nstd::chrono::milliseconds multiplayer_session_constants::member_reserved_time_out() const\n{\n    return std::chrono::milliseconds(m_constants->MemberReservedTimeout);\n}\n\nstd::chrono::milliseconds multiplayer_session_constants::member_inactive_timeout() const\n{\n    return std::chrono::milliseconds(m_constants->MemberInactiveTimeout);\n}\n\nstd::chrono::milliseconds multiplayer_session_constants::member_ready_timeout() const\n{\n    return std::chrono::milliseconds(m_constants->MemberReadyTimeout);\n}\n\nstd::chrono::milliseconds multiplayer_session_constants::session_empty_timeout() const\n{\n    return std::chrono::milliseconds(m_constants->SessionEmptyTimeout);\n}\n\nbool multiplayer_session_constants::enable_metrics_latency() const\n{\n    return m_constants->EnableMetricsLatency;\n}\n\nbool multiplayer_session_constants::enable_metrics_bandwidth_down() const\n{\n    return m_constants->EnableMetricsBandwidthDown;\n}\n\nbool multiplayer_session_constants::enable_metrics_bandwidth_up() const\n{\n    return m_constants->EnableMetricsBandwidthUp;\n}\n\nbool multiplayer_session_constants::enable_metrics_custom() const\n{\n    return m_constants->EnableMetricsCustom;\n}\n\nmultiplayer_member_initialization multiplayer_session_constants::member_initialization() const\n{\n    return multiplayer_member_initialization(m_constants->MemberInitialization);\n}\n\nmultiplayer_peer_to_peer_requirements multiplayer_session_constants::peer_to_peer_requirements() const\n{\n    return multiplayer_peer_to_peer_requirements(m_constants->PeerToPeerRequirements);\n}\n\nmultiplayer_peer_to_host_requirements multiplayer_session_constants::peer_to_host_requirements() const\n{\n    return multiplayer_peer_to_host_requirements(m_constants->PeerToHostRequirements);\n}\n\nweb::json::value multiplayer_session_constants::measurement_server_addresses_json() const\n{\n    return Utils::ParseJson(m_constants->MeasurementServerAddressesJson);\n}\n\nbool multiplayer_session_constants::client_matchmaking_capable() const\n{\n    return m_constants->ClientMatchmakingCapable;\n}\n\nbool multiplayer_session_constants::capabilities_connectivity() const\n{\n    return m_constants->SessionCapabilities.Connectivity;\n}\n\nbool multiplayer_session_constants::capabilities_suppress_presence_activity_check() const\n{\n    return m_constants->SessionCapabilities.SuppressPresenceActivityCheck;\n}\n\nbool multiplayer_session_constants::capabilities_gameplay() const\n{\n    return m_constants->SessionCapabilities.Gameplay;\n}\n\nbool multiplayer_session_constants::capabilities_large() const\n{\n    return m_constants->SessionCapabilities.Large;\n}\n\nbool multiplayer_session_constants::capabilities_connection_required_for_active_member() const\n{\n    return m_constants->SessionCapabilities.ConnectionRequiredForActiveMembers;\n}\n\nbool multiplayer_session_constants::capabilities_crossplay() const\n{\n    return m_constants->SessionCapabilities.Crossplay;\n}\n\nbool multiplayer_session_constants::capabilities_user_authorization_style() const\n{\n    return m_constants->SessionCapabilities.UserAuthorizationStyle;\n}\n\nbool multiplayer_session_constants::capabilities_searchable() const\n{\n    return m_constants->SessionCapabilities.Searchable;\n}\n\nmultiplayer_session_reference::multiplayer_session_reference() : m_reference{} \n{\n}\n\nmultiplayer_session_reference::multiplayer_session_reference(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& sessionTemplateName,\n    _In_ const string_t& sessionName\n)\n{\n    Utils::Utf8FromCharT(serviceConfigurationId.data(), m_reference.Scid, sizeof(m_reference.Scid));\n    Utils::Utf8FromCharT(sessionTemplateName.data(), m_reference.SessionTemplateName, sizeof(m_reference.SessionTemplateName));\n    Utils::Utf8FromCharT(sessionName.data(), m_reference.SessionName, sizeof(m_reference.SessionName));\n}\n\nmultiplayer_session_reference::multiplayer_session_reference(\n    _In_ const XblMultiplayerSessionReference& reference\n)\n    : m_reference(reference)\n{\n}\n\nstring_t multiplayer_session_reference::service_configuration_id() const\n{\n    return Utils::StringTFromUtf8(m_reference.Scid);\n}\n\nstring_t multiplayer_session_reference::session_template_name() const\n{\n    return Utils::StringTFromUtf8(m_reference.SessionTemplateName);\n}\n\nstring_t multiplayer_session_reference::session_name() const\n{\n    return Utils::StringTFromUtf8(m_reference.SessionName);\n}\n\nbool multiplayer_session_reference::is_null() const\n{\n    return m_reference.Scid[0] == 0 ||\n        m_reference.SessionName[0] == 0 ||\n        m_reference.SessionTemplateName[0] == 0;\n}\n\nstring_t multiplayer_session_reference::to_uri_path() const\n{\n    XblMultiplayerSessionReferenceUri uri{};\n    XblMultiplayerSessionReferenceToUriPath(&m_reference, &uri);\n\n    return Utils::StringTFromUtf8(uri.value);\n}\n\nmultiplayer_session_reference multiplayer_session_reference::parse_from_uri_path(_In_ const string_t& path)\n{\n    XblMultiplayerSessionReference reference;\n    XblMultiplayerSessionReferenceParseFromUriPath(Utils::StringFromStringT(path).data(), &reference);\n    return multiplayer_session_reference(reference);\n}\n\nmultiplayer_session_matchmaking_server::multiplayer_session_matchmaking_server(\n    _In_ XblMultiplayerSessionHandle sessionHandle\n)\n{\n    XblMultiplayerSessionDuplicateHandle(sessionHandle, &m_sessionHandle);\n    m_server = XblMultiplayerSessionMatchmakingServer(m_sessionHandle);\n}\n\nmultiplayer_session_matchmaking_server::multiplayer_session_matchmaking_server(\n    const multiplayer_session_matchmaking_server& other\n)\n    : m_server(other.m_server)\n{\n    XblMultiplayerSessionDuplicateHandle(other.m_sessionHandle, &m_sessionHandle);\n    m_server = other.m_server;\n}\n\nmultiplayer_session_matchmaking_server& multiplayer_session_matchmaking_server::operator=(\n    multiplayer_session_matchmaking_server other\n)\n{\n    std::swap(m_sessionHandle, other.m_sessionHandle);\n    m_server = other.m_server;\n    return *this;\n}\n\nmultiplayer_session_matchmaking_server::~multiplayer_session_matchmaking_server()\n{\n    XblMultiplayerSessionCloseHandle(m_sessionHandle);\n}\n\nmatchmaking_status multiplayer_session_matchmaking_server::status() const\n{\n    return m_server != nullptr ? static_cast<matchmaking_status>(m_server->Status) : matchmaking_status::unknown;\n}\n\nstring_t multiplayer_session_matchmaking_server::status_details() const\n{\n    return m_server != nullptr ? Utils::StringTFromUtf8(m_server->StatusDetails) : string_t();\n}\n\nstd::chrono::seconds multiplayer_session_matchmaking_server::typical_wait() const\n{\n    return std::chrono::seconds(m_server != nullptr ? m_server->TypicalWaitInSeconds : 0);\n}\n\nmultiplayer_session_reference multiplayer_session_matchmaking_server::target_session_ref() const\n{\n    return m_server != nullptr ? multiplayer_session_reference(m_server->TargetSessionRef) : multiplayer_session_reference();\n}\n\nbool multiplayer_session_matchmaking_server::is_null() const\n{\n    return m_server == nullptr;\n}\n\nmultiplayer_role_info::multiplayer_role_info()\n{\n}\n\nmultiplayer_role_info::multiplayer_role_info(\n    const XblMultiplayerRole* roleInfo\n)\n    : m_maxMembersCount(roleInfo->MaxMemberCount),\n    m_membersCount(roleInfo->MemberCount),\n    m_targetCount(roleInfo->TargetCount)\n{\n    m_memberXuids = Utils::XuidStringVectorFromXuidArray(roleInfo->MemberXuids, roleInfo->MemberCount);\n}\n\nconst std::vector<string_t>& multiplayer_role_info::member_xbox_user_ids() const\n{\n    return m_memberXuids;\n}\n\nuint32_t multiplayer_role_info::members_count() const\n{\n    return m_membersCount;\n}\n\nuint32_t multiplayer_role_info::target_count() const\n{\n    return m_targetCount;\n}\n\nuint32_t multiplayer_role_info::max_members_count() const\n{\n    return m_maxMembersCount;\n}\n\nvoid multiplayer_role_info::set_max_members_count(_In_ uint32_t maxCount)\n{\n    m_maxMembersCount = maxCount;\n}\n\nvoid multiplayer_role_info::set_target_count(_In_ uint32_t targetCount)\n{\n    m_targetCount = targetCount;\n}\n\nmultiplayer_role_type::multiplayer_role_type()\n{\n}\n\nmultiplayer_role_type::multiplayer_role_type(\n    const XblMultiplayerRoleType* roleType\n)\n    : m_ownerManaged(roleType->OwnerManaged)\n{\n    if ((roleType->MutableRoleSettings & XblMutableRoleSettings::Max) == XblMutableRoleSettings::Max)\n    {\n        m_mutableRoleSettings.push_back(mutable_role_setting::max);\n    }\n    if ((roleType->MutableRoleSettings & XblMutableRoleSettings::Target) == XblMutableRoleSettings::Target)\n    {\n        m_mutableRoleSettings.push_back(mutable_role_setting::target);\n    }\n\n    for (uint32_t i = 0; i < roleType->RoleCount; ++i)\n    {\n        m_roles.insert(std::make_pair(Utils::StringTFromUtf8(roleType->Roles[i].Name), multiplayer_role_info(roleType->Roles + i)));\n    }\n}\n\nbool multiplayer_role_type::owner_managed() const\n{\n    return m_ownerManaged;\n}\n\nconst std::vector<mutable_role_setting>& multiplayer_role_type::mutable_role_settings() const\n{\n    return m_mutableRoleSettings;\n}\n\nconst std::unordered_map<string_t, multiplayer_role_info>& multiplayer_role_type::roles() const\n{\n    return m_roles;\n}\n\nvoid multiplayer_role_type::set_roles(_In_ const std::unordered_map<string_t, multiplayer_role_info>& roles)\n{\n    m_roles = roles;\n}\n\nmultiplayer_session_role_types::multiplayer_session_role_types(\n    const XblMultiplayerRoleType* roleTypes, \n    size_t roleTypesCount\n)\n{\n    for (size_t i = 0; i < roleTypesCount; ++i)\n    {\n        m_roleTypes.insert(std::make_pair(Utils::StringTFromUtf8(roleTypes[i].Name), multiplayer_role_type(roleTypes + i)));\n    }\n}\n\nconst std::unordered_map<string_t, multiplayer_role_type>& multiplayer_session_role_types::role_types() const\n{\n    return m_roleTypes;\n}\n\nmultiplayer_activity_details::multiplayer_activity_details(const XblMultiplayerActivityDetails& activityDetails)\n    : m_activityDetails(activityDetails)\n{\n    if (activityDetails.CustomSessionPropertiesJson != nullptr)\n    {\n        auto len = strlen(activityDetails.CustomSessionPropertiesJson) + 1;\n        auto copy = new char[len]{};\n        Utils::CopyUtf8(copy, len, activityDetails.CustomSessionPropertiesJson);\n        m_activityDetails.CustomSessionPropertiesJson = copy;\n    }\n}\n\nmultiplayer_activity_details::multiplayer_activity_details(const multiplayer_activity_details& other)\n    : multiplayer_activity_details(other.m_activityDetails)\n{\n}\n\nmultiplayer_activity_details& multiplayer_activity_details::operator=(multiplayer_activity_details other)\n{\n    m_activityDetails = other.m_activityDetails;\n    if (m_activityDetails.CustomSessionPropertiesJson != nullptr)\n    {\n        auto len = strlen(m_activityDetails.CustomSessionPropertiesJson) + 1;\n        auto copy = new char[len] {};\n        Utils::CopyUtf8(copy, len, m_activityDetails.CustomSessionPropertiesJson);\n        m_activityDetails.CustomSessionPropertiesJson = copy;\n    }\n    return *this;\n}\n\nmultiplayer_activity_details::~multiplayer_activity_details()\n{\n    if (m_activityDetails.CustomSessionPropertiesJson != nullptr)\n    {\n        delete[] m_activityDetails.CustomSessionPropertiesJson;\n    }\n}\n\nmultiplayer_session_reference multiplayer_activity_details::session_reference() const\n{\n    return multiplayer_session_reference(m_activityDetails.SessionReference);\n}\n\nstring_t multiplayer_activity_details::handle_id() const\n{\n    return Utils::StringTFromUtf8(m_activityDetails.HandleId);\n}\n\nuint32_t multiplayer_activity_details::title_id() const\n{\n    return m_activityDetails.TitleId;\n}\n\nmultiplayer_session_visibility multiplayer_activity_details::visibility() const\n{\n    return static_cast<multiplayer_session_visibility>(m_activityDetails.Visibility);\n}\n\nmultiplayer_session_restriction multiplayer_activity_details::join_restriction() const\n{\n    return static_cast<multiplayer_session_restriction>(m_activityDetails.JoinRestriction);\n}\n\nbool multiplayer_activity_details::closed() const\n{\n    return m_activityDetails.Closed;\n}\n\nstring_t multiplayer_activity_details::owner_xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_activityDetails.OwnerXuid);\n}\n\nuint32_t multiplayer_activity_details::max_members_count() const\n{\n    return m_activityDetails.MaxMembersCount;\n}\n\nuint32_t multiplayer_activity_details::members_count() const\n{\n    return m_activityDetails.MembersCount;\n}\n\nweb::json::value multiplayer_activity_details::custom_session_properties_json() const\n{\n    return Utils::ParseJson(m_activityDetails.CustomSessionPropertiesJson);\n}\n\nmultiplayer_session_reference multiplayer_search_handle_details::session_reference() const\n{\n    XblMultiplayerSessionReference sessionRef{};\n    XblMultiplayerSearchHandleGetSessionReference(m_handle, &sessionRef);\n    return multiplayer_session_reference(sessionRef);\n}\n\nstring_t multiplayer_search_handle_details::handle_id() const\n{\n    const char* id{ nullptr };\n    XblMultiplayerSearchHandleGetId(m_handle, &id);\n    return Utils::StringTFromUtf8(id);\n}\n\nstd::vector<string_t> multiplayer_search_handle_details::session_owner_xbox_user_ids() const\n{\n    const uint64_t* xuids{ nullptr };\n    size_t xuidsCount{ 0 };\n    XblMultiplayerSearchHandleGetSessionOwnerXuids(m_handle, &xuids, &xuidsCount);\n\n    return Utils::XuidStringVectorFromXuidArray(xuids, xuidsCount);\n}\n\nstd::vector<string_t> multiplayer_search_handle_details::tags() const\n{\n    const XblMultiplayerSessionTag* tags{ nullptr };\n    size_t tagsCount{ 0 };\n    XblMultiplayerSearchHandleGetTags(m_handle, &tags, &tagsCount);\n\n    return Utils::Transform<string_t>(tags, tagsCount, [](XblMultiplayerSessionTag tag)\n    {\n        return Utils::StringTFromUtf8(tag.value);\n    });\n}\n\nstd::unordered_map<string_t, double> multiplayer_search_handle_details::numbers_metadata() const\n{\n    const XblMultiplayerSessionNumberAttribute* attributes{ nullptr };\n    size_t attributesCount{ 0 };\n    XblMultiplayerSearchHandleGetNumberAttributes(m_handle, &attributes, &attributesCount);\n\n    std::unordered_map<string_t, double> out;\n    for (auto i = 0u; i < attributesCount; ++i)\n    {\n        out[Utils::StringTFromUtf8(attributes[i].name)] = attributes[i].value;\n    }\n\n    return out;\n}\n\nstd::unordered_map<string_t, string_t> multiplayer_search_handle_details::strings_metadata() const\n{\n    const XblMultiplayerSessionStringAttribute* attributes{ nullptr };\n    size_t attributesCount{ 0 };\n    XblMultiplayerSearchHandleGetStringAttributes(m_handle, &attributes, &attributesCount);\n\n    std::unordered_map<string_t, string_t> out;\n    for (auto i = 0u; i < attributesCount; ++i)\n    {\n        out[Utils::StringTFromUtf8(attributes[i].name)] = Utils::StringTFromUtf8(attributes[i].value);\n    }\n\n    return out;\n}\n\nstd::unordered_map<string_t, multiplayer_role_type> multiplayer_search_handle_details::role_types() const\n{\n    return std::unordered_map<string_t, multiplayer_role_type>();\n}\n\nmultiplayer_session_visibility multiplayer_search_handle_details::visibility() const\n{\n    XblMultiplayerSessionVisibility visibility{ XblMultiplayerSessionVisibility::Unknown };\n    XblMultiplayerSearchHandleGetVisibility(m_handle, &visibility);\n    return static_cast<multiplayer_session_visibility>(visibility);\n}\n\nmultiplayer_session_restriction multiplayer_search_handle_details::join_restriction() const\n{\n    XblMultiplayerSessionRestriction joinRestriction{ XblMultiplayerSessionRestriction::Unknown };\n    XblMultiplayerSearchHandleGetJoinRestriction(m_handle, &joinRestriction);\n    return static_cast<multiplayer_session_restriction>(joinRestriction);\n}\n\nbool multiplayer_search_handle_details::closed() const\n{\n    bool closed{ false };\n    XblMultiplayerSearchHandleGetSessionClosed(m_handle, &closed);\n    return closed;\n}\n\nuint32_t multiplayer_search_handle_details::max_members_count() const\n{\n    size_t maxCount{ 0 };\n    size_t currentCount{ 0 };\n    XblMultiplayerSearchHandleGetMemberCounts(m_handle, &maxCount, &currentCount);\n    return static_cast<uint32_t>(maxCount);\n}\n\nuint32_t multiplayer_search_handle_details::members_count() const\n{\n    size_t maxCount{ 0 };\n    size_t currentCount{ 0 };\n    XblMultiplayerSearchHandleGetMemberCounts(m_handle, &maxCount, &currentCount);\n    return static_cast<uint32_t>(currentCount);\n}\n\nweb::json::value multiplayer_search_handle_details::custom_session_properties_json() const\n{\n    const char* customPropertiesJson{ nullptr };\n    XblMultiplayerSearchHandleGetCustomSessionPropertiesJson(m_handle, &customPropertiesJson);\n    return Utils::ParseJson(customPropertiesJson);\n}\n\nutility::datetime multiplayer_search_handle_details::handle_creation_time() const\n{\n    time_t creationTime{ 0 };\n    XblMultiplayerSearchHandleGetCreationTime(m_handle, &creationTime);\n    return Utils::DatetimeFromTimeT(creationTime);\n}\n\nmultiplayer_search_handle_details::multiplayer_search_handle_details(\n    XblMultiplayerSearchHandle handle\n)\n{\n    XblMultiplayerSearchHandleDuplicateHandle(handle, &m_handle);\n}\n\nmultiplayer_search_handle_details::multiplayer_search_handle_details(\n    const multiplayer_search_handle_details& other\n)\n{\n    XblMultiplayerSearchHandleDuplicateHandle(other.m_handle, &m_handle);\n}\n\nmultiplayer_search_handle_details& multiplayer_search_handle_details::operator=(\n    multiplayer_search_handle_details other\n)\n{\n    std::swap(m_handle, other.m_handle);\n    return *this;\n}\n\nmultiplayer_search_handle_details::~multiplayer_search_handle_details()\n{\n    XblMultiplayerSearchHandleCloseHandle(m_handle);\n}\n\nmultiplayer_session_states::multiplayer_session_states(\n    _In_ const XblMultiplayerSessionQueryResult& state\n) \n    : m_state(state)\n{\n}\n\nutility::datetime multiplayer_session_states::start_time() const\n{\n    return Utils::DatetimeFromTimeT(m_state.StartTime);\n}\n\nmultiplayer_session_reference multiplayer_session_states::session_reference() const\n{\n    return multiplayer_session_reference(m_state.SessionReference);\n}\n\nmultiplayer_session_status multiplayer_session_states::status() const\n{\n    return static_cast<multiplayer_session_status>(m_state.Status);\n}\n\nmultiplayer_session_visibility multiplayer_session_states::visibility() const\n{\n    return static_cast<multiplayer_session_visibility>(m_state.Visibility);\n}\n\nbool multiplayer_session_states::is_my_turn() const\n{\n    return m_state.IsMyTurn;\n}\n\nstring_t multiplayer_session_states::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_state.Xuid);\n}\n\nuint32_t multiplayer_session_states::accepted_member_count() const\n{\n    return m_state.AcceptedMemberCount;\n}\n\nmultiplayer_session_restriction multiplayer_session_states::join_restriction() const\n{\n    return static_cast<multiplayer_session_restriction>(m_state.JoinRestriction);\n}\n\nstd::vector<string_t> multiplayer_session_states::keywords() const\n{\n    return std::vector<string_t>();\n}\n\nmultiplayer_session_member::multiplayer_session_member(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const XblMultiplayerSessionMember* member\n) : m_member(member)\n{\n    XblMultiplayerSessionDuplicateHandle(session, &m_session);\n}\n\nmultiplayer_session_member::~multiplayer_session_member()\n{\n    XblMultiplayerSessionCloseHandle(m_session);\n}\n\nuint32_t multiplayer_session_member::member_id() const\n{\n    return m_member->MemberId;\n}\n\nstring_t multiplayer_session_member::initial_team() const\n{\n    return Utils::StringTFromUtf8(m_member->InitialTeam);\n}\n\nstring_t multiplayer_session_member::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_member->Xuid);\n}\n\nweb::json::value multiplayer_session_member::member_custom_constants_json() const\n{\n    return Utils::ParseJson(m_member->CustomConstantsJson);\n}\n\nstring_t multiplayer_session_member::secure_device_base_address64() const\n{\n    return Utils::StringTFromUtf8(m_member->SecureDeviceBaseAddress64);\n}\n\nstd::unordered_map<string_t, string_t> multiplayer_session_member::roles() const\n{\n    std::unordered_map<string_t, string_t> out;\n    for (uint32_t i = 0; i < m_member->RolesCount; ++i)\n    {\n        out[Utils::StringTFromUtf8(m_member->Roles[i].roleTypeName)] = Utils::StringTFromUtf8(m_member->Roles[i].roleName);\n    }\n    return out;\n}\n\nweb::json::value multiplayer_session_member::member_custom_properties_json() const\n{\n    return Utils::ParseJson(m_member->CustomPropertiesJson);\n}\n\nstring_t multiplayer_session_member::gamertag() const\n{\n    return Utils::StringTFromUtf8(m_member->Gamertag);\n}\n\nmultiplayer_session_member_status multiplayer_session_member::status() const\n{\n    return static_cast<multiplayer_session_member_status>(m_member->Status);\n}\n\nbool multiplayer_session_member::is_turn_available() const\n{\n    return m_member->IsTurnAvailable;\n}\n\nbool multiplayer_session_member::is_current_user() const\n{\n    return m_member->IsCurrentUser;\n}\n\nbool multiplayer_session_member::initialize_requested() const\n{\n    return m_member->InitializeRequested;\n}\n\nweb::json::value multiplayer_session_member::matchmaking_result_server_measurements_json() const\n{\n    return Utils::ParseJson(m_member->MatchmakingResultServerMeasurementsJson);\n}\n\nweb::json::value multiplayer_session_member::member_server_measurements_json() const\n{\n    return Utils::ParseJson(m_member->ServerMeasurementsJson);\n}\n\nstd::vector<std::shared_ptr<multiplayer_session_member>> multiplayer_session_member::members_in_group() const\n{\n    return Utils::Transform<std::shared_ptr<multiplayer_session_member>>(m_member->MembersInGroupIds, m_member->MembersInGroupIds + m_member->MembersInGroupCount,\n        [this](uint32_t id)\n    {\n        auto member = XblMultiplayerSessionGetMember(m_session, id);\n        if (member != nullptr)\n        {\n            return std::make_shared<multiplayer_session_member>(m_session, member);\n        }\n        return std::shared_ptr<multiplayer_session_member>();\n    });\n}\n\nstd::error_code multiplayer_session_member::set_members_list(_In_ const std::vector<std::shared_ptr<multiplayer_session_member>>& members)\n{\n    UNREFERENCED_PARAMETER(members);\n    auto ids = Utils::Transform<uint32_t>(members, [](std::shared_ptr<multiplayer_session_member> member)\n    {\n        return member->member_id();\n    });\n\n    return Utils::ConvertHr(XblMultiplayerSessionCurrentUserSetMembersInGroup(m_session, ids.data(), static_cast<uint32_t>(ids.size())));\n}\n\nstd::shared_ptr<std::vector<multiplayer_quality_of_service_measurements>> multiplayer_session_member::member_measurements() const\n{\n    auto out = std::make_shared<std::vector<multiplayer_quality_of_service_measurements>>();\n    try\n    {\n        if (m_member->QosMeasurementsJson != nullptr)\n        {\n            auto measurementsJson = Utils::ParseJson(m_member->QosMeasurementsJson);\n            for (const auto& pair : measurementsJson.as_object())\n            {\n                out->push_back(multiplayer_quality_of_service_measurements(pair.first, pair.second));\n            }\n        }\n    }\n    catch (web::json::json_exception) {}\n    return out;\n}\n\nstring_t multiplayer_session_member::device_token() const\n{\n    return Utils::StringTFromUtf8(m_member->DeviceToken.Value);\n}\n\nnetwork_address_translation_setting multiplayer_session_member::nat() const\n{\n    return static_cast<network_address_translation_setting>(m_member->Nat);\n}\n\nuint32_t multiplayer_session_member::active_title_id() const\n{\n    return m_member->ActiveTitleId;\n}\n\nuint32_t multiplayer_session_member::initialization_episode() const\n{\n    return m_member->InitializationEpisode;\n}\n\nutility::datetime multiplayer_session_member::join_time() const\n{\n    return Utils::DatetimeFromTimeT(m_member->JoinTime);\n}\n\nmultiplayer_measurement_failure multiplayer_session_member::initialization_failure_cause() const\n{\n    return static_cast<multiplayer_measurement_failure>(m_member->InitializationFailureCause);\n}\n\nstd::vector<string_t> multiplayer_session_member::groups() const\n{\n    return Utils::StringTVectorFromCStringArray(m_member->Groups, m_member->GroupsCount);\n}\n\nvoid multiplayer_session_member::set_groups(_In_ const std::vector<string_t>& groups)\n{\n    UTF8StringArrayRef groupsUtf8{ groups };\n    XblMultiplayerSessionCurrentUserSetGroups(m_session, groupsUtf8.Data(), static_cast<uint32_t>(groupsUtf8.Size()));\n}\n\nstd::vector<string_t> multiplayer_session_member::encounters() const\n{\n    return Utils::StringTVectorFromCStringArray(m_member->Encounters, m_member->EncountersCount);\n}\n\nvoid multiplayer_session_member::set_encounters(_In_ const std::vector<string_t>& encounters)\n{\n    UTF8StringArrayRef encountersUtf8{ encounters };\n    XblMultiplayerSessionCurrentUserSetEncounters(m_session, encountersUtf8.Data(), static_cast<uint32_t>(encountersUtf8.Size()));\n}\n\nmultiplayer_session_properties::multiplayer_session_properties(_In_ XblMultiplayerSessionHandle session)\n{\n    XblMultiplayerSessionDuplicateHandle(session, &m_session);\n    m_properties = XblMultiplayerSessionSessionProperties(m_session);\n}\n\nmultiplayer_session_properties::~multiplayer_session_properties()\n{\n    XblMultiplayerSessionCloseHandle(m_session);\n}\n\nstd::vector<string_t> multiplayer_session_properties::keywords() const\n{\n    return Utils::StringTVectorFromCStringArray(m_properties->Keywords, m_properties->KeywordCount);\n}\n\nvoid multiplayer_session_properties::set_keywords(_In_ const std::vector<string_t>& keywords)\n{\n    UTF8StringArrayRef utf8Keywords{ keywords };\n    XblMultiplayerSessionPropertiesSetKeywords(m_session, utf8Keywords.Data(), utf8Keywords.Size());\n}\n\nmultiplayer_session_restriction multiplayer_session_properties::join_restriction() const\n{\n    return static_cast<multiplayer_session_restriction>(m_properties->JoinRestriction);\n}\n\nstd::error_code multiplayer_session_properties::set_join_restriction(_In_ multiplayer_session_restriction joinRestriction)\n{\n    XblMultiplayerSessionPropertiesSetJoinRestriction(m_session, static_cast<XblMultiplayerSessionRestriction>(joinRestriction));\n    return std::error_code();\n}\n\nmultiplayer_session_restriction multiplayer_session_properties::read_restriction() const\n{\n    return static_cast<multiplayer_session_restriction>(m_properties->ReadRestriction);\n}\n\nstd::error_code multiplayer_session_properties::set_read_restriction(_In_ multiplayer_session_restriction readRestriction)\n{\n    XblMultiplayerSessionPropertiesSetReadRestriction(m_session, static_cast<XblMultiplayerSessionRestriction>(readRestriction));\n    return std::error_code();\n}\n\nstd::vector<std::shared_ptr<multiplayer_session_member>> multiplayer_session_properties::turn_collection() const\n{\n    std::vector<std::shared_ptr<multiplayer_session_member>> out;\n    for (size_t i = 0; i < m_properties->TurnCollectionCount; ++i)\n    {\n        out.push_back(std::make_shared<multiplayer_session_member>(\n            m_session,\n            XblMultiplayerSessionGetMember(m_session, m_properties->TurnCollection[i])\n            ));\n    }\n    return out;\n}\n\nstd::error_code multiplayer_session_properties::set_turn_collection(\n    _In_ const std::vector<std::shared_ptr<multiplayer_session_member>>& turnCollection\n)\n{\n    std::vector<uint32_t> memberIds;\n    for (auto& member : turnCollection)\n    {\n        memberIds.push_back(member->member_id());\n    }\n    auto hr = XblMultiplayerSessionPropertiesSetTurnCollection(m_session, memberIds.data(), static_cast<uint32_t>(memberIds.size()));\n\n    return std::make_error_code(xbox::services::xbox_live_error_code(hr));\n}\n\nweb::json::value multiplayer_session_properties::matchmaking_target_session_constants_json() const\n{\n    return Utils::ParseJson(m_properties->MatchmakingTargetSessionConstantsJson);\n}\n\nweb::json::value multiplayer_session_properties::session_custom_properties_json() const\n{\n    return Utils::ParseJson(m_properties->SessionCustomPropertiesJson);\n}\n\nstring_t multiplayer_session_properties::matchmaking_server_connection_string() const\n{\n    return Utils::StringTFromUtf8(m_properties->MatchmakingServerConnectionString);\n}\n\nstd::vector<string_t> multiplayer_session_properties::server_connection_string_candidates() const\n{\n    return Utils::StringTVectorFromCStringArray(m_properties->ServerConnectionStringCandidates, m_properties->ServerConnectionStringCandidatesCount);\n}\n\nstd::vector<uint32_t> multiplayer_session_properties::session_owner_indices() const\n{\n    return std::vector<uint32_t>(m_properties->SessionOwnerMemberIds, m_properties->SessionOwnerMemberIds + m_properties->SessionOwnerMemberIdsCount);\n}\n\nstring_t multiplayer_session_properties::host_device_token() const\n{\n    return Utils::StringTFromUtf8(m_properties->HostDeviceToken.Value);\n}\n\nbool multiplayer_session_properties::closed() const\n{\n    return m_properties->Closed;\n}\n\nbool multiplayer_session_properties::locked() const\n{\n    return m_properties->Locked;\n}\n\nbool multiplayer_session_properties::allocate_cloud_compute() const\n{\n    return m_properties->AllocateCloudCompute;\n}\n\nmultiplayer_session::multiplayer_session(\n    _In_ const string_t& xboxUserId\n)\n{\n    m_handle = XblMultiplayerSessionCreateHandle(Utils::Uint64FromStringT(xboxUserId), nullptr, nullptr);\n    m_sessionInfo = XblMultiplayerSessionGetInfo(m_handle);\n}\n\nmultiplayer_session::multiplayer_session(\n    _In_ const string_t& xboxUserId,\n    _In_ multiplayer_session_reference sessionReference\n)\n{\n    m_handle = XblMultiplayerSessionCreateHandle(\n        Utils::Uint64FromStringT(xboxUserId),\n        &sessionReference.m_reference,\n        nullptr\n    );\n    m_sessionInfo = XblMultiplayerSessionGetInfo(m_handle);\n}\n\nmultiplayer_session::multiplayer_session(\n    _In_ const string_t& xboxUserId,\n    _In_ multiplayer_session_reference multiplayerSessionReference,\n    _In_ uint32_t maxMembersInSession,\n    _In_ multiplayer_session_visibility multiplayerSessionVisibility,\n    _In_ std::vector<string_t> initiatorXboxUserIds,\n    _In_ const web::json::value& sessionCustomConstantsJson\n)\n{\n    auto initiatorXuids = Utils::Transform<uint64_t>(initiatorXboxUserIds.begin(), initiatorXboxUserIds.end(), Utils::Uint64FromStringT);\n    std::string sessionCustomConstantsString = Utils::StringFromStringT(sessionCustomConstantsJson.serialize());\n\n    XblMultiplayerSessionInitArgs args{};\n    args.MaxMembersInSession = maxMembersInSession;\n    args.Visibility = static_cast<XblMultiplayerSessionVisibility>(multiplayerSessionVisibility);\n    if (!initiatorXuids.empty())\n    {\n        args.InitiatorXuidsCount = static_cast<uint32_t>(initiatorXuids.size());\n        args.InitiatorXuids = initiatorXuids.data();\n    }\n    if (!sessionCustomConstantsJson.is_null())\n    {\n        args.CustomJson = sessionCustomConstantsString.data();\n    }\n\n    m_handle = XblMultiplayerSessionCreateHandle(\n        Utils::Uint64FromStringT(xboxUserId),\n        &multiplayerSessionReference.m_reference,\n        &args\n    );\n    m_sessionInfo = XblMultiplayerSessionGetInfo(m_handle);\n}\n\nmultiplayer_session::multiplayer_session(XblMultiplayerSessionHandle handle)\n{\n    XblMultiplayerSessionDuplicateHandle(handle, &m_handle);\n    m_sessionInfo = XblMultiplayerSessionGetInfo(m_handle);\n}\n\nmultiplayer_session::~multiplayer_session()\n{\n    XblMultiplayerSessionCloseHandle(m_handle);\n}\n\nstring_t multiplayer_session::multiplayer_correlation_id() const\n{\n    return Utils::StringTFromUtf8(m_sessionInfo->CorrelationId);\n}\n\nstring_t multiplayer_session::search_handle_id() const\n{\n    return Utils::StringTFromUtf8(m_sessionInfo->SearchHandleId);\n}\n\nutility::datetime multiplayer_session::start_time() const\n{\n    return Utils::DatetimeFromTimeT(m_sessionInfo->StartTime);\n}\n\nutility::datetime multiplayer_session::date_of_next_timer() const\n{\n    return Utils::DatetimeFromTimeT(m_sessionInfo->NextTimer);\n}\n\nutility::datetime multiplayer_session::date_of_session() const\n{\n    return Utils::DatetimeFromTimeT(XblMultiplayerSessionTimeOfSession(m_handle));\n}\n\nmultiplayer_initialization_stage multiplayer_session::initialization_stage() const\n{\n    auto initInfo = XblMultiplayerSessionGetInitializationInfo(m_handle);\n    if (initInfo != nullptr)\n    {\n        return static_cast<multiplayer_initialization_stage>(initInfo->Stage);\n    }\n    return multiplayer_initialization_stage::none;\n}\n\nutility::datetime multiplayer_session::initializing_stage_start_time() const\n{\n    auto initInfo = XblMultiplayerSessionGetInitializationInfo(m_handle);\n    if (initInfo != nullptr)\n    {\n        return Utils::DatetimeFromTimeT(initInfo->StageStartTime);\n    }\n    return utility::datetime();\n}\n\nuint32_t multiplayer_session::intializing_episode() const\n{\n    auto initInfo = XblMultiplayerSessionGetInitializationInfo(m_handle);\n    if (initInfo != nullptr)\n    {\n        return initInfo->Episode;\n    }\n    return 0;\n}\n\nmultiplayer_session_change_types multiplayer_session::subscribed_change_types() const\n{\n    return static_cast<multiplayer_session_change_types>(XblMultiplayerSessionSubscribedChangeTypes(m_handle));\n}\n\nstd::vector<string_t> multiplayer_session::host_candidates() const\n{\n    const XblDeviceToken* tokens{ nullptr };\n    size_t tokensCount;\n    XblMultiplayerSessionHostCandidates(m_handle, &tokens, &tokensCount);\n    return Utils::Transform<string_t>(tokens, tokens + tokensCount, [](const XblDeviceToken& token) \n    {\n        return Utils::StringTFromUtf8(token.Value);\n    });\n}\n\nmultiplayer_session_reference multiplayer_session::session_reference() const\n{\n    return multiplayer_session_reference(*XblMultiplayerSessionSessionReference(m_handle));\n}\n\nstd::shared_ptr<multiplayer_session_constants> multiplayer_session::session_constants() const\n{\n    if (m_sessionConstants == nullptr)\n    {\n        m_sessionConstants = std::make_shared<multiplayer_session_constants>(m_handle);\n    }\n    return m_sessionConstants;\n}\n\nstd::shared_ptr<multiplayer_session_properties> multiplayer_session::session_properties() const\n{\n    if (m_sessionProperties == nullptr)\n    {\n        m_sessionProperties = std::make_shared<multiplayer_session_properties>(m_handle);\n    }\n    return m_sessionProperties;\n}\n\nstd::shared_ptr<multiplayer_session_role_types> multiplayer_session::session_role_types() const\n{\n    const XblMultiplayerRoleType* roleTypes{ nullptr };\n    size_t roleTypesCount;\n    XblMultiplayerSessionRoleTypes(m_handle, &roleTypes, &roleTypesCount);\n    return std::shared_ptr<multiplayer_session_role_types>(new multiplayer_session_role_types(roleTypes, roleTypesCount));\n}\n\nstd::vector<std::shared_ptr<multiplayer_session_member>> multiplayer_session::members() const\n{\n    const XblMultiplayerSessionMember* members{ nullptr };\n    size_t membersCount;\n    XblMultiplayerSessionMembers(m_handle, &members, &membersCount);\n\n    return Utils::Transform<std::shared_ptr<multiplayer_session_member>>(members, members + membersCount,\n        [this](const XblMultiplayerSessionMember& member)\n    {\n        return std::make_shared<multiplayer_session_member>(m_handle, &member);\n    });\n}\n\nmultiplayer_session_matchmaking_server multiplayer_session::matchmaking_server() const\n{\n    return multiplayer_session_matchmaking_server(m_handle);\n}\n\nuint32_t multiplayer_session::members_accepted() const\n{\n    return XblMultiplayerSessionMembersAccepted(m_handle);\n}\n\nweb::json::value multiplayer_session::servers_json() const\n{\n    return Utils::ParseJson(XblMultiplayerSessionRawServersJson(m_handle));\n}\n\nvoid multiplayer_session::set_servers_json(_In_ const web::json::value& serversJson)\n{\n    std::string serversJsonString = Utils::StringFromStringT(serversJson.serialize());\n    XblMultiplayerSessionSetRawServersJson(m_handle, serversJsonString.data());\n}\n\nstring_t multiplayer_session::e_tag() const\n{\n    return Utils::StringTFromUtf8(XblMultiplayerSessionEtag(m_handle));\n}\n\nstd::shared_ptr<multiplayer_session_member> multiplayer_session::current_user() const\n{\n    auto currentUser = XblMultiplayerSessionCurrentUser(m_handle);\n    if (currentUser != nullptr)\n    {\n        return std::make_shared<multiplayer_session_member>(m_handle, currentUser);\n    }\n    return nullptr;\n}\n\nstring_t multiplayer_session::branch() const\n{\n    return Utils::StringTFromUtf8(m_sessionInfo->Branch);\n}\n\nuint64_t multiplayer_session::change_number() const\n{\n    return m_sessionInfo->ChangeNumber;\n}\n\nwrite_session_status multiplayer_session::write_status() const\n{\n    return static_cast<write_session_status>(XblMultiplayerSessionWriteStatus(m_handle));\n}\n\nstd::error_code multiplayer_session::add_member_reservation(\n    _In_ const string_t& xboxUserId,\n    _In_ const web::json::value& memberCustomConstantsJson\n)\n{\n    return add_member_reservation(xboxUserId, memberCustomConstantsJson, false);\n}\n\nstd::error_code multiplayer_session::add_member_reservation(\n    _In_ const string_t& xboxUserId,\n    _In_ const web::json::value& memberCustomConstantsJson,\n    _In_ bool initializeRequested\n)\n{\n    std::string jsonString = Utils::StringFromStringT(memberCustomConstantsJson.serialize());\n\n    auto hr = XblMultiplayerSessionAddMemberReservation(\n        m_handle,\n        Utils::Uint64FromStringT(xboxUserId),\n        memberCustomConstantsJson.is_null() ? nullptr : jsonString.data(),\n        initializeRequested\n    );\n\n    return std::make_error_code(xbox::services::xbox_live_error_code(hr));\n}\n\nxbox_live_result<std::shared_ptr<multiplayer_session_member>> multiplayer_session::join(\n    _In_ const web::json::value& memberCustomConstantsJson,\n    _In_ bool initializeRequested,\n    _In_ bool joinWithActiveStatus,\n    _In_ bool addInitializePropertyToRequest\n)\n{\n    UNREFERENCED_PARAMETER(addInitializePropertyToRequest);\n    std::string jsonString = Utils::StringFromStringT(memberCustomConstantsJson.serialize());\n\n    auto hr = XblMultiplayerSessionJoin(\n        m_handle,\n        memberCustomConstantsJson.is_null() ? nullptr : jsonString.data(),\n        initializeRequested,\n        joinWithActiveStatus\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        auto currentUser = std::make_shared<multiplayer_session_member>(m_handle, XblMultiplayerSessionCurrentUser(m_handle));\n        return xbox_live_result<std::shared_ptr<multiplayer_session_member>>(currentUser);\n    }\n    return xbox_live_result<std::shared_ptr<multiplayer_session_member>>(\n        std::make_error_code(xbox::services::xbox_live_error_code(hr))\n        );\n}\n\nvoid multiplayer_session::set_visibility(_In_ multiplayer_session_visibility visibility)\n{\n    XblMultiplayerSessionConstantsSetVisibility(m_handle, static_cast<XblMultiplayerSessionVisibility>(visibility));\n}\n\nvoid multiplayer_session::set_max_members_in_session(_In_ uint32_t maxMembersInSession)\n{\n    XblMultiplayerSessionConstantsSetMaxMembersInSession(m_handle, maxMembersInSession);\n}\n\nstd::error_code multiplayer_session::set_mutable_role_settings(\n    _In_ const std::unordered_map<string_t, multiplayer_role_type>& roleTypes\n)\n{\n    HRESULT finalHr = S_OK;\n    for (const auto& roleType : roleTypes)\n    {\n        for (const auto& role : roleType.second.roles())\n        {\n            auto max = role.second.max_members_count();\n            auto target = role.second.target_count();\n            auto hr = XblMultiplayerSessionSetMutableRoleSettings(\n                m_handle,\n                Utils::StringFromStringT(roleType.first).data(),\n                Utils::StringFromStringT(role.first).data(),\n                &max,\n                &target\n            );\n            if (FAILED(hr))\n            {\n                finalHr = hr;\n            }\n        }\n    }\n    return Utils::ConvertHr(finalHr);\n}\n\nstd::error_code multiplayer_session::set_timeouts(\n    _In_ std::chrono::milliseconds memberReservedTimeout,\n    _In_ std::chrono::milliseconds memberInactiveTimeout,\n    _In_ std::chrono::milliseconds memberReadyTimeout,\n    _In_ std::chrono::milliseconds sessionEmptyTimeout\n)\n{\n    auto hr = XblMultiplayerSessionConstantsSetTimeouts(\n        m_handle,\n        memberReservedTimeout.count(),\n        memberInactiveTimeout.count(),\n        memberReadyTimeout.count(),\n        sessionEmptyTimeout.count()\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_quality_of_service_connectivity_metrics(\n    _In_ bool enableLatencyMetric,\n    _In_ bool enableBandwidthDownMetric,\n    _In_ bool enableBandwidthUpMetric,\n    _In_ bool enableCustomMetric\n)\n{\n    auto hr = XblMultiplayerSessionConstantsSetQosConnectivityMetrics(\n        m_handle,\n        enableLatencyMetric,\n        enableBandwidthDownMetric,\n        enableBandwidthUpMetric,\n        enableCustomMetric\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_member_initialization(\n    _In_ std::chrono::milliseconds joinTimeout,\n    _In_ std::chrono::milliseconds measurementTimeout,\n    _In_ std::chrono::milliseconds evaluationTimeout,\n    _In_ bool externalEvaluation,\n    _In_ uint32_t membersNeededToStart\n)\n{\n    auto hr = XblMultiplayerSessionConstantsSetMemberInitialization(\n        m_handle,\n        XblMultiplayerMemberInitialization\n        {\n            static_cast<uint64_t>(joinTimeout.count()),\n            static_cast<uint64_t>(measurementTimeout.count()),\n            static_cast<uint64_t>(evaluationTimeout.count()),\n            externalEvaluation,\n            membersNeededToStart\n        }\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_peer_to_peer_requirements(\n    _In_ std::chrono::milliseconds latencyMaximum,\n    _In_ uint32_t bandwidthMinimumInKilobitsPerSecond\n)\n{\n    auto hr = XblMultiplayerSessionConstantsSetPeerToPeerRequirements(\n        m_handle,\n        XblMultiplayerPeerToPeerRequirements\n        {\n            static_cast<uint64_t>(latencyMaximum.count()),\n            bandwidthMinimumInKilobitsPerSecond\n        }\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_peer_to_host_requirements(\n    _In_ std::chrono::milliseconds latencyMaximum,\n    _In_ uint32_t bandwidthDownMinimumInKilobitsPerSecond,\n    _In_ uint32_t bandwidthUpMinimumInKilobitsPerSecond,\n    _In_ multiplay_metrics hostSelectionMetric\n)\n{\n    auto hr = XblMultiplayerSessionConstantsSetPeerToHostRequirements(\n        m_handle,\n        XblMultiplayerPeerToHostRequirements\n        {\n            static_cast<uint64_t>(latencyMaximum.count()),\n            bandwidthDownMinimumInKilobitsPerSecond,\n            bandwidthUpMinimumInKilobitsPerSecond,\n            static_cast<XblMultiplayerMetrics>(hostSelectionMetric)\n        }\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_session_capabilities(\n    _In_ const multiplayer_session_capabilities& capabilities\n)\n{\n    auto hr = XblMultiplayerSessionConstantsSetCapabilities(m_handle, capabilities.m_capabilities);\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_cloud_compute_package_json(\n    _In_ const web::json::value& sessionCloudComputePackageConstantsJson\n)\n{\n    std::string jsonString = Utils::StringFromStringT(sessionCloudComputePackageConstantsJson.serialize());\n\n    auto hr = XblMultiplayerSessionConstantsSetCloudComputePackageJson(m_handle, jsonString.data());\n    return Utils::ConvertHr(hr);\n}\n\nvoid multiplayer_session::set_initialization_status(\n    _In_ bool initializationSucceeded\n)\n{\n    XblMultiplayerSessionSetInitializationSucceeded(m_handle, initializationSucceeded);\n}\n\nvoid multiplayer_session::set_host_device_token(\n    _In_ const string_t& hostDeviceToken\n)\n{\n    XblDeviceToken token;\n    Utils::Utf8FromCharT(hostDeviceToken.data(), token.Value, sizeof(token.Value));\n    XblMultiplayerSessionSetHostDeviceToken(m_handle, token);\n}\n\nvoid multiplayer_session::set_matchmaking_server_connection_path(\n    _In_ const string_t& serverConnectionPath\n)\n{\n    XblMultiplayerSessionSetMatchmakingServerConnectionPath(\n        m_handle,\n        Utils::StringFromStringT(serverConnectionPath).data()\n    );\n}\n\nvoid multiplayer_session::set_closed(\n    _In_ bool closed\n)\n{\n    XblMultiplayerSessionSetClosed(m_handle, closed);\n}\n\nvoid multiplayer_session::set_locked(\n    _In_ bool locked\n)\n{\n    XblMultiplayerSessionSetLocked(m_handle, locked);\n}\n\nvoid multiplayer_session::set_allocate_cloud_compute(\n    _In_ bool allocateCloudCompute\n)\n{\n    XblMultiplayerSessionSetAllocateCloudCompute(m_handle, allocateCloudCompute);\n}\n\nvoid multiplayer_session::set_matchmaking_resubmit(\n    _In_ bool matchResubmit\n)\n{\n    XblMultiplayerSessionSetMatchmakingResubmit(m_handle, matchResubmit);\n}\n\nvoid multiplayer_session::set_server_connection_string_candidates(\n    _In_ const std::vector<string_t>& serverConnectionStringCandidates\n)\n{\n    UTF8StringArrayRef candidates{ serverConnectionStringCandidates };\n    XblMultiplayerSessionSetServerConnectionStringCandidates(m_handle, candidates.Data(), static_cast<uint32_t>(candidates.Size()));\n}\n\nstd::error_code multiplayer_session::set_session_change_subscription(\n    _In_ multiplayer_session_change_types changeTypes\n)\n{\n    return Utils::ConvertHr(XblMultiplayerSessionSetSessionChangeSubscription(m_handle, static_cast<XblMultiplayerSessionChangeTypes>(changeTypes)));\n}\n\nstd::error_code multiplayer_session::leave()\n{\n    return Utils::ConvertHr(XblMultiplayerSessionLeave(m_handle));\n}\n\nstd::error_code multiplayer_session::set_current_user_status(\n    _In_ multiplayer_session_member_status status\n)\n{\n    return Utils::ConvertHr(XblMultiplayerSessionCurrentUserSetStatus(m_handle, static_cast<XblMultiplayerSessionMemberStatus>(status)));\n}\n\nstd::error_code multiplayer_session::set_current_user_secure_device_address_base64(\n    _In_ const string_t& value\n)\n{\n    auto hr = XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64(m_handle, Utils::StringFromStringT(value).data());\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_current_user_role_info(\n    _In_ const std::unordered_map<string_t, string_t>& roles\n)\n{\n    auto rolesVector = Utils::Transform<XblMultiplayerSessionMemberRole>(roles.begin(), roles.end(), [](const std::pair<string_t, string_t>& in)\n    {\n        int cchRoleType = Utils::Utf8FromCharT(in.first.data(), nullptr, 0);\n        auto roleTypeName = new char[cchRoleType];\n        Utils::Utf8FromCharT(in.first.data(), roleTypeName, cchRoleType);\n\n        int cchRole = Utils::Utf8FromCharT(in.second.data(), nullptr, 0);\n        auto roleName = new char[cchRole];\n        Utils::Utf8FromCharT(in.second.data(), roleName, cchRole);\n\n        return XblMultiplayerSessionMemberRole{ roleTypeName, roleName };\n    });\n    auto hr = XblMultiplayerSessionCurrentUserSetRoles(m_handle, rolesVector.data(), static_cast<uint32_t>(rolesVector.size()));\n\n    for (auto& role : rolesVector)\n    {\n        delete[] role.roleTypeName;\n        delete[] role.roleName;\n    }\n\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_current_user_members_in_group(\n    _In_ const std::vector<std::shared_ptr<multiplayer_session_member>>& membersInGroup\n)\n{\n    auto memberIds = Utils::Transform<uint32_t>(membersInGroup.begin(), membersInGroup.end(),\n        [](std::shared_ptr<multiplayer_session_member> in)\n    {\n        return in->member_id();\n    });\n    auto hr = XblMultiplayerSessionCurrentUserSetMembersInGroup(m_handle, memberIds.data(), static_cast<uint32_t>(memberIds.size()));\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_current_user_quality_of_service_measurements(\n    _In_ std::shared_ptr<std::vector<multiplayer_quality_of_service_measurements>> measurements\n)\n{\n    web::json::value json;\n    for (const auto& measurement : *measurements)\n    {\n        json[measurement.m_memberDeviceToken] = measurement.m_measurementsJson;\n    }\n    auto hr = XblMultiplayerSessionCurrentUserSetQosMeasurements(m_handle, Utils::StringFromStringT(json.serialize()).data());\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_current_user_quality_of_service_measurements_json(\n    _In_ const web::json::value& serverMeasurementsJson\n)\n{\n    std::string jsonString = Utils::StringFromStringT(serverMeasurementsJson.serialize());\n\n    auto hr = XblMultiplayerSessionCurrentUserSetServerQosMeasurements(m_handle, jsonString.data());\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_current_user_member_custom_property_json(\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson\n)\n{\n    auto hr = XblMultiplayerSessionCurrentUserSetCustomPropertyJson(\n        m_handle,\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data()\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::delete_current_user_member_custom_property_json(\n    _In_ const string_t& name\n)\n{\n    auto hr = XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(\n        m_handle,\n        Utils::StringFromStringT(name).data()\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_matchmaking_target_session_constants_json(\n    _In_ const web::json::value& matchmakingTargetSessionConstantsJson\n)\n{\n    auto hr = XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson(\n        m_handle,\n        Utils::StringFromStringT(matchmakingTargetSessionConstantsJson.serialize()).data()\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::set_session_custom_property_json(\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson\n)\n{\n    auto hr = XblMultiplayerSessionSetCustomPropertyJson(\n        m_handle,\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data()\n    );\n    return Utils::ConvertHr(hr);\n}\n\nstd::error_code multiplayer_session::delete_session_custom_property_json(\n    _In_ const string_t& name\n)\n{\n    auto hr = XblMultiplayerSessionDeleteCustomPropertyJson(\n        m_handle,\n        Utils::StringFromStringT(name).data()\n    );\n    return Utils::ConvertHr(hr);\n}\n\nxbox_live_result<multiplayer_session_change_types> multiplayer_session::compare_multiplayer_sessions(\n    _In_ std::shared_ptr<multiplayer_session> currentSession,\n    _In_ std::shared_ptr<multiplayer_session> oldSession\n)\n{\n    if (currentSession == nullptr || oldSession == nullptr)\n    {\n        return xbox_live_result<multiplayer_session_change_types>(std::make_error_code(xbox_live_error_code::invalid_argument), \"Cannot compare a null session\");\n    }\n    auto changes = XblMultiplayerSessionCompare(currentSession->m_handle, oldSession->m_handle);\n    return xbox_live_result<multiplayer_session_change_types>(static_cast<multiplayer_session_change_types>(changes));\n}\n\nwrite_session_status multiplayer_session::convert_http_status_to_write_session_status(\n    _In_ int32_t httpStatusCode\n)\n{\n    switch (httpStatusCode)\n    {\n    case 200: return write_session_status::updated;\n    case 201: return write_session_status::created;\n    case 204: return write_session_status::session_deleted;\n    case 401: return write_session_status::access_denied;\n    case 404: return write_session_status::handle_not_found;\n    case 409: return write_session_status::conflict;\n    case 412: return write_session_status::out_of_sync;\n    default: return write_session_status::unknown;\n    }\n}\n\nmultiplayer_session_change_event_args::multiplayer_session_change_event_args(\n    const XblMultiplayerSessionChangeEventArgs& args\n) \n    : m_args(args) \n{\n}\n\nmultiplayer_session_reference multiplayer_session_change_event_args::session_reference() const\n{\n    return multiplayer_session_reference(m_args.SessionReference);\n}\n\nstring_t multiplayer_session_change_event_args::branch() const\n{\n    return Utils::StringTFromUtf8(m_args.Branch);\n}\n\nuint64_t multiplayer_session_change_event_args::change_number() const\n{\n    return m_args.ChangeNumber;\n}\n\nmultiplayer_get_sessions_request::multiplayer_get_sessions_request(\n    _In_ string_t serviceConfigurationId,\n    _In_ uint32_t maxItems\n)\n    : m_request{}\n{\n    Utils::Utf8FromCharT(serviceConfigurationId.data(), m_request.Scid, sizeof(m_request.Scid));\n    m_request.MaxItems = maxItems;\n}\n\nstring_t multiplayer_get_sessions_request::service_configuration_id()\n{\n    return Utils::StringTFromUtf8(m_request.Scid);\n}\n\nuint32_t multiplayer_get_sessions_request::max_items()\n{\n    return m_request.MaxItems;\n}\n\nbool multiplayer_get_sessions_request::include_private_sessions()\n{\n    return m_request.IncludePrivateSessions;\n}\n\nvoid multiplayer_get_sessions_request::set_include_private_sessions(_In_ bool includePrivateSessions)\n{\n    m_request.IncludePrivateSessions = includePrivateSessions;\n}\n\nbool multiplayer_get_sessions_request::include_reservations()\n{\n    return m_request.IncludeReservations;\n}\n\nvoid multiplayer_get_sessions_request::set_include_reservations(_In_ bool includeResevations)\n{\n    m_request.IncludeReservations = includeResevations;\n}\n\nbool multiplayer_get_sessions_request::include_inactive_sessions()\n{\n    return m_request.IncludeInactiveSessions;\n}\n\nvoid multiplayer_get_sessions_request::set_include_inactive_sessions(_In_ bool includeInactiveSessions)\n{\n    m_request.IncludeInactiveSessions = includeInactiveSessions;\n}\n\nstring_t multiplayer_get_sessions_request::xbox_user_id_filter()\n{\n    if (m_request.XuidFiltersCount > 0)\n    {\n        return Utils::StringTFromUint64(m_request.XuidFilters[0]);\n    }\n    return string_t();\n}\n\nvoid multiplayer_get_sessions_request::set_xbox_user_id_filter(_In_ const string_t& filter)\n{\n    m_xuidFilters.clear();\n    if (!filter.empty())\n    {\n        m_xuidFilters.push_back(Utils::Uint64FromStringT(filter));\n        m_request.XuidFilters = m_xuidFilters.data();\n    }\n    m_request.XuidFiltersCount = m_xuidFilters.size();\n}\n\nstd::vector<string_t> multiplayer_get_sessions_request::xbox_user_ids_filter()\n{\n    return Utils::Transform<string_t>(m_xuidFilters, Utils::StringTFromUint64);\n}\n\nvoid multiplayer_get_sessions_request::set_xbox_user_ids_filter(_In_ const std::vector<string_t>& filters)\n{\n    m_xuidFilters = Utils::Transform<uint64_t>(filters, Utils::Uint64FromStringT);\n    m_request.XuidFiltersCount = static_cast<uint32_t>(m_xuidFilters.size());\n    m_request.XuidFilters = m_xuidFilters.data();\n}\n\nstring_t multiplayer_get_sessions_request::keyword_filter()\n{\n    return Utils::StringTFromUtf8(m_keywordFilter.data());\n}\n\nvoid multiplayer_get_sessions_request::set_keyword_filter(_In_ const string_t& filter)\n{\n    if (!filter.empty())\n    {\n        m_keywordFilter = Utils::StringFromStringT(filter);\n        m_request.KeywordFilter = m_keywordFilter.data();\n    }\n    else\n    {\n        m_request.KeywordFilter = nullptr;\n    }\n}\n\nstring_t multiplayer_get_sessions_request::session_template_name_filter()\n{\n    return Utils::StringTFromUtf8(m_request.SessionTemplateNameFilter);\n}\n\nvoid multiplayer_get_sessions_request::set_session_template_name_filter(_In_ const string_t& filter)\n{\n    Utils::Utf8FromCharT(filter.data(), m_request.SessionTemplateNameFilter, sizeof(m_request.SessionTemplateNameFilter));\n}\n\nmultiplayer_session_visibility multiplayer_get_sessions_request::visibility_filter()\n{\n    return static_cast<multiplayer_session_visibility>(m_request.VisibilityFilter);\n}\n\nvoid multiplayer_get_sessions_request::set_visibility_filter(_In_ multiplayer_session_visibility filter)\n{\n    m_request.VisibilityFilter = static_cast<XblMultiplayerSessionVisibility>(filter);\n}\n\nuint32_t multiplayer_get_sessions_request::contract_version_filter()\n{\n    return m_request.ContractVersionFilter;\n}\n\nvoid multiplayer_get_sessions_request::set_contract_version_filter(_In_ uint32_t filter)\n{\n    m_request.ContractVersionFilter = filter;\n}\n\nmultiplayer_query_search_handle_request::multiplayer_query_search_handle_request(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& sessionTemplateName\n) :\n    m_scid{ serviceConfigurationId },\n    m_sessionTemplateName{ sessionTemplateName }\n{\n}\n\nconst string_t& multiplayer_query_search_handle_request::service_configuration_id() const\n{\n    return m_scid;\n}\n\nconst string_t& multiplayer_query_search_handle_request::session_template_name() const\n{\n    return m_sessionTemplateName;\n}\n\nconst string_t& multiplayer_query_search_handle_request::order_by() const\n{\n    return m_orderBy;\n}\n\nvoid multiplayer_query_search_handle_request::set_order_by(_In_ const string_t& orderBy)\n{\n    m_orderBy = orderBy;\n}\n\nbool multiplayer_query_search_handle_request::order_ascending() const\n{\n    return m_orderAscending;\n}\n\nvoid multiplayer_query_search_handle_request::set_order_ascending(_In_ bool orderAscending)\n{\n    m_orderAscending = orderAscending;\n}\n\nconst string_t& multiplayer_query_search_handle_request::search_filter() const\n{\n    return m_searchFilter;\n}\n\nvoid multiplayer_query_search_handle_request::set_search_filter(_In_ const string_t& searchFilter)\n{\n    m_searchFilter = searchFilter;\n}\n\nconst string_t& multiplayer_query_search_handle_request::social_group() const\n{\n    return m_socialGroup;\n}\n\nvoid multiplayer_query_search_handle_request::set_social_group(_In_ const string_t& socialGroup)\n{\n    m_socialGroup = socialGroup;\n}\n\nmultiplayer_search_handle_request::multiplayer_search_handle_request(\n    _In_ multiplayer_session_reference sessionRef\n) :\n    m_sessionRef{ sessionRef.m_reference }\n{\n}\n\nmultiplayer_session_reference multiplayer_search_handle_request::session_reference() const\n{\n    return multiplayer_session_reference(m_sessionRef);\n}\n\nstd::vector<string_t> multiplayer_search_handle_request::tags() const\n{\n    return Utils::Transform<string_t>(m_tags, [](XblMultiplayerSessionTag tag)\n    {\n        return Utils::StringTFromUtf8(tag.value);\n    });\n}\n\nvoid multiplayer_search_handle_request::set_tags(_In_ const std::vector<string_t>& value)\n{\n    m_tags = Utils::Transform<XblMultiplayerSessionTag>(value, [](const string_t& str)\n    {\n        XblMultiplayerSessionTag tag{};\n        Utils::Utf8FromCharT(str.data(), tag.value, sizeof(tag.value));\n        return tag;\n    });\n}\n\nstd::unordered_map<string_t, double> multiplayer_search_handle_request::numbers_metadata() const\n{\n    std::unordered_map<string_t, double> out;\n    for (auto& attribute : m_numberAttributes)\n    {\n        out[Utils::StringTFromUtf8(attribute.name)] = attribute.value;\n    }\n    return out;\n}\n\nvoid multiplayer_search_handle_request::set_numbers_metadata(\n    _In_ const std::unordered_map<string_t, double>& metadata\n)\n{\n    m_numberAttributes = Utils::Transform<XblMultiplayerSessionNumberAttribute>(metadata.begin(), metadata.end(),\n        [](const std::unordered_map<string_t, double>::value_type& pair)\n    {\n        XblMultiplayerSessionNumberAttribute attr{ {}, pair.second };\n        Utils::Utf8FromCharT(pair.first.data(), attr.name, sizeof(attr.name));\n        return attr;\n    });\n}\n\nstd::unordered_map<string_t, string_t> multiplayer_search_handle_request::strings_metadata() const\n{\n    std::unordered_map<string_t, string_t> out;\n    for (auto& attribute : m_stringAttributes)\n    {\n        out[Utils::StringTFromUtf8(attribute.name)] = Utils::StringTFromUtf8(attribute.value);\n    }\n    return out;\n}\n\nvoid multiplayer_search_handle_request::set_strings_metadata(\n    _In_ const std::unordered_map<string_t, string_t>& metadata\n)\n{\n    m_stringAttributes = Utils::Transform<XblMultiplayerSessionStringAttribute>(metadata.begin(), metadata.end(),\n        [](const std::unordered_map<string_t, string_t>::value_type& pair)\n    {\n        XblMultiplayerSessionStringAttribute attr{};\n        Utils::Utf8FromCharT(pair.first.data(), attr.name, sizeof(attr.name));\n        Utils::Utf8FromCharT(pair.second.data(), attr.value, sizeof(attr.value));\n        return attr;\n    });\n}\n\nmultiplayer_service::multiplayer_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_handle);\n}\n\nmultiplayer_service::multiplayer_service(const multiplayer_service& other)\n{\n    XblContextDuplicateHandle(other.m_handle, &m_handle);\n}\n\nmultiplayer_service& multiplayer_service::operator=(multiplayer_service other)\n{\n    std::swap(m_handle, other.m_handle);\n    return *this;\n}\n\nmultiplayer_service::~multiplayer_service()\n{\n    XblContextCloseHandle(m_handle);\n}\n\npplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> multiplayer_service::write_session(\n    _In_ std::shared_ptr<multiplayer_session> multiplayerSession,\n    _In_ multiplayer_session_write_mode writeMode\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<multiplayer_session>>(\n        [](XAsyncBlock* async, std::shared_ptr<multiplayer_session>& result)\n    {\n        XblMultiplayerSessionHandle sessionHandle;\n        auto hr = XblMultiplayerWriteSessionResult(async, &sessionHandle);\n        if (sessionHandle)\n        {\n            XblWriteSessionStatus sessionStatus = XblMultiplayerSessionWriteStatus(sessionHandle);\n            switch (sessionStatus)\n            {\n            case XblWriteSessionStatus::Updated: //200 Updated Successfully\n            case XblWriteSessionStatus::Created: //201 Created Successfully\n            case XblWriteSessionStatus::SessionDeleted: //204 Deleted Successfully\n                //Intentional Fallthrough\n                hr = S_OK;\n                break;\n            case XblWriteSessionStatus::AccessDenied: //403 Forbidden\n                hr = HTTP_E_STATUS_FORBIDDEN;\n                break;\n            case XblWriteSessionStatus::HandleNotFound: //404 Not Found\n                hr = HTTP_E_STATUS_NOT_FOUND;\n                break;\n            case XblWriteSessionStatus::Conflict: //409 Conflict\n                hr = HTTP_E_STATUS_CONFLICT;\n                break;\n            case XblWriteSessionStatus::OutOfSync: //412 Not the most recent\n                hr = HTTP_E_STATUS_PRECOND_FAILED;\n                break;\n            case XblWriteSessionStatus::Unknown:\n            default:\n                break;\n            }\n            result = std::shared_ptr<multiplayer_session>(new multiplayer_session(sessionHandle));\n            XblMultiplayerSessionCloseHandle(sessionHandle);\n        }\n        else\n        {\n            result = nullptr;\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerWriteSessionAsync(m_handle, multiplayerSession->m_handle, static_cast<XblMultiplayerSessionWriteMode>(writeMode), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> multiplayer_service::write_session_by_handle(\n    _In_ std::shared_ptr<multiplayer_session> multiplayerSession,\n    _In_ multiplayer_session_write_mode writeMode,\n    _In_ const string_t& handleId\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<multiplayer_session>>(\n        [](XAsyncBlock* async, std::shared_ptr<multiplayer_session>& result)\n    {\n        XblMultiplayerSessionHandle sessionHandle;\n        auto hr = XblMultiplayerWriteSessionByHandleResult(async, &sessionHandle);\n        if (SUCCEEDED(hr))\n        {\n            if (sessionHandle)\n            {\n                result = std::shared_ptr<multiplayer_session>(new multiplayer_session(sessionHandle));\n                XblMultiplayerSessionCloseHandle(sessionHandle);\n            }\n            else\n            {\n                result = nullptr;\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerWriteSessionByHandleAsync(\n        m_handle,\n        multiplayerSession->m_handle,\n        static_cast<XblMultiplayerSessionWriteMode>(writeMode),\n        Utils::StringFromStringT(handleId).data(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> multiplayer_service::get_current_session(\n    _In_ multiplayer_session_reference sessionReference\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<multiplayer_session>>(\n        [](XAsyncBlock* async, std::shared_ptr<multiplayer_session>& result)\n    {\n        XblMultiplayerSessionHandle sessionHandle;\n        auto hr = XblMultiplayerGetSessionResult(async, &sessionHandle);\n        if (SUCCEEDED(hr))\n        {\n            if (sessionHandle)\n            {\n                result = std::shared_ptr<multiplayer_session>(new multiplayer_session(sessionHandle));\n                XblMultiplayerSessionCloseHandle(sessionHandle);\n            }\n            else\n            {\n                result = nullptr;\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerGetSessionAsync(m_handle, &sessionReference.m_reference, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> multiplayer_service::get_current_session_by_handle(\n    _In_ const string_t& handleId\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<multiplayer_session>>(\n        [](XAsyncBlock* async, std::shared_ptr<multiplayer_session>& result)\n    {\n        XblMultiplayerSessionHandle sessionHandle;\n        auto hr = XblMultiplayerGetSessionByHandleResult(async, &sessionHandle);\n        if (SUCCEEDED(hr))\n        {\n            if (sessionHandle)\n            {\n                result = std::shared_ptr<multiplayer_session>(new multiplayer_session(sessionHandle));\n                XblMultiplayerSessionCloseHandle(sessionHandle);\n            }\n            else\n            {\n                result = nullptr;\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerGetSessionByHandleAsync(m_handle, Utils::StringFromStringT(handleId).data(), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<multiplayer_session_states>>> multiplayer_service::get_sessions(\n    _In_ multiplayer_get_sessions_request getSessionsRequest\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<multiplayer_session_states>>(\n        [](XAsyncBlock* async, std::vector<multiplayer_session_states>& result)\n    {\n        size_t resultCount;\n        auto hr = XblMultiplayerQuerySessionsResultCount(async, &resultCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<XblMultiplayerSessionQueryResult> intermediateResults(resultCount);\n            hr = XblMultiplayerQuerySessionsResult(async, resultCount, intermediateResults.data());\n\n            if (SUCCEEDED(hr))\n            {\n                result = std::vector<multiplayer_session_states>(intermediateResults.begin(), intermediateResults.end());\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerQuerySessionsAsync(m_handle, &getSessionsRequest.m_request, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\n\npplx::task<xbox_live_result<void>> multiplayer_service::set_activity(\n    _In_ multiplayer_session_reference sessionReference\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblMultiplayerSetActivityAsync(m_handle, &sessionReference.m_reference, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<string_t>> multiplayer_service::set_transfer_handle(\n    _In_ multiplayer_session_reference targetSessionReference,\n    _In_ multiplayer_session_reference originSessionReference\n)\n{\n    auto asyncWrapper = new AsyncWrapper<string_t>(\n        [](XAsyncBlock* async, string_t& result)\n        {\n            XblMultiplayerSessionHandleId id{};\n            HRESULT hr = XblMultiplayerSetTransferHandleResult(async, &id);\n            if (SUCCEEDED(hr))\n            {\n                result = xbox::services::Utils::StringTFromUtf8(id.value);\n            }\n            return hr;\n        });\n\n    HRESULT hr = XblMultiplayerSetTransferHandleAsync(m_handle, targetSessionReference.m_reference, originSessionReference.m_reference, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n\n}\n\npplx::task<xbox_live_result<void>> multiplayer_service::set_search_handle(\n    _In_ multiplayer_search_handle_request r\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>(\n        [](XAsyncBlock* async)\n    {\n        return XblMultiplayerCreateSearchHandleResult(async, nullptr);\n    });\n\n    auto hr = XblMultiplayerCreateSearchHandleAsync(\n        m_handle,\n        &r.m_sessionRef,\n        r.m_tags.data(),\n        r.m_tags.size(),\n        r.m_numberAttributes.data(),\n        r.m_numberAttributes.size(),\n        r.m_stringAttributes.data(),\n        r.m_stringAttributes.size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<void>> multiplayer_service::multiplayer_service::clear_activity(\n    _In_ const string_t& serviceConfigurationId\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblMultiplayerClearActivityAsync(m_handle, Utils::StringFromStringT(serviceConfigurationId).data(), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<void>> multiplayer_service::clear_search_handle(\n    _In_ const string_t& handleId\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblMultiplayerDeleteSearchHandleAsync(m_handle, Utils::StringFromStringT(handleId).data(), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<string_t>>> multiplayer_service::send_invites(\n    _In_ multiplayer_session_reference sessionReference,\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ uint32_t titleId\n)\n{\n    return send_invites(sessionReference, xboxUserIds, titleId, string_t(), string_t());\n}\n\npplx::task<xbox_live_result<std::vector<string_t>>> multiplayer_service::send_invites(\n    _In_ multiplayer_session_reference sessionReference,\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ uint32_t titleId,\n    _In_ const string_t& contextStringId,\n    _In_ const string_t& customActivationContext\n)\n{\n    auto xuids = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n    size_t xuidCount = xboxUserIds.size();\n\n    auto asyncWrapper = new AsyncWrapper<std::vector<string_t>>(\n        [xuidCount](XAsyncBlock* async, std::vector<string_t>& result)\n    {\n        std::vector<XblMultiplayerInviteHandle> inviteHandles(xuidCount);\n        auto hr = XblMultiplayerSendInvitesResult(async, xuidCount, inviteHandles.data());\n        if (SUCCEEDED(hr))\n        {\n            result = Utils::Transform<string_t>(inviteHandles, [](const XblMultiplayerInviteHandle& handle)\n            {\n                return Utils::StringTFromUtf8(handle.Data);\n            });\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerSendInvitesAsync(\n        m_handle,\n        &sessionReference.m_reference,\n        xuids.data(),\n        xuidCount,\n        titleId,\n        contextStringId.empty() ? nullptr : Utils::StringFromStringT(contextStringId).data(),\n        customActivationContext.empty() ? nullptr : Utils::StringFromStringT(customActivationContext).data(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<multiplayer_activity_details>>> multiplayer_service::get_activities_for_social_group(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& socialGroupOwnerXboxUserId,\n    _In_ const string_t& socialGroup\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<multiplayer_activity_details>>(\n        [](XAsyncBlock* async, std::vector<multiplayer_activity_details>& result)\n    {\n        size_t resultSize;\n        auto hr = XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize(async, &resultSize);\n        if (SUCCEEDED(hr))\n        {\n            size_t count{ 0 };\n            std::vector<char> buffer(resultSize, 0);\n            XblMultiplayerActivityDetails* activityDetails{};\n            if (resultSize > 0)\n            {\n                hr = XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult(async, resultSize, buffer.data(), &activityDetails, &count, nullptr);\n                if (SUCCEEDED(hr))\n                {\n                    result = std::vector<multiplayer_activity_details>(activityDetails, activityDetails + count);\n                }\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync(\n        m_handle,\n        Utils::StringFromStringT(serviceConfigurationId).data(),\n        Utils::Uint64FromStringT(socialGroupOwnerXboxUserId),\n        Utils::StringFromStringT(socialGroup).data(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<multiplayer_activity_details>>> multiplayer_service::get_activities_for_users(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const std::vector<string_t>& xboxUserIds\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<multiplayer_activity_details>>(\n        [](XAsyncBlock* async, std::vector<multiplayer_activity_details>& result)\n    {\n        size_t resultSize;\n        auto hr = XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize(async, &resultSize);\n        if (SUCCEEDED(hr))\n        {\n            size_t count{ 0 };\n            std::vector<char> buffer(resultSize, 0);\n            XblMultiplayerActivityDetails* activityDetails{};\n            if (resultSize > 0)\n            {\n                hr = XblMultiplayerGetActivitiesWithPropertiesForUsersResult(async, resultSize, buffer.data(), &activityDetails, &count, nullptr);\n                if (SUCCEEDED(hr))\n                {\n                    result = std::vector<multiplayer_activity_details>(activityDetails, activityDetails + count);\n                }\n            }\n        }\n        return hr;\n    });\n\n    auto xuids = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n\n    auto hr = XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(\n        m_handle,\n        Utils::StringFromStringT(serviceConfigurationId).data(),\n        xuids.data(),\n        xuids.size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<multiplayer_search_handle_details>>> multiplayer_service::get_search_handles(\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& sessionTemplateName,\n    _In_ const string_t& orderBy,\n    _In_ bool orderAscending,\n    _In_ const string_t& searchFilter\n)\n{\n    multiplayer_query_search_handle_request request{ serviceConfigurationId, sessionTemplateName };\n    request.set_order_by(orderBy);\n    request.set_order_ascending(orderAscending);\n    request.set_search_filter(searchFilter);\n\n    return get_search_handles(request);\n}\n\npplx::task<xbox_live_result<std::vector<multiplayer_search_handle_details>>> multiplayer_service::get_search_handles(\n    _In_ const multiplayer_query_search_handle_request& r\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<multiplayer_search_handle_details>>(\n        [](XAsyncBlock* async, std::vector<multiplayer_search_handle_details>& result)\n    {\n        size_t resultCount{ 0 };\n        auto hr = XblMultiplayerGetSearchHandlesResultCount(async, &resultCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<XblMultiplayerSearchHandle> handles{ resultCount };\n            hr = XblMultiplayerGetSearchHandlesResult(async, handles.data(), resultCount);\n            if (SUCCEEDED(hr))\n            {\n                result = std::vector<multiplayer_search_handle_details>{ handles.begin(), handles.end() };\n                for (auto& handle : handles)\n                {\n                    XblMultiplayerSearchHandleCloseHandle(handle);\n                }\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblMultiplayerGetSearchHandlesAsync(\n        m_handle,\n        Utils::StringFromStringT(r.service_configuration_id()).data(),\n        Utils::StringFromStringT(r.session_template_name()).data(),\n        Utils::StringFromStringT(r.order_by()).data(),\n        r.order_ascending(),\n        Utils::StringFromStringT(r.search_filter()).data(),\n        Utils::StringFromStringT(r.social_group()).data(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nstd::error_code multiplayer_service::enable_multiplayer_subscriptions()\n{\n    return Utils::ConvertHr(XblMultiplayerSetSubscriptionsEnabled(m_handle, true));\n}\n\nvoid multiplayer_service::disable_multiplayer_subscriptions()\n{\n    XblMultiplayerSetSubscriptionsEnabled(m_handle, false);\n}\n\nbool multiplayer_service::subscriptions_enabled()\n{\n    return XblMultiplayerSubscriptionsEnabled(m_handle);\n}\n\nstruct multiplayer_service::HandlerContext\n{\n    XblFunctionContext internalContext;\n    std::function<void(const multiplayer_session_change_event_args&)> sessionChangedHandler;\n    std::function<void()> subscriptionLostHandler;\n    std::function<void()> connectionIdChangedHandler;\n};\n\nfunction_context multiplayer_service::add_multiplayer_session_changed_handler(\n    _In_ std::function<void(const multiplayer_session_change_event_args&)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->sessionChangedHandler = std::move(handler);\n\n    context->internalContext = XblMultiplayerAddSessionChangedHandler(m_handle,\n        [](_In_ void* context, _In_ XblMultiplayerSessionChangeEventArgs internalArgs)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->sessionChangedHandler(multiplayer_session_change_event_args{ internalArgs });\n    }, context);\n\n    return context;\n}\n\nvoid multiplayer_service::remove_multiplayer_session_changed_handler(\n    _In_ function_context context\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblMultiplayerRemoveSessionChangedHandler(m_handle, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nfunction_context multiplayer_service::add_multiplayer_subscription_lost_handler(\n    _In_ std::function<void()> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->subscriptionLostHandler = std::move(handler);\n\n    context->internalContext = XblMultiplayerAddSubscriptionLostHandler(m_handle,\n        [](void* context)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->subscriptionLostHandler();\n    }, context);\n\n    return context;\n}\n\nvoid multiplayer_service::remove_multiplayer_subscription_lost_handler(\n    _In_ function_context context\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblMultiplayerRemoveSubscriptionLostHandler(m_handle, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nfunction_context multiplayer_service::add_multiplayer_connection_id_changed_handler(\n    _In_ std::function<void()> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->connectionIdChangedHandler = std::move(handler);\n\n    context->internalContext = XblMultiplayerAddConnectionIdChangedHandler(m_handle,\n        [](void* context)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->connectionIdChangedHandler();\n    }, context);\n\n    return context;\n}\n\nvoid multiplayer_service::remove_multiplayer_connection_id_changed_handler(\n    _In_ function_context context\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblMultiplayerRemoveConnectionIdChangedHandler(m_handle, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/multiplayer_manager.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nuint32_t multiplayer_member::member_id() const\n{\n    return m_internalMember.MemberId;\n}\n\nstring_t multiplayer_member::initial_team() const\n{\n    return Utils::StringTFromUtf8(m_internalMember.InitialTeam);\n}\n\nstring_t multiplayer_member::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_internalMember.Xuid);\n}\n\nstring_t multiplayer_member::debug_gamertag() const\n{\n    return Utils::StringTFromUtf8(m_internalMember.DebugGamertag);\n}\n\nbool multiplayer_member::is_local() const\n{\n    return m_internalMember.IsLocal;\n}\n\nbool multiplayer_member::is_in_lobby() const\n{\n    return m_internalMember.IsInLobby;\n}\n\nbool multiplayer_member::is_in_game() const\n{\n    return m_internalMember.IsInGame;\n}\n\nmultiplayer_session_member_status multiplayer_member::status() const\n{\n    return static_cast<multiplayer_session_member_status>(m_internalMember.Status);\n}\n\nstring_t multiplayer_member::connection_address() const\n{\n    return Utils::StringTFromUtf8(m_internalMember.ConnectionAddress);\n}\n\nweb::json::value multiplayer_member::properties() const\n{\n    return Utils::ParseJson(m_internalMember.PropertiesJson);\n}\n\nbool multiplayer_member::is_member_on_same_device(\n    _In_ std::shared_ptr<multiplayer_member> member\n) const\n{\n    return XblMultiplayerManagerMemberAreMembersOnSameDevice(&m_internalMember, &member->m_internalMember);\n}\n\nstring_t multiplayer_lobby_session::correlation_id() const\n{\n    XblGuid correlationId{};\n    XblMultiplayerManagerLobbySessionCorrelationId(&correlationId);\n    return Utils::StringTFromUtf8(correlationId.value);\n}\n\nmultiplayer_session_reference multiplayer_lobby_session::session_reference() const\n{\n    XblMultiplayerSessionReference sessionReference{};\n    XblMultiplayerManagerLobbySessionSessionReference(&sessionReference);\n    return multiplayer_session_reference(sessionReference);\n}\n\nstd::vector<std::shared_ptr<multiplayer_member>> multiplayer_lobby_session::local_members() const\n{\n    size_t localMemberCount = XblMultiplayerManagerLobbySessionLocalMembersCount();\n    std::vector<XblMultiplayerManagerMember> localMembers(localMemberCount);\n    XblMultiplayerManagerLobbySessionLocalMembers(localMemberCount, localMembers.data());\n\n    return Utils::Transform<std::shared_ptr<multiplayer_member>>(localMembers, [](const XblMultiplayerManagerMember& member)\n    {\n        return std::make_shared<multiplayer_member>(member);\n    });\n}\n\nstd::vector<std::shared_ptr<multiplayer_member>> multiplayer_lobby_session::members() const\n{\n    size_t memberCount = XblMultiplayerManagerLobbySessionMembersCount();\n    std::vector<XblMultiplayerManagerMember> members(memberCount);\n    XblMultiplayerManagerLobbySessionMembers(memberCount, members.data());\n\n    return Utils::Transform<std::shared_ptr<multiplayer_member>>(members, [](const XblMultiplayerManagerMember& member)\n    {\n        return std::make_shared<multiplayer_member>(member);\n    });\n}\n\nstd::shared_ptr<multiplayer_member> multiplayer_lobby_session::host() const\n{\n    XblMultiplayerManagerMember host;\n    XblMultiplayerManagerLobbySessionHost(&host);\n    return std::make_shared<multiplayer_member>(host);\n}\n\nweb::json::value multiplayer_lobby_session::properties() const\n{\n    return Utils::ParseJson(XblMultiplayerManagerLobbySessionPropertiesJson());\n}\n\nconst std::shared_ptr<multiplayer_session_constants> multiplayer_lobby_session::session_constants() const\n{\n    if (m_sessionConstants == nullptr)\n    {\n        m_sessionConstants = std::make_shared<multiplayer_session_constants>(true);\n    }\n    return m_sessionConstants;\n}\n\nxbox_live_result<void> multiplayer_lobby_session::add_local_user(\n    _In_ xbox_live_user_t user\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionAddLocalUser(user));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::remove_local_user(\n    _In_ xbox_live_user_t user\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionRemoveLocalUser(user));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::set_local_member_properties(\n    _In_ xbox_live_user_t user,\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(\n        user,\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::delete_local_member_properties(\n    _In_ xbox_live_user_t user,\n    _In_ const string_t& name,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(\n        user,\n        Utils::StringFromStringT(name).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::set_local_member_connection_address(\n    _In_ xbox_live_user_t user,\n    _In_ const string_t& connectionAddress,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n        user,\n        Utils::StringFromStringT(connectionAddress).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nbool multiplayer_lobby_session::is_host(\n    _In_ const string_t& xboxUserId\n)\n{\n    return XblMultiplayerManagerLobbySessionIsHost(Utils::Uint64FromStringT(xboxUserId));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::set_properties(\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionSetProperties(\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::set_synchronized_properties(\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nxbox_live_result<void> multiplayer_lobby_session::set_synchronized_host(\n    _In_ std::shared_ptr<multiplayer_member> gameHost,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionSetSynchronizedHost(\n        gameHost->m_internalMember.DeviceToken,\n        reinterpret_cast<void*>(context)\n    ));\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\nxbox_live_result<void> multiplayer_lobby_session::invite_friends(\n    _In_ xbox_live_user_t user,\n    _In_ const string_t& contextStringId,\n    _In_ const string_t& customActivationContext\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionInviteFriends(\n        user,\n        Utils::StringFromStringT(contextStringId).data(),\n        Utils::StringFromStringT(customActivationContext).data()\n    ));\n}\n#endif\n\nxbox_live_result<void> multiplayer_lobby_session::invite_users(\n    _In_ xbox_live_user_t user,\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ const string_t& contextStringId,\n    _In_ const string_t& customActivationContext\n)\n{\n    auto xuids = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n\n    return Utils::ConvertHr(XblMultiplayerManagerLobbySessionInviteUsers(\n        user,\n        xuids.data(),\n        xuids.size(),\n        Utils::StringFromStringT(contextStringId).data(),\n        Utils::StringFromStringT(customActivationContext).data()\n    ));\n}\n\nstring_t multiplayer_game_session::correlation_id() const\n{\n    return Utils::StringTFromUtf8(XblMultiplayerManagerGameSessionCorrelationId());\n}\n\nmultiplayer_session_reference multiplayer_game_session::session_reference() const\n{\n    return multiplayer_session_reference(*XblMultiplayerManagerGameSessionSessionReference());\n}\n\nstd::vector<std::shared_ptr<multiplayer_member>> multiplayer_game_session::members() const\n{\n    size_t memberCount = XblMultiplayerManagerGameSessionMembersCount();\n    std::vector<XblMultiplayerManagerMember> members(memberCount);\n    XblMultiplayerManagerGameSessionMembers(memberCount, members.data());\n\n    return Utils::Transform<std::shared_ptr<multiplayer_member>>(members, [](const XblMultiplayerManagerMember& member)\n    {\n        return std::make_shared<multiplayer_member>(member);\n    });\n}\n\nstd::shared_ptr<multiplayer_member> multiplayer_game_session::host() const\n{\n    XblMultiplayerManagerMember host{};\n    XblMultiplayerManagerGameSessionHost(&host);\n    return std::make_shared<multiplayer_member>(host);\n}\n\nweb::json::value multiplayer_game_session::properties() const\n{\n    return Utils::ParseJson(XblMultiplayerManagerGameSessionPropertiesJson());\n}\n\nconst std::shared_ptr<xbox::services::multiplayer::multiplayer_session_constants> multiplayer_game_session::session_constants() const\n{\n    if (m_sessionConstants == nullptr)\n    {\n        m_sessionConstants = std::make_shared<xbox::services::multiplayer::multiplayer_session_constants>(false);\n    }\n    return m_sessionConstants;\n}\n\nbool multiplayer_game_session::is_host(\n    _In_ const string_t& xboxUserId\n)\n{\n    return XblMultiplayerManagerGameSessionIsHost(Utils::Uint64FromStringT(xboxUserId));\n}\n\nxbox_live_result<void> multiplayer_game_session::set_properties(\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerGameSessionSetProperties(\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nxbox_live_result<void> multiplayer_game_session::set_synchronized_properties(\n    _In_ const string_t& name,\n    _In_ const web::json::value& valueJson,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerGameSessionSetSynchronizedProperties(\n        Utils::StringFromStringT(name).data(),\n        Utils::StringFromStringT(valueJson.serialize()).data(),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nxbox_live_result<void> multiplayer_game_session::set_synchronized_host(\n    _In_ std::shared_ptr<multiplayer_member> gameHost,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerGameSessionSetSynchronizedHost(\n        gameHost->m_internalMember.DeviceToken,\n        reinterpret_cast<void*>(context)\n    ));\n}\n\nmultiplayer_event_args::multiplayer_event_args(XblMultiplayerEventArgsHandle argsHandle)\n    : m_argsHandle(argsHandle) \n{\n}\n\nmultiplayer_event_args::~multiplayer_event_args()\n{\n}\n\nstring_t multiplayer_event_args::GetXuid() const\n{\n    uint64_t xuid;\n    XblMultiplayerEventArgsXuid(m_argsHandle, &xuid);\n    return Utils::StringTFromUint64(xuid);\n}\n\nstd::vector<std::shared_ptr<multiplayer_member>> multiplayer_event_args::GetMembers() const\n{\n    size_t memberCount;\n    XblMultiplayerEventArgsMembersCount(m_argsHandle, &memberCount);\n    std::vector<XblMultiplayerManagerMember> members(memberCount);\n    XblMultiplayerEventArgsMembers(m_argsHandle, memberCount, members.data());\n\n    return Utils::Transform<std::shared_ptr<multiplayer_member>>(members, [](const XblMultiplayerManagerMember& member)\n    {\n        return std::make_shared<multiplayer_member>(member);\n    });\n}\n\nstd::shared_ptr<multiplayer_member> multiplayer_event_args::GetMember() const\n{\n    XblMultiplayerManagerMember member{};\n    XblMultiplayerEventArgsMember(m_argsHandle, &member);\n    return std::make_shared<multiplayer_member>(member);\n}\n\nweb::json::value multiplayer_event_args::GetPropertiesJson() const\n{\n    const char* json = nullptr;\n    XblMultiplayerEventArgsPropertiesJson(m_argsHandle, &json);\n    return Utils::ParseJson(json);\n}\n\n\nxbox::services::multiplayer::manager::match_status find_match_completed_event_args::match_status() const\n{\n    XblMultiplayerMatchStatus status;\n    XblMultiplayerEventArgsFindMatchCompleted(m_argsHandle, &status, nullptr);\n    return static_cast<xbox::services::multiplayer::manager::match_status>(status);\n}\n\nmultiplayer_measurement_failure find_match_completed_event_args::initialization_failure_cause() const\n{\n    XblMultiplayerMeasurementFailure cause;\n    XblMultiplayerEventArgsFindMatchCompleted(m_argsHandle, nullptr, &cause);\n    return static_cast<xbox::services::multiplayer::multiplayer_measurement_failure>(cause);\n}\n\nstd::map<string_t, string_t> perform_qos_measurements_event_args::connection_address_to_device_tokens() const\n{\n    XblMultiplayerPerformQoSMeasurementsArgs args{};\n    XblMultiplayerEventArgsPerformQoSMeasurements(m_argsHandle, &args);\n\n    std::map<string_t, string_t> out;\n    for (size_t i = 0; i < args.remoteClientsSize; ++i)\n    {\n        out.insert(std::make_pair(Utils::StringTFromUtf8(args.remoteClients[i].connectionAddress), Utils::StringTFromUtf8(args.remoteClients[i].deviceToken.Value)));\n    }\n    return out;\n}\n\nmultiplayer_event::multiplayer_event(_In_ const XblMultiplayerEvent* internalEvent) \n    : m_internalEvent(internalEvent) \n{\n}\n\nstd::error_code multiplayer_event::err() const\n{\n    return std::make_error_code(static_cast<xbox::services::xbox_live_error_code>(m_internalEvent->Result));\n}\n\nstd::string multiplayer_event::err_message() const\n{\n    if (m_internalEvent->ErrorMessage)\n    {\n        return m_internalEvent->ErrorMessage;\n    }\n    return std::string();\n}\n\ncontext_t multiplayer_event::context()\n{\n    return reinterpret_cast<context_t>(m_internalEvent->Context);\n}\n\nmultiplayer_event_type multiplayer_event::event_type() const\n{\n    return static_cast<multiplayer_event_type>(m_internalEvent->EventType);\n}\n\nstd::shared_ptr<multiplayer_event_args> multiplayer_event::event_args()\n{\n    if (m_eventArgs == nullptr)\n    {\n        switch (m_internalEvent->EventType)\n        {\n        case XblMultiplayerEventType::UserAdded:\n        {\n            m_eventArgs = std::make_shared<user_added_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::UserRemoved:\n        {\n            m_eventArgs = std::make_shared<user_removed_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::MemberJoined:\n        {\n            m_eventArgs = std::make_shared<member_joined_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::MemberLeft:\n        {\n            m_eventArgs = std::make_shared<member_left_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::MemberPropertyChanged:\n        {\n            m_eventArgs = std::make_shared<member_property_changed_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::SessionPropertyChanged:\n        {\n            m_eventArgs = std::make_shared<session_property_changed_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::HostChanged:\n        {\n            m_eventArgs = std::make_shared<host_changed_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::PerformQosMeasurements:\n        {\n            m_eventArgs = std::make_shared<perform_qos_measurements_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::FindMatchCompleted:\n        {\n            m_eventArgs = std::make_shared<find_match_completed_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        case XblMultiplayerEventType::JoinLobbyCompleted:\n        {\n            m_eventArgs = std::make_shared<join_lobby_completed_event_args>(m_internalEvent->EventArgsHandle);\n            break;\n        }\n        default: break;\n        }\n    }\n    return m_eventArgs;\n}\n\nmultiplayer_session_type multiplayer_event::session_type() const\n{\n    return static_cast<multiplayer_session_type>(m_internalEvent->SessionType);\n}\n\nstd::shared_ptr<multiplayer_manager> multiplayer_manager::get_singleton_instance()\n{\n    static std::shared_ptr<multiplayer_manager> instance = std::shared_ptr<multiplayer_manager>(new multiplayer_manager());\n    return instance;\n}\n\nvoid multiplayer_manager::initialize(\n    _In_ const string_t& lobbySessionTemplateName\n)\n{\n    XblMultiplayerManagerInitialize(Utils::StringFromStringT(lobbySessionTemplateName).data(), nullptr);\n}\n\nstd::vector<multiplayer_event> multiplayer_manager::do_work()\n{\n    const XblMultiplayerEvent* eventPtr;\n    size_t eventCount;\n    XblMultiplayerManagerDoWork(&eventPtr, &eventCount);\n\n    return Utils::Transform<multiplayer_event>(eventPtr, eventCount, [](const XblMultiplayerEvent& in)\n    {\n        return multiplayer_event(&in);\n    });\n}\n\nstd::shared_ptr<multiplayer_lobby_session> multiplayer_manager::lobby_session() const\n{\n    if (m_lobbySession == nullptr)\n    {\n        m_lobbySession = std::make_shared<multiplayer_lobby_session>();\n    }\n    return m_lobbySession;\n}\n\nstd::shared_ptr<multiplayer_game_session> multiplayer_manager::game_session() const\n{\n    if (XblMultiplayerManagerGameSessionActive())\n    {\n        return std::make_shared<multiplayer_game_session>();\n    }\n    return nullptr;\n}\n\nxbox_live_result<void> multiplayer_manager::join_lobby(\n    _In_ const string_t& handleId,\n    _In_ xbox_live_user_t user\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerJoinLobby(Utils::StringFromStringT(handleId).data(), user));\n}\n\n#if (TV_API || UWP_API)\nxbox_live_result<void> multiplayer_manager::join_lobby(\n    _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n    _In_ xbox_live_user_t user\n)\n{\n    // TODO\n    UNREFERENCED_PARAMETER(eventArgs);\n    UNREFERENCED_PARAMETER(user);\n    return xbox_live_result<void>(xbox_live_error_code::unsupported);\n}\n#endif\n\n#if TV_API\nxbox_live_result<void> multiplayer_manager::join_lobby(\n    _In_ const string_t& handleId,\n    _In_ std::vector<Windows::Xbox::System::User^> users\n)\n{\n    // TODO\n    UNREFERENCED_PARAMETER(handleId);\n    UNREFERENCED_PARAMETER(users);\n    return xbox_live_result<void>(xbox_live_error_code::unsupported);\n}\n\nxbox_live_result<void> multiplayer_manager::join_lobby(\n    _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n    _In_ std::vector<Windows::Xbox::System::User^> users\n)\n{\n    // TODO\n    UNREFERENCED_PARAMETER(eventArgs);\n    UNREFERENCED_PARAMETER(users);\n    return xbox_live_result<void>(xbox_live_error_code::unsupported);\n}\n\nvoid multiplayer_manager::invite_party_to_game()\n{\n    // TODO\n}\n\n#endif\n\nxbox_live_result<void> multiplayer_manager::join_game_from_lobby(\n    _In_ const string_t& sessionTemplateName\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerJoinGameFromLobby(Utils::StringFromStringT(sessionTemplateName).data()));\n}\n\nxbox_live_result<void> multiplayer_manager::join_game(\n    _In_ const string_t& sessionName,\n    _In_ const string_t& sessionTemplateName,\n    _In_ const std::vector<string_t>& xboxUserIds\n)\n{\n    auto xuids = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n\n    return Utils::ConvertHr(XblMultiplayerManagerJoinGame(\n        Utils::StringFromStringT(sessionName).data(),\n        Utils::StringFromStringT(sessionTemplateName).data(),\n        xuids.data(),\n        static_cast<uint32_t>(xuids.size())\n    ));\n}\n\nxbox_live_result<void> multiplayer_manager::leave_game()\n{\n    return Utils::ConvertHr(XblMultiplayerManagerLeaveGame());\n}\n\nxbox_live_result<void> multiplayer_manager::find_match(\n    _In_ const string_t& hopperName,\n    _In_ const web::json::value& attributes,\n    _In_ const std::chrono::seconds& timeout\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerFindMatch(\n        Utils::StringFromStringT(hopperName).data(),\n        Utils::StringFromStringT(attributes.serialize()).data(),\n        static_cast<uint32_t>(timeout.count())\n    ));\n}\n\nvoid multiplayer_manager::cancel_match()\n{\n    return XblMultiplayerManagerCancelMatch();\n}\n\nxbox::services::multiplayer::manager::match_status multiplayer_manager::match_status() const\n{\n    return static_cast<xbox::services::multiplayer::manager::match_status>(XblMultiplayerManagerMatchStatus());\n}\n\nstd::chrono::seconds multiplayer_manager::estimated_match_wait_time() const\n{\n    return std::chrono::seconds(XblMultiplayerManagerEstimatedMatchWaitTime());\n}\n\nbool multiplayer_manager::auto_fill_members_during_matchmaking() const\n{\n    return XblMultiplayerManagerAutoFillMembersDuringMatchmaking();\n}\n\nvoid multiplayer_manager::set_auto_fill_members_during_matchmaking(\n    _In_ bool autoFillMembers\n)\n{\n    XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking(autoFillMembers);\n}\n\nvoid multiplayer_manager::set_quality_of_service_measurements(\n    _In_ std::shared_ptr<std::vector<xbox::services::multiplayer::multiplayer_quality_of_service_measurements>> measurements\n)\n{\n    web::json::value measurementsJson;\n    for (const auto& measurement : *measurements)\n    {\n        web::json::value jsonMeasurement;\n        jsonMeasurement[_T(\"latency\")] = static_cast<int64_t>(measurement.latency().count());\n        jsonMeasurement[_T(\"bandwidthDown\")] = measurement.bandwidth_down_in_kilobits_per_second();\n        jsonMeasurement[_T(\"bandwidthUp\")] = measurement.bandwidth_up_in_kilobits_per_second();\n        jsonMeasurement[_T(\"custom\")] = measurement.custom_json();\n\n        measurementsJson[measurement.member_device_token()] = jsonMeasurement;\n    }\n    auto measurementsJsonString = Utils::StringFromStringT(measurementsJson.serialize());\n    XblMultiplayerManagerSetQosMeasurements(measurementsJsonString.data());\n}\n\njoinability multiplayer_manager::joinability() const\n{\n    return static_cast<xbox::services::multiplayer::manager::joinability>(XblMultiplayerManagerJoinability());\n}\n\nxbox_live_result<void> multiplayer_manager::set_joinability(\n    _In_ xbox::services::multiplayer::manager::joinability value,\n    _In_opt_ context_t context\n)\n{\n    return Utils::ConvertHr(XblMultiplayerManagerSetJoinability(\n        static_cast<XblMultiplayerJoinability>(value),\n        reinterpret_cast<void*>(context)\n    ));\n}\n\n\n#if defined(XSAPI_CPPWINRT)\n#if TV_API\nxbox_live_result<void> multiplayer_manager::join_lobby(\n    _In_ const string_t& handleId,\n    _In_ std::vector<winrt::Windows::Xbox::System::User> users\n)\n{\n    return join_lobby(handleId, convert_user_vector_to_cppcx(users));\n}\n#endif\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/notification.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN \n#ifdef XSAPI_NOTIFICATION_SERVICE\nnotification_service::notification_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nnotification_service::~notification_service()\n{\n#ifndef XSAPI_UNIT_TESTS\n    unsubscribe_from_notifications().wait();\n#endif\n    XblContextCloseHandle(m_xblContext);\n}\n\n#if (HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID)\npplx::task<xbox_live_result<void>> notification_service::subscribe_to_notifications(\n    _In_ const string_t deviceToken\n) \n{\n    auto xblContext = m_xblContext;\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblNotificationSubscribeToNotificationsAsync(\n        xblContext, \n        &asyncWrapper->async,\n        deviceToken.c_str());\n\n    return asyncWrapper->Task(hr);\n}\n#elif HC_PLATFORM == HC_PLATFORM_WIN32 && !defined(XSAPI_UNIT_TESTS)\n\ninline invite_notification_event_args::invite_notification_event_args(_In_ const XblGameInviteNotificationEventArgs& gameInviteargs)\n    :m_gameInviteArgs(gameInviteargs)\n{\n}\n\nstring_t invite_notification_event_args::invited_xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_gameInviteArgs.invitedXboxUserId);\n}\n\nstring_t invite_notification_event_args::sender_xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_gameInviteArgs.senderXboxUserId);\n}\n\nstring_t invite_notification_event_args::sender_gamertag() const\n{\n    return Utils::StringTFromUtf8(m_gameInviteArgs.senderGamertag);\n}\n\nstring_t invite_notification_event_args::invite_handle_id() const\n{\n    return Utils::StringTFromUtf8(m_gameInviteArgs.inviteHandleId);\n}\n\nstring_t invite_notification_event_args::invite_protocol() const\n{\n    return Utils::StringTFromUtf8(m_gameInviteArgs.inviteProtocol);\n}\n\nstring_t invite_notification_event_args::invite_context() const\n{\n    return Utils::StringTFromUtf8(m_gameInviteArgs.inviteContext);\n}\n\nutility::datetime invite_notification_event_args::expiration() const\n{\n    return Utils::DatetimeFromTimeT(m_gameInviteArgs.expiration);\n}\n\nconst multiplayer::multiplayer_session_reference invite_notification_event_args::session_reference() const\n{\n    return multiplayer::multiplayer_session_reference(m_gameInviteArgs.sessionReference);\n}\n\ninline achievement_unlocked_notification_event_args::achievement_unlocked_notification_event_args(_In_ const XblAchievementUnlockEvent& achievementUnlockEvent)\n    : m_achievementUnlock(achievementUnlockEvent)\n{\n}\n\nstring_t achievement_unlocked_notification_event_args::name() const\n{\n    return Utils::StringTFromUtf8(m_achievementUnlock.achievementName);\n}\n\nstring_t achievement_unlocked_notification_event_args::id() const\n{\n    return Utils::StringTFromUtf8(m_achievementUnlock.achievementId);\n}\n\nstring_t achievement_unlocked_notification_event_args::description() const\n{\n    return Utils::StringTFromUtf8(m_achievementUnlock.achievementDescription);\n}\n\nstring_t achievement_unlocked_notification_event_args::icon_url() const\n{\n    return Utils::StringTFromUtf8(m_achievementUnlock.achievementIcon);\n}\n\nuint64_t achievement_unlocked_notification_event_args::gamerscore() const\n{\n    return m_achievementUnlock.gamerscore;\n}\n\nstring_t achievement_unlocked_notification_event_args::deeplink() const\n{\n    return Utils::StringTFromUtf8(m_achievementUnlock.deepLink);\n}\n\nstring_t achievement_unlocked_notification_event_args::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_achievementUnlock.xboxUserId);\n}\n\nutility::datetime achievement_unlocked_notification_event_args::unlockTime() const\n{\n    return Utils::DatetimeFromTimeT(m_achievementUnlock.timeUnlocked);\n}\n\nstd::function<void(invite_notification_event_args&)>& notification_service::game_invite_handler()\n{\n    return m_inviteHandler;\n}\n\nstd::function<void(achievement_unlocked_notification_event_args&)>& notification_service::achievement_unlock_handler()\n{\n    return m_achievementUnlockedHandler;\n}\n\npplx::task<xbox_live_result<void>> notification_service::subscribe_to_notifications(\n    _In_ const std::function<void(achievement_unlocked_notification_event_args&)>& achievementUnlockHandler,\n    _In_ const std::function<void(invite_notification_event_args&)>& multiplayerInviteHandler\n)\n{\n    auto xblContext = m_xblContext;\n\n    m_inviteHandler = multiplayerInviteHandler;\n    m_achievementUnlockedHandler = achievementUnlockHandler;\n\n    auto asyncWrapper = new AsyncWrapper<void>();\n    m_gameinviteFunctionContext = XblGameInviteAddNotificationHandler(\n        xblContext,\n        [](_In_ const XblGameInviteNotificationEventArgs* args, _In_opt_ void* context)\n        {\n            invite_notification_event_args resultInviteArgs(*args);\n            auto service = static_cast<notification_service*>(context);\n            service->game_invite_handler()(resultInviteArgs);\n        },\n        shared_from_this().get()\n        );\n    delete(asyncWrapper);\n\n    asyncWrapper = new AsyncWrapper<void>();\n    m_achievementUnlockFunctionContext = XblAchievementUnlockAddNotificationHandler(\n        xblContext,\n        [](_In_ const XblAchievementUnlockEvent* args, _In_opt_ void* context)\n        {\n            achievement_unlocked_notification_event_args achievementUnlockArgs(*args);\n            auto service = static_cast<notification_service*>(context);\n            service->achievement_unlock_handler()(achievementUnlockArgs);\n        },\n        shared_from_this().get()\n        );\n\n    return asyncWrapper->Task(S_OK);\n}\n#endif\n\n\n#if (HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_UWP)\npplx::task<xbox_live_result<void>> notification_service::unsubscribe_from_notifications()\n{\n    auto xblContext = m_xblContext;\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblNotificationUnsubscribeFromNotificationsAsync(xblContext, &asyncWrapper->async);\n\n    return asyncWrapper->Task(hr);\n}\n#elif HC_PLATFORM == HC_PLATFORM_WIN32 && !defined(XSAPI_UNIT_TESTS)\npplx::task<xbox_live_result<void>> notification_service::unsubscribe_from_notifications()\n{\n    XblGameInviteRemoveNotificationHandler(m_xblContext, m_gameinviteFunctionContext);\n    XblAchievementUnlockRemoveNotificationHandler(m_xblContext, m_achievementUnlockFunctionContext);\n\n    return pplx::task_from_result(xbox::services::xbox_live_result<void>());\n}\n#endif\n#endif\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/presence.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\npresence_data::presence_data(\n    _In_ string_t serviceConfigurationId,\n    _In_ string_t presenceId\n) :\n    m_serviceConfigurationId(std::move(serviceConfigurationId)),\n    m_presenceId(std::move(presenceId))\n{\n}\n\npresence_data::presence_data(\n    _In_ string_t serviceConfigurationId,\n    _In_ string_t presenceId,\n    _In_ std::vector<string_t> presenceTokenIds\n) :\n    m_serviceConfigurationId(std::move(serviceConfigurationId)),\n    m_presenceId(std::move(presenceId)),\n    m_presenceTokenIds(std::move(presenceTokenIds))\n{\n}\n\nconst string_t& presence_data::service_configuration_id() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst string_t& presence_data::presence_id() const\n{\n    return m_presenceId;\n}\n\nconst std::vector<string_t>& presence_data::presence_token_ids() const\n{\n    return m_presenceTokenIds;\n}\n\npresence_broadcast_record::presence_broadcast_record(\n    _In_ XblPresenceRecordHandle handle,\n    _In_ const XblPresenceBroadcastRecord* broadcastRecord\n) :\n    m_broadcastRecord{ broadcastRecord }\n{\n    XblPresenceRecordDuplicateHandle(handle, &m_handle);\n}\n\npresence_broadcast_record::presence_broadcast_record(\n    const presence_broadcast_record& other\n) :\n    m_broadcastRecord{ other.m_broadcastRecord }\n{\n    XblPresenceRecordDuplicateHandle(other.m_handle, &m_handle);\n}\n\npresence_broadcast_record& presence_broadcast_record::operator=(\n    presence_broadcast_record other\n)\n{\n    std::swap(m_handle, other.m_handle);\n    m_broadcastRecord = other.m_broadcastRecord;\n    return *this;\n}\n\npresence_broadcast_record::~presence_broadcast_record()\n{\n    if (m_handle)\n    {\n        XblPresenceRecordCloseHandle(m_handle);\n    }\n}\n\nstring_t presence_broadcast_record::broadcast_id() const\n{\n    if (m_broadcastRecord)\n    {\n        return Utils::StringTFromUtf8(m_broadcastRecord->broadcastId);\n    }\n    return string_t();\n}\n\nstring_t presence_broadcast_record::session() const\n{\n    if (m_broadcastRecord)\n    {\n        return Utils::StringTFromUtf8(m_broadcastRecord->session);\n    }\n    return string_t();\n}\n\nstring_t presence_broadcast_record::provider() const\n{\n    if (m_broadcastRecord)\n    {\n        switch (m_broadcastRecord->provider)\n        {\n        case XblPresenceBroadcastProvider::Twitch:\n            return _T(\"twitch\");\n        default:\n            return _T(\"unknown\");\n        }\n    }\n    return _T(\"unknown\");\n}\n\nuint32_t presence_broadcast_record::viewer_count() const\n{\n    if (m_broadcastRecord)\n    {\n        return m_broadcastRecord->viewerCount;\n    }\n    return 0;\n}\n\nutility::datetime presence_broadcast_record::start_time() const\n{\n    if (m_broadcastRecord)\n    {\n        return Utils::DatetimeFromTimeT(m_broadcastRecord->startTime);\n    }\n    return utility::datetime();\n}\n\npresence_title_record::presence_title_record(\n    _In_ XblPresenceRecordHandle handle,\n    _In_ const XblPresenceTitleRecord* titleRecord\n) :\n    m_titleRecord(titleRecord)\n{\n    XblPresenceRecordDuplicateHandle(handle, &m_handle);\n}\n\npresence_title_record::presence_title_record(\n    _In_ const presence_title_record& other\n) :\n    m_titleRecord(other.m_titleRecord)\n{\n    XblPresenceRecordDuplicateHandle(other.m_handle, &m_handle);\n}\n\npresence_title_record& presence_title_record::operator=(\n    _In_ presence_title_record other\n)\n{\n    std::swap(m_handle, other.m_handle);\n    m_titleRecord = other.m_titleRecord;\n    return *this;\n}\n\npresence_title_record::~presence_title_record()\n{\n    XblPresenceRecordCloseHandle(m_handle);\n}\n\nuint32_t presence_title_record::title_id() const\n{\n    return m_titleRecord->titleId;\n}\n\nstring_t presence_title_record::title_name() const\n{\n    return Utils::StringTFromUtf8(m_titleRecord->titleName);\n}\n\nutility::datetime presence_title_record::last_modified_date() const\n{\n    return Utils::DatetimeFromTimeT(m_titleRecord->lastModified);\n}\n\nbool presence_title_record::is_title_active() const\n{\n    return m_titleRecord->titleActive;\n}\n\nstring_t presence_title_record::presence() const\n{\n    return Utils::StringTFromUtf8(m_titleRecord->richPresenceString);\n}\n\npresence_title_view_state presence_title_record::presence_title_view() const\n{\n    return static_cast<presence_title_view_state>(m_titleRecord->viewState);\n}\n\npresence_broadcast_record presence_title_record::broadcast_record() const\n{\n    if (m_titleRecord->broadcastRecord)\n    {\n        return presence_broadcast_record(m_handle, m_titleRecord->broadcastRecord);\n    }\n    else\n    {\n        return presence_broadcast_record();\n    }\n}\n\npresence_device_record::presence_device_record(\n    _In_ XblPresenceRecordHandle handle,\n    _In_ const XblPresenceDeviceRecord* deviceRecord\n) :\n    m_deviceRecord(deviceRecord)\n{\n    XblPresenceRecordDuplicateHandle(handle, &m_handle);\n}\n\npresence_device_record::presence_device_record(\n    _In_ const presence_device_record& other\n) :\n    m_deviceRecord(other.m_deviceRecord)\n{\n    XblPresenceRecordDuplicateHandle(other.m_handle, &m_handle);\n}\n\npresence_device_record& presence_device_record::operator=(\n    _In_ presence_device_record other\n)\n{\n    std::swap(m_handle, other.m_handle);\n    m_deviceRecord = other.m_deviceRecord;\n    return *this;\n}\n\npresence_device_record::~presence_device_record()\n{\n    XblPresenceRecordCloseHandle(m_handle);\n}\n\npresence_device_type presence_device_record::device_type() const\n{\n    return static_cast<presence_device_type>(m_deviceRecord->deviceType);\n}\n\nstd::vector<presence_title_record> presence_device_record::presence_title_records() const\n{\n    return Utils::Transform<presence_title_record>(m_deviceRecord->titleRecords, m_deviceRecord->titleRecordsCount, \n        [this](const XblPresenceTitleRecord& titleRecord)\n    {\n        return presence_title_record(m_handle, &titleRecord);\n    });\n}\n\npresence_record::presence_record(\n    _In_ XblPresenceRecordHandle handle\n)\n{\n    XblPresenceRecordDuplicateHandle(handle, &m_handle);\n}\n\npresence_record::presence_record(\n    _In_ const presence_record& other\n)\n{\n    XblPresenceRecordDuplicateHandle(other.m_handle, &m_handle);\n}\n\npresence_record& presence_record::operator=(\n    presence_record other\n)\n{\n    std::swap(m_handle, other.m_handle);\n    return *this;\n}\n\npresence_record::~presence_record()\n{\n    if (m_handle)\n    {\n        XblPresenceRecordCloseHandle(m_handle);\n    }\n}\n\nstring_t presence_record::xbox_user_id() const\n{\n    uint64_t xuid;\n    XblPresenceRecordGetXuid(m_handle, &xuid);\n    return Utils::StringTFromUint64(xuid);\n}\n\nuser_presence_state presence_record::user_state() const\n{\n    XblPresenceUserState state;\n    XblPresenceRecordGetUserState(m_handle, &state);\n    return static_cast<user_presence_state>(state);\n}\n\nstd::vector<presence_device_record> presence_record::presence_device_records() const\n{\n    const XblPresenceDeviceRecord* deviceRecords{ nullptr };\n    size_t deviceRecordsCount;\n    XblPresenceRecordGetDeviceRecords(m_handle, &deviceRecords, &deviceRecordsCount);\n\n    return Utils::Transform<presence_device_record>(deviceRecords, deviceRecordsCount, \n        [this](const XblPresenceDeviceRecord& deviceRecord)\n    {\n        return presence_device_record(m_handle, &deviceRecord);\n    });\n}\n\nbool presence_record::is_user_playing_title(_In_ uint32_t titleId) const\n{\n    auto userState = user_state();\n    if (userState == user_presence_state::offline || userState == user_presence_state::unknown)\n    {\n        return false;\n    }\n\n    auto deviceRecords = presence_device_records();\n    for (const auto& deviceRecord : deviceRecords)\n    {\n        auto titleRecords = deviceRecord.presence_title_records();\n        for (const auto& titleRecord : titleRecords)\n        {\n            if (titleRecord.title_id() == titleId)\n            {\n                return titleRecord.is_title_active();\n            }\n        }\n    }\n    return false;\n}\n\ndevice_presence_change_event_args::device_presence_change_event_args(\n    _In_ uint64_t xuid,\n    _In_ XblPresenceDeviceType deviceType,\n    _In_ bool isUserLoggedOn\n) :\n    m_deviceType(deviceType),\n    m_isUserLoggedOn(isUserLoggedOn)\n{\n    m_xuid = Utils::StringTFromUint64(xuid);\n}\n\nconst string_t& device_presence_change_event_args::xbox_user_id() const\n{\n    return m_xuid;\n}\n\npresence_device_type device_presence_change_event_args::device_type() const\n{\n    return static_cast<presence_device_type>(m_deviceType);\n}\n\nbool device_presence_change_event_args::is_user_logged_on_device() const\n{\n    return m_isUserLoggedOn;\n}\n\ndevice_presence_change_subscription::device_presence_change_subscription(\n    _In_ XblRealTimeActivitySubscriptionHandle handle,\n    _In_ const string_t& xuid\n) :\n    real_time_activity_subscription(handle),\n    m_xuid(xuid)\n{\n    stringstream_t uri;\n    uri << _T(\"https://userpresence.xboxlive.com/users/xuid(\") << m_xuid << _T(\")/devices\");\n    m_resourceUri = uri.str();\n}\n\nconst string_t& device_presence_change_subscription::xbox_user_id() const\n{\n    return m_xuid;\n}\n\ntitle_presence_change_event_args::title_presence_change_event_args(\n    _In_ uint64_t xuid,\n    _In_ uint32_t titleId,\n    _In_ XblPresenceTitleState titleState\n) :\n    m_titleId(titleId),\n    m_titleState(titleState)\n{\n    m_xuid = Utils::StringTFromUint64(xuid);\n}\n\nconst string_t& title_presence_change_event_args::xbox_user_id() const\n{\n    return m_xuid;\n}\n\nuint32_t title_presence_change_event_args::title_id() const\n{\n    return m_titleId;\n}\n\ntitle_presence_state title_presence_change_event_args::title_state() const\n{\n    return static_cast<title_presence_state>(m_titleState);\n}\n\ntitle_presence_change_subscription::title_presence_change_subscription(\n    _In_ XblRealTimeActivitySubscriptionHandle handle,\n    _In_ const string_t& xuid,\n    _In_ uint32_t titleId\n) :\n    real_time_activity_subscription(handle),\n    m_xuid(xuid),\n    m_titleId(titleId)\n{\n    stringstream_t uri;\n    uri << _T(\"https://userpresence.xboxlive.com/users/xuid(\") << m_xuid << _T(\")/titles/\") << m_titleId;\n    m_resourceUri = uri.str();\n}\n\nconst string_t& title_presence_change_subscription::xbox_user_id() const\n{\n    return m_xuid;\n}\n\nuint32_t title_presence_change_subscription::title_id() const\n{\n    return m_titleId;\n}\n\npplx::task<xbox_live_result<void>> presence_service::set_presence(\n    _In_ bool isUserActiveInTitle\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>();\n\n    auto hr = XblPresenceSetPresenceAsync(\n        m_xblContextHandle,\n        isUserActiveInTitle,\n        nullptr,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<void>> presence_service::set_presence(\n    _In_ bool isUserActiveInTitle,\n    _In_ presence_data presenceData\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>();\n\n    XblPresenceRichPresenceIds ids{};\n    Utils::Utf8FromCharT(presenceData.service_configuration_id().data(), ids.scid, sizeof(ids.scid));\n\n    std::string presenceId = Utils::StringFromStringT(presenceData.presence_id());\n    ids.presenceId = presenceId.data();\n\n    UTF8StringArrayRef presenceTokenIds{ presenceData.presence_token_ids() };\n    ids.presenceTokenIds = presenceTokenIds.Data();\n    ids.presenceTokenIdsCount = presenceTokenIds.Size();\n\n\n    auto hr = XblPresenceSetPresenceAsync(\n        m_xblContextHandle,\n        isUserActiveInTitle,\n        &ids,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<presence_record>> presence_service::get_presence(\n    _In_ const string_t& xboxUserId\n)\n{\n    auto asyncWrapper = new AsyncWrapper<presence_record>(\n        [](XAsyncBlock* async, presence_record& presenceRecord)\n    {\n        XblPresenceRecordHandle handle;\n        auto hr = XblPresenceGetPresenceResult(async, &handle);\n        if (SUCCEEDED(hr))\n        {\n            presenceRecord = presence_record(handle);\n            XblPresenceRecordCloseHandle(handle);\n        }\n        return hr;\n    });\n\n    auto hr = XblPresenceGetPresenceAsync(\n        m_xblContextHandle,\n        Utils::Uint64FromStringT(xboxUserId),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<presence_record>>> presence_service::get_presence_for_multiple_users(\n    _In_ const std::vector<string_t>& xboxUserIds\n)\n{\n    return get_presence_for_multiple_users(\n        xboxUserIds,\n        {},\n        {},\n        presence_detail_level::default_level,\n        false,\n        false\n    );\n}\n\npplx::task<xbox_live_result<std::vector<presence_record>>> presence_service::get_presence_for_multiple_users(\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ const std::vector<presence_device_type>& deviceTypes,\n    _In_ const std::vector<uint32_t>& titleIds,\n    _In_ presence_detail_level presenceDetailLevel,\n    _In_ bool onlineOnly,\n    _In_ bool broadcastingOnly\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<presence_record>>(\n        [](XAsyncBlock* async, std::vector<presence_record>& presenceRecords)\n    {\n        size_t resultCount;\n        auto hr = XblPresenceGetPresenceForMultipleUsersResultCount(async, &resultCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<XblPresenceRecordHandle> recordHandles(resultCount);\n            hr = XblPresenceGetPresenceForMultipleUsersResult(async, recordHandles.data(), resultCount);\n\n            if (SUCCEEDED(hr))\n            {\n                presenceRecords = Utils::Transform<presence_record>(recordHandles, [](XblPresenceRecordHandle recordHandle)\n                {\n                    presence_record record(recordHandle);\n                    XblPresenceRecordCloseHandle(recordHandle);\n                    return record;\n                });\n            }\n        }\n        return hr;\n    });\n\n    XblPresenceQueryFilters filters{};\n    if (!deviceTypes.empty())\n    {\n        filters.deviceTypes = (XblPresenceDeviceType*)(deviceTypes.data());\n        filters.deviceTypesCount = deviceTypes.size();\n    }\n    if (!titleIds.empty())\n    {\n        filters.titleIds = titleIds.data();\n        filters.titleIdsCount = titleIds.size();\n    }\n    filters.detailLevel = static_cast<XblPresenceDetailLevel>(presenceDetailLevel);\n    filters.broadcastingOnly = broadcastingOnly;\n    filters.onlineOnly = onlineOnly;\n\n    auto xuids = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n\n    auto hr = XblPresenceGetPresenceForMultipleUsersAsync(\n        m_xblContextHandle,\n        xuids.data(),\n        xuids.size(),\n        &filters,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<presence_record>>> presence_service::get_presence_for_social_group(\n    _In_ const string_t& socialGroup\n)\n{\n    return get_presence_for_social_group(\n        socialGroup,\n        string_t(),\n        {},\n        {},\n        presence_detail_level::default_level,\n        false,\n        false\n    );\n}\n\npplx::task<xbox_live_result<std::vector<presence_record>>> presence_service::get_presence_for_social_group(\n    _In_ const string_t& socialGroup,\n    _In_ const string_t& socialGroupOwnerXboxUserId,\n    _In_ const std::vector<presence_device_type>& deviceTypes,\n    _In_ const std::vector<uint32_t>& titleIds,\n    _In_ presence_detail_level peoplehubDetailLevel,\n    _In_ bool onlineOnly,\n    _In_ bool broadcastingOnly\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<presence_record>>(\n        [](XAsyncBlock* async, std::vector<presence_record>& presenceRecords)\n    {\n        size_t resultCount;\n        auto hr = XblPresenceGetPresenceForSocialGroupResultCount(async, &resultCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<XblPresenceRecordHandle> recordHandles(resultCount);\n            hr = XblPresenceGetPresenceForSocialGroupResult(async, recordHandles.data(), resultCount);\n\n            if (SUCCEEDED(hr))\n            {\n                presenceRecords = Utils::Transform<presence_record>(recordHandles, [](XblPresenceRecordHandle recordHandle)\n                {\n                    presence_record record(recordHandle);\n                    XblPresenceRecordCloseHandle(recordHandle);\n                    return record;\n                });\n            }\n        }\n        return hr;\n    });\n\n    XblPresenceQueryFilters filters{};\n    if (!deviceTypes.empty())\n    {\n        filters.deviceTypes = (XblPresenceDeviceType*)(deviceTypes.data());\n        filters.deviceTypesCount = deviceTypes.size();\n    }\n    if (!titleIds.empty())\n    {\n        filters.titleIds = titleIds.data();\n        filters.titleIdsCount = titleIds.size();\n    }\n    filters.detailLevel = static_cast<XblPresenceDetailLevel>(peoplehubDetailLevel);\n    filters.broadcastingOnly = broadcastingOnly;\n    filters.onlineOnly = onlineOnly;\n\n    uint64_t groupOwnerXuid = 0;\n    if (!socialGroupOwnerXboxUserId.empty())\n    {\n        groupOwnerXuid = Utils::Uint64FromStringT(socialGroupOwnerXboxUserId);\n    }\n\n    auto hr = XblPresenceGetPresenceForSocialGroupAsync(\n        m_xblContextHandle,\n        Utils::StringFromStringT(socialGroup).data(),\n        groupOwnerXuid ? &groupOwnerXuid : nullptr,\n        &filters,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nxbox_live_result<std::shared_ptr<device_presence_change_subscription>> presence_service::subscribe_to_device_presence_change(\n    _In_ const string_t& xboxUserId\n)\n{\n    XblRealTimeActivitySubscriptionHandle subHandle{};\n    auto hr = XblPresenceSubscribeToDevicePresenceChange(\n        m_xblContextHandle,\n        Utils::Uint64FromStringT(xboxUserId),\n        &subHandle\n    );\n\n    if (FAILED(hr))\n    {\n        return xbox_live_result<std::shared_ptr<device_presence_change_subscription>>(Utils::ConvertHr(hr));\n    }\n    return xbox_live_result<std::shared_ptr<device_presence_change_subscription>>(std::make_shared<device_presence_change_subscription>(subHandle, xboxUserId));\n}\n\nxbox_live_result<void> presence_service::unsubscribe_from_device_presence_change(\n    _In_ std::shared_ptr<device_presence_change_subscription> subscription\n)\n{\n    return Utils::ConvertHr(XblPresenceUnsubscribeFromDevicePresenceChange(m_xblContextHandle, subscription->m_handle));\n}\n\nxbox_live_result<std::shared_ptr<title_presence_change_subscription>> presence_service::subscribe_to_title_presence_change(\n    _In_ const string_t& xboxUserId,\n    _In_ uint32_t titleId\n)\n{\n    XblRealTimeActivitySubscriptionHandle subHandle{};\n    auto hr = XblPresenceSubscribeToTitlePresenceChange(\n        m_xblContextHandle,\n        Utils::Uint64FromStringT(xboxUserId),\n        titleId,\n        &subHandle\n    );\n\n    if (FAILED(hr))\n    {\n        return xbox_live_result<std::shared_ptr<title_presence_change_subscription>>(Utils::ConvertHr(hr));\n    }\n    return xbox_live_result<std::shared_ptr<title_presence_change_subscription>>(std::make_shared<title_presence_change_subscription>(subHandle, xboxUserId, titleId));\n}\n\nxbox_live_result<void> presence_service::unsubscribe_from_title_presence_change(\n    _In_ std::shared_ptr<title_presence_change_subscription> subscription\n)\n{\n    return Utils::ConvertHr(XblPresenceUnsubscribeFromTitlePresenceChange(m_xblContextHandle, subscription->m_handle));\n}\n\nstruct presence_service::HandlerContext\n{\n    XblFunctionContext internalContext;\n    std::function<void(const device_presence_change_event_args&)> devicePresenceChangedHandler;\n    std::function<void(const title_presence_change_event_args&)> titlePresenceChangedHandler;\n};\n\nfunction_context presence_service::add_device_presence_changed_handler(\n    _In_ std::function<void(const device_presence_change_event_args&)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->devicePresenceChangedHandler = std::move(handler);\n\n    context->internalContext = XblPresenceAddDevicePresenceChangedHandler(m_xblContextHandle,\n        [](void* context, uint64_t xuid, XblPresenceDeviceType deviceType, bool isUserLoggedOnDevice)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->devicePresenceChangedHandler(device_presence_change_event_args{ xuid, deviceType, isUserLoggedOnDevice });\n    }, context);\n\n    return context;\n}\n\nvoid presence_service::remove_device_presence_changed_handler(\n    _In_ function_context context\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblPresenceRemoveDevicePresenceChangedHandler(m_xblContextHandle, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nfunction_context presence_service::add_title_presence_changed_handler(\n    _In_ std::function<void(const title_presence_change_event_args&)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->titlePresenceChangedHandler = std::move(handler);\n\n    context->internalContext = XblPresenceAddTitlePresenceChangedHandler(m_xblContextHandle,\n        [](void* context, uint64_t xuid, uint32_t titleId, XblPresenceTitleState titleState)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->titlePresenceChangedHandler(title_presence_change_event_args{ xuid, titleId, titleState });\n    }, context);\n\n    return context;\n}\n\nvoid presence_service::remove_title_presence_changed_handler(\n    _In_ function_context context\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblPresenceRemoveTitlePresenceChangedHandler(m_xblContextHandle, handlerContext->internalContext);\n    delete handlerContext;\n}\n\npresence_service::presence_service(XblContextHandle xblContextHandle)\n{\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n}\n\npresence_service::presence_service(const presence_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContextHandle, &m_xblContextHandle);\n}\n\npresence_service& presence_service::operator=(presence_service other)\n{\n    std::swap(m_xblContextHandle, other.m_xblContextHandle);\n    return *this;\n}\n\npresence_service::~presence_service()\n{\n    XblContextCloseHandle(m_xblContextHandle);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END\n\nXBL_WARNING_POP"
  },
  {
    "path": "Include/xsapi-cpp/impl/privacy.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_BEGIN\n\npermission_deny_reason::permission_deny_reason(\n    const XblPermissionDenyReasonDetails& reasonDetails\n)\n    : m_reasonDetails(reasonDetails)\n{\n}\n\nstring_t permission_deny_reason::reason() const\n{\n    static const std::unordered_map<uint32_t, string_t> reasonsMap =\n    {\n        { static_cast<uint32_t>(XblPermissionDenyReason::Unknown), _T(\"Unknown\") },\n        { static_cast<uint32_t>(XblPermissionDenyReason::NotAllowed), _T(\"NotAllowed\") },\n        { static_cast<uint32_t>(XblPermissionDenyReason::MissingPrivilege), _T(\"MissingPrivilege\") },\n        { static_cast<uint32_t>(XblPermissionDenyReason::PrivilegeRestrictsTarget), _T(\"PrivilegeRestrictsTarget\") },\n        { static_cast<uint32_t>(XblPermissionDenyReason::BlockListRestrictsTarget), _T(\"BlockListRestrictsTarget\") },\n        { static_cast<uint32_t>(XblPermissionDenyReason::MuteListRestrictsTarget), _T(\"MuteListRestrictsTarget\") },\n        { static_cast<uint32_t>(XblPermissionDenyReason::PrivacySettingRestrictsTarget), _T(\"PrivacySettingRestrictsTarget\") }\n    };\n    return reasonsMap.at(static_cast<uint32_t>(m_reasonDetails.reason));\n}\n\nstring_t permission_deny_reason::restricted_setting() const\n{\n    static const std::unordered_map<uint32_t, string_t> settingsMap =\n    {\n        // Privacy settings\n        { static_cast<uint32_t>(XblPrivacySetting::ShareFriendList), _T(\"ShareFriendList\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareGameHistory), _T(\"ShareGameHistory\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CommunicateUsingTextAndVoice), _T(\"CommunicateUsingTextAndVoice\") },\n        { static_cast<uint32_t>(XblPrivacySetting::SharePresence), _T(\"SharePresence\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareProfile), _T(\"ShareProfile\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareVideoAndMusicStatus), _T(\"ShareVideoAndMusicStatus\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CommunicateUsingVideo), _T(\"CommunicateUsingVideo\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CollectVoiceData), _T(\"CollectVoiceData\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareXboxMusicActivity), _T(\"ShareXboxMusicActivity\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareExerciseInfo), _T(\"ShareExerciseInfo\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareIdentity), _T(\"ShareIdentity\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareIdentityInGame), _T(\"ShareIdentityInGame\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareRecordedGameSessions), _T(\"ShareRecordedGameSessions\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CollectLiveTvData), _T(\"CollectLiveTvData\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CollectXboxVideoData), _T(\"CollectXboxVideoData\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareIdentityTransitively), _T(\"ShareIdentityTransitively\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareVideoHistory), _T(\"ShareVideoHistory\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareMusicHistory), _T(\"ShareMusicHistory\") },\n        { static_cast<uint32_t>(XblPrivacySetting::AllowUserCreatedContentViewing), _T(\"AllowUserCreatedContentViewing\") },\n        { static_cast<uint32_t>(XblPrivacySetting::AllowProfileViewing), _T(\"AllowProfileViewing\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShowRealTimeActivity), _T(\"ShowRealTimeActivity\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CollectVoiceDataXboxOneFull), _T(\"CollectVoiceDataXboxOneFull\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CanShareIdentity), _T(\"CanShareIdentity\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareContentToExternalNetworks), _T(\"ShareContentToExternalNetworks\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CollectVoiceSearchData), _T(\"CollectVoiceSearchData\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareClubMembership), _T(\"ShareClubMembership\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CollectVoiceGameChatData), _T(\"CollectVoiceGameChatData\") },\n        { static_cast<uint32_t>(XblPrivacySetting::ShareActivityFeed), _T(\"ShareActivityFeed\") },\n        { static_cast<uint32_t>(XblPrivacySetting::CommunicateDuringCrossNetworkPlay), _T(\"CommunicateDuringCrossNetworkPlay\") },\n    };\n\n    auto iter = settingsMap.find(static_cast<uint32_t>(m_reasonDetails.restrictedPrivacySetting));\n    if (iter != settingsMap.end())\n    {\n        return iter->second;\n    }\n\n    static const std::unordered_map<uint32_t, string_t> privMap =\n    {\n        // Permissions\n        { static_cast<uint32_t>(XblPrivilege::AllowIngameVoiceCommunications), _T(\"AllowIngameVoiceCommunications\") },\n        { static_cast<uint32_t>(XblPrivilege::AllowVideoCommunications), _T(\"PrivilegeVideoCommunications\") },\n        { static_cast<uint32_t>(XblPrivilege::AllowProfileViewing), _T(\"AllowProfileViewing\") },\n        { static_cast<uint32_t>(XblPrivilege::AllowCommunications), _T(\"AllowCommunications\") },\n        { static_cast<uint32_t>(XblPrivilege::AllowMultiplayer), _T(\"AllowMultiplayer\") },\n        { static_cast<uint32_t>(XblPrivilege::AllowAddFriend), _T(\"AllowAddFriend\") }\n    };\n\n    auto iter2 = privMap.find(static_cast<uint32_t>(m_reasonDetails.restrictedPrivacySetting));\n    if (iter2 != privMap.end())\n    {\n        return iter2->second;\n    }\n\n    return string_t();\n}\n\npermission_check_result::permission_check_result(\n    const XblPermissionCheckResult* result\n)\n    : m_result(*result)\n{\n    for (auto i = 0u; i < m_result.reasonsCount; ++i)\n    {\n        m_reasons.push_back(permission_deny_reason(m_result.reasons[i]));\n    }\n}\n\nbool permission_check_result::is_allowed() const\n{\n    return m_result.isAllowed;\n}\n\nstring_t permission_check_result::permission_requested() const\n{\n    static const std::unordered_map<uint32_t, string_t> permissionsMap =\n    {\n        { static_cast<uint32_t>(XblPermission::CommunicateUsingText), permission_id_constants::communicate_using_text() },\n        { static_cast<uint32_t>(XblPermission::CommunicateUsingVideo), permission_id_constants::communicate_using_video() },\n        { static_cast<uint32_t>(XblPermission::CommunicateUsingVoice), permission_id_constants::communicate_using_voice() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetProfile), permission_id_constants::view_target_profile() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetGameHistory), permission_id_constants::view_target_game_history() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetVideoHistory), permission_id_constants::view_target_video_history() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetMusicHistory), permission_id_constants::view_target_music_history() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetExerciseInfo), permission_id_constants::view_target_exercise_info() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetPresence), permission_id_constants::view_target_presence() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetVideoStatus), permission_id_constants::view_target_video_status() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetMusicStatus), permission_id_constants::view_target_music_status() },\n        { static_cast<uint32_t>(XblPermission::PlayMultiplayer), permission_id_constants::play_multiplayer() },\n        { static_cast<uint32_t>(XblPermission::ViewTargetUserCreatedContent), permission_id_constants::view_target_user_created_content() },\n        { static_cast<uint32_t>(XblPermission::BroadcastWithTwitch), permission_id_constants::broadcast_with_twitch() }\n    };\n    return permissionsMap.at(static_cast<uint32_t>(m_result.permissionRequested));\n}\n\nconst std::vector<permission_deny_reason>& permission_check_result::deny_reasons() const\n{\n    return m_reasons;\n}\n\ninline XblAnonymousUserType AnonymousUserTypeFromString(\n    const string_t& anonymousUserTypeString\n)\n{\n    static const std::unordered_map<string_t, XblAnonymousUserType> anonymousUserTypes\n    {\n        { anonymous_user_type_constants::cross_network_user(), XblAnonymousUserType::CrossNetworkUser },\n        { anonymous_user_type_constants::crost_network_friend(), XblAnonymousUserType::CrossNetworkFriend }\n    };\n\n    auto iter = anonymousUserTypes.find(anonymousUserTypeString);\n    if (iter != anonymousUserTypes.end())\n    {\n        return iter->second;\n    }\n    return XblAnonymousUserType::Unknown;\n}\n\nmultiple_permissions_check_result::multiple_permissions_check_result(\n    const XblPermissionCheckResult* results,\n    size_t resultCount,\n    string_t target\n) :\n    m_target{ std::move(target) }\n{\n    for (auto i = 0u; i < resultCount; ++i)\n    {\n        XblAnonymousUserType anonymousUserType{ AnonymousUserTypeFromString(m_target) };\n\n        if ((anonymousUserType != XblAnonymousUserType::Unknown && results[i].targetUserType == anonymousUserType) ||\n            results[i].targetXuid == Utils::Uint64FromStringT(m_target))\n        {\n            m_items.push_back(permission_check_result(results + i));\n        }\n    }\n}\n\nconst string_t& multiple_permissions_check_result::xbox_user_id() const\n{\n    return m_target;\n}\n\nconst std::vector<permission_check_result>& multiple_permissions_check_result::items() const\n{\n    return m_items;\n}\n\nprivacy_service::privacy_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nprivacy_service::privacy_service(const privacy_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nprivacy_service& privacy_service::operator=(privacy_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nprivacy_service::~privacy_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\npplx::task<xbox_live_result<std::vector<string_t>>> privacy_service::get_avoid_list()\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<string_t>>(\n        [](XAsyncBlock* async, std::vector<string_t>& result)\n    {\n        size_t xuidCount;\n        auto hr = XblPrivacyGetAvoidListResultCount(async, &xuidCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<uint64_t> xuids(xuidCount);\n            hr = XblPrivacyGetAvoidListResult(async, xuidCount, xuids.data());\n            for (auto& xuid : xuids)\n            {\n                result.push_back(Utils::StringTFromUint64(xuid));\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblPrivacyGetAvoidListAsync(m_xblContext, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\ninline XblPermission XblPermissionFromString(const string_t& permission)\n{\n    static const std::unordered_map<string_t, uint32_t> map =\n    {\n        { permission_id_constants::communicate_using_text(), static_cast<uint32_t>(XblPermission::CommunicateUsingText) },\n        { permission_id_constants::communicate_using_video(), static_cast<uint32_t>(XblPermission::CommunicateUsingVideo) },\n        { permission_id_constants::communicate_using_voice(), static_cast<uint32_t>(XblPermission::CommunicateUsingVoice) },\n        { permission_id_constants::view_target_profile(), static_cast<uint32_t>(XblPermission::ViewTargetProfile) },\n        { permission_id_constants::view_target_game_history(), static_cast<uint32_t>(XblPermission::ViewTargetGameHistory) },\n        { permission_id_constants::view_target_video_history(), static_cast<uint32_t>(XblPermission::ViewTargetVideoHistory) },\n        { permission_id_constants::view_target_music_history(), static_cast<uint32_t>(XblPermission::ViewTargetMusicHistory) },\n        { permission_id_constants::view_target_exercise_info(), static_cast<uint32_t>(XblPermission::ViewTargetExerciseInfo) },\n        { permission_id_constants::view_target_presence(), static_cast<uint32_t>(XblPermission::ViewTargetPresence) },\n        { permission_id_constants::view_target_video_status(), static_cast<uint32_t>(XblPermission::ViewTargetVideoStatus) },\n        { permission_id_constants::view_target_music_status(), static_cast<uint32_t>(XblPermission::ViewTargetMusicStatus) },\n        { permission_id_constants::play_multiplayer(), static_cast<uint32_t>(XblPermission::PlayMultiplayer) },\n        { permission_id_constants::view_target_user_created_content(), static_cast<uint32_t>(XblPermission::ViewTargetUserCreatedContent) },\n        { permission_id_constants::broadcast_with_twitch(), static_cast<uint32_t>(XblPermission::BroadcastWithTwitch) }\n    };\n\n    auto iter = map.find(permission);\n    if (iter == map.end())\n    {\n        return XblPermission::Unknown;\n    }\n    return static_cast<XblPermission>(iter->second);\n}\n\npplx::task<xbox_live_result<permission_check_result>> privacy_service::check_permission_with_target_user(\n    _In_ const string_t& permissionId,\n    _In_ const string_t& target\n)\n{\n    auto permission = XblPermissionFromString(permissionId);\n    if (permission == XblPermission::Unknown || target.empty())\n    {\n        return pplx::task_from_result(xbox_live_result<permission_check_result>(std::make_error_code(xbox_live_error_code::invalid_argument)));\n    }\n\n    auto asyncWrapper = new AsyncWrapper<permission_check_result>(\n        [](XAsyncBlock* async, permission_check_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblPrivacyCheckPermissionResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            auto buffer = new char[bufferSize];\n            XblPermissionCheckResult* resultPtr;\n            hr = XblPrivacyCheckPermissionResult(async, bufferSize, buffer, &resultPtr, nullptr);\n\n            result = permission_check_result(resultPtr);\n            delete[] buffer;\n        }\n        return hr;\n    });\n\n    HRESULT hr{ S_OK };\n\n    XblAnonymousUserType anonymousUserType{ AnonymousUserTypeFromString(target) };\n    if (anonymousUserType != XblAnonymousUserType::Unknown)\n    {\n        hr = XblPrivacyCheckPermissionForAnonymousUserAsync(\n            m_xblContext,\n            permission,\n            anonymousUserType,\n            &asyncWrapper->async\n        );\n    }\n    else\n    {\n        hr = XblPrivacyCheckPermissionAsync(\n            m_xblContext,\n            permission,\n            Utils::Uint64FromStringT(target),\n            &asyncWrapper->async\n        );\n    }\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<multiple_permissions_check_result>>> privacy_service::check_multiple_permissions_with_multiple_target_users(\n    _In_ const std::vector<string_t>& permissionIds,\n    _In_ const std::vector<string_t>& targets\n)\n{\n    std::vector<uint64_t> xuids{};\n    std::vector<XblAnonymousUserType> userTypes{};\n\n    for (auto& target : targets)\n    {\n        XblAnonymousUserType anonymousUserType{ AnonymousUserTypeFromString(target) };\n        if (anonymousUserType == XblAnonymousUserType::Unknown)\n        {\n            xuids.push_back(Utils::Uint64FromStringT(target));\n        }\n        else\n        {\n            userTypes.push_back(anonymousUserType);\n        }\n    }\n\n    auto asyncWrapper = new AsyncWrapper<std::vector<multiple_permissions_check_result>>(\n        [targets](XAsyncBlock* async, std::vector<multiple_permissions_check_result>& results)\n    {\n        size_t bufferSize;\n        auto hr = XblPrivacyBatchCheckPermissionResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            auto buffer = new char[bufferSize];\n            XblPermissionCheckResult* resultPtr;\n            size_t resultCount;\n            hr = XblPrivacyBatchCheckPermissionResult(async, bufferSize, buffer, &resultPtr, &resultCount, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                for (auto& target : targets)\n                {\n                    results.push_back(multiple_permissions_check_result(resultPtr, resultCount, target));\n                }\n            }\n            delete[] buffer;\n        }\n        return hr;\n    });\n\n    auto hr = XblPrivacyBatchCheckPermissionAsync(\n        m_xblContext,\n        Utils::Transform<XblPermission>(permissionIds, XblPermissionFromString).data(),\n        permissionIds.size(),\n        xuids.data(),\n        xuids.size(),\n        userTypes.data(),\n        userTypes.size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<string_t>>> privacy_service::get_mute_list()\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<string_t>>(\n        [](XAsyncBlock* async, std::vector<string_t>& result)\n    {\n        size_t xuidCount;\n        auto hr = XblPrivacyGetMuteListResultCount(async, &xuidCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<uint64_t> xuids(xuidCount);\n            hr = XblPrivacyGetMuteListResult(async, xuidCount, xuids.data());\n            for (auto& xuid : xuids)\n            {\n                result.push_back(Utils::StringTFromUint64(xuid));\n            }\n        }\n        return hr;\n    });\n\n    auto hr = XblPrivacyGetMuteListAsync(m_xblContext, &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<string_t>>> privacy_service::get_avoid_or_mute_list(\n    _In_ const string_t& subPathName\n)\n{\n    if (Utils::Stricmp(subPathName, _T(\"mute\")) == 0)\n    {\n        return get_mute_list();\n    }\n    else if (Utils::Stricmp(subPathName, _T(\"avoid\")) == 0)\n    {\n        return get_avoid_list();\n    }\n    return pplx::task_from_result(xbox_live_result<std::vector<string_t>>(std::make_error_code(xbox_live_error_code::invalid_argument)));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_END\n"
  },
  {
    "path": "Include/xsapi-cpp/impl/profile.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nxbox_user_profile::xbox_user_profile(\n    const XblUserProfile& profile\n) :\n    m_profile{ profile }\n{\n}\n\nstring_t xbox_user_profile::app_display_name() const\n{\n    return Utils::StringTFromUtf8(m_profile.appDisplayName);\n}\n\nweb::uri xbox_user_profile::app_display_picture_resize_uri() const\n{\n    return web::uri{ Utils::StringTFromUtf8(m_profile.appDisplayPictureResizeUri) };\n}\n\nstring_t xbox_user_profile::game_display_name() const\n{\n    return Utils::StringTFromUtf8(m_profile.gameDisplayName);\n}\n\nweb::uri xbox_user_profile::game_display_picture_resize_uri() const\n{\n    return web::uri{ Utils::StringTFromUtf8(m_profile.gameDisplayPictureResizeUri) };\n}\n\nstring_t xbox_user_profile::gamerscore() const\n{\n    return Utils::StringTFromUtf8(m_profile.gamerscore);\n}\n\nstring_t xbox_user_profile::gamertag() const\n{\n    return Utils::StringTFromUtf8(m_profile.gamertag);\n}\n\nstring_t xbox_user_profile::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_profile.xboxUserId);\n}\n\nprofile_service::profile_service(XblContextHandle xblContextHandle)\n{\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n}\n\nprofile_service::profile_service(const profile_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContextHandle, &m_xblContextHandle);\n}\n\nprofile_service& profile_service::operator=(profile_service other)\n{\n    std::swap(m_xblContextHandle, other.m_xblContextHandle);\n    return *this;\n}\n\nprofile_service::~profile_service()\n{\n    XblContextCloseHandle(m_xblContextHandle);\n}\n\npplx::task<xbox::services::xbox_live_result<xbox_user_profile>> profile_service::get_user_profile(\n    _In_ string_t xboxUserId\n)\n{\n    auto asyncWrapper = new AsyncWrapper<xbox_user_profile>{\n        [](XAsyncBlock* async, xbox_user_profile& result)\n    {\n        XblUserProfile profile{};\n        auto hr = XblProfileGetUserProfileResult(async, &profile);\n        if (SUCCEEDED(hr))\n        {\n            result = xbox_user_profile{ profile };\n        }\n        return hr;\n    }\n    };\n\n    auto hr = XblProfileGetUserProfileAsync(m_xblContextHandle, Utils::Uint64FromStringT(std::move(xboxUserId)), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox::services::xbox_live_result<std::vector<xbox_user_profile>>> profile_service::get_user_profiles(\n    _In_ const std::vector<string_t>& xboxUserIds\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<xbox_user_profile>>{\n        [](XAsyncBlock* async, std::vector<xbox_user_profile>& result)\n    {\n        size_t resultCount{ 0 };\n        auto hr = XblProfileGetUserProfilesResultCount(async, &resultCount);\n        if (SUCCEEDED(hr))\n        {\n            auto profiles = new XblUserProfile[resultCount];\n            hr = XblProfileGetUserProfilesResult(async, resultCount, profiles);\n            if (SUCCEEDED(hr))\n            {\n                for (size_t i = 0; i < resultCount; ++i)\n                {\n                    result.push_back(profiles[i]);\n                }\n            }\n            delete[] profiles;\n        }\n        return hr;\n    }\n    };\n\n    auto xuids{ Utils::Transform<uint64_t>(xboxUserIds, Utils::Uint64FromStringT) };\n\n    auto hr = XblProfileGetUserProfilesAsync(m_xblContextHandle, xuids.data(), xuids.size(), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox::services::xbox_live_result< std::vector< xbox_user_profile>>> profile_service::get_user_profiles_for_social_group(\n    _In_ const string_t& socialGroup\n)\n{\n    auto asyncWrapper = new AsyncWrapper<std::vector<xbox_user_profile>>{\n        [](XAsyncBlock* async, std::vector<xbox_user_profile>& result)\n    {\n        size_t resultCount{ 0 };\n        auto hr = XblProfileGetUserProfilesForSocialGroupResultCount(async, &resultCount);\n        if (SUCCEEDED(hr))\n        {\n            auto profiles = new XblUserProfile[resultCount];\n            hr = XblProfileGetUserProfilesForSocialGroupResult(async, resultCount, profiles);\n            if (SUCCEEDED(hr))\n            {\n                for (size_t i = 0; i < resultCount; ++i)\n                {\n                    result.push_back(profiles[i]);\n                }\n            }\n            delete[] profiles;\n        }\n        return hr;\n    }\n    };\n\n    auto hr = XblProfileGetUserProfilesForSocialGroupAsync(m_xblContextHandle, Utils::StringFromStringT(socialGroup).data(), &asyncWrapper->async);\n    return asyncWrapper->Task(hr);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/public_utils.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"cpprest/json.h\"\n#include \"xsapi-c/types_c.h\"\n#include \"xsapi-cpp/errors.h\"\n\n#if !XSAPI_XAL_AUTH && HC_PLATFORM != HC_PLATFORM_XDK\n#include \"xsapi-cpp/types.h\"\n#endif\n\n#ifndef MAKE_HTTP_HRESULT\n#define MAKE_HTTP_HRESULT(code) MAKE_HRESULT(1, 0x019, code)\n#endif\n\nnamespace xbox { namespace services {\n\nstruct Utils\n{\n    static xbox_live_error_code ConvertHrToXblErrorCode(HRESULT hr)\n    {\n        switch (hr)\n        {\n        case S_OK: return xbox_live_error_code::no_error;\n        case E_OUTOFMEMORY: return xbox_live_error_code::bad_alloc;\n        case E_INVALIDARG: return xbox_live_error_code::invalid_argument;\n        case E_XBL_RUNTIME_ERROR: return xbox_live_error_code::runtime_error;\n        case __HRESULT_FROM_WIN32(ERROR_BAD_LENGTH): return xbox_live_error_code::length_error;\n        case E_BOUNDS: return xbox_live_error_code::out_of_range;\n\n        case E_NOINTERFACE: return xbox_live_error_code::bad_cast;\n        case E_UNEXPECTED: return xbox_live_error_code::logic_error;\n        case WEB_E_INVALID_JSON_STRING: return xbox_live_error_code::json_error;\n        case WEB_E_UNEXPECTED_CONTENT: return xbox_live_error_code::uri_error;\n        case ONL_E_ACTION_REQUIRED: return xbox_live_error_code::auth_user_interaction_required;\n        case E_XBL_RTA_GENERIC_ERROR: return xbox_live_error_code::rta_generic_error;\n        case E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED: return xbox_live_error_code::rta_subscription_limit_reached;\n        case E_XBL_RTA_ACCESS_DENIED: return xbox_live_error_code::rta_access_denied;\n        case E_XBL_RTA_NOT_ACTIVATED: return xbox_live_error_code::rta_not_activated;\n        case E_XBL_AUTH_UNKNOWN_ERROR: return xbox_live_error_code::auth_unknown_error;\n        case E_XBL_AUTH_RUNTIME_ERROR: return xbox_live_error_code::auth_runtime_error;\n        case E_XBL_AUTH_NO_TOKEN: return xbox_live_error_code::auth_no_token_error;\n        case __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER): return xbox_live_error_code::auth_user_not_signed_in;\n        case __HRESULT_FROM_WIN32(ERROR_CANCELLED): return xbox_live_error_code::auth_user_cancel;\n        case __HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION): return xbox_live_error_code::invalid_config;\n        case E_NOTIMPL: return xbox_live_error_code::unsupported;\n\n            // HTTP errors\n        case __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND): return xbox_live_error_code::http_status_204_resource_data_not_found;\n        case HTTP_E_STATUS_AMBIGUOUS: return xbox_live_error_code::http_status_300_multiple_choices;\n        case HTTP_E_STATUS_MOVED: return xbox_live_error_code::http_status_301_moved_permanently;\n        case HTTP_E_STATUS_REDIRECT: return xbox_live_error_code::http_status_302_found;\n        case HTTP_E_STATUS_REDIRECT_METHOD: return xbox_live_error_code::http_status_303_see_other;\n        case HTTP_E_STATUS_NOT_MODIFIED: return xbox_live_error_code::http_status_304_not_modified;\n        case HTTP_E_STATUS_USE_PROXY: return xbox_live_error_code::http_status_305_use_proxy;\n        case HTTP_E_STATUS_REDIRECT_KEEP_VERB: return xbox_live_error_code::http_status_307_temporary_redirect;\n\n        case HTTP_E_STATUS_BAD_REQUEST: return xbox_live_error_code::http_status_400_bad_request;\n        case HTTP_E_STATUS_DENIED: return xbox_live_error_code::http_status_401_unauthorized;\n        case HTTP_E_STATUS_PAYMENT_REQ: return xbox_live_error_code::http_status_402_payment_required;\n        case HTTP_E_STATUS_FORBIDDEN: return xbox_live_error_code::http_status_403_forbidden;\n        case HTTP_E_STATUS_NOT_FOUND: return xbox_live_error_code::http_status_404_not_found;\n        case HTTP_E_STATUS_BAD_METHOD: return xbox_live_error_code::http_status_405_method_not_allowed;\n        case HTTP_E_STATUS_NONE_ACCEPTABLE: return xbox_live_error_code::http_status_406_not_acceptable;\n        case HTTP_E_STATUS_PROXY_AUTH_REQ: return xbox_live_error_code::http_status_407_proxy_authentication_required;\n        case HTTP_E_STATUS_REQUEST_TIMEOUT: return xbox_live_error_code::http_status_408_request_timeout;\n        case HTTP_E_STATUS_CONFLICT: return xbox_live_error_code::http_status_409_conflict;\n        case HTTP_E_STATUS_GONE: return xbox_live_error_code::http_status_410_gone;\n        case HTTP_E_STATUS_LENGTH_REQUIRED: return xbox_live_error_code::http_status_411_length_required;\n        case HTTP_E_STATUS_PRECOND_FAILED: return xbox_live_error_code::http_status_412_precondition_failed;\n        case HTTP_E_STATUS_REQUEST_TOO_LARGE: return xbox_live_error_code::http_status_413_request_entity_too_large;\n        case HTTP_E_STATUS_URI_TOO_LONG: return xbox_live_error_code::http_status_414_request_uri_too_long;\n        case HTTP_E_STATUS_UNSUPPORTED_MEDIA: return xbox_live_error_code::http_status_415_unsupported_media_type;\n        case HTTP_E_STATUS_RANGE_NOT_SATISFIABLE: return xbox_live_error_code::http_status_416_requested_range_not_satisfiable;\n        case HTTP_E_STATUS_EXPECTATION_FAILED: return xbox_live_error_code::http_status_417_expectation_failed;\n        case MAKE_HTTP_HRESULT(421): return xbox_live_error_code::http_status_421_misdirected_request;\n        case MAKE_HTTP_HRESULT(422): return xbox_live_error_code::http_status_422_unprocessable_entity;\n        case MAKE_HTTP_HRESULT(423): return xbox_live_error_code::http_status_423_locked;\n        case MAKE_HTTP_HRESULT(424): return xbox_live_error_code::http_status_424_failed_dependency;\n        case MAKE_HTTP_HRESULT(426): return xbox_live_error_code::http_status_426_upgrade_required;\n        case MAKE_HTTP_HRESULT(428): return xbox_live_error_code::http_status_428_precondition_required;\n        case MAKE_HTTP_HRESULT(429): return xbox_live_error_code::http_status_429_too_many_requests;\n        case MAKE_HTTP_HRESULT(431): return xbox_live_error_code::http_status_431_request_header_fields_too_large;\n        case MAKE_HTTP_HRESULT(449): return xbox_live_error_code::http_status_449_retry_with;\n        case MAKE_HTTP_HRESULT(451): return xbox_live_error_code::http_status_451_unavailable_for_legal_reasons;\n\n        case HTTP_E_STATUS_SERVER_ERROR: return xbox_live_error_code::http_status_500_internal_server_error;\n        case HTTP_E_STATUS_NOT_SUPPORTED: return xbox_live_error_code::http_status_501_not_implemented;\n        case HTTP_E_STATUS_BAD_GATEWAY: return xbox_live_error_code::http_status_502_bad_gateway;\n        case HTTP_E_STATUS_SERVICE_UNAVAIL: return xbox_live_error_code::http_status_503_service_unavailable;\n        case HTTP_E_STATUS_GATEWAY_TIMEOUT: return xbox_live_error_code::http_status_504_gateway_timeout;\n        case HTTP_E_STATUS_VERSION_NOT_SUP: return xbox_live_error_code::http_status_505_http_version_not_supported;\n        case MAKE_HTTP_HRESULT(506): return xbox_live_error_code::http_status_506_variant_also_negotiates;\n        case MAKE_HTTP_HRESULT(507): return xbox_live_error_code::http_status_507_insufficient_storage;\n        case MAKE_HTTP_HRESULT(508): return xbox_live_error_code::http_status_508_loop_detected;\n        case MAKE_HTTP_HRESULT(510): return xbox_live_error_code::http_status_510_not_extended;\n        case MAKE_HTTP_HRESULT(511): return xbox_live_error_code::http_status_511_network_authentication_required;\n\n        default: return xbox_live_error_code::generic_error;\n        }\n    }\n\n    static std::error_code ConvertHr(HRESULT hr)\n    {\n        return std::make_error_code(ConvertHrToXblErrorCode(hr));\n    }\n\n    static string_t StringTFromUtf8(_In_z_ const char* utf8)\n    {\n        if (utf8 == nullptr)\n        {\n            return string_t();\n        }\n\n#if HC_PLATFORM_IS_MICROSOFT\n        auto cchOutString = CharTFromUft8(utf8, nullptr, 0);\n        string_t out(static_cast<size_t>(cchOutString) - 1, '\\0');\n        CharTFromUft8(utf8, &out[0], cchOutString);\n        return out;\n#else\n        return string_t(utf8);\n#endif\n    }\n\n    static std::string StringFromStringT(_In_ const string_t& stringt)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        auto cchOutString = Utf8FromCharT(stringt.data(), nullptr, 0);\n        std::string out(static_cast<size_t>(cchOutString) - 1, '\\0');\n        Utf8FromCharT(stringt.data(), &out[0], cchOutString);\n        return out;\n#else\n        return std::string(stringt.data());\n#endif\n    }\n\n    static int Utf8FromCharT(\n        _In_z_ const char_t* inArray,\n        _Out_writes_z_(cchOutArray) char* outArray,\n        _In_ int cchOutArray\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        // query for the buffer size\n        auto queryResult = WideCharToMultiByte(\n            CP_UTF8, WC_ERR_INVALID_CHARS,\n            inArray, -1,\n            nullptr, 0,\n            nullptr, nullptr\n        );\n\n        if (queryResult > cchOutArray && cchOutArray == 0)\n        {\n            return queryResult;\n        }\n        else if (queryResult == 0 || queryResult > cchOutArray)\n        {\n            throw std::exception(\"utf8_from_char_t failed\");\n        }\n\n        auto conversionResult = WideCharToMultiByte(\n            CP_UTF8, WC_ERR_INVALID_CHARS,\n            inArray, -1,\n            outArray, cchOutArray,\n            nullptr, nullptr\n        );\n        if (conversionResult == 0)\n        {\n            throw std::exception(\"utf8_from_char_t failed\");\n        }\n\n        return conversionResult;\n#else\n        int len = (int)strlen(inArray);\n        if (len < cchOutArray && outArray != nullptr)\n        {\n            strlcpy(outArray, inArray, len + 1);\n        }\n        else if (cchOutArray > 0)\n        {\n            return 0;\n        }\n        return len + 1;\n#endif\n    }\n\n    static int CharTFromUft8(\n        _In_z_ const char* inArray,\n        _Out_writes_z_(cchOutArray) char_t* outArray,\n        _In_ int cchOutArray\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        // query for the buffer size\n        auto queryResult = MultiByteToWideChar(\n            CP_UTF8, MB_ERR_INVALID_CHARS,\n            inArray, -1,\n            nullptr, 0\n        );\n\n        if (queryResult > cchOutArray && cchOutArray == 0)\n        {\n            return queryResult;\n        }\n        else if (queryResult == 0 || queryResult > cchOutArray)\n        {\n            throw std::exception(\"char_t_from_utf8 failed\");\n        }\n\n        auto conversionResult = MultiByteToWideChar(\n            CP_UTF8, MB_ERR_INVALID_CHARS,\n            inArray, -1,\n            outArray, cchOutArray\n        );\n        if (conversionResult == 0)\n        {\n            throw std::exception(\"char_t_from_utf8 failed\");\n        }\n\n        return conversionResult;\n#else\n        int len = (int)strlen(inArray);\n        if (len < cchOutArray && outArray != nullptr)\n        {\n            strlcpy(outArray, inArray, len + 1);\n        }\n        else if (cchOutArray > 0)\n        {\n            return 0;\n        }\n        return len + 1;\n#endif\n    }\n\n    static size_t CopyUtf8(\n            _In_ char* destinationCharArr,\n            _In_ size_t sizeInWords,\n            _In_ const char* sourceCharArr\n        )\n\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return strcpy_s(destinationCharArr, sizeInWords, sourceCharArr);\n#else\n        return strlcpy(destinationCharArr, sourceCharArr, sizeInWords);\n#endif\n    }\n\n    static string_t StringTFromUint64(_In_ uint64_t val)\n    {\n        stringstream_t ss;\n        ss << val;\n        return ss.str();\n    }\n\n    static std::string StringFromUint64(_In_ uint64_t val)\n    {\n        std::stringstream ss;\n        ss << val;\n        return ss.str();\n    }\n\n    static uint64_t Uint64FromStringT(_In_ const string_t& str)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wtoi64(str.data());\n#else\n        return strtoull(str.data(), nullptr, 0);\n#endif\n    }\n\n    static int Stricmp(const char* left, const char* right) noexcept\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _stricmp(left, right);\n#else\n        return strcasecmp(left, right);\n#endif\n    }\n\n    static int Stricmp(const string_t& left, const string_t& right)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wcsicmp(left.data(), right.data());\n#else\n        return strcasecmp(left.data(), right.data());\n#endif \n    }\n\n    static web::json::value ParseJson(const char* jsonString)\n    {\n        try\n        {\n            if (jsonString)\n            {\n                return web::json::value::parse(Utils::StringTFromUtf8(jsonString));\n            }\n        }\n        catch (web::json::json_exception)\n        {\n        }\n\n        return web::json::value::null();\n    }\n\n    static web::json::value ExtractJsonField(\n        _In_ const web::json::value& json,\n        _In_ const string_t& name,\n        _In_ bool required\n    )\n    {\n        if (json.is_object())\n        {\n            auto& jsonObj = json.as_object();\n            auto it = jsonObj.find(name);\n            if (it != jsonObj.end())\n            {\n                return it->second;\n            }\n        }\n\n        if (required)\n        {\n            utility::stringstream_t ss;\n            ss << name;\n            ss << \" not found\";\n            throw web::json::json_exception(ss.str().c_str());\n        }\n\n        return web::json::value::null();\n    }\n\n    static string_t ExtractJsonString(\n        _In_ const web::json::value& jsonValue,\n        _In_ const string_t& stringName,\n        _In_ bool required = false,\n        _In_ const string_t& defaultValue = string_t()\n    )\n    {\n        web::json::value field(ExtractJsonField(jsonValue, stringName, required));\n        if ((!field.is_string() && !required) || field.is_null())\n        {\n            return defaultValue;\n        }\n        return field.as_string();\n    }\n\n    static uint64_t ExtractJsonUint64(\n        _In_ const web::json::value& jsonValue,\n        _In_ const string_t& name,\n        _In_ bool required = false,\n        _In_ uint64_t defaultValue = 0\n    )\n    {\n        web::json::value field(ExtractJsonField(jsonValue, name, required));\n        if (!field.is_number() && !required)\n        {\n            return defaultValue;\n        }\n        return field.as_number().to_uint64();\n    }\n\n    template<typename TOut, typename InputIt, typename Transformer>\n    static std::vector<TOut> Transform(InputIt first, InputIt last, Transformer op)\n    {\n        std::vector<TOut> out;\n        std::transform(first, last, std::back_inserter(out), op);\n        return out;\n    }\n\n    template<typename TOut, typename TIn, typename Transformer>\n    static std::vector<TOut> Transform(const std::vector<TIn>& in, Transformer op)\n    {\n        return Transform<TOut>(in.begin(), in.end(), op);\n    }\n\n    template<typename TOut, typename TIn, typename Transformer>\n    static std::vector<TOut> Transform(TIn* inArray, size_t inArrayCount, Transformer op)\n    {\n        return Transform<TOut>(inArray, inArray + inArrayCount, op);\n    }\n\n    template<typename TOut, typename TIn>\n    static std::vector<TOut> Transform(TIn* inArray, size_t inArrayCount)\n    {\n        return Transform<TOut>(inArray, inArrayCount, [](const TIn& in)\n        {\n            return TOut(in);\n        });\n    }\n\n    static std::vector<string_t> XuidStringVectorFromXuidArray(const uint64_t* xuids, size_t xuidsCount)\n    {\n        return Transform<string_t>(xuids, xuidsCount, StringTFromUint64);\n    }\n\n    static std::vector<uint64_t> XuidVectorFromXuidStringVector(const std::vector<string_t>& xuidStrings)\n    {\n        return Transform<uint64_t>(xuidStrings, Uint64FromStringT);\n    }\n\n    static std::vector<string_t> StringTVectorFromCStringArray(const char** stringArray, size_t arrayCount)\n    {\n        return Transform<string_t>(stringArray, arrayCount, StringTFromUtf8);\n    }\n\n#define MS_TICKS        (10000)\n#define SECOND_TICKS    (1000 * MS_TICKS)\n#define MINUTE_TICKS    (60 * SECOND_TICKS)\n#define HOUR_TICKS      (60 * MINUTE_TICKS)\n#define DAY_TICKS       (24 * HOUR_TICKS)\n\n    static utility::datetime DatetimeFromTimeT(time_t time)\n    {\n        const uint64_t epoch_offset = 11644473600LL;\n        uint64_t result = epoch_offset + time;\n        result *= SECOND_TICKS; // convert to 10e-7\n        return utility::datetime() + result;\n    }\n\n    static time_t TimeTFromDatetime(const utility::datetime& datetime)\n    {\n        const uint64_t epoch_offset = 11644473600LL;\n        uint64_t seconds = datetime.to_interval() / SECOND_TICKS;\n        if (seconds >= epoch_offset)\n        {\n            return (time_t)(seconds - epoch_offset);\n        }\n        else\n        {\n            // If time is before epoch, 0 is returned.\n            return 0;\n        }\n    }\n\n    static char_t ToLower(char_t c)\n    {\n        return std::tolower<char_t>(c, std::locale());\n    }\n};\n\n#if !XSAPI_NO_PPL\n\ntemplate<typename T>\nstruct AsyncWrapper\n{\n    typedef std::function<HRESULT(XAsyncBlock*, T&)> ResultExtractor;\n\n    AsyncWrapper(ResultExtractor resultExtractor)\n        : m_resultExtractor(std::move(resultExtractor))\n    {\n        async.queue = XblGetAsyncQueue();\n        async.context = this;\n        async.callback = [](XAsyncBlock* async)\n        {\n            auto thisPtr = static_cast<AsyncWrapper<T>*>(async->context);\n            T result;\n            auto hr = thisPtr->m_resultExtractor(async, result);\n            if (SUCCEEDED(hr))\n            {\n                thisPtr->m_taskCompletionEvent.set(xbox_live_result<T>(result));\n            }\n            else\n            {\n                thisPtr->m_taskCompletionEvent.set(xbox_live_result<T>(Utils::ConvertHr(hr)));\n            }\n            delete thisPtr;\n        };\n    }\n\n    XAsyncBlock async{};\n\n    // If the Async API fails, the callback will never be invoked. Return a failure task and self destruct.\n    pplx::task<xbox_live_result<T>> Task(HRESULT asyncApiResult)\n    {\n        if (SUCCEEDED(asyncApiResult))\n        {\n            return pplx::task<xbox_live_result<T>>(m_taskCompletionEvent);\n        }\n        else\n        {\n            delete this;\n            return pplx::task_from_result(xbox_live_result<T>(Utils::ConvertHr(asyncApiResult)));\n        }\n    }\n\nprivate:\n    AsyncWrapper(const AsyncWrapper&) = delete;\n    AsyncWrapper& operator=(AsyncWrapper) = delete;\n\n    ResultExtractor m_resultExtractor;\n    pplx::task_completion_event<xbox_live_result<T>> m_taskCompletionEvent;\n};\n\ntemplate<>\nstruct AsyncWrapper<void>\n{\n    typedef std::function<HRESULT(XAsyncBlock*)> ResultExtractor;\n\n    AsyncWrapper() : AsyncWrapper{ [](XAsyncBlock* async) { return XAsyncGetStatus(async, false); } }\n    {\n    }\n\n    AsyncWrapper(ResultExtractor resultExtractor)\n        : m_resultExtractor{ std::move(resultExtractor) }\n    {\n        async.queue = XblGetAsyncQueue();\n        async.context = this;\n        async.callback = [](XAsyncBlock* async)\n        {\n            auto thisPtr = static_cast<AsyncWrapper<void>*>(async->context);\n            auto hr = thisPtr->m_resultExtractor(async);\n            thisPtr->m_taskCompletionEvent.set(xbox_live_result<void>(Utils::ConvertHr(hr)));\n            delete thisPtr;\n        };\n    }\n\n    XAsyncBlock async{};\n\n    pplx::task<xbox_live_result<void>> Task(HRESULT asyncApiResult)\n    {\n        if (SUCCEEDED(asyncApiResult))\n        {\n            return pplx::task<xbox_live_result<void>>(m_taskCompletionEvent);\n        }\n        else\n        {\n            // If the Async API fails, the callback will never be invoked. Return a failure task and self destruct.\n            delete this;\n            return pplx::task_from_result(xbox_live_result<void>(Utils::ConvertHr(asyncApiResult)));\n        }\n    }\n\nprivate:\n    AsyncWrapper(const AsyncWrapper&) = delete;\n    AsyncWrapper& operator=(AsyncWrapper) = delete;\n\n    ResultExtractor m_resultExtractor;\n    pplx::task_completion_event<xbox_live_result<void>> m_taskCompletionEvent;\n};\n\n#endif // #if !XSAPI_NO_PPL\n\n// RAII class used to create an array of C-Strings from a std::vector<string_t>.\n// On Microsoft platforms where string_t is using wide characters, we will allocate memory for the\n// UTF-8 string array. On other platforms, UTF8StringArrayRef will only reference the existing memory.\nclass UTF8StringArrayRef\n{\npublic:\n#if HC_PLATFORM_IS_MICROSOFT\n    UTF8StringArrayRef(const std::vector<string_t>& string_tVector)\n    {\n        std::transform(string_tVector.begin(), string_tVector.end(), std::back_inserter(m_strings), [](const string_t& in)\n            {\n                auto cchOut = Utils::Utf8FromCharT(in.data(), nullptr, 0);\n                auto out = new char[cchOut];\n                Utils::Utf8FromCharT(in.data(), out, cchOut);\n                return out;\n            });\n    }\n\n    ~UTF8StringArrayRef() noexcept\n    {\n        for (auto string : m_strings)\n        {\n            delete[] string;\n        }\n    }\n#else\n    UTF8StringArrayRef(const std::vector<string_t>& string_tVector) noexcept\n    {\n        std::transform(string_tVector.begin(), string_tVector.end(), std::back_inserter(m_strings), [](const string_t& in)\n            {\n                return in.data();\n            });\n    }\n\n    ~UTF8StringArrayRef() noexcept = default;\n#endif\n\n    UTF8StringArrayRef(UTF8StringArrayRef&& other) noexcept\n        : m_strings{ std::move(other.m_strings) }\n    {\n    }\n\n    UTF8StringArrayRef(const UTF8StringArrayRef&) = delete;\n    UTF8StringArrayRef& operator=(UTF8StringArrayRef) = delete;\n\n    const char** Data() noexcept\n    {\n        return m_strings.data();\n    }\n\n    size_t Size() const noexcept\n    {\n        return m_strings.size();\n    }\n\nprivate:\n    std::vector<const char*> m_strings;\n};\n\n} } // xbox::services\n"
  },
  {
    "path": "Include/xsapi-cpp/impl/real_time_activity.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n#include \"xsapi-c/real_time_activity_c.h\"\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n\nreal_time_activity_subscription::real_time_activity_subscription(\n    XblRealTimeActivitySubscriptionHandle handle\n) :\n    m_handle{ handle }\n{\n}\n\nreal_time_activity_subscription_state real_time_activity_subscription::state() const\n{\n    XblRealTimeActivitySubscriptionState state;\n    XblRealTimeActivitySubscriptionGetState(m_handle, &state);\n    return static_cast<real_time_activity_subscription_state>(state);\n}\n\nconst string_t& real_time_activity_subscription::resource_uri() const\n{\n    return m_resourceUri;\n}\n\nuint32_t real_time_activity_subscription::subscription_id() const\n{\n    uint32_t id;\n    XblRealTimeActivitySubscriptionGetId(m_handle, &id);\n    return id;\n}\n\nreal_time_activity_subscription_error_event_args::real_time_activity_subscription_error_event_args(\n    XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    HRESULT subscriptionError\n) :\n    m_subscription{ subscriptionHandle }\n{\n    m_err = Utils::ConvertHr(subscriptionError);\n}\n\nconst real_time_activity_subscription& real_time_activity_subscription_error_event_args::subscription()\n{\n    return m_subscription;\n}\n\nstd::error_code real_time_activity_subscription_error_event_args::err() const\n{\n    return m_err;\n}\n\nstd::string real_time_activity_subscription_error_event_args::err_message() const\n{\n    return std::string();\n}\n\nreal_time_activity_service::real_time_activity_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nreal_time_activity_service::real_time_activity_service(const real_time_activity_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nreal_time_activity_service& real_time_activity_service::operator=(real_time_activity_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nreal_time_activity_service::~real_time_activity_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\nvoid real_time_activity_service::activate()\n{\n    XblRealTimeActivityActivate(m_xblContext);\n}\n\nvoid real_time_activity_service::deactivate()\n{\n    XblRealTimeActivityDeactivate(m_xblContext);\n}\n\nstruct real_time_activity_service::HandlerContext\n{\n    XblFunctionContext internalContext;\n    std::function<void(real_time_activity_connection_state)> connectionStateChangeHandler;\n    std::function<void(const real_time_activity_subscription_error_event_args&)> subscriptionErrorHandler;\n    std::function<void()> resyncHandler;\n};\n\nfunction_context real_time_activity_service::add_connection_state_change_handler(\n    _In_ std::function<void(real_time_activity_connection_state)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->connectionStateChangeHandler = std::move(handler);\n\n    context->internalContext = XblRealTimeActivityAddConnectionStateChangeHandler(m_xblContext,\n        [](_In_ void* context, _In_ XblRealTimeActivityConnectionState connectionState)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->connectionStateChangeHandler(static_cast<real_time_activity_connection_state>(connectionState));\n    }, context);\n\n    return context;\n}\n\nvoid real_time_activity_service::remove_connection_state_change_handler(\n    _In_ function_context remove\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(remove) };\n    XblRealTimeActivityRemoveConnectionStateChangeHandler(m_xblContext, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nfunction_context real_time_activity_service::add_subscription_error_handler(\n    _In_ std::function<void(const real_time_activity_subscription_error_event_args&)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->subscriptionErrorHandler = std::move(handler);\n\n    context->internalContext = XblRealTimeActivityAddSubscriptionErrorHandler(m_xblContext,\n        [](_In_ void* context, _In_ XblRealTimeActivitySubscriptionHandle subscription, HRESULT subscriptionError)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->subscriptionErrorHandler(\n            real_time_activity_subscription_error_event_args{ subscription, subscriptionError }\n        );\n    }, context);\n\n    return context;\n}\n\nvoid real_time_activity_service::remove_subscription_error_handler(\n    _In_ function_context remove\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(remove) };\n    XblRealTimeActivityRemoveSubscriptionErrorHandler(m_xblContext, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nfunction_context real_time_activity_service::add_resync_handler(\n    _In_ std::function<void()> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->resyncHandler = std::move(handler);\n\n    context->internalContext = XblRealTimeActivityAddResyncHandler(m_xblContext,\n        [](_In_ void* context)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->resyncHandler();\n    }, context);\n\n    return context;\n}\n\nvoid real_time_activity_service::remove_resync_handler(\n    _In_ function_context remove\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(remove) };\n    XblRealTimeActivityRemoveResyncHandler(m_xblContext, handlerContext->internalContext);\n    delete handlerContext;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END\n\nXBL_WARNING_POP"
  },
  {
    "path": "Include/xsapi-cpp/impl/service_call_logging_config.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#if HC_PLATFORM_IS_MICROSOFT\n\nstd::shared_ptr<service_call_logging_config> service_call_logging_config::get_singleton_instance()\n{\n    static std::shared_ptr<service_call_logging_config> s_instance = std::shared_ptr<service_call_logging_config>(new service_call_logging_config);\n    return s_instance;\n}\n\nvoid service_call_logging_config::enable() {}\nvoid service_call_logging_config::disable() {}\n#if HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP || defined(XSAPI_UNIT_TESTS)\nvoid service_call_logging_config::_Register_for_protocol_activation() {}\n#endif\n\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/social.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nxbox_social_relationship::xbox_social_relationship(\n    const XblSocialRelationship& socialRelationship\n) :\n    m_xuid{ Utils::StringTFromUint64(socialRelationship.xboxUserId) },\n    m_isFavorite{ socialRelationship.isFavorite },\n    m_isFollowingCaller{ socialRelationship.isFollowingCaller },\n    m_isFriend{ socialRelationship.isFriend },\n    m_socialNetworks{ Utils::Transform<string_t>(socialRelationship.socialNetworks, socialRelationship.socialNetworksCount, Utils::StringTFromUtf8) }\n{\n}\n\nconst string_t& xbox_social_relationship::xbox_user_id() const\n{\n    return m_xuid;\n}\n\nbool xbox_social_relationship::is_favorite() const\n{\n    return m_isFavorite;\n}\n\nbool xbox_social_relationship::is_following_caller() const\n{\n    return m_isFollowingCaller;\n}\n\nbool xbox_social_relationship::is_friend() const\n{\n    return m_isFriend;\n}\n\nconst std::vector<string_t>& xbox_social_relationship::social_networks() const\n{\n    return m_socialNetworks;\n}\n\nxbox_social_relationship_result::xbox_social_relationship_result(\n    XblSocialRelationshipResultHandle resultHandle,\n    XblContextHandle xblContextHandle\n)\n{\n    assert(resultHandle);\n    assert(xblContextHandle);\n    \n    XblSocialRelationshipResultDuplicateHandle(resultHandle, &m_resultHandle);\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n}\n\nxbox_social_relationship_result::xbox_social_relationship_result(\n    const xbox_social_relationship_result& other\n)\n{\n    if (other.m_resultHandle)\n    {\n        XblSocialRelationshipResultDuplicateHandle(other.m_resultHandle, &m_resultHandle);\n    }\n    if (other.m_xblContextHandle)\n    {\n        XblContextDuplicateHandle(other.m_xblContextHandle, &m_xblContextHandle);\n    }\n}\nxbox_social_relationship_result& xbox_social_relationship_result::operator=(\n    xbox_social_relationship_result other\n)\n{\n    std::swap(m_resultHandle, other.m_resultHandle);\n    std::swap(m_xblContextHandle, other.m_xblContextHandle);\n    return *this;\n}\n\nxbox_social_relationship_result::~xbox_social_relationship_result()\n{\n    if (m_resultHandle)\n    {\n        XblSocialRelationshipResultCloseHandle(m_resultHandle);\n    }\n    if (m_xblContextHandle)\n    {\n        XblContextCloseHandle(m_xblContextHandle);\n    }\n}\n\nstd::vector<xbox_social_relationship> xbox_social_relationship_result::items() const\n{\n    const XblSocialRelationship* relationships{ nullptr };\n    size_t relationshipsCount{ 0 };\n    XblSocialRelationshipResultGetRelationships(m_resultHandle, &relationships, &relationshipsCount);\n\n    return Utils::Transform<xbox_social_relationship>(relationships, relationshipsCount);\n}\n\nuint32_t xbox_social_relationship_result::total_count() const\n{\n    size_t totalCount{ 0 };\n    XblSocialRelationshipResultGetTotalCount(m_resultHandle, &totalCount);\n    return static_cast<uint32_t>(totalCount);\n}\n\nbool xbox_social_relationship_result::has_next() const\n{\n    bool hasNext{ false };\n    XblSocialRelationshipResultHasNext(m_resultHandle, &hasNext);\n    return hasNext;\n}\n\npplx::task<xbox_live_result<xbox_social_relationship_result>> xbox_social_relationship_result::get_next(\n    _In_ uint32_t maxItems\n)\n{\n    auto asyncWrapper = new AsyncWrapper<xbox_social_relationship_result>(\n        [this](XAsyncBlock* async, xbox_social_relationship_result& result)\n        {\n            XblSocialRelationshipResultHandle resultHandle{ nullptr };\n            auto hr = XblSocialRelationshipResultGetNextResult(async, &resultHandle);\n\n            if (SUCCEEDED(hr))\n            {\n                result = xbox_social_relationship_result(resultHandle, m_xblContextHandle);\n                XblSocialRelationshipResultCloseHandle(resultHandle);\n            }\n\n            return hr;\n        });\n\n    auto hr = XblSocialRelationshipResultGetNextAsync(m_xblContextHandle, m_resultHandle, static_cast<size_t>(maxItems), &asyncWrapper->async);\n\n    return asyncWrapper->Task(hr);\n}\n\nsocial_relationship_change_event_args::social_relationship_change_event_args(\n    const XblSocialRelationshipChangeEventArgs* args\n) :\n    m_callerXuid{ Utils::StringTFromUint64(args->callerXboxUserId) },\n    m_notificationType{ static_cast<social_notification_type>(args->socialNotification) },\n    m_xuids{ Utils::Transform<string_t>(args->xboxUserIds, args->xboxUserIdsCount, Utils::StringTFromUint64) }\n{\n}\n\nconst string_t& social_relationship_change_event_args::caller_xbox_user_id() const\n{\n    return m_callerXuid;\n}\n\nsocial_notification_type social_relationship_change_event_args::social_notification() const\n{\n    return m_notificationType;\n}\n\nconst std::vector<string_t>& social_relationship_change_event_args::xbox_user_ids() const\n{\n    return m_xuids;\n}\n\nsocial_relationship_change_subscription::social_relationship_change_subscription(\n    _In_ XblRealTimeActivitySubscriptionHandle handle, \n    _In_ uint64_t xuid\n) :\n    real_time_activity_subscription(handle),\n    m_xuid{ Utils::StringTFromUint64(xuid) }\n{\n    stringstream_t uri;\n    uri << _T(\"http://social.xboxlive.com/users/xuid(\") << m_xuid << \")/friends\";\n    m_resourceUri = uri.str();\n}\n\nconst string_t& social_relationship_change_subscription::xbox_user_id() const\n{\n    return m_xuid;\n}\n\nsocial_service::social_service(XblContextHandle xblContextHandle)\n{\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n    XblContextGetXboxUserId(m_xblContextHandle, &m_xuid);\n}\n\nsocial_service::social_service(const social_service& other)\n    : m_xuid{ other.m_xuid }\n{\n    XblContextDuplicateHandle(other.m_xblContextHandle, &m_xblContextHandle);\n}\n\nsocial_service& social_service::operator=(social_service other)\n{\n    std::swap(m_xblContextHandle, other.m_xblContextHandle);\n    m_xuid = other.m_xuid;\n    return *this;\n}\n\nsocial_service::~social_service()\n{\n    XblContextCloseHandle(m_xblContextHandle);\n}\n\npplx::task<xbox_live_result<xbox_social_relationship_result>> social_service::get_social_relationships(\n    _In_ uint64_t xuid,\n    _In_ XblSocialRelationshipFilter filter,\n    _In_ size_t startIndex,\n    _In_ size_t maxItems\n)\n{\n    XblContextHandle xblContextHandle{ nullptr };\n    XblContextDuplicateHandle(m_xblContextHandle, &xblContextHandle);\n    auto asyncWrapper = new AsyncWrapper<xbox_social_relationship_result>(\n        [xblContextHandle](XAsyncBlock* async, xbox_social_relationship_result& result)\n    {\n        XblSocialRelationshipResultHandle resultHandle{ nullptr };\n        auto hr = XblSocialGetSocialRelationshipsResult(async, &resultHandle);\n\n        if (SUCCEEDED(hr))\n        {\n            result = xbox_social_relationship_result(resultHandle, xblContextHandle);\n            XblSocialRelationshipResultCloseHandle(resultHandle);\n        }\n\n        XblContextCloseHandle(xblContextHandle);\n        return hr;\n    });\n\n    auto hr = XblSocialGetSocialRelationshipsAsync(m_xblContextHandle, xuid, filter, startIndex, maxItems, &asyncWrapper->async);\n    if (FAILED(hr))\n    {\n        //Close the duplicated handle since it won't be closed in the callback\n        XblContextCloseHandle(xblContextHandle);\n    }\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<xbox_social_relationship_result>> social_service::get_social_relationships()\n{\n    return get_social_relationships(m_xuid, XblSocialRelationshipFilter::All, 0, 0);\n}\n\npplx::task<xbox_live_result<xbox_social_relationship_result>> social_service::get_social_relationships(\n    _In_ xbox_social_relationship_filter socialRelationshipFilter\n)\n{\n    return get_social_relationships(m_xuid, static_cast<XblSocialRelationshipFilter>(socialRelationshipFilter), 0, 0);\n}\n\npplx::task<xbox_live_result<xbox_social_relationship_result>> social_service::get_social_relationships(\n    _In_ const string_t& xuid\n)\n{\n    return get_social_relationships(Utils::Uint64FromStringT(xuid), XblSocialRelationshipFilter::All, 0, 0);\n}\n\npplx::task<xbox_live_result<xbox_social_relationship_result>> social_service::get_social_relationships(\n    _In_ xbox_social_relationship_filter filter,\n    _In_ uint32_t startIndex,\n    _In_ uint32_t maxItems\n)\n{\n    return get_social_relationships(m_xuid, static_cast<XblSocialRelationshipFilter>(filter), startIndex, maxItems);\n}\n\nxbox_live_result<std::shared_ptr<social_relationship_change_subscription>> social_service::subscribe_to_social_relationship_change(\n    _In_ const string_t& xuidString\n)\n{\n    auto xuid{ Utils::Uint64FromStringT(xuidString) };\n    XblRealTimeActivitySubscriptionHandle subHandle{};\n    auto hr = XblSocialSubscribeToSocialRelationshipChange(m_xblContextHandle, xuid, &subHandle);\n\n    if (FAILED(hr))\n    {\n        return Utils::ConvertHr(hr);\n    }\n    return std::make_shared<social_relationship_change_subscription>(subHandle, xuid);\n}\n\nxbox_live_result<void> social_service::unsubscribe_from_social_relationship_change(\n    _In_ std::shared_ptr<social_relationship_change_subscription> subscription\n)\n{\n    return Utils::ConvertHr(XblSocialUnsubscribeFromSocialRelationshipChange(m_xblContextHandle, subscription->m_handle));\n}\n\nstruct social_service::HandlerContext\n{\n    XblFunctionContext token{ 0 };\n    std::function<void(social_relationship_change_event_args)> handler;\n};\n\nfunction_context social_service::add_social_relationship_changed_handler(\n    _In_ std::function<void(social_relationship_change_event_args)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->handler = std::move(handler);\n\n    context->token = XblSocialAddSocialRelationshipChangedHandler(m_xblContextHandle, \n        [](const XblSocialRelationshipChangeEventArgs* args, void* context)\n        {\n            auto handlerContext{ static_cast<HandlerContext*>(context) };\n            handlerContext->handler(args);\n        }, context);\n\n    return context;\n}\n\nvoid social_service::remove_social_relationship_changed_handler(\n    _In_ function_context context\n)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblSocialRemoveSocialRelationshipChangedHandler(m_xblContextHandle, handlerContext->token);\n    delete handlerContext;\n}\n\nreputation_feedback_item::reputation_feedback_item(\n    _In_ const string_t& xboxUserId,\n    _In_ reputation_feedback_type reputationFeedbackType,\n    _In_ xbox::services::multiplayer::multiplayer_session_reference sessionRef,\n    _In_ const string_t& reasonMessage,\n    _In_ const string_t& evidenceResourceId\n) :\n    m_xboxUserId{ Utils::Uint64FromStringT(xboxUserId) },\n    m_reputationFeedbackType{ reputationFeedbackType },\n    m_sessionRef{ std::move(sessionRef) },\n    m_reasonMessage{ Utils::StringFromStringT(reasonMessage) },\n    m_evidenceResourceId{ Utils::StringFromStringT(evidenceResourceId) }\n{\n}\n\nstring_t reputation_feedback_item::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_xboxUserId);\n}\n\nreputation_feedback_type reputation_feedback_item::feedback_type() const\n{\n    return m_reputationFeedbackType;\n}\n\nconst xbox::services::multiplayer::multiplayer_session_reference& reputation_feedback_item::session_reference() const\n{\n    return m_sessionRef;\n}\n\nstring_t reputation_feedback_item::reason_message() const\n{\n    return Utils::StringTFromUtf8(m_reasonMessage.data());\n}\n\nstring_t reputation_feedback_item::evidence_resource_id() const\n{\n    return Utils::StringTFromUtf8(m_evidenceResourceId.data());\n}\n\nreputation_service::reputation_service(XblContextHandle xblContextHandle)\n{\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n}\n\nreputation_service::reputation_service(const reputation_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContextHandle, &m_xblContextHandle);\n}\n\nreputation_service& reputation_service::operator=(reputation_service other)\n{\n    std::swap(m_xblContextHandle, other.m_xblContextHandle);\n    return *this;\n}\n\nreputation_service::~reputation_service()\n{\n    XblContextCloseHandle(m_xblContextHandle);\n}\n\npplx::task<xbox_live_result<void>> reputation_service::submit_reputation_feedback(\n    _In_ const string_t& xboxUserId,\n    _In_ reputation_feedback_type reputationFeedbackType,\n    _In_ const string_t& sessionName,\n    _In_ const string_t& reasonMessage,\n    _In_ const string_t& evidenceResourceId\n)\n{\n    UNREFERENCED_PARAMETER(sessionName);\n\n    auto asyncWrapper = new AsyncWrapper<void>(\n        [](XAsyncBlock* async)\n        {\n            return XAsyncGetStatus(async, false);\n        });\n\n    auto hr = XblSocialSubmitReputationFeedbackAsync(\n        m_xblContextHandle,\n        Utils::Uint64FromStringT(xboxUserId),\n        static_cast<XblReputationFeedbackType>(reputationFeedbackType),\n        nullptr,\n        Utils::StringFromStringT(reasonMessage).data(),\n        evidenceResourceId.size() > 0 ? Utils::StringFromStringT(evidenceResourceId).data() : nullptr,\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<void>> reputation_service::submit_batch_reputation_feedback(\n    _In_ const std::vector<reputation_feedback_item>& feedbackItems\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>(\n        [](XAsyncBlock* async)\n        {\n            return XAsyncGetStatus(async, false);\n        });\n\n    auto items = Utils::Transform<XblReputationFeedbackItem>(feedbackItems, [](const reputation_feedback_item& i)\n        {\n            XblReputationFeedbackItem item{};\n            item.xboxUserId = i.m_xboxUserId;\n            item.feedbackType = static_cast<XblReputationFeedbackType>(i.m_reputationFeedbackType);\n            item.sessionReference = &i.m_sessionRef.m_reference;\n            if (i.m_reasonMessage.size() > 0)\n            {\n                item.reasonMessage = i.m_reasonMessage.data();\n            }\n            if (i.m_evidenceResourceId.size() > 0)\n            {\n                item.evidenceResourceId = i.m_evidenceResourceId.data();\n            }\n            return item;\n        });\n\n    auto hr = XblSocialSubmitBatchReputationFeedbackAsync(\n        m_xblContextHandle,\n        items.data(),\n        items.size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END\n\nXBL_WARNING_POP\n"
  },
  {
    "path": "Include/xsapi-cpp/impl/social_manager.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\ntitle_history::title_history(\n    const XblTitleHistory& titleHistory\n) :\n    m_titleHistory{ &titleHistory }\n{\n}\n\ntitle_history::title_history(\n    const title_history& other\n) :\n    m_owningPtr{ std::make_shared<XblTitleHistory>(*other.m_titleHistory) },\n    m_titleHistory{ m_owningPtr.get() }\n{\n}\n\ntitle_history& title_history::operator=(title_history other)\n{\n    m_owningPtr = other.m_owningPtr;\n    m_titleHistory = m_owningPtr.get();\n    return *this;\n}\n\nbool title_history::has_user_played() const\n{\n    return m_titleHistory->hasUserPlayed;\n}\n\nutility::datetime title_history::last_time_user_played() const\n{\n    return Utils::DatetimeFromTimeT(m_titleHistory->lastTimeUserPlayed);\n}\n\npreferred_color::preferred_color(\n    const XblPreferredColor& preferredColor\n)\n{\n    m_primaryColor = Utils::StringTFromUtf8(preferredColor.primaryColor);\n    m_secondaryColor = Utils::StringTFromUtf8(preferredColor.secondaryColor);\n    m_tertiaryColor = Utils::StringTFromUtf8(preferredColor.tertiaryColor);\n}\n\nconst char_t* preferred_color::primary_color() const\n{\n    return m_primaryColor.data();\n}\n\nconst char_t* preferred_color::secondary_color() const\n{\n    return m_secondaryColor.data();\n}\n\nconst char_t* preferred_color::tertiary_color() const\n{\n    return m_tertiaryColor.data();\n}\n\nbool preferred_color::operator!=(\n    const preferred_color& rhs\n) const\n{\n    return Utils::Stricmp(m_primaryColor, rhs.m_primaryColor) != 0 ||\n        Utils::Stricmp(m_secondaryColor, rhs.m_secondaryColor) != 0 ||\n        Utils::Stricmp(m_tertiaryColor, rhs.m_tertiaryColor) != 0;\n}\n\nsocial_manager_presence_title_record::social_manager_presence_title_record(\n    const XblSocialManagerPresenceTitleRecord& titleRecord\n) :\n    m_titleRecord{ &titleRecord }\n{\n    m_presenceText = Utils::StringTFromUtf8(m_titleRecord->presenceText);\n}\n\nsocial_manager_presence_title_record::social_manager_presence_title_record(\n    const social_manager_presence_title_record& other\n) :\n    m_owningPtr{ std::make_shared<XblSocialManagerPresenceTitleRecord>(*other.m_titleRecord) },\n    m_titleRecord{ m_owningPtr.get() },\n    m_presenceText{ other.m_presenceText }\n{\n}\n\nsocial_manager_presence_title_record& social_manager_presence_title_record::operator=(\n    social_manager_presence_title_record other\n)\n{\n    m_owningPtr = other.m_owningPtr;\n    m_titleRecord = m_owningPtr.get();\n    m_presenceText = other.m_presenceText;\n    return *this;\n}\n\nuint32_t social_manager_presence_title_record::title_id() const\n{\n    return m_titleRecord->titleId;\n}\n\nbool social_manager_presence_title_record::is_title_active() const\n{\n    return m_titleRecord->isTitleActive;\n}\n\nconst char_t* social_manager_presence_title_record::presence_text() const\n{\n    return m_presenceText.data();\n}\n\nbool social_manager_presence_title_record::is_broadcasting() const\n{\n    return m_titleRecord->isBroadcasting;\n}\n\nxbox::services::presence::presence_device_type social_manager_presence_title_record::device_type() const\n{\n    return static_cast<xbox::services::presence::presence_device_type>(m_titleRecord->deviceType);\n}\n\nbool social_manager_presence_title_record::is_primary() const\n{\n    return m_titleRecord->isPrimary;\n}\n\nsocial_manager_presence_record::social_manager_presence_record(\n    const XblSocialManagerPresenceRecord& presenceRecord\n) :\n    m_presenceRecord{ &presenceRecord }\n{\n    m_titleRecords.reserve(XBL_NUM_PRESENCE_RECORDS);\n    for (size_t i = 0; i < m_presenceRecord->presenceTitleRecordCount; ++i)\n    {\n        m_titleRecords.push_back(social_manager_presence_title_record{ m_presenceRecord->presenceTitleRecords[i] });\n    }\n}\n\nsocial_manager_presence_record::social_manager_presence_record(\n    const social_manager_presence_record& other\n) :\n    m_owningPtr{ std::make_shared<XblSocialManagerPresenceRecord>(*other.m_presenceRecord) },\n    m_presenceRecord{ m_owningPtr.get() }\n{\n    m_titleRecords.reserve(XBL_NUM_PRESENCE_RECORDS);\n    for (size_t i = 0; i < m_presenceRecord->presenceTitleRecordCount; ++i)\n    {\n        m_titleRecords.push_back(social_manager_presence_title_record{ m_presenceRecord->presenceTitleRecords[i] });\n    }\n}\n\nsocial_manager_presence_record& social_manager_presence_record::operator=(\n    social_manager_presence_record other\n)\n{\n    m_owningPtr = other.m_owningPtr;\n    m_presenceRecord = m_owningPtr.get();\n\n    m_titleRecords.clear();\n    for (size_t i = 0; i < m_presenceRecord->presenceTitleRecordCount; ++i)\n    {\n        m_titleRecords.push_back(social_manager_presence_title_record{ m_presenceRecord->presenceTitleRecords[i] });\n    }\n    return *this;\n}\n\nxbox::services::presence::user_presence_state social_manager_presence_record::user_state() const\n{\n    return static_cast<xbox::services::presence::user_presence_state>(m_presenceRecord->userState);\n}\n\nconst std::vector<social_manager_presence_title_record>& social_manager_presence_record::presence_title_records() const\n{\n    return m_titleRecords;\n}\n\nbool social_manager_presence_record::is_user_playing_title(\n    _In_ uint32_t titleId\n) const\n{\n    for (auto& titleRecord : m_titleRecords)\n    {\n        if (titleRecord.title_id() == titleId)\n        {\n            return true;\n        }\n    }\n    return false;\n}\n\nxbox_social_user::xbox_social_user(\n    const XblSocialManagerUser& user\n) :\n    m_user{ &user },\n    m_titleHistory{ m_user->titleHistory },\n    m_preferredColor{ m_user->preferredColor },\n    m_presenceRecord{ m_user->presenceRecord }\n{\n    m_gamerscore = Utils::StringTFromUtf8(m_user->gamerscore);\n    m_gamertag = Utils::StringTFromUtf8(m_user->gamertag);\n    m_modernGamertag = Utils::StringTFromUtf8(m_user->modernGamertag);\n    m_modernGamertagSuffix = Utils::StringTFromUtf8(m_user->modernGamertagSuffix);\n    m_uniqueModernGamertag = Utils::StringTFromUtf8(m_user->uniqueModernGamertag);\n    m_xboxUserId = Utils::StringTFromUint64(m_user->xboxUserId);\n    m_displayName = Utils::StringTFromUtf8(m_user->displayName);\n    m_realName = Utils::StringTFromUtf8(m_user->realName);\n    m_displayPicUrlRaw = Utils::StringTFromUtf8(m_user->displayPicUrlRaw);\n}\n\nxbox_social_user::xbox_social_user(\n    const xbox_social_user& other\n) :\n    m_owningPtr{ std::make_shared<XblSocialManagerUser>(*other.m_user) },\n    m_user{ m_owningPtr.get() },\n    m_gamerscore{ other.m_gamerscore },\n    m_gamertag{ other.m_gamertag },\n    m_modernGamertag{ other.m_modernGamertag },\n    m_modernGamertagSuffix{ other.m_modernGamertagSuffix },\n    m_uniqueModernGamertag{ other.m_uniqueModernGamertag },\n    m_xboxUserId{ other.m_xboxUserId },\n    m_displayName{ other.m_displayName },\n    m_realName{ other.m_realName },\n    m_displayPicUrlRaw{ other.m_displayPicUrlRaw },\n    m_titleHistory{ m_user->titleHistory },\n    m_preferredColor{ m_user->preferredColor },\n    m_presenceRecord{ m_user->presenceRecord }\n{\n}\n\nxbox_social_user& xbox_social_user::operator=(\n    xbox_social_user other\n)\n{\n    m_owningPtr = std::make_shared<XblSocialManagerUser>(*other.m_user);\n    m_user = other.m_user;\n    m_gamerscore = other.m_gamerscore;\n    m_gamertag = other.m_gamertag;\n    m_modernGamertag = other.m_modernGamertag;\n    m_modernGamertagSuffix = other.m_modernGamertagSuffix;\n    m_uniqueModernGamertag = other.m_uniqueModernGamertag;\n    m_xboxUserId = other.m_xboxUserId;\n    m_displayName = other.m_displayName;\n    m_realName = other.m_realName;\n    m_displayPicUrlRaw = other.m_displayPicUrlRaw;\n    m_titleHistory = xbox::services::social::manager::title_history{ m_user->titleHistory };\n    m_preferredColor = xbox::services::social::manager::preferred_color{ m_user->preferredColor };\n    m_presenceRecord = xbox::services::social::manager::social_manager_presence_record{ m_user->presenceRecord };\n\n    return *this;\n}\n\nconst char_t* xbox_social_user::xbox_user_id() const\n{\n    return m_xboxUserId.data();\n}\n\nbool xbox_social_user::is_favorite() const\n{\n    return m_user->isFavorite;\n}\n\nbool xbox_social_user::is_following_user() const\n{\n    return m_user->isFollowingUser;\n}\n\nbool xbox_social_user::is_followed_by_caller() const\n{\n    return m_user->isFollowedByCaller;\n}\n\nconst char_t* xbox_social_user::display_name() const\n{\n    return m_displayName.data();\n}\n\nconst char_t* xbox_social_user::real_name() const\n{\n    return m_realName.data();\n}\n\nconst char_t* xbox_social_user::display_pic_url_raw() const\n{\n    return m_displayPicUrlRaw.data();\n}\n\nbool xbox_social_user::use_avatar() const\n{\n    return m_user->useAvatar;\n}\n\nconst char_t* xbox_social_user::gamerscore() const\n{\n    return m_gamerscore.data();\n}\n\nconst char_t* xbox_social_user::gamertag() const\n{\n    return m_gamertag.data();\n}\n\nconst char_t* xbox_social_user::modern_gamertag() const\n{\n    return m_modernGamertag.data();\n}\n\nconst char_t* xbox_social_user::modern_gamertag_suffix() const\n{\n    return m_modernGamertagSuffix.data();\n}\n\nconst char_t* xbox_social_user::unique_modern_gamertag() const\n{\n    return m_uniqueModernGamertag.data();\n}\n\nconst social_manager_presence_record& xbox_social_user::presence_record() const\n{\n    return m_presenceRecord;\n}\n\nconst xbox::services::social::manager::title_history& xbox_social_user::title_history() const\n{\n    return m_titleHistory;\n}\n\nconst preferred_color& xbox_social_user::preferred_color() const\n{\n    return m_preferredColor;\n}\n\nxbox_user_id_container::xbox_user_id_container(\n    _In_ uint64_t xuid\n) :\n    m_xboxUserId{ Utils::StringTFromUint64(xuid) }\n{\n}\n\nconst char_t* xbox_user_id_container::xbox_user_id() const\n{\n    return m_xboxUserId.data();\n}\n\nsocial_event::social_event(\n    const XblSocialManagerEvent& event\n) :\n    m_event{ event },\n    m_eventType{ static_cast<social_event_type>(m_event.eventType) }\n{\n    if (m_event.groupAffected)\n    {\n        auto groupAffected = social_manager::get_singleton_instance()->m_groups[m_event.groupAffected];\n        assert(groupAffected);\n        m_args = std::make_shared<social_user_group_loaded_event_args>(groupAffected);\n    }\n}\n\nsocial_event::social_event(\n    const xbox_live_user_t& removedUser\n) :\n    m_eventType{ social_event_type::local_user_removed }\n{\n    m_event.user = removedUser;\n    m_event.hr = S_OK;\n}\n\nxbox_live_user_t social_event::user() const\n{\n    return m_event.user;\n}\n\nsocial_event_type social_event::event_type() const\n{\n    return m_eventType;\n}\n\nstd::vector<xbox_user_id_container> social_event::users_affected() const\n{\n    std::vector<xbox_user_id_container> usersAffected;\n    for (auto& user : m_event.usersAffected)\n    {\n        if (user)\n        {\n            usersAffected.push_back(user->xboxUserId);\n        }\n    }\n    return usersAffected;\n}\n\nstd::shared_ptr<social_event_args> social_event::event_args() const\n{\n    return m_args;\n}\n\nstd::error_code social_event::err() const\n{\n    return Utils::ConvertHr(m_event.hr);\n}\n\nstd::string social_event::err_message() const\n{\n    return std::string{};\n}\n\nxbox_social_user_group::xbox_social_user_group(\n    XblSocialManagerUserGroupHandle group\n) :\n    m_group{ group }\n{\n}\n\nstd::vector<xbox_social_user*> xbox_social_user_group::users() const\n{\n    PopulateUsers();\n\n    std::vector<xbox_social_user*> userPointers;\n    for (auto& user : m_users)\n    {\n        userPointers.push_back(&user);\n    }\n    return userPointers;\n}\n\nxbox_live_result<void> xbox_social_user_group::get_copy_of_users(\n    _Inout_ std::vector<xbox_social_user>& socialUserVector\n)\n{\n    PopulateUsers();\n\n    for (auto& user : m_users)\n    {\n        socialUserVector.push_back(user);\n    }\n\n    return xbox_live_result<void>{};\n}\n\nsocial_user_group_type xbox_social_user_group::social_user_group_type() const\n{\n    XblSocialUserGroupType type{};\n    auto hr = XblSocialManagerUserGroupGetType(m_group, &type);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return static_cast<xbox::services::social::manager::social_user_group_type>(type);\n}\n\nstd::vector<xbox_user_id_container> xbox_social_user_group::users_tracked_by_social_user_group() const\n{\n    const uint64_t* trackedXuids{ nullptr };\n    size_t count{ 0 };\n    auto hr = XblSocialManagerUserGroupGetUsersTrackedByGroup(m_group, &trackedXuids, &count);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return Utils::Transform<xbox_user_id_container>(trackedXuids, count);\n}\n\nxbox_live_user_t xbox_social_user_group::local_user() const\n{\n    XblUserHandle userHandle{ nullptr };\n    auto hr = XblSocialManagerUserGroupGetLocalUser(m_group, &userHandle);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return userHandle;\n}\n\nvoid xbox_social_user_group::PopulateUsers() const\n{\n    const XblSocialManagerUser* const * users{ nullptr };\n    size_t usersCount{ 0 };\n\n    XblSocialManagerUserGroupGetUsers(m_group, &users, &usersCount);\n\n    m_users.clear();\n    for (size_t i = 0; i < usersCount; ++i)\n    {\n        m_users.push_back(xbox_social_user{ *users[i] });\n    }\n}\n\npresence_filter xbox_social_user_group::presence_filter_of_group() const\n{\n    XblPresenceFilter filter{ XblPresenceFilter::Unknown };\n    XblSocialManagerUserGroupGetFilters(m_group, &filter, nullptr);\n    return static_cast<presence_filter>(filter);\n}\n\nrelationship_filter xbox_social_user_group::relationship_filter_of_group() const\n{\n    XblRelationshipFilter filter{ XblRelationshipFilter::Friends };\n    XblSocialManagerUserGroupGetFilters(m_group, nullptr, &filter);\n    return static_cast<relationship_filter>(filter);\n}\n\nstd::vector<xbox_social_user*> xbox_social_user_group::get_users_from_xbox_user_ids(\n    _In_ const std::vector<xbox_user_id_container>& xboxUserIds\n)\n{\n    PopulateUsers();\n\n    std::vector<xbox_social_user*> userPointers;\n    for (auto& xuid : xboxUserIds)\n    {\n        for (auto& user : m_users)\n        {\n            if (Utils::Stricmp(user.xbox_user_id(), xuid.xbox_user_id()) == 0)\n            {\n                userPointers.push_back(&user);\n                break;\n            }\n        }\n    }\n    return userPointers;\n}\n\nsocial_user_group_loaded_event_args::social_user_group_loaded_event_args(\n    std::shared_ptr<xbox_social_user_group> group\n) :\n    m_group{ std::move(group) }\n{\n}\n\nstd::shared_ptr<xbox_social_user_group> social_user_group_loaded_event_args::social_user_group() const\n{\n    return m_group;\n}\n\nstd::shared_ptr<social_manager> social_manager::get_singleton_instance()\n{\n    static std::shared_ptr<social_manager> instance = std::shared_ptr<social_manager>(new social_manager{});\n    return instance;\n}\n\nxbox_live_result<void> social_manager::add_local_user(\n    _In_ xbox_live_user_t user,\n    _In_ social_manager_extra_detail_level extraDetailLevel\n)\n{\n    return Utils::ConvertHr(XblSocialManagerAddLocalUser(\n        user,\n        static_cast<XblSocialManagerExtraDetailLevel>(extraDetailLevel),\n        nullptr\n    ));\n}\n\nxbox_live_result<void> social_manager::remove_local_user(\n    _In_ xbox_live_user_t user\n)\n{\n    auto hr = XblSocialManagerRemoveLocalUser(user);\n    if (SUCCEEDED(hr))\n    {\n        // Track removed users to raise user removed event in next do_work call. This is to maintain\n        // legacy behavior in c++ interface since removing a user no longer yields an event.\n        m_removedUsers.push_back(user);\n    }\n\n    return Utils::ConvertHr(hr);\n}\n\nstd::vector<social_event> social_manager::do_work()\n{\n    const XblSocialManagerEvent* events{ nullptr };\n    size_t eventCount{ 0 };\n\n    auto hr = XblSocialManagerDoWork(&events, &eventCount);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    auto legacyEvents{ Utils::Transform<social_event>(events, eventCount) };\n    for (auto& user : m_removedUsers)\n    {\n        legacyEvents.push_back(social_event{ user });\n    }\n    m_removedUsers.clear();\n\n    return legacyEvents;\n}\n\nxbox_live_result<std::shared_ptr<xbox_social_user_group>> social_manager::create_social_user_group_from_filters(\n    _In_ xbox_live_user_t user,\n    _In_ presence_filter presenceDetailLevel,\n    _In_ relationship_filter filter\n)\n{\n    XblSocialManagerUserGroupHandle groupHandle{ nullptr };\n\n    HRESULT hr = XblSocialManagerCreateSocialUserGroupFromFilters(\n        user,\n        static_cast<XblPresenceFilter>(presenceDetailLevel),\n        static_cast<XblRelationshipFilter>(filter),\n        &groupHandle\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        auto group = std::make_shared<xbox_social_user_group>(groupHandle);\n        m_groups[groupHandle] = group;\n        return group;\n    }\n    return Utils::ConvertHr(hr);\n}\n\nxbox_live_result<std::shared_ptr<xbox_social_user_group>> social_manager::create_social_user_group_from_list(\n    _In_ xbox_live_user_t user,\n    _In_ std::vector<string_t> xboxUserIdList\n)\n{\n    XblSocialManagerUserGroupHandle groupHandle{ nullptr };\n\n    auto xuids{ Utils::XuidVectorFromXuidStringVector(xboxUserIdList) };\n\n    HRESULT hr = XblSocialManagerCreateSocialUserGroupFromList(\n        user,\n        xuids.data(),\n        xuids.size(),\n        &groupHandle\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        auto group = std::make_shared<xbox_social_user_group>(groupHandle);\n        m_groups[groupHandle] = group;\n        return group;\n    }\n    return Utils::ConvertHr(hr);\n}\n\nxbox_live_result<void> social_manager::destroy_social_user_group(\n    _In_ std::shared_ptr<xbox_social_user_group> socialUserGroup\n)\n{\n    auto hr = XblSocialManagerDestroySocialUserGroup(socialUserGroup->m_group);\n    if (SUCCEEDED(hr))\n    {\n        m_groups.erase(socialUserGroup->m_group);\n    }\n    return Utils::ConvertHr(hr);\n}\n\nstd::vector<xbox_live_user_t> social_manager::local_users() const\n{\n    std::vector<xbox_live_user_t> users{};\n    size_t localUsersCount{ XblSocialManagerGetLocalUserCount() };\n    users = std::vector<XblUserHandle>(localUsersCount, nullptr);\n    XblSocialManagerGetLocalUsers(localUsersCount, users.data());\n\n    return users;\n}\n\nxbox_live_result<void> social_manager::update_social_user_group(\n    _In_ const std::shared_ptr<xbox_social_user_group>& group,\n    _In_ const std::vector<string_t>& users\n)\n{\n    auto xuids{ Utils::XuidVectorFromXuidStringVector(users) };\n    return Utils::ConvertHr(XblSocialManagerUpdateSocialUserGroup(group->m_group, xuids.data(), xuids.size()));\n}\n\nxbox_live_result<void> social_manager::set_rich_presence_polling_status(\n    _In_ xbox_live_user_t user,\n    _In_ bool shouldEnablePolling\n)\n{\n    return Utils::ConvertHr(XblSocialManagerSetRichPresencePollingStatus(user, shouldEnablePolling));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END\n"
  },
  {
    "path": "Include/xsapi-cpp/impl/string_verify.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nverify_string_result::verify_string_result() :\n    m_resultCode {verify_string_result_code::success},\n    m_first_offending_substring{}\n{ }\n\nverify_string_result::verify_string_result(\n    XblVerifyStringResultCode resultCode,\n    char const* firstOffendingSubstring\n) :\n    m_resultCode{ static_cast<verify_string_result_code>(resultCode)},\n    m_first_offending_substring{ Utils::StringTFromUtf8(firstOffendingSubstring ? firstOffendingSubstring : \"\") }\n{ }\n\nverify_string_result_code verify_string_result::result_code() const\n{\n    return m_resultCode;\n}\n\nconst string_t& verify_string_result::first_offending_substring() const\n{\n    return m_first_offending_substring;\n}\n\nstring_service::string_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nstring_service::string_service(const string_service& other) \n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nstring_service& string_service::operator=(string_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nstring_service::~string_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\npplx::task<xbox_live_result<verify_string_result>> string_service::verify_string(_In_ const string_t& stringToVerify)\n{\n    auto xblContext = m_xblContext;\n    auto asyncWrapper = new AsyncWrapper<verify_string_result>(\n        [](XAsyncBlock* async, verify_string_result& result)\n    {\n        size_t bufferSize{ 0 };\n        auto hr = XblStringVerifyStringResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblVerifyStringResult* resultResponse;\n            hr = XblStringVerifyStringResult(async, bufferSize, buffer.get(), &resultResponse, nullptr);\n            if (SUCCEEDED(hr))\n            {\n                auto internalResult = reinterpret_cast<XblVerifyStringResult*>(buffer.get());\n                result = verify_string_result(internalResult->resultCode, internalResult->firstOffendingSubstring);\n            }\n        }\n        return hr;\n    });\n    auto hr = XblStringVerifyStringAsync(\n        xblContext,\n        Utils::StringFromStringT(stringToVerify).c_str(),\n        &asyncWrapper->async\n        );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<verify_string_result>>> string_service::verify_strings(_In_ const std::vector<string_t>& stringsToVerify)\n{\n    UTF8StringArrayRef stringsToVerifyInternal{ stringsToVerify };\n    auto xblContext = m_xblContext;\n    auto asyncWrapper = new AsyncWrapper<std::vector<verify_string_result>>(\n        [](XAsyncBlock* async, std::vector<verify_string_result>& results)\n    {\n        size_t bufferSize;\n        auto hr = XblStringVerifyStringsResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            std::shared_ptr<char> buffer(new char[bufferSize], std::default_delete<char[]>());\n            XblVerifyStringResult* resultResponses = nullptr;\n            size_t stringsCount{ 0 };\n            hr = XblStringVerifyStringsResult(async, bufferSize, buffer.get(), &resultResponses, &stringsCount, nullptr);\n            if (SUCCEEDED(hr))\n            {\n                for (size_t i = 0; i < stringsCount; i++) \n                {\n                    results.push_back(verify_string_result(resultResponses[i].resultCode, resultResponses[i].firstOffendingSubstring));\n                }\n            }\n        }\n        return hr;\n    });\n\n\n    auto hr = XblStringVerifyStringsAsync(\n        xblContext,\n        stringsToVerifyInternal.Data(),\n        stringsToVerifyInternal.Size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/system.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nstd::shared_ptr<xbox_live_services_settings> xbox_live_services_settings::get_singleton_instance(_In_ bool createIfRequired)\n{\n    UNREFERENCED_PARAMETER(createIfRequired);\n\n    static std::shared_ptr<xbox_live_services_settings> instance = std::shared_ptr<xbox_live_services_settings>(new xbox_live_services_settings);\n    return instance;\n}\n\nvoid xbox_live_services_settings::set_memory_allocation_hooks(\n    _In_ const std::function<_Ret_maybenull_ _Post_writable_byte_size_(dwSize) void*(_In_ size_t dwSize)>& memAllocHandler,\n    _In_ const std::function<void(_In_ void* pAddress)>& memFreeHandler\n)\n{\n    static std::function<void*(size_t)> allocHook{ nullptr };\n    static std::function<void(void*)> freeHook{ nullptr };\n\n    if (memAllocHandler != nullptr && memFreeHandler != nullptr)\n    {\n        allocHook = memAllocHandler;\n        freeHook = memFreeHandler;\n\n        XblMemSetFunctions(\n            [](size_t size, HCMemoryType)\n            {\n                return allocHook(size);\n            },\n            [](void* pointer, HCMemoryType)\n            {\n                freeHook(pointer);\n            }\n        );\n    }\n    else if (memAllocHandler == nullptr && memFreeHandler == nullptr)\n    {\n        XblMemSetFunctions(nullptr, nullptr);\n    }\n}\n\n\nfunction_context xbox_live_services_settings::add_logging_handler(\n    std::function<void(xbox_services_diagnostics_trace_level, const std::string&, const std::string&)> handler\n)\n{\n    UNREFERENCED_PARAMETER(handler);\n    return function_context{};\n}\n\nvoid xbox_live_services_settings::remove_logging_handler(_In_ function_context context)\n{\n    UNREFERENCED_PARAMETER(context);\n}\n\nxbox_services_diagnostics_trace_level xbox_live_services_settings::diagnostics_trace_level() const\n{\n    HCTraceLevel traceLevel{};\n    HCSettingsGetTraceLevel(&traceLevel);\n\n    switch (traceLevel)\n    {\n    case HCTraceLevel::Off: return xbox_services_diagnostics_trace_level::off;\n    case HCTraceLevel::Error: return xbox_services_diagnostics_trace_level::error;\n    case HCTraceLevel::Warning: return xbox_services_diagnostics_trace_level::warning;\n    case HCTraceLevel::Important: return xbox_services_diagnostics_trace_level::info;\n    case HCTraceLevel::Verbose: return xbox_services_diagnostics_trace_level::verbose;\n    default: return xbox_services_diagnostics_trace_level::off;\n    }\n}\n\nvoid xbox_live_services_settings::set_diagnostics_trace_level(_In_ xbox_services_diagnostics_trace_level value)\n{\n    HCTraceLevel traceLevel{ HCTraceLevel::Off };\n    switch (value)\n    {\n    case xbox_services_diagnostics_trace_level::off: traceLevel = HCTraceLevel::Off; break;\n    case xbox_services_diagnostics_trace_level::error: traceLevel = HCTraceLevel::Error; break;\n    case xbox_services_diagnostics_trace_level::warning: traceLevel = HCTraceLevel::Warning; break;\n    case xbox_services_diagnostics_trace_level::info: traceLevel = HCTraceLevel::Information; break;\n    case xbox_services_diagnostics_trace_level::verbose: traceLevel = HCTraceLevel::Verbose; break;\n    default: break;\n    }\n    HCSettingsSetTraceLevel(traceLevel);\n}\n\nfunction_context xbox_live_services_settings::add_wns_handler(_In_ const std::function<void(const xbox_live_wns_event_args&)>& handler)\n{\n    UNREFERENCED_PARAMETER(handler);\n    return function_context{};\n}\n\nvoid xbox_live_services_settings::remove_wns_handler(_In_ function_context context)\n{\n    UNREFERENCED_PARAMETER(context);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/title_storage.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_BEGIN\n\ninline title_storage_quota::title_storage_quota(\n    string_t scid, \n    title_storage_type storageType, \n    uint64_t xuid, \n    uint64_t usedByted, \n    uint64_t quotaBytes\n)\n    :\n    m_serviceConfigurationId{ scid },\n    m_storageType{ storageType },\n    m_xboxUserId{ xuid },\n    m_usedBytes{ usedByted },\n    m_quotaBytes{ quotaBytes }\n{ }\n\ninline const string_t& title_storage_quota::service_configuration_id() const\n{\n    return m_serviceConfigurationId;\n}\n\ninline title_storage_type title_storage_quota::storage_type() const\n{\n    return m_storageType;\n}\n\ninline string_t title_storage_quota::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_xboxUserId);\n}\n\ninline uint64_t title_storage_quota::used_bytes() const\n{\n    return m_usedBytes;\n}\n\ninline uint64_t title_storage_quota::quota_bytes() const\n{\n    return m_quotaBytes;\n}\n\ninline title_storage_blob_metadata::title_storage_blob_metadata(\n    XblTitleStorageBlobMetadata blobMetadata\n)\n    :\n    m_blobMetadata{blobMetadata}\n{ }\n\ninline title_storage_blob_metadata::title_storage_blob_metadata(\n    _In_ string_t serviceConfigurationId,\n    _In_ title_storage_type storageType,\n    _In_ string_t blobPath,\n    _In_ title_storage_blob_type blobType,\n    _In_ string_t xboxUserId\n)\n    :\n    title_storage_blob_metadata(\n        serviceConfigurationId,\n        storageType,\n        blobPath,\n        blobType,\n        xboxUserId,\n        _T(\"\"),\n        _T(\"\")\n    )\n{ }\n\ninline title_storage_blob_metadata::title_storage_blob_metadata(\n    _In_ string_t serviceConfigurationId,\n    _In_ title_storage_type storageType,\n    _In_ string_t blobPath,\n    _In_ title_storage_blob_type blobType,\n    _In_ string_t xboxUserId,\n    _In_ string_t /*displayName*/,\n    _In_ string_t /*eTag*/\n)\n    :\n    title_storage_blob_metadata(\n        serviceConfigurationId,\n        storageType,\n        blobPath,\n        blobType,\n        xboxUserId,\n        _T(\"\"),\n        _T(\"\"),\n        utility::datetime()\n    )\n{ }\n\ninline title_storage_blob_metadata::title_storage_blob_metadata(\n    _In_ string_t serviceConfigurationId,\n    _In_ title_storage_type storageType,\n    _In_ string_t blobPath,\n    _In_ title_storage_blob_type blobType,\n    _In_ string_t xboxUserId,\n    _In_ string_t displayName,\n    _In_ string_t eTag,\n    _In_ utility::datetime clientTimestamp\n)\n{\n    Utils::Utf8FromCharT(serviceConfigurationId.c_str(), m_blobMetadata.serviceConfigurationId, sizeof(m_blobMetadata.serviceConfigurationId));\n    m_blobMetadata.storageType = static_cast<XblTitleStorageType>(storageType);\n    Utils::Utf8FromCharT(blobPath.c_str(), m_blobMetadata.blobPath, sizeof(m_blobMetadata.blobPath));\n    m_blobMetadata.blobType = static_cast<XblTitleStorageBlobType>(blobType);\n    m_blobMetadata.xboxUserId = Utils::Uint64FromStringT(xboxUserId);\n    Utils::Utf8FromCharT(displayName.c_str(), m_blobMetadata.displayName, sizeof(m_blobMetadata.displayName));\n    Utils::Utf8FromCharT(eTag.c_str(), m_blobMetadata.eTag, sizeof(m_blobMetadata.eTag));\n    m_blobMetadata.clientTimestamp = Utils::TimeTFromDatetime(clientTimestamp);\n}\n\ninline string_t title_storage_blob_metadata::blob_path() const\n{\n    return Utils::StringTFromUtf8(m_blobMetadata.blobPath);\n}\n\ninline title_storage_blob_type title_storage_blob_metadata::blob_type() const\n{\n    return static_cast<title_storage_blob_type>(m_blobMetadata.blobType);\n}\n\ninline title_storage_type title_storage_blob_metadata::storage_type() const\n{\n    return static_cast<title_storage_type>(m_blobMetadata.storageType);\n}\n\ninline string_t title_storage_blob_metadata::display_name() const\n{\n    return Utils::StringTFromUtf8(m_blobMetadata.displayName);\n}\n\ninline string_t title_storage_blob_metadata::e_tag() const\n{\n    return Utils::StringTFromUtf8(m_blobMetadata.eTag);\n}\n\ninline utility::datetime title_storage_blob_metadata::client_timestamp() const\n{\n    return Utils::DatetimeFromTimeT(m_blobMetadata.clientTimestamp);\n}\n\ninline void title_storage_blob_metadata::set_client_timestamp(_In_ utility::datetime value)\n{\n    m_blobMetadata.clientTimestamp = Utils::TimeTFromDatetime(value);\n}\n\ninline uint64_t title_storage_blob_metadata::length() const\n{\n    return m_blobMetadata.length;\n}\n\ninline string_t title_storage_blob_metadata::service_configuration_id() const\n{\n    return Utils::StringTFromUtf8(m_blobMetadata.serviceConfigurationId);\n}\n\ninline string_t title_storage_blob_metadata::xbox_user_id() const\n{\n    return Utils::StringTFromUint64(m_blobMetadata.xboxUserId);\n}\n\ninline title_storage_blob_metadata_result::title_storage_blob_metadata_result(\n    XblTitleStorageBlobMetadataResultHandle handle\n)\n{\n    XblTitleStorageBlobMetadataResultDuplicateHandle(handle, &m_handle);\n\n    size_t itemsCount;\n    const XblTitleStorageBlobMetadata* items{ nullptr };\n    XblTitleStorageBlobMetadataResultGetItems(m_handle, &items, &itemsCount);\n    \n    for (size_t i = 0; i < itemsCount; i++)\n    {\n        m_items.push_back(title_storage_blob_metadata(items[i]));\n    }\n}\n\ntitle_storage_blob_metadata_result::title_storage_blob_metadata_result(\n    _In_ const title_storage_blob_metadata_result& other\n)\n{\n    XblTitleStorageBlobMetadataResultDuplicateHandle(other.m_handle, &m_handle);\n\n    size_t itemsCount;\n    const XblTitleStorageBlobMetadata* items{ nullptr };\n    XblTitleStorageBlobMetadataResultGetItems(m_handle, &items, &itemsCount);\n\n    for (size_t i = 0; i < itemsCount; i++)\n    {\n        m_items.push_back(title_storage_blob_metadata(items[i]));\n    }\n}\n\ntitle_storage_blob_metadata_result& title_storage_blob_metadata_result::operator=(\n    title_storage_blob_metadata_result other\n    )\n{\n    std::swap(m_handle, other.m_handle);\n    std::swap(m_items, other.m_items);\n    return *this;\n}\n\ninline title_storage_blob_metadata_result::~title_storage_blob_metadata_result()\n{\n    if (m_handle)\n    {\n        XblTitleStorageBlobMetadataResultCloseHandle(m_handle);\n    }\n}\n\ninline const std::vector<title_storage_blob_metadata>& title_storage_blob_metadata_result::items() const\n{\n    return m_items;\n}\n\ninline pplx::task<xbox_live_result<title_storage_blob_metadata_result>> title_storage_blob_metadata_result::get_next(\n    _In_ uint32_t maxItems\n) const\n{\n    auto asyncWrapper = new AsyncWrapper<title_storage_blob_metadata_result>(\n        [](XAsyncBlock* async, title_storage_blob_metadata_result& result)\n    {\n        XblTitleStorageBlobMetadataResultHandle handle;\n        auto hr = XblTitleStorageBlobMetadataResultGetNextResult(async, &handle);\n        if (SUCCEEDED(hr))\n        {\n            // title_storage_blob_metadata_result owns the lifetime of the handle\n            result = title_storage_blob_metadata_result(handle);\n            XblTitleStorageBlobMetadataResultCloseHandle(handle);\n        }\n        return hr;\n    });\n\n    auto hr = XblTitleStorageBlobMetadataResultGetNextAsync(\n        m_handle,\n        maxItems,\n        &asyncWrapper->async\n    );\n    return asyncWrapper->Task(hr);\n}\n\ninline bool title_storage_blob_metadata_result::has_next() const\n{\n    bool hasNext = false;\n    XblTitleStorageBlobMetadataResultHasNext(m_handle, &hasNext);\n    return hasNext;\n}\n\ninline title_storage_blob_result::title_storage_blob_result(\n    std::shared_ptr<std::vector<unsigned char>> blobBuffer, title_storage_blob_metadata blobMetadata\n)\n    :\n    m_blobBuffer{ std::move(blobBuffer) },\n    m_blobMetadata{ std::move(blobMetadata) }\n{ }\n\ninline std::shared_ptr<std::vector<unsigned char>> const title_storage_blob_result::blob_buffer() const\n{\n    return m_blobBuffer;\n}\n\ninline const title_storage_blob_metadata& title_storage_blob_result::blob_metadata() const\n{\n    return m_blobMetadata;\n}\n\ninline title_storage_service::title_storage_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\ninline title_storage_service::title_storage_service(const title_storage_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\ninline title_storage_service& title_storage_service::operator=(title_storage_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\ninline title_storage_service::~title_storage_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\ninline pplx::task<xbox_live_result<title_storage_quota>> title_storage_service::get_quota(\n    _In_ string_t serviceConfigurationId,\n    _In_ title_storage_type storageType\n)\n{\n    uint64_t xuid{ 0 };\n    XblContextGetXboxUserId(m_xblContext, &xuid);\n\n    auto asyncWrapper = new AsyncWrapper<title_storage_quota>(\n        [serviceConfigurationId, storageType, xuid](XAsyncBlock* async, title_storage_quota& result)\n    {\n        size_t usedBytes;\n        size_t quotaBytes;\n        auto hr = XblTitleStorageGetQuotaResult(async, &usedBytes, &quotaBytes);\n        if (SUCCEEDED(hr))\n        {\n            result = title_storage_quota(serviceConfigurationId, storageType, xuid, static_cast<uint64_t>(usedBytes), static_cast<uint64_t>(quotaBytes));\n        }\n        return hr;\n    });\n    \n    char scid[XBL_SCID_LENGTH];\n    Utils::Utf8FromCharT(serviceConfigurationId.c_str(), scid, sizeof(scid));\n    auto hr = XblTitleStorageGetQuotaAsync(\n        m_xblContext, \n        scid, \n        static_cast<XblTitleStorageType>(storageType), \n        &asyncWrapper->async\n    );\n    return asyncWrapper->Task(hr);\n}\n\ninline pplx::task<xbox_live_result<title_storage_blob_metadata_result>> title_storage_service::get_blob_metadata(\n    _In_ string_t serviceConfigurationId,\n    _In_ title_storage_type storageType,\n    _In_ string_t blobPath,\n    _In_ string_t xboxUserId,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems\n)\n{\n    auto asyncWrapper = new AsyncWrapper<title_storage_blob_metadata_result>(\n        [](XAsyncBlock* async, title_storage_blob_metadata_result& result)\n    {\n        XblTitleStorageBlobMetadataResultHandle handle;\n        auto hr = XblTitleStorageGetBlobMetadataResult(async, &handle);\n        if (SUCCEEDED(hr))\n        {\n            // title_storage_blob_metadata_result owns the lifetime of the handle\n            result = title_storage_blob_metadata_result(handle);\n            XblTitleStorageBlobMetadataResultCloseHandle(handle);\n        }\n        return hr;\n    });\n\n    char scid[XBL_SCID_LENGTH] = { 0 };\n    Utils::Utf8FromCharT(serviceConfigurationId.c_str(), scid, sizeof(scid));\n\n    char blobPathUTF8[XBL_TITLE_STORAGE_BLOB_PATH_MAX_LENGTH] = { 0 };\n    Utils::Utf8FromCharT(blobPath.c_str(), blobPathUTF8, sizeof(blobPathUTF8));\n\n    auto hr = XblTitleStorageGetBlobMetadataAsync(\n        m_xblContext, \n        scid, \n        static_cast<XblTitleStorageType>(storageType), \n        blobPathUTF8, \n        Utils::Uint64FromStringT(xboxUserId), \n        skipItems, \n        maxItems, \n        &asyncWrapper->async\n    );\n    return asyncWrapper->Task(hr);\n}\n\ninline pplx::task<xbox_live_result<void>> title_storage_service::delete_blob(\n    _In_ const title_storage_blob_metadata& blobMetadata,\n    _In_ bool deleteOnlyIfEtagMatches\n)\n{\n    auto asyncWrapper = new AsyncWrapper<void>();\n    auto hr = XblTitleStorageDeleteBlobAsync(\n        m_xblContext,\n        blobMetadata.m_blobMetadata,\n        deleteOnlyIfEtagMatches,\n        &asyncWrapper->async\n    );\n    return asyncWrapper->Task(hr);\n}\n\ninline pplx::task<xbox_live_result<title_storage_blob_result>> title_storage_service::download_blob(\n    _In_ title_storage_blob_metadata blobMetadata,\n    _In_ std::shared_ptr<std::vector<unsigned char>> blobBuffer,\n    _In_ title_storage_e_tag_match_condition etagMatchCondition,\n    _In_ string_t selectQuery\n)\n{\n    return download_blob(\n        blobMetadata,\n        blobBuffer,\n        etagMatchCondition,\n        selectQuery,\n        XBL_TITLE_STORAGE_DEFAULT_DOWNLOAD_BLOCK_SIZE\n    );\n}\n\ninline pplx::task<xbox_live_result<title_storage_blob_result>> title_storage_service::download_blob(\n    _In_ title_storage_blob_metadata blobMetadata,\n    _In_ std::shared_ptr<std::vector<unsigned char>> blobBuffer,\n    _In_ title_storage_e_tag_match_condition etagMatchCondition,\n    _In_ string_t selectQuery,\n    _In_ uint32_t preferredDownloadBlockSize\n)\n{\n    auto asyncWrapper = new AsyncWrapper<title_storage_blob_result>(\n        [blobBuffer](XAsyncBlock* async, title_storage_blob_result& result)\n    {\n        XblTitleStorageBlobMetadata blobMetadata;\n        auto hr = XblTitleStorageDownloadBlobResult(async, &blobMetadata);\n        if (SUCCEEDED(hr))\n        {\n            result = title_storage_blob_result(blobBuffer, blobMetadata);\n        }\n        return hr;\n    });\n\n\n    auto hr = XblTitleStorageDownloadBlobAsync(\n        m_xblContext,\n        blobMetadata.m_blobMetadata,\n        static_cast<uint8_t*>(blobBuffer->data()),\n        blobBuffer->size(),\n        static_cast<XblTitleStorageETagMatchCondition>(etagMatchCondition),\n        Utils::StringFromStringT(selectQuery).c_str(),\n        static_cast<size_t>(preferredDownloadBlockSize),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\ninline pplx::task<xbox_live_result<title_storage_blob_metadata>> title_storage_service::upload_blob(\n    _In_ title_storage_blob_metadata blobMetadata,\n    _In_ std::shared_ptr<std::vector<unsigned char>> blobBuffer,\n    _In_ title_storage_e_tag_match_condition etagMatchCondition,\n    _In_ uint32_t preferredUploadBlockSize\n)\n{\n    auto asyncWrapper = new AsyncWrapper<title_storage_blob_metadata>(\n        [](XAsyncBlock* async, title_storage_blob_metadata& result)\n    {\n        XblTitleStorageBlobMetadata blobMetadata;\n        auto hr = XblTitleStorageUploadBlobResult(async, &blobMetadata);\n        if (SUCCEEDED(hr))\n        {\n            result = title_storage_blob_metadata(blobMetadata);\n        }\n        return hr;\n    });\n\n\n    auto hr = XblTitleStorageUploadBlobAsync(\n        m_xblContext,\n        blobMetadata.m_blobMetadata,\n        static_cast<uint8_t*>(blobBuffer->data()),\n        blobBuffer->size(),\n        static_cast<XblTitleStorageETagMatchCondition>(etagMatchCondition),\n        static_cast<size_t>(preferredUploadBlockSize),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/user_statistics.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nstatistic::statistic(const XblStatistic& statistic)\n    : \n    m_statName(Utils::StringTFromUtf8(statistic.statisticName)),\n    m_statType(Utils::StringTFromUtf8(statistic.statisticType)),\n    m_value(Utils::StringTFromUtf8(statistic.value))\n{ }\n\nstatistic::statistic(\n    const string_t& name,\n    const string_t& type,\n    const string_t& value\n) :\n    m_statName{ name },\n    m_statType{ type },\n    m_value{ value }\n{ }\n\nconst string_t& statistic::statistic_name() const\n{\n    return m_statName; \n}\n\nconst string_t& statistic::statistic_type() const\n{\n    return m_statType;\n}\n\nconst string_t& statistic::value() const\n{\n    return m_value;\n}\n\nservice_configuration_statistic::service_configuration_statistic(const XblServiceConfigurationStatistic& serviceConfigurationStatistic)\n    : m_serviceConfigurationId(Utils::StringTFromUtf8(serviceConfigurationStatistic.serviceConfigurationId))\n{\n    for (uint32_t i = 0; i < serviceConfigurationStatistic.statisticsCount; i++)\n    {\n        m_statistics.push_back(serviceConfigurationStatistic.statistics[i]);\n    }\n}\n\nconst string_t& service_configuration_statistic::service_configuration_id() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst std::vector<statistic>& service_configuration_statistic::statistics() const\n{\n    return m_statistics;\n}\n\nuser_statistics_result::user_statistics_result(const XblUserStatisticsResult& userStatisticsResult)\n    : m_xboxUserId(Utils::StringTFromUint64(userStatisticsResult.xboxUserId))\n{\n    for (uint32_t i = 0; i < userStatisticsResult.serviceConfigStatisticsCount; i++)\n    {\n        m_serviceConfigurationStatistics.push_back(userStatisticsResult.serviceConfigStatistics[i]);\n    }\n}\n\nconst string_t& user_statistics_result::xbox_user_id() const\n{\n    return m_xboxUserId;\n}\n\nconst std::vector<service_configuration_statistic>& user_statistics_result::service_configuration_statistics() const\n{\n    return m_serviceConfigurationStatistics;\n}\n\nrequested_statistics::requested_statistics(\n    _In_ string_t serviceConfigurationId,\n    _In_ const std::vector<string_t>& statistics\n) :\n    m_scid(serviceConfigurationId),\n    m_statistics(statistics),\n    m_statisticsC{ statistics }\n{\n    Utils::Utf8FromCharT(serviceConfigurationId.c_str(), m_requestedStatistics.serviceConfigurationId, XBL_SCID_LENGTH);\n\n    m_requestedStatistics.statistics = m_statisticsC.Data();\n    m_requestedStatistics.statisticsCount = (uint32_t)m_statisticsC.Size();\n}\n\nrequested_statistics::requested_statistics(_In_ const requested_statistics& other) :\n    m_scid(other.m_scid),\n    m_statistics(other.m_statistics),\n    m_statisticsC{ other.m_statistics }\n{\n    Utils::Utf8FromCharT(m_scid.c_str(), m_requestedStatistics.serviceConfigurationId, XBL_SCID_LENGTH);\n\n    m_requestedStatistics.statistics = m_statisticsC.Data();\n    m_requestedStatistics.statisticsCount = (uint32_t)m_statisticsC.Size();\n}\n\nconst string_t& requested_statistics::service_configuration_id() const\n{\n    return m_scid;\n}\n\nconst std::vector<string_t>& requested_statistics::statistics() const\n{\n    return m_statistics;\n}\n\nconst XblRequestedStatistics& requested_statistics::_requested_statistics() const\n{\n    return m_requestedStatistics;\n}\n\nstatistic_change_event_args::statistic_change_event_args(const XblStatisticChangeEventArgs& statisticEventArgs)\n    :\n    m_xboxUserId { Utils::StringTFromUint64(statisticEventArgs.xboxUserId) },\n    m_serviceConfigurationId { Utils::StringTFromUtf8(statisticEventArgs.serviceConfigurationId) },\n    m_statistic { statisticEventArgs.latestStatistic }\n{ }\n\nconst string_t& statistic_change_event_args::xbox_user_id() const\n{\n    return m_xboxUserId;\n}\n\nconst string_t& statistic_change_event_args::service_configuration_id() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst statistic& statistic_change_event_args::latest_statistic() const\n{\n    return m_statistic;\n}\n\nstatistic_change_subscription::statistic_change_subscription(\n    _In_ string_t xboxUserId,\n    _In_ string_t serviceConfigurationId,\n    _In_ xbox::services::user_statistics::statistic newStat,\n    _In_ XblRealTimeActivitySubscriptionHandle handle\n) :\n    real_time_activity_subscription(handle),\n    m_xboxUserId{ xboxUserId },\n    m_serviceConfigurationId{ serviceConfigurationId },\n    m_statistic{ newStat }\n{ }\n\nconst string_t& statistic_change_subscription::xbox_user_id() const\n{\n    return m_xboxUserId;\n}\n\nconst string_t& statistic_change_subscription::service_configuration_id() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst xbox::services::user_statistics::statistic& statistic_change_subscription::statistic() const\n{\n    return m_statistic;\n}\n\nuser_statistics_service::user_statistics_service(_In_ XblContextHandle contextHandle)\n{\n    XblContextDuplicateHandle(contextHandle, &m_xblContext);\n}\n\nuser_statistics_service::user_statistics_service(const user_statistics_service& other)\n{\n    XblContextDuplicateHandle(other.m_xblContext, &m_xblContext);\n}\n\nuser_statistics_service& user_statistics_service::operator=(user_statistics_service other)\n{\n    std::swap(m_xblContext, other.m_xblContext);\n    return *this;\n}\n\nuser_statistics_service::~user_statistics_service()\n{\n    XblContextCloseHandle(m_xblContext);\n}\n\npplx::task<xbox_live_result<user_statistics_result>> user_statistics_service::get_single_user_statistics(\n    _In_ const string_t& xboxUserId,\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& statisticName\n)\n{\n    auto asyncWrapper = new AsyncWrapper<user_statistics_result>(\n        [](XAsyncBlock* async, user_statistics_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblUserStatisticsGetSingleUserStatisticResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            auto buffer = new char[bufferSize];\n            XblUserStatisticsResult* resultPtr;\n            hr = XblUserStatisticsGetSingleUserStatisticResult(async, bufferSize, buffer, &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = user_statistics_result(*resultPtr);\n            }\n            delete[] buffer;\n        }\n        return hr;\n    });\n\n    auto hr = XblUserStatisticsGetSingleUserStatisticAsync(\n        m_xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(statisticName).c_str(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<user_statistics_result>> user_statistics_service::get_single_user_statistics(\n    _In_ const string_t& xboxUserId,\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const std::vector<string_t>& statisticNames\n)\n{\n    UTF8StringArrayRef statisticNamesC{ statisticNames };\n\n    auto asyncWrapper = new AsyncWrapper<user_statistics_result>(\n        [](XAsyncBlock* async, user_statistics_result& result)\n    {\n        size_t bufferSize;\n        auto hr = XblUserStatisticsGetSingleUserStatisticsResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            auto buffer = new char[bufferSize];\n            XblUserStatisticsResult* resultPtr;\n            hr = XblUserStatisticsGetSingleUserStatisticsResult(async, bufferSize, buffer, &resultPtr, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                result = user_statistics_result(*resultPtr);\n            }\n            delete[] buffer;\n        }\n        return hr;\n    });\n\n    auto hr = XblUserStatisticsGetSingleUserStatisticsAsync(\n        m_xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        statisticNamesC.Data(),\n        statisticNamesC.Size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<user_statistics_result>>> user_statistics_service::get_multiple_user_statistics(\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ const string_t& serviceConfigurationId,\n    _In_ std::vector<string_t>& statisticNames\n)\n{\n    std::vector<uint64_t> xboxUserIdsC = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n    UTF8StringArrayRef statisticNamesC{ statisticNames };\n\n    auto asyncWrapper = new AsyncWrapper<std::vector<user_statistics_result>>(\n        [](XAsyncBlock* async, std::vector<user_statistics_result>& results)\n    {\n        size_t bufferSize;\n        auto hr = XblUserStatisticsGetMultipleUserStatisticsResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            auto buffer = new char[bufferSize];\n            XblUserStatisticsResult* resultsPtr;\n            size_t resultsCount;\n            hr = XblUserStatisticsGetMultipleUserStatisticsResult(async, bufferSize, buffer, &resultsPtr, &resultsCount, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                for (size_t i = 0; i < resultsCount; i++)\n                {\n                    results.push_back(user_statistics_result(resultsPtr[i]));\n                }\n            }\n            delete[] buffer;\n        }\n        return hr;\n    });\n\n    auto hr = XblUserStatisticsGetMultipleUserStatisticsAsync(\n        m_xblContext,\n        xboxUserIdsC.data(),\n        xboxUserIdsC.size(),\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        statisticNamesC.Data(),\n        statisticNamesC.Size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\npplx::task<xbox_live_result<std::vector<user_statistics_result>>> user_statistics_service::get_multiple_user_statistics_for_multiple_service_configurations(\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ const std::vector<requested_statistics>& requestedServiceConfigurationStatisticsCollection\n)\n{\n    std::vector<uint64_t> xboxUserIdsC = Utils::XuidVectorFromXuidStringVector(xboxUserIds);\n    std::vector<XblRequestedStatistics> requestedStatsC;\n    for (size_t i = 0; i < requestedServiceConfigurationStatisticsCollection.size(); i++)\n    {\n        requestedStatsC.push_back(requestedServiceConfigurationStatisticsCollection[i]._requested_statistics());\n    }\n\n    auto asyncWrapper = new AsyncWrapper<std::vector<user_statistics_result>>(\n        [](XAsyncBlock* async, std::vector<user_statistics_result>& results)\n    {\n        size_t bufferSize;\n        auto hr = XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize(async, &bufferSize);\n        if (SUCCEEDED(hr))\n        {\n            auto buffer = new char[bufferSize];\n            XblUserStatisticsResult* resultsPtr;\n            size_t resultsCount;\n            hr = XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult(async, bufferSize, buffer, &resultsPtr, &resultsCount, nullptr);\n\n            if (SUCCEEDED(hr))\n            {\n                for (size_t i = 0; i < resultsCount; i++)\n                {\n                    results.push_back(user_statistics_result(resultsPtr[i]));\n                }\n            }\n            delete[] buffer;\n        }\n        return hr;\n    });\n\n    auto hr = XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(\n        m_xblContext,\n        xboxUserIdsC.data(),\n        (uint32_t)xboxUserIdsC.size(),\n        requestedStatsC.data(),\n        (uint32_t)requestedStatsC.size(),\n        &asyncWrapper->async\n    );\n\n    return asyncWrapper->Task(hr);\n}\n\nxbox_live_result<std::shared_ptr<statistic_change_subscription>> user_statistics_service::subscribe_to_statistic_change(\n    _In_ const string_t& xboxUserId,\n    _In_ const string_t& serviceConfigurationId,\n    _In_ const string_t& statisticName\n)\n{\n    XblRealTimeActivitySubscriptionHandle subscription;\n\n    HRESULT hr = XblUserStatisticsSubscribeToStatisticChange(\n        m_xblContext,\n        Utils::Uint64FromStringT(xboxUserId),\n        Utils::StringFromStringT(serviceConfigurationId).c_str(),\n        Utils::StringFromStringT(statisticName).c_str(),\n        &subscription\n    );\n\n    auto statistic = xbox::services::user_statistics::statistic(statisticName, Utils::StringTFromUtf8(\"\"), Utils::StringTFromUtf8(\"\"));\n    auto result = std::make_shared<statistic_change_subscription>(xboxUserId, serviceConfigurationId, statistic, subscription);\n\n    return xbox_live_result<std::shared_ptr<statistic_change_subscription>>(result, Utils::ConvertHr(hr), \"\");\n}\n\nxbox_live_result<void> user_statistics_service::unsubscribe_from_statistic_change(\n    _In_ std::shared_ptr<statistic_change_subscription> subscription\n)\n{\n    if (subscription == nullptr)\n    {\n        return xbox_live_result<void>(Utils::ConvertHr(E_INVALIDARG), \"\");\n    }\n\n    HRESULT hr = XblUserStatisticsUnsubscribeFromStatisticChange(\n        m_xblContext,\n        subscription->m_handle\n    );\n\n    return xbox_live_result<void>(Utils::ConvertHr(hr), \"\");\n}\n\nstruct user_statistics_service::HandlerContext\n{\n    XblFunctionContext internalContext;\n    std::function<void(statistic_change_event_args)> statisticChangedHandler;\n};\n\nfunction_context user_statistics_service::add_statistic_changed_handler(_In_ std::function<void(statistic_change_event_args)> handler)\n{\n    auto context = new HandlerContext{};\n    context->statisticChangedHandler = std::move(handler);\n\n    context->internalContext = XblUserStatisticsAddStatisticChangedHandler(\n        m_xblContext,\n        [](XblStatisticChangeEventArgs args, void* context)\n        {\n            auto handler = static_cast<HandlerContext*>(context);\n            if (handler && handler->statisticChangedHandler)\n            {\n                handler->statisticChangedHandler(args);\n            }\n        }, context);\n\n    return context;\n}\n\nvoid user_statistics_service::remove_statistic_changed_handler(_In_ function_context functionContext)\n{\n    if (functionContext != nullptr)\n    {\n        auto context{ static_cast<HandlerContext*>(functionContext) };\n        XblUserStatisticsRemoveStatisticChangedHandler(m_xblContext, context->internalContext);\n        delete context;\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END\n\nXBL_WARNING_POP"
  },
  {
    "path": "Include/xsapi-cpp/impl/xbox_live_app_config.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"public_utils.h\"\n#include \"Xal/xal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nstd::shared_ptr<xbox_live_app_config> xbox_live_app_config::get_app_config_singleton()\n{\n    static std::shared_ptr<xbox_live_app_config> instance = std::shared_ptr<xbox_live_app_config>(new xbox_live_app_config());\n    return instance;\n}\n\nuint32_t xbox_live_app_config::title_id() const\n{\n    uint32_t titleId{};\n    XalGetTitleId(&titleId);\n    return titleId;\n}\n\nstring_t xbox_live_app_config::scid() const\n{\n\n    const char* scid{ nullptr };\n    XblGetScid(&scid);\n    return Utils::StringTFromUtf8(scid);\n}\n\nstring_t xbox_live_app_config::environment() const\n{\n    // Not exposed from C APIs.\n    return string_t();\n}\n\nstring_t xbox_live_app_config::sandbox() const\n{\n    size_t sandboxSize = XalGetSandboxSize();\n    string_t sandboxStr;\n    char* sandbox = new (std::nothrow) char[sandboxSize];\n    if (sandbox != nullptr)\n    {\n        if (SUCCEEDED(XalGetSandbox(sandboxSize, sandbox, nullptr)))\n        {\n            sandboxStr = Utils::StringTFromUtf8(sandbox);\n        }\n        delete[] sandbox;\n    }\n    return sandboxStr;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Include/xsapi-cpp/impl/xbox_live_context.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n// TODO exclude this from build and include in xbox_live_context.h. Circular dependency currently prevents this,\n// but after services are migrated that will work.\n#if !XSAPI_NO_PPL\n\n#include \"xsapi-c/xbox_live_context_c.h\"\n\n#include \"public_utils.h\"\n\n#include \"xsapi-cpp/xbox_live_context.h\"\n#include \"xsapi-cpp/events.h\"\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#include \"xsapi-cpp/notification_service.h\"\n#endif\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxbox_live_context::xbox_live_context(_In_ XblUserHandle user)\n{\n    HRESULT hr = XblContextCreateHandle(user, &m_handle);\n    if (FAILED(hr)) throw std::runtime_error(\"XblContextCreateHandle failed\");\n    XblSetApiType(XblApiType::XblCPPApi);\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\n    // Unlike the rest of the services, notification_service needs to maintain state\n    // That is because of the differences between C-APIs for subscribing for RTA events\n    // and the C++ subscribe_to_notifications call\n    m_notificationService = std::make_shared<notification::notification_service>(m_handle);\n#endif\n}\n\nxbox_live_context::xbox_live_context(_In_ XblContextHandle xboxLiveContextHandle)\n{\n    HRESULT hr = XblContextDuplicateHandle(xboxLiveContextHandle, &m_handle);\n    if (FAILED(hr)) throw std::runtime_error(\"XblContextCreateHandle failed\");\n    XblSetApiType(XblApiType::XblCPPApi);\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\n    // Unlike the rest of the services, notification_service needs to maintain state\n    // That is because of the differences between C-APIs for subscribing for RTA events\n    // and the C++ subscribe_to_notifications call\n    m_notificationService = std::make_shared<notification::notification_service>(m_handle);\n#endif\n}\n\nxbox_live_context::~xbox_live_context()\n{\n    XblContextCloseHandle(m_handle);\n}\n\nXblUserHandle xbox_live_context::user()\n{\n    XblUserHandle userHandle = nullptr;\n    XblContextGetUser(m_handle, &userHandle);\n    return userHandle;\n}\n\nXblContextHandle xbox_live_context::handle()\n{\n    XblContextHandle contextHandle = nullptr;\n    XblContextDuplicateHandle(m_handle, &contextHandle);\n    return contextHandle;\n}\n\nstring_t xbox_live_context::xbox_live_user_id()\n{\n    stringstream_t ss;\n    uint64_t xuid;\n    XblContextGetXboxUserId(m_handle, &xuid);\n    ss << xuid;\n    return ss.str();\n}\n\nstd::shared_ptr<xbox_live_context_settings> xbox_live_context::settings()\n{\n    return std::make_shared<xbox_live_context_settings>(m_handle);\n}\n\nstd::shared_ptr<xbox_live_app_config> xbox_live_context::application_config()\n{\n    return xbox_live_app_config::get_app_config_singleton();\n}\n\ntitle_storage::title_storage_service xbox_live_context::title_storage_service()\n{\n    return title_storage::title_storage_service(m_handle);\n}\n\nsocial::profile_service xbox_live_context::profile_service()\n{\n    return social::profile_service(m_handle);\n}\n\nprivacy::privacy_service xbox_live_context::privacy_service()\n{\n    return privacy::privacy_service(m_handle);\n}\n\n#if !defined(XBOX_LIVE_CREATORS_SDK)\nleaderboard::leaderboard_service xbox_live_context::leaderboard_service()\n{\n    return leaderboard::leaderboard_service(m_handle);\n}\n\nsocial::social_service xbox_live_context::social_service()\n{\n    return social::social_service(m_handle);\n}\n\nsocial::reputation_service xbox_live_context::reputation_service()\n{\n    return social::reputation_service(m_handle);\n}\n\nachievements::achievement_service xbox_live_context::achievement_service()\n{\n    return achievements::achievement_service(m_handle);\n}\n\nuser_statistics::user_statistics_service xbox_live_context::user_statistics_service()\n{\n    return user_statistics::user_statistics_service(m_handle);\n}\n\nmultiplayer::multiplayer_service xbox_live_context::multiplayer_service()\n{\n    return multiplayer::multiplayer_service(m_handle);\n}\n\nmatchmaking::matchmaking_service xbox_live_context::matchmaking_service()\n{\n    return matchmaking::matchmaking_service(m_handle);\n}\n\nstd::shared_ptr<real_time_activity::real_time_activity_service> xbox_live_context::real_time_activity_service()\n{\n    return std::shared_ptr<real_time_activity::real_time_activity_service>(new real_time_activity::real_time_activity_service(m_handle));\n}\n\nsystem::string_service xbox_live_context::string_service()\n{\n    return system::string_service(m_handle);\n}\n\npresence::presence_service xbox_live_context::presence_service()\n{\n    return presence::presence_service(m_handle);\n}\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\nstd::shared_ptr<notification::notification_service> xbox_live_context::notification_service()\n{\n    return m_notificationService;\n}\n#endif\n\n#ifdef XSAPI_EVENTS_SERVICE\nevents::events_service xbox_live_context::events_service()\n{\n    return events::events_service(m_handle);\n}\n#endif // XSAPI_EVENTS_SERVICE\n#endif // !defined(XBOX_LIVE_CREATORS_SDK)\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#endif"
  },
  {
    "path": "Include/xsapi-cpp/impl/xbox_live_context_settings.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/xbox_live_global_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxbox_live_context_settings::xbox_live_context_settings(XblContextHandle xblContextHandle)\n{\n    XblContextDuplicateHandle(xblContextHandle, &m_xblContextHandle);\n}\n\nxbox_live_context_settings::~xbox_live_context_settings()\n{\n    XblContextCloseHandle(m_xblContextHandle);\n}\n\nstruct xbox_live_context_settings::HandlerContext\n{\n    XblFunctionContext internalContext{ 0 };\n    std::function<void(const xbox::services::xbox_service_call_routed_event_args&)> handler;\n};\n\nfunction_context xbox_live_context_settings::add_service_call_routed_handler(\n    _In_ std::function<void(const xbox::services::xbox_service_call_routed_event_args&)> handler\n)\n{\n    auto context = new HandlerContext{};\n    context->handler = std::move(handler);\n\n    context->internalContext = XblAddServiceCallRoutedHandler(\n        [](XblServiceCallRoutedArgs internalArgs, void* context)\n    {\n        auto handlerContext{ static_cast<HandlerContext*>(context) };\n        handlerContext->handler(xbox_service_call_routed_event_args{ internalArgs });\n    }, context);\n\n    return context;\n}\n\nvoid xbox_live_context_settings::remove_service_call_routed_handler(_In_ function_context context)\n{\n    auto handlerContext{ static_cast<HandlerContext*>(context) };\n    XblRemoveServiceCallRoutedHandler(handlerContext->internalContext);\n    delete handlerContext;\n}\n\nstd::chrono::seconds xbox_live_context_settings::long_http_timeout() const\n{\n    uint32_t timeout;\n    XblContextSettingsGetLongHttpTimeout(m_xblContextHandle, &timeout);\n    return std::chrono::seconds(timeout);\n}\n\nvoid xbox_live_context_settings::set_long_http_timeout(_In_ std::chrono::seconds value)\n{\n    XblContextSettingsSetLongHttpTimeout(m_xblContextHandle, static_cast<uint32_t>(value.count()));\n}\n\nstd::chrono::seconds xbox_live_context_settings::xbox_live_context_settings::http_retry_delay() const\n{\n    uint32_t delay;\n    XblContextSettingsGetHttpRetryDelay(m_xblContextHandle, &delay);\n    return std::chrono::seconds(delay);\n}\n\nvoid xbox_live_context_settings::set_http_retry_delay(_In_ std::chrono::seconds value)\n{\n    XblContextSettingsSetHttpRetryDelay(m_xblContextHandle, static_cast<uint32_t>(value.count()));\n}\n\nstd::chrono::seconds xbox_live_context_settings::http_timeout_window() const\n{\n    uint32_t window;\n    XblContextSettingsGetHttpTimeoutWindow(m_xblContextHandle, &window);\n    return std::chrono::seconds(window);\n}\n\nvoid xbox_live_context_settings::set_http_timeout_window(_In_ std::chrono::seconds value)\n{\n    XblContextSettingsSetHttpTimeoutWindow(m_xblContextHandle, static_cast<uint32_t>(value.count()));\n}\n\nstd::chrono::seconds xbox_live_context_settings::websocket_timeout_window() const\n{\n    uint32_t window;\n    XblContextSettingsGetWebsocketTimeoutWindow(m_xblContextHandle, &window);\n    return std::chrono::seconds(window);\n}\n\nvoid xbox_live_context_settings::set_websocket_timeout_window(_In_ std::chrono::seconds value)\n{\n    XblContextSettingsSetWebsocketTimeoutWindow(m_xblContextHandle, static_cast<uint32_t>(value.count()));\n}\n\nbool xbox_live_context_settings::use_core_dispatcher_for_event_routing() const\n{\n    return false;\n}\n\nvoid xbox_live_context_settings::set_use_core_dispatcher_for_event_routing(_In_ bool value)\n{\n    UNREFERENCED_PARAMETER(value);\n}\n\nvoid xbox_live_context_settings::disable_asserts_for_xbox_live_throttling_in_dev_sandboxes(\n    _In_ xbox_live_context_throttle_setting setting\n)\n{\n    UNREFERENCED_PARAMETER(setting);\n    XblDisableAssertsForXboxLiveThrottlingInDevSandboxes(XblConfigSetting::ThisCodeNeedsToBeChanged);\n}\n\nvoid xbox_live_context_settings::disable_asserts_for_maximum_number_of_websockets_activated(\n    _In_ xbox_live_context_recommended_setting setting\n)\n{\n    UNREFERENCED_PARAMETER(setting);\n}\n\nbool xbox_live_context_settings::use_crossplatform_qos_servers() const\n{\n    bool value;\n    XblContextSettingsGetUseCrossPlatformQosServers(m_xblContextHandle, &value);\n    return value;\n}\n\nvoid xbox_live_context_settings::set_use_crossplatform_qos_servers(_In_ bool value)\n{\n    XblContextSettingsSetUseCrossPlatformQosServers(m_xblContextHandle, value);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/impl/xbox_service_call_routed_event_args.hpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"public_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxbox_service_call_routed_event_args::xbox_service_call_routed_event_args(\n    _In_ const XblServiceCallRoutedArgs& internalArgs\n)\n{\n    m_callHandle = HCHttpCallDuplicateHandle(internalArgs.call);\n    m_responseCount = static_cast<long>(internalArgs.responseCount);\n    m_fullResponseFormatted = Utils::StringTFromUtf8(internalArgs.fullResponseFormatted);\n}\n\nxbox_service_call_routed_event_args::xbox_service_call_routed_event_args(const xbox_service_call_routed_event_args& other)\n    : m_responseCount(other.m_responseCount),\n    m_fullResponseFormatted(other.m_fullResponseFormatted)\n{\n    m_callHandle = HCHttpCallDuplicateHandle(other.m_callHandle);\n}\n\nxbox_service_call_routed_event_args& xbox_service_call_routed_event_args::operator=(xbox_service_call_routed_event_args other)\n{\n    std::swap(m_callHandle, other.m_callHandle);\n    m_responseCount = other.m_responseCount;\n    m_fullResponseFormatted = other.m_fullResponseFormatted;\n    return *this;\n}\n\nxbox_service_call_routed_event_args::~xbox_service_call_routed_event_args()\n{\n    HCHttpCallCloseHandle(m_callHandle);\n}\n\nstring_t xbox_service_call_routed_event_args::xbox_user_id() const\n{\n    // TODO a lot of these fields are not exposed from the hc_call_handle. Need to expose in libHttpClient to expose them from xsapi.\n    return string_t{};\n}\n\nstring_t xbox_service_call_routed_event_args::http_method() const\n{\n    return string_t();\n}\n\nstring_t xbox_service_call_routed_event_args::uri() const\n{\n    const char* url;\n    HCHttpCallGetRequestUrl(m_callHandle, &url);\n    return Utils::StringTFromUtf8(url);\n}\n\nstring_t xbox_service_call_routed_event_args::request_headers() const\n{\n    return string_t();\n}\n\nhttp_call_request_message xbox_service_call_routed_event_args::request_body() const\n{\n    return http_call_request_message();\n}\n\nuint32_t xbox_service_call_routed_event_args::response_count() const\n{\n    return static_cast<uint32_t>(m_responseCount);\n}\n\nstring_t xbox_service_call_routed_event_args::response_headers() const\n{\n    uint32_t numHeaders;\n    HCHttpCallResponseGetNumHeaders(m_callHandle, &numHeaders);\n\n    stringstream_t ss;\n    for (uint32_t i = 0; i < numHeaders; ++i)\n    {\n        const char* headerName;\n        const char* headerValue;\n        HCHttpCallResponseGetHeaderAtIndex(m_callHandle, i, &headerName, &headerValue);\n        ss << Utils::StringTFromUtf8(headerName) << _T(\" : \") << Utils::StringTFromUtf8(headerValue) << _T(\"\\r\\n\");\n    }\n    return ss.str();\n}\n\nstring_t xbox_service_call_routed_event_args::response_body() const\n{\n    const char* responseBody;\n    HCHttpCallResponseGetResponseString(m_callHandle, &responseBody);\n    return Utils::StringTFromUtf8(responseBody);\n}\n\nstring_t xbox_service_call_routed_event_args::etag() const\n{\n    const char* etag;\n    HCHttpCallResponseGetHeader(m_callHandle, \"ETag\", &etag);\n    return Utils::StringTFromUtf8(etag);\n}\n\nstring_t xbox_service_call_routed_event_args::token() const\n{\n    const char* token;\n    HCHttpCallResponseGetHeader(m_callHandle, \"Authorization\", &token);\n    return Utils::StringTFromUtf8(token);\n}\n\nstring_t xbox_service_call_routed_event_args::signature() const\n{\n    const char* signature;\n    HCHttpCallResponseGetHeader(m_callHandle, \"Signature\", &signature);\n    return Utils::StringTFromUtf8(signature);\n}\n\nuint32_t xbox_service_call_routed_event_args::http_status() const\n{\n    uint32_t httpStatus;\n    HCHttpCallResponseGetStatusCode(m_callHandle, &httpStatus);\n    return httpStatus;\n}\n\nconst string_t& xbox_service_call_routed_event_args::full_response_formatted() const\n{\n    return m_fullResponseFormatted;\n}\n\nchrono_clock_t::time_point xbox_service_call_routed_event_args::request_time() const\n{\n    return chrono_clock_t::time_point();\n}\n\nchrono_clock_t::time_point xbox_service_call_routed_event_args::response_time() const\n{\n    return chrono_clock_t::time_point();\n}\n\nstd::chrono::milliseconds xbox_service_call_routed_event_args::elapsed_call_time() const\n{\n    return std::chrono::duration_cast<std::chrono::milliseconds>(request_time() - request_time());\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Include/xsapi-cpp/leaderboard.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"types.h\"\n#include <cstdint>\n#include <vector>\n#include \"xbox_live_app_config.h\"\n#include \"xsapi-c/leaderboard_c.h\"\n\n#define NO_SKIP_XUID (_T(\"\"))\n#define NO_XUID (_T(\"\"))\n#define NO_SOCIAL_GROUP (_T(\"\"))\n#define NO_SKIP_RANK (0)\n#define NO_MAX_ITEMS (0)\n#define NO_CONTINUATION (_T(\"\"))\n#define NO_SORT_ORDER (_T(\"\"))\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n\n    /// <summary>\n    /// Contains classes and enumerations that let you retrieve \n    /// leaderboard information from Xbox Live.\n    /// </summary>\n    namespace leaderboard {\n\n/// <summary>Enumerates the data type of a leaderboard statistic.</summary>\nenum class leaderboard_stat_type\n{\n    /// <summary>Unsigned 64 bit integer.</summary>\n    stat_uint64,\n\n    /// <summary>Boolean.</summary>\n    stat_boolean,\n\n    /// <summary>Double.</summary>\n    stat_double,\n\n    /// <summary>String.</summary>\n    stat_string,\n\n    /// <summary>Unknown.</summary>\n    stat_other\n};\n\n#if !XSAPI_NO_PPL\n\n/// <summary>\n/// Represents a column in a collection of leaderboard items.\n/// </summary>\nclass leaderboard_column\n{\npublic:\n    inline leaderboard_column(\n        std::shared_ptr<char> buffer, \n        const XblLeaderboardColumn& leaderboardColumn\n    );\n\n    /// <summary>\n    /// The name the statistic displayed in the column.\n    /// </summary>\n    inline string_t stat_name() const;\n\n    /// <summary>\n    /// The property type of the statistic in the column.\n    /// </summary>\n    inline leaderboard_stat_type stat_type() const;\n\nprivate:\n    std::shared_ptr<char> m_buffer;\n    XblLeaderboardColumn m_leaderboardColumn;\n};\n\n/// <summary>\n/// Represents a row in a collection of leaderboard items.\n/// </summary>\nclass leaderboard_row\n{\npublic:\n    inline leaderboard_row(\n        std::shared_ptr<char> buffer, \n        const XblLeaderboardRow& leaderboardRow\n    );\n\n    /// <summary>\n    /// The Gamertag of the player.\n    /// </summary>\n    inline string_t gamertag() const;\n\n    /// <summary>\n    /// The Xbox user ID of the player.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// The percentile rank of the player.\n    /// </summary>\n    inline double percentile() const;\n\n    /// <summary>\n    /// The rank of the player.\n    /// </summary>\n    inline uint32_t rank() const;\n\n    /// <summary>\n    /// Values for each column in the leaderboard row for the player.\n    /// </summary>\n    inline std::vector<string_t> column_values() const;\n\nprivate:\n    std::shared_ptr<char> m_buffer;\n    XblLeaderboardRow m_leaderboardRow;\n};\n\n/// <summary>\n/// Represents the results of a leaderboard request.\n/// </summary>\nclass leaderboard_result\n{\npublic:\n    inline leaderboard_result() { }\n    inline leaderboard_result(\n        std::shared_ptr<char> buffer,\n        const XblContextHandle& xblContext\n    );\n        \n    /// <summary>\n    /// The total number of rows in the leaderboard results.\n    /// </summary>\n    inline uint32_t total_row_count() const;\n\n    /// <summary>\n    /// The collection of columns in the leaderboard results.\n    /// </summary>\n    inline const std::vector<leaderboard_column>& columns() const;\n\n    /// <summary>\n    /// The collection of rows in the leaderboard results.\n    /// </summary>\n    inline const std::vector<leaderboard_row>& rows() const;\n\n    /// <summary>\n    /// Indicates whether there is a next page of results.\n    /// </summary>\n    /// <returns>True if there is another page of results; otherwise false.</returns>\n    inline bool has_next() const;\n\n#if !defined(XBOX_LIVE_CREATORS_SDK)\n    /// <summary>\n    /// Get the next page of a previous leaderboard call using the same service config Id and leaderboard name.\n    /// </summary>\n    /// <param name=\"maxItems\">The maximum number of items to return.</param>\n    /// <returns>A leaderboard_results object that contains the next set of results.</returns>\n    /// <remarks>\n    /// This query is only to be used to retrieve a leaderboard in a pre stats 2017 system\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET /scids/{scid}/leaderboards/{leaderboardname}?\n    ///  [maxItems={maxItems}]\n    ///  [continuationToken={token}]\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_next(_In_ uint32_t maxItems);\n#endif\n\nprivate:\n    std::shared_ptr<char> m_buffer;\n    XblLeaderboardResult m_leaderboardResult{};\n    XblContextHandle m_xblContext{};\n    std::vector<leaderboard_column> m_columns;\n    std::vector<leaderboard_row> m_rows;\n};\n\n#if !defined(XBOX_LIVE_CREATORS_SDK)\n/// <summary>\n/// Represents the leaderboard service.\n/// </summary>\nclass leaderboard_service\n{\npublic:\n    /// <summary>\n    /// Get a leaderboard for a single leaderboard given a service configuration ID and a leaderboard name.\n    /// </summary>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"name\">The name of the leaderboard.</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>\n    /// A leaderboard_result object containing a collection of the leaderboard columns and rows,\n    /// ordered by player rank descending.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET /scids/{scid}/leaderboards/{leaderboardname}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard(\n        _In_ const string_t& scid,\n        _In_ const string_t& name,\n        _In_ const std::vector<string_t>& additionalColumnNames = std::vector<string_t>()\n        );\n\n    /// <summary>\n    /// Get a leaderboard for a single leaderboard given a service configuration ID and a leaderboard name.\n    /// </summary>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"name\">The name of the leaderboard.</param>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.\n    /// See Microsoft::Xbox::Services::Social::SocialGroupConstants for the latest options.</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>\n    /// A leaderboard_result object containing a collection of the leaderboard columns and rows,\n    /// ordered by player rank descending.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V3 GET /scids/{scid}/leaderboards/{leaderboardname}?include=valuemetadata&amp;xuid={xuid}&amp;viewTarget=people&amp;view=people\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard(\n        _In_ const string_t& scid,\n        _In_ const string_t& name,\n        _In_ const string_t& xuid,\n        _In_ const string_t& socialGroup,\n        _In_ uint32_t maxItems = 0,\n        _In_ const std::vector<string_t>& additionalColumnNames = std::vector<string_t>()\n        );\n\n    /// <summary>\n    /// Get a page of leaderboard results for a single leaderboard given a service configuration ID\n    /// and a leaderboard name.\n    /// </summary>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"name\">The name of the leaderboard.</param>\n    /// <param name=\"skipToRank\">The number of ranks to skip before returning results.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>A leaderboard_result object containing a collection of the leaderboard columns and rows.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET \n    /// /scids/{scid}/leaderboards/{leaderboardname}?[&amp;skipItems={skipItems}][&amp;maxItems={maxItems}]\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard(\n        _In_ const string_t& scid,\n        _In_ const string_t& name,\n        _In_ uint32_t skipToRank,\n        _In_ uint32_t maxItems = 0,\n        _In_ const std::vector<string_t>& additionalColumnNames = std::vector<string_t>()\n        );\n\n    /// <summary>\n    /// Get a page of leaderboard results for a single leaderboard given a service configuration ID\n    /// and a leaderboard name.\n    /// </summary>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"name\">The name of the leaderboard.</param>\n    /// <param name=\"skipToRank\">The number of ranks to skip before returning results.</param>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.\n    /// See Microsoft::Xbox::Services::Social::SocialGroupConstants for the latest options.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>A leaderboard_result object containing a collection of the leaderboard columns and rows.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V3 GET \n    /// /scids/{scid}/leaderboards/{leaderboardname}?[&amp;skipItems={skipItems}][&amp;maxItems={maxItems}]&amp;include=valuemetadata&amp;xuid={xuid}&amp;viewTarget=people&amp;view=people\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard(\n        _In_ const string_t& scid,\n        _In_ const string_t& name,\n        _In_ uint32_t skipToRank,\n        _In_ const string_t& xuid,\n        _In_ const string_t& socialGroup,\n        _In_ uint32_t maxItems = 0,\n        _In_ const std::vector<string_t>& additionalColumnNames = std::vector<string_t>()\n        );\n\n    /// <summary>\n    /// Get a leaderboard starting at a specified player, regardless of the player's rank or score, ordered by\n    /// the player's percentile rank.\n    /// </summary>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"name\">The name of the leaderboard.</param>\n    /// <param name=\"skipToXuid\">The Xbox user ID of the player to skip to before retrieving results.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>\n    /// A leaderboard_result object containing a collection of the leaderboard columns and rows.\n    /// The result page is ordered by percentile rank, with the specified player in the last position of\n    /// the page for predefined views, or in the middle for stat leaderboard views.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// There is no continuation Token provided for this query.\n    ///\n    /// Calls V1 GET \n    /// /scids/{scid}/leaderboards/{leaderboardname}?[&amp;skipToUser={xuid}][&amp;maxItems={maxItems}]\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard_skip_to_xuid(\n        _In_ const string_t& scid,\n        _In_ const string_t& name,\n        _In_ const string_t& skipToXuid = string_t(),\n        _In_ uint32_t maxItems = 0,\n        _In_ const std::vector<string_t>& additionalColumnNames = std::vector<string_t>()\n        );\n\n\n    /// <summary>\n    /// Get a leaderboard starting at a specified player, regardless of the player's rank or score, ordered by\n    /// the player's percentile rank.\n    /// </summary>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"name\">The name of the leaderboard.</param>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.\n    /// See Microsoft::Xbox::Services::Social::SocialGroupConstants for the latest options.</param>\n    /// <param name=\"skipToXuid\">The Xbox user ID of the player to skip to before retrieving results.</param>\n    /// <param name=\"sortOrder\">A value indicating the sort order for the returned leaderboard result.\n    /// The possible values are 'ascending' or 'descending', without quotes.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>\n    /// A leaderboard_result object containing a collection of the leaderboard columns and rows.\n    /// The result page is ordered by percentile rank, with the specified player in the last position of\n    /// the page for predefined views, or in the middle for stat leaderboard views.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// There is no continuation Token provided for this query.\n    ///\n    /// Calls V1 GET \n    ///  /scids/{scid}/leaderboards/{leaderboardname}?[&skipToUser={xuid}][&maxItems={maxItems}]\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard_skip_to_xuid(\n        _In_ const string_t& scid,\n        _In_ const string_t& name,\n        _In_ const string_t& xuid,\n        _In_ const string_t& socialGroup,\n        _In_ const string_t& skipToXuid,\n        _In_ uint32_t maxItems = 0,\n        _In_ const std::vector<string_t>& additionalColumnNames = std::vector<string_t>()\n        );\n\n    /// <summary>\n    /// Get an unsorted leaderboard that shows members of a specified social group.\n    /// </summary>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statName\">The name of the statistic to get a leaderboard for.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.  \n    /// You can pass either \"Favorites\" or \"People\"</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <returns>\n    /// A LeaderboardResult object containing a collection of the leaderboard columns and rows.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET \n    /// https://leaderboards.xboxlive.com/users/xuid({xuid})/scids/{scid}/stats/{statname}/people/{all|favorites}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard_for_social_group(\n        _In_ const string_t& xuid,\n        _In_ const string_t& scid,\n        _In_ const string_t& statName,\n        _In_ const string_t& socialGroup,\n        _In_ uint32_t maxItems = 0\n        );\n\n    /// <summary>\n    /// Get a sorted leaderboard that shows members of a specified social group.\n    /// </summary>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statName\">The name of the statistic to get a leaderboard for.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.  \n    /// You can pass either \"Favorites\" or \"People\"</param>\n    /// <param name=\"sortOrder\">A value indicating the sort order for the returned leaderboard result.\n    /// The possible values are 'ascending' or 'descending', without quotes.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <returns>An object containing a collection of the leaderboard columns and rows</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET \n    /// https://leaderboards.xboxlive.com/users/xuid({xuid})/scids/{scid}/stats/{statname}/people/{all|favorites}[?sort=descending|ascending]\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard_for_social_group(\n        _In_ const string_t& xuid,\n        _In_ const string_t& scid,\n        _In_ const string_t& statName,\n        _In_ const string_t& socialGroup,\n        _In_ const string_t& sortOrder,\n        _In_ uint32_t maxItems = 0\n        );\n\n    /// <summary>\n    /// Get a sorted leaderboard, starting at a specified rank, that shows members of a specified social group.\n    /// </summary>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statName\">The name of the statistic to get a leaderboard for.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.\n    /// See Microsoft::Xbox::Services::Social::SocialGroupConstants for the latest options.</param>\n    /// <param name=\"skipToRank\">The number of ranks to skip before retrieving results.</param>\n    /// <param name=\"sortOrder\">A value indicating the sort order for the returned leaderboard result.\n    /// The possible values are 'ascending' or 'descending', without quotes.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <param name=\"additionalColumnNames\">The name of the stats for the additionalColumns. (Optional)</param>\n    /// <returns>\n    /// A leaderboard_result object containing a collection of the leaderboard columns and rows.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET \n    /// https://leaderboards.xboxlive.com/users/xuid({xuid})/scids/{scid}/stats/{statname}/people/{all|favorites}[?sort=descending|ascending]&amp;skipToRank={skipToUser}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard_for_social_group_skip_to_rank(\n        _In_ const string_t& xuid,\n        _In_ const string_t& scid,\n        _In_ const string_t& statName,\n        _In_ const string_t& socialGroup,\n        _In_ uint32_t skipToRank,\n        _In_ const string_t& sortOrder,\n        _In_ uint32_t maxItems = 0\n        );\n\n    /// <summary>\n    /// Get a sorted leaderboard, starting at a specified player, that shows members of a specified social group.\n    /// </summary>\n    /// <param name=\"xuid\">The Xbox user ID of the requesting user.</param>\n    /// <param name=\"scid\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statName\">The name of the statistic to get a leaderboard for.</param>\n    /// <param name=\"socialGroup\">The name of the group of users to get get leaderboard results for.\n    /// See Microsoft::Xbox::Services::Social::SocialGroupConstants for the latest options.</param>\n    /// <param name=\"skipToXuid\">The Xbox user ID of the player to skip to before retrieving results.</param>\n    /// <param name=\"sortOrder\">A value indicating the sort order for the returned leaderboard result.\n    /// The possible values are 'ascending' or 'descending', without quotes.</param>\n    /// <param name=\"maxItems\">The maximum number of items to retrieve. If this value is 0, the server defaults to 10. (Optional)</param>\n    /// <returns>\n    /// A leaderboard_result object that contains a page of leaderboard results around the specified player regardless\n    /// of that player's rank or score.\n    /// The result page is ordered by percentile rank, with the specified player in the last position of\n    /// the page for predefined views, or in the middle for stat leaderboard views.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET \n    /// https://leaderboards.xboxlive.com/users/xuid({xuid})/scids/{scid}/stats/{statname}/people/{all|favorites}[?sort=descending|ascending]&amp;skipToUser={skipToUser}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<leaderboard_result>> get_leaderboard_for_social_group_skip_to_xuid(\n        _In_ const string_t& xuid,\n        _In_ const string_t& scid,\n        _In_ const string_t& statName,\n        _In_ const string_t& socialGroup,\n        _In_ const string_t& skipToXuid,\n        _In_ const string_t& sortOrder,\n        _In_ uint32_t maxItems = 0\n        );\n\n    inline leaderboard_service(const leaderboard_service& other);\n    inline leaderboard_service& operator=(leaderboard_service other);\n    inline ~leaderboard_service();\n\nprivate:\n    inline leaderboard_service(_In_ XblContextHandle contextHandle);\n    XblContextHandle m_xblContext;\n       \n    inline XblSocialGroupType XblSocialGroupTypeFromString(string_t socialGroup);\n    inline XblLeaderboardSortOrder XblLeaderboardSortOrderFromString(string_t socialGroup);\n\n    friend xbox_live_context;\n};\n#endif\n\n#endif\n}}}\n\n#if !XSAPI_NO_PPL\n#include \"impl/leaderboard.hpp\"\n#endif\n"
  },
  {
    "path": "Include/xsapi-cpp/matchmaking.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/matchmaking_c.h\"\n#include \"xsapi-cpp/multiplayer.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n    /// <summary>\n    /// Contains classes and enumerations that let you match\n    /// players for a multiplayer session.\n    /// </summary>\n    namespace matchmaking {\n\n/// <summary>\n/// Defines values used to indicate whether a match ticket is for a new\n/// game session or an existing session.\n/// </summary>\nenum class preserve_session_mode\n{\n    /// <summary>\n    /// The server returned an unrecognized response.\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// Always use an existing game session. This is for matching more players\n    /// for a game session that is already created or in progress.\n    /// </summary>\n    always,\n\n    /// <summary>\n    /// Never use an existing game session. This is for matching players\n    /// for a new game session.\n    /// </summary>\n    never\n};\n\n/// <summary>\n/// Defines values used to indicate the status of the match request.\n/// </summary>\nenum class ticket_status\n{\n    /// <summary>\n    /// The status of the match request has not been returned by the server yet\n    /// or the server returned an unrecognized response.\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// Matchmaking has not found a match and the search\n    /// request has expired according to its give up duration.\n    /// </summary>\n    expired,\n\n    /// <summary>\n    /// Matchmaking has not found a match yet and it is\n    /// still searching.\n    /// </summary>\n    searching,\n\n    /// <summary>\n    /// Matchmaking has found a match and the ticket contains a\n    /// reference to the session that is to be created.\n    /// </summary>\n    found,\n\n    /// <summary>\n    /// Matchmaking has been canceled for this ticket.\n    /// </summary>\n    canceled\n};\n\n/// <summary>\n/// Represents a server response to a create match ticket request.\n/// </summary>\nclass create_match_ticket_response\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline create_match_ticket_response();\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline create_match_ticket_response(\n        XblCreateMatchTicketResponse response\n        );\n\n    /// <summary>\n    /// Ticket ID of a match request.\n    /// </summary>\n    inline string_t match_ticket_id() const;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    inline std::chrono::seconds estimated_wait_time() const;\n\nprivate:\n    XblCreateMatchTicketResponse m_createMatchTicketResponse;\n};\n\n/// <summary>\n/// Represents a server response to a request for match ticket details.\n/// </summary>\nclass match_ticket_details_response\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline match_ticket_details_response();\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline match_ticket_details_response(\n        std::shared_ptr<char> buffer\n        );\n\n    /// <summary>\n    /// Status of a match request.\n    /// </summary>\n    inline ticket_status match_status() const;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    inline std::chrono::seconds estimated_wait_time() const;\n\n    /// <summary>\n    /// An enum value to specify whether the match should preserve the session on which the match has been requested.\n    /// </summary>\n    inline preserve_session_mode preserve_session() const;\n\n    /// <summary>\n    /// The session on which the match was requested.\n    /// </summary>\n    inline xbox::services::multiplayer::multiplayer_session_reference ticket_session() const;\n\n    /// <summary>\n    /// The session on which a match request has been found.\n    /// </summary>\n    inline xbox::services::multiplayer::multiplayer_session_reference target_session() const;\n\n    /// <summary>\n    /// The attributes of a match request.\n    /// </summary>\n    inline web::json::value ticket_attributes() const;\n\nprivate:\n    static inline ticket_status convert_string_to_ticket_status(_In_ const string_t& value);\n\n    static inline preserve_session_mode convert_string_to_preserve_session_mode(_In_ const string_t& value);\n\n    std::shared_ptr<char> m_buffer;\n    XblMatchTicketDetailsResponse m_matchTicketDetailsResponse;\n};\n\n/// <summary>\n/// Represents a server response to a hopper statistics request.\n/// </summary>\nclass hopper_statistics_response\n{\npublic:\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline hopper_statistics_response();\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline hopper_statistics_response(\n        std::shared_ptr<char> buffer\n        );\n\n    /// <summary>\n    /// Name of the hopper in which a match was requested.\n    /// </summary>\n    inline string_t hopper_name() const;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    inline std::chrono::seconds estimated_wait_time() const;\n\n    /// <summary>\n    /// The number of players in the hopper waiting to be matched.\n    /// </summary>\n    inline uint32_t players_waiting_to_match() const;\n\nprivate:\n    std::shared_ptr<char> m_buffer;\n    XblHopperStatisticsResponse m_hopperStatisticsResponse;\n};\n\n/// <summary>\n/// Represents the Matchmaking Service.\n/// </summary>\nclass matchmaking_service\n{\npublic:\n    /// <summary>\n    /// Sends a matchmaking request to the server and returns the match ticket with a ticket id.\n    /// </summary>\n    /// <param name=\"ticketSessionReference\">The multiplayer session to use for the match.</param>\n    /// <param name=\"matchmakingServiceConfigurationId\">The service configuration ID for the match.</param>\n    /// <param name=\"hopperName\">The name of the hopper.</param>\n    /// <param name=\"ticketTimeout\">The maximum time to wait for players to join the session.</param>\n    /// <param name=\"preserveSession\">Indicates if the session should be preserved.</param>\n    /// <param name=\"ticketAttributesJson\">The ticket attributes for the session. (Optional)</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, a new match ticket\n    /// object is returned. The match ticket object contains server returned information such as ticket id and wait\n    /// time, and also contains copies of the title specified data from the ticket data object.</returns>\n    /// <remarks>Calls V103 POST /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}</remarks>\n    inline pplx::task<xbox_live_result<create_match_ticket_response>> create_match_ticket(\n        _In_ const xbox::services::multiplayer::multiplayer_session_reference& ticketSessionReference,\n        _In_ const string_t& matchmakingServiceConfigurationId,\n        _In_ const string_t& hopperName,\n        _In_ const std::chrono::seconds& ticketTimeout,\n        _In_ preserve_session_mode preserveSession,\n        _In_ const web::json::value& ticketAttributesJson = web::json::value()\n        );\n\n    /// <summary>\n    /// Deletes a the match ticket on the server.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service config id that is specific for the title.</param>\n    /// <param name=\"hopperName\">The name of the hopper where the match ticket is located.</param>\n    /// <param name=\"ticketId\">The id of the ticket to delete on the server.</param>\n    /// <returns>The async object for notifying when the operation has been completed.</returns>\n    /// <remarks>Calls V103 DELETE /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/tickets/{ticketId}</remarks>\n    inline pplx::task<xbox_live_result<void>> delete_match_ticket(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& hopperName,\n        _In_ const string_t& ticketId\n        );\n\n    /// <summary>\n    /// Retrieves the properties of a match ticket from the server.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service config id that is specific for the title.</param>\n    /// <param name=\"hopperName\">The name of the hopper where the match ticket is located.</param>\n    /// <param name=\"ticketId\">The ticket id of the match ticket to retrieve.</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, the match\n    /// ticket object with the data for the ticket, including ticket id and wait time information, is returned\n    /// returned from the server.</returns>\n    /// <remarks>Calls V103 GET /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/tickets/{ticketId}</remarks>\n    inline pplx::task<xbox_live_result<match_ticket_details_response>> get_match_ticket_details(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& hopperName,\n        _In_ const string_t& ticketId\n        );\n\n    /// <summary>\n    /// Gets statistics about a hopper such as how many players are in it.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service config id that is specific for the title.</param>\n    /// <param name=\"hopperName\">The name of the hopper to query stats for.</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, an object\n    /// containing statistics about the hopper is returned.</returns>\n    /// <remarks>Calls V103 GET /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/stats</remarks>\n    inline pplx::task<xbox_live_result<hopper_statistics_response>> get_hopper_statistics(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& hopperName\n        );\n\n    inline matchmaking_service(const matchmaking_service& other);\n    inline matchmaking_service& operator=(matchmaking_service other);\n    inline ~matchmaking_service();\n\nprivate:\n    inline matchmaking_service (_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_xblContext;\n    friend xbox_live_context;\n};\n\n}}}\n\n#include \"impl/matchmaking.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/mem.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <new>\n#include <set>\n#include <unordered_set>\n#include <stddef.h>\n#include <map>\n#include <unordered_map>\n#include <queue>\n#include <memory>\n#include <list>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nclass xsapi_memory\n{\npublic:\n    static inline _Ret_maybenull_ _Post_writable_byte_size_(dwSize) void* mem_alloc(\n        _In_ size_t dwSize\n        );\n\n    static inline void mem_free(\n        _In_opt_ void* pAddress\n        );\n\nprivate:\n    xsapi_memory() = delete;\n};\n\nclass xsapi_memory_buffer\n{\npublic:\n    xsapi_memory_buffer(_In_ size_t dwSize)\n    {\n        m_pBuffer = xsapi_memory::mem_alloc(dwSize);\n    }\n\n    ~xsapi_memory_buffer()\n    {\n        xsapi_memory::mem_free(m_pBuffer);\n        m_pBuffer = nullptr;\n    }\n\n    void* get()\n    {\n        return m_pBuffer;\n    }\n\nprivate:\n    void* m_pBuffer;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n#include \"impl/mem.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/multiplayer.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#if !XSAPI_NO_PPL\n\n#include \"xsapi-cpp/real_time_activity.h\"\n#include \"xsapi-c/multiplayer_c.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n\n    namespace social {\n        class reputation_service;\n    }\n}}\n\nnamespace xbox { namespace services { \n    /// <summary>\n    /// Contains classes and enumerations for managing a multiplayer session.\n    /// </summary>\n    namespace multiplayer {\n\n/// <summary>\n/// Defines values used to indicate status for visibility or accessibility of a session.\n/// </summary>\nenum class multiplayer_session_visibility\n{\n    /// <summary> Unknown </summary>\n    unknown,\n\n    /// <summary> Ignore the SessionVisibility filter.</summary>\n    any,\n\n    /// <summary>\n    /// The session is private and it's not visible to other users who\n    /// aren't in the session. Joining a visible or private session is a HTTP_E_STATUS_FORBIDDEN.\n    /// </summary>\n    private_session,\n\n    /// <summary>\n    /// The session is visible to other users who aren't in the session, but the session is read-only to them and they can't join.\n    /// Joining an visible causes the service to return HTTP_E_STATUS_BAD_REQUEST (403).\n    /// </summary>\n    visible,\n\n    /// <summary>\n    /// The session is full and cannot be joined by anyone.  \n    /// Joining an open but full session causes the service to return HTTP_E_STATUS_BAD_REQUEST (400).\n    /// </summary>\n    full,\n\n    /// <summary> The session is open and can be joined by anyone. </summary>\n    open\n};\n\n/// <summary>\n/// Defines values used to indicate status for the initialization stage of a session during managed initialization.\n/// </summary>\nenum class multiplayer_initialization_stage\n{\n    /// <summary> Unknown </summary>\n    unknown,\n\n    /// <summary> Initialization stage not set.</summary>\n    none,\n\n    /// <summary> \n    /// Joining initialization stage.  \n    /// Typically matchmaking creates session and puts users into it.  \n    /// SPC has up to the joining timeout to join the session during this phase. \n    /// </summary>\n    joining,\n\n    /// <summary>\n    /// Measuring initialization stage.  Stage where QoS measurement happens.  \n    /// If the title is manually managing QoS, then title will do this stage.  \n    /// Otherwise the Party system will do this when calling RegisterGameSession or RegisterMatchSession.\n    /// </summary>\n    measuring,\n\n    /// <summary>\n    /// Evaluating initialization stage.\n    /// If auto evaluate is true, then this stage is skipped.  \n    /// Otherwise the title will do its own evaluation.  \n    /// This stage is applied even with the SPC is managing QoS.\n    /// </summary>\n    evaluating,\n\n    /// <summary>\n    /// Failed initialization stage.\n    /// If episode 1 didn't succeed, then goes into failed permanently.\n    /// </summary>\n    failed\n};\n\n/// <summary>\n/// Defines values used to indicate the type of metric used to measure matchmaking QoS for a session.\n/// </summary>\nenum class multiplay_metrics\n{\n    /// <summary> Unknown metric </summary>\n    unknown,\n\n    /// <summary> Bandwidth host selection metric </summary>\n    bandwidth_up,\n\n    /// <summary> Bandwidth down host selection metric </summary>\n    bandwidth_down,\n\n    /// <summary> Bandwidth host selection metric </summary>\n    bandwidth,\n\n    /// <summary> Latency host selection metric </summary>\n    latency\n};\n\n/// <summary>\n/// Defines values used to indicate the current network address translation (NAT) settings for a console connecting to Xbox Live.\n/// </summary>\nenum class network_address_translation_setting\n{\n    /// <summary> The server returned an unrecognized response. </summary>\n    unknown,\n\n    /// <summary> Can connect with any other consoles regardless of their NAT setting. </summary>\n    open,\n\n    /// <summary> Consoles using Moderate NAT settings can only connect with other consoles using Moderate or Open settings. </summary>\n    moderate,\n\n    /// <summary> Consoles using Strict NAT settings can only connect with other consoles using Open NAT settings. </summary>\n    strict\n};\n\n/// <summary>\n/// Defines values used to indicate types measurement failures for a session member on the network.\n/// </summary>\nenum class multiplayer_measurement_failure\n{\n    /// <summary> Unknown measurement failure </summary>\n    unknown,\n\n    /// <summary> This player has no measurement failure. </summary>\n    none,\n\n    /// <summary> This player failed because timeout measurement test failed. </summary>\n    timeout,\n\n    /// <summary> This player failed because latency measurement test failed. </summary>\n    latency,\n\n    /// <summary> This player failed because bandwidth up measurement test failed. </summary>\n    bandwidth_up,\n\n    /// <summary> This player failed because bandwidth down measurement test failed. </summary>\n    bandwidth_down,\n\n    /// <summary> This player failed cause someone failed in their group failed. </summary>\n    group,\n\n    /// <summary> This player failed due to a network error such as the user was unreachable. </summary>\n    network,\n\n    /// <summary> This player failed because your episode failed.   This likely happened because there wasn't enough users in the session. </summary>\n    episode\n};\n\n/// <summary>\n/// Defines values used to indicate current status values for a session.\n/// </summary>\nenum class multiplayer_session_status\n{\n    /// <summary>\n    /// The server returned an unrecognized response.\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// The session is active and there is at least one user.\n    /// </summary>\n    active,\n\n    /// <summary>\n    /// The session is inactive. This means no users in the session are\n    /// active or all users left the session.\n    /// </summary>\n    inactive,\n\n    /// <summary>\n    /// The session is reserved. This means one for more users have not\n    /// accepted the session invite.\n    /// </summary>\n    reserved\n};\n\n/// <summary>\n/// Defines values used to indicate restrictions on the users who can join a session.\n/// </summary>\nenum class multiplayer_session_restriction\n{\n    /// <summary> The unrecognized restriction type. </summary>\n    unknown,\n\n    /// <summary> Default value, no restriction </summary>\n    none,\n\n    /// <summary> If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true. </summary>\n    local,\n\n    /// <summary> If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can join without a reservation. </summary>\n    followed\n};\n\n/// <summary>\n/// Defines values used to indicate status for a matchmaking request for a session.\n/// </summary>\nenum class matchmaking_status\n{\n    /// <summary> The server returned an unrecognized response. </summary>\n    unknown,\n\n    /// <summary> Indicates the matchmaking search is not specified.  This status is optional and requires the clientMatchmaking capability. </summary>\n    none,\n\n    /// <summary> Indicates the matchmaking search is still searching. </summary>\n    searching,\n\n    /// <summary> Indicates the matchmaking search has expired. </summary>\n    expired,\n\n    /// <summary> Indicates the matchmaking search has found a session. </summary>\n    found,\n\n    /// <summary> Indicates the matchmaking search has been canceled. </summary>\n    canceled\n};\n\n/// <summary>\n/// Defines values used to indicate status for member of a session.\n/// </summary>\nenum class multiplayer_session_member_status\n{\n    /// <summary>\n    /// Member is reserved for a specific Xbox User ID.  \n    /// This specific member must join the session to fill the reservation.  \n    /// If a reserved member doesn't join before the JoinTimeout they will be removed.\n    /// </summary>\n    reserved,\n\n    /// <summary>\n    /// The member is inactive in the current title.  \n    /// The member may be active in another title as specified by ActiveTitleId.\n    /// If an inactive member doesn't mark themselves as Active within the MemberInactiveTimeout they will be removed from the session.\n    /// </summary>\n    inactive,\n\n    /// <summary>\n    /// When the shell launches the title to start a multiplayer game, the member is marked as ready.\n    /// If a ready member doesn't mark themselves as Active within the MemberReadyTimeout they will be marked as inactive.\n    /// </summary>\n    ready,\n\n    /// <summary> The member is active in the current title. </summary>\n    active\n};\n\n/// <summary>\n/// Defines values used to indicate the mode used when creating or writing to a new Multiplayer service session.\n/// </summary>\nenum class multiplayer_session_write_mode\n{\n    /// <summary>\n    /// Create a new multiplayer session.  Fails if the session already exists.\n    /// </summary>\n    create_new,\n    \n    /// <summary>\n    /// Either update or create a new session. Doesn't care whether the session exists.\n    /// </summary>\n    update_or_create_new,\n    \n    /// <summary>\n    /// Updates an existing multiplayer session; fails if the session doesn't exist.  \n    /// </summary>\n    update_existing,\n    \n    /// <summary>\n    /// Updates an existing multiplayer session.  Fails with HTTP_E_STATUS_PRECOND_FAILED (HTTP status 412) if eTag on local session doesn't match eTag on server. \n    /// Fails if the session does not exist.\n    /// </summary>\n    synchronized_update,\n};\n\nenum class write_session_status\n{\n    /// <summary>\n    /// Unknown write result\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// HTTP Result 403- User does not have proper permission to write a session\n    /// </summary>\n    access_denied,\n\n    /// <summary>\n    /// HTTP Result 201- Write created session successfully\n    /// </summary>\n    created,\n\n    /// <summary>\n    /// HTTP Result 409- Conflict occurred during write about session document\n    /// </summary>\n    conflict,\n\n    /// <summary>\n    /// HTTP Result 404- Session not found\n    /// </summary>\n    handle_not_found,\n\n    /// <summary>\n    /// HTTP Result 412- Session document is not the most recent\n    /// </summary>\n    out_of_sync,\n\n    /// <summary>\n    /// HTTP Result 204- Session deleted successfully\n    /// </summary>\n    session_deleted,\n\n    /// <summary>\n    /// HTTP Result 200- Session updated successfully\n    /// </summary>\n    updated\n};\n\n/// <summary>\n/// Defines values used to indicate change types for a multiplayer session.\n/// </summary>\nenum multiplayer_session_change_types\n{\n    /// <summary>\n    /// None \n    /// </summary>\n    none = 0x0000,\n\n    /// <summary>\n    /// Changes to anything in the session.\n    /// </summary>\n    everything = 0x0001,\n\n    /// <summary>\n    /// Changes to the host device token.\n    /// </summary>\n    host_device_token_change = 0x0002,\n\n    /// <summary>\n    /// Changes to the stage of initialization has changed.\n    /// </summary>\n    initialization_state_change = 0x0004,\n\n    /// <summary>\n    /// Changes to the matchmaking status (e.g. match found or expired)\n    /// </summary>\n    matchmaking_status_change = 0x0008,\n\n    /// <summary>\n    /// A member joined the session\n    /// </summary>\n    member_list_change = 0x0010,\n\n    /// <summary>\n    /// A member left the session\n    /// </summary>\n    member_status_change = 0x0020,\n\n    /// <summary>\n    /// Changes to the joinability of the session.\n    /// </summary>\n    session_joinability_change = 0x0040,\n\n    /// <summary>\n    /// Changes within properties/custom\n    /// </summary>\n    custom_property_change = 0x0080,\n\n    /// <summary>\n    /// Changes within member/properties/custom, for any of the members.\n    /// </summary>\n    member_custom_property_change = 0x0100,\n};\n\n/// <summary>\n/// Defines values used to indicate mutable_role_setting types for a multiplayer role.\n/// Note: Only the session owner can modify role settings and only those that are set as multiplayer_role_type::mutable_role_settings().\n/// The mutable_role_settings can be set in the session template.\n/// </summary>\nenum class mutable_role_setting\n{\n    /// <summary>\n    /// Allows you to set a max count for the multiplayer role\n    /// </summary>\n    max,\n\n    /// <summary>\n    /// Allows you to set a target count for the multiplayer role\n    /// </summary>\n    target\n};\n\n/// <summary>\n/// Represents requirements that apply to each connection between a host candidate and session members.\n/// </summary>\nclass multiplayer_peer_to_host_requirements\n{\npublic:\n    /// <summary>\n    /// The maximum latency for the peer to host connection.\n    /// </summary>\n    inline std::chrono::milliseconds latency_maximum() const;\n\n    /// <summary>\n    /// The minimum bandwidth down in kilobits per second for the peer to host connection.\n    /// </summary>\n    inline uint64_t bandwidth_down_minimum_in_kilobits_per_second() const;\n\n    /// <summary>\n    /// The minimum bandwidth up in kilobits per second for the peer to host connection.\n    /// </summary>\n    inline uint64_t bandwidth_up_minimum_in_kilobits_per_second() const;\n\n    /// <summary>\n    /// Indicates which metric was used to select the host.\n    /// </summary>\n    inline multiplay_metrics host_selection_metric() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_peer_to_host_requirements(_In_ const XblMultiplayerPeerToHostRequirements& requirements);\n\nprivate:\n    XblMultiplayerPeerToHostRequirements m_requirements;\n};\n\n/// <summary>\n/// Represents requirements for a connection between session members.\n/// </summary>\nclass multiplayer_peer_to_peer_requirements\n{\npublic:\n    /// <summary>\n    /// The maximum latency for the peer to peer connection.\n    /// </summary>\n    inline uint64_t bandwidth_minimum_in_kilobits_per_second() const;\n\n    /// <summary>\n    /// The minimum bandwidth in kilobits per second for the peer to peer connection.\n    /// </summary>\n    inline std::chrono::milliseconds latency_maximum() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_peer_to_peer_requirements(_In_ const XblMultiplayerPeerToPeerRequirements& requirements);\nprivate:\n    XblMultiplayerPeerToPeerRequirements m_requirements;\n};\n\n/// <summary>\n/// Used to configure requirements and initialize a new Multiplayer session.\n/// </summary>\nclass multiplayer_member_initialization\n{\npublic:\n    /// <summary>\n    /// Indicates if the ManagedInitializion object is set.\n    /// </summary>\n    inline bool member_initialization_set() const;\n\n    /// <summary>\n    /// Returns the timeout for the first stage of the QoS process which is the joining stage. \n    /// </summary>\n    inline std::chrono::milliseconds join_timeout() const;\n\n    /// <summary>\n    /// Returns the timeout for the measurement stage of the QoS process. \n    /// </summary>\n    inline std::chrono::milliseconds measurement_timeout() const;\n\n    /// <summary>\n    /// Returns the timeout for the evaluation stage of the QoS process. \n    /// </summary>\n    inline std::chrono::milliseconds evaluation_timeout() const;\n\n    /// <summary>\n    /// This is an optional evaluate stage for title.  The title can do evaluation when set to true.\n    /// </summary>\n    inline bool external_evaluation() const;\n\n    /// <summary>\n    /// Defaults to 2. Must be between 1 and maxMemberCount. Only applies to initialization episode zero.\n    /// </summary>\n    inline uint32_t members_need_to_start() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_member_initialization(_In_opt_ const XblMultiplayerMemberInitialization* memberInitialization);\n\nprivate:\n    bool m_initializationSet{ false };\n    XblMultiplayerMemberInitialization m_memberInitialization{};\n};\n\n/// <summary>\n/// Represents the capabilities of a multiplayer session.\n/// </summary>\n/// <remarks>\n/// Session capabilities are boolean values that are optionally set in the session template. If no capabilities are needed, an empty SessionCapabilities object should be in the template to prevent capabilities from being specified on session creation, unless the title requires dynamic session capabilities.\n/// </remarks>\nclass multiplayer_session_capabilities\n{\npublic:\n    /// <summary>\n    /// Constructor\n    /// </summary>\n    inline multiplayer_session_capabilities();\n\n    /// <summary>\n    /// If false, the session can't enable any metrics and the session members can not set their SecureDeviceAddress.  \n    /// </summary>\n    inline bool connectivity() const;\n\n    /// <summary>\n    /// If false, the session can't enable any metrics and the session members can not set their SecureDeviceAddress.  \n    /// </summary>\n    inline void set_connectivity(_In_ bool connectivity);\n\n    /// <summary>\n    /// By default (if false), active users are required to remain online playing the title, otherwise they get demoted to \n    /// inactive status. Setting this flag to true disables this check so that members stay active indefinitely.\n    /// </summary>\n    inline bool suppress_presence_activity_check() const;\n\n    /// <summary>\n    /// By default (if false), active users are required to remain online playing the title, otherwise they get demoted to \n    /// inactive status. Setting this flag to true disables this check so that members stay active indefinitely.\n    /// </summary>\n    inline void set_suppress_presence_activity_check(_In_ bool suppressPresenceActivityCheck);\n\n    /// <summary>\n    /// Indicates whether the session represents actual gameplay, as opposed to setup/menu time like a lobby or matchmaking.\n    /// If true, then the session is in gameplay mode.\n    /// </summary>\n    inline bool gameplay() const;\n\n    /// <summary>\n    /// Indicates whether the session represents actual gameplay, as opposed to setup/menu time like a lobby or matchmaking.\n    /// If true, then the session is in gameplay mode.\n    /// </summary>\n    inline void set_gameplay(_In_ bool gameplay);\n\n    /// <summary>\n    /// If true, this session can host a large number of users, which has impact on other session properties (see documentation)\n    /// </summary>\n    inline bool large() const;\n\n    /// <summary>\n    /// If true, this session can host a large number of users, which has impact on other session properties (see documentation)\n    /// </summary>\n    inline void set_large(_In_ bool large);\n\n    /// <summary>\n    /// If true, this connection is required to have a member be active (see documentation)\n    /// </summary>\n    inline bool connection_required_for_active_members() const;\n\n    /// <summary>\n    /// If true, this connection is required to have a member be active (see documentation)\n    /// </summary>\n    inline void set_connection_required_for_active_members(_In_ bool connectionRequired);\n\n    /// <summary>\n    /// Session supports calls from platforms without strong title identity. This capability can't be set on large sessions.\n    /// </summary>\n    inline bool user_authorization_style() const;\n\n    /// <summary>\n    /// Session supports calls from platforms without strong title identity. This capability can't be set on large sessions.\n    /// </summary>\n    inline void set_user_authorization_style(_In_ bool userAuthorizationStyle);\n\n    /// <summary>\n    /// Session supports cross play between PC and Xbox\n    /// </summary>\n    inline bool crossplay() const;\n\n    /// <summary>\n    /// Session supports cross play between PC and Xbox\n    /// </summary>\n    inline void set_crossplay(_In_ bool crossplay);\n\n    /// <summary>\n    /// True, if the session can be linked to a search handle for searching.\n    /// </summary>\n    inline bool searchable() const;\n\n    /// <summary>\n    /// Allows the session to be linked to a search handle for searching.\n    /// </summary>\n    inline void set_searchable(_In_ bool searchable);\n\n    /// <summary>\n    /// True, if the session has owners. If you have user_authorization_style set, then in order to be searchable, you must have owners set.\n    /// </summary>\n    inline bool has_owners() const;\n\n    /// <summary>\n    /// If you have user_authorization_style set, then in order to be searchable, you must have owners set.\n    /// </summary>\n    inline void set_has_owners(_In_ bool hasOwners);\n\nprivate:\n    XblMultiplayerSessionCapabilities m_capabilities;\n    friend class multiplayer_session;\n};\n\n/// <summary>\n/// Represents matchmaking quality of service (QoS) measurements for the network used by a session member.\n/// </summary>\nclass multiplayer_quality_of_service_measurements\n{\npublic:\n    /// <summary>\n    /// Creates a new MultiplayerQualityOfServiceMeasurements object.\n    /// </summary>\n    /// <param name=\"memberDeviceToken\">The device token of the member that this measurement is for.</param>\n    /// <param name=\"latency\">The time of the latency measurement.</param>\n    /// <param name=\"bandwidthDownInKilobitsPerSecond\">The bandwidth down in kilobits per second.</param>\n    /// <param name=\"bandwidthUpInKilobitsPerSecond\">The bandwidth up in kilobits per second.</param>\n    /// <param name=\"customJson\">JSON string that specify the custom properties.</param>\n    inline multiplayer_quality_of_service_measurements(\n        _In_ const string_t& memberDeviceToken,\n        _In_ std::chrono::milliseconds latency,\n        _In_ uint64_t bandwidthDownInKilobitsPerSecond,\n        _In_ uint64_t bandwidthUpInKilobitsPerSecond,\n        _In_ const string_t& customJson\n    );\n\n    /// <summary>\n    /// The device token of the member that this measurement is for.\n    /// </summary>\n    inline const string_t& member_device_token() const;\n\n    /// <summary>\n    /// The time of the latency measurement.\n    /// </summary>\n    inline const std::chrono::milliseconds& latency() const;\n    \n    /// <summary>\n    /// The bandwidth down in kilobits per second.\n    /// </summary>\n    inline uint64_t bandwidth_down_in_kilobits_per_second() const;\n\n    /// <summary>\n    /// The bandwidth up in kilobits per second.\n    /// </summary>\n    inline uint64_t bandwidth_up_in_kilobits_per_second() const;\n\n    /// <summary>\n    /// JSON string that specify the custom properties.\n    /// </summary>\n    inline const web::json::value& custom_json() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_quality_of_service_measurements(\n        _In_ const string_t& memberDeviceToken,\n        _In_ const web::json::value& measurementsJson\n    );\n\nprivate:\n    string_t m_memberDeviceToken;\n    std::chrono::milliseconds m_latency;\n    uint64_t m_bandwidthDown;\n    uint64_t m_bandwidthUp;\n    web::json::value m_customJson;\n    web::json::value m_measurementsJson;\n\n    friend class multiplayer_session;\n};\n\n/// <summary>\n/// Represents constant values for a multiplayer session.\n/// </summary>\nclass multiplayer_session_constants\n{\npublic:\n    /// <summary>\n    /// The maximum number of members in this session.\n    /// </summary>\n    inline uint32_t max_members_in_session() const;\n\n    /// <summary>\n    /// The maximum number of members in this session.\n    /// </summary>\n    inline void set_max_members_in_session(_In_ uint32_t maxMembersInSession);\n\n    /// <summary>\n    /// The visibility of this session.\n    /// </summary>\n    inline multiplayer_session_visibility visibility() const;\n\n    /// <summary>\n    /// The visibility of this session.\n    /// </summary>\n    inline void set_visibility(_In_ multiplayer_session_visibility visibility);\n    \n    /// <summary>\n    /// A collection of Xbox User IDs indicating who initiated the session. (Optional)\n    /// </summary>\n    inline std::vector<string_t> initiator_xbox_user_ids() const;\n    \n    /// <summary>\n    /// JSON string that specify the custom constants for the session.  These can not be changed after the session is created. (Optional)\n    /// </summary>\n    inline web::json::value session_custom_constants_json() const;\n\n    /// <summary>\n    /// JSON string that specify the cloud compute package constants for the session.  These can not be changed after the session is created. (Optional)\n    /// </summary>\n    inline web::json::value session_cloud_compute_package_constants_json() const;\n\n    /// <summary>\n    /// If a member reservation does not join within this timeout, then reservation is removed.\n    /// </summary>\n    inline std::chrono::milliseconds member_reserved_time_out() const;\n    \n    /// <summary>\n    /// If an inactive member reservation does not become active within this timeout, then the inactive member is removed from the session.\n    /// </summary>\n    inline std::chrono::milliseconds member_inactive_timeout() const;\n    \n    /// <summary>\n    /// If a member who is marked as ready doesn't mark themselves as active within this timeout, then member becomes inactive.\n    /// When the shell launches the title to start a multiplayer game, the member is marked as ready.\n    /// </summary>\n    inline std::chrono::milliseconds member_ready_timeout() const;\n    \n    /// <summary>\n    /// If the session is empty for this timeout, then the session is deleted.\n    /// </summary>\n    inline std::chrono::milliseconds session_empty_timeout() const;\n\n    /// <summary>\n    /// Indicates if the title wants latency measured for determining connectivity\n    /// Requires CapabilitiesConnectivity capability.\n    /// </summary>\n    inline bool enable_metrics_latency() const;\n\n    /// <summary>\n    /// Indicates if the title wants bandwidth down measured for determining connectivity\n    /// Requires CapabilitiesConnectivity capability.\n    /// </summary>\n    inline bool enable_metrics_bandwidth_down() const;\n\n    /// <summary>\n    /// Indicates if the title wants bandwidth up measured for determining connectivity\n    /// Requires CapabilitiesConnectivity capability.\n    /// </summary>\n    inline bool enable_metrics_bandwidth_up() const;\n    \n    /// <summary>\n    /// Indicates if the title wants a custom measurement measured for determining connectivity\n    /// Requires CapabilitiesConnectivity capability.\n    /// </summary>\n    inline bool enable_metrics_custom() const;\n\n    /// <summary>\n    /// If a MemberInitialization object is set, the session expects the client system or title to perform\n    /// initialization following session creation. The timeouts and initialization stages are automatically tracked by\n    /// the session, including initial QoS if any metrics are set.\n    /// </summary>\n    inline multiplayer_member_initialization member_initialization() const;\n\n    /// <summary>\n    /// Peer to peer QoS requirements\n    /// </summary>\n    inline multiplayer_peer_to_peer_requirements peer_to_peer_requirements() const;\n    \n    /// <summary>\n    /// Peer to host QoS requirements\n    /// </summary>\n    inline multiplayer_peer_to_host_requirements peer_to_host_requirements() const;\n    \n    /// <summary>\n    /// The set of potential server connection strings that should be evaluated.\n    /// </summary>\n    inline web::json::value measurement_server_addresses_json() const;\n\n    /// <summary>\n    /// Indicates whether the matchmaking status fields can be written to.\n    /// </summary>\n    inline bool client_matchmaking_capable() const;\n\n    /// <summary>\n    /// If false, the session can't enable any metrics and the session members can not set their SecureDeviceAddress.  \n    /// </summary>\n    inline bool capabilities_connectivity() const;\n\n    /// <summary>\n    /// By default (if false), active users are required to remain online playing the title, otherwise they get demoted to \n    /// inactive status. Setting this flag to true disables this check so that members stay active indefinitely.\n    /// </summary>\n    inline bool capabilities_suppress_presence_activity_check() const;\n\n    /// <summary>\n    /// Indicates whether the session represents actual gameplay, as opposed to setup/menu time like a lobby or matchmaking.\n    /// If true, then the session is in gameplay mode.\n    /// </summary>\n    inline bool capabilities_gameplay() const;\n\n    /// <summary>\n    /// If true, this session can host a large number of users, which has impact on other session properties.\n    /// </summary>\n    inline bool capabilities_large() const;\n\n    /// <summary>\n    /// If true, this connection is required to have a member be active (see documentation)\n    /// </summary>\n    inline bool capabilities_connection_required_for_active_member() const;\n\n    /// <summary>\n    /// Session supports cross play between PC and Xbox\n    /// </summary>\n    inline bool capabilities_crossplay() const;\n\n    /// <summary>\n    /// Session supports calls from platforms without strong title identity. This capability can't be set on large sessions.\n    /// Using this capability will cause both 'readRestriction' and 'joinRestriction' to default to \"local\".\n    /// </summary>\n    inline bool capabilities_user_authorization_style() const;\n\n    /// <summary>\n    /// True, if the session can be linked to a search handle for searching.\n    /// </summary>\n    inline bool capabilities_searchable() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_constants(_In_ XblMultiplayerSessionHandle sessionHandle);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_constants(bool isLobbySession);\n\n    inline ~multiplayer_session_constants();\n\nprivate:\n    multiplayer_session_constants(const multiplayer_session_constants&) = delete;\n    multiplayer_session_constants& operator=(multiplayer_session_constants) = delete;\n\n    XblMultiplayerSessionHandle m_sessionHandle;\n    const XblMultiplayerSessionConstants* m_constants;\n};\n\n/// <summary>\n/// Represents a reference to a multiplayer session.\n/// </summary>\nclass multiplayer_session_reference\n{\npublic:\n    /// <summary>\n    /// Constructs a null MultiplayerSession object.\n    /// </summary>\n    inline multiplayer_session_reference();\n\n    /// <summary>\n    /// Constructs the MultiplayerSession object with data about the session.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">A service configuration ID appropriate for the title.</param>\n    /// <param name=\"sessionTemplateName\">The name of the template for the session to be based on.</param>\n    /// <param name=\"sessionName\">A unique name for the session.</param>\n    inline multiplayer_session_reference(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& sessionTemplateName,\n        _In_ const string_t& sessionName\n    );\n\n    /// <summary>\n    /// The service configuration ID specific to the title.\n    /// </summary>\n    inline string_t service_configuration_id() const;\n\n    /// <summary>\n    /// The name of the template for the session.\n    /// </summary>\n    inline string_t session_template_name() const;\n\n    /// <summary>\n    /// The name of the session.\n    /// </summary>\n    inline string_t session_name() const;\n\n    /// <summary>\n    /// Whether this object has been properly constructed\n    /// </summary>\n    inline bool is_null() const;\n\n    /// <summary>\n    /// Returns a URI path representation of the session reference.\n    /// </summary>\n    inline string_t to_uri_path() const;\n\n    /// <summary>\n    /// Returns the session reference parsed from URI.\n    /// </summary>\n    static inline multiplayer_session_reference parse_from_uri_path(_In_ const string_t& path);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_reference(_In_ const XblMultiplayerSessionReference& reference);\n\nprivate:\n    mutable XblMultiplayerSessionReference m_reference;\n    friend class multiplayer_session;\n    friend class multiplayer_service;\n    friend class multiplayer_search_handle_request;\n    friend class social::reputation_service;\n};\n\n/// <summary>\n/// Represents the matchmaking server supporting the multiplayer session.\n/// </summary>\nclass multiplayer_session_matchmaking_server\n{\npublic:\n    /// <summary>\n    /// The Matchmaking Status of the Multiplayer Session Server.\n    /// </summary>\n    inline matchmaking_status status() const;\n\n    /// <summary>\n    /// The Matchmaking Status Details of the Multiplayer Session Server.\n    /// </summary>\n    inline string_t status_details() const;\n\n    /// <summary>\n    /// The Typical Wait of the Multiplayer Session Server.\n    /// </summary>\n    inline std::chrono::seconds typical_wait() const;\n\n    /// <summary>\n    /// The Target Session Reference of the Multiplayer Session Server.\n    /// </summary>\n    inline multiplayer_session_reference target_session_ref() const;\n\n    /// <summary>\n    /// Returns true if this object is blank\n    /// </summary>\n    inline bool is_null() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_matchmaking_server(_In_ XblMultiplayerSessionHandle sessionHandle);\n    inline multiplayer_session_matchmaking_server(const multiplayer_session_matchmaking_server& other);\n    inline multiplayer_session_matchmaking_server& operator=(multiplayer_session_matchmaking_server other);\n    inline ~multiplayer_session_matchmaking_server();\n\nprivate:\n    XblMultiplayerSessionHandle m_sessionHandle;\n    const XblMultiplayerMatchmakingServer* m_server;\n};\n\n/// <summary>\n/// Represents role info for a multiplayer role.\n/// </summary>\nclass multiplayer_role_info\n{\npublic:\n    inline multiplayer_role_info();\n\n    /// <summary>\n    /// Member xbox_user_ids currently assigned for this role.\n    /// </summary>\n    inline const std::vector<string_t>& member_xbox_user_ids() const;\n\n    /// <summary>\n    /// Number of slots occupied for this role.\n    /// </summary>\n    inline uint32_t members_count() const;\n\n    /// <summary>\n    /// Number of target slots assigned for this role.\n    /// </summary>\n    inline uint32_t target_count() const;\n\n    /// <summary>\n    /// Maximum number of slots available for this role.\n    /// </summary>\n    inline uint32_t max_members_count() const;\n\n    /// <summary>\n    /// Set the max member count for this role.\n    /// Note: Only the session owner can modify role settings and only those that are multiplayer_role_type::mutable_role_settings()\n    /// In your session template, you also need to set 'hasOwners' capability and 'ownerManaged' to true for the specific role type \n    /// that you want to modify the mutable_role_setting off.\n    /// </summary>\n    /// <param name=\"maxCount\">The max member count for this role.</param>\n    inline void set_max_members_count(_In_ uint32_t maxCount);\n\n    /// <summary>\n    /// Set the target member count for this role.\n    /// Note: Only the session owner can modify role settings and only those that are multiplayer_role_type::mutable_role_settings()\n    /// In your session template, you also need to set 'hasOwners' capability and 'ownerManaged' to true for the specific role type \n    /// that you want to modify the mutable_role_setting off.\n    /// </summary>\n    /// <param name=\"targetCount\">The max member count for this role.</param>\n    inline void set_target_count(_In_ uint32_t targetCount);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_role_info(const XblMultiplayerRole* role);\n\nprivate:\n    std::vector<string_t> m_memberXuids;\n    uint32_t m_maxMembersCount{ 0 };\n    uint32_t m_membersCount{ 0 };\n    uint32_t m_targetCount{ 0 };\n};\n\n/// <summary>\n/// Represents a collection of roles for this role type.\n/// </summary>\nclass multiplayer_role_type\n{\npublic:\n    inline multiplayer_role_type();\n\n    /// <summary>\n    /// True if ownerManaged is set on the roleType.\n    /// </summary>\n    inline bool owner_managed() const;\n\n    /// <summary>\n    /// Mutable role settings for this role.\n    /// </summary>\n    inline const std::vector<mutable_role_setting>& mutable_role_settings() const;\n\n    /// <summary>\n    /// A collection of roles for this role type.\n    /// </summary>\n    inline const std::unordered_map<string_t, multiplayer_role_info>& roles() const;\n\n    /// <summary>\n    /// Set a collection of roles for this role type.\n    /// Note: Only the session owner can modify role settings and only those that are multiplayer_role_type::mutable_role_settings()\n    /// In your session template, you also need to set 'hasOwners' capability and 'ownerManaged' to true for the specific role type \n    /// that you want to modify the mutable_role_setting off.\n    /// </summary>\n    inline void set_roles(_In_ const std::unordered_map<string_t, multiplayer_role_info>& roles);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_role_type(const XblMultiplayerRoleType* roleType);\n\nprivate:\n    bool m_ownerManaged{ false };\n    std::vector<mutable_role_setting> m_mutableRoleSettings;\n    std::unordered_map<string_t, multiplayer_role_info> m_roles;\n};\n\n/// <summary>\n/// Represents session role type values for a multiplayer session.\n/// </summary>\nclass multiplayer_session_role_types\n{\npublic:\n    /// <summary>\n    /// A collection of role types.\n    /// </summary>\n    inline const std::unordered_map<string_t, multiplayer_role_type>& role_types() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_role_types(const XblMultiplayerRoleType* roleTypes, size_t roleTypesCount);\n\nprivate:\n    std::unordered_map<string_t, multiplayer_role_type> m_roleTypes;\n};\n\n/// <summary>\n/// Represents a users current multiplayer activity, along with some details about the corresponding session.\n/// </summary>\nclass multiplayer_activity_details\n{\npublic:\n    /// <summary>\n    /// Object containing identifying information for the session.\n    /// </summary>\n    inline multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// HandleId corresponding to this activity.\n    /// </summary>\n    inline string_t handle_id() const;\n\n    /// <summary>\n    /// TitleId that should be launched in order to join this activity.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    /// <summary>\n    /// The visibility state of the session. Whether other users can see, or join, etc.\n    /// </summary>\n    inline multiplayer_session_visibility visibility() const;\n\n    /// <summary>\n    /// The join restriction of the session, which applies if visibility is \"open\".\n    /// </summary>\n    inline multiplayer_session_restriction join_restriction() const;\n\n    /// <summary>\n    /// Indicates whether the session is temporarily closed for joining.\n    /// </summary>\n    inline bool closed() const;\n\n    /// <summary>\n    /// Xbox User ID of the member whose activity this is. \n    /// </summary>\n    inline string_t owner_xbox_user_id() const;\n\n    /// <summary>\n    /// Number of total slots.\n    /// </summary>\n    inline uint32_t max_members_count() const;\n\n    /// <summary>\n    /// Number of slots occupied.\n    /// </summary>\n    inline uint32_t members_count() const;\n\n    /// <summary>\n    /// Custom session properties for the session.\n    /// </summary>\n    inline web::json::value custom_session_properties_json() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_activity_details(const XblMultiplayerActivityDetails& activityDetails);\n    inline multiplayer_activity_details(const multiplayer_activity_details&);\n    inline multiplayer_activity_details& operator=(multiplayer_activity_details);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline ~multiplayer_activity_details();\n\nprivate:\n    XblMultiplayerActivityDetails m_activityDetails;\n};\n\n/// <summary>\n/// Represents a users current search handle, along with some details about the corresponding session.\n/// </summary>\nclass multiplayer_search_handle_details\n{\npublic:\n    /// <summary>\n    /// Object containing identifying information for the session.\n    /// </summary>\n    inline multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// HandleId corresponding to this activity.\n    /// </summary>\n    inline string_t handle_id() const;\n\n    /// <summary>\n    /// Owners of the session.\n    /// </summary>\n    inline std::vector<string_t> session_owner_xbox_user_ids() const;\n\n    /// <summary>\n    /// The tags that are currently set on the session.\n    /// </summary>\n    inline std::vector<string_t> tags() const;\n\n    /// <summary>\n    /// The numbers metadata that is currently set on the session.\n    /// </summary>\n    inline std::unordered_map<string_t, double> numbers_metadata() const;\n\n    /// <summary>\n    /// The strings metadata that is currently set on the session.\n    /// </summary>\n    inline std::unordered_map<string_t, string_t> strings_metadata() const;\n\n    /// <summary>\n    /// Deprecated. Note that the role types are still exposed through the multiplayer_session object.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline std::unordered_map<string_t, multiplayer_role_type> role_types() const;\n\n    /// <summary>\n    /// The visibility state of the session. Whether other users can see, or join, etc.\n    /// </summary>\n    inline multiplayer_session_visibility visibility() const;\n\n    /// <summary>\n    /// The join restriction of the session, which applies if visibility is \"open\".\n    /// </summary>\n    inline multiplayer_session_restriction join_restriction() const;\n\n    /// <summary>\n    /// Indicates whether the session is temporarily closed for joining.\n    /// </summary>\n    inline bool closed() const;\n\n    /// <summary>\n    /// Number of total slots.\n    /// </summary>\n    inline uint32_t max_members_count() const;\n\n    /// <summary>\n    /// Number of slots occupied.\n    /// </summary>\n    inline uint32_t members_count() const;\n\n    /// <summary>\n    /// Custom session properties for the session.\n    /// </summary>\n    inline web::json::value custom_session_properties_json() const;\n\n    /// <summary>\n    /// The time when the search handle was created.\n    /// </summary>\n    inline utility::datetime handle_creation_time() const;\n\n    inline multiplayer_search_handle_details(XblMultiplayerSearchHandle handle);\n    inline multiplayer_search_handle_details(const multiplayer_search_handle_details&);\n    inline multiplayer_search_handle_details& operator=(multiplayer_search_handle_details);\n    inline ~multiplayer_search_handle_details();\n\nprivate:\n    XblMultiplayerSearchHandle m_handle;\n};\n\n/// <summary>\n/// Represents a reference to a multiplayer session. It\n/// contains mostly just ids.\n/// </summary>\nclass multiplayer_session_states\n{\npublic:\n    /// <summary>\n    /// The time that the session began.\n    /// </summary>\n    inline utility::datetime start_time() const;\n\n    /// <summary>\n    /// Object containing identifying information for the session.\n    /// </summary>\n    inline multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// The current status of the session.\n    /// </summary>\n    inline multiplayer_session_status status() const;\n\n    /// <summary>\n    /// The visibility state of the session. Whether other users can see, or join, etc.\n    /// </summary>\n    inline multiplayer_session_visibility visibility() const;\n\n    /// <summary>\n    /// Indicates if it is my turn.\n    /// </summary>\n    inline bool is_my_turn() const;\n\n    /// <summary>\n    /// Xbox User ID of the member. \n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// Approximate number of non-reserved members.\n    /// </summary>\n    inline uint32_t accepted_member_count() const;\n\n    /// <summary>\n    /// Join restriction for the session.\n    /// </summary>\n    inline multiplayer_session_restriction join_restriction() const;\n\n    /// <summary>\n    /// DEPRECATED - Keywords can be obtained with get_current_session.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline std::vector<string_t> keywords() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_states(_In_ const XblMultiplayerSessionQueryResult& state);\n\nprivate:\n    XblMultiplayerSessionQueryResult m_state;\n};\n\n/// <summary>\n/// Represents a reference to member in a multiplayer session.\n/// </summary>\nclass multiplayer_session_member\n{\npublic:\n    /// <summary>\n    /// Id for this member.\n    /// </summary>\n    inline uint32_t member_id() const;\n\n    /// <summary>\n    /// Initial team assignment from SmartMatch.\n    /// </summary>\n    inline string_t initial_team() const;\n\n    /// <summary>\n    /// Xbox User ID of the member.  Only known if the member has accepted.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n    \n    /// <summary>\n    /// JSON string that specify the custom constants for the member.\n    /// </summary>\n    inline web::json::value member_custom_constants_json() const;\n    \n    /// <summary>\n    /// The base64 encoded secure device address of the member. (Optional)\n    /// </summary>\n    inline string_t secure_device_base_address64() const;\n\n    /// <summary>\n    /// A collection of role types to role names for this member. (Optional)\n    /// </summary>\n    inline std::unordered_map<string_t, string_t> roles() const;\n\n    /// <summary>\n    /// JSON string that specify the custom properties for the member.\n    /// </summary>\n    inline web::json::value member_custom_properties_json() const;\n\n    /// <summary>\n    /// The Gamertag of the member.  Only known if the member has accepted. (Optional) \n    /// </summary>\n    inline string_t gamertag() const;\n\n    /// <summary>\n    /// The status of this member.\n    /// </summary>\n    inline multiplayer_session_member_status status() const;\n\n    /// <summary>\n    /// Only true if this member is ready for turn.\n    /// </summary>\n    inline bool is_turn_available() const;\n\n    /// <summary>\n    /// Indicates if this MultiplayerSessionMember is for the current user.\n    /// </summary>\n    inline bool is_current_user() const;\n\n    /// <summary>\n    /// Indicates to run QoS initialization for this user. Defaults to false.\n    /// Ignored if there is not a \"memberInitialization\" section for the session.\n    /// </summary>\n    inline bool initialize_requested() const;\n\n    /// <summary>\n    /// When match adds a user to a session, it can provide some context around how and why they were matched into the session.\n    /// This is a copy of the user's serverMeasurements from the matchmaking session.\n    /// </summary>\n    inline web::json::value matchmaking_result_server_measurements_json() const;\n    \n    /// <summary>\n    /// QoS measurements by game-server connection string. \n    /// Like all fields, \"serverMeasurements\" must be updated as a whole, so it should be set once when measurement is complete.\n    /// If empty, it means that none of the measurements completed within the \"serverMeasurementTimeout\".\n    /// </summary>\n    inline web::json::value member_server_measurements_json() const;\n\n    /// <summary>\n    /// A collection of members in my group\n    /// If a \"initializationGroup\" list is set, the member's own index will always be added if it isn't already present.\n    /// During managed initialization, if any members in the list fail, this member will also fail.\n    /// </summary>\n    inline std::vector<std::shared_ptr<multiplayer_session_member>> members_in_group() const;\n\n    /// <summary>\n    /// A collection of members in my group\n    /// If a \"initializationGroup\" list is set, the member's own index will always be added if it isn't already present.\n    /// During managed initialization, if any members in the list fail, this member will also fail.\n    /// </summary>\n    inline std::error_code set_members_list(_In_ const std::vector<std::shared_ptr<multiplayer_session_member>>& members);\n\n    /// <summary>\n    /// QoS measurements by secure device address. Like all fields, \"measurements\" must be updated as a whole. It should be set once when measurement is complete, not incrementally.\n    /// If a \"measurements\" object is set, it can't contain an entry for the member's own address.\n    /// </summary>\n    inline std::shared_ptr<std::vector<multiplayer_quality_of_service_measurements>> member_measurements() const;\n    \n    /// <summary>\n    /// This is set when the member uploads a secure device address. It's a case-insensitive string that can be used for equality comparisons.\n    /// </summary>\n    inline string_t device_token() const;\n    \n    /// <summary>\n    /// This is the device's NAT setting when the member uploads a secure device address.\n    /// </summary>\n    inline network_address_translation_setting nat() const;\n\n    /// <summary>\n    /// If the member is active, this is the title ID in which they are active.\n    /// </summary>\n    inline uint32_t active_title_id() const;\n    \n    /// <summary>\n    /// This value is only useful to read when the title is manually managing their own QoS.\n    /// If the \"memberInitialization\" section is set and the member was added with \"initialize\":true, \n    /// this is set to the initialization episode that the member will participate in otherwise it is 0.\n    /// Users join sessions in batches.  \n    /// The initialization episode number indicates a set of users that QoS needs to be performed against.\n    /// Initialization episode 1 is a special value used for the members added to a new session at create time.\n    /// </summary>\n    inline uint32_t initialization_episode() const;\n\n    /// <summary>\n    /// The time the user joined the session. If \"reserved\" is true, this is the time the reservation was made.\n    /// </summary>\n    inline utility::datetime join_time() const;\n    \n    /// <summary>\n    /// The cause of why the initialization failed, or MultiplayerMeasurementFailure::None if there was no failure.\n    /// Set when transitioning out of the \"joining\" or \"measuring\" stage if this member doesn't pass.\n    /// </summary>\n    inline multiplayer_measurement_failure initialization_failure_cause() const;\n\n    /// <summary>\n    /// Gets or sets a string vector of group names for the current user indicating which groups that user was part of during a multiplayer session.\n    /// </summary>\n    inline std::vector<string_t> groups() const;\n\n    /// <summary>\n    /// Gets or sets a string vector of group names for the current user indicating which groups that user was part of during a multiplayer session.\n    /// </summary>\n    inline void set_groups(_In_ const std::vector<string_t>& groups);\n\n    /// <summary>\n    /// Gets a list of group names for the current user indicating which groups that user encountered during a multiplayer session.\n    /// </summary>\n    inline std::vector<string_t> encounters() const;\n\n    /// <summary>\n    /// Gets a list of group names for the current user indicating which groups that user encountered during a multiplayer session.\n    /// </summary>\n    inline void set_encounters(_In_ const std::vector<string_t>& encounters);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_member(_In_ XblMultiplayerSessionHandle session, _In_ const XblMultiplayerSessionMember* member);\n    inline ~multiplayer_session_member();\n\nprivate:\n    multiplayer_session_member(const multiplayer_session_member&) = delete;\n    multiplayer_session_member& operator=(multiplayer_session_member) = delete;\n\n    XblMultiplayerSessionHandle m_session;\n    const XblMultiplayerSessionMember* m_member;\n};\n\n/// <summary>\n/// Represents multiplayer session properties.\n/// </summary>\nclass multiplayer_session_properties\n{\npublic:\n    /// <summary>\n    /// A collection of keywords associated with the session. (Optional, might be empty)\n    /// When changing, call multiplayer_service::write_session to write the changes to the service.\n    /// </summary>\n    inline std::vector<string_t> keywords() const;\n\n    /// <summary>\n    /// A collection of keywords associated with the session. (Optional, might be empty)\n    /// When changing, call multiplayer_service::write_session to write the changes to the service.\n    /// </summary>\n    inline void set_keywords(_In_ const std::vector<string_t>& keywords);\n\n    /// <summary>\n    /// Restricts who can join \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)\n    /// Defaults to \"none\".\n    /// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.\n    /// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can join without a reservation.\n    /// </summary>\n    inline multiplayer_session_restriction join_restriction() const;\n    \n    /// <summary>\n    /// Restricts who can join \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)\n    /// Defaults to \"none\".\n    /// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.\n    /// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can join without a reservation.\n    /// </summary>\n    inline std::error_code set_join_restriction(_In_ multiplayer_session_restriction joinRestriction);\n\n    /// <summary>\n    /// Restricts who can read \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)\n    /// Defaults to \"none\".\n    /// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.\n    /// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can read without a reservation.\n    /// The read restriction applies to sessions with \"open\" or \"visible\" visibility and determines who can read the session without an invite.\n    /// The read restriction must be at least as accessible as the join restriction, i.e. 'joinRestriction' can't be set to \"followed\" without also setting 'readRestriction'.\"\n    /// </summary>\n    inline multiplayer_session_restriction read_restriction() const;\n\n    /// <summary>\n    /// Restricts who can read \"open\" sessions. (Has no effect on reservations, which means it has no impact on \"private\" and \"visible\" sessions.)\n    /// Defaults to \"none\".\n    /// If \"local\", only users whose token's DeviceId matches someone else already in the session and \"active\": true.\n    /// If \"followed\", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can read without a reservation.\n    /// </summary>\n    inline std::error_code set_read_restriction(_In_ multiplayer_session_restriction readRestriction);\n\n    /// <summary>\n    /// A collection of MultiplayerSessionMember objects indicating whose turn it is.\n    /// When changing, call multiplayer_service::write_session to write the changes to the service.\n    /// </summary>\n    inline std::vector<std::shared_ptr<multiplayer_session_member>> turn_collection() const;\n    \n    /// <summary>\n    /// A collection of MultiplayerSessionMember objects indicating whose turn it is.\n    /// When changing, call multiplayer_service::write_session to write the changes to the service.\n    /// </summary>\n    inline std::error_code set_turn_collection(_In_ const std::vector<std::shared_ptr<multiplayer_session_member>>& turnCollection);\n\n    /// <summary>\n    /// A JSON string representing the target session constants.\n    /// </summary>\n    inline web::json::value matchmaking_target_session_constants_json() const;\n\n    /// <summary>\n    /// JSON string that specify the custom properties for the session.  These can be changed anytime.\n    /// When changing, call multiplayer_service::write_session to write the changes to the service.\n    /// </summary>\n    inline web::json::value session_custom_properties_json() const;\n\n    /// <summary>\n    /// Force a specific connection string to be used.  This is useful for session in progress join scenarios.\n    /// </summary>\n    inline string_t matchmaking_server_connection_string() const;\n    \n    /// <summary>\n    /// The ordered list of connection strings that the session could use to connect to a game server. Generally titles should use the first on\n    /// the list, but sophisticated titles could use a custom mechanism for choosing one of the others (e.g. based on load).\n    /// </summary>\n    inline std::vector<string_t> server_connection_string_candidates() const;\n\n    /// <summary>\n    /// Member index of owners of the session.\n    /// </summary>\n    inline std::vector<uint32_t> session_owner_indices() const;\n    \n    /// <summary>\n    /// Device token of the host.\n    /// Must match the \"deviceToken\" of at least one member, otherwise this field is deleted.\n    /// If \"peerToHostRequirements\" is set and \"host\" is set, the measurement stage assumes the given host is the correct host and only measures metrics to that host.\n    /// </summary>\n    inline string_t host_device_token() const;\n\n    /// <summary>\n    /// Controls whether a session is joinable, independent of visibility, joinrestriction, and available space in the session.\n    /// Does not affect reservations.  Defaults to false.\n    /// </summary>\n    inline bool closed() const;\n\n    /// <summary>\n    /// If true, it would allow the members of the session to be locked, such that if a user leaves they are able to \n    /// come back into the session but no other user could take that spot. Defaults to false.\n    /// </summary>\n    inline bool locked() const;\n\n    /// <summary>\n    /// Setting to true by a client triggers a Xbox Live Compute allocation attempt by MPSD.\n    /// Defaults to false.\n    /// </summary>\n    inline bool allocate_cloud_compute() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_properties(_In_ XblMultiplayerSessionHandle session);\n    inline ~multiplayer_session_properties();\n\nprivate:\n    multiplayer_session_properties(const multiplayer_session_properties&) = delete;\n    multiplayer_session_properties& operator=(multiplayer_session_properties) = delete;\n\n    XblMultiplayerSessionHandle m_session;\n    const XblMultiplayerSessionProperties* m_properties;\n};\n\n/// <summary>\n/// Represents a multiplayer session.\n/// </summary>\nclass multiplayer_session\n{\npublic:\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only create a local session \n    /// object but does not commit it to the service.  \n    /// Creates a new MultiplayerSession without any constants or session reference.  This override is intended \n    /// to be used when the session (serviceconfigid/template/name) are not known.  A MultiplayerSession created\n    /// using this constructor must we retrieved/written using the \"ByHandle\" overrides.  \n    /// (e.g. WriteSessionByHandleAsync and GetCurrentSessionByHandleAsync)\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user who is creating this session</param>\n    /// <param name=\"multiplayerSessionReference\">A reference that uniquely identifies the session.</param>\n    inline multiplayer_session(\n        _In_ const string_t& xboxUserId\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only create a local session object but does not commit it to the service.\n    /// Creates a new MultiplayerSession without any constants, which allows the request to simply use whatever constants are already specified in the session\n    /// template on the service.  Those constants are returned in the response session data.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user who is creating this session</param>\n    /// <param name=\"multiplayerSessionReference\">A reference that uniquely identifies the session.</param>\n    inline multiplayer_session(\n        _In_ const string_t& xboxUserId,\n        _In_ multiplayer_session_reference sessionReference\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only create a local session object but does not commit it to the service.\n    /// Creates a new MultiplayerSession using the specified session constants.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user who is creating this session</param>\n    /// <param name=\"multiplayerSessionReference\">A reference that uniquely identifies the session.</param>\n    /// <param name=\"maxMembersInSession\">The maximum number of members in this session. This value can only be set if the maximum is not specified in the title's multiplayer session template.\n    /// If the maximum is specified in the title's multiplayer session template, then set to 0 to ignore this parameter</param>\n    /// <param name=\"multiplayerSessionVisibility\">The visibility of this session</param>\n    /// <param name=\"initiatorXboxUserIds\">A collection of Xbox User IDs indicating who initiated the session (Optional)</param>\n    /// <param name=\"sessionCustomConstantsJson\">JSON that specify the custom constants for the session.  These can not be changed after the session is created.  (Optional)</param>\n    inline multiplayer_session(\n        _In_ const string_t& xboxUserId,\n        _In_ multiplayer_session_reference multiplayerSessionReference,\n        _In_ uint32_t maxMembersInSession,\n        _In_ multiplayer_session_visibility multiplayerSessionVisibility,\n        _In_ std::vector<string_t> initiatorXboxUserIds = std::vector<string_t>(),\n        _In_ const web::json::value& sessionCustomConstantsJson = web::json::value()\n        );\n\n    /// <summary>\n    /// A unique ID to the session used to query trace logs for entries that relate to the session.  \n    /// </summary>\n    inline string_t multiplayer_correlation_id() const;\n\n    /// <summary>\n    /// A unique search handle ID to the session.\n    /// </summary>\n    inline string_t search_handle_id() const;\n\n    /// <summary>\n    /// The time that the session began.\n    /// </summary>\n    inline utility::datetime start_time() const;\n\n    /// <summary>\n    /// If any timeouts are in progress, this is the date when the next timer will fire.\n    /// </summary>\n    inline utility::datetime date_of_next_timer() const;\n    \n    /// <summary>\n    /// The date when the server returned the session.\n    /// </summary>\n    inline utility::datetime date_of_session() const;\n\n    /// <summary>\n    /// Present during managed initialization.\n    /// The \"stage\" goes from \"joining\" to \"measuring\" to \"evaluating\".\n    /// If episode 1 fails, then \"stage\" is set to \"failed\" and the session cannot be initialized.\n    /// Otherwise, when an initialization episode completes, the \"initialization\" object is removed.\n    /// If \"externalEvaluation\" is not set, \"evaluating\" is skipped. If \"metrics\" isn't set, \"measuring\" is skipped.\n    /// </summary>\n    inline multiplayer_initialization_stage initialization_stage() const;\n\n    /// <summary>\n    /// The time with the initialization stage started.\n    /// </summary>\n    inline utility::datetime initializing_stage_start_time() const;\n\n    /// <summary>\n    /// If MemberInitialization set and Initialize is true on the member, then the member gets assigned to an InitializingEpisode.  \n    /// An episode is a set of users that need to have QoS metrics applied to them.  \n    /// Will be 0 when the InitializingEpisode is not set.\n    /// This value is only useful when manually managing QoS.\n    /// </summary>\n    inline uint32_t intializing_episode() const;\n\n    /// <summary>\n    /// Returns an OR'd set of MultiplayerSessionChangeTypes values representing the aspects of \n    /// the session that the current xboxlivecontext is subscribed to, of None if there is none.\n    /// </summary>\n    inline multiplayer_session_change_types subscribed_change_types() const;\n\n    /// <summary>\n    /// Host candidates are an ordered list of device tokens, ordered by preference as specified by MultiplayerSessionConstants::PeerToHostRequirements::HostSelectionMetric.\n    /// </summary>\n    inline std::vector<string_t> host_candidates() const;\n    \n    /// <summary>\n    /// The uniquely identifying information for the session.\n    /// </summary>\n    inline multiplayer_session_reference session_reference() const;\n    \n    /// <summary>\n    /// A set of constants associated with this session.  These can only be set when creating the session.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_session_constants> session_constants() const;\n    \n    /// <summary>\n    /// A set of properties associated with this session.  Any player can modify these properties.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_session_properties> session_properties() const;\n\n    /// <summary>\n    /// A set of role types associated with this session.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_session_role_types> session_role_types() const;\n    \n    /// <summary>\n    /// A collection of members that are in the session or entering the session together. \n    /// Call MultiplayerSession::Join or MultiplayerSession::Leave to add or remove yourself from this list.  \n    /// Call MultiplayerSession::AddMemberReservation to add a reservation for another user on this list.\n    /// Call multiplayer_service::write_session to write these changes to the service.\n    /// </summary>\n    inline std::vector<std::shared_ptr<multiplayer_session_member>> members() const;\n    \n    /// <summary>\n    /// A multiplayer session servers that contains properties associated with a target session reference.\n    /// </summary>\n    inline multiplayer_session_matchmaking_server matchmaking_server() const;\n\n    /// <summary>\n    /// The number of members that have accepted and are added to the session and are no longer pending.\n    /// </summary>\n    inline uint32_t members_accepted() const;\n    \n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// A JSON string containing a collection of servers for this multiplayer session.\n    /// </summary>\n    inline web::json::value servers_json() const;\n    \n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// A JSON string containing a collection of servers for this multiplayer session.\n    /// </summary>\n    inline void set_servers_json(_In_ const web::json::value& serversJson);\n    \n    /// <summary>\n    /// The ETag returned with this session.\n    /// </summary>\n    inline string_t e_tag() const;\n    \n    /// <summary>\n    /// Returns the current User in the session.  A nullptr will be returned if there is no current user in the session.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_session_member> current_user() const;\n    \n    /// <summary>\n    /// The branch of the session used to scope change numbers. \n    /// </summary>\n    inline string_t branch() const;\n\n    /// <summary>\n    /// The change number of the session.\n    /// </summary>\n    inline uint64_t change_number() const;\n    \n    /// <summary>\n    /// On writing a session, the status of the write\n    /// </summary>\n    inline write_session_status write_status() const;\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Add a new member reservation on the session for the specified xboxUserId and member constants.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID to add a reservation for.</param>\n    /// <param name=\"memberCustomConstantsJson\">The custom constants to set for this member.  This is the only time the member's constants can be set. (Optional)</param>\n    inline std::error_code add_member_reservation(\n        _In_ const string_t& xboxUserId,\n        _In_ const web::json::value& memberCustomConstantsJson = web::json::value()\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Add a new member reservation on the session for the specified xboxUserId and member constants.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID to add a reservation for.</param>\n    /// <param name=\"memberCustomConstantsJson\">The custom constants to set for this member.  This is the only time the member's constants can be set. (Optional)</param>\n    /// <param name=\"initializeRequested\">True if the system should perform managed initialization, and false otherwise.</param>\n    inline std::error_code add_member_reservation(\n        _In_ const string_t& xboxUserId,\n        _In_ const web::json::value& memberCustomConstantsJson,\n        _In_ bool initializeRequested\n        );\n\n    /// <summary>\n    /// Joins this user to the session, sets the user to active.\n    /// </summary>\n    /// <param name=\"memberCustomConstantsJson\">The custom constants to set for this member.  \n    /// This is the only time the member's constants can be set. </param>\n    /// <param name=\"initializeRequested\">True if the system should perform managed    \n    /// initialization, and false otherwise.</param>\n    /// <param name=\"joinWithActiveStatus\">True if player should join with active status.</param>\n    /// <param name=\"addInitializePropertyToRequest\">True to write the 'initialize' property to the request. False otherwise and that means initializeRequested will be ignored.</param>\n    inline xbox_live_result<std::shared_ptr<multiplayer_session_member>> join(\n        _In_ const web::json::value& memberCustomConstantsJson = web::json::value(),\n        _In_ bool initializeRequested = true,\n        _In_ bool joinWithActiveStatus = true,\n        _In_ bool addInitializePropertyToRequest = true\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// Sets the visibility of the session.\n    /// </summary>\n    /// <param name=\"visibility\">Set the visibility setting of the session.</param>    \n    inline void set_visibility(_In_ multiplayer_session_visibility visibility);\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// Sets the max member count of the session.\n    /// </summary>\n    /// <param name=\"maxMembersInSession\">Set the max member count of the session.</param>    \n    inline void set_max_members_in_session(_In_ uint32_t maxMembersInSession);\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Sets the max member count per role. \n    /// Note: Only the session owner can modify role settings and only those that are multiplayer_role_type::mutable_role_settings()\n    /// In your session template, you also need to set 'hasOwners' capability and 'ownerManaged' to true for the specific role type \n    /// that you want to modify the mutable_role_setting off.\n    /// </summary>\n    /// <param name=\"roleTypes\">A map of role type names to multiplayer role type</param>\n    inline std::error_code set_mutable_role_settings(\n        _In_ const std::unordered_map<string_t, multiplayer_role_type>& roleTypes\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// Sets the timeouts for the session.\n    /// </summary>\n    /// <param name=\"memberReservedTimeout\">The timeout for a member reservation, in milliseconds. A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n    /// <param name=\"memberInactiveTimeout\">The timeout for a member to be considered inactive, in milliseconds. A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n    /// <param name=\"memberReadyTimeout\">The timeout for a member to be considered ready, in milliseconds. A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n    /// <param name=\"sessionEmptyTimeout\">The timeout for an empty session, in milliseconds. A value of 0 is allowed and indicates an immediate timeout. If the timeout is not specified, it is considered infinite.</param>\n    inline std::error_code set_timeouts(\n        _In_ std::chrono::milliseconds memberReservedTimeout,\n        _In_ std::chrono::milliseconds memberInactiveTimeout,\n        _In_ std::chrono::milliseconds memberReadyTimeout,\n        _In_ std::chrono::milliseconds sessionEmptyTimeout\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// Enables or disables connectivity metrics for the session.\n    /// For ones that are enabled, they must be sufficient to satisfy the QoS requirements.\n    /// </summary>\n    /// <param name=\"enableLatencyMetric\">True to enable the measuring of latency, and false to disable latency measurement.</param>\n    /// <param name=\"enableBandwidthDownMetric\">True to enable the measuring of bandwidth down, and false to disable bandwidth down measurement.</param>\n    /// <param name=\"enableBandwidthUpMetric\">True to enable the measuring of bandwidth up, and false to disable bandwidth up measurement.</param>\n    /// <param name=\"enableCustomMetric\">True to enable custom metrics, and false to disable them.</param>\n    inline std::error_code set_quality_of_service_connectivity_metrics(\n        _In_ bool enableLatencyMetric,\n        _In_ bool enableBandwidthDownMetric,\n        _In_ bool enableBandwidthUpMetric,\n        _In_ bool enableCustomMetric\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// If a 'memberInitialization' object is set, the session expects the client system or title to perform \n    /// initialization following session creation and/or as new members join the session.\n    /// The timeouts and initialization stages are automatically tracked by the session, including QoS \n    /// measurements if any metrics are set. These timeouts override the session's reservation and ready \n    /// timeouts for members that have 'initializationEpisode' set.\n    /// </summary>\n    /// <param name=\"joinTimeout\">The period of time, in milliseconds, that the Xbox system waits for a member to join the session.</param>\n    /// <param name=\"measurementTimeout\">The period of time, in milliseconds, that the Xbox system waits for a measuring operation during managed initialization.</param>\n    /// <param name=\"evaluationTimeout\">The period of time, in milliseconds, that the Xbox system waits for an evaluation.</param>\n    /// <param name=\"externalEvaluation\">False if the Xbox system should auto-evaluate the session service, and true if the title performs the evaluation.</param>\n    /// <param name=\"membersNeededToStart\">The number of members needed to start the session, for initialization episode zero only.</param>\n    inline std::error_code set_member_initialization(\n        _In_ std::chrono::milliseconds joinTimeout,\n        _In_ std::chrono::milliseconds measurementTimeout,\n        _In_ std::chrono::milliseconds evaluationTimeout,\n        _In_ bool externalEvaluation,\n        _In_ uint32_t membersNeededToStart\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// These thresholds apply to each pairwise connection for all members in a session.\n    /// </summary>\n    /// <param name=\"latencyMaximum\">The maximum latency, in milliseconds, between session members.</param>\n    /// <param name=\"bandwidthMinimumInKilobitsPerSecond\">The minimum bandwidth, in kilobits per second, between members.</param>\n    inline std::error_code set_peer_to_peer_requirements(\n        _In_ std::chrono::milliseconds latencyMaximum,\n        _In_ uint32_t bandwidthMinimumInKilobitsPerSecond\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// These thresholds apply to each connection from a host candidate.\n    /// </summary>\n    /// <param name=\"latencyMaximum\">The maximum latency time, in milliseconds.</param>\n    /// <param name=\"bandwidthDownMinimumInKilobitsPerSecond\">The minimum bandwidth, in kilobits per second, for information sent from the host to the session member.</param>\n    /// <param name=\"bandwidthUpMinimumInKilobitsPerSecond\">The minimum bandwidth, in kilobits per second, for information sent from the session member to the host.</param>\n    /// <param name=\"hostSelectionMetric\">An enumeration value indicating the metric for the Xbox system to use in selecting a host.</param>\n    inline std::error_code set_peer_to_host_requirements(\n        _In_ std::chrono::milliseconds latencyMaximum,\n        _In_ uint32_t bandwidthDownMinimumInKilobitsPerSecond,\n        _In_ uint32_t bandwidthUpMinimumInKilobitsPerSecond,\n        _In_ multiplay_metrics hostSelectionMetric\n        );\n    \n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.    \n    /// </summary>\n    /// <param name=\"capabilities\">A collection of MultiplayerSessionCapabilities flags that apply to the MultiplayerSessionConstant's capabilities JSON object</param>\n    inline std::error_code set_session_capabilities(\n        _In_ const multiplayer_session_capabilities& capabilities\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// Can only be specified if the 'cloudCompute' capability is set. Enables clients to request that a cloud compute instance be allocated on behalf of the session.\n    /// </summary>\n    /// <param name=\"sessionCloudComputePackageConstantsJson\">Cloud compute instance be allocated on behalf of the session.</param>\n    inline std::error_code set_cloud_compute_package_json(\n        _In_ const web::json::value& sessionCloudComputePackageConstantsJson\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// This can only be set when creating a new session.\n    /// The set of potential server connection strings that should be evaluated. \n    /// </summary>\n    /// <param name=\"initializationSucceeded\">True if initialization succeeded, and false otherwise.</param>\n    inline void set_initialization_status(\n        _In_ bool initializationSucceeded\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Sets the device token of the host.\n    /// If \"peerToHostRequirements\" is set and this is set, the measurement stage assumes the given host is the correct host and only measures metrics to that host.\n    /// </summary>\n    /// <param name=\"hostDeviceToken\">The host device token.</param>\n    inline void set_host_device_token(\n        _In_ const string_t& hostDeviceToken\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Forces a specific server connection string to be used, useful in preserveSession=always cases.\n    /// </summary>\n    /// <param name=\"serverConnectionPath\">The server connection path. Setting this path can be useful when the session is preserved.</param>\n    inline void set_matchmaking_server_connection_path(\n        _In_ const string_t& serverConnectionPath\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// If set to true, makes the session \"closed\", meaning that new users will not be able to join unless they already have a reservation.\n    /// </summary>\n    inline void set_closed(\n        _In_ bool closed\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// If set to true, it would allow the members of the session to be locked, such that if a user leaves they are able to come back into the session but\n    /// no other user could take that spot. If the session is locked, it must also be set to closed.\n    /// </summary>\n    inline void set_locked(\n        _In_ bool locked\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// If set to true, makes the session \"closed\", meaning that new users will not be able to join unless they already have a reservation.\n    /// </summary>\n    inline void set_allocate_cloud_compute(\n        _In_ bool allocateCloudCompute\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set matchResubmit to true if the match that was found didn't work out and needs to be resubmitted. \n    /// Set matchResubmit to false to signal that the match did work, and the matchmaking service can release the session.\n    /// </summary>\n    /// <param name=\"matchResubmit \">True if the match that was found was not successful and needs to be resubmitted.</param>\n    inline void set_matchmaking_resubmit(\n        _In_ bool matchResubmit\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// The ordered list of case-insensitive connection strings that the session could use to connect to \n    /// a game server. Generally titles should use the first on the list, but sophisticated titles could use \n    /// a custom mechanism for choosing one of the others (e.g. based on load).\n    /// </summary>\n    /// <param name=\"serverConnectionStringCandidates\">The collection of connection paths.</param>\n    inline void set_server_connection_string_candidates(\n        _In_ const std::vector<string_t>& serverConnectionStringCandidates\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local \n    /// session object but does not commit it to the service. Configures the set of session changes that \n    /// this client will be subscribed to.  Set to \"MultiplayerSessionChangeTypes::None\" to clear the subscription.\n    /// </summary>\n    /// <param name=\"changeTypes\">Or'd set of MultiplayerSessionChangeType enum values representing the change types to subscribe to.</param>\n    inline std::error_code set_session_change_subscription(\n        _In_ multiplayer_session_change_types changeTypes\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// With the user who either created or got the session, leave the session. If the session is deleted as a result of this action, a 204 response with a nullptr for the MultiplayerSession object will be returned. \n    /// </summary>\n    inline std::error_code leave();\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set the current user to active or inactive.  \n    /// You cannot set the user to reserved or ready in this manner.  \n    /// Use AddMemberReservation() to add a member reservation.\n    /// The member must first be joined to the session.\n    /// </summary>\n    /// <param name=\"status\">Indicates the current user status.</param>\n    inline std::error_code set_current_user_status(\n        _In_ multiplayer_session_member_status status\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set the base64 encoded secure device address of the member\n    /// The member must first be joined to the session.\n    /// </summary>\n    /// <param name=\"value\">Indicates the value of the current user's secure device address encoded in base64.</param>\n    inline std::error_code set_current_user_secure_device_address_base64(\n        _In_ const string_t& value\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set the role info of the member.\n    /// The member must first be joined to the session.\n    /// </summary>\n    /// <param name=\"roles\">Indicates a collection of role types to role names for the current user.</param>\n    inline std::error_code set_current_user_role_info(\n        _In_ const std::unordered_map<string_t, string_t>& roles\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set a collection of members in the group\n    /// The member must first be joined to the session.\n    /// </summary>\n    /// <param name=\"value\">Indicates the value of the current user's secure device address encoded in base64.</param>\n    inline std::error_code set_current_user_members_in_group(\n        _In_ const std::vector<std::shared_ptr<multiplayer_session_member>>& membersInGroup\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Sets a collection of MultiplayerQualityOfServiceMeasurements for the members.  \n    /// This is only useful when the title is manually managing QoS.\n    /// If the platform is automatically performing QoS, this does not need to be called.\n    /// </summary>\n    /// <param name=\"measurements\">A collection of objects representing the QoS measurements.</param>\n    inline std::error_code set_current_user_quality_of_service_measurements(\n        _In_ std::shared_ptr<std::vector<multiplayer_quality_of_service_measurements>> measurements\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Sets measurements JSON for the servers.  \n    /// This is only useful when the title is manually managing QoS.\n    /// If the platform is automatically performing QoS, this does not need to be called.\n    /// </summary>\n    /// <param name=\"serverMeasurementsJson\">The JSON that represents the server measurements.</param>\n    inline std::error_code set_current_user_quality_of_service_measurements_json(\n        _In_ const web::json::value& serverMeasurementsJson\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set a custom property on the current user to the specified JSON string\n    /// The member must first be joined to the session.\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    inline std::error_code set_current_user_member_custom_property_json(\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson = web::json::value()\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Delete a custom property on the current user\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set</param>\n    inline std::error_code delete_current_user_member_custom_property_json(\n        _In_ const string_t& name\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Sets the properties of the matchmaking.  This should only be set by a client acting as a matchmaking service. \n    /// </summary>\n    /// <param name=\"matchmakingTargetSessionConstantsJson\">A JSON string representing the target session constants.</param>\n    inline std::error_code set_matchmaking_target_session_constants_json(\n        _In_ const web::json::value& matchmakingTargetSessionConstantsJson\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Set a session custom property to the specified JSON string.\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    inline std::error_code set_session_custom_property_json(\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson = web::json::value()\n        );\n\n    /// <summary>\n    /// Call multiplayer_service::write_session after this to write batched local changes to the service. \n    /// If this is called without multiplayer_service::write_session, this will only change the local session object but does not commit it to the service.\n    /// Deletes a session custom property. \n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    inline std::error_code delete_session_custom_property_json(\n        _In_ const string_t& name\n        );\n\n    /// <summary>\n    /// Static compare method that allows comparison between 2 sessions and returns a Or'ed MultiplayerSessionChangeType.\n    /// </summary>\n    /// <param name=\"currentSession\">A session to compare to the other.</param>\n    /// <param name=\"oldSession\">A session to compare to the other.</param>\n    /// <returns>An OR'ed MultiplayerSessionChangeType that contains all of the differences.</returns>\n    inline static xbox_live_result<multiplayer_session_change_types> compare_multiplayer_sessions(\n        _In_ std::shared_ptr<multiplayer_session> currentSession,\n        _In_ std::shared_ptr<multiplayer_session> oldSession\n        );\n\n    /// <summary>\n    /// Static method that converts an HTTP Status code to a write_session_status\n    /// </summary>\n    /// <param name=\"httpStatusCode\">Status code of a http result</param>\n    /// <returns>A write_session_status which gives more specific information about the status code in regards to the Write Session Call</returns>\n    inline static write_session_status convert_http_status_to_write_session_status(\n        _In_ int32_t httpStatusCode\n        );\n\n    /// <summary>\n    /// Internal function.\n    /// </summary>\n    inline multiplayer_session(XblMultiplayerSessionHandle handle);\n    inline ~multiplayer_session();\n\nprivate:\n    multiplayer_session(const multiplayer_session&) = delete;\n    multiplayer_session& operator=(multiplayer_session) = delete;\n\n    XblMultiplayerSessionHandle m_handle;\n    const XblMultiplayerSessionInfo* m_sessionInfo;\n    mutable std::shared_ptr<multiplayer_session_constants> m_sessionConstants;\n    mutable std::shared_ptr<multiplayer_session_properties> m_sessionProperties;\n\n    friend class multiplayer_service;\n};\n\n/// <summary>\n/// Arguments passed to the event handler when a session change occurs.\n/// </summary>\nclass multiplayer_session_change_event_args\n{\npublic:\n    /// <summary>\n    /// The session that triggered this event.\n    /// </summary>\n    inline multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// The branch of the session used to scope change numbers. \n    /// </summary>\n    inline string_t branch() const;\n\n    /// <summary>\n    /// The change number of the session.\n    /// </summary>\n    inline uint64_t change_number() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_session_change_event_args(const XblMultiplayerSessionChangeEventArgs& args);\n\nprivate:\n    XblMultiplayerSessionChangeEventArgs m_args;\n};\n\n/// <summary>\n/// Gets the visible multiplayer sessions based on the configuration of this request.\n/// </summary>\nclass multiplayer_get_sessions_request\n{\npublic:\n    /// <summary>Creates a GetSessionsRequest object.</summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration id that the sessions part of.</param>\n    /// <param name=\"maxItems\">The maximum number of items to return.</param>\n    inline multiplayer_get_sessions_request(\n        _In_ string_t serviceConfigurationId,\n        _In_ uint32_t maxItems = 0\n        );\n\n    /// <summary>\n    /// The service configuration id that the sessions part of.\n    /// </summary>\n    inline string_t service_configuration_id();\n\n    /// <summary>\n    /// The maximum number of items to return.\n    /// </summary>\n    inline uint32_t max_items();\n\n    /// <summary>\n    /// Include private sessions to the result.\n    /// </summary>\n    inline bool include_private_sessions();\n\n    /// <summary>\n    /// Sets the query to include private sessions in the result.\n    /// </summary>\n    /// <param name=\"includePrivateSessions\">Whether to include private sessions.</param>\n    inline void set_include_private_sessions(_In_ bool includePrivateSessions);\n\n    /// <summary>\n    /// Include sessions that the user hasn't accepted.  Must specify xboxUserIdFilter to use.\n    /// </summary>\n    inline bool include_reservations();\n\n    /// <summary>\n    /// Sets the query to include session reservations for members in the result.\n    /// </summary>\n    /// <param name=\"includeResevations\">Whether to include reservations.</param>\n    inline void set_include_reservations(_In_ bool includeResevations);\n\n    /// <summary>\n    /// Include inactive sessions to the result.  Must specify xboxUserIdFilter to use.\n    /// </summary>\n    inline bool include_inactive_sessions();\n\n    /// <summary>\n    /// Sets the query to include inactive sessions in the result.\n    /// </summary>\n    /// <param name=\"includeInactiveSessions\">Whether to include inactive sessions.</param>\n    inline void set_include_inactive_sessions(_In_ bool includeInactiveSessions);\n\n    /// <summary>\n    /// Filter result to just sessions this Xbox User ID in it.\n    /// </summary>\n    inline string_t xbox_user_id_filter();\n\n    /// <summary>\n    /// Sets the xbox user id filter. (The xboxUserIdFilter, xboxUserIdsFilter, or keywordFilter must be specified)\n    /// </summary>\n    /// <param name=\"filter\">The xbox user id to filter by.</param>\n    inline void set_xbox_user_id_filter(_In_ const string_t& filter);\n\n    /// <summary>\n    /// Filter result to just sessions these Xbox User IDs in it.\n    /// </summary>\n    inline std::vector<string_t> xbox_user_ids_filter();\n\n    /// <summary>\n    /// Sets the xbox user ids filter. (The xboxUserIdFilter, xboxUserIdsFilter, or keywordFilter must be specified)\n    /// </summary>\n    /// <param name=\"filter\">The xbox user ids to filter by.</param>\n    inline void set_xbox_user_ids_filter(_In_ const std::vector<string_t>& filter);\n    \n    /// <summary>\n    /// Filter result to just sessions with this keyword.\n    /// </summary>\n    inline string_t keyword_filter();\n\n    /// <summary>\n    /// Sets the xbox user ids filter. (The xboxUserIdFilter, xboxUserIdsFilter, or keywordFilter must be specified)\n    /// </summary>\n    /// <param name=\"filter\">The keyword to filter by.</param>\n    inline void set_keyword_filter(_In_ const string_t& filter);\n\n    /// <summary>\n    /// The name of the template for the multiplayer session to filter on.\n    /// </summary>\n    inline string_t session_template_name_filter();\n\n    /// <summary>\n    /// Sets the session template to filter by.\n    /// </summary>\n    /// <param name=\"filter\">The session template name to filter by.</param>\n    inline void set_session_template_name_filter(_In_ const string_t& filter);\n\n    /// <summary>\n    /// Filter result to just sessions with the specified visibility.\n    /// </summary>\n    inline multiplayer_session_visibility visibility_filter();\n\n    /// <summary>\n    /// Sets the session template to filter by.\n    /// </summary>\n    /// <param name=\"filter\">The session template name to filter by.</param>\n    inline void set_visibility_filter(_In_ multiplayer_session_visibility filter);\n\n    /// <summary>\n    /// Filter result to just sessions with this major version or less of the contract. (use 0 to ignore)\n    /// </summary>\n    inline uint32_t contract_version_filter();\n\n    /// <summary>\n    /// Sets the contract version to filter by.\n    /// </summary>\n    /// <param name=\"filter\">The contract version to filter by.</param>\n    inline void set_contract_version_filter(_In_ uint32_t filter);\n\nprivate:\n    XblMultiplayerSessionQuery m_request;\n    std::vector<uint64_t> m_xuidFilters;\n    std::string m_keywordFilter;\n    friend class multiplayer_service;\n};\n\n/// <summary>\n/// Queries for the all search handles that references the searchable sessions given the specific query.\n/// There is no paging or continuation, and the multiplayer service will limit the number of items returned to 100.\n/// </summary>\nclass multiplayer_query_search_handle_request\n{\npublic:\n    /// <summary> Creates a multiplayer_query_search_handle_request object.\n    /// <param name=\"serviceConfigurationId\">The scid within which to query for search handles.</param>\n    /// <param name=\"sessionTemplateName\">The name of the template to query for search handles.</param>\n    /// </summary>\n    inline multiplayer_query_search_handle_request(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& sessionTemplateName\n        );\n\n    /// <summary>\n    /// The service configuration id that the sessions part of.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// The name of the template that the sessions part of.\n    /// </summary>\n    inline const string_t& session_template_name() const;\n\n    /// <summary>\n    /// The attribute to sort the search handles by.\n    /// </summary>\n    inline const string_t& order_by() const;\n\n    /// <summary>\n    /// Specify the attribute to sort the search handles by.\n    /// Valid values are \"Timestamp desc\", \"Timestamp asc\" or any Numbers search attribute followed by 'asc or 'desc' (ex: 'Numbers/gamerank asc')\n    /// </summary>\n    /// <param name=\"orderBy\">Pass empty string to default to ordering by 'Timestamp asc'.</param>\n    inline void set_order_by(_In_ const string_t& orderBy);\n\n    /// <summary>\n    /// The order to sort the search handles by.\n    /// </summary>\n    inline bool order_ascending() const;\n\n    /// <summary>\n    /// Specify the order to sort the search handles by.\n    /// </summary>\n    /// <param name=\"orderAscending\">Pass true to order ascending, false to order descending</param>\n    inline void set_order_ascending(_In_ bool orderAscending);\n\n    /// <summary>\n    /// The filter to search for.\n    /// </summary>\n    inline const string_t& search_filter() const;\n\n    /// <summary>\n    /// Specify the filter to search for.\n    /// The filter syntax is an OData like syntax with only the following operators supported EQ, NE, GE, GT, LE and LT along with the logical operators of AND and OR.\n    ///\n    /// Example 1:\n    /// To search for search handles for a specific XboxUserId use\n    ///     \"MemberXuids/any(d:d eq '12345678')\" or \"OwnerXuids/any(d:d eq '12345678')\"\n    ///\n    /// Example 2:\n    /// To search for search handles for a title defined string metadata use\n    ///     \"Strings/stringMetadataType eq 'value'\"\n    ///\n    /// Example 3:\n    /// To search for search handles for a title defined numbers metadata AND a tag type value use\n    ///     \"Numbers/numberMetadataType eq 53 AND Tags/tagType eq 'value'\"\n    /// </summary>\n    /// <param name=\"searchFilter\">The filter string to search for.</param>\n    inline void set_search_filter(_In_ const string_t& searchFilter);\n\n    /// <summary>\n    /// The social group to get the search handles for.\n    /// </summary>\n    inline const string_t& social_group() const;\n\n    /// <summary>\n    /// Specify the social group to get the search handles for.\n    /// </summary>\n    /// <param name=\"socialGroup\">The social group to use in order to get the list of users. (e.g. \"people\" or \"favorites\")</param>\n    inline void set_social_group(_In_ const string_t& socialGroup);\n\nprivate:\n    string_t m_scid;\n    string_t m_sessionTemplateName;\n    string_t m_orderBy;\n    bool m_orderAscending{ false };\n    string_t m_searchFilter;\n    string_t m_socialGroup;\n};\n\n/// <summary>\n/// Sets the search handle based on the configuration of this request.\n/// </summary>\nclass multiplayer_search_handle_request\n{\npublic:\n    /// <summary> Creates a multiplayer_search_handle_request object.</summary>\n    /// <param name=\"sessionRef\">The session referenceid that the sessions part of.</param>\n    inline multiplayer_search_handle_request(\n        _In_ multiplayer_session_reference sessionRef\n    );\n\n    /// <summary>\n    /// The session reference that the sessions part of.\n    /// </summary>\n    inline multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// Filter result to just sessions with the tags set.\n    /// </summary>\n    inline std::vector<string_t> tags() const;\n\n    /// <summary>\n    /// Sets the tags to filter by.\n    /// </summary>\n    /// <param name=\"filter\">The tags to filter by.</param>\n    inline void set_tags(_In_ const std::vector<string_t>& value);\n\n    /// <summary>\n    /// Filter result to just sessions with the numbers metadata.\n    /// </summary>\n    inline std::unordered_map<string_t, double> numbers_metadata() const;\n\n    /// <summary>\n    /// Sets the numbers metadata to filter by.\n    /// </summary>\n    /// <param name=\"filter\">The tags to filter by.</param>\n    inline void set_numbers_metadata(_In_ const std::unordered_map<string_t, double>& metadata);\n\n    /// <summary>\n    /// Filter result to just sessions with the strings metadata.\n    /// </summary>\n    inline std::unordered_map<string_t, string_t> strings_metadata() const;\n\n    /// <summary>\n    /// Sets the strings metadata to filter by.\n    /// </summary>\n    /// <param name=\"filter\">The tags to filter by.</param>\n    inline void set_strings_metadata(_In_ const std::unordered_map<string_t, string_t>& metadata);\n\nprivate:\n    XblMultiplayerSessionReference m_sessionRef;\n    std::vector<XblMultiplayerSessionTag> m_tags;\n    std::vector<XblMultiplayerSessionStringAttribute> m_stringAttributes;\n    std::vector<XblMultiplayerSessionNumberAttribute> m_numberAttributes;\n\n    friend class multiplayer_service;\n};\n\n/// <summary>\n/// Used to handle interactions with an Xbox Live service endpoint on a server. \n/// </summary>\nclass multiplayer_service\n{\npublic:\n    /// <summary>\n    /// Writes a new or updated multiplayer session to the service.\n    /// The passed multiplayerSession must have a valid multiplayer_session_reference set on it.\n    /// </summary>\n    /// <param name=\"multiplayerSession\">A MultiplayerSession object that has been modified with the changes to write.</param>\n    /// <param name=\"multiplayerSessionWriteMode\">The type of write operation</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, a MultiplayerSession\n    /// object is returned that contains the response returned from the server. Note that if you leave a session that you are the \n    /// the last member of and the sessionEmptyTimeout is equal to 0, then the session will be deleted immediately and a nullptr will be returned. </returns>\n    /// <remarks>Calls V105 PUT /serviceconfigs/{serviceConfigurationId}/sessionTemplates/{sessiontemplateName}/sessions/{sessionName}</remarks>\n    inline pplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> write_session(\n        _In_ std::shared_ptr<multiplayer_session> multiplayerSession,\n        _In_ multiplayer_session_write_mode writeMode\n        );\n\n    /// <summary>\n    /// Writes a new or updated multiplayer session to the service, using the specified handle to the session.  \n    /// A handle is a service-side pointer to a session.  The handleid is a GUID identifier of the handle.  Callers will\n    /// usually get the handleid either from another player's MultiplayerActivityDetails, or from an invite.\n    ///\n    /// Use this method only if your MultiplayerSession object doesn't have a multiplayer_session_reference, as  \n    /// a handle's lifetime may be shorter than that of the session it points to.\n    /// \n    /// </summary>\n    /// <param name=\"multiplayerSession\">A MultiplayerSession object that has been modified with the changes to write</param>\n    /// <param name=\"multiplayerSessionWriteMode\">The type of write operation</param>\n    /// <param name=\"handleId\">The ID of the handle that should be used when writing the session.</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, a MultiplayerSession\n    /// object is returned that contains the response returned from the server. The returned MultiplayerSession will\n    /// contain a multiplayer_session_reference, so may be used when calling write_session. Note that if you leave a session that you are the \n    /// the last member of and the sessionEmptyTimeout is equal to 0, then the session will be deleted immediately and a nullptr will be returned. </returns>\n    /// <remarks>Calls V105 PUT /handles/{handleid}/session</remarks>\n    inline pplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> write_session_by_handle(\n        _In_ std::shared_ptr<multiplayer_session> multiplayerSession,\n        _In_ multiplayer_session_write_mode multiplayerSessionWriteMode,\n        _In_ const string_t& handleId\n        );\n\n    /// <summary>\n    /// Gets a session object with all its attributes from the server.\n    /// </summary>\n    /// <param name=\"sessionReference\">A multiplayer_session_reference object containing identifying information for the session.</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, a MultiplayerSession\n    /// object is returned that contains the response returned from the server.</returns>\n    /// <remarks>Calls V102 GET /serviceconfigs/{serviceConfigurationId}/sessionTemplates/{sessiontemplateName}/sessions/{sessionName}</remarks>\n    inline pplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> get_current_session(\n        _In_ multiplayer_session_reference sessionReference\n        );\n\n    /// <summary>\n    /// Gets a session object with all its attributes from the server, given a session handle id.\n    /// A handle is a service-side pointer to a session.  The handleid is a GUID identifier of the handle.  Callers will\n    /// usually get the handleid either from another player's MultiplayerActivityDetails, or from an invite.\n    /// </summary>\n    /// <param name=\"handleId\">A multiplayer handle id, which uniquely identifies the session.</param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, a MultiplayerSession\n    /// object is returned that contains the response returned from the server.</returns>\n    /// <remarks>Calls GET /handles/{handleId}/session</remarks>\n    inline pplx::task<xbox_live_result<std::shared_ptr<multiplayer_session>>> get_current_session_by_handle(\n        _In_ const string_t& handleId\n        );\n\n    /// <summary>\n    /// Retrieve a list of sessions with various filters\n    /// </summary>\n    /// <param name=\"getSessionRequest\">A session request object that sends a query for the session </param>\n    /// <returns>The async object for notifying when the operation is completed. With the handler, a collection of\n    /// SessionStates objects are returned where each contains metadata about one session.</returns>\n    /// <remarks>Calls V102 GET /serviceconfigs/{scid}/sessions or /serviceconfigs/{scid}/sessiontemplates/{session-template-name}/sessions</remarks>\n    inline pplx::task<xbox_live_result<std::vector<multiplayer_session_states>>> get_sessions(\n        _In_ multiplayer_get_sessions_request getSessionsRequest\n        );\n\n    /// <summary>\n    /// Sets the passed session as the user's current activity, which will be displayed in Xbox \n    /// dashboard user experiences (e.g. friends and gamercard) as associated with the currently \n    /// running title.  If the session is joinable, it may also be displayed as such in those \n    /// user experiences.\n    /// </summary>\n    /// <param name=\"sessionReference\">A multiplayer_session_reference for the session of the activity</param>\n    /// <returns>The async object for notifying when the operation is completed.</returns>\n    inline pplx::task<xbox_live_result<void>> set_activity(_In_ multiplayer_session_reference sessionReference);\n\n    /// <summary>\n    /// The access rights the caller has to the origin session are extended to the target session.\n    /// For example, in a title with a lobby session and a game session, the title could put a transfer handle \n    /// linking the lobby to the game inside the lobby session. Users invited to the lobby can use the handle to join the game session as well.\n    /// The transfer handle is deleted once the target session is deleted.\n    /// </summary>\n    /// <param name=\"targetSessionReference\">Target multiplayer_session_reference for the session you want to extend the access rights for</param>\n    /// <param name=\"originSessionReference\">Origin multiplayer_session_reference for the session that grants access to the target session</param>\n    /// <returns>The async object for notifying when the operation is completed. This contains the transfer handle ID string.</returns>\n    inline pplx::task<xbox_live_result<string_t>> set_transfer_handle(\n        _In_ multiplayer_session_reference targetSessionReference,\n        _In_ multiplayer_session_reference originSessionReference\n        );\n\n    /// <summary>\n    /// Creates a search handle associated with the session. The visibility of the session is dependent on its search handle. \n    /// While you can create an searchable session, it is not queryable and visible to others unless you have the associated search handle committed as well. \n    /// </summary>\n    /// <param name=\"searchHandleRequest\">A search handle request object for the associated session</param>\n    /// <returns>The async object for notifying when the operation is completed.</returns>\n    inline pplx::task<xbox_live_result<void>> set_search_handle(\n        _In_ multiplayer_search_handle_request searchHandleRequest\n        );\n\n    /// <summary>\n    /// Clears the user's current activity session for the specified serviceConfigurationId\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">A string containing the serviceConfigurationId in which to clear activity.</param>\n    /// <returns>The async object for notifying when the operation is completed.</returns>\n    inline pplx::task<xbox_live_result<void>> clear_activity(_In_ const string_t& serviceConfigurationId);\n\n    /// <summary>\n    /// Clears the search handle that is associated with the session.\n    /// </summary>\n    /// <param name=\"handleId\">The handleId associated with the session to clear.</param>\n    /// <returns>The async object for notifying when the operation is completed.</returns>\n    inline pplx::task<xbox_live_result<void>> clear_search_handle(_In_ const string_t& handleId);\n\n    /// <summary>\n    /// Invites the specified users to a session.  This will result in a notification being shown to\n    /// each invited user using standard invite text.  If a user accepts that notification the title will be activated.\n    /// </summary>\n    /// <param name=\"sessionReference\">A multiplayer_session_reference object representing the session the target users will be invited to.</param>\n    /// <param name=\"xboxUserIds\">The list of xbox user IDs who will be invited.</param>\n    /// <param name=\"titleId\">The ID of the title that the invited user will activate in order to join the session.</param>\n    /// <returns>The async object for notifying when the operation is completed.  This contains a vectorview of handle ID strings corresponding to the invites that have been sent.</returns>\n    inline pplx::task<xbox_live_result<std::vector<string_t>>> send_invites(\n        _In_ multiplayer_session_reference sessionReference,\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ uint32_t titleId\n        );\n\n    /// <summary>\n    /// Invites the specified users to a session.  This will result in a notification being shown to\n    /// each invited user.  If a user accepts that notification the title will be activated.\n    /// </summary>\n    /// <param name=\"sessionReference\">A multiplayer_session_reference object representing the session the target users will be invited to.</param>\n    /// <param name=\"xboxUserIds\">The list of xbox user IDs who will be invited.</param>\n    /// <param name=\"titleId\">The ID of the title that the invited user will activate in order to join the session.</param>\n    /// <param name=\"contextStringId\">The custom context string ID.  This string ID is defined \n    /// during Xbox Live ingestion to identify the invitation text that is additional to the standard \n    /// invitation text. The ID string must be prefixed with \"///\".  Pass an empty string if \n    /// you don't want a custom string added to the invite.</param>\n    /// <param name=\"customActivationContext\">The activation context string. A game defined string that is passed to the invited game client and interpreted as desired. (Optional)</param>\n    /// <returns>The async object for notifying when the operation is completed.  This contains a vectorview of handle ID strings corresponding to the invites that have been sent.</returns>\n    inline pplx::task<xbox_live_result<std::vector<string_t>>> send_invites(\n        _In_ multiplayer_session_reference sessionReference,\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ uint32_t titleId,\n        _In_ const string_t& contextStringId,\n        _In_ const string_t& customActivationContext\n        );\n\n    /// <summary>\n    /// Queries for the current activity for a socialgroup of users associated with a particular\n    /// \"owner\" user.  There is no paging or continuation, and the multiplayer service will\n    /// limit the number of items returned to 100.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The scid within which to query for activities.</param>\n    /// <param name=\"socialGroupOwnerXboxUserId\">The person whose social group will be used for the query.</param>\n    /// <param name=\"socialGroup\">The social group to use in order to get the list of users. (e.g. \"friends\" or \"favorites\")</param>\n    /// <returns>The async object for notifying when the operation is completed.  This contains a vectorview of MultiplayerActivityDetails objects, containing the details of the activities of the targeted users.</returns>\n    inline pplx::task<xbox_live_result<std::vector<multiplayer_activity_details>>> get_activities_for_social_group(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& socialGroupOwnerXboxUserId,\n        _In_ const string_t& socialGroup\n        );\n\n    /// <summary>\n    /// Queries for the current activity for a set of users specified by xuid.  \n    /// There is no paging or continuation, and the multiplayer service will limit the \n    /// number of items returned to 100.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The scid within which to query for activities.</param>\n    /// <param name=\"xboxUserIds\">The list of user ids to find activities for.</param>\n    /// <returns>The async object for notifying when the operation is completed.  This contains a vectorview of MultiplayerActivityDetails objects, containing the details of the activities of the targeted users.</returns>\n    inline pplx::task<xbox_live_result<std::vector<multiplayer_activity_details>>> get_activities_for_users(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const std::vector<string_t>& xboxUserIds\n        );\n\n    /// <summary>\n    /// Queries for the all search handles that references the searchable sessions given the specific query.\n    /// There is no paging or continuation, and the multiplayer service will limit the number of items returned to 100.\n    /// Call get_search_handles(multiplayer_query_search_handle_request) instead.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The scid within which to query for search handles.</param>\n    /// <param name=\"sessionTemplateName\">The name of the template to query for search handles.</param>\n    /// <param name=\"orderBy\">This specifies the attribute to sort the search handles by.  Pass empty string to default to ordering by 'Timestamp asc'. (Optional)</param>\n    /// <param name=\"orderAscending\">Pass true to order ascending, false to order descending</param>\n    /// <param name=\"searchFilter\">The query string to get the search handles for. (Optional)\n    /// The search query.\n    /// The query syntax is an OData like syntax with only the following operators supported EQ, NE, GE, GT, LE and LT along with the logical operators of AND and OR.\n    ///\n    /// Example 1:\n    /// To search for search handles for a specific XboxUserId use\n    ///     \"MemberXuids/any(d:d eq '12345678')\" or \"OwnerXuids/any(d:d eq '12345678')\"\n    ///\n    /// Example 2:\n    /// To search for search handles for a title defined string metadata use\n    ///     \"Strings/stringMetadataType eq 'value'\"\n    ///\n    /// Example 3:\n    /// To search for search handles for a title defined numbers metadata AND a tag type value use\n    ///     \"Numbers/numberMetadataType eq 53 AND Tags/tagType eq 'value'\"\n    /// </param>\n    /// <returns>The async object for notifying when the operation is completed.  This contains a vectorview of multiplayer_search_handle_details objects, containing the details of the search handles.</returns>\n    inline pplx::task<xbox_live_result<std::vector<multiplayer_search_handle_details>>> get_search_handles(\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& sessionTemplateName,\n        _In_ const string_t& orderBy,\n        _In_ bool orderAscending,\n        _In_ const string_t& searchFilter\n        );\n\n    /// <summary>\n    /// Queries for the all search handles that references the searchable sessions given the specific query.\n    /// There is no paging or continuation, and the multiplayer service will limit the number of items returned to 100.\n    /// </summary>\n    /// <param name=\"searchHandleRequest\"> A search handle request object that queries for the all search handles.</param>\n    /// <returns>The async object for notifying when the operation is completed.  This contains a vectorview of multiplayer_search_handle_details objects, containing the details of the search handles.</returns>\n    inline pplx::task<xbox_live_result<std::vector<multiplayer_search_handle_details>>> get_search_handles(\n        _In_ const multiplayer_query_search_handle_request& searchHandleRequest\n        );\n\n    /// <summary>\n    /// Starts multiplayerservice connectivity via RTA, for two purposes:\n    /// 1. subscriptions to changes on specific sessions, using the MultiplayerSession object.\n    /// 2. automatic removal of members from sessions when the collection underlying this multiplayer subscription is broken.\n    /// This method does not actually make the connection, but enables the connection, and helps track its lifetime.\n    /// This method will fail if called twice, unless the multiplayerconnection has been lost or stopped in the interim.  \n    /// This can be detected by listening for the MultiplayerSubscriptionsLost event.\n    /// </summary>\n    inline std::error_code enable_multiplayer_subscriptions();\n\n    /// <summary>\n    /// Stops multiplayerservice connectivity via RTA.\n    /// When stopping multiplayer is complete, a MultiplayerSubscriptionsLost event will fire.\n    /// It is not necessary to wait for this event to fire, unless you intend to call EnableMultiplayerSubscriptions() to re-start it,\n    /// in which case you must wait for the stop to complete.\n    /// </summary>\n    inline void disable_multiplayer_subscriptions();\n\n    /// <summary>\n    /// Indicates whether multiplayer subscriptions are currently enabled.  \n    /// </summary>\n    inline bool subscriptions_enabled();\n\n    /// <summary>\n    /// Registers an event handler for notifications when a multiplayer session changes.\n    /// Event handlers receive a multiplayer_session_change_event_args&amp; object.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    /// <remarks>\n    /// Session subscriptions are created using the multiplayer_session object within the multiplayer namespace.\n    /// </remarks>\n    inline function_context add_multiplayer_session_changed_handler(_In_ std::function<void(const multiplayer_session_change_event_args&)> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for multiplayer session change notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    /// <param name=\"context\">The callback function that receives notifications.</param>\n    inline void remove_multiplayer_session_changed_handler(_In_ function_context context);\n\n    /// <summary>\n    /// Registers an event handler for notifications when a multiplayer subscription is lost.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    /// <remarks>\n    /// Session subscriptions are created using the multiplayer_session object within the multiplayer namespace.\n    /// </remarks>\n    inline function_context add_multiplayer_subscription_lost_handler(_In_ std::function<void()> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for multiplayer subscription lost notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    inline void remove_multiplayer_subscription_lost_handler(_In_ function_context context);\n\n    /// <summary>\n    /// Registers an event handler for notifications when a multiplayer connection id is changed.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    /// <remarks>\n    /// Connection id maps the multiplayer service to rta.\n    /// </remarks>\n    inline function_context add_multiplayer_connection_id_changed_handler(_In_ std::function<void()> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for multiplayer connection id changed notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    inline void remove_multiplayer_connection_id_changed_handler(_In_ function_context context);\n\n    inline multiplayer_service(const multiplayer_service& other);\n    inline multiplayer_service& operator=(multiplayer_service other);\n    inline ~multiplayer_service();\n\nprivate:\n    inline multiplayer_service(_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_handle;\n    struct HandlerContext;\n\n    friend xbox_live_context;\n};\n}}}\n\n#include \"impl/multiplayer.hpp\"\n\n#endif"
  },
  {
    "path": "Include/xsapi-cpp/multiplayer_manager.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <mutex>\n#include \"pplx/pplxtasks.h\"\n#include \"xsapi-cpp/types.h\"\n#include \"xsapi-c/multiplayer_manager_c.h\"\n\ntypedef void* context_t;\n\nnamespace xbox { namespace services { \n    /// <summary>\n    /// Contains classes related to multiplayer.\n    /// </summary>\n    namespace multiplayer { \n        /// <summary>\n        /// Contains classes and enumerations for more easily managing multiplayer\n        /// scenarios.\n        /// </summary>\n        namespace manager {\n\n/// <summary>\n/// Defines values used to indicate who can join your lobby.\n/// </summary>\nenum class joinability\n{\n    /// <summary>\n    /// Joinability not set or no lobby exists yet.\n    /// </summary>\n    none,\n\n    /// <summary>\n    /// Default value. The lobby is joinable by users who are followed by an existing member of the session.\n    /// </summary>\n    joinable_by_friends,\n\n    /// <summary>\n    /// The lobby is joinable only via an invite.\n    /// </summary>\n    invite_only,\n\n    /// <summary>\n    /// This option will close the lobby only when a game is in progress. All other times,\n    /// it will keep the lobby open for invite_only so invitees can join when no game is in progress.\n    /// </summary>\n    disable_while_game_in_progress,\n\n    /// <summary>\n    /// This option will close the lobby immediately.\n    /// </summary>\n    closed\n};\n\n/// <summary>\n/// Defines values used to indicate status for the matchmaking stages.\n/// </summary>\nenum match_status\n{\n    /// <summary>\n    /// Indicates no matchmaking search has been started.\n    /// </summary>\n    none,\n\n    /// <summary>\n    /// Indicates that a match ticket was submitted for matchmaking.\n    /// </summary>\n    submitting_match_ticket,\n\n    /// <summary>\n    /// Indicates that matchmaking is still searching.\n    /// </summary>\n    searching,\n\n    /// <summary>\n    /// Indicates that matchmaking search has found a match.\n    /// </summary>\n    found,\n\n    /// <summary> \n    /// Joining initialization stage.\n    /// Matchmaking creates the game session and adds users to it.\n    /// The client has up to the joining timeout to join the session during this phase.\n    /// </summary>\n    joining,\n\n    /// <summary> \n    /// Waiting for remote clients to join the game session.\n    /// The client has up to the joining timeout to join the session during this phase.\n    /// </summary>\n    waiting_for_remote_clients_to_join,\n\n    /// <summary>\n    /// Measuring initialization stage.\n    /// Stage where QoS measurement happens.\n    /// The client has up to the measurement timeout to upload qos measurements to the service during this phase.\n    /// </summary>\n    measuring,\n\n    /// <summary>\n    /// Uploading QoS measurement results to the service.\n    /// The client has up to the measurement timeout to upload qos measurements to the service during this phase.\n    /// </summary>\n    uploading_qos_measurements,\n\n    /// <summary>\n    /// Waiting for remote clients to upload QoS measurement results to the service.\n    /// The client has up to the measurement timeout to upload qos measurements to the service during this phase.\n    /// </summary>\n    waiting_for_remote_clients_to_upload_qos,\n\n    /// <summary>\n    /// Evaluating initialization stage.\n    /// If auto evaluate is true, then this stage is skipped.  \n    /// Otherwise the title will do its own evaluation.\n    /// </summary>\n    evaluating,\n\n    /// <summary>\n    /// Match was found and QoS measurement was successful.\n    /// </summary>\n    completed,\n\n    /// <summary>\n    /// If the match that was found was not successful and is resubmitting.\n    /// </summary>\n    resubmitting,\n\n    /// <summary>\n    /// Indicates that matchmaking search has expired.\n    /// </summary>\n    expired,\n\n    /// <summary>\n    /// Indicates that matchmaking is in the process of canceling the search.\n    /// </summary>\n    canceling,\n\n    /// <summary>\n    /// Indicates that matchmaking search has been canceled.\n    /// </summary>\n    canceled,\n\n    /// <summary>\n    /// Failed initialization stage.\n    /// The initialization failed.\n    /// </summary>\n    failed,\n};\n\n/// <summary>\n/// Defines values used to indicate event types for a multiplayer lobby or game.\n/// </summary>\nenum class multiplayer_event_type\n{\n    /// <summary>\n    /// Indicates the user was added.\n    /// </summary>\n    user_added,\n    \n    /// <summary>\n    /// Indicates the user was removed.\n    /// </summary>\n    user_removed,\n    \n    /// <summary>\n    /// Indicates a new member has joined the session.\n    /// The event_args object should be cast to a\n    /// member_joined_event_args object for more information.\n    /// </summary>\n    member_joined,\n\n    /// <summary>\n    /// Indicates a member has left the session.\n    /// The event_args object should be cast to a\n    /// member_left_event_args object for more information.\n    /// </summary>\n    member_left,\n\n    /// <summary>\n    /// Indicates a member property has changed.\n    /// The event_args object should be cast to a\n    /// member_property_changed_event_args object for more information.\n    /// </summary>\n    member_property_changed,\n\n    /// <summary>\n    /// Indicates that the set_local_member_properties() or delete_local_member_properties() operation has completed.\n    /// Upon completion, the game can view the err() to see if the write succeeded.\n    /// A game can be write local member properties by calling the set_local_member_properties() operation.\n    /// </summary>\n    local_member_property_write_completed,\n\n    /// <summary>\n    /// Indicates that the set_local_member_connection_address() operation has completed.\n    /// Upon completion, the game can view the err() to see if the write succeeded.\n    /// A game can be write local member properties by calling the set_local_member_connection_address() operation.\n    /// </summary>\n    local_member_connection_address_write_completed,\n\n    /// <summary>\n    /// Indicates a session (lobby or game) property has changed.\n    /// The event_args object should be cast to a\n    /// session_property_changed_event_args object for more information.\n    /// </summary>\n    session_property_changed,\n\n    /// <summary>\n    /// Indicates that the set_synchronized_properties() operation has completed.\n    /// Upon completion, the game can view the err() to see if the write succeeded.\n    /// A game can be write synchronized properties by calling the set_properties() operation.\n    /// </summary>\n    session_property_write_completed,\n\n    /// <summary>\n    /// Indicates that the set_synchronized_properties() operation has completed.\n    /// Upon completion, the game can view the err() to see if the write succeeded.\n    /// A game can be write synchronized properties by calling the set_synchronized_properties() operation.\n    /// </summary>\n    session_synchronized_property_write_completed,\n\n    /// <summary>\n    /// Indicates host has changed.\n    /// The event_args object should be cast to a\n    /// host_changed_event_args object for more information.\n    /// </summary>\n    host_changed,\n\n    /// <summary>\n    /// Indicates that the set_synchronized_host() operation has completed.\n    /// Upon completion, the game can view the err() to see if the write succeeded.\n    /// A game can be write synchronized host by calling the set_synchronized_host() operation.\n    /// </summary>\n    synchronized_host_write_completed,\n\n    /// <summary>\n    /// Indicates that the joinability value has changed.\n    /// A game can be change the state by calling the set_joinability() operation.\n    /// </summary>\n    joinability_state_changed,\n\n    /// <summary>\n    /// Fired when a match has been found, and the client has joined the target game session.\n    /// When this event occurs, title should provide qos measurement results (via set_quality_of_service_measurements) between itself and a list of remote clients.\n    /// Note: If your title does not require QoS (based on the session template), this event will not be triggered.\n    /// </summary>\n    perform_qos_measurements,\n\n    /// <summary>\n    /// Indicates that the find_match() operation has completed.\n    /// The event_args object should be cast to a\n    /// find_match_completed_event_args object for more information.\n    /// </summary>\n    find_match_completed,\n\n    /// <summary>\n    /// Indicates that the join_game() operation has completed. Once the join succeeds, \n    /// the member is now part of the game session, and can use data in the session \n    /// to connect to other game members.\n    /// </summary>\n    join_game_completed,\n\n    /// <summary>\n    /// Indicates that the leave_game() operation has completed. After receiving this event,\n    /// the game session object will be set to null. You can join another game by calling \n    /// join_game() or join_game_from_lobby().\n    /// </summary>\n    leave_game_completed,\n\n    /// <summary>\n    /// Indicates that the join_lobby() operation has completed. Once the join succeeds, \n    /// the member is now part of the lobby session, and can use data in the session \n    /// to connect to other lobby members. The event_args object should be cast to a\n    /// join_lobby_completed_event_args object for more information.\n    /// </summary>\n    join_lobby_completed,\n\n    /// <summary>\n    /// Fired when the title's connection to MPSD using the real-time activity service is lost. \n    /// When this event occurs, the title should shut down the multiplayer.\n    /// </summary>\n    client_disconnected_from_multiplayer_service,\n\n    /// <summary>\n    /// Indicates that the invite API operation has been completed.\n    /// </summary>\n    invite_sent\n};\n\n/// <summary>\n/// Defines values used to indicate types for multiplayer sessions.\n/// </summary>\nenum class multiplayer_session_type\n{\n    /// <summary>\n    /// The session type is unknown.\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// Indicates multiplayer lobby session.\n    /// </summary>\n    lobby_session,\n\n    /// <summary>\n    /// Indicates multiplayer game session.\n    /// </summary>\n    game_session,\n\n    /// <summary>\n    /// Indicates multiplayer match session.\n    /// </summary>\n    match_session\n};\n\n/// <summary>\n/// Represents a reference to a member in a multiplayer game.\n/// </summary>\nclass multiplayer_member\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_member(_In_ const XblMultiplayerManagerMember& internalMember) : m_internalMember(internalMember) {}\n\n    /// <summary>\n    /// Id for the member.\n    /// </summary>\n    inline uint32_t member_id() const;\n\n    /// <summary> \n    /// Only applicable if you are using Team rules with Smart Match. \n    /// Initial team assignment suggested by Smart Match. \n    /// </summary> \n    inline string_t initial_team() const;\n\n    /// <summary>\n    /// Xbox User ID of the member.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// The Gamertag of the member. This is only to be used for debugging purposes as this gamertag may be out of date.\n    /// It is recommended you use social manager or the profile service to get this information.\n    /// </summary>\n    inline string_t debug_gamertag() const;\n\n    /// <summary>\n    /// Indicates if this member is playing on the local device.\n    /// </summary>\n    inline bool is_local() const;\n\n    /// <summary>\n    /// Indicates if this member is part of the lobby.\n    /// </summary>\n    inline bool is_in_lobby() const;\n\n    /// <summary>\n    /// Indicates if this member is part of the game.\n    /// </summary>\n    inline bool is_in_game() const;\n\n    /// <summary>\n    /// The status of this member.\n    /// </summary>\n    inline xbox::services::multiplayer::multiplayer_session_member_status status() const;\n\n    /// <summary>\n    /// The address used for network connection.\n    /// This can be used for secure socket connection.\n    /// </summary>\n    inline string_t connection_address() const;\n\n    /// <summary>\n    /// JSON value that specify the custom properties of the member.\n    /// </summary>\n    inline web::json::value properties() const;\n\n    /// <summary>\n    /// Determines whether the member is on the same device.\n    /// </summary>\n    inline bool is_member_on_same_device(_In_ std::shared_ptr<multiplayer_member> member) const;\n\nprivate:\n    const XblMultiplayerManagerMember m_internalMember;\n    friend class multiplayer_lobby_session;\n    friend class multiplayer_game_session;\n};\n\n/// <summary>\n/// Represents a multiplayer lobby. This is also where you would manage members that are local to this device.\n/// There are 2 game objects when using a multiplayer manager.  One represents the lobby_session() which is where friends you invite will join.  \n/// Another is the game_session() which contains people that your lobby has been matched with.\n/// </summary>\nclass multiplayer_lobby_session\n{\npublic:\n    /// <summary>\n    /// A unique ID to the session used to query trace logs for entries that relate to the session.\n    /// </summary>\n    inline string_t correlation_id() const;\n\n    /// <summary>\n    /// Object containing identifying information for the session.\n    /// </summary>\n    inline xbox::services::multiplayer::multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// A collection of members that are local to this device.\n    /// </summary>\n    inline std::vector<std::shared_ptr<multiplayer_member>> local_members() const;\n\n    /// <summary>\n    /// A collection of members that are in the lobby. When a friend accepts a game invite, \n    /// members will be added to the lobby.\n    /// </summary>\n    inline std::vector<std::shared_ptr<multiplayer_member>> members() const;\n\n    /// <summary>\n    /// Returns the host member for the lobby.\n    /// The host is defined as the user with the lowest index on the host device.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_member> host() const;\n\n    /// <summary>\n    /// JSON string that specify the custom properties for the game.  These can be changed anytime.\n    /// </summary>\n    inline web::json::value properties() const;\n\n    /// <summary>\n    /// A set of constants associated with this session. These can only be set through the session template.\n    /// </summary>\n    inline const std::shared_ptr<xbox::services::multiplayer::multiplayer_session_constants> session_constants() const;\n\n    /// <summary>\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// Hosts a new lobby when the first user is added. For all other users, they will be added to the existing lobby\n    /// as secondary users. This API will also advertise the lobby for friends to join.\n    /// You can send invites, set lobby properties, access lobby members via lobby() only once you've added the local user.\n    /// While joining a lobby via an invite, or a handleId, you can skip adding the local user to avoid creating a lobby and \n    /// instead pass in the list of users in the join_lobby() API.\n    /// </summary>\n    /// <param name=\"user\">The associated system User.</param>\n    inline xbox_live_result<void> add_local_user(\n        _In_ xbox_live_user_t user\n    );\n\n    /// <summary>\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// Removes the local user from the lobby and game session.\n    /// After this method is called, if no local users are active, title will not be able to perform any further multiplayer operations.\n    /// You can join another game or re-add the local user.\n    /// </summary>\n    /// <param name=\"user\">The associated system User.</param>\n    inline xbox_live_result<void> remove_local_user(\n        _In_ xbox_live_user_t user\n    );\n\n    /// <summary>\n    /// Set a custom property on the local member to the specified JSON string\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// The result is delivered via multiplayer_event callback of type local_member_property_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"user\">The associated system User you want to set the property for.</param>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_local_member_properties(\n        _In_ xbox_live_user_t user,\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson,\n        _In_opt_ context_t context = nullptr\n    );\n\n    /// <summary>\n    /// Delete a custom property on the local member\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// The result is delivered via multiplayer_event callback of type local_member_property_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"user\">The associated system User you want to delete the property for.</param>\n    /// <param name=\"name\">The name of the property to delete</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> delete_local_member_properties(\n        _In_ xbox_live_user_t user,\n        _In_ const string_t& name,\n        _In_opt_ context_t context = nullptr\n    );\n\n    /// <summary>\n    /// Set connection address for the local member. The address can be used for network and secure socket connection.\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// The result is delivered via multiplayer_event callback of type local_member_connection_address_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"user\">The associated system User you want to set the property for.</param>\n    /// <param name=\"connectionAddress\">The network connection address to set.</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_local_member_connection_address(\n        _In_ xbox_live_user_t user,\n        _In_ const string_t& connectionAddress,\n        _In_opt_ context_t context = nullptr\n    );\n\n    /// <summary>\n    /// Whether or not the Xbox User ID is the host.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user</param>\n    inline bool is_host(\n        _In_ const string_t& xboxUserId\n    );\n\n    /// <summary>\n    /// Set a custom game property to the specified JSON string.\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// The result is delivered via multiplayer_event callback of type session_property_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_properties(\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson,\n        _In_opt_ context_t context = nullptr\n    );\n\n    /// <summary>\n    /// Sets a custom property to the specified JSON string using multiplayer_session_write_mode::synchronized_update.\n    /// Use this method to resolve any conflicts between devices while trying to set properties to a shared portion that other \n    /// devices can also modify. It ensures that updates to the session are atomic. If writing to non-sharable properties, use set_properties() instead.\n    /// The service may reject your request if a race condition occurred (due to a conflict) resulting in error_code \n    /// http_status_412_precondition_failed (HTTP status 412). To resolve this, evaluate the need to write again and re-submit if needed.\n    /// The result is delivered via multiplayer_event callback of type session_synchronized_property_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_synchronized_properties(\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson,\n        _In_opt_ context_t context = nullptr\n    );\n\n    /// <summary>\n    /// Sets the host for the game using multiplayer_session_write_mode::synchronized_update. Use this method to resolve\n    /// any conflicts between devices trying to set the host at the same time. It ensures that updates to the session are atomic. \n    /// The service may reject your request if a race condition occurred(due to a conflict) resulting in error_code\n    /// http_status_412_precondition_failed (HTTP status 412). To resolve this, evaluate the need to write again and re-submit if needed.\n    /// The result is delivered via multiplayer_event callback of type synchronized_host_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"gameHost\">The host member.</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_synchronized_host(\n        _In_ std::shared_ptr<multiplayer_member> gameHost,\n        _In_opt_ context_t context = nullptr\n    );\n\n#if HC_PLATFORM_IS_MICROSOFT\n    /// <summary>\n    /// Displays the invite UI and allows the user to select people from the user's people list and invite them to join the user's party\n    /// If a user accepts that notification the title will be activated.\n    /// </summary>\n    /// <param name=\"user\">The associated system User.</param>\n    /// <param name=\"contextStringId\">The custom context string ID.  This string ID is defined \n    /// during Xbox Live ingestion to identify the invitation text that is additional to the standard \n    /// invitation text. The ID string must be prefixed with \"///\". (Optional)</param>\n    /// <param name=\"customActivationContext\">The activation context string. A game defined string that is passed to the invited game client and interpreted as desired. (Optional)</param>\n    inline xbox_live_result<void> invite_friends(\n        _In_ xbox_live_user_t user,\n        _In_ const string_t& contextStringId = string_t(),\n        _In_ const string_t& customActivationContext = string_t()\n    );\n#endif\n\n    /// <summary>\n    /// Invites the specified users to a game.  This will result in a notification being shown to\n    /// each invited user using standard invite text.  If a user accepts that notification the title will be activated.\n    /// </summary>\n    /// <param name=\"user\">The associated system User.</param>\n    /// <param name=\"xboxUserIds\">The list of xbox user IDs who will be invited.</param>\n    /// <param name=\"contextStringId\">The custom context string ID.  This string ID is defined \n    /// during Xbox Live ingestion to identify the invitation text that is additional to the standard \n    /// invitation text. The ID string must be prefixed with \"///\". (Optional)</param>\n    /// <param name=\"customActivationContext\">The activation context string. A game defined string that is passed to the invited game client and interpreted as desired. (Optional)</param>\n    /// <returns>The async object for notifying when the operation is completed.</returns>\n    inline xbox_live_result<void> invite_users(\n        _In_ xbox_live_user_t user,\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ const string_t& contextStringId = string_t(),\n        _In_ const string_t& customActivationContext = string_t()\n    );\n\nprivate:\n    mutable std::shared_ptr<xbox::services::multiplayer::multiplayer_session_constants> m_sessionConstants;\n};\n\n/// <summary>\n/// Represents a multiplayer game.\n/// There are 2 game objects when using a multiplayer manager.  One represents the lobby_session() which is where friends you invite will join.  \n/// Another is the game_session() which contains people that your lobby has been matched with.\n/// </summary>\nclass multiplayer_game_session\n{\npublic:\n    /// <summary>\n    /// A unique ID to the session used to query trace logs for entries that relate to the session.\n    /// </summary>\n    inline string_t correlation_id() const;\n\n    /// <summary>\n    /// Object containing identifying information for the session.\n    /// </summary>\n    inline xbox::services::multiplayer::multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// A collection of members that are in the game. When a friend accepts a game invite, \n    /// members will be added to the lobby and the game session members list.\n    /// </summary>\n    inline std::vector<std::shared_ptr<multiplayer_member>> members() const;\n\n    /// <summary>\n    /// Returns the host member for the game.\n    /// The host is defined as the user with the lowest index on the host device.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_member> host() const;\n\n    /// <summary>\n    /// JSON string that specify the custom properties for the game.  These can be changed anytime.\n    /// </summary>\n    inline web::json::value properties() const;\n\n    /// <summary>\n    /// A set of constants associated with this session. These can only be set through the session template.\n    /// </summary>\n    inline const std::shared_ptr<xbox::services::multiplayer::multiplayer_session_constants> session_constants() const;\n\n    /// <summary>\n    /// Whether or not the Xbox User ID is the host.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user</param>\n    inline bool is_host(\n        _In_ const string_t& xboxUserId\n        );\n\n    /// <summary>\n    /// Set a custom game property to the specified JSON string.\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_properties(\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n\n    /// <summary>\n    /// Sets a custom property to the specified JSON string using multiplayer_session_write_mode::synchronized_update.\n    /// Use this method to resolve any conflicts between devices while trying to set properties to a shared portion that other \n    /// devices can also modify. It ensures that updates to the session are atomic. If writing to non-sharable properties, use set_properties() instead.\n    /// The service may reject your request if a race condition occurred (due to a conflict) resulting in error_code \n    /// http_status_412_precondition_failed (HTTP status 412). To resolve this, evaluate the need to write again and re-submit if needed.\n    /// The result is delivered via multiplayer_event callback of type synchronized_property_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"name\">The name of the property to set.</param>\n    /// <param name=\"valueJson\">The JSON value to assign to the property. (Optional)</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_synchronized_properties(\n        _In_ const string_t& name,\n        _In_ const web::json::value& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n\n    /// <summary>\n    /// Sets the host for the game using multiplayer_session_write_mode::synchronized_update. Use this method to resolve\n    /// any conflicts between devices trying to set the host at the same time. It ensures that updates to the session are atomic. \n    /// The service may reject your request if a race condition occurred(due to a conflict) resulting in error_code\n    /// http_status_412_precondition_failed (HTTP status 412). To resolve this, evaluate the need to write again and re-submit if needed.\n    /// The result is delivered via multiplayer_event callback of type synchronized_host_write_completed through do_work().\n    /// </summary>\n    /// <param name=\"gameHost\">The host member.</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_synchronized_host(\n        _In_ std::shared_ptr<multiplayer_member> gameHost,\n        _In_opt_ context_t context = nullptr\n        );\n\nprivate:\n    mutable std::shared_ptr<xbox::services::multiplayer::multiplayer_session_constants> m_sessionConstants;\n};\n\nclass multiplayer_event_args\n{\npublic:\n    inline multiplayer_event_args(XblMultiplayerEventArgsHandle argsHandle);\n    inline virtual ~multiplayer_event_args();\n\nprotected:\n    inline string_t GetXuid() const;\n    inline std::vector<std::shared_ptr<multiplayer_member>> GetMembers() const;\n    inline std::shared_ptr<multiplayer_member> GetMember() const;\n    inline web::json::value GetPropertiesJson() const;\n\n    XblMultiplayerEventArgsHandle m_argsHandle;\n};\n\n/// <summary>\n/// Notifies the title when a new user was added.\n/// </summary>\nclass user_added_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    user_added_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// Xbox User ID of the member that that was added.\n    /// </summary>\n    string_t xbox_user_id() const\n    {\n        return GetXuid();\n    }\n};\n\n/// <summary>\n/// Notifies the title when a user was removed.\n/// </summary>\nclass user_removed_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    user_removed_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// Xbox User ID of the member that that was removed.\n    /// </summary>\n    string_t xbox_user_id() const\n    {\n        return GetXuid();\n    }\n};\n\n/// <summary>\n/// Notifies the title when a new game member joins the game. \n/// </summary>\nclass member_joined_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    member_joined_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// A list of members that joined the game. \n    /// </summary>\n    std::vector<std::shared_ptr<multiplayer_member>> members()\n    {\n        return GetMembers();\n    }\n};\n\n/// <summary>\n/// Notifies the title when an existing game member leaves the game. \n/// </summary>\nclass member_left_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    member_left_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// A list of members that left the game. \n    /// </summary>\n    std::vector<std::shared_ptr<multiplayer_member>> members()\n    {\n        return GetMembers();\n    }\n};\n\n/// <summary>\n/// Notifies the title when a new host member has been set. \n/// </summary>\nclass host_changed_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    host_changed_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// The new host member. If an existing host leaves, the host_member() will be nullptr.\n    /// </summary>\n    std::shared_ptr<multiplayer_member> host_member()\n    {\n        return GetMember();\n    }\n};\n\n/// <summary>\n/// Notifies the title when a game member property has been added or modified. \n/// </summary>\nclass member_property_changed_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    member_property_changed_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// The member whose property changed.\n    /// </summary>\n    std::shared_ptr<multiplayer_member> member()\n    {\n        return GetMember();\n    }\n\n    /// <summary>\n    /// The JSON of the property that changed.\n    /// </summary>\n    web::json::value properties()\n    {\n        return GetPropertiesJson();\n    }\n};\n\n/// <summary>\n/// Notifies the title when a session property has been added or modified.\n/// </summary>\nclass session_property_changed_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    session_property_changed_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// The JSON of the property that changed.\n    /// </summary>\n    web::json::value properties()\n    {\n        return GetPropertiesJson();\n    }\n};\n\n/// <summary>\n/// Notifies the title when the client joins a lobby. Once join succeeds, the member is now \n/// part of the lobby session, and can use data in the session to connect to other lobby members.\n/// To join a friend's lobby, call join_lobby(handleId) operation using the handleId you back get from\n/// multiplayer_service::get_activities_for_social_group. If the user accepts an invite or joined a friends' game via the shell, \n/// the title will get protocol activated, in which case you should call join_lobby(IProtocolActivatedEventArgs^).\n/// \n/// For scenarios where the local user has not been added, you can pass the local user object part of the join_lobby API.\n/// If the invited user is not added via add_local_user() or through join_lobby, then join_lobby() will fail and \n/// provide the invited_xbox_user_id() that the invite was sent for as part of the join_lobby_completed_event_args().\n/// </summary>\nclass join_lobby_completed_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    join_lobby_completed_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// Invited Xbox User ID of the member that the invite was sent for.\n    /// </summary>\n    string_t invited_xbox_user_id() const\n    {\n        return GetXuid();\n    }\n};\n\n/// <summary>\n/// Contains information for an event that indicates when a multiplayer match is found.\n/// </summary>\nclass find_match_completed_event_args : public multiplayer_event_args\n{\npublic:\n    find_match_completed_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n\n    /// <summary>\n    /// Provides the current matchmaking status.\n    /// </summary>\n    inline xbox::services::multiplayer::manager::match_status match_status() const;\n\n    /// <summary>\n    /// The cause of why the initialization failed, or multiplayer_measurement_failure::None if there was no failure.\n    /// Set when transitioning out of the \"joining\" or \"measuring\" stage if this member doesn't pass.\n    /// </summary>\n    inline xbox::services::multiplayer::multiplayer_measurement_failure initialization_failure_cause() const;\n};\n\n/// <summary>\n/// Notifies the title when it should provide qos measurement results between itself and a list of remote clients.\n/// </summary>\nclass perform_qos_measurements_event_args : public multiplayer_event_args\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    perform_qos_measurements_event_args(XblMultiplayerEventArgsHandle handle) : multiplayer_event_args(handle) {}\n    \n    /// <summary>\n    /// A map of connection addresses and device tokens to run qos on.\n    /// </summary>\n    inline std::map<string_t, string_t> connection_address_to_device_tokens() const;\n};\n\n/// <summary>\n/// Base class for all event arg classes. Based on the multiplayer_event_type, you would need to cast the args\n/// to the appropriate class. Note that the event will only be valid until the next call to multiplayer_manager::do_work().\n/// </summary>\nclass multiplayer_event\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline multiplayer_event(_In_ const XblMultiplayerEvent* internalEvent);\n\n    /// <summary>\n    /// The error code indicating the result of the operation.\n    /// </summary>\n    inline std::error_code err() const;\n\n    /// <summary>\n    /// Returns call specific debug information if join fails\n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    inline std::string err_message() const;\n\n    /// <summary>\n    /// A pointer to the application-defined data passed into the initiating method.\n    /// </summary>\n    context_t inline context();\n\n    /// <summary>\n    /// Type of the event triggered.\n    /// </summary>\n    inline multiplayer_event_type event_type() const;\n\n    /// <summary>\n    /// You need to cast this to one of the event arg classes to retrieve the data for that particular event.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_event_args> event_args();\n\n    /// <summary>\n    /// The multiplayer session type this event was triggered for. Depending upon the session type,\n    /// you can then retrieve the latest lobby or game session from the multiplayer_manager class.\n    /// </summary>\n    inline multiplayer_session_type session_type() const;\n\nprivate:\n    const XblMultiplayerEvent* m_internalEvent;\n    std::shared_ptr<multiplayer_event_args> m_eventArgs;\n};\n\n/// <summary>\n/// APIs for matchmaking, player roster and multiplayer session management.\n/// </summary>\nclass multiplayer_manager\n{\npublic:\n\n    /// <summary>\n    /// Gets the multiplayer_manager singleton instance\n    /// </summary>\n    inline static std::shared_ptr<multiplayer_manager> get_singleton_instance();\n\n    /// <summary>\n    /// Initializes the object.\n    /// </summary>\n    /// <param name=\"lobbySessionTemplateName\">The name of the template for the lobby session to be based on.</param>\n    inline void initialize(\n        _In_ const string_t& lobbySessionTemplateName\n        );\n\n    /// <summary>\n    /// Ensures proper game state updates are maintained between the title and the Xbox Live Multiplayer Service.\n    /// To ensure best performance, do_work() must be called frequently, such as once per frame. \n    /// Title needs to be thread safe when calling do_work() since this is when the state will change.\n    /// For example, if you looping through the list of members() on a different thread than your calling do_work() on, \n    /// it may change when do_work() is called.\n    /// </summary>\n    /// <returns>A list of all callback events for the game to handle. Empty if no events are triggered during this update.</returns>\n    inline std::vector<multiplayer_event> do_work();\n\n    /// <summary>\n    /// Represents a lobby session used for managing members that are local to this device and your invited friends.\n    /// When a member accepts a game invite, they will be added to the lobby and the game session (if it exists).\n    /// Users found via matchmaking will not be added in the lobby. \n    /// </summary>\n    inline std::shared_ptr<multiplayer_lobby_session> lobby_session() const;\n\n    /// <summary>\n    /// Represents a game session used for your active gameplay. When a member accepts an invite, \n    /// they will be added to the lobby and the game session (if there is room).\n    /// You can call leave_game() to leave the game session.\n    /// </summary>\n    inline std::shared_ptr<multiplayer_game_session> game_session() const;\n\n    /// <summary>\n    /// Joins a game given a session handle id. A handle is a service-side pointer to a session.\n    /// The handleId is a GUID identifier of the handle.  Callers will usually get the handleId from \n    /// another member's multiplayer_activity_details. Optionally, if you haven't added the local users through\n    /// lobby_session()::add_local_user(), you can pass in the list of users via the join_lobby() API.\n    /// The result is delivered via multiplayer_event callback of type join_lobby_completed through do_work().\n    /// After joining, you can set the host via set_synchronized_host if one doesn't exist.\n    /// </summary>\n    /// <param name=\"handleId\">A multiplayer handle id, which uniquely identifies the game session you want to join.</param>\n    /// <param name=\"user\">The system User joining the lobby.</param>\n    inline xbox_live_result<void> join_lobby(\n        _In_ const string_t& handleId,\n        _In_ xbox_live_user_t user\n        );\n\n#if (HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP)\n    /// <summary>\n    /// Joins a game via the specified IProtocolActivatedEventArgs.\n    /// The IProtocolActivatedEventArgs provides arguments for protocol activation. If the user accepts an invite or \n    /// joined a friends game via a shell UI, the title will get a protocol activation. The result is delivered via \n    /// join_lobby_completed_event_args() callback through do_work(). \n    /// Optionally, if you haven't added the local users through lobby_session()::add_local_user(), you can pass in \n    /// the list of users via the join_lobby() API. If the invited user is not added either via \n    /// lobby_session()::add_local_user() or through join_lobby(), then join_lobby() will fail and provide the \n    /// invited_xbox_user_id() that the invite was sent for as part of the join_lobby_completed_event_args()\n    /// After joining, you can set the host via set_synchronized_host if one doesn't exist.\n    /// </summary>\n    /// <param name=\"eventArgs\">The IProtocolActivatedEventArgs when the title is protocol activated.</param>\n    /// <param name=\"user\">The system User joining the lobby.</param>\n    inline xbox_live_result<void> join_lobby(\n        _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n        _In_ xbox_live_user_t user\n        );\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    /// <summary>\n    /// Joins a game given a session handle id. A handle is a service-side pointer to a game session.\n    /// The handleId is a GUID identifier of the handle.  Callers will usually get the handleId from \n    /// another member's multiplayer_activity_details. Optionally, if you haven't added the local users through\n    /// lobby_session()::add_local_user(), you can pass in the list of users via the join_lobby() API.\n    /// The result is delivered via multiplayer_event callback of type join_lobby_completed through do_work().\n    /// After joining, you can set the host via set_synchronized_host if one doesn't exist.\n    /// </summary>\n    /// <param name=\"handleId\">A multiplayer handle id, which uniquely identifies the game session you want to join.</param>\n    /// <param name=\"users\">List of system Users joining the lobby.</param>\n    inline xbox_live_result<void> join_lobby(\n        _In_ const string_t& handleId,\n        _In_ std::vector<Windows::Xbox::System::User^> users\n        );\n\n    /// <summary>\n    /// Joins a game via the specified IProtocolActivatedEventArgs.\n    /// The IProtocolActivatedEventArgs provides arguments for protocol activation. If the user accepts an invite or \n    /// joined a friends game via a shell UI, the title will get a protocol activation. The result is delivered via \n    /// join_lobby_completed_event_args() callback through do_work(). \n    /// Optionally, if you haven't added the local users through lobby_session()::add_local_user(), you can pass in \n    /// the list of users via the join_lobby() API. If the invited user is not added either via \n    /// lobby_session()::add_local_user() or through join_lobby(), then join_lobby() will fail and provide the \n    /// invited_xbox_user_id() that the invite was sent for as part of the join_lobby_completed_event_args()\n    /// After joining, you can set the host via set_synchronized_host if one doesn't exist.\n    /// </summary>\n    /// <param name=\"eventArgs\">The IProtocolActivatedEventArgs when the title is protocol activated.</param>\n    /// <param name=\"users\">List of system Users joining the lobby.</param>\n    inline xbox_live_result<void> join_lobby(\n        _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n        _In_ std::vector<Windows::Xbox::System::User^> users\n        );\n\n    /// <summary>\n    /// Send invites to your party to join your game.\n    /// </summary>\n    inline void invite_party_to_game();\n\n#endif\n\n    /// <summary>\n    /// Join the lobby's game session if one exists and if there is room. If the session doesn't exist, it creates a new game session\n    /// with the existing lobby members. The result is delivered via multiplayer_event callback of \n    /// type join_game_completed through do_work(). This does not migrate existing lobby session properties over to the game session. \n    /// After joining, you can set the properties or the host via game_session()::set_synchronized APIs.\n    /// </summary>\n    /// <param name=\"sessionTemplateName\">The name of the template for the game session to be based on.</param>\n    inline xbox_live_result<void> join_game_from_lobby(\n        _In_ const string_t& sessionTemplateName\n        );\n\n    /// <summary>\n    /// Joins a game given a globally unique session name. Callers can get the unique session name\n    /// as a result of the title's third party matchmaking. Call this on all clients that needs to join this game.\n    /// The result is delivered via multiplayer_event callback of type join_game_completed through do_work().\n    /// After joining, you can set the properties or the host via game_session()::set_synchronized APIs.\n    /// </summary>\n    /// <param name=\"sessionName\">A unique name for the session.</param>\n    /// <param name=\"sessionTemplateName\">The name of the template for the game session to be based on.</param>\n    /// <param name=\"xboxUserIds\">The list of xbox user IDs you want to be part of the game.</param>\n    inline xbox_live_result<void> join_game(\n        _In_ const string_t& sessionName,\n        _In_ const string_t& sessionTemplateName,\n        _In_ const std::vector<string_t>& xboxUserIds = std::vector<string_t>()\n        );\n\n    /// <summary>\n    /// Leaving the game will put you back into the lobby. This will remove all local users from the game.\n    /// The result is delivered via multiplayer_event callback of type leave_game_completed through do_work().\n    /// </summary>\n    inline xbox_live_result<void> leave_game();\n\n    /// <summary>\n    /// Sends a matchmaking request to the server.  When a match is found, the manager will join\n    /// the game and notify the title via find_match_completed_event().\n    /// </summary>\n    /// <param name=\"hopperName\">The name of the hopper.</param>\n    /// <param name=\"attributes\">The ticket attributes for the match. (Optional)</param>\n    /// <param name=\"timeout\">The maximum time to wait for members to join the match. (Optional)</param>\n    inline xbox_live_result<void> find_match(\n        _In_ const string_t& hopperName,\n        _In_ const web::json::value& attributes = web::json::value(),\n        _In_ const std::chrono::seconds& timeout = std::chrono::seconds(60)\n        );\n\n    /// <summary>\n    /// Cancels the match request on the server, if one exists.\n    /// </summary>\n    inline void cancel_match();\n\n    /// <summary>\n    /// Provides the current status of matchmaking. 'None' if no matchmaking is in progress.\n    /// </summary>\n    inline xbox::services::multiplayer::manager::match_status match_status() const;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other members.\n    /// Only applies after find_match() has been called.\n    /// </summary>\n    inline std::chrono::seconds estimated_match_wait_time() const;\n\n    /// <summary>\n    /// Indicates whether the game should auto fill open slots during gameplay.\n    /// </summary>\n    inline bool auto_fill_members_during_matchmaking() const;\n\n    /// <summary>\n    /// If set to true, it finds members via matchmaking to fill open slots during gameplay.\n    /// This can be changed anytime.\n    /// </summary>\n    /// <param name=\"autoFillMembers\">True to search for members during matchmaking if the game has open slots.</param>\n    inline void set_auto_fill_members_during_matchmaking(\n        _In_ bool autoFillMembers\n        );\n\n    /// <summary>\n    /// Sets a collection of multiplayer_quality_of_service_measurements between itself and a list of remote clients.\n    /// This is only used when the title is manually managing QoS.\n    /// </summary>\n    inline void set_quality_of_service_measurements(\n        _In_ std::shared_ptr<std::vector<xbox::services::multiplayer::multiplayer_quality_of_service_measurements>> measurements\n        );\n\n    /// <summary>\n    /// Indicates who can join your game via the lobby.\n    /// </summary>\n    inline joinability joinability() const;\n\n    /// <summary>\n    /// Restricts who can join the game. Defaults to \"joinable_by_friends\", meaning only local users and users who are followed \n    /// by an existing member of the lobby can join without an invite.\n    /// Changes are batched and written to the service on the next do_work(). All session properties and members\n    /// contain updated response returned from the server upon calling do_work().\n    /// The result is delivered via multiplayer_event callback of type joinability_state_changed through do_work().\n    /// </summary>\n    /// <param name=\"value\">The joinability value you want to set.</param>\n    /// <param name=\"context\">The application-defined data to correlate the multiplayer_event to the initiating call. (Optional)</param>\n    inline xbox_live_result<void> set_joinability(\n        _In_ xbox::services::multiplayer::manager::joinability value,\n        _In_opt_ context_t context = nullptr\n        );\n\nprivate:\n    multiplayer_manager() {}\n    multiplayer_manager(multiplayer_manager const&) = delete;\n    void operator=(multiplayer_manager const&) = delete;\n\n    mutable std::shared_ptr<multiplayer_lobby_session> m_lobbySession;\n};\n\n}}}}\n\n#include \"impl/multiplayer_manager.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/notification_helper.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#if XSAPI_I\n#include \"errors.h\"\n\nnamespace xbox { namespace services {\n    \n    enum class xbox_live_notification_type\n    {\n        unknown = 2,\n        game_invite = 1,\n        achievement_unlocked = 0\n    };\n    \n    struct xbox_live_notification\n    {\n        xbox_live_notification_type type;\n        string_t title;\n        string_t body;\n        string_t data;\n    };\n    \n\n    xbox_live_result<xbox_live_notification> parse_notification(NSDictionary* notificationInfo);\n\n}}\n#endif\n"
  },
  {
    "path": "Include/xsapi-cpp/notification_service.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <xsapi-c/notification_c.h>\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n#include <xsapi-c/achievements_c.h>\n#include <xsapi-c/game_invite_c.h>\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\nclass xbox_live_context;\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\nclass invite_notification_event_args\n{\npublic:\n    inline string_t invited_xbox_user_id() const;\n    inline string_t sender_xbox_user_id() const;\n    inline string_t sender_gamertag() const;\n    inline string_t invite_handle_id() const;\n    inline string_t invite_protocol() const;\n    inline string_t invite_context() const;\n    inline utility::datetime expiration() const;\n    inline const multiplayer::multiplayer_session_reference session_reference() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline invite_notification_event_args(_In_ const XblGameInviteNotificationEventArgs& gameInviteargs);\n\n private:\n     XblGameInviteNotificationEventArgs m_gameInviteArgs;\n};\n\nclass achievement_unlocked_notification_event_args\n{\npublic:\n    inline string_t name() const;\n    inline string_t id() const;\n    inline string_t description() const;\n    inline string_t icon_url() const;\n    inline uint64_t gamerscore() const;\n    inline string_t deeplink() const;\n    inline string_t xbox_user_id() const;\n    inline utility::datetime unlockTime() const;\n\n    achievement_unlocked_notification_event_args(_In_ const XblAchievementUnlockEvent& achievementUnlockEvent);\n\nprivate:\n    XblAchievementUnlockEvent m_achievementUnlock;\n};\n\n#endif // WIN32\n\nenum notification_filter_source_type\n{\n    media_presence = 1,\n    presence_online = 2,\n    broadcast = 3,\n    message = 4,\n    party_invite_360 = 5,\n    multiplayer = 6,\n    achievements = 8\n};\n\nstruct notification_filter\n{\n    notification_filter_source_type sourceType;\n    uint32_t type;\n};\n\nclass notification_service : public std::enable_shared_from_this<notification_service>\n{\npublic:\n    inline notification_service(\n        _In_ XblContextHandle contextHandle);\n\n    inline ~notification_service();\n\n    inline pplx::task<xbox_live_result<void>> subscribe_to_notifications(\n#if HC_PLATFORM == HC_PLATFORM_WIN32 && !defined(XSAPI_UNIT_TESTS)\n        _In_ const std::function<void(achievement_unlocked_notification_event_args&)>& achievementUnlockHandler,\n        _In_ const std::function<void(invite_notification_event_args&)>& multiplayerInviteHandler\n#elif (HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID)\n       _In_ const string_t deviceToken\n#endif\n    );\n\n    inline pplx::task<xbox_live_result<void>> unsubscribe_from_notifications();\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 && !defined(XSAPI_UNIT_TESTS)\n    inline std::function<void(invite_notification_event_args&)>& game_invite_handler();\n\n    inline std::function<void(achievement_unlocked_notification_event_args&)>& achievement_unlock_handler();\n#endif\n\nprivate:\n    XblContextHandle m_xblContext;\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 && !defined(XSAPI_UNIT_TESTS)\n    XblFunctionContext m_gameinviteFunctionContext;\n    XblFunctionContext m_achievementUnlockFunctionContext;\n\n    std::function<void(achievement_unlocked_notification_event_args&)> m_achievementUnlockedHandler;\n    std::function<void(invite_notification_event_args&)> m_inviteHandler;\n#endif\n};\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n\n#if !XSAPI_NO_PPL\n#include \"impl/notification.hpp\"\n#endif"
  },
  {
    "path": "Include/xsapi-cpp/presence.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xsapi-c/presence_c.h\"\n#include \"xsapi-cpp/real_time_activity.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n    /// <summary>\n    /// Contains classes and enumerations that let you retrieve\n    /// information about player's online presence on Xbox Live.\n    /// </summary>\n    namespace presence {\n\n/// <summary>Defines values used to indicate the device type associate with a PresenceTitleRecord.</summary>\nenum class presence_device_type\n{\n    /// <summary>Unknown device</summary>\n    unknown,\n\n    /// <summary>Windows Phone device</summary>\n    windows_phone,\n\n    /// <summary>Windows Phone 7 device</summary>\n    windows_phone_7,\n\n    /// <summary>Web device, like Xbox.com</summary>\n    web,\n\n    /// <summary>Xbox360 device</summary>\n    xbox_360,\n\n    /// <summary>Games for Windows LIVE device</summary>\n    pc,\n\n    /// <summary>Xbox LIVE for Windows device</summary>\n    windows_8,\n\n    /// <summary>Xbox One device</summary>\n    xbox_one,\n\n    /// <summary>Windows One Core devices</summary>\n    windows_one_core,\n\n    /// <summary>Windows One Core Mobile devices</summary>\n    windows_one_core_mobile\n};\n\n/// <summary>\n/// Defines values used to indicate the state of the user with regard to the presence service.\n/// </summary>\nenum class user_presence_state\n{\n    /// <summary>The state is unknown.</summary>\n    unknown,\n\n    /// <summary>User is signed in to Xbox LIVE and active in a title.</summary>\n    online,\n\n    /// <summary>User is signed-in to Xbox LIVE, but inactive in all titles.</summary>\n    away,\n\n    /// <summary>User is not signed in to Xbox LIVE.</summary>\n    offline\n};\n\n/// <summary>\n/// Defines values used to indicate the states of the screen view of presence information.\n/// </summary>\nenum class presence_title_view_state\n{\n    /// <summary>Unknown view state.</summary>\n    unknown,\n\n    /// <summary>The title's view is using the full screen.</summary>\n    full_screen,\n\n    /// <summary>The title's view is using part of the screen with another application snapped.</summary>\n    filled,\n\n    /// <summary>The title's view is snapped with another application using a part of the screen.</summary>\n    snapped,\n\n    /// <summary>The title's running in the background and is not visible.</summary>\n    background\n};\n\n/// <summary> Defines values used to set the level of presence detail return from the service. Choosing proper detail level could help the performance of the API.</summary>\nenum class presence_detail_level\n{\n    /// <summary>Default detail level.</summary>\n    default_level,\n\n    /// <summary>User detail level. User presence info only, no device, title or rich presence info.</summary>\n    user,\n\n    /// <summary>Device detail level. User and device presence info only, no title or rich presence info.</summary>\n    device,\n\n    /// <summary>Title detail level. User, device and title presence info only, no rich presence info.</summary>\n    title,\n\n    /// <summary>All detail possible. User, device, title and rich presence info will be provided.</summary>\n    all\n};\n\n/// <summary>Defines values used to indicate the media id types for media presence data.</summary>\nenum class presence_media_id_type\n{\n    /// <summary>Unknown media Id.</summary>\n    unknown,\n\n    /// <summary>Bing media Id.</summary>\n    bing,\n\n    /// <summary>MediaProvider media Id.</summary>\n    media_provider\n};\n\n/// <summary>Defines values used to indicate the title presence state for a user.</summary>\nenum class title_presence_state\n{\n    /// <summary>\n    /// Indicates this is a Unknown state.\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// Indicates the user started playing the title.\n    /// </summary>\n    started,\n\n    /// <summary>\n    /// Indicates the user ended playing the title.\n    /// </summary>\n    ended\n};\n\n/// <summary>\n/// Represents data supporting Rich Presence features.\n/// </summary>\nclass presence_data\n{\npublic:\n    /// <summary>\n    /// Initializes a new instance of the PresenceData class, which identifies where the presence strings are defined and which of the defined strings is used.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) that identifies where the presence strings are defined by Id.</param>\n    /// <param name=\"presenceId\">Id of the presence string that should be used.</param>\n    inline presence_data(\n        _In_ string_t serviceConfigurationId,\n        _In_ string_t presenceId\n        );\n\n    /// <summary>\n    /// Initializes a new instance of the PresenceData class, which identifies where the presence strings are defines, which string is used, and IDs of strings to be used in place of tokens within the presence string.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) that identifies where the presence strings are defined by Id.</param>\n    /// <param name=\"presenceId\">Id of the presence string that should be used.</param>\n    /// <param name=\"presenceTokenIds\">Ids of the strings that should be used to replace the tokens in the presence string.</param>\n    inline presence_data(\n        _In_ string_t serviceConfigurationId,\n        _In_ string_t presenceId,\n        _In_ std::vector<string_t> presenceTokenIds\n        );\n\n    /// <summary>\n    /// ID of the service configuration containing the presence strings.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// The ID of a presence string that is defined in the service configuration.\n    /// For example, PresenceId = \"1\" could equal \"Playing {0} on {1}\" in the service configuration.\n    /// The service configuration might map token 0 to Maps and token 1 to MapId.\n    /// </summary>\n    inline const string_t& presence_id() const;\n\n    /// <summary>\n    /// The IDs of the strings to replace the format string tokens found in the presence string.  These strings are also defined in the service configuration.\n    /// The ID values in the collection map to the strings associated with the token arguments found in the PresenceId.\n    /// For example let's say this vector view contained the values \"4\" and \"1\" and PresenceId = \"1\" equals \"Playing {0} on {1}\" in the service configuration.\n    /// The service configuration might map Token 0 = Maps, where MapId = \"4\" equals \"Hometown\".\n    /// The service configuration might map Token 1 = Difficulty, where DifficultyId = \"1\" equals \"Casual\".\n    /// </summary>\n    inline const std::vector<string_t>& presence_token_ids() const;\n\nprivate:\n    string_t m_serviceConfigurationId;\n    string_t m_presenceId;\n    std::vector<string_t> m_presenceTokenIds;\n};\n\nclass presence_broadcast_record\n{\npublic:\n    /// <summary>\n    /// Id for this broadcast as defined by the broadcasting service.\n    /// </summary>\n    inline string_t broadcast_id() const;\n\n    /// <summary>\n    /// The GUID uniquely identifying the broadcasting session. \n    /// </summary>\n    inline string_t session() const;\n\n    /// <summary>\n    /// Name of the streaming provider.\n    /// </summary>\n    inline string_t provider() const;\n\n    /// <summary>\n    /// Approximate number of current viewers. \n    /// </summary>\n    inline uint32_t viewer_count() const;\n\n    /// <summary>\n    /// UTC timestamp when the broadcast was started.\n    /// </summary>\n    inline utility::datetime start_time() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline presence_broadcast_record() = default;\n    inline presence_broadcast_record(_In_ XblPresenceRecordHandle handle, _In_ const XblPresenceBroadcastRecord* broadcastRecord);\n    inline presence_broadcast_record(const presence_broadcast_record& other);\n    inline presence_broadcast_record& operator=(presence_broadcast_record other);\n    inline ~presence_broadcast_record();\n\nprivate:\n    XblPresenceRecordHandle m_handle{};\n    const XblPresenceBroadcastRecord* m_broadcastRecord{ nullptr };\n};\n\nclass presence_title_record\n{\npublic:\n\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    /// <summary>\n    /// The title name.\n    /// </summary>\n    inline string_t title_name() const;\n\n    /// <summary>\n    /// The UTC timestamp when the record was last updated.\n    /// </summary>\n    inline utility::datetime last_modified_date() const;\n\n    /// <summary>\n    /// The active state for the title.\n    /// </summary>\n    inline bool is_title_active() const;\n\n    /// <summary>\n    /// The formatted and localized presence string.\n    /// </summary>\n    inline string_t presence() const;\n\n    /// <summary>\n    /// The title view state.\n    /// </summary>\n    inline presence_title_view_state presence_title_view() const;\n\n    /// <summary>\n    /// The broadcast information of what the user is broadcasting. \n    /// </summary>\n    inline presence_broadcast_record broadcast_record() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline presence_title_record(_In_ XblPresenceRecordHandle handle, _In_ const XblPresenceTitleRecord* titleRecord);\n    inline presence_title_record(_In_ const presence_title_record& other);\n    inline presence_title_record& operator=(_In_ presence_title_record other);\n    inline ~presence_title_record();\n\nprivate:\n    XblPresenceRecordHandle m_handle;\n    const XblPresenceTitleRecord* m_titleRecord;\n};\n\nclass presence_device_record\n{\npublic:\n    /// <summary>\n    /// The device type associated with this record.\n    /// </summary>\n    inline presence_device_type device_type() const;\n\n    /// <summary>\n    /// The record containing title presence data.\n    /// </summary>\n    inline std::vector<presence_title_record> presence_title_records() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline presence_device_record(_In_ XblPresenceRecordHandle handle, _In_ const XblPresenceDeviceRecord* deviceRecord);\n    inline presence_device_record(_In_ const presence_device_record& other);\n    inline presence_device_record& operator=(_In_ presence_device_record other);\n    inline ~presence_device_record();\n\nprivate:\n    XblPresenceRecordHandle m_handle;\n    const XblPresenceDeviceRecord* m_deviceRecord;\n};\n\nclass presence_record\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// The user's presence state.\n    /// </summary>\n    inline user_presence_state user_state() const;\n\n    /// <summary>\n    /// Collection of presence_device_record objects returned by a request.\n    /// </summary>\n    inline std::vector<presence_device_record> presence_device_records() const;\n\n    /// <summary>\n    /// Returns whether the user is playing this title id\n    /// </summary>\n    inline bool is_user_playing_title(_In_ uint32_t titleId) const;\n\n    presence_record() = default;\n    inline presence_record(_In_ XblPresenceRecordHandle handle);\n    inline presence_record(_In_ const presence_record& other);\n    inline presence_record& operator=(presence_record other);\n    inline ~presence_record();\n\nprivate:\n    XblPresenceRecordHandle m_handle{ nullptr };\n};\n\n/// <summary> \n/// Used to identify the Xbox user, device, and log-in status presence values.\n/// </summary>\nclass device_presence_change_event_args\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// The type of device.\n    /// </summary>\n    inline presence_device_type device_type() const;\n\n    /// <summary>\n    /// Value used to indicate if the Xbox user is logged onto the device.\n    /// </summary>\n    inline bool is_user_logged_on_device() const;\n\n    inline device_presence_change_event_args(_In_ uint64_t xuid, _In_ XblPresenceDeviceType deviceType, _In_ bool isUserLoggedOn);\n\nprivate:\n    string_t m_xuid;\n    XblPresenceDeviceType m_deviceType;\n    bool m_isUserLoggedOn;\n};\n\n/// <summary>\n/// Subscribes to changes to an Xbox user's presence on a device.\n/// </summary>\nclass device_presence_change_subscription : public xbox::services::real_time_activity::real_time_activity_subscription\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline device_presence_change_subscription(_In_ XblRealTimeActivitySubscriptionHandle handle, _In_ const string_t& xuid);\n\nprivate:\n    string_t m_xuid;\n    friend class presence_service;\n};\n\n/// <summary>\n/// Used to identify a Xbox user, title, and presence states that can be subscribed to.\n/// </summary>\nclass title_presence_change_event_args\n{\npublic:\n    /// <summary> \n    /// The Xbox user ID.\n    /// </summary> \n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    /// <summary>\n    /// Object that defines possible presence states.\n    /// </summary>\n    inline title_presence_state title_state() const;\n\n    inline title_presence_change_event_args(_In_ uint64_t xuid, _In_ uint32_t titleId, _In_ XblPresenceTitleState titleState);\n\nprivate:\n    string_t m_xuid;\n    uint32_t m_titleId;\n    XblPresenceTitleState m_titleState;\n};\n\n/// <summary>\n/// Subscribes to presence change events for the specified title and user.\n/// </summary>\nclass title_presence_change_subscription : public real_time_activity::real_time_activity_subscription\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    inline title_presence_change_subscription(_In_ XblRealTimeActivitySubscriptionHandle handle, _In_ const string_t& xuid, _In_ uint32_t titleId);\n\nprivate:\n    string_t m_xuid;\n    uint32_t m_titleId;\n    friend class presence_service;\n};\n\n#if !XSAPI_NO_PPL\nclass presence_service\n{\npublic:\n    /// <summary>\n    /// Sets presence info for the current user context.\n    /// </summary>\n    /// <param name=\"isUserActiveInTitle\">Indicates if the current user context is currently active or inactive in the title.\n    /// The application can choose to set this based on an amount of inactivity.</param>\n    /// <param name=\"presenceData\">Current user's presence data.</param>\n    /// <remarks>Calls V1 POST /users/xuid({xuid})/devices/current/titles/current</remarks>\n    inline pplx::task<xbox_live_result<void>> set_presence(\n        _In_ bool isUserActiveInTitle\n        );\n\n    /// <summary>\n    /// Sets presence info for the current user context.\n    /// </summary>\n    /// <param name=\"isUserActiveInTitle\">Indicates if the current user context is currently active or inactive in the title.\n    /// The application can choose to set this based on an amount of inactivity.</param>\n    /// <param name=\"presenceData\">Current user's presence data.</param>\n    /// <remarks>Calls V1 POST /users/xuid({xuid})/devices/current/titles/current</remarks>\n    inline pplx::task<xbox_live_result<void>> set_presence(\n        _In_ bool isUserActiveInTitle,\n        _In_ presence_data presenceData\n        );\n\n    /// <summary>\n    /// Gets presence info for a specific Xbox User Id.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user to get presence for</param>\n    /// <remarks>Calls V3 GET /users/xuid({xuid})</remarks>\n    inline pplx::task<xbox_live_result<presence_record>> get_presence(\n        _In_ const string_t& xboxUserId\n        );\n\n    /// <summary>\n    /// Gets presence info for multiple users. This returns all possible titles on all device, \n    /// defaults to presence_detail_level::default which is equivalent to\n    /// presence_detail_level::title (get basic title level information), \n    /// and does not filter out users who are offline or broadcasting.\n    /// </summary>\n    /// <param name=\"xboxUserIds\">The name of the users to get presence for.</param>\n    /// <remarks>Calls V3 POST /users/batch</remarks>\n    inline pplx::task<xbox_live_result<std::vector<presence_record>>> get_presence_for_multiple_users(\n        _In_ const std::vector<string_t>& xboxUserIds\n        );\n\n    /// <summary>\n    /// Gets presence info for multiple users with filters.\n    /// </summary>\n    /// <param name=\"xboxUserIds\">The name of the users to get presence for.</param>\n    /// <param name=\"deviceTypes\">List of device types. If the input is an empty vector, defaults to all possible deviceTypes.</param>\n    /// <param name=\"titleIds\">List of titleIds for filtering the result. If the input is an empty vector, defaults to all possible titles.</param>\n    /// <param name=\"presenceDetailLevel\">Detail level of the result. Defaults to all details</param>\n    /// <param name=\"onlineOnly\">If true, API will filter out records for users that are offline </param>\n    /// <param name=\"broadcastingOnly\">If true, API will filter out records for users that are not broadcasting. </param>\n    /// <remarks>Calls V3 POST /users/batch</remarks>\n    inline pplx::task<xbox_live_result<std::vector<presence_record>>> get_presence_for_multiple_users(\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ const std::vector<presence_device_type>& deviceTypes,\n        _In_ const std::vector<uint32_t>& titleIds,\n        _In_ presence_detail_level presenceDetailLevel,\n        _In_ bool onlineOnly,\n        _In_ bool broadcastingOnly\n        );\n\n    /// <summary>\n    /// Gets presence info for a specific group of users.\n    /// </summary>\n    /// <param name=\"socialGroup\">The name of the group of users to get presence for.\n    /// See Microsoft::Xbox::Services::Social::SocialGroupConstants for the latest options.</param>\n    /// <remarks>Calls V3 GET /users/xuid({xuid})/groups/{socialGroup}</remarks>\n    inline pplx::task<xbox_live_result<std::vector<presence_record>>> get_presence_for_social_group(\n        _In_ const string_t& socialGroup\n        );\n\n    /// <summary>\n    /// Gets presence info for a specific group of users.\n    /// </summary>\n    /// <param name=\"socialGroup\">The name of the group of users to get presence for.</param>\n    /// <param name=\"socialGroupOwnerXboxuserId\">The user whose group should be targeted. If the input is null, current user will be used.</param>\n    /// <param name=\"deviceTypes\">List of device types. If the input is null; defaults to all possible deviceTypes. (Optional) </param>\n    /// <param name=\"titleIds\">List of titleIds for filtering the result. If the input is null, defaults to all possible titles. (Optional) </param>\n    /// <param name=\"peoplehubDetailLevel\">Detail level of the result. Defaults to all details. (Optional) </param>\n    /// <param name=\"onlineOnly\">If true, API will filter out records for users that are offline. </param>\n    /// <param name=\"broadcastingOnly\">If true, API will filter out records for users that are not broadcasting. </param>\n    /// <remarks>Calls V3 POST /users/batch</remarks>\n    inline pplx::task<xbox_live_result<std::vector<presence_record>>> get_presence_for_social_group(\n        _In_ const string_t& socialGroup,\n        _In_ const string_t& socialGroupOwnerXboxUserId,\n        _In_ const std::vector<presence_device_type>& deviceTypes,\n        _In_ const std::vector<uint32_t>& titleIds,\n        _In_ presence_detail_level peoplehubDetailLevel,\n        _In_ bool onlineOnly,\n        _In_ bool broadcastingOnly\n        );\n\n    /// <summary>\n    /// Subscribes to device presence change notifications via the DevicePresenceChanged event.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the person of the subscription.</param>\n    /// <returns>RealTimeActivityDevicePresenceChangeSubscription containing the initial value of the PresenceDeviceRecord.\n    /// Register for device presence changes via the DevicePresenceChanged event.</returns>\n    inline xbox_live_result<std::shared_ptr<device_presence_change_subscription>> subscribe_to_device_presence_change(\n        _In_ const string_t& xboxUserId\n        );\n\n    /// <summary>\n    /// Unsubscribes a previously created device presence change subscription.\n    /// </summary>\n    /// <param name=\"subscription\">The subscription object to unsubscribe.</param>\n    inline xbox_live_result<void> unsubscribe_from_device_presence_change(\n        _In_ std::shared_ptr<device_presence_change_subscription> subscription\n        );\n\n    /// <summary>\n    /// Subscribes to title presence change notifications via the TitlePresenceChanged event.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the person of the subscription.</param>\n    /// <param name=\"titleId\">The title ID of the subscription.</param>\n    /// <returns>RealTimeActivityDevicePresenceChangeSubscription containing the initial value of the PresenceDeviceRecord.\n    /// Register for device presence changes via the DevicePresenceChanged event.</returns>\n    inline xbox_live_result<std::shared_ptr<title_presence_change_subscription>> subscribe_to_title_presence_change(\n        _In_ const string_t& xboxUserId,\n        _In_ uint32_t titleId\n        );\n\n    /// <summary>\n    /// Registers for title presence change notifications.  Event handlers will receive RealTimeActivityTitlePresenceChangeEventArgs^.\n    /// </summary>\n    inline xbox_live_result<void> unsubscribe_from_title_presence_change(\n        _In_ std::shared_ptr<title_presence_change_subscription> subscription\n        );\n\n    /// <summary>\n    /// Registers an event handler for device presence change notifications.\n    /// Event handlers receive a device_presence_change_event_args&amp; object.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    inline function_context add_device_presence_changed_handler(_In_ std::function<void(const device_presence_change_event_args&)> handler);\n    \n    /// <summary>\n    /// Unregisters an event handler for device presence change notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    inline void remove_device_presence_changed_handler(_In_ function_context context);\n\n    /// <summary>\n    /// Registers an event handler for title presence change notifications.\n    /// Event handlers receive a title_presence_change_event_args&amp; object.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    inline function_context add_title_presence_changed_handler(_In_ std::function<void(const title_presence_change_event_args&)> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for title presence change notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    inline void remove_title_presence_changed_handler(_In_ function_context context);\n\n    inline presence_service(const presence_service& other);\n    inline presence_service& operator=(presence_service other);\n    inline ~presence_service();\n\nprivate:\n    inline presence_service(XblContextHandle xblContextHandle);\n\n    XblContextHandle m_xblContextHandle;\n    struct HandlerContext;\n\n    friend xbox_live_context;\n};\n#endif // !XSAPI_NO_PPL\n\n}}}\n\n#if !XSAPI_NO_PPL\n#include \"impl/presence.hpp\"\n#endif\n"
  },
  {
    "path": "Include/xsapi-cpp/privacy.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/privacy_c.h\"\n\nnamespace xbox {\nnamespace services {\n    class xbox_live_context;\n/// <summary>\n/// Contains classes and enumerations that let you retrieve\n/// information about a player's privacy settings from Xbox Live.\n/// </summary>\nnamespace privacy {\n\n/// <summary>\n/// Contains the reason why permission was denied.\n/// </summary>\nclass permission_deny_reason\n{\npublic:\n    inline permission_deny_reason(const XblPermissionDenyReasonDetails& reasonDetails);\n\n    /// <summary>\n    /// The reason why permission was denied.\n    /// </summary>\n    inline string_t reason() const;\n\n    /// <summary>\n    /// If the deny reason is privilege check, this indicates which privilege failed.\n    /// </summary>\n    inline string_t restricted_setting() const;\n\nprivate:\n    XblPermissionDenyReasonDetails m_reasonDetails;\n};\n\n/// <summary>\n/// Contains the result of a permission check.\n/// </summary>\nclass permission_check_result\n{\npublic:\n    inline permission_check_result() {}\n    inline permission_check_result(const XblPermissionCheckResult* result);\n\n    /// <summary>\n    /// Indicates if the user is allowed the requested access.\n    /// </summary>\n    inline bool is_allowed() const;\n\n    /// <summary>\n    /// The permission requested.\n    /// </summary>\n    inline string_t permission_requested() const;\n\n    /// <summary>\n    /// If IsAllowed is false, contains the reasons why the permissions were denied.\n    /// </summary>\n    inline const std::vector<permission_deny_reason>& deny_reasons() const;\n\nprivate:\n    XblPermissionCheckResult m_result{};\n    std::vector<permission_deny_reason> m_reasons;\n};\n\n/// <summary>\n/// Contains the results of multiple permission checks.\n/// </summary>\nclass multiple_permissions_check_result\n{\npublic:\n    inline multiple_permissions_check_result(const XblPermissionCheckResult* results, size_t resultCount, string_t target);\n\n    /// <summary>\n    /// Xbox User Id OR anonymous user type for the permission request.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// Contains a collection of results returned when checking multiple permissions for a user.\n    /// </summary>\n    inline const std::vector<permission_check_result>& items() const;\n\nprivate:\n    string_t m_target;\n    std::vector<permission_check_result> m_items;\n};\n\n/// <summary>\n/// Manages constant values for permission IDs. \n/// </summary>\nclass permission_id_constants\n{\npublic:\n    /// <summary>\n    /// Check whether or not the user can send a message with text content to the target user.\n    /// </summary>\n    static const string_t communicate_using_text() { return _T(\"CommunicateUsingText\"); }\n\n    /// <summary>\n    /// Check whether or not the user can communicate using video with the target user.\n    /// </summary>\n    static const string_t communicate_using_video() { return _T(\"CommunicateUsingVideo\"); }\n\n    /// <summary>\n    /// Check whether or not the user can communicate using voice with the target user.\n    /// </summary>\n    static const string_t communicate_using_voice() { return _T(\"CommunicateUsingVoice\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the profile of the target user.\n    /// </summary>\n    static const string_t view_target_profile() { return _T(\"ViewTargetProfile\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the game history of the target user.\n    /// </summary>\n    static const string_t view_target_game_history() { return _T(\"ViewTargetGameHistory\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the details video watching history of the target user.\n    /// </summary>\n    static const string_t view_target_video_history() { return _T(\"ViewTargetVideoHistory\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the detailed music listening history of the target user.\n    /// </summary>\n    static const string_t view_target_music_history() { return _T(\"ViewTargetMusicHistory\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the exercise info of the target user.\n    /// </summary>\n    static const string_t view_target_exercise_info() { return _T(\"ViewTargetExerciseInfo\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the online status of the target user.\n    /// </summary>\n    static const string_t view_target_presence() { return _T(\"ViewTargetPresence\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the details of the targets video status (extended online presence).\n    /// </summary>\n    static const string_t view_target_video_status() { return _T(\"ViewTargetVideoStatus\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the details of the targets music status (extended online presence).\n    /// </summary>\n    static const string_t view_target_music_status() { return _T(\"ViewTargetMusicStatus\"); }\n\n    /// <summary>\n    /// Check whether or not a user can play multiplayer with the target user.\n    /// </summary>\n    static const string_t play_multiplayer() { return _T(\"PlayMultiplayer\"); }\n\n    /// <summary>\n    /// Checks whether or not the user can view information about how audio buffers are broadcast for the target user.\n    /// </summary>\n    static const string_t broadcast_with_twitch() { return _T(\"BroadcastWithTwitch\"); }\n\n    /// <summary>\n    /// Check whether or not the user can view the user-created content of other users.\n    /// </summary>\n    static const string_t view_target_user_created_content() { return _T(\"ViewTargetUserCreatedContent\"); }\n};\n\n/// <summary>\n/// Special strings that can be passed in as to check_permission APIs to check permission for different\n/// classes of non-Xbox Live users.\n/// </summary>\nclass anonymous_user_type_constants\n{\npublic:\n    /// <summary>\n    /// A non Xbox Live user\n    /// </summary>\n    static string_t cross_network_user() { return _T(\"crossNetworkUser\"); }\n\n    /// <summary>\n    /// A non Xbox Live user that a title recognizes as an in-game friend.\n    /// </summary>\n    static string_t crost_network_friend() { return _T(\"crossNetworkFriend\"); }\n};\n\n/// <summary>\n/// Provides an endpoint for managing privacy settings.\n/// </summary>\nclass privacy_service\n{\npublic:\n    /// <summary>\n    /// Get the list of Xbox Live Ids the calling user should avoid during multiplayer matchmaking.\n    /// </summary>\n    /// <returns>A collection of XboxUserIds that correspond to the calling user's avoid list.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET /users/xuid({xuid})/people/avoid\n    /// </remarks>\n    inline pplx::task<xbox_live_result<std::vector<string_t>>> get_avoid_list();\n\n    /// <summary>\n    /// Check a single permission with a single target user.\n    /// </summary>\n    /// <param name=\"permissionId\">The ID of the permission to check.\n    /// See microsoft::xbox::services::privacy::permission_id_constants for the latest options.</param>\n    /// <param name=\"target\">The target user's Xbox Live ID OR an anonymous user type string from anonymous_user_type_constants.</param>\n    /// <returns>The permission check result against a single user.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET /users/{requestorId}/permission/validate\n    /// </remarks>\n    inline pplx::task<xbox_live_result<permission_check_result>> check_permission_with_target_user(\n        _In_ const string_t& permissionId,\n        _In_ const string_t& target\n    );\n\n    /// <summary>\n    /// Check multiple permissions with multiple target users.\n    /// </summary>\n    /// <param name=\"permissionIds\">The collection of IDs of the permissions to check.\n    /// See microsoft::xbox::services::privacy::permission_id_constants for the latest options.</param>\n    /// <param name=\"targets\">The collection of target Xbox user IDs and/or anonymous user types to check permissions against.</param>\n    /// <returns>A multiple permission check result which contains a collection of permission information.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 POST /users/{requestorId}/permission/validate\n    /// </remarks>\n    inline pplx::task<xbox_live_result<std::vector<multiple_permissions_check_result>>> check_multiple_permissions_with_multiple_target_users(\n        _In_ const std::vector<string_t>& permissionIds,\n        _In_ const std::vector<string_t>& targets\n    );\n\n    /// <summary>\n    /// Get the list of Xbox Live Ids that the calling user should not hear (mute) during multiplayer matchmaking.\n    /// </summary>\n    /// <returns>The collection of Xbox user IDs that represent the mute list for a user.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET /users/xuid({xuid})/people/mute\n    /// </remarks>\n    inline pplx::task<xbox_live_result<std::vector<string_t>>> get_mute_list();\n\n    /// <summary>\n    /// Get either a user's avoid list or a user's mute list.\n    /// </summary>\n    /// <param name=\"subPathName\">A string indicating what type of list to get for the user.\n    /// The valid values are \"avoid\" and \"mute\". </param>\n    /// <returns>The collection of Xbox user IDs that represent the either the avoid list or the mute list for a user.</returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    ///\n    /// Calls V1 GET /users/xuid({xuid})/people/mute\n    /// </remarks>\n    inline pplx::task<xbox_live_result<std::vector<string_t>>> get_avoid_or_mute_list(_In_ const string_t& subPathName);\n\n    inline privacy_service(const privacy_service& other);\n    inline privacy_service& operator=(privacy_service other);\n    inline ~privacy_service();\n\nprivate:\n    inline privacy_service(_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_xblContext;\n\n    friend xbox_live_context;\n};\n\n} } }\n\n#include \"impl/privacy.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/profile.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/profile_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass xbox_live_context;\n/// <summary>\n/// Contains classes and enumerations that let you retrieve\n/// information about a player's Xbox Live profile.\n/// </summary>\nnamespace social {\n\n    /// <summary> \n    /// Represents a user's Xbox Live profile.\n    /// </summary>\n    class xbox_user_profile\n    {\n    public:\n        /// <summary>\n        /// Name for displaying in apps. This will be the user's gamertag.\n        /// </summary>\n        inline string_t app_display_name() const;\n\n        /// <summary>\n        /// Uri for the user's display picture to be used in application UI.\n        /// The Uri is a resizable Uri. It can be used to specify one of the following sizes and formats by appending &apos;&amp;format={format}&amp;w={width}&amp;h={height}:\n        /// Format: png\n        /// Width   Height\n        /// 64      64\n        /// 208     208\n        /// 424     424\n        /// </summary>\n        inline web::uri app_display_picture_resize_uri() const;\n\n        /// <summary>\n        /// Name for displaying in games. This will be the user's gamertag.\n        /// </summary>\n        inline string_t game_display_name() const;\n\n        /// <summary>\n        /// Uri for the user's display picture to be used in games.\n        /// The Uri is a resizable Uri. It can be used to specify one of the following sizes and formats by appending &apos;&amp;format={format}&amp;w={width}&amp;h={height}:\n        /// Format: png\n        /// Width   Height\n        /// 64      64\n        /// 208     208\n        /// 424     424\n        /// </summary>\n        inline web::uri game_display_picture_resize_uri() const;\n\n        /// <summary>\n        /// The user's Gamerscore.\n        /// </summary>\n        inline string_t gamerscore() const;\n\n        /// <summary>\n        /// The user's Gamertag.\n        /// </summary>\n        inline string_t gamertag() const;\n\n        /// <summary>\n        /// The user's Xbox user ID.\n        /// </summary>\n        inline string_t xbox_user_id() const;\n\n        inline xbox_user_profile() = default;\n        inline xbox_user_profile(const XblUserProfile& profile);\n    private:\n        XblUserProfile m_profile{};\n    };\n\n    /// <summary>\n    /// Services that manage user profile.\n    /// </summary>\n    class profile_service\n    {\n    public:\n        /// <summary>\n        /// Gets a user profile for a specific Xbox user.\n        /// </summary>\n        /// <param name=\"xboxUserId\">The Xbox User ID of the user to get the profile for.</param>\n        /// <returns>\n        /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n        /// The result of the asynchronous operation is an xbox_user_profile object.\n        /// </returns>\n        /// <remarks>Calls V2 GET /users/batch/profile/settings</remarks>\n        inline pplx::task<xbox::services::xbox_live_result<xbox_user_profile>> get_user_profile(\n            _In_ string_t xboxUserId\n        );\n\n        /// <summary>\n        /// Gets one or more user profiles for a collection of specified Xbox users.\n        /// </summary>\n        /// <param name=\"xboxUserIds\">The collection of Xbox User IDs of the users to get profiles for</param>\n        /// <returns>\n        /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n        /// The result of the asynchronous operation is a collection of xbox_user_profile objects.\n        /// </returns>\n        /// <remarks>Calls V2 GET /users/batch/profile/settings</remarks>\n        inline pplx::task<xbox::services::xbox_live_result<std::vector<xbox_user_profile>>> get_user_profiles(\n            _In_ const std::vector<string_t>& xboxUserIds\n        );\n\n        /// <summary>\n        /// Gets user profiles for users in a specified social group.\n        /// </summary>\n        /// <param name=\"socialGroup\">The name of the social group of users to search.\n        /// See xbox::services::social::social_group_constants for the latest options.</param>\n        /// <returns>\n        /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n        /// The result of the asynchronous operation is a collection of xbox_user_profile objects.\n        /// </returns>\n        /// <remarks>Calls V2 GET /users/{userId}/profile/settings/people/{socialGroup}</remarks>\n        inline pplx::task<xbox::services::xbox_live_result< std::vector< xbox_user_profile>>> get_user_profiles_for_social_group(\n            _In_ const string_t& socialGroup\n        );\n\n        inline profile_service(const profile_service& other);\n        inline profile_service& operator=(profile_service other);\n        inline ~profile_service();\n\n    private:\n        inline profile_service(XblContextHandle xblContextHandle);\n\n        XblContextHandle m_xblContextHandle;\n\n        friend xbox_live_context;\n    };\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/profile.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/real_time_activity.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <mutex>\n#include \"xsapi-c/real_time_activity_c.h\"\n#include \"xsapi-cpp/types.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n}}\n\nnamespace xbox { namespace services { \n    /// <summary>\n    /// Contains classes and enumerations that let you subscribe\n    /// to real time activity information for a player statistic\n    /// on Xbox Live.\n    /// </summary>\n    namespace real_time_activity {\n\n/// <summary>\n/// Enumeration for the message types for the Xbox Live service.\n/// The value of each enum should not be changed.\n/// </summary>\nenum class real_time_activity_message_type\n{\n    /// <summary>\n    /// Indicates that this is a Subscribe message.\n    /// </summary>\n    subscribe = 1,\n\n    /// <summary>\n    /// Indicates that this is a Unsubscribe message.\n    /// </summary>\n    unsubscribe = 2,\n\n    /// <summary>\n    /// Indicates that this is a ChangeEvent message.\n    /// </summary>\n    change_event = 3,\n\n    /// <summary>\n    /// Indicates that this is a Resync message.\n    /// </summary>\n    resync = 4\n};\n\n/// <summary>\n/// Enumeration for the possible states of a statistic subscription request\n/// to the real-time activity service.\n/// </summary>\nenum real_time_activity_subscription_state\n{\n    /// <summary>\n    /// The subscription state is unknown.\n    /// </summary>\n    unknown,\n\n    /// <summary>\n    /// Waiting for the server to respond to the subscription request.\n    /// </summary>\n    pending_subscribe,\n\n    /// <summary>\n    /// Subscription confirmed.\n    /// </summary>\n    subscribed,\n\n    /// <summary>\n    /// Waiting for the server to respond to the unsubscribe request.\n    /// </summary>\n    pending_unsubscribe,\n\n    /// <summary>\n    /// Unsubscribe confirmed.\n    /// </summary>\n    closed\n};\n\n/// <summary>\n/// Enumeration for the possible connection states of the connection\n/// to the real-time activity service.\n/// </summary>\nenum real_time_activity_connection_state\n{\n    /// <summary>\n    /// Currently connected to the real-time activity service.\n    /// </summary>\n    connected,\n    \n    /// <summary>\n    /// Currently connecting to the real-time activity service.\n    /// </summary>\n    connecting,\n\n    /// <summary>\n    /// Currently disconnected from the real-time activity service.\n    /// </summary>\n    disconnected\n};\n\n/// <summary>\n/// The base class for real time activity subscriptions.\n/// </summary>\nclass real_time_activity_subscription\n{\npublic:\n    /// <summary>\n    /// The state of the subscription request.\n    /// DEPRECATED. The state of RTA subscriptions is no longer exposed publicly. real_time_activity_subscription_state::unknown\n    /// will always be returned.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline real_time_activity_subscription_state state() const;\n\n    /// <summary>\n    /// The resource uri for the request.\n    /// DEPRECATED. The state of RTA subscriptions is no longer exposed publicly.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline const string_t& resource_uri() const;\n\n    /// <summary>\n    /// The unique subscription id for the request.\n    /// DEPRECATED. The state of RTA subscriptions is no longer exposed publicly. This API will return a unique\n    /// client side ID, but it is in no way related to the ID assigned by the RTA service.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline uint32_t subscription_id() const;\n    \n    inline real_time_activity_subscription(XblRealTimeActivitySubscriptionHandle handle);\n\nprotected:\n    string_t m_resourceUri;\n    XblRealTimeActivitySubscriptionHandle m_handle;\n};\n\nclass real_time_activity_subscription_error_event_args\n{\npublic:\n    /// <summary>\n    /// The subscription this refers to\n    /// </summary>\n    inline const real_time_activity_subscription& subscription();\n\n    /// <summary>\n    /// The error returned by the operation.\n    /// </summary>\n    inline std::error_code err() const;\n\n    /// <summary>\n    /// The error message\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline std::string err_message() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline real_time_activity_subscription_error_event_args(\n        XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n        HRESULT subscriptionError\n    );\n\nprivate:\n    real_time_activity_subscription m_subscription;\n    std::error_code m_err;\n};\n\n/// <summary>\n/// Represents a client side service that handles connections and communications with\n/// the Xbox Live real-time activity service.\n/// </summary>\nclass real_time_activity_service : public std::enable_shared_from_this<real_time_activity_service>\n{\npublic:\n    /// <summary>\n    /// Starts a background task that creates and initializes a websocket connection to the Xbox Live real-time activity service.\n    /// Its recommended that titles do not activate more than MAXIMUM_WEBSOCKETS_ACTIVATIONS_ALLOWED_PER_USER (5) per user per title instance.\n    /// Upon reaching the limit, titles will hit an assert during development that can be temporarily disabled via\n    /// xbox_live_context_settings::disable_asserts_for_maximum_number_of_websockets_activated().\n    /// DEPRECATED. Calling this API is no longer required. The WebSocket connection will be made automatically by \n    /// XSAPI as necessary. This API will be removed in a future release.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline void activate();\n\n    /// <summary>\n    /// Cancels all existing subscriptions to the Xbox Live real-time activity service,\n    /// unhooks from the websocket connection, and stops the background task.\n    /// DEPRECATED. Calling this API is no longer required. The WebSocket connection will be cleaned up automatically\n    /// by XSAPI when it is no longer needed. This API will be removed in a future release.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline void deactivate();\n\n    /// <summary>\n    /// Registers a handler function to receive a notification that is sent when the client service\n    /// loses or gains connectivity to the real time activity service.\n    /// Event handlers receive a real_time_activity_connection_state object.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    inline function_context add_connection_state_change_handler(_In_ std::function<void(real_time_activity_connection_state)> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for real time activity connectivity state changes.\n    /// </summary>\n    /// <param name=\"remove\">The function_context object that was returned when the event handler was registered. </param>\n    inline void remove_connection_state_change_handler(_In_ function_context remove);\n\n    /// <summary>\n    /// Registers a handler function to receive a notification that is sent when there is an\n    /// error in the real time activity service.\n    /// Event handlers receive a real_time_activity_subscription_error_event_args&amp; object.\n    /// DEPRECATED. RTA service errors will now be handled by XSAPI internally and callback will no longer be invoked.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    _XSAPICPP_DEPRECATED inline function_context add_subscription_error_handler(_In_ std::function<void(const real_time_activity_subscription_error_event_args&)> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for real time activity error notifications.\n    /// DEPRECATED. RTA service errors will now be handled by XSAPI internally and callback will no longer be invoked.\n    /// </summary>\n    /// <param name=\"remove\">The function_context object that was returned when the event handler was registered. </param>\n    _XSAPICPP_DEPRECATED inline void remove_subscription_error_handler(_In_ function_context remove);\n\n    /// <summary>\n    /// Registers a handler function to receive a notification that is sent when there is a\n    /// resync message from the real time activity service.\n    /// This message indicates that data may have been lost and to resync all data by calling\n    /// corresponding REST API's\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    inline function_context add_resync_handler(_In_ std::function<void()> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for real time activity resync notifications.\n    /// </summary>\n    /// <param name=\"remove\">The function_context object that was returned when the event handler was registered. </param>\n    inline void remove_resync_handler(_In_ function_context remove);\n\n    inline real_time_activity_service(const real_time_activity_service& other);\n    inline real_time_activity_service& operator=(real_time_activity_service other);\n    inline ~real_time_activity_service();\n\nprivate:\n    inline real_time_activity_service(_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_xblContext;\n    struct HandlerContext;\n\n    friend xbox_live_context;\n};\n\n}}}\n\n#include \"impl/real_time_activity.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/service_call_logging_config.h",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#if HC_PLATFORM_IS_MICROSOFT\n\nclass service_call_logging_config\n{\npublic:\n\n    /// <summary>\n    /// Deprecated. Service call logging feature is no longer supported.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline static std::shared_ptr<service_call_logging_config> get_singleton_instance();\n\n    /// <summary>\n    /// Deprecated. Service call logging feature is no longer supported.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline void enable();\n\n    /// <summary>\n    /// Deprecated. Service call logging feature is no longer supported.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline void disable();\n\n#if HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP || defined(XSAPI_UNIT_TESTS)\n    /// <summary>\n    /// Deprecated\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline void _Register_for_protocol_activation();\n#endif\n\nprivate:\n    service_call_logging_config() = default;\n    service_call_logging_config(const service_call_logging_config&) = delete;\n    void operator=(const service_call_logging_config&) = delete;\n};\n#endif // HC_PLATFORM_IS_MICROSOFT\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/service_call_logging_config.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/services.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning(disable: 4265)\n#pragma warning(disable: 4266)\n#pragma warning(disable: 4062)\n#endif\n\n#ifndef _LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR\n#define _LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR\n#endif\n\n// cpprest assumed to be part of XSAPI static lib\n#ifndef _ASYNCRT_IMPORT // define this if cpprest is actually a dll\n#ifndef _ASYNCRT_EXPORT\n#ifndef _NO_ASYNCRTIMP\n#define _NO_ASYNCRTIMP // by default disable cpprest dll fn decorations\n#endif\n#endif\n#endif\n\n#include \"xsapi-c/services_c.h\"\n\n#include \"xsapi-cpp/types.h\"\n#include \"xsapi-cpp/errors.h\"\n#include \"xsapi-cpp/mem.h\"\n#include \"cpprest/http_msg.h\"\n#include \"xsapi-cpp/system.h\"\n#include \"xsapi-cpp/service_call_logging_config.h\"\n\n#if !XSAPI_NO_PPL\n#include \"xsapi-cpp/leaderboard.h\"\n#include \"xsapi-cpp/title_storage.h\"\n#include \"xsapi-cpp/privacy.h\"\n#include \"xsapi-cpp/profile.h\"\n#endif // !XSAPI_NO_PPL\n\n#include \"xsapi-cpp/social_manager.h\"\n#include \"xsapi-cpp/http_call.h\"\n#include \"xsapi-cpp/xbox_live_context_settings.h\"\n\n#if !defined(XBOX_LIVE_CREATORS_SDK)\n#include \"xsapi-cpp/social.h\"\n#include \"xsapi-cpp/achievements.h\"\n#include \"xsapi-cpp/real_time_activity.h\"\n#include \"xsapi-cpp/presence.h\"\n    #if !XSAPI_NO_PPL\n        #include \"xsapi-cpp/events.h\"\n        #include \"xsapi-cpp/user_statistics.h\"\n        #include \"xsapi-cpp/multiplayer.h\"\n        #include \"xsapi-cpp/matchmaking.h\"\n        #include \"xsapi-cpp/multiplayer_manager.h\"\n        #include \"xsapi-cpp/notification_service.h\"\n        #include \"xsapi-cpp/string_verify.h\"\n    #endif // !XSAPI_NO_PPL\n#endif // !defined(XBOX_LIVE_CREATORS_SDK)\n\n#include \"xsapi-cpp/title_callable_ui.h\"\n#include \"xsapi-cpp/xbox_live_context.h\"\n\n#ifdef U \n    #undef U // clean up cpprest's global define in case it's used by app\n#endif\n"
  },
  {
    "path": "Include/xsapi-cpp/social.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/social_c.h\"\n#include \"xsapi-cpp/real_time_activity.h\"\n#include \"xsapi-cpp/multiplayer.h\"\n#include \"xsapi-cpp/system.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n\n    /// <summary>\n    /// Contains classes and enumerations that let you retrieve\n    /// information about player reputation and relationship with\n    /// other players from Xbox Live.\n    /// </summary>\n    namespace social {\n\nenum class xbox_social_relationship_filter\n{\n    /// <summary>All the people on the user's people list.</summary>\n    all = static_cast<uint32_t>(XblSocialRelationshipFilter::All),\n\n    /// <summary>Filters to only the people on the user's people list that have the attribute \"Favorite\" associated with them.</summary>\n    favorite = static_cast<uint32_t>(XblSocialRelationshipFilter::Favorite),\n\n    /// <summary>Filters to only the people on the user's people list that are also legacy Xbox Live friends.</summary>\n    legacy_xbox_live_friends = static_cast<uint32_t>(XblSocialRelationshipFilter::LegacyXboxLiveFriends)\n};\n\n/// <summary>\n/// Defines values used to identify the type of reputation feedback.\n/// </summary>\nenum class reputation_feedback_type\n{\n    /// <summary>\n    /// Titles that are able to automatically determine that a user kills a teammate\n    /// may send this feedback without user intervention.\n    /// </summary>\n    fair_play_kills_teammates = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayKillsTeammates),\n\n    /// <summary>\n    /// Titles that are able to automatically determine that a user is cheating\n    /// may send this feedback without user intervention.\n    /// </summary>\n    fair_play_cheater = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayCheater),\n\n    /// <summary>\n    /// Titles that are able to automatically determine that a user has tampered with on-disk content\n    /// may send this feedback without user intervention.\n    /// </summary>\n    fair_play_tampering = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayTampering),\n\n    /// <summary>\n    /// Titles that are able to automatically determine that a user quit a game early\n    /// may send this feedback without user intervention.\n    /// </summary>\n    fair_play_quitter = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayQuitter),\n\n    /// <summary>\n    /// When a user is voted out of a game (kicked), titles\n    /// may send this feedback without user intervention.\n    /// </summary>\n    fair_play_kicked = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayKicked),\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate video communications\n    /// may send this feedback.\n    /// </summary>\n    communications_inappropiate_video = static_cast<uint32_t>(XblReputationFeedbackType::CommunicationsInappropriateVideo),\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate voice communications\n    /// may send this feedback.\n    /// </summary>\n    communications_abusive_voice = static_cast<uint32_t>(XblReputationFeedbackType::CommunicationsAbusiveVoice),\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate user generated content\n    /// may send this feedback.\n    /// </summary>\n    inappropiate_user_generated_content = static_cast<uint32_t>(XblReputationFeedbackType::InappropriateUserGeneratedContent),\n\n    /// <summary>\n    /// Titles that allow users to vote on a most valuable player at the end of a multiplayer session\n    /// may send this feedback.\n    /// </summary>\n    positive_skilled_player = static_cast<uint32_t>(XblReputationFeedbackType::PositiveSkilledPlayer),\n\n    /// <summary>\n    /// Titles that allow users to submit positive feedback on helpful fellow players\n    /// may send this feedback.\n    /// </summary>\n    positive_helpful_player = static_cast<uint32_t>(XblReputationFeedbackType::PositiveHelpfulPlayer),\n\n    /// <summary>\n    /// Titles that allow users to submit positive feedback on shared user generated content\n    /// may send this feedback.\n    /// </summary>\n    positive_high_quality_user_generated_content = static_cast<uint32_t>(XblReputationFeedbackType::PositiveHighQualityUserGeneratedContent),\n\n    /// <summary>\n    /// Titles that allow users to report phishing message may send this feedback.\n    /// </summary>\n    comms_phishing = static_cast<uint32_t>(XblReputationFeedbackType::CommsPhishing),\n\n    /// <summary>\n    /// Titles that allow users to report communication based on a picture may send this feedback.\n    /// </summary>\n    comms_picture_message = static_cast<uint32_t>(XblReputationFeedbackType::CommsPictureMessage),\n\n    /// <summary>\n    /// Titles that allow users to report spam messages may send this feedback.\n    /// </summary>\n    comms_spam = static_cast<uint32_t>(XblReputationFeedbackType::CommsSpam),\n\n    /// <summary>\n    /// Titles that allow users to report text messages may send this feedback.\n    /// </summary>\n    comms_text_message = static_cast<uint32_t>(XblReputationFeedbackType::CommsTextMessage),\n\n    /// <summary>\n    /// Titles that allow users to report voice messages may send this feedback.\n    /// </summary>\n    comms_voice_message = static_cast<uint32_t>(XblReputationFeedbackType::CommsVoiceMessage),\n\n    /// <summary>\n    /// Titles that allow users to report voice messages may send this feedback.\n    /// </summary>\n    fair_play_console_ban_request = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayConsoleBanRequest),\n\n    /// <summary>\n    /// Titles that allow users to report if determine if a user stands idle on purpose in a game, usually round after round, may send this feedback.\n    /// </summary>\n    fair_play_idler = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayIdler),\n\n    /// <summary>\n    /// Titles that report a recommendation to ban a user from Xbox Live may send this feedback.\n    /// </summary>\n    fair_play_user_ban_request = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayUserBanRequest),\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate gamer picture may send this feedback.\n    /// </summary>\n    user_content_gamerpic = static_cast<uint32_t>(XblReputationFeedbackType::UserContentGamerpic),\n\n    /// <summary>\n    /// Titles that allow users to report inappropriate biography and other personal information may send this feedback.\n    /// </summary>\n    user_content_personalinfo = static_cast<uint32_t>(XblReputationFeedbackType::UserContentPersonalInfo),\n\n    /// <summary>\n    /// Titles that allow users to report unsporting behavior may send this feedback.\n    /// </summary>\n    fair_play_unsporting = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayUnsporting),\n\n    /// <summary>\n    /// Titles that allow users to report leaderboard cheating may send this feedback.\n    /// </summary>\n    fair_play_leaderboard_cheater = static_cast<uint32_t>(XblReputationFeedbackType::FairPlayLeaderboardCheater)\n};\n\nenum class social_notification_type\n{\n    /// <summary>\n    /// unknown\n    /// </summary>\n    unknown = static_cast<uint32_t>(XblSocialNotificationType::Unknown),\n\n    /// <summary>\n    /// User(s) were added.\n    /// </summary>\n    added = static_cast<uint32_t>(XblSocialNotificationType::Added),\n\n    /// <summary>\n    /// User(s) data changed.\n    /// </summary>\n    changed = static_cast<uint32_t>(XblSocialNotificationType::Changed),\n\n    /// <summary>\n    /// User(s) were removed.\n    /// </summary>\n    removed = static_cast<uint32_t>(XblSocialNotificationType::Removed)\n};\n\nclass social_group_constants\n{\npublic:\n    /// <summary>\n    /// Returns Favorites constant string\n    /// </summary>\n    static const string_t favorite() { return _T(\"Favorites\"); }\n\n    /// <summary>\n    /// Returns People constant string\n    /// </summary>\n    static const string_t people() { return _T(\"People\"); }\n};\n\n/// <summary>\n/// Represents the relationship between the user and another Xbox user.\n/// </summary>\nclass xbox_social_relationship\n{\npublic:\n    /// <summary>\n    /// The person's Xbox user identifier.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// Indicates whether the person is one that the user cares about more. \n    /// Users can have a very large number of people in their people list, \n    /// favorite people should be prioritized first in experiences and shown before others that are not favorites. \n    /// </summary>\n    inline bool is_favorite() const;\n\n    /// <summary>\n    /// Indicates whether the person is a friend (mutual follower) of the user.\n    /// </summary>\n    inline bool is_friend() const;\n\n    /// <summary>\n    /// Does not indicate a following/follower relation between caller user other users.\n    /// Currently will return true if a person is a mutual follower of a user that\n    /// requested information (this is dependent on the value of 'isFriend' field).\n    /// </summary>\n    inline bool is_following_caller() const;\n\n    /// <summary>\n    /// A collection of strings indicating which social networks this person has a relationship with. \n    /// </summary>\n    inline const std::vector<string_t>& social_networks() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline xbox_social_relationship(\n        const XblSocialRelationship& socialRelationship\n    );\n\nprivate:\n    string_t m_xuid;\n    bool m_isFavorite{ false };\n    bool m_isFollowingCaller{ false };\n    bool m_isFriend{ false };\n    std::vector<string_t> m_socialNetworks;\n};\n\n#if !XSAPI_NO_PPL\n/// <summary>\n/// Services that manage user relationship.\n/// </summary>\nclass xbox_social_relationship_result\n{\n    // Example:\n    // {\n    //     \"people\": [\n    //         {\n    //             \"xuid\": \"2603643534573573\",\n    //             \"isFavorite\": true,\n    //             \"isFollowingCaller\": true,\n    //             \"socialNetworks\": [\"MyNetwork1\", \"MyNetwork2\"]\n    //         },\n    //         {\n    //             \"xuid\": \"2603643534573572\",\n    //             \"isFavorite\": true,\n    //             \"isFollowingCaller\": false,\n    //             \"socialNetworks\": [\"MyNetwork1\"]\n    //         },\n    //         {\n    //             \"xuid\": \"2603643534573577\",\n    //             \"isFavorite\": false\n    //             \"isFollowingCaller\": false\n    //         },\n    //     ],\n    //     \"totalCount\": 3\n    // }\n\npublic:\n    /// <summary>\n    /// Collection of XboxSocialRelationship objects returned by a request.\n    /// </summary>\n    inline std::vector<xbox_social_relationship> items() const;\n\n    /// <summary>\n    /// The total number of XboxSocialRelationship objects that can be requested.\n    /// </summary>\n    inline uint32_t total_count() const;\n\n    /// <summary>\n    /// Returns a boolean value that indicates if there are more pages of social relationships to retrieve.\n    /// </summary>\n    /// <returns>True if there are more pages, otherwise false.</returns>\n    inline bool has_next() const;\n\n    /// <summary>\n    /// Returns an XboxSocialRelationshipResult object containing the next page.\n    /// </summary>\n    /// <param name=\"maxItems\">The maximum number of items the response can contain.  Pass 0 to attempt\n    /// retrieving all items.</param>\n    /// <returns>Returns an XboxSocialRelationshipResult object.</returns>\n    /// <remarks>Calls V1 GET /users/{ownerId}/people</remarks>\n    inline pplx::task<xbox_live_result<xbox_social_relationship_result>> get_next(\n        _In_ uint32_t maxItems\n    );\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline xbox_social_relationship_result() = default;\n    inline xbox_social_relationship_result(XblSocialRelationshipResultHandle resultHandle, XblContextHandle xblContextHandle);\n    inline xbox_social_relationship_result(const xbox_social_relationship_result& other);\n    inline xbox_social_relationship_result& operator=(xbox_social_relationship_result other);\n    inline ~xbox_social_relationship_result();\n\nprivate:\n    XblSocialRelationshipResultHandle m_resultHandle{ nullptr };\n    XblContextHandle m_xblContextHandle{ nullptr };\n};\n\nclass social_relationship_change_event_args\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID for the user who's social graph changes are being listed for.\n    /// </summary>\n    inline const string_t& caller_xbox_user_id() const;\n\n    /// <summary>\n    /// The type of notification change.\n    /// </summary>\n    inline social_notification_type social_notification() const;\n\n    /// <summary>\n    /// The Xbox user ids who the event is for\n    /// </summary>\n    inline const std::vector<string_t>& xbox_user_ids() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline social_relationship_change_event_args(\n        const XblSocialRelationshipChangeEventArgs* args\n    );\n\nprivate:\n    string_t m_callerXuid;\n    social_notification_type m_notificationType{ social_notification_type::unknown };\n    std::vector<string_t> m_xuids;\n};\n\nclass social_relationship_change_subscription : public xbox::services::real_time_activity::real_time_activity_subscription\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline social_relationship_change_subscription(_In_ XblRealTimeActivitySubscriptionHandle handle, _In_ uint64_t xuid);\n\nprivate:\n    string_t m_xuid;\n    friend class social_service;\n};\n\n/// <summary>\n/// Services that manage user relationship.\n/// </summary>\nclass social_service\n{\npublic:\n    /// <summary>\n    /// Returns a XboxSocialRelationshipResult containing a the list of people that the user is connected to.\n    /// Defaults to filtering to PersonView.All.\n    /// Defaults to startIndex and maxItems of 0 to return entire list if possible.\n    /// </summary>\n    /// <returns>An XboxSocialRelationshipResult object.</returns>\n    /// <remarks>Calls V1 GET /users/{ownerId}/people?view={view}&amp;startIndex={startIndex}&amp;maxItems={maxItems}</remarks>\n    inline pplx::task<xbox_live_result<xbox_social_relationship_result>> get_social_relationships();\n\n    /// <summary>\n    /// Returns a xbox_social_relationship_result containing a the list of people that the user is connected to.\n    /// </summary>\n    /// <param name=\"socialRelationshipFilter\">Controls how the list is filtered.</param>\n    /// <returns>An xbox_social_relationship_result object.</returns>\n    /// <remarks>Calls V1 GET /users/{ownerId}/people?view={view}&amp;startIndex={startIndex}&amp;maxItems={maxItems}</remarks>\n    inline pplx::task<xbox_live_result<xbox_social_relationship_result>> get_social_relationships(\n        _In_ xbox_social_relationship_filter socialRelationshipFilter\n    );\n\n    /// <summary>\n    /// Returns a xbox_social_relationship_result containing a the list of people that the user is connected to.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User Id to get the social relationships for.</param>\n    /// <returns>An xbox_social_relationship_result object.</returns>\n    /// <remarks>Calls V1 GET /users/{ownerId}/people?view={view}&amp;startIndex={startIndex}&amp;maxItems={maxItems}</remarks>\n    inline pplx::task<xbox_live_result<xbox_social_relationship_result>> get_social_relationships(\n        _In_ const string_t& xboxUserId\n    );\n\n    /// <summary>\n    /// Returns a xbox_social_relationship_result containing a the list of people that the user is connected to.\n    /// </summary>\n    /// <param name=\"socialRelationshipFilter\">Controls how the list is filtered.</param>\n    /// <param name=\"startIndex\">Controls the starting index to return.</param>\n    /// <param name=\"maxItems\">Controls the number of xbox_social_relationship_result objects to get.  0 will return as many as possible</param>\n    /// <returns>An xbox_social_relationship_result object.</returns>\n    /// <remarks>Calls V1 GET /users/{ownerId}/people?view={view}&amp;startIndex={startIndex}&amp;maxItems={maxItems}</remarks>\n    inline pplx::task<xbox_live_result<xbox_social_relationship_result>> get_social_relationships(\n        _In_ xbox_social_relationship_filter socialRelationshipFilter,\n        _In_ uint32_t startIndex,\n        _In_ uint32_t maxItems\n    );\n\n    /// <summary>\n    /// Subscribes to the social service for people changed events\n    /// DEPRECATED. Calling this API is no longer required and it will be removed in a future release. RTA subscription will be managed \n    /// automatically by XSAPI as handlers are added and removed.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player requesting the subscription.</param>\n    /// <returns>\n    /// You can register an event handler for social relationship changes by calling set_social_changed_handler().\n    /// </returns>\n    _XSAPICPP_DEPRECATED inline xbox_live_result<std::shared_ptr<social_relationship_change_subscription>> subscribe_to_social_relationship_change(\n        _In_ const string_t& xboxUserId\n    );\n\n    /// <summary>\n    /// Unsubscribes a previously created social relationship change subscription.\n    /// DEPRECATED. Calling this API is no longer required and it will be removed in a future release. RTA subscription will be managed \n    /// automatically by XSAPI as handlers are added and removed.\n    /// </summary>\n    /// <param name=\"subscription\">The subscription object to unsubscribe</param>\n    _XSAPICPP_DEPRECATED inline xbox_live_result<void> unsubscribe_from_social_relationship_change(\n        _In_ std::shared_ptr<social_relationship_change_subscription> subscription\n    );\n\n    /// <summary>\n    /// Registers an event handler for social relationship change notifications.\n    /// Event handlers receive social_relationship_change_event_args.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    inline function_context add_social_relationship_changed_handler(\n        _In_ std::function<void(social_relationship_change_event_args)> handler\n    );\n\n    /// <summary>\n    /// Removes a social relationship change handler\n    /// </summary>\n    /// <param name=\"context\">The handler to remove.</param>\n    inline void remove_social_relationship_changed_handler(\n        _In_ function_context context\n    );\n\n    inline social_service(const social_service& other);\n    inline social_service& operator=(social_service other);\n    inline ~social_service();\n\nprivate:\n    inline social_service(XblContextHandle xblContextHandle);\n\n    // ppl wrapper around XblSocialGetSocialRelationshipsAsync\n    inline pplx::task<xbox_live_result<xbox_social_relationship_result>> get_social_relationships(\n        _In_ uint64_t xuid,\n        _In_ XblSocialRelationshipFilter filter,\n        _In_ size_t startIndex,\n        _In_ size_t maxItems\n    );\n\n    XblContextHandle m_xblContextHandle;\n    uint64_t m_xuid{ 0 };\n\n    struct HandlerContext;\n\n    friend xbox_live_context;\n};\n\n///<summary>\n///Represents the parameters for submitting reputation feedback on a user\n///</summary>\nclass reputation_feedback_item\n{\npublic:\n    reputation_feedback_item() = default;\n\n    /// <summary>\n    /// Construct a reputation_feedback_item object\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user that reputation feedback is being submitted on.</param>\n    /// <param name=\"reputationFeedbackType\">The reputation feedback type being submitted.</param>\n    /// <param name=\"sessionRef\">The session reference of the multiplayer session directory session the user is sending feedback from. (Optional)</param>\n    /// <param name=\"reasonMessage\">User supplied text added to explain the reason for the feedback. (Optional)</param>\n    /// <param name=\"evidenceResourceId\">The Id of a resource that can be used as evidence for the feedback. Example: the Id of a video file. (Optional)</param>\n    inline reputation_feedback_item(\n        _In_ const string_t& xboxUserId,\n        _In_ reputation_feedback_type reputationFeedbackType,\n        _In_ xbox::services::multiplayer::multiplayer_session_reference sessionRef = xbox::services::multiplayer::multiplayer_session_reference(),\n        _In_ const string_t& reasonMessage = string_t(),\n        _In_ const string_t& evidenceResourceId = string_t()\n    );\n\n    /// <summary>\n    /// The Xbox User ID of the user that reputation feedback is being submitted on.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// The reputation feedback type being submitted.\n    /// </summary>\n    inline reputation_feedback_type feedback_type() const;\n\n    /// <summary>\n    /// The reference to the multiplayer session directory session the user is sending feedback from.\n    /// </summary>\n    inline const xbox::services::multiplayer::multiplayer_session_reference& session_reference() const;\n\n    /// <summary>\n    /// User supplied text added to explain the reason for the feedback.\n    /// </summary>\n    inline string_t reason_message() const;\n\n     /// <summary>\n     /// The Id of a resource that can be used as evidence for the feedback. Example: the Id of a video file.\n     /// </summary>\n    inline string_t evidence_resource_id() const;\n\nprivate:\n    uint64_t m_xboxUserId;\n    reputation_feedback_type m_reputationFeedbackType;\n    xbox::services::multiplayer::multiplayer_session_reference m_sessionRef;\n    std::string m_reasonMessage;\n    std::string m_evidenceResourceId;\n\n    friend class reputation_service;\n};\n\n\n/// <summary>\n/// Manages the reputation service.\n/// </summary>\nclass reputation_service\n{\npublic:\n    /// <summary>\n    /// Submits reputation feedback on the specified user.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the user that reputation feedback is being submitted on.</param>\n    /// <param name=\"reputationFeedbackType\">The reputation feedback type being submitted.</param>\n    /// <param name=\"sessionName\">The name of the multiplayer session directory session the user is sending feedback from. (Optional)</param>\n    /// <param name=\"reasonMessage\">User supplied text added to explain the reason for the feedback. (Optional)</param>\n    /// <param name=\"evidenceResourceId\">The Id of a resource that can be used as evidence for the feedback. Example: the Id of a video file. (Optional)</param>\n    /// <returns>The async object for notifying when the operation has been completed.</returns>\n    /// <remarks>Calls V100 POST /users/xuid({xuid})/feedback</remarks>\n    inline pplx::task<xbox_live_result<void>> submit_reputation_feedback(\n        _In_ const string_t& xboxUserId,\n        _In_ reputation_feedback_type reputationFeedbackType,\n        _In_ const string_t& sessionName = string_t(),\n        _In_ const string_t& reasonMessage = string_t(),\n        _In_ const string_t& evidenceResourceId = string_t()\n    );\n\n    /// <summary>\n    /// Submits batch reputation feedback on the specified users.\n    /// </summary>\n    /// <param name=\"feedbackItems\">A vector of reputation_feedback_item objects to submit reputation feedback on.</param>\n    /// <returns>The async object for notifying when the operation has been completed.</returns>\n    /// <remarks>Calls V101 POST /users/batchfeedback</remarks>\n    inline pplx::task<xbox_live_result<void>> submit_batch_reputation_feedback(\n        _In_ const std::vector<reputation_feedback_item>& feedbackItems\n    );\n\n    inline reputation_service(const reputation_service& other);\n    inline reputation_service& operator=(reputation_service other);\n    inline ~reputation_service();\n\nprivate:\n    inline reputation_service(XblContextHandle xblContextHandle);\n\n    XblContextHandle m_xblContextHandle;\n\n    friend xbox_live_context;\n};\n#endif // !XSAPI_NO_PPL\n\n}}}\n\n#if !XSAPI_NO_PPL\n#include \"impl/social.hpp\"\n#endif"
  },
  {
    "path": "Include/xsapi-cpp/social_manager.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xsapi-cpp/presence.h\"\n#include \"xsapi-c/social_manager_c.h\"\n\n#include \"xsapi-cpp/mem.h\"\n#include \"xsapi-cpp/types.h\"\n\nnamespace xbox {\n    namespace services {\n\n        namespace social {\n            /// <summary>\n            /// Contains classes and enumerations for more easily managing social\n            /// scenarios.\n            /// </summary>\n            namespace manager {\n\n/// <summary>\n/// Detail level controls how much information is exposed in each xbox_live_social_graph_user\n/// Detail level can only be set on construction of social_manager\n/// </summary>\nenum class social_manager_extra_detail_level\n{\n    /// <summary>Only get default PeopleHub information (presence, profile)</summary>\n    no_extra_detail = static_cast<uint32_t>(XblSocialManagerExtraDetailLevel::NoExtraDetail),\n\n    /// <summary>Add extra detail for the title history for the users</summary>\n    title_history_level = static_cast<uint32_t>(XblSocialManagerExtraDetailLevel::TitleHistoryLevel),\n\n    /// <summary>Add extra detail for the preferred color for the users</summary>\n    preferred_color_level = static_cast<uint32_t>(XblSocialManagerExtraDetailLevel::PreferredColorLevel)\n};\n\nDEFINE_ENUM_FLAG_OPERATORS(social_manager_extra_detail_level);\n\n/// <summary>\n/// The filter level of information\n/// Title will only show users associated with a particular title\n/// </summary>\nenum class presence_filter\n{\n    /// <summary>Unknown</summary>\n    unknown = static_cast<uint32_t>(XblPresenceFilter::Unknown),\n\n    /// <summary>Is currently playing current title and is online</summary>\n    title_online = static_cast<uint32_t>(XblPresenceFilter::TitleOnline),\n\n    /// <summary>Has played this title and is offline</summary>\n    title_offline = static_cast<uint32_t>(XblPresenceFilter::TitleOffline),\n\n    /// <summary>Has played this title, is online but not currently playing this title</summary>\n    title_online_outside_title = static_cast<uint32_t>(XblPresenceFilter::TitleOnlineOutsideTitle),\n\n    /// <summary>Everyone currently online</summary>\n    all_online = static_cast<uint32_t>(XblPresenceFilter::AllOnline),\n\n    /// <summary>Everyone currently offline</summary>\n    all_offline = static_cast<uint32_t>(XblPresenceFilter::AllOffline),\n\n    /// <summary>Everyone who has played or is playing the title</summary>\n    all_title = static_cast<uint32_t>(XblPresenceFilter::AllTitle),\n\n    /// <summary>Everyone</summary>\n    all = static_cast<uint32_t>(XblPresenceFilter::All)\n};\n\n/// <summary>\n/// The types of possible events\n/// </summary>\nenum class social_event_type\n{\n    /// <summary>Users added to social graph</summary>\n    users_added_to_social_graph = static_cast<uint32_t>(XblSocialManagerEventType::UsersAddedToSocialGraph),\n\n    /// <summary>Users removed from social graph</summary>\n    users_removed_from_social_graph = static_cast<uint32_t>(XblSocialManagerEventType::UsersRemovedFromSocialGraph),\n\n    /// <summary>Users presence record has changed</summary>\n    presence_changed = static_cast<uint32_t>(XblSocialManagerEventType::PresenceChanged),\n\n    /// <summary>Users profile information has changed</summary>\n    profiles_changed = static_cast<uint32_t>(XblSocialManagerEventType::ProfilesChanged),\n\n    /// <summary>Relationship to users has changed</summary>\n    social_relationships_changed = static_cast<uint32_t>(XblSocialManagerEventType::SocialRelationshipsChanged),\n\n    /// <summary>Social graph load complete from adding a local user</summary>\n    local_user_added = static_cast<uint32_t>(XblSocialManagerEventType::LocalUserAdded),\n\n    /// <summary>\n    /// Legacy. Formerly raised when a user's graph was destroyed, but is no longer raised.\n    /// C++ interface will continue to raise this event (always on the next do_work call after removed_local_user)\n    /// to maintain backward compatability.\n    /// </summary>\n    local_user_removed = static_cast<uint32_t>(XblSocialManagerEventType::UnknownEvent) + 1,\n\n    /// <summary>Xbox Social User Group load complete (will only trigger for views that take a list of users)</summary>\n    social_user_group_loaded = static_cast<uint32_t>(XblSocialManagerEventType::SocialUserGroupLoaded),\n\n    /// <summary>Social user group updated</summary>\n    social_user_group_updated = static_cast<uint32_t>(XblSocialManagerEventType::SocialUserGroupUpdated),\n\n    /// <summary>unknown.</summary>\n    unknown = static_cast<uint32_t>(XblSocialManagerEventType::UnknownEvent)\n};\n\n/// <summary>\n/// Possible relationship types to filter by\n/// </summary>\nenum class relationship_filter\n{\n    /// <summary>Friends of the user (user is following)</summary>\n    friends = static_cast<uint32_t>(XblRelationshipFilter::Friends),\n\n    /// <summary>Favorites of the user</summary>\n    favorite = static_cast<uint32_t>(XblRelationshipFilter::Favorite)\n};\n\n/// <summary>\n/// Identifies type of social user group created\n/// </summary>\nenum class social_user_group_type\n{\n    /// <summary>Social user group based off of filters</summary>\n    filter_type = static_cast<uint32_t>(XblSocialUserGroupType::FilterType),\n\n    /// <summary>Social user group based off of list of users</summary>\n    user_list_type = static_cast<uint32_t>(XblSocialUserGroupType::UserListType)\n};\n\n/// <summary>\n/// Data about whether the user has played the title\n/// </summary>\nclass title_history\n{\npublic:\n    /// <summary>\n    /// Whether the user has played this title\n    /// </summary>\n    inline bool has_user_played() const;\n\n    /// <summary>\n    /// The last time the user had played\n    /// </summary>\n    inline utility::datetime last_time_user_played() const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline title_history(const XblTitleHistory& titleHistory);\n    inline title_history(const title_history& other);\n    inline title_history& operator=(title_history other);\n    inline ~title_history() = default;\n\nprivate:\n    std::shared_ptr<const XblTitleHistory> m_owningPtr{ nullptr };\n    const XblTitleHistory* m_titleHistory;\n};\n\n/// <summary>\n/// Preferred color for the user. Set via the shell. \n/// </summary>\nclass preferred_color\n{\npublic:\n    /// <summary>\n    /// Users primary color\n    /// </summary>\n    inline const char_t* primary_color() const;\n\n    /// <summary>\n    /// Users secondary color\n    /// </summary>\n    inline const char_t* secondary_color() const;\n\n    /// <summary>\n    /// Users tertiary color\n    /// </summary>\n    inline const char_t* tertiary_color() const;\n\n    /// <summary>\n    /// Does a comparison on if preferred colors are equal\n    /// </summary>\n    inline bool operator!=(const preferred_color& rhs) const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline preferred_color(const XblPreferredColor& preferredColor);\n\nprivate:\n    string_t m_primaryColor;\n    string_t m_secondaryColor;\n    string_t m_tertiaryColor;\n};\n\n/// <summary>\n/// Social manager version of the presence title record\n/// Gives information about different titles presence information\n/// </summary>\nclass social_manager_presence_title_record\n{\npublic:\n    /// <summary>\n    /// The title ID.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    /// <summary>\n    /// The active state for the title.\n    /// </summary>\n    inline bool is_title_active() const;\n\n    /// <summary>\n    /// The formatted and localized presence string.\n    /// </summary>\n    inline const char_t* presence_text() const;\n\n    /// <summary>\n    /// The active state for the title.\n    /// </summary>\n    inline bool is_broadcasting() const;\n    \n    /// <summary>\n    /// Device type\n    /// </summary>\n    inline xbox::services::presence::presence_device_type device_type() const;\n\n    /// <summary>\n    /// Whether or not this is the primary primary presence record\n    /// </summary>\n    inline bool is_primary() const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline social_manager_presence_title_record(const XblSocialManagerPresenceTitleRecord& titleRecord);\n    inline social_manager_presence_title_record(const social_manager_presence_title_record& other);\n    inline social_manager_presence_title_record& operator=(social_manager_presence_title_record other);\n    inline ~social_manager_presence_title_record() = default;\n\nprivate:\n    std::shared_ptr<const XblSocialManagerPresenceTitleRecord> m_owningPtr{ nullptr };\n    const XblSocialManagerPresenceTitleRecord* m_titleRecord;\n    string_t m_presenceText;\n};\n\n/// <summary>\n/// Social manager presence record. Shows information on users current presence status and stores title records\n/// </summary>\nclass social_manager_presence_record\n{\npublic:\n    /// <summary>\n    /// The user's presence state.\n    /// </summary>\n    inline xbox::services::presence::user_presence_state user_state() const;\n\n    /// <summary>\n    /// Collection of presence title record objects returned by a request.\n    /// </summary>\n    inline const std::vector<social_manager_presence_title_record>& presence_title_records() const;\n\n    /// <summary>\n    /// Returns whether the user is playing this title id\n    /// </summary>\n    inline bool is_user_playing_title(_In_ uint32_t titleId) const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline social_manager_presence_record(const XblSocialManagerPresenceRecord& presenceRecord);\n    inline social_manager_presence_record(const social_manager_presence_record& other);\n    inline social_manager_presence_record& operator=(social_manager_presence_record other);\n    inline ~social_manager_presence_record() = default;\n\nprivate:\n    std::shared_ptr<const XblSocialManagerPresenceRecord> m_owningPtr{ nullptr };\n    const XblSocialManagerPresenceRecord* m_presenceRecord;\n    std::vector<social_manager_presence_title_record> m_titleRecords;\n};\n\n/// <summary>\n/// Xbox Social User that contains profile, presence, preferred color, and title history data\n/// </summary>\nclass xbox_social_user\n{\npublic:\n    /// <summary>\n    /// The xbox user id\n    /// </summary>\n    inline const char_t* xbox_user_id() const;\n\n    /// <summary>\n    /// Whether they are a favorite\n    /// </summary>\n    inline bool is_favorite() const;\n\n    /// <summary>\n    /// Whether the calling user is following them\n    /// </summary>\n    inline bool is_following_user() const;\n\n    /// <summary>\n    /// Whether they calling user is followed by this person\n    /// </summary>\n    inline bool is_followed_by_caller() const;\n\n    /// <summary>\n    /// The display name\n    /// </summary>\n    inline const char_t* display_name() const;\n\n    /// <summary>\n    /// The real name\n    /// </summary>\n    inline const char_t* real_name() const;\n\n    /// <summary>\n    /// The display pic uri\n    /// </summary>\n    inline const char_t* display_pic_url_raw() const;\n\n    /// <summary>\n    /// Whether to use the players avatar\n    /// </summary>\n    inline bool use_avatar() const;\n\n    /// <summary>\n    /// Players gamerscore\n    /// </summary>\n    inline const char_t* gamerscore() const;\n\n    /// <summary>\n    /// Players gamertag\n    /// </summary>\n    inline const char_t* gamertag() const;\n\n    /// <summary>\n    /// Modern gamertag for the player. Not guaranteed to be unique.\n    /// </summary>\n    inline const char_t* modern_gamertag() const;\n\n    /// <summary>\n    /// Suffix appended to modern gamertag to ensure uniqueness. May be empty in some cases.\n    /// </summary>\n    inline const char_t* modern_gamertag_suffix() const;\n\n    /// <summary>\n    /// Combined modern gamertag and suffix. Format will be \"MGT#suffix\".\n    /// Guaranteed to be no more than 16 rendered characters.\n    /// </summary>\n    inline const char_t* unique_modern_gamertag() const;\n\n    /// <summary>\n    /// Users presence record\n    /// </summary>\n    inline const xbox::services::social::manager::social_manager_presence_record& presence_record() const;\n\n    /// <summary>\n    /// Title history for the user\n    /// </summary>\n    inline const xbox::services::social::manager::title_history& title_history() const;\n\n    /// <summary>\n    /// Preferred color for the user\n    /// </summary>\n    inline const preferred_color& preferred_color() const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline xbox_social_user(const XblSocialManagerUser& user);\n    inline xbox_social_user(const xbox_social_user& other);\n    inline xbox_social_user& operator=(xbox_social_user other);\n    inline ~xbox_social_user() = default;\n\nprivate:\n    std::shared_ptr<const XblSocialManagerUser> m_owningPtr{ nullptr };\n    const XblSocialManagerUser* m_user;\n\n    string_t m_gamerscore;\n    string_t m_gamertag;\n    string_t m_modernGamertag;\n    string_t m_modernGamertagSuffix;\n    string_t m_uniqueModernGamertag;\n    string_t m_xboxUserId;\n    string_t m_displayName;\n    string_t m_realName;\n    string_t m_displayPicUrlRaw;\n    xbox::services::social::manager::title_history m_titleHistory;\n    xbox::services::social::manager::preferred_color m_preferredColor;\n    xbox::services::social::manager::social_manager_presence_record m_presenceRecord;\n};\n\n/// <summary>\n/// Base class for social event args\n/// </summary>\nclass social_event_args\n{\npublic:\n    social_event_args() {}\n    virtual ~social_event_args() {}\n};\n\n/// <summary>\n/// Contains an xbox user id for purposes of storing in stl data types\n/// </summary>\nclass xbox_user_id_container\n{\npublic:\n    /// <summary>\n    /// A users xbox user id\n    /// </summary>\n    inline const char_t* xbox_user_id() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline xbox_user_id_container(_In_ uint64_t xuid);\n\nprivate:\n    string_t m_xboxUserId;\n};\n\n/// <summary>\n/// An event that something in the social graph has changed\n/// </summary>\nclass social_event\n{\npublic:\n    /// <summary>\n    /// The user whose graph got changed\n    /// </summary>\n    inline xbox_live_user_t user() const;\n\n    /// <summary>\n    /// The type of event this is \n    /// Tells the caller what to cast the event_args to\n    /// </summary>\n    inline social_event_type event_type() const;\n\n    /// <summary>\n    /// List of users this event affects\n    /// </summary>\n    inline std::vector<xbox_user_id_container> users_affected() const;\n\n    /// <summary>\n    /// The social event args\n    /// </summary>\n    inline std::shared_ptr<social_event_args> event_args() const;\n\n    /// <summary>\n    /// Error that occurred\n    /// </summary>\n    inline std::error_code err() const;\n\n    /// <summary>\n    /// Error message\n    /// </summary>\n    inline std::string err_message() const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline social_event(const XblSocialManagerEvent& event);\n    inline social_event(const xbox_live_user_t& removedUser);\n\nprivate:\n    XblSocialManagerEvent m_event{};\n    social_event_type m_eventType{ social_event_type::unknown };\n    std::shared_ptr<social_event_args> m_args;\n};\n\n/// <summary>\n/// A subset snapshot of the users social graph\n/// </summary>\nclass xbox_social_user_group\n{\npublic:\n    /// <summary>\n    /// Gets an up to date list of users from the social graph\n    /// The returned value remains valid until the next call to do_work\n    /// </summary>\n    inline std::vector<xbox_social_user*> users() const;\n\n    /// <summary>\n    /// Returns copied group of users from social user group\n    /// </summary>\n    /// <param name=\"socialUserVector\">Vector of social users to populate</param>\n    /// <returns>An xbox_live_result representing the success of copying the users</returns>\n    inline xbox_live_result<void> get_copy_of_users(\n        _Inout_ std::vector<xbox_social_user>& socialUserVector\n    );\n\n    /// <summary>\n    /// Type of social user group\n    /// </summary>\n    inline social_user_group_type social_user_group_type() const;\n\n    /// <summary>\n    /// Users who are contained in this user group currently\n    /// For list this is static, for filter this is dynamic and will change on do_work\n    /// </summary>\n    inline std::vector<xbox_user_id_container> users_tracked_by_social_user_group() const;\n\n    /// <summary>\n    /// The local user who the user group is related to\n    /// </summary>\n    inline xbox_live_user_t local_user() const;\n\n    /// <summary>\n    /// Returns the presence filter used if group type is filter type\n    /// </summary>\n    inline presence_filter presence_filter_of_group() const;\n\n    /// <summary>\n    /// Returns the relationship filter used if group type is filter type\n    /// </summary>\n    inline relationship_filter relationship_filter_of_group() const;\n\n    /// <summary>\n    /// Returns users from xuids. Pointers become invalidated by next do_work\n    /// </summary>\n    inline std::vector<xbox_social_user*> get_users_from_xbox_user_ids(_In_ const std::vector<xbox_user_id_container>& xboxUserIds);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline xbox_social_user_group(XblSocialManagerUserGroupHandle group);\n\nprivate:\n    inline void PopulateUsers() const;\n\n    XblSocialManagerUserGroupHandle m_group;\n    mutable std::vector<xbox_social_user> m_users;\n\n    friend class social_manager;\n};\n\n/// <summary>\n/// Social user group args for when a social user group loads\n/// </summary>\nclass social_user_group_loaded_event_args : public social_event_args\n{\npublic:\n    /// <summary>\n    /// The loaded social user group\n    /// </summary>\n    inline std::shared_ptr<xbox_social_user_group> social_user_group() const;\n\n    /// <summary>\n    /// internal function\n    /// </summary>\n    inline social_user_group_loaded_event_args(std::shared_ptr<xbox_social_user_group> group);\n\nprivate:\n    std::shared_ptr<xbox_social_user_group> m_group;\n};\n\n/// <summary>\n/// Social Manager that handles core logic\n/// </summary>\nclass social_manager\n{\npublic:\n    /// <summary>\n    /// Gets the social_manager singleton instance\n    /// </summary>\n    inline static std::shared_ptr<social_manager> get_singleton_instance();\n\n    /// <summary>\n    /// Create a social graph for the specified local user\n    /// The result of a local user being added will be triggered through the local_user_added event in do_work\n    /// </summary>\n    /// <param name=\"user\">Xbox Live User</param>\n    /// <param name=\"extraDetailLevel\">The level of verbosity that should be in the xbox_social_user</param>\n    /// <returns>An xbox_live_result to report any potential error</returns>\n    inline xbox_live_result<void> add_local_user(\n        _In_ xbox_live_user_t user,\n        _In_ social_manager_extra_detail_level extraDetailLevel\n    );\n\n    /// <summary>\n    /// Removes a social graph for the specified local user\n    /// The result of a local user being added will be triggered through the local_user_removed event in do_work\n    /// </summary>\n    /// <param name=\"user\">Xbox Live User</param>\n    /// <returns>An xbox_live_result to report any potential error</returns>\n    inline xbox_live_result<void> remove_local_user(\n        _In_ xbox_live_user_t user\n    );\n\n    /// <summary>\n    /// Called whenever the title wants to update the social graph and get list of change events\n    /// Must be called every frame for data to be up to date\n    /// </summary>\n    /// <returns> The list of what has changed in between social graph updates</returns>\n    inline std::vector<social_event> do_work();\n\n    /// <summary>\n    /// Constructs a social Xbox Social User Group, which is a collection of users with social information\n    /// The result of a user group being loaded will be triggered through the social_user_group_loaded event in do_work\n    /// </summary>\n    /// <param name=\"user\">Xbox Live User</param>\n    /// <param name=\"presenceDetailLevel\">The restriction of users based on their presence and title activity</param>\n    /// <param name=\"relationshipFilter\">The restriction of users based on their relationship to the calling user</param>\n    /// <returns>An xbox_live_result of the created Xbox Social User Group</returns>\n    inline xbox_live_result<std::shared_ptr<xbox_social_user_group>> create_social_user_group_from_filters(\n        _In_ xbox_live_user_t user,\n        _In_ presence_filter presenceDetailLevel,\n        _In_ relationship_filter filter\n    );\n\n    /// <summary>\n    /// Constructs a social Xbox Social User Group, which is a collection of users with social information\n    /// The result of a user group being loaded will be triggered through the social_user_group_loaded event in do_work\n    /// </summary>\n    /// <param name=\"user\">Xbox Live User</param>\n    /// <param name=\"xboxUserIdList\">List of users to populate the Xbox Social User Group with. This is currently capped at 100 users total.</param>\n    /// <returns>An xbox_live_result of the created Xbox Social User Group</returns>\n    inline xbox_live_result<std::shared_ptr<xbox_social_user_group>> create_social_user_group_from_list(\n        _In_ xbox_live_user_t user,\n        _In_ std::vector<string_t> xboxUserIdList\n    );\n\n    /// <summary>\n    /// Destroys a created social Xbox Social User Group\n    /// This will stop updating the Xbox Social User Group and remove tracking for any users the Xbox Social User Group holds\n    /// </summary>\n    /// <param name=\"socialUserGroup\">The social Xbox Social User Group to destroy and stop tracking</param>\n    /// <returns>An xbox_live_result to report any potential error</returns>\n    inline xbox_live_result<void> destroy_social_user_group(\n        _In_ std::shared_ptr<xbox_social_user_group> socialUserGroup\n    );\n\n    /// <summary>\n    /// Returns all local users who have been added to the social manager\n    /// </summary>\n    inline std::vector<xbox_live_user_t> local_users() const;\n\n    /// <summary>\n    /// Updates specified social user group to new group of users\n    /// Does a diff to see which users have been added or removed from \n    /// The result of a user group being updated will be triggered through the social_user_group_updated event in do_work\n    /// </summary>\n    /// <param name=\"group\">The xbox social user group to add users to</param>\n    /// <param name=\"users\">List of users to add to the xbox social user group. Total number of users not in social graph is limited at 100.</param>\n    /// <returns>An xbox_live_result representing the success of adding the users to the group</returns>\n    inline xbox_live_result<void> update_social_user_group(\n        _In_ const std::shared_ptr<xbox_social_user_group>& group,\n        _In_ const std::vector<string_t>& users\n    );\n    \n    /// <summary>\n    /// Whether to enable social manager to poll every 30 seconds from the presence service \n    /// </summary>\n    /// <param name=\"user\">Xbox Live User</param>\n    /// <param name=\"shouldEnablePolling\">Whether or not polling should enabled</param>\n    /// <returns>An xbox_live_result representing the success enabling polling</returns>\n    inline xbox_live_result<void> set_rich_presence_polling_status(\n        _In_ xbox_live_user_t user,\n        _In_ bool shouldEnablePolling\n    );\n\nprivate:\n    social_manager() = default;\n    std::vector<xbox_live_user_t> m_removedUsers;\n    std::unordered_map<XblSocialManagerUserGroupHandle, std::shared_ptr<xbox_social_user_group>> m_groups;\n\n    friend class social_event;\n};\n\n}}}}\n\n#include \"impl/social_manager.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/string_verify.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n#include \"xsapi-c/string_verify_c.h\"\n\nnamespace xbox {\nnamespace services {\n    class xbox_live_context;\nnamespace system {\n/// <summary>Enumeration values that indicate the result code from string verification.\n/// These values are defined on the service side and should not be modified.\n/// </summary>\nenum class verify_string_result_code\n{\n    /// <summary>No issues were found with the string.</summary>\n    success = (int)XblVerifyStringResultCode::Success,\n\n    /// <summary>The string contains offensive content.</summary>\n    offensive = (int)XblVerifyStringResultCode::Offensive,\n\n    /// <summary>The string is too long to verify.</summary>\n    too_long = (int)XblVerifyStringResultCode::TooLong,\n\n    /// <summary>An unknown error was encountered during string verification.</summary>\n    unknown_error = (int) XblVerifyStringResultCode::UnknownError\n};\n\n/// <summary>\n/// Contains information about the results of a string verification.\n/// </summary>\nclass verify_string_result\n{\npublic:\n    /// <summary>\n    /// The result code for the string verification.\n    /// </summary>\n    inline verify_string_result_code result_code() const;\n\n    /// <summary>\n    /// first_offending_substring() contains the first offending substring if the\n    /// result code is verify_string_result_code::offensive.\n    /// </summary>\n    inline const string_t& first_offending_substring() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline verify_string_result();\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline verify_string_result(\n        XblVerifyStringResultCode resultCode,\n        const char* firstOffendingSubstring\n    );\n\nprivate:\n    verify_string_result_code m_resultCode;\n    string_t m_first_offending_substring;\n};\n\n\n/// <summary>\n/// Provides methods to validate a string for use with Xbox live.\n/// </summary>\nclass string_service\n{\npublic:\n\n    /// <summary>\n    /// Verifies if a string contains acceptable text for use with Xbox Live.\n    /// </summary>\n    /// <param name=\"stringToVerify\">The string to verify.</param>\n    /// <returns>\n    /// A verify_string_result object which indicates if the string contains unacceptable text.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// \n    /// Calls V2 GET /system/strings/validate\n    /// </remarks>\n    inline pplx::task<xbox_live_result<verify_string_result>> verify_string(_In_ const string_t& stringToVerify);\n\n    /// <summary>\n    /// Verifies a collection of strings to see if each string contains acceptable text for use with Xbox Live.\n    /// </summary>\n    /// <param name=\"stringsToVerify\">The collection of strings to verify.</param>\n    /// <returns>\n    /// A collection of verify_string_result objects which indicate if the strings contain unacceptable text.\n    /// </returns>\n    /// <remarks>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// \n    /// Calls V2 GET /system/strings/validate\n    /// </remarks>\n    inline pplx::task<xbox_live_result<std::vector<verify_string_result>>> verify_strings(_In_ const std::vector<string_t>& stringsToVerify);\n\n    inline string_service(const string_service& other);\n    inline string_service& operator=(string_service other);\n    inline ~string_service();\n\nprivate:\n    inline string_service(_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_xblContext;\n    friend xbox_live_context;\n};\n}}}\n\n#include \"impl/string_verify.hpp\"\n\n"
  },
  {
    "path": "Include/xsapi-cpp/system.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"types.h\"\n#include \"errors.h\"\n#include \"xbox_live_context_settings.h\"\n#include \"xbox_live_app_config.h\"\n\n#ifdef __OBJC__\n#import <UIKit/UIKit.h>\n#endif\n#if !HC_PLATFORM_IS_MICROSOFT && !XSAPI_NO_PPL\n#include \"pplx/pplxtasks.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n    class XboxLiveContextSettings;\n\n#if !defined(XSAPI_UNIT_TESTS) && !XSAPI_NO_PPL\n    namespace events {\n        class events_service;\n    }\n#endif\n\n    namespace multiplayer { namespace manager {\n        class multiplayer_client_manager;\n    }}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n    /// <summary>\n    /// Configuration information for Xbox Live service objects. \n    /// </summary>\n    namespace system {\n\n    class xbox_live_wns_event_args\n    {\n    public:\n        /// <summary>\n        /// Returns the xbox user id for the WNS event\n        /// </summary>\n        const string_t& xbox_user_id() const { return m_xbox_user_id; }\n\n        /// <summary>\n        /// Returns the notification type\n        /// </summary>\n        const string_t& notification_type() const { return m_notification_type; }\n\n        /// <summary>\n        /// Returns the full notification content\n        /// </summary>\n        const string_t& notification_content() const { return m_notification_content; }\n\n        /// <summary>\n        /// Internal function\n        /// </summary>\n        xbox_live_wns_event_args(\n            _In_ string_t xbox_user_id,\n            _In_ string_t notification_type,\n            _In_ string_t notification_content\n        ) :\n            m_xbox_user_id(std::move(xbox_user_id)),\n            m_notification_type(std::move(notification_type)),\n            m_notification_content(std::move(notification_content))\n        {}\n\n    private:\n        string_t m_xbox_user_id;\n        string_t m_notification_type;\n        string_t m_notification_content;\n    };\n\n    class xbox_live_services_settings : public std::enable_shared_from_this<xbox_live_services_settings>\n    {\n    public:\n        /// <summary>\n        /// Gets the singleton instance\n        /// </summary>\n        inline static std::shared_ptr<xbox_live_services_settings> get_singleton_instance(_In_ bool createIfRequired = true);\n\n        /// <summary>\n        /// Used by titles to register memory allocation hooks that are used by XSAPI when it \n        /// needs to allocate a large block of memory such as SocialManager which uses a large block \n        /// of memory to keep track of the friends list.  \n        /// </summary>\n        /// <param name=\"memAllocHandler\">The title's allocation function.  Input is size of memory block that's being requested.  Return is pointer to the allocated memory block</param>\n        /// <param name=\"memFreeHandler\">The title's memory free function. Input is address of memory to free</param>\n        /// <remarks>\n        /// If titles choose not to provide their own allocation hooks, these system default allocators will be used instead. \n        /// To unwire your hooks, call the same routine with nullptr passed in for both parameters. \n        /// It is important to provide an implementation for both memAllocHandler and memFreeHandler if you hook them;\n        /// hooking only one of them will be considered an error.\n        /// </remarks>\n        inline static void set_memory_allocation_hooks(\n            _In_ const std::function<_Ret_maybenull_ _Post_writable_byte_size_(dwSize) void*(_In_ size_t dwSize)>& memAllocHandler,\n            _In_ const std::function<void(_In_ void* pAddress)>& memFreeHandler\n        );\n\n        /// <summary>\n        /// Deprecated. XSAPI is using libHttpClient logging. A logging handler can be added using HCTraceSetClientCallback.\n        /// </summary>\n        _XSAPICPP_DEPRECATED inline function_context add_logging_handler(_In_ std::function<void(xbox_services_diagnostics_trace_level, const std::string&, const std::string&)> handler);\n\n        /// <summary>\n        /// Deprecated. See above.\n        /// </summary>\n        _XSAPICPP_DEPRECATED inline void remove_logging_handler(_In_ function_context context);\n\n        /// <summary>\n        /// Indicates the level of debug messages to send to the debugger's Output window.\n        /// </summary>\n        inline xbox_services_diagnostics_trace_level diagnostics_trace_level() const;\n\n        /// <summary>\n        /// Sets the level of debug messages to send to the debugger's Output window.\n        /// </summary>\n        inline void set_diagnostics_trace_level(_In_ xbox_services_diagnostics_trace_level value);\n\n        /// <summary>\n        /// Deprecated. Registering WNS callbacks though XSAPI is no longer supported.\n        /// </summary>\n        _XSAPICPP_DEPRECATED inline function_context add_wns_handler(_In_ const std::function<void(const xbox_live_wns_event_args&)>& handler);\n\n        /// <summary>\n        /// Deprecated. Registering WNS callbacks though XSAPI is no longer supported.\n        /// </summary>\n        _XSAPICPP_DEPRECATED inline void remove_wns_handler(_In_ function_context context);\n\n    private:\n        xbox_live_services_settings() = default;\n    };\n} // namespace system\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#if !XSAPI_NO_PPL\n#include \"impl/system.hpp\"\n#endif\n"
  },
  {
    "path": "Include/xsapi-cpp/title_callable_ui.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#if !XSAPI_NO_PPL\n#include \"xsapi-cpp/multiplayer.h\"\n#endif // !XSAPI_NO_PPL\n\nnamespace xbox { namespace services { namespace system {\n\n/// <summary>List of gaming privilege that a user can have.</summary>\nenum class gaming_privilege\n{\n    /// <summary>The user can broadcast live gameplay.</summary>\n    broadcast = 190,\n\n    /// <summary>The user can view other user's friends list if this privilege is present.</summary>\n    view_friends_list = 197,\n\n    /// <summary>The user can upload recorded in-game videos to the cloud if this privilege is present. Viewing GameDVRs is subject to privacy controls.</summary>\n    game_dvr = 198,\n\n    /// <summary>Kinect recorded content can be uploaded to the cloud for the user and made accessible to anyone if this privilege is present. Viewing other user's Kinect content is subject to a privacy setting.</summary>\n    share_kinect_content = 199,\n\n    /// <summary>The user can join a party session if this privilege is present</summary>\n    multiplayer_parties = 203,\n\n    /// <summary>The user can participate in voice chat during parties and multiplayer game sessions if this privilege is present. Communicating with other users is subject to additional privacy permission checks</summary>\n    communication_voice_ingame = 205,\n\n    /// <summary>The user can use voice communication with Skype on Xbox One if this privilege is present</summary>\n    communication_voice_skype = 206,\n\n    /// <summary>The user can allocate a cloud compute cluster and manage a cloud compute cluster for a hosted game session if this privilege is present</summary>\n    cloud_gaming_manage_session = 207,\n\n    /// <summary>The user can join a cloud compute session if this privilege is present</summary>\n    cloud_gaming_join_session = 208,\n\n    /// <summary>The user can save games in cloud title storage if this privilege is present</summary>\n    cloud_saved_games = 209,\n\n    /// <summary>The user can share content with others if this privilege is present</summary>\n    share_content = 211,\n\n    /// <summary>The user can purchase, download and launch premium content available with the Xbox LIVE Gold subscription if this privilege is present</summary>\n    premium_content = 214,\n\n    /// <summary>The user can purchase and download premium subscription content and use premium subscription features when this privilege is present</summary>\n    subscription_content = 219,\n\n    /// <summary>The user is allowed to share progress information on social networks when this privilege is present</summary>\n    social_network_sharing = 220,\n\n    /// <summary>The user can access premium video services if this privilege is present</summary>\n    premium_video = 224,\n\n    /// <summary>The user can use video communication with Skype or other providers when this privilege is present. Communicating with other users is subject to additional privacy permission checks</summary>\n    video_communications = 235,\n\n    /// <summary>The user is authorized to purchase content when this privilege is present</summary>\n    purchase_content = 245,\n\n    /// <summary>The user is authorized to download and view online user created content when this privilege is present.</summary>\n    user_created_content = 247,\n\n    /// <summary>The user is authorized to view other user's profiles when this privilege is present. Viewing other user's profiles is subject to additional privacy checks</summary>\n    profile_viewing = 249,\n\n    /// <summary>The user can use asynchronous text messaging with anyone when this privilege is present. Extra privacy permissions checks are required to determine who the user is authorized to communicate with. Communicating with other users is subject to additional privacy permission checks</summary>\n    communications = 252,\n\n    /// <summary>The user can join a multiplayer sessions for a game when this privilege is present.</summary>\n    multiplayer_sessions = 254,\n\n    /// <summary>The user can follow other Xbox LIVE users and add Xbox LIVE friends when this privilege is present.</summary>\n    add_friend = 255\n};\n\n#if !XSAPI_NO_PPL\n/// <summary>This class contains functions used for displaying stock UI during a game such as showing a people picker.</summary>\nclass title_callable_ui\n{\npublic:\n#if HC_PLATFORM != HC_PLATFORM_UWP\n    /// <summary>\n    /// Shows a picker UI that allows a person playing the game to select players\n    /// from a presented list of other people.\n    /// After the operation is complete, the list of selected Xbox User IDs is returned to the calling app.\n    /// </summary>\n    /// <param name=\"promptDisplayText\">The prompt display text.</param>\n    /// <param name=\"xboxUserIds\">A list of Xbox User IDs which the user can select from.</param>\n    /// <param name=\"preselectedXboxUserIds\">A list of Xbox User IDs which will be pre-selected.</param>\n    /// <param name=\"minSelectionCount\">The minimum number of people the user must select.</param>\n    /// <param name=\"maxSelectionCount\">The maximum number of people the user can select.</param>\n    /// <returns>\n    /// Returns a pplx::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The task completes when the UI is closed.\n    /// result.payload() contains the list of users that were selected by the player.\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<std::vector<string_t>>>\n    show_player_picker_ui(\n        _In_ const string_t& promptDisplayText,\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ const std::vector<string_t>& preselectedXboxUserIds,\n        _In_ uint32_t minSelectionCount,\n        _In_ uint32_t maxSelectionCount\n        );\n\n    /// <summary>\n    /// Shows a picker UI populated from the selected user's friend list and suggested friend list.\n    /// After selection, the user can send an invitation to play a game and/or party chat for a\n    /// specified game session to the selected people.\n    /// </summary>\n    /// <param name=\"sessionReference\">A reference to the multiplayer session to invite people to.</param>\n    /// <param name=\"invitationDisplayText\">The ID of the custom invite string that is displayed with \n    /// the invite notification.The ID must match the ID that is assigned to the custom invite string \n    /// in the title's multiplayer service configuration. The format of the parameter is \"///{id}\", \n    /// where {id} is replaced with the ID of the custom string. For example, if the ID of the custom string \n    /// \"Play Capture the Flag\" is 1, then you would set this parameter to \"///1\" in order to display the \n    /// \"Play Capture the Flag\" custom string in the game invite. \n    /// Pass an empty string if you don't want a custom string added to the invite.</param>\n    /// <param name=\"contextStringId\">The custom activation context that is available to the invitee in the \n    /// activation URI for an invite. The custom activation context string must be URL-safe and binary content \n    /// should be encoded with URL-safe base64 encoding. The maximum length is 160 characters.</param>\n    /// <returns>\n    /// Returns a pplx::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The task completes when the UI is closed.\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_game_invite_ui(\n        _In_ const xbox::services::multiplayer::multiplayer_session_reference& sessionReference,\n        _In_ const string_t& invitationDisplayText,\n        _In_ const string_t& contextStringId = string_t()\n        );\n\n    /// <summary>\n    /// Shows UI displaying the profile card for a specified user.\n    /// </summary>\n    /// <param name=\"targetXboxUserId\">The Xbox User ID to show information about.</param>\n    /// <returns>\n    /// Returns a pplx::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The task completes when the UI is closed.\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_profile_card_ui(\n        _In_ const string_t& targetXboxUserId\n#if !HC_PLATFORM_IS_MICROSOFT\n        , _In_ xbox_live_user_t user\n#endif\n        );\n\n    /// <summary>\n    /// Shows UI for adding or removing a specified person to or from the requesting user's friend list.\n    /// </summary>\n    /// <param name=\"targetXboxUserId\">The Xbox User ID to show information about.</param>\n    /// <returns>\n    /// Returns a pplx::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The task completes when the UI is closed.\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_change_friend_relationship_ui(\n        _In_ const string_t& targetXboxUserId\n        );\n\n    /// <summary>\n    /// Shows UI presenting the requesting user's achievements for the specified title.\n    /// </summary>\n    /// <param name=\"titleId\">The Xbox titleId to show information about.</param>\n    /// <returns>\n    /// Returns a pplx::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The task completes when the UI is closed.\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_title_achievements_ui(\n        _In_ uint32_t titleId\n        );\n#endif\n\n#if defined(_APISET_TARGET_VERSION_WIN10_RS3)\n    /// <summary>\n    /// Shows UI displaying the friend finder app, so the user can get more friends\n    /// </summary>\n    /// <returns>\n    /// Returns a pplx::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The task completes when the UI is closed.\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_friend_finder_ui(\n    );\n\n    /// <summary>\n    /// Invokes the Xbox App to show full user profile for the target user\n    /// </summary>\n    /// <param name=\"targetXboxUserId\">The Xbox target xuid to show the profile for.</param>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_user_profile_ui(_In_ const string_t& targetXboxUserId);\n\n    /// <summary>\n    /// Shows UI displaying the title app for the calling application.\n    /// </summary>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_title_hub_ui(\n#if HC_PLATFORM == HC_PLATFORM_UWP\n        _In_opt_ Windows::System::User^ user = nullptr\n#endif\n    );\n\n    /// <summary>\n    /// Shows UI displaying the user settings\n    /// </summary>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_user_settings_ui(\n    );\n\n    /// <summary>\n    /// Shows UI displaying a dialog to customize the user's profile\n    /// </summary>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n        show_customize_user_profile_ui(\n        );\n#elif !HC_PLATFORM_IS_MICROSOFT\n\n    /// <summary>\n    /// Invokes the Xbox App to show full user profile for the target user\n    /// </summary>\n    /// <param name=\"targetXboxUserId\">The Xbox target xuid to show the profile for.</param>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_user_profile_ui(_In_ const string_t& targetXboxUserId);\n\n    /// <summary>\n    /// Invokes the Xbox App to show the title app for the calling application.\n    /// </summary>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_title_hub_ui();\n\n    /// <summary>\n    /// Invokes the Xbox App to show the user settings\n    /// </summary>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_user_settings_ui();\n#endif\n\n#if !HC_PLATFORM_IS_MICROSOFT\n    /// <summary>\n    /// Invokes the Xbox App to show add friends functionality.\n    /// </summary>\n    /// <returns>\n    /// result.err() contains the error based on what happened in the case of an error.\n    /// </returns>\n    static pplx::task<xbox::services::xbox_live_result<void>>\n    show_add_friends_ui();\n#endif\n\nprivate:\n};\n#endif // !XSAPI_NO_PPL\n\n}}}\n\n\n"
  },
  {
    "path": "Include/xsapi-cpp/title_storage.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <mutex>\n#include \"xsapi-c/title_storage_c.h\"\n\nstruct XblContext;\n\nnamespace xbox { namespace services {\n    class http_call;\n    class xbox_live_context;\n}}\n\nnamespace xbox { namespace services {\n    /// <summary>\n    /// Classes for handling title data in the cloud. \n    /// </summary>\n    namespace title_storage {\n\n        class title_storage_service;\n\n/// <summary>Defines values used to indicate title storage type.</summary>\nenum class title_storage_type\n{\n    /// <summary>\n    /// Per-user data storage such as game state or game settings that can be only be accessed by Xbox One.\n    /// User restrictions can be configured to public or owner only in the service configuration.\n    /// </summary>\n    trusted_platform_storage = static_cast<int>(XblTitleStorageType::TrustedPlatformStorage),\n\n    /// <summary>\n    /// Global data storage.  This storage type is only writable via title configuration sites or Xbox Live developer tools.\n    /// Any platform may read from this storage type. Data could be rosters, maps, challenges, art resources, etc.\n    /// </summary>\n    global_storage = static_cast<int>(XblTitleStorageType::GlobalStorage),\n\n    /// <summary>\n    /// Per-user data storage such as game state or game settings the can be accessed by Xbox One, Windows 10, and Windows Phone 10 devices\n    /// User restrictions can be configured to public or owner only in the service configuration.\n    /// </summary>\n    universal = static_cast<int>(XblTitleStorageType::Universal)\n};\n\n/// <summary>Defines values used to indicate title storage blob type.</summary>\nenum class title_storage_blob_type\n{\n    /// <summary>Unknown blob type.</summary>\n    unknown = static_cast<int>(XblTitleStorageBlobType::Unknown),\n\n    /// <summary>Binary blob type.</summary>\n    binary = static_cast<int>(XblTitleStorageBlobType::Binary),\n\n    /// <summary>JSON blob type.</summary>\n    json = static_cast<int>(XblTitleStorageBlobType::Json),\n\n    /// <summary>Config blob type. </summary>\n    config = static_cast<int>(XblTitleStorageBlobType::Config)\n};\n\n/// <summary>Defines values used to indicate the ETag match condition used when downloading, uploading or deleting title storage data.</summary>\nenum class title_storage_e_tag_match_condition\n{\n    /// <summary>There is no match condition.</summary>\n    not_used = static_cast<int>(XblTitleStorageETagMatchCondition::NotUsed),\n\n    /// <summary>Perform the request if the Etag value specified matches the service value.</summary>\n    if_match = static_cast<int>(XblTitleStorageETagMatchCondition::IfMatch),\n\n    /// <summary>Perform the request if the Etag value specified does not match the service value.</summary>\n    if_not_match = static_cast<int>(XblTitleStorageETagMatchCondition::IfNotMatch)\n};\n\n/// <summary>\n/// Returns the amount of storage space allocated and used.\n/// </summary>\nclass title_storage_quota\n{\npublic:\n    /// <summary>\n    /// The service configuration ID associated with the quota.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// The TitleStorageType associated with the quota.\n    /// </summary>\n    inline title_storage_type storage_type() const;\n\n    /// <summary>\n    /// The Xbox User ID associated with the quota if StorageType is TrustedPlatformStorage or JsonStorage, otherwise null.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// Number of bytes used in title storage of type StorageType.\n    /// </summary>\n    inline uint64_t used_bytes() const;\n\n    /// <summary>\n    /// Maximum number of bytes that can be used in title storage of type StorageType.\n    /// Note that this is a soft limit and the used bytes may actually exceed this value.\n    /// </summary>\n    inline uint64_t quota_bytes() const;\n\n    // Internal\n    title_storage_quota() = default;\n    inline title_storage_quota(string_t scid, title_storage_type storageType, uint64_t xuid, uint64_t usedByted, uint64_t quotaBytes);\n\nprivate:\n    string_t m_serviceConfigurationId;\n    title_storage_type m_storageType{};\n    uint64_t m_xboxUserId{ 0 };\n    uint64_t m_usedBytes{ 0 };\n    uint64_t m_quotaBytes{ 0 };\n};\n\n/// <summary>\n/// Metadata about a blob.\n/// </summary>\nclass title_storage_blob_metadata\n{\npublic:\n    /// <summary>\n    /// Initializes a new instance of the title_storage_blob_metadata class.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"storageType\">The TitleStorageType to get blob metadata objects for.  Valid values are TrustedPlatormStorage, JsonStorage and GlobalStorage.</param>\n    /// <param name=\"blobPath\">The full path to to the blob.  examples: \"gameconfig.json\" and \"user/settings/playerconfiguration.json\".</param>\n    /// <param name=\"blobType\">The TitleStorageBlobType of this object.  Valid values are Binary, Json and Config.</param>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the title storage to enumerate. Ignored when dealing with GlobalStorage, so passing nullptr is acceptable in that case. (Optional)</param>\n    /// <remarks>\n    /// All other properties of this class are optional.  To initialize optional properties, use the other constructors.\n    /// ClientTimestamp.UniversalTime will be initialized to 0. Length is initialized to 0.\n    /// title_storage_blob_metadata objects retrieved using TitleStorageService::GetBlobMetadataAsync will have current Length and ETag values.\n    /// </remarks>\n    inline title_storage_blob_metadata(\n        _In_ string_t serviceConfigurationId,\n        _In_ title_storage_type storageType,\n        _In_ string_t blobPath,\n        _In_ title_storage_blob_type blobType,\n        _In_ string_t xboxUserId\n        );\n\n    /// <summary>\n    /// Initializes a new instance of the title_storage_blob_metadata class including support for all optional properties except ClientTimestamp.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"storageType\">The TitleStorageType to get blob metadata objects for.  Valid values are TrustedPlatormStorage, JsonStorage and GlobalStorage.</param>\n    /// <param name=\"blobPath\">The full path to to the blob.  examples: \"gameconfig.json\" and \"user/settings/playerconfiguration.json\".</param>\n    /// <param name=\"blobType\">The TitleStorageBlobType of this object.  Valid values are Binary, Json and Config.</param>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the title storage to enumerate. Ignored when dealing with GlobalStorage, so passing nullptr is acceptable in that case. (Optional)</param>\n    /// <param name=\"displayName\">A display name suitable for displaying to the user. (Optional)</param>\n    /// <param name=\"eTag\">An ETag value to be associated with this instance.  It is used for upload, download and delete operations. (Optional)</param>\n    /// <remarks>\n    /// ClientTimestamp.UniversalTime will be initialized to 0. Length is initialized to 0.\n    /// title_storage_blob_metadata objects retrieved using TitleStorageService::GetBlobMetadataAsync will have current Length and ETag values.\n    /// </remarks>\n    inline title_storage_blob_metadata(\n        _In_ string_t serviceConfigurationId,\n        _In_ title_storage_type storageType,\n        _In_ string_t blobPath,\n        _In_ title_storage_blob_type blobType,\n        _In_ string_t xboxUserId,\n        _In_ string_t displayName,\n        _In_ string_t eTag\n        );\n\n    /// <summary>\n    /// Initializes a new instance of the title_storage_blob_metadata class including support for all optional properties.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"storageType\">The TitleStorageType to get blob metadata objects for.  Valid values are TrustedPlatormStorage, JsonStorage and GlobalStorage.</param>\n    /// <param name=\"blobPath\">The full path to to the blob.  examples: \"gameconfig.json\" and \"user/settings/playerconfiguration.json\".</param>\n    /// <param name=\"blobType\">The TitleStorageBlobType of this object.  Valid values are Binary, Json and Config.</param>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the title storage to enumerate. Ignored when dealing with GlobalStorage, so passing nullptr is acceptable in that case. (Optional)</param>\n    /// <param name=\"displayName\">A display name suitable for displaying to the user. (Optional)</param>\n    /// <param name=\"eTag\">An ETag value to be associated with this instance.  It is used for upload, download and delete operations. (Optional)</param>\n    /// <param name=\"clientTimestamp\">A client provided timestamp value to be associated with this instance.</param>\n    /// <remarks>\n    /// Length is initialized to 0.\n    /// title_storage_blob_metadata objects retrieved using TitleStorageService::GetBlobMetadataAsync will have current Length and ETag values.\n    /// </remarks>\n    inline title_storage_blob_metadata(\n        _In_ string_t serviceConfigurationId,\n        _In_ title_storage_type storageType,\n        _In_ string_t blobPath,\n        _In_ title_storage_blob_type blobType,\n        _In_ string_t xboxUserId,\n        _In_ string_t displayName,\n        _In_ string_t eTag,\n        _In_ utility::datetime clientTimestamp\n        );\n\n    /// <summary>\n    /// Blob path is a unique string that conforms to a SubPath\\file format (example: \"foo\\bar\\blob.txt\").\n    /// </summary>\n    inline string_t blob_path() const;\n\n    /// <summary>\n    /// Type of blob data. Possible values are: Binary, Json, and Config.\n    /// </summary>\n    inline title_storage_blob_type blob_type() const;\n\n    /// <summary>\n    /// Type of storage.\n    /// </summary>\n    inline title_storage_type storage_type() const;\n\n    /// <summary>\n    /// [optional] Friendly display name to show in app UI.\n    /// </summary>\n    inline string_t display_name() const;\n\n    /// <summary>\n    /// ETag for the file used in read and write requests.\n    /// </summary>\n    inline string_t e_tag() const;\n\n    /// <summary>\n    /// [optional] Timestamp assigned by the client.\n    /// </summary>\n    inline utility::datetime client_timestamp() const;\n\n    /// <summary>\n    /// [optional] Timestamp assigned by the client.\n    /// </summary>\n    inline void set_client_timestamp(_In_ utility::datetime value);\n\n    /// <summary>\n    /// Gets the number of bytes of the blob data.\n    /// </summary>\n    inline uint64_t length() const;\n\n    /// <summary>\n    /// The service configuration ID of the title\n    /// </summary>\n    inline string_t service_configuration_id() const;\n\n    /// <summary>\n    /// The Xbox User ID of the player this file belongs to.\n    /// This value will be null for Global and Session files.\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    // Internal\n    title_storage_blob_metadata() = default;\n    inline title_storage_blob_metadata(XblTitleStorageBlobMetadata blobMetadata);\n\nprivate:\n    XblTitleStorageBlobMetadata m_blobMetadata{};\n\n    friend title_storage_service;\n};\n\n/// <summary>\n/// Metadata about blob data returned from the cloud.\n/// </summary>\nclass title_storage_blob_metadata_result\n{\npublic:\n    /// <summary>\n    /// Collection of title_storage_blob_metadata objects returned by a service request\n    /// </summary>\n    inline const std::vector<title_storage_blob_metadata>& items() const;\n\n    /// <summary>\n    /// Returns an title_storage_blob_metadata_result object containing the next page of title_storage_blob_metadata objects\n    /// </summary>\n    /// <param name=\"maxItems\">The maximum number of items the result can contain.  Pass 0 to attempt to retrieve all items.</param>\n    /// <returns>title_storage_blob_metadata_result object for the next page.</returns>\n    inline pplx::task<xbox_live_result<title_storage_blob_metadata_result>> get_next(\n        _In_ uint32_t maxItems\n        ) const;\n\n    /// <summary>\n    /// Indicates if there is additional data to retrieve from a get_next call\n    /// </summary>\n    inline bool has_next() const;\n\n    // Internal\n    title_storage_blob_metadata_result() = default;\n    inline title_storage_blob_metadata_result(XblTitleStorageBlobMetadataResultHandle handle);\n    inline title_storage_blob_metadata_result(_In_ const title_storage_blob_metadata_result& other);\n    inline title_storage_blob_metadata_result& operator=(title_storage_blob_metadata_result other);\n    inline ~title_storage_blob_metadata_result();\n\nprivate:\n    XblTitleStorageBlobMetadataResultHandle m_handle{ nullptr };\n    std::vector<title_storage_blob_metadata> m_items;\n};\n\n/// <summary>\n/// Blob data returned from the cloud.\n/// </summary>\nclass title_storage_blob_result\n{\npublic:\n    /// <summary>\n    /// The contents of the title storage blob.\n    /// </summary>\n    inline std::shared_ptr<std::vector<unsigned char>> const blob_buffer() const;\n\n    /// <summary>\n    /// Updated title_storage_blob_metadata object following an upload or download.\n    /// </summary>\n    inline const title_storage_blob_metadata& blob_metadata() const;\n\n    // Internal\n    title_storage_blob_result() = default;\n    inline title_storage_blob_result(std::shared_ptr<std::vector<unsigned char>> blobBuffer, title_storage_blob_metadata blobMetadata);\nprivate:\n    std::shared_ptr<std::vector<unsigned char>> m_blobBuffer;\n    title_storage_blob_metadata m_blobMetadata;\n};\n\n/// <summary>\n/// Services that manage title storage.\n/// </summary>\nclass title_storage_service\n{\npublic:\n    /// <summary>\n    /// Gets title storage quota information for the specified service configuration and storage type.\n    /// For user storage types (TrustedPlatform and Json) the request will be made for the calling user's\n    /// Xbox user Id.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"storageType\">The storage type to get quota information for.</param>\n    /// <returns>title_storage_quota object containing the quota information.</returns>\n    /// <remarks>Calls\n    /// V1 GET trustedplatform/users/xuid({xuid})/scids/{scid} or\n    /// V1 GET json/users/xuid({xuid})/scids/{scid} or\n    /// V1 GET global/scids/{scid}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<title_storage_quota>> get_quota(\n        _In_ string_t serviceConfigurationId,\n        _In_ title_storage_type storageType\n        );\n\n    /// <summary>\n    /// Gets a list of blob metadata objects under a given path for the specified service configuration, storage type and storage ID.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"storageType\">The storage type to get blob metadata objects for.</param>\n    /// <param name=\"blobPath\">The root path to enumerate.  Results will be for blobs contained in this path and all subpaths. (Optional)</param>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the title storage to enumerate. Ignored when enumerating GlobalStorage, so passing nullptr is acceptable. (Optional)</param>\n    /// <param name=\"skipItems\">The number of items to skip before returning results. (Optional)</param>\n    /// <param name=\"maxItems\">The maximum number of items to return. (Optional)</param>\n    /// <returns>title_storage_blob_metadata_result object containing the list of enumerated blob metadata objects.</returns>\n    /// <remarks>Calls\n    /// V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path}?maxItems={maxItems}[skipItems={skipItems}] or\n    /// V1 GET json/users/xuid({xuid})/scids/{scid}/data/{path}?maxItems={maxItems}[skipItems={skipItems}] or\n    /// V1 GET global/scids/{scid}/data/{path}?maxItems={maxItems}[skipItems={skipItems}]\n    /// </remarks>\n    inline pplx::task<xbox_live_result<title_storage_blob_metadata_result>> get_blob_metadata(\n        _In_ string_t serviceConfigurationId,\n        _In_ title_storage_type storageType,\n        _In_ string_t blobPath = string_t(),\n        _In_ string_t xboxUserId = string_t(),\n        _In_ uint32_t skipItems = 0,\n        _In_ uint32_t maxItems = 0\n        );\n\n    /// <summary>\n    /// Deletes a blob from title storage.\n    /// </summary>\n    /// <param name=\"blobMetadata\">The blob metadata for the title storage blob to delete.</param>\n    /// <param name=\"deleteOnlyIfEtagMatches\">Specifies whether or not to have the delete operation check that the ETag matches before deleting the blob.</param>\n    /// <remarks>Calls\n    /// V1 DELETE trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 DELETE json/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 DELETE sessions/{sessionId}/scids/{scid}/data/{path},{type}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<void>> delete_blob(\n        _In_ const title_storage_blob_metadata& blobMetadata,\n        _In_ bool deleteOnlyIfEtagMatches\n        );\n\n    /// <summary>\n    /// Downloads blob data from title storage.\n    /// </summary>\n    /// <param name=\"blobMetadata\">The blob metadata for the title storage blob to download.</param>\n    /// <param name=\"blobBuffer\">The client provided buffer to store the downloaded blob data in.  This buffer needs to be large enough to store the blob being downloaded.\n    /// If necessary, the length required for the buffer can be retrieved by getting the blob metadata.</param>\n    /// <param name=\"etagMatchCondition\">The ETag match condition used to determine if the blob should be downloaded.</param>\n    /// <param name=\"selectQuery\">ConfigStorage filter string or JSONStorage json property name string to filter. (Optional)</param>\n    /// <returns>TitleStorageBlobResult object containing the client provided blob buffer and an updated title_storage_blob_metadata object.\n    /// The metadata object will contain updated ETag and Length properties.</returns>\n    /// <remarks>\n    /// This method will throw ERROR_INSUFFICIENT_BUFFER (0x8007007A) if the blobBuffer doesn't have enough capacity to hold the blob data.\n    /// Calls V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 GET json/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 GET global/scids/{scid}/data/{path},{type} or\n    /// V1 GET sessions/{sessionId}/scids/{scid}/data/{path},{type}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<title_storage_blob_result>> download_blob(\n        _In_ title_storage_blob_metadata blobMetadata,\n        _In_ std::shared_ptr<std::vector<unsigned char>> blobBuffer,\n        _In_ title_storage_e_tag_match_condition etagMatchCondition,\n        _In_ string_t selectQuery = string_t()\n        );\n\n    /// <summary>\n    /// Downloads blob data from title storage.\n    /// </summary>\n    /// <param name=\"blobMetadata\">The blob metadata for the title storage blob to download.</param>\n    /// <param name=\"blobBuffer\">The client provided buffer to store the downloaded blob data in.  This buffer needs to be large enough to store the blob being downloaded.\n    /// If necessary, the length required for the buffer can be retrieved by getting the blob metadata.</param>\n    /// <param name=\"etagMatchCondition\">The ETag match condition used to determine if the blob should be downloaded.</param>\n    /// <param name=\"selectQuery\">ConfigStorage filter string or JSONStorage json property name string to filter. (Optional)</param>\n    /// <param name=\"preferredDownloadBlockSize\">The preferred download block size in bytes for binary blobs. </param>\n    /// <returns>TitleStorageBlobResult object containing the client provided blob buffer and an updated title_storage_blob_metadata object.\n    /// The metadata object will contain updated ETag and Length properties.</returns>\n    /// <remarks>\n    /// This method will throw ERROR_INSUFFICIENT_BUFFER (0x8007007A) if the blobBuffer doesn't have enough capacity to hold the blob data.\n    /// Calls V1 GET trustedplatform/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 GET json/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 GET global/scids/{scid}/data/{path},{type} or\n    /// V1 GET sessions/{sessionId}/scids/{scid}/data/{path},{type}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<title_storage_blob_result>> download_blob(\n        _In_ title_storage_blob_metadata blobMetadata,\n        _In_ std::shared_ptr<std::vector<unsigned char>> blobBuffer,\n        _In_ title_storage_e_tag_match_condition etagMatchCondition,\n        _In_ string_t selectQuery,\n        _In_ uint32_t preferredDownloadBlockSize\n        );\n\n    /// <summary>\n    /// Uploads blob data to title storage.\n    /// </summary>\n    /// <param name=\"blobMetadata\">Contains properties required to upload the buffer to title storage.  Uploads require a service configuration Id, blob path, blob type and storage type at a minimum.</param>\n    /// <param name=\"blobBuffer\">The buffer containing the blob data to upload.  This buffer must be available for the duration of the async operation.  Clients should not modify the buffer while an upload is in progress.</param>\n    /// <param name=\"etagMatchCondition\">The ETag match condition used to determine if the blob data should be uploaded.</param>\n    /// <param name=\"preferredUploadBlockSize\">The preferred upload block size in bytes for binary blobs. Binary blobs will be\n    /// uploaded in multiple chunks of this size if they exceed it.  Larger sizes are preferred by the service.\n    /// If timeouts occur, the app should retry with a smaller size.  Block size must be within the 1K to 4MB range.  This method\n    /// will use a default size if this parameter is not within the acceptable range.  The current minimum size is 1024 bytes,\n    /// maximum size is 4194304 bytes and the default size is 262144 bytes.\n    /// </param>\n    /// <returns>title_storage_blob_metadata object with updated Etag and Length properties.</returns>\n    /// <remarks>\n    /// V1 PUT json/users/xuid({xuid})/scids/{scid}/data/{path},{type} or\n    /// V1 PUT global/scids/{scid}/data/{path},{type} or\n    /// V1 PUT sessions/{sessionId}/scids/{scid}/data/{path},{type}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<title_storage_blob_metadata>> upload_blob(\n        _In_ title_storage_blob_metadata blobMetadata,\n        _In_ std::shared_ptr<std::vector<unsigned char>> blobBuffer,\n        _In_ title_storage_e_tag_match_condition etagMatchCondition,\n        _In_ uint32_t preferredUploadBlockSize = XBL_TITLE_STORAGE_MIN_UPLOAD_BLOCK_SIZE\n        );\n\n    inline title_storage_service(const title_storage_service& other);\n    inline title_storage_service& operator=(title_storage_service other);\n    inline ~title_storage_service();\n\nprivate:\n    inline title_storage_service(_In_ XblContextHandle contextHandle);\n\n    XblContextHandle m_xblContext{ nullptr };\n\n    friend xbox_live_context;\n};\n\n}}}\n\n#include \"impl/title_storage.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/types.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <string>\n#include <regex>\n#include <chrono>\n#include \"xsapi-c/types_c.h\"\n\n#if HC_PLATFORM_IS_MICROSOFT\n#define _XSAPICPP_DEPRECATED __declspec(deprecated)\n#else\n#define _XSAPICPP_DEPRECATED __attribute__ ((deprecated))\n#endif\n\n#if !HC_PLATFORM_IS_MICROSOFT || (defined(_MSC_VER) && (_MSC_VER >= 1900))\n// VS2013 doesn't support default move constructor and assignment, so we implemented this.\n// However, a user defined move constructor and assignment will implicitly delete default copy \n// constructor and assignment in other compiler like clang. So we only define this in Win32 under VS2013\n#define DEFAULT_MOVE_ENABLED\n#endif\n\ntypedef void* function_context;\n#if HC_PLATFORM_IS_MICROSOFT\ntypedef wchar_t char_t;\ntypedef std::wstring string_t;\ntypedef std::wstringstream stringstream_t;\ntypedef std::wregex regex_t;\ntypedef std::wsmatch smatch_t;\n#else\ntypedef char char_t;\ntypedef std::string string_t;\ntypedef std::stringstream stringstream_t;\ntypedef std::regex regex_t;\ntypedef std::smatch smatch_t;\n#endif\n\n#if _MSC_VER <= 1800\ntypedef std::chrono::system_clock chrono_clock_t;\n#else\ntypedef std::chrono::steady_clock chrono_clock_t;\n#endif\n\n// Forward declarations\nnamespace xbox {\n    namespace services {\n        class xbox_live_context_settings;\n        class JsonAllocator;\n        namespace system {\n            class xbox_live_user;\n        }\n    }\n}\n\n#if HC_PLATFORM != HC_PLATFORM_XDK\n// SSL client certificate context\n#if HC_PLATFORM_IS_MICROSOFT\n#include <wincrypt.h>\ntypedef PCCERT_CONTEXT cert_context;\n#endif\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_UWP\n    typedef Windows::System::User^ user_creation_context;\n#else\n    typedef void* user_creation_context;\n#endif\n\ntypedef XblUserHandle xbox_live_user_t;\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN                     namespace xbox { namespace services {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END                       }}\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN                         namespace Microsoft { namespace Xbox { namespace Services { \n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_END                           }}}\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace system {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_BEGIN                  NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace System { \n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_END                    NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace social {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_BEGIN                  NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Social {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_END                    NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace achievements {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_BEGIN            NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Achievements {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_END              NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_BEGIN NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace achievements { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_END   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Achievements { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace leaderboard {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Leaderboard {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN      NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace user_statistics {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_BEGIN          NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace UserStatistics {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_END            NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace multiplayer {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Multiplayer {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace matchmaking {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Matchmaking {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace marketplace {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Marketplace {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace privacy {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_BEGIN                 NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Privacy {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_END                   NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN                 NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace real_time_activity {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END                   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_BEGIN                     NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace RealTimeActivity {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_END                       NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN            NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace presence {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_BEGIN                NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Presence {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_END                  NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_CPP_BEGIN  NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace game_server_platform {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_CPP_END    NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_BEGIN      NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace GameServerPlatform {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_END        NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace title_storage {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_BEGIN           NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace TitleStorage {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_END             NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace events {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_BEGIN                  NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Events {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_END                    NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_CPP_BEGIN   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace contextual_search {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_CPP_END     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace ContextualSearch {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_CPP_BEGIN   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace entertainment_profile {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_CPP_END     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace EntertainmentProfile {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace notification {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace multiplayer { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Multiplayer { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_CPP_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace experimental {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_CPP_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_BEGIN            NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Experimental {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_END              NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace social { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Social { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STAT_MANAGER_CPP_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace stats { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STAT_MANAGER_CPP_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STATISTIC_MANAGER_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Statistics { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STATISTIC_MANAGER_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_CPP_BEGIN   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace player_state {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_CPP_END     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace PlayerState {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_CPP_BEGIN          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace clubs {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_CPP_END            NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Clubs {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n"
  },
  {
    "path": "Include/xsapi-cpp/user_statistics.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xsapi-c/user_statistics_c.h\"\n#include \"xsapi-cpp/real_time_activity.h\"\n\nnamespace xbox { namespace services {\n    class xbox_live_context;\n    /// <summary>\n    /// Contains classes and enumerations that let you retrieve\n    /// player statistics from Xbox Live.\n    /// </summary>\n    namespace user_statistics {\n        \n/// <summary>\n/// Contains information about a user statistic.\n/// </summary>\nclass statistic\n{\npublic:\n    /// <summary>\n    /// The name of the statistic.\n    /// </summary>\n    inline const string_t& statistic_name() const;\n\n    /// <summary>\n    /// The type of the statistic.\n    /// </summary>\n    inline const string_t& statistic_type() const;\n\n    /// <summary>\n    /// The value of the statistic.\n    /// </summary>\n    inline const string_t& value() const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline statistic(const XblStatistic& statistic);\n    inline statistic(const string_t& name, const string_t& type, const string_t& value);\n\nprivate:\n    string_t m_statName;\n    string_t m_statType;\n    string_t m_value;\n};\n\n/// <summary>\n/// Contains statistical information from a service configuration.\n/// </summary>\nclass service_configuration_statistic\n{\npublic:    \n    /// <summary>\n    /// The service configuration ID (SCID) associated with the leaderboard.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// A collection of statistics used in leaderboards.\n    /// </summary>\n    inline const std::vector<statistic>& statistics() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline service_configuration_statistic(const XblServiceConfigurationStatistic& serviceConfigurationStatistic);\n\nprivate:\n    string_t m_serviceConfigurationId;\n    std::vector<statistic> m_statistics;\n};\n\n/// <summary>\n/// Represents the results of a user statistic query.\n/// </summary>\nclass user_statistics_result\n{\npublic:\n    /// <summary>\n    /// The Xbox User ID for the user in a statistic.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// A collection of statistics from a service configuration.\n    /// </summary>        \n    inline const std::vector<service_configuration_statistic>& service_configuration_statistics() const;\n\n    /// <summary>\n    /// Internal functions\n    /// </summary>\n    inline user_statistics_result() = default;\n    inline user_statistics_result(const XblUserStatisticsResult& userStatisticsResult);\n\nprivate:\n    string_t m_xboxUserId;\n    std::vector<service_configuration_statistic> m_serviceConfigurationStatistics;\n};\n\n/// <summary>\n/// Contains requested statistics.\n/// </summary>\nclass requested_statistics\n{\npublic:\n    /// <summary>\n    /// Constructor for an RequestedStatistics object.\n    /// </summary>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statistics\">A collection of statistics.</param>\n    inline requested_statistics(\n        _In_ string_t serviceConfigurationId,\n        _In_ const std::vector<string_t>& statistics\n    );\n\n    /// <summary>\n    /// Copy Constructor for an RequestedStatistics object.\n    /// </summary>\n    inline requested_statistics(_In_ const requested_statistics& other);\n\n    /// <summary>\n    /// The service configuration ID in use.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// A collection of statistics.\n    /// </summary>\n    inline const std::vector<string_t>& statistics() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline const XblRequestedStatistics& _requested_statistics() const;\n\nprivate:\n    XblRequestedStatistics m_requestedStatistics;\n    string_t m_scid;\n    std::vector<string_t> m_statistics;\n    UTF8StringArrayRef m_statisticsC;\n};\n\n/// <summary>\n/// Contains information about a change to a subscribed statistic.\n/// </summary>\nclass statistic_change_event_args\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID used to create the subscription.\n    /// </summary> \n    inline const string_t& xbox_user_id() const;\n\n    /// <summary>\n    /// The service configuration ID used to create the subscription.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// The statistic with an updated value.\n    /// </summary>\n    inline const statistic& latest_statistic() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline statistic_change_event_args(const XblStatisticChangeEventArgs& statisticEventArgs);\n\nprivate:\n    string_t m_xboxUserId;\n    string_t m_serviceConfigurationId;\n    statistic m_statistic;\n};\n\n/// <summary>\n/// Handles notification when the state of a statistic subscription changes.\n/// </summary>\nclass statistic_change_subscription : public xbox::services::real_time_activity::real_time_activity_subscription\n{\npublic:\n    /// <summary>\n    /// The Xbox user ID used to create the subscription.\n    /// </summary>\n    inline const string_t& xbox_user_id() const;\n    \n    /// <summary>\n    /// The service config ID used to create the subscription.\n    /// </summary>\n    inline const string_t& service_configuration_id() const;\n\n    /// <summary>\n    /// The statistic the subscription is for.\n    /// </summary>\n    inline const xbox::services::user_statistics::statistic& statistic() const;\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline statistic_change_subscription(\n        _In_ string_t xboxUserId,\n        _In_ string_t serviceConfigurationId,\n        _In_ xbox::services::user_statistics::statistic newStat,\n        _In_ XblRealTimeActivitySubscriptionHandle handle\n    );\n\nprivate:\n    string_t m_xboxUserId;\n    string_t m_serviceConfigurationId;\n    xbox::services::user_statistics::statistic m_statistic;\n\n    friend class user_statistics_service;\n};\n\n/// <summary>\n/// Represents an endpoint that you can use to access the user statistic service.\n/// </summary>\nclass user_statistics_service\n{\npublic:\n    /// <summary>\n    /// Get a specified statistic for a specified user.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player to get statistics for.</param>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statisticName\">The name of the statistic to return.</param>\n    /// <returns>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The result of the asynchronous operation is the requested statistic.\n    /// </returns>\n    /// <remarks>\n    /// Calls V1 GET /users/xuid({xuid})/scids/{scid}/stats/{statname1}\n    /// </remarks>\n    inline pplx::task<xbox_live_result<user_statistics_result>> get_single_user_statistics(\n        _In_ const string_t& xboxUserId,\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& statisticName\n        );\n\n    /// <summary>\n    /// Get specified statistics for a single user.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player to get statistics for.</param>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statisticNames\">A collection of statistic names to lookup.</param>\n    /// <returns>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The result is a user_statistics_result object that contains the requested statistics.\n    /// Only statistics with values are returned. For example, if you ask for 3 statistic names and only 2 have values,\n    /// only 2 statistics are returned by the service.\n    /// </returns>\n    /// <remarks>Calls V1 GET /users/xuid({xuid})/scids/{scid}/stats/{statname1},...,{statnameN}</remarks>\n    inline pplx::task<xbox_live_result<user_statistics_result>> get_single_user_statistics(\n        _In_ const string_t& xboxUserId,\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const std::vector<string_t>& statisticNames\n        );\n\n    /// <summary>\n    /// Get statistics for multiple users.\n    /// </summary>\n    /// <param name=\"xboxUserIds\">A list of the user Xbox user IDs to get stats for.</param>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statisticNames\">A collection of statistic names to lookup.</param>\n    /// <returns>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The result is a collection of user_statistics_result objects that contain the requested statistics.\n    /// Only statistics with values are returned. For example, if you ask for 3 statistic names and only 2 have values,\n    /// only 2 statistics are returned by the service.\n    /// </returns>\n    /// <remarks>Calls V1 POST /batch</remarks>\n    inline pplx::task<xbox_live_result<std::vector<user_statistics_result>>> get_multiple_user_statistics(\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ const string_t& serviceConfigurationId,\n        _In_ std::vector<string_t>& statisticNames\n        );\n\n    /// <summary>\n    /// Get statistics for users across different Service configurations.\n    /// </summary>\n    /// <param name=\"xboxUserIds\">A list of the user Xbox user ID to get stats for.</param>\n    /// <param name=\"requestedServiceConfigurationStatisticsCollection\">A list of the service config IDs and its associated array of statistics.</param>\n    /// <returns>\n    /// Returns a concurrency::task&lt;T&gt; object that represents the state of the asynchronous operation.\n    /// The result is a collection of user_statistics_result objects that contain the requested statistics.\n    /// Only statistics with values are returned. For example, if you ask for 3 statistic names and only 2 have values,\n    /// only 2 statistics are returned by the service.\n    /// </returns>\n    /// <remarks>Calls V1 POST /batch</remarks>\n    inline pplx::task<xbox_live_result<std::vector<user_statistics_result>>> get_multiple_user_statistics_for_multiple_service_configurations(\n        _In_ const std::vector<string_t>& xboxUserIds,\n        _In_ const std::vector<requested_statistics>& requestedServiceConfigurationStatisticsCollection\n        );\n\n    /// <summary>\n    /// Subscribes to statistic update notifications via the StatisticChanged event.\n    /// </summary>\n    /// <param name=\"xboxUserId\">The Xbox User ID of the player requesting the subscription.</param>\n    /// <param name=\"serviceConfigurationId\">The service configuration ID (SCID) of the title</param>\n    /// <param name=\"statisticName\">The name of the statistic to subscribe to.</param>\n    /// <returns>A statistic_change_subscription object that contains the state of the subscription. \n    /// You can register an event handler for statistic changes by calling set_statistic_changed_handler().\n    /// </returns>\n    inline xbox_live_result<std::shared_ptr<statistic_change_subscription>> subscribe_to_statistic_change(\n        _In_ const string_t& xboxUserId,\n        _In_ const string_t& serviceConfigurationId,\n        _In_ const string_t& statisticName\n        );\n\n    /// <summary>\n    /// Unsubscribes a previously created statistic change subscription.\n    /// </summary>\n    /// <param name=\"subscription\">The subscription object to unsubscribe</param>\n    inline xbox_live_result<void> unsubscribe_from_statistic_change(\n        _In_ std::shared_ptr<statistic_change_subscription> subscription\n        );\n\n    /// <summary>\n    /// Registers an event handler for statistic change notifications.\n    /// Event handlers receive a statistic_change_event_args object.\n    /// </summary>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    inline function_context add_statistic_changed_handler(_In_ std::function<void(statistic_change_event_args)> handler);\n\n    /// <summary>\n    /// Unregisters an event handler for statistic change notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    /// <param name=\"handler\">The callback function that receives notifications.</param>\n    inline void remove_statistic_changed_handler(_In_ function_context context);\n\n    inline user_statistics_service(const user_statistics_service& other);\n    inline user_statistics_service& operator=(user_statistics_service other);\n    inline ~user_statistics_service();\n\nprivate:\n    inline user_statistics_service(_In_ XblContextHandle contextHandle);\n\n    struct HandlerContext;\n\n    XblContextHandle m_xblContext;\n\n    friend xbox_live_context;\n};\n\n}}}\n\n#include \"impl/user_statistics.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/xbox_live_app_config.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#ifdef __OBJC__\n#import <UIKit/UIKit.h>\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n/// <summary>\n/// Represents the configuration of an Xbox Live application.\n/// </summary>\nclass xbox_live_app_config\n{\npublic:\n    /// <summary>\n    /// Gets the app config singleton.\n    /// </summary>\n    inline static std::shared_ptr<xbox_live_app_config> get_app_config_singleton();\n\n    /// <summary>\n    /// Returns the title id of the app.\n    /// </summary>\n    inline uint32_t title_id() const;\n\n    /// <summary>\n    /// Returns the service config id of the app.\n    /// </summary>\n    inline string_t scid() const;\n\n    /// <summary>\n    /// Returns the Xbox Live environment being used, it is empty before you sign in or using production.\n    /// </summary>\n    _XSAPICPP_DEPRECATED inline string_t environment() const;\n\n    /// <summary>\n    /// Returns the sandbox such as \"XDKS.1\", it is empty until you sign in.\n    /// </summary>\n    inline string_t sandbox() const;\n    \nprivate:\n    xbox_live_app_config() = default;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/xbox_live_app_config.hpp\"\n"
  },
  {
    "path": "Include/xsapi-cpp/xbox_live_context.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#if !XSAPI_NO_PPL\n\n#include \"xsapi-cpp/system.h\"\n#include \"xsapi-cpp/multiplayer.h\"\n#include \"xsapi-cpp/title_storage.h\"\n#include \"xsapi-cpp/profile.h\"\n#include \"xsapi-cpp/privacy.h\"\n#include \"xsapi-cpp/leaderboard.h\"\n#include \"xsapi-cpp/social.h\"\n#include \"xsapi-cpp/presence.h\"\n#include \"xsapi-cpp/achievements.h\"\n#include \"xsapi-cpp/matchmaking.h\"\n#include \"xsapi-cpp/user_statistics.h\"\n#include \"xsapi-cpp/string_verify.h\"\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#include \"xsapi-cpp/notification_service.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n/// <summary>\n/// Defines pointers to objects that access Xbox Live to create features for player \n/// interactions.\n///\n/// Note: the XboxLiveContext is unique per instance. Changing state on one instance for a \n/// user does not affect a second instance of the context for the same user. Using multiple\n/// instances can therefore result in unexpected behavior. Titles should ensure to only use \n/// one instance of the XboxLiveContext per user.\n/// </summary>\nclass xbox_live_context\n{\npublic:\n    /// <summary>\n    /// Creates an xbox_live_context from a xbox_live_user\n    /// </summary>\n    inline xbox_live_context(\n        _In_ XblUserHandle user\n    );\n\n    /// <summary>\n    /// Returns the associated system User.\n    /// </summary>\n    inline XblUserHandle user();\n\n    /// <summary>\n    /// Returns a copy of the associated Xbox Live context handle.\n    /// </summary>\n    /// <remarks>\n    /// It is the caller's responsibility to close the returned handle.\n    /// </remarks>\n    inline XblContextHandle handle();\n\n    /// <summary>\n    /// Returns the current user's Xbox Live User ID.\n    /// </summary>\n    inline string_t xbox_live_user_id();\n\n    /// <summary>\n    /// Returns an object containing settings that apply to all REST calls made such as retry and diagnostic settings.\n    /// </summary>\n    inline std::shared_ptr<xbox_live_context_settings> settings();\n\n    /// <summary>\n    /// Returns an object containing Xbox Live app config such as title ID\n    /// </summary>\n    inline std::shared_ptr<xbox_live_app_config> application_config();\n\n    /// <summary>\n    /// A service for storing data in the cloud.\n    /// </summary>\n    inline title_storage::title_storage_service title_storage_service();\n\n    /// <summary>\n    /// A service for managing user profiles.\n    /// </summary>\n    inline social::profile_service profile_service();\n\n    /// <summary>\n    /// A service for managing privacy settings.\n    /// </summary>\n    inline privacy::privacy_service privacy_service();\n\n#if !defined(XBOX_LIVE_CREATORS_SDK)\n    /// <summary>\n    /// A service for managing leaderboards.\n    /// </summary>\n    inline leaderboard::leaderboard_service leaderboard_service();\n\n    /// <summary>\n    /// A service for managing social networking links.\n    /// </summary>\n    inline social::social_service social_service();\n\n    /// <summary>\n    /// A service for managing reputation reports.\n    /// </summary>\n    inline social::reputation_service reputation_service();\n\n    /// <summary>\n    /// A service for managing achievements.\n    /// </summary>\n    inline achievements::achievement_service achievement_service();\n\n    /// <summary>\n    /// A service for managing user statistics.\n    /// </summary>\n    inline user_statistics::user_statistics_service user_statistics_service();\n\n    /// <summary>\n    /// A service for managing multiplayer games.\n    /// </summary>\n    inline multiplayer::multiplayer_service multiplayer_service();\n\n    /// <summary>\n    /// A service for managing matchmaking sessions.\n    /// </summary>\n    inline matchmaking::matchmaking_service matchmaking_service();\n\n    /// <summary>\n    /// A service for managing real-time activity.\n    /// </summary>\n    inline std::shared_ptr<real_time_activity::real_time_activity_service> real_time_activity_service();\n\n    /// <summary>\n    /// A service used to check for offensive strings.\n    /// </summary>\n    inline system::string_service string_service();\n\n    /// <summary>\n    /// A service for managing Rich Presence.\n    /// </summary>\n    inline presence::presence_service presence_service();\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\n    /// <summary>\n    /// A service for receiving notifications.\n    /// </summary>\n    inline std::shared_ptr<notification::notification_service> notification_service();\n#endif\n\n#ifdef XSAPI_EVENTS_SERVICE\n    /// <summary>\n    /// A service used to write in game events.\n    /// </summary>\n    inline events::events_service events_service();\n#endif // !XDK_API && !XSAPI_UNIT_TESTS\n\n#endif // !defined(XBOX_LIVE_CREATORS_SDK)\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline xbox_live_context(_In_ XblContextHandle xboxLiveContextHandle);\n    inline ~xbox_live_context();\n\nprivate:\n    XblContextHandle m_handle = nullptr;\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\n    std::shared_ptr <notification::notification_service> m_notificationService;\n#endif\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#endif\n\n#if !XSAPI_NO_PPL\n#include \"impl/xbox_live_context.hpp\"\n#endif"
  },
  {
    "path": "Include/xsapi-cpp/xbox_live_context_settings.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <chrono>\n#include <functional>\n#include <mutex>\n#include <unordered_map>\n#include \"xsapi-cpp/xbox_service_call_routed_event_args.h\"\n#include \"xsapi-c/xbox_live_context_c.h\"\n#include \"xsapi-c/xbox_live_context_settings_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\nclass http_call;\n\n/// <summary>\n/// Enumeration values that indicate the trace levels of debug output for service diagnostics.\n///\n/// Setting the debug trace level to error or higher reports the last HRESULT, the current\n/// function, the source file, and the line number for many trace points in the Xbox live code.\n/// </summary>\nenum class xbox_services_diagnostics_trace_level\n{\n    /// <summary>\n    /// Output no tracing and debugging messages.\n    /// </summary>\n    off,\n\n    /// <summary>\n    /// Output error-handling messages.\n    /// </summary>\n    error,\n\n    /// <summary>\n    /// Output warnings and error-handling messages.\n    /// </summary>\n    warning,\n\n    /// <summary>\n    /// Output informational messages, warnings, and error-handling messages.\n    /// </summary>\n    info,\n\n    /// <summary>\n    /// Output all debugging and tracing messages.\n    /// </summary>\n    verbose\n};\n\n/// <summary>\n/// Enum used with disable_asserts_for_xbox_live_throttling_in_dev_sandboxes()\n/// </summary>\nenum class xbox_live_context_throttle_setting\n{\n    /// <summary>\n    /// Passed to xboxLiveContext->settings()->disable_asserts_for_xbox_live_throttling_in_dev_sandboxes()\n    /// to warn code reviewers that there's an outstanding Xbox Live calling pattern issue that needs to be addressed.\n    /// </summary>\n    this_code_needs_to_be_changed_to_avoid_throttling\n};\n\n/// <summary>\n/// Enum used with disable_asserts_ APIs\n/// </summary>\nenum class xbox_live_context_recommended_setting\n{\n    /// <summary>\n    /// Passed to xboxLiveContext->settings()->disable_asserts_ APIs\n    /// to warn code reviewers that there's an outstanding calling pattern issue that needs to be addressed.\n    /// </summary>\n    this_code_needs_to_be_changed_to_follow_best_practices\n};\n\n/// <summary>\n/// Represents settings for an HTTP call.\n/// </summary>\nclass xbox_live_context_settings\n{\npublic:\n    inline xbox_live_context_settings(XblContextHandle xblContextHandle);\n    inline ~xbox_live_context_settings();\n\n    /// <summary>\n    /// Registers for all service call notifications.  Event handlers will receive xbox::services::xbox_service_call_routed_event_args\n    /// </summary>\n    /// <param name=\"handler\">The event handler function to call.</param>\n    /// <returns>\n    /// A function_context object that can be used to unregister the event handler.\n    /// </returns>\n    inline function_context add_service_call_routed_handler(_In_ std::function<void(const xbox::services::xbox_service_call_routed_event_args&)> handler);\n\n    /// <summary>\n    /// Unregisters from all service call notifications.\n    /// </summary>\n    /// <param name=\"context\">The function_context object that was returned when the event handler was registered. </param>\n    inline void remove_service_call_routed_handler(_In_ function_context context);\n\n    /// <summary>\n    /// Gets the connect, send, and receive timeouts for HTTP socket operations of long calls such as Title Storage calls.\n    /// Default is 5 minutes.  Calls that take longer than this are aborted.    \n    /// </summary>\n    inline std::chrono::seconds long_http_timeout() const;\n\n    /// <summary>\n    /// Sets the connect, send, and receive timeouts for HTTP socket operations of long calls such as Title Storage calls.\n    /// Default is 5 minutes.  Calls that take longer than this are aborted.\n    /// Take care when setting this to smaller values as some calls like Title Storage may take a few minutes to complete.\n    /// </summary>\n    inline void set_long_http_timeout(_In_ std::chrono::seconds value);\n\n    /// <summary>\n    /// Gets the HTTP retry delay in seconds.\n    ///\n    /// Retries are delayed using an exponential back off.  By default, it will delay 2 seconds then the \n    /// next retry will delay 4 seconds, then 8 seconds, and so on up to a max of 1 min until either\n    /// the call succeeds or the http_timeout_window is reached, at which point the call will fail.\n    /// The delay is also jittered between the current and next delay to spread out service load.\n    /// The default for http_timeout_window is 20 seconds and can be changed using set_http_timeout_window()\n    /// \n    /// If the service returns an HTTP error with a \"Retry-After\" header, then all future calls to that API \n    /// will immediately fail with the original error without contacting the service until the \"Retry-After\" \n    /// time has been reached.\n    ///\n    /// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:\n    /// 408 (Request Timeout)\n    /// 429 (Too Many Requests)\n    /// 500 (Internal Server Error)\n    /// 502 (Bad Gateway)\n    /// 503 (Service Unavailable)\n    /// 504 (Gateway Timeout)\n    /// </summary>\n    inline std::chrono::seconds http_retry_delay() const;\n\n    /// <summary>\n    /// Sets the HTTP retry delay in seconds. The default and minimum delay is 2 seconds.\n    /// \n    /// Retries are delayed using an exponential back off.  By default, it will delay 2 seconds then the \n    /// next retry will delay 4 seconds, then 8 seconds, and so on up to a max of 1 min until either\n    /// the call succeeds or the http_timeout_window is reached, at which point the call will fail.\n    /// The delay is also jittered between the current and next delay to spread out service load.\n    /// The default for http_timeout_window is 20 seconds and can be changed using set_http_timeout_window()\n    /// \n    /// If the service returns an HTTP error with a \"Retry-After\" header, then all future calls to that API \n    /// will immediately fail with the original error without contacting the service until the \"Retry-After\" \n    /// time has been reached.\n    ///\n    /// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:\n    /// 408 (Request Timeout)\n    /// 429 (Too Many Requests)\n    /// 500 (Internal Server Error)\n    /// 502 (Bad Gateway)\n    /// 503 (Service Unavailable)\n    /// 504 (Gateway Timeout)\n    /// </summary>\n    inline void set_http_retry_delay(_In_ std::chrono::seconds value);\n\n    /// <summary>\n    /// Gets the HTTP timeout window in seconds.\n    ///\n    /// This controls how long to spend attempting to retry idempotent service calls before failing.\n    /// The default is 20 seconds\n    ///\n    /// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:\n    /// 408 (Request Timeout)\n    /// 429 (Too Many Requests)\n    /// 500 (Internal Server Error)\n    /// 502 (Bad Gateway)\n    /// 503 (Service Unavailable)\n    /// 504 (Gateway Timeout)\n    /// </summary>\n    inline std::chrono::seconds http_timeout_window() const;\n\n    /// <summary>\n    /// Sets the HTTP timeout window in seconds.\n    ///\n    /// This controls how long to spend attempting to retry idempotent service calls before failing.\n    /// The default is 20 seconds.  Set to 0 to turn off retry.\n    ///\n    /// Idempotent service calls are retried when a network error occurs or the server responds with one of these HTTP status codes:\n    /// 408 (Request Timeout)\n    /// 429 (Too Many Requests)\n    /// 500 (Internal Server Error)\n    /// 502 (Bad Gateway)\n    /// 503 (Service Unavailable)\n    /// 504 (Gateway Timeout)\n    /// </summary>\n    inline void set_http_timeout_window(_In_ std::chrono::seconds value);\n\n    /// <summary>\n    /// Gets the web socket timeout window in seconds.\n    /// </summary>\n    inline std::chrono::seconds websocket_timeout_window() const;\n\n    /// <summary>\n    /// Sets the web socket timeout window in seconds.\n    /// Controls how long to spend attempting to retry establishing a websocket connection before failing. \n    /// Default is 300 seconds.  Set to 0 to turn off retry.\n    /// </summary>\n    inline void set_websocket_timeout_window(_In_ std::chrono::seconds value);\n\n    /// <summary>\n    /// Gets whether to use the dispatcher for event routing\n    /// </summary>\n    inline bool use_core_dispatcher_for_event_routing() const;\n\n    /// <summary>\n    /// Controls whether to use the CoreDispatcher from the User object to route events through. \n    /// This is required to be true if using events with JavaScript.\n    /// </summary>\n    inline void set_use_core_dispatcher_for_event_routing(_In_ bool value);\n\n    /// <summary>\n    /// Disables asserts for Xbox Live throttling in dev sandboxes.\n    /// The asserts will not fire in RETAIL sandbox, and this setting has no affect in RETAIL sandboxes.\n    /// It is best practice to not call this API, and instead adjust the calling pattern but this is provided\n    /// as a temporary way to get unblocked while in early stages of game development.\n    /// </summary>\n    inline void disable_asserts_for_xbox_live_throttling_in_dev_sandboxes(\n        _In_ xbox_live_context_throttle_setting setting\n        );\n\n    /// <summary>\n    /// Disables asserts for having maximum number of websockets being activated \n    /// i.e. MAXIMUM_WEBSOCKETS_ACTIVATIONS_ALLOWED_PER_USER (5) per user per title instance.\n    /// It is best practice to not call this API, and instead adjust the calling pattern but this is provided\n    /// as a temporary way to get unblocked while in early stages of game development.\n    /// </summary>\n    inline void disable_asserts_for_maximum_number_of_websockets_activated(\n        _In_ xbox_live_context_recommended_setting setting\n        );\n\n    /// <summary>\n    /// Gets whether to use the xplatqos server for qos calls.\n    /// </summary>\n    inline bool use_crossplatform_qos_servers() const;\n\n    /// <summary>\n    /// Controls whether we use cross platform qos endpoints or not.\n    /// In some case if you are shipping with TV_API enabled, you want to be able to choose.\n    /// </summary>\n    inline void set_use_crossplatform_qos_servers(_In_ bool value);\n\npublic:\n#ifdef XSAPI_UNIT_TESTS\n    XblContextHandle XboxLiveContextHandle()\n    {\n        return m_xblContextHandle;\n    }\n#endif\n\nprivate:\n    XblContextHandle m_xblContextHandle;\n    struct HandlerContext;\n\n    friend std::shared_ptr<http_call> create_xbox_live_http_call(\n        _In_ const std::shared_ptr<xbox_live_context_settings>& xboxLiveContextSettings,\n        _In_ const string_t& httpMethod,\n        _In_ const string_t& serverName,\n        _In_ const web::uri& pathQueryFragment\n    );\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/xbox_live_context_settings.hpp\""
  },
  {
    "path": "Include/xsapi-cpp/xbox_service_call_routed_event_args.h",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xsapi-cpp/http_call_request_message.h\"\n#include \"xsapi-c/xbox_live_context_settings_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n/// <summary>\n/// Contains information about a service call.\n/// </summary>\nclass xbox_service_call_routed_event_args\n{\npublic:\n\n    /// <summary>\n    /// Returns the XboxUserId of the User contacting the service\n    /// </summary>\n    inline string_t xbox_user_id() const;\n\n    /// <summary>\n    /// Returns the HTTP method used to contact the service.  For example, \"GET\".\n    /// </summary>\n    inline string_t http_method() const;\n\n    /// <summary>\n    /// Returns the URI used to contact the service.\n    /// </summary>\n    inline string_t uri() const;\n\n    /// <summary>\n    /// Returns the request headers that were sent to the service.\n    /// </summary>\n    inline string_t request_headers() const;\n\n    /// <summary>\n    /// Returns the request body that was sent to the service.\n    /// </summary>\n    inline http_call_request_message request_body() const;\n\n    /// <summary>\n    /// Returns the number of responses in this session.\n    /// </summary>\n    inline uint32_t response_count() const;\n\n    /// <summary>\n    /// Returns the response headers returned by the service.\n    /// </summary>\n    inline string_t response_headers() const;\n\n    /// <summary>\n    /// Returns the response body returned by the service.\n    /// </summary>\n    inline string_t response_body() const;\n\n    /// <summary>\n    /// Returns the ETag returned by the service.\n    /// </summary>\n    inline string_t etag() const;\n\n    /// <summary>\n    /// Returns the authentication token returned by GetTokenAndSignatureAsync.\n    /// </summary>\n    inline string_t token() const;\n\n    /// <summary>\n    /// Returns the authentication signature returned by GetTokenAndSignatureAsync.\n    /// </summary>\n    inline string_t signature() const;\n\n    /// <summary>\n    /// Returns the HTTP status code. For example, 200.\n    /// </summary>\n    inline uint32_t http_status() const;\n\n    /// <summary>\n    /// Returns the a full response log formatted message of all the properties in xbox_service_call_routed_event_args.\n    /// </summary>\n    inline const string_t& full_response_formatted() const;\n\n    /// <summary>\n    /// Returns the  time when the request was sent.\n    /// </summary>\n    inline chrono_clock_t::time_point request_time() const;\n\n    /// <summary>\n    /// Returns the  time when the response was received.\n    /// </summary>\n    inline chrono_clock_t::time_point response_time() const;\n\n    /// <summary>\n    /// Returns the elapsed time span between sending a request and receiving a response.\n    /// </summary>\n    inline std::chrono::milliseconds elapsed_call_time() const;\n\n    inline xbox_service_call_routed_event_args(\n        _In_ const XblServiceCallRoutedArgs& internalArgs\n    );\n\n    inline ~xbox_service_call_routed_event_args();\n    inline xbox_service_call_routed_event_args(const xbox_service_call_routed_event_args& other);\n    inline xbox_service_call_routed_event_args& operator=(xbox_service_call_routed_event_args other);\n\nprivate:\n    HCCallHandle m_callHandle{ nullptr };\n    long m_responseCount{ 0 };\n    string_t m_fullResponseFormatted;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n#include \"impl/xbox_service_call_routed_event_args.hpp\""
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) Microsoft Corporation\n\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "LINKTOSOURCE.md",
    "content": "## How to link your project against source\n\nYou might want to link against the XSAPI source if you want to debug an issue, or understand where an error code is coming from.  \n\nJump to the guide that matches the platform and API type you are using:\n- [How to link against the C GDK source](LINKTOSOURCE.md#how-to-link-against-the-xsapi-gdk-source)\n\n### How to link against the XSAPI GDK source\n\n- In Visual Studio, choose \"File->Add->Existing Project...\" in Visual Studio to add the following projects to your application's solution. The project paths below are relative to the SDK source root.\n\nFor Visual Studio 2017:\n```\n  \\Build\\Microsoft.Xbox.Services.141.GDK.C\\Microsoft.Xbox.Services.141.GDK.C.vcxproj\n  \\External\\xal\\External\\libHttpClient\\Build\\libHttpClient.141.GDK.C\\libHttpClient.141.GDK.C.vcxproj\n```\n\nFor Visual Studio 2019:\n```\n  \\Build\\Microsoft.Xbox.Services.142.GDK.C\\Microsoft.Xbox.Services.142.GDK.C.vcxproj\n  \\External\\xal\\External\\libHttpClient\\Build\\libHttpClient.142.GDK.C\\libHttpClient.142.GDK.C.vcxproj\n```\n\n- Add the XSAPI props file to your project by clicking \"View->Other Windows->Property Manager\", right clicking on your project, selecting \"Add Existing Property Sheet\", then finally selecting the xsapi.staticlib.props file in the SDK source root. This will automatically update your projects XSAPI header include paths, add references to the relevant XSAPI projects, and prevent your project from linking with the installed GDK binaries.\n\n- Rebuild your Visual Studio solution. Note that in some cases the XSAPI project references won't be fully added until you reload your project after adding the XSAPI property sheet.\n\n\n\n"
  },
  {
    "path": "Microsoft.Xbox.Services.GDK.VS2017.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.6.33829.357\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"GDK\", \"GDK\", \"{C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"APIExplorer.Shared\", \"Tests\\APIExplorer\\APIExplorer.Shared.vcxitems\", \"{CBC0BEC4-131D-4868-9345-71813557FB39}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{DC381015-B171-4DA5-B7FA-7CDE8196C6D3}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.141.GDK.C\", \"Build\\Microsoft.Xbox.Services.141.GDK.C\\Microsoft.Xbox.Services.141.GDK.C.vcxproj\", \"{60139F62-BF37-4F11-BD93-5FBF4E92100C}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.141.GDK.C.Thunks\", \"Build\\Microsoft.Xbox.Services.141.GDK.C.Thunks\\Microsoft.Xbox.Services.141.GDK.C.Thunks.vcxproj\", \"{E538394B-68CB-4597-87AD-7B6841CC1278}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"DirectXTK12\", \"Tests\\GDK\\APIRunner.GDK\\Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\", \"{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"APIRunner.GDK.Src\", \"Tests\\GDK\\APIRunner.GDK\\APIRunner.GDK.Src.vcxproj\", \"{46F31A54-4C74-41A8-B294-26B5689E51EF}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ThunksGenerator\", \"Build\\Microsoft.Xbox.Services.141.GDK.C.Thunks\\generator\\ThunksGenerator\\ThunksGenerator.csproj\", \"{21C651D1-61D7-46C5-BD23-128E40329AA5}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libHttpClient.GDK\", \"External\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK\\libHttpClient.GDK.vcxproj\", \"{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Props\", \"Props\", \"{901F04C7-6EC2-4641-90E7-54D2F72DF570}\"\n\tProjectSection(SolutionItems) = preProject\n\t\thc_settings.props = hc_settings.props\n\t\tExternal\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props = External\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props\n\t\tExternal\\xal\\External\\libHttpClient\\libHttpClient.props = External\\xal\\External\\libHttpClient\\libHttpClient.props\n\t\tExternal\\xal\\External\\libHttpClient\\platform_select.props = External\\xal\\External\\libHttpClient\\platform_select.props\n\t\tBuild\\xsapi.gdk.bwoi.props = Build\\xsapi.gdk.bwoi.props\n\t\tBuild\\xsapi.gdk.props = Build\\xsapi.gdk.props\n\t\txsapi.paths.props = xsapi.paths.props\n\t\txsapi.staticlib.props = xsapi.staticlib.props\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.Common\", \"Build\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems\", \"{CF3350E5-00A2-4647-A996-BAF7542B0327}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.GDK\", \"Build\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems\", \"{1E320494-894E-4FEB-90CA-DF4FE20499F4}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Common\", \"Common\", \"{81806275-2461-4CB7-935A-7EFEC3488A86}\"\nEndProject\nGlobal\n\tGlobalSection(SharedMSBuildProjectFiles) = preSolution\n\t\tBuild\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems*{1e320494-894e-4feb-90ca-df4fe20499f4}*SharedItemsImports = 9\n\t\tTests\\APIExplorer\\APIExplorer.Shared.vcxitems*{46f31a54-4c74-41a8-b294-26b5689e51ef}*SharedItemsImports = 4\n\t\tBuild\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems*{60139f62-bf37-4f11-bd93-5fbf4e92100c}*SharedItemsImports = 4\n\t\tBuild\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems*{60139f62-bf37-4f11-bd93-5fbf4e92100c}*SharedItemsImports = 4\n\t\tExternal\\xal\\External\\libHttpClient\\Build\\libHttpClient.Common\\libHttpClient.Common.vcxitems*{a5a6e02a-21ba-4d55-9fb9-7b24dedd3743}*SharedItemsImports = 4\n\t\tExternal\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.Shared\\libHttpClient.GDK.Shared.vcxitems*{a5a6e02a-21ba-4d55-9fb9-7b24dedd3743}*SharedItemsImports = 4\n\t\tTests\\APIExplorer\\APIExplorer.Shared.vcxitems*{cbc0bec4-131d-4868-9345-71813557fb39}*SharedItemsImports = 9\n\t\tBuild\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems*{cf3350e5-00a2-4647-a996-baf7542b0327}*SharedItemsImports = 9\n\tEndGlobalSection\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|ARM = Debug|ARM\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|Gaming.Desktop.x64 = Debug|Gaming.Desktop.x64\n\t\tDebug|Gaming.Xbox.Scarlett.x64 = Debug|Gaming.Xbox.Scarlett.x64\n\t\tDebug|Gaming.Xbox.XboxOne.x64 = Debug|Gaming.Xbox.XboxOne.x64\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|ARM = Release|ARM\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|Gaming.Desktop.x64 = Release|Gaming.Desktop.x64\n\t\tRelease|Gaming.Xbox.Scarlett.x64 = Release|Gaming.Xbox.Scarlett.x64\n\t\tRelease|Gaming.Xbox.XboxOne.x64 = Release|Gaming.Xbox.XboxOne.x64\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|ARM.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|ARM64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|x86.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|ARM.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|ARM64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|x86.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|ARM.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|ARM64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Debug|x86.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|ARM.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|ARM64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278}.Release|x86.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|ARM.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|ARM64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|x86.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Any CPU.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|ARM.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|ARM64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|x86.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|ARM.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|ARM64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Desktop.x64.Deploy.0 = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.Scarlett.x64.Deploy.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.XboxOne.x64.Deploy.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|x86.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|ARM.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|ARM64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Desktop.x64.Deploy.0 = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.Scarlett.x64.Deploy.0 = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.XboxOne.x64.Deploy.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|x86.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|ARM.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|ARM.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|ARM64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|ARM64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|ARM.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|ARM.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|ARM64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|ARM64.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|x64.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|ARM.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|ARM64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|x86.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|ARM.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|ARM64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|x86.ActiveCfg = Release|Gaming.Desktop.x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{CBC0BEC4-131D-4868-9345-71813557FB39} = {81806275-2461-4CB7-935A-7EFEC3488A86}\n\t\t{DC381015-B171-4DA5-B7FA-7CDE8196C6D3} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{E538394B-68CB-4597-87AD-7B6841CC1278} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2} = {DC381015-B171-4DA5-B7FA-7CDE8196C6D3}\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF} = {DC381015-B171-4DA5-B7FA-7CDE8196C6D3}\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{CF3350E5-00A2-4647-A996-BAF7542B0327} = {81806275-2461-4CB7-935A-7EFEC3488A86}\n\t\t{1E320494-894E-4FEB-90CA-DF4FE20499F4} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {622BB9B5-938F-41A2-BC8B-B7B3A64A73B5}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Microsoft.Xbox.Services.GDK.VS2019.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.6.33829.357\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"GDK\", \"GDK\", \"{165723E8-FF20-4427-A84B-68E05765C9AC}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.142.GDK.C\", \"Build\\Microsoft.Xbox.Services.142.GDK.C\\Microsoft.Xbox.Services.142.GDK.C.vcxproj\", \"{60139F62-BF37-4F11-BD93-5FBF4E92100C}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libHttpClient.GDK\", \"External\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK\\libHttpClient.GDK.vcxproj\", \"{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.GDK\", \"Build\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems\", \"{1E320494-894E-4FEB-90CA-DF4FE20499F4}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Props\", \"Props\", \"{68CC03E1-1625-450A-B3EF-AC356E5F5A69}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tExternal\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props = External\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props\n\t\tExternal\\xal\\External\\libHttpClient\\Build\\libHttpClient.paths.props = External\\xal\\External\\libHttpClient\\Build\\libHttpClient.paths.props\n\t\tExternal\\xal\\External\\libHttpClient\\libHttpClient.props = External\\xal\\External\\libHttpClient\\libHttpClient.props\n\t\tExternal\\xal\\External\\libHttpClient\\platform_select.props = External\\xal\\External\\libHttpClient\\platform_select.props\n\t\tBuild\\xsapi.gdk.bwoi.props = Build\\xsapi.gdk.bwoi.props\n\t\tBuild\\xsapi.gdk.props = Build\\xsapi.gdk.props\n\t\txsapi.paths.props = xsapi.paths.props\n\t\txsapi.staticlib.props = xsapi.staticlib.props\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Common\", \"Common\", \"{8280F3FB-83FF-4351-A5F3-55E806F4D2D8}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.Common\", \"Build\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems\", \"{CF3350E5-00A2-4647-A996-BAF7542B0327}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.GDK.C.Thunks\", \"Build\\Microsoft.Xbox.Services.GDK.C.Thunks\\Microsoft.Xbox.Services.GDK.C.Thunks.vcxproj\", \"{6AA78AA9-78A5-40C0-828F-5933AF847111}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ThunksGenerator\", \"Build\\Microsoft.Xbox.Services.GDK.C.Thunks\\generator\\ThunksGenerator\\ThunksGenerator.csproj\", \"{21C651D1-61D7-46C5-BD23-128E40329AA5}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|Gaming.Desktop.x64 = Debug|Gaming.Desktop.x64\n\t\tDebug|Gaming.Xbox.Scarlett.x64 = Debug|Gaming.Xbox.Scarlett.x64\n\t\tDebug|Gaming.Xbox.XboxOne.x64 = Debug|Gaming.Xbox.XboxOne.x64\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|Gaming.Desktop.x64 = Release|Gaming.Desktop.x64\n\t\tRelease|Gaming.Xbox.Scarlett.x64 = Release|Gaming.Xbox.Scarlett.x64\n\t\tRelease|Gaming.Xbox.XboxOne.x64 = Release|Gaming.Xbox.XboxOne.x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Any CPU.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Any CPU.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Any CPU.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Any CPU.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Any CPU.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Any CPU.Build.0 = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Desktop.x64.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Any CPU\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C} = {165723E8-FF20-4427-A84B-68E05765C9AC}\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743} = {165723E8-FF20-4427-A84B-68E05765C9AC}\n\t\t{1E320494-894E-4FEB-90CA-DF4FE20499F4} = {165723E8-FF20-4427-A84B-68E05765C9AC}\n\t\t{CF3350E5-00A2-4647-A996-BAF7542B0327} = {8280F3FB-83FF-4351-A5F3-55E806F4D2D8}\n\t\t{6AA78AA9-78A5-40C0-828F-5933AF847111} = {165723E8-FF20-4427-A84B-68E05765C9AC}\n\t\t{21C651D1-61D7-46C5-BD23-128E40329AA5} = {165723E8-FF20-4427-A84B-68E05765C9AC}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {AB434E05-34C8-4B45-BE86-E363CCF8DD76}\n\tEndGlobalSection\n\tGlobalSection(SharedMSBuildProjectFiles) = preSolution\n\t\tBuild\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems*{1e320494-894e-4feb-90ca-df4fe20499f4}*SharedItemsImports = 9\n\t\tBuild\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems*{60139f62-bf37-4f11-bd93-5fbf4e92100c}*SharedItemsImports = 4\n\t\tBuild\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems*{60139f62-bf37-4f11-bd93-5fbf4e92100c}*SharedItemsImports = 4\n\t\tExternal\\Xal\\External\\libHttpClient\\Build\\libHttpClient.Common\\libHttpClient.Common.vcxitems*{a5a6e02a-21ba-4d55-9fb9-7b24dedd3743}*SharedItemsImports = 4\n\t\tExternal\\Xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.Shared\\libHttpClient.GDK.Shared.vcxitems*{a5a6e02a-21ba-4d55-9fb9-7b24dedd3743}*SharedItemsImports = 4\n\t\tBuild\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems*{cf3350e5-00a2-4647-a996-baf7542b0327}*SharedItemsImports = 9\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Microsoft.Xbox.Services.GDK.VS2022.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.6.33829.357\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"GDK\", \"GDK\", \"{C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"APIExplorer.Shared\", \"Tests\\APIExplorer\\APIExplorer.Shared.vcxitems\", \"{CBC0BEC4-131D-4868-9345-71813557FB39}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{DC381015-B171-4DA5-B7FA-7CDE8196C6D3}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.142.GDK.C\", \"Build\\Microsoft.Xbox.Services.142.GDK.C\\Microsoft.Xbox.Services.142.GDK.C.vcxproj\", \"{60139F62-BF37-4F11-BD93-5FBF4E92100C}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"DirectXTK12\", \"Tests\\GDK\\APIRunner.GDK\\Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\", \"{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"APIRunner.143.GDK.Src\", \"Tests\\GDK\\APIRunner.GDK\\APIRunner.143.GDK.Src.vcxproj\", \"{46F31A54-4C74-41A8-B294-26B5689E51EF}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Props\", \"Props\", \"{E10FED00-36AB-4B26-8945-3E7D996C955C}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tExternal\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props = External\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.props\n\t\tExternal\\xal\\External\\libHttpClient\\libHttpClient.props = External\\xal\\External\\libHttpClient\\libHttpClient.props\n\t\tExternal\\xal\\External\\libHttpClient\\platform_select.props = External\\xal\\External\\libHttpClient\\platform_select.props\n\t\tBuild\\xsapi.gdk.bwoi.props = Build\\xsapi.gdk.bwoi.props\n\t\tBuild\\xsapi.gdk.props = Build\\xsapi.gdk.props\n\t\txsapi.paths.props = xsapi.paths.props\n\t\txsapi.staticlib.props = xsapi.staticlib.props\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"libHttpClient.GDK\", \"External\\xal\\External\\libHttpClient\\Build\\libHttpClient.GDK\\libHttpClient.GDK.vcxproj\", \"{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.GDK\", \"Build\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems\", \"{1E320494-894E-4FEB-90CA-DF4FE20499F4}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.Xbox.Services.Common\", \"Build\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems\", \"{CF3350E5-00A2-4647-A996-BAF7542B0327}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Common\", \"Common\", \"{E4213904-77D5-4847-B858-0938BF96064C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|ARM = Debug|ARM\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|Gaming.Desktop.x64 = Debug|Gaming.Desktop.x64\n\t\tDebug|Gaming.Xbox.Scarlett.x64 = Debug|Gaming.Xbox.Scarlett.x64\n\t\tDebug|Gaming.Xbox.XboxOne.x64 = Debug|Gaming.Xbox.XboxOne.x64\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tProfile|Any CPU = Profile|Any CPU\n\t\tProfile|ARM = Profile|ARM\n\t\tProfile|ARM64 = Profile|ARM64\n\t\tProfile|Gaming.Desktop.x64 = Profile|Gaming.Desktop.x64\n\t\tProfile|Gaming.Xbox.Scarlett.x64 = Profile|Gaming.Xbox.Scarlett.x64\n\t\tProfile|Gaming.Xbox.XboxOne.x64 = Profile|Gaming.Xbox.XboxOne.x64\n\t\tProfile|x64 = Profile|x64\n\t\tProfile|x86 = Profile|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|ARM = Release|ARM\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|Gaming.Desktop.x64 = Release|Gaming.Desktop.x64\n\t\tRelease|Gaming.Xbox.Scarlett.x64 = Release|Gaming.Xbox.Scarlett.x64\n\t\tRelease|Gaming.Xbox.XboxOne.x64 = Release|Gaming.Xbox.XboxOne.x64\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|ARM.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|ARM64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Debug|x86.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Any CPU.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|ARM.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|ARM.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|ARM64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|ARM64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|x86.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Profile|x86.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|ARM.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|ARM64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C}.Release|x86.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|ARM.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|ARM64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|x86.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Any CPU.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|ARM.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|ARM64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Desktop.x64.ActiveCfg = Profile|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Desktop.x64.Build.0 = Profile|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|x86.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Any CPU.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|ARM.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|ARM64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|x86.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|ARM.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|ARM64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Desktop.x64.Deploy.0 = Debug|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.Scarlett.x64.Deploy.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|Gaming.Xbox.XboxOne.x64.Deploy.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Debug|x86.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Any CPU.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|ARM.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|ARM64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Desktop.x64.ActiveCfg = Profile|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Desktop.x64.Build.0 = Profile|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Desktop.x64.Deploy.0 = Profile|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Xbox.Scarlett.x64.Deploy.0 = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|Gaming.Xbox.XboxOne.x64.Deploy.0 = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Profile|x86.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Any CPU.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|ARM.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|ARM64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Desktop.x64.Deploy.0 = Release|Gaming.Desktop.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.Scarlett.x64.Deploy.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|Gaming.Xbox.XboxOne.x64.Deploy.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF}.Release|x86.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Any CPU.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|ARM.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|ARM.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|ARM64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|ARM64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|x86.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Debug|x86.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Any CPU.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Any CPU.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|ARM.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|ARM.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|ARM64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|ARM64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|x86.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Profile|x86.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Any CPU.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Any CPU.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|ARM.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|ARM.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|ARM64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|ARM64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|x86.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743}.Release|x86.Build.0 = Release|Gaming.Desktop.x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{CBC0BEC4-131D-4868-9345-71813557FB39} = {E4213904-77D5-4847-B858-0938BF96064C}\n\t\t{DC381015-B171-4DA5-B7FA-7CDE8196C6D3} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{60139F62-BF37-4F11-BD93-5FBF4E92100C} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{052C4858-C76F-4CEA-8A1A-E8E5559E67C2} = {DC381015-B171-4DA5-B7FA-7CDE8196C6D3}\n\t\t{46F31A54-4C74-41A8-B294-26B5689E51EF} = {DC381015-B171-4DA5-B7FA-7CDE8196C6D3}\n\t\t{A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{1E320494-894E-4FEB-90CA-DF4FE20499F4} = {C9C47451-FCA6-4B7F-9BD0-20AD3B119737}\n\t\t{CF3350E5-00A2-4647-A996-BAF7542B0327} = {E4213904-77D5-4847-B858-0938BF96064C}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {622BB9B5-938F-41A2-BC8B-B7B3A64A73B5}\n\tEndGlobalSection\n\tGlobalSection(SharedMSBuildProjectFiles) = preSolution\n\t\tBuild\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems*{1e320494-894e-4feb-90ca-df4fe20499f4}*SharedItemsImports = 9\n\t\tTests\\APIExplorer\\APIExplorer.Shared.vcxitems*{46f31a54-4c74-41a8-b294-26b5689e51ef}*SharedItemsImports = 4\n\t\tBuild\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems*{60139f62-bf37-4f11-bd93-5fbf4e92100c}*SharedItemsImports = 4\n\t\tBuild\\Microsoft.Xbox.Services.GDK\\Microsoft.Xbox.Services.GDK.vcxitems*{60139f62-bf37-4f11-bd93-5fbf4e92100c}*SharedItemsImports = 4\n\t\tExternal\\Xal\\External\\libHttpClient\\Build\\libHttpClient.Common\\libHttpClient.Common.vcxitems*{a5a6e02a-21ba-4d55-9fb9-7b24dedd3743}*SharedItemsImports = 4\n\t\tExternal\\Xal\\External\\libHttpClient\\Build\\libHttpClient.GDK.Shared\\libHttpClient.GDK.Shared.vcxitems*{a5a6e02a-21ba-4d55-9fb9-7b24dedd3743}*SharedItemsImports = 4\n\t\tTests\\APIExplorer\\APIExplorer.Shared.vcxitems*{cbc0bec4-131d-4868-9345-71813557fb39}*SharedItemsImports = 9\n\t\tBuild\\Microsoft.Xbox.Services.Common\\Microsoft.Xbox.Services.Common.vcxitems*{cf3350e5-00a2-4647-a996-baf7542b0327}*SharedItemsImports = 9\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "NuGet.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Auto generated file from Gardener Plugin CentralFeedServiceAdoptionPlugin -->\n<configuration>\n  <packageSources>\n    <clear />\n    <add key=\"xbox.services_PublicPackages\" value=\"https://pkgs.dev.azure.com/microsoft/xbox.services/_packaging/xbox.services_PublicPackages/nuget/v3/index.json\" />\n  </packageSources>\n</configuration>"
  },
  {
    "path": "README.md",
    "content": "## Welcome!\n\nThe Microsoft Xbox Live Service API (XSAPI) enables game developers to access Xbox Live. To get access to the Xbox Live service, you can join the Xbox Live Creators Program at https://aka.ms/xblcp, or apply to the ID@Xbox program at: http://www.xbox.com/en-us/Developers/id\n\nTo learn more about these programs, please refer to the [developer program overview](https://docs.microsoft.com/en-us/windows/uwp/xbox-live/developer-program-overview).\n\n## What's in the API:\n\n*   Xbox Live Features - profile, social, presence, leaderboards, achievements, multiplayer, matchmaking, title storage\n*   Xbox Live Authentication Library (XAL) public headers - Note that this repository does not contain full XAL source, it only contains XAL source files needed to support building with the Microsoft GDK.\n*   Platforms - Microsoft GDK (targeting both PC and Console). Installing the Microsoft GDK is a prerequisite for building XSAPI. Additionally, source and projects for XDK and UWP platforms can be found at https://github.com/microsoft/xbox-live-api/tree/1807_xdk_qfe_preview\n*   Support for Visual Studio 2017 and 2019\n\n## How to use the Xbox Live Services API (XSAPI)\n\nThe best way to learn the API and see the best practices is to look at the Xbox Live samples that ship with the Microsoft GDK, and the [Xbox Live developer docs](https://docs.microsoft.com/en-us/windows/uwp/xbox-live/)\n\n## How to clone repo\n\nThis repo contains submodules.  There are two ways to make sure you get submodules.\n\nWhen initially cloning, make sure you use the `--recursive` option. IE:\n\n    git clone --recursive https://github.com/Microsoft/xbox-live-api.git\n\nIf you already cloned the repo, you can initialize submodules with:\n\n    git submodule sync\n    git submodule update --init --recursive\n\n**Note that using GitHub's feature to \"Download Zip\" does not contain the submodules and will not properly build.  Please clone recursively instead.**\n\n## How to link your project against source\n\nYou might want to link against the XSAPI source if you want to debug an issue, or understand where an error code is coming from.  How to do this can be found at [How to link your project against source](LINKTOSOURCE.md)\n\n## Contribute Back!\n\nIs there a feature missing that you'd like to see, or found a bug that you have a fix for? Or do you have an idea or just interest in helping out in building the library? Let us know and we'd love to work with you. For a good starting point on where we are headed and feature ideas, take a look at our [requested features and bugs](https://github.com/Microsoft/xbox-live-api/issues).  \n\nBig or small we'd like to take your contributions back to help improve the Xbox Live Service API for everyone.\n\n## Having Trouble?\n\nWe'd love to get your review score, whether good or bad, but even more than that, we want to fix your problem. If you submit your issue as a Review, we won't be able to respond to your problem and ask any follow-up questions that may be necessary. The most efficient way to do that is to open a an issue in our [issue tracker](https://github.com/Microsoft/xbox-live-api/issues).  The Xbox Live team will be engaged with the community and be continually improving our APIs, tools, and documentation based on the feedback received.\n\n### Xbox Live GitHub projects\n*   [Xbox Live Service API for C++](https://github.com/Microsoft/xbox-live-api)\n*   [Xbox Live Samples (XDK/UWP)](https://github.com/Microsoft/xbox-live-samples)\n*   [Xbox Live Resiliency Fiddler Plugin](https://github.com/Microsoft/xbox-live-resiliency-fiddler-plugin)\n*   [Xbox Live Trace Analyzer](https://github.com/Microsoft/xbox-live-trace-analyzer)\n*   [Xbox Live Developer Tools](https://github.com/Microsoft/xbox-live-developer-tools)\n*   [libHttpClient](https://github.com/Microsoft/libHttpClient)\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).\n\nIf you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).\n\nIf you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).\n\nYou should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). \n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n  * Full paths of source file(s) related to the manifestation of the issue\n  * The location of the affected source code (tag/branch/commit or direct URL)\n  * Any special configuration required to reproduce the issue\n  * Step-by-step instructions to reproduce the issue\n  * Proof-of-concept or exploit code (if possible)\n  * Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\nIf you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.\n\n## Preferred Languages\n\nWe prefer all communications to be in English.\n\n## Policy\n\nMicrosoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).\n\n<!-- END MICROSOFT SECURITY.MD BLOCK -->"
  },
  {
    "path": "Source/Services/Achievements/Manager/achievements_manager_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"achievements_manager_internal.h\"\n#include <utility>\n\nusing namespace xbox::services;\nusing namespace xbox::services::achievements::manager;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_BEGIN\n\ntemplate<typename Ret, typename TWork>\nRet ApiImpl(Ret&& fallbackReturnValue, TWork&& work) noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (!state)\n    {\n        return fallbackReturnValue;\n    }\n\n    assert(state->AchievementsManager());\n    return work(*state->AchievementsManager());\n}\n\ntemplate<typename TWork>\nHRESULT ApiImpl(TWork&& work) noexcept\n{\n    return ApiImpl<HRESULT, TWork>(E_XBL_NOT_INITIALIZED, std::move(work));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_END\n\nSTDAPI XblAchievementsManagerResultGetAchievements(\n    _In_ XblAchievementsManagerResultHandle resultHandle,\n    _Out_ const XblAchievement** achievements,\n    _Out_ uint64_t* achievementsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(achievementsCount == nullptr || achievements == nullptr || resultHandle == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    *achievementsCount = resultHandle->Achievements().size();\n    *achievements = *achievementsCount > 0 ? resultHandle->Achievements().data() : nullptr;\n    \n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerResultDuplicateHandle(\n    _In_ XblAchievementsManagerResultHandle handle,\n    _Out_ XblAchievementsManagerResultHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || duplicatedHandle == nullptr);\n\n    handle->AddRef();\n    *duplicatedHandle = handle;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblAchievementsManagerResultCloseHandle(\n    _In_ XblAchievementsManagerResultHandle handle\n) XBL_NOEXCEPT\ntry\n{\n    if (handle)\n    {\n        handle->DecRef();\n    }\n\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblAchievementsManagerAddLocalUser(\n    _In_ XblUserHandle user,\n    _In_opt_ XTaskQueueHandle queue\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n            return achievementsManager.AddLocalUser(wrapUserResult.ExtractPayload(), TaskQueue::DeriveWorkerQueue(queue));\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerRemoveLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(user);\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n            return achievementsManager.RemoveLocalUser(wrapUserResult.Payload());\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerIsUserInitialized(\n    _In_ uint64_t xboxUserId\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(!achievementsManager.HasUser(xboxUserId));\n            if (!achievementsManager.IsUserInitialized(xboxUserId))\n            {\n                return E_FAIL;\n            }\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\n\nSTDAPI XblAchievementsManagerDoWork(\n    _Outptr_result_maybenull_ const XblAchievementsManagerEvent** achievementsEvents,\n    _Out_ size_t* achievementsEventsCount\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(achievementsEvents);\n\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(achievementsEvents == nullptr || achievementsEventsCount == nullptr);\n            auto& events = achievementsManager.DoWork();\n\n            *achievementsEvents = nullptr;\n            if (!events.empty())\n            {\n                *achievementsEvents = &(*events.begin());\n            }\n            *achievementsEventsCount = events.size();\n            return S_OK;\n        }\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerGetAchievement(\n    _In_ uint64_t xboxUserId,\n    _In_ const char* achievementId,\n    _Outptr_result_maybenull_ XblAchievementsManagerResultHandle* achievementResult\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(achievementId == nullptr || achievementResult == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(achievementId);\n    *achievementResult = nullptr;\n\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            auto achievement = achievementsManager.GetAchievement(xboxUserId, achievementId);\n            if (Failed(achievement))\n            {\n                LOGS_ERROR << achievement.ErrorMessage();\n                return achievement.Hresult();\n            }\n\n            std::shared_ptr<XblAchievementsManagerResult> resultHandle = MakeShared<XblAchievementsManagerResult>(achievement.ExtractPayload());//resultData);\n            *achievementResult = resultHandle.get(); \n            resultHandle->AddRef();\n            return S_OK;    \n        }\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerGetAchievements(\n    _In_ uint64_t xboxUserId,\n    _In_ XblAchievementOrderBy sortField,\n    _In_ XblAchievementsManagerSortOrder sortOrder,\n    _Outptr_result_maybenull_ XblAchievementsManagerResultHandle* achievementsResult\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(achievementsResult);\n    \n    // Can't specify a sort order when just using default field to order on\n    RETURN_HR_INVALIDARGUMENT_IF(sortField != XblAchievementOrderBy::UnlockTime && sortOrder != XblAchievementsManagerSortOrder::Unsorted);\n    \n    // Can't specify a sort field without specifying the order to sort on.\n    RETURN_HR_INVALIDARGUMENT_IF(sortField == XblAchievementOrderBy::UnlockTime && sortOrder == XblAchievementsManagerSortOrder::Unsorted);\n    \n    bool areSortOptionsDefault = sortField != XblAchievementOrderBy::UnlockTime && sortOrder == XblAchievementsManagerSortOrder::Unsorted;\n    if (!areSortOptionsDefault)\n    {\n        return XblAchievementsManagerGetAchievementsByState(\n            xboxUserId,\n            sortField,\n            sortOrder,\n            XblAchievementProgressState::Unknown,\n            achievementsResult\n        );\n    }\n\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(achievementsResult == nullptr);\n            *achievementsResult = nullptr;\n\n            auto achievements = achievementsManager.GetAchievements(xboxUserId);\n            if (Failed(achievements))\n            {\n                LOGS_ERROR << achievements.ErrorMessage();\n                return achievements.Hresult();\n            }\n            \n            if (achievements.Payload().second == 0)\n            {\n                return E_UNEXPECTED;\n            }\n            \n            std::shared_ptr<XblAchievementsManagerResult> resultHandle = MakeShared<XblAchievementsManagerResult>(achievements.Payload().first, achievements.Payload().second, true);\n            *achievementsResult = resultHandle.get();\n            resultHandle->AddRef();\n            \n            return S_OK;\n        }\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerGetAchievementsByState(\n    _In_ uint64_t xboxUserId,\n    _In_ XblAchievementOrderBy sortField,\n    _In_ XblAchievementsManagerSortOrder sortOrder,\n    _In_ XblAchievementProgressState achievementState,\n    _Outptr_result_maybenull_ XblAchievementsManagerResultHandle* achievementsResult\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(achievementsResult);\n\n    // Can't specify a sort order when just using default field to order on\n    RETURN_HR_INVALIDARGUMENT_IF(sortField != XblAchievementOrderBy::UnlockTime && sortOrder != XblAchievementsManagerSortOrder::Unsorted);\n\n    // Can't specify a sort field without specifying the order to sort on.\n    RETURN_HR_INVALIDARGUMENT_IF(sortField == XblAchievementOrderBy::UnlockTime && sortOrder == XblAchievementsManagerSortOrder::Unsorted);\n\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(achievementsResult == nullptr);\n\n            // Return an invalid arg if one of sortField or sortOrder are set to a \n            //  non-default value while the other is set to a default value.\n            RETURN_HR_INVALIDARGUMENT_IF((sortField == XblAchievementOrderBy::UnlockTime && sortOrder == XblAchievementsManagerSortOrder::Unsorted)\n                || (sortOrder != XblAchievementsManagerSortOrder::Unsorted && sortField == XblAchievementOrderBy::DefaultOrder));\n            \n            *achievementsResult = nullptr;\n\n            AchievementsManagerSortFilterSettings sortOptions{ sortField, sortOrder, AchievementsManagerFilterType::All };\n            switch (achievementState)\n            {\n            case XblAchievementProgressState::Achieved:\n                sortOptions.stateFilter = AchievementsManagerFilterType::Unlocked;\n                break;\n            case XblAchievementProgressState::InProgress:\n                sortOptions.stateFilter = AchievementsManagerFilterType::InProgress;\n                break;\n            case XblAchievementProgressState::NotStarted:\n                sortOptions.stateFilter = AchievementsManagerFilterType::NotStarted;\n                break;\n            default:\n                sortOptions.stateFilter = AchievementsManagerFilterType::All;\n                break;\n            }\n\n            auto achievements = achievementsManager.GetAchievements(xboxUserId, sortOptions);\n            if (Failed(achievements))\n            {\n                LOGS_ERROR << achievements.ErrorMessage();\n                return achievements.Hresult();\n            }\n\n            // don't need to return an error for getting an empty vector, as it means there\n            // were no elements that matched made it through the filter.\n\n            std::shared_ptr<XblAchievementsManagerResult> resultHandle = MakeShared<XblAchievementsManagerResult>(achievements.Payload());\n            *achievementsResult = resultHandle.get();\n            resultHandle->AddRef();\n            return S_OK;\n        }\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsManagerUpdateAchievement(\n    _In_ uint64_t xboxUserId,\n    _In_ const char* achievementId,\n    _In_ uint8_t currentProgress\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](AchievementsManager& achievementsManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(achievementId);\n            RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(achievementId);\n\n            currentProgress = static_cast<uint8_t>(fmin(currentProgress, 100));\n\n            auto updateResult = achievementsManager.UpdateAchievement(xboxUserId, achievementId, currentProgress);\n            if (Failed(updateResult))\n            {\n                LOGS_ERROR << updateResult.ErrorMessage();\n                return updateResult.Hresult();\n            }\n            return S_OK;\n        }\n    );\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Achievements/Manager/achievements_manager_internal.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"achievements_manager_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nusing namespace xbox::services;\n\nXblAchievementsManagerResult::XblAchievementsManagerResult(_In_ const XblAchievement & achievement)\n    : m_achievements({ achievement }),\n    m_achievementsData(nullptr),\n    m_achievementsCount(),\n    m_explicitCleanup(false)\n{\n}\n\nXblAchievementsManagerResult::XblAchievementsManagerResult(_In_ Vector<XblAchievement>& achievements, _In_ bool explicitCleanup)\n    : m_achievements(std::move(achievements)),\n    m_achievementsData(m_achievements.data()),\n    m_achievementsCount(m_achievements.size()),\n    m_explicitCleanup(explicitCleanup)\n{\n}\n\nXblAchievementsManagerResult::XblAchievementsManagerResult(_In_ XblAchievement* achievements, _In_ size_t achievementCount, _In_ bool explicitCleanup)\n    : m_achievements(achievements, achievements + achievementCount),\n    m_achievementsData(achievements),\n    m_achievementsCount(achievementCount),\n    m_explicitCleanup(explicitCleanup)\n{\n}\n\nXblAchievementsManagerResult::~XblAchievementsManagerResult()\n{\n    for (auto& achievement : m_achievements)\n    {\n        achievements::manager::AchievementsManager::CleanUpAchievementCopyForResult(achievement);\n    }\n    if (m_explicitCleanup)\n    {\n        DeleteArray<XblAchievement>(m_achievementsData, m_achievementsCount);\n    }\n    m_achievementsData = nullptr;\n    m_achievementsCount = 0;\n    m_achievements.clear();\n}\n\nconst Vector<XblAchievement>& XblAchievementsManagerResult::Achievements() const\n{\n    return m_achievements;\n}\n\nstd::shared_ptr<xbox::services::RefCounter> XblAchievementsManagerResult::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_BEGIN\n\nAchievementsManagerUser::AchievementsManagerUser(\n    _In_ User&& localUser,\n    _In_ const TaskQueue& queue\n) noexcept :\n    m_xuid{ localUser.Xuid() },\n    m_rtaManager{ GlobalState::Get()->RTAManager() },\n    m_queue{ queue.DeriveWorkerQueue() }\n{\n    // Maintain legacy RTA activation count.\n    m_rtaManager->Activate(localUser);\n\n    m_xblContext = XblContext::Make(std::move(localUser));\n}\n\nAchievementsManagerUser::~AchievementsManagerUser()\n{\n    // Terminate any background work\n    m_queue.Terminate(false);\n\n    // Unregister rta handlers\n    if (m_achievementProgressToken)\n    {\n        m_xblContext->AchievementsService()->RemoveAchievementProgressChangeHandler(m_achievementProgressToken);\n    }\n    if (m_rtaResyncToken)\n    {\n        m_rtaManager->RemoveResyncHandler(m_xblContext->User(), m_rtaResyncToken);\n    }\n    if (m_rtaConnectionToken)\n    {\n        m_rtaManager->RemoveStateChangedHandler(m_xblContext->User(), m_rtaConnectionToken);\n    }\n\n    m_rtaManager->Deactivate(m_xblContext->User());\n\n    for (auto& pair : m_userAchievements)\n    {\n        AchievementsManager::CleanUpDeepCopyAchievement(*pair.second);\n    }\n    DeleteArray(m_achievementCache, m_userAchievements.size());\n}\n\nResult<void> AchievementsManagerUser::Initialize(\n    _In_ AsyncContext<HRESULT> async\n)\n{\n    assert(!m_isInitialized);\n    RETURN_HR_IF_FAILED(m_xblContext->Initialize(m_rtaManager));\n    m_xblContext->Settings()->SetHttpUserAgent(HttpCallAgent::AchievementsManager);\n\n    std::weak_ptr<AchievementsManagerUser> weakThis{ shared_from_this() };\n    m_achievementProgressToken = m_xblContext->AchievementsService()->AddAchievementProgressChangeHandler(\n        [weakThis](const XblAchievementProgressChangeEventArgs& args)\n        {\n            auto sharedThis{ weakThis.lock() };\n            if (sharedThis)\n            {\n                // convert to manager event\n                for (uint32_t entryIndex = 0; entryIndex < args.entryCount; ++entryIndex)\n                {\n                    // In rare cases, we may get a notification for an achievement that we don't have\n                    //  cached. We'll log but otherwise ignore the RTA notification in those cases\n                    auto achievementId = args.updatedAchievementEntries[entryIndex].achievementId;\n\n                    if (sharedThis->m_userAchievements.find(achievementId) == sharedThis->m_userAchievements.end())\n                    {\n                        LOGS_WARN << \"Ignoring unexpected Achievement Progress RTA event for achievement not in the AchievementManager local cache.\";\n                        continue;\n                    }\n\n                    XblAchievementsManagerEvent achievementEvent;\n                    achievementEvent.xboxUserId = sharedThis->m_xuid;\n                    achievementEvent.eventType = XblAchievementsManagerEventType::AchievementProgressUpdated;\n                    \n                    // Make a deep copy of the achievement entries here. Can't steal them with move,\n                    //  as other handlers might have been added.\n                    achievementEvent.progressInfo = AchievementProgressChangeSubscription::DeepCopyProgressChangeEntry(\n                        args.updatedAchievementEntries[entryIndex]\n                    );\n\n                    // Achievement progress notifications can potentially come in with no \n                    //  targetProgressValue defined if it does not result in an achievement \n                    //  being unlocked, so we need to copy the targetProgressValue from \n                    //  the cached achievement.\n                    auto& progression = achievementEvent.progressInfo.progression;\n                    for (uint64_t i = 0; i < progression.requirementsCount; ++i)\n                    {\n                        auto& requirement = progression.requirements[i];\n                        if (requirement.targetProgressValue == nullptr)\n                        {\n                            auto& cachedAchievement = sharedThis->m_userAchievements[achievementEvent.progressInfo.achievementId];\n                            auto& cachedProgression = cachedAchievement->progression;\n\n                            auto matchedRequirement = std::find_if(cachedProgression.requirements, cachedProgression.requirements +cachedProgression.requirementsCount,\n                                [&requirement](const XblAchievementRequirement& cachedRequirement)->bool\n                                {\n                                    return utils::str_icmp(requirement.id, cachedRequirement.id);\n                                });\n                            if (matchedRequirement == (cachedProgression.requirements + cachedProgression.requirementsCount))\n                            {\n                                char errorMsg[1024];\n                                SPRINTF(errorMsg, 1024, \"Could not find a requirement with ID %s for cached achievement %s. Couldn't populate event with targetProgressValue.\", requirement.id, achievementEvent.progressInfo.achievementId);\n                                LOGS_ERROR << errorMsg;\n                            }\n                            requirement.targetProgressValue = Make(matchedRequirement->targetProgressValue);\n                        }\n                    }\n\n                    {\n                        std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n                        sharedThis->m_eventsToProcess.push_back(achievementEvent);\n                    }\n                }\n\n            }\n        }\n    );\n    \n    auto resyncCallback = [weakThis] (HRESULT hr)\n    {\n        auto sharedThis{ weakThis.lock() };\n        auto state{ GlobalState::Get() };\n        if (sharedThis && state)\n        {\n            std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n            sharedThis->m_isFetchingAchievements = false;\n            if (FAILED(hr))\n            {\n                LOGS_ERROR << \"Fetching state of achievements for user with ID \" << sharedThis->Xuid() << \" for RTA Resync failed with error code \" << hr;\n            }\n            else\n            {\n                // Needed if not already initialized, for instance if the user was added while offline\n                sharedThis->m_isInitialized = true;\n            }\n        }\n    };\n\n    // rta resync\n    m_rtaResyncToken = m_rtaManager->AddResyncHandler(m_xblContext->User(),\n        [weakThis, resyncCallback]()\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n                sharedThis->m_isFetchingAchievements = true;\n                sharedThis->FetchAchievements(AsyncContext<HRESULT> {\n                    sharedThis->m_queue,\n                    resyncCallback\n                });\n            }\n        }\n    );\n\n    m_rtaConnectionToken = m_rtaManager->AddStateChangedHandler(m_xblContext->User(),\n        [weakThis, resyncCallback](XblRealTimeActivityConnectionState connectionState)\n        {\n            // Only take action if rta just connected.\n            if (connectionState != XblRealTimeActivityConnectionState::Connected)\n            {\n                return;\n            }\n\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n                // We only want to refetch state data if we're not in the middle of a fetch\n                if (sharedThis->m_isFetchingAchievements)\n                {\n                    return;\n                }\n\n                sharedThis->m_isFetchingAchievements = true;\n                // If this function hasn't returned yet, this means that the\n                //  RTA connection dropped at some point (whether the network \n                //  connection dropped, or an issue with the RTA service, \n                //  etc.) and we've missed some data, meaning we need to \n                //  resync the cached state from the service.\n                sharedThis->FetchAchievements(AsyncContext<HRESULT> {\n                    sharedThis->m_queue,\n                    resyncCallback\n                });\n            }\n        }\n    );\n\n    return FetchAchievements(AsyncContext<HRESULT> {\n        m_queue,\n            [\n                async,\n                weakThis\n            ]\n        (HRESULT hr)\n        {\n            auto sharedThis{ weakThis.lock() };\n            auto state{ GlobalState::Get() };\n            if (sharedThis && state)\n            {\n                {\n                    std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n                    sharedThis->m_isFetchingAchievements = false;\n                    if (SUCCEEDED(hr))\n                    {\n                        sharedThis->m_isInitialized = true;\n                    }\n                }\n                async.Complete(hr);\n            }\n        }\n    });\n}\n\nbool AchievementsManagerUser::IsInitialized() const\n{\n    return m_isInitialized;\n}\n\nuint64_t AchievementsManagerUser::Xuid() const\n{\n    return m_xuid;\n}\n\nResult<XblAchievement> AchievementsManagerUser::GetAchievement(_In_ const String & id)\n{\n    if (m_userAchievements.find(id) == m_userAchievements.end())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"Cannot find achievement with ID %s for user with ID %llu.\", id.c_str(), static_cast<unsigned long long>(m_xuid));\n        return { E_BOUNDS, errorMsg };\n    }\n\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    return AchievementsManager::CopyAchievementForResult(*m_userAchievements[id]);\n}\n\nXblAchievement* AchievementsManagerUser::GetAchievements() \n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    return AchievementsManager::DeepCopyAchievements(m_achievementCache, m_userAchievements.size());\n}\n\nVector<XblAchievement> AchievementsManagerUser::GetAchievements(\n    _In_ AchievementsManagerSortFilterSettings sortFilterSettings\n)\n{\n    Vector<XblAchievement> filteredAchievements;\n    \n    {\n        std::lock_guard<std::mutex> lock{ m_mutex };\n        for (const auto& pair : m_userAchievements)\n        {\n            const XblAchievement& achievement = *pair.second;\n            bool isIncluded = true;\n            \n            // Does this achievement match the state requested?\n            switch (sortFilterSettings.stateFilter)\n            {\n            case AchievementsManagerFilterType::Unlocked:\n                isIncluded &= achievement.progressState == XblAchievementProgressState::Achieved;\n                break;\n            case AchievementsManagerFilterType::InProgress:\n                isIncluded &= achievement.progressState == XblAchievementProgressState::InProgress;\n                break;\n            case AchievementsManagerFilterType::NotStarted:\n                isIncluded &= achievement.progressState == XblAchievementProgressState::NotStarted;\n                break; \n            default:\n                break; // Don't need to &= true here, it's just a wasted op.\n            }\n\n            if (isIncluded)\n            {\n                // Pushing back a shallow copy here, in case we need to truncate\n                //  the list before we return it.\n                filteredAchievements.push_back(achievement);\n            }\n        }\n    }\n    \n    // We only sort on UnlockTime, since we don't offer achievements from multiple\n    //  titles. This would need to change if we ever give more options for values to\n    //  sort on.\n    if (sortFilterSettings.sortBy == XblAchievementOrderBy::UnlockTime)\n    {\n        // call sort function\n        if (sortFilterSettings.sortOrder == XblAchievementsManagerSortOrder::Ascending)\n        {\n            std::sort(filteredAchievements.begin(), filteredAchievements.end(), \n                [](const XblAchievement& a, const XblAchievement& b) -> bool\n                {\n                    return a.progression.timeUnlocked < b.progression.timeUnlocked;\n                }\n            );\n        }\n        else if (sortFilterSettings.sortOrder == XblAchievementsManagerSortOrder::Descending)\n        {\n            std::sort(filteredAchievements.begin(), filteredAchievements.end(),\n                [](const XblAchievement& a, const XblAchievement& b) -> bool\n                {\n                    return a.progression.timeUnlocked > b.progression.timeUnlocked;\n                }\n            );\n        }\n    }\n    return AchievementsManager::DeepCopyAchievements(filteredAchievements);\n}\n\nuint64_t AchievementsManagerUser::GetAchievementCount() const\n{\n    return m_userAchievements.size();\n}\n\nResult<void> AchievementsManagerUser::CanUpdateAchievement(_In_ const String & achievementId, _In_ uint8_t progress)\n{\n    // User added offline if still uninitialized, so must assume we can update for offline achievements\n    if (!m_isInitialized)\n    {\n        return S_OK;\n    }\n\n    if (m_userAchievements.find(achievementId) == m_userAchievements.end())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"Requested achievement with ID %s doesn't exist.\", achievementId.c_str());\n        return { E_BOUNDS, errorMsg };\n    }\n    if (m_userAchievements[achievementId]->progressState == XblAchievementProgressState::Achieved)\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"Requested achievement with ID %s already achieved.\", achievementId.c_str());\n        return{ E_UNEXPECTED, errorMsg };\n    }\n    if (m_userAchievements[achievementId]->progression.requirementsCount > 1)\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"Requested achievement with ID %s is an event based achievement and can't be updated through AchievementManager. Use the Stats API instead.\", achievementId.c_str());\n        return { E_NOT_SUPPORTED, errorMsg };\n    }\n\n    uint32_t targetValue = xbox::services::utils::internal_string_to_uint32(m_userAchievements[achievementId]->progression.requirements[0].targetProgressValue);\n    if (targetValue != 100)\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"Requested achievement with ID %s is an event based achievement and can't be updated through AchievementManager. Use the Stats API instead.\", achievementId.c_str());\n        return { E_NOT_SUPPORTED, errorMsg };\n    }\n\n    uint32_t currentValue = xbox::services::utils::internal_string_to_uint32(m_userAchievements[achievementId]->progression.requirements[0].currentProgressValue);\n    if (currentValue >= progress)\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"Can't update achievement with ID %s because the new progress value of %u is less than or equal to the achievement's current progress value of %u.\",\n            achievementId.c_str(),\n            progress,\n            currentValue\n        );\n        return { E_INVALIDARG, errorMsg };\n    }\n    return S_OK;\n}\n\nResult<void> AchievementsManagerUser::UpdateAchievement(_In_ const String& achievementId, _In_ uint8_t percent)\n{\n    return m_xblContext->AchievementsService()->UpdateAchievement(\n        m_xuid,\n        achievementId,\n        percent,\n        AsyncContext<Result<void>> {\n        [\n            achievementId, \n            percent\n        ]\n    (Result<void> result)\n    {\n        if (FAILED(result.Hresult()))\n        {\n            LOGS_ERROR << \"Updating achievement \" << achievementId << \" to \" << percent << \"% complete failed with error code \" << result.Hresult();\n        }\n    }\n    });\n}\n\nenum class ProgressValueType : uint32_t\n{\n    NonNumeric = 0,\n    UnsignedLong,\n    SignedLong,\n    FloatingPoint\n};\n\nProgressValueType IsNumber(const char* str)\n{\n    char* p = nullptr;\n    \n    (void)strtoul(str, &p, 0);\n    if (p == nullptr)\n    {\n        return ProgressValueType::UnsignedLong;\n    }\n\n    // If it couldn't be represented as an unsigned long, check to see if it can be signed next.\n    (void)strtol(str, &p, 0);\n    if (p == nullptr)\n    {\n        return ProgressValueType::SignedLong;\n    }\n    \n    // If neither of those, then either it is a floating point number, or it is non-numeric.\n    (void)strtod(str, &p);\n    if (p == nullptr)\n    {\n        return ProgressValueType::FloatingPoint;\n    }\n\n    return ProgressValueType::NonNumeric;\n}\n\nbool TryParseToDouble(const char* str, double* out)\n{\n    char* p = nullptr;\n    double parsedValue = 0.0;\n    parsedValue = strtod(str, &p);\n    if (out)\n    {\n        *out = parsedValue;\n    }\n    return p == nullptr;\n}\n\nbool TryParseToUnsignedLong(const char* str, unsigned long* out)\n{\n    char* p = nullptr;\n    unsigned long parsedValue = 0;\n    parsedValue = strtoul(str, &p, 0);\n    if (out)\n    {\n        *out = parsedValue;\n    }\n    return p == nullptr;\n}\n\nbool TryParseToLong(const char* str, long* out)\n{\n    char* p = nullptr;\n    long parsedValue = 0;\n    parsedValue = strtol(str, &p, 0);\n    if (out)\n    { \n        *out = parsedValue;\n    }\n    return p == nullptr;\n}\n\nunsigned long ForceProgressValueToUnsignedLong(const char* progressValue, ProgressValueType valueType)\n{\n    unsigned long forcedValue = 0;\n    switch (valueType)\n    {\n    case ProgressValueType::UnsignedLong:\n        TryParseToUnsignedLong(progressValue, &forcedValue);\n        break;\n    case ProgressValueType::SignedLong:\n    {\n        long parsedValue = 0;\n        TryParseToLong(progressValue, &parsedValue);\n        forcedValue = parsedValue > 0 ? parsedValue : 0;\n        break;\n    }\n    case ProgressValueType::FloatingPoint:\n    {\n        double parsedValue = 0.0;\n        TryParseToDouble(progressValue, &parsedValue);\n        forcedValue = static_cast<unsigned long>(parsedValue);\n        break;\n    }\n    default:\n        break;\n    }\n    return forcedValue;\n}\n\nbool ShouldUpdateProgress(const char* eventProgressValue, const char* cachedProgressValue)\n{\n    ProgressValueType eventValueType = IsNumber(eventProgressValue); \n    ProgressValueType cachedValueType = IsNumber(cachedProgressValue);\n\n    // Always update if both values are non numeric, as we don't know how to do that comparison.\n    // Maybe add a way for the title to add a conversion handler(s) in case they use non-numbers\n    //  to represent achievement progress?\n    if (eventValueType == cachedValueType && eventValueType == ProgressValueType::NonNumeric)\n    {\n        LOGS_WARN << \"Comparing progress values that are string typed. Cannot determine which string is considered greater by the title, and will always result in updating to cached value\";\n        return true;\n    }\n    else if (eventValueType == ProgressValueType::NonNumeric || cachedValueType == ProgressValueType::NonNumeric)\n    {\n        // Only one of the two progress values is numeric, so we don't know how to do that \n        //  conversion. In this case we should log an error and not update, as this is \n        //  likely an unintended result.\n        LOGS_ERROR << \"Cannot compare numeric event progress value against cached non-numeric progress value. Progress for this requirement will not be updated.\";\n        return false;\n    }\n    else if (eventValueType != cachedValueType)\n    {\n        // Cached and event progress values are represented by different numeric types, so log \n        //  a warning and continue. Going to cast all values to unsigned long to continue.\n        LOGS_WARN << \"Comparing two different numeric types. Both values will be cast to unsigned long before comparison.\";\n        return ForceProgressValueToUnsignedLong(eventProgressValue, eventValueType) > ForceProgressValueToUnsignedLong(cachedProgressValue, cachedValueType);\n    }\n\n    // Value types are the same.\n    bool shouldUpdate = false;\n    switch (cachedValueType)\n    {\n    case ProgressValueType::UnsignedLong:\n    {\n        unsigned long eventValue, cachedValue; \n        TryParseToUnsignedLong(cachedProgressValue, &cachedValue);\n        TryParseToUnsignedLong(eventProgressValue, &eventValue);\n\n        shouldUpdate = eventValue > cachedValue;\n        break;\n    }\n    case ProgressValueType::SignedLong:\n    {\n        long eventValue, cachedValue;\n        TryParseToLong(cachedProgressValue, &cachedValue);\n        TryParseToLong(eventProgressValue, &eventValue);\n\n        shouldUpdate = eventValue > cachedValue;\n        break;\n    }\n    case ProgressValueType::FloatingPoint:\n    {\n        double eventValue, cachedValue;\n        TryParseToDouble(cachedProgressValue, &cachedValue);\n        TryParseToDouble(eventProgressValue, &eventValue);\n\n        shouldUpdate = eventValue > cachedValue;\n        break;\n    }\n    default:\n        break;\n    }\n\n    return shouldUpdate;\n}\n\nVector<XblAchievementsManagerEvent> AchievementsManagerUser::ProcessEvents()\n{\n    Vector<XblAchievementsManagerEvent> eventsToApply;\n    {\n        std::lock_guard<std::mutex> lock{ m_mutex };\n        eventsToApply = std::move(m_eventsToProcess);\n        eventsToApply.insert(eventsToApply.end(), m_generatedEvents.begin(), m_generatedEvents.end());\n        m_generatedEvents.clear();\n    }\n\n    // Using a regular for-loop here since we are modifying the contents of the \n    //  vector while iterating over it. Using a range-based for loop or using\n    //  iterators would result in the loop ending before the additional members \n    //  are iterated over.\n    for (uint32_t i = 0; i < eventsToApply.size(); ++i)\n    {\n        const XblAchievementsManagerEvent& achievementEvent = eventsToApply[i];\n        switch (achievementEvent.eventType)\n        {\n        case XblAchievementsManagerEventType::AchievementProgressUpdated:\n        {\n            bool createUnlockEvent = false;\n\n            const XblAchievementProgression& eventProgression = achievementEvent.progressInfo.progression;\n            XblAchievementProgression& cachedProgression = m_userAchievements[achievementEvent.progressInfo.achievementId]->progression;\n            \n            // Explicitly not setting unlock time here, since if this is just getting achieved, we'll have an\n            //  unlock event to handle that.\n\n            // Only set the state of the achievement if the event makes the state \"InProgress\", and the \n            //  achievement wasn't already completed.\n            if (m_userAchievements[achievementEvent.progressInfo.achievementId]->progressState != XblAchievementProgressState::Achieved\n                && achievementEvent.progressInfo.progressState == XblAchievementProgressState::InProgress)\n            {\n                m_userAchievements[achievementEvent.progressInfo.achievementId]->progressState = achievementEvent.progressInfo.progressState;\n            }\n\n            // Shortcut for if there is only one requirement in each to avoid the logic for the loop.            \n            if (cachedProgression.requirementsCount == 1)\n            {\n                // Check to make sure that the IDs are the same, just to be sure.\n                if (!utils::str_icmp(cachedProgression.requirements[0].id, eventProgression.requirements[0].id))\n                {\n                    char errorMsg[1024];\n                    SPRINTF(errorMsg, 1024, \"Achievement event for achievement with ID %s has a requirement with ID %s that doesn't exist in the cached achievement.\",\n                        achievementEvent.progressInfo.achievementId,\n                        eventProgression.requirements[0].id\n                    );\n                    LOGS_ERROR << String(errorMsg);\n                }\n\n                // Perform comparison. This can change if service implementation simplifies getting cumulative progress values back.\n                if(ShouldUpdateProgress(eventProgression.requirements[0].currentProgressValue, cachedProgression.requirements[0].currentProgressValue))\n                {\n                    Delete(cachedProgression.requirements[0].currentProgressValue);\n                    cachedProgression.requirements[0].currentProgressValue = Make(eventProgression.requirements[0].currentProgressValue);\n\n                    createUnlockEvent = (achievementEvent.progressInfo.progressState == XblAchievementProgressState::Achieved\n                        || (String)cachedProgression.requirements[0].currentProgressValue == (String)cachedProgression.requirements[0].targetProgressValue);\n                }\n            }\n            else\n            {\n                bool allRequirementsComplete = true;\n                Vector<XblAchievementRequirement> cachedRequirements(cachedProgression.requirements, cachedProgression.requirements + cachedProgression.requirementsCount);\n                for (uint32_t requirementIndex = 0; requirementIndex < eventProgression.requirementsCount; ++requirementIndex)\n                {\n                    // Find the cached requirement whose ID matches the requirement that was updated.\n                    auto requirement = std::find_if(cachedRequirements.begin(), cachedRequirements.end(),\n                        [&eventProgression, requirementIndex](const XblAchievementRequirement& requirement)->bool\n                        {\n                            return utils::str_icmp(requirement.id, eventProgression.requirements[requirementIndex].id) == 0;\n                        }\n                    );\n\n                    if (requirement == cachedRequirements.end())\n                    {\n                        char errorMsg[1024];\n                        SPRINTF(errorMsg, 1024, \"Achievement event for achievement with ID %s has a requirement with ID %s that doesn't exist in the cached achievement.\",\n                            achievementEvent.progressInfo.achievementId,\n                            eventProgression.requirements[requirementIndex].id\n                        );\n                        LOGS_ERROR << String(errorMsg);\n                    }\n                    else\n                    {\n                        // This check can change to simple eventProgress > cachedProgress check if service implementation simplifies \n                        //  getting cumulative progress values back.\n                        if (ShouldUpdateProgress(eventProgression.requirements[requirementIndex].currentProgressValue, requirement->currentProgressValue))\n                        {\n                            requirement->currentProgressValue = eventProgression.requirements[requirementIndex].currentProgressValue;\n                        }\n                        allRequirementsComplete &= (String)requirement->currentProgressValue == (String)requirement->targetProgressValue;\n                    }\n                }\n                createUnlockEvent = (allRequirementsComplete || achievementEvent.progressInfo.progressState == XblAchievementProgressState::Achieved);\n            }\n\n            if (createUnlockEvent)\n            {\n                XblAchievementsManagerEvent unlockEvent;\n                unlockEvent.eventType = XblAchievementsManagerEventType::AchievementUnlocked;\n                unlockEvent.xboxUserId = m_xuid;\n                unlockEvent.progressInfo.progressState = XblAchievementProgressState::Achieved;\n                unlockEvent.progressInfo.achievementId = Make(achievementEvent.progressInfo.achievementId);\n\n                // Only populating the time unlocked as the actual progress info is irrelevent, since it just boils down to 100%\n                //  the title can grab that info if it needs it from the preceeding progress update event.\n                unlockEvent.progressInfo.progression = XblAchievementProgression{ 0 };\n                unlockEvent.progressInfo.progression.timeUnlocked = achievementEvent.progressInfo.progression.timeUnlocked;\n                eventsToApply.push_back(unlockEvent);\n            }\n            break;\n        }\n        case XblAchievementsManagerEventType::AchievementUnlocked:\n        {\n            auto achievementId = achievementEvent.progressInfo.achievementId;\n            XblAchievement& cachedAchievement = *m_userAchievements[achievementId];\n            if (cachedAchievement.progression.requirementsCount != achievementEvent.progressInfo.progression.requirementsCount)\n            {\n                LOGS_ERROR << \"Achievement event for achievement with ID \" << achievementId << \" has a different number of requirements than the cached version of the achievement.\";\n            }\n\n            cachedAchievement.progressState = achievementEvent.progressInfo.progressState;\n            cachedAchievement.progression.timeUnlocked = achievementEvent.progressInfo.progression.timeUnlocked;\n            // For each reuqirement, update the current value to the target value.\n            for (uint32_t requirementIndex = 0; requirementIndex < cachedAchievement.progression.requirementsCount; ++requirementIndex)\n            {\n                // Clean up expects currentProgressValue to be a dynamically allocated string,\n                //  so dynamically allocate this too so we don't crash trying to Delete a \n                //  statically allocated literal.\n                Delete(cachedAchievement.progression.requirements[requirementIndex].currentProgressValue);\n                cachedAchievement.progression.requirements[requirementIndex].currentProgressValue = Make(\"100\");\n            }\n            break;\n        }\n        default:\n            break;\n        }\n    }\n\n    return eventsToApply;\n}\n\nVector<XblAchievementsManagerEvent> GenerateEventFromAchievementDiff(uint64_t xuid, const XblAchievement& cached, const XblAchievement& updated)\n{\n    Vector<XblAchievementsManagerEvent> generatedEvents;\n\n    // Check each requirement on the achievement, and if there is a difference in the progress value,\n    //  then generate a progress event.\n    Vector<XblAchievementRequirement> updatedRequirements;\n\n    uint64_t requirementCount = updated.progression.requirementsCount;\n    for (uint64_t requirementIndex = 0; requirementIndex < requirementCount; ++requirementIndex)\n    {\n        Vector<XblAchievementRequirement> cachedRequirements(cached.progression.requirements, cached.progression.requirements + cached.progression.requirementsCount);\n\n        auto& updatedRequirement = updated.progression.requirements[requirementIndex];\n        \n        // Find the cached requirement whose ID matches the requirement that was updated.\n        auto cachedRequirement = std::find_if(cachedRequirements.begin(), cachedRequirements.end(),\n            [&updatedRequirement](const XblAchievementRequirement& requirement)->bool\n            {\n                return utils::str_icmp(requirement.id, updatedRequirement.id) == 0;\n            }\n        );\n        if (cachedRequirement == cachedRequirements.end())\n        {\n            char errorMsg[1024];\n            SPRINTF(errorMsg, 1024, \"Achievement from achievement event with ID %s has a requirement with ID %s that doesn't exist in the cached achievement.\",\n                updated.id,\n                updatedRequirement.id\n            );\n            LOGS_ERROR << String(errorMsg);\n        }\n        else\n        {\n            // Compare the progress values.\n            if (utils::internal_string_to_uint32(cachedRequirement->currentProgressValue) <\n                utils::internal_string_to_uint32(updatedRequirement.currentProgressValue))\n            {\n                updatedRequirements.push_back(updatedRequirement);\n            }\n        }\n    }\n\n    if (updatedRequirements.size() > 0)\n    {\n        // check to see if we have an event for this change already.\n        XblAchievementsManagerEvent event;\n        event.xboxUserId = xuid;\n        event.eventType = XblAchievementsManagerEventType::AchievementProgressUpdated;\n        XblAchievementProgressChangeEntry& progressEntry = event.progressInfo;\n        progressEntry.progressState = updated.progressState;\n        progressEntry.achievementId = Make(updated.id);\n        XblAchievementProgression& progress = progressEntry.progression;\n\n        \n        // Move the contents of the vector into the progression struct.\n        progress.requirementsCount = updatedRequirements.size();\n        progress.requirements = MakeArray<XblAchievementRequirement>(progress.requirementsCount);\n        for (uint64_t i = 0; i < progress.requirementsCount; ++i)\n        {\n            std::swap(progress.requirements[i].id, updatedRequirements[i].id);\n            std::swap(progress.requirements[i].currentProgressValue, updatedRequirements[i].currentProgressValue);\n            std::swap(progress.requirements[i].targetProgressValue, updatedRequirements[i].targetProgressValue);\n        }\n        progress.timeUnlocked = updated.progression.timeUnlocked;\n        \n        generatedEvents.push_back(event);\n    }\n\n    return generatedEvents;\n}\n\nHRESULT AchievementsManagerUser::FetchAchievements(_In_ AsyncContext<HRESULT> async)\n{\n    constexpr uint32_t achievementsPerFetch = 100;\n\n    return m_xblContext->AchievementsService()->GetAchievementsForTitle(\n        m_xuid,\n        AppConfig::Instance()->TitleId(),\n        XblAchievementType::All,\n        false,\n        XblAchievementOrderBy::DefaultOrder,\n        0,\n        achievementsPerFetch,\n        AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>>{ async.Queue(),\n        [\n            =,\n            weakThis = std::weak_ptr<AchievementsManagerUser>{ shared_from_this() }\n        ]\n    (Result<std::shared_ptr<XblAchievementsResult>> result)\n    {\n        auto sharedThis{ weakThis.lock() };\n        if (sharedThis)\n        {\n            sharedThis->HandleAchievementsResults(result, achievementsPerFetch, async);\n        }\n    }\n    });\n}\n\nHRESULT AchievementsManagerUser::HandleAchievementsResults(\n    _In_ Result<std::shared_ptr<XblAchievementsResult>> result,\n    _In_ uint32_t achievementsPerFetch,\n    _In_ AsyncContext<HRESULT> async,\n    _In_ Vector<XblAchievement> fetchedAchievements\n)\n{\n    if (Succeeded(result))\n    {\n        {\n            std::lock_guard<std::mutex> lock{ m_mutex };\n            for (const XblAchievement& achievement : result.Payload()->Achievements())\n            {\n                // If this is being called after the user has already been initialized, then\n                //  something happened and needed to do an RTA resync. So compare against the\n                //  existing achievement, and generate the proper event from it.\n                if (m_isInitialized)\n                {\n                    // In rare cases we'll get back a notification that isn't in our local cache. If that happens\n                    //  we'll simply ignore the new achievement until the title restarts or the user is removed\n                    //  and re-added to achievements manager\n                    if (m_userAchievements.find(achievement.id) == m_userAchievements.end())\n                    {\n                        LOGS_WARN << \"Fetch achievements returned new achievement that wasn't present in local achievement cache.\";\n                        continue;\n                    }\n\n                    // We only want to have this function generate unlock events if we're expecting \n                    //  RTA notifications. Otherwise it will be produced from the progress change\n                    //  event.\n                    auto generatedEvents = GenerateEventFromAchievementDiff(m_xuid, *m_userAchievements[achievement.id], achievement);\n                    if (generatedEvents.size() > 0)\n                    {\n                        for (auto generatedEvent : generatedEvents)\n                        {\n                            // Check to see if there is already an event for this change. Only add this event\n                            //  to the generated list if it is completely unique.\n                            auto foundEvent = std::find_if(m_eventsToProcess.begin(), m_eventsToProcess.end(),\n                                [&generatedEvent](const XblAchievementsManagerEvent& elem)->bool\n                                {\n                                    if (generatedEvent.eventType != elem.eventType)\n                                    {\n                                        return false;\n                                    }\n                                    if (generatedEvent.progressInfo.achievementId != elem.progressInfo.achievementId)\n                                    {\n                                        return false;\n                                    }\n                                    if (generatedEvent.progressInfo.progressState != elem.progressInfo.progressState)\n                                    {\n                                        return false;\n                                    }\n                                    auto& cachedProgression = elem.progressInfo.progression;\n                                    auto& eventProgression = generatedEvent.progressInfo.progression;\n                                    if (eventProgression.timeUnlocked != cachedProgression.timeUnlocked)\n                                    {\n                                        return false;\n                                    }\n                                    if (eventProgression.requirementsCount != cachedProgression.requirementsCount)\n                                    {\n                                        return false;\n                                    }\n                                    for (uint32_t i = 0; i < eventProgression.requirementsCount; ++i)\n                                    {\n                                        auto& eventRequirement = eventProgression.requirements[i];\n                                        auto& cachedRequirement = cachedProgression.requirements[i];\n\n                                        // If the requirement IDs are different between events for the same achievement, then this is a \n                                        //  unique progress update. If the target progress values are different, then they are also unique,\n                                        //  however it likely means that there was a modification to the requirement on the achievement service\n                                        //  (which is unlikely to happen with a released game).\n                                        if (((String)eventRequirement.id != (String)cachedRequirement.id ||\n                                            (String)eventRequirement.targetProgressValue != (String)cachedRequirement.targetProgressValue))\n                                        {\n                                            return false;\n                                        }\n\n                                        // Only recognize this as a unique event if the events current progress is greater than the caches.\n                                        if (!ShouldUpdateProgress(eventRequirement.currentProgressValue, cachedRequirement.currentProgressValue))\n                                        {\n                                            return false;\n                                        }\n                                    }\n                                    return true;\n                                }\n                            );\n\n                            // Event is unique, so push it onto the list of events to process.\n                            if (foundEvent == m_eventsToProcess.end())\n                            {\n                                m_generatedEvents.push_back(generatedEvent);\n                            }\n                        }\n                    }\n                    continue;\n                }\n                fetchedAchievements.push_back(AchievementsManager::DeepCopyAchievement(achievement));\n            }\n        }\n\n        if (result.Payload()->HasNext())\n        {\n            result.Payload()->GetNext(\n                achievementsPerFetch,\n                AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>>{ async.Queue(),\n                [\n                    async,\n                    achievementsPerFetch,\n                    weakThis = std::weak_ptr<AchievementsManagerUser>(shared_from_this()),\n                    fetchedAchievements\n                ]\n            (Result<std::shared_ptr<XblAchievementsResult>> result)\n            {\n                auto sharedThis{ weakThis.lock() };\n                if (sharedThis)\n                {\n                    sharedThis->HandleAchievementsResults(result, achievementsPerFetch, async, fetchedAchievements);                \n                }\n            }\n            });\n        }\n        else\n        {\n            if (!m_isInitialized)\n            {\n                size_t achievementCount = fetchedAchievements.size();\n                m_achievementCache = MakeArray<XblAchievement>(achievementCount);\n                for (size_t index = 0; index < achievementCount; ++index)\n                {\n                    m_achievementCache[index] = fetchedAchievements[index];\n                    m_userAchievements[m_achievementCache[index].id] = m_achievementCache + index;\n                }\n            }\n            async.Complete(result.Hresult());\n        }\n    }\n    else\n    {\n        LOGS_ERROR << \"Failed to fetch current state of achievements for user \" << m_xuid << \" with error code \" << result.Hresult();\n        async.Complete(result.Hresult());\n    }\n    return S_OK;\n}\n\n//////////////////////////////////////////////////////////\n\nXblAchievement AchievementsManager::CopyAchievementForResult(const XblAchievement& other)\n{\n    // Most values that are dynamically allocated when creating the \n    //  original achievement struct should not change between frames,\n    //  so it is okay if we do shallow copies for those values.\n    XblAchievement copy\n    {\n        other.id,\n        other.serviceConfigurationId,\n        other.name,\n        other.titleAssociations,    // title associations\n        other.titleAssociationsCount,\n        other.progressState,\n        other.progression,  // need to do a deep copy of this\n        other.mediaAssets,    // media assets\n        other.mediaAssetsCount,\n        other.platformsAvailableOn,    // platforms available on\n        other.platformsAvailableOnCount,\n        other.isSecret,\n        other.unlockedDescription,\n        other.lockedDescription,\n        other.productId,\n        other.type,\n        other.participationType,\n        other.available,\n        other.rewards,    // rewards\n        other.rewardsCount,\n        other.estimatedUnlockTime,\n        other.deepLink,\n        other.isRevoked\n    };\n\n    // Need to do a deep copy of progression so that, if progress values change\n    //  while the title is still using a result from a prior frame, we do not\n    //  invalidate the memory that the requirement is using. \n    copy.progression.requirements = MakeArray<XblAchievementRequirement>(copy.progression.requirementsCount);\n    XblAchievementRequirement* sourceRequirements = other.progression.requirements;\n    for (uint64_t i = 0; i < copy.progression.requirementsCount; ++i)\n    {\n        copy.progression.requirements[i] = XblAchievementRequirement{\n            sourceRequirements[i].id,\n            Make(sourceRequirements[i].currentProgressValue),\n            sourceRequirements[i].targetProgressValue\n        };\n    }\n\n    return copy;\n}\n\nHRESULT AchievementsManager::CleanUpAchievementCopyForResult(XblAchievement& achievement)\n{\n    for (uint64_t i = 0; i < achievement.progression.requirementsCount; ++i)\n    {\n        XblAchievementRequirement& requirement = achievement.progression.requirements[i];\n        Delete(requirement.currentProgressValue);\n    }\n    DeleteArray(achievement.progression.requirements, achievement.progression.requirementsCount);\n\n    return S_OK;\n}\n\nXblAchievement AchievementsManager::DeepCopyAchievement(_In_ const XblAchievement & other)\n{\n    XblAchievement copy\n    {\n        Make(other.id),\n        Make(other.serviceConfigurationId),\n        Make(other.name),\n        nullptr,    // title associations\n        other.titleAssociationsCount,\n        other.progressState,\n        other.progression,  // need to do a deep copy of this\n        nullptr,    // media assets\n        other.mediaAssetsCount,\n        nullptr,    // platforms available on\n        other.platformsAvailableOnCount,\n        other.isSecret,\n        Make(other.unlockedDescription),\n        Make(other.lockedDescription),\n        Make(other.productId),\n        other.type,\n        other.participationType,\n        other.available,\n        nullptr,    // rewards\n        other.rewardsCount,\n        other.estimatedUnlockTime,\n        Make(other.deepLink),\n        other.isRevoked\n    };\n\n    // titleAssociations\n    XblAchievementTitleAssociation* associations = MakeArray<XblAchievementTitleAssociation>(copy.titleAssociationsCount);\n    for (uint64_t i = 0; i < copy.titleAssociationsCount; ++i)\n    {\n        associations[i] = XblAchievementTitleAssociation{\n            Make(other.titleAssociations[i].name),\n            other.titleAssociations[i].titleId\n        };\n    }\n    copy.titleAssociations = associations;\n\n    // deep copy progression\n    copy.progression.requirements = MakeArray<XblAchievementRequirement>(copy.progression.requirementsCount);\n    XblAchievementRequirement* sourceRequirements = other.progression.requirements;\n    for (uint64_t i = 0; i < copy.progression.requirementsCount; ++i)\n    {\n        copy.progression.requirements[i] = XblAchievementRequirement{\n            Make(sourceRequirements[i].id),\n            Make(sourceRequirements[i].currentProgressValue),\n            Make(sourceRequirements[i].targetProgressValue)\n        };\n    }\n\n    auto CloneMediaAsset = [](const XblAchievementMediaAsset& arg)->XblAchievementMediaAsset\n    {\n        return XblAchievementMediaAsset{\n            arg.name ? Make(arg.name) : nullptr,\n            arg.mediaAssetType,\n            arg.url ? Make(arg.url) : nullptr\n        };\n    };\n    // media assets\n    XblAchievementMediaAsset* assets = MakeArray<XblAchievementMediaAsset>(copy.mediaAssetsCount);\n    for (uint64_t i = 0; i < copy.mediaAssetsCount; ++i)\n    {\n        assets[i] = CloneMediaAsset(other.mediaAssets[i]);        \n    }\n    copy.mediaAssets = assets;\n\n    // platforms\n    Vector<String> platforms(other.platformsAvailableOn, other.platformsAvailableOn + other.platformsAvailableOnCount);\n    copy.platformsAvailableOn = const_cast<const char**>(MakeArray(platforms));\n\n    // rewards\n    XblAchievementReward* rewards = MakeArray<XblAchievementReward>(copy.rewardsCount);\n    for (uint64_t i = 0; i < copy.rewardsCount; ++i)\n    {\n        rewards[i] = XblAchievementReward{\n            Make(other.rewards[i].name),\n            Make(other.rewards[i].description),\n            Make(other.rewards[i].value),\n            other.rewards[i].rewardType,\n            Make(other.rewards[i].valueType),\n            nullptr\n        };\n        if (other.rewards[i].mediaAsset != nullptr)\n        {\n            rewards[i].mediaAsset = Make<XblAchievementMediaAsset>(\n                CloneMediaAsset(*other.rewards[i].mediaAsset)\n            );\n        }\n    }\n    copy.rewards = rewards;\n    return copy;\n}\n\nXblAchievement* AchievementsManager::DeepCopyAchievements(XblAchievement* cache, size_t size)\n{\n    XblAchievement* copiedArray = MakeArray<XblAchievement>(cache, size);\n    memcpy(copiedArray, cache, sizeof(XblAchievement)*size);\n    \n    for (size_t index = 0; index < size; ++index)\n    {\n        // Need to do a deep copy of progression so that, if progress values change\n        //  while the title is still using a result from a prior frame, we do not\n        //  invalidate the memory that the requirement is using. \n        copiedArray[index].progression.requirements = MakeArray<XblAchievementRequirement>(copiedArray[index].progression.requirementsCount);\n        XblAchievementRequirement* sourceRequirements = cache[index].progression.requirements;\n        for (uint64_t i = 0; i < copiedArray[index].progression.requirementsCount; ++i)\n        {\n            copiedArray[index].progression.requirements[i] = XblAchievementRequirement{\n                sourceRequirements[i].id,\n                Make(sourceRequirements[i].currentProgressValue),\n                sourceRequirements[i].targetProgressValue\n            };\n        }\n    }\n    return copiedArray;\n}\n\nVector<XblAchievement> AchievementsManager::DeepCopyAchievements(const Vector<XblAchievement>& achievements)\n{\n    Vector<XblAchievement> achievementsCopy;\n    for (const auto& source : achievements)\n    {\n        achievementsCopy.push_back(CopyAchievementForResult(source));\n    }\n    return achievementsCopy;\n}\n\nHRESULT AchievementsManager::CleanUpDeepCopyAchievement(_In_ XblAchievement& achievement)\n{\n    Delete(achievement.id);\n    Delete(achievement.serviceConfigurationId);\n    Delete(achievement.name);\n    \n    for (uint64_t i = 0; i < achievement.titleAssociationsCount; ++i)\n    {\n        Delete(achievement.titleAssociations[i].name);\n    }\n    DeleteArray(achievement.titleAssociations, achievement.titleAssociationsCount);\n    \n    for (uint64_t i = 0; i < achievement.progression.requirementsCount; ++i)\n    {\n        XblAchievementRequirement& requirement = achievement.progression.requirements[i];\n        Delete(requirement.id);\n        Delete(requirement.currentProgressValue);\n        Delete(requirement.targetProgressValue);\n    }\n    DeleteArray(achievement.progression.requirements, achievement.progression.requirementsCount);\n        \n    for (uint64_t i = 0; i < achievement.mediaAssetsCount; ++i)\n    {\n        XblAchievementMediaAsset& asset = achievement.mediaAssets[i];\n        if (asset.name)\n        {\n            Delete(asset.name);\n        }\n        if (asset.url)\n        {\n            Delete(asset.url);\n        }\n    }\n    DeleteArray(achievement.mediaAssets, achievement.mediaAssetsCount);\n    \n    DeleteArray(achievement.platformsAvailableOn, achievement.platformsAvailableOnCount);\n\n    Delete(achievement.unlockedDescription);\n    Delete(achievement.lockedDescription);\n    Delete(achievement.productId);\n    \n    for (uint64_t i = 0; i < achievement.rewardsCount; ++i)\n    {\n        XblAchievementReward& reward = achievement.rewards[i];\n        Delete(reward.name);\n        Delete(reward.description);\n        Delete(reward.value);\n        Delete(reward.valueType);\n        if (reward.mediaAsset != nullptr)\n        {\n            if (reward.mediaAsset->name)\n            {\n                Delete(reward.mediaAsset->name);\n            }\n            if (reward.mediaAsset->url)\n            {\n                Delete(reward.mediaAsset->url);\n            }\n            Delete(reward.mediaAsset);\n        }\n    }\n    DeleteArray(achievement.rewards, achievement.rewardsCount);\n    \n    Delete(achievement.deepLink);\n    return S_OK;\n}\n\nHRESULT AchievementsManager::AddLocalUser(\n    User&& user, \n    TaskQueue && queue\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto xuid{ user.Xuid() };\n    if (m_localUsers.find(xuid) != m_localUsers.end())\n    {\n        LOGS_ERROR << \"User \" << xuid << \" already added to AchievementsManager\";\n        return E_UNEXPECTED;\n    }\n\n    auto localUser = MakeShared<AchievementsManagerUser>(std::move(user), queue);\n\n    Result<void> result = localUser->Initialize(AsyncContext<HRESULT>{\n        [\n            sharedThis{ shared_from_this() },\n            weakUser = std::weak_ptr<AchievementsManagerUser>{ localUser->shared_from_this() }\n        ]\n        (HRESULT hr)\n        {\n            auto user{ weakUser.lock() };\n            if (FAILED(hr))\n            {\n                LOGS_WARN << \"Failed to initialize local user online with ID \" << user->Xuid() << \" with error code \" << hr;\n            }\n\n            std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n            if (user)\n            {\n                XblAchievementsManagerEvent userAddedEvent{ {}, user->Xuid(), XblAchievementsManagerEventType::LocalUserInitialStateSynced };\n                sharedThis->m_pendingEvents.push_back(userAddedEvent);\n            }\n        }\n    });\n\n    if (Succeeded(result))\n    {\n        m_localUsers[xuid] = localUser;\n    }\n\n    return result.Hresult();\n}\n\nHRESULT AchievementsManager::RemoveLocalUser(\n    _In_ const User & user\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto userIter{ m_localUsers.find(user.Xuid()) };\n    if (userIter == m_localUsers.end())\n    {\n        LOGS_ERROR << \"User \" << user.Xuid() << \" was not added to AchievementsManager\";\n        return E_BOUNDS;\n    }\n\n    m_localUsers.erase(userIter);\n    m_localUsers.erase(user.Xuid());\n\n    return S_OK;\n}\n\nconst Vector<XblAchievementsManagerEvent>& AchievementsManager::DoWork() XBL_NOEXCEPT\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    // Clean up the allocations made when doing the copy of the progress entry\n    //  for the event.\n    for (auto& event : m_publishedEvents)\n    {\n        AchievementProgressChangeSubscription::CleanUpProgressChangeEntry(event.progressInfo);\n    }\n\n    m_publishedEvents = std::move(m_pendingEvents);\n    for (auto& pair : m_localUsers)\n    {\n        auto& user{ pair.second };\n        auto achievementEvents = user->ProcessEvents();\n        m_publishedEvents.insert(m_publishedEvents.end(), achievementEvents.begin(), achievementEvents.end());\n    }\n\n    m_pendingEvents.clear();\n\n    return m_publishedEvents;\n}\n\nResult<XblAchievement> AchievementsManager::GetAchievement(\n    _In_ uint64_t xuid,\n    _In_ const String achievementId\n)\n{\n    if (m_localUsers.find(xuid) == m_localUsers.end())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet registered with AchievementsManager.\", static_cast<unsigned long long>(xuid));\n        return { E_BOUNDS, errorMsg};\n    }\n    if (!m_localUsers[xuid]->IsInitialized())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet initialized.\", static_cast<unsigned long long>(xuid));\n        return { E_UNEXPECTED, errorMsg};\n    }\n    \n    return m_localUsers[xuid]->GetAchievement(achievementId);\n}\n\nResult<std::pair<XblAchievement*, size_t>> AchievementsManager::GetAchievements(_In_ uint64_t xuid)\n{\n    if (m_localUsers.find(xuid) == m_localUsers.end())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet registered with AchievementsManager.\", static_cast<unsigned long long>(xuid));\n        return { E_BOUNDS, errorMsg };\n    }\n    if (!m_localUsers[xuid]->IsInitialized())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet initialized.\", static_cast<unsigned long long>(xuid));\n        return { E_UNEXPECTED, errorMsg };\n    }\n    \n    return std::pair<XblAchievement*, size_t>({ m_localUsers[xuid]->GetAchievements() , m_localUsers[xuid]->GetAchievementCount() });\n}\n\nResult<Vector<XblAchievement>> AchievementsManager::GetAchievements(\n    _In_ uint64_t xuid,\n    _In_ AchievementsManagerSortFilterSettings requestConfig\n)\n{\n    if (m_localUsers.find(xuid) == m_localUsers.end())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet registered with AchievementsManager.\", static_cast<unsigned long long>(xuid));\n        return { E_BOUNDS, errorMsg };\n    }\n    if (!m_localUsers[xuid]->IsInitialized())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet initialized.\", static_cast<unsigned long long>(xuid));\n        return { E_UNEXPECTED, errorMsg };\n    }\n    \n    return m_localUsers[xuid]->GetAchievements(requestConfig);\n}\n\nResult<void> AchievementsManager::UpdateAchievement(\n    _In_ uint64_t xuid,\n    _In_ const String achievementId,\n    _In_ uint8_t progress\n)\n{\n    if (m_localUsers.find(xuid) == m_localUsers.end())\n    {\n        char errorMsg[1024];\n        SPRINTF(errorMsg, 1024, \"User with ID %llu not yet registered with AchievementsManager.\", static_cast<unsigned long long>(xuid));\n        return { E_BOUNDS, errorMsg };\n    }\n\n    std::shared_ptr<AchievementsManagerUser> localUser = m_localUsers[xuid];\n    auto isAchievementUpdateable = localUser->CanUpdateAchievement(achievementId, progress);\n    if (Failed(isAchievementUpdateable))\n    {\n        return isAchievementUpdateable;\n    }\n    \n    return localUser->UpdateAchievement(achievementId, progress);\n}\n\nbool AchievementsManager::HasUser(_In_ uint64_t xuid) const\n{\n    return m_localUsers.find(xuid) != m_localUsers.end();\n}\n\nbool AchievementsManager::IsUserInitialized(_In_ uint64_t xuid)\n{\n    return m_localUsers[xuid]->IsInitialized();\n}\n\nuint64_t AchievementsManager::GetUserAchievementCount(_In_ uint64_t xuid)\n{\n    return m_localUsers[xuid]->GetAchievementCount();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_END\n\n\n"
  },
  {
    "path": "Source/Services/Achievements/Manager/achievements_manager_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/achievements_manager_c.h\"\n#include \"achievements_internal.h\"\n\nnamespace xbox {\nnamespace services {\nnamespace achievements {\nnamespace manager {\n\nclass AchievementsManager;\n\n}\n}\n}\n}\n\nstruct XblAchievementsManagerResult : public xbox::services::RefCounter, public std::enable_shared_from_this<XblAchievementsManagerResult>\n{\npublic: \n    XblAchievementsManagerResult(_In_ const XblAchievement& achievement);\n    XblAchievementsManagerResult(_In_ Vector<XblAchievement>& achievements, _In_ bool explicitCleanup = false);\n    XblAchievementsManagerResult(_In_ XblAchievement* achievements, _In_ size_t achievementCount, _In_ bool explicitCleanup = false);\n    virtual ~XblAchievementsManagerResult();\n\n    const Vector<XblAchievement>& Achievements() const;\n    \nprotected:\n    // RefCounter\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override;\n\nprivate:\n    XblAchievementsManagerResult(const XblAchievementsManagerResult& other) = delete;\n    XblAchievementsManagerResult& operator=(XblAchievementsManagerResult other) = delete;\n\n    Vector<XblAchievement> m_achievements;\n    XblAchievement* m_achievementsData;\n    size_t m_achievementsCount;\n    bool m_explicitCleanup;\n};\n\n/// <summary>\n/// Enumeration values that indicate the lock state of an achievement.\n/// </summary>\n/// <memof><see cref=\"XblAchievement\"/></memof>\nenum class AchievementsManagerFilterType : uint32_t\n{\n    /// <summary>\n    /// Specifies both locked and unlocked achievements to be included.\n    /// </summary>\n    All = 0,\n\n    /// <summary>\n    /// Specifies that unlocked achievements should be included.\n    /// </summary>\n    Unlocked = 1,\n\n    /// <summary>\n    ///  Specifies that achievements with no progress should be included.\n    /// </summary>\n    NotStarted = 2, \n\n    /// <summary>\n    ///  Specifies that achievements currently in progress should be included.\n    /// </summary>\n    InProgress = 3,\n};\n\n/// <summary>\n/// Collection of options used to customise the subset of achievements \n/// to return back to the caller.\n/// </summary>\nstruct AchievementsManagerSortFilterSettings\n{\n    /// <summary>\n    /// The field to sort the list of achievements on. TitleId will behave\n    /// the same as DefaultOrder, as AchievementsManager only handles one title\n    /// at a time.\n    /// </summary>\n    XblAchievementOrderBy sortBy;\n\n    /// <summary>\n    /// The direction by which to sort the list of achievements.\n    /// </summary>\n    XblAchievementsManagerSortOrder sortOrder;\n\n    /// <summary>\n    /// The achievement state to include in the list of achievements.\n    /// </summary>\n    AchievementsManagerFilterType stateFilter;\n} ;\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_BEGIN\n\nclass AchievementsManagerUser : public std::enable_shared_from_this<AchievementsManagerUser>\n{\npublic:\n    AchievementsManagerUser(\n        _In_ User&& localUser,\n        _In_ const TaskQueue& queue\n    ) noexcept;\n    virtual ~AchievementsManagerUser();\n\n    Result<void> Initialize(\n        _In_ AsyncContext<HRESULT> async\n    );\n    \n    bool IsInitialized() const;\n    uint64_t Xuid() const;\n    uint64_t GetAchievementCount() const;\n\n    Vector<XblAchievementsManagerEvent> ProcessEvents();\n\n    Result<XblAchievement> GetAchievement(\n        _In_ const String& id\n    );\n    \n    XblAchievement* GetAchievements();\n    Vector<XblAchievement> GetAchievements(\n        _In_ AchievementsManagerSortFilterSettings sortFilterSettings\n    );\n    \n    Result<void> CanUpdateAchievement(\n        _In_ const String& achievementId, \n        _In_ uint8_t percent\n    );\n    \n    Result<void> UpdateAchievement(\n        _In_ const String& achievementId, \n        _In_ uint8_t percent\n    );\n\nprivate:\n\n    HRESULT FetchAchievements(\n        _In_ AsyncContext<HRESULT> async\n    );\n    \n    HRESULT HandleAchievementsResults(\n        _In_ Result<std::shared_ptr<XblAchievementsResult>> result,\n        _In_ uint32_t achievementsPerFetch,\n        _In_ AsyncContext<HRESULT> async,\n        _In_ Vector<XblAchievement> fetchedAchievements = Vector<XblAchievement>()\n    );\n\n    std::mutex m_mutex;\n    bool m_isInitialized = false;\n    bool m_isFetchingAchievements = true;\n\n    Map<String, XblAchievement*> m_userAchievements;\n    XblAchievement* m_achievementCache{ nullptr };\n    uint64_t m_xuid{ 0 };\n   \n    Vector<XblAchievementsManagerEvent> m_eventsToProcess;\n    Vector<XblAchievementsManagerEvent> m_generatedEvents;\n\n    std::shared_ptr<XblContext> m_xblContext;\n    \n    XblFunctionContext m_achievementProgressToken{ 0 };\n    XblFunctionContext m_rtaResyncToken{ 0 };\n    XblFunctionContext m_rtaConnectionToken{ 0 };\n    \n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n    \n    TaskQueue m_queue;\n};\n\nclass AchievementsManager : public std::enable_shared_from_this<AchievementsManager>\n{\npublic:\n    AchievementsManager() = default;\n\n    // In this case, The object returned from this function is mostly a shallow \n    //  copy of the argument, as most values in an XblAchievement don't change\n    //  during gameplay. The ones that do will be deep copied. Should only\n    //  be called \n    static XblAchievement CopyAchievementForResult(const XblAchievement & other);\n    static HRESULT CleanUpAchievementCopyForResult(XblAchievement & achievement);\n\n    // Deep copy makes dynamic allocations so that the object can be completely \n    //  detatched from the original object. Requires parts of the object to be \n    //  manually deallocated.\n    static XblAchievement DeepCopyAchievement(_In_ const XblAchievement& other);\n    static Vector<XblAchievement> DeepCopyAchievements(const Vector<XblAchievement>& achievements);\n    static XblAchievement* DeepCopyAchievements(XblAchievement* cache, size_t size);\n\n    // Helper function that aids in freeing the dynamically allocated memory used \n    //  when creating a deep copy of an achievement. \n    static HRESULT CleanUpDeepCopyAchievement(_In_ XblAchievement& achievement);\n    \n    HRESULT AddLocalUser(\n        _In_ User&& user,\n        _In_ TaskQueue&& queue\n    ) noexcept;\n\n    HRESULT RemoveLocalUser(\n        _In_ const User& user\n    ) noexcept;\n\n    const Vector<XblAchievementsManagerEvent>& DoWork() XBL_NOEXCEPT;\n\n    Result<XblAchievement> GetAchievement(\n        _In_ uint64_t xuid, \n        _In_ const String achievementId\n    );\n\n    Result<std::pair<XblAchievement*, size_t>> GetAchievements(\n        _In_ uint64_t xuid\n    );\n\n    Result<Vector<XblAchievement>> GetAchievements(\n        _In_ uint64_t xuid,\n        _In_ AchievementsManagerSortFilterSettings requestConfig\n    );\n\n    Result<void> UpdateAchievement(\n        _In_ uint64_t xuid,\n        _In_ const String achievementId,\n        _In_ uint8_t progress\n    );\n    \n    bool HasUser(\n        _In_ uint64_t xuid\n    ) const;\n    \n    bool IsUserInitialized(\n        _In_ uint64_t xuid\n    );\n    \n    uint64_t GetUserAchievementCount(\n        _In_ uint64_t xuid\n    );\n\nprivate:\n    \n    std::mutex m_mutex;\n    Vector<XblAchievementsManagerEvent> m_publishedEvents;\n    Vector<XblAchievementsManagerEvent> m_pendingEvents;\n    Map<uint64_t, std::shared_ptr<AchievementsManagerUser>> m_localUsers;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Achievements/achievement_service_internal.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"achievements_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"xsapi-c/errors_c.h\"\n\n#include \"real_time_activity_manager.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n#pragma pack(push, 16)\n#include \"EtwPlus.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_BEGIN\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n\nEXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR XSAPI_Update_Achievement_Fields[5] =\n{\n    { EtxFieldType_UnicodeString,0 },\n    { EtxFieldType_UnicodeString,0 },\n    { EtxFieldType_GUID,0 },\n    { EtxFieldType_UnicodeString,0 },\n    { EtxFieldType_UInt32,0 }\n};\n\nEXTERN_C __declspec(selectany) ETX_EVENT_DESCRIPTOR XSAPI_Update_Achievement_Events[1] =\n{\n    {\n        { 1, 1, 0, 0, 0, 0, 0x0 },\n        \"AchievementUpdate\",\n        \"0.7.IGAU-1.0\",\n        XSAPI_Update_Achievement_Fields,\n        5,\n        0,\n        EtxEventEnabledState_Undefined,\n        EtxEventEnabledState_ProviderDefault,\n        EtxPopulationSample_Undefined,\n        EtxPopulationSample_UseProviderPopulationSample,\n        EtxEventLatency_Undefined,\n        EtxEventLatency_ProviderDefault,\n        EtxEventPriority_Undefined,\n        EtxEventPriority_ProviderDefault\n    }\n};\n\nEXTERN_C __declspec(selectany) REGHANDLE XSAPI_Update_Achievement_Handle = (REGHANDLE)0;\n\nEXTERN_C __declspec(selectany) ETX_PROVIDER_DESCRIPTOR XSAPI_Update_Achievement_Provider =\n{\n    \"\",\n    { 0 },\n    1,\n    (ETX_EVENT_DESCRIPTOR*)&XSAPI_Update_Achievement_Events,\n    0,\n    EtxProviderEnabledState_Undefined,\n    EtxProviderEnabledState_OnByDefault,\n    0,\n    100,\n    EtxProviderLatency_Undefined,\n    EtxProviderLatency_RealTime,\n    EtxProviderPriority_Undefined,\n    EtxProviderPriority_Critical\n};\n#endif\n\nAchievementsService::AchievementsService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<AppConfig> appConfig,\n    _In_ std::weak_ptr<XblContext> xboxLiveContextImpl,\n    _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n) :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings{ std::move(xboxLiveContextSettings) },\n    m_appConfig{ std::move(appConfig) },\n    m_rtaManager{ std::move(rtaManager) },\n    m_xboxLiveContextImpl{ std::move(xboxLiveContextImpl) }\n{\n}\n\nHRESULT AchievementsService::UpdateAchievement(\n    _In_ uint64_t xboxUserId,\n    _In_ const String& achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ AsyncContext<Result<void>> async\n) const noexcept\n{\n    return UpdateAchievement(\n        xboxUserId,\n        m_appConfig->TitleId(),\n        m_appConfig->Scid(),\n        achievementId,\n        percentComplete,\n        std::move(async)\n    );\n}\n\nHRESULT AchievementsService::UpdateAchievement(\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t titleId,\n    _In_ const String& scid,\n    _In_ const String& achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ AsyncContext<Result<void>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(titleId == 0);\n    RETURN_HR_INVALIDARGUMENT_IF(scid.empty());\n    RETURN_HR_INVALIDARGUMENT_IF(achievementId.empty());\n    RETURN_HR_INVALIDARGUMENT_IF(percentComplete > 100);\n\n    // Achievements service is doing case sensitive comparison on scid and always expects it to be lower case\n    String lowercaseScid = utils::ToLower(scid);\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    {\n        auto state = GlobalState::Get();\n        if (!state)\n        {\n            return E_XBL_NOT_INITIALIZED;\n        }\n        // Register ETX provider if it hasn't been registered yet\n        if (XSAPI_Update_Achievement_Handle == 0)\n        {\n            string_t wScid = utils::string_t_from_internal_string(lowercaseScid);\n            std::error_code errC = utils::guid_from_string(wScid, const_cast<GUID*>(&XSAPI_Update_Achievement_Provider.Guid), false);\n            if (errC)\n            {\n                return utils::convert_xbox_live_error_code_to_hresult(errC);\n            }\n\n            XSAPI_Update_Achievement_Provider.Name = state->AchievementsProviderName().data();\n\n            ULONG errorCode = EtxRegister(&XSAPI_Update_Achievement_Provider, &XSAPI_Update_Achievement_Handle);\n            RETURN_HR_IF_FAILED(HRESULT_FROM_WIN32(errorCode));\n        }\n    }\n#endif\n\n    Stringstream subPath;\n    subPath << (\"/users/xuid(\") << xboxUserId << (\")/achievements/\") << lowercaseScid << (\"/update\");\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"achievements\", subPath.str()),\n        xbox_live_api::update_achievement\n    );\n    RETURN_HR_IF_FAILED(hr);\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(2));\n\n    JsonDocument request(rapidjson::kObjectType);\n    JsonDocument::AllocatorType& allocator = request.GetAllocator();\n\n    JsonValue achievementJson(rapidjson::kObjectType);\n    achievementJson.AddMember(\"id\", JsonValue (achievementId.c_str(), allocator).Move(), allocator);\n    achievementJson.AddMember(\"percentComplete\", percentComplete, allocator);\n\n    JsonValue achievementsJson = JsonValue(rapidjson::kArrayType);\n    achievementsJson.PushBack(achievementJson, allocator);\n\n    request.AddMember(\"action\", \"progressUpdate\", allocator);\n    request.AddMember(\"serviceConfigId\", JsonValue(lowercaseScid.c_str(), allocator).Move(), allocator);\n    request.AddMember(\"titleId\", titleId, allocator);\n    request.AddMember(\"userId\", JsonValue(utils::uint64_to_internal_string(xboxUserId).c_str(), allocator).Move(), allocator);\n    request.AddMember(\"achievements\", achievementsJson, allocator);\n\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(request)));\n\n    hr = httpCall->Perform(AsyncContext<HttpResult>{\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async,\n            achievementId,\n            percentComplete,\n            xboxLiveContext{ m_xboxLiveContextImpl.lock() }\n        ]\n    (HttpResult httpResult)\n    {\n        bool shouldWriteOffline{ false };\n        HRESULT hrHttp{ S_OK };\n\n        // Errors from the task include auth errors when getting the token and sig\n        HRESULT hrTask = httpResult.Hresult();\n\n        auto xblConditionTask = XblGetErrorCondition(hrTask);\n        if (xblConditionTask == XblErrorCondition::Network ||\n            xblConditionTask == XblErrorCondition::Auth ||\n            xblConditionTask == XblErrorCondition::GenericError)\n        {\n            shouldWriteOffline = true;\n        }\n\n        if (SUCCEEDED(hrTask) && httpResult.Payload())\n        {\n            // Errors from the http stack include network errors \n            hrHttp = httpResult.Payload()->Result();\n            auto xblConditionHttp = XblGetErrorCondition(hrHttp);\n\n            // The HTTP status code\n            auto statusCode = httpResult.Payload()->HttpStatus();\n\n            if (xblConditionHttp == XblErrorCondition::Network ||\n                xblConditionHttp == XblErrorCondition::Auth ||\n                xblConditionHttp == XblErrorCondition::Http429TooManyRequests ||\n                xblConditionHttp == XblErrorCondition::GenericError ||\n                (statusCode >= 500 && statusCode < 600))\n            {\n                shouldWriteOffline = true;\n            }\n        }\n\n        // If any error or HTTP status code falls into one of these known buckets, \n        // then write the achievement unlock event so it can be sent when the device is back online\n        // even if the game isn't running\n        if (shouldWriteOffline && xboxLiveContext)\n        {\n            async.Complete(WriteOfflineUpdateAchievement(\n                xboxLiveContext,\n                achievementId,\n                percentComplete\n            ));\n        }\n        else\n        {\n            async.Complete(FAILED(hrTask) ? hrTask : hrHttp);\n        }\n    }\n    });\n\n    return hr;\n}\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n\nULONG AchievementsService::EventWriteAchievementUpdate(\n    _In_ PCWSTR userId,\n    _In_ PCWSTR achievementId,\n    _In_ const uint32_t percentComplete\n)\n{\n    if (achievementId == nullptr) return ERROR_BAD_ARGUMENTS;\n    if (userId == nullptr) return ERROR_BAD_ARGUMENTS;\n\n    static const uint32_t EventWriteAchievementUpdate_ArgCount = 5;\n    static const uint32_t EventWriteAchievementUpdate_ScratchSize = 64;\n    EVENT_DATA_DESCRIPTOR eventData[EventWriteAchievementUpdate_ArgCount] = { 0 };\n    UINT8 scratch[EventWriteAchievementUpdate_ScratchSize] = { 0 };\n\n    EtxFillCommonFields_v7(&eventData[0], scratch, EventWriteAchievementUpdate_ScratchSize);\n\n    EventDataDescCreate(&eventData[1], userId, (ULONG)((wcslen(userId) + 1) * sizeof(WCHAR)));\n    EventDataDescCreate(&eventData[2], &GlobalState::Get()->AchievementsSessionId(), sizeof(GUID));\n    EventDataDescCreate(&eventData[3], achievementId, (ULONG)((wcslen(achievementId) + 1) * sizeof(WCHAR)));\n    EventDataDescCreate(&eventData[4], &percentComplete, sizeof(percentComplete));\n\n    return EtxEventWrite(\n        &XSAPI_Update_Achievement_Events[0],\n        &XSAPI_Update_Achievement_Provider,\n        XSAPI_Update_Achievement_Handle,\n        EventWriteAchievementUpdate_ArgCount,\n        eventData\n    );\n}\n\nHRESULT\nAchievementsService::WriteOfflineUpdateAchievement(\n    _In_ std::shared_ptr<XblContext> xboxLiveContextImpl,\n    _In_ const String& achievementId,\n    _In_ uint32_t percentComplete\n)\n{\n    ULONG errorCode = EventWriteAchievementUpdate(\n        utils::uint64_to_string_t(xboxLiveContextImpl->Xuid()).c_str(),\n        convert::utf8_to_utf16(achievementId).c_str(),\n        percentComplete\n    );\n    HRESULT hr = HRESULT_FROM_WIN32(errorCode);\n    return hr;\n}\n\n#else\n\nHRESULT AchievementsService::WriteOfflineUpdateAchievement(\n    _In_ std::shared_ptr<XblContext> xboxLiveContextImpl,\n    _In_ const String& achievementId,\n    _In_ uint32_t percentComplete\n)\n{\n    JsonDocument properties(rapidjson::kObjectType);\n    properties.AddMember(\"AchievementId\", JsonValue(achievementId.c_str(), properties.GetAllocator()).Move(), properties.GetAllocator());\n    properties.AddMember(\"PercentComplete\", percentComplete, properties.GetAllocator());\n    auto propertiesStrUtf8 = JsonUtils::SerializeJson(properties);\n#ifdef XSAPI_EVENTS_SERVICE\n    HRESULT hr = xboxLiveContextImpl->EventsService()->WriteInGameEvent(\"AchievementUpdate\", propertiesStrUtf8.c_str(), nullptr);\n#else // aka XSAPI_UNIT_TESTS\n    HRESULT hr = E_FAIL; \n    UNREFERENCED_PARAMETER(propertiesStrUtf8);\n#endif\n    return hr;\n}\n#endif\n\nHRESULT AchievementsService::GetAchievementsForTitle(\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t titleId,\n    _In_ XblAchievementType type,\n    _In_ bool unlockedOnly,\n    _In_ XblAchievementOrderBy orderBy,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>> async\n) const noexcept\n{\n    return GetAchievements(\n        xboxUserId,\n        Vector<uint32_t>{ titleId },\n        type,\n        unlockedOnly,\n        orderBy,\n        skipItems,\n        maxItems,\n        String{},\n        std::move(async)\n    );\n}\n\nHRESULT AchievementsService::GetAchievement(\n    _In_ uint64_t xboxUserId,\n    _In_ const String& serviceConfigurationId,\n    _In_ const String& achievementId,\n    _In_ AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(serviceConfigurationId.empty());\n    RETURN_HR_INVALIDARGUMENT_IF(achievementId.empty());\n\n    Stringstream subPath;\n    subPath << (\"/users/xuid(\") << xboxUserId << (\")/achievements/\") << utils::ToLower(serviceConfigurationId) << (\"/\") << achievementId;\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"achievements\", subPath.str()),\n        xbox_live_api::get_achievement\n    );\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(2));\n\n    hr = httpCall->Perform(AsyncContext<HttpResult>{\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async,\n            service{ shared_from_this() }\n        ]\n    (HttpResult httpResult)\n    {\n        HRESULT hr = httpResult.Hresult();\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n        auto result = XblAchievementsResult::Deserialize(httpResult.Payload()->GetResponseBodyJson(), service);\n\n        if (Succeeded(result))\n        {\n            auto& achievements = result.Payload()->Achievements();\n            if (achievements.size() == 1)\n            {\n                async.Complete({ result });\n            }\n            else if (achievements.size() > 1)\n            {\n                LOG_DEBUG(\"get_achievement:Return payload was larger than expected\");\n                async.Complete({ E_UNEXPECTED });\n            }\n            else\n            {\n                LOG_DEBUG(\"get_achievement:The achievement is not found\");\n                async.Complete({ E_UNEXPECTED });\n            }\n        }\n        else\n        {\n            async.Complete({ result.Hresult() });\n        }\n    }\n    });\n\n    return hr;\n}\n\nHRESULT AchievementsService::GetAchievements(\n    _In_ uint64_t xboxUserId,\n    _In_ const Vector<uint32_t>& titleIds,\n    _In_ XblAchievementType type,\n    _In_ bool unlockedOnly,\n    _In_ XblAchievementOrderBy orderBy,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ const String& continuationToken,\n    _In_ AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(type == XblAchievementType::Unknown);\n    \n    auto subPath = GetAchievementsSubpath(\n        xboxUserId,\n        titleIds,\n        type,\n        unlockedOnly,\n        orderBy,\n        skipItems,\n        maxItems,\n        continuationToken\n    );\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"achievements\", subPath),\n        xbox_live_api::get_achievement\n    );\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(2));\n\n    hr = httpCall->Perform(AsyncContext<HttpResult>{\n        async.Queue().DeriveWorkerQueue(),\n        [\n            service{ shared_from_this() },\n            async,\n            xboxUserId,\n            titleIds,\n            type,\n            unlockedOnly,\n            orderBy\n        ]\n    (HttpResult httpResult)\n    {\n        HRESULT hr = httpResult.Hresult();\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        if (!httpResult.Payload()->GetResponseBodyJson().IsNull())\n        {\n            auto result = XblAchievementsResult::Deserialize(httpResult.Payload()->GetResponseBodyJson(), service);\n\n            if (Succeeded(result))\n            {\n                result.Payload()->SetNextPageQueryParameters(\n                    xboxUserId,\n                    titleIds,\n                    static_cast<XblAchievementType>(type),\n                    unlockedOnly,\n                    static_cast<XblAchievementOrderBy>(orderBy)\n                );\n            }\n            async.Complete(result);\n        }\n    }\n    });\n\n    return hr;\n}\n\nXblFunctionContext AchievementsService::AddAchievementProgressChangeHandler(\n    _In_ AchievementProgressChangeHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n\n    if (!m_achievementProgressChangeSubscription)\n    {\n        m_achievementProgressChangeSubscription = MakeShared<AchievementProgressChangeSubscription>(m_user.Xuid(), m_appConfig->Scid());\n        m_rtaManager->AddSubscription(m_user, m_achievementProgressChangeSubscription);\n    }\n    return m_achievementProgressChangeSubscription->AddHandler(std::move(handler));\n}\n\nvoid AchievementsService::RemoveAchievementProgressChangeHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n\n    if (m_achievementProgressChangeSubscription)\n    {\n        if (m_achievementProgressChangeSubscription->RemoveHandler(token) == 0)\n        {\n            m_rtaManager->RemoveSubscription(m_user, m_achievementProgressChangeSubscription);\n            m_achievementProgressChangeSubscription.reset();\n        }\n    }\n}\n\nString AchievementsService::GetAchievementsSubpath(\n    _In_ uint64_t xboxUserId,\n    _In_ const Vector<uint32_t>& titleIds,\n    _In_ XblAchievementType type,\n    _In_ bool unlockedOnly,\n    _In_ XblAchievementOrderBy orderBy,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ const String& continuationToken\n)\n{\n    xbox::services::uri_builder subPathBuilder;\n    Stringstream path;\n    path << (\"/users/xuid(\");\n    path << xboxUserId;\n    path << (\")/achievements\");\n\n    subPathBuilder.append_path(path.str());\n\n    Stringstream titleQuery;\n    auto &last = titleIds.back();\n    for (const auto& titleId : titleIds)\n    {\n        titleQuery << titleId;\n        if (&titleId != &last)\n        {\n            titleQuery << (\",\");\n        }\n    }\n    subPathBuilder.append_query(\"titleId\", titleQuery.str());\n\n    if (type != XblAchievementType::All)\n    {\n        subPathBuilder.append_query(\"types\", EnumName(type));\n    }\n\n    if (unlockedOnly)\n    {\n        subPathBuilder.append_query(\"unlockedOnly=true\");\n    }\n\n    switch (orderBy)\n    {\n    case XblAchievementOrderBy::TitleId:\n    {\n        subPathBuilder.append_query(\"orderBy\", \"title\");\n        break;\n    }\n    case XblAchievementOrderBy::UnlockTime:\n    {\n        subPathBuilder.append_query(\"orderBy\", \"unlocktime\");\n        break;\n    }\n    default: break;\n    }\n\n    utils::append_paging_info(\n        subPathBuilder,\n        skipItems,\n        maxItems,\n        continuationToken\n    );\n\n    return subPathBuilder.to_string();\n}\n\nvoid AchievementsService::CleanupAchievement(XblAchievement& a)\n{\n    Delete(a.id);\n    Delete(a.serviceConfigurationId);\n    Delete(a.name);\n    for (size_t i = 0; i < a.titleAssociationsCount; ++i)\n    {\n        Delete(a.titleAssociations[i].name);\n    }\n    DeleteArray(a.titleAssociations, a.titleAssociationsCount);\n    for (size_t i = 0; i < a.mediaAssetsCount; ++i)\n    {\n        Delete(a.mediaAssets[i].name);\n        Delete(a.mediaAssets[i].url);\n    }\n    DeleteArray(a.mediaAssets, a.mediaAssetsCount);\n    DeleteArray(a.platformsAvailableOn, a.platformsAvailableOnCount);\n    Delete(a.unlockedDescription);\n    Delete(a.lockedDescription);\n    Delete(a.productId);\n    for (size_t i = 0; i < a.rewardsCount; ++i)\n    {\n        Delete(a.rewards[i].name);\n        Delete(a.rewards[i].description);\n        Delete(a.rewards[i].value);\n        Delete(a.rewards[i].valueType);\n        if (a.rewards[i].mediaAsset)\n        {\n            Delete(a.rewards[i].mediaAsset->name);\n            Delete(a.rewards[i].mediaAsset->url);\n        }\n    }\n    DeleteArray(a.rewards, a.rewardsCount);\n    Delete(a.deepLink);\n\n    ZeroMemory(&a, sizeof(XblAchievement));\n}\n\nXblAchievementProgressState ProgressStateFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"Achieved\") == 0)\n    {\n        return XblAchievementProgressState::Achieved;\n    }\n    else if (utils::str_icmp_internal(value, \"NotStarted\") == 0)\n    {\n        return XblAchievementProgressState::NotStarted;\n    }\n    else if (utils::str_icmp_internal(value, \"InProgress\") == 0)\n    {\n        return XblAchievementProgressState::InProgress;\n    }\n\n    return XblAchievementProgressState::Unknown;\n}\n\nXblAchievementType AchievementTypeFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"Persistent\") == 0)\n    {\n        return XblAchievementType::Persistent;\n    }\n    else if (utils::str_icmp_internal(value, \"Challenge\") == 0)\n    {\n        return XblAchievementType::Challenge;\n    }\n\n    return XblAchievementType::Unknown;\n}\n\nXblAchievementParticipationType ParticipationTypeFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"Individual\") == 0)\n    {\n        return XblAchievementParticipationType::Individual;\n    }\n    else if (utils::str_icmp_internal(value, \"Group\") == 0)\n    {\n        return XblAchievementParticipationType::Group;\n    }\n\n    return XblAchievementParticipationType::Unknown;\n}\n\nXblAchievementMediaAssetType MediaAssetTypeFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"Icon\") == 0)\n    {\n        return XblAchievementMediaAssetType::Icon;\n    }\n    else if (utils::str_icmp_internal(value, \"Art\") == 0)\n    {\n        return XblAchievementMediaAssetType::Art;\n    }\n\n    return XblAchievementMediaAssetType::Unknown;\n}\n\nXblAchievementRewardType RewardTypeFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"Gamerscore\") == 0)\n    {\n        return XblAchievementRewardType::Gamerscore;\n    }\n    else if (utils::str_icmp_internal(value, \"InApp\") == 0)\n    {\n        return XblAchievementRewardType::InApp;\n    }\n    else if (utils::str_icmp_internal(value, \"Art\") == 0)\n    {\n        return XblAchievementRewardType::Art;\n    }\n\n    return XblAchievementRewardType::Unknown;\n}\n\nResult<XblAchievementTitleAssociation> AchievementsService::DeserializeTitleAssociation(\n    const JsonValue& json\n)\n{\n    XblAchievementTitleAssociation titleAssociation{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievementTitleAssociation>{ titleAssociation };\n    }\n\n    HRESULT errc = S_OK;\n\n    xsapi_internal_string name;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"name\", name, true));\n    titleAssociation.name = Make(name);\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"id\", titleAssociation.titleId, true));\n\n    return Result<XblAchievementTitleAssociation>{ titleAssociation, errc };\n}\n\n\nResult<XblAchievementRequirement> AchievementsService::DeserializeRequirement(\n    const JsonValue& json\n)\n{\n    XblAchievementRequirement requirement{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievementRequirement>{ requirement };\n    }\n\n    xsapi_internal_string id, current, target;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", id, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"current\", current, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"target\", target, true));\n    requirement.id = Make(id);\n    requirement.currentProgressValue = Make(current);\n    requirement.targetProgressValue = Make(target);\n\n    return Result<XblAchievementRequirement>{ requirement, S_OK };\n}\n\nResult<XblAchievementProgression> AchievementsService::DeserializeProgression(\n    const JsonValue& json\n)\n{\n    XblAchievementProgression progression{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievementProgression>{ progression };\n    }\n\n    HRESULT errc = S_OK;\n\n    xsapi_internal_vector<XblAchievementRequirement> requirementsVector;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblAchievementRequirement>(\n        DeserializeRequirement,\n        json, \"requirements\", requirementsVector, true\n        ));\n\n    progression.requirements = MakeArray(requirementsVector);\n    progression.requirementsCount = requirementsVector.size();\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"timeUnlocked\", progression.timeUnlocked, true));\n\n    return Result<XblAchievementProgression>{ progression, xbox::services::legacy::ConvertHr(errc) };\n}\n\nResult<XblAchievementTimeWindow> AchievementsService::DeserializeTimeWindow(\n    const JsonValue& json\n)\n{\n    XblAchievementTimeWindow timeWindow{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievementTimeWindow>{ timeWindow };\n    }\n\n    HRESULT errc = S_OK;\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"startDate\", timeWindow.startDate, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"endDate\", timeWindow.endDate, true));\n\n    return Result<XblAchievementTimeWindow>{ timeWindow, xbox::services::legacy::ConvertHr(errc) };\n}\n\nResult<XblAchievementMediaAsset> AchievementsService::DeserializeMediaAsset(\n    const JsonValue& json\n)\n{\n    XblAchievementMediaAsset mediaAsset{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievementMediaAsset>{ mediaAsset };\n    }\n\n    xsapi_internal_string name, type, url;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"name\", name, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"type\", type, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"url\", url, true));\n    mediaAsset.name = Make(name);\n    mediaAsset.mediaAssetType = MediaAssetTypeFromString(type);\n    mediaAsset.url = Make(url);\n\n    return Result<XblAchievementMediaAsset>{ mediaAsset, S_OK };\n}\n\nResult<XblAchievementReward> AchievementsService::DeserializeReward(\n    const JsonValue& json\n)\n{\n    XblAchievementReward reward{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievementReward>{ reward };\n    }\n\n    HRESULT errc = S_OK;\n    xsapi_internal_string name, description, value, rewardType, valueType;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"name\", name, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"description\", description, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"value\", value, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"type\", rewardType, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"valueType\", valueType, true));\n    reward.name = Make(name);\n    reward.description = Make(description);\n    reward.value = Make(value);\n    reward.rewardType = RewardTypeFromString(rewardType);\n    reward.valueType = Make(valueType);\n\n    if (json.IsObject() && json.HasMember(\"mediaAsset\"))\n    {\n        auto mediaAssetResult = DeserializeMediaAsset(json[\"mediaAsset\"]);\n        reward.mediaAsset = Make<XblAchievementMediaAsset>(mediaAssetResult.ExtractPayload());\n\n        if (Failed(mediaAssetResult) || FAILED(errc))\n        {\n            return Result<XblAchievementReward>{ reward, E_FAIL };\n        }\n\n        return Result<XblAchievementReward>{ reward };\n    }\n    else\n    {\n        reward.mediaAsset = Make<XblAchievementMediaAsset>(XblAchievementMediaAsset());\n        return Result<XblAchievementReward>{ reward, E_FAIL };\n    }\n}\n\nResult<XblAchievement> AchievementsService::DeserializeAchievement(\n    const JsonValue& json\n)\n{\n    XblAchievement a{};\n\n    if (json.IsNull())\n    {\n        return Result<XblAchievement>{ a };\n    }\n\n    HRESULT errCode = S_OK;\n\n    xsapi_internal_string id, serviceConfigId, name;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", id, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"serviceConfigId\", serviceConfigId, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"name\", name, true));\n    a.id = Make(id);\n    a.serviceConfigurationId = Make(serviceConfigId);\n    a.name = Make(name);\n\n    xsapi_internal_vector<XblAchievementTitleAssociation> titleAssociationVector;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblAchievementTitleAssociation>(\n        DeserializeTitleAssociation,\n        json, \"titleAssociations\", titleAssociationVector, true\n        ));\n    a.titleAssociations = MakeArray(titleAssociationVector);\n    a.titleAssociationsCount = titleAssociationVector.size();\n    xsapi_internal_string progressState;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"progressState\", progressState));\n    a.progressState = ProgressStateFromString(progressState);\n\n    xsapi_internal_vector<XblAchievementMediaAsset> mediaAssetsVector;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblAchievementMediaAsset>(\n        DeserializeMediaAsset,\n        json, \"mediaAssets\", mediaAssetsVector, true\n        ));\n\n    a.mediaAssets = MakeArray(mediaAssetsVector);\n    a.mediaAssetsCount = mediaAssetsVector.size();\n\n    xsapi_internal_vector<xsapi_internal_string> platformsVector;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<xsapi_internal_string>(JsonUtils::JsonStringExtractor, json, \"platforms\", platformsVector, true));\n    a.platformsAvailableOn = const_cast<const char**>(MakeArray(platformsVector));\n    a.platformsAvailableOnCount = platformsVector.size();\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"isSecret\", a.isSecret));\n    xsapi_internal_string description, lockedDescription, productId;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"description\", description, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"lockedDescription\", lockedDescription, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"productId\", productId, true));\n    a.unlockedDescription = Make(description);\n    a.lockedDescription = Make(lockedDescription);\n    a.productId = Make(productId);\n\n    xsapi_internal_string achievementType, participationType;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"achievementType\", achievementType, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"participationType\", participationType, true));\n    a.type = AchievementTypeFromString(achievementType);\n    a.participationType = ParticipationTypeFromString(participationType);\n\n    Result<XblAchievementTimeWindow> timeWindowResult{ XblAchievementTimeWindow() };\n    if (json.IsObject() && json.HasMember(\"timeWindow\"))\n    {\n        timeWindowResult = DeserializeTimeWindow(json[\"timeWindow\"]);\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n    a.available = timeWindowResult.ExtractPayload();\n\n\n    xsapi_internal_vector<XblAchievementReward> rewardsVector;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblAchievementReward>(\n        DeserializeReward,\n        json, \"rewards\", rewardsVector, true\n        ));\n\n    a.rewards = MakeArray(rewardsVector);\n    a.rewardsCount = rewardsVector.size();\n\n    std::chrono::seconds seconds{};\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringTimespanInSeconds(json, \"estimatedTime\", seconds, true));\n    a.estimatedUnlockTime = seconds.count(); \n    xsapi_internal_string deeplink;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"deeplink\", deeplink, true));\n    a.deepLink = Make(deeplink);\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"isRevoked\", a.isRevoked, true));\n\n    Result<XblAchievementProgression> progressionResult{ XblAchievementProgression() };\n    if (json.IsObject() && json.HasMember(\"progression\"))\n    {\n        progressionResult = DeserializeProgression(json[\"progression\"]);\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n    a.progression = progressionResult.ExtractPayload();\n\n    if (Failed(progressionResult) || Failed(timeWindowResult) || FAILED(errCode))\n    {\n        CleanupAchievement(a);\n        return Result<XblAchievement>{ E_FAIL };\n    }\n\n    return Result<XblAchievement>{ a };\n}\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n#pragma pack(pop)\n#endif\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_END"
  },
  {
    "path": "Source/Services/Achievements/achievements_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/achievements_c.h\"\n#include \"Achievements/achievements_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::achievements;\nusing namespace xbox::services::system;\n\nSTDAPI XblAchievementsGetAchievementsForTitleIdAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t titleId,\n    _In_ XblAchievementType type,\n    _In_ bool unlockedOnly,\n    _In_ XblAchievementOrderBy orderBy,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            xboxUserId,\n            titleId,\n            type,\n            unlockedOnly,\n            orderBy,\n            skipItems,\n            maxItems,\n            achievmentsResult{ std::shared_ptr<XblAchievementsResult>() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->AchievementsService()->GetAchievementsForTitle(\n                xboxUserId,\n                titleId,\n                type,\n                unlockedOnly,\n                orderBy,\n                skipItems,\n                maxItems,\n                AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>>{ data->async->queue,\n                [\n                    &achievmentsResult,\n                    async{ data->async }\n                ]\n            (Result<std::shared_ptr<XblAchievementsResult>> result)\n            {\n                if (Succeeded(result))\n                {\n                    achievmentsResult = result.ExtractPayload();\n                }\n                XAsyncComplete(async, result.Hresult(), sizeof(XblAchievementsResultHandle));\n            }\n            }));\n\n            return E_PENDING;\n        }\n\n        case XAsyncOp::GetResult:\n        {\n            auto resultHandle = static_cast<XblAchievementsResultHandle*>(data->buffer);\n            *resultHandle = achievmentsResult.get();\n            achievmentsResult->AddRef();\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsGetAchievementsForTitleIdResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblAchievementsResultHandle* result\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblAchievementsResultHandle), result, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsResultGetAchievements(\n    _In_ XblAchievementsResultHandle result,\n    _Out_ const XblAchievement** achievements,\n    _Out_ size_t* achievementsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(achievementsCount == nullptr || achievements == nullptr || result == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    *achievementsCount = result->Achievements().size();\n    *achievements = result->Achievements().data();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsResultHasNext(\n    _In_ XblAchievementsResultHandle result,\n    _Out_ bool* hasNext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(result == nullptr || hasNext == nullptr);\n    VERIFY_XBL_INITIALIZED();\n    *hasNext = result->HasNext();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsResultGetNextAsync(\n    _In_ XblAchievementsResultHandle result,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            inputResult{ result->shared_from_this() },\n            maxItems,\n            outputResult{ std::shared_ptr<XblAchievementsResult>() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(inputResult->GetNext(\n                maxItems,\n                AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>>{ data->async->queue,\n                [\n                    &outputResult,\n                    async{ data->async }\n                ]\n            (Result<std::shared_ptr<XblAchievementsResult>> result)\n            {\n                if (Succeeded(result))\n                {\n                    outputResult = result.ExtractPayload();\n                }\n                XAsyncComplete(async, result.Hresult(), sizeof(XblAchievementsResultHandle));\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto resultHandle = static_cast<XblAchievementsResultHandle*>(data->buffer);\n            *resultHandle = outputResult.get();\n            outputResult->AddRef();\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblAchievementsResultHandle* result\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblAchievementsResultHandle), result, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsUpdateAchievementAsyncInternal(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t titleId,\n    _In_opt_z_ const char* serviceConfigurationId,\n    _In_z_ const char* achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(achievementId);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            xboxUserId,\n            titleId,\n            scid = String{ serviceConfigurationId ? serviceConfigurationId : \"\" },\n            achievementId = String{ achievementId },\n            percentComplete\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            if (titleId == 0)\n            {\n                RETURN_HR_IF_FAILED(xboxLiveContext->AchievementsService()->UpdateAchievement(\n                    xboxUserId,\n                    achievementId,\n                    percentComplete,\n                    data->async\n                ));\n            }\n            else\n            {\n                RETURN_HR_IF_FAILED(xboxLiveContext->AchievementsService()->UpdateAchievement(\n                    xboxUserId,\n                    titleId,\n                    scid,\n                    achievementId,\n                    percentComplete,\n                    data->async\n                ));\n            }\n\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsUpdateAchievementAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(achievementId);\n\n    return XblAchievementsUpdateAchievementAsyncInternal(\n        xboxLiveContext, \n        xboxUserId, \n        AppConfig::Instance()->TitleId(),\n        AppConfig::Instance()->Scid().c_str(),\n        achievementId, \n        percentComplete, \n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsUpdateAchievementForTitleIdAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xboxUserId,\n    _In_ const uint32_t titleId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* achievementId,\n    _In_ uint32_t percentComplete,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(achievementId);\n\n    return XblAchievementsUpdateAchievementAsyncInternal(xboxLiveContext, xboxUserId, titleId, serviceConfigurationId, achievementId, percentComplete, async);\n}\nCATCH_RETURN()\n\n\nSTDAPI XblAchievementsGetAchievementAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* achievementId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(achievementId);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            xboxUserId,\n            scid = String{ serviceConfigurationId },\n            achievementId = String{ achievementId },\n            achievementResult = std::shared_ptr<XblAchievementsResult>{ nullptr }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->AchievementsService()->GetAchievement(\n                xboxUserId,\n                scid,\n                achievementId,\n                AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>>{ data->async->queue,\n                [\n                    &achievementResult,\n                    async{ data->async }\n                ]\n            (Result<std::shared_ptr<XblAchievementsResult>> result)\n            {\n                if (Succeeded(result))\n                {\n                    achievementResult = result.ExtractPayload();\n                }\n                XAsyncComplete(async, result.Hresult(), sizeof(XblAchievementsResultHandle));\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto resultHandle = static_cast<XblAchievementsResultHandle*>(data->buffer);\n            *resultHandle = achievementResult.get();\n            achievementResult->AddRef();\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsGetAchievementResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblAchievementsResultHandle* result\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblAchievementsResultHandle), result, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsResultDuplicateHandle(\n    _In_ XblAchievementsResultHandle handle,\n    _Out_ XblAchievementsResultHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || duplicatedHandle == nullptr);\n\n    handle->AddRef();\n    *duplicatedHandle = handle;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblAchievementsResultCloseHandle(\n    _In_ XblAchievementsResultHandle handle\n) XBL_NOEXCEPT\ntry\n{\n    if (handle)\n    {\n        handle->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(XblFunctionContext) XblAchievementsAddAchievementProgressChangeHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblAchievementsProgressChangeHandler handler,\n    _In_opt_ void* handlerContext\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContextHandle == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    return xblContextHandle->AchievementsService()->AddAchievementProgressChangeHandler(\n        [\n            handler,\n            handlerContext\n        ]\n    (const XblAchievementProgressChangeEventArgs& args)\n    {\n        try\n        {\n            handler(&args, handlerContext);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblAchievementsRemoveAchievementProgressChangeHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext functionContext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    xboxLiveContext->AchievementsService()->RemoveAchievementProgressChangeHandler(functionContext);\n    return S_OK;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Achievements/achievements_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/achievements_c.h\"\n#include \"real_time_activity_subscription.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_BEGIN\n\ntypedef Callback<const XblAchievementProgressChangeEventArgs&> AchievementProgressChangeHandler;\n\nclass AchievementProgressChangeSubscription : public real_time_activity::Subscription\n{\npublic:\n    AchievementProgressChangeSubscription(\n        _In_ uint64_t xuid, \n        _In_ const xbox::services::String& scid\n    ) noexcept;\n\n    XblFunctionContext AddHandler(AchievementProgressChangeHandler handler) noexcept;\n    size_t RemoveHandler(XblFunctionContext token) noexcept;\n\n    static XblAchievementProgressChangeEntry DeepCopyProgressChangeEntry (XblAchievementProgressChangeEntry& source);\n    static void CleanUpProgressChangeEntry(XblAchievementProgressChangeEntry& entry);\n\nprotected:\n    void OnEvent(const JsonValue& data) noexcept override;\n\nprivate:\n    Map<XblFunctionContext, AchievementProgressChangeHandler> m_handlers;\n    XblFunctionContext m_nextHandlerToken{ 1 };\n    mutable std::mutex m_lock;\n\n    uint64_t m_userId;\n};\n\n\nclass AchievementsService : public std::enable_shared_from_this<AchievementsService>\n{\npublic:\n    AchievementsService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<AppConfig> appConfig,\n        _In_ std::weak_ptr<::XblContext> xboxLiveContextImpl,\n        _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n    );\n\n    HRESULT UpdateAchievement(\n        _In_ uint64_t xboxUserId,\n        _In_ const String& achievementId,\n        _In_ uint32_t percentComplete,\n        _In_ AsyncContext<Result<void>> async\n    ) const noexcept;\n\n    HRESULT UpdateAchievement(\n        _In_ uint64_t xboxUserId,\n        _In_ uint32_t titleId,\n        _In_ const String& serviceConfigurationId,\n        _In_ const String& achievementId,\n        _In_ uint32_t percentComplete,\n        _In_ AsyncContext<Result<void>> async\n    ) const noexcept;\n    \n    HRESULT GetAchievementsForTitle(\n        _In_ uint64_t xboxUserId,\n        _In_ uint32_t titleId,\n        _In_ XblAchievementType type,\n        _In_ bool unlockedOnly,\n        _In_ XblAchievementOrderBy orderBy,\n        _In_ uint32_t skipItems,\n        _In_ uint32_t maxItems,\n        _In_ AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>> async\n    ) const noexcept;\n\n    HRESULT GetAchievement(\n        _In_ uint64_t xboxUserId,\n        _In_ const String& serviceConfigurationId,\n        _In_ const String& achievementId,\n        _In_ AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>> async\n    ) const noexcept;\n\n    HRESULT GetAchievements(\n        _In_ uint64_t xboxUserId,\n        _In_ const Vector<uint32_t>& titleIds,\n        _In_ XblAchievementType type,\n        _In_ bool unlockedOnly,\n        _In_ XblAchievementOrderBy orderBy,\n        _In_ uint32_t skipItems,\n        _In_ uint32_t maxItems,\n        _In_ const String& continuationToken,\n        _In_ AsyncContext<Result<std::shared_ptr<XblAchievementsResult>>> callback\n    ) const noexcept;\n\n    XblFunctionContext AddAchievementProgressChangeHandler(\n        _In_ AchievementProgressChangeHandler handler\n    ) noexcept;\n\n    void RemoveAchievementProgressChangeHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\n    // Since there is not a destructor for XblAchievement objects, use this helper to free any dynamically\n    // allocated memory associated with an XblAchievement and zero it out.\n    static void CleanupAchievement(XblAchievement& achievement);\n\n    static Result<XblAchievement> DeserializeAchievement(const JsonValue& json);\n\nprivate:\n    // Achievements endpoints\n    static String GetAchievementsSubpath(\n        _In_ uint64_t xboxUserId,\n        _In_ const Vector<uint32_t>& titleIds,\n        _In_ XblAchievementType type,\n        _In_ bool unlockedOnly,\n        _In_ XblAchievementOrderBy orderBy,\n        _In_ uint32_t skipItems,\n        _In_ uint32_t maxItems,\n        _In_ const String& continuationToken\n    );\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<xbox::services::AppConfig> m_appConfig;\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n    std::weak_ptr<XblContext> m_xboxLiveContextImpl;\n\n    std::shared_ptr<AchievementProgressChangeSubscription> m_achievementProgressChangeSubscription;\n    mutable std::mutex m_lock;\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    static HRESULT WriteOfflineUpdateAchievement(\n        _In_ std::shared_ptr<XblContext> xboxLiveContextImpl,\n        _In_ const String& achievementId,\n        _In_ uint32_t percentComplete\n    );\n\n    static ULONG EventWriteAchievementUpdate(\n        _In_ PCWSTR userId,\n        _In_ PCWSTR achievementId,\n        _In_ const uint32_t percentComplete\n    );\n\n#else\n    static HRESULT WriteOfflineUpdateAchievement(\n        _In_ std::shared_ptr<XblContext> xboxLiveContextImpl,\n        _In_ const String& achievementId,\n        _In_ uint32_t percentComplete\n    );\n#endif\n\n    // Deserialization helpers\n    static Result<XblAchievementTitleAssociation> DeserializeTitleAssociation(const JsonValue& json);\n    static Result<XblAchievementRequirement> DeserializeRequirement(const JsonValue& json);\n    static Result<XblAchievementProgression> DeserializeProgression(const JsonValue& json);\n    static Result<XblAchievementTimeWindow> DeserializeTimeWindow(const JsonValue& json);\n    static Result<XblAchievementMediaAsset> DeserializeMediaAsset(const JsonValue& json);\n    static Result<XblAchievementReward> DeserializeReward(const JsonValue& json);\n\n    friend struct XblContext;\n    friend class achievements_result_internal;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_END\n\nstruct XblAchievementsResult : public xbox::services::RefCounter, public std::enable_shared_from_this<XblAchievementsResult>\n{\npublic:\n    XblAchievementsResult(_In_ std::shared_ptr<const xbox::services::achievements::AchievementsService> service);\n    virtual ~XblAchievementsResult();\n\n    static xbox::services::Result<std::shared_ptr<XblAchievementsResult>> Deserialize(\n        _In_ const JsonDocument& json,\n        _In_ std::shared_ptr<const xbox::services::achievements::AchievementsService> service);\n\n    const Vector<XblAchievement>& Achievements() const;\n\n    bool HasNext() const;\n\n    HRESULT GetNext(\n        _In_ uint32_t maxItems,\n        _In_ AsyncContext<xbox::services::Result<std::shared_ptr<XblAchievementsResult>>> async\n    ) const noexcept;\n\n    void SetNextPageQueryParameters(\n        _In_ uint64_t xuid,\n        _In_ const xsapi_internal_vector<uint32_t>& titleIds,\n        _In_ XblAchievementType type,\n        _In_ bool unlockedOnly,\n        _In_ XblAchievementOrderBy orderBy\n    );\n\nprotected:\n    // RefCounter\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override;\n\nprivate:\n    XblAchievementsResult(const XblAchievementsResult& other) = delete;\n    XblAchievementsResult& operator=(XblAchievementsResult other) = delete;\n\n    xsapi_internal_vector<XblAchievement> m_achievements;\n\n    // Info needed for GetNext query\n    xsapi_internal_string m_continuationToken;\n    uint64_t m_xuid{ 0 };\n    xsapi_internal_vector<uint32_t> m_titleIds;\n    XblAchievementType m_achievementType{ XblAchievementType::All };\n    bool m_unlockedOnly{ false };\n    XblAchievementOrderBy m_orderBy{ XblAchievementOrderBy::DefaultOrder };\n\n    std::weak_ptr<const xbox::services::achievements::AchievementsService> m_serviceWeakPointer;\n};\n\n\n"
  },
  {
    "path": "Source/Services/Achievements/achievements_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"achievements_internal.h\"\n#include \"xsapi_utils.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::achievements;\n\nXblAchievementsResult::~XblAchievementsResult()\n{\n    for (auto& achievement : m_achievements)\n    {\n        AchievementsService::CleanupAchievement(achievement);\n    }\n}\n\nResult<std::shared_ptr<XblAchievementsResult>> XblAchievementsResult::Deserialize(\n    _In_ const JsonDocument& json,\n    _In_ std::shared_ptr<const xbox::services::achievements::AchievementsService> service)\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    auto achievementResult = MakeShared<XblAchievementsResult>(service);\n\n    HRESULT errCode = S_OK;\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblAchievement>(\n        AchievementsService::DeserializeAchievement,\n        json, \"achievements\", achievementResult->m_achievements, true\n        ));\n\n    if (json.IsObject() && json.HasMember(\"pagingInfo\"))\n    {\n        const JsonValue& pageInfoJson = json[\"pagingInfo\"];\n        if (!pageInfoJson.IsNull())\n        {\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(pageInfoJson, \"continuationToken\", achievementResult->m_continuationToken, true));\n        }\n    }\n\n    if (FAILED(errCode))\n    {\n        return Result<std::shared_ptr<XblAchievementsResult>>{ errCode };\n    }\n    return Result<std::shared_ptr<XblAchievementsResult>>{ achievementResult };\n}\n\nXblAchievementsResult::XblAchievementsResult(\n    _In_ std::shared_ptr<const xbox::services::achievements::AchievementsService> service\n) : \n    m_serviceWeakPointer{ service }\n{\n}\n\nconst xsapi_internal_vector<XblAchievement>& XblAchievementsResult::Achievements() const\n{\n    return m_achievements;\n}\n\nstd::shared_ptr<xbox::services::RefCounter> XblAchievementsResult::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nbool XblAchievementsResult::HasNext() const\n{\n    return !m_continuationToken.empty();\n}\n\nHRESULT XblAchievementsResult::GetNext(\n    _In_ uint32_t maxItems,\n    _In_ AsyncContext<xbox::services::Result<std::shared_ptr<XblAchievementsResult>>> async\n) const noexcept\n{\n    auto service{ m_serviceWeakPointer.lock() };\n\n    if (m_continuationToken.empty() || service == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n\n    return service->GetAchievements(\n        m_xuid,\n        m_titleIds,\n        m_achievementType,\n        m_unlockedOnly,\n        m_orderBy,\n        0, // use continuationToken, ignore skipItems.\n        maxItems,\n        m_continuationToken,\n        std::move(async)\n    );\n}\n\nvoid XblAchievementsResult::SetNextPageQueryParameters(\n    _In_ uint64_t xuid,\n    _In_ const xsapi_internal_vector<uint32_t>& titleIds,\n    _In_ XblAchievementType type,\n    _In_ bool unlockedOnly,\n    _In_ XblAchievementOrderBy orderBy\n)\n{\n    m_xuid = xuid;\n    m_titleIds = titleIds;\n    m_achievementType = type;\n    m_unlockedOnly = unlockedOnly;\n    m_orderBy = orderBy;\n}"
  },
  {
    "path": "Source/Services/Achievements/achievements_subscription.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"achievements_internal.h\"\n\n#include \"xsapi_utils.h\"\n#include \"xsapi-c/errors_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_BEGIN\n\nAchievementProgressChangeSubscription::AchievementProgressChangeSubscription(\n    _In_ uint64_t xuid,\n    _In_ const xbox::services::String& scid\n) noexcept\n    : m_userId(xuid)\n{\n    Stringstream uri;\n    uri << \"https://achievements.xboxlive.com/users/xuid(\" << m_userId << \")/achievements/\" << utils::ToLower(scid);\n    m_resourceUri = uri.str();\n}\n\nXblFunctionContext AchievementProgressChangeSubscription::AddHandler(\n    AchievementProgressChangeHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n    m_handlers[m_nextHandlerToken] = std::move(handler);\n    return m_nextHandlerToken++;\n}\n\nsize_t AchievementProgressChangeSubscription::RemoveHandler(\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n    m_handlers.erase(token);\n    return m_handlers.size();\n}\n\nXblAchievementProgressChangeEntry AchievementProgressChangeSubscription::DeepCopyProgressChangeEntry(XblAchievementProgressChangeEntry & source)\n{\n    XblAchievementProgressChangeEntry entry;\n    \n    entry.achievementId = Make(source.achievementId);\n    entry.progressState = source.progressState;\n    entry.progression.requirementsCount = source.progression.requirementsCount;\n    entry.progression.timeUnlocked = source.progression.timeUnlocked;\n    entry.progression.requirements = MakeArray<XblAchievementRequirement>(source.progression.requirementsCount);\n    \n    XblAchievementRequirement*& eventRequirements = entry.progression.requirements;\n    for (uint64_t i = 0; i < entry.progression.requirementsCount; ++i)\n    {\n        eventRequirements[i].id = Make(source.progression.requirements[i].id);\n        eventRequirements[i].currentProgressValue = Make(source.progression.requirements[i].currentProgressValue);\n        eventRequirements[i].targetProgressValue = Make(source.progression.requirements[i].targetProgressValue);\n    }\n\n    return entry;\n}\n\nvoid AchievementProgressChangeSubscription::CleanUpProgressChangeEntry(XblAchievementProgressChangeEntry & entry)\n{\n    Delete(entry.achievementId);\n    auto& progression = entry.progression;\n\n    for (uint64_t i = 0; i < progression.requirementsCount; ++i)\n    {\n        Delete(progression.requirements[i].id);\n        Delete(progression.requirements[i].currentProgressValue);\n        Delete(progression.requirements[i].targetProgressValue);\n    }\n    DeleteArray(progression.requirements, progression.requirementsCount);\n}\n\nvoid AchievementProgressChangeSubscription::OnEvent(\n    const JsonValue& data\n) noexcept\n{\n    //  Payload format at http://xboxwiki/wiki/RTA%3AEVENT#Achievements is currently out of\n    //  date. Below is the payload format discovered while debugging.\n    //  [<API_ID>, <SUB_ID>, \n    //  {\n    //      \"progression\": [\n    //          {\n    //              \"id\" : \"1\",\n    //              \"progressState\" : \"InProgress\",\n    //              \"timeUnlocked\" : \"2013-01-17T03:19:00.3087016Z\",\n    //              \"requirements\" : [\n    //                  {\n    //                      \"id\":\"12345678-1234-1234-1234-123456789012\",\n    //                      \"current\" : \"1\",\n    //                      \"target\" : \"100\",\n    //                      \"operationType\" : \"sum\",\n    //                      \"valueType\" : \"Integer\",\n    //                      \"ruleParticipationType\" : \"Individual\"\n    //                  }\n    //              ]\n    //          }\n    //      ],\n    //      \"serviceConfigId\" : \"87654321-4321-4321-4321-210987654321\"\n    //  }\n    \n    HRESULT hr(S_OK);\n    xbox::services::Vector<XblAchievementProgressChangeEntry> progressEntries;\n\n    auto deserializeRequirement = [](const JsonValue& json) -> Result<XblAchievementRequirement> {\n        XblAchievementRequirement requirement{};\n\n        if (json.IsNull())\n        {\n            return Result<XblAchievementRequirement>{ requirement };\n        }\n\n        xbox::services::String id, current, target;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", id, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"current\", current, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"target\", target, false));\n        requirement.id = Make(id);\n        requirement.currentProgressValue = Make(current);\n        requirement.targetProgressValue = Make(target);\n\n        return Result<XblAchievementRequirement>{ requirement, S_OK };\n    };\n\n    auto deserializeProgressEntry = [&deserializeRequirement](const JsonValue& json) -> Result<XblAchievementProgressChangeEntry>\n    {\n        XblAchievementProgressChangeEntry progressEntry{};\n        XblAchievementProgression progression{};\n\n        if (json.IsNull())\n        {\n            return Result<XblAchievementProgressChangeEntry>{ progressEntry };\n        }\n\n        xbox::services::String achievementId, progressState;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", achievementId, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"progressState\", progressState, true));\n        \n        xbox::services::Vector<XblAchievementRequirement> requirementsVector;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblAchievementRequirement>(\n            deserializeRequirement,\n            json, \"requirements\", requirementsVector, true\n        ));\n\n        progression.requirements = MakeArray(requirementsVector);\n        progression.requirementsCount = requirementsVector.size();\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"timeUnlocked\", progression.timeUnlocked, true));\n\n        progressEntry.progression = progression;\n        progressEntry.achievementId = Make(achievementId);\n        progressEntry.progressState = EnumValue<XblAchievementProgressState>(progressState.data());\n\n        return Result<XblAchievementProgressChangeEntry>{progressEntry, S_OK};\n    };\n\n    hr = JsonUtils::ExtractJsonVector<XblAchievementProgressChangeEntry>(\n        deserializeProgressEntry,\n        data,\n        \"progression\",\n        progressEntries,\n        true\n    );\n\n    if (!SUCCEEDED(hr))\n    {\n        LOGS_ERROR << __FUNCTION__ << \": Ignoring malformed payload\";\n        return;\n    }\n\n    XblAchievementProgressChangeEventArgs args{ progressEntries.data(), progressEntries.size() };\n\n    if (SUCCEEDED(hr))\n    {\n        std::unique_lock<std::mutex> lock{ m_lock };\n        auto handlers{ m_handlers };\n        lock.unlock();\n\n        for (auto& handler : handlers)\n        {\n            handler.second(args);\n        }\n    }\n    else\n    {\n        LOGS_DEBUG << __FUNCTION__ << \": Ignoring malformed event\";\n    }\n    \n    // clean up allocations for each of the entries.\n    for (auto& entry : progressEntries)\n    {\n        Delete(entry.achievementId);\n        auto& progression = entry.progression;\n        \n        for (uint64_t i = 0; i < progression.requirementsCount; ++i)\n        {\n            Delete(progression.requirements[i].id);\n            Delete(progression.requirements[i].currentProgressValue);\n            Delete(progression.requirements[i].targetProgressValue);\n        }\n\n        DeleteArray(progression.requirements, progression.requirementsCount);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_END\n"
  },
  {
    "path": "Source/Services/Common/Cpp/pch.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\""
  },
  {
    "path": "Source/Services/Common/Cpp/pch.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"pch_common.h\"\n"
  },
  {
    "path": "Source/Services/Common/Unix/pch.cpp",
    "content": "#include \"pch.h\"\n\n#ifndef _LINK_WITH_CPPRESTSDK\n#include \"cpprestsdk_impl.h\"\n#endif"
  },
  {
    "path": "Source/Services/Common/Unix/pch.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch_common.h\""
  },
  {
    "path": "Source/Services/Common/iOS/pch.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n\n#ifndef _LINK_WITH_CPPRESTSDK\n#include \"cpprestsdk_impl.h\"\n#endif\n"
  },
  {
    "path": "Source/Services/Common/iOS/pch.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#define _LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR\n\n#include \"Unix/pch.h\"\n\n#define XSAPI_I 1\n"
  },
  {
    "path": "Source/Services/Common/pch_common.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"httpClient/config.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM_IS_APPLE\n#pragma clang diagnostic ignored \"-Woverloaded-virtual\"\n#pragma clang diagnostic ignored \"-Wc++14-extensions\"\n#pragma clang diagnostic ignored \"-Wreorder\"\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning(disable : 4355 4628 4266 4555 4263 4264 4868 4062 4826 4244 4654)\n#pragma warning(disable : 4619 4616 4350 4351 4472 4640 5038 4471)\n#pragma warning(disable : 4061 4265 4365 4571 4623 4625 4626 4668 4710 4711 4746 4774 4820 4987 4996 5026 5027 5031 5032 5039 5037 5045)\n\n#pragma warning(disable: 4503) // C4503: decorated name length exceeded, name was truncated  \n#pragma warning(disable: 4242) \n#pragma warning(disable: 4634) // C4634: Discarding XML document comment for invalid target.\n#pragma warning(disable: 26812)  // enum instead of enum class\n\n#if _DEBUG && defined(XSAPI_UNIT_TESTS)\n#define _CRTDBG_MAP_ALLOC\n#include <stdlib.h>\n#include <crtdbg.h>\n#endif\n\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\n#include <SDKDDKVer.h>\n\n// Windows\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\n#endif\n#include <windows.h>\n\n#else // HC_PLATFORM_IS_MICROSOFT\n\n#ifndef __STDC_LIMIT_MACROS\n#define __STDC_LIMIT_MACROS\n#endif\n#include <stdint.h>\n\n#endif // HC_PLATFORM_IS_MICROSOFT\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM_IS_APPLE\n#define _NOEXCEPT noexcept\n#endif\n\n// STL includes\n#include <string>\n#include <map>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <deque>\n#include <queue>\n#include <vector>\n#include <memory>\n#include <stdint.h>\n#include <thread>\n#include <mutex>\n#include <atomic>\n#include <cstdint>\n#include <limits>\n#include <list>\n#include <assert.h>\n#include <array>\n#if HC_PLATFORM_IS_MICROSOFT\n#include <objbase.h>\n#endif\n\n#include \"httpClient/pal.h\"\n#include \"httpClient/httpClient.h\"\n#include \"XAsync.h\"\n#include \"XAsyncProvider.h\"\n#include \"XTaskQueue.h\"\n\n#include \"xsapi-c/types_c.h\"\n#include \"internal_types.h\"\n#include \"xsapi-c/pal.h\"\n#include \"internal_mem.h\"\n\n#include <Xal/xal.h>\n#include \"http_headers.h\"\n#if HC_PLATFORM != HC_PLATFORM_GDK\n#include \"cpprest/http_msg.h\"\n#endif\n#include \"http_utils.h\"\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include \"HookedUri/uri.h\"\n#endif\n\n#undef max // needed for the version of RapidJson we're using to avoid warnings\n#undef min\n\n#define RAPIDJSON_NAMESPACE xbox::services::rapidjson\n#define RAPIDJSON_NAMESPACE_BEGIN namespace xbox { namespace services { namespace rapidjson {\n#define RAPIDJSON_NAMESPACE_END } } }\n#include \"rapidjson/document.h\"\n#include \"rapidjson/stringbuffer.h\"\n#include \"rapidjson/writer.h\"\n\n#include \"async_helpers.h\"\n#include \"xsapi_utils.h\"\n#include \"xsapi_json_utils.h\"\n#include \"public_utils_legacy.h\"\n#include \"ref_counter.h\"\n#include \"internal_errors.h\"\n#include \"Logger/log.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include \"user.h\"\n#include \"http_call_wrapper_internal.h\"\n#include \"global_state.h\"\n#include \"enum_traits.h\"\n#include \"xsapi-c/xbox_live_context_c.h\"\n\n#include \"shared_macros.h\"\n\n#ifndef ARRAYSIZE\n#define ARRAYSIZE(x) sizeof(x) / sizeof(x[0])\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT\n    #define SPRINTF(buffer, size, format, ...) sprintf_s(buffer, size, format, __VA_ARGS__)\n#else\n    #define SPRINTF(buffer, size, format, ...) snprintf(buffer, size, format, __VA_ARGS__)\n#endif\n\n#if HC_PLATFORM_IS_PLAYSTATION\n#include \"xsapi_ps.h\"\n#endif"
  },
  {
    "path": "Source/Services/Common/xbox_live_context.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"presence_internal.h\"\n\n#include \"Achievements/achievements_internal.h\"\n#include \"profile_internal.h\"\n#include \"social_internal.h\"\n#include \"string_service_internal.h\"\n#include \"multiplayer_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include \"xbox_live_context_settings_internal.h\"\n#include \"title_storage_internal.h\"\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#include \"notification_internal.h\"\n#endif\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\n/*static*/ std::shared_ptr<XblContext> XblContext::Make(\n    _In_ xbox::services::User&&  user\n) noexcept\n{\n    auto xblContext = std::shared_ptr<XblContext>(\n        new (Alloc(sizeof(XblContext))) XblContext{ std::move(user) },\n        Deleter<XblContext>(),\n        Allocator<XblContext>()\n        );\n    return xblContext;\n}\n\nconst xbox::services::User& XblContext::User() const noexcept\n{\n    return m_user;\n}\n\nXblContext::~XblContext()\n{\n    if (m_userChangeEventToken)\n    {\n        User::UnregisterChangeEventHandle(m_userChangeEventToken);\n    }\n}\n\nstd::shared_ptr<xbox::services::RefCounter> XblContext::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nHRESULT XblContext::Initialize(\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> rtaManager\n)\n{\n    m_xboxLiveContextSettings = MakeShared<xbox::services::XboxLiveContextSettings>();\n\n    std::weak_ptr<XblContext> thisWeakPtr = shared_from_this();\n    TaskQueue globalQueue;\n    {\n        auto state = GlobalState::Get();\n        if (state)\n        {\n            globalQueue = state->Queue();\n        }\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_achievementService = MakeShared<xbox::services::achievements::AchievementsService>(userResult.ExtractPayload(), m_xboxLiveContextSettings, AppConfig::Instance(), thisWeakPtr, rtaManager);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_profileService = MakeShared<xbox::services::social::ProfileService>(userResult.ExtractPayload(), m_xboxLiveContextSettings, AppConfig::Instance());\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_reputationServiceImpl = MakeShared<xbox::services::social::ReputationService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_presenceService = MakeShared<xbox::services::presence::PresenceService>(userResult.ExtractPayload(), globalQueue, m_xboxLiveContextSettings, rtaManager);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_socialService = MakeShared<xbox::services::social::SocialService>(userResult.ExtractPayload(), m_xboxLiveContextSettings, rtaManager);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_stringService = MakeShared<xbox::services::system::StringService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_multiplayerService = MakeShared<xbox::services::multiplayer::MultiplayerService>(userResult.ExtractPayload(), m_xboxLiveContextSettings, AppConfig::Instance(), rtaManager);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_privacyService = MakeShared<privacy::PrivacyService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_titleManagedStatisticsService = MakeShared<xbox::services::user_statistics::TitleManagedStatisticsService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_userStatisticsService = MakeShared<xbox::services::user_statistics::UserStatisticsService>(userResult.ExtractPayload(), globalQueue, m_xboxLiveContextSettings, rtaManager);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_leaderboardService = MakeShared<xbox::services::leaderboard::LeaderboardService>(userResult.ExtractPayload(), m_xboxLiveContextSettings, AppConfig::Instance());\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_matchmakingService = MakeShared<xbox::services::matchmaking::MatchmakingService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_titleStorageService = MakeShared<xbox::services::title_storage::TitleStorageService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        m_multiplayerActivityService = MakeShared<multiplayer_activity::MultiplayerActivityService>(userResult.ExtractPayload(), globalQueue, m_xboxLiveContextSettings);\n    }\n    \n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n#ifdef XSAPI_EVENTS_SERVICE\n        m_eventsService = MakeShared<events::EventsService>(\n            userResult.ExtractPayload()\n#ifdef XSAPI_INTERNAL_EVENTS_SERVICE\n            , globalQueue\n#endif\n            );\n        RETURN_HR_IF_FAILED(m_eventsService->Initialize());\n#endif\n    }\n\n    {\n        Result<xbox::services::User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#if !defined(XSAPI_UNIT_TESTS) && (HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL)\n        m_notificationService = MakeShared<xbox::services::notification::RTANotificationService>(userResult.ExtractPayload(), globalQueue, m_xboxLiveContextSettings, rtaManager);\n        RETURN_HR_IF_FAILED(m_notificationService->Initialize());\n#elif HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_IOS\n        m_notificationService = MakeShared<xbox::services::notification::MobileNotificationService>(userResult.ExtractPayload(), m_xboxLiveContextSettings);\n#endif\n#endif\n    }\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\n    auto userChangedRegistrationResult = User::RegisterChangeEventHandler(\n        [\n            thisWeakPtr,\n            queue{ globalQueue.DeriveWorkerQueue() }\n        ]\n    (UserLocalId localId, UserChangeType changeType)\n    {\n        auto sharedThis{ thisWeakPtr.lock() };\n        if (sharedThis)\n        {\n            if (sharedThis->m_user.LocalId() == localId.value && changeType == XalUserChange_SignedOut)\n            {\n                sharedThis->NotificationService()->UnregisterFromNotificationService(AsyncContext<HRESULT>{ queue });\n            }\n        }\n    });\n\n    RETURN_HR_IF_FAILED(userChangedRegistrationResult.Hresult());\n    m_userChangeEventToken = userChangedRegistrationResult.Payload();\n#endif\n\n    return S_OK;\n}\n\nuint64_t XblContext::Xuid() const\n{\n    return m_user.Xuid();\n}\n\nstd::shared_ptr<social::ProfileService> XblContext::ProfileService()\n{\n    return m_profileService;\n}\n\nstd::shared_ptr<social::SocialService> XblContext::SocialService()\n{\n    return m_socialService;\n}\n\nstd::shared_ptr<social::ReputationService> XblContext::ReputationService()\n{\n    return m_reputationServiceImpl;\n}\n\nstd::shared_ptr<achievements::AchievementsService> XblContext::AchievementsService()\n{\n    return m_achievementService;\n}\n\nstd::shared_ptr<multiplayer::MultiplayerService> XblContext::MultiplayerService()\n{\n    return m_multiplayerService;\n}\n\nstd::shared_ptr<xbox::services::system::StringService> XblContext::StringService()\n{\n    return m_stringService;\n}\n\nstd::shared_ptr<matchmaking::MatchmakingService> XblContext::MatchmakingService()\n{\n    return m_matchmakingService;\n}\n\nstd::shared_ptr<privacy::PrivacyService> XblContext::PrivacyService()\n{\n    return m_privacyService;\n}\n\nstd::shared_ptr<user_statistics::TitleManagedStatisticsService> XblContext::TitleManagedStatisticsService()\n{\n    return m_titleManagedStatisticsService;\n}\n\nstd::shared_ptr<user_statistics::UserStatisticsService> XblContext::UserStatisticsService()\n{\n    return m_userStatisticsService;\n}\n\nstd::shared_ptr<leaderboard::LeaderboardService> XblContext::LeaderboardService()\n{\n    return m_leaderboardService;\n}\n\nstd::shared_ptr<title_storage::TitleStorageService> XblContext::TitleStorageService()\n{\n    return m_titleStorageService;\n}\n\n#ifdef XSAPI_EVENTS_SERVICE\nstd::shared_ptr<events::IEventsService> XblContext::EventsService()\n{\n    return m_eventsService;\n}\n#endif \n\nstd::shared_ptr<presence::PresenceService> XblContext::PresenceService()\n{\n    return m_presenceService;\n}\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\nstd::shared_ptr<notification::NotificationService> XblContext::NotificationService()\n{\n    return m_notificationService;\n}\n#endif\n\nstd::shared_ptr<multiplayer_activity::MultiplayerActivityService> XblContext::MultiplayerActivityService() noexcept\n{\n    return m_multiplayerActivityService;\n}\n\nstd::shared_ptr<XboxLiveContextSettings> XblContext::Settings()\n{\n    return m_xboxLiveContextSettings;\n}\n"
  },
  {
    "path": "Source/Services/Common/xbox_live_context_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n\nusing namespace xbox::services;\n\nSTDAPI XblContextCreateHandle(\n    _In_ XblUserHandle user,\n    _Out_ XblContextHandle* context\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || context == nullptr);\n    auto globalState{ GlobalState::Get() };\n    if (!globalState)\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n\n    auto wrapUserResult{ User::WrapHandle(user) };\n    RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n    auto xboxLiveContext = XblContext::Make(wrapUserResult.ExtractPayload());\n\n    HRESULT hr = xboxLiveContext->Initialize(globalState->RTAManager());\n    if (SUCCEEDED(hr))\n    {\n        xboxLiveContext->AddRef();\n        *context = xboxLiveContext.get();\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextDuplicateHandle(\n    _In_ XblContextHandle handle,\n    _Out_ XblContextHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || duplicatedHandle == nullptr);\n\n    handle->AddRef();\n    *duplicatedHandle = handle;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblContextCloseHandle(\n    _In_ XblContextHandle handle\n) XBL_NOEXCEPT\ntry\n{\n    if (handle)\n    {\n        handle->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblContextGetUser(\n    _In_ XblContextHandle context,\n    _Out_ XblUserHandle* user\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || context == nullptr);\n    return XalUserDuplicateHandle(context->User().Handle(), user);\n}\nCATCH_RETURN()\n\nSTDAPI XblContextGetXboxUserId(\n    _In_ XblContextHandle context,\n    _Out_ uint64_t* xuid\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || xuid == nullptr);\n    *xuid = context->Xuid();\n    return S_OK;\n}\nCATCH_RETURN()\n\nvoid XblSetApiType(\n    _In_ XblApiType apiType\n) XBL_NOEXCEPT\ntry\n{\n    auto state = GlobalState::Get();\n    if (state)\n    {\n        state->ApiType = apiType;\n    }\n}\nCATCH_RETURN_WITH(;)"
  },
  {
    "path": "Source/Services/Common/xbox_live_context_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <mutex>\n\n#include \"achievements_internal.h\"\n#include \"multiplayer_internal.h\"\n#include \"matchmaking_internal.h\"\n#include \"privacy_service_internal.h\"\n#include \"user_statistics_internal.h\"\n#include \"title_managed_statistics_internal.h\"\n#include \"leaderboard_internal.h\"\n#include \"events_service.h\"\n#include \"presence_internal.h\"\n#include \"profile_internal.h\"\n#include \"title_storage_internal.h\"\n#include \"string_service_internal.h\"\n#include \"social_internal.h\"\n#include \"multiplayer_activity_internal.h\"\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#include \"notification_internal.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN\nnamespace legacy\n{\n    class matchmaking_service;\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END\n\nstruct XblContext : public std::enable_shared_from_this<XblContext>, public xbox::services::RefCounter\n{\npublic:\n    static std::shared_ptr<XblContext> Make(\n        _In_ xbox::services::User&&  user\n    ) noexcept;\n\n    ~XblContext();\n\n    const xbox::services::User& User() const noexcept;\n    uint64_t Xuid() const;\n\n    /// <summary>\n    /// A service for managing user profiles.\n    /// </summary>\n    std::shared_ptr<xbox::services::social::ProfileService> ProfileService();\n\n    /// <summary>\n    /// A service for managing social networking links.\n    /// </summary>\n    std::shared_ptr<xbox::services::social::SocialService> SocialService();\n\n    /// <summary>\n    /// A service for managing reputation reports.\n    /// </summary>\n    std::shared_ptr<xbox::services::social::ReputationService> ReputationService();\n\n    /// <summary>\n    /// A service for managing achievements.\n    /// </summary>\n    std::shared_ptr<xbox::services::achievements::AchievementsService> AchievementsService();\n\n    /// <summary>\n    /// A service for managing multiplayer games.\n    /// </summary>\n    std::shared_ptr<xbox::services::multiplayer::MultiplayerService> MultiplayerService();\n\n\n    /// <summary>\n    /// A service for managing Matchmaking Requests.\n    /// </summary>\n    std::shared_ptr<xbox::services::matchmaking::MatchmakingService> MatchmakingService();\n\n    /// <summary>\n    /// A service for managing privacy settings.\n    /// </summary>\n    std::shared_ptr<xbox::services::privacy::PrivacyService> PrivacyService();\n\n    /// <summary>\n    /// A service for verifying strings.\n    /// </summary>\n    std::shared_ptr<xbox::services::system::StringService> StringService();\n\n    /// <summary>\n    /// A service for managing document statistics.\n    /// </summary>\n    std::shared_ptr<xbox::services::user_statistics::TitleManagedStatisticsService> TitleManagedStatisticsService();\n\n    /// <summary>\n    /// A service for managing user statistics.\n    /// </summary>\n    std::shared_ptr<xbox::services::user_statistics::UserStatisticsService> UserStatisticsService();\n\n    /// <summary>\n    /// A service for managing leaderboards.\n    /// </summary>\n    std::shared_ptr<xbox::services::leaderboard::LeaderboardService> LeaderboardService();\n\n    /// <summary>\n    /// A service for managing Rich Presence.\n    /// </summary>\n    std::shared_ptr<xbox::services::presence::PresenceService> PresenceService();\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\n    /// <summary>\n    /// A service used for delivering notifications.\n    /// </summary>\n    std::shared_ptr<xbox::services::notification::NotificationService> NotificationService();\n#endif\n\n    /// <summary>\n    /// A service for storing data in the cloud.\n    /// </summary>\n    std::shared_ptr<xbox::services::title_storage::TitleStorageService> TitleStorageService();\n\n    /// <summary>\n    /// Service for tracking multiplayer activity, recent players, and sending multiplayer invites.\n    /// </summary>\n    std::shared_ptr<xbox::services::multiplayer_activity::MultiplayerActivityService> MultiplayerActivityService() noexcept;\n\n#ifdef XSAPI_EVENTS_SERVICE\n    /// <summary>\n    /// A service used to write in game events.\n    /// </summary>\n    std::shared_ptr<xbox::services::events::IEventsService> EventsService();\n#endif\n\n    std::shared_ptr<xbox::services::AppConfig> ApplicationConfig() const;\n\n    /// <summary>\n    /// Returns an object containing settings that apply to all REST calls made such as retry and diagnostic settings.\n    /// </summary>\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> Settings();\n\n    HRESULT Initialize(std::shared_ptr<real_time_activity::RealTimeActivityManager> rtaManager);\n\nprotected:\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override;\n    XblContext(_In_ xbox::services::User&& user) noexcept\n        : m_user{ std::move(user) }\n    {}\n\nprivate:\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n\n    std::shared_ptr<xbox::services::achievements::AchievementsService> m_achievementService;\n    std::shared_ptr<xbox::services::social::ProfileService> m_profileService;\n    std::shared_ptr<xbox::services::social::ReputationService> m_reputationServiceImpl;\n    std::shared_ptr<xbox::services::social::SocialService> m_socialService;\n    std::shared_ptr<xbox::services::system::StringService> m_stringService;\n    std::shared_ptr<xbox::services::multiplayer::MultiplayerService> m_multiplayerService;\n    std::shared_ptr<xbox::services::matchmaking::MatchmakingService> m_matchmakingService;\n    std::shared_ptr<xbox::services::privacy::PrivacyService> m_privacyService;\n    std::shared_ptr<xbox::services::user_statistics::TitleManagedStatisticsService> m_titleManagedStatisticsService;\n    std::shared_ptr<xbox::services::user_statistics::UserStatisticsService> m_userStatisticsService;\n    std::shared_ptr<xbox::services::leaderboard::LeaderboardService> m_leaderboardService;\n    std::shared_ptr<xbox::services::title_storage::TitleStorageService> m_titleStorageService;\n    std::shared_ptr<xbox::services::multiplayer_activity::MultiplayerActivityService> m_multiplayerActivityService;\n\n    std::shared_ptr<xbox::services::presence::PresenceService> m_presenceService;\n#if !defined(XSAPI_UNIT_TESTS) && (HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL)\n    std::shared_ptr<xbox::services::notification::RTANotificationService> m_notificationService;\n#elif HC_PLATFORM == HC_PLATFORM_UWP\n    std::shared_ptr<xbox::services::notification::UWPNotificationService> m_notificationService;\n#elif HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_IOS\n    std::shared_ptr<xbox::services::notification::MobileNotificationService> m_notificationService;\n#elif defined(XSAPI_NOTIFICATION_SERVICE)\n    std::shared_ptr<xbox::services::notification::NotificationService> m_notificationService;\n#endif\n\n#ifdef XSAPI_EVENTS_SERVICE\n    std::shared_ptr<xbox::services::events::IEventsService> m_eventsService;\n#endif\n\n    uint64_t m_userChangeEventToken{ 0 };\n    uint64_t m_xuid{ 0 };\n\n    xbox::services::User m_user;\n};"
  },
  {
    "path": "Source/Services/Common/xbox_live_context_settings.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include <httpClient/trace.h>\n#endif\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#if __cplusplus_winrt\nWindows::UI::Core::CoreDispatcher^ XboxLiveContextSettings::_s_dispatcher;\n#endif\n\nuint32_t XboxLiveContextSettings::LongHttpTimeout() const\n{\n    return m_longHttpTimeoutInSeconds;\n}\n\nvoid XboxLiveContextSettings::SetLongHttpTimeout(_In_ uint32_t timeoutInSeconds)\n{\n    m_longHttpTimeoutInSeconds = timeoutInSeconds;\n}\n\nuint32_t XboxLiveContextSettings::HttpRetryDelay() const\n{\n    return m_httpRetryDelayInSeconds;\n}\n\nvoid XboxLiveContextSettings::SetHttpRetryDelay(_In_ uint32_t delayInSeconds)\n{\n    m_httpRetryDelayInSeconds = __max(delayInSeconds, MIN_RETRY_DELAY_SECONDS);\n}\n\nuint32_t XboxLiveContextSettings::HttpTimeoutWindow() const\n{\n    return m_httpTimeoutWindowInSeconds;\n}\n\nvoid XboxLiveContextSettings::SetHttpTimeoutWindow(_In_ uint32_t timeoutWindowInSeconds)\n{\n    m_httpTimeoutWindowInSeconds = timeoutWindowInSeconds;\n}\n\nuint32_t XboxLiveContextSettings::WebsocketTimeoutWindow() const\n{\n    return m_websocketTimeoutWindowInSeconds;\n}\n\nvoid XboxLiveContextSettings::SetWebsocketTimeoutWindow(_In_ uint32_t timeoutInSeconds)\n{\n    m_websocketTimeoutWindowInSeconds = timeoutInSeconds;\n}\n\nHttpCallAgent XboxLiveContextSettings::HttpUserAgent() const\n{\n    return m_userAgent;\n}\n\nvoid XboxLiveContextSettings::SetHttpUserAgent(_In_ HttpCallAgent userAgent)\n{\n    m_userAgent = userAgent;\n}\n\n#if XSAPI_WINRT\nbool XboxLiveContextSettings::UseCoreDispatcherForEventRouting() const\n{\n    return m_useCoreDispatcherForEventRouting;\n}\n\nvoid XboxLiveContextSettings::SetUseCoreDispatcherForEventRouting(_In_ bool value)\n{\n    m_useCoreDispatcherForEventRouting = value;\n}\n#endif\n\nbool XboxLiveContextSettings::UseCrossplatformQosServers() const\n{\n    return m_useXplatQosServer;\n}\n\nvoid XboxLiveContextSettings::SetUseCrossplatformQosServers(_In_ bool value)\n{\n    m_useXplatQosServer = value;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\nSTDAPI XblContextSettingsGetLongHttpTimeout(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* timeoutInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || timeoutInSeconds == nullptr);\n    *timeoutInSeconds = context->Settings()->LongHttpTimeout();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsSetLongHttpTimeout(\n    _In_ XblContextHandle context,\n    _In_ uint32_t timeoutInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr);\n    context->Settings()->SetLongHttpTimeout(timeoutInSeconds);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsGetHttpRetryDelay(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* delayInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || delayInSeconds == nullptr);\n    *delayInSeconds = context->Settings()->HttpRetryDelay();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsSetHttpRetryDelay(\n    _In_ XblContextHandle context,\n    _In_ uint32_t delayInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr);\n    context->Settings()->SetHttpRetryDelay(delayInSeconds);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsGetHttpTimeoutWindow(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* timeoutWindowInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || timeoutWindowInSeconds == nullptr);\n    *timeoutWindowInSeconds = context->Settings()->HttpTimeoutWindow();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsSetHttpTimeoutWindow(\n    _In_ XblContextHandle context,\n    _In_ uint32_t timeoutWindowInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr);\n    context->Settings()->SetHttpTimeoutWindow(timeoutWindowInSeconds);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsGetWebsocketTimeoutWindow(\n    _In_ XblContextHandle context,\n    _Out_ uint32_t* timeoutWindowInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || timeoutWindowInSeconds == nullptr);\n    *timeoutWindowInSeconds = context->Settings()->WebsocketTimeoutWindow();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsSetWebsocketTimeoutWindow(\n    _In_ XblContextHandle context,\n    _In_ uint32_t timeoutWindowInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr);\n    context->Settings()->SetWebsocketTimeoutWindow(timeoutWindowInSeconds);\n    return S_OK;\n}\nCATCH_RETURN()\n\n#if XSAPI_WINRT\nSTDAPI XblContextSettingsGetUseCoreDispatcherForEventRouting(\n    _In_ XblContextHandle context,\n    _Out_ bool* useDispatcher\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || useDispatcher == nullptr);\n    *useDispatcher = context->Settings()->UseCoreDispatcherForEventRouting();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsSetUseCoreDispatcherForEventRouting(\n    _In_ XblContextHandle context,\n    _In_ bool useDispatcher\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr);\n    context->Settings()->SetUseCoreDispatcherForEventRouting(useDispatcher);\n    return S_OK;\n}\nCATCH_RETURN()\n#endif\n\nSTDAPI XblContextSettingsGetUseCrossPlatformQosServers(\n    _In_ XblContextHandle context,\n    _Out_ bool* value\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(context == nullptr || value == nullptr);\n    *value = context->Settings()->UseCrossplatformQosServers();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblContextSettingsSetUseCrossPlatformQosServers(\n    _In_ XblContextHandle context,\n    _In_ bool value\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(context);\n    context->Settings()->SetUseCrossplatformQosServers(value);\n    return S_OK;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Common/xbox_live_context_settings_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <mutex>\n#include <unordered_map>\n#include \"xsapi-c/xbox_live_context_settings_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#define DEFAULT_HTTP_TIMEOUT_SECONDS (30)\n#ifdef XSAPI_UNIT_TESTS\n#define MIN_HTTP_TIMEOUT_SECONDS (0) // speed up unit tests\n#else\n#define MIN_HTTP_TIMEOUT_SECONDS (5)\n#endif\n#define MIN_HTTP_TIMEOUT_MILLISECONDS (MIN_HTTP_TIMEOUT_SECONDS * 1000)\n#define DEFAULT_LONG_HTTP_TIMEOUT_SECONDS (5 * 60)\n#ifdef XSAPI_UNIT_TESTS\n#define DEFAULT_WEBSOCKET_TIMEOUT_SECONDS (1)\n#else\n#define DEFAULT_WEBSOCKET_TIMEOUT_SECONDS (60)\n#endif\n#define MAXIMUM_WEBSOCKETS_ACTIVATIONS_ALLOWED_PER_USER (5)\n#define DEFAULT_HTTP_RETRY_WINDOW_SECONDS (20)\n#define DEFAULT_RETRY_DELAY_SECONDS (2)\n#define MIN_RETRY_DELAY_SECONDS (2)\n\nenum class HttpCallAgent : uint32_t\n{\n    Title,\n    MultiplayerManager,\n    SocialManager,\n    MultiplayerActivity,\n    AchievementsManager\n};\n\nclass XboxLiveContextSettings\n{\npublic:\n    XboxLiveContextSettings() = default;\n\n    uint32_t LongHttpTimeout() const;\n    void SetLongHttpTimeout(_In_ uint32_t timeoutInSeconds);\n\n    uint32_t HttpRetryDelay() const;\n    void SetHttpRetryDelay(_In_ uint32_t delayInSeconds);\n\n    uint32_t HttpTimeoutWindow() const;\n    void SetHttpTimeoutWindow(_In_ uint32_t timeoutWindowInSeconds);\n\n    uint32_t WebsocketTimeoutWindow() const;\n    void SetWebsocketTimeoutWindow(_In_ uint32_t timeoutInSeconds);\n\n    HttpCallAgent HttpUserAgent() const;\n    void SetHttpUserAgent(_In_ HttpCallAgent userAgent);\n\n#if XSAPI_WINRT // WinRT only\n    bool UseCoreDispatcherForEventRouting() const;\n\n    void SetUseCoreDispatcherForEventRouting(_In_ bool value);\n#endif\n\n    bool UseCrossplatformQosServers() const;\n    void SetUseCrossplatformQosServers(_In_ bool value);\n\npublic:\n\n#if __cplusplus_winrt\n    static Windows::UI::Core::CoreDispatcher^ _s_dispatcher;\n#endif\n\nprivate:\n    uint32_t m_httpTimeoutInSeconds{ DEFAULT_HTTP_TIMEOUT_SECONDS };\n    uint32_t m_longHttpTimeoutInSeconds{ DEFAULT_LONG_HTTP_TIMEOUT_SECONDS };\n    uint32_t m_httpRetryDelayInSeconds{ DEFAULT_RETRY_DELAY_SECONDS };\n    uint32_t m_httpTimeoutWindowInSeconds{ DEFAULT_HTTP_RETRY_WINDOW_SECONDS };\n    uint32_t m_websocketTimeoutWindowInSeconds{ DEFAULT_WEBSOCKET_TIMEOUT_SECONDS };\n    HttpCallAgent m_userAgent{ HttpCallAgent::Title };\n#if XSAPI_WINRT\n    bool m_useCoreDispatcherForEventRouting{ false };\n#endif\n    bool m_useXplatQosServer{ HC_PLATFORM == HC_PLATFORM_XDK };\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Services/Common/xbox_live_global_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/errors_c.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\n#ifndef MAKE_HTTP_HRESULT\n#define MAKE_HTTP_HRESULT(code) MAKE_HRESULT(1, 0x019, code)\n#endif\n\nSTDAPI XblMemSetFunctions(\n    _In_opt_ XblMemAllocFunction memAllocFunc,\n    _In_opt_ XblMemFreeFunction memFreeFunc\n) XBL_NOEXCEPT\ntry\n{\n    if (GlobalState::Get())\n    {\n        return E_XBL_ALREADY_INITIALIZED;\n    }\n\n    if (memAllocFunc && memFreeFunc)\n    {\n        g_pMemAllocHook = memAllocFunc;\n        g_pMemFreeHook = memFreeFunc;\n    }\n    else if (!memAllocFunc && !memFreeFunc)\n    {\n        g_pMemAllocHook = DefaultAlloc;\n        g_pMemFreeHook = DefaultFree;\n    }\n    else\n    {\n        // Require that the hooks be set together\n        return E_INVALIDARG;\n    }\n\n    // Try to set memory hooks for libHttpClient as well. If it is already initialized (either by Xal or by the client),\n    // there is nothing we can do. We can't log an error either because GlobalState has not yet been set up.\n    auto hr = HCMemSetFunctions(memAllocFunc, memFreeFunc);\n    if (FAILED(hr) && hr != E_HC_ALREADY_INITIALISED)\n    {\n        return hr;\n    }\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMemGetFunctions(\n    _Out_ XblMemAllocFunction* memAllocFunc,\n    _Out_ XblMemFreeFunction* memFreeFunc\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(memAllocFunc == nullptr || memFreeFunc == nullptr);\n\n    *memAllocFunc = g_pMemAllocHook;\n    *memFreeFunc = g_pMemFreeHook;\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblInitialize(\n    _In_ const XblInitArgs* args\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args);\n\n    HRESULT hr = GlobalState::Create(args);\n    LOGS_DEBUG << __FUNCTION__;\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblCleanupAsync(\n    XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    return GlobalState::CleanupAsync(async);\n}\nCATCH_RETURN()\n\nSTDAPI_(XTaskQueueHandle)\nXblGetAsyncQueue() XBL_NOEXCEPT\ntry\n{\n    XTaskQueueHandle duplicatedHandle{ nullptr };\n    auto state = GlobalState::Get();\n    if (state && state->Queue().GetHandle())\n    {\n        XTaskQueueDuplicateHandle(state->Queue().GetHandle(), &duplicatedHandle);\n    }\n    return duplicatedHandle;\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI XblGetScid(\n    _Out_ const char** scid\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(scid);\n    VERIFY_XBL_INITIALIZED();\n\n    *scid = AppConfig::Instance()->Scid().data();\n    return S_OK;\n}\nCATCH_RETURN();\n\nSTDAPI_(XblErrorCondition)\nXblGetErrorCondition(\n    _In_ HRESULT inHr\n    ) XBL_NOEXCEPT\ntry\n{\n    if (SUCCEEDED(inHr))\n    {\n        return XblErrorCondition::NoError;\n    }\n    else if (HRESULT_FACILITY(inHr) == FACILITY_HTTP)\n    {\n        switch (inHr)\n        {\n        case HTTP_E_STATUS_NOT_MODIFIED:\n            return XblErrorCondition::Http304NotModified;\n        case HTTP_E_STATUS_NOT_FOUND:\n            return XblErrorCondition::Http404NotFound;\n        case HTTP_E_STATUS_PRECOND_FAILED:\n            return XblErrorCondition::Http412PreconditionFailed;\n        case MAKE_HTTP_HRESULT(429):\n            return XblErrorCondition::Http429TooManyRequests;\n        case HTTP_E_STATUS_REQUEST_TIMEOUT:\n        case HTTP_E_STATUS_SERVICE_UNAVAIL:\n        case HTTP_E_STATUS_GATEWAY_TIMEOUT:\n            return XblErrorCondition::HttpServiceTimeout;\n        default:\n            return XblErrorCondition::HttpGeneric;\n        }\n    }\n    else if (HRESULT_FACILITY(inHr) == FACILITY_INTERNET)\n    {\n        return XblErrorCondition::Network;\n    }\n    else if ((inHr >= (unsigned)xbl_error_code::AM_E_XASD_UNEXPECTED && inHr <= (unsigned)xbl_error_code::AM_E_XTITLE_TIMEOUT) ||\n             (inHr >= (unsigned)xbl_error_code::XO_E_DEVMODE_NOT_AUTHORIZED && inHr <= (unsigned)xbl_error_code::XO_E_CONTENT_NOT_AUTHORIZED))\n    {\n        return XblErrorCondition::Auth;\n    }\n    else\n    {\n        switch (inHr)\n        {\n        case ONL_E_ACTION_REQUIRED:\n        case E_XBL_AUTH_UNKNOWN_ERROR:\n        case E_XBL_AUTH_RUNTIME_ERROR:\n        case E_XBL_AUTH_NO_TOKEN:\n        case __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER):\n        case __HRESULT_FROM_WIN32(ERROR_CANCELLED):\n            return XblErrorCondition::Auth;\n        case E_BOUNDS:\n            return XblErrorCondition::GenericOutOfRange;\n        default:\n            return XblErrorCondition::GenericError;\n        }\n    }\n}\nCATCH_RETURN_WITH(XblErrorCondition::GenericError)\n\nSTDAPI_(void) XblDisableAssertsForXboxLiveThrottlingInDevSandboxes(\n    _In_ XblConfigSetting setting\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(setting);\n    AppConfig::Instance()->DisableAssertsForXboxLiveThrottlingInDevSandboxes();\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblSetOverrideConfiguration(\n    _In_ const char* overrideScid,\n    _In_ uint32_t overrideTitleId\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(overrideScid);\n    VERIFY_XBL_INITIALIZED();\n    AppConfig::Instance()->SetOverrideScid(overrideScid);\n    AppConfig::Instance()->SetOverrideTitleId(overrideTitleId);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSetOverrideLocale(\n    _In_ char const* overrideLocale\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(overrideLocale);\n    VERIFY_XBL_INITIALIZED();\n    auto state{ GlobalState::Get() };\n    if (state)\n    {\n        state->OverrideLocale(overrideLocale);\n        return S_OK;\n    }\n    else \n    {\n        return E_FAIL;\n    }\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblAddServiceCallRoutedHandler(\n    _In_ XblCallRoutedHandler handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    auto state{ GlobalState::Get() };\n    if (state && handler)\n    {\n        return state->AddServiceCallRoutedHandler(handler, context);\n    }\n    else\n    {\n        return XblFunctionContext{ 0 };\n    }\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblRemoveServiceCallRoutedHandler(\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    auto state{ GlobalState::Get() };\n    if (state)\n    {\n        state->RemoveServiceCallRoutedHandler(token);\n    }\n}\nCATCH_RETURN_WITH(;)\n\n"
  },
  {
    "path": "Source/Services/Events/Android/events_service_android.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_xsapi.h\"\n#include \"a/java_interop.h\"\n#include \"a/jni_utils.h\"\n#include <cll/AndroidPartA.h>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nvoid EventsService::InitializeTenantSettings()\n{\n    m_tenantSettings = MakeShared<cll::CllTenantSettings>(cll::AndroidPartA(java_interop::get_java_interop_singleton()->GetJniEnv(), nullptr, IKey()));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END"
  },
  {
    "path": "Source/Services/Events/Generic/events_service_generic.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n\n#include <cll/GenericPartA.h>\n\n#include \"events_service_xsapi.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nvoid EventsService::InitializeTenantSettings()\n{\n    auto appConfig = AppConfig::Instance();\n\n    // .c_str() to force conversion from xsapi_internal_string const& to std::string&&\n    m_tenantSettings = MakeShared<cll::CllTenantSettings>(cll::GenericPartA{\n        IKey().c_str(),\n        appConfig->AppId().c_str(),\n        appConfig->AppVer().c_str(),\n        appConfig->OsName().c_str(),\n        appConfig->OsLocale().c_str(),\n        appConfig->OsVersion().c_str(),\n        appConfig->DeviceClass().c_str(),\n        appConfig->DeviceId().c_str()\n    });\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END"
  },
  {
    "path": "Source/Services/Events/Windows/events_service_windows.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_xsapi.h\"\n#include <cll/Windows7PartA.h>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nvoid EventsService::InitializeTenantSettings()\n{\n    m_tenantSettings = MakeShared<cll::CllTenantSettings>(cll::Windows7PartA(IKey()));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END"
  },
  {
    "path": "Source/Services/Events/event.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_xsapi.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include \"cll/BasicJsonWriter.h\"\n#include \"cll/ConversionHelpers.h\"\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\n#define EVENT_NAME_PREFIX \"Microsoft.XboxLive.T\"\n\nEvent::Event(\n    _In_ uint64_t xuid,\n    _In_ const xsapi_internal_string& eventName,\n    _In_ const JsonValue& dimensions,\n    _In_ const JsonValue& measurements,\n    _In_ xbox::services::datetime timestamp\n) :\n    m_xuid{ xuid },\n    m_eventName{ eventName },\n    m_fullEventName{ EVENT_NAME_PREFIX + std::to_string(AppConfig::Instance()->TitleId()) + \".\" + m_eventName.data() },\n    m_timestamp{ std::move(timestamp) }\n{\n\n    JsonUtils::CopyFrom(m_dimensions, dimensions);\n    JsonUtils::CopyFrom(m_measurements, measurements);\n\n    bool state;\n\n    cll::BasicJsonWriter::StartObject(m_data, state);\n    cll::BasicJsonWriter::WriteField(m_data, state, \"baseType\", \"Microsoft.XboxLive.InGame\");\n    cll::BasicJsonWriter::StartStruct(m_data, state, \"baseData\");\n\n    cll::BasicJsonWriter::WriteField(m_data, state, \"name\", eventName.data());\n    cll::BasicJsonWriter::WriteField(m_data, state, \"serviceConfigId\", AppConfig::Instance()->Scid().data());\n    cll::BasicJsonWriter::WriteField(m_data, state, \"titleId\", std::to_string(AppConfig::Instance()->TitleId()));\n    cll::BasicJsonWriter::WriteField(m_data, state, \"userId\", utils::uint64_to_internal_string(xuid).data());\n\n    if (dimensions.IsObject())\n    {\n        cll::BasicJsonWriter::StartStruct(m_data, state, \"properties\");\n\n        for (const auto& pair : dimensions.GetObject())\n        {\n#if _WIN32\n            cll::BasicJsonWriter::WriteSerializedStruct(m_data, state, pair.name.GetString(), JsonUtils::SerializeJson(pair.value).c_str());\n#else\n            cll::BasicJsonWriter::WriteSerializedStruct(m_data, state, pair.name.GetString(), JsonUtils::SerializeJson(pair.value).c_str());\n#endif\n        }\n        cll::BasicJsonWriter::EndStruct(m_data, state); // properties\n    }\n\n    if (measurements.IsObject())\n    {\n        cll::BasicJsonWriter::StartStruct(m_data, state, \"measurements\");\n        for (const auto& pair : measurements.GetObject())\n        {\n#if _WIN32\n            cll::BasicJsonWriter::WriteSerializedStruct(m_data, state, pair.name.GetString(), JsonUtils::SerializeJson(pair.value).c_str());\n#else\n            cll::BasicJsonWriter::WriteSerializedStruct(m_data, state, pair.name.GetString(), JsonUtils::SerializeJson(pair.value).c_str());\n#endif\n        }\n        cll::BasicJsonWriter::EndStruct(m_data, state); // measurements\n    }\n\n    cll::BasicJsonWriter::EndStruct(m_data, state); // baseData\n    cll::BasicJsonWriter::EndObject(m_data, state);\n}\n\nEvent::Event(const Event& other)\n{\n    m_xuid = other.m_xuid;\n    m_eventName = other.m_eventName;\n    m_fullEventName = other.m_fullEventName;\n    JsonUtils::CopyFrom(m_dimensions, other.m_dimensions);\n    JsonUtils::CopyFrom(m_measurements, other.m_measurements);\n    m_timestamp = other.m_timestamp;\n    m_data = other.m_data;\n}\n\nResult<Event> Event::Deserialize(\n    _In_ const xsapi_internal_string& inputData\n)\n{\n    // tab-separated (0x0A)\n    // xuid | event name | timestamp | dimensions json | measurements json\n\n    auto parts = utils::string_split_internal(inputData, '\\t');\n\n    if (parts.size() < 5)\n    {\n        return Result<Event>{ Event{}, E_FAIL };\n    }\n\n    auto xuid = utils::internal_string_to_uint64(parts[0]);\n    auto& eventName = parts[1];\n    auto timestamp = xbox::services::datetime::from_string(parts[2], xbox::services::datetime::ISO_8601);\n\n    JsonDocument dimensionsJson;\n    dimensionsJson.Parse(parts[3].data());\n    JsonDocument measurementsJson;\n    measurementsJson.Parse(parts[4].data());\n\n    if (dimensionsJson.IsNull() || measurementsJson.IsNull())\n    {\n        return Result<Event>{ Event{}, E_FAIL };\n    }\n\n    return Result<Event>(Event{ xuid, eventName, dimensionsJson, measurementsJson, timestamp });\n}\n\nconst std::string& Event::Data() const\n{\n    return m_data;\n}\n\nconst std::string& Event::FullEventName() const\n{\n    return m_fullEventName;\n}\n\nconst xbox::services::datetime& Event::Timestamp() const\n{\n    return m_timestamp;\n}\n\nstd::string Event::SerializeFieldValue(\n    _In_ const JsonValue& value\n)\n{\n    xsapi_internal_string valueStr;\n    if (value.IsString())\n    {\n        valueStr = value.GetString();\n    }\n    else\n    {\n        valueStr = JsonUtils::SerializeJson(value);\n    }\n    return valueStr.data();\n}\n\nxsapi_internal_string Event::Serialize() const\n{\n    // serialization format\n    // tab-separated (0x0A)\n    // xuid | event name | timestamp | dimensions json | measurements json\n\n    char seperator{ '\\t' };\n\n    xsapi_internal_stringstream ss;\n\n    ss << m_xuid << seperator;\n    ss << m_eventName << seperator;\n    ss << m_timestamp.to_string(xbox::services::datetime::ISO_8601) << seperator;\n    ss << JsonUtils::SerializeJson(m_dimensions) << seperator;\n    ss << JsonUtils::SerializeJson(m_measurements);\n\n    return ss.str();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n"
  },
  {
    "path": "Source/Services/Events/event_queue.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_xsapi.h\"\n#include \"local_storage.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nEventQueue::EventQueue(\n    User&& user,\n    std::shared_ptr<cll::CllTenantSettings> tenantSettings\n) :\n    m_user{ std::move(user) },\n    m_tenantSettings{ tenantSettings }\n{\n    auto state{ GlobalState::Get() };\n    assert(state);\n    m_localStorage = state->LocalStorage();\n\n    Stringstream ss;\n    ss << m_filenamePrefix << m_user.Xuid() << \".dir\";\n    m_directoryFilename = ss.str();\n}\n\nvoid EventQueue::Initialize()\n{\n    // Initialize in memory directory. Treat as write through cache, don't read from directory file on disk after this.\n    m_localStorage->ReadAsync(m_user, m_directoryFilename,\n        [\n            weakThis = std::weak_ptr<EventQueue>{ shared_from_this() }\n        ]\n    (Result<xsapi_internal_vector<uint8_t>> result)\n    {\n        auto sharedThis{ weakThis.lock() };\n        if (sharedThis && Succeeded(result))\n        {\n            auto& bytes = result.Payload();\n            auto fileMetadata = utils::string_split_internal(xsapi_internal_string{ bytes.begin(), bytes.end() }, '\\n');\n\n            std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n            for (auto& metadata : fileMetadata)\n            {\n                xsapi_internal_stringstream ss{ metadata };\n                xsapi_internal_string filename;\n                uint64_t fileSize{ 0 };\n                ss >> filename >> fileSize;\n\n                sharedThis->m_fileMetadata[filename] = fileSize;\n                sharedThis->m_totalFilesSize += fileSize;\n            }\n\n            sharedThis->Populate();\n        }\n    });\n}\n\nvoid EventQueue::Cleanup()\n{\n    // Doing this in a cleanup method rather than the destructor so that we can ensure queue lifetime\n    // during the asynchronous flush. If we are already in the destructor, we can't take a shared reference\n    // to the queue.\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    // Make sure the failed payload gets flushed as well\n    if (m_failedPayload)\n    {\n        m_queue.push_back(std::move(m_failedPayload));\n    }\n    Flush();\n}\n\nHRESULT EventQueue::AddEvent(Event&& event)\n{\n    return AddEvents(xsapi_internal_vector<Event>{ 1, std::move(event) });\n}\n\nHRESULT EventQueue::AddEvents(xsapi_internal_vector<Event>&& events)\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    std::shared_ptr<EventUploadPayload> payload;\n    if (m_queue.empty())\n    {\n        auto copyUserResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n        payload = MakeShared<EventUploadPayload>(copyUserResult.ExtractPayload(), m_tenantSettings);\n        m_queue.push_back(payload);\n    }\n    else\n    {\n        payload = m_queue.back();\n    }\n\n    for (auto& event : events)\n    {\n        auto hr = payload->AddEvent(event);\n        if (FAILED(hr))\n        {\n            auto copyUserResult = m_user.Copy();\n            RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n            payload = MakeShared<EventUploadPayload>(copyUserResult.ExtractPayload(), m_tenantSettings);\n            m_queue.push_back(payload);\n            hr = payload->AddEvent(event);\n            RETURN_HR_IF_FAILED(hr);\n        }\n    }\n\n    if (m_mode == Mode::Offline)\n    {\n        return Flush();\n    }\n\n    return S_OK;\n}\n\nstd::shared_ptr<EventUploadPayload> EventQueue::GetNextPayload(size_t minimumEventCount)\n{\n    std::lock_guard<std::mutex> guard{ m_mutex };\n\n    std::shared_ptr<EventUploadPayload> nextPayload{ nullptr };\n\n    if (m_failedPayload)\n    {\n        std::swap(m_failedPayload, nextPayload);\n    }\n    else if (!m_queue.empty() && m_queue.front()->EventCount() >= minimumEventCount)\n    {\n        nextPayload = m_queue.front();\n        m_queue.pop_front();\n    }\n\n    return nextPayload;\n}\n\nvoid EventQueue::SetMode(Mode mode)\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    if (m_mode == mode)\n    {\n        return;\n    }\n\n    m_mode = mode;\n    switch (mode)\n    {\n        case Mode::Offline:\n        {\n            assert(m_failedPayload);\n            Flush();\n            break;\n        }\n        case Mode::Normal:\n        {\n            Populate();\n            break;\n        }\n    }\n}\n\nvoid EventQueue::RequeueFailedPayload(std::shared_ptr<EventUploadPayload> failedPayload)\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_failedPayload = std::move(failedPayload);\n}\n\nHRESULT EventQueue::Populate()\n{\n    // Ensure that m_mutex is locked when calling this helper function\n\n    for (auto& metadata : m_fileMetadata)\n    {\n        HRESULT hr = m_localStorage->ReadAsync(\n            m_user,\n            metadata.first,\n            [\n                metadata = std::pair<xsapi_internal_string, uint64_t>{ metadata },\n                weakThis = std::weak_ptr<EventQueue>{ shared_from_this() }\n            ]\n        (Result<Vector<uint8_t>> readResult)\n        {\n            auto sharedThis{ weakThis.lock() };\n            if (sharedThis && Succeeded(readResult) && sharedThis->m_mode == Mode::Normal)\n            {\n                auto& bytes = readResult.Payload();\n                auto serializedEvents = utils::string_split_internal(xsapi_internal_string{ bytes.begin(), bytes.end() }, '\\n');\n\n                for (const auto& serializedEvent : serializedEvents)\n                {\n                    auto deserializationResult = Event::Deserialize(serializedEvent);\n                    if (Succeeded(deserializationResult))\n                    {\n                        sharedThis->AddEvent(deserializationResult.ExtractPayload());\n                    }\n                }\n\n                {\n                    std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n                    sharedThis->m_totalFilesSize -= metadata.second;\n                    sharedThis->m_fileMetadata.erase(metadata.first);\n                    sharedThis->WriteDirectoryFile();\n                }\n\n                auto clearAsyncHR = sharedThis->m_localStorage->ClearAsync(sharedThis->m_user, metadata.first, nullptr);\n                if (FAILED(clearAsyncHR))\n                {\n                    // Log failure but don't let when failure prevent populating the rest of the files.\n                    LOGS_WARN << \"Failed to read events file due to user being available. HR = \" << clearAsyncHR;\n                }\n            }\n        });\n\n        if (FAILED(hr))\n        {\n            // Log failure but don't let when failure prevent populating the rest of the files.\n            LOGS_WARN << \"Failed to read events file \" << metadata.first << \" that appeared in \" << m_directoryFilename;\n        }\n    }\n\n    return S_OK;\n}\n\nHRESULT EventQueue::Flush()\n{\n    // Ensure that m_mutex is locked when calling this helper function\n\n    if (m_flushInProgress)\n    {\n        return S_OK;\n    }\n\n    // If there is an existing non-full file, continue writing to that\n    std::pair<String, uint64_t> fileMetadata{ \"\", 0 };\n    if (!m_fileMetadata.empty() && m_fileMetadata.rbegin()->second < m_maxFileSize)\n    {\n        fileMetadata = *m_fileMetadata.rbegin();\n    }\n\n    xsapi_internal_vector<uint8_t> flushData;\n    auto targetDataSize = static_cast<size_t>(m_maxFileSize - fileMetadata.second);\n    flushData.reserve(targetDataSize + static_cast<size_t>(m_tenantSettings->getMaxEventSizeInBytes()));\n    xbox::services::datetime earliestTimestamp{ xbox::services::datetime::utc_now() };\n\n    for (auto iter = m_queue.begin(); iter != m_queue.end(); iter = m_queue.erase(iter))\n    {\n        auto payload{ *iter };\n        auto eventsRemainingInPayload = payload->ExtractEventsAndSerialize(flushData, targetDataSize, earliestTimestamp);\n\n        if (eventsRemainingInPayload)\n        {\n            // The only reason events can be remaining after ExtractEventsAndSerialize is if the flushData was full.\n            // Break early so the partial payload doesn't get erased from queue.\n            break;\n        }\n    }\n\n    if (flushData.empty())\n    {\n        return S_OK;\n    }\n\n    // Construct filename if we don't already have one\n    if (fileMetadata.first.empty())\n    {\n        Stringstream ss;\n        ss << m_filenamePrefix << std::hex << std::uppercase << earliestTimestamp.to_interval() << \".json\";\n        fileMetadata.first = ss.str();\n\n        assert(m_fileMetadata.empty() || fileMetadata.first > m_fileMetadata.rend()->first);\n    }\n\n    m_flushInProgress = true;\n\n    // To avoid client event data from being lost, we never want to cleanup before\n    // we finish flushing unuploaded events\n    auto holdCleanup{ GlobalState::Get() };\n    assert(holdCleanup);\n\n    HRESULT hr = m_localStorage->WriteAsync(\n        m_user,\n        XblLocalStorageWriteMode::Append,\n        fileMetadata.first,\n        std::move(flushData),\n        [\n            sharedThis{ shared_from_this() },\n            filename{ fileMetadata.first },\n            holdCleanup\n        ]\n    (Result<size_t> result)\n    {\n        std::lock_guard<std::mutex> lock{ sharedThis->m_mutex };\n        assert(sharedThis->m_flushInProgress);\n        sharedThis->m_flushInProgress = false;\n\n        if (Succeeded(result))\n        {\n            auto previousFileSize{ sharedThis->m_fileMetadata[filename] };\n            auto newFileSize{ result.ExtractPayload() };\n            sharedThis->m_totalFilesSize += (newFileSize - previousFileSize);\n            sharedThis->m_fileMetadata[filename] = newFileSize;\n\n            while (sharedThis->m_totalFilesSize > sharedThis->m_storageAllotment)\n            {\n                LOGS_INFO << \"Offline events files have exceeded the configured storage allotment.\";\n                LOGS_INFO << \"The oldest events file will be deleted and offline event data will be permanently lost.\";\n\n                auto metadataToDelete{ sharedThis->m_fileMetadata.begin() };\n                sharedThis->m_totalFilesSize -= metadataToDelete->second;\n                \n                auto clearAsyncHR = sharedThis->m_localStorage->ClearAsync(sharedThis->m_user, metadataToDelete->first, nullptr);\n                if (SUCCEEDED(clearAsyncHR))\n                {\n                    sharedThis->m_fileMetadata.erase(metadataToDelete);\n                }\n                else \n                {\n                    LOGS_INFO << \"The user is currently unavailable. Failed to clear oldest event.\";\n                    return; //todo: What's the proper handling here?\n                }\n            }\n\n            sharedThis->WriteDirectoryFile();\n            sharedThis->Flush();\n        }\n    });\n\n    return hr;\n}\n\nHRESULT EventQueue::WriteDirectoryFile()\n{\n    // Ensure that m_mutex is locked when calling this helper function\n\n    xsapi_internal_vector<uint8_t> data;\n    for (auto& metadata : m_fileMetadata)\n    {\n        data.insert(data.end(), metadata.first.begin(), metadata.first.end());\n        data.push_back('\\t');\n\n        auto sizeString{ utils::uint64_to_internal_string(metadata.second) };\n        data.insert(data.end(), sizeString.begin(), sizeString.end());\n        data.push_back('\\n');\n    }\n\n    auto holdCleanup{ GlobalState::Get() };\n    assert(holdCleanup);\n\n    return m_localStorage->WriteAsync(\n        m_user,\n        XblLocalStorageWriteMode::Truncate,\n        m_directoryFilename,\n        std::move(data),\n        [\n            holdCleanup\n        ]\n    (Result<size_t> result)\n    {\n        if (Failed(result))\n        {\n            LOGS_ERROR << \"Failed to write events directory file. Offline event data may be lost!\";\n        }\n    });\n}\n\nHRESULT EventQueue::SetMaxFileSize(uint64_t fileSizeInBytes)\n{\n    if (fileSizeInBytes < 1024)\n    {\n        LOGS_ERROR << \"Max file size must be at least 1kb\";\n        return E_INVALIDARG;\n    }\n\n    m_maxFileSize = fileSizeInBytes;\n    return S_OK;\n}\n\nHRESULT EventQueue::SetStorageAllotment(uint64_t storageAllotmentInBytes)\n{\n    if (storageAllotmentInBytes < m_maxFileSize)\n    {\n        LOGS_ERROR << \"Storage allotment must be greater than the maximum file size.\";\n        return E_INVALIDARG;\n    }\n\n    m_storageAllotment = storageAllotmentInBytes;\n    return S_OK;\n}\n\nuint64_t EventQueue::m_maxFileSize{ 128000 }; // default file size of 128k\nuint64_t EventQueue::m_storageAllotment{ m_maxFileSize * 150 }; // default storage allotment of 150 files (~20MB)\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n"
  },
  {
    "path": "Source/Services/Events/event_upload_payload.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_xsapi.h\"\n#include \"cll/ExceptionCodes.h\"\n\n#define DEVICE_TICKET_ID    \"1\"\n#define USER_TICKET_ID      \"2\"\n\nusing namespace xbox::services::legacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nEventUploadPayload::EventUploadPayload(\n    _In_ User&& user,\n    _In_ std::shared_ptr<cll::CllTenantSettings> tenantSettings\n) :\n    m_user{ std::move(user) },\n    m_tenantSettings{ tenantSettings }\n{\n}\n\nHRESULT EventUploadPayload::AddEvent(_In_ const Event& event)\n{\n    if (m_events.size() >= static_cast<size_t>(m_tenantSettings->getMaxEventsPerPost()))\n    {\n        LOGS_DEBUG << \"Cannot add more events to payload.\";\n        return E_FAIL;\n    }\n\n    m_events.push_back(event);\n    return S_OK;\n}\n\nsize_t EventUploadPayload::EventCount() const\n{\n    return m_events.size();\n}\n\nHRESULT EventUploadPayload::GetRequestData(\n    _In_ AsyncContext<Result<const RequestData&>> async\n)\n{\n    if (!m_requestData.requestBody.empty())\n    {\n        async.Complete(m_requestData);\n        return S_OK;\n    }\n\n    return CreateTicketData({ async.Queue(),\n        [\n            sharedThis{ shared_from_this() },\n            async\n        ]\n    (Result<std::vector<cll::TicketData>> result)\n    {\n        if (Succeeded(result))\n        {\n            cll::CllUploadRequestData cllRequestData;\n            for (auto& event : sharedThis->m_events)\n            {\n                cll::CllEvent cllEvent;\n                sharedThis->m_tenantSettings->populateEvent(\n                    cllEvent,\n                    EventsService::IKey(),\n                    event.FullEventName(),\n                    event.Data(),\n                    event.Timestamp().to_string(xbox::services::datetime::date_format::ISO_8601).c_str(),\n                    cll::LatencyNormal,\n                    cll::PersistenceUnspecified,\n                    cll::SensitivityUnspecified,\n                    cll::SampleRate_Unspecified,\n                    result.Payload(),\n                    cll::CorrelationVector{}\n                );\n\n                sharedThis->m_tenantSettings->addEventToRequest(cllEvent, cllRequestData);\n            }\n\n            sharedThis->m_requestData.requestBody = cllRequestData.getRequestBody().data();\n            for (const auto& header : cllRequestData.getHeaders())\n            {\n                sharedThis->m_requestData.headers[header.first.data()] = header.second.data();\n            }\n        }\n\n        async.Complete(Result<const RequestData&>{ sharedThis->m_requestData, result.Hresult() });\n    }\n    });\n}\n\nsize_t EventUploadPayload::ExtractEventsAndSerialize(\n    _Inout_ xsapi_internal_vector<uint8_t>& serializedData,\n    _In_ size_t targetDataSize,\n    _Inout_ xbox::services::datetime& timestamp\n)\n{\n    for (auto iter = m_events.begin(); iter != m_events.end() && serializedData.size() < targetDataSize; iter = m_events.erase(iter))\n    {\n        auto& event{ *iter };\n\n        auto serializedEvent = event.Serialize();\n        serializedData.insert(serializedData.end(), serializedEvent.begin(), serializedEvent.end());\n        serializedData.push_back('\\n');\n\n        if (event.Timestamp() < timestamp)\n        {\n            timestamp = event.Timestamp();\n        }\n    }\n\n    return m_events.size();\n}\n\nHRESULT EventUploadPayload::CreateTicketData(\n    _In_ AsyncContext<Result<std::vector<cll::TicketData>>> async\n)\n{\n    m_user.GetTokenAndSignature(\"POST\", \"https://vortex-win.data.microsoft.com\", {}, nullptr, 0, false, { async.Queue(),\n        [\n            async,\n            sharedThis{ shared_from_this() }\n        ]\n    (Result<TokenAndSignature> result)\n    {\n        if (Failed(result))\n        {\n            return async.Complete(result.Hresult());\n        }\n        \n        cll::TicketData deviceTicketData {\n            cll::TicketType::TicketTypeXauthDevice,\n            DEVICE_TICKET_ID,\n            result.Payload().token.data()\n        };\n\n        sharedThis->m_user.GetTokenAndSignature(\"POST\", \"https://vortex-events.xboxlive.com\", {}, nullptr, 0, false, { async.Queue(),\n            [\n                async,\n                deviceTicketData\n            ]\n        (Result<TokenAndSignature> result)\n        {\n            if (Failed(result))\n            {\n                return async.Complete(result.Hresult());\n            }\n\n            cll::TicketData userTicketData{\n                cll::TicketType::TicketTypeXauthUser,\n                USER_TICKET_ID,\n                result.Payload().token.data()\n            };\n\n            return async.Complete(std::vector<cll::TicketData>{ deviceTicketData, userTicketData });\n        }\n        });\n    }\n    });\n\n    return S_OK;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END"
  },
  {
    "path": "Source/Services/Events/events_service.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nclass IEventsService\n{\npublic:\n    virtual HRESULT WriteInGameEvent(\n        _In_z_ const char* eventName,\n        _In_opt_z_ const char* dimensions,\n        _In_opt_z_ const char* measurements\n    ) = 0;\n\n    virtual HRESULT Initialize() = 0;\n\n    virtual ~IEventsService() = default;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n\n#ifdef XSAPI_EVENTS_SERVICE\n    #ifdef XSAPI_GRTS_EVENTS_SERVICE\n        #include \"events_service_gdk.h\"\n    #elif defined(XSAPI_WRL_EVENTS_SERVICE)\n        #include \"events_service_etw.h\"\n    #elif defined(XSAPI_INTERNAL_EVENTS_SERVICE)\n        #include \"events_service_xsapi.h\"\n    #endif\n#endif\n"
  },
  {
    "path": "Source/Services/Events/events_service_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/events_c.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\n\nSTDAPI XblEventsWriteInGameEvent(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* eventName,\n    _In_opt_z_ const char* dimensions,\n    _In_opt_z_ const char* measurements\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || eventName == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return xboxLiveContext->EventsService()->WriteInGameEvent(eventName, dimensions, measurements);\n}\nCATCH_RETURN()\n\n#ifdef XSAPI_INTERNAL_EVENTS_SERVICE\n\nSTDAPI XblEventsSetStorageAllotment(\n    uint64_t storageAllotmentInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return events::EventQueue::SetStorageAllotment(storageAllotmentInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblEventsSetMaxFileSize(\n    uint64_t maxFileSizeInByes\n) XBL_NOEXCEPT\ntry\n{\n    return events::EventQueue::SetMaxFileSize(maxFileSizeInByes);\n}\nCATCH_RETURN()\n\n#endif // !XSAPI_ETW_EVENTS_SERVICE"
  },
  {
    "path": "Source/Services/Events/events_service_etw.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n\n#ifdef XSAPI_WRL_EVENTS_SERVICE\n\n#include \"events_service_etw.h\"\n\n#include <initguid.h>\n#include <wrl.h>\n#include <windows.foundation.diagnostics.h>\n\nusing namespace xbox::services::system;\nusing namespace Microsoft::WRL;\nusing namespace Microsoft::WRL::Wrappers;\nusing namespace ABI::Windows::Foundation;\nusing namespace ABI::Windows::Foundation::Diagnostics;\n\nDEFINE_GUID(XSAPI_TELEMETRY_GROUP,\n    0x53b78fc6, 0xe359, 0x453e, 0x89, 0xfe, 0xa5, 0xf4, 0xe5, 0xff, 0x4a, 0xf3);\n\n// {5E9EDC93-F04F-47EC-8DCB-0CF8F3442BDC}\nDEFINE_GUID(GUID_LOGGING_CHANNEL,\n    0x5e9edc93, 0xf04f, 0x47ec, 0x8d, 0xcb, 0xc, 0xf8, 0xf3, 0x44, 0x2b, 0xdc);\n\n#define XBOX_LIVE_LOGGING_OPTIONS  0x0000800000000000\n#define XBOX_LIVE_LOGGING_TAGS  0x00B00000\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nEventsService::EventsService(_In_ User&& user)\n    : m_user{ std::move(user) }\n{\n    m_playSession = utils::create_guid(true);\n}\n\nEventsService::~EventsService()\n{\n#if HC_PLATFORM != HC_PLATFORM_UWP\n    if (SUCCEEDED(m_hrCoIncrementMTAUsage))\n    {\n        CoDecrementMTAUsage(m_mtaUsageCookie);\n    }\n#endif\n}\n\nHRESULT EventsService::Initialize(\n)\n{\n\n#if HC_PLATFORM != HC_PLATFORM_UWP\n    m_hrCoIncrementMTAUsage = CoIncrementMTAUsage(&m_mtaUsageCookie);\n    if (FAILED(m_hrCoIncrementMTAUsage))\n    {\n        LOG_DEBUG(\"CoIncrementMTAUsage failed with during EventsService::Initialize.\");\n        return m_hrCoIncrementMTAUsage;\n    }\n#endif\n\n    ComPtr<ILoggingChannelOptionsFactory> loggingChannelOptionsFactory;\n    HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Diagnostics_LoggingChannelOptions).Get(), &loggingChannelOptionsFactory);\n    if (FAILED(hr))\n    {\n        LOG_DEBUG(\"GetActivationFactory for ILoggingChannelOptionsFactory failed during EventsService::Initialize.\");\n        return hr;\n    }\n\n    ComPtr<ILoggingChannelOptions> loggingChannelOptions;\n    hr = loggingChannelOptionsFactory->Create(XSAPI_TELEMETRY_GROUP, &loggingChannelOptions);\n    if (FAILED(hr))\n    {\n        LOG_DEBUG(\"ILoggingChannelOptions::Create failed during EventsService::Initialize.\");\n        return hr;\n    }\n\n    ComPtr<ILoggingChannelFactory2> loggingChannelFactory;\n    hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Diagnostics_LoggingChannel).Get(), &loggingChannelFactory);\n    if (FAILED(hr))\n    {\n        LOG_DEBUG(\"GetActivationFactory for ILoggingChannelFactory2 failed during EventsService::Initialize.\");\n        return hr;\n    }\n\n    xsapi_internal_wstringstream ss;\n    ss << L\"Microsoft.XboxLive.T\" << AppConfig::Instance()->TitleId();\n\n    HString channelName;\n    channelName.Set(ss.str().data());\n    hr = loggingChannelFactory->CreateWithOptionsAndId(channelName.Get(), loggingChannelOptions.Get(), GUID_LOGGING_CHANNEL, &m_loggingChannel);\n    if (FAILED(hr))\n    {\n        LOG_DEBUG(\"ILoggingChannelFactory2::CreateWithOptionsAndId failed during EventsService::Initialize.\");\n        return hr;\n    }\n\n    ComPtr<ILoggingOptionsFactory> loggingOptionsFactory;\n    hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Diagnostics_LoggingOptions).Get(), &loggingOptionsFactory);\n    if (FAILED(hr))\n    {\n        LOG_DEBUG(\"GetActivationFactory for ILoggingOptionsFactory failed during EventsService::Initialize.\");\n        return hr;\n    }\n\n    hr = loggingOptionsFactory->CreateWithKeywords(XBOX_LIVE_LOGGING_OPTIONS, &m_loggingOptions);\n    if (FAILED(hr))\n    {\n        LOG_DEBUG(\"ILoggingOptionsFactory::CreateWithKeywords failed during EventsService::Initialize.\");\n        return hr;\n    }\n\n    m_loggingOptions->put_Tags(XBOX_LIVE_LOGGING_TAGS);\n\n    return S_OK;\n}\n\nHRESULT EventsService::WriteInGameEvent(\n    _In_z_ const char* eventName,\n    _In_opt_z_ const char* dimensions,\n    _In_opt_z_ const char* measurements\n)\n{\n    JsonDocument dimensionsJson;\n    JsonDocument measurementsJson;\n\n    std::regex regex(\"[A-Za-z]+[A-Za-z0-9_]*\");\n    bool matchFound = std::regex_match(eventName, regex);\n    if (!matchFound)\n    {\n        LOG_DEBUG(\"Invalid event name\");\n        return E_INVALIDARG;\n    }\n\n    if (dimensions)\n    {\n        dimensionsJson.Parse(dimensions);\n    }\n    if (measurements)\n    {\n        measurementsJson.Parse(measurements);\n    }\n\n    if(dimensionsJson.HasParseError() || measurementsJson.HasParseError())\n    {\n        LOG_DEBUG(\"Unable to parse json string\");\n        return E_INVALIDARG;\n    }\n\n    return WriteInGameEventHelper(eventName, dimensionsJson, measurementsJson);\n}\n\n\nHRESULT EventsService::WriteInGameEventHelper(\n    _In_ const xsapi_internal_string& eventName,\n    _In_ const JsonValue& dimensions,\n    _In_ const JsonValue& measurements\n)\n{\n    try\n    {\n        auto fields = CreateLoggingFields(eventName, dimensions, measurements);\n\n        //m_loggingChannel->loge\n        ComPtr<ILoggingTarget> loggingTarget;\n        m_loggingChannel->QueryInterface(__uuidof(ILoggingTarget), &loggingTarget);\n\n        loggingTarget->LogEventWithFieldsAndOptions(utils::HStringFromUtf8(eventName.data()).Get(), fields.Get(), LoggingLevel_Critical, m_loggingOptions.Get());\n    }\n    catch (const std::exception&)\n    {\n        return utils::convert_exception_to_hresult();\n    }\n    catch (...)\n    {\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\nComPtr<ILoggingFields> EventsService::CreateLoggingFields(\n    _In_ const xsapi_internal_string& eventName,\n    _In_ const JsonValue& dimensions,\n    _In_ const JsonValue& measurements\n)\n{\n    THROW_CPP_INVALIDARGUMENT_IF_STRING_EMPTY(eventName);\n    THROW_CPP_INVALIDARGUMENT_IF(!(dimensions.IsObject() || dimensions.IsNull()));\n    THROW_CPP_INVALIDARGUMENT_IF(!(measurements.IsObject() || measurements.IsNull()));\n\n    ComPtr<ILoggingFields> fields;\n    RoActivateInstance(HStringReference(RuntimeClass_Windows_Foundation_Diagnostics_LoggingFields).Get(), &fields);\n\n    fields->BeginStruct(HStringReference(L\"PartB_Microsoft.XboxLive.InGame\").Get());\n    fields->AddString(HStringReference(L\"name\").Get(), utils::HStringFromUtf8(eventName.data()).Get());\n\n    fields->AddString(HStringReference(L\"serviceConfigId\").Get(), utils::HStringFromUtf8(AppConfig::Instance()->Scid().data()).Get());\n    fields->AddString(HStringReference(L\"playerSessionId\").Get(), utils::HStringFromUtf8(m_playSession.data()).Get());\n    fields->AddUInt32(HStringReference(L\"titleId\").Get(), AppConfig::Instance()->TitleId());\n    fields->AddString(HStringReference(L\"userId\").Get(), utils::HStringFromUtf8(utils::uint64_to_internal_string(m_user.Xuid()).data()).Get());\n    fields->AddUInt16(HStringReference(L\"ver\").Get(), 1);\n\n    if (dimensions.IsObject())\n    {\n        // Add properties\n        fields->BeginStruct(HStringReference(L\"properties\").Get());\n        for (const auto& jsonPair : dimensions.GetObject())\n        {\n            std::pair<xsapi_internal_string, JsonDocument> pair;\n            pair.first = jsonPair.name.GetString();\n            JsonUtils::CopyFrom(pair.second, jsonPair.value);\n            AddValuePair(fields, pair);\n        }\n        fields->EndStruct();\n    }\n\n    if (measurements.IsObject())\n    {\n        // Add measurements\n        fields->BeginStruct(HStringReference(L\"measurements\").Get());\n        for (const auto& jsonPair : measurements.GetObject())\n        {\n            std::pair<xsapi_internal_string, JsonDocument> pair;\n            pair.first = jsonPair.name.GetString();\n            JsonUtils::CopyFrom(pair.second, jsonPair.value);\n            AddValuePair(fields, pair);\n        }\n        fields->EndStruct();\n    }\n\n    fields->EndStruct();\n\n    return fields;\n}\n\nvoid EventsService::AddValuePair(\n    _Inout_ Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Diagnostics::ILoggingFields> fields,\n    _In_ const std::pair<xsapi_internal_string, JsonDocument>& pair\n)\n{\n    // check property name.\n    const auto& name = pair.first;\n    THROW_CPP_INVALIDARGUMENT_IF_STRING_EMPTY(name);\n\n    std::regex regex(\"[A-Za-z]+[A-Za-z0-9]*\");\n    bool matchFound = std::regex_match(name, regex);\n    if (!matchFound)\n    {\n        throw std::invalid_argument(\"Invalid properties or measurements name\");\n    }\n\n    auto s = utility::conversions::utf8_to_utf16(name.data());\n    HStringReference propertyName{ s.c_str() };\n\n    const auto& value = pair.second;\n    switch (value.GetType())\n    {\n    case rapidjson::Type::kNumberType:\n        // if value can fit into int64, add as int64\n        if (value.IsInt64())\n        {\n            fields->AddInt64(propertyName.Get(), value.GetInt64());\n        }\n        else if (value.IsUint64())\n        {\n            fields->AddUInt64(propertyName.Get(), value.GetUint64());\n        }\n        else\n        {\n            fields->AddDouble(propertyName.Get(), value.GetDouble());\n        }\n        break;\n\n    case rapidjson::Type::kTrueType:\n    case rapidjson::Type::kFalseType:\n        fields->AddBoolean(propertyName.Get(), value.GetBool());\n        break;\n\n    case rapidjson::Type::kNullType:\n        fields->AddEmpty(propertyName.Get());\n        break;\n\n    case rapidjson::Type::kStringType:\n        fields->AddString(propertyName.Get(), HStringReference(utils::string_t_from_internal_string(value.GetString()).data()).Get());\n        break;\n\n    default:\n        throw std::invalid_argument(\"Logging property type not supported\");\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n\n#endif"
  },
  {
    "path": "Source/Services/Events/events_service_etw.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#ifdef XSAPI_WRL_EVENTS_SERVICE\n\n#include <wrl.h>\n#include <windows.foundation.diagnostics.h>\n#include \"events_service.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nclass EventsService : public IEventsService, public std::enable_shared_from_this<EventsService>\n{\npublic:\n    EventsService(_In_ User&& user);\n    ~EventsService();\n\n    HRESULT Initialize();\n\n    HRESULT WriteInGameEvent(\n        _In_z_ const char* eventName,\n        _In_opt_z_ const char* dimensions,\n        _In_opt_z_ const char* measurements\n    );\n\nprivate:\n    HRESULT WriteInGameEventHelper(\n        _In_ const xsapi_internal_string& eventName,\n        _In_ const JsonValue& dimensions,\n        _In_ const JsonValue& measurement\n    );\n\n    CO_MTA_USAGE_COOKIE m_mtaUsageCookie = nullptr;\n#if HC_PLATFORM != HC_PLATFORM_UWP\n    HRESULT m_hrCoIncrementMTAUsage = E_FAIL;\n#endif\n    User m_user;\n\n    xsapi_internal_string m_playSession;\n    xsapi_internal_string m_scid;\n\n    Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Diagnostics::ILoggingChannel> m_loggingChannel;\n    Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Diagnostics::ILoggingOptions> m_loggingOptions;\n\n    void AddValuePair(\n        _Inout_ Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Diagnostics::ILoggingFields> fields,\n        _In_ const std::pair<xsapi_internal_string, JsonDocument>& pair\n    );\n\n    Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Diagnostics::ILoggingFields> CreateLoggingFields(\n        _In_ const xsapi_internal_string& eventName,\n        _In_ const JsonValue& properties,\n        _In_ const JsonValue& measurement\n    );\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n\n#endif"
  },
  {
    "path": "Source/Services/Events/events_service_gdk.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_gdk.h\"\n\n#if XSAPI_BUILD_WITH_1910_GRTS\n\n#include \"XGameEvent.h\"\n#include \"XGameRuntimeFeature.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nEventsService::EventsService(\n    User&& user\n) :\n    m_user{ std::move(user) },\n    m_playSession{ utils::create_guid(true) }\n{\n}\n\nEventsService::~EventsService()\n{\n}\n\nHRESULT EventsService::Initialize()\n{\n    return S_OK;\n}\n\nHRESULT EventsService::WriteInGameEvent(\n    _In_z_ const char* eventName,\n    _In_opt_z_ const char* dimensions,\n    _In_opt_z_ const char* measurements\n)\n{\n    if (XGameRuntimeIsFeatureAvailable(XGameRuntimeFeature::XGameEvent))\n    {\n        const char* scid{ nullptr };\n        HRESULT hr = XblGetScid(&scid);\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        String lowercaseScid = utils::ToLower(scid);\n\n        return XGameEventWrite(\n            m_user.Handle(),\n            lowercaseScid.c_str(),\n            m_playSession.c_str(), \n            eventName, \n            dimensions, \n            measurements);\n    }\n    else\n    {\n        return E_NOTIMPL;\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n\n#endif"
  },
  {
    "path": "Source/Services/Events/events_service_gdk.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"events_service.h\"\n\n#if XSAPI_BUILD_WITH_1910_GRTS\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nclass EventsService : public IEventsService, public std::enable_shared_from_this<EventsService>\n{\npublic:\n    EventsService(_In_ User&& user);\n    ~EventsService();\n\n    HRESULT Initialize();\n\n    HRESULT WriteInGameEvent(   \n        _In_z_ const char* eventName,\n        _In_opt_z_ const char* dimensions,\n        _In_opt_z_ const char* measurements\n    );\n\nprivate:\n    User m_user;\n    xsapi_internal_string m_playSession;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n\n#endif XSAPI_BUILD_WITH_1910_GRTS\n"
  },
  {
    "path": "Source/Services/Events/events_service_xsapi.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/events_c.h\"\n#include \"events_service_xsapi.h\"\n#include \"xbox_live_context_internal.h\"\n#include <cll/Windows7PartA.h>\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nEventsService::EventsService(\n    _In_ User user,\n    _In_ const TaskQueue& queue\n) :\n    m_user{ std::move(user) },\n    m_queue{ queue.DeriveWorkerQueue() }\n{\n    InitializeTenantSettings();\n}\n\nEventsService::~EventsService()\n{\n    assert(m_eventQueue);\n    m_eventQueue->Cleanup();\n}\n\nHRESULT EventsService::Initialize()\n{\n    auto copyUserResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n    m_eventQueue = MakeShared<EventQueue>(copyUserResult.ExtractPayload(), m_tenantSettings);\n    m_eventQueue->Initialize();\n    return ScheduleUpload();\n}\n\nHRESULT EventsService::WriteInGameEvent(\n    _In_z_ const char* eventName,\n    _In_opt_z_ const char* dimensions,\n    _In_opt_z_ const char* measurements\n)\n{\n    JsonDocument dimensionsJson;\n    JsonDocument measurementsJson;\n\n    std::regex regex(\"[A-Za-z]+[A-Za-z0-9_]*\");\n    bool matchFound = std::regex_match(eventName, regex);\n    if (!matchFound)\n    {\n        LOG_DEBUG(\"Invalid event name\");\n        return E_INVALIDARG;\n    }\n\n    if (dimensions)\n    {\n        dimensionsJson.Parse(dimensions);\n    }\n    if (measurements)\n    {\n        measurementsJson.Parse(measurements);\n    }\n\n    if(dimensionsJson.HasParseError() || measurementsJson.HasParseError())\n    {\n        LOG_DEBUG(\"Unable to parse json string\");\n        return E_INVALIDARG;\n    }\n\n    return WriteInGameEventHelper(eventName, dimensionsJson, measurementsJson);\n}\n\nHRESULT EventsService::WriteInGameEventHelper(\n    _In_ const xsapi_internal_string& eventName,\n    _In_ const JsonValue& dimensions,\n    _In_ const JsonValue& measurements\n)\n{\n    return m_eventQueue->AddEvent(Event{ m_user.Xuid(), eventName, dimensions, measurements });\n}\n\nconst std::string& EventsService::IKey()\n{\n    static std::string iKey;\n\n    if (iKey.empty())\n    {\n        std::stringstream defaultIKey;\n        defaultIKey << \"P-XBL-T\" << AppConfig::Instance()->TitleId();\n        iKey = defaultIKey.str();\n    }\n    return iKey;\n}\n\nHRESULT EventsService::ScheduleUpload() noexcept\n{\n    auto hr = m_queue.RunWork([ weakThis = std::weak_ptr<EventsService>{ shared_from_this() } ]\n        {\n            auto state{ GlobalState::Get() };\n            auto sharedThis{ weakThis.lock() };\n\n            // Don't schedule another upload if XblCleanup has been called. Otherwise,\n            // ensure lifetime of EventsService & GlobalState until the upload is complete\n            // to make sure no client data is lost.\n            if (sharedThis && state)\n            {\n                sharedThis->UploadAsync(AsyncContext<>{ [ sharedThis, state ]\n                    {\n                        // Schedule the next upload\n                        sharedThis->ScheduleUpload();\n                    }\n                    });\n            }\n        },\n        __min(std::pow(2, m_numRetryAttempts), 600) * m_minimumUploadIntervalInMs\n    );\n\n    if (FAILED(hr))\n    {\n        // Not much we can do if RunWork fails so just log the error and return\n        LOGS_ERROR << __FUNCTION__ << \" failed with HRESULT \" << hr;\n    }\n\n    return hr;\n}\n\nvoid EventsService::UploadAsync(\n    AsyncContext<> async\n) noexcept\n{\n    // If more than m_maximumUploadIntervalInMs has passed since the last upload, begin an upload\n    // with whatever events are pending. Otherwise, wait until we have at least m_payloadMinimumEventCount\n    // events and return immediately.\n    uint64_t timeSinceLastUpload = std::chrono::duration_cast<std::chrono::milliseconds> (chrono_clock_t::now() - m_lastUploadAttempt).count();\n    size_t payloadMinumumEventCount = timeSinceLastUpload > m_maximumUploadIntervalInMs ? 1 : m_payloadMinimumEventCount;\n\n    std::shared_ptr<EventUploadPayload> payload = m_eventQueue->GetNextPayload(payloadMinumumEventCount);\n    if (!payload)\n    {\n        return async.Complete();\n    }\n\n    HRESULT hr = UploadEventPayload(payload, AsyncContext<HRESULT>{ TaskQueue(),\n        [\n            sharedThis{ shared_from_this() },\n            payload,\n            async\n        ]\n    (HRESULT hr)\n        {\n            // Super naive implementation for now - on every failed upload switch to offline mode, on every successful upload\n            // switch to normal mode. This will incur a lot of disk I/O so this needs to be tuned long term.\n            switch (hr)\n            {\n            //Intentional fallthrough here for certain failure http statuses.\n            //Failures that shouldn't be retried are functionally the same as successes,\n            //in that we want to reset the backoff process and not requeue the payload.\n            case HTTP_E_STATUS_BAD_REQUEST:\n                //Retrying a 400 likely won't resolve the issue. Drop the request.\n                //TODO: [natiskan] Write telemetry to keep track of failed 400s.\n            case S_OK:\n                sharedThis->m_numRetryAttempts = 0;\n                sharedThis->m_eventQueue->SetMode(Mode::Normal);\n                break;\n            default:\n                sharedThis->OnFailedPayload(payload);\n                sharedThis->m_eventQueue->SetMode(Mode::Offline);\n                break;\n            }\n\n            async.Complete();\n        }\n    });\n\n    if (FAILED(hr))\n    {\n        OnFailedPayload(payload);\n        return async.Complete();\n    }\n}\n\nHRESULT EventsService::UploadEventPayload(\n    std::shared_ptr<EventUploadPayload> payload,\n    AsyncContext<HRESULT> async\n)\n{\n    m_lastUploadAttempt = chrono_clock_t::now();\n\n    return payload->GetRequestData({ async.Queue(),\n        [\n            weakThis = std::weak_ptr<EventsService>{ shared_from_this() },\n            async\n        ]\n    (Result<const EventUploadPayload::RequestData&> result)\n    {\n        auto sharedThis{ weakThis.lock() };\n        if (sharedThis && Succeeded(result))\n        {\n\n            Result<User> userResult = sharedThis->m_user.Copy();\n            if (FAILED(userResult.Hresult()))\n            {\n                return async.Complete(userResult.Hresult());\n            }\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            auto hr = httpCall->Init(MakeShared<XboxLiveContextSettings>(), \"POST\", sharedThis->m_eventUploadUrl, xbox_live_api::events_upload);\n            if (FAILED(hr))\n            {\n                return async.Complete(hr);\n            }\n\n            // Don't allow retries. We want to fail as fast as possible and the payload will\n            // be retried by the EventsService later anyways.\n            httpCall->SetRetryAllowed(false);\n            //Explicitly allow retry of 401s with an updated token, as this can only retry once at most\n            httpCall->SetAuthRetryAllowed(true);\n            httpCall->SetTimeout(sharedThis->m_uploadTimeoutInSeconds);\n\n            for (auto& header : result.Payload().headers)\n            {\n                httpCall->SetHeader(header.first, header.second);\n            }\n\n            httpCall->SetRequestBody(result.Payload().requestBody);\n\n            httpCall->Perform(AsyncContext<HttpResult>{\n                async.Queue().GetHandle(),\n                [\n                    async\n                ]\n            (HttpResult result)\n            {\n                HRESULT hr = result.Hresult();\n                if (SUCCEEDED(hr))\n                {\n                    hr = result.Payload()->Result();\n                    if (FAILED(hr))\n                    {\n                        HC_TRACE_INFORMATION(XSAPI, \"Event upload failed with HTTP status %u\", result.Payload()->HttpStatus());\n                    }\n                }\n                async.Complete(hr);\n            }\n            });\n        }\n    }\n    });\n}\n\nvoid xbox::services::events::EventsService::OnFailedPayload(std::shared_ptr<EventUploadPayload> failedPayload)\n{\n    m_eventQueue->RequeueFailedPayload(failedPayload);\n    m_numRetryAttempts++;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n"
  },
  {
    "path": "Source/Services/Events/events_service_xsapi.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <cll/CllPartA.h>\n#include <cll/CllTenantSettings.h>\n#include \"events_service.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nclass Event\n{\npublic:\n    Event(\n        _In_ uint64_t xuid,\n        _In_ const xsapi_internal_string& eventName,\n        _In_ const JsonValue& dimensions,\n        _In_ const JsonValue& measurements,\n        _In_ xbox::services::datetime timestamp = xbox::services::datetime::utc_now()\n    );\n\n    Event(const Event& other);\n\n    static Result<Event> Deserialize(\n        _In_ const xsapi_internal_string& inputData\n    );\n\n    const std::string& Data() const;\n    const std::string& FullEventName() const;\n    const xbox::services::datetime& Timestamp() const;\n\n    xsapi_internal_string Serialize() const;\n\nprivate:\n    Event() = default;\n\n    std::string SerializeFieldValue(\n        _In_ const JsonValue& value\n    );\n\n    uint64_t m_xuid{ 0 };\n    xsapi_internal_string m_eventName;\n    std::string m_fullEventName;\n    JsonDocument m_dimensions;\n    JsonDocument m_measurements;\n    xbox::services::datetime m_timestamp;\n    std::string m_data;\n};\n\nclass EventUploadPayload : public std::enable_shared_from_this<EventUploadPayload>\n{\npublic:\n    EventUploadPayload(\n        _In_ User&& user,\n        _In_ std::shared_ptr<cll::CllTenantSettings> tenantSettings\n    );\n\n    HRESULT AddEvent(_In_ const Event& event);\n    size_t EventCount() const;\n\n    struct RequestData\n    {\n        xsapi_internal_http_headers headers;\n        xsapi_internal_string requestBody;\n    };\n\n    HRESULT GetRequestData(_In_ AsyncContext<Result<const RequestData&>> async);\n\n    size_t ExtractEventsAndSerialize(\n        _Inout_ xsapi_internal_vector<uint8_t>& serializedData,\n        _In_ size_t targetDataSize,\n        _Inout_ xbox::services::datetime& timestamp\n    );\n\nprivate:\n    HRESULT CreateTicketData(\n        _In_ AsyncContext<Result<std::vector<cll::TicketData>>> async\n    );\n\n    User m_user;\n    std::shared_ptr<cll::CllTenantSettings> m_tenantSettings;\n    cll::CllUploadRequestData m_cllRequestData;\n    RequestData m_requestData;\n    xsapi_internal_list<Event> m_events;\n};\n\nenum class Mode\n{\n    Normal,\n    Offline\n};\n\n// Class to manage pending events\nclass EventQueue : public std::enable_shared_from_this<EventQueue>\n{\npublic:\n    EventQueue(\n        User&& user,\n        std::shared_ptr<cll::CllTenantSettings> tenantSettings\n    );\n\n    void Initialize();\n    void Cleanup();\n\n    HRESULT AddEvent(Event&& event);\n    HRESULT AddEvents(xsapi_internal_vector<Event>&& events);\n    std::shared_ptr<EventUploadPayload> GetNextPayload(size_t minimumEventCount = 1);\n    void SetMode(Mode mode);\n    void RequeueFailedPayload(std::shared_ptr<EventUploadPayload> failedPayload);\n\n    static HRESULT SetMaxFileSize(uint64_t fileSizeInBytes);\n    static HRESULT SetStorageAllotment(uint64_t storageAllotmentInBytes);\n\nprivate:\n    HRESULT WriteDirectoryFile();\n    HRESULT Populate();\n    HRESULT Flush();\n\n    std::mutex m_mutex;\n    std::atomic<Mode> m_mode{ Mode::Normal };\n\n    User m_user;\n    std::shared_ptr<cll::CllTenantSettings> m_tenantSettings;\n\n    xsapi_internal_string const m_filenamePrefix{ \"XblEvents\" };\n    xsapi_internal_string m_directoryFilename;\n\n    xsapi_internal_list<std::shared_ptr<EventUploadPayload>> m_queue;\n    std::shared_ptr<EventUploadPayload> m_failedPayload;\n\n    // flush metadata\n    Map<String, uint64_t> m_fileMetadata;\n    uint64_t m_totalFilesSize{ 0 };\n    bool m_flushInProgress{ false };\n\n    std::shared_ptr<system::LocalStorage> m_localStorage;\n\n    static uint64_t m_maxFileSize;\n    static uint64_t m_storageAllotment;\n};\n\nclass EventsService : public IEventsService, public std::enable_shared_from_this<EventsService>\n{\npublic:\n    EventsService(\n        _In_ User user,\n        _In_ const TaskQueue& queue\n    );\n    ~EventsService();\n\n    HRESULT Initialize();\n\n    HRESULT WriteInGameEvent(\n        _In_z_ const char* eventName,\n        _In_opt_z_ const char* dimensions,\n        _In_opt_z_ const char* measurements\n    );\n\n    static const std::string& IKey();\n\nprivate:\n    HRESULT WriteInGameEventHelper(\n        _In_ const xsapi_internal_string& eventName,\n        _In_ const JsonValue& dimensions,\n        _In_ const JsonValue& measurement\n    );\n\n    User m_user;\n    TaskQueue m_queue;\n\n    void InitializeTenantSettings();\n\n    HRESULT ScheduleUpload() noexcept;\n    void UploadAsync(AsyncContext<> async) noexcept;\n\n    HRESULT UploadEventPayload(\n        std::shared_ptr<EventUploadPayload> payload,\n        AsyncContext<HRESULT> async\n    );\n\n    void OnFailedPayload(std::shared_ptr<EventUploadPayload> failedPayload);\n\n    uint64_t m_minimumUploadIntervalInMs{ 1000 };\n    uint64_t m_maximumUploadIntervalInMs{ 5000 };\n    size_t m_payloadMinimumEventCount{ 1 };\n    uint32_t m_numRetryAttempts{ 0 };\n    xsapi_internal_string m_eventUploadUrl{ \"https://vortex.data.microsoft.com/collect/v1\" };\n    uint32_t m_uploadTimeoutInSeconds{ 5 };\n\n    chrono_clock_t::time_point m_lastUploadAttempt{ chrono_clock_t::now() };\n\n    std::shared_ptr<EventQueue> m_eventQueue;\n\n    std::shared_ptr<cll::CllTenantSettings> m_tenantSettings;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n"
  },
  {
    "path": "Source/Services/Events/iOS/events_service_ios.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"events_service_xsapi.h\"\n#include <cll/iOSPartA.h>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN\n\nvoid EventsService::InitializeTenantSettings()\n{\n    m_tenantSettings = MakeShared<cll::CllTenantSettings>(cll::iOSPartA(IKey()));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END\n"
  },
  {
    "path": "Source/Services/Leaderboard/leaderboard_column.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"shared_macros.h\"\n#include \"leaderboard_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN\n\nLeaderboardColumn::LeaderboardColumn()\n{\n    m_statName = xsapi_internal_string();\n    m_statType = legacy::leaderboard_stat_type::stat_other;\n}\n\nLeaderboardColumn::LeaderboardColumn(\n    _In_ xsapi_internal_string statName,\n    _In_ legacy::leaderboard_stat_type stat_type\n    ) :\n    m_statName(std::move(statName)),\n    m_statType(std::move(stat_type))\n{ }\n\nconst xsapi_internal_string&\nLeaderboardColumn::StatName() const\n{\n    return m_statName;\n}\n\nlegacy::leaderboard_stat_type\nLeaderboardColumn::StatType() const\n{\n    return m_statType;\n}\n\n/* static */ xbox::services::Result<xbox::services::leaderboard::LeaderboardColumn> LeaderboardColumn::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    xsapi_internal_string statName;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"statName\", statName, true));\n    xsapi_internal_string statTypeStr;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"type\", statTypeStr, true));\n    legacy::leaderboard_stat_type statType = legacy::leaderboard_stat_type::stat_other;\n\n    if (utils::str_icmp_internal(statTypeStr, \"Integer\") == 0)\n    {\n        statType = legacy::leaderboard_stat_type::stat_uint64;\n    }\n    else if (utils::str_icmp_internal(statTypeStr, \"Double\") == 0)\n    {\n        statType = legacy::leaderboard_stat_type::stat_double;\n    }\n    else if (utils::str_icmp_internal(statTypeStr, \"String\") == 0)\n    {\n        statType = legacy::leaderboard_stat_type::stat_string;\n    }\n\n    return LeaderboardColumn(\n        std::move(statName),\n        statType\n    );\n}\n\nsize_t \nLeaderboardColumn::SizeOf()\n{\n    size_t size = sizeof(XblLeaderboardColumn);\n    size += m_statName.size() + 1;\n    size = static_cast<size_t>((size + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n    return size;\n}\n\nchar* \nLeaderboardColumn::Serialize(XblLeaderboardColumn* column, char* buffer)\n{\n    utils::strcpy(buffer, m_statName.size() + 1, m_statName.c_str());\n    column->statName = static_cast<char*>(buffer);\n    size_t s = m_statName.size() + 1;\n    if ((s % XBL_ALIGN_SIZE) != 0) {\n        s = static_cast<size_t>((s + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n    }\n    buffer += s;\n\n    XblLeaderboardStatType statType = XblLeaderboardStatType::Other;\n    if (m_statType == legacy::leaderboard_stat_type::stat_boolean) statType = XblLeaderboardStatType::Boolean;\n    else if (m_statType == legacy::leaderboard_stat_type::stat_double) statType = XblLeaderboardStatType::Double;\n    else if (m_statType == legacy::leaderboard_stat_type::stat_string) statType = XblLeaderboardStatType::String;\n    else if (m_statType == legacy::leaderboard_stat_type::stat_uint64) statType = XblLeaderboardStatType::Uint64;\n    column->statType = statType;\n\n    return buffer;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END"
  },
  {
    "path": "Source/Services/Leaderboard/leaderboard_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xsapi-c/leaderboard_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN\n\nclass LeaderboardResult;\n\nnamespace legacy\n{\n    /// <summary>Enumerates the data type of a leaderboard statistic.</summary>\n    enum class leaderboard_stat_type\n    {\n        /// <summary>Unsigned 64 bit integer.</summary>\n        stat_uint64,\n\n        /// <summary>Boolean.</summary>\n        stat_boolean,\n\n        /// <summary>Double.</summary>\n        stat_double,\n\n        /// <summary>String.</summary>\n        stat_string,\n\n        /// <summary>Unknown.</summary>\n        stat_other\n    };\n}\n\nstruct LeaderboardGlobalQuery\n{\n    xsapi_internal_string scid;\n    xsapi_internal_string name;\n    xsapi_internal_string xuid;\n    xsapi_internal_string socialGroup;\n    xsapi_internal_vector<xsapi_internal_string> columns;\n    bool isTitleManaged{ false };\n};\n\nstruct LeaderboardSocialQuery\n{\n    xsapi_internal_string xuid;\n    xsapi_internal_string scid;\n    xsapi_internal_string statName;\n    xsapi_internal_string socialGroup;\n    xsapi_internal_string sortOrder;\n    bool isTitleManaged{ false };\n};\n\nclass LeaderboardColumn\n{\npublic:\n    LeaderboardColumn();\n    LeaderboardColumn(\n        _In_ xsapi_internal_string statName,\n        _In_ legacy::leaderboard_stat_type stat_type\n    );\n\n    static Result<LeaderboardColumn> Deserialize(\n        _In_ const JsonValue& json\n    );\n    size_t SizeOf();\n    char* Serialize(XblLeaderboardColumn* column, char* buffer);\n\n    const xsapi_internal_string& StatName() const;\n    legacy::leaderboard_stat_type StatType() const;\n\nprivate:\n    xsapi_internal_string m_statName;\n    legacy::leaderboard_stat_type m_statType;\n};\n\nclass LeaderboardRow\n{\npublic:\n    LeaderboardRow();\n\n    LeaderboardRow(\n        _In_ xsapi_internal_string gamertag,\n        _In_ xsapi_internal_string modernGamertag,\n        _In_ xsapi_internal_string modernGamertagSuffix,\n        _In_ xsapi_internal_string uniqueModernGamertag,\n        _In_ uint64_t xboxUserId,\n        _In_ double percentile,\n        _In_ uint32_t rank,\n        _In_ uint32_t globalRank,\n        _In_ xsapi_internal_vector<xsapi_internal_string> columnValues,\n        _In_ xsapi_internal_string metadata\n    );\n\n    LeaderboardRow(const LeaderboardRow& other);\n    \n    LeaderboardRow& operator =(const LeaderboardRow& other);\n\n    static Result<LeaderboardRow> Deserialize(\n        _In_ const JsonValue& json\n    );\n    size_t SizeOf();\n    char* Serialize(XblLeaderboardRow* row, char* buffer);\n\n    const xsapi_internal_string& Gamertag() const;\n    const xsapi_internal_string& ModernGamertag() const;\n    const xsapi_internal_string& ModernGamertagSuffix() const;\n    const xsapi_internal_string& UniqueGamertagSuffix() const;\n    uint64_t XboxUserId() const;\n    double Percentile() const;\n    uint32_t Rank() const;\n    uint32_t GlobalRank() const;\n    const xsapi_internal_vector<xsapi_internal_string>& ColumnValues() const;\n\nprivate:\n    xsapi_internal_string m_gamertag;\n    xsapi_internal_string m_modernGamertag;\n    xsapi_internal_string m_modernGamertagSuffix;\n    xsapi_internal_string m_uniqueModernGamertag;\n    uint64_t m_xuid{ 0 };\n    double m_percentile{ 0.0 };\n    uint32_t m_rank{ 0 };\n    uint32_t m_globalRank{ 0 };\n    xsapi_internal_vector<xsapi_internal_string> m_columnValues;\n    xsapi_internal_vector<const char*> m_columnValuesC;\n    JsonDocument m_metadata;\n\n    friend LeaderboardResult;\n};\n\nclass LeaderboardResult\n{\npublic:\n    LeaderboardResult() = default;\n    static Result<LeaderboardResult> Deserialize(_In_ const JsonValue& json);\n\n    size_t SizeOfQuery();\n    char* SerializeQuery(XblLeaderboardQuery* query, char* buffer);\n    size_t SizeOf();\n    char* Serialize(char* buffer);\n    XblSocialGroupType ParseSocialGroup(xsapi_internal_string socialGroupStr);\n\n    uint32_t TotalRowCount() const;\n    const xsapi_internal_vector<LeaderboardColumn>& Columns() const;\n    const xsapi_internal_vector<LeaderboardRow>& Rows() const;\n    bool HasNext() const;\n    \n    void SetNextQuery(std::shared_ptr<LeaderboardGlobalQuery> query);\n    void SetNextQuery(std::shared_ptr<LeaderboardSocialQuery> query);\n    void ParseAdditionalColumns(const xsapi_internal_vector<xsapi_internal_string>& additionalColumnNames);\n\nprivate:\n    LeaderboardResult(\n        _In_ uint32_t totalRowCount,\n        _In_ String continuationToken,\n        _In_ Vector<LeaderboardColumn> columns,\n        _In_ Vector<LeaderboardRow> rows\n    );\n\n    uint32_t m_totalRowCount{};\n    String m_continuationToken;\n    Vector<LeaderboardColumn> m_columns;\n    Vector<LeaderboardRow> m_rows;\n\n    std::shared_ptr<LeaderboardGlobalQuery> m_globalQuery;\n    xsapi_internal_vector<const char*> m_additionalColumnleaderboardNamesC;\n    std::shared_ptr<LeaderboardSocialQuery> m_socialQuery;\n};\n\nclass LeaderboardService : public std::enable_shared_from_this<LeaderboardService>\n{\npublic:\n    LeaderboardService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<xbox::services::AppConfig> appConfig\n    );\n\n    HRESULT GetLeaderboardForSocialGroup(\n        _In_ const xsapi_internal_string& xuid,\n        _In_ const xsapi_internal_string& scid,\n        _In_ const xsapi_internal_string& statName,\n        _In_ const xsapi_internal_string& socialGroup,\n        _In_ uint32_t skipToRank,\n        _In_ const xsapi_internal_string& skipToXuid,\n        _In_ const xsapi_internal_string& sortOrder,\n        _In_ uint32_t maxItems,\n        _In_ const xsapi_internal_string& continuationToken,\n        _In_ bool isTitleManaged,\n        _In_ XAsyncBlock* async\n    );\n\n    HRESULT GetLeaderboard(\n        _In_ const xsapi_internal_string& scid,\n        _In_ const xsapi_internal_string& name,\n        _In_ uint32_t skipToRank,\n        _In_ const xsapi_internal_string& skipToXuid,\n        _In_ const xsapi_internal_string& xuid,\n        _In_ const xsapi_internal_string& socialGroup,\n        _In_ uint32_t maxItems,\n        _In_ const xsapi_internal_string& continuationToken,\n        _In_ const xsapi_internal_vector<xsapi_internal_string>& additionalColumnNames,\n        _In_ bool isTitleManaged,\n        _In_ XAsyncBlock* async\n    );\n\nprivate:\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<xbox::services::AppConfig> m_appConfig;\n\n    friend LeaderboardResult;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END"
  },
  {
    "path": "Source/Services/Leaderboard/leaderboard_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"leaderboard_internal.h\"\n#include \"social_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN\n\nLeaderboardResult::LeaderboardResult(\n    _In_ uint32_t totalRowCount,\n    _In_ String continuationToken,\n    _In_ Vector<LeaderboardColumn> columns,\n    _In_ Vector<LeaderboardRow> rows\n) :\n    m_totalRowCount{ totalRowCount },\n    m_continuationToken{ std::move(continuationToken) },\n    m_columns{ std::move(columns) },\n    m_rows{ std::move(rows) }\n{\n}\n\nuint32_t \nLeaderboardResult::TotalRowCount() const\n{\n    return m_totalRowCount;\n}\n\nconst xsapi_internal_vector<LeaderboardColumn>& \nLeaderboardResult::Columns() const\n{\n    return m_columns;\n}\n\nconst xsapi_internal_vector<LeaderboardRow>& \nLeaderboardResult::Rows() const\n{\n    return m_rows;\n}\n\nvoid \nLeaderboardResult::SetNextQuery(std::shared_ptr<LeaderboardGlobalQuery> query)\n{\n    m_globalQuery = std::move(query);\n}\n\nvoid \nLeaderboardResult::SetNextQuery(std::shared_ptr<LeaderboardSocialQuery> query)\n{\n    m_socialQuery = std::move(query);\n}\n\nvoid \nLeaderboardResult::ParseAdditionalColumns(const xsapi_internal_vector<xsapi_internal_string>& additionalColumnNames)\n{\n    xsapi_internal_vector<LeaderboardColumn> columns;\n    if (m_columns.size() == 0)\n    {\n        return;\n    }\n    columns.push_back(m_columns[0]);\n\n    std::unordered_map<xsapi_internal_string, legacy::leaderboard_stat_type> stats;\n\n    for (auto& row : m_rows)\n    {\n        for (uint32_t i = 0; i < additionalColumnNames.size(); ++i)\n        {\n            const xsapi_internal_string& columnName = additionalColumnNames[i];\n            auto stat = stats.find(columnName);\n            if (row.m_metadata.IsObject() && row.m_metadata.HasMember(columnName.data()))\n            {\n                const JsonValue& val = row.m_metadata[columnName.c_str()];\n                if (stat == stats.end() || stat->second == legacy::leaderboard_stat_type::stat_other)\n                {\n                    if (val.IsBool())\n                    {\n                        stats[columnName] = legacy::leaderboard_stat_type::stat_boolean;\n                    }\n                    else if (val.IsNumber())\n                    {\n                        stats[columnName] = legacy::leaderboard_stat_type::stat_double;\n                    }\n                    else if (val.IsString())\n                    {\n                        stats[columnName] = legacy::leaderboard_stat_type::stat_string;\n                    }\n                    else\n                    {\n                        stats[columnName] = legacy::leaderboard_stat_type::stat_other;\n                    }\n\n                }\n\n                auto columnValues = JsonUtils::SerializeJson(val);\n                if (i >= row.m_columnValues.size() - 1)\n                {\n                    row.m_columnValues.push_back(columnValues);\n                }\n                else\n                {\n                    row.m_columnValues[i] = columnValues;\n                }\n            }\n        }\n    }\n\n    for (const auto& columnName : additionalColumnNames)\n    {\n        columns.push_back(LeaderboardColumn(columnName, stats[columnName]));\n    }\n    m_columns = columns;\n}\n\nbool \nLeaderboardResult::HasNext() const\n{\n    return !m_continuationToken.empty();\n}\n\nResult<LeaderboardResult> LeaderboardResult::Deserialize(_In_ const JsonValue& json)\n{\n    if (!json.IsObject())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    // Paging info\n    String continuationToken;\n    if (json.HasMember(\"pagingInfo\"))\n    {\n        const JsonValue& pagingInfo = json[\"pagingInfo\"];\n        if (!pagingInfo.IsNull())\n        {\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(pagingInfo, \"continuationToken\", continuationToken, false));\n        }\n    }\n    else\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    // Leaderboard metadata\n    uint32_t totalCount{ 0 };\n    Vector<LeaderboardColumn> columns;\n    if (json.HasMember(\"leaderboardInfo\"))\n    {\n        const auto& leaderboardInfoJson{ json[\"leaderboardInfo\"] };\n        if (!leaderboardInfoJson.IsObject())\n        {\n            return WEB_E_INVALID_JSON_STRING;\n        }\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(leaderboardInfoJson, \"totalCount\", totalCount));\n\n        if (leaderboardInfoJson.HasMember(\"columnDefinition\"))\n        {\n            // This response schema is used by Global event based stat backed leaderboard queries\n            auto columnResult = LeaderboardColumn::Deserialize(leaderboardInfoJson[\"columnDefinition\"]);\n            RETURN_HR_IF_FAILED(columnResult.Hresult());\n            columns.push_back(columnResult.ExtractPayload());\n        }\n        else if (leaderboardInfoJson.HasMember(\"columns\") && leaderboardInfoJson[\"columns\"].IsArray())\n        {\n            // These response schema is used by all other leaderboard queries\n            for (auto& columnJson : leaderboardInfoJson[\"columns\"].GetArray())\n            {\n                auto columnResult = LeaderboardColumn::Deserialize(columnJson);\n                RETURN_HR_IF_FAILED(columnResult.Hresult());\n                columns.push_back(columnResult.ExtractPayload());\n            }\n        }\n        else\n        {\n            return WEB_E_INVALID_JSON_STRING;\n        }\n    }\n    else\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    Vector<LeaderboardRow> rows;\n    if (json.HasMember(\"userList\") && json[\"userList\"].IsArray())\n    {\n        const auto& jsonRows = json[\"userList\"].GetArray();\n        for (const auto& row : jsonRows)\n        {\n            auto rowResult = LeaderboardRow::Deserialize(row);\n            RETURN_HR_IF_FAILED(rowResult.Hresult());\n            rows.push_back(rowResult.ExtractPayload());\n        }\n    }\n    else if (json.HasMember(\"leaderboard\"))\n    {\n\n    }\n    else\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return LeaderboardResult{ totalCount, continuationToken, std::move(columns), std::move(rows) };\n}\n\nsize_t\nLeaderboardResult::SizeOfQuery()\n{\n    size_t size = m_continuationToken.size() + 1;\n    if (m_globalQuery)\n    {\n        size += m_globalQuery->name.size() + 1;\n        size += sizeof(char*) * m_globalQuery->columns.size();\n        for (auto column : m_globalQuery->columns)\n        {\n            size += column.size() + 1;\n        }\n    }\n    else if (m_socialQuery)\n    {\n        size += m_socialQuery->statName.size() + 1;\n    }\n    return size;\n}\n\nXblSocialGroupType \nLeaderboardResult::ParseSocialGroup(xsapi_internal_string socialGroupStr)\n{\n    XblSocialGroupType socialGroup = XblSocialGroupType::None;\n\n    if (utils::str_icmp_internal(socialGroupStr, xbox::services::social::legacy::social_group_constants::people()) == 0)\n    {\n        socialGroup = XblSocialGroupType::People;\n    }\n    else if (utils::str_icmp_internal(socialGroupStr, xbox::services::social::legacy::social_group_constants::favorite()) == 0)\n    {\n        socialGroup = XblSocialGroupType::Favorites;\n    }\n\n    return socialGroup;\n}\n\nchar*\nLeaderboardResult::SerializeQuery(XblLeaderboardQuery* query, char* buffer)\n{\n    utils::strcpy(buffer, m_continuationToken.size() + 1, m_continuationToken.c_str());\n    query->continuationToken = static_cast<char*>(buffer);\n    buffer += m_continuationToken.size() + 1;\n\n    if (m_globalQuery)\n    {\n        utils::strcpy(query->scid, m_globalQuery->scid.size() + 1, m_globalQuery->scid.c_str());\n        query->socialGroup = ParseSocialGroup(m_globalQuery->socialGroup);\n        query->xboxUserId = m_globalQuery->xuid.empty() ? 0 : utils::internal_string_to_uint64(m_globalQuery->xuid);\n\n        utils::strcpy(buffer, m_globalQuery->name.size() + 1, m_globalQuery->name.c_str());\n        if (m_globalQuery->isTitleManaged)\n        {\n            query->statName = static_cast<char*>(buffer);\n        }\n        else\n        {\n            query->leaderboardName = static_cast<char*>(buffer);\n        }\n        buffer += m_globalQuery->name.size() + 1;\n\n        m_additionalColumnleaderboardNamesC.resize(m_globalQuery->columns.size());\n        query->additionalColumnleaderboardNamesCount = m_globalQuery->columns.size();\n        query->additionalColumnleaderboardNames = reinterpret_cast<const char**>(buffer);\n        buffer += sizeof(char*) * m_globalQuery->columns.size();\n        for (size_t i = 0; i < m_globalQuery->columns.size(); i++)\n        {\n            m_additionalColumnleaderboardNamesC[i] = m_globalQuery->columns[i].c_str();\n\n            utils::strcpy(buffer, m_globalQuery->columns[i].size() + 1, m_additionalColumnleaderboardNamesC[i]);\n            query->additionalColumnleaderboardNames[i] = static_cast<char*>(buffer);\n            buffer += m_globalQuery->columns[i].size() + 1;\n        }\n        query->queryType = m_globalQuery->isTitleManaged ? XblLeaderboardQueryType::TitleManagedStatBackedGlobal : XblLeaderboardQueryType::UserStatBacked;\n    }\n    else if (m_socialQuery)\n    {\n        utils::strcpy(query->scid, m_socialQuery->scid.size() + 1, m_socialQuery->scid.c_str());\n        query->socialGroup = ParseSocialGroup(m_socialQuery->socialGroup);\n        query->xboxUserId = m_socialQuery->xuid.empty() ? 0 : utils::internal_string_to_uint64(m_socialQuery->xuid);\n\n        XblLeaderboardSortOrder sortOrder = XblLeaderboardSortOrder::Descending;\n        if (utils::str_icmp_internal(m_socialQuery->sortOrder, \"ascending\") == 0) sortOrder = XblLeaderboardSortOrder::Ascending;\n        query->order = sortOrder;\n\n        utils::strcpy(buffer, m_socialQuery->statName.size() + 1, m_socialQuery->statName.c_str());\n        query->statName = static_cast<char*>(buffer);\n        buffer += m_socialQuery->statName.size() + 1;\n        query->queryType = m_socialQuery->isTitleManaged ? XblLeaderboardQueryType::TitleManagedStatBackedSocial : XblLeaderboardQueryType::UserStatBacked;\n    }\n\n    return buffer;\n}\n\nsize_t\nLeaderboardResult::SizeOf()\n{\n    size_t size = sizeof(XblLeaderboardResult);\n    for (auto column : m_columns)\n    {\n        size += column.SizeOf();\n    }\n    for (auto row : m_rows)\n    {\n        size += row.SizeOf();\n    }\n    \n    size += SizeOfQuery();\n\n    return size;\n}\n\nchar*\nLeaderboardResult::Serialize(char* buffer)\n{\n    XblLeaderboardResult* result = reinterpret_cast<XblLeaderboardResult*>(buffer);\n    buffer += sizeof(XblLeaderboardResult);\n\n    result->hasNext = !m_continuationToken.empty();\n    result->totalRowCount = m_totalRowCount;\n\n    result->columnsCount = m_columns.size();\n    result->columns = reinterpret_cast<XblLeaderboardColumn*>(buffer);\n    buffer += sizeof(XblLeaderboardColumn) * m_columns.size();\n    for (size_t i = 0; i < m_columns.size(); i++)\n    {\n        buffer = m_columns[i].Serialize(&result->columns[i], buffer);\n    }\n\n    result->rowsCount = m_rows.size();\n    result->rows = reinterpret_cast<XblLeaderboardRow*>(buffer);\n    buffer += sizeof(XblLeaderboardRow) * m_rows.size();\n    for (size_t i = 0; i < m_rows.size(); i++)\n    {\n        buffer = m_rows[i].Serialize(&result->rows[i], buffer);\n    }\n\n    return SerializeQuery(&result->nextQuery, buffer);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END"
  },
  {
    "path": "Source/Services/Leaderboard/leaderboard_row.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"shared_macros.h\"\n#include \"leaderboard_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN\n\nLeaderboardRow::LeaderboardRow()\n{\n\n}\n\nLeaderboardRow::LeaderboardRow(\n    _In_ xsapi_internal_string gamertag,\n    _In_ xsapi_internal_string modernGamertag,\n    _In_ xsapi_internal_string modernGamertagSuffix,\n    _In_ xsapi_internal_string uniqueModernGamertag,\n    _In_ uint64_t xboxUserId,\n    _In_ double percentile,\n    _In_ uint32_t rank,\n    _In_ uint32_t globalRank,\n    _In_ xsapi_internal_vector<xsapi_internal_string> columnValues,\n    _In_ xsapi_internal_string metadata\n) :\n    m_gamertag{ std::move(gamertag) },\n    m_modernGamertag{ std::move(modernGamertag) },\n    m_modernGamertagSuffix{ std::move(modernGamertagSuffix) },\n    m_uniqueModernGamertag{ std::move(uniqueModernGamertag) },\n    m_xuid{ xboxUserId },\n    m_percentile{ percentile },\n    m_rank{ rank },\n    m_globalRank{ globalRank },\n    m_columnValues(std::move(columnValues))\n{\n    if(!metadata.empty())\n    {\n        m_metadata.Parse(metadata.c_str());\n    }\n}\n\nLeaderboardRow::LeaderboardRow(const LeaderboardRow& other)\n{\n    m_gamertag = other.m_gamertag;\n    m_modernGamertag = other.m_modernGamertag;\n    m_modernGamertagSuffix = other.m_modernGamertagSuffix;\n    m_uniqueModernGamertag = other.m_uniqueModernGamertag;\n    m_xuid = other.m_xuid;\n    m_percentile = other.m_percentile;\n    m_rank = other.m_rank;\n    m_globalRank = other.m_globalRank;\n    m_columnValues = other.m_columnValues;\n    m_columnValuesC = other.m_columnValuesC;\n    JsonUtils::CopyFrom(m_metadata, other.m_metadata);\n}\n\nLeaderboardRow& LeaderboardRow::operator =(const LeaderboardRow& other)\n{\n    m_gamertag = other.m_gamertag;\n    m_modernGamertag = other.m_modernGamertag;\n    m_modernGamertagSuffix = other.m_modernGamertagSuffix;\n    m_uniqueModernGamertag = other.m_uniqueModernGamertag;\n    m_xuid = other.m_xuid;\n    m_percentile = other.m_percentile;\n    m_rank = other.m_rank;\n    m_globalRank = other.m_globalRank;\n    m_columnValues = other.m_columnValues;\n    m_columnValuesC = other.m_columnValuesC;\n    JsonUtils::CopyFrom(m_metadata, other.m_metadata);\n\n    return *this;\n}\n\nconst xsapi_internal_string& LeaderboardRow::Gamertag() const\n{\n    return m_gamertag;\n}\n\nconst xsapi_internal_string& LeaderboardRow::ModernGamertag() const\n{\n    return m_modernGamertag;\n}\n\nconst xsapi_internal_string& LeaderboardRow::ModernGamertagSuffix() const\n{\n    return m_modernGamertagSuffix;\n}\n\nconst xsapi_internal_string& LeaderboardRow::UniqueGamertagSuffix() const\n{\n    return m_uniqueModernGamertag;\n}\n\nuint64_t LeaderboardRow::XboxUserId() const\n{\n    return m_xuid;\n}\n\ndouble LeaderboardRow::Percentile() const\n{\n    return m_percentile;\n}\n\nuint32_t LeaderboardRow::Rank() const\n{\n    return m_rank;\n}\n\nuint32_t LeaderboardRow::GlobalRank() const \n{\n    return m_globalRank;\n}\n\nconst xsapi_internal_vector<xsapi_internal_string>& LeaderboardRow::ColumnValues() const\n{\n    return m_columnValues;\n}\n\n/* static */ Result<LeaderboardRow> LeaderboardRow::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    xsapi_internal_string gamertag;\n    xsapi_internal_string modernGamertag;\n    xsapi_internal_string modernGamertagSuffix;\n    xsapi_internal_string uniqueModernGamertag;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"gamertag\", gamertag, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"moderngamertag\", modernGamertag, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"moderngamertagsuffix\", modernGamertagSuffix, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"uniquemoderngamertag\", uniqueModernGamertag, true));\n    uint64_t xuid = 0;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"xuid\", xuid, true));\n    double percentile = 0.0;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonDouble(json, \"percentile\", percentile, true));\n    int rank = 0;\n    int globalRank = 0;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"rank\", rank, true));\n    if (json.IsObject() && json.HasMember(\"globalrank\") && !json[\"globalrank\"].IsNull())\n    {\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"globalrank\", globalRank, false));\n    }\n    xsapi_internal_vector<xsapi_internal_string> values;\n    if (json.IsObject() && json.HasMember(\"value\") && !json[\"value\"].IsNull())\n    {\n        xsapi_internal_string value;\n        JsonUtils::ExtractJsonString(json, \"value\", value, true);\n        values.push_back(value);\n    }\n    else\n    {\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<xsapi_internal_string>(JsonUtils::JsonStringExtractor, json, \"values\", values, true));\n    }\n    xsapi_internal_string metadata;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"valuemetadata\", metadata, false));\n\n    return LeaderboardRow(\n        gamertag,\n        modernGamertag,\n        modernGamertagSuffix,\n        uniqueModernGamertag,\n        xuid,\n        percentile,\n        rank,\n        globalRank,\n        values,\n        metadata\n    );\n}\n\nsize_t LeaderboardRow::SizeOf()\n{\n    // size must be rounded up to support word aligned data because of the arbitrary length string packing\n    // we won't actually use the extra space, but this will report that it is how much is needed\n    size_t size = sizeof(XblLeaderboardRow);\n    size += sizeof(char*) * m_columnValues.size();\n    for (auto columnVal : m_columnValues)\n    {\n        size += columnVal.size() + 1;\n    }\n    size = static_cast<size_t>((size + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n    return size;\n}\n\nchar* LeaderboardRow::Serialize(XblLeaderboardRow* row, char* buffer)\n{\n    // the function needs to return the final position of the buffer;  however\n    // we have to ensure that the buffer is left word-aligned so that the next\n    // data can be read on proper boundaries.\n    row->percentile = m_percentile;\n\n    row->rank = m_rank;\n    row->globalRank = m_globalRank;\n    row->xboxUserId = m_xuid;\n\n    utils::strcpy(row->gamertag, sizeof(XblLeaderboardRow::gamertag), m_gamertag.c_str());\n    utils::strcpy(row->modernGamertag, sizeof(XblLeaderboardRow::modernGamertag), m_modernGamertag.data());\n    utils::strcpy(row->modernGamertagSuffix, sizeof(XblLeaderboardRow::modernGamertagSuffix), m_modernGamertagSuffix.data());\n    utils::strcpy(row->uniqueModernGamertag, sizeof(XblLeaderboardRow::uniqueModernGamertag), m_uniqueModernGamertag.data());\n\n    m_columnValuesC.resize(m_columnValues.size());\n    row->columnValuesCount = m_columnValues.size();\n    row->columnValues = reinterpret_cast<const char**>(buffer);\n    size_t s1 = sizeof(char*) * m_columnValues.size();\n    buffer += s1;\n    size_t s2 = 0;\n    for (size_t i = 0; i < m_columnValues.size(); i++)\n    {\n        m_columnValuesC[i] = m_columnValues[i].c_str();\n\n        utils::strcpy(buffer, m_columnValues[i].size() + 1, m_columnValuesC[i]);\n        row->columnValues[i] = static_cast<char*>(buffer);\n        s2 += m_columnValues[i].size() + 1;\n        buffer += m_columnValues[i].size() + 1;\n    }\n    size_t s = s1 + s2;\n    if ((s % XBL_ALIGN_SIZE) != 0) {\n        // calculate how much padding is needed\n        s = (static_cast<size_t>((s + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE) - s;\n        buffer += s;\n    }\n\n    return buffer;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END"
  },
  {
    "path": "Source/Services/Leaderboard/leaderboard_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"leaderboard_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\nusing namespace xbox::services::legacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN\n\n// We need to use a different XBL contract versions depending on \n// 1) whether the leaderboard is backed event based stats vs. title managed stats\n// 2) whether it is a social leaderboard or a global leaderboard\n// Using set header manually instead of SetContractVersion since leaderboard service is using contract versions that are\n// not integer values.\n\nconstexpr const char* g_titleMangedStatsGlobalLeaderboardVersion{ \"4.1\" };\nconstexpr const char* g_titleMangedStatsSocialLeaderboardVersion{ \"2.1\" };\nconstexpr const char* g_eventBasedStatsGlobalLeaderboardVersion{ \"3.1\" };\nconstexpr const char* g_eventBasedStatsSocialLeaderboardVersion{ \"1.1\" };\n\nLeaderboardService::LeaderboardService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<xbox::services::AppConfig> appConfig\n) :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings(std::move(xboxLiveContextSettings)),\n    m_appConfig(std::move(appConfig))\n{\n}\n\nxbl_result<xsapi_internal_string> \nCreateLeaderboardUrl(\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& name,\n    _In_ uint32_t skipToRank,\n    _In_ const xsapi_internal_string& skipToXuid,\n    _In_ uint32_t maxItems,\n    _In_ const xsapi_internal_string& continuationToken,\n    _In_ bool metadata,\n    _In_ bool isTitleManaged,\n    _In_ const xsapi_internal_string& xuid = xsapi_internal_string(),\n    _In_ const xsapi_internal_string& socialGroup = xsapi_internal_string()\n    )\n{\n    if (scid.empty())\n        return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"scid is required for getting leaderboards\");\n    if (name.empty())\n        return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"name is required for getting leaderboards\");\n\n    xbox::services::uri_builder builder;\n\n    xsapi_internal_stringstream path;\n    path << \"/scids/\";\n    path << xbox::services::uri::encode_uri(scid, xbox::services::uri::components::path);\n    if (isTitleManaged)\n    {\n        path << \"/leaderboards/stat(\";\n        path << xbox::services::uri::encode_uri(name, xbox::services::uri::components::path);\n        path << \")\";\n    }\n    else\n    {\n        path << \"/leaderboards/\";\n        path << xbox::services::uri::encode_uri(name, xbox::services::uri::components::path);\n    }\n    builder.set_path(path.str());\n\n    if (metadata)\n    {\n        builder.append_query(\"include\", \"valuemetadata\");\n    }\n\n    if (!xuid.empty())\n    {\n        builder.append_query(\"xuid\", xuid);\n    }\n\n    if (maxItems > 0)\n    {\n        builder.append_query(\"maxItems\", maxItems);\n    }\n\n    if (!skipToXuid.empty())\n    {\n        if (skipToRank > 0)\n        {\n            return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"Cannot skip to XUID and rank\");\n        }\n\n        builder.append_query(\"skipToUser\", skipToXuid);\n    }\n    else\n    {\n        if (!continuationToken.empty())\n        {\n            builder.append_query(\"continuationToken\", continuationToken);\n        }\n        else if (skipToRank > 0)\n        {\n            builder.append_query(\"skipToRank\", skipToRank);\n        }\n    }\n\n    if (!socialGroup.empty())\n    {\n        builder.append_query(\"view\", \"People\");\n        builder.append_query(\"viewTarget\", socialGroup);\n    }\n\n    return xbl_result<xsapi_internal_string>(builder.to_string());\n}\n\nHRESULT\nLeaderboardService::GetLeaderboard(\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& name,\n    _In_ uint32_t skipToRank,\n    _In_ const xsapi_internal_string& skipToXuid,\n    _In_ const xsapi_internal_string& xuid,\n    _In_ const xsapi_internal_string& socialGroup,\n    _In_ uint32_t maxItems,\n    _In_ const xsapi_internal_string& continuationToken,\n    _In_ const xsapi_internal_vector<xsapi_internal_string>& additionalColumnNames,\n    _In_ bool isTitleManaged,\n    _In_ XAsyncBlock* async\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(scid);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(name);\n\n    xbl_result<xsapi_internal_string> url = CreateLeaderboardUrl(\n        scid,\n        name,\n        skipToRank,\n        skipToXuid,\n        maxItems,\n        continuationToken,\n        additionalColumnNames.size() != 0,\n        isTitleManaged,\n        xuid,\n        socialGroup\n        );\n\n    if (url.err()) return utils::convert_xbox_live_error_code_to_hresult(url.err());\n\n    std::shared_ptr<LeaderboardGlobalQuery> query = MakeShared<LeaderboardGlobalQuery>();\n    query->scid = scid;\n    query->name = name;\n    query->xuid = xuid;\n    query->socialGroup = socialGroup;\n    query->columns = additionalColumnNames;\n    query->isTitleManaged = isTitleManaged;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            result = LeaderboardResult{},\n            sharedThis{ shared_from_this() }, \n            url,\n            query,\n            additionalColumnNames\n        ]\n    (_In_ XAsyncOp op, _In_ const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n\n            Result<User> userResult = sharedThis->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                sharedThis->m_xboxLiveContextSettings,\n                \"GET\",\n                XblHttpCall::BuildUrl(\"leaderboards\", url.payload()),\n                xbox_live_api::get_leaderboard_internal\n            );\n\n            RETURN_HR_IF_FAILED(hr);\n\n            // Using set header directly instead of SetContractVersion since leaderboard service is using contract versions that are\n            // not integer values.\n            if (query->isTitleManaged)\n            {\n                RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTRACT_VERSION_HEADER, g_titleMangedStatsGlobalLeaderboardVersion));\n            }\n            else\n            {\n                RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTRACT_VERSION_HEADER, g_eventBasedStatsGlobalLeaderboardVersion));\n            }\n\n            hr = httpCall->Perform(AsyncContext<HttpResult>{\n                TaskQueue::DeriveWorkerQueue(data->async->queue),\n                    [\n                        &result,\n                        data,\n                        additionalColumnNames,\n                        query\n                    ]\n                (HttpResult httpResult)\n                {\n                    HRESULT hr = httpResult.Hresult();\n                    if (SUCCEEDED(hr))\n                    {\n                        hr = httpResult.Payload()->Result();\n                        if (SUCCEEDED(hr))\n                        {\n                            auto xblResult = LeaderboardResult::Deserialize(\n                                httpResult.Payload()->GetResponseBodyJson()\n                            );\n                            result = xblResult.Payload();\n                            result.SetNextQuery(query);\n                            if (additionalColumnNames.size() > 0)\n                            {\n                                result.ParseAdditionalColumns(additionalColumnNames);\n                            }\n\n                            hr = xblResult.Hresult();\n                        }\n                    }\n                    XAsyncComplete(data->async, hr, result.SizeOf());\n                }});\n            \n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            buffer = result.Serialize(buffer);\n            XSAPI_ASSERT(static_cast<void*>(buffer) == static_cast<void*>(static_cast<char*>(data->buffer) + result.SizeOf()));\n        }\n\n        return S_OK;\n    });\n}\n\nxbl_result<xsapi_internal_string> \nCreateLeaderboardForSocialGroupUrl(\n    _In_ const xsapi_internal_string& xuid,\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& statName,\n    _In_ const xsapi_internal_string& socialGroup,\n    _In_ uint32_t skipToRank,\n    _In_ const xsapi_internal_string& skipToXuid,\n    _In_ const xsapi_internal_string& sortOrder,\n    _In_ uint32_t maxItems,\n    _In_ const xsapi_internal_string& continuationToken\n    )\n{\n\n    if (xuid.empty()) return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"xuid is required for getting leaderboard for social group\");\n    if (scid.empty()) return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"scid is required for getting leaderboard for social group\");\n    if (statName.empty()) return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"statName is required for getting leaderboard for social group\");\n    if (socialGroup.empty()) return xbl_result<xsapi_internal_string>(xbl_error_code::invalid_argument, \"socialGroup is required for getting leaderboard for social group\");\n\n    // \"/users/xuid({xuid})/scids/{scid}/stats/{statname}/people/{group}\"\n\n    xbox::services::uri_builder builder;\n    \n    xsapi_internal_stringstream path;\n    path << \"/users/xuid(\";\n    path << xbox::services::uri::encode_uri(xuid, xbox::services::uri::components::path);\n    path << \")/scids/\";\n    path << xbox::services::uri::encode_uri(scid, xbox::services::uri::components::path);\n    path << \"/stats/\";\n    path << xbox::services::uri::encode_uri(statName, xbox::services::uri::components::path);\n    path << \"/people/\";\n    path << xbox::services::uri::encode_uri(socialGroup, xbox::services::uri::components::path);\n    builder.set_path(path.str());\n\n    if (!sortOrder.empty())\n    {\n        builder.append_query(\"sort\", sortOrder);\n    }\n\n    if (maxItems > 0)\n    {\n        builder.append_query(\"maxItems\", maxItems);\n    }\n\n    if (!skipToXuid.empty())\n    {\n        builder.append_query(\"skipToUser\", skipToXuid);\n    }\n    else\n    {\n        if (!continuationToken.empty())\n        {\n            builder.append_query(\"continuationToken\", continuationToken);\n        }\n        else if (skipToRank > 0)\n        {\n            builder.append_query(\"skipToRank\", skipToRank);\n        }\n    }\n\n    return xbl_result<xsapi_internal_string>(builder.to_string());\n}\n\nHRESULT \nLeaderboardService::GetLeaderboardForSocialGroup(\n    _In_ const xsapi_internal_string& xuid,\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& statName,\n    _In_ const xsapi_internal_string& socialGroup,\n    _In_ uint32_t skipToRank,\n    _In_ const xsapi_internal_string& skipToXuid,\n    _In_ const xsapi_internal_string& sortOrder,\n    _In_ uint32_t maxItems,\n    _In_ const xsapi_internal_string& continuationToken,\n    _In_ bool isTitleManaged,\n    _In_ XAsyncBlock* async\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(xuid);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(scid);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(statName);\n\n    // To align with People moniker support, we are mapping \"People\" to \"all\" until the\n    // leaderboard service can align with naming conventions.\n    xsapi_internal_string group = socialGroup;\n    if (utils::str_icmp_internal(socialGroup, \"People\") == 0)\n    {\n        group = \"all\";\n    }\n\n    xbl_result<xsapi_internal_string> url = CreateLeaderboardForSocialGroupUrl(\n        xuid,\n        scid,\n        statName,\n        group,\n        skipToRank,\n        skipToXuid,\n        sortOrder,\n        maxItems,\n        continuationToken);\n\n    if (url.err()) return utils::convert_xbox_live_error_code_to_hresult(url.err());\n\n    auto query = MakeShared<LeaderboardSocialQuery>();\n    query->xuid = xuid;\n    query->scid = scid;\n    query->statName = statName;\n    query->socialGroup = group;\n    query->sortOrder = sortOrder;\n    query->isTitleManaged = isTitleManaged;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            result = LeaderboardResult{},\n            sharedThis{ shared_from_this() }, \n            url, \n            query\n        ]\n    (_In_ XAsyncOp op, _In_ const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            Result<User> userResult = sharedThis->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                sharedThis->m_xboxLiveContextSettings,\n                \"GET\",\n                XblHttpCall::BuildUrl(\"leaderboards\", url.payload()),\n                xbox_live_api::get_leaderboard_for_social_group_internal\n            );\n\n            RETURN_HR_IF_FAILED(hr);\n            if (query->isTitleManaged)\n            {\n                RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTRACT_VERSION_HEADER, g_titleMangedStatsSocialLeaderboardVersion));\n            }\n            else\n            {\n                RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTRACT_VERSION_HEADER, g_eventBasedStatsSocialLeaderboardVersion));\n            }\n\n            hr = httpCall->Perform(AsyncContext<HttpResult>{\n                TaskQueue::DeriveWorkerQueue(data->async->queue),\n                    [\n                        &result,\n                        data,\n                        query\n                    ]\n                (HttpResult httpResult)\n                {\n                    HRESULT hr = httpResult.Hresult();\n                    if (SUCCEEDED(hr))\n                    {\n                        hr = httpResult.Payload()->Result();\n                        if (SUCCEEDED(hr))\n                        {\n                            auto xblResult = LeaderboardResult::Deserialize(\n                                httpResult.Payload()->GetResponseBodyJson()\n                            );\n                            result = xblResult.Payload();\n                            result.SetNextQuery(query);\n\n                            hr = xblResult.Hresult();\n                        }\n                    }\n                    XAsyncComplete(data->async, hr, result.SizeOf());\n                }});\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            buffer = result.Serialize(buffer);\n            XSAPI_ASSERT(static_cast<void*>(buffer) == static_cast<void*>(static_cast<char*>(data->buffer) + data->bufferSize));\n        }\n\n        return S_OK;\n    });\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END\n\nSTDAPI XblLeaderboardGetLeaderboardAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblLeaderboardQuery leaderboardQuery,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n\n    if (leaderboardQuery.queryType != XblLeaderboardQueryType::UserStatBacked)\n    {\n        // For title managed stat backed leaderboards, the statistic name must be specified\n        RETURN_HR_INVALIDARGUMENT_IF_NULL(leaderboardQuery.statName);\n    }\n    else\n    {\n        // For event stat backed leaderboards, the query must specify a leaderboard name OR a stat name\n        RETURN_HR_INVALIDARGUMENT_IF(leaderboardQuery.leaderboardName == nullptr && leaderboardQuery.statName == nullptr);\n    }\n\n    xsapi_internal_string xuid = utils::uint64_to_internal_string(leaderboardQuery.xboxUserId);\n    if (leaderboardQuery.xboxUserId == 0) xuid = \"\";\n\n    xsapi_internal_string skipToXuid = utils::uint64_to_internal_string(leaderboardQuery.skipToXboxUserId);\n    if (leaderboardQuery.skipToXboxUserId == 0) skipToXuid = \"\";\n\n    xsapi_internal_string continuationToken(\"\");\n    if (leaderboardQuery.continuationToken) continuationToken = leaderboardQuery.continuationToken;\n\n    xsapi_internal_string socialGroup(\"\");\n    if (leaderboardQuery.socialGroup == XblSocialGroupType::People)\n    {\n        socialGroup = xbox::services::social::legacy::social_group_constants::people();\n    }\n    else if (leaderboardQuery.socialGroup == XblSocialGroupType::Favorites)\n    {\n        socialGroup = xbox::services::social::legacy::social_group_constants::favorite();\n    }\n\n    if ((leaderboardQuery.queryType == XblLeaderboardQueryType::UserStatBacked && leaderboardQuery.leaderboardName) || \n         leaderboardQuery.queryType == XblLeaderboardQueryType::TitleManagedStatBackedGlobal)\n    {\n        // Depending on the type of query, we either use the leaderboard name or the stat name\n        String name{};\n        switch (leaderboardQuery.queryType)\n        {\n        case XblLeaderboardQueryType::UserStatBacked:\n        {\n            name = leaderboardQuery.leaderboardName;\n            break;\n        }\n        case XblLeaderboardQueryType::TitleManagedStatBackedGlobal:\n        {\n            name = leaderboardQuery.statName;\n            break;\n        }\n        default: break;\n        }\n\n        return xboxLiveContext->LeaderboardService()->GetLeaderboard(\n            leaderboardQuery.scid,\n            name,\n            leaderboardQuery.skipResultToRank,\n            skipToXuid,\n            xuid,\n            socialGroup,\n            leaderboardQuery.maxItems,\n            continuationToken,\n            utils::string_array_to_internal_string_vector(leaderboardQuery.additionalColumnleaderboardNames, leaderboardQuery.additionalColumnleaderboardNamesCount),\n            leaderboardQuery.queryType != XblLeaderboardQueryType::UserStatBacked,\n            async\n        );\n    }\n    else\n    {\n        if (socialGroup.empty())\n        {\n            socialGroup = xbox::services::social::legacy::social_group_constants::people();\n        }\n\n        xsapi_internal_string statName(\"\");\n        if (leaderboardQuery.statName) statName = leaderboardQuery.statName;\n\n        xsapi_internal_string sortOrder(\"\");\n        if (leaderboardQuery.order == XblLeaderboardSortOrder::Ascending)\n        {\n            sortOrder = \"ascending\";\n        }\n        if (leaderboardQuery.order == XblLeaderboardSortOrder::Descending)\n        {\n            sortOrder = \"descending\";\n        }\n\n        return xboxLiveContext->LeaderboardService()->GetLeaderboardForSocialGroup(\n            xuid,\n            leaderboardQuery.scid,\n            statName,\n            socialGroup,\n            leaderboardQuery.skipResultToRank,\n            skipToXuid,\n            sortOrder,\n            leaderboardQuery.maxItems,\n            continuationToken,\n            leaderboardQuery.queryType != XblLeaderboardQueryType::UserStatBacked,\n            async\n        );\n    }\n}\nCATCH_RETURN()\n\nSTDAPI XblLeaderboardGetLeaderboardResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblLeaderboardGetLeaderboardResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblLeaderboardResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblLeaderboardResult*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblLeaderboardResultGetNextAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblLeaderboardResult* leaderboardResult,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_IF(leaderboardResult->nextQuery.continuationToken == nullptr, E_BOUNDS);\n\n    leaderboardResult->nextQuery.maxItems = maxItems;\n    return XblLeaderboardGetLeaderboardAsync(\n        xboxLiveContext,\n        leaderboardResult->nextQuery,\n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblLeaderboardResultGetNextResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblLeaderboardResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblLeaderboardResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    VERIFY_XBL_INITIALIZED();\n\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblLeaderboardResult*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Matchmaking/hopper_statistics_response.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"matchmaking_internal.h\"\n\nusing namespace xbox::services::multiplayer;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN\nHopperStatisticsResponse::HopperStatisticsResponse()\n{}\n\nHopperStatisticsResponse::HopperStatisticsResponse(\n    _In_ xsapi_internal_string hopperName,\n    _In_ std::chrono::seconds estimatedWaitTime,\n    _In_ uint32_t playersWaitingToMatch\n)\n    : m_hopperName(hopperName), \n    m_estimatedWaitTime(estimatedWaitTime), \n    m_playersWaitingToMatch(playersWaitingToMatch)\n{\n}\n\nconst xsapi_internal_string& HopperStatisticsResponse::HopperName() const\n{\n    return m_hopperName;\n}\n\nconst std::chrono::seconds& HopperStatisticsResponse::EstimatedWaitTime() const\n{\n    return m_estimatedWaitTime;\n}\n\nuint32_t HopperStatisticsResponse::PlayersWaitingToMatch() const\n{\n    return m_playersWaitingToMatch;\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END"
  },
  {
    "path": "Source/Services/Matchmaking/match_ticket_details_response.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"matchmaking_internal.h\"\n\nusing namespace xbox::services::multiplayer;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN\nconst XblTicketStatus MatchTicketDetailsResponse::MatchStatus() const\n{\n    return m_matchStatus;\n}\n\nconst std::chrono::seconds& MatchTicketDetailsResponse::EstimatedWaitTime() const\n{\n    return m_estimatedWaitTime;\n}\n\nconst XblPreserveSessionMode MatchTicketDetailsResponse::PreserveSession() const\n{\n    return m_preserveSession;\n}\n\nconst XblMultiplayerSessionReference MatchTicketDetailsResponse::TicketSession() const\n{\n    return m_ticketSession;\n}\n\nconst XblMultiplayerSessionReference MatchTicketDetailsResponse::TargetSession() const\n{\n    return m_targetSession;\n}\n\nconst JsonValue& MatchTicketDetailsResponse::TicketAttributes() const\n{\n    return m_ticketAttributes;\n}\n\nMatchTicketDetailsResponse::MatchTicketDetailsResponse()\n{\n}\n\nMatchTicketDetailsResponse::MatchTicketDetailsResponse(\n    _In_ XblTicketStatus matchStatus,\n    _In_ std::chrono::seconds estimatedWaitTime,\n    _In_ XblPreserveSessionMode preserveSession,\n    _In_ XblMultiplayerSessionReference ticketSession,\n    _In_ XblMultiplayerSessionReference targetSession,\n    _In_ const JsonValue& ticketAttributes\n) :\n    m_matchStatus(matchStatus),\n    m_estimatedWaitTime(estimatedWaitTime),\n    m_preserveSession(preserveSession),\n    m_ticketSession(ticketSession),\n    m_targetSession(targetSession)\n{\n    JsonUtils::CopyFrom(m_ticketAttributes, ticketAttributes);\n}\n\nMatchTicketDetailsResponse::MatchTicketDetailsResponse(const MatchTicketDetailsResponse& other)\n    :\n    m_matchStatus(other.m_matchStatus),\n    m_estimatedWaitTime(other.m_estimatedWaitTime),\n    m_preserveSession(other.m_preserveSession),\n    m_ticketSession(other.m_ticketSession),\n    m_targetSession(other.m_targetSession)\n{\n    JsonUtils::CopyFrom(m_ticketAttributes, other.m_ticketAttributes);\n}\n\nMatchTicketDetailsResponse& MatchTicketDetailsResponse::operator =(const MatchTicketDetailsResponse& other)\n{\n    if (this != &other)\n    {\n        m_matchStatus = other.m_matchStatus;\n        m_estimatedWaitTime = other.m_estimatedWaitTime;\n        m_preserveSession = other.m_preserveSession;\n        m_ticketSession = other.m_ticketSession;\n        m_targetSession = other.m_targetSession;\n        JsonUtils::CopyFrom(m_ticketAttributes, other.m_ticketAttributes);\n    }\n    return *this;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END"
  },
  {
    "path": "Source/Services/Matchmaking/matchmaking_internal.h",
    "content": "#pragma once\n\n#include \"xsapi-c/matchmaking_c.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN\n\nclass MatchmakingService : public std::enable_shared_from_this<MatchmakingService> \n{\n\npublic:\n    MatchmakingService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n    );\n\n    HRESULT CreateMatchTicket(\n        _In_ const XblMultiplayerSessionReference& ticketSessionReference,\n        _In_ const xsapi_internal_string& matchmakingServiceConfigurationId,\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ const std::chrono::seconds& ticketTimeout,\n        _In_ XblPreserveSessionMode preserveSession,\n        _In_ JsonValue& ticketAttributesJson,\n        _In_ XAsyncBlock* async\n    );\n\n    HRESULT DeleteMatchTicketAsync(\n        _In_ const xsapi_internal_string& serviceConfigurationId,\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ const xsapi_internal_string& ticketId,\n        _In_ XAsyncBlock* async\n    );\n\n    HRESULT GetMatchTicketDetailsAsync(\n        _In_ const xsapi_internal_string& serviceConfigurationId,\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ const xsapi_internal_string& ticketId,\n        _In_ XAsyncBlock* async\n    );\n\n    HRESULT GetHopperStatistics(\n        _In_ const xsapi_internal_string& serviceConfigurationId,\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ XAsyncBlock* async\n    );\n\nprivate:\n    static xsapi_internal_string GetMatchmakingSubPath(\n        _In_ const xsapi_internal_string& serviceConfigId,\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ const xsapi_internal_string& ticketId\n    );\n\n    static xsapi_internal_string GetHopperSubPath(\n        _In_ const xsapi_internal_string& serviceConfigId,\n        _In_ const xsapi_internal_string& hopperName\n    );\n\n    static xsapi_internal_string ConvertPreserveSessionModeToString(\n        _In_ XblPreserveSessionMode preserve_session\n    );\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_contextSettings;\n};\n\n/// <summary>\n/// Represents a server response to a hopper statistics request.\n/// </summary>\nclass HopperStatisticsResponse \n{\npublic:\n    HopperStatisticsResponse();\n\n    HopperStatisticsResponse(\n        _In_ xsapi_internal_string hopperName,\n        _In_ std::chrono::seconds estimatedWaitTime,\n        _In_ uint32_t playersWaitingToMatch\n    );\n\n    /// <summary>\n    /// Name of the hopper in which a match was requested.\n    /// </summary>\n    const xsapi_internal_string& HopperName() const;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    const std::chrono::seconds& EstimatedWaitTime() const;\n\n    /// <summary>\n    /// The number of players in the hopper waiting to be matched.\n    /// </summary>\n    uint32_t PlayersWaitingToMatch() const;\n\nprivate:\n    /// <summary>\n    /// Name of the hopper in which a match was requested.\n    /// </summary>\n    xsapi_internal_string m_hopperName;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    std::chrono::seconds m_estimatedWaitTime{};\n\n    /// <summary>\n    /// The number of players in the hopper waiting to be matched.\n    /// </summary>\n    uint32_t m_playersWaitingToMatch{ 0 };\n};\n\n/// <summary>\n/// Represents a server response to a request for match ticket details.\n/// </summary>\nclass MatchTicketDetailsResponse\n{\npublic:\n    MatchTicketDetailsResponse();\n\n    MatchTicketDetailsResponse (\n        _In_ XblTicketStatus matchStatus,\n        _In_ std::chrono::seconds estimatedWaitTime,\n        _In_ XblPreserveSessionMode preserveSession,\n        _In_ XblMultiplayerSessionReference ticketSession,\n        _In_ XblMultiplayerSessionReference targetSession,\n        _In_ const JsonValue& ticketAttributes\n    );\n\n    MatchTicketDetailsResponse(const MatchTicketDetailsResponse& other);\n\n    MatchTicketDetailsResponse& operator =(const MatchTicketDetailsResponse& other);\n\n    /// <summary>\n    /// Status of a match request.\n    /// </summary>\n    const XblTicketStatus MatchStatus() const;\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    const std::chrono::seconds& EstimatedWaitTime() const;\n\n    /// <summary>\n    /// An enum value to specify whether the match should preserve the session on which the match has been requested.\n    /// </summary>\n    const XblPreserveSessionMode PreserveSession() const;\n\n    /// <summary>\n    /// The session on which the match was requested.\n    /// </summary>\n    const XblMultiplayerSessionReference TicketSession() const;\n\n    /// <summary>\n    /// The session on which a match request has been found.\n    /// </summary>\n    const XblMultiplayerSessionReference TargetSession() const;\n\n    /// <summary>\n    /// The attributes of a match request.\n    /// </summary>\n    const JsonValue& TicketAttributes() const;\n\n    static XblTicketStatus ConvertStringToTicketStatus(_In_ const xsapi_internal_string& value);\n    static XblPreserveSessionMode ConvertStringToPreserveSessionMode(_In_ const xsapi_internal_string& value);\n\nprivate:\n\n    /// <summary>\n    /// Status of a match request.\n    /// </summary>\n    XblTicketStatus m_matchStatus{ XblTicketStatus::Unknown };\n\n    /// <summary>\n    /// Estimated wait time for a match request to be matched with other players.\n    /// </summary>\n    std::chrono::seconds m_estimatedWaitTime{};\n\n    /// <summary>\n    /// An enum value to specify whether the match should preserve the session on which the match has been requested.\n    /// </summary>\n    XblPreserveSessionMode m_preserveSession{ XblPreserveSessionMode::Unknown };\n\n    /// <summary>\n    /// The session on which the match was requested.\n    /// </summary>\n    XblMultiplayerSessionReference m_ticketSession{};\n\n    /// <summary>\n    /// The session on which a match request has been found.\n    /// </summary>\n    XblMultiplayerSessionReference m_targetSession{};\n\n    /// <summary>\n    /// The attributes of a match request.\n    /// </summary>\n    JsonDocument m_ticketAttributes;\n\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END"
  },
  {
    "path": "Source/Services/Matchmaking/matchmaking_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"shared_macros.h\"\n#include \"matchmaking_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN\n\nMatchmakingService::MatchmakingService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n) :\n    m_user{ std::move(user) },\n    m_contextSettings(contextSettings)\n{\n}\n\n/*static*/ XblTicketStatus MatchTicketDetailsResponse::ConvertStringToTicketStatus(_In_ const xsapi_internal_string& value)\n{\n    XblTicketStatus ticketStatus = XblTicketStatus::Unknown;\n    if (!value.empty())\n    {\n        if (utils::str_icmp_internal(value, \"expired\") == 0)\n        {\n            ticketStatus = XblTicketStatus::Expired;\n        }\n        else if (utils::str_icmp_internal(value, \"searching\") == 0)\n        {\n            ticketStatus = XblTicketStatus::Searching;\n        }\n        else if (utils::str_icmp_internal(value, \"found\") == 0)\n        {\n            ticketStatus = XblTicketStatus::Found;\n        }\n        else if (utils::str_icmp_internal(value, \"canceled\") == 0)\n        {\n            ticketStatus = XblTicketStatus::Canceled;\n        }\n    }\n    return ticketStatus;\n}\n\n/*static*/ XblPreserveSessionMode MatchTicketDetailsResponse::ConvertStringToPreserveSessionMode(_In_ const xsapi_internal_string& value)\n{\n    XblPreserveSessionMode preserveSessionMode = XblPreserveSessionMode::Unknown;\n    if (!value.empty())\n    {\n        if (utils::str_icmp_internal(value, \"always\") == 0)\n        {\n            preserveSessionMode = XblPreserveSessionMode::Always;\n        }\n        else if (utils::str_icmp_internal(value, \"never\") == 0)\n        {\n            preserveSessionMode = XblPreserveSessionMode::Never;\n        }\n    }\n    return preserveSessionMode;\n}\n\n\nxsapi_internal_string MatchmakingService::GetMatchmakingSubPath(\n    _In_ const xsapi_internal_string& serviceConfigId,\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ const xsapi_internal_string& ticketId\n)\n{\n    xsapi_internal_stringstream ss;\n    ss << \"/serviceconfigs/\";\n    ss << serviceConfigId;\n    ss << \"/hoppers/\";\n    ss << hopperName;\n\n    if (!ticketId.empty())\n    {\n        ss << \"/tickets/\";\n        ss << ticketId;\n    }\n\n    return ss.str();\n}\n\nxsapi_internal_string MatchmakingService::GetHopperSubPath(\n    _In_ const xsapi_internal_string& serviceConfigId,\n    _In_ const xsapi_internal_string& hopperName\n) \n{\n    xsapi_internal_stringstream ss;\n    ss << \"/serviceconfigs/\";\n    ss << serviceConfigId;\n    ss << \"/hoppers/\";\n    ss << hopperName;\n    ss << \"/stats\";\n    \n    return ss.str();\n}\n\nxsapi_internal_string MatchmakingService::ConvertPreserveSessionModeToString(\n    _In_ XblPreserveSessionMode preserve_session\n) \n{\n    xsapi_internal_string retval(\"unknown\");\n    if (preserve_session == XblPreserveSessionMode::Always)\n    {\n        retval = \"always\";\n    }\n    else if (preserve_session == XblPreserveSessionMode::Never)\n    {\n        retval = \"never\";\n    }\n    \n    return retval;\n}\n\n/*static*/ HRESULT DeserializeHopperStatisticsResponseResult(\n    _In_ const JsonValue& json,\n    _Out_ HopperStatisticsResponse& result\n)\n{\n    HRESULT errc = S_OK;\n    if (json.IsNull())\n    {\n        result = HopperStatisticsResponse();\n    }\n    else\n    {\n        xsapi_internal_string name;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"name\", name, true));\n        int waitTime = 0;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"waitTime\", waitTime));\n        int population = 0;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"population\", population, false));\n        result = HopperStatisticsResponse(\n            name,\n            std::chrono::seconds(waitTime),\n            population\n        );\n    }\n\n    if (FAILED(errc))\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return S_OK;\n}\n\n/*static*/ HRESULT DeserializeCreateMatchTicketResponseResult(\n    _In_ const JsonValue& json,\n    _Out_ XblCreateMatchTicketResponse& result\n)\n{\n    HRESULT errc = S_OK;\n    if (json.IsNull())\n    {\n        result = XblCreateMatchTicketResponse();\n        memset(&result, 0, sizeof(XblCreateMatchTicketResponse));\n    }\n    else\n    {\n        xsapi_internal_string ticketId;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"ticketId\", ticketId, true));\n        memset(&result, 0, sizeof(XblCreateMatchTicketResponse));\n        utils::strcpy(result.matchTicketId, ticketId.size() + 1, ticketId.c_str());\n        int waitTime = 0;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"waitTime\", waitTime));\n        result.estimatedWaitTime = waitTime;\n    }\n\n    if (FAILED(errc))\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return S_OK;\n}\n\n/*static*/ HRESULT DeserializeMatchTicketDetailsResponse(\n    _In_ const JsonValue& json,\n    _Out_ MatchTicketDetailsResponse& result\n)\n{\n    HRESULT errc = S_OK;\n    if (json.IsNull() || !json.IsObject())\n    {\n        result = MatchTicketDetailsResponse();\n    }\n    else\n    {\n        XblMultiplayerSessionReference ticketSession{};\n        XblMultiplayerSessionReference targetSession{};\n        if (json.HasMember(\"ticketSessionRef\"))\n        {\n            ticketSession = xbox::services::multiplayer::Serializers::DeserializeSessionReference(json[\"ticketSessionRef\"]).Payload();\n        }\n        if (json.HasMember(\"targetSessionRef\"))\n        {\n            targetSession = xbox::services::multiplayer::Serializers::DeserializeSessionReference(json[\"targetSessionRef\"]).Payload();\n        }\n\n        xsapi_internal_string ticketStatus, preserveSession;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"ticketStatus\", ticketStatus, true));\n        int waitTime = 0;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"waitTime\", waitTime));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"preserveSession\", preserveSession, false));\n\n        if (json.HasMember(\"ticketAttributes\"))\n        {\n            result = MatchTicketDetailsResponse(\n                MatchTicketDetailsResponse::ConvertStringToTicketStatus(ticketStatus),\n                std::chrono::seconds(waitTime),\n                MatchTicketDetailsResponse::ConvertStringToPreserveSessionMode(preserveSession),\n                ticketSession, \n                targetSession,\n                json[\"ticketAttributes\"]\n            );\n        }\n        else\n        {\n            result = MatchTicketDetailsResponse(\n                MatchTicketDetailsResponse::ConvertStringToTicketStatus(ticketStatus),\n                std::chrono::seconds(waitTime),\n                MatchTicketDetailsResponse::ConvertStringToPreserveSessionMode(preserveSession),\n                ticketSession,\n                targetSession,\n                JsonValue()\n            );\n        }\n\n\n    }\n\n    if (FAILED(errc))\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return S_OK;\n}\n\nHRESULT MatchmakingService::CreateMatchTicket(\n    _In_ const XblMultiplayerSessionReference& ticketSessionReference,\n    _In_ const xsapi_internal_string& matchmakingServiceConfigurationId,\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ const std::chrono::seconds& ticketTimeout,\n    _In_ XblPreserveSessionMode preserveSession,\n    _In_ JsonValue& ticketAttributesJson,\n    _In_ XAsyncBlock* async\n) \n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n    XblCreateMatchTicketResponse result;\n    xsapi_internal_string subPath = GetMatchmakingSubPath(\n        matchmakingServiceConfigurationId,\n        hopperName,\n        xsapi_internal_string()\n    );\n\n    JsonDocument request(rapidjson::kObjectType);\n    JsonDocument::AllocatorType& allocator = request.GetAllocator();\n    request.AddMember(\"giveUpDuration\", JsonValue(static_cast<int32_t>(ticketTimeout.count())).Move(), allocator);\n    request.AddMember(\"preserveSession\", JsonValue(ConvertPreserveSessionModeToString(preserveSession).c_str(), allocator).Move(), allocator);\n    XblMultiplayerSessionReference _ticketSessionReference = XblMultiplayerSessionReferenceCreate(\n            ticketSessionReference.Scid, \n            ticketSessionReference.SessionTemplateName, \n            ticketSessionReference.SessionName);\n    JsonValue ticketSessonRefJsonObj(rapidjson::kObjectType);\n    multiplayer::Serializers::SerializeSessionReference(_ticketSessionReference, ticketSessonRefJsonObj, allocator);\n    request.AddMember(\"ticketSessionRef\", ticketSessonRefJsonObj, allocator);\n    if (!ticketAttributesJson.IsNull())\n    {\n       request.AddMember(\"ticketAttributes\", ticketAttributesJson, allocator);\n    }\n\n    xsapi_internal_string requestString = JsonUtils::SerializeJson(request);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            result, \n            sharedThis{ shared_from_this() }, \n            subPath, \n            requestString\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            Result<User> userResult = sharedThis->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                sharedThis->m_contextSettings,\n                \"POST\",\n                XblHttpCall::BuildUrl(\"smartmatch\", subPath),\n                xbox_live_api::create_match_ticket\n            );\n\n            RETURN_HR_IF_FAILED(hr);\n            RETURN_HR_IF_FAILED(httpCall->SetRetryAllowed(false));\n            RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(103));\n            RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestString));\n           \n            hr = httpCall->Perform(AsyncContext<HttpResult>{\n                TaskQueue::DeriveWorkerQueue(data->async->queue),\n                    [&result, data](HttpResult httpResult)\n                {\n                    HRESULT hr = httpResult.Hresult();\n                    if (SUCCEEDED(hr))\n                    {\n                        hr = httpResult.Payload()->Result();\n                        if (SUCCEEDED(hr))\n                        {\n                            hr = DeserializeCreateMatchTicketResponseResult(httpResult.Payload()->GetResponseBodyJson(), result);\n                        }\n                    }\n                    XAsyncComplete(data->async, hr, sizeof(XblCreateMatchTicketResponse));\n                }});\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            auto resultPtr = static_cast<XblCreateMatchTicketResponse*>(data->buffer);\n            *resultPtr = result;\n        }\n\n        return S_OK;\n    });\n}\n\nHRESULT MatchmakingService::DeleteMatchTicketAsync(\n    _In_ const xsapi_internal_string& serviceConfigurationId,\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ const xsapi_internal_string& ticketId,\n    _In_ XAsyncBlock* async\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n    xsapi_internal_string subPath = GetMatchmakingSubPath(\n        serviceConfigurationId,\n        hopperName,\n        ticketId\n    );\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            sharedThis{ shared_from_this() }, \n            subPath\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            Result<User> userResult = sharedThis->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                sharedThis->m_contextSettings,\n                \"DELETE\",\n                XblHttpCall::BuildUrl(\"smartmatch\", subPath),\n                xbox_live_api::delete_match_ticket\n            );\n\n            RETURN_HR_IF_FAILED(hr);\n            RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(103));\n\n            hr = httpCall->Perform(AsyncContext<HttpResult>{\n                TaskQueue::DeriveWorkerQueue(data->async->queue),\n                    [data](HttpResult httpResult)\n                {\n                    HRESULT hr = httpResult.Hresult();\n                    XAsyncComplete(data->async, hr, 0);\n                }});\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n\n        return S_OK;\n    });\n}\n\nHRESULT MatchmakingService::GetMatchTicketDetailsAsync(\n    _In_ const xsapi_internal_string& serviceConfigurationId,\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ const xsapi_internal_string& ticketId,\n    _In_ XAsyncBlock* async\n) \n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n    xsapi_internal_string subPath = GetMatchmakingSubPath(\n        serviceConfigurationId,\n        hopperName,\n        ticketId\n    );\n\n    MatchTicketDetailsResponse result;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            result, \n            subPath, \n            sharedThis{ shared_from_this() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            Result<User> userResult = sharedThis->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                sharedThis->m_contextSettings,\n                \"GET\",\n                XblHttpCall::BuildUrl(\"smartmatch\", subPath),\n                xbox_live_api::get_match_ticket_details\n            );\n\n            RETURN_HR_IF_FAILED(hr);\n            RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(103));\n\n            hr = httpCall->Perform(AsyncContext<HttpResult>{\n                TaskQueue::DeriveWorkerQueue(data->async->queue),\n                    [data, &result](HttpResult httpResult)\n                {\n                    HRESULT hr = httpResult.Hresult();\n                    if (SUCCEEDED(hr))\n                    {\n                        hr = httpResult.Payload()->Result();\n                        if (SUCCEEDED(hr))\n                        {\n                            hr = DeserializeMatchTicketDetailsResponse(httpResult.Payload()->GetResponseBodyJson(), result);\n                        }\n                    }\n\n                    size_t bufferSize = 0;\n                    if (!result.TicketAttributes().IsNull()) {\n                        bufferSize += JsonUtils::SerializeJson(result.TicketAttributes()).length() + 1;\n                    }\n        \n                    bufferSize += sizeof(XblMatchTicketDetailsResponse);\n                    XAsyncComplete(data->async, hr, bufferSize);\n                }});\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            XblMatchTicketDetailsResponse* matchTicketResult = reinterpret_cast<XblMatchTicketDetailsResponse*>(buffer);\n            matchTicketResult->preserveSession = result.PreserveSession();\n            matchTicketResult->estimatedWaitTime = result.EstimatedWaitTime().count();\n            matchTicketResult->matchStatus = result.MatchStatus();\n            utils::strcpy(matchTicketResult->ticketSession.Scid, sizeof(result.TicketSession().Scid), result.TicketSession().Scid);\n            utils::strcpy(matchTicketResult->ticketSession.SessionName, sizeof(result.TicketSession().SessionName), result.TicketSession().SessionName);\n            utils::strcpy(matchTicketResult->ticketSession.SessionTemplateName, sizeof(result.TicketSession().SessionTemplateName), result.TicketSession().SessionTemplateName);\n            utils::strcpy(matchTicketResult->targetSession.Scid, sizeof(result.TargetSession().Scid), result.TargetSession().Scid);\n            utils::strcpy(matchTicketResult->targetSession.SessionName, sizeof(result.TargetSession().SessionName), result.TargetSession().SessionName);\n            utils::strcpy(matchTicketResult->targetSession.SessionTemplateName, sizeof(result.TargetSession().SessionTemplateName), result.TargetSession().SessionTemplateName);\n            if (!result.TicketAttributes().IsNull()) {\n                buffer += sizeof(XblMatchTicketDetailsResponse);\n                matchTicketResult->ticketAttributes = static_cast<char*>(buffer);\n            \tutils::strcpy(buffer, JsonUtils::SerializeJson(result.TicketAttributes()).size() + 1, JsonUtils::SerializeJson(result.TicketAttributes()).c_str());\n            }\n            else \n            {\n                matchTicketResult->ticketAttributes = nullptr;\n            }\n        }\n\n        return S_OK;\n    });\n}\n\nHRESULT MatchmakingService::GetHopperStatistics(\n    _In_ const xsapi_internal_string& serviceConfigurationId,\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ XAsyncBlock* async\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n    xsapi_internal_string subPath = GetHopperSubPath(\n        serviceConfigurationId,\n        hopperName\n    );\n    HopperStatisticsResponse result;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            result, \n            subPath, \n            sharedThis{ shared_from_this() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            Result<User> userResult = sharedThis->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                sharedThis->m_contextSettings,\n                \"GET\",\n                XblHttpCall::BuildUrl(\"smartmatch\", subPath),\n                xbox_live_api::get_hopper_statistics\n            );\n\n            RETURN_HR_IF_FAILED(hr);\n            RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(103));\n\n            hr = httpCall->Perform(AsyncContext<HttpResult>{\n                TaskQueue::DeriveWorkerQueue(data->async->queue),\n                    [data, &result](HttpResult httpResult)\n                {\n                    HRESULT hr = httpResult.Hresult();\n                    if (SUCCEEDED(hr))\n                    {\n                        hr = httpResult.Payload()->Result();\n                        if (SUCCEEDED(hr))\n                        {\n                            hr = DeserializeHopperStatisticsResponseResult(httpResult.Payload()->GetResponseBodyJson(), result);\n                        }\n                    }\n                    XAsyncComplete(data->async, hr, sizeof(XblHopperStatisticsResponse) + result.HopperName().size() + 1);\n                }\n            });\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            auto resultPtr = reinterpret_cast<XblHopperStatisticsResponse*>(buffer);\n            resultPtr->estimatedWaitTime = result.EstimatedWaitTime().count();\n            resultPtr->playersWaitingToMatch = result.PlayersWaitingToMatch();\n            auto hopperName = result.HopperName();\n            auto stringPtr = buffer + sizeof(XblHopperStatisticsResponse);\n            utils::strcpy(stringPtr, hopperName.size() + 1, hopperName.c_str());\n            resultPtr->hopperName = stringPtr;\n        }\n\n        return S_OK;\n    });\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END\n\n\n/// <summary>\n/// Sends a matchmaking request to the server and returns the match ticket with a ticket id.\n/// Call XblMatchmakingCreateMatchTicketResultSize and XblMatchmakingCreateMatchTicketResult upon completion to get the result\n/// </summary>\n/// <param name=\"XboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"ticketSessionReference\">The multiplayer session to use for the match.</param>\n/// <param name=\"matchmakingServiceConfigurationId\">The service configuration ID for the match.</param>\n/// <param name=\"hopperName\">The name of the hopper.</param>\n/// <param name=\"ticketTimeout\">The maximum time to wait for players to join the session.</param>\n/// <param name=\"preserveSession\">Indicates if the session should be preserved.</param>\n/// <param name=\"ticketAttributesJson\">The ticket attributes for the session. (Optional)</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>The async object for notifying when the operation is completed. With the handler, a new match ticket\n/// object is returned. The match ticket object contains server returned information such as ticket id and wait\n/// time, and also contains copies of the title specified data from the ticket data object.</returns>\n/// <remarks>Calls V103 POST /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}</remarks>\nSTDAPI XblMatchmakingCreateMatchTicketAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblMultiplayerSessionReference ticketSessionReference,\n    _In_ const char* matchmakingServiceConfigurationId,\n    _In_ const char* hopperName,\n    _In_ const uint64_t ticketTimeout,\n    _In_ XblPreserveSessionMode preserveSession,\n    _In_ const char* ticketAttributesJson,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(matchmakingServiceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(asyncBlock);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(hopperName);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ticketAttributesJson);\n    VERIFY_XBL_INITIALIZED();\n\n    return xboxLiveContext->MatchmakingService()->CreateMatchTicket(\n        ticketSessionReference,\n        matchmakingServiceConfigurationId,\n        hopperName,\n        std::chrono::seconds(ticketTimeout),\n        preserveSession,\n        JsonDocument().Parse(ticketAttributesJson),\n        asyncBlock);\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Get the result for an XblMatchmakingCreateMatchTicketAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.</param>\n/// <param name=\"buffer\">Byte buffer to write result into.</param>\n/// <param name=\"resultPtr\">Pointer to result.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\nSTDAPI XblMatchmakingCreateMatchTicketResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ XblCreateMatchTicketResponse* resultPtr\n) XBL_NOEXCEPT \ntry\n{\n    auto hr = XAsyncGetResult(asyncBlock, nullptr, sizeof(XblCreateMatchTicketResponse), resultPtr, nullptr);\n    return hr;\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Deletes a the match ticket on the server.\n/// </summary>\n/// <param name=\"XboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"serviceConfigurationId\">The service config id that is specific for the title.</param>\n/// <param name=\"hopperName\">The name of the hopper where the match ticket is located.</param>\n/// <param name=\"ticketId\">The id of the ticket to delete on the server.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>The async object for notifying when the operation has been completed.</returns>\n/// <remarks>Calls V103 DELETE /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/tickets/{ticketId}</remarks>\nSTDAPI XblMatchmakingDeleteMatchTicketAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* serviceConfiguration,\n    _In_ const char* hopperName,\n    _In_ const char* ticketId,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT \ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfiguration);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(asyncBlock);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(hopperName);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ticketId);\n    VERIFY_XBL_INITIALIZED();\n\n    return xboxLiveContext->MatchmakingService()->DeleteMatchTicketAsync(\n        serviceConfiguration,\n        hopperName,\n        ticketId,\n        asyncBlock);\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Retrieves the properties of a match ticket from the server.\n/// </summary>\n/// <param name=\"XboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"serviceConfigurationId\">The service config id that is specific for the title.</param>\n/// <param name=\"hopperName\">The name of the hopper where the match ticket is located.</param>\n/// <param name=\"ticketId\">The ticket id of the match ticket to retrieve.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>The async object for notifying when the operation is completed. With the handler, the match\n/// ticket object with the data for the ticket, including ticket id and wait time information, is returned\n/// returned from the server.</returns>\n/// <remarks>Calls V103 GET /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/tickets/{ticketId}</remarks>\nSTDAPI XblMatchmakingGetMatchTicketDetailsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* serviceConfiguration,\n    _In_ const char* hopperName,\n    _In_ const char* ticketId,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT \ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfiguration);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(asyncBlock);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(hopperName);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ticketId);\n    VERIFY_XBL_INITIALIZED();\n\n    return xboxLiveContext->MatchmakingService()->GetMatchTicketDetailsAsync(\n        serviceConfiguration,\n        hopperName,\n        ticketId,\n        asyncBlock);\n\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Get the result size for an XblMatchmakingGetMatchTicketDetailsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the Create Match Ticket result.</param>\nSTDAPI XblMatchmakingGetMatchTicketDetailsResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT \ntry\n{\n    return XAsyncGetResultSize(asyncBlock, resultSizeInBytes);\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Get the result for an XblMatchmakingGetMatchTicketDetailsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.</param>\n/// <param name=\"buffer\">Byte buffer to write result into.</param>\n/// <param name=\"result\">Pointer to result.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\nSTDAPI XblMatchmakingGetMatchTicketDetailsResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMatchTicketDetailsResponse** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT \ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    auto hr = XAsyncGetResult(asyncBlock, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblMatchTicketDetailsResponse*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Gets statistics about a hopper such as how many players are in it.\n/// </summary>\n/// <param name=\"XboxLiveContext\">Xbox live context for the local user.</param>\n/// <param name=\"serviceConfigurationId\">The service config id that is specific for the title.</param>\n/// <param name=\"hopperName\">The name of the hopper to query stats for.</param>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <returns>The async object for notifying when the operation is completed. With the handler, an object\n/// containing statistics about the hopper is returned.</returns>\n/// <remarks>Calls V103 GET /serviceconfigs/{serviceConfigId}/hoppers/{hopperName}/stats</remarks>\nSTDAPI XblMatchmakingGetHopperStatisticsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ const char* serviceConfiguration,\n    _In_ const char* hopperName,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT \ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfiguration);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(asyncBlock);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(hopperName);\n    VERIFY_XBL_INITIALIZED();\n\n    return xboxLiveContext->MatchmakingService()->GetHopperStatistics(\n        serviceConfiguration,\n        hopperName,\n        asyncBlock\n    );\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Get the result size for an XblMatchmakingGetHopperStatisticsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"resultSizeInBytes\">The size in bytes required to store the Create Match Ticket result.</param>\nSTDAPI XblMatchmakingGetHopperStatisticsResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT \ntry\n{\n    return XAsyncGetResultSize(asyncBlock, resultSizeInBytes);\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Get the result for an XblMatchmakingGetHopperStatisticsAsync call.\n/// </summary>\n/// <param name=\"asyncBlock\">The AsyncBlock for this operation.</param>\n/// <param name=\"bufferSize\">The size of the provided buffer.</param>\n/// <param name=\"buffer\">Byte buffer to write result into.</param>\n/// <param name=\"result\">Pointer to result.</param>\n/// <param name=\"bufferUsed\">Number of bytes written to the buffer.</param>\nSTDAPI XblMatchmakingGetHopperStatisticsResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblHopperStatisticsResponse** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    auto hr = XAsyncGetResult(asyncBlock, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblHopperStatisticsResponse*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_client_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#if !XSAPI_NO_PPL\n#include \"pplx/pplxtasks.h\"\n#endif\n#include \"multiplayer_manager_internal.h\"\n#include \"multiplayer_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n\n#if HC_PLATFORM != HC_PLATFORM_WIN32 && !XSAPI_NO_PPL\n#include \"xsapi-cpp/title_callable_ui.h\"\n#endif\n\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include \"XGameUI.h\"\n#endif\n\nusing namespace xbox::services;\nusing namespace xbox::services::legacy;\nusing namespace xbox::services::multiplayer;\n#if __cplusplus_winrt\nusing namespace Windows::Foundation;\nusing namespace Windows::Foundation::Collections;\n#endif\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerClientManager::MultiplayerClientManager(_In_ const MultiplayerClientManager& other) \n{\n    std::lock_guard<std::mutex> lock(other.m_clientRequestLock);\n\n    m_sessionChangedContext = other.m_sessionChangedContext;\n    m_subscriptionLostContext = other.m_subscriptionLostContext;\n    m_rtaResyncContext = other.m_rtaResyncContext;\n    m_primaryXboxLiveContext = other.m_primaryXboxLiveContext == nullptr ? nullptr : other.m_primaryXboxLiveContext;\n    m_lastPendingRead = other.m_lastPendingRead == nullptr ? nullptr : other.m_lastPendingRead;\n    m_latestPendingRead = other.m_latestPendingRead == nullptr ? nullptr : other.m_latestPendingRead;\n    m_queue = other.m_queue;\n}\n\nMultiplayerClientManager::MultiplayerClientManager(\n    _In_ const xsapi_internal_string& lobbySessionTemplateName,\n    _In_ const TaskQueue& queue\n) :\n    m_subscriptionsLostFired(false),\n    m_autoFillMembers(false),\n    m_lobbySessionTemplateName(lobbySessionTemplateName),\n    m_sessionChangedContext(0),\n    m_subscriptionLostContext(0),\n    m_rtaResyncContext(0),\n    m_queue{ queue.DeriveWorkerQueue() }\n{\n    m_multiplayerLocalUserManager = MakeShared<MultiplayerLocalUserManager>();\n}\n\nvoid MultiplayerClientManager::RegisterLocalUserManagerEvents()\n{\n    std::weak_ptr<MultiplayerClientManager> weakSessionWriter = shared_from_this();\n    m_sessionChangedContext = m_multiplayerLocalUserManager->AddMultiplayerSessionChangedHandler([weakSessionWriter](_In_ XblMultiplayerSessionChangeEventArgs args)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(weakSessionWriter.lock());\n        if (pThis != nullptr)\n        {\n            pThis->OnSessionChanged(args);\n        }\n    });\n\n    m_connectionIdChangedContext = m_multiplayerLocalUserManager->AddMultiplayerConnectionIdChangedHandler([weakSessionWriter](void)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(weakSessionWriter.lock());\n        if (pThis != nullptr)\n        {\n            pThis->OnMultiplayerConnectionIdChanged();\n        }\n    });\n\n    m_subscriptionLostContext = m_multiplayerLocalUserManager->AddMultiplayerSubscriptionLostHandler([weakSessionWriter](void)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(weakSessionWriter.lock());\n        if (pThis != nullptr)\n        {\n            pThis->OnMultiplayerSubscriptionsLost();\n        }\n    });\n\n    m_rtaResyncContext = m_multiplayerLocalUserManager->AddRtaResyncHandler([weakSessionWriter](void)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(weakSessionWriter.lock());\n        if (pThis != nullptr)\n        {\n            pThis->OnResyncMessageReceived();\n        }\n    });\n}\n\nvoid\nMultiplayerClientManager::Initialize()\n{\n    if (m_multiplayerLocalUserManager == nullptr)\n    {\n        m_multiplayerLocalUserManager = MakeShared<MultiplayerLocalUserManager>();\n        RegisterLocalUserManagerEvents();\n    }\n\n    m_latestPendingRead = MakeShared<MultiplayerClientPendingReader>(\n        m_queue,\n        m_lobbySessionTemplateName, \n        m_multiplayerLocalUserManager\n        );\n\n    m_lastPendingRead = MakeShared<MultiplayerClientPendingReader>(m_queue);\n    m_subscriptionsLostFired.store(false);\n    m_latestPendingRead->SetAutoFillMembersDuringMatchmaking(m_autoFillMembers);\n}\n\nvoid MultiplayerClientManager::Shutdown()\n{\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    Destroy();\n}\n\nvoid\nMultiplayerClientManager::Destroy()\n{\n    m_latestPendingRead.reset();\n    m_lastPendingRead.reset();\n    if (m_multiplayerLocalUserManager != nullptr)\n    {\n        m_multiplayerLocalUserManager->RemoveMultiplayerSessionChangedHandler(m_sessionChangedContext);\n        m_multiplayerLocalUserManager->RemoveMultiplayerSubscriptionLostHandler(m_subscriptionLostContext);\n        m_multiplayerLocalUserManager->RemoveMultiplayerConnectionIdChangedHandler(m_connectionIdChangedContext);\n        m_multiplayerLocalUserManager->RemoveRtaResyncHandler(m_rtaResyncContext);\n        m_multiplayerLocalUserManager.reset();\n    }\n}\n\nstd::shared_ptr<MultiplayerLocalUserManager>\nMultiplayerClientManager::LocalUserManager()\n{\n    return m_multiplayerLocalUserManager;\n}\n\nHRESULT\nMultiplayerClientManager::SetProperties(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    // Note: sessionRef can be empty for the lobby initially as we may have not created one yet.\n    RETURN_HR_IF(name.empty(), E_INVALIDARG);\n\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    auto latestPending = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPending == nullptr || GetXboxLiveContextMap().size() == 0, E_UNEXPECTED, \"Call add_local_user() before writing lobby properties.\");\n\n    latestPending->SetProperties(sessionRef, name, valueJson, context);\n    return S_OK;\n}\n\nHRESULT\nMultiplayerClientManager::SetJoinability(\n    _In_ XblMultiplayerJoinability value,\n    _In_opt_ context_t context\n    )\n{\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    auto latestPending = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPending == nullptr || GetXboxLiveContextMap().size() == 0, E_UNEXPECTED, \"Call add_local_user() before writing lobby properties.\");\n\n    return latestPending->LobbyClient()->SetJoinability(value, context);\n}\n\nHRESULT\nMultiplayerClientManager::SetSynchronizedHost(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ const xsapi_internal_string& hostDeviceToken,\n    _In_opt_ context_t context\n    )\n{\n    // Note: sessionRef can be empty for the lobby initially as we may have not created one yet.\n    RETURN_HR_IF(hostDeviceToken.empty(), E_INVALIDARG);\n\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    auto latestPending = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPending == nullptr || GetXboxLiveContextMap().size() == 0, E_UNEXPECTED, \"Call add_local_user() before writing host properties.\");\n\n    return latestPending->SetSynchronizedHost(sessionRef, hostDeviceToken, context);\n}\n\nHRESULT\nMultiplayerClientManager::SetSynchronizedProperties(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    // Note: sessionRef can be empty for the lobby initially as we may have not created one yet.\n    RETURN_HR_IF(name.empty(), E_INVALIDARG);\n\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    auto latestPending = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPending == nullptr || GetXboxLiveContextMap().size() == 0, E_UNEXPECTED, \"Call add_local_user() before writing lobby properties.\");\n\n    return latestPending->SetSynchronizedProperties(sessionRef, name, valueJson, context);\n}\n\nvoid\nMultiplayerClientManager::SynchronizedWriteCompleted(\n    _In_ std::error_code errorCode,\n    _In_ XblMultiplayerEventType eventType,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    AddToLatestPendingReadEventQueue(eventType, sessionType, nullptr, errorCode);\n}\n\nHRESULT\nMultiplayerClientManager::JoinLobbyByHandle(\n    _In_ const xsapi_internal_string& handleId,\n    _In_ const xsapi_internal_vector<xbox_live_user_t>& users\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handleId.empty() || users.empty());\n\n    auto latestPending = LatestPendingRead();\n    if (latestPending == nullptr)\n    {\n        Initialize();\n        latestPending = LatestPendingRead();\n    }\n\n    latestPending->LobbyClient()->AddLocalUsers(users, handleId);\n    return S_OK;\n}\n\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK \nHRESULT\nMultiplayerClientManager::JoinLobby(\n    _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n    _In_ xsapi_internal_vector<xbox_live_user_t> users\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF(users.empty());\n    return JoinLobby(ref new Windows::Foundation::Uri(eventArgs->Uri->RawUri), users);\n}\n\nHRESULT\nMultiplayerClientManager::JoinLobby(\n    _In_ Windows::Foundation::Uri^ url,\n    _In_ xsapi_internal_vector<xbox_live_user_t> users\n    )\n{\n    xsapi_internal_string handleId;\n    uint64_t invitedXuid;\n    if (utils::str_icmp(url->Host->Data(), _T(\"inviteHandleAccept\")) == 0)\n    {\n        handleId = utils::internal_string_from_utf16(url->QueryParsed->GetFirstValueByName(\"handle\")->Data());\n        invitedXuid = utils::string_t_to_uint64(url->QueryParsed->GetFirstValueByName(\"invitedXuid\")->Data());\n    }\n    else if(utils::str_icmp(url->Host->Data(), _T(\"activityHandleJoin\")) == 0)\n    {\n        handleId = utils::internal_string_from_utf16(url->QueryParsed->GetFirstValueByName(\"handle\")->Data());\n        invitedXuid = utils::string_t_to_uint64(url->QueryParsed->GetFirstValueByName(\"joinerXuid\")->Data());\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n\n    // Check if the xuid matches with the sent users.\n    bool invitedUserFound = false;\n    int invitedUserIndex = 0;\n    for (auto& user: users)\n    {\n        auto userResult = User::WrapHandle(user);\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n        if (invitedXuid == userResult.ExtractPayload().Xuid())\n        {\n            invitedUserFound = true;\n            break;\n        }\n        invitedUserIndex++;\n    }\n\n    if (!invitedUserFound)\n    {\n        // The invited user hasn't been added.\n        std::shared_ptr<JoinLobbyCompletedEventArgs> joinLobbyEventArgs = MakeShared<JoinLobbyCompletedEventArgs>(invitedXuid);\n\n        // Since m_latestPendingRead hasn't been initialized yet, this will ensure \n        // the event is still returned correctly through multiplayer_manager::do_work();\n        // InvitedXuid's user hasn't been added. Pass in the invited user into join_lobby() API.\n        m_multiplayerEventQueue.AddEvent(\n            XblMultiplayerEventType::JoinLobbyCompleted,\n            XblMultiplayerSessionType::LobbySession,\n            std::dynamic_pointer_cast<JoinLobbyCompletedEventArgs>(joinLobbyEventArgs),\n            E_UNEXPECTED,\n            \"Pass in the invited user into join_lobby() API.\"\n        );\n\n        LOG_DEBUG(\"Pass in the invited user into join_lobby() API.\");\n        return E_UNEXPECTED;\n    }\n    else if (invitedUserFound && invitedUserIndex > 0)\n    {\n        auto invitedUser = users[0];\n        users[0] = users[invitedUserIndex];\n        users[invitedUserIndex] = invitedUser;\n    }\n\n    // This will also join any game that is associated with the lobby.\n    if (!handleId.empty())\n    {\n        return JoinLobbyByHandle(handleId, users);\n    }\n\n    return S_OK;\n}\n#endif\n\nHRESULT\nMultiplayerClientManager::JoinGameFromLobby(\n    _In_ const xsapi_internal_string& sessionTemplateName\n    )\n{\n    auto primaryContext = GetPrimaryContext();\n    auto latestPending = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr || latestPending == nullptr || latestPending->LobbyClient()->Session() == nullptr, E_UNEXPECTED, \"No lobby session exists. Call add_local_user() to create a lobby first.\");\n    RETURN_HR_IF_LOG_DEBUG(latestPending->GameClient()->Session() != nullptr, E_UNEXPECTED, \"A game session already exists. Call leave_game() to leave existing game before creating a new one.\");\n    RETURN_HR_IF_LOG_DEBUG (latestPending->MatchClient()->MatchStatus() > XblMultiplayerMatchStatus::None, E_UNEXPECTED, \"Matchmaking is currently in progress. Call cancel_match() before joining a game.\")\n\n    latestPending->GameClient()->SetGameSessionTemplate(sessionTemplateName);\n\n    // We don't care about the async result here, Join result raised as an event after calling do_work so just pass nullptr as callback\n    return latestPending->GameClient()->JoinGameFromLobbyHelper( \n        [](Result<std::shared_ptr<XblMultiplayerSession>> result)\n    {\n        assert(SUCCEEDED(result.Hresult()));\n    });\n}\n\nHRESULT\nMultiplayerClientManager::JoinGame(\n    _In_ const xsapi_internal_string& sessionName,\n    _In_ const xsapi_internal_string& sessionTemplateName,\n    _In_ const xsapi_internal_vector<uint64_t>& xboxUserIds\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF(sessionName.empty());\n    std::shared_ptr<XblContext> primaryContext = GetPrimaryContext();\n    RETURN_HR_IF(primaryContext == nullptr, E_UNEXPECTED);\n\n    auto latestPending = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPending == nullptr, E_UNEXPECTED, \"No lobby session exists. Call add_local_user() to create a lobby first.\");\n    RETURN_HR_IF_LOG_DEBUG(latestPending->MatchClient()->MatchStatus() > XblMultiplayerMatchStatus::None, E_UNEXPECTED, \"Matchmaking is currently in progress. Call cancel_match() before joining a game\");\n\n    auto gameClient = latestPending->GameClient();\n    RETURN_HR_IF(gameClient == nullptr, E_FAIL);\n\n    Function<void()> joinGameHelper = [sharedThis{ shared_from_this() }, gameClient, sessionTemplateName, sessionName]()\n    {\n        gameClient->SetGameSessionTemplate(sessionTemplateName);\n        gameClient->JoinGameHelper(sessionName, nullptr);\n    };\n\n    if (xboxUserIds.size() > 0)\n    {\n        auto gameSessionRef = XblMultiplayerSessionReferenceCreate(\n            AppConfig::Instance()->OverrideScid().data(),\n            sessionTemplateName.data(),\n            sessionName.data()\n        );\n\n        XblMultiplayerSessionInitArgs initArgs{};\n        initArgs.InitiatorXuids = xboxUserIds.data();\n        initArgs.InitiatorXuidsCount = static_cast<uint32_t>(xboxUserIds.size());\n\n        auto gameSession = MakeShared<XblMultiplayerSession>(\n            primaryContext->Xuid(),\n            &gameSessionRef,\n            &initArgs\n            );\n\n        gameSession->Join(nullptr, false);\n        for (const auto& memberXuid : xboxUserIds)\n        {\n            if (memberXuid != primaryContext->Xuid())\n            {\n                gameSession->AddMemberReservation(memberXuid);\n            }\n        }\n\n        std::weak_ptr<MultiplayerClientManager> weakThis = shared_from_this();\n        return primaryContext->MultiplayerService()->WriteSession(gameSession, XblMultiplayerSessionWriteMode::UpdateOrCreateNew, { m_queue,\n            [weakThis, sessionTemplateName, joinGameHelper](Result<std::shared_ptr<XblMultiplayerSession>> result)\n        {\n            std::shared_ptr<MultiplayerClientManager> pThis(weakThis.lock());\n            if (pThis == nullptr || pThis->m_latestPendingRead == nullptr)\n            {\n                return;\n            }\n\n            if (FAILED(result.Hresult()))\n            {\n                pThis->AddToLatestPendingReadEventQueue(\n                    XblMultiplayerEventType::JoinGameCompleted,\n                    XblMultiplayerSessionType::GameSession,\n                    nullptr,\n                    result\n                );\n            }\n            else\n            {\n                // Continue joining the session for all local users.\n                joinGameHelper();\n            }\n        }\n        });\n    }\n    else\n    {\n        joinGameHelper();\n    }\n\n    return S_OK;\n}\n\nHRESULT\nMultiplayerClientManager::LeaveGame()\n{\n    std::shared_ptr<XblContext> primaryContext = GetPrimaryContext();\n    auto latestPendingRead = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPendingRead == nullptr || primaryContext == nullptr, E_UNEXPECTED, \"Call add_local_user() before committing.\");\n\n    auto gameSession = latestPendingRead->GameClient()->Session();\n    if (gameSession != nullptr)\n    {\n        latestPendingRead->GameClient()->LeaveRemoteSession(gameSession, true, true);\n    }\n\n    if (latestPendingRead->MatchClient()->MatchStatus() != XblMultiplayerMatchStatus::None)\n    {\n        latestPendingRead->MatchClient()->CancelMatch();\n        latestPendingRead->MatchClient()->SetMatchStatus(XblMultiplayerMatchStatus::Canceled);\n        // Matchmaking request was canceled since leave_game() was called\n        latestPendingRead->MatchClient()->HandleFindMatchCompleted({ xbl_error_code::generic_error, \"Matchmaking request was canceled since leave_game() was called\" });\n    }\n\n    m_multiplayerLocalUserManager->ChangeAllLocalUserGameState(MultiplayerLocalUserGameState::Unknown);\n    return S_OK;\n}\n\nHRESULT\nMultiplayerClientManager::GetActivitiesForSocialGroup(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& socialGroup,\n    _In_ XTaskQueueHandle queue,\n    _In_ Callback<Result<xsapi_internal_vector<XblMultiplayerActivityDetails>>> callback\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n    auto wrapUserResult{ User::WrapHandle(user) };\n    RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n    auto serviceResult = GetMultiplayerService(user);\n    RETURN_HR_IF_FAILED(serviceResult.Hresult());\n\n    return serviceResult.ExtractPayload()->GetActivitiesForSocialGroup(\n        AppConfig::Instance()->OverrideScid(),\n        wrapUserResult.Payload().Xuid(),\n        socialGroup,\n        AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>>{ queue, std::move(callback) }\n        );\n}\n\nHRESULT\nMultiplayerClientManager::InviteFriends(\n    _In_ xbox_live_user_t requestingUser,\n    _In_ const xsapi_internal_string& invitationText,\n    _In_ const xsapi_internal_string& customActivationContext\n    )\n{\n    UNREFERENCED_PARAMETER(customActivationContext);\n    UNREFERENCED_PARAMETER(invitationText);\n    RETURN_HR_INVALIDARGUMENT_IF(requestingUser == nullptr);\n    auto latestPendingRead = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPendingRead == nullptr || latestPendingRead->LobbyClient()->Session() == nullptr, E_UNEXPECTED, \"Call add_local_user() and wait for user_added completion event before sending invites.\");\n    HRESULT hr = S_OK;\n\n    std::weak_ptr<MultiplayerClientManager> thisWeakPtr = shared_from_this();\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n\n    auto sessionRef = latestPendingRead->LobbyClient()->Session()->SessionReference();\n    auto sessionReferenceToInviteTo = ref new Windows::Xbox::Multiplayer::MultiplayerSessionReference(\n        utils::PlatformStringFromUtf8(sessionRef.SessionName),\n        utils::PlatformStringFromUtf8(sessionRef.Scid),\n        utils::PlatformStringFromUtf8(sessionRef.SessionTemplateName)\n    );\n\n    Windows::Xbox::System::IUser^ systemUser = nullptr;\n    hr = XalUserToXboxSystemUser(requestingUser, &systemUser);\n    if (FAILED(hr)) return hr;\n\n    auto asyncOp = Windows::Xbox::UI::SystemUI::ShowSendGameInvitesAsync(\n        systemUser,\n        sessionReferenceToInviteTo,\n        utils::PlatformStringFromUtf8(invitationText.data()),\n        utils::PlatformStringFromUtf8(customActivationContext.data())\n    );\n\n    asyncOp->Completed = ref new AsyncActionCompletedHandler(\n        [thisWeakPtr](IAsyncAction^ asyncInfo, AsyncStatus asyncStatus)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(thisWeakPtr.lock());\n        if(pThis != nullptr)\n        {\n            if (asyncStatus == AsyncStatus::Completed && SUCCEEDED(asyncInfo->ErrorCode.Value))\n            {\n                pThis->AddToLatestPendingReadEventQueue(\n                    XblMultiplayerEventType::InviteSent,\n                    XblMultiplayerSessionType::LobbySession\n                );\n            }\n            else\n            {\n                pThis->AddToLatestPendingReadEventQueue(\n                    XblMultiplayerEventType::InviteSent,\n                    XblMultiplayerSessionType::LobbySession,\n                    nullptr,\n                    ConvertHr(asyncInfo->ErrorCode.Value)\n                );\n            }\n        }\n    });\n\n#elif HC_PLATFORM == HC_PLATFORM_GDK\n\n    XAsyncBlock* asyncBlock = Make<XAsyncBlock>();\n    asyncBlock->queue = m_queue.GetHandle();\n    asyncBlock->context = utils::store_shared_ptr(shared_from_this());\n    asyncBlock->callback = [](_In_ XAsyncBlock* asyncBlock)\n    {\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        auto pThis = utils::get_shared_ptr<MultiplayerClientManager>(asyncBlock->context);\n        pThis->AddToLatestPendingReadEventQueue(\n            XblMultiplayerEventType::InviteSent,\n            XblMultiplayerSessionType::LobbySession,\n            nullptr,\n            make_error_code(xbl_error_code(hr)));\n\n        Delete(asyncBlock);\n    };\n\n    // TODO have a way to set async queue here\n    hr = XGameUiShowSendGameInviteAsync(\n        asyncBlock,\n        requestingUser,\n        LobbyClient()->Session()->SessionReference().Scid,\n        LobbyClient()->Session()->SessionReference().SessionTemplateName,\n        LobbyClient()->Session()->SessionReference().SessionName,\n        invitationText.c_str(),\n        customActivationContext.c_str());\n\n#elif HC_PLATFORM != HC_PLATFORM_WIN32 && !XSAPI_NO_PPL\n\n    UNREFERENCED_PARAMETER(customActivationContext);\n    auto asyncOp = xbox::services::system::title_callable_ui::show_game_invite_ui(\n        latestPendingRead->LobbyClient()->Session()->SessionReference(),\n        utils::string_t_from_internal_string(invitationText)\n        );\n\n    pplx::create_task(asyncOp)\n    .then([thisWeakPtr](xbox_live_result<void> result)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(thisWeakPtr.lock());\n        if (pThis != nullptr)\n        {\n            pThis->AddToLatestPendingReadEventQueue(\n                XblMultiplayerEventType::InviteSent,\n                XblMultiplayerSessionType::LobbySession,\n                nullptr,\n                result.err()\n            );\n        }\n    });\n\n#else\n\n    UNREFERENCED_PARAMETER(invitationText);\n    UNREFERENCED_PARAMETER(customActivationContext);\n\n#endif\n\n    return hr;\n}\n\nHRESULT\nMultiplayerClientManager::InviteUsers(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_vector<uint64_t>& xboxUserIds,\n    _In_ const xsapi_internal_string& invitationText,\n    _In_ const xsapi_internal_string& customActivationContext\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n    auto latestPendingRead = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPendingRead == nullptr || latestPendingRead->LobbyClient()->Session() == nullptr,\n        E_UNEXPECTED, \"Call add_local_user() and wait for user_added completion event before sending invites.\");\n\n    std::weak_ptr<MultiplayerClientManager> weakSessionWriter = shared_from_this();\n\n    auto serviceResult = GetMultiplayerService(user);\n    RETURN_HR_IF_FAILED(serviceResult.Hresult());\n\n    return serviceResult.ExtractPayload()->SendInvites(\n        latestPendingRead->LobbyClient()->Session()->SessionReference(),\n        xboxUserIds,\n        AppConfig::Instance()->OverrideTitleId(),\n        invitationText,\n        customActivationContext,\n        AsyncContext<Result<Vector<String>>>{ m_queue,\n        [weakSessionWriter](Result<Vector<String>> result)\n    {\n        std::shared_ptr<MultiplayerClientManager> pThis(weakSessionWriter.lock());\n        if (pThis != nullptr)\n        {\n            std::lock_guard<std::mutex> guard(pThis->m_clientRequestLock);\n            pThis->AddToLatestPendingReadEventQueue(\n                XblMultiplayerEventType::InviteSent,\n                XblMultiplayerSessionType::LobbySession,\n                nullptr,\n                result\n            );\n        }\n    }\n    });\n}\n\nResult<std::shared_ptr<MultiplayerService>>\nMultiplayerClientManager::GetMultiplayerService(\n    _In_ xbox_live_user_t user\n    )\n{\n    auto localUser = m_multiplayerLocalUserManager->GetLocalUser(user);\n    if (localUser != nullptr)\n    {\n        return localUser->Context()->MultiplayerService();\n    }\n    else\n    {\n        std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings = MakeShared<xbox::services::XboxLiveContextSettings>();\n        std::shared_ptr<AppConfig> appConfig = xbox::services::AppConfig::Instance();\n        auto wrapUserResult{ User::WrapHandle(user) };\n        RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n        auto multiplayerService = MakeShared<MultiplayerService>(wrapUserResult.ExtractPayload(), xboxLiveContextSettings, appConfig, nullptr);\n        return multiplayerService;\n    }\n}\n\nstd::shared_ptr<MultiplayerClientPendingReader>\nMultiplayerClientManager::LatestPendingRead() const\n{\n    return m_latestPendingRead;\n}\n\nstd::shared_ptr<MultiplayerClientPendingReader>\nMultiplayerClientManager::LastPendingRead() const\n{\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    return m_lastPendingRead;\n}\n\nstd::shared_ptr<MultiplayerLobbyClient>\nMultiplayerClientManager::LobbyClient() const\n{\n    return m_latestPendingRead->LobbyClient();\n}\n\nbool\nMultiplayerClientManager::IsRequestInProgress()\n{\n    if (m_latestPendingRead->LobbyClient()->IsRequestInProgress() ||\n        m_latestPendingRead->GameClient()->IsRequestInProgress())\n    {\n        return true;\n    }\n\n    return false;\n}\n\nbool\nMultiplayerClientManager::IsUpdateAvailable()\n{\n    if (m_latestPendingRead == nullptr || m_lastPendingRead == nullptr)\n    {\n        return false;\n    }\n\n    if (m_lastPendingRead->IsUpdateAvailable(*m_latestPendingRead))\n    {\n        return true;\n    }\n\n    if (GetXboxLiveContextMap().size() == 0 && IsRequestInProgress())\n    {\n        return true;\n    }\n\n    // Always do work for match\n    m_latestPendingRead->ProcessMatchEvents();\n\n    return false;\n}\n\nMultiplayerEventQueue\nMultiplayerClientManager::DoWork()\n{\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    m_multiplayerEventQueue.Clear();\n\n    if (m_latestPendingRead == nullptr)\n    {\n        return m_multiplayerEventQueue;\n    }\n\n    m_latestPendingRead->DoWork();\n\n    ProcessEvents(m_latestPendingRead->LobbyClient()->Session(), m_lastPendingRead->LobbyClient()->Session(), XblMultiplayerSessionType::LobbySession);\n    ProcessEvents(m_latestPendingRead->GameClient()->Session(), m_lastPendingRead->GameClient()->Session(), XblMultiplayerSessionType::GameSession);\n    ProcessEvents(m_latestPendingRead->MatchClient()->Session(), m_lastPendingRead->MatchClient()->Session(), XblMultiplayerSessionType::MatchSession);\n\n    m_lastPendingRead->deep_copy_if_updated(*m_latestPendingRead);\n    auto eventQueue = m_lastPendingRead->EventQueue();\n\n    if (GetXboxLiveContextMap().size() == 0 && !IsRequestInProgress())\n    {\n        if (!m_subscriptionsLostFired)\n        {\n            // Force client disconnected event to fire for consistent developer behavior.\n            OnMultiplayerSubscriptionsLost();\n        }\n        else\n        {\n            // If the last person just left and no more events left, destroy all objects.\n            Destroy();\n            return eventQueue;\n        }\n    }\n\n    m_latestPendingRead->ClearEventQueue();\n    m_lastPendingRead->ClearEventQueue();\n\n    return eventQueue;\n}\n\nxsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>\nMultiplayerClientManager::GetXboxLiveContextMap()\n{\n    return m_multiplayerLocalUserManager->GetLocalUserMap();\n}\n\nstd::shared_ptr<XblContext>\nMultiplayerClientManager::GetPrimaryContext()\n{\n    return m_multiplayerLocalUserManager->GetPrimaryContext();\n}\n\nvoid\nMultiplayerClientManager::OnMultiplayerConnectionIdChanged()\n{\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    auto lobbyClient = m_latestPendingRead->LobbyClient();\n    auto lobbySession = lobbyClient->Session();\n    XblMultiplayerSessionReadLockGuard lobbyClientSessionSafe(lobbySession);\n    if (lobbySession && lobbyClientSessionSafe.CurrentUser() && lobbyClientSessionSafe.CurrentUser()->Status == XblMultiplayerSessionMemberStatus::Active)\n    {\n        MultiplayerSessionMember::Get(lobbyClientSessionSafe.CurrentUser())->SetStatus(lobbyClientSessionSafe.CurrentUser()->Status);\n        auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n        lobbyClient->AddToPendingQueue(pendingRequest);\n    }\n\n    auto gameClient = m_latestPendingRead->GameClient();\n    auto gameSession = gameClient->Session();\n    XblMultiplayerSessionReadLockGuard gameClientSessionSafe(gameSession);\n    if (gameSession && gameClientSessionSafe.CurrentUser() && gameClientSessionSafe.CurrentUser()->Status == XblMultiplayerSessionMemberStatus::Active)\n    {\n        MultiplayerSessionMember::Get(gameClientSessionSafe.CurrentUser())->SetStatus(gameClientSessionSafe.CurrentUser()->Status);\n        auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n        gameClient->AddToPendingQueue(pendingRequest);\n    }\n}\n\nvoid MultiplayerClientManager::OnMultiplayerSubscriptionsLost()\n{\n    HRESULT hr = m_queue.RunWork([weakThis = std::weak_ptr<MultiplayerClientManager>{ shared_from_this() }]\n    {\n        auto pThis{ weakThis.lock() };\n        if (pThis)\n        {\n            std::lock_guard<std::mutex> guard(pThis->m_clientRequestLock);\n\n            bool expected = false;\n            if (pThis->m_subscriptionsLostFired.compare_exchange_strong(expected, true))\n            {\n                // Fired when the title's connection to MPSD using the real-time activity service is lost. \n                // When this event occurs, the title should shut down the multiplayer.\n\n                auto lobbyClient = pThis->LobbyClient();\n                if (lobbyClient != nullptr)\n                {\n                    lobbyClient->RemoveAllLocalUsers();\n                }\n                pThis->AddToLatestPendingReadEventQueue(XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService, XblMultiplayerSessionType::LobbySession);\n            }\n        }\n    });\n\n    if (FAILED(hr))\n    {\n        LOGS_INFO << __FUNCTION__ << \": RunWork failed with hr=\" << hr;\n    }\n}\n\nvoid\nMultiplayerClientManager::OnResyncMessageReceived()\n{\n    // Upon receiving RTA resync message, re-fetch all multiplayer sessions.\n    // Note: You could get multiple re-sync messages. It's recommended that you only fetch once every 30 secs.\n    if (m_latestPendingRead != nullptr)\n    {\n        m_latestPendingRead->LobbyClient()->SessionWriter()->OnResyncMessageReceived();\n        m_latestPendingRead->GameClient()->SessionWriter()->OnResyncMessageReceived();\n    }\n}\n\nvoid\nMultiplayerClientManager::OnSessionChanged(\n    _In_ XblMultiplayerSessionChangeEventArgs args\n    )\n{\n    std::lock_guard<std::mutex> guard(m_synchronizeWriteWithTapLock);\n\n    if (m_latestPendingRead != nullptr)\n    {\n        if (m_latestPendingRead->IsMatch(args.SessionReference))\n        {\n            m_latestPendingRead->MatchClient()->OnSessionChanged(args);\n        }\n        \n        if (m_latestPendingRead->IsLobby(args.SessionReference))\n        {\n            m_latestPendingRead->LobbyClient()->SessionWriter()->OnSessionChanged(args);\n        }\n        else if (m_latestPendingRead->IsGame(args.SessionReference))\n        {\n            m_latestPendingRead->GameClient()->SessionWriter()->OnSessionChanged(args);\n        }\n    }\n}\n\nconst MultiplayerEventQueue&\nMultiplayerClientManager::EventQueue() const\n{\n    std::lock_guard<std::mutex> guard(m_clientRequestLock);\n    return m_multiplayerEventQueue;\n}\n\nvoid\nMultiplayerClientManager::ClearEventQueue()\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    m_multiplayerEventQueue.Clear();\n}\n\nvoid \nMultiplayerClientManager::AddToLatestPendingReadEventQueue(\n    _In_ XblMultiplayerEventType eventType,\n    _In_ XblMultiplayerSessionType sessionType,\n    _In_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs,\n    _In_opt_ Result<void> error,\n    _In_opt_ context_t context\n)\n{\n    // Note: This function does not require a lock. Caller already has a m_clientRequestLock TODO is this actually true?\n    if (m_latestPendingRead != nullptr)\n    {\n        m_latestPendingRead->AddEvent(eventType, eventArgs, sessionType, error, context);\n    }\n}\n\nXblMultiplayerSessionType\nMultiplayerClientManager::GetSessionType(\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    XblMultiplayerSessionType sessionType = XblMultiplayerSessionType::Unknown;\n    auto latestPendingRead = LatestPendingRead();\n    if (latestPendingRead != nullptr)\n    {\n        if (latestPendingRead->IsLobby(session->SessionReference()))\n        {\n            sessionType = XblMultiplayerSessionType::LobbySession;\n        }\n        else if (latestPendingRead->IsGame(session->SessionReference()))\n        {\n            sessionType = XblMultiplayerSessionType::GameSession;\n        }\n    }\n\n    return sessionType;\n}\n\nvoid\nMultiplayerClientManager::ProcessEvents(\n    _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n    _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    if (oldSession == nullptr || currentSession == nullptr || oldSession->SessionInfo().ChangeNumber == currentSession->SessionInfo().ChangeNumber)\n    {\n        return;\n    }\n\n    xbl_result<XblMultiplayerSessionChangeTypes> diff = currentSession->XblMultiplayerSession::CompareMultiplayerSessions(oldSession);\n    if (!diff.err() && diff.payload() == XblMultiplayerSessionChangeTypes::None)\n    {\n        return;\n    }\n\n    XblMultiplayerSessionChangeTypes diffType = diff.payload();\n\n    if (sessionType != XblMultiplayerSessionType::MatchSession)\n    {\n        if (MultiplayerManagerUtils::IsMultiplayerSessionChangeType(diffType, XblMultiplayerSessionChangeTypes::HostDeviceTokenChange))\n        {\n            HandleHostChanged(currentSession, sessionType);\n        }\n\n        if (MultiplayerManagerUtils::IsMultiplayerSessionChangeType(diffType, XblMultiplayerSessionChangeTypes::MemberListChange))\n        {\n            HandleMemberListChanged(currentSession, oldSession, sessionType);\n        }\n\n        if (MultiplayerManagerUtils::IsMultiplayerSessionChangeType(diffType, XblMultiplayerSessionChangeTypes::CustomPropertyChange))\n        {\n            HandleSessionPropertiesChanged(currentSession, oldSession, sessionType);\n        }\n\n        if (MultiplayerManagerUtils::IsMultiplayerSessionChangeType(diffType, XblMultiplayerSessionChangeTypes::MemberCustomPropertyChange))\n        {\n            HandleMemberPropertiesChanged(currentSession, oldSession, sessionType);\n        }\n    }\n    \n    if (sessionType != XblMultiplayerSessionType::GameSession)\n    {\n        // Don't need to process these for game. The match will take care of handling these events.\n        if (MultiplayerManagerUtils::IsMultiplayerSessionChangeType(diffType, XblMultiplayerSessionChangeTypes::MatchmakingStatusChange)\n            && currentSession->MatchmakingServer())\n        {\n            m_latestPendingRead->MatchClient()->HandleMatchStatusChanged(currentSession);\n        }\n    }\n}\n\nvoid\nMultiplayerClientManager::HandleMemberListChanged(\n    _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n    _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    xsapi_internal_map<uint64_t, const XblMultiplayerSessionMember*> currentSessionMembers;\n    xsapi_internal_map<uint64_t, const XblMultiplayerSessionMember*> oldSessionMembers;\n\n    XblMultiplayerSessionReadLockGuard currentSessionSafe(currentSession);\n    for (const auto& currentSessionMember : currentSessionSafe.Members())\n    {\n        currentSessionMembers[currentSessionMember.Xuid] = &currentSessionMember;\n    }\n\n    XblMultiplayerSessionReadLockGuard oldSessionSafe(oldSession);\n    for (const auto& oldSessionMember : oldSessionSafe.Members())\n    {\n        oldSessionMembers[oldSessionMember.Xuid] = &oldSessionMember;\n    }\n\n    bool haveMembersJoined = false;\n    bool haveMembersLeft = false;\n\n    // See if any new members joined\n    xsapi_internal_vector<const XblMultiplayerSessionMember*> membersJoined;\n    for (const auto& currentSessionMember : currentSessionSafe.Members())\n    {\n        if (oldSessionMembers.find(currentSessionMember.Xuid) == oldSessionMembers.end())\n        {\n            haveMembersJoined = true;\n            membersJoined.push_back(&currentSessionMember);\n        }\n    }\n\n    // See if any members left\n    xsapi_internal_vector<const XblMultiplayerSessionMember*> membersLeft;\n    for (const auto& oldSessionMember : oldSessionSafe.Members())\n    {\n        if (currentSessionMembers.find(oldSessionMember.Xuid) == currentSessionMembers.end())\n        {\n            haveMembersLeft = true;\n            membersLeft.push_back(&oldSessionMember);\n        }\n    }\n\n    if (haveMembersJoined || haveMembersLeft)\n    {\n        auto latestPendingRead = LatestPendingRead();\n        if (latestPendingRead == nullptr)\n        {\n            return;\n        }\n\n        if (haveMembersJoined)\n        {\n            xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> gameMembers;\n            for (auto member : membersJoined)\n            {\n                gameMembers.push_back(latestPendingRead->ConvertToGameMember(member));\n            }\n\n            std::shared_ptr<MemberJoinedEventArgs> memberJoinedEventArgs = MakeShared<MemberJoinedEventArgs>(gameMembers);\n\n            AddToLatestPendingReadEventQueue(\n                XblMultiplayerEventType::MemberJoined,\n                sessionType,\n                memberJoinedEventArgs\n            );\n        }\n\n        if (haveMembersLeft)\n        {\n            xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> gameMembers;\n            for (const auto& member : membersLeft)\n            {\n                gameMembers.push_back(latestPendingRead->ConvertToGameMember(member));\n            }\n\n            std::shared_ptr<MemberLeftEventArgs> memberLeftEventArgs = MakeShared<MemberLeftEventArgs>(\n                gameMembers\n                );\n\n            AddToLatestPendingReadEventQueue(\n                XblMultiplayerEventType::MemberLeft,\n                sessionType,\n                memberLeftEventArgs\n            );\n        }\n    }\n}\n\nvoid\nMultiplayerClientManager::HandleMemberPropertiesChanged(\n    _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n    _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    xsapi_internal_map<uint64_t, const XblMultiplayerSessionMember*> oldSessionMembers;\n    XblMultiplayerSessionReadLockGuard oldSessionSafe(oldSession);\n    for (const auto& oldSessionMember : oldSessionSafe.Members())\n    {\n        oldSessionMembers[oldSessionMember.Xuid] = &oldSessionMember;\n    }\n\n    // See if properties changed and add them to the queue.\n    xsapi_internal_vector<const XblMultiplayerSessionMember*> memberPropertiesChanged;\n    XblMultiplayerSessionReadLockGuard currentSessionSafe(currentSession);\n    for (const auto& currentSessionMember : currentSessionSafe.Members())\n    {\n        if (oldSessionMembers.find(currentSessionMember.Xuid) != oldSessionMembers.end())\n        {\n            auto oldSessionMember = oldSessionMembers[currentSessionMember.Xuid];\n            if (utils::str_icmp(currentSessionMember.CustomPropertiesJson, oldSessionMember->CustomPropertiesJson) != 0)\n            {\n                memberPropertiesChanged.push_back(&currentSessionMember);\n            }\n        }\n    }\n\n    if (memberPropertiesChanged.size() > 0)\n    {\n        xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> gameMembers;\n        const auto& localUsersMap = m_multiplayerLocalUserManager->GetLocalUserMap();\n        for (auto member : memberPropertiesChanged)\n        {\n            auto iter = localUsersMap.find(member->Xuid);\n            if (iter != localUsersMap.end())\n            {\n                // Don't trigger member property changed events for local users.\n                continue;\n            }\n\n            auto latestPendingRead = LatestPendingRead();\n            if (latestPendingRead == nullptr)\n            {\n                continue;\n            }\n            std::shared_ptr<MemberPropertyChangedEventArgs> memberPropertiesChangedArgs = MakeShared<MemberPropertyChangedEventArgs>(\n                latestPendingRead->ConvertToGameMember(member),\n                member->CustomPropertiesJson\n                );\n\n            AddToLatestPendingReadEventQueue(\n                XblMultiplayerEventType::MemberPropertyChanged,\n                sessionType,\n                memberPropertiesChangedArgs\n            );\n        }\n    }\n}\n\nvoid\nMultiplayerClientManager::HandleSessionPropertiesChanged(\n    _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n    _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    if (sessionType == XblMultiplayerSessionType::LobbySession &&\n        m_multiplayerLocalUserManager->IsLocalUserGameState(MultiplayerLocalUserGameState::PendingJoin))\n    {\n        // Don't join the game if matchmaking is in progress.\n        auto latestPendingRead = LatestPendingRead();\n        if (latestPendingRead != nullptr && latestPendingRead->MatchClient()->MatchStatus() == XblMultiplayerMatchStatus::None)\n        {\n            // If state is completed, or transfer handle was removed.\n            if (latestPendingRead->LobbyClient()->IsTransferHandleState(\"completed\") ||\n                (XblMultiplayerSession::HasSessionPropertyChanged(currentSession, oldSession, MultiplayerLobbyClient_TransferHandlePropertyName) &&\n                latestPendingRead->LobbyClient()->GetTransferHandle().empty())\n                )\n            {\n                m_multiplayerLocalUserManager->ChangeAllLocalUserGameState(MultiplayerLocalUserGameState::Join);\n\n                // Join the game session using the handleId.\n                latestPendingRead->GameClient()->JoinGameFromLobbyHelper(nullptr);\n            }\n        }\n    }\n\n    // Don't trigger property changed event if the transfer handle property changes.\n    if (XblMultiplayerSession::HasSessionPropertyChanged(currentSession, oldSession, MultiplayerLobbyClient_TransferHandlePropertyName) ||\n        XblMultiplayerSession::HasSessionPropertyChanged(currentSession, oldSession, MultiplayerLobbyClient_JoinabilityPropertyName))\n    {\n        return;\n    }\n\n    XblMultiplayerSessionReadLockGuard currentSessionSafe(currentSession);\n    auto gamePropertiesChangedArgs = MakeShared<SessionPropertyChangedEventArgs>(\n        currentSessionSafe.SessionProperties().SessionCustomPropertiesJson\n    );\n\n    AddToLatestPendingReadEventQueue(\n        XblMultiplayerEventType::SessionPropertyChanged,\n        sessionType,\n        gamePropertiesChangedArgs\n    );\n}\n\nvoid\nMultiplayerClientManager::HandleHostChanged(\n    _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    /// A host may have left, and there may be no new host.\n    std::shared_ptr<MultiplayerMember> hostMember = nullptr;\n    auto host = XblMultiplayerSession::HostMember(currentSession);\n    if (host != nullptr)\n    {\n        auto latestPendingRead = LatestPendingRead();\n        if (latestPendingRead != nullptr)\n        {\n            hostMember = latestPendingRead->ConvertToGameMember(host);\n        }\n    }\n\n    std::shared_ptr<HostChangedEventArgs> hostChangedEventArgs = MakeShared<HostChangedEventArgs>(\n        hostMember\n        );\n\n    AddToLatestPendingReadEventQueue(\n        XblMultiplayerEventType::HostChanged,\n        sessionType,\n        hostChangedEventArgs\n    );\n}\n\nstd::shared_ptr<MultiplayerMatchClient>\nMultiplayerClientManager::MatchClient()\n{\n    auto latestPendingRead = LatestPendingRead();\n    if (latestPendingRead == nullptr)\n    {\n        return nullptr;\n    }\n\n    return latestPendingRead->MatchClient();\n}\n\nHRESULT\nMultiplayerClientManager::FindMatch(\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ JsonValue& attributes,\n    _In_ const std::chrono::seconds& timeout\n)\n{\n    auto latestPendingRead = LatestPendingRead();\n    RETURN_HR_IF_LOG_DEBUG(latestPendingRead == nullptr || latestPendingRead->LobbyClient()->Session() == nullptr, E_UNEXPECTED, \"No local user added. Call add_local_user() first.\");\n    return latestPendingRead->FindMatch(hopperName, attributes, timeout);\n}\n\nvoid\nMultiplayerClientManager::SetAutoFillMembersDuringMatchmaking(\n    _In_ bool autoFillMembers\n    )\n{\n    m_autoFillMembers = autoFillMembers;\n    auto latestPendingRead = LatestPendingRead();\n    if (latestPendingRead != nullptr)\n    {\n        latestPendingRead->SetAutoFillMembersDuringMatchmaking(autoFillMembers);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_client_pending_reader.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services::multiplayer;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nvoid MultiplayerClientPendingReader::deep_copy_if_updated(\n    _In_ const MultiplayerClientPendingReader& other\n    )\n{\n    std::lock_guard<std::mutex> lock(other.m_clientRequestLock);\n\n    m_multiplayerEventQueue = other.m_multiplayerEventQueue;\n    if (other.m_lobbyClient == nullptr)\n    {\n        m_lobbyClient = nullptr;\n    }\n    else\n    {\n        m_lobbyClient->deep_copy_if_updated(*other.m_lobbyClient);\n    }\n\n    if (other.m_gameClient == nullptr)\n    {\n        m_gameClient = nullptr;\n    }\n    else\n    {\n        m_gameClient->deep_copy_if_updated(*other.m_gameClient);\n    }\n\n    if (other.m_matchClient == nullptr)\n    {\n        m_matchClient = nullptr;\n    }\n    else\n    {\n        m_matchClient->deep_copy_if_updated(*other.m_matchClient);\n    }\n}\n\nMultiplayerClientPendingReader::MultiplayerClientPendingReader(const TaskQueue& queue) :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_autoFillMembers(false)\n{\n    m_multiplayerLocalUserManager = MakeShared<MultiplayerLocalUserManager>();\n    m_lobbyClient = MakeShared<MultiplayerLobbyClient>(m_queue);\n    m_gameClient = MakeShared<MultiplayerGameClient>(m_queue);\n    m_matchClient = MakeShared<manager::MultiplayerMatchClient>(m_queue, m_multiplayerLocalUserManager);\n}\n\nMultiplayerClientPendingReader::~MultiplayerClientPendingReader()\n{\n    m_lobbyClient.reset();\n    m_gameClient.reset();\n    m_matchClient.reset();\n    m_multiplayerLocalUserManager.reset();\n}\n\nMultiplayerClientPendingReader::MultiplayerClientPendingReader(\n    _In_ const TaskQueue& queue,\n    _In_ const xsapi_internal_string& lobbySessionTemplateName,\n    _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n    ) :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_autoFillMembers(false),\n    m_multiplayerLocalUserManager(localUserManager)\n{\n    m_lobbyClient = MakeShared<MultiplayerLobbyClient>(m_queue, lobbySessionTemplateName, m_multiplayerLocalUserManager);\n    m_gameClient = MakeShared<MultiplayerGameClient>(m_queue, m_multiplayerLocalUserManager);\n    m_matchClient = MakeShared<manager::MultiplayerMatchClient>(m_queue, m_multiplayerLocalUserManager);\n    m_lobbyClient->Initialize();\n    m_gameClient->Initialize();\n}\n\nbool\nMultiplayerClientPendingReader::IsUpdateAvailable(\n    _In_ const MultiplayerClientPendingReader& other\n    )\n{\n    std::lock_guard<std::mutex> lock(other.m_clientRequestLock);\n\n    if (other.m_lobbyClient->IsPendingLobbyChanges() ||\n        other.m_gameClient->IsPendingGameChanges())\n    {\n        return true;\n    }\n\n    auto lobbySession = m_lobbyClient->Session();\n    auto otherLobbySession = other.m_lobbyClient->Session();\n    auto gameSession = m_gameClient->Session();\n    auto otherGameSession = other.m_gameClient->Session();\n    if ( !MultiplayerManagerUtils::CompareSessions(lobbySession, otherLobbySession) ||\n         !MultiplayerManagerUtils::CompareSessions(gameSession, otherGameSession) ||\n         !MultiplayerManagerUtils::CompareSessions(m_matchClient->Session(), other.m_matchClient->Session()) ||\n         m_lobbyClient->EventQueue().Size() != other.m_lobbyClient->EventQueue().Size() ||\n         m_gameClient->EventQueue().Size() != other.m_gameClient->EventQueue().Size() ||\n         m_matchClient->EventQueue().Size() != other.m_matchClient->EventQueue().Size() ||\n         m_multiplayerEventQueue.Size() != other.m_multiplayerEventQueue.Size())\n    {\n        return true;\n    }\n\n    return false;\n}\n\nstd::shared_ptr<MultiplayerLobbyClient>\nMultiplayerClientPendingReader::LobbyClient()\n{\n    return m_lobbyClient;\n}\n\nstd::shared_ptr<MultiplayerGameClient>\nMultiplayerClientPendingReader::GameClient()\n{\n    return m_gameClient;\n}\n\nstd::shared_ptr<MultiplayerMatchClient>\nMultiplayerClientPendingReader::MatchClient()\n{\n    return m_matchClient;\n}\n\nvoid \nMultiplayerClientPendingReader::UpdateSession(\n    _In_ XblMultiplayerSessionReference sessionRef,\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n\n    if (IsLobby(sessionRef))\n    {\n        m_lobbyClient->UpdateSession(session);\n    }\n    else if(IsGame(sessionRef))\n    {\n        m_gameClient->UpdateSession(session);\n    }\n}\n\nstd::shared_ptr<XblMultiplayerSession>\nMultiplayerClientPendingReader::GetSession(\n    _In_ XblMultiplayerSessionReference sessionRef\n    )\n{\n    if (IsLobby(sessionRef))\n    {\n        return m_lobbyClient->Session();\n    }\n    else if (IsGame(sessionRef))\n    {\n        return m_gameClient->Session();\n    }\n\n    return nullptr;\n}\n\nbool\nMultiplayerClientPendingReader::IsLobby(\n    _In_ XblMultiplayerSessionReference sessionRef\n    )\n{\n    if (!XblMultiplayerSessionReferenceIsValid(&sessionRef) || m_lobbyClient == nullptr || m_lobbyClient->Session() == nullptr)\n    {\n        return false;\n    }\n\n    return sessionRef == m_lobbyClient->Session()->SessionReference();\n}\n\nbool\nMultiplayerClientPendingReader::IsGame(\n    _In_ XblMultiplayerSessionReference sessionRef\n    )\n{\n    if (!XblMultiplayerSessionReferenceIsValid(&sessionRef) || m_gameClient == nullptr || m_gameClient->Session() == nullptr)\n    {\n        return false;\n    }\n\n    return sessionRef == m_gameClient->Session()->SessionReference();\n}\n\nbool\nMultiplayerClientPendingReader::IsMatch(\n    _In_ XblMultiplayerSessionReference sessionRef\n)\n{\n    if (!XblMultiplayerSessionReferenceIsValid(&sessionRef) || m_matchClient == nullptr || m_matchClient->Session() == nullptr)\n    {\n        return false;\n    }\n\n    return sessionRef == m_matchClient->Session()->SessionReference();\n}\n\nconst MultiplayerEventQueue&\nMultiplayerClientPendingReader::EventQueue() const\n{\n    return m_multiplayerEventQueue;\n}\n\nvoid\nMultiplayerClientPendingReader::ClearEventQueue()\n{\n    m_multiplayerEventQueue.Clear();\n}\n\nvoid MultiplayerClientPendingReader::AddEvent(\n    _In_ XblMultiplayerEventType eventType,\n    _In_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs,\n    _In_ XblMultiplayerSessionType sessionType,\n    _In_ Result<void> error,\n    _In_opt_ context_t context\n)\n{\n    // TODO: add logging for error message\n    m_multiplayerEventQueue.AddEvent(eventType, sessionType, eventArgs, error, context);\n}\n\nvoid\nMultiplayerClientPendingReader::AddEvent(\n    _In_ const XblMultiplayerEvent& multiplayerEvent\n    )\n{\n    m_multiplayerEventQueue.AddEvent(multiplayerEvent);\n}\n\nvoid\nMultiplayerClientPendingReader::AddEvents(\n    _In_ const MultiplayerEventQueue& multiplayerEventQueue\n    )\n{\n    if (multiplayerEventQueue.Size() > 0)\n    {\n        for (const auto& multiplayerEvent : multiplayerEventQueue)\n        {\n            m_multiplayerEventQueue.AddEvent(multiplayerEvent);\n        }\n    }\n}\n\nvoid\nMultiplayerClientPendingReader::DoWork()\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n\n    if (primaryContext == nullptr && \n        m_lobbyClient->EventQueue().Size() == 0 && \n        m_gameClient->EventQueue().Size() == 0 &&\n        m_matchClient->EventQueue().Size() == 0 &&\n        m_multiplayerEventQueue.Size() == 0)\n    {\n        // After the primaryContext has been deleted, the lobbyClient could have userRemoved event in the queue.\n        // The pending reader will also fire a client_disconnected_from_multiplayer_service event.\n        return;\n    }\n\n    auto lobbySession = m_lobbyClient->Session();\n    auto gameSession = m_gameClient->Session();\n    m_lobbyClient->UpdateObjects(lobbySession, gameSession);\n    m_gameClient->UpdateObjects(gameSession, lobbySession);\n\n    auto lobbyClientEventQueue = m_lobbyClient->DoWork();\n    AddEvents(lobbyClientEventQueue);\n\n    auto gameClientEventQueue = m_gameClient->DoWork();\n    AddEvents(gameClientEventQueue);\n\n    ProcessMatchEvents();\n}\n\nHRESULT\nMultiplayerClientPendingReader::SetJoinability(\n    _In_ XblMultiplayerJoinability value,\n    _In_opt_ context_t context\n    )\n{\n    return m_lobbyClient->SetJoinability(value, context);\n}\n\nHRESULT\nMultiplayerClientPendingReader::SetProperties(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetSessionProperties(name, valueJson, context);\n    AddToPendingQueue(sessionRef, pendingRequest);\n    return S_OK;\n}\n\nHRESULT\nMultiplayerClientPendingReader::SetSynchronizedHost(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ const xsapi_internal_string& hostDeviceToken,\n    _In_opt_ context_t context\n    )\n{\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetSynchronizedHostDeviceToken(hostDeviceToken, context);\n    AddToPendingQueue(sessionRef, pendingRequest);\n    return S_OK;\n}\n\nHRESULT\nMultiplayerClientPendingReader::SetSynchronizedProperties(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetSynchronizedSessionProperties(name, valueJson, context);\n    AddToPendingQueue(sessionRef, pendingRequest);\n    return S_OK;\n}\n\nvoid\nMultiplayerClientPendingReader::AddToPendingQueue(\n    _In_ const XblMultiplayerSessionReference& sessionRef,\n    _In_ std::shared_ptr<MultiplayerClientPendingRequest> pendingRequest\n    )\n{\n    if (sessionRef.SessionName[0] == 0 || IsLobby(sessionRef))\n    {\n        m_lobbyClient->AddToPendingQueue(pendingRequest);\n    }\n    else if (IsGame(sessionRef))\n    {\n        m_gameClient->AddToPendingQueue(pendingRequest);\n    }\n}\n\nbool\nMultiplayerClientPendingReader::IsLocal(\n    _In_ uint64_t xuid,\n    _In_ const xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>& xboxLiveContextMap\n    )\n{\n    for(auto& xboxLiveContext : xboxLiveContextMap)\n    {\n        std::shared_ptr<MultiplayerLocalUser> localUser =  xboxLiveContext.second;\n        if (localUser != nullptr && xuid == localUser->Xuid())\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstd::shared_ptr<MultiplayerMember>\nMultiplayerClientPendingReader::ConvertToGameMember(\n    _In_ const XblMultiplayerSessionMember* member\n    )\n{\n    return MultiplayerMember::CreateFromSessionMember(\n        member,\n        m_lobbyClient->Session(),\n        m_gameClient->Session(),\n        m_multiplayerLocalUserManager->GetLocalUserMap()\n        );\n}\n\nvoid\nMultiplayerClientPendingReader::ProcessMatchEvents()\n{\n    if (m_matchClient == nullptr || m_matchClient->MatchStatus() == XblMultiplayerMatchStatus::None)\n    {\n        return;\n    }\n\n    auto matchEventQueue = m_matchClient->DoWork();\n    auto matchSession = m_matchClient->Session();\n\n    if (matchEventQueue.Size() > 0)\n    {\n        for (const auto& multiplayerEvent : matchEventQueue)\n        {\n            AddEvent(multiplayerEvent);\n\n            if (multiplayerEvent.EventType == XblMultiplayerEventType::FindMatchCompleted)\n            {\n                auto matchStatus = m_matchClient->MatchStatus();\n                if (FAILED(multiplayerEvent.Result))\n                {\n                    if (!XblMultiplayerSession::DoSessionsMatch(m_gameClient->Session(), matchSession) &&\n                        !XblMultiplayerSession::DoSessionsMatch(m_lobbyClient->Session(), matchSession))\n                    {\n                        // TODO should be able to control the async queue here\n                        m_lobbyClient->SessionWriter()->LeaveRemoteSession(matchSession, nullptr);\n                    }\n                }\n\n                if (matchStatus == XblMultiplayerMatchStatus::Resubmitting)\n                {\n                    auto lobbySessionCopy = MakeShared<XblMultiplayerSession>(*m_lobbyClient->Session());\n                    m_matchClient->ResubmitMatchmaking(lobbySessionCopy);\n                    break;\n                }\n\n                if (matchStatus == XblMultiplayerMatchStatus::Completed)\n                {\n                    m_gameClient->UpdateGameSession(matchSession);\n                    m_gameClient->UpdateObjects(matchSession, m_lobbyClient->Session());\n                    m_lobbyClient->AdvertiseGameSession();\n                }\n\n                XblMultiplayerSessionReadLockGuard matchSessionSafe(matchSession);\n                if (m_autoFillMembers && matchSession != nullptr &&\n                    matchSessionSafe.Members().size() < matchSessionSafe.SessionConstants().MaxMembersInSession &&\n                    (matchStatus == XblMultiplayerMatchStatus::Completed || matchStatus == XblMultiplayerMatchStatus::Expired))\n                {\n                    // Continue looking for more players\n                    m_matchClient->SetMatchStatus(XblMultiplayerMatchStatus::None);\n                    m_matchClient->FindMatch(matchSession, true);\n                    break;\n                }\n\n                m_matchClient->SetMatchStatus(XblMultiplayerMatchStatus::None);\n                m_matchClient->UpdateSession(nullptr);\n                break;\n            }\n        }\n    }\n}\n\nHRESULT\nMultiplayerClientPendingReader::FindMatch(\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ JsonValue& attributes,\n    _In_ const std::chrono::seconds& timeout\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(!m_autoFillMembers && m_gameClient->Session() != nullptr, E_UNEXPECTED, \"A game already exists. Call leave_game() before you can start matchmaking.\");\n    RETURN_HR_IF_LOG_DEBUG(!m_autoFillMembers && !m_lobbyClient->GetTransferHandle().empty(), E_UNEXPECTED, \"A game already exists for your Lobby. Call leave_game() for all Lobby members before you can start matchmaking.\");\n\n    if (m_autoFillMembers && m_gameClient->Session() != nullptr)\n    {\n        return m_matchClient->FindMatch(hopperName, attributes, timeout, m_gameClient->Session(), true);\n    }\n\n    return m_matchClient->FindMatch(hopperName, attributes, timeout, m_lobbyClient->Session(), false);\n}\n\nvoid\nMultiplayerClientPendingReader::SetAutoFillMembersDuringMatchmaking(\n    _In_ bool autoFillMembers\n    )\n{\n    m_autoFillMembers = autoFillMembers;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_client_pending_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerClientPendingRequest::MultiplayerClientPendingRequest() :\n    m_context(nullptr),\n    m_requestType(PendingRequestType::NonSynchronizedChanges),\n    m_localUserLobbyState(MultiplayerLocalUserLobbyState::Unknown),\n    m_joinability(XblMultiplayerJoinability::None)\n{\n}\n\nPendingRequestType\nMultiplayerClientPendingRequest::RequestType() const\n{\n    return m_requestType;\n}\n\ncontext_t\nMultiplayerClientPendingRequest::Context()\n{\n    return m_context;\n}\n\nuint32_t\nMultiplayerClientPendingRequest::Identifier() const\n{\n    return m_identifier;\n}\n\n// Local User properties\nstd::shared_ptr<MultiplayerLocalUser>\nMultiplayerClientPendingRequest::LocalUser()\n{\n    return m_localUser;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetLocalUser(\n    _In_ std::shared_ptr<MultiplayerLocalUser> user\n    )\n{\n    m_localUser = user;\n}\n\nMultiplayerLocalUserLobbyState\nMultiplayerClientPendingRequest::LobbyState()\n{\n    return m_localUserLobbyState;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetLobbyState(\n    _In_ MultiplayerLocalUserLobbyState userState\n    )\n{\n    m_localUserLobbyState = userState;\n}\n\nconst xsapi_internal_string&\nMultiplayerClientPendingRequest::LobbyHandleId() const\n{\n    return m_lobbyHandleId;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetLobbyHandleId(_In_ const xsapi_internal_string& handleId)\n{\n    m_lobbyHandleId = handleId;\n}\n\nconst xsapi_internal_string&\nMultiplayerClientPendingRequest::LocalUserSecureDeivceAddress() const\n{\n    return m_localUserSecureDeivceAddress;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetLocalUserConnectionAddress(\n    _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n    _In_ const xsapi_internal_string& connectionAddress,\n    _In_opt_ context_t context\n    )\n{\n    m_context = context;\n    m_localUser = localUser;\n    m_localUserSecureDeivceAddress = utils::format_secure_device_address(connectionAddress);\n}\n\nconst xsapi_internal_map<xsapi_internal_string, JsonDocument>&\nMultiplayerClientPendingRequest::LocalUserProperties() const\n{\n    return m_localUserProperties;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetLocalUserProperties(\n    _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    m_context = context;\n    m_localUser = localUser;\n    JsonUtils::CopyFrom(m_localUserProperties[name], valueJson);\n}\n\n// Session non-synchronized properties\nXblMultiplayerJoinability\nMultiplayerClientPendingRequest::Joinability()\n{\n    return m_joinability;\n}\n\nvoid MultiplayerClientPendingRequest::SetJoinability(\n    _In_ XblMultiplayerJoinability value,\n    _In_opt_ context_t context\n    )\n{\n    m_context = context;\n    m_joinability = value;\n}\n\nconst xsapi_internal_map<xsapi_internal_string, JsonDocument>&\nMultiplayerClientPendingRequest::SessionProperties() const\n{\n    return m_sessionProperties;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetSessionProperties(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    m_context = context;\n    JsonUtils::CopyFrom(m_sessionProperties[name], valueJson);\n}\n\n// Session synchronized properties\nconst xsapi_internal_string&\nMultiplayerClientPendingRequest::SynchronizedHostDeviceToken() const\n{\n    return m_synchronizedHostDeviceToken;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetSynchronizedHostDeviceToken(\n    _In_ const xsapi_internal_string& hostDeviceToken,\n    _In_opt_ context_t context\n    )\n{\n    m_context = context;\n    m_requestType = PendingRequestType::SynchronizedChanges;\n    m_synchronizedHostDeviceToken = hostDeviceToken;\n}\n\nconst xsapi_internal_map<xsapi_internal_string, JsonDocument>&\nMultiplayerClientPendingRequest::SynchronizedSessionProperties() const\n{\n    return m_synchronizedSessionProperties;\n}\n\nvoid\nMultiplayerClientPendingRequest::SetSynchronizedSessionProperties(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    m_context = context;\n    m_requestType = PendingRequestType::SynchronizedChanges;\n    JsonUtils::CopyFrom(m_synchronizedSessionProperties[name], valueJson);\n}\n\nvoid\nMultiplayerClientPendingRequest::AppendPendingChanges(\n    _In_ std::shared_ptr<XblMultiplayerSession> sessionToCommit,\n    _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n    _In_ bool isGameInProgress\n    )\n{\n    // Apply local user properties\n    if (localUser != nullptr && m_localUser != nullptr && localUser->Xuid() == m_localUser->Xuid())\n    {\n        XblMultiplayerSessionReadLockGuard sessionToCommitSafe(sessionToCommit);\n        if (!m_localUserSecureDeivceAddress.empty())\n        {\n            // Assign connection address to the localUser instance as it's used in other places locally.\n            localUser->SetConnectionAddress(m_localUserSecureDeivceAddress);\n            if (sessionToCommitSafe.CurrentUser() != nullptr)\n            {\n                sessionToCommitSafe.CurrentUserInternal()->SetSecureDeviceBaseAddress64(m_localUserSecureDeivceAddress);\n            }\n        }\n\n        if (m_localUserProperties.size() > 0 && sessionToCommitSafe.CurrentUser() != nullptr)\n        {\n            for (const auto& prop : m_localUserProperties)\n            {\n                sessionToCommitSafe.CurrentUserInternal()->SetCustomPropertyJson(prop.first, prop.second);\n            }\n        }\n\n        localUser->SetWriteChangesToService(false);\n    }\n\n    // Apply session non-sync properties\n\n    if (m_joinability != XblMultiplayerJoinability::None)\n    {\n        MultiplayerManagerUtils::SetJoinability(m_joinability, sessionToCommit, isGameInProgress);\n    }\n\n    if (m_sessionProperties.size() > 0)\n    {\n        for (const auto& prop : m_sessionProperties)\n        {\n            sessionToCommit->SetSessionCustomPropertyJson(prop.first, prop.second);\n        }\n    }\n\n    // Apply session sync properties\n\n    if (!m_synchronizedHostDeviceToken.empty())\n    {\n        sessionToCommit->SetHostDeviceToken(m_synchronizedHostDeviceToken.data());\n    }\n\n    if (m_synchronizedSessionProperties.size() > 0)\n    {\n        for (const auto& prop : m_synchronizedSessionProperties)\n        {\n            sessionToCommit->SetSessionCustomPropertyJson(prop.first, prop.second);\n        }\n    }\n}\n\nstd::atomic<uint32_t> MultiplayerClientPendingRequest::s_nextUniqueIdentifier{ 0 };\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_event_args.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::multiplayer::manager;\nusing std::dynamic_pointer_cast;\n\nSTDAPI XblMultiplayerEventArgsXuid(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ uint64_t* xuid\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(argsHandle == nullptr || xuid == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    auto userAddedArgs = dynamic_cast<UserAddedEventArgs*>(argsHandle);\n    auto userRemovedArgs = dynamic_cast<UserRemovedEventArgs*>(argsHandle);\n    auto joinLobbyCompletedArgs = dynamic_cast<JoinLobbyCompletedEventArgs*>(argsHandle);\n\n    if (userAddedArgs != nullptr)\n    {\n        *xuid = userAddedArgs->Xuid;\n    }\n    else if (userRemovedArgs != nullptr)\n    {\n        *xuid = userRemovedArgs->Xuid;\n    }\n    else if (joinLobbyCompletedArgs != nullptr)\n    {\n        *xuid = joinLobbyCompletedArgs->Xuid;\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsMembersCount(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ size_t* memberCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(argsHandle == nullptr || memberCount == nullptr);\n\n    auto memberJoinedArgs = dynamic_cast<MemberJoinedEventArgs*>(argsHandle);\n    auto memberLeftArgs = dynamic_cast<MemberLeftEventArgs*>(argsHandle);\n\n    if (memberJoinedArgs != nullptr)\n    {\n        *memberCount = memberJoinedArgs->Members.size();\n    }\n    else if (memberLeftArgs != nullptr)\n    {\n        *memberCount = memberLeftArgs->Members.size();\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsMembers(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _In_ size_t membersCount,\n    _Out_writes_(membersCount) XblMultiplayerManagerMember* members\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(argsHandle == nullptr || members == nullptr);\n\n    auto memberJoinedArgs = dynamic_cast<MemberJoinedEventArgs*>(argsHandle);\n    auto memberLeftArgs = dynamic_cast<MemberLeftEventArgs*>(argsHandle);\n\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> membersVector;\n    if (memberJoinedArgs != nullptr)\n    {\n        membersVector = memberJoinedArgs->Members;\n    }\n    else if (memberLeftArgs != nullptr)\n    {\n        membersVector = memberLeftArgs->Members;\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n    RETURN_HR_INVALIDARGUMENT_IF(membersCount < membersVector.size());\n\n    for (size_t i = 0; i < membersVector.size(); ++i)\n    {\n        members[i] = membersVector[i]->GetReference();\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsMember(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ XblMultiplayerManagerMember* member\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(argsHandle == nullptr || member == nullptr);\n\n    auto hostChangedArgs = dynamic_cast<HostChangedEventArgs*>(argsHandle);\n    auto memberPropertyChangedArgs = dynamic_cast<MemberPropertyChangedEventArgs*>(argsHandle);\n\n    if (hostChangedArgs != nullptr)\n    {\n        if (hostChangedArgs->HostMember != nullptr)\n        {\n            *member = hostChangedArgs->HostMember->GetReference();\n        }\n        else\n        {\n            return __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);\n        }\n    }\n    else if (memberPropertyChangedArgs != nullptr)\n    {\n        if (memberPropertyChangedArgs->Member != nullptr)\n        {\n            *member = memberPropertyChangedArgs->Member->GetReference();\n        }\n        else\n        {\n            return __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);\n        }\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsPropertiesJson(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ const char** properties\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(argsHandle == nullptr || properties == nullptr);\n\n    auto sessionPropertyChangedArgs = dynamic_cast<SessionPropertyChangedEventArgs*>(argsHandle);\n    auto memberPropertyChangedArgs = dynamic_cast<MemberPropertyChangedEventArgs*>(argsHandle);\n\n    if (sessionPropertyChangedArgs != nullptr)\n    {\n        *properties = sessionPropertyChangedArgs->Properties.data();\n    }\n    else if (memberPropertyChangedArgs != nullptr)\n    {\n        *properties = memberPropertyChangedArgs->Properties.data();\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsFindMatchCompleted(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_opt_ XblMultiplayerMatchStatus* matchStatus,\n    _Out_opt_ XblMultiplayerMeasurementFailure* initializationFailureCause\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(argsHandle);\n    auto args = dynamic_cast<FindMatchCompletedEventArgs*>(argsHandle);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args);\n\n    if (matchStatus != nullptr)\n    {\n        *matchStatus = args->MatchStatus;\n    }\n    if (initializationFailureCause != nullptr)\n    {\n        *initializationFailureCause = args->InitializationFailure;\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsTournamentRegistrationStateChanged(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_opt_ XblTournamentRegistrationState* registrationState,\n    _Out_opt_ XblTournamentRegistrationReason* registrationReason\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(argsHandle);\n    UNREFERENCED_PARAMETER(registrationState);\n    UNREFERENCED_PARAMETER(registrationReason);\n    return E_NOTIMPL;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsTournamentGameSessionReady(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ time_t* startTime\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(argsHandle);\n    UNREFERENCED_PARAMETER(startTime);\n\n    return E_NOTIMPL;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerEventArgsPerformQoSMeasurements(\n    _In_ XblMultiplayerEventArgsHandle argsHandle,\n    _Out_ XblMultiplayerPerformQoSMeasurementsArgs* performQoSMeasurementsArgs\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(argsHandle == nullptr || performQoSMeasurementsArgs == nullptr);\n    auto args = dynamic_cast<PerformQosMeasurementsEventArgs*>(argsHandle);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args);\n\n    performQoSMeasurementsArgs->remoteClientsSize = args->remoteClients.size();\n    performQoSMeasurementsArgs->remoteClients = args->remoteClients.data();\n\n    return S_OK;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_event_queue.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerEventQueue::MultiplayerEventQueue()\n{\n}\n\nMultiplayerEventQueue::MultiplayerEventQueue(const MultiplayerEventQueue& other)\n{\n    {\n        std::lock_guard<std::mutex> lock(other.m_lock);\n        m_events = other.m_events;\n    }\n\n    for (auto& event : m_events)\n    {\n        if (event.ErrorMessage)\n        {\n            event.ErrorMessage = Make(event.ErrorMessage);\n        }\n        if (event.EventArgsHandle)\n        {\n            event.EventArgsHandle->AddRef();\n        }\n    }\n}\n\nMultiplayerEventQueue& MultiplayerEventQueue::operator=(MultiplayerEventQueue other)\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    std::swap(m_events, other.m_events);\n    return *this;\n}\n\nMultiplayerEventQueue::~MultiplayerEventQueue()\n{\n    for (const auto& event : m_events)\n    {\n        if (event.ErrorMessage)\n        {\n            Delete(event.ErrorMessage);\n        }\n        if (event.EventArgsHandle)\n        {\n            event.EventArgsHandle->DecRef();\n        }\n    }\n}\n\nsize_t MultiplayerEventQueue::Size() const\n{\n    return m_events.size();\n}\n\nbool MultiplayerEventQueue::Empty() const\n{\n    return m_events.empty();\n}\n\nvoid MultiplayerEventQueue::Clear()\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    for (auto& e : m_events)\n    {\n        if (e.ErrorMessage)\n        {\n            Delete(e.ErrorMessage);\n        }\n        if (e.EventArgsHandle)\n        {\n            e.EventArgsHandle->DecRef();\n        }\n    }\n    m_events.clear();\n}\n\nxsapi_internal_vector<XblMultiplayerEvent>::const_iterator MultiplayerEventQueue::begin() const\n{\n    return m_events.begin();\n}\n\nxsapi_internal_vector<XblMultiplayerEvent>::const_iterator MultiplayerEventQueue::end() const\n{\n    return m_events.end();\n}\n\nvoid MultiplayerEventQueue::AddEvent(\n    _In_ XblMultiplayerEventType eventType,\n    _In_ XblMultiplayerSessionType sessionType,\n    _In_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs,\n    _In_ Result<void> error,\n    _In_opt_ context_t context\n)\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    XblMultiplayerEvent event{};\n    event.EventType = eventType;\n    event.SessionType = sessionType;\n    if (eventArgs)\n    {\n        eventArgs->AddRef();\n        event.EventArgsHandle = eventArgs.get();\n    }\n    event.Result = error.Hresult();\n    event.ErrorMessage = Make(error.ErrorMessage());\n\n#if XSAPI_WINRT\n    event.Context = reinterpret_cast<void*>(context);\n#else\n    event.Context = context;\n#endif\n\n    m_events.push_back(event);\n}\n\nvoid MultiplayerEventQueue::AddEvent(_In_ const XblMultiplayerEvent& multiplayerEvent)\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    m_events.push_back(multiplayerEvent);\n    auto& addedEvent = m_events.back();\n    if (addedEvent.ErrorMessage)\n    {\n        addedEvent.ErrorMessage = Make(addedEvent.ErrorMessage);\n    }\n    if (addedEvent.EventArgsHandle)\n    {\n        addedEvent.EventArgsHandle->AddRef();\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_game_client.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services::system;\nusing namespace xbox::services::legacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerGameClient::MultiplayerGameClient(\n    const TaskQueue& queue\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_sessionWriter{ MakeShared<MultiplayerSessionWriter>(queue) }\n{\n}\n\nMultiplayerGameClient::MultiplayerGameClient(\n    const TaskQueue& queue,\n    _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_sessionWriter{ MakeShared<MultiplayerSessionWriter>(queue, localUserManager) },\n    m_multiplayerLocalUserManager{ std::move(localUserManager) }\n{\n}\n\nMultiplayerGameClient::~MultiplayerGameClient()\n{\n    m_sessionWriter.reset();\n}\n\nvoid\nMultiplayerGameClient::Initialize()\n{\n    std::weak_ptr<MultiplayerGameClient> weakSessionWriter = shared_from_this();\n    m_sessionWriter->AddMultiplayerSessionUpdatedHandler([weakSessionWriter](_In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession)\n    {\n        std::shared_ptr<MultiplayerGameClient> pThis(weakSessionWriter.lock());\n        if (pThis != nullptr)\n        {\n            pThis->UpdateSession(updatedSession);\n        }\n    });\n}\n\nstd::shared_ptr<MultiplayerLobbyClient>\nMultiplayerGameClient::LobbyClient() const\n{\n    // TODO this should be changed such that nothing here needs to depend on the GlobalState.\n    // For now just try to get the global state and return null (which is handled by callers) if\n    // it that fails.\n    auto state{ GlobalState::Get() };\n    return state ? state->MultiplayerManager()->LobbyClient() : nullptr;\n}\n\nstd::shared_ptr<XblMultiplayerSession>\nMultiplayerGameClient::LobbySession() const\n{\n    auto lobbyClient{ LobbyClient() };\n    return lobbyClient ? lobbyClient->Session() : nullptr;\n}\n\nvoid\nMultiplayerGameClient::SetGameSessionTemplate(\n    _In_ const xsapi_internal_string& sessionTemplateName\n    )\n{\n    m_gameSessionTemplateName = sessionTemplateName;\n}\n\nvoid\nMultiplayerGameClient::deep_copy_if_updated(\n    _In_ const MultiplayerGameClient& other\n    )\n{\n    std::lock_guard<std::mutex> lock(other.m_clientRequestLock);\n\n    if (other.m_sessionWriter->Session() == nullptr)\n    {\n        m_sessionWriter->UpdateSession(nullptr);\n        m_multiplayerGame = nullptr;\n    }\n    else if (other.m_multiplayerGame == nullptr)\n    {\n        m_multiplayerGame = nullptr;\n    }\n    else if (m_sessionWriter->Session() == nullptr ||\n            other.m_sessionWriter->Session()->SessionInfo().ChangeNumber > m_sessionWriter->Session()->SessionInfo().ChangeNumber ||\n            other.m_sessionWriter->Session()->ETag() > m_sessionWriter->Session()->ETag())\n    {\n        m_sessionWriter->UpdateSession(MakeShared<XblMultiplayerSession>(*other.m_sessionWriter->Session()));\n        m_multiplayerGame = MakeShared<MultiplayerGameSession>(*other.m_multiplayerGame);\n    }\n    else if (m_updateNumber != other.m_updateNumber)\n    {\n        m_multiplayerGame = MakeShared<MultiplayerGameSession>(*other.m_multiplayerGame);\n    }\n}\n\nstd::shared_ptr<MultiplayerSessionWriter>\nMultiplayerGameClient::SessionWriter() const\n{\n    return m_sessionWriter;\n}\n\nstd::shared_ptr<MultiplayerGameSession>\nMultiplayerGameClient::Game() const\n{\n    return m_multiplayerGame;\n}\n\nvoid\nMultiplayerGameClient::UpdateGame(\n    _In_ const std::shared_ptr<MultiplayerGameSession>& multiplayerGame\n    )\n{\n    ++m_updateNumber;\n    m_multiplayerGame = multiplayerGame;\n}\n\nstd::shared_ptr<XblMultiplayerSession>\nMultiplayerGameClient::Session() const\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    return m_sessionWriter->Session();\n}\n\nvoid \nMultiplayerGameClient::UpdateSession(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n    )\n{\n    auto cachedSession = Session();\n    if (updatedSession == nullptr || cachedSession == nullptr ||\n        updatedSession->SessionInfo().ChangeNumber > cachedSession->SessionInfo().ChangeNumber ||\n        updatedSession->ETag() != cachedSession->ETag())\n    {\n        UpdateGameSession(updatedSession);\n    }\n}\n\nvoid \nMultiplayerGameClient::UpdateGameSession(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    m_sessionWriter->UpdateSession(updatedSession);\n}\n\nvoid\nMultiplayerGameClient::UpdateObjects(\n    const std::shared_ptr<XblMultiplayerSession>& updatedSession,\n    const std::shared_ptr<XblMultiplayerSession>& lobbySession\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    if (updatedSession == nullptr)\n    {\n        UpdateGame(nullptr);\n    }\n    else\n    {\n        auto multiplayerGame = ConvertToMultiplayerGame(updatedSession, lobbySession);\n        UpdateGame(multiplayerGame);\n    }\n}\n\nstd::shared_ptr<MultiplayerGameSession>\nMultiplayerGameClient::ConvertToMultiplayerGame(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& sessionToConvert,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession\n    )\n{\n    if (sessionToConvert == nullptr)\n    {\n        return nullptr;\n    }\n\n    std::shared_ptr<MultiplayerMember> hostMember = nullptr;\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> gameMembers;\n    XblMultiplayerSessionReadLockGuard sessionToConvertSafe(sessionToConvert);\n    for (const auto& member : sessionToConvertSafe.Members())\n    {\n        auto gameMember = MultiplayerMember::CreateFromSessionMember(\n            &member,\n            lobbySession,\n            sessionToConvert,\n            m_multiplayerLocalUserManager->GetLocalUserMap()\n            );\n        if (member.DeviceToken.Value[0] != 0 && utils::str_icmp(member.DeviceToken.Value, sessionToConvertSafe.SessionProperties().HostDeviceToken.Value) == 0)\n        {\n            hostMember = gameMember;\n        }\n\n        gameMembers.push_back(gameMember);\n    }\n\n    return MakeShared<MultiplayerGameSession>(\n        sessionToConvert,\n        hostMember,\n        gameMembers\n        );\n}\n\nconst MultiplayerEventQueue&\nMultiplayerGameClient::EventQueue()\n{\n    // Don't require a lock as STL is multithread read safe\n    return m_multiplayerEventQueue;\n}\n\nvoid\nMultiplayerGameClient::ClearPendingQueue()\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    while (!m_pendingRequestQueue.empty())\n    {\n        m_pendingRequestQueue.pop();\n    }\n}\n\nvoid\nMultiplayerGameClient::AddToPendingQueue(\n    _In_ std::shared_ptr<MultiplayerClientPendingRequest> pendingRequest\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    m_pendingRequestQueue.push(pendingRequest);\n}\n\nvoid\nMultiplayerGameClient::AddToProcessingQueue(\n    _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue\n    )\n{\n    for (const auto& request : processingQueue)\n    {\n        m_processingQueue.push_back(request);\n    }\n}\n\nvoid\nMultiplayerGameClient::RemoveFromProcessingQueue(\n    _In_ uint32_t identifier\n)\n{\n    for (auto request = m_processingQueue.begin(); request != m_processingQueue.end(); ++request)\n    {\n        if ((*request)->Identifier() == identifier)\n        {\n            m_processingQueue.erase(request);\n            break;\n        }\n    }\n}\n\nxsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>>\nMultiplayerGameClient::GetProcessingQueue()\n{\n    return m_processingQueue;\n}\n\nMultiplayerEventQueue\nMultiplayerGameClient::DoWork()\n{\n    bool expected = false;\n    if (m_pendingCommitInProgress.compare_exchange_strong(expected, true))\n    {\n        if (m_pendingRequestQueue.size() > 0)\n        {\n            xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue;\n            bool applySynchronizedChanges = false;\n            bool doneProcessing = false;\n            do\n            {\n                std::lock_guard<std::mutex> lock(m_clientRequestLock);\n                {\n                    auto pendingRequest = m_pendingRequestQueue.front();\n                    processingQueue.push_back(pendingRequest);\n                    m_pendingRequestQueue.pop();\n\n                    if (m_pendingRequestQueue.size() > 0)\n                    {\n                        if (pendingRequest->RequestType() != m_pendingRequestQueue.front()->RequestType())\n                        {\n                            doneProcessing = true;\n                        }\n                    }\n\n                    if (!applySynchronizedChanges && pendingRequest->RequestType() == PendingRequestType::SynchronizedChanges)\n                    {\n                        applySynchronizedChanges = true;\n                    }\n                }\n\n            } while (!doneProcessing && m_pendingRequestQueue.size() > 0);\n\n            if (processingQueue.size() > 0)\n            {\n                AddToProcessingQueue(processingQueue);\n                std::weak_ptr<MultiplayerGameClient> weakSessionWriter = shared_from_this();\n\n                Callback<Result<MultiplayerEventQueue>> callback = \n                    [weakSessionWriter, processingQueue](Result<MultiplayerEventQueue> result)\n                {\n                    std::shared_ptr<MultiplayerGameClient> pThis(weakSessionWriter.lock());\n                    if (pThis != nullptr)\n                    {\n                        std::lock_guard<std::mutex> lock(pThis->m_clientRequestLock);\n                        {\n                            auto eventQueue = result.Payload();\n                            for (const auto& ev : eventQueue)\n                            {\n                                pThis->m_multiplayerEventQueue.AddEvent(ev);\n                            }\n                        }\n\n                        for (const auto& processingRequest : processingQueue)\n                        {\n                            pThis->RemoveFromProcessingQueue(processingRequest->Identifier());\n                        }\n\n                        pThis->m_pendingCommitInProgress.store(false);\n                    }\n                };\n\n                // TODO we should have a way to configure the queue here\n                if (applySynchronizedChanges)\n                {\n                    m_sessionWriter->CommitPendingSynchronizedChanges(processingQueue, XblMultiplayerSessionType::GameSession, callback);\n                }\n                else\n                {\n                    m_sessionWriter->CommitPendingChanges(processingQueue, XblMultiplayerSessionType::GameSession, false, callback);\n                }\n            }\n            else\n            {\n                m_pendingCommitInProgress.store(false);\n            }\n        }\n        else\n        {\n            m_pendingCommitInProgress.store(false);\n        }\n    }\n\n    MultiplayerEventQueue eventQueue;\n    {\n        std::lock_guard<std::mutex> lock(m_clientRequestLock);\n        eventQueue = m_multiplayerEventQueue;\n        m_multiplayerEventQueue.Clear();\n    }\n\n    return eventQueue;\n}\n\nbool\nMultiplayerGameClient::IsPendingGameChanges()\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    if (m_pendingRequestQueue.size() > 0)\n    {\n        return true;\n    }\n\n    if (m_sessionWriter != nullptr)\n    {\n        auto latestSession = m_sessionWriter->Session();\n        if (latestSession != nullptr &&\n            m_multiplayerGame != nullptr &&\n            latestSession->SessionInfo().ChangeNumber != m_multiplayerGame->ChangeNumber())\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool\nMultiplayerGameClient::IsRequestInProgress()\n{\n    return m_pendingRequestQueue.size() > 0 || m_processingQueue.size() > 0 || m_multiplayerEventQueue.Size() > 0;\n}\n\nvoid MultiplayerGameClient::SetLocalMemberPropertiesToRemoteSession(\n    _In_ const std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerLocalUser>& localUser,\n    _In_ const Map<String, JsonDocument>& propertiesToWrite,\n    _In_ const String& localUserSecureDeviceAddress\n) noexcept\n{\n    if (Session() == nullptr || localUser == nullptr)\n    {\n        return;\n    }\n\n    // This operation will wait until any pending commits complete, set the provided custom properties for the local user,\n    // and then write the game session.\n    struct SetPropertiesOperation : public std::enable_shared_from_this<SetPropertiesOperation>\n    {\n        SetPropertiesOperation(\n            std::shared_ptr<MultiplayerGameClient> gameClient,\n            std::shared_ptr<MultiplayerLocalUser> localUser,\n            const Map<String, JsonDocument>& propertiesToWrite,\n            String localUserSecureDeviceAddressToWrite\n        ) noexcept\n            : m_gameClient{ std::move(gameClient) },\n            m_localUser{ std::move(localUser) },\n            m_secureDeviceAddressToWrite{std::move(localUserSecureDeviceAddressToWrite)}\n        {\n            for (const auto& prop : propertiesToWrite)\n            {\n                m_propertiesToWrite[prop.first] = JsonDocument{};\n                JsonUtils::CopyFrom(m_propertiesToWrite[prop.first], prop.second);\n            }\n        }\n\n        void Run() noexcept\n        {\n            bool commitInProgress = false;\n            if (!m_gameClient->m_pendingCommitInProgress.compare_exchange_weak(commitInProgress, true))\n            {\n                // Already a commit in progress. Reschedule operation.\n                // Seems like we could add a little sleep here, but keeping behavior consistent since 1806 implementation\n                m_gameClient->m_queue.RunWork([op{ shared_from_this() }]\n                    {\n                        op->Run();\n                    });\n            }\n            else if (auto gameSession{ m_gameClient->Session() })\n            {\n                assert(m_gameClient->m_pendingCommitInProgress);\n\n                // Set the properties and write the session if it still exists\n                auto sessionToCommit = MakeShared<XblMultiplayerSession>(m_localUser->Xuid(), &gameSession->SessionReference(), nullptr);\n                sessionToCommit->Join(nullptr, false, true);\n\n                // Ok to use \"unsafe\" method here because we just created and have the only instance of this session\n                auto sessionUser{ sessionToCommit->CurrentUserInternalUnsafe() };\n                assert(sessionUser);\n\n                for (const auto& prop : m_propertiesToWrite)\n                {\n                    sessionUser->SetCustomPropertyJson(prop.first, prop.second);\n                }\n\n                if (!m_secureDeviceAddressToWrite.empty())\n                {\n                    sessionUser->SetSecureDeviceBaseAddress64(m_secureDeviceAddressToWrite);\n                }\n\n                m_gameClient->m_sessionWriter->WriteSession(\n                    m_localUser->Context(),\n                    sessionToCommit,\n                    XblMultiplayerSessionWriteMode::UpdateExisting,\n                    true,\n                    [gameClient{ m_gameClient }](Result<std::shared_ptr<XblMultiplayerSession>>)\n                {\n                    gameClient->m_pendingCommitInProgress = false;\n                });\n            }\n        }\n\n    private:\n        std::shared_ptr<MultiplayerGameClient> m_gameClient;\n        std::shared_ptr<MultiplayerLocalUser> m_localUser;\n        Map<String, JsonDocument> m_propertiesToWrite;\n        String m_secureDeviceAddressToWrite;\n    };\n\n    auto operation = MakeShared<SetPropertiesOperation>(shared_from_this(), localUser, propertiesToWrite, localUserSecureDeviceAddress);\n    operation->Run();\n}\n\nvoid\nMultiplayerGameClient::RemoveStaleUsersFromRemoteSession()\n{\n    auto gameSession = Session();\n    if (gameSession == nullptr)\n    {\n        return;\n    }\n\n    auto xboxLiveContextMap = m_multiplayerLocalUserManager->GetLocalUserMap();\n    for (auto xboxLiveContext : xboxLiveContextMap)\n    {\n        auto localUser = xboxLiveContext.second;\n        if (localUser != nullptr && localUser->LobbyState() == MultiplayerLocalUserLobbyState::Remove)\n        {\n            // Leave the game session if it exists.\n            if (gameSession != nullptr)\n            {\n                std::weak_ptr<MultiplayerGameClient> weakSessionWriter = shared_from_this();\n\n                auto sessionToCommit = MakeShared<XblMultiplayerSession>(localUser->Xuid(), &gameSession->SessionReference(), nullptr);\n                sessionToCommit->Leave();\n                m_sessionWriter->WriteSession(localUser->Context(), sessionToCommit, XblMultiplayerSessionWriteMode::UpdateExisting, true,\n                [weakSessionWriter](Result<std::shared_ptr<XblMultiplayerSession>> result)\n                {\n                    std::shared_ptr<MultiplayerGameClient> pThis(weakSessionWriter.lock());\n                    if (pThis)\n                    {\n                        auto lobbyClient{ pThis->LobbyClient() };\n                        if (lobbyClient)\n                        {\n                            lobbyClient->StopAdvertisingGameSession(result);\n                        }\n                    }\n                });\n            }\n        }\n    }\n}\n\nHRESULT MultiplayerGameClient::JoinHelper(\n    _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ bool writeMemberPropertiesFromLobby,\n    _In_ const String& handleId,\n    _In_ MultiplayerSessionCallback callback\n) const noexcept\n{\n    RETURN_HR_IF_LOG_DEBUG(localUser == nullptr || localUser->Context() == nullptr, E_UNEXPECTED, \"Call add_local_user() first.\");\n\n    session->Join(nullptr, false, true);\n    XblMultiplayerSessionReadLockGuard sessionSafe(session);\n    if (sessionSafe.CurrentUser() != nullptr)\n    {\n        sessionSafe.CurrentUserInternal()->SetSecureDeviceBaseAddress64(localUser->ConnectionAddress());\n    }\n    session->SetSessionChangeSubscription(XblMultiplayerSessionChangeTypes::Everything);\n\n    if (writeMemberPropertiesFromLobby)\n    {\n        auto localMember = XblMultiplayerSession::GetPlayerInSession(localUser->Xuid(), LobbySession());\n        if (localMember != nullptr && strlen(localMember->CustomPropertiesJson) > 0)\n        {\n            JsonDocument jsonPropertyObj;\n            jsonPropertyObj.Parse(localMember->CustomPropertiesJson);\n            for (const auto& prop : jsonPropertyObj.GetObject())\n            {\n                session->SetCurrentUserMemberCustomPropertyJson(prop.name.GetString(), prop.value);\n            }\n        }\n    }\n    if (handleId.empty())\n    {\n        m_sessionWriter->WriteSession(\n            localUser->Context(),\n            session,\n            XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n            true,\n            std::move(callback)\n        );\n    }\n    else\n    {\n        m_sessionWriter->WriteSessionByHandle(\n            localUser->Context(),\n            session,\n            XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n            handleId,\n            true,\n            std::move(callback)\n        );\n    }\n    return S_OK;\n}\n\nHRESULT MultiplayerGameClient::JoinGameHelper(\n    _In_ const String& sessionName,\n    _In_ Callback<Result<void>> callback\n) noexcept\n{\n    XblMultiplayerSessionReference gameSessionRef = XblMultiplayerSessionReferenceCreate(\n        AppConfig::Instance()->OverrideScid().data(),\n        m_gameSessionTemplateName.data(),\n        sessionName.data()\n    );\n\n    return JoinGameBySessionReference(gameSessionRef,\n        [\n            sharedThis{ shared_from_this() },\n            callback\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> joinResult)\n    {\n        if (SUCCEEDED(joinResult.Hresult()) && joinResult.Payload() != nullptr && sharedThis->LobbyClient() != nullptr)\n        {\n            // If join_game succeeds, advertise game sessions via the lobby. If the advertising fails, \n            // we simply eat the error as it isn't actionable for the title.\n            sharedThis->LobbyClient()->AdvertiseGameSession();\n        }\n        callback(joinResult.Hresult());\n    });\n}\n\nHRESULT MultiplayerGameClient::JoinGameBySessionReference(\n    _In_ const XblMultiplayerSessionReference& gameSessionRef,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr, E_UNEXPECTED, \"Call add_local_user() before joining.\");\n\n    return JoinGameForAllLocalMembers(gameSessionRef, String{}, false, std::move(callback));\n}\n\nHRESULT MultiplayerGameClient::JoinGameByHandle(\n    _In_ const String& handleId,\n    _In_ bool createGameIfFailedToJoin,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr, E_UNEXPECTED, \"Call add_local_user() before joining.\");\n\n    return JoinGameForAllLocalMembers(XblMultiplayerSessionReference{}, handleId, createGameIfFailedToJoin, std::move(callback));\n}\n\nHRESULT MultiplayerGameClient::JoinGameForAllLocalMembers(\n    _In_ const XblMultiplayerSessionReference& sessionRefToJoin,\n    _In_ const String& handleId,\n    _In_ bool createGameIfFailedToJoin,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(!XblMultiplayerSessionReferenceIsValid(&sessionRefToJoin) && handleId.empty());\n\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr, E_UNEXPECTED, \"Call add_local_user() before joining.\");\n\n    // Leave existing game without updating the latest as the leave may comeback after the actual join and overwrite it.\n    auto cachedSession = Session();\n    if (cachedSession != nullptr)\n    {\n        LeaveRemoteSession(cachedSession, false, false);\n    }\n    UpdateSession(nullptr);\n\n    // Join either an existing or new game session. If attempting to join an existing session fails,\n    // optionally creates a new game session from the lobby. When all users have joined the game, a JoinGameCompleted\n    // event will be raised.\n    struct JoinGameOperation : public std::enable_shared_from_this<JoinGameOperation>\n    {\n        JoinGameOperation(\n            std::shared_ptr<MultiplayerGameClient> gameClient,\n            const XblMultiplayerSessionReference& sessionRefToJoin,\n            String handleIdToJoin,\n            bool createGameIfFailedToJoin,\n            MultiplayerSessionCallback&& callback\n        ) noexcept :\n            m_gameClient{ std::move(gameClient) },\n            m_sessionRefToJoin{ sessionRefToJoin },\n            m_handleIdToJoin{ std::move(handleIdToJoin) },\n            m_createGameIfFailedToJoin{ createGameIfFailedToJoin },\n            m_localUsers{ m_gameClient->m_multiplayerLocalUserManager->GetLocalUserMap() },\n            m_callback{ std::move(callback) }\n        {\n        }\n\n        void Run() noexcept\n        {\n            JoinGameWithNextUser();\n        }\n\n    private:\n        void JoinGameWithNextUser() noexcept\n        {\n            assert(!m_localUsers.empty());\n            auto localUser{ m_localUsers.begin()->second };\n            m_localUsers.erase(m_localUsers.begin());\n\n            auto sessionToCommit = MakeShared<XblMultiplayerSession>(localUser->Xuid(), &m_sessionRefToJoin, nullptr);\n            HRESULT hr = m_gameClient->JoinHelper(localUser, sessionToCommit, true, m_handleIdToJoin,\n                [\n                    this,\n                    sharedThis{ shared_from_this() },\n                    localUser\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> joinSessionResult)\n            {\n                if (Succeeded(joinSessionResult))\n                {\n                    localUser->SetGameState(MultiplayerLocalUserGameState::InSession);\n                }\n\n                if (Failed(joinSessionResult) || m_localUsers.empty())\n                {\n                    OnJoinCompleted(std::move(joinSessionResult));\n                }\n                else\n                {\n                    JoinGameWithNextUser();\n                }\n            });\n\n            if (FAILED(hr))\n            {\n                OnJoinCompleted(hr);\n            }\n        }\n\n        void OnJoinCompleted(Result<std::shared_ptr<XblMultiplayerSession>>&& joinResult) noexcept\n        {\n            if (auto lobbyClient{ m_gameClient->LobbyClient() })\n            {\n                if (joinResult.Hresult() == HTTP_E_STATUS_NOT_FOUND && !m_handleIdToJoin.empty())\n                {\n                    // We tried to join an existing session but it didn't exist. Create a new game session\n                    // from the lobby and clear the existing handleId since it must be invalid.\n                    if (m_createGameIfFailedToJoin)\n                    {\n                        m_callback(lobbyClient->CreateGameFromLobby());\n                        return;\n                    }\n                    lobbyClient->ClearGameSessionFromLobby();\n                }\n                else if (Failed(joinResult) && m_handleIdToJoin.empty())\n                {\n                    // Tried to create a new game and we failed. Clear the transfer handle pending state (GameSessionTransferHandle=pending~xuid).\n                    lobbyClient->ClearGameSessionFromLobby();\n                }\n            }\n\n            if (Succeeded(joinResult))\n            {\n                m_gameClient->UpdateSession(joinResult.Payload());\n                m_gameClient->m_multiplayerLocalUserManager->ChangeAllLocalUserGameState(MultiplayerLocalUserGameState::InSession);\n            }\n\n            {\n                std::lock_guard<std::mutex> lock(m_gameClient->m_clientRequestLock);\n                m_gameClient->m_multiplayerEventQueue.AddEvent(\n                    XblMultiplayerEventType::JoinGameCompleted,\n                    XblMultiplayerSessionType::GameSession,\n                    MakeShared<XblMultiplayerEventArgs>(),\n                    joinResult\n                );\n            }\n            m_callback(joinResult);\n        }\n\n        std::shared_ptr<MultiplayerGameClient> m_gameClient;\n        XblMultiplayerSessionReference m_sessionRefToJoin;\n        String m_handleIdToJoin;\n        bool m_createGameIfFailedToJoin;\n        Map<uint64_t, std::shared_ptr<MultiplayerLocalUser>> m_localUsers;\n        MultiplayerSessionCallback m_callback;\n    };\n\n    auto operation = MakeShared<JoinGameOperation>(\n        shared_from_this(),\n        sessionRefToJoin,\n        handleId,\n        createGameIfFailedToJoin,\n        std::move(callback)\n    );\n\n    operation->Run();\n    return S_OK;\n}\n\nHRESULT MultiplayerGameClient::JoinGameFromLobbyHelper(\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    auto lobbySession = LobbySession();\n    auto lobbyClient = LobbyClient();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr || lobbyClient == nullptr || lobbySession == nullptr, E_UNEXPECTED, \"No lobby session exists. Call add_local_user() to create a lobby first.\");\n\n    // Check if the lobby has a game session associated with it to join.\n    XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n\n    JsonDocument jsonDoc;\n    jsonDoc.Parse(lobbySessionSafe.SessionProperties().SessionCustomPropertiesJson);\n\n    xsapi_internal_string transferHandle;\n    if (!jsonDoc.HasParseError())\n    {\n        JsonUtils::ExtractJsonString(jsonDoc, MultiplayerLobbyClient_TransferHandlePropertyName, transferHandle, false);\n    }\n    if (transferHandle.empty()) // aka the field isn't there\n    {\n        return lobbyClient->CreateGameFromLobby();\n    }\n\n    String handleId;\n    if (lobbyClient->IsTransferHandleState(\"pending\"))\n    {\n        // Wait for the property changed event to join.\n        m_multiplayerLocalUserManager->ChangeAllLocalUserGameState(MultiplayerLocalUserGameState::PendingJoin);\n        return S_OK;\n    }\n    else if (lobbyClient->IsTransferHandleState(\"completed\"))\n    {\n        handleId = lobbyClient->GetTransferHandle();\n    }\n    return JoinGameByHandle(handleId, true, std::move(callback));\n}\n\nvoid MultiplayerGameClient::LeaveRemoteSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ bool stopAdvertisingGameSession,\n    _In_ bool triggerCompletionEvent\n) noexcept\n{\n    auto processingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    m_processingQueue.push_back(processingRequest);\n\n    m_sessionWriter->LeaveRemoteSession(session,\n        [\n            weakThis = std::weak_ptr<MultiplayerGameClient>{ shared_from_this() },\n            this,\n            stopAdvertisingGameSession,\n            triggerCompletionEvent,\n            processingRequest\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> result)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            auto lobbyClient{ LobbyClient() };\n            if (stopAdvertisingGameSession && lobbyClient)\n            {\n                lobbyClient->StopAdvertisingGameSession(result);\n            }\n\n            // Always set your local game session to null upon leaving.\n            UpdateSession(nullptr);\n\n            if (triggerCompletionEvent)\n            {\n                {\n                    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n                    m_multiplayerEventQueue.AddEvent(\n                        XblMultiplayerEventType::LeaveGameCompleted,\n                        XblMultiplayerSessionType::GameSession\n                    );\n                }\n\n                RemoveFromProcessingQueue(processingRequest->Identifier());\n            }\n        }\n    });\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_game_session.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerGameSession::MultiplayerGameSession():\n    m_changeNumber(0),\n    m_sessionReference{},\n    m_sessionConstants{},\n    m_memberInitialization{}\n{\n}\n\nMultiplayerGameSession::MultiplayerGameSession(_In_ const MultiplayerGameSession& other):\n    m_correlationId(other.m_correlationId),\n    m_changeNumber(other.m_changeNumber),\n    m_sessionReference(other.m_sessionReference),\n    m_host(other.m_host),\n    m_members(other.m_members),\n    m_properties(other.m_properties),\n    m_multiplayerClientManager(other.m_multiplayerClientManager),\n    m_sessionConstants {},\n    m_memberInitialization{}\n{\n    DeepCopyConstants(other.m_sessionConstants);\n}\n\nMultiplayerGameSession::MultiplayerGameSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ std::shared_ptr<MultiplayerMember> host,\n    _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> members\n    ):\n    m_correlationId(session->SessionInfo().CorrelationId),\n    m_changeNumber(session->SessionInfo().ChangeNumber),\n    m_sessionReference(session->SessionReference()),\n    m_host(std::move(host)),\n    m_members(std::move(members)),\n    m_sessionConstants{},\n    m_memberInitialization{}\n{\n    XblMultiplayerSessionReadLockGuard sessionSafe(session);\n    DeepCopyConstants(sessionSafe.SessionConstants());\n\n    if (sessionSafe.SessionProperties().SessionCustomPropertiesJson != nullptr)\n    {\n        m_properties = sessionSafe.SessionProperties().SessionCustomPropertiesJson;\n    }\n}\n\nconst XblMultiplayerSessionReference&\nMultiplayerGameSession::SessionReference() const\n{\n    return m_sessionReference;\n}\n\nconst xsapi_internal_string&\nMultiplayerGameSession::CorrelationId() const\n{\n    return m_correlationId;\n}\n\nuint64_t\nMultiplayerGameSession::ChangeNumber() const\n{\n    return m_changeNumber;\n}\n\nstd::shared_ptr<MultiplayerMember>\nMultiplayerGameSession::Host() const\n{\n    return m_host;\n}\n\nvoid\nMultiplayerGameSession::SetHost(\n    _In_ std::shared_ptr<MultiplayerMember> hostMember\n    )\n{\n    m_host = hostMember;\n}\n\nconst xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>&\nMultiplayerGameSession::Members() const\n{\n    return m_members;\n}\n\nconst XblMultiplayerSessionConstants&\nMultiplayerGameSession::SessionConstants() const\n{\n    return m_sessionConstants;\n}\n\nconst xsapi_internal_string&\nMultiplayerGameSession::Properties() const\n{\n    return m_properties;\n}\n\nHRESULT\nMultiplayerGameSession::SetProperties(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    return m_multiplayerClientManager->SetProperties(m_sessionReference, name, valueJson, context);\n}\n\nbool\nMultiplayerGameSession::IsHost( \n    _In_ uint64_t xuid\n    )\n{\n    if (m_host == nullptr || m_members.size() == 0)\n    {\n        return false;\n    }\n\n    return xuid == m_host->Xuid();\n}\n\nHRESULT\nMultiplayerGameSession::SetSynchronizedHost(\n    _In_ const xsapi_internal_string& deviceToken,\n    _In_opt_ context_t context\n    )\n{\n    return m_multiplayerClientManager->SetSynchronizedHost(m_sessionReference, deviceToken, context);\n}\n\nHRESULT\nMultiplayerGameSession::SetSynchronizedProperties(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    return m_multiplayerClientManager->SetSynchronizedProperties(m_sessionReference, name, valueJson, context);\n}\n\nvoid\nMultiplayerGameSession::SetMultiplayerClientManager(\n    _In_ std::shared_ptr<MultiplayerClientManager> clientManager\n    )\n{\n    m_multiplayerClientManager = clientManager;\n}\n\nvoid MultiplayerGameSession::DeepCopyConstants(const XblMultiplayerSessionConstants& other)\n{\n    m_sessionConstants = other;\n    m_initiatorXuids = xsapi_internal_vector<uint64_t>(other.InitiatorXuids, other.InitiatorXuids + other.InitiatorXuidsCount);\n    m_sessionConstants.InitiatorXuids = m_initiatorXuids.data();\n    if (m_sessionConstants.MemberInitialization)\n    {\n        m_memberInitialization = *m_sessionConstants.MemberInitialization;\n        m_sessionConstants.MemberInitialization = &m_memberInitialization;\n    }\n    if (m_sessionConstants.CustomJson)\n    {\n        m_constantsCustomJson = m_sessionConstants.CustomJson;\n        m_sessionConstants.CustomJson = m_constantsCustomJson.data();\n    }\n    if (m_sessionConstants.SessionCloudComputePackageConstantsJson)\n    {\n        m_constantsCloudComputePackageJson = m_sessionConstants.SessionCloudComputePackageConstantsJson;\n        m_sessionConstants.SessionCloudComputePackageConstantsJson = m_constantsCloudComputePackageJson.data();\n    }\n    if (m_sessionConstants.MeasurementServerAddressesJson)\n    {\n        m_constantsMeasurementServerAddressesJson = m_sessionConstants.MeasurementServerAddressesJson;\n        m_sessionConstants.MeasurementServerAddressesJson = m_constantsMeasurementServerAddressesJson.data();\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_lobby_client.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n#include \"xbox_live_app_config_internal.h\"\n\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services::system;\nusing namespace xbox::services::legacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\n#ifdef XSAPI_UNIT_TESTS\n#define RETRY_DELAY_MS 0\n#else\n#define RETRY_DELAY_MS 1000\n#endif\n#define MAX_CONNECTION_ATTEMPTS 3\n\nMultiplayerLobbyClient::MultiplayerLobbyClient(\n    _In_ const TaskQueue& queue\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_sessionWriter{ MakeShared<MultiplayerSessionWriter>(queue) }\n{\n}\n\nMultiplayerLobbyClient::MultiplayerLobbyClient(\n    _In_ const TaskQueue& queue,\n    _In_ String lobbySessionTemplateName,\n    _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_lobbySessionTemplateName{ std::move(lobbySessionTemplateName) },\n    m_sessionWriter{ MakeShared<MultiplayerSessionWriter>(queue, localUserManager) },\n    m_multiplayerLocalUserManager{ std::move(localUserManager) }\n{\n}\n\nMultiplayerLobbyClient::~MultiplayerLobbyClient() noexcept\n{\n    m_sessionWriter.reset();\n}\n\nvoid\nMultiplayerLobbyClient::Initialize()\n{\n    std::weak_ptr<MultiplayerLobbyClient> weakThis = shared_from_this();\n    m_sessionWriter->AddMultiplayerSessionUpdatedHandler([weakThis](_In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession)\n    {\n        std::shared_ptr<MultiplayerLobbyClient> pThis(weakThis.lock());\n        if (pThis != nullptr)\n        {\n            pThis->UpdateSession(updatedSession);\n        }\n    });\n}\n\nvoid MultiplayerLobbyClient::deep_copy_if_updated(\n    _In_ const MultiplayerLobbyClient& other\n    )\n{\n    std::lock_guard<std::mutex> lock(other.m_clientRequestLock);\n\n    m_joinability = other.m_joinability;\n    if (other.m_sessionWriter->Session() == nullptr)\n    {\n        m_sessionWriter->UpdateSession(nullptr);\n        m_multiplayerLobby = nullptr;\n    }\n    else if (other.m_multiplayerLobby == nullptr)\n    {\n        m_multiplayerLobby = nullptr;\n    }\n    else if (m_sessionWriter->Session() == nullptr ||\n            other.m_sessionWriter->Session()->SessionInfo().ChangeNumber > m_sessionWriter->Session()->SessionInfo().ChangeNumber ||\n            other.m_sessionWriter->Session()->ETag() > m_sessionWriter->Session()->ETag())\n    {\n        m_sessionWriter->UpdateSession(MakeShared<XblMultiplayerSession>(*other.m_sessionWriter->Session()));\n        m_multiplayerLobby = MakeShared<MultiplayerLobbySession>(*other.m_multiplayerLobby);\n    }\n    else if (m_updateNumber != other.m_updateNumber)\n    {\n        m_multiplayerLobby = MakeShared<MultiplayerLobbySession>(*other.m_multiplayerLobby);\n    }\n}\n\nstd::shared_ptr<MultiplayerGameClient>\nMultiplayerLobbyClient::GameClient()\n{\n    // TODO this should be changed such that nothing here needs to depend on the GlobalState.\n    // For now just try to get the global state and return null (which is handled by callers) if\n    // it that fails.\n    auto state{ GlobalState::Get() };\n    return state ? state->MultiplayerManager()->GameClient() : nullptr;\n}\n\nstd::shared_ptr<XblMultiplayerSession>\nMultiplayerLobbyClient::GameSession()\n{\n    auto gameClient{ GameClient() };\n    return gameClient ? gameClient->Session() : nullptr;\n}\n\nconst std::shared_ptr<MultiplayerSessionWriter>&\nMultiplayerLobbyClient::SessionWriter() const\n{\n    return m_sessionWriter;\n}\n\nconst std::shared_ptr<MultiplayerLobbySession>&\nMultiplayerLobbyClient::Lobby() const\n{\n    return m_multiplayerLobby;\n}\n\nvoid\nMultiplayerLobbyClient::UpdateLobby(\n    _In_ std::shared_ptr<MultiplayerLobbySession> multiplayerLobby\n    )\n{\n    ++m_updateNumber;\n    m_multiplayerLobby = multiplayerLobby;\n}\n\nconst std::shared_ptr<XblMultiplayerSession>&\nMultiplayerLobbyClient::Session() const\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    return m_sessionWriter->Session();\n}\n\nvoid\nMultiplayerLobbyClient::UpdateSession(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n    )\n{\n    auto cachedSession = Session();\n    if (updatedSession == nullptr || cachedSession == nullptr ||\n        updatedSession->SessionInfo().ChangeNumber > cachedSession->SessionInfo().ChangeNumber ||\n        updatedSession->ETag() != cachedSession->ETag())\n    {\n        UpdateLobbySession(updatedSession);\n    }\n}\n\nvoid \nMultiplayerLobbyClient::UpdateLobbySession(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    m_sessionWriter->UpdateSession(updatedSession);\n}\n\nvoid\nMultiplayerLobbyClient::UpdateObjects(\n    const std::shared_ptr<XblMultiplayerSession>& updatedSession, \n    const std::shared_ptr<XblMultiplayerSession>& gameSession\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    if (updatedSession == nullptr)\n    {\n        UpdateLobby(nullptr);\n        m_localLobbyMembers.clear();\n        m_joinability = XblMultiplayerJoinability::None;\n    }\n    else\n    {\n        UpdateLocalLobbyMembers(updatedSession, gameSession);\n        auto multiplayerLobby = ConvertToMultiplayerLobby(updatedSession, gameSession);\n        UpdateLobby(multiplayerLobby);\n        XblMultiplayerSessionReadLockGuard updatedSessionSafe(updatedSession);\n        m_joinability = MultiplayerManagerUtils::GetJoinability(updatedSessionSafe.SessionProperties());\n    }\n}\n\nvoid\nMultiplayerLobbyClient::UpdateLocalLobbyMembers(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedLobbySession,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& gameSession\n    )\n{\n    m_localLobbyMembers.clear();\n    if (updatedLobbySession == nullptr)\n    {\n        return;\n    }\n\n    auto localLobbyGameMembers = xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>();\n\n    auto xboxLiveContextMap = m_multiplayerLocalUserManager->GetLocalUserMap();\n    for(auto xboxLiveContext : xboxLiveContextMap)\n    {\n        auto localUser =  xboxLiveContext.second;\n        if (localUser != nullptr)\n        {\n            auto member = XblMultiplayerSession::GetPlayerInSession(localUser->Xuid(), updatedLobbySession);\n            if (member != nullptr)\n            {\n                auto localMember = MultiplayerMember::CreateFromSessionMember(member, updatedLobbySession, gameSession, true);\n                localLobbyGameMembers.push_back(localMember);\n            }\n        }\n    }\n\n    m_localLobbyMembers = localLobbyGameMembers;\n}\n\nstd::shared_ptr<MultiplayerLobbySession>\nMultiplayerLobbyClient::ConvertToMultiplayerLobby(\n    _In_ const  std::shared_ptr<XblMultiplayerSession>& sessionToConvert,\n    _In_ const  std::shared_ptr<XblMultiplayerSession>& gameSession\n    )\n{\n    if (sessionToConvert == nullptr)\n    {\n        return nullptr;\n    }\n\n    std::shared_ptr<MultiplayerMember> hostMember = nullptr;\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> gameMembers;\n    XblMultiplayerSessionReadLockGuard sessionToConvertSafe(sessionToConvert);\n    for (const auto& member : sessionToConvertSafe.Members())\n    {\n        auto gameMember = MultiplayerMember::CreateFromSessionMember(\n            &member, \n            sessionToConvert,\n            gameSession,\n            m_multiplayerLocalUserManager->GetLocalUserMap()\n            );\n        if (member.DeviceToken.Value[0] != 0 && utils::str_icmp(member.DeviceToken.Value, sessionToConvertSafe.SessionProperties().HostDeviceToken.Value) == 0)\n        {\n            hostMember = gameMember;\n        }\n\n        gameMembers.push_back(gameMember);\n    }\n\n    return MakeShared<MultiplayerLobbySession>(\n        sessionToConvert,\n        hostMember,\n        gameMembers,\n        m_localLobbyMembers\n        );\n}\n\nXblMultiplayerJoinability\nMultiplayerLobbyClient::Joinability()\n{\n    return m_joinability;\n}\n\nconst MultiplayerEventQueue&\nMultiplayerLobbyClient::EventQueue()\n{\n    // Don't require a lock as STL is multithread read safe\n    return m_multiplayerEventQueue;\n}\n\nvoid\nMultiplayerLobbyClient::ClearPendingQueue()\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    while (!m_pendingRequestQueue.empty())\n    {\n        m_pendingRequestQueue.pop();\n    }\n}\n\nvoid\nMultiplayerLobbyClient::AddToPendingQueue(\n    _In_ std::shared_ptr<MultiplayerClientPendingRequest> pendingRequest\n    )\n{\n    // No lock required. Methods that call this already has a lock\n    m_pendingRequestQueue.push(pendingRequest);\n}\n\nvoid\nMultiplayerLobbyClient::AddToProcessingQueue(\n    _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue\n    )\n{\n    for (const auto& request : processingQueue)\n    {\n        m_processingQueue.push_back(request);\n    }\n}\n\nvoid\nMultiplayerLobbyClient::RemoveFromProcessingQueue(\n    _In_ uint32_t identifier\n    )\n{\n    for (auto request = m_processingQueue.begin(); request != m_processingQueue.end(); ++request)\n    {\n        if ((*request)->Identifier() == identifier)\n        {\n            m_processingQueue.erase(request);\n            break;\n        }\n    }\n}\n\nxsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>>\nMultiplayerLobbyClient::GetProcessingQueue()\n{\n    return m_processingQueue;\n}\n\nHRESULT\nMultiplayerLobbyClient::AddLocalUser(\n    _In_ xbox_live_user_t user,\n    _In_ MultiplayerLocalUserLobbyState userState,\n    _In_ const xsapi_internal_string& handleId\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n    auto localUser = m_multiplayerLocalUserManager->GetLocalUserHelper(user);\n    RETURN_HR_IF_LOG_DEBUG(localUser != nullptr && userState == MultiplayerLocalUserLobbyState::Add, E_UNEXPECTED, \"User already added.\");\n\n    if (localUser == nullptr)\n    {\n        auto localUserResult = m_multiplayerLocalUserManager->AddUserToXboxLiveContextToMap(user);\n        RETURN_HR_IF_FAILED(localUserResult.Hresult());\n\n        localUser = localUserResult.ExtractPayload();\n    }\n\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetLocalUser(localUser);\n    pendingRequest->SetLobbyState(userState);\n    if (userState == MultiplayerLocalUserLobbyState::Join)\n    {\n        if (!handleId.empty())\n        {\n            pendingRequest->SetLobbyHandleId(handleId);\n        }\n    }\n    AddToPendingQueue(pendingRequest);\n\n    return S_OK;\n}\n\nvoid\nMultiplayerLobbyClient::AddLocalUsers(\n    _In_ xsapi_internal_vector<xbox_live_user_t> users,\n    _In_ const xsapi_internal_string& handleId\n    )\n{\n    for (const auto& user : users)\n    {\n        AddLocalUser(user, MultiplayerLocalUserLobbyState::Join, handleId);\n    }\n}\n\n\nvoid\nMultiplayerLobbyClient::AddLocalUsers(\n    _In_ xsapi_internal_vector<xbox_live_user_t> users\n    )\n{\n    for (const auto& user : users)\n    {\n        AddLocalUser(user, MultiplayerLocalUserLobbyState::Join, xsapi_internal_string());\n    }\n}\n\nHRESULT\nMultiplayerLobbyClient::RemoveLocalUser(\n    _In_ xbox_live_user_t user\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n\n    auto localUser = m_multiplayerLocalUserManager->GetLocalUserHelper(user);\n    RETURN_HR_IF_LOG_DEBUG(localUser == nullptr || localUser->Context() == nullptr, E_UNEXPECTED, \"Call add_local_user() first.\");\n\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetLocalUser(localUser);\n    pendingRequest->SetLobbyState(MultiplayerLocalUserLobbyState::Leave);\n    AddToPendingQueue(pendingRequest);\n\n    return S_OK;\n}\n\nvoid\nMultiplayerLobbyClient::RemoveAllLocalUsers()\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n\n    if (m_multiplayerLocalUserManager != nullptr)\n    {\n        const auto& xboxLiveContextMap = m_multiplayerLocalUserManager->GetLocalUserMap();\n        for (auto xboxLiveContext : xboxLiveContextMap)\n        {\n            const auto& localUser = xboxLiveContext.second;\n            if (localUser != nullptr)\n            {\n                auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n                pendingRequest->SetLocalUser(localUser);\n                pendingRequest->SetLobbyState(MultiplayerLocalUserLobbyState::Leave);\n                AddToPendingQueue(pendingRequest);\n            }\n        }\n    }\n}\n\nHRESULT\nMultiplayerLobbyClient::SetLocalMemberProperties(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n\n    auto localUser = m_multiplayerLocalUserManager->GetLocalUserHelper(user);\n    RETURN_HR_IF_LOG_DEBUG(localUser == nullptr || localUser->Context() == nullptr, E_UNEXPECTED, \"Call add_local_user() before setting local member properties.\");\n\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetLocalUserProperties(localUser, name, valueJson, context);\n    AddToPendingQueue(pendingRequest);\n\n    return S_OK;\n}\n\nHRESULT\nMultiplayerLobbyClient::DeleteLocalMemberProperties(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& name,\n    _In_opt_ context_t context\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n\n    auto localUser = m_multiplayerLocalUserManager->GetLocalUserHelper(user);\n    RETURN_HR_IF_LOG_DEBUG(localUser == nullptr || localUser->Context() == nullptr, E_UNEXPECTED, \"Call add_local_user() before deleting local member properties.\");\n\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetLocalUserProperties(localUser, name, JsonValue(), context);\n    AddToPendingQueue(pendingRequest);\n\n    return S_OK;\n}\n\nHRESULT\nMultiplayerLobbyClient::SetLocalMemberConnectionAddress(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& address,\n    _In_opt_ context_t context\n    )\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n\n    auto localUser = m_multiplayerLocalUserManager->GetLocalUserHelper(user);\n    RETURN_HR_IF_LOG_DEBUG(localUser == nullptr || localUser->Context() == nullptr, E_UNEXPECTED, \"Call add_local_user() before setting local member connection address.\");\n\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetLocalUserConnectionAddress(localUser, address, context);\n    AddToPendingQueue(pendingRequest);\n\n    return S_OK;\n}\n\nHRESULT MultiplayerLobbyClient::SetJoinability(\n    _In_ XblMultiplayerJoinability value,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF(value < XblMultiplayerJoinability::JoinableByFriends || value > XblMultiplayerJoinability::Closed);\n\n    auto pendingRequest = MakeShared<MultiplayerClientPendingRequest>();\n    pendingRequest->SetJoinability(value, context);\n    AddToPendingQueue(pendingRequest);\n\n    return S_OK;\n}\n\nMultiplayerEventQueue\nMultiplayerLobbyClient::DoWork()\n{\n    bool expected = false;\n    if (m_pendingCommitInProgress.compare_exchange_strong(expected, true))\n    {\n        if (m_pendingRequestQueue.size() > 0)\n        {\n            xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue;\n            XblMultiplayerSessionReference teamSessionRef{};\n            bool applySynchronizedChanges = false;\n            bool lobbyStateIsJoin = false;\n            bool joinByHandleId = false;\n            bool doneProcessing = false;\n            do\n            {\n                std::lock_guard<std::mutex> lock(m_clientRequestLock);\n                {\n                    auto pendingRequest = m_pendingRequestQueue.front();\n                    processingQueue.push_back(pendingRequest);\n                    m_pendingRequestQueue.pop();\n\n                    if (m_pendingRequestQueue.size() > 0)\n                    {\n                        if (pendingRequest->RequestType() != m_pendingRequestQueue.front()->RequestType())\n                        {\n                            doneProcessing = true;\n                        }\n                    }\n\n                    if (!applySynchronizedChanges && pendingRequest->RequestType() == PendingRequestType::SynchronizedChanges)\n                    {\n                        applySynchronizedChanges = true;\n                    }\n\n                    if (pendingRequest->LocalUser() != nullptr)\n                    {\n                        auto lobbyState = pendingRequest->LobbyState();\n                        if (lobbyState == MultiplayerLocalUserLobbyState::Join)\n                        {\n                            lobbyStateIsJoin = true;\n\n                            // Leave existing lobby without updating the latest as the leave may comeback after the actual join and overwrite it.\n                            auto latestSession = m_sessionWriter->Session();\n                            if (latestSession != nullptr)\n                            {\n                                LeaveRemoteSession(latestSession);\n                            }\n\n                            m_sessionWriter->UpdateSession(nullptr);\n                            UpdateLobby(nullptr);\n                            m_localLobbyMembers.clear();\n                            m_joinability = XblMultiplayerJoinability::None;\n\n                            if (!pendingRequest->LobbyHandleId().empty())\n                            {\n                                pendingRequest->LocalUser()->SetLobbyHandleId(pendingRequest->LobbyHandleId());\n                                joinByHandleId = true;\n                            }\n                        }\n\n                        if (lobbyState != MultiplayerLocalUserLobbyState::Unknown)\n                        {\n                            pendingRequest->LocalUser()->SetLobbyState(lobbyState);\n                        }\n                        \n                        pendingRequest->LocalUser()->SetWriteChangesToService(true);\n                    }\n                }\n\n            } while (!doneProcessing && m_pendingRequestQueue.size() > 0);\n\n            if (processingQueue.size() > 0)\n            {\n                AddToProcessingQueue(processingQueue);\n\n                std::weak_ptr<MultiplayerLobbyClient> weakThis = shared_from_this();\n\n                MultiplayerEventQueueCallback callback = [weakThis, processingQueue](Result<MultiplayerEventQueue> result)\n                {\n                    std::shared_ptr<MultiplayerLobbyClient> pThis(weakThis.lock());\n                    if (pThis != nullptr)\n                    {\n                        std::lock_guard<std::mutex> lock(pThis->m_clientRequestLock);\n                        {\n                            auto eventQueue = result.Payload();\n                            for (const auto& ev : eventQueue)\n                            {\n                                pThis->m_multiplayerEventQueue.AddEvent(ev);\n                            }\n                        }\n\n                        for (const auto& processingRequest : processingQueue)\n                        {\n                            pThis->RemoveFromProcessingQueue(processingRequest->Identifier());\n                        }\n\n                        pThis->m_pendingCommitInProgress.store(false);\n                    }\n                };\n\n                if (applySynchronizedChanges)\n                {\n                    m_sessionWriter->CommitPendingSynchronizedChanges(processingQueue, XblMultiplayerSessionType::LobbySession, callback);\n                }\n                else\n                {\n                    Vector<uint64_t> xuidsInOrder;\n\n                    if (lobbyStateIsJoin)\n                    {\n                        // If users are joining from an invite than the first multiplayer_client_pending_request in processingQueue references was the invited user.\n                        // We want the invited user to join first since it is possible that users in the local graph might not meet the criteria\n                        // to join the invited session until the invited user joins. Imagine that the inviting session has the session privacy set to joinable_by_friends\n                        // and only the invited user is a friend of the inviting user. If any additional users attempt to join the inviting session before the invited user\n                        // than the join fails for the whole list of users.\n                        for (auto pendingRequest : processingQueue)\n                        {\n                            if (pendingRequest->LocalUser())\n                            {\n                                xuidsInOrder.push_back(pendingRequest->LocalUser()->Xuid());\n                            }\n                        }\n                    }\n\n                    CommitPendingLobbyChanges(xuidsInOrder, joinByHandleId, teamSessionRef, callback);\n                }\n\n\n            }\n            else\n            {\n                m_pendingCommitInProgress.store(false);\n            }\n        }\n        else\n        {\n            m_pendingCommitInProgress.store(false);\n        }\n    }\n\n    MultiplayerEventQueue eventQueue;\n    {\n        std::lock_guard<std::mutex> lock(m_clientRequestLock);\n        eventQueue = m_multiplayerEventQueue;\n        m_multiplayerEventQueue.Clear();\n    }\n\n    return eventQueue;\n}\n\nbool\nMultiplayerLobbyClient::IsPendingLobbyChanges()\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    if (m_pendingRequestQueue.size() > 0 || IsPendingLobbyLocalUserChanges())\n    {\n        return true;\n    }\n\n    if (m_sessionWriter != nullptr)\n    {\n        auto latestSession = m_sessionWriter->Session();\n        if (latestSession != nullptr &&\n            m_multiplayerLobby != nullptr &&\n            latestSession->SessionInfo().ChangeNumber != m_multiplayerLobby->ChangeNumber())\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool\nMultiplayerLobbyClient::IsRequestInProgress()\n{\n    return m_pendingRequestQueue.size() > 0 || m_processingQueue.size() > 0 || m_multiplayerEventQueue.Size() > 0;\n}\n\nbool\nMultiplayerLobbyClient::IsPendingLobbyLocalUserChanges()\n{\n    const auto& xboxLiveContextMap = m_multiplayerLocalUserManager->GetLocalUserMap();\n    for (auto xboxLiveContext : xboxLiveContextMap)\n    {\n        const auto& localUser = xboxLiveContext.second;\n        if (localUser != nullptr && localUser->WriteChangesToService())\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nHRESULT MultiplayerLobbyClient::CommitPendingLobbyChanges(\n    _In_ const Vector<uint64_t>& xuidsInOrder,\n    _In_ bool joinByHandleId,\n    _In_ XblMultiplayerSessionReference sessionRef,\n    _In_ MultiplayerEventQueueCallback callback\n) noexcept\n{\n    if (IsPendingLobbyLocalUserChanges())\n    {\n        // All local member changes always happen on the lobby session.\n        std::shared_ptr<XblMultiplayerSession> latestLobbySession;\n        auto lobbySession = Session();\n        if (lobbySession == nullptr)\n        {\n            auto primaryContext  = m_multiplayerLocalUserManager->GetPrimaryContext();\n            if (joinByHandleId)\n            {\n                latestLobbySession = MakeShared<XblMultiplayerSession>(primaryContext->Xuid(), nullptr, nullptr);\n            }\n            else\n            {\n                if (sessionRef.Scid[0] == 0)\n                {\n                    String sessionName = utils::create_guid(true);\n                    sessionRef = XblMultiplayerSessionReferenceCreate(\n                        AppConfig::Instance()->OverrideScid().data(),\n                        m_lobbySessionTemplateName.data(),\n                        sessionName.data()\n                    );\n                }\n\n                latestLobbySession = MakeShared<XblMultiplayerSession>(primaryContext->Xuid(), &sessionRef, nullptr);\n            }\n        }\n        else\n        {\n            latestLobbySession = MakeShared<XblMultiplayerSession>(*lobbySession);\n        }\n\n        // Committing  local user changes will also update any pending lobby properties.\n        return CommitLobbyChanges(xuidsInOrder, latestLobbySession, [callback](Result<void> result)\n        {\n            callback(Result<MultiplayerEventQueue>{ result.Hresult(), result.ErrorMessage() });\n        });\n    }\n    else\n    {\n        bool isGameInProgress = GameSession() != nullptr;\n        return m_sessionWriter->CommitPendingChanges(GetProcessingQueue(), XblMultiplayerSessionType::LobbySession, isGameInProgress, callback);\n    }\n}\n\nHRESULT MultiplayerLobbyClient::CommitLobbyChanges(\n    _In_ const Vector<uint64_t>& xuidsInOrder,\n    _In_ std::shared_ptr<XblMultiplayerSession> lobbySessionToCommit,\n    _In_ Callback<Result<void>> callback\n) noexcept\n{\n    // For each User in xuidsInOrder, prepare an XblMultiplayerSession with their pending lobby changes\n    // and write it to MPSD. Will also update the user's multiplayer activity & set the session host token\n    // as neeeded. Consistent with 1806 XDK behavior, if any individual MPSD call fails unexpectedly,\n    // we abort the entire operation and return that result.\n    struct CommitLobbyChangesOperation : public std::enable_shared_from_this<CommitLobbyChangesOperation>\n    {\n        CommitLobbyChangesOperation(\n            std::shared_ptr<MultiplayerLobbyClient> lobbyClient,\n            const Vector<uint64_t>& xuidsInOrder,\n            std::shared_ptr<XblMultiplayerSession> lobbySessionToCommit,\n            Callback<Result<void>>&& callback\n        ) noexcept :\n            m_lobbyClient{ std::move(lobbyClient) },\n            m_lobbySessionToCommit{ std::move(lobbySessionToCommit) },\n            m_callback{ std::move(callback) }\n        {\n            auto& localUsers{ m_lobbyClient->GetLocalUserMap() };\n            if (xuidsInOrder.empty())\n            {\n                for (auto pair : localUsers)\n                {\n                    m_users.push_back(pair.second);\n                }\n            }\n            else\n            {\n                for (auto xuid : xuidsInOrder)\n                {\n                    auto iter = localUsers.find(xuid);\n                    if (iter != localUsers.end())\n                    {\n                        m_users.push_back(iter->second);\n                    }\n                }\n            }\n        }\n\n        void Run() noexcept\n        {\n            CommitChangesForNextUser();\n        }\n\n    private:\n        void CommitChangesForNextUser() noexcept\n        {\n            if (m_users.empty())\n            {\n                Complete(S_OK);\n            }\n            else\n            {\n                auto user{ m_users.front() };\n                m_users.pop_front();\n                CommitChangesForUser(user);\n            }\n        }\n\n        void CommitChangesForUser(\n            std::shared_ptr<MultiplayerLocalUser> user\n        ) noexcept\n        {\n            // Prepare a session with changes specific to this user.\n            // Ok to use MPSD 'unsafe' methods here since we created the session locally, thus it is the only reference\n            auto session = MakeShared<XblMultiplayerSession>(user->Xuid(), &m_lobbySessionToCommit->SessionReference(), nullptr);\n\n            switch (user->LobbyState())\n            {\n            case MultiplayerLocalUserLobbyState::Add:\n            {\n                session->Join();\n                if (!user->ConnectionAddress().empty())\n                {\n                    session->CurrentUserInternalUnsafe()->SetSecureDeviceBaseAddress64(user->ConnectionAddress());\n                }\n                session->SetSessionChangeSubscription(XblMultiplayerSessionChangeTypes::Everything);\n\n                // Only set this for the first user. Could cause a race condition if XblMultiplayerJoinability was changed during the second write.\n                if (m_setJoinability)\n                {\n                    m_setJoinability = false;\n                    session->SetJoinRestriction(XblMultiplayerSessionRestriction::Followed);\n                    session->SetReadRestriction(XblMultiplayerSessionRestriction::Followed);\n\n                    String jsonValueStr = MultiplayerManagerUtils::ConvertJoinabilityToString(XblMultiplayerJoinability::JoinableByFriends);\n                    JsonDocument jsonValue;\n                    jsonValue.SetString(jsonValueStr.c_str(), jsonValue.GetAllocator());\n                    session->SetSessionCustomPropertyJson(MultiplayerLobbyClient_JoinabilityPropertyName, jsonValue);\n                }\n                break;\n            }\n            case MultiplayerLocalUserLobbyState::Join:\n            {\n                session->Join();\n\n                if (!user->ConnectionAddress().empty())\n                {\n                    session->CurrentUserInternalUnsafe()->SetSecureDeviceBaseAddress64(user->ConnectionAddress());\n                }\n                session->SetSessionChangeSubscription(XblMultiplayerSessionChangeTypes::Everything);\n                break;\n            }\n            case MultiplayerLocalUserLobbyState::InSession:\n            {\n                // Forces to set the current user to yourself.\n                session->Join();\n                break;\n            }\n            case MultiplayerLocalUserLobbyState::Leave:\n            {\n                if (XblMultiplayerSession::IsPlayerInSession(user->Xuid(), m_lobbySessionToCommit))\n                {\n                    session->Leave();\n                }\n                else\n                {\n                    // In a scenario where the user was removed before he could have been added.\n                    m_lobbyClient->UserStateChanged({ xbl_error_code::logic_error, \"The user was removed before they could be added\" }, MultiplayerLocalUserLobbyState::Add, user->Xuid());\n                    m_lobbyClient->UserStateChanged({ xbl_error_code::no_error }, MultiplayerLocalUserLobbyState::Leave, user->Xuid());\n\n                    m_removeStaleUsers = true;\n                    user->SetLobbyState(MultiplayerLocalUserLobbyState::Remove);\n\n                    // Since the user has been removed, no work to be done for this user\n                    this->CommitChangesForNextUser();\n                    return;\n                }\n                break;\n            }\n            default:\n            {\n                break;\n            }\n            }\n\n            bool isGameInProgress = m_lobbyClient->GameSession() != nullptr;\n\n            // Update any pending local user or lobby session properties.\n            for (auto& request : m_lobbyClient->m_processingQueue)\n            {\n                request->AppendPendingChanges(session, user, isGameInProgress);\n            }\n\n            // Now write the session to MPSD\n            HRESULT hr{ S_OK };\n            if (user->LobbyHandleId().empty())\n            {\n                hr = m_lobbyClient->m_sessionWriter->WriteSession(\n                    user->Context(),\n                    session,\n                    XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n                    true,\n                    [\n                        op{ shared_from_this() },\n                        user\n                    ]\n                (Result<std::shared_ptr<XblMultiplayerSession>> result)\n                {\n                    op->HandleWriteSessionResult(user, std::move(result));\n                });\n            }\n            else\n            {\n                hr = m_lobbyClient->m_sessionWriter->WriteSessionByHandle(\n                    user->Context(),\n                    session,\n                    XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n                    user->LobbyHandleId(),\n                    true,\n                    [\n                        op{ shared_from_this() },\n                        user\n                    ]\n                (Result<std::shared_ptr<XblMultiplayerSession>> result)\n                {\n                    op->HandleWriteSessionResult(user, std::move(result));\n                });\n\n                user->SetLobbyHandleId(String{});\n            }\n            if (FAILED(hr))\n            {\n                Complete(hr);\n            }\n        }\n\n        void HandleWriteSessionResult(\n            std::shared_ptr<MultiplayerLocalUser> user,\n            Result<std::shared_ptr<XblMultiplayerSession>>&& sessionResult\n        ) noexcept\n        {\n            m_lobbyClient->UserStateChanged(sessionResult, user->LobbyState(), user->Xuid());\n            m_lobbyClient->HandleLobbyChangeEvents(sessionResult, user, m_lobbyClient->m_processingQueue);\n\n            if (Failed(sessionResult))\n            {\n                m_lobbyClient->JoinLobbyCompleted(sessionResult, user->Xuid());\n\n                // If we failed to join the lobby, make sure the local user context is cleaned up\n                switch (user->LobbyState())\n                {\n                case MultiplayerLocalUserLobbyState::Add:\n                case MultiplayerLocalUserLobbyState::Join:\n                {\n                    m_removeStaleUsers = true;\n                    user->SetLobbyState(MultiplayerLocalUserLobbyState::Remove);\n                }\n                default:\n                {\n                    break;\n                }\n                }\n\n                Complete(sessionResult);\n                return;\n            }\n\n            switch (user->LobbyState())\n            {\n            case MultiplayerLocalUserLobbyState::Add:\n            case MultiplayerLocalUserLobbyState::Join:\n            {\n                auto updatedSession = sessionResult.ExtractPayload();\n                m_lobbyClient->UpdateSession(updatedSession);\n                auto oldLobbyState = user->LobbyState();\n                user->SetLobbyState(MultiplayerLocalUserLobbyState::InSession);\n\n                if (oldLobbyState == MultiplayerLocalUserLobbyState::Join)\n                {\n                    m_lobbyClient->HandleJoinLobbyCompleted(sessionResult, user->Xuid());\n                }\n\n                if (oldLobbyState == MultiplayerLocalUserLobbyState::Add && m_lobbyClient->ShouldUpdateHostToken(user, updatedSession))\n                {\n                    UpdateHostDeviceToken(user, updatedSession);\n                }\n                else\n                {\n                    SetActivityForUser(user, updatedSession);\n                }\n                return;\n            }\n            case MultiplayerLocalUserLobbyState::Leave:\n            {\n                m_removeStaleUsers = true;\n\n                // If you leave the session you were advertising, you don't need to clear the activity.\n                user->SetLobbyState(MultiplayerLocalUserLobbyState::Remove);\n\n                // Intentional fallthrough\n            }\n            default:\n            {\n                // Work done for this user, continue operation\n                CommitChangesForNextUser();\n                return;\n            }\n            }\n        }\n\n        void UpdateHostDeviceToken(\n            std::shared_ptr<MultiplayerLocalUser> user,\n            std::shared_ptr<XblMultiplayerSession> session\n        ) noexcept\n        {\n            XblMultiplayerSessionReadLockGuard sessionSafe{ session };\n            session->SetHostDeviceToken(sessionSafe.CurrentUser()->DeviceToken);\n\n            auto hr = m_lobbyClient->m_sessionWriter->WriteSession(\n                user->Context(),\n                session,\n                XblMultiplayerSessionWriteMode::UpdateExisting,\n                true,\n                [\n                    op{ shared_from_this() },\n                    user\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> writeHostTokenResult)\n            {\n                if (Failed(writeHostTokenResult))\n                {\n                    op->Complete(writeHostTokenResult);\n                }\n                else\n                {\n                    op->SetActivityForUser(user, writeHostTokenResult.ExtractPayload());\n                }\n            });\n\n            if (FAILED(hr))\n            {\n                Complete(hr);\n            }\n        }\n\n        void SetActivityForUser(\n            std::shared_ptr<MultiplayerLocalUser> user,\n            std::shared_ptr<XblMultiplayerSession> session\n        ) noexcept\n        {\n            auto hr = user->Context()->MultiplayerService()->SetActivity(\n                session->SessionReference(),\n                AsyncContext<Result<void>>{ m_lobbyClient->m_queue,\n                [\n                    op{ shared_from_this() }\n                ]\n            (Result<void> setActivityResult)\n            {\n                if (Failed(setActivityResult))\n                {\n                    op->Complete(std::move(setActivityResult));\n                }\n                else\n                {\n                    op->CommitChangesForNextUser();\n                }\n            }\n            });\n\n            if (FAILED(hr))\n            {\n                Complete(hr);\n            }\n        }\n\n        void Complete(Result<void>&& result)\n        {\n            LOGS_DEBUG << __FUNCTION__ << \": HRESULT=\" << result.Hresult() << \", ErrorMessage=\" << result.ErrorMessage();\n\n            if (m_removeStaleUsers)\n            {\n                m_lobbyClient->RemoveStaleXboxLiveContextFromMap();\n            }\n            m_callback(result);\n        }\n\n        std::shared_ptr<MultiplayerLobbyClient> m_lobbyClient;\n        List<std::shared_ptr<MultiplayerLocalUser>> m_users;\n        std::shared_ptr<XblMultiplayerSession> m_lobbySessionToCommit;\n        bool m_setJoinability{ true };\n        bool m_removeStaleUsers{ false };\n        Callback<Result<void>> m_callback;\n    };\n\n    auto operation = MakeShared<CommitLobbyChangesOperation>(\n        shared_from_this(),\n        xuidsInOrder,\n        lobbySessionToCommit,\n        std::move(callback)\n    );\n\n    operation->Run();\n    return S_OK;\n}\n\nvoid\nMultiplayerLobbyClient::RemoveStaleXboxLiveContextFromMap()\n{\n    auto gameClient = GameClient();\n    if (gameClient != nullptr)\n    {\n        gameClient->RemoveStaleUsersFromRemoteSession();\n    }\n\n    // Remove stale context, switch primary context and re-activate multiplayer events.\n    m_multiplayerLocalUserManager->RemoveStaleLocalUsersFromMap();\n}\n\nconst xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>&\nMultiplayerLobbyClient::GetLocalUserMap()\n{\n    return m_multiplayerLocalUserManager->GetLocalUserMap();\n}\n\nstd::shared_ptr<XblContext>\nMultiplayerLobbyClient::GetPrimaryContext()\n{\n    return m_multiplayerLocalUserManager->GetPrimaryContext();\n}\n\nHRESULT MultiplayerLobbyClient::CreateGameFromLobby() noexcept\n{\n    auto lobbySession = Session();\n    RETURN_HR_IF_LOG_DEBUG(lobbySession == nullptr, E_UNEXPECTED, \"No lobby session exists. Call add_local_user() to create a lobby first\");\n\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr, E_UNEXPECTED, \"Call add_local_user() before joining.\");\n\n    // Try to write transfer handle to the lobby as pending state\n    // If succeeded, then create the game session, and join it. The game session will later be advertised.\n    // If failed, complete the operation. The game session will later be joined when we get a SessionPropertyChanged event\n    struct CreateGameOperation : public std::enable_shared_from_this<CreateGameOperation>\n    {\n        CreateGameOperation(\n            std::shared_ptr<MultiplayerLobbyClient> lobbyClient,\n            std::shared_ptr<XblMultiplayerSession> lobbySession,\n            uint64_t primaryXuid\n        ) noexcept :\n            m_lobbyClient{ std::move(lobbyClient) },\n            m_sessionToCommit{ MakeShared<XblMultiplayerSession>(*lobbySession) },\n            m_primaryXuid{ primaryXuid }\n        {\n        }\n\n        void Run() noexcept\n        {\n            SetTransferHandleToPending();\n        }\n\n    private:\n        void SetTransferHandleToPending()\n        {\n            // Add transfer handle property to lobby session\n            Stringstream jsonValue;\n            jsonValue << \"pending~\" << m_primaryXuid;\n            JsonDocument value;\n            value.SetString(jsonValue.str().data(), value.GetAllocator());\n            m_sessionToCommit->SetSessionCustomPropertyJson(MultiplayerLobbyClient_TransferHandlePropertyName, value);\n\n            auto hr = m_lobbyClient->m_sessionWriter->CommitSynchronizedChanges(m_sessionToCommit,\n                [\n                    sharedThis{ shared_from_this() }\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> result)\n            {\n                sharedThis->HandleWriteSessionResult(std::move(result));\n            });\n\n            if (FAILED(hr))\n            {\n                Complete(hr);\n            }\n        }\n\n        void HandleWriteSessionResult(Result<std::shared_ptr<XblMultiplayerSession>>&& writeSessionResult)\n        {\n            auto op{ shared_from_this() };\n            auto gameClient = m_lobbyClient->GameClient();\n\n            if (gameClient == nullptr)\n            {\n                op->Complete(Result<void>{ E_FAIL, \"MultiplayerGameClient destroyed\" });\n            }\n            else if (writeSessionResult.Hresult() == HTTP_E_STATUS_PRECOND_FAILED)\n            {\n                if (m_lobbyClient->IsTransferHandleState(\"completed\") || m_lobbyClient->IsTransferHandleState(\"pending\"))\n                {\n                    // We couldn't set transfer handle, but a game session already exists. Join that instead\n                    HRESULT hr = gameClient->JoinGameFromLobbyHelper([op](Result<std::shared_ptr<XblMultiplayerSession>> result)\n                    {\n                        op->Complete(result);\n                    });\n\n                    if (FAILED(hr))\n                    {\n                        Complete(hr);\n                    }\n                }\n                else if(m_setTransferHandleAttempt++ < MAX_CONNECTION_ATTEMPTS)\n                {\n\n                    std::shared_ptr<XblMultiplayerSession> sessionToCommitTemp = writeSessionResult.ExtractPayload();\n\n                    HRESULT hr = S_OK;\n                    if (sessionToCommitTemp != nullptr) // handle rare case where an empty body is returned\n                    {\n                        m_sessionToCommit = sessionToCommitTemp;\n                        // Retry setting transfer handle after a small delay\n                        hr = m_lobbyClient->m_queue.RunWork([op] {\n                            op->SetTransferHandleToPending();\n                        }, RETRY_DELAY_MS);\n                    }\n                    else\n                    {\n                        hr = writeSessionResult.Hresult();\n                    }\n\n                    if (FAILED(hr))\n                    {\n                        op->Complete(hr);\n                    }\n                }\n                else\n                {\n                    // We were unable to set the transfer handle after MAX_CONNECTION_ATTEMPTS\n                    m_lobbyClient->UpdateSession(m_sessionToCommit);\n\n                    Result<void> opResult{ writeSessionResult.Hresult(), \"Max connection attempts exceeded\" };\n                    m_lobbyClient->JoinLobbyCompleted(\n                        opResult,\n                        m_primaryXuid\n                    );\n\n                    op->Complete(std::move(opResult));\n                }\n            }\n            else \n            {\n                // Should we not check for WriteSession failures other than 412?\n                // 1806 XDK assumes the transfer handle was successfully set, creates a game session, and joins it\n\n                auto sessionName = utils::create_guid(true);\n                HRESULT hr = gameClient->JoinGameHelper(sessionName, [op](Result<void> result)\n                {\n                    op->Complete(std::move(result));\n                });\n\n                if (FAILED(hr))\n                {\n                    op->Complete(hr);\n                }\n            }\n        }\n\n        void Complete(Result<void>&& result) noexcept\n        {\n            // This operation is strange in that nothing directly looks at the result.\n            // The result is exposed to title via events, but MPM doesn't seem to handle failures.\n            // Trying to keep the purpose of each operation as consistent with 1806 XDK as possible, so leaving as is for now.\n\n            LOGS_DEBUG << __FUNCTION__ << \": HRESULT=\" << result.Hresult() << \", ErrorMessage=\" << result.ErrorMessage();\n        }\n\n        std::shared_ptr<MultiplayerLobbyClient> m_lobbyClient;\n        std::shared_ptr<XblMultiplayerSession> m_sessionToCommit;\n        uint64_t const m_primaryXuid;\n        uint8_t m_setTransferHandleAttempt{ 0 };\n    };\n\n    auto operation = MakeShared<CreateGameOperation>(\n        shared_from_this(),\n        lobbySession,\n        primaryContext->Xuid()\n    );\n\n    operation->Run();\n    return S_OK;\n}\n\nvoid MultiplayerLobbyClient::AdvertiseGameSession() noexcept\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    if (primaryContext == nullptr || GameSession() == nullptr)\n    {\n        return;\n    }\n\n    // This operation performs several sub-steps as follows:\n    // 1. If a pending commit is currently in progress, wait until it is completed\n    // 2. Establish a lobby session & commit any pending lobby changes\n    // 3. Create an MPSD transfer handle from the lobby session to the game session\n    // 4. Update the lobby session properties (custom transfer handle & joinability)\n    struct AdvertiseGameSessionOperation : public std::enable_shared_from_this<AdvertiseGameSessionOperation>\n    {\n        AdvertiseGameSessionOperation(\n            std::shared_ptr<MultiplayerLobbyClient> lobbyClient,\n            std::shared_ptr<XblContext> primaryContext\n        ) noexcept\n            : m_lobbyClient{ std::move(lobbyClient) },\n            m_primaryContext{ std::move(primaryContext) }\n        {\n        }\n\n        void Run() noexcept\n        {\n            bool expected{ false };\n            if (!m_lobbyClient->m_pendingCommitInProgress.compare_exchange_strong(expected, true))\n            {\n                // Wait until there isn't commit in progress before continuing.\n                // Reschedule op with no delay (1806 XDK behavior)\n                HRESULT hr = m_lobbyClient->m_queue.RunWork([op{ shared_from_this() }]\n                    {\n                        op->Run();\n                    });\n\n                if (FAILED(hr))\n                {\n                    Complete(hr);\n                }\n            }\n            else\n            {\n                EstablishLobbySession();\n            }\n        }\n\n    private:\n        void EstablishLobbySession() noexcept\n        {\n            auto lobbySession{ m_lobbyClient->Session() };\n            if (!lobbySession)\n            {\n                if (m_lobbyClient->m_multiplayerLocalUserManager->GetLocalUserMap().empty())\n                {\n                    // There are no remaining local users. Complete the operation\n                    return Complete(S_OK);\n                }\n\n                m_lobbyClient->m_multiplayerLocalUserManager->ChangeAllLocalUserLobbyState(MultiplayerLocalUserLobbyState::Add);\n                auto hr = m_lobbyClient->CommitPendingLobbyChanges(Vector<uint64_t>{}, false, XblMultiplayerSessionReference{},\n                    [\n                        op{ shared_from_this() }\n                    ]\n                (Result<MultiplayerEventQueue> joinLobbyResult)\n                {\n                    op->m_lobbyClient->m_pendingCommitInProgress = false;\n                    op->m_lobbyClient->JoinLobbyCompleted(joinLobbyResult, op->m_primaryContext->Xuid());\n                    if (Failed(joinLobbyResult))\n                    {\n                        op->Complete(joinLobbyResult);\n                    }\n                    else\n                    {\n                        op->CreateTransferHandle(op->m_lobbyClient->Session());\n                    }\n                });\n\n                if (FAILED(hr))\n                {\n                    Complete(hr);\n                }\n            }\n            else\n            {\n                m_lobbyClient->m_pendingCommitInProgress = false;\n                CreateTransferHandle(lobbySession);\n            }\n        }\n\n        void CreateTransferHandle(std::shared_ptr<XblMultiplayerSession> lobbySession) noexcept\n        {\n            JsonDocument lobbyProperties;\n            {\n                XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n                lobbyProperties.Parse(lobbySessionSafe.SessionProperties().SessionCustomPropertiesJson);\n            }\n\n            if (!lobbyProperties.HasMember(MultiplayerLobbyClient_TransferHandlePropertyName) ||\n                (m_lobbyClient->IsTransferHandleState(\"pending\") && m_lobbyClient->GetTransferHandle() == utils::uint64_to_internal_string(m_primaryContext->Xuid())))\n            {\n                auto gameSession{ m_lobbyClient->GameSession() };\n                if (!gameSession)\n                {\n                    return Complete(Result<void>{E_ABORT, \"GameSession null\"});\n                }\n\n                auto hr = m_primaryContext->MultiplayerService()->SetTransferHandle(\n                    gameSession->SessionReference(),\n                    lobbySession->SessionReference(),\n                    AsyncContext<Result<String>>{ m_lobbyClient->m_queue,\n                    [\n                        op{ shared_from_this() },\n                        lobbySession\n                    ]\n                (Result<String> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        op->UpdateLobbySession(MakeShared<XblMultiplayerSession>(*lobbySession), result.ExtractPayload());\n                    }\n                    else\n                    {\n                        if (result.Hresult() == HTTP_E_STATUS_FORBIDDEN)\n                        {\n                            // By MPSD design, if the game session doesn't exist on transfer handle creation, it throws a 403.\n                            op->m_lobbyClient->ClearGameSessionFromLobby();\n                        }\n                        op->Complete(result);\n                    }\n                }\n                });\n\n                if (FAILED(hr))\n                {\n                    return Complete(hr);\n                }\n            }\n        }\n\n        void UpdateLobbySession(\n            std::shared_ptr<XblMultiplayerSession> lobbySession,\n            String&& transferHandle\n        ) noexcept\n        {\n            if (m_lobbyClient->m_joinability == XblMultiplayerJoinability::DisableWhileGameInProgress)\n            {\n                lobbySession->SetClosed(true);\n            }\n\n            Stringstream jsonHandleValue;\n            jsonHandleValue << \"completed~\" << transferHandle;\n\n            JsonDocument jsonValue;\n            jsonValue.SetString(jsonHandleValue.str().data(), jsonValue.GetAllocator());\n            lobbySession->SetSessionCustomPropertyJson(\n                MultiplayerLobbyClient_TransferHandlePropertyName,\n                jsonValue\n            );\n\n            HRESULT hr = m_lobbyClient->m_sessionWriter->WriteSession(\n                m_primaryContext,\n                lobbySession,\n                XblMultiplayerSessionWriteMode::UpdateExisting,\n                true,\n                [\n                    op{ shared_from_this() }\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> result)\n            {\n                op->Complete(result);\n            });\n\n            if (FAILED(hr))\n            {\n                Complete(hr);\n            }\n        }\n\n        void Complete(Result<void>&& result)\n        {\n            // This operation is strange in that nothing directly looks at the result.\n            // The result is exposed to title via events, but MPM doesn't seem to handle failures.\n            // Trying to keep the purpose of each operation as consistent with 1806 XDK as possible, so leaving as is for now.\n\n            LOGS_DEBUG << __FUNCTION__ << \": HRESULT=\" << result.Hresult() << \", ErrorMessage=\" << result.ErrorMessage();\n        }\n\n        std::shared_ptr<MultiplayerLobbyClient> m_lobbyClient;\n        std::shared_ptr<XblContext> m_primaryContext;\n    };\n\n    auto operation = MakeShared<AdvertiseGameSessionOperation>(shared_from_this(), primaryContext);\n    operation->Run();\n}\n\nvoid\nMultiplayerLobbyClient::StopAdvertisingGameSession(\n    _In_ Result<std::shared_ptr<XblMultiplayerSession>> result\n    )\n{\n    bool bClearGameSession = false;\n    auto lobbySession = Session();\n    XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n    if (SUCCEEDED(result.Hresult()) && result.Payload() == nullptr)\n    {\n        // When you are the last person to leave the session (handling err 204).\n        bClearGameSession = true;\n    }\n    else if (result.Payload() != nullptr && lobbySession != nullptr)\n    {\n        auto latestGameSession = result.Payload();\n\n        bool found = false;\n        auto members = lobbySessionSafe.Members();\n        for (const auto& member : members)\n        {\n            if (XblMultiplayerSession::IsPlayerInSession(member.Xuid, latestGameSession))\n            {\n                found = true;\n                break;\n            }\n        }\n\n        if (!found && members.size() > 0)\n        {\n            bClearGameSession = true;\n        }\n    }\n\n    if (bClearGameSession)\n    {\n        ClearGameSessionFromLobby();\n    }\n}\n\nvoid\nMultiplayerLobbyClient::ClearGameSessionFromLobby()\n{\n    auto lobbySession = Session();\n    if (lobbySession != nullptr)\n    {\n        auto lobbySessionCopy = MakeShared<XblMultiplayerSession>(*lobbySession);\n\n        if (m_joinability == XblMultiplayerJoinability::DisableWhileGameInProgress)\n        {\n            // Re-open the lobby to be joinable when leaving the game session.\n            lobbySessionCopy->SetClosed(false);\n        }\n\n        lobbySessionCopy->DeleteSessionCustomPropertyJson(MultiplayerLobbyClient_TransferHandlePropertyName);\n        m_sessionWriter->WriteSession(m_multiplayerLocalUserManager->GetPrimaryContext(), lobbySessionCopy, XblMultiplayerSessionWriteMode::UpdateExisting, true, nullptr);\n    }\n}\n\nbool\nMultiplayerLobbyClient::IsTransferHandleState(\n    _In_ const xsapi_internal_string& state\n    )\n{\n    auto lobbySession = Session();\n    if (lobbySession == nullptr)\n    {\n        return false;\n    }\n\n    XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n\n    JsonDocument jsonDoc;\n    jsonDoc.Parse(lobbySessionSafe.SessionProperties().SessionCustomPropertiesJson);\n\n    if (!jsonDoc.HasParseError())\n    {\n        xsapi_internal_string transferHandleProp;\n        if (SUCCEEDED(JsonUtils::ExtractJsonString(jsonDoc, MultiplayerLobbyClient_TransferHandlePropertyName, transferHandleProp, true)))\n        {\n            xsapi_internal_vector<xsapi_internal_string> transferHandleSplit = utils::string_split_internal(transferHandleProp, '~');\n\n            if (transferHandleSplit.size() > 0 &&\n                utils::str_icmp_internal(transferHandleSplit[0], state) == 0)\n            {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nxsapi_internal_string\nMultiplayerLobbyClient::GetTransferHandle()\n{\n    auto lobbySession = Session();\n    if (lobbySession == nullptr)\n    {\n        return xsapi_internal_string();\n    }\n\n    XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n    JsonDocument jsonDoc;\n    jsonDoc.Parse(lobbySessionSafe.SessionProperties().SessionCustomPropertiesJson);\n\n    if (!jsonDoc.HasParseError())\n    {\n        xsapi_internal_string transferHandleProp;\n        if (SUCCEEDED(JsonUtils::ExtractJsonString(jsonDoc, MultiplayerLobbyClient_TransferHandlePropertyName, transferHandleProp, true)))\n        {\n            xsapi_internal_vector<xsapi_internal_string> transferHandleSplit = utils::string_split_internal(transferHandleProp, '~');\n\n            if (transferHandleSplit.size() == 2)\n            {\n                return transferHandleSplit[1];\n            }\n        }\n    }\n\n    return xsapi_internal_string();\n}\n\nvoid\nMultiplayerLobbyClient::LeaveRemoteSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    m_sessionWriter->LeaveRemoteSession(session, nullptr);\n}\n\nbool\nMultiplayerLobbyClient::ShouldUpdateHostToken(\n    _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    if(XblMultiplayerSession::HostMember(session) != nullptr)\n    {\n        return false;\n    }\n\n    if(!localUser->IsPrimaryXboxLiveContext())\n    {\n        return false;\n    }\n\n    // If the local user is already the host, skip it.\n    if (XblMultiplayerSession::IsHost(utils::uint64_to_internal_string(localUser->Xuid()), session))\n    {\n        return false;\n    }\n\n    return true;\n}\n\nvoid\nMultiplayerLobbyClient::UserStateChanged(\n    _In_ Result<void> error,\n    _In_ MultiplayerLocalUserLobbyState localUserLobbyState,\n    _In_ uint64_t xboxUserId\n    )\n{\n    if (localUserLobbyState != MultiplayerLocalUserLobbyState::Add &&\n        localUserLobbyState != MultiplayerLocalUserLobbyState::Leave)\n    {\n        return;\n    }\n\n    std::shared_ptr<XblMultiplayerEventArgs> eventArgs;\n    XblMultiplayerEventType eventType = XblMultiplayerEventType::UserAdded;\n    if (localUserLobbyState == MultiplayerLocalUserLobbyState::Add)\n    {\n        eventType = XblMultiplayerEventType::UserAdded;\n        std::shared_ptr<UserAddedEventArgs> userAddedEventArgs = MakeShared<UserAddedEventArgs>(xboxUserId);\n        eventArgs = std::dynamic_pointer_cast<UserAddedEventArgs>(userAddedEventArgs);\n    }\n    else if (localUserLobbyState == MultiplayerLocalUserLobbyState::Leave)\n    {\n        eventType = XblMultiplayerEventType::UserRemoved;\n        std::shared_ptr<UserRemovedEventArgs> userRemovedEventArgs = MakeShared<UserRemovedEventArgs>(xboxUserId);\n        eventArgs = std::dynamic_pointer_cast<UserRemovedEventArgs>(userRemovedEventArgs);\n    }\n    else\n    {\n        // We only care about user_added & user_removed.\n        return;\n    }\n\n    AddEvent(eventType, eventArgs, error);\n}\n\nvoid\nMultiplayerLobbyClient::HandleLobbyChangeEvents(\n    _In_ Result<void> error,\n    _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n    _In_ const xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>>& processingQueue\n    )\n{\n    xsapi_internal_map<xsapi_internal_string, JsonDocument> localUsersMap;\n    xsapi_internal_string localUserSecureDeviceAddress;\n    for (auto& request : processingQueue)\n    {\n        // Handle local user change events\n        if (localUser != nullptr && request->LocalUser() != nullptr && localUser->Xuid() == request->LocalUser()->Xuid())\n        {\n            if (!request->LocalUserSecureDeivceAddress().empty())\n            {\n                AddEvent(\n                    XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted,\n                    nullptr,\n                    error,\n                    request->Context()\n                );\n\n                localUserSecureDeviceAddress = request->LocalUserSecureDeivceAddress();\n            }\n\n            // Fire events for each of the properties\n            for (const auto& prop : request->LocalUserProperties())\n            {\n                AddEvent(\n                    XblMultiplayerEventType::LocalMemberPropertyWriteCompleted,\n                    nullptr,\n                    error,\n                    request->Context()\n                );\n\n                localUsersMap[prop.first] = JsonDocument();\n                JsonUtils::CopyFrom(localUsersMap[prop.first], prop.second);\n            }\n        }\n    }\n\n    // Handle lobby change events (session properties, etc)\n    auto eventQueue = m_sessionWriter->HandleEvents(processingQueue, error, XblMultiplayerSessionType::LobbySession);\n    if (eventQueue.Size() > 0)\n    {\n        std::lock_guard<std::mutex> lock(m_clientRequestLock);\n        for (auto& ev : eventQueue)\n        {\n            m_multiplayerEventQueue.AddEvent(ev);\n        }\n    }\n\n    if (localUsersMap.size() != 0 || !localUserSecureDeviceAddress.empty())\n    {\n        // write member properties to the game session.\n        auto gameClient = GameClient();\n        if (gameClient != nullptr)\n        {\n            gameClient->SetLocalMemberPropertiesToRemoteSession(localUser, localUsersMap, localUserSecureDeviceAddress);\n        }\n    }\n}\n\nvoid\nMultiplayerLobbyClient::HandleJoinLobbyCompleted(\n    _In_ Result<void> error,\n    _In_ uint64_t joinedXuid\n    )\n{\n    JoinLobbyCompleted(error, joinedXuid);\n    if (FAILED(error.Hresult()))\n    {\n        // If joining the lobby succeeded, check if it has a game session associated with it to join.\n\n        auto gameClient = GameClient();\n        if (gameClient == nullptr)\n        {\n            return;\n        }\n\n        auto lobbySession = Session();\n\n        // Join game via the transfer handle.\n        XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n\n        JsonDocument lobbyProperties;\n        lobbyProperties.Parse(lobbySessionSafe.SessionProperties().SessionCustomPropertiesJson);\n\n        if (!lobbyProperties.HasParseError())\n        {\n            if (lobbyProperties.IsObject() && lobbyProperties.MemberCount() > 0)\n            {\n                xsapi_internal_string transferHandle;\n\n                if (IsTransferHandleState(\"completed\"))\n                {\n                    transferHandle = GetTransferHandle();\n                }\n                else\n                {\n                    // No existing game session\n                    return;\n                }\n\n                gameClient->JoinGameByHandle(transferHandle, false, nullptr);\n            }\n        }\n    }\n}\n\nvoid\nMultiplayerLobbyClient::JoinLobbyCompleted(\n    _In_ Result<void> error,\n    _In_ uint64_t invitedXboxUserId\n    )\n{\n    std::shared_ptr<JoinLobbyCompletedEventArgs> joinLobbyEventArgs = MakeShared<JoinLobbyCompletedEventArgs>(\n        invitedXboxUserId\n        );\n\n    AddEvent(\n        XblMultiplayerEventType::JoinLobbyCompleted,\n        std::dynamic_pointer_cast<JoinLobbyCompletedEventArgs>(joinLobbyEventArgs),\n        error\n    );\n}\n\n// TODO remove this and add locking to event queue class\nvoid \nMultiplayerLobbyClient::AddEvent(\n    _In_ XblMultiplayerEventType eventType,\n    _In_opt_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs,\n    _In_opt_ Result<void> error,\n    _In_opt_ context_t context\n)\n{\n    std::lock_guard<std::mutex> lock(m_clientRequestLock);\n    m_multiplayerEventQueue.AddEvent(eventType,\n        XblMultiplayerSessionType::LobbySession,\n        eventArgs,\n        error,\n        context\n    );\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_lobby_session.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerLobbySession::MultiplayerLobbySession(\n    _In_ std::shared_ptr<MultiplayerClientManager> multiplayerClientManagerInstance\n    ):\n    m_multiplayerClientManager(std::move(multiplayerClientManagerInstance)),\n    m_changeNumber(0),\n    m_sessionReference{},\n    m_sessionConstants{},\n    m_memberInitialization{}\n{\n}\n\nMultiplayerLobbySession::MultiplayerLobbySession():\n    m_changeNumber(0),\n    m_sessionReference{},\n    m_sessionConstants{},\n    m_memberInitialization{}\n{\n}\n\nMultiplayerLobbySession::MultiplayerLobbySession(_In_ const MultiplayerLobbySession& other):\n    m_multiplayerClientManager(other.m_multiplayerClientManager),\n    m_correlationId(other.m_correlationId),\n    m_changeNumber(other.m_changeNumber),\n    m_sessionReference(other.m_sessionReference),\n    m_host(other.m_host),\n    m_members(other.m_members),\n    m_localMembers(other.m_localMembers),\n    m_customPropertiesJson(other.m_customPropertiesJson)\n{\n    DeepCopyConstants(other.m_sessionConstants);\n}\n\nMultiplayerLobbySession::MultiplayerLobbySession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ std::shared_ptr<MultiplayerMember> host,\n    _In_ const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& members,\n    _In_ const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& localMembers\n    ) :\n    m_correlationId(session->SessionInfo().CorrelationId),\n    m_changeNumber(session->SessionInfo().ChangeNumber),\n    m_sessionReference(session->SessionReference()),\n    m_host(std::move(host)),\n    m_members(members),\n    m_localMembers(localMembers)\n{\n    XblMultiplayerSessionReadLockGuard sessionSafe(session);\n    m_customPropertiesJson = sessionSafe.SessionProperties().SessionCustomPropertiesJson;\n    m_sessionConstants = sessionSafe.SessionConstants();\n    DeepCopyConstants(sessionSafe.SessionConstants());\n}\n\nMultiplayerLobbySession::~MultiplayerLobbySession()\n{\n}\n\nHRESULT\nMultiplayerLobbySession::AddLocalUser(\n    _In_ xbox_live_user_t user\n    )\n{\n    if (m_multiplayerClientManager->LatestPendingRead() == nullptr)\n    {\n        m_multiplayerClientManager->Initialize();\n    }\n    return m_multiplayerClientManager->LobbyClient()->AddLocalUser(user, MultiplayerLocalUserLobbyState::Add);\n}\n\nHRESULT\nMultiplayerLobbySession::RemoveLocalUser(\n    _In_ xbox_live_user_t user\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->LobbyClient()->RemoveLocalUser(user);\n}\n\nHRESULT\nMultiplayerLobbySession::SetLocalMemberProperties(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->LobbyClient()->SetLocalMemberProperties(user, name, valueJson, context);\n}\n\nHRESULT\nMultiplayerLobbySession::DeleteLocalMemberProperties(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& name,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->LobbyClient()->DeleteLocalMemberProperties(user, name, context);\n}\n\nHRESULT\nMultiplayerLobbySession::SetLocalMemberConnectionAddress(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& connectionAddress,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->LobbyClient()->SetLocalMemberConnectionAddress(user, connectionAddress, context);\n}\n\nconst XblMultiplayerSessionReference&\nMultiplayerLobbySession::SessionReference() const\n{\n    return m_sessionReference;\n}\n\nconst xsapi_internal_string&\nMultiplayerLobbySession::CorrelationId() const\n{\n    return m_correlationId;\n}\n\nuint64_t\nMultiplayerLobbySession::ChangeNumber() const\n{\n    return m_changeNumber;\n}\n\nstd::shared_ptr<MultiplayerMember>\nMultiplayerLobbySession::Host() const\n{\n    return m_host;\n}\n\nvoid\nMultiplayerLobbySession::SetHost(\n    _In_ std::shared_ptr<MultiplayerMember> hostMember\n    )\n{\n    m_host = hostMember;\n}\n\nconst xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>&\nMultiplayerLobbySession::Members() const\n{\n    return m_members;\n}\n\nconst XblMultiplayerSessionConstants&\nMultiplayerLobbySession::SessionConstants() const\n{\n    return m_sessionConstants;\n}\n\nconst xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>&\nMultiplayerLobbySession::LocalMembers() const\n{\n    return m_localMembers;\n}\n\nconst xsapi_internal_string&\nMultiplayerLobbySession::CustomPropertiesJson() const\n{\n    return m_customPropertiesJson;\n}\n\nHRESULT\nMultiplayerLobbySession::SetProperties(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->SetProperties(m_sessionReference, name, valueJson, context);\n}\n\nbool\nMultiplayerLobbySession::IsHost(\n    _In_ uint64_t xuid\n    )\n{\n    if (m_host == nullptr || m_members.size() == 0)\n    {\n        return false;\n    }\n\n    return xuid == m_host->Xuid();\n}\n\nHRESULT\nMultiplayerLobbySession::SetSynchronizedHost(\n    _In_ const xsapi_internal_string& hostDeviceToken,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->SetSynchronizedHost(m_sessionReference, hostDeviceToken, context);\n}\n\nHRESULT\nMultiplayerLobbySession::SetSynchronizedProperties(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->SetSynchronizedProperties(m_sessionReference, name, valueJson, context);\n}\n\nvoid\nMultiplayerLobbySession::SetMultiplayerClientManager(\n    _In_ std::shared_ptr<MultiplayerClientManager> clientManager\n    )\n{\n    m_multiplayerClientManager = clientManager;\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\nHRESULT\nMultiplayerLobbySession::InviteFriends(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_string& contextStringId,\n    _In_ const xsapi_internal_string& customActivationContext\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->InviteFriends(user, contextStringId, customActivationContext);\n}\n#endif\n\nHRESULT\nMultiplayerLobbySession::InviteUsers(\n    _In_ xbox_live_user_t user,\n    _In_ const xsapi_internal_vector<uint64_t>& xboxUserIds,\n    _In_ const xsapi_internal_string& contextStringId,\n    _In_ const xsapi_internal_string& customActivationContext\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager->LatestPendingRead() == nullptr, E_UNEXPECTED, \"No user added. Call add_local_user() first.\");\n    return m_multiplayerClientManager->InviteUsers(user, xboxUserIds, contextStringId, customActivationContext);\n}\n\nvoid MultiplayerLobbySession::DeepCopyConstants(const XblMultiplayerSessionConstants& other)\n{\n    m_sessionConstants = other;\n    m_initiatorXuids = xsapi_internal_vector<uint64_t>(other.InitiatorXuids, other.InitiatorXuids + other.InitiatorXuidsCount);\n    m_sessionConstants.InitiatorXuids = m_initiatorXuids.data();\n    if (m_sessionConstants.MemberInitialization)\n    {\n        m_memberInitialization = *m_sessionConstants.MemberInitialization;\n        m_sessionConstants.MemberInitialization = &m_memberInitialization;\n    }\n    if (m_sessionConstants.CustomJson)\n    {\n        m_constantsCustomJson = m_sessionConstants.CustomJson;\n        m_sessionConstants.CustomJson = m_constantsCustomJson.data();\n    }\n    if (m_sessionConstants.SessionCloudComputePackageConstantsJson)\n    {\n        m_constantsCloudComputePackageJson = m_sessionConstants.SessionCloudComputePackageConstantsJson;\n        m_sessionConstants.SessionCloudComputePackageConstantsJson = m_constantsCloudComputePackageJson.data();\n    }\n    if (m_sessionConstants.MeasurementServerAddressesJson)\n    {\n        m_constantsMeasurementServerAddressesJson = m_sessionConstants.MeasurementServerAddressesJson;\n        m_sessionConstants.MeasurementServerAddressesJson = m_constantsMeasurementServerAddressesJson.data();\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_local_user.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services::multiplayer;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerLocalUser::MultiplayerLocalUser(\n    _In_ User&& user,\n    _In_ uint64_t xuid,\n    _In_ bool isPrimary\n) :\n    m_sessionChangedContext(0),\n    m_subscriptionLostContext(0),\n    m_rtaResyncContext(0),\n    m_writeChangesToService(false),\n    m_xuid(xuid),\n    m_lobbyState(MultiplayerLocalUserLobbyState::Unknown),\n    m_gameState(MultiplayerLocalUserGameState::Unknown),\n    m_isPrimaryXboxLiveContext(isPrimary)\n{\n    // TODO parameterize RTAManager\n    m_xboxLiveContextImpl = XblContext::Make(std::move(user));\n\n    m_xboxLiveContextImpl->Initialize(GlobalState::Get()->RTAManager());\n    m_xboxLiveContextImpl->Settings()->SetHttpUserAgent(HttpCallAgent::MultiplayerManager);\n}\n\nMultiplayerLocalUser::~MultiplayerLocalUser()\n{\n    m_xboxLiveContextImpl.reset();\n}\n\nuint64_t\nMultiplayerLocalUser::Xuid() const\n{\n    return m_xuid;\n}\n\nMultiplayerLocalUserLobbyState\nMultiplayerLocalUser::LobbyState() const\n{\n    return m_lobbyState;\n}\n\nvoid\nMultiplayerLocalUser::SetLobbyState(\n    _In_ MultiplayerLocalUserLobbyState userState\n    )\n{\n    m_lobbyState = userState;\n\n    if (userState == MultiplayerLocalUserLobbyState::Add ||\n        userState == MultiplayerLocalUserLobbyState::Join ||\n        userState == MultiplayerLocalUserLobbyState::Leave )\n    {\n        m_writeChangesToService = true;\n    }\n}\n\nMultiplayerLocalUserGameState\nMultiplayerLocalUser::GameState() const\n{\n    return m_gameState;\n}\n\nvoid\nMultiplayerLocalUser::SetGameState(\n    _In_ MultiplayerLocalUserGameState userState\n    )\n{\n    m_gameState = userState;\n}\n\nconst xsapi_internal_string&\nMultiplayerLocalUser::LobbyHandleId() const\n{\n    return m_lobbyHandleId;\n}\n\nvoid\nMultiplayerLocalUser::SetLobbyHandleId(_In_ const xsapi_internal_string& handleId)\n{\n    m_lobbyHandleId = handleId;\n}\n\nconst xsapi_internal_string&\nMultiplayerLocalUser::ConnectionAddress() const\n{\n    return m_connectionAddress;\n}\n\nvoid\nMultiplayerLocalUser::SetConnectionAddress(_In_ const xsapi_internal_string& address)\n{\n    m_connectionAddress = address;\n}\n\nbool\nMultiplayerLocalUser::IsPrimaryXboxLiveContext() const\n{\n    return m_isPrimaryXboxLiveContext;\n}\n\nvoid\nMultiplayerLocalUser::SetIsPrimaryXboxLiveContext(\n    _In_ bool isPrimary\n    )\n{\n    m_isPrimaryXboxLiveContext = isPrimary;\n}\n\nbool\nMultiplayerLocalUser::WriteChangesToService() const\n{\n    return m_writeChangesToService;\n}\n\nvoid\nMultiplayerLocalUser::SetWriteChangesToService(_In_ bool value)\n{\n    m_writeChangesToService = value;\n}\n\nstd::shared_ptr<XblContext>\nMultiplayerLocalUser::Context() const\n{\n    return m_xboxLiveContextImpl;\n}\n\nXblFunctionContext\nMultiplayerLocalUser::SessionChangedContext() const\n{\n    return m_sessionChangedContext;\n}\n\nvoid\nMultiplayerLocalUser::SetSessionChangedContext(\n    _In_ XblFunctionContext functionContext\n    )\n{\n    m_sessionChangedContext = functionContext;\n}\n\nXblFunctionContext\nMultiplayerLocalUser::ConnectionIdChangedContext() const\n{\n    return m_connectionIdChangedContext;\n}\n\nvoid\nMultiplayerLocalUser::SetConnectionIdChangedContext(\n    _In_ XblFunctionContext functionContext\n)\n{\n    m_connectionIdChangedContext = functionContext;\n}\n\nXblFunctionContext\nMultiplayerLocalUser::SubscriptionLostContext() const\n{\n    return m_subscriptionLostContext;\n}\n\nvoid\nMultiplayerLocalUser::SetSubscriptionLostContext(\n    _In_ XblFunctionContext functionContext\n    )\n{\n    m_subscriptionLostContext = functionContext;\n}\n\nXblFunctionContext\nMultiplayerLocalUser::RtaResyncContext() const\n{\n    return m_rtaResyncContext;\n}\n\nvoid\nMultiplayerLocalUser::SetRtaResyncContext(\n    _In_ XblFunctionContext functionContext\n    )\n{\n    m_rtaResyncContext = functionContext;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_local_user_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::multiplayer;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerLocalUserManager::~MultiplayerLocalUserManager()\n{\n    ChangeAllLocalUserLobbyState(MultiplayerLocalUserLobbyState::Remove);\n    RemoveStaleLocalUsersFromMap();\n\n    m_sessionChangeEventHandler.clear();\n    m_multiplayerSubscriptionLostEventHandler.clear();\n    m_rtaResyncEventHandler.clear();\n}\n\nconst xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>&\nMultiplayerLocalUserManager::GetLocalUserMap()\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    return m_localUserRequestMap;\n}\n\nstd::shared_ptr<XblContext>\nMultiplayerLocalUserManager::GetContext(\n    _In_ uint64_t xboxUserId\n)\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    auto iter = m_localUserRequestMap.find(xboxUserId);\n    if (iter != m_localUserRequestMap.end())\n    {\n        return iter->second->Context();\n    }\n    return nullptr;\n}\n\nstd::shared_ptr<MultiplayerLocalUser>\nMultiplayerLocalUserManager::GetLocalUser(\n    _In_ xbox_live_user_t user\n    )\n{\n    if (user == nullptr)\n    {\n        return nullptr;\n    }\n\n    std::lock_guard<std::mutex> lock(m_lock);\n    return GetLocalUserHelper(user);\n}\n\nstd::shared_ptr<MultiplayerLocalUser>\nMultiplayerLocalUserManager::GetLocalUser(\n    _In_ uint64_t xuid\n    )\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    return GetLocalUserHelper(xuid);\n}\n\nstd::shared_ptr<MultiplayerLocalUser>\nMultiplayerLocalUserManager::GetLocalUserHelper(\n    _In_ xbox_live_user_t user\n    )\n{\n    auto wrapUserResult{ User::WrapHandle(user) };\n    if (Failed(wrapUserResult))\n    {\n        return nullptr;\n    }\n\n    return GetLocalUserHelper(wrapUserResult.Payload().Xuid());\n}\n\nstd::shared_ptr<MultiplayerLocalUser>\nMultiplayerLocalUserManager::GetLocalUserHelper(\n    _In_ uint64_t xuid\n    )\n{\n    auto iter = m_localUserRequestMap.find(xuid);\n    if (iter != m_localUserRequestMap.end())\n    {\n        return iter->second;\n    }\n    return nullptr;\n}\n\nstd::shared_ptr<XblContext>\nMultiplayerLocalUserManager::GetPrimaryContext()\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    return m_primaryXboxLiveContext;\n}\n\nvoid\nMultiplayerLocalUserManager::ChangeAllLocalUserLobbyState(\n    _In_ MultiplayerLocalUserLobbyState state\n    )\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    for(const auto& user : m_localUserRequestMap)\n    {\n        const auto& localUser =  user.second;\n        if (localUser != nullptr)\n        {\n            localUser->SetLobbyState(state);\n        }\n    }\n}\n\nvoid\nMultiplayerLocalUserManager::ChangeAllLocalUserGameState(\n    _In_ MultiplayerLocalUserGameState state\n    )\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    for(const auto& user : m_localUserRequestMap)\n    {\n        const auto& localUser =  user.second;\n        if (localUser != nullptr)\n        {\n            localUser->SetGameState(state);\n        }\n    }\n}\n\nbool\nMultiplayerLocalUserManager::IsLocalUserGameState(\n    _In_ MultiplayerLocalUserGameState state\n    )\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    for(const auto& user : m_localUserRequestMap)\n    {\n        const auto& localUser =  user.second;\n        if (localUser != nullptr && localUser->GameState() != state)\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nResult<const std::shared_ptr<MultiplayerLocalUser>>\nMultiplayerLocalUserManager::AddUserToXboxLiveContextToMap(\n    _In_ xbox_live_user_t user\n    )\n{\n    auto wrapUserResult{ User::WrapHandle(user) };\n    if (Failed(wrapUserResult))\n    {\n        return wrapUserResult.Hresult();\n    }\n\n    uint64_t xboxUserId = wrapUserResult.Payload().Xuid();\n\n    bool isPrimary = m_localUserRequestMap.size() == 0 ? true : false;\n\n    auto iter = m_localUserRequestMap.find(xboxUserId);\n    if (iter == m_localUserRequestMap.end())\n    {\n        auto innerWrapUserResult{ User::WrapHandle(user) };\n        if (Failed(innerWrapUserResult))\n        {\n            return innerWrapUserResult.Hresult();\n        }\n\n        auto localUser = MakeShared<MultiplayerLocalUser>(\n            innerWrapUserResult.ExtractPayload(),\n            xboxUserId,\n            isPrimary\n            );\n\n        auto ret = m_localUserRequestMap.insert(std::pair<uint64_t, std::shared_ptr<MultiplayerLocalUser>>(xboxUserId, localUser));\n        iter = ret.first;\n\n        if (isPrimary)\n        {\n            m_primaryXboxLiveContext = localUser->Context();\n        }\n\n        // Activate events only for all users\n        ActivateMultiplayerEvents(localUser);\n    }\n\n    return iter->second;\n}\n\nvoid\nMultiplayerLocalUserManager::RemoveStaleLocalUsersFromMap()\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    bool swtichPrimaryXboxLiveContext = false;\n    for(auto iter = m_localUserRequestMap.begin(); iter != m_localUserRequestMap.end(); )\n    {\n        const auto& localUser =  iter->second;\n        if (localUser != nullptr && localUser->LobbyState() == MultiplayerLocalUserLobbyState::Remove)\n        {\n            // De-activate rta events for the old user.\n            DeactivateMultiplayerEvents(localUser);\n\n            swtichPrimaryXboxLiveContext = localUser->IsPrimaryXboxLiveContext();\n            m_localUserRequestMap.erase(iter++);\n        }\n        else\n        {\n            ++iter;\n        }\n    }\n\n    if (m_localUserRequestMap.size() == 0)\n    {\n        m_primaryXboxLiveContext = nullptr;\n        return;\n    }\n\n    if (swtichPrimaryXboxLiveContext)\n    {\n        // Assign the first guy in the map to be the primary user.\n        std::shared_ptr<MultiplayerLocalUser> user = m_localUserRequestMap.begin()->second;\n        if (user != nullptr)\n        {\n            user->SetIsPrimaryXboxLiveContext(true);\n            m_primaryXboxLiveContext = user->Context();\n        }\n    }\n}\n\nvoid\nMultiplayerLocalUserManager::ActivateMultiplayerEvents(\n    _In_ const std::shared_ptr<MultiplayerLocalUser>& localUser\n    )\n{\n    XSAPI_ASSERT(localUser != nullptr);\n    if (localUser == nullptr) return;\n\n    std::weak_ptr<MultiplayerLocalUserManager> weakThis = shared_from_this();\n    auto xboxUserId = localUser->Xuid();\n\n    if (auto globalState{ GlobalState::Get() })\n    {\n        globalState->RTAManager()->Activate(localUser->Context()->User());\n\n        XblFunctionContext rtaResyncContext = globalState->RTAManager()->AddResyncHandler(localUser->Context()->User(), \n            [weakThis]\n        {\n            std::shared_ptr<MultiplayerLocalUserManager> pThis(weakThis.lock());\n            if (pThis != nullptr)\n            {\n                pThis->OnResyncMessageReceived();\n            }\n        });\n        localUser->SetRtaResyncContext(rtaResyncContext);\n    }\n\n    if (!localUser->Context()->MultiplayerService()->SubscriptionsEnabled())\n    {\n        localUser->Context()->MultiplayerService()->EnableMultiplayerSubscriptions();\n        XblFunctionContext sessionChangedContext = localUser->Context()->MultiplayerService()->AddMultiplayerSessionChangedHandler([weakThis](_In_ XblMultiplayerSessionChangeEventArgs args)\n        {\n            std::shared_ptr<MultiplayerLocalUserManager> pThis(weakThis.lock());\n            if (pThis != nullptr)\n            {\n                pThis->OnSessionChanged(args);\n            }\n        });\n        localUser->SetSessionChangedContext(sessionChangedContext);\n\n        XblFunctionContext connectionIdChangedContext = localUser->Context()->MultiplayerService()->AddMultiplayerConnectionIdChangedHandler([weakThis](const String&)\n        {\n            std::shared_ptr<MultiplayerLocalUserManager> pThis(weakThis.lock());\n            if (pThis != nullptr)\n            {\n                pThis->OnConnectionIdChanged();\n            }\n        });\n        localUser->SetConnectionIdChangedContext(connectionIdChangedContext);\n\n        XblFunctionContext subscriptionLostContext = localUser->Context()->MultiplayerService()->AddMultiplayerSubscriptionLostHandler([weakThis, xboxUserId](void)\n        {\n            std::shared_ptr<MultiplayerLocalUserManager> pThis(weakThis.lock());\n            if (pThis != nullptr)\n            {\n                pThis->OnSubscriptionsLost(xboxUserId);\n            }\n        });\n        localUser->SetSubscriptionLostContext(subscriptionLostContext);\n    }\n}\n\nvoid MultiplayerLocalUserManager::DeactivateMultiplayerEvents(\n    _In_ const std::shared_ptr<MultiplayerLocalUser>& localUser\n)\n{\n    XSAPI_ASSERT(localUser != nullptr);\n    if (localUser == nullptr)\n    {\n        return;\n    }\n\n    // TODO allow setting queue\n    HRESULT hr = m_queue.RunWork([localUser = std::shared_ptr<MultiplayerLocalUser>{ localUser }]\n    {\n        if (localUser->Context()->MultiplayerService()->SubscriptionsEnabled())\n        {\n            localUser->Context()->MultiplayerService()->RemoveMultiplayerSessionChangedHandler(localUser->SessionChangedContext());\n            localUser->Context()->MultiplayerService()->DisableMultiplayerSubscriptions();\n            localUser->Context()->MultiplayerService()->RemoveMultiplayerConnectionIdChangedHandler(localUser->ConnectionIdChangedContext());\n        }\n        auto globalState{ GlobalState::Get() };\n        if (globalState != nullptr)\n        {\n            globalState->RTAManager()->RemoveResyncHandler(localUser->Context()->User(), localUser->RtaResyncContext());\n            globalState->RTAManager()->Deactivate(localUser->Context()->User());\n        }\n    });\n\n    if (FAILED(hr))\n    {\n        LOGS_INFO << __FUNCTION__ << \" RunAsync failed with hr=\" << hr;\n    }\n}\n\nXblFunctionContext\nMultiplayerLocalUserManager::AddMultiplayerSessionChangedHandler(\n    _In_ Callback<XblMultiplayerSessionChangeEventArgs> handler\n    )\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n\n    XblFunctionContext context = 0;\n    if (handler != nullptr)\n    {\n        context = m_sessionChangeEventHandlerCounter;\n        m_sessionChangeEventHandler[m_sessionChangeEventHandlerCounter++] = std::move(handler);\n    }\n\n    return context;\n}\n\nvoid\nMultiplayerLocalUserManager::RemoveMultiplayerSessionChangedHandler(\n    _In_ XblFunctionContext context\n    )\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n    m_sessionChangeEventHandler.erase(context);\n}\n\nvoid\nMultiplayerLocalUserManager::OnSessionChanged(\n    _In_ const XblMultiplayerSessionChangeEventArgs& args\n    )\n{\n    xsapi_internal_unordered_map<uint32_t, Callback<XblMultiplayerSessionChangeEventArgs>> sessionChangeEventHandlerCopy;\n    {\n        std::lock_guard<std::mutex> lock(m_subscriptionLock);\n        sessionChangeEventHandlerCopy = m_sessionChangeEventHandler;\n    }\n\n    for(auto& handler : sessionChangeEventHandlerCopy)\n    {\n        XSAPI_ASSERT(handler.second != nullptr);\n        if (handler.second != nullptr)\n        {\n            try\n            {\n                handler.second(args);\n            }\n            catch (...)\n            {\n                LOG_ERROR(\"MultiplayerLocalUserManager::on_session_changed call threw an exception\");\n            }\n        }\n    }\n}\n\nXblFunctionContext\nMultiplayerLocalUserManager::AddMultiplayerConnectionIdChangedHandler(\n    _In_ Function<void()> handler\n)\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n\n    XblFunctionContext context = 0;\n    if (handler != nullptr)\n    {\n        context = m_multiplayerConnectionIdChangedEventHandlerCounter;\n        m_multiplayerConnectionIdChangedEventHandler[m_multiplayerConnectionIdChangedEventHandlerCounter++] = std::move(handler);\n    }\n\n    return context;\n}\n\nvoid\nMultiplayerLocalUserManager::RemoveMultiplayerConnectionIdChangedHandler(\n    _In_ XblFunctionContext context\n)\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n    m_multiplayerConnectionIdChangedEventHandler.erase(context);\n}\n\nvoid\nMultiplayerLocalUserManager::OnConnectionIdChanged(\n)\n{\n    xsapi_internal_unordered_map<uint32_t, Function<void()>> multiplayerConnectionIdChangedEventHandlerCopy;\n    {\n        std::lock_guard<std::mutex> lock(m_subscriptionLock);\n        multiplayerConnectionIdChangedEventHandlerCopy = m_multiplayerConnectionIdChangedEventHandler;\n    }\n\n    for (auto& handler : multiplayerConnectionIdChangedEventHandlerCopy)\n    {\n        XSAPI_ASSERT(handler.second != nullptr);\n        if (handler.second != nullptr)\n        {\n            try\n            {\n                handler.second();\n            }\n            catch (...)\n            {\n                LOG_ERROR(\"MultiplayerLocalUserManager::on_connection_id_changed call threw an exception\");\n            }\n        }\n    }\n}\n\nXblFunctionContext\nMultiplayerLocalUserManager::AddMultiplayerSubscriptionLostHandler(\n    _In_ Function<void()> handler\n    )\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n\n    XblFunctionContext context = 0;\n    if (handler != nullptr)\n    {\n        context = m_multiplayerSubscriptionLostEventHandlerCounter;\n        m_multiplayerSubscriptionLostEventHandler[m_multiplayerSubscriptionLostEventHandlerCounter++] = std::move(handler);\n    }\n\n    return context;\n}\n\nvoid\nMultiplayerLocalUserManager::RemoveMultiplayerSubscriptionLostHandler(\n    _In_ XblFunctionContext context\n    )\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n    m_multiplayerSubscriptionLostEventHandler.erase(context);\n}\n\nvoid\nMultiplayerLocalUserManager::OnSubscriptionsLost(\n    _In_ uint64_t xuid\n    )\n{\n    {\n        // Only fire this for the last user.\n        // Note: This will be fired from the previous user's deactivation.\n        std::lock_guard<std::mutex> lock(m_lock);\n        auto user = GetLocalUserHelper(xuid);\n        if (user == nullptr && m_localUserRequestMap.size() > 0)\n        {\n            return;\n        }\n    }\n\n    xsapi_internal_unordered_map<uint32_t, Function<void()>> multiplayerSubscriptionLostEventHandlerCopy;\n    {\n        std::lock_guard<std::mutex> lock(m_subscriptionLock);\n        multiplayerSubscriptionLostEventHandlerCopy = m_multiplayerSubscriptionLostEventHandler;\n    }\n\n    for(auto& handler : multiplayerSubscriptionLostEventHandlerCopy)\n    {\n        XSAPI_ASSERT(handler.second != nullptr);\n        if (handler.second != nullptr)\n        {\n            try\n            {\n                handler.second();\n            }\n            catch (...)\n            {\n                LOG_ERROR(\"MultiplayerLocalUserManager::on_subscriptions_lost call threw an exception\");\n            }\n        }\n    }\n}\n\nXblFunctionContext\nMultiplayerLocalUserManager::AddRtaResyncHandler(\n    _In_ Function<void()> handler\n    )\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n\n    XblFunctionContext context = 0;\n    if (handler != nullptr)\n    {\n        context = m_rtaResyncEventHandlerCounter;\n        m_rtaResyncEventHandler[m_rtaResyncEventHandlerCounter++] = std::move(handler);\n    }\n\n    return context;\n}\n\nvoid\nMultiplayerLocalUserManager::RemoveRtaResyncHandler(\n    _In_ XblFunctionContext context\n    )\n{\n    std::lock_guard<std::mutex> lock(m_subscriptionLock);\n    m_rtaResyncEventHandler.erase(context);\n}\n\nvoid\nMultiplayerLocalUserManager::OnResyncMessageReceived()\n{\n    xsapi_internal_unordered_map<uint32_t, Function<void()>> rtaResyncEventHandlerCopy;\n    {\n        std::lock_guard<std::mutex> lock(m_subscriptionLock);\n        rtaResyncEventHandlerCopy = m_rtaResyncEventHandler;\n    }\n\n    for(auto& handler : rtaResyncEventHandlerCopy)\n    {\n        XSAPI_ASSERT(handler.second != nullptr);\n        if (handler.second != nullptr)\n        {\n            try\n            {\n                handler.second();\n            }\n            catch (...)\n            {\n                LOG_ERROR(\"MultiplayerLocalUserManager::on_resync_message_received call threw an exception\");\n            }\n        }\n    }\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services::multiplayer::manager;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerManager::~MultiplayerManager()\n{\n    if (m_queue)\n    {\n        XTaskQueueCloseHandle(m_queue);\n    }\n\n    if (m_multiplayerClientManager != nullptr)\n    {\n        m_multiplayerClientManager->Shutdown();\n    }\n}\n\nbool MultiplayerManager::IsInitialized()\n{\n    return m_multiplayerClientManager != nullptr;\n}\n\nvoid MultiplayerManager::Initialize(\n    _In_ const xsapi_internal_string& lobbySessionTemplateName,\n    _In_opt_ XTaskQueueHandle asyncQueue\n)\n{\n    XSAPI_ASSERT(!lobbySessionTemplateName.empty());\n\n    if (asyncQueue)\n    {\n        XTaskQueueDuplicateHandle(asyncQueue, &m_queue);\n    }\n\n    std::lock_guard<std::mutex> guard(m_lock);\n    if(m_multiplayerClientManager != nullptr)\n    {\n        m_multiplayerClientManager->Shutdown();\n\n        m_multiplayerLobbySession = nullptr;\n        m_multiplayerGameSession = nullptr;\n        m_multiplayerClientManager = nullptr;\n    }\n\n    m_multiplayerClientManager = MakeShared<MultiplayerClientManager>(lobbySessionTemplateName, m_queue);\n\n    m_multiplayerClientManager->RegisterLocalUserManagerEvents();\n    m_multiplayerLobbySession = MakeShared<MultiplayerLobbySession>(m_multiplayerClientManager);\n}\n\nbool MultiplayerManager::IsDirty()\n{\n    return m_isDirty;\n}\n\nconst MultiplayerEventQueue& MultiplayerManager::DoWork()\n{\n    std::lock_guard<std::mutex> guard(m_lock);\n    m_eventQueue.Clear();\n\n    if (!IsInitialized())\n    {\n        // The title hasn't called initialize() on the manager yet.\n        m_isDirty = false;\n        return m_eventQueue;\n    }\n    else if (!m_multiplayerClientManager->IsUpdateAvailable())\n    {\n        m_isDirty = false;\n\n        // To handle the scenario of returning InvitedXuid info in the join_lobby_completed event\n        if (m_multiplayerClientManager->EventQueue().Size() > 0)\n        {\n            m_eventQueue = m_multiplayerClientManager->EventQueue();\n            m_multiplayerClientManager->ClearEventQueue();\n        }\n\n        return m_eventQueue;\n    }\n\n    try\n    {\n        m_isDirty = true;\n        m_eventQueue = m_multiplayerClientManager->DoWork();\n\n        std::shared_ptr<MultiplayerClientPendingReader> clientRequest = m_multiplayerClientManager->LastPendingRead();\n        if (clientRequest != nullptr)\n        {\n            m_joinability = clientRequest->LobbyClient()->Joinability();\n            SetMultiplayerGameSession(clientRequest->GameClient()->Game());\n            SetMultiplayerLobbySession(clientRequest->LobbyClient()->Lobby());\n        }\n        else\n        {\n            m_joinability = XblMultiplayerJoinability::None;\n            SetMultiplayerGameSession(nullptr);\n            SetMultiplayerLobbySession(nullptr);\n        }\n    }\n    catch(...){}\n\n    return m_eventQueue;\n}\n\nstd::shared_ptr<MultiplayerGameSession>\nMultiplayerManager::GameSession() const\n{\n    std::lock_guard<std::mutex> guard(m_lock);\n    return m_multiplayerGameSession;\n}\n\nstd::shared_ptr<MultiplayerLobbySession>\nMultiplayerManager::LobbySession() const\n{\n    std::lock_guard<std::mutex> guard(m_lock);\n    return m_multiplayerLobbySession;\n}\n\nvoid\nMultiplayerManager::SetMultiplayerGameSession(\n    _In_ std::shared_ptr<MultiplayerGameSession> gameSession\n    ) \n{\n    // Note: This function does not require a lock as the functions that call this already has a m_lock.\n\n    if (gameSession == nullptr)\n    {\n        m_multiplayerGameSession = nullptr;\n    }\n    else\n    {\n        m_multiplayerGameSession = gameSession;\n        m_multiplayerGameSession->SetMultiplayerClientManager(m_multiplayerClientManager);\n    }\n}\n\nvoid\nMultiplayerManager::SetMultiplayerLobbySession(\n    _In_ std::shared_ptr<MultiplayerLobbySession> multiplayerLobby\n    ) \n{\n    // Note: This function does not require a lock as the functions that call this already has a m_lock.\n\n    if (multiplayerLobby == nullptr)\n    {\n        if (m_multiplayerLobbySession != nullptr)\n        {\n            m_multiplayerLobbySession.reset();\n        }\n\n        // Don't set the lobby to null so that the title can add local users whenever it chooses.\n        m_multiplayerLobbySession = MakeShared<MultiplayerLobbySession>(m_multiplayerClientManager);\n    }\n    else\n    {\n        m_multiplayerLobbySession = multiplayerLobby;\n        m_multiplayerLobbySession->SetMultiplayerClientManager(m_multiplayerClientManager);\n    }\n}\n\nHRESULT\nMultiplayerManager::JoinLobby(\n    _In_ const xsapi_internal_string& handleId,\n    _In_ xbox_live_user_t user\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager == nullptr, E_UNEXPECTED, \"Call multiplayer_manager::initialize() first.\");\n\n    xsapi_internal_vector<xbox_live_user_t> users;\n    users.push_back(user);\n    return m_multiplayerClientManager->JoinLobbyByHandle(handleId, users);\n}\n\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK \nHRESULT\nMultiplayerManager::JoinLobby(\n    _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n    _In_ xbox_live_user_t user\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager == nullptr, E_UNEXPECTED, \"Call multiplayer_manager::initialize() first.\");\n\n    xsapi_internal_vector<xbox_live_user_t> users{ user };\n    return m_multiplayerClientManager->JoinLobby(eventArgs, users);\n}\n#endif\n\nHRESULT\nMultiplayerManager::JoinGameFromLobby(\n    _In_ const xsapi_internal_string& sessionTemplateName\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager == nullptr, E_UNEXPECTED, \"Call multiplayer_manager::initialize() first.\");\n    return m_multiplayerClientManager->JoinGameFromLobby(sessionTemplateName);\n}\n\nHRESULT\nMultiplayerManager::JoinGame(\n    _In_ const xsapi_internal_string& sessionName,\n    _In_ const xsapi_internal_string& sessionTemplateName,\n    _In_ const xsapi_internal_vector<uint64_t>& xuids\n    )\n{\n    RETURN_HR_IF(m_multiplayerClientManager == nullptr, E_UNEXPECTED);\n    RETURN_EXCEPTION_FREE_HRESULT(m_multiplayerClientManager->JoinGame(sessionName, sessionTemplateName, xuids));\n}\n\nHRESULT\nMultiplayerManager::LeaveGame()\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager == nullptr, E_UNEXPECTED, \"Call multiplayer_manager::initialize() first.\");\n    return m_multiplayerClientManager->LeaveGame();\n}\n\nHRESULT\nMultiplayerManager::FindMatch(\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ JsonValue& attributes,\n    _In_ const std::chrono::seconds& timeout\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager == nullptr, E_UNEXPECTED, \"Call multiplayer_manager::initialize() first.\");\n    return m_multiplayerClientManager->FindMatch(hopperName, attributes, timeout);\n}\n\nvoid\nMultiplayerManager::CancelMatch()\n{\n    if (m_multiplayerClientManager != nullptr && m_multiplayerClientManager->MatchClient() != nullptr)\n    {\n        m_multiplayerClientManager->MatchClient()->CancelMatch();\n    }\n}\n\nXblMultiplayerMatchStatus\nMultiplayerManager::MatchStatus() const\n{\n    if (m_multiplayerClientManager != nullptr && m_multiplayerClientManager->MatchClient() != nullptr)\n    {\n        return m_multiplayerClientManager->MatchClient()->MatchStatus();\n    }\n\n    return XblMultiplayerMatchStatus::None;\n}\n\nstd::chrono::seconds\nMultiplayerManager::EstimatedMatchWaitTime() const\n{\n    if (m_multiplayerClientManager != nullptr && m_multiplayerClientManager->MatchClient() != nullptr)\n    {\n        return m_multiplayerClientManager->MatchClient()->EstimatedMatchWaitTime();\n    }\n\n    return std::chrono::seconds(0);\n}\n\nvoid\nMultiplayerManager::SetQosMeasurements(\n    _In_ const JsonValue& measurements\n    )\n{\n    if (m_multiplayerClientManager != nullptr && m_multiplayerClientManager->MatchClient() != nullptr)\n    {\n        m_multiplayerClientManager->MatchClient()->SetQosMeasurements(measurements);\n    }\n}\n\nbool\nMultiplayerManager::AutoFillMembersDuringMatchmaking() const\n{\n    return false;\n}\n\nvoid\nMultiplayerManager::SetAutoFillMembersDuringMatchmaking(\n    _In_ bool autoFillMembers\n    )\n{\n    if (m_multiplayerClientManager != nullptr)\n    {\n        m_multiplayerClientManager->SetAutoFillMembersDuringMatchmaking(autoFillMembers);\n    }\n}\n\nXblMultiplayerJoinability\nMultiplayerManager::Joinability() const\n{\n    return m_joinability;\n}\n\nHRESULT\nMultiplayerManager::SetJoinability(\n    _In_ XblMultiplayerJoinability value,\n    _In_opt_ context_t context\n    )\n{\n    RETURN_HR_IF_LOG_DEBUG(m_multiplayerClientManager == nullptr, E_UNEXPECTED, \"Call multiplayer_manager::initialize() first.\");\n    return m_multiplayerClientManager->SetJoinability(value, context);\n}\n\nstd::shared_ptr<MultiplayerGameClient>\nMultiplayerManager::GameClient()\n{\n    auto clientManger = m_multiplayerClientManager;\n    if (clientManger == nullptr || clientManger->LatestPendingRead() == nullptr)\n    {\n        return nullptr;\n    }\n    return clientManger->LatestPendingRead()->GameClient();\n}\n\nstd::shared_ptr<MultiplayerLobbyClient>\nMultiplayerManager::LobbyClient()\n{\n    auto clientManger = m_multiplayerClientManager;\n    if (clientManger == nullptr || clientManger->LatestPendingRead() == nullptr)\n    {\n        return nullptr;\n    }\n    return clientManger->LatestPendingRead()->LobbyClient();\n}\n\n#ifdef XSAPI_UNIT_TESTS\nvoid\nMultiplayerManager::Shutdown()\n{\n    auto clientManger = m_multiplayerClientManager;\n    if (clientManger == nullptr || clientManger->LatestPendingRead() == nullptr)\n    {\n        return;\n    }\n    return clientManger->Shutdown();\n}\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_manager_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::multiplayer::manager;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\ntemplate<typename Ret, typename TWork>\nRet ApiImpl(Ret&& fallbackReturnValue, TWork&& work, bool requireInit = true) noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (!state)\n    {\n        return fallbackReturnValue;\n    }\n\n    assert(state->MultiplayerManager());\n    if (requireInit)\n    {\n        RETURN_HR_IF(state->MultiplayerManager()->IsInitialized() == false, fallbackReturnValue);\n    }\n    return work(*state->MultiplayerManager());\n}\n\ntemplate<typename TWork>\nHRESULT ApiImpl(TWork&& work, bool requireInit = true) noexcept\n{\n    return ApiImpl<HRESULT, TWork>(E_XBL_NOT_INITIALIZED, std::move(work), requireInit);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n\nSTDAPI XblMultiplayerManagerInitialize(\n    _In_z_ const char* lobbySessionTemplateName,\n    _In_opt_ XTaskQueueHandle asyncQueue\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(lobbySessionTemplateName);\n\n            mpm.Initialize(lobbySessionTemplateName, asyncQueue);\n            return S_OK;\n        }, false); // doesn't require init\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerDoWork(\n    _Deref_out_opt_ const XblMultiplayerEvent** multiplayerEvents,\n    _Out_ size_t* multiplayerEventsCount\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(multiplayerEvents);\n\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(multiplayerEvents == nullptr || multiplayerEventsCount == nullptr);\n            auto& events = mpm.DoWork();\n\n            if (!events.Empty())\n            {\n                *multiplayerEvents = &(*events.begin());\n            }\n            else\n            {\n                *multiplayerEvents = nullptr;\n            }\n            *multiplayerEventsCount = events.Size();\n\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerJoinLobby(\n    _In_z_ const char* handleId,\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(handleId);\n            return mpm.JoinLobby(handleId, user);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerJoinGameFromLobby(\n    _In_z_ const char* sessionTemplateName\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(sessionTemplateName);\n            return mpm.JoinGameFromLobby(sessionTemplateName);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerJoinGame(\n    _In_z_ const char* sessionName,\n    _In_z_ const char* sessionTemplateName,\n    _In_opt_ const uint64_t* xuids,\n    _In_ size_t xuidsCount\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(sessionName == nullptr || sessionTemplateName == nullptr || (xuids == nullptr && xuidsCount > 0));\n\n            return mpm.JoinGame(\n                sessionName,\n                sessionTemplateName,\n                xsapi_internal_vector<uint64_t>(xuids, xuids + xuidsCount)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLeaveGame() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([](MultiplayerManager& mpm)\n        {\n            return mpm.LeaveGame();\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerFindMatch(\n    _In_z_ const char* hopperName,\n    _In_opt_z_ const char* attributesJson,\n    _In_ uint32_t timeoutInSeconds\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(hopperName == nullptr);\n\n            JsonDocument json;\n            if (attributesJson)\n            {\n                json.Parse(attributesJson);\n                if (json.HasParseError() &&\n                    json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n                {\n                    return E_INVALIDARG;\n                }\n            }\n\n            return mpm.FindMatch(\n                hopperName,\n                json,\n                std::chrono::seconds(timeoutInSeconds)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerManagerCancelMatch() XBL_NOEXCEPT\ntry\n{\n    ApiImpl([](MultiplayerManager& mpm)\n        {\n            mpm.CancelMatch();\n            return S_OK;\n        });\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(XblMultiplayerMatchStatus) XblMultiplayerManagerMatchStatus() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl(XblMultiplayerMatchStatus::None, [](MultiplayerManager& mpm)\n        {\n            return mpm.MatchStatus();\n        });\n}\nCATCH_RETURN_WITH(XblMultiplayerMatchStatus::None)\n\nSTDAPI_(uint32_t) XblMultiplayerManagerEstimatedMatchWaitTime() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl(0, [](MultiplayerManager& mpm)\n        {\n            return static_cast<uint32_t>(mpm.EstimatedMatchWaitTime().count());\n        });\n}\nCATCH_RETURN_WITH(0)\n\nSTDAPI_(bool) XblMultiplayerManagerAutoFillMembersDuringMatchmaking() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl(false, [](MultiplayerManager& mpm)\n        {\n            return mpm.AutoFillMembersDuringMatchmaking();\n        });\n}\nCATCH_RETURN_WITH(false)\n\nSTDAPI_(void) XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking(\n    _In_ bool autoFillMembers\n) XBL_NOEXCEPT\ntry\n{\n    ApiImpl([&](MultiplayerManager& mpm)\n        {\n            mpm.SetAutoFillMembersDuringMatchmaking(autoFillMembers);\n            return S_OK;\n        });\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblMultiplayerManagerSetQosMeasurements(\n    _In_z_ const char* measurementsJson\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(measurementsJson);\n\n            JsonDocument json;\n            json.Parse(measurementsJson);\n            if (json.HasParseError() &&\n                json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n            {\n                return E_INVALIDARG;\n            }\n\n            mpm.SetQosMeasurements(json);\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(XblMultiplayerJoinability) XblMultiplayerManagerJoinability() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl(XblMultiplayerJoinability::None, [](MultiplayerManager& mpm)\n        {\n            return mpm.Joinability();\n        });\n}\nCATCH_RETURN_WITH(XblMultiplayerJoinability::None)\n\nSTDAPI XblMultiplayerManagerSetJoinability(\n    _In_ XblMultiplayerJoinability joinability,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            return mpm.SetJoinability(joinability, reinterpret_cast<context_t>(context));\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionCorrelationId(\n    _Out_ XblGuid* correlationId\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(correlationId);\n            utils::strcpy(correlationId->value, sizeof(correlationId->value), mpm.LobbySession()->CorrelationId().data());\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionSessionReference(\n    _Out_ XblMultiplayerSessionReference* sessionReference\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(sessionReference);\n            *sessionReference = mpm.LobbySession()->SessionReference();\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(size_t) XblMultiplayerManagerLobbySessionLocalMembersCount() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl<size_t>(0, [](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->LocalMembers().size();\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionLocalMembers(\n    _In_ size_t localMembersCount,\n    _Out_writes_(localMembersCount) XblMultiplayerManagerMember* localMembers\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            auto& localMembersVector = mpm.LobbySession()->LocalMembers();\n            RETURN_HR_INVALIDARGUMENT_IF(localMembersCount < localMembersVector.size());\n            RETURN_HR_INVALIDARGUMENT_IF(localMembers == nullptr && localMembersCount > 0);\n            for (size_t i = 0; i < localMembersVector.size(); ++i)\n            {\n                DISABLE_WARNING_PUSH;\n                SUPPRESS_WARNING_NULL_PTR_DEREFERENCE; // null pointer deref\n                localMembers[i] = localMembersVector[i]->GetReference();\n                DISABLE_WARNING_POP;\n            }\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(size_t) XblMultiplayerManagerLobbySessionMembersCount() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl<size_t>(0, [](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->Members().size();\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionMembers(\n    _In_ size_t membersCount,\n    _Out_writes_(membersCount) XblMultiplayerManagerMember* members\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            auto& membersVector = mpm.LobbySession()->Members();\n            RETURN_HR_INVALIDARGUMENT_IF(membersCount < membersVector.size() || members == nullptr);\n            for (size_t i = 0; i < membersVector.size(); ++i)\n            {\n                members[i] = membersVector[i]->GetReference();\n            }\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionHost(\n    _Out_ XblMultiplayerManagerMember* hostMember\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            if (mpm.LobbySession()->Host())\n            {\n                *hostMember = mpm.LobbySession()->Host()->GetReference();\n                return S_OK;\n            }\n            else\n            {\n                return __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);\n            }\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(const char*) XblMultiplayerManagerLobbySessionPropertiesJson() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl<const char*>(nullptr, [](MultiplayerManager& mpm)-> const char*\n        {\n            auto& customProperties = mpm.LobbySession()->CustomPropertiesJson();\n            if (!customProperties.empty())\n            {\n                return customProperties.data();\n            }\n            return nullptr;\n        });\n    \n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerSessionConstants*) XblMultiplayerManagerLobbySessionConstants() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl<const XblMultiplayerSessionConstants*>(nullptr, [](MultiplayerManager& mpm)\n        {\n            return &mpm.LobbySession()->SessionConstants();\n        });\n}\nCATCH_RETURN_WITH(nullptr)\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\nSTDAPI_(const XblTournamentTeamResult*) XblMultiplayerManagerLobbySessionLastTournamentTeamResult() XBL_NOEXCEPT\ntry\n{\n    return nullptr;\n}\nCATCH_RETURN_WITH(nullptr)\nXBL_WARNING_POP\n\nSTDAPI XblMultiplayerManagerLobbySessionAddLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->AddLocalUser(user);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionRemoveLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->RemoveLocalUser(user);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionSetLocalMemberProperties(\n    _In_ XblUserHandle user,\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n            JsonDocument json;\n            json.Parse(valueJson);\n            if (json.HasParseError() &&\n                json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n            {\n                return E_INVALIDARG;\n            }\n\n            return mpm.LobbySession()->SetLocalMemberProperties(\n                user,\n                name,\n                json,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(\n    _In_ XblUserHandle user,\n    _In_z_ const char* name,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(name);\n            return mpm.LobbySession()->DeleteLocalMemberProperties(\n                user,\n                name,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n    _In_ XblUserHandle user,\n    _In_z_ const char* connectionAddress,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(connectionAddress);\n            return mpm.LobbySession()->SetLocalMemberConnectionAddress(\n                user,\n                connectionAddress,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(bool) XblMultiplayerManagerLobbySessionIsHost(\n    _In_ uint64_t xuid\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl(false, [&](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->IsHost(xuid);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionSetProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n            JsonDocument json;\n            json.Parse(valueJson);\n            if (json.HasParseError() &&\n                json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n            {\n                return E_INVALIDARG;\n            }\n\n            return mpm.LobbySession()->SetProperties(\n                name,\n                json,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n            JsonDocument json;\n            json.Parse(valueJson);\n            if (json.HasParseError() &&\n                json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n            {\n                return E_INVALIDARG;\n            }\n\n            return mpm.LobbySession()->SetSynchronizedProperties(\n                name,\n                json,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerLobbySessionSetSynchronizedHost(\n    _In_ const char* deviceToken,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(deviceToken);\n            return mpm.LobbySession()->SetSynchronizedHost(\n                deviceToken,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\n#if HC_PLATFORM_IS_MICROSOFT\nSTDAPI XblMultiplayerManagerLobbySessionInviteFriends(\n    _In_ XblUserHandle user,\n    _In_opt_z_ const char* contextStringId,\n    _In_opt_z_ const char* customActivationContext\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->InviteFriends(\n                user,\n                contextStringId != nullptr ? contextStringId : xsapi_internal_string(),\n                customActivationContext != nullptr ? customActivationContext : xsapi_internal_string()\n            );\n        });\n}\nCATCH_RETURN()\n#endif\n\nSTDAPI XblMultiplayerManagerLobbySessionInviteUsers(\n    _In_ XblUserHandle user,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_opt_z_ const char* contextStringId,\n    _In_opt_z_ const char* customActivationContext\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](MultiplayerManager& mpm)\n        {\n            return mpm.LobbySession()->InviteUsers(\n                user,\n                xsapi_internal_vector<uint64_t>(xuids, xuids + xuidsCount),\n                contextStringId != nullptr ? contextStringId : xsapi_internal_string(),\n                customActivationContext != nullptr ? customActivationContext : xsapi_internal_string()\n            );\n        });\n}\nCATCH_RETURN()\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\n// GameSession APIs\ntemplate<typename Ret, typename TWork>\nRet GameSessionApiImpl(Ret&& fallbackReturnValue, TWork&& work) noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (!state)\n    {\n        return fallbackReturnValue;\n    }\n\n    assert(state->MultiplayerManager());\n    auto gameSession{ state->MultiplayerManager()->GameSession() };\n    RETURN_HR_IF(state->MultiplayerManager()->IsInitialized() == false, fallbackReturnValue);\n    if (!gameSession)\n    {\n        LOGS_ERROR << \"XblMultiplayerManagerGameSession* API called before GameSession was established\";\n        return fallbackReturnValue;\n    }\n\n    return work(state->MultiplayerManager()->GameSession());\n}\n\ntemplate<typename TWork>\nHRESULT GameSessionApiImpl(TWork&& work) noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (!state)\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n\n    assert(state->MultiplayerManager());\n    RETURN_HR_IF(state->MultiplayerManager()->IsInitialized() == false, E_XBL_NOT_INITIALIZED);\n    auto gameSession{ state->MultiplayerManager()->GameSession() };\n    if (!gameSession)\n    {\n        LOGS_ERROR << \"XblMultiplayerManagerGameSession* API called before GameSession was established\";\n        return E_UNEXPECTED;\n    }\n\n    return work(state->MultiplayerManager()->GameSession());\n}\n\ntypedef std::shared_ptr<MultiplayerGameSession> GameSessionPtr;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n\nSTDAPI_(bool) XblMultiplayerManagerGameSessionActive() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl(false, [](MultiplayerManager& mpm)\n        {\n            return mpm.GameSession() != nullptr;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(const char*) XblMultiplayerManagerGameSessionCorrelationId() XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl<const char*>(nullptr, [](GameSessionPtr gameSession)\n        {\n            return gameSession->CorrelationId().data();\n        });\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerSessionReference*) XblMultiplayerManagerGameSessionSessionReference() XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl<const XblMultiplayerSessionReference *>(nullptr, [](GameSessionPtr gameSession)\n        {\n            return &gameSession->SessionReference();\n        });\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(size_t) XblMultiplayerManagerGameSessionMembersCount() XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl<size_t>(0, [](GameSessionPtr gameSession)\n        {\n            return gameSession->Members().size();\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerGameSessionMembers(\n    _In_ size_t membersCount,\n    _Out_writes_(membersCount) XblMultiplayerManagerMember* members\n) XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl([&](GameSessionPtr gameSession)\n        {\n            auto& membersVector = gameSession->Members();\n            RETURN_HR_INVALIDARGUMENT_IF(membersCount < membersVector.size());\n            RETURN_HR_INVALIDARGUMENT_IF(members == nullptr && membersCount > 0);\n            for (size_t i = 0; i < membersVector.size(); ++i)\n            {\n                DISABLE_WARNING_PUSH;\n                SUPPRESS_WARNING_NULL_PTR_DEREFERENCE;\n                members[i] = membersVector[i]->GetReference();\n                DISABLE_WARNING_POP;\n            }\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerGameSessionHost(\n    _Out_ XblMultiplayerManagerMember* hostMember\n) XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl([&](GameSessionPtr gameSession)\n        {\n            if (gameSession->Host())\n            {\n                *hostMember = gameSession->Host()->GetReference();\n                return S_OK;\n            }\n            else\n            {\n                return __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);\n            }\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(const char*) XblMultiplayerManagerGameSessionPropertiesJson() XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl<const char*>(nullptr, [](GameSessionPtr gameSession)\n        {\n            return gameSession->Properties().data();\n        });\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerSessionConstants*) XblMultiplayerManagerGameSessionConstants() XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl<const XblMultiplayerSessionConstants*>(nullptr, [](GameSessionPtr gameSession)\n        {\n            return &gameSession->SessionConstants();\n        });\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(bool) XblMultiplayerManagerGameSessionIsHost(\n    _In_ uint64_t xuid\n) XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl(false, [&](GameSessionPtr gameSession)\n        {\n            return gameSession->IsHost(xuid);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerGameSessionSetProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl([&](GameSessionPtr gameSession)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n            JsonDocument json;\n            json.Parse(valueJson);\n            if (json.HasParseError() &&\n                json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n            {\n                return E_INVALIDARG;\n            }\n\n            return gameSession->SetProperties(\n                name,\n                json,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerGameSessionSetSynchronizedProperties(\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl([&](GameSessionPtr gameSession)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n            JsonDocument json;\n            json.Parse(valueJson);\n            if (json.HasParseError() &&\n                json.GetParseError() != rapidjson::kParseErrorDocumentEmpty)\n            {\n                return E_INVALIDARG;\n            }\n\n            return gameSession->SetSynchronizedProperties(\n                name,\n                json,\n                reinterpret_cast<context_t>(context)\n            );\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerManagerGameSessionSetSynchronizedHost(\n    _In_ const char* deviceToken,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return GameSessionApiImpl([&](GameSessionPtr gameSession)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(deviceToken);\n\n            return gameSession->SetSynchronizedHost(deviceToken, reinterpret_cast<context_t>(context));\n        });\n}\nCATCH_RETURN()\n\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_manager_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <mutex>\n#include <set>\n#include \"xbox_live_context_internal.h\"\n#include \"multiplayer_internal.h\"\n#include \"xsapi-c/multiplayer_manager_c.h\"\n\ntypedef void* context_t;\n\nstruct XblMultiplayerEventArgs : public xbox::services::RefCounter, public std::enable_shared_from_this<XblMultiplayerEventArgs>\n{\n    XblMultiplayerEventArgs() = default;\n    virtual ~XblMultiplayerEventArgs() = default;\n\nprivate:\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override\n    {\n        return shared_from_this();\n    }\n};\n\nnamespace xbox { namespace services { namespace multiplayer { namespace manager {\n\nclass MultiplayerMatchClient;\nclass MultiplayerClientManager;\nclass MultiplayerLocalUserManager;\nclass MultiplayerLobbyClient;\nclass MultiplayerGameClient;\nclass MultiplayerLocalUser;\n\nenum class MultiplayerLocalUserLobbyState\n{\n    Unknown,\n    Add,\n    Join,\n    InSession,\n    Leave,\n    Remove\n};\n\nenum class MultiplayerLocalUserGameState\n{\n    Unknown,\n    PendingJoin,\n    Join,\n    InSession,\n    Leave\n};\n\nenum class PendingRequestType\n{\n    SynchronizedChanges,\n    NonSynchronizedChanges\n};\n\nclass MultiplayerMember\n{\npublic:\n\n    MultiplayerMember();\n\n    MultiplayerMember(\n        _In_ const XblMultiplayerSessionMember* member,\n        _In_ bool isLocal,\n        _In_ bool isGameHost,\n        _In_ bool isLobbyHost,\n        _In_ bool isInLobby,\n        _In_ bool isInGame\n        );\n\n    uint32_t MemberId() const;\n    const xsapi_internal_string& TeamId() const;\n    const xsapi_internal_string& InitialTeam() const;\n    uint64_t Xuid() const;\n    const xsapi_internal_string& DebugGamertag() const;\n    bool IsLocal() const;\n    bool IsInLobby() const;\n    bool IsInGame() const;\n    XblMultiplayerSessionMemberStatus Status() const;\n    const xsapi_internal_string& ConnectionAddress() const;\n    const xsapi_internal_string& CustomPropertiesJson() const;\n    bool IsMemberOnSameDevice(\n        _In_ std::shared_ptr<MultiplayerMember> member\n        ) const;\n    const xsapi_internal_string& DeviceToken() const;\n    static std::shared_ptr<MultiplayerMember> CreateFromSessionMember(\n        _In_ const XblMultiplayerSessionMember* member,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& gameSession,\n        _In_ const xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>& xboxLiveContextMap\n        );\n    static std::shared_ptr<MultiplayerMember> CreateFromSessionMember(\n        _In_ const XblMultiplayerSessionMember* member,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& gameSession,\n        _In_ bool isLocal\n        );\n\n    XblMultiplayerManagerMember GetReference() const;\n\nprivate:\n    xsapi_internal_string m_teamId;\n    xsapi_internal_string m_initialTeam;\n    uint32_t m_memberId;\n    uint64_t m_xuid;\n    xsapi_internal_string m_gamertag;\n    xsapi_internal_string m_deviceToken;\n    bool m_isLocal;\n    bool m_isInLobby;\n    bool m_isInGame;\n    XblMultiplayerSessionMemberStatus m_status;\n    xsapi_internal_string m_connectionAddress;\n    xsapi_internal_string m_jsonProperties;\n};\n\nclass MultiplayerLobbySession\n{\npublic:\n    MultiplayerLobbySession();\n    MultiplayerLobbySession(_In_ const MultiplayerLobbySession& other);\n    MultiplayerLobbySession(_In_ std::shared_ptr<MultiplayerClientManager> multiplayerClientManagerInstance);\n    MultiplayerLobbySession(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ std::shared_ptr<MultiplayerMember> host,\n        _In_ const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& members,\n        _In_ const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& localMmembers\n        );\n\n    ~MultiplayerLobbySession();\n\n    const xsapi_internal_string& CorrelationId() const;\n    const XblMultiplayerSessionReference& SessionReference() const;\n    const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& LocalMembers() const;\n    const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& Members() const;\n    std::shared_ptr<MultiplayerMember> Host() const;\n    const xsapi_internal_string& CustomPropertiesJson() const;\n    const XblMultiplayerSessionConstants& SessionConstants() const;\n\n    HRESULT AddLocalUser(\n        _In_ xbox_live_user_t user\n        );\n\n    HRESULT RemoveLocalUser(\n        _In_ xbox_live_user_t user\n        );\n\n    HRESULT SetLocalMemberProperties(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n\n    HRESULT DeleteLocalMemberProperties(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& name,\n        _In_opt_ context_t context = nullptr\n        );\n\n    HRESULT SetLocalMemberConnectionAddress(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& connectionAddress,\n        _In_opt_ context_t context = nullptr\n        );\n\n    bool IsHost(\n        _In_ uint64_t xuid\n        );\n\n    HRESULT SetProperties(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n\n    HRESULT SetSynchronizedProperties(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n\n    HRESULT SetSynchronizedHost(\n        _In_ const xsapi_internal_string& hostDeviceToken,\n        _In_opt_ context_t context = nullptr\n        );\n\n#if HC_PLATFORM_IS_MICROSOFT\n    HRESULT InviteFriends(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& contextStringId = xsapi_internal_string(),\n        _In_ const xsapi_internal_string& customActivationContext = xsapi_internal_string()\n        );\n#endif\n\n    HRESULT InviteUsers(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_vector<uint64_t>& xuids,\n        _In_ const xsapi_internal_string& contextStringId = xsapi_internal_string(),\n        _In_ const xsapi_internal_string& customActivationContext = xsapi_internal_string()\n        );\n\n    uint64_t ChangeNumber() const;\n\n    void SetMultiplayerClientManager(\n        _In_ std::shared_ptr<MultiplayerClientManager> clientManager\n        );\n\n    void SetHost(_In_ std::shared_ptr<MultiplayerMember> hostMember);\n\n#if defined(XSAPI_CPPWINRT)\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    // TODO is there a better way to do this?\n    HRESULT AddLocalUser(\n        _In_ winrt::Windows::Xbox::System::User user\n        )\n    {\n        return AddLocalUser(convert_user_to_cppcx(user));\n    }\n\n    HRESULT RemoveLocalUser(\n        _In_ winrt::Windows::Xbox::System::User user\n        )\n    {\n        return RemoveLocalUser(convert_user_to_cppcx(user));\n    }\n\n    HRESULT SetLocalMemberProperties(\n        _In_ winrt::Windows::Xbox::System::User user,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context = nullptr\n        )\n    {\n        return SetLocalMemberProperties(\n            convert_user_to_cppcx(user),\n            name,\n            valueJson,\n            context\n            );\n    }\n\n    HRESULT DeleteLocalMemberProperties(\n        _In_ winrt::Windows::Xbox::System::User user,\n        _In_ const xsapi_internal_string& name,\n        _In_opt_ context_t context = nullptr\n        )\n    {\n        return DeleteLocalMemberProperties(\n            convert_user_to_cppcx(user),\n            name,\n            context\n            );\n    }\n\n    HRESULT SetLocalMemberConnectionAddress(\n        _In_ winrt::Windows::Xbox::System::User user,\n        _In_ const xsapi_internal_string& connectionAddress,\n        _In_opt_ context_t context = nullptr\n        )\n    {\n        return SetLocalMemberConnectionAddress(\n            convert_user_to_cppcx(user),\n            connectionAddress,\n            context\n            );\n    }\n\n    HRESULT InviteFriends(\n        _In_ winrt::Windows::Xbox::System::User user,\n        _In_ const xsapi_internal_string& contextStringId = xsapi_internal_string(),\n        _In_ const xsapi_internal_string& customActivationContext = xsapi_internal_string()\n        )\n    {\n        return InviteFriends(\n            convert_user_to_cppcx(user),\n            contextStringId,\n            customActivationContext\n            );\n    }\n\n    HRESULT InviteUsers(\n        _In_ winrt::Windows::Xbox::System::User user,\n        _In_ const xsapi_internal_vector<xsapi_internal_string>& xboxUserIds,\n        _In_ const xsapi_internal_string& contextStringId = xsapi_internal_string(),\n        _In_ const xsapi_internal_string& customActivationContext = xsapi_internal_string()\n        )\n    {\n        return InviteUsers(\n            convert_user_to_cppcx(user),\n            xboxUserIds,\n            contextStringId,\n            customActivationContext\n            );\n    }\n#endif\n#endif\n\nprivate:\n    void DeepCopyConstants(const XblMultiplayerSessionConstants& other);\n\n    std::shared_ptr<MultiplayerClientManager> m_multiplayerClientManager;\n\n    xsapi_internal_string m_correlationId;\n    uint64_t m_changeNumber;\n    XblMultiplayerSessionReference m_sessionReference;\n    std::shared_ptr<MultiplayerMember> m_host;\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> m_members;\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> m_localMembers;\n    xsapi_internal_string m_customPropertiesJson;\n\n    XblMultiplayerSessionConstants m_sessionConstants{};\n    xsapi_internal_vector<uint64_t> m_initiatorXuids;\n    XblMultiplayerMemberInitialization m_memberInitialization{};\n    xsapi_internal_string m_constantsCustomJson;\n    xsapi_internal_string m_constantsCloudComputePackageJson;\n    xsapi_internal_string m_constantsMeasurementServerAddressesJson;\n};\n\n\nclass MultiplayerGameSession\n{\npublic:\n    MultiplayerGameSession();\n    MultiplayerGameSession(_In_ const MultiplayerGameSession& other);\n    MultiplayerGameSession(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ std::shared_ptr<MultiplayerMember> host,\n        _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> members\n        );\n\n    const xsapi_internal_string& CorrelationId() const;\n    const XblMultiplayerSessionReference& SessionReference() const;\n    const xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& Members() const;\n    std::shared_ptr<MultiplayerMember> Host() const;\n    const xsapi_internal_string& Properties() const;\n    const XblMultiplayerSessionConstants& SessionConstants() const;\n    bool IsHost(\n        _In_ uint64_t xuid\n        );\n    HRESULT SetProperties(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n    HRESULT SetSynchronizedProperties(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context = nullptr\n        );\n    HRESULT SetSynchronizedHost(\n        _In_ const xsapi_internal_string& deviceToken,\n        _In_opt_ context_t context = nullptr\n        );\n    uint64_t ChangeNumber() const;\n    void SetMultiplayerClientManager(\n        _In_ std::shared_ptr<MultiplayerClientManager> clientManager\n        );\n    void SetHost(_In_ std::shared_ptr<MultiplayerMember> hostMember);\n\nprivate:\n    void DeepCopyConstants(const XblMultiplayerSessionConstants& other);\n\n    xsapi_internal_string m_correlationId;\n    uint64_t m_changeNumber;\n    XblMultiplayerSessionReference m_sessionReference;\n    std::shared_ptr<MultiplayerMember> m_host;\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> m_members;\n    xsapi_internal_string m_properties;\n    std::shared_ptr<MultiplayerClientManager> m_multiplayerClientManager;\n\n    // Constants\n    XblMultiplayerSessionConstants m_sessionConstants;\n    xsapi_internal_vector<uint64_t> m_initiatorXuids;\n    XblMultiplayerMemberInitialization m_memberInitialization;\n    xsapi_internal_string m_constantsCustomJson;\n    xsapi_internal_string m_constantsCloudComputePackageJson;\n    xsapi_internal_string m_constantsMeasurementServerAddressesJson;\n};\n\nstruct UserAddedEventArgs : public XblMultiplayerEventArgs\n{\n    UserAddedEventArgs(_In_ uint64_t xuid) : Xuid(xuid) {}\n    uint64_t Xuid;\n};\n\nstruct UserRemovedEventArgs : public XblMultiplayerEventArgs\n{\n    UserRemovedEventArgs(_In_ uint64_t xuid) : Xuid(xuid) {}\n    uint64_t Xuid;\n};\n\nstruct MemberJoinedEventArgs : public XblMultiplayerEventArgs\n{\n    MemberJoinedEventArgs(const _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& members) : Members(members) {}\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> Members;\n};\n\nstruct MemberLeftEventArgs : public XblMultiplayerEventArgs\n{\n    MemberLeftEventArgs(const _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerMember>>& members) : Members(members) {}\n    xsapi_internal_vector<std::shared_ptr<MultiplayerMember>> Members;\n};\n\nstruct HostChangedEventArgs : public XblMultiplayerEventArgs\n{\n    HostChangedEventArgs(_In_ std::shared_ptr<MultiplayerMember> hostMember) : HostMember(hostMember) {}\n    std::shared_ptr<MultiplayerMember> HostMember;\n};\n\nstruct MemberPropertyChangedEventArgs : public XblMultiplayerEventArgs\n{\n    MemberPropertyChangedEventArgs(\n        _In_ std::shared_ptr<MultiplayerMember> member,\n        _In_ const xsapi_internal_string& jsonProperties\n        ) : Member(member),\n        Properties(jsonProperties)\n    {\n    }\n\n    std::shared_ptr<MultiplayerMember> Member;\n    xsapi_internal_string Properties;\n};\n\nstruct SessionPropertyChangedEventArgs : public XblMultiplayerEventArgs\n{\n    SessionPropertyChangedEventArgs(_In_ const xsapi_internal_string& jsonProperties) : Properties(jsonProperties) {}\n    xsapi_internal_string Properties;\n};\n\nstruct JoinLobbyCompletedEventArgs : public XblMultiplayerEventArgs\n{\n    JoinLobbyCompletedEventArgs(_In_ uint64_t xuid) : Xuid(xuid) {}\n    uint64_t Xuid;\n};\n\nstruct FindMatchCompletedEventArgs : public XblMultiplayerEventArgs\n{\n    FindMatchCompletedEventArgs(\n        _In_ XblMultiplayerMatchStatus status,\n        _In_ XblMultiplayerMeasurementFailure failure\n        ) : MatchStatus(status),\n        InitializationFailure(failure)\n    {\n    }\n\n    XblMultiplayerMatchStatus MatchStatus;\n    XblMultiplayerMeasurementFailure InitializationFailure;\n};\n\nstruct PerformQosMeasurementsEventArgs : public XblMultiplayerEventArgs\n{\n    PerformQosMeasurementsEventArgs() { }\n    ~PerformQosMeasurementsEventArgs()\n    {\n        for (auto& client : remoteClients)\n        {\n            Delete(client.connectionAddress);\n        }\n    }\n\n    void AddRemoteClient(const xsapi_internal_string& connectionAddress, const xsapi_internal_string& deviceToken)\n    {\n        XblMultiplayerConnectionAddressDeviceTokenPair client{};\n        client.connectionAddress = Make(connectionAddress);\n        utils::strcpy(client.deviceToken.Value, sizeof(client.deviceToken.Value), deviceToken.data());\n\n        remoteClients.push_back(std::move(client));\n    }\n\n    xsapi_internal_vector<XblMultiplayerConnectionAddressDeviceTokenPair> remoteClients;\n};\n\nclass MultiplayerEventQueue\n{\npublic:\n    MultiplayerEventQueue();\n    MultiplayerEventQueue(const MultiplayerEventQueue& other);\n    MultiplayerEventQueue& operator=(MultiplayerEventQueue other);\n    ~MultiplayerEventQueue();\n\n    size_t Size() const;\n    bool Empty() const;\n    void Clear();\n\n    xsapi_internal_vector<XblMultiplayerEvent>::const_iterator begin() const;\n    xsapi_internal_vector<XblMultiplayerEvent>::const_iterator end() const;\n\n    void AddEvent(\n        _In_ XblMultiplayerEventType eventType,\n        _In_ XblMultiplayerSessionType sessionType,\n        _In_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs = nullptr,\n        _In_ Result<void> error = {},\n        _In_opt_ context_t context = nullptr\n    );\n\n    void AddEvent(_In_ const XblMultiplayerEvent& multiplayerEvent);\n\nprivate:\n    xsapi_internal_vector<XblMultiplayerEvent> m_events;\n    mutable std::mutex m_lock;\n};\n\nclass MultiplayerManager\n{\npublic:\n    MultiplayerManager() = default;\n    ~MultiplayerManager();\n\n    void Initialize(\n        _In_ const xsapi_internal_string& lobbySessionTemplateName,\n        _In_opt_ XTaskQueueHandle asyncQueue\n    );\n\n    bool IsInitialized();\n\n    const MultiplayerEventQueue& DoWork();\n    std::shared_ptr<MultiplayerLobbySession> LobbySession() const;\n    std::shared_ptr<MultiplayerGameSession> GameSession() const;\n\n    HRESULT JoinLobby(\n        _In_ const xsapi_internal_string& handleId,\n        _In_ xbox_live_user_t user\n        );\n\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK \n    HRESULT JoinLobby(\n        _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n        _In_ xbox_live_user_t user\n        );\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    HRESULT JoinLobby(\n        _In_ const xsapi_internal_string& handleId,\n        _In_ xsapi_internal_vector<Windows::Xbox::System::User^> users\n        );\n\n    HRESULT JoinLobby(\n        _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n        _In_ xsapi_internal_vector<Windows::Xbox::System::User^> users\n        );\n\n    void InvitePartyToGame();\n\n#endif\n\n    HRESULT JoinGameFromLobby(\n        _In_ const xsapi_internal_string& sessionTemplateName\n        );\n\n    HRESULT JoinGame(\n        _In_ const xsapi_internal_string& sessionName,\n        _In_ const xsapi_internal_string& sessionTemplateName,\n        _In_ const xsapi_internal_vector<uint64_t>& xuids = xsapi_internal_vector<uint64_t>()\n        );\n\n    HRESULT LeaveGame();\n\n    HRESULT FindMatch(\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ JsonValue& attributes,\n        _In_ const std::chrono::seconds& timeout = std::chrono::seconds(60)\n        );\n\n    void CancelMatch();\n\n    XblMultiplayerMatchStatus MatchStatus() const;\n\n    std::chrono::seconds EstimatedMatchWaitTime() const;\n\n    bool AutoFillMembersDuringMatchmaking() const;\n\n    void SetAutoFillMembersDuringMatchmaking(\n        _In_ bool autoFillMembers\n        );\n\n    void SetQosMeasurements(\n        _In_ const JsonValue& measurements\n        );\n\n    XblMultiplayerJoinability Joinability() const;\n\n    HRESULT SetJoinability(\n        _In_ XblMultiplayerJoinability value,\n        _In_opt_ context_t context = nullptr\n        );\n\n    bool IsDirty();\n\n    std::shared_ptr<MultiplayerClientManager> GetMultiplayerClientManager() { return m_multiplayerClientManager; }\n\n    std::shared_ptr<MultiplayerGameClient> GameClient();\n\n    std::shared_ptr<MultiplayerLobbyClient> LobbyClient();\n\n#ifdef XSAPI_UNIT_TESTS\n    void Shutdown();\n#endif\n\n#if defined(XSAPI_CPPWINRT)\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    xbox_live_result<void> join_lobby(\n        _In_ const xsapi_internal_string& handleId,\n        _In_ xsapi_internal_vector<winrt::Windows::Xbox::System::User> users\n        )\n    {\n        return join_lobby(handleId, convert_user_vector_to_cppcx(users));\n    }\n#endif\n#endif\n\nprivate:\n    MultiplayerManager(MultiplayerManager const&) = delete;\n    void operator=(MultiplayerManager const&) = delete;\n\n    bool m_isDirty = false;\n    void SetMultiplayerGameSession(_In_ std::shared_ptr<MultiplayerGameSession> gameSession);\n    void SetMultiplayerLobbySession(_In_ std::shared_ptr<MultiplayerLobbySession> multiplayerLobby);\n\n    mutable std::mutex m_lock;\n    XblMultiplayerJoinability m_joinability = XblMultiplayerJoinability::None;\n    std::shared_ptr<MultiplayerLobbySession> m_multiplayerLobbySession;\n    std::shared_ptr<MultiplayerGameSession> m_multiplayerGameSession;\n    std::shared_ptr<MultiplayerClientManager> m_multiplayerClientManager;\n\n    MultiplayerEventQueue m_eventQueue;\n    XTaskQueueHandle m_queue{ nullptr };\n};\n\ntypedef Callback<Result<std::shared_ptr<XblMultiplayerSession>>> MultiplayerSessionCallback;\ntypedef Callback<Result<MultiplayerEventQueue>> MultiplayerEventQueueCallback; // Maybe just pass queue\n\nclass MultiplayerClientPendingRequest\n{\npublic:\n    MultiplayerClientPendingRequest();\n\n    PendingRequestType RequestType() const;\n\n    context_t Context();\n\n    uint32_t Identifier() const;\n\n    // Local user properties\n    std::shared_ptr<MultiplayerLocalUser> LocalUser();\n    void SetLocalUser(_In_ std::shared_ptr<MultiplayerLocalUser> user);\n\n    MultiplayerLocalUserLobbyState LobbyState();\n    void SetLobbyState(_In_ MultiplayerLocalUserLobbyState userState);\n\n    const xsapi_internal_string& LobbyHandleId() const;\n    void SetLobbyHandleId(_In_ const xsapi_internal_string& handleId);\n\n    const xsapi_internal_string& LocalUserSecureDeivceAddress() const;\n    void SetLocalUserConnectionAddress(\n        _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n        _In_ const xsapi_internal_string& connectionAddress,\n        _In_opt_ context_t context\n        );\n\n    const xsapi_internal_map<xsapi_internal_string, JsonDocument>& LocalUserProperties() const;\n    void SetLocalUserProperties(\n        _In_ std::shared_ptr<MultiplayerLocalUser> localUser, \n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson, \n        _In_opt_ context_t context\n        );\n\n    // Session non-synchronized properties\n    XblMultiplayerJoinability Joinability();\n    void SetJoinability(_In_ XblMultiplayerJoinability value, _In_opt_ context_t context);\n\n    const xsapi_internal_map<xsapi_internal_string, JsonDocument>& SessionProperties() const;\n    void SetSessionProperties(_In_ const xsapi_internal_string& name, _In_ const JsonValue& valueJson, _In_opt_ context_t context);\n\n    // Session synchronized properties\n    const xsapi_internal_string& SynchronizedHostDeviceToken() const;\n    void SetSynchronizedHostDeviceToken(_In_ const xsapi_internal_string& hostDeviceToken, _In_opt_ context_t context);\n\n    const xsapi_internal_map<xsapi_internal_string, JsonDocument>& SynchronizedSessionProperties() const;\n    void SetSynchronizedSessionProperties(_In_ const xsapi_internal_string& name, const _In_ JsonValue& valueJson, _In_opt_ context_t context);\n\n    void AppendPendingChanges(\n        _In_ std::shared_ptr<XblMultiplayerSession> sessionToCommit, \n        _In_ std::shared_ptr<MultiplayerLocalUser> localUser, \n        _In_ bool isGameInProgress = false\n        );\n\nprivate:\n    context_t m_context;\n    PendingRequestType m_requestType{};\n    uint32_t m_identifier{ s_nextUniqueIdentifier++ };\n\n    // Local user properties\n    std::shared_ptr<MultiplayerLocalUser> m_localUser;\n    MultiplayerLocalUserLobbyState m_localUserLobbyState;\n    xsapi_internal_map<xsapi_internal_string, JsonDocument> m_localUserProperties;\n    xsapi_internal_string m_localUserSecureDeivceAddress;\n    xsapi_internal_string m_lobbyHandleId;   // Only used while joining a friend's lobby\n\n    // Session non-synchronized properties\n    xsapi_internal_map<xsapi_internal_string, JsonDocument> m_sessionProperties;\n    XblMultiplayerJoinability m_joinability{};\n\n    // Session synchronized properties\n    xsapi_internal_string m_synchronizedHostDeviceToken;\n    xsapi_internal_map<xsapi_internal_string, JsonDocument> m_synchronizedSessionProperties;\n\n    static std::atomic<uint32_t> s_nextUniqueIdentifier;\n};\n\n\nclass MultiplayerSessionWriter : public std::enable_shared_from_this<MultiplayerSessionWriter>\n{\npublic:\n    MultiplayerSessionWriter(const TaskQueue& queue) noexcept;\n    MultiplayerSessionWriter(\n        const TaskQueue& queue,\n        _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n    ) noexcept;\n\n    uint64_t Id() const;\n\n    const std::shared_ptr<XblMultiplayerSession>& Session() const;\n    void UpdateSession(_In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession);\n\n    uint64_t TapChangeNumber() const;\n    void SetTapChangeNumber(_In_ uint64_t changeNumber);\n\n    bool IsTapReceived() const;\n    void SetTapReceived(_In_ bool bReceived);\n\n    bool IsWriteInProgress() const;\n    void SetWriteInProgress(_In_ bool writeInProgress);\n\n    void OnSessionChanged(\n        _In_ XblMultiplayerSessionChangeEventArgs args\n    ) noexcept;\n\n    HRESULT CommitSynchronizedChanges(\n        _In_ std::shared_ptr<XblMultiplayerSession> sessionToCommit,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT LeaveRemoteSession(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT CommitPendingChanges(\n        _In_ Vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue,\n        _In_ XblMultiplayerSessionType sessionType,\n        _In_ bool isGameInProgress,\n        _In_ MultiplayerEventQueueCallback callback\n    ) noexcept;\n\n    HRESULT CommitPendingSynchronizedChanges(\n        _In_ Vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue,\n        _In_ XblMultiplayerSessionType sessionType,\n        _In_ MultiplayerEventQueueCallback callback\n    ) noexcept;\n\n    HRESULT WriteSession(\n        _In_ std::shared_ptr<XblContext> xboxLiveContext,\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ XblMultiplayerSessionWriteMode mode,\n        _In_ bool updateLatest,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT WriteSessionByHandle(\n        _In_ std::shared_ptr<XblContext> xboxLiveContext,\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ XblMultiplayerSessionWriteMode mode,\n        _In_ const String& handleId,\n        _In_ bool updateLatest,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    void OnSessionUpdated(\n        _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n        );\n\n    XblFunctionContext AddMultiplayerSessionUpdatedHandler(\n        _In_ Callback<const std::shared_ptr<XblMultiplayerSession>&> handler\n        );\n\n    void OnResyncMessageReceived();\n\n    std::shared_ptr<XblContext> GetPrimaryContext();\n\n    MultiplayerEventQueue HandleEvents(\n        _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue,\n        _In_ Result<void> error,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\nprivate:\n    void Destroy();\n    void Resync();\n\n    // Synchronize write session result with any changes that happened in the interim.\n    void HandleWriteSessionResult(\n        _In_ Result<std::shared_ptr<XblMultiplayerSession>> writeSessionResult,\n        _In_ bool updateLatest,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT GetCurrentSessionHelper(\n        _In_ std::shared_ptr<XblContext> xboxLiveContext,\n        _In_ const XblMultiplayerSessionReference& sessionReference,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    TaskQueue m_queue;\n\n    // resync\n    bool m_isResyncTaskInProgress{ false };\n    XblFunctionContext m_handleResyncEventCounter{ 0 };\n    std::mutex m_resyncLock;\n\n    std::mutex m_stateLock;\n    XblFunctionContext m_sessionUpdateEventHandlerCounter{ 1 };\n    UnorderedMap<uint32_t, Callback<const std::shared_ptr<XblMultiplayerSession>>> m_sessionUpdateEventHandler;\n\n    uint64_t m_id{ 0 }; // used to ignore calls made before resetting the state via destory()\n    std::mutex m_synchronizeWriteWithTapLock;\n    uint64_t m_tapChangeNumber{ 0 };\n    bool m_isTapReceived{ false };\n    uint64_t m_numOfWritesInProgress{ 0 };\n    std::shared_ptr<XblMultiplayerSession> m_session;\n    std::shared_ptr<MultiplayerLocalUserManager> m_multiplayerLocalUserManager;\n\n};\n\nclass MultiplayerGameClient : public std::enable_shared_from_this<MultiplayerGameClient>\n{\npublic:\n    MultiplayerGameClient(const TaskQueue& queue) noexcept;\n    MultiplayerGameClient(\n        const TaskQueue& queue,\n        _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n    ) noexcept;\n    ~MultiplayerGameClient();\n\n    // TODO\n    void deep_copy_if_updated(_In_ const MultiplayerGameClient& other);\n    void Initialize();\n    void SetGameSessionTemplate(_In_ const xsapi_internal_string& sessionTemplateName);\n    std::shared_ptr<MultiplayerSessionWriter> SessionWriter() const;\n    std::shared_ptr<MultiplayerGameSession> Game() const;\n    void UpdateGame(_In_ const std::shared_ptr<MultiplayerGameSession>& multiplayerGame);\n\n    MultiplayerEventQueue DoWork();\n    bool IsRequestInProgress();\n    bool IsPendingGameChanges();\n\n    void ClearPendingQueue();\n    void AddToPendingQueue(_In_ std::shared_ptr<MultiplayerClientPendingRequest> pendingRequest);\n    void AddToProcessingQueue(_In_ xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue);\n    void RemoveFromProcessingQueue(_In_ uint32_t identifier);\n\n    const MultiplayerEventQueue& EventQueue();\n    xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> GetProcessingQueue();\n\n    void UpdateGameSession(_In_ const std::shared_ptr<XblMultiplayerSession>& session);\n\n    void UpdateObjects(\n        const std::shared_ptr<XblMultiplayerSession>& updatedSession,\n        const std::shared_ptr<XblMultiplayerSession>& lobbySession\n        );\n\n    std::shared_ptr<XblMultiplayerSession> Session() const;\n\n    void UpdateSession(_In_ const std::shared_ptr<XblMultiplayerSession>& session);\n\n    void RemoveStaleUsersFromRemoteSession();\n    void SetLocalMemberPropertiesToRemoteSession(\n        _In_ const std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerLocalUser>& localUser,\n        _In_ const Map<String, JsonDocument>& propertiesToWrite,\n        _In_ const String& localUserSecureDeviceAddress\n    ) noexcept;\n\n    HRESULT JoinGameHelper(\n        _In_ const String& sessionName,\n        _In_ Callback<Result<void>> callback\n    ) noexcept;\n\n    void LeaveRemoteSession(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ bool stopAdvertisingGameSession,\n        _In_ bool triggerCompletionEvent\n    ) noexcept;\n\n    HRESULT JoinGameFromLobbyHelper(\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT JoinGameBySessionReference(\n        _In_ const XblMultiplayerSessionReference& gameSessionRef,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT JoinGameByHandle(\n        _In_ const String& handleId,\n        _In_ bool createGameIfFailedToJoin,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\nprivate:\n    std::shared_ptr<XblMultiplayerSession> LobbySession() const;\n    std::shared_ptr<MultiplayerLobbyClient> LobbyClient() const;\n\n    std::shared_ptr<MultiplayerGameSession> ConvertToMultiplayerGame(\n        _In_ const std::shared_ptr<XblMultiplayerSession>& sessionToConvert,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession\n        );\n\n    HRESULT JoinGameForAllLocalMembers(\n        _In_ const XblMultiplayerSessionReference& sessionRefToJoin,\n        _In_ const String& handleIdToJoin,\n        _In_ bool createGameIfFailedToJoin,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    HRESULT JoinHelper(\n        _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ bool writeMemberPropertiesFromLobby,\n        _In_ const String& handleId,\n        _In_ MultiplayerSessionCallback callback\n    ) const noexcept;\n\n    TaskQueue m_queue;\n    mutable std::mutex m_clientRequestLock;\n    std::atomic<bool> m_pendingCommitInProgress{ false };\n    String m_gameSessionTemplateName;\n    uint64_t m_updateNumber{ 0 };\n    std::shared_ptr<MultiplayerSessionWriter> m_sessionWriter;\n    MultiplayerEventQueue m_multiplayerEventQueue;\n    std::shared_ptr<MultiplayerGameSession> m_multiplayerGame;\n    std::shared_ptr<MultiplayerLocalUserManager> m_multiplayerLocalUserManager;\n    Queue<std::shared_ptr<MultiplayerClientPendingRequest>> m_pendingRequestQueue;\n    Vector<std::shared_ptr<MultiplayerClientPendingRequest>> m_processingQueue;\n};\n\n#define MultiplayerLobbyClient_TransferHandlePropertyName \"GameSessionTransferHandle\"\n#define MultiplayerLobbyClient_JoinabilityPropertyName \"Joinability\"\n\nclass MultiplayerLobbyClient : public std::enable_shared_from_this<MultiplayerLobbyClient>\n{\npublic:\n    MultiplayerLobbyClient(_In_ const TaskQueue& queue) noexcept;\n    MultiplayerLobbyClient(\n        _In_ const TaskQueue& queue,\n        _In_ String lobbySessionTemplateName,\n        _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n    ) noexcept;\n    ~MultiplayerLobbyClient() noexcept;\n\n    // TODO\n    void deep_copy_if_updated(_In_ const MultiplayerLobbyClient& other);\n    void Initialize();\n    const std::shared_ptr<MultiplayerSessionWriter>& SessionWriter() const;\n    const std::shared_ptr<MultiplayerLobbySession>& Lobby() const;\n    void ClearPendingQueue();\n    void AddToPendingQueue(_In_ std::shared_ptr<MultiplayerClientPendingRequest> pendingRequest);\n    void AddToProcessingQueue(_In_ xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue);\n    void RemoveFromProcessingQueue(_In_ uint32_t identifier);\n\n    HRESULT AddLocalUser(\n        _In_ xbox_live_user_t user,\n        _In_ MultiplayerLocalUserLobbyState userState,\n        _In_ const xsapi_internal_string& handleId = xsapi_internal_string()\n        );\n\n    void AddLocalUsers(_In_ xsapi_internal_vector<xbox_live_user_t> user, _In_ const xsapi_internal_string& handleId);\n    void AddLocalUsers(_In_ xsapi_internal_vector<xbox_live_user_t> user);\n\n    HRESULT RemoveLocalUser(_In_ xbox_live_user_t user);\n    void RemoveAllLocalUsers();\n\n    HRESULT SetLocalMemberProperties(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context\n        );\n\n    HRESULT DeleteLocalMemberProperties(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& name,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetLocalMemberConnectionAddress(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& address,\n        _In_opt_ context_t context\n        );\n\n    MultiplayerEventQueue DoWork();\n    bool IsPendingLobbyChanges();\n    bool IsRequestInProgress();\n\n    HRESULT CreateGameFromLobby() noexcept;\n\n    XblMultiplayerJoinability Joinability();\n\n    HRESULT SetJoinability(\n        _In_ XblMultiplayerJoinability value,\n        _In_opt_ context_t context\n        );\n\n    const MultiplayerEventQueue& EventQueue();\n    xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> GetProcessingQueue();\n\n    void UpdateLobbySession(_In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession);\n\n    void UpdateObjects(\n        const std::shared_ptr<XblMultiplayerSession>& updatedSession,\n        const std::shared_ptr<XblMultiplayerSession>& gameSession\n        );\n\n    const std::shared_ptr<XblMultiplayerSession>& Session() const;\n\n    void UpdateSession(\n        _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n        );\n\n    void LeaveRemoteSession(\n        _In_ std::shared_ptr<XblMultiplayerSession> session\n        );\n\n    void StopAdvertisingGameSession(\n        _In_ Result<std::shared_ptr<XblMultiplayerSession>> result\n        );\n\n    void AdvertiseGameSession() noexcept;\n    void ClearGameSessionFromLobby();\n\n    bool IsTransferHandleState(_In_ const xsapi_internal_string& state);\n    xsapi_internal_string GetTransferHandle();\n\n    void RemoveStaleXboxLiveContextFromMap();\n    const xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>& GetLocalUserMap();\n    std::shared_ptr<XblContext> GetPrimaryContext();\n\nprivate:\n    std::shared_ptr<MultiplayerGameClient> GameClient();\n    std::shared_ptr<XblMultiplayerSession> GameSession();\n\n    HRESULT CommitPendingLobbyChanges(\n        _In_ const Vector<uint64_t>& xuidsInOrder,\n        _In_ bool joinByHandleId,\n        _In_ XblMultiplayerSessionReference sessionRef,\n        _In_ MultiplayerEventQueueCallback callback\n    ) noexcept;\n\n    HRESULT CommitLobbyChanges(\n        _In_ const Vector<uint64_t>& xuidsInOrder,\n        _In_ std::shared_ptr<XblMultiplayerSession> lobbySessionToCommit,\n        _In_ Callback<Result<void>> callback\n    ) noexcept;\n\n    void UpdateLobby(_In_ std::shared_ptr<MultiplayerLobbySession> multiplayerLobby);\n    void UpdateLocalLobbyMembers(\n        _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& gameSession\n        );\n\n    bool IsPendingLobbyLocalUserChanges();\n\n    bool ShouldUpdateHostToken(\n        _In_ std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerLocalUser> localUser,\n        _In_ std::shared_ptr<XblMultiplayerSession> session\n        );\n\n    void UserStateChanged(\n        _In_ Result<void> error,\n        _In_ MultiplayerLocalUserLobbyState localUserLobbyState,\n        _In_ uint64_t xboxUserId\n        );\n\n    void HandleLobbyChangeEvents(\n        _In_ Result<void> error,\n        _In_ std::shared_ptr<MultiplayerLocalUser> localUser,\n        _In_ const xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>>& processingQueue\n        );\n\n    void HandleJoinLobbyCompleted(\n        _In_ Result<void> error,\n        _In_ uint64_t joinedXuid\n        );\n\n    void JoinLobbyCompleted(\n        _In_ Result<void> error,\n        _In_ uint64_t invitedXboxUserId\n        );\n\n    void AddEvent(\n        _In_ XblMultiplayerEventType eventType,\n        _In_opt_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs = nullptr,\n        _In_opt_ Result<void> error = {},\n        _In_opt_ context_t context = nullptr\n        );\n\n    std::shared_ptr<MultiplayerLobbySession> ConvertToMultiplayerLobby(\n        _In_ const  std::shared_ptr<XblMultiplayerSession>& sessionToConvert,\n        _In_ const  std::shared_ptr<XblMultiplayerSession>& gameSession\n        );\n\n    TaskQueue m_queue;\n\n    String m_lobbySessionTemplateName;\n    std::atomic<bool> m_pendingCommitInProgress{ false };\n\n    uint64_t m_updateNumber{ 0 };\n    XblMultiplayerJoinability m_joinability{ XblMultiplayerJoinability::None };\n    mutable std::mutex m_clientRequestLock;\n    Queue<std::shared_ptr<MultiplayerClientPendingRequest>> m_pendingRequestQueue;\n    MultiplayerEventQueue m_multiplayerEventQueue;\n    std::shared_ptr<MultiplayerSessionWriter> m_sessionWriter;\n    std::shared_ptr<MultiplayerLobbySession> m_multiplayerLobby;\n    Vector<std::shared_ptr<MultiplayerMember>> m_localLobbyMembers;\n    std::shared_ptr<MultiplayerLocalUserManager> m_multiplayerLocalUserManager;\n    Vector<std::shared_ptr<MultiplayerClientPendingRequest>> m_processingQueue;\n};\n\nclass MultiplayerClientPendingReader : public std::enable_shared_from_this<MultiplayerClientPendingReader>\n{\npublic:\n    MultiplayerClientPendingReader(const TaskQueue& queue);\n    ~MultiplayerClientPendingReader();\n    MultiplayerClientPendingReader(\n        _In_ const TaskQueue& queue,\n        _In_ const xsapi_internal_string& lobbySessionTemplateName,\n        _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n        );\n\n    // TODO\n    void deep_copy_if_updated(_In_ const MultiplayerClientPendingReader& other);\n    bool IsUpdateAvailable(_In_ const MultiplayerClientPendingReader& other);\n\n    void DoWork();\n    void ProcessMatchEvents();\n\n    std::shared_ptr<MultiplayerLobbyClient> LobbyClient();\n    std::shared_ptr<MultiplayerGameClient> GameClient();\n    std::shared_ptr<MultiplayerMatchClient> MatchClient();\n\n    const MultiplayerEventQueue& EventQueue() const;\n    void ClearEventQueue();\n\n    void AddEvent(\n        _In_ XblMultiplayerEventType eventType,\n        _In_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs,\n        _In_ XblMultiplayerSessionType sessionType,\n        _In_ Result<void> error,\n        _In_opt_ context_t context = nullptr\n    );\n\n    void AddEvent(_In_ const XblMultiplayerEvent& multiplayerEvent);\n    void AddEvents(_In_ const MultiplayerEventQueue& multiplayerEventQueue);\n\n    std::shared_ptr<XblMultiplayerSession> GetSession(_In_ XblMultiplayerSessionReference sessionRef);\n    void UpdateSession(_In_ XblMultiplayerSessionReference sessionRef, _In_ std::shared_ptr<XblMultiplayerSession> session);\n\n    bool IsLobby(_In_ XblMultiplayerSessionReference sessionRef);\n    bool IsGame(_In_ XblMultiplayerSessionReference sessionRef);\n    bool IsMatch(_In_ XblMultiplayerSessionReference sessionRef);\n\n    HRESULT FindMatch(\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ JsonValue& attributes,\n        _In_ const std::chrono::seconds& timeout\n        );\n\n    void SetAutoFillMembersDuringMatchmaking(_In_ bool autoFillMembers);\n\n    HRESULT SetJoinability(\n        _In_ XblMultiplayerJoinability value,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetProperties(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetSynchronizedProperties(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetSynchronizedHost(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ const xsapi_internal_string& hostDeviceToken,\n        _In_opt_ context_t context\n        );\n\n    std::shared_ptr<MultiplayerMember> ConvertToGameMember(_In_ const XblMultiplayerSessionMember* member);\n\nprivate:\n    void AddToPendingQueue(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ std::shared_ptr<MultiplayerClientPendingRequest> pendingRequest\n        );\n\n    static bool IsLocal(_In_ uint64_t xuid, _In_ const xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>& xboxLiveContextMap);\n\n    TaskQueue m_queue;\n    bool m_autoFillMembers;\n    MultiplayerEventQueue m_multiplayerEventQueue;\n    mutable std::mutex m_clientRequestLock;\n    std::shared_ptr<MultiplayerLobbyClient> m_lobbyClient;\n    std::shared_ptr<MultiplayerGameClient> m_gameClient;\n    std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerMatchClient> m_matchClient;\n    std::shared_ptr<MultiplayerLocalUserManager> m_multiplayerLocalUserManager;\n};\n\nclass MultiplayerLocalUser\n{\npublic:\n\n    MultiplayerLocalUser(\n        _In_ User&& user,\n        _In_ uint64_t xboxUserId,\n        _In_ bool isPrimary\n        );\n\n    ~MultiplayerLocalUser();\n\n    uint64_t Xuid() const;\n    std::shared_ptr<XblContext> Context() const;\n\n    const xsapi_internal_string& LobbyHandleId() const;\n    void SetLobbyHandleId(_In_ const xsapi_internal_string& handleId);\n    MultiplayerLocalUserLobbyState LobbyState() const;\n    void SetLobbyState(_In_ MultiplayerLocalUserLobbyState userState);\n    MultiplayerLocalUserGameState GameState() const;\n    void SetGameState(_In_ MultiplayerLocalUserGameState userState);\n    const xsapi_internal_string& ConnectionAddress() const;\n    void SetConnectionAddress(_In_ const xsapi_internal_string& address);\n    bool IsPrimaryXboxLiveContext() const;\n    void SetIsPrimaryXboxLiveContext(_In_ bool isPrimary);\n    bool WriteChangesToService() const;\n    void SetWriteChangesToService(_In_ bool value);\n    XblFunctionContext SessionChangedContext() const;\n    void SetSessionChangedContext(_In_ XblFunctionContext functionContext);\n    XblFunctionContext RtaResyncContext() const;\n    void SetRtaResyncContext(_In_ XblFunctionContext functionContext);\n    XblFunctionContext ConnectionIdChangedContext() const;\n    void SetConnectionIdChangedContext(_In_ XblFunctionContext functionContext);\n    XblFunctionContext SubscriptionLostContext() const;\n    void SetSubscriptionLostContext(_In_ XblFunctionContext functionContext);\n\nprivate:\n    XblFunctionContext m_sessionChangedContext{};\n    XblFunctionContext m_connectionIdChangedContext{};\n    XblFunctionContext m_subscriptionLostContext{};\n    XblFunctionContext m_rtaResyncContext{};\n    bool m_writeChangesToService{ false };\n    uint64_t m_xuid{ 0 };\n    xsapi_internal_string m_connectionAddress;\n    xsapi_internal_string m_lobbyHandleId;\n    MultiplayerLocalUserLobbyState m_lobbyState{ MultiplayerLocalUserLobbyState::Unknown };\n    MultiplayerLocalUserGameState m_gameState{ MultiplayerLocalUserGameState::Unknown };\n    bool m_isPrimaryXboxLiveContext{ false };\n    std::shared_ptr<XblContext> m_xboxLiveContextImpl;\n};\n\nclass MultiplayerLocalUserManager : public std::enable_shared_from_this<MultiplayerLocalUserManager>\n{\npublic:\n    MultiplayerLocalUserManager() = default;\n    ~MultiplayerLocalUserManager();\n\n    std::shared_ptr<XblContext> GetPrimaryContext();\n\n    void ChangeAllLocalUserLobbyState(_In_ MultiplayerLocalUserLobbyState state);\n    void ChangeAllLocalUserGameState(_In_ MultiplayerLocalUserGameState state);\n    bool IsLocalUserGameState(_In_ MultiplayerLocalUserGameState state);\n\n    const xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>& GetLocalUserMap();\n    std::shared_ptr<XblContext> GetContext(_In_ uint64_t xuid);\n\n    std::shared_ptr<MultiplayerLocalUser> GetLocalUser(_In_ uint64_t xuid);\n    std::shared_ptr<MultiplayerLocalUser> GetLocalUserHelper(_In_ uint64_t xuid);\n\n    std::shared_ptr<MultiplayerLocalUser> GetLocalUser(\n        _In_ xbox_live_user_t user\n    );\n\n    std::shared_ptr<MultiplayerLocalUser> GetLocalUserHelper(\n        _In_ xbox_live_user_t user\n    );\n\n    Result<const std::shared_ptr<MultiplayerLocalUser>> AddUserToXboxLiveContextToMap(_In_ xbox_live_user_t user);\n    void RemoveStaleLocalUsersFromMap();\n\n    void ActivateMultiplayerEvents(_In_ const std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerLocalUser>& localuser);\n    void DeactivateMultiplayerEvents(_In_ const std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerLocalUser>& localUser);\n\n    XblFunctionContext AddMultiplayerSessionChangedHandler(\n        _In_ Callback<XblMultiplayerSessionChangeEventArgs> handler\n        );\n    void RemoveMultiplayerSessionChangedHandler(_In_ XblFunctionContext context);\n\n\n    XblFunctionContext AddMultiplayerConnectionIdChangedHandler(_In_ Function<void()> handler);\n    void RemoveMultiplayerConnectionIdChangedHandler(_In_ XblFunctionContext context);\n\n    XblFunctionContext AddMultiplayerSubscriptionLostHandler(_In_ Function<void()> handler);\n    void RemoveMultiplayerSubscriptionLostHandler(_In_ XblFunctionContext context);\n\n    XblFunctionContext AddRtaResyncHandler(_In_ Function<void()> handler);\n    void RemoveRtaResyncHandler(_In_ XblFunctionContext context);\n\nprivate:\n    std::mutex m_lock;\n\n    void OnConnectionIdChanged();\n\n    void OnSubscriptionsLost(_In_ uint64_t xuid);\n\n    void OnSessionChanged(\n        _In_ const XblMultiplayerSessionChangeEventArgs& args\n        );\n\n    void OnConnectionStateChanged(\n        _In_ uint64_t xuid,\n        _In_ XblRealTimeActivityConnectionState state\n        );\n\n    void OnResyncMessageReceived();\n\n    std::mutex m_subscriptionLock;\n\tXblFunctionContext m_sessionChangeEventHandlerCounter{ 1 };\n\tXblFunctionContext m_multiplayerConnectionIdChangedEventHandlerCounter{ 1 };\n\tXblFunctionContext m_multiplayerSubscriptionLostEventHandlerCounter{ 1 };\n\tXblFunctionContext m_rtaResyncEventHandlerCounter{ 1 };\n    xsapi_internal_unordered_map<uint32_t, Callback<XblMultiplayerSessionChangeEventArgs>> m_sessionChangeEventHandler;\n    xsapi_internal_unordered_map<uint32_t, Function<void()>> m_multiplayerConnectionIdChangedEventHandler;\n    xsapi_internal_unordered_map<uint32_t, Function<void()>> m_multiplayerSubscriptionLostEventHandler;\n    xsapi_internal_unordered_map<uint32_t, Function<void()>> m_rtaResyncEventHandler;\n\n    xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>> m_localUserRequestMap;\n    std::shared_ptr<XblContext> m_primaryXboxLiveContext;\n    TaskQueue m_queue;\n};\n\nclass MultiplayerClientManager : public std::enable_shared_from_this<MultiplayerClientManager>\n{\npublic:\n    MultiplayerClientManager(_In_ const MultiplayerClientManager& other);\n    MultiplayerClientManager(\n        _In_ const xsapi_internal_string& lobbySessionTemplateName,\n        _In_ const TaskQueue& queue\n    );\n\n    ~MultiplayerClientManager() = default;\n\n    void Initialize();\n    void Shutdown();\n\n    void RegisterLocalUserManagerEvents();\n    bool IsUpdateAvailable();\n    bool IsRequestInProgress();\n\n    std::shared_ptr<MultiplayerLocalUserManager> LocalUserManager();\n\n    std::shared_ptr<XblContext> GetPrimaryContext();\n\n    std::shared_ptr<MultiplayerLobbyClient> LobbyClient() const;\n    std::shared_ptr<MultiplayerClientPendingReader> LatestPendingRead() const;\n    std::shared_ptr<MultiplayerClientPendingReader> LastPendingRead() const;\n\n    HRESULT JoinLobbyByHandle(\n        _In_ const xsapi_internal_string& handleId,\n        _In_ const xsapi_internal_vector<xbox_live_user_t>& users\n        );\n\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK\n    HRESULT JoinLobby(\n        _In_ Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ eventArgs,\n        _In_ xsapi_internal_vector<xbox_live_user_t> users\n        );\n\n    HRESULT JoinLobby( _In_ Windows::Foundation::Uri^ url, _In_ xsapi_internal_vector<xbox_live_user_t> users);\n#endif\n    HRESULT JoinGameFromLobby(_In_ const xsapi_internal_string& sessionTemplateName);\n\n    HRESULT JoinGame(\n        _In_ const xsapi_internal_string& sessionName,\n        _In_ const xsapi_internal_string& sessionTemplateName,\n        _In_ const xsapi_internal_vector<uint64_t>& xuids\n        );\n\n    HRESULT LeaveGame();\n\n    MultiplayerEventQueue DoWork(); // TODO see if we can switch these to ref\n\n    HRESULT GetActivitiesForSocialGroup(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& socialGroup,\n        _In_ XTaskQueueHandle queue,\n        _In_ Callback<Result<xsapi_internal_vector<XblMultiplayerActivityDetails>>> callback\n        );\n\n    HRESULT InviteFriends(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_string& contextStringId,\n        _In_ const xsapi_internal_string& customActivationContext\n        );\n\n    HRESULT InviteUsers(\n        _In_ xbox_live_user_t user,\n        _In_ const xsapi_internal_vector<uint64_t>& xboxUserIds,\n        _In_ const xsapi_internal_string& contextStringId,\n        _In_ const xsapi_internal_string& customActivationContext\n        );\n\n    HRESULT SetProperties(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetJoinability(\n        _In_ XblMultiplayerJoinability value,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetSynchronizedHost(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ const xsapi_internal_string& hostDeviceToken,\n        _In_opt_ context_t context\n        );\n\n    HRESULT SetSynchronizedProperties(\n        _In_ const XblMultiplayerSessionReference& sessionRef,\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson,\n        _In_opt_ context_t context\n        );\n\n    std::shared_ptr<MultiplayerMatchClient> MatchClient();\n\n    HRESULT FindMatch(\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ JsonValue& attributes,\n        _In_ const std::chrono::seconds& timeout\n        );\n\n    void SetAutoFillMembersDuringMatchmaking(_In_ bool autoFillMembers);\n\n    void OnSessionChanged(\n        _In_ XblMultiplayerSessionChangeEventArgs args\n        );\n\n    const MultiplayerEventQueue& EventQueue() const;\n    void ClearEventQueue();\n\n    void OnMultiplayerConnectionIdChanged();\n\n    void OnMultiplayerSubscriptionsLost();\n\nprivate:\n    MultiplayerClientManager& operator=(MultiplayerClientManager other) = delete;\n\n    void Destroy();\n\n    Result<std::shared_ptr<xbox::services::multiplayer::MultiplayerService>> GetMultiplayerService(\n        _In_ xbox_live_user_t user\n        );\n\n    xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>> GetXboxLiveContextMap();\n\n    void OnResyncMessageReceived();\n\n    void AddToLatestPendingReadEventQueue(\n        _In_ XblMultiplayerEventType eventType,\n        _In_ XblMultiplayerSessionType sessionType,\n        _In_ std::shared_ptr<XblMultiplayerEventArgs> eventArgs = nullptr,\n        _In_opt_ Result<void> error = {},\n        _In_opt_ context_t context = nullptr\n    );\n\n    XblMultiplayerSessionType GetSessionType(\n        _In_ std::shared_ptr<XblMultiplayerSession> session\n        );\n\n    void ProcessEvents(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n        _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\n    void HandleMemberListChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n        _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\n    void HandleMemberPropertiesChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n        _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\n    void HandleSessionPropertiesChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n        _In_ std::shared_ptr<XblMultiplayerSession> oldSession,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\n    void HandleHostChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\n    void HandleMatchStatusChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession\n        );\n\n    void HandleInitializationStateChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession\n        );\n\n    void SynchronizedWriteCompleted(\n        _In_ std::error_code errorCode,\n        _In_ XblMultiplayerEventType eventType,\n        _In_ XblMultiplayerSessionType sessionType\n        );\n\n    mutable std::mutex m_clientRequestLock;\n    std::mutex m_synchronizeWriteWithTapLock;\n    std::atomic<bool> m_subscriptionsLostFired;\n\n    bool m_autoFillMembers{ false };\n    xsapi_internal_string m_lobbySessionTemplateName;\n    XblFunctionContext m_sessionChangedContext{ 0 };\n    XblFunctionContext m_connectionIdChangedContext{ 0 };\n    XblFunctionContext m_subscriptionLostContext{ 0 };\n    XblFunctionContext m_rtaResyncContext{ 0 };\n\n    MultiplayerEventQueue m_multiplayerEventQueue;\n    std::shared_ptr<XblContext> m_primaryXboxLiveContext;\n    std::shared_ptr<MultiplayerLocalUserManager> m_multiplayerLocalUserManager;\n    std::shared_ptr<MultiplayerClientPendingReader> m_lastPendingRead;\n    std::shared_ptr<MultiplayerClientPendingReader> m_latestPendingRead;\n\n    TaskQueue m_queue;\n};\n\nclass MultiplayerMatchClient : public std::enable_shared_from_this<MultiplayerMatchClient>\n{\npublic:\n    MultiplayerMatchClient(\n        _In_ const TaskQueue& queue,\n        _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n    ) noexcept;\n\n    ~MultiplayerMatchClient() noexcept = default;\n\n    MultiplayerEventQueue DoWork();\n    const MultiplayerEventQueue& EventQueue();\n    // TODO remove in favor of assignment operator\n    void deep_copy_if_updated(_In_ const MultiplayerMatchClient& other);\n\n    XblMultiplayerMatchStatus MatchStatus() const;\n    void SetMatchStatus(_In_ XblMultiplayerMatchStatus status);\n\n    const std::chrono::seconds EstimatedMatchWaitTime() const;\n\n    HRESULT FindMatch(\n        _In_ const xsapi_internal_string& hopperName,\n        _In_ JsonValue& attributes,\n        _In_ const std::chrono::seconds& timeout,\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ bool preserveSession = false\n        );\n\n    HRESULT FindMatch(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ bool preserveSession\n        );\n\n    void CancelMatch();\n\n    void UpdateSession(_In_ std::shared_ptr<XblMultiplayerSession> currentSession);\n    std::shared_ptr<XblMultiplayerSession> Session();\n\n    void HandleMatchStatusChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> matchSession\n        );\n\n    void HandleInitializationStateChanged(\n        _In_ std::shared_ptr<XblMultiplayerSession> matchSession\n        );\n\n    void OnSessionChanged(\n        _In_ const XblMultiplayerSessionChangeEventArgs& args\n        );\n\n    void SetQosMeasurements(\n        _In_ const JsonValue& measurements\n    ) noexcept;\n\n    void ResubmitMatchmaking(\n        _In_ std::shared_ptr<XblMultiplayerSession> session\n        );\n\n    void HandleFindMatchCompleted(\n        _In_ Result<void> error\n        );\n\n    void DisableNextTimer(bool value);\n\n    bool m_disableNextTimer{ false };\n\nprivate:\n    void CheckNextTimer();\n    void HandleSessionJoined();\n    void GetLatestSession();\n    void HandleQosMeasurements();\n\n    void HandleMatchFound(\n        _In_ std::shared_ptr<XblMultiplayerSession> currentSession\n    ) noexcept;\n\n    HRESULT JoinSession(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ MultiplayerSessionCallback callback\n    ) noexcept;\n\n    TaskQueue m_queue;\n    std::mutex m_lock;\n    std::mutex m_getSessionLock;\n    xbox::services::datetime m_nextTimerToFetchSession;\n    String m_hopperName;\n    JsonDocument m_attributes;\n    std::chrono::seconds m_timeout{};\n    bool m_preservingMatchmakingSession{ false };\n    std::atomic<XblMultiplayerMatchStatus> m_matchStatus{ XblMultiplayerMatchStatus::None };\n    mutable std::mutex m_multiplayerEventQueueLock;\n    MultiplayerEventQueue m_multiplayerEventQueue;\n    XblCreateMatchTicketResponse m_matchTicketResponse{};\n    XblMultiplayerSessionReference m_matchTicketSessionRef{};\n    std::shared_ptr<XblMultiplayerSession> m_matchSession;\n    std::shared_ptr<MultiplayerLocalUserManager> m_multiplayerLocalUserManager;\n\n    std::atomic<bool> m_getSessionInProgress{ false };\n    std::atomic<bool> m_joinTargetSessionComplete{ false };\n    Result<std::shared_ptr<XblMultiplayerSession>> m_joinTargetSessionResult;\n};\n\nclass MultiplayerManagerUtils\n{\npublic:\n    static bool IsMultiplayerSessionChangeType(\n        _In_ XblMultiplayerSessionChangeTypes diffType,\n        _In_ XblMultiplayerSessionChangeTypes value\n        )\n    {\n        return (diffType & value) == value;\n    }\n\n    static bool CompareSessions(\n        _In_ const std::shared_ptr<XblMultiplayerSession>& session1,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& session2\n        );\n\n    static void SetJoinability(\n        _In_ XblMultiplayerJoinability value,\n        _In_ std::shared_ptr<XblMultiplayerSession> sessionToCommit,\n        _In_ bool isGameInProgress\n        );\n\n    static XblMultiplayerJoinability GetJoinability(\n        _In_ const XblMultiplayerSessionProperties& sessionProperties\n        );\n\n    static XblMultiplayerJoinability ConvertStringToJoinability(\n        _In_ const xsapi_internal_string& value\n        );\n\n    static xsapi_internal_string ConvertJoinabilityToString(_In_ XblMultiplayerJoinability value);\n};\n\n}}}}\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_manager_utils.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services::legacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nbool MultiplayerManagerUtils::CompareSessions(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& session1,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& session2\n    )\n{\n    if (session1 == nullptr && session2 == nullptr)\n    {\n        return true;\n    }\n\n    if ( (session1 == nullptr && session2 != nullptr) ||\n         (session1 != nullptr && session2 == nullptr) ||\n         session1->SessionInfo().ChangeNumber != session2->SessionInfo().ChangeNumber)\n    {\n        return false;\n    }\n\n    return true;\n}\n\n\n// joinable_by_friends                 : !closed & JoinRestricion::Followed\n// invite_only                         : !closed & JoinRestricion::Local\n// disable_while_game_in_progress      : closed & JoinRestricion::Local (when in game)\n// closed                              : closed & JoinRestricion::Local\n\nvoid MultiplayerManagerUtils::SetJoinability(\n    _In_ XblMultiplayerJoinability value,\n    _In_ std::shared_ptr<XblMultiplayerSession> sessionToCommit,\n    _In_ bool isGameInProgress\n    )\n{\n    sessionToCommit->SetClosed(false);\n    sessionToCommit->SetJoinRestriction(XblMultiplayerSessionRestriction::Local);\n    if (value == XblMultiplayerJoinability::JoinableByFriends)\n    {\n        sessionToCommit->SetJoinRestriction(XblMultiplayerSessionRestriction::Followed);\n    }\n    else if (value == XblMultiplayerJoinability::Closed ||\n            (isGameInProgress && value == XblMultiplayerJoinability::DisableWhileGameInProgress))\n    {\n        sessionToCommit->SetClosed(true);\n    }\n\n    xsapi_internal_string jsonValueStr = ConvertJoinabilityToString(value);\n    JsonDocument json;\n    json.SetString(jsonValueStr.c_str(), json.GetAllocator());\n    sessionToCommit->SetSessionCustomPropertyJson(MultiplayerLobbyClient_JoinabilityPropertyName, json);\n}\n\nXblMultiplayerJoinability MultiplayerManagerUtils::GetJoinability(\n    _In_ const XblMultiplayerSessionProperties& sessionProperties\n    )\n{\n    xsapi_internal_string joinableStr;\n    JsonDocument jsonDoc;\n    jsonDoc.Parse(sessionProperties.SessionCustomPropertiesJson);\n\n    if (!jsonDoc.HasParseError())\n    {\n        JsonUtils::ExtractJsonString(jsonDoc, MultiplayerLobbyClient_JoinabilityPropertyName, joinableStr, false);\n    }\n\n    return ConvertStringToJoinability(joinableStr);\n}\n\nXblMultiplayerJoinability MultiplayerManagerUtils::ConvertStringToJoinability(\n    _In_ const xsapi_internal_string& value\n    )\n{\n    if (utils::str_icmp_internal(value, \"joinable_by_friends\") == 0)\n    {\n        return XblMultiplayerJoinability::JoinableByFriends;\n    }\n    else if (utils::str_icmp_internal(value, \"invite_only\") == 0)\n    {\n        return XblMultiplayerJoinability::InviteOnly;\n    }\n    else if (utils::str_icmp_internal(value, \"disable_while_game_in_progress\") == 0)\n    {\n        return XblMultiplayerJoinability::DisableWhileGameInProgress;\n    }\n    else if (utils::str_icmp_internal(value, \"closed\") == 0)\n    {\n        return XblMultiplayerJoinability::Closed;\n    }\n\n    return XblMultiplayerJoinability::None;\n}\n\nxsapi_internal_string MultiplayerManagerUtils::ConvertJoinabilityToString(\n    _In_ XblMultiplayerJoinability value\n    )\n{\n    switch (value)\n    {\n        case XblMultiplayerJoinability::JoinableByFriends: return \"joinable_by_friends\";\n        case XblMultiplayerJoinability::InviteOnly: return \"invite_only\";\n        case XblMultiplayerJoinability::DisableWhileGameInProgress: return \"disable_while_game_in_progress\";\n        case XblMultiplayerJoinability::Closed: return \"closed\";\n        default: return \"none\";\n    }\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_match_client.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n#include \"multiplayer_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::legacy;\nusing namespace xbox::services::system;\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services::matchmaking;\n#if HC_PLATFORM == HC_PLATFORM_XDK\nusing namespace Windows::Xbox::Networking;\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerMatchClient::MultiplayerMatchClient(\n    _In_ const TaskQueue& queue,\n    _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_multiplayerLocalUserManager{ localUserManager }\n{\n}\n\nvoid MultiplayerMatchClient::deep_copy_if_updated(\n    _In_ const MultiplayerMatchClient& other\n)\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    if (other.m_matchSession == nullptr)\n    {\n        m_matchSession = nullptr;\n    }\n    else if (m_matchSession == nullptr || other.m_matchSession->SessionInfo().ChangeNumber > m_matchSession->SessionInfo().ChangeNumber)\n    {\n        m_matchSession = MakeShared<XblMultiplayerSession>(*other.m_matchSession);\n    }\n}\n\nconst MultiplayerEventQueue&\nMultiplayerMatchClient::EventQueue()\n{\n    return m_multiplayerEventQueue;\n}\n\nMultiplayerEventQueue\nMultiplayerMatchClient::DoWork()\n{\n    switch (static_cast<XblMultiplayerMatchStatus>(m_matchStatus))\n    {\n        case XblMultiplayerMatchStatus::None:\n        {\n            return MultiplayerEventQueue();\n        }\n\n        case XblMultiplayerMatchStatus::Searching:\n        {\n            CheckNextTimer();\n            break;\n        }\n\n        case XblMultiplayerMatchStatus::Found:\n        case XblMultiplayerMatchStatus::Canceled:\n        {\n            // Nothing to do here. Wait for match_status_changed event.\n            break;\n        }\n\n        case XblMultiplayerMatchStatus::Joining:\n        {\n            if(m_joinTargetSessionComplete)\n            {\n                HandleSessionJoined();\n            }\n            break;\n        }\n\n        case XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin:\n        case XblMultiplayerMatchStatus::WaitingForRemoteClientsToUploadQos:\n        {\n            HandleInitializationStateChanged(Session());\n            break;\n        }\n\n        case XblMultiplayerMatchStatus::Measuring:\n        {\n            // Waiting for title to perform qos and provide qos measurements (via set_quality_of_service_measurements)\n            HandleInitializationStateChanged(Session());\n            break;\n        }\n\n        case XblMultiplayerMatchStatus::Evaluating:\n        {\n            // Nothing to do here. Wait for initialization stage changed event.\n            break;\n        }\n            \n        default:\n            break;\n    }\n\n    MultiplayerEventQueue eventQueue;\n    {\n        std::lock_guard<std::mutex> lock(m_multiplayerEventQueueLock);\n        eventQueue = m_multiplayerEventQueue;\n        m_multiplayerEventQueue.Clear();\n    }\n\n    return eventQueue;\n}\n\nvoid\nMultiplayerMatchClient::DisableNextTimer(bool value)\n{\n    m_disableNextTimer = value;\n}\n\nvoid\nMultiplayerMatchClient::CheckNextTimer()\n{\n    if (m_disableNextTimer) return;     // Only used for Unit tests\n\n    int64_t delta = m_nextTimerToFetchSession.to_interval() - xbox::services::datetime::utc_now().to_interval();\n    if ( delta < 0)\n    {\n        if (m_matchStatus == XblMultiplayerMatchStatus::Searching)\n        {\n            std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n            if (primaryContext == nullptr || m_getSessionInProgress)\n            {\n                return;\n            }\n\n            // Fetch ticket session\n            std::weak_ptr<MultiplayerMatchClient> weakSessionWriter = shared_from_this();\n            m_getSessionInProgress = true;\n\n            primaryContext->MultiplayerService()->GetCurrentSession(m_matchTicketSessionRef, { m_queue,\n            [weakSessionWriter](Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n            {\n                std::shared_ptr<MultiplayerMatchClient> pThis(weakSessionWriter.lock());\n                if (pThis != nullptr)\n                {\n                    if (SUCCEEDED(sessionResult.Hresult()))\n                    {\n                        pThis->HandleMatchStatusChanged(sessionResult.Payload());\n                    }\n                    pThis->m_getSessionInProgress = false;\n                }\n            }\n            });\n        }\n        else\n        {\n            GetLatestSession();\n        }\n    }\n}\n\nvoid\nMultiplayerMatchClient::HandleQosMeasurements()\n{\n    std::shared_ptr<PerformQosMeasurementsEventArgs> performQosEventArgs = MakeShared<PerformQosMeasurementsEventArgs>();\n\n    XblMultiplayerSessionReadLockGuard sessionSafe(Session());\n    for (const auto& member : sessionSafe.Members())\n    {\n        if (!member.IsCurrentUser)\n        {\n            std::vector<unsigned char> base64ConnectionAddress(xbox::services::convert::from_base64(member.SecureDeviceBaseAddress64));\n            const xsapi_internal_string& secureDeviceAddress = xsapi_internal_string(base64ConnectionAddress.begin(), base64ConnectionAddress.end());\n            if (!secureDeviceAddress.empty())\n            {\n                performQosEventArgs->AddRemoteClient(secureDeviceAddress, member.DeviceToken.Value);\n            }\n        }\n    }\n\n    if (performQosEventArgs->remoteClients.size() > 0)\n    {\n        m_matchStatus = XblMultiplayerMatchStatus::Measuring;\n\n        {\n            std::lock_guard<std::mutex> lock(m_multiplayerEventQueueLock);\n            m_multiplayerEventQueue.AddEvent(\n                XblMultiplayerEventType::PerformQosMeasurements,\n                XblMultiplayerSessionType::GameSession,\n                std::dynamic_pointer_cast<PerformQosMeasurementsEventArgs>(performQosEventArgs)\n            );\n        }\n    }\n    else\n    {\n        // If clients fail to join, the stage advances to \"measuring\".\n        // Wait until memberInitialization either succeeds or fails.\n        CheckNextTimer();\n    }\n}\n\nvoid\nMultiplayerMatchClient::HandleFindMatchCompleted(\n    _In_ Result<void> error\n    )\n{\n    XblMultiplayerMeasurementFailure failure = XblMultiplayerMeasurementFailure::Unknown;\n\n    auto matchSession = Session();\n    XblMultiplayerSessionReadLockGuard matchSessionSafe(matchSession);\n    if (matchSession != nullptr && matchSessionSafe.CurrentUser() != nullptr)\n    {\n        failure = matchSessionSafe.CurrentUser()->InitializationFailureCause;\n    }\n\n    std::shared_ptr<FindMatchCompletedEventArgs> findMatchEventArgs = MakeShared<FindMatchCompletedEventArgs>(\n        m_matchStatus,\n        failure\n        );\n\n    {\n        std::lock_guard<std::mutex> lock(m_multiplayerEventQueueLock);\n        m_multiplayerEventQueue.AddEvent(\n            XblMultiplayerEventType::FindMatchCompleted,\n            XblMultiplayerSessionType::GameSession,\n            std::dynamic_pointer_cast<FindMatchCompletedEventArgs>(findMatchEventArgs),\n            error\n        );\n    }\n}\n\nvoid\nMultiplayerMatchClient::HandleMatchStatusChanged(\n    _In_ std::shared_ptr<XblMultiplayerSession> matchSession\n    )\n{\n    switch (matchSession->MatchmakingServer()->Status)\n    {\n        case XblMatchmakingStatus::Searching:\n        {\n            XblMultiplayerMatchStatus expected = XblMultiplayerMatchStatus::None;\n            if (m_matchStatus.compare_exchange_strong(expected, XblMultiplayerMatchStatus::Searching, std::memory_order_release))\n            {\n                // Wait for status to change on ticket session or fetch after 2 mins.\n                m_nextTimerToFetchSession = xbox::services::datetime::utc_now() + xbox::services::datetime::from_seconds(120);\n            }\n            else \n            {\n                if (m_disableNextTimer) return;     // Only used for Unit tests\n\n                int64_t delta = m_nextTimerToFetchSession.to_interval() - xbox::services::datetime::utc_now().to_interval();\n                if ( delta < 0)\n                {\n                    // Delete the match ticket and let the title know that it failed.\n                    if (!m_hopperName.empty() && m_matchTicketResponse.matchTicketId[0] != '\\0')\n                    {\n                        // Only the host has the ticketId info. Since we aren't the host who started the match, we cannot cancel it either.\n                        std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n                        if (primaryContext == nullptr)\n                        {\n                            return;\n                        }\n\n                        auto asyncBlock = utils::MakeDefaultAsyncBlock(m_queue.GetHandle());\n                        primaryContext->MatchmakingService()->DeleteMatchTicketAsync(\n                            AppConfig::Instance()->Scid(),\n                            m_hopperName,\n                            m_matchTicketResponse.matchTicketId,\n                            asyncBlock\n                        );\n                    }\n\n                    m_matchStatus = XblMultiplayerMatchStatus::Failed;\n                    HandleFindMatchCompleted({ xbl_error_code::generic_error, \"Timer exceeded\" });\n                }\n            }\n            break;\n        }\n        case XblMatchmakingStatus::Expired:\n        {\n            m_matchStatus = XblMultiplayerMatchStatus::Expired;\n            HandleFindMatchCompleted({ xbl_error_code::generic_error, \"Match status: Expired\" });\n            break;\n        }\n        case XblMatchmakingStatus::Canceled:\n        {\n            m_matchStatus = XblMultiplayerMatchStatus::Canceled;\n            HandleFindMatchCompleted({ xbl_error_code::generic_error, \"Match status: Canceled\" });\n            break;\n        }\n        case XblMatchmakingStatus::Found:\n        {\n            HandleMatchFound(matchSession);\n            break;\n        }\n        default:\n            break;\n    }\n}\n\nvoid\nMultiplayerMatchClient::HandleInitializationStateChanged(\n    _In_ std::shared_ptr<XblMultiplayerSession> matchSession\n    )\n{\n    UpdateSession(matchSession);\n    if (matchSession->InitializationInfo().Episode > 0)\n    {\n        switch (matchSession->InitializationInfo().Stage)\n        {\n            case XblMultiplayerInitializationStage::Joining:\n            {\n                CheckNextTimer();\n                break;\n            }\n            case XblMultiplayerInitializationStage::Measuring:\n            {\n                if (m_matchStatus == XblMultiplayerMatchStatus::WaitingForRemoteClientsToUploadQos ||\n                    m_matchStatus == XblMultiplayerMatchStatus::Measuring)\n                {\n                    CheckNextTimer();\n                }\n                else if (m_matchStatus == XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin)\n                {\n                    HandleQosMeasurements();\n                }\n                break;\n            }\n            case XblMultiplayerInitializationStage::Failed:\n            {\n                m_matchStatus = XblMultiplayerMatchStatus::Failed;\n                HandleFindMatchCompleted({ xbl_error_code::generic_error, \"Initialization failed\" });\n                return;\n            }\n                \n            default:\n                break;\n        }\n    }\n    else\n    {\n        XblMultiplayerSessionReadLockGuard matchSessionSafe(matchSession);\n        if (matchSessionSafe.CurrentUser()->InitializationFailureCause == XblMultiplayerMeasurementFailure::None)\n        {\n            // QoS succeeded.\n            m_matchStatus = XblMultiplayerMatchStatus::Completed;\n            HandleFindMatchCompleted({ xbl_error_code::no_error });\n        }\n        else\n        {\n            // Resubmit\n            m_matchStatus = XblMultiplayerMatchStatus::Resubmitting;\n            HandleFindMatchCompleted({ xbl_error_code::generic_error, \"Measurement failure\" });\n        }\n    }\n}\n\nHRESULT\nMultiplayerMatchClient::FindMatch(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ bool preserveSession\n    )\n{\n    return FindMatch(m_hopperName, m_attributes, m_timeout, session, preserveSession);\n}\n\nHRESULT\nMultiplayerMatchClient::FindMatch(\n    _In_ const xsapi_internal_string& hopperName,\n    _In_ JsonValue& attributes,\n    _In_ const std::chrono::seconds& timeout,\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ bool preserveSession\n    )\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    RETURN_HR_IF_LOG_DEBUG(primaryContext == nullptr || session == nullptr, E_UNEXPECTED, \"No local user added. Call add_local_user() first.\");\n\n    XblMultiplayerMatchStatus expected = XblMultiplayerMatchStatus::None;\n    RETURN_HR_IF_LOG_DEBUG(!m_matchStatus.compare_exchange_strong(expected, XblMultiplayerMatchStatus::SubmittingMatchTicket, std::memory_order_release), E_UNEXPECTED, \"Match search already in progress.\");\n\n    if (preserveSession)\n    {\n        UpdateSession(session);\n    }\n    else\n    {\n        UpdateSession(nullptr);\n    }\n\n    m_hopperName = hopperName;\n    JsonUtils::CopyFrom(m_attributes, attributes);\n    m_timeout = timeout;\n    m_preservingMatchmakingSession = preserveSession;\n    m_matchTicketSessionRef = session->SessionReference();\n\n    std::weak_ptr<MultiplayerMatchClient> thisWeakPtr = shared_from_this();\n\n    auto asyncBlock = utils::MakeAsyncBlock(\n        m_queue.GetHandle(),\n        utils::store_weak_ptr<MultiplayerMatchClient>(shared_from_this()),\n        [](XAsyncBlock* asyncBlock)\n    {\n        auto pThis = utils::get_shared_ptr<MultiplayerMatchClient>(asyncBlock->context);\n        if (pThis != nullptr)\n        {\n            XblCreateMatchTicketResponse result;\n            auto hr = XblMatchmakingCreateMatchTicketResult(asyncBlock, &result);              \n            if (SUCCEEDED(hr))\n            {\n                pThis->m_matchTicketResponse = result;\n                pThis->m_matchStatus = XblMultiplayerMatchStatus::Searching;\n                pThis->m_nextTimerToFetchSession = xbox::services::datetime::utc_now()\n                   + xbox::services::datetime::from_seconds(static_cast<int32_t>(pThis ->m_timeout.count()))\n                   + xbox::services::datetime::from_seconds(5);   // some extra delay to be safe\n            }\n\n            if (FAILED(hr))\n            {\n                pThis->m_matchStatus = XblMultiplayerMatchStatus::Failed;\n                pThis->HandleFindMatchCompleted({ hr, \"MatchTicketResult failed\" });\n            }\n        }\n        Delete(asyncBlock);\n    });\n\n    return primaryContext->MatchmakingService()->CreateMatchTicket(\n        session->SessionReference(),\n        session->SessionReference().Scid,\n        hopperName,\n        timeout,\n        preserveSession ? XblPreserveSessionMode::Always : XblPreserveSessionMode::Never,\n        attributes,\n        asyncBlock);\n}\n\nvoid\nMultiplayerMatchClient::CancelMatch()\n{\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    if (primaryContext == nullptr)\n    {\n         return;\n    }\n\n    if (m_matchStatus == XblMultiplayerMatchStatus::None || m_matchStatus == XblMultiplayerMatchStatus::Expired ||\n        m_matchStatus == XblMultiplayerMatchStatus::Canceled || m_matchStatus == XblMultiplayerMatchStatus::Failed)\n    {\n        return;\n    }\n\n    if (m_hopperName.empty() && m_matchTicketResponse.matchTicketId[0] != '\\0')\n    {\n        // Since we aren't the host who started the match, we cannot cancel it either.\n        return;\n    }\n\n    m_matchStatus = XblMultiplayerMatchStatus::Canceling;\n    auto asyncBlock = utils::MakeDefaultAsyncBlock(m_queue.GetHandle());\n    primaryContext->MatchmakingService()->DeleteMatchTicketAsync(\n        AppConfig::Instance()->Scid(),\n        m_hopperName,\n        m_matchTicketResponse.matchTicketId,\n        asyncBlock\n    );\n}\n\nXblMultiplayerMatchStatus\nMultiplayerMatchClient::MatchStatus() const\n{\n    return m_matchStatus;\n}\n\nvoid\nMultiplayerMatchClient::SetMatchStatus(\n    _In_ XblMultiplayerMatchStatus status\n    )\n{\n    m_matchStatus = status;\n}\n\nconst std::chrono::seconds\nMultiplayerMatchClient::EstimatedMatchWaitTime() const\n{\n    return std::chrono::seconds(m_matchTicketResponse.estimatedWaitTime);\n}\n\nvoid\nMultiplayerMatchClient::OnSessionChanged(\n    _In_ const XblMultiplayerSessionChangeEventArgs& args\n    )\n{\n    auto matchSession = Session();\n    if (matchSession != nullptr &&\n        matchSession->SessionReference() == args.SessionReference &&\n        args.ChangeNumber > matchSession->SessionInfo().ChangeNumber)\n    {\n        GetLatestSession();\n    }\n}\n\nvoid \nMultiplayerMatchClient::UpdateSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    if (m_matchSession == nullptr || session == nullptr)\n    {\n        m_matchSession = session;\n        m_matchTicketSessionRef = {};\n    }\n    else if(XblMultiplayerSession::DoSessionsMatch(m_matchSession, session) &&\n        session->SessionInfo().ChangeNumber > m_matchSession->SessionInfo().ChangeNumber)\n    {\n        m_matchSession = session;\n        m_nextTimerToFetchSession = xbox::services::datetime::utc_now() + xbox::services::datetime::from_seconds(static_cast<uint32_t>(session->SessionInfo().NextTimer - session->TimeOfSession()));\n    }\n}\n\nstd::shared_ptr<XblMultiplayerSession> \nMultiplayerMatchClient::Session()\n{\n    std::lock_guard<std::mutex> lock(m_lock);\n    return m_matchSession;\n}\n\nvoid\nMultiplayerMatchClient::HandleSessionJoined()\n{\n    if (FAILED(m_joinTargetSessionResult.Hresult()))\n    {\n        m_matchStatus = XblMultiplayerMatchStatus::Failed;\n        HandleFindMatchCompleted({ m_joinTargetSessionResult.Hresult(), \"JoinSession failed\" });\n        return;\n    }\n\n    if (Session()->InitializationInfo().Episode == 0)\n    {\n        m_matchStatus = XblMultiplayerMatchStatus::Completed;\n        HandleFindMatchCompleted({ xbl_error_code::no_error });\n    }\n    else\n    {\n        m_matchStatus = XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin;\n    }\n}\n\nvoid MultiplayerMatchClient::HandleMatchFound(\n    _In_ std::shared_ptr<XblMultiplayerSession> currentSession\n) noexcept\n{\n    std::shared_ptr<XblContext> primaryXboxLiveContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    if(primaryXboxLiveContext == nullptr)\n    {\n        m_matchStatus = XblMultiplayerMatchStatus::Failed;\n        // No primary xbox live context\n        HandleFindMatchCompleted({ xbl_error_code::runtime_error, \"No primary xbox live context\" });\n        return;\n    }\n\n    m_matchStatus = XblMultiplayerMatchStatus::Found;\n    auto& targetSessionRef = currentSession->MatchmakingServer()->TargetSessionRef;\n    auto targetGameSession = MakeShared<XblMultiplayerSession>(\n        primaryXboxLiveContext->Xuid(),\n        &targetSessionRef,\n        nullptr\n        );\n\n    auto state{ GlobalState::Get() };\n    auto gameClient = state ? state->MultiplayerManager()->GameClient() : nullptr;\n    if (m_preservingMatchmakingSession && gameClient != nullptr)\n    {\n        auto gameSession = gameClient->Session();\n        if (gameSession != nullptr && gameSession->SessionReference() == targetSessionRef)\n        {\n            targetGameSession = gameSession;\n        }\n    }\n\n    UpdateSession(targetGameSession);\n\n    JoinSession(targetGameSession,\n        [\n            weakThis = std::weak_ptr<MultiplayerMatchClient>{ shared_from_this() }\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> result)\n    {\n        auto pThis = weakThis.lock();\n        if (pThis)\n        {\n            // Perhaps its OK to call handle_session_joined() immediately here, but to maintain behavioral parody with\n            // pplx code, differ that until the next do_work call\n            pThis->m_joinTargetSessionResult = std::move(result);\n            pThis->m_joinTargetSessionComplete = true;\n        }\n    });\n}\n\nHRESULT MultiplayerMatchClient::JoinSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    // Join Match session for each local user.\n    struct JoinSessionOperation : public std::enable_shared_from_this<JoinSessionOperation>\n    {\n        JoinSessionOperation(\n            std::shared_ptr<MultiplayerMatchClient> matchClient,\n            std::shared_ptr<XblMultiplayerSession> session,\n            MultiplayerSessionCallback&& callback\n        ) noexcept :\n            m_matchClient{ std::move(matchClient) },\n            m_latestSession{ std::move(session) },\n            m_callback{ std::move(callback) }\n        {\n            for (auto& pair : m_matchClient->m_multiplayerLocalUserManager->GetLocalUserMap())\n            {\n                m_users.push_back(pair.second);\n            }\n        }\n\n        void Run() noexcept\n        {\n            m_matchClient->m_matchStatus = XblMultiplayerMatchStatus::Joining;\n\n            if (m_matchClient->m_preservingMatchmakingSession)\n            {\n                // Matchmaking session was preserved so we're already part of it\n                Complete(m_latestSession);\n            }\n            else\n            {\n                JoinNextUser();\n            }\n        }\n\n    private:\n        void JoinNextUser() noexcept\n        {\n            if (m_users.empty())\n            {\n                Complete(m_latestSession);\n            }\n            else\n            {\n                auto user{ m_users.front() };\n                m_users.pop_front();\n                JoinSession(user);\n            }\n        }\n\n        void JoinSession(std::shared_ptr<MultiplayerLocalUser> user)\n        {\n            auto userSession = MakeShared<XblMultiplayerSession>(user->Xuid(), &m_latestSession->SessionReference(), nullptr);\n            userSession->Join();\n            // Ok to use 'unsafe' method here since we have the only instance\n            userSession->CurrentUserInternalUnsafe()->SetSecureDeviceBaseAddress64(user->ConnectionAddress());\n            userSession->SetSessionChangeSubscription(XblMultiplayerSessionChangeTypes::Everything);\n\n            HRESULT hr = user->Context()->MultiplayerService()->WriteSession(\n                userSession,\n                XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n                AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>>{ m_matchClient->m_queue,\n                [\n                    op{ shared_from_this() }\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> writeSessionResult)\n            {\n                if (Failed(writeSessionResult))\n                {\n                    op->Complete(std::move(writeSessionResult));\n                }\n                else\n                {\n                    op->m_latestSession = writeSessionResult.ExtractPayload();\n                    op->JoinNextUser();\n                }\n            }\n            });\n\n            if (FAILED(hr))\n            {\n                Complete(hr);\n            }\n        }\n\n        void Complete(Result<std::shared_ptr<XblMultiplayerSession>>&& result) noexcept\n        {\n            m_matchClient->m_queue.RunCompletion([op{shared_from_this()}, result]\n                {\n                    op->m_matchClient->UpdateSession(result.Payload());\n                    op->m_callback(std::move(result));\n                });\n        }\n\n        std::shared_ptr<MultiplayerMatchClient> m_matchClient;\n        std::shared_ptr<XblMultiplayerSession> m_latestSession;\n        List<std::shared_ptr<MultiplayerLocalUser>> m_users;\n        MultiplayerSessionCallback m_callback;\n    };\n\n    auto operation = MakeShared<JoinSessionOperation>(shared_from_this(), session, std::move(callback));\n    operation->Run();\n    return S_OK;\n}\n\nvoid\nMultiplayerMatchClient::GetLatestSession()\n{\n    std::lock_guard<std::mutex> lock(m_getSessionLock);\n    if (Session() == nullptr) return;\n\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    if (primaryContext == nullptr || m_getSessionInProgress)\n    {\n        return;\n    }\n\n    std::weak_ptr<MultiplayerMatchClient> weakSessionWriter = shared_from_this();\n    m_getSessionInProgress = true;\n    primaryContext->MultiplayerService()->GetCurrentSession(Session()->SessionReference(), { m_queue,\n    [weakSessionWriter](Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        if (SUCCEEDED(sessionResult.Hresult()))\n        {\n            std::shared_ptr<MultiplayerMatchClient> pThis(weakSessionWriter.lock());\n            if (pThis != nullptr)\n            {\n                pThis->UpdateSession(sessionResult.Payload());\n                pThis->m_getSessionInProgress = false;\n            }\n        }\n    }\n    });\n}\n\nvoid MultiplayerMatchClient::SetQosMeasurements(\n    _In_ const JsonValue& measurements\n) noexcept\n{\n    // Set QoS measurements for each local user.\n    // Result delivered by updating the latest session and updating the match status.\n    struct SetQosMeasurementsOperation : public std::enable_shared_from_this<SetQosMeasurementsOperation>\n    {\n        SetQosMeasurementsOperation(\n            std::shared_ptr<MultiplayerMatchClient> matchClient,\n            const JsonValue& measurements,\n            const XblMultiplayerSessionReference& matchSessionRef\n        ) noexcept :\n            m_matchClient{ std::move(matchClient) },\n            m_matchSessionRef{ matchSessionRef }\n        {\n            JsonUtils::CopyFrom(m_measurements, measurements);\n            for (auto& pair : m_matchClient->m_multiplayerLocalUserManager->GetLocalUserMap())\n            {\n                m_users.push_back(pair.second);\n            }\n        }\n\n        void Run() noexcept\n        {\n            m_matchClient->m_matchStatus = XblMultiplayerMatchStatus::UploadingQosMeasurements;\n            SetMeasurementsForNextUser();\n        }\n\n    private:\n        void SetMeasurementsForNextUser() noexcept\n        {\n            if (m_users.empty())\n            {\n                Complete(S_OK);\n            }\n            else\n            {\n                auto user{ m_users.front() };\n                m_users.pop_front();\n\n                auto session = MakeShared<XblMultiplayerSession>(user->Xuid(), &m_matchSessionRef, nullptr);\n                session->Join();\n                // Fine to use 'unsafe' method here since this is the only instance of the session\n                session->CurrentUserInternalUnsafe()->SetQosMeasurementsJson(JsonUtils::SerializeJson(m_measurements));\n\n                HRESULT hr = user->Context()->MultiplayerService()->WriteSession(\n                    session,\n                    XblMultiplayerSessionWriteMode::UpdateExisting,\n                    AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>>{ m_matchClient->m_queue,\n                    [\n                        op{ shared_from_this() }\n                    ]\n                (Result<std::shared_ptr<XblMultiplayerSession>> result)\n                {\n                    if (Failed(result))\n                    {\n                        op->Complete(result);\n                    }\n                    else\n                    {\n                        op->m_latestSession = result.ExtractPayload();\n                        op->SetMeasurementsForNextUser();\n                    }\n                }\n                });\n\n                if (FAILED(hr))\n                {\n                    Complete(hr);\n                }\n            }\n        }\n\n        void Complete(Result<void>&& result)\n        {\n            LOGS_DEBUG << __FUNCTION__ << \": HRESULT=\" << result.Hresult() << \", ErrorMessage=\" << result.ErrorMessage();\n\n            m_matchClient->UpdateSession(m_latestSession);\n            m_matchClient->m_matchStatus = XblMultiplayerMatchStatus::WaitingForRemoteClientsToUploadQos;\n        }\n\n        std::shared_ptr<MultiplayerMatchClient> m_matchClient;\n        JsonDocument m_measurements;\n        std::shared_ptr<XblMultiplayerSession> m_latestSession;\n        List<std::shared_ptr<MultiplayerLocalUser>> m_users;\n        XblMultiplayerSessionReference m_matchSessionRef;\n    };\n\n    if (auto matchSession{ Session() })\n    {\n        auto operation = MakeShared<SetQosMeasurementsOperation>(shared_from_this(), measurements, matchSession->SessionReference());\n        operation->Run();\n    }\n}\n\nvoid\nMultiplayerMatchClient::ResubmitMatchmaking(\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    std::shared_ptr<XblContext> primaryContext = m_multiplayerLocalUserManager->GetPrimaryContext();\n    if (primaryContext == nullptr)\n    {\n        return;\n    }\n\n    m_matchStatus = XblMultiplayerMatchStatus::Resubmitting;\n    session->SetMatchmakingResubmit(true);\n    std::weak_ptr<MultiplayerMatchClient> weakSessionWriter = shared_from_this();\n    primaryContext->MultiplayerService()->WriteSession(session, XblMultiplayerSessionWriteMode::UpdateExisting, { m_queue,\n    [weakSessionWriter](Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        if (FAILED(sessionResult.Hresult()))\n        {\n            std::shared_ptr<MultiplayerMatchClient> pThis(weakSessionWriter.lock());\n            if (pThis != nullptr)\n            {\n                pThis->m_matchStatus = XblMultiplayerMatchStatus::Failed;\n                pThis->HandleFindMatchCompleted({ sessionResult.Hresult(), \"Resubmit failed\" });\n            }\n        }\n    }\n    });\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_member.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::multiplayer;\n\nSTDAPI_(bool) XblMultiplayerManagerMemberAreMembersOnSameDevice(\n    _In_ const XblMultiplayerManagerMember* first,\n    _In_ const XblMultiplayerManagerMember* second\n) XBL_NOEXCEPT\ntry\n{\n    if (first != nullptr && second != nullptr)\n    {\n        return utils::str_icmp(first->DeviceToken, second->DeviceToken) == 0;\n    }\n    return false;\n}\nCATCH_RETURN()\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\nMultiplayerMember::MultiplayerMember() :\n    m_memberId(0),\n    m_xuid(0),\n    m_isLocal(false),\n    m_isInLobby(false),\n    m_isInGame(false),\n    m_status(XblMultiplayerSessionMemberStatus::Inactive)\n{\n}\n\nMultiplayerMember::MultiplayerMember(\n    _In_ const XblMultiplayerSessionMember* member,\n    _In_ bool isLocal,\n    _In_ bool /*isGameHost*/,\n    _In_ bool /*isLobbyHost*/,\n    _In_ bool isInLobby,\n    _In_ bool isInGame\n    ):\n    m_memberId(member->MemberId),\n    m_xuid(member->Xuid),\n    m_gamertag(member->Gamertag),\n    m_deviceToken(member->DeviceToken.Value),\n    m_isLocal(isLocal),\n    m_isInLobby(isInLobby),\n    m_isInGame(isInGame),\n    m_status(member->Status)\n{\n    if (member->InitialTeam)\n    {\n        m_initialTeam = member->InitialTeam;\n    }\n    if (member->CustomPropertiesJson)\n    {\n        m_jsonProperties = member->CustomPropertiesJson;\n    }\n    if (member->SecureDeviceBaseAddress64)\n    {\n        m_connectionAddress = utils::parse_secure_device_address(member->SecureDeviceBaseAddress64);\n    }\n}\n\nuint32_t\nMultiplayerMember::MemberId() const\n{\n    return m_memberId;\n}\n\nconst xsapi_internal_string&\nMultiplayerMember::TeamId() const\n{\n    return m_teamId;\n}\n\nconst xsapi_internal_string& \nMultiplayerMember::InitialTeam() const\n{\n    return m_initialTeam;\n}\n\nuint64_t\nMultiplayerMember::Xuid() const\n{\n    return m_xuid;\n}\n\nconst xsapi_internal_string&\nMultiplayerMember::DebugGamertag() const\n{\n    return m_gamertag;\n}\n\nconst xsapi_internal_string&\nMultiplayerMember::DeviceToken() const\n{\n    return m_deviceToken;\n}\n\nbool\nMultiplayerMember::IsLocal() const\n{\n    return m_isLocal;\n}\n\nbool\nMultiplayerMember::IsInLobby() const\n{\n    return m_isInLobby;\n}\n\nbool\nMultiplayerMember::IsInGame() const\n{\n    return m_isInGame;\n}\n\nXblMultiplayerSessionMemberStatus\nMultiplayerMember::Status() const\n{\n    return m_status;\n}\n\nconst xsapi_internal_string&\nMultiplayerMember::ConnectionAddress() const\n{\n    return m_connectionAddress;\n}\n\nconst xsapi_internal_string&\nMultiplayerMember::CustomPropertiesJson() const\n{\n    return m_jsonProperties;\n}\n\nbool\nMultiplayerMember::IsMemberOnSameDevice(\n    _In_ std::shared_ptr<MultiplayerMember> member\n    ) const\n{\n    if(member == nullptr)\n    {\n        return false;\n    }\n\n    return utils::str_icmp_internal(m_deviceToken, member->DeviceToken()) == 0;\n}\n\nstd::shared_ptr<MultiplayerMember> MultiplayerMember::CreateFromSessionMember(\n    _In_ const XblMultiplayerSessionMember* member,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& gameSession,\n    _In_ const xsapi_internal_map<uint64_t, std::shared_ptr<MultiplayerLocalUser>>& xboxLiveContextMap\n    )\n{\n    bool isLocal = false;\n    for (const auto& xboxLiveContext : xboxLiveContextMap)\n    {\n        const auto& localUser = xboxLiveContext.second;\n        if (localUser != nullptr && member->Xuid == localUser->Xuid())\n        {\n            isLocal = true;\n            break;\n        }\n    }\n    return CreateFromSessionMember(member, lobbySession, gameSession, isLocal);\n}\n\nstd::shared_ptr<MultiplayerMember> MultiplayerMember::CreateFromSessionMember(\n    _In_ const XblMultiplayerSessionMember* member,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& lobbySession,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& gameSession,\n    _In_ bool isLocal\n    )\n{\n    return MakeShared<MultiplayerMember>(\n        member,\n        isLocal,                                                           // isLocal\n        XblMultiplayerSession::IsHost(member->DeviceToken.Value, gameSession),      // isGameHost\n        XblMultiplayerSession::IsHost(member->DeviceToken.Value, lobbySession),     // isLobbyHost\n        XblMultiplayerSession::IsPlayerInSession(member->Xuid, lobbySession), // isinLobby\n        XblMultiplayerSession::IsPlayerInSession(member->Xuid, gameSession)   // isinGame\n        );\n}\n\nXblMultiplayerManagerMember MultiplayerMember::GetReference() const\n{\n    XblMultiplayerManagerMember ref = XblMultiplayerManagerMember{};\n    ref.MemberId = m_memberId;\n    ref.InitialTeam = m_initialTeam.data();\n    ref.Xuid = m_xuid;\n    ref.DebugGamertag = m_gamertag.data();\n    ref.IsLocal = m_isLocal;\n    ref.IsInLobby = m_isInLobby;\n    ref.IsInGame = m_isInGame;\n    ref.Status = m_status;\n    ref.ConnectionAddress = m_connectionAddress.data();\n    ref.PropertiesJson = m_jsonProperties.data();\n    ref.DeviceToken = m_deviceToken.data();\n    return ref;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/Manager/multiplayer_session_writer.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n\nusing namespace xbox::services::system;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK\n#define TIME_PER_CALL_MS (1 * 1000)\n#elif defined(XSAPI_UNIT_TESTS)\n#define TIME_PER_CALL_MS (30 * 1000)\n#endif\n\nMultiplayerSessionWriter::MultiplayerSessionWriter(\n    const TaskQueue& queue\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() }\n{\n}\n\nMultiplayerSessionWriter::MultiplayerSessionWriter(\n    const TaskQueue& queue,\n    _In_ std::shared_ptr<MultiplayerLocalUserManager> localUserManager\n) noexcept :\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_multiplayerLocalUserManager{ std::move(localUserManager) }\n{\n}\n\nvoid\nMultiplayerSessionWriter::Destroy()\n{\n    m_id++;\n    m_session = nullptr;\n    m_isTapReceived = false;\n    m_numOfWritesInProgress = 0;\n    m_tapChangeNumber = 0;\n}\n\nstd::shared_ptr<XblContext>\nMultiplayerSessionWriter::GetPrimaryContext()\n{\n    return m_multiplayerLocalUserManager->GetPrimaryContext();\n}\n\nuint64_t\nMultiplayerSessionWriter::Id() const\n{\n    return m_id;\n}\n\nconst std::shared_ptr<XblMultiplayerSession>&\nMultiplayerSessionWriter::Session() const\n{\n    return m_session;\n}\n\nvoid\nMultiplayerSessionWriter::UpdateSession(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n    )\n{\n    if (updatedSession == nullptr)\n    {\n        Destroy();\n    }\n    else\n    {\n        m_session = updatedSession;\n    }\n}\n\nXblFunctionContext\nMultiplayerSessionWriter::AddMultiplayerSessionUpdatedHandler(\n    _In_ Callback<const std::shared_ptr<XblMultiplayerSession>&> handler\n    )\n{\n    std::lock_guard<std::mutex> lock(m_stateLock);\n\n    XblFunctionContext context = 0;\n    if (handler != nullptr)\n    {\n\t\tcontext = m_sessionUpdateEventHandlerCounter++;\n        m_sessionUpdateEventHandler[m_sessionUpdateEventHandlerCounter] = std::move(handler);\n    }\n\n    return context;\n}\n\nvoid\nMultiplayerSessionWriter::OnResyncMessageReceived()\n{\n    m_handleResyncEventCounter++;\n    Resync();\n}\n\nvoid\nMultiplayerSessionWriter::OnSessionUpdated(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& updatedSession\n    )\n{\n    std::lock_guard<std::mutex> lock(m_stateLock);\n\n    for (const auto& handler : m_sessionUpdateEventHandler)\n    {\n        XSAPI_ASSERT(handler.second != nullptr);\n        if (handler.second != nullptr)\n        {\n            try\n            {\n                handler.second(updatedSession);\n            }\n            catch (...)\n            {\n                LOG_ERROR(\"MultiplayerSessionWriter::on_session_updated call threw an exception\");\n            }\n        }\n    }\n}\n\nbool\nMultiplayerSessionWriter::IsTapReceived() const\n{\n    return m_isTapReceived;\n}\n\nvoid\nMultiplayerSessionWriter::SetTapReceived(\n    _In_ bool bReceived\n    )\n{\n    m_isTapReceived = bReceived;\n}\n\nbool\nMultiplayerSessionWriter::IsWriteInProgress() const\n{\n    return m_numOfWritesInProgress > 0;\n}\n\nvoid\nMultiplayerSessionWriter::SetWriteInProgress(\n    _In_ bool writeInProgress\n    )\n{\n    if (writeInProgress)\n    {\n        m_numOfWritesInProgress++;\n    }\n    else\n    {\n        m_numOfWritesInProgress--;\n    }\n}\n\nuint64_t\nMultiplayerSessionWriter::TapChangeNumber() const\n{\n    return m_tapChangeNumber;\n}\n\nvoid\nMultiplayerSessionWriter::SetTapChangeNumber(\n    _In_ uint64_t changeNumber\n    )\n{\n    m_tapChangeNumber = changeNumber;\n}\n\nHRESULT MultiplayerSessionWriter::CommitSynchronizedChanges(\n    _In_ std::shared_ptr<XblMultiplayerSession> sessionToCommit,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    // Retrieve the latest session and write the pending commit changes to it.\n    return WriteSession(\n        m_multiplayerLocalUserManager->GetPrimaryContext(),\n        sessionToCommit,\n        XblMultiplayerSessionWriteMode::SynchronizedUpdate,\n        true,\n        std::move(callback)\n    );\n}\n\nHRESULT MultiplayerSessionWriter::CommitPendingSynchronizedChanges(\n    _In_ Vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue,\n    _In_ XblMultiplayerSessionType sessionType,\n    _In_ MultiplayerEventQueueCallback callback\n) noexcept\n{\n    if (m_session == nullptr)\n    {\n        auto eventQueue = HandleEvents(processingQueue, { E_FAIL, \"Session null\" }, sessionType);\n        // TODO this may need to be invoked on another thread\n        callback(Result<MultiplayerEventQueue>(eventQueue, xbl_error_code::generic_error));\n        return S_OK;\n    }\n\n    auto sessionToCommitCopy = MakeShared<XblMultiplayerSession>(*m_session);\n\n    // Update any pending local user or lobby session properties.\n    for (auto& request : processingQueue)\n    {\n        request->AppendPendingChanges(sessionToCommitCopy, nullptr);\n    }\n\n    return WriteSession(GetPrimaryContext(), sessionToCommitCopy, XblMultiplayerSessionWriteMode::SynchronizedUpdate, true,\n        [\n            weakThis = std::weak_ptr<MultiplayerSessionWriter>{ shared_from_this() },\n            processingQueue,\n            sessionType,\n            callback\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        MultiplayerEventQueue eventQueue;\n        auto sharedThis{ weakThis.lock() };\n        if (sharedThis)\n        {\n            std::lock_guard<std::mutex> lock(sharedThis->m_stateLock);\n            eventQueue = sharedThis->HandleEvents(processingQueue, sessionResult, sessionType);\n        }\n        callback(Result<MultiplayerEventQueue>(eventQueue, sessionResult.Hresult()));\n    });\n}\n\nHRESULT MultiplayerSessionWriter::CommitPendingChanges(\n    _In_ Vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue,\n    _In_ XblMultiplayerSessionType sessionType,\n    _In_ bool isGameInProgress,\n    _In_ MultiplayerEventQueueCallback callback\n) noexcept\n{\n    if (m_session == nullptr)\n    {\n        auto eventQueue = HandleEvents(processingQueue, { E_FAIL, \"Session is null\" }, sessionType);\n        // TODO this may need to be invoked on another thread\n        callback(Result<MultiplayerEventQueue>(eventQueue, xbl_error_code::generic_error, \"Session is null\"));\n        return S_OK;\n    }\n\n    std::shared_ptr<XblMultiplayerSession> sessionToCommitCopy = MakeShared<XblMultiplayerSession>(*m_session);\n\n    // Update any pending local user or lobby session properties.\n    for (auto& request : processingQueue)\n    {\n        request->AppendPendingChanges(sessionToCommitCopy, nullptr, isGameInProgress);\n    }\n\n    return WriteSession(m_multiplayerLocalUserManager->GetPrimaryContext(), sessionToCommitCopy, XblMultiplayerSessionWriteMode::UpdateExisting, true,\n        [\n            weakThis = std::weak_ptr<MultiplayerSessionWriter>{ shared_from_this() },\n            processingQueue,\n            sessionType,\n            callback\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        MultiplayerEventQueue eventQueue;\n        auto sharedThis{ weakThis.lock() };\n        if (sharedThis)\n        {\n            std::lock_guard<std::mutex> lock(sharedThis->m_stateLock);\n            eventQueue = sharedThis->HandleEvents(processingQueue, sessionResult, sessionType);\n        }\n        callback(Result<MultiplayerEventQueue>(eventQueue, sessionResult.Hresult(), sessionResult.ErrorMessage()));\n    });\n}\n\nHRESULT MultiplayerSessionWriter::WriteSession(\n    _In_ std::shared_ptr<XblContext> xboxLiveContext,\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ XblMultiplayerSessionWriteMode mode,\n    _In_ bool updateLatest,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    RETURN_HR_IF_LOG_DEBUG(xboxLiveContext == nullptr, E_UNEXPECTED, \"Call add_local_user() first.\");\n\n    auto hr = xboxLiveContext->MultiplayerService()->WriteSession(\n        session,\n        mode,\n        AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>>{ m_queue,\n        [\n            weakThis = std::weak_ptr<MultiplayerSessionWriter>{ shared_from_this() },\n            sessionWriterId = m_id,\n            updateLatest,\n            callback\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            if (sharedThis->Id() != sessionWriterId)\n            {\n                callback({ E_FAIL, \"Session writer has been reset\" });\n            }\n            else\n            {\n                sharedThis->HandleWriteSessionResult(sessionResult, updateLatest, callback);\n            }\n        }\n        else\n        {\n            callback({ E_FAIL, \"Session writer is null\" });\n        }\n    }\n    });\n\n    if (SUCCEEDED(hr))\n    {\n        SetWriteInProgress(true);\n    }\n    return hr;\n}\n\nHRESULT MultiplayerSessionWriter::WriteSessionByHandle(\n    _In_ std::shared_ptr<XblContext> xboxLiveContext,\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ XblMultiplayerSessionWriteMode mode,\n    _In_ const String& handleId,\n    _In_ bool updateLatest,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    RETURN_HR_IF_LOG_DEBUG(xboxLiveContext == nullptr, E_UNEXPECTED, \"Call add_local_user() first.\");\n\n    auto hr = xboxLiveContext->MultiplayerService()->WriteSessionByHandle(\n        session,\n        mode,\n        handleId,\n        AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>>{ m_queue,\n        [\n            weakThis = std::weak_ptr<MultiplayerSessionWriter>{ shared_from_this() },\n            sessionWriterId = m_id,\n            updateLatest,\n            callback\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            if (sharedThis->Id() != sessionWriterId)\n            {\n                callback({ E_FAIL, \"Session writer has been reset\" });\n            }\n            else\n            {\n                sharedThis->HandleWriteSessionResult(sessionResult, updateLatest, callback);\n            }\n        }\n        else\n        {\n            callback({ E_FAIL, \"Session writer is null\" });\n        }\n    }\n    });\n\n    if (SUCCEEDED(hr))\n    {\n        SetWriteInProgress(true);\n    }\n    return hr;\n}\n\nvoid MultiplayerSessionWriter::HandleWriteSessionResult(\n    _In_ Result<std::shared_ptr<XblMultiplayerSession>> writeSessionResult,\n    _In_ bool updateLatest,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    std::lock_guard<std::mutex> guard{ m_synchronizeWriteWithTapLock };\n\n    if (Succeeded(writeSessionResult) || writeSessionResult.Hresult() == HTTP_E_STATUS_PRECOND_FAILED)\n    {\n        if (updateLatest)\n        {\n            OnSessionUpdated(writeSessionResult.Payload());\n        }\n    }\n\n    SetWriteInProgress(false);\n    if (IsTapReceived())\n    {\n        SetTapReceived(false);\n        auto latestSession = m_session;  // always check against the latest session().\n        if(updateLatest && latestSession != nullptr && latestSession->SessionInfo().ChangeNumber < TapChangeNumber())\n        {\n            GetCurrentSessionHelper(m_multiplayerLocalUserManager->GetPrimaryContext(), latestSession->SessionReference(), callback);\n        }\n        else\n        {\n            callback(writeSessionResult);\n        }\n    }\n    else\n    {\n        callback(writeSessionResult);\n    }\n}\n\nvoid MultiplayerSessionWriter::OnSessionChanged(\n    _In_ XblMultiplayerSessionChangeEventArgs args\n) noexcept\n{\n    std::lock_guard<std::mutex> guard(m_synchronizeWriteWithTapLock);\n\n    if (IsWriteInProgress())\n    {\n        if (args.ChangeNumber > TapChangeNumber())\n        {\n            SetTapReceived(true);\n            SetTapChangeNumber(args.ChangeNumber);\n        }\n    }\n    else\n    {\n        auto latestSession = Session();\n        if(latestSession != nullptr && args.ChangeNumber > latestSession->SessionInfo().ChangeNumber)\n        {\n            GetCurrentSessionHelper(m_multiplayerLocalUserManager->GetPrimaryContext(), latestSession->SessionReference(), nullptr);\n        }\n    }\n}\n\nHRESULT MultiplayerSessionWriter::GetCurrentSessionHelper(\n    _In_ std::shared_ptr<XblContext> xboxLiveContext,\n    _In_ const XblMultiplayerSessionReference& sessionReference,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    RETURN_HR_IF_LOG_DEBUG(xboxLiveContext == nullptr, E_UNEXPECTED, \"Call add_local_user() first.\");\n\n    return xboxLiveContext->MultiplayerService()->GetCurrentSession(\n        sessionReference,\n        AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>>{ m_queue,\n        [\n            weakThis = std::weak_ptr<MultiplayerSessionWriter>{ shared_from_this() },\n            callback\n        ]\n    (Result<std::shared_ptr<XblMultiplayerSession>> sessionResult)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            if (Succeeded(sessionResult) || sessionResult.Hresult() == HTTP_E_STATUS_PRECOND_FAILED)\n            {\n                sharedThis->OnSessionUpdated(sessionResult.Payload());\n            }\n            callback(sessionResult);\n        }\n        else\n        {\n            callback({E_FAIL, \"Session writer is null\"});\n        }\n    }\n    });\n}\n\nvoid MultiplayerSessionWriter::Resync()\n{\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK || defined(XSAPI_UNIT_TESTS)\n    std::lock_guard<std::mutex> lock(m_resyncLock);\n\n    auto cachedSession = Session();\n    if (cachedSession != nullptr && !m_isResyncTaskInProgress && m_handleResyncEventCounter > 0)\n    {\n        m_isResyncTaskInProgress = true;\n        m_handleResyncEventCounter = 0;\n        XblMultiplayerSessionChangeEventArgs changeEventArgs{ cachedSession->SessionReference(), \"\", cachedSession->SessionInfo().ChangeNumber + 1 };\n        OnSessionChanged(changeEventArgs);\n\n        // You could get multiple resync events. To avoid fetching the session too often, only check back after TIME_PER_CALL_MS secs\n        m_queue.RunWork([ weakThis = std::weak_ptr<MultiplayerSessionWriter>{ shared_from_this() }, this ]\n            {\n                if (auto sharedThis{ weakThis.lock() })\n                {\n                    std::unique_lock<std::mutex> lock{ m_resyncLock };\n                    m_isResyncTaskInProgress = false;\n                    lock.unlock();\n\n                    Resync();\n                }\n            }, TIME_PER_CALL_MS);\n    }\n#else\n    UNREFERENCED_PARAMETER(m_isResyncTaskInProgress);\n#endif\n}\n\nHRESULT MultiplayerSessionWriter::LeaveRemoteSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ MultiplayerSessionCallback callback\n) noexcept\n{\n    RETURN_HR_IF_LOG_DEBUG(session == nullptr, E_UNEXPECTED, \"Session is null\");\n\n    // LeaveSessionOperation will leave the provided session for each local user.\n    // Because a User must leave the session on their own, this requires an MPSD call for each local user.\n    // To be consistent with 1806 XDK behavior, if any of these MPSD calls fail, the rest of the operation\n    // will be aborted and that failure will be returned.\n    struct LeaveSessionOperation : public std::enable_shared_from_this<LeaveSessionOperation>\n    {\n        LeaveSessionOperation(\n            std::shared_ptr<MultiplayerSessionWriter> sessionWriter,\n            const XblMultiplayerSessionReference& sessionRefToLeave,\n            TaskQueue& queue,\n            MultiplayerSessionCallback&& callback\n        ) noexcept :\n            m_sessionWriter{ std::move(sessionWriter) },\n            m_sessionToLeaveRef{ sessionRefToLeave },\n            m_queue{ queue },\n            m_localUsers{ m_sessionWriter->m_multiplayerLocalUserManager->GetLocalUserMap() },\n            m_callback{ std::move(callback) }\n        {\n        }\n\n        void Run() noexcept\n        {\n            if (m_localUsers.empty())\n            {\n                // Nothing left to do, return latest session\n                m_callback(m_latestSession);\n            }\n            else\n            {\n                auto userContext{ m_localUsers.begin()->second->Context() };\n                m_localUsers.erase(m_localUsers.begin());\n                HRESULT hr = LeaveSession(userContext);\n                if (FAILED(hr))\n                {\n                    m_callback(hr);\n                }\n            }\n        }\n\n    private:\n        HRESULT LeaveSession(std::shared_ptr<XblContext> userContext) noexcept\n        {\n            auto sessionToCommit = MakeShared<XblMultiplayerSession>(userContext->Xuid(), &m_sessionToLeaveRef, nullptr);\n            RETURN_HR_IF_FAILED(sessionToCommit->Leave());\n\n            // Never update latest copy upon leaving.\n\n            return userContext->MultiplayerService()->WriteSession(\n                sessionToCommit,\n                XblMultiplayerSessionWriteMode::UpdateExisting,\n                AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>>{ m_queue,\n                [\n                    sharedThis{ shared_from_this() }, this\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> writeSessionResult)\n            {\n                if (Failed(writeSessionResult))\n                {\n                    m_callback(writeSessionResult);\n                }\n                else\n                {\n                    m_latestSession = writeSessionResult.ExtractPayload();\n                    sharedThis->Run();\n                }\n            }});\n        }\n\n        std::shared_ptr<MultiplayerSessionWriter> m_sessionWriter;\n        XblMultiplayerSessionReference m_sessionToLeaveRef;\n        TaskQueue m_queue;\n        Map<uint64_t, std::shared_ptr<MultiplayerLocalUser>> m_localUsers;\n        std::shared_ptr<XblMultiplayerSession> m_latestSession{ nullptr };\n        MultiplayerSessionCallback m_callback;\n    };\n\n    auto operation = MakeShared<LeaveSessionOperation>(\n        shared_from_this(),\n        session->SessionReference(),\n        m_queue,\n        std::move(callback)\n    );\n\n    operation->Run();\n    return S_OK;\n}\n\nMultiplayerEventQueue\nMultiplayerSessionWriter::HandleEvents(\n    _In_ xsapi_internal_vector<std::shared_ptr<MultiplayerClientPendingRequest>> processingQueue,\n    _In_ Result<void> error,\n    _In_ XblMultiplayerSessionType sessionType\n    )\n{\n    MultiplayerEventQueue eventQueue;\n    for (auto& request : processingQueue)\n    {\n        if (request->Joinability() != XblMultiplayerJoinability::None)\n        {\n            eventQueue.AddEvent(\n                XblMultiplayerEventType::JoinabilityStateChanged,\n                sessionType,\n                nullptr,\n                error,\n                request->Context()\n            );\n        }\n\n        if (request->SessionProperties().size() > 0)\n        {\n            // Fire events for each of the properties\n            for (auto iter = request->SessionProperties().begin(); iter != request->SessionProperties().end(); ++iter)\n            {\n                eventQueue.AddEvent(\n                    XblMultiplayerEventType::SessionPropertyWriteCompleted,\n                    sessionType,\n                    nullptr,\n                    error,\n                    request->Context()\n                );\n            }\n        }\n\n        if (!request->SynchronizedHostDeviceToken().empty())\n        {\n            eventQueue.AddEvent(\n                XblMultiplayerEventType::SynchronizedHostWriteCompleted,\n                sessionType,\n                MakeShared<XblMultiplayerEventArgs>(),\n                error,\n                request->Context()\n            );\n        }\n\n        if (request->SynchronizedSessionProperties().size() > 0)\n        {\n            // Fire events for each of the properties\n            for (auto iter = request->SynchronizedSessionProperties().begin(); iter != request->SynchronizedSessionProperties().end(); ++iter)\n            {\n                eventQueue.AddEvent(\n                    XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted,\n                    sessionType,\n                    nullptr,\n                    error,\n                    request->Context()\n                );\n            }\n        }\n    }\n    return eventQueue;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_activity_handle_post_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nMultiplayerActivityHandlePostRequest::MultiplayerActivityHandlePostRequest(\n    _In_ XblMultiplayerSessionReference sessionReference\n) :\n    m_sessionReference(std::move(sessionReference))\n{\n    XSAPI_ASSERT(XblMultiplayerSessionReferenceIsValid(&m_sessionReference));\n}\n\nconst XblMultiplayerSessionReference&\nMultiplayerActivityHandlePostRequest::SessionReference() const\n{\n    return m_sessionReference;\n}\n\nvoid\nMultiplayerActivityHandlePostRequest::Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator) const\n{\n    json.SetObject();\n\n    json.AddMember(\"type\", \"activity\", allocator);\n    JsonValue sessionRefJson;\n    Serializers::SerializeSessionReference(m_sessionReference, sessionRefJson, allocator);\n    json.AddMember(\"sessionRef\", sessionRefJson, allocator);\n    json.AddMember(\"version\", MULTIPLAYER_HANDLE_VERSION, allocator);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_activity_query_post_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nMultiplayerActivityQueryPostRequest::MultiplayerActivityQueryPostRequest()\n{\n}\n\nMultiplayerActivityQueryPostRequest::MultiplayerActivityQueryPostRequest(\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_vector<uint64_t>& xuids\n    ) :\n    m_scid(scid),\n    m_xuids(xuids)\n{\n}\n\nMultiplayerActivityQueryPostRequest::MultiplayerActivityQueryPostRequest(\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& socialGroup,\n    _In_ uint64_t socialGroupXuid\n    ) :\n    m_scid(scid),\n    m_socialGroupXuid(socialGroupXuid),\n    m_socialGroup(socialGroup)\n{\n}\n\nconst xsapi_internal_string&\nMultiplayerActivityQueryPostRequest::Scid() const\n{\n    return m_scid;\n}\n\nconst xsapi_internal_vector<uint64_t>&\nMultiplayerActivityQueryPostRequest::Xuids() const\n{\n    return m_xuids;\n}\nconst xsapi_internal_string&\nMultiplayerActivityQueryPostRequest::SocialGroup() const\n{\n    return m_socialGroup;\n}\n\nuint64_t\nMultiplayerActivityQueryPostRequest::SocialGroupXuid() const\n{\n    return m_socialGroupXuid;\n}\n\nvoid\nMultiplayerActivityQueryPostRequest::Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    XSAPI_ASSERT(m_socialGroup.empty() || m_xuids.empty());\n    XSAPI_ASSERT(!m_socialGroup.empty() || !m_xuids.empty());\n\n    json.SetObject();\n    json.AddMember(\"type\", \"activity\", allocator);\n    json.AddMember(\"scid\", JsonValue(m_scid.c_str(), allocator).Move(), allocator);\n\n    JsonValue ownerObject(rapidjson::kObjectType);\n    if (!m_xuids.empty())\n    {\n        JsonValue xuidsJson;\n        JsonUtils::SerializeVector<uint64_t>(JsonUtils::JsonXuidSerializer, m_xuids, xuidsJson, allocator);\n        ownerObject.AddMember(\"xuids\", xuidsJson, allocator);\n    }\n    else\n    {\n        JsonValue peopleObject(rapidjson::kObjectType);\n        peopleObject.AddMember(\"moniker\", JsonValue(m_socialGroup.c_str(), allocator).Move(), allocator);\n        peopleObject.AddMember(\"monikerXuid\", JsonValue(utils::uint64_to_internal_string(m_socialGroupXuid).c_str(), allocator).Move(), allocator);\n        ownerObject.AddMember(\"people\", peopleObject, allocator);\n    }\n\n    json.AddMember(\"owners\", ownerObject, allocator);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/multiplayer_c.h\"\n#include \"multiplayer_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::multiplayer;\n\nSTDAPI XblMultiplayerSearchHandleDuplicateHandle(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSearchHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || duplicatedHandle == nullptr);\n\n    handle->AddRef();\n    *duplicatedHandle = handle;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerSearchHandleCloseHandle(\n    _In_ XblMultiplayerSearchHandle handle\n) XBL_NOEXCEPT\ntry\n{\n    if (handle)\n    {\n        handle->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblMultiplayerSearchHandleGetSessionReference(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSessionReference* sessionRef\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || sessionRef == nullptr);\n    *sessionRef = handle->SessionReference();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetId(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const char** id\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || id == nullptr);\n    *id = handle->HandleId().data();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetSessionOwnerXuids(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const uint64_t** xuids,\n    _Out_ size_t* xuidsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || xuids == nullptr || xuidsCount == nullptr);\n\n    *xuids = handle->SessionOwnerXuids().data();\n    *xuidsCount = handle->SessionOwnerXuids().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetTags(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const XblMultiplayerSessionTag** tags,\n    _Out_ size_t* tagsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || tags == nullptr || tagsCount == nullptr);\n\n    *tags = handle->Tags().data();\n    *tagsCount = handle->Tags().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetStringAttributes(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const XblMultiplayerSessionStringAttribute** attributes,\n    _Out_ size_t* attributesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || attributes == nullptr || attributesCount == nullptr);\n\n    *attributes = handle->StringAttributes().data();\n    *attributesCount = handle->StringAttributes().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetNumberAttributes(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const XblMultiplayerSessionNumberAttribute** attributes,\n    _Out_ size_t* attributesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || attributes == nullptr || attributesCount == nullptr);\n\n    *attributes = handle->NumberAttributes().data();\n    *attributesCount = handle->NumberAttributes().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetVisibility(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSessionVisibility* visibility\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || visibility == nullptr);\n    *visibility = handle->Visibility();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetJoinRestriction(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ XblMultiplayerSessionRestriction* joinRestriction\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || joinRestriction == nullptr);\n    *joinRestriction = handle->JoinRestriction();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetSessionClosed(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ bool* closed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || closed == nullptr);\n    *closed = handle->Closed();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetMemberCounts(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_opt_ size_t* maxMembers,\n    _Out_opt_ size_t* currentMembers\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr);\n\n    if (maxMembers)\n    {\n        *maxMembers = handle->MaxMembersCount();\n    }\n    if (currentMembers)\n    {\n        *currentMembers = handle->MembersCount();\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetCreationTime(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ time_t* creationTime\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || creationTime == nullptr);\n    *creationTime = utils::time_t_from_datetime(handle->HandleCreationTime());\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSearchHandleGetCustomSessionPropertiesJson(\n    _In_ XblMultiplayerSearchHandle handle,\n    _Out_ const char** customPropertiesJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || customPropertiesJson == nullptr);\n    auto& customPropertiesString{ handle->CustomSessionPropertiesJson() };\n    if (customPropertiesString.empty())\n    {\n        *customPropertiesJson = nullptr;\n    }\n    else\n    {\n        *customPropertiesJson = customPropertiesString.data();\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerCreateSearchHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionReference* sessionRef,\n    _In_reads_opt_(tagsCount) const XblMultiplayerSessionTag* tags,\n    _In_ size_t tagsCount,\n    _In_reads_opt_(numberAttributesCount) const XblMultiplayerSessionNumberAttribute* numberAttributes,\n    _In_ size_t numberAttributesCount,\n    _In_reads_opt_(stringAttributesCount) const XblMultiplayerSessionStringAttribute* stringAttributes,\n    _In_ size_t stringAttributesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || sessionRef == nullptr || async == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(tagsCount > 0 && tags == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(numberAttributesCount > 0 && numberAttributes == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(stringAttributesCount > 0 && stringAttributes == nullptr);\n\n    //ensure all attributes are properly terminated, otherwise we'll write a property \n    //longer than is allowed into the json, which will crash eventually on deserialization\n    if (tagsCount > 0)\n    {\n        for (size_t i = 0; i < tagsCount; i++)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(utils::EnsureLessThanMaxLength(tags[i].value, XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH) == false);\n        }\n    }\n    if (numberAttributesCount > 0)\n    {\n        for (size_t i = 0; i < numberAttributesCount; i++)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(utils::EnsureLessThanMaxLength(numberAttributes[i].name, XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH) == false);\n        }\n    }\n    if (stringAttributesCount > 0)\n    {\n        for (size_t i = 0; i < stringAttributesCount; i++)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(utils::EnsureLessThanMaxLength(stringAttributes[i].name, XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH) == false);\n            RETURN_HR_INVALIDARGUMENT_IF(utils::EnsureLessThanMaxLength(stringAttributes[i].value, XBL_MULTIPLAYER_SEARCH_HANDLE_MAX_FIELD_LENGTH) == false);\n        }\n    }\n\n    MultiplayerSearchHandleRequest request{ *sessionRef };\n    if (tagsCount > 0)\n    {\n        request.SetTags(xsapi_internal_vector<XblMultiplayerSessionTag>{ tags, tags + tagsCount });\n    }\n    if (numberAttributesCount > 0)\n    {\n        request.SetNumberAttributes(xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>{ numberAttributes, numberAttributes + numberAttributesCount });\n    }\n    if (stringAttributesCount > 0)\n    {\n        request.SetStringAttributes(xsapi_internal_vector<XblMultiplayerSessionStringAttribute>{ stringAttributes, stringAttributes + stringAttributesCount });\n    }\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            context{ xblContext->shared_from_this() },\n            request,\n            resultHandle = std::shared_ptr<XblMultiplayerSearchHandleDetails>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(context->MultiplayerService()->CreateSearchHandle(\n                request,\n                AsyncContext<Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>>> { data->async->queue,\n                [\n                    &resultHandle,\n                    data\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>> result)\n            {\n                if (Succeeded(result))\n                {\n                    resultHandle = result.ExtractPayload();\n                }\n                XAsyncComplete(data->async, result.Hresult(), sizeof(XblMultiplayerSearchHandle));\n            }\n            }));\n\n            return E_PENDING;\n        }\n\n        case XAsyncOp::GetResult:\n        {\n            auto handlePtr = static_cast<XblMultiplayerSearchHandle*>(data->buffer);\n            resultHandle->AddRef();\n            *handlePtr = resultHandle.get();\n\n            return S_OK;\n        }\n\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerCreateSearchHandleResult(\n    _In_ XAsyncBlock* async,\n    _Out_opt_ XblMultiplayerSearchHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n\n    XblMultiplayerSearchHandle handleCopy{ nullptr };\n    auto hr = XAsyncGetResult(async, nullptr, sizeof(XblMultiplayerSearchHandle), &handleCopy, nullptr);\n    if (SUCCEEDED(hr))\n    {\n        if (handle != nullptr)\n        {\n            *handle = handleCopy;\n        }\n        else\n        {\n            XblMultiplayerSearchHandleCloseHandle(handleCopy);\n        }\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerDeleteSearchHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* handleId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || handleId == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            context{ xblContext->shared_from_this() },\n            handleId = xsapi_internal_string{ handleId }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(context->MultiplayerService()->DeleteSearchHandle(handleId, data->async));\n            return E_PENDING;\n        }\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSearchHandlesAsync(\n    _In_ XblContextHandle xblContext,\n    _In_z_ const char* scid,\n    _In_z_ const char* sessionTemplateName,\n    _In_opt_z_ const char* orderByAttribute,\n    _In_ bool orderAscending,\n    _In_opt_z_ const char* searchFilter,\n    _In_opt_z_ const char* socialGroup,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || scid == nullptr || sessionTemplateName == nullptr || async == nullptr);\n\n    MultiplayerQuerySearchHandleRequest request{ scid, sessionTemplateName };\n    if (orderByAttribute)\n    {\n        request.SetOrderBy(orderByAttribute);\n        request.SetOrderAscending(orderAscending);\n    }\n    if (searchFilter)\n    {\n        request.SetSearchFilter(searchFilter);\n    }\n    if (socialGroup)\n    {\n        request.SetSocialGroup(socialGroup);\n    }\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            context{ xblContext->shared_from_this() },\n            request,\n            searchHandles = xsapi_internal_vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(context->MultiplayerService()->GetSearchHandles(\n                request,\n                AsyncContext<Result<Vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>>>{ data->async->queue,\n                [\n                    &searchHandles,\n                    data\n                ]\n            (Result<Vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>> result)\n            {\n                if (Succeeded(result))\n                {\n                    searchHandles = result.ExtractPayload();\n                }\n                XAsyncComplete(data->async, result.Hresult(), searchHandles.size() * sizeof(XblMultiplayerSearchHandle));\n            }\n            }));\n\n            return E_PENDING;\n        }\n\n        case XAsyncOp::GetResult:\n        {\n            auto handlesPtr = static_cast<XblMultiplayerSearchHandle*>(data->buffer);\n            for (const auto& searchHandle : searchHandles)\n            {\n                searchHandle->AddRef();\n                *handlesPtr++ = searchHandle.get();\n            }\n            return S_OK;\n        }\n\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSearchHandlesResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* searchHandleCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || searchHandleCount == nullptr);\n\n    size_t bufferSize{ 0 };\n    auto hr = XAsyncGetResultSize(async, &bufferSize);\n\n    if (SUCCEEDED(hr))\n    {\n        *searchHandleCount = bufferSize / sizeof(XblMultiplayerSearchHandle);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSearchHandlesResult(\n    _In_ XAsyncBlock* async,\n    _Out_writes_(searchHandlesCount) XblMultiplayerSearchHandle* searchHandles,\n    _In_ size_t searchHandlesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(searchHandlesCount == 0, S_OK);\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || searchHandles == nullptr);\n    return XAsyncGetResult(async, nullptr, searchHandlesCount * sizeof(XblMultiplayerSearchHandle), searchHandles, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSetTransferHandleAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblMultiplayerSessionReference targetSessionReference,\n    _In_ XblMultiplayerSessionReference originSessionReference,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            targetSessionReference,\n            originSessionReference,\n            result = XblMultiplayerSessionHandleId{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->SetTransferHandle(\n                targetSessionReference,\n                originSessionReference,\n                AsyncContext<Result<String>>{ data->async->queue,\n                [\n                    async{ data->async },\n                    &result\n                ]\n            (Result<String> internalResult)\n            {\n                auto hr = internalResult.Hresult();\n                if (SUCCEEDED(hr))\n                {\n                    utils::strcpy(result.value, sizeof(result.value), internalResult.Payload().data());\n                }\n                XAsyncComplete(async, hr, sizeof(XblMultiplayerSessionHandleId));\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto resultPtr = static_cast<XblMultiplayerSessionHandleId*>(data->buffer);\n            *resultPtr = result;\n            return S_OK;\n        }\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSetTransferHandleResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandleId* handleId\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblMultiplayerSessionHandleId), handleId, nullptr);\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"xsapi-c/multiplayer_c.h\"\n#include \"real_time_activity_subscription.h\"\n\n#define MULTIPLAYER_HANDLE_VERSION 1\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\n// Forward declarations\nstruct SendInvitesContext;\n\nbool operator==(const XblMultiplayerSessionReference& lhs, const XblMultiplayerSessionReference& rhs);\n\nstruct Serializers\n{\n    static Result<XblMultiplayerActivityDetails> DeserializeMultiplayerActivityDetails(_In_ const JsonValue& json);\n\n    static Result<XblMultiplayerSessionQueryResult> DeserializeMultiplayerSessionQueryResult(_In_ const JsonValue& json);\n\n    static Result<XblMultiplayerSessionReference> DeserializeSessionReference(_In_ const JsonValue& json);\n    static void SerializeSessionReference(const XblMultiplayerSessionReference& sessionReference, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\n    static Result<XblMultiplayerInviteHandle> DeserializeMultiplayerInvite(_In_ const JsonValue& json);\n\n    static XblMultiplayerSessionRestriction MultiplayerSessionRestrictionFromString(_In_ const xsapi_internal_string &value);\n    static xsapi_internal_string StringFromMultiplayerSessionRestriction(_In_ XblMultiplayerSessionRestriction joinRestriction);\n    static XblMultiplayerSessionStatus MultiplayerSessionStatusFromString(_In_ const xsapi_internal_string& value);\n    static XblMultiplayerSessionVisibility MultiplayerSessionVisibilityFromString(_In_ const xsapi_internal_string& value);\n    static xsapi_internal_string StringFromMultiplayerSessionVisibility(_In_ XblMultiplayerSessionVisibility sessionVisibility);\n\n    static XblNetworkAddressTranslationSetting MultiplayerNatSettingFromString(_In_ const xsapi_internal_string& value);\n    static XblMultiplayerMeasurementFailure MultiplayerMeasurementFailureFromString(_In_ const xsapi_internal_string& value);\n    static XblMultiplayerSessionChangeTypes MultiplayerSessionChangeTypesFromStringVector(_In_ const xsapi_internal_vector<xsapi_internal_string>& changeTypeList);\n};\n\n/// <summary>\n/// Represents a reference to member in a multiplayer session.\n/// </summary>\nclass MultiplayerSessionMember\n{\npublic:\n    MultiplayerSessionMember() = default;\n    MultiplayerSessionMember(const xsapi_internal_string& memberId);\n    MultiplayerSessionMember(const MultiplayerSessionMember& other);\n\n    static Result<XblMultiplayerSessionMember> Deserialize(\n        _In_ const JsonValue& json\n    );\n\n    static XblMultiplayerSessionMember Construct(\n        _In_ bool isCurrentUser,\n        _In_ const xsapi_internal_string& memberId,\n        _In_ uint64_t xuid,\n        _In_opt_z_ const char* customConstantsJson,\n        _In_ bool initializeRequested\n    );\n\n    static MultiplayerSessionMember* Get(const XblMultiplayerSessionMember* member);\n    // Sets the internal member's m_member pointer and updates the fields of member accordingly\n    // TODO fix this. If external member objects move around things break\n    static void SetExternalMemberPointer(XblMultiplayerSessionMember& member);\n\n    ~MultiplayerSessionMember();\n\n    xsapi_internal_string MemberId() const;\n    XblMultiplayerSessionChangeTypes SubscribedChangeTypes() const;\n\n    void StateLock() const;\n    void StateUnlock() const;\n\n    // Use MultiplayerSessionMemberReadLockGuard that wraps StateLock/StateUnlock\n    const xsapi_internal_vector<uint32_t>& MembersInGroupUnsafe() const;\n    const xsapi_internal_vector<const char*>& GroupsUnsafe() const;\n    const xsapi_internal_vector<const char*>& EncountersUnSafe() const;\n    const JsonValue& CustomPropertiesJsonUnsafe() const;\n\n    void SetSecureDeviceBaseAddress64(_In_ const xsapi_internal_string& deviceBaseAddress);\n    void SetRoles(_In_ const xsapi_internal_vector<XblMultiplayerSessionMemberRole>& roles);\n    void SetGroups(_In_reads_(groupsCount) const char** groups, _In_ size_t groupsCount);\n    void SetEncounters(_In_reads_(encountersCount) const char** encounters, _In_ size_t encountersCount);\n\n    HRESULT SetStatus(_In_ XblMultiplayerSessionMemberStatus status);\n    void SetMembersInGroup(_In_ const xsapi_internal_vector<uint32_t>& membersInGroup);\n\n    HRESULT SetCustomPropertyJson(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson\n    );\n    void DeleteCustomPropertyJson(_In_ const xsapi_internal_string& name);\n    HRESULT SetServerMeasurementsJson(_In_ const xsapi_internal_string& serverMeasurementsJson);\n    HRESULT SetQosMeasurementsJson(_In_ const xsapi_internal_string& qosMeasurementsJson);\n    void SetRtaConnectionId(_In_ const xsapi_internal_string& rtaConnectionId);\n    void SetSessionChangeSubscription(\n        _In_ XblMultiplayerSessionChangeTypes changeTypes,\n        _In_ const xsapi_internal_string& subscriptionId\n    );\n\n    void Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\nprivate:\n    static xsapi_internal_vector<xsapi_internal_string> GetVectorViewForChangeTypes(_In_ XblMultiplayerSessionChangeTypes changeTypes);\n\n    XblMultiplayerSessionMember* m_member = nullptr;\n    xsapi_internal_string m_customConstantsJson;\n    xsapi_internal_string m_customPropertiesString;\n    JsonDocument m_customPropertiesJson{ rapidjson::Type::kObjectType };\n    xsapi_internal_string m_secureDeviceAddressBase64;\n    xsapi_internal_vector<XblMultiplayerSessionMemberRole> m_roles;\n    JsonDocument m_resultsJson;\n    xsapi_internal_string m_teamId;\n    xsapi_internal_string m_initialTeam;\n\n    xsapi_internal_vector<const char*> m_groups;\n    xsapi_internal_vector<const char*> m_encounters;\n    xsapi_internal_vector<uint32_t> m_membersInGroupIds;\n\n    XblMultiplayerSessionChangeTypes m_subscribedChangeTypes{ XblMultiplayerSessionChangeTypes::None };\n    xsapi_internal_string m_matchmakingResultServerMeasurementsJson;\n    xsapi_internal_string m_serverMeasurementsJson;\n    xsapi_internal_string m_qosMeasurementsJson;\n\n    xsapi_internal_string m_subscriptionId;\n    xsapi_internal_string m_rtaConnectionId;\n\n    xsapi_internal_string m_memberIdToWrite;\n    bool m_newMember{ false };\n    bool m_writeConstants{ false };\n    bool m_writeIsActive{ false };\n    bool m_writeRoleInfo{ false };\n    bool m_writeSecureDeviceAddressBase64{ false };\n    bool m_writeQoSMeasurementsJson{ false };\n    bool m_writeServerMeasurementsJson{ false };\n    bool m_writeMembersInGroup{ false };\n    bool m_writeGroups{ false };\n    bool m_writeEncounters{ false };\n    bool m_writeSubscribedChangeTypes{ false };\n    bool m_writeResults{ false };\n    bool m_writeCustomPropertiesJson{ false };\n\n    // needs to be recursive mutex since CompareMultiplayerSessions will lock both currentMember and olderSessionMember which might be same \n    mutable std::recursive_mutex m_lockMember; \n};\n\nclass MultiplayerSessionMemberReadLockGuard\n{\npublic:\n    MultiplayerSessionMemberReadLockGuard(_In_opt_ MultiplayerSessionMember* member) :\n        m_member(member)\n    {\n        if (m_member)\n        {\n            m_member->StateLock();\n        }\n    }\n\n    ~MultiplayerSessionMemberReadLockGuard()\n    {\n        if (m_member)\n        {\n            m_member->StateUnlock();\n        }\n    }\n\n    const xsapi_internal_vector<uint32_t>& MembersInGroup() const\n    {\n        return m_member->MembersInGroupUnsafe();\n    }\n\n    const xsapi_internal_vector<const char*>& Groups() const\n    {\n        return m_member->GroupsUnsafe();\n    }\n\n    const xsapi_internal_vector<const char*>& Encounters() const\n    {\n        return m_member->EncountersUnSafe();\n    }\n\n    const JsonValue& CustomPropertiesJson() const\n    {\n        return m_member->CustomPropertiesJsonUnsafe();\n    }\n\nprivate:\n    MultiplayerSessionMember* m_member;\n};\n\nclass MultiplayerQuerySearchHandleRequest\n{\npublic:\n    MultiplayerQuerySearchHandleRequest(\n        _In_ const xsapi_internal_string& scid,\n        _In_ const xsapi_internal_string& sessionTemplateName\n        );\n    MultiplayerQuerySearchHandleRequest(\n        _In_ const xsapi_internal_string& scid,\n        _In_ const xsapi_internal_string& sessionTemplateName,\n        _In_ const xsapi_internal_string& orderBy,\n        _In_ bool orderAscending,\n        _In_ const xsapi_internal_string& searchFilter\n        );\n\n    const xsapi_internal_string& Scid() const;\n    const xsapi_internal_string& SessionTemplateName() const;\n    const xsapi_internal_string& OrderBy() const;\n    void SetOrderBy(_In_ const xsapi_internal_string& orderBy);\n    bool OrderAscending();\n    void SetOrderAscending(_In_ bool orderAscending);\n    const xsapi_internal_string& SearchFilter() const;\n    void SetSearchFilter(_In_ const xsapi_internal_string& searchFilter);\n    const xsapi_internal_string& SocialGroup() const;\n    void SetSocialGroup(_In_ const xsapi_internal_string& socialGroup);\n\n    void Serialize(_In_ uint64_t socialGroupXuid, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator) const;\n\nprivate:\n    xsapi_internal_string m_serviceConfigurationId;\n    xsapi_internal_string m_sessionTemplateName;\n    xsapi_internal_string m_orderBy;\n    bool m_orderAscending{ false };\n    xsapi_internal_string m_searchFilter;\n    xsapi_internal_string m_socialGroup;\n};\n\nclass MultiplayerSearchHandleRequest\n{\npublic:\n    MultiplayerSearchHandleRequest(\n        _In_ XblMultiplayerSessionReference sessionRef\n    );\n\n    const XblMultiplayerSessionReference& SessionReference() const;\n    const xsapi_internal_vector<XblMultiplayerSessionTag>& Tags() const;\n    void SetTags(_In_ xsapi_internal_vector<XblMultiplayerSessionTag>&& value);\n    const xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>& NumberAttributes() const;\n    void SetNumberAttributes(_In_ xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>&& attributes);\n    const xsapi_internal_vector<XblMultiplayerSessionStringAttribute>& StringAttributes() const;\n    void SetStringAttributes(_In_ xsapi_internal_vector<XblMultiplayerSessionStringAttribute>&& attributes);\n\n    void Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator) const;\n\nprivate:\n    uint32_t m_version{ MULTIPLAYER_HANDLE_VERSION };\n    XblMultiplayerSessionReference m_sessionReference;\n    xsapi_internal_vector<XblMultiplayerSessionTag> m_tags;\n    xsapi_internal_vector<XblMultiplayerSessionStringAttribute> m_stringAttributes;\n    xsapi_internal_vector<XblMultiplayerSessionNumberAttribute> m_numberAttributes;\n};\n\nclass MultiplayerInviteHandlePostRequest\n{\npublic:\n    MultiplayerInviteHandlePostRequest(\n        _In_ const XblMultiplayerSessionReference& sessionReference,\n        _In_ uint64_t invitedXuid,\n        _In_ uint32_t titleId,\n        _In_ const String& contextString,\n        _In_ const String& customActivationContext\n    ) noexcept;\n\n    void SetInvitedXuid(uint64_t invitedXuid) noexcept;\n    const JsonValue& Json() const noexcept;\n\nprivate:\n    JsonDocument m_json;\n};\n\nclass MultiplayerSubscription : public real_time_activity::Subscription\n{\npublic:\n    MultiplayerSubscription() noexcept;\n\n    const String& RtaConnectionId() const;\n\n    typedef Function<void(const XblMultiplayerSessionChangeEventArgs& args)> SessionChangedHandler;\n    XblFunctionContext AddSessionChangedHandler(\n        SessionChangedHandler handler\n    ) noexcept;\n\n    size_t RemoveSessionChangedHandler(\n        XblFunctionContext token\n    ) noexcept;\n\n    typedef Function<void(const String& connectionId)> ConnectionIdChangedHandler;\n    XblFunctionContext AddConnectionIdChangedHandler(\n        ConnectionIdChangedHandler handler\n    ) noexcept;\n\n    size_t RemoveConnectionIdChangedHandler(\n        XblFunctionContext token\n    ) noexcept;\n\nprotected:\n    void OnSubscribe(_In_ const JsonValue& data) noexcept override;\n    void OnEvent(_In_ const JsonValue& data) noexcept override;\n\nprivate:\n    String m_connectionId;\n\n    XblFunctionContext m_nextToken{ 1 };\n    Map<XblFunctionContext, SessionChangedHandler> m_sessionChangedHandlers;\n    Map<XblFunctionContext, ConnectionIdChangedHandler> m_connectionIdChangedHandlers;\n\n    std::mutex m_mutexMultiplayerSubscription;\n};\n\nclass MultiplayerActivityQueryPostRequest\n{\npublic:\n    MultiplayerActivityQueryPostRequest();\n    MultiplayerActivityQueryPostRequest(_In_ const xsapi_internal_string& scid, _In_ const xsapi_internal_vector<uint64_t>& xuids);\n    MultiplayerActivityQueryPostRequest(_In_ const xsapi_internal_string& scid, _In_ const xsapi_internal_string& socialGroup, _In_ uint64_t socialGroupXuid);\n\n    const xsapi_internal_string& Scid() const;\n    const xsapi_internal_vector<uint64_t>& Xuids() const;\n    const xsapi_internal_string& SocialGroup() const;\n    uint64_t SocialGroupXuid() const;\n\n    void Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\nprivate:\n    xsapi_internal_string m_scid;\n    xsapi_internal_vector<uint64_t> m_xuids;\n    uint64_t m_socialGroupXuid{ 0 };\n    xsapi_internal_string m_socialGroup;\n};\n\nclass MultiplayerActivityHandlePostRequest\n{\npublic:\n    MultiplayerActivityHandlePostRequest(_In_ XblMultiplayerSessionReference sessionReference);\n\n    const XblMultiplayerSessionReference& SessionReference() const;\n\n    void Serialize(_Out_ JsonValue&, _In_ JsonDocument::AllocatorType& allocator) const;\nprivate:\n    XblMultiplayerSessionReference m_sessionReference;\n};\n\nclass MultiplayerTransferHandlePostRequest\n{\npublic:\n    MultiplayerTransferHandlePostRequest(\n        _In_ XblMultiplayerSessionReference targetSessionReference,\n        _In_ XblMultiplayerSessionReference originSessionReference\n    );\n\n    const XblMultiplayerSessionReference& OriginSessionReference() const;\n    const XblMultiplayerSessionReference& TargetSessionReference() const;\n\n    void Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator) const;\nprivate:\n    XblMultiplayerSessionReference m_originSessionReference;\n    XblMultiplayerSessionReference m_targetSessionReference;\n};\n\nstruct SessionQuery : public XblMultiplayerSessionQuery\n{\npublic:\n    SessionQuery(const XblMultiplayerSessionQuery* other) noexcept;\n    SessionQuery(const SessionQuery& other) noexcept;\n    SessionQuery& operator=(SessionQuery other) noexcept = delete;\n    ~SessionQuery() noexcept = default;\n\n    String PathAndQuery() const noexcept;\n    JsonDocument RequestBody() const noexcept;\n\nprivate:\n    Vector<uint64_t> m_xuidFilters;\n    String m_keywordFilter;\n};\n\nclass MultiplayerService : public std::enable_shared_from_this<MultiplayerService>\n{\npublic:\n    MultiplayerService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<xbox::services::AppConfig> appConfig,\n        _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaService\n    ) noexcept;\n\n    ~MultiplayerService() noexcept;\n\n    HRESULT WriteSession(\n        _In_ std::shared_ptr<XblMultiplayerSession> multiplayerSession,\n        _In_ XblMultiplayerSessionWriteMode writeMode,\n        _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n    ) noexcept;\n\n    HRESULT WriteSessionByHandle(\n        _In_ std::shared_ptr<XblMultiplayerSession> multiplayerSession,\n        _In_ XblMultiplayerSessionWriteMode writeMode,\n        _In_ const String& handleId,\n        _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n    ) noexcept;\n\n    HRESULT GetCurrentSession(\n        _In_ XblMultiplayerSessionReference sessionReference,\n        _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n    ) const noexcept;\n\n    HRESULT GetCurrentSessionByHandle(\n        _In_ const String& handleId,\n        _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n    ) const noexcept;\n\n    HRESULT GetSessions(\n        _In_ const SessionQuery& getSessionsRequest,\n        _In_ AsyncContext<Result<Vector<XblMultiplayerSessionQueryResult>>> async\n    ) const noexcept;\n\n    HRESULT SetActivity(\n        _In_ const XblMultiplayerSessionReference& sessionReference,\n        _In_ AsyncContext<Result<void>> async\n    ) const noexcept;\n\n    HRESULT SetTransferHandle(\n        _In_ const XblMultiplayerSessionReference& targetSessionReference,\n        _In_ const XblMultiplayerSessionReference& originSessionReference,\n        _In_ AsyncContext<Result<String>> async\n    ) const noexcept;\n\n    HRESULT CreateSearchHandle(\n        _In_ MultiplayerSearchHandleRequest searchHandleRequest,\n        _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>>> async\n    ) const noexcept;\n\n    HRESULT ClearActivity(\n        _In_ const String& scid,\n        _In_ AsyncContext<Result<void>> callback\n    ) const noexcept;\n\n    HRESULT DeleteSearchHandle(\n        _In_ const String& handleId,\n        _In_ AsyncContext<Result<void>> async\n    ) const noexcept;\n\n    HRESULT SendInvites(\n        _In_ XblMultiplayerSessionReference sessionReference,\n        _In_ const Vector<uint64_t>& xboxUserIds,\n        _In_ uint32_t titleId,\n        _In_ const String& contextStringId,\n        _In_ const String& customActivationContext,\n        _In_ AsyncContext<Result<Vector<String>>> async\n    ) const noexcept;\n\n    HRESULT GetActivitiesForSocialGroup(\n        _In_ const String& scid,\n        _In_ uint64_t socialGroupOwnerXuid,\n        _In_ const String& socialGroup,\n        _In_ AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>> async\n    ) const noexcept;\n\n    HRESULT GetActivitiesForUsers(\n        _In_ const String& scid,\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>> async\n    ) const noexcept;\n\n    HRESULT GetSearchHandles(\n        _In_ const MultiplayerQuerySearchHandleRequest& searchHandleRequest,\n        _In_ AsyncContext<Result<Vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>>> async\n    ) const noexcept;\n\n    HRESULT EnableMultiplayerSubscriptions() noexcept;\n    HRESULT DisableMultiplayerSubscriptions() noexcept;\n    bool SubscriptionsEnabled() noexcept;\n\n    XblFunctionContext AddMultiplayerSessionChangedHandler(\n        _In_ MultiplayerSubscription::SessionChangedHandler handler\n    ) noexcept;\n\n    void RemoveMultiplayerSessionChangedHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\n    typedef Function<void()> SubscriptionLostHandler;\n    XblFunctionContext AddMultiplayerSubscriptionLostHandler(\n        _In_ SubscriptionLostHandler handler\n    ) noexcept;\n\n    void RemoveMultiplayerSubscriptionLostHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\n    XblFunctionContext AddMultiplayerConnectionIdChangedHandler(\n        _In_ MultiplayerSubscription::ConnectionIdChangedHandler handler\n    ) noexcept;\n\n    void RemoveMultiplayerConnectionIdChangedHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\nprivate:\n    // Sets the RTA connection Id on a session if subscriptions are enabled\n    HRESULT SetRtaConnectionId(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ AsyncContext<Result<void>> async\n    ) noexcept;\n\n    HRESULT SubscribeToRta(std::unique_lock<std::mutex> lock) noexcept;\n    HRESULT UnsubscribeFromRta() noexcept;\n\n    HRESULT WriteSessionUsingSubpath(\n        _In_ std::shared_ptr<XblMultiplayerSession> session,\n        _In_ XblMultiplayerSessionWriteMode mode,\n        _In_ const String& subpathAndQuery,\n        _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n    ) noexcept;\n\n    static String MultiplayerSessionDirectoryCreateOrUpdateSubpath(\n        _In_ const String& serviceConfigurationId,\n        _In_ const String& sessionTemplateName,\n        _In_ const String& sessionName\n    ) noexcept;\n\n    static String MultiplayerSessionDirectoryCreateOrUpdateByHandleSubpath(\n        _In_ const String& handleId\n    ) noexcept;\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<xbox::services::AppConfig> m_appConfig;\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n\n    // RTA state\n    std::shared_ptr<MultiplayerSubscription> m_subscription;\n\n    XblFunctionContext m_rtaConnectionStateChangedToken{ 0 };\n    XblFunctionContext m_nextClientToken{ 1 };\n    Map<XblFunctionContext, SubscriptionLostHandler> m_subscriptionLostHandlers;\n    Map<XblFunctionContext, MultiplayerSubscription::ConnectionIdChangedHandler> m_connectionIdChangedHandlers;\n\n    List<std::pair<std::shared_ptr<XblMultiplayerSession>, AsyncContext<Result<void>>>> m_sessionsAwaitingConnectionId;\n\n    // Since MPSA RTA subscription can be used both to get session changed events and to enable\n    // automatic session member removal, we allow titles to force enable the RTA subscription\n    bool m_forceEnableRtaSubscription{ false };\n\n    std::mutex m_mutexMultiplayerService;\n};\n\nclass RoleTypes\n{\npublic:\n    RoleTypes() = default;\n    RoleTypes(const RoleTypes& other) noexcept;\n    RoleTypes& operator=(RoleTypes other) noexcept;\n    ~RoleTypes() noexcept;\n\n    static Result<RoleTypes> Deserialize(const JsonValue& json) noexcept;\n    JsonValue Serialize(JsonDocument::AllocatorType& allocator) const noexcept;\n\n    const Vector<XblMultiplayerRoleType>& Values() const noexcept;\n\n    HRESULT SetRoleSettings(\n        String&& roleTypeName,\n        String&& roleName,\n        uint32_t* maxCount,\n        uint32_t* targetCount\n    ) noexcept;\n\n    XblMultiplayerRole* GetRole(\n        String&& roleType,\n        String&& roleName\n    ) const noexcept;\nprivate:\n    Vector<XblMultiplayerRoleType> m_values{};\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END\n\nstruct XblMultiplayerSession : public xbox::services::RefCounter, public std::enable_shared_from_this<XblMultiplayerSession>\n{\npublic:\n    XblMultiplayerSession(\n        _In_ uint64_t xuid,\n        _In_opt_ const XblMultiplayerSessionReference* sessionReference = nullptr,\n        _In_opt_ const XblMultiplayerSessionInitArgs* initArgs = nullptr\n    );\n\n    XblMultiplayerSession(\n        _In_ uint64_t xboxUserId,\n        _In_ XblMultiplayerSessionReference sessionReference,\n        _In_ const xsapi_internal_string& eTag,\n        _In_ const xsapi_internal_string& responseDate,\n        _In_ const JsonValue& json\n    );\n\n    XblMultiplayerSession(const XblMultiplayerSession& other);\n    XblMultiplayerSession& operator=(const XblMultiplayerSession& rhs) = delete;\n\n    ~XblMultiplayerSession();\n\n    bool operator==(const XblMultiplayerSession& rhs) const;\n\n    void Initialize();\n\n    time_t TimeOfSession() const;\n    const xsapi_internal_string ETag() const;\n    const XblMultiplayerSessionInfo& SessionInfo() const; // only written during Deserialize so safe to return ref\n    const XblMultiplayerSessionInitializationInfo& InitializationInfo() const; // only written during Deserialize so safe to return ref\n    const XblMultiplayerSessionReference& SessionReference() const; // only written during ctor so safe to return ref\n    const xsapi_internal_vector<XblDeviceToken>& HostCandidates() const; // only written during Deserialize so safe to return ref\n\n    void StateLock() const;\n    void StateUnlock() const;\n\n    // Use XblMultiplayerSessionReadLockGuard that wraps StateLock/StateUnlock\n    const XblMultiplayerSessionConstants& SessionConstantsUnsafe() const;\n    const XblMultiplayerSessionProperties& SessionPropertiesUnsafe() const;\n    const xbox::services::multiplayer::RoleTypes& RoleTypesUnsafe() const;\n    const xsapi_internal_vector<XblMultiplayerSessionMember>& MembersUnsafe() const;\n    const xsapi_internal_vector<const char*>& ServerConnectionStringCandidatesUnsafe() const;\n    const xsapi_internal_vector<uint32_t>& TurnCollectionUnsafe() const;\n    const xsapi_internal_vector<const char*>& KeywordsUnsafe() const;\n    const XblMultiplayerSessionMember* CurrentUserUnsafe() const;\n    xbox::services::multiplayer::MultiplayerSessionMember* CurrentUserInternalUnsafe() const;\n    const XblMultiplayerSessionMember* GetMemberUnsafe(uint32_t memberId) const;\n    const xsapi_internal_string& RawServersJsonUnsafe() const;\n    const xsapi_internal_string& ETagUnsafe() const;\n\n    uint32_t MembersAccepted() const;\n    const xsapi_internal_string RawServersJson() const;\n    std::shared_ptr<const XblMultiplayerMatchmakingServer> MatchmakingServer() const; // only written during Deserialize so safe to return ref\n    XblWriteSessionStatus WriteStatus() const;\n\n    HRESULT DeserializationError() const;\n\n    HRESULT SetServersJson(\n        _In_ const xsapi_internal_string& serversJson\n    );\n    HRESULT AddMemberReservation(\n        _In_ uint64_t xuid,\n        _In_opt_z_ const char* memberCustomConstantsJson = nullptr,\n        _In_ bool initializeRequested = false\n    );\n    HRESULT Join(\n        _In_opt_z_ const char* memberCustomConstantsJson = nullptr,\n        _In_ bool initializeRequested = true,\n        _In_ bool joinWithActiveStatus = true\n    );\n    void SetVisibility(\n        _In_ XblMultiplayerSessionVisibility visibility\n    );\n    void SetMaxMembersInSession(\n        _In_ uint32_t maxMembersInSession\n    );\n    HRESULT SetMutableRoleSettings(\n        _In_ String&& roleTypeName,\n        _In_ String&& roleName,\n        _In_opt_ uint32_t * maxCount,\n        _In_opt_ uint32_t * targetCount\n    );\n    HRESULT SetTimeouts(\n        _In_ uint64_t memberReservedTimeout,\n        _In_ uint64_t memberInactiveTimeout,\n        _In_ uint64_t memberReadyTimeout,\n        _In_ uint64_t sessionEmptyTimeout\n    );\n    HRESULT SetQosConnectivityMetrics(\n        _In_ bool enableLatencyMetric,\n        _In_ bool enableBandwidthDownMetric,\n        _In_ bool enableBandwidthUpMetric,\n        _In_ bool enableCustomMetric\n    );\n    HRESULT SetMemberInitialization(\n        _In_ const XblMultiplayerMemberInitialization& memberInitialization\n    );\n    HRESULT SetPeerToPeerRequirements(\n        _In_ const XblMultiplayerPeerToPeerRequirements& requirements\n    );\n    HRESULT SetPeerToHostRequirements(\n        _In_ const XblMultiplayerPeerToHostRequirements& requirements\n    );\n    HRESULT SetMeasurementServerAddresses(\n        _In_ const xsapi_internal_string& measurementServerAddresses\n    );\n    HRESULT SetSessionCapabilities(\n        _In_ const XblMultiplayerSessionCapabilities& capabilities\n    );\n    HRESULT SetCloudComputePackageJson(\n        _In_ const xsapi_internal_string& sessionCloudComputePackageConstantsJson\n    );\n    void SetInitializationStatus(\n        _In_ bool initializationSucceeded\n    );\n    void SetHostDeviceToken(\n        _In_ const XblDeviceToken hostDeviceToken\n    );\n    void SetHostDeviceToken(\n        _In_ const xsapi_internal_string& deviceToken\n    );\n    void SetMatchmakingServerConnectionPath(\n        _In_ const xsapi_internal_string& serverConnectionPath\n    );\n    void SetClosed(\n        _In_ bool closed\n    );\n    void SetLocked(\n        _In_ bool locked\n    );\n    void SetAllocateCloudCompute(\n        _In_ bool allocateCloudCompute\n    );\n    void SetMatchmakingResubmit(\n        _In_ bool matchResubmit\n    );\n    HRESULT SetServerConnectionStringCandidates(\n        _In_reads_(serverConnectionStringCandidatesCount) const char** serverConnectionStringCandidates,\n        _In_ size_t serverConnectionStringCandidatesCount\n    );\n    HRESULT SetSessionChangeSubscription(\n        _In_ XblMultiplayerSessionChangeTypes changeTypes\n    );\n    HRESULT Leave();\n    HRESULT SetCurrentUserStatus(\n        _In_ XblMultiplayerSessionMemberStatus status\n    );\n    HRESULT SetCurrentUserSecureDeviceAddressBase64(\n        _In_ const xsapi_internal_string& value\n    );\n    HRESULT SetCurrentUserRoleInfo(\n        _In_ const xsapi_internal_vector<XblMultiplayerSessionMemberRole>& roles\n    );\n    HRESULT SetCurrentUserMembersInGroup(\n        _In_ const xsapi_internal_vector<uint32_t>& membersInGroup\n    );\n    HRESULT SetCurrentUserGroups(\n        _In_reads_(groupsCount) const char** groups,\n        _In_ size_t groupsCount\n    );\n    HRESULT SetCurrentUserEncounters(\n        _In_reads_(encountersCount) const char** encounters,\n        _In_ size_t encountersCount\n    );\n    HRESULT SetCurrentUserServerMeasurementsJson(\n        _In_ const xsapi_internal_string& serverMeasurementsJson\n    );\n    HRESULT SetCurrentUserQosMeasurementsJson(\n        _In_ const xsapi_internal_string& qosMeasurementsJson\n    );\n    HRESULT SetCurrentUserMemberCustomPropertyJson(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson = JsonValue()\n    );\n    HRESULT DeleteCurrentUserMemberCustomPropertyJson(\n        _In_ const xsapi_internal_string& name\n    );\n    HRESULT SetMatchmakingTargetSessionConstantsJson(\n        _In_ const xsapi_internal_string& matchmakingTargetSessionConstantsJson\n    );\n    HRESULT SetSessionCustomPropertyJson(\n        _In_ const xsapi_internal_string& name,\n        _In_ const JsonValue& valueJson = JsonValue()\n    );\n    HRESULT DeleteSessionCustomPropertyJson(\n        _In_ const xsapi_internal_string& name\n    );\n    HRESULT SetKeywords(\n        _In_ const char** keywords,\n        _In_ size_t keywordsCount\n    );\n    void SetJoinRestriction(\n        _In_ XblMultiplayerSessionRestriction joinRestriction\n    );\n    void SetReadRestriction(\n        _In_ XblMultiplayerSessionRestriction readRestriction\n    );\n    HRESULT SetTurnCollection(\n        _In_ const xsapi_internal_vector<uint32_t>& turnCollection\n    );\n\n    XblMultiplayerSessionChangeTypes CompareMultiplayerSessions(\n        _In_ std::shared_ptr<XblMultiplayerSession> other\n    );\n    static XblWriteSessionStatus ConvertHttpStatusToWriteSessionStatus(\n        _In_ int32_t httpStatusCode\n    );\n\n    void SetWriteSessionStatus(\n        int32_t httpStatusCode\n    );\n\n    static xsapi_internal_string ConvertMultiplayerHostSelectionMetricToString(_In_ XblMultiplayerMetrics multiplayMetric);\n    static XblMultiplayerMetrics ConvertStringToMultiplayerHostSelectionMetric(_In_ const xsapi_internal_string& value);\n    static XblMultiplayerInitializationStage ConvertStringToMultiplayerInitializationStage(_In_ const xsapi_internal_string& value);\n    static XblMatchmakingStatus ConvertStringToMatchmakingStatus(_In_ const xsapi_internal_string& value);\n    static xsapi_internal_string ConvertMatchmakingStatusToString(_In_ XblMatchmakingStatus matchmakingStatus);\n\n    static bool IsHost(\n        _In_ const xsapi_internal_string& memberDeviceToken,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& session\n    );\n\n    static bool IsPlayerInSession(\n        _In_ uint64_t xboxUserId,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& session\n    );\n\n    static const XblMultiplayerSessionMember* GetPlayerInSession(\n        _In_ uint64_t xboxUserId,\n        _In_ std::shared_ptr<XblMultiplayerSession> session\n    );\n    static const XblMultiplayerSessionMember* HostMember(_In_ std::shared_ptr<XblMultiplayerSession> session);\n    static bool HasSessionPropertyChanged(\n        _In_ const std::shared_ptr<XblMultiplayerSession>& session1,\n        _In_ const std::shared_ptr<XblMultiplayerSession>& session2,\n        _In_ const xsapi_internal_string& propertyName\n    );\n\n    static bool DoSessionsMatch(_In_ std::shared_ptr<XblMultiplayerSession> lhs, _In_ std::shared_ptr<XblMultiplayerSession> rhs);\n\n    void Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\nprivate:\n    // Deserialization helpers\n    HRESULT Deserialize(_In_ const JsonValue& json);\n    HRESULT DeserializeMembers(_In_ const JsonValue& json);\n    HRESULT DeserializeMatchmakingServer(_In_ const JsonValue& json);\n    HRESULT DeserializeSessionProperties(_In_ const JsonValue& json);\n    HRESULT DeserializeSessionConstants(_In_ const JsonValue& json);\n\n    // Serialization helpers\n    void SerializeSessionProperties(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n    void SerializeSessionConstants(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\n    // Fields not part of MPSD document\n    uint64_t m_xuid{ 0 };\n    xsapi_internal_string m_eTag;\n    time_t m_sessionRetrievedTime;\n\n    // MPSD document fields\n    XblMultiplayerSessionInfo m_info{};\n    XblMultiplayerSessionInitializationInfo m_initialization{};\n    XblMultiplayerSessionReference m_sessionReference{};\n    xsapi_internal_vector<XblDeviceToken> m_hostCandidates;\n\n    // Constants\n    XblMultiplayerSessionConstants m_sessionConstants{};\n    xsapi_internal_vector<uint64_t> m_initiatorXuids;\n    XblMultiplayerMemberInitialization m_memberInitialization{};\n    xsapi_internal_string m_constantsCustomJson;\n    xsapi_internal_string m_constantsCloudComputePackageJson;\n    xsapi_internal_string m_constantsMeasurementServerAddressesJson;\n\n    // Properties\n    XblMultiplayerSessionProperties m_sessionProperties{};\n    xsapi_internal_vector<const char*> m_keywords;\n    xsapi_internal_vector<uint32_t> m_sessionOwnerIndices;\n    xsapi_internal_vector<uint32_t> m_turnCollection;\n    xsapi_internal_vector<const char*> m_serverConnectionStringCandidates;\n    xsapi_internal_string m_matchmakingServerConnectionString;\n    xsapi_internal_string m_matchmakingTargetSessionConstantsJson;\n    xsapi_internal_string m_sessionCustomPropertiesJson;\n\n    // Roles\n    xbox::services::multiplayer::RoleTypes m_roleTypes;\n\n    // Member info\n    xsapi_internal_vector<XblMultiplayerSessionMember> m_members;\n    XblMultiplayerSessionMember* m_memberCurrentUser{ nullptr };\n    uint32_t m_membersAccepted{ 0 };\n\n    // Servers info\n    xsapi_internal_string m_serversJson;\n    std::shared_ptr<XblMultiplayerMatchmakingServer> m_matchmakingServer;\n    xsapi_internal_string m_matchmakingStatusDetails;\n    xsapi_internal_string m_lastTeamResultTeam;\n\n    XblWriteSessionStatus m_writeSessionStatus{};\n    std::atomic<bool> m_joiningSession;\n    bool m_newSession{ false };\n    HRESULT m_deserializationError;\n    xsapi_internal_string m_sessionSubscriptionGuid;\n\n    bool m_writePropertiesKeywords{ false };\n    bool m_writePropertiesTurns{ false };\n    bool m_writeInitializationStatus{ false };\n    bool m_initializationSucceeded{ false };\n    bool m_writeHostDeviceToken{ false };\n    bool m_writeMatchmakingServerConnectionPath{ false };\n    bool m_writeMatchmakingResubmit{ false };\n    bool m_writeServerConnectionStringCandidates{ false };\n    bool m_leaveSession{ false };\n    bool m_writeClosed{ false };\n    bool m_writeLocked{ false };\n    bool m_writeAllocateCloudCompute{ false };\n    bool m_writeRoleTypes{ false };\n    bool m_writeTimeouts{ false };\n    bool m_writeQosConnectivityMetrics{ false };\n    bool m_writeMemberInitialization{ false };\n    bool m_writePeerToPeerRequirements{ false };\n    bool m_writePeerToHostRequirements{ false };\n    bool m_writeMeasurementServerAddresses{ false };\n    bool m_writeJoinRestriction{ false };\n    bool m_writeReadRestriction{ false };\n    bool m_writeServersJson{ false };\n    bool m_writeMatchmakingTargetSessionConstants{ false };\n    bool m_writeSessionCustomPropertiesJson{ false };\n    bool m_writeConstants{ false };\n\n    mutable std::recursive_mutex m_lockSession;\n    uint32_t m_memberRequestIndex{ 0 };\n\n    // RefCounter override\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override;\n};\n\nclass XblMultiplayerSessionReadLockGuard\n{\npublic:\n    XblMultiplayerSessionReadLockGuard(_In_opt_ std::shared_ptr<XblMultiplayerSession> session) :\n        m_session(session)\n    {\n        if (m_session)\n        {\n            m_session->StateLock();\n        }\n    }\n\n    ~XblMultiplayerSessionReadLockGuard()\n    {\n        if (m_session)\n        {\n            m_session->StateUnlock();\n        }\n    }\n\n    const XblMultiplayerSessionConstants& SessionConstants() const\n    {\n        return m_session->SessionConstantsUnsafe();\n    }\n\n    const XblMultiplayerSessionProperties& SessionProperties() const\n    {\n        return m_session->SessionPropertiesUnsafe();\n    }\n\n    const xbox::services::multiplayer::RoleTypes& RoleTypes() const\n    {\n        return m_session->RoleTypesUnsafe();\n    }\n\n    const xsapi_internal_vector<XblMultiplayerSessionMember>& Members() const\n    {\n        return m_session->MembersUnsafe();\n    }\n\n    const xsapi_internal_vector<const char*>& ServerConnectionStringCandidates() const\n    {\n        return m_session->ServerConnectionStringCandidatesUnsafe();\n    }\n\n    const xsapi_internal_vector<uint32_t>& TurnCollection() const\n    {\n        return m_session->TurnCollectionUnsafe();\n    }\n\n    const xsapi_internal_vector<const char*>& Keywords() const\n    {\n        return m_session->KeywordsUnsafe();\n    }\n    const XblMultiplayerSessionMember* CurrentUser() const\n    {\n        return m_session->CurrentUserUnsafe();\n    }\n\n    xbox::services::multiplayer::MultiplayerSessionMember* CurrentUserInternal() const\n    {\n        return m_session->CurrentUserInternalUnsafe();\n    }\n\n    const XblMultiplayerSessionMember* GetMember(uint32_t memberId) const\n    {\n        return m_session->GetMemberUnsafe(memberId);\n    }\n\nprivate:\n    std::shared_ptr<XblMultiplayerSession> m_session;\n};\n\nstruct XblMultiplayerSearchHandleDetails : public xbox::services::RefCounter, public std::enable_shared_from_this<XblMultiplayerSearchHandleDetails>\n{\npublic:\n    XblMultiplayerSearchHandleDetails() = default;\n\n    static xbox::services::Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>> Deserialize(_In_ const JsonValue& json);\n\n    const XblMultiplayerSessionReference& SessionReference() const;\n    const xsapi_internal_string& HandleId() const;\n    const xsapi_internal_vector<uint64_t>& SessionOwnerXuids() const;\n    const xsapi_internal_vector<XblMultiplayerSessionTag>& Tags() const;\n    const xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>& NumberAttributes() const;\n    const xsapi_internal_vector<XblMultiplayerSessionStringAttribute>& StringAttributes() const;\n    const xbox::services::multiplayer::RoleTypes& RoleTypes() const;\n    XblMultiplayerSessionVisibility Visibility() const;\n    XblMultiplayerSessionRestriction JoinRestriction() const;\n    bool Closed() const;\n    size_t MaxMembersCount() const;\n    size_t MembersCount() const;\n    const xsapi_internal_string& CustomSessionPropertiesJson() const;\n    const xbox::services::datetime& HandleCreationTime() const;\n\nprivate:\n    XblMultiplayerSearchHandleDetails(const XblMultiplayerSearchHandleDetails&) = delete;\n    XblMultiplayerSearchHandleDetails& operator=(XblMultiplayerSearchHandleDetails) = delete;\n\n    // RefCounter\n    std::shared_ptr<RefCounter> GetSharedThis() override;\n\n    XblMultiplayerSessionReference m_sessionReference{};\n    xsapi_internal_string m_handleId;\n    xsapi_internal_vector<XblMultiplayerSessionTag> m_tags;\n    xsapi_internal_vector<uint64_t> m_sessionOwners;\n    bool m_closed{ false };\n    xsapi_internal_vector<XblMultiplayerSessionStringAttribute> m_stringAttributes;\n    xsapi_internal_vector<XblMultiplayerSessionNumberAttribute> m_numberAttributes;\n    xbox::services::multiplayer::RoleTypes m_roleTypes;\n    XblMultiplayerSessionVisibility m_visibility{ XblMultiplayerSessionVisibility::Unknown };\n    XblMultiplayerSessionRestriction m_joinRestriction{ XblMultiplayerSessionRestriction::Unknown };\n    size_t m_maxMembersCount{ 0 };\n    size_t m_membersCount{ 0 };\n    xbox::services::datetime m_handleCreationTime;\n    xsapi_internal_string m_customSessionPropertiesJson;\n};\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_invite_handle_post_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nMultiplayerInviteHandlePostRequest::MultiplayerInviteHandlePostRequest(\n    _In_ const XblMultiplayerSessionReference& sessionReference,\n    _In_ uint64_t invitedXuid,\n    _In_ uint32_t titleId,\n    _In_ const String& contextString,\n    _In_ const String& customActivationContext\n) noexcept :\n    m_json{ rapidjson::kObjectType }\n{\n    assert(XblMultiplayerSessionReferenceIsValid(&sessionReference));\n\n    auto& a{ m_json.GetAllocator() };\n\n    m_json.AddMember(\"type\", \"invite\", a);\n    JsonValue sessionRefJson;\n    Serializers::SerializeSessionReference(sessionReference, sessionRefJson, a);\n    m_json.AddMember(\"sessionRef\", sessionRefJson, a);\n    m_json.AddMember(\"version\", MULTIPLAYER_HANDLE_VERSION, a);\n    m_json.AddMember(\"invitedXuid\", JsonValue{ utils::uint64_to_internal_string(invitedXuid).c_str(), a }.Move(), a);\n\n    JsonValue jsonInviteAttributes(rapidjson::kObjectType);\n    jsonInviteAttributes.AddMember(\"titleId\", JsonValue{ utils::uint32_to_internal_string(titleId).c_str(), a }.Move(), a);\n\n    if (!contextString.empty())\n    {\n        jsonInviteAttributes.AddMember(\"contextString\", JsonValue{ contextString.c_str(), a }.Move(), a);\n    }\n\n    if (!customActivationContext.empty())\n    {\n        jsonInviteAttributes.AddMember(\"context\", JsonValue{ customActivationContext.c_str(), a }.Move(), a);\n    }\n    m_json.AddMember(\"inviteAttributes\", jsonInviteAttributes, a);\n}\n\nvoid MultiplayerInviteHandlePostRequest::SetInvitedXuid(uint64_t invitedXuid) noexcept\n{\n    JsonUtils::SetMember(m_json, \"invitedXuid\", JsonValue{ utils::uint64_to_internal_string(invitedXuid).c_str(), m_json.GetAllocator() }.Move());\n}\n\nconst JsonValue& MultiplayerInviteHandlePostRequest::Json() const noexcept\n{\n    return m_json;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_query_search_handle_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nMultiplayerQuerySearchHandleRequest::MultiplayerQuerySearchHandleRequest(\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& sessionTemplateName,\n    _In_ const xsapi_internal_string& orderBy,\n    _In_ bool orderAscending,\n    _In_ const xsapi_internal_string& searchFilter\n    ) :\n    m_serviceConfigurationId(scid),\n    m_sessionTemplateName(sessionTemplateName),\n    m_orderBy(orderBy),\n    m_orderAscending(orderAscending),\n    m_searchFilter(searchFilter)\n{\n}\n\nMultiplayerQuerySearchHandleRequest::MultiplayerQuerySearchHandleRequest(\n    _In_ const xsapi_internal_string& scid,\n    _In_ const xsapi_internal_string& sessionTemplateName\n    ) :\n    m_serviceConfigurationId(scid),\n    m_sessionTemplateName(sessionTemplateName)\n{\n}\n\nconst xsapi_internal_string&\nMultiplayerQuerySearchHandleRequest::Scid() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst xsapi_internal_string&\nMultiplayerQuerySearchHandleRequest::SessionTemplateName() const\n{\n    return m_sessionTemplateName;\n}\n\nbool\nMultiplayerQuerySearchHandleRequest::OrderAscending()\n{\n    return m_orderAscending;\n}\n\nvoid\nMultiplayerQuerySearchHandleRequest::SetOrderAscending(_In_ bool orderAscending)\n{\n    m_orderAscending = orderAscending;\n}\n\nconst xsapi_internal_string&\nMultiplayerQuerySearchHandleRequest::OrderBy() const\n{\n    return m_orderBy;\n}\n\nvoid\nMultiplayerQuerySearchHandleRequest::SetOrderBy(_In_ const xsapi_internal_string& orderBy)\n{\n    m_orderBy = orderBy;\n}\n\nconst xsapi_internal_string&\nMultiplayerQuerySearchHandleRequest::SearchFilter() const\n{\n    return m_searchFilter;\n}\n\nvoid\nMultiplayerQuerySearchHandleRequest::SetSearchFilter(_In_ const xsapi_internal_string& searchFilter)\n{\n    m_searchFilter = searchFilter;\n}\n\nconst xsapi_internal_string&\nMultiplayerQuerySearchHandleRequest::SocialGroup() const\n{\n    return m_socialGroup;\n}\n\nvoid\nMultiplayerQuerySearchHandleRequest::SetSocialGroup(_In_ const xsapi_internal_string& socialGroup)\n{\n    m_socialGroup = socialGroup;\n}\n\nvoid\nMultiplayerQuerySearchHandleRequest::Serialize(\n    _In_ uint64_t socialGroupXuid,\n    _Out_ JsonValue& json,\n    _In_ JsonDocument::AllocatorType& allocator\n) const\n{\n    json.SetObject();\n    json.AddMember(\"type\", JsonValue(\"search\", allocator).Move(), allocator);\n    json.AddMember(\"scid\", JsonValue(m_serviceConfigurationId.c_str(), allocator).Move(), allocator);\n    json.AddMember(\"templateName\", JsonValue(m_sessionTemplateName.c_str(), allocator).Move(), allocator);\n    json.AddMember(\"global\", true, allocator);\n\n    if (!m_searchFilter.empty())\n    {\n        json.AddMember(\"filter\", JsonValue(m_searchFilter.c_str(), allocator).Move(), allocator);\n    }\n\n    if (!m_orderBy.empty())\n    {\n        xsapi_internal_stringstream orderByQuery;\n        orderByQuery << m_orderBy;\n        if (m_orderAscending)\n        {\n            orderByQuery << \" asc\";\n        }\n        else\n        {\n            orderByQuery << \" desc\";\n        }\n        json.AddMember(\"orderBy\", JsonValue(orderByQuery.str().c_str(), allocator).Move(), allocator);\n    }\n\n    if (!m_socialGroup.empty())\n    {\n        JsonValue ownerObject(rapidjson::kObjectType);\n        JsonValue peopleObject(rapidjson::kObjectType);\n        peopleObject.AddMember(\"moniker\", JsonValue(m_socialGroup.c_str(), allocator).Move(), allocator);\n        peopleObject.AddMember(\"monikerXuid\", JsonValue(utils::uint64_to_internal_string(socialGroupXuid).c_str(), allocator).Move(), allocator);\n\n        ownerObject.AddMember(\"people\", peopleObject, allocator);\n        json.AddMember(\"sessionMembers\", ownerObject, allocator);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_search_handle_details.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::multiplayer;\n\nstd::shared_ptr<RefCounter> XblMultiplayerSearchHandleDetails::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nconst XblMultiplayerSessionReference&\nXblMultiplayerSearchHandleDetails::SessionReference() const\n{\n    return m_sessionReference;\n}\n\nconst xsapi_internal_string&\nXblMultiplayerSearchHandleDetails::HandleId() const\n{\n    return m_handleId;\n}\n\nconst xsapi_internal_vector<uint64_t>&\nXblMultiplayerSearchHandleDetails::SessionOwnerXuids() const\n{\n    return m_sessionOwners;\n}\n\nconst RoleTypes&\nXblMultiplayerSearchHandleDetails::RoleTypes() const\n{\n    return m_roleTypes;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionTag>&\nXblMultiplayerSearchHandleDetails::Tags() const\n{\n    return m_tags;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>&\nXblMultiplayerSearchHandleDetails::NumberAttributes() const\n{\n    return m_numberAttributes;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionStringAttribute>&\nXblMultiplayerSearchHandleDetails::StringAttributes() const\n{\n    return m_stringAttributes;\n}\n\nXblMultiplayerSessionVisibility\nXblMultiplayerSearchHandleDetails::Visibility() const\n{\n    return m_visibility;\n}\n\nXblMultiplayerSessionRestriction\nXblMultiplayerSearchHandleDetails::JoinRestriction() const\n{\n    return m_joinRestriction;\n}\n\nbool\nXblMultiplayerSearchHandleDetails::Closed() const\n{\n    return m_closed;\n}\n\nsize_t\nXblMultiplayerSearchHandleDetails::MaxMembersCount() const\n{\n    return m_maxMembersCount;\n}\n\nsize_t\nXblMultiplayerSearchHandleDetails::MembersCount() const\n{\n    return m_membersCount;\n}\n\nconst xbox::services::datetime&\nXblMultiplayerSearchHandleDetails::HandleCreationTime() const\n{\n    return m_handleCreationTime;\n}\n\nconst xsapi_internal_string&\nXblMultiplayerSearchHandleDetails::CustomSessionPropertiesJson() const\n{\n    return m_customSessionPropertiesJson;\n}\n\nResult<std::shared_ptr<XblMultiplayerSearchHandleDetails>>\nXblMultiplayerSearchHandleDetails::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    if (json.IsNull())\n    {\n        return Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>>{ S_OK };\n    }\n\n    auto returnResult{ MakeShared<XblMultiplayerSearchHandleDetails>() };\n\n    HRESULT errc = S_OK;\n\n    xsapi_internal_string type;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"type\", type));\n    if (utils::str_icmp_internal(type, \"search\") != 0)\n    {\n        return Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>>{ E_UNEXPECTED };\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", returnResult->m_handleId));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTime(json, \"createTime\", returnResult->m_handleCreationTime));\n    if (json.IsObject() && json.HasMember(\"sessionRef\"))\n    {\n        returnResult->m_sessionReference = Serializers::DeserializeSessionReference(json[\"sessionRef\"]).Payload();\n    }\n    else\n    {\n        returnResult->m_sessionReference = XblMultiplayerSessionReference();\n    }\n\n    if (json.IsObject() && json.HasMember(\"customProperties\"))\n    {\n        const JsonValue& customPropertiesObject = json[\"customProperties\"];\n        if (!customPropertiesObject.IsNull())\n        {\n        returnResult->m_customSessionPropertiesJson = JsonUtils::SerializeJson(customPropertiesObject);\n        }\n    }\n\n    if (json.IsObject() && json.HasMember(\"searchAttributes\"))\n    {\n        const JsonValue& searchAttributesObject = json[\"searchAttributes\"];\n        if (!searchAttributesObject.IsNull())\n        {\n            if (searchAttributesObject.IsObject() && searchAttributesObject.HasMember(\"tags\"))\n            {\n                const JsonValue& tagAttributesJson = searchAttributesObject[\"tags\"];\n                if (!tagAttributesJson.IsNull() && tagAttributesJson.IsArray())\n                {\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblMultiplayerSessionTag>(\n                        [](const JsonValue& json)\n                        {\n                            if (!json.IsString())\n                            {\n                                return Result<XblMultiplayerSessionTag>{ WEB_E_INVALID_JSON_STRING };\n                            }\n                            XblMultiplayerSessionTag tag{};\n                            utils::strcpy(tag.value, sizeof(tag.value), json.GetString());\n\n                            return Result<XblMultiplayerSessionTag>{ tag };\n                        },\n                        searchAttributesObject,\n                            \"tags\",\n                            returnResult->m_tags,\n                            false\n                            ));\n                }\n            }\n\n            if (searchAttributesObject.IsObject() && searchAttributesObject.HasMember(\"strings\"))\n            {\n                const JsonValue& stringAttributesJson = searchAttributesObject[\"strings\"];\n                if (!stringAttributesJson.IsNull() && stringAttributesJson.IsObject())\n                {\n                    for (const auto& stringsMetadata : stringAttributesJson.GetObject())\n                    {\n                        XblMultiplayerSessionStringAttribute attr{};\n                        utils::strcpy(attr.name, sizeof(attr.name), stringsMetadata.name.GetString());\n                        utils::strcpy(attr.value, sizeof(attr.name), stringsMetadata.value.GetString());\n\n                        returnResult->m_stringAttributes.push_back(std::move(attr));\n                    }\n                }\n            }\n\n            if (searchAttributesObject.IsObject() && searchAttributesObject.HasMember(\"numbers\"))\n            {\n                const JsonValue& numbersMetadataJson = searchAttributesObject[\"numbers\"];\n                if (!numbersMetadataJson.IsNull() && numbersMetadataJson.IsObject())\n                {\n                    for (const auto& numbersMetadata : numbersMetadataJson.GetObject())\n                    {\n                        XblMultiplayerSessionNumberAttribute attr{};\n                        utils::strcpy(attr.name, sizeof(attr.name), numbersMetadata.name.GetString());\n                        attr.value = numbersMetadata.value.GetDouble();\n\n                        returnResult->m_numberAttributes.push_back(std::move(attr));\n                    }\n                }\n            }\n        }\n    }\n\n    if (json.IsObject() && json.HasMember(\"relatedInfo\"))\n    {\n        const JsonValue& relatedInfoObject = json[\"relatedInfo\"];\n        if (!relatedInfoObject.IsNull())\n        {\n            int membersCount = 0;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(relatedInfoObject, \"membersCount\", membersCount, true));\n            returnResult->m_membersCount = membersCount;\n            int maxMembersCount = 0;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(relatedInfoObject, \"maxMembersCount\", maxMembersCount, true));\n            returnResult->m_maxMembersCount = maxMembersCount;\n            xsapi_internal_string joinRestriction;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(relatedInfoObject, \"joinRestriction\", joinRestriction));\n            returnResult->m_joinRestriction = Serializers::MultiplayerSessionRestrictionFromString(joinRestriction);\n            xsapi_internal_string visibility;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(relatedInfoObject, \"visibility\", visibility));\n            returnResult->m_visibility = Serializers::MultiplayerSessionVisibilityFromString(visibility);\n\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(relatedInfoObject, \"closed\", returnResult->m_closed));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint64_t>(JsonUtils::JsonXuidExtractor, relatedInfoObject, \"sessionOwners\", returnResult->m_sessionOwners, false));\n        }\n    }\n\n    if (json.IsObject() && json.HasMember(\"roleInfo\"))\n    {\n        const JsonValue& roleInfo = json[\"roleInfo\"];\n        if (!roleInfo.IsNull())\n        {\n            if (roleInfo.IsObject() && roleInfo.HasMember(\"roleTypes\"))\n            {\n                auto roleTypesResult{ RoleTypes::Deserialize(roleInfo[\"roleTypes\"]) };\n                RETURN_HR_IF_FAILED(roleTypesResult.Hresult());\n                returnResult->m_roleTypes = roleTypesResult.ExtractPayload();\n            }\n        }\n    }\n\n    return Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>>{ returnResult, errc };\n}"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_search_handle_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nMultiplayerSearchHandleRequest::MultiplayerSearchHandleRequest(\n    _In_ XblMultiplayerSessionReference sessionReference\n) :\n    m_sessionReference(std::move(sessionReference))\n{\n}\n\nconst XblMultiplayerSessionReference&\nMultiplayerSearchHandleRequest::SessionReference() const\n{\n    return m_sessionReference;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionTag>&\nMultiplayerSearchHandleRequest::Tags() const\n{\n    return m_tags;\n}\n\nvoid\nMultiplayerSearchHandleRequest::SetTags(\n    _In_ xsapi_internal_vector<XblMultiplayerSessionTag>&& value\n)\n{\n    m_tags = value;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>&\nMultiplayerSearchHandleRequest::NumberAttributes() const\n{\n    return m_numberAttributes;\n}\n\nvoid\nMultiplayerSearchHandleRequest::SetNumberAttributes(\n    _In_ xsapi_internal_vector<XblMultiplayerSessionNumberAttribute>&& attributes\n)\n{\n    m_numberAttributes = attributes;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionStringAttribute>&\nMultiplayerSearchHandleRequest::StringAttributes() const\n{\n    return m_stringAttributes;\n}\n\nvoid\nMultiplayerSearchHandleRequest::SetStringAttributes(\n    _In_ xsapi_internal_vector<XblMultiplayerSessionStringAttribute>&& attributes\n)\n{\n    m_stringAttributes = attributes;\n}\n\nvoid\nMultiplayerSearchHandleRequest::Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator) const\n{\n    json.SetObject();\n\n    json.AddMember(\"type\", \"search\", allocator);\n    json.AddMember(\"version\", m_version, allocator);\n    JsonValue sessionRefJson;\n    Serializers::SerializeSessionReference(m_sessionReference, sessionRefJson, allocator);\n    json.AddMember(\"sessionRef\", sessionRefJson, allocator);\n\n    JsonValue searchAttributesJson(rapidjson::kObjectType);\n    bool setSearchAttributes = false;\n    if (!m_tags.empty())\n    {\n        setSearchAttributes = true;\n        JsonValue tagsJson(rapidjson::kArrayType);\n        JsonUtils::SerializeVector<XblMultiplayerSessionTag>(\n            [](XblMultiplayerSessionTag tag, JsonValue& j, JsonDocument::AllocatorType& a)\n            {\n                j.SetString(tag.value, a);\n            },\n            m_tags,\n            tagsJson,\n            allocator);\n        searchAttributesJson.AddMember(\"tags\", tagsJson, allocator);\n    }\n\n    if (!m_numberAttributes.empty())\n    {\n        setSearchAttributes = true;\n        JsonValue numberAttributesJson(rapidjson::kObjectType);\n        for (auto& attr : m_numberAttributes)\n        {\n            numberAttributesJson.AddMember(JsonValue(attr.name, allocator).Move(), attr.value, allocator);\n        }\n        searchAttributesJson.AddMember(\"numbers\", numberAttributesJson, allocator);\n    }\n\n    if (!m_stringAttributes.empty())\n    {\n        setSearchAttributes = true;\n        JsonValue stringAttributesJson(rapidjson::kObjectType);\n        for (auto& attr : m_stringAttributes)\n        {\n            stringAttributesJson.AddMember(JsonValue(attr.name, allocator).Move(), JsonValue(attr.value, allocator).Move(), allocator);\n        }\n        searchAttributesJson.AddMember(\"strings\", stringAttributesJson, allocator);\n    }\n\n    if (setSearchAttributes)\n    {\n        json.AddMember(\"searchAttributes\", searchAttributesJson, allocator);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_serializers.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nResult<XblMultiplayerActivityDetails> Serializers::DeserializeMultiplayerActivityDetails(\n    _In_ const JsonValue& json\n)\n{\n    XblMultiplayerActivityDetails returnResult{};\n    XSAPI_ASSERT(!json.IsNull());\n\n    xsapi_internal_string type;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"type\", type));\n    if (type.compare(\"activity\") != 0)\n    {\n        return returnResult;\n    }\n\n    xsapi_internal_string id;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", id));\n    utils::strcpy(returnResult.HandleId, sizeof(returnResult.HandleId), id.data());\n    if (json.IsObject() && json.HasMember(\"sessionRef\"))\n    {\n        returnResult.SessionReference = DeserializeSessionReference(json[\"sessionRef\"]).Payload();\n    }\n    else\n    {\n        returnResult.SessionReference = XblMultiplayerSessionReference();\n    }\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"ownerXuid\", returnResult.OwnerXuid));\n    xsapi_internal_string titleId;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"titleId\", titleId));\n    returnResult.TitleId = utils::internal_string_to_uint32(titleId);\n\n    xsapi_internal_string customProperties = JsonUtils::SerializeJson(json[\"customProperties\"]);\n    returnResult.CustomSessionPropertiesJson = Make(customProperties.c_str());\n    \n    if (json.IsObject() && json.HasMember(\"relatedInfo\"))\n    {\n        const JsonValue& relatedInfoObject = json[\"relatedInfo\"];\n        if (!relatedInfoObject.IsNull())\n        {\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(relatedInfoObject, \"membersCount\", returnResult.MembersCount));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(relatedInfoObject, \"maxMembersCount\", returnResult.MaxMembersCount));\n            xsapi_internal_string joinRestriction;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(relatedInfoObject, \"joinRestriction\", joinRestriction));\n            returnResult.JoinRestriction = MultiplayerSessionRestrictionFromString(joinRestriction);\n            xsapi_internal_string visibility;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(relatedInfoObject, \"visibility\", visibility));\n            returnResult.Visibility = MultiplayerSessionVisibilityFromString(visibility);\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(relatedInfoObject, \"closed\", returnResult.Closed));\n        }\n    }\n\n    return returnResult;\n}\n\nResult<XblMultiplayerSessionQueryResult> Serializers::DeserializeMultiplayerSessionQueryResult(\n    _In_ const JsonValue& json\n)\n{\n    if (json.IsNull())\n    {\n        return E_INVALIDARG;\n    }\n    XblMultiplayerSessionQueryResult returnResult{};\n\n    if (json.IsObject() && json.HasMember(\"sessionRef\"))\n    {\n        const JsonValue& sessionRefJson = json[\"sessionRef\"];\n        returnResult.SessionReference = DeserializeSessionReference(sessionRefJson).Payload();\n    }\n    else\n    {\n        returnResult.SessionReference = XblMultiplayerSessionReference();\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"myTurn\", returnResult.IsMyTurn));\n    xsapi_internal_string sessionStatus;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"status\", sessionStatus));\n    if (!sessionStatus.empty())\n    {\n        returnResult.Status = MultiplayerSessionStatusFromString(std::move(sessionStatus));\n    }\n\n    xsapi_internal_string sessionVisibility;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"visibility\", sessionVisibility));\n    if (!sessionVisibility.empty())\n    {\n        returnResult.Visibility = MultiplayerSessionVisibilityFromString(sessionVisibility);\n    }\n\n    xsapi_internal_string joinRestriction;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"joinRestriction\", joinRestriction));\n    if (!joinRestriction.empty())\n    {\n        returnResult.JoinRestriction = MultiplayerSessionRestrictionFromString(joinRestriction);\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"startTime\", returnResult.StartTime));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"xuid\", returnResult.Xuid));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"accepted\", returnResult.AcceptedMemberCount));\n\n    return returnResult;\n}\n\nResult<XblMultiplayerSessionReference> Serializers::DeserializeSessionReference(\n    _In_ const JsonValue& json\n)\n{\n    XblMultiplayerSessionReference result{};\n    if (json.IsNull())\n    {\n        return result;\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"scid\", result.Scid, sizeof(result.Scid)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"templateName\", result.SessionTemplateName, sizeof(result.SessionTemplateName)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"name\", result.SessionName, sizeof(result.SessionName)));\n\n    return result;\n}\n\nvoid Serializers::SerializeSessionReference(const XblMultiplayerSessionReference& sessionReference, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    json.SetObject();\n    json.AddMember(\"scid\", JsonValue(sessionReference.Scid, allocator).Move(), allocator);\n    json.AddMember(\"templateName\", JsonValue(sessionReference.SessionTemplateName, allocator).Move(), allocator);\n    json.AddMember(\"name\", JsonValue(sessionReference.SessionName, allocator).Move(), allocator);\n}\n\nResult<XblMultiplayerInviteHandle> Serializers::DeserializeMultiplayerInvite(\n    _In_ const JsonValue& json\n)\n{\n    XblMultiplayerInviteHandle returnResult{};\n    if (json.IsNull())\n    {\n        return returnResult;\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"id\", returnResult.Data, sizeof(returnResult.Data)));\n    return returnResult;\n}\n\nXblMultiplayerSessionRestriction Serializers::MultiplayerSessionRestrictionFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"none\") == 0)\n    {\n        return XblMultiplayerSessionRestriction::None;\n    }\n    else if (utils::str_icmp_internal(value, \"local\") == 0)\n    {\n        return XblMultiplayerSessionRestriction::Local;\n    }\n    else if (utils::str_icmp_internal(value, \"followed\") == 0)\n    {\n        return XblMultiplayerSessionRestriction::Followed;\n    }\n\n    return XblMultiplayerSessionRestriction::Unknown;\n}\n\nxsapi_internal_string Serializers::StringFromMultiplayerSessionRestriction(\n    _In_ XblMultiplayerSessionRestriction joinRestriction\n)\n{\n    switch (joinRestriction)\n    {\n    case XblMultiplayerSessionRestriction::Unknown: return \"unknown\";\n    case XblMultiplayerSessionRestriction::None: return \"none\";\n    case XblMultiplayerSessionRestriction::Local: return \"local\";\n    case XblMultiplayerSessionRestriction::Followed: return \"followed\";\n    default:\n    {\n        XSAPI_ASSERT(false);\n        return \"unknown\";\n    }\n    }\n}\n\nXblMultiplayerSessionStatus Serializers::MultiplayerSessionStatusFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"active\") == 0)\n    {\n        return XblMultiplayerSessionStatus::Active;\n    }\n    else if (utils::str_icmp_internal(value, \"inactive\") == 0)\n    {\n        return XblMultiplayerSessionStatus::Inactive;\n    }\n    else if (utils::str_icmp_internal(value, \"reserved\") == 0)\n    {\n        return XblMultiplayerSessionStatus::Reserved;\n    }\n\n    return XblMultiplayerSessionStatus::Unknown;\n}\n\nXblMultiplayerSessionVisibility Serializers::MultiplayerSessionVisibilityFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"private\") == 0)\n    {\n        return XblMultiplayerSessionVisibility::PrivateSession;\n    }\n    else if (utils::str_icmp_internal(value, \"visible\") == 0)\n    {\n        return XblMultiplayerSessionVisibility::Visible;\n    }\n    else if (utils::str_icmp_internal(value, \"full\") == 0)\n    {\n        return XblMultiplayerSessionVisibility::Full;\n    }\n    else if (utils::str_icmp_internal(value, \"open\") == 0)\n    {\n        return XblMultiplayerSessionVisibility::Open;\n    }\n\n    return XblMultiplayerSessionVisibility::Unknown;\n}\n\nxsapi_internal_string Serializers::StringFromMultiplayerSessionVisibility(_In_ XblMultiplayerSessionVisibility sessionVisibility)\n{\n    switch (sessionVisibility)\n    {\n    case XblMultiplayerSessionVisibility::Unknown: return \"unknown\";\n    case XblMultiplayerSessionVisibility::Any: return \"any\";\n    case XblMultiplayerSessionVisibility::PrivateSession: return \"private\";\n    case XblMultiplayerSessionVisibility::Visible: return \"visible\";\n    case XblMultiplayerSessionVisibility::Full: return \"full\";\n    case XblMultiplayerSessionVisibility::Open: return \"open\";\n    default:\n    {\n        XSAPI_ASSERT(false);\n        return \"unknown\";\n    }\n    }\n}\n\nXblNetworkAddressTranslationSetting Serializers::MultiplayerNatSettingFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (value.empty())\n    {\n        return XblNetworkAddressTranslationSetting::Unknown;\n    }\n    else if (utils::str_icmp_internal(value, \"strict\") == 0)\n    {\n        return XblNetworkAddressTranslationSetting::Strict;\n    }\n    else if (utils::str_icmp_internal(value, \"moderate\") == 0)\n    {\n        return XblNetworkAddressTranslationSetting::Moderate;\n    }\n    else if (utils::str_icmp_internal(value, \"open\") == 0)\n    {\n        return XblNetworkAddressTranslationSetting::Open;\n    }\n\n    return XblNetworkAddressTranslationSetting::Unknown;\n}\n\nXblMultiplayerMeasurementFailure Serializers::MultiplayerMeasurementFailureFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (value.empty())\n    {\n        return XblMultiplayerMeasurementFailure::None;\n    }\n    else if (utils::str_icmp_internal(value, \"bandwidthUp\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::BandwidthUp;\n    }\n    else if (utils::str_icmp_internal(value, \"bandwidthDown\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::BandwidthDown;\n    }\n    else if (utils::str_icmp_internal(value, \"latency\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::Latency;\n    }\n    else if (utils::str_icmp_internal(value, \"timeout\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::Timeout;\n    }\n    else if (utils::str_icmp_internal(value, \"group\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::Group;\n    }\n    else if (utils::str_icmp_internal(value, \"network\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::Network;\n    }\n    else if (utils::str_icmp_internal(value, \"episode\") == 0)\n    {\n        return XblMultiplayerMeasurementFailure::Episode;\n    }\n\n    return XblMultiplayerMeasurementFailure::Unknown;\n}\n\nXblMultiplayerSessionChangeTypes Serializers::MultiplayerSessionChangeTypesFromStringVector(\n    _In_ const xsapi_internal_vector<xsapi_internal_string>& changeTypeList\n)\n{\n    XblMultiplayerSessionChangeTypes resultingChangeTypes = XblMultiplayerSessionChangeTypes::None;\n    for (auto& current : changeTypeList)\n    {\n        if (utils::str_icmp_internal(current, \"everything\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::Everything;\n        }\n        else if (utils::str_icmp_internal(current, \"host\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::HostDeviceTokenChange;\n        }\n        else if (utils::str_icmp_internal(current, \"initialization\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::InitializationStateChange;\n        }\n        else if (utils::str_icmp_internal(current, \"matchmakingStatus\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::MatchmakingStatusChange;\n        }\n        else if (utils::str_icmp_internal(current, \"membersList\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::MemberListChange;\n        }\n        else if (utils::str_icmp_internal(current, \"membersStatus\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::MemberStatusChange;\n        }\n        else if (utils::str_icmp_internal(current, \"XblMultiplayerJoinability\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::SessionJoinabilityChange;\n        }\n        else if (utils::str_icmp_internal(current, \"customProperty\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::CustomPropertyChange;\n        }\n        else if (utils::str_icmp_internal(current, \"membersCustomProperty\") == 0)\n        {\n            resultingChangeTypes |= XblMultiplayerSessionChangeTypes::MemberCustomPropertyChange;\n        }\n    }\n    return static_cast<XblMultiplayerSessionChangeTypes>(resultingChangeTypes);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nusing namespace xbox::services::multiplayer;\nusing namespace xbox::services::system;\nusing namespace xbox::services::legacy;\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\n#define GET_ACTIIVITIES_SUBPATH \"/handles/query?include=relatedInfo,customProperties\"\n#define GET_SEARCH_HANDLES_SUBPATH \"/handles/query?include=relatedInfo,roleInfo,customProperties\"\n#define MULTIPLAYER_SERVICE_CONTRACT_VERSION 107\n\nMultiplayerService::MultiplayerService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<xbox::services::AppConfig> appConfig,\n    _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> realTimeActivity\n) noexcept\n    : m_user{ std::move(user) },\n    m_xboxLiveContextSettings{ std::move(xboxLiveContextSettings) },\n    m_appConfig{ std::move(appConfig) },\n    m_rtaManager{ std::move(realTimeActivity) }\n{\n}\n\nMultiplayerService::~MultiplayerService() noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n    UnsubscribeFromRta();\n}\n\nHRESULT MultiplayerService::WriteSession(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ XblMultiplayerSessionWriteMode mode,\n    _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n) noexcept\n{\n    auto& sessionReference = session->SessionReference();\n\n    auto pathAndQuery = MultiplayerSessionDirectoryCreateOrUpdateSubpath(\n        sessionReference.Scid,\n        sessionReference.SessionTemplateName,\n        sessionReference.SessionName\n    );\n\n    return WriteSessionUsingSubpath(\n        session,\n        mode,\n        pathAndQuery,\n        std::move(async)\n    );\n}\n\nHRESULT MultiplayerService::WriteSessionByHandle(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ XblMultiplayerSessionWriteMode mode,\n    _In_ const String& handleId,\n    _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handleId.empty());\n\n    auto pathAndQuery = MultiplayerSessionDirectoryCreateOrUpdateByHandleSubpath(handleId);\n    return WriteSessionUsingSubpath(\n        session,\n        mode,\n        pathAndQuery,\n        std::move(async)\n    );\n}\n\nHRESULT MultiplayerService::GetCurrentSession(\n    _In_ XblMultiplayerSessionReference sessionReference,\n    _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(sessionReference.Scid);\n\n    String pathAndQuery = MultiplayerSessionDirectoryCreateOrUpdateSubpath(\n        sessionReference.Scid,\n        sessionReference.SessionTemplateName,\n        sessionReference.SessionName\n    );\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", pathAndQuery),\n        xbox_live_api::get_current_session\n    );\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [\n            sessionReference,\n            xuid{ m_user.Xuid() },\n            async\n        ]\n    (HttpResult httpResult)\n    {\n        HRESULT hr = httpResult.Hresult();\n        if (FAILED(hr))\n        {\n            return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(hr, \"Http call failed\"));\n        }\n\n        hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(hr, errorMessagePtr));\n        }\n        else if (httpResult.Payload()->HttpStatus() == 204)\n        {\n            // Return a not found error when trying to get an non-existing session\n            return async.Complete(__HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND));\n        }\n\n        auto session = MakeShared<XblMultiplayerSession>(\n            xuid,\n            sessionReference,\n            httpResult.Payload()->GetResponseHeader(ETAG_HEADER),\n            httpResult.Payload()->GetResponseHeader(DATE_HEADER),\n            httpResult.Payload()->GetResponseBodyJson()\n        );\n\n        async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(session, session->DeserializationError(), \"Deserialize error\"));\n    }\n    });\n}\n\nHRESULT MultiplayerService::GetCurrentSessionByHandle(\n    _In_ const String& handleId,\n    _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handleId.empty());\n    String pathAndQuery = MultiplayerSessionDirectoryCreateOrUpdateByHandleSubpath(handleId);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", pathAndQuery),\n        xbox_live_api::get_current_session_by_handle\n    );\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [\n            xuid{ m_user.Xuid() },\n            async\n        ]\n    (HttpResult httpResult)\n    {\n        HRESULT hr = httpResult.Hresult();\n        if (FAILED(hr))\n        {\n            return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(hr));\n        }\n\n        hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(hr));\n        }\n        else if (httpResult.Payload()->HttpStatus() == 204)\n        {\n            // Return a not found error when trying to get an non-existing session\n            return async.Complete(__HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND));\n        }\n\n        auto contentLocation = httpResult.Payload()->GetResponseHeader(\"Content-Location\");\n\n        XblMultiplayerSessionReference sessionReference;\n        hr = XblMultiplayerSessionReferenceParseFromUriPath(contentLocation.c_str(), &sessionReference);\n        if (FAILED(hr))\n        {\n            // Failed to parse session reference from URI\n            return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(hr));\n        }\n\n        auto session = MakeShared<XblMultiplayerSession>(\n            xuid,\n            sessionReference,\n            httpResult.Payload()->GetResponseHeader(ETAG_HEADER),\n            httpResult.Payload()->GetResponseHeader(DATE_HEADER),\n            httpResult.Payload()->GetResponseBodyJson()\n        );\n\n        async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(session, session->DeserializationError()));\n    }\n    });\n}\n\nSessionQuery::SessionQuery(const XblMultiplayerSessionQuery* other) noexcept\n    : XblMultiplayerSessionQuery{ *other }\n{\n    // Deep copy xuid filters & keyword filter so that we own them\n    for (size_t i = 0; i < XuidFiltersCount; ++i)\n    {\n        m_xuidFilters.push_back(other->XuidFilters[i]);\n    }\n    XuidFilters = m_xuidFilters.data();\n\n    if (KeywordFilter)\n    {\n        m_keywordFilter = KeywordFilter;\n        KeywordFilter = m_keywordFilter.data();\n    }\n}\n\nSessionQuery::SessionQuery(const SessionQuery& other) noexcept\n    : SessionQuery{ &other }\n{\n}\n\nString SessionQuery::PathAndQuery() const noexcept\n{\n    Stringstream source;\n\n    source << \"/serviceconfigs/\";\n    source << Scid;\n    if (SessionTemplateNameFilter[0] != 0)\n    {\n        source << \"/sessiontemplates/\";\n        source << SessionTemplateNameFilter;\n    }\n\n    if (XuidFiltersCount > 1)\n    {\n        source << \"/batch\";\n    }\n    else\n    {\n        source << \"/sessions\";\n    }\n\n    Vector<String> params;\n    if (XuidFiltersCount == 1)\n    {\n        Stringstream param;\n        param << \"xuid=\";\n        param << xbox::services::uri::encode_uri(utils::uint64_to_internal_string(XuidFilters[0]));\n        params.push_back(param.str());\n    }\n\n    if (!m_keywordFilter.empty())\n    {\n        Stringstream param;\n        param << \"keyword=\";\n        param << xbox::services::uri::encode_uri(KeywordFilter);\n        params.push_back(param.str());\n    }\n\n    if (VisibilityFilter != XblMultiplayerSessionVisibility::Any)\n    {\n        Stringstream param;\n        param << \"visibility=\";\n        param << xbox::services::uri::encode_uri(Serializers::StringFromMultiplayerSessionVisibility(VisibilityFilter));\n        params.push_back(param.str());\n    }\n\n    if (ContractVersionFilter != 0)\n    {\n        Stringstream param;\n        param << \"version=\";\n        param << ContractVersionFilter;\n        params.push_back(param.str());\n    }\n\n    if (IncludePrivateSessions)\n    {\n        params.push_back(\"private=true\");\n    }\n\n    if (IncludeReservations)\n    {\n        params.push_back(\"reservations=true\");\n    }\n\n    if (IncludeInactiveSessions)\n    {\n        params.push_back(\"inactive=true\");\n    }\n\n    if (MaxItems != 0)\n    {\n        Stringstream param;\n        param << \"take=\";\n        param << MaxItems;\n        params.push_back(param.str());\n    }\n\n    source << utils::get_query_from_params(params);\n\n    return source.str();\n}\n\nJsonDocument SessionQuery::RequestBody() const noexcept\n{\n    JsonDocument requestBody{ rapidjson::kNullType };\n    if (m_xuidFilters.size() > 1)\n    {\n        requestBody.SetObject();\n        JsonValue xuidsArrayJson{ rapidjson::kArrayType };\n        JsonUtils::SerializeVector(JsonUtils::JsonXuidSerializer, m_xuidFilters, xuidsArrayJson, requestBody.GetAllocator());\n        requestBody.AddMember(\"xuids\", xuidsArrayJson, requestBody.GetAllocator());\n    }\n    return requestBody;\n}\n\nHRESULT MultiplayerService::GetSessions(\n    _In_ const SessionQuery& getSessionsRequest,\n    _In_ AsyncContext<Result<Vector<XblMultiplayerSessionQueryResult>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(getSessionsRequest.Scid);\n    RETURN_HR_INVALIDARGUMENT_IF((getSessionsRequest.XuidFilters == nullptr || getSessionsRequest.XuidFiltersCount == 0) && \n                                 (getSessionsRequest.KeywordFilter == nullptr || getSessionsRequest.KeywordFilter[0] == 0));\n    RETURN_HR_INVALIDARGUMENT_IF(getSessionsRequest.IncludeReservations && (getSessionsRequest.XuidFilters == nullptr || getSessionsRequest.XuidFiltersCount == 0));\n    RETURN_HR_INVALIDARGUMENT_IF(getSessionsRequest.IncludeInactiveSessions && (getSessionsRequest.XuidFilters == nullptr || getSessionsRequest.XuidFiltersCount == 0));\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        getSessionsRequest.XuidFiltersCount > 1 ? \"POST\" : \"GET\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", getSessionsRequest.PathAndQuery()),\n        xbox_live_api::get_sessions\n    );\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\n    auto requestBody{ getSessionsRequest.RequestBody() };\n    if (!requestBody.IsNull())\n    {\n        RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestBody));\n    }\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [\n            async\n        ]\n    (HttpResult httpResult)\n    {\n        if (FAILED(httpResult.Hresult()))\n        {\n            return async.Complete({ httpResult.Hresult(), \"Http call failed\" });\n        }\n\n        auto hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete({ hr, errorMessagePtr });\n        }\n\n        Vector<XblMultiplayerSessionQueryResult> sessionStates;\n        hr = JsonUtils::ExtractJsonVector<XblMultiplayerSessionQueryResult>(\n            Serializers::DeserializeMultiplayerSessionQueryResult,\n            httpResult.Payload()->GetResponseBodyJson(),\n            \"results\",\n            sessionStates,\n            true\n        );\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n        \n        return async.Complete(sessionStates);\n    }\n    });\n}\n\nHRESULT MultiplayerService::SetActivity(\n    _In_ const XblMultiplayerSessionReference& sessionReference,\n    _In_ AsyncContext<Result<void>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(sessionReference.Scid);\n\n    MultiplayerActivityHandlePostRequest request{ sessionReference };\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", \"/handles\"),\n        xbox_live_api::set_activity\n    );\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n    JsonDocument requestJson;\n    request.Serialize(requestJson, requestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(requestJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        if (FAILED(httpResult.Hresult()))\n        {\n            async.Complete({ httpResult.Hresult(), \"Http call failed\" });\n        }\n        else\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            async.Complete({ httpResult.Payload()->Result(), errorMessagePtr });\n        }\n    }\n    });\n}\n\nHRESULT MultiplayerService::SetTransferHandle(\n    _In_ const XblMultiplayerSessionReference& targetSessionReference,\n    _In_ const XblMultiplayerSessionReference& originSessionReference,\n    _In_ AsyncContext<Result<String>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(targetSessionReference.Scid);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(originSessionReference.Scid);\n\n    MultiplayerTransferHandlePostRequest request{ targetSessionReference, originSessionReference };\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", \"/handles\"),\n        xbox_live_api::set_transfer_handle\n    ));\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n    JsonDocument requestJson;\n    request.Serialize(requestJson, requestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(requestJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        if (FAILED(httpResult.Hresult()))\n        {\n            return async.Complete({ httpResult.Hresult(), \"Http call failed\" });\n        }\n\n        auto hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete({ hr, errorMessagePtr });\n        }\n\n        auto result = Serializers::DeserializeMultiplayerInvite(httpResult.Payload()->GetResponseBodyJson());\n        auto multiplayerInvite = result.Payload();\n\n        if (Failed(result))\n        {\n            return async.Complete(result.Hresult());\n        }\n        else\n        {\n            return async.Complete(String{ multiplayerInvite.Data });\n        }\n    }});\n}\n\nHRESULT MultiplayerService::CreateSearchHandle(\n    _In_ MultiplayerSearchHandleRequest searchHandleRequest,\n    _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSearchHandleDetails>>> async\n) const noexcept\n{\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", \"/handles\"),\n        xbox_live_api::set_search_handle\n    ));\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\tJsonDocument searchHandleRequestJson;\n    searchHandleRequest.Serialize(searchHandleRequestJson, searchHandleRequestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(searchHandleRequestJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        if (FAILED(httpResult.Hresult()))\n        {\n            return async.Complete({ httpResult.Hresult(), \"Http call failed\" });\n        }\n\n        auto hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete({ hr, errorMessagePtr });\n        }\n\n        auto result = XblMultiplayerSearchHandleDetails::Deserialize(httpResult.Payload()->GetResponseBodyJson());\n        async.Complete(result);\n    }});\n}\n\nHRESULT MultiplayerService::ClearActivity(\n    _In_ const String& scid,\n    _In_ AsyncContext<Result<void>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(scid.empty());\n\n    return GetActivitiesForUsers(\n        scid, \n        Vector<uint64_t>{ m_user.Xuid() },\n        AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>>{ async.Queue().DeriveWorkerQueue(),\n        [\n            sharedThis{ shared_from_this() },\n            this,\n            async\n        ]\n    (Result<Vector<XblMultiplayerActivityDetails>> result)\n    {\n        if (FAILED(result.Hresult()))\n        {\n            return async.Complete(result.Hresult());\n        }\n\n        auto& activityDetails = result.Payload();\n        size_t responseSize = activityDetails.size();\n\n        Stringstream subPath;\n        if (responseSize == 0)\n        {\n            // There should be at least one activity per user\n            // Don't want to change behavior, but I think we should treat it as a success if there is no\n            // activity to clear.\n            return async.Complete(utils::convert_xbox_live_error_code_to_hresult(xbl_error_code::invalid_argument));\n        }\n        else if (responseSize > 1)\n        {\n            // There should only be one activity per user\n            // Don't want to change behavior, but it seems like this is an unexpected service response, so \n            // we should return E_UNEXPECTED rather than E_INVALIDARG\n            return async.Complete(utils::convert_xbox_live_error_code_to_hresult(xbl_error_code::invalid_argument));\n        }\n        else\n        {\n            subPath << \"/handles/\" << activityDetails.at(0).HandleId;\n        }\n\n        Result<User> userResult = m_user.Copy();\n        if (FAILED(userResult.Hresult()))\n        {\n            return async.Complete(userResult.Hresult());\n        }\n\n        auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n        HRESULT hr = httpCall->Init(\n            m_xboxLiveContextSettings,\n            \"DELETE\",\n            XblHttpCall::BuildUrl(\"sessiondirectory\", subPath.str()),\n            xbox_live_api::clear_activity\n        );\n\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        hr = httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION);\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        hr = httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n            [async](HttpResult httpResult)\n        {\n            if (Failed(httpResult))\n            {\n                async.Complete(httpResult.Hresult());\n            }\n            else\n            {\n                async.Complete(httpResult.Payload()->Result());\n            }\n        }});\n\n        if (FAILED(hr))\n        {\n            async.Complete(hr);\n        }\n    }\n    });\n}\n\nHRESULT MultiplayerService::DeleteSearchHandle(\n    _In_ const String& handleId,\n    _In_ AsyncContext<Result<void>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handleId.empty());\n\n    String handleStr = \"/handles/\" + handleId;\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"DELETE\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", handleStr),\n        xbox_live_api::delete_search_handle\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        if (Failed(httpResult))\n        {\n            async.Complete(httpResult.Hresult());\n        }\n        else\n        {\n            async.Complete(httpResult.Payload()->Result());\n        }\n    }});\n}\n\nHRESULT MultiplayerService::SendInvites(\n    _In_ XblMultiplayerSessionReference sessionReference,\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ uint32_t titleId,\n    _In_ const String& contextStringId,\n    _In_ const String& customActivationContext,\n    _In_ AsyncContext<Result<Vector<String>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(!XblMultiplayerSessionReferenceIsValid(&sessionReference) || xuids.empty());\n\n    // MPSD only allows creating a single invite handle at a time. SendInvitesOperation attempts\n    // to create an invite handle for each invited user. If creation of a single handle fails, the operation\n    // will continue, attempting to create the remaining handles. The result will contain all handles which\n    // were successfully created.\n    struct SendInvitesOperation : public std::enable_shared_from_this<SendInvitesOperation>\n    {\n        SendInvitesOperation(\n            std::shared_ptr<const MultiplayerService> multiplayerService,\n            const XblMultiplayerSessionReference& sessionReference,\n            const Vector<uint64_t>& xuidsToInvite,\n            uint32_t titleId,\n            const String& contextString,\n            const String& customActivationContext,\n            AsyncContext<Result<Vector<String>>> async\n        ) noexcept\n            : m_multiplayerService{ std::move(multiplayerService) },\n            m_requestBody{ sessionReference, 0, titleId, contextString, customActivationContext },\n            m_xuidsToInvite{ xuidsToInvite.rbegin(), xuidsToInvite.rend() },\n            m_async{ std::move(async) }\n        {\n        }\n\n        void Run() noexcept\n        {\n            if (m_xuidsToInvite.empty())\n            {\n                m_async.Complete(m_inviteHandles);\n            }\n            else\n            {\n                auto nextXuid{ m_xuidsToInvite.back() };\n                m_xuidsToInvite.pop_back();\n                HRESULT hr = SendInvite(nextXuid);\n                if (FAILED(hr))\n                {\n                    LOGS_ERROR << __FUNCTION__ << \" Invite failed for user[\" << nextXuid << \"], hr=\" << hr;\n                    LOGS_ERROR << __FUNCTION__ << \" Continuing with remaining invited users.\";\n                    this->Run();\n                }\n            }\n        }\n\n    private:\n        HRESULT SendInvite(uint64_t xuid) noexcept\n        {\n            Result<User> userResult = m_multiplayerService->m_user.Copy();\n            RETURN_HR_IF_FAILED(userResult.Hresult());\n\n            auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n            RETURN_HR_IF_FAILED(httpCall->Init(\n                m_multiplayerService->m_xboxLiveContextSettings,\n                \"POST\",\n                XblHttpCall::BuildUrl(\"sessiondirectory\", \"/handles\"),\n                xbox_live_api::send_invites\n            ));\n\n            RETURN_HR_IF_FAILED(httpCall->SetRetryAllowed(false));\n            RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\n            m_requestBody.SetInvitedXuid(xuid);\n            RETURN_HR_IF_FAILED(httpCall->SetRequestBody(m_requestBody.Json()));\n\n            return httpCall->Perform(AsyncContext<HttpResult>{ m_async.Queue().DeriveWorkerQueue(),\n                [\n                    sharedThis{ shared_from_this() },\n                    this,\n                    xuid\n                ]\n                (HttpResult httpResult)\n                {\n                    auto inviteHandleResult = HandleServiceResult(httpResult);\n                    if (Succeeded(inviteHandleResult))\n                    {\n                        m_inviteHandles.push_back(inviteHandleResult.ExtractPayload());\n                    }\n                    else\n                    {\n                        LOGS_ERROR << __FUNCTION__ << \" Invite failed for user[\" << xuid << \"], hr=\" << inviteHandleResult.Hresult();\n                        LOGS_ERROR << __FUNCTION__ << \" Continuing with remaining invited users.\";\n                    }\n                    Run();\n                }\n            });\n        }\n\n        Result<String> HandleServiceResult(HttpResult httpResult) noexcept\n        {\n            RETURN_HR_IF_FAILED(httpResult.Hresult());\n            RETURN_HR_IF_FAILED(httpResult.Payload()->Result());\n\n            auto deserializationResult = Serializers::DeserializeMultiplayerInvite(httpResult.Payload()->GetResponseBodyJson());\n            return Result<String>{ deserializationResult.Payload().Data, deserializationResult.Hresult() };\n        }\n\n        std::shared_ptr<const MultiplayerService> m_multiplayerService;\n        MultiplayerInviteHandlePostRequest m_requestBody;\n        Vector<uint64_t> m_xuidsToInvite;\n        Vector<String> m_inviteHandles;\n        AsyncContext<Result<Vector<String>>> m_async;\n    };\n\n    auto operation = MakeShared<SendInvitesOperation>(\n        shared_from_this(),\n        sessionReference,\n        xuids,\n        titleId,\n        contextStringId,\n        customActivationContext,\n        std::move(async)\n    );\n\n    operation->Run();\n    return S_OK;\n}\n\nHRESULT MultiplayerService::GetActivitiesForSocialGroup(\n    _In_ const String& scid,\n    _In_ uint64_t socialGroupOwnerXuid,\n    _In_ const String& socialGroup,\n    _In_ AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(scid.empty() || socialGroupOwnerXuid == 0 || socialGroup.empty());\n\n    MultiplayerActivityQueryPostRequest request{ scid, socialGroup, socialGroupOwnerXuid };\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", GET_ACTIIVITIES_SUBPATH),\n        xbox_live_api::get_activities_for_social_group\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\tJsonDocument requestJson;\n    request.Serialize(requestJson, requestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(requestJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        auto hr = httpResult.Hresult();\n        if (FAILED(hr))\n        {\n            return async.Complete({ hr, \"Http call failed\" });\n        }\n\n        hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete({ hr, errorMessagePtr });\n        }\n\n        Vector<XblMultiplayerActivityDetails> activityDetails;\n        hr = JsonUtils::ExtractJsonVector<XblMultiplayerActivityDetails>(\n            Serializers::DeserializeMultiplayerActivityDetails,\n            httpResult.Payload()->GetResponseBodyJson(),\n            \"results\",\n            activityDetails,\n            true\n        );\n\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        async.Complete(activityDetails);\n    }});\n}\n\nHRESULT MultiplayerService::GetActivitiesForUsers(\n    _In_ const String& scid,\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(scid.empty() || xuids.empty());\n\n    MultiplayerActivityQueryPostRequest request{ scid, xuids };\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", GET_ACTIIVITIES_SUBPATH),\n        xbox_live_api::get_activities_for_users\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n    JsonDocument requestJson;\n    request.Serialize(requestJson, requestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(requestJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        if (FAILED(httpResult.Hresult()))\n        {\n            return async.Complete({ httpResult.Hresult(), \"Http call failed\" });\n        }\n\n        auto hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete({ hr, errorMessagePtr });\n        }\n\n        Vector<XblMultiplayerActivityDetails> activityDetails;\n        hr = JsonUtils::ExtractJsonVector<XblMultiplayerActivityDetails>(\n            Serializers::DeserializeMultiplayerActivityDetails,\n            httpResult.Payload()->GetResponseBodyJson(),\n            \"results\",\n            activityDetails,\n            true\n        );\n\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        async.Complete(activityDetails);\n    }});\n}\n\nHRESULT MultiplayerService::GetSearchHandles(\n    _In_ const MultiplayerQuerySearchHandleRequest& searchHandleRequest,\n    _In_ AsyncContext<Result<Vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(searchHandleRequest.Scid().empty() || searchHandleRequest.SessionTemplateName().empty());\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", GET_SEARCH_HANDLES_SUBPATH),\n        xbox_live_api::get_search_handles\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\tJsonDocument searchHandleRequestJson;\n    searchHandleRequest.Serialize(m_user.Xuid(), searchHandleRequestJson, searchHandleRequestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(searchHandleRequestJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n        [async](HttpResult httpResult)\n    {\n        if (FAILED(httpResult.Hresult()))\n        {\n            return async.Complete({ httpResult.Hresult(), \"Http call failed\" });\n        }\n\n        auto hr = httpResult.Payload()->Result();\n        if (FAILED(hr))\n        {\n            const char* errorMessagePtr{};\n            std::unique_ptr<const char> errorMessage{ errorMessagePtr };\n            httpResult.Payload()->GetErrorMessage(&errorMessagePtr);\n            return async.Complete({ hr, errorMessagePtr });\n        }\n\n        Vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>> searchHandleDetails;\n        hr = JsonUtils::ExtractJsonVector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>(\n            XblMultiplayerSearchHandleDetails::Deserialize,\n            httpResult.Payload()->GetResponseBodyJson(),\n            \"results\",\n            searchHandleDetails,\n            true\n            );\n\n        async.Complete(Result<Vector<std::shared_ptr<XblMultiplayerSearchHandleDetails>>>{ searchHandleDetails, hr });\n    }});\n}\n\nHRESULT MultiplayerService::WriteSessionUsingSubpath(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ XblMultiplayerSessionWriteMode mode,\n    _In_ const String& subpathAndQuery,\n    _In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(subpathAndQuery.empty());\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"PUT\",\n        XblHttpCall::BuildUrl(\"sessiondirectory\", subpathAndQuery),\n        xbox_live_api::write_session_using_subpath\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetRetryAllowed(false));\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));\n\n    switch (mode)\n    {\n    case XblMultiplayerSessionWriteMode::CreateNew:\n    {\n        RETURN_HR_IF_FAILED(httpCall->SetHeader(\"If-None-Match\", \"*\"));\n        break;\n    }\n    case XblMultiplayerSessionWriteMode::UpdateExisting:\n    {\n        RETURN_HR_IF_FAILED(httpCall->SetHeader(\"If-Match\", \"*\"));\n        break;\n    }\n    case XblMultiplayerSessionWriteMode::UpdateOrCreateNew:\n    {\n        // No match header\n        break;\n    }\n    case XblMultiplayerSessionWriteMode::SynchronizedUpdate:\n    {\n        if (session->ETag().empty())\n        {\n            RETURN_HR_IF_FAILED(httpCall->SetHeader(\"If-None-Match\", \"*\"));\n        }\n        else\n        {\n            RETURN_HR_IF_FAILED(httpCall->SetHeader(\"If-Match\", session->ETag()));\n        }\n        break;\n    }\n    default:\n    {\n        return E_INVALIDARG;\n    }\n    }\n\n    // Set the ConnectionId for the session\n    TaskQueue derivedQueue{ async.Queue().DeriveWorkerQueue() };\n\n    return SetRtaConnectionId(session, AsyncContext<Result<void>>{ derivedQueue,\n        [\n            httpCall,\n            xuid{ m_user.Xuid() },\n            sessionReference{ session->SessionReference() },\n            session,\n            async{ std::move(async) }\n        ]\n    (Result<void> setConnectionIdResult)\n    {\n        if (Failed(setConnectionIdResult))\n        {\n            return async.Complete({ setConnectionIdResult.Hresult(), \"Failed to establish MPSD RTA subscription\" });\n        }\n\n        JsonDocument requestBody{ rapidjson::kObjectType };\n        session->Serialize(requestBody, requestBody.GetAllocator());\n\n        HRESULT hr = httpCall->SetRequestBody(requestBody);\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        hr = httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n            [\n                xuid,\n                sessionReference,\n                async\n            ]\n        (HttpResult httpResult)\n        {\n            HRESULT hr = httpResult.Hresult();\n            if (FAILED(hr))\n            {\n                return async.Complete({ hr, \"Http call failed\" });\n            }\n\n            hr = httpResult.Payload()->Result();\n            auto statusCode = httpResult.Payload()->HttpStatus();\n            if (FAILED(hr) && statusCode != 412)\n            {\n                return async.Complete(hr);\n            }\n            else if (statusCode == 204)\n            {\n                // Consistent with XDK behavior, return success on 204 when writing session\n                return async.Complete(S_OK);\n            }\n\n            auto responseJson = httpResult.Payload()->GetResponseBodyJson();\n            if (responseJson.IsNull())\n            {\n                return async.Complete(hr);\n            }\n\n            XblMultiplayerSessionReference localSessionRef;\n            if (sessionReference.Scid[0] == 0)\n            {\n                auto contentLocation = httpResult.Payload()->GetResponseHeader(\"Content-Location\");\n\n                hr = XblMultiplayerSessionReferenceParseFromUriPath(contentLocation.c_str(), &localSessionRef);\n                if (FAILED(hr))\n                {\n                    return async.Complete({ E_FAIL, \"Failed to parse session reference from URI\" });\n                }\n            }\n            else\n            {\n                localSessionRef = sessionReference;\n            }\n\n            auto session = MakeShared<XblMultiplayerSession>(\n                xuid,\n                localSessionRef,\n                httpResult.Payload()->GetResponseHeader(ETAG_HEADER),\n                httpResult.Payload()->GetResponseHeader(DATE_HEADER),\n                httpResult.Payload()->GetResponseBodyJson()\n                );\n\n            if (FAILED(session->DeserializationError()) && SUCCEEDED(hr))\n            {\n                // WriteSession failed due to deserialization error\n                hr = session->DeserializationError();\n            }\n\n            session->SetWriteSessionStatus(\n                statusCode\n            );\n\n            return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(session, hr));\n        }});\n\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n    }\n    });\n}\n\nHRESULT MultiplayerService::SetRtaConnectionId(\n    _In_ std::shared_ptr<XblMultiplayerSession> session,\n    _In_ AsyncContext<Result<void>> async\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n    XblMultiplayerSessionReadLockGuard sessionSafe(session);\n    if (!m_subscription || !sessionSafe.CurrentUserInternal())\n    {\n        // If we don't have an active subscription or the current user is not in the session do nothing\n        async.Complete(S_OK);\n    }\n    else if (!m_subscription->RtaConnectionId().empty())\n    {\n        // If we already have a connectionId add it\n        sessionSafe.CurrentUserInternal()->SetRtaConnectionId(m_subscription->RtaConnectionId());\n        async.Complete(S_OK);\n    }\n    else\n    {\n        // Wait for subscription to be finalized and add connectionId then\n        m_sessionsAwaitingConnectionId.emplace_back(session, std::move(async));\n    }\n    return S_OK;\n}\n\nHRESULT MultiplayerService::SubscribeToRta(std::unique_lock<std::mutex> lock) noexcept\n{\n    if (m_subscription == nullptr)\n    {\n        m_subscription = MakeShared<MultiplayerSubscription>();\n\n        m_subscription->AddConnectionIdChangedHandler(\n            [\n                weakThis = std::weak_ptr<MultiplayerService>{ shared_from_this() }\n            ]\n        (const String& connectionId)\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                std::unique_lock<std::mutex> lock{ sharedThis->m_mutexMultiplayerService };\n                for (auto& pair : sharedThis->m_sessionsAwaitingConnectionId)\n                {\n                    // Make sure the current user is still in the session\n                    XblMultiplayerSessionReadLockGuard pairSafe(pair.first);\n                    if (pairSafe.CurrentUserInternal())\n                    {\n                        pairSafe.CurrentUserInternal()->SetRtaConnectionId(connectionId);\n                    }\n                    pair.second.Complete(S_OK);\n                }\n                sharedThis->m_sessionsAwaitingConnectionId.clear();\n\n                // Invoke client connectionId changed handlers as well\n                auto clientHandlers{ sharedThis->m_connectionIdChangedHandlers };\n                lock.unlock();\n\n                for (auto& handler : clientHandlers)\n                {\n                    handler.second(connectionId);\n                }\n            }\n        });\n\n        // To support title subscription lost events, add an RTA connection state changed handler\n        m_rtaConnectionStateChangedToken = m_rtaManager->AddStateChangedHandler(m_user, \n            [\n                weakThis = std::weak_ptr<MultiplayerService>{ shared_from_this() }\n            ]\n        (XblRealTimeActivityConnectionState state)\n        {\n            auto sharedThis{ weakThis.lock() };\n            if (state == XblRealTimeActivityConnectionState::Disconnected && sharedThis)\n            {\n                std::unique_lock<std::mutex> lock{ sharedThis->m_mutexMultiplayerService };\n                auto handlers{ sharedThis->m_subscriptionLostHandlers };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second();\n                }\n\n                // If there were sessions awaiting a connectionId, complete those AsyncContexts\n                for (auto& pair : sharedThis->m_sessionsAwaitingConnectionId)\n                {\n                    pair.second.Complete(S_OK);\n                }\n                sharedThis->m_sessionsAwaitingConnectionId.clear();\n            }\n        });\n\n        // Unlock before adding subscription as it can synchronously call back into our ConnectionIdChanged handler\n        lock.unlock();\n        return m_rtaManager->AddSubscription(m_user, m_subscription);\n    }\n    return S_OK;\n}\n\nHRESULT MultiplayerService::UnsubscribeFromRta() noexcept\n{\n    if (m_subscription != nullptr)\n    {\n        m_rtaManager->RemoveStateChangedHandler(m_user, m_rtaConnectionStateChangedToken);\n        m_rtaManager->RemoveSubscription(m_user, m_subscription);\n        m_subscription.reset();\n\n        // If there were sessions awaiting a connectionId, complete those AsyncContexts\n        for (auto& pair : m_sessionsAwaitingConnectionId)\n        {\n            pair.second.Complete(S_OK);\n        }\n        m_sessionsAwaitingConnectionId.clear();\n    }\n    return S_OK;\n}\n\nHRESULT MultiplayerService::EnableMultiplayerSubscriptions() noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutexMultiplayerService };\n    m_forceEnableRtaSubscription = true;\n    return SubscribeToRta(std::move(lock));\n}\n\nHRESULT MultiplayerService::DisableMultiplayerSubscriptions() noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutexMultiplayerService };\n    m_forceEnableRtaSubscription = false;\n    HRESULT hr = UnsubscribeFromRta();\n\n    // Maintain existing behavior and invoke subscription lost handler here\n    auto handlers{ m_subscriptionLostHandlers };\n    lock.unlock();\n\n    for (auto& handler : handlers)\n    {\n        handler.second();\n    }\n\n    return hr;\n}\n\nbool MultiplayerService::SubscriptionsEnabled() noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n    return m_subscription != nullptr;\n}\n\nXblFunctionContext MultiplayerService::AddMultiplayerSessionChangedHandler(\n    _In_ MultiplayerSubscription::SessionChangedHandler handler\n) noexcept\n{\n    {\n        std::unique_lock<std::mutex> lock{ m_mutexMultiplayerService };\n        SubscribeToRta(std::move(lock));\n    }\n\n    XblFunctionContext token{};\n    {\n        std::unique_lock<std::mutex> lock{ m_mutexMultiplayerService };\n        if (m_subscription)\n        {\n            token = m_subscription->AddSessionChangedHandler(std::move(handler));\n        }\n    }\n\n    return token;\n}\n\nvoid MultiplayerService::RemoveMultiplayerSessionChangedHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n\n    if (m_subscription)\n    {\n        size_t remainingHandlers = m_subscription->RemoveSessionChangedHandler(token);\n        // If that was the last handler and the title hasn't force enabled the RTA subscription then unsubscribe\n        if (!remainingHandlers && !m_forceEnableRtaSubscription)\n        {\n            UnsubscribeFromRta();\n        }\n    }\n}\n\nXblFunctionContext MultiplayerService::AddMultiplayerSubscriptionLostHandler(\n    _In_ SubscriptionLostHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n    m_subscriptionLostHandlers[m_nextClientToken] = std::move(handler);\n    return m_nextClientToken++;\n}\n\nvoid MultiplayerService::RemoveMultiplayerSubscriptionLostHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n    m_subscriptionLostHandlers.erase(token);\n}\n\nXblFunctionContext MultiplayerService::AddMultiplayerConnectionIdChangedHandler(\n    _In_ MultiplayerSubscription::ConnectionIdChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n\n    // For legacy reasons, allow adding a connectionId changed handler even if subscriptions are not enabled\n    m_connectionIdChangedHandlers[m_nextClientToken] = std::move(handler);\n    return m_nextClientToken++;\n}\n\nvoid MultiplayerService::RemoveMultiplayerConnectionIdChangedHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerService };\n    m_connectionIdChangedHandlers.erase(token);\n}\n\n\nString MultiplayerService::MultiplayerSessionDirectoryCreateOrUpdateSubpath(\n    _In_ const String& serviceConfigurationId,\n    _In_ const String& sessionTemplateName,\n    _In_ const String& sessionName\n) noexcept\n{\n    Stringstream source;\n    source << \"/serviceconfigs/\";\n    source << serviceConfigurationId;\n    source << \"/sessionTemplates/\";\n    source << sessionTemplateName;\n    source << \"/sessions/\";\n    source << sessionName;\n    return source.str();\n}\n\nString MultiplayerService::MultiplayerSessionDirectoryCreateOrUpdateByHandleSubpath(\n    _In_ const String& handleId\n) noexcept\n{\n    Stringstream source;\n    source << \"/handles/\";\n    source << handleId;\n    source << \"/session\";\n\n    return source.str();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END\n\nSTDAPI MultiplayerWriteSessionHelper(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblMultiplayerSessionHandle multiplayerSession,\n    _In_ XblMultiplayerSessionWriteMode writeMode,\n    _In_opt_ const char* handleIdArg,\n    _Inout_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || multiplayerSession == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            inputSession{ multiplayerSession->shared_from_this() },\n            writeMode,\n            handleId{ String{handleIdArg ? handleIdArg : \"\"} },\n            outputSession{ std::shared_ptr<XblMultiplayerSession>() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async{ data->async->queue,\n                [\n                    &outputSession,\n                    async{ data->async }\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> result)\n            {\n                outputSession = result.ExtractPayload();\n                auto hr = result.Hresult();\n\n                // Still must return latest session to allow retries\n                if (hr == HTTP_E_STATUS_PRECOND_FAILED)\n                {\n                    hr = S_OK;\n                }\n\n                XAsyncComplete(async, hr, sizeof(XblMultiplayerSessionHandle));\n            }\n            };\n\n            if (handleId.empty())\n            {\n                RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->WriteSession(\n                    inputSession,\n                    writeMode,\n                    std::move(async)\n                ));\n            }\n            else\n            {\n                RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->WriteSessionByHandle(\n                    inputSession,\n                    writeMode,\n                    handleId,\n                    std::move(async)\n                ));\n            }\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto handlePtr = static_cast<XblMultiplayerSessionHandle*>(data->buffer);\n            if (outputSession)\n            {\n                outputSession->AddRef();\n                *handlePtr = outputSession.get();\n            }\n            else\n            {\n                *handlePtr = nullptr;\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerWriteSessionAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionHandle multiplayerSession,\n    _In_ XblMultiplayerSessionWriteMode writeMode,\n    _Inout_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(multiplayerSession);\n\n    if (!XblMultiplayerSessionReferenceIsValid(&multiplayerSession->SessionReference()))\n    {\n        LOGS_DEBUG << \"XblMultiplayerWriteSessionAsync cannot be called on a session without a valid session reference\";\n        return E_XBL_RUNTIME_ERROR;\n    }\n\n    return MultiplayerWriteSessionHelper(xblContext, multiplayerSession, writeMode, nullptr, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerWriteSessionResult(\n    _Inout_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    XblMultiplayerSessionHandle handleCopy = nullptr;\n    auto hr = XAsyncGetResult(async, nullptr, sizeof(XblMultiplayerSessionHandle), &handleCopy, nullptr);\n    if (handle != nullptr)\n    {\n        *handle = handleCopy;\n    }\n    else\n    {\n        XblMultiplayerSessionCloseHandle(handleCopy);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerWriteSessionByHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionHandle multiplayerSession,\n    _In_ XblMultiplayerSessionWriteMode writeMode,\n    _In_ const char* handleId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(handleId);\n\n    return MultiplayerWriteSessionHelper(xblContext, multiplayerSession, writeMode, handleId, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerWriteSessionByHandleResult(\n    _Inout_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    return XblMultiplayerWriteSessionResult(async, handle);\n}\nCATCH_RETURN()\n\nSTDAPI MultiplayerGetSessionHelper(\n    _In_ XblContextHandle xblContextHandle,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReferenceArg,\n    _In_opt_ const char* handleIdArg,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            sessionReference = sessionReferenceArg ? XblMultiplayerSessionReference{ *sessionReferenceArg } : XblMultiplayerSessionReference{},\n            handleId = handleIdArg ? String{ handleIdArg } : String{},\n            session = std::shared_ptr<XblMultiplayerSession>{ nullptr }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async{ data->async->queue,\n                [\n                    &session,\n                    async{ data->async }\n                ]\n            (Result<std::shared_ptr<XblMultiplayerSession>> result)\n            {\n                session = result.ExtractPayload();\n                XAsyncComplete(async, result.Hresult(), sizeof(XblMultiplayerSessionHandle));\n            }\n            };\n\n            if (handleId.empty())\n            {\n                RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetCurrentSession(sessionReference, std::move(async)));\n            }\n            else\n            {\n                RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetCurrentSessionByHandle(handleId, std::move(async)));\n            }\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto handlePtr = static_cast<XblMultiplayerSessionHandle*>(data->buffer);\n            if (session)\n            {\n                session->AddRef();\n                *handlePtr = session.get();\n            }\n            else\n            {\n                *handlePtr = nullptr;\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSessionAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(sessionReference);\n    return MultiplayerGetSessionHelper(xblContext, sessionReference, nullptr, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSessionResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblMultiplayerSessionHandle), handle, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSessionByHandleAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ const char* handleId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(handleId);\n    return MultiplayerGetSessionHelper(xblContext, nullptr, handleId, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetSessionByHandleResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblMultiplayerSessionHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblMultiplayerSessionHandle), handle, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerQuerySessionsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const XblMultiplayerSessionQuery* sessionQuery,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || sessionQuery == nullptr || async == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(sessionQuery->Scid);\n    RETURN_HR_INVALIDARGUMENT_IF((sessionQuery->XuidFilters == nullptr || sessionQuery->XuidFiltersCount == 0) &&\n        (sessionQuery->KeywordFilter == nullptr || sessionQuery->KeywordFilter[0] == 0));\n    RETURN_HR_INVALIDARGUMENT_IF(sessionQuery->IncludeReservations && (sessionQuery->XuidFilters == nullptr || sessionQuery->XuidFiltersCount == 0));\n    RETURN_HR_INVALIDARGUMENT_IF(sessionQuery->IncludeInactiveSessions && (sessionQuery->XuidFilters == nullptr || sessionQuery->XuidFiltersCount == 0));\n    RETURN_HR_INVALIDARGUMENT_IF(sessionQuery->VisibilityFilter == XblMultiplayerSessionVisibility::Unknown);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            query = SessionQuery{ sessionQuery },\n            sessions = Vector<XblMultiplayerSessionQueryResult>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetSessions(\n                query,\n                AsyncContext<Result<Vector<XblMultiplayerSessionQueryResult>>>{ data->async->queue,\n                [\n                    &sessions,\n                    async{ data->async }\n                ]\n            (Result<Vector<XblMultiplayerSessionQueryResult>> result)\n            {\n                sessions = result.ExtractPayload();\n                XAsyncComplete(async, result.Hresult(), sizeof(XblMultiplayerSessionQueryResult) * sessions.size());\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            memcpy(data->buffer, sessions.data(), data->bufferSize);\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerQuerySessionsResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* sessionCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || sessionCount == nullptr);\n\n    size_t sizeInBytes;\n    auto hr = XAsyncGetResultSize(async, &sizeInBytes);\n    *sessionCount = sizeInBytes / sizeof(XblMultiplayerSessionQueryResult);\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerQuerySessionsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t sessionCount,\n    _Out_writes_(sessionCount) XblMultiplayerSessionQueryResult* sessions\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(sessionCount == 0, S_OK);\n    return XAsyncGetResult(async, nullptr, sessionCount * sizeof(XblMultiplayerSessionQueryResult), sessions, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSetActivityAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const XblMultiplayerSessionReference* sessionReferenceArg,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || sessionReferenceArg == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            sessionReference{ *sessionReferenceArg }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->SetActivity(sessionReference, data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerClearActivityAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_z_ const char* scidArg,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || scidArg == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            scid = String{ scidArg }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->ClearActivity(scid, data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSendInvitesAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_ uint32_t titleId,\n    _In_opt_z_ const char* contextStringId,\n    _In_opt_z_ const char* customActivationContext,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || sessionReference == nullptr || xuids == nullptr || xuidsCount == 0 || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            sessionRef{ *sessionReference },\n            xuidsVector{ Vector<uint64_t>(xuids, xuids + xuidsCount) },\n            titleId,\n            contextString{ String{ contextStringId ? contextStringId : \"\" } },\n            activiationContext{ String{customActivationContext ? customActivationContext : \"\"} },\n            inviteHandles{ Vector<String>() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->SendInvites(\n                sessionRef,\n                xuidsVector,\n                titleId,\n                contextString,\n                activiationContext,\n                AsyncContext<Result<Vector<String>>>{ data->async->queue,\n                [\n                    &inviteHandles,\n                    async{ data->async }\n                ]\n            (Result<Vector<String>> result)\n            {\n                if (Succeeded(result))\n                {\n                    inviteHandles = result.ExtractPayload();\n                }\n                XAsyncComplete(async, result.Hresult(), sizeof(XblMultiplayerInviteHandle) * inviteHandles.size());\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto handlesArray = static_cast<XblMultiplayerInviteHandle*>(data->buffer);\n            for (uint32_t i = 0; i < inviteHandles.size(); ++i)\n            {\n                utils::strcpy(handlesArray[i].Data, sizeof(handlesArray[i].Data), inviteHandles[i].data());\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSendInvitesResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t handlesCount,\n    _Out_writes_(handlesCount) XblMultiplayerInviteHandle* handles\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(handlesCount == 0, S_OK);\n    return XAsyncGetResult(async, nullptr, sizeof(XblMultiplayerInviteHandle) * handlesCount, handles, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesForSocialGroupAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const char* scidArg,\n    _In_ uint64_t socialGroupOwnerXuid,\n    _In_ const char* socialGroupArg,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || scidArg == nullptr || socialGroupOwnerXuid == 0 || socialGroupArg == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            scid = String{ scidArg },\n            socialGroupOwnerXuid,\n            socialGroup = String{ socialGroupArg },\n            activityDetails = Vector<XblMultiplayerActivityDetails>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetActivitiesForSocialGroup(\n                scid,\n                socialGroupOwnerXuid,\n                socialGroup,\n                AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>>{ data->async->queue,\n                [\n                    &activityDetails,\n                    async{ data->async }\n                ]\n            (Result<Vector<XblMultiplayerActivityDetails>> result)\n            {\n                activityDetails = result.ExtractPayload();\n                XAsyncComplete(async, result.Hresult(), sizeof(XblMultiplayerActivityDetails) * activityDetails.size());\n            }\n            }));\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            for (auto& activity : activityDetails)\n            {\n                Delete(activity.CustomSessionPropertiesJson);\n                activity.CustomSessionPropertiesJson = nullptr;\n            }\n\n            memcpy(data->buffer, activityDetails.data(), data->bufferSize);\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const char* scidArg,\n    _In_ uint64_t socialGroupOwnerXuid,\n    _In_ const char* socialGroupArg,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || scidArg == nullptr || socialGroupOwnerXuid == 0 || socialGroupArg == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            scid = String{ scidArg },\n            socialGroupOwnerXuid,\n            socialGroup = String{ socialGroupArg },\n            activityDetails = Vector<XblMultiplayerActivityDetails>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetActivitiesForSocialGroup(\n                scid,\n                socialGroupOwnerXuid,\n                socialGroup,\n                AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>>{ data->async->queue,\n                [\n                    &activityDetails,\n                    async{ data->async }\n                ]\n            (Result<Vector<XblMultiplayerActivityDetails>> result)\n            {\n                activityDetails = result.ExtractPayload();\n                auto hr = result.Hresult();\n\n                size_t jsonSize{};\n                for (auto& activity : activityDetails)\n                {\n                    jsonSize += strlen(activity.CustomSessionPropertiesJson) + 1;\n                }\n\n                size_t bufferSize = jsonSize + sizeof(XblMultiplayerActivityDetails) * activityDetails.size();\n                bufferSize = static_cast<size_t>((bufferSize + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n                XAsyncComplete(async, hr, bufferSize);\n            }\n            }));\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto activityPtr = reinterpret_cast<XblMultiplayerActivityDetails*>(data->buffer);\n            auto jsonPtr = reinterpret_cast<char*>(data->buffer) + sizeof(XblMultiplayerActivityDetails) * activityDetails.size();\n\n            for (auto& activity : activityDetails)\n            {\n                size_t len = strlen(activity.CustomSessionPropertiesJson) + 1;\n\n                *activityPtr = activity;\n                utils::strcpy(jsonPtr, len, activity.CustomSessionPropertiesJson);\n                activityPtr->CustomSessionPropertiesJson = jsonPtr;\n                Delete(activity.CustomSessionPropertiesJson);\n\n                jsonPtr += len;\n                ++activityPtr;\n            }\n\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesForSocialGroupResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* activityCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(activityCount);\n\n    size_t sizeInBytes;\n    auto hr = XAsyncGetResultSize(async, &sizeInBytes);\n    *activityCount = sizeInBytes / sizeof(XblMultiplayerActivityDetails);\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t activityCount,\n    _Out_writes_(activityCount) XblMultiplayerActivityDetails* activities\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(activityCount == 0, S_OK);\n    return XAsyncGetResult(async, nullptr, activityCount * sizeof(XblMultiplayerActivityDetails), activities, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(resultSizeInBytes);\n\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMultiplayerActivityDetails** ptrToBuffer,\n    _Out_ size_t* ptrToBufferCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(buffer == nullptr || ptrToBuffer == nullptr || ptrToBufferCount == nullptr);\n\n    size_t bufferUsedTemp{};\n    if (bufferUsed == nullptr)\n    {\n        bufferUsed = &bufferUsedTemp;\n    }\n\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    \n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblMultiplayerActivityDetails*>(buffer);\n\n        size_t count{ 0 };\n        size_t verifiedSize{ 0 };\n        for (; *bufferUsed > 0 && verifiedSize < *bufferUsed - XBL_ALIGN_SIZE; ++count)\n        {\n            verifiedSize += sizeof(XblMultiplayerActivityDetails);\n            verifiedSize += strlen((*ptrToBuffer)[count].CustomSessionPropertiesJson) + 1;\n        }\n        verifiedSize = static_cast<size_t>((verifiedSize + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n        assert(verifiedSize == *bufferUsed);\n        *ptrToBufferCount = count;\n    }\n\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesForUsersAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const char* scidArg,\n    _In_reads_(xuidsCount) const uint64_t* xuidsArg,\n    _In_ size_t xuidsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || scidArg == nullptr || xuidsArg == nullptr || xuidsCount == 0 || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            scid = String{ scidArg },\n            xuids = Vector<uint64_t>(xuidsArg, xuidsArg + xuidsCount),\n            activityDetails = Vector<XblMultiplayerActivityDetails>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetActivitiesForUsers(\n                scid,\n                xuids,\n                AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>>{ data->async->queue,\n                [\n                    &activityDetails,\n                    async{ data->async }\n                ]\n            (Result<Vector<XblMultiplayerActivityDetails>> result)\n            {\n                activityDetails = result.ExtractPayload();\n                XAsyncComplete(async, result.Hresult(), sizeof(XblMultiplayerActivityDetails) * activityDetails.size());\n            }\n            }));\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            for (auto& activity : activityDetails)\n            {\n                Delete(activity.CustomSessionPropertiesJson);\n                activity.CustomSessionPropertiesJson = nullptr;\n            }\n\n            memcpy(data->buffer, activityDetails.data(), data->bufferSize);\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const char* scidArg,\n    _In_reads_(xuidsCount) const uint64_t* xuidsArg,\n    _In_ size_t xuidsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || scidArg == nullptr || xuidsArg == nullptr || xuidsCount == 0 || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            scid = String{ scidArg },\n            xuids = Vector<uint64_t>(xuidsArg, xuidsArg + xuidsCount),\n            activityDetails = Vector<XblMultiplayerActivityDetails>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerService()->GetActivitiesForUsers(\n                scid,\n                xuids,\n                AsyncContext<Result<Vector<XblMultiplayerActivityDetails>>>{ data->async->queue,\n                [\n                    &activityDetails,\n                    async{ data->async }\n                ]\n            (Result<Vector<XblMultiplayerActivityDetails>> result)\n            {\n                activityDetails = result.ExtractPayload();\n                auto hr = result.Hresult();\n\n                size_t jsonSize{};\n                for (auto& activity : activityDetails)\n                {\n                    jsonSize += strlen(activity.CustomSessionPropertiesJson) + 1;\n                }\n\n                size_t bufferSize = jsonSize + sizeof(XblMultiplayerActivityDetails) * activityDetails.size();\n                bufferSize = static_cast<size_t>((bufferSize + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n                XAsyncComplete(async, hr, bufferSize);\n            }\n            }));\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto activityPtr = reinterpret_cast<XblMultiplayerActivityDetails*>(data->buffer);\n            auto jsonPtr = reinterpret_cast<char*>(data->buffer) + sizeof(XblMultiplayerActivityDetails) * activityDetails.size();\n\n            for (auto& activity : activityDetails)\n            {\n                size_t len = strlen(activity.CustomSessionPropertiesJson) + 1;\n\n                *activityPtr = activity;\n                utils::strcpy(jsonPtr, len, activity.CustomSessionPropertiesJson);\n                activityPtr->CustomSessionPropertiesJson = jsonPtr;\n                Delete(activity.CustomSessionPropertiesJson);\n\n                jsonPtr += len;\n                ++activityPtr;\n            }\n\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesForUsersResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* activityCount\n) XBL_NOEXCEPT\ntry\n{\n    return XblMultiplayerGetActivitiesForSocialGroupResultCount(async, activityCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesForUsersResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t activityCount,\n    _Out_writes_(activityCount) XblMultiplayerActivityDetails* activities\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, activityCount * sizeof(XblMultiplayerActivityDetails), activities, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerGetActivitiesWithPropertiesForUsersResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMultiplayerActivityDetails** ptrToBuffer,\n    _Out_ size_t* ptrToBufferCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    return XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult(async, bufferSize, buffer, ptrToBuffer, ptrToBufferCount, bufferUsed);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSetSubscriptionsEnabled(\n    _In_ XblContextHandle xblContext,\n    _In_ bool subscriptionsEnabled\n) XBL_NOEXCEPT\ntry\n{\n    if (subscriptionsEnabled)\n    {\n        return xblContext->MultiplayerService()->EnableMultiplayerSubscriptions();\n    }\n    else\n    {\n        return xblContext->MultiplayerService()->DisableMultiplayerSubscriptions();\n    }\n}\nCATCH_RETURN()\n\nSTDAPI_(bool) XblMultiplayerSubscriptionsEnabled(\n    _In_ XblContextHandle xblContext\n) XBL_NOEXCEPT\ntry\n{\n    return xblContext->MultiplayerService()->SubscriptionsEnabled();\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblMultiplayerAddSessionChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return xblContext->MultiplayerService()->AddMultiplayerSessionChangedHandler(\n        [\n            handler,\n            context\n        ]\n    (const XblMultiplayerSessionChangeEventArgs& args)\n    {\n        try \n        {\n            handler(context, args);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerRemoveSessionChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    xblContext->MultiplayerService()->RemoveMultiplayerSessionChangedHandler(token);\n}\nCATCH_RETURN_WITH(;)\n\n\nSTDAPI_(XblFunctionContext) XblMultiplayerAddSubscriptionLostHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerSessionSubscriptionLostHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return xblContext->MultiplayerService()->AddMultiplayerSubscriptionLostHandler(\n        [\n            handler,\n            context\n        ]\n    {\n        try\n        {\n            handler(context);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerRemoveSubscriptionLostHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    xblContext->MultiplayerService()->RemoveMultiplayerSubscriptionLostHandler(token);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(XblFunctionContext) XblMultiplayerAddConnectionIdChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerConnectionIdChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    return xblContext->MultiplayerService()->AddMultiplayerConnectionIdChangedHandler(\n        [\n            handler,\n            context\n        ]\n    (const String&)\n    {\n        try\n        {\n            handler(context);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerRemoveConnectionIdChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    xblContext->MultiplayerService()->RemoveMultiplayerConnectionIdChangedHandler(token);\n}\nCATCH_RETURN_WITH(;)\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_session.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::legacy;\nusing namespace xbox::services::multiplayer;\n\n#define MULTIPLAYER_SESSION_VERSION 1\n\nXblMultiplayerSession::XblMultiplayerSession(\n    _In_ uint64_t xuid,\n    _In_ XblMultiplayerSessionReference sessionReference,\n    _In_ const xsapi_internal_string& eTag,\n    _In_ const xsapi_internal_string& responseDate,\n    _In_ const JsonValue& json\n) :\n    m_xuid(xuid),\n    m_eTag(eTag),\n    m_sessionRetrievedTime(),\n    m_info(),\n    m_sessionReference(sessionReference),\n    m_sessionConstants{},\n    m_memberInitialization(),\n    m_sessionProperties(),\n    m_memberCurrentUser(nullptr),\n    m_membersAccepted(0),\n    m_writeSessionStatus(),\n    m_joiningSession(false),\n    m_newSession(false),\n    m_deserializationError(),\n    m_writePropertiesKeywords(false),\n    m_writePropertiesTurns(false),\n    m_writeInitializationStatus(false),\n    m_initializationSucceeded(false),\n    m_writeHostDeviceToken(false),\n    m_writeMatchmakingServerConnectionPath(false),\n    m_writeMatchmakingResubmit(false),\n    m_writeServerConnectionStringCandidates(false),\n    m_leaveSession(false),\n    m_writeClosed(false),\n    m_writeLocked(false),\n    m_writeAllocateCloudCompute(false),\n    m_writeRoleTypes(false),\n    m_writeTimeouts(false),\n    m_writeQosConnectivityMetrics(false),\n    m_writeMemberInitialization(false),\n    m_writePeerToPeerRequirements(false),\n    m_writePeerToHostRequirements(false),\n    m_writeMeasurementServerAddresses(false),\n    m_writeJoinRestriction(false),\n    m_writeReadRestriction(false),\n    m_writeServersJson(false),\n    m_writeMatchmakingTargetSessionConstants(false),\n    m_writeSessionCustomPropertiesJson(false),\n    m_writeConstants(false),\n    m_memberRequestIndex(0)\n{\n    auto sessionDatetime = xbox::services::datetime::from_string(responseDate, xbox::services::datetime::date_format::RFC_1123);\n    m_sessionRetrievedTime = utils::time_t_from_datetime(sessionDatetime);\n    Initialize();\n    Deserialize(json);\n}\n\nXblMultiplayerSession::XblMultiplayerSession(\n    _In_ uint64_t xuid,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n    _In_opt_ const XblMultiplayerSessionInitArgs* initArgs\n) :\n    m_xuid(xuid),\n    m_sessionReference{},\n    m_sessionConstants{},\n    m_memberCurrentUser(nullptr),\n    m_membersAccepted(0),\n    m_joiningSession(false),\n    m_newSession(true),\n    m_writePropertiesKeywords(false),\n    m_writePropertiesTurns(false),\n    m_writeInitializationStatus(false),\n    m_initializationSucceeded(false),\n    m_writeHostDeviceToken(false),\n    m_writeMatchmakingServerConnectionPath(false),\n    m_writeMatchmakingResubmit(false),\n    m_writeServerConnectionStringCandidates(false),\n    m_leaveSession(false),\n    m_writeClosed(false),\n    m_writeLocked(false),\n    m_writeAllocateCloudCompute(false),\n    m_writeRoleTypes(false),\n    m_writeTimeouts(false),\n    m_writeQosConnectivityMetrics(false),\n    m_writeMemberInitialization(false),\n    m_writePeerToPeerRequirements(false),\n    m_writePeerToHostRequirements(false),\n    m_writeMeasurementServerAddresses(false),\n    m_writeJoinRestriction(false),\n    m_writeReadRestriction(false),\n    m_writeServersJson(false),\n    m_writeMatchmakingTargetSessionConstants(false),\n    m_writeSessionCustomPropertiesJson(false),\n    m_writeConstants(false),\n    m_memberRequestIndex(0)\n{\n    if (sessionReference != nullptr)\n    {\n        m_sessionReference = *sessionReference;\n    }\n    Initialize();\n    if (initArgs != nullptr)\n    {\n        if (initArgs->CustomJson)\n        {\n            m_constantsCustomJson = initArgs->CustomJson;\n            m_sessionConstants.CustomJson = m_constantsCustomJson.data();\n        }\n        m_sessionConstants.MaxMembersInSession = initArgs->MaxMembersInSession;\n        m_sessionConstants.Visibility = initArgs->Visibility;\n        if (initArgs->InitiatorXuids && initArgs->InitiatorXuidsCount > 0)\n        {\n            m_initiatorXuids = xsapi_internal_vector<uint64_t>(initArgs->InitiatorXuids, initArgs->InitiatorXuids + initArgs->InitiatorXuidsCount);\n            m_sessionConstants.InitiatorXuids = m_initiatorXuids.data();\n            m_sessionConstants.InitiatorXuidsCount = m_initiatorXuids.size();\n        }\n        m_writeConstants = true;\n    }\n}\n\nXblMultiplayerSession::XblMultiplayerSession(const XblMultiplayerSession& other)\n    : m_xuid(other.m_xuid),\n    m_eTag(other.m_eTag),\n    m_sessionRetrievedTime(other.m_sessionRetrievedTime),\n    m_info(other.m_info),\n    m_initialization(other.m_initialization),\n    m_sessionReference(other.m_sessionReference),\n    m_hostCandidates(other.m_hostCandidates),\n    m_sessionConstants(other.m_sessionConstants),\n    m_initiatorXuids(other.m_initiatorXuids),\n    m_memberInitialization(other.m_memberInitialization),\n    m_constantsCustomJson(other.m_constantsCustomJson),\n    m_constantsCloudComputePackageJson(other.m_constantsCloudComputePackageJson),\n    m_constantsMeasurementServerAddressesJson(other.m_constantsMeasurementServerAddressesJson),\n    m_sessionProperties(other.m_sessionProperties),\n    m_keywords(other.m_keywords),\n    m_sessionOwnerIndices(other.m_sessionOwnerIndices),\n    m_turnCollection(other.m_turnCollection),\n    m_serverConnectionStringCandidates(other.m_serverConnectionStringCandidates),\n    m_matchmakingServerConnectionString(other.m_matchmakingServerConnectionString),\n    m_matchmakingTargetSessionConstantsJson(other.m_matchmakingTargetSessionConstantsJson),\n    m_sessionCustomPropertiesJson(other.m_sessionCustomPropertiesJson),\n    m_roleTypes(other.m_roleTypes),\n    m_members(other.m_members),\n    m_membersAccepted(other.m_membersAccepted),\n    m_serversJson(other.m_serversJson),\n    m_matchmakingStatusDetails(other.m_matchmakingStatusDetails),\n    m_lastTeamResultTeam(other.m_lastTeamResultTeam),\n    m_writeSessionStatus(other.m_writeSessionStatus),\n    m_newSession(other.m_newSession),\n    m_deserializationError(other.m_deserializationError),\n    m_sessionSubscriptionGuid(other.m_sessionSubscriptionGuid),\n    m_writePropertiesKeywords(other.m_writePropertiesKeywords),\n    m_writePropertiesTurns(other.m_writePropertiesTurns),\n    m_writeInitializationStatus(other.m_writeInitializationStatus),\n    m_initializationSucceeded(other.m_initializationSucceeded),\n    m_writeHostDeviceToken(other.m_writeHostDeviceToken),\n    m_writeMatchmakingServerConnectionPath(other.m_writeMatchmakingServerConnectionPath),\n    m_writeMatchmakingResubmit(other.m_writeMatchmakingResubmit),\n    m_writeServerConnectionStringCandidates(other.m_writeServerConnectionStringCandidates),\n    m_leaveSession(other.m_leaveSession),\n    m_writeClosed(other.m_writeClosed),\n    m_writeLocked(other.m_writeLocked),\n    m_writeAllocateCloudCompute(other.m_writeAllocateCloudCompute),\n    m_writeRoleTypes(other.m_writeRoleTypes),\n    m_writeTimeouts(other.m_writeTimeouts),\n    m_writeQosConnectivityMetrics(other.m_writeQosConnectivityMetrics),\n    m_writeMemberInitialization(other.m_writeMemberInitialization),\n    m_writePeerToPeerRequirements(other.m_writePeerToPeerRequirements),\n    m_writePeerToHostRequirements(other.m_writePeerToHostRequirements),\n    m_writeMeasurementServerAddresses(other.m_writeMeasurementServerAddresses),\n    m_writeJoinRestriction(other.m_writeJoinRestriction),\n    m_writeReadRestriction(other.m_writeReadRestriction),\n    m_writeServersJson(other.m_writeServersJson),\n    m_writeMatchmakingTargetSessionConstants(other.m_writeMatchmakingTargetSessionConstants),\n    m_writeSessionCustomPropertiesJson(other.m_writeSessionCustomPropertiesJson),\n    m_writeConstants(other.m_writeConstants),\n    m_memberRequestIndex(other.m_memberRequestIndex)\n{\n    m_joiningSession.exchange(other.m_joiningSession);\n\n    for (auto& candidate : m_serverConnectionStringCandidates)\n    {\n        candidate = Make(candidate);\n    }\n\n    for (auto& keyword : m_keywords)\n    {\n        keyword = Make(keyword);\n    }\n    m_sessionProperties.Keywords = m_keywords.data();\n    m_sessionProperties.SessionOwnerMemberIds = m_sessionOwnerIndices.data();\n    m_sessionProperties.TurnCollection = m_turnCollection.data();\n    m_sessionProperties.ServerConnectionStringCandidates = m_serverConnectionStringCandidates.data();\n    m_sessionProperties.MatchmakingServerConnectionString = m_matchmakingServerConnectionString.data();\n    m_sessionProperties.MatchmakingTargetSessionConstantsJson = m_matchmakingTargetSessionConstantsJson.data();\n    m_sessionProperties.SessionCustomPropertiesJson = m_sessionCustomPropertiesJson.data();\n\n    for (auto& member : m_members)\n    {\n        auto internalMember = Make<MultiplayerSessionMember>(*static_cast<MultiplayerSessionMember*>(member.Internal));\n        member.Internal = internalMember;\n        MultiplayerSessionMember::SetExternalMemberPointer(member);\n\n        if (member.Xuid == m_xuid)\n        {\n            m_memberCurrentUser = &member;\n        }\n\n    }\n\n    if (other.m_matchmakingServer != nullptr)\n    {\n        m_matchmakingServer = MakeShared<XblMultiplayerMatchmakingServer>(*other.m_matchmakingServer);\n        m_matchmakingServer->StatusDetails = m_matchmakingStatusDetails.data();\n    }\n\n    m_sessionConstants.InitiatorXuids = m_initiatorXuids.data();\n    m_sessionConstants.InitiatorXuidsCount = static_cast<uint32_t>(m_initiatorXuids.size());\n    if (m_sessionConstants.MemberInitialization != nullptr)\n    {\n        m_sessionConstants.MemberInitialization = &m_memberInitialization;\n    }\n    m_sessionConstants.CustomJson = m_constantsCustomJson.data();\n    m_sessionConstants.SessionCloudComputePackageConstantsJson = m_constantsCloudComputePackageJson.data();\n    m_sessionConstants.MeasurementServerAddressesJson = m_constantsMeasurementServerAddressesJson.data();\n}\n\nXblMultiplayerSession::~XblMultiplayerSession()\n{\n    for (auto candidate : m_serverConnectionStringCandidates)\n    {\n        Delete(candidate);\n    }\n\n    for (auto keyword : m_keywords)\n    {\n        Delete(keyword);\n    }\n\n    for (auto& member : m_members)\n    {\n        Delete(static_cast<MultiplayerSessionMember*>(member.Internal));\n    }\n}\n\nstd::shared_ptr<xbox::services::RefCounter> XblMultiplayerSession::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nvoid XblMultiplayerSession::Initialize()\n{\n    m_info = XblMultiplayerSessionInfo{};\n    m_initialization = XblMultiplayerSessionInitializationInfo{};\n    m_sessionProperties = XblMultiplayerSessionProperties{};\n    m_sessionSubscriptionGuid = utils::create_guid(true);\n\n    m_sessionCustomPropertiesJson = \"{}\";\n    m_sessionProperties.SessionCustomPropertiesJson = m_sessionCustomPropertiesJson.data();\n\n    m_constantsCustomJson = \"\";\n    m_sessionConstants.CustomJson = m_constantsCustomJson.data();\n\n    m_constantsCloudComputePackageJson = \"\";\n    m_sessionConstants.SessionCloudComputePackageConstantsJson = m_constantsCloudComputePackageJson.data();\n\n    m_constantsMeasurementServerAddressesJson = \"\";\n    m_sessionConstants.MeasurementServerAddressesJson = m_constantsMeasurementServerAddressesJson.data();\n\n    m_matchmakingTargetSessionConstantsJson = \"\";\n    m_sessionProperties.MatchmakingTargetSessionConstantsJson = m_matchmakingTargetSessionConstantsJson.data();\n\n    m_matchmakingServerConnectionString = \"\";\n    m_sessionProperties.MatchmakingServerConnectionString = m_matchmakingServerConnectionString.data();\n\n    // Skipping this one cause m_matchmakingServer is optional and nullptr\n    // m_matchmakingServer->StatusDetails = m_matchmakingStatusDetails.data();\n\n    // TODO remove this after fixing member management\n    m_members.reserve(100);\n}\n\nconst xsapi_internal_string XblMultiplayerSession::ETag() const\n{\n    return m_eTag;\n}\n\nconst xsapi_internal_string& XblMultiplayerSession::ETagUnsafe() const\n{\n    return m_eTag;\n}\n\nconst XblMultiplayerSessionInfo& XblMultiplayerSession::SessionInfo() const\n{\n    return m_info;\n}\n\nconst XblMultiplayerSessionInitializationInfo& XblMultiplayerSession::InitializationInfo() const\n{\n    return m_initialization;\n}\n\ntime_t XblMultiplayerSession::TimeOfSession() const\n{\n    return m_sessionRetrievedTime;\n}\nconst XblMultiplayerSessionReference& XblMultiplayerSession::SessionReference() const\n{\n    return m_sessionReference;\n}\n\nconst xsapi_internal_vector<XblDeviceToken>& XblMultiplayerSession::HostCandidates() const\n{\n    return m_hostCandidates;\n}\n\nconst XblMultiplayerSessionConstants& XblMultiplayerSession::SessionConstantsUnsafe() const\n{\n    return m_sessionConstants;\n}\n\nconst XblMultiplayerSessionProperties& XblMultiplayerSession::SessionPropertiesUnsafe() const\n{\n    return m_sessionProperties;\n}\n\nvoid XblMultiplayerSession::StateLock() const\n{\n    m_lockSession.lock();\n}\n\nvoid XblMultiplayerSession::StateUnlock() const\n{\n    m_lockSession.unlock();\n}\n\nconst RoleTypes& XblMultiplayerSession::RoleTypesUnsafe() const\n{\n    return m_roleTypes;\n}\n\nconst xsapi_internal_vector<XblMultiplayerSessionMember>& XblMultiplayerSession::MembersUnsafe() const\n{\n    return m_members;\n}\n\nconst xsapi_internal_vector<const char*>& XblMultiplayerSession::ServerConnectionStringCandidatesUnsafe() const\n{\n    return m_serverConnectionStringCandidates;\n}\n\nconst xsapi_internal_vector<uint32_t>& XblMultiplayerSession::TurnCollectionUnsafe() const\n{\n    return m_turnCollection;\n}\n\nconst xsapi_internal_vector<const char*>& XblMultiplayerSession::KeywordsUnsafe() const\n{\n    return m_keywords;\n}\n\nconst XblMultiplayerSessionMember* XblMultiplayerSession::CurrentUserUnsafe() const\n{\n    return m_memberCurrentUser;\n}\n\nMultiplayerSessionMember* XblMultiplayerSession::CurrentUserInternalUnsafe() const\n{\n    if (m_memberCurrentUser != nullptr)\n    {\n        return MultiplayerSessionMember::Get(m_memberCurrentUser);\n    }\n    return nullptr;\n}\n\nconst XblMultiplayerSessionMember* XblMultiplayerSession::GetMemberUnsafe(uint32_t memberId) const\n{\n    const XblMultiplayerSessionMember* out = nullptr;\n    for (const auto& member : m_members)\n    {\n        if (member.MemberId == memberId)\n        {\n            out = &member;\n        }\n    }\n    return out;\n}\n\nuint32_t XblMultiplayerSession::MembersAccepted() const\n{\n    return m_membersAccepted;\n}\n\nconst xsapi_internal_string XblMultiplayerSession::RawServersJson() const\n{\n    return m_serversJson;\n}\n\nconst xsapi_internal_string& XblMultiplayerSession::RawServersJsonUnsafe() const\n{\n    return m_serversJson;\n}\n\nstd::shared_ptr<const XblMultiplayerMatchmakingServer> XblMultiplayerSession::MatchmakingServer() const\n{\n    return m_matchmakingServer;\n}\n\nXblWriteSessionStatus XblMultiplayerSession::WriteStatus() const\n{\n    return m_writeSessionStatus;\n}\n\nHRESULT XblMultiplayerSession::DeserializationError() const\n{\n    return m_deserializationError;\n}\n\nHRESULT XblMultiplayerSession::SetServersJson(\n    _In_ const xsapi_internal_string& serversJson\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n\n    auto hr = JsonUtils::ValidateJson(serversJson.data());\n    if (SUCCEEDED(hr))\n    {\n        m_serversJson = serversJson;\n        m_writeServersJson = true;\n    }\n    return hr;\n}\n\nvoid XblMultiplayerSession::SetWriteSessionStatus(\n    int32_t httpStatusCode\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_writeSessionStatus = ConvertHttpStatusToWriteSessionStatus(httpStatusCode);\n}\n\nHRESULT XblMultiplayerSession::AddMemberReservation(\n    _In_ uint64_t xuid,\n    _In_opt_z_ const char* memberCustomConstantsJson,\n    _In_ bool initializeRequested\n)\n{\n    if (memberCustomConstantsJson)\n    {\n        auto hr = JsonUtils::ValidateJson(memberCustomConstantsJson);\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    xsapi_internal_stringstream memberId;\n    memberId << \"reserve_\";\n    memberId << m_memberRequestIndex++;\n\n    m_members.push_back(MultiplayerSessionMember::Construct(false, memberId.str(), xuid, memberCustomConstantsJson, initializeRequested));\n    MultiplayerSessionMember::SetExternalMemberPointer(m_members.back());\n\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::Join(\n    _In_opt_z_ const char* memberCustomConstantsJson,\n    _In_ bool initializeRequested,\n    _In_ bool joinWithActiveStatus\n)\n{\n    auto alreadyJoined = m_joiningSession.exchange(true);\n    if (alreadyJoined)\n    {\n        return E_UNEXPECTED;\n    }\n\n    if (memberCustomConstantsJson)\n    {\n        auto hr = JsonUtils::ValidateJson(memberCustomConstantsJson);\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_members.push_back(MultiplayerSessionMember::Construct(true, \"me\", m_xuid, memberCustomConstantsJson, initializeRequested));\n    m_memberCurrentUser = &m_members.back();\n    MultiplayerSessionMember::SetExternalMemberPointer(m_members.back());\n\n    if (joinWithActiveStatus)\n    {\n        MultiplayerSessionMember::Get(m_memberCurrentUser)->SetStatus(XblMultiplayerSessionMemberStatus::Active);\n    }\n\n    return S_OK;\n}\n\nvoid XblMultiplayerSession::SetVisibility(\n    _In_ XblMultiplayerSessionVisibility visibility\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.Visibility = visibility;\n    m_writeConstants = true;\n}\n\nvoid\nXblMultiplayerSession::SetMaxMembersInSession(\n    _In_ uint32_t maxMembersInSession\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.MaxMembersInSession = maxMembersInSession;\n    m_writeConstants = true;\n}\n\n\nHRESULT\nXblMultiplayerSession::SetTimeouts(\n    _In_ uint64_t memberReservedTimeout,\n    _In_ uint64_t memberInactiveTimeout,\n    _In_ uint64_t memberReadyTimeout,\n    _In_ uint64_t sessionEmptyTimeout\n    )\n{\n    // Call set_timeouts/SetTimeouts before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.MemberReservedTimeout = memberReservedTimeout;\n    m_sessionConstants.MemberInactiveTimeout = memberInactiveTimeout;\n    m_sessionConstants.MemberReadyTimeout = memberReadyTimeout;\n    m_sessionConstants.SessionEmptyTimeout = sessionEmptyTimeout;\n    m_writeTimeouts = true;\n    m_writeConstants = true;\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetQosConnectivityMetrics(\n    _In_ bool enableLatencyMetric,\n    _In_ bool enableBandwidthDownMetric,\n    _In_ bool enableBandwidthUpMetric,\n    _In_ bool enableCustomMetric\n    )\n{\n    // Call set_quality_of_service_connectivity_metrics/SetQualityOfServiceConnectivityMetrics \n    // before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.EnableMetricsLatency = enableLatencyMetric;\n    m_sessionConstants.EnableMetricsBandwidthUp = enableBandwidthUpMetric;\n    m_sessionConstants.EnableMetricsBandwidthDown = enableBandwidthDownMetric;\n    m_sessionConstants.EnableMetricsCustom = enableCustomMetric;\n    m_writeQosConnectivityMetrics = true;\n    m_writeConstants = true;\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetMemberInitialization(\n    _In_ const XblMultiplayerMemberInitialization& memberInitialization\n)\n{\n    // Call set_member_initialization/SetMemberInitialization before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_memberInitialization = memberInitialization;\n    m_sessionConstants.MemberInitialization = &m_memberInitialization;\n    m_writeMemberInitialization = true;\n    m_writeConstants = true;\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetPeerToPeerRequirements(\n    _In_ const XblMultiplayerPeerToPeerRequirements& requirements\n    )\n{\n    // Call set_peer_to_peer_requirements/SetPeerToPeerRequirements before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.PeerToPeerRequirements = requirements;\n    m_writePeerToPeerRequirements = true;\n    m_writeConstants = true;\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::SetPeerToHostRequirements(\n    _In_ const XblMultiplayerPeerToHostRequirements& requirements\n    )\n{\n    // Call set_peer_to_host_requirements/SetPeerToHostRequirements before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.PeerToHostRequirements = requirements;\n    m_writePeerToHostRequirements = true;\n    m_writeConstants = true;\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::SetMeasurementServerAddresses(\n    _In_ const xsapi_internal_string& measurementServerAddresses\n)\n{\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    auto hr = JsonUtils::ValidateJson(measurementServerAddresses.data());\n    if (SUCCEEDED(hr))\n    {\n        std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n        m_constantsMeasurementServerAddressesJson = measurementServerAddresses;\n        m_sessionConstants.MeasurementServerAddressesJson = m_constantsMeasurementServerAddressesJson.data();\n        m_writeMeasurementServerAddresses = true;\n        m_writeConstants = true;\n    }\n    return hr;\n}\n\nHRESULT\nXblMultiplayerSession::SetSessionCapabilities(\n    _In_ const XblMultiplayerSessionCapabilities& capabilities\n    )\n{\n    // Call set_session_capabilities/SetSessionCapabilities before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionConstants.SessionCapabilities = capabilities;\n    m_writeConstants = true;\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetCloudComputePackageJson(\n    _In_ const xsapi_internal_string& sessionCloudComputePackageConstantsJson\n    )\n{\n    // Call set_cloud_compute_package_json/SetCloudComputePackageJson before writing a new session to the service\n    if (!m_newSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_constantsCloudComputePackageJson = sessionCloudComputePackageConstantsJson;\n    m_sessionConstants.SessionCloudComputePackageConstantsJson = m_constantsCloudComputePackageJson.data();\n    m_writeConstants = true;\n    return S_OK;\n}\n\nvoid\nXblMultiplayerSession::SetInitializationStatus(\n    _In_ bool initializationSucceeded\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_writeInitializationStatus = true;\n    m_initializationSucceeded = initializationSucceeded;\n}\n\nvoid\nXblMultiplayerSession::SetHostDeviceToken(\n    _In_ const XblDeviceToken hostDeviceToken\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    utils::strcpy(m_sessionProperties.HostDeviceToken.Value, sizeof(m_sessionProperties.HostDeviceToken.Value), hostDeviceToken.Value);\n    m_writeHostDeviceToken = true;\n}\n\nvoid\nXblMultiplayerSession::SetHostDeviceToken(\n    _In_ const xsapi_internal_string& hostDeviceToken\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    utils::strcpy(m_sessionProperties.HostDeviceToken.Value, sizeof(m_sessionProperties.HostDeviceToken.Value), hostDeviceToken.data());\n    m_writeHostDeviceToken = true;\n}\n\nvoid\nXblMultiplayerSession::SetMatchmakingServerConnectionPath(\n    _In_ const xsapi_internal_string& serverConnectionPath\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_matchmakingServerConnectionString = serverConnectionPath;\n    m_sessionProperties.MatchmakingServerConnectionString = m_matchmakingServerConnectionString.data();\n    m_writeMatchmakingServerConnectionPath = true;\n}\n\nvoid\nXblMultiplayerSession::SetMatchmakingResubmit(\n    _In_ bool matchResubmit\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionProperties.MatchmakingResubmit = matchResubmit;\n    m_writeMatchmakingResubmit = true;\n}\n\nvoid\nXblMultiplayerSession::SetClosed(\n    _In_ bool closed\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionProperties.Closed = closed;\n    m_writeClosed = true;\n}\n\nvoid\nXblMultiplayerSession::SetLocked(\n    _In_ bool locked\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionProperties.Locked = locked;\n    m_writeLocked = true;\n}\n\nvoid\nXblMultiplayerSession::SetAllocateCloudCompute(\n    _In_ bool allocateCloudCompute\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionProperties.AllocateCloudCompute = allocateCloudCompute;\n    m_writeAllocateCloudCompute = true;\n}\n\nHRESULT XblMultiplayerSession::SetServerConnectionStringCandidates(\n    _In_reads_(serverConnectionStringCandidatesCount) const char** serverConnectionStringCandidates,\n    _In_ size_t serverConnectionStringCandidatesCount\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF(serverConnectionStringCandidates == nullptr)\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    for (auto candidate : m_serverConnectionStringCandidates)\n    {\n        Delete(candidate);\n    }\n    m_serverConnectionStringCandidates.clear();\n    for (uint32_t i = 0; i < serverConnectionStringCandidatesCount; ++i)\n    {\n        m_serverConnectionStringCandidates.push_back(Make(serverConnectionStringCandidates[i]));\n    }\n\n    m_sessionProperties.ServerConnectionStringCandidates = m_serverConnectionStringCandidates.data();\n    m_sessionProperties.ServerConnectionStringCandidatesCount = m_serverConnectionStringCandidates.size();\n    m_writeServerConnectionStringCandidates = true;\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetSessionChangeSubscription(\n    _In_ XblMultiplayerSessionChangeTypes changeTypes\n    )\n{\n    if(m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->SetSessionChangeSubscription(changeTypes, m_sessionSubscriptionGuid);\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::Leave()\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Failed trying to leave and join the session at the same time\n    if (m_joiningSession)\n    {\n        return E_UNEXPECTED;\n    }\n\n    for (auto iter = m_members.begin(); iter != m_members.end(); iter++)\n    {\n        if (iter->IsCurrentUser)\n        {\n            Delete(static_cast<MultiplayerSessionMember*>(iter->Internal));\n            m_members.erase(iter);\n            m_memberCurrentUser = nullptr;\n            break;\n        }\n    }\n\n    m_leaveSession = true;\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetCurrentUserStatus(\n    _In_ XblMultiplayerSessionMemberStatus status\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserStatus\n    // Can not set member to ready\n    // Can not set member to reserved.  Use AddMemberReservation instead\n    if (m_memberCurrentUser == nullptr || status == XblMultiplayerSessionMemberStatus::Ready || status == XblMultiplayerSessionMemberStatus::Reserved)\n    {\n        return E_UNEXPECTED;\n    }\n\n    return MultiplayerSessionMember::Get(m_memberCurrentUser)->SetStatus(status);\n}\n\nHRESULT\nXblMultiplayerSession::SetCurrentUserSecureDeviceAddressBase64(\n    _In_ const xsapi_internal_string& value\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserSecureDeviceAddressBase64\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->SetSecureDeviceBaseAddress64(value);\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetCurrentUserRoleInfo(\n    _In_ const xsapi_internal_vector<XblMultiplayerSessionMemberRole>& roles\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserRoleInfo\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->SetRoles(roles);\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::SetMutableRoleSettings(\n    _In_ String&& roleTypeName,\n    _In_ String&& roleName,\n    _In_opt_ uint32_t* maxCount,\n    _In_opt_ uint32_t* targetCount\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    auto hr = m_roleTypes.SetRoleSettings(std::move(roleTypeName), std::move(roleName), maxCount, targetCount);\n    if (SUCCEEDED(hr))\n    {\n        m_writeRoleTypes = true;\n    }\n    return hr;\n}\n\nHRESULT XblMultiplayerSession::SetCurrentUserMembersInGroup(\n    _In_ const xsapi_internal_vector<uint32_t>& membersInGroup\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserMembersInGroup\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->SetMembersInGroup(membersInGroup);\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::SetCurrentUserGroups(\n    _In_reads_(groupsCount) const char** groups,\n    _In_ size_t groupsCount\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserGroups\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->SetGroups(groups, groupsCount);\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::SetCurrentUserEncounters(\n    _In_reads_(encountersCount) const char** encounters,\n    _In_ size_t encountersCount\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserEncounters\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->SetEncounters(encounters, encountersCount);\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::SetCurrentUserServerMeasurementsJson(\n    _In_ const xsapi_internal_string& serverMeasurementsJson\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserServerMeasurementsJson\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n    return MultiplayerSessionMember::Get(m_memberCurrentUser)->SetServerMeasurementsJson(serverMeasurementsJson);\n}\n\nHRESULT\nXblMultiplayerSession::SetCurrentUserQosMeasurementsJson(\n    _In_ const xsapi_internal_string& serverMeasurementsJson\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserQosMeasurementsJson\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n    return MultiplayerSessionMember::Get(m_memberCurrentUser)->SetQosMeasurementsJson(serverMeasurementsJson);\n}\n\nHRESULT\nXblMultiplayerSession::SetCurrentUserMemberCustomPropertyJson(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson\n)\n{\n    if (name.empty())\n    {\n        return E_INVALIDARG;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling SetCurrentUserMemberCustomPropertyJson\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n\n    return MultiplayerSessionMember::Get(m_memberCurrentUser)->SetCustomPropertyJson(name, valueJson);\n}\n\nHRESULT\nXblMultiplayerSession::DeleteCurrentUserMemberCustomPropertyJson(\n    _In_ const xsapi_internal_string& name\n    )\n{\n    if (name.empty())\n    {\n        return E_INVALIDARG;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    // Must join the session first before calling DeleteCurrentUserMemberCustomPropertyJson\n    if (m_memberCurrentUser == nullptr)\n    {\n        return E_UNEXPECTED;\n    }\n    MultiplayerSessionMember::Get(m_memberCurrentUser)->DeleteCustomPropertyJson(name);\n\n    return S_OK;\n}\n\nHRESULT\nXblMultiplayerSession::SetMatchmakingTargetSessionConstantsJson(\n    _In_ const xsapi_internal_string& matchmakingTargetSessionConstantsJson\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n\n    auto hr = JsonUtils::ValidateJson(matchmakingTargetSessionConstantsJson.data());\n    if (SUCCEEDED(hr))\n    {\n        m_matchmakingTargetSessionConstantsJson = matchmakingTargetSessionConstantsJson;\n        m_sessionProperties.MatchmakingTargetSessionConstantsJson = m_matchmakingTargetSessionConstantsJson.data();\n        m_writeMatchmakingTargetSessionConstants = true;\n    }\n    return hr;\n}\n\nHRESULT\nXblMultiplayerSession::SetSessionCustomPropertyJson(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& customProperty\n)\n{\n    if (name.empty())\n    {\n        return E_INVALIDARG;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n\n    JsonDocument customProperties;\n    customProperties.Parse(m_sessionCustomPropertiesJson.data());\n    auto hr = JsonUtils::SetMember(customProperties, name, customProperty);\n    XSAPI_ASSERT(SUCCEEDED(hr));\n    if (SUCCEEDED(hr))\n    {\n        m_sessionCustomPropertiesJson = JsonUtils::SerializeJson(customProperties);\n        m_sessionProperties.SessionCustomPropertiesJson = m_sessionCustomPropertiesJson.data();\n        m_writeSessionCustomPropertiesJson = true;\n    }\n\n    return hr;\n}\n\nHRESULT\nXblMultiplayerSession::DeleteSessionCustomPropertyJson(\n    _In_ const xsapi_internal_string& name\n    )\n{\n    return SetSessionCustomPropertyJson(name, JsonValue());\n}\n\nHRESULT XblMultiplayerSession::SetKeywords(\n    _In_ const char** keywords,\n    _In_ size_t keywordsCount\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF(keywords == nullptr)\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    for (auto keyword : m_keywords)\n    {\n        Delete(keyword);\n    }\n    m_keywords.clear();\n    for (uint32_t i = 0; i < keywordsCount; ++i)\n    {\n        m_keywords.push_back(Make(keywords[i]));\n    }\n    m_sessionProperties.Keywords = m_keywords.data();\n    m_sessionProperties.KeywordCount = m_keywords.size();\n    m_writePropertiesKeywords = true;\n    return S_OK;\n}\n\nvoid XblMultiplayerSession::SetJoinRestriction(\n    _In_ XblMultiplayerSessionRestriction joinRestriction\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionProperties.JoinRestriction = joinRestriction;\n    m_writeJoinRestriction = true;\n}\n\nvoid XblMultiplayerSession::SetReadRestriction(\n    _In_ XblMultiplayerSessionRestriction readRestriction\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n    m_sessionProperties.ReadRestriction = readRestriction;\n    m_writeReadRestriction = true;\n}\n\nXblMultiplayerMetrics XblMultiplayerSession::ConvertStringToMultiplayerHostSelectionMetric(\n    _In_ const xsapi_internal_string& value\n    )\n{\n    if (value.empty())\n    {\n        return XblMultiplayerMetrics::Latency;\n    }\n    else if (utils::str_icmp_internal(value, \"bandwidthUp\") == 0)\n    {\n        return XblMultiplayerMetrics::BandwidthUp;\n    }\n    else if (utils::str_icmp_internal(value, \"bandwidthDown\") == 0)\n    {\n        return XblMultiplayerMetrics::BandwidthDown;\n    }\n    else if (utils::str_icmp_internal(value, \"bandwidth\") == 0)\n    {\n        return XblMultiplayerMetrics::Bandwidth;\n    }\n    else if (utils::str_icmp_internal(value, \"latency\") == 0)\n    {\n        return XblMultiplayerMetrics::Latency;\n    }\n\n    return XblMultiplayerMetrics::Unknown;\n}\n\nxsapi_internal_string\nXblMultiplayerSession::ConvertMultiplayerHostSelectionMetricToString(\n    _In_ XblMultiplayerMetrics multiplayMetric\n    )\n{\n    switch (multiplayMetric)\n    {\n        case XblMultiplayerMetrics::Unknown: return \"unknown\";\n        case XblMultiplayerMetrics::BandwidthUp: return \"bandwidthUp\";\n        case XblMultiplayerMetrics::BandwidthDown: return \"bandwidthDown\";\n        case XblMultiplayerMetrics::Bandwidth: return \"bandwidth\";\n        case XblMultiplayerMetrics::Latency: return \"latency\";\n        default: \n        {\n            XSAPI_ASSERT(false);\n            return \"unknown\";\n        };\n    }\n}\n\nXblMultiplayerInitializationStage\nXblMultiplayerSession::ConvertStringToMultiplayerInitializationStage(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (value.empty())\n    {\n        return XblMultiplayerInitializationStage::None;\n    }\n    else if (utils::str_icmp_internal(value, \"joining\") == 0)\n    {\n        return XblMultiplayerInitializationStage::Joining;\n    }\n    else if (utils::str_icmp_internal(value, \"failed\") == 0)\n    {\n        return XblMultiplayerInitializationStage::Failed;\n    }\n    else if (utils::str_icmp_internal(value, \"evaluating\") == 0)\n    {\n        return XblMultiplayerInitializationStage::Evaluating;\n    }\n    else if (utils::str_icmp_internal(value, \"measuring\") == 0)\n    {\n        return XblMultiplayerInitializationStage::Measuring;\n    }\n\n    return XblMultiplayerInitializationStage::Unknown;\n}\n\nXblMatchmakingStatus\nXblMultiplayerSession::ConvertStringToMatchmakingStatus(\n    _In_ const xsapi_internal_string& value\n    )\n{\n    XSAPI_ASSERT(!value.empty());\n    if (utils::str_icmp_internal(value, \"searching\") == 0)\n    {\n        return XblMatchmakingStatus::Searching;\n    }\n    else if (utils::str_icmp_internal(value, \"expired\") == 0)\n    {\n        return XblMatchmakingStatus::Expired;\n    }\n    else if (utils::str_icmp_internal(value, \"found\") == 0)\n    {\n        return XblMatchmakingStatus::Found;\n    }\n    else if (utils::str_icmp_internal(value, \"canceled\") == 0)\n    {\n        return XblMatchmakingStatus::Canceled;\n    }\n    return XblMatchmakingStatus::Unknown;\n}\n\nxsapi_internal_string\nXblMultiplayerSession::ConvertMatchmakingStatusToString(\n    _In_ XblMatchmakingStatus matchmakingStatus\n    )\n{\n    switch (matchmakingStatus)\n    {\n        case XblMatchmakingStatus::Unknown: return \"unknown\";\n        case XblMatchmakingStatus::Searching: return \"searching\";\n        case XblMatchmakingStatus::Expired: return \"expired\";\n        case XblMatchmakingStatus::Found: return \"found\";\n        case XblMatchmakingStatus::Canceled: return \"canceled\";\n        default: \n        {\n            XSAPI_ASSERT(false);\n            return \"unknown\";\n        }\n    }\n}\n\nXblWriteSessionStatus\nXblMultiplayerSession::ConvertHttpStatusToWriteSessionStatus(\n_In_ int32_t httpStatusCode\n)\n{\n    switch (httpStatusCode)\n    {\n        case 200: return XblWriteSessionStatus::Updated;\n        case 201: return XblWriteSessionStatus::Created;\n        case 204: return XblWriteSessionStatus::SessionDeleted;\n        case 401: return XblWriteSessionStatus::AccessDenied;\n        case 404: return XblWriteSessionStatus::HandleNotFound;\n        case 409: return XblWriteSessionStatus::Conflict;\n        case 412: return XblWriteSessionStatus::OutOfSync;\n        default: return XblWriteSessionStatus::Unknown;\n    }\n}\n\nHRESULT XblMultiplayerSession::DeserializeMembers(\n    _In_ const JsonValue& json\n)\n{\n    if (!json.IsNull() && json.IsObject())\n    {\n        uint32_t first = 0;\n        uint32_t last = 0;\n        if (json.HasMember(\"membersInfo\"))\n        {\n            const JsonValue& membersInfo = json[\"membersInfo\"];\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(membersInfo, \"first\", first, true));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(membersInfo, \"next\", last, true));\n        }\n        else\n        {\n            //required\n            return WEB_E_INVALID_JSON_STRING;\n        }\n\n        for (uint32_t current = first; current != last;)\n        {\n            XblMultiplayerSessionMember member;\n            if (json.HasMember(\"members\"))\n            {\n                const JsonValue& membersJson = json[\"members\"];\n                // In large sessions the member json only contains \"me\" member\n                auto currentIdString = m_sessionConstants.SessionCapabilities.Large ? \"me\" : utils::uint32_to_internal_string(current);\n                if (membersJson.IsObject() && membersJson.HasMember(currentIdString.c_str()))\n                {\n                    const JsonValue& memberJson = membersJson[currentIdString.c_str()];\n                    member = MultiplayerSessionMember::Deserialize(memberJson).Payload();\n\n                    member.MemberId = current;\n\n                    if (member.Xuid == m_xuid)\n                    {\n                        member.IsCurrentUser = true;\n                    }\n\n                    m_members.push_back(std::move(member));\n                    if (m_members.back().IsCurrentUser)\n                    {\n                        m_memberCurrentUser = &m_members.back();\n                    }\n                    MultiplayerSessionMember::SetExternalMemberPointer(m_members.back());\n\n                    if (m_sessionConstants.SessionCapabilities.Large)\n                    {\n                        break;\n                    }\n\n                    current = last;\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(memberJson, \"next\", current, false));\n                }\n                else\n                {\n                    //required\n                    return WEB_E_INVALID_JSON_STRING;\n                }\n            }\n\n        }\n        \n    }\n\n    return S_OK;\n}\n\nXblMultiplayerSessionChangeTypes\nXblMultiplayerSession::CompareMultiplayerSessions(\n    _In_ std::shared_ptr<XblMultiplayerSession> other\n    )\n{\n    XblMultiplayerSessionChangeTypes currentType = XblMultiplayerSessionChangeTypes::None;\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n\n    if (utils::str_icmp_internal(m_sessionProperties.HostDeviceToken.Value, other->m_sessionProperties.HostDeviceToken.Value) != 0)\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::HostDeviceTokenChange;\n    }\n\n    if (m_initialization.Stage != other->m_initialization.Stage)\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::InitializationStateChange;\n    }\n\n    if ((m_matchmakingServer == nullptr) != (other->m_matchmakingServer == nullptr))\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::MatchmakingStatusChange;\n    }\n    else if (m_matchmakingServer != nullptr &&\n        ((m_matchmakingServer->Status != other->m_matchmakingServer->Status) || !(m_matchmakingServer->TargetSessionRef == other->m_matchmakingServer->TargetSessionRef))\n        )\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::MatchmakingStatusChange;\n    }\n\n    bool hasMemberChanged = false;\n    bool memberStatusChanged = false;\n    bool memberCustomPropertyChanged = false;\n\n    if (m_members.size() != other->m_members.size())\n    {\n        hasMemberChanged = true;\n    }\n\n    for (const auto& currentMember : m_members)\n    {\n        bool isMemberFound = false;\n        for (const auto& olderSessionMember : other->m_members)\n        {\n            if (currentMember.Xuid == olderSessionMember.Xuid)\n            {\n                isMemberFound = true;\n\n                if (currentMember.Status != olderSessionMember.Status)\n                {\n                    memberStatusChanged = true;\n                }\n\n                MultiplayerSessionMemberReadLockGuard memberSafe(MultiplayerSessionMember::Get(&currentMember));\n                MultiplayerSessionMemberReadLockGuard olderSessionMemberSafe(MultiplayerSessionMember::Get(&olderSessionMember));\n                if (utils::str_icmp(JsonUtils::SerializeJson(memberSafe.CustomPropertiesJson()).c_str(),\n                    JsonUtils::SerializeJson(olderSessionMemberSafe.CustomPropertiesJson()).c_str()) != 0)\n                {\n                    memberCustomPropertyChanged = true;\n                }\n            }\n        }\n\n        if (!isMemberFound)\n        {\n            hasMemberChanged = true;\n        }\n\n        if (memberStatusChanged && hasMemberChanged && memberCustomPropertyChanged)\n        {\n            break;\n        }\n    }\n\n    if (hasMemberChanged)\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::MemberListChange;\n    }\n\n    if (memberStatusChanged)\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::MemberStatusChange;\n    }\n\n    if (memberCustomPropertyChanged)\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::MemberCustomPropertyChange;\n    }\n\n    XblMultiplayerSessionReadLockGuard otherSafe(other);\n    if (m_sessionProperties.Closed != other->m_sessionProperties.Closed ||\n        m_sessionProperties.Locked != other->m_sessionProperties.Locked ||\n        m_sessionProperties.JoinRestriction != other->m_sessionProperties.JoinRestriction ||\n        (m_members.size() == m_sessionConstants.MaxMembersInSession) != \n        (otherSafe.Members().size() == other->m_sessionConstants.MaxMembersInSession)     // if the session is open again or closed again because the max member has changed\n        )\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::SessionJoinabilityChange;\n    }\n\n    if (utils::str_icmp_internal(m_sessionCustomPropertiesJson, other->m_sessionCustomPropertiesJson) != 0)\n    {\n        currentType |= XblMultiplayerSessionChangeTypes::CustomPropertyChange;\n    }\n\n    return static_cast<XblMultiplayerSessionChangeTypes>(currentType);\n}\n\nHRESULT XblMultiplayerSession::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"contractVersion\", m_info.ContractVersion));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"correlationId\", m_info.CorrelationId, sizeof(m_info.CorrelationId)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"searchHandle\", m_info.SearchHandleId, sizeof(m_info.SearchHandleId)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"branch\", m_info.Branch, sizeof(m_info.Branch)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(json, \"changeNumber\", m_info.ChangeNumber, false));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"startTime\", m_info.StartTime));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"nextTimer\", m_info.NextTimer));\n\n    if (json.IsObject() && json.HasMember(\"constants\"))\n    {\n        DeserializeSessionConstants(json[\"constants\"]);\n    }\n    else\n    {\n        //required\n        DeserializeSessionConstants(JsonValue());\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    if (json.IsObject() && json.HasMember(\"initializing\"))\n    {\n        const JsonValue& initializingJson = json[\"initializing\"];\n        xsapi_internal_string stage;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(initializingJson, \"stage\", stage));\n        m_initialization.Stage = ConvertStringToMultiplayerInitializationStage(stage);\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(initializingJson, \"stageStartTime\", m_initialization.StageStartTime));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(initializingJson, \"episode\", m_initialization.Episode));\n    }\n    else\n    {\n        m_initialization.Stage = XblMultiplayerInitializationStage::None;\n        m_initialization.StageStartTime = utils::time_t_from_datetime(xbox::services::datetime());\n        m_initialization.Episode = 0;\n    }\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblDeviceToken>([](const JsonValue& json)\n    {\n        if (!json.IsString())\n        {\n            return Result<XblDeviceToken>(WEB_E_INVALID_JSON_STRING);\n        }\n        XblDeviceToken token{};\n        utils::strcpy(token.Value, sizeof(token.Value), json.GetString());\n        return Result<XblDeviceToken>(token);\n    }, json, \"hostCandidates\", m_hostCandidates, false));\n\n    if (json.IsObject() && json.HasMember(\"roleTypes\"))\n    {\n        auto roleTypesResult{ RoleTypes::Deserialize(json[\"roleTypes\"]) };\n        RETURN_HR_IF_FAILED(roleTypesResult.Hresult());\n        m_roleTypes = roleTypesResult.ExtractPayload();\n    }\n\n    DeserializeMembers(json);\n\n    if (json.IsObject() && json.HasMember(\"properties\"))\n    {\n        DeserializeSessionProperties(json[\"properties\"]);\n    }\n    else\n    {\n        //required\n        DeserializeSessionProperties(JsonValue());\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    if (json.IsObject() && json.HasMember(\"membersInfo\"))\n    {\n        const JsonValue& memberInfoJson = json[\"membersInfo\"];\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(memberInfoJson, \"accepted\", m_membersAccepted));\n    }\n    else\n    {\n        m_membersAccepted = 0;\n    }\n\n    if (json.IsObject() && json.HasMember(\"servers\"))\n    {\n        const JsonValue& serversJson = json[\"servers\"];\n\n        if (serversJson.IsObject())\n        {\n            if (serversJson.HasMember(\"matchmaking\"))\n            {\n                const JsonValue& serversMatchmakingJson = serversJson[\"matchmaking\"];\n                if (!serversMatchmakingJson.IsNull())\n                {\n                    DeserializeMatchmakingServer(serversMatchmakingJson);\n                }\n            }\n        }\n\n        m_serversJson = JsonUtils::SerializeJson(serversJson);\n    }\n    else\n    {\n        m_serversJson = \"\";\n    }\n\n    return S_OK;\n}\n\nvoid XblMultiplayerSession::SerializeSessionProperties(_Out_ JsonValue& jsonProperties, _In_ JsonDocument::AllocatorType& allocator)\n{\n    jsonProperties.SetObject();\n    JsonValue jsonPropertiesSystem(rapidjson::kObjectType);\n    if (m_writePropertiesKeywords)\n    {\n        JsonValue keywordsJson;\n        JsonUtils::SerializeVector<const char*>(JsonUtils::JsonUtf8Serializer, m_keywords, keywordsJson, allocator);\n        jsonPropertiesSystem.AddMember(\"keywords\", keywordsJson, allocator);\n    }\n\n    if (m_writePropertiesTurns)\n    {\n        JsonValue turnJson;\n        JsonUtils::SerializeVector<uint32_t>(JsonUtils::JsonIntSerializer, m_turnCollection, turnJson, allocator);\n        jsonPropertiesSystem.AddMember(\"turn\", turnJson, allocator);\n    }\n\n    if (m_writeJoinRestriction && m_sessionProperties.JoinRestriction != XblMultiplayerSessionRestriction::Unknown)\n    {\n        auto joinRestrictionToString = Serializers::StringFromMultiplayerSessionRestriction(m_sessionProperties.JoinRestriction);\n        jsonPropertiesSystem.AddMember(\"joinRestriction\", JsonValue(joinRestrictionToString.c_str(), allocator).Move(), allocator);\n    }\n\n    if (m_writeReadRestriction && m_sessionProperties.ReadRestriction != XblMultiplayerSessionRestriction::Unknown)\n    {\n        auto readRestrictionToString = Serializers::StringFromMultiplayerSessionRestriction(m_sessionProperties.ReadRestriction);\n        jsonPropertiesSystem.AddMember(\"readRestriction\", JsonValue(readRestrictionToString.c_str(), allocator).Move(), allocator);\n    }\n\n    if (m_writeClosed)\n    {\n        jsonPropertiesSystem.AddMember(\"closed\", m_sessionProperties.Closed, allocator);\n    }\n\n    if (m_writeLocked)\n    {\n        jsonPropertiesSystem.AddMember(\"locked\", m_sessionProperties.Locked, allocator);\n    }\n\n    if (m_writeAllocateCloudCompute)\n    {\n        jsonPropertiesSystem.AddMember(\"allocateCloudCompute\", m_sessionProperties.AllocateCloudCompute, allocator);\n    }\n\n    if (m_writeMatchmakingTargetSessionConstants || m_writeMatchmakingServerConnectionPath)\n    {\n        JsonValue jsonMatchmaking(rapidjson::kObjectType);\n        if (m_writeMatchmakingTargetSessionConstants)\n        {\n            JsonDocument targetSessionConstraintsJson{ &allocator };\n            targetSessionConstraintsJson.Parse(m_matchmakingTargetSessionConstantsJson.c_str());\n            jsonMatchmaking.AddMember(\"targetSessionConstants\", targetSessionConstraintsJson, allocator);\n        }\n\n        if (m_writeMatchmakingServerConnectionPath)\n        {\n            jsonMatchmaking.AddMember(\"serverConnectionString\", JsonValue(m_sessionProperties.MatchmakingServerConnectionString, allocator).Move(), allocator);\n        }\n\n        jsonPropertiesSystem.AddMember(\"matchmaking\", jsonMatchmaking, allocator);\n    }\n\n    if (m_writeMatchmakingResubmit)\n    {\n        jsonPropertiesSystem.AddMember(\"matchmakingResubmit\", m_sessionProperties.MatchmakingResubmit, allocator);\n    }\n\n    if (m_writeInitializationStatus)\n    {\n        jsonPropertiesSystem.AddMember(\"initializationSucceeded\", m_initializationSucceeded, allocator);\n    }\n\n    if (m_writeHostDeviceToken)\n    {\n        jsonPropertiesSystem.AddMember(\"host\", JsonValue(m_sessionProperties.HostDeviceToken.Value, allocator).Move(), allocator);\n    }\n\n    if (m_writeServerConnectionStringCandidates)\n    {\n        JsonValue serverConnectionStringCandidatesJson;\n        JsonUtils::SerializeVector<const char*>(JsonUtils::JsonUtf8Serializer, m_serverConnectionStringCandidates, serverConnectionStringCandidatesJson, allocator);\n        jsonPropertiesSystem.AddMember(\"serverConnectionStringCandidates\", serverConnectionStringCandidatesJson, allocator);\n    }\n\n    if (!jsonPropertiesSystem.IsNull() && !jsonPropertiesSystem.ObjectEmpty())\n    {\n        jsonProperties.AddMember(\"system\", jsonPropertiesSystem, allocator);\n    }\n\n    if (m_writeSessionCustomPropertiesJson)\n    {\n        JsonDocument customJson{ &allocator };\n        customJson.Parse(m_sessionCustomPropertiesJson.c_str());\n        jsonProperties.AddMember(\"custom\", customJson, allocator);\n    }\n}\n\nvoid XblMultiplayerSession::SerializeSessionConstants(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    if (!m_writeConstants)\n    {\n        return;\n    }\n\n    json.SetObject();\n\n    JsonValue systemJson(rapidjson::kObjectType);\n    systemJson.AddMember(\"version\", MULTIPLAYER_SESSION_VERSION, allocator);\n    if (m_sessionConstants.MaxMembersInSession > 0)\n    {\n        systemJson.AddMember(\"maxMembersCount\", m_sessionConstants.MaxMembersInSession, allocator);\n    }\n\n    JsonValue systemCapabilitiesJson(rapidjson::kObjectType);\n    if (m_sessionConstants.SessionCapabilities.Connectivity)\n    {\n        systemCapabilitiesJson.AddMember(\"connectivity\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.SuppressPresenceActivityCheck)\n    {\n        systemCapabilitiesJson.AddMember(\"suppressPresenceActivityCheck\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.Gameplay)\n    {\n        systemCapabilitiesJson.AddMember(\"gameplay\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.Large)\n    {\n        systemCapabilitiesJson.AddMember(\"large\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.UserAuthorizationStyle)\n    {\n        systemCapabilitiesJson.AddMember(\"userAuthorizationStyle\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.ConnectionRequiredForActiveMembers)\n    {\n        systemCapabilitiesJson.AddMember(\"connectionRequiredForActiveMembers\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.Crossplay)\n    {\n        systemCapabilitiesJson.AddMember(\"crossPlay\", true, allocator);\n    }\n    \n    if (m_sessionConstants.SessionCapabilities.Searchable)\n    {\n        systemCapabilitiesJson.AddMember(\"searchable\", true, allocator);\n    }\n\n    if (m_sessionConstants.SessionCapabilities.HasOwners)\n    {\n        systemCapabilitiesJson.AddMember(\"hasOwners\", true, allocator);\n    }\n\n    if (!systemCapabilitiesJson.IsNull() && !systemCapabilitiesJson.ObjectEmpty())\n    {\n        systemJson.AddMember(\"capabilities\", systemCapabilitiesJson, allocator);\n    }\n\n    if (m_sessionConstants.Visibility != XblMultiplayerSessionVisibility::Any && m_sessionConstants.Visibility != XblMultiplayerSessionVisibility::Unknown)\n    {\n        auto visibilityString = Serializers::StringFromMultiplayerSessionVisibility(m_sessionConstants.Visibility);\n        systemJson.AddMember(\"visibility\", JsonValue(visibilityString.c_str(), allocator).Move(), allocator);\n    }\n\n    if (m_sessionConstants.InitiatorXuids != nullptr && m_sessionConstants.InitiatorXuidsCount > 0)\n    {\n        std::sort(m_sessionConstants.InitiatorXuids, m_sessionConstants.InitiatorXuids + m_sessionConstants.InitiatorXuidsCount);\n        JsonValue jsonArray(rapidjson::kArrayType);\n        for (uint32_t i = 0; i < m_sessionConstants.InitiatorXuidsCount; ++i)\n        {\n            jsonArray.PushBack(JsonValue(utils::uint64_to_internal_string(m_sessionConstants.InitiatorXuids[i]).c_str(), allocator).Move(), allocator);\n        }\n        systemJson.AddMember(\"initiators\", jsonArray, allocator);\n    }\n\n    if (m_writeTimeouts)\n    {\n        JsonValue reservedRemovalTimeoutJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.MemberReservedTimeout, reservedRemovalTimeoutJson);\n        systemJson.AddMember(\"reservedRemovalTimeout\", reservedRemovalTimeoutJson, allocator);\n\n        JsonValue inactiveRemovalTimeoutJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.MemberInactiveTimeout, inactiveRemovalTimeoutJson);\n        systemJson.AddMember(\"inactiveRemovalTimeout\", inactiveRemovalTimeoutJson, allocator);\n        \n        JsonValue readyRemovalTimeoutJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.MemberReadyTimeout, readyRemovalTimeoutJson);\n        systemJson.AddMember(\"readyRemovalTimeout\", readyRemovalTimeoutJson, allocator);\n\n        JsonValue sessionEmptyTimeoutJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.SessionEmptyTimeout, sessionEmptyTimeoutJson);\n        systemJson.AddMember(\"sessionEmptyTimeout\", sessionEmptyTimeoutJson, allocator);\n    }\n\n    if (m_writeQosConnectivityMetrics)\n    {\n        JsonValue systemMetricsJson(rapidjson::kObjectType);\n        systemMetricsJson.AddMember(\"latency\", m_sessionConstants.EnableMetricsLatency, allocator);\n        systemMetricsJson.AddMember(\"bandwidthDown\", m_sessionConstants.EnableMetricsBandwidthDown, allocator);\n        systemMetricsJson.AddMember(\"bandwidthUp\", m_sessionConstants.EnableMetricsBandwidthUp, allocator);\n        systemMetricsJson.AddMember(\"custom\", m_sessionConstants.EnableMetricsCustom, allocator);\n        systemJson.AddMember(\"metrics\", systemMetricsJson, allocator);\n    }\n\n    if (m_writeMemberInitialization)\n    {\n        JsonValue memberInitializationJson{ rapidjson::kObjectType };\n\n        JsonValue joinTimeoutJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.MemberInitialization->JoinTimeout, joinTimeoutJson);\n        memberInitializationJson.AddMember(\"joinTimeout\", joinTimeoutJson, allocator);\n\n        JsonValue measurementTimeoutJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.MemberInitialization->MeasurementTimeout, measurementTimeoutJson);\n        memberInitializationJson.AddMember(\"measurementTimeout\", measurementTimeoutJson, allocator);\n\n        if (m_sessionConstants.MemberInitialization->ExternalEvaluation)\n        {\n            JsonValue evaluationTimeoutJson;\n            JsonUtils::SerializeUInt52ToJson(m_sessionConstants.MemberInitialization->EvaluationTimeout, evaluationTimeoutJson);\n            memberInitializationJson.AddMember(\"evaluationTimeout\", evaluationTimeoutJson, allocator);\n        }\n\n        memberInitializationJson.AddMember(\"externalEvaluation\", m_sessionConstants.MemberInitialization->ExternalEvaluation, allocator);\n        memberInitializationJson.AddMember(\"membersNeededToStart\", m_sessionConstants.MemberInitialization->MembersNeededToStart, allocator);\n\n        systemJson.AddMember(\"memberInitialization\", memberInitializationJson, allocator);\n    }\n\n    if (m_writePeerToPeerRequirements)\n    {\n        JsonValue peerToPeerRequirementsJson(rapidjson::kObjectType);\n\n        JsonValue latencyMaxJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.PeerToPeerRequirements.LatencyMaximum, latencyMaxJson);\n        peerToPeerRequirementsJson.AddMember(\"latencyMaximum\", latencyMaxJson, allocator);\n\n        peerToPeerRequirementsJson.AddMember(\"bandwidthMinimum\", m_sessionConstants.PeerToPeerRequirements.BandwidthMinimumInKbps, allocator);\n        systemJson.AddMember(\"peerToPeerRequirements\", peerToPeerRequirementsJson, allocator);\n    }\n\n    if (m_writePeerToHostRequirements)\n    {\n        JsonValue peerToHostRequirementsJson(rapidjson::kObjectType);\n\n        JsonValue latencyMaxJson;\n        JsonUtils::SerializeUInt52ToJson(m_sessionConstants.PeerToHostRequirements.LatencyMaximum, latencyMaxJson);\n        peerToHostRequirementsJson.AddMember(\"latencyMaximum\",latencyMaxJson, allocator);\n\n        peerToHostRequirementsJson.AddMember(\"bandwidthDownMinimum\", m_sessionConstants.PeerToHostRequirements.BandwidthDownMinimumInKbps, allocator);\n        peerToHostRequirementsJson.AddMember(\"bandwidthUpMinimum\", m_sessionConstants.PeerToHostRequirements.BandwidthUpMinimumInKbps, allocator);\n        peerToHostRequirementsJson.AddMember(\n            \"hostSelectionMetric\", \n            JsonValue(XblMultiplayerSession::ConvertMultiplayerHostSelectionMetricToString(m_sessionConstants.PeerToHostRequirements.HostSelectionMetric).c_str(), allocator).Move(), \n            allocator\n        );\n\n        systemJson.AddMember(\"peerToHostRequirements\", peerToHostRequirementsJson, allocator);\n    }\n\n    if (m_writeMeasurementServerAddresses)\n    {\n        JsonDocument measurementServerAddressesJson;\n        measurementServerAddressesJson.Parse(m_sessionConstants.MeasurementServerAddressesJson);\n        systemJson.AddMember(\"measurementServerAddresses\", measurementServerAddressesJson, allocator);\n    }\n\n    if (m_sessionConstants.SessionCloudComputePackageConstantsJson != nullptr && m_sessionConstants.SessionCloudComputePackageConstantsJson[0] != 0)\n    {\n        JsonDocument cloudComputePackage{ &allocator };\n        cloudComputePackage.Parse(m_sessionConstants.SessionCloudComputePackageConstantsJson);\n        systemJson.AddMember(\"cloudComputePackage\", cloudComputePackage, allocator);\n    }\n\n    json.AddMember(\"system\", systemJson, allocator);\n\n    if (m_sessionConstants.CustomJson != nullptr && m_sessionConstants.CustomJson[0] != 0)\n    {\n        JsonDocument customJson{ &allocator };\n        customJson.Parse(m_sessionConstants.CustomJson);\n        json.AddMember(\"custom\", customJson, allocator);\n    }\n    else\n    {\n        json.AddMember(\"custom\", JsonValue(rapidjson::kObjectType), allocator);\n    }\n}\n\nvoid XblMultiplayerSession::Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    json.SetObject();\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n\n    if (m_newSession && m_writeConstants)\n    {\n        JsonValue serializedSessionConstants;\n        SerializeSessionConstants(serializedSessionConstants, allocator);\n        json.AddMember(\"constants\", serializedSessionConstants, allocator);\n    }\n\n    if (m_writeRoleTypes)\n    {\n        json.AddMember(\"roleTypes\", m_roleTypes.Serialize(allocator), allocator);\n    }\n\n    JsonValue serializedSessionProperties;\n    SerializeSessionProperties(serializedSessionProperties, allocator);\n    if (!serializedSessionProperties.IsNull() && !serializedSessionProperties.ObjectEmpty())\n    {\n        json.AddMember(\"properties\", serializedSessionProperties, allocator);\n    }\n\n    if (!m_members.empty() || m_leaveSession)\n    {\n        JsonValue memberListJson(rapidjson::kObjectType);\n        for (const auto& member : m_members)\n        {\n            auto internalMember = MultiplayerSessionMember::Get(&member);\n\n            JsonValue memberJson{ rapidjson::kObjectType };\n            internalMember->Serialize(memberJson, allocator);\n            if (memberJson.MemberCount())\n            {\n                memberListJson.AddMember(JsonValue(internalMember->MemberId().c_str(), allocator).Move(), memberJson, allocator);\n            }\n        }\n\n        if (m_leaveSession)\n        {\n            // Write \"me\" : null to leave session.\n            memberListJson.AddMember(\"me\", JsonValue{ rapidjson::kNullType }, allocator);\n        }\n\n        if (memberListJson.MemberCount())\n        {\n            json.AddMember(\"members\", memberListJson, allocator);\n        }\n    }\n\n    if (m_writeServersJson)\n    {\n        JsonDocument serversJson{};\n        serversJson.Parse(m_serversJson.c_str());\n        JsonUtils::SetMember(json, allocator, \"servers\", serversJson);\n    }\n}\n\nbool XblMultiplayerSession::operator==(const XblMultiplayerSession& rhs) const\n{\n    return m_sessionReference == rhs.m_sessionReference;\n}\n\nbool XblMultiplayerSession::IsHost(\n    _In_ const xsapi_internal_string& memberDeviceToken,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& session\n    )\n{\n    if (memberDeviceToken.empty() || session == nullptr)\n    {\n        return false;\n    }\n\n    return utils::str_icmp(memberDeviceToken.data(), session->m_sessionProperties.HostDeviceToken.Value) == 0;\n}\n\nbool XblMultiplayerSession::IsPlayerInSession(\n    _In_ uint64_t xboxUserId,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& session\n    )\n{\n    if (session == nullptr)\n    {\n        return false;\n    }\n\n    for (const auto& member : session->m_members)\n    {\n        if (xboxUserId == member.Xuid)\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nconst XblMultiplayerSessionMember* XblMultiplayerSession::GetPlayerInSession(\n    _In_ uint64_t xboxUserId,\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n    )\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    for (const auto& member : session->m_members)\n    {\n        if (xboxUserId == member.Xuid)\n        {\n            return &member;\n        }\n    }\n    return nullptr;\n}\n\nconst XblMultiplayerSessionMember* XblMultiplayerSession::HostMember(\n    _In_ std::shared_ptr<XblMultiplayerSession> session\n)\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    for (const auto& member : session->m_members)\n    {\n        if (utils::str_icmp(member.DeviceToken.Value, session->m_sessionProperties.HostDeviceToken.Value) == 0)\n        {\n            return &member;\n        }\n    }\n    return nullptr;\n}\n\nHRESULT XblMultiplayerSession::SetTurnCollection(_In_ const xsapi_internal_vector<uint32_t>& turnCollection)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockSession };\n\n    if (turnCollection.empty())\n    {\n        return E_INVALIDARG;\n    }\n\n    m_turnCollection = turnCollection;\n    m_sessionProperties.TurnCollection = m_turnCollection.data();\n    m_sessionProperties.TurnCollectionCount = m_turnCollection.size();\n    m_writePropertiesTurns = true;\n    return S_OK;\n}\n\nbool XblMultiplayerSession::HasSessionPropertyChanged(\n    _In_ const std::shared_ptr<XblMultiplayerSession>& session1,\n    _In_ const std::shared_ptr<XblMultiplayerSession>& session2,\n    _In_ const xsapi_internal_string& _propertyName\n    )\n{\n    if (session1 == nullptr && session2 == nullptr)\n    {\n        return true;\n    }\n\n    if (session1 == nullptr || session2 == nullptr)\n    {\n        return false;\n    }\n\n    auto propertyName = _propertyName;\n\n    JsonDocument customProp1;\n    JsonDocument customProp2;\n    customProp1.Parse(session1->m_sessionCustomPropertiesJson.data());\n    customProp2.Parse(session2->m_sessionCustomPropertiesJson.data());\n\n    if (!customProp1.HasParseError() &&\n        !customProp2.HasParseError())\n    {\n        xsapi_internal_string prop1;\n        xsapi_internal_string prop2;\n\n        bool isInProp1 = SUCCEEDED(JsonUtils::ExtractJsonString(customProp1, propertyName, prop1, true));\n        bool isInProp2 = SUCCEEDED(JsonUtils::ExtractJsonString(customProp2, propertyName, prop2, true));\n\n        if ((isInProp1 && !isInProp2) ||\n            (!isInProp1 && isInProp2))\n        {\n            return true;\n        }\n\n        if (isInProp1 && isInProp2)\n        {\n            return utils::str_icmp(prop1.c_str(), prop2.c_str()) != 0;\n        }\n    }\n\n    return false;\n}\n\nbool XblMultiplayerSession::DoSessionsMatch(\n    _In_ std::shared_ptr<XblMultiplayerSession> lhs,\n    _In_ std::shared_ptr<XblMultiplayerSession> rhs\n    )\n{\n    return lhs != nullptr && rhs != nullptr && *rhs == *lhs;\n}\n\nHRESULT XblMultiplayerSession::DeserializeMatchmakingServer(\n    _In_ const JsonValue& serversMatchmakingJson\n)\n{\n    if (serversMatchmakingJson.IsObject() && serversMatchmakingJson.HasMember(\"properties\"))\n    {\n        const JsonValue& serversMatchmakingPropertiesJson = serversMatchmakingJson[\"properties\"];\n\n        if (serversMatchmakingPropertiesJson.IsObject() && serversMatchmakingPropertiesJson.HasMember(\"system\"))\n        {\n            const JsonValue& json = serversMatchmakingPropertiesJson[\"system\"];\n\n            if (!json.IsNull())\n            {\n                m_matchmakingServer = MakeShared<XblMultiplayerMatchmakingServer>();\n\n                xsapi_internal_string status;\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"status\", status));\n                m_matchmakingServer->Status = XblMultiplayerSession::ConvertStringToMatchmakingStatus(status);\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"statusDetails\", m_matchmakingStatusDetails));\n                m_matchmakingServer->StatusDetails = m_matchmakingStatusDetails.data();\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"typicalWait\", m_matchmakingServer->TypicalWaitInSeconds));\n\n                if (json.IsObject() && json.HasMember(\"targetSessionRef\"))\n                {\n                    m_matchmakingServer->TargetSessionRef = Serializers::DeserializeSessionReference(json[\"targetSessionRef\"]).Payload();\n                }\n                else\n                {\n                    m_matchmakingServer->TargetSessionRef = XblMultiplayerSessionReference();\n                }\n            }\n        }\n    }\n\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::DeserializeSessionProperties(\n    _In_ const JsonValue& json\n)\n{\n    if (json.IsObject() && json.HasMember(\"system\"))\n    {\n        const JsonValue& systemJson = json[\"system\"];\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<const char*>(JsonUtils::JsonUtf8Extractor, systemJson, \"keywords\", m_keywords, false));\n        m_sessionProperties.KeywordCount = m_keywords.size();\n        m_sessionProperties.Keywords = m_keywords.data();\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint32_t>(JsonUtils::JsonIntExtractor, systemJson, \"owners\", m_sessionOwnerIndices, false));\n        m_sessionProperties.SessionOwnerMemberIdsCount = m_sessionOwnerIndices.size();\n        m_sessionProperties.SessionOwnerMemberIds = m_sessionOwnerIndices.data();\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint32_t>(JsonUtils::JsonIntExtractor, systemJson, \"turn\", m_turnCollection, false));\n        m_sessionProperties.TurnCollectionCount = static_cast<uint32_t>(m_turnCollection.size());\n        m_sessionProperties.TurnCollection = m_turnCollection.data();\n\n        xsapi_internal_string joinRestrictionString;\n        xsapi_internal_string readRestrictionString;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(systemJson, \"joinRestriction\", joinRestrictionString));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(systemJson, \"readRestriction\", readRestrictionString));\n        if (!joinRestrictionString.empty())\n        {\n            m_sessionProperties.JoinRestriction = Serializers::MultiplayerSessionRestrictionFromString(joinRestrictionString);\n        }\n\n        if (!readRestrictionString.empty())\n        {\n            m_sessionProperties.ReadRestriction = Serializers::MultiplayerSessionRestrictionFromString(readRestrictionString);\n        }\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemJson, \"closed\", m_sessionProperties.Closed));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemJson, \"locked\", m_sessionProperties.Locked));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemJson, \"allocateCloudCompute\", m_sessionProperties.AllocateCloudCompute));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemJson, \"matchmakingResubmit\", m_sessionProperties.MatchmakingResubmit));\n\n        if (systemJson.IsObject() && systemJson.HasMember(\"matchmaking\"))\n        {\n            const JsonValue& systemMatchmakingJson = systemJson[\"matchmaking\"];\n\n            if (systemMatchmakingJson.IsObject() && systemMatchmakingJson.HasMember(\"targetSessionConstants\"))\n            {\n                m_matchmakingTargetSessionConstantsJson = JsonUtils::SerializeJson(\n                    systemMatchmakingJson[\"targetSessionConstants\"]\n                );\n            }\n\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(systemMatchmakingJson, \"serverConnectionString\", m_matchmakingServerConnectionString));\n            m_sessionProperties.MatchmakingServerConnectionString = m_matchmakingServerConnectionString.data();\n        }\n\n        m_sessionProperties.MatchmakingTargetSessionConstantsJson = m_matchmakingTargetSessionConstantsJson.data();\n\n        xsapi_internal_string host;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(systemJson, \"host\", host));\n        utils::strcpy(\n            m_sessionProperties.HostDeviceToken.Value,\n            sizeof(m_sessionProperties.HostDeviceToken),\n            host.c_str()\n        );\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<const char*>(JsonUtils::JsonUtf8Extractor, systemJson, \"serverConnectionStringCandidates\", m_serverConnectionStringCandidates, false));\n        m_sessionProperties.ServerConnectionStringCandidatesCount = static_cast<uint32_t>(m_serverConnectionStringCandidates.size());\n        m_sessionProperties.ServerConnectionStringCandidates = m_serverConnectionStringCandidates.data();\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    if (json.IsObject() && json.HasMember(\"custom\"))\n    {\n        m_sessionCustomPropertiesJson = JsonUtils::SerializeJson(json[\"custom\"]);\n    }\n    m_sessionProperties.SessionCustomPropertiesJson = m_sessionCustomPropertiesJson.data();\n\n    return S_OK;\n}\n\nHRESULT XblMultiplayerSession::DeserializeSessionConstants(\n    _In_ const JsonValue& json\n)\n{\n    if (!json.IsObject()) \n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    if (json.HasMember(\"system\"))\n    {\n        const JsonValue& systemJson = json[\"system\"];\n\n        if (systemJson.IsObject())\n        {\n            if (systemJson.HasMember(\"cloudComputePackage\"))\n            {\n                m_constantsCloudComputePackageJson = JsonUtils::SerializeJson(systemJson[\"cloudComputePackage\"]);\n                m_sessionConstants.SessionCloudComputePackageConstantsJson = m_constantsCloudComputePackageJson.data();\n            }\n\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(systemJson, \"maxMembersCount\", m_sessionConstants.MaxMembersInSession));\n\n            xsapi_internal_string visibility;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(systemJson, \"visibility\", visibility));\n            m_sessionConstants.Visibility = Serializers::MultiplayerSessionVisibilityFromString(visibility);\n\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint64_t>(JsonUtils::JsonXuidExtractor, systemJson, \"initiators\", m_initiatorXuids, false));\n            m_sessionConstants.InitiatorXuids = m_initiatorXuids.data();\n            m_sessionConstants.InitiatorXuidsCount = m_initiatorXuids.size();\n\n            if (systemJson.HasMember(\"capabilities\"))\n            {\n                const JsonValue& systemCapabilitiesJson = systemJson[\"capabilities\"];\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"connectivity\", m_sessionConstants.SessionCapabilities.Connectivity, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"suppressPresenceActivityCheck\", m_sessionConstants.SessionCapabilities.SuppressPresenceActivityCheck, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"gameplay\", m_sessionConstants.SessionCapabilities.Gameplay, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"large\", m_sessionConstants.SessionCapabilities.Large, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"connectionRequiredForActiveMembers\", m_sessionConstants.SessionCapabilities.ConnectionRequiredForActiveMembers, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"userAuthorizationStyle\", m_sessionConstants.SessionCapabilities.UserAuthorizationStyle, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"crossPlay\", m_sessionConstants.SessionCapabilities.Crossplay, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"hasOwners\", m_sessionConstants.SessionCapabilities.HasOwners, false));\n                 RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemCapabilitiesJson, \"searchable\", m_sessionConstants.SessionCapabilities.Searchable, false));\n            }\n            else\n            {\n                m_sessionConstants.SessionCapabilities.Connectivity = false;\n                m_sessionConstants.SessionCapabilities.SuppressPresenceActivityCheck = false;\n                m_sessionConstants.SessionCapabilities.Gameplay = false;\n                m_sessionConstants.SessionCapabilities.Large = false;\n                m_sessionConstants.SessionCapabilities.ConnectionRequiredForActiveMembers = false;\n                m_sessionConstants.SessionCapabilities.UserAuthorizationStyle = false;\n                m_sessionConstants.SessionCapabilities.Crossplay = false;\n                m_sessionConstants.SessionCapabilities.HasOwners = false;\n                m_sessionConstants.SessionCapabilities.Searchable = false;\n            }\n\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(systemJson, \"reservedRemovalTimeout\", m_sessionConstants.MemberReservedTimeout, false));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(systemJson, \"inactiveRemovalTimeout\", m_sessionConstants.MemberInactiveTimeout, false));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(systemJson, \"readyRemovalTimeout\", m_sessionConstants.MemberReadyTimeout, false));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(systemJson, \"sessionEmptyTimeout\", m_sessionConstants.SessionEmptyTimeout, false));\n\n            if (systemJson.HasMember(\"metrics\"))\n            {\n                const JsonValue& systemMetricsJson = systemJson[\"metrics\"];\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemMetricsJson, \"latency\", m_sessionConstants.EnableMetricsLatency, false));\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemMetricsJson, \"bandwidthDown\", m_sessionConstants.EnableMetricsBandwidthDown, false));\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemMetricsJson, \"bandwidthUp\", m_sessionConstants.EnableMetricsBandwidthUp, false));\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(systemMetricsJson, \"custom\", m_sessionConstants.EnableMetricsCustom, false));\n            }\n            else\n            {\n                m_sessionConstants.EnableMetricsLatency = false;\n                m_sessionConstants.EnableMetricsBandwidthDown = false;\n                m_sessionConstants.EnableMetricsBandwidthUp = false;\n                m_sessionConstants.EnableMetricsCustom = false;\n            }\n\n            if (systemJson.HasMember(\"memberInitialization\"))\n            {\n                const JsonValue& memberInitializationJson = systemJson[\"memberInitialization\"];\n                if (!memberInitializationJson.IsNull())\n                {\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(memberInitializationJson, \"joinTimeout\", m_memberInitialization.JoinTimeout));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(memberInitializationJson, \"measurementTimeout\", m_memberInitialization.MeasurementTimeout));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(memberInitializationJson, \"evaluationTimeout\", m_memberInitialization.EvaluationTimeout));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(memberInitializationJson, \"externalEvaluation\", m_memberInitialization.ExternalEvaluation));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(memberInitializationJson, \"membersNeededToStart\", m_memberInitialization.MembersNeededToStart));\n                    m_sessionConstants.MemberInitialization = &m_memberInitialization;\n                }\n            }\n\n            if (systemJson.HasMember(\"peerToHostRequirements\"))\n            {\n                const JsonValue& peerToHostRequirementsJson = systemJson[\"peerToHostRequirements\"];\n                if (!peerToHostRequirementsJson.IsNull())\n                {\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(peerToHostRequirementsJson, \"latencyMaximum\", m_sessionConstants.PeerToHostRequirements.LatencyMaximum));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(peerToHostRequirementsJson, \"bandwidthDownMinimum\", m_sessionConstants.PeerToHostRequirements.BandwidthDownMinimumInKbps));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(peerToHostRequirementsJson, \"bandwidthUpMinimum\", m_sessionConstants.PeerToHostRequirements.BandwidthUpMinimumInKbps));\n                    xsapi_internal_string hostSelectionMetric;\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"hostSelectionMetric\", hostSelectionMetric));\n                    m_sessionConstants.PeerToHostRequirements.HostSelectionMetric = XblMultiplayerSession::ConvertStringToMultiplayerHostSelectionMetric(hostSelectionMetric);\n                }\n            }\n\n            if (systemJson.HasMember(\"peerToPeerRequirements\"))\n            {\n                const JsonValue& peerToPeerRequirementsJson = systemJson[\"peerToPeerRequirements\"];\n                if (!peerToPeerRequirementsJson.IsNull())\n                {\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(peerToPeerRequirementsJson, \"latencyMaximum\", m_sessionConstants.PeerToPeerRequirements.LatencyMaximum));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(peerToPeerRequirementsJson, \"bandwidthMinimum\", m_sessionConstants.PeerToPeerRequirements.BandwidthMinimumInKbps));\n                }\n            }\n\n            if (systemJson.HasMember(\"measurementServerAddresses\"))\n            {\n                m_constantsMeasurementServerAddressesJson = JsonUtils::SerializeJson(systemJson[\"measurementServerAddresses\"]);\n                m_sessionConstants.MeasurementServerAddressesJson = m_constantsMeasurementServerAddressesJson.data();\n            }\n        }\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    if (json.HasMember(\"custom\"))\n    {\n        m_constantsCustomJson = JsonUtils::SerializeJson(json[\"custom\"]);\n        m_sessionConstants.CustomJson = m_constantsCustomJson.data();\n    }\n\n    return S_OK;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nRoleTypes::RoleTypes(const RoleTypes& other) noexcept\n    : m_values{ other.m_values }\n{\n    for (auto& roleType : m_values)\n    {\n        roleType.Name = Make(roleType.Name);\n        roleType.Roles = MakeArray(roleType.Roles, roleType.RoleCount);\n\n        for (size_t i = 0; i < roleType.RoleCount; ++i)\n        {\n            roleType.Roles[i].RoleType = &roleType;\n            roleType.Roles[i].Name = Make(roleType.Roles[i].Name);\n            roleType.Roles[i].MemberXuids = MakeArray(roleType.Roles[i].MemberXuids, roleType.Roles[i].MemberCount);\n        }\n    }\n}\n\nRoleTypes& RoleTypes::operator=(RoleTypes other) noexcept\n{\n    std::swap(other.m_values, m_values);\n    return *this;\n}\n\nRoleTypes::~RoleTypes() noexcept\n{\n    for (auto& roleType : m_values)\n    {\n        Delete(roleType.Name);\n        for (size_t i = 0; i < roleType.RoleCount; ++i)\n        {\n            Delete(roleType.Roles[i].Name);\n            Delete(roleType.Roles[i].MemberXuids);\n        }\n        Delete(roleType.Roles);\n    }\n}\n\nResult<RoleTypes> RoleTypes::Deserialize(const JsonValue& json) noexcept\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    RoleTypes roleTypes{};\n    roleTypes.m_values.reserve(json.MemberCount());\n\n    for (const auto& roleTypeJson : json.GetObject())\n    {\n        roleTypes.m_values.push_back(XblMultiplayerRoleType{});\n        auto& roleType{ roleTypes.m_values.back() };\n\n        roleType.Name = Make(roleTypeJson.name.GetString());\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(roleTypeJson.value, \"ownerManaged\", roleType.OwnerManaged, false));\n\n        Vector<String> mutableSettingsVector;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<String>(JsonUtils::JsonStringExtractor, roleTypeJson.value, \"mutableRoleSettings\", mutableSettingsVector, false));\n        for (auto& setting : mutableSettingsVector)\n        {\n            if (utils::str_icmp_internal(setting, \"max\") == 0)\n            {\n                roleType.MutableRoleSettings |= XblMutableRoleSettings::Max;\n            }\n            else if (utils::str_icmp_internal(setting, \"target\") == 0)\n            {\n                roleType.MutableRoleSettings |= XblMutableRoleSettings::Target;\n            }\n        }\n\n        if (roleTypeJson.value.HasMember(\"roles\"))\n        {\n            const auto& rolesJson = roleTypeJson.value[\"roles\"];\n            if (rolesJson.IsObject())\n            {\n                roleType.Roles = MakeArray<XblMultiplayerRole>(rolesJson.MemberCount());\n\n                for (const auto& roleJson : rolesJson.GetObject())\n                {\n                    auto& role{ roleType.Roles[roleType.RoleCount++] };\n\n                    role.RoleType = &roleType;\n                    role.Name = Make(roleJson.name.GetString());\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(roleJson.value, \"count\", role.MemberCount, false));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(roleJson.value, \"max\", role.MaxMemberCount, false));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(roleJson.value, \"target\", role.TargetCount, false));\n                    if (role.MemberCount > 0)\n                    {\n                        Vector<uint64_t> memberXuidsVector;\n                        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint64_t>(JsonUtils::JsonXuidExtractor, roleJson.value, \"memberXuids\", memberXuidsVector, true));\n                        role.MemberXuids = MakeArray(memberXuidsVector);\n                    }\n                }\n            }\n        }\n    }\n\n    return roleTypes;\n}\n\nJsonValue RoleTypes::Serialize(JsonDocument::AllocatorType& a) const noexcept\n{\n    JsonValue roleTypesJson{ rapidjson::Type::kObjectType };\n    for (const auto& roleType : m_values)\n    {\n        JsonValue roleTypeJson{ rapidjson::kObjectType };\n        JsonValue rolesJson{ rapidjson::kObjectType };\n\n        for (size_t i = 0; i < roleType.RoleCount; ++i)\n        {\n            auto& role = roleType.Roles[i];\n            JsonValue roleJson{ rapidjson::kObjectType };\n            if (role.MaxMemberCount)\n            {\n                roleJson.AddMember(\"max\", role.MaxMemberCount, a);\n            }\n            if (role.TargetCount > 0)\n            {\n                roleJson.AddMember(\"target\", role.TargetCount, a);\n            }\n            rolesJson.AddMember(JsonValue{ role.Name, a }.Move(), roleJson, a);\n        }\n        roleTypeJson.AddMember(\"roles\", rolesJson, a);\n        roleTypesJson.AddMember(JsonValue{ roleType.Name, a }.Move(), roleTypeJson, a);\n    }\n    return roleTypesJson;\n}\n\nconst Vector<XblMultiplayerRoleType>& RoleTypes::Values() const noexcept\n{\n    return m_values;\n}\n\nHRESULT RoleTypes::SetRoleSettings(\n    String&& roleTypeName,\n    String&& roleName,\n    uint32_t* maxCount,\n    uint32_t* targetCount\n) noexcept\n{\n    auto role{ GetRole(std::move(roleTypeName), std::move(roleName)) };\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(role);\n\n    bool maxMutable{ (role->RoleType->MutableRoleSettings | XblMutableRoleSettings::Max) != XblMutableRoleSettings::None };\n    bool targetMutable{ (role->RoleType->MutableRoleSettings | XblMutableRoleSettings::Target) != XblMutableRoleSettings::None };\n    RETURN_HR_IF((maxCount && !maxMutable) || (targetCount && !targetMutable), E_UNEXPECTED);\n\n    if (maxCount)\n    {\n        role->MaxMemberCount = *maxCount;\n    }\n    if (targetCount)\n    {\n        role->TargetCount = *targetCount;\n    }\n\n    return S_OK;\n}\n\nXblMultiplayerRole* RoleTypes::GetRole(\n    String&& roleTypeName,\n    String&& roleName\n) const noexcept\n{\n    // Could store these in a map to make lookup quicker but the collection of roles should be small\n    for (const auto& roleType : m_values)\n    {\n        if (Stricmp(roleType.Name, roleTypeName.data()) == 0)\n        {\n            for (size_t i = 0; i < roleType.RoleCount; ++i)\n            {\n                if (Stricmp(roleType.Roles[i].Name, roleName.data()) == 0)\n                {\n                    return &roleType.Roles[i];\n                }\n            }\n            break;\n        }\n    }\n    return nullptr;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END\n\nSTDAPI_(XblMultiplayerSessionHandle) XblMultiplayerSessionCreateHandle(\n    _In_ uint64_t xuid,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n    _In_opt_ const XblMultiplayerSessionInitArgs* initArgs\n) XBL_NOEXCEPT\ntry\n{\n    auto session = MakeShared<XblMultiplayerSession>(xuid, sessionReference, initArgs);\n    session->AddRef();\n    return session.get();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI XblMultiplayerSessionDuplicateHandle(\n    _In_ XblMultiplayerSessionHandle session,\n    _Out_ XblMultiplayerSessionHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(session == nullptr || duplicatedHandle == nullptr);\n\n    session->AddRef();\n    *duplicatedHandle = session;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerSessionCloseHandle(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session)\n    {\n        session->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(XblTournamentArbitrationStatus) XblMultiplayerSessionArbitrationStatus(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(session);\n    return XblTournamentArbitrationStatus::Incomplete;\n}\nCATCH_RETURN_WITH(XblTournamentArbitrationStatus::Incomplete)\n\nSTDAPI_(time_t) XblMultiplayerSessionTimeOfSession(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return 0;\n    }\n\n    return session->TimeOfSession();\n}\nCATCH_RETURN()\n\nSTDAPI_(const XblMultiplayerSessionInitializationInfo*) XblMultiplayerSessionGetInitializationInfo(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return &session->InitializationInfo();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(XblMultiplayerSessionChangeTypes) XblMultiplayerSessionSubscribedChangeTypes(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return XblMultiplayerSessionChangeTypes::None;\n    }\n\n    if (session->CurrentUserUnsafe() == nullptr)\n    {\n        return XblMultiplayerSessionChangeTypes::None;\n    }\n    return MultiplayerSessionMember::Get(session->CurrentUserUnsafe())->SubscribedChangeTypes();\n}\nCATCH_RETURN_WITH(XblMultiplayerSessionChangeTypes::None)\n\nSTDAPI XblMultiplayerSessionHostCandidates(\n    _In_ XblMultiplayerSessionHandle session,\n    _Out_ const XblDeviceToken** deviceTokens,\n    _Out_ size_t* deviceTokensCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(deviceTokens == nullptr || deviceTokensCount == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n\n    *deviceTokens = session->HostCandidates().data();\n    *deviceTokensCount = session->HostCandidates().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(const XblMultiplayerSessionReference*) XblMultiplayerSessionSessionReference(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return &session->SessionReference();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerSessionConstants*) XblMultiplayerSessionSessionConstants(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return &session->SessionConstantsUnsafe();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(void) XblMultiplayerSessionConstantsSetMaxMembersInSession(\n    _In_ XblMultiplayerSessionHandle session,\n    uint32_t maxMembersInSession\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetMaxMembersInSession(maxMembersInSession);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionConstantsSetVisibility(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerSessionVisibility visibility\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetVisibility(visibility);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblMultiplayerSessionConstantsSetTimeouts(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ uint64_t memberReservedTimeout,\n    _In_ uint64_t memberInactiveTimeout,\n    _In_ uint64_t memberReadyTimeout,\n    _In_ uint64_t sessionEmptyTimeout\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetTimeouts(memberReservedTimeout, memberInactiveTimeout, memberReadyTimeout, sessionEmptyTimeout);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetArbitrationTimeouts(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ uint64_t arbitrationTimeout,\n    _In_ uint64_t forfeitTimeout\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(session);\n    UNREFERENCED_PARAMETER(arbitrationTimeout);\n    UNREFERENCED_PARAMETER(forfeitTimeout);\n\n    return E_NOTIMPL;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetQosConnectivityMetrics(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ bool enableLatencyMetric,\n    _In_ bool enableBandwidthDownMetric,\n    _In_ bool enableBandwidthUpMetric,\n    _In_ bool enableCustomMetric\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetQosConnectivityMetrics(enableLatencyMetric, enableBandwidthDownMetric, enableBandwidthUpMetric, enableCustomMetric);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetMemberInitialization(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerMemberInitialization memberInitialization\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetMemberInitialization(std::move(memberInitialization));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetPeerToPeerRequirements(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerPeerToPeerRequirements requirements\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetPeerToPeerRequirements(std::move(requirements));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetPeerToHostRequirements(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerPeerToHostRequirements requirements\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetPeerToHostRequirements(std::move(requirements));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const char* measurementServerAddressesJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(session == nullptr || measurementServerAddressesJson == nullptr);\n    return session->SetMeasurementServerAddresses(measurementServerAddressesJson);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetCapabilities(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerSessionCapabilities capabilities\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetSessionCapabilities(std::move(capabilities));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionConstantsSetCloudComputePackageJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const char* sessionCloudComputePackageConstantsJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetCloudComputePackageJson(sessionCloudComputePackageConstantsJson);\n}\nCATCH_RETURN()\n\nSTDAPI_(const XblMultiplayerSessionProperties*) XblMultiplayerSessionSessionProperties(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return &session->SessionPropertiesUnsafe();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI XblMultiplayerSessionPropertiesSetKeywords(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const char** keywords,\n    _In_ size_t keywordsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetKeywords(keywords, keywordsCount);\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerSessionPropertiesSetJoinRestriction(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerSessionRestriction joinRestriction\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetJoinRestriction(joinRestriction);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionPropertiesSetReadRestriction(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerSessionRestriction readRestriction\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetReadRestriction(readRestriction);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblMultiplayerSessionPropertiesSetTurnCollection(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const uint32_t* turnCollectionMemberIds,\n    _In_ size_t turnCollectionMemberIdsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetTurnCollection(xsapi_internal_vector<uint32_t>(turnCollectionMemberIds, turnCollectionMemberIds + turnCollectionMemberIdsCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionRoleTypes(\n    _In_ XblMultiplayerSessionHandle session,\n    _Out_ const XblMultiplayerRoleType** roleTypes,\n    _Out_ size_t* roleTypesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF(roleTypes == nullptr || roleTypesCount == nullptr);\n\n    *roleTypes = session->RoleTypesUnsafe().Values().data();\n    *roleTypesCount = session->RoleTypesUnsafe().Values().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionGetRoleByName(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* roleTypeName,\n    _In_z_ const char* roleName,\n    _Out_ const XblMultiplayerRole** role\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF(roleTypeName == nullptr || roleName == nullptr || role == nullptr);\n    *role = session->RoleTypesUnsafe().GetRole(roleTypeName, roleName);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionSetMutableRoleSettings(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* roleTypeName,\n    _In_z_ const char* roleName,\n    _In_opt_ uint32_t* maxMemberCount,\n    _In_opt_ uint32_t* targetMemberCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF(roleTypeName == nullptr || roleName == nullptr);\n    return session->SetMutableRoleSettings(roleTypeName, roleName, maxMemberCount, targetMemberCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionMembers(\n    _In_ XblMultiplayerSessionHandle session,\n    _Out_ const XblMultiplayerSessionMember** members,\n    _Out_ size_t* membersCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF(members == nullptr || membersCount == nullptr);\n\n    *members = session->MembersUnsafe().data();\n    *membersCount = session->MembersUnsafe().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(const XblMultiplayerSessionMember*) XblMultiplayerSessionGetMember(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ uint32_t memberId\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    // Could store these in a map to improve lookup but member count should not be large\n    auto& members = session->MembersUnsafe();\n    for (const auto& member : members)\n    {\n        if (member.MemberId == memberId)\n        {\n            return &member;\n        }\n    }\n    return nullptr;\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerMatchmakingServer*) XblMultiplayerSessionMatchmakingServer(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return session->MatchmakingServer().get();\n}\nCATCH_RETURN_WITH(nullptr)\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\nSTDAPI_(const XblMultiplayerTournamentsServer*) XblMultiplayerSessionTournamentsServer(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(session);\n    return nullptr;\n}\nCATCH_RETURN_WITH(nullptr)\nXBL_WARNING_POP\n\nXBL_WARNING_PUSH\nXBL_WARNING_DISABLE_DEPRECATED\nSTDAPI_(const XblMultiplayerArbitrationServer*) XblMultiplayerSessionArbitrationServer(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(session);\n    return nullptr;\n}\nCATCH_RETURN_WITH(nullptr)\nXBL_WARNING_POP\n\nSTDAPI_(uint32_t) XblMultiplayerSessionMembersAccepted(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return 0;\n    }\n\n    return session->MembersAccepted();\n}\nCATCH_RETURN()\n\nSTDAPI_(const char*) XblMultiplayerSessionRawServersJson(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return session->RawServersJsonUnsafe().data();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI XblMultiplayerSessionSetRawServersJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* rawServersJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetServersJson(rawServersJson);\n}\nCATCH_RETURN()\n\nSTDAPI_(const char*) XblMultiplayerSessionEtag(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return session->ETagUnsafe().data();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerSessionMember*) XblMultiplayerSessionCurrentUser(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return session->CurrentUserUnsafe();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(const XblMultiplayerSessionInfo*) XblMultiplayerSessionGetInfo(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return nullptr;\n    }\n\n    return &session->SessionInfo();\n}\nCATCH_RETURN_WITH(nullptr)\n\nSTDAPI_(XblWriteSessionStatus) XblMultiplayerSessionWriteStatus(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        // TODO: is this correct?\n        return XblWriteSessionStatus::Unknown;\n    }\n    else\n    {\n        return session->WriteStatus();\n    }\n}\nCATCH_RETURN_WITH(XblWriteSessionStatus::Unknown)\n\nSTDAPI XblMultiplayerSessionAddMemberReservation(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ uint64_t xuid,\n    _In_opt_z_ const char* memberCustomConstantsJson,\n    _In_ bool initializeRequested\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->AddMemberReservation(xuid, memberCustomConstantsJson, initializeRequested);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionJoin(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_opt_z_ const char* memberCustomConstantsJson,\n    _In_ bool initializeRequested,\n    _In_ bool joinWithActiveStatus\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->Join(memberCustomConstantsJson, initializeRequested, joinWithActiveStatus);\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblMultiplayerSessionSetInitializationSucceeded(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ bool initializationSucceeded\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetInitializationStatus(initializationSucceeded);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionSetHostDeviceToken(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblDeviceToken hostDeviceToken\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetHostDeviceToken(hostDeviceToken);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionSetMatchmakingServerConnectionPath(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* serverConnectionPath\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    return session->SetMatchmakingServerConnectionPath(serverConnectionPath);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionSetClosed(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ bool closed\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetClosed(closed);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionSetLocked(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ bool locked\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetLocked(locked);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionSetAllocateCloudCompute(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ bool allocateCloudCompute\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetAllocateCloudCompute(allocateCloudCompute);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(void) XblMultiplayerSessionSetMatchmakingResubmit(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ bool matchResubmit\n) XBL_NOEXCEPT\ntry\n{\n    if (session == nullptr)\n    {\n        return;\n    }\n\n    session->SetMatchmakingResubmit(matchResubmit);\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblMultiplayerSessionSetServerConnectionStringCandidates(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_reads_(serverConnectionStringCandidatesCount) const char** serverConnectionStringCandidates,\n    _In_ size_t serverConnectionStringCandidatesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetServerConnectionStringCandidates(serverConnectionStringCandidates, serverConnectionStringCandidatesCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionSetSessionChangeSubscription(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerSessionChangeTypes changeTypes\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetSessionChangeSubscription(changeTypes);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionLeave(\n    _In_ XblMultiplayerSessionHandle session\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->Leave();\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetStatus(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ XblMultiplayerSessionMemberStatus status\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetCurrentUserStatus(status);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const char* value\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    return session->SetCurrentUserSecureDeviceAddressBase64(value);\n}\nCATCH_RETURN()\n\n#if HC_PLATFORM != HC_PLATFORM_XDK && HC_PLATFORM != HC_PLATFORM_UWP\nSTDAPI XblFormatSecureDeviceAddress(\n    _In_ const char* deviceId,\n    _Inout_ XblFormattedSecureDeviceAddress* address\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(address);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(deviceId);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(deviceId);\n\n    auto sda = utils::format_secure_device_address(deviceId);\n    utils::strcpy(address->value, sizeof(address->value), sda.c_str());\n    return S_OK;\n}\nCATCH_RETURN()\n#endif\n\nSTDAPI XblMultiplayerSessionCurrentUserSetRoles(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const XblMultiplayerSessionMemberRole* roles,\n    _In_ size_t rolesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(roles);\n    return session->SetCurrentUserRoleInfo(xsapi_internal_vector<XblMultiplayerSessionMemberRole>(roles, roles + rolesCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetMembersInGroup(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_reads_(memberIdsCount) uint32_t* memberIds,\n    _In_ size_t memberIdsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(memberIds);\n    return session->SetCurrentUserMembersInGroup(xsapi_internal_vector<uint32_t>(memberIds, memberIds + memberIdsCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetGroups(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_reads_(groupsCount) const char** groups,\n    _In_ size_t groupsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(groups);\n    return session->SetCurrentUserGroups(groups, groupsCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetEncounters(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_reads_(encountersCount) const char** encounters,\n    _In_ size_t encountersCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(encounters);\n    return session->SetCurrentUserEncounters(encounters, encountersCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetQosMeasurements(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* measurements\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(measurements);\n    return session->SetCurrentUserQosMeasurementsJson(measurements);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetServerQosMeasurements(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* measurements\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(measurements);\n    return session->SetCurrentUserServerMeasurementsJson(measurements);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserSetCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n    JsonDocument valueJsonObject;\n    auto hr = JsonUtils::ValidateJson(valueJson, valueJsonObject);\n    if (SUCCEEDED(hr))\n    {\n        hr = session->SetCurrentUserMemberCustomPropertyJson(name, valueJsonObject);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* name\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(name);\n    return session->DeleteCurrentUserMemberCustomPropertyJson(name);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_ const char* matchmakingTargetSessionConstantsJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(session == nullptr || matchmakingTargetSessionConstantsJson == nullptr);\n    return session->SetMatchmakingTargetSessionConstantsJson(matchmakingTargetSessionConstantsJson);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionSetCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* name,\n    _In_z_ const char* valueJson\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF(name == nullptr || valueJson == nullptr);\n\n    JsonDocument valueJsonObject;\n    auto hr = JsonUtils::ValidateJson(valueJson, valueJsonObject);\n    if (SUCCEEDED(hr))\n    {\n        hr = session->SetSessionCustomPropertyJson(name, valueJsonObject);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionDeleteCustomPropertyJson(\n    _In_ XblMultiplayerSessionHandle session,\n    _In_z_ const char* name\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(session);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(name);\n    return session->DeleteSessionCustomPropertyJson(name);\n}\nCATCH_RETURN()\n\nSTDAPI_(XblMultiplayerSessionChangeTypes) XblMultiplayerSessionCompare(\n    _In_ XblMultiplayerSessionHandle currentSessionHandle,\n    _In_ XblMultiplayerSessionHandle oldSessionHandle\n) XBL_NOEXCEPT\ntry\n{\n    if (currentSessionHandle == nullptr || oldSessionHandle == nullptr)\n    {\n        return XblMultiplayerSessionChangeTypes::None;\n    }\n    return currentSessionHandle->CompareMultiplayerSessions(oldSessionHandle->shared_from_this());\n}\nCATCH_RETURN_WITH(XblMultiplayerSessionChangeTypes::None)\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_session_member.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nXblMultiplayerSessionMember MultiplayerSessionMember::Construct(\n    _In_ bool isCurrentUser,\n    _In_ const xsapi_internal_string& memberIdToWrite,\n    _In_ uint64_t xuid,\n    _In_opt_z_ const char* customConstantsJson,\n    _In_ bool initializeRequested\n)\n{\n    XblMultiplayerSessionMember member{};\n\n    auto memberInternal = Make<MultiplayerSessionMember>(memberIdToWrite);\n    member.Internal = memberInternal;\n\n    member.Xuid = xuid;\n    member.IsCurrentUser = isCurrentUser;\n    if (customConstantsJson)\n    {\n        memberInternal->m_customConstantsJson = customConstantsJson;\n        member.CustomConstantsJson = memberInternal->m_customConstantsJson.data();\n    }\n    member.Nat = XblNetworkAddressTranslationSetting::Unknown;\n    member.InitializationFailureCause = XblMultiplayerMeasurementFailure::None;\n    memberInternal->m_subscribedChangeTypes = XblMultiplayerSessionChangeTypes::None;\n    member.InitializeRequested = initializeRequested;\n    return member;\n}\n\nMultiplayerSessionMember::MultiplayerSessionMember(const xsapi_internal_string& memberIdToWrite)\n    : MultiplayerSessionMember()\n{\n    m_memberIdToWrite = memberIdToWrite;\n    m_newMember = true;\n}\n\nMultiplayerSessionMember::MultiplayerSessionMember(const MultiplayerSessionMember& other) :\n    m_customConstantsJson(other.m_customConstantsJson),\n    m_customPropertiesString(other.m_customPropertiesString),\n    m_secureDeviceAddressBase64(other.m_secureDeviceAddressBase64),\n    m_roles(other.m_roles),\n    m_teamId(other.m_teamId),\n    m_initialTeam(other.m_initialTeam),\n    m_membersInGroupIds(other.m_membersInGroupIds),\n    m_subscribedChangeTypes(other.m_subscribedChangeTypes),\n    m_matchmakingResultServerMeasurementsJson(other.m_matchmakingResultServerMeasurementsJson),\n    m_serverMeasurementsJson(other.m_serverMeasurementsJson),\n    m_qosMeasurementsJson(other.m_qosMeasurementsJson),\n    m_subscriptionId(other.m_subscriptionId),\n    m_rtaConnectionId(other.m_rtaConnectionId),\n    m_memberIdToWrite(other.m_memberIdToWrite),\n    m_newMember(other.m_newMember),\n    m_writeConstants(other.m_writeConstants),\n    m_writeIsActive(other.m_writeIsActive),\n    m_writeRoleInfo(other.m_writeRoleInfo),\n    m_writeSecureDeviceAddressBase64(other.m_writeSecureDeviceAddressBase64),\n    m_writeQoSMeasurementsJson(other.m_writeQoSMeasurementsJson),\n    m_writeServerMeasurementsJson(other.m_writeServerMeasurementsJson),\n    m_writeMembersInGroup(other.m_writeMembersInGroup),\n    m_writeGroups(other.m_writeGroups),\n    m_writeEncounters(other.m_writeEncounters),\n    m_writeSubscribedChangeTypes(other.m_writeSubscribedChangeTypes),\n    m_writeResults(other.m_writeResults),\n    m_writeCustomPropertiesJson(other.m_writeCustomPropertiesJson)\n{\n    for (auto group : other.m_groups)\n    {\n        m_groups.push_back(Make(group));\n    }\n    for (auto encounter : other.m_encounters)\n    {\n        m_encounters.push_back(Make(encounter));\n    }\n    for (auto& role : m_roles)\n    {\n        role.roleName = Make(role.roleName);\n        role.roleTypeName = Make(role.roleTypeName);\n    }\n\n    JsonUtils::CopyFrom(m_customPropertiesJson, other.m_customPropertiesJson);\n    JsonUtils::CopyFrom(m_resultsJson, other.m_resultsJson);\n}\n\nMultiplayerSessionMember::~MultiplayerSessionMember()\n{\n    for (auto group : m_groups)\n    {\n        Delete(group);\n    }\n    for (auto encounter : m_encounters)\n    {\n        Delete(encounter);\n    }\n    for (auto& role : m_roles)\n    {\n        Delete(role.roleName);\n        Delete(role.roleTypeName);\n    }\n}\n\nxsapi_internal_string MultiplayerSessionMember::MemberId() const\n{\n    return m_member->IsCurrentUser ? \"me\" : m_memberIdToWrite;\n}\n\nvoid \nMultiplayerSessionMember::SetSecureDeviceBaseAddress64(_In_ const xsapi_internal_string& deviceBaseAddress)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    m_secureDeviceAddressBase64 = deviceBaseAddress;\n    m_member->SecureDeviceBaseAddress64 = m_secureDeviceAddressBase64.data();\n    m_writeSecureDeviceAddressBase64 = true;\n}\n\nvoid\nMultiplayerSessionMember::SetRoles(_In_ const xsapi_internal_vector<XblMultiplayerSessionMemberRole>& roles)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n\n    for (auto& role : m_roles)\n    {\n        Delete(role.roleName);\n        Delete(role.roleTypeName);\n    }\n    m_roles = roles;\n    for (auto& role : m_roles)\n    {\n        role.roleName = Make(role.roleName);\n        role.roleTypeName = Make(role.roleTypeName);\n    }\n    m_member->Roles = m_roles.data();\n    m_member->RolesCount = m_roles.size();\n    m_writeRoleInfo = true;\n}\n\nconst xsapi_internal_vector<const char*>& MultiplayerSessionMember::GroupsUnsafe() const\n{\n    return m_groups;\n}\n\nvoid MultiplayerSessionMember::SetGroups(\n    _In_reads_(groupsCount) const char** groups,\n    _In_ size_t groupsCount\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    for (auto& group : m_groups)\n    {\n        Delete(group);\n    }\n    m_groups.clear();\n    for (size_t i = 0; i < groupsCount; ++i)\n    {\n        m_groups.push_back(Make(groups[i]));\n    }\n    m_member->Groups = m_groups.data();\n    m_member->GroupsCount = m_groups.size();\n    m_writeGroups = true;\n}\n\nconst xsapi_internal_vector<const char*>&\nMultiplayerSessionMember::EncountersUnSafe() const\n{\n    return m_encounters;\n}\n\nvoid \nMultiplayerSessionMember::SetEncounters(\n    _In_reads_(encountersCount) const char** encounters,\n    _In_ size_t encountersCount\n)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    for (auto& encounter : m_encounters)\n    {\n        Delete(encounter);\n    }\n    m_encounters.clear();\n    for (uint32_t i = 0; i < encountersCount; ++i)\n    {\n        m_encounters.push_back(Make(encounters[i]));\n    }\n    m_member->Encounters = m_encounters.data();\n    m_member->EncountersCount = m_encounters.size();\n    m_writeEncounters = true;\n}\n\nHRESULT MultiplayerSessionMember::SetStatus(\n    _In_ XblMultiplayerSessionMemberStatus status\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    XSAPI_ASSERT(m_member->IsCurrentUser);\n    if (status != XblMultiplayerSessionMemberStatus::Active && status != XblMultiplayerSessionMemberStatus::Inactive)\n    {\n        return E_INVALIDARG;\n    }\n\n    m_member->Status = status;\n    m_writeIsActive = true;\n    return S_OK;\n}\n\nvoid MultiplayerSessionMember::StateLock() const\n{\n    m_lockMember.lock();\n}\n\nvoid MultiplayerSessionMember::StateUnlock() const\n{\n    m_lockMember.unlock();\n}\n\nconst xsapi_internal_vector<uint32_t>& MultiplayerSessionMember::MembersInGroupUnsafe() const\n{\n    return m_membersInGroupIds;\n}\n\nvoid MultiplayerSessionMember::SetMembersInGroup(\n    _In_ const xsapi_internal_vector<uint32_t>& membersInGroup\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    m_membersInGroupIds = membersInGroup;\n    m_member->MembersInGroupIds = m_membersInGroupIds.data();\n    m_member->MembersInGroupCount = static_cast<uint32_t>(m_membersInGroupIds.size());\n    m_writeMembersInGroup = true;\n}\n\nHRESULT\nMultiplayerSessionMember::SetCustomPropertyJson(\n    _In_ const xsapi_internal_string& name,\n    _In_ const JsonValue& valueJson\n)\n{\n    if (name.empty())\n    {\n        return E_INVALIDARG;\n    }\n\n    if (!m_member->IsCurrentUser)\n    {\n        return E_UNEXPECTED;\n    }\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n\n    auto hr = JsonUtils::SetMember(m_customPropertiesJson, name, valueJson);\n    if (SUCCEEDED(hr))\n    {\n        m_customPropertiesString = JsonUtils::SerializeJson(m_customPropertiesJson);\n        m_member->CustomPropertiesJson = m_customPropertiesString.data();\n        m_writeCustomPropertiesJson = true;\n    }\n\n    return hr;\n}\n\nvoid \nMultiplayerSessionMember::DeleteCustomPropertyJson(\n    _In_ const xsapi_internal_string& name\n    )\n{\n    SetCustomPropertyJson(name, JsonValue());\n}\n\nHRESULT MultiplayerSessionMember::SetQosMeasurementsJson(\n    _In_ const xsapi_internal_string& qosMeasurementsJson\n    )\n{\n    auto hr = JsonUtils::ValidateJson(qosMeasurementsJson.data());\n    if (SUCCEEDED(hr))\n    {\n        std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n        m_qosMeasurementsJson = qosMeasurementsJson;\n        m_member->QosMeasurementsJson = m_qosMeasurementsJson.data();\n        m_writeQoSMeasurementsJson = true;\n    }\n    return hr;\n}\n\nHRESULT MultiplayerSessionMember::SetServerMeasurementsJson(\n    _In_ const xsapi_internal_string& serverMeasurementsJson\n    )\n{\n    auto hr = JsonUtils::ValidateJson(serverMeasurementsJson.data());\n    if (SUCCEEDED(hr))\n    {\n        std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n        m_serverMeasurementsJson = serverMeasurementsJson;\n        m_member->ServerMeasurementsJson = m_serverMeasurementsJson.data();\n        m_writeServerMeasurementsJson = true;\n    }\n    return hr;\n}\n\nXblMultiplayerSessionChangeTypes \nMultiplayerSessionMember::SubscribedChangeTypes() const\n{\n    return m_subscribedChangeTypes;\n}\n\nvoid \nMultiplayerSessionMember::SetSessionChangeSubscription(\n    _In_ XblMultiplayerSessionChangeTypes changeTypes, \n    _In_ const xsapi_internal_string& subscriptionId\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    m_subscribedChangeTypes = changeTypes;\n    m_subscriptionId = subscriptionId;\n    m_writeSubscribedChangeTypes = true;\n}\n\nconst JsonValue& MultiplayerSessionMember::CustomPropertiesJsonUnsafe() const\n{\n    return m_customPropertiesJson;\n}\n\nvoid MultiplayerSessionMember::SetRtaConnectionId(\n    _In_ const xsapi_internal_string& rtaConnectionId\n    )\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    LOGS_DEBUG << \"MultiplayerSessionMember::SetRtaConnectionId \" << rtaConnectionId;\n    m_rtaConnectionId = rtaConnectionId;\n}\n\nResult<XblMultiplayerSessionMember> MultiplayerSessionMember::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    XblMultiplayerSessionMember returnResult{};\n    if (json.IsNull())\n    {\n        return returnResult;\n    }\n    auto returnResultInternal = Make<MultiplayerSessionMember>();\n    returnResult.Internal = returnResultInternal;\n\n    bool reserved = false;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"reserved\", reserved));\n    bool active = false;\n    bool ready = false;\n\n\n    returnResultInternal->m_customConstantsJson = \"\";\n    returnResult.Xuid = 0;\n    returnResult.InitializeRequested = false;\n    returnResultInternal->m_teamId = \"\";\n    returnResultInternal->m_initialTeam = \"\";\n    returnResultInternal->m_matchmakingResultServerMeasurementsJson = \"\";\n\n    if (json.IsObject() && json.HasMember(\"constants\"))\n    {\n        const JsonValue& constantsJson = json[\"constants\"];\n\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonFieldAsString(constantsJson, \"custom\", returnResultInternal->m_customConstantsJson, false));\n        \n        if (constantsJson.IsObject() && constantsJson.HasMember(\"custom\"))\n        {\n            const JsonValue& constantsCustomJson = constantsJson[\"custom\"];\n            if (constantsCustomJson.IsObject() && constantsCustomJson.HasMember(\"matchmakingResult\"))\n            {\n                const JsonValue& constantsCustomMatchmakingResultJson = constantsCustomJson[\"matchmakingResult\"];\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(constantsCustomMatchmakingResultJson, \"initialTeam\", returnResultInternal->m_initialTeam, false));                \n            }\n        }\n\n        if (constantsJson.IsObject() && constantsJson.HasMember(\"system\"))\n        {\n            const JsonValue& constantsSystemJson = constantsJson[\"system\"];\n\n            xsapi_internal_string xuid;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(constantsSystemJson, \"xuid\", xuid));\n            returnResult.Xuid = utils::internal_string_to_uint64(xuid);\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(constantsSystemJson, \"initialize\", returnResult.InitializeRequested));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(constantsSystemJson, \"team\", returnResultInternal->m_teamId));\n            \n            if (constantsSystemJson.IsObject() && constantsSystemJson.HasMember(\"matchmakingResult\"))\n            {\n                const JsonValue& constantsSystemMatchmakingResultJson = constantsSystemJson[\"matchmakingResult\"];\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonFieldAsString(constantsSystemMatchmakingResultJson, \"serverMeasurements\", returnResultInternal->m_matchmakingResultServerMeasurementsJson, false));\n            }\n        }\n        else\n        {\n            //required\n            return WEB_E_INVALID_JSON_STRING;\n        }\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    returnResult.CustomConstantsJson = returnResultInternal->m_customConstantsJson.data();\n    returnResult.InitialTeam = returnResultInternal->m_initialTeam.data();\n    returnResult.MatchmakingResultServerMeasurementsJson = returnResultInternal->m_matchmakingResultServerMeasurementsJson.data();\n\n    returnResultInternal->m_secureDeviceAddressBase64 = \"\";\n    returnResultInternal->m_serverMeasurementsJson = \"\";\n    returnResultInternal->m_qosMeasurementsJson = \"\";\n    returnResultInternal->m_customPropertiesString = \"\";\n\n    if (json.IsObject() && json.HasMember(\"properties\"))\n    {\n        const JsonValue& propertiesJson = json[\"properties\"];\n        if (propertiesJson.IsObject() && propertiesJson.HasMember(\"custom\"))\n        {\n            JsonUtils::CopyFrom(returnResultInternal->m_customPropertiesJson, propertiesJson[\"custom\"]);\n            returnResultInternal->m_customPropertiesString = JsonUtils::SerializeJson(returnResultInternal->m_customPropertiesJson);\n        }\n\n        if (propertiesJson.IsObject() && propertiesJson.HasMember(\"system\"))\n        {\n            const JsonValue& propertiesSystemJson = propertiesJson[\"system\"];\n\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(propertiesSystemJson, \"secureDeviceAddress\", returnResultInternal->m_secureDeviceAddressBase64));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonFieldAsString(propertiesSystemJson, \"serverMeasurements\", returnResultInternal->m_serverMeasurementsJson, false));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonFieldAsString(propertiesSystemJson, \"measurements\", returnResultInternal->m_qosMeasurementsJson, false));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint32_t>(JsonUtils::JsonIntExtractor, propertiesSystemJson, \"initializationGroup\", returnResultInternal->m_membersInGroupIds, false));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(propertiesSystemJson, \"active\", active));\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(propertiesSystemJson, \"ready\", ready));\n\n            if (propertiesSystemJson.IsObject() && propertiesSystemJson.HasMember(\"subscription\"))\n            {\n                const JsonValue& propertiesSystemSubscriptionJson = propertiesSystemJson[\"subscription\"];\n\n                xsapi_internal_vector<xsapi_internal_string> changeTypes;\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<xsapi_internal_string>(JsonUtils::JsonStringExtractor, propertiesSystemSubscriptionJson, \"changeTypes\", changeTypes, false));\n                returnResultInternal->m_subscribedChangeTypes = Serializers::MultiplayerSessionChangeTypesFromStringVector(changeTypes);\n            }\n\n            if (propertiesSystemJson.IsObject() && propertiesSystemJson.HasMember(\"groups\"))\n            {\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<const char*>(JsonUtils::JsonUtf8Extractor, propertiesSystemJson, \"groups\", returnResultInternal->m_groups, false));\n            }\n\n            if (propertiesSystemJson.IsObject() && propertiesSystemJson.HasMember(\"encounters\"))\n            {\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<const char*>(JsonUtils::JsonUtf8Extractor, propertiesSystemJson, \"encounters\", returnResultInternal->m_encounters, false));\n            }\n        }\n        else\n        {\n            //required\n            return WEB_E_INVALID_JSON_STRING;\n        }\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    returnResult.SecureDeviceBaseAddress64 = returnResultInternal->m_secureDeviceAddressBase64.data();\n    returnResult.ServerMeasurementsJson = returnResultInternal->m_serverMeasurementsJson.data();\n    returnResult.QosMeasurementsJson = returnResultInternal->m_qosMeasurementsJson.data();\n    returnResult.MembersInGroupIds = returnResultInternal->m_membersInGroupIds.data();\n    returnResult.MembersInGroupCount = static_cast<uint32_t>(returnResultInternal->m_membersInGroupIds.size());\n    returnResult.Groups = returnResultInternal->m_groups.data();\n    returnResult.GroupsCount = static_cast<uint32_t>(returnResultInternal->m_groups.size());\n    returnResult.Encounters = returnResultInternal->m_encounters.data();\n    returnResult.EncountersCount = static_cast<uint32_t>(returnResultInternal->m_encounters.size());\n    returnResult.CustomPropertiesJson = returnResultInternal->m_customPropertiesString.data();\n\n    if (active)\n    {\n        returnResult.Status = XblMultiplayerSessionMemberStatus::Active;\n    }\n    else if (ready)\n    {\n        returnResult.Status = XblMultiplayerSessionMemberStatus::Ready;\n    }\n    else if (reserved)\n    {\n        returnResult.Status = XblMultiplayerSessionMemberStatus::Reserved;\n    }\n    else\n    {\n        returnResult.Status = XblMultiplayerSessionMemberStatus::Inactive;\n    }\n    xsapi_internal_string gamertag, deviceToken, nat;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"gamertag\", gamertag));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"deviceToken\", deviceToken));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"nat\", nat));\n    utils::strcpy(returnResult.Gamertag, sizeof(returnResult.Gamertag), gamertag.c_str());\n    utils::strcpy(returnResult.DeviceToken.Value, sizeof(returnResult.DeviceToken.Value), deviceToken.c_str());\n    returnResult.Nat = Serializers::MultiplayerNatSettingFromString(nat);\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"turn\", returnResult.IsTurnAvailable));\n\n    if (json.IsObject() && json.HasMember(\"roles\"))\n    {\n        const JsonValue& rolesJson = json[\"roles\"];\n        if (!rolesJson.IsNull() && rolesJson.IsObject())\n        {\n            for (const auto& rolePair : rolesJson.GetObject())\n            {\n                XblMultiplayerSessionMemberRole role{};\n                role.roleTypeName = Make(rolePair.name.GetString());\n                role.roleName = Make(rolePair.value.GetString());\n                returnResultInternal->m_roles.push_back(std::move(role));\n            }\n            returnResult.Roles = returnResultInternal->m_roles.data();\n            returnResult.RolesCount = returnResultInternal->m_roles.size();\n        }\n    }\n\n    xsapi_internal_string titleIdString;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"activeTitleId\", titleIdString));\n    if (!titleIdString.empty())\n    {\n        returnResult.ActiveTitleId = utils::internal_string_to_uint32(titleIdString);\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"joinTime\", returnResult.JoinTime));\n    xsapi_internal_string initializationFailure;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"initializationFailure\", initializationFailure))\n    returnResult.InitializationFailureCause = Serializers::MultiplayerMeasurementFailureFromString(initializationFailure);\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"initializationEpisode\", returnResult.InitializationEpisode));\n\n    return returnResult;\n}\n\nxsapi_internal_vector<xsapi_internal_string> MultiplayerSessionMember::GetVectorViewForChangeTypes(\n    _In_ XblMultiplayerSessionChangeTypes changeTypes\n)\n{\n    xsapi_internal_vector<xsapi_internal_string> resultVector;\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::Everything) == XblMultiplayerSessionChangeTypes::Everything)\n    {\n        resultVector.push_back(\"everything\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::HostDeviceTokenChange) == XblMultiplayerSessionChangeTypes::HostDeviceTokenChange)\n    {\n        resultVector.push_back(\"host\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::InitializationStateChange) == XblMultiplayerSessionChangeTypes::InitializationStateChange)\n    {\n        resultVector.push_back(\"initialization\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::MatchmakingStatusChange) == XblMultiplayerSessionChangeTypes::MatchmakingStatusChange)\n    {\n        resultVector.push_back(\"matchmakingStatus\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::MemberListChange) == XblMultiplayerSessionChangeTypes::MemberListChange)\n    {\n        resultVector.push_back(\"membersList\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::MemberStatusChange) == XblMultiplayerSessionChangeTypes::MemberStatusChange)\n    {\n        resultVector.push_back(\"membersStatus\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::SessionJoinabilityChange) == XblMultiplayerSessionChangeTypes::SessionJoinabilityChange)\n    {\n        resultVector.push_back(\"joinability\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::CustomPropertyChange) == XblMultiplayerSessionChangeTypes::CustomPropertyChange)\n    {\n        resultVector.push_back(\"customProperty\");\n    }\n    if ((changeTypes & XblMultiplayerSessionChangeTypes::MemberCustomPropertyChange) == XblMultiplayerSessionChangeTypes::MemberCustomPropertyChange)\n    {\n        resultVector.push_back(\"membersCustomProperty\");\n    }\n\n    return resultVector;\n}\n\nvoid MultiplayerSessionMember::Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lockMember };\n    json.SetObject();\n    if (m_newMember)\n    {\n        JsonValue systemConstantsJson(rapidjson::kObjectType);\n        systemConstantsJson.AddMember(\"xuid\", JsonValue(utils::uint64_to_internal_string(m_member->Xuid).c_str(), allocator).Move(), allocator);\n        if (m_member->InitializeRequested)\n        {\n            systemConstantsJson.AddMember(\"initialize\", m_member->InitializeRequested, allocator);\n        }\n\n        JsonValue constantsJson(rapidjson::kObjectType);\n        constantsJson.AddMember(\"system\", systemConstantsJson, allocator);\n        if (!m_customConstantsJson.empty())\n        {\n            JsonDocument customJson{ &allocator };\n            customJson.Parse(m_customConstantsJson.data());\n            if (!customJson.IsNull())\n            {\n                constantsJson.AddMember(\"custom\", customJson, allocator);\n            }\n        }\n        json.AddMember(\"constants\", constantsJson, allocator);\n    }\n\n    if (m_newMember || m_member->IsCurrentUser)\n    {\n        JsonValue propertiesJson(rapidjson::kObjectType);\n        JsonValue systemPropertiesJson(rapidjson::kObjectType);\n\n        if (m_writeIsActive)\n        {\n            bool isActive = m_member->Status == XblMultiplayerSessionMemberStatus::Active;\n            systemPropertiesJson.AddMember(\"active\", isActive, allocator);\n            if (!isActive)\n            {\n                systemPropertiesJson.AddMember(\"ready\", isActive, allocator);\n            }\n            else\n            {\n                if (!m_rtaConnectionId.empty())\n                {\n                    systemPropertiesJson.AddMember(\"connection\", JsonValue(m_rtaConnectionId.c_str(), allocator).Move(), allocator);\n                    LOGS_DEBUG << \"MultiplayerSessionMember::Serialize \" << m_rtaConnectionId << \" for \" << m_member->Xuid;\n                }\n            }\n        }\n\n        if (m_writeRoleInfo && m_member->RolesCount > 0)\n        {\n            JsonValue rolesJson(rapidjson::kObjectType);\n            for (uint32_t i = 0; i < m_member->RolesCount; ++i)\n            {\n                rolesJson.AddMember(JsonValue(m_member->Roles[i].roleTypeName, allocator).Move(), JsonValue(m_member->Roles[i].roleName, allocator).Move(), allocator);\n            }\n            json.AddMember(\"roles\", rolesJson, allocator);\n        }\n\n        if (m_writeSubscribedChangeTypes)\n        {\n            JsonValue subscriptionJson(rapidjson::kObjectType);\n\n            subscriptionJson.AddMember(\"id\", JsonValue(m_subscriptionId.c_str(), allocator).Move(), allocator);\n\n            JsonValue changeTypesJson;\n            JsonUtils::SerializeVector(JsonUtils::JsonStringSerializer, GetVectorViewForChangeTypes(m_subscribedChangeTypes), changeTypesJson, allocator);\n            subscriptionJson.AddMember(\"changeTypes\", changeTypesJson, allocator);\n\n            systemPropertiesJson.AddMember(\"subscription\", subscriptionJson, allocator);\n        }\n\n        if (m_writeSecureDeviceAddressBase64)\n        {\n            systemPropertiesJson.AddMember(\"secureDeviceAddress\", JsonValue(m_member->SecureDeviceBaseAddress64, allocator).Move(), allocator);\n        }\n\n        if (m_writeMembersInGroup)\n        {\n            JsonValue initializationGroupJson(rapidjson::kArrayType);\n            JsonUtils::SerializeVector<uint32_t>(JsonUtils::JsonIntSerializer, m_membersInGroupIds, initializationGroupJson, allocator);\n            systemPropertiesJson.AddMember(\"initializationGroup\", initializationGroupJson, allocator);\n        }\n\n        if (m_writeGroups)\n        {\n            JsonValue groupsJson(rapidjson::kArrayType);\n            JsonUtils::SerializeVector<const char*>(JsonUtils::JsonUtf8Serializer, m_groups, groupsJson, allocator);\n            systemPropertiesJson.AddMember(\"groups\", groupsJson, allocator);\n        }\n\n        if (m_writeEncounters)\n        {\n            JsonValue encountersJson(rapidjson::kArrayType);\n            JsonUtils::SerializeVector<const char*>(JsonUtils::JsonUtf8Serializer, m_encounters, encountersJson, allocator);\n            systemPropertiesJson.AddMember(\"encounters\", encountersJson, allocator);\n        }\n\n        if (m_writeQoSMeasurementsJson)\n        {\n            JsonDocument measurementsJson{ &allocator };\n            measurementsJson.Parse(m_qosMeasurementsJson.data());\n            systemPropertiesJson.AddMember(\"measurements\", measurementsJson, allocator);\n        }\n\n        if (m_writeServerMeasurementsJson)\n        {\n            JsonDocument serverMeasurementsJson{ &allocator };\n            serverMeasurementsJson.Parse(m_serverMeasurementsJson.data());\n            systemPropertiesJson.AddMember(\"serverMeasurements\", serverMeasurementsJson, allocator);\n        }\n\n        if (systemPropertiesJson.MemberCount())\n        {\n            propertiesJson.AddMember(\"system\", systemPropertiesJson, allocator);\n        }\n\n        if (m_writeCustomPropertiesJson)\n        {\n            propertiesJson.AddMember(\"custom\", JsonValue{}.CopyFrom(m_customPropertiesJson, allocator).Move(), allocator);\n        }\n\n        if (propertiesJson.MemberCount())\n        {\n            json.AddMember(\"properties\", propertiesJson, allocator);\n        }\n    }\n}\n\nMultiplayerSessionMember* MultiplayerSessionMember::Get(const XblMultiplayerSessionMember* member)\n{\n    if (member == nullptr || member->Internal == nullptr)\n    {\n        XSAPI_ASSERT(false);\n    }\n    return static_cast<MultiplayerSessionMember*>(member->Internal);\n}\n\nvoid MultiplayerSessionMember::SetExternalMemberPointer(XblMultiplayerSessionMember& member)\n{\n    auto internalMember = Get(&member);\n    internalMember->m_member = &member;\n\n    member.InitialTeam = internalMember->m_initialTeam.empty() ? nullptr : internalMember->m_initialTeam.data();\n    member.CustomConstantsJson = internalMember->m_customConstantsJson.empty() ? nullptr :internalMember->m_customConstantsJson.data();\n    member.SecureDeviceBaseAddress64 = internalMember->m_secureDeviceAddressBase64.empty() ? nullptr : internalMember->m_secureDeviceAddressBase64.data();\n    member.Roles = internalMember->m_roles.empty() ? nullptr : internalMember->m_roles.data();\n    member.CustomPropertiesJson = internalMember->m_customPropertiesString.empty() ? nullptr : internalMember->m_customPropertiesString.data();\n    member.MatchmakingResultServerMeasurementsJson = internalMember->m_matchmakingResultServerMeasurementsJson.empty() ? nullptr : internalMember->m_matchmakingResultServerMeasurementsJson.data();\n    member.ServerMeasurementsJson = internalMember->m_serverMeasurementsJson.empty() ? nullptr : internalMember->m_serverMeasurementsJson.data();\n    member.MembersInGroupIds = internalMember->m_membersInGroupIds.empty() ? nullptr : internalMember->m_membersInGroupIds.data();\n    member.QosMeasurementsJson = internalMember->m_qosMeasurementsJson.empty() ? nullptr : internalMember->m_qosMeasurementsJson.data();\n    member.Groups = internalMember->m_groups.empty() ? nullptr : internalMember->m_groups.data();\n    member.Encounters = internalMember->m_encounters.empty() ? nullptr : internalMember->m_encounters.data();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END\n"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_session_reference.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::legacy;\nusing namespace xbox::services::multiplayer;\n\nSTDAPI XblMultiplayerSessionReferenceParseFromUriPath(\n    _In_ const char* path,\n    _Out_ XblMultiplayerSessionReference* ref\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ref);\n\n    //   /      0       /  1   /      2        /           3           /    4    /    5\n    //  /serviceconfigs/{scid}/sessiontemplates/{session-template-name}/sessions/{session-name}\n\n    xsapi_internal_vector<xsapi_internal_string> pathComponents = utils::string_split_internal(xsapi_internal_string(path), '/');\n    if (pathComponents.size() < 6)\n    {\n        return E_INVALIDARG;\n    }\n\n    memset(ref, 0, sizeof(XblMultiplayerSessionReference));\n    utils::strcpy(ref->Scid, sizeof(ref->Scid), pathComponents.at(1).data());\n    utils::strcpy(ref->SessionTemplateName, sizeof(ref->SessionTemplateName), pathComponents.at(3).data());\n    utils::strcpy(ref->SessionName, sizeof(ref->SessionName), pathComponents.at(5).data());\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerSessionReferenceToUriPath(\n    _In_ const XblMultiplayerSessionReference* sessionReference,\n    _Out_ XblMultiplayerSessionReferenceUri* sessionReferenceUri\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(sessionReference == nullptr || sessionReferenceUri == nullptr);\n\n    xsapi_internal_stringstream uriStream;\n    uriStream << \"/serviceconfigs/\";\n    uriStream << sessionReference->Scid;\n    uriStream << \"/sessiontemplates/\";\n    uriStream << sessionReference->SessionTemplateName;\n    uriStream << \"/sessions/\";\n    uriStream << sessionReference->SessionName;\n\n    memset(sessionReferenceUri, 0, sizeof(XblMultiplayerSessionReferenceUri));\n    utils::strcpy(sessionReferenceUri->value, sizeof(sessionReferenceUri->value), uriStream.str().data());\n\n    return S_OK;\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Checks whether an XblMultiplayerSessionReference is well formed. It is considered well formed if none of the\n/// fields are empty strings.\n/// </summary>\nSTDAPI_(bool) XblMultiplayerSessionReferenceIsValid(\n    _In_ const XblMultiplayerSessionReference* sessionReference\n) XBL_NOEXCEPT\ntry\n{\n    if (sessionReference == nullptr)\n    {\n        return false;\n    }\n    return sessionReference->Scid[0] != 0 && sessionReference->SessionTemplateName[0] != 0 && sessionReference->SessionName[0] != 0;\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Creates an XblMultiplayerSessionReference from a scid, session template name, and session name.\n/// </summary>\nSTDAPI_(XblMultiplayerSessionReference) XblMultiplayerSessionReferenceCreate(\n    _In_z_ const char* scid,\n    _In_z_ const char* sessionTemplateName,\n    _In_z_ const char* sessionName\n) XBL_NOEXCEPT\ntry\n{\n    XblMultiplayerSessionReference out{};\n    if (scid != nullptr)\n    {\n        utils::strcpy(out.Scid, sizeof(out.Scid), scid);\n    }\n    if (sessionTemplateName != nullptr)\n    {\n        utils::strcpy(out.SessionTemplateName, sizeof(out.SessionTemplateName), sessionTemplateName);\n    }\n    if (sessionName != nullptr)\n    {\n        utils::strcpy(out.SessionName, sizeof(out.SessionName), sessionName);\n    }\n    return out;\n}\nCATCH_RETURN_WITH({})\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nbool operator==(const XblMultiplayerSessionReference& lhs, const XblMultiplayerSessionReference& rhs)\n{\n    return utils::str_icmp(lhs.Scid, rhs.Scid) == 0 &&\n           utils::str_icmp(lhs.SessionName, rhs.SessionName) == 0 &&\n           utils::str_icmp(lhs.SessionTemplateName, rhs.SessionTemplateName) == 0;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_subscription.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nconst char mp_default_resourceUri[] = \"https://sessiondirectory.xboxlive.com/connections/\";\n\nMultiplayerSubscription::MultiplayerSubscription() noexcept\n{\n    m_resourceUri = mp_default_resourceUri;\n}\n\nconst String& MultiplayerSubscription::RtaConnectionId() const\n{\n    return m_connectionId;\n}\n\nXblFunctionContext MultiplayerSubscription::AddSessionChangedHandler(\n    SessionChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerSubscription };\n    m_sessionChangedHandlers[m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nsize_t MultiplayerSubscription::RemoveSessionChangedHandler(\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerSubscription };\n    m_sessionChangedHandlers.erase(token);\n    return m_sessionChangedHandlers.size();\n}\n\nXblFunctionContext MultiplayerSubscription::AddConnectionIdChangedHandler(\n    ConnectionIdChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerSubscription };\n    m_connectionIdChangedHandlers[m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nsize_t MultiplayerSubscription::RemoveConnectionIdChangedHandler(\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutexMultiplayerSubscription };\n    m_connectionIdChangedHandlers.erase(token);\n    return m_connectionIdChangedHandlers.size();\n}\n\nvoid MultiplayerSubscription::OnSubscribe(\n    _In_ const JsonValue& data\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutexMultiplayerSubscription };\n\n    HRESULT hr = JsonUtils::ExtractJsonString(data, \"ConnectionId\", m_connectionId, true);\n    if (FAILED(hr))\n    {\n        LOGS_ERROR << __FUNCTION__ << \": Ignoring malformed payload\";\n        return;\n    }\n\n    auto handlers{ m_connectionIdChangedHandlers };\n    lock.unlock();\n\n    for (auto& handler : handlers)\n    {\n        handler.second(m_connectionId);\n    }\n}\n\nvoid MultiplayerSubscription::OnEvent(\n    _In_ const JsonValue& data\n) noexcept\n{\n    if (!data.IsObject() || !data.HasMember(\"shoulderTaps\"))\n    {\n        LOGS_ERROR << __FUNCTION__ << \": Ignoring malformed payload\";\n        return;\n    }\n\n    List<XblMultiplayerSessionChangeEventArgs> taps;\n\n    const JsonValue& shoulderTaps = data[\"shoulderTaps\"];\n    if (shoulderTaps.IsArray())\n    {\n        for (const auto& tapValue : shoulderTaps.GetArray())\n        {\n            String resourceName;\n            JsonUtils::ExtractJsonString(tapValue, \"resource\", resourceName, true);\n            Vector<String> nameComponents = utils::string_split_internal(resourceName, '~');\n\n            if (nameComponents.size() != 3)\n            {\n                LOGS_ERROR << __FUNCTION__ << \": Resource has too many values\";\n                continue;\n            }\n\n            taps.emplace_back();\n            auto& tap{ taps.back() };\n\n            tap.SessionReference = XblMultiplayerSessionReferenceCreate(\n                nameComponents[0].data(),\n                nameComponents[1].data(),\n                nameComponents[2].data()\n            );\n            JsonUtils::ExtractJsonInt(tapValue, \"changeNumber\", tap.ChangeNumber, false);\n            JsonUtils::ExtractJsonStringToCharArray(tapValue, \"branch\", tap.Branch, sizeof(tap.Branch));\n\n            LOGS_DEBUG << __FUNCTION__ << \": Resource=\" << resourceName;\n        }\n    }\n\n    std::unique_lock<std::mutex> lock{ m_mutexMultiplayerSubscription };\n    auto handlers{ m_sessionChangedHandlers };\n    lock.unlock();\n\n    for (auto& handler : handlers)\n    {\n        for (auto& tap : taps)\n        {\n            handler.second(tap);\n        }\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/Multiplayer/multiplayer_transfer_handle_post_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN\n\nMultiplayerTransferHandlePostRequest::MultiplayerTransferHandlePostRequest(\n    _In_ XblMultiplayerSessionReference targetSessionReference,\n    _In_ XblMultiplayerSessionReference originSessionReference\n) :\n    m_originSessionReference(std::move(originSessionReference)),\n    m_targetSessionReference(std::move(targetSessionReference))\n{\n    XSAPI_ASSERT(XblMultiplayerSessionReferenceIsValid(&m_targetSessionReference));\n    XSAPI_ASSERT(XblMultiplayerSessionReferenceIsValid(&m_originSessionReference));\n}\n\nconst XblMultiplayerSessionReference&\nMultiplayerTransferHandlePostRequest::OriginSessionReference() const\n{\n    return m_originSessionReference;\n}\n\nconst XblMultiplayerSessionReference&\nMultiplayerTransferHandlePostRequest::TargetSessionReference() const\n{\n    return m_targetSessionReference;\n}\n\nvoid\nMultiplayerTransferHandlePostRequest::Serialize(_Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator) const\n{\n    json.SetObject();\n\n    json.AddMember(\"type\", \"transfer\", allocator);\n    JsonValue targetSessionJson;\n    Serializers::SerializeSessionReference(m_targetSessionReference, targetSessionJson, allocator);\n    json.AddMember(\"sessionRef\", targetSessionJson, allocator);\n    json.AddMember(\"version\", MULTIPLAYER_HANDLE_VERSION, allocator);\n    JsonValue originSessionJson;\n    Serializers::SerializeSessionReference(m_originSessionReference, originSessionJson, allocator);\n    json.AddMember(\"originSessionRef\", originSessionJson, allocator);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END"
  },
  {
    "path": "Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"multiplayer_activity_internal.h\"\n#ifdef XSAPI_NOTIFICATION_SERVICE\n#include \"notification_internal.h\"\n#endif\n\nusing namespace xbox::services::multiplayer_activity;\n\n#ifdef XSAPI_NOTIFICATION_SERVICE\nusing namespace xbox::services::notification;\n#endif\n\nSTDAPI XblMultiplayerActivityUpdateRecentPlayers(\n    _In_ XblContextHandle xblContextHandle,\n    _In_reads_(updatesCount) const XblMultiplayerActivityRecentPlayerUpdate* updates,\n    _In_ size_t updatesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr);\n    return xblContextHandle->MultiplayerActivityService()->UpdateRecentPlayers(updates, updatesCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivityFlushRecentPlayersAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerActivityService()->FlushRecentPlayers(data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivitySetActivityAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const XblMultiplayerActivityInfo* activityInfo,\n    _In_ bool allowCrossPlatformJoin,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || activityInfo == nullptr || activityInfo->connectionString ==  nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            info = ActivityInfo{ activityInfo },\n            allowCrossPlatformJoin\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerActivityService()->SetActivity(info, allowCrossPlatformJoin, data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivityGetActivityAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_reads_(xuidsCount) const uint64_t* xuidsPtr,\n    _In_ size_t xuidsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || xuidsPtr == nullptr || xuidsCount == 0);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            xuids = Vector<uint64_t>(xuidsPtr, xuidsPtr + xuidsCount),\n            activityInfo = Vector<ActivityInfo>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerActivityService()->GetActivity(xuids, { data->async->queue,\n                [\n                    &activityInfo,\n                    async{ data->async }\n                ]\n            (Result<Vector<ActivityInfo>> result)\n            {\n                size_t requiredBufferSize{ 0 };\n                if (Succeeded(result))\n                {\n                    activityInfo = result.ExtractPayload();\n                    for (const auto& a : activityInfo)\n                    {\n                        requiredBufferSize += sizeof(XblMultiplayerActivityInfo);\n                        if (!a.connectionString.empty())\n                        {\n                            requiredBufferSize += (a.connectionString.size() + 1);\n                        }\n                        if (!a.groupId.empty())\n                        {\n                            requiredBufferSize += (a.groupId.size() + 1);\n                        }\n                    }\n\n                    // Add padding to store the arraysize\n                    requiredBufferSize += sizeof(size_t);\n                }\n                XAsyncComplete(async, result.Hresult(), requiredBufferSize);\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto activityCountPtr{ static_cast<size_t*>(data->buffer) };\n            auto activityInfoPtr{ reinterpret_cast<XblMultiplayerActivityInfo*>(activityCountPtr + 1) };\n            auto stringPtr{ reinterpret_cast<char*>(activityInfoPtr + activityInfo.size()) };\n            size_t bufferSize{ sizeof(size_t) };\n\n            *activityCountPtr = activityInfo.size();\n\n            for (const auto& a : activityInfo)\n            {\n                new (activityInfoPtr) XblMultiplayerActivityInfo\n                {\n                    a.xuid,\n                    nullptr,\n                    a.joinRestriction,\n                    a.maxPlayers,\n                    a.currentPlayers,\n                    nullptr,\n                    a.platform\n                };\n\n                if (!a.connectionString.empty())\n                {\n                    utils::strcpy(stringPtr, a.connectionString.size() + 1, a.connectionString.data());\n                    activityInfoPtr->connectionString = stringPtr;\n                    stringPtr += (a.connectionString.size() + 1);\n                    bufferSize += (a.connectionString.size() + 1);\n                }\n\n                if (!a.groupId.empty())\n                {\n                    utils::strcpy(stringPtr, a.groupId.size() + 1, a.groupId.data());\n                    activityInfoPtr->groupId = stringPtr;\n                    stringPtr += (a.groupId.size() + 1);\n                    bufferSize += (a.groupId.size() + 1);\n                }\n\n                bufferSize += sizeof(XblMultiplayerActivityInfo);\n                ++activityInfoPtr;\n            }\n            assert(static_cast<char*>(data->buffer) + bufferSize == stringPtr);\n\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivityGetActivityResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivityGetActivityResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblMultiplayerActivityInfo** results,\n    _Out_ size_t* resultCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(results == nullptr || resultCount == nullptr);\n\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        auto resultCountPtr{ static_cast<size_t*>(buffer) };\n        *resultCount = *resultCountPtr;\n        *results = reinterpret_cast<XblMultiplayerActivityInfo*>(resultCountPtr + 1);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivityDeleteActivityAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerActivityService()->DeleteActivity(data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivitySendInvitesAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xuidsPtr,\n    _In_ size_t xuidsCount,\n    _In_ bool allowCrossPlatformJoin,\n    _In_opt_z_ const char* _connectionString,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || xuidsPtr == nullptr || xuidsCount == 0);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            xuids{ Vector<uint64_t>(xuidsPtr, xuidsPtr + xuidsCount) },\n            allowCrossPlatformJoin,\n            connectionString = _connectionString ? String{ _connectionString } : String{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->MultiplayerActivityService()->SendInvites(xuids, allowCrossPlatformJoin, connectionString, data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\n#if (HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL) && !defined(XSAPI_UNIT_TESTS)\nSTDAPI_(XblFunctionContext) XblMultiplayerActivityAddInviteHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblMultiplayerActivityInviteHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContext == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    auto rtaNotificationService = std::dynamic_pointer_cast<RTANotificationService>(xblContext->NotificationService());\n    return rtaNotificationService->AddGameInviteHandler(NotificationSubscription::MultiplayerActivityInviteHandler{\n        [\n            handler, context\n        ]\n    (const notification::MultiplayerActivityInviteData& args)\n    {\n        try\n        {\n            handler(&args, context);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    } \n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblMultiplayerActivityRemoveInviteHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContext);\n    auto rtaNotificationService = std::dynamic_pointer_cast<RTANotificationService>(xblContext->NotificationService());\n    rtaNotificationService->RemoveNotificationHandler(token);\n    return S_OK;\n}\nCATCH_RETURN()\n#endif\n"
  },
  {
    "path": "Source/Services/MultiplayerActivity/multiplayer_activity_info.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_activity_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace multiplayer_activity\n{\n\nActivityInfo::ActivityInfo(const XblMultiplayerActivityInfo* info) noexcept\n    : XblMultiplayerActivityInfo{ *info },\n    connectionString{ info->connectionString }\n{\n    if (info->groupId)\n    {\n        groupId = info->groupId;\n    }\n}\n\nActivityInfo::ActivityInfo(uint64_t xuid) noexcept\n    : XblMultiplayerActivityInfo{ xuid }\n{\n}\n\nResult<Vector<ActivityInfo>> ActivityInfo::Deserialize(\n    const JsonValue& responseJson,\n    uint32_t titleId\n) noexcept\n{\n    if (!responseJson.HasMember(\"userActivities\") || !responseJson[\"userActivities\"].IsArray())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    Vector<ActivityInfo> result;\n\n    const auto& users{ responseJson[\"userActivities\"].GetArray() };\n    for (const auto& user : users)\n    {\n        uint64_t xuid{};\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(user, \"userId\", xuid, true));\n\n        // Users may have multiple activities, but we only care about their activities within our title\n        auto activities = JsonUtils::ExtractJsonArray(user, \"activities\", true);\n        for (const auto& activity : activities)\n        {\n            uint32_t activityTitleId{};\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(activity, \"titleId\", activityTitleId, true));\n\n            if (activityTitleId == titleId)\n            {\n                ActivityInfo i{ xuid };\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(activity, \"connectionString\", i.connectionString));\n\n                String joinRestriction;\n                JsonUtils::ExtractJsonString(activity, \"joinRestriction\", joinRestriction, false);\n                i.joinRestriction = EnumValue<XblMultiplayerActivityJoinRestriction>(joinRestriction.data());\n\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonSizeT(activity, \"maxPlayers\", i.maxPlayers));\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonSizeT(activity, \"currentPlayers\", i.currentPlayers));\n                RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(activity, \"groupId\", i.groupId));\n\n                String platform;\n                JsonUtils::ExtractJsonString(activity, \"platform\", platform, false);\n                i.platform = EnumValue<XblMultiplayerActivityPlatform, 0, static_cast<uint32_t>(XblMultiplayerActivityPlatform::All)>(platform.data());\n\n                result.push_back(i);\n            }\n        }\n    }\n\n    return result;\n}\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Services/MultiplayerActivity/multiplayer_activity_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/multiplayer_activity_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace multiplayer_activity\n{\n\nclass ActivityInfo : public XblMultiplayerActivityInfo\n{\npublic:\n    ActivityInfo(const XblMultiplayerActivityInfo* info) noexcept;\n\n    static Result<Vector<ActivityInfo>> Deserialize(\n        const JsonValue& responseJson,\n        uint32_t titleId\n    ) noexcept;\n\n    String connectionString;\n    String groupId;\n\nprivate:\n    ActivityInfo(uint64_t xuid) noexcept;\n};\n\nclass MultiplayerActivityService : public std::enable_shared_from_this<MultiplayerActivityService>\n{\npublic:\n    MultiplayerActivityService(\n        _In_ User&& user,\n        _In_ const TaskQueue& queue,\n        _In_ std::shared_ptr<XboxLiveContextSettings> settings\n    ) noexcept;\n\n    ~MultiplayerActivityService() noexcept;\n\n    HRESULT UpdateRecentPlayers(\n        _In_reads_(updatesCount) const XblMultiplayerActivityRecentPlayerUpdate* updates,\n        _In_ size_t updatesCount\n    ) noexcept;\n\n    HRESULT FlushRecentPlayers(\n        _In_ AsyncContext<Result<void>>&& async\n    ) noexcept;\n\n    HRESULT SetActivity(\n        _In_ const ActivityInfo& info,\n        _In_ bool allowCrossPlatformJoin,\n        _In_ AsyncContext<HRESULT> async\n    ) const noexcept;\n\n    HRESULT GetActivity(\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ AsyncContext<Result<Vector<ActivityInfo>>> async\n    ) const noexcept;\n\n    HRESULT DeleteActivity(\n        _In_ AsyncContext<HRESULT> async\n    ) const noexcept;\n\n    HRESULT SendInvites(\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ bool allowCrossPlatformJoin,\n        _In_ const String& connectionString,\n        _In_ AsyncContext<HRESULT> async\n    ) const noexcept;\n\nprivate:\n    struct RecentPlayerUpdateMetadata\n    {\n        time_t timestamp{};\n        XblMultiplayerActivityEncounterType encounterType{};\n    };\n\n    UnorderedMap<uint64_t, RecentPlayerUpdateMetadata> m_pendingRecentPlayerUpdates{};\n    bool m_recentPlayersUpdateScheduled{ false };\n\n    static uint64_t GetSequenceNumber();\n    void ScheduleRecentPlayersUpdate() noexcept;\n    static XblMultiplayerActivityPlatform GetLocalPlatform() noexcept;\n\n    User m_user;\n    TaskQueue m_queue;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    uint32_t m_titleId{ AppConfig::Instance()->TitleId() };\n    mutable std::mutex m_mutex{};\n};\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Services/MultiplayerActivity/multiplayer_activity_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_activity_internal.h\"\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include <XSystem.h>\n#endif\n\n#define RECENT_PLAYERS_UPLOAD_INTERVAL_MS 5000\n#define MPA_SERVICE_NAME \"multiplayeractivity\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace multiplayer_activity\n{\n\nconstexpr auto PlatformName = EnumName<XblMultiplayerActivityPlatform, 0, static_cast<uint32_t>(XblMultiplayerActivityPlatform::All)>;\n\nMultiplayerActivityService::MultiplayerActivityService(\n    _In_ User&& user,\n    _In_ const TaskQueue& queue,\n    _In_ std::shared_ptr<XboxLiveContextSettings> settings\n) noexcept\n    : m_user{ std::move(user) },\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_xboxLiveContextSettings{ std::move(settings) }\n{\n}\n\nMultiplayerActivityService::~MultiplayerActivityService() noexcept\n{\n    FlushRecentPlayers(m_queue);\n\n    // Terminating m_queue to cancel next scheduled flush. FlushRecentPlayers call above will not be canceled\n    // since the work will happen on a queue derived from m_queue.\n    m_queue.Terminate(false);\n}\n\nHRESULT MultiplayerActivityService::UpdateRecentPlayers(\n    _In_reads_(updatesCount) const XblMultiplayerActivityRecentPlayerUpdate* updates,\n    _In_ size_t updatesCount\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(updates == nullptr || updatesCount == 0);\n\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    time_t now{ time(nullptr) };\n    for (size_t i = 0; i < updatesCount; ++i)\n    {\n        m_pendingRecentPlayerUpdates[updates[i].xuid] = RecentPlayerUpdateMetadata{ now, updates[i].encounterType };\n    }\n\n    if (!m_recentPlayersUpdateScheduled)\n    {\n        m_recentPlayersUpdateScheduled = true;\n        ScheduleRecentPlayersUpdate();\n    }\n\n    return S_OK;\n}\n\nHRESULT MultiplayerActivityService::FlushRecentPlayers(\n    _In_ AsyncContext<Result<void>>&& async\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    if (m_pendingRecentPlayerUpdates.empty())\n    {\n        async.Complete(S_OK);\n        return S_OK;\n    }\n\n    // Build HTTP request\n    class ServiceCall : public XblHttpCall\n    {\n    public:\n        ServiceCall(User&& user) noexcept\n            : XblHttpCall{ std::move(user) }\n        {\n        }\n\n        HRESULT InitServiceCall(\n            _In_ std::shared_ptr<XboxLiveContextSettings> contextSettings,\n            _In_ uint32_t titleId\n        ) noexcept\n        {\n            m_globalState = GlobalState::Get();\n            if (!m_globalState)\n            {\n                return E_XBL_NOT_INITIALIZED;\n            }\n\n            Stringstream path{};\n            path << \"/titles/\" << titleId << \"/recentplayers\";\n\n            RETURN_HR_IF_FAILED(XblHttpCall::Init(\n                contextSettings,\n                \"POST\",\n                XblHttpCall::BuildUrl(MPA_SERVICE_NAME, path.str()),\n                xbox_live_api::post_recent_players\n            ));\n            RETURN_HR_IF_FAILED(XblHttpCall::SetUserAgent(HttpCallAgent::MultiplayerActivity));\n\n            return S_OK;\n        }\n\n        HRESULT PerformWithRetry(\n            AsyncContext<xbox::services::Result<void>>&& async\n        )\n        {\n            return XblHttpCall::Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n                [async](HttpResult httpResult) mutable\n                {\n                    HandleHttpResult(std::move(httpResult), std::move(async));\n                }\n            });\n        }\n\n    private:\n        static void HandleHttpResult(\n            HttpResult result,\n            AsyncContext<xbox::services::Result<void>>&& async\n        ) noexcept\n        {\n            auto sharedThis{ std::dynamic_pointer_cast<ServiceCall>(result.Payload()) };\n\n            if (Failed(result))\n            {\n                return async.Complete(result);\n            }\n\n            auto httpResult{ result.Payload()->Result() };\n            switch (httpResult)\n            {\n            case HTTP_E_STATUS_BAD_REQUEST:\n                // Retrying 400 unlikely to resolve the issue so just treat that the same as\n                // a success and complete the async operation\n            case HTTP_E_STATUS_DENIED:\n                // XblHttpCall already retries 401 so don't do it again here.\n            case S_OK:\n            {\n                return async.Complete(S_OK);\n            }\n            default:\n            {\n                // For other failures, backoff and retry\n                auto backoff{ __min(std::pow(2, ++sharedThis->m_iteration), 60) * 1000 };\n\n                async.Queue().RunWork([ sharedThis, async ]\n                {\n                    HRESULT hr = sharedThis->ResetAndCopyForRetry();\n                    if (FAILED(hr))\n                    {\n                        return async.Complete(hr);\n                    }\n\n                    hr = sharedThis->XblHttpCall::Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),\n                        [async](HttpResult httpResult) mutable\n                        {\n                            HandleHttpResult(std::move(httpResult), std::move(async));\n                        }\n                    });\n\n                    if (FAILED(hr))\n                    {\n                        return async.Complete(hr);\n                    }\n                },\n                backoff);\n            }\n            }\n        }\n\n        uint32_t m_iteration{ 0 };\n        std::shared_ptr<GlobalState> m_globalState{ nullptr };\n    };\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto serviceCall = MakeShared<ServiceCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(serviceCall->InitServiceCall(m_xboxLiveContextSettings, m_titleId));\n\n    JsonDocument requestBody{ rapidjson::kObjectType };\n    auto& a{ requestBody.GetAllocator() };\n\n    JsonValue recentPlayers{ rapidjson::kArrayType };\n    for (auto& update : m_pendingRecentPlayerUpdates)\n    {\n        JsonValue player{ rapidjson::kObjectType };\n        player.AddMember(\"id\", JsonValue{ utils::uint64_to_internal_string(update.first).data(), a }.Move(), a);\n        player.AddMember(\"timestamp\", JsonUtils::SerializeTime(update.second.timestamp, a).Move(), a);\n        player.AddMember(\"encounterType\", JsonValue{ EnumName(update.second.encounterType).data(), a }.Move(), a);\n        recentPlayers.PushBack(player.Move(), a);\n    }\n\n    requestBody.AddMember(\"recentPlayers\", recentPlayers.Move(), a);\n\n    RETURN_HR_IF_FAILED(serviceCall->SetRequestBody(requestBody));\n    RETURN_HR_IF_FAILED(serviceCall->PerformWithRetry(std::move(async)));\n\n    m_pendingRecentPlayerUpdates.clear();\n    return S_OK;\n}\n\nuint64_t MultiplayerActivityService::GetSequenceNumber()\n{\n    uint64_t dateTime = xbox::services::datetime::utc_now().to_interval(); // eg. 131472330440000000\n    const uint64_t dateTimeFromJan1st2015 = 130645440000000000;\n    if (dateTime < dateTimeFromJan1st2015)\n    {\n        return static_cast<int64_t>(time(nullptr)); // Clock is wrong and is not yet sync'd with internet time so just revert to old logic\n    }\n    else\n    {\n        uint64_t dateTimeSince2015 = dateTime - dateTimeFromJan1st2015; // eg. 826888900000000\n        uint64_t dateTimeTrimmed = dateTimeSince2015 >> 16; // divide by 2^16 to get it to sub second range.  eg. 12617323303\n        return dateTimeTrimmed;\n    }\n}\n\nHRESULT MultiplayerActivityService::SetActivity(\n    _In_ const ActivityInfo& info,\n    _In_ bool allowCrossPlatformJoin,\n    _In_ AsyncContext<HRESULT> async\n) const noexcept\n{\n    Stringstream path{};\n    path << \"/titles/\" << m_titleId << \"/users/\" << m_user.Xuid() << \"/activities\";\n\n    JsonDocument requestBody{ rapidjson::kObjectType };\n    auto& a{ requestBody.GetAllocator() };\n\n    requestBody.AddMember(\"sequenceNumber\", GetSequenceNumber(), a);\n    requestBody.AddMember(\"connectionString\", JsonValue{ info.connectionString.data(), a }, a);\n    requestBody.AddMember(\"joinRestriction\", JsonValue{ EnumName(info.joinRestriction).data(), a }, a);\n    if (info.maxPlayers)\n    {\n        requestBody.AddMember(\"maxPlayers\", static_cast<uint64_t>(info.maxPlayers), a);\n    }\n    if (info.currentPlayers)\n    {\n        requestBody.AddMember(\"currentPlayers\", static_cast<uint64_t>(info.currentPlayers), a);\n    }\n    if (!info.groupId.empty())\n    {\n        requestBody.AddMember(\"groupId\", JsonValue{ info.groupId.data(), a }, a);\n    }\n    if (!allowCrossPlatformJoin)\n    {\n        requestBody.AddMember(\"platform\", JsonValue{ PlatformName(GetLocalPlatform()).data(), a }, a);\n    }\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"PUT\",\n        XblHttpCall::BuildUrl(MPA_SERVICE_NAME, path.str()),\n        xbox_live_api::set_activity\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestBody));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            async.Complete(hr);\n        }\n        });\n}\n\nHRESULT MultiplayerActivityService::GetActivity(\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ AsyncContext<Result<Vector<ActivityInfo>>> async\n) const noexcept\n{\n    Stringstream path{};\n    path << \"/titles/\" << m_titleId << \"/activities/query\";\n\n    JsonDocument requestBody{ rapidjson::kObjectType };\n    auto& a{ requestBody.GetAllocator() };\n\n    JsonValue userList;\n    JsonUtils::SerializeVector(JsonUtils::JsonXuidSerializer, xuids, userList, a);\n    requestBody.AddMember(\"users\", userList.Move(), a);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(MPA_SERVICE_NAME, path.str()),\n        xbox_live_api::get_activity_batch\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestBody));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async,\n            titleId{ m_titleId }\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            if (SUCCEEDED(hr))\n            {\n                return async.Complete(ActivityInfo::Deserialize(httpResult.Payload()->GetResponseBodyJson(), titleId));\n            }\n            return async.Complete(hr);\n        }\n        });\n}\n\nHRESULT MultiplayerActivityService::DeleteActivity(\n    _In_ AsyncContext<HRESULT> async\n) const noexcept\n{\n    Stringstream path;\n    path << \"/titles/\" << m_titleId << \"/users/\" << m_user.Xuid() << \"/activities\";\n\n    JsonDocument requestBody{ rapidjson::kObjectType };\n    auto& a{ requestBody.GetAllocator() };\n\n    requestBody.AddMember(\"sequenceNumber\", GetSequenceNumber(), a);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"DELETE\",\n        XblHttpCall::BuildUrl(MPA_SERVICE_NAME, path.str()),\n        xbox_live_api::delete_activity\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestBody));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            async.Complete(hr);\n        }\n        });\n}\n\nHRESULT MultiplayerActivityService::SendInvites(\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ bool allowCrossPlatformJoin,\n    _In_ const String& connectionString,\n    _In_ AsyncContext<HRESULT> async\n) const noexcept\n{\n    Stringstream path;\n    path << \"/titles/\" << m_titleId << \"/invites\";\n\n    JsonDocument requestBody{ rapidjson::kObjectType };\n    auto& a{ requestBody.GetAllocator() };\n\n    if (!allowCrossPlatformJoin)\n    {\n        requestBody.AddMember(\"platform\", JsonValue{ PlatformName(GetLocalPlatform()).data(), a }, a);\n    }\n    if (!connectionString.empty())\n    {\n        requestBody.AddMember(\"connectionString\", JsonValue{ connectionString.data(), a }, a);\n    }\n    JsonValue invitedUsersArray{ rapidjson::kArrayType };\n    for (auto xuid : xuids)\n    {\n        auto xuidString{ utils::uint64_to_internal_string(xuid) };\n        invitedUsersArray.PushBack(JsonValue{ xuidString.data(), a }, a);\n    }\n    requestBody.AddMember(\"invitedUsers\", invitedUsersArray.Move(), a);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(MPA_SERVICE_NAME, path.str()),\n        xbox_live_api::mpa_send_invites\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestBody));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            async.Complete(hr);\n        }\n        });\n}\n\nvoid MultiplayerActivityService::ScheduleRecentPlayersUpdate() noexcept\n{\n    auto hr = m_queue.RunWork([weakThis = std::weak_ptr<MultiplayerActivityService>{ shared_from_this() }]\n        {\n            auto pThis{ weakThis.lock() };\n            if (pThis)\n            {\n                pThis->FlushRecentPlayers({ pThis->m_queue, [ pThis ] (Result<void> result)\n                {\n                    // FlushRecentPlayers already has retry logic. If we get to this point, just log the error\n                    // and schedule the next upload.\n                    if (Failed(result))\n                    {\n                        LOGS_ERROR << \"MultiplayerActivity::FlushRecentPlayers failed with HRESULT \" << result.Hresult();\n                    }\n                    pThis->ScheduleRecentPlayersUpdate();\n                } });\n            }\n        },\n        RECENT_PLAYERS_UPLOAD_INTERVAL_MS\n    );\n\n    if (FAILED(hr))\n    {\n        // Not much we can do if RunWork fails so just log the error and return\n        LOGS_ERROR << __FUNCTION__ << \" failed with HRESULT \" << hr;\n    }\n}\n\nXblMultiplayerActivityPlatform MultiplayerActivityService::GetLocalPlatform() noexcept\n{\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    auto GDKDeviceType{ XSystemGetDeviceType() };\n    switch (GDKDeviceType)\n    {\n    case XSystemDeviceType::Pc:\n    {\n        return XblMultiplayerActivityPlatform::WindowsOneCore;\n    }\n    case XSystemDeviceType::XboxOne:\n    case XSystemDeviceType::XboxOneS:\n    case XSystemDeviceType::XboxOneX:\n    case XSystemDeviceType::XboxOneXDevkit:\n    {\n        return XblMultiplayerActivityPlatform::XboxOne;\n    }\n    case XSystemDeviceType::XboxScarlettLockhart:\n    case XSystemDeviceType::XboxScarlettAnaconda:\n    case XSystemDeviceType::XboxScarlettDevkit:\n    {\n        return XblMultiplayerActivityPlatform::Scarlett;\n    }\n    case XSystemDeviceType::Unknown:\n    default:\n    {\n        LOGS_DEBUG << \"Unable to detect GDK device type\";\n        assert(false);\n        return XblMultiplayerActivityPlatform::Unknown;\n    }\n    }\n#else\n    constexpr XblMultiplayerActivityPlatform localPlatform\n    {\n    #if HC_PLATFORM == HC_PLATFORM_WIN32\n        XblMultiplayerActivityPlatform::Win32\n    #elif HC_PLATFORM == HC_PLATFORM_UWP\n        XblMultiplayerActivityPlatform::WindowsOneCore\n    #elif HC_PLATFORM == HC_PLATFORM_XDK\n        XblMultiplayerActivityPlatform::XboxOne\n    #elif HC_PLATFORM == HC_PLATFORM_ANDROID\n        XblMultiplayerActivityPlatform::Android\n    #elif HC_PLATFORM == HC_PLATFORM_IOS\n        XblMultiplayerActivityPlatform::iOS\n    #elif HC_PLATFORM == HC_PLATFORM_MAC\n        XblMultiplayerActivityPlatform::MacOS\n    #elif HC_PLATFORM == HC_PLATFORM_NINTENDO_SWITCH\n        XblMultiplayerActivityPlatform::Nintendo\n    #elif HC_PLATFORM_IS_PLAYSTATION\n        XblMultiplayerActivityPlatform::PlayStation\n    #else\n        XblMultiplayerActivityPlatform::Unknown\n    #endif\n    };\n\n    static_assert(localPlatform != XblMultiplayerActivityPlatform::Unknown, \"Unable to detect platform\");\n\n    return localPlatform;\n#endif\n}\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Services/Notification/Mobile/notification_service_mobile.cpp",
    "content": "#include \"pch.h\"\n#include \"notification_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\nMobileNotificationService::MobileNotificationService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n) : NotificationService(std::move(user), contextSettings)\n{}\n\nHRESULT MobileNotificationService::RegisterWithNotificationService(\n    _In_ const String& endpointId,\n    _In_ AsyncContext<HRESULT> async) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(endpointId);\n\n    // http://xboxwiki/wiki/DeviceEndpoint_Object#Filter_Sources\n    Vector<NotificationFilter> notificationFilterList;\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    notificationFilterList.push_back({ NotificationTypeFilterSourceType::Multiplayer, 1 });  // Game invites\n    notificationFilterList.push_back({ NotificationTypeFilterSourceType::Multiplayer, 8 });  // Game invites with connection string\n    notificationFilterList.push_back({ NotificationTypeFilterSourceType::Achievements, 1 }); // Achievement unlocked\n#endif\n    auto currentEndPointId = AppConfig::Instance()->EndpointId();\n    if (!currentEndPointId.empty())\n    {\n        std::weak_ptr<MobileNotificationService> thisWeak = std::dynamic_pointer_cast<MobileNotificationService>(shared_from_this());\n        // If already subscribed before, unsubscribe the old endpoint first\n        return UnregisterFromNotificationHelper(\n            currentEndPointId,\n            {\n                async.Queue(),\n                [\n                    thisWeak,\n                    endpointId,\n                    async,\n                    notificationFilterList\n                ](HRESULT result)\n                {\n                    if (FAILED(result))\n                    {\n                        return async.Complete(result);\n                    }\n\n                    std::shared_ptr<MobileNotificationService> pThis(thisWeak.lock());\n                    if (pThis != nullptr)\n                    {\n                        pThis->RegisterForNotificationsHelper(\n                            utils::create_guid(true),\n                            endpointId,\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n                            _T(\"Android\"),\n                            _T(\"AndroidDevice\"),\n                            _T(\"XSAPI_ANDROID\"),\n#elif HC_PLATFORM == HC_PLATFORM_IOS\n                            _T(\"iOS\"),\n                            _T(\"iOSDevice\"),\n                            _T(\"XSAPI_I\"),\n#endif\n                            notificationFilterList,\n                            async\n                        );\n                    }\n                }\n            });\n    }\n    else {\n        return RegisterForNotificationsHelper(\n            utils::create_guid(true),\n            endpointId,\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n            _T(\"Android\"),\n            _T(\"AndroidDevice\"),\n            _T(\"XSAPI_ANDROID\"),\n#elif HC_PLATFORM == HC_PLATFORM_IOS\n            _T(\"iOS\"),\n            _T(\"iOSDevice\"),\n            _T(\"XSAPI_I\"),\n#endif\n            notificationFilterList,\n            async\n        );\n    }\n}\n\n#endif\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n"
  },
  {
    "path": "Source/Services/Notification/RTA/notification_service_rta.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"notification_internal.h\"\n#include \"real_time_activity_manager.h\"\n#include \"multiplayer_internal.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\n\nRTANotificationService::RTANotificationService(\n    _In_ User&& user,\n    _In_ const TaskQueue& queue,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings,\n    _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n) noexcept :\n    NotificationService(std::move(user), contextSettings),\n    m_taskQueue{ queue.DeriveWorkerQueue() },\n    m_rtaManager{ std::move(rtaManager) }\n{\n}\n\nRTANotificationService::~RTANotificationService() noexcept\n{\n    m_rtaManager->RemoveSubscription(m_user, m_rtaSubscription);\n    m_rtaManager->Deactivate(m_user);\n}\n\nHRESULT RTANotificationService::Initialize() noexcept\n{\n    // Always register with notification service as it powers SPOP for Win32\n\n    // Subscribing to events requires two separate steps:\n    // 1) Creating and adding an RTA subscription to the notification endpoint\n    // 2) Registering with the notification service\n\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    auto copyUserResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n\n    m_rtaManager->Activate(m_user);\n    m_rtaSubscription = MakeShared<NotificationSubscription>(copyUserResult.ExtractPayload(), m_taskQueue, AppConfig::Instance()->TitleId());\n    RETURN_HR_IF_FAILED(m_rtaManager->AddSubscription(m_user, m_rtaSubscription));\n\n    return RegisterWithNotificationService(\n        m_rtaSubscription->ResourceUri(),\n        AsyncContext<HRESULT>{ m_taskQueue,\n        [](HRESULT hr)\n        {\n            if (FAILED(hr))\n            {\n                LOGS_ERROR << \"Failed to register with Notification Service hr=\" << std::hex << hr;\n            }\n        }\n    });\n}\n\nHRESULT RTANotificationService::RegisterWithNotificationService(\n    _In_ const String& uriData,\n    _In_ AsyncContext<HRESULT> async\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    Stringstream titleId;\n    titleId << AppConfig::Instance()->TitleId();\n\n    const char platform[]{\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    \"Win32\",\n#elif HC_PLATFORM == HC_PLATFORM_NINTENDO_SWITCH\n    \"NintendoSwitch\",\n#elif HC_PLATFORM_IS_PLAYSTATION\n    \"PlayStation\",\n#endif\n    };\n\n    Vector<NotificationFilter> notificationFilterList;\n    notificationFilterList.push_back({ NotificationTypeFilterSourceType::Multiplayer, 1 });\n    notificationFilterList.push_back({ NotificationTypeFilterSourceType::Multiplayer, 8 });\n    notificationFilterList.push_back({ NotificationTypeFilterSourceType::Achievements, 1 });\n\n    return NotificationService::RegisterForNotificationsHelper(\n        utils::create_guid(true), // applicationInstanceId\n        uriData,\n        platform,\n        \"\",\n        \"\",\n        notificationFilterList,\n        std::move(async)\n    );\n}\n\nXblFunctionContext RTANotificationService::AddGameInviteHandler(\n    _In_ NotificationSubscription::MPSDInviteHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    assert(m_rtaSubscription);\n    return m_rtaSubscription->AddHandler(std::move(handler));\n}\n\nXblFunctionContext RTANotificationService::AddGameInviteHandler(\n    _In_ NotificationSubscription::MultiplayerActivityInviteHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    assert(m_rtaSubscription);\n    return m_rtaSubscription->AddHandler(std::move(handler));\n}\n\nXblFunctionContext RTANotificationService::AddAchievementUnlockNotificationHandler(\n    _In_ NotificationSubscription::AchievementUnlockHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    assert(m_rtaSubscription);\n    return m_rtaSubscription->AddHandler(std::move(handler));\n}\n\nvoid RTANotificationService::RemoveNotificationHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    m_rtaSubscription->RemoveHandler(token);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n#endif\n"
  },
  {
    "path": "Source/Services/Notification/RTA/notification_subscription.cpp",
    "content": "#include \"pch.h\"\n#include \"notification_subscription.h\"\n#include \"real_time_activity_manager.h\"\n#include \"multiplayer_internal.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\n\nNotificationSubscription::NotificationSubscription(\n    _In_ User&& user,\n    _In_ TaskQueue queue,\n    _In_ uint32_t titleId\n) noexcept :\n    m_user{ std::move(user) },\n    m_queue{ std::move(queue) }\n{\n    Stringstream ss;\n    ss << \"https://notify.xboxlive.com/users/xuid(\" << m_user.Xuid() << \")/deviceId/current/titleId/\" << titleId;\n    m_resourceUri = ss.str();\n}\n\nconst String& NotificationSubscription::ResourceUri() const noexcept\n{\n    return m_resourceUri;\n}\n\nXblFunctionContext NotificationSubscription::AddHandler(MPSDInviteHandler&& handler) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_mpsdInviteHandlers[m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nXblFunctionContext NotificationSubscription::AddHandler(MultiplayerActivityInviteHandler&& handler) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_mpaInviteHandlers[m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nXblFunctionContext NotificationSubscription::AddHandler(AchievementUnlockHandler&& handler) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_achievementUnlockHandlers[m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nsize_t NotificationSubscription::RemoveHandler(XblFunctionContext token) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    \n    m_mpaInviteHandlers.erase(token);\n    m_mpsdInviteHandlers.erase(token);\n    m_achievementUnlockHandlers.erase(token);\n\n    // return the total number of handlers remaining\n    return m_mpaInviteHandlers.size() + m_mpsdInviteHandlers.size() + m_achievementUnlockHandlers.size();\n}\n\nvoid NotificationSubscription::OnEvent(\n    _In_ const JsonValue& data\n) noexcept\n{\n    // Notifications from several services are delivered via the same RTA subscription. Examine the payload to \n    // distinguish between them.\n\n    if (!data.IsObject())\n    {\n        LOGS_ERROR << __FUNCTION__ << \": Ignoring unrecognized payload\";\n    }\n    else if (data.HasMember(\"inviteHandle\"))\n    {\n        String originatingService;\n        JsonUtils::ExtractJsonString(data, \"service\", originatingService);\n        if (originatingService != \"achievements\")\n        {\n            // Deserialize and send invite notification\n            auto deserializationResult = GameInviteNotificationEventArgs::Deserialize(data[\"inviteHandle\"]);\n            if (Succeeded(deserializationResult))\n            {\n                std::unique_lock<std::mutex> lock{ m_mutex };\n                auto handlers{ m_mpsdInviteHandlers };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second(deserializationResult.Payload());\n                }\n            }\n        }\n    }\n    else if (data.HasMember(\"notificationData\"))\n    {\n        // Deserialize and send invite notification\n        auto deserializationResult = MultiplayerActivityInviteData::Deserialize(data[\"notificationData\"]);\n        if (Succeeded(deserializationResult))\n        {\n            std::unique_lock<std::mutex> lock{ m_mutex };\n            auto handlers{ m_mpaInviteHandlers };\n            lock.unlock();\n\n            for (auto& handler : handlers)\n            {\n                handler.second(deserializationResult.Payload());\n            }\n        }\n    }\n    else if (data.HasMember(\"KickNotification\"))\n    {\n        XalUserGetTokenAndSignatureArgs args{};\n        args.forceRefresh = true;\n        args.url = \"https://xboxlive.com/\";\n        args.method = \"GET\";\n\n        auto async = MakeUnique<XAsyncBlock>();\n        async->queue = m_queue.GetHandle();\n        async->callback = [](XAsyncBlock* async)\n        {\n            // Take ownership of async block\n            UniquePtr<XAsyncBlock> asyncUnique{ async };\n\n            // Get the result even though we aren't using it so Xal can release it\n            size_t bufferSize{};\n            HRESULT hr = XalUserGetTokenAndSignatureSilentlyResultSize(async, &bufferSize);\n\n            if (SUCCEEDED(hr))\n            {\n                Vector<uint8_t> buffer(bufferSize);\n                XalUserGetTokenAndSignatureData* xalTokenSignatureData{ nullptr };\n\n                hr = XalUserGetTokenAndSignatureSilentlyResult(async, bufferSize, buffer.data(), &xalTokenSignatureData, nullptr);\n                UNREFERENCED_PARAMETER(hr);\n            }\n        };\n\n        if (SUCCEEDED(XalUserGetTokenAndSignatureSilentlyAsync(m_user.Handle(), &args, async.get())))\n        {\n            async.release();\n        }\n    }\n    else if (data.HasMember(\"service\"))\n    {\n        String originatingService;\n        JsonUtils::ExtractJsonString(data, \"service\", originatingService);\n\n        if (originatingService == \"achievements\")\n        {\n            // Deserialize and send invite notification\n            auto deserializationResult = AchievementUnlockEvent::Deserialize(data);\n            if (Succeeded(deserializationResult))\n            {\n                std::unique_lock<std::mutex> lock{ m_mutex };\n                auto handlers{ m_achievementUnlockHandlers };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second(deserializationResult.Payload());\n                }\n            }\n        }\n    }\n    else\n    {\n        LOGS_ERROR << __FUNCTION__ << \": Ignoring unrecognized payload\";\n    }\n}\n\nGameInviteNotificationEventArgs::GameInviteNotificationEventArgs(\n    const GameInviteNotificationEventArgs& other\n) noexcept\n    : XblGameInviteNotificationEventArgs{ other },\n    m_inviteHandleId{ other.m_inviteHandleId },\n    m_inviteProtocol{ other.m_inviteProtocol },\n    m_inviteContext{ other.m_inviteContext },\n    m_senderImageUrl{ other.m_senderImageUrl }\n{\n    if (!m_inviteHandleId.empty())\n    {\n        inviteHandleId = m_inviteHandleId.data();\n    }\n    if (!m_inviteProtocol.empty())\n    {\n        inviteProtocol = m_inviteProtocol.data();\n    }\n    if (!m_inviteContext.empty())\n    {\n        inviteContext = m_inviteContext.data();\n    }\n    if (!m_senderImageUrl.empty())\n    {\n        senderImageUrl = m_senderImageUrl.data();\n    }\n}\n\nResult<GameInviteNotificationEventArgs> GameInviteNotificationEventArgs::Deserialize(\n    _In_ const JsonValue& inviteHandle\n) noexcept\n{\n    if (!inviteHandle.IsObject())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    GameInviteNotificationEventArgs result{};\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(inviteHandle, \"invitedXuid\", result.invitedXboxUserId, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(inviteHandle, \"senderXuid\", result.senderXboxUserId, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteHandle, \"id\", result.m_inviteHandleId, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteHandle, \"inviteProtocol\", result.m_inviteProtocol, true));\n    if (inviteHandle.IsObject() && inviteHandle.HasMember(\"inviteAttributes\"))\n    {\n        const JsonValue& inviteAttributesValue = inviteHandle[\"inviteAttributes\"];\n\n        if (inviteAttributesValue.HasMember(\"context\"))\n        {\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteAttributesValue, \"context\", result.m_inviteContext, true));\n        }\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(inviteHandle, \"expiration\", result.expiration, true));\n    result.sessionReference = xbox::services::multiplayer::Serializers::DeserializeSessionReference(inviteHandle[\"sessionRef\"]).Payload();\n\n    if (inviteHandle.IsObject() && inviteHandle.HasMember(\"inviteInfo\"))\n    {\n        const JsonValue& inviteInfoValue = inviteHandle[\"inviteInfo\"];\n        String sender, senderMGT, senderMGTSuffix, senderUniqueMGT;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteInfoValue, \"sender\", sender, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteInfoValue, \"senderModernGamertag\", senderMGT, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteInfoValue, \"senderModernGamertagSuffix\", senderMGTSuffix, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteInfoValue, \"senderUniqueModernGamertag\", senderUniqueMGT, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inviteInfoValue, \"senderImageUrl\", result.m_senderImageUrl, true));\n        utils::strcpy(result.senderGamertag, sizeof(result.senderGamertag), sender.c_str());\n        utils::strcpy(result.senderModernGamertag, sizeof(result.senderModernGamertag), senderMGT.c_str());\n        utils::strcpy(result.senderModernGamertagSuffix, sizeof(result.senderModernGamertagSuffix), senderMGTSuffix.c_str());\n        utils::strcpy(result.senderUniqueModernGamertag, sizeof(result.senderUniqueModernGamertag), senderUniqueMGT.c_str());\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n    return result;\n}\n\nMultiplayerActivityInviteData::MultiplayerActivityInviteData(\n    const MultiplayerActivityInviteData& other\n) noexcept\n    : XblMultiplayerActivityInviteData{ other },\n    m_senderImageUrl{ other.m_senderImageUrl },\n    m_titleName{ other.m_titleName },\n    m_titleImageUrl{ other.m_titleImageUrl },\n    m_connectionString{ other.m_connectionString }\n{\n    if (!m_titleName.empty())\n    {\n        titleName = m_titleName.data();\n    }\n    if (!m_connectionString.empty())\n    {\n        connectionString = m_connectionString.data();\n    }\n    if (!m_titleImageUrl.empty())\n    {\n        titleImageUrl = m_titleImageUrl.data();\n    }\n    if (!m_senderImageUrl.empty())\n    {\n        senderImageUrl = m_senderImageUrl.data();\n    }\n}\n\nResult<MultiplayerActivityInviteData> MultiplayerActivityInviteData::Deserialize(\n    const JsonValue& notificationData\n) noexcept\n{\n    if (!notificationData.IsObject())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    MultiplayerActivityInviteData data{};\n    if (notificationData.HasMember(\"sender\"))\n    {\n        auto& senderJson{ notificationData[\"sender\"] };\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(senderJson, \"xuid\", data.senderXuid, true));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(senderJson, \"imageUrl\", data.m_senderImageUrl));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(senderJson, \"gamertag\", data.senderGamertag, sizeof(data.senderGamertag)));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(senderJson, \"modernGamertag\", data.senderModernGamertag, sizeof(data.senderModernGamertag)));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(senderJson, \"modernGamertagSuffix\", data.senderModernGamertagSuffix, sizeof(data.senderModernGamertagSuffix)));\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(senderJson, \"uniqueModernGamertag\", data.senderUniqueModernGamertag, sizeof(data.senderUniqueModernGamertag)));\n    }\n    else\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(notificationData, \"invitedUser\", data.invitedXuid, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(notificationData, \"titleName\", data.m_titleName, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(notificationData, \"titleImageUrl\", data.m_titleImageUrl));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(notificationData, \"connectionString\", data.m_connectionString));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(notificationData, \"expirationTime\", data.expirationTime));\n\n    return data;\n}\n\nAchievementUnlockEvent::AchievementUnlockEvent(AchievementUnlockEvent&& event) noexcept :\n    m_achievementId(std::move(event.m_achievementId)),\n    m_achievementDescription(std::move(event.m_achievementDescription)),\n    m_achievementName(std::move(event.m_achievementName)),\n    m_achievementIconUri(std::move(event.m_achievementIconUri)),\n    m_deepLink(event.m_deepLink)\n{\n    // strings for the C API\n    achievementId = m_achievementId.c_str();\n    achievementName = m_achievementName.c_str();\n    achievementDescription = m_achievementDescription.c_str();\n    achievementIcon = m_achievementIconUri.c_str();\n    titleId = event.titleId;\n    gamerscore = event.gamerscore;\n    rarityPercentage = event.rarityPercentage;\n    rarityCategory = event.rarityCategory;\n    timeUnlocked = event.timeUnlocked;\n    xboxUserId = event.xboxUserId;\n}\n\nAchievementUnlockEvent::AchievementUnlockEvent(const AchievementUnlockEvent& event) :\n    m_achievementId(event.m_achievementId),\n    m_achievementDescription(event.m_achievementDescription),\n    m_achievementName(event.m_achievementName),\n    m_achievementIconUri(event.m_achievementIconUri),\n    m_deepLink(event.m_deepLink)\n{\n    // strings for the C API\n    achievementId = m_achievementId.c_str();\n    achievementName = m_achievementName.c_str();\n    achievementDescription = m_achievementDescription.c_str();\n    achievementIcon = m_achievementIconUri.c_str();\n\n    titleId = event.titleId;\n    gamerscore = event.gamerscore;\n    rarityPercentage = event.rarityPercentage;\n    rarityCategory = event.rarityCategory;\n    timeUnlocked = event.timeUnlocked;\n    xboxUserId = event.xboxUserId;\n}\n\n\nResult<AchievementUnlockEvent> AchievementUnlockEvent::Deserialize(_In_ const JsonValue& json) noexcept\n{\n    AchievementUnlockEvent result{};\n    if (!json.IsObject())\n    {\n        return result;\n    }\n\n    double rarityPercentage = 0.0; // We are guaranteed that rarityPercentage is only float, but can only extract as double.\n    uint64_t titleId = 0; // We are guaranteed that titleId is only uint32, but can only extract as uint64.\n    String rarityCategory; // Will be converted into an enum value after extraction\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"achievementId\", result.m_achievementId, true));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"achievementDescription\", result.m_achievementDescription, false));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"achievementName\", result.m_achievementName, true));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"achievementIcon\", result.m_achievementIconUri, true));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToUInt64(json, \"titleId\", titleId, true));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(json, \"gamerscore\", result.gamerscore, true));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"xuid\", result.xboxUserId, true));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"extendedInfoUrl\", result.m_deepLink, true));\n\n    // RarityPercentage and rarityCategory are only in payload version 2 so make them optional\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonDouble(json, \"rarityPercentage\", rarityPercentage, false));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"rarityCategory\", rarityCategory, false));\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"unlockTime\", result.timeUnlocked));\n\n    result.titleId = static_cast<uint32_t>(titleId);\n    result.rarityPercentage = static_cast<float>(rarityPercentage);\n    result.rarityCategory = EnumValue<XblAchievementRarityCategory>(rarityCategory.c_str());\n\n    // strings for the C API\n    result.achievementId = result.m_achievementId.c_str();\n    result.achievementName = result.m_achievementName.c_str();\n    if (!result.m_achievementDescription.empty())\n    {\n        result.achievementDescription = result.m_achievementDescription.c_str();\n    }\n    result.achievementIcon = result.m_achievementIconUri.c_str();\n    result.m_deepLink = result.m_deepLink.c_str();\n\n    return result;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n\n#endif"
  },
  {
    "path": "Source/Services/Notification/RTA/notification_subscription.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/game_invite_c.h\"\n#include \"xsapi-c/achievements_c.h\"\n#include \"xsapi-c/multiplayer_activity_c.h\"\n#include \"real_time_activity_subscription.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\n\n// Event args for MPSD game invites\nstruct GameInviteNotificationEventArgs : public XblGameInviteNotificationEventArgs\n{\npublic:\n    GameInviteNotificationEventArgs() noexcept = default;\n    GameInviteNotificationEventArgs(const GameInviteNotificationEventArgs& other) noexcept;\n    GameInviteNotificationEventArgs& operator=(GameInviteNotificationEventArgs other) noexcept = delete;\n\n    static Result<GameInviteNotificationEventArgs> Deserialize(\n        _In_ const JsonValue& json\n    ) noexcept;\n\nprivate:\n    String m_inviteHandleId;\n    String m_inviteProtocol;\n    String m_inviteContext;\n    String m_senderImageUrl;\n};\n\nstruct MultiplayerActivityInviteData : public XblMultiplayerActivityInviteData\n{\npublic:\n    MultiplayerActivityInviteData() noexcept = default;\n    MultiplayerActivityInviteData(const MultiplayerActivityInviteData& other) noexcept;\n    MultiplayerActivityInviteData& operator=(MultiplayerActivityInviteData other) noexcept = delete;\n\n    static Result<MultiplayerActivityInviteData> Deserialize(\n        const JsonValue& json\n    ) noexcept;\n\nprivate:\n    String m_senderImageUrl;\n    String m_titleName;\n    String m_titleImageUrl;\n    String m_connectionString;\n};\n\nstruct AchievementUnlockEvent : public XblAchievementUnlockEvent\n{\npublic:\n\n    AchievementUnlockEvent() = default;\n    AchievementUnlockEvent(AchievementUnlockEvent&& event) noexcept;\n    AchievementUnlockEvent(const AchievementUnlockEvent& event);\n\n    static Result<AchievementUnlockEvent> Deserialize(_In_ const JsonValue& json) noexcept;\n\nprivate:\n\n    String m_achievementId;\n    String m_achievementDescription;\n    String m_achievementName;\n    String m_achievementIconUri;\n    String m_deepLink;\n};\n\nclass NotificationSubscription : public real_time_activity::Subscription\n{\npublic:\n    NotificationSubscription(\n        User&& user,\n        TaskQueue queue,\n        uint32_t titleId\n    ) noexcept;\n\n    const String& ResourceUri() const noexcept;\n\n    using MPSDInviteHandler = Function<void(GameInviteNotificationEventArgs&)>;\n    using MultiplayerActivityInviteHandler = Function<void(MultiplayerActivityInviteData&)>;\n    using AchievementUnlockHandler = Function<void(const AchievementUnlockEvent&)>;\n\n    XblFunctionContext AddHandler(MPSDInviteHandler&& handler) noexcept;\n    XblFunctionContext AddHandler(MultiplayerActivityInviteHandler&& handler) noexcept;\n    XblFunctionContext AddHandler(AchievementUnlockHandler&& handler) noexcept;\n\n    size_t RemoveHandler(XblFunctionContext token) noexcept;\n\nprotected:\n    void OnEvent(_In_ const JsonValue& event) noexcept override;\n\nprivate:\n    User m_user;\n    TaskQueue m_queue;\n    std::mutex m_mutex;\n    XblFunctionContext m_nextToken{ 1 };\n\n    Map<XblFunctionContext, MPSDInviteHandler> m_mpsdInviteHandlers;\n    Map<XblFunctionContext, MultiplayerActivityInviteHandler> m_mpaInviteHandlers;\n    Map<XblFunctionContext, AchievementUnlockHandler> m_achievementUnlockHandlers;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n#endif"
  },
  {
    "path": "Source/Services/Notification/UWP/notification_service_uwp.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"notification_internal.h\"\n#include \"xsapi_utils.h\"\n#include \"xsapi-cpp/system.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\n\nUWPNotificationService::UWPNotificationService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n) noexcept :\n    NotificationService(std::move(user), contextSettings)\n{\n}\n\nHRESULT UWPNotificationService::RegisterWithNotificationService(\n    _In_ AsyncContext<HRESULT> async\n) noexcept\n{\n\n    std::weak_ptr<UWPNotificationService> thisWeak = std::dynamic_pointer_cast<UWPNotificationService>(shared_from_this());\n\n    //hold onto a reference to global state to prevent cleanup while the subscribe call is still out\n    std::shared_ptr<GlobalState> holdCleanup{ GlobalState::Get() };\n\n    // Setup WNS Channel for Push Notifications\n    auto notificationChannelAsyncOp = Windows::Networking::PushNotifications::PushNotificationChannelManager::CreatePushNotificationChannelForApplicationAsync();\n    notificationChannelAsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Networking::PushNotifications::PushNotificationChannel ^>(\n        [thisWeak, async, holdCleanup](Windows::Foundation::IAsyncOperation<Windows::Networking::PushNotifications::PushNotificationChannel^>^ asyncOp, Windows::Foundation::AsyncStatus status)\n    {\n        if (status == Windows::Foundation::AsyncStatus::Completed)\n        {\n            try\n            {\n                auto channel = asyncOp->GetResults();\n                channel->PushNotificationReceived += ref new Windows::Foundation::TypedEventHandler<Windows::Networking::PushNotifications::PushNotificationChannel ^, Windows::Networking::PushNotifications::PushNotificationReceivedEventArgs ^>(\n                    [thisWeak, async](Windows::Networking::PushNotifications::PushNotificationChannel ^ channel, Windows::Networking::PushNotifications::PushNotificationReceivedEventArgs^ args)\n                {\n                    try\n                    {\n                        std::shared_ptr<UWPNotificationService> pThis(thisWeak.lock());\n                        if (pThis != nullptr)\n                        {\n                            try\n                            {\n                                pThis->OnPushNotificationReceived(channel, args);\n                            }\n                            catch (...)\n                            {\n                                LOG_ERROR(\"OnPushNotificationReceived error\");\n                            }\n                        }\n                    }\n\n                    catch (...)\n                    {\n                        LOG_ERROR(\"OnPushNotificationReceived error\");\n                    }\n                });\n\n                auto family = Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamily;\n                auto form = Windows::System::Profile::AnalyticsInfo::DeviceForm;\n                auto version = Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamilyVersion;\n                xsapi_internal_string platform;\n                if (family == \"Windows.Mobile\")\n                {\n                    platform = \"WindowsOneCoreMobile\";\n                }\n                else if (family == \"Windows.Xbox\")\n                {\n                    platform = \"Durango\";\n                }\n                else\n                {\n                    platform = \"WindowsOneCore\";\n                }\n\n                Vector<NotificationFilter> notificationFilterList;\n                std::shared_ptr<UWPNotificationService> pThis(thisWeak.lock());\n                if (pThis != nullptr)\n                {\n                    pThis->RegisterForNotificationsHelper(\n                        utils::create_guid(true), // applicationInstanceId\n                        utils::internal_string_from_string_t(channel->Uri->Data()),\n                        platform,\n                        \"\",\n                        \"\",\n                        notificationFilterList,\n                        {\n                            async.Queue(),\n                            [thisWeak, async](HRESULT hr)\n                            {\n                               if (auto pThis{ thisWeak.lock() })\n                               {\n                                  if (SUCCEEDED(hr))\n                                  {\n                                      async.Complete(hr);\n                                  }\n                                  else\n                                  {\n                                      LOG_ERROR(\"Failed to successfully register with notification service\");\n                                      async.Complete(E_XBL_RUNTIME_ERROR);\n                                  }\n                               }\n                            }\n                        });\n                }\n            }\n            catch (...)\n            {\n                LOG_ERROR(\"Failed to successfully register with notification service\");\n            }\n        }\n    });\n\n    return S_OK;\n}\n\nvoid UWPNotificationService::OnPushNotificationReceived(\n    _In_ Windows::Networking::PushNotifications::PushNotificationChannel ^sender,\n    _In_ Windows::Networking::PushNotifications::PushNotificationReceivedEventArgs ^args\n)\n{\n    HRESULT errc = S_OK;\n    if (args && args->RawNotification && args->RawNotification->Content)\n    {\n        string_t content = args->RawNotification->Content->Data();\n        JsonDocument parsedJson;\n        parsedJson.Parse(utils::internal_string_from_string_t(content).c_str());\n\n        if (parsedJson.HasParseError())\n        {\n            errc = WEB_E_INVALID_JSON_STRING;\n        }\n\n        xsapi_internal_string notificationTypeString;\n        xsapi_internal_string xuid;\n        if (parsedJson.IsObject() && parsedJson.HasMember(\"xboxLiveNotification\"))\n        {\n            const JsonValue& xboxLiveNotificationJson = parsedJson[\"xboxLiveNotification\"];\n            errc |= JsonUtils::ExtractJsonString(xboxLiveNotificationJson, \"notificationType\", notificationTypeString);\n            errc |= JsonUtils::ExtractJsonString(xboxLiveNotificationJson, \"userXuid\", xuid);\n        }\n\n        if (!errc)\n        {\n            LOGS_INFO << \"Received WNS notification, type: \" << notificationTypeString << \", xuid: \" << xuid;\n\n            if (utils::str_icmp(notificationTypeString.c_str(), \"spop\") == 0)\n            {\n                User::SetTokenExpired(utils::internal_string_to_uint64(xuid));\n            }\n        }\n        else\n        {\n            LOGS_ERROR << \"Receiving WNS notification error: \" << errc << \", message: \" << utils::convert_hresult_to_error_name(errc);\n        }\n    }\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END"
  },
  {
    "path": "Source/Services/Notification/iOS/notification_helper.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"notification_helper.h\"\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#if XSAPI_I\n\nxbox_live_result<xbox_live_notification> parse_notification(NSDictionary* notificationInfo)\n{\n    NSError *error;\n    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:notificationInfo\n        options:0\n        error:&error];\n    \n    if (error != nil)\n    {\n        string_t errorDescription = string_t([[NSString stringWithFormat:@\"Error parsing the notification payload! Error: %@\", [error localizedDescription]] UTF8String]);\n        return xbox_live_result<xbox_live_notification>(xbox_live_error_code::json_error, errorDescription);\n    }\n    else\n    {\n        xbox_live_notification result;\n        string_t notificationStr([[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] UTF8String]);\n        JsonDocument payload;\n        payload.Parse(utils::internal_string_from_string_t(notificationStr).c_str());\n\n        if(!payload.HasParseError())\n        {\n            HRESULT errc = S_OK;\n            string_t title;\n            string_t body;\n            \n            if(payload.IsObject() && payload.HasMember(\"aps\") && payload.HasMember(\"data\"))\n            {\n                const JsonValue& aps = payload[\"aps\"]; //required\n                const JsonValue& data = payload[\"data\"]; //required\n                \n                string_t type;\n                errc |= JsonUtils::ExtractJsonString(data, \"type\", type, true);\n                \n                if(aps.IsObject() && aps.HasMember(\"alert\"))\n                {\n                    const JsonValue& alert = aps[\"alert\"]; //required\n                \n                    if(utils::str_icmp(type, _T(\"xbox_live_game_invite\")) == 0)\n                    {\n                        result.type = xbox_live_notification_type::game_invite;\n                        \n                        string_t locKey;\n                        errc |= JsonUtils::ExtractJsonString(alert, \"loc-key\", locKey, true);\n                        string_t titleLocKey;\n                        errc |= JsonUtils::ExtractJsonString(alert, \"title-loc-key\", titleLocKey, true);\n                        std::vector<string_t> bodyArgs;\n                        \n                        if(alert.IsObject() && alert.HasMember(\"loc-args\"))\n                        {\n                            const JsonValue& locArgs= alert[\"loc-args\"]; //requried\n                            \n                            for(const JsonValue& arg : locArgs.GetArray())\n                            {\n                                xsapi_internal_string argString;\n                                errc |= JsonUtils::ExtractJsonAsString(arg, argString);\n                                bodyArgs.push_back(utils::string_t_from_internal_string(argString));\n                            }\n                            \n                            NSString* titleLocStr = NSLocalizedString([NSString stringWithUTF8String:titleLocKey.c_str()], nil);\n                            NSString* bodyLocStr = NSLocalizedString([NSString stringWithUTF8String:locKey.c_str()], nil);\n\n                            //The below snippet formats the localization string one parameter at a time.\n                            stringstream_t ss;\n                            NSArray *items = [bodyLocStr componentsSeparatedByString:@\"%\"];\n                            uint32_t index = 0;\n                            for (NSString* item in items)\n                            {\n                                if(item.length > 0)\n                                {\n                                    NSString *format = @\"%\";\n                                    format = [format stringByAppendingString:item];\n                                    ss << [[NSString stringWithFormat:format, [NSString stringWithUTF8String:bodyArgs[index].c_str()]] UTF8String];\n                                    index = MIN((uint32_t)bodyArgs.size(), index + 1);\n                                }\n                            }\n                            \n                            title = [titleLocStr UTF8String];\n                            body = ss.str();\n                        }\n                    }\n                    else if(utils::str_icmp(type, _T(\"xbox_live_achievement_unlock\")) == 0)\n                    {\n                        result.type = xbox_live_notification_type::achievement_unlocked;\n                        errc |= JsonUtils::ExtractJsonString(alert, \"title\", title, true);\n                        errc |= JsonUtils::ExtractJsonString(alert, \"body\", body, true);\n                    }\n                    else\n                    {\n                        result.type = xbox_live_notification_type::unknown;\n                    }\n                }\n                \n                if(data.IsObject() && data.HasMember(\"xbl\"))\n                {\n                    const JsonValue& xblInfo = data[\"xbl\"]; //required\n                    \n                    result.title = title;\n                    result.body = body;\n                    result.data = JsonUtils::SerializeJson(xblInfo);\n                    \n                    return xbox_live_result<xbox_live_notification>(result, ConvertHrToXblErrorCode(errc));\n                }\n            }\n        }\n\n        return xbox_live_result<xbox_live_notification>(result, xbox_live_error_code::json_error);\n    }\n}\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Services/Notification/notification_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n\n#include \"pch.h\"\n#include \"notification_internal.h\"\n#include \"multiplayer_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::notification;\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\nSTDAPI XblNotificationSubscribeToNotificationsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ const char* registrationToken\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(registrationToken == nullptr || strlen(registrationToken) <= 1);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(asyncBlock);\n\n    return RunAsync(asyncBlock, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            registrationToken\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n             auto result = xblContext->NotificationService()->RegisterWithNotificationService(\n                registrationToken,\n                {\n                    data->async->queue,\n                    [\n                        async{ data->async }\n                    ]\n                    (HRESULT hr)\n                    {\n                        XAsyncComplete(async, hr, 0);\n                    }\n             });\n            \n             if (FAILED(result))\n             {\n                 return result;\n             }\n             return E_PENDING;\n        }\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\n/// <summary>\n/// Unsubscribes title from push notifications.\n/// </summary>\nSTDAPI XblNotificationUnsubscribeFromNotificationsAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(asyncBlock);\n\n    return RunAsync(asyncBlock, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            auto result = xblContext->NotificationService()->UnregisterFromNotificationService(\n                {\n                       data->async->queue,\n                       [\n                           async{ data->async }\n                       ]\n                       (HRESULT hr)\n                       {\n                           XAsyncComplete(async, hr, 0);\n                       }\n                });\n\n            if (FAILED(result))\n            {\n                return result;\n            }\n            return E_PENDING;\n        }\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\n#elif HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n\nSTDAPI XblGameInviteRegisterForEventAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::Begin:\n        {\n            XAsyncComplete(data->async, S_OK, sizeof(XblRealTimeActivitySubscriptionHandle));\n            return S_OK;\n        }\n        case XAsyncOp::GetResult:\n        {\n            // Return a dummy subscription handle that is cleaned up when client unsubscribes\n            auto handlePtr = static_cast<XblRealTimeActivitySubscriptionHandle*>(data->buffer);\n            *handlePtr = Make<XblRealTimeActivitySubscription>();\n            return S_OK;\n        }\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblGameInviteRegisterForEventResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblRealTimeActivitySubscriptionHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(handle);\n\n    XblRealTimeActivitySubscriptionHandle handleCopy{ nullptr };\n    auto hr = XAsyncGetResult(async, nullptr, sizeof(XblRealTimeActivitySubscriptionHandle), &handleCopy, nullptr);\n\n    if (SUCCEEDED(hr))\n    {\n        *handle = handleCopy;\n    }\n    else\n    {\n        *handle = nullptr;\n    }\n\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblGameInviteUnregisterForEventAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || subscriptionHandle == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            subscriptionHandle\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::Begin:\n        {\n            Delete(subscriptionHandle);\n            XAsyncComplete(data->async, S_OK, 0);\n            return S_OK;\n        }\n        default: return S_OK;\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblGameInviteAddNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblGameInviteHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    // TODO really should be returning HRESULT E_INVALIDARG here\n    if (xblContextHandle == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    auto rtaNotificationService = std::dynamic_pointer_cast<RTANotificationService>(xblContextHandle->NotificationService());\n    return rtaNotificationService->AddGameInviteHandler(NotificationSubscription::MPSDInviteHandler{\n        [\n            handler, context\n        ]\n    (const GameInviteNotificationEventArgs& args)\n    {\n        try\n        {\n            handler(&args, context);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblGameInviteRemoveNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContextHandle)\n    {\n        auto rtaNotificationService = std::dynamic_pointer_cast<RTANotificationService>(xblContextHandle->NotificationService());\n        rtaNotificationService->RemoveNotificationHandler(token);\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(XblFunctionContext) XblAchievementUnlockAddNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblAchievementUnlockHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    // TODO really should be returning HRESULT E_INVALIDARG here\n    if (xblContextHandle == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    auto rtaNotificationService = std::dynamic_pointer_cast<RTANotificationService>(xblContextHandle->NotificationService());\n    return rtaNotificationService->AddAchievementUnlockNotificationHandler(\n        [handler, context]\n        (const AchievementUnlockEvent& args)\n        {\n            try\n            {\n                handler(&args, context);\n            }\n            catch (...)\n            {\n                LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n            }\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblAchievementUnlockRemoveNotificationHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext functionContext\n) XBL_NOEXCEPT\ntry\n{\n    auto rtaNotificationService = std::dynamic_pointer_cast<RTANotificationService>(xblContextHandle->NotificationService());\n    rtaNotificationService->RemoveNotificationHandler(functionContext);\n}\nCATCH_RETURN_WITH(;)\n\n#endif\n"
  },
  {
    "path": "Source/Services/Notification/notification_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n#include \"real_time_activity_subscription.h\"\n#include \"RTA/notification_subscription.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\n\nenum NotificationTypeFilterSourceType\n{\n    Media_Presence = 1,\n    Presence_Online = 2,\n    Broadcast = 3,\n    Message = 4,\n    Party_Invite_360 = 5,\n    Multiplayer = 6,\n    Achievements = 8\n};\n\nstruct NotificationFilter\n{\n    NotificationTypeFilterSourceType sourceType;\n    uint32_t type;\n};\n\nclass NotificationService : public std::enable_shared_from_this<NotificationService>\n{\npublic:\n    enum class RegistrationStatus : uint32_t\n    {\n        Unregistered,\n        Unregistering,\n        PendingUnregistration,\n        Registered,\n        Registering\n    } m_registrationStatus{ RegistrationStatus::Unregistered };\n\n    NotificationService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings);\n    virtual ~NotificationService() = default;\n\n    virtual HRESULT RegisterWithNotificationService(\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n        _In_ const String& endpointId,\n#endif\n        _In_ AsyncContext<HRESULT> async) = 0;\n\n    virtual HRESULT UnregisterFromNotificationService(\n        _In_ AsyncContext<HRESULT> async);\n\nprotected:\n    AsyncContext<HRESULT> m_registrationAsync;\n    AsyncContext<HRESULT> m_unregistrationAsync;\n\n    HRESULT RegisterForNotificationsHelper(\n        _In_ const String& applicationInstanceId,\n        _In_ const String& uriData,\n        _In_ const String& platform,\n        _In_ const String& deviceName,\n        _In_ const String& platformVersion,\n        _In_ const Vector<NotificationFilter> notificationFilterEnum,\n        _In_ AsyncContext<HRESULT> async\n    );\n\n    HRESULT UnregisterFromNotificationHelper(\n        _In_ const String& endpointId,\n        _In_ AsyncContext<HRESULT> async);\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_contextSettings;\n\n    String m_endpointId;\n    bool m_isInitialized{ false };\n\n    std::recursive_mutex m_mutex;\n};\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_IOS\nclass MobileNotificationService : public NotificationService\n{\npublic:\n    MobileNotificationService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings);\n\n    HRESULT RegisterWithNotificationService(\n        _In_ const String& uriData,\n        _In_ AsyncContext<HRESULT> async\n    ) noexcept override;\n};\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n\nclass RTANotificationService : public NotificationService\n{\npublic:\n    RTANotificationService(\n        _In_ User&& user,\n        _In_ const TaskQueue& taskQueue,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings,\n        _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n    ) noexcept;\n\n    ~RTANotificationService() noexcept;\n\n    HRESULT Initialize() noexcept;\n\n    XblFunctionContext AddGameInviteHandler(\n        _In_ NotificationSubscription::MPSDInviteHandler handler\n    ) noexcept;\n\n    XblFunctionContext AddGameInviteHandler(\n        _In_ NotificationSubscription::MultiplayerActivityInviteHandler handler\n    ) noexcept;\n\n    void RemoveNotificationHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\n    XblFunctionContext AddAchievementUnlockNotificationHandler(\n        _In_ NotificationSubscription::AchievementUnlockHandler handler\n    ) noexcept;\n\n    HRESULT RegisterWithNotificationService(\n        _In_ const String& endpointId,\n        _In_ AsyncContext<HRESULT> async\n    ) noexcept override;\n\nprivate:\n    TaskQueue m_taskQueue;\n    std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> m_rtaManager;\n    std::shared_ptr<NotificationSubscription> m_rtaSubscription;\n};\n#endif\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n"
  },
  {
    "path": "Source/Services/Notification/notification_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"notification_internal.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\nusing namespace pplx;\n\nstatic const std::chrono::milliseconds RETRY_LENGTH(60 * 1000);\nstatic const int32_t NUM_RETRY_TIMES = 10;\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN\nNotificationService::NotificationService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n) :\n    m_user(std::move(user)),\n    m_contextSettings(contextSettings)\n{}\n\nHRESULT NotificationService::UnregisterFromNotificationService(\n    _In_ AsyncContext<HRESULT> async)\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    switch (m_registrationStatus)\n    {\n    case RegistrationStatus::Unregistered:\n    {\n        // No work to do in this case\n        async.Complete(S_OK);\n        return S_OK;\n    }\n    case RegistrationStatus::Unregistering:\n    case RegistrationStatus::PendingUnregistration:\n    {\n        // If we are already unregistering, collapse the AsyncContext and return\n        m_unregistrationAsync = AsyncContext<HRESULT>::Collapse({ std::move(m_unregistrationAsync), std::move(async) });\n        return S_OK;\n    }\n    case RegistrationStatus::Registering:\n    {\n        // Wait until registration finishes and then unregister\n        m_registrationStatus = RegistrationStatus::PendingUnregistration;\n        m_unregistrationAsync = std::move(async);\n        return S_OK;\n    }\n    case RegistrationStatus::Registered:\n    default:\n    {\n        // Otherwise proceed with unregistration\n        m_registrationStatus = RegistrationStatus::Unregistering;\n        m_unregistrationAsync = std::move(async);\n\n        assert(!m_endpointId.empty());\n        return UnregisterFromNotificationHelper(m_endpointId, async);\n    }\n    }\n}\n\nHRESULT NotificationService::UnregisterFromNotificationHelper(\n    _In_ const String& endpointId,\n    _In_ AsyncContext<HRESULT> async)\n{\n    auto subpath = \"/system/notifications/endpoints/\" + endpointId;\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_contextSettings,\n        \"DELETE\",\n        XblHttpCall::BuildUrl(\"notify\", subpath),\n        xbox_live_api::subscribe_to_notifications\n    );\n\n    RETURN_HR_IF_FAILED(hr);\n\n    return httpCall->Perform(AsyncContext<HttpResult>{\n        async.Queue().DeriveWorkerQueue(),\n            [\n                thisWeakPtr = std::weak_ptr<NotificationService>{ shared_from_this() },\n                async\n            ](HttpResult httpResult)\n        {\n            if (auto pThis{ thisWeakPtr.lock() })\n            {\n                if (pThis == nullptr)\n                {\n                    async.Complete(E_XBL_RUNTIME_ERROR);\n                    return;\n                }\n\n                std::lock_guard<std::recursive_mutex> lock{ pThis->m_mutex };\n                // If the call fails, log but still treat it as though we are now unregistered\n                pThis->m_registrationStatus = RegistrationStatus::Unregistered;\n                pThis->m_endpointId.clear();\n                HRESULT hr = httpResult.Hresult();\n                if (SUCCEEDED(hr))\n                {\n                    hr = httpResult.Payload()->Result();\n                    if (FAILED(hr))\n                    {\n                        LOG_ERROR(\"notification service attempt failed\\n\");\n                        LOG_ERROR(\"http status code: \");\n                        LOGS_ERROR << httpResult.Payload()->HttpStatus();\n                    }\n                }\n\n                async.Complete(hr);\n                return pThis->m_unregistrationAsync.Complete(hr);\n            }\n            else\n            {\n                return async.Complete(E_XBL_RUNTIME_ERROR);\n            }\n        }\n    });\n}\n\nHRESULT NotificationService::RegisterForNotificationsHelper(\n    _In_ const String& applicationInstanceId,\n    _In_ const String& uriData,\n    _In_ const String& platform,\n    _In_ const String& deviceName,\n    _In_ const String& platformVersion,\n    _In_ const Vector<NotificationFilter> notificationFilterEnum,\n    _In_ AsyncContext<HRESULT> async\n)\n{\n    switch (m_registrationStatus)\n    {\n    case RegistrationStatus::PendingUnregistration:\n    {\n        // This indicates registration is in progress. Since another registration was requested, abort the \n        // pending unregistration, complete the unregistration AsyncContext, and collapse the register AsyncContexts\n        m_registrationAsync = AsyncContext<HRESULT>::Collapse({ std::move(m_registrationAsync), std::move(async) });\n        m_registrationStatus = RegistrationStatus::Registering;\n        m_unregistrationAsync.Complete(E_ABORT);\n        return S_OK;\n    }\n    case RegistrationStatus::Registered:\n    {\n        // If we have already registered, no work to do\n        async.Complete(S_OK);\n        return S_OK;\n    }\n    case RegistrationStatus::Registering:\n    {\n        // If we are already registering, collapse the AsyncContexts and return\n        m_registrationAsync = AsyncContext<HRESULT>::Collapse({ std::move(m_registrationAsync), std::move(async) });\n        return S_OK;\n    }\n    default:\n    {\n        auto workQueue = async.Queue().DeriveWorkerQueue();\n        m_registrationAsync = std::move(async);\n        m_registrationStatus = RegistrationStatus::Registering;\n\n        xsapi_internal_stringstream str;\n        str << AppConfig::Instance()->TitleId();\n        xsapi_internal_string titleId = str.str();\n        JsonDocument payload(rapidjson::kObjectType);\n        JsonDocument::AllocatorType& allocator = payload.GetAllocator();\n        payload.AddMember(\"systemId\", JsonValue(applicationInstanceId.data(), allocator).Move(), allocator);\n        payload.AddMember(\"endpointUri\", JsonValue(uriData.data(), allocator).Move(), allocator);\n        payload.AddMember(\"platform\", JsonValue(platform.data(), allocator).Move(), allocator);\n        if (!platformVersion.empty())\n        {\n            payload.AddMember(\"platformVersion\", JsonValue(platformVersion.data(), allocator).Move(), allocator);\n        }\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n        payload.AddMember(\"transport\", \"NotiHub\", allocator);\n        payload.AddMember(\"transportPath\", JsonValue(AppConfig::Instance()->APNSEnvironment().c_str(), allocator).Move(), allocator);\n#elif HC_PLATFORM == HC_PLATFORM_ANDROID\n        payload.AddMember(\"transport\", \"FCM\", allocator);\n#elif HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK || HC_PLATFORM_IS_EXTERNAL\n        payload.AddMember(\"transport\", \"RTA\", allocator);\n#endif\n        xsapi_internal_string locale = utils::get_locales();\n        payload.AddMember(\"locale\", JsonValue(locale.c_str(), allocator).Move(), allocator);\n        payload.AddMember(\"titleId\", JsonValue(titleId.c_str(), allocator).Move(), allocator);\n\n        if (!deviceName.empty())\n        {\n            payload.AddMember(\"deviceName\", JsonValue(deviceName.data(), allocator).Move(), allocator);\n        }\n\n        JsonValue filterJson(rapidjson::kArrayType);\n        for (auto& notificationFilter : notificationFilterEnum)\n        {\n            JsonValue filterObj(rapidjson::kObjectType);\n            filterObj.AddMember(\"action\", \"Include\", allocator);\n            filterObj.AddMember(\"source\", notificationFilter.sourceType, allocator);\n            filterObj.AddMember(\"type\", notificationFilter.type, allocator);\n            filterJson.PushBack(filterObj, allocator);\n        }\n\n        payload.AddMember(\"filters\", filterJson, allocator);\n        Result<User> userResult = m_user.Copy();\n        RETURN_HR_IF_FAILED(userResult.Hresult());\n\n        auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n        RETURN_HR_IF_FAILED(httpCall->Init(\n            m_contextSettings,\n            \"POST\",\n            XblHttpCall::BuildUrl(\"notify\", \"/system/notifications/endpoints\"),\n            xbox_live_api::subscribe_to_notifications\n        ));\n\n        RETURN_HR_IF_FAILED(httpCall->SetRequestBody(payload));\n        return httpCall->Perform(AsyncContext<HttpResult>{\n            workQueue,\n                [\n                    thisWeakPtr = std::weak_ptr<NotificationService>{ shared_from_this() }\n                ](HttpResult httpResult)\n            {\n                std::shared_ptr<NotificationService> pThis(thisWeakPtr.lock());\n\n                if (pThis == nullptr)\n                {\n                    return;\n                }\n\n                HRESULT hr = httpResult.Hresult();\n                if (SUCCEEDED(hr))\n                {\n                    hr = httpResult.Payload()->Result();\n                    if (SUCCEEDED(hr))\n                    {\n                        const JsonValue& responseJson = httpResult.Payload()->GetResponseBodyJson();\n                        hr = JsonUtils::ExtractJsonString(responseJson, \"endpointId\", pThis->m_endpointId);\n                        // Registration has succeeded at this point\n                        switch (pThis->m_registrationStatus)\n                        {\n                        case RegistrationStatus::Registering:\n                        {\n                            pThis->m_registrationStatus = RegistrationStatus::Registered;\n                            pThis->m_registrationAsync.Complete(hr);\n                            break;\n                        }\n                        default:\n                        {\n                            // No other states should be possible\n                            assert(false);\n                        }\n                        }\n                    }\n                    else\n                    {\n                        // Registration failed for some reason\n                        pThis->m_registrationStatus = RegistrationStatus::Unregistered;\n                        pThis->m_registrationAsync.Complete(E_XBL_RUNTIME_ERROR);\n                    }\n                }\n            }\n        });\n    }\n    };\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END\n\n\n"
  },
  {
    "path": "Source/Services/Presence/device_presence_change_subscription.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"presence_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nDevicePresenceChangeSubscription::DevicePresenceChangeSubscription(\n    _In_ uint64_t xuid,\n    _In_ std::shared_ptr<PresenceService> presenceService\n) noexcept\n    : m_xuid{ xuid },\n    m_presenceService{ presenceService }\n{\n    Stringstream uri;\n    uri << \"https://userpresence.xboxlive.com/users/xuid(\" << m_xuid << \")/devices\";\n    m_resourceUri = uri.str();\n}\n\nvoid DevicePresenceChangeSubscription::OnSubscribe(\n    const JsonValue& data\n) noexcept\n{\n    if (data.IsNull())\n    {\n        LOGS_ERROR << __FUNCTION__ << \": RTA payload unexpectedly null\";\n        return;\n    }\n\n    auto presenceService{ m_presenceService.lock() };\n    if (presenceService)\n    {\n        auto deserializationResult = XblPresenceRecord::Deserialize(data);\n        if (Succeeded(deserializationResult))\n        {\n            for (const auto& deviceRecord : deserializationResult.Payload()->DeviceRecords())\n            {\n                presenceService->HandleDevicePresenceChanged(m_xuid, deviceRecord.deviceType, true);\n            }\n        }\n    }\n}\n\nvoid DevicePresenceChangeSubscription::OnEvent(\n    _In_ const JsonValue& data\n) noexcept\n{\n    auto presenceService{ m_presenceService.lock() };\n    if (presenceService && data.IsString())\n    {\n        auto devicePresenceValues = utils::string_split_internal(String{ data.GetString() }, ':');\n        if (devicePresenceValues.size() == 2)\n        {\n            presenceService->HandleDevicePresenceChanged(\n                m_xuid,\n                DeviceRecord::DeviceTypeFromString(devicePresenceValues[0]),\n                utils::str_icmp_internal(devicePresenceValues[1], \"true\") == 0\n            );\n        }\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END"
  },
  {
    "path": "Source/Services/Presence/presence_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/presence_c.h\"\n#include \"presence_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::presence;\n\nSTDAPI XblPresenceRecordGetXuid(\n    _In_ XblPresenceRecordHandle record,\n    _Out_ uint64_t* xuid\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(record == nullptr || xuid == nullptr);\n    *xuid = record->Xuid();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceRecordGetUserState(\n    _In_ XblPresenceRecordHandle record,\n    _Out_ XblPresenceUserState* userState\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(record == nullptr || userState == nullptr);\n    *userState = record->UserState();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceRecordGetDeviceRecords(\n    _In_ XblPresenceRecordHandle record,\n    _Out_ const XblPresenceDeviceRecord** deviceRecords,\n    _Out_ size_t* deviceRecordsCount\n) XBL_NOEXCEPT \ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(record == nullptr || deviceRecords == nullptr || deviceRecordsCount == nullptr);\n\n    *deviceRecords = record->DeviceRecords().data();\n    *deviceRecordsCount = record->DeviceRecords().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceRecordDuplicateHandle(\n    _In_ XblPresenceRecordHandle record,\n    _Out_ XblPresenceRecordHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(record == nullptr || duplicatedHandle == nullptr);\n\n    record->AddRef();\n    *duplicatedHandle = record;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblPresenceRecordCloseHandle(\n    _In_ XblPresenceRecordHandle record\n) XBL_NOEXCEPT\ntry\n{\n    if (record)\n    {\n        record->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblPresenceSetPresenceAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ bool isUserActiveInTitle,\n    _In_opt_ XblPresenceRichPresenceIds* richPresenceIds,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            titleRequest = TitleRequest{ isUserActiveInTitle, richPresenceIds }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_PENDING_OR_HR(xblContext->PresenceService()->SetPresence(\n                std::move(titleRequest),\n                AsyncContext<HRESULT>{ data->async }\n            ));\n        }\n\n        default:\n        {\n            return S_OK;\n        }\n        } // end switch\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            xuid,\n            presenceRecord = std::shared_ptr<XblPresenceRecord>{ nullptr } // result\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_PENDING_OR_HR(xblContext->PresenceService()->GetPresence(\n                xuid,\n                AsyncContext<Result<std::shared_ptr<XblPresenceRecord>>>{\n                TaskQueue{ data->async->queue },\n                    [\n                        &presenceRecord,\n                        asyncBlock{ data->async }\n                    ]\n                (Result<std::shared_ptr<XblPresenceRecord>> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        presenceRecord = result.ExtractPayload();\n                    }\n                    XAsyncComplete(asyncBlock, result.Hresult(), sizeof(XblPresenceRecordHandle));\n                }\n            }));\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto handlePtr = static_cast<XblPresenceRecordHandle*>(data->buffer);\n            presenceRecord->AddRef();\n            *handlePtr = presenceRecord.get();\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        } // end switch\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblPresenceRecordHandle* presenceRecordHandle\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblPresenceRecordHandle), presenceRecordHandle, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI GetBatchPresenceProvider(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ UserBatchRequest&& request,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            request,\n            presenceRecords = Vector<std::shared_ptr<XblPresenceRecord>>{} // result\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_PENDING_OR_HR(xblContext->PresenceService()->GetBatchPresence(\n                std::move(request),\n                {\n                TaskQueue{ data->async->queue },\n                    [\n                        &presenceRecords,\n                        asyncBlock{ data->async }\n                    ]\n                (Result<Vector<std::shared_ptr<XblPresenceRecord>>> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        presenceRecords = result.ExtractPayload();\n                    }\n                    XAsyncComplete(asyncBlock, result.Hresult(), sizeof(XblPresenceRecordHandle)* presenceRecords.size());\n                }\n                }));\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto handlesPtr = static_cast<XblPresenceRecordHandle*>(data->buffer);\n            for (const auto& record : presenceRecords)\n            {\n                record->AddRef();\n                *handlesPtr++ = record.get();\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        } // end switch\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceForMultipleUsersAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_opt_ XblPresenceQueryFilters* filters,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || xuids == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return GetBatchPresenceProvider(\n        xblContextHandle,\n        UserBatchRequest{ xuids, xuidsCount, filters },\n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceForMultipleUsersResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(resultCount);\n\n    size_t bufferSize;\n    auto hr = XAsyncGetResultSize(async, &bufferSize);\n\n    if (SUCCEEDED(hr))\n    {\n        *resultCount = bufferSize / sizeof(XblPresenceRecordHandle);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceForMultipleUsersResult(\n    _In_ XAsyncBlock* async,\n    _Out_writes_(presenceRecordHandlesCount) XblPresenceRecordHandle* presenceRecordHandles,\n    _In_ size_t presenceRecordHandlesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(presenceRecordHandlesCount == 0, S_OK);\n    RETURN_HR_INVALIDARGUMENT_IF(presenceRecordHandles == nullptr);\n\n    return XAsyncGetResult(async, nullptr, sizeof(XblPresenceRecordHandle) * presenceRecordHandlesCount, presenceRecordHandles, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceForSocialGroupAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_z_ const char* socialGroupName,\n    _In_opt_ uint64_t* socialGroupOwnerXuid,\n    _In_opt_ XblPresenceQueryFilters* filters,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || socialGroupName == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return GetBatchPresenceProvider(\n        xblContextHandle,\n        UserBatchRequest{ socialGroupName, socialGroupOwnerXuid, filters },\n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceForSocialGroupResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultCount\n) XBL_NOEXCEPT\ntry\n{\n    return XblPresenceGetPresenceForMultipleUsersResultCount(async, resultCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceGetPresenceForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblPresenceRecordHandle* presenceRecordHandles,\n    _In_ size_t presenceRecordHandlesCount\n) XBL_NOEXCEPT\ntry\n{\n    return XblPresenceGetPresenceForMultipleUsersResult(async, presenceRecordHandles, presenceRecordHandlesCount);\n}\nCATCH_RETURN()\n\nnamespace xbox {\n    namespace services {\n        namespace presence {\n            namespace legacy {\n                struct Subscription : public XblRealTimeActivitySubscription\n                {\n                    Subscription(\n                        std::shared_ptr<PresenceService> presenceService,\n                        uint64_t xuid\n                    ) noexcept\n                        : m_presenceService{ presenceService },\n                        m_xuid{ xuid } \n                    {\n                        presenceService->TrackUsers(Vector<uint64_t>{ m_xuid });\n                    }\n\n                    virtual ~Subscription() noexcept\n                    {\n                        if (auto presenceService{ m_presenceService.lock() })\n                        {\n                            presenceService->StopTrackingUsers(Vector<uint64_t>{ m_xuid });\n                        }\n                    }\n\n                protected:\n                    std::weak_ptr<PresenceService> m_presenceService;\n\n                private:\n                    uint64_t m_xuid{ 0 };\n                };\n\n                struct TitleSubscription : public Subscription\n                {\n                    TitleSubscription(\n                        std::shared_ptr<PresenceService> presenceService,\n                        uint64_t xuid,\n                        uint32_t titleId\n                    ) noexcept\n                        : Subscription{ presenceService, xuid },\n                        m_titleId{ titleId }\n                    {\n                        presenceService->TrackAdditionalTitles(Vector<uint32_t>{ m_titleId });\n                    }\n\n                    ~TitleSubscription() noexcept\n                    {\n                        if (auto presenceService{ m_presenceService.lock() })\n                        {\n                            presenceService->StopTrackingAdditionalTitles(Vector<uint32_t>{ m_titleId });\n                        }\n                    }\n\n                private:\n                    uint32_t m_titleId{ 0 };\n                };\n            }\n        }\n    }\n}\n\nSTDAPI XblPresenceSubscribeToDevicePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(subscriptionHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || subscriptionHandle == nullptr);\n\n    *subscriptionHandle = Make<presence::legacy::Subscription>(xblContextHandle->PresenceService(), xuid);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceUnsubscribeFromDevicePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || subscriptionHandle == nullptr);\n\n    Delete(subscriptionHandle);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceSubscribeToTitlePresenceChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _In_ uint32_t titleId,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(subscriptionHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle == nullptr || subscriptionHandle == nullptr);\n\n    *subscriptionHandle = Make<presence::legacy::TitleSubscription>(xblContextHandle->PresenceService(), xuid, titleId);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceUnsubscribeFromTitlePresenceChange(\n    _In_ XblContextHandle xblContext,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || subscriptionHandle == nullptr);\n\n    Delete(subscriptionHandle);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblPresenceAddDevicePresenceChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblPresenceDevicePresenceChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContext == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    return xblContext->PresenceService()->AddDevicePresenceChangedHandler(\n        [\n            handler,\n            context\n        ]\n    (uint64_t xuid, XblPresenceDeviceType deviceType, bool isOnline)\n    {\n        try\n        {\n            handler(context, xuid, deviceType, isOnline);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceRemoveDevicePresenceChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContext);\n    xblContext->PresenceService()->RemoveDevicePresenceChangedHandler(token);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblPresenceAddTitlePresenceChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblPresenceTitlePresenceChangedHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContext == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    return xblContext->PresenceService()->AddTitlePresenceChangedHandler(\n        [\n            handler,\n            context\n        ]\n    (uint64_t xuid, uint32_t titleId, XblPresenceTitleState state)\n    {\n        try\n        {\n            handler(context, xuid, titleId, state);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceRemoveTitlePresenceChangedHandler(\n    _In_ XblContextHandle xblContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContext);\n    xblContext->PresenceService()->RemoveTitlePresenceChangedHandler(token);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceTrackUsers(\n    _In_ XblContextHandle xblContext,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || xuids == nullptr);\n    return xblContext->PresenceService()->TrackUsers(Vector<uint64_t>(xuids, xuids + xuidsCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceStopTrackingUsers(\n    _In_ XblContextHandle xblContext,\n    _In_ const uint64_t* xuids,\n    _In_ size_t xuidsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || xuids == nullptr);\n    return xblContext->PresenceService()->StopTrackingUsers(Vector<uint64_t>(xuids, xuids + xuidsCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceTrackAdditionalTitles(\n    _In_ XblContextHandle xblContext,\n    _In_ const uint32_t* titleIds,\n    _In_ size_t titleIdsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || titleIds == nullptr);\n    return xblContext->PresenceService()->TrackAdditionalTitles(Vector<uint32_t>(titleIds, titleIds + titleIdsCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblPresenceStopTrackingAdditionalTitles(\n    _In_ XblContextHandle xblContext,\n    _In_ const uint32_t* titleIds,\n    _In_ size_t titleIdsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xblContext == nullptr || titleIds == nullptr);\n    return xblContext->PresenceService()->StopTrackingAdditionalTitles(Vector<uint32_t>(titleIds, titleIds + titleIdsCount));\n}\nCATCH_RETURN()"
  },
  {
    "path": "Source/Services/Presence/presence_device_record.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"presence_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nDeviceRecord::~DeviceRecord()\n{\n    for (auto& titleRecord : m_titleRecords)\n    {\n        Delete(titleRecord.titleName);\n        Delete(titleRecord.richPresenceString);\n\n        if (titleRecord.broadcastRecord)\n        {\n            Delete(titleRecord.broadcastRecord->broadcastId);\n            Delete(titleRecord.broadcastRecord);\n        };\n    }\n}\n\nDeviceRecord::DeviceRecord(const DeviceRecord& other)\n    : m_deviceType{ other.m_deviceType },\n    m_titleRecords{ other.m_titleRecords }\n{\n    for (auto& titleRecord : m_titleRecords)\n    {\n        titleRecord.titleName = Make(titleRecord.titleName);\n        titleRecord.richPresenceString = Make(titleRecord.richPresenceString);\n        titleRecord.broadcastRecord = Make<XblPresenceBroadcastRecord>(*titleRecord.broadcastRecord);\n        titleRecord.broadcastRecord->broadcastId = Make(titleRecord.broadcastRecord->broadcastId);\n    }\n}\n\nDeviceRecord& DeviceRecord::operator=(DeviceRecord other)\n{\n    std::swap(m_deviceType, other.m_deviceType);\n    std::swap(m_titleRecords, other.m_titleRecords);\n    return *this;\n}\n\nXblPresenceDeviceType DeviceRecord::DeviceType() const\n{\n    return m_deviceType;\n}\n\nconst xsapi_internal_vector<XblPresenceTitleRecord>& DeviceRecord::TitleRecords() const\n{\n    return m_titleRecords;\n}\n\nResult<std::shared_ptr<DeviceRecord>> DeviceRecord::Deserialize(\n    _In_ const JsonValue& inputJson\n)\n{\n    if (inputJson.IsNull())\n    {\n        return Result<std::shared_ptr<DeviceRecord>>();\n    }\n\n    auto returnObject = MakeShared<DeviceRecord>();\n\n    xsapi_internal_string type;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(inputJson, \"type\", type));\n    returnObject->m_deviceType = DeviceTypeFromString(type);\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblPresenceTitleRecord>(\n        DeserializeTitleRecord,\n        inputJson, \n        \"titles\",\n         returnObject->m_titleRecords,\n        false\n    ));\n\n    return Result<std::shared_ptr<DeviceRecord>>(returnObject, S_OK);\n}\n\nResult<XblPresenceTitleRecord> DeviceRecord::DeserializeTitleRecord(_In_ const JsonValue& json)\n{\n    if (json.IsNull())\n    {\n        Result<XblPresenceTitleRecord>();\n    }\n\n    XblPresenceTitleRecord titleRecord{};\n\n    HRESULT errc = S_OK;\n    xsapi_internal_string id;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", id))\n    titleRecord.titleId = utils::internal_string_to_uint32(id);\n    xsapi_internal_string titleName;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"name\", titleName));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"lastModified\", titleRecord.lastModified));\n\n    xsapi_internal_string state;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"state\", state));\n    titleRecord.titleActive = (!state.empty() && utils::str_icmp_internal(state, \"active\") == 0);\n    xsapi_internal_string placement;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"placement\", placement));\n    titleRecord.viewState = TitleViewStateFromString(placement);\n\n    xsapi_internal_string richPresenceString = \"\";\n    if (json.IsObject() && json.HasMember(\"activity\"))\n    {\n        const JsonValue& activityJson = json[\"activity\"];\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(activityJson, \"richPresence\", richPresenceString));\n\n        if (activityJson.IsObject() && activityJson.HasMember(\"broadcast\"))\n        {\n            const JsonValue& broadcastRecordJson = activityJson[\"broadcast\"];\n            if (!broadcastRecordJson.IsNull())\n            {\n                auto broadcastRecordResult = DeserializeBroadcastRecord(broadcastRecordJson);\n                if (SUCCEEDED(broadcastRecordResult.Hresult()))\n                {\n                    titleRecord.broadcastRecord = Make<XblPresenceBroadcastRecord>(broadcastRecordResult.Payload());\n                }\n                else\n                {\n                    return Result<XblPresenceTitleRecord>(broadcastRecordResult.Hresult());\n                }\n            }\n        }\n    }\n\n    if (SUCCEEDED(errc))\n    {\n        titleRecord.titleName = Make(titleName);\n        titleRecord.richPresenceString = Make(richPresenceString);\n    }\n\n    return Result<XblPresenceTitleRecord>(titleRecord, errc);\n}\n\nResult<XblPresenceBroadcastRecord> DeviceRecord::DeserializeBroadcastRecord(_In_ const JsonValue& json)\n{\n    if (json.IsNull())\n    {\n        return Result<XblPresenceBroadcastRecord>();\n    }\n\n    XblPresenceBroadcastRecord broadcastRecord{};\n\n    HRESULT errc = S_OK;\n    \n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"session\", broadcastRecord.session, sizeof(broadcastRecord.session)));\n    xsapi_internal_string provider;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"provider\", provider));\n    broadcastRecord.provider = BroadcastProviderFromString(provider);\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"viewers\", broadcastRecord.viewerCount));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"started\", broadcastRecord.startTime));\n    xsapi_internal_string broadcastId;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"id\", broadcastId));\n\n    if (SUCCEEDED(errc))\n    {\n        broadcastRecord.broadcastId = Make(broadcastId);\n    }\n\n    return Result<XblPresenceBroadcastRecord>(broadcastRecord, errc);\n}\n\nXblPresenceTitleViewState DeviceRecord::TitleViewStateFromString(\n    _In_ const xsapi_internal_string &value\n)\n{\n    if (utils::str_icmp_internal(value, \"full\") == 0)\n    {\n        return XblPresenceTitleViewState::FullScreen;\n    }\n    else if (utils::str_icmp_internal(value, \"fill\") == 0)\n    {\n        return XblPresenceTitleViewState::Filled;\n    }\n    else if (utils::str_icmp_internal(value, \"snapped\") == 0)\n    {\n        return XblPresenceTitleViewState::Snapped;\n    }\n    else if (utils::str_icmp_internal(value, \"background\") == 0)\n    {\n        return XblPresenceTitleViewState::Background;\n    }\n\n    return XblPresenceTitleViewState::Unknown;\n}\n\nXblPresenceBroadcastProvider DeviceRecord::BroadcastProviderFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"twitch\") == 0)\n    {\n        return XblPresenceBroadcastProvider::Twitch;\n    }\n    return XblPresenceBroadcastProvider::Unknown;\n}\n\nXblPresenceDeviceType DeviceRecord::DeviceTypeFromString(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"MoLive\") == 0)\n    {\n        return XblPresenceDeviceType::Windows8;\n    }\n    else if (utils::str_icmp_internal(value, \"MCapensis\") == 0)\n    {\n        return XblPresenceDeviceType::XboxOne;\n    }\n    else\n    {\n        // The other enums line up with strings so EnumValue to automap\n        return EnumValue<XblPresenceDeviceType>(value.data());\n    }\n}\n\nxsapi_internal_string DeviceRecord::DeviceTypeAsString(\n    _In_ XblPresenceDeviceType deviceType\n)\n{\n    switch (deviceType)\n    {\n    case XblPresenceDeviceType::Windows8:\n        return \"MoLive\";\n        \n    default:\n        // The other enums line up with enums so EnumName to automap\n        return EnumName(deviceType);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END\n"
  },
  {
    "path": "Source/Services/Presence/presence_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/presence_c.h\"\n#include \"real_time_activity_subscription.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nclass UserBatchRequest\n{\npublic:\n    UserBatchRequest(\n        _In_ uint64_t* xuids,\n        _In_ size_t xuidsCount,\n        _In_opt_ XblPresenceQueryFilters* filters\n    ) noexcept;\n\n    UserBatchRequest(\n        _In_ String&& socialGroup,\n        _In_opt_ uint64_t* socialGroupOwnerXuid,\n        _In_opt_ XblPresenceQueryFilters* filters\n    ) noexcept;\n\n    static String StringFromDetailLevel(\n        _In_ XblPresenceDetailLevel level\n    );\n\n    void Serialize(_Out_ JsonValue& serializedObject, _In_ JsonDocument::AllocatorType& allocator) const;\n\nprivate:\n    UserBatchRequest(_In_opt_ XblPresenceQueryFilters* filters) noexcept;\n\n    Vector<String> m_xuids;\n    String m_socialGroup;\n    String m_socialGroupOwnerXuid;\n    Vector<String> m_deviceTypes;\n    Vector<String> m_titleIds;\n    XblPresenceDetailLevel m_presenceDetailLevel{ XblPresenceDetailLevel::Default };\n    bool m_onlineOnly{ false };\n    bool m_broadcastingOnly{ false };\n};\n\nclass TitleRequest\n{\npublic:\n    TitleRequest(\n        _In_ bool isUserActive,\n        _In_opt_ const XblPresenceRichPresenceIds* richPresenceIds\n    );\n\n    void Serialize(_Out_ JsonValue& serializedObject, _In_ JsonDocument::AllocatorType& allocator);\n\nprivate:\n    bool m_isUserActive;\n    String m_scid;\n    String m_presenceId;\n    Vector<String> m_presenceTokenIds;\n};\n\nclass PresenceService;\n\nclass TitlePresenceChangeSubscription : public real_time_activity::Subscription, public std::enable_shared_from_this<TitlePresenceChangeSubscription>\n{\npublic:\n    TitlePresenceChangeSubscription(\n        _In_ uint64_t xuid,\n        _In_ uint32_t titleId,\n        _In_ std::shared_ptr<PresenceService> presenceService\n    ) noexcept;\n\nprotected:\n    void OnSubscribe(const JsonValue& data) noexcept override;\n    void OnEvent(const JsonValue& event) noexcept override;\n\nprivate:\n    uint64_t m_xuid;\n    uint32_t m_titleId;\n    std::weak_ptr<PresenceService> m_presenceService;\n};\n\nclass DevicePresenceChangeSubscription : public real_time_activity::Subscription, public std::enable_shared_from_this<DevicePresenceChangeSubscription>\n{\npublic:\n    DevicePresenceChangeSubscription(\n        _In_ uint64_t xuid,\n        _In_ std::shared_ptr<PresenceService> presenceService\n    ) noexcept;\n\nprotected:\n    void OnSubscribe(const JsonValue& data) noexcept override;\n    void OnEvent(_In_ const JsonValue& event) noexcept override;\n\nprivate:\n    uint64_t m_xuid;\n    std::weak_ptr<class PresenceService> m_presenceService;\n};\n\nclass DeviceRecord\n{\npublic:\n    DeviceRecord() = default;\n    DeviceRecord(const DeviceRecord& other);\n    DeviceRecord& operator=(DeviceRecord other);\n    ~DeviceRecord();\n\n    XblPresenceDeviceType DeviceType() const;\n\n    const Vector<XblPresenceTitleRecord>& TitleRecords() const;\n\n    static Result<std::shared_ptr<DeviceRecord>> Deserialize(_In_ const JsonValue& json);\n\n    static String DeviceTypeAsString(_In_ XblPresenceDeviceType deviceType);\n    static XblPresenceDeviceType DeviceTypeFromString(_In_ const String& value);\n\nprivate:\n    static Result<XblPresenceTitleRecord> DeserializeTitleRecord(_In_ const JsonValue& json);\n    static Result<XblPresenceBroadcastRecord> DeserializeBroadcastRecord(_In_ const JsonValue& json);\n\n    static XblPresenceTitleViewState TitleViewStateFromString(_In_ const String& viewState);\n    static XblPresenceBroadcastProvider BroadcastProviderFromString(_In_ const String& provider);\n\n    XblPresenceDeviceType m_deviceType{ XblPresenceDeviceType::Unknown };\n    Vector<XblPresenceTitleRecord> m_titleRecords;\n};\n\nnamespace legacy\n{\n    // To support legacy RTA path, subscriptions require some extra state to be tracked\n    struct Subscription;\n    struct TitleSubscription;\n}\n\nclass PresenceService : public std::enable_shared_from_this<PresenceService>\n{\npublic:\n    PresenceService(\n        _In_ User&& user,\n        _In_ const TaskQueue& backgroundQueue,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n    ) noexcept;\n\n    ~PresenceService() noexcept;\n\n    typedef Function<void(uint64_t xuid, uint32_t titleId, XblPresenceTitleState state)> TitlePresenceChangedHandler;\n\n    XblFunctionContext AddTitlePresenceChangedHandler(\n        TitlePresenceChangedHandler handler\n    ) noexcept;\n\n    void RemoveTitlePresenceChangedHandler(\n        _In_ XblFunctionContext context\n    ) noexcept;\n\n    typedef Function<void(uint64_t xuid, XblPresenceDeviceType deviceType, bool isUserLoggedOnDevice)> DevicePresenceChangedHandler;\n\n    XblFunctionContext AddDevicePresenceChangedHandler(\n        DevicePresenceChangedHandler handler\n    ) noexcept;\n\n    void RemoveDevicePresenceChangedHandler(\n        _In_ XblFunctionContext context\n    ) noexcept;\n\n    HRESULT TrackUsers(\n        const Vector<uint64_t>& xuids\n    ) noexcept;\n\n    HRESULT StopTrackingUsers(\n        const Vector<uint64_t>& xuids\n    ) noexcept;\n\n    HRESULT TrackAdditionalTitles(\n        const Vector<uint32_t>& titleIds\n    ) noexcept;\n\n    HRESULT StopTrackingAdditionalTitles(\n        const Vector<uint32_t>& titleIds\n    ) noexcept;\n\n    HRESULT SetPresence(\n        _In_ TitleRequest&& titleRequest,\n        _In_ AsyncContext<HRESULT> async\n    ) const noexcept;\n\n    HRESULT GetPresence(\n        _In_ uint64_t xuid,\n        _In_ AsyncContext<Result<std::shared_ptr<XblPresenceRecord>>> async\n    ) const noexcept;\n\n    HRESULT GetBatchPresence(\n        _In_ UserBatchRequest&& batchRequest,\n        _In_ AsyncContext<Result<Vector<std::shared_ptr<XblPresenceRecord>>>> async\n    ) const noexcept;\n\nprivate:\n    void HandleDevicePresenceChanged(\n        _In_ uint64_t xuid,\n        _In_ XblPresenceDeviceType deviceType,\n        _In_ bool isUserLoggedOnDevice\n    ) const noexcept;\n\n    void HandleTitlePresenceChanged(\n        _In_ uint64_t xuid,\n        _In_ uint32_t titleId,\n        _In_ XblPresenceTitleState state\n    ) const noexcept;\n\n    void HandleRTAResync();\n\n    static Result<Vector<std::shared_ptr<XblPresenceRecord>>> DeserializeBatchPresenceRecordsResponse(\n        const JsonValue& json\n    ) noexcept;\n\n    User m_user;\n    TaskQueue m_queue;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n\n    XblFunctionContext m_resyncHandlerToken{ 0 };\n    Map<XblFunctionContext, DevicePresenceChangedHandler> m_devicePresenceChangedHandlers;\n    Map<XblFunctionContext, TitlePresenceChangedHandler> m_titlePresenceChangedHandlers;\n    XblFunctionContext m_nextHandlerToken{ 1 };\n\n    struct TrackedXuidSubscriptions\n    {\n        size_t refCount{ 0 };\n        std::shared_ptr<DevicePresenceChangeSubscription> devicePresenceChangedSub;\n        Map<uint32_t, std::shared_ptr<TitlePresenceChangeSubscription>> titlePresenceChangedSubscriptions;\n    };\n\n    Map<uint64_t, TrackedXuidSubscriptions> m_trackedXuids;\n    Map<uint32_t, size_t> m_trackedTitles;\n    uint32_t const m_titleId;\n\n    mutable std::recursive_mutex m_mutex;\n\n    friend class DevicePresenceChangeSubscription;\n    friend class TitlePresenceChangeSubscription;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END\n\nstruct XblPresenceRecord : public xbox::services::RefCounter, public std::enable_shared_from_this<XblPresenceRecord>\n{\npublic:\n    XblPresenceRecord() = default;\n\n    uint64_t Xuid() const;\n\n    XblPresenceUserState UserState() const;\n\n    const Vector<XblPresenceDeviceRecord>& DeviceRecords() const;\n\n    bool IsUserPlayingTitle(_In_ uint32_t titleId) const;\n\n    static xbox::services::Result<std::shared_ptr<XblPresenceRecord>> Deserialize(_In_ const JsonValue& json);\n\n    static XblPresenceUserState UserStateFromString(_In_ const xbox::services::String& value);\n\nprotected:\n    // RefCounter overrides\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override;\n\nprivate:\n    uint64_t m_xuid{};\n    XblPresenceUserState m_userState{ XblPresenceUserState::Unknown };\n\n    Vector<XblPresenceDeviceRecord> m_deviceRecords;\n    Vector<std::shared_ptr<xbox::services::presence::DeviceRecord>> m_deviceRecordsInternal;\n};"
  },
  {
    "path": "Source/Services/Presence/presence_record.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK || defined(XSAPI_UNIT_TESTS)\n#include \"social_manager_internal.h\"\n#endif\n#include \"presence_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::presence;\n\nuint64_t XblPresenceRecord::Xuid() const\n{\n    return m_xuid;\n}\n\nXblPresenceUserState XblPresenceRecord::UserState() const\n{\n    return m_userState;\n}\n\nconst xsapi_internal_vector<XblPresenceDeviceRecord>& XblPresenceRecord::DeviceRecords() const\n{\n    return m_deviceRecords;\n}\n\nbool XblPresenceRecord::IsUserPlayingTitle(\n    _In_ uint32_t titleId\n) const\n{\n    if (m_userState == XblPresenceUserState::Offline || m_userState == XblPresenceUserState::Unknown)\n    {\n        return false;\n    }\n\n    for (const auto& deviceRecord : m_deviceRecordsInternal)\n    {\n        for (const auto& titleRecord : deviceRecord->TitleRecords())\n        {\n            if (titleRecord.titleId == titleId)\n            {\n                return titleRecord.titleActive;\n            }\n        }\n    }\n\n    return false;\n}\n\nResult<std::shared_ptr<XblPresenceRecord>> XblPresenceRecord::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    if (json.IsNull())\n    {\n        return Result<std::shared_ptr<XblPresenceRecord>>(nullptr);\n    }\n\n    auto presenceRecord = MakeShared<XblPresenceRecord>();\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"xuid\", presenceRecord->m_xuid));\n    xsapi_internal_string state;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"state\", state));\n    presenceRecord->m_userState = UserStateFromString(state);\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<std::shared_ptr<DeviceRecord>>(\n        DeviceRecord::Deserialize,\n        json,\n        \"devices\",\n         presenceRecord->m_deviceRecordsInternal,\n        false\n    ));\n\n    for (const auto& deviceRecordInternal : presenceRecord->m_deviceRecordsInternal)\n    {\n        XblPresenceDeviceRecord deviceRecord\n        {\n            deviceRecordInternal->DeviceType(),\n            deviceRecordInternal->TitleRecords().data(),\n            deviceRecordInternal->TitleRecords().size()\n        };\n        presenceRecord->m_deviceRecords.push_back(std::move(deviceRecord));\n    }\n\n    return Result<std::shared_ptr<XblPresenceRecord>>(presenceRecord, S_OK);\n}\n\nXblPresenceUserState XblPresenceRecord::UserStateFromString(\n    _In_ const xsapi_internal_string& value\n    )\n{\n    if (utils::str_icmp_internal(value, \"Online\") == 0)\n    {\n        return XblPresenceUserState::Online;\n    }\n    else if (utils::str_icmp_internal(value, \"Away\") == 0)\n    {\n        return XblPresenceUserState::Away;\n    }\n    else if (utils::str_icmp_internal(value, \"Offline\") == 0)\n    {\n        return XblPresenceUserState::Offline;\n    }\n\n    return XblPresenceUserState::Unknown;\n}\n\nstd::shared_ptr<RefCounter> XblPresenceRecord::GetSharedThis()\n{\n    return shared_from_this();\n}\n"
  },
  {
    "path": "Source/Services/Presence/presence_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"presence_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nusing namespace xbox::services::system;\nusing namespace xbox::services::real_time_activity;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nPresenceService::PresenceService(\n    _In_ User&& user,\n    _In_ const TaskQueue& queue,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n) noexcept\n    : m_user{ std::move(user) },\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_xboxLiveContextSettings{ xboxLiveContextSettings },\n    m_rtaManager{ rtaManager },\n    m_titleId{ AppConfig::Instance()->TitleId() }\n{\n    // Track title presence changes for this title by default\n    m_trackedTitles.insert(std::pair<uint32_t, size_t>{ m_titleId, 1 });\n}\n\nPresenceService::~PresenceService() noexcept\n{\n    if (m_resyncHandlerToken)\n    {\n        m_rtaManager->RemoveResyncHandler(m_user, m_resyncHandlerToken);\n    }\n\n    for (auto& xuidPair : m_trackedXuids)\n    {\n        if (!m_devicePresenceChangedHandlers.empty())\n        {\n            m_rtaManager->RemoveSubscription(m_user, xuidPair.second.devicePresenceChangedSub);\n        }\n        if (!m_titlePresenceChangedHandlers.empty())\n        {\n            for (auto& titlePair : xuidPair.second.titlePresenceChangedSubscriptions)\n            {\n                m_rtaManager->RemoveSubscription(m_user, titlePair.second);\n            }\n        }\n    }\n}\n\nXblFunctionContext PresenceService::AddTitlePresenceChangedHandler(\n    TitlePresenceChangedHandler handler\n) noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n    m_titlePresenceChangedHandlers[m_nextHandlerToken] = std::move(handler);\n    auto token = m_nextHandlerToken++;\n\n    // Add subs to RTA manager if needed\n    if (m_titlePresenceChangedHandlers.empty())\n    {\n        for (auto& xuidPair : m_trackedXuids)\n        {\n            for (auto& titlePair : m_trackedTitles)\n            {\n                auto sub{ MakeShared<TitlePresenceChangeSubscription>(xuidPair.first, titlePair.first, shared_from_this()) };\n                xuidPair.second.titlePresenceChangedSubscriptions[titlePair.first] = sub;\n                m_rtaManager->AddSubscription(m_user, sub);\n            }\n        }\n    }\n\n    return token;\n}\n\nvoid PresenceService::RemoveTitlePresenceChangedHandler(\n    _In_ XblFunctionContext context\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    auto removed{ m_titlePresenceChangedHandlers.erase(context) };\n    if (removed && m_titlePresenceChangedHandlers.empty())\n    {\n        for (auto& xuidPair : m_trackedXuids)\n        {\n            for (auto& titlePair : xuidPair.second.titlePresenceChangedSubscriptions)\n            {\n                m_rtaManager->RemoveSubscription(m_user, titlePair.second);\n                titlePair.second.reset();\n            }\n        }\n    }\n}\n\nXblFunctionContext PresenceService::AddDevicePresenceChangedHandler(\n    DevicePresenceChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    // Add subs to RTA manager if needed\n    if (m_devicePresenceChangedHandlers.empty())\n    {\n        for (auto& pair : m_trackedXuids)\n        {\n            pair.second.devicePresenceChangedSub = MakeShared<DevicePresenceChangeSubscription>(pair.first, shared_from_this());\n            m_rtaManager->AddSubscription(m_user, pair.second.devicePresenceChangedSub);\n        }\n    }\n\n    m_devicePresenceChangedHandlers[m_nextHandlerToken] = std::move(handler);\n    return m_nextHandlerToken++;\n}\n\nvoid PresenceService::RemoveDevicePresenceChangedHandler(\n    _In_ XblFunctionContext context\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    auto removed{ m_devicePresenceChangedHandlers.erase(context) };\n    if (removed && m_devicePresenceChangedHandlers.empty())\n    {\n        for (auto& pair : m_trackedXuids)\n        {\n            m_rtaManager->RemoveSubscription(m_user, pair.second.devicePresenceChangedSub);\n            pair.second.devicePresenceChangedSub.reset();\n        }\n    }\n}\n\nHRESULT PresenceService::TrackUsers(\n    const Vector<uint64_t>& xuids\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    if (!m_resyncHandlerToken)\n    {\n        m_resyncHandlerToken = m_rtaManager->AddResyncHandler(m_user, [weakThis = std::weak_ptr<PresenceService>{ shared_from_this() } ]\n        {\n            auto sharedThis = weakThis.lock();\n            if (sharedThis)\n            {\n                sharedThis->HandleRTAResync();\n            }\n        });\n    }\n\n    for (auto& xuid : xuids)\n    {\n        // If we don't have them already, create RTA subscriptions for the new user\n        auto iter{ m_trackedXuids.find(xuid) };\n        if (iter == m_trackedXuids.end())\n        {\n            TrackedXuidSubscriptions newSubs{};\n            newSubs.refCount = 1;\n\n            // If there are existing handlers, add the new subs to RTA managers\n            if (!m_devicePresenceChangedHandlers.empty())\n            {\n                newSubs.devicePresenceChangedSub = MakeShared<DevicePresenceChangeSubscription>(xuid, shared_from_this());\n                RETURN_HR_IF_FAILED(m_rtaManager->AddSubscription(m_user, newSubs.devicePresenceChangedSub));\n            }\n\n            if (!m_titlePresenceChangedHandlers.empty())\n            {\n                for (auto& pair : m_trackedTitles)\n                {\n                    auto sub{ MakeShared<TitlePresenceChangeSubscription>(xuid, pair.first, shared_from_this()) };\n                    newSubs.titlePresenceChangedSubscriptions[pair.first] = sub;\n                    RETURN_HR_IF_FAILED(m_rtaManager->AddSubscription(m_user, sub));\n                }\n            }\n            m_trackedXuids[xuid] = std::move(newSubs);\n        }\n        else\n        {\n            ++(iter->second.refCount);\n        }\n    }\n    return S_OK;\n}\n\nHRESULT PresenceService::StopTrackingUsers(\n    const Vector<uint64_t>& xuids\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto& xuid : xuids)\n    {\n        auto iter{ m_trackedXuids.find(xuid) };\n        if (iter != m_trackedXuids.end() && --(iter->second.refCount) == 0)\n        {\n            // Remove the subs from RTA manager as necessary\n            if (!m_devicePresenceChangedHandlers.empty())\n            {\n                RETURN_HR_IF_FAILED(m_rtaManager->RemoveSubscription(m_user, iter->second.devicePresenceChangedSub));\n            }\n            if (!m_titlePresenceChangedHandlers.empty())\n            {\n                for (auto& pair : iter->second.titlePresenceChangedSubscriptions)\n                {\n                    RETURN_HR_IF_FAILED(m_rtaManager->RemoveSubscription(m_user, pair.second));\n                }\n            }\n            m_trackedXuids.erase(iter);\n        }\n    }\n    return S_OK;\n}\n\nHRESULT PresenceService::TrackAdditionalTitles(\n    const Vector<uint32_t>& titleIds\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto& titleId : titleIds)\n    {\n        auto iter{ m_trackedTitles.find(titleId) };\n        if (iter == m_trackedTitles.end())\n        {\n            m_trackedTitles[titleId] = 1;\n\n            // If its a new title, create the appropriate subscriptions\n            for (auto& pair : m_trackedXuids)\n            {\n                // Add new subs to RTA manager if we have handlers\n                if (!m_titlePresenceChangedHandlers.empty())\n                {\n                    auto sub{ MakeShared<TitlePresenceChangeSubscription>(pair.first, titleId, shared_from_this()) };\n                    pair.second.titlePresenceChangedSubscriptions[titleId] = sub;\n                    RETURN_HR_IF_FAILED(m_rtaManager->AddSubscription(m_user, sub));\n                }\n            }\n        }\n        else\n        {\n            ++(iter->second);\n        }\n    }\n\n    return S_OK;\n}\n\nHRESULT PresenceService::StopTrackingAdditionalTitles(\n    const Vector<uint32_t>& titleIds\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    List<uint32_t> removedTitles{};\n    for (auto& titleId : titleIds)\n    {\n        // Don't allow removal of the current title\n        if (titleId == m_titleId)\n        {\n            continue;\n        }\n\n        auto iter{ m_trackedTitles.find(titleId) };\n        if (iter != m_trackedTitles.end() && --(iter->second) == 0)\n        {\n            for (auto& pair : m_trackedXuids)\n            {\n                auto& subs{ pair.second.titlePresenceChangedSubscriptions };\n                auto subIter{ subs.find(titleId) };\n                assert(subIter != subs.end());\n\n                // Remove subs from RTA manager as necessary\n                if (!m_titlePresenceChangedHandlers.empty())\n                {\n                    RETURN_HR_IF_FAILED(m_rtaManager->RemoveSubscription(m_user, subIter->second));\n                }\n                subs.erase(subIter);\n            }\n            m_trackedTitles.erase(iter);\n        }\n    }\n    return S_OK;\n}\n\nHRESULT PresenceService::SetPresence(\n    _In_ TitleRequest&& request,\n    _In_ AsyncContext<HRESULT> async\n) const noexcept\n{\n\n    Stringstream subpath;\n    subpath << \"/users/xuid(\" << m_user.Xuid() << \")/devices/current/titles/current\";\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"userpresence\", subpath.str()),\n        xbox_live_api::set_presence_helper\n    ));\n\n    JsonDocument titleRequestJson(rapidjson::kObjectType);\n    request.Serialize(titleRequestJson, titleRequestJson.GetAllocator());\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(titleRequestJson));\n    RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTRACT_VERSION_HEADER, \"3\"));\n\n    return httpCall->Perform({\n        async.Queue(),\n        [\n            async\n        ]\n    (HttpResult result)\n    {\n        HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n        async.Complete(hr);\n    } });\n}\n\nHRESULT PresenceService::GetPresence(\n    _In_ uint64_t xuid,\n    _In_ AsyncContext<Result<std::shared_ptr<XblPresenceRecord>>> async\n) const noexcept\n{\n    Stringstream subpath;\n    subpath << \"/users/xuid(\" << xuid << \")?level=all\";\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"userpresence\", subpath.str()),\n        xbox_live_api::get_presence\n    ));\n\n    httpCall->SetHeader(CONTRACT_VERSION_HEADER, \"3\");\n\n    return httpCall->Perform({\n        async.Queue(),\n        [\n            async\n        ]\n    (HttpResult result)\n    {\n        HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n        if (SUCCEEDED(hr))\n        {\n            return async.Complete(XblPresenceRecord::Deserialize(result.Payload()->GetResponseBodyJson()));\n        }\n        return async.Complete(hr);\n    } });\n}\n\nHRESULT PresenceService::GetBatchPresence(\n    _In_ UserBatchRequest&& batchRequest,\n    _In_ AsyncContext<Result<xsapi_internal_vector<std::shared_ptr<XblPresenceRecord>>>> async\n) const noexcept\n{\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"userpresence\", \"/users/batch\"),\n        xbox_live_api::get_presence_for_multiple_users\n    ));\n\n    JsonDocument batchRequestJson(rapidjson::kObjectType);\n    batchRequest.Serialize(batchRequestJson, batchRequestJson.GetAllocator());\n    httpCall->SetRequestBody(batchRequestJson);\n    httpCall->SetHeader(CONTRACT_VERSION_HEADER, \"3\");\n\n    return httpCall->Perform({\n        async.Queue().GetHandle(),\n        [\n            async\n        ]\n    (HttpResult result)\n    {\n        HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n        if (SUCCEEDED(hr))\n        {\n            return async.Complete(DeserializeBatchPresenceRecordsResponse(result.Payload()->GetResponseBodyJson()));\n        }\n        return async.Complete(hr);\n    } });\n}\n\nvoid PresenceService::HandleDevicePresenceChanged(\n    _In_ uint64_t xuid,\n    _In_ XblPresenceDeviceType deviceType,\n    _In_ bool isUserLoggedOnDevice\n) const noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n    auto handlers{ m_devicePresenceChangedHandlers };\n    lock.unlock();\n\n    for (auto& pair : handlers)\n    {\n        pair.second(xuid, deviceType, isUserLoggedOnDevice);\n    }\n}\n\nvoid PresenceService::HandleTitlePresenceChanged(\n    _In_ uint64_t xuid,\n    _In_ uint32_t titleId,\n    _In_ XblPresenceTitleState state\n) const noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n    auto handlers{ m_titlePresenceChangedHandlers };\n    lock.unlock();\n\n    for (auto& pair : handlers)\n    {\n        pair.second(xuid, titleId, state);\n    }\n}\n\nvoid PresenceService::HandleRTAResync()\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n    LOGS_DEBUG << \"Resyncing \" << m_trackedXuids.size() << \" Presence Subscriptions\";\n\n    auto weakThis = std::weak_ptr<PresenceService>{ shared_from_this() };\n    auto handleGetPresenceResult = [weakThis, this](Result<Vector<std::shared_ptr<XblPresenceRecord>>> result)\n    {\n        auto sharedThis = weakThis.lock();\n        if (!sharedThis)\n        {\n            return;\n        }\n\n        std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n        if(Succeeded(result))\n        {\n            Vector<uint32_t> trackedTitles;\n            for (auto& pair : m_trackedTitles)\n            {\n                trackedTitles.push_back(pair.first);\n            }\n            auto titlePresenceChangedHandlers{ m_titlePresenceChangedHandlers };\n            auto devicePresenceChangedHandlers{ m_devicePresenceChangedHandlers };\n\n            lock.unlock();\n\n            for (auto& presenceRecord : result.Payload())\n            {\n                // Invoke title presence changed subs for tracked titles\n                for (auto titleId : trackedTitles)\n                {\n                    bool isPlaying = presenceRecord->IsUserPlayingTitle(titleId);\n                    for (auto& pair : titlePresenceChangedHandlers)\n                    {\n                        pair.second(presenceRecord->Xuid(), titleId, isPlaying ? XblPresenceTitleState::Started : XblPresenceTitleState::Ended);\n                    }\n                }\n\n                // Invoke device presence changed handlers\n                for (const auto& deviceRecord : presenceRecord->DeviceRecords())\n                {\n                    for (auto& pair : devicePresenceChangedHandlers)\n                    {\n                        pair.second(presenceRecord->Xuid(), deviceRecord.deviceType, true);\n                    }\n                }\n            }\n        }\n    };\n\n    Vector<uint64_t> trackedXuids;\n    for (auto& pair : m_trackedXuids)\n    {\n        trackedXuids.push_back(pair.first);\n    }\n\n    if (trackedXuids.empty())\n    {\n        // nothing to resync\n        return;\n    }\n    else if (trackedXuids.size() > 1)\n    {\n        // Make batch query\n        GetBatchPresence(\n            UserBatchRequest{ trackedXuids.data(), trackedXuids.size(), nullptr },\n            AsyncContext<Result<Vector<std::shared_ptr<XblPresenceRecord>>>>{ m_queue, std::move(handleGetPresenceResult) }\n        );\n    }\n    else\n    {\n        GetPresence(\n            trackedXuids.front(),\n            AsyncContext<Result<std::shared_ptr<XblPresenceRecord>>>{m_queue, [batchResultHandler = std::move(handleGetPresenceResult)](Result<std::shared_ptr<XblPresenceRecord>> result)\n        {\n            if (Succeeded(result))\n            {\n                batchResultHandler(Vector<std::shared_ptr<XblPresenceRecord>>{ result.ExtractPayload() });\n            }\n            else\n            {\n                batchResultHandler(result.Hresult());\n            }\n        }\n        });\n    }\n}\n\nResult<Vector<std::shared_ptr<XblPresenceRecord>>> PresenceService::DeserializeBatchPresenceRecordsResponse(\n    const JsonValue& json\n) noexcept\n{\n    Vector<std::shared_ptr<XblPresenceRecord>> presenceRecords;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<std::shared_ptr<XblPresenceRecord>>(\n        XblPresenceRecord::Deserialize,\n        json,\n        presenceRecords\n    ));\n\n    return presenceRecords;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END\n\n"
  },
  {
    "path": "Source/Services/Presence/presence_title_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"presence_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nTitleRequest::TitleRequest(\n    _In_ bool isUserActive,\n    _In_opt_ const XblPresenceRichPresenceIds* richPresenceIds\n) :\n    m_isUserActive{ isUserActive }\n{\n    if (richPresenceIds)\n    {\n        m_scid = richPresenceIds->scid;\n        m_presenceId = richPresenceIds->presenceId;\n\n        for (auto i = 0u; i < richPresenceIds->presenceTokenIdsCount; ++i)\n        {\n            m_presenceTokenIds.push_back(richPresenceIds->presenceTokenIds[i]);\n        }\n    }\n}\n\nvoid TitleRequest::Serialize(_Out_ JsonValue& serializedObject, _In_ JsonDocument::AllocatorType& allocator)\n{\n    serializedObject.SetObject();\n    xsapi_internal_string state = m_isUserActive ? \"active\" : \"inactive\";\n    serializedObject.AddMember(\"state\", JsonValue(state.c_str(), allocator).Move(), allocator);\n\n    if (!m_scid.empty() && !m_presenceId.empty())\n    {\n        JsonValue richPresenceJson(rapidjson::kObjectType);\n\n        richPresenceJson.AddMember(\"id\", JsonValue(m_presenceId.c_str(), allocator).Move(), allocator);\n        richPresenceJson.AddMember(\"scid\", JsonValue(m_scid.c_str(), allocator).Move(), allocator);\n        if (!m_presenceTokenIds.empty())\n        {\n            JsonValue presenceTokenIDsJson(rapidjson::kArrayType);\n            JsonUtils::SerializeVector(JsonUtils::JsonStringSerializer, m_presenceTokenIds, presenceTokenIDsJson, allocator);\n            richPresenceJson.AddMember(\"params\", presenceTokenIDsJson, allocator);\n        }\n\n        serializedObject.AddMember(\"activity\", JsonValue(rapidjson::kObjectType).AddMember(\"richPresence\", richPresenceJson, allocator).Move(), allocator);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END"
  },
  {
    "path": "Source/Services/Presence/presence_user_batch_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"presence_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nUserBatchRequest::UserBatchRequest(\n    _In_ uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _In_opt_ XblPresenceQueryFilters* filters\n) noexcept :\n    UserBatchRequest{ filters }\n{\n    for (size_t i = 0; i < xuidsCount; ++i)\n    {\n        m_xuids.push_back(utils::uint64_to_internal_string(xuids[i]));\n    }\n}\n\nUserBatchRequest::UserBatchRequest(\n    _In_ xsapi_internal_string&& socialGroup,\n    _In_opt_ uint64_t* socialGroupOwnerXuid,\n    _In_opt_ XblPresenceQueryFilters* filters\n) noexcept :\n    UserBatchRequest{ filters }\n{\n    m_socialGroup = socialGroup;\n    if (socialGroupOwnerXuid)\n    {\n        m_socialGroupOwnerXuid = utils::uint64_to_internal_string(*socialGroupOwnerXuid);\n    }\n}\n\nUserBatchRequest::UserBatchRequest(\n    _In_opt_ XblPresenceQueryFilters* filters\n) noexcept\n{\n    if (filters)\n    {\n        for (size_t i = 0; i < filters->deviceTypesCount; ++i)\n        {\n            m_deviceTypes.push_back(DeviceRecord::DeviceTypeAsString(filters->deviceTypes[i]));\n        }\n\n        for (size_t i = 0; i < filters->titleIdsCount; ++i)\n        {\n            m_titleIds.push_back(utils::uint64_to_internal_string(filters->titleIds[i]));\n        }\n\n        m_presenceDetailLevel = filters->detailLevel;\n        m_onlineOnly = filters->onlineOnly;\n        m_broadcastingOnly = filters->broadcastingOnly;\n    }\n}\n\nxsapi_internal_string UserBatchRequest::StringFromDetailLevel(\n    _In_ XblPresenceDetailLevel level\n)\n{\n    switch (level)\n    {\n    case XblPresenceDetailLevel::User:\n        return \"user\";\n\n    case XblPresenceDetailLevel::Device:\n        return \"device\";\n\n    case XblPresenceDetailLevel::Title:\n        return \"title\";\n\n    case XblPresenceDetailLevel::All:\n        return \"all\";\n\n    default:\n        return \"\";\n    }\n}\n\nvoid UserBatchRequest::Serialize(_Out_ JsonValue& serializedObject, _In_ JsonDocument::AllocatorType& allocator) const\n{\n    serializedObject.SetObject();\n\n    if (!m_xuids.empty())\n    {\n        JsonValue xuidsVectorJson(rapidjson::kObjectType);\n        JsonUtils::SerializeVector<xsapi_internal_string>(\n            JsonUtils::JsonStringSerializer, \n            m_xuids,\n            xuidsVectorJson,\n            allocator\n        );\n\n        serializedObject.AddMember(\"users\", xuidsVectorJson, allocator);\n    }\n    else if (!m_socialGroup.empty())\n    {\n        serializedObject.AddMember(\"group\", JsonValue(m_socialGroup.c_str(), allocator).Move(), allocator);\n        if (!m_socialGroupOwnerXuid.empty())\n        {\n            serializedObject.AddMember(\"groupXuid\",JsonValue( m_socialGroupOwnerXuid.c_str(), allocator).Move(), allocator);\n        }\n    }\n\n    if (m_deviceTypes.size() > 0)\n    {\n        JsonValue deviceTypesJson(rapidjson::kArrayType);\n        JsonUtils::SerializeVector<xsapi_internal_string>(\n            JsonUtils::JsonStringSerializer,\n            m_deviceTypes,\n            deviceTypesJson,\n            allocator\n        );\n        serializedObject.AddMember(\"deviceTypes\", deviceTypesJson, allocator);\n    }\n\n    if (m_titleIds.size() > 0)\n    {\n        JsonValue titleIdsJson(rapidjson::kArrayType);\n        JsonUtils::SerializeVector<xsapi_internal_string>(\n            JsonUtils::JsonStringSerializer,\n            m_titleIds,\n            titleIdsJson,\n            allocator\n        );\n        serializedObject.AddMember(\"titles\", titleIdsJson, allocator);\n    }\n\n    auto presenceDetailLevel = StringFromDetailLevel(m_presenceDetailLevel);\n    if (!presenceDetailLevel.empty())\n    {\n        serializedObject.AddMember(\"level\", JsonValue(presenceDetailLevel.c_str(), allocator).Move(), allocator);\n    }\n\n    serializedObject.AddMember(\"onlineOnly\", m_onlineOnly, allocator);\n    serializedObject.AddMember(\"broadcastingOnly\", m_broadcastingOnly, allocator);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END"
  },
  {
    "path": "Source/Services/Presence/title_presence_change_subscription.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"presence_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN\n\nusing namespace xbox::services::real_time_activity;\n\nTitlePresenceChangeSubscription::TitlePresenceChangeSubscription(\n    _In_ uint64_t xuid,\n    _In_ uint32_t titleId,\n    _In_ std::shared_ptr<PresenceService> presenceService\n) noexcept\n    : m_xuid{ xuid },\n    m_titleId{ titleId },\n    m_presenceService{ presenceService }\n{\n    Stringstream uri;\n    uri << \"https://userpresence.xboxlive.com/users/xuid(\" << m_xuid << \")/titles/\" << m_titleId;\n    m_resourceUri = uri.str();\n}\n\nvoid TitlePresenceChangeSubscription::OnSubscribe(\n    const JsonValue& data\n) noexcept\n{\n    if (data.IsNull())\n    {\n        LOGS_ERROR << __FUNCTION__ << \": RTA payload unexpectedly null\";\n        return;\n    }\n\n    auto presenceService{ m_presenceService.lock() };\n    if (presenceService)\n    {\n        auto deserializationResult = XblPresenceRecord::Deserialize(data);\n        if (Succeeded(deserializationResult))\n        {\n            bool isPlaying{ deserializationResult.Payload()->IsUserPlayingTitle(m_titleId) };\n            presenceService->HandleTitlePresenceChanged(\n                m_xuid,\n                m_titleId,\n                isPlaying ? XblPresenceTitleState::Started : XblPresenceTitleState::Ended\n            );\n        }\n    }\n}\n\nvoid TitlePresenceChangeSubscription::OnEvent(\n    const JsonValue& data\n) noexcept\n{\n    auto presenceService{ m_presenceService.lock() };\n    if (presenceService && data.IsString())\n    {\n        //data is formatted as \"state:titleId\"\n        xsapi_internal_string state = data.GetString();\n        state = state.substr(0, state.find(':'));\n        presenceService->HandleTitlePresenceChanged(m_xuid, m_titleId, EnumValue<XblPresenceTitleState>(state.c_str()));\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END"
  },
  {
    "path": "Source/Services/Privacy/permission_check_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"privacy_service_internal.h\"\n\nconstexpr auto XblPrivilegeValue = EnumValue<XblPrivilege, 205, 255>;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_BEGIN\n\nPermissionCheckResult::PermissionCheckResult(\n    const PermissionCheckResult& other\n) noexcept\n{\n    *this = other;\n}\n\nPermissionCheckResult::PermissionCheckResult(\n    PermissionCheckResult&& other\n) noexcept :\n    m_reasons{ std::move(other.m_reasons) }\n{\n    isAllowed = other.isAllowed;\n    targetXuid = other.targetXuid;\n    targetUserType = other.targetUserType;\n    permissionRequested = other.permissionRequested;\n    reasons = m_reasons.data();\n    reasonsCount = m_reasons.size();\n}\n\nPermissionCheckResult& PermissionCheckResult::operator=(\n    const PermissionCheckResult& other\n) noexcept\n{\n    m_reasons = other.m_reasons;\n    isAllowed = other.isAllowed;\n    targetXuid = other.targetXuid;\n    targetUserType = other.targetUserType;\n    permissionRequested = other.permissionRequested;\n    reasons = m_reasons.data();\n    reasonsCount = m_reasons.size();\n\n    return *this;\n}\n\nResult<PermissionCheckResult> PermissionCheckResult::Deserialize(\n    _In_ const JsonValue& json,\n    _In_ XblPermission permissionRequested\n) noexcept\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    PermissionCheckResult result{};\n    HRESULT errc = S_OK;\n\n    result.permissionRequested = permissionRequested;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"isAllowed\", result.isAllowed, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblPermissionDenyReasonDetails>(\n        [&errc](_In_ const JsonValue& json)\n        {\n            XblPermissionDenyReasonDetails result{};\n            String reasonString;\n            errc = JsonUtils::ExtractJsonString(json, \"reason\", reasonString, true);\n            result.reason = EnumValue<XblPermissionDenyReason>(reasonString.data());\n\n            if (SUCCEEDED(errc))\n            {\n                String restrictedSetting;\n                errc = JsonUtils::ExtractJsonString(json, \"restrictedSetting\", restrictedSetting, false);\n                switch (result.reason)\n                {\n                case XblPermissionDenyReason::MissingPrivilege: // intentional fallthrough\n                case XblPermissionDenyReason::PrivilegeRestrictsTarget:\n                {\n                    result.restrictedPrivilege = XblPrivilegeValue(restrictedSetting.data());\n                    break;\n                }\n                case XblPermissionDenyReason::PrivacySettingRestrictsTarget:\n                {\n                    result.restrictedPrivacySetting = EnumValue<XblPrivacySetting>(restrictedSetting.data());\n                    break;\n                }\n                default: break;\n                }\n            }\n\n            return Result<XblPermissionDenyReasonDetails>(result, errc);\n        },\n        json, \"reasons\", result.m_reasons, false\n    ));\n\n    result.reasons = result.m_reasons.data();\n    result.reasonsCount = result.m_reasons.size();\n\n    if (FAILED(errc))\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return result;\n}\n\nResult<xsapi_internal_vector<PermissionCheckResult>> PermissionCheckResult::BatchDeserialize(\n    _In_ const JsonValue& json,\n    _In_ const xsapi_internal_vector<XblPermission>& permissionsRequested\n) noexcept\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    xsapi_internal_vector<PermissionCheckResult> result;\n\n    if (json.IsObject() && json.HasMember(\"responses\"))\n    {\n        const JsonValue& responsesJsonArray = json[\"responses\"];\n        if (responsesJsonArray.IsArray())\n        {\n            for (const JsonValue& userJson : responsesJsonArray.GetArray())\n            {\n                if (userJson.IsObject() && userJson.HasMember(\"user\"))\n                {\n                    const JsonValue& userObj = userJson[\"user\"];\n                    uint64_t xuid = 0;\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(userObj, \"xuid\", xuid, false));\n                    String anonymousUserTypeString;\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(userObj, \"anonymousUser\", anonymousUserTypeString, false));\n                    auto userType = EnumValue<XblAnonymousUserType>(anonymousUserTypeString.data());\n\n                    xsapi_internal_vector<PermissionCheckResult> userResults;\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<PermissionCheckResult>(\n                        [&xuid, &userType](const JsonValue& json)\n                        {\n                            auto result { Deserialize(json, XblPermission::Unknown) };\n                            auto& payload { result.Payload() };\n                            payload.targetXuid = xuid;\n                            payload.targetUserType = userType;\n                            return Result<PermissionCheckResult>(payload, result.Hresult());\n                        },\n                        userJson,\n                        \"permissions\",\n                        userResults,\n                        true\n                        ));\n\n                    if (userResults.size() != permissionsRequested.size())\n                    {\n                        LOG_DEBUG(\"The resulting number of items did not match the number of items requested!\");\n                        return WEB_E_INVALID_JSON_STRING;\n                    }\n                    for (size_t i = 0; i < userResults.size(); ++i)\n                    {\n                        userResults[i].permissionRequested = permissionsRequested[i];\n                    }\n\n                    result.insert(result.end(), userResults.begin(), userResults.end());\n                }\n                else\n                {\n                    //required\n                    return WEB_E_INVALID_JSON_STRING;\n                }\n            }\n        }\n    }\n    return result;\n}\n\nsize_t PermissionCheckResult::SizeOf() const noexcept\n{\n    return sizeof(XblPermissionCheckResult) + m_reasons.size() * sizeof(XblPermissionDenyReasonDetails);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_END\n"
  },
  {
    "path": "Source/Services/Privacy/privacy_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"privacy_service_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::privacy;\n\nSTDAPI XblPrivacyGetAvoidListAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            avoidList = xsapi_internal_vector<uint64_t>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->PrivacyService()->GetAvoidList({\n                data->async->queue,\n                [\n                    &avoidList,\n                    async{ data->async }\n                ]\n            (Result<xsapi_internal_vector<uint64_t>> result)\n            {\n                if (Succeeded(result))\n                {\n                    avoidList = result.ExtractPayload();\n                }\n                XAsyncComplete(async, result.Hresult(), avoidList.size() * sizeof(uint64_t));\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            memcpy(data->buffer, avoidList.data(), avoidList.size() * sizeof(uint64_t));\n            return S_OK;\n        }\n        default: \n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyGetAvoidListResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* xuidCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || xuidCount == nullptr);\n\n    size_t resultSize{ 0 };\n    RETURN_HR_IF_FAILED(XAsyncGetResultSize(async, &resultSize));\n    *xuidCount = resultSize / sizeof(uint64_t);\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyGetAvoidListResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t xuidCount,\n    _Out_writes_(xuidCount) uint64_t* xuids\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(xuidCount == 0, S_OK);\n    return XAsyncGetResult(async, nullptr, xuidCount * sizeof(uint64_t), xuids, nullptr);\n}\nCATCH_RETURN()\n\nHRESULT CopyPermissionCheckResult(\n    const PermissionCheckResult& result,\n    void* buffer\n) noexcept\ntry\n{\n    auto resultPtr = static_cast<XblPermissionCheckResult*>(buffer);\n    auto reasonsPtr = reinterpret_cast<XblPermissionDenyReasonDetails*>(resultPtr + 1);\n\n    new (resultPtr) XblPermissionCheckResult{\n        result.isAllowed,\n        result.targetXuid,\n        result.targetUserType,\n        result.permissionRequested,\n        reasonsPtr,\n        result.reasonsCount\n    };\n\n    memcpy(reasonsPtr, result.reasons, sizeof(XblPermissionDenyReasonDetails) * result.reasonsCount);\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyCheckPermissionAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblPermission permission,\n    _In_ uint64_t targetXuid,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            result = PermissionCheckResult{},\n            targetXuid,\n            permission\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->PrivacyService()->CheckPermission(permission, targetXuid, { data->async->queue,\n                [\n                    &result,\n                    async{ data->async }\n                ]\n            (Result<PermissionCheckResult> r)\n            {\n                if (Succeeded(r))\n                {\n                    result = r.ExtractPayload();\n                }\n                XAsyncComplete(async, r.Hresult(), result.SizeOf());\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            return CopyPermissionCheckResult(result, data->buffer);\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyCheckPermissionResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyCheckPermissionResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblPermissionCheckResult** result,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(result);\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *result = static_cast<XblPermissionCheckResult*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyCheckPermissionForAnonymousUserAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblPermission permission,\n    _In_ XblAnonymousUserType userType,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            result = PermissionCheckResult{},\n            permission,\n            userType\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->PrivacyService()->CheckPermission(permission, userType, { data->async->queue,\n                [\n                    &result,\n                    async{ data->async }\n                ]\n            (Result<PermissionCheckResult> r)\n            {\n                if (Succeeded(r))\n                {\n                    result = r.ExtractPayload();\n                }\n                XAsyncComplete(async, r.Hresult(), result.SizeOf());\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            return CopyPermissionCheckResult(result, data->buffer);\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyCheckPermissionForAnonymousUserResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyCheckPermissionForAnonymousUserResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblPermissionCheckResult** result,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    return XblPrivacyCheckPermissionResult(async, bufferSize, buffer, result, bufferUsed);\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyBatchCheckPermissionAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_reads_(permissionsCount) XblPermission* permissionsToCheck,\n    _In_ size_t permissionsCount,\n    _In_reads_(xuidsCount) uint64_t* targetXuids,\n    _In_ size_t xuidsCount,\n    _In_reads_(userTypesCount) XblAnonymousUserType* targetUserTypes,\n    _In_ size_t userTypesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(permissionsToCheck == nullptr || permissionsCount == 0);\n    RETURN_HR_INVALIDARGUMENT_IF(targetXuids == nullptr && xuidsCount != 0);\n    RETURN_HR_INVALIDARGUMENT_IF(targetUserTypes == nullptr && userTypesCount != 0);\n    RETURN_HR_INVALIDARGUMENT_IF(xuidsCount == 0 && userTypesCount == 0);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            permissions = xsapi_internal_vector<XblPermission>(permissionsToCheck, permissionsToCheck + permissionsCount),\n            xuids = xsapi_internal_vector<uint64_t>(targetXuids, targetXuids + xuidsCount),\n            userTypes = xsapi_internal_vector<XblAnonymousUserType>(targetUserTypes, targetUserTypes + userTypesCount),\n            result = xsapi_internal_vector<PermissionCheckResult>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->PrivacyService()->BatchCheckPermission(std::move(permissions), xuids, userTypes, { data->async->queue,\n                [\n                    &result,\n                    async{ data->async }\n                ]\n            (Result<xsapi_internal_vector<PermissionCheckResult>> r)\n            {\n                if (Succeeded(r))\n                {\n                    result = r.ExtractPayload();\n                }\n\n                size_t requiredBufferSize{ 0 };\n                for (auto& i : result)\n                {\n                    requiredBufferSize += i.SizeOf();\n                }\n                XAsyncComplete(async, r.Hresult(), requiredBufferSize);\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto resultPtr = static_cast<XblPermissionCheckResult*>(data->buffer);\n            auto reasonsPtr = reinterpret_cast<XblPermissionDenyReasonDetails*>(resultPtr + result.size());\n\n            for (const auto& elt : result)\n            {\n                new (resultPtr) XblPermissionCheckResult{\n                    elt.isAllowed,\n                    elt.targetXuid,\n                    elt.targetUserType,\n                    elt.permissionRequested,\n                    reasonsPtr,\n                    elt.reasonsCount\n                };\n\n                memcpy(reasonsPtr, elt.reasons, sizeof(XblPermissionDenyReasonDetails) * elt.reasonsCount);\n\n                resultPtr++;\n                reasonsPtr += elt.reasonsCount;\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyBatchCheckPermissionResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyBatchCheckPermissionResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblPermissionCheckResult** results,\n    _Out_ size_t* resultsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(results == nullptr || resultsCount == nullptr);\n\n    // bufferUsed is needed to calculate resultsCount\n    auto bufferUsedPtr = MakeUnique<size_t>();\n    if (bufferUsed == nullptr)\n    {\n        bufferUsed = bufferUsedPtr.get();\n    }\n\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *results = static_cast<XblPermissionCheckResult*>(buffer);\n\n        // Calulate how many items are in the results array\n        size_t count{ 0 };\n        size_t verifiedSize{ 0 };\n        for(; verifiedSize < *bufferUsed; ++count)\n        {\n            verifiedSize += sizeof(XblPermissionCheckResult);\n            verifiedSize += ((*results)[count].reasonsCount * sizeof(XblPermissionDenyReasonDetails));\n        }\n        assert(verifiedSize == *bufferUsed);\n        *resultsCount = count;\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyGetMuteListAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            muteList = xsapi_internal_vector<uint64_t>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->PrivacyService()->GetMuteList({\n                data->async->queue,\n                [\n                    &muteList,\n                    async{ data->async }\n                ]\n            (Result<xsapi_internal_vector<uint64_t>> result)\n            {\n                if (Succeeded(result))\n                {\n                    muteList = result.ExtractPayload();\n                }\n                XAsyncComplete(async, result.Hresult(), muteList.size() * sizeof(uint64_t));\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            memcpy(data->buffer, muteList.data(), muteList.size() * sizeof(uint64_t));\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyGetMuteListResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* xuidCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || xuidCount == nullptr);\n\n    size_t resultSize{ 0 };\n    RETURN_HR_IF_FAILED(XAsyncGetResultSize(async, &resultSize));\n    *xuidCount = resultSize / sizeof(uint64_t);\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblPrivacyGetMuteListResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t xuidCount,\n    _Out_writes_(xuidCount) uint64_t* xuids\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(xuidCount == 0, S_OK);\n    return XAsyncGetResult(async, nullptr, xuidCount * sizeof(uint64_t), xuids, nullptr);\n}\nCATCH_RETURN()"
  },
  {
    "path": "Source/Services/Privacy/privacy_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"privacy_service_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::legacy;\nusing namespace xbox::services::privacy;\n\nconstexpr auto XblPermissionName = EnumName<XblPermission, 1000, 1025>;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_BEGIN\n\nPrivacyService::PrivacyService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n) noexcept :\n    m_user{ std::move(user) },\n    m_contextSettings{ contextSettings }\n{\n}\n\nHRESULT PrivacyService::GetAvoidList(\n    _In_ AsyncContext<Result<xsapi_internal_vector<uint64_t>>> async\n) const noexcept\n{\n    return GetUserList(PrivacyListType::Avoid, async);\n}\n\nHRESULT PrivacyService::GetMuteList(\n    _In_ AsyncContext<Result<xsapi_internal_vector<uint64_t>>> async\n) const noexcept\n{\n    return GetUserList(PrivacyListType::Mute, async);\n}\n\nHRESULT PrivacyService::GetUserList(\n    _In_ PrivacyListType listType,\n    _In_ AsyncContext<Result<xsapi_internal_vector<uint64_t>>> async\n) const noexcept\n{\n    xsapi_internal_stringstream path;\n    path << \"/users/xuid(\" << m_user.Xuid() << \")/people/\" << (listType == PrivacyListType::Mute ? \"mute\" : \"avoid\");\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_contextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"privacy\", path.str()),\n        xbox_live_api::get_avoid_or_mute_list\n    ));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            if (SUCCEEDED(hr))\n            {\n                return async.Complete(DeserializeUserList(httpResult.Payload()->GetResponseBodyJson()));\n            }\n            return async.Complete(hr);\n        }\n        });\n}\n\nHRESULT PrivacyService::CheckPermission(\n    _In_ XblPermission permission,\n    _In_ uint64_t targetXuid,\n    _In_ AsyncContext<Result<PermissionCheckResult>> async\n) const noexcept\n{\n    // users/xuid({xuid})/permission/validate?setting={setting}&target=xuid({targetXuid})\n    Stringstream targetQuery;\n    targetQuery << \"xuid(\" << targetXuid << \")\";\n\n    return CheckPermission(permission, targetQuery.str(), { async.Queue(),\n        [\n            targetXuid,\n            async\n        ]\n    (Result<PermissionCheckResult> result)\n        {\n            result.Payload().targetXuid = targetXuid;\n            async.Complete(result);\n        }\n        });\n}\n\nHRESULT PrivacyService::CheckPermission(\n    _In_ XblPermission permission,\n    _In_ XblAnonymousUserType userType,\n    _In_ AsyncContext<Result<PermissionCheckResult>> async\n) const noexcept\n{\n    return CheckPermission(permission, EnumName(userType), { async.Queue(),\n        [\n            userType,\n            async\n        ]\n    (Result<PermissionCheckResult> result)\n        {\n            result.Payload().targetUserType = userType;\n            async.Complete(result);\n        }\n        });\n}\n\nHRESULT PrivacyService::CheckPermission(\n    _In_ XblPermission permission,\n    _In_ const String& targetQuery,\n    _In_ AsyncContext<Result<PermissionCheckResult>> async\n) const noexcept\n{\n    // users/xuid({xuid})/permission/validate?setting={setting}&target={target})\n    xbox::services::uri_builder subPathBuilder;\n    xsapi_internal_stringstream path;\n    path << \"/users/xuid(\" << m_user.Xuid() << \")/permission/validate\";\n\n    subPathBuilder.append_path(path.str());\n    subPathBuilder.append_query(\"setting\", XblPermissionName(permission).data());\n    subPathBuilder.append_query(\"target\", targetQuery);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_contextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"privacy\", subPathBuilder.to_string()),\n        xbox_live_api::check_permission_with_target_user\n    ));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async,\n            permission\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            if (SUCCEEDED(hr))\n            {\n                return async.Complete(PermissionCheckResult::Deserialize(httpResult.Payload()->GetResponseBodyJson(), permission));\n            }\n            return async.Complete(hr);\n        }\n        });\n}\n\nHRESULT PrivacyService::BatchCheckPermission(\n    _In_ xsapi_internal_vector<XblPermission> permissions,\n    _In_ const xsapi_internal_vector<uint64_t>& targetXuids,\n    _In_ const xsapi_internal_vector<XblAnonymousUserType>& userTypes,\n    _In_ AsyncContext<Result<xsapi_internal_vector<PermissionCheckResult>>> async\n) const noexcept\n{\n    // users/xuid({xuid})/permission/validate\n    xsapi_internal_stringstream path;\n    path << \"/users/xuid(\" << m_user.Xuid() << \")/permission/validate\";\n\n    // Set request body to something like:\n    //{\n    //    \"users\":\n    //    [\n    //        {\"xuid\":\"12345\"},\n    //        {\"anonymousUser\":\"crossNetworkUser\"}\n    //    ],\n    //    \"permissions\":\n    //    [\n    //        \"ViewTargetGameHistory\",\n    //        \"ViewTargetProfile\"\n    //    ]\n    //}\n\n    JsonDocument requestBody(rapidjson::kObjectType);\n    JsonDocument::AllocatorType& allocator = requestBody.GetAllocator();\n\n    JsonValue usersJson(rapidjson::kArrayType);\n    for (auto xuid : targetXuids)\n    {\n        JsonValue userJson(rapidjson::kObjectType);\n        userJson.AddMember(\"xuid\", JsonValue(utils::uint64_to_internal_string(xuid).c_str(), allocator).Move(), allocator);\n        usersJson.PushBack(userJson, allocator);\n    }\n    for (auto userType : userTypes)\n    {\n        JsonValue userJson(rapidjson::kObjectType);\n        userJson.AddMember(\"anonymousUser\", JsonValue(EnumName(userType).data(), allocator).Move(), allocator);\n        usersJson.PushBack(userJson, allocator);\n    }\n\n    requestBody.AddMember(\"users\", usersJson, allocator);\n    JsonValue permissionsJson(rapidjson::kArrayType);\n    JsonUtils::SerializeVector<XblPermission>(\n        [](XblPermission permission, JsonValue& outObj, JsonDocument::AllocatorType& allocator)\n        {\n            outObj.SetString(XblPermissionName(permission).data(), allocator);\n        },\n        permissions,\n        permissionsJson,\n        allocator\n    );\n\n    requestBody.AddMember(\"permissions\", permissionsJson, allocator);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_contextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"privacy\", path.str()),\n        xbox_live_api::check_multiple_permissions_with_multiple_target_users\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(requestBody));\n\n    return httpCall->Perform({\n        async.Queue().DeriveWorkerQueue(),\n        [\n            async,\n            permissionsRequested{ std::move(permissions) }\n        ]\n    (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            if (SUCCEEDED(hr))\n            {\n                return async.Complete(PermissionCheckResult::BatchDeserialize(httpResult.Payload()->GetResponseBodyJson(), permissionsRequested));\n            }\n            return async.Complete(hr);\n        }\n        });\n}\n\nResult<xsapi_internal_vector<uint64_t>> PrivacyService::DeserializeUserList(\n    _In_ const JsonValue& json\n) noexcept\n{\n    HRESULT errc = S_OK;\n    xsapi_internal_vector<uint64_t> xuids;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<uint64_t>(\n        [&errc](_In_ const JsonValue& json)\n        {\n            if (json.IsNull())\n            {\n                return Result<uint64_t>(WEB_E_INVALID_JSON_STRING);\n            }\n\n            uint64_t xuid = 0;\n            HRESULT tempErr = JsonUtils::ExtractJsonXuid(json, \"xuid\", xuid, true);\n            if (FAILED(tempErr))\n            {\n                errc = tempErr;\n            }\n\n            return Result<uint64_t>(xuid, errc);\n        },\n        json, (\"users\"), xuids, true\n        ));\n\n    if (FAILED(errc))\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n    \n    return xuids;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_END\n"
  },
  {
    "path": "Source/Services/Privacy/privacy_service_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/privacy_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_BEGIN\n\nclass PermissionCheckResult : public XblPermissionCheckResult\n{\npublic:\n    PermissionCheckResult() noexcept = default;\n    PermissionCheckResult(const PermissionCheckResult& other) noexcept;\n    PermissionCheckResult(PermissionCheckResult&& other) noexcept;\n    PermissionCheckResult& operator=(const PermissionCheckResult& other) noexcept;\n    ~PermissionCheckResult() noexcept = default;\n\n    static Result<PermissionCheckResult> Deserialize(\n        _In_ const JsonValue& json,\n        _In_ XblPermission requestedPermission\n    ) noexcept;\n\n    static Result<xsapi_internal_vector<PermissionCheckResult>> BatchDeserialize(\n        _In_ const JsonValue& json,\n        _In_ const xsapi_internal_vector<XblPermission>& permissionsRequested\n    ) noexcept;\n\n    size_t SizeOf() const noexcept;\n\nprivate:\n    xsapi_internal_vector<XblPermissionDenyReasonDetails> m_reasons;\n};\n\nclass PrivacyService : public std::enable_shared_from_this<PrivacyService>\n{\npublic:\n    PrivacyService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n    ) noexcept;\n\n    HRESULT GetAvoidList(\n        _In_ AsyncContext<Result<xsapi_internal_vector<uint64_t>>> async\n    ) const noexcept;\n\n    HRESULT GetMuteList(\n        _In_ AsyncContext<Result<xsapi_internal_vector<uint64_t>>> async\n    ) const noexcept;\n\n    HRESULT CheckPermission(\n        _In_ XblPermission permission,\n        _In_ uint64_t targetXuid,\n        _In_ AsyncContext<Result<PermissionCheckResult>> async\n    ) const noexcept;\n\n    HRESULT CheckPermission(\n        _In_ XblPermission permissionToCheck,\n        _In_ XblAnonymousUserType userType,\n        _In_ AsyncContext<Result<PermissionCheckResult>> async\n    ) const noexcept;\n\n    HRESULT BatchCheckPermission(\n        _In_ xsapi_internal_vector<XblPermission> permissionsToCheck,\n        _In_ const xsapi_internal_vector<uint64_t>& targetXuids,\n        _In_ const xsapi_internal_vector<XblAnonymousUserType>& userTypes,\n        _In_ AsyncContext<Result<xsapi_internal_vector<PermissionCheckResult>>> async\n    ) const noexcept;\n\nprivate:\n    enum class PrivacyListType\n    {\n        Avoid,\n        Mute\n    };\n\n    HRESULT GetUserList(\n        _In_ PrivacyListType listType,\n        _In_ AsyncContext<Result<xsapi_internal_vector<uint64_t>>> async\n    ) const noexcept;\n\n    static Result<xsapi_internal_vector<uint64_t>> DeserializeUserList(\n        _In_ const JsonValue& json\n    ) noexcept;\n\n    HRESULT CheckPermission(\n        _In_ XblPermission permissionToCheck,\n        _In_ const String& targetQuery,\n        _In_ AsyncContext<Result<PermissionCheckResult>> async\n    ) const noexcept;\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_contextSettings;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_END"
  },
  {
    "path": "Source/Services/RealTimeActivityManager/real_time_activity_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/real_time_activity_c.h\"\n#include \"real_time_activity_manager.h\"\n#include \"xbox_live_context_internal.h\"\n\nstd::atomic<uint32_t> XblRealTimeActivitySubscription::s_nextId{ 1 };\n\nSTDAPI XblRealTimeActivitySubscriptionGetState(\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    _Out_ XblRealTimeActivitySubscriptionState* state\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(subscriptionHandle == nullptr || state == nullptr);\n    *state = subscriptionHandle->state;\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblRealTimeActivitySubscriptionGetId(\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle,\n    _Out_ uint32_t* id\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(subscriptionHandle == nullptr || id == nullptr);\n    *id = subscriptionHandle->id;\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblRealTimeActivityActivate(\n    _In_ XblContextHandle xboxLiveContext\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    if (auto state{ GlobalState::Get() })\n    {\n        state->RTAManager()->Activate(xboxLiveContext->User(), true);\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblRealTimeActivityDeactivate(\n    _In_ XblContextHandle xboxLiveContext\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    if (auto state{ GlobalState::Get() })\n    {\n        state->RTAManager()->Deactivate(xboxLiveContext->User());\n    }\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblRealTimeActivityAddConnectionStateChangeHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivityConnectionStateChangeHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || handler == nullptr);\n\n    if (auto state{ GlobalState::Get() })\n    {\n        return state->RTAManager()->AddStateChangedHandler(xboxLiveContext->User(),\n            [\n                handler,\n                context\n            ]\n        (XblRealTimeActivityConnectionState state)\n        {\n            try\n            {\n                handler(context, state); \n            }\n            catch (...)\n            {\n                LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n            }\n        });\n    }\n    else\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n}\nCATCH_RETURN()\n\nSTDAPI XblRealTimeActivityRemoveConnectionStateChangeHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n\n    if (auto state{ GlobalState::Get() })\n    {\n        state->RTAManager()->RemoveStateChangedHandler(xboxLiveContext->User(), token);\n        return S_OK;\n    }\n    else\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblRealTimeActivityAddSubscriptionErrorHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivitySubscriptionErrorHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__ << \": DEPRECATED, No action taken by XSAPI.\";\n    UNREFERENCED_PARAMETER(xboxLiveContext);\n    UNREFERENCED_PARAMETER(handler);\n    UNREFERENCED_PARAMETER(context);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblRealTimeActivityRemoveSubscriptionErrorHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__ << \": DEPRECATED, No action taken by XSAPI.\";\n    UNREFERENCED_PARAMETER(xboxLiveContext);\n    UNREFERENCED_PARAMETER(token);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblRealTimeActivityAddResyncHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivityResyncHandler* handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || handler == nullptr);\n\n    if (auto state{ GlobalState::Get() })\n    {\n        return state->RTAManager()->AddResyncHandler(xboxLiveContext->User(),\n            [\n                handler,\n                context\n            ]\n        {\n            try\n            {\n                handler(context);\n            }\n            catch (...)\n            {\n                LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n            }\n        });\n    }\n    else\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n}\nCATCH_RETURN()\n\nSTDAPI XblRealTimeActivityRemoveResyncHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext token\n) XBL_NOEXCEPT\ntry\n{\n    LOGS_DEBUG << __FUNCTION__;\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n\n    if (auto state{ GlobalState::Get() })\n    {\n        state->RTAManager()->RemoveResyncHandler(xboxLiveContext->User(), token);\n        return S_OK;\n    }\n    else\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"real_time_activity_subscription.h\"\n#include \"real_time_activity_connection.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n\nconstexpr char s_rtaUri[]{ \"wss://rta.xboxlive.com/connect\" };\nconstexpr char s_rtaSubprotocol[]{ \"rta.xboxlive.com.V2\" };\n\nstruct ServiceSubscription\n{\n    ServiceSubscription(String _uri, uint32_t _clientId) noexcept : uri{ std::move(_uri) }, clientId { _clientId } {}\n\n    // Resource uri for the subscription\n    String const uri;\n\n    // Client ID is assigned by XSAPI and used to identify subscriptions.\n    // Used as the unique SEQUENCE_N during RTA Sub/Unsub handshakes.\n    uint32_t const clientId;\n\n    // Assigned by service when we successfully subscribe. Used to identify subscription in RTA event messages.\n    uint32_t serviceId{ 0 };\n\n    // Current status with respect to RTA service\n    enum class Status : uint32_t\n    {\n        // RTA service has no knowledge of this subscription\n        Inactive,\n        // Registered with RTA service\n        Active,\n        // Client has indicated that they want to subscribe while unsubscribing. Resubscribe will\n        // happen as soon as unsubscribe handshake completes.\n        PendingSubscribe,\n        // We've sent subscribe message to RTA service but has not yet received the handshake response\n        Subscribing,\n        // Client has indicated they want to unsubscribe while subscribing. Unsubscribe requires\n        // we have a serviceID. Unsubscribe will happen as soon as the subscribe handshake is finished.\n        PendingUnsubscribe,\n        // We've sent unsubscribe message to RTA service but has not yet received the handshake response\n        Unsubscribing\n    } status{ Status::Inactive };\n\n    uint32_t subscribeAttempt{ 0 };\n\n    Set<std::shared_ptr<Subscription>> clientSubscriptions;\n    List<AsyncContext<Result<void>>> subscribeAsyncContexts;\n    List<AsyncContext<Result<void>>> unsubscribeAsyncContexts;\n\n    // OnSubscribe data payload\n    JsonDocument onSubscribeData{ rapidjson::kNullType };\n};\n\n// RTA message types and error codes define by service here http://xboxwiki/wiki/Real_Time_Activity\nenum class MessageType : uint32_t\n{\n    Subscribe = 1,\n    Unsubscribe = 2,\n    Event = 3,\n    Resync = 4\n};\n\nenum class ErrorCode : uint32_t\n{\n    Success = 0,\n    UnknownResource = 1,\n    SubscriptionLimitReached = 2,\n    NoResourceData = 3,\n    Throttled = 1001,\n    ServiceUnavailable = 1002\n};\n\nHRESULT ConvertRTAErrorCode(ErrorCode rtaErrorCode) noexcept\n{\n    switch (rtaErrorCode)\n    {\n    case ErrorCode::Success: return S_OK;\n    case ErrorCode::SubscriptionLimitReached: return E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED;\n    case ErrorCode::NoResourceData: return E_XBL_RTA_ACCESS_DENIED;\n    default: return E_XBL_RTA_GENERIC_ERROR;\n    }\n}\n\nConnection::Connection(\n    User&& user,\n    const TaskQueue& queue,\n    ConnectionStateChangedHandler stateChangedHandler,\n    real_time_activity::ResyncHandler resyncHandler\n) noexcept\n    : m_user{ std::move(user) },\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_stateChangedHandler{ std::move(stateChangedHandler) },\n    m_resyncHandler{ std::move(resyncHandler) }\n{\n    LOGS_DEBUG << __FUNCTION__ << \"[\" << this << \"]\";\n}\n\nConnection::~Connection() noexcept\n{\n    LOGS_DEBUG << __FUNCTION__ << \"[\" << this << \"]\";\n\n    m_queue.Terminate(false);\n}\n\nResult<std::shared_ptr<Connection>> Connection::Make(\n    User&& user,\n    const TaskQueue& queue,\n    ConnectionStateChangedHandler stateChangedHandler,\n    real_time_activity::ResyncHandler resyncHandler\n) noexcept\n{\n    auto rtaConnection = std::shared_ptr<Connection>(\n        new (Alloc(sizeof(Connection))) Connection\n        {\n            std::move(user),\n            queue,\n            std::move(stateChangedHandler),\n            std::move(resyncHandler)\n        },\n        Deleter<Connection>(),\n        Allocator<Connection>()\n    );\n\n    rtaConnection->m_stateChangedHandler(rtaConnection->m_state);\n    rtaConnection->ScheduleConnect();\n\n    return rtaConnection;\n}\n\nvoid Connection::Cleanup()\n{\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    if (m_websocket)\n    {\n        // Clear our disconnect handler to disable auto-reconnect logic\n        m_websocket->SetDisconnectHandler(nullptr);\n        m_websocket->Disconnect();\n    }\n\n    List<AsyncContext<Result<void>>> pendingAsyncContexts;\n    for (auto& subPair : m_subsByClientId)\n    {\n        auto& sub{ subPair.second };\n        pendingAsyncContexts.insert(pendingAsyncContexts.end(), sub->subscribeAsyncContexts.begin(), sub->subscribeAsyncContexts.end());\n        sub->subscribeAsyncContexts.clear();\n        pendingAsyncContexts.insert(pendingAsyncContexts.end(), sub->unsubscribeAsyncContexts.begin(), sub->unsubscribeAsyncContexts.end());      \n        sub->unsubscribeAsyncContexts.clear();\n    }\n\n    lock.unlock();\n\n    m_queue.Terminate(\n        false,\n        [pendingAsyncContexts = std::move(pendingAsyncContexts)]() {\n            for (auto& async : pendingAsyncContexts)\n            {\n                async.Complete(E_ABORT);\n            }\n        }\n    );\n}\n\nHRESULT Connection::AddSubscription(\n    std::shared_ptr<Subscription> sub,\n    AsyncContext<Result<void>> async\n) noexcept\n{\n    assert(sub);\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    std::shared_ptr<ServiceSubscription> serviceSub{ nullptr };\n    auto serviceSubIter = m_subsByUri.find(sub->ResourceUri());\n    if (serviceSubIter != m_subsByUri.end())\n    {\n        serviceSub = serviceSubIter->second;\n    }\n    else\n    {\n        serviceSub = MakeShared<ServiceSubscription>(sub->ResourceUri(), m_nextSubId++);\n        assert(m_subsByClientId.find(serviceSub->clientId) == m_subsByClientId.end());\n        m_subsByClientId[serviceSub->clientId] = serviceSub;\n        m_subsByUri[serviceSub->uri] = serviceSub;\n    }\n\n    serviceSub->clientSubscriptions.emplace(sub);\n\n    LOGS_DEBUG << __FUNCTION__ << \": [\" << serviceSub->clientId << \"] Uri=\" << serviceSub->uri << \", ServiceStatus=\" << EnumName(serviceSub->status);\n\n    switch (serviceSub->status)\n    {\n    case ServiceSubscription::Status::Inactive:\n    {\n        serviceSub->subscribeAsyncContexts.push_back(std::move(async));\n\n        // If our connection is active, immediately register with RTA service\n        if (m_state == XblRealTimeActivityConnectionState::Connected)\n        {\n            return SendSubscribeMessage(serviceSub, std::move(lock));\n        }\n        return S_OK;\n    }\n    case ServiceSubscription::Status::PendingUnsubscribe:\n    {\n        // Client previously removed subscription while we were subscribing. Reset the state to subscribing and complete unsubscribe\n        // operations with E_ABORT\n\n        serviceSub->status = ServiceSubscription::Status::Subscribing;\n        serviceSub->subscribeAsyncContexts.push_back(std::move(async));\n\n        List<AsyncContext<Result<void>>> unsubscribeAsyncContexts{ std::move(serviceSub->unsubscribeAsyncContexts) };\n\n        lock.unlock();\n\n        for (auto& asyncContext : unsubscribeAsyncContexts)\n        {\n            asyncContext.Complete(E_ABORT);\n        }\n\n        return S_OK;\n    }\n    case ServiceSubscription::Status::Unsubscribing:\n    {\n        // Wait for unsubscribe to finish before resubscribing\n        serviceSub->status = ServiceSubscription::Status::PendingSubscribe;\n        serviceSub->subscribeAsyncContexts.push_back(std::move(async));\n        return S_OK;\n    }\n    case ServiceSubscription::Status::Active:\n    {\n        // Subscription is already active, trivially complete\n        lock.unlock();\n        // Pass along original OnSubscribe payload for this subscription\n        sub->OnSubscribe(serviceSub->onSubscribeData);\n        async.Complete(S_OK);\n        return S_OK;\n    }\n    case ServiceSubscription::Status::PendingSubscribe:\n    case ServiceSubscription::Status::Subscribing:\n    {\n        serviceSub->subscribeAsyncContexts.push_back(std::move(async));\n        return S_OK;\n    }\n    default:\n    {\n        assert(false);\n        return E_UNEXPECTED;\n    }\n    }\n}\n\nHRESULT Connection::RemoveSubscription(\n    std::shared_ptr<Subscription> sub,\n    AsyncContext<Result<void>> async\n) noexcept\n{\n    assert(sub);\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    std::shared_ptr<ServiceSubscription> serviceSub{ nullptr };\n    auto serviceSubIter = m_subsByUri.find(sub->ResourceUri());\n    if (serviceSubIter != m_subsByUri.end())\n    {\n        serviceSub = serviceSubIter->second;\n    }\n    else\n    {\n        return S_OK;\n    }\n\n    serviceSub->clientSubscriptions.erase(sub);\n\n    LOGS_DEBUG << __FUNCTION__ << \": [\" << serviceSub->clientId << \"] Uri=\" << serviceSub->uri << \", ServiceStatus=\" << EnumName(serviceSub->status);\n\n    if (!serviceSub->clientSubscriptions.empty())\n    {\n        // Service subscription still needed by other clients. Complete asyncContext but don't unsubscribe from service\n        lock.unlock();\n\n        async.Complete(S_OK);\n        return S_OK;\n    }\n\n    switch (serviceSub->status)\n    {\n    case ServiceSubscription::Status::Inactive:\n    {\n        // RTA service has no knowledge of inactive subs. Just remove from our local state and complete the AsyncContext.\n        assert(serviceSub->serviceId == 0);\n        m_subsByClientId.erase(serviceSub->clientId);\n        m_subsByUri.erase(serviceSub->uri);\n\n        lock.unlock();\n\n        async.Complete(S_OK);\n        return S_OK;\n    }\n    case ServiceSubscription::Status::Active:\n    {\n        // Unregister subscription from RTA service\n        serviceSub->unsubscribeAsyncContexts.push_back(std::move(async));\n        return SendUnsubscribeMessage(serviceSub, std::move(lock));\n    }\n    case ServiceSubscription::Status::PendingSubscribe:\n    {\n        // Client previously added the subscription while we were unsubscribing. Reset the state to unsubscribe and complete\n        // subscribe operations with E_ABORT\n\n        serviceSub->status = ServiceSubscription::Status::Unsubscribing;\n        serviceSub->unsubscribeAsyncContexts.push_back(std::move(async));\n        List<AsyncContext<Result<void>>> subscribeAsyncContexts{ std::move(serviceSub->subscribeAsyncContexts) };\n        \n        lock.unlock();\n\n        for (auto& asyncContext : subscribeAsyncContexts)\n        {\n            asyncContext.Complete(E_ABORT);\n        }\n\n        return S_OK;\n    }\n    case ServiceSubscription::Status::Subscribing:\n    {\n        // We are in the process of subscribing. RTA protocol doesn't allow us to unsubscribe\n        // until subscription is complete, so just mark the subscription as pending unsubscribe.\n        // After the subscription completes, we will unsubscribe and complete the AsyncContext.\n        serviceSub->status = ServiceSubscription::Status::PendingUnsubscribe;\n        serviceSub->unsubscribeAsyncContexts.push_back(std::move(async));\n\n        return S_OK;\n    }\n    case ServiceSubscription::Status::PendingUnsubscribe:\n    case ServiceSubscription::Status::Unsubscribing:\n    {\n        serviceSub->unsubscribeAsyncContexts.push_back(std::move(async));\n\n        return S_OK;\n    }\n    default:\n    {\n        assert(false);\n        return E_UNEXPECTED;\n    }\n    }\n}\n\nsize_t Connection::SubscriptionCount() const noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_lock };\n    return m_subsByClientId.size();\n}\n\nJsonDocument Connection::AssembleSubscribeMessage(std::shared_ptr<ServiceSubscription> sub) const noexcept\n{\n    // Payload format [<API_ID>, <SEQUENCE_N>, <RESOURCE_URI>]\n\n    sub->status = ServiceSubscription::Status::Subscribing;\n\n    JsonDocument request{ rapidjson::kArrayType };\n    auto& a{ request.GetAllocator() };\n\n    request.PushBack(static_cast<uint32_t>(MessageType::Subscribe), a);\n    request.PushBack(sub->clientId, a);\n    request.PushBack(JsonValue{ sub->uri.data(), a }, a);\n\n    return request;\n}\n\nHRESULT Connection::SendSubscribeMessage(\n    std::shared_ptr<ServiceSubscription> sub,\n    std::unique_lock<std::mutex>&& lock\n) const noexcept\n{\n    JsonDocument request = AssembleSubscribeMessage(sub);\n\n    lock.unlock();\n\n    return SendAssembledMessage(request);\n}\n\nHRESULT Connection::SendAssembledMessage(_In_ const JsonValue& request) const noexcept\n{\n    String requestString{ JsonUtils::SerializeJson(request) };\n    LOGS_DEBUG << __FUNCTION__ << \"[\" << this << \"]: \" << requestString;\n\n    return m_websocket->Send(requestString.data());\n}\n\nHRESULT Connection::SendUnsubscribeMessage(\n    std::shared_ptr<ServiceSubscription> sub,\n    std::unique_lock<std::mutex>&& lock\n) const noexcept\n{\n    // Payload format [<API_ID>, <SEQUENCE_N>, <SUB_ID>]\n\n    sub->status = ServiceSubscription::Status::Unsubscribing;\n\n    JsonDocument request{ rapidjson::kArrayType };\n    auto& a{ request.GetAllocator() };\n\n    request.PushBack(static_cast<uint32_t>(MessageType::Unsubscribe), a);\n    request.PushBack(sub->clientId, a);\n    request.PushBack(sub->serviceId, a);\n\n    lock.unlock();\n\n    String requestString{ JsonUtils::SerializeJson(request) };\n    LOGS_DEBUG << __FUNCTION__ << \"[\" << this << \"]: \" << requestString;\n\n    return m_websocket->Send(requestString.data());\n}\n\nvoid Connection::SubscribeResponseHandler(_In_ const JsonValue& message) noexcept\n{\n    // Payload format [<API_ID>, <SEQUENCE_N>, <CODE_N>, <SUB_ID>, <DATA>]\n\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    auto clientId = message[1].GetUint();\n    auto errorCode = static_cast<ErrorCode>(message[2].GetUint());\n\n    auto subIter{ m_subsByClientId.find(clientId) };\n    if (subIter == m_subsByClientId.end())\n    {\n        // Ignore unexpected message\n        LOGS_DEBUG << \"__FUNCTION__\" << \": [\" << clientId << \"] Ignoring unexpected message\";\n        return;\n    }\n    auto serviceSub{ subIter->second };\n\n    switch (errorCode)\n    {\n    case ErrorCode::Success:\n    {\n        serviceSub->serviceId = message[3].GetInt();\n        serviceSub->onSubscribeData.CopyFrom(message[4], serviceSub->onSubscribeData.GetAllocator());\n\n        m_subsByServiceId[serviceSub->serviceId] = serviceSub;\n        List<AsyncContext<Result<void>>> subscribeAsyncContexts{ std::move(serviceSub->subscribeAsyncContexts) };\n        List<std::shared_ptr<Subscription>> clientSubs{ serviceSub->clientSubscriptions.begin(), serviceSub->clientSubscriptions.end() };\n\n        switch (serviceSub->status)\n        {\n        case ServiceSubscription::Status::Subscribing:\n        {\n            serviceSub->status = ServiceSubscription::Status::Active;\n            break;\n        }\n        case ServiceSubscription::Status::PendingUnsubscribe:\n        {\n            // Client has removed the subscription while subscribe handshake was happening,\n            // so immediately begin unsubscribing.\n            SendUnsubscribeMessage(serviceSub, std::move(lock));\n            break;\n        }\n        default:\n        {\n            // Any other Status indicates a XSAPI bug\n            assert(false);\n            break;\n        }\n        }\n\n        if (lock)\n        {\n            lock.unlock();\n        }\n\n        for (auto& asyncContext : subscribeAsyncContexts)\n        {\n            asyncContext.Complete(ConvertRTAErrorCode(errorCode));\n        }\n        for (auto& clientSub : clientSubs)\n        {\n            clientSub->OnSubscribe(serviceSub->onSubscribeData);\n        }\n\n        return;\n    }\n    case ErrorCode::UnknownResource:\n    case ErrorCode::SubscriptionLimitReached:\n    case ErrorCode::NoResourceData:\n    {\n        // With the possible exception of SubscriptionLimitReached, these are all indicative of a bug in XSAPI\n        LOGS_ERROR << __FUNCTION__ << \": Failed with [\" << static_cast<uint32_t>(errorCode) << \"]\";\n        return;\n    }\n    case ErrorCode::Throttled:\n    case ErrorCode::ServiceUnavailable:\n    {\n        auto serviceStatus{ serviceSub->status };\n        serviceSub->status = ServiceSubscription::Status::Inactive;\n\n        switch (serviceStatus)\n        {\n        case ServiceSubscription::Status::Subscribing:\n        {\n            uint64_t backoff = __min(std::pow(serviceSub->subscribeAttempt++, 2), 60) * 1000;\n            m_queue.RunWork([weakSub = std::weak_ptr<ServiceSubscription>{ serviceSub }, weakThis = std::weak_ptr<Connection>{ shared_from_this() }]\n                {\n                    auto sharedThis{ weakThis.lock() };\n                    if (sharedThis)\n                    {\n                        std::unique_lock<std::mutex> lock{ sharedThis->m_lock };\n\n                        auto serviceSub{ weakSub.lock() };\n                        if (serviceSub && serviceSub->status == ServiceSubscription::Status::Inactive)\n                        {\n                            sharedThis->SendSubscribeMessage(serviceSub, std::move(lock));\n                        }\n                    }\n                },\n                backoff\n            );\n\n            return;\n        }\n        case ServiceSubscription::Status::PendingUnsubscribe:\n        {\n            m_subsByClientId.erase(serviceSub->clientId);\n            m_subsByUri.erase(serviceSub->uri);\n            \n            // Complete subscribe operations with error, but don't retry since the client has since removed the subscription\n            List<AsyncContext<Result<void>>> subscribeAsyncContexts{ std::move(serviceSub->subscribeAsyncContexts) };               \n\n            // Unsubscribe operations are also trivially done at this point\n            List<AsyncContext<Result<void>>> unsubscribeAsyncContexts{ std::move(serviceSub->unsubscribeAsyncContexts) };\n\n            lock.unlock();\n\n            for (auto& asyncContext : subscribeAsyncContexts)\n            {\n                asyncContext.Complete(ConvertRTAErrorCode(errorCode));\n            }\n\n            for (auto& asyncContext : unsubscribeAsyncContexts)\n            {\n                asyncContext.Complete(S_OK);\n            }\n\n            return;\n        }\n        default:\n        {\n            assert(false);\n            return;\n        }\n        }\n    }\n    default:\n    {\n        LOGS_ERROR << __FUNCTION__ << \": Failed with unrecognized error code [\" << static_cast<uint32_t>(errorCode) << \"]\";\n        return;\n    }\n    }\n}\n\nvoid Connection::UnsubscribeResponseHandler(_In_ const JsonValue& message) noexcept\n{\n    // Payload format [<API_ID>, <SEQUENCE_N>, <CODE_N>]\n\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    auto clientId = message[1].GetUint();\n    auto errorCode = static_cast<ErrorCode>(message[2].GetUint());\n\n    if (errorCode != ErrorCode::Success)\n    {\n        // Not sure why unsubscribing would ever fail\n        LOGS_ERROR << __FUNCTION__ << \": Failed with error code [\" << static_cast<uint32_t>(errorCode) << \"]\";\n    }\n\n    auto subIter{ m_subsByClientId.find(clientId) };\n    if (subIter == m_subsByClientId.end())\n    {\n        // Ignore unexpected message\n        LOGS_DEBUG << \"__FUNCTION__\" << \": [\" << clientId << \"] Ignoring unexpected message\";\n        return;\n    }\n    auto serviceSub{ subIter->second };\n    m_subsByServiceId.erase(serviceSub->serviceId);\n    serviceSub->serviceId = 0;\n\n    LOGS_DEBUG << __FUNCTION__ << \": [\" << serviceSub->clientId <<\"] ServiceStatus=\" << EnumName(serviceSub->status);\n\n    List<AsyncContext<Result<void>>> unsubscribeAsyncContexts{ std::move(serviceSub->unsubscribeAsyncContexts) };\n\n    switch (serviceSub->status)\n    {\n    case ServiceSubscription::Status::Unsubscribing:\n    {\n        // We can now remove the subscription from our state entirely\n        m_subsByClientId.erase(serviceSub->clientId);\n        m_subsByUri.erase(serviceSub->uri);\n        serviceSub->status = ServiceSubscription::Status::Inactive;\n        break;\n    }\n    case ServiceSubscription::Status::PendingSubscribe:\n    {\n        // Client has re-added the subscription while unsubscibe handshake was happening,\n        // so immediately begin subscribing.\n        SendSubscribeMessage(serviceSub, std::move(lock));\n        break;\n    }\n    default:\n    {\n        assert(false);\n        break;\n    }\n    }\n\n    if (lock)\n    {\n        lock.unlock();\n    }\n\n    for (auto& asyncContext : unsubscribeAsyncContexts)\n    {\n        asyncContext.Complete(ConvertRTAErrorCode(errorCode));\n    }\n}\n\nvoid Connection::EventHandler(_In_ const JsonValue& message) const noexcept\n{\n    // Payload format [<API_ID>, <SUB_ID>, <DATA>]\n\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    auto serviceId = message[1].GetInt();\n    const auto& data = message[2];\n\n    auto subIter{ m_subsByServiceId.find(serviceId) };\n    assert(subIter != m_subsByServiceId.end());\n    auto serviceSub = subIter->second;\n\n    lock.unlock();\n\n    for (auto& clientSub : serviceSub->clientSubscriptions)\n    {\n        clientSub->OnEvent(data);\n    }\n}\n\nvoid Connection::ConnectCompleteHandler(WebsocketResult result) noexcept\n{\n    LOGS_DEBUG << __FUNCTION__ << \": WebsocketResult [\" << result.hr << \",\" << result.platformErrorCode << \"]\";\n\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    if (SUCCEEDED(result.hr))\n    {\n        // Ignore resync messages for 5 minutes after connecting to\n        // avoid overwhelming the service with update requests\n        m_ignoreResyncTimer = xbox::services::datetime::utc_now() + xbox::services::datetime::from_minutes(5);\n\n        m_state = XblRealTimeActivityConnectionState::Connected;\n        m_connectTime = std::chrono::system_clock::now();\n        m_connectAttempt = 0;\n        m_connectNum++;\n\n        assert(m_subsByServiceId.empty());\n\n        List<JsonDocument> subMessages{};\n        for (auto& pair : m_subsByClientId)\n        {\n            assert(pair.second->status == ServiceSubscription::Status::Inactive);\n            subMessages.push_back(AssembleSubscribeMessage(pair.second));\n        }\n\n        // RTA v2 has a lifetime of 2 hours. After 2 hours RTA service will disconnect the title. On some platforms\n        // the websocket stack is able to recognize that the disconnect happened and notify libHttpClient/xsapi,\n        // triggering a reconnect attempt, but on others the disconnect goes undetected. To be more defensive against \n        // this, xsapi proactively will disconnect from rta after ~90 minutes and trigger the reconnect flow.\n#define CONNECTION_TIMEOUT_MS (90 /*mins*/ * 60 /*seconds/min*/ * 1000 /*ms/second*/)\n        m_queue.RunWork([weakThis = std::weak_ptr<Connection>{ shared_from_this() }]\n            {\n                if (auto sharedThis{ weakThis.lock() })\n                {\n                    std::unique_lock<std::mutex> lock{ sharedThis->m_lock };\n                    if ((std::chrono::system_clock::now() - sharedThis->m_connectTime).count() >= CONNECTION_TIMEOUT_MS)\n                    {\n                        auto socket = sharedThis->m_websocket;\n                        lock.unlock();\n                        // Disconnect so that auto-reconnect logic kicks in\n                        socket->Disconnect();\n                    }\n                }\n            },\n            CONNECTION_TIMEOUT_MS\n        );\n\n        lock.unlock();\n\n        for (auto& request : subMessages)\n        {\n            SendAssembledMessage(request);\n        }\n    }\n    else\n    {\n        if (m_connectAttempt > 3)\n        {\n            m_state = XblRealTimeActivityConnectionState::Disconnected;\n        }\n        ScheduleConnect();\n    }\n\n    if (lock)\n    {\n        lock.unlock();\n    }\n\n    m_stateChangedHandler(m_state);\n}\n\nvoid Connection::ScheduleConnect() noexcept\n{\n    LOGS_DEBUG << __FUNCTION__;\n\n    // Backoff and attempt to connect again. \n    auto timeNow{ chrono_clock_t::now() };\n    double lerpScaler = (timeNow.time_since_epoch().count() % 10000) / 10000.0; // from 0 to 1 based on clock\n    double jitterDelayMin = 0.0f;\n    double jitterDelayMax = (m_connectNum == 0) ? 0.0f : 5000.0f; // don't bother jitter in initial connection since it doesn't need it\n    uint64_t jitterDelay = static_cast<uint64_t>(jitterDelayMin + jitterDelayMax * lerpScaler); // lerp between min & max wait\n    uint64_t retryBackoffWithJitter = __min(std::pow(m_connectAttempt, 2), 60) * 1000 + jitterDelay;\n    m_connectAttempt++;\n\n    m_queue.RunWork([weakThis = std::weak_ptr<Connection>{ shared_from_this() }, this]\n    {\n        auto sharedThis{ weakThis.lock() };\n        if (sharedThis)\n        {\n            std::unique_lock<std::mutex> lock{ m_lock };\n\n            LOGS_DEBUG << \"RTA::Connection Initializing WebSocket and attempting connect. Subcount=\" << m_subsByClientId.size();\n\n            auto hr = InitializeWebsocket();\n            if (FAILED(hr))\n            {\n                ScheduleConnect();\n            }\n            else\n            {\n                m_state = XblRealTimeActivityConnectionState::Connecting;\n                lock.unlock();\n\n                sharedThis->m_stateChangedHandler(sharedThis->m_state);\n                sharedThis->m_websocket->Connect(s_rtaUri, s_rtaSubprotocol); // Do synchronous failures need to be handled here?\n            }\n        }\n    },\n    retryBackoffWithJitter\n    );\n}\n\n\nvoid Connection::DisconnectHandler(WebSocketCloseStatus status) noexcept\n{\n    LOGS_DEBUG << __FUNCTION__ << \": WebocketCloseStatus [\" << static_cast<uint32_t>(status) << \"]\";\n\n    List<AsyncContext<Result<void>>> unsubscribeAsyncContexts;\n    List<AsyncContext<Result<void>>> subscribeAsyncContexts;\n\n    std::unique_lock<std::mutex> lock{ m_lock };\n\n    // All subs are inactive if we are disconnected\n    m_subsByServiceId.clear();\n\n    // Update state of our subs\n    for (auto subsIter = m_subsByClientId.begin(); subsIter != m_subsByClientId.end();)\n    {\n        auto serviceSub{ subsIter->second };\n        switch (serviceSub->status)\n        {\n        case ServiceSubscription::Status::Inactive:\n        case ServiceSubscription::Status::Active:\n        case ServiceSubscription::Status::Subscribing:\n        {\n            ++subsIter;\n            break;\n        }\n        case ServiceSubscription::Status::PendingSubscribe:\n        {\n            // Complete the Unsubscribe AsyncContext, but since the client re-added the subscription,\n            // don't remove it from our state\n            unsubscribeAsyncContexts.insert(unsubscribeAsyncContexts.end(), serviceSub->unsubscribeAsyncContexts.begin(), serviceSub->unsubscribeAsyncContexts.end());\n            serviceSub->unsubscribeAsyncContexts.clear();\n\n            ++subsIter;\n            break;\n        }\n        // For subscriptions which removed by clients, complete the relevant AsyncContexts and erase the\n        // subscription from our state\n        case ServiceSubscription::Status::PendingUnsubscribe:\n        {\n            subscribeAsyncContexts.insert(subscribeAsyncContexts.end(), serviceSub->subscribeAsyncContexts.begin(), serviceSub->subscribeAsyncContexts.end());\n            serviceSub->subscribeAsyncContexts.clear();\n\n            // Intentional fallthrough\n        }\n        case ServiceSubscription::Status::Unsubscribing:\n        {\n            unsubscribeAsyncContexts.insert(unsubscribeAsyncContexts.end(), serviceSub->unsubscribeAsyncContexts.begin(), serviceSub->unsubscribeAsyncContexts.end());\n            serviceSub->unsubscribeAsyncContexts.clear();\n\n            m_subsByUri.erase(serviceSub->uri);\n            subsIter = m_subsByClientId.erase(subsIter);\n            break;\n        }\n        default:\n        {\n            assert(false);\n            break;\n        }\n        }\n\n        serviceSub->serviceId = 0;\n        serviceSub->subscribeAttempt = 0;\n        serviceSub->status = ServiceSubscription::Status::Inactive;\n    }\n\n    ScheduleConnect();\n    lock.unlock();\n\n    for (auto& async : unsubscribeAsyncContexts)\n    {\n        // Consider any unsubscribes successful. Service will eventually drop our subscriptions\n        // since we disconnected anyways\n        async.Complete(S_OK);\n    }\n\n    for (auto& async : subscribeAsyncContexts)\n    {\n        async.Complete(E_XBL_RTA_GENERIC_ERROR);\n    }\n}\n\nvoid Connection::WebsocketMessageReceived(const String& message) noexcept\n{\n    // Payload format defined here http://xboxwiki/wiki/Real_Time_Activity\n\n    LOGS_DEBUG << __FUNCTION__ << \"[\" << this << \"]: \" << message;\n\n    JsonDocument msgJson;\n    msgJson.Parse(message.c_str());\n    MessageType messageType = static_cast<MessageType>(msgJson[0].GetInt());\n\n    switch (messageType)\n    {\n    case MessageType::Subscribe:\n    {\n        SubscribeResponseHandler(msgJson);\n        break;\n    }\n    case MessageType::Unsubscribe:\n    {\n        UnsubscribeResponseHandler(msgJson);\n        break;\n    }\n    case MessageType::Event:\n    {\n        EventHandler(msgJson);\n        break;\n    }\n    case MessageType::Resync:\n    {\n        int64_t delta = m_ignoreResyncTimer.to_interval() - xbox::services::datetime::utc_now().to_interval();\n        if (delta < 0)\n        {\n            m_resyncHandler();\n        }\n        break;\n    }\n    default:\n    {\n        LOGS_ERROR << \"Received unrecognized RTA payload, ignoring\";\n        break;\n    }\n    }\n}\n\nHRESULT Connection::InitializeWebsocket() noexcept\n{\n    LOGS_DEBUG << __FUNCTION__;\n\n    if (m_websocket)\n    {\n        m_websocket->SetConnectCompleteHandler([](WebsocketResult) {});\n        m_websocket->SetDisconnectHandler([](WebSocketCloseStatus) {});\n        m_websocket->SetReceiveHandler([](String) {});\n    }\n\n    auto copyUserResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n\n    m_websocket = IWebsocket::Make(copyUserResult.ExtractPayload(), m_queue);\n\n    std::weak_ptr<Connection> thisWeakPtr{ shared_from_this() };\n\n    m_websocket->SetConnectCompleteHandler([thisWeakPtr](WebsocketResult result)\n    {\n        auto sharedThis{ thisWeakPtr.lock() };\n        if (sharedThis)\n        {\n            sharedThis->ConnectCompleteHandler(result);\n        }\n    });\n\n    m_websocket->SetDisconnectHandler([thisWeakPtr](WebSocketCloseStatus status)\n    {\n        auto sharedThis{ thisWeakPtr.lock() };\n        if (sharedThis)\n        {\n            sharedThis->DisconnectHandler(status);\n        }\n    });\n\n    m_websocket->SetReceiveHandler([thisWeakPtr](String message)\n    {\n        auto sharedThis{ thisWeakPtr.lock() };\n        if (sharedThis)\n        {\n            sharedThis->WebsocketMessageReceived(message);\n        }\n    });\n\n    return S_OK;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END"
  },
  {
    "path": "Source/Services/RealTimeActivityManager/real_time_activity_connection.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/real_time_activity_c.h\"\n#include \"real_time_activity_manager.h\"\n#include \"web_socket.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n\nstruct ServiceSubscription;\n\nclass Connection : public std::enable_shared_from_this<Connection>\n{\npublic:\n    static Result<std::shared_ptr<Connection>> Make(\n        User&& user,\n        const TaskQueue& queue,\n        ConnectionStateChangedHandler stateChangedHandler,\n        ResyncHandler resyncHandler\n    ) noexcept;\n\n    ~Connection() noexcept;\n\n    // Disconnect WebSocket, terminate background queue, and complete any pending async operations\n    void Cleanup();\n\n    HRESULT AddSubscription(\n        std::shared_ptr<Subscription> subscription,\n        AsyncContext<Result<void>> async\n    ) noexcept;\n\n    HRESULT RemoveSubscription(\n        std::shared_ptr<Subscription> subscription,\n        AsyncContext<Result<void>> async\n    ) noexcept;\n\n    size_t SubscriptionCount() const noexcept;\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    void AppStateChangeNotificationReceived(\n        bool isSuspended\n    ) noexcept;\n#endif\n\nprivate:\n    Connection(\n        User&& user,\n        const TaskQueue& queue,\n        ConnectionStateChangedHandler stateChangedHandler,\n        ResyncHandler resyncHandler\n    ) noexcept;\n\n    JsonDocument AssembleSubscribeMessage(\n        std::shared_ptr<ServiceSubscription> sub\n    ) const noexcept;\n\n    // RTA protocol implementation\n    HRESULT SendSubscribeMessage(\n        std::shared_ptr<ServiceSubscription> subscription,\n        std::unique_lock<std::mutex>&& lock\n    ) const noexcept;\n\n    HRESULT SendUnsubscribeMessage(\n        std::shared_ptr<ServiceSubscription> subscription,\n        std::unique_lock<std::mutex>&& lock\n    ) const noexcept;\n\n    HRESULT SendAssembledMessage(_In_ const JsonValue& message) const noexcept;\n\n    void SubscribeResponseHandler(_In_ const JsonValue& message) noexcept;\n    void UnsubscribeResponseHandler(_In_ const JsonValue& message) noexcept;\n    void EventHandler(_In_ const JsonValue& message) const noexcept;\n\n    // IWebsocket handlers\n    void ConnectCompleteHandler(WebsocketResult result) noexcept;\n    void DisconnectHandler(WebSocketCloseStatus result) noexcept;\n    void WebsocketMessageReceived(const String& message) noexcept;\n    HRESULT InitializeWebsocket() noexcept;\n    void ScheduleConnect() noexcept;\n\n    User m_user;\n    TaskQueue const m_queue;\n    std::shared_ptr<IWebsocket> m_websocket;\n    uint32_t m_connectAttempt{ 0 };\n    uint32_t m_connectNum{ 0 };\n    std::chrono::time_point<std::chrono::system_clock> m_connectTime;\n    XblRealTimeActivityConnectionState m_state{ XblRealTimeActivityConnectionState::Connecting };\n    xbox::services::datetime m_ignoreResyncTimer;\n    const ConnectionStateChangedHandler m_stateChangedHandler;\n    const real_time_activity::ResyncHandler m_resyncHandler;\n\n    Map<String, std::shared_ptr<ServiceSubscription>> m_subsByUri; // needed to add/remove client subscription\n    Map<uint32_t, std::shared_ptr<ServiceSubscription>> m_subsByClientId; // needed for subscribe/unsubscribe handshake\n    Map<uint32_t, std::shared_ptr<ServiceSubscription>> m_subsByServiceId; // needed to handle subscription events\n\n    uint32_t m_nextSubId{ 1 };\n\n    mutable std::mutex m_lock;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END"
  },
  {
    "path": "Source/Services/RealTimeActivityManager/real_time_activity_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"real_time_activity_manager.h\"\n#include \"real_time_activity_connection.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n\nRealTimeActivityManager::RealTimeActivityManager(\n    const TaskQueue& queue\n) noexcept\n    : m_queue{ queue.DeriveWorkerQueue() }\n{\n}\n\nRealTimeActivityManager::~RealTimeActivityManager() noexcept\n{\n    HC_TRACE_MESSAGE(XSAPI, HCTraceLevel::Verbose, __FUNCTION__);\n}\n\nvoid RealTimeActivityManager::Cleanup()\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_lock };\n\n    // Don't invoke disconnect handlers during cleanup\n    m_stateChangedHandlers.clear();\n\n    Map<uint64_t, std::shared_ptr<Connection>> connections{ std::move(m_rtaConnections) };\n    m_rtaConnections.clear();\n    lock.unlock();\n\n    for (auto& pair : connections)\n    {\n        pair.second->Cleanup();\n    }\n}\n\nHRESULT RealTimeActivityManager::AddSubscription(\n    const User& user,\n    std::shared_ptr<Subscription> subscription\n) noexcept\n{\n    assert(subscription);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(subscription);\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n    auto connectionResult{ GetConnection(user) };\n    RETURN_HR_IF_FAILED(connectionResult.Hresult());\n    return connectionResult.ExtractPayload()->AddSubscription(subscription, AsyncContext<Result<void>>{ m_queue });\n}\n\nHRESULT RealTimeActivityManager::RemoveSubscription(\n    const User& user,\n    std::shared_ptr<Subscription> subscription\n) noexcept\n{\n    assert(subscription);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(subscription);\n\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n\n    auto iter{ m_rtaConnections.find(user.Xuid()) };\n    if (iter == m_rtaConnections.end())\n    {\n        return S_OK;\n    }\n\n    return iter->second->RemoveSubscription(subscription, AsyncContext<Result<void>>{ m_queue,\n        [\n            xuid{ user.Xuid() },\n            weakThis{ std::weak_ptr<RealTimeActivityManager>{ shared_from_this() } }\n        ]\n    (Result<void> result)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            std::unique_lock<std::recursive_mutex> lock{ sharedThis->m_lock };\n            // If that was the last remaining subscription and there are no remaining legacy activations, close the connection\n            auto iter{ sharedThis->m_rtaConnections.find(xuid) };\n            if (iter != sharedThis->m_rtaConnections.end() && iter->second->SubscriptionCount() == 0 && sharedThis->m_legacyActivations[xuid] == 0)\n            {\n                LOGS_DEBUG << __FUNCTION__ << \": No remaining activations or subscriptions, tearing down connection\";\n                iter->second->Cleanup();\n                sharedThis->m_rtaConnections.erase(iter);\n\n                // Maintain legacy behavior and raise Disconnected event even on intentional shutdown\n                auto handlers{ sharedThis->m_stateChangedHandlers[xuid] };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second(XblRealTimeActivityConnectionState::Disconnected);\n                }\n            }\n        }\n    }\n    });\n}\n\nXblFunctionContext RealTimeActivityManager::AddStateChangedHandler(\n    const User& user,\n    ConnectionStateChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n    m_stateChangedHandlers[user.Xuid()][m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nvoid RealTimeActivityManager::RemoveStateChangedHandler(\n    const User& user,\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n    m_stateChangedHandlers[user.Xuid()].erase(token);\n}\n\nXblFunctionContext RealTimeActivityManager::AddResyncHandler(\n    const User& user,\n    ResyncHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n    m_resyncHandlers[user.Xuid()][m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nvoid RealTimeActivityManager::RemoveResyncHandler(\n    const User& user,\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n    m_resyncHandlers[user.Xuid()].erase(token);\n}\n\nvoid RealTimeActivityManager::Activate(\n    const User& user,\n    bool titleActivation\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_lock };\n    m_legacyActivations[user.Xuid()]++;\n\n    // If the title manually activated, establish RTA connection if its not already set up\n    if (titleActivation)\n    {\n        m_titleActivated = true;\n        (void)GetConnection(user); \n    }\n}\n\nvoid RealTimeActivityManager::Deactivate(\n    const User& user\n) noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_lock };\n\n    auto& activationCount{ m_legacyActivations[user.Xuid()] };\n    auto connectionIter{ m_rtaConnections.find(user.Xuid()) };\n    if (connectionIter == m_rtaConnections.end())\n    {\n        return;\n    }\n\n    assert(activationCount > 0);\n    if (activationCount > 0 && --activationCount == 0)\n    {\n        // When the activation count reaches 0, tear down the WebSocket connection if the title\n        // manually activated/deactivated RTA or if there are no remaining subscriptions.\n        // The second case is important due to a race condition between RemoveSubscription and Deactivate.\n        if (m_titleActivated || connectionIter->second->SubscriptionCount() == 0)\n        {\n            LOGS_DEBUG << __FUNCTION__ << \": No remaining activations tearing down connection\";\n            connectionIter->second->Cleanup();\n            m_rtaConnections.erase(connectionIter);\n\n            // Maintain legacy behavior and raise Disconnected event even on intentional shutdown\n            auto handlers{ m_stateChangedHandlers[user.Xuid()] };\n            lock.unlock();\n\n            for (auto& handler : handlers)\n            {\n                handler.second(XblRealTimeActivityConnectionState::Disconnected);\n            }\n        }\n    }\n}\n\nvoid RealTimeActivityManager::TriggerResync() const noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_lock };\n    auto handlers{ m_resyncHandlers };\n    lock.unlock();\n\n    for (auto& userPair : handlers)\n    {\n        for (auto& handlerPair : userPair.second)\n        {\n            handlerPair.second();\n        }\n    }\n}\n\nResult<std::shared_ptr<Connection>> RealTimeActivityManager::GetConnection(\n    const User& user\n) noexcept\n{\n    std::shared_ptr<Connection> connection;\n\n    auto iter{ m_rtaConnections.find(user.Xuid()) };\n    if (iter != m_rtaConnections.end())\n    {\n        connection = iter->second;\n    }\n    else\n    {\n        ConnectionStateChangedHandler stateChangedHandler =\n            [\n                xuid{ user.Xuid() },\n                weakThis{ std::weak_ptr<RealTimeActivityManager>{ shared_from_this() } }\n            ]\n        (XblRealTimeActivityConnectionState state)\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                std::unique_lock<std::recursive_mutex> lock{ sharedThis->m_lock };\n                auto handlers{ sharedThis->m_stateChangedHandlers[xuid] };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second(state);\n                }\n            }\n        };\n\n        ResyncHandler resyncHandler =\n            [\n                xuid{ user.Xuid() },\n                weakThis{ std::weak_ptr<RealTimeActivityManager>{ shared_from_this() } }\n            ]\n        (void)\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                std::unique_lock<std::recursive_mutex> lock{ sharedThis->m_lock };\n                auto handlers{ sharedThis->m_resyncHandlers[xuid] };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second();\n                }\n            }\n        };\n\n        auto copyUserResult{ user.Copy() };\n        if (Failed(copyUserResult))\n        {\n            return copyUserResult.Hresult();\n        }\n\n        auto connectionResult = Connection::Make(copyUserResult.ExtractPayload(), m_queue, std::move(stateChangedHandler), std::move(resyncHandler));\n        if (Failed(connectionResult))\n        {\n            return connectionResult.Hresult();\n        }\n        \n        connection = connectionResult.ExtractPayload();\n        m_rtaConnections[user.Xuid()] = connection;\n    }\n\n    return connection;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END\n\n// Test Hook\nHRESULT XblTestHooksTriggerRTAResync()\n{\n    auto state = GlobalState::Get();\n    if (!state)\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n    state->RTAManager()->TriggerResync();\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Source/Services/RealTimeActivityManager/real_time_activity_manager.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/real_time_activity_c.h\"\n#include \"real_time_activity_subscription.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n\ntypedef Callback<XblRealTimeActivityConnectionState> ConnectionStateChangedHandler;\ntypedef Function<void()> ResyncHandler;\n\nclass RealTimeActivityManager : public std::enable_shared_from_this<RealTimeActivityManager>\n{\npublic:\n    RealTimeActivityManager(const TaskQueue& queue) noexcept;\n    ~RealTimeActivityManager() noexcept;\n\n    // Finalize RTA communication and disconnect all WebSockets\n    void Cleanup();\n\n    HRESULT AddSubscription(\n        const User& user,\n        std::shared_ptr<Subscription> subscription\n    ) noexcept;\n\n    HRESULT RemoveSubscription(\n        const User& user,\n        std::shared_ptr<Subscription> subscription\n    ) noexcept;\n\n    XblFunctionContext AddStateChangedHandler(\n        const User& user,\n        ConnectionStateChangedHandler handler\n    ) noexcept;\n\n    void RemoveStateChangedHandler(\n        const User& user,\n        XblFunctionContext token\n    ) noexcept;\n\n    XblFunctionContext AddResyncHandler(\n        const User& user,\n        ResyncHandler handler\n    ) noexcept;\n\n    void RemoveResyncHandler(\n        const User& user,\n        XblFunctionContext token\n    ) noexcept;\n\n    // Legacy API support. Allow titles to explicitly activate and deactivate the RTA connection.\n    // Internal components will also maintain the activation count to maintain existing behavior.\n    void Activate(\n        const User& user,\n        bool titleActivation = false\n    ) noexcept;\n\n    void Deactivate(\n        const User& user\n    ) noexcept;\n\n    // Test Hook\n    void TriggerResync() const noexcept;\n\nprivate:\n    Result<std::shared_ptr<class Connection>> GetConnection(\n        const User& user\n    ) noexcept;\n\n    Map<uint64_t, std::shared_ptr<class Connection>> m_rtaConnections;\n    TaskQueue const m_queue;\n\n    XblFunctionContext m_nextToken{ 1 };\n    Map<uint64_t, Map<XblFunctionContext, ConnectionStateChangedHandler>> m_stateChangedHandlers;\n    Map<uint64_t, Map<XblFunctionContext, ResyncHandler>> m_resyncHandlers;\n\n    uint32_t m_pendingOperations{ 0 };\n\n    // Legacy API support\n    Map<uint64_t, size_t> m_legacyActivations;\n    bool m_titleActivated{ false };\n\n    mutable std::recursive_mutex m_lock;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END"
  },
  {
    "path": "Source/Services/RealTimeActivityManager/real_time_activity_subscription.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/real_time_activity_c.h\"\n\n// Support for legacy APIs\nstruct XblRealTimeActivitySubscription\n{\n    XblRealTimeActivitySubscription() noexcept = default;\n    virtual ~XblRealTimeActivitySubscription() noexcept = default;\n\n    const XblRealTimeActivitySubscriptionState state{ XblRealTimeActivitySubscriptionState::Unknown };\n    const uint32_t id{ s_nextId++ };\nprivate:\n    static std::atomic<uint32_t> s_nextId;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n\nclass Subscription\n{\npublic:\n    Subscription() noexcept = default;\n    virtual ~Subscription() noexcept = default;\n\n    String const& ResourceUri() const\n    {\n        return m_resourceUri;\n    }\n\n    virtual void OnSubscribe(const JsonValue& data) noexcept\n    {\n        UNREFERENCED_PARAMETER(data);\n        // If the data is non-null, this should have been handled by the child class\n        assert(data.IsNull());\n    };\n    virtual void OnEvent(const JsonValue& event) noexcept = 0;\n\nprotected:\n    String m_resourceUri;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END"
  },
  {
    "path": "Source/Services/Social/Manager/peoplehub_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"peoplehub_service.h\"\n#include \"presence_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\nPeoplehubService::PeoplehubService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> httpCallSettings,\n    _In_ uint32_t titleId\n) noexcept :\n    m_user{ std::move(user) },\n    m_httpSettings{ std::move(httpCallSettings) },\n    m_titleId{ titleId }\n{\n}\n\nHRESULT PeoplehubService::GetSocialGraph(\n    _In_ uint64_t xuid,\n    _In_ XblSocialManagerExtraDetailLevel decorations,\n    _In_ AsyncContext<Result<Vector<XblSocialManagerUser>>> async\n) const noexcept\n{\n    return MakeServiceCall(xuid, decorations, RelationshipType::Social, Vector<uint64_t>{}, async);\n}\n\nHRESULT PeoplehubService::GetSocialUsers(\n    _In_ uint64_t xuid,\n    _In_ XblSocialManagerExtraDetailLevel decorations,\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ AsyncContext<Result<Vector<XblSocialManagerUser>>> async\n) const noexcept\n{\n    return MakeServiceCall(xuid, decorations, RelationshipType::Batch, xuids, async);\n}\n    \nHRESULT PeoplehubService::MakeServiceCall(\n    _In_ uint64_t xuid,\n    _In_ XblSocialManagerExtraDetailLevel decorations,\n    _In_ RelationshipType relationshipType,\n    _In_opt_ const Vector<uint64_t>& batchUsers,\n    _In_ AsyncContext<Result<Vector<XblSocialManagerUser>>> async\n) const noexcept\n{\n    Stringstream subpath;\n    JsonDocument bodyJson;\n\n    subpath << \"/users/xuid(\" << xuid << \")/people/\";\n\n    switch (relationshipType)\n    {\n    case RelationshipType::Social:\n    {\n        subpath << \"friends\";\n        break;\n    }\n    case RelationshipType::Batch:\n    {\n        subpath << \"batch\";\n\n        JsonValue xuidJson = JsonValue(rapidjson::kArrayType);\n        for (size_t i = 0; i < batchUsers.size(); ++i)\n        {\n            xuidJson.PushBack(JsonValue(utils::uint64_to_internal_string(batchUsers[i]).c_str(), bodyJson.GetAllocator()).Move(), bodyJson.GetAllocator());\n        }\n\n        bodyJson.SetObject();\n        bodyJson.AddMember(\"xuids\", xuidJson, bodyJson.GetAllocator());\n        break;\n    }\n    }\n\n    // Always include the presenceDetail decoration\n    subpath << \"/decoration/presenceDetail\";\n\n    if (decorations != XblSocialManagerExtraDetailLevel::NoExtraDetail)\n    {\n        if ((decorations & XblSocialManagerExtraDetailLevel::TitleHistoryLevel) == XblSocialManagerExtraDetailLevel::TitleHistoryLevel)\n        {\n            subpath << \",titlehistory(\" << m_titleId << \")\";\n        }\n        if ((decorations & XblSocialManagerExtraDetailLevel::PreferredColorLevel) == XblSocialManagerExtraDetailLevel::PreferredColorLevel)\n        {\n            subpath << \",preferredcolor\";\n        }\n    }\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_httpSettings,\n        relationshipType == RelationshipType::Batch ? \"POST\" : \"GET\",\n        XblHttpCall::BuildUrl(\"peoplehub\", subpath.str()),\n        xbox_live_api::get_social_graph\n    ));\n\n    httpCall->SetXblServiceContractVersion(7);\n\n    if (!bodyJson.IsNull())\n    {\n        httpCall->SetRequestBody(bodyJson);\n    }\n\n    return httpCall->Perform({\n        async.Queue(),\n        [\n            async\n        ]\n    (HttpResult httpResult)\n    {\n        HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n\n        auto httpCall{ httpResult.ExtractPayload() };\n\n        auto header = httpCall->GetResponseHeader(\"x-xbl-servicedefault\");\n        if (!header.empty())\n        {\n            LOGS_ERROR << \"Peoplehub dependency failed to load: \" << header;\n            return async.Complete({ utils::convert_xbox_live_error_code_to_hresult(xbl_error_code::http_status_424_failed_dependency) });\n        }\n\n        Vector<XblSocialManagerUser> users;\n\n        JsonDocument responseBodyJson = httpCall->GetResponseBodyJson();\n        auto peopleJsonArray = JsonUtils::ExtractJsonArray(\n            responseBodyJson,\n            \"people\",\n            false\n        );\n\n        for (auto& user : peopleJsonArray)\n        {\n            auto result{ DeserializeUser(user) };\n            if (Succeeded(result))\n            {\n                users.push_back(result.ExtractPayload());\n            }\n            else\n            {\n                return async.Complete({ result.Hresult() });\n            }\n        }\n\n        return async.Complete(users);\n    } });\n}\n\nResult<XblSocialManagerUser> PeoplehubService::DeserializeUser(\n    const JsonValue& json\n)\n{\n    XblSocialManagerUser user{};\n\n    if (!json.IsObject())\n    {\n        return user;\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"xuid\", user.xboxUserId, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"isFriend\", user.isFriend));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"isFavorite\", user.isFavorite));   \n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"displayName\", user.displayName, sizeof(user.displayName)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"realName\", user.realName, sizeof(user.realName)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"displayPicRaw\", user.displayPicUrlRaw, sizeof(user.displayPicUrlRaw)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"useAvatar\", user.useAvatar));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"gamertag\", user.gamertag, sizeof(user.gamertag)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"modernGamertag\", user.modernGamertag, sizeof(user.modernGamertag)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"modernGamertagSuffix\", user.modernGamertagSuffix, sizeof(user.modernGamertagSuffix)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"uniqueModernGamertag\", user.uniqueModernGamertag, sizeof(user.uniqueModernGamertag)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"gamerScore\", user.gamerscore, sizeof(user.gamerscore)));\n\n    // isFavorite should reflect both isFavorite && isFriend from the service response\n    user.isFavorite = user.isFavorite && user.isFriend;\n    // Shim isFollowingUser and isFollowedByCaller to be true if isFriend is true\n    // This is purely for compatibility purposes and doesnt reflect a follower/following relationship\n    user.isFollowedByCaller = user.isFriend;\n    user.isFollowingUser = user.isFriend;\n\n\n    auto presenceRecordResult = DeserializePresenceRecord(json);\n    if (Succeeded(presenceRecordResult))\n    {\n        user.presenceRecord = presenceRecordResult.ExtractPayload();\n    }\n    else\n    {\n        return { presenceRecordResult.Hresult() };\n    }\n\n    if (json.IsObject() && json.HasMember(\"titleHistory\"))\n    {\n        auto titleHistoryResult = DeserializeTitleHistory(json[\"titleHistory\"]);\n        if (Succeeded(titleHistoryResult))\n        {\n            user.titleHistory = titleHistoryResult.ExtractPayload();\n        }\n        else\n        {\n            return { titleHistoryResult.Hresult() };\n        }\n    }\n\n    if (json.IsObject() && json.HasMember(\"preferredColor\"))\n    {\n        auto preferredColorResult = DeserializePreferredColor(json[\"preferredColor\"]);\n        if (Succeeded(preferredColorResult))\n        {\n            user.preferredColor = preferredColorResult.ExtractPayload();\n        }\n        else\n        {\n            return { preferredColorResult.Hresult() };\n        }\n    }\n\n    return Result<XblSocialManagerUser>{ user };\n}\n\nResult<XblSocialManagerPresenceRecord> PeoplehubService::DeserializePresenceRecord(\n    const JsonValue& json\n)\n{\n    XblSocialManagerPresenceRecord record{};\n\n    if (!json.IsObject())\n    {\n        return record;\n    }\n\n    String presenceState;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"presenceState\", presenceState));\n    record.userState = XblPresenceRecord::UserStateFromString(presenceState);\n\n    auto presenceDetailsJson = JsonUtils::ExtractJsonArray(\n        json,\n        \"presenceDetails\",\n        false\n    );\n\n    for (const auto& titleRecordJson : presenceDetailsJson)\n    {\n        auto titleRecordResult = DeserializePresenceTitleRecord(titleRecordJson);\n        if (Succeeded(titleRecordResult))\n        {\n            record.presenceTitleRecords[record.presenceTitleRecordCount++] = titleRecordResult.ExtractPayload();\n        }\n\n        if (record.presenceTitleRecordCount >= XBL_NUM_PRESENCE_RECORDS)\n        {\n            break;\n        }\n    }\n\n    return Result<XblSocialManagerPresenceRecord>{ record };\n}\n\nResult<XblSocialManagerPresenceTitleRecord> PeoplehubService::DeserializePresenceTitleRecord(\n    const JsonValue& json\n)\n{\n    XblSocialManagerPresenceTitleRecord record{};\n\n    if (!json.IsObject())\n    {\n        return { record };\n    }\n\n    String device, state, titleId;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"Device\", device));\n    record.deviceType = presence::DeviceRecord::DeviceTypeFromString(device);\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"PresenceText\", record.presenceText, sizeof(record.presenceText)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"State\", state));\n    record.isTitleActive = utils::str_icmp_internal(state, \"active\") == 0;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"TitleId\", titleId));\n    record.titleId = utils::internal_string_to_uint32(titleId);\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(json, \"IsPrimary\", record.isPrimary));\n\n    //get titleName from Presence string: format should be \"Title - Rich Presence Text\"\n    for (int i = 0; i < XBL_TITLE_NAME_CHAR_SIZE; i++)\n    {\n        char c = record.presenceText[i];\n        if (c == '-' || c == '\\0')\n        {\n            record.titleName[i] = '\\0';\n            break;\n        }\n        record.titleName[i] = c;\n    }\n\n    return Result<XblSocialManagerPresenceTitleRecord>{ record };\n}\n\nResult<XblPreferredColor> PeoplehubService::DeserializePreferredColor(\n    const JsonValue& json\n)\n{\n    XblPreferredColor color{};\n\n    if (!json.IsObject())\n    {\n        return { color };\n    }\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"primaryColor\", color.primaryColor, sizeof(color.primaryColor)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"secondaryColor\", color.secondaryColor, sizeof(color.secondaryColor)));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(json, \"tertiaryColor\", color.tertiaryColor, sizeof(color.tertiaryColor)));\n\n    return Result<XblPreferredColor>{ color };\n}\n\nResult<XblTitleHistory> PeoplehubService::DeserializeTitleHistory(\n    const JsonValue& json\n)\n{\n    XblTitleHistory titleHistory{};\n\n    if (!json.IsObject())\n    {\n        return titleHistory;\n    }\n\n    // If PeopleHub service fails to query TitleHistory, the \"lastTimePlayed\" field may be null.\n    // We don't want to fail deserialization in this case, so just return that the user has not played\n    constexpr const char* lastTimePlayedKey{ \"lastTimePlayed\" };\n    if (json.HasMember(lastTimePlayedKey) && json[lastTimePlayedKey].IsString())\n    {\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(\n            json,\n            lastTimePlayedKey,\n            titleHistory.lastTimeUserPlayed,\n            true\n        ));\n    }\n\n    constexpr const char* lastTimePlayedTextKey{ \"lastTimePlayedText\" };\n    if (json.HasMember(lastTimePlayedTextKey) && json[lastTimePlayedTextKey].IsString())\n    {\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonStringToCharArray(\n            json,\n            lastTimePlayedTextKey,\n            titleHistory.lastTimeUserPlayedText,\n            XBL_LAST_TIME_PLAYED_CHAR_SIZE\n        ));\n    }\n\n    titleHistory.hasUserPlayed = titleHistory.lastTimeUserPlayed != 0;\n\n    return Result<XblTitleHistory>{ titleHistory };\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Social/Manager/peoplehub_service.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/social_manager_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\nclass PeoplehubService\n{\npublic:\n    PeoplehubService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> httpCallSettings,\n        _In_ uint32_t titleId\n    ) noexcept;\n\n    HRESULT GetSocialGraph(\n        _In_ uint64_t xuid,\n        _In_ XblSocialManagerExtraDetailLevel decorations,\n        _In_ AsyncContext<Result<Vector<XblSocialManagerUser>>> async\n    ) const noexcept;\n\n    HRESULT GetSocialUsers(\n        _In_ uint64_t xuid,\n        _In_ XblSocialManagerExtraDetailLevel decorations,\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ AsyncContext<Result<Vector<XblSocialManagerUser>>> async\n    ) const noexcept;\n\nprivate:\n    enum class RelationshipType\n    {\n        Social,\n        Batch\n    };\n\n    HRESULT MakeServiceCall(\n        _In_ uint64_t xuid,\n        _In_ XblSocialManagerExtraDetailLevel decorations,\n        _In_ RelationshipType relationshipType,\n        _In_opt_ const Vector<uint64_t>& batchUsers,\n        _In_ AsyncContext<Result<Vector<XblSocialManagerUser>>> async\n    ) const noexcept;\n\n    static Result<XblSocialManagerUser> DeserializeUser(const JsonValue& json);\n    static Result<XblSocialManagerPresenceRecord> DeserializePresenceRecord(const JsonValue& json);\n    static Result<XblSocialManagerPresenceTitleRecord> DeserializePresenceTitleRecord(const JsonValue& json);\n    static Result<XblPreferredColor> DeserializePreferredColor(const JsonValue& json);\n    static Result<XblTitleHistory> DeserializeTitleHistory(const JsonValue& json);\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_httpSettings;\n    uint32_t const m_titleId;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Social/Manager/social_graph.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_graph.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"social_manager_user_group.h\"\n#include \"perf_tester.h\"\n\n// Max full graph refresh interval - 20 mins in ms\n#define GRAPH_REFRESH_INTERVAL_MS (20 * 60 * 1000)\n\n// Presence poll interval - 30 seconds in ms. Presence is only polled if rich presence polling is enabled.\n#ifdef XSAPI_UNIT_TESTS\n#define PRESENCE_POLL_INTERVAL_MS (1 * 1000)\n#else\n#define PRESENCE_POLL_INTERVAL_MS (30 * 1000)\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\n// Helper class to manage batching, retrying, and throttling of service calls needed by SocialGraph.\n// Seperating the state needed to manage the service calls from the actual SocialGraph state for clarity and\n// easier state synchronization.\nstruct ServiceCallManager : public std::enable_shared_from_this<ServiceCallManager>\n{\n    // Handlers invoked when Presence and Peoplehub Polls complete\n    using PresenceResultHandler = std::function<void(Vector<std::shared_ptr<XblPresenceRecord>>&&)>;\n    using PeopleHubResultHandler = std::function<void(Vector<XblSocialManagerUser>&&)>;\n\n    ServiceCallManager(\n        const User& user,\n        const TaskQueue& queue,\n        XblSocialManagerExtraDetailLevel peoplehubDetailLevel,\n        std::shared_ptr<presence::PresenceService> presenceService,\n        std::shared_ptr<PeoplehubService> peoplehubService,\n        PresenceResultHandler presenceResultHandler,\n        PeopleHubResultHandler peopleHubResultHandler\n    ) noexcept;\n\n    ~ServiceCallManager() noexcept;\n\n    // Poll rich presence for a set of users. Result delivered via PresenceResultHandler.\n    HRESULT PollPresence(const Vector<uint64_t>& xuids) noexcept;\n\n    // Poll PeopleHub profiles for a set of users. Result delivered via PeoplehubResultHandler.\n    HRESULT PollPeopleHub(const Vector<uint64_t>& xuids) noexcept;\n\n    // Get PeopleHub profiles for all followed users. Non-batched, but service failures will be retried\n    // automatically. Result delivered via 'handler' arg\n    HRESULT PeopleHubGetFollowedUsers(PeopleHubResultHandler handler) const noexcept;\n\n    // Needed to check compatibility between determined detail level and XblPresenceFilter for a social group\n    XblSocialManagerExtraDetailLevel GetDetailLevel() const noexcept;\n\nprivate:\n    HRESULT PollPresenceServiceCall(std::unique_lock<std::mutex> lock) noexcept;\n    HRESULT PollPeopleHubServiceCall(std::unique_lock<std::mutex> lock) noexcept;\n\n    static constexpr uint32_t c_failureRetryIntervalMs{ 10000 };\n    // Adhere to service throttle limits\n    static constexpr uint32_t c_presencePollIntervalMs{ 500 };\n\n    TaskQueue const m_queue;\n    XblSocialManagerExtraDetailLevel const m_peoplehubDetailLevel;\n    uint64_t const m_localUserXuid;\n\n    // Presence polling state\n    UnorderedSet<uint64_t> m_usersPendingPresence;\n    bool m_presencePollInProgress{ false };\n    PresenceResultHandler const m_presenceResultHandler;\n\n    // Peoplehub polling state\n    UnorderedSet<uint64_t> m_usersPendingPeoplehub;\n    bool m_peoplehubPollInProgress{ false };\n    PeopleHubResultHandler const m_peopleHubResultHandler;\n\n    std::shared_ptr<presence::PresenceService> m_presenceService;\n    std::shared_ptr<PeoplehubService> m_peoplehubService;\n    std::mutex m_mutex;\n};\n\n/// -----------------------------------------------------------------------------------------------\n/// SocialGraph implementation\n/// -----------------------------------------------------------------------------------------------\n\nSocialGraph::SocialGraph(\n    _In_ User&& localUser,\n    _In_ const TaskQueue& queue,\n    _In_ std::shared_ptr<real_time_activity::RealTimeActivityManager> rtaManager\n) noexcept : \n    m_user{ MakeShared<User>(std::move(localUser))},\n    m_queue{ queue.DeriveWorkerQueue() },\n    m_rtaManager{ std::move(rtaManager) }\n{\n}\n\n\nHRESULT SocialGraph::Initialize() noexcept\n{\n    // Maintain legacy RTA activation count.\n    m_rtaManager->Activate(*m_user);\n\n    auto copiedUser = m_user->Copy();\n    RETURN_HR_IF_FAILED(copiedUser.Hresult());\n\n    m_xblContext = XblContext::Make(copiedUser.ExtractPayload());\n    RETURN_HR_IF_FAILED(m_xblContext->Initialize(m_rtaManager));\n    m_xblContext->Settings()->SetHttpUserAgent(HttpCallAgent::SocialManager);\n\n    return S_OK;\n}\n\nSocialGraph::~SocialGraph()\n{\n    // Terminate any background work\n    m_queue.Terminate(false);\n\n    if (m_socialRelationshipChangedToken)\n    {\n        m_xblContext->SocialService()->RemoveSocialRTAHandler(m_socialRelationshipChangedToken);\n    }\n    if (m_devicePresenceChangedToken)\n    {\n        m_xblContext->PresenceService()->RemoveDevicePresenceChangedHandler(m_devicePresenceChangedToken);\n    }\n    if (m_titlePresenceChangedToken)\n    {\n        m_xblContext->PresenceService()->RemoveTitlePresenceChangedHandler(m_titlePresenceChangedToken);\n    }\n    if (m_rtaResyncToken)\n    {\n        m_rtaManager->RemoveResyncHandler(*m_user, m_rtaResyncToken);\n    }\n\n    m_rtaManager->Deactivate(*m_user);\n}\n\nResult<std::shared_ptr<SocialGraph>> SocialGraph::Make(\n    _In_ User&& user,\n    _In_ const XblSocialManagerExtraDetailLevel detailLevel,\n    _In_ const TaskQueue& queue,\n    _In_ std::shared_ptr<real_time_activity::RealTimeActivityManager> rtaManager\n) noexcept\n{\n    Result<xbox::services::User> userResult = user.Copy();\n    if (userResult.Hresult())\n    {\n        return userResult.Hresult();\n    }\n\n    auto graph = std::shared_ptr<SocialGraph>(\n        new (Alloc(sizeof(SocialGraph))) SocialGraph{ userResult.ExtractPayload(), queue, rtaManager },\n        Deleter<SocialGraph>(),\n        Allocator<SocialGraph>()\n    );\n    auto hr = graph->Initialize();\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    std::weak_ptr<SocialGraph> weakGraph{ graph };\n\n    auto peoplehubService = MakeShared<PeoplehubService>(std::move(user), graph->m_xblContext->Settings(), AppConfig::Instance()->TitleId());\n\n    auto presenceService = graph->m_xblContext->PresenceService();\n\n    auto peoplehubResultHandler = [weakGraph](Vector<XblSocialManagerUser>&& profiles)\n    {\n        if (auto graph{ weakGraph.lock() })\n        {\n            graph->PeoplehubResultHandler(profiles);\n        }\n    };\n\n    auto presenceResultHandler = [weakGraph](Vector<std::shared_ptr<XblPresenceRecord>>&& records)\n    {\n        if (auto graph{ weakGraph.lock() })\n        {\n            graph->PresenceResultHandler(records);\n        }\n    };\n\n    graph->m_serviceCallManager = MakeShared<ServiceCallManager>(\n        user,\n        queue,\n        detailLevel,\n        presenceService,\n        std::move(peoplehubService),\n        presenceResultHandler,\n        peoplehubResultHandler\n    );\n\n    graph->m_getSocialGraphTask = PeriodicTask::MakeAndRun(queue, GRAPH_REFRESH_INTERVAL_MS, [weakGraph]\n    {\n        if (auto graph{ weakGraph.lock() })\n        {\n            graph->m_serviceCallManager->PeopleHubGetFollowedUsers([weakGraph](Vector<XblSocialManagerUser>&& profiles)\n            {\n                if (auto graph{ weakGraph.lock() })\n                {\n                    // Update observer counts based on updated follower list\n                    std::unique_lock<std::recursive_mutex> lock{ graph->m_mutex };\n                    Vector<uint64_t> previouslyFollowedXuids, followedXuids;\n                    for (auto& pair : graph->m_profiles)\n                    {\n                        if (pair.second->isFollowedByCaller)\n                        {\n                            previouslyFollowedXuids.push_back(pair.first);\n                        }\n                    }\n                    std::transform(profiles.begin(), profiles.end(), std::back_inserter(followedXuids), [](const XblSocialManagerUser& profile)\n                    {\n                        return profile.xboxUserId;\n                    });\n                    lock.unlock();\n\n                    // Don't repoll profiles since we just called PeopleHub\n                    graph->TrackUsers(followedXuids, PeoplehubPollMode::Never);\n                    graph->StopTrackingUsers(previouslyFollowedXuids);\n\n                    // Generate graph updates\n                    graph->PeoplehubResultHandler(profiles);\n\n                    // Build initial graph on background thread since we don't care about generating events during initialization\n                    if (!graph->m_initialized)\n                    {\n                        lock.lock();\n                        Vector<XblSocialManagerEvent> events;\n                        Vector<std::shared_ptr<XblSocialManagerUser>> affectedUsers;\n                        graph->ApplyGraphUpdates(events, affectedUsers);\n                        graph->m_initialized = true;\n                    }\n                }\n            });\n\n            std::unique_lock<std::recursive_mutex> lock{ graph->m_mutex };\n            Vector<uint64_t> nonFollowedXuids;\n            for (auto& pair : graph->m_profiles)\n            {\n                if (!pair.second->isFollowedByCaller)\n                {\n                    nonFollowedXuids.push_back(pair.first);\n                }\n            }\n            lock.unlock();\n\n            if (!nonFollowedXuids.empty())\n            {\n                graph->m_serviceCallManager->PollPeopleHub(nonFollowedXuids);\n            }\n        }\n    });\n\n    graph->m_socialRelationshipChangedToken = graph->m_xblContext->SocialService()->AddSocialRelationshipChangedHandler(\n        [weakGraph](const XblSocialRelationshipChangeEventArgs& args)\n        {\n            if (auto graph{ weakGraph.lock() })\n            {\n                graph->SocialRelationshipChangedHandler(args);\n            }\n        });\n\n    // Presence change handlers can in theory be optimized to avoid a service call when presence ends,\n    // but it requires remembering a lot more state. Handling all presence changes notifications uniformly\n    // by just repolling presence simplifies the logic dramatically.\n\n    graph->m_devicePresenceChangedToken = presenceService->AddDevicePresenceChangedHandler(\n        [weakGraph](uint64_t xuid, XblPresenceDeviceType deviceType, bool isUserLoggedOnDevice)\n        {\n            UNREFERENCED_PARAMETER(deviceType);\n            UNREFERENCED_PARAMETER(isUserLoggedOnDevice);\n\n            if (auto graph{ weakGraph.lock() })\n            {\n                graph->m_serviceCallManager->PollPresence({ xuid });\n            }\n        });\n\n    graph->m_titlePresenceChangedToken = presenceService->AddTitlePresenceChangedHandler(\n        [weakGraph](uint64_t xuid, uint32_t titleId, XblPresenceTitleState state)\n        {\n            UNREFERENCED_PARAMETER(titleId);\n            UNREFERENCED_PARAMETER(state);\n\n            if (auto graph{ weakGraph.lock() })\n            {\n                graph->m_serviceCallManager->PollPresence({ xuid });\n            }\n        });\n\n    graph->m_rtaResyncToken = rtaManager->AddResyncHandler(user, [weakGraph]\n        {\n            if (auto graph{ weakGraph.lock() })\n            {\n                graph->m_getSocialGraphTask->ScheduleImmediately();\n            }\n        });\n\n    return graph;\n}\n\nstd::shared_ptr<User> SocialGraph::LocalUser() const noexcept\n{\n    return m_user;\n}\n\nvoid SocialGraph::DoWork(\n    _Inout_ Vector<XblSocialManagerEvent>& events,\n    _Inout_ Vector<std::shared_ptr<XblSocialManagerUser>>& affectedUsers\n) noexcept\n{\n    PERF_START();\n    // For performance reasons, don't wait for the mutex if a background thread holds it\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex, std::defer_lock };\n    if (lock.try_lock() && m_initialized)\n    {\n        // Raise the LocalUserAdded Event in the first DoWork call after the intial graph has loaded\n        if (!m_localUserAdded)\n        {\n            events.push_back(XblSocialManagerEvent{ m_user->Handle(), XblSocialManagerEventType::LocalUserAdded });\n            m_localUserAdded = true;\n        }\n\n        // Apply graph updates\n        ApplyGraphUpdates(events, affectedUsers);\n\n        // Notify groups of graph changes\n        for (auto& pair : m_groups)\n        {\n            // If group isn't initialized, schedule initialization to background queue.\n            switch (pair.second)\n            {\n            case GroupInitializationStage::Pending:\n            {\n                pair.second = GroupInitializationStage::Scheduled;\n\n                m_queue.RunWork([this, sharedThis{ shared_from_this() }, group{ pair.first }]\n                {\n                    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n                    group->Initialize(m_profiles);\n                    m_groups[group] = GroupInitializationStage::Complete;\n                });\n\n                break;\n            }\n            case GroupInitializationStage::Complete:\n            {\n                pair.first->DoWork(events);\n                break;\n            }\n            case GroupInitializationStage::Scheduled:\n            default:\n            {\n                break;\n            }\n            }\n        }\n    }\n    PERF_STOP();\n}\n\nvoid SocialGraph::RegisterGroup(std::shared_ptr<XblSocialManagerUserGroup> group) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    // If this is a new group or an existing group that has already completed initialization, set initialization stage\n    // so that it gets initialized during DoWork.\n    auto iter{ m_groups.find(group) };\n    if (iter == m_groups.end() || iter->second == GroupInitializationStage::Complete)\n    {\n        m_groups[group] = GroupInitializationStage::Pending;\n\n        // Check if the filter is one that relies on title history but TitleHistoryLevel is not set\n        if ((group->presenceFilter == XblPresenceFilter::TitleOffline || \n             group->presenceFilter == XblPresenceFilter::TitleOnlineOutsideTitle || \n             group->presenceFilter == XblPresenceFilter::AllTitle) && \n            (m_serviceCallManager->GetDetailLevel() & XblSocialManagerExtraDetailLevel::TitleHistoryLevel) != XblSocialManagerExtraDetailLevel::TitleHistoryLevel)\n        {\n            LOGS_DEBUG << \"TitleOffline, TitleOnlineOutsideTitle, and AllTitle filters require XblSocialManagerExtraDetailLevel::TitleHistoryLevel to be set for this user\";\n        }\n    }\n}\n\nvoid SocialGraph::UnregisterGroup(std::shared_ptr<XblSocialManagerUserGroup> group) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    m_groups.erase(group);\n}\n\nvoid SocialGraph::TrackUsers(\n    _In_ const Vector<uint64_t>& xuids\n) noexcept\n{\n    // Only poll PeopleHub for profiles not already in the graph\n    TrackUsers(xuids, PeoplehubPollMode::IfNew);\n}\n\nvoid SocialGraph::TrackUsers(\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ PeoplehubPollMode refreshMode\n) noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n    Vector<uint64_t> refreshXuids;\n    for (auto xuid : xuids)\n    {\n        auto iter = m_trackedUsers.find(xuid);\n        if (iter == m_trackedUsers.end())\n        {\n            // Add new graph entry\n            m_trackedUsers.emplace(xuid, TrackedUser{ xuid, m_xblContext->PresenceService() });\n            if (refreshMode == PeoplehubPollMode::Always || refreshMode == PeoplehubPollMode::IfNew)\n            {\n                refreshXuids.emplace_back(xuid);\n            }\n        }\n        else\n        {\n            ++iter->second.refCount;\n            if (refreshMode == PeoplehubPollMode::Always)\n            {\n                refreshXuids.emplace_back(xuid);\n            }\n        }\n    }\n\n    lock.unlock();\n    if (!refreshXuids.empty())\n    {\n        m_serviceCallManager->PollPeopleHub(refreshXuids);\n    }\n}\n\nvoid SocialGraph::StopTrackingUsers(\n    _In_ const Vector<uint64_t>& xuids\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto xuid : xuids)\n    {\n        auto iter{ m_trackedUsers.find(xuid) };\n        if (iter != m_trackedUsers.end() && --iter->second.refCount == 0)\n        {\n            m_trackedUsers.erase(iter);\n            m_pendingUpdates[xuid] = { ProfileChanges::None, nullptr };\n        }\n    }\n}\n\nvoid SocialGraph::SetRichPresencePolling(bool enabled) noexcept\n{\n    if (enabled != m_presencePollingEnabled)\n    {\n        m_presencePollingEnabled = enabled;\n        if (m_presencePollingEnabled)\n        {\n            assert(!m_getPresenceForGraphTask);\n\n            m_getPresenceForGraphTask = PeriodicTask::MakeAndRun(m_queue, PRESENCE_POLL_INTERVAL_MS, \n                [\n                    weakGraph = std::weak_ptr<SocialGraph>{ shared_from_this() },\n                    this\n                ]\n            {\n                if (auto graph{weakGraph.lock()})\n                {\n                    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n                    Vector<uint64_t> xuids;\n                    std::transform(m_trackedUsers.begin(), m_trackedUsers.end(), std::back_inserter(xuids), [](const auto& pair)\n                    {\n                        return pair.first;\n                    });\n\n                    lock.unlock();\n                    m_serviceCallManager->PollPresence(xuids);\n                }\n            });\n        }\n        else\n        {\n            assert(m_getPresenceForGraphTask);\n            m_getPresenceForGraphTask.reset();\n        }\n    }\n}\n\nvoid SocialGraph::PeoplehubResultHandler(\n    const Vector<XblSocialManagerUser>& users\n) noexcept\n{\n    PERF_START();\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto& profile : users)\n    {\n        auto iter{ m_profiles.find(profile.xboxUserId) };\n        if (iter == m_profiles.end())\n        {\n            m_pendingUpdates[profile.xboxUserId] = { ProfileChanges::None, MakeShared<XblSocialManagerUser>(profile) };\n        }\n        else if (auto changes = CompareProfiles(*iter->second, profile))\n        {\n            m_pendingUpdates[profile.xboxUserId] = { changes, MakeShared<XblSocialManagerUser>(profile) };\n        }\n    }\n    PERF_STOP();\n}\n\nvoid SocialGraph::PresenceResultHandler(\n    const Vector<std::shared_ptr<XblPresenceRecord>>& presenceRecords\n) noexcept\n{\n    PERF_START();\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n    for (auto& record : presenceRecords)\n    {\n        // When comparing with existing profile, first check if there is a pending update\n        std::shared_ptr<XblSocialManagerUser> compareProfile{ nullptr };\n\n        auto updatesIter{ m_pendingUpdates.find(record->Xuid()) };\n        if (updatesIter != m_pendingUpdates.end())\n        {\n            compareProfile = updatesIter->second.second;\n        }\n        if (!compareProfile)\n        {\n            auto profilesIter{ m_profiles.find(record->Xuid()) };\n            if (profilesIter != m_profiles.end())\n            {\n                compareProfile = profilesIter->second;\n            }\n        }\n\n        // If there is no entry to compare, ignore. The profile (including presence) will be updated\n        // when the associated Peoplehub call completes\n        if (compareProfile)\n        {\n            auto smRecord{ ConvertPresenceRecord(record) };\n            if (memcmp(&compareProfile->presenceRecord, &smRecord, sizeof(XblSocialManagerPresenceRecord)))\n            {\n                auto updatedProfile = MakeShared<XblSocialManagerUser>(*compareProfile);\n                memcpy(&updatedProfile->presenceRecord, &smRecord, sizeof(XblSocialManagerPresenceRecord));\n\n                m_pendingUpdates[updatedProfile->xboxUserId] = { ProfileChanges::PresenceChanged, updatedProfile };\n            }\n        }\n    }\n    PERF_STOP();\n}\n\nvoid SocialGraph::SocialRelationshipChangedHandler(\n    const XblSocialRelationshipChangeEventArgs& args\n) noexcept\n{\n    // Depending on the type of notification and whether or not the user is still being tracked\n    // in our graph, we will need to refresh the profiles for a subset of the affected xuids.\n    Vector<uint64_t> affectedXuids(args.xboxUserIds, args.xboxUserIds + args.xboxUserIdsCount);\n    Vector<uint64_t> refreshXuids;\n\n    switch (args.socialNotification)\n    {\n    case XblSocialNotificationType::Added:\n    {\n        TrackUsers(affectedXuids, PeoplehubPollMode::Always);\n        break;\n    }\n    case XblSocialNotificationType::Changed:\n    {\n        refreshXuids = std::move(affectedXuids);\n        break;\n    }\n    case XblSocialNotificationType::Removed:\n    {\n        StopTrackingUsers(affectedXuids);\n\n        // If the users are still in the graph, refresh their profile\n        std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n        for (auto xuid : affectedXuids)\n        {\n            if(m_trackedUsers.find(xuid) != m_trackedUsers.end())\n            {\n                refreshXuids.push_back(xuid);\n            }\n        }\n        break;\n    }\n    default:\n    {\n        LOGS_DEBUG << \"Unknown social notification received and ignored.\";\n    }\n    }\n\n    if (!refreshXuids.empty())\n    {\n        m_serviceCallManager->PollPeopleHub(refreshXuids);\n    }\n}\n\nvoid SocialGraph::AddOrUpdateEvent(\n    XblSocialManagerEventType type,\n    const std::shared_ptr<XblSocialManagerUser>& affectedUser,\n    Vector<XblSocialManagerEvent>& events,\n    Vector<std::shared_ptr<XblSocialManagerUser>>& affectedUsers\n) noexcept\n{\n    PERF_START();\n\n    // Update affected users set\n    affectedUsers.push_back(affectedUser);\n\n    // Try to update an existing event first\n    for (auto& event : events)\n    {\n        if (event.eventType == type)\n        {\n            uint8_t affectedUserIndex{ 0 };\n            for (; affectedUserIndex < std::extent<decltype(event.usersAffected)>::value && event.usersAffected[affectedUserIndex]; ++affectedUserIndex);\n            if (affectedUserIndex < std::extent<decltype(event.usersAffected)>::value)\n            {\n                event.usersAffected[affectedUserIndex] = affectedUser.get();\n                return;\n            }\n        }\n    }\n\n    // If we couldn't update an existing event, add a new one\n    events.emplace_back();\n    auto& newEvent{ events.back() };\n    newEvent.eventType = type;\n    newEvent.user = m_user->Handle();\n    newEvent.usersAffected[0] = affectedUser.get();\n\n    PERF_STOP();\n}\n\nvoid SocialGraph::ApplyGraphUpdates(\n    _Inout_ Vector<XblSocialManagerEvent>& events,\n    _Inout_ Vector<std::shared_ptr<XblSocialManagerUser>>& affectedUsers\n) noexcept\n{\n    PERF_START();\n\n    // Apply updates. After initialization, apply at most MAX_GRAPH_UPDATES_PER_FRAME\n    size_t updatesApplied = 0;\n    size_t updateLimit{ m_initialized ? MAX_GRAPH_UPDATES_PER_FRAME : 1000u };\n\n    for (auto updateIter = m_pendingUpdates.begin(); updateIter != m_pendingUpdates.end() && updatesApplied < updateLimit; updateIter = m_pendingUpdates.erase(updateIter), ++updatesApplied)\n    {\n        auto& xuid{ updateIter->first };\n        auto trackedUserIter{ m_trackedUsers.find(xuid) };\n        auto profileIter{ m_profiles.find(xuid) };\n        auto profileChanges{ updateIter->second.first };\n        auto& updatedProfile{ updateIter->second.second };\n\n        // If we are no longer tracking the user remove the profile and add event\n        if (trackedUserIter == m_trackedUsers.end() && profileIter != m_profiles.end())\n        {\n            AddOrUpdateEvent(XblSocialManagerEventType::UsersRemovedFromSocialGraph, profileIter->second, events, affectedUsers);\n            m_profiles.erase(profileIter);\n        }\n        else if (updatedProfile) // This could be null in cases where the user is untracked/tracked in the same DoWork cycle\n        {\n            // If this is a new profile, generate only a user added event. Otherwise generate depending on the profileChanges\n            if (profileIter == m_profiles.end())\n            {\n                AddOrUpdateEvent(XblSocialManagerEventType::UsersAddedToSocialGraph, updatedProfile, events, affectedUsers);\n                m_profiles.insert({ xuid, updatedProfile });\n            }\n            else\n            {\n                profileIter->second = updatedProfile;\n                if (profileChanges & ProfileChanges::PresenceChanged)\n                {\n                    AddOrUpdateEvent(XblSocialManagerEventType::PresenceChanged, updatedProfile, events, affectedUsers);\n                }\n                if (profileChanges & ProfileChanges::RelationshipChanged)\n                {\n                    AddOrUpdateEvent(XblSocialManagerEventType::SocialRelationshipsChanged, updatedProfile, events, affectedUsers);\n                }\n                if (profileChanges & ProfileChanges::ProfileChanged)\n                {\n                    AddOrUpdateEvent(XblSocialManagerEventType::ProfilesChanged, updatedProfile, events, affectedUsers);\n                }\n            }\n        }\n    }\n    PERF_STOP();\n}\n\nProfileChanges SocialGraph::CompareProfiles(\n    const XblSocialManagerUser& old,\n    const XblSocialManagerUser& updated\n) noexcept\n{\n    auto changes{ ProfileChanges::None };\n\n    // ProfileChanges::RelationshipChanged indicates favorite/following/followed changed\n    if (old.isFollowedByCaller != updated.isFollowedByCaller ||\n        old.isFollowingUser != updated.isFollowingUser ||\n        old.isFavorite != updated.isFavorite\n    )\n    {\n        changes |= ProfileChanges::RelationshipChanged;\n    }\n    // ProfileChanges::PresenceChange indicates a change in the presence record\n    if (memcmp(&old.presenceRecord, &updated.presenceRecord, sizeof(XblSocialManagerPresenceRecord)))\n    {\n        changes |= ProfileChanges::PresenceChanged;\n    }\n    // ProfileChanges::ProfileChanged indicates any other change\n    if (utils::str_icmp(old.gamerscore, updated.gamerscore) != 0 ||\n        old.titleHistory.hasUserPlayed != updated.titleHistory.hasUserPlayed ||\n        old.titleHistory.lastTimeUserPlayed != updated.titleHistory.lastTimeUserPlayed ||\n        utils::str_icmp(old.displayPicUrlRaw, updated.displayPicUrlRaw) != 0 ||\n        old.useAvatar != updated.useAvatar ||\n        utils::str_icmp(old.gamertag, updated.gamertag) != 0 ||\n        utils::str_icmp(old.modernGamertag, updated.modernGamertag) != 0 ||\n        utils::str_icmp(old.modernGamertagSuffix, updated.modernGamertagSuffix) != 0 ||\n        utils::str_icmp(old.uniqueModernGamertag, updated.uniqueModernGamertag) != 0 ||\n        utils::str_icmp(old.displayName, updated.displayName) != 0 ||\n        utils::str_icmp(old.realName, updated.realName) != 0 ||\n        utils::str_icmp(old.preferredColor.primaryColor, updated.preferredColor.primaryColor) != 0 ||\n        utils::str_icmp(old.preferredColor.secondaryColor, updated.preferredColor.secondaryColor) != 0 ||\n        utils::str_icmp(old.preferredColor.tertiaryColor, updated.preferredColor.tertiaryColor) != 0\n    )\n    {\n        changes |= ProfileChanges::ProfileChanged;\n    }\n    return changes;\n}\n\nXblSocialManagerPresenceRecord SocialGraph::ConvertPresenceRecord(\n    std::shared_ptr<XblPresenceRecord> presenceRecord\n) noexcept\n{\n    XblSocialManagerPresenceRecord smPresenceRecord{};\n    smPresenceRecord.userState = presenceRecord->UserState();\n\n    for (auto& deviceRecord : presenceRecord->DeviceRecords())\n    {\n        for (uint32_t i = 0; i < deviceRecord.titleRecordsCount && smPresenceRecord.presenceTitleRecordCount < XBL_NUM_PRESENCE_RECORDS; ++i)\n        {\n            auto& smTitleRecord{ smPresenceRecord.presenceTitleRecords[smPresenceRecord.presenceTitleRecordCount++] };\n            auto& newTitleRecord{ deviceRecord.titleRecords[i] };\n\n            smTitleRecord.titleId = newTitleRecord.titleId;\n            smTitleRecord.isTitleActive = newTitleRecord.titleActive;\n            utils::strcpy(smTitleRecord.titleName, sizeof(smTitleRecord.titleName), newTitleRecord.titleName);\n            utils::strcpy(smTitleRecord.presenceText, sizeof(smTitleRecord.presenceText), newTitleRecord.richPresenceString);\n            smTitleRecord.isBroadcasting = newTitleRecord.broadcastRecord != nullptr;\n            smTitleRecord.deviceType = deviceRecord.deviceType;\n        }\n\n        if (smPresenceRecord.presenceTitleRecordCount == XBL_NUM_PRESENCE_RECORDS)\n        {\n            break;\n        }\n    }\n    return smPresenceRecord;\n}\n\n/// -----------------------------------------------------------------------------------------------\n/// TrackedUser implementation\n/// -----------------------------------------------------------------------------------------------\n\nTrackedUser::TrackedUser(\n    uint64_t _xuid,\n    std::shared_ptr<presence::PresenceService> _presenceService\n) noexcept\n    : xuid{ _xuid },\n    presenceService{ std::move(_presenceService) }\n{\n    PERF_START();\n    HRESULT hr = presenceService->TrackUsers({ xuid });\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n    PERF_STOP();\n}\n\nTrackedUser::TrackedUser(const TrackedUser& other) noexcept\n    : TrackedUser{ other.xuid, other.presenceService }\n{\n}\n\nTrackedUser::~TrackedUser() noexcept\n{\n    PERF_START();\n    assert(presenceService);\n    presenceService->StopTrackingUsers({ xuid });\n    PERF_STOP();\n}\n\n/// -----------------------------------------------------------------------------------------------\n/// ServiceCallManager implementation\n/// -----------------------------------------------------------------------------------------------\n\nServiceCallManager::ServiceCallManager(\n    const User& user,\n    const TaskQueue& queue,\n    XblSocialManagerExtraDetailLevel peoplehubDetailLevel,\n    std::shared_ptr<presence::PresenceService> presenceService,\n    std::shared_ptr<PeoplehubService> peoplehubService,\n    PresenceResultHandler presenceResultHandler,\n    PeopleHubResultHandler peoplehubResultHandler\n) noexcept\n    : m_queue{ queue.DeriveWorkerQueue() },\n    m_peoplehubDetailLevel{ peoplehubDetailLevel },\n    m_localUserXuid{ user.Xuid() },\n    m_presenceResultHandler{ std::move(presenceResultHandler) },\n    m_peopleHubResultHandler{ std::move(peoplehubResultHandler) },\n    m_presenceService{ std::move(presenceService) },\n    m_peoplehubService{ std::move(peoplehubService) }\n{\n}\n\nServiceCallManager::~ServiceCallManager() noexcept\n{\n    m_queue.Terminate(false);\n}\n\nHRESULT ServiceCallManager::PollPresence(const Vector<uint64_t>& xuids) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n\n    m_usersPendingPresence.insert(xuids.begin(), xuids.end());\n    if (!m_presencePollInProgress)\n    {\n        return PollPresenceServiceCall(std::move(lock));\n    }\n    return S_OK;\n}\n\nHRESULT ServiceCallManager::PollPeopleHub(const Vector<uint64_t>& xuids) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n\n    m_usersPendingPeoplehub.insert(xuids.begin(), xuids.end());\n    if (!m_peoplehubPollInProgress)\n    {\n        return PollPeopleHubServiceCall(std::move(lock));\n    }\n    return S_OK;\n}\n\nHRESULT ServiceCallManager::PeopleHubGetFollowedUsers(PeopleHubResultHandler handler) const noexcept\n{\n    return m_peoplehubService->GetSocialGraph(m_localUserXuid, m_peoplehubDetailLevel, { m_queue,\n        [\n            weakThis = std::weak_ptr<ServiceCallManager const>{ shared_from_this() },\n            this,\n            handler{ std::move(handler) }\n        ]\n    (Result<Vector<XblSocialManagerUser>> result)\n    {\n        if (Failed(result))\n        {\n            m_queue.RunWork([weakThis, this, handler]\n            {\n                if (auto sharedThis{ weakThis.lock() })\n                {\n                    PeopleHubGetFollowedUsers(handler);\n                }\n            }, c_failureRetryIntervalMs);\n        }\n        else\n        {\n            handler(result.ExtractPayload());\n        }\n    }\n    });\n}\n\nHRESULT ServiceCallManager::PollPresenceServiceCall(std::unique_lock<std::mutex> lock) noexcept\n{\n    assert(lock.owns_lock());\n    if (m_usersPendingPresence.empty())\n    {\n        return S_OK;\n    }\n\n    XblPresenceQueryFilters filters{};\n    filters.detailLevel = XblPresenceDetailLevel::All;\n\n    Vector<uint64_t> pollXuids{ m_usersPendingPresence.begin(), m_usersPendingPresence.end() };\n\n    auto hr = m_presenceService->GetBatchPresence(\n        presence::UserBatchRequest{ pollXuids.data(), pollXuids.size(), &filters }, { m_queue,\n        [\n            weakThis = std::weak_ptr<ServiceCallManager>{ shared_from_this() },\n            this,\n            pollXuids\n        ]\n    (Result<Vector<std::shared_ptr<XblPresenceRecord>>> result)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            uint32_t interval{ c_presencePollIntervalMs };\n\n            std::unique_lock<std::mutex> lock{ sharedThis->m_mutex };\n            if (Failed(result))\n            {\n                // Ensure failed xuids are retried. Increase poll interval for failures\n                m_usersPendingPresence.insert(pollXuids.begin(), pollXuids.end());\n                interval = c_failureRetryIntervalMs;\n            }\n            else\n            {\n                m_presenceResultHandler(result.ExtractPayload());\n            }\n\n            // Schedule next poll if xuids are still pending\n            if (!m_usersPendingPresence.empty())\n            {\n                m_queue.RunWork([weakThis, this]\n                {\n                    if (auto sharedThis{ weakThis.lock() })\n                    {\n                        PollPresenceServiceCall(std::unique_lock<std::mutex>{ m_mutex });\n                    }\n                }, interval);\n            }\n            else\n            {\n                m_presencePollInProgress = false;\n            }\n        }\n    }\n    });\n\n    m_presencePollInProgress = true;\n    m_usersPendingPresence.clear();\n\n    return hr;\n}\n\nHRESULT ServiceCallManager::PollPeopleHubServiceCall(std::unique_lock<std::mutex> lock) noexcept\n{\n    assert(lock.owns_lock());\n    if (m_usersPendingPeoplehub.empty())\n    {\n        return S_OK;\n    }\n\n    Vector<uint64_t> pollXuids{ m_usersPendingPeoplehub.begin(), m_usersPendingPeoplehub.end() };\n\n    auto hr = m_peoplehubService->GetSocialUsers(m_localUserXuid, m_peoplehubDetailLevel, pollXuids, { m_queue,\n        [\n            weakThis = std::weak_ptr<ServiceCallManager>{ shared_from_this() },\n            this,\n            pollXuids\n        ]\n    (Result<Vector<XblSocialManagerUser>> result)\n    {\n        if (auto sharedThis{ weakThis.lock() })\n        {\n            uint32_t interval{ 0 };\n\n            std::unique_lock<std::mutex> lock{ sharedThis->m_mutex };\n            if (Failed(result))\n            {\n                // Ensure failed xuids are retried. Increase poll interval for failures\n                m_usersPendingPeoplehub.insert(pollXuids.begin(), pollXuids.end());\n                interval = c_failureRetryIntervalMs;\n            }\n            else\n            {\n                m_peopleHubResultHandler(result.ExtractPayload());\n            }\n\n            // Schedule next poll if xuids are still pending\n            if (!m_usersPendingPeoplehub.empty())\n            {\n                m_queue.RunWork([weakThis, this]\n                {\n                    if (auto sharedThis{ weakThis.lock() })\n                    {\n                        PollPeopleHubServiceCall(std::unique_lock<std::mutex>{ m_mutex });\n                    }\n                }, interval);\n            }\n            else\n            {\n                m_peoplehubPollInProgress = false;\n            }\n        }\n    }\n    });\n\n    m_peoplehubPollInProgress = true;\n    m_usersPendingPeoplehub.clear();\n\n    return hr;\n}\n\nXblSocialManagerExtraDetailLevel ServiceCallManager::GetDetailLevel() const noexcept\n{\n    return m_peoplehubDetailLevel;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Social/Manager/social_graph.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"presence_internal.h\"\n#include \"social_internal.h\"\n#include \"peoplehub_service.h\"\n#include \"real_time_activity_manager.h\"\n\n#ifdef max\n#undef max\n#endif\n\n// Throttle the maximum number of updates the SocialGraph will process each call to DoWork\n#define MAX_GRAPH_UPDATES_PER_FRAME 5\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\n// Enum describing how a profile has changed\nenum ProfileChanges : uint32_t\n{\n    None = 0x0,\n    ProfileChanged = 0x1,\n    PresenceChanged = 0x2,\n    RelationshipChanged = 0x4\n};\n\nDEFINE_ENUM_FLAG_OPERATORS(ProfileChanges);\n\n// Metadata about a user tracked by SocialGraph. Maintains RTA tracking and counts references within the SocialGraph\nstruct TrackedUser\n{\n    TrackedUser(\n        uint64_t xuid,\n        std::shared_ptr<presence::PresenceService> presenceService\n    ) noexcept;\n    TrackedUser(const TrackedUser& other) noexcept;\n    TrackedUser& operator=(TrackedUser) = delete;\n    ~TrackedUser() noexcept;\n\n    uint32_t refCount{ 1 };\n    uint64_t xuid;\n    std::shared_ptr<presence::PresenceService> presenceService;\n};\n\n// Tracks profile and presence changes for other XboxLiveUsers. Automatically tracks users followed by the \n// local user, but additional remote users can be added explicitly. \nclass SocialGraph : public std::enable_shared_from_this<SocialGraph>\n{\npublic:\n    static Result<std::shared_ptr<SocialGraph>> Make(\n        _In_ User&& localUser,\n        _In_ const XblSocialManagerExtraDetailLevel detailLevel,\n        _In_ const TaskQueue& queue,\n        _In_ std::shared_ptr<real_time_activity::RealTimeActivityManager> rtaManager\n    ) noexcept;\n\n    ~SocialGraph();\n\n    // LocalUser that the SocialGraph is for\n    std::shared_ptr<User> LocalUser() const noexcept;\n\n    // Patches profile and presence updates that have happened since the last call to DoWork into the graph.\n    // Appends XblSocialManagerEvents describing the updates to 'events' list. Appends all affected users to the list of affected users.\n    // This is used to maintain their lifetime since the events reference them.\n    void DoWork(\n        _Inout_ Vector<XblSocialManagerEvent>& events,\n        _Inout_ Vector<std::shared_ptr<XblSocialManagerUser>>& affectedUsers\n    ) noexcept;\n\n    // Registers/Unregisters an XblSocialManagerUserGroup backed by this graph. Registered groups\n    // will be initialized and then notified of graph changes each call to DoWork\n    void RegisterGroup(std::shared_ptr<XblSocialManagerUserGroup> group) noexcept;\n    void UnregisterGroup(std::shared_ptr<XblSocialManagerUserGroup> group) noexcept;\n\n    // Track a list of users. If they are not currently tracked, they will be added to the graph.\n    void TrackUsers(\n        _In_ const Vector<uint64_t>& xuids\n    ) noexcept;\n\n    // Stop tracking a list of users that were previously added via TrackUsers.\n    void StopTrackingUsers(\n        _In_ const Vector<uint64_t>& xuids\n    ) noexcept;\n\n    // Enable/Disbale rich presence polling. If set to true, creates a Periodic Task to refresh presence and\n    // runs it immediately.\n    void SetRichPresencePolling(bool enabled) noexcept;\n\n    HRESULT Initialize() noexcept;\nprivate:\n    SocialGraph(\n        _In_ User&& localUser,\n        _In_ const TaskQueue& queue,\n        _In_ std::shared_ptr<real_time_activity::RealTimeActivityManager> rtaManager\n    ) noexcept;\n\n    // Generate Graph Updates based on the result of a PeopleHub service call\n    void PeoplehubResultHandler(\n        const Vector<XblSocialManagerUser>& users\n    ) noexcept;\n\n    // Generate Graph Updates based on the result of a Presence service call\n    void PresenceResultHandler(\n        const Vector<std::shared_ptr<XblPresenceRecord>>& presenceRecords\n    ) noexcept;\n\n    // RTA handler\n    void SocialRelationshipChangedHandler(const XblSocialRelationshipChangeEventArgs& args) noexcept;\n\n    // Enum describing how to update a tracked User's profile\n    enum PeoplehubPollMode { Never, IfNew, Always };\n    void TrackUsers(\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ PeoplehubPollMode refreshMode\n    ) noexcept;\n\n    // Helper that aggregates events based on graph updates\n    inline void AddOrUpdateEvent(\n        XblSocialManagerEventType type,\n        const std::shared_ptr<XblSocialManagerUser>& affectedUser,\n        Vector<XblSocialManagerEvent>& events,\n        Vector<std::shared_ptr<XblSocialManagerUser>>& affectedUsers\n    ) noexcept;\n\n    // Applies all pending updates to local graph. Updates events and affected users\n    void ApplyGraphUpdates(\n        _Inout_ Vector<XblSocialManagerEvent>& events,\n        _Inout_ Vector<std::shared_ptr<XblSocialManagerUser>>& affectedUsers\n    ) noexcept;\n\n    static ProfileChanges CompareProfiles(\n        const XblSocialManagerUser& old,\n        const XblSocialManagerUser& updated\n    ) noexcept;\n\n    static XblSocialManagerPresenceRecord ConvertPresenceRecord(\n        std::shared_ptr<XblPresenceRecord> presenceRecord\n    ) noexcept;\n\n    std::shared_ptr<User> m_user;\n    TaskQueue const m_queue;\n\n    // Graph state\n    UnorderedMap<uint64_t, std::shared_ptr<XblSocialManagerUser>> m_profiles;\n    UnorderedMap<uint64_t, TrackedUser> m_trackedUsers;\n    UnorderedMap<uint64_t, std::pair<ProfileChanges, std::shared_ptr<XblSocialManagerUser>>> m_pendingUpdates;\n\n    // Groups. Initialization stage indicates whether or not a group has been initialized yet\n    enum GroupInitializationStage{ Pending, Scheduled, Complete };\n    Map<std::shared_ptr<XblSocialManagerUserGroup>, GroupInitializationStage> m_groups;\n\n    bool m_presencePollingEnabled{ false };\n    bool m_localUserAdded{ false };\n    bool m_initialized{ false };\n\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n    std::shared_ptr<XblContext> m_xblContext;\n    std::shared_ptr<struct ServiceCallManager> m_serviceCallManager;\n\n    // Handler tokens\n    XblFunctionContext m_socialRelationshipChangedToken{ 0 };\n    XblFunctionContext m_devicePresenceChangedToken{ 0 };\n    XblFunctionContext m_titlePresenceChangedToken{ 0 };\n    XblFunctionContext m_rtaResyncToken{ 0 };\n\n    // Background PeriodicTasks\n    std::shared_ptr<PeriodicTask> m_getPresenceForGraphTask;\n    std::shared_ptr<PeriodicTask> m_getSocialGraphTask;\n\n    mutable std::recursive_mutex m_mutex;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Social/Manager/social_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_manager_internal.h\"\n#include \"social_manager_user_group.h\"\n#include \"social_graph.h\"\n#include \"perf_tester.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\nSocialManager::SocialManager() noexcept\n{\n    // MAX_GRAPH_UPDATES_PER_FRAME doesn't directly map to a number XblSocialManagerEvents, but it is correlated so\n    // we can use it to preallocate some memory for events nonetheless\n    m_events.reserve(MAX_GRAPH_UPDATES_PER_FRAME * 2);\n    m_affectedUsersLifetime.reserve(m_events.capacity() * std::extent<decltype(XblSocialManagerEvent::usersAffected)>::value);\n}\n\nHRESULT SocialManager::AddLocalUser(\n    User&& user,\n    XblSocialManagerExtraDetailLevel detailLevel,\n    TaskQueue&& queue\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto xuid{ user.Xuid() };\n    if (m_graphs.find(xuid) != m_graphs.end())\n    {\n        LOGS_ERROR << \"User \" << xuid << \" already added to SocialManager\";\n        return E_UNEXPECTED;\n    }\n\n    auto socialGraph = SocialGraph::Make(std::move(user), detailLevel, queue, GlobalState::Get()->RTAManager());\n    RETURN_HR_IF_FAILED(socialGraph.Hresult());\n\n    m_graphs[xuid] = socialGraph.ExtractPayload();\n    return S_OK;\n}\n\nHRESULT SocialManager::RemoveLocalUser(\n    const User& user\n) noexcept\n{\n    // Destroy graph outside lock so DoWork thread isn't blocked\n    std::shared_ptr<SocialGraph> graph{ nullptr };\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto xuid = user.Xuid();\n    auto graphIter{ m_graphs.find(xuid) };\n    if (graphIter == m_graphs.end())\n    {\n        LOGS_ERROR << \"User \" << user.Xuid() << \" was not added to SocialManager\";\n        return E_UNEXPECTED;\n    }\n    graph = std::move(graphIter->second);\n    m_graphs.erase(graphIter);\n\n    // Ensure lifetime of User object since it is referenced in returned events\n    m_removedUsersLifetime.push_back(graph->LocalUser());\n\n    // When a user is removed, also destroy any groups associated with the user\n    for (auto iter = m_groups.begin(); iter != m_groups.end();)\n    {\n        if (iter->second->LocalUser()->Xuid() == user.Xuid())\n        {\n            iter = m_groups.erase(iter);\n        }\n        else\n        {\n            ++iter;\n        }\n    }\n\n    return S_OK;\n}\n\nResult<std::shared_ptr<XblSocialManagerUserGroup>> SocialManager::CreateUserGroup(\n    const User& user,\n    XblPresenceFilter presenceFilter,\n    XblRelationshipFilter relationshipFilter\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto graphIter = m_graphs.find(user.Xuid());\n    if (graphIter == m_graphs.end())\n    {\n        LOGS_ERROR << \"Add user \" << user.Xuid() << \" to SocialManager before creating a user group for them\";\n        return E_UNEXPECTED;\n    }\n\n    auto group = XblSocialManagerUserGroup::Make(graphIter->second, presenceFilter, relationshipFilter);\n    m_groups[group.get()] = group;\n    return group;\n}\n\nResult<std::shared_ptr<XblSocialManagerUserGroup>> SocialManager::CreateUserGroup(\n    const xbox::services::User& user,\n    Vector<uint64_t>&& trackedUsers\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto graphIter = m_graphs.find(user.Xuid());\n    if (graphIter == m_graphs.end())\n    {\n        LOGS_ERROR << \"Add user \" << user.Xuid() << \" to SocialManager before creating a user group for them\";\n        return E_UNEXPECTED;\n    }\n\n    auto group = XblSocialManagerUserGroup::Make(graphIter->second, std::move(trackedUsers));\n    m_groups[group.get()] = group;\n    return group;\n}\n\nstd::shared_ptr<XblSocialManagerUserGroup> SocialManager::GetUserGroup(\n    XblSocialManagerUserGroupHandle groupHandle\n) const\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto groupIter = m_groups.find(groupHandle);\n    if (groupIter == m_groups.end())\n    {\n        LOGS_ERROR << \"Group is not valid. It was destroyed with XblSocialManagerDestroyUserGroup or the associated local user was removed.\";\n        return nullptr;\n    }\n\n    return groupIter->second;\n}\n\nHRESULT SocialManager::DestroyUserGroup(\n    XblSocialManagerUserGroupHandle groupHandle\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto groupIter = m_groups.find(groupHandle);\n    if (groupIter == m_groups.end())\n    {\n        LOGS_ERROR << \"Group handle provided is invalid.\";\n        return E_FAIL;\n    }\n\n    auto xuid{ groupIter->second->LocalUser()->Xuid() };\n    auto graphIter = m_graphs.find(xuid);\n    if (graphIter == m_graphs.end())\n    {\n        LOGS_ERROR << \"Add user \" << xuid << \" to SocialManager before creating a user group for them\";\n        return E_UNEXPECTED;\n    }\n\n    graphIter->second->UnregisterGroup(groupIter->second);\n    m_groups.erase(groupHandle);\n\n    return S_OK;\n}\n\nconst Vector<XblSocialManagerEvent>& SocialManager::DoWork() noexcept\n{\n    PERF_START();\n    std::unique_lock<std::mutex> eventsLock{ m_eventsMutex };\n\n    m_events.clear();\n    m_affectedUsersLifetime.clear();\n    m_removedUsersLifetime.clear();\n\n    // For performance reasons, don't wait for the graph mutex if another thread holds it.\n    std::unique_lock<std::mutex> graphLock{ m_mutex, std::defer_lock };\n    if (graphLock.try_lock())\n    {\n        for (auto& pair : m_graphs)\n        {\n            pair.second->DoWork(m_events, m_affectedUsersLifetime);\n        }\n    }\n\n    PERF_STOP();\n    return m_events;\n}\n\nHRESULT SocialManager::SetRichPresencePolling(\n    const User& user,\n    bool enabled\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    auto graphIter = m_graphs.find(user.Xuid());\n    if (graphIter == m_graphs.end())\n    {\n        LOGS_ERROR << \"Add user \" << user.Xuid() << \" to SocialManager before creating a user group for them\";\n        return E_UNEXPECTED;\n    }\n\n    graphIter->second->SetRichPresencePolling(enabled);\n    return S_OK;\n}\n\nsize_t SocialManager::LocalUserCount() const noexcept\n{\n    return m_graphs.size();\n}\n\nHRESULT SocialManager::GetLocalUsers(\n    _In_ size_t usersCount,\n    _Out_writes_(usersCount) XblUserHandle* users\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(usersCount < m_graphs.size());\n    RETURN_HR_INVALIDARGUMENT_IF(users == nullptr && usersCount > 0);\n\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    size_t index{ 0 };\n    for (auto& pair : m_graphs)\n    {\n        users[index++] = pair.second->LocalUser()->Handle();\n    }\n    return S_OK;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END"
  },
  {
    "path": "Source/Services/Social/Manager/social_manager_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_manager_internal.h\"\n#include \"social_manager_user_group.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::social::manager;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\ntemplate<typename Ret, typename TWork>\nRet ApiImpl(Ret&& fallbackReturnValue, TWork&& work) noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (!state)\n    {\n        return fallbackReturnValue;\n    }\n\n    assert(state->SocialManager());\n    return work(*state->SocialManager());\n}\n\ntemplate<typename TWork>\nHRESULT ApiImpl(TWork&& work) noexcept\n{\n    return ApiImpl<HRESULT, TWork>(E_XBL_NOT_INITIALIZED, std::move(work));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END\n\nSTDAPI_(bool) XblSocialManagerPresenceRecordIsUserPlayingTitle(\n    _In_ const XblSocialManagerPresenceRecord* presenceRecord,\n    _In_ uint32_t titleId\n) XBL_NOEXCEPT\ntry\n{\n    if (presenceRecord == nullptr ||\n        presenceRecord->userState == XblPresenceUserState::Offline ||\n        presenceRecord->userState == XblPresenceUserState::Unknown)\n    {\n        return false;\n    }\n\n    for (uint32_t i = 0; i < presenceRecord->presenceTitleRecordCount; ++i)\n    {\n        if (presenceRecord->presenceTitleRecords[i].titleId == titleId)\n        {\n            return true;\n        }\n    }\n    return false;\n}\nCATCH_RETURN_WITH(false);\n\nSTDAPI XblSocialManagerUserGroupGetType(\n    _In_ XblSocialManagerUserGroupHandle groupHandle,\n    _Out_ XblSocialUserGroupType* type\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n    {\n        RETURN_HR_INVALIDARGUMENT_IF(groupHandle == nullptr || type == nullptr);\n\n        auto group{ socialManager.GetUserGroup(groupHandle) };\n        if (!group)\n        {\n            return E_UNEXPECTED;\n        }\n\n        *type = group->type;\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerUserGroupGetLocalUser(\n    _In_ XblSocialManagerUserGroupHandle groupHandle,\n    _Out_ XblUserHandle* localUser\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n    {\n        RETURN_HR_INVALIDARGUMENT_IF(groupHandle == nullptr || localUser == nullptr);\n\n        auto group{ socialManager.GetUserGroup(groupHandle) };\n        if (!group)\n        {\n            return E_UNEXPECTED;\n        }\n\n        *localUser = group->LocalUser()->Handle();\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerUserGroupGetFilters(\n    _In_ XblSocialManagerUserGroupHandle groupHandle,\n    _Out_opt_ XblPresenceFilter* presenceFilter,\n    _Out_opt_ XblRelationshipFilter* relationshipFilter\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n    {\n        RETURN_HR_INVALIDARGUMENT_IF(groupHandle == nullptr);\n\n        auto group{ socialManager.GetUserGroup(groupHandle) };\n        if (!group || group->type != XblSocialUserGroupType::FilterType)\n        {\n            return E_UNEXPECTED;\n        }\n\n        if (presenceFilter)\n        {\n            *presenceFilter = group->presenceFilter;\n        }\n        if (relationshipFilter)\n        {\n            *relationshipFilter = group->relationshipFilter;\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerUserGroupGetUsers(\n    _In_ XblSocialManagerUserGroupHandle groupHandle,\n    _Outptr_result_maybenull_ XblSocialManagerUserPtrArray* users,\n    _Out_ size_t* usersCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(groupHandle == nullptr || users == nullptr || usersCount == nullptr);\n    *users = nullptr;\n    \n    return ApiImpl([&](SocialManager& socialManager)\n    {\n        auto group{ socialManager.GetUserGroup(groupHandle) };\n        if (!group)\n        {\n            *users = nullptr;\n            *usersCount = 0;\n            return E_UNEXPECTED;\n        }\n\n        auto& groupUsers = group->Users();\n        *users = groupUsers.data();\n        *usersCount = groupUsers.size();\n\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerUserGroupGetUsersTrackedByGroup(\n    _In_ XblSocialManagerUserGroupHandle groupHandle,\n    _Outptr_result_maybenull_ const uint64_t** trackedUsers,\n    _Out_ size_t* trackedUsersCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(groupHandle == nullptr || trackedUsers == nullptr || trackedUsersCount == nullptr);\n    *trackedUsers = nullptr;\n    \n    return ApiImpl([&](SocialManager& socialManager)\n    {\n        auto group{ socialManager.GetUserGroup(groupHandle) };\n        if (!group)\n        {\n            *trackedUsers = nullptr;\n            *trackedUsersCount = 0;\n            return E_UNEXPECTED;\n        }\n\n        const auto& groupTrackedUsers = group->TrackedUsers();\n        *trackedUsers = groupTrackedUsers.data();\n        *trackedUsersCount = groupTrackedUsers.size();\n\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerAddLocalUser(\n    _In_ XblUserHandle user,\n    _In_ XblSocialManagerExtraDetailLevel extraLevelDetail,\n    _In_opt_ XTaskQueueHandle queue\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(user == nullptr);\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n            return socialManager.AddLocalUser(wrapUserResult.ExtractPayload(), extraLevelDetail, TaskQueue::DeriveWorkerQueue(queue));\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerRemoveLocalUser(\n    _In_ XblUserHandle user\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(user);\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n            return socialManager.RemoveLocalUser(wrapUserResult.Payload());\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerDoWork(\n    _Outptr_result_maybenull_ const XblSocialManagerEvent** socialEvents,\n    _Out_ size_t* socialEventsCount\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(socialEvents);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(socialEvents);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(socialEventsCount);\n\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            auto& events = socialManager.DoWork();\n            *socialEvents = events.empty() ? nullptr : events.data();\n            *socialEventsCount = events.size();\n\n            return S_OK;\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerCreateSocialUserGroupFromFilters(\n    _In_ XblUserHandle user,\n    _In_ XblPresenceFilter presenceFilter,\n    _In_ XblRelationshipFilter relationshipFilter,\n    _Outptr_result_maybenull_ XblSocialManagerUserGroupHandle* group\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(group);\n\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || group == nullptr);\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n\n            auto result = socialManager.CreateUserGroup(wrapUserResult.Payload(), presenceFilter, relationshipFilter);\n            if (Succeeded(result))\n            {\n                *group = result.ExtractPayload().get();\n            }\n            return result.Hresult();\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerCreateSocialUserGroupFromList(\n    _In_ XblUserHandle user,\n    _In_ uint64_t* xuids,\n    _In_ size_t xuidsCount,\n    _Outptr_result_maybenull_ XblSocialManagerUserGroup** group\n) XBL_NOEXCEPT\ntry\n{\n    INIT_OUT_PTR_PARAM(group);\n\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || xuids == nullptr || xuidsCount <= 0 || xuidsCount > XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST || group == nullptr);\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n            \n            auto result = socialManager.CreateUserGroup(wrapUserResult.Payload(), Vector<uint64_t>(xuids, xuids + xuidsCount));\n            if (Succeeded(result))\n            {\n                *group = result.ExtractPayload().get();\n            }\n            return result.Hresult();\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerDestroySocialUserGroup(\n    _In_ XblSocialManagerUserGroupHandle groupHandle\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            RETURN_HR_INVALIDARGUMENT_IF_NULL(groupHandle);\n            return socialManager.DestroyUserGroup(groupHandle);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI_(size_t) XblSocialManagerGetLocalUserCount() XBL_NOEXCEPT\ntry\n{\n    return ApiImpl<size_t>(0, [](SocialManager& socialManager)\n        {\n            return socialManager.LocalUserCount();\n        });\n}\nCATCH_RETURN_WITH(0)\n\nSTDAPI XblSocialManagerGetLocalUsers(\n    _In_ size_t usersCount,\n    _Out_writes_(usersCount) XblUserHandle* users\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            return socialManager.GetLocalUsers(usersCount, users);\n        });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerUpdateSocialUserGroup(\n    _In_ XblSocialManagerUserGroupHandle group,\n    _In_ uint64_t* users,\n    _In_ size_t usersCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(group == nullptr || users == nullptr || usersCount <= 0 || usersCount > XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST);\n    return group->UpdateTrackedUsers(Vector<uint64_t>(users, users + usersCount));\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialManagerSetRichPresencePollingStatus(\n    _In_ XblUserHandle user,\n    _In_ bool shouldEnablePolling\n) XBL_NOEXCEPT\ntry\n{\n    return ApiImpl([&](SocialManager& socialManager)\n        {\n            auto wrapUserResult{ User::WrapHandle(user) };\n            RETURN_HR_IF_FAILED(wrapUserResult.Hresult());\n            return socialManager.SetRichPresencePolling(wrapUserResult.Payload(), shouldEnablePolling);\n        });\n}\nCATCH_RETURN()"
  },
  {
    "path": "Source/Services/Social/Manager/social_manager_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/social_manager_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n\nclass SocialManager : public std::enable_shared_from_this<SocialManager>\n{\npublic:\n    SocialManager() noexcept;\n\n    HRESULT AddLocalUser(\n        User&& user,\n        XblSocialManagerExtraDetailLevel detailLevel,\n        TaskQueue&& queue\n    ) noexcept;\n\n    HRESULT RemoveLocalUser(\n        const User& user\n    ) noexcept;\n\n    Result<std::shared_ptr<XblSocialManagerUserGroup>> CreateUserGroup(\n        const User& user,\n        XblPresenceFilter presenceFilter,\n        XblRelationshipFilter relationshipFilter\n    ) noexcept;\n\n    Result<std::shared_ptr<XblSocialManagerUserGroup>> CreateUserGroup(\n        const User& user,\n        Vector<uint64_t>&& trackedUsers\n    ) noexcept;\n\n    // Because group lifetime is managed by SocialManager (handles are not refCounted), this API\n    // is used to get a group if it is still valid.\n    std::shared_ptr<XblSocialManagerUserGroup> GetUserGroup(\n        XblSocialManagerUserGroupHandle groupHandle\n    ) const;\n\n    HRESULT DestroyUserGroup(\n        XblSocialManagerUserGroupHandle groupHandle\n    ) noexcept;\n\n    const Vector<XblSocialManagerEvent>& DoWork() noexcept;\n\n    HRESULT SetRichPresencePolling(\n        const User& user,\n        bool enabled\n    ) noexcept;\n\n    size_t LocalUserCount() const noexcept;\n\n    HRESULT GetLocalUsers(\n        _In_ size_t usersCount,\n        _Out_writes_(usersCount) XblUserHandle* users\n    ) const noexcept;\n\nprivate:\n    // Controls access to m_events, which is only be written during DoWork\n    mutable std::mutex m_eventsMutex;\n    // Controls access to all other state, which may be updated from non-UI threads and is read by UI-thread (DoWork)\n    mutable std::mutex m_mutex;\n\n    Vector<XblSocialManagerEvent> m_events;\n    // Maintain lifetime for local users and XblSocialManagerUsers referenced in m_events\n    Vector<std::shared_ptr<XblSocialManagerUser>> m_affectedUsersLifetime;\n    List<std::shared_ptr<User>> m_removedUsersLifetime;\n\n    UnorderedMap<uint64_t, std::shared_ptr<class SocialGraph>> m_graphs;\n\n    // Lifetime of groups is managed entirely by SocialManager (i.e. they are not refCounted). To maintain legacy\n    // behavior, when a local user is removed, clean up all their groups. If an API call is made on an invalid group,\n    // this map can be used to detect that.\n    UnorderedMap<XblSocialManagerUserGroupHandle, std::shared_ptr<XblSocialManagerUserGroup>> m_groups;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END\n"
  },
  {
    "path": "Source/Services/Social/Manager/social_manager_user_group.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_manager_user_group.h\"\n#include \"perf_tester.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::social::manager;\n\nXblSocialManagerUserGroup::XblSocialManagerUserGroup(\n    std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n    XblPresenceFilter _presenceFilter,\n    XblRelationshipFilter _relationshipFilter\n) noexcept :\n    type{ XblSocialUserGroupType::FilterType },\n    presenceFilter{ _presenceFilter },\n    relationshipFilter{ _relationshipFilter },\n    m_localUser{ socialGraph->LocalUser() },\n    m_graph{ socialGraph }\n{\n}\n\nXblSocialManagerUserGroup::XblSocialManagerUserGroup(\n    std::shared_ptr<SocialGraph> socialGraph,\n    Vector<uint64_t>&& trackedUsers\n) noexcept :\n    type{ XblSocialUserGroupType::UserListType },\n    m_localUser{ socialGraph->LocalUser() },\n    m_graph{ socialGraph },\n    m_trackedUsersView{ std::move(trackedUsers) },\n    m_trackedUsers{ m_trackedUsersView.begin(), m_trackedUsersView.end() }\n{\n    m_usersView.reserve(m_trackedUsersView.size());\n    socialGraph->TrackUsers(m_trackedUsersView);\n}\n\nXblSocialManagerUserGroup::~XblSocialManagerUserGroup() noexcept\n{\n    auto graph{ m_graph.lock() };\n    if (graph && type == XblSocialUserGroupType::UserListType )\n    {\n        graph->StopTrackingUsers(m_trackedUsersView);\n    }\n}\n\nstd::shared_ptr<XblSocialManagerUserGroup> XblSocialManagerUserGroup::Make(\n    std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n    XblPresenceFilter presenceFilter,\n    XblRelationshipFilter relationshipFilter\n) noexcept\n{\n    auto group = std::shared_ptr<XblSocialManagerUserGroup>(\n        new (Alloc(sizeof(XblSocialManagerUserGroup))) XblSocialManagerUserGroup{ socialGraph, presenceFilter, relationshipFilter },\n        Deleter<XblSocialManagerUserGroup>(),\n        Allocator<XblSocialManagerUserGroup>()\n        );\n    socialGraph->RegisterGroup(group);\n    return group;\n}\n\nstd::shared_ptr<XblSocialManagerUserGroup> XblSocialManagerUserGroup::Make(\n    std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n    Vector<uint64_t>&& trackedUsers\n) noexcept\n{\n    auto group = std::shared_ptr<XblSocialManagerUserGroup>(\n        new (Alloc(sizeof(XblSocialManagerUserGroup))) XblSocialManagerUserGroup{ socialGraph, std::move(trackedUsers) },\n        Deleter<XblSocialManagerUserGroup>(),\n        Allocator<XblSocialManagerUserGroup>()\n        );\n    socialGraph->RegisterGroup(group);\n    return group;\n}\n\nvoid XblSocialManagerUserGroup::Initialize(const UnorderedMap<uint64_t, std::shared_ptr<XblSocialManagerUser>>& graphSnapshot) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    switch (type)\n    {\n    case XblSocialUserGroupType::FilterType:\n    {\n        for (auto& pair : graphSnapshot)\n        {\n            if (IsMemberOfGroup(pair.second.get()))\n            {\n                m_users[pair.first] = pair.second.get();\n            }\n        }\n        // Do allocations for view structures now, but don't actually populate them until they\n        // are requested.\n        m_usersView.reserve(m_users.size());\n        m_trackedUsersView.reserve(m_users.size());\n        break;\n    }\n    case XblSocialUserGroupType::UserListType:\n    {\n        for (auto& xuid : m_trackedUsers)\n        {\n            auto graphIter{ graphSnapshot.find(xuid) };\n            if (graphIter != graphSnapshot.end())\n            {\n                m_users[xuid] = graphIter->second.get();\n            }\n        }\n        break;\n    }\n    default:\n    {\n        assert(false);\n    }\n    }\n}\n\nvoid XblSocialManagerUserGroup::DoWork(\n    _Inout_ Vector<XblSocialManagerEvent>& events\n) noexcept\n{\n    PERF_START();\n    std::lock_guard<std::mutex> lock{ m_mutex };\n\n    // Update users based on graph events\n    for (auto& event : events)\n    {\n        switch (event.eventType)\n        {\n        case XblSocialManagerEventType::ProfilesChanged:\n        case XblSocialManagerEventType::SocialRelationshipsChanged:\n        case XblSocialManagerEventType::PresenceChanged:\n        case XblSocialManagerEventType::UsersAddedToSocialGraph:\n        {\n            for (uint8_t i = 0; i < std::extent<decltype(event.usersAffected)>::value && event.usersAffected[i]; ++i)\n            {\n                if (IsMemberOfGroup(event.usersAffected[i]))\n                {\n                    m_users[event.usersAffected[i]->xboxUserId] = event.usersAffected[i];\n                }\n                else\n                {\n                    m_users.erase(event.usersAffected[i]->xboxUserId);\n                }\n            }\n            break;\n        }\n        case XblSocialManagerEventType::UsersRemovedFromSocialGraph:\n        {\n            for (uint8_t i = 0; i < std::extent<decltype(event.usersAffected)>::value && event.usersAffected[i]; ++i)\n            {\n                m_users.erase(event.usersAffected[i]->xboxUserId);\n            }\n            break;\n        }\n        default:\n        {\n            // We don't care about other types of events\n            break;\n        }\n        }\n    }\n\n    // Generate loaded event if needed\n    if (!m_loaded)\n    {\n        switch (type)\n        {\n        case XblSocialUserGroupType::FilterType:\n        {\n            // Because all followed users are automatically in the SocialGraph, Filter groups are loaded \n            // as soon as initialization has completed\n            events.push_back(XblSocialManagerEvent{\n                m_localUser->Handle(),\n                XblSocialManagerEventType::SocialUserGroupLoaded,\n                S_OK,\n                this\n            });\n\n            m_loaded = true;\n            break;\n        }\n        case XblSocialUserGroupType::UserListType:\n        {\n            // List groups are loaded when the users they track have been added to the SocialGraph\n            if (m_users.size() == m_trackedUsers.size())\n            {\n                events.push_back(XblSocialManagerEvent{\n                    m_localUser->Handle(),\n                    m_updated ? XblSocialManagerEventType::SocialUserGroupUpdated : XblSocialManagerEventType::SocialUserGroupLoaded,\n                    S_OK,\n                    this\n                });\n\n                m_loaded = true;\n            }\n            break;\n        }\n        }\n    }\n    PERF_STOP();\n}\n\nconst Vector<const XblSocialManagerUser*>& XblSocialManagerUserGroup::Users() noexcept\n{\n    PERF_START();\n    std::unique_lock<std::mutex> lock{ m_mutex };\n    m_usersView.clear();\n    if (m_loaded)\n    {\n        std::transform(m_users.begin(), m_users.end(), std::back_inserter(m_usersView), [](const auto& pair)\n        {\n            return pair.second;\n        });\n    }\n    PERF_STOP();\n    return m_usersView;\n}\n\nconst Vector<uint64_t>& XblSocialManagerUserGroup::TrackedUsers() noexcept\n{\n    PERF_START();\n    std::unique_lock<std::mutex> lock{ m_mutex };\n    if (m_loaded)\n    {\n        switch (type)\n        {\n        case XblSocialUserGroupType::FilterType:\n        {\n            m_trackedUsersView.clear();\n            std::transform(m_users.begin(), m_users.end(), std::back_inserter(m_trackedUsersView), [](const auto& pair)\n                {\n                    return pair.first;\n                });\n            break;\n        }\n        case XblSocialUserGroupType::UserListType:\n        {\n            // Tracked users view is static\n            break;\n        }\n        }\n    }\n    else\n    {\n        m_trackedUsersView.clear();\n    }\n    PERF_STOP();\n    return m_trackedUsersView;\n}\n\nstd::shared_ptr<User> XblSocialManagerUserGroup::LocalUser() const noexcept\n{\n    return m_localUser;\n}\n\nHRESULT XblSocialManagerUserGroup::UpdateTrackedUsers(\n    Vector<uint64_t>&& trackedUsers\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n    auto graph{ m_graph.lock() };\n    assert(graph);\n\n    switch (type)\n    {\n    case XblSocialUserGroupType::FilterType:\n    {\n        LOGS_ERROR << \"Can't update tracked users for XblSocialUserGroupType::FilterType\";\n        return E_UNEXPECTED;\n    }\n    case XblSocialUserGroupType::UserListType:\n    {\n        // Track new users before untracking old users to avoid users being removed from and\n        // then immediately readded to the graph.\n        graph->TrackUsers(trackedUsers);\n        graph->StopTrackingUsers(m_trackedUsersView);\n\n        m_trackedUsersView = trackedUsers;\n        m_trackedUsers.clear();\n        m_trackedUsers.insert(m_trackedUsersView.begin(), m_trackedUsersView.end());\n        m_users.clear();\n\n        // Register again to retrigger initialization\n        graph->RegisterGroup(shared_from_this());\n\n        m_loaded = false;\n        m_updated = true;\n        return S_OK;\n    }\n    default:\n    {\n        assert(false);\n        return S_OK;\n    }\n    }\n}\n\nbool XblSocialManagerUserGroup::IsMemberOfGroup(XblSocialManagerUser const* user) const noexcept\n{\n    switch (type)\n    {\n    case XblSocialUserGroupType::FilterType:\n    {\n        if ((relationshipFilter == XblRelationshipFilter::Friends && !user->isFollowedByCaller) ||\n            (relationshipFilter == XblRelationshipFilter::Favorite && !user->isFavorite))\n        {\n            return false;\n        }\n\n        switch (presenceFilter)\n        {\n        case XblPresenceFilter::All:\n        {\n            return true;\n        }\n        case XblPresenceFilter::AllOffline:\n        {\n            return user->presenceRecord.userState == XblPresenceUserState::Offline;\n        }\n        case XblPresenceFilter::AllOnline:\n        {\n            return user->presenceRecord.userState == XblPresenceUserState::Online;\n        }\n        case XblPresenceFilter::AllTitle:\n        {\n            return user->titleHistory.hasUserPlayed;\n        }\n        case XblPresenceFilter::TitleOffline:\n        {\n            return user->titleHistory.hasUserPlayed && user->presenceRecord.userState == XblPresenceUserState::Offline;\n        }\n        case XblPresenceFilter::TitleOnline:\n        {\n            return XblSocialManagerPresenceRecordIsUserPlayingTitle(&user->presenceRecord, AppConfig::Instance()->TitleId());\n        }\n        case XblPresenceFilter::TitleOnlineOutsideTitle:\n        {\n            return user->titleHistory.hasUserPlayed &&\n                user->presenceRecord.userState == XblPresenceUserState::Online &&\n                !XblSocialManagerPresenceRecordIsUserPlayingTitle(&user->presenceRecord, AppConfig::Instance()->TitleId());\n        }\n        default:\n        {\n            return false;\n        }\n        }\n        return true;\n    }\n    case XblSocialUserGroupType::UserListType:\n    {\n        return m_trackedUsers.find(user->xboxUserId) != m_trackedUsers.end();\n    }\n    default:\n    {\n        assert(false);\n        return false;\n    }\n    }\n}\n"
  },
  {
    "path": "Source/Services/Social/Manager/social_manager_user_group.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"social_graph.h\"\n\n#pragma once\n\n// An XblSocialManagerUserGroup is a projection of a local user's SocialGraph.\n// It can be created as either a filtered set of the local user's followees or from a list of remote XboxLive user xuids.\nstruct XblSocialManagerUserGroup : public std::enable_shared_from_this<XblSocialManagerUserGroup>\n{\npublic:\n    // Creates a user group and registers it with the local user's underlying SocialGraph\n    static std::shared_ptr<XblSocialManagerUserGroup> Make(\n        std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n        XblPresenceFilter presenceFilter,\n        XblRelationshipFilter relationshipFilter\n    ) noexcept;\n\n    static std::shared_ptr<XblSocialManagerUserGroup> Make(\n        std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n        Vector<uint64_t>&& trackedUsers\n    ) noexcept;\n\n    ~XblSocialManagerUserGroup() noexcept;\n\n    // Initializes the group based on the current state of the SocialGraph.\n    void Initialize(const UnorderedMap<uint64_t, std::shared_ptr<XblSocialManagerUser>>& profiles) noexcept;\n\n    // Updates user and tracked user list based on graph changes since last DoWork call.\n    // Input events vector contains events generated by graph changes since the previous DoWork call.\n    // Output events vector will also contain SocialUserGroupLoaded/Updated events if applicable.\n    void DoWork(_Inout_ Vector<XblSocialManagerEvent>& events) noexcept;\n\n    // Properties of the group\n    XblSocialUserGroupType const type;\n    XblPresenceFilter const presenceFilter{ XblPresenceFilter::Unknown };\n    XblRelationshipFilter const relationshipFilter{ XblRelationshipFilter::Unknown };\n\n    // Public vector view of users tracked by the group.\n    // For Filter groups, this will be a filtered list of the Local user's full GraphView.\n    // For List groups, this will be fixed set of users.\n    const Vector<const XblSocialManagerUser*>& Users() noexcept;\n\n    // List of Xuids tracked by the group.\n    const Vector<uint64_t>& TrackedUsers() noexcept;\n\n    // Local user whose SocialGraph the group is backed by\n    std::shared_ptr<User> LocalUser() const noexcept;\n\n    // Updates the list of tracked Xuids. Only valid for List based groups.\n    HRESULT UpdateTrackedUsers(Vector<uint64_t>&& newUserList) noexcept;\n\nprivate:\n    XblSocialManagerUserGroup(\n        std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n        XblPresenceFilter presenceFilter,\n        XblRelationshipFilter relationshipFilter\n    ) noexcept;\n\n    XblSocialManagerUserGroup(\n        std::shared_ptr<xbox::services::social::manager::SocialGraph> socialGraph,\n        Vector<uint64_t>&& trackedUsers\n    ) noexcept;\n\n    bool IsMemberOfGroup(XblSocialManagerUser const* user) const noexcept;\n\n    std::shared_ptr<User> m_localUser;\n    std::weak_ptr<xbox::services::social::manager::SocialGraph> m_graph;\n\n    // Public views of users/trackedUesrs\n    Vector<const XblSocialManagerUser*> m_usersView;\n    Vector<uint64_t> m_trackedUsersView;\n\n    UnorderedMap<uint64_t, XblSocialManagerUser const*> m_users;\n    UnorderedSet<uint64_t> m_trackedUsers;\n\n    bool m_loaded{ false };\n    bool m_updated{ false };\n\n    mutable std::mutex m_mutex;\n};"
  },
  {
    "path": "Source/Services/Social/profile_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/profile_c.h\"\n#include \"profile_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\nusing namespace xbox::services::social;\n\nSTDAPI XblProfileGetUserProfileAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    return XblProfileGetUserProfilesAsync(xboxLiveContextHandle, &xboxUserId, 1, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfilesAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || xboxUserIds == nullptr || xboxUserIdsCount == 0 || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            xuids = xsapi_internal_vector<uint64_t>(xboxUserIds, xboxUserIds + xboxUserIdsCount),\n            profiles = xsapi_internal_vector<XblUserProfile>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->ProfileService()->GetUserProfiles(\n                std::move(xuids),\n                AsyncContext<Result<xsapi_internal_vector<XblUserProfile>>>{\n                data->async->queue,\n                    [\n                        &profiles,\n                        asyncBlock{ data->async }\n                    ]\n                (Result<xsapi_internal_vector<XblUserProfile>> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        profiles = result.ExtractPayload();\n                    }\n                    XAsyncComplete(asyncBlock, result.Hresult(), profiles.size() * sizeof(XblUserProfile));\n                }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto profilesPtr = static_cast<XblUserProfile*>(data->buffer);\n            for (auto& profile : profiles)\n            {\n                *profilesPtr++ = profile;\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfilesForSocialGroupAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_z_ const char* socialGroup,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || socialGroup == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            group = xsapi_internal_string{ socialGroup },\n            profiles = xsapi_internal_vector<XblUserProfile>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->ProfileService()->GetUserProfilesForSocialGroup(\n                std::move(group),\n                AsyncContext<Result<xsapi_internal_vector<XblUserProfile>>>{\n                data->async->queue,\n                    [\n                        &profiles,\n                        asyncBlock{ data->async }\n                    ]\n                (Result<xsapi_internal_vector<XblUserProfile>> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        profiles = result.ExtractPayload();\n                    }\n                    XAsyncComplete(asyncBlock, result.Hresult(), profiles.size() * sizeof(XblUserProfile));\n                }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto profilesPtr = static_cast<XblUserProfile*>(data->buffer);\n            for (auto& profile : profiles)\n            {\n                *profilesPtr++ = profile;\n            }\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfilesResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* profileCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || profileCount == nullptr);\n\n    size_t bufferSize;\n    auto hr = XAsyncGetResultSize(async, &bufferSize);\n\n    if (SUCCEEDED(hr))\n    {\n        *profileCount = bufferSize / sizeof(XblUserProfile);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfileResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblUserProfile* profile\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblUserProfile), profile, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfilesResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t profilesCount,\n    _Out_writes_(profilesCount) XblUserProfile* profiles\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_IF(profilesCount == 0, S_OK);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(async);\n\n    size_t actualProfilesCount = 0;\n    auto hr = XblProfileGetUserProfilesResultCount(async, &actualProfilesCount);\n    if (SUCCEEDED(hr))\n    {\n        RETURN_HR_INVALIDARGUMENT_IF(actualProfilesCount > profilesCount);\n    }\n\n    hr = XAsyncGetResult(async, nullptr, profilesCount * sizeof(XblUserProfile), profiles, nullptr);\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfilesForSocialGroupResultCount(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* profileCount\n) XBL_NOEXCEPT\ntry\n{\n    return XblProfileGetUserProfilesResultCount(async, profileCount);\n}\nCATCH_RETURN()\n\nSTDAPI XblProfileGetUserProfilesForSocialGroupResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t profilesCount,\n    _Out_writes_(profilesCount) XblUserProfile* profiles\n) XBL_NOEXCEPT\ntry\n{\n    return XblProfileGetUserProfilesResult(async, profilesCount, profiles);\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Social/profile_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/profile_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nclass ProfileService : public std::enable_shared_from_this<ProfileService>\n{\npublic:\n    ProfileService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<AppConfig> appConfig\n    ) noexcept;\n\n    HRESULT GetUserProfiles(\n        _In_ xsapi_internal_vector<uint64_t>&& xuids,\n        _In_ AsyncContext<Result<xsapi_internal_vector<XblUserProfile>>> async\n    ) const noexcept;\n\n    HRESULT GetUserProfilesForSocialGroup(\n        _In_ xsapi_internal_string&& socialGroup,\n        _In_ AsyncContext<Result<xsapi_internal_vector<XblUserProfile>>> async\n    ) const noexcept;\n\nprivate:\n    static Result<xsapi_internal_vector<XblUserProfile>> DeserializeUserProfiles(\n        _In_ const JsonValue& json\n    ) noexcept;\n\n    static Result<XblUserProfile> DeserializeUserProfile(\n        _In_ const JsonValue& json\n    ) noexcept;\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<xbox::services::AppConfig> m_appConfig;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Source/Services/Social/profile_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"profile_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nusing namespace xbox::services;\n\nstatic const char* s_settings[] = {\n    \"AppDisplayName\",\n    \"AppDisplayPicRaw\",\n    \"GameDisplayName\",\n    \"GameDisplayPicRaw\",\n    \"Gamerscore\",\n    \"Gamertag\",\n    \"ModernGamertag\",\n    \"ModernGamertagSuffix\",\n    \"UniqueModernGamertag\"\n};\n\nProfileService::ProfileService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<AppConfig> appConfig\n) noexcept :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings{ std::move(xboxLiveContextSettings) },\n    m_appConfig{ std::move(appConfig) }\n{\n}\n\nHRESULT ProfileService::GetUserProfiles(\n    _In_ xsapi_internal_vector<uint64_t>&& xuids,\n    _In_ AsyncContext<Result<xsapi_internal_vector<XblUserProfile>>> async\n) const noexcept\n{\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"profile\", \"/users/batch/profile/settings\"),\n        xbox_live_api::get_user_profiles\n    ));\n\n    httpCall->SetHeader(CONTRACT_VERSION_HEADER, \"2\");\n\n    JsonDocument request(rapidjson::kObjectType);\n    JsonValue userIdsJson(rapidjson::kArrayType);\n    JsonUtils::SerializeVector<uint64_t>(JsonUtils::JsonXuidSerializer, xuids, userIdsJson, request.GetAllocator());\n    request.AddMember(\"userIds\", userIdsJson, request.GetAllocator());\n\n    JsonValue settingsArray(rapidjson::kArrayType);\n    for (size_t i = 0; i < ARRAYSIZE(s_settings); ++i)\n    {\n        settingsArray.PushBack(JsonValue(s_settings[i], request.GetAllocator()).Move(), request.GetAllocator());\n    }\n    request.AddMember(\"settings\", settingsArray, request.GetAllocator());\n\n    httpCall->SetRequestBody(request);\n\n    return httpCall->Perform({\n        async.Queue(),\n        [\n            async\n        ]\n    (HttpResult result)\n    {\n        HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n        return async.Complete(DeserializeUserProfiles(result.Payload()->GetResponseBodyJson()));\n    } });\n}\n\nHRESULT ProfileService::GetUserProfilesForSocialGroup(\n    _In_ xsapi_internal_string&& socialGroup,\n    _In_ AsyncContext<Result<xsapi_internal_vector<XblUserProfile>>> async\n) const noexcept\n{\n    xsapi_internal_stringstream pathAndQuery;\n    pathAndQuery << \"/users/me/profile/settings/people/\";\n    pathAndQuery << socialGroup;\n    pathAndQuery << \"?settings=\";\n\n    for (uint32_t i = 0; i < ARRAYSIZE(s_settings); ++i)\n    {\n        if (i > 0)\n        {\n            pathAndQuery << \",\";\n        }\n        pathAndQuery << s_settings[i];\n    }\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"profile\", pathAndQuery.str()),\n        xbox_live_api::get_user_profiles_for_social_group\n    ));\n\n    httpCall->SetHeader(CONTRACT_VERSION_HEADER, \"2\");\n\n    return httpCall->Perform({\n        async.Queue(),\n        [\n            async\n        ]\n    (HttpResult result)\n    {\n        HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n        return async.Complete(DeserializeUserProfiles(result.Payload()->GetResponseBodyJson()));\n    } });\n}\n\nResult<xsapi_internal_vector<XblUserProfile>> ProfileService::DeserializeUserProfiles(\n    _In_ const JsonValue& json\n) noexcept\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    HRESULT errc = S_OK;\n    xsapi_internal_vector<XblUserProfile> profilesVector;\n    RETURN_HR_IF_FAILED( JsonUtils::ExtractJsonVector<XblUserProfile>(\n        DeserializeUserProfile,\n        json,\n        \"profileUsers\",\n        profilesVector,\n        true\n        ));\n\n    return Result<xsapi_internal_vector<XblUserProfile>>{ profilesVector, errc };\n}\n\nResult<XblUserProfile> ProfileService::DeserializeUserProfile(\n    _In_ const JsonValue& json\n) noexcept\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    XblUserProfile profile{};\n\n    HRESULT errc = S_OK;\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(json, \"id\", profile.xboxUserId, true));\n\n    if (json.IsObject() && json.HasMember(\"settings\"))\n    {\n        const JsonValue& settingsJson = json[\"settings\"];\n        if(settingsJson.IsArray())\n        for (const auto& setting : settingsJson.GetArray())\n        {\n            xsapi_internal_string id;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(setting, \"id\", id, true));\n            xsapi_internal_string value;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(setting, \"value\", value, true));\n\n            if (id == \"AppDisplayName\")\n            {\n                utils::strcpy(profile.appDisplayName, sizeof(profile.appDisplayName), value.data());\n            }\n            else if (id == \"AppDisplayPicRaw\")\n            {\n                utils::strcpy(profile.appDisplayPictureResizeUri, sizeof(profile.appDisplayPictureResizeUri), value.data());\n            }\n            else if (id == \"GameDisplayName\")\n            {\n                utils::strcpy(profile.gameDisplayName, sizeof(profile.gameDisplayName), value.data());\n            }\n            else if (id == \"GameDisplayPicRaw\")\n            {\n                utils::strcpy(profile.gameDisplayPictureResizeUri, sizeof(profile.gameDisplayPictureResizeUri), value.data());\n            }\n            else if (id == \"Gamerscore\")\n            {\n                utils::strcpy(profile.gamerscore, sizeof(profile.gamerscore), value.data());\n            }\n            else if (id == \"Gamertag\")\n            {\n                utils::strcpy(profile.gamertag, sizeof(profile.gamertag), value.data());\n            }\n            else if (id == \"ModernGamertag\")\n            {\n                utils::strcpy(profile.modernGamertag, sizeof(profile.modernGamertag), value.data());\n            }\n            else if (id == \"ModernGamertagSuffix\")\n            {\n                utils::strcpy(profile.modernGamertagSuffix, sizeof(profile.modernGamertagSuffix), value.data());\n            }\n            else if (id == \"UniqueModernGamertag\")\n            {\n                utils::strcpy(profile.uniqueModernGamertag, sizeof(profile.uniqueModernGamertag), value.data());\n            }\n        }\n    }\n    else\n    {\n        //required\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return Result<XblUserProfile>{ std::move(profile), errc };\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Source/Services/Social/reputation_feedback_request.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_internal.h\"\n#include \"multiplayer_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nReputationFeedbackRequest::ReputationFeedbackRequest(\n    _In_ uint64_t xuid,\n    _In_ XblReputationFeedbackType feedbackType,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n    _In_z_ const char* reasonMessage,\n    _In_opt_z_ const char* evidenceResourceId\n)\n{\n    xsapi_internal_stringstream pathAndQuery;\n    pathAndQuery << \"/users/xuid(\" << xuid << \")/feedback\";\n    m_pathAndQuery = pathAndQuery.str();\n\n    m_requestBody.SetObject();\n    JsonDocument::AllocatorType& allocator = m_requestBody.GetAllocator();\n\n    if (sessionReference)\n    {\n        JsonValue sessionRefJson;\n        multiplayer::Serializers::SerializeSessionReference(*sessionReference, sessionRefJson, allocator);\n        m_requestBody.AddMember(\"sessionRef\", sessionRefJson, allocator);\n    }\n    else\n    {\n        m_requestBody.AddMember(\"sessionRef\", JsonValue(rapidjson::kNullType), allocator);\n    }\n    xsapi_internal_string feedbackTypeString = ReputationFeedbackTypeToString(feedbackType);\n    m_requestBody.AddMember(\"feedbackType\", JsonValue(feedbackTypeString.c_str(), allocator).Move(), allocator);\n    m_requestBody.AddMember(\"textReason\", JsonValue(reasonMessage, allocator).Move(), allocator);\n    \n    if (evidenceResourceId)\n    {\n        m_requestBody.AddMember(\"evidenceId\", JsonValue(evidenceResourceId, allocator).Move(), allocator);\n    }\n    else\n    {\n        m_requestBody.AddMember(\"evidenceId\", JsonValue(rapidjson::kNullType), allocator);\n    }\n}\n\nReputationFeedbackRequest::ReputationFeedbackRequest(\n    _In_ const XblReputationFeedbackItem* items,\n    _In_ size_t itemsCount\n) :\n    m_pathAndQuery{ \"/users/batchtitlefeedback\" }\n{\n    m_requestBody.SetObject();\n    JsonDocument::AllocatorType& allocator = m_requestBody.GetAllocator();\n\n    JsonValue itemArrayJson(rapidjson::kArrayType);\n    for (size_t i = 0; i < itemsCount; ++i)\n    {\n        // Example:\n        //\n        // \"targetXuid\": \"33445566778899\",\n        // \"titleId\" : \"6487\",\n        // \"sessionRef\" :\n        // {\n        //     \"scid\": \"1234-1234-471F-B696-07B61F09EC20\",\n        //     \"templateName\" : \"CaptureFlag5\",\n        //     \"name\" : \"Example556932\",\n        // },\n        // \"feedbackType\": \"FairPlayKillsTeammates\",\n        // \"textReason\" : \"Killed 19 team members in a single session\",\n        // \"evidenceId\" : null\n\n        JsonValue itemJson(rapidjson::kObjectType);\n        itemJson.AddMember(\"targetXuid\", JsonValue(utils::uint64_to_internal_string(items[i].xboxUserId).c_str(), allocator).Move(), allocator);\n        itemJson.AddMember(\"titleId\", JsonValue(rapidjson::kNullType), allocator);\n\n        if (items[i].sessionReference)\n        {\n            JsonValue sessionRefJson;\n            multiplayer::Serializers::SerializeSessionReference(*items[i].sessionReference, sessionRefJson, allocator);\n            itemJson.AddMember(\"sessionRef\", sessionRefJson, allocator);\n        }\n        else\n        {\n            itemJson.AddMember(\"sessionRef\", JsonValue(rapidjson::kNullType), allocator);\n        }\n        xsapi_internal_string feedbackTypeString = ReputationFeedbackTypeToString(items[i].feedbackType);\n        itemJson.AddMember(\"feedbackType\", JsonValue(feedbackTypeString.c_str(), allocator).Move(), allocator);\n        itemJson.AddMember(\"textReason\", JsonValue(items[i].reasonMessage, allocator).Move(), allocator);\n        if (items[i].evidenceResourceId)\n        {\n            itemJson.AddMember(\"evidenceId\", JsonValue(items[i].evidenceResourceId, allocator).Move(), allocator);\n        }\n        else\n        {\n            itemJson.AddMember(\"evidenceId\", JsonValue(rapidjson::kNullType), allocator);\n        }\n\n        itemArrayJson.PushBack(itemJson, allocator);\n    }\n\n    m_requestBody.AddMember(\"items\", itemArrayJson, allocator);\n}\n\nReputationFeedbackRequest::ReputationFeedbackRequest(const ReputationFeedbackRequest& other)\n{\n    m_pathAndQuery = other.m_pathAndQuery;\n    JsonUtils::CopyFrom(m_requestBody, other.m_requestBody);\n}\n\nconst xsapi_internal_string& ReputationFeedbackRequest::PathAndQuery() const noexcept\n{\n    return m_pathAndQuery;\n}\n\nconst JsonValue& ReputationFeedbackRequest::Body() const noexcept\n{\n    return m_requestBody;\n}\n\nxsapi_internal_string ReputationFeedbackRequest::ReputationFeedbackTypeToString(\n    XblReputationFeedbackType feedbackType\n)\n{\n    switch (feedbackType)\n    {\n        case XblReputationFeedbackType::FairPlayKillsTeammates: return \"FairPlayKillsTeammates\";\n        case XblReputationFeedbackType::FairPlayCheater: return \"FairPlayCheater\";\n        case XblReputationFeedbackType::FairPlayTampering: return \"FairPlayTampering\";\n        case XblReputationFeedbackType::FairPlayQuitter: return \"FairPlayQuitter\";\n        case XblReputationFeedbackType::FairPlayKicked : return \"FairPlayKicked\";\n        case XblReputationFeedbackType::CommunicationsInappropriateVideo: return \"CommsInappropriateVideo\";\n        case XblReputationFeedbackType::CommunicationsAbusiveVoice: return \"CommsAbusiveVoice\";\n        case XblReputationFeedbackType::InappropriateUserGeneratedContent: return \"UserContentInappropriateUGC\";\n        case XblReputationFeedbackType::PositiveSkilledPlayer: return \"PositiveSkilledPlayer\";\n        case XblReputationFeedbackType::PositiveHelpfulPlayer: return \"PositiveHelpfulPlayer\";\n        case XblReputationFeedbackType::PositiveHighQualityUserGeneratedContent: return \"PositiveHighQualityUGC\";\n        case XblReputationFeedbackType::CommsPhishing: return \"CommsPhishing\";\n        case XblReputationFeedbackType::CommsPictureMessage: return \"CommsPictureMessage\";\n        case XblReputationFeedbackType::CommsSpam: return \"CommsSpam\";\n        case XblReputationFeedbackType::CommsTextMessage: return \"CommsTextMessage\";\n        case XblReputationFeedbackType::CommsVoiceMessage: return \"CommsVoiceMessage\";\n        case XblReputationFeedbackType::FairPlayConsoleBanRequest: return \"FairPlayConsoleBanRequest\";\n        case XblReputationFeedbackType::FairPlayIdler: return \"FairPlayIdler\";\n        case XblReputationFeedbackType::FairPlayUserBanRequest: return \"FairPlayUserBanRequest\";\n        case XblReputationFeedbackType::UserContentGamerpic: return \"UserContentGamertag\";\n        case XblReputationFeedbackType::UserContentPersonalInfo: return \"UserContentPersonalInfo\";\n        case XblReputationFeedbackType::FairPlayUnsporting: return \"FairplayUnsporting\";\n        case XblReputationFeedbackType::FairPlayLeaderboardCheater: return \"FairplayLeaderboardCheater\";\n\n        default:\n        {\n            assert(false);\n            return xsapi_internal_string{};\n        }\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Source/Services/Social/reputation_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nReputationService::ReputationService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings\n) noexcept :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings{ std::move(xboxLiveContextSettings) }\n{\n}\n\nHRESULT ReputationService::SubmitFeedback(\n    const ReputationFeedbackRequest& request,\n    AsyncContext<HRESULT> async\n) const noexcept\n{\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"reputation\", request.PathAndQuery()),\n        xbox_live_api::submit_reputation_feedback\n    ));\n\n    httpCall->SetRetryAllowed(false);\n    httpCall->SetXblServiceContractVersion(101);\n    httpCall->SetRequestBody(request.Body());\n\n    return httpCall->Perform({ async.Queue(),\n        [async](HttpResult httpResult)\n        {\n            async.Complete(Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result());\n        }\n        });\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Source/Services/Social/social_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"real_time_activity_subscription.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::social;\n\nSTDAPI XblSocialGetSocialRelationshipsAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ uint64_t xuid,\n    _In_ XblSocialRelationshipFilter filter,\n    _In_ size_t startIndex,\n    _In_ size_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || async == nullptr);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            xuid,\n            filter,\n            startIndex,\n            maxItems,\n            socialRelationshipResult = std::shared_ptr<XblSocialRelationshipResult>{ nullptr }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->SocialService()->GetSocialRelationships(xuid, filter, startIndex, maxItems, {\n                data->async->queue,\n                [\n                    &socialRelationshipResult,\n                    asyncBlock{ data->async }\n                ]\n            (Result<std::shared_ptr<XblSocialRelationshipResult>> result)\n            {\n                if (Succeeded(result))\n                {\n                    socialRelationshipResult = result.ExtractPayload();\n                }\n                XAsyncComplete(asyncBlock, result.Hresult(), sizeof(XblSocialRelationshipResultHandle));\n            }\n            }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            auto resultHandle = static_cast<XblSocialRelationshipResultHandle*>(data->buffer);\n            socialRelationshipResult->AddRef();\n            *resultHandle = socialRelationshipResult.get();\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialGetSocialRelationshipsResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblSocialRelationshipResultHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblSocialRelationshipResultHandle), handle, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRelationshipResultGetRelationships(\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _Out_ const XblSocialRelationship** relationships,\n    _Out_ size_t* relationshipsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(resultHandle == nullptr || relationships == nullptr || relationshipsCount == nullptr);\n\n    *relationships = resultHandle->SocialRelationships().data();\n    *relationshipsCount = resultHandle->SocialRelationships().size();\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRelationshipResultHasNext(\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _Out_ bool* hasNext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(resultHandle == nullptr || hasNext == nullptr);\n    *hasNext = resultHandle->HasNext();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRelationshipResultGetTotalCount(\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _Out_ size_t* totalCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(resultHandle == nullptr || totalCount == nullptr);\n    *totalCount = resultHandle->TotalCount();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRelationshipResultGetNextAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblSocialRelationshipResultHandle resultHandle,\n    _In_ size_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || resultHandle == nullptr || async == nullptr);\n    return XblSocialGetSocialRelationshipsAsync(xboxLiveContext, xboxLiveContext->Xuid(), resultHandle->Filter, resultHandle->ContinuationSkip, maxItems, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRelationshipResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblSocialRelationshipResultHandle* handle\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblSocialRelationshipResultHandle), handle, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRelationshipResultDuplicateHandle(\n    _In_ XblSocialRelationshipResultHandle handle,\n    _Out_ XblSocialRelationshipResultHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || duplicatedHandle == nullptr);\n    handle->AddRef();\n    *duplicatedHandle = handle;\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblSocialRelationshipResultCloseHandle(\n    _In_ XblSocialRelationshipResultHandle handle\n) XBL_NOEXCEPT\ntry\n{\n    if (handle)\n    {\n        handle->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblSocialSubscribeToSocialRelationshipChange(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ uint64_t xuid,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(xboxLiveContext);\n    UNREFERENCED_PARAMETER(xuid);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(subscriptionHandle);\n    *subscriptionHandle = Make<XblRealTimeActivitySubscription>();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialUnsubscribeFromSocialRelationshipChange(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(xboxLiveContext);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(subscriptionHandle);\n    Delete(subscriptionHandle);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblSocialAddSocialRelationshipChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblSocialRelationshipChangedHandler handler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    // TODO really should be returning HRESULT E_INVALIDARG here\n    if (xboxLiveContext == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    return xboxLiveContext->SocialService()->AddSocialRelationshipChangedHandler(\n        [\n            handler,\n            context\n        ]\n    (const XblSocialRelationshipChangeEventArgs& args)\n    {\n        try\n        {\n            handler(&args, context);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRemoveSocialRelationshipChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext handlerFunctionContext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    xboxLiveContext->SocialService()->RemoveSocialRTAHandler(handlerFunctionContext);\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialAddFriendRequestCountChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblSocialIncomingFriendRequestCountChangedHandler handler,\n    _In_opt_ void* handlerContext,\n    _Out_ XblFunctionContext* handlerFunctionContext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(handler == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(handlerFunctionContext == nullptr);\n\n    *handlerFunctionContext = xboxLiveContext->SocialService()->AddFriendRequestCountChangedHandler(\n        [\n            handler,\n            handlerContext\n        ]\n        (const XblSocialFriendRequestCountChangedEventArgs& args)\n    {\n        try\n        {\n            handler(&args, handlerContext);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialRemoveFriendRequestCountChangedHandler(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblFunctionContext handlerFunctionContext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xboxLiveContext);\n    xboxLiveContext->SocialService()->RemoveSocialRTAHandler(handlerFunctionContext);\n    return S_OK;\n}\nCATCH_RETURN()\n\nHRESULT SubmitReputationFeedback(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ ReputationFeedbackRequest r,\n    _In_ XAsyncBlock* async\n)\n{\n    assert(async);\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            request{ std::move(r) }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->ReputationService()->SubmitFeedback(request, data->async));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\n\nSTDAPI XblSocialSubmitReputationFeedbackAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ uint64_t xuid,\n    _In_ XblReputationFeedbackType feedbackType,\n    _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n    _In_z_ const char* reasonMessage,\n    _In_opt_z_ const char* evidenceResourceId,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || reasonMessage == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return SubmitReputationFeedback(\n        xboxLiveContextHandle,\n        ReputationFeedbackRequest{ xuid, feedbackType, sessionReference, reasonMessage, evidenceResourceId },\n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblSocialSubmitBatchReputationFeedbackAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ const XblReputationFeedbackItem* feedbackItems,\n    _In_ size_t feedbackItemsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || feedbackItems == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return SubmitReputationFeedback(\n        xboxLiveContextHandle,\n        ReputationFeedbackRequest{ feedbackItems, feedbackItemsCount },\n        async\n    );\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Social/social_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/social_c.h\"\n#include \"real_time_activity_subscription.h\"\n#include \"string_array.h\"\n\nstruct XblSocialRelationshipResult : public xbox::services::RefCounter, public std::enable_shared_from_this<XblSocialRelationshipResult>\n{\npublic:\n    XblSocialRelationshipResult() noexcept = default;\n    XblSocialRelationshipResult(const XblSocialRelationshipResult&) = delete;\n    XblSocialRelationshipResult& operator=(XblSocialRelationshipResult) = delete;\n\n    static xbox::services::Result<std::shared_ptr<XblSocialRelationshipResult>> Deserialize(const JsonValue& json);\n\n    const xsapi_internal_vector<XblSocialRelationship>& SocialRelationships() const noexcept;\n\n    // Service paging metadata\n    bool HasNext() const noexcept;\n    size_t TotalCount() const noexcept;\n    size_t ContinuationSkip{ 0 };\n    XblSocialRelationshipFilter Filter{ XblSocialRelationshipFilter::All };\n\nprivate:\n    std::shared_ptr<RefCounter> GetSharedThis();\n\n    size_t m_totalCount{ 0 };\n    xsapi_internal_vector<XblSocialRelationship> m_socialRelationships;\n    xsapi_internal_vector<xbox::services::UTF8StringArray> m_socialNetworks;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nnamespace legacy\n{\n    class social_group_constants\n    {\n    public:\n        /// <summary>\n        /// Returns Favorites constant string\n        /// </summary>\n        static const char* favorite() { return \"Favorites\"; }\n\n        /// <summary>\n        /// Returns People constant string\n        /// </summary>\n        static const char* people() { return \"People\"; }\n    };\n}\n\ntypedef Callback<const XblSocialRelationshipChangeEventArgs&> SocialRelationshipChangedHandler;\ntypedef Callback<const XblSocialFriendRequestCountChangedEventArgs&> FriendRequestCountChangedHandler;\n\nclass SocialRelationshipChangeSubscription : public real_time_activity::Subscription\n{\npublic:\n    SocialRelationshipChangeSubscription(_In_ uint64_t xuid) noexcept;\n\n    XblFunctionContext AddHandler(SocialRelationshipChangedHandler handler) noexcept;\n    XblFunctionContext AddHandler(FriendRequestCountChangedHandler handler) noexcept;\n    size_t RemoveHandler(XblFunctionContext token) noexcept;\n\nprotected:\n    void OnEvent(const JsonValue& data) noexcept override;\n\nprivate:\n    uint64_t m_xuid;\n    Map<XblFunctionContext, SocialRelationshipChangedHandler> m_handlers;\n    Map<XblFunctionContext, FriendRequestCountChangedHandler> m_friendRequestCountChangedHandlers;\n    XblFunctionContext m_nextHandlerToken{ 1 };\n    mutable std::mutex m_lock;\n};\n\nclass SocialService : public std::enable_shared_from_this<SocialService>\n{\npublic:\n    SocialService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n    ) noexcept;\n\n    ~SocialService() noexcept;\n\n    XblFunctionContext AddSocialRelationshipChangedHandler(\n        _In_ SocialRelationshipChangedHandler handler\n    ) noexcept;\n\n    XblFunctionContext AddFriendRequestCountChangedHandler(\n        _In_ FriendRequestCountChangedHandler handler\n    ) noexcept;\n\n    void RemoveSocialRTAHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\n    HRESULT GetSocialRelationships(\n        _In_ uint64_t xuid,\n        _In_ XblSocialRelationshipFilter filter,\n        _In_ size_t startIndex,\n        _In_ size_t maxItems,\n        _In_ AsyncContext<Result<std::shared_ptr<XblSocialRelationshipResult>>> async\n    ) const noexcept;\n\nprivate:\n    static xsapi_internal_string SocialRelationshipFilterToString(\n        _In_ XblSocialRelationshipFilter filter\n    ) noexcept;\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n\n    std::shared_ptr<SocialRelationshipChangeSubscription> m_socialRelationshipChangedSubscription;\n    mutable std::mutex m_lock;\n};\n\nclass ReputationFeedbackRequest\n{\npublic:\n    ReputationFeedbackRequest(\n        _In_ uint64_t xuid,\n        _In_ XblReputationFeedbackType feedbackType,\n        _In_opt_ const XblMultiplayerSessionReference* sessionReference,\n        _In_z_ const char* reasonMessage,\n        _In_opt_z_ const char* evidenceResourceId\n    );\n\n    ReputationFeedbackRequest(\n        _In_ const XblReputationFeedbackItem* items,\n        _In_ size_t itemsCount\n    );\n\n    ReputationFeedbackRequest(const ReputationFeedbackRequest& other);\n\n    const xsapi_internal_string& PathAndQuery() const noexcept;\n\n    const JsonValue& Body() const noexcept;\n\n    static xsapi_internal_string ReputationFeedbackTypeToString(\n        XblReputationFeedbackType feedbackType\n    );\n\nprivate:\n    xsapi_internal_string m_pathAndQuery;\n    JsonDocument m_requestBody;\n};\n\nclass ReputationService : public std::enable_shared_from_this<ReputationService>\n{\npublic:\n    ReputationService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings\n    ) noexcept;\n\n    HRESULT SubmitFeedback(\n        const ReputationFeedbackRequest& request,\n        AsyncContext<HRESULT> async\n    ) const noexcept;\n\nprivate:\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Source/Services/Social/social_relationship_change_subscription.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nSocialRelationshipChangeSubscription::SocialRelationshipChangeSubscription(\n    _In_ uint64_t xuid\n) noexcept\n    : m_xuid{ xuid }\n{\n    Stringstream uri;\n    uri << \"http://social.xboxlive.com/users/xuid(\" << m_xuid << \")/friends\";\n    m_resourceUri = uri.str();\n}\n\nXblFunctionContext SocialRelationshipChangeSubscription::AddHandler(\n    SocialRelationshipChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n    m_handlers[m_nextHandlerToken] = std::move(handler);\n    return m_nextHandlerToken++;\n}\n\nXblFunctionContext SocialRelationshipChangeSubscription::AddHandler(\n    FriendRequestCountChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n    m_friendRequestCountChangedHandlers[m_nextHandlerToken] = std::move(handler);\n    return m_nextHandlerToken++;\n}\n\nsize_t SocialRelationshipChangeSubscription::RemoveHandler(\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n    m_handlers.erase(token);\n    m_friendRequestCountChangedHandlers.erase(token);\n    return m_handlers.size() + m_friendRequestCountChangedHandlers.size();\n}\n\nvoid SocialRelationshipChangeSubscription::OnEvent(\n    const JsonValue& data\n) noexcept\n{\n    // Payload format http://xboxwiki/wiki/RTA%3AEVENT#People\n    // [<API_ID>, <SUB_ID>, {\"NotificationType\":\"Added\",\"Xuids\":[\"2533274964271787\"]}]\n\n    String notificationTypeString;\n    XblSocialNotificationType notificationType;\n    Vector<uint64_t> xuids;\n\n    HRESULT hr = JsonUtils::ExtractJsonString(data, \"NotificationType\", notificationTypeString);\n    if (SUCCEEDED(hr))\n    {\n        notificationType = EnumValue<XblSocialNotificationType>(notificationTypeString.data());\n\n        switch (notificationType)\n        {\n        // Special handling for IncomingFriendRequestCountChanged as that payload is structured differently\n        // and results in a different event handler firing\n        case XblSocialNotificationType::IncomingFriendRequestCountChanged:\n        {\n\n            size_t incomingFriendRequestCount{};\n            hr = JsonUtils::ExtractJsonSizeT(data, \"Count\", incomingFriendRequestCount, true);\n            if (SUCCEEDED(hr))\n            {\n                XblSocialFriendRequestCountChangedEventArgs args\n                {\n                    m_xuid, \n                    incomingFriendRequestCount \n                };\n\n                std::unique_lock<std::mutex> lock{ m_lock };\n                auto handlers{ m_friendRequestCountChangedHandlers };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second(args);\n                }\n            }\n            else\n            {\n                LOGS_DEBUG << __FUNCTION__ << \": Ignoring malformed event\";\n            }\n            break;\n        }\n        // Everything else can be handled the same\n        case XblSocialNotificationType::Added:\n        case XblSocialNotificationType::Changed:\n        case XblSocialNotificationType::Removed:\n        {\n            hr = JsonUtils::ExtractJsonVector<uint64_t>(\n                JsonUtils::JsonXuidExtractor,\n                data,\n                \"Xuids\",\n                xuids,\n                true\n            );\n\n            if (SUCCEEDED(hr))\n            {\n                XblSocialRelationshipChangeEventArgs args\n                {\n                    m_xuid,\n                    notificationType,\n                    xuids.data(),\n                    xuids.size()\n                };\n\n                std::unique_lock<std::mutex> lock{ m_lock };\n                auto handlers{ m_handlers };\n                lock.unlock();\n\n                for (auto& handler : handlers)\n                {\n                    handler.second(args);\n                }\n            }\n            else\n            {\n                LOGS_DEBUG << __FUNCTION__ << \": Ignoring malformed event\";\n            }\n            break;\n        }\n        case XblSocialNotificationType::Unknown:\n        default:\n        {\n            LOGS_DEBUG << __FUNCTION__ << \": Ignoring malformed event\";\n            break;\n        }\n        }\n    }\n    else\n    {\n        LOGS_DEBUG << __FUNCTION__ << \": Ignoring malformed event\";\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END\n"
  },
  {
    "path": "Source/Services/Social/social_relationship_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::social;\n\nResult<std::shared_ptr<XblSocialRelationshipResult>> XblSocialRelationshipResult::Deserialize(\n    const JsonValue& json\n)\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    auto result{ MakeShared<XblSocialRelationshipResult>() };\n\n    HRESULT errc = S_OK;\n    \n    uint64_t totalCount = 0;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"totalCount\", totalCount, false));\n    result->m_totalCount = static_cast<size_t>(totalCount);\n\n    if (json.IsObject() && json.HasMember(\"people\"))\n    {\n        const JsonValue& peopleJson = json[\"people\"];\n        if (peopleJson.IsArray())\n        {\n            result->m_socialRelationships.reserve(peopleJson.Size());\n            result->m_socialNetworks.reserve(peopleJson.Size());\n\n            for (const JsonValue& person : peopleJson.GetArray())\n            {\n                if (person.IsObject())\n                {\n                    XblSocialRelationship relationship{};\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonXuid(person, \"xuid\", relationship.xboxUserId, true));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(person, \"isFavorite\", relationship.isFavorite));\n                    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonBool(person, \"isFriend\", relationship.isFriend)); \n\n                    // isFavorite should reflect the vlaues of 'isFavorite' and  isFriend from the service response\n                    relationship.isFavorite = relationship.isFavorite && relationship.isFriend;\n                    // Shimming isFriend response into isFollowingCaller for compatibility purposes.\n                    // This does not reflect a follower/following relationship.\n                    relationship.isFollowingCaller = relationship.isFriend;\n                    xsapi_internal_vector<xsapi_internal_string> socialNetworksInternalVector;\n                    JsonUtils::ExtractJsonVector<xsapi_internal_string>(JsonUtils::JsonStringExtractor, person, \"socialNetworks\", socialNetworksInternalVector, false);\n                    UTF8StringArray socialNetworks(socialNetworksInternalVector);\n                    relationship.socialNetworks = socialNetworks.Data();\n                    relationship.socialNetworksCount = socialNetworks.Size();\n\n                    result->m_socialRelationships.push_back(std::move(relationship));\n                    result->m_socialNetworks.push_back(std::move(socialNetworks));\n                }\n            }\n        }\n    }\n\n    return Result<std::shared_ptr<XblSocialRelationshipResult>>{ result, errc };\n}\n\nconst xsapi_internal_vector<XblSocialRelationship>& XblSocialRelationshipResult::SocialRelationships() const noexcept\n{\n    return m_socialRelationships;\n}\n\nbool XblSocialRelationshipResult::HasNext() const noexcept\n{\n    return ContinuationSkip < m_totalCount;\n}\n\nsize_t XblSocialRelationshipResult::TotalCount() const noexcept\n{\n    return m_totalCount;\n}\n\nstd::shared_ptr<RefCounter> XblSocialRelationshipResult::GetSharedThis()\n{\n    return shared_from_this();\n}\n"
  },
  {
    "path": "Source/Services/Social/social_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"social_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN\n\nSocialService::SocialService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n) noexcept :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings{ std::move(xboxLiveContextSettings) },\n    m_rtaManager{ std::move(rtaManager) }\n{\n}\n\nSocialService::~SocialService() noexcept\n{\n    if (m_socialRelationshipChangedSubscription)\n    {\n        m_rtaManager->RemoveSubscription(m_user, m_socialRelationshipChangedSubscription);\n    }\n}\n\nXblFunctionContext SocialService::AddSocialRelationshipChangedHandler(\n    _In_ SocialRelationshipChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n\n    if (!m_socialRelationshipChangedSubscription)\n    {\n        m_socialRelationshipChangedSubscription = MakeShared<SocialRelationshipChangeSubscription>(m_user.Xuid());\n        m_rtaManager->AddSubscription(m_user, m_socialRelationshipChangedSubscription);\n    }\n    return m_socialRelationshipChangedSubscription->AddHandler(std::move(handler));\n}\n\nXblFunctionContext SocialService::AddFriendRequestCountChangedHandler(\n    _In_ FriendRequestCountChangedHandler handler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n\n    if (!m_socialRelationshipChangedSubscription)\n    {\n        m_socialRelationshipChangedSubscription = MakeShared<SocialRelationshipChangeSubscription>(m_user.Xuid());\n        m_rtaManager->AddSubscription(m_user, m_socialRelationshipChangedSubscription);\n    }\n    return m_socialRelationshipChangedSubscription->AddHandler(std::move(handler));\n}\n\nvoid SocialService::RemoveSocialRTAHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_lock };\n\n    if (m_socialRelationshipChangedSubscription)\n    {\n        if (m_socialRelationshipChangedSubscription->RemoveHandler(token) == 0)\n        {\n            m_rtaManager->RemoveSubscription(m_user, m_socialRelationshipChangedSubscription);\n            m_socialRelationshipChangedSubscription.reset();\n        }\n    }\n}\n\nHRESULT SocialService::GetSocialRelationships(\n    _In_ uint64_t xuid,\n    _In_ XblSocialRelationshipFilter filter,\n    _In_ size_t startIndex,\n    _In_ size_t maxItems,\n    _In_ AsyncContext<Result<std::shared_ptr<XblSocialRelationshipResult>>> async\n) const noexcept\n{\n\n    xsapi_internal_stringstream subpath;\n    subpath << \"/users/xuid(\";\n    subpath << xuid;\n    subpath << \")/people\";\n\n    xsapi_internal_string nextDelimiter = \"?\";\n\n    subpath << nextDelimiter;\n    subpath << \"view=\";\n    subpath << SocialRelationshipFilterToString(filter);\n    nextDelimiter = \"&\";\n    \n\n    if (startIndex > 0)\n    {\n        subpath << nextDelimiter;\n        subpath << \"startIndex=\";\n        subpath << startIndex;\n        nextDelimiter = \"&\";\n    }\n\n    if (maxItems > 0)\n    {\n        subpath << nextDelimiter;\n        subpath << \"maxItems=\";\n        subpath << maxItems;\n        nextDelimiter = \"&\";\n    }\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"social\", subpath.str()),\n        xbox_live_api::get_social_relationships\n    ));\n\n    httpCall->SetXblServiceContractVersion(3);\n\n    return httpCall->Perform({\n        async.Queue(),\n        [\n            async,\n            filter,\n            startIndex\n        ]\n    (HttpResult httpResult)\n    {\n        HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n        if (FAILED(hr))\n        {\n            return async.Complete(hr);\n        }\n        else\n        {\n            auto result{ XblSocialRelationshipResult::Deserialize(httpResult.Payload()->GetResponseBodyJson()) };\n\n            if (Succeeded(result))\n            {\n                result.Payload()->ContinuationSkip = startIndex + result.Payload()->SocialRelationships().size();\n                result.Payload()->Filter = filter;\n            }\n\n            return async.Complete(result);\n        }\n    } });\n}\n\nxsapi_internal_string SocialService::SocialRelationshipFilterToString(\n    _In_ XblSocialRelationshipFilter filter\n) noexcept\n{\n    switch (filter)\n    {\n    case XblSocialRelationshipFilter::Favorite:\n    {\n        return \"Favorite\";\n    }\n    case XblSocialRelationshipFilter::LegacyXboxLiveFriends:\n    {\n        return \"LegacyXboxLiveFriends\";\n    } \n    case XblSocialRelationshipFilter::All:\n    default:\n    {\n        return \"FriendList\";\n    }\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END"
  },
  {
    "path": "Source/Services/Stats/requested_statistics.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"user_statistics_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nRequestedStatistics::RequestedStatistics()\n{ }\n\nRequestedStatistics::RequestedStatistics(\n    _In_ xsapi_internal_string serviceConfigurationId,\n    _In_ xsapi_internal_vector<xsapi_internal_string> statistics\n    ) :\n    m_serviceConfigurationId(serviceConfigurationId),\n    m_statistics(statistics)\n{ }\n\nRequestedStatistics::RequestedStatistics(\n    _In_ XblRequestedStatistics requestedStatistics\n    )\n{\n    m_serviceConfigurationId = xsapi_internal_string(requestedStatistics.serviceConfigurationId);\n    m_statistics = utils::string_array_to_internal_string_vector(requestedStatistics.statistics, requestedStatistics.statisticsCount);\n}\n\nconst xsapi_internal_string& RequestedStatistics::ServiceConfigurationId() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst xsapi_internal_vector<xsapi_internal_string>& RequestedStatistics::Statistics() const\n{\n    return m_statistics;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/service_configuration_statistic.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi_utils.h\"\n#include \"user_statistics_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nServiceConfigurationStatistic::ServiceConfigurationStatistic()\n{ }\n\nServiceConfigurationStatistic::ServiceConfigurationStatistic(\n    _In_ xsapi_internal_string serviceConfigurationId,\n    _In_ xsapi_internal_vector<Statistic> stats\n    ) :\n    m_serviceConfigurationId(serviceConfigurationId),\n    m_stats(stats)\n{ }\n\nconst xsapi_internal_string& \nServiceConfigurationStatistic::ServiceConfigurationId() const\n{\n    return m_serviceConfigurationId;\n}\n\nconst xsapi_internal_vector<Statistic>&\nServiceConfigurationStatistic::Statistics() const\n{\n    return m_stats;\n}\n\nvoid\nServiceConfigurationStatistic::SetServiceConfigurationId(_In_ xsapi_internal_string serviceConfigId)\n{\n    m_serviceConfigurationId = std::move(serviceConfigId);\n}\n\n/* static */ Result<ServiceConfigurationStatistic>\nServiceConfigurationStatistic::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    ServiceConfigurationStatistic returnResult;\n\n    if (json.IsNull())\n    {\n        return returnResult;\n    }\n\n    xsapi_internal_string scid;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"scid\", scid, true));\n    xsapi_internal_vector<Statistic> stats;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<Statistic>(Statistic::Deserialize, json, \"stats\", stats, true));\n    returnResult = ServiceConfigurationStatistic(\n        scid,\n        stats\n    );\n\n    return Result<ServiceConfigurationStatistic>(returnResult, S_OK);\n}\n\nsize_t \nServiceConfigurationStatistic::SizeOf() const\n{\n    size_t size = sizeof(XblServiceConfigurationStatistic);\n\n    for (Statistic stat : m_stats)\n    {\n        size += stat.SizeOf();\n    }\n\n    return size;\n}\n\nchar*\nServiceConfigurationStatistic::Serialize(XblServiceConfigurationStatistic* serviceConfigStat, char* buffer) const\n{\n    utils::strcpy(serviceConfigStat->serviceConfigurationId, m_serviceConfigurationId.size() + 1, m_serviceConfigurationId.c_str());\n\n    serviceConfigStat->statisticsCount = (uint32_t)m_stats.size();\n    serviceConfigStat->statistics = reinterpret_cast<XblStatistic*>(buffer);\n    buffer += sizeof(XblStatistic) * m_stats.size();\n    \n    for (size_t i = 0; i < m_stats.size(); i++)\n    {\n        buffer = m_stats[i].Serialize(&serviceConfigStat->statistics[i], buffer);\n    }\n\n    return buffer;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/statistic.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi_utils.h\"\n#include \"user_statistics_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nStatistic::Statistic()\n{ }\n\n// class statistic\nStatistic::Statistic(\n    _In_ xsapi_internal_string name,\n    _In_ xsapi_internal_string type,\n    _In_ xsapi_internal_string value\n    ) :\n    m_statName(std::move(name)),\n    m_statType(std::move(type)),\n    m_value(std::move(value))\n{ }\n\nconst xsapi_internal_string&\nStatistic::StatisticName() const\n{\n    return m_statName;\n}\n\nconst xsapi_internal_string&\nStatistic::StatisticType() const\n{\n    return m_statType;\n}\n\nconst xsapi_internal_string&\nStatistic::Value() const\n{\n    return m_value;\n}\n\nvoid\nStatistic::SetStatisticName(\n    _In_ xsapi_internal_string name\n    )\n{\n    m_statName = std::move(name);\n}\n\nvoid \nStatistic::SetStatisticType(\n    _In_ xsapi_internal_string type\n    )\n{\n    m_statType = std::move(type);\n}\n\nvoid\nStatistic::SetStatisticValue(\n    _In_ xsapi_internal_string value\n    )\n{\n    m_value = std::move(value);\n}\n\n/* static */ Result<Statistic>\nStatistic::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    Statistic returnResult;\n    if (json.IsNull())\n    {\n        return returnResult;\n    }\n\n    xsapi_internal_string statname, type, value;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"statname\", statname, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"type\", type, true));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"value\", value, true));\n    returnResult = Statistic(\n        statname,\n        type,\n        value\n    );\n\n    return Result<Statistic>(returnResult, S_OK);\n}\n\nsize_t \nStatistic::SizeOf() const\n{\n    size_t size = sizeof(XblStatistic);\n    size += m_statName.size() + 1;\n    size += m_statType.size() + 1;\n    size += m_value.size() + 1;\n    return size;\n}\n\nchar*\nStatistic::Serialize(XblStatistic* statistic, char* buffer) const\n{\n    utils::strcpy(buffer, m_statName.size() + 1, m_statName.c_str());\n    statistic->statisticName = static_cast<char*>(buffer);\n    buffer += m_statName.size() + 1;\n\n    utils::strcpy(buffer, m_statType.size() + 1, m_statType.c_str());\n    statistic->statisticType = static_cast<char*>(buffer);\n    buffer += m_statType.size() + 1;\n\n    utils::strcpy(buffer, m_value.size() + 1, m_value.c_str());\n    statistic->value = static_cast<char*>(buffer);\n    buffer += m_value.size() + 1;\n\n    return buffer;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/statistic_change_subscription.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"user_statistics_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nStatisticChangeSubscription::StatisticChangeSubscription(\n    _In_ uint64_t xuid,\n    _In_ String scid,\n    _In_ String statisticName,\n    _In_ std::shared_ptr<UserStatisticsService> statisticsService\n) noexcept :\n    m_xuid{ xuid },\n    m_scid{ std::move(scid) },\n    m_statisticName{ std::move(statisticName) },\n    m_statisticsService{ statisticsService }\n{\n    Stringstream uriPath;\n    uriPath << \"https://userstats.xboxlive.com/users/xuid(\" << m_xuid << \")/scids/\" << m_scid << \"/stats/\" << m_statisticName;\n    m_resourceUri = uriPath.str();\n}\n\nvoid StatisticChangeSubscription::OnSubscribe(\n    _In_ const JsonValue& data\n) noexcept\n{\n    // Payload format http://xboxwiki/wiki/RTA%3ASUBSCRIBE#Subscribing_to_Stats\n    // [<API_ID>, <SUB_ID>, { \"name\": \"Kills\", \"type\" : \"Integer\", \"value\": 219 }]\n\n    if (data.IsNull())\n    {\n        LOGS_ERROR << __FUNCTION__ << \": RTA payload unexpectedly null\";\n        return;\n    }\n    else if (auto statisticsService{ m_statisticsService.lock() })\n    {\n        String name;\n        String value;\n        JsonUtils::ExtractJsonString(data, \"name\", name);\n        assert(name == m_statisticName);\n        JsonUtils::ExtractJsonString(data, \"type\", m_statisticType);\n\n        if (data.IsObject() && data.HasMember(\"value\"))\n        {\n            const JsonValue& field = data[\"value\"];\n            if (field.IsInt())\n            {\n                Stringstream stream;\n                stream << field.GetInt();\n                value = stream.str();\n            }\n            else if (field.IsInt64())\n            {\n                Stringstream stream;\n                stream << field.GetInt64();\n                value = stream.str();\n            }\n            else if (field.IsUint())\n            {\n                Stringstream stream;\n                stream << field.GetUint();\n                value = stream.str();\n            }\n            else if (field.IsUint64())\n            {\n                Stringstream stream;\n                stream << field.GetUint64();\n                value = stream.str();\n            }\n            else if (field.IsDouble())\n            {\n                Stringstream stream;\n                stream << field.GetDouble();\n                value = stream.str();\n            }\n            else if (field.IsBool())\n            {\n                Stringstream stream;\n                stream << field.GetBool();\n                value = stream.str();\n            }\n            else if (field.IsString())\n            {\n                value = field.GetString();\n            }\n        }\n\n        statisticsService->HandleStatisticChanged(StatisticChangeEventArgs\n            {\n                m_xuid,\n                m_scid,\n                m_statisticName,\n                m_statisticType,\n                std::move(value)\n            });\n    }\n}\n\nvoid StatisticChangeSubscription::OnEvent(\n    _In_ const JsonValue& data\n) noexcept\n{\n    // Payload format http://xboxwiki/wiki/RTA:EVENT#Stats\n    // [<API_ID>, <SUB_ID>, \"Value\"]\n\n    if (data.IsNull())\n    {\n        LOGS_ERROR << __FUNCTION__ << \": RTA payload unexpectedly null\";\n    }\n    else if (auto statisticsService{ m_statisticsService.lock() })\n    {\n        statisticsService->HandleStatisticChanged(StatisticChangeEventArgs\n            {\n                m_xuid,\n                m_scid,\n                m_statisticName,\n                m_statisticType,\n                JsonUtils::SerializeJson(data)\n            });\n    }\n}\n\nStatisticChangeEventArgs::StatisticChangeEventArgs(\n    _In_ uint64_t _xboxUserId,\n    _In_ const String& _serviceConfigurationId,\n    _In_ String _statisticName,\n    _In_ String _statisticType,\n    _In_ String _value\n) noexcept :\n    XblStatisticChangeEventArgs{ _xboxUserId },\n    m_statisticName{ std::move(_statisticName) },\n    m_statisticType{ std::move(_statisticType) },\n    m_value{ std::move(_value) }\n{\n    utils::strcpy(serviceConfigurationId, sizeof(serviceConfigurationId), _serviceConfigurationId.data());\n    latestStatistic = XblStatistic\n    {\n        m_statisticName.data(),\n        m_statisticType.data(),\n        m_value.data()\n    };\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/title_managed_statistics_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"title_managed_statistics_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::user_statistics;\n\nSTDAPI XblTitleManagedStatsWriteAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_ const XblTitleManagedStatistic* statistics,\n    _In_ size_t statisticsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    // It is only valid to write stats for the local user, but the service will return 200 if we try to write\n    // stats for another user (it just won't actually update the SVD). Add a client side check so games get\n    // an error in this case.\n    RETURN_HR_INVALIDARGUMENT_IF(xblContextHandle->Xuid() != xboxUserId);\n    RETURN_HR_INVALIDARGUMENT_IF(statistics == nullptr || statisticsCount == 0);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext = xblContextHandle->shared_from_this(),\n            statList = Vector<TitleManagedStatistic>(statistics, statistics + statisticsCount)\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->TitleManagedStatisticsService()->WriteTitleManagedStatisticsAsync(\n                statList,\n                data->async\n            ));\n\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nHRESULT UpdateStatsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ Vector<TitleManagedStatistic>&& stats,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext = xblContextHandle->shared_from_this(),\n            stats{ std::move(stats) }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xboxLiveContext->TitleManagedStatisticsService()->UpdateTitleManagedStatistics(\n                stats,\n                data->async\n            ));\n\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\n\nSTDAPI XblTitleManagedStatsUpdateStatsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const XblTitleManagedStatistic* statistics,\n    _In_ size_t statisticsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(statistics == nullptr || statisticsCount == 0);\n\n    return UpdateStatsAsync(\n        xblContextHandle,\n        Vector<TitleManagedStatistic>(statistics, statistics + statisticsCount),\n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleManagedStatsDeleteStatsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const char** names,\n    _In_ size_t count,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(names == nullptr || count == 0);\n\n    return UpdateStatsAsync(\n        xblContextHandle,\n        Vector<TitleManagedStatistic>(names, names + count),\n        async\n    );\n}\nCATCH_RETURN()"
  },
  {
    "path": "Source/Services/Stats/title_managed_statistics_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/title_managed_statistics_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nstruct TitleManagedStatistic\n{\n    TitleManagedStatistic(const XblTitleManagedStatistic& s) noexcept\n        : name{ s.statisticName },\n        type{ static_cast<Type>(s.statisticType) },\n        numberValue{ s.numberValue },\n        stringValue{ s.stringValue ? s.stringValue : \"\" }\n    {\n    }\n\n    // The statswrite PATCH endpoint allows stat deletions by writing a null\n    // JSON value for an existing statname. This constructor is used to create a\n    // a \"NULL\" TitleManagedStatistic to be used for deletion.\n    TitleManagedStatistic(const char* nameToDelete) noexcept\n        : name{ nameToDelete },\n        type{ Type::Null }\n    {\n    }\n\n    String name;\n    enum class Type : uint32_t\n    {\n        Number = static_cast<uint32_t>(XblTitleManagedStatType::Number),\n        String = static_cast<uint32_t>(XblTitleManagedStatType::String),\n        Null\n    } type;\n    double numberValue{ 0.0 };\n    String stringValue;\n};\n\nclass TitleManagedStatisticsService: public std::enable_shared_from_this<TitleManagedStatisticsService>\n{\npublic:\n    TitleManagedStatisticsService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings\n    ) noexcept;\n\n    HRESULT WriteTitleManagedStatisticsAsync(\n        _In_ const Vector<TitleManagedStatistic>& statistics,\n        _In_ AsyncContext<HRESULT> async\n    ) const noexcept;\n\n    HRESULT UpdateTitleManagedStatistics(\n        _In_ const Vector<TitleManagedStatistic>& statistics,\n        _In_ AsyncContext<HRESULT> async\n    ) const noexcept;\n\nprivate:\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    String m_statswritePath;\n\n    static uint64_t GetRevisionFromClock() noexcept;\n\n    static JsonDocument SerializeStatistics(\n        const Vector<TitleManagedStatistic>& stats\n    ) noexcept;\n};\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/title_managed_statistics_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"title_managed_statistics_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nTitleManagedStatisticsService::TitleManagedStatisticsService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings\n) noexcept :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings(std::move(xboxLiveContextSettings))\n{\n    Stringstream ss;\n    ss << \"/stats/users/\" << m_user.Xuid() << \"/scids/\" << AppConfig::Instance()->Scid();\n    m_statswritePath = ss.str();\n}\n\nHRESULT TitleManagedStatisticsService::WriteTitleManagedStatisticsAsync(\n    _In_ const Vector<TitleManagedStatistic>& statistics,\n    _In_ AsyncContext<HRESULT> async\n) const noexcept\n{\n    JsonDocument request{ SerializeStatistics(statistics) };\n    JsonDocument::AllocatorType& allocator = request.GetAllocator();\n    request.AddMember(\"$schema\", \"http://stats.xboxlive.com/2017-1/schema#\", allocator);\n    request.AddMember(\"previousRevision\", 0, allocator);\n    request.AddMember(\"revision\", GetRevisionFromClock(), allocator);\n    request.AddMember(\"timestamp\", JsonValue(xbox::services::datetime::utc_now().to_string(xbox::services::datetime::date_format::ISO_8601).c_str(), allocator).Move(), allocator);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"statswrite\", m_statswritePath),\n        xbox_live_api::post_stats_value_document\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(4));\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(request));\n\n    return httpCall->Perform({ async.Queue().GetHandle(),\n        [\n            async\n        ]\n        (HttpResult result)\n        {\n           HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n           return async.Complete(hr);\n        }\n    });\n}\n\nHRESULT TitleManagedStatisticsService::UpdateTitleManagedStatistics(\n    _In_ const Vector<TitleManagedStatistic>& statistics,\n    _In_ AsyncContext<HRESULT> async\n) const noexcept\n{\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"PATCH\",\n        XblHttpCall::BuildUrl(\"statswrite\", m_statswritePath),\n        xbox_live_api::patch_stats_value_document\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(4));\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(SerializeStatistics(statistics)));\n\n    return httpCall->Perform({ async.Queue().DeriveWorkerQueue(),\n        [\n            async\n        ]\n        (HttpResult result)\n        {\n            HRESULT hr{ Failed(result) ? result.Hresult() : result.Payload()->Result() };\n            return async.Complete(hr);\n        }\n    });\n}\n\nuint64_t TitleManagedStatisticsService::GetRevisionFromClock() noexcept\n{\n    uint64_t dateTime = xbox::services::datetime::utc_now().to_interval(); // eg. 131472330440000000\n    const uint64_t dateTimeFromJan1st2015 = 130645440000000000;\n    if (dateTime < dateTimeFromJan1st2015)\n    {\n        return 1; // Clock is wrong and is not yet sync'd with internet time, so just setting the revision to 1\n    }\n    else\n    {\n        uint64_t dateTimeSince2015 = dateTime - dateTimeFromJan1st2015; // eg. 826888900000000\n        uint64_t dateTimeTrimmed = dateTimeSince2015 >> 16; // divide by 2^16 to get it to sub second range.  eg. 12617323303\n        return dateTimeTrimmed;\n    }\n}\n\n\nJsonDocument TitleManagedStatisticsService::SerializeStatistics(\n    const Vector<TitleManagedStatistic>& stats\n) noexcept\n{\n    assert(!stats.empty());\n\n    JsonDocument jsonDoc{ rapidjson::kObjectType };\n    auto& a{ jsonDoc.GetAllocator() };\n\n    JsonValue statsJson{ rapidjson::kObjectType };\n    JsonValue titleJson{ rapidjson::kObjectType };\n\n    for (auto& stat : stats)\n    {\n        JsonValue statJson{ rapidjson::kObjectType };\n        switch (stat.type)\n        {\n        case TitleManagedStatistic::Type::Number:\n        {\n            statJson.AddMember(\"value\", stat.numberValue, a);\n            break;\n        }\n        case TitleManagedStatistic::Type::String:\n        {\n            statJson.AddMember(\"value\", JsonValue{ stat.stringValue.data(), a }.Move(), a);\n            break;\n        }\n        case TitleManagedStatistic::Type::Null:\n        {\n            statJson.SetNull();\n            break;\n        }\n        default:\n        {\n            assert(false);\n            break;\n        }\n        }\n        titleJson.AddMember(JsonValue{ stat.name.data(), a }.Move(), statJson.Move(), a);\n    }\n    statsJson.AddMember(\"title\", titleJson.Move(), a);\n    jsonDoc.AddMember(\"stats\", statsJson.Move(), a);\n\n    return jsonDoc;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END\n"
  },
  {
    "path": "Source/Services/Stats/user_statistics_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/user_statistics_c.h\"\n#include \"user_statistics_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\nusing namespace xbox::services::user_statistics;\n\nSTDAPI XblUserStatisticsGetSingleUserStatisticAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_z_ const char* statisticName,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    return XblUserStatisticsGetSingleUserStatisticsAsync(\n        xblContext,\n        xboxUserId,\n        serviceConfigurationId,\n        &statisticName,\n        1,\n        async\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetSingleUserStatisticResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetSingleUserStatisticResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblUserStatisticsResult*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetSingleUserStatisticsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xboxUserId,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF(statisticNames == nullptr || statisticNamesCount == 0);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            resultPayload = UserStatisticsResult{},\n            xboxUserId,\n            scid = String{ serviceConfigurationId },\n            statisticNames{ Vector<String>(statisticNames, statisticNames + statisticNamesCount) }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->UserStatisticsService()->GetSingleUserStatistics(\n                xboxUserId,\n                scid,\n                statisticNames,\n                {\n                    TaskQueue{ data->async->queue }.DeriveWorkerQueue(),\n                    [\n                        &resultPayload,\n                        async{ data->async }\n                    ]\n                    (Result<UserStatisticsResult> result)\n                    {\n                        if (Succeeded(result))\n                        {\n                            resultPayload = std::move(result.ExtractPayload());\n                        }\n                        XAsyncComplete(async, result.Hresult(), resultPayload.SizeOf());\n                    }\n                }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            buffer = resultPayload.Serialize(buffer);\n            assert(static_cast<void*>(buffer) == static_cast<void*>(static_cast<char*>(data->buffer) + resultPayload.SizeOf()));\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetSingleUserStatisticsResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetSingleUserStatisticsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblUserStatisticsResult*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsAsync(\n    _In_ XblContextHandle xblContext,\n    _In_ uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF(statisticNames == nullptr || statisticNamesCount == 0);\n\n    XblRequestedStatistics requestedStats{ {}, statisticNames, static_cast<uint32_t>(statisticNamesCount) };\n    utils::strcpy(requestedStats.serviceConfigurationId, sizeof(requestedStats.serviceConfigurationId), serviceConfigurationId);\n\n    return XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(\n        xblContext,\n        xboxUserIds,\n        static_cast<uint32_t>(xboxUserIdsCount),\n        &requestedStats,\n        1,\n        async\n    );\n\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** results,\n    _Out_ size_t* resultsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(results == nullptr || resultsCount == nullptr);\n\n    size_t bufferUsedTemp{};\n    if (bufferUsed == nullptr)\n    {\n        bufferUsed = &bufferUsedTemp;\n    }\n\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *results = static_cast<XblUserStatisticsResult*>(buffer);\n        auto sizePtr = reinterpret_cast<size_t*>(static_cast<char*>(buffer) + *bufferUsed) - 1;\n        *resultsCount = *sizePtr;\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t* xboxUserIds,\n    _In_ uint32_t xboxUserIdsCount,\n    _In_ const XblRequestedStatistics* requestedStats,\n    _In_ uint32_t requestedStatsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(xboxUserIds == nullptr || xboxUserIdsCount == 0);\n    RETURN_HR_INVALIDARGUMENT_IF(requestedStats == nullptr || requestedStatsCount == 0);\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xblContextHandle->shared_from_this() },\n            resultPayload{ Vector<UserStatisticsResult>{} },\n            xuids{ Vector<uint64_t>(xboxUserIds, xboxUserIds + xboxUserIdsCount) },\n            requestedStats{ Vector<RequestedStatistics>(requestedStats, requestedStats + requestedStatsCount) }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(xblContext->UserStatisticsService()->GetMultipleUserStatisticsForMultipleServiceConfigurations(\n                xuids,\n                requestedStats,\n                {\n                    TaskQueue{ data->async->queue }.DeriveWorkerQueue(),\n                    [\n                        &resultPayload,\n                        async{ data->async }\n                    ]\n                    (Result<Vector<UserStatisticsResult>> result)\n                    {\n                        size_t bufferSize{ 0 };\n                        if (Succeeded(result))\n                        {\n                            resultPayload = std::move(result.ExtractPayload());\n                            for (auto& userStatResult : resultPayload)\n                            {\n                                bufferSize += userStatResult.SizeOf();\n                            }\n                            // Add some padding at the end of the buffer to store the number of XblUserStatisticsResult\n                            // objects since there is no way to deduce it just from the buffer size\n                            bufferSize += sizeof(size_t);\n                        }\n\n                        XAsyncComplete(async, result.Hresult(), bufferSize);\n                    }\n                }));\n\n            return E_PENDING;\n        }\n        case XAsyncOp::GetResult:\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            XblUserStatisticsResult * resultArr = reinterpret_cast<XblUserStatisticsResult*>(buffer);\n            buffer += sizeof(XblUserStatisticsResult) * resultPayload.size();\n            size_t bufferSize{};\n\n            for (size_t i = 0; i < resultPayload.size(); i++)\n            {\n                bufferSize += resultPayload[i].SizeOf();\n                buffer = resultPayload[i].Serialize(&resultArr[i], buffer);\n            }\n\n            // Validate that everything that was expected to be written was written to the buffer\n            size_t * resultArrSize = reinterpret_cast<size_t*>(buffer);\n            XSAPI_ASSERT(static_cast<void*>(resultArrSize) == static_cast<void*>(static_cast<char*>(data->buffer) + bufferSize));\n            *resultArrSize = resultPayload.size();\n            return S_OK;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(async, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblUserStatisticsResult** results,\n    _Out_ size_t* resultsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(results == nullptr || resultsCount == nullptr);\n\n    size_t bufferUsedTemp{};\n    if (bufferUsed == nullptr)\n    {\n        bufferUsed = &bufferUsedTemp;\n    }\n\n    auto hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *results = static_cast<XblUserStatisticsResult*>(buffer);\n        auto sizePtr = reinterpret_cast<size_t*>(static_cast<char*>(buffer) + *bufferUsed) - 1;\n        *resultsCount = *sizePtr;\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nnamespace xbox {\n    namespace services {\n        namespace user_statistics {\n            namespace legacy {\n                struct Subscription : public XblRealTimeActivitySubscription\n                {\n                    Subscription(uint64_t _xuid, String _scid, String _statName) noexcept\n                        : xuid{ _xuid },\n                        scid{ std::move(_scid) },\n                        statName{ std::move(_statName) }\n                    {\n                    }\n                    uint64_t xuid;\n                    String scid;\n                    String statName;\n                };\n            }\n        }\n    }\n}\n\nSTDAPI XblUserStatisticsSubscribeToStatisticChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ uint64_t xuid,\n    _In_z_ const char* scid,\n    _In_z_ const char* statisticName,\n    _Out_ XblRealTimeActivitySubscriptionHandle* subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(subscriptionHandle);\n\n    HRESULT hr = XblUserStatisticsTrackStatistics(\n        xblContextHandle,\n        &xuid,\n        1,\n        scid,\n        &statisticName,\n        1\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        *subscriptionHandle = Make<user_statistics::legacy::Subscription>(xuid, scid, statisticName);\n    }\n    return hr;\n}\nCATCH_RETURN();\n\nSTDAPI XblUserStatisticsUnsubscribeFromStatisticChange(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblRealTimeActivitySubscriptionHandle subscriptionHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(subscriptionHandle);\n\n    auto sub{ static_cast<user_statistics::legacy::Subscription*>(subscriptionHandle) };\n    const char* statName{ sub->statName.data() };\n\n    HRESULT hr = XblUserStatisticsStopTrackingStatistics(\n        xblContextHandle,\n        &sub->xuid,\n        1,\n        sub->scid.data(),\n        &statName,\n        1\n    );\n\n    assert(SUCCEEDED(hr));\n    Delete(sub);\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI_(XblFunctionContext) XblUserStatisticsAddStatisticChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblStatisticChangedHandler handler,\n    _In_opt_ void* handlerContext\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContextHandle == nullptr || handler == nullptr)\n    {\n        return XblFunctionContext{ 0 };\n    }\n\n    return xblContextHandle->UserStatisticsService()->AddStatisticChangedHandler(\n        [\n            handler,\n            handlerContext\n        ]\n    (const StatisticChangeEventArgs& eventArgs)\n    {\n        try\n        {\n            handler(eventArgs, handlerContext);\n        }\n        catch (...)\n        {\n            LOGS_ERROR << __FUNCTION__ << \": exception in client handler!\";\n        }\n    });\n}\nCATCH_RETURN_WITH(-1)\n\nSTDAPI_(void) XblUserStatisticsRemoveStatisticChangedHandler(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ XblFunctionContext context\n) XBL_NOEXCEPT\ntry\n{\n    if (xblContextHandle != nullptr)\n    {\n        xblContextHandle->UserStatisticsService()->RemoveStatisticChangedHandler(context);\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblUserStatisticsTrackStatistics(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(xboxUserIds == nullptr || xboxUserIdsCount == 0);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF(statisticNames == nullptr || statisticNamesCount == 0);\n\n    return xblContextHandle->UserStatisticsService()->TrackStatistics(\n        Vector<uint64_t>{ xboxUserIds, xboxUserIds + xboxUserIdsCount },\n        serviceConfigurationId,\n        Vector<String>{ statisticNames, statisticNames + statisticNamesCount }\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsStopTrackingStatistics(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ const char** statisticNames,\n    _In_ size_t statisticNamesCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(xboxUserIds == nullptr || xboxUserIdsCount == 0);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF(statisticNames == nullptr || statisticNamesCount == 0);\n\n    return xblContextHandle->UserStatisticsService()->StopTrackingStatistics(\n        Vector<uint64_t>{ xboxUserIds, xboxUserIds + xboxUserIdsCount },\n        serviceConfigurationId,\n        Vector<String>{ statisticNames, statisticNames + statisticNamesCount }\n    );\n}\nCATCH_RETURN()\n\nSTDAPI XblUserStatisticsStopTrackingUsers(\n    _In_ XblContextHandle xblContextHandle,\n    _In_ const uint64_t* xboxUserIds,\n    _In_ size_t xboxUserIdsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(xblContextHandle);\n    RETURN_HR_INVALIDARGUMENT_IF(xboxUserIds == nullptr || xboxUserIdsCount == 0);\n\n    return xblContextHandle->UserStatisticsService()->StopTrackingUsers(\n        Vector<uint64_t>{ xboxUserIds, xboxUserIds + xboxUserIdsCount }\n    );\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/Stats/user_statistics_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/user_statistics_c.h\"\n#include \"real_time_activity_subscription.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nclass Statistic\n{\npublic:\n    Statistic();\n\n    Statistic(\n        _In_ String name,\n        _In_ String type,\n        _In_ String value\n    );\n\n    static Result<Statistic> Deserialize(\n        _In_ const JsonValue& json\n    );\n\n    const String& StatisticName() const;\n    const String& StatisticType() const;\n    const String& Value() const;\n\n    void SetStatisticName(_In_ String name);\n    void SetStatisticType(_In_ String type);\n    void SetStatisticValue(_In_ String value);\n\n    size_t SizeOf() const;\n    char* Serialize(XblStatistic* statistic, char* buffer) const;\n\nprivate:\n    String m_statName;\n    String m_statType;\n    String m_value;\n};\n\nclass ServiceConfigurationStatistic\n{\npublic:\n    ServiceConfigurationStatistic();\n\n    ServiceConfigurationStatistic(\n        _In_ String serviceConfigurationId,\n        _In_ Vector<Statistic> stats\n    );\n\n    static Result<ServiceConfigurationStatistic> Deserialize(\n        _In_ const JsonValue& json\n    );\n\n    const String& ServiceConfigurationId() const;\n    const Vector<Statistic>& Statistics() const;\n    \n    void SetServiceConfigurationId(_In_ String serviceConfigId);\n\n    size_t SizeOf() const;\n    char* Serialize(XblServiceConfigurationStatistic* serviceConfigStat, char* buffer) const;\n\nprivate:\n    String m_serviceConfigurationId;\n    Vector<Statistic> m_stats;\n};\n\nclass UserStatisticsResult\n{\npublic:\n    UserStatisticsResult();\n\n    UserStatisticsResult(\n        _In_ String xboxUserId,\n        _In_ Vector<ServiceConfigurationStatistic> serviceConfigStatistics\n    );\n\n    static Result<UserStatisticsResult> Deserialize(\n        _In_ const JsonValue& json\n    );\n\n    const String& XboxUserId() const;\n    const Vector<ServiceConfigurationStatistic>& ServiceConfigurationStatistics() const;\n\n    void SetServiceConfigurationId(_In_ String serviceConfigId);\n\n    size_t SizeOf() const;\n    char* Serialize(char* buffer) const;\n    char* Serialize(XblUserStatisticsResult* userStatResult, char* buffer) const;\n\nprivate:\n    String m_xboxUserId;\n    Vector<ServiceConfigurationStatistic> m_serviceConfigStatistics;\n};\n\nclass RequestedStatistics\n{\npublic:\n    RequestedStatistics();\n\n    RequestedStatistics(\n        _In_ String serviceConfigurationId,\n        _In_ Vector<String> statistics\n    );\n\n    RequestedStatistics(\n        _In_ XblRequestedStatistics requestedStatistics\n    );\n\n    const String& ServiceConfigurationId() const;\n    const Vector<String>& Statistics() const;\n\nprivate:\n    String m_serviceConfigurationId;\n    Vector<String> m_statistics;\n};\n\nclass StatisticChangeEventArgs : public XblStatisticChangeEventArgs\n{\npublic:\n    StatisticChangeEventArgs(\n        _In_ uint64_t xboxUserId,\n        _In_ const String& serviceConfigurationId,\n        _In_ String statisticName,\n        _In_ String statisticType,\n        _In_ String value\n    ) noexcept;\n\n    ~StatisticChangeEventArgs() = default;\n\nprivate:\n    String m_statisticName;\n    String m_statisticType;\n    String m_value;\n};\n\nclass StatisticChangeSubscription : public real_time_activity::Subscription, public std::enable_shared_from_this<StatisticChangeSubscription>\n{\npublic:\n    StatisticChangeSubscription(\n        _In_ uint64_t xuid,\n        _In_ String scid,\n        _In_ String statisticName,\n        _In_ std::shared_ptr<class UserStatisticsService> statisticsService\n    ) noexcept;\n\nprotected:\n    void OnSubscribe(_In_ const JsonValue& data) noexcept override;\n    void OnEvent(_In_ const JsonValue& data) noexcept override;\n\nprivate:\n    const uint64_t m_xuid;\n    const String m_scid;\n    const String m_statisticName;\n    String m_statisticType;\n    const std::weak_ptr<class UserStatisticsService> m_statisticsService;\n};\n\nclass UserStatisticsService : public std::enable_shared_from_this<UserStatisticsService>\n{\npublic:\n    UserStatisticsService(\n        _In_ User&& user,\n        _In_ const TaskQueue& backgroundQueue,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n        _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n    ) noexcept;\n\n    ~UserStatisticsService() noexcept;\n\n    HRESULT GetSingleUserStatistic(\n        _In_ uint64_t xuid,\n        _In_ const String& serviceConfigurationId,\n        _In_ const String& statisticName,\n        _In_ AsyncContext<Result<UserStatisticsResult>> async\n    ) const noexcept;\n\n    HRESULT GetSingleUserStatistics(\n        _In_ uint64_t xuid,\n        _In_ const String& serviceConfigurationId,\n        _In_ const Vector<String>& statisticNames,\n        _In_ AsyncContext<Result<UserStatisticsResult>> async\n    ) const noexcept;\n\n    HRESULT GetMultipleUserStatistics(\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ const String& serviceConfigurationId,\n        _In_ const Vector<String>& statisticNames,\n        _In_ AsyncContext<Result<Vector<UserStatisticsResult>>> async\n    ) const noexcept;\n\n    HRESULT GetMultipleUserStatisticsForMultipleServiceConfigurations(\n        _In_ const Vector<uint64_t>& xuids,\n        _In_ const Vector<RequestedStatistics>& requestedServiceConfigurationStatisticsCollection,\n        _In_ AsyncContext<Result<Vector<UserStatisticsResult>>> async\n    ) const noexcept;\n\n    typedef Callback<const StatisticChangeEventArgs&> StatisticChangeHandler;\n\n    XblFunctionContext AddStatisticChangedHandler(\n        StatisticChangeHandler handler\n    ) noexcept;\n\n    void RemoveStatisticChangedHandler(\n        XblFunctionContext token\n    ) noexcept;\n\n    HRESULT TrackStatistics(\n        _In_ const Vector<uint64_t> xuids,\n        _In_ const String& scid,\n        _In_ const Vector<String>& statNames\n    ) noexcept;\n\n    HRESULT StopTrackingStatistics(\n        _In_ const Vector<uint64_t> xuids,\n        _In_ const String& scid,\n        _In_ const Vector<String>& statNames\n    ) noexcept;\n\n    HRESULT StopTrackingUsers(\n        _In_ const Vector<uint64_t>& xuids\n    ) noexcept;\n\nprivate:\n    void HandleStatisticChanged(\n        const StatisticChangeEventArgs& args\n    ) const noexcept;\n\n    void HandleRTAResync();\n\n    static String UserStatsSubpath(\n        _In_ uint64_t xuid,\n        _In_ const String& serviceConfigurationId,\n        _In_ Vector<String> statNames\n    ) noexcept;\n\n    User m_user;\n    TaskQueue m_queue;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n    std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> m_rtaManager;\n\n    XblFunctionContext m_resyncHandlerToken{ 0 };\n    Map<XblFunctionContext, StatisticChangeHandler> m_statisticChangeHandlers;\n    XblFunctionContext m_nextToken{ 1 };\n\n    struct SubscriptionHolder\n    {\n        size_t refCount{ 0 };\n        std::shared_ptr<StatisticChangeSubscription> subscription;\n    };\n    // Indexing on Xuid before StatName because the set of tracked Users is probably more\n    // likely to change than the set of tracked Stats.\n    Map<uint64_t, Map<std::pair<String, String>, SubscriptionHolder>> m_trackedStatsByUser;\n\n    // Tracked stats by scid. Needed to perform RTA resync\n    Map<String, Vector<String>> m_trackedStatsByScid;\n\n    mutable std::recursive_mutex m_mutex;\n\n    friend class StatisticChangeSubscription;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/user_statistics_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi_utils.h\"\n#include \"user_statistics_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nUserStatisticsResult::UserStatisticsResult()\n{ }\n\nUserStatisticsResult::UserStatisticsResult(\n    _In_ xsapi_internal_string xboxUserId,\n    _In_ xsapi_internal_vector<ServiceConfigurationStatistic> serviceConfigStatistics\n    ) :\n    m_xboxUserId(std::move(xboxUserId)),\n    m_serviceConfigStatistics(std::move(serviceConfigStatistics))\n{ }\n\nconst xsapi_internal_string&\nUserStatisticsResult::XboxUserId() const\n{\n    return m_xboxUserId;\n}\n\nconst xsapi_internal_vector<ServiceConfigurationStatistic>&\nUserStatisticsResult::ServiceConfigurationStatistics() const\n{\n    return m_serviceConfigStatistics;\n}\n\nvoid\nUserStatisticsResult::SetServiceConfigurationId(_In_ xsapi_internal_string serviceConfigId)\n{\n    for (auto& stat : m_serviceConfigStatistics)\n    {\n        stat.SetServiceConfigurationId(serviceConfigId);\n    }\n}\n\n/* static */ Result<UserStatisticsResult>\nUserStatisticsResult::Deserialize(\n    _In_ const JsonValue& json\n)\n{\n    UserStatisticsResult returnResult;\n    if (json.IsNull())\n    {\n        return returnResult;\n    }\n\n    xsapi_internal_vector<ServiceConfigurationStatistic> serviceConfigStatisticses;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<ServiceConfigurationStatistic>(ServiceConfigurationStatistic::Deserialize, json, \"scids\", serviceConfigStatisticses, false));\n    if (serviceConfigStatisticses.size() == 0)\n    {\n        xsapi_internal_vector<Statistic> statistics;\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<Statistic>(Statistic::Deserialize, json, \"stats\", statistics, false));\n        ServiceConfigurationStatistic serviceConfigStatistics(xsapi_internal_string(), statistics);\n        serviceConfigStatisticses.push_back(serviceConfigStatistics);\n    }\n    xsapi_internal_string xuid;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"xuid\", xuid, true));\n    returnResult = UserStatisticsResult(\n        xuid,\n        serviceConfigStatisticses\n    );\n\n    return Result<UserStatisticsResult>(returnResult, S_OK);\n}\n\nsize_t \nUserStatisticsResult::SizeOf() const\n{\n    size_t size = sizeof(XblUserStatisticsResult);\n    \n    for (ServiceConfigurationStatistic serviceConfigStat : m_serviceConfigStatistics)\n    {\n        size += serviceConfigStat.SizeOf();\n    }\n\n    return size;\n}\nchar*\nUserStatisticsResult::Serialize(char* buffer) const\n{\n    XblUserStatisticsResult* userStatResult = reinterpret_cast<XblUserStatisticsResult*>(buffer);\n    buffer += sizeof(XblUserStatisticsResult);\n    return Serialize(userStatResult, buffer);\n}\n\nchar*\nUserStatisticsResult::Serialize(XblUserStatisticsResult* userStatResult, char* buffer) const\n{\n    userStatResult->xboxUserId = utils::internal_string_to_uint64(m_xboxUserId);\n\n    userStatResult->serviceConfigStatisticsCount = (uint32_t)m_serviceConfigStatistics.size();\n    userStatResult->serviceConfigStatistics = reinterpret_cast<XblServiceConfigurationStatistic*>(buffer);\n    buffer += sizeof(XblServiceConfigurationStatistic) * m_serviceConfigStatistics.size();\n\n    for (size_t i = 0; i < m_serviceConfigStatistics.size(); i++)\n    {\n        buffer = m_serviceConfigStatistics[i].Serialize(&userStatResult->serviceConfigStatistics[i], buffer);\n    }\n\n    return buffer;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/Stats/user_statistics_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"user_statistics_internal.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"real_time_activity_manager.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN\n\nUserStatisticsService::UserStatisticsService(\n    _In_ User&& user,\n    _In_ const TaskQueue& backgroundQueue,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings,\n    _In_ std::shared_ptr<xbox::services::real_time_activity::RealTimeActivityManager> rtaManager\n) noexcept :\n    m_user{ std::move(user) },\n    m_queue{ backgroundQueue.DeriveWorkerQueue() },\n    m_xboxLiveContextSettings{ std::move(xboxLiveContextSettings) },\n    m_rtaManager{ std::move(rtaManager) }\n{\n}\n\nUserStatisticsService::~UserStatisticsService() noexcept\n{\n    if (m_resyncHandlerToken)\n    {\n        m_rtaManager->RemoveResyncHandler(m_user, m_resyncHandlerToken);\n    }\n\n    if (!m_statisticChangeHandlers.empty())\n    {\n        for (auto& userPair : m_trackedStatsByUser)\n        {\n            for (auto& statPair : userPair.second)\n            {\n                m_rtaManager->RemoveSubscription(m_user, statPair.second.subscription);\n            }\n        }\n    }\n}\n\nHRESULT UserStatisticsService::GetSingleUserStatistic(\n    _In_ uint64_t xuid,\n    _In_ const String& scid,\n    _In_ const String& statisticName,\n    _In_ AsyncContext<Result<UserStatisticsResult>> async\n) const noexcept\n{\n    return GetSingleUserStatistics(xuid, scid, Vector<String>{ statisticName }, std::move(async));\n}\n\nHRESULT UserStatisticsService::GetSingleUserStatistics(\n    _In_ uint64_t xuid,\n    _In_ const String& scid,\n    _In_ const Vector<String>& statisticNames,\n    _In_ AsyncContext<Result<UserStatisticsResult>> async\n) const noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(scid.empty());\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"userstats\", UserStatsSubpath(xuid, scid, statisticNames)),\n        xbox_live_api::get_single_user_statistics\n    );\n\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(1));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{\n        async.Queue().DeriveWorkerQueue(),\n            [\n                async,\n                scid\n            ]\n        (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            if (SUCCEEDED(hr))\n            {\n                auto result = UserStatisticsResult::Deserialize(httpResult.Payload()->GetResponseBodyJson());\n                result.Payload().SetServiceConfigurationId(scid);\n                return async.Complete(result);\n            }\n            async.Complete(hr);\n        }});\n}\n\nHRESULT UserStatisticsService::GetMultipleUserStatistics(\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ const String& serviceConfigurationId,\n    _In_ const Vector<String>& statisticNames,\n    _In_ AsyncContext<Result<Vector<UserStatisticsResult>>> async\n) const noexcept\n{\n    return GetMultipleUserStatisticsForMultipleServiceConfigurations(\n        xuids,\n        Vector<RequestedStatistics>{ RequestedStatistics{ serviceConfigurationId, statisticNames } },\n        std::move(async)\n    );\n}\n\nHRESULT UserStatisticsService::GetMultipleUserStatisticsForMultipleServiceConfigurations(\n    _In_ const Vector<uint64_t>& xuids,\n    _In_ const Vector<RequestedStatistics>& requestedServiceConfigurationStatisticsCollection,\n    _In_ AsyncContext<Result<Vector<UserStatisticsResult>>> async\n) const noexcept\n{\n    // Set request body to something like:\n    //{    \n    //    \"requestedusers\": \n    //    [\n    //        \"1234567890123460\",\n    //        \"1234567890123234\"\n    //    ],\n    //    \"requestedscids\": \n    //    [\n    //        {\n    //            \"scid\": \"c402ff50-3e76-11e2-a25f-0800200c1212\",\n    //            \"requestedstats\": \n    //            [\n    //                \"Game4FirefightKills\",\n    //                \"Game4FirefightHeadshots\"\n    //            ]\n    //        },\n    //        {\n    //            \"scid\": \"c402ff50-3e76-11e2-a25f-0800200c0343\",\n    //            \"requestedstats\": \n    //            [\n    //                \"OverallGameKills\",\n    //                \"GameHeadshots\"\n    //            ]\n    //        }\n    //    ] \n    //}\n\n    RETURN_HR_INVALIDARGUMENT_IF(xuids.empty());\n    RETURN_HR_INVALIDARGUMENT_IF(requestedServiceConfigurationStatisticsCollection.empty());\n\n    JsonDocument rootJson{ rapidjson::kObjectType };\n    JsonDocument::AllocatorType& allocator{ rootJson.GetAllocator() };\n\n    JsonValue requestedUsersJsonArray{ rapidjson::kArrayType };\n    JsonUtils::SerializeVector(JsonUtils::JsonXuidSerializer, xuids, requestedUsersJsonArray, allocator);\n    rootJson.AddMember(\"requestedusers\", requestedUsersJsonArray.Move(), allocator);\n\n    //requestedscids\n    JsonValue requestedscidsJson{ rapidjson::kArrayType };\n    for (const auto& request : requestedServiceConfigurationStatisticsCollection)\n    {\n        JsonValue requestedJson{ rapidjson::kObjectType };\n        JsonValue val;\n        val.SetString(request.ServiceConfigurationId().c_str(), allocator);\n        requestedJson.AddMember(\"scid\", val, allocator);\n\n        JsonValue requestedstatsJson{ rapidjson::kArrayType };\n        for (const auto& stat : request.Statistics())\n        {\n            JsonValue statValue;\n            statValue.SetString(stat.c_str(), allocator);\n            requestedstatsJson.PushBack(statValue, allocator);\n        }\n        requestedJson.AddMember(\"requestedstats\", requestedstatsJson, allocator);\n\n        requestedscidsJson.PushBack(requestedJson, allocator);\n    }\n\n    rootJson.AddMember(\"requestedscids\", requestedscidsJson, allocator);\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    RETURN_HR_IF_FAILED(httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"userstats\", \"/batch?operation=read\"),\n        xbox_live_api::get_multiple_user_statistics_for_multiple_service_configurations\n    ));\n\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(1));\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(rootJson)));\n\n    return httpCall->Perform(AsyncContext<HttpResult>{\n        async.Queue().DeriveWorkerQueue(),\n            [\n                async\n            ]\n        (HttpResult httpResult)\n        {\n            HRESULT hr{ Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n            if (SUCCEEDED(hr))\n            {\n                Vector<UserStatisticsResult> result;\n                hr = JsonUtils::ExtractJsonVector<UserStatisticsResult>(\n                    UserStatisticsResult::Deserialize,\n                    httpResult.Payload()->GetResponseBodyJson(),\n                    \"users\",\n                    result,\n                    true\n                );\n\n                return async.Complete({ result, hr });\n            }\n            async.Complete(hr);\n        }});\n}\n\nXblFunctionContext UserStatisticsService::AddStatisticChangedHandler(\n    StatisticChangeHandler handler\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    if (!m_resyncHandlerToken)\n    {\n        m_resyncHandlerToken = m_rtaManager->AddResyncHandler(m_user, [weakThis = std::weak_ptr<UserStatisticsService>{ shared_from_this() }]\n        {\n            auto sharedThis = weakThis.lock();\n            if (sharedThis)\n            {\n                sharedThis->HandleRTAResync();\n            }\n        });\n    }\n\n    // Add subs to RTA manager if needed\n    if (m_statisticChangeHandlers.empty())\n    {\n        for (auto& userPair : m_trackedStatsByUser)\n        {\n            for (auto& statPair : userPair.second)\n            {\n                statPair.second.subscription = MakeShared<StatisticChangeSubscription>(userPair.first, statPair.first.first, statPair.first.second, shared_from_this());\n                m_rtaManager->AddSubscription(m_user, statPair.second.subscription);\n            }\n        }\n    }\n\n    m_statisticChangeHandlers[m_nextToken] = std::move(handler);\n    return m_nextToken++;\n}\n\nvoid UserStatisticsService::RemoveStatisticChangedHandler(\n    XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    auto removed{ m_statisticChangeHandlers.erase(token) };\n\n    // Remove subs if there are no more handlers\n    if (removed && m_statisticChangeHandlers.empty())\n    {\n        for (auto& userPair : m_trackedStatsByUser)\n        {\n            for (auto& statPair : userPair.second)\n            {\n                m_rtaManager->RemoveSubscription(m_user, statPair.second.subscription);\n                statPair.second.subscription.reset();\n            }\n        }\n    }\n}\n\nHRESULT UserStatisticsService::TrackStatistics(\n    _In_ const Vector<uint64_t> xuids,\n    _In_ const String& scid,\n    _In_ const Vector<String>& statNames\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto& xuid : xuids)\n    {\n        auto& userStats{ m_trackedStatsByUser[xuid] };\n        for (auto& statName : statNames)\n        {\n            auto iter{ userStats.find({ scid, statName }) };\n            if (iter == userStats.end())\n            {\n                userStats[{scid, statName}] = SubscriptionHolder{ 1, nullptr };\n\n                // If there are existing handlers, add the new subs to RTA manager\n                if (!m_statisticChangeHandlers.empty())\n                {\n                    auto sub{ MakeShared<StatisticChangeSubscription>(xuid, scid, statName, shared_from_this()) };\n                    userStats[{scid, statName}].subscription = sub;\n                    RETURN_HR_IF_FAILED(m_rtaManager->AddSubscription(m_user, sub));\n                }\n            }\n            else\n            {\n                ++(iter->second.refCount);\n            }\n        }\n    }\n    return S_OK;\n}\n\nHRESULT UserStatisticsService::StopTrackingStatistics(\n    _In_ const Vector<uint64_t> xuids,\n    _In_ const String& scid,\n    _In_ const Vector<String>& statNames\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto& xuid : xuids)\n    {\n        auto& userStats{ m_trackedStatsByUser[xuid] };\n        for (auto& statName : statNames)\n        {\n            auto iter{ userStats.find({ scid, statName }) };\n            if (iter != userStats.end() && --(iter->second.refCount) == 0)\n            {\n                // Remove subs from RTA manager as necessary\n                if (!m_statisticChangeHandlers.empty())\n                {\n                    RETURN_HR_IF_FAILED(m_rtaManager->RemoveSubscription(m_user, iter->second.subscription));\n                }\n                userStats.erase(iter);\n            }\n        }\n    }\n    return S_OK;\n}\n\nHRESULT UserStatisticsService::StopTrackingUsers(\n    _In_ const Vector<uint64_t>& xuids\n) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n\n    for (auto& xuid : xuids)\n    {\n        auto& userStats{ m_trackedStatsByUser[xuid] };\n        for (auto& statPair : userStats)\n        {\n            if (--(statPair.second.refCount) == 0)\n            {\n                // Remove the subs from RTA manager as necessary\n                if (!m_statisticChangeHandlers.empty())\n                {\n                    RETURN_HR_IF_FAILED(m_rtaManager->RemoveSubscription(m_user, statPair.second.subscription));\n                    statPair.second.subscription.reset();\n                }\n            }\n        }\n    }\n    return S_OK;\n}\n\nvoid UserStatisticsService::HandleStatisticChanged(\n    const StatisticChangeEventArgs& args\n) const noexcept\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n    auto handlers{ m_statisticChangeHandlers };\n    lock.unlock();\n\n    for (auto& pair : handlers)\n    {\n        pair.second(args);\n    }\n}\n\nvoid UserStatisticsService::HandleRTAResync()\n{\n    std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n    // Get all stats tracked stats for all tracked users so that we can resync in a single request.\n    // In the request callback, we will only invoke the stat changed handlers for the tracked users/stats\n    Vector<uint64_t> trackedUsers;\n    Vector<RequestedStatistics> trackedStats;\n\n    for (auto& pair : m_trackedStatsByUser)\n    {\n        trackedUsers.push_back(pair.first);\n    }\n    for (auto& pair : m_trackedStatsByScid)\n    {\n        trackedStats.push_back(RequestedStatistics{ pair.first, pair.second });\n    }\n\n    auto weakThis = std::weak_ptr<UserStatisticsService>{ shared_from_this() };\n    auto getStatsCallback = [weakThis, this](Result<Vector<UserStatisticsResult>> result)\n    {\n        auto sharedThis = weakThis.lock();\n        if (!sharedThis)\n        {\n            return;\n        }\n\n        std::unique_lock<std::recursive_mutex> lock{ m_mutex };\n\n        if (Succeeded(result))\n        {\n            Vector<StatisticChangeEventArgs> changeEvents;\n\n            for (auto& userStatsResult : result.Payload())\n            {\n                // Only invoke handler for tracked stats\n                auto trackedUserIter = m_trackedStatsByUser.find(utils::internal_string_to_uint64(userStatsResult.XboxUserId()));\n                if (trackedUserIter != m_trackedStatsByUser.end())\n                {\n                    for (auto& scidStats : userStatsResult.ServiceConfigurationStatistics())\n                    {\n                        for (auto& stat : scidStats.Statistics())\n                        {\n                            auto trackedStatIter = trackedUserIter->second.find({ scidStats.ServiceConfigurationId(), stat.StatisticName() });\n                            if (trackedStatIter != trackedUserIter->second.end())\n                            {\n                                changeEvents.emplace_back(trackedUserIter->first, scidStats.ServiceConfigurationId(), stat.StatisticName(), stat.StatisticType(), stat.Value());\n                            }\n                        }\n                    }\n                }\n            }\n\n            auto statChangedHandlers{ m_statisticChangeHandlers };\n            lock.unlock();\n\n            for (auto& pair : statChangedHandlers)\n            {\n                for (auto& eventArgs : changeEvents)\n                {\n                    pair.second(eventArgs);\n                }\n            }\n        }\n    };\n\n    GetMultipleUserStatisticsForMultipleServiceConfigurations(trackedUsers, trackedStats, AsyncContext<Result<Vector<UserStatisticsResult>>>{ m_queue, std::move(getStatsCallback) });\n}\n\nString UserStatisticsService::UserStatsSubpath(\n    _In_ uint64_t xuid,\n    _In_ const String& serviceConfigurationId,\n    _In_ Vector<String> statNames\n) noexcept\n{\n    Stringstream ss;\n    ss << \"/users/xuid(\" << xuid << \")/scids/\" << serviceConfigurationId  << \"/stats/\";\n\n    for (const auto& statName : statNames)\n    {\n        if (statName != statNames.front())\n        {\n            ss << \",\";\n        }\n        ss << statName;\n    }\n    return ss.str();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END"
  },
  {
    "path": "Source/Services/StringVerify/string_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"string_service_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nStringService::StringService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n) :\n    m_user{ std::move(user) },\n    m_contextSettings{ std::move(contextSettings) }\n{\n}\n\nHRESULT StringService::VerifyStrings(\n    _In_ const xsapi_internal_vector<xsapi_internal_string> stringsToVerify,\n    _In_ AsyncContext<Result<xsapi_internal_vector<VerifyStringResult>>> async\n)\n{\n    if (stringsToVerify.size() == 0) {\n        return E_INVALIDARG;\n    }\n\n    JsonDocument request(rapidjson::kObjectType);\n    JsonValue stringsJson(rapidjson::kArrayType); // = request[_T(\"stringstoVerify\")];\n    for (const auto& stringToVerify : stringsToVerify)\n    {\n        stringsJson.PushBack(JsonValue(stringToVerify.c_str(), request.GetAllocator()).Move(), request.GetAllocator());\n    }\n    request.AddMember(\"stringsToVerify\", stringsJson, request.GetAllocator());\n\n    xsapi_internal_vector<VerifyStringResult> result;\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_contextSettings,\n        \"POST\",\n        XblHttpCall::BuildUrl(\"client-strings\", \"/system/strings/validate\"),\n        xbox_live_api::verify_strings\n    );\n\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(2));\n    RETURN_HR_IF_FAILED(httpCall->SetRequestBody(JsonUtils::SerializeJson(request)));\n\n    return httpCall->Perform({\n       async.Queue(),\n       [\n           async,\n           result\n       ]\n    (HttpResult httpResult)\n    {\n       HRESULT hr { Failed(httpResult) ? httpResult.Hresult() : httpResult.Payload()->Result() };\n       if (FAILED(hr))\n       {\n            return async.Complete(hr);\n       }\n\n       return async.Complete(VerifyStringResult::DeserializeVerifyStringsResult(\n           httpResult.Payload()->GetResponseBodyJson()));\n    } });\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\nSTDAPI XblStringVerifyStringAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ const char* stringToVerify,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || stringToVerify == nullptr || async == nullptr);\n\n    return XblStringVerifyStringsAsync(xboxLiveContextHandle, &stringToVerify, 1, async);\n}\nCATCH_RETURN()\n\nSTDAPI XblStringVerifyStringResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(asyncBlock, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblStringVerifyStringResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblVerifyStringResult** ptrToBuffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n    auto hr = XAsyncGetResult(asyncBlock, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblVerifyStringResult*>(buffer);\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblStringVerifyStringsAsync(\n    _In_ XblContextHandle xboxLiveContextHandle,\n    _In_ const char** stringsToVerify,\n    _In_ const uint64_t stringsCount,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    xsapi_internal_vector<xsapi_internal_string> strings;\n    for (uint32_t i = 0; i < stringsCount; i++) {\n        strings.push_back(xsapi_internal_string(stringsToVerify[i]));\n    }\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContextHandle == nullptr || stringsToVerify == nullptr || async == nullptr);\n    return RunAsync(async, __FUNCTION__,\n        [\n            xboxLiveContext{ xboxLiveContextHandle->shared_from_this() },\n            strings,\n            verifyStringResults = xsapi_internal_vector<VerifyStringResult>{}\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            HRESULT hr = xboxLiveContext->StringService()->VerifyStrings(\n                std::move(strings),\n                AsyncContext<Result<xsapi_internal_vector<VerifyStringResult>>>{\n                data->async->queue,\n                    [\n                        &verifyStringResults,\n                        asyncBlock{ data->async }\n                    ]\n                (Result<xsapi_internal_vector<VerifyStringResult>> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        auto payload = result.ExtractPayload();\n                        size_t bufferSize = 0;\n                        if (!payload.empty())\n                        {\n                            for (size_t i = 0; i < payload.size(); i++)\n                            {\n                                verifyStringResults.push_back(payload[i]);\n                                bufferSize += payload[i].SizeOf();\n                            }\n\n                            // Add some padding at the end of the buffer to store the number of XblVerifyStringResult\n                            // objects since there is no way to deduce it just from the buffer size\n                            bufferSize += sizeof(size_t);\n\n                            // size must be rounded up to support word aligned data because of the arbitrary length string packing\n                            // we won't actually use the extra space, but this will report that it is how much is needed\n                            bufferSize = static_cast<size_t>((bufferSize + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n\n                            XAsyncComplete(asyncBlock, result.Hresult(), bufferSize);\n                        }\n                        else {\n                            XAsyncComplete(asyncBlock, E_FAIL, 0);\n                        }\n                    }\n                    else\n                    {\n                        XAsyncComplete(asyncBlock, result.Hresult(), 0);\n                    }\n                }\n            });\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        case XAsyncOp::GetResult:\n        {\n            char* buffer = static_cast<char*>(data->buffer);\n            ZeroMemory(buffer, data->bufferSize);\n            auto resultPtr = reinterpret_cast<XblVerifyStringResult*>(buffer);\n            auto stringPtr = buffer + (sizeof(XblVerifyStringResult)*verifyStringResults.size());\n            size_t bufferSize{ sizeof(size_t) };\n\n            for (auto& verifyStringResult : verifyStringResults)\n            {\n                bufferSize += verifyStringResult.SizeOf();\n                resultPtr->resultCode = verifyStringResult.ResultCode();\n                if (resultPtr->resultCode != XblVerifyStringResultCode::Success)\n                {\n                    utils::strcpy(stringPtr, verifyStringResult.FirstOffendingSubstring().size() + 1, verifyStringResult.FirstOffendingSubstring().c_str());\n                    resultPtr->firstOffendingSubstring = stringPtr;\n                    stringPtr += verifyStringResult.FirstOffendingSubstring().size() + 1;\n                }\n                else\n                {\n                    resultPtr->firstOffendingSubstring = nullptr;\n                }\n                \n                resultPtr++;\n            }\n\n            // Calculate buffer used plus padding (to stay word aligned, see above)\n            bufferSize = static_cast<size_t>((bufferSize + XBL_ALIGN_SIZE - 1) / XBL_ALIGN_SIZE) * XBL_ALIGN_SIZE;\n            size_t* resultArrSize = reinterpret_cast<size_t*>(buffer + bufferSize) - 1;\n            *resultArrSize = verifyStringResults.size();\n        }\n\n        default: return S_OK;\n\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblStringVerifyStringsResultSize(\n    _In_ XAsyncBlock* asyncBlock,\n    _Out_ size_t* resultSizeInBytes\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResultSize(asyncBlock, resultSizeInBytes);\n}\nCATCH_RETURN()\n\nSTDAPI XblStringVerifyStringsResult(\n    _In_ XAsyncBlock* asyncBlock,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XblVerifyStringResult** ptrToBuffer,\n    _Out_ size_t* stringsCount,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(ptrToBuffer);\n\n    size_t bufferUsedTemp{};\n    if (bufferUsed == nullptr)\n    {\n        bufferUsed = &bufferUsedTemp;\n    }\n\n    auto hr = XAsyncGetResult(asyncBlock, nullptr, bufferSize, buffer, bufferUsed);\n    if (SUCCEEDED(hr))\n    {\n        *ptrToBuffer = static_cast<XblVerifyStringResult*>(buffer);\n        auto sizePtr = reinterpret_cast<size_t*>(static_cast<char*>(buffer) + *bufferUsed) - 1;\n        *stringsCount = *sizePtr;\n    }\n    return hr;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/StringVerify/string_service_internal.h",
    "content": "#pragma once\n#include \"xsapi-c/string_verify_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nclass VerifyStringResult\n{\npublic:\n    VerifyStringResult();\n\n    VerifyStringResult(\n        XblVerifyStringResultCode resultCode,\n        xsapi_internal_string firstOffendingSubstring\n    );\n\n    const XblVerifyStringResultCode ResultCode() const;\n\n    const xsapi_internal_string& FirstOffendingSubstring() const;\n\n    static Result<xsapi_internal_vector<VerifyStringResult>> DeserializeVerifyStringsResult(\n        _In_ const JsonValue& json\n    );\n\n    size_t SizeOf() const;\n\nprivate:\n    XblVerifyStringResultCode m_resultCode = XblVerifyStringResultCode::Success;\n    xsapi_internal_string m_firstOffendingSubstring;\n    \n    static Result<VerifyStringResult> DeserializeVerifyStringResult(\n        _In_ const JsonValue& json\n    );\n\n};\n\nclass StringService : public std::enable_shared_from_this<StringService>\n{\n\npublic:\n    StringService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> contextSettings\n    );\n\n    HRESULT VerifyStrings(\n        _In_ const xsapi_internal_vector<xsapi_internal_string> stringsToVerify,\n        _In_ AsyncContext<Result<xsapi_internal_vector<VerifyStringResult>>> async\n    );\n\nprivate:\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_contextSettings;\n};\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/Services/StringVerify/verify_string_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"string_service_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\nVerifyStringResult::VerifyStringResult()\n{\n\n}\n\nVerifyStringResult::VerifyStringResult(\n    XblVerifyStringResultCode resultCode,\n    xsapi_internal_string firstOffendingSubstring\n) :\n    m_resultCode(resultCode),\n    m_firstOffendingSubstring(firstOffendingSubstring)\n{\n}\n\nconst XblVerifyStringResultCode VerifyStringResult::ResultCode() const\n{\n    return m_resultCode;\n}\n\nconst xsapi_internal_string& VerifyStringResult::FirstOffendingSubstring() const\n{\n    return m_firstOffendingSubstring;\n}\n\nsize_t VerifyStringResult::SizeOf() const\n{\n    size_t size = sizeof(XblVerifyStringResult);\n    if (m_resultCode != XblVerifyStringResultCode::Success)\n    {\n        size += m_firstOffendingSubstring.length() + 1;\n    }\n    return size;\n}\n\n/*static*/ Result<xsapi_internal_vector<VerifyStringResult>> VerifyStringResult::DeserializeVerifyStringsResult(\n    _In_ const JsonValue& json\n)\n{\n    if (json.IsNull())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    HRESULT errc = S_OK;\n    xsapi_internal_vector<VerifyStringResult> resultVector;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<VerifyStringResult>(\n        VerifyStringResult::DeserializeVerifyStringResult,\n        json,\n        \"verifyStringResult\",\n        resultVector,\n        true\n        ));\n\n    return Result<xsapi_internal_vector<VerifyStringResult>> {resultVector, errc};\n}\n\n/*static*/ Result<VerifyStringResult> VerifyStringResult::DeserializeVerifyStringResult(\n    _In_ const JsonValue& json\n)\n{\n    VerifyStringResult returnResult;\n    if (json.IsNull())\n    {\n        return returnResult;\n    }\n\n\tint32_t resultCode = 0;\n    xsapi_internal_string offendingString;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, \"resultCode\", resultCode));\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"offendingString\", offendingString));\n    returnResult = VerifyStringResult(\n        static_cast<XblVerifyStringResultCode>(resultCode),\n        offendingString\n    );\n\n    return Result<VerifyStringResult>(returnResult, S_OK);\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/Services/TCUI/Android/title_callable_static_glue.h",
    "content": "#pragma once\nbool title_callable_ui_register_natives(JNIEnv *env, jobject clsLoader, jmethodID loadClass);"
  },
  {
    "path": "Source/Services/TCUI/Android/title_callable_ui_android.cpp",
    "content": "//*********************************************************\n//\n// Copyright (c) Microsoft. All rights reserved.\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n#include \"pch.h\"\n#include \"xsapi-cpp/title_callable_ui.h\"\n#include \"a/java_interop.h\"\n#include \"a/jni_utils.h\"\n#include \"TCUI/Android/title_callable_ui_jni.h\"\n\nusing namespace pplx;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nbool title_callable_ui_internal::s_isTcuiRunning = false;\npplx::task_completion_event<int32_t> title_callable_ui_internal::s_tcuiEventCompleted;\n\nvoid\ntitle_callable_ui_internal::tcui_completed_callback(JNIEnv *, jclass, int errorCode)\n{\n    s_tcuiEventCompleted.set(errorCode);\n}\n\nxbox_live_result<std::shared_ptr<java_interop>>\ntcui_init()\n{\n    if (title_callable_ui_internal::s_isTcuiRunning)\n    {\n        return xbox_live_result<std::shared_ptr<java_interop>>(xbox_live_result<std::shared_ptr<java_interop>>(\n            xbox_live_error_code::logic_error,\n            _T(\"Previous tcui operation has not been completed\"))\n            );\n    }\n\n    std::shared_ptr<java_interop> interop = java_interop::get_java_interop_singleton();\n    if (interop == nullptr)\n    {\n        return xbox_live_result<std::shared_ptr<java_interop>>(xbox_live_result<std::shared_ptr<java_interop>>(\n            xbox_live_error_code::logic_error,\n            _T(\"XSAPI has not been initialized with the JVM\"))\n            );\n    }\n\n    title_callable_ui_internal::s_tcuiEventCompleted = task_completion_event<int32_t>();\n    return interop;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_profile_card_ui(\n    _In_ const string_t& targetXboxUserId,\n    _In_ xbox_live_user_t user\n)\n{\n    XblAddServiceCallRoutedHandler(\n        [](XblServiceCallRoutedArgs args, void* context)\n        {\n\n        LOG_DEBUG(args.fullResponseFormatted);\n        },\n        nullptr\n    );\n\n    auto interopResult = tcui_init();\n\n    if (interopResult.err())\n    {\n        return pplx::task_from_result<xbox::services::xbox_live_result<void>>(\n            xbox_live_result<void>(\n                interopResult.err(),\n                interopResult.err_message()\n                )\n            );\n    }\n    auto task = pplx::create_task(title_callable_ui_internal::s_tcuiEventCompleted)\n    .then([](int32_t errorCode)\n    {\n        title_callable_ui_internal::s_isTcuiRunning = false;\n        (void) java_interop::get_java_interop_singleton()->ExtractStoredUser();\n        return xbox_live_result<void>(xbox_live_result<void>());\n    });\n\n    auto interop = interopResult.payload();\n    auto jvm = interop->get_java_vm();\n    JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, \"java interop not initialized properly\")\n\n    auto interopTcuiClass = interop->get_tcui_interop_class();\n    auto activity = interop->get_activity();\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(jvm, jniEnv);\n\n    jmethodID showProfileCardUIMethodId = jniEnv->GetStaticMethodID(interopTcuiClass, \"ShowProfileCardUI\", \"(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n    auto wrapUserResult = User::WrapHandle(user);\n    if (showProfileCardUIMethodId != NULL && Succeeded(wrapUserResult))\n    {\n        java_interop::get_java_interop_singleton()->StoreUser(wrapUserResult.ExtractPayload());\n        title_callable_ui_internal::s_isTcuiRunning = true;\n\n        uint64_t xuid;\n        XalUserGetId(user, &xuid);\n        xsapi_internal_stringstream xuidSS;\n        xuidSS << xuid;\n\n        // The only privileges that are needed for TCUI are 254 (Communications) and 255 (AddFriends) so just query those here\n        xsapi_internal_stringstream privilegesSS;\n        bool hasPrivilege;\n        XalUserCheckPrivilege(user, XalPrivilege::XalPrivilege_Comms, &hasPrivilege, nullptr);\n        if (hasPrivilege)\n        {\n            privilegesSS << XalPrivilege::XalPrivilege_Comms;\n        }\n        XalUserCheckPrivilege(user, XalPrivilege::XalPrivilege_AddFriends, &hasPrivilege, nullptr);\n        if (hasPrivilege)\n        {\n            privilegesSS << \" \" << XalPrivilege::XalPrivilege_AddFriends;\n        }\n\n        auto currentUserIdString = jniEnv->NewStringUTF(xuidSS.str().data());\n        auto targetUserIdString = jniEnv->NewStringUTF(targetXboxUserId.c_str());\n        auto currentUserPrivileges = jniEnv->NewStringUTF(privilegesSS.str().data());\n        jniEnv->CallStaticVoidMethod(interopTcuiClass, showProfileCardUIMethodId, activity, currentUserIdString, targetUserIdString, currentUserPrivileges, user);\n    }\n    else\n    {\n        pplx::task_from_result<xbox_live_result<void>>(xbox_live_result<void>(\n            xbox_live_error_code::logic_error,\n            _T(\"ShowProfileCardUI method not found\"))\n            );\n    }\n\n    JNI_ERROR_CHECK(jniEnv)\n\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_user_profile_ui(\n    _In_ const string_t& targetXboxUserId\n)\n{\n    auto interopResult = tcui_init();\n    if (interopResult.err())\n    {\n        return pplx::task_from_result<xbox::services::xbox_live_result<void>>(\n            xbox_live_result<void>(\n                interopResult.err(),\n                interopResult.err_message()\n                )\n            );\n    }\n\n    auto task = pplx::create_task(title_callable_ui_internal::s_tcuiEventCompleted)\n    .then([](int32_t errorCode)\n    {\n        title_callable_ui_internal::s_isTcuiRunning = false;\n        return xbox_live_result<void>(xbox_live_result<void>());\n    });\n\n    auto interop = interopResult.payload();\n    auto jvm = interop->get_java_vm();\n    JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, \"java interop not initialized properly\")\n\n    auto interopTcuiClass = interop->get_tcui_interop_class();\n    auto activity = interop->get_activity();\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(jvm, jniEnv);\n    jmethodID showUserProfileMethodId = jniEnv->GetStaticMethodID(interopTcuiClass, \"ShowUserProfile\", \"(Landroid/content/Context;Ljava/lang/String;J)V\");\n    if (showUserProfileMethodId != NULL)\n    {\n        auto targetXuid = jniEnv->NewStringUTF(targetXboxUserId.c_str());\n        jniEnv->CallStaticVoidMethod(interopTcuiClass, showUserProfileMethodId, activity, targetXuid);\n    }\n\n    JNI_ERROR_CHECK(jniEnv);\n\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_title_hub_ui()\n{\n    auto interopResult = tcui_init();\n    if (interopResult.err())\n    {\n        return pplx::task_from_result<xbox::services::xbox_live_result<void>>(\n            xbox_live_result<void>(\n                interopResult.err(),\n                interopResult.err_message()\n                )\n            );\n    }\n\n    auto task = pplx::create_task(title_callable_ui_internal::s_tcuiEventCompleted)\n    .then([](int32_t errorCode)\n    {\n        title_callable_ui_internal::s_isTcuiRunning = false;\n        return xbox_live_result<void>(xbox_live_result<void>());\n    });\n\n    auto interop = interopResult.payload();\n    auto jvm = interop->get_java_vm();\n    JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, \"java interop not initialized properly\")\n\n    auto interopTcuiClass = interop->get_tcui_interop_class();\n    auto activity = interop->get_activity();\n    auto titleId = AppConfig::Instance()->TitleId();\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(jvm, jniEnv);\n    jmethodID showTitleHubMethodId = jniEnv->GetStaticMethodID(interopTcuiClass, \"ShowTitleHub\", \"(Landroid/content/Context;Ljava/lang/String;)V\");\n    if (showTitleHubMethodId != NULL)\n    {\n        stringstream_t titleIdStr;\n        titleIdStr << titleId;\n        auto jTitleId = jniEnv->NewStringUTF(titleIdStr.str().c_str());\n        jniEnv->CallStaticVoidMethod(interopTcuiClass, showTitleHubMethodId, activity, jTitleId);\n    }\n\n    JNI_ERROR_CHECK(jniEnv);\n\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_title_achievements_ui(\n    _In_ uint32_t titleId\n    )\n{\n    auto interopResult = tcui_init();\n    if (interopResult.err())\n    {\n        return pplx::task_from_result<xbox::services::xbox_live_result<void>>(\n            xbox_live_result<void>(\n                interopResult.err(),\n                interopResult.err_message()\n            )\n        );\n    }\n\n    auto task = pplx::create_task(title_callable_ui_internal::s_tcuiEventCompleted)\n    .then([](int32_t errorCode)\n    {\n        title_callable_ui_internal::s_isTcuiRunning = false;\n        return xbox_live_result<void>(xbox_live_result<void>());\n    });\n\n    auto interop = interopResult.payload();\n    auto jvm = interop->get_java_vm();\n    JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, \"java interop not initialized properly\")\n\n    auto interopTcuiClass = interop->get_tcui_interop_class();\n    auto activity = interop->get_activity();\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(jvm, jniEnv);\n    jmethodID showTitleAchievementsMethodId = jniEnv->GetStaticMethodID(interopTcuiClass, \"ShowTitleAchievements\", \"(Landroid/content/Context;Ljava/lang/String;)V\");\n    if (showTitleAchievementsMethodId != NULL)\n    {\n        stringstream_t titleIdStr;\n        titleIdStr << titleId;\n        auto jTitleId = jniEnv->NewStringUTF(titleIdStr.str().c_str());\n        jniEnv->CallStaticVoidMethod(interopTcuiClass, showTitleAchievementsMethodId, activity, jTitleId);\n    }\n\n    JNI_ERROR_CHECK(jniEnv);\n\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_user_settings_ui()\n{\n    auto interopResult = tcui_init();\n    if (interopResult.err())\n    {\n        return pplx::task_from_result<xbox::services::xbox_live_result<void>>(\n            xbox_live_result<void>(\n                interopResult.err(),\n                interopResult.err_message()\n                )\n            );\n    }\n\n    auto task = pplx::create_task(title_callable_ui_internal::s_tcuiEventCompleted)\n    .then([](int32_t errorCode)\n    {\n        title_callable_ui_internal::s_isTcuiRunning = false;\n        return xbox_live_result<void>(xbox_live_result<void>());\n    });\n\n    auto interop = interopResult.payload();\n    auto jvm = interop->get_java_vm();\n    JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, \"java interop not initialized properly\")\n\n    auto interopTcuiClass = interop->get_tcui_interop_class();\n    auto context = interop->get_context_object();\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(jvm, jniEnv);\n    jmethodID showUserSettingsMethodId = jniEnv->GetStaticMethodID(interopTcuiClass, \"ShowUserSettings\", \"(Landroid/content/Context;)V\");\n    if (showUserSettingsMethodId != NULL)\n    {\n        jniEnv->CallStaticVoidMethod(interopTcuiClass, showUserSettingsMethodId, context);\n    }\n\n    JNI_ERROR_CHECK(jniEnv);\n\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_add_friends_ui()\n{\n    auto interopResult = tcui_init();\n    if (interopResult.err())\n    {\n        return pplx::task_from_result<xbox::services::xbox_live_result<void>>(\n            xbox_live_result<void>(\n                interopResult.err(),\n                interopResult.err_message()\n                )\n            );\n    }\n\n    auto task = pplx::create_task(title_callable_ui_internal::s_tcuiEventCompleted)\n        .then([](int32_t errorCode)\n    {\n        title_callable_ui_internal::s_isTcuiRunning = false;\n        return xbox_live_result<void>(xbox_live_result<void>());\n    });\n\n    auto interop = interopResult.payload();\n    auto jvm = interop->get_java_vm();\n    JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, \"java interop not initialized properly\")\n\n    auto interopTcuiClass = interop->get_tcui_interop_class();\n    auto context = interop->get_context_object();\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(jvm, jniEnv);\n    jmethodID showAddFriendsMethodId = jniEnv->GetStaticMethodID(interopTcuiClass, \"ShowAddFriends\", \"(Landroid/content/Context;)V\");\n    if (showAddFriendsMethodId != NULL)\n    {\n        jniEnv->CallStaticVoidMethod(interopTcuiClass, showAddFriendsMethodId, context);\n    }\n\n    JNI_ERROR_CHECK(jniEnv);\n\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<std::vector<string_t>>>\ntitle_callable_ui::show_player_picker_ui(\n    _In_ const string_t& promptDisplayText,\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ const std::vector<string_t>& preselectedXboxUserIds,\n    _In_ uint32_t minSelectionCount,\n    _In_ uint32_t maxSelectionCount\n    )\n{\n    return pplx::task_from_result<xbox::services::xbox_live_result<std::vector<string_t>>>(xbox::services::xbox_live_result<std::vector<string_t>>(xbox_live_error_code::unsupported));\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_game_invite_ui(\n    _In_ const xbox::services::multiplayer::multiplayer_session_reference& sessionReference,\n    _In_ const string_t& invitationDisplayText,\n    _In_ const string_t& contextStringId\n    )\n{\n    return pplx::task_from_result<xbox::services::xbox_live_result<void>>(xbox::services::xbox_live_result<void>(xbox_live_error_code::unsupported));\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_change_friend_relationship_ui(\n    _In_ const string_t& targetXboxUserId\n    )\n{\n    return pplx::task_from_result<xbox::services::xbox_live_result<void>>(xbox::services::xbox_live_result<void>(xbox_live_error_code::unsupported));\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Source/Services/TCUI/Android/title_callable_ui_jni.h",
    "content": "#pragma once\nnamespace xbox { namespace services { namespace system { \nclass title_callable_ui_internal\n{\npublic:\n    static void tcui_completed_callback(JNIEnv *, jclass, int errorCode);\n    static pplx::task_completion_event<int32_t> s_tcuiEventCompleted;\n    static bool s_isTcuiRunning;\n};\n} } }\n\n"
  },
  {
    "path": "Source/Services/TCUI/Android/title_callable_ui_static_glue.cpp",
    "content": "#include \"pch.h\"\n#include \"TCUI/Android/title_callable_ui_jni.h\"\n#include <android/log.h>\n#include \"a/jni_utils.h\"\n\n#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, \"XSAPI.Android\", __VA_ARGS__))\n#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"XSAPI.Android\", __VA_ARGS__))\n\nJNINativeMethod tcuiMethods[] =\n{\n    {\n        \"tcui_completed_callback\",\n        \"(I)V\",\n        (void*)&xbox::services::system::title_callable_ui_internal::tcui_completed_callback\n    },\n};\n\nbool title_callable_ui_register_natives(JNIEnv *env, jobject clsLoader, jmethodID loadClass)\n{\n    jstring clsName = env->NewStringUTF(\"com/microsoft/xboxtcui/Interop\");\n    JNI_ERROR_CHECK(env);\n    jclass cls = (jclass)env->CallObjectMethod(clsLoader, loadClass, clsName);\n    env->DeleteLocalRef(clsName);\n    if (cls == NULL) {\n        LOGE(\"Failed to load class com/microsoft/xboxtcui/Interop\");\n        return false;\n    }\n    auto size = (sizeof tcuiMethods / sizeof *tcuiMethods);\n\n    if (env->RegisterNatives(cls, tcuiMethods, size) != 0) {\n        LOGE(\"Failed to register native tcuiMethods\");\n        env->DeleteLocalRef(cls);\n        return false;\n    }\n    env->DeleteLocalRef(cls);\n    LOGD(\"Successfully registerered HttpCall tcuiMethods\");\n    return true;\n}"
  },
  {
    "path": "Source/Services/TCUI/iOS/title_callable_ui.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"xsapi-cpp/system.h\"\n#include \"xsapi-cpp/title_callable_ui.h\"\n#import \"XBLServiceManager.h\"\n#import <XSAPITCUI/XSAPITCUI.h>\n#import <XSAPITCUI/XBLService.h>\n\nstatic NSString *const XboxAppStoreLink = @\"itms-apps://itunes.apple.com/app/xbox-one-smartglass/id736179781?mt=8\";\nusing namespace pplx;\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\npplx::task<xbox_live_result<void>>\ntitle_callable_ui::show_profile_card_ui(\n                     _In_ const string_t& targetXboxUserId,\n                     _In_ xbox_live_user_t user\n                     )\n{\n    auto completionEvent = pplx::task_completion_event<xbox_live_result<void>>();\n    \n    XBLServiceManager *manager = [[XBLServiceManager alloc] init];\n    [manager setUser:user];\n    [XBLService setUpWithServiceManager:manager];\n    [TCUIManager displayProfileCard:manager.userXuid youXuid:[NSString stringWithUTF8String:targetXboxUserId.c_str()] canAddFriend: manager.privilegeForAddFriend completionBlock:^{\n        completionEvent.set(xbox_live_result<void>());\n    }];\n    \n    return create_task(completionEvent);\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_user_profile_ui(_In_ const string_t& targetXboxUserId)\n{\n    auto completionEvent = pplx::task_completion_event<xbox_live_result<void>>();\n    auto task = create_task(completionEvent);\n    /* TODO 1808\n    XLSCll *telemetry = [XLSCll sharedTelemetryManager];\n    \n    NSString *deeplink = [NSString stringWithFormat:@\"smartglass://profile?xuid=%@&deepLinkId=%@&deepLinkCaller=%@\", [NSString stringWithUTF8String:targetXboxUserId.c_str()], [telemetry getAppSessionId], [telemetry getAppBundleName]];\n\n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:deeplink]])\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_UserProfile withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                                  @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                                  @\"targetXUID\" : [NSString stringWithFormat:@\"x:%@\",[NSString stringWithUTF8String:targetXboxUserId.c_str()]]}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:deeplink]];\n    }\n    else\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_SendToStore withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                                  @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                                  @\"intendedAction\" : IDP_PageAction_DeepLink_UserProfile}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:XboxAppStoreLink]];\n    }\n     */\n    completionEvent.set(xbox_live_result<void>());\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_title_hub_ui()\n{\n    auto completionEvent = pplx::task_completion_event<xbox_live_result<void>>();\n    auto task = create_task(completionEvent);\n    /* TODO 1808\n    auto titleId = xbox_live_app_config::get_app_config_singleton()->title_id();\n    XLSCll *telemetry = [XLSCll sharedTelemetryManager];\n    \n    NSString *deeplink = [NSString stringWithFormat:@\"smartglass://game?titleid=%u&deepLinkId=%@&deepLinkCaller=%@\", titleId, [telemetry getAppSessionId], [telemetry getAppBundleName]];\n    \n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:deeplink]])\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_TitleHub withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                               @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                               @\"targetTitleId\" : [NSNumber numberWithInt:titleId]}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:deeplink]];\n\n    }\n    else\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_SendToStore withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                                  @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                                  @\"intendedAction\" : IDP_PageAction_DeepLink_TitleHub}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:XboxAppStoreLink]];\n    }\n    \n     */\n    completionEvent.set(xbox_live_result<void>());\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_title_achievements_ui(_In_ uint32_t titleId)\n{\n    auto completionEvent = pplx::task_completion_event<xbox_live_result<void>>();\n    auto task = create_task(completionEvent);\n    /* TODO 1808\n    XLSCll *telemetry = [XLSCll sharedTelemetryManager];\n\n    NSString *deeplink = [NSString stringWithFormat:@\"smartglass://achievement?titleid=%u&deepLinkId=%@&deepLinkCaller=%@\", titleId, [telemetry getAppSessionId], [telemetry getAppBundleName]];\n    \n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:deeplink]])\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_TitleAchievements withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                               @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                               @\"targetTitleId\" : [NSNumber numberWithInt:titleId]}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:deeplink]];\n    }\n    else\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_SendToStore withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                                  @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                                  @\"intendedAction\" : IDP_PageAction_DeepLink_TitleAchievements}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:XboxAppStoreLink]];\n    }\n    \n     */\n    completionEvent.set(xbox_live_result<void>());\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_user_settings_ui()\n{\n    auto completionEvent = pplx::task_completion_event<xbox_live_result<void>>();\n    auto task = create_task(completionEvent);\n     /* TODO 1808\n    XLSCll *telemetry = [XLSCll sharedTelemetryManager];\n\n    NSString *deeplink = [NSString stringWithFormat:@\"smartglass://settings?deepLinkId=%@&deepLinkCaller=%@\", [telemetry getAppSessionId], [telemetry getAppBundleName]];\n     \n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:deeplink]])\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_UserSettings withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                                    @\"deepLinkCaller\" : [telemetry getAppBundleName]}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:deeplink]];\n    }\n    else\n    {\n        [telemetry pageActionEvent:IDP_PageAction_DeepLink_SendToStore withData:@{@\"deepLinkId\" : [telemetry getAppSessionId],\n                                                                                  @\"deepLinkCaller\" : [telemetry getAppBundleName],\n                                                                                  @\"intendedAction\" : IDP_PageAction_DeepLink_UserSettings}];\n        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:XboxAppStoreLink]];\n    }\n    \n      */\n    completionEvent.set(xbox_live_result<void>());\n    return task;\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_add_friends_ui()\n{\n     return pplx::task_from_result<xbox::services::xbox_live_result<void>>(xbox::services::xbox_live_result<void>(xbox_live_error_code::unsupported));\n}\n\npplx::task<xbox::services::xbox_live_result<std::vector<string_t>>>\ntitle_callable_ui::show_player_picker_ui(\n    _In_ const string_t& promptDisplayText,\n    _In_ const std::vector<string_t>& xboxUserIds,\n    _In_ const std::vector<string_t>& preselectedXboxUserIds,\n    _In_ uint32_t minSelectionCount,\n    _In_ uint32_t maxSelectionCount\n    )\n{\n    return pplx::task_from_result<xbox::services::xbox_live_result<std::vector<string_t>>>(xbox::services::xbox_live_result<std::vector<string_t>>(xbox_live_error_code::unsupported));\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_game_invite_ui(\n    _In_ const xbox::services::multiplayer::multiplayer_session_reference& sessionReference,\n    _In_ const string_t& invitationDisplayText,\n    _In_ const string_t& contextStringId\n    )\n{\n    return pplx::task_from_result<xbox::services::xbox_live_result<void>>(xbox::services::xbox_live_result<void>(xbox_live_error_code::unsupported));\n}\n\npplx::task<xbox::services::xbox_live_result<void>>\ntitle_callable_ui::show_change_friend_relationship_ui(\n    _In_ const string_t& targetXboxUserId\n    )\n{\n    return pplx::task_from_result<xbox::services::xbox_live_result<void>>(xbox::services::xbox_live_result<void>(xbox_live_error_code::unsupported));\n}\n"
  },
  {
    "path": "Source/Services/TitleStorage/title_storage_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-c/title_storage_c.h\"\n#include \"title_storage_internal.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::title_storage;\n\nSTDAPI XblTitleStorageBlobMetadataResultGetItems(\n    _In_ XblTitleStorageBlobMetadataResultHandle resultHandle,\n    _Out_ const XblTitleStorageBlobMetadata** items,\n    _Out_ size_t* itemsCount\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(resultHandle == nullptr || items == nullptr || itemsCount == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    *items = resultHandle->Items().data();\n    *itemsCount = resultHandle->Items().size();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageBlobMetadataResultHasNext(\n    _In_ XblTitleStorageBlobMetadataResultHandle resultHandle,\n    _Out_ bool* hasNext\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(resultHandle == nullptr || hasNext == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    *hasNext = resultHandle->HasNext();\n    \n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageBlobMetadataResultGetNextAsync(\n    _In_ XblTitleStorageBlobMetadataResultHandle resultHandle,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(resultHandle == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    std::shared_ptr<XblTitleStorageBlobMetadataResult> cResult{ nullptr };\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            resultHandle,\n            maxItems,\n            async,\n            cResult\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            HRESULT hr = resultHandle->GetNext(\n                maxItems,\n                AsyncContext<Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>>\n                (async->queue, [async, &cResult](Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>> result)\n            {\n                if (Succeeded(result))\n                {\n                    cResult = result.ExtractPayload();\n                }\n\n                XAsyncComplete(async, result.Hresult(), sizeof(XblTitleStorageBlobMetadataResultHandle));\n            }\n            ));\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            auto resultHandlePtr = static_cast<XblTitleStorageBlobMetadataResultHandle*>(data->buffer);\n            *resultHandlePtr = cResult.get();\n            cResult->AddRef();\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageBlobMetadataResultGetNextResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadataResultHandle* result\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(result == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    return XAsyncGetResult(async, nullptr, sizeof(XblTitleStorageBlobMetadataResultHandle), result, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageBlobMetadataResultDuplicateHandle(\n    _In_ XblTitleStorageBlobMetadataResultHandle handle,\n    _Out_ XblTitleStorageBlobMetadataResultHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(handle == nullptr || duplicatedHandle == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    handle->AddRef();\n    *duplicatedHandle = handle;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblTitleStorageBlobMetadataResultCloseHandle(\n    _In_ XblTitleStorageBlobMetadataResultHandle handle\n) XBL_NOEXCEPT\ntry\n{\n    if (handle)\n    {\n        handle->DecRef();\n    }\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblTitleStorageGetQuotaAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ XblTitleStorageType storageType,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || serviceConfigurationId == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    XblTitleStorageQuota cResult;\n\n    \n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            scid{ xsapi_internal_string(serviceConfigurationId) },\n            storageType,\n            async,\n            cResult\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            HRESULT hr = xblContext->TitleStorageService()->GetQuota(\n                scid, \n                storageType, \n                AsyncContext<Result<XblTitleStorageQuota>>\n                (async->queue, [async, &cResult](Result<XblTitleStorageQuota> result) \n                {\n                    if (Succeeded(result))\n                    {\n                        cResult = result.ExtractPayload();\n                    }\n                    \n                    XAsyncComplete(async, result.Hresult(), sizeof(XblTitleStorageQuota));\n                }\n            ));\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            auto resultHandle = static_cast<XblTitleStorageQuota*>(data->buffer);\n            *resultHandle = std::move(cResult);\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageGetQuotaResult(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* usedBytes,\n    _Out_ size_t* quotaBytes\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(async == nullptr || usedBytes == nullptr || quotaBytes == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    XblTitleStorageQuota quota{};\n    HRESULT hr = XAsyncGetResult(async, nullptr, sizeof(XblTitleStorageQuota), &quota, nullptr);\n\n    if (SUCCEEDED(hr))\n    {\n        *usedBytes = quota.usedBytes;\n        *quotaBytes = quota.quotaBytes;\n    }\n\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageGetBlobMetadataAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_z_ const char* serviceConfigurationId,\n    _In_ XblTitleStorageType storageType,\n    _In_z_ const char* blobPath,\n    _In_ uint64_t xuid,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || serviceConfigurationId == nullptr || async == nullptr);\n    VERIFY_XBL_INITIALIZED();\n\n    std::shared_ptr<XblTitleStorageBlobMetadataResult> cResult;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            scid{ xsapi_internal_string(serviceConfigurationId) },\n            storageType,\n            blobPathStr{ xsapi_internal_string(blobPath) },\n            xuid,\n            skipItems,\n            maxItems,\n            async,\n            cResult\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            HRESULT hr = xblContext->TitleStorageService()->GetBlobMetadata(\n                scid, \n                storageType,\n                blobPathStr,\n                xuid,\n                skipItems,\n                maxItems,\n                \"\",\n                AsyncContext<Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>>\n                (async->queue, [async, &cResult](Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>> result)\n                {\n                    if (Succeeded(result))\n                    {\n                        cResult = result.ExtractPayload();\n                    }\n\n                    XAsyncComplete(async, result.Hresult(), sizeof(XblTitleStorageBlobMetadataResultHandle));\n                }\n            ));\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            auto resultHandle = static_cast<XblTitleStorageBlobMetadataResultHandle*>(data->buffer);\n            *resultHandle = cResult.get();\n            cResult->AddRef();\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageGetBlobMetadataResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadataResultHandle* result\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblTitleStorageBlobMetadataResultHandle), result, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageDeleteBlobAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ bool deleteOnlyIfEtagMatches,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || async == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(blobMetadata.blobType == XblTitleStorageBlobType::Unknown);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.blobPath);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            blobMetadata,\n            deleteOnlyIfEtagMatches,\n            async\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        UNREFERENCED_PARAMETER(data);\n\n        if (op == XAsyncOp::DoWork)\n        {\n            HRESULT hr = xblContext->TitleStorageService()->DeleteBlob(\n                blobMetadata,\n                deleteOnlyIfEtagMatches,\n                AsyncContext<HRESULT>(async)\n            );\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageDownloadBlobAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _Out_writes_(blobBufferCount) uint8_t* blobBuffer,\n    _In_ size_t blobBufferCount,\n    _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n    _In_opt_z_ const char* selectQuery,\n    _In_ size_t preferredDownloadBlockSize,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || blobBuffer == nullptr || async == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF(blobMetadata.blobType == XblTitleStorageBlobType::Unknown);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.blobPath);\n\n    VERIFY_XBL_INITIALIZED();\n\n    XblTitleStorageBlobMetadata cResult;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            blobMetadata,\n            blobBuffer,\n            blobBufferCount,\n            etagMatchCondition,\n            selectQueryStr = selectQuery ? String{ selectQuery } : String{},\n            preferredDownloadBlockSize,\n            async,\n            cResult\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            HRESULT hr = xblContext->TitleStorageService()->DownloadBlob(\n                blobMetadata,\n                blobBuffer,\n                blobBufferCount,\n                etagMatchCondition,\n                selectQueryStr,\n                preferredDownloadBlockSize,\n                AsyncContext<Result<XblTitleStorageBlobMetadata>>\n                (async->queue, [async, &cResult](Result<XblTitleStorageBlobMetadata> result)\n            {\n                if (Succeeded(result))\n                {\n                    cResult = result.ExtractPayload();\n                }\n\n                XAsyncComplete(async, result.Hresult(), sizeof(XblTitleStorageBlobMetadata));\n            }\n            ));\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            std::memcpy(data->buffer, &cResult, sizeof(XblTitleStorageBlobMetadata));\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageDownloadBlobResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadata* blobMetadata\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblTitleStorageBlobMetadata), blobMetadata, nullptr);\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageUploadBlobAsync(\n    _In_ XblContextHandle xboxLiveContext,\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ const uint8_t* blobBuffer,\n    _In_ size_t blobBufferCount,\n    _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n    _In_ size_t preferredDownloadBlockSize,\n    _In_ XAsyncBlock* async\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(xboxLiveContext == nullptr || blobBuffer == nullptr || async == nullptr);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.blobPath);\n    VERIFY_XBL_INITIALIZED();\n\n    XblTitleStorageBlobMetadata cResult;\n\n    return RunAsync(async, __FUNCTION__,\n        [\n            xblContext{ xboxLiveContext->shared_from_this() },\n            blobMetadata,\n            blobBuffer,\n            blobBufferCount,\n            etagMatchCondition,\n            preferredDownloadBlockSize,\n            async,\n            cResult\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data) mutable\n    {\n        if (op == XAsyncOp::DoWork)\n        {\n            HRESULT hr = xblContext->TitleStorageService()->UploadBlob(\n                blobMetadata,\n                blobBuffer,\n                blobBufferCount,\n                etagMatchCondition,\n                preferredDownloadBlockSize,\n                AsyncContext<Result<XblTitleStorageBlobMetadata>>\n                (async->queue, [async, &cResult](Result<XblTitleStorageBlobMetadata> result)\n            {\n                if (Succeeded(result))\n                {\n                    cResult = result.ExtractPayload();\n                }\n\n                XAsyncComplete(async, result.Hresult(), sizeof(XblTitleStorageBlobMetadata));\n            }\n            ));\n\n            return SUCCEEDED(hr) ? E_PENDING : hr;\n        }\n        else if (op == XAsyncOp::GetResult)\n        {\n            std::memcpy(data->buffer, &cResult, sizeof(XblTitleStorageBlobMetadata));\n        }\n        return S_OK;\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblTitleStorageUploadBlobResult(\n    _In_ XAsyncBlock* async,\n    _Out_ XblTitleStorageBlobMetadata* blobMetadata\n) XBL_NOEXCEPT\ntry\n{\n    return XAsyncGetResult(async, nullptr, sizeof(XblTitleStorageBlobMetadata), blobMetadata, nullptr);\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Services/TitleStorage/title_storage_blob_metadata_result.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"title_storage_internal.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::title_storage;\n\nvoid XblTitleStorageBlobMetadataResult::Initialize(\n    _In_ std::shared_ptr<TitleStorageService> titleStorageService,\n    _In_ xsapi_internal_string scid,\n    _In_ uint64_t xuid,\n    _In_ XblTitleStorageType storageType,\n    _In_ xsapi_internal_string blobPath\n)\n{\n    m_titleStorageService = titleStorageService;\n    m_scid = scid;\n    m_xuid = xuid;\n    m_storageType = storageType;\n    m_blobPath = blobPath;\n\n    for (auto& item : m_items)\n    {\n        utils::strcpy(item.serviceConfigurationId, XBL_SCID_LENGTH, m_scid.c_str());\n        item.xboxUserId = m_xuid;\n        item.storageType = m_storageType;\n    }\n}\n\nconst xsapi_internal_vector<XblTitleStorageBlobMetadata>&\nXblTitleStorageBlobMetadataResult::Items() const\n{\n    return m_items;\n}\n\nbool XblTitleStorageBlobMetadataResult::HasNext() const\n{\n    return !m_continuationToken.empty();\n}\n\nHRESULT XblTitleStorageBlobMetadataResult::GetNext(\n    _In_ uint32_t maxItems, \n    _In_ AsyncContext<Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>> async\n)\n{\n    return m_titleStorageService->GetBlobMetadata(\n        m_scid,\n        m_storageType,\n        m_blobPath,\n        m_xuid,\n        0, // use continuationToken, ignore skipItems.\n        maxItems,\n        m_continuationToken,\n        async\n    );\n}\n\nstd::shared_ptr<xbox::services::RefCounter>\nXblTitleStorageBlobMetadataResult::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nResult<std::shared_ptr<XblTitleStorageBlobMetadataResult>> \nXblTitleStorageBlobMetadataResult::Deserialize(_In_ const JsonValue& json)\n{\n    if (json.IsNull())\n    {\n        return Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>(nullptr);\n    }\n\n    auto titleStorageBlobMetadataResult = MakeShared<XblTitleStorageBlobMetadataResult>();\n\n    if (json.IsObject() && json.HasMember(\"blobs\"))\n    {\n        const JsonValue& blobs = json[\"blobs\"];\n        RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonVector<XblTitleStorageBlobMetadata>(\n            DeserializeXblTitleStorageBlobMetadata,\n            blobs,\n            titleStorageBlobMetadataResult->m_items\n            ));\n    }\n    else\n    {\n        //required\n        titleStorageBlobMetadataResult->m_items = xsapi_internal_vector<XblTitleStorageBlobMetadata>();\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n\n    if (json.IsObject() && json.HasMember(\"pagingInfo\"))\n    {\n        const JsonValue& pagingInfoJson = json[\"pagingInfo\"];\n        if (!pagingInfoJson.IsNull())\n        {\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(\n                pagingInfoJson,\n                \"continuationToken\",\n                titleStorageBlobMetadataResult->m_continuationToken\n            ));\n        }\n    }\n\n    return Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>(titleStorageBlobMetadataResult, S_OK);\n}\n\nXblTitleStorageBlobType\nXblTitleStorageBlobMetadataResult::ConvertStringToTitleStorageBlobType(\n    _In_ const xsapi_internal_string& value\n)\n{\n    if (utils::str_icmp_internal(value, \"binary\") == 0)\n    {\n        return XblTitleStorageBlobType::Binary;\n    }\n    else if (utils::str_icmp_internal(value, \"json\") == 0)\n    {\n        return XblTitleStorageBlobType::Json;\n    }\n    else if (utils::str_icmp_internal(value, \"config\") == 0)\n    {\n        return XblTitleStorageBlobType::Config;\n    }\n\n    return XblTitleStorageBlobType::Unknown;\n}\n\nResult<XblTitleStorageBlobMetadata> \nXblTitleStorageBlobMetadataResult::DeserializeXblTitleStorageBlobMetadata(_In_ const JsonValue& json)\n{\n    XblTitleStorageBlobMetadata returnObject{};\n    if (json.IsNull()) return Result<XblTitleStorageBlobMetadata>(returnObject);\n\n    HRESULT errc = S_OK;\n\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonTimeT(json, \"clientFileTime\", returnObject.clientTimestamp));\n\n    xsapi_internal_string displayName;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"displayName\", displayName));\n    utils::strcpy(returnObject.displayName, displayName.length() + 1, displayName.c_str());\n\n    xsapi_internal_string etag;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"etag\", etag));\n    utils::strcpy(returnObject.eTag, etag.length() + 1, etag.c_str());\n\n    uint64_t size = 0;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(json, \"size\", size));\n    returnObject.length = static_cast<size_t>(size);\n\n    xsapi_internal_string fileName;\n    RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonString(json, \"fileName\", fileName));\n    if (!fileName.empty())\n    {\n        auto nPos = fileName.find(',');\n        if (nPos == std::string::npos)\n        {\n            return Result<XblTitleStorageBlobMetadata>(returnObject, WEB_E_INVALID_JSON_STRING);\n        }\n\n        xsapi_internal_string smartBlobType = fileName.substr(nPos + 1);\n        returnObject.blobType = ConvertStringToTitleStorageBlobType(smartBlobType);\n        fileName.resize(nPos);\n        utils::strcpy(returnObject.blobPath, fileName.length() + 1, fileName.c_str());\n    }\n\n    return Result<XblTitleStorageBlobMetadata>(returnObject, xbox::services::legacy::ConvertHr(errc));\n}"
  },
  {
    "path": "Source/Services/TitleStorage/title_storage_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/title_storage_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_BEGIN\n\nclass TitleStorageService;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_END\n\nstruct XblTitleStorageQuota\n{\n    size_t usedBytes;\n    size_t quotaBytes;\n};\n\nstruct XblTitleStorageBlobMetadataResult : public xbox::services::RefCounter, public std::enable_shared_from_this<XblTitleStorageBlobMetadataResult>\n{\npublic:\n    XblTitleStorageBlobMetadataResult() = default;\n\n    void Initialize(_In_ std::shared_ptr<xbox::services::title_storage::TitleStorageService> titleStorageService, _In_ xsapi_internal_string scid, _In_ uint64_t xuid, _In_ XblTitleStorageType storageType, _In_ xsapi_internal_string blobPath);\n\n    const xsapi_internal_vector<XblTitleStorageBlobMetadata>& Items() const;\n\n    bool HasNext() const;\n\n    HRESULT GetNext(_In_ uint32_t maxItems, _In_ xbox::services::AsyncContext<xbox::services::Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>> async);\n\n    static xbox::services::Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>> Deserialize(_In_ const JsonValue& json);\n    static xbox::services::Result<XblTitleStorageBlobMetadata> DeserializeXblTitleStorageBlobMetadata(_In_ const JsonValue& json);\n\n    static XblTitleStorageBlobType ConvertStringToTitleStorageBlobType(_In_ const xsapi_internal_string& value);\n\nprotected:\n    // RefCounter\n    std::shared_ptr<xbox::services::RefCounter> GetSharedThis() override;\n\nprivate:\n    std::shared_ptr<xbox::services::title_storage::TitleStorageService> m_titleStorageService;\n    xsapi_internal_string m_scid;\n    uint64_t m_xuid{};\n    XblTitleStorageType m_storageType{};\n    xsapi_internal_string m_blobPath;\n\n    xsapi_internal_vector<XblTitleStorageBlobMetadata> m_items;\n    xsapi_internal_string m_continuationToken;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_BEGIN\n\nclass TitleStorageService : public std::enable_shared_from_this<TitleStorageService>\n{\npublic:\n    TitleStorageService(\n        _In_ User&& user,\n        _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings\n    );\n\n    HRESULT GetQuota(\n        _In_ xsapi_internal_string scid,\n        _In_ XblTitleStorageType storageType,\n        _In_ AsyncContext<Result<XblTitleStorageQuota>> async\n    );\n\n    HRESULT GetBlobMetadata(\n        _In_ xsapi_internal_string scid,\n        _In_ XblTitleStorageType storageType,\n        _In_ xsapi_internal_string blobPath,\n        _In_ uint64_t xboxUserId,\n        _In_ uint32_t skipItems,\n        _In_ uint32_t maxItems,\n        _In_ xsapi_internal_string continuationToken,\n        _In_ AsyncContext<Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>> async\n    );\n\n    HRESULT DeleteBlob(\n        _In_ XblTitleStorageBlobMetadata blobMetadata,\n        _In_ bool deleteOnlyIfEtagMatches,\n        _In_ AsyncContext<HRESULT> async\n    );\n\n    HRESULT DownloadBlob(\n        _In_ XblTitleStorageBlobMetadata blobMetadata,\n        _In_ uint8_t* blobBuffer,\n        _In_ size_t blobBufferSize,\n        _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n        _In_ xsapi_internal_string selectQuery,\n        _In_ size_t preferredDownloadBlockSize,\n        _In_ AsyncContext<Result<XblTitleStorageBlobMetadata>> async\n    );\n\n    HRESULT UploadBlob(\n        _In_ XblTitleStorageBlobMetadata blobMetadata,\n        _In_ const uint8_t* blobBuffer,\n        _In_ size_t blobBufferSize,\n        _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n        _In_ size_t preferredUploadBlockSize,\n        _In_ AsyncContext<Result<XblTitleStorageBlobMetadata>> async\n    );\nprivate:\n\n    struct BlobArgs\n    {\n        XblTitleStorageBlobMetadata blobMetadata{};\n        uint8_t* downloadBlobBuffer{ nullptr };\n        const uint8_t* uploadBlobBuffer{ nullptr };\n        size_t blobBufferSize{ 0 };\n        XblTitleStorageETagMatchCondition etagMatchCondition{};\n        xsapi_internal_string selectQuery;\n        size_t preferredBlockSize{ 0 };\n        size_t startByte{ 0 };\n        AsyncContext<Result<XblTitleStorageBlobMetadata>> async;\n    };\n\n    HRESULT DownloadBlobHelper(\n        _In_ std::shared_ptr<BlobArgs> downloadBlobArgs\n    );\n\n    HRESULT UploadBlobHelper(\n        _In_ std::shared_ptr<BlobArgs> uploadBlobArgs,\n        _In_ const xsapi_internal_string& continuationToken\n    );\n\n    static Result<xsapi_internal_string> TitleStorageQuotaSubpath(\n        _In_ XblTitleStorageType storageType,\n        _In_ const xsapi_internal_string& serviceConfigurationId,\n        _In_ uint64_t xboxUserId\n    );\n\n    static Result<xsapi_internal_string> TitleStorageBlobMetadataSubpath(\n            _In_ XblTitleStorageType storageType,\n            _In_ const xsapi_internal_string& serviceConfigurationId,\n            _In_ uint64_t xboxUserId,\n            _In_ const xsapi_internal_string& blobPath,\n            _In_ uint32_t skipItems,\n            _In_ uint32_t maxItems,\n            _In_ const xsapi_internal_string& continuationToken\n    );\n\n    static Result<xsapi_internal_string> TitleStorageDownloadBlobSubpath(\n        _In_ const XblTitleStorageBlobMetadata& blobMetadata,\n        _In_ const xsapi_internal_string& selectQuery\n    );\n\n    static Result<xsapi_internal_string> TitleStorageUploadBlobSubpath(\n        _In_ const XblTitleStorageBlobMetadata& blobMetadata,\n        _In_ const xsapi_internal_string& continuationToken,\n        _In_ bool finalBlock\n    );\n\n    HRESULT SetEtagHeader(\n        _In_ std::shared_ptr<XblHttpCall> httpCall,\n        _In_ xsapi_internal_string etag,\n        _In_ XblTitleStorageETagMatchCondition eTagMatchCondition\n    );\n\n    HRESULT SetRangeHeader(\n        _In_ std::shared_ptr<XblHttpCall> httpCall,\n        _In_ size_t startByte,\n        _In_ size_t endByte\n    );\n\n    // Deserialize Helpers\n    static Result<XblTitleStorageQuota> DeserializeTitleStorageQuota(\n        _In_ const JsonValue& json\n    );\n\n    User m_user;\n    std::shared_ptr<xbox::services::XboxLiveContextSettings> m_xboxLiveContextSettings;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_END\n"
  },
  {
    "path": "Source/Services/TitleStorage/title_storage_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"title_storage_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_BEGIN\n\nconst char CONTENT_TYPE_HEADER_VALUE[] = \"application/octet-stream\";\nconst char E_TAG_HEADER_NAME[] = \"ETag\";\nconst char IF_MATCH_HEADER_NAME[] = \"If-Match\";\nconst char IF_NONE_HEADER_NAME[] = \"If-None-Match\";\nconst char E_TAG_INVALID_VALUE[] = \"InvalidETagValue\";\nconst char RANGE_HEADER_NAME[] = \"Range\";\n \nTitleStorageService::TitleStorageService(\n    _In_ User&& user,\n    _In_ std::shared_ptr<xbox::services::XboxLiveContextSettings> xboxLiveContextSettings\n) :\n    m_user{ std::move(user) },\n    m_xboxLiveContextSettings(std::move(xboxLiveContextSettings))\n{\n}\n\nHRESULT \nTitleStorageService::GetQuota(\n    _In_ xsapi_internal_string scid,\n    _In_ XblTitleStorageType storageType,\n    _In_ AsyncContext<Result<XblTitleStorageQuota>> async\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(scid);\n\n    auto subpath = TitleStorageQuotaSubpath(storageType, scid, m_user.Xuid());\n    RETURN_HR_INVALIDARGUMENT_IF(!Succeeded(subpath));\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"titlestorage\", subpath.Payload()),\n        xbox_live_api::get_quota\n    );\n\n    RETURN_HR_IF_FAILED(hr);\n\n    hr = httpCall->Perform(\n        AsyncContext<HttpResult>{\n            async.Queue(),\n            [async](HttpResult httpResult)\n        {\n            HRESULT hr = httpResult.Hresult();\n            if (SUCCEEDED(hr))\n            {\n                hr = httpResult.Payload()->Result();\n                if (SUCCEEDED(hr))\n                {\n                    async.Complete(DeserializeTitleStorageQuota(httpResult.Payload()->GetResponseBodyJson()));\n                }\n            }\n\n            if (!SUCCEEDED(hr))\n            {\n                async.Complete(hr);\n            }\n        }});\n\n    return hr;\n}\n\nResult<XblTitleStorageQuota>\nTitleStorageService::DeserializeTitleStorageQuota(\n    _In_ const JsonValue& json\n    )\n{\n    XblTitleStorageQuota returnObject {};\n    if (json.IsNull())\n    {\n        return returnObject;\n    }\n\n    HRESULT errc = S_OK;\n\n    if (json.IsObject() && json.HasMember(\"quotaInfo\"))\n    {\n        const JsonValue& quotaInfoJson = json[\"quotaInfo\"];\n        if (!quotaInfoJson.IsNull())\n        {\n            uint64_t usedBytes = 0;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(quotaInfoJson, \"usedBytes\", usedBytes));\n            returnObject.usedBytes = (size_t)usedBytes;\n\n            uint64_t quotaBytes = 0;\n            RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonUInt64(quotaInfoJson, \"quotaBytes\", quotaBytes));\n            returnObject.quotaBytes = (size_t)quotaBytes;\n        }\n    }\n\n    if (FAILED(errc))\n    {\n        return E_FAIL;\n    }\n    \n    return returnObject;\n}\n\nHRESULT \nTitleStorageService::GetBlobMetadata(\n    _In_ xsapi_internal_string scid,\n    _In_ XblTitleStorageType storageType,\n    _In_ xsapi_internal_string blobPath,\n    _In_ uint64_t xboxUserId,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ xsapi_internal_string continuationToken,\n    _In_ AsyncContext<Result<std::shared_ptr<XblTitleStorageBlobMetadataResult>>> async\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(scid);\n\n    uint64_t xuid = xboxUserId;\n    if (xuid == 0 && (storageType == XblTitleStorageType::TrustedPlatformStorage || storageType == XblTitleStorageType::Universal))\n    {\n        xuid = m_user.Xuid();\n    }\n\n    auto subpath = TitleStorageBlobMetadataSubpath(\n        storageType,\n        scid,\n        xuid,\n        blobPath,\n        skipItems,\n        maxItems,\n        continuationToken\n    );\n\n    RETURN_HR_INVALIDARGUMENT_IF(!Succeeded(subpath));\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"titlestorage\", subpath.Payload()),\n        xbox_live_api::get_blob_metadata\n    );\n\n    RETURN_HR_IF_FAILED(hr);\n\n    hr = httpCall->Perform(\n        AsyncContext<HttpResult>{\n        async.Queue(),\n            [\n                sharedThis{ shared_from_this() }, \n                scid, \n                xuid, \n                storageType, \n                blobPath, \n                async\n            ]\n        (HttpResult httpResult)\n        {\n            HRESULT hr = httpResult.Hresult();\n            if (SUCCEEDED(hr))\n            {\n                hr = httpResult.Payload()->Result();\n                if (SUCCEEDED(hr))\n                {\n                    auto result = XblTitleStorageBlobMetadataResult::Deserialize(httpResult.Payload()->GetResponseBodyJson());\n                    if (Succeeded(result))\n                    {\n                        result.Payload()->Initialize(sharedThis, scid, xuid, storageType, blobPath);\n                    }\n                    async.Complete(result);\n                }\n            }\n\n            if (!SUCCEEDED(hr))\n            {\n                async.Complete(hr);\n            }\n        }});\n\n    return hr;\n}\n\nHRESULT\nTitleStorageService::DeleteBlob(\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ bool deleteOnlyIfEtagMatches,\n    _In_ AsyncContext<HRESULT> async\n    )\n{\n    Result<xsapi_internal_string> subpath = TitleStorageDownloadBlobSubpath(blobMetadata, \"\");\n\n    RETURN_HR_INVALIDARGUMENT_IF(!Succeeded(subpath));\n\n    XblTitleStorageETagMatchCondition etagMatchCondition = deleteOnlyIfEtagMatches ?\n        XblTitleStorageETagMatchCondition::IfMatch :\n        XblTitleStorageETagMatchCondition::NotUsed;\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"DELETE\",\n        XblHttpCall::BuildUrl(\"titlestorage\", subpath.Payload()),\n        xbox_live_api::delete_blob\n    );\n\n    RETURN_HR_IF_FAILED(hr);\n    RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE_HEADER_VALUE));\n\n    hr = SetEtagHeader(\n        httpCall,\n        blobMetadata.eTag,\n        etagMatchCondition\n        );\n\n    RETURN_HR_IF_FAILED(hr);\n\n    hr = httpCall->Perform(\n        AsyncContext<HttpResult>{\n        async.Queue(),\n            [async](HttpResult httpResult)\n        {\n            HRESULT hr = httpResult.Hresult();\n            if (SUCCEEDED(hr))\n            {\n                hr = httpResult.Payload()->Result();\n            }\n\n            async.Complete(hr);\n        }});\n\n    return hr;\n}\n\nHRESULT\nTitleStorageService::DownloadBlob(\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ uint8_t* blobBuffer,\n    _In_ size_t blobBufferSize,\n    _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n    _In_ xsapi_internal_string selectQuery,\n    _In_ size_t preferredDownloadBlockSize,\n    _In_ AsyncContext<Result<XblTitleStorageBlobMetadata>> async\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(blobBuffer);\n    RETURN_HR_INVALIDARGUMENT_IF(blobBufferSize < blobMetadata.length);\n\n    Result<xsapi_internal_string> subpath = TitleStorageDownloadBlobSubpath(blobMetadata, selectQuery);\n\n    RETURN_HR_INVALIDARGUMENT_IF(!Succeeded(subpath));\n\n    if (preferredDownloadBlockSize == 0)\n    {\n        preferredDownloadBlockSize = XBL_TITLE_STORAGE_DEFAULT_DOWNLOAD_BLOCK_SIZE;\n    }\n    else\n    {\n        preferredDownloadBlockSize = preferredDownloadBlockSize < XBL_TITLE_STORAGE_MIN_DOWNLOAD_BLOCK_SIZE ? XBL_TITLE_STORAGE_MIN_DOWNLOAD_BLOCK_SIZE : preferredDownloadBlockSize;\n    }\n\n    auto args = MakeShared<BlobArgs>();\n    args->blobMetadata = { blobMetadata };\n    args->downloadBlobBuffer = blobBuffer;\n    args->blobBufferSize = blobBufferSize;\n    args->etagMatchCondition = etagMatchCondition;\n    args->selectQuery = selectQuery;\n    args->preferredBlockSize = preferredDownloadBlockSize;\n    args->startByte = 0;\n    args->async = std::move(async);\n\n    return DownloadBlobHelper(args);\n}\n\nHRESULT TitleStorageService::DownloadBlobHelper(\n    _In_ std::shared_ptr<BlobArgs> args\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args->downloadBlobBuffer);\n    RETURN_HR_INVALIDARGUMENT_IF(args->blobBufferSize < args->blobMetadata.length);\n\n    Result<xsapi_internal_string> subpath = TitleStorageDownloadBlobSubpath(args->blobMetadata, args->selectQuery);\n\n    RETURN_HR_INVALIDARGUMENT_IF(!Succeeded(subpath));\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"GET\",\n        XblHttpCall::BuildUrl(\"titlestorage\", subpath.Payload()),\n        xbox_live_api::download_blob\n    );\n    RETURN_HR_IF_FAILED(hr);\n    \n    RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE_HEADER_VALUE));\n    httpCall->SetLongHttpCall(true);\n\n    hr = SetEtagHeader(\n        httpCall,\n        args->blobMetadata.eTag,\n        args->etagMatchCondition\n    );\n    RETURN_HR_IF_FAILED(hr);\n\n    if (args->blobMetadata.blobType == XblTitleStorageBlobType::Binary)\n    {\n        // Partial download is only used for binary blob types\n        hr = SetRangeHeader(\n            httpCall,\n            args->startByte,\n            args->startByte + args->preferredBlockSize - 1\n        );\n        RETURN_HR_IF_FAILED(hr);\n    }\n\n    return httpCall->Perform(\n        AsyncContext<HttpResult>{\n            args->async.Queue(),\n            [\n                args,\n                sharedThis{ shared_from_this() }\n            ](HttpResult httpResult)\n            {\n                HRESULT hr = httpResult.Hresult();\n                if (SUCCEEDED(hr))\n                {\n                    hr = httpResult.Payload()->Result();\n\n                    if (SUCCEEDED(hr))\n                    {\n                        auto responseBody = httpResult.Payload()->GetResponseBodyBytes();\n                        if (args->startByte + responseBody.size() > args->blobBufferSize)\n                        {\n                            args->async.Complete(E_NOT_SUFFICIENT_BUFFER);\n                            return;\n                        }\n\n                        memcpy(args->downloadBlobBuffer + args->startByte, responseBody.data(), responseBody.size());\n                        \n                        args->startByte += responseBody.size();\n\n                        // Check if there is more data to load\n                        // If not binary blob type then the service has returned the entire payload.\n                        // If binary blob type then check if the service returned less data than requested or\n                        // if we've loaded all the data defined by the blob metadata length property.\n                        if (args->blobMetadata.blobType != XblTitleStorageBlobType::Binary ||\n                            responseBody.size() < args->preferredBlockSize ||\n                            args->startByte == args->blobMetadata.length)\n                        {\n                            auto etag = httpResult.Payload()->GetResponseHeader(ETAG_HEADER);\n                            utils::strcpy(args->blobMetadata.eTag, etag.length() + 1, etag.c_str());\n                            args->blobMetadata.length = args->startByte;\n                            args->async.Complete(std::move(args->blobMetadata));\n                        }\n                        else\n                        {\n                            hr = sharedThis->DownloadBlobHelper(args);\n                        }\n                    }\n                }\n\n                if (!SUCCEEDED(hr))\n                {\n                    args->async.Complete(hr);\n                }\n            }});\n}\n\nHRESULT\nTitleStorageService::UploadBlob(\n    _In_ XblTitleStorageBlobMetadata blobMetadata,\n    _In_ const uint8_t* blobBuffer,\n    _In_ size_t blobBufferSize,\n    _In_ XblTitleStorageETagMatchCondition etagMatchCondition,\n    _In_ size_t preferredUploadBlockSize,\n    _In_ AsyncContext<Result<XblTitleStorageBlobMetadata>> async\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(blobBuffer);\n    RETURN_HR_INVALIDARGUMENT_IF(blobBufferSize == 0);\n\n    if (preferredUploadBlockSize == 0)\n    {\n        preferredUploadBlockSize = XBL_TITLE_STORAGE_DEFAULT_UPLOAD_BLOCK_SIZE;\n    }\n    else\n    {\n        preferredUploadBlockSize = preferredUploadBlockSize < XBL_TITLE_STORAGE_MIN_UPLOAD_BLOCK_SIZE ? XBL_TITLE_STORAGE_MIN_UPLOAD_BLOCK_SIZE : preferredUploadBlockSize;\n        preferredUploadBlockSize = preferredUploadBlockSize > XBL_TITLE_STORAGE_MAX_UPLOAD_BLOCK_SIZE ? XBL_TITLE_STORAGE_MAX_UPLOAD_BLOCK_SIZE : preferredUploadBlockSize;\n    }\n\n    auto args = MakeShared<BlobArgs>();\n    args->blobMetadata = { blobMetadata };\n    args->uploadBlobBuffer = blobBuffer;\n    args->blobBufferSize = blobBufferSize;\n    args->etagMatchCondition = etagMatchCondition;\n    args->preferredBlockSize = preferredUploadBlockSize;\n    args->startByte = 0;\n    args->async = async;\n\n    if (args->blobMetadata.xboxUserId == 0)\n    {\n        args->blobMetadata.xboxUserId = m_user.Xuid();\n    }\n\n    return UploadBlobHelper(args, \"\");\n}\n\nHRESULT \nTitleStorageService::UploadBlobHelper(\n    _In_ std::shared_ptr<BlobArgs> args,\n    _In_ const xsapi_internal_string& continuationToken\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args->uploadBlobBuffer);\n    RETURN_HR_INVALIDARGUMENT_IF(args->blobBufferSize == 0);\n\n    bool isBinary = args->blobMetadata.blobType == XblTitleStorageBlobType::Binary;\n\n    bool finalBlock = true;\n\n    size_t dataChunkSize = isBinary ? args->blobBufferSize - args->startByte : args->blobBufferSize;\n    if (isBinary)\n    {\n        if (dataChunkSize > args->preferredBlockSize)\n        {\n            dataChunkSize = args->preferredBlockSize;\n        }\n\n        size_t endByteOfChunk = args->startByte + dataChunkSize;\n        finalBlock = (endByteOfChunk == args->blobBufferSize);\n    }\n\n    Result<xsapi_internal_string> subpath = TitleStorageUploadBlobSubpath(args->blobMetadata, continuationToken, finalBlock);\n    RETURN_HR_INVALIDARGUMENT_IF(!Succeeded(subpath));\n\n    Result<User> userResult = m_user.Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(\n        m_xboxLiveContextSettings,\n        \"PUT\",\n        XblHttpCall::BuildUrl(\"titlestorage\", subpath.Payload()),\n        xbox_live_api::upload_blob\n    );\n\n    RETURN_HR_IF_FAILED(httpCall->SetHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE_HEADER_VALUE));\n    httpCall->SetLongHttpCall(true);\n\n    if (isBinary)\n    {\n        xsapi_internal_vector<uint8_t> dataChunk(dataChunkSize);\n        memcpy(dataChunk.data(), args->uploadBlobBuffer + args->startByte, dataChunkSize);\n        RETURN_HR_IF_FAILED(httpCall->SetRequestBody(std::move(dataChunk)));\n        \n        args->startByte += dataChunkSize; // Now move the start byte forward\n    }\n    else \n    {\n        RETURN_HR_IF_FAILED(httpCall->SetRequestBody((const char*)std::move(args->uploadBlobBuffer)));\n    }\n\n    hr = SetEtagHeader(\n        httpCall,\n        args->blobMetadata.eTag,\n        args->etagMatchCondition\n    );\n    RETURN_HR_IF_FAILED(hr);\n    \n    return httpCall->Perform(\n        AsyncContext<HttpResult>{\n        args->async.Queue(),\n            [\n                args,\n                finalBlock,\n                sharedThis{ shared_from_this() }\n            ](HttpResult httpResult)\n        {\n            HRESULT hr = httpResult.Hresult();\n            if (SUCCEEDED(hr))\n            {\n                hr = httpResult.Payload()->Result();\n\n                if (SUCCEEDED(hr))\n                {\n                    auto etag = httpResult.Payload()->GetResponseHeader(ETAG_HEADER);\n                    utils::strcpy(args->blobMetadata.eTag, etag.length() + 1, etag.c_str());\n\n                    if (finalBlock)\n                    {\n                        args->async.Complete(std::move(args->blobMetadata));\n                    }\n                    else\n                    {\n                        auto responseBody = httpResult.Payload()->GetResponseBodyJson();\n                        xsapi_internal_string continuationToken;\n                        JsonUtils::ExtractJsonString(responseBody, \"continuationToken\", continuationToken);\n                        hr = sharedThis->UploadBlobHelper(args, continuationToken);\n                    }\n                }\n            }\n\n            if (!SUCCEEDED(hr))\n            {\n                args->async.Complete(hr);\n            }\n        }});\n}\n\nHRESULT\nTitleStorageService::SetEtagHeader(\n    _In_ std::shared_ptr<XblHttpCall> httpCall,\n    _In_ xsapi_internal_string etag,\n    _In_ XblTitleStorageETagMatchCondition eTagMatchCondition\n    )\n{\n    if (eTagMatchCondition == XblTitleStorageETagMatchCondition::NotUsed)\n    {\n        RETURN_HR_IF_FAILED(httpCall->SetHeader(E_TAG_HEADER_NAME, E_TAG_INVALID_VALUE));\n        RETURN_HR_IF_FAILED(httpCall->SetHeader(IF_NONE_HEADER_NAME, E_TAG_INVALID_VALUE));\n    }\n    else\n    {\n        xsapi_internal_string etagValue = etag.empty() ?\n            IF_NONE_HEADER_NAME :\n            etag;\n\n        RETURN_HR_IF_FAILED(httpCall->SetHeader(E_TAG_HEADER_NAME, etagValue));\n\n        if (eTagMatchCondition == XblTitleStorageETagMatchCondition::IfMatch)\n        {\n            RETURN_HR_IF_FAILED(httpCall->SetHeader(IF_MATCH_HEADER_NAME, etagValue));\n        }\n        else\n        {\n            RETURN_HR_IF_FAILED(httpCall->SetHeader(IF_NONE_HEADER_NAME, etagValue));\n        }\n    }\n    return S_OK;\n}\n\nHRESULT\nTitleStorageService::SetRangeHeader(\n    _In_ std::shared_ptr<XblHttpCall> httpCall,\n    _In_ size_t startByte,\n    _In_ size_t endByte\n    )\n{\n    xsapi_internal_stringstream byteRange;\n    byteRange << \"bytes=\";\n    byteRange << startByte;\n    byteRange << \"-\";\n    byteRange << endByte;\n\n    RETURN_HR_IF_FAILED(httpCall->SetHeader(RANGE_HEADER_NAME, byteRange.str()));\n    return S_OK;\n}\n\nResult<xsapi_internal_string>\nTitleStorageService::TitleStorageQuotaSubpath(\n    _In_ XblTitleStorageType storageType,\n    _In_ const xsapi_internal_string& serviceConfigurationId,\n    _In_ uint64_t xboxUserId\n)\n{\n    xsapi_internal_stringstream path;\n    switch (storageType)\n    {\n        case XblTitleStorageType::TrustedPlatformStorage:\n            path << \"/trustedplatform/users/xuid(\";\n            path << xboxUserId;\n            path << \")/scids/\";\n            path << serviceConfigurationId;\n            break;\n            \n        case XblTitleStorageType::GlobalStorage:\n            path << \"/global/scids/\";\n            path << serviceConfigurationId;\n            break;\n\n        case XblTitleStorageType::Universal:\n            path << \"/universalplatform/users/xuid(\";\n            path << xboxUserId;\n            path << \")/scids/\";\n            path << serviceConfigurationId;\n            break;\n\n        default:\n            return Result<xsapi_internal_string>(E_INVALIDARG);\n    }\n\n    return path.str();\n}\n\nResult<xsapi_internal_string>\nTitleStorageService::TitleStorageBlobMetadataSubpath(\n    _In_ XblTitleStorageType storageType,\n    _In_ const xsapi_internal_string& serviceConfigurationId,\n    _In_ uint64_t xboxUserId,\n    _In_ const xsapi_internal_string& blobPath,\n    _In_ uint32_t skipItems,\n    _In_ uint32_t maxItems,\n    _In_ const xsapi_internal_string& continuationToken\n    )\n{\n    xsapi_internal_stringstream path;\n    switch (storageType)\n    {\n        case XblTitleStorageType::TrustedPlatformStorage:\n            path << \"/trustedplatform/users/xuid(\";\n            path << xboxUserId;\n            path << \")/scids/\";\n            path << serviceConfigurationId;\n            break;\n            \n        case XblTitleStorageType::GlobalStorage:\n            path << \"/global/scids/\";\n            path << serviceConfigurationId; \n            break;\n            \n        case XblTitleStorageType::Universal:\n            path << \"/universalplatform/users/xuid(\";\n            path << xboxUserId;\n            path << \")/scids/\";\n            path << serviceConfigurationId;\n            break;\n\n        default:\n            return Result<xsapi_internal_string>(E_INVALIDARG);\n    }\n\n    path << \"/data\";\n\n    if (!blobPath.empty())\n    {\n        path << \"/\";\n        path << utils::encode_uri(blobPath, xbox::services::uri::components::query);\n    }\n\n    xbox::services::uri_builder params;\n    utils::append_paging_info(\n        params,\n        skipItems,\n        maxItems,\n        continuationToken\n        );\n\n    xsapi_internal_string paramPath = params.query();\n    if (paramPath.size() > 1)\n    {\n        path << \"?\" << paramPath;\n    }\n\n    return path.str();\n}\n\nResult<xsapi_internal_string>\nTitleStorageService::TitleStorageDownloadBlobSubpath(\n    _In_ const XblTitleStorageBlobMetadata& blobMetadata,\n    _In_ const xsapi_internal_string& selectQuery\n    )\n{\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.serviceConfigurationId);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(blobMetadata.blobPath);\n\n    xsapi_internal_stringstream path;\n\n    xsapi_internal_string titleStorageBlobToString;\n    switch (blobMetadata.blobType)\n    {\n    case XblTitleStorageBlobType::Binary: titleStorageBlobToString = \"binary\"; break;\n    case XblTitleStorageBlobType::Json: titleStorageBlobToString = \"json\"; break;\n    case XblTitleStorageBlobType::Config: titleStorageBlobToString = \"config\"; break;\n    default: return Result<xsapi_internal_string>(E_INVALIDARG);\n    }\n\n    switch (blobMetadata.storageType)\n    {\n        case XblTitleStorageType::TrustedPlatformStorage:\n            path << \"/trustedplatform/users/xuid(\";\n            path << blobMetadata.xboxUserId;\n            path << \")/scids/\";\n            break;\n            \n        case XblTitleStorageType::GlobalStorage:\n            path << \"/global/scids/\";\n            break;\n            \n        case XblTitleStorageType::Universal:\n            path << \"/universalplatform/users/xuid(\";\n            path << blobMetadata.xboxUserId;\n            path << \")/scids/\";\n            break;\n\n        default:\n            return Result<xsapi_internal_string>(E_INVALIDARG);\n    }\n    \n    path << blobMetadata.serviceConfigurationId;\n    path << \"/data/\";\n    path << blobMetadata.blobPath;\n    path << \",\";\n    path << titleStorageBlobToString;\n\n    xsapi_internal_vector<xsapi_internal_string> params;\n    if (!selectQuery.empty())\n    {\n        if (blobMetadata.blobType == XblTitleStorageBlobType::Config)\n        {\n            xsapi_internal_stringstream param;\n            param << \"customSelector=\";\n            param << utils::encode_uri(selectQuery.c_str());\n            params.push_back(param.str());\n        }\n        else if (blobMetadata.blobType == XblTitleStorageBlobType::Json)\n        {\n            xsapi_internal_stringstream param;\n            param << \"select=\";\n            param << utils::encode_uri(selectQuery.c_str());\n            params.push_back(param.str());\n        }\n    }\n\n    path << utils::get_query_from_params(params);\n\n    return Result<xsapi_internal_string>(path.str());\n}\n\nResult<xsapi_internal_string>\nTitleStorageService::TitleStorageUploadBlobSubpath(\n    _In_ const XblTitleStorageBlobMetadata& blobMetadata,\n    _In_ const xsapi_internal_string& continuationToken,\n    _In_ bool finalBlock\n    )\n{\n    xsapi_internal_stringstream source;\n    Result<xsapi_internal_string> titleStorageDlSubpath = TitleStorageDownloadBlobSubpath(\n        blobMetadata,\n        \"\"\n        );\n\n    if (!Succeeded(titleStorageDlSubpath)) return titleStorageDlSubpath;\n\n    source << titleStorageDlSubpath.Payload();\n\n    xsapi_internal_vector<xsapi_internal_string> params;\n\n    if (blobMetadata.clientTimestamp != 0)\n    {\n        // Format: Tue, 13 Aug 2019 09:01:23 GMT\n        char clientTimeStamp[37]{};\n\n#if HC_PLATFORM_IS_MICROSOFT\n        struct tm timeinfo{};\n        if (gmtime_s(&timeinfo, &blobMetadata.clientTimestamp) == 0)\n        {\n            strftime(clientTimeStamp, 32, \"%a, %d %b %Y %H:%M:%S GMT\", &timeinfo);\n        }\n#else\n        struct tm* timeinfo{ nullptr };\n        timeinfo = gmtime(&blobMetadata.clientTimestamp);\n        strftime(clientTimeStamp, 32, \"%a, %d %b %Y %H:%M:%S GMT\", timeinfo);\n#endif\n\n        xsapi_internal_stringstream param;\n        param << \"clientFileTime=\";\n        param << utils::encode_uri(clientTimeStamp);\n        params.push_back(param.str());\n    }\n\n    if (strlen(blobMetadata.displayName) > 0)\n    {\n        xsapi_internal_stringstream param;\n        param << \"displayName=\";\n        param << utils::encode_uri(blobMetadata.displayName);\n        params.push_back(param.str());\n    }\n\n    if (!continuationToken.empty())\n    {\n        xsapi_internal_stringstream param;\n        param << \"continuationToken=\";\n        param << utils::encode_uri(continuationToken);\n        params.push_back(param.str());\n    }\n\n    if (blobMetadata.blobType == XblTitleStorageBlobType::Binary)\n    {\n        xsapi_internal_string param = finalBlock ? \"finalBlock=true\" : \"finalBlock=false\";\n        params.push_back(param);\n    }\n\n    source << utils::get_query_from_params(params);\n\n    return Result<xsapi_internal_string>(source.str());\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_END\n"
  },
  {
    "path": "Source/Shared/HookedUri/asyncrt_utils.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Various common utilities.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <string>\n#include <vector>\n#include <cstdint>\n#include <system_error>\n#include <random>\n#include <locale.h>\n\n#include \"HookedUri/details/basic_types.h\"\n\n#if !defined(_WIN32) || (_MSC_VER >= 1700)\n#include <chrono>\n#endif\n\n#ifndef _WIN32\n#include <sys/time.h>\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#endif\n\nnamespace xbox { namespace services { namespace cppresturi {\n\n/// Various utilities for string conversions and date and time manipulation.\nnamespace utility\n{\n\n// Left over from VS2010 support, remains to avoid breaking.\ntypedef std::chrono::seconds seconds;\n\n/// Functions for converting to/from std::chrono::seconds to xml string.\nnamespace timespan\n{\n    /// <summary>\n    /// Converts a timespan/interval in seconds to xml duration string as specified by\n    /// http://www.w3.org/TR/xmlschema-2/#duration\n    /// </summary>\n    utility::string_t seconds_to_xml_duration(utility::seconds numSecs);\n\n    /// <summary>\n    /// Converts an xml duration to timespan/interval in seconds\n    /// http://www.w3.org/TR/xmlschema-2/#duration\n    /// </summary>\n    utility::seconds xml_duration_to_seconds(const utility::string_t &timespanString);\n}\n\n/// Functions for Unicode string conversions.\nnamespace conversions\n{\n    /// <summary>\n    /// Converts a UTF-16 string to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"w\">A two byte character UTF-16 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    xsapi_internal_string utf16_to_utf8_internal(const xsapi_internal_wstring &w);\n    std::string utf16_to_utf8(const utf16string&w);\n\n    /// <summary>\n    /// Converts a UTF-8 string to a UTF-16\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    utf16string utf8_to_utf16(const std::string &s);\n\n    /// <summary>\n    /// Converts a ASCII (us-ascii) string to a UTF-16 string.\n    /// </summary>\n    /// <param name=\"s\">A single byte character us-ascii string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    utf16string usascii_to_utf16(const std::string &s);\n\n    /// <summary>\n    /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    utf8string latin1_to_utf8(const std::string &s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    utility::string_t to_string_t(std::string &&s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A two byte character UTF-16 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    utility::string_t to_string_t(utf16string &&s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A single byte character UTF-8 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    utility::string_t to_string_t(const std::string &s);\n\n    /// <summary>\n    /// Converts to a platform dependent Unicode string type.\n    /// </summary>\n    /// <param name=\"s\">A two byte character UTF-16 string.</param>\n    /// <returns>A platform dependent string type.</returns>\n    utility::string_t to_string_t(const utf16string &s);\n\n    /// <summary>\n    /// Converts to a UTF-16 from string.\n    /// </summary>\n    /// <param name=\"value\">A single byte character UTF-8 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    utf16string to_utf16string(const std::string &value);\n\n    /// <summary>\n    /// Converts to a UTF-16 from string.\n    /// </summary>\n    /// <param name=\"value\">A two byte character UTF-16 string.</param>\n    /// <returns>A two byte character UTF-16 string.</returns>\n    utf16string to_utf16string(utf16string value);\n\n    /// <summary>\n    /// Converts to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"value\">A single byte character UTF-8 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    xsapi_internal_string to_utf8string_internal(xsapi_internal_string value);\n\n    /// <summary>\n    /// Converts to a UTF-8 string.\n    /// </summary>\n    /// <param name=\"value\">A two byte character UTF-16 string.</param>\n    /// <returns>A single byte character UTF-8 string.</returns>\n    xsapi_internal_string to_utf8string_internal(const xsapi_internal_wstring &value);\n\n    xsapi_internal_string latin1_to_utf8_internal(const xsapi_internal_string &s);\n    xsapi_internal_wstring latin1_to_utf16_internal(const xsapi_internal_string &s);\n\n    /// <summary>\n    /// Encode the given byte array into a base64 string\n    /// </summary>\n    utility::string_t to_base64(const unsigned char* data, size_t dataSize);\n\n    /// <summary>\n    /// Encode the given byte array into a base64 string\n    /// </summary>\n    utility::string_t to_base64(const std::vector<unsigned char>& data);\n\n    /// <summary>\n    /// Encode the given 8-byte integer into a base64 string\n    /// </summary>\n    utility::string_t to_base64(uint64_t data);\n\n    /// <summary>\n    /// Decode the given base64 string to a byte array\n    /// </summary>\n    std::vector<unsigned char> from_base64(const utility::string_t& str);\n\n    template <typename Source>\n    utility::string_t print_string(const Source &val, const std::locale &loc)\n    {\n        utility::ostringstream_t oss;\n        oss.imbue(loc);\n        oss << val;\n        if (oss.bad())\n        {\n            throw std::bad_cast();\n        }\n        return oss.str();\n    }\n\n    template <typename Source>\n    utility::string_t print_string(const Source &val)\n    {\n        return print_string(val, std::locale());\n    }\n\n    inline utility::string_t print_string(const utility::string_t &val)\n    {\n        return val;\n    }\n\n    template <typename Target>\n    Target scan_string(const utility::string_t &str, const std::locale &loc)\n    {\n        Target t;\n        utility::istringstream_t iss(str);\n        iss.imbue(loc);\n        iss >> t;\n        if (iss.bad())\n        {\n            throw std::bad_cast();\n        }\n        return t;\n    }\n\n    template <typename Target>\n    Target scan_string(const utility::string_t &str)\n    {\n        return scan_string<Target>(str, std::locale());\n    }\n\n    inline utility::string_t scan_string(const utility::string_t &str)\n    {\n        return str;\n    }\n}\n\nnamespace details\n{\n    /// <summary>\n    /// Cross platform RAII container for setting thread local locale.\n    /// </summary>\n    class scoped_c_thread_locale\n    {\n    public:\n        _ASYNCRTIMP scoped_c_thread_locale();\n        _ASYNCRTIMP ~scoped_c_thread_locale();\n\n#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(PAVO) // CodePlex 269\n#ifdef _WIN32\n        typedef _locale_t xplat_locale;\n#else\n        typedef locale_t xplat_locale;\n#endif\n\n        static _ASYNCRTIMP xplat_locale c_locale();\n#endif\n    private:\n#ifdef _WIN32\n        std::string m_prevLocale;\n        int m_prevThreadSetting;\n#elif !(defined(ANDROID) || defined(__ANDROID__) || defined(PAVO))\n        locale_t m_prevLocale;\n#endif\n        scoped_c_thread_locale(const scoped_c_thread_locale &);\n        scoped_c_thread_locale & operator=(const scoped_c_thread_locale &);\n    };\n\n    /// <summary>\n    /// Our own implementation of alpha numeric instead of std::isalnum to avoid\n    /// taking global lock for performance reasons.\n    /// </summary>\n    inline bool __cdecl is_alnum(char ch)\n    {\n        return (ch >= '0' && ch <= '9')\n            || (ch >= 'A' && ch <= 'Z')\n            || (ch >= 'a' && ch <= 'z');\n    }\n\n    /// <summary>\n    /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates\n    /// and therefore not be compatible with Dev10.\n    /// </summary>\n    template <typename _Type>\n    std::unique_ptr<_Type> make_unique() {\n        return std::unique_ptr<_Type>(new _Type());\n    }\n\n    template <typename _Type, typename _Arg1>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));\n    }\n\n    template <typename _Type, typename _Arg1, typename _Arg2>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2)));\n    }\n\n    template <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3)));\n    }\n\n    template <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4>\n    std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) {\n        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4)));\n    }\n\n    /// <summary>\n    /// Cross platform utility function for performing case insensitive string comparision.\n    /// </summary>\n    /// <param name=\"left\">First string to compare.</param>\n    /// <param name=\"right\">Second strong to compare.</param>\n    /// <returns>true if the strings are equivalent, false otherwise</returns>\n    inline bool str_icmp(const utility::string_t &left, const utility::string_t &right)\n    {\n#ifdef _WIN32\n        return _wcsicmp(left.c_str(), right.c_str()) == 0;\n#else\n        return strcasecmp(left.c_str(), right.c_str());\n#endif\n    }\n\n#ifdef _WIN32\n\n/// <summary>\n/// Category error type for Windows OS errors.\n/// </summary>\nclass windows_category_impl : public std::error_category\n{\npublic:\n    virtual const char *name() const CPPREST_NOEXCEPT { return \"windows\"; }\n\n    _ASYNCRTIMP virtual std::string message(int errorCode) const CPPREST_NOEXCEPT;\n\n    _ASYNCRTIMP virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT;\n};\n\n/// <summary>\n/// Gets the one global instance of the windows error category.\n/// </summary>\n/// <returns>An error category instance.</returns>\n_ASYNCRTIMP const std::error_category & __cdecl windows_category();\n\n#else\n\n/// <summary>\n/// Gets the one global instance of the linux error category.\n/// </summary>\n/// </returns>An error category instance.</returns>\n_ASYNCRTIMP const std::error_category & __cdecl linux_category();\n\n#endif\n\n/// <summary>\n/// Gets the one global instance of the current platform's error category.\n/// </summary>\n_ASYNCRTIMP const std::error_category & __cdecl platform_category();\n\n/// <summary>\n/// Creates an instance of std::system_error from a OS error code.\n/// </summary>\ninline std::system_error __cdecl create_system_error(unsigned long errorCode)\n{\n    std::error_code code((int)errorCode, platform_category());\n    return std::system_error(code, code.message());\n}\n\n/// <summary>\n/// Creates a std::error_code from a OS error code.\n/// </summary>\ninline std::error_code __cdecl create_error_code(unsigned long errorCode)\n{\n    return std::error_code((int)errorCode, platform_category());\n}\n\n/// <summary>\n/// Creates the corresponding error message from a OS error code.\n/// </summary>\ninline utility::string_t __cdecl create_error_message(unsigned long errorCode)\n{\n    return utility::conversions::to_string_t(create_error_code(errorCode).message());\n}\n\n}\n\nclass datetime\n{\npublic:\n    typedef uint64_t interval_type;\n\n    /// <summary>\n    /// Defines the supported date and time string formats.\n    /// </summary>\n    enum date_format { RFC_1123, ISO_8601 };\n\n    /// <summary>\n    /// Returns the current UTC time.\n    /// </summary>\n    static _ASYNCRTIMP datetime __cdecl utc_now();\n\n    /// <summary>\n    /// An invalid UTC timestamp value.\n    /// </summary>\n    enum:interval_type { utc_timestamp_invalid = static_cast<interval_type>(-1) };\n\n    /// <summary>\n    /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.\n    /// If time is before epoch, utc_timestamp_invalid is returned.\n    /// </summary>\n    static interval_type utc_timestamp()\n    {\n        const auto seconds = utc_now().to_interval() / _secondTicks;\n        if (seconds >= 11644473600LL)\n        {\n            return seconds - 11644473600LL;\n        }\n        else\n        {\n            return utc_timestamp_invalid;\n        }\n    }\n\n    datetime() : m_interval(0)\n    {\n    }\n\n    /// <summary>\n    /// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.\n    /// </summary>\n    /// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>\n    static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);\n\n    /// <summary>\n    /// Returns a string representation of the <c>datetime</c>.\n    /// </summary>\n    _ASYNCRTIMP xsapi_internal_string to_string_internal(date_format format = RFC_1123) const;\n\n    /// <summary>\n    /// Returns the integral time value.\n    /// </summary>\n    interval_type to_interval() const\n    {\n        return m_interval;\n    }\n\n    datetime operator- (interval_type value) const\n    {\n        return datetime(m_interval - value);\n    }\n\n    datetime operator+ (interval_type value) const\n    {\n        return datetime(m_interval + value);\n    }\n\n    bool operator== (datetime dt) const\n    {\n        return m_interval == dt.m_interval;\n    }\n\n    bool operator!= (const datetime& dt) const\n    {\n        return !(*this == dt);\n    }\n\n    static interval_type from_milliseconds(unsigned int milliseconds)\n    {\n        return milliseconds*_msTicks;\n    }\n\n    static interval_type from_seconds(unsigned int seconds)\n    {\n        return seconds*_secondTicks;\n    }\n\n    static interval_type from_minutes(unsigned int minutes)\n    {\n        return minutes*_minuteTicks;\n    }\n\n    static interval_type from_hours(unsigned int hours)\n    {\n        return hours*_hourTicks;\n    }\n\n    static interval_type from_days(unsigned int days)\n    {\n        return days*_dayTicks;\n    }\n\n    bool is_initialized() const\n    {\n        return m_interval != 0;\n    }\n\nprivate:\n\n    friend int operator- (datetime t1, datetime t2);\n\n    static const interval_type _msTicks = static_cast<interval_type>(10000);\n    static const interval_type _secondTicks = 1000*_msTicks;\n    static const interval_type _minuteTicks = 60*_secondTicks;\n    static const interval_type _hourTicks   = 60*60*_secondTicks;\n    static const interval_type _dayTicks    = 24*60*60*_secondTicks;\n\n\n#ifdef _WIN32\n    // void* to avoid pulling in windows.h\n    static _ASYNCRTIMP bool __cdecl system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt);\n#else\n    static datetime timeval_to_datetime(const timeval &time);\n#endif\n\n    // Private constructor. Use static methods to create an instance.\n    datetime(interval_type interval) : m_interval(interval)\n    {\n    }\n\n    // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.\n    interval_type m_interval;\n};\n\n#ifndef _WIN32\n\n// temporary workaround for the fact that\n// utf16char is not fully supported in GCC\nclass cmp\n{\npublic:\n\n    static int icmp(std::string left, std::string right)\n    {\n        size_t i;\n        for (i = 0; i < left.size(); ++i)\n        {\n            if (i == right.size()) return 1;\n\n            auto l = cmp::tolower(left[i]);\n            auto r = cmp::tolower(right[i]);\n            if (l > r) return 1;\n            if (l < r) return -1;\n        }\n        if (i < right.size()) return -1;\n        return 0;\n    }\n\nprivate:\n    static char tolower(char c)\n    {\n        if (c >= 'A' && c <= 'Z')\n            return static_cast<char>(c - 'A' + 'a');\n        return c;\n    }\n};\n\n#endif\n\ninline int operator- (datetime t1, datetime t2)\n{\n    auto diff = (t1.m_interval - t2.m_interval);\n\n    // Round it down to seconds\n    diff /= 10 * 1000 * 1000;\n\n    return static_cast<int>(diff);\n}\n\n/// <summary>\n/// Nonce string generator class.\n/// </summary>\nclass nonce_generator\n{\npublic:\n\n    /// <summary>\n    /// Define default nonce length.\n    /// </summary>\n    enum { default_length = 32 };\n\n    /// <summary>\n    /// Nonce generator constructor.\n    /// </summary>\n    /// <param name=\"length\">Length of the generated nonce string.</param>\n    nonce_generator(int length=default_length) :\n        m_random(static_cast<unsigned int>(utility::datetime::utc_timestamp())),\n        m_length(length)\n    {}\n\n    /// <summary>\n    /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).\n    /// Length of the generated string is set by length().\n    /// </summary>\n    /// <returns>The generated nonce string.</returns>\n    _ASYNCRTIMP utility::string_t generate();\n\n    /// <summary>\n    /// Get length of generated nonce string.\n    /// </summary>\n    /// <returns>Nonce string length.</returns>\n    int length() const { return m_length; }\n\n    /// <summary>\n    /// Set length of the generated nonce string.\n    /// </summary>\n    /// <param name=\"length\">Lenght of nonce string.</param>\n    void set_length(int length) { m_length = length; }\n\nprivate:\n    static const utility::char_t* c_allowed_chars;\n    std::mt19937 m_random;\n    int m_length;\n};\n\n} // namespace utility;\n\n} } }\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Source/Shared/HookedUri/base_uri.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Protocol independent support for URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n#include <vector>\n#include <functional>\n\n#include \"HookedUri/asyncrt_utils.h\"\n#include \"HookedUri/details/basic_types.h\"\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace web {\n\n    namespace details\n    {\n        struct uri_components\n        {\n            uri_components() : m_path(\"/\"), m_port(-1)\n            {}\n\n            uri_components(const uri_components &other) :\n                m_scheme(other.m_scheme),\n                m_host(other.m_host),\n                m_user_info(other.m_user_info),\n                m_path(other.m_path),\n                m_query(other.m_query),\n                m_fragment(other.m_fragment),\n                m_port(other.m_port)\n            {}\n\n            uri_components & operator=(const uri_components &other)\n            {\n                if (this != &other)\n                {\n                    m_scheme = other.m_scheme;\n                    m_host = other.m_host;\n                    m_user_info = other.m_user_info;\n                    m_path = other.m_path;\n                    m_query = other.m_query;\n                    m_fragment = other.m_fragment;\n                    m_port = other.m_port;\n                }\n                return *this;\n            }\n\n            uri_components(uri_components &&other) CPPREST_NOEXCEPT :\n                m_scheme(std::move(other.m_scheme)),\n                m_host(std::move(other.m_host)),\n                m_user_info(std::move(other.m_user_info)),\n                m_path(std::move(other.m_path)),\n                m_query(std::move(other.m_query)),\n                m_fragment(std::move(other.m_fragment)),\n                m_port(other.m_port)\n            {}\n\n            uri_components & operator=(uri_components &&other) CPPREST_NOEXCEPT\n            {\n                if (this != &other)\n                {\n                    m_scheme = std::move(other.m_scheme);\n                    m_host = std::move(other.m_host);\n                    m_user_info = std::move(other.m_user_info);\n                    m_path = std::move(other.m_path);\n                    m_query = std::move(other.m_query);\n                    m_fragment = std::move(other.m_fragment);\n                    m_port = other.m_port;\n                }\n                return *this;\n            }\n\n            xsapi_internal_string join();\n\n            xsapi_internal_string m_scheme;\n            xsapi_internal_string m_host;\n            xsapi_internal_string m_user_info;\n            xsapi_internal_string m_path;\n            xsapi_internal_string m_query;\n            xsapi_internal_string m_fragment;\n            int m_port;\n        };\n    }\n\n    /// <summary>\n    /// A single exception type to represent errors in parsing, encoding, and decoding URIs.\n    /// </summary>\n    class uri_exception : public std::exception\n    {\n    public:\n\n        uri_exception(std::string msg) : m_msg(std::move(msg)) {}\n\n        ~uri_exception() CPPREST_NOEXCEPT {}\n\n        const char* what() const CPPREST_NOEXCEPT\n        {\n            return m_msg.c_str();\n        }\n\n    private:\n        std::string m_msg;\n    };\n\n    /// <summary>\n    /// A flexible, protocol independent URI implementation.\n    ///\n    /// URI instances are immutable. Querying the various fields on an emtpy URI will return empty strings. Querying\n    /// various diagnostic members on an empty URI will return false.\n    /// </summary>\n    /// <remarks>\n    /// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references\n    /// ('/path?query#frag').\n    ///\n    /// This implementation does not provide any scheme-specific handling -- an example of this\n    /// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid\n    /// http-uri -- that is, it's syntactically correct but does not conform to the requirements\n    /// of the http scheme (http requires a host).\n    /// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide\n    /// extra capability for validating and canonicalizing a URI according to scheme, and would\n    /// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics.\n    ///\n    /// One issue with implementing a scheme-independent URI facility is that of comparing for equality.\n    /// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is --\n    /// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme\n    /// to it's default port, we don't have a way to know these are equal. This is just one of a class of\n    /// issues with regard to scheme-specific behavior.\n    /// </remarks>\n    class uri\n    {\n    public:\n\n        /// <summary>\n        /// The various components of a URI. This enum is used to indicate which\n        /// URI component is being encoded to the encode_uri_component. This allows\n        /// specific encoding to be performed.\n        ///\n        /// Scheme and port don't allow '%' so they don't need to be encoded.\n        /// </summary>\n        class components\n        {\n        public:\n            enum component\n            {\n                user_info,\n                host,\n                path,\n                query,\n                fragment,\n                full_uri\n            };\n        };\n\n        /// <summary>\n        /// Encodes a URI component according to RFC 3986.\n        /// Note if a full URI is specified instead of an individual URI component all\n        /// characters not in the unreserved set are escaped.\n        /// </summary>\n        /// <param name=\"raw\">The URI as a string.</param>\n        /// <returns>The encoded string.</returns>\n        _ASYNCRTIMP static xsapi_internal_string __cdecl encode_uri(const xsapi_internal_string &raw, uri::components::component = components::full_uri);\n\n        /// <summary>\n        /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their\n        /// hexadecimal representation.\n        /// </summary>\n        /// <param name=\"utf8data\">The UTF-8 string data.</param>\n        /// <returns>The encoded string.</returns>\n        _ASYNCRTIMP static xsapi_internal_string __cdecl encode_data_string(const xsapi_internal_string &utf8data);\n\n        /// <summary>\n        /// Decodes an encoded string.\n        /// </summary>\n        /// <param name=\"encoded\">The URI as a string.</param>\n        /// <returns>The decoded string.</returns>\n        _ASYNCRTIMP static xsapi_internal_string __cdecl decode(const xsapi_internal_string &encoded);\n\n        /// <summary>\n        /// Splits a path into its hierarchical components.\n        /// </summary>\n        /// <param name=\"path\">The path as a string</param>\n        /// <returns>A <c>std::vector&lt;xsapi_internal_string&gt;</c> containing the segments in the path.</returns>\n        _ASYNCRTIMP static std::vector<xsapi_internal_string> __cdecl split_path(const xsapi_internal_string &path);\n\n        /// <summary>\n        /// Splits a query into its key-value components.\n        /// </summary>\n        /// <param name=\"query\">The query string</param>\n        /// <returns>A <c>std::map&lt;xsapi_internal_string, xsapi_internal_string&gt;</c> containing the key-value components of the query.</returns>\n        _ASYNCRTIMP static std::map<xsapi_internal_string, xsapi_internal_string> __cdecl split_query(const xsapi_internal_string &query);\n\n        /// <summary>\n        /// Validates a string as a URI.\n        /// </summary>\n        /// <param name=\"uri_string\">The URI string to be validated.</param>\n        /// <returns><c>true</c> if the given string represents a valid URI, <c>false</c> otherwise.</returns>\n        _ASYNCRTIMP static bool __cdecl validate(const xsapi_internal_string &uri_string);\n\n        /// <summary>\n        /// Creates an empty uri\n        /// </summary>\n        uri() { m_uri = \"/\";};\n\n        /// <summary>\n        /// Creates a URI from the given URI components.\n        /// </summary>\n        /// <param name=\"components\">A URI components object to create the URI instance.</param>\n        _ASYNCRTIMP uri(const details::uri_components &components);\n\n        /// <summary>\n        /// Creates a URI from the given encoded string. This will throw an exception if the string\n        /// does not contain a valid URI. Use uri::validate if processing user-input.\n        /// </summary>\n        /// <param name=\"uri_string\">A pointer to an encoded string to create the URI instance.</param>\n        _ASYNCRTIMP uri(const char *uri_string);\n\n        /// <summary>\n        /// Creates a URI from the given encoded string. This will throw an exception if the string\n        /// does not contain a valid URI. Use uri::validate if processing user-input.\n        /// </summary>\n        /// <param name=\"uri_string\">An encoded URI string to create the URI instance.</param>\n        _ASYNCRTIMP uri(const xsapi_internal_string &uri_string);\n\n        /// <summary>\n        /// Copy constructor.\n        /// </summary>\n        uri(const uri &other) :\n            m_uri(other.m_uri),\n            m_components(other.m_components)\n        {}\n\n        /// <summary>\n        /// Copy assignment operator.\n        /// </summary>\n        uri & operator=(const uri &other)\n        {\n            if (this != &other)\n            {\n                m_uri = other.m_uri;\n                m_components = other.m_components;\n            }\n            return *this;\n        }\n\n        /// <summary>\n        /// Move constructor.\n        /// </summary>\n        uri(uri &&other) CPPREST_NOEXCEPT :\n            m_uri(std::move(other.m_uri)),\n            m_components(std::move(other.m_components))\n        {}\n\n        /// <summary>\n        /// Move assignment operator\n        /// </summary>\n        uri & operator=(uri &&other) CPPREST_NOEXCEPT\n        {\n            if (this != &other)\n            {\n                m_uri = std::move(other.m_uri);\n                m_components = std::move(other.m_components);\n            }\n            return *this;\n        }\n\n        /// <summary>\n        /// Get the scheme component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI scheme as a string.</returns>\n        const xsapi_internal_string &scheme() const { return m_components.m_scheme; }\n\n        /// <summary>\n        /// Get the user information component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI user information as a string.</returns>\n        const xsapi_internal_string &user_info() const { return m_components.m_user_info; }\n\n        /// <summary>\n        /// Get the host component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI host as a string.</returns>\n        const xsapi_internal_string &host() const { return m_components.m_host; }\n\n        /// <summary>\n        /// Get the port component of the URI. Returns -1 if no port is specified.\n        /// </summary>\n        /// <returns>The URI port as an integer.</returns>\n        int port() const { return m_components.m_port; }\n\n        /// <summary>\n        /// Get the path component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI path as a string.</returns>\n        const xsapi_internal_string &path() const { return m_components.m_path; }\n\n        /// <summary>\n        /// Get the query component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI query as a string.</returns>\n        const xsapi_internal_string &query() const { return m_components.m_query; }\n\n        /// <summary>\n        /// Get the fragment component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI fragment as a string.</returns>\n        const xsapi_internal_string &fragment() const { return m_components.m_fragment; }\n\n        /// <summary>\n        /// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions.\n        /// </summary>\n        /// <returns>The new uri object with the same authority.</returns>\n        _ASYNCRTIMP uri authority() const;\n\n        /// <summary>\n        /// Gets the path, query, and fragment portion of this uri, which may be empty.\n        /// </summary>\n        /// <returns>The new URI object with the path, query and fragment portion of this URI.</returns>\n        _ASYNCRTIMP uri resource() const;\n\n        /// <summary>\n        /// An empty URI specifies no components, and serves as a default value\n        /// </summary>\n        bool is_empty() const\n        {\n            return this->m_uri.empty() || this->m_uri == \"/\";\n        }\n\n        /// <summary>\n        /// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine.\n        /// </summary>\n        /// <remarks>\n        /// Examples include \"locahost\", or ip addresses in the loopback range (127.0.0.0/24).\n        /// </remarks>\n        /// <returns><c>true</c> if this URI references the local host, <c>false</c> otherwise.</returns>\n        bool is_host_loopback() const\n        {\n            return !is_empty() && ((host() == \"localhost\") || (host().size() > 4 && host().substr(0,4) == \"127.\"));\n        }\n\n        /// <summary>\n        /// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +)\n        /// </summary>\n        /// <example>\n        /// http://*:80\n        /// </example>\n        bool is_host_wildcard() const\n        {\n            return !is_empty() && (this->host() == \"*\" || this->host() == \"+\");\n        }\n\n        /// <summary>\n        /// A portable URI is one with a hostname that can be resolved globally (used from another machine).\n        /// </summary>\n        /// <returns><c>true</c> if this URI can be resolved globally (used from another machine), <c>false</c> otherwise.</returns>\n        /// <remarks>\n        /// The hostname \"localhost\" is a reserved name that is guaranteed to resolve to the local machine,\n        /// and cannot be used for inter-machine communication. Likewise the hostnames \"*\" and \"+\" on Windows\n        /// represent wildcards, and do not map to a resolvable address.\n        /// </remarks>\n        bool is_host_portable() const\n        {\n            return !(is_empty() || is_host_loopback() || is_host_wildcard());\n        }\n\n        /// <summary>\n        /// A default port is one where the port is unspecified, and will be determined by the operating system.\n        /// The choice of default port may be dictated by the scheme (http -> 80) or not.\n        /// </summary>\n        /// <returns><c>true</c> if this URI instance has a default port, <c>false</c> otherwise.</returns>\n        bool is_port_default() const\n        {\n            return !is_empty() && this->port() == 0;\n        }\n\n        /// <summary>\n        /// An \"authority\" URI is one with only a scheme, optional userinfo, hostname, and (optional) port.\n        /// </summary>\n        /// <returns><c>true</c> if this is an \"authority\" URI, <c>false</c> otherwise.</returns>\n        bool is_authority() const\n        {\n            return !is_empty() && is_path_empty() && query().empty() && fragment().empty();\n        }\n\n        /// <summary>\n        /// Returns whether the other URI has the same authority as this one\n        /// </summary>\n        /// <param name=\"other\">The URI to compare the authority with.</param>\n        /// <returns><c>true</c> if both the URI's have the same authority, <c>false</c> otherwise.</returns>\n        bool has_same_authority(const uri &other) const\n        {\n            return !is_empty() && this->authority() == other.authority();\n        }\n\n        /// <summary>\n        /// Returns whether the path portion of this URI is empty\n        /// </summary>\n        /// <returns><c>true</c> if the path portion of this URI is empty, <c>false</c> otherwise.</returns>\n        bool is_path_empty() const\n        {\n            return path().empty() || path() == \"/\";\n        }\n\n        /// <summary>\n        /// Returns the full (encoded) URI as a string.\n        /// </summary>\n         /// <returns>The full encoded URI string.</returns>\n        xsapi_internal_string to_string() const\n        {\n            return m_uri;\n        }\n\n        _ASYNCRTIMP bool operator == (const uri &other) const;\n\n        bool operator < (const uri &other) const\n        {\n            return m_uri < other.m_uri;\n        }\n\n        bool operator != (const uri &other) const\n        {\n            return !(this->operator == (other));\n        }\n\n        friend class uri_builder;\n\n        // Encodes all characters not in given set determined by given function.\n        _ASYNCRTIMP static xsapi_internal_string __cdecl encode_impl(const xsapi_internal_string& raw, const std::function<bool __cdecl(int)>& should_encode);\n\n        xsapi_internal_string m_uri;\n        details::uri_components m_components;\n    };\n\n} // namespace web\n\n} } }"
  },
  {
    "path": "Source/Shared/HookedUri/details/asyncrt_utils.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Utilities\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#if defined(_WIN32)\n#if HC_PLATFORM != HC_PLATFORM_XDK\n#include <winhttp.h>\n#endif\n#else // _WIN32\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-local-typedef\"\n#endif\n// TODO 1808 #include <boost/date_time/posix_time/posix_time.hpp>\n// #include <boost/date_time/posix_time/posix_time_io.hpp>\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n#endif // _WIN32\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#pragma warning( disable : 26498 ) // ignore eof warning \n#pragma warning( disable : 26812 )  // enum instead of enum class\n#endif\n\n// Could use C++ standard library if not __GLIBCXX__,\n// For testing purposes we just the handwritten on all platforms.\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n#include <codecvt>\n#endif\n\nusing namespace xbox::services::cppresturi::web;\nusing namespace xbox::services::cppresturi::utility;\nusing namespace xbox::services::cppresturi::utility::conversions;\n\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace utility\n{\n\nnamespace details\n{\n\n#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(PAVO)\nstd::once_flag g_c_localeFlag;\nstd::unique_ptr<scoped_c_thread_locale::xplat_locale, void(*)(scoped_c_thread_locale::xplat_locale *)> g_c_locale(nullptr, [](scoped_c_thread_locale::xplat_locale *){});\nscoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale()\n{\n    std::call_once(g_c_localeFlag, [&]()\n    {\n        scoped_c_thread_locale::xplat_locale *clocale = new scoped_c_thread_locale::xplat_locale();\n#ifdef _WIN32\n        if (clocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to create 'C' locale.\");\n        }\n        *clocale = _create_locale(LC_ALL, \"C\");\n        if (clocale == nullptr || *clocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to create 'C' locale.\");\n        }\n        auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale)\n        {\n            _free_locale(*clocale);\n            delete clocale;\n        };\n#else\n        *clocale = newlocale(LC_ALL, \"C\", nullptr);\n        if (clocale == nullptr || *clocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to create 'C' locale.\");\n        }\n        auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale)\n        {\n            freelocale(*clocale);\n            delete clocale;\n        };\n#endif\n        g_c_locale = std::unique_ptr<scoped_c_thread_locale::xplat_locale, void(*)(scoped_c_thread_locale::xplat_locale *)>(clocale, deleter);\n    });\n    return *g_c_locale;\n}\n#endif\n\n#ifdef _WIN32\nscoped_c_thread_locale::scoped_c_thread_locale()\n    : m_prevLocale(), m_prevThreadSetting(-1)\n{\n    char *prevLocale = setlocale(LC_ALL, nullptr);\n    if (prevLocale == nullptr)\n    {\n        throw std::runtime_error(\"Unable to retrieve current locale.\");\n    }\n\n    if (std::strcmp(prevLocale, \"C\") != 0)\n    {\n        m_prevLocale = prevLocale;\n        m_prevThreadSetting = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);\n        if (m_prevThreadSetting == -1)\n        {\n            throw std::runtime_error(\"Unable to enable per thread locale.\");\n        }\n        if (setlocale(LC_ALL, \"C\") == nullptr)\n        {\n             _configthreadlocale(m_prevThreadSetting);\n             throw std::runtime_error(\"Unable to set locale\");\n        }\n    }\n}\n\nscoped_c_thread_locale::~scoped_c_thread_locale()\n{\n    if (m_prevThreadSetting != -1)\n    {\n        setlocale(LC_ALL, m_prevLocale.c_str());\n        _configthreadlocale(m_prevThreadSetting);\n    }\n}\n#elif (defined(ANDROID) || defined(__ANDROID__) || defined(PAVO))\nscoped_c_thread_locale::scoped_c_thread_locale() {}\nscoped_c_thread_locale::~scoped_c_thread_locale() {}\n#else\nscoped_c_thread_locale::scoped_c_thread_locale()\n    : m_prevLocale(nullptr)\n{\n    char *prevLocale = setlocale(LC_ALL, nullptr);\n    if (prevLocale == nullptr)\n    {\n        throw std::runtime_error(\"Unable to retrieve current locale.\");\n    }\n\n    if (std::strcmp(prevLocale, \"C\") != 0)\n    {\n        m_prevLocale = uselocale(c_locale());\n        if (m_prevLocale == nullptr)\n        {\n            throw std::runtime_error(\"Unable to set locale\");\n        }\n    }\n}\n\nscoped_c_thread_locale::~scoped_c_thread_locale()\n{\n    if (m_prevLocale != nullptr)\n    {\n        uselocale(m_prevLocale);\n    }\n}\n#endif\n}\n\nnamespace details\n{\n\nconst std::error_category & platform_category()\n{\n#ifdef _WIN32\n    return windows_category();\n#else\n    return linux_category();\n#endif\n}\n\n#ifdef _WIN32\n\n// Remove once VS 2013 is no longer supported.\n#if _MSC_VER < 1900\nstatic details::windows_category_impl instance;\n#endif\nconst std::error_category & windows_category()\n{\n#if _MSC_VER >= 1900\n    static details::windows_category_impl instance;\n#endif\n    return instance;\n}\n\nstd::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT\n{\n#if 0 // this returns a non-mem hooked string which can't be changed so commenting it out since its not really needed\n    const size_t buffer_size = 4096;\n    DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;\n    LPCVOID lpSource = NULL;\n\n#if !defined(__cplusplus_winrt)\n    if (errorCode >= 12000)\n    {\n        dwFlags = FORMAT_MESSAGE_FROM_HMODULE;\n        lpSource = GetModuleHandleA(\"winhttp.dll\"); // this handle DOES NOT need to be freed\n    }\n#endif\n\n    std::wstring buffer;\n    buffer.resize(buffer_size);\n\n    const auto result = ::FormatMessageW(\n        dwFlags,\n        lpSource,\n        errorCode,\n        0,\n        &buffer[0],\n        buffer_size,\n        NULL);\n    if (result == 0)\n    {\n        std::ostringstream os;\n        os << \"Unable to get an error message for error code: \" << errorCode << \".\";\n        return os.str();\n    }\n\n    return utility::conversions::to_utf8string(buffer);\n#else\n    UNREFERENCED_PARAMETER(errorCode);\n    return std::string();\n#endif\n}\n\nstd::error_condition windows_category_impl::default_error_condition(int errorCode) const CPPREST_NOEXCEPT\n{\n    // First see if the STL implementation can handle the mapping for common cases.\n    const std::error_condition errCondition = std::system_category().default_error_condition(errorCode);\n    const std::string errConditionMsg = errCondition.message();\n    if(_stricmp(errConditionMsg.c_str(), \"unknown error\") != 0)\n    {\n        return errCondition;\n    }\n\n    switch(errorCode)\n    {\n#ifndef __cplusplus_winrt\n    case ERROR_WINHTTP_TIMEOUT:\n        return std::errc::timed_out;\n    case ERROR_WINHTTP_CANNOT_CONNECT:\n        return std::errc::host_unreachable;\n    case ERROR_WINHTTP_CONNECTION_ERROR:\n        return std::errc::connection_aborted;\n#endif\n    case INET_E_RESOURCE_NOT_FOUND:\n    case INET_E_CANNOT_CONNECT:\n        return std::errc::host_unreachable;\n    case INET_E_CONNECTION_TIMEOUT:\n        return std::errc::timed_out;\n    case INET_E_DOWNLOAD_FAILURE:\n        return std::errc::connection_aborted;\n    default:\n        break;\n    }\n\n    return std::error_condition(errorCode, *this);\n}\n\n#else\n\nconst std::error_category & linux_category()\n{\n    // On Linux we are using boost error codes which have the exact same\n    // mapping and are equivalent with std::generic_category error codes.\n    return std::generic_category();\n}\n\n#endif\n\n}\n\n#define LOW_3BITS 0x7\n#define LOW_4BITS 0xF\n#define LOW_5BITS 0x1F\n#define LOW_6BITS 0x3F\n#define BIT4 0x8\n#define BIT5 0x10\n#define BIT6 0x20\n#define BIT7 0x40\n#define BIT8 0x80\n#define L_SURROGATE_START 0xDC00\n#define L_SURROGATE_END 0xDFFF\n#define H_SURROGATE_START 0xD800\n#define H_SURROGATE_END 0xDBFF\n#define SURROGATE_PAIR_START 0x10000\n\nutf16string conversions::utf8_to_utf16(const std::string &s)\n{\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n    std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n    return conversion.from_bytes(s);\n#else\n    utf16string dest;\n    // Save repeated heap allocations, use less than source string size assuming some\n    // of the characters are not just ASCII and collapse.\n    dest.reserve(static_cast<size_t>(static_cast<double>(s.size()) * .70));\n    \n    for (auto src = s.begin(); src != s.end(); ++src)\n    {\n        if ((*src & BIT8) == 0) // single byte character, 0x0 to 0x7F\n        {\n            dest.push_back(utf16string::value_type(*src));\n        }\n        else\n        {\n            unsigned char numContBytes = 0;\n            uint32_t codePoint;\n            if ((*src & BIT7) == 0)\n            {\n                throw std::range_error(\"UTF-8 string character can never start with 10xxxxxx\");\n            }\n            else if ((*src & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF\n            {\n                codePoint = *src & LOW_5BITS;\n                numContBytes = 1;\n            }\n            else if ((*src & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF\n            {\n                codePoint = *src & LOW_4BITS;\n                numContBytes = 2;\n            }\n            else if ((*src & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF\n            {\n                codePoint = *src & LOW_3BITS;\n                numContBytes = 3;\n            }\n            else\n            {\n                throw std::range_error(\"UTF-8 string has invalid Unicode code point\");\n            }\n\n            for (unsigned char i = 0; i < numContBytes; ++i)\n            {\n                if (++src == s.end())\n                {\n                    throw std::range_error(\"UTF-8 string is missing bytes in character\");\n                }\n                if ((*src & BIT8) == 0 || (*src & BIT7) != 0)\n                {\n                    throw std::range_error(\"UTF-8 continuation byte is missing leading byte\");\n                }\n                codePoint <<= 6;\n                codePoint |= *src & LOW_6BITS;\n            }\n\n            if (codePoint >= SURROGATE_PAIR_START)\n            {\n                // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs.\n                //  - 0x10000 is subtracted from the code point\n                //  - high surrogate is 0xD800 added to the top ten bits\n                //  - low surrogate is 0xDC00 added to the low ten bits\n                codePoint -= SURROGATE_PAIR_START;\n                dest.push_back(utf16string::value_type((codePoint >> 10) | H_SURROGATE_START));\n                dest.push_back(utf16string::value_type((codePoint & 0x3FF) | L_SURROGATE_START));\n            }\n            else\n            {\n                // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value.\n                // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode\n                // them if encountered.\n                dest.push_back(utf16string::value_type(codePoint));\n            }\n        }\n    }\n    return dest;\n#endif\n}\n\nxsapi_internal_string conversions::utf16_to_utf8_internal(const xsapi_internal_wstring &w)\n{\n #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n     std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n     return conversion.to_bytes(w);\n #else\n    xsapi_internal_string dest;\n    dest.reserve(w.size());\n    for (auto src = w.begin(); src != w.end(); ++src)\n    {\n        // Check for high surrogate.\n        if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END)\n        {\n            const auto highSurrogate = *src++;\n            if (src == w.end())\n            {\n                throw std::range_error(\"UTF-16 string is missing low surrogate\");\n            }\n            const auto lowSurrogate = *src;\n            if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END)\n            {\n                throw std::range_error(\"UTF-16 string has invalid low surrogate\");\n            }\n\n            // To get from surrogate pair to Unicode code point:\n            // - subract 0xD800 from high surrogate, this forms top ten bits\n            // - subract 0xDC00 from low surrogate, this forms low ten bits\n            // - add 0x10000\n            // Leaves a code point in U+10000 to U+10FFFF range.\n            uint32_t codePoint = highSurrogate - H_SURROGATE_START;\n            codePoint <<= 10;\n            codePoint |= lowSurrogate - L_SURROGATE_START;\n            codePoint += SURROGATE_PAIR_START;\n\n            // 4 bytes need using 21 bits\n            dest.push_back(char((codePoint >> 18) | 0xF0));                 // leading 3 bits\n            dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8));   // next 6 bits\n            dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8));    // next 6 bits\n            dest.push_back(char((codePoint & LOW_6BITS) | BIT8));           // trailing 6 bits\n        }\n        else\n        {\n            if (*src <= 0x7F) // single byte character\n            {\n                dest.push_back(static_cast<char>(*src));\n            }\n            else if (*src <= 0x7FF) // 2 bytes needed (11 bits used)\n            {\n                dest.push_back(char((*src >> 6) | 0xC0));               // leading 5 bits\n                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n            }\n            else // 3 bytes needed (16 bits used)\n            {\n                dest.push_back(char((*src >> 12) | 0xE0));              // leading 4 bits\n                dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits\n                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n            }\n        }\n    }\n\n    return dest;\n #endif\n}\n\nstd::string conversions::utf16_to_utf8(const utf16string&w)\n{\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n    std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n    return conversion.to_bytes(w);\n#else\n    std::string dest;\n    dest.reserve(w.size());\n    for (auto src = w.begin(); src != w.end(); ++src)\n    {\n        // Check for high surrogate.\n        if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END)\n        {\n            const auto highSurrogate = *src++;\n            if (src == w.end())\n            {\n                throw std::range_error(\"UTF-16 string is missing low surrogate\");\n            }\n            const auto lowSurrogate = *src;\n            if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END)\n            {\n                throw std::range_error(\"UTF-16 string has invalid low surrogate\");\n            }\n\n            // To get from surrogate pair to Unicode code point:\n            // - subract 0xD800 from high surrogate, this forms top ten bits\n            // - subract 0xDC00 from low surrogate, this forms low ten bits\n            // - add 0x10000\n            // Leaves a code point in U+10000 to U+10FFFF range.\n            uint32_t codePoint = highSurrogate - H_SURROGATE_START;\n            codePoint <<= 10;\n            codePoint |= lowSurrogate - L_SURROGATE_START;\n            codePoint += SURROGATE_PAIR_START;\n\n            // 4 bytes need using 21 bits\n            dest.push_back(char((codePoint >> 18) | 0xF0));                 // leading 3 bits\n            dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8));   // next 6 bits\n            dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8));    // next 6 bits\n            dest.push_back(char((codePoint & LOW_6BITS) | BIT8));           // trailing 6 bits\n        }\n        else\n        {\n            if (*src <= 0x7F) // single byte character\n            {\n                dest.push_back(static_cast<char>(*src));\n            }\n            else if (*src <= 0x7FF) // 2 bytes needed (11 bits used)\n            {\n                dest.push_back(char((*src >> 6) | 0xC0));               // leading 5 bits\n                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n            }\n            else // 3 bytes needed (16 bits used)\n            {\n                dest.push_back(char((*src >> 12) | 0xE0));              // leading 4 bits\n                dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits\n                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n            }\n        }\n    }\n\n    return dest;\n#endif\n}\n\nutf16string conversions::usascii_to_utf16(const std::string &s)\n{\n    // Ascii is a subset of UTF-8 so just convert to UTF-16\n    return utf8_to_utf16(s);\n}\n\nxsapi_internal_wstring conversions::latin1_to_utf16_internal(const xsapi_internal_string &s)\n{\n    // Latin1 is the first 256 code points in Unicode.\n    // In UTF-16 encoding each of these is represented as exactly the numeric code point.\n    xsapi_internal_wstring dest;\n    dest.resize(s.size());\n    for (size_t i = 0; i < s.size(); ++i)\n    {\n        dest[i] = utf16char(static_cast<unsigned char>(s[i]));\n    }\n    return dest;\n}\n\nxsapi_internal_string conversions::latin1_to_utf8_internal(const xsapi_internal_string &s)\n{\n    return utf16_to_utf8_internal(latin1_to_utf16_internal(s));\n}\n\nutility::string_t conversions::to_string_t(utf16string &&s)\n{\n#ifdef _UTF16_STRINGS\n    return std::move(s);\n#else\n    return utf16_to_utf8(std::move(s));\n#endif\n}\n\nutility::string_t conversions::to_string_t(std::string &&s)\n{\n#ifdef _UTF16_STRINGS\n    return utf8_to_utf16(std::move(s));\n#else\n    return std::move(s);\n#endif\n}\n\nutility::string_t conversions::to_string_t(const utf16string &s)\n{\n#ifdef _UTF16_STRINGS\n    return s;\n#else\n    return utf16_to_utf8(s);\n#endif\n}\n\nutility::string_t conversions::to_string_t(const std::string &s)\n{\n#ifdef _UTF16_STRINGS\n    return utf8_to_utf16(s);\n#else\n    return s;\n#endif\n}\n\nxsapi_internal_string conversions::to_utf8string_internal(xsapi_internal_string value) { return value; }\n\nxsapi_internal_string conversions::to_utf8string_internal(const xsapi_internal_wstring &value)\n{ \n    return utf16_to_utf8_internal(value);\n}\n\nutf16string conversions::to_utf16string(const std::string &value) { return utf8_to_utf16(value); }\n\nutf16string conversions::to_utf16string(utf16string value) { return value; }\n\n#ifndef _WIN32\ndatetime datetime::timeval_to_datetime(const timeval &time)\n{\n    const uint64_t epoch_offset = 11644473600LL; // diff between windows and unix epochs (seconds)\n    uint64_t result = epoch_offset + time.tv_sec;\n    result *= _secondTicks; // convert to 10e-7\n    result += time.tv_usec * 10; // convert and add microseconds, 10e-6 to 10e-7\n    return datetime(result);\n}\n#endif\n\nstatic bool is_digit(utility::char_t c) { return c >= _XPLATSTR('0') && c <= _XPLATSTR('9'); }\n\ndatetime datetime::utc_now()\n{\n#ifdef _WIN32\n    ULARGE_INTEGER largeInt;\n    FILETIME fileTime;\n    GetSystemTimeAsFileTime(&fileTime);\n\n    largeInt.LowPart = fileTime.dwLowDateTime;\n    largeInt.HighPart = fileTime.dwHighDateTime;\n\n    return datetime(largeInt.QuadPart);\n#else //LINUX\n    timeval time {};\n    gettimeofday(&time, nullptr);\n    return timeval_to_datetime(time);\n#endif\n}\n\nxsapi_internal_string datetime::to_string_internal(date_format format) const\n{\n#ifdef _WIN32\n    int status;\n\n    ULARGE_INTEGER largeInt;\n    largeInt.QuadPart = m_interval;\n\n    FILETIME ft;\n    ft.dwHighDateTime = largeInt.HighPart;\n    ft.dwLowDateTime = largeInt.LowPart;\n\n    SYSTEMTIME systemTime;\n    if (!FileTimeToSystemTime((const FILETIME *)&ft, &systemTime))\n    {\n        throw utility::details::create_system_error(GetLastError());\n    }\n\n    constexpr size_t dateTimeMaxLength{ 256 };\n    wchar_t dateTimeBuffer[dateTimeMaxLength]{ 0 };\n\n    if (format == RFC_1123)\n    {\n        wchar_t dateStr[18] = { 0 };\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        status = GetDateFormatW(LOCALE_INVARIANT, 0, &systemTime, L\"ddd',' dd MMM yyyy\", dateStr, sizeof(dateStr) / sizeof(wchar_t));\n#else\n        status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L\"ddd',' dd MMM yyyy\", dateStr, sizeof(dateStr) / sizeof(wchar_t), NULL);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        wchar_t timeStr[10] = { 0 };\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        status = GetTimeFormatW(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, sizeof(timeStr) / sizeof(wchar_t));\n#else\n        status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, sizeof(timeStr) / sizeof(wchar_t));\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        _snwprintf_s(dateTimeBuffer, sizeof(dateTimeBuffer), L\"%s %s GMT\", dateStr, timeStr);\n    }\n    else if (format == ISO_8601)\n    {\n        const size_t buffSize = 64;\n        wchar_t dateStr[buffSize] = { 0 };\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        status = GetDateFormatW(LOCALE_INVARIANT, 0, &systemTime, L\"yyyy-MM-dd\", dateStr, buffSize);\n#else\n        status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L\"yyyy-MM-dd\", dateStr, buffSize, NULL);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        wchar_t timeStr[buffSize] = { 0 };\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n        status = GetTimeFormatW(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, buffSize);\n#else\n        status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, buffSize);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n        if (status == 0)\n        {\n            throw utility::details::create_system_error(GetLastError());\n        }\n\n        wchar_t fracSecBuf[9] = { 0 };\n        uint64_t frac_sec = largeInt.QuadPart % _secondTicks;\n        if (frac_sec > 0)\n        {\n            // Append fractional second, which is a 7-digit value with no trailing zeros\n            // This way, '1200' becomes '00012'\n            _snwprintf_s(fracSecBuf, sizeof(fracSecBuf), L\".%07ld\", (long int)frac_sec);\n            // trim trailing zeros\n            for (int i = 7; fracSecBuf[i] == '0'; i--) fracSecBuf[i] = '\\0';\n        }\n\n        _snwprintf_s(dateTimeBuffer, dateTimeMaxLength, L\"%sT%sZ%s\", dateStr, timeStr, fracSecBuf);\n    }\n\n    return conversions::to_utf8string_internal(dateTimeBuffer);\n#else //LINUX\n    uint64_t input = m_interval;\n    uint64_t frac_sec = input % _secondTicks;\n    input /= _secondTicks; // convert to seconds\n    time_t time = (time_t)input - (time_t)11644473600LL;// diff between windows and unix epochs (seconds)\n\n    struct tm datetime;\n#if defined(PAVO)\n    gmtime_s(&time, &datetime);\n#else\n    gmtime_r(&time, &datetime);\n#endif // PAVO\n\n    const int max_dt_length = 64;\n    char output[max_dt_length+1] = {0};\n\n    if (format != RFC_1123 && frac_sec > 0)\n    {\n        // Append fractional second, which is a 7-digit value with no trailing zeros\n        // This way, '1200' becomes '00012'\n        char buf[9] = { 0 };\n        snprintf(buf, sizeof(buf), \".%07ld\", (long int)frac_sec);\n        // trim trailing zeros\n        for (int i = 7; buf[i] == '0'; i--) buf[i] = '\\0';\n        // format the datetime into a separate buffer\n        char datetime_str[max_dt_length+1] = {0};\n        strftime(datetime_str, sizeof(datetime_str), \"%Y-%m-%dT%H:%M:%S\", &datetime);\n        // now print this buffer into the output buffer\n        snprintf(output, sizeof(output), \"%s%sZ\", datetime_str, buf);\n    }\n    else\n    {\n        strftime(output, sizeof(output),\n            format == RFC_1123 ? \"%a, %d %b %Y %H:%M:%S GMT\" : \"%Y-%m-%dT%H:%M:%SZ\",\n            &datetime);\n    }\n\n    return xsapi_internal_string(output);\n#endif\n}\n\n#ifdef _WIN32\nbool datetime::system_type_to_datetime(void* pvsysTime, uint64_t seconds, datetime * pdt)\n{\n    SYSTEMTIME* psysTime = (SYSTEMTIME*)pvsysTime;\n    FILETIME fileTime;\n\n    if (SystemTimeToFileTime(psysTime, &fileTime))\n    {\n        ULARGE_INTEGER largeInt;\n        largeInt.LowPart = fileTime.dwLowDateTime;\n        largeInt.HighPart = fileTime.dwHighDateTime;\n\n        // Add hundredths of nanoseconds\n        largeInt.QuadPart += seconds;\n\n        *pdt = datetime(largeInt.QuadPart);\n        return true;\n    }\n    return false;\n}\n#endif\n\n// Take a string that represents a fractional second and return the number of ticks\n// This is equivalent to doing atof on the string and multiplying by 10000000,\n// but does not lose precision\ntemplate<typename StringIterator>\nuint64_t timeticks_from_second(StringIterator begin, StringIterator end)\n{\n    int size = (int)(end - begin);\n    _ASSERTE(begin[0] == U('.'));\n    uint64_t ufrac_second = 0;\n    for (int i = 1; i <= 7; ++i)\n    {\n        ufrac_second *= 10;\n        int add = i < size ? begin[i] - U('0') : 0;\n        ufrac_second += add;\n    }\n    return ufrac_second;\n}\n\nvoid extract_fractional_second(const utility::string_t& dateString, utility::string_t& resultString, uint64_t& ufrac_second)\n{\n    resultString = dateString;\n    // First, the string must be strictly longer than 2 characters, and the trailing character must be 'Z'\n    if (resultString.size() > 2 && resultString[resultString.size() - 1] == U('Z'))\n    {\n        // Second, find the last non-digit by scanning the string backwards\n        auto last_non_digit = std::find_if_not(resultString.rbegin() + 1, resultString.rend(), is_digit);\n        if (last_non_digit < resultString.rend() - 1)\n        {\n            // Finally, make sure the last non-digit is a dot:\n            auto last_dot = last_non_digit.base() - 1;\n            if (*last_dot == U('.'))\n            {\n                // Got it! Now extract the fractional second\n                auto last_before_Z = std::end(resultString) - 1;\n                ufrac_second = timeticks_from_second(last_dot, last_before_Z);\n                // And erase it from the string\n                resultString.erase(last_dot, last_before_Z);\n            }\n        }\n    }\n}\n\ndatetime datetime::from_string(const utility::string_t& dateString, date_format format)\n{\n    // avoid floating point math to preserve precision\n    uint64_t ufrac_second = 0;\n\n#ifdef _WIN32\n    datetime result;\n    if (format == RFC_1123)\n    {\n        SYSTEMTIME sysTime = {0};\n\n        std::wstring month(3, L'\\0');\n        std::wstring unused(3, L'\\0');\n\n        const wchar_t * formatString = L\"%3c, %2d %3c %4d %2d:%2d:%2d %3c\";\n        auto n = swscanf_s(dateString.c_str(), formatString,\n            unused.data(), unused.size(),\n            &sysTime.wDay,\n            month.data(), month.size(),\n            &sysTime.wYear,\n            &sysTime.wHour,\n            &sysTime.wMinute,\n            &sysTime.wSecond,\n            unused.data(), unused.size());\n\n        if (n == 8)\n        {\n            std::wstring monthnames[12] = {L\"Jan\", L\"Feb\", L\"Mar\", L\"Apr\", L\"May\", L\"Jun\", L\"Jul\", L\"Aug\", L\"Sep\", L\"Oct\", L\"Nov\", L\"Dec\"};\n            auto loc = std::find_if(monthnames, monthnames+12, [&month](const std::wstring& m) { return m == month;});\n\n            if (loc != monthnames+12)\n            {\n                sysTime.wMonth = (short) ((loc - monthnames) + 1);\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (format == ISO_8601)\n    {\n        // Unlike FILETIME, SYSTEMTIME does not have enough precision to hold seconds in 100 nanosecond\n        // increments. Therefore, start with seconds and milliseconds set to 0, then add them separately\n\n        // Try to extract the fractional second from the timestamp\n        utility::string_t input;\n        extract_fractional_second(dateString, input, ufrac_second);\n        {\n            SYSTEMTIME sysTime = { 0 };\n            const wchar_t * formatString = L\"%4d-%2d-%2dT%2d:%2d:%2dZ\";\n            auto n = swscanf_s(input.c_str(), formatString,\n                &sysTime.wYear,\n                &sysTime.wMonth,\n                &sysTime.wDay,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond);\n\n            if (n == 3 || n == 6)\n            {\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n        {\n            SYSTEMTIME sysTime = {0};\n            DWORD date = 0;\n\n            const wchar_t * formatString = L\"%8dT%2d:%2d:%2dZ\";\n            auto n = swscanf_s(input.c_str(), formatString,\n                &date,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond);\n\n            if (n == 1 || n == 4)\n            {\n                sysTime.wDay = date % 100;\n                date /= 100;\n                sysTime.wMonth = date % 100;\n                date /= 100;\n                sysTime.wYear = (WORD)date;\n\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n        {\n            SYSTEMTIME sysTime = {0};\n            GetSystemTime(&sysTime);    // Fill date portion with today's information\n            sysTime.wSecond = 0;\n            sysTime.wMilliseconds = 0;\n\n            const wchar_t * formatString = L\"%2d:%2d:%2dZ\";\n            auto n = swscanf_s(input.c_str(), formatString,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond);\n\n            if (n == 3)\n            {\n                if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                {\n                    return result;\n                }\n            }\n        }\n    }\n\n    return datetime();\n#else\n    std::string input(dateString);\n\n    struct tm output = tm();\n\n    if (format == RFC_1123)\n    {\n        strptime(input.data(), \"%a, %d %b %Y %H:%M:%S GMT\", &output);\n    }\n    else\n    {\n        // Try to extract the fractional second from the timestamp\n        utility::string_t input;\n        extract_fractional_second(dateString, input, ufrac_second);\n\n        auto result = strptime(input.data(), \"%Y-%m-%dT%H:%M:%SZ\", &output);\n\n        if (result == nullptr)\n        {\n            result = strptime(input.data(), \"%Y%m%dT%H:%M:%SZ\", &output);\n        }\n        if (result == nullptr)\n        {\n            // Fill the date portion with the epoch,\n            // strptime will do the rest\n            memset(&output, 0, sizeof(struct tm));\n            output.tm_year = 70;\n            output.tm_mon = 1;\n            output.tm_mday = 1;\n            result = strptime(input.data(), \"%H:%M:%SZ\", &output);\n        }\n        if (result == nullptr)\n        {\n            result = strptime(input.data(), \"%Y-%m-%d\", &output);\n        }\n        if (result == nullptr)\n        {\n            result = strptime(input.data(), \"%Y%m%d\", &output);\n        }\n        if (result == nullptr)\n        {\n            return datetime();\n        }\n    }\n\n#if (defined(ANDROID) || defined(__ANDROID__))\n    // HACK: The (nonportable?) POSIX function timegm is not available in\n    //       bionic. As a workaround[1][2], we set the C library timezone to\n    //       UTC, call mktime, then set the timezone back. However, the C\n    //       environment is fundamentally a shared global resource and thread-\n    //       unsafe. We can protect our usage here, however any other code might\n    //       manipulate the environment at the same time.\n    //\n    // [1] http://linux.die.net/man/3/timegm\n    // [2] http://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html\n    time_t time;\n\n    static std::mutex env_var_lock;\n    {\n        std::lock_guard<std::mutex> lock(env_var_lock);\n        std::string prev_env;\n        auto prev_env_cstr = getenv(\"TZ\");\n        if (prev_env_cstr != nullptr)\n        {\n            prev_env = prev_env_cstr;\n        }\n        setenv(\"TZ\", \"UTC\", 1);\n\n        time = mktime(&output);\n\n        if (prev_env_cstr)\n        {\n            setenv(\"TZ\", prev_env.c_str(), 1);\n        }\n        else\n        {\n            unsetenv(\"TZ\");\n        }\n        tzset();\n    }\n#else\n    time_t time = timegm(&output);\n#endif\n    struct timeval tv = timeval();\n    tv.tv_sec = time;\n    auto result = timeval_to_datetime(tv);\n\n    // fractional seconds are already in correct format so just add them.\n    result = result + ufrac_second;\n    return result;\n#endif\n}\n\n/// <summary>\n/// Converts a timespan/interval in seconds to xml duration string as specified by\n/// http://www.w3.org/TR/xmlschema-2/#duration\n/// </summary>\nutility::string_t timespan::seconds_to_xml_duration(utility::seconds durationSecs)\n{\n    auto numSecs = durationSecs.count();\n\n    // Find the number of minutes\n    auto numMins =  numSecs / 60;\n    if (numMins > 0)\n    {\n        numSecs = numSecs % 60;\n    }\n\n    // Hours\n    auto numHours = numMins / 60;\n    if (numHours > 0)\n    {\n        numMins = numMins % 60;\n    }\n\n    // Days\n    auto numDays = numHours / 24;\n    if (numDays > 0)\n    {\n        numHours = numHours % 24;\n    }\n\n    // The format is:\n    // PdaysDThoursHminutesMsecondsS\n    utility::ostringstream_t oss;\n    oss.imbue(std::locale::classic());\n\n    oss << _XPLATSTR(\"P\");\n    if (numDays > 0)\n    {\n        oss << numDays << _XPLATSTR(\"D\");\n    }\n\n    oss << _XPLATSTR(\"T\");\n\n    if (numHours > 0)\n    {\n        oss << numHours << _XPLATSTR(\"H\");\n    }\n\n    if (numMins > 0)\n    {\n        oss << numMins << _XPLATSTR(\"M\");\n    }\n\n    if (numSecs > 0)\n    {\n        oss << numSecs << _XPLATSTR(\"S\");\n    }\n\n    return oss.str();\n}\n\nutility::seconds timespan::xml_duration_to_seconds(const utility::string_t &timespanString)\n{\n    // The format is:\n    // PnDTnHnMnS\n    // if n == 0 then the field could be omitted\n    // The final S could be omitted\n\n    int64_t numSecs = 0;\n\n    utility::istringstream_t is(timespanString);\n    is.imbue(std::locale::classic());\n    auto eof = std::char_traits<utility::char_t>::eof();\n\n    std::basic_istream<utility::char_t>::int_type c;\n    c = is.get(); // P\n\n    while (c != eof)\n    {\n        int val = 0;\n        c = is.get();\n\n        while (is_digit((utility::char_t)c))\n        {\n            val = val * 10 + (c - L'0');\n            c = is.get();\n\n            if (c == '.')\n            {\n                // decimal point is not handled\n                do { c = is.get(); } while(is_digit((utility::char_t)c));\n            }\n        }\n\n        if (c == L'D') numSecs += static_cast<int64_t>(val) * 24 * 3600; // days\n        if (c == L'H') numSecs += static_cast<int64_t>(val) * 3600; // Hours\n        if (c == L'M') numSecs += static_cast<int64_t>(val) * 60; // Minutes\n        if (c == L'S' || c == eof)\n        {\n            numSecs += val; // seconds\n            break;\n        }\n    }\n\n    return utility::seconds(numSecs);\n}\n\nconst utility::char_t * nonce_generator::c_allowed_chars = _XPLATSTR(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\");\n\nutility::string_t nonce_generator::generate()\n{\n    std::uniform_int_distribution<> distr(0, static_cast<int>(ustrlen(c_allowed_chars) - 1));\n    utility::string_t result;\n    result.reserve(length());\n    std::generate_n(std::back_inserter(result), length(), [&]() { return c_allowed_chars[distr(m_random)]; } );\n    return result;\n}\n\n\n}\n\n} } }\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Source/Shared/HookedUri/details/basic_types.h",
    "content": "/***\n* Copyright (C) Microsoft. All rights reserved.\n* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Platform-dependent type definitions\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <string>\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include \"HookedUri/details/cpprest_compat.h\"\n#include \"pplx/pplxtasks.h\"\n\n#ifndef _WIN32\n# define __STDC_LIMIT_MACROS\n# include <stdint.h>\n#else\n#include <cstdint>\n#endif\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace utility\n{\n\n#ifdef _WIN32\n#define _UTF16_STRINGS\n#endif\n\n// We should be using a 64-bit size type for most situations that do\n// not involve specifying the size of a memory allocation or buffer.\ntypedef uint64_t size64_t;\n\n#ifdef _UTF16_STRINGS\n//\n// On Windows, all strings are wide\n//\ntypedef wchar_t char_t ;\ntypedef std::wstring string_t;\n#define _XPLATSTR(x) L ## x\ntypedef std::wostringstream ostringstream_t;\ntypedef std::wofstream ofstream_t;\ntypedef std::wostream ostream_t;\ntypedef std::wistream istream_t;\ntypedef std::wifstream ifstream_t;\ntypedef std::wistringstream istringstream_t;\ntypedef std::wstringstream stringstream_t;\n#define ucout std::wcout\n#define ucin std::wcin\n#define ucerr std::wcerr\n#define ustrlen wcslen\n#else\n//\n// On POSIX platforms, all strings are narrow\n//\ntypedef char char_t;\ntypedef std::string string_t;\n#define _XPLATSTR(x) x\ntypedef std::ostringstream ostringstream_t;\ntypedef std::ofstream ofstream_t;\ntypedef std::ostream ostream_t;\ntypedef std::istream istream_t;\ntypedef std::ifstream ifstream_t;\ntypedef std::istringstream istringstream_t;\ntypedef std::stringstream stringstream_t;\n#define ucout std::cout\n#define ucin std::cin\n#define ucerr std::cerr\n#define ustrlen strlen\n#endif // endif _UTF16_STRINGS\n\n#ifndef _TURN_OFF_PLATFORM_STRING\n#define U(x) _XPLATSTR(x)\n#endif // !_TURN_OFF_PLATFORM_STRING\n\n}// namespace utility\n\n} } }\n\ntypedef char utf8char;\ntypedef std::string utf8string;\ntypedef std::stringstream utf8stringstream;\ntypedef std::ostringstream utf8ostringstream;\ntypedef std::ostream utf8ostream;\ntypedef std::istream utf8istream;\ntypedef std::istringstream utf8istringstream;\n\n#ifdef _UTF16_STRINGS\ntypedef wchar_t utf16char;\ntypedef std::wstring utf16string;\ntypedef std::wstringstream utf16stringstream;\ntypedef std::wostringstream utf16ostringstream;\ntypedef std::wostream utf16ostream;\ntypedef std::wistream utf16istream;\ntypedef std::wistringstream utf16istringstream;\n#else\ntypedef char16_t utf16char;\ntypedef std::u16string utf16string;\ntypedef std::basic_stringstream<utf16char> utf16stringstream;\ntypedef std::basic_ostringstream<utf16char> utf16ostringstream;\ntypedef std::basic_ostream<utf16char> utf16ostream;\ntypedef std::basic_istream<utf16char> utf16istream;\ntypedef std::basic_istringstream<utf16char> utf16istringstream;\n#endif\n\n\n#if defined(_WIN32)\n// Include on everything except Windows Desktop ARM, unless explicitly excluded.\n#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)\n#if defined(WINAPI_FAMILY)\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM)\n#define CPPREST_EXCLUDE_WEBSOCKETS\n#endif\n#else\n#if defined(_M_ARM)\n#define CPPREST_EXCLUDE_WEBSOCKETS\n#endif\n#endif\n#endif\n#endif\n"
  },
  {
    "path": "Source/Shared/HookedUri/details/cpprest_compat.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Standard macros and definitions.\n* This header has minimal dependency on windows headers and is safe for use in the public API\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#if defined(_WIN32) // Settings specific to Windows\n\n#if _MSC_VER >= 1900\n#define CPPREST_NOEXCEPT noexcept\n#else\n#define CPPREST_NOEXCEPT\n#endif\n\n#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)\n\n#include <sal.h>\n\n#else // End settings specific to Windows\n\n// Settings common to all but Windows\n\n#define __declspec(x) __attribute__ ((x))\n#define dllimport\n#define novtable /* no novtable equivalent */\n#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false)\n#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x\n#define CPPREST_NOEXCEPT noexcept\n\n#include <assert.h>\n#define _ASSERTE(x) assert(x)\n\n// No SAL on non Windows platforms\n#include \"HookedUri/details/nosal.h\"\n\n#if not defined __cdecl\n#if defined cdecl\n#define __cdecl __attribute__ ((cdecl))\n#else\n#define __cdecl\n#endif\n\n#if defined(__ANDROID__)\n// This is needed to disable the use of __thread inside the boost library.\n// Android does not support thread local storage -- if boost is included\n// without this macro defined, it will create references to __tls_get_addr\n// which (while able to link) will not be available at runtime and prevent\n// the .so from loading.\n#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION\n#endif\n\n#ifdef __clang__\n#include <cstdio>\n#endif\n\n#endif // defined(__APPLE__)\n\n#endif\n\n\n#ifdef _NO_ASYNCRTIMP\n#define _ASYNCRTIMP\n#else\n#ifdef _ASYNCRT_EXPORT\n#define _ASYNCRTIMP __declspec(dllexport)\n#else\n#define _ASYNCRTIMP __declspec(dllimport)\n#endif\n#endif\n\n#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS\n#define CASABLANCA_DEPRECATED(x)\n#else\n#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))\n#endif\n"
  },
  {
    "path": "Source/Shared/HookedUri/details/nosal.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n***/\n\n#pragma once\n// selected MS SAL annotations\n\n#ifdef _In_\n#undef _In_\n#endif\n#define _In_\n\n#ifdef _Inout_\n#undef _Inout_\n#endif\n#define _Inout_\n\n#ifdef _Out_\n#undef _Out_\n#endif\n#define _Out_\n\n#ifdef _In_z_\n#undef _In_z_\n#endif\n#define _In_z_\n\n#ifdef _Out_z_\n#undef _Out_z_\n#endif\n#define _Out_z_\n\n#ifdef _Inout_z_\n#undef _Inout_z_\n#endif\n#define _Inout_z_\n\n#ifdef _In_opt_\n#undef _In_opt_\n#endif\n#define _In_opt_\n\n#ifdef _Out_opt_\n#undef _Out_opt_\n#endif\n#define _Out_opt_\n\n#ifdef _Inout_opt_\n#undef _Inout_opt_\n#endif\n#define _Inout_opt_\n\n#ifdef _Out_writes_\n#undef _Out_writes_\n#endif\n#define _Out_writes_(x)\n\n#ifdef _Out_writes_opt_\n#undef _Out_writes_opt_\n#endif\n#define _Out_writes_opt_(x)\n\n#ifdef _In_reads_\n#undef _In_reads_\n#endif\n#define _In_reads_(x)\n\n#ifdef _Inout_updates_bytes_\n#undef _Inout_updates_bytes_\n#endif\n#define _Inout_updates_bytes_(x)"
  },
  {
    "path": "Source/Shared/HookedUri/details/uri.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Protocol independent support for URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\nusing namespace xbox::services::cppresturi::utility::conversions;\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#pragma warning( disable : 26812 )  // enum instead of enum class\n#endif\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace web { namespace details\n{\nxsapi_internal_string uri_components::join()\n{\n    // canonicalize components first\n\n    // convert scheme to lowercase\n    std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [](char c) {\n        return (char)tolower(c);\n    });\n\n    // convert host to lowercase\n    std::transform(m_host.begin(), m_host.end(), m_host.begin(), [](char c) {\n        return (char)tolower(c);\n    });\n\n    // canonicalize the path to have a leading slash if it's a full uri\n    if (!m_host.empty() && m_path.empty())\n    {\n        m_path = \"/\";\n    }\n    else if (!m_host.empty() && m_path[0] != '/')\n    {\n        m_path.insert(m_path.begin(), 1, '/');\n    }\n\n    xsapi_internal_string ret;\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800))\n    if (!m_scheme.empty())\n    {\n        ret.append(m_scheme).append({ ':' });\n    }\n\n    if (!m_host.empty())\n    {\n        ret.append(\"//\");\n\n        if (!m_user_info.empty())\n        {\n            ret.append(m_user_info).append({ '@' });\n        }\n\n        ret.append(m_host);\n\n        if (m_port > 0)\n        {\n            char buf[16] = { 0 };\n            sprintf_s(buf, sizeof(buf), \":%d\", m_port);\n            ret.append(buf);\n        }\n    }\n\n    if (!m_path.empty())\n    {\n        // only add the leading slash when the host is present\n        if (!m_host.empty() && m_path.front() != '/')\n        {\n            ret.append({ '/' });\n        }\n\n        ret.append(m_path);\n    }\n\n    if (!m_query.empty())\n    {\n        ret.append({ '?' }).append(m_query);\n    }\n\n    if (!m_fragment.empty())\n    {\n        ret.append({ '#' }).append(m_fragment);\n    }\n\n    return ret;\n#else\n    xsapi_internal_ostringstream_t os;\n    os.imbue(std::locale::classic());\n\n    if (!m_scheme.empty())\n    {\n        os << m_scheme << ':';\n    }\n\n    if (!m_host.empty())\n    {\n        os << \"//\";\n\n        if (!m_user_info.empty())\n        {\n            os << m_user_info << '@';\n        }\n\n        os << m_host;\n\n        if (m_port > 0)\n        {\n            os << ':' << m_port;\n        }\n    }\n\n    if (!m_path.empty())\n    {\n        // only add the leading slash when the host is present\n        if (!m_host.empty() && m_path.front() != '/')\n        {\n            os << '/';\n        }\n        os << m_path;\n    }\n\n    if (!m_query.empty())\n    {\n        os << '?' << m_query;\n    }\n\n    if (!m_fragment.empty())\n    {\n        os << '#' << m_fragment;\n    }\n\n    return os.str();\n#endif\n}\n}\n\nusing namespace xbox::services::cppresturi::web::details;\n\nuri::uri(const details::uri_components &components) : m_components(components)\n{\n    m_uri = m_components.join();\n    if (!details::uri_parser::validate(m_uri))\n    {\n        throw uri_exception(\"\"); // provided uri is invalid : \" + utility::conversions::to_utf8string(m_uri));\n    }\n}\n\nuri::uri(const xsapi_internal_string &uri_string)\n{\n    if (!details::uri_parser::parse(uri_string, m_components))\n    {\n        throw uri_exception(\"\"); // provided uri is invalid : \" + utility::conversions::to_utf8string(uri_string));\n    }\n    m_uri = m_components.join();\n}\n\nuri::uri(const char *uri_string): m_uri(uri_string)\n{\n    if (!details::uri_parser::parse(uri_string, m_components))\n    {\n#if 0 // this returns a non-mem hooked string which can't be changed so commenting it out since its not really needed\n        throw uri_exception(\"provided uri is invalid: \" + utility::conversions::to_utf8string_internal(uri_string));\n#else\n        throw uri_exception(std::string());\n#endif\n    }\n    m_uri = m_components.join();\n}\n\nxsapi_internal_string uri::encode_impl(const xsapi_internal_string &utf8raw, const std::function<bool(int)>& should_encode)\n{\n    const char * const hex = \"0123456789ABCDEF\";\n    xsapi_internal_string encoded;\n    for (auto iter = utf8raw.begin(); iter != utf8raw.end(); ++iter)\n    {\n        // for utf8 encoded string, char ASCII can be greater than 127.\n        int ch = static_cast<unsigned char>(*iter);\n        // ch should be same under both utf8 and utf16.\n        if(should_encode(ch))\n        {\n            encoded.push_back('%');\n            encoded.push_back(hex[(ch >> 4) & 0xF]);\n            encoded.push_back(hex[ch & 0xF]);\n        }\n        else\n        {\n            // ASCII don't need to be encoded, which should be same on both utf8 and utf16.\n            encoded.push_back((char)ch);\n        }\n    }\n    return encoded;\n}\n\n/// <summary>\n/// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their\n/// hexadecimal representation.\n/// </summary>\nxsapi_internal_string uri::encode_data_string(const xsapi_internal_string &raw)\n{\n    return uri::encode_impl(raw, [](int ch) -> bool\n    {\n        return !uri_parser::is_unreserved(ch);\n    });\n}\n\nxsapi_internal_string uri::encode_uri(const xsapi_internal_string &raw, uri::components::component component)\n{\n    // Note: we also encode the '+' character because some non-standard implementations\n    // encode the space character as a '+' instead of %20. To better interoperate we encode\n    // '+' to avoid any confusion and be mistaken as a space.\n    switch(component)\n    {\n    case components::user_info:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_user_info_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::host:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            // No encoding of ASCII characters in host name (RFC 3986 3.2.2)\n            return ch > 127;\n        });\n    case components::path:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_path_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::query:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_query_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::fragment:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_fragment_character(ch)\n                || ch == '%' || ch == '+';\n        });\n    case components::full_uri:\n    default:\n        return uri::encode_impl(raw, [](int ch) -> bool\n        {\n            return !uri_parser::is_unreserved(ch) && !uri_parser::is_reserved(ch);\n        });\n    };\n}\n\n/// <summary>\n/// Helper function to convert a hex character digit to a decimal character value.\n/// Throws an exception if not a valid hex digit.\n/// </summary>\nstatic int hex_char_digit_to_decimal_char(int hex)\n{\n    int decimal;\n    if(hex >= '0' && hex <= '9')\n    {\n        decimal = hex - '0';\n    }\n    else if(hex >= 'A' && hex <= 'F')\n    {\n        decimal = 10 + (hex - 'A');\n    }\n    else if(hex >= 'a' && hex <= 'f')\n    {\n        decimal = 10 + (hex - 'a');\n    }\n    else\n    {\n        throw uri_exception(\"Invalid hexadecimal digit\");\n    }\n    return decimal;\n}\n\nxsapi_internal_string uri::decode(const xsapi_internal_string &encoded)\n{\n    xsapi_internal_string utf8raw;\n    for(auto iter = encoded.begin(); iter != encoded.end(); ++iter)\n    {\n        if(*iter == '%')\n        {\n            if(++iter == encoded.end())\n            {\n                throw uri_exception(\"Invalid URI string, two hexadecimal digits must follow '%'\");\n            }\n            int decimal_value = hex_char_digit_to_decimal_char(static_cast<int>(*iter)) << 4;\n            if(++iter == encoded.end())\n            {\n                throw uri_exception(\"Invalid URI string, two hexadecimal digits must follow '%'\");\n            }\n            decimal_value += hex_char_digit_to_decimal_char(static_cast<int>(*iter));\n\n            utf8raw.push_back(static_cast<char>(decimal_value));\n        }\n        else\n        {\n            // encoded string has to be ASCII.\n            utf8raw.push_back(reinterpret_cast<const char &>(*iter));\n        }\n    }\n    return utf8raw;\n}\n\nstd::vector<xsapi_internal_string> uri::split_path(const xsapi_internal_string &path)\n{\n    std::vector<xsapi_internal_string> results;\n    xsapi_internal_istringstream iss(path);\n    iss.imbue(std::locale::classic());\n    xsapi_internal_string s;\n\n    while (std::getline(iss, s, '/'))\n    {\n        if (!s.empty())\n        {\n            results.push_back(s);\n        }\n    }\n\n    return results;\n}\n\nstd::map<xsapi_internal_string, xsapi_internal_string> uri::split_query(const xsapi_internal_string &query)\n{\n    std::map<xsapi_internal_string, xsapi_internal_string> results;\n\n    // Split into key value pairs separated by '&'.\n    size_t prev_amp_index = 0;\n    while(prev_amp_index != xsapi_internal_string::npos)\n    {\n        size_t amp_index = query.find_first_of('&', prev_amp_index);\n        if (amp_index == xsapi_internal_string::npos)\n            amp_index = query.find_first_of(';', prev_amp_index);\n\n        xsapi_internal_string key_value_pair = query.substr(\n            prev_amp_index,\n            amp_index == xsapi_internal_string::npos ? query.size() - prev_amp_index : amp_index - prev_amp_index);\n        prev_amp_index = amp_index == xsapi_internal_string::npos ? xsapi_internal_string::npos : amp_index + 1;\n\n        size_t equals_index = key_value_pair.find_first_of('=');\n        if(equals_index == xsapi_internal_string::npos)\n        {\n            continue;\n        }\n        else if (equals_index == 0)\n        {\n            xsapi_internal_string value(key_value_pair.begin() + equals_index + 1, key_value_pair.end());\n            results[\"\"] = value;\n        }\n        else\n        {\n            xsapi_internal_string key(key_value_pair.begin(), key_value_pair.begin() + equals_index);\n            xsapi_internal_string value(key_value_pair.begin() + equals_index + 1, key_value_pair.end());\n            results[key] = value;\n        }\n    }\n\n    return results;\n}\n\nbool uri::validate(const xsapi_internal_string &uri_string)\n{\n    return uri_parser::validate(uri_string);\n}\n\nuri uri::authority() const\n{\n    return uri_builder().set_scheme(this->scheme()).set_host(this->host()).set_port(this->port()).set_user_info(this->user_info()).to_uri();\n}\n\nuri uri::resource() const\n{\n    return uri_builder().set_path(this->path()).set_query(this->query()).set_fragment(this->fragment()).to_uri();\n}\n\nbool uri::operator == (const uri &other) const\n{\n    // Each individual URI component must be decoded before performing comparison.\n    // TFS # 375865\n\n    if (this->is_empty() && other.is_empty())\n    {\n        return true;\n    }\n    else if (this->is_empty() || other.is_empty())\n    {\n        return false;\n    }\n    else if (this->scheme() != other.scheme())\n    {\n        // scheme is canonicalized to lowercase\n        return false;\n    }\n    else if(uri::decode(this->user_info()) != uri::decode(other.user_info()))\n    {\n        return false;\n    }\n    else if (uri::decode(this->host()) != uri::decode(other.host()))\n    {\n        // host is canonicalized to lowercase\n        return false;\n    }\n    else if (this->port() != other.port())\n    {\n        return false;\n    }\n    else if (uri::decode(this->path()) != uri::decode(other.path()))\n    {\n        return false;\n    }\n    else if (uri::decode(this->query()) != uri::decode(other.query()))\n    {\n        return false;\n    }\n    else if (uri::decode(this->fragment()) != uri::decode(other.fragment()))\n    {\n        return false;\n    }\n\n    return true;\n}\n\n}\n\n} } }\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Source/Shared/HookedUri/details/uri_builder.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Builder for constructing URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace web\n{\n\nnamespace http\n{\n    // URI class has been moved from web::http namespace to web namespace.\n    // The below using declarations ensure we don't break existing code.\n    // Please use the web::uri class going forward.\n    using web::uri;\n    using web::uri_builder;\n}\n\nuri_builder &uri_builder::append_path(const xsapi_internal_string &path, bool is_encode)\n{\n    if(path.empty() || path == \"/\")\n    {\n        return *this;\n    }\n\n    auto encoded_path = is_encode ? uri::encode_uri(path, uri::components::path) : path;\n    auto thisPath = this->path();\n    if(thisPath.empty() || thisPath == \"/\")\n    {\n        if(encoded_path.front() != '/')\n        {\n            set_path(\"/\" + encoded_path);\n        }\n        else\n        {\n            set_path(encoded_path);\n        }\n    }\n    else if(thisPath.back() == '/' && encoded_path.front() == '/')\n    {\n        thisPath.pop_back();\n        set_path(thisPath + encoded_path);\n    }\n    else if(thisPath.back() != '/' && encoded_path.front() != '/')\n    {\n        set_path(thisPath + \"/\" + encoded_path);\n    }\n    else\n    {\n        // Only one slash.\n        set_path(thisPath + encoded_path);\n    }\n    return *this;\n}\n\nuri_builder &uri_builder::append_query(const xsapi_internal_string &query, bool is_encode)\n{\n    if(query.empty())\n    {\n        return *this;\n    }\n\n    auto encoded_query = is_encode ? uri::encode_uri(query, uri::components::query) : query;\n    auto thisQuery = this->query();\n    if (thisQuery.empty())\n    {\n        this->set_query(encoded_query);\n    }\n    else if(thisQuery.back() == '&' && encoded_query.front() == '&')\n    {\n        thisQuery.pop_back();\n        this->set_query(thisQuery + encoded_query);\n    }\n    else if(thisQuery.back() != '&' && encoded_query.front() != '&')\n    {\n        this->set_query(thisQuery + \"&\" + encoded_query);\n    }\n    else\n    {\n        // Only one ampersand.\n        this->set_query(thisQuery + encoded_query);\n    }\n    return *this;\n}\n\nuri_builder &uri_builder::append(const http::uri &relative_uri)\n{\n    append_path(relative_uri.path());\n    append_query(relative_uri.query());\n    this->set_fragment(this->fragment() + relative_uri.fragment());\n    return *this;\n}\n\nxsapi_internal_string uri_builder::to_string()\n{\n    return to_uri().to_string();\n}\n\nuri uri_builder::to_uri()\n{\n    return uri(m_uri);\n}\n\nbool uri_builder::is_valid()\n{\n    return uri::validate(m_uri.join());\n}\n\n} // namespace web\n\n} } }\n"
  },
  {
    "path": "Source/Shared/HookedUri/details/uri_parser.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* URI parsing implementation\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <string>\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace web { namespace details\n{\n    namespace uri_parser\n    {\n\n        /// <summary>\n        /// Parses the uri, attempting to determine its validity.\n        ///\n        /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query')\n        /// </summary>\n        bool validate(const xsapi_internal_string &encoded_string);\n\n        /// <summary>\n        /// Parses the uri, setting each provided string to the value of that component. Components\n        /// that are not part of the provided text are set to the empty string. Component strings\n        /// DO NOT contain their beginning or ending delimiters.\n        ///\n        /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query')\n        /// </summary>\n        bool parse(const xsapi_internal_string &encoded_string, uri_components &components);\n\n        /// <summary>\n        /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include:\n        /// - A-Z\n        /// - a-z\n        /// - 0-9\n        /// - '-' (hyphen)\n        /// - '.' (period)\n        /// - '_' (underscore)\n        /// - '~' (tilde)\n        /// </summary>\n        inline bool is_unreserved(int c)\n        {\n            return xbox::services::cppresturi::utility::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~';\n        }\n\n        /// <summary>\n        /// General delimiters serve as the delimiters between different uri components.\n        /// General delimiters include:\n        /// - All of these :/?#[]@\n        /// </summary>\n        inline bool is_gen_delim(int c)\n        {\n            return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@';\n        }\n\n        /// <summary>\n        /// Subdelimiters are those characters that may have a defined meaning within component\n        /// of a uri for a particular scheme. They do not serve as delimiters in any case between\n        /// uri segments. sub_delimiters include:\n        /// - All of these !$&amp;'()*+,;=\n        /// </summary>\n        inline bool is_sub_delim(int c)\n        {\n            switch (c)\n            {\n            case '!':\n            case '$':\n            case '&':\n            case '\\'':\n            case '(':\n            case ')':\n            case '*':\n            case '+':\n            case ',':\n            case ';':\n            case '=':\n                return true;\n            default:\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Reserved characters includes the general delimiters and sub delimiters. Some characters\n        /// are neither reserved nor unreserved, and must be percent-encoded.\n        /// </summary>\n        inline bool is_reserved(int c)\n        {\n            return is_gen_delim(c) || is_sub_delim(c);\n        }\n\n        /// <summary>\n        /// Legal characters in the scheme portion include:\n        /// - Any alphanumeric character\n        /// - '+' (plus)\n        /// - '-' (hyphen)\n        /// - '.' (period)\n        ///\n        /// Note that the scheme must BEGIN with an alpha character.\n        /// </summary>\n        inline bool is_scheme_character(int c)\n        {\n            return xbox::services::cppresturi::utility::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.';\n        }\n\n        /// <summary>\n        /// Legal characters in the user information portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        /// </summary>\n        inline bool is_user_info_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':';\n        }\n\n        /// <summary>\n        /// Legal characters in the host portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        /// - '[' (open bracket)\n        /// - ']' (close bracket)\n        /// </summary>\n        inline bool is_host_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':' || c == '[' || c == ']';\n        }\n\n        /// <summary>\n        /// Legal characters in the authority portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        ///\n        /// Note that we don't currently support:\n        /// - IPv6 addresses (requires '[]')\n        /// </summary>\n        inline bool is_authority_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':';\n        }\n\n        /// <summary>\n        /// Legal characters in the path portion include:\n        /// - Any unreserved character\n        /// - The percent character ('%'), and thus any percent-endcoded octet\n        /// - The sub-delimiters\n        /// - ':' (colon)\n        /// - '@' (ampersand)\n        /// </summary>\n        inline bool is_path_character(int c)\n        {\n            return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@';\n        }\n\n        /// <summary>\n        /// Legal characters in the query portion include:\n        /// - Any path character\n        /// - '?' (question mark)\n        /// </summary>\n        inline bool is_query_character(int c)\n        {\n            return is_path_character(c) || c == '?';\n        }\n\n        /// <summary>\n        /// Legal characters in the fragment portion include:\n        /// - Any path character\n        /// - '?' (question mark)\n        /// </summary>\n        inline bool is_fragment_character(int c)\n        {\n            // this is intentional, they have the same set of legal characters\n            return is_query_character(c);\n        }\n\n        /// <summary>\n        /// Parses the uri, setting the given pointers to locations inside the given buffer.\n        /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri\n        /// </summary>\n        bool inner_parse(\n            const char *encoded,\n            const char **scheme_begin, const char **scheme_end,\n            const char **uinfo_begin, const char **uinfo_end,\n            const char **host_begin, const char **host_end,\n            _Out_ int *port,\n            const char **path_begin, const char **path_end,\n            const char **query_begin, const char **query_end,\n            const char **fragment_begin, const char **fragment_end);\n    }\n}}\n\n} } }"
  },
  {
    "path": "Source/Shared/HookedUri/details/uri_parser.hpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* URI parsing implementation\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <locale>\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace web { namespace details { namespace uri_parser\n{\n\nbool validate(const xsapi_internal_string& encoded_string)\n{\n    const char* scheme_begin = nullptr;\n    const char* scheme_end = nullptr;\n    const char* uinfo_begin = nullptr;\n    const char* uinfo_end = nullptr;\n    const char* host_begin = nullptr;\n    const char* host_end = nullptr;\n    int port_ptr = 0;\n    const char* path_begin = nullptr;\n    const char* path_end = nullptr;\n    const char* query_begin = nullptr;\n    const char* query_end = nullptr;\n    const char* fragment_begin = nullptr;\n    const char* fragment_end = nullptr;\n\n    // perform a parse, but don't copy out the data\n    return inner_parse(\n        encoded_string.c_str(),\n        &scheme_begin,\n        &scheme_end,\n        &uinfo_begin,\n        &uinfo_end,\n        &host_begin,\n        &host_end,\n        &port_ptr,\n        &path_begin,\n        &path_end,\n        &query_begin,\n        &query_end,\n        &fragment_begin,\n        &fragment_end);\n}\n\nbool parse(const xsapi_internal_string &encoded_string, uri_components &components)\n{\n    const char* scheme_begin = nullptr;\n    const char* scheme_end = nullptr;\n    const char* host_begin = nullptr;\n    const char* host_end = nullptr;\n    const char* uinfo_begin = nullptr;\n    const char* uinfo_end = nullptr;\n    int port_ptr = 0;\n    const char* path_begin = nullptr;\n    const char* path_end = nullptr;\n    const char* query_begin = nullptr;\n    const char* query_end = nullptr;\n    const char* fragment_begin = nullptr;\n    const char* fragment_end = nullptr;\n\n    if (inner_parse(\n        encoded_string.c_str(),\n        &scheme_begin,\n        &scheme_end,\n        &uinfo_begin,\n        &uinfo_end,\n        &host_begin,\n        &host_end,\n        &port_ptr,\n        &path_begin,\n        &path_end,\n        &query_begin,\n        &query_end,\n        &fragment_begin,\n        &fragment_end))\n    {\n        if (scheme_begin)\n        {\n            components.m_scheme.assign(scheme_begin, scheme_end);\n\n            // convert scheme to lowercase\n            std::transform(components.m_scheme.begin(), components.m_scheme.end(), components.m_scheme.begin(), [](char c) {\n                return (char)tolower(c);\n            });\n        }\n        else\n        {\n            components.m_scheme.clear();\n        }\n\n        if (uinfo_begin)\n        {\n            components.m_user_info.assign(uinfo_begin, uinfo_end);\n        }\n\n        if (host_begin)\n        {\n            components.m_host.assign(host_begin, host_end);\n\n            // convert host to lowercase\n            std::transform(components.m_host.begin(), components.m_host.end(), components.m_host.begin(), [](char c) {\n                return (char)tolower(c);\n            });\n        }\n        else\n        {\n            components.m_host.clear();\n        }\n\n        if (port_ptr)\n        {\n            components.m_port = port_ptr;\n        }\n        else\n        {\n            components.m_port = 0;\n        }\n\n        if (path_begin)\n        {\n            components.m_path.assign(path_begin, path_end);\n        }\n        else\n        {\n            // default path to begin with a slash for easy comparison\n            components.m_path = \"/\";\n        }\n\n        if (query_begin)\n        {\n            components.m_query.assign(query_begin, query_end);\n        }\n        else\n        {\n            components.m_query.clear();\n        }\n\n        if (fragment_begin)\n        {\n            components.m_fragment.assign(fragment_begin, fragment_end);\n        }\n        else\n        {\n            components.m_fragment.clear();\n        }\n\n        return true;\n    }\n    else\n    {\n        return false;\n    }\n}\n\nbool inner_parse(\n            const char* encoded,\n            const char** scheme_begin, const char** scheme_end,\n            const char** uinfo_begin, const char** uinfo_end,\n            const char** host_begin, const char** host_end,\n            _Out_ int * port,\n            const char** path_begin, const char** path_end,\n            const char** query_begin, const char** query_end,\n            const char** fragment_begin, const char** fragment_end)\n{\n    *scheme_begin = nullptr;\n    *scheme_end = nullptr;\n    *uinfo_begin = nullptr;\n    *uinfo_end = nullptr;\n    *host_begin = nullptr;\n    *host_end = nullptr;\n    *port = 0;\n    *path_begin = nullptr;\n    *path_end = nullptr;\n    *query_begin = nullptr;\n    *query_end = nullptr;\n    *fragment_begin = nullptr;\n    *fragment_end = nullptr;\n\n    const char*p = encoded;\n\n    // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference\n    // Absolute: 'http://host.com'\n    // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2'\n    // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash\n\n    bool is_relative_reference = true;\n    const char*p2 = p;\n    for (;*p2 != '/' && *p2 != '\\0'; p2++)\n    {\n        if (*p2 == ':')\n        {\n            // found a colon, the first portion is a scheme\n            is_relative_reference = false;\n            break;\n        }\n    }\n\n    if (!is_relative_reference)\n    {\n        // the first character of a scheme must be a letter\n        if (!isalpha(*p))\n        {\n            return false;\n        }\n\n        // start parsing the scheme, it's always delimited by a colon (must be present)\n        *scheme_begin = p++;\n        for (;*p != ':'; p++)\n        {\n            if (!is_scheme_character(*p))\n            {\n                return false;\n            }\n        }\n        *scheme_end = p;\n\n        // skip over the colon\n        p++;\n    }\n\n    // if we see two slashes next, then we're going to parse the authority portion\n    // later on we'll break up the authority into the port and host\n    const char*authority_begin = nullptr;\n    const char*authority_end = nullptr;\n    if (*p == '/' && p[1] == '/')\n    {\n        // skip over the slashes\n        p += 2;\n        authority_begin = p;\n\n        // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment)\n        // or by EOS. The authority could be empty ('file:///C:\\file_name.txt')\n        for (;*p != '/' && *p != '?' && *p != '#' && *p != '\\0'; p++)\n        {\n            // We're NOT currently supporting IPv6, IPvFuture or username/password in authority\n            if (!is_authority_character(*p))\n            {\n                return false;\n            }\n        }\n        authority_end = p;\n\n        // now lets see if we have a port specified -- by working back from the end\n        if (authority_begin != authority_end)\n        {\n            // the port is made up of all digits\n            const char*port_begin = authority_end - 1;\n            for (;isdigit(*port_begin) && port_begin != authority_begin; port_begin--)\n            { }\n\n            if (*port_begin == ':')\n            {\n                // has a port\n                *host_begin = authority_begin;\n                *host_end = port_begin;\n\n                //skip the colon\n                port_begin++;\n\n                *port = utility::conversions::scan_string<int>(utility::string_t(port_begin, authority_end), std::locale::classic());\n            }\n            else\n            {\n                // no port\n                *host_begin = authority_begin;\n                *host_end = authority_end;\n            }\n\n            // look for a user_info component\n            const char*u_end = *host_begin;\n            for (;is_user_info_character(*u_end) && u_end != *host_end; u_end++)\n            { }\n\n            if (*u_end == '@')\n            {\n                *host_begin = u_end+1;\n                *uinfo_begin = authority_begin;\n                *uinfo_end = u_end;\n            }\n            else\n            {\n                uinfo_end = uinfo_begin = nullptr;\n            }\n        }\n    }\n\n    // if we see a path character or a slash, then the\n    // if we see a slash, or any other legal path character, parse the path next\n    if (*p == '/' || is_path_character(*p))\n    {\n        *path_begin = p;\n\n        // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS\n        for (;*p != '?' && *p != '#' && *p != '\\0'; p++)\n        {\n            if (!is_path_character(*p))\n            {\n                return false;\n            }\n        }\n        *path_end = p;\n    }\n\n    // if we see a ?, then the query is next\n    if (*p == '?')\n    {\n        // skip over the question mark\n        p++;\n        *query_begin = p;\n\n        // the query is delimited by a '#' (fragment) or EOS\n        for (;*p != '#' && *p != '\\0'; p++)\n        {\n            if (!is_query_character(*p))\n            {\n                return false;\n            }\n        }\n        *query_end = p;\n    }\n\n    // if we see a #, then the fragment is next\n    if (*p == '#')\n    {\n        // skip over the hash mark\n        p++;\n        *fragment_begin = p;\n\n        // the fragment is delimited by EOS\n        for (;*p != '\\0'; p++)\n        {\n            if (!is_fragment_character(*p))\n            {\n                return false;\n            }\n        }\n        *fragment_end = p;\n    }\n\n    return true;\n}\n\n}}}\n\n} } }"
  },
  {
    "path": "Source/Shared/HookedUri/uri.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Protocol independent support for URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n#pragma once\n\n#ifndef _CASA_URI_H\n#define _CASA_URI_H\n\n#include \"HookedUri/base_uri.h\"\n#include \"HookedUri/uri_builder.h\"\n\n#endif\n\n\n"
  },
  {
    "path": "Source/Shared/HookedUri/uri_builder.h",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Builder style class for creating URIs.\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#pragma once\n\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include \"HookedUri/base_uri.h\"\n#include \"HookedUri/details/uri_parser.h\"\n\nnamespace xbox { namespace services { namespace cppresturi {\n\nnamespace web\n{\n    /// <summary>\n    /// Builder for constructing URIs incrementally.\n    /// </summary>\n    class uri_builder\n    {\n    public:\n\n        /// <summary>\n        /// Creates a builder with an initially empty URI.\n        /// </summary>\n        uri_builder() {}\n\n        /// <summary>\n        /// Creates a builder with a existing URI object.\n        /// </summary>\n        /// <param name=\"uri_str\">Encoded string containing the URI.</param>\n        uri_builder(const uri &uri_str): m_uri(uri_str.m_components) {}\n\n        /// <summary>\n        /// Get the scheme component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI scheme as a string.</returns>\n        const xsapi_internal_string &scheme() const { return m_uri.m_scheme; }\n\n        /// <summary>\n        /// Get the user information component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI user information as a string.</returns>\n        const xsapi_internal_string &user_info() const { return m_uri.m_user_info; }\n\n        /// <summary>\n        /// Get the host component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI host as a string.</returns>\n        const xsapi_internal_string &host() const { return m_uri.m_host; }\n\n        /// <summary>\n        /// Get the port component of the URI. Returns -1 if no port is specified.\n        /// </summary>\n        /// <returns>The URI port as an integer.</returns>\n        int port() const { return m_uri.m_port; }\n\n        /// <summary>\n        /// Get the path component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI path as a string.</returns>\n        const xsapi_internal_string &path() const { return m_uri.m_path; }\n\n        /// <summary>\n        /// Get the query component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI query as a string.</returns>\n        const xsapi_internal_string &query() const { return m_uri.m_query; }\n\n        /// <summary>\n        /// Get the fragment component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI fragment as a string.</returns>\n        const xsapi_internal_string &fragment() const { return m_uri.m_fragment; }\n\n        /// <summary>\n        /// Set the scheme of the URI.\n        /// </summary>\n        /// <param name=\"scheme\">Uri scheme.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_scheme(const xsapi_internal_string &scheme)\n        {\n            m_uri.m_scheme = scheme;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the user info component of the URI.\n        /// </summary>\n        /// <param name=\"user_info\">User info as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_user_info(const xsapi_internal_string &user_info, bool do_encoding = false)\n        {\n            m_uri.m_user_info = do_encoding ? uri::encode_uri(user_info, uri::components::user_info) : user_info;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the host component of the URI.\n        /// </summary>\n        /// <param name=\"host\">Host as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_host(const xsapi_internal_string &host, bool do_encoding = false)\n        {\n            m_uri.m_host = do_encoding ? uri::encode_uri(host, uri::components::host) : host;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the port component of the URI.\n        /// </summary>\n        /// <param name=\"port\">Port as an integer.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_port(int port)\n        {\n            m_uri.m_port = port;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the port component of the URI.\n        /// </summary>\n        /// <param name=\"port\">Port as a string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        /// <remarks>When string can't be converted to an integer the port is left unchanged.</remarks>\n        uri_builder & set_port(const xsapi_internal_string &port)\n        {\n            xsapi_internal_istringstream portStream(port);\n            int port_tmp;\n            portStream >> port_tmp;\n            if(portStream.fail() || portStream.bad())\n            {\n                throw std::invalid_argument(\"invalid port argument, must be non empty string containing integer value\");\n            }\n            m_uri.m_port = port_tmp;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the path component of the URI.\n        /// </summary>\n        /// <param name=\"path\">Path as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_path(const xsapi_internal_string &path, bool do_encoding = false)\n        {\n            m_uri.m_path = do_encoding ? uri::encode_uri(path, uri::components::path) : path;\n            return *this;\n        }\n\n\n        /// <summary>\n        /// Set the query component of the URI.\n        /// </summary>\n        /// <param name=\"query\">Query as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_query(const xsapi_internal_string &query, bool do_encoding = false)\n        {\n            m_uri.m_query = do_encoding ? uri::encode_uri(query, uri::components::query) : query;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the fragment component of the URI.\n        /// </summary>\n        /// <param name=\"fragment\">Fragment as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder & set_fragment(const xsapi_internal_string &fragment, bool do_encoding = false)\n        {\n            m_uri.m_fragment = do_encoding ? uri::encode_uri(fragment, uri::components::fragment) : fragment;\n            return *this;\n        }\n\n        /// <summary>\n        /// Clears all components of the underlying URI in this uri_builder.\n        /// </summary>\n        void clear()\n        {\n            m_uri = details::uri_components();\n        }\n\n        /// <summary>\n        /// Appends another path to the path of this uri_builder.\n        /// </summary>\n        /// <param name=\"path\">Path to append as a already encoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        _ASYNCRTIMP uri_builder &append_path(const xsapi_internal_string &path, bool do_encoding = false);\n\n        /// <summary>\n        /// Appends another query to the query of this uri_builder.\n        /// </summary>\n        /// <param name=\"query\">Query to append as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        _ASYNCRTIMP uri_builder &append_query(const xsapi_internal_string &query, bool do_encoding = false);\n\n        /// <summary>\n        /// Appends an relative uri (Path, Query and fragment) at the end of the current uri.\n        /// </summary>\n        /// <param name=\"relative_uri\">The relative uri to append.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        _ASYNCRTIMP uri_builder &append(const uri &relative_uri);\n\n        /// <summary>\n        /// Appends another query to the query of this uri_builder, encoding it first. This overload is useful when building a query segment of\n        /// the form \"element=10\", where the right hand side of the query is stored as a type other than a string, for instance, an integral type.\n        /// </summary>\n        /// <param name=\"name\">The name portion of the query string</param>\n        /// <param name=\"value\">The value portion of the query string</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        template<typename T>\n        uri_builder &append_query(const xsapi_internal_string &name, const T &value, bool do_encoding = true)\n        {\n            auto encodedName = name;\n            auto encodedValue = ::utility::conversions::print_string(value, std::locale::classic());\n\n            if (do_encoding)\n            {\n                auto encodingCheck = [](int ch)\n                {\n                    switch (ch)\n                    {\n                        // Encode '&', ';', and '=' since they are used\n                        // as delimiters in query component.\n                    case '&':\n                    case ';':\n                    case '=':\n                    case '%':\n                    case '+':\n                        return true;\n                    default:\n                        return !::web::details::uri_parser::is_query_character(ch);\n                    }\n                };\n                encodedName = uri::encode_impl(encodedName, encodingCheck);\n                encodedValue = uri::encode_impl(encodedValue, encodingCheck);\n            }\n\n            auto encodedQuery = encodedName;\n            encodedQuery.append(_XPLATSTR(\"=\"));\n            encodedQuery.append(encodedValue);\n            // The query key value pair was already encoded by us or the user separately.\n            return append_query(encodedQuery, false);\n        }\n\n        /// <summary>\n        /// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is invalid.\n        /// </summary>\n        /// <returns>The created URI as a string.</returns>\n        _ASYNCRTIMP xsapi_internal_string to_string();\n\n        /// <summary>\n        /// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is invalid.\n        /// </summary>\n        /// <returns>The create URI as a URI class instance.</returns>\n        _ASYNCRTIMP uri to_uri();\n\n        /// <summary>\n        /// Validate the generated URI from all existing components of this uri_builder.\n        /// </summary>\n        /// <returns>Whether the URI is valid.</returns>\n        _ASYNCRTIMP bool is_valid();\n\n    private:\n        details::uri_components m_uri;\n    };\n} // namespace web\n\n} } }\n"
  },
  {
    "path": "Source/Shared/Logger/log.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"log.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nstd::shared_ptr<logger> logger::get_logger()\n{\n    auto state = GlobalState::Get();\n    if (state)\n    {\n        return state->Logger();\n    }\n    return nullptr;\n}\n\nvoid logger::add_log_output(std::shared_ptr<log_output> output)\n{\n    m_log_outputs.emplace_back(output); \n};\n\nvoid logger::set_log_level(HCTraceLevel level)\n{\n    HCSettingsSetTraceLevel(level);\n}\n\nbool logger::is_log_enabled(HCTraceLevel level)\n{\n    for (const auto& output : m_log_outputs)\n    {\n        if (output->log_level_enabled(level))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid logger::add_log(const log_entry& logEntry)\n{\n    for(const auto& output : m_log_outputs)\n    {\n        if (output->log_level_enabled(logEntry.get_log_level()))\n        {\n            output->add_log(logEntry);\n        }\n    }\n}\n\nvoid logger::operator+=(const log_entry& logEntry)\n{\n    add_log(logEntry);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/Logger/log.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"internal_mem.h\"\n\n#if XSAPI_ANDROID_STUDIO\n#include \"trace.h\"\n#endif\n\n#define DEFAULT_LOGGER xbox::services::logger::get_logger()\n\n#if HC_PLATFORM_IS_MICROSOFT\n    #define LOG(logger, level, category, msg)  \\\n        __pragma(warning( push )) \\\n        __pragma(warning( disable : 26444 )) \\\n        { auto logInst = logger; if (logInst) { logInst->add_log({ level, category, msg }); } } \\\n        __pragma(warning( pop ))\n#else\n    #define LOG(logger, level, category, msg) \\\n        { auto logInst = logger; if (logInst) { logInst->add_log({ level, category, msg }); } }\n#endif\n\n#define LOGS(level, category) xbox::services::logger_raii() += xbox::services::log_entry(level, category)\n\n// default logging macro\nconst char defaultCategory[] = \"\";\n#define IF_LOG_ERROR_ENABLED(x) { auto logger = DEFAULT_LOGGER; if (logger && logger->is_log_enabled(HCTraceLevel::Error)) { x; } }\n#define LOG_ERROR(msg) LOG(DEFAULT_LOGGER, HCTraceLevel::Error, defaultCategory, msg)\n#define LOG_ERROR_IF(boolean_expression, msg) if(boolean_expression) LOG_ERROR(msg)\n#define LOGS_ERROR LOGS(HCTraceLevel::Error, defaultCategory)\n#define LOGS_ERROR_IF(boolean_expression) if(boolean_expression) LOGS_ERROR\n\n#define IF_LOG_WARN_ENABLED(x) { auto logger = DEFAULT_LOGGER; if (logger && logger->is_log_enabled(HCTraceLevel::Warning)) { x; } }\n#define LOG_WARN(msg) LOG(DEFAULT_LOGGER, HCTraceLevel::Warning, defaultCategory, msg)\n#define LOG_WARN_IF(boolean_expression, msg) if(boolean_expression) LOG_WARN(msg)\n#define LOGS_WARN LOGS(HCTraceLevel::Warning, defaultCategory)\n#define LOGS_WARN_IF(boolean_expression) if(boolean_expression) LOGS_WARN\n\n#define IF_LOG_INFO_ENABLED(x) { auto logger = DEFAULT_LOGGER; if (logger && logger->is_log_enabled(HCTraceLevel::Information)) { x; } }\n#define LOG_INFO(msg) LOG(DEFAULT_LOGGER, HCTraceLevel::Information, defaultCategory, msg)\n#define LOG_INFO_IF(boolean_expression, msg) if(boolean_expression) LOG_INFO(msg)\n#define LOGS_INFO LOGS(HCTraceLevel::Information, defaultCategory)\n#define LOGS_INFO_IF(boolean_expression) if(boolean_expression) LOGS_INFO\n\n#define IF_LOG_DEBUG_ENABLED(x) { auto logger = DEFAULT_LOGGER; if (logger && logger->is_log_enabled(HCTraceLevel::Verbose)) { x; } }\n#define LOG_DEBUG(msg) LOG(DEFAULT_LOGGER, HCTraceLevel::Verbose, defaultCategory, msg)\n#define LOG_DEBUG_IF(boolean_expression, msg) if(boolean_expression) LOG_DEBUG(msg)\n#define LOGS_DEBUG LOGS(HCTraceLevel::Verbose, defaultCategory)\n#define LOGS_DEBUG_IF(boolean_expression) if(boolean_expression) LOGS_DEBUG\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass log_entry\n{\npublic:\n    log_entry(HCTraceLevel level, xsapi_internal_string category);\n\n    log_entry(HCTraceLevel level, xsapi_internal_string category, xsapi_internal_string msg);\n\n    xsapi_internal_string level_to_string() const;\n\n    const xsapi_internal_stringstream& msg_stream() const { return m_message; }\n\n    const xsapi_internal_string& category() const { return m_category; }\n\n    HCTraceLevel get_log_level() const { return m_logLevel; }\n\n    log_entry& operator<<(const char* data)\n    {\n        m_message << data;\n        return *this;\n    }\n\n    log_entry& operator<<(const xsapi_internal_string& data)\n    {\n        m_message << data;\n        return *this;\n    }\n\n#if HC_PLATFORM_IS_MICROSOFT\n    log_entry& operator<<(const wchar_t* data)\n    {\n        m_message << xbox::services::convert::to_utf8string(data);\n        return *this;\n    }\n\n    log_entry& operator<<(const xsapi_internal_wstring& data)\n    {\n        m_message << xbox::services::convert::to_utf8string(data);\n        return *this;\n    }\n#endif\n\n    template<typename T>\n    log_entry& operator<<(const T& data)\n    {\n        m_message << data;\n        return *this;\n    }\n\nprivate:\n    HCTraceLevel m_logLevel;\n    xsapi_internal_string m_category;\n    xsapi_internal_stringstream m_message;\n};\n\nclass log_output\n{\npublic:\n    log_output();\n\n    virtual void add_log(_In_ const log_entry& entry);\n\n    bool log_level_enabled(HCTraceLevel level) const { return get_log_level() >= level; }\n\n    HCTraceLevel get_log_level() const\n    {\n        HCTraceLevel traceLevel = HCTraceLevel::Off;\n        HCSettingsGetTraceLevel(&traceLevel);\n        return traceLevel;\n    }\n\n    virtual ~log_output() = default;\n\nprotected:\n    // This function is to write the string to the final output, don't need to be thread safe.\n    virtual void write(_In_ HCTraceLevel level, _In_ const xsapi_internal_string& msg);\n\n    virtual xsapi_internal_string format_log(_In_ const log_entry& entry);\n\nprivate:\n    mutable std::mutex m_mutex;\n};\n\nclass logger\n{\npublic:\n    logger() {}\n\n    static std::shared_ptr<logger> get_logger();\n\n    void set_log_level(HCTraceLevel level);\n    void add_log_output(std::shared_ptr<log_output> output);\n\n    void add_log(const log_entry& entry);\n    bool is_log_enabled(HCTraceLevel level);\n    void operator+=(const log_entry& record);\n\nprivate:\n    Vector<std::shared_ptr<log_output>> m_log_outputs;\n};\n\nclass logger_raii\n{\npublic:\n    logger_raii()\n    {\n        m_logger = xbox::services::logger::get_logger();\n    }\n\n    void set_log_level(HCTraceLevel level)\n    {\n        if (m_logger) m_logger->set_log_level(level);\n    }\n\n    void add_log_output(std::shared_ptr<log_output> output)\n    {\n        if (m_logger) m_logger->add_log_output(output);\n    }\n\n    void add_log(const log_entry& entry)\n    {\n        if (m_logger) m_logger->add_log(entry);\n    }\n\n    void operator+=(const log_entry& record)\n    {\n        add_log(record);\n    }\n\nprivate:\n    std::shared_ptr<logger> m_logger;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/Logger/log_entry.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"log.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nlog_entry::log_entry(HCTraceLevel level, xsapi_internal_string category) :\n    m_logLevel(level),\n    m_category(std::move(category))\n{\n}\n\nlog_entry::log_entry(HCTraceLevel level, xsapi_internal_string category, xsapi_internal_string msg) :\n    m_logLevel(level),\n    m_category(std::move(category))\n{\n    m_message << msg;\n}\n\nxsapi_internal_string log_entry::level_to_string() const\n{\n    switch (m_logLevel)\n    {\n        case HCTraceLevel::Error: return \"L1\";\n        case HCTraceLevel::Warning: return \"L2\";\n        case HCTraceLevel::Important: return \"L3\";\n        case HCTraceLevel::Information: return \"L4\";\n        case HCTraceLevel::Verbose: return \"L5\";\n        default: break;\n    }\n\n    return \"\";\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/Logger/log_hc_output.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"log_hc_output.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nvoid log_hc_output::write(_In_ HCTraceLevel level, _In_ const String& msg)\n{\n    constexpr char escapedFormatSpecifier[]{ \"%%\" };\n\n    String const* msgPtr{ &msg };\n    String escapedMsg{};\n\n    size_t index = msg.find('%');\n    if (index != std::string::npos)\n    {\n        // Escape format string before passing to HC_TRACE\n        escapedMsg = msg;\n\n        while ((index = escapedMsg.find('%', index)) != std::string::npos)\n        {\n            escapedMsg.replace(index, 1, escapedFormatSpecifier);\n            index += (sizeof(escapedFormatSpecifier) - 1);\n        }\n\n        msgPtr = &escapedMsg;\n    }\n\n    HC_TRACE_MESSAGE(XSAPI, level, msgPtr->data());\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/Logger/log_hc_output.h",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"log.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass log_hc_output : public log_output\n{\npublic:\n    log_hc_output() : log_output() {}\n\n    void write(_In_ HCTraceLevel level, _In_ const xsapi_internal_string& msg) override;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/Logger/log_output.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"Logger/log.h\"\n#include <iomanip>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nlog_output::log_output()\n{\n}\n\nvoid log_output::add_log(_In_ const log_entry& entry)\n{\n    xsapi_internal_string msg = format_log(entry);\n    {\n        std::lock_guard<std::mutex> lock(m_mutex);\n        write(entry.get_log_level(), msg);\n    }\n}\n\nvoid log_output::write(_In_ HCTraceLevel level, _In_ const xsapi_internal_string& msg)\n{\n    UNREFERENCED_PARAMETER(level);\n    UNREFERENCED_PARAMETER(msg);\n}\n\nxsapi_internal_string\nlog_output::format_log(_In_ const log_entry& entry)\n{\n    return entry.msg_stream().str();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/a/android_utils.cpp",
    "content": "#include \"android_utils.h\"\n#include <assert.h>\n#include \"Logger/log.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\nJString::JString(JNIEnv* env, jstring string) noexcept :\n    m_env{ env },\n    m_string{ string },\n    m_cStr{ nullptr }\n{\n    assert(env);\n    assert(string);\n}\n\nJString::~JString() noexcept\n{\n    if (m_cStr != nullptr)\n    {\n        assert(m_env);\n        assert(m_string);\n\n        m_env->ReleaseStringUTFChars(m_string, m_cStr);\n    }\n}\n\nchar const* JString::c_str()\n{\n    assert(m_env);\n    assert(m_string);\n\n    if (m_cStr == nullptr)\n    {\n        m_cStr = m_env->GetStringUTFChars(m_string, nullptr);\n\n        if (m_cStr == nullptr)\n        {\n            LOG_ERROR(\"GetStringUTFChars failed\");\n        }\n    }\n\n    return m_cStr;\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/a/android_utils.h",
    "content": "#pragma once\n\n#include <jni.h>\n\n#if XSAPI_ANDROID_STUDIO\n#include \"types.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n/// <summary>\n/// Thread unsafe wrapper for the jni jstring object to ensure we don't leak memory\n/// </summary>\nclass JString\n{\npublic:\n    JString(JNIEnv* env, jstring string) noexcept;\n    ~JString() noexcept;\n\n    JString(JString const&) = delete;\n    JString(JString&&) = delete;\n    JString& operator=(JString const&) = delete;\n    JString& operator=(JString&&) = delete;\n\n    char const* c_str();\n\nprivate:\n    JNIEnv * m_env;\n    jstring m_string;\n    char const* m_cStr;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/a/guid.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbl_guid.h\"\n#include \"android_utils.h\"\n#include \"a/java_interop.h\"\n#include \"a/jni_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n#define UNREFERENCED_LOCAL(x) (void)(x);\ntemplate<class TBuffer>\nvoid FormatHelper(TBuffer& buffer, _In_z_ _Printf_format_string_ char const* format, va_list args)\n{\n    va_list args1{};\n    va_copy(args1, args);\n    int required = vsnprintf(nullptr, 0, format, args1);\n    va_end(args1);\n\n    assert(required > 0);\n\n    size_t originalSize = buffer.size();\n\n    va_list args2{};\n    va_copy(args2, args);\n    buffer.resize(originalSize + static_cast<size_t>(required) + 1); // add space for null terminator\n    int written = vsnprintf(reinterpret_cast<char*>(&buffer[originalSize]), buffer.size(), format, args2);\n    va_end(args2);\n\n    assert(written == required);\n    UNREFERENCED_LOCAL(written);\n\n    buffer.resize(buffer.size() - 1); // drop null terminator\n}\n\ninline xsapi_internal_string Format(_In_z_ _Printf_format_string_ char const* format, ...)\n{\n    xsapi_internal_string s;\n\n    va_list args{};\n    va_start(args, format);\n    FormatHelper(s, format, args);\n    va_end(args);\n\n    return s;\n}\n\nxsapi_internal_string generate_guid()\n{\n    auto javaInterop = java_interop::get_java_interop_singleton();\n    auto javaVM = javaInterop->get_java_vm();\n    if (javaVM == nullptr)\n    {\n        LOG_ERROR(\"java interop not initialized properly\");\n        return \"\";\n    }\n    if (javaVM != nullptr)\n    {\n        JNIEnv* jniEnv;\n        JNI_ATTACH_THREAD(javaVM, jniEnv);\n        jclass guidClass = jniEnv->FindClass(\"java/util/UUID\");\n        if (guidClass == nullptr)\n        {\n            LOG_ERROR(\"Could not find UUID class\");\n            return \"\";\n        }\n        jclass m_guidClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(guidClass));\n        jmethodID generateUuidMethodId = jniEnv->GetStaticMethodID(m_guidClass, \"randomUUID\", \"()Ljava/util/UUID;\");\n        jmethodID uuidToStringMethodId = jniEnv->GetMethodID(m_guidClass, \"toString\", \"()Ljava/lang/String;\");\n\n        jobject uuidObject = jniEnv->CallStaticObjectMethod(m_guidClass, generateUuidMethodId);\n        JString rawUuid{ jniEnv, static_cast<jstring>(jniEnv->CallObjectMethod(uuidObject, uuidToStringMethodId)) };\n\n        return Format(\"{%s}\", rawUuid.c_str());\n    }\n    return \"\";\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/a/http_call_jni.cpp",
    "content": "#include \"pch.h\"\n#include \"http_call_jni.h\"\n#include <string>\n#include <android/log.h>\n#include \"jni_utils.h\"\n#include \"http_call_legacy.h\"\n#include \"a/java_interop.h\"\n\n#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, \"HttpCall\", __VA_ARGS__))\n#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"HttpCall\", __VA_ARGS__))\n\n#define JENV_CHECK_MSG(var, env, msg)  \\\n    if (var == nullptr) \\\n    { \\\n    clear_and_log_exception(env); \\\n    LOG_ERROR(msg); \\\n    return; \\\n    }\n\n#define JENV_CHECK_MSG_RET(var, env, msg, ret) \\\n    if (var == nullptr) \\\n    { \\\n    clear_and_log_exception(env); \\\n    LOG_ERROR(msg); \\\n    return ret; \\\n    }\n\nstatic xbox::services::legacy::http_call* getHttpCall(JNIEnv * env, jobject httpCall)\n{\n    jclass cls = env->GetObjectClass(httpCall);\n    jfieldID id = env->GetFieldID(cls, \"id\", \"J\");\n    if (id == nullptr)\n    {\n        XSAPI_ASSERT(false);\n    }\n    return reinterpret_cast<std::shared_ptr<xbox::services::legacy::http_call>*>(env->GetLongField(httpCall, id))->get();\n}\n\nstatic bool clear_and_log_exception(JNIEnv* env)\n{\n    bool ret = false;\n    if (env->ExceptionCheck())\n    {\n        jthrowable e = env->ExceptionOccurred();\n        env->ExceptionClear();\n        jclass cls = env->GetObjectClass(e);\n        jmethodID getMessage = env->GetMethodID(cls, \"getMessage\", \"()Ljava/lang/String;\");\n        jstring_t msg(env, static_cast<jstring>(env->CallObjectMethod(e, getMessage)));\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wformat-security\"\n        LOGE(msg);\n#pragma clang diagnostic pop\n        ret = true;\n    }\n    return ret;\n}\n\nstatic bool prepare_stream(JNIEnv * myEnv, std::shared_ptr<xbox::services::legacy::http_call_response> response, jobject& stream, jmethodID& closeStream)\n{\n    if(!response)\n    {\n        return false;\n    }\n    auto v = response->response_body_vector();\n    auto sz = v.size();\n    LOGD(\"Received %zu bytes\", sz);\n\n    jbyteArray array = myEnv->NewByteArray(sz);\n    JENV_CHECK_MSG_RET(array, myEnv, \"Failed creating Java byte array\", false)\n\n    jbyte* buf = myEnv->GetByteArrayElements(array, nullptr);\n    JENV_CHECK_MSG_RET(buf, myEnv, \"Failed getting array elements\", false)\n\n    memcpy(buf, v.data(), sz);\n    myEnv->ReleaseByteArrayElements(array, buf, 0);\n\n    jclass clsStream = myEnv->FindClass(\"java/io/ByteArrayInputStream\");\n    JENV_CHECK_MSG_RET(clsStream, myEnv, \"Could not find ByteArrayInputStream class\", false)\n\n    jmethodID initStream = myEnv->GetMethodID(clsStream, \"<init>\", \"([B)V\");\n    JENV_CHECK_MSG_RET(initStream, myEnv, \"Failed getting <init> method ID\", false)\n\n    closeStream = myEnv->GetMethodID(clsStream, \"close\", \"()V\");\n    JENV_CHECK_MSG_RET(closeStream, myEnv, \"Failed getting close method ID\", false)\n\n    stream = myEnv->NewObject(clsStream, initStream, array);\n    JENV_CHECK_MSG_RET(stream, myEnv, \"Failed creating ByteArrayInputStream instance\", false)\n\n    return true;\n}\n\nstatic bool prepare_headers(JNIEnv* myEnv, std::shared_ptr<xbox::services::legacy::http_call_response> response, jclass clsHeaders, jobject& headers)\n{\n    if (!response)\n    {\n        return false;\n    }\n\n    jmethodID initHeaders = myEnv->GetMethodID(clsHeaders, \"<init>\", \"()V\");\n    JENV_CHECK_MSG_RET(initHeaders, myEnv, \"Failed getting <init> method ID\", false)\n\n    jmethodID addHeader = myEnv->GetMethodID(clsHeaders, \"add\", \"(Ljava/lang/String;Ljava/lang/String;)V\");\n    JENV_CHECK_MSG_RET(addHeader, myEnv, \"Failed getting add() method ID\", false)\n\n    headers = myEnv->NewObject(clsHeaders, initHeaders);\n    JENV_CHECK_MSG_RET(headers, myEnv, \"Failed creating ByteArrayInputStream instance\", false)\n\n    web::http::http_headers hdr = response->response_headers();\n    for (web::http::http_headers::iterator itr = hdr.begin(); itr != hdr.end(); ++itr)\n    {\n        jstring key = myEnv->NewStringUTF(itr->first.c_str());\n        JENV_CHECK_MSG_RET(key, myEnv, \"Error allocating string for a key\", false)\n\n        local_ref_holder lrKey(std::pair<JNIEnv*, jstring>(myEnv, key));\n\n        jstring value = myEnv->NewStringUTF(itr->second.c_str());\n        JENV_CHECK_MSG_RET(value, myEnv, \"Error allocating string for a value\", false)\n\n        local_ref_holder lrValue(std::pair<JNIEnv*, jstring>(myEnv, value));\n\n        myEnv->CallVoidMethod(headers, addHeader, key, value);\n    }\n\n    return true;\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setRequestBody\n* Signature: (Ljava/lang/String;)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setRequestBody__Ljava_lang_String_2(\n    JNIEnv * env, jobject httpCall, jstring value)\n{\n    if (value != nullptr)\n    {\n        jstring_t strValue(env, value);\n        getHttpCall(env, httpCall)->set_request_body(strValue);\n    }\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setRequestBody\n* Signature: ([B)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setRequestBody___3B(\n    JNIEnv * env, jobject httpCall, jbyteArray value)\n{\n    jbyte* buf = env->GetByteArrayElements(value, nullptr);\n    std::vector<uint8_t> v(reinterpret_cast<uint8_t*>(buf), reinterpret_cast<uint8_t*>(buf) + env->GetArrayLength(value));\n    getHttpCall(env, httpCall)->set_request_body(v);\n    env->ReleaseByteArrayElements(value, buf, JNI_ABORT);\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setCustomHeader\n* Signature: (Ljava/lang/String;Ljava/lang/String;)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setCustomHeader(\n    JNIEnv * env, jobject httpCall, jstring name, jstring value)\n{\n    if (name != nullptr && value != nullptr)\n    {\n        jstring_t strName(env, name);\n        jstring_t strValue(env, value);\n        getHttpCall(env, httpCall)->set_custom_header(strName, strValue);\n    }\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setRetryAllowed\n* Signature: (Z)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setRetryAllowed(\n    JNIEnv * env, jobject httpCall, jboolean value)\n{\n    getHttpCall(env, httpCall)->set_retry_allowed(value);\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setLongHttpCall\n* Signature: (Z)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setLongHttpCall(\n    JNIEnv * env, jobject httpCall, jboolean value)\n{\n    getHttpCall(env, httpCall)->set_long_http_call(value);\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setContentTypeHeaderValue\n* Signature: (Ljava/lang/String;)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setContentTypeHeaderValue(\n    JNIEnv * env, jobject httpCall, jstring value)\n{\n    if (value != nullptr)\n    {\n        jstring_t strValue(env, value);\n        getHttpCall(env, httpCall)->set_content_type_header_value(strValue);\n    }\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    setXboxContractVersionHeaderValue\n* Signature: (Ljava/lang/String;)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setXboxContractVersionHeaderValue(\n    JNIEnv * env, jobject httpCall, jstring value)\n{\n    if (value != nullptr)\n    {\n        jstring_t strValue(env, value);\n        getHttpCall(env, httpCall)->set_xbox_contract_version_header_value(strValue);\n    }\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    getResponseAsync\n* Signature: (Lcom/microsoft/xbox/idp/util/HttpCall/Callback;)V\n*/\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_getResponseAsync__Lcom_microsoft_xbox_idp_util_HttpCall_Callback_2\n    (JNIEnv * env, jobject httpCall, jobject callback)\n{\n\n    jclass clsHeaders = env->FindClass(\"com/microsoft/xbox/idp/util/HttpHeaders\");\n    if (clsHeaders == nullptr) {\n        LOG_ERROR(\"Could not find HttpHeaders class\");\n        return;\n    }\n    jclass myClsHeaders = (jclass)env->NewGlobalRef(clsHeaders);\n\n    JavaVM* jvm;\n    env->GetJavaVM(&jvm);\n    jobject myCallback = env->NewGlobalRef(callback);\n\n    xbox::services::legacy::http_call* http_call = getHttpCall(env, httpCall);\n    auto task = http_call->get_response_with_auth(\n        xbox::services::legacy::http_call_response_body_type::vector_body\n        )\n        .then([jvm, myCallback, myClsHeaders](std::shared_ptr<xbox::services::legacy::http_call_response> response)\n    {\n        if (response)\n        {\n            LOGD(\"HttpCall response error code %d\", response->http_status());\n        }\n\n        JNIEnv* myEnv;\n        jvm->AttachCurrentThread(&myEnv, nullptr);\n        JNI_ERROR_CHECK(myEnv);\n\n        thread_holder th(jvm);\n        global_ref_holder grCallback(std::pair<JNIEnv*, jobject>(myEnv, myCallback));\n        global_ref_holder grClsHeaders(std::pair<JNIEnv*, jobject>(myEnv, myClsHeaders));\n\n        jclass clsCallback = myEnv->GetObjectClass(myCallback);\n        jmethodID processResponse = myEnv->GetMethodID(clsCallback, \"processResponse\", \"(ILjava/io/InputStream;Lcom/microsoft/xbox/idp/util/HttpHeaders;)V\");\n        if (processResponse == nullptr)\n        {\n            LOG_ERROR(\"Failed getting processResponse method ID\");\n            return;\n        }\n\n        jobject stream;\n        jmethodID closeStream;\n\n        if (!prepare_stream(myEnv, response, stream, closeStream))\n        {\n            LOG_ERROR(\"prepare_stream error\");\n            return;\n        }\n\n        local_ref_holder lrStream(std::pair<JNIEnv*, jobject>(myEnv, stream));\n\n        jobject headers = nullptr;\n        if (!prepare_headers(myEnv, response, myClsHeaders, headers))\n        {\n            clear_and_log_exception(myEnv);\n            LOG_ERROR(\"prepare_headers error\");\n            return;\n        }\n\n        local_ref_holder lrHeaders(std::pair<JNIEnv*, jobject>(myEnv, headers));\n\n        jint httpStatus = response->http_status();\n\n        myEnv->CallVoidMethod(myCallback, processResponse, httpStatus, stream, headers);\n        clear_and_log_exception(myEnv);\n\n        myEnv->CallVoidMethod(stream, closeStream);\n        clear_and_log_exception(myEnv);\n    });\n}\n\n/*\n* Class:     com_microsoft_xbox_idp_util_HttpCall\n* Method:    create\n* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)J\n*/\nJNIEXPORT jlong JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_create\n(JNIEnv * env, jclass cls, jstring method, jstring endpoint, jstring pathAndQuery, jboolean addDefaultHeaders)\n{\n    jstring_t strMethod(env, method);\n    jstring_t strEndpoint(env, endpoint);\n    jstring_t strPathAndQuery(env, pathAndQuery);\n\n    LOGD(\"Create HttpCall with uri %s\", strEndpoint.get());\n\n    std::shared_ptr<xbox::services::legacy::http_call>* legacyHttpCallPtr{ nullptr };\n\n    auto user = java_interop::get_java_interop_singleton()->GetStoredUser();\n    if (user)\n    {\n        auto userCopyResult = user->Copy();\n        if (Succeeded(userCopyResult))\n        {\n            String fullUrl{ strEndpoint.get() };\n            xbox::services::uri path{ strPathAndQuery.get() };\n\n            if (!path.is_empty())\n            {\n                fullUrl += path.to_string();\n            }\n\n            auto httpCall = MakeShared<XblHttpCall>(userCopyResult.ExtractPayload());\n            HRESULT hr = httpCall->Init(\n                std::shared_ptr<XboxLiveContextSettings>{ new xbox::services::XboxLiveContextSettings },\n                strMethod.get(),\n                fullUrl,\n                xbox::services::xbox_live_api::unspecified\n            );\n\n            if (SUCCEEDED(hr))\n            {\n                // legacy http_call doesn't duplicate the provided XblHttpCall handle so do it before passing.\n                // This seems like a poor design, but keeping behavior same for now\n                httpCall->AddRef();\n\n                web::uri_builder uriBuilder;\n                uriBuilder.append(strPathAndQuery.get());\n                auto legacyHttpCall = std::make_shared<legacy::http_call>(httpCall.get(), strMethod.get(), strEndpoint.get(), uriBuilder.to_uri());\n                legacyHttpCallPtr = new std::shared_ptr<xbox::services::legacy::http_call>(std::move(legacyHttpCall));\n\n                (*legacyHttpCallPtr)->set_add_default_headers(addDefaultHeaders);\n            }\n        }\n    }\n\n    return reinterpret_cast<jlong>(legacyHttpCallPtr);\n}\n\n/*\n * Class:     com_microsoft_xbox_idp_util_HttpCall\n * Method:    delete\n * Signature: (J)V\n */\nJNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_delete(JNIEnv * env, jclass cls, jlong id)\n{\n    delete reinterpret_cast<std::shared_ptr<xbox::services::legacy::http_call>*>(id);\n}\n\n"
  },
  {
    "path": "Source/Shared/a/http_call_jni.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class com_microsoft_xbox_idp_util_HttpCall */\n\n#ifndef _Included_com_microsoft_xbox_idp_util_HttpCall\n#define _Included_com_microsoft_xbox_idp_util_HttpCall\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setRequestBody\n    * Signature: (Ljava/lang/String;)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setRequestBody__Ljava_lang_String_2\n    (JNIEnv *, jobject, jstring);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setRequestBody\n    * Signature: ([B)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setRequestBody___3B\n    (JNIEnv *, jobject, jbyteArray);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setCustomHeader\n    * Signature: (Ljava/lang/String;Ljava/lang/String;)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setCustomHeader\n    (JNIEnv *, jobject, jstring, jstring);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setRetryAllowed\n    * Signature: (Z)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setRetryAllowed\n    (JNIEnv *, jobject, jboolean);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setLongHttpCall\n    * Signature: (Z)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setLongHttpCall\n    (JNIEnv *, jobject, jboolean);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setContentTypeHeaderValue\n    * Signature: (Ljava/lang/String;)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setContentTypeHeaderValue\n    (JNIEnv *, jobject, jstring);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    setXboxContractVersionHeaderValue\n    * Signature: (Ljava/lang/String;)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_setXboxContractVersionHeaderValue\n    (JNIEnv *, jobject, jstring);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    getResponseAsync\n    * Signature: (Lcom/microsoft/xbox/idp/util/HttpCall/Callback;)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_getResponseAsync__Lcom_microsoft_xbox_idp_util_HttpCall_Callback_2\n    (JNIEnv *, jobject, jobject);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    create\n    * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)J\n    */\n    JNIEXPORT jlong JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_create\n    (JNIEnv *, jclass, jstring, jstring, jstring, jboolean);\n\n    /*\n    * Class:     com_microsoft_xbox_idp_util_HttpCall\n    * Method:    delete\n    * Signature: (J)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_util_HttpCall_delete\n    (JNIEnv *, jclass, jlong);\n\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n\n"
  },
  {
    "path": "Source/Shared/a/http_call_static_glue.cpp",
    "content": "#include \"pch.h\"\n#include \"http_call_jni.h\"\n#include <android/log.h>\n\n#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, \"HttpCallStaticGlue\", __VA_ARGS__))\n#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"HttpCallStaticGlue\", __VA_ARGS__))\n\nstatic JNINativeMethod methods[] = {\n    {\n        \"setRequestBody\",\n        \"(Ljava/lang/String;)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setRequestBody__Ljava_lang_String_2\n    },\n    {\n        \"setRequestBody\",\n        \"([B)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setRequestBody___3B\n    },\n    {\n        \"setCustomHeader\",\n        \"(Ljava/lang/String;Ljava/lang/String;)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setCustomHeader\n    },\n    {\n        \"setRetryAllowed\",\n        \"(Z)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setRetryAllowed\n    },\n    {\n        \"setLongHttpCall\",\n        \"(Z)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setLongHttpCall\n    },\n    {\n        \"setContentTypeHeaderValue\",\n        \"(Ljava/lang/String;)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setContentTypeHeaderValue\n    },\n    {\n        \"setXboxContractVersionHeaderValue\",\n        \"(Ljava/lang/String;)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_setXboxContractVersionHeaderValue\n    },\n    {\n        \"getResponseAsync\",\n        \"(Lcom/microsoft/xbox/idp/util/HttpCall$Callback;)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_getResponseAsync__Lcom_microsoft_xbox_idp_util_HttpCall_Callback_2\n    },\n    {\n        \"create\",\n        \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)J\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_create\n    },\n    {\n        \"delete\",\n        \"(J)V\",\n        (void*)Java_com_microsoft_xbox_idp_util_HttpCall_delete\n    }\n};\n\nbool http_call_register_natives(JNIEnv *env, jobject clsLoader, jmethodID loadClass)\n{\n    jstring clsName = env->NewStringUTF(\"com/microsoft/xbox/idp/util/HttpCall\");\n    jclass cls = (jclass)env->CallObjectMethod(clsLoader, loadClass, clsName);\n    env->DeleteLocalRef(clsName);\n    if (cls == NULL) {\n        LOGE(\"Failed to load class com/microsoft/xbox/idp/util/HttpCall\");\n        return false;\n    }\n    if (env->RegisterNatives(cls, methods, sizeof methods / sizeof *methods) != 0) {\n        LOGE(\"Failed to register native methods\");\n        env->DeleteLocalRef(cls);\n        return false;\n    }\n    env->DeleteLocalRef(cls);\n    LOGD(\"Successfully registerered HttpCall methods\");\n    return true;\n}\n"
  },
  {
    "path": "Source/Shared/a/http_call_static_glue.h",
    "content": "#pragma once\n\nextern bool http_call_register_natives(JNIEnv *env, jobject clsLoader, jmethodID loadClass);\n\n"
  },
  {
    "path": "Source/Shared/a/interop_jni.cpp",
    "content": "#include \"pch.h\"\n#include \"a/java_interop.h\"\n#include <rapidjson/allocators.hpp>\n#include \"uri_impl.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n    JNIEXPORT jboolean JNICALL Java_com_microsoft_xbox_idp_interop_Interop_initializeInterop(JNIEnv* env, jclass clsInterop, jobject context)\n    {\n        xbox::services::xbl_result<void> result = xbox::services::java_interop::get_java_interop_singleton()->initialize(env, clsInterop, context);\n        return result.err() ? 0 : 1;\n    }\n\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_interop_Interop_deinitializeInterop(JNIEnv* env, jclass clsInterop)\n    {\n        xbox::services::java_interop::get_java_interop_singleton()->deinitialize();\n    }\n\n#ifdef __cplusplus\n}\n#endif"
  },
  {
    "path": "Source/Shared/a/interop_jni.h",
    "content": "#pragma once\n\n#include <jni.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n    JNIEXPORT jboolean JNICALL Java_com_microsoft_xbox_idp_interop_Interop_initializeInterop(JNIEnv* env, jclass clsInterop, jobject context);\n\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_interop_Interop_deinitializeInterop(JNIEnv* env, jclass clsInterop);\n\n#ifdef __cplusplus\n}\n#endif"
  },
  {
    "path": "Source/Shared/a/jni_utils.h",
    "content": "#pragma once\n#include <memory>\n#include \"xsapi_utils.h\"\n\ntemplate <class T> struct ref_holder {\n    ref_holder(T ref) : m_ref(ref) { }\n    operator T() const { return m_ref; }\nprotected:\n    T m_ref;\n}; \n\nstruct thread_holder : ref_holder<JavaVM*> {\n    thread_holder() : ref_holder<JavaVM*>(nullptr) {}\n    thread_holder(JavaVM* jvm) : ref_holder<JavaVM*>(jvm) {}\n    ~thread_holder() { if (m_ref != nullptr) { LOG_INFO(_T(\"thread detached\")); m_ref->DetachCurrentThread(); } }\n    void set_ref(JavaVM* ref) { m_ref = ref; }\n};\n\nstruct global_ref_holder : ref_holder<std::pair<JNIEnv*, jobject>> {\n    global_ref_holder(std::pair<JNIEnv*, jobject> ref) : ref_holder<std::pair<JNIEnv*, jobject>>(ref) { }\n    ~global_ref_holder() { m_ref.first->DeleteGlobalRef(m_ref.second); }\n};\n\nstruct local_ref_holder : ref_holder<std::pair<JNIEnv*, jobject>> {\n    local_ref_holder(std::pair<JNIEnv*, jobject> ref) : ref_holder<std::pair<JNIEnv*, jobject>>(ref) { }\n    ~local_ref_holder() { m_ref.first->DeleteLocalRef(m_ref.second); }\n};\n\nclass jstring_deleter : ref_holder<JNIEnv*> {\n    jstring m_s;\npublic:\n    jstring_deleter(JNIEnv * env, jstring s) : ref_holder<JNIEnv*>(env), m_s(s) { }\n    void operator()(const char* s) const { m_ref->ReleaseStringUTFChars(m_s, s); }\n};\n\nstruct jstring_t : std::shared_ptr<const char> {\npublic:\n    jstring_t(JNIEnv* env, jstring s) : std::shared_ptr<const char>(env->GetStringUTFChars(s, NULL), jstring_deleter(env, s)) { }\n    operator string_t() const { return get(); }\n    operator xbox::services::uri() const { return get(); }\n    operator const char*() const { return get(); }\n};\n\n#define JNI_ATTACH_THREAD(jvm, env) \\\n    jvm->GetEnv((void **)&env, JNI_VERSION_1_6); \\\n    thread_holder th; \\\n    if (env == nullptr) \\\n    { \\\n        jvm->AttachCurrentThread(&env, nullptr); \\\n        th.set_ref(jvm); \\\n    } \n\n#define JNI_ERROR_CHECK(env) \\\n    if (env->ExceptionCheck()) \\\n    { \\\n        env->ExceptionDescribe(); \\\n        env->ExceptionClear(); \\\n    }\n\n#define JVM_CHECK_RETURN_TASK_RESULT_VOID(jvm, msg) \\\n    if (jvm == nullptr) \\\n    { \\\n        LOG_ERROR(msg); \\\n        return pplx::task_from_result<xbox_live_result<void>>(xbox_live_result<void>(xbox_live_error_code::runtime_error, msg)); \\\n    }\n\n#define JVM_CHECK_RETURN_RESULT_VOID(jvm, msg) \\\n    if (jvm == nullptr) \\\n    { \\\n        LOG_ERROR(msg); \\\n        return xbox_live_result<void>(xbox_live_error_code::runtime_error, msg); \\\n    }"
  },
  {
    "path": "Source/Shared/a/rwlock_guard.cpp",
    "content": "#include \"a/rwlock_guard.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nrwlock_guard::rwlock_guard(pthread_rwlock_t& lock, bool exclusive) :\n    rwlock(&lock)\n{\n    if (exclusive)\n    {\n        pthread_rwlock_wrlock(rwlock);\n    }\n    else\n    {\n        pthread_rwlock_rdlock(rwlock);\n    }\n}\n\nrwlock_guard::~rwlock_guard()\n{\n    pthread_rwlock_unlock(rwlock);\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/a/rwlock_guard.h",
    "content": "#pragma once\n\n#include <pthread.h>\n\n#if XSAPI_ANDROID_STUDIO\n#include \"types.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n/// <summary>\n/// Wrapper class to use pthread_rwlock_t in an RAII style\n/// We cannot use std::shared_mutex as it was not introduced until c++17\n/// </summary>\nclass rwlock_guard\n{\npublic:\n    /// <summary>\n    /// Constructs a rwlock_guard and locks the given pthread_rwlock\n    /// </summary>\n    rwlock_guard(pthread_rwlock_t& lock, bool exclusive);\n\n    /// <summary>\n    /// Destructs the rwlock_guard and unlocks the pthread_rwlock\n    /// </summary>\n    ~rwlock_guard();\n\n    rwlock_guard(const rwlock_guard&) = delete;\n    rwlock_guard& operator=(const rwlock_guard&) = delete;\nprivate:\n    pthread_rwlock_t* rwlock;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/a/utils_a.cpp",
    "content": "//*********************************************************\n//\n// Copyright (c) Microsoft. All rights reserved.\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n#include \"pch.h\"\n#include \"utils_a.h\"\n#include <android/log.h>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, \"XSAPI.Android\", __VA_ARGS__))\n#define LOGCAT_BUFFER_SIZE 746\nvoid utils_a::log_output(\n    _In_ const string_t& logMessage\n    )\n{\n    std::vector<string_t> logMessageList;\n    auto logMessageSize = logMessage.size();\n    if (logMessageSize > LOGCAT_BUFFER_SIZE)\n    {\n        uint32_t arraySize = logMessageSize / LOGCAT_BUFFER_SIZE;\n        for (uint32_t i = 0; i <= arraySize; ++i)\n        {\n            string_t logSplitMessage;\n            logSplitMessage = logMessage.substr(i * LOGCAT_BUFFER_SIZE, LOGCAT_BUFFER_SIZE);\n            logMessageList.push_back(logSplitMessage);\n        }\n    }\n    else\n    {\n        logMessageList.push_back(logMessage);\n    }\n\n    for (const auto& entry : logMessageList)\n    {\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wformat-security\"\n        LOGI(entry.c_str());\n#pragma clang diagnostic pop\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/a/utils_a.h",
    "content": "//*********************************************************\n//\n// Copyright (c) Microsoft. All rights reserved.\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass utils_a\n{\npublic:\n    static void log_output(_In_ const string_t& logMessage);\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n"
  },
  {
    "path": "Source/Shared/a/xbox_live_app_config_jni.cpp",
    "content": "#include \"pch.h\"\n#include \"jni_utils.h\"\n#include \"xbox_live_app_config_static_glue.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include <httpClient/httpClient.h>\n#include <android/log.h>\n\n#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, \"XboxLiveAppConfig\", __VA_ARGS__))\n#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"XboxLiveAppConfig\", __VA_ARGS__))\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n    /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    create\n    * Signature: ()J\n    */\n    JNIEXPORT jlong JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_create\n        (JNIEnv * env, jclass cls)\n    {\n        return reinterpret_cast<jlong>(new std::shared_ptr<AppConfig>(xbox::services::AppConfig::Instance()));\n    }\n\n   /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    delete\n    * Signature: (J)V\n    */\n    JNIEXPORT void JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_delete\n        (JNIEnv * env, jclass cls, jlong id)\n    {\n        delete reinterpret_cast<std::shared_ptr<AppConfig>*>(id);\n    }\n\n    /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    getTitleId\n    * Signature: (J)I\n    */\n    JNIEXPORT jint JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getTitleId\n        (JNIEnv * env, jclass cls, jlong id)\n    {\n        std::shared_ptr<AppConfig>* cfg = reinterpret_cast<std::shared_ptr<AppConfig>*>(id);\n        return static_cast<jint>((*cfg)->TitleId());\n    }\n\n    /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    getOverrideTitleId\n    * Signature: (J)I\n    */\n    JNIEXPORT jint JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getOverrideTitleId\n    (JNIEnv * env, jclass cls, jlong id)\n    {\n        std::shared_ptr<AppConfig>* cfg = reinterpret_cast<std::shared_ptr<AppConfig>*>(id);\n        return static_cast<jint>(std::stoi((*cfg)->OverrideScid().data()));\n    }\n\n    /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    getScid\n    * Signature: (J)Ljava/lang/String;\n    */\n    JNIEXPORT jstring JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getScid\n        (JNIEnv * env, jclass cls, jlong id)\n    {\n        std::shared_ptr<AppConfig>* cfg = reinterpret_cast<std::shared_ptr<AppConfig>*>(id);\n        string_t scid = (*cfg)->Scid().c_str();\n        return scid.empty() ? nullptr : env->NewStringUTF(scid.c_str());\n    }\n\n    /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    getEnvironment\n    * Signature: (J)Ljava/lang/String;\n    */\n    JNIEXPORT jstring JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getEnvironment\n        (JNIEnv * env, jclass cls, jlong id)\n    {\n        return nullptr;\n    }\n\n    /*\n    * Class:     com_microsoft_xbox_idp_interop_XboxLiveAppConfig\n    * Method:    getSandbox\n    * Signature: (J)Ljava/lang/String;\n    */\n    JNIEXPORT jstring JNICALL Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getSandbox\n        (JNIEnv * env, jclass cls, jlong id)\n    {\n        std::shared_ptr<AppConfig>* cfg = reinterpret_cast<std::shared_ptr<AppConfig>*>(id);\n        auto& sandbox = (*cfg)->Sandbox();\n        return sandbox.empty() ? nullptr : env->NewStringUTF(sandbox.c_str());\n    }\n\n#ifdef __cplusplus\n}\n#endif\n\nstatic JNINativeMethod methods[] = {\n    {\n        \"create\",\n        \"()J\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_create\n    },\n    {\n        \"delete\",\n        \"(J)V\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_delete\n    },\n    {\n        \"getTitleId\",\n        \"(J)I\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getTitleId\n    },\n    {\n        \"getOverrideTitleId\",\n        \"(J)I\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getOverrideTitleId\n    },\n    {\n        \"getScid\",\n        \"(J)Ljava/lang/String;\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getScid\n    },\n    {\n        \"getEnvironment\",\n        \"(J)Ljava/lang/String;\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getEnvironment\n    },\n    {\n        \"getSandbox\",\n        \"(J)Ljava/lang/String;\",\n        (void*)Java_com_microsoft_xbox_idp_interop_XboxLiveAppConfig_getSandbox\n    }\n};\n\nbool xbox_live_app_config_register_natives(JNIEnv *env, jobject clsLoader, jmethodID loadClass)\n{\n    jstring clsName = env->NewStringUTF(\"com/microsoft/xbox/idp/interop/XboxLiveAppConfig\");\n    jclass cls = (jclass)env->CallObjectMethod(clsLoader, loadClass, clsName);\n    env->DeleteLocalRef(clsName);\n    if (cls == NULL) {\n        LOGE(\"Failed to load class com/microsoft/xbox/idp/interop/XboxLiveAppConfig\");\n        return false;\n    }\n    if (env->RegisterNatives(cls, methods, sizeof methods / sizeof *methods) != 0) {\n        LOGE(\"Failed to register native methods\");\n        env->DeleteLocalRef(cls);\n        return false;\n    }\n    env->DeleteLocalRef(cls);\n    LOGD(\"Successfully registerered XboxLiveAppConfig methods\");\n    return true;\n}\n"
  },
  {
    "path": "Source/Shared/a/xbox_live_app_config_static_glue.h",
    "content": "#pragma once\n\nextern bool xbox_live_app_config_register_natives(JNIEnv *env, jobject clsLoader, jmethodID loadClass);\n\n"
  },
  {
    "path": "Source/Shared/async_helpers.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nTaskQueue::TaskQueue() noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (state)\n    {\n        *this = state->Queue();\n    }\n}\n\nTaskQueue::TaskQueue(XTaskQueueHandle handle) noexcept\n{\n    if (handle)\n    {\n        auto hr = XTaskQueueDuplicateHandle(handle, &m_handle);\n        assert(SUCCEEDED(hr));\n        UNREFERENCED_PARAMETER(hr);\n    }\n}\n\nTaskQueue::TaskQueue(const TaskQueue& other) noexcept\n{\n    if (other.m_handle)\n    {\n        auto hr = XTaskQueueDuplicateHandle(other.m_handle, &m_handle);\n        assert(SUCCEEDED(hr));\n        UNREFERENCED_PARAMETER(hr);\n    }\n}\n\nTaskQueue::TaskQueue(TaskQueue&& other) noexcept\n{\n    m_handle = other.m_handle;\n    other.m_handle = nullptr;\n}\n\nTaskQueue& TaskQueue::operator=(TaskQueue other) noexcept\n{\n    std::swap(other.m_handle, m_handle);\n    return *this;\n}\n\nTaskQueue::~TaskQueue() noexcept\n{\n    if (m_handle)\n    {\n        XTaskQueueCloseHandle(m_handle);\n    }\n}\n\nTaskQueue TaskQueue::DeriveWorkerQueue() const noexcept\n{\n    return DeriveWorkerQueue(m_handle);\n}\n\nXTaskQueueHandle TaskQueue::GetHandle() const noexcept\n{\n    return m_handle;\n}\n\nHRESULT TaskQueue::Terminate(\n    _In_ bool wait,\n    _In_opt_ Callback<> queueTerminatedCallback\n) const noexcept\n{\n    auto context{ MakeUnique<Callback<>>(std::move(queueTerminatedCallback)) };\n\n    HRESULT hr = XTaskQueueTerminate(m_handle, wait, context.get(),\n        [](void* context)\n    {\n        // Be sure to retake ownership of the callback here\n        UniquePtr<Callback<>> callback{ reinterpret_cast<Callback<>*>(context) };\n        (*callback)();\n    });\n\n    RETURN_HR_IF_FAILED(hr);\n\n    context.release();\n    return S_OK;\n}\n\nHRESULT TaskQueue::RunWork(\n    _In_ AsyncWork&& work,\n    _In_ uint64_t delayInMs\n) const noexcept\n{\n    return RunOnPort(XTaskQueuePort::Work, std::move(work), delayInMs);\n}\n\nHRESULT TaskQueue::RunCompletion(\n    _In_ AsyncWork&& work,\n    _In_ uint64_t delayInMs\n) const noexcept\n{\n    return RunOnPort(XTaskQueuePort::Completion, std::move(work), delayInMs);\n}\n\nHRESULT TaskQueue::RunOnPort(\n    _In_ XTaskQueuePort port,\n    _In_ AsyncWork&& work,\n    _In_ uint64_t delayInMs\n) const noexcept\n{\n    auto context{ MakeUnique<AsyncWork>(std::move(work)) };\n\n    HRESULT hr = XTaskQueueSubmitDelayedCallback(m_handle, port, static_cast<uint32_t>(delayInMs), context.get(),\n        [](void* context, bool canceled)\n    {\n        UniquePtr<AsyncWork> work{ static_cast<AsyncWork*>(context) };\n        if (!canceled)\n        {\n            (*work)();\n        }\n    });\n\n    RETURN_HR_IF_FAILED(hr);\n\n    context.release();\n    return S_OK;\n}\n\nTaskQueue TaskQueue::DeriveWorkerQueue(XTaskQueueHandle handle) noexcept\n{\n    TaskQueue derivedQueue{ nullptr };\n    TaskQueue queue{ handle };\n\n    // If handle is null, derive a queue from XSAPI global queue\n    if (!queue.m_handle)\n    {\n        queue = TaskQueue{};\n    }\n\n    // If queue is still null, try to derive from the process default queue\n    if (!queue.m_handle)\n    {\n        TaskQueue processQueue{ nullptr };\n        bool haveProcessQueue = XTaskQueueGetCurrentProcessTaskQueue(&processQueue.m_handle);\n        if (haveProcessQueue)\n        {\n            queue = processQueue;\n        }\n    }\n\n    assert(queue.m_handle);\n\n    XTaskQueuePortHandle worker{ nullptr };\n    auto hr = XTaskQueueGetPort(queue.m_handle, XTaskQueuePort::Work, &worker);\n    assert(SUCCEEDED(hr));\n    hr = XTaskQueueCreateComposite(worker, worker, &derivedQueue.m_handle);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return derivedQueue;\n}\n\nPeriodicTask::PeriodicTask(\n    const TaskQueue& queue,\n    uint32_t interval,\n    std::function<void()> task\n) noexcept\n    : m_queue{ queue.DeriveWorkerQueue() },\n    m_interval{ interval },\n    m_task{ std::move(task) }\n{\n}\n\nstd::shared_ptr<PeriodicTask> PeriodicTask::MakeAndRun(\n    const TaskQueue& queue,\n    uint32_t interval,\n    std::function<void()> task\n) noexcept\n{\n    auto periodicTask = std::shared_ptr<PeriodicTask>(\n        new (Alloc(sizeof(PeriodicTask))) PeriodicTask{ queue, interval, std::move(task) },\n        Deleter<PeriodicTask>(),\n        Allocator<PeriodicTask>()\n        );\n\n    periodicTask->m_queue.RunWork([weakThis = std::weak_ptr<PeriodicTask>{ periodicTask }]\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                sharedThis->Run();\n            }\n        });\n\n    return periodicTask;\n}\n\nPeriodicTask::~PeriodicTask() noexcept\n{\n    m_queue.Terminate(false);\n}\n\nHRESULT PeriodicTask::ScheduleImmediately() noexcept\n{\n    std::lock_guard<std::mutex> lock{ mutex };\n    // Every time the task is scheduled manually, skip the next scheduled run\n    m_skipCount++;\n\n    return m_queue.RunWork([weakThis = std::weak_ptr<PeriodicTask>{ shared_from_this() }]\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                sharedThis->Run();\n            }\n        });\n}\n\nvoid PeriodicTask::Run() noexcept\n{\n    try\n    {\n        m_task();\n    }\n    catch (...)\n    {\n        LOGS_ERROR << __FUNCTION__ << \" Failed unexpectedly with exception!\";\n        assert(false);\n    }\n\n    // Schedule the next run\n    m_queue.RunWork([this, weakThis = std::weak_ptr<PeriodicTask>{ shared_from_this() }]\n        {\n            if (auto sharedThis{ weakThis.lock() })\n            {\n                std::unique_lock<std::mutex> lock{ mutex };\n                if (m_skipCount > 0)\n                {\n                    LOGS_DEBUG << __FUNCTION__ << \": Skipping scheduled PeriodicTask, m_skipCount=\" << m_skipCount;\n                    --m_skipCount;\n                }\n                else\n                {\n                    lock.unlock();\n                    Run();\n                }\n            }\n        }, m_interval);\n}\n\nstruct AsyncProviderContext\n{\n    AsyncProviderContext(\n        AsyncProvider&& _provider,\n        const char* _identityName,\n        uint64_t _delay\n    ) noexcept\n        : provider{ std::move(_provider) },\n        identityName{ _identityName },\n        delay{ _delay }\n    {\n    }\n\n    AsyncProvider provider;\n    const char* identityName;\n    uint64_t delay;\n    std::weak_ptr<GlobalState> globalState;\n};\n\nHRESULT RunAsync(\n    XAsyncBlock* async,\n    const char* identityName,\n    AsyncProvider&& provider,\n    uint64_t delayInMs\n) noexcept\n{\n    auto context = MakeUnique<AsyncProviderContext>(std::move(provider), identityName, delayInMs);\n\n    HRESULT hr = XAsyncBegin(async, context.get(), nullptr, identityName,\n        [](_In_ XAsyncOp op, _In_ const XAsyncProviderData* data) noexcept\n    {\n        auto context{ static_cast<AsyncProviderContext*>(data->context) };\n\n        HC_TRACE_VERBOSE(XSAPI, \"RunAsync::XAsyncOp::%s: IdentityName=%s\", EnumName(op).data(), context->identityName);\n        \n        switch (op)\n\n        {\n        case XAsyncOp::Begin:\n            try\n            {\n                // Should we invoke provider on XAsyncOp::Begin?\n                RETURN_HR_IF_FAILED(XAsyncSchedule(data->async, static_cast<uint32_t>(context->delay)));\n#if TRACK_ASYNC\n                auto state = GlobalState::Get();\n                if (state)\n                {\n                    std::lock_guard<std::mutex> lock{ state->asyncBlocksMutex };\n                    state->asyncBlocks[data->async] = context->identityName;\n                    context->globalState = state;\n                }\n                else\n                {\n                    HC_TRACE_VERBOSE(XSAPI, \"XAsync operation running after GlobalState has been destroyed\");\n                    return E_UNEXPECTED;\n                }\n#endif\n                return S_OK;\n            }\n            catch (...)\n            {\n                DISABLE_WARNING_PUSH;\n                SUPPRESS_WARNING_UNNAMED_CUSTOM_OBJ;\n                LOGS_ERROR << \"Unexpected exception in \" << __FUNCTION__ << \", completing XAsyncOperation.\";\n                DISABLE_WARNING_POP;\n                return E_UNEXPECTED;\n            }\n        // For DoWork, GetResult, and Cancel, we have nothing to do. Invoke provider and handle any exceptions.\n        case XAsyncOp::DoWork:\n        case XAsyncOp::GetResult:\n        case XAsyncOp::Cancel:\n            try\n            {\n                return context->provider(op, data);\n            }\n            catch (...)\n            {\n                LOGS_ERROR << \"Unexpected provider exception in \" << __FUNCTION__ << \", completing XAsyncOperation.\";\n                return E_FAIL;\n            }\n        case XAsyncOp::Cleanup:\n        {\n#if TRACK_ASYNC\n            if (auto state{ context->globalState.lock() })\n            {\n                std::lock_guard<std::mutex> lock{ state->asyncBlocksMutex };\n                state->asyncBlocks.erase(data->async);\n            }\n#endif\n\n            // Cleanup should only fail in catostrophic cases. Can't pass result to client \n            // at this point so die with exception.\n\n            HRESULT hr = context->provider(op, data);\n            Delete(context);\n            return hr;\n        }\n        default:\n        {\n            assert(false);\n            return S_OK;\n        }\n        }\n    });\n\n    RETURN_HR_IF_FAILED(hr);\n\n    context.release();\n    return S_OK;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/async_helpers.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"internal_errors.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// Memhook aware function class with type erasure\ntemplate<typename T>\nclass Function;\n\ntemplate<typename Ret, typename... Args>\nclass Function<Ret(Args...)>\n{\npublic:\n    Function() noexcept = default;\n    ~Function() = default;\n\n    Function(std::nullptr_t) noexcept : m_callable{ nullptr }\n    {\n    }\n\n    template <typename Functor>\n    Function(Functor functor) noexcept\n    {\n        m_callable = UniquePtr<ICallable>{ MakeUnique<Callable<Functor>>(std::move(functor)).release() };\n    }\n\n    Function(const Function& rhs) noexcept\n    {\n        *this = rhs;\n    }\n\n    Function(Function&& rhs) noexcept\n    {\n        *this = std::move(rhs);\n    }\n\n    template <typename Functor>\n    Function& operator=(Functor f) noexcept\n    {\n        m_callable = UniquePtr<ICallable>{ MakeUnique<Callable<Functor>>(std::move(f)).release() };\n        return *this;\n    }\n\n    Function& operator=(const Function& rhs) noexcept\n    {\n        if (rhs.m_callable != nullptr)\n        {\n            m_callable = rhs.m_callable->Copy();\n        }\n        else\n        {\n            m_callable.reset();\n        }\n        return *this;\n    }\n\n    Function& operator=(Function&& rhs) noexcept\n    {\n        m_callable = std::move(rhs.m_callable);\n        return *this;\n    }\n\n    Function& operator=(std::nullptr_t) noexcept\n    {\n        m_callable.reset();\n        return *this;\n    }\n\n    Ret operator()(Args... args) const\n    {\n        if (m_callable != nullptr)\n        {\n            return (*m_callable)(args...);\n        }\n        else\n        {\n            return Ret();\n        }\n    }\n\n    bool operator==(std::nullptr_t) const noexcept\n    {\n        return m_callable == nullptr;\n    }\n\n    bool operator!=(std::nullptr_t) const noexcept\n    {\n        return m_callable != nullptr;\n    }\n\nprivate:\n    struct ICallable\n    {\n        virtual ~ICallable() = default;\n        virtual Ret operator()(Args...) = 0;\n        virtual UniquePtr<ICallable> Copy() = 0;\n    };\n\n    template <typename Functor>\n    struct Callable : public ICallable\n    {\n        Callable(Functor functor) : m_functor{ std::move(functor) }\n        {\n        }\n\n        ~Callable() override = default;\n\n        Ret operator()(Args... args) override\n        {\n            return m_functor(args...);\n        }\n\n        UniquePtr<ICallable> Copy() override\n        {\n            return UniquePtr<ICallable>{ MakeUnique<Callable<Functor>>(m_functor).release() };\n        }\n\n        Functor m_functor;\n    };\n\n    UniquePtr<ICallable> m_callable{ nullptr };\n};\n\ntemplate<typename... Args>\nusing xbox_live_callback = Function<void(Args...)>;\n\ntemplate<typename... Args>\nusing Callback = Function<void(Args...)>;\n\nusing AsyncWork = Function<void(void)>;\n\n// RAII wrapper around XTaskQueueHandle\nclass TaskQueue\n{\npublic:\n    TaskQueue() noexcept;\n    TaskQueue(XTaskQueueHandle handle) noexcept;\n    TaskQueue(const TaskQueue& other) noexcept;\n    TaskQueue(TaskQueue&& other) noexcept;\n    TaskQueue& operator=(TaskQueue other) noexcept;\n    ~TaskQueue() noexcept;\n\n    TaskQueue DeriveWorkerQueue() const noexcept;\n    static TaskQueue DeriveWorkerQueue(XTaskQueueHandle handle) noexcept;\n\n    XTaskQueueHandle GetHandle() const noexcept;\n\n    HRESULT Terminate(\n        _In_ bool wait,\n        _In_opt_ Callback<> queueTerminatedCallback = nullptr\n    ) const noexcept;\n\n    HRESULT RunWork(\n        _In_ AsyncWork&& work,\n        _In_ uint64_t delayInMs = 0\n    ) const noexcept;\n\n    HRESULT RunCompletion(\n        _In_ AsyncWork&& work,\n        _In_ uint64_t delayInMs = 0\n    ) const noexcept;\n\nprivate:\n    HRESULT RunOnPort(\n        _In_ XTaskQueuePort port,\n        _In_ AsyncWork&& work,\n        _In_ uint64_t delayInMs = 0\n    ) const noexcept;\n\n    XTaskQueueHandle m_handle{ nullptr };\n};\n\n// PeriodicTask class. Periodically runs synchronous work at fixed intervals or when explicitly requested.\n// Each time the task is run (manually or otherwise), it will be reschduled. Once started, a periodic\n// task will continue to repeat for its lifetime.\nclass PeriodicTask : public std::enable_shared_from_this<PeriodicTask>\n{\npublic:\n    // Create a PeriodTask. The task will be immediately scheduled to the provided queue.\n    static std::shared_ptr<PeriodicTask> MakeAndRun(\n        const TaskQueue& queue,\n        uint32_t interval,\n        std::function<void()> task\n    ) noexcept;\n\n    PeriodicTask(const PeriodicTask&) = delete;\n    PeriodicTask& operator=(PeriodicTask) = delete;\n    ~PeriodicTask() noexcept;\n\n    // Schedules task to the queue immediately.\n    HRESULT ScheduleImmediately() noexcept;\n\nprivate:\n    PeriodicTask(\n        const TaskQueue& queue,\n        uint32_t interval,\n        std::function<void()> work\n    ) noexcept;\n\n    void Run() noexcept;\n\n    TaskQueue m_queue;\n    uint32_t const m_interval;\n    std::function<void()> const m_task;\n\n    int32_t m_skipCount{ 0 };\n    std::mutex mutex;\n};\n\ntemplate<typename... Args>\nclass AsyncContext\n{\npublic:\n    AsyncContext() noexcept = default;\n\n    AsyncContext(Function<void(Args...)>&& callback) noexcept\n        : m_callback{ callback }\n    {\n    }\n\n    AsyncContext(TaskQueue queue, Function<void(Args...)>&& callback) noexcept\n        : m_queue{ std::move(queue) },\n        m_callback{ callback }\n    {\n    }\n\n    AsyncContext(XTaskQueueHandle queueHandle, Function<void(Args...)>&& callback) noexcept\n        : m_queue{ queueHandle },\n        m_callback{ callback }\n    {\n    }\n\n    AsyncContext(TaskQueue queue) noexcept\n        : m_queue{ std::move(queue) }\n    {\n    }\n\n    AsyncContext(XAsyncBlock* asyncBlock) noexcept\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        // Clang seems to compile this and assert even with no invalid uses of this template.\n        // Keep this assert here to catch invalid uses on Microsoft platforms.\n        static_assert(false, \"Constructor only valid for Args... = <HRESULT>\");\n#endif\n    }\n\n    AsyncContext(const AsyncContext& other) = default;\n    AsyncContext(AsyncContext&& other) = default;\n    AsyncContext& operator=(const AsyncContext& other) = default;\n    ~AsyncContext() = default;\n\n    void Complete(Args... args) const noexcept\n    {\n        m_callback(args...);\n    }\n\n    const TaskQueue& Queue() const noexcept\n    {\n        return m_queue;\n    }\n\n    static AsyncContext<Args...> Collapse(\n        Vector<AsyncContext<Args...>> _contexts\n    ) noexcept\n    {\n        return AsyncContext<Args...>(\n            [\n                contexts{ std::move(_contexts) }\n            ]\n        (Args... args)\n        {\n            for (auto& context : contexts)\n            {\n                context.Complete(args...);\n            }\n        });\n    }\n\nprivate:\n    TaskQueue m_queue{ nullptr };\n    Function<void(Args...)> m_callback{ nullptr };\n};\n\ntemplate<>\ninline AsyncContext<HRESULT>::AsyncContext(XAsyncBlock* asyncBlock) noexcept\n    : m_queue{ asyncBlock->queue }\n{\n    m_callback = [asyncBlock](HRESULT hr)\n    {\n        XAsyncComplete(asyncBlock, hr, 0);\n    };\n}\n\ntemplate<>\ninline AsyncContext<Result<void>>::AsyncContext(XAsyncBlock* asyncBlock) noexcept\n    : m_queue{ asyncBlock->queue }\n{\n    m_callback = [asyncBlock](Result<void> result)\n    {\n        XAsyncComplete(asyncBlock, result.Hresult(), 0);\n    };\n}\n\ntypedef Function<HRESULT(XAsyncOp, const XAsyncProviderData*)> AsyncProvider;\n\n// Helper method for writing XAsync Providers.\n// AsyncProvider type allows for capture enabled lambdas. XAsyncProvider context lifetime is managed automatically.\nHRESULT RunAsync(\n    XAsyncBlock* async,\n    const char* identityName,\n    AsyncProvider&& provider,\n    uint64_t delayInMs = 0\n) noexcept;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/build_version.h",
    "content": "//********************************************************* \n//\n// Copyright (c) Microsoft. All rights reserved.\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n#pragma once\n \n#define XBOX_SERVICES_API_VERSION_STRING \"2025.10.20251000.0\"\n"
  },
  {
    "path": "Source/Shared/enum_traits.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#define DEFAULT_ENUM_MIN 0u\n#define DEFAULT_ENUM_MAX 30u\n#define ENUM_RANGE_MAX 1000u\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace detail\n{\n\ntemplate<size_t n>\nclass StaticString\n{\npublic:\n    DISABLE_WARNING_PUSH;\n    SUPPRESS_WARNING_UNINITIALIZED_MEMBER;\n    constexpr StaticString(const char* name) noexcept\n        : StaticString{ name, std::make_index_sequence<n>{} }\n    {\n    }\n    DISABLE_WARNING_POP;\n\n    constexpr operator const char*() const noexcept\n    {\n        return chars;\n    }\n\nprivate:\n    template<std::size_t... I>\n    constexpr StaticString(const char* name, std::index_sequence<I...>) noexcept\n        : chars{ name[I]..., 0 }\n    {\n    }\n\n    const char chars[n + 1]{};\n};\n\ntemplate<>\nclass StaticString<0>\n{\npublic:\n    constexpr StaticString(const char*) noexcept {};\n    constexpr operator const char*() const noexcept\n    {\n        return nullptr;\n    }\n};\n\nusing StringView = std::pair<const char*, size_t>;\n\nconstexpr StringView ParseName(const char* funcName) noexcept\n{\n#if defined(_MSC_VER)\n    constexpr auto delim{ '>' };\n#elif defined(__clang__)\n    constexpr auto delim{ ']' };\n#endif\n    size_t end{ 0 };\n    for (; funcName[end] && funcName[end] != delim; ++end) {}\n\n    size_t begin{ end };\n    for (; begin > 0; --begin)\n    {\n        if (!((funcName[begin - 1] >= '0' && funcName[begin - 1] <= '9') ||\n            (funcName[begin - 1] >= 'a' && funcName[begin - 1] <= 'z') ||\n            (funcName[begin - 1] >= 'A' && funcName[begin - 1] <= 'Z') ||\n            (funcName[begin - 1] == '_')))\n        {\n            break;\n        }\n    }\n\n    // Symbol names cannot begin with a number\n    if (funcName[begin] >= '0' && funcName[begin] <= '9')\n    {\n        // Invalid enum value\n        return StringView{ nullptr, 0 };\n    }\n\n    return StringView{ funcName + begin, end - begin };\n}\n\ntemplate<typename E, E V>\nstatic constexpr auto N() noexcept\n{\n    static_assert(std::is_enum<E>::value, \"E must be an enum type.\");\n#if defined(_MSC_VER)\n    constexpr auto name = ParseName(__FUNCSIG__);\n#elif defined(__clang__)\n    constexpr auto name = ParseName(__PRETTY_FUNCTION__);\n#else\n    static_assert(false, \"Unrecognized platform\");\n#endif\n    return StaticString<name.second>{ name.first };\n}\n\ntemplate<typename E, E V>\nconstexpr auto EnumValueName = N<E, V>();\n\ntemplate<typename E, uint32_t MIN_E, uint32_t MAX_E>\nclass EnumTraits\n{\nprivate:\n    static_assert(std::is_enum<E>::value, \"EnumTraits can only be instantiated for enum types.\");\n    static_assert(std::is_same<std::underlying_type_t<E>, uint32_t>::value, \"EnumTraits can only be instantiated for enums with uint32_t as their underlying type\");\n\n    static constexpr uint32_t range = MAX_E - MIN_E + 1;\n    static_assert(range < ENUM_RANGE_MAX, \"EnumTraits only supports a maximum value range of ENUM_RANGE_MAX\");\n\n    template<std::size_t... I>\n    static constexpr auto Names(std::index_sequence<I...>) noexcept\n    {\n        return std::array<const char*, sizeof...(I)>{ { EnumValueName<E, static_cast<E>(I + MIN_E)>... } };\n    }\n    static constexpr std::array<const char*, range> names = Names(std::make_index_sequence<range>());\n\npublic:\n    static String Name(E v) noexcept\n    {\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n        // This gets around the ODR-use rule on clang when compiling without C++17 support\n        constexpr auto names_{ names };\n#else \n        auto& names_{ names };\n#endif\n        auto i{ static_cast<size_t>(v) };\n        if (i < MIN_E || i > MAX_E)\n        {\n            // Value outside the specified range. Return empty string.\n            return String{};\n        }\n        return String{ names_[i - MIN_E] };\n    }\n\n    static E Value(const char* n) noexcept\n    {\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n        constexpr auto names_{ names };\n#else \n        auto& names_{ names };\n#endif\n\n        for (size_t i = 0; i < names_.size(); ++i)\n        {\n            if (names_[i] && xbox::services::legacy::Stricmp(n, names_[i]) == 0)\n            {\n                return static_cast<E>(i + MIN_E);\n            }\n        }\n        // Provided string didn't map to an enum value. Return default value.\n        return E{};\n    }\n};\n\n}\n\ntemplate<typename E, size_t MIN_E = DEFAULT_ENUM_MIN, size_t MAX_E = DEFAULT_ENUM_MAX>\nconstexpr auto EnumName(E value) noexcept -> std::enable_if_t<std::is_enum<E>::value, String>\n{\n    return detail::EnumTraits<E, MIN_E, MAX_E>::Name(value);\n}\n\ntemplate<typename E, size_t MIN_E = DEFAULT_ENUM_MIN, size_t MAX_E = DEFAULT_ENUM_MAX>\nconstexpr auto EnumValue(const char* name) noexcept -> std::enable_if_t<std::is_enum<E>::value, E>\n{\n    return detail::EnumTraits<E, MIN_E, MAX_E>::Value(name);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/errors.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace legacy\n{\n\n    static xbox_services_error_code_category_impl s_error_code_category_instance;\n\n    const xbox_services_error_code_category_impl& xbox_services_error_code_category()\n    {\n        return s_error_code_category_instance;\n    }\n\n    static xbox_services_error_condition_category_impl s_error_condition_category_instance;\n\n    const xbox_services_error_condition_category_impl& xbox_services_error_condition_category()\n    {\n        return s_error_condition_category_instance;\n    }\n\n    std::string xbox_services_error_code_category_impl::message(_In_ int errorCode) const _NOEXCEPT\n    {\n#if 0 // this returns a non-mem hooked string which can't be changed so commenting it out since its not really needed\n        xbl_error_code code = static_cast<xbl_error_code>(errorCode);\n        switch (code)\n        {\n            case xbl_error_code::no_error: return \"No error\";\n            case xbl_error_code::bad_alloc: return \"bad_alloc\";\n            case xbl_error_code::bad_cast: return \"bad_cast\";\n            case xbl_error_code::invalid_argument: return \"invalid_argument\";\n            case xbl_error_code::out_of_range: return \"out_of_range\";\n            case xbl_error_code::length_error: return \"length_error\";\n            case xbl_error_code::range_error: return \"range_error\";\n            case xbl_error_code::logic_error: return \"logic_error\";\n            case xbl_error_code::runtime_error: return \"runtime_error\";\n            case xbl_error_code::json_error: return \"json_error\";\n            case xbl_error_code::websocket_error: return \"websocket_error\";\n            case xbl_error_code::uri_error: return \"uri_error\";\n            case xbl_error_code::generic_error: return \"generic_error\";\n\n            case xbl_error_code::rta_generic_error: return \"rta_generic_error\";\n            case xbl_error_code::rta_access_denied: return \"rta_access_denied\";\n            case xbl_error_code::rta_subscription_limit_reached: return \"rta_subscription_limit_reached\";\n\n            case xbl_error_code::auth_user_interaction_required: return \"auth_user_interaction_required\";\n            case xbl_error_code::auth_user_switched: return \"auth_user_switched\";\n            case xbl_error_code::auth_user_cancel: return \"auth_user_cancel\";\n            case xbl_error_code::auth_unknown_error: return \"auth_unknown_error\";\n            case xbl_error_code::auth_user_not_signed_in: return \"auth_user_not_signed_in\";\n            case xbl_error_code::auth_runtime_error: return \"auth_runtime_error\";\n            case xbl_error_code::auth_no_token_error: return \"auth_no_token_error\";\n\n            case xbl_error_code::invalid_config: return \"invalid_config\";\n            case xbl_error_code::unsupported: return \"unsupported\";\n\n            case xbl_error_code::HR_ERROR_INTERNET_TIMEOUT: return \"ERROR_INTERNET_TIMEOUT\";\n            case xbl_error_code::AM_E_XASD_UNEXPECTED: return \"AM_E_XASD_UNEXPECTED\";\n            case xbl_error_code::AM_E_XASU_UNEXPECTED: return \"AM_E_XASU_UNEXPECTED\";\n            case xbl_error_code::AM_E_XAST_UNEXPECTED: return \"AM_E_XAST_UNEXPECTED\";\n            case xbl_error_code::AM_E_XSTS_UNEXPECTED: return \"AM_E_XSTS_UNEXPECTED\";\n            case xbl_error_code::AM_E_XDEVICE_UNEXPECTED: return \"AM_E_XDEVICE_UNEXPECTED\";\n            case xbl_error_code::AM_E_DEVMODE_NOT_AUTHORIZED: return \"AM_E_DEVMODE_NOT_AUTHORIZED\";\n            case xbl_error_code::AM_E_NOT_AUTHORIZED: return \"AM_E_NOT_AUTHORIZED\";\n            case xbl_error_code::AM_E_FORBIDDEN: return \"AM_E_FORBIDDEN\";\n            case xbl_error_code::AM_E_UNKNOWN_TARGET: return \"AM_E_UNKNOWN_TARGET\";\n            case xbl_error_code::AM_E_INVALID_NSAL_DATA: return \"AM_E_INVALID_NSAL_DATA\";\n            case xbl_error_code::AM_E_TITLE_NOT_AUTHENTICATED: return \"AM_E_TITLE_NOT_AUTHENTICATED\";\n            case xbl_error_code::AM_E_TITLE_NOT_AUTHORIZED: return \"AM_E_TITLE_NOT_AUTHORIZED\";\n            case xbl_error_code::AM_E_USER_HASH_MISSING: return \"AM_E_USER_HASH_MISSING\";\n            case xbl_error_code::AM_E_USER_NOT_FOUND: return \"AM_E_USER_NOT_FOUND\";\n            case xbl_error_code::AM_E_INVALID_ENVIRONMENT: return \"AM_E_INVALID_ENVIRONMENT\";\n            case xbl_error_code::AM_E_XASD_TIMEOUT: return \"AM_E_XASD_TIMEOUT\";\n            case xbl_error_code::AM_E_XASU_TIMEOUT: return \"AM_E_XASU_TIMEOUT\";\n            case xbl_error_code::AM_E_XAST_TIMEOUT: return \"AM_E_XAST_TIMEOUT\";\n            case xbl_error_code::AM_E_XSTS_TIMEOUT: return \"AM_E_XSTS_TIMEOUT\";\n            case xbl_error_code::AM_E_LIVE_CONNECTION_REQUIRED: return \"AM_E_LIVE_CONNECTION_REQUIRED\";\n            case xbl_error_code::AM_E_NO_NETWORK: return \"AM_E_NO_NETWORK\";\n            case xbl_error_code::AM_E_XTITLE_UNEXPECTED: return \"AM_E_XTITLE_UNEXPECTED\";\n            case xbl_error_code::AM_E_NO_TOKEN_REQUIRED: return \"AM_E_NO_TOKEN_REQUIRED\";\n            case xbl_error_code::AM_E_XTITLE_TIMEOUT: return \"AM_E_XTITLE_TIMEOUT\";\n            case xbl_error_code::XO_E_DEVMODE_NOT_AUTHORIZED: return \"XO_E_DEVMODE_NOT_AUTHORIZED\";\n            case xbl_error_code::XO_E_SYSTEM_UPDATE_REQUIRED: return \"XO_E_SYSTEM_UPDATE_REQUIRED\";\n            case xbl_error_code::XO_E_CONTENT_UPDATE_REQUIRED: return \"XO_E_CONTENT_UPDATE_REQUIRED\";\n            case xbl_error_code::XO_E_ENFORCEMENT_BAN: return \"XO_E_ENFORCEMENT_BAN\";\n            case xbl_error_code::XO_E_THIRD_PARTY_BAN: return \"XO_E_THIRD_PARTY_BAN\";\n            case xbl_error_code::XO_E_ACCOUNT_PARENTALLY_RESTRICTED: return \"XO_E_ACCOUNT_PARENTALLY_RESTRICTED\";\n            case xbl_error_code::XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED: return \"XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED\";\n            case xbl_error_code::XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED: return \"XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED\";\n            case xbl_error_code::XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED: return \"XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED\";\n            case xbl_error_code::XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED: return \"XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED\";\n            case xbl_error_code::XO_E_ACCOUNT_CURFEW: return \"XO_E_ACCOUNT_CURFEW\";\n            case xbl_error_code::XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY: return \"XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY\";\n            case xbl_error_code::XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED: return \"XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED\";\n            case xbl_error_code::XO_E_ACCOUNT_MAINTENANCE_REQUIRED: return \"XO_E_ACCOUNT_MAINTENANCE_REQUIRED\";\n            case xbl_error_code::XO_E_ACCOUNT_TYPE_NOT_ALLOWED: return \"XO_E_ACCOUNT_TYPE_NOT_ALLOWED\";\n            case xbl_error_code::XO_E_CONTENT_ISOLATION: return \"XO_E_CONTENT_ISOLATION\";\n            case xbl_error_code::XO_E_ACCOUNT_NAME_CHANGE_REQUIRED: return \"XO_E_ACCOUNT_NAME_CHANGE_REQUIRED\";\n            case xbl_error_code::XO_E_DEVICE_CHALLENGE_REQUIRED: return \"XO_E_DEVICE_CHALLENGE_REQUIRED\";\n            case xbl_error_code::XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED: return \"XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED\";\n            case xbl_error_code::XO_E_PIN_CHALLENGE_REQUIRED: return \"XO_E_PIN_CHALLENGE_REQUIRED\";\n            case xbl_error_code::XO_E_RETAIL_ACCOUNT_NOT_ALLOWED: return \"XO_E_RETAIL_ACCOUNT_NOT_ALLOWED\";\n            case xbl_error_code::XO_E_SANDBOX_NOT_ALLOWED: return \"XO_E_SANDBOX_NOT_ALLOWED\";\n            case xbl_error_code::XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER: return \"XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER\";\n            case xbl_error_code::XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED: return \"XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED\";\n            case xbl_error_code::XO_E_CONTENT_NOT_AUTHORIZED: return \"XO_E_CONTENT_NOT_AUTHORIZED\";\n\n            case xbl_error_code::http_status_204_resource_data_not_found: return \"204 - ResourceDataNotFound\";\n            case xbl_error_code::http_status_400_bad_request: return \"400 - BadRequest\";\n            case xbl_error_code::http_status_401_unauthorized: return \"401 - Unauthorized\";\n            case xbl_error_code::http_status_403_forbidden: return \"403 - Forbidden\";\n            case xbl_error_code::http_status_404_not_found: return \"404 - NotFound\";\n            case xbl_error_code::http_status_405_method_not_allowed: return \"405 - MethodNotAllowed\";\n            case xbl_error_code::http_status_406_not_acceptable: return \"406 - NotAcceptable\";\n            case xbl_error_code::http_status_407_proxy_authentication_required: return \"407 - ProxyAuthenticationRequired\";\n            case xbl_error_code::http_status_408_request_timeout: return \"408 - RequestTimeout\";\n            case xbl_error_code::http_status_409_conflict: return \"409 - Conflict\";\n            case xbl_error_code::http_status_410_gone: return \"410 - Gone\";\n            case xbl_error_code::http_status_411_length_required: return \"411 - LengthRequired\";\n            case xbl_error_code::http_status_412_precondition_failed: return \"412 - PreconditionFailed\";\n            case xbl_error_code::http_status_413_request_entity_too_large: return \"413 - RequestEntityTooLarge\";\n            case xbl_error_code::http_status_414_request_uri_too_long: return \"414 - RequestUriTooLong\";\n            case xbl_error_code::http_status_415_unsupported_media_type: return \"415 - UnsupportedMediaType\";\n            case xbl_error_code::http_status_416_requested_range_not_satisfiable: return \"416 - RequestedRangeNotSatisfiable\";\n            case xbl_error_code::http_status_417_expectation_failed: return \"417 - Expectation Failed\";\n            case xbl_error_code::http_status_421_misdirected_request: return \"421 - Misdirected Request\";\n            case xbl_error_code::http_status_422_unprocessable_entity: return \"422 - Unprocessable Entity\";\n            case xbl_error_code::http_status_423_locked: return \"423 - Locked\";\n            case xbl_error_code::http_status_424_failed_dependency: return \"424 - Failed Dependency\";\n            case xbl_error_code::http_status_426_upgrade_required: return \"426 - Upgrade Required\";\n            case xbl_error_code::http_status_428_precondition_required: return \"428 - Precondition Required\";\n            case xbl_error_code::http_status_429_too_many_requests: return \"429 - TooManyRequests\";\n            case xbl_error_code::http_status_431_request_header_fields_too_large: return \"431 - Request Header Fields Too Large\";\n            case xbl_error_code::http_status_451_unavailable_for_legal_reasons: return \"451 - Unavailable For Legal Reasons\";\n            case xbl_error_code::http_status_500_internal_server_error: return \"500 - InternalServerError\";\n            case xbl_error_code::http_status_501_not_implemented: return \"501 - Not Implemented\";\n            case xbl_error_code::http_status_502_bad_gateway: return \"502 - Bad Gateway\";\n            case xbl_error_code::http_status_503_service_unavailable: return \"503 - ServiceUnavailable\";\n            case xbl_error_code::http_status_504_gateway_timeout: return \"504 - GatewayTimeout\";\n            case xbl_error_code::http_status_505_http_version_not_supported: return \"505 - HttpVersionNotSupported\";\n            case xbl_error_code::http_status_506_variant_also_negotiates: return \"506 - Variant Also Negotiates\";\n            case xbl_error_code::http_status_507_insufficient_storage: return \"507 - Insufficient Storage\";\n            case xbl_error_code::http_status_508_loop_detected: return \"508 - Loop Detected\";\n            case xbl_error_code::http_status_510_not_extended: return \"510 - Not Extended\";\n            case xbl_error_code::http_status_511_network_authentication_required: return \"511 - Network Authentication Required\";\n\n            case xbl_error_code::HR_INET_E_INVALID_URL: return \"INET_E_INVALID_URL\";\n            case xbl_error_code::HR_INET_E_NO_SESSION: return \"INET_E_NO_SESSION\";\n            case xbl_error_code::HR_INET_E_CANNOT_CONNECT: return \"INET_E_CANNOT_CONNECT\";\n            case xbl_error_code::HR_INET_E_RESOURCE_NOT_FOUND: return \"INET_E_RESOURCE_NOT_FOUND\";\n            case xbl_error_code::HR_INET_E_OBJECT_NOT_FOUND: return \"INET_E_OBJECT_NOT_FOUND\";\n            case xbl_error_code::HR_INET_E_DATA_NOT_AVAILABLE: return \"INET_E_DATA_NOT_AVAILABLE\";\n            case xbl_error_code::HR_INET_E_DOWNLOAD_FAILURE: return \"INET_E_DOWNLOAD_FAILURE\";\n            case xbl_error_code::HR_INET_E_AUTHENTICATION_REQUIRED: return \"INET_E_AUTHENTICATION_REQUIRED\";\n            case xbl_error_code::HR_INET_E_NO_VALID_MEDIA: return \"INET_E_NO_VALID_MEDIA\";\n            case xbl_error_code::HR_INET_E_CONNECTION_TIMEOUT: return \"INET_E_CONNECTION_TIMEOUT\";\n            case xbl_error_code::HR_INET_E_INVALID_REQUEST: return \"INET_E_INVALID_REQUEST\";\n            case xbl_error_code::HR_INET_E_UNKNOWN_PROTOCOL: return \"INET_E_UNKNOWN_PROTOCOL\";\n            case xbl_error_code::HR_INET_E_SECURITY_PROBLEM: return \"INET_E_SECURITY_PROBLEM\";\n            case xbl_error_code::HR_INET_E_CANNOT_LOAD_DATA: return \"INET_E_CANNOT_LOAD_DATA\";\n            case xbl_error_code::HR_INET_E_CANNOT_INSTANTIATE_OBJECT: return \"INET_E_CANNOT_INSTANTIATE_OBJECT\";\n            case xbl_error_code::HR_INET_E_INVALID_CERTIFICATE: return \"INET_E_INVALID_CERTIFICATE\";\n            case xbl_error_code::HR_INET_E_REDIRECT_FAILED: return \"INET_E_REDIRECT_FAILED\";\n            case xbl_error_code::HR_INET_E_REDIRECT_TO_DIR: return \"INET_E_REDIRECT_TO_DIR\";\n            case xbl_error_code::HR_ERROR_NETWORK_UNREACHABLE: return \"ERROR_NETWORK_UNREACHABLE\";\n\n            default:\n                {\n                    std::stringstream msg;\n                    msg << \"Unknown error: 0x\" << std::hex << errorCode;\n                    return msg.str();\n                }\n        }\n#else\n        UNREFERENCED_PARAMETER(errorCode);\n        return std::string();\n#endif\n    }\n\n    std::string xbox_services_error_condition_category_impl::message(_In_ int errorCode) const _NOEXCEPT\n    {\n#if 0 // this returns a non-mem hooked string which can't be changed so commenting it out since its not really needed\n        xbl_error_condition code = static_cast<xbl_error_condition>(errorCode);\n\n        switch (code)\n        {\n            case xbl_error_condition::no_error: return \"No error\";\n            case xbl_error_condition::generic_error: return \"Generic Error\";\n            case xbl_error_condition::generic_out_of_range: return \"Out of Range\";\n            case xbl_error_condition::auth: return \"Authorization Error\";\n            case xbl_error_condition::http: return \"HTTP\";\n            case xbl_error_condition::http_404_not_found: return \"404 - Not Found\";\n            case xbl_error_condition::http_412_precondition_failed: return \"412 - PreconditionFailed\";\n            case xbl_error_condition::http_429_too_many_requests: return \"429- Too Many Requests\";\n            case xbl_error_condition::http_service_timeout: return \"Service Timeout\";\n            case xbl_error_condition::network: return \"Network Error\";\n            case xbl_error_condition::rta: return \"Real Time Activity\";\n\n            default:\n                {\n                    std::stringstream msg;\n                    msg << \"Unknown error: 0x\" << std::hex << errorCode;\n                    return msg.str();\n                }\n        }\n#else\n        UNREFERENCED_PARAMETER(errorCode);\n        return std::string();\n#endif\n    }\n\n    bool xbox_services_error_condition_category_impl::equivalent(\n        _In_ const std::error_code& arbitraryErrorCode,\n        _In_ int xboxLiveErrorCondition) const _NOEXCEPT\n    {\n        if (arbitraryErrorCode.category() != xbox_services_error_code_category())\n        {\n            return false;\n        }\n\n        xbl_error_code code = static_cast<xbl_error_code>(arbitraryErrorCode.value());\n        xbl_error_condition condition = static_cast<xbl_error_condition>(xboxLiveErrorCondition);\n\n        // range 0x80860000 - 0x8086FFFF is reserved for other OnlineId error code\n        // put is under auth_msa error condition\n        if ((arbitraryErrorCode.value() & 0x80860000) == 0x80860000)\n        {\n            return condition == xbl_error_condition::auth;\n        }\n\n        switch (code)\n        {\n            case xbl_error_code::no_error:\n                return (condition == xbl_error_condition::no_error);\n\n            case xbl_error_code::http_status_404_not_found:\n                return (condition == xbl_error_condition::http_404_not_found ||\n                    condition == xbl_error_condition::http);\n\n            case xbl_error_code::http_status_412_precondition_failed:\n                return (condition == xbl_error_condition::http_412_precondition_failed ||\n                    condition == xbl_error_condition::http);\n\n            case xbl_error_code::http_status_408_request_timeout:\n            case xbl_error_code::http_status_503_service_unavailable:\n            case xbl_error_code::http_status_504_gateway_timeout:\n                return (condition == xbl_error_condition::http_service_timeout ||\n                    condition == xbl_error_condition::http);\n\n            case xbl_error_code::http_status_429_too_many_requests:\n                return (condition == xbl_error_condition::http_429_too_many_requests ||\n                    condition == xbl_error_condition::http);\n\n            case xbl_error_code::http_status_500_internal_server_error:\n                return (condition == xbl_error_condition::http);\n\n            case xbl_error_code::http_status_204_resource_data_not_found:\n            case xbl_error_code::http_status_400_bad_request:\n            case xbl_error_code::http_status_401_unauthorized:\n            case xbl_error_code::http_status_402_payment_required:\n            case xbl_error_code::http_status_403_forbidden:\n            case xbl_error_code::http_status_405_method_not_allowed:\n            case xbl_error_code::http_status_406_not_acceptable:\n            case xbl_error_code::http_status_407_proxy_authentication_required:\n            case xbl_error_code::http_status_409_conflict:\n            case xbl_error_code::http_status_410_gone:\n            case xbl_error_code::http_status_411_length_required:\n            case xbl_error_code::http_status_413_request_entity_too_large:\n            case xbl_error_code::http_status_414_request_uri_too_long:\n            case xbl_error_code::http_status_415_unsupported_media_type:\n            case xbl_error_code::http_status_416_requested_range_not_satisfiable:\n            case xbl_error_code::http_status_417_expectation_failed:\n            case xbl_error_code::http_status_421_misdirected_request:\n            case xbl_error_code::http_status_422_unprocessable_entity:\n            case xbl_error_code::http_status_423_locked:\n            case xbl_error_code::http_status_424_failed_dependency:\n            case xbl_error_code::http_status_426_upgrade_required:\n            case xbl_error_code::http_status_428_precondition_required:\n            case xbl_error_code::http_status_431_request_header_fields_too_large:\n            case xbl_error_code::http_status_449_retry_with:\n            case xbl_error_code::http_status_451_unavailable_for_legal_reasons:\n            case xbl_error_code::http_status_501_not_implemented:\n            case xbl_error_code::http_status_502_bad_gateway:\n            case xbl_error_code::http_status_505_http_version_not_supported:\n            case xbl_error_code::http_status_506_variant_also_negotiates:\n            case xbl_error_code::http_status_507_insufficient_storage:\n            case xbl_error_code::http_status_508_loop_detected:\n            case xbl_error_code::http_status_510_not_extended:\n            case xbl_error_code::http_status_511_network_authentication_required:\n                return (condition == xbl_error_condition::http);\n\n            case xbl_error_code::auth_user_interaction_required:\n            case xbl_error_code::auth_user_switched:\n            case xbl_error_code::auth_unknown_error:\n            case xbl_error_code::auth_user_cancel:\n            case xbl_error_code::auth_user_not_signed_in:\n            case xbl_error_code::auth_runtime_error:\n            case xbl_error_code::auth_no_token_error:\n                return condition == xbl_error_condition::auth;\n\n            case xbl_error_code::invalid_config:\n            case xbl_error_code::unsupported:\n                return condition == xbl_error_condition::generic_error;\n\n            case xbl_error_code::AM_E_XASD_UNEXPECTED:\n            case xbl_error_code::AM_E_XASU_UNEXPECTED:\n            case xbl_error_code::AM_E_XAST_UNEXPECTED:\n            case xbl_error_code::AM_E_XSTS_UNEXPECTED:\n            case xbl_error_code::AM_E_XDEVICE_UNEXPECTED:\n            case xbl_error_code::AM_E_DEVMODE_NOT_AUTHORIZED:\n            case xbl_error_code::AM_E_NOT_AUTHORIZED:\n            case xbl_error_code::AM_E_FORBIDDEN:\n            case xbl_error_code::AM_E_UNKNOWN_TARGET:\n            case xbl_error_code::AM_E_INVALID_NSAL_DATA:\n            case xbl_error_code::AM_E_TITLE_NOT_AUTHENTICATED:\n            case xbl_error_code::AM_E_TITLE_NOT_AUTHORIZED:\n            case xbl_error_code::AM_E_USER_HASH_MISSING:\n            case xbl_error_code::AM_E_USER_NOT_FOUND:\n            case xbl_error_code::AM_E_INVALID_ENVIRONMENT:\n            case xbl_error_code::AM_E_XASD_TIMEOUT:\n            case xbl_error_code::AM_E_XASU_TIMEOUT:\n            case xbl_error_code::AM_E_XAST_TIMEOUT:\n            case xbl_error_code::AM_E_XSTS_TIMEOUT:\n            case xbl_error_code::AM_E_LIVE_CONNECTION_REQUIRED:\n            case xbl_error_code::AM_E_NO_NETWORK:\n            case xbl_error_code::AM_E_XTITLE_UNEXPECTED:\n            case xbl_error_code::AM_E_NO_TOKEN_REQUIRED:\n            case xbl_error_code::AM_E_XTITLE_TIMEOUT:\n            case xbl_error_code::XO_E_DEVMODE_NOT_AUTHORIZED:\n            case xbl_error_code::XO_E_SYSTEM_UPDATE_REQUIRED:\n            case xbl_error_code::XO_E_CONTENT_UPDATE_REQUIRED:\n            case xbl_error_code::XO_E_ENFORCEMENT_BAN:\n            case xbl_error_code::XO_E_THIRD_PARTY_BAN:\n            case xbl_error_code::XO_E_ACCOUNT_PARENTALLY_RESTRICTED:\n            case xbl_error_code::XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED:\n            case xbl_error_code::XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED:\n            case xbl_error_code::XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED:\n            case xbl_error_code::XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED:\n            case xbl_error_code::XO_E_ACCOUNT_CURFEW:\n            case xbl_error_code::XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY:\n            case xbl_error_code::XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED:\n            case xbl_error_code::XO_E_ACCOUNT_MAINTENANCE_REQUIRED:\n            case xbl_error_code::XO_E_ACCOUNT_TYPE_NOT_ALLOWED:\n            case xbl_error_code::XO_E_CONTENT_ISOLATION:\n            case xbl_error_code::XO_E_ACCOUNT_NAME_CHANGE_REQUIRED:\n            case xbl_error_code::XO_E_DEVICE_CHALLENGE_REQUIRED:\n            case xbl_error_code::XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED:\n            case xbl_error_code::XO_E_PIN_CHALLENGE_REQUIRED:\n            case xbl_error_code::XO_E_RETAIL_ACCOUNT_NOT_ALLOWED:\n            case xbl_error_code::XO_E_SANDBOX_NOT_ALLOWED:\n            case xbl_error_code::XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER:\n            case xbl_error_code::XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED:\n            case xbl_error_code::XO_E_CONTENT_NOT_AUTHORIZED:\n            case xbl_error_code::HR_ERROR_INTERNET_TIMEOUT:\n                return (condition == xbl_error_condition::auth);\n\n            case xbl_error_code::HR_INET_E_INVALID_URL:\n            case xbl_error_code::HR_INET_E_NO_SESSION:\n            case xbl_error_code::HR_INET_E_CANNOT_CONNECT:\n            case xbl_error_code::HR_INET_E_RESOURCE_NOT_FOUND:\n            case xbl_error_code::HR_INET_E_OBJECT_NOT_FOUND:\n            case xbl_error_code::HR_INET_E_DATA_NOT_AVAILABLE:\n            case xbl_error_code::HR_INET_E_DOWNLOAD_FAILURE:\n            case xbl_error_code::HR_INET_E_AUTHENTICATION_REQUIRED:\n            case xbl_error_code::HR_INET_E_NO_VALID_MEDIA:\n            case xbl_error_code::HR_INET_E_CONNECTION_TIMEOUT:\n            case xbl_error_code::HR_INET_E_INVALID_REQUEST:\n            case xbl_error_code::HR_INET_E_UNKNOWN_PROTOCOL:\n            case xbl_error_code::HR_INET_E_SECURITY_PROBLEM:\n            case xbl_error_code::HR_INET_E_CANNOT_LOAD_DATA:\n            case xbl_error_code::HR_INET_E_CANNOT_INSTANTIATE_OBJECT:\n            case xbl_error_code::HR_INET_E_INVALID_CERTIFICATE:\n            case xbl_error_code::HR_INET_E_REDIRECT_FAILED:\n            case xbl_error_code::HR_INET_E_REDIRECT_TO_DIR:\n            case xbl_error_code::HR_ERROR_NETWORK_UNREACHABLE:\n                return (condition == xbl_error_condition::network);\n\n            case xbl_error_code::out_of_range:\n                return (condition == xbl_error_condition::generic_out_of_range ||\n                    condition == xbl_error_condition::generic_error);\n\n            case xbl_error_code::bad_alloc:\n            case xbl_error_code::bad_cast:\n            case xbl_error_code::invalid_argument:\n            case xbl_error_code::json_error:\n            case xbl_error_code::length_error:\n            case xbl_error_code::range_error:\n            case xbl_error_code::logic_error:\n            case xbl_error_code::runtime_error:\n            case xbl_error_code::uri_error:\n            case xbl_error_code::rta_generic_error:\n            case xbl_error_code::rta_access_denied:\n            case xbl_error_code::rta_subscription_limit_reached:\n            case xbl_error_code::generic_error:\n            default:\n                return (condition == xbl_error_condition::generic_error);\n\n        }\n    }\n\n}\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/errors_legacy.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <system_error>\n\n#ifndef _NOEXCEPT\n#define _NOEXCEPT noexcept\n#endif\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n    /// <summary>\n    /// Enumeration values that define the Xbox Live API error conditions.\n    /// </summary>\n    /// <remarks>\n    /// A best practice is to test the returned std::error_code against these error conditions.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition \n    /// </remarks>\n    /// <example>\n    /// For example:\n    /// <code>\n    /// if( result.err() == xbox::services::legacy::xbox_live_error_condition::auth )\n    /// { \n    ///     // ...\n    /// } \n    /// </code>\n    /// or\n    /// <code>\n    /// switch (result.err().default_error_condition().value())\n    /// {\n    ///   case xbox::services::legacy::xbox_live_error_condition::auth:\n    ///     // ...\n    ///     break;\n    /// }\n    /// </code>\n    /// </example>\n    enum class xbl_error_condition\n    {\n        /// <summary>\n        /// No error.\n        /// </summary>\n        no_error = 0,\n\n        /// <summary>\n        /// A generic error condition.\n        /// </summary>\n        generic_error,\n\n        /// <summary>\n        /// An error condition related to an object being out of range.\n        /// </summary>\n        generic_out_of_range,\n\n        /// <summary>\n        /// An error condition related to attempting to authenticate.\n        /// </summary>\n        auth,\n\n        /// <summary>\n        /// An error condition related to network connectivity.\n        /// </summary>\n        network,\n\n        /// <summary>\n        /// An error condition related to an HTTP method call.\n        /// </summary>\n        http,\n\n        /// <summary>\n        /// The requested resource was not found.\n        /// </summary>\n        http_404_not_found,\n\n        /// <summary>\n        /// The precondition given in one or more of the request-header fields evaluated\n        /// to false when it was tested on the server.\n        /// </summary>\n        http_412_precondition_failed,\n\n        /// <summary>\n        /// Client is sending too many requests\n        /// </summary>\n        http_429_too_many_requests,\n\n        /// <summary>\n        /// The service timed out while attempting to process the request.\n        /// </summary>\n        http_service_timeout,\n\n        /// <summary>\n        /// An error related to real time activity.\n        /// </summary>\n        rta\n    };\n\n    \n    \n    /// <summary>\n    /// These are XSAPI specific error codes.\n    /// Only the HTTP codes and errors that are commonly seen when calling Xbox LIVE are called out with guidance about the cause.\n    /// The best practice to test for and react to using the xbox_live_error_condition enum instead of these error codes.\n    /// </summary>\n    enum class xbl_error_code\n    {\n        /// <summary>\n        /// <b>0</b>\n        /// No error\n        /// </summary>\n        no_error = 0,\n\n        //////////////////////////////////////////////////////////////////////////\n        // HTTP errors\n        //////////////////////////////////////////////////////////////////////////\n\n        /// <summary>\n        /// The 204 response indicates that the content data was not found.\n        /// This code is returned when you are trying to access or write to a session that has been deleted.\n        /// </summary>\n        http_status_204_resource_data_not_found = 204,\n\n        /// <summary>\n        /// <b>0x8019012C</b>\n        /// The 300 response indicates there are multiple choices.  Not returned by Xbox Live services\n        /// </summary>\n        http_status_300_multiple_choices = 300,\n\n        /// <summary>\n        /// <b>0x8019012D</b>\n        /// The 301 response indicates that the request should be directed at a new URI\n        /// </summary>\n        http_status_301_moved_permanently = 301,\n\n        /// <summary>\n        /// <b>0x8019012E</b>\n        /// The 302 response indicates found.\n        /// </summary>\n        http_status_302_found = 302,\n\n        /// <summary>\n        /// <b>0x8019012F</b>\n        /// The 303 response indicates see other.  Not returned by Xbox Live services\n        /// </summary>\n        http_status_303_see_other = 303,\n\n        /// <summary>\n        /// <b>0x80190130</b>\n        /// The 304 response indicates resource has not been modified.\n        /// </summary>\n        http_status_304_not_modified = 304,\n\n        /// <summary>\n        /// <b>0x80190131</b>\n        /// The 305 response indicates you must a use proxy.  Not typically returned by Xbox Live services\n        /// </summary>\n        http_status_305_use_proxy = 305,\n\n        /// <summary>\n        /// <b>0x80190133</b>\n        /// The 307 response indicates a temporary redirect.\n        /// </summary>\n        http_status_307_temporary_redirect = 307,\n\n        /// <summary>\n        /// <b>0x80190190</b>\n        /// The request could not be understood by the server due to malformed syntax. \n        /// The client should not repeat this request without modification.\n        ///\n        /// This code is returned by the following methods:\n        /// Social services\n        /// GetUserProfileAsync:\n        /// The list of XUIDs returned from a leaderboard read operation and passed to this method has failed\n        /// due to one or more invalid XUID values.\n        ///\n        /// Data services\n        /// GetSingleUserStatisticsAsync: \n        /// Corresponds to a general HTTP error code: HTTP 400 Bad Request.\n        ///\n        /// Server Platform services\n        /// AllocateClusterAsync: \n        /// Matchmaking request failure, typically due to QoS (where the requirement is all-or-nothing).\n        ///\n        /// Marketplace services\n        /// GetCatalogItemDetailsAsync: \n        /// The Details service can only support 10 CatalogItems per request (MAX_DETAILS_ITEMS).\n        /// BrowseCatalogAsync: Typically an error of setting maxItems too large. The catalog service only supports a max of \n        /// 25 items per call.\n        /// </summary>\n        http_status_400_bad_request = 400,\n\n        /// <summary>\n        /// <b>0x80190191</b>\n        /// The 401 response typically indicates that authorization has been refused for provided credentials.\n        /// This code is returned when the user(s) or the device is not authorized to access the requested data \n        /// or perform the requested action.\n        /// </summary>\n        http_status_401_unauthorized = 401,\n\n        /// <summary>\n        /// <b>0x80190192</b>\n        /// 402 Payment Required\n        /// </summary>\n        http_status_402_payment_required = 402,\n\n        /// <summary>\n        /// <b>0x80190193</b>\n        /// Corresponds to general HTTP error code HTTP 403 - Forbidden.\n        /// The server understood the request but is refusing to fulfill. Authorization will not resolve the issue\n        /// and the request should not be repeated.\n        ///\n        /// General\n        /// This is typically a service configuration issue or a malformed HTTP request. To resolve, make sure that \n        /// your service configuration is correct, that your console is in the right sandbox, and that you are using \n        /// the correct title id and SCID. Using fiddler to examine the failing HTTP request will often help root cause the issue.\n        ///\n        /// Multiplayer services\n        /// The user doesn't have multiplayer privileges, or the session is private/reserved and the user isn't a member.\n        /// </summary>\n        http_status_403_forbidden = 403,\n\n        /// <summary>\n        /// <b>0x80190194</b>\n        /// This typically indicates that the server has not found anything matching the provided URI.\n        /// The root cause of the 404 will depend on the API you are using. \n        /// For example many of the \"Get Leaderboard\" \n        /// APIs return a 404 error if you request a stat that does not exist, or if the leader board is empty, \n        /// CreateSessionAsync returns a 404 error if you call it with an invalid Session Template name, and \n        /// GetPartyViewAsync fails with a 404 if the multiplayer session times out. Using fiddler to examine the failing \n        /// HTTP request will often help root cause the issue.\n        /// </summary>\n        http_status_404_not_found = 404,\n\n        /// <summary>\n        /// <b>0x80190195</b>\n        /// The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. \n        /// For example, the request is a POST where a PUT is needed.\n        /// </summary>\n        http_status_405_method_not_allowed = 405,\n\n        /// <summary>\n        /// <b>0x80190196</b>\n        /// The resource identified by the request is only capable for generating response entities which have \n        /// content characteristics not acceptable according to the accept headers sent in the Request.\n        /// </summary>\n        http_status_406_not_acceptable = 406,\n\n        /// <summary>\n        /// <b>0x80190197</b>\n        /// This code is similar to HTTP 401 (Unauthorized), but indicates that the client must first \n        /// authenticate itself with the proxy.\n        /// </summary>\n        http_status_407_proxy_authentication_required = 407,\n\n        /// <summary>\n        /// <b>0x80190198</b>\n        /// The client did not produce a request within the time the server was prepared to wait. The client MAY \n        /// repeat the request without modifications at a later time.\n        /// </summary>\n        http_status_408_request_timeout = 408,\n\n        /// <summary>\n        /// <b>0x80190199</b>\n        /// This typically indicates that the request could not be completed due to a conflict with the current \n        /// state of the resource. This code is only allowed in situations where it is expected that a user might \n        /// be able to resolve the conflict and re-submit the request.\n        ///\n        /// Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being \n        /// used and the entity being PUT included changes to a resource which conflict with those made by an earlier \n        /// (third-party) request, the server might use the 409 response to indicate that it can't complete the request. \n        /// In this case, the response entity would likely contain a list of the differences between the two versions in a \n        /// format defined by the Response-ContentType.\n        ///\n        /// Multiplayer services:\n        /// Incorrect session or matchmaking query syntax or re-setting properties that are already pre-defined in the session template.\n        /// The session couldn't be updated because the request is incompatible with the session. For example:\n        /// Constants in the request conflict with constants in the session or session template.\n        /// Members other than the caller are added to, or removed, from a large session.\n        /// </summary>\n        http_status_409_conflict = 409,\n\n        /// <summary>\n        /// <b>0x8019019A</b>\n        /// This typically indicates that the requested resource is no longer available at the server and no forwarding address \n        /// is known. The expectation is that this condition is considered to be permanent.\n        /// </summary>\n        http_status_410_gone = 410,\n\n        /// <summary>\n        /// <b>0x8019019B</b>\n        /// The server refuses to accept the request without a defined Content-Length. The client MAY repeat the request if it \n        /// adds a valid Content-Length header field containing the length of the message-body in the request.\n        /// </summary>\n        http_status_411_length_required = 411,\n\n        /// <summary>\n        /// <b>0x8019019C</b>\n        /// The precondition given in one or more of the request-header fields evaluated to false when it was tested on the \n        /// server. This response code allows the client to place preconditions on the current resource meta information \n        /// (header field data) to prevent the requested method from being applied to a resource other than the one intended.\n        /// \n        /// Multiplayer services\n        /// The If-Match header, or (other than on a GET) the If-None-Match header couldn't be satisfied.\n        /// The If-Match header couldn't be satisfied on a PUT or DELETE to an existing session. The current state of the session \n        /// is returned along with the current ETag.\n        /// </summary>\n        http_status_412_precondition_failed = 412,\n\n        /// <summary>\n        /// <b>0x8019019D</b>\n        /// The server is refusing to process a request because the request entity is larger than the server is willing, or able, \n        /// to process. The server MAY close the connection to prevent the client from continuing with the request.\n        /// </summary>\n        http_status_413_request_entity_too_large = 413,\n\n        /// <summary>\n        /// <b>0x8019019E</b>\n        /// The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. \n        /// This rare condition is only likely to occur when a client has improperly converted a POST Request to a GET Request with long query information.\n        /// </summary>\n        http_status_414_request_uri_too_long = 414,\n\n        /// <summary>\n        /// <b>0x8019019F</b>\n        /// The server is refusing to service the request because the entity of the request is in a format not supported by the \n        /// requested resource for the requested method.\n        /// </summary>\n        http_status_415_unsupported_media_type = 415,\n\n        /// <summary>\n        /// <b>0x801901A0</b>\n        /// A server SHOULD return a response with this status code if a requested included in a Range request-header field, and none of \n        /// the range-specifier values in this field overlap the current extent of the selected resource, and the request did not \n        /// include an If-Range request-header field.\n        /// </summary>\n        http_status_416_requested_range_not_satisfiable = 416,\n\n        /// <summary>\n        /// <b>0x801901A1</b>\n        /// Expect-request header failure\n        /// </summary>\n        http_status_417_expectation_failed = 417,\n\n        /// <summary>\n        /// <b>0x801901A5</b>\n        /// The request was misdirected \n        /// </summary>\n        http_status_421_misdirected_request = 421,\n\n        /// <summary>\n        /// <b>0x801901A6</b>\n        /// The request was not processable\n        /// </summary>\n        http_status_422_unprocessable_entity = 422,\n\n        /// <summary>\n        /// <b>0x801901A7</b>\n        /// The resource was locked \n        /// </summary>\n        http_status_423_locked = 423,\n\n        /// <summary>\n        /// <b>0x801901A8</b>\n        /// The request failed due to dependency\n        /// </summary>\n        http_status_424_failed_dependency = 424,\n\n        /// <summary>\n        /// <b>0x801901AA</b>\n        /// The client should upgrade to later protocol\n        /// </summary>\n        http_status_426_upgrade_required = 426,\n\n        /// <summary>\n        /// <b>0x801901AC</b>\n        /// The server requires a precondition\n        /// </summary>\n        http_status_428_precondition_required = 428,\n\n        /// <summary>\n        /// <b>0x801901AD</b>\n        /// Client is sending too many requests\n        /// </summary>\n        http_status_429_too_many_requests = 429,\n\n        /// <summary>\n        /// <b>0x801901AF</b>\n        /// The request headers are too large\n        /// </summary>\n        http_status_431_request_header_fields_too_large = 431,\n\n        /// <summary>\n        /// <b>0x801901C1</b>\n        /// The request should be retried after doing the appropriate action\n        /// </summary>\n        http_status_449_retry_with = 449,\n\n        /// <summary>\n        /// <b>0x801901C3</b>\n        /// The request was unavailable for legal reasons\n        /// </summary>\n        http_status_451_unavailable_for_legal_reasons = 451,\n\n        /// <summary>\n        /// <b>0x801901F4</b>\n        /// Corresponds to HTTP 500 Internal Server Error.This error can occur when invalid parameters are provided to the web service \n        /// via a RESTful API call, or if the web service encounters a crash or other unexpected error state. Using fiddler to examine \n        /// the failing HTTP request will often help root cause the issue.\n        /// </summary>\n        http_status_500_internal_server_error = 500,\n\n        /// <summary>\n        /// <b>0x801901F5</b>\n        /// The requested service is not implemented.\n        /// </summary>\n        http_status_501_not_implemented = 501,\n\n        /// <summary>\n        /// <b>0x801901F6</b>\n        /// The request got an invalid response to the gateway\n        /// </summary>\n        http_status_502_bad_gateway = 502,\n\n        /// <summary>\n        /// <b>0x801901F7</b>\n        /// The requested service is not available.\n        /// </summary>\n        http_status_503_service_unavailable = 503,\n\n        /// <summary>\n        /// <b>0x801901F8</b>\n        /// The HTTP gateway has timed out.\n        /// </summary>\n        http_status_504_gateway_timeout = 504,\n\n        /// <summary>\n        /// <b>0x801901F9</b>\n        /// This version of HTTP is not supported by the endpoint.\n        /// </summary>\n        http_status_505_http_version_not_supported = 505,\n\n        /// <summary>\n        /// <b>0x801901FA</b>\n        /// Internal configuration error\n        /// </summary>\n        http_status_506_variant_also_negotiates = 506,\n\n        /// <summary>\n        /// <b>0x801901FB</b>\n        /// The service was unable complete the request due to storage\n        /// </summary>\n        http_status_507_insufficient_storage = 507,\n\n        /// <summary>\n        /// <b>0x801901FC</b>\n        /// The service detected an infinite loop while processing\n        /// </summary>\n        http_status_508_loop_detected = 508,\n\n        /// <summary>\n        /// <b>0x801901FE</b>\n        /// The request requires more extensions to complete\n        /// </summary>\n        http_status_510_not_extended = 510,\n\n        /// <summary>\n        /// <b>0x801901FF</b>\n        /// The client needs to authenticate to gain network access.  Not used by Xbox Live services.\n        /// </summary>\n        http_status_511_network_authentication_required = 511,\n\n        //////////////////////////////////////////////////////////////////////////\n        // Errors from exception enabled components such as Casablanca\n        //////////////////////////////////////////////////////////////////////////\n        /// <summary>\n        /// <b>0x8007000e</b>\n        /// xbl_error_code 1000\n        /// Bad alloc\n        /// </summary>\n        bad_alloc = 1000,\n\n        /// <summary>\n        /// <b>0x80004002</b>\n        /// xbl_error_code 1001\n        /// Bad cast\n        /// </summary>\n        bad_cast,\n\n        /// <summary>\n        /// <b>0x80070057</b>\n        /// xbl_error_code 1002\n        /// Invalid argument\n        /// </summary>\n        invalid_argument,\n\n        /// <summary>\n        /// <b>0x8000000b</b>\n        /// xbl_error_code 1003\n        /// Out of range\n        /// </summary>\n        out_of_range,\n\n        /// <summary>\n        /// <b>0x80070018</b>\n        /// xbl_error_code 1004\n        /// Length error\n        /// </summary>\n        length_error,\n\n        /// <summary>\n        /// <b>0x8000000b</b>\n        /// xbl_error_code 1005\n        /// Range error\n        /// </summary>\n        range_error,\n\n        /// <summary>\n        /// <b>0x8000ffff</b>\n        /// xbl_error_code 1006\n        /// Logic error\n        /// </summary>\n        logic_error,\n\n        /// <summary>\n        /// <b>0x89235200</b>\n        /// xbl_error_code 1007\n        /// Runtime error\n        /// </summary>\n        runtime_error,\n\n        /// <summary>\n        /// <b>0x83750007</b>\n        /// xbl_error_code 1008\n        /// JSON error\n        /// </summary>\n        json_error,\n\n        /// <summary>\n        /// <b>0x83750005</b>\n        /// xbl_error_code 1009\n        /// Websocket error\n        /// </summary>\n        websocket_error,\n\n        /// <summary>\n        /// <b>0x83750005</b>\n        /// xbl_error_code 1010\n        /// URI error\n        /// </summary>\n        uri_error,\n\n        /// <summary>\n        /// <b>0x80004005</b>\n        /// xbl_error_code 1011\n        /// Generic error\n        /// </summary>\n        generic_error,\n\n        //////////////////////////////////////////////////////////////////////////\n        // RTA errors\n        //////////////////////////////////////////////////////////////////////////\n        /// <summary>\n        /// <b>0x89235201</b>\n        /// xbl_error_code 1500\n        /// RTA generic error\n        /// </summary>\n        rta_generic_error = 1500,\n\n        /// <summary>\n        /// <b>0x89235202</b>\n        /// xbl_error_code 1501\n        /// RTA subscription limit reached\n        /// </summary>\n        rta_subscription_limit_reached,\n\n        /// <summary>\n        /// <b>0x89235203</b>\n        /// xbl_error_code 1502\n        /// RTA access denied\n        /// </summary>\n        rta_access_denied,\n\n        /// <summary>\n        /// <b>0x89235209</b>\n        /// xbl_error_code 1503\n        /// RTA not activated\n        /// </summary>\n        rta_not_activated,\n\n        //////////////////////////////////////////////////////////////////////////\n        // Auth errors\n        //////////////////////////////////////////////////////////////////////////\n\n        /// <summary>\n        /// <b>0x89235204</b>\n        /// xbl_error_code 2000\n        /// Unknown auth error\n        /// </summary>\n        auth_unknown_error = 2000,\n\n        /// <summary>\n        /// <b>0x8086000c</b>\n        /// xbl_error_code 2001\n        /// User interaction required\n        /// </summary>\n        auth_user_interaction_required,\n\n        /// <summary>\n        /// <b>0x80070525</b>\n        /// xbl_error_code 2002\n        /// User interaction required\n        /// </summary>\n        auth_user_switched,\n\n        /// <summary>\n        /// <b>0x80070525</b>\n        /// xbl_error_code 2003\n        /// User cancelled\n        /// </summary>\n        auth_user_cancel,\n\n        /// <summary>\n        /// <b>0x80070525</b>\n        /// xbl_error_code 2004\n        /// User not signed in\n        /// </summary>\n        auth_user_not_signed_in,\n\n        /// <summary>\n        /// <b>0x89235205</b>\n        /// xbl_error_code 2005\n        /// Auth runtime error\n        /// </summary>\n        auth_runtime_error,\n\n        /// <summary>\n        /// <b>0x89235206</b>\n        /// xbl_error_code 2006\n        /// Auth no token error\n        /// </summary>\n        auth_no_token_error,\n\n        //////////////////////////////////////////////////////////////////////////\n        // Xbox Live SDK errors\n        //////////////////////////////////////////////////////////////////////////\n        /// <summary>\n        /// <b>0x8007064a</b>\n        /// xbl_error_code 3000\n        /// Could not read the xboxservices.config.  Ensure it is deployed in the package at\n        /// Windows::ApplicationModel::Package::Current->InstalledLocation + \"\\xboxservices.config\"\n        /// </summary>\n        invalid_config = 3000,\n\n        /// <summary>\n        /// <b>0x80004001</b>\n        /// xbl_error_code 3001\n        /// API is not supported\n        /// </summary>\n        unsupported = 3001,\n\n        //////////////////////////////////////////////////////////////////////////\n        // xbox live auth errors\n        //////////////////////////////////////////////////////////////////////////\n        /// <summary>\n        /// <b>0x80072EE2</b>\n        /// This error is typically returned by Xbox::Services APIs, GetTokenAndSignatureAsync, \n        /// and CheckLicense. It indicates that the Internet connection or a server response was \n        /// interrupted; possibly the result of a incorrectly configured NSAL. Pending requests \n        /// should be retried when this error is encountered.\n        /// </summary>\n        HR_ERROR_INTERNET_TIMEOUT = (int)0x80072EE2,\n\n        /// <summary>\n        /// <b>0x87DD0003</b>\n        /// XASD returned an unexpected response.\n        /// </summary>\n        AM_E_XASD_UNEXPECTED = (int)0x87DD0003,\n\n        /// <summary>\n        /// <b>0x87DD0004</b>\n        /// XASU returned an unexpected response.\n        /// </summary>\n        AM_E_XASU_UNEXPECTED = (int)0x87DD0004,\n\n        /// <summary>\n        /// <b>0x87DD0005</b>\n        /// XAST returned an unexpected response.\n        /// Cause: Your NSAL configuration is set up correctly for your service, however the \n        /// Relying Party certificate is not yet trusted by Xbox Live.\n        ///\n        /// Resolution : Relying Party configuration on XDP and provide the Relying Party \n        /// certificate in the XSTS token certificate for your endpoint.\n        /// If you are using the NSAL.json file, double check that the Relying Party name is \n        /// correct in the 'target' field of your NSAL.json file on the console and ensure that \n        /// the certificate has been specified in XDP.\n        ///\n        /// If you are developing a UWP title and performing service configuration in XDP, then\n        /// you may have not completed the Application ID binding step correctly.  For more\n        /// information, please see the \"Troubleshooting Sign-in\" article in the Xbox Live documentation.\n        /// </summary>\n        AM_E_XAST_UNEXPECTED = (int)0x87DD0005,\n\n        /// <summary>\n        /// <b>0x87DD0006</b>\n        /// Cause : Your NSAL configuration is set up correctly for your service, however the \n        /// Relying Party certificate is not yet trusted by Xbox Live.\n        /// \n        /// Resolution : Relying Party configuration on XDP and provide the Relying Party \n        /// certificate in the XSTS token certificate for your endpoint.\n        /// If you are using the NSAL.json file, double check that the Relying Party name is \n        /// correct in the 'target' field of your NSAL.json file on the console and ensure \n        /// that the certificate has been specified in XDP.\n        /// </summary>\n        AM_E_XSTS_UNEXPECTED = (int)0x87DD0006,\n\n        /// <summary>\n        /// <b>0x87DD0007</b>\n        /// XDevice returned an unexpected response.\n        /// </summary>\n        AM_E_XDEVICE_UNEXPECTED = (int)0x87DD0007,\n\n        /// <summary>\n        /// <b>0x87DD0008</b>\n        /// The console is not authorized to enable development mode.\n        /// </summary>\n        AM_E_DEVMODE_NOT_AUTHORIZED = (int)0x87DD0008,\n\n        /// <summary>\n        /// <b>0x87DD0009</b>\n        /// The operation was not authorized.\n        /// Cause: The user is not authorized to get an XSTS token with the current TitleID or \n        /// SandboxID setup on the console for the provided URL.\n        /// \n        /// Resolution:\n        /// Ensure that your console is in the proper SandboxID for the TitleID you are using.\n        /// See this forum thread for instructions on changing your SandboxID and which SandboxID \n        /// to use for samples.\n        ///\n        /// Ensure that the test account you are using is partitioned to a group in XDP that has \n        /// access to the TitleID and SandboxID for your title(Note that all accounts are able to \n        /// access the samples while in the sample SandboxID).\n        /// </summary>\n        AM_E_NOT_AUTHORIZED = (int)0x87DD0009,\n\n        /// <summary>\n        /// <b>0x87DD000A</b>\n        /// The operation was forbidden. The server responded with a 403, and a more detailed error is not available.\n        /// </summary>\n        AM_E_FORBIDDEN = (int)0x87DD000A,\n\n        /// <summary>\n        /// <b>0x87DD000B</b>\n        /// The URL specified does not match a known target.\n        ///\n        /// Cause: \n        /// The URL you are attempting to get a token for was not found within your NSAL configuration.\n        /// \n        /// Resolution:\n        /// Ensure that the Relying Party and server name are properly set up as an endpoint \n        /// on your console and in your NSAL.\n        ///\n        /// Try calling a known Xbox Service such as https ://social.xboxlive.com/users/xuid(user's xuid)/people \n        /// to ensure that you can get tokens for the Xbox services. If you are using the NSAL.json file, make sure \n        /// that the 'target' field in the file has your Relying Party name ending with '/' and \n        /// that the server name is set up correctly.\n        /// </summary>\n        AM_E_UNKNOWN_TARGET = (int)0x87DD000B,\n\n        /// <summary>\n        /// <b>0x87DD000C</b>\n        /// There were problems with the JSON data downloaded from the server.\n        /// </summary>\n        AM_E_INVALID_NSAL_DATA = (int)0x87DD000C,\n\n        /// <summary>\n        /// <b>0x87DD000D</b>\n        /// The title has not yet been successfully authenticated.\n        /// Cause: This will be returned when a title token is required, but has not been cached. For example, \n        /// attempting to retrieve an X token with title claims will fail with this error if AuthenticateTitle \n        /// hasn't been called successfully.\n        /// \n        /// Resolution: Check your TitleID, SOCID, and SandboxID, or check your title's configuration on XDP.\n        /// </summary>\n        AM_E_TITLE_NOT_AUTHENTICATED = (int)0x87DD000D,\n\n        /// <summary>\n        /// <b>0x87DD000E</b>\n        /// XAST returned 401 when attempting to retrieve the T token.  Double-check that your device is set to the\n        /// proper development sandbox and that the user has access to the sandbox.\n        ///\n        /// For more information, please see the \"Troubleshooting Sign-in\" article in the Xbox Live documentation.\n        /// </summary>\n        AM_E_TITLE_NOT_AUTHORIZED = (int)0x87DD000E,\n\n        /// <summary>\n        /// <b>0x87DD0011</b>\n        /// The user hash value for the specified user hasn't been recorded, so a valid token can't be generated.\n        /// </summary>\n        AM_E_USER_HASH_MISSING = (int)0x87DD0011,\n\n        /// <summary>\n        /// <b>0x87DD0013</b>\n        /// The Authentication Manager can't find the user for which an authentication token is being retrieved. \n        /// One possible scenario is that the User signed out, but the title still has a reference to the User object.\n        /// </summary>\n        AM_E_USER_NOT_FOUND = (int)0x87DD0013,\n\n        /// <summary>\n        /// <b>0x87DD0015</b>\n        /// The environment configured or specified is not valid.\n        /// </summary>\n        AM_E_INVALID_ENVIRONMENT = (int)0x87DD0015,\n\n        /// <summary>\n        /// <b>0x87DD0016</b>\n        /// The XASD authentication server has timed out.\n        /// </summary>\n        AM_E_XASD_TIMEOUT = (int)0x87DD0016,\n\n        /// <summary>\n        /// <b>0x87DD0017</b>\n        /// The XASU authentication server has timed out.\n        /// </summary>\n        AM_E_XASU_TIMEOUT = (int)0x87DD0017,\n\n        /// <summary>\n        /// <b>0x87DD0018</b>\n        /// The XAST authentication server has timed out.\n        /// </summary>\n        AM_E_XAST_TIMEOUT = (int)0x87DD0018,\n\n        /// <summary>\n        /// <b>0x87DD0019</b>\n        /// The XSTS authentication server has timed out.\n        /// </summary>\n        AM_E_XSTS_TIMEOUT = (int)0x87DD0019,\n\n        /// <summary>\n        /// <b>0x87DD001A</b>\n        /// Title authentication failed because a connection to Xbox Live is required, by policy, and none is present.\n        /// </summary>\n        AM_E_LIVE_CONNECTION_REQUIRED = (int)0x87DD001A,\n\n        /// <summary>\n        /// <b>0x87dd001e</b>\n        /// There is no network connection.\n        /// </summary>\n        AM_E_NO_NETWORK = (int)0x87dd001e,\n\n        /// <summary>\n        /// <b>0x87dd0020</b>\n        /// The Network Security Authorization List(NSAL) returned an unexpected response.\n        /// </summary>\n        AM_E_XTITLE_UNEXPECTED = (int)0x87dd0020,\n\n        /// <summary>\n        /// <b>0x87dd0021</b>\n        /// The endpoint does not require an authorization token, but the application is attempting to \n        /// retrieve a token via GetTokenAndSignatureAsync.\n        /// </summary>\n        AM_E_NO_TOKEN_REQUIRED = (int)0x87dd0021,\n\n        /// <summary>\n        /// <b>0x87dd0022</b>\n        /// Timeouts were received from the various authorization servers.\n        /// </summary>\n        AM_E_XTITLE_TIMEOUT = (int)0x87dd0022,\n\n        /// <summary>\n        /// <b>0x8015DC00</b>\n        /// Developer mode is not authorized for the client device.\n        /// </summary>\n        XO_E_DEVMODE_NOT_AUTHORIZED = (int)0x8015DC00,\n\n        /// <summary>\n        /// <b>0x8015DC01</b>\n        /// A system update is required before this action can be performed.\n        /// </summary>\n        XO_E_SYSTEM_UPDATE_REQUIRED = (int)0x8015DC01,\n\n        /// <summary>\n        /// <b>0x8015DC02</b>\n        /// A content update is required before this action can be performed.\n        /// </summary>\n        XO_E_CONTENT_UPDATE_REQUIRED = (int)0x8015DC02,\n\n        /// <summary>\n        /// <b>0x8015DC03</b>\n        /// The device or user was banned.\n        /// </summary>\n        XO_E_ENFORCEMENT_BAN = (int)0x8015DC03,\n\n        /// <summary>\n        /// <b>0x8015DC04</b>\n        /// The device or user was banned.\n        /// </summary>\n        XO_E_THIRD_PARTY_BAN = (int)0x8015DC04,\n\n        /// <summary>\n        /// <b>0x8015DC05</b>\n        /// Access to this resource has been parentally restricted.\n        /// </summary>\n        XO_E_ACCOUNT_PARENTALLY_RESTRICTED = (int)0x8015DC05,\n\n        /// <summary>\n        /// <b>0x8015DC08</b>\n        /// Access to this resource requires that the account billing information\n        /// is updated.\n        /// </summary>\n        XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED = (int)0x8015DC08,\n\n        /// <summary>\n        /// <b>0x8015DC0A</b>\n        /// The user has not accepted the terms of use for this resource.\n        /// </summary>\n        XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED = (int)0x8015DC0A,\n\n        /// <summary>\n        /// <b>0x8015DC0B</b>\n        /// This resource is not available in the country associated with the user.\n        /// </summary>\n        XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED = (int)0x8015DC0B,\n\n        /// <summary>\n        /// <b>0x8015DC0C</b>\n        /// Access to this resource requires age verification.\n        /// </summary>\n        XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED = (int)0x8015DC0C,\n\n        /// <summary>\n        /// <b>0x8015DC0D</b>\n        /// </summary>\n        XO_E_ACCOUNT_CURFEW = (int)0x8015DC0D,\n\n        /// <summary>\n        /// <b>0x8015DC0E</b>\n        /// </summary>\n        XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY = (int)0x8015DC0E,\n\n        /// <summary>\n        /// <b>0x8015DC0F</b>\n        /// </summary>\n        XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED = (int)0x8015DC0F,\n\n        /// <summary>\n        /// <b>0x8015DC09</b>\n        /// </summary>\n        XO_E_ACCOUNT_CREATION_REQUIRED = (int)0x8015DC09,\n\n        /// <summary>\n        /// <b>0x8015DC10</b>\n        /// </summary>\n        XO_E_ACCOUNT_MAINTENANCE_REQUIRED = (int)0x8015DC10,\n\n        /// <summary>\n        /// <b>0x8015DC11</b>\n        /// The call was blocked because there was a conflict with the sandbox, console, application, or \n        /// your account.Verify your account, console and title settings in XDP, and check the current \n        /// Sandbox on the device.\n        /// </summary>\n        XO_E_ACCOUNT_TYPE_NOT_ALLOWED = (int)0x8015DC11,\n\n        /// <summary>\n        /// <b>0x8015DC12</b>\n        /// Your device does not have access to the Sandbox it is set to, or the account you are signed \n        /// in with does not have access to the Sandbox.Check that you are using the correct Sandbox.\n        ///\n        /// Note: All XDK samples use XDKS.1 SandboxID, which allow all user accounts to access and run \n        /// the samples.SandboxID's are case sensitive- Not matching the case of your SandboxID exactly may \n        /// result in errors. If you are still having issues running the sample, please work with your \n        /// Developer Account Manager and provide a fiddler trace to help with troubleshooting.\n        ///\n        /// For more information on handling this error, please see the \"Troubleshooting Sign-in\" article\n        /// in the Xbox Live documentation\n        /// </summary>\n        XO_E_CONTENT_ISOLATION = (int)0x8015DC12,\n\n        /// <summary>\n        /// <b>0x8015DC13</b>\n        /// </summary>\n        XO_E_ACCOUNT_NAME_CHANGE_REQUIRED = (int)0x8015DC13,\n\n        /// <summary>\n        /// <b>0x8015DC14</b>\n        /// </summary>\n        XO_E_DEVICE_CHALLENGE_REQUIRED = (int)0x8015DC14,\n\n        /// <summary>\n        /// <b>0x8015DC16</b>\n        /// The account was signed in on another device.\n        /// </summary>\n        XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED = (int)0x8015DC16,\n\n        /// <summary>\n        /// <b>0x8015DC17</b>\n        /// </summary>\n        XO_E_PIN_CHALLENGE_REQUIRED = (int)0x8015DC17,\n\n        /// <summary>\n        /// <b>0x8015DC18</b>\n        /// </summary>\n        XO_E_RETAIL_ACCOUNT_NOT_ALLOWED = (int)0x8015DC18,\n\n        /// <summary>\n        /// <b>0x8015DC19</b>\n        /// The current sandbox is not allowed to access the SCID.  Please ensure that your current\n        /// sandbox is set to your development sandbox.  If you are running on a Windows 10 PC, then\n        /// you can change your current sandbox using the SwitchSandbox.cmd script in the Xbox Live SDK\n        /// tools directory.  If you are using an Xbox One, you can switch the sandbox using Xbox One\n        /// Manager.\n        ///\n        /// For more information on handling this error, please see the \"Troubleshooting Sign-in\" article\n        /// in the Xbox Live documentation.\n        /// </summary>\n        XO_E_SANDBOX_NOT_ALLOWED = (int)0x8015DC19,\n\n        /// <summary>\n        /// <b>0x8015DC1A</b>\n        /// </summary>\n        XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER = (int)0x8015DC1A,\n\n        /// <summary>\n        /// <b>0x8015DC1B</b>\n        /// </summary>\n        XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED = (int)0x8015DC1B,\n\n        /// <summary>\n        /// <b>0x8015DC1C</b>\n        /// </summary>\n        XO_E_CONTENT_NOT_AUTHORIZED = (int)0x8015DC1C,\n\n        //////////////////////////////////////////////////////////////////////////\n        // Generic errors\n        //////////////////////////////////////////////////////////////////////////\n\n        /// <summary>\n        /// <b>0x800C0002</b>\n        /// The URL is invalid.\n        /// </summary>\n        HR_INET_E_INVALID_URL = (int)0x800C0002,\n\n        /// <summary>\n        /// <b>0x800C0003</b>\n        /// No session.\n        /// </summary>\n        HR_INET_E_NO_SESSION = (int)0x800C0003,\n\n        /// <summary>\n        /// <b>0x800C0004</b>\n        /// WinINet cannot connect to the requested resource.\n        /// </summary>\n        HR_INET_E_CANNOT_CONNECT = (int)0x800C0004,\n\n        /// <summary>\n        /// <b>0x800C0005</b>\n        /// The requested resource was not found.\n        /// </summary>\n        HR_INET_E_RESOURCE_NOT_FOUND = (int)0x800C0005,\n\n        /// <summary>\n        /// <b>0x800C0006</b>\n        /// The requested resource was not found.\n        /// </summary>\n        HR_INET_E_OBJECT_NOT_FOUND = (int)0x800C0006,\n\n        /// <summary>\n        /// <b>0x800C0007</b>\n        /// The requested resource was not found.\n        /// </summary>\n        HR_INET_E_DATA_NOT_AVAILABLE = (int)0x800C0007,\n\n        /// <summary>\n        /// <b>0x800C0008</b>\n        /// Operation restricted by the current inability to discover or join the multiplayer session, or \n        /// the player does not have the multiplayer privilege.\n        /// </summary>\n        HR_INET_E_DOWNLOAD_FAILURE = (int)0x800C0008,\n\n        /// <summary>\n        /// <b>0x800C0009</b>\n        /// Authentication is required to access this resource.\n        /// </summary>\n        HR_INET_E_AUTHENTICATION_REQUIRED = (int)0x800C0009,\n\n        /// <summary>\n        /// <b>0x800C000A</b>\n        /// No valid media\n        /// </summary>\n        HR_INET_E_NO_VALID_MEDIA = (int)0x800C000A,\n\n        /// <summary>\n        /// <b>0x800C000B</b>\n        /// The connection has timed out.\n        /// </summary>\n        HR_INET_E_CONNECTION_TIMEOUT = (int)0x800C000B,\n\n        /// <summary>\n        /// <b>0x800C000C</b>\n        /// Invalid request\n        /// </summary>\n        HR_INET_E_INVALID_REQUEST = (int)0x800C000C,\n\n        /// <summary>\n        /// <b>0x800C000D</b>\n        /// The requested protocol is unknown.\n        /// </summary>\n        HR_INET_E_UNKNOWN_PROTOCOL = (int)0x800C000D,\n\n        /// <summary>\n        /// <b>0x800C000E</b>\n        /// Security problem\n        /// </summary>\n        HR_INET_E_SECURITY_PROBLEM = (int)0x800C000E,\n\n        /// <summary>\n        /// <b>0x800C000F</b>\n        /// Cannot load data\n        /// </summary>\n        HR_INET_E_CANNOT_LOAD_DATA = (int)0x800C000F,\n\n        /// <summary>\n        /// <b>0x800C0010</b>\n        /// Cannot instantiate object\n        /// </summary>\n        HR_INET_E_CANNOT_INSTANTIATE_OBJECT = (int)0x800C0010,\n\n        /// <summary>\n        /// <b>0x800C0019</b>\n        /// The certificate presented for the request is invalid.\n        /// </summary>\n        HR_INET_E_INVALID_CERTIFICATE = (int)0x800C0019,\n\n        /// <summary>\n        /// <b>0x800C0014</b>\n        /// The redirect to a different endpoint has failed.\n        /// </summary>\n        HR_INET_E_REDIRECT_FAILED = (int)0x800C0014,\n\n        /// <summary>\n        /// <b>0x800C0015</b>\n        /// A resource request has been directed to a directory rather than an individual resource.\n        /// </summary>\n        HR_INET_E_REDIRECT_TO_DIR = (int)0x800C0015,\n\n        /// <summary>\n        /// <b>0x800704cf</b>\n        /// The network location cannot be reached.\n        /// </summary>\n        HR_ERROR_NETWORK_UNREACHABLE = (int)0x800704cf,\n\n        /// <summary>\n        /// <b>0x89235007</b>\n        /// The network has not been initialized.\n        /// </summary>\n        HR_HC_NETWORK_NOT_INTIALIZED = (int)0x89235007\n    };\n\n\n\n    namespace legacy\n    {\n    /// <summary>\n    /// Category error type for XSAPI error codes.\n    /// </summary>\n    class xbox_services_error_code_category_impl : public std::error_category\n    {\n        public:\n            /// <summary>\n            /// Gets the error category name.\n            /// </summary>\n            /// <returns>A string identifying the category.</returns>\n        _XSAPIIMP const char* name() const _NOEXCEPT override { return \"XBL\"; }\n\n        /// <summary>\n        /// Converts an error value into a string that describes the error.\n        /// </summary>\n        /// <returns>A string that describes the error.</returns>\n        _XSAPIIMP std::string message(_In_ int errorCode) const _NOEXCEPT override;\n    };\n\n    /// <summary>\n    /// Category error type for XSAPI error conditions.\n    /// </summary>\n    class xbox_services_error_condition_category_impl : public std::error_category\n    {\n        public:\n            /// <summary>\n            /// Gets the error category name.\n            /// </summary>\n            /// <returns>A string identifying the category.</returns>\n        _XSAPIIMP const char* name() const _NOEXCEPT override { return \"XBL CONDITION\"; }\n\n        /// <summary>\n        /// Converts an error value into a string that describes the error.\n        /// </summary>\n        /// <returns>A string that describes the error.</returns>\n        _XSAPIIMP std::string message(_In_ int errorCode) const _NOEXCEPT override;\n\n        /// <summary>\n        /// Used to establish equivalence between arbitrary error_codes in\n        /// the current category with arbitrary error_conditions.\n        /// </summary>\n        /// <param name=\"arbitraryErrorCode\">An error code.</param>\n        /// <param name=\"xboxLiveErrorCondition\">An error condition.</param>\n        /// <returns>True if the error code and the error condition are related; otherwise false.</returns>\n        _XSAPIIMP bool equivalent(\n            _In_ const std::error_code& arbitraryErrorCode,\n            _In_ int xboxLiveErrorCondition) const _NOEXCEPT override;\n    };\n\n    /// <summary>\n    /// Gets the one global instance of the error code category.\n    /// </summary>\n    /// <returns>An error category instance.</returns>\n    _XSAPIIMP const xbox_services_error_code_category_impl& xbox_services_error_code_category();\n\n    /// <summary>\n    /// Gets the one global instance of the error condition category.\n    /// </summary>\n    /// <returns>An error category instance.</returns>\n    _XSAPIIMP const xbox_services_error_condition_category_impl& xbox_services_error_condition_category();\n     }\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n\nnamespace xbox {\n    namespace services\n    {\n        inline std::error_code make_error_code(xbl_error_code e)\n        {\n            return std::error_code(static_cast<int>(e), legacy::xbox_services_error_code_category());\n        }\n\n        inline std::error_condition make_error_condition(xbl_error_condition e)\n        {\n            return std::error_condition(static_cast<int>(e),  legacy::xbox_services_error_condition_category());\n        }\n    }\n}\n\nnamespace std\n{\n\ttemplate <>\n\tstruct is_error_code_enum<xbox::services::xbl_error_code> : public std::true_type {};\n\n\ttemplate <>\n\tstruct is_error_condition_enum<xbox::services::xbl_error_condition> : public std::true_type {};\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n\ntemplate<typename T>\nclass xbl_result\n{\n    public:\n    xbl_result();\n    xbl_result(_In_ T payload);\n    xbl_result(_In_ std::error_code errorCode, _In_ xsapi_internal_string errorMessage = xsapi_internal_string());\n    xbl_result(_In_ T payload, _In_ std::error_code errorCode, _In_ xsapi_internal_string errorMessage = xsapi_internal_string());\n\n    xbl_result(_In_ const xbl_result&);\n    xbl_result& operator=(_In_ const xbl_result&);\n    xbl_result(_In_ xbl_result&& other) noexcept;\n    xbl_result& operator=(_In_ xbl_result&& other) noexcept;\n\n    /// <summary>\n    /// The payload of the result.  It may be empty if there was an error\n    /// </summary>\n    T& payload();\n\n    /// <summary>\n    /// The payload of the result.  It may be empty if there was an error\n    /// </summary>\n    const T& payload() const;\n\n    /// <summary>\n    /// Sets the payload.\n    /// </summary>\n    void set_payload(T payload);\n\n    /// <summary>\n    /// The error returned by the operation.\n    /// To test for and potentially react to in your code, use the values in xbox_error_condition\n    /// To see the specific error value returned by the operation, use err_code().value() but testing for these values is discouraged.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition\n    /// </summary>\n    const std::error_code& err() const;\n\n    /// <summary>\n    /// Sets the error.\n    /// To test for and potentially react to in your code, use the values in xbox_error_condition\n    /// To see the specific error value returned by the operation, use err_code().value() but testing for these values is discouraged.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition\n    /// </summary>\n    void _Set_err(std::error_code errc);\n\n    /// <summary>\n    /// Returns call specific debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    const xsapi_internal_string& err_message() const;\n\n    /// <summary>\n    /// Sets error code debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    void _Set_err_message(xsapi_internal_string errMessage);\n\n    private:\n    T m_payload{};\n    std::error_code m_errorCode{};\n    xsapi_internal_string m_errorMessage;\n};\n\ntemplate<>\nclass xbl_result <void>\n{\n    public:\n    xbl_result()\n        : m_errorMessage(std::string())\n    {\n        //m_errorCode = std::make_error_code(xbl_error_code::no_error);\n        m_errorCode = make_error_code(xbl_error_code::no_error);\n    }\n\n    xbl_result(_In_ std::error_code errorCode, _In_ std::string errorMessage = std::string()) :\n        m_errorCode(std::move(errorCode)),\n        m_errorMessage(std::move(errorMessage))\n    {\n    }\n\n    xbl_result(_In_ const xbl_result& other)\n    {\n        *this = other;\n    }\n\n    xbl_result& operator=(_In_ const xbl_result& other)\n    {\n        m_errorCode = other.m_errorCode;\n        m_errorMessage = other.m_errorMessage;\n        return *this;\n    }\n\n    xbl_result(_In_ xbl_result&& other) noexcept\n    {\n        *this = std::move(other);\n    }\n\n    xbl_result& operator=(_In_ xbl_result&& other) noexcept\n    {\n        if (this != &other)\n        {\n            m_errorCode = std::move(other.m_errorCode);\n            m_errorMessage = std::move(other.m_errorMessage);\n        }\n\n        return *this;\n    }\n\n    /// <summary>\n    /// The error returned by the operation.\n    /// To test for and potentially react to in your code, use the values in xbox_error_condition\n    /// To see the specific error value returned by the operation, use err_code().value() but testing for these values is discouraged.\n    /// For more detail about std::error_code vs std::error_condition, see \n    /// http://en.cppreference.com/w/cpp/error/error_condition\n    /// </summary>\n    const std::error_code& err() const\n    {\n        return m_errorCode;\n    }\n\n    /// <summary>\n    /// Returns call specific debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    const std::string& err_message() const\n    {\n        return m_errorMessage;\n    }\n\n    /// <summary>\n    /// Returns call specific debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    void _Set_err(std::error_code errCode)\n    {\n        m_errorCode = std::move(errCode);\n    }\n\n    /// <summary>\n    /// Sets error code debug information.  \n    /// It is not localized, so only use for debugging purposes.\n    /// </summary>\n    void _Set_err_message(std::string errMessage)\n    {\n        m_errorMessage = std::move(errMessage);\n    }\n\n    private:\n    std::error_code m_errorCode;\n    std::string m_errorMessage;\n};\n\ntemplate<typename T>\nxbl_result<T>::xbl_result() :\n    m_errorMessage(xsapi_internal_string())\n{\n    m_errorCode = make_error_code(xbl_error_code::no_error);\n}\n\ntemplate<typename T>\nxbl_result<T>::xbl_result(_In_ T payload) :\n    m_payload(std::move(payload)),\n    m_errorMessage(xsapi_internal_string())\n{\n    m_errorCode = make_error_code(xbl_error_code::no_error);\n}\n\ntemplate<typename T>\nxbl_result<T>::xbl_result(\n    _In_ std::error_code errorCode,\n    _In_ xsapi_internal_string errorMessage\n) :\n    m_errorCode(std::move(errorCode)),\n    m_errorMessage(std::move(errorMessage))\n{\n}\n\ntemplate<typename T>\nxbl_result<T>::xbl_result(\n    _In_ T payload,\n    _In_ std::error_code errorCode,\n    _In_ xsapi_internal_string errorMessage\n) :\n    m_payload(std::move(payload)),\n    m_errorCode(std::move(errorCode)),\n    m_errorMessage(std::move(errorMessage))\n{\n}\n\ntemplate<typename T>\nT& xbl_result<T>::payload()\n{\n    return m_payload;\n}\n\ntemplate<typename T>\nconst T& xbl_result<T>::payload() const\n{\n    return m_payload;\n}\n\ntemplate<typename T>\nvoid xbl_result<T>::set_payload(T payload)\n{\n    m_payload = std::move(payload);\n}\n\ntemplate<typename T>\nconst std::error_code& xbl_result<T>::err() const\n{\n    return m_errorCode;\n}\n\ntemplate<typename T>\nvoid xbl_result<T>::_Set_err(std::error_code errCode)\n{\n    m_errorCode = std::move(errCode);\n}\n\ntemplate<typename T>\nconst xsapi_internal_string& xbl_result<T>::err_message() const\n{\n    return m_errorMessage;\n}\n\ntemplate<typename T>\nvoid xbl_result<T>::_Set_err_message(xsapi_internal_string errorMsg)\n{\n    m_errorMessage = std::move(errorMsg);\n}\n\ntemplate<typename T>\nxbl_result<T>::xbl_result(\n    _In_ const xbl_result& other\n) :\n    m_payload{ other.m_payload },\n    m_errorCode{ other.m_errorCode },\n    m_errorMessage{ other.m_errorMessage }\n{\n}\n\ntemplate<typename T>\nxbl_result<T>&\n    xbl_result<T>::operator=(_In_ const xbl_result& other)\n{\n    m_payload = other.m_payload;\n    m_errorCode = other.m_errorCode;\n    m_errorMessage = other.m_errorMessage;\n    return *this;\n}\n\ntemplate<typename T>\nxbl_result<T>::xbl_result(\n    _In_ xbl_result&& other\n) noexcept :\n    m_payload{ std::move(other.m_payload) },\n    m_errorCode{ other.m_errorCode },\n    m_errorMessage{ std::move(other.m_errorMessage) }\n{\n}\n\ntemplate<typename T>\nxbl_result<T>& xbl_result<T>::operator=(_In_ xbl_result&& other) noexcept\n{\n    if (this != &other)\n    {\n        m_payload = std::move(other.m_payload);\n        m_errorCode = std::move(other.m_errorCode);\n        m_errorMessage = std::move(other.m_errorMessage);\n    }\n\n    return *this;\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/fault_injection.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"fault_injection.h\"\n\n#if _DEBUG // fault injection only enabled on debug bits so as not to impact retail titles\nstatic fault_injection g_faultInjection; // not hanging this off of global state since it needs to keep between XblCleanups so long test runs are useful\n#endif\n\nSTDAPI_(void) XblEnableFaultInjection(_In_ uint64_t featureId) XBL_NOEXCEPT\ntry\n{\n#if _DEBUG // fault injection only enabled on debug bits so as not to impact retail titles\n    g_faultInjection.m_enabledFeatureMask |= featureId;\n#else \n    UNREFERENCED_PARAMETER(featureId);\n#endif\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(uint64_t) XblGetFaultCounter() XBL_NOEXCEPT\ntry\n{\n#if _DEBUG // testing feature only enabled on debug bits so as not to impact retail titles\n    return g_faultInjection.m_failTotalCounter;\n#else\n    return 0;\n#endif\n}\nCATCH_RETURN_WITH(0)\n\nSTDAPI_(void) XblSetFaultInjectOptions(int64_t failFreq, uint64_t freqChangeSpeed, int64_t freqChangeAmount) XBL_NOEXCEPT\ntry\n{\n#if _DEBUG // testing feature only enabled on debug bits so as not to impact retail titles\n    g_faultInjection.m_failFreq = failFreq;\n    g_faultInjection.m_freqChangeSpeed = freqChangeSpeed;\n    g_faultInjection.m_freqChangeAmount = freqChangeAmount;\n#else \n    UNREFERENCED_PARAMETER(failFreq);\n    UNREFERENCED_PARAMETER(freqChangeSpeed);\n    UNREFERENCED_PARAMETER(freqChangeAmount);\n#endif\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI_(bool) XblShouldFaultInject(_In_ uint64_t featureId) XBL_NOEXCEPT\ntry\n{\n#if _DEBUG // testing feature only enabled on debug bits so as not to impact retail titles\n    if ((g_faultInjection.m_enabledFeatureMask & featureId) == featureId)\n    {\n        g_faultInjection.m_freqChangeCounter++;\n        g_faultInjection.m_freqChangeCounter %= g_faultInjection.m_freqChangeSpeed;\n        if (g_faultInjection.m_freqChangeCounter == 0)\n        {\n            // Alter the fail freq every so often so it doesn't just fall into testing a repeated calling pattern\n            g_faultInjection.m_failFreq += g_faultInjection.m_freqChangeAmount;\n            g_faultInjection.m_failFreq = std::max<int64_t>(0, g_faultInjection.m_failFreq);\n        }\n\n        g_faultInjection.m_failTotalCounter++;\n        g_faultInjection.m_failCounter++;\n        g_faultInjection.m_failCounter %= g_faultInjection.m_failFreq;\n        return (g_faultInjection.m_failCounter == 0);\n    }\n#else\n    UNREFERENCED_PARAMETER(featureId);\n#endif\n\n    return false;\n}\nCATCH_RETURN()\n\n"
  },
  {
    "path": "Source/Shared/fault_injection.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\n#define INJECTION_FEATURE_USER 0x0001\n#define INJECTION_FEATURE_HTTP 0x0002\n\nextern \"C\"\n{\nSTDAPI_(void) XblEnableFaultInjection(_In_ uint64_t featureId) XBL_NOEXCEPT;\nSTDAPI_(bool) XblShouldFaultInject(_In_ uint64_t featureId) XBL_NOEXCEPT;\nSTDAPI_(uint64_t) XblGetFaultCounter() XBL_NOEXCEPT;\nSTDAPI_(void) XblSetFaultInjectOptions(int64_t failFreq, uint64_t freqChangeSpeed, int64_t freqChangeAmount) XBL_NOEXCEPT;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nstruct fault_injection\n{\n    uint64_t m_enabledFeatureMask{ 0 };\n    uint64_t m_failCounter{ 0 };\n    uint64_t m_failTotalCounter{ 0 };\n    int64_t m_failFreq{ 3 };\n\n    // Alter the fail freq every so often so it doesn't just fall into testing a repeated calling pattern\n    uint64_t m_freqChangeCounter{ 0 };\n    uint64_t m_freqChangeSpeed{ 7 };\n    int64_t m_freqChangeAmount{ 1 };\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/global_state.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"global_state.h\"\n#include \"Achievements/Manager/achievements_manager_internal.h\"\n#include \"multiplayer_manager_internal.h\"\n#include \"social_manager_internal.h\"\n#include \"real_time_activity_manager.h\"\n#include \"Logger/log_hc_output.h\"\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"a/utils_a.h\"\n#include \"a/java_interop.h\"\n#endif\n\nHC_DEFINE_TRACE_AREA(XSAPI, HCTraceLevel::Verbose);\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// Local Storage in Android is dependent on the JNI Initialization done in GlobalState::Create\n// Only on Android the initialization of m_localStorage is done outside of the constructor.\nGlobalState::GlobalState(\n    _In_ const XblInitArgs* args\n) :\n    m_taskQueue{ args ? TaskQueue::DeriveWorkerQueue(args->queue) : nullptr },\n    m_achievementsManager{ MakeShared<achievements::manager::AchievementsManager>() },\n    m_multiplayerManager{ MakeShared<multiplayer::manager::MultiplayerManager>() },\n    m_socialManager{ MakeShared<social::manager::SocialManager>() },\n    m_rtaManager{ MakeShared<real_time_activity::RealTimeActivityManager>(m_taskQueue) },\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n    m_localStorage{ MakeShared<system::LocalStorage>(m_taskQueue) },\n#endif\n    m_appConfig{ MakeShared<xbox::services::AppConfig>() },\n    m_logger{ MakeShared<logger>() }\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    HCTraceSetEtwEnabled(true);\n#endif\n    m_logger->add_log_output(MakeShared<log_hc_output>());\n\n#if _DEBUG && defined(XSAPI_UNIT_TESTS) && XSAPI_PROFILE\n    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);\n#endif\n}\n\nHRESULT GlobalState::Create(\n    _In_ const XblInitArgs* args\n)\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args);\n\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP)\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args->scid);\n    RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(args->scid);\n#endif\n\n    XTaskQueueHandle processQueue{ nullptr };\n    bool haveProcessQueue = XTaskQueueGetCurrentProcessTaskQueue(&processQueue);\n    if (!haveProcessQueue && args->queue == nullptr)\n    {\n        return E_NO_TASK_QUEUE;\n    }\n\n    if (AccessHelper(AccessMode::GET))\n    {\n        return E_XBL_ALREADY_INITIALIZED;\n    }\n\n    // Global state depends on libHttpClient state so call HCInitialize before creating our state.\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    HCInitArgs hcArgs{};\n    hcArgs.javaVM = args->javaVM;\n    hcArgs.applicationContext = args->applicationContext;\n    RETURN_HR_IF_FAILED(HCInitialize(&hcArgs));\n#else\n    RETURN_HR_IF_FAILED(HCInitialize(nullptr));\n#endif\n\n    auto state = std::shared_ptr<GlobalState>(\n        new (Alloc(sizeof(GlobalState))) GlobalState(args),\n        Deleter<GlobalState>(),\n        Allocator<GlobalState>()\n    );\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    // TODO Should make the java interop singleton a member of GlobalState rather than a separate static\n    auto javaInteropInitResult = xbox::services::java_interop::get_java_interop_singleton()->initialize(\n        args->javaVM,\n        args->applicationContext\n    );\n    if (javaInteropInitResult.err())\n    {\n        return utils::convert_xbox_live_error_code_to_hresult(javaInteropInitResult.err());\n    }\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    // Local Storage in Android is dependent on the JNI Initialization so create LocalStorage now.\n    state->m_localStorage = MakeShared<system::LocalStorage>(state->m_taskQueue);\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    // On Win32, set Local Storage path using init args\n    RETURN_HR_IF_FAILED(state->m_localStorage->SetStoragePath(args->localStoragePath));\n#endif\n\n#if HC_PLATFORM != HC_PLATFORM_XDK && HC_PLATFORM != HC_PLATFORM_UWP\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(args->scid);\n    RETURN_HR_IF_FAILED(state->m_appConfig->Initialize(args->scid));\n#else\n    RETURN_HR_IF_FAILED(state->m_appConfig->Initialize());\n#endif\n\n#if HC_PLATFORM_IS_EXTERNAL\n    state->m_appConfig->SetAppId(args->appId);\n    state->m_appConfig->SetAppVer(args->appVer);\n    state->m_appConfig->SetOsName(args->osName);\n    state->m_appConfig->SetOsVersion(args->osVersion);\n    state->m_appConfig->SetOsLocale(args->osLocale);\n    state->m_appConfig->SetDeviceClass(args->deviceClass);\n    state->m_appConfig->SetDeviceId(args->deviceId);\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n    if (args->apnsEnvironment)\n    {\n        state->m_appConfig->SetAPNSEnvironment(args->apnsEnvironment);\n    }\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    // Initialize achievements provider properties\n    RETURN_HR_IF_FAILED(CoCreateGuid(&state->m_achievementsSessionId));\n\n    CHAR strTitleId[16] = \"\";\n    sprintf_s(strTitleId, \"%0.8X\", state->m_appConfig->TitleId());\n\n    Stringstream achievementsProviderName;\n    achievementsProviderName << \"XSAPI_\" << strTitleId;\n    state->m_achivementsEventProviderName = achievementsProviderName.str();\n#endif\n\n    state->m_locales = utils::generate_locales();\n\n    // GlobalState object has been created and initialized successfully at this point so store it.\n    (void)AccessHelper(AccessMode::SET, state);\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    RegisterAppStateChangeNotification(AppStateChangeNotificationReceived, nullptr, &state->m_registrationID);\n#endif\n\n    // Leak a ref until Cleanup is called\n    state->AddRef();\n\n    return S_OK;\n}\n\nstruct HCCleanupContext\n{\n    XAsyncBlock* xblCleanupAsyncBlock;\n    TaskQueue hcCleanupQueue;\n    XAsyncBlock hcCleanupAsyncBlock;\n};\n\nHRESULT GlobalState::CleanupAsync(\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    auto state{ AccessHelper(AccessMode::SET, nullptr) };\n    if (!state)\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    // In case of GDK, make sure to unregister from App Change Notifications before disconnecting\n    UnregisterAppStateChangeNotification(state->m_registrationID);\n#endif\n\n    return XAsyncBegin(\n        async,\n        state.get(),\n        reinterpret_cast<void*>(CleanupAsync),\n        __FUNCTION__,\n        [](XAsyncOp op, const XAsyncProviderData* data)\n    {\n\n        switch(op)\n        {\n        case XAsyncOp::Begin:\n        {\n            return XAsyncSchedule(data->async, 0);\n        }\n        case XAsyncOp::DoWork:\n        {\n            //Limit shared_ptr scope so that it never lives beyond the XTaskQueueTerminate callback,\n            //even if XTaskQueueTerminate completes synchronously. This ensures the call to DecRef\n            //in the callback releases the last remaining reference.\n            XTaskQueueHandle stateTaskQueueHandle;\n            {\n                // Create a shared_ptr to the state so we can track the use_count here\n                auto state{ static_cast<GlobalState*>(data->context)->shared_from_this() };\n\n                stateTaskQueueHandle = state->Queue().GetHandle();\n\n                // Wait for all other references to the GlobalState to go away.\n                // Note that the use count check here is only valid because we never create\n                // a weak_ptr to the singleton. If we did that could cause the use count\n                // to increase even though we are the only strong reference\n                if (state.use_count() > 2)\n                {\n                    // Wait for async tasks which require the GlobalState to finish.\n                    RETURN_HR_IF_FAILED(XAsyncSchedule(data->async, 10));\n                    return E_PENDING;\n                }\n\n#ifdef XSAPI_UNIT_TESTS\n                // As a sanity check, ensure there aren't other references to RTA manager.\n                // Don't always block on this - unclosed XblContexts would then prevent XblCleanup from completing.\n                auto rtaManagerUseCount{ state->m_rtaManager.use_count() };\n                if (rtaManagerUseCount > 1)\n                {\n                    HC_TRACE_VERBOSE(XSAPI, \"RTAManager still in use (use_count=%d)\", rtaManagerUseCount);\n                    RETURN_HR_IF_FAILED(XAsyncSchedule(data->async, 10));\n                    return E_PENDING;\n                }\n#if TRACK_ASYNC\n                // Wait for any outstanding XAsync operations to be cleaned up. XAsync makes no guarantee \n                // that XAsyncOp::Cleanup will be called & completed before prior to signaling to the client that the\n                // operation has completed. This leads to a race condition where titles could be told XblCleanupAsync\n                // has finished while we still have XAsync provider contexts that need to be cleaned up. We don't want\n                // to always block on this since XAsync operations whose result is never consumed by the client would\n                // stop XblCleanupAsync from ever returning.\n                {\n                    std::lock_guard<std::mutex> lock{ state->asyncBlocksMutex };\n                    if (!state->asyncBlocks.empty())\n                    {\n                        Stringstream ss;\n                        ss << \"Awaiting outstanding XAsync operations:\";\n                        for (auto& pair : state->asyncBlocks)\n                        {\n                            ss << \"\\nXAsyncBlock[\" << pair.first << \"] Identity=\" << pair.second;\n                        }\n\n                        HC_TRACE_VERBOSE(XSAPI, ss.str().data());\n                        RETURN_HR_IF_FAILED(XAsyncSchedule(data->async, 10));\n                        return E_PENDING;\n                    }\n                }\n#endif // TRACK_ASYNC\n#endif // XSAPI_UNIT_TESTS\n\n                // Cleanup RTA state and open connections\n                state->m_rtaManager->Cleanup();\n            }\n\n            // Terminate all pending/running async tasks on the global background queue.\n            // We don't use TaskQueue::Terminate here because control will return to the client before\n            // the Callback is cleaned up, giving them freedom to clean up custom memory hooks.\n            auto hr = XTaskQueueTerminate(stateTaskQueueHandle, false, const_cast<XAsyncProviderData*>(data), [](void* context)\n            {\n                HC_TRACE_VERBOSE(XSAPI, \"Cleaning up GlobalState\");\n\n                auto data{ static_cast<const XAsyncProviderData*>(context) };\n                auto state{ static_cast<GlobalState*>(data->context) };\n\n#if TRACK_ASYNC\n                {\n                    // Log warning for unfinished async operations\n                    std::lock_guard<std::mutex> lock{ state->asyncBlocksMutex };\n                    for (auto& pair : state->asyncBlocks)\n                    {\n                        HC_TRACE_WARNING(XSAPI, \"Unfinished XAsyncBlock[%llu], Identity=%s\", pair.first, pair.second);\n                    }\n                }\n#endif\n\n                // Release the leaked reference from Create\n                state->DecRef();\n\n                // Don't call HCCleanup until after GlobalState is destroyed since some of our state\n                // depends on HC state.\n                auto hcCleanupContext = MakeUnique<HCCleanupContext>();\n                hcCleanupContext->xblCleanupAsyncBlock = data->async;\n                hcCleanupContext->hcCleanupQueue = TaskQueue::DeriveWorkerQueue(data->async->queue);\n                hcCleanupContext->hcCleanupAsyncBlock.queue = hcCleanupContext->hcCleanupQueue.GetHandle();\n                hcCleanupContext->hcCleanupAsyncBlock.context = hcCleanupContext.get();\n                hcCleanupContext->hcCleanupAsyncBlock.callback = GlobalState::HCCleanupComplete;\n\n                HRESULT hr = HCCleanupAsync(&hcCleanupContext->hcCleanupAsyncBlock);\n                if (FAILED(hr))\n                {\n                    HC_TRACE_ERROR_HR(XSAPI, hr, \"HCCleanupAsync Failed\");\n                    XAsyncComplete(data->async, hr, 0);\n                }\n\n                hcCleanupContext.release();\n            });\n\n            RETURN_HR_IF_FAILED(hr);\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\n\nvoid GlobalState::HCCleanupComplete(XAsyncBlock* async) noexcept\n{\n    UniquePtr<HCCleanupContext> context{ static_cast<HCCleanupContext*>(async->context) };\n    \n    XAsyncBlock* xblCleanupAsyncBlock = context->xblCleanupAsyncBlock;\n    HRESULT hr = XAsyncGetStatus(async, true);\n    if (hr == E_HC_INTERNAL_STILLINUSE)\n    {\n        // If something else is still referencing libHttpClient, consider that a success\n        hr = S_OK;\n    }\n    context.reset(); // Cleanup context before returning to caller\n\n    XAsyncComplete(xblCleanupAsyncBlock, hr, 0);\n}\n\nstd::shared_ptr<GlobalState> GlobalState::Get() noexcept\n{\n    return AccessHelper(AccessMode::GET);\n}\n\nstd::shared_ptr<GlobalState> GlobalState::AccessHelper(\n    _In_ AccessMode mode,\n    _In_opt_ std::shared_ptr<GlobalState> state\n) noexcept\n{\n    static std::mutex s_mutex;\n    static std::shared_ptr<GlobalState> s_state{ nullptr };\n\n    std::lock_guard<std::mutex> lock{ s_mutex };\n\n    switch (mode)\n    {\n    case AccessMode::GET:\n    {\n        assert(!state);\n        return s_state;\n    }\n\n    case AccessMode::SET:\n    {\n        auto previousValue{ s_state };\n        s_state = state;\n        return previousValue;\n    }\n    }\n\n    return nullptr;\n}\n\nconst TaskQueue& GlobalState::Queue() const noexcept\n{\n    return m_taskQueue;\n}\n\nstd::shared_ptr<multiplayer::manager::MultiplayerManager> GlobalState::MultiplayerManager() const noexcept\n{\n    return m_multiplayerManager;\n}\n\nstd::shared_ptr<social::manager::SocialManager> GlobalState::SocialManager() const noexcept\n{\n    return m_socialManager;\n}\n\nstd::shared_ptr<achievements::manager::AchievementsManager> GlobalState::AchievementsManager() const noexcept\n{\n    return m_achievementsManager;\n}\n\nstd::shared_ptr<real_time_activity::RealTimeActivityManager> GlobalState::RTAManager() const noexcept\n{\n    return m_rtaManager;\n}\n\nvoid GlobalState::SetUserChangeHandler(uint64_t token, std::shared_ptr<UserChangeEventHandler> context) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_userChangeHandlers[token] = context;\n}\n\nsize_t GlobalState::EraseUserChangeHandler(uint64_t token) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    return m_userChangeHandlers.erase(token);\n}\n\nsize_t GlobalState::EraseUserExpiredToken(uint64_t xuid) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    return m_userExpiredTokens.erase(xuid);\n}\n\nvoid GlobalState::InsertUserExpiredToken(uint64_t xuid) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_userExpiredTokens.insert(xuid);\n}\n\nXblFunctionContext GlobalState::AddServiceCallRoutedHandler(\n    _In_ XblCallRoutedHandler callback,\n    _In_opt_ void* context\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n \n    m_callRoutedHandlers.emplace(m_nextHandlerToken, MakeShared<ServiceCallRoutedHandler>(callback, context));\n    return m_nextHandlerToken++;\n}\n\nvoid GlobalState::RemoveServiceCallRoutedHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_callRoutedHandlers.erase(token);\n}\n\nstd::shared_ptr<system::LocalStorage> GlobalState::LocalStorage() const noexcept\n{\n    return m_localStorage;\n}\n\nstd::shared_ptr<xbox::services::AppConfig> GlobalState::AppConfig() const noexcept\n{\n    return m_appConfig;\n}\n\nstd::shared_ptr<logger> GlobalState::Logger() const noexcept\n{\n    return m_logger;\n}\n\nstd::shared_ptr<RefCounter> GlobalState::GetSharedThis()\n{\n    return shared_from_this();\n}\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n\nXblFunctionContext GlobalState::AddAppChangeNotificationHandler(\n    _In_ AppChangeNotificationHandler appChangeNotificationHandler\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_appChangeNotificationHandlers.emplace(m_nextAppChangeHandlerToken, appChangeNotificationHandler);\n    return m_nextAppChangeHandlerToken++;\n}\n\n/* static */ void GlobalState::AppStateChangeNotificationReceived(\n    BOOLEAN quiesced,\n    PVOID context\n)\n{\n    UNREFERENCED_PARAMETER(context);\n    auto state{ GlobalState::Get() };\n\n    if (state)\n    {\n        // Before moving to the handlers, we need to unlock the mutex or run into a deadlock inside\n        // the erase_token_and_signature function. For now, copying the handlers locally and unlocking\n        std::unique_lock<std::mutex> lock{ state->m_mutex };\n        auto localAppChangeNotificationHandlers = state->m_appChangeNotificationHandlers;\n\n        lock.unlock();\n        for (const auto& pair : localAppChangeNotificationHandlers)\n        {\n            auto handler = pair.second;\n            handler(quiesced);\n        }\n    }\n}\n\nvoid GlobalState::RemoveAppChangeNotificationHandler(\n    _In_ XblFunctionContext token\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_appChangeNotificationHandlers.erase(token);\n}\n\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\nconst String& GlobalState::AchievementsProviderName() const noexcept\n{\n    return m_achivementsEventProviderName;\n}\n\nconst GUID& GlobalState::AchievementsSessionId() const noexcept\n{\n    return m_achievementsSessionId;\n}\n#endif\n\nconst String& GlobalState::Locales() const noexcept\n{\n    return m_locales;\n}\n\nvoid GlobalState::OverrideLocale(const xsapi_internal_string& locale) noexcept\n{\n    m_locales = utils::generate_locales(locale);\n}\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/global_state.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"service_call_routed_handler.h\"\n#include \"local_storage.h\"\n#include \"fault_injection.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include <appnotify.h>\n#endif\n\n// When TRACK_ASYNC is enabled, we will monitor the progress of each XAsync operation, asserting\n// if tasks are started or outstanding when XblCleanup completes. By default only do async tracking\n// for UnitTests, but it can be enabled for debugging in other situations as well.\n#define TRACK_ASYNC XSAPI_UNIT_TESTS\n\n// Forward declarations\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_BEGIN\n    class AchievementsManager;\nNAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_END\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN\n    class MultiplayerManager;\nNAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN\n    class SocialManager;\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN\n    class RealTimeActivityManager;\nNAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\ntypedef Function<void(bool isSuspended)> AppChangeNotificationHandler;\n#endif\n\nclass GlobalState : public RefCounter, public std::enable_shared_from_this<GlobalState>\n{\npublic:\n    virtual ~GlobalState() noexcept = default;\n\n    static HRESULT Create(_In_ const XblInitArgs* args);\n    static HRESULT CleanupAsync(_In_ XAsyncBlock* async) noexcept;\n    static std::shared_ptr<GlobalState> Get() noexcept;\n\n    const TaskQueue& Queue() const noexcept;\n\n    std::shared_ptr<achievements::manager::AchievementsManager> AchievementsManager() const noexcept;\n    std::shared_ptr<multiplayer::manager::MultiplayerManager> MultiplayerManager() const noexcept;\n    std::shared_ptr<social::manager::SocialManager> SocialManager() const noexcept;\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> RTAManager() const noexcept;\n\n    void SetUserChangeHandler(uint64_t token, std::shared_ptr<UserChangeEventHandler> context) noexcept;\n    size_t EraseUserChangeHandler(uint64_t token) noexcept;\n\n    size_t EraseUserExpiredToken(uint64_t xuid) noexcept;\n    void InsertUserExpiredToken(uint64_t xuid) noexcept;\n\n    XblFunctionContext AddServiceCallRoutedHandler(\n        _In_ XblCallRoutedHandler handler,\n        _In_opt_ void* context\n    ) noexcept;\n\n    void RemoveServiceCallRoutedHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n\n    std::shared_ptr<system::LocalStorage> LocalStorage() const noexcept;\n\n    std::shared_ptr<AppConfig> AppConfig() const noexcept;\n\n    std::shared_ptr<logger> Logger() const noexcept;\n \n#if HC_PLATFORM == HC_PLATFORM_GDK\n    XblFunctionContext AddAppChangeNotificationHandler(\n        _In_ AppChangeNotificationHandler routine\n    ) noexcept;\n\n    void RemoveAppChangeNotificationHandler(\n        _In_ XblFunctionContext token\n    ) noexcept;\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    // On XDK, offline achievements are driven by ETX. \n    // The AchievementsService will create one ETX provider per XSAPI session (when needed) using these properties.\n    const String& AchievementsProviderName() const noexcept;\n    const GUID& AchievementsSessionId() const noexcept;\n#endif\n\n    const String& Locales() const noexcept;\n    void OverrideLocale(const xsapi_internal_string& locales) noexcept;\n\n    // API Type to be used in HTTP requests so they are identifiable in traces.\n    // TODO consider configuring this with XblInitArgs\n    XblApiType ApiType{ XblApiType::XblCApi };\n\n#if TRACK_ASYNC\n    std::mutex asyncBlocksMutex{};\n    UnorderedMap<XAsyncBlock*, const char*> asyncBlocks{};\n#endif\n\nprivate:\n    GlobalState(_In_ const XblInitArgs* args);\n    GlobalState(const GlobalState&) = delete;\n    GlobalState& operator=(const GlobalState&) = delete;\n\n    static void CALLBACK HCCleanupComplete(XAsyncBlock* async) noexcept;\n\n    mutable std::mutex m_mutex;\n    TaskQueue m_taskQueue{ nullptr };\n    std::shared_ptr<achievements::manager::AchievementsManager> m_achievementsManager;\n    std::shared_ptr<multiplayer::manager::MultiplayerManager> m_multiplayerManager;\n    std::shared_ptr<social::manager::SocialManager> m_socialManager;\n    std::shared_ptr<real_time_activity::RealTimeActivityManager> m_rtaManager;\n    std::shared_ptr<system::LocalStorage> m_localStorage;\n    Set<uint64_t> m_userExpiredTokens;\n\n    UnorderedMap<uint64_t, std::shared_ptr<UserChangeEventHandler>> m_userChangeHandlers;\n    XblFunctionContext m_nextHandlerToken{ 1 };\n    UnorderedMap<XblFunctionContext, std::shared_ptr<ServiceCallRoutedHandler>> m_callRoutedHandlers;\n\n    String m_locales{ \"en-US\" };\n\n    // from Shared\\xbox_live_app_config.cpp\n    const std::shared_ptr<xbox::services::AppConfig> m_appConfig;\n\n    // from Shared\\Logger\\log.cpp\n    const std::shared_ptr<logger> m_logger;\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\n    String m_achivementsEventProviderName;\n    GUID m_achievementsSessionId{};\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    XblFunctionContext m_nextAppChangeHandlerToken{ 1 };\n    xsapi_internal_unordered_map<XblFunctionContext, AppChangeNotificationHandler> m_appChangeNotificationHandlers;\n#endif\n\n    enum class AccessMode\n    {\n        GET,\n        SET,\n    };\n\n    // In order to avoid uncertainty of global static initialization order, keep the static state pointer to a function scope\n    static std::shared_ptr<GlobalState> AccessHelper(\n        _In_ AccessMode mode,\n        _In_opt_ std::shared_ptr<GlobalState> state = nullptr\n    ) noexcept;\n\n    // RefCounter\n    std::shared_ptr<RefCounter> GetSharedThis() override;\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    // Holds the registration ID for receiving App State Notifications (aka Quick Resume)\n    PAPPSTATE_REGISTRATION m_registrationID;\n\n    static void AppStateChangeNotificationReceived(\n        BOOLEAN quiesced,\n        PVOID context\n    );\n#endif\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/http_call_api.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi_utils.h\"\n#include \"xbox_live_context_internal.h\"\n#include \"xsapi-c/http_call_c.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\n// Http APIs\nSTDAPI XblHttpCallCreate(\n    _In_ XblContextHandle xblContext,\n    _In_z_ const char* method,\n    _In_z_ const char* url,\n    _Out_ XblHttpCallHandle* call\n) XBL_NOEXCEPT\ntry\n{\n    VERIFY_XBL_INITIALIZED();\n\n    auto userResult = xblContext->User().Copy();\n    RETURN_HR_IF_FAILED(userResult.Hresult());\n\n    auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());\n    HRESULT hr = httpCall->Init(xblContext->Settings(), method, url, xbox_live_api::unspecified);\n    if (SUCCEEDED(hr)) \n    {\n        httpCall->AddRef();\n        *call = httpCall.get();\n    }\n    return hr;\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallPerformAsync(\n    _In_ XblHttpCallHandle call,\n    _In_ XblHttpCallResponseBodyType type,\n    _Inout_ XAsyncBlock* asyncBlock\n) XBL_NOEXCEPT\ntry\n{\n    UNREFERENCED_PARAMETER(type);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    VERIFY_XBL_INITIALIZED();\n\n    return RunAsync(asyncBlock, __FUNCTION__,\n        [\n            call{ std::dynamic_pointer_cast<XblHttpCall>(call->shared_from_this()) }\n        ]\n    (XAsyncOp op, const XAsyncProviderData* data)\n    {\n        switch (op)\n        {\n        case XAsyncOp::DoWork:\n        {\n            RETURN_HR_IF_FAILED(call->Perform(AsyncContext<HttpResult>{ TaskQueue::DeriveWorkerQueue(data->async->queue),\n                [data](HttpResult httpResult)\n            {\n                auto hr = httpResult.Hresult();\n                if (SUCCEEDED(hr))\n                {\n                    hr = httpResult.Payload()->Result();\n                }\n                XAsyncComplete(data->async, hr, 0);\n            }\n            }));\n            return E_PENDING;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    });\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallDuplicateHandle(\n    _In_ XblHttpCallHandle call,\n    _Out_ XblHttpCallHandle* duplicatedHandle\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF(call == nullptr || duplicatedHandle == nullptr);\n    call->AddRef();\n    *duplicatedHandle = call;\n\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI_(void) XblHttpCallCloseHandle(\n    _In_ XblHttpCallHandle call\n) XBL_NOEXCEPT\ntry\n{\n    if (call)\n    {\n        call->DecRef();\n    }\n    return;\n}\nCATCH_RETURN_WITH(;)\n\nSTDAPI XblHttpCallSetTracing(\n    _In_ XblHttpCallHandle call,\n    _In_ bool traceCall\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n\n    return call->SetTracing(traceCall);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetRequestUrl(\n    _In_ XblHttpCallHandle call,\n    _Out_ const char** url\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(url);\n\n    return call->GetRequestUrl(url);\n}\nCATCH_RETURN()\n\n// HttpCallRequest Set APIs\nSTDAPI XblHttpCallRequestSetRequestBodyBytes(\n    _In_ XblHttpCallHandle call,\n    _In_reads_bytes_(requestBodySize) const uint8_t* requestBodyBytes,\n    _In_ uint32_t requestBodySize\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->SetRequestBody(requestBodyBytes, requestBodySize);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallRequestSetRequestBodyString(\n    _In_ XblHttpCallHandle call,\n    _In_z_ const char* requestBodyString\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->SetRequestBody(requestBodyString);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallRequestSetHeader(\n    _In_ XblHttpCallHandle call,\n    _In_z_ const char* headerName,\n    _In_z_ const char* headerValue,\n    _In_ bool allowTracing\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(headerName);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(headerValue);\n    const xsapi_internal_string headerNameString{ headerName };\n    const xsapi_internal_string headerValueString{ headerValue };\n\n    return call->SetHeader(headerNameString, headerValueString, allowTracing);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallRequestSetRetryAllowed(\n    _In_ XblHttpCallHandle call,\n    _In_ bool retryAllowed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n\n    return call->SetRetryAllowed(retryAllowed);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallRequestSetRetryCacheId(\n    _In_ XblHttpCallHandle call,\n    _In_ uint32_t retryAfterCacheId\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n\n    // values 1-1000 are reserved for XSAPI\n    if (retryAfterCacheId <= 1000)\n    {\n        return E_INVALIDARG;\n    }\n\n    return call->SetRetryCacheId(retryAfterCacheId);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallRequestSetLongHttpCall(\n    _In_ XblHttpCallHandle call,\n    _In_ bool longHttpCall\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n\n    call->SetLongHttpCall(longHttpCall);\n    return S_OK;\n}\nCATCH_RETURN()\n\n// HttpCallResponse Get APIs\nSTDAPI XblHttpCallGetResponseString(\n    _In_ XblHttpCallHandle call,\n    _Out_ const char** responseString\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->GetResponseString(responseString);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetResponseBodyBytesSize(\n    _In_ XblHttpCallHandle call,\n    _Out_ size_t* bufferSize\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->GetResponseBodyBytesSize(bufferSize);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetResponseBodyBytes(\n    _In_ XblHttpCallHandle call,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) uint8_t* buffer,\n    _Out_opt_ size_t* bufferUsed\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->GetResponseBodyBytes(bufferSize, buffer, bufferUsed);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetStatusCode(\n    _In_ XblHttpCallHandle call,\n    _Out_ uint32_t* statusCode\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(statusCode);\n\n    *statusCode = call->HttpStatus();\n    return S_OK;\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetNetworkErrorCode(\n    _In_ XblHttpCallHandle call,\n    _Out_ HRESULT* networkErrorCode,\n    _Out_ uint32_t* platformNetworkErrorCode\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->GetNetworkErrorCode(networkErrorCode, platformNetworkErrorCode);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetPlatformNetworkErrorMessage(\n    _In_ XblHttpCallHandle call,\n    _Out_ const char** platformNetworkErrorMessage\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->GetPlatformNetworkErrorMessage(platformNetworkErrorMessage);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetHeader(\n    _In_ XblHttpCallHandle call,\n    _In_z_ const char* headerName,\n    _Out_ const char** headerValue\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->ResponseGetHeader(headerName, headerValue);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetNumHeaders(\n    _In_ XblHttpCallHandle call,\n    _Out_ uint32_t* numHeaders\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->ResponseGetNumHeaders(numHeaders);\n}\nCATCH_RETURN()\n\nSTDAPI XblHttpCallGetHeaderAtIndex(\n    _In_ XblHttpCallHandle call,\n    _In_ uint32_t headerIndex,\n    _Out_ const char** headerName,\n    _Out_ const char** headerValue\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(call);\n    return call->ResponseGetHeaderAtIndex(headerIndex, headerName, headerValue);\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Source/Shared/http_call_legacy.cpp",
    "content": "#include \"pch.h\"\n\n#include \"http_call_legacy.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace legacy\n{\n\nhttp_call_response::http_call_response(\n    _In_ XblHttpCallHandle call,\n    _In_ XblHttpCallResponseBodyType type\n)\n{\n    XblHttpCallDuplicateHandle(call, &m_handle);\n    m_bodyType = static_cast<http_call_response_body_type>(type);\n}\n\nhttp_call_response_body_type http_call_response::body_type() const\n{\n    return m_bodyType;\n}\n\nstring_t http_call_response::response_body_string()\n{\n    if (m_responseBodyString != string_t())\n    {\n        return m_responseBodyString;\n    }\n\n    const char* responseString;\n    HRESULT hr = XblHttpCallGetResponseString(m_handle, &responseString);\n    if (FAILED(hr))\n    {\n        return string_t();\n    }\n\n    m_responseBodyString = StringTFromUtf8(responseString);\n    return m_responseBodyString;\n}\n\nweb::json::value http_call_response::response_body_json()\n{\n    auto str = response_body_string();\n    m_responseBodyJson = web::json::value::parse(str);\n    return m_responseBodyJson;\n}\n\nstd::vector<unsigned char> http_call_response::response_body_vector()\n{\n    if (!m_responseBodyVector.empty())\n    {\n        return m_responseBodyVector;\n    }\n\n    size_t bufferSize;\n    HRESULT hr = XblHttpCallGetResponseBodyBytesSize(m_handle, &bufferSize);\n    if (FAILED(hr))\n    {\n        return {};\n    }\n\n    uint8_t* buffer = new uint8_t[bufferSize];\n    size_t bufferUsed;\n    hr = XblHttpCallGetResponseBodyBytes(m_handle, bufferSize, buffer, &bufferUsed);\n    if (FAILED(hr))\n    {\n        return {};\n    }\n\n    auto bufferInput = std::vector<uint8_t>(buffer, buffer + bufferUsed);\n    m_responseBodyVector = std::vector<unsigned char>(bufferUsed);\n    std::transform(bufferInput.begin(), bufferInput.end(), m_responseBodyVector.begin(),\n        [](uint8_t c)\n        {\n            return static_cast<unsigned char>(c);\n        });\n\n    return m_responseBodyVector;\n}\n\nweb::http::http_headers http_call_response::response_headers()\n{\n    if (!m_responseHeaders.empty())\n    {\n        return m_responseHeaders;\n    }\n\n    uint32_t numHeader;\n    HRESULT hr = XblHttpCallGetNumHeaders(m_handle, &numHeader);\n    if (FAILED(hr))\n    {\n        return web::http::http_headers();\n    }\n\n    const char* headerName;\n    const char* headerValue;\n    auto headers = web::http::http_headers();\n    for (auto i = 0u; i < numHeader; i++)\n    {\n        hr = XblHttpCallGetHeaderAtIndex(m_handle, i, &headerName, &headerValue);\n        if (SUCCEEDED(hr))\n        {\n            headers.add(StringTFromUtf8(headerName), StringTFromUtf8(headerValue));\n        }\n    }\n\n    m_responseHeaders = headers;\n    return headers;\n}\n\nuint32_t http_call_response::http_status()\n{\n    uint32_t statusCode;\n    HRESULT hr = XblHttpCallGetStatusCode(m_handle, &statusCode);\n    if (FAILED(hr))\n    {\n        return 0;\n    }\n\n    m_httpStatus = statusCode;\n    return m_httpStatus;\n}\n\nstd::error_code http_call_response::err_code()\n{\n    if (m_errorCode == std::error_code())\n    {\n        return m_errorCode;\n    }\n\n    HRESULT networkErrorCode;\n    uint32_t platformNetworkErrorCode;\n\n    HRESULT hr = XblHttpCallGetNetworkErrorCode(m_handle, &networkErrorCode, &platformNetworkErrorCode);\n    if (FAILED(hr))\n    {\n        return make_error_code(ConvertHrToXblErrorCode(hr));\n    }\n\n    m_errorCode = make_error_code(ConvertHrToXblErrorCode(networkErrorCode));\n    return m_errorCode;\n}\n\nstd::string http_call_response::err_message()\n{\n    if (m_errMessage != std::string())\n    {\n        return m_errMessage;\n    }\n\n    const char* errorMessage;\n    HRESULT hr = XblHttpCallGetPlatformNetworkErrorMessage(m_handle, &errorMessage);\n    if (FAILED(hr))\n    {\n        return std::string();\n    }\n\n    m_errMessage = std::string(errorMessage);\n    return m_errMessage;\n}\n\nstring_t http_call_response::e_tag() const\n{\n    // return default value because there is no matching method\n    return string_t();\n}\n\nstring_t http_call_response::response_date() const\n{\n    // return default value because there is no matching method\n    return string_t();\n}\n\nstd::chrono::seconds http_call_response::retry_after() const\n{\n    // return default value because there is no matching method\n    return std::chrono::seconds();\n}\n\nhttp_call_response::http_call_response(const http_call_response& other)\n    : m_bodyType(other.m_bodyType),\n    m_responseBodyString(other.m_responseBodyString),\n    m_responseBodyJson(other.m_responseBodyJson),\n    m_responseBodyVector(other.m_responseBodyVector),\n    m_responseHeaders(other.m_responseHeaders),\n    m_httpStatus(other.m_httpStatus),\n    m_errorCode(other.m_errorCode),\n    m_errMessage(other.m_errMessage)\n{\n    XblHttpCallDuplicateHandle(other.m_handle, &m_handle);\n}\n\nhttp_call_response& http_call_response::operator=(http_call_response other)\n{\n    std::swap(m_handle, other.m_handle);\n    m_responseBodyString = other.m_responseBodyString;\n    m_responseBodyJson = other.m_responseBodyJson;\n    m_responseBodyVector = other.m_responseBodyVector;\n    m_httpStatus = other.m_httpStatus;\n    m_responseHeaders = other.m_responseHeaders;\n    m_errorCode = other.m_errorCode;\n    m_errMessage = other.m_errMessage;\n\n    return *this;\n}\n\nhttp_call_response::~http_call_response()\n{\n    XblHttpCallCloseHandle(m_handle);\n}\n\nhttp_call::http_call(\n    _In_ XblHttpCallHandle callHandle,\n    _In_ string_t httpMethod,\n    _In_ string_t serverName,\n    _In_ web::uri pathQueryFragment\n) :\n    m_callHandle(std::move(callHandle)),\n    m_httpMethod(std::move(httpMethod)),\n    m_serverName(std::move(serverName)),\n    m_pathQueryFragment(std::move(pathQueryFragment))\n{\n}\n\n#if !XSAPI_NO_PPL\npplx::task<std::shared_ptr<http_call_response>> http_call::get_response_with_auth(\n    _In_ http_call_response_body_type httpCallResponseBodyType\n)\n{\n    XblHttpCallHandle xblHttpCall = m_callHandle;\n\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<http_call_response>>(\n        [xblHttpCall, httpCallResponseBodyType](\n            _In_ XAsyncBlock* async,\n            _In_ std::shared_ptr<http_call_response>& result)\n        {\n            HRESULT hr = XAsyncGetStatus(async, false);\n            if (SUCCEEDED(hr))\n            {\n                result = std::make_shared<http_call_response>(xblHttpCall, static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType));\n            }\n            return hr;\n        });\n\n    auto hr = XblHttpCallPerformAsync(\n        m_callHandle,\n        static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType),\n        &asyncWrapper->async\n    );\n\n    pplx::task_completion_event<std::shared_ptr<http_call_response>> taskCompletionEvent;\n\n    auto response = asyncWrapper->Task(hr).then([taskCompletionEvent](xbl_result<std::shared_ptr<http_call_response>> result) {\n        taskCompletionEvent.set(result.payload());\n        });\n    return pplx::task<std::shared_ptr<http_call_response>>(taskCompletionEvent);\n}\n\npplx::task<std::shared_ptr<http_call_response>> http_call::get_response_with_auth(\n    _In_ XalUserHandle user,\n    _In_ http_call_response_body_type httpCallResponseBodyType,\n    _In_ bool allUsersAuthRequired\n)\n{\n    UNREFERENCED_PARAMETER(user);\n    UNREFERENCED_PARAMETER(allUsersAuthRequired);\n\n    auto xblHttpCall = m_callHandle;\n\n    auto asyncWrapper = new AsyncWrapper<std::shared_ptr<http_call_response>>(\n        [xblHttpCall, httpCallResponseBodyType](XAsyncBlock* async, std::shared_ptr<http_call_response>& response)\n        {\n            HRESULT hr = XAsyncGetStatus(async, false);\n            if (SUCCEEDED(hr))\n            {\n                response = std::make_shared<http_call_response>(xblHttpCall, static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType));\n            }\n            return hr;\n        });\n\n    auto hr = XblHttpCallPerformAsync(\n        m_callHandle,\n        static_cast<XblHttpCallResponseBodyType>(httpCallResponseBodyType),\n        &asyncWrapper->async\n    );\n\n    pplx::task_completion_event<std::shared_ptr<http_call_response>> taskCompletionEvent;\n\n    auto response = asyncWrapper->Task(hr).then([taskCompletionEvent](xbl_result<std::shared_ptr<http_call_response>> result) {\n        taskCompletionEvent.set(result.payload());\n        });\n    return pplx::task<std::shared_ptr<http_call_response>>(taskCompletionEvent);\n}\n\npplx::task<std::shared_ptr<http_call_response>> http_call::get_response(\n    _In_ http_call_response_body_type httpCallResponseBodyType\n)\n{\n    // no matching function\n    UNREFERENCED_PARAMETER(httpCallResponseBodyType);\n    return pplx::task<std::shared_ptr<http_call_response>>();\n}\n#endif // !XSAPI_NO_PPL\n\nvoid http_call::set_request_body(\n    _In_ const string_t& value\n)\n{\n    XblHttpCallRequestSetRequestBodyString(m_callHandle, StringFromStringT(value).c_str());\n}\n\nvoid http_call::set_request_body(\n    _In_ const rapidjson::Value& value\n)\n{\n    XblHttpCallRequestSetRequestBodyString(m_callHandle, SerializeJson(value).c_str());\n}\n\nvoid http_call::set_request_body(\n    _In_ const std::vector<uint8_t>& value\n)\n{\n    uint8_t* buffer{ nullptr };\n    auto neededSize = value.size();\n    std::copy(value.begin(), value.end(), buffer);\n    if (buffer == nullptr)\n    {\n        return;\n    }\n    XblHttpCallRequestSetRequestBodyBytes(m_callHandle, buffer, static_cast<uint32_t>(neededSize));\n}\n\n\nvoid http_call::set_custom_header(\n    _In_ const string_t& Name,\n    _In_ const string_t& Value\n)\n{\n    XblHttpCallRequestSetHeader(\n        m_callHandle, \n        StringFromStringT(Name).c_str(), \n        StringFromStringT(Value).c_str(),\n        false\n    );\n}\n\nvoid http_call::set_long_http_call(\n    _In_ bool value\n)\n{\n    XblHttpCallRequestSetLongHttpCall(m_callHandle, value);\n    m_longHttpCall = value;\n}\n\nbool http_call::long_http_call() const\n{\n    return m_longHttpCall;\n}\n\nvoid http_call::set_retry_allowed(\n    _In_ bool value\n)\n{\n    XblHttpCallRequestSetLongHttpCall(m_callHandle, value);\n    m_retryAllowed = value;\n}\n\nbool http_call::retry_allowed() const\n{\n    return m_retryAllowed;\n}\n\nvoid http_call::set_content_type_header_value(\n    _In_ const string_t& value\n)\n{\n    XblHttpCallRequestSetHeader(m_callHandle, \"Content-Type\", StringFromStringT(value).c_str(), true);\n}\n\nstring_t http_call::content_type_header_value() const\n{\n    //no matching method\n    return string_t();\n}\n\nvoid http_call::set_xbox_contract_version_header_value(\n    _In_ const string_t& value\n)\n{\n    XblHttpCallRequestSetHeader(m_callHandle, \"x-xbl-contract-version\", StringFromStringT(value).c_str(), true);\n}\n\nstring_t http_call::xbox_contract_version_header_value() const\n{\n    //no matching method\n    return string_t();\n}\n\nstring_t http_call::server_name() const\n{\n    return m_serverName;\n}\n\nconst web::uri& http_call::path_query_fragment() const\n{\n    return m_pathQueryFragment;\n}\n\nstring_t http_call::http_method() const\n{\n    return m_httpMethod;\n}\n\nvoid http_call::set_add_default_headers(\n    _In_ bool value\n)\n{\n    UNREFERENCED_PARAMETER(value);\n    //no matching method\n}\n\nbool http_call::add_default_headers() const\n{\n    //no matching method\n    return false;\n}\n\nhttp_call::~http_call()\n{\n    XblHttpCallCloseHandle(m_callHandle);\n}\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/http_call_legacy.h",
    "content": "#pragma once\n\n#include \"xsapi-c/http_call_c.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace legacy\n{\n\n/// <summary>\n/// Enumerates the type of structured data contained in the http response body.\n/// </summary>\nenum class http_call_response_body_type\n{\n    /// <summary>\n    /// The response body consists of a string.\n    /// </summary>\n    string_body,\n\n    /// <summary>\n    /// The response body consists of a vector of bytes.\n    /// </summary>\n    vector_body,\n\n    /// <summary>\n    /// The response body consists of a JavaScript Object Notation (JSON) object.\n    /// </summary>\n    json_body\n};\n\n/// <summary>\n/// Represents an http response from the Xbox Live service.\n/// </summary>\nclass http_call_response\n{\npublic:\n#ifndef DEFAULT_MOVE_ENABLED\n    http_call_response(http_call_response&& other);\n    http_call_response& operator=(http_call_response&& other);\n#endif\n    http_call_response(\n        _In_ XblHttpCallHandle call,\n        _In_ XblHttpCallResponseBodyType type\n    );\n\n    /// <summary>\n    /// Gets the body type of the response.\n    /// </summary>\n    http_call_response_body_type body_type() const;\n\n    /// <summary>\n    /// Gets the response body of the response as a string.\n    /// </summary>\n    string_t response_body_string();\n\n    /// <summary>\n    /// Gets the response body of the response as a JSON value.\n    /// </summary>\n    web::json::value response_body_json();\n\n    /// <summary>\n    /// Gets the response body of the response as a byte vector.\n    /// </summary>\n    std::vector<unsigned char> response_body_vector();\n\n    /// <summary>\n    /// Gets the http headers of the response.\n    /// </summary>\n    web::http::http_headers response_headers();\n\n    /// <summary>\n    /// Gets the http status of the response.\n    /// </summary>\n    uint32_t http_status();\n\n    /// <summary>\n    /// Gets the error code of the response.\n    /// </summary>\n    std::error_code err_code();\n\n    /// <summary>\n    /// Gets the error message of the response.\n    /// </summary>\n    std::string err_message();\n\n    /// <summary>\n    /// Gets the eTag of the response.\n    /// </summary>\n    string_t e_tag() const;\n\n    /// <summary>\n    /// Gets the response date of the response.\n    /// </summary>\n    string_t response_date() const;\n\n    /// <summary>\n    /// Gets the \"retry after\" value found in the response.\n    /// </summary>\n    std::chrono::seconds retry_after() const;\n\n    http_call_response(const http_call_response&);\n    http_call_response& operator=(http_call_response other);\n    ~http_call_response();\n\nprivate:\n    XblHttpCallHandle m_handle;\n    http_call_response_body_type m_bodyType;\n    string_t m_responseBodyString;\n    web::json::value m_responseBodyJson;\n    std::vector<unsigned char> m_responseBodyVector;\n    web::http::http_headers m_responseHeaders;\n    uint32_t m_httpStatus{ 0 };\n    std::error_code m_errorCode;\n    std::string m_errMessage;\n\n    http_call_response() = delete;\n};\n\nclass http_call\n{\npublic:\n    http_call(\n        _In_ XblHttpCallHandle callHandle,\n        _In_ string_t httpMethod,\n        _In_ string_t serverName,\n        _In_ web::uri pathQueryFragment\n    );\n\n#if !XSAPI_NO_PPL\n    /// <summary>\n    /// Attach the Xbox Live token, sign the request, send the request to the service, and return the response.\n    /// </summary>\n    pplx::task<std::shared_ptr<http_call_response>> get_response_with_auth(\n        _In_ http_call_response_body_type httpCallResponseBodyType = http_call_response_body_type::json_body\n    );\n\n    pplx::task<std::shared_ptr<http_call_response>> get_response_with_auth(\n        _In_ XalUserHandle user,\n        _In_ http_call_response_body_type httpCallResponseBodyType = http_call_response_body_type::json_body,\n        _In_ bool allUsersAuthRequired = false\n    );\n\n    /// <summary>\n    /// Send the request without authentication and get the response.\n    /// </summary>\n    pplx::task< std::shared_ptr<http_call_response> > get_response(\n        _In_ http_call_response_body_type httpCallResponseBodyType\n    );\n#endif // !XSAPI_NO_PPL\n\n    /// <summary>\n    /// Sets the request body using a string.\n    /// </summary>\n    void set_request_body(_In_ const string_t& value);\n\n    /// <summary>\n    /// Sets the request body using a JSON value.\n    /// </summary>\n    void set_request_body(_In_ const rapidjson::Value& value);\n\n    /// <summary>\n    /// Sets the request body using a byte array value.\n    /// </summary>\n    void set_request_body(_In_ const std::vector<uint8_t>& value);\n\n    /// <summary>\n    /// Sets a custom header.\n    /// </summary>\n    void set_custom_header(\n        _In_ const string_t& headerName,\n        _In_ const string_t& headerValue);\n\n    /// <summary>\n    /// Sets if this is a long http call, and should use the long_http_timeout setting.\n    /// </summary>\n    void set_long_http_call(_In_ bool value);\n\n    /// <summary>\n    /// Gets if this is a long http call, and should use the long_http_timeout setting.\n    /// </summary>\n    bool long_http_call() const;\n\n    /// <summary>\n    /// Sets if retry is allowed during this call.\n    /// </summary>\n    void set_retry_allowed(_In_ bool value);\n\n    /// <summary>\n    /// Get if retry is allowed during this call.\n    /// </summary>\n    bool retry_allowed() const;\n\n    /// <summary>\n    /// Sets the content type header value for this call.\n    /// </summary>\n    void set_content_type_header_value(_In_ const string_t& value);\n\n    /// <summary>\n    /// Gets the content type header value for this call.\n    /// </summary>\n    string_t content_type_header_value() const;\n\n    /// <summary>\n    /// Sets the Xbox Live contract version header value for this call.\n    /// </summary>\n    void set_xbox_contract_version_header_value(_In_ const string_t& value);\n\n    /// <summary>\n    /// Gets the Xbox Live contract version header value for this call.\n    /// </summary>\n    string_t xbox_contract_version_header_value() const;\n\n    /// <summary>\n    /// Gets the server name for this call.\n    /// </summary>\n    string_t server_name() const;\n\n    /// <summary>\n    /// Gets the path for this call.\n    /// </summary>\n    const web::uri& path_query_fragment() const;\n\n    /// <summary>\n    /// Gets the http method for this call.\n    /// </summary>\n    string_t http_method() const;\n\n    /// <summary>\n    /// Sets a flag indicating if default headers should be added or not.\n    /// </summary>\n    void set_add_default_headers(_In_ bool value);\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    bool add_default_headers() const;\n\n    ~http_call();\n\nprivate:\n    XblHttpCallHandle m_callHandle;\n    string_t m_httpMethod;\n    string_t m_serverName;\n    web::uri m_pathQueryFragment;\n    bool m_longHttpCall{ false };\n    bool m_retryAllowed{ false };\n};\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/http_call_request_message.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"http_call_request_message_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace legacy\n{\n\nhttp_call_request_message::http_call_request_message()\n    : m_httpRequestMessageType(http_request_message_type::empty_message)\n{\n}\n\nhttp_call_request_message::http_call_request_message(\n    _In_ const http_call_request_message_internal *internalObj\n    ) :\n    m_httpRequestMessageType(internalObj->get_http_request_message_type())\n{\n    m_requestMessageString = internalObj->request_message_string();\n    m_requestMessageVector = internalObj->request_message_vector();\n}\n\nconst xsapi_internal_string& http_call_request_message::request_message_string() const\n{\n    return m_requestMessageString;\n}\n\nconst xsapi_internal_vector<unsigned char>& http_call_request_message::request_message_vector() const\n{\n    return m_requestMessageVector;\n}\n\nhttp_request_message_type http_call_request_message::get_http_request_message_type() const\n{\n    return m_httpRequestMessageType;\n}\n\nhttp_call_request_message_internal::http_call_request_message_internal()\n    : m_httpRequestMessageType(http_request_message_type::empty_message)\n{\n}\n\nhttp_call_request_message_internal::http_call_request_message_internal(\n    _In_ xsapi_internal_string messageString\n    ) :\n    m_requestMessageString(std::move(messageString)),\n    m_httpRequestMessageType(http_request_message_type::string_message)\n{\n}\n\nhttp_call_request_message_internal::http_call_request_message_internal(\n    _In_ xsapi_internal_vector<unsigned char> messageVector\n    ) :\n    m_requestMessageVector(std::move(messageVector)),\n    m_httpRequestMessageType(http_request_message_type::vector_message)\n{\n}\n\nconst xsapi_internal_string& http_call_request_message_internal::request_message_string() const\n{\n    return m_requestMessageString;\n}\n\nconst xsapi_internal_vector<unsigned char>& http_call_request_message_internal::request_message_vector() const\n{\n    return m_requestMessageVector;\n}\n\nhttp_request_message_type\nhttp_call_request_message_internal::get_http_request_message_type() const\n{\n    return m_httpRequestMessageType;\n}\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/http_call_request_message_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nnamespace legacy\n{\n\n/// <summary>\n/// Enumerates the type of data contained in the http request body.\n/// </summary>\nenum http_request_message_type\n{\n    /// <summary>\n    /// No message.\n    /// </summary>\n    empty_message,\n\n    /// <summary>\n    /// The message is of type string.\n    /// </summary>\n    string_message,\n\n    /// <summary>\n    /// The message is of type vector, and acts as a memory buffer.\n    /// </summary>\n    vector_message\n};\n\nclass http_call_request_message_internal\n{\npublic:\n    http_call_request_message_internal();\n\n    http_call_request_message_internal(_In_ xsapi_internal_string messageString);\n\n    http_call_request_message_internal(_In_ xsapi_internal_vector<unsigned char> messageVector);\n\n    _XSAPIIMP const xsapi_internal_string& request_message_string() const;\n\n    _XSAPIIMP const xsapi_internal_vector<unsigned char>& request_message_vector() const;\n\n    _XSAPIIMP http_request_message_type get_http_request_message_type() const;\n\nprivate:\n    xsapi_internal_vector<unsigned char> m_requestMessageVector;\n    xsapi_internal_string m_requestMessageString;\n    http_request_message_type m_httpRequestMessageType;\n};\n\n/// <summary>\n/// Represents an http request message.\n/// </summary>\nclass http_call_request_message\n{\npublic:\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline http_call_request_message();\n\n    /// <summary>\n    /// Internal function\n    /// </summary>\n    inline http_call_request_message(_In_ const http_call_request_message_internal* internalObj);\n\n    /// <summary>\n    /// The http request message if it is a string type.\n    /// </summary>\n    inline _XSAPIIMP const xsapi_internal_string& request_message_string() const;\n\n    /// <summary>\n    /// The http request message if it is a buffer.\n    /// </summary>\n    inline _XSAPIIMP const xsapi_internal_vector<unsigned char>& request_message_vector() const;\n\n    /// <summary>\n    /// The type of message.\n    /// </summary>\n    inline _XSAPIIMP http_request_message_type get_http_request_message_type() const;\n\nprivate:\n    xsapi_internal_vector<unsigned char> m_requestMessageVector;\n    xsapi_internal_string m_requestMessageString;\n    http_request_message_type m_httpRequestMessageType;\n};\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/http_call_wrapper_internal.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbox_live_context_internal.h\"\n#include <httpClient/httpProvider.h>\n\nusing namespace xbox::services;\n\n#define DEFAULT_USER_AGENT      \"XboxServicesAPI/\" XBOX_SERVICES_API_VERSION_STRING\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nHttpCall::~HttpCall()\n{\n    if (m_callHandle)\n    {\n        HCHttpCallCloseHandle(m_callHandle);\n    }\n}\n\nHRESULT HttpCall::Init(\n    _In_ const xsapi_internal_string& httpMethod,\n    _In_ const xsapi_internal_string& fullUrl\n)\n{\n    assert(m_step == Step::Uninitialized);\n    RETURN_HR_IF_FAILED( HCHttpCallCreate(&m_callHandle) );\n    m_step = Step::Pending;\n\n    RETURN_HR_IF_FAILED( HCHttpCallRequestSetUrl(m_callHandle, httpMethod.data(), fullUrl.data()) );\n\n    // Add default User-Agent header\n    xsapi_internal_string userAgent = DEFAULT_USER_AGENT;\n    return SetHeader(USER_AGENT_HEADER, userAgent);\n}\n\nHRESULT HttpCall::SetHeader(\n    _In_ const xsapi_internal_string& key,\n    _In_ const xsapi_internal_string& value,\n    _In_ bool allowTracing\n)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetHeader(m_callHandle, key.data(), value.data(), allowTracing);\n}\n\nHRESULT HttpCall::SetRequestBody(const xsapi_internal_vector<uint8_t>& bytes)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetRequestBodyBytes(m_callHandle, bytes.data(), static_cast<uint32_t>(bytes.size()));\n}\n\nHRESULT HttpCall::SetRequestBody(const xsapi_internal_string& bodyString)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetRequestBodyString(m_callHandle, bodyString.data());\n}\n\nHRESULT HttpCall::SetRequestBody(const JsonValue& bodyJson)\n{\n    assert(m_step == Step::Pending);\n    return SetRequestBody(JsonUtils::SerializeJson(bodyJson));\n}\n\nHRESULT HttpCall::SetRetryAllowed(bool retryAllowed)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetRetryAllowed(m_callHandle, retryAllowed);\n}\n\nHRESULT HttpCall::SetRetryCacheId(uint32_t retryAfterCacheId)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetRetryCacheId(m_callHandle, retryAfterCacheId);\n}\n\nHRESULT HttpCall::SetRetryDelay(uint32_t retryDelayInSeconds)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetRetryDelay(m_callHandle, retryDelayInSeconds);\n}\n\nHRESULT HttpCall::SetTimeout(uint32_t timeoutInSeconds)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetTimeout(m_callHandle, timeoutInSeconds);\n}\n\nHRESULT HttpCall::SetTimeoutWindow(uint32_t timeoutWindowInSeconds)\n{\n    assert(m_step == Step::Pending);\n    return HCHttpCallRequestSetTimeoutWindow(m_callHandle, timeoutWindowInSeconds);\n}\n\nHRESULT HttpCall::Perform(\n    AsyncContext<HttpResult> async,\n    bool forceRefresh\n)\n{\n    UNREFERENCED_PARAMETER(forceRefresh);\n    assert(m_step == Step::Pending);\n\n    m_asyncContext = std::move(async);\n    m_asyncBlock.queue = m_asyncContext.Queue().GetHandle();\n    m_asyncBlock.context = this;\n    m_asyncBlock.callback = &HttpCall::CompletionCallback;\n\n    HRESULT hr = S_OK;\n    if (m_performAlreadyCalled)\n    {\n        hr = CopyHttpCallHandle();\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        m_performAlreadyCalled = true;\n        m_step = Step::Running;\n\n        if (XblShouldFaultInject(INJECTION_FEATURE_HTTP))\n        {\n            LOGS_ERROR << \"FAULT INJECTION: HttpCall::Perform ID:\" << XblGetFaultCounter();\n            hr = E_FAIL;\n        }\n        else\n        {\n            hr = HCHttpCallPerformAsync(m_callHandle, &m_asyncBlock);\n        }\n\n        if (SUCCEEDED(hr))\n        {\n            AddRef(); // Keep HttpCall object alive until call completes\n        }\n        else\n        {\n            m_step = Step::Done;\n        }\n    }\n    return hr;\n}\n\nstruct RAIIHttpCallHandle\n{\npublic:\n    ~RAIIHttpCallHandle() { if(h) HCHttpCallCloseHandle(h); }\n    HCCallHandle h{ nullptr };\n};\n\nHRESULT HttpCall::CopyHttpCallHandle()\n{\n    RAIIHttpCallHandle newCallHandle;\n    RETURN_HR_IF_FAILED(HCHttpCallCreate(&newCallHandle.h));\n\n    const char* method{ nullptr };\n    const char* url{ nullptr };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetUrl(m_callHandle, &method, &url));\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetUrl(newCallHandle.h, method, url));\n\n    bool retryAllowed{ false };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetRetryAllowed(m_callHandle, &retryAllowed));\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetRetryAllowed(newCallHandle.h, retryAllowed));\n\n    uint32_t retryAfterCacheId{ 0 };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetRetryCacheId(m_callHandle, &retryAfterCacheId));\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetRetryCacheId(newCallHandle.h, retryAfterCacheId));\n\n    uint32_t retryDelayInSeconds{ 0 };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetRetryDelay(m_callHandle, &retryDelayInSeconds));\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetRetryDelay(newCallHandle.h, retryDelayInSeconds));\n\n    uint32_t timeoutInSeconds{ 0 };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetTimeout(m_callHandle, &timeoutInSeconds));\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetTimeout(newCallHandle.h, timeoutInSeconds));\n\n    uint32_t timeoutWindowInSeconds{ 0 };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetTimeoutWindow(m_callHandle, &timeoutWindowInSeconds));\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetTimeoutWindow(newCallHandle.h, timeoutWindowInSeconds));\n\n    uint32_t headerCount{ 0 };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetNumHeaders(m_callHandle, &headerCount));\n\n    for (uint32_t i = 0; i < headerCount; ++i)\n    {\n        const char* headerName{ nullptr };\n        const char* headerValue{ nullptr };\n        RETURN_HR_IF_FAILED(HCHttpCallRequestGetHeaderAtIndex(m_callHandle, i, &headerName, &headerValue));\n        RETURN_HR_IF_FAILED(HCHttpCallRequestSetHeader(newCallHandle.h, headerName, headerValue, false));\n    }\n\n    const uint8_t* requestBodyBytes{ nullptr };\n    uint32_t requestBodySize{ 0 };\n    RETURN_HR_IF_FAILED(HCHttpCallRequestGetRequestBodyBytes(m_callHandle, &requestBodyBytes, &requestBodySize));\n    if (requestBodyBytes != nullptr && requestBodySize > 0)\n    {\n        RETURN_HR_IF_FAILED(HCHttpCallRequestSetRequestBodyBytes(newCallHandle.h, requestBodyBytes, requestBodySize));\n    }\n\n    HCHttpCallCloseHandle(m_callHandle);\n    m_callHandle = HCHttpCallDuplicateHandle(newCallHandle.h);\n\n    return S_OK;\n}\n\n\nHRESULT xbox::services::HttpCall::ResetAndCopyForRetry()\n{\n    HRESULT hr = CopyHttpCallHandle();\n    if (SUCCEEDED(hr))\n    {\n        m_step = Step::Pending;\n        m_performAlreadyCalled = false;\n    }\n    return hr;\n}\n\nHRESULT HttpCall::ConvertHttpStatusToHRESULT(_In_ uint32_t httpStatusCode)\n{\n    xbox::services::xbl_error_code errCode = static_cast<xbox::services::xbl_error_code>(httpStatusCode);\n    HRESULT hr = HTTP_E_STATUS_UNEXPECTED;\n\n    // 2xx are http success codes\n    if ((httpStatusCode >= 200) && (httpStatusCode < 300))\n    {\n        hr = S_OK;\n    }\n\n    // MSXML XHR bug: get_status() returns HTTP/1223 for HTTP/204:\n    // http://blogs.msdn.com/b/ieinternals/archive/2009/07/23/the-ie8-native-xmlhttprequest-object.aspx\n    // treat it as success code as well\n    else if (httpStatusCode == 1223)\n    {\n        hr = S_OK;\n    }\n    else\n    {\n        switch (errCode)\n        {\n        case xbl_error_code::http_status_300_multiple_choices: hr = HTTP_E_STATUS_AMBIGUOUS; break;\n        case xbl_error_code::http_status_301_moved_permanently: hr = HTTP_E_STATUS_MOVED; break;\n        case xbl_error_code::http_status_302_found: hr = HTTP_E_STATUS_REDIRECT; break;\n        case xbl_error_code::http_status_303_see_other: hr = HTTP_E_STATUS_REDIRECT_METHOD; break;\n        case xbl_error_code::http_status_304_not_modified: hr = HTTP_E_STATUS_NOT_MODIFIED; break;\n        case xbl_error_code::http_status_305_use_proxy: hr = HTTP_E_STATUS_USE_PROXY; break;\n        case xbl_error_code::http_status_307_temporary_redirect: hr = HTTP_E_STATUS_REDIRECT_KEEP_VERB; break;\n\n        case xbl_error_code::http_status_400_bad_request: hr = HTTP_E_STATUS_BAD_REQUEST; break;\n        case xbl_error_code::http_status_401_unauthorized: hr = HTTP_E_STATUS_DENIED; break;\n        case xbl_error_code::http_status_402_payment_required: hr = HTTP_E_STATUS_PAYMENT_REQ; break;\n        case xbl_error_code::http_status_403_forbidden: hr = HTTP_E_STATUS_FORBIDDEN; break;\n        case xbl_error_code::http_status_404_not_found: hr = HTTP_E_STATUS_NOT_FOUND; break;\n        case xbl_error_code::http_status_405_method_not_allowed: hr = HTTP_E_STATUS_BAD_METHOD; break;\n        case xbl_error_code::http_status_406_not_acceptable: hr = HTTP_E_STATUS_NONE_ACCEPTABLE; break;\n        case xbl_error_code::http_status_407_proxy_authentication_required: hr = HTTP_E_STATUS_PROXY_AUTH_REQ; break;\n        case xbl_error_code::http_status_408_request_timeout: hr = HTTP_E_STATUS_REQUEST_TIMEOUT; break;\n        case xbl_error_code::http_status_409_conflict: hr = HTTP_E_STATUS_CONFLICT; break;\n        case xbl_error_code::http_status_410_gone: hr = HTTP_E_STATUS_GONE; break;\n        case xbl_error_code::http_status_411_length_required: hr = HTTP_E_STATUS_LENGTH_REQUIRED; break;\n        case xbl_error_code::http_status_412_precondition_failed: hr = HTTP_E_STATUS_PRECOND_FAILED; break;\n        case xbl_error_code::http_status_413_request_entity_too_large: hr = HTTP_E_STATUS_REQUEST_TOO_LARGE; break;\n        case xbl_error_code::http_status_414_request_uri_too_long: hr = HTTP_E_STATUS_URI_TOO_LONG; break;\n        case xbl_error_code::http_status_415_unsupported_media_type: hr = HTTP_E_STATUS_UNSUPPORTED_MEDIA; break;\n        case xbl_error_code::http_status_416_requested_range_not_satisfiable: hr = HTTP_E_STATUS_RANGE_NOT_SATISFIABLE; break;\n        case xbl_error_code::http_status_417_expectation_failed: hr = HTTP_E_STATUS_EXPECTATION_FAILED; break;\n        case xbl_error_code::http_status_421_misdirected_request: hr = MAKE_HTTP_HRESULT(421); break;\n        case xbl_error_code::http_status_422_unprocessable_entity: hr = MAKE_HTTP_HRESULT(422); break;\n        case xbl_error_code::http_status_423_locked: hr = MAKE_HTTP_HRESULT(423); break;\n        case xbl_error_code::http_status_424_failed_dependency: hr = MAKE_HTTP_HRESULT(424); break;\n        case xbl_error_code::http_status_426_upgrade_required: hr = MAKE_HTTP_HRESULT(426); break;\n        case xbl_error_code::http_status_428_precondition_required: hr = MAKE_HTTP_HRESULT(428); break;\n        case xbl_error_code::http_status_429_too_many_requests: hr = MAKE_HTTP_HRESULT(429); break;\n        case xbl_error_code::http_status_431_request_header_fields_too_large: hr = MAKE_HTTP_HRESULT(431); break;\n        case xbl_error_code::http_status_449_retry_with:hr = MAKE_HTTP_HRESULT(449); break;\n        case xbl_error_code::http_status_451_unavailable_for_legal_reasons: hr = MAKE_HTTP_HRESULT(451); break;\n\n        case xbl_error_code::http_status_500_internal_server_error: hr = HTTP_E_STATUS_SERVER_ERROR; break;\n        case xbl_error_code::http_status_501_not_implemented: hr = HTTP_E_STATUS_NOT_SUPPORTED; break;\n        case xbl_error_code::http_status_502_bad_gateway: hr = HTTP_E_STATUS_BAD_GATEWAY; break;\n        case xbl_error_code::http_status_503_service_unavailable: hr = HTTP_E_STATUS_SERVICE_UNAVAIL; break;\n        case xbl_error_code::http_status_504_gateway_timeout: hr = HTTP_E_STATUS_GATEWAY_TIMEOUT; break;\n        case xbl_error_code::http_status_505_http_version_not_supported: hr = HTTP_E_STATUS_VERSION_NOT_SUP; break;\n        case xbl_error_code::http_status_506_variant_also_negotiates: hr = MAKE_HTTP_HRESULT(506); break;\n        case xbl_error_code::http_status_507_insufficient_storage: hr = MAKE_HTTP_HRESULT(507); break;\n        case xbl_error_code::http_status_508_loop_detected: hr = MAKE_HTTP_HRESULT(508); break;\n        case xbl_error_code::http_status_510_not_extended: hr = MAKE_HTTP_HRESULT(510); break;\n        case xbl_error_code::http_status_511_network_authentication_required: hr = MAKE_HTTP_HRESULT(511); break;\n\n        default:\n            hr = HTTP_E_STATUS_UNEXPECTED;\n            break;\n        }\n    }\n\n    return hr;\n}\n\nHRESULT HttpCall::Result() const\n{\n    HRESULT hrNetworkError{ S_OK };\n    uint32_t platformNetworkResult{ 0 };\n  \n    RETURN_HR_IF_FAILED(HCHttpCallResponseGetNetworkErrorCode(m_callHandle, &hrNetworkError, &platformNetworkResult));\n\n    if (XblShouldFaultInject(INJECTION_FEATURE_HTTP))\n    {\n        LOGS_ERROR << \"FAULT INJECTION: HttpCall::Result\" << XblGetFaultCounter();\n        hrNetworkError = E_FAIL;\n    }\n\n    if (SUCCEEDED(hrNetworkError))\n    {\n        HRESULT hrHttpStatus = ConvertHttpStatusToHRESULT(HttpStatus());\n        return hrHttpStatus;\n    }\n    else\n    {\n        LOGS_ERROR << \"HttpCall failed due to network error \" << platformNetworkResult;\n        return hrNetworkError;\n    }\n}\n\nHRESULT HttpCall::GetErrorMessage(const char** errorMessage) const\n{\n    return HCHttpCallResponseGetPlatformNetworkErrorMessage(m_callHandle, errorMessage);\n}\n\nuint32_t HttpCall::HttpStatus() const\n{\n    assert(m_step == Step::Done);\n\n    uint32_t status{ 0 };\n    auto hr = HCHttpCallResponseGetStatusCode(m_callHandle, &status);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return status;\n}\n\nxsapi_internal_vector<uint8_t> HttpCall::GetResponseBodyBytes() const\n{\n    assert(m_step == Step::Done);\n\n    size_t bodySize{ 0 };\n    xsapi_internal_vector<uint8_t> body;\n\n    HRESULT hr = HCHttpCallResponseGetResponseBodyBytesSize(m_callHandle, &bodySize);\n    if (SUCCEEDED(hr))\n    {\n        body.resize(bodySize);\n        hr = HCHttpCallResponseGetResponseBodyBytes(m_callHandle, body.size(), body.data(), nullptr);\n        assert(SUCCEEDED(hr));\n    }\n    return body;\n}\n\nxsapi_internal_string HttpCall::GetResponseBodyString() const\n{\n    assert(m_step == Step::Done);\n\n    const char* bodyString{ nullptr };\n    auto hr = HCHttpCallResponseGetResponseString(m_callHandle, &bodyString);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return bodyString != nullptr ? xsapi_internal_string{ bodyString } : xsapi_internal_string();\n}\n\n//TODO: consider keeping a JsonDocument member instead of parsing every time\nJsonDocument HttpCall::GetResponseBodyJson() const\n{\n    assert(m_step == Step::Done);\n\n    const char* bodyString{ nullptr };\n    auto hr = HCHttpCallResponseGetResponseString(m_callHandle, &bodyString);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    JsonDocument json;\n    if (bodyString != nullptr)\n    {\n        json.Parse(bodyString);\n        if (!json.HasParseError())\n        {\n            return json;\n        }\n    }\n    return JsonDocument(rapidjson::kNullType);\n}\n\nxsapi_internal_string HttpCall::GetResponseHeader(const xsapi_internal_string& key) const\n{\n    assert(m_step == Step::Done);\n\n    const char* headerValue{ nullptr };\n    auto hr = HCHttpCallResponseGetHeader(m_callHandle, key.data(), &headerValue);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n\n    return headerValue ? xsapi_internal_string{ headerValue } : xsapi_internal_string{};\n}\n\nHRESULT HttpCall::SetRequestBody(\n    _In_reads_bytes_(requestBodySize) const uint8_t* requestBodyBytes,\n    _In_ uint32_t requestBodySize\n)\n{\n    return HCHttpCallRequestSetRequestBodyBytes(m_callHandle, requestBodyBytes, requestBodySize);\n}\n\nHRESULT HttpCall::SetRequestBody(\n    _In_z_ const char* requestBodyString\n)\n{\n    return HCHttpCallRequestSetRequestBodyString(m_callHandle, requestBodyString);\n}\n\nHRESULT HttpCall::GetResponseString(\n    _Out_ const char** responseString\n)\n{\n    return HCHttpCallResponseGetResponseString(m_callHandle, responseString);\n}\n\nHRESULT HttpCall::GetResponseBodyBytesSize(\n    _Out_ size_t* bufferSize\n)\n{\n    return HCHttpCallResponseGetResponseBodyBytesSize(m_callHandle, bufferSize);\n}\n\nHRESULT HttpCall::GetResponseBodyBytes(\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) uint8_t* buffer,\n    _Out_opt_ size_t* bufferUsed\n)\n{\n    return HCHttpCallResponseGetResponseBodyBytes(m_callHandle, bufferSize, buffer, bufferUsed);\n}\n\nHRESULT HttpCall::GetNetworkErrorCode(\n    _Out_ HRESULT* networkErrorCode,\n    _Out_ uint32_t* platformNetworkErrorCode\n)\n{\n    return HCHttpCallResponseGetNetworkErrorCode(m_callHandle, networkErrorCode, platformNetworkErrorCode);\n}\n\nHRESULT HttpCall::GetPlatformNetworkErrorMessage(\n    _Out_ const char** platformNetworkErrorMessage\n)\n{\n    return HCHttpCallResponseGetPlatformNetworkErrorMessage(m_callHandle, platformNetworkErrorMessage);\n}\n\nHRESULT HttpCall::ResponseGetHeader(\n    _In_z_ const char* headerName,\n    _Out_ const char** headerValue\n)\n{\n    return HCHttpCallResponseGetHeader(m_callHandle, headerName, headerValue);\n}\n\nHRESULT HttpCall::ResponseGetNumHeaders(\n    _Out_ uint32_t* numHeaders\n)\n{\n    return HCHttpCallResponseGetNumHeaders(m_callHandle, numHeaders);\n}\n\nHRESULT HttpCall::ResponseGetHeaderAtIndex(\n    _In_ uint32_t headerIndex,\n    _Out_ const char** headerName,\n    _Out_ const char** headerValue\n)\n{\n    return HCHttpCallResponseGetHeaderAtIndex(m_callHandle, headerIndex, headerName, headerValue);\n}\n\nHRESULT HttpCall::SetTracing(bool traceCall)\n{\n    return HCHttpCallSetTracing(m_callHandle, traceCall);\n}\n\nHRESULT HttpCall::GetRequestUrl(const char** url) const\n{\n    return HCHttpCallGetRequestUrl(m_callHandle, url);\n}\n\nHttpHeaders HttpCall::GetResponseHeaders() const\n{\n    assert(m_step == Step::Done);\n\n    uint32_t headerCount{ 0 };\n    auto hr = HCHttpCallResponseGetNumHeaders(m_callHandle, &headerCount);\n    assert(SUCCEEDED(hr));\n\n    HttpHeaders headers{};\n    for (uint32_t i = 0; i < headerCount; ++i)\n    {\n        const char* headerName{ nullptr };\n        const char* headerValue{ nullptr };\n        hr = HCHttpCallResponseGetHeaderAtIndex(m_callHandle, i, &headerName, &headerValue);\n        assert(SUCCEEDED(hr));\n        headers[headerName] = headerValue;\n    }\n    UNREFERENCED_PARAMETER(hr);\n\n    return headers;\n}\n\nvoid HttpCall::CompletionCallback(_In_ XAsyncBlock* async)\n{\n    auto sharedThis{ static_cast<HttpCall*>(async->context)->shared_from_this() };\n    sharedThis->DecRef();\n\n    sharedThis->m_step = Step::Done;\n    sharedThis->m_asyncContext.Complete(HttpResult{ sharedThis });\n}\n\nstd::shared_ptr<RefCounter> HttpCall::GetSharedThis()\n{\n    return shared_from_this();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\nusing namespace xbox::services;\n\nHRESULT XblHttpCall::SetXblServiceContractVersion(uint32_t contractVersion)\n{\n    xsapi_internal_stringstream ss;\n    ss << contractVersion;\n    return SetHeader(CONTRACT_VERSION_HEADER, ss.str());\n}\n\nvoid XblHttpCall::SetLongHttpCall(_In_ bool longHttpCall)\n{\n    m_longHttpCall = longHttpCall;\n}\n\nXblHttpCall::XblHttpCall(_In_ User&& user)\n    : m_user{ std::move(user) }\n{\n}\n\nHRESULT XblHttpCall::Init(\n    _In_ std::shared_ptr<XboxLiveContextSettings> contextSettings,\n    _In_ const xsapi_internal_string& httpMethod,\n    _In_ const xsapi_internal_string& fullUrl,\n    _In_ xbox_live_api xboxLiveApi\n)\n{\n    m_httpMethod = httpMethod;\n    m_fullUrl = fullUrl;\n    m_longHttpTimeout = contextSettings->LongHttpTimeout();\n\n    RETURN_HR_IF_FAILED(HttpCall::Init(httpMethod, fullUrl));\n    RETURN_HR_IF_FAILED(SetRetryCacheId(static_cast<uint32_t>(xboxLiveApi)));\n    m_httpTimeoutWindowInSeconds = contextSettings->HttpTimeoutWindow();\n    RETURN_HR_IF_FAILED(SetTimeoutWindow(contextSettings->HttpTimeoutWindow()));\n    RETURN_HR_IF_FAILED(SetRetryDelay(contextSettings->HttpRetryDelay()));\n    RETURN_HR_IF_FAILED(SetHeader(CONTRACT_VERSION_HEADER, \"1\"));\n    RETURN_HR_IF_FAILED(SetHeader(CONTENT_TYPE_HEADER, \"application/json; charset=utf-8\"));\n    RETURN_HR_IF_FAILED(SetHeader(ACCEPT_LANGUAGE_HEADER, utils::get_locales()));\n    RETURN_HR_IF_FAILED(SetUserAgent(contextSettings->HttpUserAgent()));\n\n    return S_OK;\n}\n\nHRESULT XblHttpCall::CalcHttpTimeout()\n{\n    if (m_longHttpCall)\n    {\n        // Long calls such as Title Storage upload/download ignore http_timeout_window so they act as expected with \n        // requiring the game developer to manually adjust http_timeout_window before calling them.\n        return SetTimeout(m_longHttpTimeout);\n    }\n    else\n    {\n        // For all other calls, set the timeout to be how much time left before hitting the http_timeout_window setting with a min of 5 second\n        std::chrono::milliseconds timeElapsedSinceFirstCall = std::chrono::duration_cast<std::chrono::milliseconds>(m_requestStartTime - m_firstCallStartTime);\n        std::chrono::seconds remainingTimeBeforeTimeout = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(m_httpTimeoutWindowInSeconds) - timeElapsedSinceFirstCall);\n        uint64_t secondsLeft = __min(DEFAULT_HTTP_TIMEOUT_SECONDS, static_cast<uint64_t>(remainingTimeBeforeTimeout.count()));\n        uint64_t secondsLeftCapped = __max(MIN_HTTP_TIMEOUT_SECONDS, secondsLeft);\n        return SetTimeout(static_cast<uint32_t>(secondsLeftCapped));\n    }\n}\n\nHRESULT XblHttpCall::SetHeader(\n    _In_ const xsapi_internal_string& key,\n    _In_ const xsapi_internal_string& value,\n    _In_ bool allowTracing\n)\n{\n    m_requestHeaders[key] = value;\n    return HttpCall::SetHeader(key, value, allowTracing);\n}\n\nHRESULT XblHttpCall::SetUserAgent(_In_ HttpCallAgent userAgent)\n{\n    String headerValue{ DEFAULT_USER_AGENT };\n    if (userAgent != HttpCallAgent::Title)\n    {\n        headerValue += EnumName(userAgent);\n    }\n\n    XblApiType apiType{ XblApiType::XblCApi };\n    {\n        auto state{ GlobalState::Get() };\n        if (state)\n        {\n            apiType = state->ApiType;\n        }\n    }\n\n    switch (apiType)\n    {\n    case XblApiType::XblCApi:\n    {\n        headerValue += \" c\";\n        break;\n    }\n    case XblApiType::XblCPPApi:\n    {\n        headerValue += \" cpp\";\n        break;\n    }\n    }\n\n    return SetHeader(USER_AGENT_HEADER, headerValue);\n}\n\nHRESULT XblHttpCall::SetRequestBody(const xsapi_internal_vector<uint8_t>& bytes)\n{\n    m_requestBody = bytes;\n    return HttpCall::SetRequestBody(xsapi_internal_vector<uint8_t>{ bytes });\n}\n\nHRESULT XblHttpCall::SetRequestBody(_In_reads_bytes_(requestBodySize) const uint8_t* requestBodyBytes, _In_ uint32_t requestBodySize)\n{\n    m_requestBody = xsapi_internal_vector<uint8_t>{ requestBodyBytes, requestBodyBytes + requestBodySize };\n    return HttpCall::SetRequestBody(requestBodyBytes, requestBodySize);\n}\n\nHRESULT XblHttpCall::SetRequestBody(_In_z_ const char* requestBodyString)\n{\n    xsapi_internal_string requestBody{ requestBodyString };\n    return XblHttpCall::SetRequestBody(requestBody);\n}\n\nHRESULT XblHttpCall::SetRequestBody(const xsapi_internal_string& bodyString)\n{\n    m_requestBody = xsapi_internal_vector<uint8_t>{ bodyString.begin(), bodyString.end() };\n    return HttpCall::SetRequestBody(bodyString);\n}\n\nHRESULT XblHttpCall::SetRequestBody(const JsonValue& bodyJson)\n{\n    return SetRequestBody(JsonUtils::SerializeJson(bodyJson));\n}\n\nvoid XblHttpCall::SetAuthRetryAllowed(bool authRetryAllowed)\n{\n    m_authRetryExplicitlyAllowed = authRetryAllowed;\n}\n\nHRESULT XblHttpCall::Perform(\n    AsyncContext<HttpResult> async,\n    bool forceRefresh\n)\n{\n    m_asyncContext = std::move(async);\n\n    std::shared_ptr<XblHttpCall> sharedThis = { std::dynamic_pointer_cast<XblHttpCall>(shared_from_this()) };\n\n    auto now = chrono_clock_t::now();\n    if (m_iterationNumber == 0)\n    {\n        m_firstCallStartTime = now;\n    }\n    m_iterationNumber++;\n    m_requestStartTime = now;\n\n    if (forceRefresh)\n    {\n        m_user.SetTokenExpired(m_user.Xuid());\n    }\n\n    return m_user.GetTokenAndSignature(\n        m_httpMethod,\n        m_fullUrl,\n        m_requestHeaders,\n        m_requestBody.data(),\n        m_requestBody.size(),\n        false, // allUsersAuthRequired\n        AsyncContext<xbox::services::Result<TokenAndSignature>>{ m_asyncContext.Queue(),\n        [\n            sharedThis\n        ]\n    (xbox::services::Result<TokenAndSignature> authResult)\n    {\n        if (Failed(authResult))\n        {\n            sharedThis->IntermediateHttpCallCompleteCallback(authResult.Hresult());\n        }\n        else\n        {\n            const auto& authPayload = authResult.Payload();\n            HRESULT hr = S_OK;\n\n            if (!authPayload.token.empty())\n            {\n                hr = sharedThis->HttpCall::SetHeader(AUTH_HEADER, authPayload.token, false);\n            }\n\n            if (SUCCEEDED(hr) && !authPayload.signature.empty())\n            {\n                hr = sharedThis->HttpCall::SetHeader(SIG_HEADER, authPayload.signature, false);\n            }\n\n            if (SUCCEEDED(hr))\n            {\n                hr = sharedThis->CalcHttpTimeout();\n                if (SUCCEEDED(hr))\n                {\n                    hr = sharedThis->HttpCall::Perform(AsyncContext<HttpResult>{\n                        sharedThis->m_asyncContext.Queue(),\n                            [\n                                // Don't store a shared ref here since this lambda will be stored in HttpCall object, creating a self reference that would never\n                                // be cleaned up. HttpCallPerform already guarantees lifetime until this callback is called.\n                                rawThis{ sharedThis.get() }\n                            ]\n                        (HttpResult result)\n                        {\n                            rawThis->IntermediateHttpCallCompleteCallback(result);\n                        }});\n                }\n            }\n\n            if (FAILED(hr))\n            {\n                sharedThis->IntermediateHttpCallCompleteCallback(HttpResult{ hr });\n            }\n        }\n    }\n    });\n}\n\nvoid XblHttpCall::IntermediateHttpCallCompleteCallback(HttpResult result)\n{\n    auto httpCall = result.Payload();\n    if (httpCall)\n    {\n        bool wasHandled{ false };\n        HRESULT hr = HandleAuthError(httpCall, wasHandled);\n        if (wasHandled)\n        {\n            return;\n        }\n        if (FAILED(hr))\n        {\n            m_asyncContext.Complete(HttpResult{ hr });\n            return;\n        }\n\n        HandleThrottleError(httpCall);\n    }\n\n    m_asyncContext.Complete(std::move(result));\n}\n\nHRESULT XblHttpCall::HandleAuthError(_In_ std::shared_ptr<class HttpCall> httpCall, _Out_ bool& wasHandled)\n{\n    if (httpCall->HttpStatus() != 401)\n    {\n        wasHandled = false;\n        return S_OK;\n    }\n\n    bool retryAllowed{ false };\n    HCHttpCallRequestGetRetryAllowed(m_callHandle, &retryAllowed);\n    if (!retryAllowed && !m_authRetryExplicitlyAllowed)\n    {\n        wasHandled = false;\n        return S_OK;\n    }\n\n    if (m_hasPerformedRetryOn401)\n    {\n        // Ignore 401 retrying if we already have retried a 401\n        wasHandled = false;\n        return S_OK;\n    }\n    m_hasPerformedRetryOn401 = true;\n\n    HRESULT hr = ResetAndCopyForRetry();\n    if (SUCCEEDED(hr))\n    {\n        hr = XblHttpCall::Perform(m_asyncContext, true);\n    }\n    if (SUCCEEDED(hr))\n    {\n        wasHandled = true;\n        return S_OK;\n    }\n\n    wasHandled = false;\n    return hr;\n}\n\nvoid XblHttpCall::HandleThrottleError(_In_ std::shared_ptr<class HttpCall> httpCall)\n{\n    if (httpCall->HttpStatus() != 429)\n    {\n        return;\n    }\n\n    // Assert if we were throttled by the service so the game dev knows that they are calling Xbox Live to agressively\n    auto appConfig = AppConfig::Instance();\n    if (appConfig && utils::str_icmp_internal(appConfig->Sandbox(), \"RETAIL\") != 0)\n    {\n        if (!appConfig->IsDisableAssertsForXboxLiveThrottlingInDevSandboxes())\n        {\n            LOGS_ERROR << \"Xbox Live service call to \" << m_fullUrl << \" was throttled\";\n            LOGS_ERROR << GetResponseBodyString();\n            LOGS_ERROR << \"You can temporarily disable the assert by calling\";\n            LOGS_ERROR << \"XblDisableAssertsForXboxLiveThrottlingInDevSandboxes()\";\n            LOGS_ERROR << \"Note that this will only disable this assert.  You will still be throttled in all sandboxes.\";\n#ifndef XSAPI_UNIT_TESTS\n            assert(false && \"Xbox Live service call was throttled.  See Output for more detail\");\n#endif\n        }\n    }\n}\n\nxsapi_internal_string XblHttpCall::BuildUrl(\n    xsapi_internal_string&& serviceName,\n    const xsapi_internal_string& pathQueryFragment\n)\n{\n    xsapi_internal_stringstream source;\n    source << \"https://\" << serviceName << \".xboxlive.com\" << pathQueryFragment;\n    return source.str();\n}\n"
  },
  {
    "path": "Source/Shared/http_call_wrapper_internal.h",
    "content": "#pragma once\n#include \"httpClient/httpClient.h\"\n#include \"shared_macros.h\"\n#include \"xbox_live_context_settings_internal.h\"\n\nconst char CONTENT_TYPE_HEADER[] = \"Content-Type\";\nconst char ACCEPT_LANGUAGE_HEADER[] = \"Accept-Language\";\nconst char CONTRACT_VERSION_HEADER[] = \"x-xbl-contract-version\";\nconst char USER_AGENT_HEADER[] = \"User-Agent\";\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nenum class xbox_live_api\n{\n    unspecified,\n    add_user_to_club,\n    add_club_role,\n    allocate_cluster,\n    allocate_cluster_inline,\n    allocate_session_host,\n    browse_catalog_bundles_helper,\n    browse_catalog_helper,\n    check_multiple_permissions_with_multiple_target_users,\n    check_permission_with_target_user,\n    clear_activity,\n    clear_search_handle,\n    consume_inventory_item,\n    create_club,\n    create_match_ticket,\n    delete_blob,\n    delete_club,\n    delete_match_ticket,\n    download_blob,\n    events_upload,\n    get_achievement,\n    get_achievements,\n    get_activities_for_social_group,\n    get_activities_for_users,\n    get_avoid_or_mute_list,\n    get_blob_metadata,\n    get_broadcasts,\n    get_catalog_item_details,\n    get_club,\n    get_club_batch,\n    get_clubs_owned,\n    get_configuration,\n    get_current_session,\n    get_current_session_by_handle,\n    get_game_clips,\n    get_game_server_metadata,\n    get_hopper_statistics,\n    get_inventory_item,\n    get_inventory_items,\n    get_leaderboard_for_social_group_internal,\n    get_leaderboard_internal,\n    get_match_ticket_details,\n    get_multiple_user_statistics_for_multiple_service_configurations,\n    get_presence,\n    get_presence_for_multiple_users,\n    get_presence_for_social_group,\n    get_quality_of_service_servers,\n    get_quota,\n    get_quota_for_session_storage,\n    get_search_handles,\n    delete_search_handle,\n    get_session_host_allocation_status,\n    get_sessions,\n    get_single_user_statistics,\n    get_social_graph,\n    get_social_relationships,\n    get_stats_value_document,\n    get_ticket_status,\n    get_teams,\n    get_team_details,\n    get_user_profiles,\n    get_user_profiles_for_social_group,\n    get_users_club_associations,\n    recommend_clubs,\n    register_team,\n    remove_user_from_club,\n    remove_club_role,\n    rename_club,\n    search_clubs,\n    send_invites,\n    set_activity,\n    set_presence_helper,\n    set_search_handle,\n    set_transfer_handle,\n    set_user_presence_within_club,\n    submit_batch_reputation_feedback,\n    submit_reputation_feedback,\n    subscribe_to_notifications,\n    suggest_clubs,\n    update_achievement,\n    patch_stats_value_document,\n    post_stats_value_document,\n    upload_blob,\n    verify_strings,\n    write_session_using_subpath,\n    xbox_one_pins_add_item,\n    xbox_one_pins_contains_item,\n    xbox_one_pins_remove_item,\n    post_recent_players,\n    get_activity_batch,\n    delete_activity,\n    mpa_send_invites\n};\n\nusing HttpHeaders = xsapi_internal_map<xsapi_internal_string, xsapi_internal_string>;\nusing HttpResult = Result<std::shared_ptr<class HttpCall>>;\n\n// RAII wrapper around HCHttpCall. No Xbox Live specific logic.\nclass HttpCall : public RefCounter, public std::enable_shared_from_this<HttpCall>\n{\npublic:\n    HttpCall() = default;\n    virtual ~HttpCall();\n\n    HRESULT Init(\n        _In_ const xsapi_internal_string& httpMethod,\n        _In_ const xsapi_internal_string& fullUrl\n    );\n\n    virtual HRESULT SetHeader(\n        _In_ const xsapi_internal_string& key,\n        _In_ const xsapi_internal_string& value,\n        _In_ bool allowTracing = true\n    );\n\n    virtual HRESULT SetTracing(bool traceCall);\n    virtual HRESULT SetRequestBody(const xsapi_internal_vector<uint8_t>& bytes);\n    virtual HRESULT SetRequestBody(_In_reads_bytes_(requestBodySize) const uint8_t* requestBodyBytes, _In_ uint32_t requestBodySize);\n    virtual HRESULT SetRequestBody(const xsapi_internal_string& bodyString);\n    virtual HRESULT SetRequestBody(const JsonValue& bodyJson);\n    virtual HRESULT SetRequestBody(_In_z_ const char* requestBodyString);\n    virtual HRESULT SetRetryAllowed(bool retryAllowed);\n    virtual HRESULT SetRetryCacheId(uint32_t retryAfterCacheId);\n    virtual HRESULT SetRetryDelay(uint32_t retryDelayInSeconds);\n    virtual HRESULT SetTimeout(uint32_t timeoutInSeconds);\n    virtual HRESULT SetTimeoutWindow(uint32_t timeoutWindowInSeconds);\n\n    virtual HRESULT Perform(\n        AsyncContext<HttpResult> async,\n        bool forceRefresh = false\n    );\n\n\n    virtual HRESULT GetRequestUrl(const char** url) const;\n    virtual HRESULT GetErrorMessage(const char** errorMessage) const;\n    virtual HRESULT Result() const;\n    virtual uint32_t HttpStatus() const;\n\n    virtual xsapi_internal_string GetResponseHeader(const xsapi_internal_string& key) const;\n    virtual HttpHeaders GetResponseHeaders() const;\n    virtual xsapi_internal_vector<uint8_t> GetResponseBodyBytes() const;\n    virtual HRESULT GetResponseBodyBytesSize(_Out_ size_t* bufferSize);\n    virtual HRESULT GetResponseBodyBytes(_In_ size_t bufferSize, _Out_writes_bytes_to_(bufferSize, *bufferUsed) uint8_t* buffer, _Out_opt_ size_t* bufferUsed);\n    virtual xsapi_internal_string GetResponseBodyString() const;\n    virtual HRESULT GetResponseString(_Out_ const char** responseString);\n    virtual JsonDocument GetResponseBodyJson() const;\n    virtual HRESULT GetNetworkErrorCode(_Out_ HRESULT* networkErrorCode, _Out_ uint32_t* platformNetworkErrorCode);\n    virtual HRESULT GetPlatformNetworkErrorMessage(_Out_ const char** platformNetworkErrorMessage);\n    virtual HRESULT ResponseGetHeader(_In_z_ const char* headerName, _Out_ const char** headerValue);\n    virtual HRESULT ResponseGetNumHeaders(_Out_ uint32_t* numHeaders);\n    virtual HRESULT ResponseGetHeaderAtIndex(_In_ uint32_t headerIndex, _Out_ const char** headerName, _Out_ const char** headerValue);\n\nprivate:\n    HttpCall(const HttpCall&) = delete;\n    HttpCall& operator=(HttpCall) = delete;\n    static void CALLBACK CompletionCallback(_In_ XAsyncBlock* async);\n    std::shared_ptr<RefCounter> GetSharedThis() override;\n    static HRESULT ConvertHttpStatusToHRESULT(_In_ uint32_t httpStatusCode);\n    HRESULT CopyHttpCallHandle();\n\n    XAsyncBlock m_asyncBlock{};\n    AsyncContext<HttpResult> m_asyncContext;\n    bool m_performAlreadyCalled{ false };\n\n    enum class Step\n    {\n        Uninitialized,\n        Pending,\n        Running,\n        Done\n    } m_step{ Step::Uninitialized };\n\nprotected:\n    HCCallHandle m_callHandle{ nullptr };\n    HRESULT ResetAndCopyForRetry();\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n\nusing namespace xbox::services;\n\n// Xbox Live specific http call wrapper that gets and attaches the Xbox Live token,\n// signs the request, and adds Xbox Live specific headers automatically.\n// Handles 401 token refresh logic, and 429 throttling logic\nstruct XblHttpCall : public HttpCall\n{\npublic:\n    XblHttpCall(User&& user);\n\n    virtual HRESULT Init(\n        _In_ std::shared_ptr<XboxLiveContextSettings> contextSettings,\n        _In_ const xsapi_internal_string& httpMethod,\n        _In_ const xsapi_internal_string& fullUrl,\n        _In_ xbox_live_api xboxLiveApi\n    );\n\n    HRESULT SetHeader(\n        _In_ const xsapi_internal_string& key,\n        _In_ const xsapi_internal_string& value,\n        _In_ bool allowTracing = true\n    ) override;\n\n    // Override the UserAgent that was specified in the contextSettings\n    HRESULT SetUserAgent(_In_ HttpCallAgent userAgent);\n\n    void SetLongHttpCall(_In_ bool longHttpCall);\n    HRESULT SetXblServiceContractVersion(uint32_t contractVersion);\n\n    HRESULT SetRequestBody(const xsapi_internal_vector<uint8_t>& bytes) override;\n    HRESULT SetRequestBody(_In_reads_bytes_(requestBodySize) const uint8_t* requestBodyBytes, _In_ uint32_t requestBodySize) override;\n    HRESULT SetRequestBody(const xsapi_internal_string& bodyString) override;\n    HRESULT SetRequestBody(const JsonValue& bodyJson) override;\n    HRESULT SetRequestBody(_In_z_ const char* requestBodyString) override;\n\n    void SetAuthRetryAllowed(bool authRetryAllowed);\n    HRESULT Perform(\n        AsyncContext<HttpResult> async,\n        bool forceRefresh = false\n    ) override;\n\n    static xsapi_internal_string BuildUrl(\n        xsapi_internal_string&& serviceName,\n        const xsapi_internal_string& pathQueryFragment\n    );\n\nprivate:\n    XblHttpCall(const XblHttpCall&) = delete;\n    XblHttpCall& operator=(XblHttpCall) = delete;\n\n    void IntermediateHttpCallCompleteCallback(HttpResult result);\n    HRESULT HandleAuthError(_In_ std::shared_ptr<class HttpCall> httpCall, _Out_ bool& wasHandled);\n    void HandleThrottleError(_In_ std::shared_ptr<class HttpCall> httpCall);\n    HRESULT CalcHttpTimeout();\n\n    User m_user;\n    xsapi_internal_vector<uint8_t> m_requestBody;\n    HttpHeaders m_requestHeaders;\n    xsapi_internal_string m_httpMethod;\n    xsapi_internal_string m_fullUrl;\n    bool m_longHttpCall{ false };\n    uint32_t m_longHttpTimeout{ 0 };\n    uint32_t m_httpTimeoutWindowInSeconds{ 0 };\n    chrono_clock_t::time_point m_firstCallStartTime;\n    chrono_clock_t::time_point m_requestStartTime;\n    uint32_t m_iterationNumber{ 0 };\n    AsyncContext<HttpResult> m_asyncContext;\n    bool m_authRetryExplicitlyAllowed{ false };\n    bool m_hasPerformedRetryOn401{ false };\n};"
  },
  {
    "path": "Source/Shared/http_headers.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\ntypedef xsapi_internal_map<xsapi_internal_string, xsapi_internal_string> xsapi_internal_http_headers;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/http_utils.cpp",
    "content": "/***\n* ==++==\n*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*\n* ==--==\n* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n*\n* Utilities\n*\n* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk\n*\n* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n****/\n\n#include \"pch.h\"\n\n#include <array>\n\n#if defined(_WIN32)\n#if HC_PLATFORM != HC_PLATFORM_XDK\n#include <winhttp.h>\n#endif\n#else // _WIN32\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-local-typedef\"\n#endif\n// TODO 1808 #include <boost/date_time/posix_time/posix_time.hpp>\n// #include <boost/date_time/posix_time/posix_time_io.hpp>\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n#endif // _WIN32\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#pragma warning( disable : 26498 ) // ignore eof warning \n#pragma warning( disable : 26812 )  // enum instead of enum class\n#endif\n\n// Could use C++ standard library if not __GLIBCXX__,\n// For testing purposes we just the handwritten on all platforms.\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n#include <codecvt>\n#endif\n\nnamespace xbox\n{\nnamespace services\n{\nnamespace detail\n{\n    xsapi_internal_string _to_base64(const unsigned char *ptr, size_t size);\n    std::vector<unsigned char> _from_base64(const xsapi_internal_string& str);\n\n    struct _triple_byte\n    {\n        unsigned char _1_1 : 2;\n        unsigned char _0 : 6;\n        unsigned char _2_1 : 4;\n        unsigned char _1_2 : 4;\n        unsigned char _3 : 6;\n        unsigned char _2_2 : 2;\n    };\n\n    static const char* _base64_enctbl = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n    const std::array<unsigned char, 128> _base64_dectbl =\n    { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,\n        52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255, 254, 255, 255,\n       255,  0,    1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,\n        15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,\n       255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,\n        41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255 } };\n\n    xsapi_internal_string _to_base64(const unsigned char *ptr, size_t size)\n    {\n        xsapi_internal_string result;\n\n        for (; size >= 3; )\n        {\n            const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);\n            unsigned char idx0 = record->_0;\n            unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;\n            unsigned char idx2 = (record->_2_1 << 2) | record->_2_2;\n            unsigned char idx3 = record->_3;\n            result.push_back(char(_base64_enctbl[idx0]));\n            result.push_back(char(_base64_enctbl[idx1]));\n            result.push_back(char(_base64_enctbl[idx2]));\n            result.push_back(char(_base64_enctbl[idx3]));\n            size -= 3;\n            ptr += 3;\n        }\n        switch (size)\n        {\n        case 1:\n        {\n            const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);\n            unsigned char idx0 = record->_0;\n            unsigned char idx1 = (record->_1_1 << 4);\n            result.push_back(char(_base64_enctbl[idx0]));\n            result.push_back(char(_base64_enctbl[idx1]));\n            result.push_back('=');\n            result.push_back('=');\n            break;\n        }\n        case 2:\n        {\n            const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);\n            unsigned char idx0 = record->_0;\n            unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;\n            unsigned char idx2 = (record->_2_1 << 2);\n            result.push_back(char(_base64_enctbl[idx0]));\n            result.push_back(char(_base64_enctbl[idx1]));\n            result.push_back(char(_base64_enctbl[idx2]));\n            result.push_back('=');\n            break;\n        }\n        }\n        return result;\n    }\n\n//\n// A note on the implementation of BASE64 encoding and decoding:\n//\n// This is a fairly basic and naive implementation; there is probably a lot of room for\n// performance improvement, as well as for adding options such as support for URI-safe base64,\n// ignoring CRLF, relaxed validation rules, etc. The decoder is currently pretty strict.\n//\n\n#ifdef __GNUC__\n// gcc is concerned about the bitfield uses in the code, something we simply need to ignore.\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#endif\n    std::vector<unsigned char> _from_base64(const xsapi_internal_string& input)\n    {\n        std::vector<unsigned char> result;\n\n        if (input.empty())\n            return result;\n\n        size_t padding = 0;\n\n        // Validation\n        {\n            auto size = input.size();\n\n            if ((size % 4) != 0)\n            {\n                throw std::runtime_error(\"length of base64 string is not an even multiple of 4\");\n            }\n\n            for (auto iter = input.begin(); iter != input.end(); ++iter, --size)\n            {\n                const size_t ch_sz = static_cast<size_t>(*iter);\n                if (ch_sz >= _base64_dectbl.size() || _base64_dectbl[ch_sz] == 255)\n                {\n                    throw std::runtime_error(\"invalid character found in base64 string\");\n                }\n                if (_base64_dectbl[ch_sz] == 254)\n                {\n                    padding++;\n                    // padding only at the end\n                    if (size > 2)\n                    {\n                        throw std::runtime_error(\"invalid padding character found in base64 string\");\n                    }\n                    if (size == 2)\n                    {\n                        const size_t ch2_sz = static_cast<size_t>(*(iter + 1));\n                        if (ch2_sz >= _base64_dectbl.size() || _base64_dectbl[ch2_sz] != 254)\n                        {\n                            throw std::runtime_error(\"invalid padding character found in base64 string\");\n                        }\n                    }\n                }\n            }\n        }\n\n\n        auto size = input.size();\n        const char* ptr = &input[0];\n\n        auto outsz = (size / 4) * 3;\n        outsz -= padding;\n\n        result.resize(outsz);\n\n        size_t idx = 0;\n        for (; size > 4; ++idx)\n        {\n            unsigned char target[3];\n            memset(target, 0, sizeof(target));\n            _triple_byte* record = reinterpret_cast<_triple_byte*>(target);\n\n            unsigned char val0 = _base64_dectbl[ptr[0]];\n            unsigned char val1 = _base64_dectbl[ptr[1]];\n            unsigned char val2 = _base64_dectbl[ptr[2]];\n            unsigned char val3 = _base64_dectbl[ptr[3]];\n\n            record->_0 = val0;\n            record->_1_1 = val1 >> 4;\n            result[idx] = target[0];\n\n            record->_1_2 = val1 & 0xF;\n            record->_2_1 = val2 >> 2;\n            result[++idx] = target[1];\n\n            record->_2_2 = val2 & 0x3;\n            record->_3 = val3 & 0x3F;\n            result[++idx] = target[2];\n\n            ptr += 4;\n            size -= 4;\n        }\n\n        // Handle the last four bytes separately, to avoid having the conditional statements\n        // in all the iterations (a performance issue).\n\n        {\n            unsigned char target[3];\n            memset(target, 0, sizeof(target));\n            _triple_byte* record = reinterpret_cast<_triple_byte*>(target);\n\n            DISABLE_WARNING_PUSH;\n            SUPPRESS_WARNING_EXPRESSION_NOT_TRUE;\n            unsigned char val0 = _base64_dectbl[ptr[0]];\n            DISABLE_WARNING_POP;\n            unsigned char val1 = _base64_dectbl[ptr[1]];\n            unsigned char val2 = _base64_dectbl[ptr[2]];\n            unsigned char val3 = _base64_dectbl[ptr[3]];\n\n            record->_0 = val0;\n            record->_1_1 = val1 >> 4;\n            result[idx] = target[0];\n\n            record->_1_2 = val1 & 0xF;\n            if (val2 != 254)\n            {\n                record->_2_1 = val2 >> 2;\n                result[++idx] = target[1];\n            }\n            else\n            {\n                // There shouldn't be any information (ones) in the unused bits,\n                if (record->_1_2 != 0)\n                {\n                    throw std::runtime_error(\"Invalid end of base64 string\");\n                }\n                return result;\n            }\n\n            record->_2_2 = val2 & 0x3;\n            if (val3 != 254)\n            {\n                record->_3 = val3 & 0x3F;\n                result[++idx] = target[2];\n            }\n            else\n            {\n                // There shouldn't be any information (ones) in the unused bits.\n                if (record->_2_2 != 0)\n                {\n                    throw std::runtime_error(\"Invalid end of base64 string\");\n                }\n                return result;\n            }\n        }\n\n        return result;\n    }\n}\n\n#ifndef _WIN32\n    datetime datetime::timeval_to_datetime(const timeval& time)\n    {\n        const uint64_t epoch_offset = 11644473600LL; // diff between windows and unix epochs (seconds)\n        uint64_t result = epoch_offset + time.tv_sec;\n        result *= _secondTicks; // convert to 10e-7\n        result += time.tv_usec * 10; // convert and add microseconds, 10e-6 to 10e-7\n        return datetime(result);\n    }\n#endif\n\n    static bool is_digit(char c) { return c >= '0' && c <= '9'; }\n\n    datetime datetime::utc_now()\n    {\n#ifdef _WIN32\n        ULARGE_INTEGER largeInt;\n        FILETIME fileTime;\n        GetSystemTimeAsFileTime(&fileTime);\n\n        largeInt.LowPart = fileTime.dwLowDateTime;\n        largeInt.HighPart = fileTime.dwHighDateTime;\n\n        return datetime(largeInt.QuadPart);\n#else //LINUX\n        timeval time{};\n        gettimeofday(&time, nullptr);\n        return timeval_to_datetime(time);\n#endif\n    }\n\n    xsapi_internal_string datetime::to_string(date_format format) const\n    {\n#ifdef _WIN32\n        int status;\n\n        ULARGE_INTEGER largeInt;\n        largeInt.QuadPart = m_interval;\n\n        FILETIME ft;\n        ft.dwHighDateTime = largeInt.HighPart;\n        ft.dwLowDateTime = largeInt.LowPart;\n\n        SYSTEMTIME systemTime;\n        if (!FileTimeToSystemTime((const FILETIME*)&ft, &systemTime))\n        {\n            throw details::create_system_error(GetLastError());\n        }\n\n        xsapi_internal_wostringstream outStream;\n        outStream.imbue(std::locale::classic());\n\n        if (format == RFC_1123)\n        {\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n            TCHAR dateStr[18] = { 0 };\n            status = GetDateFormat(LOCALE_INVARIANT, 0, &systemTime, __TEXT(\"ddd',' dd MMM yyyy\"), dateStr, sizeof(dateStr) / sizeof(TCHAR));\n#else\n            wchar_t dateStr[18] = { 0 };\n            status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L\"ddd',' dd MMM yyyy\", dateStr, sizeof(dateStr) / sizeof(wchar_t), NULL);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n            if (status == 0)\n            {\n                throw details::create_system_error(GetLastError());\n            }\n\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n            TCHAR timeStr[10] = { 0 };\n            status = GetTimeFormat(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, __TEXT(\"HH':'mm':'ss\"), timeStr, sizeof(timeStr) / sizeof(TCHAR));\n#else\n            wchar_t timeStr[10] = { 0 };\n            status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, sizeof(timeStr) / sizeof(wchar_t));\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n            if (status == 0)\n            {\n                throw details::create_system_error(GetLastError());\n            }\n\n            outStream << dateStr << \" \" << timeStr << \" \" << \"GMT\";\n        }\n        else if (format == ISO_8601)\n        {\n            const size_t buffSize = 64;\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n            TCHAR dateStr[buffSize] = { 0 };\n            status = GetDateFormat(LOCALE_INVARIANT, 0, &systemTime, __TEXT(\"yyyy-MM-dd\"), dateStr, buffSize);\n#else\n            wchar_t dateStr[buffSize] = { 0 };\n            status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L\"yyyy-MM-dd\", dateStr, buffSize, NULL);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n            if (status == 0)\n            {\n                throw details::create_system_error(GetLastError());\n            }\n\n#if _WIN32_WINNT < _WIN32_WINNT_VISTA\n            TCHAR timeStr[buffSize] = { 0 };\n            status = GetTimeFormat(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, __TEXT(\"HH':'mm':'ss\"), timeStr, buffSize);\n#else\n            wchar_t timeStr[buffSize] = { 0 };\n            status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L\"HH':'mm':'ss\", timeStr, buffSize);\n#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA\n            if (status == 0)\n            {\n                throw details::create_system_error(GetLastError());\n            }\n\n            outStream << dateStr << \"T\" << timeStr;\n            uint64_t frac_sec = largeInt.QuadPart % _secondTicks;\n            if (frac_sec > 0)\n            {\n                // Append fractional second, which is a 7-digit value with no trailing zeros\n                // This way, '1200' becomes '00012'\n                char buf[9] = { 0 };\n                sprintf_s(buf, sizeof(buf), \".%07ld\", (long int)frac_sec);\n                // trim trailing zeros\n                for (int i = 7; buf[i] == '0'; i--) buf[i] = '\\0';\n                outStream << buf;\n            }\n            outStream << \"Z\";\n        }\n\n        auto result = convert::utf16_to_utf8_internal(outStream.str());\n        return result;\n#else //LINUX\n        uint64_t input = m_interval;\n        uint64_t frac_sec = input % _secondTicks;\n        input /= _secondTicks; // convert to seconds\n        time_t time = (time_t)input - (time_t)11644473600LL;// diff between windows and unix epochs (seconds)\n\n        struct tm datetime;\n#if defined(PAVO)\n        gmtime_s(&time, &datetime);\n#else\n        gmtime_r(&time, &datetime);\n#endif // PAVO\n\n        const int max_dt_length = 64;\n        char output[max_dt_length + 1] = { 0 };\n\n        if (format != RFC_1123 && frac_sec > 0)\n        {\n            // Append fractional second, which is a 7-digit value with no trailing zeros\n            // This way, '1200' becomes '00012'\n            char buf[9] = { 0 };\n            snprintf(buf, sizeof(buf), \".%07ld\", (long int)frac_sec);\n            // trim trailing zeros\n            for (int i = 7; buf[i] == '0'; i--) buf[i] = '\\0';\n            // format the datetime into a separate buffer\n            char datetime_str[max_dt_length + 1] = { 0 };\n            strftime(datetime_str, sizeof(datetime_str), \"%Y-%m-%dT%H:%M:%S\", &datetime);\n            // now print this buffer into the output buffer\n            snprintf(output, sizeof(output), \"%s%sZ\", datetime_str, buf);\n        }\n        else\n        {\n            strftime(output, sizeof(output),\n                format == RFC_1123 ? \"%a, %d %b %Y %H:%M:%S GMT\" : \"%Y-%m-%dT%H:%M:%SZ\",\n                &datetime);\n        }\n\n        return xsapi_internal_string(output);\n#endif\n    }\n\n    // Take a string that represents a fractional second and return the number of ticks\n    // This is equivalent to doing atof on the string and multiplying by 10000000,\n    // but does not lose precision\n    template<typename StringIterator>\n    uint64_t timeticks_from_second(StringIterator begin, StringIterator end)\n    {\n        int size = (int)(end - begin);\n        _ASSERTE(begin[0] == U('.'));\n        uint64_t ufrac_second = 0;\n        for (int i = 1; i <= 7; ++i)\n        {\n            ufrac_second *= 10;\n            int add = i < size ? begin[i] - U('0') : 0;\n            ufrac_second += add;\n        }\n        return ufrac_second;\n    }\n\n    void extract_fractional_second(const xsapi_internal_string& dateString, xsapi_internal_string& resultString, uint64_t& ufrac_second)\n    {\n        resultString = dateString;\n        // First, the string must be strictly longer than 2 characters, and the trailing character must be 'Z'\n        if (resultString.size() > 2 && resultString[resultString.size() - 1] == U('Z'))\n        {\n            // Second, find the last non-digit by scanning the string backwards\n            auto last_non_digit = std::find_if_not(resultString.rbegin() + 1, resultString.rend(), is_digit);\n            if (last_non_digit < resultString.rend() - 1)\n            {\n                // Finally, make sure the last non-digit is a dot:\n                auto last_dot = last_non_digit.base() - 1;\n                if (*last_dot == U('.'))\n                {\n                    // Got it! Now extract the fractional second\n                    auto last_before_Z = std::end(resultString) - 1;\n                    ufrac_second = timeticks_from_second(last_dot, last_before_Z);\n                    // And erase it from the string\n                    resultString.erase(last_dot, last_before_Z);\n                }\n            }\n        }\n    }\n\n#ifdef _WIN32\n    bool datetime::system_type_to_datetime(void* pvsysTime, uint64_t seconds, datetime* pdt)\n    {\n        SYSTEMTIME* psysTime = (SYSTEMTIME*)pvsysTime;\n        FILETIME fileTime;\n\n        if (SystemTimeToFileTime(psysTime, &fileTime))\n        {\n            ULARGE_INTEGER largeInt;\n            largeInt.LowPart = fileTime.dwLowDateTime;\n            largeInt.HighPart = fileTime.dwHighDateTime;\n\n            // Add hundredths of nanoseconds\n            largeInt.QuadPart += seconds;\n\n            *pdt = datetime(largeInt.QuadPart);\n            return true;\n        }\n        return false;\n    }\n#endif\n\n    datetime datetime::from_string(const xsapi_internal_string& dateString, date_format format)\n    {\n        // avoid floating point math to preserve precision\n        uint64_t ufrac_second = 0;\n\n#ifdef _WIN32\n        datetime result;\n        if (format == RFC_1123)\n        {\n            SYSTEMTIME sysTime = { 0 };\n\n            xsapi_internal_string month(3, '\\0');\n            xsapi_internal_string unused(3, '\\0');\n\n            const char* formatString = \"%3c, %2d %3c %4d %2d:%2d:%2d %3c\";\n            auto n = sscanf_s(dateString.c_str(), formatString,\n                unused.data(), unused.size(),\n                &sysTime.wDay,\n                month.data(), month.size(),\n                &sysTime.wYear,\n                &sysTime.wHour,\n                &sysTime.wMinute,\n                &sysTime.wSecond,\n                unused.data(), unused.size());\n\n            if (n == 8)\n            {\n                xsapi_internal_string monthnames[12] = { \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" };\n                auto loc = std::find_if(monthnames, monthnames + 12, [&month](const xsapi_internal_string& m) { return m == month; });\n\n                if (loc != monthnames + 12)\n                {\n                    sysTime.wMonth = (short)((loc - monthnames) + 1);\n                    if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                    {\n                        return result;\n                    }\n                }\n            }\n        }\n        else if (format == ISO_8601)\n        {\n            // Unlike FILETIME, SYSTEMTIME does not have enough precision to hold seconds in 100 nanosecond\n            // increments. Therefore, start with seconds and milliseconds set to 0, then add them separately\n\n            // Try to extract the fractional second from the timestamp\n            xsapi_internal_string input;\n            extract_fractional_second(dateString, input, ufrac_second);\n            {\n                SYSTEMTIME sysTime = { 0 };\n                const char* formatString = \"%4d-%2d-%2dT%2d:%2d:%2dZ\";\n                auto n = sscanf_s(input.c_str(), formatString,\n                    &sysTime.wYear,\n                    &sysTime.wMonth,\n                    &sysTime.wDay,\n                    &sysTime.wHour,\n                    &sysTime.wMinute,\n                    &sysTime.wSecond);\n\n                if (n == 3 || n == 6)\n                {\n                    if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                    {\n                        return result;\n                    }\n                }\n            }\n            {\n                SYSTEMTIME sysTime = { 0 };\n                DWORD date = 0;\n\n                const char* formatString = \"%8dT%2d:%2d:%2dZ\";\n                auto n = sscanf_s(input.c_str(), formatString,\n                    &date,\n                    &sysTime.wHour,\n                    &sysTime.wMinute,\n                    &sysTime.wSecond);\n\n                if (n == 1 || n == 4)\n                {\n                    sysTime.wDay = date % 100;\n                    date /= 100;\n                    sysTime.wMonth = date % 100;\n                    date /= 100;\n                    sysTime.wYear = (WORD)date;\n\n                    if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                    {\n                        return result;\n                    }\n                }\n            }\n            {\n                SYSTEMTIME sysTime = { 0 };\n                GetSystemTime(&sysTime);    // Fill date portion with today's information\n                sysTime.wSecond = 0;\n                sysTime.wMilliseconds = 0;\n\n                const char* formatString = \"%2d:%2d:%2dZ\";\n                auto n = sscanf_s(input.c_str(), formatString,\n                    &sysTime.wHour,\n                    &sysTime.wMinute,\n                    &sysTime.wSecond);\n\n                if (n == 3)\n                {\n                    if (system_type_to_datetime(&sysTime, ufrac_second, &result))\n                    {\n                        return result;\n                    }\n                }\n            }\n        }\n\n        return datetime();\n#else\n        xsapi_internal_string input(dateString);\n\n        struct tm output = tm();\n\n        if (format == RFC_1123)\n        {\n            strptime(input.data(), \"%a, %d %b %Y %H:%M:%S GMT\", &output);\n        }\n        else\n        {\n            // Try to extract the fractional second from the timestamp\n            xsapi_internal_string input;\n            extract_fractional_second(dateString, input, ufrac_second);\n\n            auto result = strptime(input.data(), \"%Y-%m-%dT%H:%M:%SZ\", &output);\n\n            if (result == nullptr)\n            {\n                result = strptime(input.data(), \"%Y%m%dT%H:%M:%SZ\", &output);\n            }\n            if (result == nullptr)\n            {\n                // Fill the date portion with the epoch,\n                // strptime will do the rest\n                memset(&output, 0, sizeof(struct tm));\n                output.tm_year = 70;\n                output.tm_mon = 1;\n                output.tm_mday = 1;\n                result = strptime(input.data(), \"%H:%M:%SZ\", &output);\n            }\n            if (result == nullptr)\n            {\n                result = strptime(input.data(), \"%Y-%m-%d\", &output);\n            }\n            if (result == nullptr)\n            {\n                result = strptime(input.data(), \"%Y%m%d\", &output);\n            }\n            if (result == nullptr)\n            {\n                return datetime();\n            }\n        }\n\n#if (defined(ANDROID) || defined(__ANDROID__))\n        // HACK: The (nonportable?) POSIX function timegm is not available in\n        //       bionic. As a workaround[1][2], we set the C library timezone to\n        //       UTC, call mktime, then set the timezone back. However, the C\n        //       environment is fundamentally a shared global resource and thread-\n        //       unsafe. We can protect our usage here, however any other code might\n        //       manipulate the environment at the same time.\n        //\n        // [1] http://linux.die.net/man/3/timegm\n        // [2] http://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html\n        time_t time;\n\n        static std::mutex env_var_lock;\n        {\n            std::lock_guard<std::mutex> lock(env_var_lock);\n            xsapi_internal_string prev_env;\n            auto prev_env_cstr = getenv(\"TZ\");\n            if (prev_env_cstr != nullptr)\n            {\n                prev_env = prev_env_cstr;\n            }\n            setenv(\"TZ\", \"UTC\", 1);\n\n            time = mktime(&output);\n\n            if (prev_env_cstr)\n            {\n                setenv(\"TZ\", prev_env.c_str(), 1);\n            }\n            else\n            {\n                unsetenv(\"TZ\");\n            }\n            tzset();\n        }\n#else\n        time_t time = timegm(&output);\n#endif\n        struct timeval tv = timeval();\n        tv.tv_sec = time;\n        auto result = timeval_to_datetime(tv);\n\n        // fractional seconds are already in correct format so just add them.\n        result = result + ufrac_second;\n        return result;\n#endif\n    }\n\n#define LOW_3BITS 0x7\n#define LOW_4BITS 0xF\n#define LOW_5BITS 0x1F\n#define LOW_6BITS 0x3F\n#define BIT4 0x8\n#define BIT5 0x10\n#define BIT6 0x20\n#define BIT7 0x40\n#define BIT8 0x80\n#define L_SURROGATE_START 0xDC00\n#define L_SURROGATE_END 0xDFFF\n#define H_SURROGATE_START 0xD800\n#define H_SURROGATE_END 0xDBFF\n#define SURROGATE_PAIR_START 0x10000\n\n    xsapi_internal_wstring convert::utf8_to_utf16(const xsapi_internal_string &s)\n    {\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n        std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n        return conversion.from_bytes(s);\n#else\n        xsapi_internal_wstring dest;\n        // Save repeated heap allocations, use less than source string size assuming some\n        // of the characters are not just ASCII and collapse.\n        dest.reserve(static_cast<size_t>(static_cast<double>(s.size()) * .70));\n\n        for (auto src = s.begin(); src != s.end(); ++src)\n        {\n            if ((*src & BIT8) == 0) // single byte character, 0x0 to 0x7F\n            {\n                dest.push_back(xsapi_internal_wstring::value_type(*src));\n            }\n            else\n            {\n                unsigned char numContBytes = 0;\n                uint32_t codePoint;\n                if ((*src & BIT7) == 0)\n                {\n                    throw std::range_error(\"UTF-8 string character can never start with 10xxxxxx\");\n                }\n                else if ((*src & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF\n                {\n                    codePoint = *src & LOW_5BITS;\n                    numContBytes = 1;\n                }\n                else if ((*src & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF\n                {\n                    codePoint = *src & LOW_4BITS;\n                    numContBytes = 2;\n                }\n                else if ((*src & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF\n                {\n                    codePoint = *src & LOW_3BITS;\n                    numContBytes = 3;\n                }\n                else\n                {\n                    throw std::range_error(\"UTF-8 string has invalid Unicode code point\");\n                }\n\n                for (unsigned char i = 0; i < numContBytes; ++i)\n                {\n                    if (++src == s.end())\n                    {\n                        throw std::range_error(\"UTF-8 string is missing bytes in character\");\n                    }\n                    if ((*src & BIT8) == 0 || (*src & BIT7) != 0)\n                    {\n                        throw std::range_error(\"UTF-8 continuation byte is missing leading byte\");\n                    }\n                    codePoint <<= 6;\n                    codePoint |= *src & LOW_6BITS;\n                }\n\n                if (codePoint >= SURROGATE_PAIR_START)\n                {\n                    // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs.\n                    //  - 0x10000 is subtracted from the code point\n                    //  - high surrogate is 0xD800 added to the top ten bits\n                    //  - low surrogate is 0xDC00 added to the low ten bits\n                    codePoint -= SURROGATE_PAIR_START;\n                    dest.push_back(xsapi_internal_wstring::value_type((codePoint >> 10) | H_SURROGATE_START));\n                    dest.push_back(xsapi_internal_wstring::value_type((codePoint & 0x3FF) | L_SURROGATE_START));\n                }\n                else\n                {\n                    // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value.\n                    // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode\n                    // them if encountered.\n                    dest.push_back(xsapi_internal_wstring::value_type(codePoint));\n                }\n            }\n        }\n        return dest;\n#endif\n    }\n\n    xsapi_internal_string convert::to_utf8string(xsapi_internal_string value) { return value; }\n\n    xsapi_internal_string convert::to_utf8string(const xsapi_internal_wstring &value) { return utf16_to_utf8_internal(value); }\n\n    std::string convert::utf16_to_utf8(const std::wstring &w)\n    {\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n        std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n        return conversion.to_bytes(w);\n#else\n        std::string dest;\n        dest.reserve(w.size());\n        for (auto src = w.begin(); src != w.end(); ++src)\n        {\n            // Check for high surrogate.\n            if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END)\n            {\n                const auto highSurrogate = *src++;\n                if (src == w.end())\n                {\n                    throw std::range_error(\"UTF-16 string is missing low surrogate\");\n                }\n                const auto lowSurrogate = *src;\n                if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END)\n                {\n                    throw std::range_error(\"UTF-16 string has invalid low surrogate\");\n                }\n\n                // To get from surrogate pair to Unicode code point:\n                // - subract 0xD800 from high surrogate, this forms top ten bits\n                // - subract 0xDC00 from low surrogate, this forms low ten bits\n                // - add 0x10000\n                // Leaves a code point in U+10000 to U+10FFFF range.\n                uint32_t codePoint = highSurrogate - H_SURROGATE_START;\n                codePoint <<= 10;\n                codePoint |= lowSurrogate - L_SURROGATE_START;\n                codePoint += SURROGATE_PAIR_START;\n\n                // 4 bytes need using 21 bits\n                dest.push_back(char((codePoint >> 18) | 0xF0));                 // leading 3 bits\n                dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8));   // next 6 bits\n                dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8));    // next 6 bits\n                dest.push_back(char((codePoint & LOW_6BITS) | BIT8));           // trailing 6 bits\n            }\n            else\n            {\n                if (*src <= 0x7F) // single byte character\n                {\n                    dest.push_back(static_cast<char>(*src));\n                }\n                else if (*src <= 0x7FF) // 2 bytes needed (11 bits used)\n                {\n                    dest.push_back(char((*src >> 6) | 0xC0));               // leading 5 bits\n                    dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n                }\n                else // 3 bytes needed (16 bits used)\n                {\n                    dest.push_back(char((*src >> 12) | 0xE0));              // leading 4 bits\n                    dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits\n                    dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n                }\n            }\n        }\n\n        return dest;\n#endif\n    }\n\n    xsapi_internal_string convert::utf16_to_utf8_internal(const xsapi_internal_wstring &w)\n    {\n#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)\n        std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;\n        return conversion.to_bytes(w);\n#else\n        xsapi_internal_string dest;\n        dest.reserve(w.size());\n        for (auto src = w.begin(); src != w.end(); ++src)\n        {\n            // Check for high surrogate.\n            if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END)\n            {\n                const auto highSurrogate = *src++;\n                if (src == w.end())\n                {\n                    throw std::range_error(\"UTF-16 string is missing low surrogate\");\n                }\n                const auto lowSurrogate = *src;\n                if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END)\n                {\n                    throw std::range_error(\"UTF-16 string has invalid low surrogate\");\n                }\n\n                // To get from surrogate pair to Unicode code point:\n                // - subract 0xD800 from high surrogate, this forms top ten bits\n                // - subract 0xDC00 from low surrogate, this forms low ten bits\n                // - add 0x10000\n                // Leaves a code point in U+10000 to U+10FFFF range.\n                uint32_t codePoint = highSurrogate - H_SURROGATE_START;\n                codePoint <<= 10;\n                codePoint |= lowSurrogate - L_SURROGATE_START;\n                codePoint += SURROGATE_PAIR_START;\n\n                // 4 bytes need using 21 bits\n                dest.push_back(char((codePoint >> 18) | 0xF0));                 // leading 3 bits\n                dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8));   // next 6 bits\n                dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8));    // next 6 bits\n                dest.push_back(char((codePoint & LOW_6BITS) | BIT8));           // trailing 6 bits\n            }\n            else\n            {\n                if (*src <= 0x7F) // single byte character\n                {\n                    dest.push_back(static_cast<char>(*src));\n                }\n                else if (*src <= 0x7FF) // 2 bytes needed (11 bits used)\n                {\n                    dest.push_back(char((*src >> 6) | 0xC0));               // leading 5 bits\n                    dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n                }\n                else // 3 bytes needed (16 bits used)\n                {\n                    dest.push_back(char((*src >> 12) | 0xE0));              // leading 4 bits\n                    dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits\n                    dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits\n                }\n            }\n        }\n\n        return dest;\n#endif\n    }\n\n    xsapi_internal_string convert::to_base64(const Vector<unsigned char>& input)\n    {\n        if (input.size() == 0)\n        {\n            // return empty string\n            return String();\n        }\n\n        return detail::_to_base64(&input[0], input.size());\n    }\n\n    std::vector<unsigned char> convert::from_base64(const xsapi_internal_string& str)\n    {\n        return detail::_from_base64(str);\n    }\n\n    namespace details\n    {\n\n        const std::error_category & platform_category()\n        {\n#ifdef _WIN32\n            return windows_category();\n#else\n            return linux_category();\n#endif\n        }\n\n#ifdef _WIN32\n\n        // Remove once VS 2013 is no longer supported.\n#if _MSC_VER < 1900\n        static details::windows_category_impl instance;\n#endif\n        const std::error_category & windows_category()\n        {\n#if _MSC_VER >= 1900\n            static details::windows_category_impl instance;\n#endif\n            return instance;\n        }\n\n        std::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT\n        {\n#if 0 // this returns a non-mem hooked string which can't be changed so commenting it out since its not really needed\n            const size_t buffer_size = 4096;\n            DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;\n            LPCVOID lpSource = NULL;\n\n#if !defined(__cplusplus_winrt)\n            if (errorCode >= 12000)\n            {\n                dwFlags = FORMAT_MESSAGE_FROM_HMODULE;\n                lpSource = GetModuleHandleA(\"winhttp.dll\"); // this handle DOES NOT need to be freed\n            }\n#endif\n\n            std::wstring buffer;\n            buffer.resize(buffer_size);\n\n            const auto result = ::FormatMessageW(\n                dwFlags,\n                lpSource,\n                errorCode,\n                0,\n                &buffer[0],\n                buffer_size,\n                NULL);\n            if (result == 0)\n            {\n                std::ostringstream os;\n                os << \"Unable to get an error message for error code: \" << errorCode << \".\";\n                return os.str();\n            }\n            return convert::to_utf8string(buffer);\n#else\n            UNREFERENCED_PARAMETER(errorCode);\n            return std::string();\n#endif\n        }\n\n        std::error_condition windows_category_impl::default_error_condition(int errorCode) const CPPREST_NOEXCEPT\n        {\n            // First see if the STL implementation can handle the mapping for common cases.\n            const std::error_condition errCondition = std::system_category().default_error_condition(errorCode);\n            const std::string errConditionMsg = errCondition.message();\n            if (_stricmp(errConditionMsg.c_str(), \"unknown error\") != 0)\n            {\n                return errCondition;\n            }\n\n            switch (errorCode)\n            {\n#ifndef __cplusplus_winrt\n            case ERROR_WINHTTP_TIMEOUT:\n                return std::errc::timed_out;\n            case ERROR_WINHTTP_CANNOT_CONNECT:\n                return std::errc::host_unreachable;\n            case ERROR_WINHTTP_CONNECTION_ERROR:\n                return std::errc::connection_aborted;\n#endif\n            case INET_E_RESOURCE_NOT_FOUND:\n            case INET_E_CANNOT_CONNECT:\n                return std::errc::host_unreachable;\n            case INET_E_CONNECTION_TIMEOUT:\n                return std::errc::timed_out;\n            case INET_E_DOWNLOAD_FAILURE:\n                return std::errc::connection_aborted;\n            default:\n                break;\n            }\n\n            return std::error_condition(errorCode, *this);\n        }\n\n#else\n\n        const std::error_category & linux_category()\n        {\n            // On Linux we are using boost error codes which have the exact same\n            // mapping and are equivalent with std::generic_category error codes.\n            return std::generic_category();\n        }\n\n#endif\n    }\n\n\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 26444 ) // ignore various unnamed objects\n#pragma warning( disable : 26812 )  // enum instead of enum class\n#endif\n\nnamespace services\n{\n    namespace details\n    {\n        xsapi_internal_string uri_components::join()\n        {\n            // canonicalize components first\n\n            // convert scheme to lowercase\n            std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [](char c) {\n                return (char)tolower(c);\n                });\n\n            // convert host to lowercase\n            std::transform(m_host.begin(), m_host.end(), m_host.begin(), [](char c) {\n                return (char)tolower(c);\n                });\n\n            // canonicalize the path to have a leading slash if it's a full uri\n            if (!m_host.empty() && m_path.empty())\n            {\n                m_path = \"/\";\n            }\n            else if (!m_host.empty() && m_path[0] != '/')\n            {\n                m_path.insert(m_path.begin(), 1, '/');\n            }\n\n            xsapi_internal_string ret;\n\n#if (defined(_MSC_VER) && (_MSC_VER >= 1800))\n            if (!m_scheme.empty())\n            {\n                ret.append(m_scheme).append({ ':' });\n            }\n\n            if (!m_host.empty())\n            {\n                ret.append(\"//\");\n\n                if (!m_user_info.empty())\n                {\n                    ret.append(m_user_info).append({ '@' });\n                }\n\n                ret.append(m_host);\n\n                if (m_port > 0)\n                {\n                    char buf[16] = { 0 };\n                    sprintf_s(buf, sizeof(buf), \":%d\", m_port);\n                    ret.append(buf);\n                }\n            }\n\n            if (!m_path.empty())\n            {\n                // only add the leading slash when the host is present\n                if (!m_host.empty() && m_path.front() != '/')\n                {\n                    ret.append({ '/' });\n                }\n\n                ret.append(m_path);\n            }\n\n            if (!m_query.empty())\n            {\n                ret.append({ '?' }).append(m_query);\n            }\n\n            if (!m_fragment.empty())\n            {\n                ret.append({ '#' }).append(m_fragment);\n            }\n\n            return ret;\n#else\n            xsapi_internal_ostringstream_t os;\n            os.imbue(std::locale::classic());\n\n            if (!m_scheme.empty())\n            {\n                os << m_scheme << ':';\n            }\n\n            if (!m_host.empty())\n            {\n                os << \"//\";\n\n                if (!m_user_info.empty())\n                {\n                    os << m_user_info << '@';\n                }\n\n                os << m_host;\n\n                if (m_port > 0)\n                {\n                    os << ':' << m_port;\n                }\n            }\n\n            if (!m_path.empty())\n            {\n                // only add the leading slash when the host is present\n                if (!m_host.empty() && m_path.front() != '/')\n                {\n                    os << '/';\n                }\n                os << m_path;\n            }\n\n            if (!m_query.empty())\n            {\n                os << '?' << m_query;\n            }\n\n            if (!m_fragment.empty())\n            {\n                os << '#' << m_fragment;\n            }\n\n            return os.str();\n#endif\n        }\n\n        namespace uri_parser\n        {\n\n            bool validate(const xsapi_internal_string& encoded_string)\n            {\n                const char* scheme_begin = nullptr;\n                const char* scheme_end = nullptr;\n                const char* uinfo_begin = nullptr;\n                const char* uinfo_end = nullptr;\n                const char* host_begin = nullptr;\n                const char* host_end = nullptr;\n                int port_ptr = 0;\n                const char* path_begin = nullptr;\n                const char* path_end = nullptr;\n                const char* query_begin = nullptr;\n                const char* query_end = nullptr;\n                const char* fragment_begin = nullptr;\n                const char* fragment_end = nullptr;\n\n                // perform a parse, but don't copy out the data\n                return inner_parse(\n                    encoded_string.c_str(),\n                    &scheme_begin,\n                    &scheme_end,\n                    &uinfo_begin,\n                    &uinfo_end,\n                    &host_begin,\n                    &host_end,\n                    &port_ptr,\n                    &path_begin,\n                    &path_end,\n                    &query_begin,\n                    &query_end,\n                    &fragment_begin,\n                    &fragment_end);\n            }\n\n            bool parse(const xsapi_internal_string& encoded_string, uri_components& components)\n            {\n                const char* scheme_begin = nullptr;\n                const char* scheme_end = nullptr;\n                const char* host_begin = nullptr;\n                const char* host_end = nullptr;\n                const char* uinfo_begin = nullptr;\n                const char* uinfo_end = nullptr;\n                int port_ptr = 0;\n                const char* path_begin = nullptr;\n                const char* path_end = nullptr;\n                const char* query_begin = nullptr;\n                const char* query_end = nullptr;\n                const char* fragment_begin = nullptr;\n                const char* fragment_end = nullptr;\n\n                if (inner_parse(\n                    encoded_string.c_str(),\n                    &scheme_begin,\n                    &scheme_end,\n                    &uinfo_begin,\n                    &uinfo_end,\n                    &host_begin,\n                    &host_end,\n                    &port_ptr,\n                    &path_begin,\n                    &path_end,\n                    &query_begin,\n                    &query_end,\n                    &fragment_begin,\n                    &fragment_end))\n                {\n                    if (scheme_begin)\n                    {\n                        components.m_scheme.assign(scheme_begin, scheme_end);\n\n                        // convert scheme to lowercase\n                        std::transform(components.m_scheme.begin(), components.m_scheme.end(), components.m_scheme.begin(), [](char c) {\n                            return (char)tolower(c);\n                            });\n                    }\n                    else\n                    {\n                        components.m_scheme.clear();\n                    }\n\n                    if (uinfo_begin)\n                    {\n                        components.m_user_info.assign(uinfo_begin, uinfo_end);\n                    }\n\n                    if (host_begin)\n                    {\n                        components.m_host.assign(host_begin, host_end);\n\n                        // convert host to lowercase\n                        std::transform(components.m_host.begin(), components.m_host.end(), components.m_host.begin(), [](char c) {\n                            return (char)tolower(c);\n                            });\n                    }\n                    else\n                    {\n                        components.m_host.clear();\n                    }\n\n                    if (port_ptr)\n                    {\n                        components.m_port = port_ptr;\n                    }\n                    else\n                    {\n                        components.m_port = 0;\n                    }\n\n                    if (path_begin)\n                    {\n                        components.m_path.assign(path_begin, path_end);\n                    }\n                    else\n                    {\n                        // default path to begin with a slash for easy comparison\n                        components.m_path = \"/\";\n                    }\n\n                    if (query_begin)\n                    {\n                        components.m_query.assign(query_begin, query_end);\n                    }\n                    else\n                    {\n                        components.m_query.clear();\n                    }\n\n                    if (fragment_begin)\n                    {\n                        components.m_fragment.assign(fragment_begin, fragment_end);\n                    }\n                    else\n                    {\n                        components.m_fragment.clear();\n                    }\n\n                    return true;\n                }\n                else\n                {\n                    return false;\n                }\n            }\n\n            bool inner_parse(\n                const char* encoded,\n                const char** scheme_begin, const char** scheme_end,\n                const char** uinfo_begin, const char** uinfo_end,\n                const char** host_begin, const char** host_end,\n                _Out_ int* port,\n                const char** path_begin, const char** path_end,\n                const char** query_begin, const char** query_end,\n                const char** fragment_begin, const char** fragment_end)\n            {\n                *scheme_begin = nullptr;\n                *scheme_end = nullptr;\n                *uinfo_begin = nullptr;\n                *uinfo_end = nullptr;\n                *host_begin = nullptr;\n                *host_end = nullptr;\n                *port = 0;\n                *path_begin = nullptr;\n                *path_end = nullptr;\n                *query_begin = nullptr;\n                *query_end = nullptr;\n                *fragment_begin = nullptr;\n                *fragment_end = nullptr;\n\n                const char* p = encoded;\n\n                // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference\n                // Absolute: 'http://host.com'\n                // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2'\n                // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash\n\n                bool is_relative_reference = true;\n                const char* p2 = p;\n                for (; *p2 != '/' && *p2 != '\\0'; p2++)\n                {\n                    if (*p2 == ':')\n                    {\n                        // found a colon, the first portion is a scheme\n                        is_relative_reference = false;\n                        break;\n                    }\n                }\n\n                if (!is_relative_reference)\n                {\n                    // the first character of a scheme must be a letter\n                    if (!isalpha(*p))\n                    {\n                        return false;\n                    }\n\n                    // start parsing the scheme, it's always delimited by a colon (must be present)\n                    *scheme_begin = p++;\n                    for (; *p != ':'; p++)\n                    {\n                        if (!is_scheme_character(*p))\n                        {\n                            return false;\n                        }\n                    }\n                    *scheme_end = p;\n\n                    // skip over the colon\n                    p++;\n                }\n\n                // if we see two slashes next, then we're going to parse the authority portion\n                // later on we'll break up the authority into the port and host\n                const char* authority_begin = nullptr;\n                const char* authority_end = nullptr;\n                if (*p == '/' && p[1] == '/')\n                {\n                    // skip over the slashes\n                    p += 2;\n                    authority_begin = p;\n\n                    // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment)\n                    // or by EOS. The authority could be empty ('file:///C:\\file_name.txt')\n                    for (; *p != '/' && *p != '?' && *p != '#' && *p != '\\0'; p++)\n                    {\n                        // We're NOT currently supporting IPv6, IPvFuture or username/password in authority\n                        if (!is_authority_character(*p))\n                        {\n                            return false;\n                        }\n                    }\n                    authority_end = p;\n\n                    // now lets see if we have a port specified -- by working back from the end\n                    if (authority_begin != authority_end)\n                    {\n                        // the port is made up of all digits\n                        const char* port_begin = authority_end - 1;\n                        for (; isdigit(*port_begin) && port_begin != authority_begin; port_begin--)\n                        {\n                        }\n\n                        if (*port_begin == ':')\n                        {\n                            // has a port\n                            *host_begin = authority_begin;\n                            *host_end = port_begin;\n\n                            //skip the colon\n                            port_begin++;\n\n                            *port = convert::scan_string<int>(xsapi_internal_string(port_begin, authority_end), std::locale::classic());\n                        }\n                        else\n                        {\n                            // no port\n                            *host_begin = authority_begin;\n                            *host_end = authority_end;\n                        }\n\n                        // look for a user_info component\n                        const char* u_end = *host_begin;\n                        for (; is_user_info_character(*u_end) && u_end != *host_end; u_end++)\n                        {\n                        }\n\n                        if (*u_end == '@')\n                        {\n                            *host_begin = u_end + 1;\n                            *uinfo_begin = authority_begin;\n                            *uinfo_end = u_end;\n                        }\n                        else\n                        {\n                            uinfo_end = uinfo_begin = nullptr;\n                        }\n                    }\n                }\n\n                // if we see a path character or a slash, then the\n                // if we see a slash, or any other legal path character, parse the path next\n                if (*p == '/' || is_path_character(*p))\n                {\n                    *path_begin = p;\n\n                    // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS\n                    for (; *p != '?' && *p != '#' && *p != '\\0'; p++)\n                    {\n                        if (!is_path_character(*p))\n                        {\n                            return false;\n                        }\n                    }\n                    *path_end = p;\n                }\n\n                // if we see a ?, then the query is next\n                if (*p == '?')\n                {\n                    // skip over the question mark\n                    p++;\n                    *query_begin = p;\n\n                    // the query is delimited by a '#' (fragment) or EOS\n                    for (; *p != '#' && *p != '\\0'; p++)\n                    {\n                        if (!is_query_character(*p))\n                        {\n                            return false;\n                        }\n                    }\n                    *query_end = p;\n                }\n\n                // if we see a #, then the fragment is next\n                if (*p == '#')\n                {\n                    // skip over the hash mark\n                    p++;\n                    *fragment_begin = p;\n\n                    // the fragment is delimited by EOS\n                    for (; *p != '\\0'; p++)\n                    {\n                        if (!is_fragment_character(*p))\n                        {\n                            return false;\n                        }\n                    }\n                    *fragment_end = p;\n                }\n\n                return true;\n            }\n\n        }\n\n\n    }\n\n    using namespace details;\n\n    uri::uri(const details::uri_components& components) : m_components(components)\n    {\n        m_uri = m_components.join();\n        if (!details::uri_parser::validate(m_uri))\n        {\n            throw uri_exception(\"provided uri is invalid: \" + convert::to_utf8string(m_uri));\n        }\n    }\n\n    uri::uri(const xsapi_internal_string& uri_string)\n    {\n        if (!details::uri_parser::parse(uri_string, m_components))\n        {\n            throw uri_exception(\"provided uri is invalid: \" + convert::to_utf8string(uri_string));\n        }\n        m_uri = m_components.join();\n    }\n\n    uri::uri(const char* uri_string) : m_uri(uri_string)\n    {\n        if (!details::uri_parser::parse(uri_string, m_components))\n        {\n            throw uri_exception(\"provided uri is invalid: \" + convert::to_utf8string(uri_string));\n        }\n        m_uri = m_components.join();\n    }\n\n    xsapi_internal_string uri::encode_impl(const xsapi_internal_string& utf8raw, const std::function<bool(int)>& should_encode)\n    {\n        const char* const hex = \"0123456789ABCDEF\";\n        xsapi_internal_string encoded;\n        for (auto iter = utf8raw.begin(); iter != utf8raw.end(); ++iter)\n        {\n            // for utf8 encoded string, char ASCII can be greater than 127.\n            int ch = static_cast<unsigned char>(*iter);\n            // ch should be same under both utf8 and utf16.\n            if (should_encode(ch))\n            {\n                encoded.push_back('%');\n                encoded.push_back(hex[(ch >> 4) & 0xF]);\n                encoded.push_back(hex[ch & 0xF]);\n            }\n            else\n            {\n                // ASCII don't need to be encoded, which should be same on both utf8 and utf16.\n                encoded.push_back((char)ch);\n            }\n        }\n        return encoded;\n    }\n\n    /// <summary>\n    /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their\n    /// hexadecimal representation.\n    /// </summary>\n    xsapi_internal_string uri::encode_data_string(const xsapi_internal_string& raw)\n    {\n        return uri::encode_impl(raw, [](int ch) -> bool\n            {\n                return !uri_parser::is_unreserved(ch);\n            });\n    }\n\n    xsapi_internal_string uri::encode_uri(const xsapi_internal_string& raw, uri::components::component component)\n    {\n        // Note: we also encode the '+' character because some non-standard implementations\n        // encode the space character as a '+' instead of %20. To better interoperate we encode\n        // '+' to avoid any confusion and be mistaken as a space.\n        switch (component)\n        {\n        case components::user_info:\n            return uri::encode_impl(raw, [](int ch) -> bool\n                {\n                    return !uri_parser::is_user_info_character(ch)\n                        || ch == '%' || ch == '+';\n                });\n        case components::host:\n            return uri::encode_impl(raw, [](int ch) -> bool\n                {\n                    // No encoding of ASCII characters in host name (RFC 3986 3.2.2)\n                    return ch > 127;\n                });\n        case components::path:\n            return uri::encode_impl(raw, [](int ch) -> bool\n                {\n                    return !uri_parser::is_path_character(ch)\n                        || ch == '%' || ch == '+';\n                });\n        case components::query:\n            return uri::encode_impl(raw, [](int ch) -> bool\n                {\n                    return !uri_parser::is_query_character(ch)\n                        || ch == '%' || ch == '+';\n                });\n        case components::fragment:\n            return uri::encode_impl(raw, [](int ch) -> bool\n                {\n                    return !uri_parser::is_fragment_character(ch)\n                        || ch == '%' || ch == '+';\n                });\n        case components::full_uri:\n        default:\n            return uri::encode_impl(raw, [](int ch) -> bool\n                {\n                    return !uri_parser::is_unreserved(ch) && !uri_parser::is_reserved(ch);\n                });\n        };\n    }\n\n    /// <summary>\n    /// Helper function to convert a hex character digit to a decimal character value.\n    /// Throws an exception if not a valid hex digit.\n    /// </summary>\n    static int hex_char_digit_to_decimal_char(int hex)\n    {\n        int decimal;\n        if (hex >= '0' && hex <= '9')\n        {\n            decimal = hex - '0';\n        }\n        else if (hex >= 'A' && hex <= 'F')\n        {\n            decimal = 10 + (hex - 'A');\n        }\n        else if (hex >= 'a' && hex <= 'f')\n        {\n            decimal = 10 + (hex - 'a');\n        }\n        else\n        {\n            throw uri_exception(\"Invalid hexadecimal digit\");\n        }\n        return decimal;\n    }\n\n    xsapi_internal_string uri::decode(const xsapi_internal_string& encoded)\n    {\n        xsapi_internal_string utf8raw;\n        for (auto iter = encoded.begin(); iter != encoded.end(); ++iter)\n        {\n            if (*iter == '%')\n            {\n                if (++iter == encoded.end())\n                {\n                    throw uri_exception(\"Invalid URI string, two hexadecimal digits must follow '%'\");\n                }\n                int decimal_value = hex_char_digit_to_decimal_char(static_cast<int>(*iter)) << 4;\n                if (++iter == encoded.end())\n                {\n                    throw uri_exception(\"Invalid URI string, two hexadecimal digits must follow '%'\");\n                }\n                decimal_value += hex_char_digit_to_decimal_char(static_cast<int>(*iter));\n\n                utf8raw.push_back(static_cast<char>(decimal_value));\n            }\n            else\n            {\n                // encoded string has to be ASCII.\n                utf8raw.push_back(reinterpret_cast<const char&>(*iter));\n            }\n        }\n        return utf8raw;\n    }\n\n    std::vector<xsapi_internal_string> uri::split_path(const xsapi_internal_string& path)\n    {\n        std::vector<xsapi_internal_string> results;\n        xsapi_internal_istringstream iss(path);\n        iss.imbue(std::locale::classic());\n        xsapi_internal_string s;\n\n        while (std::getline(iss, s, '/'))\n        {\n            if (!s.empty())\n            {\n                results.push_back(s);\n            }\n        }\n\n        return results;\n    }\n\n    std::map<xsapi_internal_string, xsapi_internal_string> uri::split_query(const xsapi_internal_string& query)\n    {\n        std::map<xsapi_internal_string, xsapi_internal_string> results;\n\n        // Split into key value pairs separated by '&'.\n        size_t prev_amp_index = 0;\n        while (prev_amp_index != xsapi_internal_string::npos)\n        {\n            size_t amp_index = query.find_first_of('&', prev_amp_index);\n            if (amp_index == xsapi_internal_string::npos)\n                amp_index = query.find_first_of(';', prev_amp_index);\n\n            xsapi_internal_string key_value_pair = query.substr(\n                prev_amp_index,\n                amp_index == xsapi_internal_string::npos ? query.size() - prev_amp_index : amp_index - prev_amp_index);\n            prev_amp_index = amp_index == xsapi_internal_string::npos ? xsapi_internal_string::npos : amp_index + 1;\n\n            size_t equals_index = key_value_pair.find_first_of('=');\n            if (equals_index == xsapi_internal_string::npos)\n            {\n                continue;\n            }\n            else if (equals_index == 0)\n            {\n                xsapi_internal_string value(key_value_pair.begin() + equals_index + 1, key_value_pair.end());\n                results[\"\"] = value;\n            }\n            else\n            {\n                xsapi_internal_string key(key_value_pair.begin(), key_value_pair.begin() + equals_index);\n                xsapi_internal_string value(key_value_pair.begin() + equals_index + 1, key_value_pair.end());\n                results[key] = value;\n            }\n        }\n\n        return results;\n    }\n\n    bool uri::validate(const xsapi_internal_string& uri_string)\n    {\n        return uri_parser::validate(uri_string);\n    }\n\n    uri uri::authority() const\n    {\n        return uri_builder().set_scheme(this->scheme()).set_host(this->host()).set_port(this->port()).set_user_info(this->user_info()).to_uri();\n    }\n\n    uri uri::resource() const\n    {\n        return uri_builder().set_path(this->path()).set_query(this->query()).set_fragment(this->fragment()).to_uri();\n    }\n\n    bool uri::operator == (const uri& other) const\n    {\n        // Each individual URI component must be decoded before performing comparison.\n        // TFS # 375865\n\n        if (this->is_empty() && other.is_empty())\n        {\n            return true;\n        }\n        else if (this->is_empty() || other.is_empty())\n        {\n            return false;\n        }\n        else if (this->scheme() != other.scheme())\n        {\n            // scheme is canonicalized to lowercase\n            return false;\n        }\n        else if (uri::decode(this->user_info()) != uri::decode(other.user_info()))\n        {\n            return false;\n        }\n        else if (uri::decode(this->host()) != uri::decode(other.host()))\n        {\n            // host is canonicalized to lowercase\n            return false;\n        }\n        else if (this->port() != other.port())\n        {\n            return false;\n        }\n        else if (uri::decode(this->path()) != uri::decode(other.path()))\n        {\n            return false;\n        }\n        else if (uri::decode(this->query()) != uri::decode(other.query()))\n        {\n            return false;\n        }\n        else if (uri::decode(this->fragment()) != uri::decode(other.fragment()))\n        {\n            return false;\n        }\n\n        return true;\n    }\n\n\n    uri_builder& uri_builder::append_path(const xsapi_internal_string& path, bool is_encode)\n    {\n        if (path.empty() || path == \"/\")\n        {\n            return *this;\n        }\n\n        auto encoded_path = is_encode ? uri::encode_uri(path, uri::components::path) : path;\n        auto thisPath = this->path();\n        if (thisPath.empty() || thisPath == \"/\")\n        {\n            if (encoded_path.front() != '/')\n            {\n                set_path(\"/\" + encoded_path);\n            }\n            else\n            {\n                set_path(encoded_path);\n            }\n        }\n        else if (thisPath.back() == '/' && encoded_path.front() == '/')\n        {\n            thisPath.pop_back();\n            set_path(thisPath + encoded_path);\n        }\n        else if (thisPath.back() != '/' && encoded_path.front() != '/')\n        {\n            set_path(thisPath + \"/\" + encoded_path);\n        }\n        else\n        {\n            // Only one slash.\n            set_path(thisPath + encoded_path);\n        }\n        return *this;\n    }\n\n    uri_builder& uri_builder::append_query(const xsapi_internal_string& query, bool is_encode)\n    {\n        if (query.empty())\n        {\n            return *this;\n        }\n\n        auto encoded_query = is_encode ? uri::encode_uri(query, uri::components::query) : query;\n        auto thisQuery = this->query();\n        if (thisQuery.empty())\n        {\n            this->set_query(encoded_query);\n        }\n        else if (thisQuery.back() == '&' && encoded_query.front() == '&')\n        {\n            thisQuery.pop_back();\n            this->set_query(thisQuery + encoded_query);\n        }\n        else if (thisQuery.back() != '&' && encoded_query.front() != '&')\n        {\n            this->set_query(thisQuery + \"&\" + encoded_query);\n        }\n        else\n        {\n            // Only one ampersand.\n            this->set_query(thisQuery + encoded_query);\n        }\n        return *this;\n    }\n\n    uri_builder& uri_builder::append(const xbox::services::uri& relative_uri)\n    {\n        append_path(relative_uri.path());\n        append_query(relative_uri.query());\n        this->set_fragment(this->fragment() + relative_uri.fragment());\n        return *this;\n    }\n\n    xsapi_internal_string uri_builder::to_string()\n    {\n        return to_uri().to_string();\n    }\n\n    uri uri_builder::to_uri()\n    {\n        return uri(m_uri);\n    }\n\n    bool uri_builder::is_valid()\n    {\n        return uri::validate(m_uri.join());\n    }\n\n}\n}\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Source/Shared/http_utils.h",
    "content": "#pragma once\n\n#include <string>\n#include <sstream>\n#include <functional>\n\n#ifndef _WIN32\n# define __STDC_LIMIT_MACROS\n# include <stdint.h>\n#else\n#include <cstdint>\n#endif\nnamespace xbox\n{\nnamespace services\n{\n\n#ifdef _WIN32\n#define _UTF16_STRINGS\n#endif\n\n    // We should be using a 64-bit size type for most situations that do\n    // not involve specifying the size of a memory allocation or buffer.\n    typedef uint64_t size64_t;\n\n#ifdef _UTF16_STRINGS\n    //\n    // On Windows, all strings are wide\n    //\n    typedef wchar_t char_t ;\n    typedef std::wstring string_t;\n#define _XPLATSTR(x) L ## x\n    typedef std::wostringstream ostringstream_t;\n    typedef std::wofstream ofstream_t;\n    typedef std::wostream ostream_t;\n    typedef std::wistream istream_t;\n    typedef std::wifstream ifstream_t;\n    typedef std::wistringstream istringstream_t;\n    typedef std::wstringstream stringstream_t;\n#define ucout std::wcout\n#define ucin std::wcin\n#define ucerr std::wcerr\n#else\n    //\n    // On POSIX platforms, all strings are narrow\n    //\n    typedef char char_t;\n    typedef std::string string_t;\n#define _XPLATSTR(x) x\n    typedef std::ostringstream ostringstream_t;\n    typedef std::ofstream ofstream_t;\n    typedef std::ostream ostream_t;\n    typedef std::istream istream_t;\n    typedef std::ifstream ifstream_t;\n    typedef std::istringstream istringstream_t;\n    typedef std::stringstream stringstream_t;\n#define ucout std::cout\n#define ucin std::cin\n#define ucerr std::cerr\n#endif // endif _UTF16_STRINGS\n\n#ifndef _TURN_OFF_PLATFORM_STRING\n#define U(x) _XPLATSTR(x)\n#endif // !_TURN_OFF_PLATFORM_STRING\n\n    typedef char utf8char;\n    typedef std::string utf8string;\n    typedef xsapi_internal_stringstream utf8stringstream;\n    typedef std::ostringstream utf8ostringstream;\n    typedef std::ostream utf8ostream;\n    typedef std::istream utf8istream;\n    typedef std::istringstream utf8istringstream;\n\n#ifdef _UTF16_STRINGS\n    typedef wchar_t utf16char;\n    typedef std::wostringstream utf16ostringstream;\n    typedef std::wostream utf16ostream;\n    typedef std::wistream utf16istream;\n    typedef std::wistringstream utf16istringstream;\n#else\n    typedef char16_t utf16char;\n    typedef std::basic_ostringstream<utf16char> utf16ostringstream;\n    typedef std::basic_ostream<utf16char> utf16ostream;\n    typedef std::basic_istream<utf16char> utf16istream;\n    typedef std::basic_istringstream<utf16char> utf16istringstream;\n#endif\n\n    class datetime\n    {\n    public:\n        typedef uint64_t interval_type;\n\n        /// <summary>\n        /// Defines the supported date and time string formats.\n        /// </summary>\n        enum date_format { RFC_1123, ISO_8601 };\n\n        /// <summary>\n        /// Returns the current UTC time.\n        /// </summary>\n        static datetime utc_now();\n\n        /// <summary>\n        /// An invalid UTC timestamp value.\n        /// </summary>\n        enum :interval_type { utc_timestamp_invalid = static_cast<interval_type>(-1) };\n\n        /// <summary>\n        /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.\n        /// If time is before epoch, utc_timestamp_invalid is returned.\n        /// </summary>\n        static interval_type utc_timestamp()\n        {\n            const auto seconds = utc_now().to_interval() / _secondTicks;\n            if (seconds >= 11644473600LL)\n            {\n                return seconds - 11644473600LL;\n            }\n            else\n            {\n                return utc_timestamp_invalid;\n            }\n        }\n\n        datetime() : m_interval(0)\n        {\n        }\n\n        /// <summary>\n        /// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.\n        /// </summary>\n        /// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>\n        static datetime from_string(const xsapi_internal_string& timestring, date_format format = RFC_1123);\n\n        /// <summary>\n        /// Returns a string representation of the <c>datetime</c>.\n        /// </summary>\n        xsapi_internal_string to_string(date_format format = RFC_1123) const;\n\n        /// <summary>\n        /// Returns the integral time value.\n        /// </summary>\n        interval_type to_interval() const\n        {\n            return m_interval;\n        }\n\n        datetime operator- (interval_type value) const\n        {\n            return datetime(m_interval - value);\n        }\n\n        datetime operator+ (interval_type value) const\n        {\n            return datetime(m_interval + value);\n        }\n\n        bool operator== (datetime dt) const\n        {\n            return m_interval == dt.m_interval;\n        }\n\n        bool operator!= (const datetime& dt) const\n        {\n            return !(*this == dt);\n        }\n\n        static interval_type from_milliseconds(unsigned int milliseconds)\n        {\n            return milliseconds * _msTicks;\n        }\n\n        static interval_type from_seconds(unsigned int seconds)\n        {\n            return seconds * _secondTicks;\n        }\n\n        static interval_type from_minutes(unsigned int minutes)\n        {\n            return minutes * _minuteTicks;\n        }\n\n        static interval_type from_hours(unsigned int hours)\n        {\n            return hours * _hourTicks;\n        }\n\n        static interval_type from_days(unsigned int days)\n        {\n            return days * _dayTicks;\n        }\n\n        bool is_initialized() const\n        {\n            return m_interval != 0;\n        }\n\n    private:\n\n        friend int operator- (datetime t1, datetime t2);\n\n        static const interval_type _msTicks = static_cast<interval_type>(10000);\n        static const interval_type _secondTicks = 1000 * _msTicks;\n        static const interval_type _minuteTicks = 60 * _secondTicks;\n        static const interval_type _hourTicks = 60 * 60 * _secondTicks;\n        static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks;\n\n\n    #ifdef _WIN32\n        // void* to avoid pulling in windows.h\n        static  bool system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime* pdt);\n    #else\n        static datetime timeval_to_datetime(const timeval& time);\n    #endif\n\n        // Private constructor. Use static methods to create an instance.\n        datetime(interval_type interval) : m_interval(interval)\n        {\n        }\n\n        // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.\n        interval_type m_interval;\n    };\n\n    inline int operator- (datetime t1, datetime t2)\n    {\n        auto diff = (t1.m_interval - t2.m_interval);\n\n        // Round it down to seconds\n        diff /= 10 * 1000 * 1000;\n\n        return static_cast<int>(diff);\n    }\n\n    /// Functions for Unicode string conversions.\n    namespace convert\n    {\n        /// <summary>\n        /// Converts a UTF-16 string to a UTF-8 string.\n        /// </summary>\n        /// <param name=\"w\">A two byte character UTF-16 string.</param>\n        /// <returns>A single byte character UTF-8 string.</returns>\n        xsapi_internal_string utf16_to_utf8_internal(const xsapi_internal_wstring &w);\n        std::string utf16_to_utf8(const std::wstring &w);\n\n        /// <summary>\n        /// Converts a UTF-8 string to a UTF-16\n        /// </summary>\n        /// <param name=\"s\">A single byte character UTF-8 string.</param>\n        /// <returns>A two byte character UTF-16 string.</returns>\n        xsapi_internal_wstring utf8_to_utf16(const xsapi_internal_string &s);\n\n        /// <summary>\n        /// Converts to a UTF-8 string.\n        /// </summary>\n        /// <param name=\"value\">A single byte character UTF-8 string.</param>\n        /// <returns>A single byte character UTF-8 string.</returns>\n        xsapi_internal_string to_utf8string(xsapi_internal_string value);\n\n        /// <summary>\n        /// Converts to a UTF-8 string.\n        /// </summary>\n        /// <param name=\"value\">A two byte character UTF-16 string.</param>\n        /// <returns>A single byte character UTF-8 string.</returns>\n        xsapi_internal_string to_utf8string(const xsapi_internal_wstring &value);\n\n        /// <summary>\n        /// Converts to a platform dependent Unicode string type.\n        /// </summary>\n        /// <param name=\"s\">A single byte character UTF-8 string.</param>\n        /// <returns>A platform dependent string type.</returns>\n        string_t to_string_t(const xsapi_internal_string_t &s);\n\n        /// <summary>\n        /// Encode the given byte array into a base64 string\n        /// </summary>\n        String to_base64(const Vector<unsigned char>& data);\n\n        /// <summary>\n        /// Decode the given base64 string to a byte array\n        /// </summary>\n        std::vector<unsigned char> from_base64(const xsapi_internal_string& str);\n\n        template <typename Source>\n        xsapi_internal_string print_string(const Source& val, const std::locale& loc)\n        {\n            xsapi_internal_ostringstream oss;\n            (void) oss.imbue(loc);\n            oss << val;\n            if (oss.bad())\n            {\n                throw std::bad_cast();\n            }\n            return oss.str();\n        }\n\n        template <typename Target>\n        Target scan_string(const xsapi_internal_string& str, const std::locale& loc)\n        {\n            Target t;\n            xsapi_internal_istringstream iss(str);\n            (void) iss.imbue(loc);\n            iss >> t;\n            if (iss.bad())\n            {\n                throw std::bad_cast();\n            }\n            return t;\n        }\n\n    }\n\n\n    namespace details\n    {\n        /// <summary>\n        /// Gets the one global instance of the current platform's error category.\n        /// </summary>\n        const std::error_category & platform_category();\n\n        /// <summary>\n        /// Creates an instance of std::system_error from a OS error code.\n        /// </summary>\n        inline std::system_error create_system_error(unsigned long errorCode)\n        {\n            std::error_code code((int)errorCode, platform_category());\n            return std::system_error(code, code.message());\n        }\n\n\n    #ifdef _WIN32\n\n        /// <summary>\n        /// Category error type for Windows OS errors.\n        /// </summary>\n        class windows_category_impl : public std::error_category\n        {\n        public:\n            virtual const char *name() const noexcept { return \"windows\"; }\n\n            virtual std::string message(int errorCode) const noexcept;\n\n            virtual std::error_condition default_error_condition(int errorCode) const noexcept;\n        };\n\n        /// <summary>\n        /// Gets the one global instance of the windows error category.\n        /// </summary>\n        /// <returns>An error category instance.</returns>\n        const std::error_category & windows_category();\n\n    #else\n\n        /// <summary>\n        /// Gets the one global instance of the linux error category.\n        /// </summary>\n        /// </returns>An error category instance.</returns>\n        const std::error_category & linux_category();\n\n    #endif\n\n        /// <summary>\n        /// Our own implementation of alpha numeric instead of std::isalnum to avoid\n        /// taking global lock for performance reasons.\n        /// </summary>\n        inline bool is_alnum(char ch)\n        {\n            return (ch >= '0' && ch <= '9')\n                || (ch >= 'A' && ch <= 'Z')\n                || (ch >= 'a' && ch <= 'z');\n        }\n    }\n}\n\nnamespace services\n{\n    namespace details\n    {\n        struct uri_components\n        {\n            uri_components() : m_path(\"/\"), m_port(-1)\n            {}\n\n            uri_components(const uri_components& other) :\n                m_scheme(other.m_scheme),\n                m_host(other.m_host),\n                m_user_info(other.m_user_info),\n                m_path(other.m_path),\n                m_query(other.m_query),\n                m_fragment(other.m_fragment),\n                m_port(other.m_port)\n            {}\n\n            uri_components& operator=(const uri_components& other)\n            {\n                if (this != &other)\n                {\n                    m_scheme = other.m_scheme;\n                    m_host = other.m_host;\n                    m_user_info = other.m_user_info;\n                    m_path = other.m_path;\n                    m_query = other.m_query;\n                    m_fragment = other.m_fragment;\n                    m_port = other.m_port;\n                }\n                return *this;\n            }\n\n            uri_components(uri_components&& other) noexcept :\n                m_scheme(std::move(other.m_scheme)),\n                m_host(std::move(other.m_host)),\n                m_user_info(std::move(other.m_user_info)),\n                m_path(std::move(other.m_path)),\n                m_query(std::move(other.m_query)),\n                m_fragment(std::move(other.m_fragment)),\n                m_port(other.m_port)\n            {}\n\n            uri_components& operator=(uri_components&& other) noexcept\n            {\n                if (this != &other)\n                {\n                    m_scheme = std::move(other.m_scheme);\n                    m_host = std::move(other.m_host);\n                    m_user_info = std::move(other.m_user_info);\n                    m_path = std::move(other.m_path);\n                    m_query = std::move(other.m_query);\n                    m_fragment = std::move(other.m_fragment);\n                    m_port = other.m_port;\n                }\n                return *this;\n            }\n\n            xsapi_internal_string join();\n\n            xsapi_internal_string m_scheme;\n            xsapi_internal_string m_host;\n            xsapi_internal_string m_user_info;\n            xsapi_internal_string m_path;\n            xsapi_internal_string m_query;\n            xsapi_internal_string m_fragment;\n            int m_port;\n        };\n\n        namespace uri_parser\n        {\n\n            /// <summary>\n            /// Parses the uri, attempting to determine its validity.\n            ///\n            /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query')\n            /// </summary>\n            bool validate(const xsapi_internal_string& encoded_string);\n\n            /// <summary>\n            /// Parses the uri, setting each provided string to the value of that component. Components\n            /// that are not part of the provided text are set to the empty string. Component strings\n            /// DO NOT contain their beginning or ending delimiters.\n            ///\n            /// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query')\n            /// </summary>\n            bool parse(const xsapi_internal_string& encoded_string, uri_components& components);\n\n            /// <summary>\n            /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include:\n            /// - A-Z\n            /// - a-z\n            /// - 0-9\n            /// - '-' (hyphen)\n            /// - '.' (period)\n            /// - '_' (underscore)\n            /// - '~' (tilde)\n            /// </summary>\n            inline bool is_unreserved(int c)\n            {\n                return ::xbox::services::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~';\n            }\n\n            /// <summary>\n            /// General delimiters serve as the delimiters between different uri components.\n            /// General delimiters include:\n            /// - All of these :/?#[]@\n            /// </summary>\n            inline bool is_gen_delim(int c)\n            {\n                return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@';\n            }\n\n            /// <summary>\n            /// Subdelimiters are those characters that may have a defined meaning within component\n            /// of a uri for a particular scheme. They do not serve as delimiters in any case between\n            /// uri segments. sub_delimiters include:\n            /// - All of these !$&amp;'()*+,;=\n            /// </summary>\n            inline bool is_sub_delim(int c)\n            {\n                switch (c)\n                {\n                case '!':\n                case '$':\n                case '&':\n                case '\\'':\n                case '(':\n                case ')':\n                case '*':\n                case '+':\n                case ',':\n                case ';':\n                case '=':\n                    return true;\n                default:\n                    return false;\n                }\n            }\n\n            /// <summary>\n            /// Reserved characters includes the general delimiters and sub delimiters. Some characters\n            /// are neither reserved nor unreserved, and must be percent-encoded.\n            /// </summary>\n            inline bool is_reserved(int c)\n            {\n                return is_gen_delim(c) || is_sub_delim(c);\n            }\n\n            /// <summary>\n            /// Legal characters in the scheme portion include:\n            /// - Any alphanumeric character\n            /// - '+' (plus)\n            /// - '-' (hyphen)\n            /// - '.' (period)\n            ///\n            /// Note that the scheme must BEGIN with an alpha character.\n            /// </summary>\n            inline bool is_scheme_character(int c)\n            {\n                return ::xbox::services::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.';\n            }\n\n            /// <summary>\n            /// Legal characters in the user information portion include:\n            /// - Any unreserved character\n            /// - The percent character ('%'), and thus any percent-endcoded octet\n            /// - The sub-delimiters\n            /// - ':' (colon)\n            /// </summary>\n            inline bool is_user_info_character(int c)\n            {\n                return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':';\n            }\n\n            /// <summary>\n            /// Legal characters in the host portion include:\n            /// - Any unreserved character\n            /// - The percent character ('%'), and thus any percent-endcoded octet\n            /// - The sub-delimiters\n            /// - ':' (colon)\n            /// - '[' (open bracket)\n            /// - ']' (close bracket)\n            /// </summary>\n            inline bool is_host_character(int c)\n            {\n                return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':' || c == '[' || c == ']';\n            }\n\n            /// <summary>\n            /// Legal characters in the authority portion include:\n            /// - Any unreserved character\n            /// - The percent character ('%'), and thus any percent-endcoded octet\n            /// - The sub-delimiters\n            /// - ':' (colon)\n            ///\n            /// Note that we don't currently support:\n            /// - IPv6 addresses (requires '[]')\n            /// </summary>\n            inline bool is_authority_character(int c)\n            {\n                return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':';\n            }\n\n            /// <summary>\n            /// Legal characters in the path portion include:\n            /// - Any unreserved character\n            /// - The percent character ('%'), and thus any percent-endcoded octet\n            /// - The sub-delimiters\n            /// - ':' (colon)\n            /// - '@' (ampersand)\n            /// </summary>\n            inline bool is_path_character(int c)\n            {\n                return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@';\n            }\n\n            /// <summary>\n            /// Legal characters in the query portion include:\n            /// - Any path character\n            /// - '?' (question mark)\n            /// </summary>\n            inline bool is_query_character(int c)\n            {\n                return is_path_character(c) || c == '?';\n            }\n\n            /// <summary>\n            /// Legal characters in the fragment portion include:\n            /// - Any path character\n            /// - '?' (question mark)\n            /// </summary>\n            inline bool is_fragment_character(int c)\n            {\n                // this is intentional, they have the same set of legal characters\n                return is_query_character(c);\n            }\n\n            /// <summary>\n            /// Parses the uri, setting the given pointers to locations inside the given buffer.\n            /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri\n            /// </summary>\n            bool inner_parse(\n                const char* encoded,\n                const char** scheme_begin, const char** scheme_end,\n                const char** uinfo_begin, const char** uinfo_end,\n                const char** host_begin, const char** host_end,\n                _Out_ int* port,\n                const char** path_begin, const char** path_end,\n                const char** query_begin, const char** query_end,\n                const char** fragment_begin, const char** fragment_end);\n        }\n    }\n\n    /// <summary>\n    /// A single exception type to represent errors in parsing, encoding, and decoding URIs.\n    /// </summary>\n    class uri_exception : public std::exception\n    {\n    public:\n\n        uri_exception(xsapi_internal_string msg) : m_msg(std::move(msg)) {}\n\n        ~uri_exception() noexcept {}\n\n        const char* what() const noexcept\n        {\n            return m_msg.c_str();\n        }\n\n    private:\n        xsapi_internal_string m_msg;\n    };\n\n    /// <summary>\n    /// A flexible, protocol independent URI implementation.\n    ///\n    /// URI instances are immutable. Querying the various fields on an emtpy URI will return empty strings. Querying\n    /// various diagnostic members on an empty URI will return false.\n    /// </summary>\n    /// <remarks>\n    /// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references\n    /// ('/path?query#frag').\n    ///\n    /// This implementation does not provide any scheme-specific handling -- an example of this\n    /// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid\n    /// http-uri -- that is, it's syntactically correct but does not conform to the requirements\n    /// of the http scheme (http requires a host).\n    /// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide\n    /// extra capability for validating and canonicalizing a URI according to scheme, and would\n    /// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics.\n    ///\n    /// One issue with implementing a scheme-independent URI facility is that of comparing for equality.\n    /// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is --\n    /// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme\n    /// to it's default port, we don't have a way to know these are equal. This is just one of a class of\n    /// issues with regard to scheme-specific behavior.\n    /// </remarks>\n    class uri\n    {\n    public:\n\n        /// <summary>\n        /// The various components of a URI. This enum is used to indicate which\n        /// URI component is being encoded to the encode_uri_component. This allows\n        /// specific encoding to be performed.\n        ///\n        /// Scheme and port don't allow '%' so they don't need to be encoded.\n        /// </summary>\n        class components\n        {\n        public:\n            enum component\n            {\n                user_info,\n                host,\n                path,\n                query,\n                fragment,\n                full_uri\n            };\n        };\n\n        /// <summary>\n        /// Encodes a URI component according to RFC 3986.\n        /// Note if a full URI is specified instead of an individual URI component all\n        /// characters not in the unreserved set are escaped.\n        /// </summary>\n        /// <param name=\"raw\">The URI as a string.</param>\n        /// <returns>The encoded string.</returns>\n        static xsapi_internal_string encode_uri(const xsapi_internal_string& raw, uri::components::component = components::full_uri);\n\n        /// <summary>\n        /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their\n        /// hexadecimal representation.\n        /// </summary>\n        /// <param name=\"utf8data\">The UTF-8 string data.</param>\n        /// <returns>The encoded string.</returns>\n        static xsapi_internal_string encode_data_string(const xsapi_internal_string& utf8data);\n\n        /// <summary>\n        /// Decodes an encoded string.\n        /// </summary>\n        /// <param name=\"encoded\">The URI as a string.</param>\n        /// <returns>The decoded string.</returns>\n        static xsapi_internal_string decode(const xsapi_internal_string& encoded);\n\n        /// <summary>\n        /// Splits a path into its hierarchical components.\n        /// </summary>\n        /// <param name=\"path\">The path as a string</param>\n        /// <returns>A <c>std::vector&lt;xsapi_internal_string&gt;</c> containing the segments in the path.</returns>\n        static std::vector<xsapi_internal_string> split_path(const xsapi_internal_string& path);\n\n        /// <summary>\n        /// Splits a query into its key-value components.\n        /// </summary>\n        /// <param name=\"query\">The query string</param>\n        /// <returns>A <c>std::map&lt;xsapi_internal_string, xsapi_internal_string&gt;</c> containing the key-value components of the query.</returns>\n        static std::map<xsapi_internal_string, xsapi_internal_string> split_query(const xsapi_internal_string& query);\n\n        /// <summary>\n        /// Validates a string as a URI.\n        /// </summary>\n        /// <param name=\"uri_string\">The URI string to be validated.</param>\n        /// <returns><c>true</c> if the given string represents a valid URI, <c>false</c> otherwise.</returns>\n        static bool validate(const xsapi_internal_string& uri_string);\n\n        /// <summary>\n        /// Creates an empty uri\n        /// </summary>\n        uri() { m_uri = \"/\"; };\n\n        /// <summary>\n        /// Creates a URI from the given URI components.\n        /// </summary>\n        /// <param name=\"components\">A URI components object to create the URI instance.</param>\n        uri(const details::uri_components& components);\n\n        /// <summary>\n        /// Creates a URI from the given encoded string. This will throw an exception if the string\n        /// does not contain a valid URI. Use uri::validate if processing user-input.\n        /// </summary>\n        /// <param name=\"uri_string\">A pointer to an encoded string to create the URI instance.</param>\n        uri(const char* uri_string);\n\n        /// <summary>\n        /// Creates a URI from the given encoded string. This will throw an exception if the string\n        /// does not contain a valid URI. Use uri::validate if processing user-input.\n        /// </summary>\n        /// <param name=\"uri_string\">An encoded URI string to create the URI instance.</param>\n        uri(const xsapi_internal_string& uri_string);\n\n        /// <summary>\n        /// Copy constructor.\n        /// </summary>\n        uri(const uri& other) :\n            m_uri(other.m_uri),\n            m_components(other.m_components)\n        {}\n\n        /// <summary>\n        /// Copy assignment operator.\n        /// </summary>\n        uri& operator=(const uri& other)\n        {\n            if (this != &other)\n            {\n                m_uri = other.m_uri;\n                m_components = other.m_components;\n            }\n            return *this;\n        }\n\n        /// <summary>\n        /// Move constructor.\n        /// </summary>\n        uri(uri&& other) noexcept :\n        m_uri(std::move(other.m_uri)),\n            m_components(std::move(other.m_components))\n        {}\n\n        /// <summary>\n        /// Move assignment operator\n        /// </summary>\n        uri& operator=(uri&& other) noexcept\n        {\n            if (this != &other)\n            {\n                m_uri = std::move(other.m_uri);\n                m_components = std::move(other.m_components);\n            }\n            return *this;\n        }\n\n        /// <summary>\n        /// Get the scheme component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI scheme as a string.</returns>\n        const xsapi_internal_string& scheme() const { return m_components.m_scheme; }\n\n        /// <summary>\n        /// Get the user information component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI user information as a string.</returns>\n        const xsapi_internal_string& user_info() const { return m_components.m_user_info; }\n\n        /// <summary>\n        /// Get the host component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI host as a string.</returns>\n        const xsapi_internal_string& host() const { return m_components.m_host; }\n\n        /// <summary>\n        /// Get the port component of the URI. Returns -1 if no port is specified.\n        /// </summary>\n        /// <returns>The URI port as an integer.</returns>\n        int port() const { return m_components.m_port; }\n\n        /// <summary>\n        /// Get the path component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI path as a string.</returns>\n        const xsapi_internal_string& path() const { return m_components.m_path; }\n\n        /// <summary>\n        /// Get the query component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI query as a string.</returns>\n        const xsapi_internal_string& query() const { return m_components.m_query; }\n\n        /// <summary>\n        /// Get the fragment component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI fragment as a string.</returns>\n        const xsapi_internal_string& fragment() const { return m_components.m_fragment; }\n\n        /// <summary>\n        /// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions.\n        /// </summary>\n        /// <returns>The new uri object with the same authority.</returns>\n        uri authority() const;\n\n        /// <summary>\n        /// Gets the path, query, and fragment portion of this uri, which may be empty.\n        /// </summary>\n        /// <returns>The new URI object with the path, query and fragment portion of this URI.</returns>\n        uri resource() const;\n\n        /// <summary>\n        /// An empty URI specifies no components, and serves as a default value\n        /// </summary>\n        bool is_empty() const\n        {\n            return this->m_uri.empty() || this->m_uri == \"/\";\n        }\n\n        /// <summary>\n        /// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine.\n        /// </summary>\n        /// <remarks>\n        /// Examples include \"locahost\", or ip addresses in the loopback range (127.0.0.0/24).\n        /// </remarks>\n        /// <returns><c>true</c> if this URI references the local host, <c>false</c> otherwise.</returns>\n        bool is_host_loopback() const\n        {\n            return !is_empty() && ((host() == \"localhost\") || (host().size() > 4 && host().substr(0, 4) == \"127.\"));\n        }\n\n        /// <summary>\n        /// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +)\n        /// </summary>\n        /// <example>\n        /// http://*:80\n        /// </example>\n        bool is_host_wildcard() const\n        {\n            return !is_empty() && (this->host() == \"*\" || this->host() == \"+\");\n        }\n\n        /// <summary>\n        /// A portable URI is one with a hostname that can be resolved globally (used from another machine).\n        /// </summary>\n        /// <returns><c>true</c> if this URI can be resolved globally (used from another machine), <c>false</c> otherwise.</returns>\n        /// <remarks>\n        /// The hostname \"localhost\" is a reserved name that is guaranteed to resolve to the local machine,\n        /// and cannot be used for inter-machine communication. Likewise the hostnames \"*\" and \"+\" on Windows\n        /// represent wildcards, and do not map to a resolvable address.\n        /// </remarks>\n        bool is_host_portable() const\n        {\n            return !(is_empty() || is_host_loopback() || is_host_wildcard());\n        }\n\n        /// <summary>\n        /// A default port is one where the port is unspecified, and will be determined by the operating system.\n        /// The choice of default port may be dictated by the scheme (http -> 80) or not.\n        /// </summary>\n        /// <returns><c>true</c> if this URI instance has a default port, <c>false</c> otherwise.</returns>\n        bool is_port_default() const\n        {\n            return !is_empty() && this->port() == 0;\n        }\n\n        /// <summary>\n        /// An \"authority\" URI is one with only a scheme, optional userinfo, hostname, and (optional) port.\n        /// </summary>\n        /// <returns><c>true</c> if this is an \"authority\" URI, <c>false</c> otherwise.</returns>\n        bool is_authority() const\n        {\n            return !is_empty() && is_path_empty() && query().empty() && fragment().empty();\n        }\n\n        /// <summary>\n        /// Returns whether the other URI has the same authority as this one\n        /// </summary>\n        /// <param name=\"other\">The URI to compare the authority with.</param>\n        /// <returns><c>true</c> if both the URI's have the same authority, <c>false</c> otherwise.</returns>\n        bool has_same_authority(const uri& other) const\n        {\n            return !is_empty() && this->authority() == other.authority();\n        }\n\n        /// <summary>\n        /// Returns whether the path portion of this URI is empty\n        /// </summary>\n        /// <returns><c>true</c> if the path portion of this URI is empty, <c>false</c> otherwise.</returns>\n        bool is_path_empty() const\n        {\n            return path().empty() || path() == \"/\";\n        }\n\n        /// <summary>\n        /// Returns the full (encoded) URI as a string.\n        /// </summary>\n         /// <returns>The full encoded URI string.</returns>\n        xsapi_internal_string to_string() const\n        {\n            return m_uri;\n        }\n\n        bool operator == (const uri& other) const;\n\n        bool operator < (const uri& other) const\n        {\n            return m_uri < other.m_uri;\n        }\n\n        bool operator != (const uri& other) const\n        {\n            return !(this->operator == (other));\n        }\n\n    private:\n        friend class uri_builder;\n\n        // Encodes all characters not in given set determined by given function.\n        static xsapi_internal_string encode_impl(const xsapi_internal_string& raw, const std::function<bool __cdecl(int)>& should_encode);\n\n        xsapi_internal_string m_uri;\n        details::uri_components m_components;\n    };\n\n    /// <summary>\n    /// Builder for constructing URIs incrementally.\n    /// </summary>\n    class uri_builder\n    {\n    public:\n\n        /// <summary>\n        /// Creates a builder with an initially empty URI.\n        /// </summary>\n        uri_builder() {}\n\n        /// <summary>\n        /// Creates a builder with a existing URI object.\n        /// </summary>\n        /// <param name=\"uri_str\">Encoded string containing the URI.</param>\n        uri_builder(const uri& uri_str) : m_uri(uri_str.m_components) {}\n\n        /// <summary>\n        /// Get the scheme component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI scheme as a string.</returns>\n        const xsapi_internal_string& scheme() const { return m_uri.m_scheme; }\n\n        /// <summary>\n        /// Get the user information component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI user information as a string.</returns>\n        const xsapi_internal_string& user_info() const { return m_uri.m_user_info; }\n\n        /// <summary>\n        /// Get the host component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI host as a string.</returns>\n        const xsapi_internal_string& host() const { return m_uri.m_host; }\n\n        /// <summary>\n        /// Get the port component of the URI. Returns -1 if no port is specified.\n        /// </summary>\n        /// <returns>The URI port as an integer.</returns>\n        int port() const { return m_uri.m_port; }\n\n        /// <summary>\n        /// Get the path component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI path as a string.</returns>\n        const xsapi_internal_string& path() const { return m_uri.m_path; }\n\n        /// <summary>\n        /// Get the query component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI query as a string.</returns>\n        const xsapi_internal_string& query() const { return m_uri.m_query; }\n\n        /// <summary>\n        /// Get the fragment component of the URI as an encoded string.\n        /// </summary>\n        /// <returns>The URI fragment as a string.</returns>\n        const xsapi_internal_string& fragment() const { return m_uri.m_fragment; }\n\n        /// <summary>\n        /// Set the scheme of the URI.\n        /// </summary>\n        /// <param name=\"scheme\">Uri scheme.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_scheme(const xsapi_internal_string& scheme)\n        {\n            m_uri.m_scheme = scheme;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the user info component of the URI.\n        /// </summary>\n        /// <param name=\"user_info\">User info as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_user_info(const xsapi_internal_string& user_info, bool do_encoding = false)\n        {\n            m_uri.m_user_info = do_encoding ? uri::encode_uri(user_info, uri::components::user_info) : user_info;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the host component of the URI.\n        /// </summary>\n        /// <param name=\"host\">Host as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_host(const xsapi_internal_string& host, bool do_encoding = false)\n        {\n            m_uri.m_host = do_encoding ? uri::encode_uri(host, uri::components::host) : host;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the port component of the URI.\n        /// </summary>\n        /// <param name=\"port\">Port as an integer.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_port(int port)\n        {\n            m_uri.m_port = port;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the port component of the URI.\n        /// </summary>\n        /// <param name=\"port\">Port as a string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        /// <remarks>When string can't be converted to an integer the port is left unchanged.</remarks>\n        uri_builder& set_port(const xsapi_internal_string& port)\n        {\n            xsapi_internal_istringstream portStream(port);\n            int port_tmp;\n            portStream >> port_tmp;\n            if (portStream.fail() || portStream.bad())\n            {\n                throw std::invalid_argument(\"invalid port argument, must be non empty string containing integer value\");\n            }\n            m_uri.m_port = port_tmp;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the path component of the URI.\n        /// </summary>\n        /// <param name=\"path\">Path as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_path(const xsapi_internal_string& path, bool do_encoding = false)\n        {\n            m_uri.m_path = do_encoding ? uri::encode_uri(path, uri::components::path) : path;\n            return *this;\n        }\n\n\n        /// <summary>\n        /// Set the query component of the URI.\n        /// </summary>\n        /// <param name=\"query\">Query as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_query(const xsapi_internal_string& query, bool do_encoding = false)\n        {\n            m_uri.m_query = do_encoding ? uri::encode_uri(query, uri::components::query) : query;\n            return *this;\n        }\n\n        /// <summary>\n        /// Set the fragment component of the URI.\n        /// </summary>\n        /// <param name=\"fragment\">Fragment as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>\n        uri_builder& set_fragment(const xsapi_internal_string& fragment, bool do_encoding = false)\n        {\n            m_uri.m_fragment = do_encoding ? uri::encode_uri(fragment, uri::components::fragment) : fragment;\n            return *this;\n        }\n\n        /// <summary>\n        /// Clears all components of the underlying URI in this uri_builder.\n        /// </summary>\n        void clear()\n        {\n            m_uri = details::uri_components();\n        }\n\n        /// <summary>\n        /// Appends another path to the path of this uri_builder.\n        /// </summary>\n        /// <param name=\"path\">Path to append as a already encoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        uri_builder& append_path(const xsapi_internal_string& path, bool do_encoding = false);\n\n        /// <summary>\n        /// Appends another query to the query of this uri_builder.\n        /// </summary>\n        /// <param name=\"query\">Query to append as a decoded string.</param>\n        /// <param name=\"do_encoding\">Specify whether to apply URI encoding to the given string.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        uri_builder& append_query(const xsapi_internal_string& query, bool do_encoding = false);\n\n        /// <summary>\n        /// Appends an relative uri (Path, Query and fragment) at the end of the current uri.\n        /// </summary>\n        /// <param name=\"relative_uri\">The relative uri to append.</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        uri_builder& append(const uri& relative_uri);\n\n        /// <summary>\n        /// Appends another query to the query of this uri_builder, encoding it first. This overload is useful when building a query segment of\n        /// the form \"element=10\", where the right hand side of the query is stored as a type other than a string, for instance, an integral type.\n        /// </summary>\n        /// <param name=\"name\">The name portion of the query string</param>\n        /// <param name=\"value\">The value portion of the query string</param>\n        /// <returns>A reference to this uri_builder to support chaining.</returns>\n        template<typename T>\n        uri_builder& append_query(const xsapi_internal_string& name, const T& value, bool do_encoding = true)\n        {\n            auto encodedName = name;\n            auto encodedValue = ::xbox::services::convert::print_string(value, std::locale::classic());\n\n            if (do_encoding)\n            {\n                auto encodingCheck = [](int ch)\n                {\n                    switch (ch)\n                    {\n                        // Encode '&', ';', and '=' since they are used\n                        // as delimiters in query component.\n                    case '&':\n                    case ';':\n                    case '=':\n                    case '%':\n                    case '+':\n                        return true;\n                    default:\n                        return !::xbox::services::details::uri_parser::is_query_character(ch);\n                    }\n                };\n                encodedName = uri::encode_impl(encodedName, encodingCheck);\n                encodedValue = uri::encode_impl(encodedValue, encodingCheck);\n            }\n\n            auto encodedQuery = encodedName;\n            encodedQuery.append(\"=\");\n            encodedQuery.append(encodedValue);\n            // The query key value pair was already encoded by us or the user separately.\n            return append_query(encodedQuery, false);\n        }\n\n        /// <summary>\n        /// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is invalid.\n        /// </summary>\n        /// <returns>The created URI as a string.</returns>\n        xsapi_internal_string to_string();\n\n        /// <summary>\n        /// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is invalid.\n        /// </summary>\n        /// <returns>The create URI as a URI class instance.</returns>\n        uri to_uri();\n\n        /// <summary>\n        /// Validate the generated URI from all existing components of this uri_builder.\n        /// </summary>\n        /// <returns>Whether the URI is valid.</returns>\n        bool is_valid();\n\n    private:\n        details::uri_components m_uri;\n    };\n} // namespace web\n}"
  },
  {
    "path": "Source/Shared/i/guid.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xbl_guid.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxsapi_internal_string generate_guid()\n{\n    \n    NSUUID* guid = [NSUUID UUID];\n    NSString* guidNSString = [guid UUIDString];\n    return guidNSString.UTF8String;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/i/utils_locales_ios.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi_utils.h\"\n\nusing namespace xbox::services;\n\nxsapi_internal_vector<xsapi_internal_string>\nutils::get_locale_list()\n{\n    NSString *local = [NSLocale preferredLanguages][0];\n    string_t localeStr([local UTF8String]);\n    xsapi_internal_vector<xsapi_internal_string> localeList;\n    localeList.push_back(utils::internal_string_from_string_t(localeStr));\n    return localeList;\n}\n"
  },
  {
    "path": "Source/Shared/internal_errors.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <cassert>\n#include <exception>\n#include <string>\n#include \"xsapi_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\ntemplate<typename T>\nclass Result\n{\npublic:\n    Result() = default;\n    Result(const Result&) = default;\n    Result(Result&& other) = default;\n    ~Result() = default;\n\n    Result& operator=(const Result& rhs) = default;\n\n    Result(HRESULT hr, String errorMessage = {}) : m_result{ hr }, m_errorMessage{ std::move(errorMessage) } {}\n\n    Result(T payload, HRESULT hr = S_OK, String errorMessage = {}) : m_result{ hr }, m_payload{ payload }, m_errorMessage{ std::move(errorMessage) } {}\n\n    Result(std::error_code errc, String errorMessage = {}) : m_errorMessage{ std::move(errorMessage) }\n    {\n        m_result = utils::convert_xbox_live_error_code_to_hresult(errc);\n    }\n\n    Result(T payload, std::error_code errc, String errorMessage = {}) : m_payload{ payload }, m_errorMessage{ std::move(errorMessage) }\n    {\n        m_result = utils::convert_xbox_live_error_code_to_hresult(errc);\n    }\n\n    HRESULT Hresult() const noexcept\n    {\n        return m_result;\n    }\n\n    const char* ErrorMessage() const noexcept\n    {\n        return m_errorMessage.c_str();\n    }\n\n    T& Payload() noexcept\n    {\n        return m_payload;\n    }\n\n    const T& Payload() const noexcept\n    {\n        return m_payload;\n    }\n\n    T&& ExtractPayload()\n    {\n        return std::move(m_payload);\n    }\n\nprivate:\n    HRESULT m_result{ S_OK };\n    T m_payload{};\n    String m_errorMessage{};\n};\n\ntemplate<>\nclass Result<void>\n{\npublic:\n    Result() = default;\n    Result(const Result<void>&) = default;\n\n    template<typename T>\n    Result(const Result<T>& other) : m_result{ other.Hresult() }, m_errorMessage{ other.ErrorMessage() } {}\n\n    Result(HRESULT hr, String errorMessage = {}) : m_result{ hr }, m_errorMessage{ std::move(errorMessage) } {}\n\n    Result(std::error_code errc, String errorMessage = {}) : m_errorMessage{ std::move(errorMessage) }\n    {\n        m_result = utils::convert_xbox_live_error_code_to_hresult(errc);\n    }\n\n    HRESULT Hresult() const noexcept\n    {\n        return m_result;\n    }\n\n    const char* ErrorMessage() const noexcept\n    {\n        return m_errorMessage.c_str();\n    }\n\nprivate:\n    HRESULT m_result{ S_OK };\n    String m_errorMessage{};\n};\n\ntemplate<typename T>\nbool Succeeded(const Result<T>& result)\n{\n    return SUCCEEDED(result.Hresult());\n}\n\ntemplate<typename T>\nbool Failed(const Result<T>& result)\n{\n    return FAILED(result.Hresult());\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/internal_mem.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include <rapidjson/allocators.hpp>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nXblMemAllocFunction g_pMemAllocHook{ DefaultAlloc };\nXblMemFreeFunction g_pMemFreeHook{ DefaultFree };\n\n_Ret_maybenull_ _Post_writable_byte_size_(size) void* DefaultAlloc(\n    size_t size,\n    HCMemoryType memoryType\n) noexcept\n{\n    UNREFERENCED_PARAMETER(memoryType);\n    if (size > 0)\n    {\n        return malloc(size);\n    }\n    return static_cast<void*>(nullptr);\n}\n\nvoid DefaultFree(\n    _In_ _Post_invalid_ void* pointer,\n    HCMemoryType memoryType\n) noexcept\n{\n    UNREFERENCED_PARAMETER(memoryType);\n    if (pointer)\n    {\n        free(pointer);\n    }\n}\n\n_Post_writable_byte_size_(size) void* STDAPIVCALLTYPE Alloc(\n    size_t size,\n    HCMemoryType memoryType\n) noexcept\n{\n    assert(g_pMemAllocHook);\n    try\n    {\n        return g_pMemAllocHook(size, memoryType);\n    }\n    catch (...)\n    {\n        LOGS_ERROR << \"Caught exception in MemAlloc hook!\";\n        return nullptr;\n    }\n}\n\nvoid STDAPIVCALLTYPE Free(\n    _Post_invalid_ void* pointer,\n    HCMemoryType memoryType\n) noexcept\n{\n    assert(g_pMemFreeHook);\n    try\n    {\n        DISABLE_WARNING_PUSH;\n        SUPPRESS_WARNING_UNINITIALIZED_MEMORY;\n        g_pMemFreeHook(pointer, memoryType);\n        DISABLE_WARNING_POP;\n    }\n    catch (...)\n    {\n        LOGS_ERROR << \"Caught exception in MemFree hook!\";\n    }\n}\n\nchar* Make(const char* str)\n{\n    auto length = strlen(str) + 1;\n    char* copy = static_cast<char*>(Alloc(length));\n    if (copy != nullptr)\n    {\n        utils::strcpy(copy, length, str);\n    }\n    return copy;\n}\n\nchar* Make(const String& str)\n{\n    char* cstr = static_cast<char*>(Alloc(str.length() + 1));\n    if (cstr != nullptr)\n    {\n        utils::strcpy(cstr, str.length() + 1, str.data());\n    }\n    return cstr;\n}\n\nchar* Make(const string_t& strt)\n{\n    auto cchCString = utils::utf8_from_char_t(strt.data(), nullptr, 0);\n    char* cstr = static_cast<char*>(Alloc(cchCString));\n    if (cstr != nullptr)\n    {\n        utils::utf8_from_char_t(strt.data(), cstr, cchCString);\n    }\n    return cstr;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/internal_mem.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\n#include \"xsapi-c/xbox_live_global_c.h\"\n#include <list>\n#include <map>\n#include <set>\n#include <sstream>\n#include <queue>\n#include <unordered_map>\n#include <unordered_set>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// The memhooks are intentionally global and independent of GlobalState. GlobalState depends\n// on them being configured before it is constructed.\nextern XblMemAllocFunction g_pMemAllocHook;\nextern XblMemFreeFunction g_pMemFreeHook;\n\n// Raw allocation/deallocation functions, using memhooks if they are provided\n_Ret_maybenull_ _Post_writable_byte_size_(size) void* DefaultAlloc(\n    size_t size,\n    HCMemoryType memoryType\n) noexcept;\n\nvoid DefaultFree(\n    _In_ _Post_invalid_ void* pointer,\n    HCMemoryType memoryType\n) noexcept;\n\n_Post_writable_byte_size_(size) void* STDAPIVCALLTYPE Alloc(\n    size_t size,\n    HCMemoryType memoryType = 0\n) noexcept;\n\nvoid STDAPIVCALLTYPE Free(\n    _Post_invalid_ void* pointer,\n    HCMemoryType memoryType = 0\n) noexcept;\n\n// Memhooked STL types\ntemplate<typename T>\nstruct Allocator\n{\npublic:\n    typedef T value_type;\n\n    Allocator() = default;\n    template<class U> Allocator(Allocator<U> const&) {}\n\n    T* allocate(size_t n)\n    {\n        T* p = static_cast<T*>(Alloc(n * sizeof(T)));\n        if (p == nullptr)\n        {\n            throw std::bad_alloc();\n        }\n        return p;\n    }\n\n    void deallocate(_In_opt_ void* p, size_t)\n    {\n        Free(p);\n    }\n};\n\ntemplate<class T>\nbool operator==(Allocator<T> const&, Allocator<T> const&)\n{\n    return true;\n}\n\ntemplate<class T>\nbool operator!=(Allocator<T> const&, Allocator<T> const&)\n{\n    return false;\n}\n\ntemplate<class T>\nstruct Deleter\n{\npublic:\n    Deleter() = default;\n\n    void operator()(typename std::allocator_traits<Allocator<T>>::pointer p) const\n    {\n        Allocator<T> alloc{};\n        std::allocator_traits<Allocator<T>>::destroy(alloc, std::addressof(*p));\n        std::allocator_traits<Allocator<T>>::deallocate(alloc, p, 1);\n    }\n};\n\ntemplate<class T>\nusing UniquePtr = std::unique_ptr<T, Deleter<T>>;\n\ntemplate<class T>\nusing Vector = std::vector<T, Allocator<T>>;\n\ntemplate<class K, class V, class LESS = std::less<K>>\nusing Map = std::map<K, V, LESS, Allocator<std::pair<K const, V>>>;\n\ntemplate<class K, class LESS = std::less<K>>\nusing Set = std::set<K, LESS, Allocator<K>>;\n\ntemplate<class K, class V, class HASH = std::hash<K>, class EQUAL = std::equal_to<K>>\nusing UnorderedMap = std::unordered_map<K, V, HASH, EQUAL, Allocator<std::pair<K const, V>>>;\n\ntemplate<class K, class HASH = std::hash<K>, class EQUAL = std::equal_to<K>>\nusing UnorderedSet = std::unordered_set<K, HASH, EQUAL, Allocator<K>>;\n\ntemplate<class C, class TRAITS = std::char_traits<C>>\nusing BasicString = std::basic_string<C, TRAITS, Allocator<C>>;\nusing String = BasicString<char>;\nusing WString = BasicString<wchar_t>;\n\ntemplate<class C, class TRAITS = std::char_traits<C>>\nusing BasicStringsteam = std::basic_stringstream<C, TRAITS, Allocator<C>>;\nusing Stringstream = BasicStringsteam<char>;\nusing WStringstream = BasicStringsteam<wchar_t>;\n\ntemplate<class C, class TRAITS = std::char_traits<C>>\nusing BasicIStringsteam = std::basic_istringstream<C, TRAITS, Allocator<C>>;\nusing IStringstream = BasicIStringsteam<char>;\nusing WIStringstream = BasicIStringsteam<wchar_t>;\n\ntemplate<class C, class TRAITS = std::char_traits<C>>\nusing BasicOStringsteam = std::basic_ostringstream<C, TRAITS, Allocator<C>>;\nusing OStringstream = BasicOStringsteam<char>;\nusing WOStringstream = BasicOStringsteam<wchar_t>;\n\ntemplate<class T>\nusing Deque = std::deque<T, Allocator<T>>;\n\ntemplate<class T>\nusing Queue = std::queue<T, Deque<T>>;\n\ntemplate<class T>\nusing List = std::list<T, Allocator<T>>;\n\n// Memhooked allocation/deallocation helpers\ntemplate<typename T, class... TArgs>\ninline std::shared_ptr<T> MakeShared(TArgs&&... args)\n{\n#if !HC_PLATFORM_IS_MICROSOFT || _MSC_VER >= 1910\n    return std::allocate_shared<T, Allocator<T>>(Allocator<T>(), std::forward<TArgs>(args)...);\n#else\n    return std::allocate_shared<T, std::allocator<T>>(std::allocator<T>(), std::forward<TArgs>(args)...);\n#endif\n}\n\ntemplate<typename T, typename... TArgs>\nUniquePtr<T> MakeUnique(TArgs&& ... args)\n{\n    Allocator<T> alloc{};\n    auto mem = alloc.allocate(1);\n    auto obj = new (mem) T(std::forward<TArgs>(args)...);\n    return UniquePtr<T>{ obj };\n}\n\n// Make specializations to allocate UTF-8 strings\nchar* Make(const char* str);\nchar* Make(const String& str);\nchar* Make(const string_t& strt);\n\ntemplate<typename T, class... TArgs>\ninline T* Make(TArgs&&... args)\n{\n    auto mem = Alloc(sizeof(T));\n    return new (mem) T(std::forward<TArgs>(args)...);\n}\n\ntemplate<typename T>\ninline void Delete(T* ptr)\n{\n    if (ptr != nullptr)\n    {\n        ptr->~T();\n        Free((void*)ptr);\n    }\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 6386 ) // VS2019 code analysis incorrectly warns about 'elementCount*sizeof(T)' bytes \n#endif\ntemplate<typename T>\ninline T* MakeArray(size_t elementCount)\n{\n    auto mem = Alloc(elementCount * sizeof(T));\n    if (mem == nullptr)\n    {\n        return nullptr;\n    }\n\n    T* arrayPtr = reinterpret_cast<T*>(mem);\n    for (size_t i = 0; i < elementCount; ++i)\n    {\n        arrayPtr[i] = T{};\n    }\n    return arrayPtr;\n}\n\ntemplate<typename T>\ninline T* MakeArray(T* elements, size_t elementCount)\n{\n    auto mem = Alloc(elementCount * sizeof(T));\n    if (mem == nullptr)\n    {\n        return nullptr;\n    }\n\n    T* arrayPtr = reinterpret_cast<T*>(mem);\n    for (size_t i = 0; i < elementCount; ++i)\n    {\n        arrayPtr[i] = elements[i];\n    }\n    return arrayPtr;\n}\n\ntemplate<typename T>\ninline T* MakeArray(const Vector<T>& vector)\n{\n    auto mem = Alloc(vector.size() * sizeof(T));\n    if (mem == nullptr)\n    {\n        return nullptr;\n    }\n\n    T* arrayPtr = reinterpret_cast<T*>(mem);\n    for (size_t i = 0; i < vector.size(); ++i)\n    {\n        arrayPtr[i] = vector[i];\n    }\n    return arrayPtr;\n}\n\ntemplate<typename T>\ninline void DeleteArray(T* arrayPtr, size_t elementCount)\n{\n    for (size_t i = 0; i < elementCount; ++i)\n    {\n        arrayPtr[i].~T();\n    }\n    Free(arrayPtr, 0);\n}\n\ninline char** MakeArray(const Vector<String>& vector)\n{\n    char** arrayPtr = static_cast<char**>(Alloc(vector.size() * sizeof(char*)));\n    if (arrayPtr == nullptr)\n    {\n        return nullptr;\n    }\n\n    for (size_t i = 0; i < vector.size(); ++i)\n    {\n        arrayPtr[i] = Make(vector[i]);\n    }\n    return arrayPtr;\n}\n\ntemplate<>\ninline void DeleteArray(const char** arrayPtr, size_t elementCount)\n{\n    for (size_t i = 0; i < elementCount; ++i)\n    {\n        Delete(arrayPtr[i]);\n    }\n    Free(arrayPtr);\n}\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n// Keep old global namespace typedefs for now as well. These should be removed from xsapi lib and just kept\n// legacy header eventually.\n\ntemplate<class T>\nusing xsapi_internal_vector = xbox::services::Vector<T>;\n\ntemplate<class K, class V, class LESS = std::less<K>>\nusing xsapi_internal_map = xbox::services::Map<K, V, LESS>;\n\ntemplate<class K, class LESS = std::less<K>>\nusing xsapi_internal_set = xbox::services::Set<K, LESS>;\n\ntemplate<class K, class V, class HASH = std::hash<K>, class EQUAL = std::equal_to<K>>\nusing xsapi_internal_unordered_map = xbox::services::UnorderedMap<K, V, HASH, EQUAL>;\n\ntemplate<class K, class HASH = std::hash<K>, class EQUAL = std::equal_to<K>>\nusing xsapi_internal_unordered_set = xbox::services::UnorderedSet<K, HASH, EQUAL>;\n\nusing xsapi_internal_string = xbox::services::String;\nusing xsapi_internal_wstring = xbox::services::WString;\n\nusing xsapi_internal_stringstream = xbox::services::Stringstream;\nusing xsapi_internal_wstringstream = xbox::services::WStringstream;\n\nusing xsapi_internal_istringstream = xbox::services::IStringstream;\nusing xsapi_internal_wistringstream = xbox::services::WIStringstream;\n\nusing xsapi_internal_ostringstream = xbox::services::OStringstream;\nusing xsapi_internal_wostringstream = xbox::services::WOStringstream;\n\n#ifdef _WIN32\nusing xsapi_internal_string_t = xbox::services::WString;\nusing xsapi_internal_stringstream_t = xbox::services::WStringstream;\nusing xsapi_internal_istringstream_t = xbox::services::WIStringstream;\nusing xsapi_internal_ostringstream_t = xbox::services::WOStringstream;\n#else\nusing xsapi_internal_string_t = xbox::services::String;\nusing xsapi_internal_stringstream_t = xbox::services::Stringstream;\nusing xsapi_internal_istringstream_t = xbox::services::IStringstream;\nusing xsapi_internal_ostringstream_t = xbox::services::OStringstream;\n#endif\n\n\ntemplate<class T>\nusing xsapi_internal_dequeue = xbox::services::Deque<T>;\n\ntemplate<class T>\nusing xsapi_internal_queue = xbox::services::Queue<T>;\n\ntemplate<class T>\nusing xsapi_internal_list = xbox::services::List<T>;"
  },
  {
    "path": "Source/Shared/internal_types.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <string>\n#include <regex>\n#include <chrono>\n#include \"xsapi-c/types_c.h\"\n\n#if HC_PLATFORM_IS_MICROSOFT\n#define _XSAPIIMP_DEPRECATED __declspec(deprecated)    \n#ifdef _NO_XSAPIIMP\n#define _XSAPIIMP\n#else\n#ifdef _XSAPIIMP_EXPORT\n#define _XSAPIIMP __declspec(dllexport)\n#define _XSAPIIMP_DEPRECATED __declspec(dllexport, deprecated)\n#else\n#define _XSAPIIMP __declspec(dllimport)\n#define _XSAPIIMP_DEPRECATED __declspec(dllimport, deprecated)\n#endif\n#endif\n#else\n#if defined _NO_XSAPIIMP || __GNUC__ < 4\n#define _XSAPIIMP\n#define _XSAPIIMP_DEPRECATED __attribute__ ((deprecated))\n#else\n#define _XSAPIIMP __attribute__ ((visibility (\"default\")))\n#define _XSAPIIMP_DEPRECATED __attribute__ ((visibility (\"default\"), deprecated))\n#endif\n#endif\n\ntypedef void* function_context;\n#if HC_PLATFORM_IS_MICROSOFT\ntypedef wchar_t char_t;\ntypedef std::wstring string_t;\ntypedef std::wstringstream stringstream_t;\ntypedef std::wregex regex_t;\ntypedef std::wsmatch smatch_t;\n#else\ntypedef char char_t;\ntypedef std::string string_t;\ntypedef std::stringstream stringstream_t;\ntypedef std::regex regex_t;\ntypedef std::smatch smatch_t;\n#endif\n\n#if HC_PLATFORM_IS_MICROSOFT\ntypedef std::chrono::steady_clock chrono_clock_t;\n#else\ntypedef std::chrono::system_clock chrono_clock_t;\n#endif\n\n// Forward declarations\nnamespace xbox {\n    namespace services {\n        class xbox_live_context_settings;\n        namespace system {\n            class xbox_live_user;\n        }\n    }\n}\n\n#if HC_PLATFORM != HC_PLATFORM_XDK\n// SSL client certificate context\n#if HC_PLATFORM_IS_MICROSOFT\n#include <wincrypt.h>\ntypedef PCCERT_CONTEXT cert_context;\n#endif\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_UWP\ntypedef Windows::System::User^ user_creation_context;\n#else\ntypedef void* user_creation_context;\n#endif\n\ntypedef XblUserHandle xbox_live_user_t;\n\n#define XBL_ALIGN_SIZE 8\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN                     namespace xbox { namespace services {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END                       }}\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN                         namespace Microsoft { namespace Xbox { namespace Services { \n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_END                           }}}\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace system {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_BEGIN                  NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace System { \n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_END                    NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace social {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_CPP_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_BEGIN                  NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Social {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_END                    NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace achievements {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_CPP_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_BEGIN            NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Achievements {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_END              NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_BEGIN    NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace achievements { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_CPP_END      NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Achievements { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ACHIEVEMENTS_MANAGER_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace leaderboard {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Leaderboard {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_LEADERBOARD_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_BEGIN      NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace user_statistics {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_CPP_END        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_BEGIN          NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace UserStatistics {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_USERSTATISTICS_END            NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace multiplayer {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Multiplayer {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace matchmaking {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Matchmaking {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_CPP_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace marketplace {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_CPP_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Marketplace {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MARKETPLACE_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_BEGIN             NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace privacy {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_CPP_END               NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_BEGIN                 NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Privacy {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRIVACY_END                   NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_BEGIN                 NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace real_time_activity {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_CPP_END                   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_BEGIN                     NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace RealTimeActivity {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_RTA_END                       NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_BEGIN            NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace presence {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_CPP_END              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_BEGIN                NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Presence {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PRESENCE_END                  NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_CPP_BEGIN  NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace game_server_platform {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_CPP_END    NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_BEGIN      NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace GameServerPlatform {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_GAMESERVERPLATFORM_END        NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace title_storage {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_CPP_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_BEGIN           NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace TitleStorage {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_TITLE_STORAGE_END             NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace events {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_CPP_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_BEGIN                  NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Events {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EVENTS_END                    NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_CPP_BEGIN   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace contextual_search {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_CPP_END     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace ContextualSearch {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CONTEXTUAL_SEARCH_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_CPP_BEGIN   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace entertainment_profile {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_CPP_END     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace EntertainmentProfile {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_ENTERTAINMENT_PROFILE_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace notification {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_BEGIN NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace multiplayer { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_CPP_END   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Multiplayer { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_MULTIPLAYER_MANAGER_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_CPP_BEGIN        NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace experimental {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_CPP_END          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_BEGIN            NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Experimental {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_EXPERIMENTAL_END              NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace social { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_CPP_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Social { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_SOCIAL_MANAGER_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STAT_MANAGER_CPP_BEGIN     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace stats { namespace manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STAT_MANAGER_CPP_END       NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END } }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STATISTIC_MANAGER_BEGIN         NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Statistics { namespace Manager {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_STATISTIC_MANAGER_END           NAMESPACE_MICROSOFT_XBOX_SERVICES_END } }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_CPP_BEGIN   NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace player_state {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_CPP_END     NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_BEGIN       NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace PlayerState {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_PLAYER_STATE_END         NAMESPACE_MICROSOFT_XBOX_SERVICES_END }\n\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_CPP_BEGIN          NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN namespace clubs {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_CPP_END            NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END }\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_BEGIN              NAMESPACE_MICROSOFT_XBOX_SERVICES_BEGIN namespace Clubs {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CLUBS_END                NAMESPACE_MICROSOFT_XBOX_SERVICES_END }"
  },
  {
    "path": "Source/Shared/mem.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-cpp/mem.h\"\n#include \"xsapi-cpp/system.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/Shared/perf_tester.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include <mutex>\n#include <map>\n#include <chrono>\n\n#define ENABLE_PERF_PROFILING 0\n\n#if ENABLE_PERF_PROFILING\n#define PERF_START() xbox::services::detail::PerfTester::Instance().Start(__FUNCTION__)\n#define PERF_STOP() xbox::services::detail::PerfTester::Instance().Stop(__FUNCTION__)\n#define PERF_START_AREA(area) xbox::services::detail::PerfTester::Instance().Start(area)\n#define PERF_STOP_AREA(area) xbox::services::detail::PerfTester::Instance().Stop(area)\n\nnamespace xbox{\nnamespace services{\nnamespace detail{\n\nstruct PerfTester\n{\n    static PerfTester& Instance()\n    {\n        static PerfTester instance;\n        return instance;\n    }\n\n    void Start(const char* area)\n    {\n        std::lock_guard<std::mutex> lock{ m_mutex };\n        m_stats[area].StartTime = std::chrono::high_resolution_clock::now();\n    }\n\n    void Stop(const char* area)\n    {\n        std::lock_guard<std::mutex> lock{ m_mutex };\n        auto& stats{ m_stats[area] };\n\n        ++stats.Count;\n        auto duration{ std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - stats.StartTime).count() };\n        stats.AverageTime = static_cast<uint64_t>(stats.AverageTime * ((double)(stats.Count - 1) / stats.Count) + duration * (1 / (double)stats.Count));\n        if (duration > stats.MaxTime)\n        {\n            stats.MaxTime = duration;\n        }\n    }\n\n    std::string FormatStats() const\n    {\n        std::stringstream ss;\n        ss << __FUNCTION__ << std::endl;\n        for (auto& entry : m_stats)\n        {\n            auto& s{ entry.second };\n            ss << \"Area:\" << entry.first << \" Count:\" << s.Count << \" MaxTime:\" << s.MaxTime << \" AverageTime:\" << s.AverageTime << std::endl;\n        }\n        return ss.str();\n    }\n\nprivate:\n    PerfTester() = default;\n\n    struct Stats\n    {\n        int64_t Count{ 0 };\n        int64_t MaxTime{ 0 };\n        int64_t AverageTime{ 0 };\n        std::chrono::time_point<std::chrono::high_resolution_clock> StartTime{};\n    };\n\n    mutable std::mutex m_mutex;\n    std::map<std::string, Stats> m_stats;\n};\n\n}\n}\n}\n\n#else\n#define PERF_START()\n#define PERF_STOP()\n#define PERF_START_AREA(area)\n#define PERF_STOP_AREA(area)\n#endif\n"
  },
  {
    "path": "Source/Shared/public_utils_legacy.cpp",
    "content": "#include \"pch.h\"\n\n#define MS_TICKS        (10000)\n#define SECOND_TICKS    (1000 * MS_TICKS)\n#define MINUTE_TICKS    (60 * SECOND_TICKS)\n#define HOUR_TICKS      (60 * MINUTE_TICKS)\n#define DAY_TICKS       (24 * HOUR_TICKS)\n\nusing namespace xbox::services::cppresturi::utility;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxbl_error_code ConvertHrToXblErrorCode(HRESULT hr)\n{\n    switch (hr)\n    {\n        case S_OK: return xbl_error_code::no_error;\n        case E_OUTOFMEMORY: return xbl_error_code::bad_alloc;\n        case E_INVALIDARG: return xbl_error_code::invalid_argument;\n        case E_XBL_RUNTIME_ERROR: return xbl_error_code::runtime_error;\n        case __HRESULT_FROM_WIN32(ERROR_BAD_LENGTH): return xbl_error_code::length_error;\n        case E_BOUNDS: return xbl_error_code::out_of_range;\n\n        case E_NOINTERFACE: return xbl_error_code::bad_cast;\n        case E_UNEXPECTED: return xbl_error_code::logic_error;\n        case WEB_E_INVALID_JSON_STRING: return xbl_error_code::json_error;\n        case WEB_E_UNEXPECTED_CONTENT: return xbl_error_code::uri_error;\n        case ONL_E_ACTION_REQUIRED: return xbl_error_code::auth_user_interaction_required;\n        case E_XBL_RTA_GENERIC_ERROR: return xbl_error_code::rta_generic_error;\n        case E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED: return xbl_error_code::rta_subscription_limit_reached;\n        case E_XBL_RTA_ACCESS_DENIED: return xbl_error_code::rta_access_denied;\n        case E_XBL_RTA_NOT_ACTIVATED: return xbl_error_code::rta_not_activated;\n        case E_XBL_AUTH_UNKNOWN_ERROR: return xbl_error_code::auth_unknown_error;\n        case E_XBL_AUTH_RUNTIME_ERROR: return xbl_error_code::auth_runtime_error;\n        case E_XBL_AUTH_NO_TOKEN: return xbl_error_code::auth_no_token_error;\n        case __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER): return xbl_error_code::auth_user_not_signed_in;\n        case __HRESULT_FROM_WIN32(ERROR_CANCELLED): return xbl_error_code::auth_user_cancel;\n        case __HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION): return xbl_error_code::invalid_config;\n        case E_NOTIMPL: return xbl_error_code::unsupported;\n\n            // HTTP errors\n        case __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND): return xbl_error_code::http_status_204_resource_data_not_found;\n        case HTTP_E_STATUS_AMBIGUOUS: return xbl_error_code::http_status_300_multiple_choices;\n        case HTTP_E_STATUS_MOVED: return xbl_error_code::http_status_301_moved_permanently;\n        case HTTP_E_STATUS_REDIRECT: return xbl_error_code::http_status_302_found;\n        case HTTP_E_STATUS_REDIRECT_METHOD: return xbl_error_code::http_status_303_see_other;\n        case HTTP_E_STATUS_NOT_MODIFIED: return xbl_error_code::http_status_304_not_modified;\n        case HTTP_E_STATUS_USE_PROXY: return xbl_error_code::http_status_305_use_proxy;\n        case HTTP_E_STATUS_REDIRECT_KEEP_VERB: return xbl_error_code::http_status_307_temporary_redirect;\n\n        case HTTP_E_STATUS_BAD_REQUEST: return xbl_error_code::http_status_400_bad_request;\n        case HTTP_E_STATUS_DENIED: return xbl_error_code::http_status_401_unauthorized;\n        case HTTP_E_STATUS_PAYMENT_REQ: return xbl_error_code::http_status_402_payment_required;\n        case HTTP_E_STATUS_FORBIDDEN: return xbl_error_code::http_status_403_forbidden;\n        case HTTP_E_STATUS_NOT_FOUND: return xbl_error_code::http_status_404_not_found;\n        case HTTP_E_STATUS_BAD_METHOD: return xbl_error_code::http_status_405_method_not_allowed;\n        case HTTP_E_STATUS_NONE_ACCEPTABLE: return xbl_error_code::http_status_406_not_acceptable;\n        case HTTP_E_STATUS_PROXY_AUTH_REQ: return xbl_error_code::http_status_407_proxy_authentication_required;\n        case HTTP_E_STATUS_REQUEST_TIMEOUT: return xbl_error_code::http_status_408_request_timeout;\n        case HTTP_E_STATUS_CONFLICT: return xbl_error_code::http_status_409_conflict;\n        case HTTP_E_STATUS_GONE: return xbl_error_code::http_status_410_gone;\n        case HTTP_E_STATUS_LENGTH_REQUIRED: return xbl_error_code::http_status_411_length_required;\n        case HTTP_E_STATUS_PRECOND_FAILED: return xbl_error_code::http_status_412_precondition_failed;\n        case HTTP_E_STATUS_REQUEST_TOO_LARGE: return xbl_error_code::http_status_413_request_entity_too_large;\n        case HTTP_E_STATUS_URI_TOO_LONG: return xbl_error_code::http_status_414_request_uri_too_long;\n        case HTTP_E_STATUS_UNSUPPORTED_MEDIA: return xbl_error_code::http_status_415_unsupported_media_type;\n        case HTTP_E_STATUS_RANGE_NOT_SATISFIABLE: return xbl_error_code::http_status_416_requested_range_not_satisfiable;\n        case HTTP_E_STATUS_EXPECTATION_FAILED: return xbl_error_code::http_status_417_expectation_failed;\n        case MAKE_HTTP_HRESULT(421): return xbl_error_code::http_status_421_misdirected_request;\n        case MAKE_HTTP_HRESULT(422): return xbl_error_code::http_status_422_unprocessable_entity;\n        case MAKE_HTTP_HRESULT(423): return xbl_error_code::http_status_423_locked;\n        case MAKE_HTTP_HRESULT(424): return xbl_error_code::http_status_424_failed_dependency;\n        case MAKE_HTTP_HRESULT(426): return xbl_error_code::http_status_426_upgrade_required;\n        case MAKE_HTTP_HRESULT(428): return xbl_error_code::http_status_428_precondition_required;\n        case MAKE_HTTP_HRESULT(429): return xbl_error_code::http_status_429_too_many_requests;\n        case MAKE_HTTP_HRESULT(431): return xbl_error_code::http_status_431_request_header_fields_too_large;\n        case MAKE_HTTP_HRESULT(449): return xbl_error_code::http_status_449_retry_with;\n        case MAKE_HTTP_HRESULT(451): return xbl_error_code::http_status_451_unavailable_for_legal_reasons;\n\n        case HTTP_E_STATUS_SERVER_ERROR: return xbl_error_code::http_status_500_internal_server_error;\n        case HTTP_E_STATUS_NOT_SUPPORTED: return xbl_error_code::http_status_501_not_implemented;\n        case HTTP_E_STATUS_BAD_GATEWAY: return xbl_error_code::http_status_502_bad_gateway;\n        case HTTP_E_STATUS_SERVICE_UNAVAIL: return xbl_error_code::http_status_503_service_unavailable;\n        case HTTP_E_STATUS_GATEWAY_TIMEOUT: return xbl_error_code::http_status_504_gateway_timeout;\n        case HTTP_E_STATUS_VERSION_NOT_SUP: return xbl_error_code::http_status_505_http_version_not_supported;\n        case MAKE_HTTP_HRESULT(506): return xbl_error_code::http_status_506_variant_also_negotiates;\n        case MAKE_HTTP_HRESULT(507): return xbl_error_code::http_status_507_insufficient_storage;\n        case MAKE_HTTP_HRESULT(508): return xbl_error_code::http_status_508_loop_detected;\n        case MAKE_HTTP_HRESULT(510): return xbl_error_code::http_status_510_not_extended;\n        case MAKE_HTTP_HRESULT(511): return xbl_error_code::http_status_511_network_authentication_required;\n\n        default: return xbl_error_code::generic_error;\n    }\n}\n\nnamespace legacy\n{\n    string_t StringTFromUtf8(_In_z_ const char* utf8)\n    {\n        if (utf8 == nullptr)\n        {\n            return string_t();\n        }\n\n#if HC_PLATFORM_IS_MICROSOFT\n        auto cchOutString = CharTFromUft8(utf8, nullptr, 0);\n        string_t out(static_cast<size_t>(cchOutString) - 1, '\\0');\n        CharTFromUft8(utf8, &out[0], cchOutString);\n        return out;\n#else\n        return string_t(utf8);\n#endif\n    }\n\n    std::string StringFromStringT(_In_ const string_t& stringt)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        auto cchOutString = Utf8FromCharT(stringt.data(), nullptr, 0);\n        std::string out(static_cast<size_t>(cchOutString) - 1, '\\0');\n        Utf8FromCharT(stringt.data(), &out[0], cchOutString);\n        return out;\n#else\n        return std::string(stringt.data());\n#endif\n    }\n\n    int Utf8FromCharT(\n        _In_z_ const char_t* inArray,\n        _Out_writes_z_(cchOutArray) char* outArray,\n        _In_ int cchOutArray\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        // query for the buffer size\n        auto queryResult = WideCharToMultiByte(\n            CP_UTF8, WC_ERR_INVALID_CHARS,\n            inArray, -1,\n            nullptr, 0,\n            nullptr, nullptr\n        );\n\n        if (queryResult > cchOutArray && cchOutArray == 0)\n        {\n            return queryResult;\n        }\n        else if (queryResult == 0 || queryResult > cchOutArray)\n        {\n            throw std::exception(\"utf8_from_char_t failed\");\n        }\n\n        auto conversionResult = WideCharToMultiByte(\n            CP_UTF8, WC_ERR_INVALID_CHARS,\n            inArray, -1,\n            outArray, cchOutArray,\n            nullptr, nullptr\n        );\n        if (conversionResult == 0)\n        {\n            throw std::exception(\"utf8_from_char_t failed\");\n        }\n\n        return conversionResult;\n#else\n        int len = (int)strlen(inArray);\n        if (len < cchOutArray && outArray != nullptr)\n        {\n            strlcpy(outArray, inArray, len + 1);\n        }\n        else if (cchOutArray > 0)\n        {\n            return 0;\n        }\n        return len + 1;\n#endif\n    }\n\n    int CharTFromUft8(\n        _In_z_ const char* inArray,\n        _Out_writes_z_(cchOutArray) char_t* outArray,\n        _In_ int cchOutArray\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        // query for the buffer size\n        auto queryResult = MultiByteToWideChar(\n            CP_UTF8, MB_ERR_INVALID_CHARS,\n            inArray, -1,\n            nullptr, 0\n        );\n\n        if (queryResult > cchOutArray && cchOutArray == 0)\n        {\n            return queryResult;\n        }\n        else if (queryResult == 0 || queryResult > cchOutArray)\n        {\n            throw std::exception(\"char_t_from_utf8 failed\");\n        }\n\n        auto conversionResult = MultiByteToWideChar(\n            CP_UTF8, MB_ERR_INVALID_CHARS,\n            inArray, -1,\n            outArray, cchOutArray\n        );\n        if (conversionResult == 0)\n        {\n            throw std::exception(\"char_t_from_utf8 failed\");\n        }\n\n        return conversionResult;\n#else\n        int len = (int)strlen(inArray);\n        if (len < cchOutArray && outArray != nullptr)\n        {\n            strlcpy(outArray, inArray, len + 1);\n        }\n        else if (cchOutArray > 0)\n        {\n            return 0;\n        }\n        return len + 1;\n#endif\n    }\n\n    size_t CopyUtf8(\n        _In_ char* destinationCharArr,\n        _In_ size_t sizeInWords,\n        _In_ const char* sourceCharArr\n    )\n\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return strcpy_s(destinationCharArr, sizeInWords, sourceCharArr);\n#else\n        return strlcpy(destinationCharArr, sourceCharArr, sizeInWords);\n#endif\n    }\n\n    string_t StringTFromUint64(_In_ uint64_t val)\n    {\n        stringstream_t ss;\n        ss << val;\n        return ss.str();\n    }\n\n    std::string StringFromUint64(_In_ uint64_t val)\n    {\n        std::stringstream ss;\n        ss << val;\n        return ss.str();\n    }\n\n    uint64_t Uint64FromStringT(_In_ const string_t& str)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wtoi64(str.data());\n#else\n        return strtoull(str.data(), nullptr, 0);\n#endif\n    }\n\n    int Stricmp(const char* left, const char* right) noexcept\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _stricmp(left, right);\n#else\n        return strcasecmp(left, right);\n#endif\n    }\n\n    int Stricmp(const string_t& left, const string_t& right)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wcsicmp(left.data(), right.data());\n#else\n        return strcasecmp(left.data(), right.data());\n#endif \n    }\n\n    std::string SerializeJson(const rapidjson::Value& json)\n    {\n        rapidjson::StringBuffer buffer;\n        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n        json.Accept(writer);\n\n        return buffer.GetString();\n    }\n\n    const rapidjson::Value& ExtractJsonField(\n        _In_ const rapidjson::Value& json,\n        _In_ const std::string& name,\n        _In_ bool required\n    )\n    {\n        if (json.IsObject())\n        {\n            auto it = json.FindMember(name.c_str());\n            if (it != json.MemberEnd())\n            {\n                return it->value;\n            }\n        }\n\n        if (required)\n        {\n            //TODO: Throw exception\n        }\n\n        return json;\n    }\n\n    uint64_t ExtractJsonUint64(\n        _In_ const rapidjson::Value& jsonValue,\n        _In_ const std::string& name,\n        _In_ bool required,\n        _In_ uint64_t defaultValue\n    )\n    {\n        const rapidjson::Value& field(ExtractJsonField(jsonValue, name, required));\n        if (!field.IsNumber() && !required)\n        {\n            return defaultValue;\n        }\n        return field.GetUint64();\n    }\n\n    std::vector<string_t> XuidStringVectorFromXuidArray(const uint64_t* xuids, size_t xuidsCount)\n    {\n        return Transform<string_t>(xuids, xuidsCount, StringTFromUint64);\n    }\n\n    std::vector<uint64_t> XuidVectorFromXuidStringVector(const std::vector<string_t>& xuidStrings)\n    {\n        return Transform<uint64_t>(xuidStrings, Uint64FromStringT);\n    }\n\n    std::vector<string_t> StringTVectorFromCStringArray(const char** stringArray, size_t arrayCount)\n    {\n        return Transform<string_t>(stringArray, arrayCount, StringTFromUtf8);\n    }\n\n    xbox::services::cppresturi::utility::datetime DatetimeFromTimeT(time_t time)\n    {\n        const uint64_t epoch_offset = 11644473600LL;\n        uint64_t result = epoch_offset + time;\n        result *= SECOND_TICKS; // convert to 10e-7\n        return xbox::services::cppresturi::utility::datetime() + result;\n    }\n\n    time_t TimeTFromDatetime(const xbox::services::cppresturi::utility::datetime& datetime)\n    {\n        const uint64_t epoch_offset = 11644473600LL;\n        uint64_t seconds = datetime.to_interval() / SECOND_TICKS;\n        if (seconds >= epoch_offset)\n        {\n            return (time_t)(seconds - epoch_offset);\n        }\n        else\n        {\n            // If time is before epoch, 0 is returned.\n            return 0;\n        }\n    }\n\n    char_t ToLower(char_t c)\n    {\n        return std::tolower<char_t>(c, std::locale());\n    }\n\n    std::error_code ConvertHr(HRESULT hr)\n    {\n        return make_error_code(ConvertHrToXblErrorCode(hr));\n    }\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/public_utils_legacy.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"HookedUri/uri.h\"\n#include \"HookedUri/uri_builder.h\"\n#include \"HookedUri/asyncrt_utils.h\"\n\n#ifndef MAKE_HTTP_HRESULT\n#define MAKE_HTTP_HRESULT(code) MAKE_HRESULT(1, 0x019, code)\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxbl_error_code ConvertHrToXblErrorCode(HRESULT hr);\n\nnamespace legacy\n{\n    string_t StringTFromUtf8( _In_z_ const char* utf8 );\n\n    std::string StringFromStringT(_In_ const string_t& stringt);\n\n    int Utf8FromCharT( _In_z_ const char_t* inArray,\n                       _Out_writes_z_(cchOutArray) char* outArray,\n                       _In_ int cchOutArray );\n\n    int CharTFromUft8( _In_z_ const char* inArray,\n                       _Out_writes_z_(cchOutArray) char_t* outArray,\n                       _In_ int cchOutArray );\n\n    size_t CopyUtf8( _In_ char* destinationCharArr,\n                     _In_ size_t sizeInWords,\n                     _In_ const char* sourceCharArr );\n\n    string_t StringTFromUint64(_In_ uint64_t val);\n\n    std::string StringFromUint64(_In_ uint64_t val);\n\n    uint64_t Uint64FromStringT(_In_ const string_t& str);\n\n    int Stricmp(const char* left, const char* right) noexcept;\n\n    int Stricmp(const string_t& left, const string_t& right);\n    \n    std::string SerializeJson(const rapidjson::Value& json);\n\n    const rapidjson::Value& ExtractJsonField(\n        _In_ const rapidjson::Value& json,\n        _In_ const std::string& name,\n        _In_ bool required\n    );\n\n    uint64_t ExtractJsonUint64(\n        _In_ const rapidjson::Value& jsonValue,\n        _In_ const std::string& name,\n        _In_ bool required = false,\n        _In_ uint64_t defaultValue = 0\n    );\n\n    template<typename TOut, typename InputIt, typename Transformer>\n    std::vector<TOut> Transform(InputIt first, InputIt last, Transformer op)\n    {\n        std::vector<TOut> out;\n        std::transform(first, last, std::back_inserter(out), op);\n        return out;\n    }\n\n    template<typename TOut, typename TIn, typename Transformer>\n    std::vector<TOut> Transform(const std::vector<TIn>& in, Transformer op)\n    {\n        return Transform<TOut>(in.begin(), in.end(), op);\n    }\n\n    template<typename TOut, typename TIn, typename Transformer>\n    std::vector<TOut> Transform(TIn* inArray, size_t inArrayCount, Transformer op)\n    {\n        return Transform<TOut>(inArray, inArray + inArrayCount, op);\n    }\n\n    template<typename TOut, typename TIn>\n    std::vector<TOut> Transform(TIn* inArray, size_t inArrayCount)\n    {\n        return Transform<TOut>(inArray, inArrayCount, [](const TIn& in)\n            {\n                return TOut(in);\n            });\n    }\n\n    std::vector<string_t> XuidStringVectorFromXuidArray(const uint64_t* xuids, size_t xuidsCount);\n\n    std::vector<uint64_t> XuidVectorFromXuidStringVector(const std::vector<string_t>& xuidStrings);\n\n    std::vector<string_t> StringTVectorFromCStringArray(const char** stringArray, size_t arrayCount);\n\n    xbox::services::cppresturi::utility::datetime DatetimeFromTimeT(time_t time);\n\n    time_t TimeTFromDatetime(const xbox::services::cppresturi::utility::datetime& datetime);\n\n    char_t ToLower(char_t c);\n\n    std::error_code ConvertHr(HRESULT hr);\n\n\n#if !XSAPI_NO_PPL\n\n    template<typename T>\n    struct AsyncWrapper\n    {\n        typedef std::function<HRESULT(XAsyncBlock*, T&)> ResultExtractor;\n\n        AsyncWrapper(ResultExtractor resultExtractor)\n            : m_resultExtractor(std::move(resultExtractor))\n        {\n            async.queue = XblGetAsyncQueue();\n            async.context = this;\n            async.callback = [](XAsyncBlock* async)\n            {\n                auto thisPtr = static_cast<AsyncWrapper<T>*>(async->context);\n                T result;\n                auto hr = thisPtr->m_resultExtractor(async, result);\n                if (SUCCEEDED(hr))\n                {\n                    thisPtr->m_taskCompletionEvent.set(xbl_result<T>(result));\n                }\n                else\n                {\n                    thisPtr->m_taskCompletionEvent.set(xbl_result<T>(ConvertHr(hr)));\n                }\n                delete thisPtr;\n            };\n        }\n\n        XAsyncBlock async{};\n\n        // If the Async API fails, the callback will never be invoked. Return a failure task and self destruct.\n        pplx::task<xbl_result<T>> Task(HRESULT asyncApiResult)\n        {\n            if (SUCCEEDED(asyncApiResult))\n            {\n                return pplx::task<xbl_result<T>>(m_taskCompletionEvent);\n            }\n            else\n            {\n                delete this;\n                return pplx::task_from_result(xbl_result<T>(ConvertHr(asyncApiResult)));\n            }\n        }\n\n        private:\n        AsyncWrapper(const AsyncWrapper&) = delete;\n        AsyncWrapper& operator=(AsyncWrapper) = delete;\n\n        ResultExtractor m_resultExtractor;\n        pplx::task_completion_event<xbl_result<T>> m_taskCompletionEvent;\n    };\n\n    template<>\n    struct AsyncWrapper<void>\n    {\n        typedef std::function<HRESULT(XAsyncBlock*)> ResultExtractor;\n\n        AsyncWrapper() : AsyncWrapper{ [](XAsyncBlock* async) { return XAsyncGetStatus(async, false); } }\n        {\n        }\n\n        AsyncWrapper(ResultExtractor resultExtractor)\n            : m_resultExtractor{ std::move(resultExtractor) }\n        {\n            async.queue = XblGetAsyncQueue();\n            async.context = this;\n            async.callback = [](XAsyncBlock* async)\n            {\n                auto thisPtr = static_cast<AsyncWrapper<void>*>(async->context);\n                auto hr = thisPtr->m_resultExtractor(async);\n                thisPtr->m_taskCompletionEvent.set(xbl_result<void>(ConvertHr(hr)));\n                delete thisPtr;\n            };\n        }\n\n        XAsyncBlock async{};\n\n        pplx::task<xbl_result<void>> Task(HRESULT asyncApiResult)\n        {\n            if (SUCCEEDED(asyncApiResult))\n            {\n                return pplx::task<xbl_result<void>>(m_taskCompletionEvent);\n            }\n            else\n            {\n                // If the Async API fails, the callback will never be invoked. Return a failure task and self destruct.\n                delete this;\n                return pplx::task_from_result(xbl_result<void>(ConvertHr(asyncApiResult)));\n            }\n        }\n\n        private:\n        AsyncWrapper(const AsyncWrapper&) = delete;\n        AsyncWrapper& operator=(AsyncWrapper) = delete;\n\n        ResultExtractor m_resultExtractor;\n        pplx::task_completion_event<xbl_result<void>> m_taskCompletionEvent;\n    };\n\n#endif\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/ref_counter.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"ref_counter.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nvoid RefCounter::AddRef()\n{\n    if (m_refCount++ == 0)\n    {\n        m_extraRefHolder = GetSharedThis();\n    }\n}\n\nvoid RefCounter::DecRef()\n{\n    if (--m_refCount == 0)\n    {\n        m_extraRefHolder.reset();\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/ref_counter.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// Class for managing client ref count to Xbox Live objects. All types that need client references\n// counted should inherit from this class\nstruct RefCounter\n{\n    RefCounter() = default;\n    virtual ~RefCounter() = default;\n\n    void AddRef();\n    void DecRef();\n\nprotected:\n    virtual std::shared_ptr<RefCounter> GetSharedThis() = 0;\n\nprivate:\n    std::atomic<uint32_t> m_refCount{ 0 };\n    std::shared_ptr<RefCounter> m_extraRefHolder;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/service_call_routed_handler.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"service_call_routed_handler.h\"\n#include \"http_call_request_message_internal.h\"\n#include \"xsapi_utils.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nServiceCallRoutedHandler::ServiceCallRoutedHandler(\n    _In_ XblCallRoutedHandler handler,\n    _In_opt_ void* context\n) noexcept :\n    m_clientHandler{ handler },\n    m_clientContext{ context }\n{\n    m_hcToken = HCAddCallRoutedHandler(HCCallRoutedHandler, this);\n}\n\nServiceCallRoutedHandler::~ServiceCallRoutedHandler() noexcept\n{\n    HCRemoveCallRoutedHandler(m_hcToken);\n}\n\nvoid ServiceCallRoutedHandler::HCCallRoutedHandler(\n    _In_ HCCallHandle call,\n    _In_ void* context\n)\n{\n    auto pThis{ static_cast<ServiceCallRoutedHandler*>(context) };\n\n    String formattedResponse{ pThis->GetFormattedResponse(call) };\n\n    XblServiceCallRoutedArgs args\n    {\n        call,\n        s_nextResponseNumber++,\n        formattedResponse.data()\n    };\n\n    pThis->m_clientHandler(args, pThis->m_clientContext);\n}\n\nString ServiceCallRoutedHandler::GetFormattedResponse(\n    HCCallHandle call\n) const noexcept\n{\n    Stringstream response;\n\n    response << \"== [XBOX SERVICE CALL] #\";\n    response << s_nextResponseNumber;\n    response << \"\\r\\n\";\n\n    const char* uri{ nullptr };\n    HCHttpCallGetRequestUrl(call, &uri);\n    response << \"\\r\\n[URI]: \";\n    response << uri;\n\n    const char* token{ nullptr };\n    HCHttpCallResponseGetHeader(call, AUTH_HEADER, &token);\n    if (token)\n    {\n        response << \"\\r\\n[Authorization Header]: \";\n        response << token;\n    }\n\n    const char* signature{ nullptr };\n    HCHttpCallResponseGetHeader(call, SIG_HEADER, &signature);\n    if (signature)\n    {\n        response << \"\\r\\n[Signature Header]: \";\n        response << signature;\n    }\n\n    uint32_t httpStatus{ 0 };\n    HCHttpCallResponseGetStatusCode(call, &httpStatus);\n    response << \"\\r\\n[HTTP Status]: \";\n    response << httpStatus;\n#if HC_PLATFORM_IS_MICROSOFT\n    HRESULT hr = utils::convert_http_status_to_hresult(httpStatus);\n    response << \" [\";\n    response << utils::convert_hresult_to_error_name(hr);\n    response << \"] \";\n#endif\n\n    uint32_t numHeaders{ 0 };\n    HCHttpCallResponseGetNumHeaders(call, &numHeaders);\n\n    if (numHeaders > 0)\n    {\n        response << \"\\r\\n[Response Headers]: \";\n\n        const char* headerName{ nullptr };\n        const char* headerValue{ nullptr };\n        for (uint32_t i = 0; i < numHeaders; ++i)\n        {\n            HCHttpCallResponseGetHeaderAtIndex(call, i, &headerName, &headerValue);\n            response << headerName << \" : \" << headerValue << \"; \";\n        }\n    }\n\n    const char* responseBody{ nullptr };\n    HCHttpCallResponseGetResponseString(call, &responseBody);\n    if (responseBody)\n    {\n        response << \"\\r\\n[Response Body]: \";\n        response << responseBody;\n    }\n\n    response << \"\\r\\n\";\n\n    return response.str();\n}\n\nstd::atomic<uint64_t> ServiceCallRoutedHandler::s_nextResponseNumber{ 0 };\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/service_call_routed_handler.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"http_call_request_message_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass ServiceCallRoutedHandler\n{\npublic:\n    ServiceCallRoutedHandler(\n        _In_ XblCallRoutedHandler handler,\n        _In_opt_ void* context\n    ) noexcept;\n\n    ~ServiceCallRoutedHandler() noexcept;\n\nprivate:\n    static void HCCallRoutedHandler(\n        _In_ HCCallHandle call,\n        _In_ void* context\n    );\n\n    String GetFormattedResponse(\n        HCCallHandle call\n    ) const noexcept;\n\n    XblCallRoutedHandler m_clientHandler{ nullptr };\n    void* m_clientContext{ nullptr };\n    int32_t m_hcToken{ 0 };\n    static std::atomic<uint64_t> s_nextResponseNumber;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/shared_macros.h",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"build_version.h\"\n\n#ifndef XSAPI_UNIT_TESTS\n#define XSAPI_ASSERT(x) assert(x);\n#else\n#define XSAPI_ASSERT(x) if(!(x)) throw std::invalid_argument(\"\");\n#endif\n\n#define VERIFY_XBL_INITIALIZED() { if (xbox::services::GlobalState::Get() == nullptr) return E_XBL_NOT_INITIALIZED; }\n\n#if defined(XSAPI_UNIT_TESTS)\n#if !XSAPI_NO_PPL\n#define RETURN_TASK_CPP_INVALIDARGUMENT_IF(x, type, message) { if ( x ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message)); } }\n#endif // !XSAPI_NO_PPL\n#define RETURN_CPP_INVALIDARGUMENT_IF(x, type, message) { if ( x ) { return xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message); } }\n#define RETURN_HR_INVALIDARGUMENT_IF(x) { if ( x ) { return E_INVALIDARG; } }\n#define RETURN_HR_INVALIDARGUMENT_IF_NULL(x) { if ( ( x ) == nullptr ) { return E_INVALIDARG; } }\n#define RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(x) { if ( x[0] == 0) { return E_INVALIDARG; } }\n#else\n#if !XSAPI_NO_PPL\n#define RETURN_TASK_CPP_INVALIDARGUMENT_IF(x, type, message) { assert(!(x)); if ( x ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message)); } }\n#endif // !XSAPI_NO_PPL\n#define RETURN_CPP_INVALIDARGUMENT_IF(x, type, message) { assert(!(x)); if ( x ) { return xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message); } }\n#define RETURN_HR_INVALIDARGUMENT_IF(x) { assert(!(x)); if ( x ) { return E_INVALIDARG; } }\n#define RETURN_HR_INVALIDARGUMENT_IF_NULL(x) { assert(!(( x ) == nullptr)); if ( ( x ) == nullptr ) { return E_INVALIDARG; } }\n#define RETURN_HR_INVALIDARGUMENT_IF_EMPTY_STRING(x) { assert(!(x[0] == 0)); if ( x[0] == 0) { return E_INVALIDARG; } }\n#endif\n#define INIT_OUT_PTR_PARAM(x) { if ( x ) { *x = nullptr; } }\n#define THROW_CPP_INVALIDARGUMENT_IF(x) if ( x ) { throw std::invalid_argument(\"\"); }\n#define THROW_CPP_INVALIDARGUMENT_IF_NULL(x) if ( ( x ) == nullptr ) { throw std::invalid_argument(\"\"); }\n\n#if !XSAPI_NO_PPL\n    #if defined(XSAPI_UNIT_TESTS)\n    #define RETURN_TASK_CPP_INVALIDARGUMENT_IF(x, type, message) { if ( x ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message)); } }\n    #define RETURN_TASK_CPP_INVALIDARGUMENT_IF_STRING_EMPTY(x, type, message) { if ( x.empty() ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message));  } }\n    #else\n    #define RETURN_TASK_CPP_INVALIDARGUMENT_IF_STRING_EMPTY(x, type, message) { assert(!x.empty()); if ( x.empty() ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message));  } }\n    #define RETURN_TASK_CPP_INVALIDARGUMENT_IF(x, type, message) { assert(!(x)); if ( x ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::invalid_argument, message)); } }\n    #endif\n\n    #define RETURN_TASK_CPP_IF_ERR(x, type) if ( x.err() ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(x.err(), x.err_message())); }\n    #define RETURN_TASK_CPP_IF(x, type, message) { if ( x ) { return pplx::task_from_result(xbox::services::xbox_live_result<type>(xbox_live_error_code::logic_error, message)); } }\n#endif // !XSAPI_NO_PPL\n\n#define THROW_CPP_INVALIDARGUMENT_IF_STRING_EMPTY(x) { auto y = x; if ( y.empty() ) { throw std::invalid_argument(\"\"); } }\n#define RETURN_CPP_IF_ERR(x, type) if ( x.err() ) { return xbox::services::xbox_live_result<type>(x.err(), x.err_message()); }\n#define RETURN_CPP_IF(x, type, errc, message) { if ( x ) { return xbox::services::xbox_live_result<type>(errc, message); } }\n#define RETURN_HR_IF(x, hr) { if (x) { return hr; } }\n#define RETURN_HR_IF_FAILED(expr) { HRESULT exprResult{ expr }; if (FAILED(exprResult)) { return exprResult; } }\n#define RETURN_PENDING_OR_HR(expr) { HRESULT exprResult{ expr }; return SUCCEEDED(exprResult) ? E_PENDING : exprResult; }\n#define RETURN_HR_IF_LOG_DEBUG(x, hr, message) { if (x) { LOG_DEBUG(message); return hr; } }\n\n#define ASSERT_CPP_INVALIDARGUMENT_IF_NULL(x) XSAPI_ASSERT(x != nullptr);\n#define ASSERT_CPP_INVALIDARGUMENT_IF(x) XSAPI_ASSERT(x)\n#define ASSERT_CPP_INVALIDARGUMENT_IF_STRING_EMPTY(x) XSAPI_ASSERT(!x.empty());\n\n#define THROW_CPP_RUNTIME_IF(x,y) if ( x ) { throw std::runtime_error(y); }\n\n#define COMPLETE_ASYNC_AND_RETURN(async, result, resultSize, returnValue) { XAsyncComplete(async, result, resultSize); return returnValue; }\n#define COMPLETE_ASYNC_AND_RETURN_VOID(async, result, resultSize) { XAsyncComplete(async, result, resultSize); return; }\n\n#define NO_COPY_AND_ASSIGN(T) \\\n    T(const T&); \\\n    T& operator=(const T&);\n\n#define SECONDS_PER_DAY 86400\n\n#define STRING_T_FROM_PLATFORM_STRING(x) \\\n    (x->IsEmpty() ? string_t() : string_t(x->Data()))\n\n#define PLATFORM_STRING_FROM_STRING_T(x) \\\n    (x.empty() ? nullptr : ref new Platform::String(x.c_str()))\n\n#define PLATFORM_STRING_FROM_INTERNAL_STRING(x) \\\n    (x.empty() ? nullptr : ref new Platform::String(xbox::services::utils::string_t_from_internal_string(x).c_str()))\n\n#define INTERNAL_STRING_FROM_PLATFORM_STRING(x) \\\n    (x->IsEmpty() ? xsapi_internal_string() : xbox::services::utils::internal_string_from_utf16(x->Data()))\n\n#define AUTH_HEADER (\"Authorization\")\n#define SIG_HEADER (\"Signature\")\n#define ETAG_HEADER (\"ETag\")\n#define DATE_HEADER (\"Date\")\n#define RETRY_AFTER_HEADER (\"Retry-After\")\n#define DEFAULT_USER_AGENT \"XboxServicesAPI/\" XBOX_SERVICES_API_VERSION_STRING\n\n#define RETURN_EXCEPTION_FREE_XBOX_LIVE_RESULT(func, type) \\\n{ \\\n    try { return func; } \\\n    catch (const std::exception& e) \\\n    { \\\n        xbox_live_error_code err = xbox::services::utils::convert_exception_to_xbox_live_error_code(); \\\n        return xbox_live_result<type>(err, e.what()); \\\n    } \\\n}\n\n#define RETURN_EXCEPTION_FREE_XBOX_LIVE_RESULT_FROM_HR(func, type) \\\n{ \\\n    try \\\n    { \\\n        auto hr = func; \\\n        return xbox_live_result<type>(xbox_live_error_code(hr)); \\\n    } \\\n    catch (const std::exception& e) \\\n    { \\\n        xbox_live_error_code err = xbox::services::utils::convert_exception_to_xbox_live_error_code(); \\\n        return xbox_live_result<type>(err, e.what()); \\\n    } \\\n}\n\n#define RETURN_EXCEPTION_FREE_HRESULT(func) \\\n{ \\\n    try { return func; } \\\n    catch (const std::exception& e) \\\n    { \\\n        e; \\\n        return utils::convert_exception_to_hresult(); \\\n    } \\\n}\n\n#define CREATE_EXTERNAL_XBOX_LIVE_RESULT(type, internalReturnObj) \\\n    xbox_live_result<type>(type(internalReturnObj.payload()), internalReturnObj.err(), internalReturnObj.err_message())\n\n\n#define CATCH_RETURN() \\\n    catch (...) { return xbox::services::utils::convert_exception_to_hresult(); }\n\n#define CATCH_RETURN_WITH(errCode) \\\n    catch (...) \\\n    { \\\n        HRESULT hr = xbox::services::utils::convert_exception_to_hresult(); \\\n        xsapi_internal_stringstream ss; \\\n        ss << \"Exception reached api boundry: HR\" << hr; \\\n        LOG_ERROR(ss.str().data()); \\\n        return errCode; \\\n    }\n\n#define DEFINE_GET_STRING(className, methodName) \\\n    string_t className::methodName() const \\\n    { \\\n        return utils::string_t_from_internal_string(m_internalObj->methodName()); \\\n    }\n\n#define DEFINE_GET_STD_STRING(className, methodName) \\\n    std::string className::methodName() const \\\n    { \\\n        return std::string(m_internalObj->methodName().data()); \\\n    }\n\n#define DEFINE_GET_BOOL(className, methodName) \\\n    bool className::methodName() const \\\n    { \\\n        return m_internalObj->methodName(); \\\n    }\n\n#define DEFINE_GET_UINT32(className, methodName) \\\n    uint32_t className::methodName() const \\\n    { \\\n        return m_internalObj->methodName(); \\\n    }\n\n#define DEFINE_GET_ENUM_TYPE(className, enumType, methodName) \\\n    enumType className::methodName() const \\\n    { \\\n        return m_internalObj->methodName(); \\\n    }\n\n#define DEFINE_GET_URI(className, methodName) \\\n    const xbox::services::uri& className::methodName() const \\\n    { \\\n        return m_internalObj->methodName(); \\\n    }\n\n#define DEFINE_GET_VECTOR_INTERNAL_TYPE(className, externalType, methodName) \\\n    std::vector<externalType> className::methodName() const \\\n    { \\\n        return utils::std_vector_external_from_internal_vector<externalType, std::shared_ptr<externalType##_internal>>(m_internalObj->methodName()); \\\n    }\n\n#define DEFINE_GET_VECTOR(className, typeName, methodName) \\\n    std::vector<typeName> className::methodName() const \\\n    { \\\n        return utils::std_vector_from_internal_vector<typeName>(m_internalObj->methodName()); \\\n    }\n\n#define DEFINE_GET_OBJECT(className, objectType, methodName) \\\n    objectType className::methodName() const \\\n    { \\\n        return m_internalObj->methodName(); \\\n    }\n\n#define DEFINE_GET_OBJECT_REF(className, objectType, methodName) \\\n    const objectType& className::methodName() const \\\n    { \\\n        return m_internalObj->methodName(); \\\n    }\n\n\n// Disable Warning macros\n\n// if msvc\n#if defined (_MSC_VER)\n\n#define DISABLE_WARNING_PUSH                    __pragma(warning(push))\n#define DISABLE_WARNING_POP                     __pragma(warning(pop))\n#define DISABLE_WARNING(warningCode)            __pragma(warning(disable:warningCode))  // expects numeric code for msvc\n#define SUPPRESS_ANALYSIS_WARNING(warningCode)  __pragma(warning(suppress:warningCode))\n\n#define SUPPRESS_WARNING_NULL_PTR_DEREFERENCE   SUPPRESS_ANALYSIS_WARNING(6011)\n#define SUPPRESS_WARNING_UNINITIALIZED_MEMORY   SUPPRESS_ANALYSIS_WARNING(6001)\n#define SUPPRESS_WARNING_EXPRESSION_NOT_TRUE    SUPPRESS_ANALYSIS_WARNING(28020)\n#define SUPPRESS_WARNING_UNINITIALIZED_MEMBER   SUPPRESS_ANALYSIS_WARNING(26495)\n#define SUPPRESS_WARNING_UNNAMED_CUSTOM_OBJ     SUPPRESS_ANALYSIS_WARNING(26444)\n\n\n#elif defined(__GNUC__)\n\n#define DO_PRAGMA(X)                            _Pragma(#X)\n#define DISABLE_WARNING_PUSH                    DO_PRAGMA(GCC diagnostic push)\n#define DISABLE_WARNING_POP                     DO_PRAGMA(GCC diagnostic pop)\n#define DISABLE_WARNING(warningCode)            DO_PRAGMA(GCC diagnostic ignored #warningCode)  // expects arg name for clang and gnu compilers\n#define SUPPRESS_ANALYSIS_WARNING(warningCode)  // gnu doesn't support per-instance static analyzer warning suppression\n\n#define SUPPRESS_WARNING_NULL_PTR_DEREFERENCE\n#define SUPPRESS_WARNING_UNINITIALIZED_MEMORY\n#define SUPPRESS_WARNING_EXPRESSION_NOT_TRUE \n#define SUPPRESS_WARNING_UNINITIALIZED_MEMBER\n#define SUPPRESS_WARNING_UNNAMED_CUSTOM_OBJ  \n\n\n#elif defined(__clang__)\n\n#define DO_PRAGMA(X)                            _Pragma(#X)\n#define DISABLE_WARNING_PUSH                    DO_PRAGMA(GCC diagnostic push)\n#define DISABLE_WARNING_POP                     DO_PRAGMA(GCC diagnostic pop)\n#define DISABLE_WARNING(warningCode)            DO_PRAGMA(GCC diagnostic ignored #warningCode)  // expects arg name for clang and gnu compilers\n#define SUPPRESS_ANALYSIS_WARNING(warningCode)  // clang doesn't support per-instance static analyzer warning suppression\n\n#define SUPPRESS_WARNING_NULL_PTR_DEREFERENCE\n#define SUPPRESS_WARNING_UNINITIALIZED_MEMORY\n#define SUPPRESS_WARNING_EXPRESSION_NOT_TRUE \n#define SUPPRESS_WARNING_UNINITIALIZED_MEMBER\n#define SUPPRESS_WARNING_UNNAMED_CUSTOM_OBJ  \n\n\n// default for non-defined platforms\n#else\n\n#define DISABLE_WARNING_PUSH\n#define DISABLE_WARNING_POP\n#define DISABLE_WARNING(warningCode)\n\n#define SUPPRESS_WARNING_NULL_PTR_DEREFERENCE\n#define SUPPRESS_WARNING_UNINITIALIZED_MEMORY\n#define SUPPRESS_WARNING_EXPRESSION_NOT_TRUE \n#define SUPPRESS_WARNING_UNINITIALIZED_MEMBER\n#define SUPPRESS_WARNING_UNNAMED_CUSTOM_OBJ  \n\n\n#endif"
  },
  {
    "path": "Source/Shared/string_array.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// RAII class wrapping an array C-Strings\nclass UTF8StringArray\n{\npublic:\n    UTF8StringArray(const xsapi_internal_vector<xsapi_internal_string>& vector)\n    {\n        std::transform(vector.begin(), vector.end(), std::back_inserter(m_strings), \n            [](const xsapi_internal_string& in)\n            {\n                return Make(in);\n            });\n    }\n\n    UTF8StringArray(const UTF8StringArray& other)\n    {\n        std::transform(other.m_strings.begin(), other.m_strings.end(), std::back_inserter(m_strings),\n            [](const char* in)\n            {\n                return Make(in);\n            });\n    }\n\n    UTF8StringArray(UTF8StringArray&& other) noexcept\n        : m_strings{ std::move(other.m_strings) }\n    {\n    }\n\n    UTF8StringArray& operator=(UTF8StringArray other)\n    {\n        std::swap(other.m_strings, m_strings);\n        return *this;\n    }\n\n    ~UTF8StringArray() noexcept\n    {\n        for (auto string : m_strings)\n        {\n            Delete(string);\n        }\n    }\n\n    const char** Data() noexcept\n    {\n        return m_strings.data();\n    }\n\n    size_t Size() const noexcept\n    {\n        return m_strings.size();\n    }\n\nprivate:\n    xsapi_internal_vector<const char*> m_strings;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/u/xbl_guid.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"pch.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nxsapi_internal_string generate_guid();\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/uri_impl.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"HookedUri/details/asyncrt_utils.hpp\"\n#include \"HookedUri/details/uri.hpp\"\n#include \"HookedUri/details/uri_builder.hpp\"\n#include \"HookedUri/details/uri_parser.hpp\"\n\n"
  },
  {
    "path": "Source/Shared/user.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"user.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nUser::User(XblUserHandle userHandle) noexcept\n    : m_handle(userHandle)\n{}\n\n\nUser::User(User&& other) noexcept\n    : m_handle{ other.m_handle }, m_xuid{ other.m_xuid }, m_localId { std::move(other.m_localId) }\n{\n    Map<XalGamertagComponent, String>::iterator it = other.m_gamertags.begin();\n\n    while(it != other.m_gamertags.end())\n    {\n        m_gamertags[it->first] = std::move(it->second);\n        it++;\n    }\n\n    other.m_gamertags.clear();\n    other.m_handle = nullptr;\n}\n\nUser& User::operator=(User&& other) noexcept\n{\n    std::swap(other.m_handle, m_handle);\n\n    m_localId = std::move(other.m_localId);\n    m_xuid = other.m_xuid;\n\n    Map<XalGamertagComponent, String>::iterator it = other.m_gamertags.begin();\n\n    while (it != other.m_gamertags.end())\n    {\n        m_gamertags[it->first] = std::move(it->second);\n        it++;\n    }\n\n    other.m_gamertags.clear();\n    return *this;\n}\n\nUser::~User() noexcept\n{\n    if (m_handle)\n    {\n        XalUserCloseHandle(m_handle);\n    }\n}\n\n/*static*/ Result<User> User::WrapHandle(XblUserHandle userHandle) noexcept\n{\n    if (XblShouldFaultInject(INJECTION_FEATURE_USER))\n    {\n        LOGS_ERROR << \"FAULT INJECTION: User::WrapHandle ID:\" << XblGetFaultCounter();\n        return Result<User>{ User(nullptr), E_FAIL };\n    }\n\n    if (userHandle == nullptr)\n    {\n        return Result<User>{ User(nullptr), E_INVALIDARG };\n    }\n\n    XalUserHandle copiedHandle;\n    auto hr = XalUserDuplicateHandle(userHandle, &copiedHandle);\n    if (FAILED(hr))\n    {\n        LOGS_ERROR << \"Copying user failed: User failed to duplicate.\";\n        return Result<User>{ User(nullptr), hr };\n    }\n    else\n    {\n        User user{ copiedHandle };\n        hr = user.InitializeUser();\n\n        if (FAILED(hr))\n        {\n            LOGS_ERROR << \"Copying user failed: User failed to duplicate.\";\n            return Result<User>{ User(nullptr), hr };\n        }\n\n        return Result<User>{ std::move(user) , S_OK };\n    }\n\n}\n\nHRESULT User::InitializeUser() noexcept\n{\n    auto hr = XalUserGetId(m_handle, &m_xuid);\n    if (FAILED(hr))\n    {\n        LOGS_ERROR << \"Failed to get User ID with HRESULT: \" << hr;\n        return hr;\n    }\n\n    hr = XalUserGetLocalId(m_handle, &m_localId);\n    if (FAILED(hr))\n    {\n        LOGS_ERROR << \"Failed to get User LocalID with HRESULT: \" << hr;\n        return hr;\n    }\n\n    auto gamertagComponentResult = GetGamertagComponent(XalGamertagComponent_Classic);\n    if (FAILED(gamertagComponentResult.Hresult()))\n    {\n        LOGS_ERROR << \"Failed to get Gamertag Component\" << XalGamertagComponent_Classic << \" with HRESULT: \" << hr;\n        return hr;\n    }\n\n    m_gamertags[XalGamertagComponent_Classic] = gamertagComponentResult.ExtractPayload();\n\n    gamertagComponentResult = GetGamertagComponent(XalGamertagComponent_Modern);\n    if (FAILED(gamertagComponentResult.Hresult()))\n    {\n        LOGS_ERROR << \"Failed to get Gamertag Component\" << XalGamertagComponent_Modern << \" with HRESULT: \" << hr;\n        return hr;\n    }\n\n    m_gamertags[XalGamertagComponent_Modern] = gamertagComponentResult.ExtractPayload();\n\n    gamertagComponentResult = GetGamertagComponent(XalGamertagComponent_ModernSuffix);\n    if (FAILED(gamertagComponentResult.Hresult()))\n    {\n        LOGS_ERROR << \"Failed to get Gamertag Component\" << XalGamertagComponent_ModernSuffix << \" with HRESULT: \" << hr;\n        return hr;\n    }\n\n    m_gamertags[XalGamertagComponent_ModernSuffix] = gamertagComponentResult.ExtractPayload();\n\n    gamertagComponentResult = GetGamertagComponent(XalGamertagComponent_UniqueModern);\n    if (FAILED(gamertagComponentResult.Hresult()))\n    {\n        LOGS_ERROR << \"Failed to get Gamertag Component\" << XalGamertagComponent_UniqueModern << \" with HRESULT: \" << hr;\n        return hr;\n    }\n\n    m_gamertags[XalGamertagComponent_UniqueModern] = gamertagComponentResult.ExtractPayload();\n\n    return S_OK;\n}\n\nResult<User> User::Copy() const noexcept\n{\n    if (XblShouldFaultInject(INJECTION_FEATURE_USER))\n    {\n        LOGS_ERROR << \"FAULT INJECTION: User::Copy ID:\" << XblGetFaultCounter();\n        return Result<User>{ User(nullptr), E_FAIL };\n    }\n\n    XalUserHandle copiedHandle;\n    auto hr = XalUserDuplicateHandle(this->m_handle, &copiedHandle);\n    if (FAILED(hr))\n    {\n        LOGS_ERROR << \"Copying user failed: User failed to duplicate.\";\n        return Result<User>{ User(nullptr), hr};\n    }\n    else\n    {\n        User copiedUser{ copiedHandle };\n        hr = copiedUser.InitializeUser();\n        return Result<User>{std::move(copiedUser), hr};\n    }\n}\n\nuint64_t User::Xuid() const noexcept\n{\n    return m_xuid;\n}\n\nuint64_t User::LocalId() const noexcept\n{\n    XalUserLocalId localId{ 0 };\n    if (m_handle != nullptr && !XblShouldFaultInject(INJECTION_FEATURE_USER))\n    {\n        auto hr = XalUserGetLocalId(m_handle, &localId);\n        if (SUCCEEDED(hr))\n        {\n            m_localId = localId;\n        }\n    }\n\n    return m_localId.value;\n}\n\nxsapi_internal_string User::Gamertag() const noexcept\n{\n    auto result = GetGamertagComponent(XalGamertagComponent_Classic);\n    if (Failed(result))\n    {\n        return m_gamertags[XalGamertagComponent_Classic];\n    }\n    else\n    {\n        return result.ExtractPayload();\n    }\n}\n\nxsapi_internal_string User::ModernGamertag() const noexcept\n{\n    auto result = GetGamertagComponent(XalGamertagComponent_Modern);\n    if (Failed(result))\n    {\n        return m_gamertags[XalGamertagComponent_Modern];\n    }\n    else\n    {\n        return result.ExtractPayload();\n    }\n}\n\nxsapi_internal_string User::ModernGamertagSuffix() const noexcept\n{\n    auto result = GetGamertagComponent(XalGamertagComponent_ModernSuffix);\n    if (Failed(result))\n    {\n        return m_gamertags[XalGamertagComponent_ModernSuffix];\n    }\n    else\n    {\n        return result.ExtractPayload();\n    }\n}\n\nxsapi_internal_string User::UniqueModernGamertag() const noexcept\n{\n    auto result = GetGamertagComponent(XalGamertagComponent_UniqueModern);\n    if (Failed(result))\n    {\n        return m_gamertags[XalGamertagComponent_UniqueModern];\n    }\n    else\n    {\n        return result.ExtractPayload();\n    }\n}\n\nHRESULT User::GetTokenAndSignature(\n    const String& httpMethod,\n    const String& url,\n    const HttpHeaders& headers,\n    const uint8_t* requestBody,\n    size_t requestBodySize,\n    bool allUsers,\n    AsyncContext<Result<TokenAndSignature>>&& async\n) noexcept\n{\n    if (XblShouldFaultInject(INJECTION_FEATURE_USER))\n    {\n        LOGS_ERROR << \"FAULT INJECTION: User::GetTokenAndSignature ID:\" << XblGetFaultCounter();\n        return E_FAIL;\n    }\n\n    bool forceRefresh{ false };\n\n    auto state{ GlobalState::Get() };\n    if (state)\n    {\n        if (state->EraseUserExpiredToken(Xuid()) > 0)\n        {\n            forceRefresh = true;\n        }\n    }\n\n    XalUserGetTokenAndSignatureArgs tokenAndSigArgs{\n        httpMethod.data(),\n        url.data(),\n        static_cast<uint32_t>(headers.size()),\n        nullptr,\n        requestBodySize,\n        (requestBodySize == 0) ? nullptr : requestBody, // XUser requires nullptr body if body is 0 size\n        forceRefresh,\n        allUsers\n    };\n\n    Vector<XalHttpHeader> xalHttpHeaders{};\n    if (headers.size() > 0)\n    {\n        xalHttpHeaders.reserve(tokenAndSigArgs.headerCount);\n        for (const auto& header : headers)\n        {\n            xalHttpHeaders.push_back(XalHttpHeader{ header.first.data(), header.second.data() });\n        }\n\n        tokenAndSigArgs.headers = xalHttpHeaders.data();\n    }\n\n    auto asyncBlock{ Make<XAsyncBlock>() };\n\n    asyncBlock->queue = async.Queue().GetHandle();\n    asyncBlock->context = Make<AsyncContext<Result<TokenAndSignature>>>(std::move(async));\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        auto async{ static_cast<AsyncContext<Result<TokenAndSignature>>*>(asyncBlock->context) };\n\n        size_t bufferSize{ 0 };\n        HRESULT hr = XalUserGetTokenAndSignatureSilentlyResultSize(asyncBlock, &bufferSize);\n        TokenAndSignature payload;\n\n        if (SUCCEEDED(hr))\n        {\n            auto buffer{ MakeArray<uint8_t>(bufferSize) };\n            XalUserGetTokenAndSignatureData* xalTokenSignatureData{ nullptr };\n\n            hr = XalUserGetTokenAndSignatureSilentlyResult(asyncBlock, bufferSize, buffer, &xalTokenSignatureData, nullptr);\n            if (SUCCEEDED(hr))\n            {\n                payload.token = String{ xalTokenSignatureData->token, xalTokenSignatureData->tokenSize };\n                payload.signature = String{ xalTokenSignatureData->signature, xalTokenSignatureData->signatureSize };\n            }\n\n            DeleteArray(buffer, bufferSize);\n        }\n        else if (hr == E_XAL_NOTOKENREQUIRED)\n        {\n            // Consider this a success\n            hr = S_OK;\n        }\n\n        async->Complete(Result<TokenAndSignature>{ payload, hr });\n\n        Delete(async);\n        Delete(asyncBlock);\n    };\n\n    HRESULT hr = XalUserGetTokenAndSignatureSilentlyAsync(\n        m_handle,\n        &tokenAndSigArgs,\n        asyncBlock);\n    if (FAILED(hr))\n    {\n        auto asyncPtr{ static_cast<AsyncContext<Result<TokenAndSignature>>*>(asyncBlock->context) };\n        Delete(asyncPtr);\n        Delete(asyncBlock);\n    }\n    return hr;\n}\n\nXalUserHandle User::Handle() const noexcept\n{\n    return m_handle;\n}\n\nvoid User::SetTokenExpired(uint64_t xuid) noexcept\n{\n    auto state{ GlobalState::Get() };\n    if (state)\n    {\n        state->InsertUserExpiredToken(xuid);\n    }\n\n}\n\nResult<uint64_t> User::RegisterChangeEventHandler(\n    UserChangeEventHandler handler\n) noexcept\n{\n    XalRegistrationToken token{};\n    auto context{ MakeShared<UserChangeEventHandler>(std::move(handler)) };\n\n    auto hr = E_FAIL;\n    if (!XblShouldFaultInject(INJECTION_FEATURE_USER))\n    {\n        hr = XalUserRegisterChangeEventHandler(\n            TaskQueue().GetHandle(),\n            context.get(),\n            [](void* context, UserLocalId userId, UserChangeType change)\n            {\n                auto handler{ static_cast<UserChangeEventHandler*>(context) };\n                (*handler)(std::move(userId), std::move(static_cast<UserChangeType>(change)));\n            },\n            &token\n        ); \n    }\n    else\n    {\n        LOGS_ERROR << \"FAULT INJECTION: User::RegisterChangeEventHandler ID:\" << XblGetFaultCounter();\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        auto state{ GlobalState::Get() };\n        if (state)\n        {\n            state->SetUserChangeHandler(token.token, context);\n        }\n    }\n    return Result<uint64_t>{token.token, hr };\n}\n\nvoid User::UnregisterChangeEventHandle(\n    uint64_t token\n) noexcept\n{\n    XalUserUnregisterChangeEventHandler(XalRegistrationToken{ token });\n    auto state{ GlobalState::Get() };\n    if (state)\n    {\n        state->EraseUserChangeHandler(token);\n    }\n}\n\nResult<String> User::GetGamertagComponent(\n    XalGamertagComponent component\n) const noexcept\n{\n    if (m_handle != nullptr)\n    {\n        size_t size = XalUserGetGamertagSize(m_handle, component);\n\n        Vector<char> gamertagComponent(size, char{});\n        auto hr = XalUserGetGamertag(m_handle, component, size, &gamertagComponent[0], nullptr);\n        if (SUCCEEDED(hr))\n        {\n            m_gamertags[component] = gamertagComponent.data();\n        }\n        else \n        {\n            LOGS_ERROR << \"Getting Gamertag failed with HR: \"<< hr ;\n        }\n\n        return Result<String>{m_gamertags[component], hr };\n    }\n\n    return  E_UNEXPECTED;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/user.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nstruct XblHttpCall;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nusing HttpHeaders = Map<String, String>;\n\nstruct TokenAndSignature\n{\n    String token;\n    String signature;\n};\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\ntypedef XUserLocalId UserLocalId;\ntypedef XUserChangeEvent UserChangeType;\n#else\ntypedef XalUserLocalId UserLocalId;\ntypedef XalUserChangeType UserChangeType;\n#endif\n\nusing UserChangeEventHandler = Function<void(UserLocalId /*localId*/, UserChangeType /*changeType*/)>;\n\nclass User;\n\ntemplate<>\nclass Result<User>;\n\n// RAII wrapper around XalUser\nclass User\n{\npublic:\n    User(const User& other) = delete;\n    User(User&& other) noexcept;\n    User& operator=(User&& other) noexcept;\n    ~User() noexcept;\n\n    static Result<User> WrapHandle(XblUserHandle userHandle) noexcept;\n    Result<User> Copy() const noexcept;\n\n    uint64_t Xuid() const noexcept;\n    uint64_t LocalId() const noexcept;\n    String Gamertag() const noexcept;\n    String ModernGamertag() const noexcept;\n    String ModernGamertagSuffix() const noexcept;\n    String UniqueModernGamertag() const noexcept;\n\n    HRESULT GetTokenAndSignature(\n        const String& httpMethod,\n        const String& url,\n        const HttpHeaders& headers,\n        const uint8_t* requestBody,\n        size_t requestBodySize,\n        bool allUsers,\n        AsyncContext<Result<TokenAndSignature>>&& async\n    ) noexcept;\n\n    XalUserHandle Handle() const noexcept;\n\n    static void SetTokenExpired(uint64_t xuid) noexcept;\n\n    static Result<uint64_t> RegisterChangeEventHandler(\n        UserChangeEventHandler handler\n    ) noexcept;\n\n    static void UnregisterChangeEventHandle(\n        uint64_t token\n    ) noexcept;\n\nprivate:\n    User() noexcept = default;\n    User(XblUserHandle userHandle) noexcept;\n\n    HRESULT InitializeUser() noexcept;\n    Result<String> GetGamertagComponent(XalGamertagComponent component) const noexcept;\t\n    XblUserHandle m_handle{ nullptr };\n    mutable uint64_t m_xuid;\n    mutable XalUserLocalId m_localId;\n    mutable Map<XalGamertagComponent, String> m_gamertags;\n\n    friend class Result<User>;\n};\n\ntemplate<>\nclass Result<User>\n{\npublic:\n    Result(User&& user) : m_payload{ std::move(user) } {}\n    Result(User&& user, HRESULT error) : m_result{ error }, m_payload{ std::move(user) } {}\n    Result(Result&& other) = default;\n    Result(const Result& other) = delete;\n\n    HRESULT Hresult() const noexcept\n    {\n        return m_result;\n    }\n\n    const User& Payload() const noexcept\n    {\n        return m_payload;\n    }\n\n    User&& ExtractPayload() noexcept\n    {\n        return std::move(m_payload);\n    }\n\nprivate:\n    HRESULT m_result;\n    User m_payload;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/utils_locales.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include <mutex>\n#include \"xsapi_utils.h\"\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"a/java_interop.h\"\n#include \"a/jni_utils.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\nstd::map<xsapi_internal_string, xsapi_internal_string> serviceLocales =\n{ \n    { \"es_AR\",    \"es-AR\" },\n    { \"AR\",         \"es-AR\" },\n    { \"en_AU\",     \"en-AU\" },\n    { \"AU\",         \"en-AU\" },\n    { \"de_AT\",     \"de-AT\" },\n    { \"AT\",         \"de-AT\" },\n    { \"fr_BE\",     \"fr-BE\" },\n    { \"nl_BE\",     \"nl-BE\" },\n    { \"BE\",         \"fr-BE\" },\n    { \"pt_BR\",     \"pt-BR\" },\n    { \"BR\",         \"pt-BR\" },\n    { \"en_CA\",     \"en-CA\" },\n    { \"fr_CA\",     \"fr-CA\" },\n    { \"CA\",         \"en-CA\" },\n    { \"en_CZ\",     \"en-CZ\" },\n    { \"CZ\",         \"en-CZ\" },\n    { \"da_DK\",     \"da-DK\" },\n    { \"DK\",         \"da-DK\" },\n    { \"fi_FI\",     \"fi-FI\" },\n    { \"FI\",         \"fi-FI\" },\n    { \"fr_FR\",     \"fr-FR\" },\n    { \"FR\",         \"fr-FR\" },\n    { \"de_DE\",    \"de-DE\" },\n    { \"DE\",         \"de-DE\" },\n    { \"en_GR\",     \"en-GR\" },\n    { \"GR\",         \"en-GR\" },\n    { \"en_HK\",     \"en-HK\" },\n    { \"zh_HK\",     \"zh-HK\" },\n    { \"HK\",         \"en-HK\" },\n    { \"en_HU\",     \"en-HU\" },\n    { \"HU\",         \"en-HU\" },\n    { \"en_IN\",     \"en-IN\" },\n    { \"IN\",         \"en-IN\" },\n    { \"en_GB\",     \"en-GB\" },\n    { \"GB\",         \"en-GB\" },\n    { \"en_IL\",     \"en-IL\" },\n    { \"IL\",         \"en-IL\" },\n    { \"it_IT\",     \"it-IT\" },\n    { \"IT\",         \"it-IT\" },\n    { \"ja_JP\",     \"ja-JP\" },\n    { \"JP\",         \"ja-JP\" },\n    { \"zh_CN\",     \"zh-CN\" },\n    { \"CN\",         \"zh-CN\" },\n    { \"es_MX\",     \"es-MX\" },\n    { \"MX\",         \"es-MX\" },\n    { \"es_CL\",     \"es-CL\" },\n    { \"CL\",         \"es-CL\" },\n    { \"es_CO\",     \"es-CO\" },\n    { \"CO\",         \"es-CO\" },\n    { \"nl_NL\",     \"nl-NL\" },\n    { \"NL\",         \"nl-NL\" },\n    { \"en_NZ\",     \"en-NZ\" },\n    { \"NZ\",         \"en-NZ\" },\n    { \"nb_NO\",     \"nb-NO\" },\n    { \"NO\",         \"nb-NO\" },\n    { \"pl_PL\",     \"pl-PL\" },\n    { \"PL\",         \"pl-PL\" },\n    { \"pt_PT\",     \"pt-PT\" },\n    { \"PT\",         \"pt-PT\" },\n    { \"ru_RU\",    \"ru-RU\" },\n    { \"RU\",        \"ru-RU\" },\n    { \"en_SA\",     \"en-SA\" },\n    { \"SA\",         \"en-SA\" },\n    { \"en_SG\",     \"en-SG\" },\n    { \"zh_SG\",     \"zh-SG\" },\n    { \"SG\",         \"en-SG\" },\n    { \"en_SK\",     \"en-SK\" },\n    { \"SK\",         \"en-SK\" },\n    { \"en_ZA\",     \"en-ZA\" },\n    { \"ZA\",         \"en-ZA\" },\n    { \"ko_KR\",     \"ko-KR\" },\n    { \"KR\",         \"ko-KR\" },\n    { \"es_ES\",     \"es-ES\" },\n    { \"es\",         \"es-ES\" },\n    { \"de_CH\",     \"de-CH\" },\n    { \"fr_CH\",     \"fr-CH\" },\n    { \"CH\",         \"fr-CH\" },\n    { \"zh_TW\",     \"zh-TW\" },\n    { \"TW\",         \"zh-TW\" },\n    { \"en_AE\",     \"en-AE\" },\n    { \"AE\",         \"en-AE\" },\n    { \"en_US\",     \"en-US\" },\n    { \"US\",         \"en-US\" },\n    { \"sv_SE\",     \"sv-SE\" },\n    { \"SE\",         \"sv-SE\" },\n    { \"tr_Tr\",     \"tr-TR\" },\n    { \"Tr\",         \"tr-TR\" },\n    { \"en_IE\",   \"en-IE\" },\n    { \"IE\",      \"en-IE\" },\n    { \"es_US\",      \"es-US\" }\n};\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_GDK\n// Locale api for desktop and xbox\nxsapi_internal_vector<xsapi_internal_string> utils::get_locale_list()\n{\n    xsapi_internal_vector<xsapi_internal_string> localeList;\n\n    char_t localeName[LOCALE_NAME_MAX_LENGTH] = { 0 };\n    auto localeLen = GetUserDefaultLocaleName(localeName, ARRAYSIZE(localeName));\n\n    if (localeLen > 0)\n    {\n        localeList.push_back(utils::internal_string_from_char_t(localeName));\n    }\n    else\n    {\n        localeList.push_back(\"en-US\");\n    }\n\n    return localeList;\n}\n\n#elif HC_PLATFORM == HC_PLATFORM_UWP\n\nxsapi_internal_vector<xsapi_internal_string> utils::get_locale_list()\n{\n    xsapi_internal_vector<xsapi_internal_string> localeList;\n\n    try\n    {\n        auto resourceContext = Windows::ApplicationModel::Resources::Core::ResourceContext::GetForCurrentView();\n\n        auto languages = resourceContext->Languages;\n        for (auto language : languages)\n        {\n            localeList.push_back(utils::internal_string_from_utf16(language->Data()));\n        }\n    }\n    catch (...)\n    {\n        LOG_ERROR(\"Failed to get system locale, fall back to en-US\");\n        localeList.push_back(\"en-US\");\n    }\n\n    return localeList;\n}\n\n#elif HC_PLATFORM == HC_PLATFORM_ANDROID\n\nxsapi_internal_vector<xsapi_internal_string> utils::get_locale_list()\n{\n    auto javaInterop = java_interop::get_java_interop_singleton();\n    xsapi_internal_vector<xsapi_internal_string> localeList;\n    rwlock_guard guard(javaInterop->java_interop_singletonLock, false);\n    auto javaVM = javaInterop->get_java_vm();\n    if (javaVM == nullptr)\n    {\n        LOG_ERROR(\"java interop not initialized properly\");\n        return localeList;\n    }\n    auto marketActivityClass = javaInterop->get_market_activity_class();\n    if (javaVM != nullptr && marketActivityClass != nullptr)\n    {\n        JNIEnv* jniEnv;\n        JNI_ATTACH_THREAD(javaVM, jniEnv);\n        jmethodID getLocaleMethod = jniEnv->GetStaticMethodID(marketActivityClass, \"getLocale\", \"()Ljava/lang/String;\");\n        if (getLocaleMethod != nullptr)\n        {\n            jstring localeJString = (jstring)jniEnv->CallStaticObjectMethod(marketActivityClass, getLocaleMethod);\n            xsapi_internal_string localeString = jniEnv->GetStringUTFChars(localeJString, nullptr);\n            auto findResult = serviceLocales.find(localeString);\n            if (findResult != serviceLocales.end())\n            {\n                localeList.push_back(findResult->second);\n            }\n            else\n            {\n                localeList.push_back(_T(\"en-US\"));\n            }\n            return localeList;\n        }\n    }\n\n    localeList.push_back(_T(\"en-US\"));\n    return localeList;\n}\n\n#endif\n\nString utils::generate_locales(_In_z_ const xsapi_internal_string& overrideLocale)\n{\n    xsapi_internal_vector<xsapi_internal_string> localeList;\n    \n    // If an overrideLocale is provided, it should be added to the front of the localeList\n    auto osLocaleList = get_locale_list();\n    if (!overrideLocale.empty())\n    {\n        localeList.push_back(overrideLocale);\n        localeList.insert(localeList.end(), osLocaleList.begin(), osLocaleList.end());\n    }\n    else \n    {\n        localeList = osLocaleList;\n    }\n\n    xsapi_internal_vector<xsapi_internal_string> localeFallbackList;\n\n\n    for (auto& locale : localeList)\n    {\n        // Build up fallback list, for instance, if the lang is \"sd-Arab-PK\"\n        // We add \"sd-Arab\" and \"sd\" as well \n        // So that if an user's language preference is \"fr-ml\", \"zh-hans\", \"en-us\"\n        // fallback chain is going to be:\n        // fr-ml -> fr -> zh-hans -> zh -> en-us -> en\n        localeFallbackList.push_back(locale);\n        size_t nPos = locale.rfind(\"-\");\n        while (nPos != xsapi_internal_string::npos)\n        {\n            localeFallbackList.push_back(locale.substr(0, nPos));\n            nPos = locale.rfind(\"-\", nPos - 1);\n        }\n    }\n\n    String locales{};\n    for (auto& locale : localeFallbackList)\n    {\n        locales += locale;\n        locales += ',';\n    }\n    // erase the last ','\n    locales.pop_back();\n\n    return locales;\n}\n\nString utils::get_locales()\n{\n    auto state = GlobalState::Get();\n    if (state)\n    {\n        return state->Locales().data();\n    }\n    return String{ \"en-US\" };\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/Shared/web_socket.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"web_socket.h\"\n#include \"xsapi_utils.h\"\n#ifdef XSAPI_UNIT_TESTS\n#include \"mock_web_socket.h\"\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nusing namespace xbox::services::system;\n\n// Context passed to LHC XAsync APIs. Ensures WebSocket is kept alive until those calls complete\nstruct XAsyncContext\n{\n\tXAsyncContext(std::shared_ptr<Websocket> _websocket) : websocket{ std::move(_websocket) }\n\t{\n\t}\n\tstd::shared_ptr<Websocket> websocket;\n};\n\nWebsocket::Websocket(\n    _In_ User&& user,\n    _In_ TaskQueue queue\n) noexcept :\n    m_user{ std::move(user) },\n    m_queue{ std::move(queue) }\n{\n    HCWebSocketCreate(&m_hcWebsocket, ReceiveHandler, BinaryReceiveHandler, CloseHandler, this);\n}\n\nWebsocket::~Websocket()\n{\n    if (m_hcWebsocket)\n    {\n        HCWebSocketCloseHandle(m_hcWebsocket);\n    }\n}\n\nHRESULT Websocket::Connect(\n    _In_ const String& uri,\n    _In_ const String& subProtocol\n) noexcept\n{\n    auto state = GlobalState::Get();\n    if (!state)\n    {\n        return E_XBL_NOT_INITIALIZED;\n    }\n\n    m_user.GetTokenAndSignature(\"GET\", uri, HttpHeaders{}, nullptr, 0, false, AsyncContext<Result<TokenAndSignature>>{\n        m_queue.GetHandle(),\n        [\n            uri = String{ uri },\n            subProtocol = String{ subProtocol },\n            locales = state->Locales(),\n            weakThis{ std::weak_ptr<Websocket>{ shared_from_this() } }\n        ]\n        (Result<TokenAndSignature> authResult)\n    {\n        auto sharedThis{ weakThis.lock() };\n        if (!sharedThis)\n        {\n            LOGS_DEBUG << \"Websocket object destroyed before auth call completed\";\n            return;\n        }\n        else if (Failed(authResult))\n        {\n            sharedThis->m_connectCompleteHandler(WebsocketResult{ authResult.Hresult(), 0 });\n            return;\n        }\n        else\n        {\n            const auto& authPayload = authResult.Payload();\n\n            HCWebSocketSetHeader(sharedThis->m_hcWebsocket, \"Authorization\", authPayload.token.data());\n            HCWebSocketSetHeader(sharedThis->m_hcWebsocket, \"Signature\", authPayload.signature.data());\n            HCWebSocketSetHeader(sharedThis->m_hcWebsocket, \"Accept-Language\", locales.data());\n\n            xsapi_internal_string userAgent = DEFAULT_USER_AGENT;\n            HCWebSocketSetHeader(sharedThis->m_hcWebsocket, \"User-Agent\", userAgent.data());\n\n\t\t\tauto asyncContext = MakeUnique<XAsyncContext>(sharedThis);\n            auto asyncBlock = MakeUnique<XAsyncBlock>();\n            asyncBlock->queue = sharedThis->m_queue.GetHandle();\n\t\t\tasyncBlock->context = asyncContext.get();\n            asyncBlock->callback = [](_In_ XAsyncBlock* asyncBlock)\n            {\n                UniquePtr<XAsyncBlock> asyncUnique{ asyncBlock };\n\t\t\t\tUniquePtr<XAsyncContext> asyncContext{ static_cast<XAsyncContext*>(asyncBlock->context) };\n\n                WebSocketCompletionResult hcResult{};\n                HRESULT hr = HCGetWebSocketConnectResult(asyncBlock, &hcResult);\n\n                WebsocketResult result{ hr };\n                if (SUCCEEDED(hr))\n                {\n                    result.hr = hcResult.errorCode;\n                    result.platformErrorCode = hcResult.platformErrorCode;\n                }\n                asyncContext->websocket->m_connectCompleteHandler(result);\n            };\n\n            auto hr = HCWebSocketConnectAsync(uri.data(), subProtocol.data(), sharedThis->m_hcWebsocket, asyncBlock.get());\n            if (SUCCEEDED(hr))\n            {\n                asyncBlock.release();\n\t\t\t\tasyncContext.release();\n            }\n            else\n            {\n                sharedThis->m_connectCompleteHandler(WebsocketResult{ hr, 0 });\n            }\n        }\n    }\n    });\n\n    return S_OK;\n}\n\nHRESULT Websocket::Send(_In_ const char* message) noexcept\n{\n\tauto asyncContext = MakeUnique<XAsyncContext>(shared_from_this());\n    auto asyncBlock = MakeUnique<XAsyncBlock>();\n    asyncBlock->queue = m_queue.GetHandle();\n    asyncBlock->context = asyncContext.get();\n    asyncBlock->callback = [](_In_ XAsyncBlock* asyncBlock)\n    {\n        UniquePtr<XAsyncBlock> asyncUnique{ asyncBlock };\n\t\tUniquePtr<XAsyncContext> asyncContext{ static_cast<XAsyncContext*>(asyncBlock->context) };\n\n        WebSocketCompletionResult hcResult{};\n        HRESULT hr = HCGetWebSocketSendMessageResult(asyncBlock, &hcResult);\n\n        WebsocketResult result{ hr };\n        if (SUCCEEDED(hr))\n        {\n            result.hr = hcResult.errorCode;\n            result.platformErrorCode = hcResult.platformErrorCode;\n        }\n        asyncContext->websocket->m_sendCompleteHandler(result);\n    };\n\n    HRESULT hr = HCWebSocketSendMessageAsync(m_hcWebsocket, message, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        asyncBlock.release();\n\t\tasyncContext.release();\n    }\n    return hr;\n}\n\nHRESULT Websocket::Disconnect() noexcept\n{\n    return HCWebSocketDisconnect(m_hcWebsocket);\n}\n\nvoid Websocket::OnMessageReceived(String&& m) const noexcept\n{\n    // LHC doesn't guarantee that it will invoke message handlers on a specific thread. Because we want to ensure our\n    // callbacks are made on the proper thread, submit the message handler to the provided TaskQueue.\n\n    m_queue.RunWork([clientHandler = m_receiveHandler, message = std::move(m) ]() mutable\n    {\n        clientHandler(std::move(message));\n    });\n}\n\nvoid Websocket::ReceiveHandler(\n    _In_ HCWebsocketHandle /*websocket*/,\n    _In_z_ const char* incomingBodyString,\n    _In_ void* functionContext\n)\n{\n    auto thisPtr{ static_cast<Websocket*>(functionContext) };\n    thisPtr->OnMessageReceived(incomingBodyString);\n}\n\nvoid Websocket::BinaryReceiveHandler(\n    _In_ HCWebsocketHandle /*websocket*/,\n    _In_reads_bytes_(payloadSize) const uint8_t* payloadBytes,\n    _In_ uint32_t payloadSize,\n    _In_ void* functionContext\n)\n{\n    auto thisPtr{ static_cast<Websocket*>(functionContext) };\n    thisPtr->OnMessageReceived(xsapi_internal_string{ reinterpret_cast<const char*>(payloadBytes), payloadSize });\n}\n\nvoid Websocket::CloseHandler(\n    _In_ HCWebsocketHandle /*websocket*/,\n    _In_ HCWebSocketCloseStatus closeStatus,\n    _In_ void* functionContext\n)\n{\n    auto thisPtr{ static_cast<Websocket*>(functionContext) };\n    thisPtr->m_disconnectHandler(closeStatus);\n}\n\nstd::shared_ptr<IWebsocket> IWebsocket::Make(\n    User&& user,\n    TaskQueue queue\n) noexcept\n{\n\n#ifdef XSAPI_UNIT_TESTS\n    auto webSocket = MakeShared<MockWebsocket>(std::move(user), std::move(queue));\n#else\n    auto webSocket = MakeShared<Websocket>(std::move(user), std::move(queue));\n#endif\n\n    return webSocket;\n}\n\nvoid IWebsocket::SetConnectCompleteHandler(_In_ Callback<WebsocketResult> connectCompleteHandler) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    m_connectCompleteHandler = std::move(connectCompleteHandler);\n}\n\nvoid IWebsocket::SetDisconnectHandler(_In_ Callback<WebSocketCloseStatus> disconnectHandler) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    m_disconnectHandler = std::move(disconnectHandler);\n}\n\nvoid IWebsocket::SetSendCompleteHandler(_In_ Callback<WebsocketResult> sendCompleteHandler) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    m_sendCompleteHandler = std::move(sendCompleteHandler);\n}\n\nvoid IWebsocket::SetReceiveHandler(_In_ Callback<xsapi_internal_string> receiveHandler) noexcept\n{\n    std::lock_guard<std::recursive_mutex> lock{ m_mutex };\n    m_receiveHandler = std::move(receiveHandler);\n\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/web_socket.h",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\ntypedef HCWebSocketCloseStatus WebSocketCloseStatus;\n\nstruct WebsocketResult\n{\n    HRESULT hr;\n    uint32_t platformErrorCode;\n};\n\n// Base class for Websocket and MockWebsocket\nclass IWebsocket\n{\npublic:\n    static std::shared_ptr<IWebsocket> Make(\n        User&& user,\n        TaskQueue queue\n    ) noexcept;\n\n    virtual ~IWebsocket() = default;\n\n    virtual void SetConnectCompleteHandler(_In_ Callback<WebsocketResult> connectCompleteHandler) noexcept;\n\n    virtual void SetDisconnectHandler(_In_ Callback<WebSocketCloseStatus> disconnectHandler) noexcept;\n\n    virtual void SetSendCompleteHandler(_In_ Callback<WebsocketResult> sendCompleteHandler) noexcept;\n\n    virtual void SetReceiveHandler(_In_ Callback<String> receiveHandler) noexcept;\n\n    virtual HRESULT Connect(\n        _In_ const String& uri,\n        _In_ const String& subProtocol\n    ) noexcept = 0;\n\n    virtual HRESULT Send(_In_ const char* message) noexcept = 0;\n\n    virtual HRESULT Disconnect() noexcept = 0;\n\nprotected:\n    std::recursive_mutex m_mutex;\n    Callback<WebsocketResult> m_connectCompleteHandler;\n    Callback<WebSocketCloseStatus> m_disconnectHandler;\n    Callback<String> m_receiveHandler;\n    Callback<WebsocketResult> m_sendCompleteHandler;\n};\n\nclass Websocket : public IWebsocket, public std::enable_shared_from_this<Websocket>\n{\npublic:\n    Websocket(\n        _In_ User&& user,\n        _In_ TaskQueue queue\n    ) noexcept;\n\n    ~Websocket();\n\n    HRESULT Connect(\n        _In_ const String& uri,\n        _In_ const String& subProtocol\n    ) noexcept override;\n\n    HRESULT Send(_In_ const char* message) noexcept override;\n\n    HRESULT Disconnect() noexcept override;\n\nprivate:\n    void OnMessageReceived(String&& message) const noexcept;\n\n    static void CALLBACK ReceiveHandler(\n        _In_ HCWebsocketHandle websocket,\n        _In_z_ const char* incomingBodyString,\n        _In_ void* functionContext\n    );\n\n    static void CALLBACK BinaryReceiveHandler(\n        _In_ HCWebsocketHandle websocket,\n        _In_reads_bytes_(payloadSize) const uint8_t* payloadBytes,\n        _In_ uint32_t payloadSize,\n        _In_ void* functionContext\n    );\n\n    static void CALLBACK CloseHandler(\n        _In_ HCWebsocketHandle websocket,\n        _In_ HCWebSocketCloseStatus closeStatus,\n        _In_ void* functionContext\n    );\n\n    HCWebsocketHandle m_hcWebsocket{ nullptr };\n    User m_user;\n    TaskQueue m_queue;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/xbox_live_app_config.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"shared_macros.h\"\n#include \"xbox_live_app_config_internal.h\"\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nstd::shared_ptr<AppConfig> AppConfig::Instance()\n{\n    auto state = GlobalState::Get();\n    if (state)\n    {\n        return state->AppConfig();\n    }\n    return nullptr;\n}\n\n#if HC_PLATFORM == HC_PLATFORM_XDK\nHRESULT AppConfig::Initialize()\n{\n    m_sandbox = utils::internal_string_from_utf16(Windows::Xbox::Services::XboxLiveConfiguration::SandboxId->Data());\n    m_titleId = std::stoi(Windows::Xbox::Services::XboxLiveConfiguration::TitleId->Data());\n    m_scid = utils::internal_string_from_utf16(Windows::Xbox::Services::XboxLiveConfiguration::PrimaryServiceConfigId->Data());\n\n    return S_OK;\n}\n#else\n\nHRESULT AppConfig::Initialize(\n    xsapi_internal_string scid\n)\n{\n    HRESULT hr = XalGetTitleId(&m_titleId);\n\n    size_t sandboxSize = XalGetSandboxSize();\n    char* sandbox = MakeArray<char>(sandboxSize);\n\n    hr = XalGetSandbox(sandboxSize, sandbox, nullptr);\n    if (SUCCEEDED(hr))\n    {\n        m_sandbox = sandbox;\n    }\n    DeleteArray(sandbox, sandboxSize);\n\n    m_scid = std::move(scid);\n\n    return hr;\n}\n#endif\n\nuint32_t AppConfig::TitleId()\n{\n    return m_titleId;\n}\n\nuint32_t AppConfig::OverrideTitleId() const\n{\n    if (m_overrideTitleId == 0)\n    {\n        return m_titleId;\n    }\n    return m_overrideTitleId;\n}\n\nvoid AppConfig::SetOverrideTitleId(uint32_t overrideTitleId)\n{\n    m_overrideTitleId = overrideTitleId;\n}\n\nconst xsapi_internal_string& AppConfig::Scid() const\n{\n    return m_scid;\n}\n\nconst xsapi_internal_string& AppConfig::OverrideScid() const\n{\n    if (m_overrideScid.empty())\n    {\n        return m_scid;\n    }\n    return m_overrideScid;\n}\n\nvoid AppConfig::SetOverrideScid(const xsapi_internal_string& overrideScid)\n{\n    m_overrideScid = overrideScid;\n}\n\nconst xsapi_internal_string& AppConfig::Sandbox() const\n{\n    return m_sandbox;\n}\n\n#if HC_PLATFORM == HC_PLATFORM_UWP\nvoid AppConfig::SetSandbox(const xsapi_internal_string& sandbox)\n{\n    m_sandbox = sandbox;\n}\n#endif\n\nconst xsapi_internal_string& AppConfig::EndpointId() const\n{\n    return m_endpointId;\n}\n\nvoid AppConfig::SetEndpointId(const xsapi_internal_string& endpointId)\n{\n    m_endpointId = endpointId;\n}\n\nvoid AppConfig::DisableAssertsForXboxLiveThrottlingInDevSandboxes()\n{\n    m_disableAssertsForXboxLiveThrottlingInDevSandboxes = true;\n}\n\nbool AppConfig::IsDisableAssertsForXboxLiveThrottlingInDevSandboxes() const\n{\n    return m_disableAssertsForXboxLiveThrottlingInDevSandboxes;\n}\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\nconst xsapi_internal_string& AppConfig::APNSEnvironment() const\n{\n    return m_apnsEnvironment;\n}\n\nvoid AppConfig::SetAPNSEnvironment(const xsapi_internal_string& apnsEnvironment)\n{\n    m_apnsEnvironment = apnsEnvironment;\n}\n#endif\n\n#if HC_PLATFORM_IS_EXTERNAL\nxsapi_internal_string const& AppConfig::AppId() const\n{\n    return m_telemetryAppId;\n}\n\nxsapi_internal_string const& AppConfig::AppVer() const\n{\n    return m_telemetryAppVer;\n}\n\nxsapi_internal_string const& AppConfig::OsName() const\n{\n    return m_telemetryOsName;\n}\n\nxsapi_internal_string const& AppConfig::OsLocale() const\n{\n    return m_telemetryOsLocale;\n}\n\nxsapi_internal_string const& AppConfig::OsVersion() const\n{\n    return m_telemetryOsVersion;\n}\n\nxsapi_internal_string const& AppConfig::DeviceClass() const\n{\n    return m_telemetryDeviceClass;\n}\n\nxsapi_internal_string const& AppConfig::DeviceId() const\n{\n    return m_telemetryDeviceId;\n}\n\nvoid AppConfig::SetAppId(xsapi_internal_string&& v)\n{\n    m_telemetryAppId = std::move(v);\n}\n\nvoid AppConfig::SetAppVer(xsapi_internal_string&& v)\n{\n    m_telemetryAppVer = std::move(v);\n}\n\nvoid AppConfig::SetOsName(xsapi_internal_string&& v)\n{\n    m_telemetryOsName = std::move(v);\n}\n\nvoid AppConfig::SetOsLocale(xsapi_internal_string&& v)\n{\n    m_telemetryOsLocale = std::move(v);\n}\n\nvoid AppConfig::SetOsVersion(xsapi_internal_string&& v)\n{\n    m_telemetryOsVersion = std::move(v);\n}\n\nvoid AppConfig::SetDeviceClass(xsapi_internal_string&& v)\n{\n    m_telemetryDeviceClass = std::move(v);\n}\n\nvoid AppConfig::SetDeviceId(xsapi_internal_string&& v)\n{\n    m_telemetryDeviceId = std::move(v);\n}\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/xbox_live_app_config_internal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include <set>\n\n#ifdef __OBJC__\n#import <UIKit/UIKit.h>\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass AppConfig : public std::enable_shared_from_this<AppConfig>\n{\npublic:\n    AppConfig() = default;\n\n    // TODO Remove. Unsafe method - returns null if GlobalState doesn't exist and is unchecked by callers\n    static std::shared_ptr<AppConfig> Instance();\n\n#if HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK\n    HRESULT Initialize();\n#else\n    HRESULT Initialize(xsapi_internal_string scid);\n#endif\n\n    uint32_t TitleId();\n    const xsapi_internal_string& Scid() const;\n    const xsapi_internal_string& Sandbox() const;\n\n    const xsapi_internal_string& EndpointId() const;\n    void SetEndpointId(const xsapi_internal_string& endpointId);\n\n    uint32_t OverrideTitleId() const;\n    void SetOverrideTitleId(uint32_t overrideTitleId);\n    const xsapi_internal_string& OverrideScid() const;\n    void SetOverrideScid(const xsapi_internal_string& overrideScid);\n\n    void DisableAssertsForXboxLiveThrottlingInDevSandboxes();\n    bool IsDisableAssertsForXboxLiveThrottlingInDevSandboxes() const;\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n    const xsapi_internal_string& APNSEnvironment() const;\n    void SetAPNSEnvironment(const xsapi_internal_string& apnsEnvironment);\n#endif\n\n#if !HC_PLATFORM_IS_MICROSOFT && defined(__OBJC__)\n    /// Set the view controller that your app wants to launch any xbox live services ui like sign in, profile\n    /// card, etc from. This will set a weak pointer to this view controller. If at any point this view controller\n    /// is no longer the desired presenting view controller, then set this to nil. If the weak pointer that backs\n    /// this view controller ever is nil, then the fallback view controller for the app is the application's\n    /// key window's root view controller.\n    ///\n    /// @param viewController The view controller to present any xbox live services ui from. Can be nil.\n    ///\n    /// Usage for using a view controller as the presenting view controller only once:\n    ///\n    ///     xbox_live_app_config::set_launch_view_controller(viewController)\n    ///     user->signin().then...\n    ///     // Then when done with sign in or any ui\n    ///     xbox_live_app_config::set_launch_view_controller(nil)\n    ///\n    /// Usage for setting the view controller that will always be used:\n    ///\n    ///     xbox_live_app_config::set_launch_view_controller(viewController)\n    ///     // Some time later in your application\n    ///     title_callable_ui::show_profile_card_ui(xuid)\n    ///\n    _XSAPIIMP static void set_launch_view_controller(_In_ UIViewController *viewController);\n#endif\n\n#if HC_PLATFORM_IS_EXTERNAL\n    xsapi_internal_string const& AppId() const;\n    xsapi_internal_string const& AppVer() const;\n    xsapi_internal_string const& OsName() const;\n    xsapi_internal_string const& OsLocale() const;\n    xsapi_internal_string const& OsVersion() const;\n    xsapi_internal_string const& DeviceClass() const;\n    xsapi_internal_string const& DeviceId() const;\n\n    void SetAppId(xsapi_internal_string&& v);\n    void SetAppVer(xsapi_internal_string&& v);\n    void SetOsName(xsapi_internal_string&& v);\n    void SetOsLocale(xsapi_internal_string&& v);\n    void SetOsVersion(xsapi_internal_string&& v);\n    void SetDeviceClass(xsapi_internal_string&& v);\n    void SetDeviceId(xsapi_internal_string&& v);\n#endif\n\nprivate:\n    uint32_t m_titleId{ 0 };\n    uint32_t m_overrideTitleId{ 0 };\n    xsapi_internal_string m_sandbox;\n    xsapi_internal_string m_scid;\n    xsapi_internal_string m_overrideScid;\n    xsapi_internal_string m_endpointId;\n    bool m_disableAssertsForXboxLiveThrottlingInDevSandboxes{ false };\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n    xsapi_internal_string m_apnsEnvironment{ \"apnsProduction\" };\n    xsapi_internal_string m_registrationToken;\n#endif\n\n#if HC_PLATFORM_IS_EXTERNAL\n    xsapi_internal_string m_telemetryAppId;\n    xsapi_internal_string m_telemetryAppVer;\n    xsapi_internal_string m_telemetryOsName;\n    xsapi_internal_string m_telemetryOsLocale;\n    xsapi_internal_string m_telemetryOsVersion;\n    xsapi_internal_string m_telemetryDeviceClass;\n    xsapi_internal_string m_telemetryDeviceId;\n#endif\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/xsapi_json_utils.cpp",
    "content": "#include \"pch.h\"\n#include \"xsapi_json_utils.h\"\n#include \"uri_impl.h\"\n\nusing namespace xbox::services::legacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nHRESULT JsonUtils::ExtractJsonFieldAsString(\n    _In_ const JsonValue& json,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ xsapi_internal_string& outString,\n    _In_ bool required\n)\n{\n    if (json.IsObject())\n    {\n        if (json.HasMember(name.c_str()))\n        {\n            const JsonValue& jsonField = json[name.c_str()];\n            outString = SerializeJson(jsonField);\n            return S_OK;\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\n HRESULT JsonUtils::ExtractJsonStringVector(\n    _In_ const JsonValue& json,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ xsapi_internal_vector<xsapi_internal_string>& outVector,\n    _In_ bool required\n)\n{\n    if (json.IsObject())\n    {\n        if (json.HasMember(name.c_str()))\n        {\n            return ExtractJsonStringVector(\n                json[name.c_str()],\n                outVector\n            );\n        }\n        else if (!required)\n        {\n            outVector = xsapi_internal_vector<xsapi_internal_string>();\n            return S_OK;\n        }\n    }\n\n    outVector = xsapi_internal_vector<xsapi_internal_string>();\n    return WEB_E_INVALID_JSON_STRING;\n}\n\n HRESULT JsonUtils::ExtractJsonStringVector(\n     _In_ const JsonValue& json,\n     _Inout_ xsapi_internal_vector<xsapi_internal_string>& outVector\n )\n {\n     outVector = xsapi_internal_vector<xsapi_internal_string>();\n     if (!json.IsArray())\n     {\n         return WEB_E_INVALID_JSON_STRING;\n     }\n\n     for (const auto& string : json.GetArray())\n     {\n         if (!string.IsString())\n         {\n             return WEB_E_INVALID_JSON_STRING;\n         }\n         outVector.push_back(string.GetString());\n     }\n\n     return S_OK;\n}\n\nResult<xsapi_internal_string> JsonUtils::JsonStringExtractor(_In_ const JsonValue& json)\n{\n    if (!json.IsString())\n    {\n        return Result<xsapi_internal_string>(WEB_E_INVALID_JSON_STRING);\n    }\n    return Result<xsapi_internal_string>(json.GetString());\n}\n\nvoid JsonUtils::JsonStringSerializer(_In_ const xsapi_internal_string& value, _Out_ JsonValue& json, JsonDocument::AllocatorType& allocator)\n{\n    json.SetString(value.c_str(), allocator);\n}\n\nvoid JsonUtils::JsonXuidSerializer(_In_ uint64_t xuid, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    json.SetString(utils::uint64_to_internal_string(xuid).c_str(), allocator);\n}\n\nResult<int> JsonUtils::JsonIntExtractor(_In_ const JsonValue& json)\n{\n    if (!json.IsInt())\n    {\n        return Result<int>(0, WEB_E_INVALID_JSON_STRING);\n    }\n    return Result<int>(json.GetInt(), S_OK);\n}\n\nResult<uint64_t>\nJsonUtils::JsonXuidExtractor(_In_ const JsonValue& json)\n{\n    if (!json.IsString())\n    {\n        return Result<uint64_t>(WEB_E_INVALID_JSON_STRING);\n    }\n\n    return Result<uint64_t>(utils::internal_string_to_uint64(json.GetString()));\n}\n\nvoid JsonUtils::JsonUtf8Serializer(_In_ const char* value, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator)\n{\n    //TODO: Verify UTF8 format is maintained\n    json.SetString(value, allocator);\n}\n\nResult<const char*> JsonUtils::JsonUtf8Extractor(_In_ const JsonValue& json)\n{\n    if (!json.IsString())\n    {\n        return Result<const char*>(WEB_E_INVALID_JSON_STRING);\n    }\n    return Result<const char*>(Make(json.GetString()));\n}\n\nvoid JsonUtils::JsonIntSerializer(_In_ int32_t value, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType&)\n{\n    json.SetInt(value);\n}\n\nHRESULT JsonUtils::ExtractJsonXuid(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Out_ uint64_t& xuid,\n    _In_ bool required /*= false*/\n)\n{\n    xsapi_internal_string xuidString;\n    RETURN_HR_IF_FAILED(ExtractJsonString(jsonValue, name, xuidString, required));\n    xuid = utils::internal_string_to_uint64(xuidString);\n    return S_OK;\n}\n\nHRESULT JsonUtils::ExtractJsonString(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& stringName,\n    _Inout_ xsapi_internal_string& outString,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(stringName.c_str()))\n        {\n            const JsonValue& field = jsonValue[stringName.c_str()];\n            if (field.IsString())\n            {\n                outString = field.GetString();\n                return S_OK;\n            }\n            else if (field.IsNull())\n            {\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonStringToCharArray(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& stringName,\n    _Inout_updates_bytes_(size) char* charArray,\n    _In_ size_t size\n)\n{\n    xsapi_internal_string jsonStr;\n    RETURN_HR_IF_FAILED(ExtractJsonString(jsonValue, stringName, jsonStr));\n    if (jsonStr.size() < size)\n    {\n        utils::strcpy(charArray, size, jsonStr.data());\n    }\n    else\n    {\n        return E_INVALIDARG;\n    }\n    return S_OK;\n}\n\nJsonValue::ConstArray JsonUtils::ExtractJsonArray(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& arrayName,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject() && jsonValue.HasMember(arrayName.c_str()))\n    {\n\n        const JsonValue& field = jsonValue[arrayName.c_str()];\n        if ((!field.IsArray() && !required) || field.IsNull())\n        {\n            const JsonValue emptyArrayJson(rapidjson::kArrayType);\n            return emptyArrayJson.GetArray();\n        }\n        return field.GetArray();\n    }\n\n    const JsonValue emptyArrayJson(rapidjson::kArrayType);\n    return emptyArrayJson.GetArray();\n}\n\n HRESULT JsonUtils::ExtractJsonAsString(\n    _In_ const JsonValue& jsonValue,\n    _Inout_ xsapi_internal_string& outString\n)\n{\n    if (jsonValue.IsString())\n    {\n        outString = jsonValue.GetString();\n        return S_OK;\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonBool(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& stringName,\n    _Inout_ bool& outBool,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(stringName.c_str()))\n        {\n            const JsonValue& field = jsonValue[stringName.c_str()];\n            if (field.IsBool())\n            {\n                outBool = field.GetBool();\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonInt(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ int32_t& outInt,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n\n            if (field.IsInt())\n            {\n                outInt = field.GetInt();\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonInt(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ uint32_t& outInt,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n\n            if (field.IsUint())\n            {\n                outInt = field.GetUint();\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonInt(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ int64_t& outInt,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n\n            if (field.IsInt64())\n            {\n                outInt = field.GetInt64();\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonInt(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ uint64_t& outInt,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n\n            if (field.IsUint64())\n            {\n                outInt = field.GetUint64();\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonSizeT(\n    _In_ const JsonValue& jsonValue,\n    _In_ const String& name,\n    _Inout_ size_t& size,\n    _In_ bool required\n)\n{\n    uint64_t temp{};\n    RETURN_HR_IF_FAILED(ExtractJsonInt(jsonValue, name, temp, required));\n    size = static_cast<size_t>(temp);\n    return S_OK;\n}\n\nHRESULT JsonUtils::ExtractJsonStringToUInt64(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ uint64_t& outUInt64,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n            if (field.IsString())\n            {\n                outUInt64 = utils::internal_string_to_uint64(field.GetString());\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n    \n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonUInt64(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ uint64_t& outUInt64,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n            if (field.IsNumber())\n            {\n                outUInt64 = field.GetUint64();\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    } \n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\n HRESULT JsonUtils::ExtractJsonTime(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ xbox::services::datetime& outTime,\n    _In_ bool required\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n\n            if (field.IsString())\n            {\n                //convert to wstring for use with xbox::services::datetime\n                //xbox::services::datetime is still part of cpprestsdk\n                outTime = xbox::services::datetime::from_string(field.GetString(), xbox::services::datetime::date_format::ISO_8601);\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonTimeT(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ time_t& outTime,\n    _In_ bool required\n)\n{\n    xbox::services::datetime time;\n    RETURN_HR_IF_FAILED(ExtractJsonTime(jsonValue, name, time, required));\n    outTime = utils::time_t_from_datetime(time);\n    return S_OK;\n}\n\n HRESULT JsonUtils::ExtractJsonStringTimespanInSeconds(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ std::chrono::seconds& outTime,\n    _In_ bool required)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n            if (field.IsString())\n            {\n                char delimiter;\n                int hour = 0, min = 0, sec = 0;\n                xsapi_internal_stringstream ss(field.GetString());\n                ss >> hour >> delimiter >> min >> delimiter >> sec;\n\n                outTime = std::chrono::hours(hour) + std::chrono::minutes(min) + std::chrono::seconds(sec);\n                return S_OK;\n            }\n        }\n        else if (!required)\n        {\n            return S_OK;\n        }\n    }\n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\nHRESULT JsonUtils::ExtractJsonDouble(\n    _In_ const JsonValue& jsonValue,\n    _In_ const xsapi_internal_string& name,\n    _Inout_ double& outDouble,\n    _In_ bool required /* = false */\n)\n{\n    if (jsonValue.IsObject())\n    {\n        if (jsonValue.HasMember(name.c_str()))\n        {\n            const JsonValue& field = jsonValue[name.c_str()];\n            if (field.IsDouble())\n            {\n                outDouble = field.GetDouble();\n                return S_OK;\n            }\n\n        }\n        else if(!required)\n        {\n            return S_OK;\n        }\n    } \n\n    return WEB_E_INVALID_JSON_STRING;\n}\n\n\nvoid\nJsonUtils::SerializeUInt52ToJson(\n    _In_ uint64_t integer,\n    _Inout_ JsonValue& json\n)\n{\n    if ((integer & 0xFFF0000000000000) != 0)\n    {\n        //TODO: Throw exception here\n        return;\n    }\n\n    json.SetUint64(integer);\n}\n\nJsonValue JsonUtils::SerializeTime(\n    _In_ time_t time,\n    _In_ JsonDocument::AllocatorType& a\n) noexcept\n{\n    auto timestampString = DatetimeFromTimeT(time).to_string_internal(xbox::services::cppresturi::utility::datetime::ISO_8601);\n    return JsonValue{ timestampString.data(), a };\n}\n\nHRESULT JsonUtils::ValidateJson(\n    _In_ const char* jsonString\n)\n{\n    if (jsonString != nullptr)\n    {\n        JsonDocument d;\n        d.Parse(jsonString);\n        if (d.HasParseError())\n        {\n            return WEB_E_INVALID_JSON_STRING;\n        }\n    }\n\n    return S_OK;\n}\n\nHRESULT JsonUtils::ValidateJson(\n    _In_ const char* jsonString,\n    _Out_ JsonDocument& jsonDocument\n)\n{\n    if (jsonString == nullptr)\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    jsonDocument.Parse(jsonString);\n    if (jsonDocument.HasParseError())\n    {\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    return S_OK;\n}\n\nvoid JsonUtils::CopyFrom(JsonDocument& dest, const JsonValue& src)\n{\n    if (static_cast<void*>(&dest) != static_cast<void const*>(&src))\n    {\n        dest.CopyFrom(src, dest.GetAllocator());\n    }\n}\n\nHRESULT JsonUtils::SetMember(\n    _In_ JsonDocument& document,\n    _In_ const String& key,\n    _In_ const JsonValue& value\n) noexcept\n{\n    return SetMember(document, document.GetAllocator(), key, value);\n}\n\nHRESULT JsonUtils::SetMember(\n    _In_ JsonValue& object,\n    _In_ JsonDocument::AllocatorType& a,\n    _In_ const String& key,\n    _In_ const JsonValue& value\n) noexcept\n{\n    if (!object.IsObject())\n    {\n        return E_UNEXPECTED;\n    }\n\n    auto existingMember = object.FindMember(key.data());\n    if (existingMember == object.MemberEnd())\n    {\n        object.AddMember(JsonValue{ key.data(), a }.Move(), JsonValue{}.CopyFrom(value, a).Move(), a);\n    }\n    else\n    {\n        existingMember->value.CopyFrom(value, a);\n    }\n    return S_OK;\n}\n\nxsapi_internal_string JsonUtils::SerializeJson(_In_ const JsonValue& json)\n{\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    json.Accept(writer);\n    return buffer.GetString();\n}\n\nvoid* JsonAllocator::Malloc(size_t size)\n{\n    if (size)\n    {\n        return xbox::services::Alloc(size);\n    }\n    return nullptr;\n}\n\nvoid* JsonAllocator::Realloc(void* originalPtr, size_t originalSize, size_t newSize)\n{\n    void* newPtr = nullptr;\n    if (newSize > 0)\n    {\n        newPtr = Alloc(newSize);\n        memcpy(newPtr, originalPtr, (originalSize < newSize ? originalSize : newSize));\n    }\n    xbox::services::Free(originalPtr);\n    return newPtr;\n\n}\n\nvoid JsonAllocator::Free(void* ptr)\n{\n    xbox::services::Free(ptr);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/xsapi_json_utils.h",
    "content": "#pragma once\n#include \"internal_errors.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nclass JsonAllocator\n{\npublic:\n    static const bool kNeedFree = true;\n\n    void* Malloc(size_t size);\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);\n\n    static void Free(void* ptr);\n};\n\ntypedef rapidjson::GenericDocument<rapidjson::UTF8<>, JsonAllocator> JsonDocument;\ntypedef rapidjson::GenericValue<rapidjson::UTF8<>, JsonAllocator> JsonValue;\n\nclass JsonUtils\n{\npublic:\n    static HRESULT ExtractJsonXuid(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Out_ uint64_t& xuid,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonString(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& stringName,\n        _Inout_ xsapi_internal_string& outString,\n        _In_ bool required = false\n    );\n    \n    static HRESULT ExtractJsonStringToCharArray(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& stringName,\n        _Inout_updates_bytes_(size) char* charArr,\n        _In_ size_t size\n    );\n\n    static HRESULT ExtractJsonAsString(\n        _In_ const JsonValue& jsonValue,\n        _Inout_ xsapi_internal_string& outString\n    );\n\n    static JsonValue::ConstArray ExtractJsonArray(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& arrayName,\n        _In_ bool required\n    );\n\n    static HRESULT ExtractJsonBool(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& stringName,\n        _Inout_ bool& outBool,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonInt(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ int32_t& outInt,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonInt(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ uint32_t& outInt,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonInt(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ int64_t& outInt,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonInt(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ uint64_t& outInt,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonSizeT(\n        _In_ const JsonValue& jsonValue,\n        _In_ const String& name,\n        _Inout_ size_t& size,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonStringToUInt64(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ uint64_t& outUInt64,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonUInt64(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ uint64_t& outUInt64,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonTime(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ xbox::services::datetime& outTime,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonTimeT(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ time_t& outTime,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonStringTimespanInSeconds(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& stringName,\n        _Inout_ std::chrono::seconds& outTime,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonDouble(\n        _In_ const JsonValue& jsonValue,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ double& outDouble,\n        _In_ bool required = false\n    );\n\n    static HRESULT ExtractJsonFieldAsString(\n        _In_ const JsonValue& json,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ xsapi_internal_string& outString,\n        _In_ bool required\n    );\n\n    static HRESULT ExtractJsonStringVector(\n        _In_ const JsonValue& json,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ xsapi_internal_vector<xsapi_internal_string>& outVector,\n        _In_ bool required\n    );\n\n    static HRESULT ExtractJsonStringVector(\n        _In_ const JsonValue& json,\n        _Inout_ xsapi_internal_vector<xsapi_internal_string>& outVector\n    );\n\n    template<typename T, typename F>\n    static HRESULT ExtractJsonVector(\n        _In_ F deserialize,\n        _In_ const JsonValue& json,\n        _In_ const xsapi_internal_string& name,\n        _Inout_ xsapi_internal_vector<T>& outVector,\n        _In_ bool required\n    )\n    {\n        outVector = xsapi_internal_vector<T>();\n        if (json.IsObject())\n        {\n            if (json.HasMember(name.c_str()))\n            {\n                const JsonValue& field = json[name.c_str()];\n                if (field.IsArray())\n                {\n                    for (auto it = field.Begin(); it != field.End(); ++it)\n                    {\n                        auto obj = deserialize(*it);\n                        if (Failed(obj))\n                        {\n                            return obj.Hresult();\n                            break;\n                        }\n                        outVector.push_back(obj.Payload());\n                    }\n                    return S_OK;\n                }\n            }\n            else if (!required)\n            {\n                return S_OK;\n            }\n        }\n        return WEB_E_INVALID_JSON_STRING;\n    }\n\n    template<typename T, typename F>\n    static HRESULT ExtractJsonVector(\n        _In_ F deserialize,\n        _In_ const JsonValue& json,\n        _Inout_ xsapi_internal_vector<T>& outVector\n    )\n    {\n        outVector = xsapi_internal_vector<T>();\n        if (!json.IsArray())\n        {\n            return WEB_E_INVALID_JSON_STRING;\n        }\n\n        for (auto it = json.Begin(); it != json.End(); ++it)\n        {\n            auto obj = deserialize(*it);\n            if (Failed(obj))\n            {\n                return obj.Hresult();\n                break;\n            }\n            outVector.push_back(obj.Payload());\n        }\n\n        return S_OK;\n    }\n\n    static Result<xsapi_internal_string> JsonStringExtractor(_In_ const JsonValue& json);\n\n    static void JsonStringSerializer(_In_ const xsapi_internal_string& value, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\n    static void JsonXuidSerializer(_In_ uint64_t xuid, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\n    static Result<int> JsonIntExtractor(_In_ const JsonValue& json);\n\n    static Result<uint64_t> JsonXuidExtractor(_In_ const JsonValue& json);\n\n    static void JsonUtf8Serializer(_In_ const char* value, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& allocator);\n\n    // Note that this function allocates memory that must be freed by the caller.\n    static Result<const char*> JsonUtf8Extractor(_In_ const JsonValue& json);\n\n    static void JsonIntSerializer(_In_ int32_t value, _Out_ JsonValue& json, _In_ JsonDocument::AllocatorType& UNUSED);\n\n    template<typename T, typename F>\n    static void SerializeVector(\n        _In_ F serializer,\n        _In_ xsapi_internal_vector<T> inputVector,\n        _Out_ JsonValue& jsonArray,\n        _In_ JsonDocument::AllocatorType& allocator\n    )\n    {\n        jsonArray.SetArray();\n\n        for (auto& s : inputVector)\n        {\n            JsonValue val;\n            serializer(s, val, allocator);\n            jsonArray.PushBack(val, allocator);\n        }\n    }\n\n    static void SerializeUInt52ToJson(_In_ uint64_t integer, _Inout_ JsonValue& json);\n\n    static JsonValue SerializeTime(\n        _In_ time_t time,\n        _In_ JsonDocument::AllocatorType& allocator\n    ) noexcept;\n\n    static HRESULT ValidateJson(_In_ const char* jsonString);\n    static HRESULT ValidateJson(_In_ const char* jsonString, _Out_ JsonDocument& jsonDocument);\n\n    static void CopyFrom(JsonDocument& dest, const JsonValue& src);\n\n    // Set a member of an json object to a new value. The added value to be added will be deep copied.\n    // Note that the semantics of JsonValue::AddMember are to add a second member with\n    // the same key if one already exists; this method instead updates an existing member.\n    static HRESULT SetMember(\n        _In_ JsonDocument& document,\n        _In_ const String& key,\n        _In_ const JsonValue& value\n    ) noexcept;\n\n    static HRESULT SetMember(\n        _In_ JsonValue& object,\n        _In_ JsonDocument::AllocatorType& allocator,\n        _In_ const String& key,\n        _In_ const JsonValue& value\n    ) noexcept;\n\n    static xsapi_internal_string SerializeJson(_In_ const JsonValue& json);\n};\n\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/xsapi_utils.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi_utils.h\"\n#include \"xbox_live_app_config_internal.h\"\n#include <iomanip>\n#include <chrono>\n#include <time.h>\n#include <string>\n#if !HC_PLATFORM_IS_MICROSOFT\n#include \"xbl_guid.h\"\n#elif defined(_WIN32)\n#include <objbase.h>\n#endif\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"a/utils_a.h\"\n#include \"a/java_interop.h\"\n#endif\n#include \"presence_internal.h\"\n#include \"httpClient/httpClient.h\"\n#include \"Logger/log_hc_output.h\"\n#include \"global_state.h\"\n\n#if !_LINK_WITH_CPPRESTSDK && HC_PLATFORM != HC_PLATFORM_GDK\n#include \"cpprestsdk_impl.h\"\n#endif\n\n#ifndef _XTIME_TICKS_PER_TIME_T\n#define _XTIME_TICKS_PER_TIME_T 10000000LL\n#endif\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#define MAKE_HTTP_HRESULT(code) MAKE_HRESULT(1, 0x019, code)\n\nstatic char const * _sdaPrefix = \"AAAAAAAA\";\n\nstatic const uint64_t _msTicks = static_cast<uint64_t>(10000);\nstatic const uint64_t _secondTicks = 1000*_msTicks;\n\nxsapi_internal_string utils::encode_uri(\n    _In_ const xsapi_internal_string& data, \n    _In_ xbox::services::uri::components::component component\n    )\n{\n    return xbox::services::uri::encode_uri(data, component);\n}\n\nxsapi_internal_string utils::headers_to_string(\n    _In_ const xsapi_internal_http_headers& headers\n    )\n{\n    xsapi_internal_stringstream ss;\n\n    for (const auto& header : headers)\n    {\n        ss << header.first << \": \" << header.second << \"\\r\\n\";\n    }\n\n    return ss.str();\n}\n\nxsapi_internal_string \nutils::get_query_from_params(\n    _In_ const xsapi_internal_vector<xsapi_internal_string>& params\n    )\n{\n    xsapi_internal_stringstream strQueryString;\n\n    size_t cItems = params.size();\n    if (cItems > 0)\n    {\n        xsapi_internal_string strDelimiter = \"&\";\n\n        strQueryString << \"?\";\n        strQueryString << params[0];\n\n        size_t i = 0;\n        while (++i < cItems)\n        {\n            strQueryString << strDelimiter;\n            strQueryString << params[i];\n        }\n    }\n\n    return strQueryString.str();\n}\n\nvoid utils::append_paging_info(\n    _In_ xbox::services::uri_builder& uriBuilder,\n    _In_ unsigned int skipItems,\n    _In_ unsigned int maxItems,\n    _In_opt_ xsapi_internal_string continuationToken\n    )\n{\n    // add maxItem parameter\n    if (maxItems > 0)\n    {\n        uriBuilder.append_query(\"maxItems\", maxItems);\n    }\n\n    if (continuationToken.empty())\n    {\n        // use skip items value if continuation token is empty\n        if (skipItems > 0)\n        {\n            uriBuilder.append_query(\"skipItems\", skipItems);\n        }\n    }\n    else\n    {\n        uriBuilder.append_query(\"continuationToken\", continuationToken);\n    }\n}\n\n#if defined(_WIN32) \nuint32_t utils::convert_timespan_to_days(\n    _In_ uint64_t timespan\n    )\n{\n    int64_t days = (timespan / _XTIME_TICKS_PER_TIME_T) / SECONDS_PER_DAY;\n    THROW_CPP_INVALIDARGUMENT_IF(days < 0 || days > UINT32_MAX);\n\n    return static_cast<uint32_t>(days);\n}\n\nvoid utils::convert_unix_time_to_filetime(\n    _In_ std::time_t t,\n    _In_ FILETIME* ft\n    )\n{\n    if (!ft)\n    {\n        return;\n    }\n\n    LONGLONG ll;\n\n#ifdef _USE_32BIT_TIME_T\n    ll = Int32x32To64(t * 10000000) + 116444736000000000;\n#else\n    ll = (t * 10000000) + 116444736000000000;\n#endif\n\n    ft->dwLowDateTime = (DWORD)ll;\n    ft->dwHighDateTime = ll >> 32;\n}\nvoid utils::convert_timepoint_to_filetime(\n    _In_ const chrono_clock_t::time_point& time_point,\n    _Inout_ uint64_t& largeInt\n    )\n{\n    // time_point to system time\n    std::time_t t = convert_timepoint_to_time(time_point);\n    // system time to FILETIME\n    FILETIME ft = { 0 };\n    convert_unix_time_to_filetime(t, &ft);\n\n    if (largeInt)\n    {\n        ULARGE_INTEGER large;\n        large.LowPart = ft.dwLowDateTime;\n        large.HighPart = ft.dwHighDateTime;\n        largeInt = large.QuadPart;\n    }\n}\n#endif\n\nstd::time_t utils::convert_timepoint_to_time(\n    _In_ const chrono_clock_t::time_point& time_point\n    )\n{\n#if _MSC_VER <= 1800\n    return chrono_clock_t::to_time_t(time_point);\n#else\n    uint64_t timeDiff = std::chrono::duration_cast<std::chrono::seconds>(time_point.time_since_epoch() - std::chrono::steady_clock::now().time_since_epoch()).count();\n    uint64_t timeNow = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();\n    return timeNow + timeDiff;\n#endif\n}\n\nxsapi_internal_string utils::convert_timepoint_to_string(\n    _In_ const chrono_clock_t::time_point& time_point\n    )\n{\n    xsapi_internal_string result;\n    xsapi_internal_string::value_type buff[FILENAME_MAX];\n    std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_point.time_since_epoch());\n    time_t t = utils::convert_timepoint_to_time(time_point);\n    std::tm time;\n#if defined(_WIN32)\n    errno_t errorCode = localtime_s(&time, &t);\n    if (errorCode != 0)\n    {\n        return result;\n    }\n    sprintf_s(buff, \"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\",\n        time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,\n        time.tm_hour, time.tm_min, time.tm_sec, static_cast<int>(ms.count() % 1000));\n#else\n#if defined(PAVO)\n    std::tm* error = localtime_s(&t, &time);\n#else\n    std::tm* error = localtime_r(&t, &time);\n#endif // PAVO\n    if (error == nullptr)\n    {\n        return result;\n    }\n    snprintf(buff, sizeof(buff), _T(\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"),\n              time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,\n              time.tm_hour, time.tm_min, time.tm_sec, static_cast<int>(ms.count() % 1000));\n\n#endif\n    result = buff;\n\n    return result;\n}\n\nxsapi_internal_string utils::escape_special_characters(const xsapi_internal_string& str)\n{\n    xsapi_internal_string result = str;\n    for (auto iter = result.begin(); iter != result.end(); ++iter)\n    {\n        if (*iter == '\\r' || *iter == '\\n')\n        {\n            iter = result.insert(iter, ' ');\n            iter = result.erase(iter + 1);\n            --iter;\n        }\n        else if (*iter == '\\\"')\n        {\n            iter = result.insert(iter, '\\\"');\n            ++iter;\n        }\n    }\n    return result;\n}\n\nuint32_t\nutils::char_t_copy(\n    _In_reads_bytes_(sizeInWords) char_t* destinationCharArr,\n    _In_ size_t sizeInWords,\n    _In_ const char_t* sourceCharArr\n    )\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    return wcscpy_s(destinationCharArr, sizeInWords, sourceCharArr);\n#else\n    return (uint32_t)strlcpy(destinationCharArr, sourceCharArr, (uint32_t)sizeInWords);\n#endif\n}\n\nsize_t\nutils::strcpy(\n    _In_ char* destinationCharArr,\n    _In_ size_t sizeInWords,\n    _In_ const char* sourceCharArr\n    )\n\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    return strcpy_s(destinationCharArr, sizeInWords, sourceCharArr);\n#else\n    return strlcpy(destinationCharArr, sourceCharArr, sizeInWords);\n#endif\n}\n\nHRESULT\nutils::convert_exception_to_hresult()\n{\n    // Default value, if there is no exception appears, return S_OK\n    HRESULT hr = S_OK;\n\n    try\n    {\n        throw;\n    }\n    // std exceptions\n    catch (const std::bad_alloc&) // is an exception\n    {\n        hr = E_OUTOFMEMORY;\n    }\n    catch (const std::bad_cast&) // is an exception\n    {\n        hr = E_NOINTERFACE;\n    }\n    catch (const std::invalid_argument&) // is a logic_error\n    {\n        hr = E_INVALIDARG;\n    }\n    catch (const std::out_of_range&) // is a logic_error\n    {\n        hr = E_BOUNDS;\n    }\n    catch (const std::length_error&) // is a logic_error\n    {\n        hr = __HRESULT_FROM_WIN32(ERROR_BAD_LENGTH);\n    }\n    catch (const std::overflow_error&) // is a runtime_error\n    {\n        hr = __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n    }\n    catch (const std::underflow_error&) // is a runtime_error\n    {\n        hr = __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n    }\n    catch (const std::range_error&) // is a runtime_error\n    {\n        hr = E_BOUNDS;\n    }\n    catch (const std::system_error& ex) // is a runtime_error\n    {\n        if (ex.code().category() == std::system_category())\n        {\n            hr = __HRESULT_FROM_WIN32(ex.code().value());\n        }\n        else\n        {\n            hr = ex.code().value();\n        }\n    }\n    catch (const std::logic_error&) // is an exception\n    {\n        hr = E_UNEXPECTED;\n    }\n    catch (const std::runtime_error&) // is an exception\n    {\n        hr = E_FAIL;\n    }\n#if !XSAPI_NO_PPL\n    catch (const web::http::http_exception&) // is an exception\n    {\n        hr = HTTP_E_STATUS_UNEXPECTED;\n    }\n#endif // !XSAPI_NO_PPL\n    catch (const xbox::services::uri_exception&) // is an exception\n    {\n        hr = WEB_E_UNEXPECTED_CONTENT;\n    }\n    catch (const std::exception&) // base class for standard C++ exceptions\n    {\n        hr = E_FAIL;\n    }\n    catch (HRESULT exceptionHR)\n    {\n        hr = exceptionHR;\n    }\n    catch (...) // everything else\n    {\n        hr = E_FAIL;\n    }\n\n    return hr;\n}\n\nHRESULT\nutils::convert_xbox_live_error_code_to_hresult(\n    _In_ const std::error_code& errCode\n    )\n{\n    int err = static_cast<int>(errCode.value());\n    xbl_error_code xblErr = static_cast<xbl_error_code>(err);\n\n    if (err == 204)\n    {\n        return __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);\n    }\n    else if (err >= 300 && err <= 505)\n    {\n        return (HRESULT)convert_http_status_to_hresult(err);\n    }\n    else if (err >= 1000 && err <= 9999)\n    {\n        switch (xblErr)\n        {\n            case xbl_error_code::bad_alloc: return E_OUTOFMEMORY;\n            case xbl_error_code::invalid_argument: return E_INVALIDARG;\n            case xbl_error_code::runtime_error: return E_XBL_RUNTIME_ERROR;\n            case xbl_error_code::length_error: return __HRESULT_FROM_WIN32(ERROR_BAD_LENGTH);\n            case xbl_error_code::out_of_range: return E_BOUNDS;\n            case xbl_error_code::range_error: return E_BOUNDS;\n            case xbl_error_code::bad_cast: return E_NOINTERFACE;\n            case xbl_error_code::logic_error: return E_UNEXPECTED;\n            case xbl_error_code::json_error: return WEB_E_INVALID_JSON_STRING;\n            case xbl_error_code::uri_error: return WEB_E_UNEXPECTED_CONTENT;\n            case xbl_error_code::websocket_error: return WEB_E_UNEXPECTED_CONTENT;\n            case xbl_error_code::auth_user_interaction_required: return ONL_E_ACTION_REQUIRED;\n            case xbl_error_code::rta_generic_error: return E_XBL_RTA_GENERIC_ERROR;\n            case xbl_error_code::rta_subscription_limit_reached: return E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED;\n            case xbl_error_code::rta_access_denied: return E_XBL_RTA_ACCESS_DENIED;\n            case xbl_error_code::auth_unknown_error: return E_XBL_AUTH_UNKNOWN_ERROR;\n            case xbl_error_code::auth_runtime_error: return E_XBL_AUTH_RUNTIME_ERROR;\n            case xbl_error_code::auth_no_token_error: return E_XBL_AUTH_NO_TOKEN;\n            case xbl_error_code::auth_user_not_signed_in: return __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);\n            case xbl_error_code::auth_user_cancel: return __HRESULT_FROM_WIN32(ERROR_CANCELLED);\n            case xbl_error_code::auth_user_switched: return __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);\n            case xbl_error_code::invalid_config: return __HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION);\n            case xbl_error_code::unsupported: return E_NOTIMPL;\n\n            default: return E_FAIL;\n        }\n    }\n    else if ((err & 0x87DD0000) == 0x87D8000)\n    {\n        return HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR;\n    }\n    else return err; //return the original error code if can't be translated.\n}\n\nxbl_error_code utils::convert_http_status_to_xbox_live_error_code(\n    _In_ uint32_t statusCode\n    )\n{\n    if (statusCode < 300 || statusCode >= 600)\n    {\n        // Treat as success so \n        //      if (!result.err()) \n        // works properly which requires all non-errors to be 0.\n        return xbl_error_code::no_error;\n    }\n    else\n    {\n        return static_cast<xbl_error_code>(statusCode);\n    }\n}\n\nHRESULT utils::convert_http_status_to_hresult(_In_ uint32_t httpStatusCode)\n{\n    xbl_error_code errCode = static_cast<xbl_error_code>(httpStatusCode);\n    HRESULT hr = HTTP_E_STATUS_UNEXPECTED;\n    \n    // 2xx are http success codes\n    if ((httpStatusCode >= 200) && (httpStatusCode < 300))\n    {\n        hr = S_OK;\n    }\n    \n    // MSXML XHR bug: get_status() returns HTTP/1223 for HTTP/204:\n    // http://blogs.msdn.com/b/ieinternals/archive/2009/07/23/the-ie8-native-xmlhttprequest-object.aspx\n    // treat it as success code as well\n    else if (httpStatusCode == 1223)\n    {\n        hr = S_OK;\n    }\n    else\n    {\n        switch (errCode)\n        {\n            case xbl_error_code::http_status_300_multiple_choices: hr = HTTP_E_STATUS_AMBIGUOUS; break;\n            case xbl_error_code::http_status_301_moved_permanently: hr = HTTP_E_STATUS_MOVED; break;\n            case xbl_error_code::http_status_302_found: hr = HTTP_E_STATUS_REDIRECT; break;\n            case xbl_error_code::http_status_303_see_other: hr = HTTP_E_STATUS_REDIRECT_METHOD; break;\n            case xbl_error_code::http_status_304_not_modified: hr = HTTP_E_STATUS_NOT_MODIFIED; break;\n            case xbl_error_code::http_status_305_use_proxy: hr = HTTP_E_STATUS_USE_PROXY; break;\n            case xbl_error_code::http_status_307_temporary_redirect: hr = HTTP_E_STATUS_REDIRECT_KEEP_VERB; break;\n            \n            case xbl_error_code::http_status_400_bad_request: hr = HTTP_E_STATUS_BAD_REQUEST; break;\n            case xbl_error_code::http_status_401_unauthorized: hr = HTTP_E_STATUS_DENIED; break;\n            case xbl_error_code::http_status_402_payment_required: hr = HTTP_E_STATUS_PAYMENT_REQ; break;\n            case xbl_error_code::http_status_403_forbidden: hr = HTTP_E_STATUS_FORBIDDEN; break;\n            case xbl_error_code::http_status_404_not_found: hr = HTTP_E_STATUS_NOT_FOUND; break;\n            case xbl_error_code::http_status_405_method_not_allowed: hr = HTTP_E_STATUS_BAD_METHOD; break;\n            case xbl_error_code::http_status_406_not_acceptable: hr = HTTP_E_STATUS_NONE_ACCEPTABLE; break;\n            case xbl_error_code::http_status_407_proxy_authentication_required: hr = HTTP_E_STATUS_PROXY_AUTH_REQ; break;\n            case xbl_error_code::http_status_408_request_timeout: hr = HTTP_E_STATUS_REQUEST_TIMEOUT; break;\n            case xbl_error_code::http_status_409_conflict: hr = HTTP_E_STATUS_CONFLICT; break;\n            case xbl_error_code::http_status_410_gone: hr = HTTP_E_STATUS_GONE; break;\n            case xbl_error_code::http_status_411_length_required: hr = HTTP_E_STATUS_LENGTH_REQUIRED; break;\n            case xbl_error_code::http_status_412_precondition_failed: hr = HTTP_E_STATUS_PRECOND_FAILED; break;\n            case xbl_error_code::http_status_413_request_entity_too_large: hr = HTTP_E_STATUS_REQUEST_TOO_LARGE; break;\n            case xbl_error_code::http_status_414_request_uri_too_long: hr = HTTP_E_STATUS_URI_TOO_LONG; break;\n            case xbl_error_code::http_status_415_unsupported_media_type: hr = HTTP_E_STATUS_UNSUPPORTED_MEDIA; break;\n            case xbl_error_code::http_status_416_requested_range_not_satisfiable: hr = HTTP_E_STATUS_RANGE_NOT_SATISFIABLE; break;\n            case xbl_error_code::http_status_417_expectation_failed: hr = HTTP_E_STATUS_EXPECTATION_FAILED; break;\n            case xbl_error_code::http_status_421_misdirected_request: hr = MAKE_HTTP_HRESULT(421); break;\n            case xbl_error_code::http_status_422_unprocessable_entity: hr = MAKE_HTTP_HRESULT(422); break;\n            case xbl_error_code::http_status_423_locked: hr = MAKE_HTTP_HRESULT(423); break;\n            case xbl_error_code::http_status_424_failed_dependency: hr = MAKE_HTTP_HRESULT(424); break;\n            case xbl_error_code::http_status_426_upgrade_required: hr = MAKE_HTTP_HRESULT(426); break;\n            case xbl_error_code::http_status_428_precondition_required: hr = MAKE_HTTP_HRESULT(428); break;\n            case xbl_error_code::http_status_429_too_many_requests: hr = MAKE_HTTP_HRESULT(429); break;\n            case xbl_error_code::http_status_431_request_header_fields_too_large: hr = MAKE_HTTP_HRESULT(431); break;\n            case xbl_error_code::http_status_449_retry_with:hr = MAKE_HTTP_HRESULT(449); break;\n            case xbl_error_code::http_status_451_unavailable_for_legal_reasons: hr = MAKE_HTTP_HRESULT(451); break;\n            \n            case xbl_error_code::http_status_500_internal_server_error: hr = HTTP_E_STATUS_SERVER_ERROR; break;\n            case xbl_error_code::http_status_501_not_implemented: hr = HTTP_E_STATUS_NOT_SUPPORTED; break;\n            case xbl_error_code::http_status_502_bad_gateway: hr = HTTP_E_STATUS_BAD_GATEWAY; break;\n            case xbl_error_code::http_status_503_service_unavailable: hr = HTTP_E_STATUS_SERVICE_UNAVAIL; break;\n            case xbl_error_code::http_status_504_gateway_timeout: hr = HTTP_E_STATUS_GATEWAY_TIMEOUT; break;\n            case xbl_error_code::http_status_505_http_version_not_supported: hr = HTTP_E_STATUS_VERSION_NOT_SUP; break;\n            case xbl_error_code::http_status_506_variant_also_negotiates: hr = MAKE_HTTP_HRESULT(506); break;\n            case xbl_error_code::http_status_507_insufficient_storage: hr = MAKE_HTTP_HRESULT(507); break;\n            case xbl_error_code::http_status_508_loop_detected: hr = MAKE_HTTP_HRESULT(508); break;\n            case xbl_error_code::http_status_510_not_extended: hr = MAKE_HTTP_HRESULT(510); break;\n            case xbl_error_code::http_status_511_network_authentication_required: hr = MAKE_HTTP_HRESULT(511); break;\n            \n            default:\n            hr = HTTP_E_STATUS_UNEXPECTED;\n            break;\n        }\n    }\n    \n    return hr;\n}\n#if HC_PLATFORM_IS_MICROSOFT\n// TODO: remove\nxsapi_internal_string utils::convert_hresult_to_error_name(_In_ long hr)\n{\n    switch (hr)\n    {\n        // Generic errors\n    case S_OK: return \"S_OK\";\n    case S_FALSE: return \"S_FALSE\";\n    case E_OUTOFMEMORY: return \"E_OUTOFMEMORY\";\n    case E_ACCESSDENIED: return \"E_ACCESSDENIED\";\n    case E_INVALIDARG: return \"E_INVALIDARG\";\n    case E_UNEXPECTED: return \"E_UNEXPECTED\";\n    case E_ABORT: return \"E_ABORT\";\n    case E_FAIL: return \"E_FAIL\";\n    case E_NOTIMPL: return \"E_NOTIMPL\";\n    case E_ILLEGAL_METHOD_CALL: return \"E_ILLEGAL_METHOD_CALL\";\n\n        // Authentication specific errors\n    case 0x87DD0003: return \"AM_E_XASD_UNEXPECTED\";\n    case 0x87DD0004: return \"AM_E_XASU_UNEXPECTED\";\n    case 0x87DD0005: return \"AM_E_XAST_UNEXPECTED\";\n    case 0x87DD0006: return \"AM_E_XSTS_UNEXPECTED\";\n    case 0x87DD0007: return \"AM_E_XDEVICE_UNEXPECTED\";\n    case 0x87DD0008: return \"AM_E_DEVMODE_NOT_AUTHORIZED\";\n    case 0x87DD0009: return \"AM_E_NOT_AUTHORIZED\";\n    case 0x87DD000A: return \"AM_E_FORBIDDEN\";\n    case 0x87DD000B: return \"AM_E_UNKNOWN_TARGET\";\n    case 0x87DD000C: return \"AM_E_INVALID_NSAL_DATA\";\n    case 0x87DD000D: return \"AM_E_TITLE_NOT_AUTHENTICATED\";\n    case 0x87DD000E: return \"AM_E_TITLE_NOT_AUTHORIZED\";\n    case 0x87DD000F: return \"AM_E_DEVICE_NOT_AUTHENTICATED\";\n    case 0x87DD0010: return \"AM_E_INVALID_USER_INDEX\";\n\n    case 0x8015DC00: return \"XO_E_DEVMODE_NOT_AUTHORIZED\";\n    case 0x8015DC01: return \"XO_E_SYSTEM_UPDATE_REQUIRED\";\n    case 0x8015DC02: return \"XO_E_CONTENT_UPDATE_REQUIRED\";\n    case 0x8015DC03: return \"XO_E_ENFORCEMENT_BAN\";\n    case 0x8015DC04: return \"XO_E_THIRD_PARTY_BAN\";\n    case 0x8015DC05: return \"XO_E_ACCOUNT_PARENTALLY_RESTRICTED\";\n    case 0x8015DC06: return \"XO_E_DEVICE_SUBSCRIPTION_NOT_ACTIVATED\";\n    case 0x8015DC08: return \"XO_E_ACCOUNT_BILLING_MAINTENANCE_REQUIRED\";\n    case 0x8015DC09: return \"XO_E_ACCOUNT_CREATION_REQUIRED\";\n    case 0x8015DC0A: return \"XO_E_ACCOUNT_TERMS_OF_USE_NOT_ACCEPTED\";\n    case 0x8015DC0B: return \"XO_E_ACCOUNT_COUNTRY_NOT_AUTHORIZED\";\n    case 0x8015DC0C: return \"XO_E_ACCOUNT_AGE_VERIFICATION_REQUIRED\";\n    case 0x8015DC0D: return \"XO_E_ACCOUNT_CURFEW\";\n    case 0x8015DC0E: return \"XO_E_ACCOUNT_CHILD_NOT_IN_FAMILY\";\n    case 0x8015DC0F: return \"XO_E_ACCOUNT_CSV_TRANSITION_REQUIRED\";\n    case 0x8015DC10: return \"XO_E_ACCOUNT_MAINTENANCE_REQUIRED\";\n    case 0x8015DC11: return \"XO_E_ACCOUNT_TYPE_NOT_ALLOWED\"; // dev account on retail box\n    case 0x8015DC12: return \"XO_E_CONTENT_ISOLATION (Verify SCID / Sandbox)\";\n    case 0x8015DC13: return \"XO_E_ACCOUNT_NAME_CHANGE_REQUIRED\";\n    case 0x8015DC14: return \"XO_E_DEVICE_CHALLENGE_REQUIRED\";\n        // case 0x8015DC15: synthetic device type not allowed - does not apply to consoles\n    case 0x8015DC16: return \"XO_E_SIGNIN_COUNT_BY_DEVICE_TYPE_EXCEEDED\";\n    case 0x8015DC17: return \"XO_E_PIN_CHALLENGE_REQUIRED\";\n    case 0x8015DC18: return \"XO_E_RETAIL_ACCOUNT_NOT_ALLOWED\"; // RETAIL account on devkit\n    case 0x8015DC19: return \"XO_E_SANDBOX_NOT_ALLOWED\";\n    case 0x8015DC1A: return \"XO_E_ACCOUNT_SERVICE_UNAVAILABLE_UNKNOWN_USER\";\n    case 0x8015DC1B: return \"XO_E_GREEN_SIGNED_CONTENT_NOT_AUTHORIZED\";\n    case 0x8015DC1C: return \"XO_E_CONTENT_NOT_AUTHORIZED\";\n\n    case 0x8015DC20: return \"XO_E_EXPIRED_DEVICE_TOKEN\";\n    case 0x8015DC21: return \"XO_E_EXPIRED_TITLE_TOKEN\";\n    case 0x8015DC22: return \"XO_E_EXPIRED_USER_TOKEN\";\n    case 0x8015DC23: return \"XO_E_INVALID_DEVICE_TOKEN\";\n    case 0x8015DC24: return \"XO_E_INVALID_TITLE_TOKEN\";\n    case 0x8015DC25: return \"XO_E_INVALID_USER_TOKEN\";\n\n        // HTTP specific errors\n    case WEB_E_UNSUPPORTED_FORMAT: return \"WEB_E_UNSUPPORTED_FORMAT\";\n    case WEB_E_INVALID_XML: return \"WEB_E_INVALID_XML\";\n    case WEB_E_MISSING_REQUIRED_ELEMENT: return \"WEB_E_MISSING_REQUIRED_ELEMENT\";\n    case WEB_E_MISSING_REQUIRED_ATTRIBUTE: return \"WEB_E_MISSING_REQUIRED_ATTRIBUTE\";\n    case WEB_E_UNEXPECTED_CONTENT: return \"WEB_E_UNEXPECTED_CONTENT\";\n    case WEB_E_RESOURCE_TOO_LARGE: return \"WEB_E_RESOURCE_TOO_LARGE\";\n    case WEB_E_INVALID_JSON_STRING: return \"WEB_E_INVALID_JSON_STRING\";\n    case WEB_E_INVALID_JSON_NUMBER: return \"WEB_E_INVALID_JSON_NUMBER\";\n    case WEB_E_JSON_VALUE_NOT_FOUND: return \"WEB_E_JSON_VALUE_NOT_FOUND\";\n    case ERROR_RESOURCE_DATA_NOT_FOUND: return \"ERROR_RESOURCE_DATA_NOT_FOUND\";\n\n    case HTTP_E_STATUS_UNEXPECTED: return \"HTTP_E_STATUS_UNEXPECTED\";\n    case HTTP_E_STATUS_UNEXPECTED_REDIRECTION: return \"HTTP_E_STATUS_UNEXPECTED_REDIRECTION\";\n    case HTTP_E_STATUS_UNEXPECTED_CLIENT_ERROR: return \"HTTP_E_STATUS_UNEXPECTED_CLIENT_ERROR\";\n    case HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR: return \"HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR\";\n    case HTTP_E_STATUS_AMBIGUOUS: return \"HTTP_E_STATUS_AMBIGUOUS\";\n    case HTTP_E_STATUS_MOVED: return \"HTTP_E_STATUS_MOVED\";\n    case HTTP_E_STATUS_REDIRECT: return \"HTTP_E_STATUS_REDIRECT\";\n    case HTTP_E_STATUS_REDIRECT_METHOD: return \"HTTP_E_STATUS_REDIRECT_METHOD\";\n    case HTTP_E_STATUS_NOT_MODIFIED: return \"HTTP_E_STATUS_NOT_MODIFIED\";\n    case HTTP_E_STATUS_USE_PROXY: return \"HTTP_E_STATUS_USE_PROXY\";\n    case HTTP_E_STATUS_REDIRECT_KEEP_VERB: return \"HTTP_E_STATUS_REDIRECT_KEEP_VERB\";\n    case HTTP_E_STATUS_BAD_REQUEST: return \"HTTP_E_STATUS_BAD_REQUEST\";\n    case HTTP_E_STATUS_DENIED: return \"HTTP_E_STATUS_DENIED\";\n    case HTTP_E_STATUS_PAYMENT_REQ: return \"HTTP_E_STATUS_PAYMENT_REQ\";\n    case HTTP_E_STATUS_FORBIDDEN: return \"HTTP_E_STATUS_FORBIDDEN\";\n    case HTTP_E_STATUS_NOT_FOUND: return \"HTTP_E_STATUS_NOT_FOUND\";\n    case HTTP_E_STATUS_BAD_METHOD: return \"HTTP_E_STATUS_BAD_METHOD\";\n    case HTTP_E_STATUS_NONE_ACCEPTABLE: return \"HTTP_E_STATUS_NONE_ACCEPTABLE\";\n    case HTTP_E_STATUS_PROXY_AUTH_REQ: return \"HTTP_E_STATUS_PROXY_AUTH_REQ\";\n    case HTTP_E_STATUS_REQUEST_TIMEOUT: return \"HTTP_E_STATUS_REQUEST_TIMEOUT\";\n    case HTTP_E_STATUS_CONFLICT: return \"HTTP_E_STATUS_CONFLICT\";\n    case HTTP_E_STATUS_GONE: return \"HTTP_E_STATUS_GONE\";\n    case HTTP_E_STATUS_LENGTH_REQUIRED: return \"HTTP_E_STATUS_LENGTH_REQUIRED\";\n    case HTTP_E_STATUS_PRECOND_FAILED: return \"HTTP_E_STATUS_PRECOND_FAILED\";\n    case HTTP_E_STATUS_REQUEST_TOO_LARGE: return \"HTTP_E_STATUS_REQUEST_TOO_LARGE\";\n    case HTTP_E_STATUS_URI_TOO_LONG: return \"HTTP_E_STATUS_URI_TOO_LONG\";\n    case HTTP_E_STATUS_UNSUPPORTED_MEDIA: return \"HTTP_E_STATUS_UNSUPPORTED_MEDIA\";\n    case HTTP_E_STATUS_RANGE_NOT_SATISFIABLE: return \"HTTP_E_STATUS_RANGE_NOT_SATISFIABLE\";\n    case HTTP_E_STATUS_EXPECTATION_FAILED: return \"HTTP_E_STATUS_EXPECTATION_FAILED\";\n\n    case MAKE_HTTP_HRESULT(421): return \"HTTP_E_STATUS_421_MISDIRECTED_REQUEST\";\n    case MAKE_HTTP_HRESULT(422): return \"HTTP_E_STATUS_422_UNPROCESSABLE_ENTITY\";\n    case MAKE_HTTP_HRESULT(423): return \"HTTP_E_STATUS_423_LOCKED\";\n    case MAKE_HTTP_HRESULT(424): return \"HTTP_E_STATUS_424_FAILED_DEPENDENCY\";\n    case MAKE_HTTP_HRESULT(426): return \"HTTP_E_STATUS_426_UPGRADE_REQUIRED\";\n    case MAKE_HTTP_HRESULT(428): return \"HTTP_E_STATUS_428_PRECONDITION_REQUIRED\";\n    case MAKE_HTTP_HRESULT(429): return \"HTTP_E_STATUS_429_TOO_MANY_REQUESTS\";\n    case MAKE_HTTP_HRESULT(431): return \"HTTP_E_STATUS_431_REQUEST_HEADER_FIELDS_TOO_LARGE\";\n    case MAKE_HTTP_HRESULT(449): return \"HTTP_E_STATUS_449_RETRY_WITH\";\n    case MAKE_HTTP_HRESULT(451): return \"HTTP_E_STATUS_451_UNAVAILABLE_FOR_LEGAL_REASONS\";\n\n    case HTTP_E_STATUS_SERVER_ERROR: return \"HTTP_E_STATUS_SERVER_ERROR\";\n    case HTTP_E_STATUS_NOT_SUPPORTED: return \"HTTP_E_STATUS_NOT_SUPPORTED\";\n    case HTTP_E_STATUS_BAD_GATEWAY: return \"HTTP_E_STATUS_BAD_GATEWAY\";\n    case HTTP_E_STATUS_SERVICE_UNAVAIL: return \"HTTP_E_STATUS_SERVICE_UNAVAIL\";\n    case HTTP_E_STATUS_GATEWAY_TIMEOUT: return \"HTTP_E_STATUS_GATEWAY_TIMEOUT\";\n    case HTTP_E_STATUS_VERSION_NOT_SUP: return \"HTTP_E_STATUS_VERSION_NOT_SUP\";\n\n    case MAKE_HTTP_HRESULT(506): return \"HTTP_E_STATUS_506_VARIANT_ALSO_NEGOTIATES\";\n    case MAKE_HTTP_HRESULT(507): return \"HTTP_E_STATUS_507_INSUFFICIENT_STORAGE\";\n    case MAKE_HTTP_HRESULT(508): return \"HTTP_E_STATUS_508_LOOP_DETECTED\";\n    case MAKE_HTTP_HRESULT(510): return \"HTTP_E_STATUS_510_NOT_EXTENDED\";\n    case MAKE_HTTP_HRESULT(511): return \"HTTP_E_STATUS_511_NETWORK_AUTHENTICATION_REQUIRED\";\n\n        // WinINet specific errors\n    case INET_E_INVALID_URL: return \"INET_E_INVALID_URL\";\n    case INET_E_NO_SESSION: return \"INET_E_NO_SESSION\";\n    case INET_E_CANNOT_CONNECT: return \"INET_E_CANNOT_CONNECT\";\n    case INET_E_RESOURCE_NOT_FOUND: return \"INET_E_RESOURCE_NOT_FOUND\";\n    case INET_E_OBJECT_NOT_FOUND: return \"INET_E_OBJECT_NOT_FOUND\";\n    case INET_E_DATA_NOT_AVAILABLE: return \"INET_E_DATA_NOT_AVAILABLE\";\n    case INET_E_DOWNLOAD_FAILURE: return \"INET_E_DOWNLOAD_FAILURE\";\n    case INET_E_AUTHENTICATION_REQUIRED: return \"INET_E_AUTHENTICATION_REQUIRED\";\n    case INET_E_NO_VALID_MEDIA: return \"INET_E_NO_VALID_MEDIA\";\n    case INET_E_CONNECTION_TIMEOUT: return \"INET_E_CONNECTION_TIMEOUT\";\n    case INET_E_INVALID_REQUEST: return \"INET_E_INVALID_REQUEST\";\n    case INET_E_UNKNOWN_PROTOCOL: return \"INET_E_UNKNOWN_PROTOCOL\";\n    case INET_E_SECURITY_PROBLEM: return \"INET_E_SECURITY_PROBLEM\";\n    case INET_E_CANNOT_LOAD_DATA: return \"INET_E_CANNOT_LOAD_DATA\";\n    case INET_E_CANNOT_INSTANTIATE_OBJECT: return \"INET_E_CANNOT_INSTANTIATE_OBJECT\";\n    case INET_E_INVALID_CERTIFICATE: return \"INET_E_INVALID_CERTIFICATE\";\n    case INET_E_REDIRECT_FAILED: return \"INET_E_REDIRECT_FAILED\";\n    case INET_E_REDIRECT_TO_DIR: return \"INET_E_REDIRECT_TO_DIR\";\n    }\n\n    return \"Unknown error\";\n}\n#endif\n\nxbox::services::xbl_error_code\nutils::convert_exception_to_xbox_live_error_code()\n{\n    // Default value, if there is no exception appears, return no_error\n    xbox::services::xbl_error_code errCode = xbl_error_code::no_error;\n\n    try\n    {\n        throw;\n    }\n    // std exceptions\n    catch (const std::bad_alloc&) // is an exception\n    {\n        errCode = xbl_error_code::bad_alloc;\n    }\n    catch (const std::bad_cast&) // is an exception\n    {\n        errCode = xbl_error_code::bad_cast;\n    }\n    catch (const std::invalid_argument&) // is a logic_error\n    {\n        errCode = xbl_error_code::invalid_argument;\n    }\n    catch (const std::out_of_range&) // is a logic_error\n    {\n        errCode = xbl_error_code::out_of_range;\n    }\n    catch (const std::length_error&) // is a logic_error\n    {\n        errCode = xbl_error_code::length_error;\n    }\n    catch (const std::range_error&) // is a runtime_error\n    {\n        errCode = xbl_error_code::range_error;\n    }\n    catch (const std::system_error& ex) // is a runtime_error\n    {\n        errCode = static_cast<xbl_error_code>(ex.code().value());\n    }\n    catch (const std::logic_error&) // is an exception\n    {\n        errCode = xbl_error_code::logic_error;\n    }\n    catch (const std::runtime_error&) // is an exception\n    {\n        errCode = xbl_error_code::runtime_error;\n    }\n#if !XSAPI_NO_PPL\n    catch (const web::http::http_exception& ex) // is an exception\n    {\n        errCode = static_cast<xbl_error_code>(ex.error_code().value());\n    }\n#endif // !XSAPI_NO_PPL\n    catch (const xbox::services::uri_exception&) // is an exception\n    {\n        errCode = xbl_error_code::uri_error;\n    }\n    catch (const std::exception&) // base class for standard C++ exceptions\n    {\n        errCode = xbl_error_code::generic_error;\n    }\n#if HC_PLATFORM_IS_MICROSOFT\n    catch (HRESULT exceptionHR)\n    {\n        errCode = static_cast<xbl_error_code>(exceptionHR);\n    }\n#endif\n    catch (...) // everything else\n    {\n        errCode = xbl_error_code::generic_error;\n    }\n\n    return errCode;\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\nstd::error_code utils::guid_from_string(\n    _In_ const string_t& str, \n    _In_ GUID* guid,\n    _In_ bool withBraces\n    )\n{\n    uint32_t data[3] = {0};\n    uint32_t charData[8] = {0};\n\n    auto n = swscanf_s(\n        str.c_str(), \n        withBraces ? L\"{%x-%x-%x-%2x%2x-%2x%2x%2x%2x%2x%2x}\" : L\"%x-%x-%x-%2x%2x-%2x%2x%2x%2x%2x%2x\", \n        &data[0], \n        &data[1], \n        &data[2], \n        &charData[0], \n        &charData[1], \n        &charData[2], \n        &charData[3], \n        &charData[4], \n        &charData[5], \n        &charData[6], \n        &charData[7]\n        );\n    \n    guid->Data1 = data[0];\n    guid->Data2 = static_cast<uint8_t>(data[1]);\n    guid->Data3 = static_cast<uint8_t>(data[2]);\n    for(uint32_t i=0; i<8; i++ )\n    {\n        guid->Data4[i] = static_cast<uint8_t>(charData[i]);\n    }\n\n    return ( n == 11 ) ? xbl_error_code::no_error : xbl_error_code::logic_error;\n}\n#endif\n\nxsapi_internal_string utils::create_guid(_In_ bool removeBraces)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    GUID guid = {0};\n    THROW_CPP_RUNTIME_IF(FAILED(CoCreateGuid(&guid)), \"\");\n\n    WCHAR wszGuid[50];\n    THROW_CPP_RUNTIME_IF(FAILED(::StringFromGUID2(\n        guid,\n        wszGuid,\n        ARRAYSIZE(wszGuid)\n        )), \"\");\n\n    xsapi_internal_string strGuid = utils::internal_string_from_utf16(wszGuid);\n#elif !HC_PLATFORM_IS_MICROSOFT\n    xsapi_internal_string strGuid = generate_guid();\n#else\n    uuid_t uuid;\n    uuid_generate_random(uuid);\n    char s[37] = { 0 };\n    uuid_unparse(uuid, s);\n    string_t strGuid = s;\n#endif\n\n    if (removeBraces)\n    {\n        if (strGuid.length() > 3 && strGuid[0] == L'{')\n        {\n            // Remove the { } \n            strGuid.erase(0, 1);\n            strGuid.erase(strGuid.end() - 1, strGuid.end());\n        }\n    }\n\n    return strGuid;\n}\nString\nutils::format_secure_device_address(String deviceAddress)\n{\n    if (deviceAddress.empty())\n    {\n        return \"\";\n    }\n\n    // A secure device address(SDA) is a legacy concept for UWP/Xbox One.\n    // SDAs encapsulate the deviceToken which is used by MPSD to identify \n    // a session host and the connection address which is used by the title\n    // to connect to the title.\n\n    String formattedDeviceAddress = deviceAddress;\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP)\n    // SDAs that start with a 1 byte (\\001) will be parsed differently in MPSD.\n    // Since this platform does not have a valid SDA, we are adding a prefix\n    // to ensure that the SDA is handled as a non-valid SDA.\n    //\n    // MPSD will base64 decode a non-valid SDA and the hashed value will be used\n    // as the device token. The SDA can then be parsed by the title while \n    // deserializing the MPSD session to retrieve the connectionAddress.\n    formattedDeviceAddress = _sdaPrefix + deviceAddress;\n#endif\n\n    Vector<unsigned char> input(formattedDeviceAddress.c_str(), formattedDeviceAddress.c_str() + formattedDeviceAddress.size());\n    String sda = xbox::services::convert::to_base64(input);\n\n    return sda;\n}\n\nString\nutils::parse_secure_device_address(String secureDeviceAddress)\n{\n    if (secureDeviceAddress.empty())\n    {\n        return \"\";\n    }\n\n    // A secure device address(SDA) is a legacy concept for UWP/Xbox One.\n    // SDAs encapsulate the deviceToken which is used by MPSD to identify \n    // a session host and the connection address which is used by the title\n    // to connect to the title.\n\n    std::vector<unsigned char> base64ConnectionAddress(xbox::services::convert::from_base64(secureDeviceAddress.c_str()));\n    auto formattedDeviceAddress = String(base64ConnectionAddress.begin(), base64ConnectionAddress.end());\n\n    String deviceAddress = formattedDeviceAddress;\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP)\n    if (deviceAddress.find(_sdaPrefix) == 0)\n    {\n        deviceAddress = deviceAddress.substr(strlen(_sdaPrefix));\n    }\n#endif\n\n    return deviceAddress;\n}\n\nstd::vector<string_t>\nutils::string_split(\n    _In_ const string_t& string,\n    _In_ string_t::value_type seperator\n    )\n{\n    std::vector<string_t> vSubStrings;\n\n    if (!string.empty())\n    {\n        size_t posStart = 0, posFound = 0;\n        while (posFound != string_t::npos && posStart < string.length())\n        {\n            posFound = string.find(seperator, posStart);\n            if (posFound != string_t::npos)\n            {\n                if (posFound != posStart)\n                {\n                    // this substring is not empty\n                    vSubStrings.push_back(string.substr(posStart, posFound - posStart));\n                }\n                posStart = posFound + 1;\n            }\n            else\n            {\n                vSubStrings.push_back(string.substr(posStart));\n            }\n        }\n    }\n\n    return vSubStrings;\n}\n\nxsapi_internal_vector<xsapi_internal_string> utils::string_split_internal(\n    _In_ const xsapi_internal_string& string,\n    _In_ xsapi_internal_string::value_type seperator\n    )\n{\n    xsapi_internal_vector<xsapi_internal_string> vSubStrings;\n\n    if (!string.empty())\n    {\n        size_t posStart = 0, posFound = 0;\n        while (posFound != xsapi_internal_string::npos && posStart < string.length())\n        {\n            posFound = string.find(seperator, posStart);\n            if (posFound != string_t::npos)\n            {\n                if (posFound != posStart)\n                {\n                    // this substring is not empty\n                    vSubStrings.push_back(string.substr(posStart, posFound - posStart));\n                }\n                posStart = posFound + 1;\n            }\n            else\n            {\n                vSubStrings.push_back(string.substr(posStart));\n            }\n        }\n    }\n\n    return vSubStrings;\n}\n\nstring_t utils::vector_join(\n    _In_ const std::vector<string_t>& vector,\n    _In_ string_t::value_type seperator\n    )\n{\n    stringstream_t ss;\n    \n    if (!vector.empty())\n    {\n        string_t::value_type delimiter[2] = { seperator, 0 };\n        std::copy(vector.begin(), vector.end() - 1, std::ostream_iterator<string_t, string_t::value_type>(ss, delimiter));\n        ss << vector.back();\n    }\n\n    return ss.str();\n}\n\nxsapi_internal_string utils::vector_join_internal(\n    _In_ const std::vector<xsapi_internal_string>& vector,\n    _In_ xsapi_internal_string::value_type seperator\n)\n{\n    xsapi_internal_stringstream ss;\n\n    if (!vector.empty())\n    {\n        xsapi_internal_string::value_type delimiter[2] = { seperator, 0 };\n        std::copy(vector.begin(), vector.end() - 1, std::ostream_iterator<xsapi_internal_string, xsapi_internal_string::value_type>(ss, delimiter));\n        ss << vector.back();\n    }\n\n    return ss.str();\n}\n\nstring_t\nutils::replace_sub_string(\n    _In_ const string_t& source,\n    _In_ const string_t& pattern,\n    _In_ const string_t& replacement\n    )\n{\n    string_t result = source;\n    // Search the string backward for the given pattern first\n    size_t nPos = source.rfind(pattern);\n\n    while (nPos != source.npos)\n    {\n        result.replace(nPos, pattern.length(), replacement);\n\n        if (nPos == 0)\n        {\n            // There is nothing left to look at, break\n            break;\n        }\n\n        // Find the next match starting from the last replaced position\n        nPos = source.rfind(pattern, nPos - 1);\n    }\n\n    return result;\n}\n\nxsapi_internal_string_t utils::read_file_to_string(\n    _In_ const xsapi_internal_string_t& filePath\n    )\n{\n    std::ifstream in(filePath.c_str(), std::ios::in | std::ios::binary);\n    if (in)\n    {\n        std::vector<char> fileData;\n        in.seekg(0, std::ios::end);\n        uint32_t fileSizeInBytes = static_cast<uint32_t>(in.tellg());\n        if (fileSizeInBytes > 3)\n        {\n            fileData.resize(fileSizeInBytes);\n            in.seekg(0, std::ios::beg);\n            if (fileData.size() > 0)\n            {\n                in.read(&fileData[0], fileData.size());\n            }\n            in.close();\n\n            bool isUtf16LE = \n                (static_cast<unsigned char>(fileData[0]) == 0xFF &&\n                 static_cast<unsigned char>(fileData[1]) == 0xFE); // check for UTF-16 LE BOM\n\n            bool isUtf8 = \n                (static_cast<unsigned char>(fileData[0]) == 0xEF && \n                 static_cast<unsigned char>(fileData[1]) == 0xBB && \n                 static_cast<unsigned char>(fileData[2]) == 0xBF); // check for UTF-8 BOM\n\n            xsapi_internal_string_t fileDataString;\n#ifdef WIN32            \n            // Convert file data to UTF16 string\n            if (isUtf16LE)\n            {\n                uint32_t byteOrderMarkSizeInBytes = 2;\n                uint32_t strLength = (fileSizeInBytes - byteOrderMarkSizeInBytes) / sizeof(WCHAR);\n                fileDataString = xsapi_internal_string_t(reinterpret_cast<WCHAR*>(fileData.data() + byteOrderMarkSizeInBytes), strLength);\n            }\n            else\n            {\n                int byteOrderMarkSizeInBytes = (isUtf8) ? 3 : 0;\n                uint32_t strLength = fileSizeInBytes - byteOrderMarkSizeInBytes;\n                xsapi_internal_string utf8FileData = xsapi_internal_string(fileData.data() + byteOrderMarkSizeInBytes, strLength);\n                fileDataString = xbox::services::convert::utf8_to_utf16(utf8FileData);\n            }\n#else\n            // Convert file data to UTF8 string\n            if (isUtf16LE)\n            {\n                int byteOrderMarkSizeInBytes = 2;\n                uint32_t strLength = (fileSizeInBytes - byteOrderMarkSizeInBytes) / sizeof(wchar_t);\n                xsapi_internal_string_t utf16FileData = xsapi_internal_string_t(fileData.data(), strLength);\n                fileDataString = utf16FileData;\n            }\n            else\n            {\n                int byteOrderMarkSizeInBytes = (isUtf8) ? 3 : 0;\n                uint32_t strLength = fileSizeInBytes - byteOrderMarkSizeInBytes;\n                fileDataString = xsapi_internal_string(fileData.data(), strLength);\n            }\n#endif\n            return fileDataString;\n        }\n    }\n\n    return xsapi_internal_string_t();\n}\n\nint utils::interlocked_increment(volatile long& incrementNum)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    return InterlockedIncrement(&incrementNum);\n#else\n    return static_cast<uint32_t>(__sync_fetch_and_add(&incrementNum, 1));\n#endif\n}\n\nint utils::interlocked_decrement(volatile long& decrementNum)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    return InterlockedDecrement(&decrementNum);\n#else\n    return static_cast<uint32_t>(__sync_fetch_and_sub(&decrementNum, 1));\n#endif\n}\n\nstd::vector<string_t> utils::string_array_to_string_vector(\n    const char* *stringArray,\n    size_t stringArrayCount\n    )\n{\n    std::vector<xbox::services::string_t> stringVector;\n    for (size_t i = 0; i < stringArrayCount; ++i)\n    {\n        stringVector.push_back(string_t_from_utf8(stringArray[i]));\n    }\n    return stringVector;\n}\n\nxsapi_internal_vector<xsapi_internal_string> utils::string_array_to_internal_string_vector(\n    const char* *stringArray,\n    size_t stringArrayCount\n    )\n{\n    xsapi_internal_vector<xsapi_internal_string> stringVector;\n    stringVector.reserve(stringArrayCount);\n    for (size_t i = 0; i < stringArrayCount; ++i)\n    {\n        stringVector.push_back(stringArray[i]);\n    }\n    return stringVector;\n}\n\nxsapi_internal_vector<xsapi_internal_string> utils::xuid_array_to_internal_string_vector(\n    uint64_t* xuidArray,\n    size_t xuidArrayCount\n    )\n{\n    xsapi_internal_vector<xsapi_internal_string> stringVector;\n    stringVector.reserve(xuidArrayCount);\n    for (size_t i = 0; i < xuidArrayCount; ++i)\n    {\n        stringVector.push_back(utils::uint64_to_internal_string(xuidArray[i]));\n    }\n    return stringVector;\n}\n\nxsapi_internal_vector<uint32_t> utils::uint32_array_to_internal_vector(\n    uint32_t* intArray,\n    size_t intArrayCount\n    )\n{\n    xsapi_internal_vector<uint32_t> vector;\n    vector.reserve(intArrayCount);\n    for (size_t i = 0; i < intArrayCount; ++i)\n    {\n        vector.push_back(intArray[i]);\n    }\n    return vector;\n}\n\nbool utils::EnsureLessThanMaxLength(const char* str, size_t maxLength)\n{\n    size_t i = 0;\n    while (true)\n    {\n        if (i >= maxLength)\n        {\n            return false;\n        }\n        if (str[i] == '\\0')\n        {\n            return true;\n        }\n        i++;\n    }\n\n    return false;\n}\n\nString utils::ToLower(String str) noexcept\n{\n    std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c)\n        {\n            return static_cast<char>(tolower(c));\n        });\n\n    return str;\n}\n\nXAsyncBlock* utils::MakeAsyncBlock(XTaskQueueHandle queue, void* context, XAsyncCompletionRoutine* callback)\n{\n    auto async = Make<XAsyncBlock>();\n    async->queue = queue;\n    async->context = context;\n    async->callback = callback;\n    return async;\n}\n\nstatic void CALLBACK s_defaultAsyncBlockCallback(XAsyncBlock* async)\n{\n    Delete(async);\n}\n\nXAsyncBlock* utils::MakeDefaultAsyncBlock(XTaskQueueHandle queue)\n{\n    return MakeAsyncBlock(queue, nullptr, s_defaultAsyncBlockCallback);\n}\n\ntime_t utils::time_t_from_datetime(const xbox::services::datetime& datetime)\n{\n    uint64_t seconds = datetime.to_interval() / _secondTicks;\n    if (seconds >= 11644473600LL)\n    {\n        return (time_t)(seconds - 11644473600LL);\n    }\n    else\n    {\n        // If time is before epoch, 0 is returned.\n        return 0;\n    }\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\nxsapi_internal_string utils::internal_string_from_utf16(_In_z_ const wchar_t* utf16)\n{\n    return internal_string_from_char_t(utf16);\n}\n#endif\n\n#ifdef XSAPI_WRL_EVENTS_SERVICE\nMicrosoft::WRL::Wrappers::HString utils::HStringFromUtf8(_In_z_ const char* utf8)\n{\n    auto cchOutString = char_t_from_utf8(utf8, nullptr, 0);\n    xsapi_internal_wstring wstring(cchOutString - 1, '\\0');\n    char_t_from_utf8(utf8, &wstring[0], cchOutString);\n\n    Microsoft::WRL::Wrappers::HString hstring;\n    hstring.Set(wstring.data());\n    return hstring;\n}\n#endif\n\n#if __cplusplus_winrt\nPlatform::String^ utils::PlatformStringFromUtf8(_In_z_ const char* utf8)\n{\n    auto cchOutString = char_t_from_utf8(utf8, nullptr, 0);\n    xsapi_internal_wstring wstr(cchOutString - 1, '\\0');\n    char_t_from_utf8(utf8, &wstr[0], cchOutString);\n    return ref new Platform::String(wstr.data());\n}\n#endif\n\nstd::string utils::std_string_from_string_t(_In_ const string_t& stringt)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    auto cchOutString = utf8_from_char_t(stringt.data(), nullptr, 0);\n    std::string out(static_cast<size_t>(cchOutString) - 1, '\\0');\n    utf8_from_char_t(stringt.data(), &out[0], cchOutString);\n    return out;\n#else\n    return std::string(stringt.data());\n#endif\n}\n\nxsapi_internal_string utils::internal_string_from_char_t(_In_ const char_t* char_t)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    auto cchOutString = utf8_from_char_t(char_t, nullptr, 0);\n    xsapi_internal_string out(static_cast<size_t>(cchOutString) - 1, '\\0');\n    utf8_from_char_t(char_t, &out[0], cchOutString);\n    return out;\n#else\n    return xsapi_internal_string(char_t);\n#endif\n}\n\nstring_t utils::string_t_from_internal_string(_In_ const xsapi_internal_string& internalString)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    return string_t_from_utf8(internalString.data());\n#else\n    return string_t(internalString.c_str());\n#endif\n}\n\nstring_t utils::string_t_from_utf8(_In_z_ const char* utf8)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    auto cchOutString = char_t_from_utf8(utf8, nullptr, 0);\n    string_t out(static_cast<size_t>(cchOutString) - 1, '\\0');\n    char_t_from_utf8(utf8, &out[0], cchOutString);\n    return out;\n#else\n    return string_t(utf8);\n#endif\n}\n\nxsapi_internal_string utils::internal_string_from_string_t(_In_ const string_t& externalString)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    return internal_string_from_utf16(externalString.c_str());\n#else\n    return xsapi_internal_string(externalString.c_str());\n#endif\n}\n\nint utils::utf8_from_char_t(\n    _In_z_ const char_t* inArray, \n    _Out_writes_z_(cchOutArray) char* outArray,\n    _In_ int cchOutArray\n    )\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    // query for the buffer size\n    auto queryResult = WideCharToMultiByte(\n        CP_UTF8, WC_ERR_INVALID_CHARS,\n        inArray, -1,\n        nullptr, 0,\n        nullptr, nullptr\n    );\n\n    if (queryResult > cchOutArray && cchOutArray == 0)\n    {\n        return queryResult;\n    }\n    else if (queryResult == 0 || queryResult > cchOutArray)\n    {\n        throw std::exception(\"utf8_from_char_t failed\");\n    }\n\n    auto conversionResult = WideCharToMultiByte(\n        CP_UTF8, WC_ERR_INVALID_CHARS,\n        inArray, -1,\n        outArray, cchOutArray,\n        nullptr, nullptr\n    );\n    if (conversionResult == 0)\n    {\n        throw std::exception(\"utf8_from_char_t failed\");\n    }\n\n    return conversionResult;\n#else\n    int len = (int)strlen(inArray);\n    if (len < cchOutArray && outArray != nullptr)\n    {\n        strcpy(outArray, len + 1, inArray);\n    }\n    else if (cchOutArray > 0)\n    {\n        return 0;\n    }\n    return len + 1;\n#endif\n}\n\nint utils::char_t_from_utf8(\n    _In_z_ const char* inArray,\n    _Out_writes_z_(cchOutArray) char_t* outArray,\n    _In_ int cchOutArray\n    )\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    // query for the buffer size\n    auto queryResult = MultiByteToWideChar(\n        CP_UTF8, MB_ERR_INVALID_CHARS,\n        inArray, -1,\n        nullptr, 0\n    );\n\n    if (queryResult > cchOutArray && cchOutArray == 0)\n    {\n        return queryResult;\n    }\n    else if (queryResult == 0 || queryResult > cchOutArray)\n    {\n        throw std::exception(\"char_t_from_utf8 failed\");\n    }\n\n    auto conversionResult = MultiByteToWideChar(\n        CP_UTF8, MB_ERR_INVALID_CHARS,\n        inArray, -1,\n        outArray, cchOutArray\n    );\n    if (conversionResult == 0)\n    {\n        throw std::exception(\"char_t_from_utf8 failed\");\n    }\n\n    return conversionResult;\n#else\n    int len = (int)strlen(inArray);\n    if (len < cchOutArray && outArray != nullptr)\n    {\n        strcpy(outArray, len + 1, inArray);\n    }\n    else if (cchOutArray > 0)\n    {\n        return 0;\n    }\n    return len + 1;\n#endif\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/Shared/xsapi_utils.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#if HC_PLATFORM_IS_MICROSOFT\n#include <Rpc.h>\n#include <codecvt>\n#endif\n#ifdef XSAPI_WRL_EVENTS_SERVICE\n#include <wrl.h>\n#endif\n#include \"errors_legacy.h\"\n#include \"xsapi-c/pal.h\"\n\nHC_DECLARE_TRACE_AREA(XSAPI);\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n#ifndef __min\n#define __min(a,b)            (((a) < (b)) ? (a) : (b))\n#endif\n\n#ifndef __max\n#define __max(a,b)            (((a) < (b)) ? (b) : (a))\n#endif  \n\ninline bool operator<(const xbox::services::datetime& lhs, const xbox::services::datetime& rhs)\n{\n    return lhs.to_interval() < rhs.to_interval();\n}\n\n#ifndef _In_reads_bytes_\n#define _In_reads_bytes_(s)\n#endif\n\nclass utils\n{\npublic:\n    static int interlocked_increment(volatile long& incrementNum);\n    static int interlocked_decrement(volatile long& decrementNum);\n    \n    static xsapi_internal_string encode_uri(_In_ const xsapi_internal_string& data, _In_ xbox::services::uri::components::component component = xbox::services::uri::components::full_uri);\n\n    static xsapi_internal_string headers_to_string(_In_ const xsapi_internal_http_headers& headers);\n\n    static xsapi_internal_string get_query_from_params(_In_ const xsapi_internal_vector<xsapi_internal_string>& params);\n\n    static xsapi_internal_string create_guid(_In_ bool removeBraces);\n\n#if HC_PLATFORM_IS_MICROSOFT\n    static std::error_code guid_from_string(_In_ const string_t& str, _In_ GUID* guid, _In_ bool withBraces);\n#endif\n\n    static String format_secure_device_address(String deviceAddress);\n    static String parse_secure_device_address(String secureDeviceAddress);\n\n    static void append_paging_info(\n        _In_ xbox::services::uri_builder& uriBuilder,\n        _In_ unsigned int skipItems,\n        _In_ unsigned int maxItems,\n        _In_opt_ xsapi_internal_string continuationToken\n    );\n\n    static uint32_t convert_timespan_to_days(\n        _In_ uint64_t timespan\n    );\n\n    static std::time_t convert_timepoint_to_time(\n        _In_ const chrono_clock_t::time_point& time_point\n    );\n\n    static xsapi_internal_string convert_timepoint_to_string(\n        _In_ const chrono_clock_t::time_point& time_point\n    );\n\n    static inline xbox::services::datetime DatetimeFromTimeT(time_t time)\n    {\n        uint64_t result = EPOCH_OFFSET + time;\n        result *= TICKS_PER_SEC; // convert to 10e-7\n        return xbox::services::datetime() + result;\n    }\n\n    static inline time_t TimeTFromDatetime(const xbox::services::datetime& datetime)\n    {\n        uint64_t seconds = datetime.to_interval() / TICKS_PER_SEC;\n        if (seconds >= EPOCH_OFFSET)\n        {\n            return (time_t)(seconds - EPOCH_OFFSET);\n        }\n        else\n        {\n            // If time is before epoch, 0 is returned.\n            return 0;\n        }\n    }\n\n    static xsapi_internal_string escape_special_characters(const xsapi_internal_string& str);\n\n    static inline int str_icmp(const string_t &left, const string_t &right)\n    {\n        return char_t_cmp(left.c_str(), right.c_str());\n    }\n\n    static inline int str_icmp_internal(const xsapi_internal_string& left, const xsapi_internal_string& right)\n    {\n        return str_icmp(left.data(), right.data());\n    }\n\n    static inline int str_icmp(const char* left, const char* right)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _stricmp(left, right);\n#else\n        return strcasecmp(left, right);\n#endif \n    }\n\n    static inline int char_t_cmp(const char_t* left, const char_t* right)\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wcsicmp(left, right);\n#else\n        return strcasecmp(left, right);\n#endif \n    }\n\n    static std::vector<string_t> string_split(\n        _In_ const string_t& string,\n        _In_ string_t::value_type seperator\n        );\n\n    static xsapi_internal_vector<xsapi_internal_string> string_split_internal(\n        _In_ const xsapi_internal_string& string,\n        _In_ xsapi_internal_string::value_type seperator\n        );\n\n    static xbl_error_code convert_exception_to_xbox_live_error_code();\n\n    static string_t vector_join(\n        _In_ const std::vector<string_t>& vector,\n        _In_ string_t::value_type seperator\n    );\n\n    static xsapi_internal_string vector_join_internal(\n        _In_ const std::vector<xsapi_internal_string>& vector,\n        _In_ xsapi_internal_string::value_type seperator\n    );\n\n#if HC_PLATFORM_IS_MICROSOFT\n    static void convert_unix_time_to_filetime(\n        _In_ std::time_t t,\n        _In_ FILETIME* ft);\n\n    static void convert_timepoint_to_filetime(\n        _In_ const chrono_clock_t::time_point& time_point,\n        _Inout_ uint64_t& largeInt);\n#endif\n\n    static HRESULT convert_exception_to_hresult();\n    static HRESULT convert_xbox_live_error_code_to_hresult(_In_ const std::error_code& errCode);\n\n    static xsapi_internal_string convert_hresult_to_error_name(_In_ long hr);\n    static HRESULT convert_http_status_to_hresult(_In_ uint32_t httpStatusCode);\n    static xbl_error_code convert_http_status_to_xbox_live_error_code(_In_ uint32_t statusCode);\n\n#if HC_PLATFORM_IS_MICROSOFT\n    static xsapi_internal_string internal_string_from_utf16(_In_z_ const wchar_t* utf16);\n#endif\n#ifdef XSAPI_WRL_EVENTS_SERVICE\n    static Microsoft::WRL::Wrappers::HString HStringFromUtf8(_In_z_ const char* utf8);\n#endif\n#if __cplusplus_winrt\n    static Platform::String^ PlatformStringFromUtf8(_In_z_ const char* utf8);\n#endif\n\n    static std::string std_string_from_string_t(_In_ const string_t& stringt);\n    static xsapi_internal_string internal_string_from_string_t(_In_ const string_t& stringt);\n    static xsapi_internal_string internal_string_from_char_t(_In_ const char_t* char_t);\n\n    static string_t string_t_from_internal_string(_In_ const xsapi_internal_string& internalString);\n    static string_t string_t_from_utf8(_In_z_ const char* utf8);\n\n    static int utf8_from_char_t(_In_z_ const char_t* inArray, _Out_writes_z_(cchOutArray) char* outArray, _In_ int cchOutArray);\n    static int char_t_from_utf8(_In_z_ const char* inArray, _Out_writes_z_(cchOutArray) char_t* outArray, _In_ int cchOutArray);\n\n    static String generate_locales(_In_z_ const xsapi_internal_string& locale = \"\");\n    // Helper function to get locales from GlobalState. Fallback to \"en-us\" if GlobalState is not initialized\n    static String get_locales();\n\n    static string_t replace_sub_string(\n        _In_ const string_t& source,\n        _In_ const string_t& pattern,\n        _In_ const string_t& replacement\n    );\n\n    static xsapi_internal_string_t read_file_to_string(\n        _In_ const xsapi_internal_string_t& filePath\n    );\n\n    inline static uint32_t string_t_to_uint32(\n        _In_ const string_t& str\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return std::stoul(str);\n#else\n        return (uint32_t)std::strtoul(str.c_str(), nullptr, 0);\n#endif\n    }\n\n    inline static uint32_t internal_string_to_uint32(\n        _In_ const xsapi_internal_string& str\n    )\n    {\n        return (uint32_t)std::strtoul(str.c_str(), nullptr, 0);\n    }\n\n    inline static string_t uint32_to_string_t(\n        _In_ uint32_t val\n    )\n    {\n        stringstream_t stream;\n        stream << val;\n        return stream.str();\n    }\n\n    inline static xsapi_internal_string uint32_to_internal_string(\n        _In_ uint32_t val\n    )\n    {\n        xsapi_internal_stringstream stream;\n        stream << val;\n        return stream.str();\n    }\n\n    inline static xsapi_internal_string uint64_to_internal_string(\n        _In_ uint64_t val\n    )\n    {\n        xsapi_internal_stringstream stream;\n        stream << val;\n        return stream.str();\n    }\n\n    inline static uint64_t string_t_to_uint64(\n        _In_ const string_t& str\n    )\n    {\n        return uint64_from_char_t(str.data());\n    }\n\n    inline static uint64_t uint64_from_char_t(\n        _In_ const char_t* str\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wtoi64(str);\n#else\n        return strtoull(str, nullptr, 0);\n#endif\n    }\n\n    inline static uint64_t internal_string_to_uint64(\n        _In_ const xsapi_internal_string& str\n    )\n    {\n        return strtoull(str.c_str(), nullptr, 0);\n    }\n\n    inline static int32_t string_t_to_int32(\n        _In_ const string_t& str\n    )\n    {\n#if HC_PLATFORM_IS_MICROSOFT\n        return _wtoi(str.c_str());\n#else\n        return std::atoi(str.c_str());\n#endif\n    }\n\n    #define initialize_char_arr(charArr) \\\n    { \\\n        auto charArrSize = sizeof(charArr) / sizeof(*charArr); \\\n        std::fill(charArr, charArr + charArrSize, _T('\\0')); \\\n    }\n\n    #define initialize_arr(arr) \\\n    { \\\n        auto arrSize = sizeof(arr) / sizeof(*arr); \\\n        std::fill(arr, arr + arrSize, 0); \\\n    }\n    \n    inline static string_t uint64_to_string_t(\n        _In_ uint64_t num\n        )\n    {\n        stringstream_t stream;\n        stream << num;\n        auto numStr = stream.str();\n        return numStr;\n    }\n\n    static uint32_t char_t_copy(\n        _In_reads_bytes_(sizeInWords) char_t* destinationCharArr,\n        _In_ size_t sizeInWords,\n        _In_ const char_t* sourceCharArr\n        );\n        \n    static size_t strcpy(\n        _In_ char* destinationCharArr,\n        _In_ size_t sizeInWords,\n        _In_ const char* sourceCharArr\n        );\n\n    static std::vector<string_t> string_array_to_string_vector(\n        const char* *stringArray,\n        size_t stringArrayCount\n        );\n\n    static xsapi_internal_vector<xsapi_internal_string> string_array_to_internal_string_vector(\n        const char* *stringArray,\n        size_t stringArrayCount\n        );\n    \n    static xsapi_internal_vector<xsapi_internal_string> xuid_array_to_internal_string_vector(\n        uint64_t* xuidArray,\n        size_t xuidArrayCount\n        );\n\n    static xsapi_internal_vector<uint32_t> uint32_array_to_internal_vector(\n        uint32_t* intArray,\n        size_t intArrayCount\n        );\n\n    static bool EnsureLessThanMaxLength(const char* str, size_t maxLength);\n\n    // date and time constants\n    static constexpr uint64_t TICKS_PER_MS = 10000;\n    static constexpr uint64_t TICKS_PER_SEC = (1000 * TICKS_PER_MS);\n    static constexpr uint64_t EPOCH_OFFSET = 11644473600LL;\n\n    static String ToLower(String str) noexcept;\n\nprivate:\n    template<typename T>\n    struct SmartPointerContainer\n    {\n        virtual ~SmartPointerContainer() {}\n        virtual std::shared_ptr<T> GetShared() const = 0;\n    };\n\n    template<typename T>\n    struct SharedPointerContainer : public SmartPointerContainer<T>\n    {\n        SharedPointerContainer(std::shared_ptr<T> sharedPtr) : m_sharedPtr(std::move(sharedPtr)) {}\n\n        std::shared_ptr<T> GetShared() const override\n        {\n            return m_sharedPtr;\n        }\n    private:\n        std::shared_ptr<T> m_sharedPtr;\n    };\n\n    template<typename T>\n    struct WeakPointerContainer : public SmartPointerContainer<T>\n    {\n        WeakPointerContainer(std::weak_ptr<T> weakPtr) : m_weakPtr(std::move(weakPtr)) {}\n\n        std::shared_ptr<T> GetShared() const override\n        {\n            return m_weakPtr.lock();\n        }\n    private:\n        std::weak_ptr<T> m_weakPtr;\n    };\n\npublic:\n    // Returns a handle that can be used to later retrieve the stored shared_ptr.\n    // Used when an asynchronous flat-C API requires a shared_ptr as its context.\n    template<typename T>\n    static void* store_shared_ptr(std::shared_ptr<T> contextSharedPtr)\n    {\n        return Make<SharedPointerContainer<T>>(contextSharedPtr);\n    }\n\n    // Returns a handle that can be used to later retrieve the stored weak_ptr (as a shared_ptr, so\n    // it will be null if the object has since been cleaned up).\n    template<typename T>\n    static void* store_weak_ptr(std::weak_ptr<T> contextWeakPtr)\n    {\n        return Make<WeakPointerContainer<T>>(contextWeakPtr);\n    }\n\n    // Retrieves a shared previouly stored with store_shared_ptr or store_weak_ptr. If releaseContext is true\n    // the copy of the smart pointer stored internally is deleted.\n    template<typename T>\n    static std::shared_ptr<T> get_shared_ptr(void* context, bool releaseContext = true)\n    {\n        auto smartPtrContainer = reinterpret_cast<SmartPointerContainer<T>*>(context);\n        auto sharedPtr = smartPtrContainer->GetShared();\n        if (releaseContext)\n        {\n            Delete(smartPtrContainer);\n        }\n        return sharedPtr;\n    }\n\n    static time_t time_t_from_datetime(const xbox::services::datetime& datetime);\n\n    // Creates an asyncBlock that clean itself up in the completion callback\n    static XAsyncBlock* MakeDefaultAsyncBlock(XTaskQueueHandle queue);\n\n    static XAsyncBlock* MakeAsyncBlock(XTaskQueueHandle queue, void* context, XAsyncCompletionRoutine* callback);\n\nprivate:\n    static xsapi_internal_vector<xsapi_internal_string> get_locale_list();\n    \n    utils();\n    utils(const utils&);\n    utils& operator=(const utils&);\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/System/Android/local_storage_android.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"local_storage.h\"\n#include \"a/java_interop.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\nString LocalStorage::GetDefaultStoragePath()\n{\n    std::shared_ptr<java_interop> interop{ java_interop::get_java_interop_singleton() };\n\n    JNIEnv* jniEnv{ interop->GetJniEnv() };\n    jclass localStorageClass = interop->GetLocalStorageClass();\n    if (localStorageClass == nullptr)\n    {\n        LOGS_ERROR << \"Couldn't find Storage class in Jni Environment.\";\n        assert(false);\n    }\n\n    jmethodID getStoragePathMethodId = jniEnv->GetStaticMethodID(localStorageClass, \"getPath\", \"(Landroid/content/Context;)Ljava/lang/String;\");\n    jstring jStr = static_cast<jstring>(jniEnv->CallStaticObjectMethod(localStorageClass, getStoragePathMethodId, interop->get_activity()));\n    if (jStr == nullptr)\n    {\n        LOGS_ERROR << \"getStoragePath returned a null path\";\n        assert(false);\n    }\n\n    return java_interop::StringFromJString(jniEnv, jStr) + \"/\";\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/System/Win32/local_storage_win32.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"local_storage.h\"\n#include <WinBase.h>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nHRESULT LocalStorage::SetStoragePath(\n    _In_opt_z_ const char* path\n)\n{\n    // On Win32, if the default storage handlers are being used, the client must\n    // specify a base storage path. If custom storage handlers have been specified,\n    // the path will just be ignored.\n    if (m_writeHandler == DefaultWrite)\n    {\n        if (path)\n        {\n            m_path = path;\n            return S_OK;\n        }\n        else\n        {\n            return E_INVALIDARG;\n        }\n    }\n    return S_OK;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Source/System/a/java_interop.cpp",
    "content": "#include \"pch.h\"\n#include <android/log.h>\n#include \"a/http_call_static_glue.h\"\n#include \"a/xbox_live_app_config_static_glue.h\"\n#include \"TCUI/Android/title_callable_static_glue.h\"\n#include \"a/jni_utils.h\"\n#include \"a/java_interop.h\"\n#include \"TCUI/Android/title_callable_ui_jni.h\"\n\nusing namespace xbox::services::system;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nstd::shared_ptr<java_interop> java_interop::s_javaInterop;\n\nstd::shared_ptr<java_interop> java_interop::java_interop::get_java_interop_singleton()\n{\n    if (s_javaInterop != nullptr)\n    {\n        return s_javaInterop;\n    }\n    s_javaInterop = std::make_shared<java_interop>();\n    return s_javaInterop;\n}\n\njava_interop::java_interop():\n    m_javaVM(nullptr),\n    m_activity(nullptr),\n    m_marketActivityClass(nullptr),\n    m_contextObject(nullptr),\n    m_tcuiInteropClass(nullptr),\n    m_initialized(false)\n{\n\n}\n\nxbl_result<void> java_interop::initialize(JavaVM* jvm, jobject activity)\n{\n    rwlock_guard guard(java_interop_singletonLock, true);\n\n    m_javaVM = jvm;\n    m_activity = activity;\n    cpprest_init(m_javaVM);\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n\n    jclass acl = jniEnv->GetObjectClass(m_activity);\n    if (acl != NULL)\n    {\n        jmethodID getClassLoader = jniEnv->GetMethodID(acl, \"getClassLoader\", \"()Ljava/lang/ClassLoader;\");\n        if (getClassLoader != NULL)\n        {\n            jobject cls = jniEnv->CallObjectMethod(m_activity, getClassLoader);\n            if (cls != NULL)\n            {\n                jclass classLoader = jniEnv->FindClass(\"java/lang/ClassLoader\");\n                if (classLoader != NULL)\n                {\n                    jmethodID findClass = jniEnv->GetMethodID(classLoader, \"loadClass\", \"(Ljava/lang/String;)Ljava/lang/Class;\");\n                    if (findClass != NULL)\n                    {\n                        // Get a reference to the core activity for purposes of having a context: https://groups.google.com/forum/#!topic/android-ndk/SHCXgUCE7t4, http://stackoverflow.com/questions/25167806/sending-an-intent-from-c-via-jni\n                        // And be able to create an intent which will launch the activity\n                        jclass classNativeActivity = jniEnv->FindClass(\"android/app/NativeActivity\");\n                        if (classNativeActivity != NULL)\n                        {\n                            jclass contextClass = jniEnv->FindClass(\"android/content/Context\");\n                            if (contextClass != NULL)\n                            {\n                                jmethodID startActivityMethodId = jniEnv->GetMethodID(contextClass, \"startActivity\", \"(Landroid/content/Intent;)V\");\n                                if (startActivityMethodId != NULL)\n                                {\n                                    jmethodID applicationContextMethodId = jniEnv->GetMethodID(classNativeActivity, \"getApplicationContext\", \"()Landroid/content/Context;\");\n                                    if (applicationContextMethodId != NULL)\n                                    {\n                                        jobject contextObj = jniEnv->CallObjectMethod(m_activity, applicationContextMethodId);\n                                        if (contextObj != NULL)\n                                        {\n                                            m_contextObject = jniEnv->NewGlobalRef(contextObj);\n                                            if (m_contextObject != NULL)\n                                            {\n                                                jstring strClassNameActivity = jniEnv->NewStringUTF(\"com/microsoft/xbox/idp/interop/Interop\");\n                                                if (strClassNameActivity != NULL)\n                                                {\n                                                    jclass marketActivityClass = (jclass)jniEnv->CallObjectMethod(cls, findClass, strClassNameActivity);\n                                                    if (marketActivityClass != NULL)\n                                                    {\n                                                        m_marketActivityClass = (jclass)jniEnv->NewGlobalRef(marketActivityClass);\n                                                        jstring strTCUIClassNameActivity = jniEnv->NewStringUTF(\"com/microsoft/xboxtcui/Interop\");\n                                                        if (strTCUIClassNameActivity != NULL)\n                                                        {\n                                                            jclass tcuiClass = (jclass)jniEnv->CallObjectMethod(cls, findClass, strTCUIClassNameActivity);\n                                                            if (tcuiClass != NULL)\n                                                            {\n                                                                m_tcuiInteropClass = (jclass)jniEnv->NewGlobalRef(tcuiClass);\n                                                                if (m_marketActivityClass != NULL && m_tcuiInteropClass != NULL)\n                                                                {\n                                                                    jstring localStorageClassName = jniEnv->NewStringUTF(\"com/microsoft/xboxlive/LocalStorage\");\n                                                                    auto tempClass = (jclass)jniEnv->CallObjectMethod(cls, findClass, localStorageClassName);\n                                                                    assert(tempClass);\n                                                                    m_localStorageClass = (jclass)jniEnv->NewGlobalRef(tempClass);\n\n                                                                    return finish_initialization(jniEnv, cls, findClass, true);\n                                                                }\n                                                            }\n                                                        }\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    JNI_ERROR_CHECK(jniEnv)\n    return xbl_result<void>(xbl_error_code::runtime_error, \"Initialize failed\");\n}\n\n\nxbl_result<void> java_interop::initialize(JNIEnv* env, jclass clsInterop, jobject context)\n{\n    rwlock_guard guard(java_interop_singletonLock, true);\n\n    JavaVM* jvm;\n    if (env->GetJavaVM(&jvm) == 0) {\n        m_javaVM = jvm;\n        cpprest_init(m_javaVM);\n        m_contextObject = env->NewGlobalRef(context);\n        m_marketActivityClass = (jclass)env->NewGlobalRef(clsInterop);\n\n        jclass clsContext = env->GetObjectClass(m_contextObject);\n        if (clsContext != NULL)\n        {\n            jmethodID getClassLoader = env->GetMethodID(clsContext, \"getClassLoader\", \"()Ljava/lang/ClassLoader;\");\n            if (getClassLoader != NULL)\n            {\n                jobject classLoader = env->CallObjectMethod(m_contextObject, getClassLoader);\n                if (classLoader != NULL)\n                {\n                    jmethodID loadClass = env->GetMethodID(env->GetObjectClass(classLoader), \"loadClass\", \"(Ljava/lang/String;)Ljava/lang/Class;\");\n                    if (loadClass != NULL)\n                    {\n                        return finish_initialization(env, classLoader, loadClass, false);\n                    }\n                }\n            }\n        }\n    }\n    JNI_ERROR_CHECK(env)\n    return xbl_result<void>(xbl_error_code::runtime_error, \"Initialize failed\");\n}\n\njobject java_interop::app_callback_intent()\n{\n    return m_pendingIntent;\n}\n\nvoid java_interop::set_app_callback_intent(\n    jobject pendingIntent\n    )\n{\n    m_pendingIntent = pendingIntent;\n}\n\nxbl_result<void> java_interop::finish_initialization(JNIEnv* env, jobject clsLoader, jmethodID loadClass, bool useTcui)\n{\n    if (http_call_register_natives(env, clsLoader, loadClass)\n        && xbox_live_app_config_register_natives(env, clsLoader, loadClass)\n        && (!useTcui || title_callable_ui_register_natives(env, clsLoader, loadClass))\n        )\n    {\n        m_initialized = true;\n        LOG_INFO(\"java_interop initialized\");\n    }\n    else\n    {\n        LOG_ERROR(\"error registering native methods\");\n        return xbl_result<void>(xbl_error_code::runtime_error, \"Registration error\");\n    }\n\n    return xbl_result<void>(xbl_error_code::no_error);\n}\n\nvoid java_interop::deinitialize()\n{\n    rwlock_guard guard(java_interop_singletonLock, true);\n\n    if (m_javaVM == nullptr)\n    {\n        return;\n    }\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n\n    if (m_marketActivityClass != nullptr)\n    {\n        jniEnv->DeleteGlobalRef(m_marketActivityClass);\n    }\n    if (m_contextObject != nullptr)\n    {\n        jniEnv->DeleteGlobalRef(m_contextObject);\n    }\n\n    JNI_ERROR_CHECK(jniEnv)\n\n    m_initialized = false;\n    m_javaVM = nullptr;\n    m_activity = nullptr;\n    m_marketActivityClass = nullptr;\n    m_contextObject = nullptr;\n}\n\nxbl_result<void> java_interop::log_cll(const string_t& xuid, const string_t& eventName, const string_t& eventData)\n{\n    rwlock_guard guard(java_interop_singletonLock, false);\n\n    if (!m_initialized)\n    {\n        LOG_ERROR(\"java_interop not initialized\");\n        assert(false);\n        return xbl_result<void>(xbl_error_code::runtime_error, \"java_interop not initialized\");\n    }\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n\n    auto localCapacityResult = jniEnv->EnsureLocalCapacity(24); // the size of the three pointers we allocate below (assuming they are 8 bytes each)\n    if (localCapacityResult == 0)\n    {\n        jmethodID initMethodId = jniEnv->GetStaticMethodID(m_marketActivityClass, \"LogCLL\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n        if (initMethodId != NULL)\n        {\n            JNI_ERROR_CHECK(jniEnv)\n\n            jstring jxuid = jniEnv->NewStringUTF(xuid.c_str());\n            jstring jeventName = jniEnv->NewStringUTF(eventName.c_str());\n            jstring jeventData = jniEnv->NewStringUTF(eventData.c_str());\n\n            if (jniEnv->ExceptionCheck())\n            {\n                JNI_ERROR_CHECK(jniEnv)\n                jniEnv->DeleteLocalRef(jxuid);\n                jniEnv->DeleteLocalRef(jeventName);\n                jniEnv->DeleteLocalRef(jeventData);\n                LOG_ERROR(\"failure to allocated\");\n                return xbl_result<void>(xbl_error_code::runtime_error, \"failed to allocate\");\n            }\n            jniEnv->CallStaticVoidMethod(m_marketActivityClass, initMethodId, jxuid, jeventName, jeventData);\n\n            jniEnv->DeleteLocalRef(jxuid);\n            jniEnv->DeleteLocalRef(jeventName);\n            jniEnv->DeleteLocalRef(jeventData);\n\n            if (!jniEnv->ExceptionCheck())\n            {\n                return xbl_result<void>(xbl_error_code::no_error);\n            }\n        }\n    }\n\n    JNI_ERROR_CHECK(jniEnv)\n    return xbl_result<void>(xbl_error_code::runtime_error, \"cll logging failed\");\n}\n\nxbl_result<void> java_interop::log_telemetry_signin(bool silentAPI, const string_t& state)\n{\n    rwlock_guard guard(java_interop_singletonLock, false);\n\n    if (!m_initialized)\n    {\n        LOG_ERROR(\"java_interop not initialized\");\n        assert(false);\n        return xbl_result<void>(xbl_error_code::runtime_error, \"java_interop not initialized\");\n    }\n\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n\n    auto localCapacityResult = jniEnv->EnsureLocalCapacity(16); // the size of the two pointers we allocate below (assuming they are 8 bytes each)\n    if (localCapacityResult == 0)\n    {\n        jmethodID initMethodId = jniEnv->GetStaticMethodID(m_marketActivityClass, \"LogTelemetrySignIn\", \"(Ljava/lang/String;Ljava/lang/String;)V\");\n        if (initMethodId != NULL)\n        {\n            JNI_ERROR_CHECK(jniEnv)\n\n            jstring japi;\n            if (silentAPI)\n            {\n               japi = jniEnv->NewStringUTF(\"API - signin_silently - \");\n            }\n            else\n            {\n                japi = jniEnv->NewStringUTF(\"API - signin - \");\n            }\n            jstring jstate = jniEnv->NewStringUTF(state.c_str());\n            if (jniEnv->ExceptionCheck())\n            {\n                JNI_ERROR_CHECK(jniEnv)\n                jniEnv->DeleteLocalRef(japi);\n                jniEnv->DeleteLocalRef(jstate);\n                LOG_ERROR(\"failure to allocated\");\n                return xbl_result<void>(xbl_error_code::runtime_error, \"failed to allocate\");\n            }\n            jniEnv->CallStaticVoidMethod(m_marketActivityClass, initMethodId, japi, jstate);\n\n            jniEnv->DeleteLocalRef(japi);\n            jniEnv->DeleteLocalRef(jstate);\n\n            if (!jniEnv->ExceptionCheck())\n            {\n                return xbl_result<void>(xbl_error_code::no_error);\n            }\n        }\n    }\n\n    JNI_ERROR_CHECK(jniEnv)\n    return xbl_result<void>(xbl_error_code::runtime_error, \"cll logging failed\");\n}\n\nstring_t java_interop::read_config_file()\n{\n    rwlock_guard guard(java_interop_singletonLock, false);\n\n    if (!m_initialized)\n    {\n        LOG_ERROR(\"java_interop not initialized\");\n        assert(false);\n        return {};\n    }\n    string_t configText;\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n    \n    jmethodID initMethodId = jniEnv->GetStaticMethodID(m_marketActivityClass, \"ReadConfigFile\", \"(Landroid/content/Context;)Ljava/lang/String;\");\n    if (initMethodId != NULL)\n    {\n        jobject result = jniEnv->CallStaticObjectMethod(m_marketActivityClass, initMethodId, m_contextObject);\n        if (jniEnv->ExceptionCheck())\n        {\n            return configText;\n        }\n        const char* str = jniEnv->GetStringUTFChars((jstring)result, NULL);\n        configText = str;\n        jniEnv->ReleaseStringUTFChars((jstring)result, str);\n    }\n    \n    JNI_ERROR_CHECK(jniEnv)\n    return configText;\n}\n\nstring_t java_interop::get_local_storage_path()\n{\n    rwlock_guard singletonGuard(java_interop_singletonLock, false);\n\n    if (!m_initialized)\n    {\n        LOG_ERROR(\"java_interop not initialized\");\n        assert(false);\n        return {};\n    }\n    std::lock_guard<std::mutex> guard(m_localStoragePathLock);\n    if (m_localStoragePath.empty())\n    {\n        JNIEnv* jniEnv;\n        JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n\n        jmethodID initMethodId = jniEnv->GetStaticMethodID(m_marketActivityClass, \"GetLocalStoragePath\", \"(Landroid/content/Context;)Ljava/lang/String;\");\n        if (initMethodId != NULL)\n        {\n            jobject result = jniEnv->CallStaticObjectMethod(m_marketActivityClass, initMethodId, m_contextObject);\n            if (jniEnv->ExceptionCheck())\n            {\n                return m_localStoragePath;\n            }\n            const char* str = jniEnv->GetStringUTFChars((jstring)result, NULL);\n            m_localStoragePath = str;\n            jniEnv->ReleaseStringUTFChars((jstring)result, str);\n        }\n\n        JNI_ERROR_CHECK(jniEnv)\n    }\n    return m_localStoragePath;\n}\n\nJavaVM* java_interop::get_java_vm()\n{\n    return m_javaVM;\n}\n\njobject java_interop::get_activity()\n{\n    return m_activity;\n}\n\njclass java_interop::get_market_activity_class()\n{\n    return m_marketActivityClass;\n}\n\njclass java_interop::get_tcui_interop_class()\n{\n    return m_tcuiInteropClass;\n}\n\njobject java_interop::get_context_object()\n{\n    return m_contextObject;\n}\n\nvoid java_interop::register_natives(\n    JNINativeMethod nativeMethods[]\n    )\n{\n    JNIEnv* jniEnv;\n    JNI_ATTACH_THREAD(m_javaVM, jniEnv)\n    jniEnv->RegisterNatives(m_marketActivityClass, nativeMethods, 1);\n    JNI_ERROR_CHECK(jniEnv)\n}\n\nJNIEnv* java_interop::GetJniEnv() const\n{\n    JNIEnv* env{ nullptr };\n    auto result = m_javaVM->GetEnv((void**)& env, JNI_VERSION_1_6);\n\n    if (result != JNI_OK)\n    {\n        LOGS_ERROR << \"Failed to retrieve the JNIEnv from the JavaVM.\";\n        assert(false);\n    }\n\n    return env;\n}\n\nString java_interop::StringFromJString(JNIEnv* env, jstring jStr)\n{\n    assert(env);\n    assert(jStr);\n\n    const char* charPtr = env->GetStringUTFChars(jStr, nullptr);\n    String string{ charPtr };\n    env->ReleaseStringUTFChars(jStr, charPtr);\n\n    return string;\n}\n\nvoid java_interop::StoreUser(User&& user)\n{\n    std::lock_guard<std::mutex> lock{ m_storedUserMutex };\n    m_storedUser = std::make_shared<User>(std::move(user));\n}\n\nstd::shared_ptr<User> java_interop::GetStoredUser()\n{\n    std::lock_guard<std::mutex> lock{ m_storedUserMutex };\n    return m_storedUser;\n}\n\nstd::shared_ptr<User> java_interop::ExtractStoredUser()\n{\n    std::lock_guard<std::mutex> lock{ m_storedUserMutex };\n    return std::move(m_storedUser);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/System/a/java_interop.h",
    "content": "//*********************************************************\n//\n// Copyright (c) Microsoft. All rights reserved.\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n#pragma once\n#include <jni.h>\n#include \"a/rwlock_guard.h\"\n\nnamespace xbox { namespace services { \n\nclass java_interop : public std::enable_shared_from_this<java_interop>\n{\npublic:\n\n    static std::shared_ptr<java_interop> get_java_interop_singleton();\n\n    java_interop();\n\n    xbl_result<void> initialize(JavaVM* jvm, jobject activity);\n    xbl_result<void> initialize(JNIEnv* env, jclass clsInterop, jobject context);\n    void deinitialize();\n\n    xbl_result<void> log_cll(const string_t& xuid, const string_t& eventName, const string_t& eventData);\n\n    xbl_result<void> log_telemetry_signin(bool silentAPI, const string_t& state);\n\n    string_t read_config_file();\n\n    string_t get_local_storage_path();\n\n    JavaVM* get_java_vm();\n\n    jobject get_activity();\n\n    jclass get_market_activity_class();\n\n    jclass get_tcui_interop_class();\n\n    jobject get_context_object();\n\n    void register_natives(JNINativeMethod nativeMethods[]);\n\n    jobject app_callback_intent();\n\n    void set_app_callback_intent(jobject pendingIntent);\n\n    pthread_rwlock_t java_interop_singletonLock = PTHREAD_RWLOCK_INITIALIZER;\n\n    JNIEnv* GetJniEnv() const;\n\n    static String StringFromJString(JNIEnv* env, jstring jStr);\n\n    jclass GetLocalStorageClass() const { return m_localStorageClass; }\n\n    // TODO This is a temporary workaround for TCUI. XSAPI C++ TCUI API's accept a xal_user_handle, from which we extract\n    // XUID and privileges and call into Java code. Java code then calls back into XSAPI to make an HTTP call, but it does not pass and user\n    // context or xal_user_handle but it most likely should. Previously we just remembered the last signed in user, so we can \n    // emulate that behavior again for now.\n    void StoreUser(User&& user);\n    std::shared_ptr<User> GetStoredUser();\n    std::shared_ptr<User> ExtractStoredUser();\n\nprivate:\n\n    JavaVM* m_javaVM;\n    jobject m_activity;\n    jclass  m_marketActivityClass;\n    jclass m_tcuiInteropClass;\n    jobject m_contextObject;\n    jobject m_pendingIntent;\n    static std::shared_ptr<java_interop> s_javaInterop;\n    bool m_initialized;\n\n    jclass m_localStorageClass{ nullptr };\n\n    string_t m_localStoragePath;\n\n    std::mutex m_localStoragePathLock;\n\n    xbl_result<void> finish_initialization(JNIEnv* env, jobject clsLoader, jmethodID loadClass, bool useTcui);\n\n    std::shared_ptr<User> m_storedUser{ nullptr };\n    std::mutex m_storedUserMutex;\n};\n\n}}"
  },
  {
    "path": "Source/System/client_operation.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/platform_c.h\"\n\nstruct XblClientOperation\n{\npublic:\n    static HRESULT HresultFromResult(XblClientOperationResult result) noexcept\n    {\n        switch (result)\n        {\n        case XblClientOperationResult::Success:\n        {\n            return S_OK;\n        }\n        case XblClientOperationResult::Failure:\n        {\n            return E_FAIL;\n        }\n        default:\n        {\n            return S_OK;\n        }\n        }\n    }\n\n    virtual HRESULT Begin() noexcept = 0;\n    virtual HRESULT Fail(HRESULT result) noexcept = 0;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\ntemplate<typename ResultT>\nclass ClientOperation :\n    public XblClientOperation,\n    public RefCounter,\n    public std::enable_shared_from_this<ClientOperation<ResultT>>\n{\npublic:\n    using OperationLauncher = Function<void(XblClientOperationHandle)>;\n\n    ClientOperation(\n        OperationLauncher launcher,\n        AsyncContext<ResultT> async\n    ) noexcept;\n\n    ClientOperation() = delete;\n    ClientOperation(const ClientOperation&) = delete;\n    ClientOperation(ClientOperation&&) = delete;\n    ClientOperation& operator=(ClientOperation) = delete;\n\n    virtual HRESULT Begin() noexcept override;\n    virtual HRESULT Fail(HRESULT result) noexcept override;\n    virtual HRESULT Complete(ResultT args) noexcept;\n\nprivate:\n    // RefCounter\n    std::shared_ptr<RefCounter> GetSharedThis() override;\n\n    OperationLauncher m_launcher;\n    AsyncContext<ResultT> m_asyncContext;\n};\n\ntemplate<typename ResultT>\nClientOperation<ResultT>::ClientOperation(\n    OperationLauncher launcher,\n    AsyncContext<ResultT> async\n) noexcept \n    : m_launcher{ std::move(launcher) },\n    m_asyncContext{ std::move(async) }\n{\n}\n\ntemplate<typename ResultT>\nHRESULT ClientOperation<ResultT>::Begin() noexcept\n{\n    // Leak a ref until client calls Complete\n    AddRef();\n\n    // Marshall the launcher to the correct task queue\n    return m_asyncContext.Queue().RunWork([this]\n        {\n            m_launcher(this);\n        });\n}\n\ntemplate<typename ResultT>\nHRESULT ClientOperation<ResultT>::Fail(\n    HRESULT result\n) noexcept\n{\n    return Complete(ResultT{ result });\n}\n\ntemplate<typename ResultT>\nHRESULT ClientOperation<ResultT>::Complete(\n    ResultT result\n) noexcept\n{\n    // Marshall the completion to the completion port\n    return m_asyncContext.Queue().RunCompletion(\n        [\n            this,\n            result{ std::move(result) }\n        ]\n    () mutable\n    {\n        m_asyncContext.Complete(std::move(result));\n\n        // Reclaim the ref leaked in Run\n        DecRef();\n    });\n}\n\ntemplate<typename ResultT>\nstd::shared_ptr<RefCounter> ClientOperation<ResultT>::GetSharedThis()\n{\n    return this->shared_from_this();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Source/System/iOS/XBLDictionaryToJSON.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#import <Foundation/Foundation.h>\n#import \"xsapi-cpp/services.h\"\n\n@interface XBLDictionaryToJSON : NSObject \n\n- (web::json::value)jsonForObject:(id)object;\n\n@end\n"
  },
  {
    "path": "Source/System/iOS/XBLDictionaryToJSON.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#import \"XBLDictionaryToJSON.h\"\n#import \"xsapi_utils.h\"\n\nusing namespace web::http;\nusing namespace web::http::client;\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\n@implementation XBLDictionaryToJSON\n\n- (web::json::value)jsonForObject:(id)object {\n    \n    if ([object isKindOfClass:[NSString class]]) {\n        return [self jsonForString:object];\n    }\n    else if ([object isKindOfClass:[NSNumber class]]) {\n        return [self jsonForNumber:object];\n    }\n    else if ([object isKindOfClass:[NSArray class]]) {\n        return [self jsonForArray:object];\n    }\n    else if ([object isKindOfClass:[NSDictionary class]]) {\n        return [self jsonForDictionary:object];\n    }\n    else {\n        return web::json::value::null();\n    }\n}\n\n- (web::json::value)jsonForString:(NSString *)string {\n    NSString *value = (NSString *)string;\n    string_t value_t = string_t([value UTF8String]);\n    return web::json::value(value_t);\n}\n\n- (web::json::value)jsonForNumber:(NSNumber *)number {\n    if ([self numberIsBool:number]) {\n        BOOL value = [number boolValue];\n        if (value) {\n            return web::json::value(\"true\");\n        } else {\n            return web::json::value(\"false\");\n        }\n    } else if ([self numberIsInteger:number]) {\n        uint64_t value = (uint64_t)[number unsignedLongLongValue];\n        return web::json::value(value);\n    } else {\n        float value = [number floatValue];\n        return web::json::value(value);\n    }\n}\n\n- (web::json::value)jsonForDictionary:(NSDictionary *)json {\n    \n    web::json::value node;\n    \n    for (NSString *key in json) {\n        id value = json[key];\n        \n        string_t key_t = string_t([key UTF8String]);\n        auto value_t = [self jsonForObject:value];\n        \n        node[key_t] = value_t;\n    }\n    \n    return node;\n}\n\n- (web::json::value)jsonForArray:(NSArray *)json {\n    std::vector<web::json::value> array;\n    \n    for (id value in json) {\n        web::json::value jsonValue = [self jsonForObject:value];\n        array.push_back(jsonValue);\n    }\n    \n    return web::json::value::array(array);\n}\n\n- (BOOL)numberIsBool:(NSNumber *)number {\n    \n    NSNumber *trueNumber = [NSNumber numberWithBool:YES];\n    NSString *trueString = [NSString stringWithUTF8String:[trueNumber objCType]];\n    \n    NSNumber *falseNumber = [NSNumber numberWithBool:NO];\n    NSString *falseString = [NSString stringWithUTF8String:[falseNumber objCType]];\n    \n    NSString *objCType = [NSString stringWithUTF8String:[number objCType]];\n    \n    if (([trueNumber compare:number] == NSOrderedSame && [objCType isEqualToString:trueString])\n        || ([falseNumber compare:number] == NSOrderedSame && [objCType isEqualToString:falseString])) {\n        return YES;\n    }\n    \n    return NO;\n}\n\n- (BOOL)numberIsInteger:(NSNumber *)number {\n    if(CFNumberIsFloatType((CFNumberRef)number))\n    {\n        return NO;\n    }\n    else\n    {\n        return YES;\n    }\n}\n\n@end\n"
  },
  {
    "path": "Source/System/iOS/XBLKeychainStorage.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/** The default access group Xbox Live Services uses for shared data. */\nextern NSString *const _Nonnull XBLKeychainStorageSharedAccessGroup;\n\n/** Interface for accessing the keychain on iOS. */\n@interface XBLKeychainStorage : NSObject\n\n/** Gets the access group this storage object is pointing to. */\n@property (readonly, nonatomic, nonnull) NSString *accessGroup;\n\n/** Gets and sets the label to use to filter read items and to use to mark written items with. Use nil to indicate read\n all items and to write no label. */\n@property (copy, nonatomic, nullable) NSString *itemLabel;\n\n/**\n *  Do not use. Please use one of the other initializers.\n */\n- (instancetype _Nonnull)init NS_UNAVAILABLE;\n\n/**\n Initializes the keychain storage object to put items into the default access group of the current running app.\n */\n- (instancetype _Nonnull)initWithDefaultAccessGroup;\n\n/**\n Initializes the keychain storage object with a given access group. The identifier prefix is prepended\n automatically.\n \n @param accessGroup The access group to use for this keychain storage object or nil to not specify one and allow the\n keychain service to use its default behavior.\n */\n- (instancetype _Nonnull)initWithAccessGroup:(NSString * _Nullable)accessGroup;\n\n/**\n Initializes the keychain storage with a specific label.\n \n @param label Value to be set for kSecAttrLabel to make it easy to query for items in keychain.\n */\n- (instancetype _Nonnull)initWithDefaultAccessGroupAndLabel:(NSString * _Nullable)label;\n\n/**\n Initializes the keychain storage with a given access group and label.\n \n @param accessGroup The access group to use for this keychain storage object or nil to not specify one and allow the\n keychain service to use its default behavior.\n @param label Value to be set for kSecAttrLabel to make it easy to query for items in keychain.\n */\n- (instancetype _Nonnull)initWithAccessGroup:(NSString * _Nullable)accessGroup\n                                       label:(NSString * _Nullable)label;\n\n/**\n Adds or updates an item to the keychain under the specified key. If an item does not already exist at the key\n one will be added. If an item does already exist at the key, it will be updated. Returns YES if the operation succeeds\n and NO with a corresponding error if it does not.\n \n @param key The key to store the item under.\n @param item Archivable item to save.\n @param error optional: The error pointer to assign upon error or nil if not wanted.\n @return YES if the operation succeeds and NO with an accompanying error if it does not.\n */\n- (BOOL)addOrUpdateItemForKey:(NSString * _Nonnull)key\n                         item:(id _Nonnull)item\n                        error:(out NSError * _Nullable __autoreleasing * _Nullable)error;\n\n/**\n Retrieves the attributes for the item with the given key. If the item is missing, the out parameter is set to\n nil and YES is returned.\n \n @param key The key to query the attributes for.\n @param attributes The out param to which a new dictionary will be assigned.\n @param error optional: The error pointer to assign upon error or nil if not wanted.\n @return YES if the operation succeeds and NO with an accompanying error if it does not.\n */\n- (BOOL)getAttributesForKey:(NSString * _Nonnull)key\n                 attributes:(out NSDictionary * _Nullable __autoreleasing * _Nonnull)attributes\n                      error:(out NSError * _Nullable __autoreleasing * _Nullable)error;\n\n/**\n Reads and unarchives the data at the specified key. Returns YES if the operation succeeds and NO with a\n corresponding error if it does not. If the item is missing, the out parameter is set to nil and YES is returned.\n \n @param key The key to read the item under.\n @param item The id to assign upon unarchiving.\n @param error optional: The error pointer to assign upon error or nil if not wanted.\n @return YES if the operation succeeds and NO with an accompanying error if it does not.\n */\n- (BOOL)readItemForKey:(NSString * _Nonnull)key\n                  item:(out id _Nullable __autoreleasing * _Nonnull)item\n                 error:(out NSError * _Nullable __autoreleasing * _Nullable)error;\n\n/**\n Deletes the item at the specified index if it exists.\n \n @param key The key of the item to delete.\n @param error optional: The error pointer to assign upon error or nil if not wanted.\n @return YES if the operation succeeds and NO with an accompanying error if it does not.\n */\n- (BOOL)deleteItemForKey:(NSString * _Nonnull)key\n                   error:(out NSError * _Nullable __autoreleasing * _Nullable)error;\n\n/**\n Reads and unarchives the data for the current access group and label combination. Returns YES if the operation\n succeeds and NO with a corresponding error if it does not. If there are no items in the access group, the out parameter\n NSArray is set to empty array and YES is returned.\n \n @param items An array of items in the access group.\n @param error optional: The error pointer to assign upon error or nil if not wanted.\n @return YES if the operation succeeds and NO with an accompanying error if it does not.\n */\n- (BOOL)readAllItemsForAccessGroup:(out NSArray<id> * _Nullable __autoreleasing * _Nonnull)items\n                             error:(out NSError * _Nullable __autoreleasing * _Nullable)error;\n\n/**\n Reads all the keys in the current access group and label combination. Returns YES on success and NO with an\n error object if the operation fails. If no keys are found, an empty array is returned.\n \n @param keys An array of existing keys.\n @param error optional: The error pointer to assign upon error or nil if not wanted.\n @return YES if the operation succeeds and NO with an accompanying error if it does not.\n */\n- (BOOL)getAllKeys:(out NSArray<NSString *> * _Nullable __autoreleasing * _Nonnull)keys\n             error:(out NSError * _Nullable __autoreleasing * _Nullable)error;\n\n@end\n"
  },
  {
    "path": "Source/System/iOS/XBLKeychainStorage.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#import \"XBLKeychainStorage.h\"\n#import \"XBLServiceManager.h\"\n\nNSString *const _Nonnull XBLKeychainStorageSharedAccessGroup = @\"com.microsoft.xboxliveservices\";\n\n/** The service name to use for items stored in the keychain by Xbox Live Services. */\nstatic NSString *const XBLKeychainStorageServiceName = @\"com.microsoft.xboxliveservices\";\n\n/** The application identifier prefix for the current running app. Note: this should only be accessed via\n getApplicationPrefix. */\nstatic NSString *XBLKeychainStorageApplicationIdentifierPrefix = nil;\n\n@implementation XBLKeychainStorage\n\n- (instancetype _Nonnull)initWithDefaultAccessGroup {\n    return [self initWithAccessGroup:nil label:nil];\n}\n\n- (instancetype _Nonnull)initWithAccessGroup:(NSString * _Nullable)accessGroup; {\n    return [self initWithAccessGroup:accessGroup label:nil];\n}\n\n- (instancetype _Nonnull)initWithDefaultAccessGroupAndLabel:(NSString * _Nullable)label {\n   return [self initWithAccessGroup:nil label:label];\n}\n\n- (instancetype _Nonnull)initWithAccessGroup:(NSString * _Nullable)accessGroup\n                                       label:(NSString * _Nullable)label {\n    self = [super init];\n    if (self != nil) {\n        if (accessGroup != nil) {\n            _accessGroup = [NSString stringWithFormat:@\"%@.%@\", [XBLKeychainStorage getApplicationPrefix], accessGroup];\n        }\n        \n        _itemLabel = [label copy];\n    }\n    \n    return self;\n}\n\n/**\n Retrieves the application identifier prefix for use with accessing keychain groups.\n */\n+ (NSString * _Nonnull)getApplicationPrefix {\n    if (XBLKeychainStorageApplicationIdentifierPrefix == nil) {\n        // We have to call this method to get the prefix initialized as well.\n        [XBLKeychainStorage getApplicationAccessGroup];\n        \n        LOG_DEBUG(([[NSString stringWithFormat:@\"Application bundle prefix detected: %@\",\n                     XBLKeychainStorageApplicationIdentifierPrefix] UTF8String]));\n    }\n    \n    return XBLKeychainStorageApplicationIdentifierPrefix;\n}\n\n/**\n Retrieves the application's default access group. In the case of a simulator runtime, this might return an empty\n string.\n \n @return The application's default access group specified in the application's entitlements file.\n */\n+ (NSString * _Nonnull)getApplicationAccessGroup {\n    static NSString *keychainStorageApplicationAccessGroup = nil;\n    \n    // Perform the detection inside of a dispatch_once block. We don't expect any failures but there's no reason to kill\n    // the app if one step fails.\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        // Add a unique item to the keychain. The item will be added with the app's default access group.\n        XBLKeychainStorage *keychain = [[XBLKeychainStorage alloc] initWithAccessGroup:nil];\n        \n        NSString *uniqueKey = [NSString stringWithFormat:@\"AccessGroupDetection-%@\",\n                               [[NSUUID UUID] UUIDString]];\n        \n        NSError *error = nil;\n        if (![keychain addOrUpdateItemForKey:uniqueKey item:uniqueKey error:&error]) {\n            NSAssert(NO,\n                     @\"Error when adding new unique item %@ to the keychain: %@\",\n                     uniqueKey,\n                     error);\n            \n            return;\n        }\n        \n        NSString *applicationAccessGroup = nil;\n        // Retrieve the unique item's access group.\n        if (![keychain retrieveItemAccessGroupForKey:uniqueKey\n                                         accessGroup:&applicationAccessGroup\n                                               error:&error]) {\n            NSAssert(NO,\n                     @\"Error when reading the default access group: %@\",\n                     error);\n            \n            return;\n        }\n        \n        // For signed apps this will come back as the first entry in the entitlements file or in an\n        // unsigned build it should come back simply as @\"test\".\n        NSAssert([applicationAccessGroup length] > 0,\n                 @\"Default access group came back as empty: %@\",\n                 applicationAccessGroup);\n        \n        NSArray *components = [applicationAccessGroup componentsSeparatedByString:@\".\"];\n        XBLKeychainStorageApplicationIdentifierPrefix = [[components objectEnumerator] nextObject];\n        \n        keychainStorageApplicationAccessGroup = [applicationAccessGroup substringFromIndex:\n                                                 XBLKeychainStorageApplicationIdentifierPrefix.length];\n        if ([keychainStorageApplicationAccessGroup hasPrefix:@\".\"]) {\n            // Remove the first '.' from the default group name\n            keychainStorageApplicationAccessGroup = [keychainStorageApplicationAccessGroup\n                                                     substringFromIndex:1];\n        }\n        \n        // Delete the unique item.\n        if (![keychain deleteItemForKey:uniqueKey error:&error]) {\n            NSAssert(NO,\n                     @\"Error when deleting unique item %@ from the keychain: %@\",\n                     uniqueKey,\n                     error);\n            \n            return;\n        }\n        \n        LOG_DEBUG(([[NSString stringWithFormat:@\"Default app access group detected: %@\",\n                     keychainStorageApplicationAccessGroup] UTF8String]));\n    });\n    \n    return keychainStorageApplicationAccessGroup;\n}\n\n/**\n Reads the access group for the specified key. YES with a nil access group is returned if the item cannot be\n found.\n \n @param key The key of the item to examine.\n @param accessGroup The out parameter the access group is returned through.\n @param error optional: The error object describing the failure that occurred if one occurred.\n @return YES if the call succeeds. Otherwise NO is returned along with a populated error object.\n */\n- (BOOL)retrieveItemAccessGroupForKey:(NSString * _Nonnull)key\n                          accessGroup:(out NSString * _Nullable __autoreleasing * _Nonnull)accessGroup\n                                error:(out NSError * _Nullable __autoreleasing * _Nullable)error {\n    NSAssert(accessGroup != nil, @\"Out parameter must be non-nil.\");\n    \n    // Build the query to search for the requested item.\n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:key];\n    query[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;\n    \n    // Search for it.\n    CFDictionaryRef cfAttributes = NULL;\n    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&cfAttributes);\n    if (status == errSecSuccess) {\n        NSDictionary *attributes = (__bridge_transfer NSDictionary *)cfAttributes;\n        *accessGroup = attributes[(__bridge id)kSecAttrAccessGroup];\n        \n        NSAssert([*accessGroup length] > 0, @\"The access group should be non-empty: %@\", *accessGroup);\n        if ([*accessGroup length] == 0) {\n            // For compiled versions of the library we ship, make sure that if this is running in an environment where\n            // access groups are empty, we should still behave nicely\n            *accessGroup = nil;\n        }\n    } else if (status == errSecItemNotFound) {\n        // Item not found. Set return to nil and still call this a success.\n        *accessGroup = nil;\n    } else {\n        NSAssert(NO, @\"Error loading keychain item: %d\", (int)status);\n        \n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@\"Error occurred while loading keychain item \\\"%@\\\" for retrieving access group.\",\n                                                                            key]}];\n        }\n        \n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)addOrUpdateItemForKey:(NSString * _Nonnull)key\n                         item:(id _Nonnull)item\n                        error:(out NSError * _Nullable __autoreleasing * _Nullable)error {\n    NSAssert(item != nil, @\"Trying to write a nil item to keychain. This probably isn't intended. key: %@\", key);\n    \n    // First find out if the item already exists\n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:key];\n    \n    // For the initial query we don't want to use a label because the caller is asking to update the item. This should\n    // be performed even if an existing item with a different label exists. If the item does exist, the label will be\n    // added as part of the update dictionary. If the item does not exist, the query dictionary will be replaced\n    // entirely.\n    [query removeObjectForKey:(__bridge id)kSecAttrLabel];\n    \n    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);\n    if (status == errSecSuccess) {\n        LOG_DEBUG(([[NSString stringWithFormat:@\"Updating existing item in keychain: %@\", key] UTF8String]));\n        \n        // The item exists, perform an update\n        NSMutableDictionary *update = [self dictionaryForKeychainAddOrUpdate:key];\n        \n        // Set the data on the update\n        update[(__bridge id)kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:item];\n        \n        // The class key must be removed from the update because... dragons?\n        [update removeObjectForKey:(__bridge id)kSecClass];\n        \n        status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);\n        \n        if (status == errSecItemNotFound) {\n            // If we get errSecItemNotFound, assume the item was deleted by another thread and allow the deleter to win\n            // the last-write-wins game.\n            LOG_WARN(\"Item we were trying to update no longer exists.\");\n        } else if (status != errSecSuccess) {\n            if (error != nil) {\n                *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                             code:status\n                                         userInfo:@{NSLocalizedDescriptionKey: @\"Error occurred while updating keychain item.\"}];\n            }\n            \n            return NO;\n        }\n    } else if (status == errSecItemNotFound) {\n        LOG_DEBUG(([[NSString stringWithFormat:@\"Adding new item in keychain: %@\", key] UTF8String]));\n        \n        // The item does not exist, perform an add\n        query = [self dictionaryForKeychainAddOrUpdate:key];\n        \n        query[(__bridge id)kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:item];\n        status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);\n        \n        if (status == errSecDuplicateItem) {\n            // If we get errSecDuplicateItem assume the item was added by another thread and allow them to win the\n            // last-write-wins game.\n            LOG_WARN(\"Item we were trying to add is now a duplicate.\");\n        } else if (status != errSecSuccess) {\n            if (error != nil) {\n                *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                             code:status\n                                         userInfo:@{NSLocalizedDescriptionKey: @\"Error occurred while trying to add keychain item.\"}];\n            }\n            \n            return NO;\n        }\n    } else {\n        // Unexpected error\n        \n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@\"Error occurred while checking the status of a keychain item \\\"%@\\\".\",\n                                                                            key]}];\n        }\n        \n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)getAttributesForKey:(NSString * _Nonnull)key\n                 attributes:(out NSDictionary * _Nullable __autoreleasing * _Nonnull)attributes\n                      error:(out NSError * _Nullable __autoreleasing * _Nullable)error {\n    NSAssert(key.length > 0, @\"key must be non-empty.\");\n    NSAssert(attributes != nil, @\"Out param must be non-nil.\");\n    \n    BOOL success = YES;\n    CFArrayRef itemAttributes = NULL;\n    \n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:key];\n    query[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;\n    query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;\n    \n    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&itemAttributes);\n    if (status == errSecSuccess) {\n        NSAssert(itemAttributes != NULL, @\"Attributes expected to be non-nil on success.\");\n        \n        *attributes = (__bridge_transfer NSDictionary*)itemAttributes;\n    } else if (status == errSecItemNotFound) {\n        *attributes = nil;\n    } else {\n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@\"Error occurred while reading attributes for item \\\"%@\\\" from keychain.\",\n                                                                            key]}];\n        }\n        \n        success = NO;\n    }\n    \n    return success;\n}\n\n- (BOOL)readItemForKey:(NSString * _Nonnull)key\n                  item:(out id _Nullable __autoreleasing * _Nonnull)item\n                 error:(out NSError * _Nullable __autoreleasing * _Nullable)error {\n    NSAssert(item != nil, @\"Out param must be non-nil.\");\n    \n    BOOL success = YES;\n    CFDataRef itemData = NULL;\n    \n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:key];\n    query[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;\n    query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;\n    \n    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&itemData);\n    if (status == errSecSuccess) {\n        NSAssert(itemData != NULL, @\"Data expected to be non-nil on success.\");\n        \n        *item = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)itemData];\n    } else if (status == errSecItemNotFound) {\n        *item = nil;\n    } else {\n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@\"Error occurred while reading item \\\"%@\\\" from keychain.\",\n                                                                            key]}];\n        }\n        \n        // Don't return right away so that we make sure to clean up itemData.\n        // In theory there should be nothing to clean up if an error occurred but this is safer.\n        success = NO;\n    }\n    \n    if (itemData != NULL) {\n        CFRelease(itemData);\n    }\n    \n    return success;\n}\n\n- (BOOL)deleteItemForKey:(NSString * _Nonnull)key\n                   error:(out NSError * _Nullable __autoreleasing * _Nullable)error {\n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:key];\n    OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);\n    if (status != errSecSuccess && status != errSecItemNotFound) {\n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@\"Error occurred while deleting item \\\"%@\\\" from keychain.\",\n                                                                            key]}];\n        }\n        \n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)readAllItemsForAccessGroup:(out NSArray<id> * _Nullable __autoreleasing * _Nonnull)items\n                             error:(out NSError * _Nullable __autoreleasing * _Nullable)error {\n    NSAssert(items != nil, @\"Out param must be non-nil.\");\n             \n    BOOL success = YES;\n    CFArrayRef itemData = NULL;\n    \n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:nil];\n    query[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;\n    query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;\n    \n    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&itemData);\n    \n    if (status == errSecSuccess) {\n        NSAssert(itemData != NULL, @\"Data expected to be non-nil on success.\");\n        \n        NSArray *itemArray = (__bridge_transfer NSArray *)itemData;\n        \n        NSMutableArray<id> *valueData = [[NSMutableArray alloc] initWithCapacity:itemArray.count];\n        \n        for (NSData *item in itemArray) {\n            id decodedItem = [NSKeyedUnarchiver unarchiveObjectWithData:item];\n            \n            // For unknown reasons, it's possible for the item to come out as nil\n            if (decodedItem != nil) {\n                [valueData addObject:decodedItem];\n            } else {\n                LOG_ERROR(([[NSString stringWithFormat:@\"Decoded value from keychain resulted in nil: %@\",\n                             (item == nil) ? @\"nil\" : @\"non-nil\"] UTF8String]));\n                NSAssert(NO, @\"A keychain item is either nil or could not be unarchived.\");\n            }\n        }\n        \n        *items = [valueData copy];\n    } else if (status == errSecItemNotFound) {\n        *items = [NSArray array];\n    } else {\n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: @\"Error occurred while reading items from keychain.\"}];\n        }\n        \n        success = NO;\n    }\n    \n    return success;\n}\n\n- (BOOL)getAllKeys:(out NSArray<NSString *> * _Nullable __autoreleasing * _Nonnull)keys\n             error:(out NSError * __autoreleasing * _Nullable)error {\n    NSAssert(keys != nil, @\"Out param must be non-nil.\");\n    \n    BOOL success = YES;\n    CFArrayRef itemAttributes = NULL;\n    \n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:nil];\n    query[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;\n    query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;\n    \n    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&itemAttributes);\n    \n    if (status == errSecSuccess) {\n        NSAssert(itemAttributes != NULL, @\"Attributes expected to be non-nil on success.\");\n        \n        NSArray *attributesArray = (__bridge_transfer NSArray *)itemAttributes;\n        \n        NSMutableArray<NSString *> *mutableKeyList = [[NSMutableArray alloc] initWithCapacity:attributesArray.count];\n        \n        for (NSDictionary *attributes in attributesArray) {\n            NSString *key = attributes[(__bridge id)kSecAttrAccount];\n            if (key.length > 0) {\n                [mutableKeyList addObject:[key copy]];\n            }\n        }\n        \n        *keys = [mutableKeyList copy];\n    } else if (status == errSecItemNotFound) {\n        *keys = [NSArray array];\n    } else {\n        if (error != nil) {\n            *error = [NSError errorWithDomain:kXboxLiveServicesDomain\n                                         code:status\n                                     userInfo:@{NSLocalizedDescriptionKey: @\"Error occurred while reading attributes from keychain.\"}];\n        }\n        \n        success = NO;\n    }\n    \n    return success;\n}\n\n/**\n Creates a keychain query for writing or updating the given key.\n \n @param key The key to taget the query to.\n @return A keychain query dictionary.\n */\n- (NSMutableDictionary * _Nonnull)dictionaryForKeychainAddOrUpdate:(NSString * _Nonnull)key {\n    NSMutableDictionary *query = [self dictionaryForKeychainQuery:key];\n\n    query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock;\n    query[(__bridge id)kSecAttrIsInvisible] = (__bridge id)kCFBooleanTrue;\n    \n    return query;\n}\n\n/**\n Creates a keychain query for reading or deleting the given key.\n \n @param key The key to target the query to.\n @return A keychain query dictionary.\n */\n- (NSMutableDictionary * _Nonnull)dictionaryForKeychainQuery:(NSString * _Nonnull)key {\n    NSMutableDictionary *query = [NSMutableDictionary dictionary];\n    \n    query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;\n    query[(__bridge id)kSecAttrService] = XBLKeychainStorageServiceName;\n    query[(__bridge id)kSecAttrAccount] = key;\n    \n    if (_itemLabel != nil) {\n        query[(__bridge id)kSecAttrLabel] = _itemLabel;\n    }\n    \n    if (_accessGroup != nil) {\n        query[(__bridge id)kSecAttrAccessGroup] = _accessGroup;\n    }\n    \n    return query;\n}\n\n@end\n"
  },
  {
    "path": "Source/System/iOS/XBLiOSGlobalState.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n@interface XBLiOSGlobalState : NSObject\n\n/**\n Set the launch view controller to be used by XSAPI. This is held by a weak pointer and is not thread safe to set this.\n Typically you only need to set this once. If this is nil when XSAPI UI is launched, the application root view controller\n will be used\n \n @param viewController The view controller or nil to launch XSAPI from. Default is application root view controller\n */\n+ (void)setLaunchViewController:(UIViewController * _Nullable)viewController;\n\n/**\n Returns the launch view controller used by XSAPI to launch UI from. This is either the view controller set previously\n in the +setLaunchViewController method or the root view controller of the application\n \n @return The launch view controller used by XSAPI\n */\n+ (UIViewController * _Nullable)launchViewController;\n@end\n"
  },
  {
    "path": "Source/System/iOS/XBLiOSGlobalState.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#import \"XBLiOSGlobalState.h\"\n\n__weak static UIViewController *gLaunchViewController;\n\n@implementation XBLiOSGlobalState\n\n+ (void)setLaunchViewController:(UIViewController *)viewController {\n    gLaunchViewController = viewController;\n}\n\n+ (UIViewController *)launchViewController {\n    return nullptr;\n    // TODO 1808 return gLaunchViewController ?: [XBLIDPScenario getTopViewController];\n}\n\n@end\n"
  },
  {
    "path": "Source/System/iOS/local_storage_ios.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"local_storage.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nString LocalStorage::GetDefaultStoragePath()\n{\n    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);\n    NSString* applicationSupportDirectory = [paths firstObject];\n    if (applicationSupportDirectory.length == 0)\n    {\n        LOGS_DEBUG << \"Failed to find application support directory.\";\n        assert(false);\n    }\n\n    NSString* storagePath = [NSString stringWithFormat:@\"%@/\", applicationSupportDirectory];\n\n    NSError* createDirectoryError = nil;\n    [[NSFileManager defaultManager] createDirectoryAtPath:storagePath\n                              withIntermediateDirectories:YES\n                                               attributes:nil\n                                                    error:&createDirectoryError];\n    if (createDirectoryError != nil)\n    {\n        LOGS_DEBUG << \"Failed to create application support directory: \" << createDirectoryError.localizedDescription.UTF8String;\n        \n        assert(false);\n    }\n\n    return storagePath.UTF8String;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/System/iOS/xbox_live_app_config_ios.mm",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"xsapi-cpp/system.h\"\n#include \"xbox_live_app_config_internal.h\"\n#import \"XBLiOSGlobalState.h\"\n#include <rapidjson/allocators.hpp>\n#include \"uri_impl.h\"\t\n\nusing namespace xbox::services;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nconst xsapi_internal_string& AppConfig::APNSEnvironment() const\n{\n    return m_apnsEnvironment;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n"
  },
  {
    "path": "Source/System/local_storage.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"local_storage.h\"\n#include <iostream>\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nXblLocalStorageWriteHandler g_localStorageWriteHandler{ nullptr };\nXblLocalStorageReadHandler g_localStorageReadHandler{ nullptr };\nXblLocalStorageClearHandler g_localStorageClearHandler{ nullptr };\nXTaskQueueHandle g_localStorageTaskQueue{ nullptr };\nvoid* g_localStorageClientContext{ nullptr };\n\nLocalStorage::LocalStorage(\n    const TaskQueue& queue\n) :\n    m_writeHandler{ g_localStorageWriteHandler },\n    m_readHandler{ g_localStorageReadHandler },\n    m_clearHandler{ g_localStorageClearHandler },\n    m_context{ g_localStorageClientContext }\n{\n    // If the storage hooks were not configured, fall back to defaults\n    if (!m_writeHandler || !m_readHandler || !m_clearHandler)\n    {\n        m_writeHandler = DefaultWrite;\n        m_readHandler = DefaultRead;\n        m_clearHandler = DefaultClear;\n        m_context = this;\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\n        m_path = GetDefaultStoragePath();\n#endif\n    }\n\n    // If title configured a queue for local storage, use that. Otherwise use provided queue\n    if (g_localStorageTaskQueue)\n    {\n        m_queue = TaskQueue::DeriveWorkerQueue(g_localStorageTaskQueue);\n    }\n    else\n    {\n        m_queue = queue.DeriveWorkerQueue();\n    }\n}\n\nHRESULT LocalStorage::WriteAsync(\n    const User& user,\n    XblLocalStorageWriteMode mode,\n    String key,\n    Vector<uint8_t> data,\n    Callback<Result<size_t>> callback\n) noexcept\n{\n    auto copyUserResult{ user.Copy() };\n    RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n\n    WriteOperation::OperationLauncher launcher{\n        [\n            sharedThis{ shared_from_this() },\n            user = MakeShared<User>(copyUserResult.ExtractPayload()),\n            mode,\n            key{ std::move(key) },\n            data{ std::move(data) }\n        ]\n    (XblClientOperationHandle op)\n    {\n        sharedThis->m_writeHandler(\n            sharedThis->m_context,\n            op,\n            user->Handle(),\n            mode,\n            key.data(),\n            data.size(),\n            data.data()\n        );\n    }};\n\n    auto op = MakeShared<WriteOperation>(\n        std::move(launcher),\n        AsyncContext<Result<size_t>>{ m_queue,\n        [\n            sharedThis{ shared_from_this() },\n            callback{ std::move(callback) }\n        ]\n    (Result<size_t> result)\n    {\n        sharedThis->OperationComplete();\n        callback(std::move(result));\n    }\n    });\n\n    QueueOperation(op);\n\n    return S_OK;\n}\n\nHRESULT LocalStorage::ReadAsync(\n    const User& user,\n    String key,\n    Callback<Result<Vector<uint8_t>>> callback\n) noexcept\n{\n    auto copyUserResult{ user.Copy() };\n    RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n\n    ReadOperation::OperationLauncher launcher{\n        [\n            sharedThis{ shared_from_this() },\n            user = MakeShared<User>(copyUserResult.ExtractPayload()),\n            key{ std::move(key) }\n        ]\n    (XblClientOperationHandle op)\n    {\n        sharedThis->m_readHandler(sharedThis->m_context, op, user->Handle(), key.data());\n    }};\n\n    auto op = MakeShared<ReadOperation>(\n        std::move(launcher),\n        AsyncContext<Result<Vector<uint8_t>>>{ m_queue,\n        [\n            sharedThis{ shared_from_this() },\n            callback{ std::move(callback) }\n        ]\n    (Result<Vector<uint8_t>> result)\n    {\n        sharedThis->OperationComplete();\n        callback(std::move(result));\n    }\n    });\n\n    QueueOperation(op);\n\n    return S_OK;\n}\n\nHRESULT LocalStorage::ClearAsync(\n    const User& user,\n    String key,\n    Callback<HRESULT> callback\n) noexcept\n{\n    auto copyUserResult{ user.Copy() };\n    RETURN_HR_IF_FAILED(copyUserResult.Hresult());\n\n    ClearOperation::OperationLauncher launcher {\n        [\n            sharedThis{ shared_from_this() },\n            user = MakeShared<User>(copyUserResult.ExtractPayload()),\n            key{ std::move(key) }\n        ]\n    (XblClientOperationHandle op)\n    {\n        sharedThis->m_clearHandler(sharedThis->m_context, op, user->Handle(), key.data());\n    }};\n\n    auto op = MakeShared<ClearOperation>(\n        std::move(launcher),\n        AsyncContext<HRESULT>{ m_queue,\n        [\n            sharedThis{ shared_from_this() },\n            callback{ std::move(callback) }\n        ]\n    (HRESULT result)\n    {\n        sharedThis->OperationComplete();\n        callback(result);\n    }\n    });\n\n    QueueOperation(op);\n\n    return S_OK;\n}\n\nvoid LocalStorage::QueueOperation(\n    std::shared_ptr<XblClientOperation> op\n) noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_operationQueue.push(op);\n    RunNextOperation();\n}\n\nvoid LocalStorage::RunNextOperation() noexcept\n{\n    // m_mutex must be held when calling this function\n    if (!m_currentOperation && !m_operationQueue.empty())\n    {\n        m_currentOperation = m_operationQueue.front();\n        m_operationQueue.pop();\n\n        // Because operations aren't even kicked off synchronously, always raise errors through the\n        // AsyncContext. If begin succeeds, client will complete operation later and the operation will\n        // manage its own lifetime.\n        HRESULT hr = m_currentOperation->Begin();\n        if (FAILED(hr))\n        {\n            m_currentOperation->Fail(hr);\n        }\n    }\n}\n\nvoid LocalStorage::OperationComplete() noexcept\n{\n    std::lock_guard<std::mutex> lock{ m_mutex };\n    m_currentOperation = nullptr;\n    RunNextOperation();\n}\n\nvoid LocalStorage::DefaultWrite(\n    _In_opt_ void* context,\n    _In_ XblClientOperationHandle op,\n    _In_ XblUserHandle user,\n    _In_ XblLocalStorageWriteMode mode,\n    _In_z_ char const* key,\n    _In_ size_t dataSize,\n    _In_reads_bytes_(dataSize) void const* data\n)\n{\n    assert(context);\n    UNREFERENCED_PARAMETER(user);\n\n    auto pThis{ static_cast<LocalStorage*>(context) };\n    auto writeOp{ static_cast<LocalStorage::WriteOperation*>(op) };\n\n    String fullPath = pThis->m_path + key;\n\n    std::ios_base::openmode openMode{};\n    switch (mode)\n    {\n    case XblLocalStorageWriteMode::Append:\n    {\n        openMode = std::ios_base::app;\n        break;\n    }\n    case XblLocalStorageWriteMode::Truncate:\n    {\n        openMode = std::ios_base::trunc;\n        break;\n    }\n    }\n\n    std::ofstream file{ fullPath.data(), std::ios::binary | openMode };\n    if (!file.is_open())\n    {\n        LOGS_DEBUG << \"Failed to open file during LocalStorageService::WriteAsync, errno = \" << errno;\n        writeOp->Complete(E_FAIL);\n        return;\n    }\n\n    file.write(reinterpret_cast<const char*>(data), dataSize);\n    if (!file.good())\n    {\n        LOGS_DEBUG << \"Write failed during LocalStorageService::WriteAsync, errno = \" << errno;\n        writeOp->Complete(E_FAIL);\n        return;\n    }\n\n    uint64_t filesize = file.tellp();\n    writeOp->Complete(static_cast<size_t>(filesize));\n}\n\nvoid LocalStorage::DefaultRead(\n    _In_opt_ void* context,\n    _In_ XblClientOperationHandle op,\n    _In_ XblUserHandle user,\n    _In_z_ const char* key\n)\n{\n    assert(context);\n    UNREFERENCED_PARAMETER(user);\n\n    auto pThis{ static_cast<LocalStorage*>(context) };\n    auto readOp{ static_cast<LocalStorage::ReadOperation*>(op) };\n\n    String fullPath = pThis->m_path + key;\n\n    std::ifstream file{ fullPath.data(), std::ios::binary | std::ios::ate };\n    if (!file.is_open())\n    {\n        LOGS_DEBUG << \"Failed to open file during LocalStorageService::ReadAsync, errno = \" << errno;\n        readOp->Complete(E_FAIL);\n        return;\n    }\n\n    int64_t size = file.tellg();\n    if (size < 0)\n    {\n        LOGS_DEBUG << \"Failed to read file length during LocalStorageService::ReadAsync, errno = \" << errno;\n        readOp->Complete(E_FAIL);\n        return;\n    }\n\n    file.seekg(0);\n\n    Vector<uint8_t> data(static_cast<size_t>(size));\n\n    file.read(reinterpret_cast<char*>(data.data()), data.size());\n    if (!file.good())\n    {\n        LOGS_DEBUG << \"Failed to read file during LocalStorageService::ReadAsync, errno = \" << errno;\n        readOp->Complete(E_FAIL);\n        return;\n    }\n\n    assert(size == file.gcount());\n    readOp->Complete(std::move(data));\n}\n\nvoid LocalStorage::DefaultClear(\n    _In_opt_ void* context,\n    _In_ XblClientOperationHandle op,\n    _In_ XblUserHandle user,\n    _In_z_ const char* key\n)\n{\n    assert(context);\n    UNREFERENCED_PARAMETER(user);\n\n    auto pThis{ static_cast<LocalStorage*>(context) };\n    auto clearOp{ static_cast<LocalStorage::ClearOperation*>(op) };\n\n    String fullPath = pThis->m_path + key;\n\n    int res = std::remove(fullPath.data());\n    if (res != 0)\n    {\n        LOGS_DEBUG << \"Failed to delete file in LocalStorageService::DeleteAsync, errno = \" << errno;\n        clearOp->Complete(E_FAIL);\n    }\n    else\n    {\n        clearOp->Complete(S_OK);\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/System/local_storage.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"xsapi-c/platform_c.h\"\n#include \"client_operation.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nextern XblLocalStorageWriteHandler g_localStorageWriteHandler;\nextern XblLocalStorageReadHandler g_localStorageReadHandler;\nextern XblLocalStorageClearHandler g_localStorageClearHandler;\nextern XTaskQueueHandle g_localStorageTaskQueue;\nextern void* g_localStorageClientContext;\n\nclass LocalStorage : public std::enable_shared_from_this<LocalStorage>\n{\npublic:\n    LocalStorage(const TaskQueue& queue);\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    HRESULT SetStoragePath(_In_opt_z_ const char* path);\n#endif\n\n    using WriteOperation = ClientOperation<Result<size_t>>;\n    using ReadOperation = ClientOperation<Result<Vector<uint8_t>>>;\n    using ClearOperation = ClientOperation<HRESULT>;\n\n    HRESULT WriteAsync(\n        const User& user,\n        XblLocalStorageWriteMode mode,\n        String key,\n        Vector<uint8_t> data,\n        Callback<Result<size_t>> callback\n    ) noexcept;\n\n    HRESULT ReadAsync(\n        const User& user,\n        String key,\n        Callback<Result<Vector<uint8_t>>> callback\n    ) noexcept;\n\n    HRESULT ClearAsync(\n        const User& user,\n        String key,\n        Callback<HRESULT> callback\n    ) noexcept;\n\nprivate:\n    void QueueOperation(std::shared_ptr<XblClientOperation> op) noexcept;\n    void RunNextOperation() noexcept;\n    void OperationComplete() noexcept;\n\n    static void DefaultWrite(\n        _In_opt_ void* context,\n        _In_ XblClientOperationHandle operation,\n        _In_ XblUserHandle user,\n        _In_ XblLocalStorageWriteMode mode,\n        _In_z_ char const* key,\n        _In_ size_t dataSize,\n        _In_reads_bytes_(dataSize) void const* data\n    );\n\n    static void DefaultRead(\n        _In_opt_ void* context,\n        _In_ XblClientOperationHandle operation,\n        _In_ XblUserHandle user,\n        _In_z_ const char* key\n    );\n\n    static void DefaultClear(\n        _In_opt_ void* context,\n        _In_ XblClientOperationHandle operation,\n        _In_ XblUserHandle user,\n        _In_z_ const char* key\n    );\n\n    std::mutex m_mutex;\n    TaskQueue m_queue;\n    Queue<std::shared_ptr<XblClientOperation>> m_operationQueue;\n    std::shared_ptr<XblClientOperation> m_currentOperation;\n\n    XblLocalStorageWriteHandler m_writeHandler;\n    XblLocalStorageReadHandler m_readHandler;\n    XblLocalStorageClearHandler m_clearHandler;\n    void* m_context;\n\n    // State for default handlers\n    String m_path;\n\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\n    static String GetDefaultStoragePath();\n#endif\n\n    friend class StorageOperationLauncher;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Source/System/platform_api.cpp",
    "content": "#include \"pch.h\"\n#include \"client_operation.h\"\n#include \"local_storage.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::system;\n\nSTDAPI XblLocalStorageWriteComplete(\n    _In_ XblClientOperationHandle operation,\n    _In_ XblClientOperationResult result,\n    _In_ size_t dataSize\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(operation);\n\n    auto writeOp{ static_cast<LocalStorage::WriteOperation*>(operation) };\n    return writeOp->Complete({ dataSize, XblClientOperation::HresultFromResult(result) });\n}\nCATCH_RETURN()\n\nSTDAPI XblLocalStorageReadComplete(\n    _In_ XblClientOperationHandle operation,\n    _In_ XblClientOperationResult result,\n    _In_ size_t dataSize,\n    _In_reads_bytes_opt_(dataSize) void const* data\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(operation);\n    RETURN_HR_INVALIDARGUMENT_IF(dataSize && !data);\n\n    auto readOp{ static_cast<LocalStorage::ReadOperation*>(operation) };\n\n    Vector<uint8_t> dataVector(dataSize);\n    memcpy(dataVector.data(), data, dataSize);\n\n    return readOp->Complete(Result<Vector<uint8_t>>{ std::move(dataVector), XblClientOperation::HresultFromResult(result) });\n}\nCATCH_RETURN()\n\nSTDAPI XblLocalStorageClearComplete(\n    _In_ XblClientOperationHandle operation,\n    _In_ XblClientOperationResult result\n) XBL_NOEXCEPT\ntry\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(operation);\n\n    auto clearOp{ static_cast<LocalStorage::ClearOperation*>(operation) };\n    return clearOp->Complete(XblClientOperation::HresultFromResult(result));\n}\nCATCH_RETURN()\n\nSTDAPI XblLocalStorageSetHandlers(\n    _In_opt_ XTaskQueueHandle queue,\n    _In_ XblLocalStorageWriteHandler writeHandler,\n    _In_ XblLocalStorageReadHandler readHandler,\n    _In_ XblLocalStorageClearHandler clearHandler,\n    _In_opt_ void* context\n) XBL_NOEXCEPT\ntry\n{\n    if (GlobalState::Get())\n    {\n        return E_XBL_ALREADY_INITIALIZED;\n    }\n\n    if ((writeHandler && readHandler && clearHandler) || \n       (!writeHandler && !readHandler && !clearHandler))\n    {\n        g_localStorageWriteHandler = writeHandler;\n        g_localStorageReadHandler = readHandler;\n        g_localStorageClearHandler = clearHandler;\n        g_localStorageClientContext = context;\n        g_localStorageTaskQueue = queue; // Store a non-owning pointer until XblInitialize is called\n    }\n    else\n    {\n        // Require that the hooks be set together\n        return E_INVALIDARG;\n    }\n\n    return S_OK;\n}\nCATCH_RETURN()\n"
  },
  {
    "path": "Tests/ApiExplorer/APIExplorer.Shared.vcxitems",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>\n    <HasSharedItems>true</HasSharedItems>\n    <ItemsProjectGuid>{CBC0BEC4-131D-4868-9345-71813557FB39}</ItemsProjectGuid>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectCapability Include=\"SourceItemsFromImports\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_docs.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_grts_gameinvite.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_libhttp.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievements_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievements_progress_notification.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievement_unlock_notification.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_events.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_gameinvite_notifications.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_grts.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_leaderboard.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_multiplayer.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_multiplayer_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_presence.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_privacy.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_profile.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_real_time_activity.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_social.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_social_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_statistics.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_stats2017.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_stringVerify.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_title_storage.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_xblhttp.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\api_xblc_multiplayer_activity.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_achievements.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_leaderboard.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_profile.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_privacy.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_stringverify.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_title_storage.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_events.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_social.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_social_manager.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_presence.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_real_time_activity.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_statistics.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_multiplayer.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lapi.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lauxlib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lbaselib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lbitlib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lcode.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lcorolib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lctype.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldblib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldebug.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldo.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldump.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lfunc.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lgc.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\linit.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\liolib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\llex.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lmathlib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lmem.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\loadlib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lobject.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lopcodes.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\loslib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lparser.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstate.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstring.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstrlib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltable.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltablib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltm.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lundump.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lutf8lib.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lvm.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lzio.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <ExcludedFromBuild>true</ExcludedFromBuild>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\log.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\lua-include.cpp\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\mem_hook.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\multidevice.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\pch_common.cpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)APIs\\apis.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Include\\api_explorer.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Include\\multidevice.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Include\\runner.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lapi.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lauxlib.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lcode.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lctype.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldebug.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldo.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lfunc.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lgc.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\llex.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\llimits.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lmem.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lobject.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lopcodes.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lparser.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lprefix.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstate.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstring.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltable.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltm.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lua.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lua.hpp\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\luaconf.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lualib.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lundump.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lvm.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lzio.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\apirunnercloudfns.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\mem_hook.h\" />\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\pal.h\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\pch_common.h\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\utils.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievements.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_async.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xal.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\commands.cpp\" />\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\pch_apicommon.cpp\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"$(MSBuildThisFileDirectory)Shared\\xboxservices.config\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_manager.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_manager_performance_test.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_manager_update_achievements.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_progress_notification.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\PerformanceTestMockResponse.json\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\update-achievements-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\update-achievements.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\cmds.json\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\events\\events.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\events\\offline.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\events\\offline2.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\gdk-gameinvite\\game-invite-listen.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\gdk-gameinvite\\game-invite-send.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\gdk-gameinvite\\game-mpainvite-send.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard-2017.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard-bvt.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\httpHandle.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\httpPerform.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\libHCTrace.lua\" />\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\manualDispatchTest.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_cleanup_while_connected.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_cleanup_while_connecting.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_closehandle_while_connected.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_disconnect_while_connecting.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_send.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\global_state.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\null_task_queue.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\override_locale.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\simpletest.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\xbox_live_context.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\matchmaking_single_device.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\matchmaking_single_device-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\MP_JoinLobbyViaActivity.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_multiple_contexts.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_partial_invite_flow.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_search-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_search.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_transfer-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_transfer.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\receive_invite_gsdk.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\receive_invite_win32.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\send_invite.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\set_activity.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\update_activity.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\update_recent_players.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_Invite.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_InviteUI.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_JoinFixedGameSession.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_JoinLobbyViaActivity.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_Match.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\notification\\achievement_unlock_notification.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_SingleDevice_JoinLeaveGame.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_SingleDevice_SyncHostWrite.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\notification\\gameinvitenotifications.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\notification\\multiple_notification_subscriptions.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\presence\\presence-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\presence\\presence.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\presence\\presence_rta.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\privacy\\privacy-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\privacy\\privacy.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfile-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfile.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfiles-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfiles.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfilesForSocialGroup-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfilesForSocialGroupAsync.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTAResync.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTASuspendResume.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTA_activation.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTA_MP_SM.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\simpleRTA-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\simpleRTA.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\simpleRTA_legacy.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\reputation-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\reputation.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_1-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_1.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_2-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_2.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_filter-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_filter.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_list-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_list.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_remove_realloc-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_remove_realloc.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_wait.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_relationship_changed.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_sub_unsub.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats2017\\stats2017-test429.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats2017\\stats2017.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats-bvt.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats_legacy.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stringVerify\\stringVerify-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stringVerify\\stringVerify.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\tests.root\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\titleStorage\\title_storage-cpp.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\titleStorage\\title_storage-restCalls.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\titleStorage\\title_storage.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xal\\addfirst.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xal\\signOut.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xblHttp\\XBLHttpCall.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xblHttp\\XBLHttpCallPerform.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\_luasetup_\\u-test\\u-test.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\_luasetup_\\xal\\common.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\_luasetup_\\xal\\setup.lua\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n  </ItemGroup>\n  <Target Name=\"XblBuildDebug\" BeforeTargets=\"InitializeBuildStatus\">\n    <Message Importance=\"High\" Text=\"APIExplorerBuild\" />\n    <Message Importance=\"High\" Text=\"    OutputPath                   = '$(OutputPath)'\" />\n  </Target>\n</Project>"
  },
  {
    "path": "Tests/ApiExplorer/APIExplorer.Shared.vcxitems.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\commands.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\utils.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_async.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xal.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\pch_apicommon.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\pch_common.h\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lapi.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lauxlib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lbaselib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lbitlib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lcode.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lcorolib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lctype.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldblib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldebug.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldo.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldump.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lfunc.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lgc.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\linit.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\liolib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\llex.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lmathlib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lmem.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\loadlib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lobject.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lopcodes.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\loslib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lparser.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstate.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstring.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstrlib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltable.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltablib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltm.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lundump.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lutf8lib.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lvm.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)lua\\src\\lzio.c\">\n      <Filter>LUA</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\lua-include.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\pch_common.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievements.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_social_manager.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_profile.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_social.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_libhttp.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_multiplayer_manager.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_multiplayer.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_privacy.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_events.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_leaderboard.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_statistics.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_grts_gameinvite.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_presence.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_real_time_activity.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_xblhttp.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\log.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_stats2017.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_title_storage.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\log.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_gameinvite_notifications.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_stringVerify.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_grts.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\multidevice.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\api_xblc_multiplayer_activity.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_achievements.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_leaderboard.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_profile.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_privacy.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_stringverify.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_title_storage.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievement_unlock_notification.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_events.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_social.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_social_manager.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_presence.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_statistics.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_real_time_activity.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_docs.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_cpp_multiplayer.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievements_manager.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)APIs\\apis_xblc_achievements_progress_notification.cpp\">\n      <Filter>APIs</Filter>\n    </ClCompile>\n    <ClCompile Include=\"$(MSBuildThisFileDirectory)Shared\\mem_hook.cpp\">\n      <Filter>Shared</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"Shared\">\n      <UniqueIdentifier>{1b3bad2e-684e-4774-b5c3-c898ff1fe82a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\">\n      <UniqueIdentifier>{a78b1f06-3ccf-4126-ab54-3f6d64ffee17}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Include\">\n      <UniqueIdentifier>{461223d9-00e1-4edd-8e00-4ce6d2a1e08f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\achievements\">\n      <UniqueIdentifier>{d029161e-3101-45c2-a911-1e7ea5272070}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\profile\">\n      <UniqueIdentifier>{794ce350-68de-4521-bc2c-72a7e4a8ae52}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"LUA\">\n      <UniqueIdentifier>{4b0ee3e5-31ef-4a67-a583-8c526eb8600d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\misc\">\n      <UniqueIdentifier>{293c02c1-bd8d-43f2-a66a-5d8f14ace95e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\social\">\n      <UniqueIdentifier>{8c17651b-4171-4478-b119-8a38277dcc92}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"APIs\">\n      <UniqueIdentifier>{735bd0d7-b2eb-40b2-9b6a-8c7716b7f3ba}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\libHttp\">\n      <UniqueIdentifier>{c7d6f82d-c973-49e4-9182-bfaf5f3d9f7c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\xal\">\n      <UniqueIdentifier>{ed76de34-56a5-4397-b48d-c025f3d0f77a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\multiplayerManager\">\n      <UniqueIdentifier>{71e58020-fc08-4499-94ac-0a63526ee83a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\privacy\">\n      <UniqueIdentifier>{4f077db1-539e-494b-8a09-5297b318d974}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\events\">\n      <UniqueIdentifier>{47403098-99a3-4b9e-9e9a-bf77f814ade6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\leaderboard\">\n      <UniqueIdentifier>{c7061bd9-a6c7-4e14-9781-8faf6deebab0}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\stats\">\n      <UniqueIdentifier>{61a364d7-b4ca-4d79-88d9-556e78b36357}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\mp\">\n      <UniqueIdentifier>{568ef0b4-4d4e-49a6-a248-d895d558e529}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\gdk-gameinvite\">\n      <UniqueIdentifier>{bf87e97f-bc1b-4d47-981a-0715c54ee9f8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\presence\">\n      <UniqueIdentifier>{bea3c22d-0bb2-4cde-bdb6-4ea78f13e2df}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\_luasetup_\">\n      <UniqueIdentifier>{4a5c870b-1540-4160-8ae8-46c8bb18bfe4}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\_luasetup_\\xal\">\n      <UniqueIdentifier>{c9ea0c89-d604-46ab-8b52-972078a2f857}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\_luasetup_\\uwp\">\n      <UniqueIdentifier>{b3715910-a3cd-4f6f-83d5-077f0a6a7325}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\_luasetup_\\u-test\">\n      <UniqueIdentifier>{a67c0f51-6ded-4bda-b61b-7e032a7ae5a4}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\rta\">\n      <UniqueIdentifier>{4b9ea591-072a-4fda-8fcb-dd9e20778fc0}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\xblHttp\">\n      <UniqueIdentifier>{cc49c082-b80b-4362-9212-e5afcc83c21e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\stats2017\">\n      <UniqueIdentifier>{e54673b6-05cd-4d00-83df-a74ba081a5d1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\titleStorage\">\n      <UniqueIdentifier>{16160a81-596f-4afb-ab5c-e7b0946714ac}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\notification\">\n      <UniqueIdentifier>{a12769dd-fa4e-4f7e-ab94-7e339900e11f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\stringVerify\">\n      <UniqueIdentifier>{f62f4642-5d6a-4c0d-ba9a-9f8bce53994d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Tests\\multiplayerActivity\">\n      <UniqueIdentifier>{4cddcf8f-24ed-4308-9d6a-d5367a8920a9}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\utils.h\">\n      <Filter>Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\pal.h\">\n      <Filter>Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Include\\runner.h\">\n      <Filter>Include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Include\\api_explorer.h\">\n      <Filter>Include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lapi.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lauxlib.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lcode.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lctype.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldebug.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ldo.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lfunc.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lgc.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\llex.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\llimits.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lmem.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lobject.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lopcodes.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lparser.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lprefix.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstate.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lstring.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltable.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\ltm.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lua.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lua.hpp\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\luaconf.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lualib.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lundump.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lvm.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)lua\\src\\lzio.h\">\n      <Filter>LUA</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)APIs\\apis.h\">\n      <Filter>APIs</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Include\\multidevice.h\">\n      <Filter>Include</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\apirunnercloudfns.h\">\n      <Filter>Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"$(MSBuildThisFileDirectory)Shared\\mem_hook.h\">\n      <Filter>Shared</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\simpletest.lua\">\n      <Filter>Tests\\misc</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\xbox_live_context.lua\">\n      <Filter>Tests\\misc</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\null_task_queue.lua\">\n      <Filter>Tests\\misc</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_filter.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_list.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Shared\\xboxservices.config\">\n      <Filter>Shared</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfiles.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfilesForSocialGroupAsync.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfile.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfiles.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfilesForSocialGroupAsync.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfile.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfiles.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfilesForSocialGroupAsync.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfile.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\httpHandle.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\httpPerform.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\privacy\\privacy.lua\">\n      <Filter>Tests\\privacy</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\events\\events.lua\">\n      <Filter>Tests\\events</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats.lua\">\n      <Filter>Tests\\stats</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard.lua\">\n      <Filter>Tests\\leaderboard</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\presence\\presence.lua\">\n      <Filter>Tests\\presence</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\tests.root\">\n      <Filter>Tests</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xal\\addfirst.lua\">\n      <Filter>Tests\\xal</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\_luasetup_\\u-test\\u-test.lua\">\n      <Filter>Tests\\_luasetup_\\u-test</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\_luasetup_\\xal\\common.lua\">\n      <Filter>Tests\\_luasetup_\\xal</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\_luasetup_\\xal\\setup.lua\">\n      <Filter>Tests\\_luasetup_\\xal</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\update-achievements.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\simpleRTA.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_1.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_2.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xblHttp\\XBLHttpCall.lua\">\n      <Filter>Tests\\xblHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xblHttp\\XBLHttpCallPerform.lua\">\n      <Filter>Tests\\xblHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\xal\\signOut.lua\">\n      <Filter>Tests\\xal</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats2017\\stats2017.lua\">\n      <Filter>Tests\\stats2017</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\events\\offline.lua\">\n      <Filter>Tests\\events</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\events\\offline2.lua\">\n      <Filter>Tests\\events</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_remove_realloc.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_closehandle_while_connected.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_disconnect_while_connecting.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\titleStorage\\title_storage.lua\">\n      <Filter>Tests\\titleStorage</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_search.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_transfer.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_search.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_transfer.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\cmds.json\" />\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats-bvt.lua\">\n      <Filter>Tests\\stats</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard-bvt.lua\">\n      <Filter>Tests\\leaderboard</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_send.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\global_state.lua\">\n      <Filter>Tests\\misc</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\misc\\override_locale.lua\">\n      <Filter>Tests\\misc</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\notification\\gameinvitenotifications.lua\">\n      <Filter>Tests\\notification</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\reputation.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stringVerify\\stringVerify.lua\">\n      <Filter>Tests\\stringVerify</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\reputation.lua\" />\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_partial_invite_flow.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_Invite.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_Match.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_InviteUI.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_JoinLobbyViaActivity.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_JoinFixedGameSession.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\MP_JoinLobbyViaActivity.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\send_invite.lua\">\n      <Filter>Tests\\multiplayerActivity</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\update_activity.lua\">\n      <Filter>Tests\\multiplayerActivity</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\update_recent_players.lua\">\n      <Filter>Tests\\multiplayerActivity</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\receive_invite_win32.lua\">\n      <Filter>Tests\\multiplayerActivity</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements-cpp.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\update-achievements-cpp.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard-cpp.lua\">\n      <Filter>Tests\\leaderboard</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfile-cpp.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfiles-cpp.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\profile\\GetUserProfilesForSocialGroup-cpp.lua\">\n      <Filter>Tests\\profile</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\privacy\\privacy-cpp.lua\">\n      <Filter>Tests\\privacy</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stringVerify\\stringVerify-cpp.lua\">\n      <Filter>Tests\\stringVerify</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\titleStorage\\title_storage-cpp.lua\">\n      <Filter>Tests\\titleStorage</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\notification\\achievement_unlock_notification.lua\">\n      <Filter>Tests\\notification</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\gdk-gameinvite\\game-invite-listen.lua\">\n      <Filter>Tests\\gdk-gameinvite</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\gdk-gameinvite\\game-invite-send.lua\">\n      <Filter>Tests\\gdk-gameinvite</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTA_MP_SM.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats_legacy.lua\">\n      <Filter>Tests\\stats</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\presence\\presence_rta.lua\">\n      <Filter>Tests\\presence</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_relationship_changed.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\simpleRTA_legacy.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTA_activation.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats2017\\stats2017-test429.lua\">\n      <Filter>Tests\\stats2017</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\matchmaking_single_device.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\set_activity.lua\">\n      <Filter>Tests\\multiplayerActivity</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\MultiplayerActivity\\receive_invite_gsdk.lua\">\n      <Filter>Tests\\multiplayerActivity</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats2017\\stats2017-test429.lua\">\n      <Filter>Tests\\stats2017</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\reputation-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_1-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_2-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_filter-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_list-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_remove_realloc-cpp.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\presence\\presence-cpp.lua\">\n      <Filter>Tests\\presence</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\stats\\stats-cpp.lua\">\n      <Filter>Tests\\stats</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\simpleRTA-cpp.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp-cpp.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\matchmaking_single_device-cpp.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_search-cpp.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_transfer-cpp.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\leaderboard\\leaderboard-2017.lua\">\n      <Filter>Tests\\leaderboard</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_manager_performance_test.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_manager.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\PerformanceTestMockResponse.json\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_progress_notification.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\achievements\\achievements_manager_update_achievements.lua\">\n      <Filter>Tests\\achievements</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_SingleDevice_JoinLeaveGame.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\multiplayerManager\\MPM_SingleDevice_SyncHostWrite.lua\">\n      <Filter>Tests\\multiplayerManager</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\titleStorage\\title_storage-restCalls.lua\">\n      <Filter>Tests\\titleStorage</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_manager_wait.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\social\\social_sub_unsub.lua\">\n      <Filter>Tests\\social</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTAResync.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\rta\\RTASuspendResume.lua\">\n      <Filter>Tests\\rta</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\gdk-gameinvite\\game-mpainvite-send.lua\">\n      <Filter>Tests\\gdk-gameinvite</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\manualDispatchTest.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_cleanup_while_connected.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\websocket_cleanup_while_connecting.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\notification\\multiple_notification_subscriptions.lua\">\n      <Filter>Tests\\notification</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\mp\\mp_multiple_contexts.lua\">\n      <Filter>Tests\\mp</Filter>\n    </None>\n    <None Include=\"$(MSBuildThisFileDirectory)Tests\\libHttp\\libHCTrace.lua\">\n      <Filter>Tests\\libHttp</Filter>\n    </None>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/ApiExplorer/APIs/api_xblc_multiplayer_activity.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n// Random Xuids from XDKS.1 sandbox\nstatic uint64_t xuids[] =\n{\n    2814639011617876,\n    2814641789541994,\n    2814644008675844\n};\n\nint XblMultiplayerActivityUpdateRecentPlayers_Lua(lua_State *L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n    uint32_t xuidIndex{ GetUint32FromLua(L, 1, 0) };\n    uint64_t xuid{ xuids[xuidIndex] };\n\n    // CODE SNIPPET START: XblMultiplayerActivityUpdateRecentPlayers_C\n    XblMultiplayerActivityRecentPlayerUpdate update{ xuid };\n    HRESULT hr = XblMultiplayerActivityUpdateRecentPlayers(xblContext, &update, 1);\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerActivityFlushRecentPlayersAsync_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n\n    // CODE SNIPPET START: XblMultiplayerActivityFlushRecentPlayersAsync_C\n    auto async = std::make_unique<XAsyncBlock>();\n    async->queue = Data()->queue;\n    async->callback = [](XAsyncBlock* async)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock\n        HRESULT hr = XAsyncGetStatus(async, false);\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerActivityFlushRecentPlayersAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerActivityFlushRecentPlayersAsync(xblContext, async.get());\n    if (SUCCEEDED(hr))\n    {\n        async.release();\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerActivitySetActivityAsync_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n\n    // CODE SNIPPET START: XblMultiplayerActivitySetActivityAsync_C\n    auto async = std::make_unique<XAsyncBlock>();\n    async->queue = Data()->queue;\n    async->callback = [](XAsyncBlock* async)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock\n        HRESULT hr = XAsyncGetStatus(async, false);\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerActivitySetActivityAsync\"); // CODE SNIP SKIP\n    };\n\n    XblMultiplayerActivityInfo info{};\n    info.connectionString = \"dummyConnectionString\";\n    info.joinRestriction = XblMultiplayerActivityJoinRestriction::Followed;\n    info.maxPlayers = 10;\n    info.currentPlayers = 1;\n    info.groupId = \"dummyGroupId\";\n\n    HRESULT hr = XblMultiplayerActivitySetActivityAsync(\n        xblContext,\n        &info,\n        true,\n        async.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        async.release();\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nstd::string SerializeActivityInfo(\n    const XblMultiplayerActivityInfo* activityInfo,\n    size_t activityCount\n) noexcept\n{\n    std::stringstream ss;\n\n    for (size_t i = 0; i < activityCount; ++i, ++activityInfo)\n    {\n        ss << \"{\\n\";\n        ss << \"\\txuid: \" << activityInfo->xuid << \"\\n\";\n\n        ss << \"\\tconnectionString: \";\n        if (activityInfo->connectionString)\n        {\n            ss << activityInfo->connectionString << \"\\n\";\n        }\n        ss << \"\\n\";\n        \n        ss << \"\\tjoinRestriction: \" << static_cast<uint32_t>(activityInfo->joinRestriction) << \"\\n\";\n        ss << \"\\tmaxPlayers: \" << activityInfo->maxPlayers << \"\\n\";\n        ss << \"\\tcurrentPlayers: \" << activityInfo->currentPlayers << \"\\n\";\n        \n        ss << \"\\tgroupId: \";\n        if (activityInfo->groupId)\n        {\n            ss << activityInfo->groupId << \"\\n\";\n        }\n        ss << \"\\n\";\n\n        ss << \"\\tplatform: \" << static_cast<uint32_t>(activityInfo->platform) << \"\\n\";\n        ss << \"},\\n\";\n    }\n\n    return ss.str();\n}\n\nint XblMultiplayerActivityGetActivityAsync_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n\n    // Get our own activity\n    uint64_t xuid{ Data()->xboxUserId };\n\n    // CODE SNIPPET START: XblMultiplayerActivityGetActivityAsync_C\n    auto async = std::make_unique<XAsyncBlock>();\n    async->queue = Data()->queue;\n    async->callback = [](XAsyncBlock* async)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock\n\n        size_t resultSize{};\n        HRESULT hr = XblMultiplayerActivityGetActivityResultSize(async, &resultSize);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<uint8_t> buffer(resultSize);\n            XblMultiplayerActivityInfo* activityInfo{};\n            size_t resultCount{};\n            hr = XblMultiplayerActivityGetActivityResult(async, buffer.size(), buffer.data(), &activityInfo, &resultCount, nullptr);\n            if (SUCCEEDED(hr))\n            {\n                // ...\n                // CODE SKIP START\n                auto serializedInfo{ SerializeActivityInfo(activityInfo, resultCount) };\n                LogToFile(\"XblMultiplayerActivityGetActivityAsync complete with %u results:\\n%s\", resultCount, serializedInfo.data());\n                // CODE SKIP END\n            }\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerActivityGetActivityAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerActivityGetActivityAsync(\n        xblContext,\n        &xuid,\n        1,\n        async.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        async.release();\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerActivityDeleteActivityAsync_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n\n    // CODE SNIPPET START: XblMultiplayerActivityDeleteActivityAsync_C\n    auto async = std::make_unique<XAsyncBlock>();\n    async->queue = Data()->queue;\n    async->callback = [](XAsyncBlock* async)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock\n        HRESULT hr = XAsyncGetStatus(async, false);\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerActivityDeleteActivityAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerActivityDeleteActivityAsync(xblContext, async.get());\n\n    if (SUCCEEDED(hr))\n    {\n        async.release();\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerActivitySendInvitesAsync_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n    //uint64_t xuid{ GetUint64FromLua(L, 1, xuids[0]) };\n    //uint64_t xuid{ 2814636782672891 };\n    uint64_t xuid{ 2533274873775631 };\n\n    // CODE SNIPPET START: XblMultiplayerActivitySendInvitesAsync_C\n    auto async = std::make_unique<XAsyncBlock>();\n    async->queue = Data()->queue;\n    async->callback = [](XAsyncBlock* async)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock\n        HRESULT hr = XAsyncGetStatus(async, false);\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerActivitySendInvitesAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerActivitySendInvitesAsync(\n        xblContext,\n        &xuid,\n        1,\n        true,\n        nullptr,\n        async.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        async.release();\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n\nstatic struct MultiplayerActivityState\n{\n    MultiplayerActivityState() = default;\n    ~MultiplayerActivityState()\n    {\n        assert(!gameInviteHandlerToken);\n    }\n\n    XblFunctionContext gameInviteHandlerToken{ 0 };\n} state;\n\nint XblMultiplayerActivityAddInviteHandler_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n\n    // CODE SNIPPET START: XblMultiplayerActivityAddInviteHandler_C\n    state.gameInviteHandlerToken = XblMultiplayerActivityAddInviteHandler(\n        xblContext,\n        [](_In_ const XblMultiplayerActivityInviteData* data, _In_opt_ void*)\n        {\n            // DOTS\n            // CODE SKIP START\n            std::stringstream ss;\n            ss << \"{\\n\";\n            ss << \"\\tinvitedXuid: \" << data->invitedXuid << \"\\n\";\n            ss << \"\\tsenderXuid: \" << data->senderXuid << \"\\n\";\n            ss << \"\\tsenderGamertag: \" << data->senderGamertag << \"\\n\";\n            ss << \"\\tsenderUniqueModernGamertag: \" << data->senderUniqueModernGamertag << \"\\n\";\n            ss << \"\\ttitleName: \" << data->titleName << \"\\n\";\n            ss << \"\\texpirationTime: \" << data->expirationTime << \"\\n\";\n            ss << \"}\\n\";\n\n            LogToScreen(\"MultiplayerActivity invite received: \\n%s\", ss.str().data());\n            CallLuaFunctionWithHr(S_OK, \"OnMultiplayerActivityGameInvite\"); \n            // CODE SKIP END\n        },\n        nullptr\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerActivityAddInviteHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerActivityRemoveInviteHandler_Lua(lua_State* L)\n{\n    XblContextHandle xblContext{ Data()->xboxLiveContext };\n\n    // CODE SNIPPET START: XblMultiplayerActivityRemoveInviteHandler_C\n    HRESULT hr = XblMultiplayerActivityRemoveInviteHandler(\n        xblContext,\n        state.gameInviteHandlerToken\n    );\n\n    state.gameInviteHandlerToken = 0;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerActivityRemoveInviteHandler: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n#endif\n\nvoid SetupAPIs_XblMultiplayerActivity()\n{\n    lua_register(Data()->L, \"XblMultiplayerActivityUpdateRecentPlayers\", XblMultiplayerActivityUpdateRecentPlayers_Lua);\n    lua_register(Data()->L, \"XblMultiplayerActivityFlushRecentPlayersAsync\", XblMultiplayerActivityFlushRecentPlayersAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerActivitySetActivityAsync\", XblMultiplayerActivitySetActivityAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerActivityGetActivityAsync\", XblMultiplayerActivityGetActivityAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerActivityDeleteActivityAsync\", XblMultiplayerActivityDeleteActivityAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerActivitySendInvitesAsync\", XblMultiplayerActivitySendInvitesAsync_Lua);\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM_IS_EXTERNAL\n    lua_register(Data()->L, \"XblMultiplayerActivityAddInviteHandler\", XblMultiplayerActivityAddInviteHandler_Lua);\n    lua_register(Data()->L, \"XblMultiplayerActivityRemoveInviteHandler\", XblMultiplayerActivityRemoveInviteHandler_Lua);\n#endif\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint SetCheckHR_Lua(lua_State *L)\n{\n    Data()->m_checkHR = GetBoolFromLua(L, 1, true);\n    return 0;\n}\n\nint GetCheckHR_Lua(lua_State *L)\n{\n    lua_pushboolean(L, Data()->m_checkHR);\n    return 1;\n}\n\nint Sleep_Lua(lua_State *L)\n{\n    DWORD time = (DWORD)GetUint32FromLua(L, 1, 0);\n    LogToScreen(\"Sleep(%d)\", time);\n    pal::Sleep(time);\n    return LuaReturnHR(L, S_OK);\n}\n\nint StopTestFile_Lua(lua_State *L)\n{\n    Data()->m_stopTest = true;\n    return LuaReturnHR(L, S_OK);\n}\n\nint LogHelper(bool logToFile, lua_State *L)\n{\n    int arg = 1;\n    int nargs = lua_gettop(L);\n    for (; nargs--; arg++) \n    {\n        if (lua_type(L, arg) == LUA_TNUMBER) \n        {\n            if (lua_isinteger(L, arg))\n            {\n                LogCat(logToFile, \"%d\", lua_tointeger(L, arg));\n            }\n            else\n            {\n                LogCat(logToFile, \"%f\", lua_tonumber(L, arg));\n            }\n        }\n        else if (lua_type(L, arg) == LUA_TBOOLEAN)\n        {\n            LogCat(logToFile, \"%d\", lua_toboolean(L, arg));\n        }\n        else if (lua_type(L, arg) == LUA_TSTRING)\n        {\n            size_t l;\n            const char *s = luaL_checklstring(L, arg, &l);\n            LogCat(logToFile, s);\n        }\n    }\n    LogCat(logToFile, \"\\n\");\n    return 0;\n}\n\nint LogToFile_Lua(lua_State *L)\n{\n    return LogHelper(true, L);\n}\n\nint LogToScreen_Lua(lua_State *L)\n{\n    return LogHelper(false, L);\n}\n\nint IsRunningTests_Lua(lua_State *L)\n{\n    bool isTestDone = !Data()->m_runningTests;\n    lua_pushboolean(L, isTestDone);\n    return 1;\n}\n\nint GetLastError_Lua(lua_State *L)\n{\n    HRESULT hr = Data()->m_lastError;\n    lua_pushinteger(L, hr);\n    return 1;\n}\n\nint SetCallUpdate_Lua(lua_State *L)\n{\n    Data()->m_callUpdate = GetBoolFromLua(L, 1, true);\n    return 0;\n}\n\nint SetTestWasSkipped_Lua(lua_State *L)\n{\n    UNREFERENCED_PARAMETER(L);\n    Data()->m_wasTestSkipped = true;\n    return 0;\n}\n\nint SetOnXalTryAddFirstUserSilentlyAsync_Lua(lua_State *L)\n{\n    Data()->m_onXalTryAddFirstUserSilentlyAsync = GetStringFromLua(L, 1, \"\");\n    return 0;\n}\n\nint SetOnTaskQueueTerminateWithAsyncWait_Lua(lua_State *L)\n{\n    Data()->m_onTaskQueueTerminateWithAsyncWait = GetStringFromLua(L, 1, \"\");\n    return 0;\n}\n\nint MultiDeviceGetRemoteState_Lua(lua_State *L)\n{\n    std::string key = GetStringFromLua(L, 1, \"\");\n\n    std::string value = Data()->m_multiDeviceManager->GetStateValueFromKey(key);\n    lua_pushstring(L, value.c_str());\n    return 1;\n}\n\nvoid MultiDeviceWaitTillRemoteStateHelper(const std::string key, const std::string& valueToWaitFor)\n{\n    LogToScreen(\"MultiDevice: Waiting for %s key to be %s in cloud DB\", key.c_str(), valueToWaitFor.c_str());\n    while (true)\n    {\n        std::string curValue = Data()->m_multiDeviceManager->GetStateValueFromKey(key);\n        if (curValue == valueToWaitFor)\n        {\n            LogToScreen(\"MultiDevice: Done waiting. Got %s from cloud DB\", valueToWaitFor.c_str());\n            break;\n        }\n        pal::Sleep(100);\n    }\n}\n\nint MultiDeviceWaitTillRemoteState_Lua(lua_State *L)\n{\n    std::string key = GetStringFromLua(L, 1, \"\");\n    std::string valueToWaitFor = GetStringFromLua(L, 2, \"\");\n\n    MultiDeviceWaitTillRemoteStateHelper(key, valueToWaitFor);\n    return 0;\n}\n\nint MultiDeviceSyncAndWait_Lua(lua_State *L)\n{\n    std::string key = GetStringFromLua(L, 1, \"\");\n\n    if (Data()->m_multiDeviceManager->IsHost())\n    {\n        // Set to READY, and wait for peer to ACK, then delete ACK\n        Data()->m_multiDeviceManager->SetSessionState(key, \"READY\", [](HRESULT) {});\n        MultiDeviceWaitTillRemoteStateHelper(key, \"ACK\");\n        Data()->m_multiDeviceManager->SetSessionState(key, \"\", [](HRESULT) {});\n    }\n    else\n    {\n        // Wait for state to be READY, then ACK\n        MultiDeviceWaitTillRemoteStateHelper(key, \"READY\");\n        Data()->m_multiDeviceManager->SetSessionState(key, \"ACK\", [](HRESULT) {});\n    }\n\n    return 0;\n}\n\nint MultiDeviceSetLocalState_Lua(lua_State *L)\n{\n    std::string key = GetStringFromLua(L, 1, \"\");\n    std::string value = GetStringFromLua(L, 2, \"\");\n\n    Data()->m_multiDeviceManager->SetSessionState(key, value, [](HRESULT) {});\n    return 0;\n}\n\nint MultiDeviceIsHost_Lua(lua_State *L)\n{\n    int value = Data()->m_multiDeviceManager->IsHost() ? 1 : 0;\n    lua_pushnumber(L, value);\n    return 1;\n}\n\nint MultiDeviceGetRemoteXuid_Lua(lua_State *L)\n{\n    if (Data()->m_multiDeviceManager->IsHost())\n    {\n        std::string value = Data()->m_multiDeviceManager->GetSessionState().client2xuid;\n        lua_pushstring(L, value.c_str());\n    }\n    else\n    {\n        std::string value = Data()->m_multiDeviceManager->GetSessionState().client1xuid;\n        lua_pushstring(L, value.c_str());\n    }\n    return 1;\n}\n\nint APIRunner_AssertOnAllocOfId_Lua(lua_State *L)\n{\n    auto id = GetUint64FromLua(L, 1, 0);\n    auto memHook = GetApiRunnerMemHook();\n    memHook->AssertOnAllocOfId(id);\n    return LuaReturnHR(L, S_OK);\n}\n\nint APIRunner_MemStartTracking_Lua(lua_State *L)\n{\n    auto memHook = GetApiRunnerMemHook();\n    memHook->StartMemTracking();\n    return LuaReturnHR(L, S_OK);\n}\n\nint APIRunner_LogStats_Lua(lua_State *L)\n{\n    auto memHook = GetApiRunnerMemHook();\n    memHook->LogStats(\"MemCheck\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint APIRunner_MemLogUnhookedStats_Lua(lua_State *L)\n{\n    auto memHook = GetApiRunnerMemHook();\n    memHook->LogUnhookedStats();\n    return LuaReturnHR(L, S_OK);\n}\n\nint IsGDKPlatform_Lua(lua_State *L)\n{\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    lua_pushboolean(L, true);\n#else \n    lua_pushboolean(L, false);\n#endif\n    return 1;\n}\n\nvoid RegisterLuaAPIs()\n{\n    SetupAPIs_Xal();\n    SetupAPIs_Xbl();\n    SetupAPIs_Async();\n    SetupAPIs_XblAchievements();\n    SetupAPIs_XblAchievementsManager();\n    SetupAPIs_XblAchievementsProgressNotifications();\n    SetupAPIs_XblSocial();\n    SetupAPIs_XblSocialManager();\n    SetupAPIs_XblProfile();\n    SetupAPIS_Platform();\n    SetupAPIs_LibHttp();\n    SetupAPIs_XblMultiplayer();\n    SetupAPIs_XblMultiplayerManager();\n    SetupAPIs_XblPrivacy();\n    SetupAPIs_XblEvents();\n    SetupAPIs_XblStatistics();\n    SetupAPIs_XblLeaderboard();\n    SetupAPIs_GrtsGameInvite();\n    SetupAPIs_XblRta();\n    SetupAPIs_XblPresence();\n    SetupAPIs_XblHttp();\n    SetupAPIs_XblTitleStorage();\n    SetupAPIs_XblTitleManagedStats();\n    SetupAPIs_XblStringVerify();\n    SetupAPIs_XblMultiplayerActivity();\n\n    SetupAPIs_CppAchievements();\n    SetupAPIs_CppLeaderboard();\n    SetupAPIs_CppProfile();\n    SetupAPIs_CppPrivacy();\n    SetupAPIs_CppStringVerify();\n    SetupAPIs_CppTitleStorage();\n    SetupAPIs_CppEvents();\n    SetupAPIs_CppSocial();\n    SetupAPIs_CppSocialManager();\n    SetupAPIs_CppPresence();\n    SetupAPIs_CppStatistics();\n    SetupAPIs_CppRta();\n    SetupAPIs_CppMultiplayer();\n\n    \n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    SetupupAPIs_XblGameInviteNotifications();\n    SetupAPIs_XblAchievementUnlockNotification();\n#endif\n    SetupAPIs_GRTS();\n\n    lua_register(Data()->L, \"SetCheckHR\", SetCheckHR_Lua);\n    lua_register(Data()->L, \"GetCheckHR\", GetCheckHR_Lua);\n    lua_register(Data()->L, \"StopTestFile\", StopTestFile_Lua);\n    lua_register(Data()->L, \"Sleep\", Sleep_Lua);\n    lua_register(Data()->L, \"LogToScreen\", LogToScreen_Lua);\n    lua_register(Data()->L, \"LogToFile\", LogToFile_Lua);\n    lua_register(Data()->L, \"IsRunningTests\", IsRunningTests_Lua);\n    lua_register(Data()->L, \"GetLastError\", GetLastError_Lua);\n    lua_register(Data()->L, \"SetCallUpdate\", SetCallUpdate_Lua);\n    lua_register(Data()->L, \"SetTestWasSkipped\", SetTestWasSkipped_Lua);\n    lua_register(Data()->L, \"SetOnXalTryAddFirstUserSilentlyAsync\", SetOnXalTryAddFirstUserSilentlyAsync_Lua);\n    lua_register(Data()->L, \"SetOnTaskQueueTerminateWithAsyncWait\", SetOnTaskQueueTerminateWithAsyncWait_Lua);\n\n    lua_register(Data()->L, \"MultiDeviceGetRemoteState\", MultiDeviceGetRemoteState_Lua);\n    lua_register(Data()->L, \"MultiDeviceSetLocalState\", MultiDeviceSetLocalState_Lua);\n    lua_register(Data()->L, \"MultiDeviceSyncAndWait\", MultiDeviceSyncAndWait_Lua);\n    lua_register(Data()->L, \"MultiDeviceIsHost\", MultiDeviceIsHost_Lua);\n    lua_register(Data()->L, \"MultiDeviceGetRemoteXuid\", MultiDeviceGetRemoteXuid_Lua);\n    lua_register(Data()->L, \"MultiDeviceWaitTillRemoteState\", MultiDeviceWaitTillRemoteState_Lua);\n\n    lua_register(Data()->L, \"APIRunner_MemStartTracking\", APIRunner_MemStartTracking_Lua);\n    lua_register(Data()->L, \"APIRunner_LogStats\", APIRunner_LogStats_Lua);\n    lua_register(Data()->L, \"APIRunner_AssertOnAllocOfId\", APIRunner_AssertOnAllocOfId_Lua);\n    lua_register(Data()->L, \"APIRunner_MemLogUnhookedStats\", APIRunner_MemLogUnhookedStats_Lua);\n    lua_register(Data()->L, \"IsGDKPlatform\", IsGDKPlatform_Lua);\n}\n\nvoid SetupAPIS_Platform()\n{\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\nvoid SetupAPIs_Xal();\nvoid SetupAPIs_Xbl();\nvoid SetupAPIs_Async();\nvoid SetupAPIs_XblAchievements();\nvoid SetupAPIs_XblAchievementsManager();\nvoid SetupAPIs_XblAchievementsProgressNotifications();\nvoid SetupAPIs_XblSocial();\nvoid SetupAPIs_XblSocialManager();\nvoid SetupAPIs_XblProfile();\nvoid SetupAPIS_Platform();\nvoid SetupAPIs_LibHttp();\nvoid SetupAPIs_XblMultiplayer();\nvoid SetupAPIs_XblMultiplayerManager();\nvoid SetupAPIs_XblPrivacy();\nvoid SetupAPIs_XblEvents();\nvoid SetupAPIs_XblStatistics();\nvoid SetupAPIs_XblLeaderboard();\nvoid SetupAPIs_XblRta();\nvoid SetupAPIs_GrtsGameInvite();\nvoid SetupAPIs_XblPresence();\nvoid SetupAPIs_XblHttp();\nvoid SetupAPIs_XblTitleManagedStats();\nvoid SetupAPIs_XblTitleStorage();\nvoid SetupAPIs_XblStringVerify();\nvoid SetupAPIs_GRTS();\nvoid SetupAPIs_XblMultiplayerActivity();\n\nvoid SetupAPIs_CppAchievements();\nvoid SetupAPIs_CppLeaderboard();\nvoid SetupAPIs_CppProfile();\nvoid SetupAPIs_CppPrivacy();\nvoid SetupAPIs_CppStringVerify();\nvoid SetupAPIs_CppTitleStorage();\nvoid SetupAPIs_CppEvents();\nvoid SetupAPIs_CppSocial();\nvoid SetupAPIs_CppSocialManager();\nvoid SetupAPIs_CppPresence();\nvoid SetupAPIs_CppStatistics();\nvoid SetupAPIs_CppRta();\nvoid SetupAPIs_CppMultiplayer();\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\nvoid SetupupAPIs_XblGameInviteNotifications();\nvoid SetupAPIs_XblAchievementUnlockNotification();\n#endif\n\nint LuaReturnHR(lua_State *L, HRESULT hr, int extraParams = 0);\nvoid LuaStopTestIfFailed(HRESULT hr);\nHRESULT CallLuaString(std::string str);\nHRESULT CallLuaStringWithDefault(std::string customFn, std::string defaultFn);\nHRESULT CallLuaFunction(std::string fnName);\nHRESULT CallLuaFunctionWithHr(HRESULT hr, std::string fnName);\nint StopTestFile_Lua(lua_State *L);\n\nuint64_t GetUint64FromLua(lua_State *L, int paramNum, uint64_t defaultArg);\nuint32_t GetUint32FromLua(lua_State *L, int paramNum, uint32_t defaultArg);\nbool GetBoolFromLua(lua_State *L, int paramNum, bool defaultArg);\nstd::string GetStringFromLua(lua_State *L, int paramNum, std::string defaultArg);\n\nint XalPlatformWebSetEventHandler_Lua(lua_State *L);\nint XalPlatformStorageSetEventHandlers_Lua(lua_State *L);\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_async.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint XTaskQueueCreate_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XTaskQueueCreate\n    XTaskQueueHandle queue = nullptr;\n    HRESULT hr = XTaskQueueCreate(\n        XTaskQueueDispatchMode::Manual,\n        XTaskQueueDispatchMode::Manual,\n        &queue);\n    // CODE SNIPPET END\n\n    Data()->queue = queue;\n    LogToFile(\"XTaskQueueCreate: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XTaskQueueDuplicateHandle_Lua(lua_State *L)\n{\n    XTaskQueueHandle queue = Data()->queue;\n\n    // CODE SNIPPET START: XTaskQueueDuplicateHandle\n    XTaskQueueHandle newQueue = nullptr;\n    HRESULT hr = XTaskQueueDuplicateHandle(\n        queue,\n        &newQueue);\n    // CODE SNIPPET END\n    XTaskQueueCloseHandle(newQueue);\n    return LuaReturnHR(L, hr);\n}\n\nint XTaskQueueDispatch_Lua(lua_State *L)\n{\n    XTaskQueueHandle queue = Data()->queue;\n\n    // CODE SNIPPET START: XTaskQueueDispatch\n    HRESULT hr = XTaskQueueDispatch(queue, XTaskQueuePort::Completion, 0);\n    // CODE SNIPPET END\n    LogToFile(\"XTaskQueueDispatch: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XTaskQueueCloseHandle_Lua(lua_State *L)\n{\n    XTaskQueueHandle queue = Data()->queue;\n\n    // CODE SNIPPET START: XTaskQueueCloseHandle\n    if (queue != nullptr) \n    {\n        XTaskQueueCloseHandle(queue);\n    }\n    // CODE SNIPPET END\n    Data()->queue = nullptr;\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XTaskQueueTerminate_Lua(lua_State *L)\n{\n    XTaskQueueHandle queue = Data()->queue;\n\n    // CODE SNIPPET START: XTaskQueueTerminate\n    HRESULT hr = XTaskQueueTerminate(queue, true, nullptr, nullptr);\n    // CODE SNIPPET END\n\n    LogToFile(\"XTaskQueueTerminate: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint XTaskQueueTerminateWithAsyncWait_Lua(lua_State *L)\n{\n    XTaskQueueHandle queue = Data()->queue;\n    HRESULT hr = S_OK;\n    if (queue == nullptr)\n    {\n        Data()->m_stopTest = true;\n        LogToFile(\"XTaskQueueTerminate with async wait: hr=%s\", ConvertHR(hr).c_str());\n        return LuaReturnHR(L, hr);\n    }\n    else\n    {\n        hr = XTaskQueueTerminate(queue, false, nullptr, [](void*)\n        {\n            CallLuaStringWithDefault(Data()->m_onTaskQueueTerminateWithAsyncWait, \"common = require 'common'; common.cleanup()\");\n            LogToFile(\"StopTest\\n\");\n            Data()->m_stopTest = true;\n        });\n    }\n\n    LogToFile(\"XTaskQueueTerminate with async wait: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XTaskQueueSetCurrentProcessTaskQueue_Lua(lua_State *L)\n{\n    auto luaHandle = GetUint64FromLua(L, 1, 0);\n    // CODE SNIPPET START: XTaskQueueSetCurrentProcessTaskQueue\n    XTaskQueueHandle queue = nullptr;\n    // CODE SKIP START\n    if (luaHandle != 0)\n    {\n        queue = reinterpret_cast<XTaskQueueHandle>(luaHandle);\n    }\n    // CODE SKIP END\n    XTaskQueueSetCurrentProcessTaskQueue(queue);\n    // CODE SNIPPET END\n\n    LogToFile(\"XTaskQueueSetCurrentProcessTaskQueue\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XTaskQueueGetCurrentProcessTaskQueue_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XTaskQueueGetCurrentProcessTaskQueue\n    XTaskQueueHandle queue = nullptr;\n    XTaskQueueGetCurrentProcessTaskQueue(&queue);\n    // CODE SNIPPET END\n\n    LogToFile(\"XTaskQueueGetCurrentProcessTaskQueue 0x%0.8x\", queue);\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(queue));\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nstd::thread g_dispatchThread{};\nbool g_dispatch = false;\n\nint StartManualDispatchThread_Lua(lua_State* L)\n{\n    g_dispatch = true;\n    g_dispatchThread = std::thread{ []()\n    {\n        while (g_dispatch)\n        {\n            auto queue = Data()->queue;\n\n            bool workAvailable = true;\n            while (workAvailable)\n            {\n                workAvailable = XTaskQueueDispatch(queue, XTaskQueuePort::Work, 0);\n            }\n\n            workAvailable = true;\n            while (workAvailable)\n            {\n                workAvailable = XTaskQueueDispatch(queue, XTaskQueuePort::Completion, 0);\n            }\n\n            pal::Sleep(10);\n        }\n    }\n    };\n\n    g_dispatchThread.detach();\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint StopManualDispatchThread_Lua(lua_State* L)\n{\n    g_dispatch = false;\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_Async()\n{\n    lua_register(Data()->L, \"XTaskQueueCreate\", XTaskQueueCreate_Lua);\n    lua_register(Data()->L, \"XTaskQueueDuplicateHandle\", XTaskQueueDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XTaskQueueDispatch\", XTaskQueueDispatch_Lua);\n    lua_register(Data()->L, \"XTaskQueueCloseHandle\", XTaskQueueCloseHandle_Lua);\n    lua_register(Data()->L, \"XTaskQueueTerminate\", XTaskQueueTerminate_Lua);\n    lua_register(Data()->L, \"XTaskQueueTerminateWithAsyncWait\", XTaskQueueTerminateWithAsyncWait_Lua);\n    lua_register(Data()->L, \"XTaskQueueSetCurrentProcessTaskQueue\", XTaskQueueSetCurrentProcessTaskQueue_Lua);\n    lua_register(Data()->L, \"XTaskQueueGetCurrentProcessTaskQueue\", XTaskQueueGetCurrentProcessTaskQueue_Lua);\n   \n    //lua_register(Data()->L, \"XTaskQueueGetPort\", XTaskQueueGetPort_Lua);\n    //lua_register(Data()->L, \"XTaskQueueCreateComposite\", XTaskQueueCreateComposite_Lua);\n    //lua_register(Data()->L, \"XTaskQueueSubmitCallback\", XTaskQueueSubmitCallback_Lua);\n    //lua_register(Data()->L, \"XTaskQueueSubmitDelayedCallback\", XTaskQueueSubmitDelayedCallback_Lua);\n    //lua_register(Data()->L, \"XTaskQueueRegisterWaiter\", XTaskQueueRegisterWaiter_Lua);\n    //lua_register(Data()->L, \"XTaskQueueUnregisterWaiter\", XTaskQueueUnregisterWaiter_Lua);\n    //lua_register(Data()->L, \"XTaskQueueRegisterMonitor\", XTaskQueueRegisterMonitor_Lua);\n    //lua_register(Data()->L, \"XTaskQueueUnregisterMonitor\", XTaskQueueUnregisterMonitor_Lua);\n\n    // Helper methods\n    lua_register(Data()->L, \"StartManualDispatchThread\", StartManualDispatchThread_Lua);\n    lua_register(Data()->L, \"StopManualDispatchThread\", StopManualDispatchThread_Lua);\n}\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_achievements.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#if CPP_TESTS_ENABLED\n\nxbox::services::achievements::achievement_type ConvertStringToCppAchievementType(const char* str)\n{\n    xbox::services::achievements::achievement_type type = xbox::services::achievements::achievement_type::unknown;\n\n    if (pal::stricmp(str, \"XblAchievementType::Unknown\") == 0) type = xbox::services::achievements::achievement_type::unknown;\n    else if (pal::stricmp(str, \"XblAchievementType::All\") == 0) type = xbox::services::achievements::achievement_type::all;\n    else if (pal::stricmp(str, \"XblAchievementType::Persistent\") == 0) type = xbox::services::achievements::achievement_type::persistent;\n    else if (pal::stricmp(str, \"XblAchievementType::Challenge\") == 0) type = xbox::services::achievements::achievement_type::challenge;\n\n    return type;\n}\n\nxbox::services::achievements::achievement_order_by ConvertStringToCppAchievementOrderBy(const char* str)\n{\n    xbox::services::achievements::achievement_order_by orderBy = xbox::services::achievements::achievement_order_by::default_order;\n\n    if (pal::stricmp(str, \"XblAchievementOrderBy::DefaultOrder\") == 0) orderBy = xbox::services::achievements::achievement_order_by::default_order;\n    else if (pal::stricmp(str, \"XblAchievementOrderBy::TitleId\") == 0) orderBy = xbox::services::achievements::achievement_order_by::title_id;\n    else if (pal::stricmp(str, \"XblAchievementOrderBy::UnlockTime\") == 0) orderBy = xbox::services::achievements::achievement_order_by::unlock_time;\n\n    return orderBy;\n}\n\n#endif\n\nint AchievementsResultHasNextCpp_Lua(lua_State* L)\n{\n    bool hasNext = false;\n#if CPP_TESTS_ENABLED\n    hasNext = Data()->achievementsResultCpp.has_next();\n    LogToFile(\"AchievementsResultHasNextCpp: hasNext=%s\", hasNext ? \"true\" : \"false\");\n#else\n    LogToFile(\"AchievementsResultHasNextCpp disabled for this platform.\");\n#endif\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint AchievementsResultGetNextCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    uint32_t maxItems = GetUint32FromLua(L, 1, 100);\n    LogToFile(\"XblAchievementsResultGetNextAsync: MaxItems: %d\", maxItems);\n\n    Data()->achievementsResultCpp.get_next(maxItems).then(\n        [](xbox::services::xbox_live_result<xbox::services::achievements::achievements_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::achievements::achievements_result achievementsResult = result.payload();\n                Data()->achievementsResultCpp = xbox::services::achievements::achievements_result(achievementsResult);\n\n                auto achievements = achievementsResult.items();\n                size_t achievementsCount = achievements.size();\n\n                LogToFile(\"AchievementsServiceGetAchievementsForTitleId: Got achievementsCount: %d\", achievementsCount);\n\n                for (size_t i = 0; i < achievementsCount; i++)\n                {\n                    LogToScreen(\"Achievement %s: %s = %s\",\n                        xbox::services::Utils::StringFromStringT(achievements[i].id()).c_str(),\n                        xbox::services::Utils::StringFromStringT(achievements[i].name()).c_str(),\n                        (achievements[i].progress_state() == xbox::services::achievements::achievement_progress_state::achieved) ? \"Achieved\" : \"Not achieved\");\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnAchievementsResultGetNextCpp\");\n        }\n    );\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnAchievementsResultGetNextCpp\");\n    LogToFile(\"AchievementsResultGetNextCpp disabled for this platform.\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint AchievementsServiceGetAchievementsForTitleId_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::achievements::achievement_type achievementType = ConvertStringToCppAchievementType(GetStringFromLua(L, 1, \"XblAchievementType::All\").c_str());\n    bool unlockedOnly = GetBoolFromLua(L, 2, false);\n    xbox::services::achievements::achievement_order_by orderBy = ConvertStringToCppAchievementOrderBy(GetStringFromLua(L, 3, \"XblAchievementOrderBy::DefaultOrder\").c_str());\n    uint32_t skipItems = GetUint32FromLua(L, 4, 0);\n    uint32_t maxItems = GetUint32FromLua(L, 5, 100);\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n\n    LogToFile(\"AchievementsServiceGetAchievementsForTitleId: AchievementType: %d\", achievementType);\n    LogToFile(\"AchievementsServiceGetAchievementsForTitleId: unlockedOnly: %s\", unlockedOnly ? \"true\" : \"false\");\n    LogToFile(\"AchievementsServiceGetAchievementsForTitleId: OrderBy: %d\", orderBy);\n    LogToFile(\"AchievementsServiceGetAchievementsForTitleId: SkipItems: %d\", skipItems);\n    LogToFile(\"AchievementsServiceGetAchievementsForTitleId: MaxItems: %d\", maxItems);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->achievement_service().get_achievements_for_title_id(\n        xboxUserId,\n        Data()->titleId,\n        achievementType,\n        unlockedOnly,\n        orderBy,\n        skipItems,\n        maxItems\n    ).then([](xbox::services::xbox_live_result < xbox::services::achievements::achievements_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"AchievementsServiceGetAchievementsForTitleId: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::achievements::achievements_result achievementsResult = result.payload();\n                Data()->achievementsResultCpp = xbox::services::achievements::achievements_result(achievementsResult);\n\n                auto achievements = achievementsResult.items();\n                size_t achievementsCount = achievements.size();\n\n                LogToFile(\"AchievementsServiceGetAchievementsForTitleId: Got achievementsCount: %d\", achievementsCount);\n\n                for (size_t i = 0; i < achievementsCount; i++)\n                {\n                    LogToScreen(\"Achievement %s: %s = %s\",\n                        xbox::services::Utils::StringFromStringT(achievements[i].id()).c_str(),\n                        xbox::services::Utils::StringFromStringT(achievements[i].name()).c_str(),\n                        (achievements[i].progress_state() == xbox::services::achievements::achievement_progress_state::achieved) ? \"Achieved\" : \"Not achieved\");\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnAchievementsServiceGetAchievementsForTitleId\");\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnAchievementsServiceGetAchievementsForTitleId\");\n    LogToFile(\"AchievementsServiceGetAchievementsForTitleId disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint AchievementsServiceGetAchievement_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    auto achievementId = GetStringFromLua(L, 1, \"1\");\n    LogToFile(\"XblAchievementsGetAchievementAsync: AchievementId: %s\", achievementId.c_str());\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    string_t serviceConfigId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    string_t achievementIdString = xbox::services::Utils::StringTFromUtf8(achievementId.c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->achievement_service().get_achievement(\n        xboxUserId,\n        serviceConfigId,\n        achievementIdString\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::achievements::achievement> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"AchievementsServiceGetAchievement: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::achievements::achievement achievement = result.payload();\n\n                LogToScreen(\"Achievement %s: %s = %s\",\n                    xbox::services::Utils::StringFromStringT(achievement.id()).c_str(),\n                    xbox::services::Utils::StringFromStringT(achievement.name()).c_str(),\n                    (achievement.progress_state() == xbox::services::achievements::achievement_progress_state::achieved) ? \"Achieved\" : \"Not achieved\");\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnAchievementsServiceGetAchievement\");\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnAchievemementsServiceGetAchievement\");\n    LogToFile(\"AchievemementsServiceGetAchievement disabled for this platform.\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n\n}\n\nint AchievementsServiceUpdateAchievement_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    auto achievementId = GetStringFromLua(L, 1, \"1\");\n    uint32_t percentComplete = GetUint32FromLua(L, 2, 100);\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: AchievementId: %s\", achievementId.c_str());\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: PercentComplete: %d\", percentComplete);\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    string_t achievementIdString = xbox::services::Utils::StringTFromUtf8(achievementId.c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->achievement_service().update_achievement(\n        xboxUserId,\n        achievementIdString,\n        percentComplete\n    ).then(\n        [](xbox::services::xbox_live_result <void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"AchievementsServiceUpdateAchievement: hr=%s\", ConvertHR(hr).c_str());\n            if (SUCCEEDED(hr))\n            {\n                //Achievement Updated\n            }\n            else if (hr == HTTP_E_STATUS_NOT_MODIFIED)\n            {\n                //Achievement Not Modified\n            }\n            else\n            {\n                //Achievement Failed to Update\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnAchievementsServiceUpdateAchievement\");\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnAchievementsServiceUpdateAchievement\");\n    LogToFile(\"AchievementsServiceUpdateAchievement disabled for this platform.\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint AchievementsServiceUpdateAchievementForTitleId_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    auto achievementId = GetStringFromLua(L, 1, \"1\");\n    uint32_t percentComplete = GetUint32FromLua(L, 2, 100);\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: AchievementId: %s\", achievementId.c_str());\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: PercentComplete: %d\", percentComplete);\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    string_t serviceConfigId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    string_t achievementIdString = xbox::services::Utils::StringTFromUtf8(achievementId.c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->achievement_service().update_achievement(\n        xboxUserId,\n        Data()->titleId,\n        serviceConfigId,\n        achievementIdString,\n        percentComplete\n    ).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"AchievementsServiceUpdateAchievementForTitleId: hr=%s\", ConvertHR(hr).c_str());\n            if (SUCCEEDED(hr))\n            {\n                //Achievement Updated\n            }\n            else if (hr == HTTP_E_STATUS_NOT_MODIFIED)\n            {\n                //Achievement Not Modified\n            }\n            else\n            {\n                //Achievement Failed to Update\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnAchievementServiceUpdateAchievementForTitleId\");\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnAchievementServiceUpdateAchievementForTitleId\");\n    LogToFile(\"AchievementServiceUpdateAchievementForTitleId disabled for this platform.\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppAchievements()\n{\n    lua_register(Data()->L, \"AchievementsResultGetNextCpp\", AchievementsResultGetNextCpp_Lua);\n    lua_register(Data()->L, \"AchievementsResultHasNextCpp\", AchievementsResultHasNextCpp_Lua);\n    lua_register(Data()->L, \"AchievementsServiceGetAchievement\", AchievementsServiceGetAchievement_Lua);\n    lua_register(Data()->L, \"AchievementsServiceGetAchievementsForTitleId\", AchievementsServiceGetAchievementsForTitleId_Lua);\n    lua_register(Data()->L, \"AchievementsServiceUpdateAchievement\", AchievementsServiceUpdateAchievement_Lua);\n    lua_register(Data()->L, \"AchievementsServiceUpdateAchievementForTitleId\", AchievementsServiceUpdateAchievementForTitleId_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_events.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint EventsServiceWriteInGameEvent_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED && HC_PLATFORM != HC_PLATFORM_XDK\n    string_t eventName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"PuzzleSolved\").c_str());\n    string_t dimensionsJson = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"{\\\"DifficultyLevelId\\\":100,\\\"EnemyRoleId\\\":3,\\\"GameplayModeId\\\":\\\"gameplay mode id\\\",\\\"KillTypeId\\\":4,\\\"MultiplayerCorrelationId\\\":\\\"multiplayer correlation id\\\",\\\"PlayerRoleId\\\":1,\\\"PlayerWeaponId\\\":2,\\\"RoundId\\\":1}\").c_str());\n    string_t measurementsJson = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, \"{\\\"LocationX\\\":1,\\\"LocationY\\\":2.12121,\\\"LocationZ\\\":-90909093}\").c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xbox::services::xbox_live_result<void> result = xblc->events_service().write_in_game_event(\n        eventName,\n        web::json::value::parse(dimensionsJson),\n        web::json::value::parse(measurementsJson)\n    );\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    LogToFile(\"EventsServiceWriteInGameEvent: hr=%s\", ConvertHR(hr).c_str());\n#else\n    HRESULT hr = S_OK;\n    LogToFile(\"EventsServiceWriteInGameEvent is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_CppEvents()\n{\n    lua_register(Data()->L, \"EventsServiceWriteInGameEvent\", EventsServiceWriteInGameEvent_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_leaderboard.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint LeaderboardServiceGetLeaderboard_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t scid = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"00000000-0000-0000-0000-000076029b4d\").c_str());\n    string_t leaderboardName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"TotalPuzzlesSolvedLB\").c_str());\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 3, Data()->xboxUserId));\n    string_t socialGroup = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 8, \"XblSocialGroupType::None\").c_str());\n    uint32_t maxItems = GetUint32FromLua(L, 5, 0);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->leaderboard_service().get_leaderboard(\n        scid,\n        leaderboardName,\n        xboxUserId,\n        socialGroup,\n        maxItems\n    ).then(\n        [xblc](xbox::services::xbox_live_result<xbox::services::leaderboard::leaderboard_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"LeaderboardServiceGetLeaderboard: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::leaderboard::leaderboard_result leaderboardResult{ result.payload() };\n                Data()->leaderboardResultCpp = leaderboardResult;\n\n                LogToScreen(\"Got %d rows in leaderboard\", leaderboardResult.rows().size());\n                for (size_t row = 0; row < leaderboardResult.rows().size(); ++row)\n                {\n                    std::stringstream rowText;\n                    rowText << xbox::services::Utils::Uint64FromStringT(leaderboardResult.rows()[row].xbox_user_id()) << \"\\t\";\n\n                    for (size_t column = 0; column < leaderboardResult.rows()[row].column_values().size(); ++column)\n                    {\n                        rowText << xbox::services::Utils::StringFromStringT(leaderboardResult.rows()[row].column_values()[column]) << \"\\t\";\n                    }\n                    LogToFile(rowText.str().data());\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnLeaderboardServiceGetLeaderboard\");\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnLeaderboardServiceGetLeaderboard\");\n    LogToFile(\"LeaderboardServiceGetLeaderboard disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint LeaderboardResultHasNextCpp_Lua(lua_State* L)\n{\n    bool hasNext = false;\n#if CPP_TESTS_ENABLED\n    hasNext = Data()->leaderboardResultCpp.has_next();\n    LogToFile(\"LeaderboardResultHasNextCpp: hasNext=%s\", hasNext ? \"true\" : \"false\");\n#else\n    LogToFile(\"LeaderboardResultHasNextCpp disabled for this platform.\");\n#endif\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint LeaderboardResultGetNextCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    uint32_t maxItems = GetUint32FromLua(L, 1, 0);\n    LogToFile(\"LeaderboardResultGetNextCpp: maxItems: %d\", maxItems);\n\n    Data()->leaderboardResultCpp.get_next(maxItems).then(\n        [](xbox::services::xbox_live_result<xbox::services::leaderboard::leaderboard_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"LeaderboardResultGetNextCpp: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::leaderboard::leaderboard_result leaderboardResult{ result.payload() };\n                Data()->leaderboardResultCpp = leaderboardResult;\n\n                LogToScreen(\"Got %d rows in leaderboard\", leaderboardResult.rows().size());\n                for (size_t row = 0; row < leaderboardResult.rows().size(); ++row)\n                {\n                    std::stringstream rowText;\n                    rowText << xbox::services::Utils::Uint64FromStringT(leaderboardResult.rows()[row].xbox_user_id()) << \"\\t\";\n\n                    for (size_t column = 0; column < leaderboardResult.rows()[row].column_values().size(); ++column)\n                    {\n                        rowText << xbox::services::Utils::StringFromStringT(leaderboardResult.rows()[row].column_values()[column]) << \"\\t\";\n                    }\n                    LogToFile(rowText.str().data());\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnLeaderboardResultGetNextCpp\");\n        }\n    );\n\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnLeaderboardResultGetNextCpp\");\n    LogToFile(\"LeaderboardResultGetNextCpp disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\n\nvoid SetupAPIs_CppLeaderboard()\n{\n    lua_register(Data()->L, \"LeaderboardServiceGetLeaderboard\", LeaderboardServiceGetLeaderboard_Lua);\n    lua_register(Data()->L, \"LeaderboardResultGetNextCpp\", LeaderboardResultGetNextCpp_Lua);\n    lua_register(Data()->L, \"LeaderboardResultHasNextCpp\", LeaderboardResultHasNextCpp_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_multiplayer.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nusing namespace utility;\n\n#if CPP_TESTS_ENABLED\nstruct MultiplayerStateCpp\n{\n    std::vector<std::shared_ptr<xbox::services::multiplayer::multiplayer_session>> sessionHandles;\n    xbox::services::multiplayer::multiplayer_session_reference sessionRef;\n    std::shared_ptr<xbox::services::multiplayer::multiplayer_search_handle_details> searchHandleDetails;\n    std::string inviteHandle{};\n    function_context sessionChangedContext{ 0 };\n    function_context subscriptionLostContext{ 0 };\n    function_context connectionIdChangedContext{ 0 };\n    std::string activityHandle{};\n\n    static std::string GetSessionName(uint64_t sessionId = 0) noexcept\n    {\n        // ID to make session names unique per API runner run\n#if HC_PLATFORM == HC_PLATFORM_GDK\n        ULARGE_INTEGER largeInt;\n        FILETIME fileTime;\n        GetSystemTimeAsFileTime(&fileTime);\n\n        largeInt.LowPart = fileTime.dwLowDateTime;\n        largeInt.HighPart = fileTime.dwHighDateTime;\n\n        static uint64_t runId{ largeInt.QuadPart };\n#else\n        static uint64_t runId{ datetime::utc_now().to_interval() };\n#endif\n\n        std::stringstream ss;\n        ss << \"GameSession-\" << runId << \"-ID\" << sessionId;\n        return ss.str();\n    }\n};\nstd::unique_ptr<MultiplayerStateCpp> g_multiplayerStateCpp;\n\nMultiplayerStateCpp* MPStateCpp()\n{\n    if (!g_multiplayerStateCpp)\n    {\n        g_multiplayerStateCpp = std::make_unique<MultiplayerStateCpp>();\n        g_multiplayerStateCpp->sessionHandles.resize(10);\n    }\n    return g_multiplayerStateCpp.get();\n}\n\n\nxbox::services::multiplayer::multiplayer_session_write_mode ConvertStringToCppMultiplayerSessionWriteMode(const char* str)\n{\n    xbox::services::multiplayer::multiplayer_session_write_mode writeMode = xbox::services::multiplayer::multiplayer_session_write_mode::update_or_create_new;\n\n    if (pal::stricmp(str, \"multiplayer_session_write_mode::synchronized_update\") == 0) writeMode = xbox::services::multiplayer::multiplayer_session_write_mode::synchronized_update;\n    else if (pal::stricmp(str, \"multiplayer_session_write_mode::create_new\") == 0) writeMode = xbox::services::multiplayer::multiplayer_session_write_mode::create_new;\n    else if (pal::stricmp(str, \"multiplayer_session_write_mode::update_existing\") == 0) writeMode = xbox::services::multiplayer::multiplayer_session_write_mode::update_existing;\n\n    return writeMode;\n}\n\n//multiplayer_session_reference\n\nvoid LogSessionRef(const xbox::services::multiplayer::multiplayer_session_reference* sessionRef)\n{\n    LogToFile(\"Scid:%s\", xbox::services::Utils::StringFromStringT(sessionRef->service_configuration_id()).c_str());\n    LogToFile(\"SessionName:%s\", xbox::services::Utils::StringFromStringT(sessionRef->session_name()).c_str());\n    LogToFile(\"SessionTemplateName:%s\", xbox::services::Utils::StringFromStringT(sessionRef->session_template_name()).c_str());\n}\n\nint MultiplayerSessionReferenceIsValidCpp_Lua(lua_State *L)\n{\n    bool isValid = !MPStateCpp()->sessionRef.is_null();\n    LogToFile(\"MultiplayerSessionReferenceIsValidCpp isValid:%d\", isValid);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionReferenceCreateCpp_Lua(lua_State* L)\n{\n    string_t scid = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, Data()->scid).c_str());\n    string_t sessionTemplateName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"MinGameSession\").c_str());\n    string_t sessionName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, MultiplayerStateCpp::GetSessionName()).c_str());\n\n    MPStateCpp()->sessionRef = xbox::services::multiplayer::multiplayer_session_reference(scid, sessionTemplateName, sessionName);\n\n    LogToFile(\"MultiplayerSessionReferenceCreateCpp\");\n    LogSessionRef(&MPStateCpp()->sessionRef);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionReferenceParseFromUriPathCpp_Lua(lua_State* L)\n{\n    string_t path = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"\").c_str());\n    if (path.empty())\n    {\n        stringstream_t ss;\n        ss << L\"/serviceconfigs/00000000-0000-0000-0000-000076029b4d/sessionTemplates/MinGameSession/sessions/\";\n        ss << xbox::services::Utils::StringTFromUtf8(MultiplayerStateCpp::GetSessionName().c_str());\n        path = ss.str();\n    }\n\n    MPStateCpp()->sessionRef.parse_from_uri_path(path);\n    LogToFile(\"MultiplayerSessionReferenceParseFromUriPathCpp\");\n    LogToFile(\"Scid:%s\", xbox::services::Utils::StringFromStringT(MPStateCpp()->sessionRef.service_configuration_id()).c_str());\n    LogToFile(\"SessionName:%s\", xbox::services::Utils::StringFromStringT(MPStateCpp()->sessionRef.session_name()).c_str());\n    LogToFile(\"SessionTemplateName:%s\", xbox::services::Utils::StringFromStringT(MPStateCpp()->sessionRef.session_template_name()).c_str());\n\n    return LuaReturnHR(L, S_OK);\n}\n\n//multitplayer_session\n\nstd::shared_ptr<xbox::services::multiplayer::multiplayer_session> GetSessionHandleFromArgCpp(lua_State *L, int paramNum, uint64_t* sessionIndexOut = nullptr)\n{\n    uint64_t sessionIndex { GetUint64FromLua(L, paramNum, 0) };\n    assert(MPStateCpp()->sessionHandles.size() > sessionIndex);\n    if (sessionIndexOut != nullptr)\n    {\n        *sessionIndexOut = sessionIndex;\n    }\n    return MPStateCpp()->sessionHandles[static_cast<uint32_t>(sessionIndex)];\n}\n\nint MultiplayerSessionCreateCpp_Lua(lua_State *L)\n{\n    string_t scid = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, Data()->scid).c_str());\n    string_t sessionTemplateName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"MinGameSession\").c_str());\n    uint64_t sessionIndex{ GetUint64FromLua(L, 4, 0) };\n    string_t sessionName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, \"\").c_str());\n    if (sessionName.empty())\n    {\n        sessionName = xbox::services::Utils::StringTFromUtf8(MultiplayerStateCpp::GetSessionName(sessionIndex).c_str());\n    }\n\n    xbox::services::multiplayer::multiplayer_session_reference sessionRef(scid, sessionTemplateName, sessionName);\n    string_t xuid = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n\n    MPStateCpp()->sessionHandles[static_cast<uint32_t>(sessionIndex)] = std::make_shared<xbox::services::multiplayer::multiplayer_session>(xuid, sessionRef);\n\n    lua_pushinteger(L, static_cast<lua_Integer>(sessionIndex));\n    LogToFile(\"MultiplayerSessionCreateCpp\");\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint MultiplayerSessionJoinCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    string_t memberCustomConstantsJsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"{}\").c_str());\n    bool initializeRequested = GetBoolFromLua(L, 3, true);\n    bool joinWithActiveStatus = GetBoolFromLua(L, 4, true);\n    bool addInitializePropertyToRequest = GetBoolFromLua(L, 5, true);\n\n    web::json::value memberCustomConstantsJson = web::json::value::parse(memberCustomConstantsJsonString);\n\n    sessionHandle->join(memberCustomConstantsJson, initializeRequested, joinWithActiveStatus, addInitializePropertyToRequest);\n\n    LogToFile(\"MultiplayerSessionJoinCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionAddMemberReservationCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    string_t xuid = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 2, 2814636782672891));\n    string_t memberCustomConstantsJsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, \"{}\").c_str());\n    web::json::value memberCustomConstantsJson = web::json::value::parse(memberCustomConstantsJsonString);\n    bool initializeRequested = GetBoolFromLua(L, 4, true);\n\n    \n    sessionHandle->add_member_reservation(xuid, memberCustomConstantsJson, initializeRequested);\n\n    LogToFile(\"MultiplayerSessionAddMemberReservationCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\n\nint MultiplayerSessionTimeOfSessionCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    datetime timeOfSession = sessionHandle->date_of_session();\n\n    LogToFile(\"MultiplayerSessionStartTime timeOfSession:%s\", xbox::services::Utils::StringFromStringT(timeOfSession.to_string()).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionGetInitializationInfoCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    xbox::services::multiplayer::multiplayer_initialization_stage stage = sessionHandle->initialization_stage();\n    datetime stageStartTime = sessionHandle->initializing_stage_start_time();\n    uint32_t episode = sessionHandle->intializing_episode();\n\n    LogToFile(\"MultiplayerSessionGetInitializationInfoCpp\");\n    LogToFile(\"Stage: %d\", stage);\n    LogToFile(\"StageStartTime: %ul\", stageStartTime);\n    LogToFile(\"Episode: %d\", episode);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSubscribedChangeTypesCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    xbox::services::multiplayer::multiplayer_session_change_types changeTypes = sessionHandle->subscribed_change_types();\n\n    LogToFile(\"MultiplayerSessionSubscribedChangeTypesCpp\");\n    LogToFile(\"changeTypes: 0x%0.4x\", changeTypes);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionHostCandidatesCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    std::vector<string_t> hostCandidates = sessionHandle->host_candidates();\n\n    LogToFile(\"MultiplayerSessionHostCandidatesCpp:\");\n    for (string_t hostCandidate : hostCandidates)\n    {\n        LogToFile(xbox::services::Utils::StringFromStringT(hostCandidate).c_str());\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSessionReferenceCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    xbox::services::multiplayer::multiplayer_session_reference sessionRef = sessionHandle->session_reference();\n\n    LogToFile(\"MultiplayerSessionSessionReferenceCpp\");\n    LogToFile(\"Scid:%s\", xbox::services::Utils::StringFromStringT(sessionRef.service_configuration_id()).c_str());\n    LogToFile(\"SessionName:%s\", xbox::services::Utils::StringFromStringT(sessionRef.session_name()).c_str());\n    LogToFile(\"SessionTemplateName:%s\", xbox::services::Utils::StringFromStringT(sessionRef.session_template_name()).c_str());\n    \n    MPStateCpp()->sessionRef = sessionRef;\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSessionConstantsCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    auto sessionConstants = sessionHandle->session_constants();\n\n    LogToFile(\"MultiplayerSessionSessionConstantsCpp\");\n    LogToFile(\"MaxMembersInSession: %d\", sessionConstants->max_members_in_session());\n    LogToFile(\"Visibility: %d\", sessionConstants->visibility());\n    LogToFile(\"InitiatorXuidsSize: %ul\", sessionConstants->initiator_xbox_user_ids().size());\n    LogToFile(\"CustomJson: %s\", xbox::services::Utils::StringFromStringT(sessionConstants->session_custom_constants_json().serialize()).c_str());\n    LogToFile(\"SessionCloudComputePackageConstantsJson: %s\", xbox::services::Utils::StringFromStringT(sessionConstants->session_cloud_compute_package_constants_json().serialize()).c_str());\n    LogToFile(\"MemberReservedTimeout: %ul\", sessionConstants->member_reserved_time_out());\n    LogToFile(\"MemberInactiveTimeout: %ul\", sessionConstants->member_inactive_timeout());\n    LogToFile(\"MemberReadyTimeout: %ul\", sessionConstants->member_ready_timeout());\n    LogToFile(\"SessionEmptyTimeout: %ul\", sessionConstants->session_empty_timeout());\n    LogToFile(\"EnableMetricsLatency: %d\", sessionConstants->enable_metrics_latency());\n    LogToFile(\"EnableMetricsBandwidthDown: %d\", sessionConstants->enable_metrics_bandwidth_down());\n    LogToFile(\"EnableMetricsBandwidthUp: %d\", sessionConstants->enable_metrics_bandwidth_up());\n    LogToFile(\"EnableMetricsCustom: %d\", sessionConstants->enable_metrics_custom());\n    LogToFile(\"PeerToPeerRequirements->LatencyMaximum: %ul\", sessionConstants->peer_to_peer_requirements().latency_maximum());\n    LogToFile(\"PeerToPeerRequirements->BandwidthMinimumInKbps: %ul\", sessionConstants->peer_to_peer_requirements().bandwidth_minimum_in_kilobits_per_second());\n    LogToFile(\"PeerToHostRequirements->LatencyMaximum: %ul\", sessionConstants->peer_to_host_requirements().latency_maximum());\n    LogToFile(\"PeerToHostRequirements->BandwidthMinimumInKbps: %ul\", sessionConstants->peer_to_host_requirements().bandwidth_down_minimum_in_kilobits_per_second());\n    LogToFile(\"PeerToHostRequirements->BandwidthUpMinimumInKbps: %ul\", sessionConstants->peer_to_host_requirements().bandwidth_up_minimum_in_kilobits_per_second());\n    LogToFile(\"PeerToHostRequirements->HostSelectionMetric: %ul\", sessionConstants->peer_to_host_requirements().host_selection_metric());\n    LogToFile(\"MeasurementServerAddressesJson: %s\", xbox::services::Utils::StringFromStringT(sessionConstants->measurement_server_addresses_json().serialize()).c_str());\n    LogToFile(\"ClientMatchmakingCapable: %d\", sessionConstants->client_matchmaking_capable());\n    LogToFile(\"EnableMetricsCustom: %d\", sessionConstants->enable_metrics_custom());\n    LogToFile(\"CapabilitiesConnectivity: %d\", sessionConstants->capabilities_connectivity());\n    LogToFile(\"CapabilitiesSuppressPresenceActivityCheck: %d\", sessionConstants->capabilities_suppress_presence_activity_check());\n    LogToFile(\"CapabilitiesGameplay: %d\", sessionConstants->capabilities_gameplay());\n    LogToFile(\"CapabilitiesLarge: %d\", sessionConstants->capabilities_large());\n    LogToFile(\"CapabilitiesConnectionRequiredForActiveMembers: %d\", sessionConstants->capabilities_connection_required_for_active_member());\n    LogToFile(\"CapabilitiesUserAuthorizationStyle: %d\", sessionConstants->capabilities_user_authorization_style());\n    LogToFile(\"CapabilitiesCrossplay: %d\", sessionConstants->capabilities_crossplay());\n    LogToFile(\"CapabilitiesSearchable: %d\", sessionConstants->capabilities_searchable());\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetVisibilityCpp_Lua(lua_State *L)\n{\n    xbox::services::multiplayer::multiplayer_session_visibility visibility = static_cast<xbox::services::multiplayer::multiplayer_session_visibility>(GetUint32FromLua(L, 1, 3));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_visibility(visibility);\n\n    LogToFile(\"MultiplayerSessionSetVisibilityCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMaxMembersInSessionCpp_Lua(lua_State *L)\n{\n    uint32_t maxMembersInSession = GetUint32FromLua(L, 1, 10);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_max_members_in_session(maxMembersInSession);\n\n    LogToFile(\"MultiplayerSessionSetMaxMembersInSessionCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetTimeoutsCpp_Lua(lua_State *L)\n{\n    std::chrono::milliseconds memberReservedTimeout{ GetUint64FromLua(L, 1, 100) };\n    std::chrono::milliseconds memberInactiveTimeout{ GetUint64FromLua(L, 2, 100) };\n    std::chrono::milliseconds memberReadyTimeout{ GetUint64FromLua(L, 3, 100) };\n    std::chrono::milliseconds sessionEmptyTimeout{ GetUint64FromLua(L, 4, 100) };\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 5);\n    sessionHandle->set_timeouts(memberReservedTimeout, memberInactiveTimeout, memberReadyTimeout, sessionEmptyTimeout);\n\n    LogToFile(\"MultiplayerSessionSetTimeoutsCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetQosConnectivityMetricsCpp_Lua(lua_State *L)\n{\n    bool enableLatencyMetric = GetBoolFromLua(L, 1, false);\n    bool enableBandwidthDownMetric = GetBoolFromLua(L, 2, false);\n    bool enableBandwidthUpMetric = GetBoolFromLua(L, 3, false);\n    bool enableCustomMetric = GetBoolFromLua(L, 4, false);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 5);\n    sessionHandle->set_quality_of_service_connectivity_metrics(enableLatencyMetric, enableBandwidthDownMetric, enableBandwidthUpMetric, enableCustomMetric);\n\n    LogToFile(\"MultiplayerSessionSetQosConnectivityMetricsCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMemberInitializationCpp_Lua(lua_State *L)\n{\n    std::chrono::milliseconds joinTimeout{ GetUint64FromLua(L, 1, 100) };\n    std::chrono::milliseconds measurementTimeout{ GetUint64FromLua(L, 2, 100) };\n    std::chrono::milliseconds evaluationTimeout{ GetUint64FromLua(L, 3, 100) };\n    bool externalEvaluation = GetBoolFromLua(L, 4, false);\n    uint32_t membersNeededToStart = GetUint32FromLua(L, 5, 2);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 6);\n    sessionHandle->set_member_initialization(joinTimeout, measurementTimeout, evaluationTimeout, externalEvaluation, membersNeededToStart);\n\n    LogToFile(\"MultiplayerSessionSetMemberInitializationCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetPeerToPeerRequirementsCpp_Lua(lua_State *L)\n{\n    std::chrono::milliseconds latencyMaximum{ GetUint64FromLua(L, 1, 100) };\n    uint32_t bandwidthMinimumInKbps = GetUint32FromLua(L, 2, 100);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    sessionHandle->set_peer_to_peer_requirements(latencyMaximum, bandwidthMinimumInKbps);\n\n    LogToFile(\"MultiplayerSessionSetPeerToPeerRequirementsCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetPeerToHostRequirementsCpp_Lua(lua_State *L)\n{\n    std::chrono::milliseconds latencyMaximum{ GetUint64FromLua(L, 1, 100) };\n    uint32_t bandwidthDownMinimumInKbps = GetUint32FromLua(L, 2, 10);\n    uint32_t bandwidthUpMinimumInKbps = GetUint32FromLua(L, 3, 10);\n    xbox::services::multiplayer::multiplay_metrics hostSelectionMetric = static_cast<xbox::services::multiplayer::multiplay_metrics>(GetUint64FromLua(L, 4, 1));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 5);\n    sessionHandle->set_peer_to_host_requirements(latencyMaximum, bandwidthDownMinimumInKbps, bandwidthUpMinimumInKbps, hostSelectionMetric);\n\n    LogToFile(\"MultiplayerSessionSetPeerToHostRequirementsCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetSessionCapabilitiesCpp_Lua(lua_State *L)\n{\n    xbox::services::multiplayer::multiplayer_session_capabilities caps = {};\n    caps.set_connectivity(GetBoolFromLua(L, 1, false));\n    caps.set_suppress_presence_activity_check(GetBoolFromLua(L, 4, false));\n    caps.set_gameplay(GetBoolFromLua(L, 5, false));\n    caps.set_large(GetBoolFromLua(L, 6, true));\n    caps.set_connection_required_for_active_members(GetBoolFromLua(L, 7, false));\n    caps.set_user_authorization_style(GetBoolFromLua(L, 8, false));\n    caps.set_crossplay(GetBoolFromLua(L, 9, false));\n    caps.set_searchable(GetBoolFromLua(L, 10, false));\n    caps.set_has_owners(GetBoolFromLua(L, 11, false));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 12);\n    sessionHandle->set_session_capabilities(caps);\n\n    LogToFile(\"MultiplayerSessionSetSessionCapabilitiesCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCloudComputePackageJsonCpp_Lua(lua_State *L)\n{\n    string_t sessionCloudComputePackageConstantsJsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"{}\").c_str());\n    web::json::value sessionCloudComputePackageConstantsJson = web::json::value::parse(sessionCloudComputePackageConstantsJsonString);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_cloud_compute_package_json(sessionCloudComputePackageConstantsJson);\n\n    LogToFile(\"MultiplayerSessionSetCloudComputePackageJsonCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSessionPropertiesCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    std::shared_ptr<xbox::services::multiplayer::multiplayer_session_properties> props = sessionHandle->session_properties();\n\n    LogToFile(\"MultiplayerSessionSessionPropertiesCpp\");\n    LogToFile(\"KeywordCount: %ul\", props->keywords().size());\n    for (size_t i = 0; i < props->keywords().size(); i++)\n    {\n        LogToFile(\"Keywords[%ul]: %s\", i, xbox::services::Utils::StringFromStringT(props->keywords()[i]).c_str());\n    }\n    LogToFile(\"JoinRestriction: %d\", props->join_restriction());\n    LogToFile(\"ReadRestriction: %d\", props->read_restriction());\n    LogToFile(\"TurnCollectionCount: %ul\", props->turn_collection().size());\n    for (size_t i = 0; i < props->turn_collection().size(); i++)\n    {\n        LogToFile(\"TurnCollection[%d]: %x\", i, props->turn_collection()[i].get());\n    }\n    LogToFile(\"MatchmakingTargetSessionConstantsJson: %s\", xbox::services::Utils::StringFromStringT(props->matchmaking_target_session_constants_json().serialize()).c_str());\n    LogToFile(\"SessionCustomPropertiesJson: %s\", xbox::services::Utils::StringFromStringT(props->session_custom_properties_json().serialize()).c_str());\n    LogToFile(\"MatchmakingServerConnectionString: %s\", xbox::services::Utils::StringFromStringT(props->matchmaking_server_connection_string()).c_str());\n    LogToFile(\"ServerConnectionStringCandidatesCount: %ul\", props->server_connection_string_candidates().size());\n    for (size_t i = 0; i < props->server_connection_string_candidates().size(); i++)\n    {\n        LogToFile(\"ServerConnectionStringCandidates[%ul]: %s\", i, xbox::services::Utils::StringFromStringT(props->server_connection_string_candidates()[i]).c_str());\n    }\n    LogToFile(\"HostDeviceToken: %s\", xbox::services::Utils::StringFromStringT(props->host_device_token()).c_str());\n    LogToFile(\"Closed: %d\", props->closed());\n    LogToFile(\"Locked: %d\", props->locked());\n    LogToFile(\"AllocateCloudCompute: %d\", props->allocate_cloud_compute());\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionPropertiesSetKeywordsCpp_Lua(lua_State *L)\n{\n    string_t key1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"Keyword1\").c_str());\n    string_t key2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"Keyword2\").c_str());\n\n    std::vector<string_t> keywords{ key1, key2 };\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    sessionHandle->session_properties()->set_keywords(keywords);\n\n    LogToFile(\"MultiplayerSessionPropertiesSetKeywordsCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionPropertiesSetJoinRestrictionCpp_Lua(lua_State *L)\n{\n    auto joinRestriction = static_cast<xbox::services::multiplayer::multiplayer_session_restriction>(GetUint64FromLua(L, 1, static_cast<int>(xbox::services::multiplayer::multiplayer_session_restriction::followed)));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    std::error_code err = sessionHandle->session_properties()->set_join_restriction(joinRestriction);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionPropertiesSetJoinRestrictionCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionPropertiesSetReadRestrictionCpp_Lua(lua_State *L)\n{\n    auto readRestriction = static_cast<xbox::services::multiplayer::multiplayer_session_restriction>(GetUint64FromLua(L, 1, static_cast<int>(xbox::services::multiplayer::multiplayer_session_restriction::followed)));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->session_properties()->set_read_restriction(readRestriction);\n\n    LogToFile(\"MultiplayerSessionPropertiesSetReadRestrictionCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionRoleTypesCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    std::shared_ptr<xbox::services::multiplayer::multiplayer_session_role_types> roleTypes = sessionHandle->session_role_types();\n\n    LogToFile(\"MultiplayerSessionRoleTypesCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid LogSessionMember(const xbox::services::multiplayer::multiplayer_session_member* member)\n{\n    LogToFile(\"member->MemberId: %d\", member->member_id());\n    LogToFile(\"member->InitialTeam: %s\", xbox::services::Utils::StringFromStringT(member->initial_team()).c_str());\n    LogToFile(\"member->Xuid: %s\", xbox::services::Utils::StringFromStringT(member->xbox_user_id()).c_str());\n    LogToFile(\"member->CustomConstantsJson: %s\", xbox::services::Utils::StringFromStringT(member->member_custom_constants_json().serialize()).c_str());\n    LogToFile(\"member->SecureDeviceBaseAddress64: %s\", xbox::services::Utils::StringFromStringT(member->secure_device_base_address64()).c_str());\n    for (auto role : member->roles())\n    {\n        LogToFile(\"member->roles %s : %s\", xbox::services::Utils::StringFromStringT(role.first).c_str(), xbox::services::Utils::StringFromStringT(role.second).c_str());\n    }\n    LogToFile(\"member->RolesCount: %ul\", member->roles().size());\n    LogToFile(\"member->CustomPropertiesJson: %s\", xbox::services::Utils::StringFromStringT(member->member_custom_properties_json().serialize()).c_str());\n    LogToFile(\"member->Gamertag: %s\", xbox::services::Utils::StringFromStringT(member->gamertag()).c_str());\n    LogToFile(\"member->XblMultiplayerSessionMemberStatus: %d\", member->status());\n    LogToFile(\"member->IsTurnAvailable: %d\", member->is_turn_available());\n    LogToFile(\"member->IsCurrentUser: %d\", member->is_current_user());\n    LogToFile(\"member->InitializeRequested: %d\", member->initialize_requested());\n    LogToFile(\"member->MatchmakingResultServerMeasurementsJson: %s\", xbox::services::Utils::StringFromStringT(member->matchmaking_result_server_measurements_json().serialize()).c_str());\n    LogToFile(\"member->ServerMeasurementsJson: %s\", xbox::services::Utils::StringFromStringT(member->member_server_measurements_json().serialize()).c_str());\n    for (size_t i = 0; i < member->members_in_group().size(); i++)\n    {\n        LogToFile(\"member->MembersInGroupIds[%d]: %ul\", i, member->members_in_group()[i]->member_id());\n    }\n    LogToFile(\"member->MembersInGroupCount: %ul\", member->members_in_group().size());\n    LogToFile(\"member->DeviceToken: %s\", xbox::services::Utils::StringFromStringT(member->device_token()).c_str());\n    LogToFile(\"member->Nat: %d\", member->nat());\n    LogToFile(\"member->ActiveTitleId: %d\", member->active_title_id());\n    LogToFile(\"member->InitializationEpisode: %d\", member->initialization_episode());\n    LogToFile(\"member->JoinTime: %s\", xbox::services::Utils::StringFromStringT(member->join_time().to_string()).c_str());\n    LogToFile(\"member->InitializationFailureCause: %d\", member->initialization_failure_cause());\n    for (size_t i = 0; i < member->groups().size(); i++)\n    {\n        LogToFile(\"member->Groups[%d]: %s\", i, xbox::services::Utils::StringFromStringT(member->groups()[i]).c_str());\n    }\n    LogToFile(\"member->GroupsCount: %ul\", member->groups().size());\n    for (size_t i = 0; i < member->encounters().size(); i++)\n    {\n        LogToFile(\"member->Encounters[%d]: %s\", i, xbox::services::Utils::StringFromStringT(member->encounters()[i]).c_str());\n    }\n    LogToFile(\"member->EncountersCount: %ul\", member->encounters().size());\n}\n\nint MultiplayerSessionMembersCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    std::vector<std::shared_ptr<xbox::services::multiplayer::multiplayer_session_member>> members = sessionHandle->members();\n\n    LogToFile(\"MultiplayerSessionMembersCpp\");\n    for (auto member : members)\n    {\n        LogSessionMember(member.get());\n    }\n    LogToFile(\"membersCount: %d\", members.size());\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionGetMemberCpp_Lua(lua_State *L)\n{\n    uint32_t memberId = GetUint32FromLua(L, 1, 0);\n\n    LogToFile(\"MultiplayerSessionGetMemberCpp\");\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    for (auto member : sessionHandle->members())\n    {\n        if (member->member_id() == memberId)\n        {\n            LogSessionMember(member.get());\n        }\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionMatchmakingServerCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    xbox::services::multiplayer::multiplayer_session_matchmaking_server server = sessionHandle->matchmaking_server();\n\n    LogToFile(\"MultiplayerSessionMatchmakingServerCpp\");\n    if (server.is_null())\n    {\n        LogToFile(\"server is null\");\n        return LuaReturnHR(L, S_OK);\n    }\n\n    LogToFile(\"server.status: %d\", server.status());\n    LogToFile(\"server.status_details: %s\", xbox::services::Utils::StringFromStringT(server.status_details()).c_str());\n    LogToFile(\"server.typical_wait: %d\", server.typical_wait());\n    auto sessionRef = server.target_session_ref();\n    LogSessionRef(&sessionRef);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionMembersAcceptedCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    uint32_t membersAccepted = sessionHandle->members_accepted();\n\n    LogToFile(\"MultiplayerSessionMembersAcceptedCpp\");\n    LogToFile(\"membersAccepted: %d\", membersAccepted);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionServersJsonCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    string_t serversJsonString = sessionHandle->servers_json().serialize();\n\n    LogToFile(\"MultiplayerSessionServersJsonCpp\");\n    LogToFile(\"json: %s\", xbox::services::Utils::StringFromStringT(serversJsonString).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetServersJsonCpp_Lua(lua_State *L)\n{\n    string_t jsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"{}\").c_str());\n    web::json::value json = web::json::value::parse(jsonString);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_servers_json(json);\n\n    LogToFile(\"MultiplayerSessionSetServersJsonCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionEtagCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    string_t etag = sessionHandle->e_tag();\n\n    LogToFile(\"MultiplayerSessionEtagCpp\");\n    LogToFile(\"etag: %s\", xbox::services::Utils::StringFromStringT(etag).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionCurrentUserCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    std::shared_ptr<xbox::services::multiplayer::multiplayer_session_member> currentUser = sessionHandle->current_user();\n\n\n    LogToFile(\"MultiplayerSessionCurrentUserCpp\");\n    if (currentUser == nullptr)\n    {\n        LogToFile(\"currentUser == nullptr\");\n        return LuaReturnHR(L, S_OK);\n    }\n\n    LogSessionMember(currentUser.get());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionGetInfoCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n\n    LogToFile(\"MultiplayerSessionGetInfoCpp:\");\n    LogToFile(\"branch: %s\", xbox::services::Utils::StringFromStringT(sessionHandle->branch()).c_str());\n    LogToFile(\"change_number: %ul\", sessionHandle->change_number());\n    LogToFile(\"multiplayer_correlation_id: %s\", xbox::services::Utils::StringFromStringT(sessionHandle->multiplayer_correlation_id()).c_str());\n    LogToFile(\"start_time: %s\", xbox::services::Utils::StringFromStringT(sessionHandle->start_time().to_string()).c_str());\n    LogToFile(\"date_of_next_timer: %s\", xbox::services::Utils::StringFromStringT(sessionHandle->date_of_next_timer().to_string()).c_str());\n    LogToFile(\"search_handle_id: %s\", xbox::services::Utils::StringFromStringT(sessionHandle->search_handle_id()).c_str());\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionWriteStatusCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    xbox::services::multiplayer::write_session_status writeStatus = sessionHandle->write_status();\n\n    LogToFile(\"MultiplayerSessionWriteStatusCpp\");\n    LogToFile(\"writeStatus: %d\", writeStatus);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetInitializationStatusCpp_Lua(lua_State *L)\n{\n    bool initSucceded = GetBoolFromLua(L, 1, false);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_initialization_status(initSucceded);\n\n    LogToFile(\"MultiplayerSessionSetInitializationStatusCpp %d\", initSucceded);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetHostDeviceTokenCpp_Lua(lua_State *L)\n{\n    string_t hostDeviceToken = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"DefaultHost\").c_str());\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_host_device_token(hostDeviceToken);\n\n    LogToFile(\"MultiplayerSessionSetHostDeviceTokenCpp host:%s\", xbox::services::Utils::StringFromStringT(hostDeviceToken).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMatchmakingServerConnectionPathCpp_Lua(lua_State *L)\n{\n    string_t path = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"DefaultPath\").c_str());\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_matchmaking_server_connection_path(path);\n\n    LogToFile(\"MultiplayerSessionSetMatchmakingServerConnectionPathCpp path:%s\", xbox::services::Utils::StringFromStringT(path).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetClosedCpp_Lua(lua_State *L)\n{\n    bool closed = GetBoolFromLua(L, 1, true);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_closed(closed);\n\n    LogToFile(\"MultiplayerSessionSetClosedCpp %d\", closed);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetLockedCpp_Lua(lua_State *L)\n{\n    bool locked = GetBoolFromLua(L, 1, false);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_locked(locked);\n\n    LogToFile(\"MultiplayerSessionSetLockedCpp %d\", locked);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetAllocateCloudComputeCpp_Lua(lua_State *L)\n{\n    bool allocate = GetBoolFromLua(L, 1, false);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_allocate_cloud_compute(allocate);\n\n    LogToFile(\"MultiplayerSessionSetAllocateCloudComputeCpp %d\", allocate);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMatchmakingResubmitCpp_Lua(lua_State *L)\n{\n    bool matchResubmit = GetBoolFromLua(L, 1, false);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    sessionHandle->set_matchmaking_resubmit(matchResubmit);\n\n    LogToFile(\"MultiplayerSessionSetMatchmakingResubmitCpp %d\", matchResubmit);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetServerConnectionStringCandidatesCpp_Lua(lua_State *L)\n{\n    string_t candidate1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"Candidate1\").c_str());\n    string_t candidate2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"Candidate2\").c_str());\n    std::vector<string_t> candidates{ candidate1, candidate2 };\n\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    sessionHandle->set_server_connection_string_candidates(candidates);\n\n    LogToFile(\"MultiplayerSessionSetServerConnectionStringCandidatesCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetSessionChangeSubscriptionCpp_Lua(lua_State *L)\n{\n    auto changeTypes = static_cast<xbox::services::multiplayer::multiplayer_session_change_types>(GetUint32FromLua(L, 1, static_cast<int>(xbox::services::multiplayer::multiplayer_session_change_types::everything)));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    std::error_code err = sessionHandle->set_session_change_subscription(changeTypes);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetSessionChangeSubscriptionCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionLeaveCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    std::error_code err = sessionHandle->leave();\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionLeaveCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionSetCurrentUserStatusCpp_Lua(lua_State *L)\n{\n    auto status = static_cast<xbox::services::multiplayer::multiplayer_session_member_status>(GetUint32FromLua(L, 1, 3));\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n    std::error_code err = sessionHandle->set_current_user_status(status);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetCurrentUserStatusCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionSetCurrentUserSecureDeviceAddressBase64Cpp_Lua(lua_State *L)\n{\n    string_t deviceAddress = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"ExampleDeviceAddress\").c_str());\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n    std::error_code err = sessionHandle->set_current_user_secure_device_address_base64(deviceAddress);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetCurrentUserSecureDeviceAddressBase64Cpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionSetCurrentUserRolesCpp_Lua(lua_State *L)\n{\n    string_t roleTypeName1 = _T(\"roleTypeName1\");\n    string_t roleName1 = _T(\"roleName1\");\n    string_t roleTypeName2 = _T(\"roleTypeName2\");\n    string_t roleName2 = _T(\"roleName2\");\n\n    std::unordered_map<string_t, string_t> roleInfo{\n        std::pair<string_t, string_t>(roleTypeName1, roleName1),\n        std::pair<string_t, string_t>(roleTypeName2, roleName2) };\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    std::error_code err = sessionHandle->set_current_user_role_info(roleInfo);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetCurrentUserRolesCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionCurrentUserSetGroupsCpp_Lua(lua_State *L)\n{\n    string_t group1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"group1\").c_str());\n    string_t group2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"group2\").c_str());\n    std::vector<string_t> groups{ group1, group2 };\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n    sessionHandle->current_user()->set_groups(groups);\n\n    LogToFile(\"MultiplayerSessionCurrentUserSetGroupsCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionCurrentUserSetEncountersCpp_Lua(lua_State *L)\n{\n    string_t encounter1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"encounter1\").c_str());\n    string_t encounter2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"encounter2\").c_str());\n    std::vector<string_t> encounters{ encounter1, encounter2 };\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n    sessionHandle->current_user()->set_encounters(encounters);\n\n    LogToFile(\"MultiplayerSessionCurrentUserSetEncountersCpp\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCurrentUserQosMeasurementsJsonCpp_Lua(lua_State *L)\n{\n    string_t measurementsJsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"{\\\"measurements1\\\":5}\").c_str());\n    web::json::value measurementsJson = web::json::value::parse(measurementsJsonString);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    std::error_code err = sessionHandle->set_current_user_quality_of_service_measurements_json(measurementsJson);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetCurrentUserQosMeasurementsCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionSetCurrentUserMemberCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    string_t name = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"name1\").c_str());\n    string_t jsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"{\\\"myscore\\\":123}\").c_str());\n    web::json::value json = web::json::value::parse(jsonString);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n    std::error_code err = sessionHandle->set_current_user_member_custom_property_json(name, json);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetCurrentUserMemberCustomPropertyJsonCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionDeleteCurrentUserMemberCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    string_t name = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"name1\").c_str());\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    std::error_code err = sessionHandle->delete_current_user_member_custom_property_json(name);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionDeleteCurrentUserMemberCustomPropertyJsonCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionSetMatchmakingTargetSessionConstantsJsonCpp_Lua(lua_State *L)\n{\n    string_t constsString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"{}\").c_str());\n    web::json::value consts = web::json::value::parse(constsString);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    std::error_code err = sessionHandle->set_matchmaking_target_session_constants_json(consts);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetMatchmakingTargetSessionConstantsJsonCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionSetSessionCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    string_t name = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"name1\").c_str());\n    string_t jsonString = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"{}\").c_str());\n    web::json::value json = web::json::value::parse(jsonString);\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n    std::error_code err = sessionHandle->set_session_custom_property_json(name, json);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionSetSessionCustomPropertyJsonCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionDeleteSessionCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    string_t name = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"name1\").c_str());\n\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 2);\n    std::error_code err = sessionHandle->delete_session_custom_property_json(name);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n\n    LogToFile(\"MultiplayerSessionDeleteSessionCustomPropertyJsonCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerSessionCompareCpp_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1);\n    auto sessionHandle2 = sessionHandle;\n\n    xbox::services::xbox_live_result<xbox::services::multiplayer::multiplayer_session_change_types> result = xbox::services::multiplayer::multiplayer_session::compare_multiplayer_sessions(sessionHandle, sessionHandle2);\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    LogToFile(\"MultiplayerSessionCompareCpp: hr=%s\", ConvertHR(hr).c_str());\n    if (SUCCEEDED(hr))\n    {\n        xbox::services::multiplayer::multiplayer_session_change_types changeTypes = result.payload();\n        LogToFile(\"changeTypes: %d\", changeTypes);\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\n//multiplayer_service\n\nint MultiplayerServiceWriteSession_Lua(lua_State *L)\n{\n    uint64_t sessionIndex;\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 1, &sessionIndex);\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    auto sessionWriteMode = ConvertStringToCppMultiplayerSessionWriteMode(GetStringFromLua(L, 2, \"multiplayer_session_write_mode::update_or_create_new\").c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().write_session(\n        sessionHandle, \n        sessionWriteMode\n    ).then(\n        [sessionIndex](xbox::services::xbox_live_result<std::shared_ptr<xbox::services::multiplayer::multiplayer_session>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceWriteSession: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                MPStateCpp()->sessionHandles[static_cast<uint32_t>(sessionIndex)] = result.payload();\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceWriteSession\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceWriteSessionByHandle_Lua(lua_State *L)\n{\n    auto writeMode = static_cast<xbox::services::multiplayer::multiplayer_session_write_mode>(GetUint32FromLua(L, 1, static_cast<int>(xbox::services::multiplayer::multiplayer_session_write_mode::update_existing)));\n    string_t handleId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, MPStateCpp()->activityHandle).c_str());\n    auto sessionHandle = GetSessionHandleFromArgCpp(L, 3);\n\n    LogToFile(\"MultiplayerServiceWriteSessionByHandle\");\n    LogToFile(\"writeMode: %d\", writeMode);\n    LogToFile(\"handleId: %s\", xbox::services::Utils::StringFromStringT(handleId).c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().write_session_by_handle(\n        sessionHandle, \n        writeMode, \n        handleId\n    ).then(\n        [](xbox::services::xbox_live_result<std::shared_ptr<xbox::services::multiplayer::multiplayer_session>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceWriteSessionByHandle: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::shared_ptr<xbox::services::multiplayer::multiplayer_session> session = result.payload();\n                UNREFERENCED_PARAMETER(session);\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceWriteSessionByHandle\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetCurrentSession_Lua(lua_State *L)\n{\n    string_t scid = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, Data()->scid).c_str());\n    string_t sessionTemplateName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"MinGameSession\").c_str());\n    uint64_t sessionIndex{ GetUint64FromLua(L, 4, 0) };\n    string_t sessionName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, MultiplayerStateCpp::GetSessionName(sessionIndex)).c_str());\n\n    xbox::services::multiplayer::multiplayer_session_reference sessionRef{ scid, sessionTemplateName, sessionName };\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().get_current_session(sessionRef).then(\n        [sessionIndex](xbox::services::xbox_live_result<std::shared_ptr<xbox::services::multiplayer::multiplayer_session>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceGetCurrentSession: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                MPStateCpp()->sessionHandles[static_cast<uint32_t>(sessionIndex)] = result.payload();\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceGetCurrentSession\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetCurrentSessionByHandle_Lua(lua_State *L)\n{\n    string_t handleId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, MPStateCpp()->inviteHandle).c_str());\n    auto sessionIndex{ GetUint64FromLua(L, 2, 0) };\n    if (handleId.empty())\n    {\n        handleId = _T(\"86191619-4002-044f-4846-f8f903c71512\");\n    }\n\n    LogToFile(\"handleId: %s\", xbox::services::Utils::StringFromStringT(handleId).c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().get_current_session_by_handle(handleId).then(\n        [sessionIndex](xbox::services::xbox_live_result<std::shared_ptr<xbox::services::multiplayer::multiplayer_session>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceGetCurrentSessionByHandle: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                MPStateCpp()->sessionHandles[static_cast<uint32_t>(sessionIndex)] = result.payload();\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceGetCurrentSessionByHandle\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetSessions_Lua(lua_State *L)\n{\n    string_t scid = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, Data()->scid).c_str());\n    uint32_t maxItems = GetUint32FromLua(L, 2, 0);\n\n    bool includePrivateSessions = GetBoolFromLua(L, 3, false);\n    bool includeReservations = GetBoolFromLua(L, 4, false);\n    bool includeInactiveSessions = GetBoolFromLua(L, 5, false);\n    string_t keywordFilter = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 6, \"killzone\").c_str());\n    string_t sessionTemplateNameFilter = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 7, \"\").c_str());\n    xbox::services::multiplayer::multiplayer_session_visibility visibilityFilter = static_cast<xbox::services::multiplayer::multiplayer_session_visibility>(GetUint32FromLua(L, 8, 5));\n    uint32_t contractVersionFilter = GetUint32FromLua(L, 9, 0);\n\n    xbox::services::multiplayer::multiplayer_get_sessions_request request(scid, maxItems);\n    request.set_include_private_sessions(includePrivateSessions);\n    request.set_include_reservations(includeReservations);\n    request.set_include_inactive_sessions(includeInactiveSessions);\n    request.set_keyword_filter(keywordFilter);\n    request.set_session_template_name_filter(sessionTemplateNameFilter);\n    request.set_visibility_filter(visibilityFilter);\n    request.set_contract_version_filter(contractVersionFilter);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().get_sessions(request).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::multiplayer::multiplayer_session_states>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceGetSessions: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::multiplayer::multiplayer_session_states> sessionStates = result.payload();\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceGetSessions\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSetActivity_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().set_activity(MPStateCpp()->sessionRef).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceSetActivity: hr=%s\", ConvertHR(hr).c_str());\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceSetActivity\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceClearActivity_Lua(lua_State *L)\n{\n    string_t serviceConfigurationID = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().clear_activity(serviceConfigurationID).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceClearActivity: hr=%s\", ConvertHR(hr).c_str());\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceClearActivity\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSendInvites_Lua(lua_State *L)\n{\n    string_t contextStringId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"contextStringId1\").c_str());\n    string_t customActivationContext = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"customActivationContext1\").c_str());\n    string_t targetXuid = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 3, 2814679169942680));\n\n    xbox::services::multiplayer::multiplayer_session_reference sessionReference = MPStateCpp()->sessionRef;\n    std::vector<string_t> xuids{ targetXuid };\n    uint32_t titleId = Data()->titleId;\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().send_invites(\n        sessionReference,\n        xuids,\n        titleId,\n        contextStringId,\n        customActivationContext\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<string_t>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceSendInvites: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<string_t> inviteHandles = result.payload();\n                LogToFile(\"MultiplayerServiceSendInvites got %d invite handles\", inviteHandles.size());\n                MPStateCpp()->inviteHandle = xbox::services::Utils::StringFromStringT(inviteHandles[0]);\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceSendInvites\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetActivitiesForSocialGroup_Lua(lua_State *L)\n{\n    string_t serviceConfigurationID = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    string_t socialGroupOwnerXuid = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 1, 2814632956486799));\n    string_t socialGroup = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"people\").c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().get_activities_for_social_group(\n        serviceConfigurationID,\n        socialGroupOwnerXuid,\n        socialGroup\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::multiplayer::multiplayer_activity_details>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceGetActivitiesForSocialGroup: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::multiplayer::multiplayer_activity_details> activityDetails = result.payload();\n                UNREFERENCED_PARAMETER(activityDetails);\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceGetActivitiesForSocialGroup\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetActivitiesForUsers_Lua(lua_State *L)\n{\n    uint64_t xuid1 = GetUint64FromLua(L, 1, Data()->m_multiDeviceManager->GetRemoteXuid());\n    if (xuid1 == 0) xuid1 = 2814636782672891;\n\n    string_t serviceConfigurationID = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    std::vector<string_t> xuids{ xbox::services::Utils::StringTFromUint64(xuid1) };\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().get_activities_for_users(\n        serviceConfigurationID,\n        xuids\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::multiplayer::multiplayer_activity_details>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceGetActivitiesForUsers: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::multiplayer::multiplayer_activity_details> activityDetails = result.payload();\n\n                if (activityDetails.size() > 0)\n                {\n                    std::string handleIdStr = xbox::services::Utils::StringFromStringT(activityDetails[0].handle_id());\n                    LogToScreen(\"Joining lobby via handle %s\", handleIdStr.c_str());\n                    MPStateCpp()->activityHandle = handleIdStr; // CODE SNIP SKIP\n                }\n                else\n                {\n                    if (Data()->m_multiDeviceManager->GetRemoteXuid() != 0)\n                    {\n                        LogToScreen(\"No activity handle to join.  Failing...\");\n                        hr = E_FAIL;\n                    }\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceGetActivitiesForUsers\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceEnableMultiplayerSubscriptions_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    std::error_code err = xblc->multiplayer_service().enable_multiplayer_subscriptions();\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(err);\n    LogToFile(\"MultiplayerServiceEnableMultiplayerSubscriptions: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint MultiplayerServiceDisableMultiplayerSubscriptions_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().disable_multiplayer_subscriptions();\n    LogToFile(\"MultiplayerServiceDisableMultiplayerSubscriptions\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceMultiplayerSubscriptionsEnabled_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    bool enabled = xblc->multiplayer_service().subscriptions_enabled();\n\n    LogToFile(\"MultiplayerServiceMultiplayerSubscriptionsEnabled\");\n    LogToFile(\"enabled: %d\", enabled);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceAddMultiplayerSessionChangedHandler_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    function_context fnContext = xblc->multiplayer_service().add_multiplayer_session_changed_handler(\n        [](const xbox::services::multiplayer::multiplayer_session_change_event_args& args)\n        {\n            LogToFile(\"MultiplayerServiceAddMultiplayerSessionChangedHandler\");\n            LogToFile(\"ChangeNumber: %d\", args.change_number());\n            CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceAddMultiplayerSessionChangedHandler\");\n        });\n\n    MPStateCpp()->sessionChangedContext = fnContext;\n    LogToFile(\"MultiplayerServiceAddMultiplayerSessionChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceRemoveMultiplayerSessionChangedHandler_Lua(lua_State *L)\n{\n    function_context fnContext = MPStateCpp()->sessionChangedContext;\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().remove_multiplayer_session_changed_handler(fnContext);\n    MPStateCpp()->sessionChangedContext = nullptr;\n\n    LogToFile(\"MultiplayerServiceRemoveMultiplayerSessionChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceAddMultiplayerSubscriptionLostHandler_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    function_context fnContext = xblc->multiplayer_service().add_multiplayer_subscription_lost_handler(\n        []()\n        {\n            LogToFile(\"MultiplayerServiceAddMultiplayerSubscriptionLostHandler\");\n            CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceAddMultiplayerSubscriptionLostHandler\");\n        });\n\n    MPStateCpp()->subscriptionLostContext = fnContext;\n    LogToFile(\"MultiplayerServiceAddMultiplayerSubscriptionLostHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler_Lua(lua_State *L)\n{\n    function_context fnContext = MPStateCpp()->subscriptionLostContext;\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().remove_multiplayer_subscription_lost_handler(fnContext);\n    MPStateCpp()->subscriptionLostContext = nullptr;\n\n    LogToFile(\"MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceAddMultiplayerConnectionIdChangedHandler_Lua(lua_State *L)\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    function_context fnContext = xblc->multiplayer_service().add_multiplayer_connection_id_changed_handler(\n        []()\n        {\n            LogToFile(\"MultiplayerServiceAddMultiplayerConnectionIdChangedHandler\");\n            CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceAddMultiplayerConnectionIdChangedHandler\");\n        });\n\n    MPStateCpp()->connectionIdChangedContext = fnContext;\n    LogToFile(\"MultiplayerServiceAddMultiplayerConnectionIdChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceRemoveMultiplayerConnectionIdChangedHandler_Lua(lua_State *L)\n{\n    function_context fnContext = MPStateCpp()->connectionIdChangedContext;\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().remove_multiplayer_connection_id_changed_handler(fnContext);\n    MPStateCpp()->connectionIdChangedContext = nullptr;\n\n    LogToFile(\"MultiplayerServiceRemoveMultiplayerConnectionIdChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSetTransferHandle_Lua(lua_State* L)\n{\n    uint64_t targetIndex{ GetUint64FromLua(L, 1, 0) };\n    uint64_t originIndex{ GetUint64FromLua(L, 2, 0) };\n\n    auto targetReference = MPStateCpp()->sessionHandles[static_cast<uint32_t>(targetIndex)]->session_reference();\n    auto originReference = MPStateCpp()->sessionHandles[static_cast<uint32_t>(originIndex)]->session_reference();\n\n    if (!originReference.is_null() && !targetReference.is_null())\n    {\n        std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n        xblc->multiplayer_service().set_transfer_handle(\n            targetReference,\n            originReference\n        ).then(\n            [](xbox::services::xbox_live_result<string_t> result)\n            {\n                HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n                LogToFile(\"MultiplayerServiceSetTransferHandle: hr=%s\", ConvertHR(hr).c_str());\n\n                if (SUCCEEDED(hr))\n                {\n                    string_t transferId = result.payload();\n                    LogToFile(\"Successfully set transfer handle, ID = %s\", xbox::services::Utils::StringFromStringT(transferId).c_str());\n                }\n\n                CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceSetTransferHandle\");\n            });\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSetSearchHandle_Lua(lua_State *L)\n{\n    std::vector<string_t> tags{ _T(\"SessionTag\") };\n    std::unordered_map<string_t, double> numbersMetadata{ std::pair<string_t, double>(_T(\"numberattributename\"), 1.1) };\n    std::unordered_map<string_t, string_t> stringsMetadata{ std::pair<string_t, string_t>(_T(\"stringattributename\"), _T(\"string attribute value\")) };\n\n    xbox::services::multiplayer::multiplayer_session_reference sessionRef = MPStateCpp()->sessionRef;\n    xbox::services::multiplayer::multiplayer_search_handle_request searchRequest(sessionRef);\n    searchRequest.set_tags(tags);\n    searchRequest.set_numbers_metadata(numbersMetadata);\n    searchRequest.set_strings_metadata(stringsMetadata);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().set_search_handle(searchRequest).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceSetSearchHandle: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceSetSearchHandle\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceClearSearchHandle_Lua(lua_State *L)\n{\n    string_t handleId;\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().clear_search_handle(handleId).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceClearSearchHandle: hr=%s\", ConvertHR(hr).c_str());\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceClearSearchHandle\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetSearchHandles_Lua(lua_State *L)\n{\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    bool orderAscending{ false };\n    string_t sessionTemplateName = _T(\"MinGameSession\");\n    string_t orderByAttribute = _T(\"\");\n    string_t searchFilter = _T(\"\");\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->multiplayer_service().get_search_handles(\n        serviceConfigurationId,\n        sessionTemplateName,\n        orderByAttribute,\n        orderAscending,\n        searchFilter\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::multiplayer::multiplayer_search_handle_details>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MultiplayerServiceGetSearchHandles: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::multiplayer::multiplayer_search_handle_details> searchHandles = result.payload();\n                LogToFile(\"Got %u search handles:\", searchHandles.size());\n                for (auto searchHandle : searchHandles)\n                {\n                    LogToFile(\"\\t%s\", xbox::services::Utils::StringFromStringT(searchHandle.handle_id()).c_str());\n                }\n\n                if (searchHandles.size() > 0)\n                {\n                    MPStateCpp()->searchHandleDetails = std::make_shared< xbox::services::multiplayer::multiplayer_search_handle_details>(searchHandles[0]);\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMultiplayerServiceGetSearchHandles\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\n//multiplayer_search_handle_detail\n\nint MultiplayerSearchHandleDetailsCloseHandle_Lua(lua_State *L)\n{\n    MPStateCpp()->searchHandleDetails = nullptr;\n\n    LogToFile(\"MultiplayerSearchHandleDetailsCloseHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsSessionReference_Lua(lua_State *L)\n{\n    auto sessionRef = MPStateCpp()->searchHandleDetails->session_reference();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsSessionReference\");\n    LogSessionRef(&sessionRef);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsHandleId_Lua(lua_State *L)\n{\n    string_t handleId = MPStateCpp()->searchHandleDetails->handle_id();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsHandleId\");\n    LogToFile(\"Search Handle Id: %s\", xbox::services::Utils::StringFromStringT(handleId).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsSessionOwnerXuids_Lua(lua_State *L)\n{\n    std::vector<string_t> xuids;\n    if (MPStateCpp()->searchHandleDetails)\n    {\n        xuids = MPStateCpp()->searchHandleDetails->session_owner_xbox_user_ids();\n    }\n\n    LogToFile(\"MultiplayerSearchHandleDetailsSessionOwnerXuids\");\n    LogToFile(\"There are %u session owners:\", xuids.size());\n    for (string_t xuid : xuids)\n    {\n        LogToFile(\"\\t%s\", xbox::services::Utils::StringFromStringT(xuid).c_str());\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsTags_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    std::vector<string_t> tags = MPStateCpp()->searchHandleDetails->tags();\n    \n    LogToFile(\"MultiplayerSearchHandleDetailsTags\");\n    LogToFile(\"There are %u tags for the session:\", tags.size());\n    for (string_t tag : tags)\n    {\n        LogToFile(\"\\t%s\", xbox::services::Utils::StringFromStringT(tag).c_str());\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsStringsMetadata_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    auto stringsMetadata = MPStateCpp()->searchHandleDetails->strings_metadata();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsStringsMetadata\");\n    LogToFile(\"There are %u string metadata for the session:\", stringsMetadata.size());\n    for (std::pair<string_t, string_t> stringMetadata : stringsMetadata)\n    {\n        LogToFile(\"\\t%s : %s\", xbox::services::Utils::StringFromStringT(stringMetadata.first).c_str(), xbox::services::Utils::StringFromStringT(stringMetadata.second).c_str());\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsNumbersMetadata_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    auto numbersMetadata = MPStateCpp()->searchHandleDetails->numbers_metadata();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsNumbersMetadata\");\n    LogToFile(\"There are %u number metadata for the session:\", numbersMetadata.size());\n    for (std::pair<string_t, double> numberMetadata : numbersMetadata)\n    {\n        LogToFile(\"\\t%s : %f\", xbox::services::Utils::StringFromStringT(numberMetadata.first).c_str(), numberMetadata.second);\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsVisibility_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    xbox::services::multiplayer::multiplayer_session_visibility sessionVisibility = MPStateCpp()->searchHandleDetails->visibility();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsVisibility: visibility=%u\", sessionVisibility);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsJoinRestriction_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    xbox::services::multiplayer::multiplayer_session_restriction joinRestriction = MPStateCpp()->searchHandleDetails->join_restriction();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsJoinRestriction: restriction=%u\", joinRestriction);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsClosed_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    bool sessionClosed = MPStateCpp()->searchHandleDetails->closed();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsClosed: closed=%d\", sessionClosed);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsMemberCounts_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    uint32_t membersCount = MPStateCpp()->searchHandleDetails->members_count();\n    uint32_t maxMembersCount = MPStateCpp()->searchHandleDetails->max_members_count();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsMemberCounts: max members=%u, current members=%u \", maxMembersCount, membersCount);\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsHandleCreationTime_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    auto creationTime = MPStateCpp()->searchHandleDetails->handle_creation_time();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsHandleCreationTime: creation time=%s\", xbox::services::Utils::StringFromStringT(creationTime.to_string()).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsCustomSessionPropertiesJson_Lua(lua_State *L)\n{\n    if (MPStateCpp()->searchHandleDetails == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    string_t customPropertiesJsonStr = MPStateCpp()->searchHandleDetails->custom_session_properties_json().serialize();\n\n    LogToFile(\"MultiplayerSearchHandleDetailsCustomSessionPropertiesJson: properties=%s\", xbox::services::Utils::StringFromStringT(customPropertiesJsonStr).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\n//matchmaking_service\n\nint MatchmakingServiceCreateTicket_Lua(lua_State* L)\n{\n    string_t hopperName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"PlayerSkillNoQoS\").c_str());\n    string_t attributesJsonStr = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"{}\").c_str());\n    std::chrono::seconds timeoutInSeconds{ GetUint32FromLua(L, 6, 100) };\n\n    auto sessionRef = MPStateCpp()->sessionRef;\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    xbox::services::matchmaking::preserve_session_mode preserveSession = xbox::services::matchmaking::preserve_session_mode::never;\n    web::json::value attributesJson = web::json::value::parse(attributesJsonStr);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->matchmaking_service().create_match_ticket(\n        sessionRef,\n        serviceConfigurationId,\n        hopperName,\n        timeoutInSeconds,\n        preserveSession,\n        attributesJson\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::matchmaking::create_match_ticket_response> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MatchmakingServiceCreateTicket: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::matchmaking::create_match_ticket_response ticketResponse = result.payload();\n                LogToScreen(\"create_match_ticket_response.match_ticket_id: %s\", xbox::services::Utils::StringFromStringT(ticketResponse.match_ticket_id()).c_str());\n                LogToScreen(\"create_match_ticket_response.estimated_wait_time: %d\", ticketResponse.estimated_wait_time());\n                Data()->matchTicketResponseCpp = ticketResponse;\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMatchmakingServiceCreateTicket\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MatchmakingServiceGetMatchTicketDetails_Lua(lua_State* L)\n{\n    string_t hopperName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"PlayerSkillNoQoS\").c_str());\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, Data()->scid).c_str());\n    string_t ticketId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, \"\").c_str());\n    if (ticketId.empty())\n    {\n        ticketId = Data()->matchTicketResponseCpp.match_ticket_id();\n    }\n\n    if (Data()->xalUser == nullptr)\n    {\n        return LuaReturnHR(L, E_UNEXPECTED);\n    }\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->matchmaking_service().get_match_ticket_details(\n        serviceConfigurationId,\n        hopperName,\n        ticketId\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::matchmaking::match_ticket_details_response> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MatchmakingServiceGetMatchTicketDetails: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::matchmaking::match_ticket_details_response ticketDetailsResponse = result.payload();\n\n                LogToScreen(\"match_ticket_details_response.match_status: %d\", ticketDetailsResponse.match_status());\n                LogToScreen(\"match_ticket_details_response.estimated_wait_time: %d\", ticketDetailsResponse.estimated_wait_time());\n                LogToScreen(\"match_ticket_details_response.preserve_session: %d\", ticketDetailsResponse.preserve_session());\n                LogToScreen(\"match_ticket_details_response.ticketSession: SCID: %s, Session Name: %s, Session Template Name: %s\",\n                    xbox::services::Utils::StringFromStringT(ticketDetailsResponse.ticket_session().service_configuration_id()).c_str(),\n                    xbox::services::Utils::StringFromStringT(ticketDetailsResponse.ticket_session().session_name()).c_str(),\n                    xbox::services::Utils::StringFromStringT(ticketDetailsResponse.ticket_session().session_template_name()).c_str());\n                LogToScreen(\"match_ticket_details_response.targetSession: SCID: %s, Session Name: %s, Session Template Name: %s\",\n                    xbox::services::Utils::StringFromStringT(ticketDetailsResponse.target_session().service_configuration_id()).c_str(),\n                    xbox::services::Utils::StringFromStringT(ticketDetailsResponse.target_session().session_name()).c_str(),\n                    xbox::services::Utils::StringFromStringT(ticketDetailsResponse.target_session().session_template_name()).c_str());\n\n                if (!ticketDetailsResponse.ticket_attributes().is_null())\n                {\n                    LogToScreen(\"match_ticket_details_response.ticket_attributes: %d\", xbox::services::Utils::StringFromStringT(ticketDetailsResponse.ticket_attributes().serialize()).c_str());\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMatchmakingServiceGetMatchTicketDetails\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MatchmakingServiceGetHopperStatistics_Lua(lua_State* L)\n{\n    string_t hopperName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"PlayerSkillNoQoS\").c_str());\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, Data()->scid).c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->matchmaking_service().get_hopper_statistics(serviceConfigurationId, hopperName).then(\n        [](xbox::services::xbox_live_result<xbox::services::matchmaking::hopper_statistics_response> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MatchmakingServiceGetHopperStatistics: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::matchmaking::hopper_statistics_response hopperStatisticsResponse = result.payload();\n\n                LogToScreen(\"hopper_statistics_response.hopper_name: %s\", xbox::services::Utils::StringFromStringT(hopperStatisticsResponse.hopper_name()).c_str());\n                LogToScreen(\"hopper_statistics_response.estimated_wait_time: %d\", hopperStatisticsResponse.estimated_wait_time());\n                LogToScreen(\"hopper_statistics_response.players_waiting_to_match: %d\", hopperStatisticsResponse.players_waiting_to_match());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnMatchmakingServiceGetHopperStatistics\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint MatchmakingServiceDeleteMatchTicket_Lua(lua_State* L)\n{\n    string_t hopperName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"PlayerSkillNoQoS\").c_str());\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, Data()->scid).c_str());\n    string_t ticketId = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 3, \"\").c_str());\n    if (ticketId.empty())\n    {\n        ticketId = Data()->matchTicketResponseCpp.match_ticket_id();\n    }\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->matchmaking_service().delete_match_ticket(\n        serviceConfigurationId,\n        hopperName,\n        ticketId\n    ).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"MatchmakingServiceDeleteMatchTicket: hr=%s\", ConvertHR(hr).c_str());\n\n            CallLuaFunctionWithHr(hr, \"OnMatchmakingServiceDeleteMatchTicket\");\n        });\n\n    return LuaReturnHR(L, S_OK);\n}\n\n#else //CPP_TESTS_ENABLED\n\n//multiplayer_session_reference\n\nint MultiplayerSessionReferenceIsValidCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionReferenceCreateCpp_Lua(lua_State* L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionReferenceParseFromUriPathCpp_Lua(lua_State* L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\n//multitplayer_session\n\nint MultiplayerSessionCreateCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionJoinCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionAddMemberReservationCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionTimeOfSessionCpp_Lua(lua_State* L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionGetInitializationInfoCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSubscribedChangeTypesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionHostCandidatesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSessionReferenceCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSessionConstantsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetVisibilityCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMaxMembersInSessionCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetTimeoutsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetQosConnectivityMetricsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMemberInitializationCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetPeerToPeerRequirementsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetPeerToHostRequirementsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetSessionCapabilitiesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCloudComputePackageJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSessionPropertiesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionPropertiesSetKeywordsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionPropertiesSetJoinRestrictionCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionPropertiesSetReadRestrictionCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionRoleTypesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionMembersCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionGetMemberCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionMatchmakingServerCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionMembersAcceptedCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionServersJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetServersJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionEtagCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionCurrentUserCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionGetInfoCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionWriteStatusCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetInitializationStatusCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetHostDeviceTokenCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMatchmakingServerConnectionPathCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetClosedCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetLockedCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetAllocateCloudComputeCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMatchmakingResubmitCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetServerConnectionStringCandidatesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetSessionChangeSubscriptionCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionLeaveCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCurrentUserStatusCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCurrentUserSecureDeviceAddressBase64Cpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCurrentUserRolesCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionCurrentUserSetGroupsCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionCurrentUserSetEncountersCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCurrentUserQosMeasurementsJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetCurrentUserMemberCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionDeleteCurrentUserMemberCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetMatchmakingTargetSessionConstantsJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionSetSessionCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionDeleteSessionCustomPropertyJsonCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSessionCompareCpp_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\n//multiplayer_service\n\nint MultiplayerServiceWriteSession_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceWriteSession\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceWriteSessionByHandle_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceWriteSessionByHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetCurrentSession_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceGetCurrentSession\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetCurrentSessionByHandle_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceGetCurrentSessionByHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetSessions_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceGetSessions\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSetActivity_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceSetActivity\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceClearActivity_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceClearActivity\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSendInvites_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceSendInvites\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetActivitiesForSocialGroup_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceGetActivitiesForSocialGroup\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetActivitiesForUsers_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceGetActivitiesForUsers\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceEnableMultiplayerSubscriptions_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceDisableMultiplayerSubscriptions_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceMultiplayerSubscriptionsEnabled_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceAddMultiplayerSessionChangedHandler_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceRemoveMultiplayerSessionChangedHandler_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceAddMultiplayerSubscriptionLostHandler_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceAddMultiplayerConnectionIdChangedHandler_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceRemoveMultiplayerConnectionIdChangedHandler_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSetTransferHandle_Lua(lua_State* L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceSetTransferHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceSetSearchHandle_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceSetSearchHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceClearSearchHandle_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceClearSearchHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerServiceGetSearchHandles_Lua(lua_State *L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMultiplayerServiceGetSearchHandles\");\n    return LuaReturnHR(L, S_OK);\n}\n\n//multiplayer_search_handle_detail\n\nint MultiplayerSearchHandleDetailsCloseHandle_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsSessionReference_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsHandleId_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsSessionOwnerXuids_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsTags_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsStringsMetadata_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsNumbersMetadata_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsVisibility_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsJoinRestriction_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsClosed_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsMemberCounts_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsHandleCreationTime_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\nint MultiplayerSearchHandleDetailsCustomSessionPropertiesJson_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n\n//matchmaking_service\n\nint MatchmakingServiceCreateTicket_Lua(lua_State* L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMatchmakingServiceCreateTicket\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MatchmakingServiceGetMatchTicketDetails_Lua(lua_State* L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMatchmakingServiceGetMatchTicketDetails\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MatchmakingServiceGetHopperStatistics_Lua(lua_State* L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMatchmakingServiceGetHopperStatistics\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint MatchmakingServiceDeleteMatchTicket_Lua(lua_State* L)\n{\n    CallLuaFunctionWithHr(S_OK, \"OnMatchmakingServiceDeleteMatchTicket\");\n    return LuaReturnHR(L, S_OK);\n}\n\n#endif //CPP_TESTS_ENABLED\n\nvoid SetupAPIs_CppMultiplayer()\n{\n    //multiplayer_session_reference\n    lua_register(Data()->L, \"MultiplayerSessionReferenceCreateCpp\", MultiplayerSessionReferenceCreateCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionReferenceParseFromUriPathCpp\", MultiplayerSessionReferenceParseFromUriPathCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionReferenceIsValidCpp\", MultiplayerSessionReferenceIsValidCpp_Lua);\n\n    //multiplayer_session\n    lua_register(Data()->L, \"MultiplayerSessionCreateCpp\", MultiplayerSessionCreateCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionJoinCpp\", MultiplayerSessionJoinCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionAddMemberReservationCpp\", MultiplayerSessionAddMemberReservationCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionTimeOfSessionCpp\", MultiplayerSessionTimeOfSessionCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionGetInitializationInfoCpp\", MultiplayerSessionGetInitializationInfoCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSubscribedChangeTypesCpp\", MultiplayerSessionSubscribedChangeTypesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionHostCandidatesCpp\", MultiplayerSessionHostCandidatesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSessionReferenceCpp\", MultiplayerSessionSessionReferenceCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSessionConstantsCpp\", MultiplayerSessionSessionConstantsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetVisibilityCpp\", MultiplayerSessionSetVisibilityCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetMaxMembersInSessionCpp\", MultiplayerSessionSetMaxMembersInSessionCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetTimeoutsCpp\", MultiplayerSessionSetTimeoutsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetQosConnectivityMetricsCpp\", MultiplayerSessionSetQosConnectivityMetricsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetMemberInitializationCpp\", MultiplayerSessionSetMemberInitializationCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetPeerToPeerRequirementsCpp\", MultiplayerSessionSetPeerToPeerRequirementsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetPeerToHostRequirementsCpp\", MultiplayerSessionSetPeerToHostRequirementsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetSessionCapabilitiesCpp\", MultiplayerSessionSetSessionCapabilitiesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetCloudComputePackageJsonCpp\", MultiplayerSessionSetCloudComputePackageJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSessionPropertiesCpp\", MultiplayerSessionSessionPropertiesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionPropertiesSetKeywordsCpp\", MultiplayerSessionPropertiesSetKeywordsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionPropertiesSetJoinRestrictionCpp\", MultiplayerSessionPropertiesSetJoinRestrictionCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionPropertiesSetReadRestrictionCpp\", MultiplayerSessionPropertiesSetReadRestrictionCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionRoleTypesCpp\", MultiplayerSessionRoleTypesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionMembersCpp\", MultiplayerSessionMembersCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionGetMemberCpp\", MultiplayerSessionGetMemberCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionMatchmakingServerCpp\", MultiplayerSessionMatchmakingServerCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionMembersAcceptedCpp\", MultiplayerSessionMembersAcceptedCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionServersJsonCpp\", MultiplayerSessionServersJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetServersJsonCpp\", MultiplayerSessionSetServersJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionEtagCpp\", MultiplayerSessionEtagCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionCurrentUserCpp\", MultiplayerSessionCurrentUserCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionGetInfoCpp\", MultiplayerSessionGetInfoCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionWriteStatusCpp\", MultiplayerSessionWriteStatusCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetInitializationStatusCpp\", MultiplayerSessionSetInitializationStatusCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetHostDeviceTokenCpp\", MultiplayerSessionSetHostDeviceTokenCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetMatchmakingServerConnectionPathCpp\", MultiplayerSessionSetMatchmakingServerConnectionPathCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetClosedCpp\", MultiplayerSessionSetClosedCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetLockedCpp\", MultiplayerSessionSetLockedCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetAllocateCloudComputeCpp\", MultiplayerSessionSetAllocateCloudComputeCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetMatchmakingResubmitCpp\", MultiplayerSessionSetMatchmakingResubmitCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetServerConnectionStringCandidatesCpp\", MultiplayerSessionSetServerConnectionStringCandidatesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetSessionChangeSubscriptionCpp\", MultiplayerSessionSetSessionChangeSubscriptionCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionLeaveCpp\", MultiplayerSessionLeaveCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetCurrentUserStatusCpp\", MultiplayerSessionSetCurrentUserStatusCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetCurrentUserSecureDeviceAddressBase64Cpp\", MultiplayerSessionSetCurrentUserSecureDeviceAddressBase64Cpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetCurrentUserRolesCpp\", MultiplayerSessionSetCurrentUserRolesCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionCurrentUserSetGroupsCpp\", MultiplayerSessionCurrentUserSetGroupsCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionCurrentUserSetEncountersCpp\", MultiplayerSessionCurrentUserSetEncountersCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetCurrentUserQosMeasurementsJsonCpp\", MultiplayerSessionSetCurrentUserQosMeasurementsJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetCurrentUserMemberCustomPropertyJsonCpp\", MultiplayerSessionSetCurrentUserMemberCustomPropertyJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionDeleteCurrentUserMemberCustomPropertyJsonCpp\", MultiplayerSessionDeleteCurrentUserMemberCustomPropertyJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetMatchmakingTargetSessionConstantsJsonCpp\", MultiplayerSessionSetMatchmakingTargetSessionConstantsJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionSetSessionCustomPropertyJsonCpp\", MultiplayerSessionSetSessionCustomPropertyJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionDeleteSessionCustomPropertyJsonCpp\", MultiplayerSessionDeleteSessionCustomPropertyJsonCpp_Lua);\n    lua_register(Data()->L, \"MultiplayerSessionCompareCpp\", MultiplayerSessionCompareCpp_Lua);\n\n    //multiplayer_service\n    lua_register(Data()->L, \"MultiplayerServiceWriteSession\", MultiplayerServiceWriteSession_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceWriteSessionByHandle\", MultiplayerServiceWriteSessionByHandle_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceGetCurrentSession\", MultiplayerServiceGetCurrentSession_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceGetCurrentSessionByHandle\", MultiplayerServiceGetCurrentSessionByHandle_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceGetSessions\", MultiplayerServiceGetSessions_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceSetActivity\", MultiplayerServiceSetActivity_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceClearActivity\", MultiplayerServiceClearActivity_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceSendInvites\", MultiplayerServiceSendInvites_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceGetActivitiesForSocialGroup\", MultiplayerServiceGetActivitiesForSocialGroup_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceGetActivitiesForUsers\", MultiplayerServiceGetActivitiesForUsers_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceEnableMultiplayerSubscriptions\", MultiplayerServiceEnableMultiplayerSubscriptions_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceDisableMultiplayerSubscriptions\", MultiplayerServiceDisableMultiplayerSubscriptions_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceMultiplayerSubscriptionsEnabled\", MultiplayerServiceMultiplayerSubscriptionsEnabled_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceAddMultiplayerSessionChangedHandler\", MultiplayerServiceAddMultiplayerSessionChangedHandler_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceRemoveMultiplayerSessionChangedHandler\", MultiplayerServiceRemoveMultiplayerSessionChangedHandler_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceAddMultiplayerSubscriptionLostHandler\", MultiplayerServiceAddMultiplayerSubscriptionLostHandler_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler\", MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceAddMultiplayerConnectionIdChangedHandler\", MultiplayerServiceAddMultiplayerConnectionIdChangedHandler_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceRemoveMultiplayerConnectionIdChangedHandler\", MultiplayerServiceRemoveMultiplayerConnectionIdChangedHandler_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceSetTransferHandle\", MultiplayerServiceSetTransferHandle_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceSetSearchHandle\", MultiplayerServiceSetSearchHandle_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceClearSearchHandle\", MultiplayerServiceClearSearchHandle_Lua);\n    lua_register(Data()->L, \"MultiplayerServiceGetSearchHandles\", MultiplayerServiceGetSearchHandles_Lua);\n\n    //multiplayer_search_handle_details\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsCloseHandle\", MultiplayerSearchHandleDetailsCloseHandle_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsSessionReference\", MultiplayerSearchHandleDetailsSessionReference_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsHandleId\", MultiplayerSearchHandleDetailsHandleId_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsSessionOwnerXuids\", MultiplayerSearchHandleDetailsSessionOwnerXuids_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsTags\", MultiplayerSearchHandleDetailsTags_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsStringsMetadata\", MultiplayerSearchHandleDetailsStringsMetadata_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsNumbersMetadata\", MultiplayerSearchHandleDetailsNumbersMetadata_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsVisibility\", MultiplayerSearchHandleDetailsVisibility_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsJoinRestriction\", MultiplayerSearchHandleDetailsJoinRestriction_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsClosed\", MultiplayerSearchHandleDetailsClosed_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsMemberCounts\", MultiplayerSearchHandleDetailsMemberCounts_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsHandleCreationTime\", MultiplayerSearchHandleDetailsHandleCreationTime_Lua);\n    lua_register(Data()->L, \"MultiplayerSearchHandleDetailsCustomSessionPropertiesJson\", MultiplayerSearchHandleDetailsCustomSessionPropertiesJson_Lua);\n\n    //matchmaking_service\n    lua_register(Data()->L, \"MatchmakingServiceCreateTicket\", MatchmakingServiceCreateTicket_Lua);\n    lua_register(Data()->L, \"MatchmakingServiceGetMatchTicketDetails\", MatchmakingServiceGetMatchTicketDetails_Lua);\n    lua_register(Data()->L, \"MatchmakingServiceGetHopperStatistics\", MatchmakingServiceGetHopperStatistics_Lua);\n    lua_register(Data()->L, \"MatchmakingServiceDeleteMatchTicket\", MatchmakingServiceDeleteMatchTicket_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_presence.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#if CPP_TESTS_ENABLED\nstatic struct PresenceStateCpp\n{\n    PresenceStateCpp() = default;\n    ~PresenceStateCpp()\n    {\n        //assert(!presenceRecord);\n        assert(!devicePresenceChangeSubscription);\n        assert(!titlePresenceChangeSubscription);\n        assert(!devicePresenceChangedHandlerContext);\n        assert(!titlePresenceChangedHandlerContext);\n    }\n\n    std::shared_ptr<xbox::services::presence::presence_record> presenceRecord{ nullptr };\n    std::shared_ptr<xbox::services::presence::device_presence_change_subscription> devicePresenceChangeSubscription{ nullptr };\n    std::shared_ptr<xbox::services::presence::title_presence_change_subscription> titlePresenceChangeSubscription{ nullptr };\n    function_context devicePresenceChangedHandlerContext{ nullptr };\n    function_context titlePresenceChangedHandlerContext{ nullptr };\n} presenceStateCpp;\n\n#endif\n\nint PresenceRecordGetXuidCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t xuid = presenceStateCpp.presenceRecord->xbox_user_id();\n    LogToScreen(\"PresenceRecordGetXuidCpp xuid=%s\", xbox::services::Utils::StringFromStringT(xuid).c_str());\n#else\n    LogToFile(\"PresenceRecordGetXuidCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceRecordGetUserStateCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::presence::user_presence_state userState = presenceStateCpp.presenceRecord->user_state();\n    LogToScreen(\"PresenceRecordGetUserStateCpp state=%u\", userState);\n#else\n    LogToFile(\"PresenceRecordGetUserStateCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceRecordGetDeviceRecordsCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::vector<xbox::services::presence::presence_device_record> deviceRecords = presenceStateCpp.presenceRecord->presence_device_records();\n    for (auto deviceRecord : deviceRecords)\n    {\n        LogToScreen(\"Got presence_device_record with device type %u and %u title records\", deviceRecord.device_type(), deviceRecord.presence_title_records().size());\n        for (auto titleRecord : deviceRecord.presence_title_records())\n        {\n            LogToScreen(\"Title record titleId %u\", titleRecord.title_id());\n        }\n\n    }\n    LogToFile(\"PresenceRecordGetDeviceRecordsCpp\");\n#else\n    LogToFile(\"PresenceRecordGetDeviceRecordsCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceRecordCloseHandleCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    presenceStateCpp.presenceRecord = nullptr;\n    LogToFile(\"PresenceRecordCloseHandleCpp\");\n#else\n    LogToFile(\"PresenceRecordCloseHandleCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceSetPresence_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    bool isActiveInTitle = GetUint64FromLua(L, 1, 1);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->presence_service().set_presence(isActiveInTitle).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PresenceServiceSetPresence: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n\n            }\n            if (hr == HTTP_E_STATUS_429_TOO_MANY_REQUESTS)\n            {\n                LogToFile(\"PresenceServiceSetPresence returned 429.  Ignoring failure\");\n                hr = S_OK;\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPresenceServiceSetPresence\");\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnPresenceServiceSetPresence\");\n    LogToFile(\"PresenceServiceSetPresence is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceGetPresence_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    uint64_t xuid = Data()->xboxUserId;\n    if (Data()->m_multiDeviceManager->GetRemoteXuid() != 0)\n    {\n        xuid = Data()->m_multiDeviceManager->GetRemoteXuid();\n    }\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 1, xuid));\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->presence_service().get_presence(xboxUserId).then(\n        [](xbox::services::xbox_live_result<xbox::services::presence::presence_record> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PresenceServiceGetPresence: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                presenceStateCpp.presenceRecord = std::make_shared<xbox::services::presence::presence_record>(result.payload());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPresenceServiceGetPresence\");\n        });\n#else\n    LogToFile(\"PresenceServiceGetPresence is disabled for this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnPresenceServiceGetPresence\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceGetPresenceForMultipleUsers_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::vector<string_t> xuids{ _T(\"2814639011617876\"), _T(\"2814641789541994\") };\n    std::vector<xbox::services::presence::presence_device_type> deviceTypes;\n    std::vector<uint32_t> titleIds;\n    xbox::services::presence::presence_detail_level detailLevel = xbox::services::presence::presence_detail_level::all;\n    bool onlineOnly = true;\n    bool broadcastingOnly = false;\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->presence_service().get_presence_for_multiple_users(\n        xuids,\n        deviceTypes,\n        titleIds,\n        detailLevel,\n        onlineOnly,\n        broadcastingOnly\n    ).then([](xbox::services::xbox_live_result<std::vector<xbox::services::presence::presence_record>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PresenceServiceGetPresenceForMultipleUsers: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                LogToFile(\"Got %u presence records\", result.payload().size());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPresenceServiceGetPresenceForMultipleUsers\");\n        });\n#else\n    LogToFile(\"PresenceServiceGetPresenceForMultipleUsers is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnPresenceServiceGetPresenceForMultipleUsers\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceGetPresenceForSocialGroup_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t socialGroup = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"Friends\").c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->presence_service().get_presence_for_social_group(socialGroup).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::presence::presence_record>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PresenceServiceGetPresenceForSocialGroup: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                LogToFile(\"Got %u presence records\", result.payload().size());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPresenceServiceGetPresenceForMultipleUsers\");\n        });\n#else\n    LogToFile(\"PresenceServiceGetPresenceForSocialGroup is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnPresenceServiceGetPresenceForMultipleUsers\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceSubscribeToDevicePresenceChange_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t xuid{ _T(\"2814639011617876\") };\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xbox::services::xbox_live_result<std::shared_ptr<xbox::services::presence::device_presence_change_subscription>> result = xblc->presence_service().subscribe_to_device_presence_change(xuid);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    LogToFile(\"PresenceServiceSubscribeToDevicePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n\n    if (SUCCEEDED(hr))\n    {\n        presenceStateCpp.devicePresenceChangeSubscription = result.payload();\n    }\n\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"PresenceServiceSubscribeToDevicePresenceChange is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint PresenceServiceUnsubscribeFromDevicePresenceChange_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xbox::services::xbox_live_result<void> result = xblc->presence_service().unsubscribe_from_device_presence_change(presenceStateCpp.devicePresenceChangeSubscription);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    LogToFile(\"PresenceServiceUnsubscribeFromDevicePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n\n    if (SUCCEEDED(hr))\n    {\n        presenceStateCpp.devicePresenceChangeSubscription = nullptr;\n    }\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"PresenceServiceUnsubscribeFromDevicePresenceChange is disabled for this platform\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint PresenceServiceSubscribeToTitlePresenceChange_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t xuid{ _T(\"2814639011617876\") };\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xbox::services::xbox_live_result<std::shared_ptr<xbox::services::presence::title_presence_change_subscription>> result = xblc->presence_service().subscribe_to_title_presence_change(xuid, Data()->titleId);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    LogToFile(\"PresenceServiceSubscribeToTitlePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n\n    if (SUCCEEDED(hr))\n    {\n        presenceStateCpp.titlePresenceChangeSubscription = result.payload();\n    }\n\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"PresenceServiceSubscribeToTitlePresenceChange is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint PresenceServiceUnsubscribeFromTitlePresenceChange_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xbox::services::xbox_live_result<void> result = xblc->presence_service().unsubscribe_from_title_presence_change(presenceStateCpp.titlePresenceChangeSubscription);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    LogToFile(\"PresenceServiceUnsubscribeFromTitlePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n\n    if (SUCCEEDED(hr))\n    {\n        presenceStateCpp.titlePresenceChangeSubscription = nullptr;\n    }\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"PresenceServiceUnsubscribeFromTitlePresenceChange is disabled for this platform\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint PresenceServiceAddDevicePresenceChangedHandler_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    presenceStateCpp.devicePresenceChangedHandlerContext = xblc->presence_service().add_device_presence_changed_handler(\n        [](xbox::services::presence::device_presence_change_event_args args) \n        {\n            LogToFile(\"Device presence change notification received:\");\n            LogToFile(\"Xuid = %s, device_type = %u, is_user_logged_on_device = %u\", xbox::services::Utils::StringFromStringT(args.xbox_user_id()).c_str(), args.device_type(), args.is_user_logged_on_device());\n        });\n\n    LogToFile(\"PresenceServiceAddDevicePresenceChangedHandler\");\n#else\n    LogToFile(\"PresenceServiceAddDevicePresenceChangedHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceRemoveDevicePresenceChangedHandler_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->presence_service().remove_device_presence_changed_handler(presenceStateCpp.devicePresenceChangedHandlerContext);\n\n    presenceStateCpp.devicePresenceChangedHandlerContext = nullptr;\n    LogToFile(\"PresenceServiceRemoveDevicePresenceChangedHandler\");\n#else\n    LogToFile(\"PresenceServiceRemoveDevicePresenceChangedHandler is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceAddTitlePresenceChangedHandler_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    presenceStateCpp.titlePresenceChangedHandlerContext = xblc->presence_service().add_title_presence_changed_handler(\n        [](xbox::services::presence::title_presence_change_event_args args)\n        {\n            LogToFile(\"Title presence change notification received:\");\n            LogToFile(\"Xuid = %s, title_id = %u, title_state = %u\", xbox::services::Utils::StringFromStringT(args.xbox_user_id()).c_str(), args.title_id(), args.title_state());\n        });\n\n    LogToFile(\"PresenceServiceAddTitlePresenceChangedHandler\");\n#else\n    LogToFile(\"PresenceServiceAddTitlePresenceChangedHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PresenceServiceRemoveTitlePresenceChangedHandler_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->presence_service().remove_title_presence_changed_handler(presenceStateCpp.titlePresenceChangedHandlerContext);\n\n    presenceStateCpp.titlePresenceChangedHandlerContext = nullptr;\n    LogToFile(\"PresenceServiceRemoveTitlePresenceChangedHandler\");\n#else\n    LogToFile(\"PresenceServiceRemoveTitlePresenceChangedHandler is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppPresence()\n{\n    lua_register(Data()->L, \"PresenceRecordGetXuidCpp\", PresenceRecordGetXuidCpp_Lua);\n    lua_register(Data()->L, \"PresenceRecordGetUserStateCpp\", PresenceRecordGetUserStateCpp_Lua);\n    lua_register(Data()->L, \"PresenceRecordGetDeviceRecordsCpp\", PresenceRecordGetDeviceRecordsCpp_Lua);\n    lua_register(Data()->L, \"PresenceRecordCloseHandleCpp\", PresenceRecordCloseHandleCpp_Lua);\n\n    lua_register(Data()->L, \"PresenceServiceSetPresence\", PresenceServiceSetPresence_Lua);\n    lua_register(Data()->L, \"PresenceServiceGetPresence\", PresenceServiceGetPresence_Lua);\n    lua_register(Data()->L, \"PresenceServiceGetPresenceForSocialGroup\", PresenceServiceGetPresenceForSocialGroup_Lua);\n    lua_register(Data()->L, \"PresenceServiceGetPresenceForMultipleUsers\", PresenceServiceGetPresenceForMultipleUsers_Lua);\n    lua_register(Data()->L, \"PresenceServiceSubscribeToDevicePresenceChange\", PresenceServiceSubscribeToDevicePresenceChange_Lua);\n    lua_register(Data()->L, \"PresenceServiceUnsubscribeFromDevicePresenceChange\", PresenceServiceUnsubscribeFromDevicePresenceChange_Lua);\n    lua_register(Data()->L, \"PresenceServiceSubscribeToTitlePresenceChange\", PresenceServiceSubscribeToTitlePresenceChange_Lua);\n    lua_register(Data()->L, \"PresenceServiceUnsubscribeFromTitlePresenceChange\", PresenceServiceUnsubscribeFromTitlePresenceChange_Lua);\n    lua_register(Data()->L, \"PresenceServiceAddDevicePresenceChangedHandler\", PresenceServiceAddDevicePresenceChangedHandler_Lua);\n    lua_register(Data()->L, \"PresenceServiceRemoveDevicePresenceChangedHandler\", PresenceServiceRemoveDevicePresenceChangedHandler_Lua);\n    lua_register(Data()->L, \"PresenceServiceAddTitlePresenceChangedHandler\", PresenceServiceAddTitlePresenceChangedHandler_Lua);\n    lua_register(Data()->L, \"PresenceServiceRemoveTitlePresenceChangedHandler\", PresenceServiceRemoveTitlePresenceChangedHandler_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_privacy.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#if CPP_TESTS_ENABLED\nstring_t ConvertXblPermissionToStringT(XblPermission permissionType)\n{\n    switch (permissionType)\n    {\n    case XblPermission::BroadcastWithTwitch:\n        return xbox::services::privacy::permission_id_constants::broadcast_with_twitch();\n    case XblPermission::CommunicateUsingText:\n        return xbox::services::privacy::permission_id_constants::communicate_using_text();\n    case XblPermission::CommunicateUsingVideo:\n        return xbox::services::privacy::permission_id_constants::communicate_using_video();\n    case XblPermission::CommunicateUsingVoice:\n        return xbox::services::privacy::permission_id_constants::communicate_using_voice();\n    case XblPermission::PlayMultiplayer:\n        return xbox::services::privacy::permission_id_constants::play_multiplayer();\n    //case XblPermission::ShareItem:\n        //unsupported\n    //case XblPermission::ShareTargetContentToExternalNetworks:\n        //unsupported\n    case XblPermission::ViewTargetExerciseInfo:\n        return xbox::services::privacy::permission_id_constants::view_target_exercise_info();\n    case XblPermission::ViewTargetGameHistory:\n        return xbox::services::privacy::permission_id_constants::view_target_game_history();\n    case XblPermission::ViewTargetMusicHistory:\n        return xbox::services::privacy::permission_id_constants::view_target_music_history();\n    case XblPermission::ViewTargetMusicStatus:\n        return xbox::services::privacy::permission_id_constants::view_target_music_status();\n    case XblPermission::ViewTargetPresence:\n        return xbox::services::privacy::permission_id_constants::view_target_presence();\n    case XblPermission::ViewTargetProfile:\n        return xbox::services::privacy::permission_id_constants::view_target_profile();\n    case XblPermission::ViewTargetUserCreatedContent:\n        return xbox::services::privacy::permission_id_constants::view_target_user_created_content();\n    case XblPermission::ViewTargetVideoHistory:\n        return xbox::services::privacy::permission_id_constants::view_target_video_history();\n    case XblPermission::ViewTargetVideoStatus:\n        return xbox::services::privacy::permission_id_constants::view_target_video_status();\n    case XblPermission::WriteComment:\n    case XblPermission::ShareItem:\n    case XblPermission::ShareTargetContentToExternalNetworks:\n    case XblPermission::Unknown:\n    default:\n        return _T(\"Unknown\");\n    }\n}\n#endif\nint PrivacyServiceGetAvoidList_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->privacy_service().get_avoid_list().then(\n        [](xbox::services::xbox_live_result<std::vector<string_t>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PrivacyServiceGetAvoidList: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<string_t> avoidList = result.payload();\n                LogToFile(\"PrivacyServiceGetAvoidList avoided xuids count=%d\", avoidList.size());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPrivacyServiceGetAvoidList\");\n        });\n#else\n    LogToFile(\"PrivacyServiceGetAvoidList is disabled on this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnPrivacyServiceGetAvoidList\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint PrivacyServiceCheckPermissionWithTargetUser_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t permissionToCheck = ConvertXblPermissionToStringT(static_cast<XblPermission>(GetUint32FromLua(L, 1, (uint32_t)XblPermission::ViewTargetProfile)));\n    string_t targetXuid = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 2, 2743710844428572));\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->privacy_service().check_permission_with_target_user(\n        permissionToCheck,\n        targetXuid\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::privacy::permission_check_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PrivacyServiceCheckPermissionWithTargetUser: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::privacy::permission_check_result permissionResult = result.payload();\n                LogToFile(\"PrivacyServiceCheckPermissionWithTargetUser: isAllowed=%d\", permissionResult.is_allowed());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPrivacyServiceCheckPermissionWithTargetUser\");\n        });\n#else\n    LogToFile(\"PrivacyServiceCheckPermissionWithTargetUser is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnPrivacyServiceCheckPermissionWithTargetUser\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::vector<string_t> permissionsToCheck{\n        xbox::services::privacy::permission_id_constants::communicate_using_text(),\n        xbox::services::privacy::permission_id_constants::communicate_using_video(),\n        xbox::services::privacy::permission_id_constants::communicate_using_voice(),\n        xbox::services::privacy::permission_id_constants::view_target_profile(),\n        xbox::services::privacy::permission_id_constants::view_target_game_history(),\n        xbox::services::privacy::permission_id_constants::view_target_video_history(),\n        xbox::services::privacy::permission_id_constants::view_target_music_history(),\n        xbox::services::privacy::permission_id_constants::view_target_exercise_info(),\n        xbox::services::privacy::permission_id_constants::view_target_presence(),\n        xbox::services::privacy::permission_id_constants::view_target_video_status(),\n        xbox::services::privacy::permission_id_constants::view_target_music_status(),\n        xbox::services::privacy::permission_id_constants::play_multiplayer(),\n        xbox::services::privacy::permission_id_constants::view_target_user_created_content(),\n        xbox::services::privacy::permission_id_constants::broadcast_with_twitch()\n    };\n    std::vector<string_t> targetXuids{\n        _T(\"2743710844428572\"),\n        _T(\"2533274819720636\"),\n        xbox::services::privacy::anonymous_user_type_constants::cross_network_user(),\n        xbox::services::privacy::anonymous_user_type_constants::crost_network_friend()\n    };\n\n    //the multiple_permissions_check_result for an anonymous type returns results for both anonymous types, is this expected?\n    size_t expectedResultCount{ permissionsToCheck.size() * (targetXuids.size() + 2) };\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->privacy_service().check_multiple_permissions_with_multiple_target_users(\n        permissionsToCheck,\n        targetXuids\n    ).then(\n        [expectedResultCount](xbox::services::xbox_live_result<std::vector<xbox::services::privacy::multiple_permissions_check_result>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::privacy::multiple_permissions_check_result> multiplePermissionsResults = result.payload();\n                size_t resultCount = 0;\n                for (xbox::services::privacy::multiple_permissions_check_result multiplePermissionsResult : multiplePermissionsResults)\n                {\n                    resultCount += multiplePermissionsResult.items().size();\n                }\n\n                LogToFile(\"PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers: expectedResultCount=%d resultCount=%d\", expectedResultCount, resultCount);\n                assert(resultCount == expectedResultCount);\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers\");\n        });\n#else\n    LogToFile(\"PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers is disabled for this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnPrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint PrivacyServiceGetMuteList_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->privacy_service().get_mute_list().then(\n        [](xbox::services::xbox_live_result<std::vector<string_t>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PrivacyServiceGetMuteList: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<string_t> muteList = result.payload();\n                LogToFile(\"PrivacyServiceGetMuteList muted xuids count=%d\", muteList.size());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPrivacyServiceGetMuteList\");\n        });\n#else\n    LogToFile(\"PrivacyServiceGetMuteList is disabled on this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnPrivacyServiceGetMuteList\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint PrivacyServiceGetAvoidOrMuteList_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->privacy_service().get_avoid_or_mute_list(\n        _T(\"avoid\")\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<string_t>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"PrivacyServiceGetAvoidOrMuteList: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<string_t> avoidList = result.payload();\n                LogToFile(\"PrivacyServiceGetAvoidOrMuteList xuids count=%d\", avoidList.size());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnPrivacyServiceGetAvoidOrMuteList\");\n        });\n#else\n    LogToFile(\"PrivacyServiceGetAvoidOrMuteList is disabled on this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnPrivacyServiceGetAvoidOrMuteList\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppPrivacy()\n{\n    lua_register(Data()->L, \"PrivacyServiceGetAvoidList\", PrivacyServiceGetAvoidList_Lua);\n    lua_register(Data()->L, \"PrivacyServiceCheckPermissionWithTargetUser\", PrivacyServiceCheckPermissionWithTargetUser_Lua);\n    lua_register(Data()->L, \"PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers\", PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers_Lua);\n    lua_register(Data()->L, \"PrivacyServiceGetMuteList\", PrivacyServiceGetMuteList_Lua);\n    lua_register(Data()->L, \"PrivacyServiceGetAvoidOrMuteList\", PrivacyServiceGetAvoidOrMuteList_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_profile.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint ProfileServiceGetUserProfile_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->profile_service().get_user_profile(\n        xboxUserId\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::social::xbox_user_profile> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"ProfileServiceGetUserProfile: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::social::xbox_user_profile userProfile = result.payload();\n                LogToFile(\"ProfileServiceGetUserProfile: gamertag=%s\", ConvertHR(hr).c_str(), xbox::services::Utils::StringFromStringT(userProfile.gamertag()).c_str());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnProfileServiceGetUserProfile\");\n        });\n#else\n    LogToFile(\"ProfileServiceGetUserProfile is disabled on this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnProfileServiceGetUserProfile\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint ProfileServiceGetUserProfiles_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::vector<string_t> userIds;\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    userIds.push_back(xboxUserId);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->profile_service().get_user_profiles(\n        userIds\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::social::xbox_user_profile>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"ProfileServiceGetUserProfiles: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::social::xbox_user_profile> profiles = result.payload();\n                LogToFile(\"ProfileServiceGetUserProfiles: gamertag=%s\", ConvertHR(hr).c_str(), xbox::services::Utils::StringFromStringT(profiles[0].gamertag()).c_str());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnProfileServiceGetUserProfiles\");\n        });\n#else\n    LogToFile(\"ProfileServiceGetUserProfiles is disabled on this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnProfileServiceGetUserProfiles\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint ProfileServiceGetUserProfilesForSocialGroup_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t socialGroup = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"People\").c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->profile_service().get_user_profiles_for_social_group(\n        socialGroup\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::social::xbox_user_profile>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"ProfileServiceGetUserProfilesForSocialGroup: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::social::xbox_user_profile> profiles = result.payload();\n                LogToFile(\"ProfileServiceGetUserProfilesForSocialGroup: profilesCount=%d\", profiles.size());\n                for (auto profile : profiles)\n                {\n                     LogToFile(\"\\tgamertag=%s\", xbox::services::Utils::StringFromStringT(profile.gamertag()).c_str());\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnProfileServiceGetUserProfilesForSocialGroup\");\n        });\n#else\n    LogToFile(\"ProfileServiceGetUserProfiles is disabled on this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnProfileServiceGetUserProfilesForSocialGroup\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppProfile()\n{\n    lua_register(Data()->L, \"ProfileServiceGetUserProfile\", ProfileServiceGetUserProfile_Lua);\n    lua_register(Data()->L, \"ProfileServiceGetUserProfiles\", ProfileServiceGetUserProfiles_Lua);\n    lua_register(Data()->L, \"ProfileServiceGetUserProfilesForSocialGroup\", ProfileServiceGetUserProfilesForSocialGroup_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_real_time_activity.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\n#if CPP_TESTS_ENABLED\nstatic function_context s_connectionStateHandlerContextCpp{ nullptr };\nstatic function_context s_subscriptionErrorHandlerContextCpp{ nullptr };\nstatic function_context s_resyncHandlerContextCpp{ nullptr };\n#endif\n\nint RealTimeActivityServiceActivate_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->real_time_activity_service()->activate();\n    LogToFile(\"RealTimeActivityServiceActivate\");\n#else\n    LogToFile(\"RealTimeActivityServiceActivate is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceDeactivate_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->real_time_activity_service()->deactivate();\n    LogToFile(\"RealTimeActivityServiceDeactivate\");\n#else\n    LogToFile(\"RealTimeActivityServiceDeactivate is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceAddConnectionStateChangeHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    s_connectionStateHandlerContextCpp = xblc->real_time_activity_service()->add_connection_state_change_handler(\n        [](xbox::services::real_time_activity::real_time_activity_connection_state connectionState)\n        {\n            LogToFile(\"RealTimeActivityServiceConnectionState changed to %d\", connectionState);\n\n            switch (connectionState)\n            {\n            case xbox::services::real_time_activity::real_time_activity_connection_state::connecting:\n                LogToFile(\"RealTimeActivityServiceAddConnectionStateChangeHandler: Connecting\\n\");\n                CallLuaFunction(\"OnRealTimeActivityServiceAddConnectionStateChangeHandler_Connecting\");\n                break;\n            case xbox::services::real_time_activity::real_time_activity_connection_state::connected:\n                LogToFile(\"RealTimeActivityServiceAddConnectionStateChangeHandler: Connected\\n\");\n                CallLuaFunction(\"OnRealTimeActivityServiceAddConnectionStateChangeHandler_Connected\");\n                break;\n            case xbox::services::real_time_activity::real_time_activity_connection_state::disconnected:\n                LogToFile(\"RealTimeActivityServiceAddConnectionStateChangeHandler: Connected\\n\");\n                CallLuaFunction(\"OnRealTimeActivityServiceAddConnectionStateChangeHandler_Disconnected\");\n                break;\n            }\n        });\n\n    LogToFile(\"RealTimeActivityServiceAddConnectionStateChangeHandler\");\n#else\n    LogToFile(\"RealTimeActivityServiceAddConnectionStateChangeHandler is disabled on this platform.\");\n    CallLuaFunction(\"OnRealTimeActivityServiceAddConnectionStateChangeHandler_Disabled\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceRemoveConnectionStateChangeHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    if (s_connectionStateHandlerContextCpp)\n    {\n        std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n        xblc->real_time_activity_service()->remove_connection_state_change_handler(s_connectionStateHandlerContextCpp);\n        s_connectionStateHandlerContextCpp = nullptr;\n    }\n\n    LogToFile(\"RealTimeActivityServiceRemoveConnectionStateChangeHandler\");\n#else\n    LogToFile(\"RealTimeActivityServiceRemoveConnectionStateChangeHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceAddSubscriptionErrorHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    s_subscriptionErrorHandlerContextCpp = xblc->real_time_activity_service()->add_subscription_error_handler(\n        [](xbox::services::real_time_activity::real_time_activity_subscription_error_event_args subscriptionError)\n        {\n            LogToFile(\"Rta subscription error %s\", ConvertHR(ConvertXboxLiveErrorCodeToHresult(subscriptionError.err())).c_str());\n        });\n\n    LogToFile(\"RealTimeActivityServiceAddSubscriptionErrorHandler\");\n#else\n    LogToFile(\"RealTimeActivityServiceAddSubscriptionErrorHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceRemoveSubscriptionErrorHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    if (s_subscriptionErrorHandlerContextCpp)\n    {\n        std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n        xblc->real_time_activity_service()->remove_subscription_error_handler(s_subscriptionErrorHandlerContextCpp);\n        s_subscriptionErrorHandlerContextCpp = nullptr;\n    }\n\n    LogToFile(\"RealTimeActivityServiceRemoveSubscriptionErrorHandler\");\n#else\n    LogToFile(\"RealTimeActivityServiceRemoveSubscriptionErrorHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceAddResyncHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    s_resyncHandlerContextCpp = xblc->real_time_activity_service()->add_resync_handler(\n        []()\n        {\n            LogToFile(\"RealTimeActivityServiceResyncHandler called\");\n        });\n\n    LogToFile(\"RealTimeActivityServiceAddResyncHandler\");\n#else\n    LogToFile(\"RealTimeActivityServiceAddResyncHandler is disabled for this platform\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint RealTimeActivityServiceRemoveResyncHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    if (s_resyncHandlerContextCpp)\n    {\n        std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n        xblc->real_time_activity_service()->remove_resync_handler(s_resyncHandlerContextCpp);\n        s_resyncHandlerContextCpp = nullptr;\n    }\n\n    LogToFile(\"RealTimeActivityServiceRemoveResyncHandler\");\n#else\n    LogToFile(\"RealTimeActivityServiceRemoveResyncHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppRta()\n{\n    lua_register(Data()->L, \"RealTimeActivityServiceActivate\", RealTimeActivityServiceActivate_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceDeactivate\", RealTimeActivityServiceDeactivate_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceAddConnectionStateChangeHandler\", RealTimeActivityServiceAddConnectionStateChangeHandler_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceRemoveConnectionStateChangeHandler\", RealTimeActivityServiceRemoveConnectionStateChangeHandler_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceAddSubscriptionErrorHandler\", RealTimeActivityServiceAddSubscriptionErrorHandler_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceRemoveSubscriptionErrorHandler\", RealTimeActivityServiceRemoveSubscriptionErrorHandler_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceAddResyncHandler\", RealTimeActivityServiceAddResyncHandler_Lua);\n    lua_register(Data()->L, \"RealTimeActivityServiceRemoveResyncHandler\", RealTimeActivityServiceRemoveResyncHandler_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_social.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\n#if CPP_TESTS_ENABLED\n\nxbox::services::social::xbox_social_relationship_filter ConvertStringToCppSocialRelationshipFilter(const char* str)\n{\n    xbox::services::social::xbox_social_relationship_filter filter = xbox::services::social::xbox_social_relationship_filter::all;\n\n    if (pal::stricmp(str, \"xbox_social_relationship_filter::all\") == 0) filter = xbox::services::social::xbox_social_relationship_filter::all;\n    else if (pal::stricmp(str, \"xbox_social_relationship_filter::Favorite\") == 0) filter = xbox::services::social::xbox_social_relationship_filter::favorite;\n    else if (pal::stricmp(str, \"xbox_social_relationship_filter::LegacyXboxLiveFriends\") == 0) filter = xbox::services::social::xbox_social_relationship_filter::legacy_xbox_live_friends;\n\n    return filter;\n}\n\n#endif\n\nint SocialServiceGetSocialRelationships_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::social::xbox_social_relationship_filter socialRelationshipFilter = ConvertStringToCppSocialRelationshipFilter(GetStringFromLua(L, 1, \"xbox_social_relationship_filter::all\").c_str());\n    uint32_t startIndex = 0;\n    uint32_t maxItems = 0;\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    auto task = xblc->social_service().get_social_relationships(\n        socialRelationshipFilter,\n        startIndex,\n        maxItems\n    ).then([xblc](xbox::services::xbox_live_result<xbox::services::social::xbox_social_relationship_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"SocialServiceGetSocialRelationships: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::social::xbox_social_relationship_result socialRelationshipResult = result.payload();\n                Data()->socialRelationshipResult = socialRelationshipResult;\n\n                auto relationships = socialRelationshipResult.items();\n                size_t relationshipsCount = relationships.size();\n\n                LogToFile(\"Got %u SocialRelationships:\", relationshipsCount);;\n                for (size_t i = 0; i < relationshipsCount; i++)\n                {\n                    LogToFile(\"Xuid = %s, isFollowingCaller = %u\", xbox::services::Utils::StringFromStringT(relationships[i].xbox_user_id()).c_str(), relationships[i].is_following_caller());\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnSocialServiceGetSocialRelationships\");\n\n        });\n#else\n    CallLuaFunctionWithHr(S_OK, \"OnSocialServiceGetSocialRelationships\");\n    LogToFile(\"SocialServiceGetSocialRelationships is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialRelationshipResultHasNextCpp_Lua(lua_State *L)\n{\n    bool hasNext{ false };\n#if CPP_TESTS_ENABLED\n    hasNext = Data()->socialRelationshipResult.has_next();\n    LogToFile(\"SocialRelationshipResultHasNextCpp: hasNext=%s\", hasNext ? \"true\" : \"false\");\n#else\n    LogToFile(\"SocialRelationshipResultHasNextCpp is disabled for this platform.\");\n#endif\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint SocialRelationshipResultGetNextCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    uint32_t maxItems = 100;\n    LogToFile(\"SocialRelationshipResultGetNextCpp MaxItems: %d\", maxItems);\n    Data()->socialRelationshipResult.get_next(maxItems).then(\n        [](xbox::services::xbox_live_result< xbox::services::social::xbox_social_relationship_result > result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::social::xbox_social_relationship_result socialRelationshipResult = result.payload();\n                Data()->socialRelationshipResult = socialRelationshipResult;\n\n                auto relationships = socialRelationshipResult.items();\n                size_t relationshipsCount = relationships.size();\n\n                LogToFile(\"Got %u SocialRelationships:\", relationshipsCount);;\n                for (size_t i = 0; i < relationshipsCount; i++)\n                {\n                    LogToFile(\"Xuid = %s, isFollowingCaller = %u\", xbox::services::Utils::StringFromStringT(relationships[i].xbox_user_id()).c_str(), relationships[i].is_following_caller());\n                }\n            }\n            CallLuaFunctionWithHr(hr, \"OnSocialRelationshipsResultGetNextCpp\");\n        });\n#else\n    LogToFile(\"SocialRelationshipResultGetNextCpp is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnSocialRelationshipsResultGetNextCpp\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialRelationshipResultCloseHandleCpp_Lua(lua_State* L)\n{\n    //The relationship result needs to be cleaned up before the lua script ends and global state is cleaned up, \n    //otherwise it will be the last reference to the xblContext, and cause the xblContext and xalUser to cleanup\n    //without global state.\n#if CPP_TESTS_ENABLED\n    //Force the relationship result to release it's handles early. Realistically this should never be called in a real use case scenario.\n    Data()->socialRelationshipResult.~xbox_social_relationship_result();\n#else\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialServiceSubscribeToSocialRelationshipChange_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t xboxUserID = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    auto result = xblc->social_service().subscribe_to_social_relationship_change(xboxUserID);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        Data()->socialRelationshipChangeSubscription = result.payload();\n    }\n    LogToFile(\"SocialServiceSubscribeToSocialRelationshipChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialServiceSubscribeToSocialRelationshipChange is disabled on this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n\n}\n\nint SocialServiceUnsubscribeFromSocialRelationshipChange_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    auto result = xblc->social_service().unsubscribe_from_social_relationship_change(Data()->socialRelationshipChangeSubscription);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        Data()->socialRelationshipChangeSubscription = nullptr;\n    }\n    LogToFile(\"SocialServiceUnsubscribeFromSocialRelationshipChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialServiceUnsubscribeFromSocialRelationshipChange is disabled on this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialServiceAddSocialRelationshipChangedHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    Data()->socialRelationshipChangedHandlerContext = xblc->social_service().add_social_relationship_changed_handler(\n        [](xbox::services::social::social_relationship_change_event_args args)\n        {\n            LogToFile(\"Social relationship changed:\");\n            std::stringstream ss;\n            for (size_t i = 0; i < args.xbox_user_ids().size(); ++i)\n            {\n                if (i > 0)\n                {\n                    ss << \", \";\n                }\n                ss << xbox::services::Utils::StringFromStringT(args.xbox_user_ids()[i]);\n            }\n            LogToFile(\"socialNotification = %u, affectedXuids = %s\", args.social_notification(), ss.str().data());\n        });\n    LogToFile(\"SocialServiceAddSocialRelationshipChangedHandler\");\n#else\n    LogToFile(\"SocialServiceAddSocialRelationshipChangedHandler is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialServiceRemoveSocialRelationshipChangedHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->social_service().remove_social_relationship_changed_handler(Data()->socialRelationshipChangedHandlerContext);\n    Data()->socialRelationshipChangedHandlerContext = nullptr;\n    LogToFile(\"SocialServiceRemoveSocialRelationshipChangedHandler\");\n#else\n    LogToFile(\"SocialServiceRemoveSocialRelationshipChangedHandler is disabled on this platform\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint ReputationServiceSubmitReputationFeedback_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::social::reputation_feedback_type reputationFeedbackType = xbox::services::social::reputation_feedback_type::positive_helpful_player;\n\n    string_t xuid = _T(\"2814639011617876\");\n    string_t sessionName = _T(\"\");\n    string_t reasonMessage = _T(\"Helpful player\");\n    string_t evidenceResourceId = _T(\"\");\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->reputation_service().submit_reputation_feedback(\n        xuid,\n        reputationFeedbackType,\n        sessionName,\n        reasonMessage,\n        evidenceResourceId\n    ).then([](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"ReputationServiceSubmitReputationFeedback: hr=%s\", ConvertHR(hr).c_str());\n            CallLuaFunctionWithHr(hr, \"OnReputationServiceSubmitReputationFeedback\");\n\n        });\n#else\n    LogToFile(\"ReputationServiceSubmitReputationFeedback is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnReputationServiceSubmitReputationFeedback\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint ReputationServiceSubmitBatchReputationFeedback_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::vector<xbox::services::social::reputation_feedback_item> feedbackItems;\n\n    feedbackItems.push_back(xbox::services::social::reputation_feedback_item\n        {\n            _T(\"2814639011617876\"),\n            xbox::services::social::reputation_feedback_type::positive_helpful_player,\n            xbox::services::multiplayer::multiplayer_session_reference(),\n            _T(\"Helpful player\"),\n            _T(\"\")\n        });\n\n    // Add any additional feedback items here\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->reputation_service().submit_batch_reputation_feedback(feedbackItems).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"ReputationServiceSubmitBatchReputationFeedback: hr=%s\", ConvertHR(hr).c_str());\n            CallLuaFunctionWithHr(hr, \"OnReputationServiceSubmitBatchReputationFeedback\");\n        });\n#else\n    LogToFile(\"ReputationServiceSubmitBatchReputationFeedback is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnReputationServiceSubmitBatchReputationFeedback\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppSocial()\n{\n    lua_register(Data()->L, \"SocialServiceGetSocialRelationships\", SocialServiceGetSocialRelationships_Lua);\n    lua_register(Data()->L, \"SocialRelationshipResultHasNextCpp\", SocialRelationshipResultHasNextCpp_Lua);\n    lua_register(Data()->L, \"SocialRelationshipResultGetNextCpp\", SocialRelationshipResultGetNextCpp_Lua);\n    lua_register(Data()->L, \"SocialRelationshipResultCloseHandleCpp\", SocialRelationshipResultCloseHandleCpp_Lua);\n\n    lua_register(Data()->L, \"SocialServiceSubscribeToSocialRelationshipChange\", SocialServiceSubscribeToSocialRelationshipChange_Lua);\n    lua_register(Data()->L, \"SocialServiceUnsubscribeFromSocialRelationshipChange\", SocialServiceUnsubscribeFromSocialRelationshipChange_Lua);\n    lua_register(Data()->L, \"SocialServiceAddSocialRelationshipChangedHandler\", SocialServiceAddSocialRelationshipChangedHandler_Lua);\n    lua_register(Data()->L, \"SocialServiceRemoveSocialRelationshipChangedHandler\", SocialServiceRemoveSocialRelationshipChangedHandler_Lua);\n\n    lua_register(Data()->L, \"ReputationServiceSubmitReputationFeedback\", ReputationServiceSubmitReputationFeedback_Lua);\n    lua_register(Data()->L, \"ReputationServiceSubmitBatchReputationFeedback\", ReputationServiceSubmitBatchReputationFeedback_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_social_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include <atomic>\n\n#if CPP_TESTS_ENABLED\nstatic struct SocialManagerCppState\n{\n    SocialManagerCppState() = default;\n    ~SocialManagerCppState()\n    {\n        // Validate that our tests cleaned up correctly\n        assert(!doWork);\n        assert(groups.empty());\n    }\n\n    std::map<uint64_t, std::shared_ptr<xbox::services::social::manager::xbox_social_user_group>> groups;\n    std::thread doWorkThread{};\n    std::atomic<bool> doWork{ false };\n    std::atomic<bool> doWorkJoinWhenDone{ false };\n} socialManagerCppState;\n\nHRESULT SocialManagerDoWorkCpp()\n{\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    std::vector<xbox::services::social::manager::social_event> events = socialManager->do_work();\n\n    for (auto& socialEvent : events)\n    {\n        static std::unordered_map<xbox::services::social::manager::social_event_type, std::string> eventTypesMap\n        {\n            { xbox::services::social::manager::social_event_type::users_added_to_social_graph, \"users_added_to_social_graph\" },\n            { xbox::services::social::manager::social_event_type::users_removed_from_social_graph, \"users_removed_from_social_graph\" },\n            { xbox::services::social::manager::social_event_type::presence_changed, \"presence_changed\" },\n            { xbox::services::social::manager::social_event_type::profiles_changed, \"profiles_changed\" },\n            { xbox::services::social::manager::social_event_type::social_relationships_changed, \"social_relationships_changed\" },\n            { xbox::services::social::manager::social_event_type::local_user_added, \"local_user_added\" },\n            { xbox::services::social::manager::social_event_type::social_user_group_loaded, \"social_user_group_loaded\" },\n            { xbox::services::social::manager::social_event_type::social_user_group_updated, \"social_user_group_updated\" },\n            { xbox::services::social::manager::social_event_type::unknown, \"unknown\" }\n        };\n\n        std::stringstream ss;\n        ss << \"social_manager::do_work: Event of type \" << eventTypesMap[socialEvent.event_type()] << std::endl;\n        ss << \"Users affected: \" << std::endl;\n        for (auto userContainer : socialEvent.users_affected())\n        {\n            char xuid[17];\n            xbox::services::Utils::Utf8FromCharT(userContainer.xbox_user_id(), xuid, sizeof(xuid));\n            ss << \"\\t\" << xuid << std::endl;\n        }\n        LogToFile(ss.str().c_str());\n\n        switch (socialEvent.event_type())\n        {\n        case xbox::services::social::manager::social_event_type::users_added_to_social_graph:\n            LogToFile(\"social_manager::do_work: users_added_to_social_graph event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_UsersAddedToSocialGraphEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::users_removed_from_social_graph:\n            LogToFile(\"social_manager::do_work: users_removed_from_social_graph event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_UsersRemovedFromSocialGraphEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::presence_changed:\n            LogToFile(\"social_manager::do_work: presence_changed event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_PresenceChangedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::profiles_changed:\n            LogToFile(\"social_manager::do_work: profiles_changed event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_ProfilesChangedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::social_relationships_changed:\n            LogToFile(\"social_manager::do_work: social_relationships_changed event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_SocialRelationshipsChangedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::local_user_added:\n            LogToFile(\"social_manager::do_work: local_user_added event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_LocalUserAddedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::local_user_removed:\n            LogToFile(\"social_manager::do_work: local_user_removed event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_LocalUserRemovedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::social_user_group_loaded:\n            LogToFile(\"social_manager::do_work: social_user_group_loaded event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::social_user_group_updated:\n            LogToFile(\"social_manager::do_work: social_user_group_updated event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_SocialUserGroupUpdatedEvent\");\n            break;\n        case xbox::services::social::manager::social_event_type::unknown:\n        default:\n            LogToFile(\"social_manager::do_work: unknown event\");\n            CallLuaFunctionWithHr(S_OK, \"OnSocialManagerDoWorkCpp_UnknownEvent\");\n            break;\n        }\n    }\n\n    return S_OK;\n}\n\nvoid StopSocialManagerDoWorkHelperCpp()\n{\n    if (socialManagerCppState.doWorkJoinWhenDone)\n    {\n        socialManagerCppState.doWork = false;\n        socialManagerCppState.doWorkJoinWhenDone = false;\n        socialManagerCppState.doWorkThread.join();\n    }\n}\n\nxbox::services::social::manager::social_manager_extra_detail_level ConvertStringToCppSocialManagerExtraDetailLevel(const char* str)\n{\n    xbox::services::social::manager::social_manager_extra_detail_level detailLevel = xbox::services::social::manager::social_manager_extra_detail_level::no_extra_detail;\n\n    if (pal::stricmp(str, \"social_manager_extra_detail_level::title_history_leve_T(\") == 0) detailLevel = xbox::services::social::manager::social_manager_extra_detail_level::title_history_level;\n    else if (pal::stricmp(str, \"social_manager_extra_detail_level::preferred_color_leve_T(\") == 0) detailLevel = xbox::services::social::manager::social_manager_extra_detail_level::preferred_color_level;\n\n    return detailLevel;\n}\n\nxbox::services::social::manager::presence_filter ConvertStringToCppPresenceFilter(const char* str)\n{\n    xbox::services::social::manager::presence_filter filter = xbox::services::social::manager::presence_filter::unknown;\n\n    if (pal::stricmp(str, \"presence_filter::title_online\") == 0) filter = xbox::services::social::manager::presence_filter::title_online;\n    else if (pal::stricmp(str, \"presence_filter::title_offline\") == 0) filter = xbox::services::social::manager::presence_filter::title_offline;\n#if XSAPI_BUILT_FROM_SOURCE\n    else if (pal::stricmp(str, \"presence_filter::title_online_outside_title\") == 0) filter = xbox::services::social::manager::presence_filter::title_online_outside_title;\n#endif\n    else if (pal::stricmp(str, \"presence_filter::all_online\") == 0) filter = xbox::services::social::manager::presence_filter::all_online;\n    else if (pal::stricmp(str, \"presence_filter::all_offline\") == 0) filter = xbox::services::social::manager::presence_filter::all_offline;\n    else if (pal::stricmp(str, \"presence_filter::all_title\") == 0) filter = xbox::services::social::manager::presence_filter::all_title;\n    else if (pal::stricmp(str, \"presence_filter::al_T(\") == 0) filter = xbox::services::social::manager::presence_filter::all;\n\n    return filter;\n}\n\nxbox::services::social::manager::relationship_filter ConvertStringToCppRelationshipFilter(const char* str)\n{\n    xbox::services::social::manager::relationship_filter filter = xbox::services::social::manager::relationship_filter::friends;\n\n    if (pal::stricmp(str, \"relationship_filter::friends\") == 0) filter = xbox::services::social::manager::relationship_filter::friends;\n    else if (pal::stricmp(str, \"relationship_filter::favorite\") == 0) filter = xbox::services::social::manager::relationship_filter::favorite;\n\n    return filter;\n}\n\n// Pool of XDKS.1 xuids to create social groups from\nstd::vector<string_t> listXuidStrings\n{\n    _T(\"2814639011617876\"),_T(\"2814641789541994\"),_T(\"2814644008675844\"),_T(\"2814644210052185\"),_T(\"2814645164579523\"),_T(\"2814646075485729\"),_T(\"2814649783195402\"),_T(\"2814650260879943\"),\n    _T(\"2814652370182940\"),_T(\"2814652714045777\"),_T(\"2814654391560620\"),_T(\"2814654975417728\"),_T(\"2814656000993855\"),_T(\"2814660006763195\"),_T(\"2814666715930430\"),_T(\"2814667316080600\"),\n    _T(\"2814669550092398\"),_T(\"2814669684179632\"),_T(\"2814669733667211\"),_T(\"2814671180786692\"),_T(\"2814679901432274\"),_T(\"2814613501048225\"),_T(\"2814614352529204\"),_T(\"2814615856126401\"),\n    _T(\"2814616641363830\"),_T(\"2814617883586813\"),_T(\"2814618053453081\"),_T(\"2814629752527080\"),_T(\"2814631255161151\"),_T(\"2814632477267887\"),_T(\"2814633284389038\"),_T(\"2814635732495522\"),\n    _T(\"2814635779785472\"),_T(\"2814635974475208\"),_T(\"2814636979708499\"),_T(\"2814618092438397\"),_T(\"2814618260480530\"),_T(\"2814618319551907\"),_T(\"2814619559360314\"),_T(\"2814620368929739\"),\n    _T(\"2814620769042115\"),_T(\"2814621007349381\"),_T(\"2814623088399025\"),_T(\"2814623825448960\"),_T(\"2814624220291971\"),_T(\"2814624961587858\"),_T(\"2814626394212372\"),_T(\"2814626639518570\"),\n    _T(\"2814628203722867\"),_T(\"2814629143923154\"),_T(\"2814614382301082\"),_T(\"2814614959737919\"),_T(\"2814615558140392\"),_T(\"2814618401629514\"),_T(\"2814618701087902\"),_T(\"2814619300882392\"),\n    _T(\"2814623785189962\"),_T(\"2814623956387698\"),_T(\"2814625066090704\"),_T(\"2814625471782204\"),_T(\"2814626946705530\"),_T(\"2814627006318591\"),_T(\"2814628046127456\"),_T(\"2814631487749991\"),\n    _T(\"2814631517599783\"),_T(\"2814632798310691\"),_T(\"2814633582140204\"),_T(\"2814634204785789\"),_T(\"2814634895412664\"),_T(\"2814635439049207\"),_T(\"2814638609354868\"),_T(\"2814639589885754\"),\n    _T(\"2814641670947751\"),_T(\"2814643512602566\"),_T(\"2814646137630843\"),_T(\"2814648499394446\"),_T(\"2814651465227139\"),_T(\"2814652150012664\"),_T(\"2814653926747608\"),_T(\"2814655098938516\"),\n    _T(\"2814655264861214\"),_T(\"2814655417678099\"),_T(\"2814655883565306\"),_T(\"2814656031821923\"),_T(\"2814656159501072\"),_T(\"2814656780954834\"),_T(\"2814660657970845\"),_T(\"2814661604435490\"),\n    _T(\"2814663444319727\"),_T(\"2814663818015575\"),_T(\"2814665274839967\"),_T(\"2814667273133504\"),_T(\"2814670761542037\"),_T(\"2814672762886609\"),_T(\"2814673772488023\"),_T(\"2814674096344056\"),\n    _T(\"2814674229538758\"),_T(\"2814678943953289\"),_T(\"2814680898042782\")\n};\n#endif\n\n//lua commands\n\nint StartSocialManagerDoWorkLoopCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    socialManagerCppState.doWork = true;\n    socialManagerCppState.doWorkJoinWhenDone = true;\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    socialManagerCppState.doWorkThread = std::thread([]()\n        {\n            Data()->m_socialDoWorkDone = false;\n            while (socialManagerCppState.doWork && !Data()->m_quit)\n            {\n                {\n                    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n                    SocialManagerDoWorkCpp();\n                }\n                pal::Sleep(10);\n            }\n            Data()->m_socialDoWorkDone = true;\n            LogToFile(\"Exiting do work thread\");\n        });\n#else\n    LogToFile(\"StartSocialManagerDoWorkLoopCpp is disabled for this platform.\");\n    //Call a 'disabled' function so tests that are waiting on do work events can still terminate\n    CallLuaFunctionWithHr(S_OK, \"OnStartSocialManagerDoWorkLoopCppDisabled\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint StopSocialManagerDoWorkLoopCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    LogToFile(\"StopSocialManagerDoWorkLoopCpp\");\n    socialManagerCppState.doWorkJoinWhenDone = true;\n    socialManagerCppState.doWork = false;\n#else\n    LogToFile(\"StopSocialManagerDoWorkLoopCpp is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerPresenceRecordIsUserPlayingTitleCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED    \n    using xbox::services::social::manager::xbox_social_user_group;\n    using xbox::services::social::manager::xbox_social_user;\n\n    std::shared_ptr<xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerPresenceRecordIsUserPlayingTitleCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    uint32_t titleId = GetUint32FromLua(L, 1, 174925616);\n\n    std::vector<xbox_social_user*> userVec = group->users();\n    for (auto user : userVec)\n    {\n        xbox::services::social::manager::social_manager_presence_record presenceRecord = user->presence_record();\n        bool playingTitle = presenceRecord.is_user_playing_title(titleId);\n        LogToFile(\"SocialManagerPresenceRecordIsUserPlayingTitleCpp: TitleId: %d, playing: %u\", titleId, playingTitle);\n    }\n\n#else\n    LogToFile(\"SocialManagerPresenceRecordIsUserPlayingTitleCpp is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerUserGroupGetTypeCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerUserGroupGetTypeCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    xbox::services::social::manager::social_user_group_type type = group->social_user_group_type();\n    LogToFile(\"SocialManagerUserGroupGetTypeCpp: type=%u\", type);\n#else\n    LogToFile(\"SocialManagerUserGroupGetTypeCpp is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerUserGroupGetLocalUserCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerUserGroupGetLocalUserCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    xbox_live_user_t user = group->local_user();\n    LogToFile(\"SocialManagerUserGroupGetLocalUserCpp: user=%llu\", user);\n#else\n    LogToFile(\"SocialManagerUserGroupGetLocalUserCpp is disabled on this platform.\");\n\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerUserGroupGetFiltersCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerUserGroupGetFiltersCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    xbox::services::social::manager::presence_filter presenceFilter = group->presence_filter_of_group();\n    xbox::services::social::manager::relationship_filter relationshipFilter = group->relationship_filter_of_group();\n\n    LogToFile(\"SocialManagerUserGroupGetFiltersCpp: presenceFilter=%u, relationshipFilter=%u\", presenceFilter, relationshipFilter);\n#else\n    LogToFile(\"SocialManagerUserGroupGetFiltersCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerUserGroupGetUsersCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerUserGroupGetUsersCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    LogToFile(\"SocialManagerUserGroupGetUsersCpp: usersCount: %d\", group->users().size());\n    for (auto user : group->users())\n    {\n        char buffer[17];\n        xbox::services::Utils::Utf8FromCharT(user->gamertag(), buffer, sizeof(buffer));\n        LogToFile(\"\\t%s\", buffer);\n    }\n#else\n    LogToFile(\"SocialManagerUserGroupGetUsersCpp is not supported on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerUserGroupGetUsersTrackedByGroupCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerUserGroupGetUsersTrackedByGroupCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    LogToFile(\"SocialManagerUserGroupGetUsersTrackedByGroupCpp trackedUsersCount: %d\",  group->users_tracked_by_social_user_group().size());\n\n    for (auto user : group->users_tracked_by_social_user_group())\n    {\n        LogToFile(\"\\t%s\", user.xbox_user_id());\n    }\n#else\n    LogToFile(\"SocialManagerUserGroupGetUsersTrackByGroupCpp is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerAddLocalUserCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::social::manager::social_manager_extra_detail_level extraDetailLevel = ConvertStringToCppSocialManagerExtraDetailLevel(\n        GetStringFromLua(L, 1, \"social_manager_extra_detail_level::no_extra_detai_T(\").c_str());\n    LogToFile(\"SocialManagerAddLocalUserCpp: social_manager_extra_detail_level: %d\", extraDetailLevel);\n\n    xbox_live_user_t user = Data()->xalUser;\n\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    socialManager->add_local_user(user, extraDetailLevel);\n    LogToFile(\"SocialManagerAddLocalUserCpp\");\n#else\n    LogToFile(\"SocialManagerAddLocalUserCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerRemoveLocalUserCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    xbox_live_user_t user = Data()->xalUser;\n\n    socialManager->remove_local_user(user);\n\n    LogToFile(\"SocialManagerRemoveLocalUserCpp\");\n#else\n    LogToFile(\"SocialManagerRemoveLocalUserCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint SocialManagerCreateSocialUserGroupFromFiltersCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    xbox_live_user_t user = Data()->xalUser;\n    xbox::services::social::manager::presence_filter presenceFilter = ConvertStringToCppPresenceFilter(GetStringFromLua(L, 1, \"presence_filter::al_T(\").c_str());\n    xbox::services::social::manager::relationship_filter relationshipFilter = ConvertStringToCppRelationshipFilter(GetStringFromLua(L, 2, \"relationship_filter::friends\").c_str());\n\n    LogToFile(\"SocialManagerCreateSocialUserGroupFromFiltersCpp: presence_filter: %d\", presenceFilter);\n    LogToFile(\"SocialManagerCreateSocialUserGroupFromFiltersCpp: relationship_filter: %d\", relationshipFilter);\n\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    xbox::services::xbox_live_result<std::shared_ptr<xbox::services::social::manager::xbox_social_user_group>> result = socialManager->create_social_user_group_from_filters(user, presenceFilter, relationshipFilter);\n\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        group = result.payload();\n        socialManagerCppState.groups.insert(std::pair<uint64_t, std::shared_ptr<xbox::services::social::manager::xbox_social_user_group>>(reinterpret_cast<uint64_t>(group.get()), group));\n    }\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(group.get()));\n\n    LogToFile(\"SocialManagerCreateSocialUserGroupFromFiltersCpp: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n#else\n    LogToFile(\"SocialManagerCreateSocialUserGroupFromFiltersCpp is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialManagerDestroySocialUserGroupCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerDestroySocialUserGroupCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    xbox::services::xbox_live_result<void> result = socialManager->destroy_social_user_group(group);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        socialManagerCppState.groups.erase(reinterpret_cast<uint64_t>(group.get()));\n    }\n\n    LogToFile(\"SocialManagerDestroySocialUserGroupCpp: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialManagerDestroySocialUserGroupCpp is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialManagerCreateSocialUserGroupFromListCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    // Params:\n    // 1) number of xuids to include in list\n    // 2) offset in the above vector of first xuid\n    uint64_t count{ GetUint64FromLua(L, 1, 10) };\n    uint64_t offset{ GetUint64FromLua(L, 2, 0) };\n\n    assert(offset + count <= listXuidStrings.size());\n\n    xbox_live_user_t user = Data()->xalUser;\n    std::vector<string_t> xuids\n    {\n        listXuidStrings.begin() + static_cast<int>(offset),\n        listXuidStrings.begin() + static_cast<int>(offset + count)\n    };\n\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    xbox::services::xbox_live_result<std::shared_ptr<xbox::services::social::manager::xbox_social_user_group>> result = socialManager->create_social_user_group_from_list(user, xuids);\n\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group;\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        group = result.payload();\n        socialManagerCppState.groups.insert(std::pair<uint64_t, std::shared_ptr<xbox::services::social::manager::xbox_social_user_group>>(reinterpret_cast<uint64_t>(group.get()), group));\n    }\n\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(group.get()));\n\n    LogToFile(\"SocialManagerCreateSocialUserGroupFromListCpp: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n#else\n    LogToFile(\"SocialManagerCreateSocialUserGroupFromListCpp is disabled on this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialManagerGetLocalUsersCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n\n    LogToFile(\"XblSocialManagerGetLocalUsers localUsersCount: %d\", socialManager->local_users().size());\n\n    HRESULT hr = S_OK;\n    for (xbox_live_user_t user : socialManager->local_users())\n    {\n        size_t gamertagSize = XalUserGetGamertagSize(user, XalGamertagComponent_Classic);\n        std::vector<char> gamertag(gamertagSize, '\\0');\n\n        size_t bufferUsed;\n        hr = XalUserGetGamertag(user, XalGamertagComponent_Classic, gamertagSize, gamertag.data(), &bufferUsed);\n        if (SUCCEEDED(hr))\n        {\n            LogToFile(\"\\t%s\", gamertag.data());\n        }\n    }\n\n    LogToFile(\"SocialManagerGetLocalUsersCpp: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialManagerGetLocalUsersCpp is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialManagerUpdateSocialUserGroupCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    // Params:\n    // 1) group pointer\n    // 1) number of xuids to include in list\n    // 2) offset in the above vector of first xuid\n    std::shared_ptr<xbox::services::social::manager::xbox_social_user_group> group{ nullptr };\n    uint64_t luaGroup = GetUint64FromLua(L, 1, 0);\n    if (luaGroup)\n    {\n        group = (*socialManagerCppState.groups.find(luaGroup)).second;\n    }\n    else\n    {\n        group = (*socialManagerCppState.groups.begin()).second;\n    }\n    if (group == nullptr)\n    {\n        LogToFile(\"SocialManagerUpdateSocialUserGroupCpp: No xbox_social_user_group Loaded\");\n        return S_OK;\n    }\n\n    auto count{ GetUint64FromLua(L, 2, 15) };\n    auto offset{ GetUint64FromLua(L, 3, 0) };\n\n    // CODE SNIPPET START: XblSocialManagerUpdateSocialUserGroup_C\n    std::vector<string_t> xuids\n    {\n        listXuidStrings.begin() + static_cast<int>(offset),\n        listXuidStrings.begin() + static_cast<int>(offset + count)\n    };\n\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    xbox::services::xbox_live_result<void> result = socialManager->update_social_user_group(group, xuids);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n\n    LogToFile(\"SocialManagerUpdateSocialUserGroupCpp: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialManagerUpdateSocialUserGroupCpp is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialManagerSetRichPresencePollingStatusCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    xbox_live_user_t user = Data()->xalUser;\n    bool shouldEnablePolling = GetBoolFromLua(L, 1, false);\n    LogToFile(\"SocialManagerSetRichPresencePollingStatusCpp: ShouldEnablePolling: %s\", shouldEnablePolling ? \"true\" : \"false\");\n\n    std::shared_ptr<xbox::services::social::manager::social_manager> socialManager = xbox::services::social::manager::social_manager::get_singleton_instance();\n    xbox::services::xbox_live_result<void> result = socialManager->set_rich_presence_polling_status(user, shouldEnablePolling);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n\n    LogToFile(\"SocialManagerSetRichPresencePollingStatusCpp: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialManagerSetRichPresencePollingStatusCpp is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint SocialManagerDoWorkCpp_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    HRESULT hr = SocialManagerDoWorkCpp();\n    LogToFile(\"SocialManagerDoWorkCpp: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"SocialManagerDoWorkCpp is disabled on this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nvoid SetupAPIs_CppSocialManager()\n{\n    lua_register(Data()->L, \"StartSocialManagerDoWorkLoopCpp\", StartSocialManagerDoWorkLoopCpp_Lua);\n    lua_register(Data()->L, \"StopSocialManagerDoWorkLoopCpp\", StopSocialManagerDoWorkLoopCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerPresenceRecordIsUserPlayingTitleCpp\", SocialManagerPresenceRecordIsUserPlayingTitleCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerUserGroupGetTypeCpp\", SocialManagerUserGroupGetTypeCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerUserGroupGetLocalUserCpp\", SocialManagerUserGroupGetLocalUserCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerUserGroupGetFiltersCpp\", SocialManagerUserGroupGetFiltersCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerUserGroupGetUsersCpp\", SocialManagerUserGroupGetUsersCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerUserGroupGetUsersTrackedByGroupCpp\", SocialManagerUserGroupGetUsersTrackedByGroupCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerAddLocalUserCpp\", SocialManagerAddLocalUserCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerRemoveLocalUserCpp\", SocialManagerRemoveLocalUserCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerCreateSocialUserGroupFromFiltersCpp\", SocialManagerCreateSocialUserGroupFromFiltersCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerCreateSocialUserGroupFromListCpp\", SocialManagerCreateSocialUserGroupFromListCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerGetLocalUsersCpp\", SocialManagerGetLocalUsersCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerUpdateSocialUserGroupCpp\", SocialManagerUpdateSocialUserGroupCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerSetRichPresencePollingStatusCpp\", SocialManagerSetRichPresencePollingStatusCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerDoWorkCpp\", SocialManagerDoWorkCpp_Lua);\n    lua_register(Data()->L, \"SocialManagerDestroySocialUserGroupCpp\", SocialManagerDestroySocialUserGroupCpp_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_statistics.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#pragma warning(disable:4996)\n\nint UserStatisticsServiceGetSingleUserStatistic_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    string_t statisticName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"TotalPuzzlesSolved\").c_str());\n\n    LogToFile(\"UserStatisticsServiceGetSingleUserStatistic: statisticName: %s\", xbox::services::Utils::StringFromStringT(statisticName).c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->user_statistics_service().get_single_user_statistics(\n        xboxUserId,\n        serviceConfigurationId,\n        statisticName\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::user_statistics::user_statistics_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"UserStatisticsServiceGetSingleUserStatistic: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::user_statistics::user_statistics_result userStatisticsResult{ result.payload() };\n\n                VERIFY_IS_TRUE(userStatisticsResult.service_configuration_statistics().size() == 1, \"service_configuration_statistics size\");\n                VERIFY_IS_TRUE(userStatisticsResult.service_configuration_statistics()[0].statistics().size() == 1, \"statistics size\");\n\n                if (userStatisticsResult.service_configuration_statistics().size() > 0 && userStatisticsResult.service_configuration_statistics()[0].statistics().size() > 0)\n                {\n                    xbox::services::user_statistics::statistic stat = userStatisticsResult.service_configuration_statistics()[0].statistics()[0];\n                    //Data()->lastUserStat = stat.value();\n\n                    LogToScreen(\"%s's stat %s is %s.  Note: With GDK, ensure fiddler isn't running for stat upload to work\",\n                        Data()->gamertag.c_str(),\n                        xbox::services::Utils::StringFromStringT(stat.statistic_name()).c_str(),\n                        xbox::services::Utils::StringFromStringT(stat.value()).c_str()\n                    );\n\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnUserStatisticsServiceGetSingleUserStatistic\");\n        });\n#else\n    LogToFile(\"UserStatisticsServiceGetSingleUserStatistic is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnUserStatisticsServiceGetSingleUserStatistic\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint UserStatisticsServiceGetSingleUserStatistics_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t statisticName1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"TotalPuzzlesSolved\").c_str());\n    string_t statisticName2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"TotalRoundsStarted\").c_str());\n    LogToFile(\"UserStatisticsServiceGetSingleUserStatistics: statisticName1: %s\", xbox::services::Utils::StringFromStringT(statisticName1).c_str());\n    LogToFile(\"UserStatisticsServiceGetSingleUserStatistics: statisticName2: %s\", xbox::services::Utils::StringFromStringT(statisticName2).c_str());\n\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    std::vector<string_t> statisticNames{ statisticName1, statisticName2 };\n\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->user_statistics_service().get_single_user_statistics(\n        xboxUserId,\n        serviceConfigurationId,\n        statisticNames\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::user_statistics::user_statistics_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"UserStatisticsServiceGetSingleUserStatistics: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::user_statistics::user_statistics_result userStatisticsResult{ result.payload() };\n\n                if (userStatisticsResult.service_configuration_statistics().size() > 0)\n                {\n                    std::vector<xbox::services::user_statistics::statistic> stats = userStatisticsResult.service_configuration_statistics()[0].statistics();\n                    LogToFile(\"Got %u statistics for %s\", stats.size(), Data()->gamertag.c_str());\n                    for (auto stat : stats)\n                    {\n                        LogToScreen(\"stat %s is %s\",\n                            xbox::services::Utils::StringFromStringT(stat.statistic_name()).c_str(),\n                            xbox::services::Utils::StringFromStringT(stat.value()).c_str()\n                        );\n                    }\n\n                }\n\n\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnUserStatisticsServiceGetSingleUserStatistics\");\n        });\n#else\n    LogToFile(\"UserStatisticsServiceGetSingleUserStatistics is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnUserStatisticsServiceGetSingleUserStatistics\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint UserStatisticsServiceGetMultipleUserStatistics_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t statisticName1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"TotalPuzzlesSolved\").c_str());\n    string_t statisticName2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"TotalRoundsStarted\").c_str());\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatistics: statisticName1: %s\", xbox::services::Utils::StringFromStringT(statisticName1).c_str());\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatistics: statisticName2: %s\", xbox::services::Utils::StringFromStringT(statisticName2).c_str());\n\n    string_t xuid1 = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 3, Data()->xboxUserId));\n    string_t xuid2 = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 4, 2814634367189975));\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatistics: xuid1: %ul\", xbox::services::Utils::StringFromStringT(xuid1).c_str());\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatistics: xuid2: %ul\", xbox::services::Utils::StringFromStringT(xuid2).c_str());\n\n    std::vector<string_t> xboxUserIds{ xuid1, xuid2 };\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    std::vector<string_t> statisticNames{ statisticName1, statisticName2 };\n\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->user_statistics_service().get_multiple_user_statistics(\n        xboxUserIds,\n        serviceConfigurationId,\n        statisticNames\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::user_statistics::user_statistics_result>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"UserStatisticsServiceGetMultipleUserStatistics: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::user_statistics::user_statistics_result> userStatisticsResults = result.payload();\n\n                for (auto statResult : userStatisticsResults)\n                {\n                    LogToFile(\"XUID: %d\", xbox::services::Utils::StringFromStringT(statResult.xbox_user_id()).c_str());\n                    for (auto scidStats : statResult.service_configuration_statistics())\n                    {\n                        LogToFile(\"SCID: %s\", xbox::services::Utils::StringFromStringT(scidStats.service_configuration_id()).c_str());\n                        for (auto stat : scidStats.statistics())\n                        {\n                            LogToFile(\"Stat name:%s value:%s type:%s\",\n                                xbox::services::Utils::StringFromStringT(stat.statistic_name()).c_str(),\n                                xbox::services::Utils::StringFromStringT(stat.value()).c_str(),\n                                xbox::services::Utils::StringFromStringT(stat.statistic_type()).c_str()\n                            );\n                        }\n                    }\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnUserStatisticsServiceGetMultipleUserStatistics\");\n        });\n#else\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatistics is disabled for this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnUserStatisticsServiceGetMultipleUserStatistics\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t statisticName1 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"TotalPuzzlesSolved\").c_str());\n    string_t statisticName2 = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"TotalRoundsStarted\").c_str());\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations: statisticName1: %s\", xbox::services::Utils::StringFromStringT(statisticName1).c_str());\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations: statisticName2: %s\", xbox::services::Utils::StringFromStringT(statisticName2).c_str());\n\n    std::vector<string_t> statisticNames{ statisticName1, statisticName2 };\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n\n    xbox::services::user_statistics::requested_statistics requestedStatistic1{ serviceConfigurationId, statisticNames };\n\n    string_t xuid1 = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 3, Data()->xboxUserId));\n    string_t xuid2 = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 4, 2814634367189975));\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations: xuid1: %ul\", xbox::services::Utils::StringFromStringT(xuid1).c_str());\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations: xuid2: %ul\", xbox::services::Utils::StringFromStringT(xuid2).c_str());\n\n    std::vector<string_t> xboxUserIds{ xuid1, xuid2 };\n    std::vector<xbox::services::user_statistics::requested_statistics> requestedStatistics{ requestedStatistic1 };\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->user_statistics_service().get_multiple_user_statistics_for_multiple_service_configurations(\n        xboxUserIds,\n        requestedStatistics\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::user_statistics::user_statistics_result>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations: hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::user_statistics::user_statistics_result> userStatisticsResults = result.payload();\n\n                for (auto statResult : userStatisticsResults)\n                {\n                    LogToFile(\"Xbox User ID: %d\", xbox::services::Utils::StringFromStringT(statResult.xbox_user_id()).c_str());\n                    for (auto scidStats : statResult.service_configuration_statistics())\n                    {\n                        LogToFile(\"SCID: %s\", xbox::services::Utils::StringFromStringT(scidStats.service_configuration_id()).c_str());\n                        for (auto stat : scidStats.statistics())\n                        {\n                            LogToFile(\"Stat name:%s value:%s type:%s\",\n                                xbox::services::Utils::StringFromStringT(stat.statistic_name()).c_str(),\n                                xbox::services::Utils::StringFromStringT(stat.value()).c_str(),\n                                xbox::services::Utils::StringFromStringT(stat.statistic_type()).c_str()\n                            );\n                        }\n                    }\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnUserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations\");\n        });\n#else\n    LogToFile(\"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations is disabled for this platform\");\n    CallLuaFunctionWithHr(S_OK, \"OnUserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint UserStatisticsServiceSubscribeToStatisticChange_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    if (Data()->statisticChangeSubscriptionCpp != nullptr)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(Data()->xboxUserId);\n    string_t serviceConfigurationId = xbox::services::Utils::StringTFromUtf8(Data()->scid);\n    string_t statisticName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"TotalPuzzlesSolved\").c_str());\n    \n    LogToFile(\"UserStatisticsServiceSubscribeToStatisticChange: statisticName: %s\", xbox::services::Utils::StringFromStringT(statisticName).c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    auto result = xblc->user_statistics_service().subscribe_to_statistic_change(xboxUserId, serviceConfigurationId, statisticName);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        Data()->statisticChangeSubscriptionCpp = result.payload();\n    }\n    LogToFile(\"UserStatisticsServiceSubscribeToStatisticChange: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"UserStatisticsServiceSubscribeToStatisticChange is disabled for this platform.\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint UserStatisticsServiceUnsubscribeFromStatisticChange_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    auto result = xblc->user_statistics_service().unsubscribe_from_statistic_change(Data()->statisticChangeSubscriptionCpp);\n\n    HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n    if (SUCCEEDED(hr))\n    {\n        Data()->statisticChangeSubscriptionCpp = nullptr;\n    }\n    LogToFile(\"UserStatisticsServiceUnsubscribeFromStatisticChange: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n#else\n    LogToFile(\"UserStatisticsServiceUnsubscribeFromStatisticChange is disabled for this platform\");\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint UserStatisticsServiceAddStatisticChangedHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    Data()->statisticChangedFunctionContextCpp = xblc->user_statistics_service().add_statistic_changed_handler(\n        [](xbox::services::user_statistics::statistic_change_event_args args) \n        {\n            // Handle stat change \n            LogToScreen(\"Statistic changed callback: stat changed (%s = %s)\",\n                xbox::services::Utils::StringFromStringT(args.latest_statistic().statistic_name()).c_str(),\n                xbox::services::Utils::StringFromStringT(args.latest_statistic().value()).c_str());\n            CallLuaFunctionWithHr(S_OK, \"OnStatisticChangedHandlerCpp\");\n        });\n\n    LogToFile(\"UserStatisticsServiceAddStatisticChangedHandler\");\n#else\n    LogToFile(\"UserStatisticsServiceAddStatisticChangedHandler is disabled on this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint UserStatisticsServiceRemoveStatisticChangedHandler_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xboxLiveContext);\n    xblc->user_statistics_service().remove_statistic_changed_handler(Data()->statisticChangedFunctionContextCpp);\n    Data()->statisticChangedFunctionContextCpp = nullptr;\n    LogToFile(\"UserStatisticsServiceRemoveStatisticChangedHandler\");\n#else\n    LogToFile(\"UserStatisticsServiceRemoveStatisticChangedHandler is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint StatisticChangeSubscriptionGetStateCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    if (Data()->statisticChangeSubscriptionCpp)\n    {\n        xbox::services::real_time_activity::real_time_activity_subscription_state subscriptionState = Data()->statisticChangeSubscriptionCpp->state();\n        LogToFile(\"StatisticChangeSubscriptionGetStateCpp: subscriptionState=%u\", subscriptionState);\n    }\n    else\n    {\n        LogToFile(\"StatisticChangeSubscriptionGetStateCpp: No subscription found\");\n    }\n#else\n    LogToFile(\"StatisticChangeSubscriptionGetStateCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint StatisticChangeSubscriptionGetIdCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    if (Data()->statisticChangeSubscriptionCpp)\n    {\n        uint32_t subscriptionId = Data()->statisticChangeSubscriptionCpp->subscription_id();\n        LogToFile(\"StatisticChangeSubscriptionGetStateCpp: subscriptionState=%u\", subscriptionId);\n    }\n    else\n    {\n        LogToFile(\"StatisticChangeSubscriptionGetIdCpp: No subscription found\");\n    }\n#else\n    LogToFile(\"StatisticChangeSubscriptionGetIdCpp is disabled for this platform.\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppStatistics()\n{\n    lua_register(Data()->L, \"UserStatisticsServiceGetSingleUserStatistic\", UserStatisticsServiceGetSingleUserStatistic_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceGetSingleUserStatistics\", UserStatisticsServiceGetSingleUserStatistics_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceGetMultipleUserStatistics\", UserStatisticsServiceGetMultipleUserStatistics_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations\", UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceSubscribeToStatisticChange\", UserStatisticsServiceSubscribeToStatisticChange_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceUnsubscribeFromStatisticChange\", UserStatisticsServiceUnsubscribeFromStatisticChange_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceAddStatisticChangedHandler\", UserStatisticsServiceAddStatisticChangedHandler_Lua);\n    lua_register(Data()->L, \"UserStatisticsServiceRemoveStatisticChangedHandler\", UserStatisticsServiceRemoveStatisticChangedHandler_Lua);\n\n    lua_register(Data()->L, \"StatisticChangeSubscriptionGetStateCpp\", StatisticChangeSubscriptionGetStateCpp_Lua);\n    lua_register(Data()->L, \"StatisticChangeSubscriptionGetIdCpp\", StatisticChangeSubscriptionGetIdCpp_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_stringverify.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint StringServiceVerifyString_Lua(lua_State *L)\n{\n#if CPP_TESTS_ENABLED\n    string_t testString = _T(\"Shltstring\");\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->string_service().verify_string(\n        testString\n    ).then(\n        [](xbox::services::xbox_live_result<xbox::services::system::verify_string_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"StringServiceVerifyString: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::system::verify_string_result verifyStringResult = result.payload();\n\n                LogToFile(\n                    \"Result: Result Code: %d - First Offending String: %s\",\n                    verifyStringResult.result_code(),\n                    (verifyStringResult.result_code() == xbox::services::system::verify_string_result_code::offensive) ? xbox::services::Utils::StringFromStringT(verifyStringResult.first_offending_substring()).c_str() : \"\");\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnStringServiceVerifyString\");\n        });\n#else\n    LogToFile(\"StringServiceVerifyString is disabled on this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnStringServiceVerifyString\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint StringServiceVerifyStrings_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    string_t testString1 = _T(\"Shltstring\");\n    string_t testString2 = _T(\"Goodstring\");\n    string_t testString3 = _T(\"Shltstring2\");\n    std::vector<string_t> testStrings{ testString1, testString2, testString3 };\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->string_service().verify_strings(\n        testStrings\n    ).then(\n        [](xbox::services::xbox_live_result<std::vector<xbox::services::system::verify_string_result>> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"StringServiceVerifyStrings: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                std::vector<xbox::services::system::verify_string_result> verifyStringResults = result.payload();\n\n                LogToScreen(\"StringServiceVerifyStrings: count=%d\", verifyStringResults.size());\n                assert(verifyStringResults.size() == 3);\n\n                for (xbox::services::system::verify_string_result verifyStringResult : verifyStringResults)\n                {\n                    LogToFile(\n                        \"Result: Result Code: %d - First Offending String: %s\",\n                        verifyStringResult.result_code(),\n                        (verifyStringResult.result_code() == xbox::services::system::verify_string_result_code::offensive) ? xbox::services::Utils::StringFromStringT(verifyStringResult.first_offending_substring()).c_str() : \"\");\n                }\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnStringServiceVerifyStrings\");\n        });\n#else\n    LogToFile(\"StringServiceVerifyStrings is disabled on this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnStringServiceVerifyStrings\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppStringVerify()\n{\n    lua_register(Data()->L, \"StringServiceVerifyString\", StringServiceVerifyString_Lua);\n    lua_register(Data()->L, \"StringServiceVerifyStrings\", StringServiceVerifyStrings_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_cpp_title_storage.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#if CPP_TESTS_ENABLED\nxbox::services::title_storage::title_storage_type ConvertStringToCppTitleStorageType(const char* str)\n{\n    xbox::services::title_storage::title_storage_type storageType = xbox::services::title_storage::title_storage_type::trusted_platform_storage;\n\n    if (pal::stricmp(str, \"title_storage_type::trusted_platform_storage\") == 0) storageType = xbox::services::title_storage::title_storage_type::trusted_platform_storage;\n    else if (pal::stricmp(str, \"title_storage_type::global_storage\") == 0) storageType = xbox::services::title_storage::title_storage_type::global_storage;\n    else if (pal::stricmp(str, \"title_storage_type::universal\") == 0) storageType = xbox::services::title_storage::title_storage_type::universal;\n\n    return storageType;\n}\n\nxbox::services::title_storage::title_storage_blob_type ConvertStringToCppTitleStorageBlobType(const char* str)\n{\n    xbox::services::title_storage::title_storage_blob_type blobType = xbox::services::title_storage::title_storage_blob_type::unknown;\n\n    if (pal::stricmp(str, \"title_storage_blob_type::binary\") == 0) blobType = xbox::services::title_storage::title_storage_blob_type::binary;\n    else if(pal::stricmp(str, \"title_storage_blob_type::json\") == 0) blobType = xbox::services::title_storage::title_storage_blob_type::json;\n    else if (pal::stricmp(str, \"title_storage_blob_type::config\") == 0) blobType = xbox::services::title_storage::title_storage_blob_type::config;\n\n    return blobType;\n}\n\nxbox::services::title_storage::title_storage_e_tag_match_condition ConvertStringToCppETagMatchCondition(const char* str)\n{\n    xbox::services::title_storage::title_storage_e_tag_match_condition matchCondition = xbox::services::title_storage::title_storage_e_tag_match_condition::not_used;\n\n    if (pal::stricmp(str, \"title_storage_e_tag_match_condition::if_match\") == 0) matchCondition = xbox::services::title_storage::title_storage_e_tag_match_condition::if_match;\n    else if (pal::stricmp(str, \"title_storage_e_tag_match_condition::if_not_match\") == 0) matchCondition = xbox::services::title_storage::title_storage_e_tag_match_condition::if_not_match;\n\n    return matchCondition;\n}\n#endif\n\nint TitleStorageServiceGetQuota_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::title_storage::title_storage_type storageType = ConvertStringToCppTitleStorageType(GetStringFromLua(L, 1, \"title_storage_type::universal\").c_str());\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->title_storage_service().get_quota(\n        xbox::services::Utils::StringTFromUtf8(Data()->scid),\n        storageType\n    ).then(\n        [](xbox::services::xbox_live_result < xbox::services::title_storage::title_storage_quota> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"TitleStorageServiceGetQuota: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::title_storage::title_storage_quota storageQuota = result.payload();\n                LogToScreen(\"XblTitleStorageGetQuotaResult: usedBytes=%u quotaBytes=%u\", storageQuota.used_bytes(), storageQuota.quota_bytes());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnTitleStorageServiceGetQuota\");\n        });\n#else\n    LogToFile(\"TitleStorageServiceGetQuota is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnTitleStorageServiceGetQuota\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint TitleStorageServiceGetBlobMetadata_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::title_storage::title_storage_type storageType = ConvertStringToCppTitleStorageType(GetStringFromLua(L, 1, \"title_storage_type::universal\").c_str());\n    string_t blobPath = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"\").c_str());\n    string_t xboxUserId = xbox::services::Utils::StringTFromUint64(GetUint64FromLua(L, 3, 0));\n    uint32_t skipItems = GetUint32FromLua(L, 4, 0);\n    uint32_t maxItems = GetUint32FromLua(L, 5, 0);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->title_storage_service().get_blob_metadata(\n        xbox::services::Utils::StringTFromUtf8(Data()->scid),\n        storageType,\n        blobPath,\n        xboxUserId,\n        skipItems,\n        maxItems\n    ).then(\n        [xblc](xbox::services::xbox_live_result<xbox::services::title_storage::title_storage_blob_metadata_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"TitleStorageServiceGetBlobMetadata: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::title_storage::title_storage_blob_metadata_result metadataResult = result.payload();\n                Data()->blobMetadataResultCpp = metadataResult;\n                LogToScreen(\"TitleStorageServiceGetBlobMetadata result count: %d\", metadataResult.items().size());\n                Data()->blobMetadataCpp = metadataResult.items()[0];\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnTitleStorageServiceGetBlobMetadata\");\n        });\n#else\n    LogToFile(\"TitleStorageServiceGetBlobMetadata is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnTitleStorageServiceGetBlobMetadata\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint TitleStorageBlobMetadataResultHasNextCpp_Lua(lua_State* L)\n{\n    bool hasNext = false;\n#if CPP_TESTS_ENABLED\n    hasNext = Data()->blobMetadataResultCpp.has_next();\n    LogToFile(\"TitleStorageBlobMetadataResultHasNextCpp: hasNext=%s\", hasNext ? \"true\" : \"false\");\n#else\n    LogToFile(\"TitleStorageBlobMetadataResultHasNextCpp is disabled form this platform.\");\n#endif\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint TitleStorageBlobMetadataResultGetNextCpp_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    uint32_t maxItems = GetUint32FromLua(L, 1, 100);\n    LogToFile(\"TitleStorageBlobMetadataResultGetNextCpp: MaxItems: %d\", maxItems);\n\n    Data()->blobMetadataResultCpp.get_next(maxItems).then(\n        [](xbox::services::xbox_live_result<xbox::services::title_storage::title_storage_blob_metadata_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToFile(\"TitleStorageBlobMetadataResultGetNextCpp: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                xbox::services::title_storage::title_storage_blob_metadata_result metadataResult = result.payload();\n                Data()->blobMetadataResultCpp = metadataResult;\n                LogToScreen(\"TitleStorageBlobMetadataResultGetNext count: %d\", metadataResult.items().size());\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnTitleStorageBlobMetadataResultGetNextCpp\");\n        });\n#else\n    LogToFile(\"TitleStorageBlobMetadataResultGetNextCpp is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnTitleStorageBlobMetadataResultGetNextCpp\");\n#endif\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint TitleStorageServiceDeleteBlob_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    bool deleteOnlyIfEtagMatches = GetBoolFromLua(L, 1, false);\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->title_storage_service().delete_blob(\n        Data()->blobMetadataCpp,\n        deleteOnlyIfEtagMatches\n    ).then(\n        [](xbox::services::xbox_live_result<void> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToScreen(\"TitleStorageServiceDeleteBlob: hr=%s\", ConvertHR(hr).c_str());\n\n            CallLuaFunctionWithHr(hr, \"OnTitleStorageServiceDeleteBlob\");\n        });\n#else\n    LogToFile(\"TitleStorageServiceDeleteBlob is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnTitleStorageServiceDeleteBlob\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint TitleStorageServiceDownloadBlob_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::title_storage::title_storage_e_tag_match_condition eTagMatchCondition{ xbox::services::title_storage::title_storage_e_tag_match_condition::not_used };\n    string_t selectQuery = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 1, \"\").c_str());\n    uint32_t preferredDownloadBlockSize = GetUint32FromLua(L, 2, 1024 * 256);\n\n    std::shared_ptr<std::vector<unsigned char>> downloadBlobBuffer = std::make_shared<std::vector<unsigned char>>((unsigned int)(Data()->blobMetadataCpp.length()));\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->title_storage_service().download_blob(\n        Data()->blobMetadataCpp,\n        downloadBlobBuffer,\n        eTagMatchCondition,\n        selectQuery,\n        preferredDownloadBlockSize\n    ).then(\n        [downloadBlobBuffer](xbox::services::xbox_live_result<xbox::services::title_storage::title_storage_blob_result> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToScreen(\"TitleStorageServiceDownloadBlob: hr=%s\", ConvertHR(hr).c_str());\n\n            CallLuaFunctionWithHr(hr, \"OnTitleStorageServiceDownloadBlob\");\n        });\n#else\n    LogToFile(\"TitleStorageServiceDownloadBlob is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnTitleStorageServiceDownloadBlob\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint TitleStorageServiceUploadBlob_Lua(lua_State* L)\n{\n#if CPP_TESTS_ENABLED\n    xbox::services::title_storage::title_storage_type storageType = ConvertStringToCppTitleStorageType(GetStringFromLua(L, 1, \"title_storage_type::universal\").c_str());\n    string_t blobPath = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 2, \"apirunner/test/path.txt\").c_str());\n    xbox::services::title_storage::title_storage_blob_type blobType = ConvertStringToCppTitleStorageBlobType(GetStringFromLua(L, 3, \"title_storage_blob_type::binary\").c_str());\n    string_t displayName = xbox::services::Utils::StringTFromUtf8(GetStringFromLua(L, 4, \"Test Binary Data\").c_str());\n    string_t eTag = _T(\"TestETag\");\n\n    xbox::services::title_storage::title_storage_blob_metadata blobMetadata(\n        xbox::services::Utils::StringTFromUtf8(Data()->scid),\n        storageType,\n        blobPath,\n        blobType,\n        xbox::services::Utils::StringTFromUint64(Data()->xboxUserId),\n        displayName,\n        eTag\n    );\n\n    std::shared_ptr<std::vector<unsigned char>> blobBuffer = std::make_shared<std::vector<unsigned char>>();\n\n    xbox::services::title_storage::title_storage_e_tag_match_condition eTagMatchCondition = ConvertStringToCppETagMatchCondition(GetStringFromLua(L, 5, \"title_storage_e_tag_match_condition::not_used\").c_str());\n\n    uint32_t preferredUploadBlockSize = 1024 * 256;\n    size_t blobBufferSize = 1024 * 600; // requires 3 chunk uploads\n    blobBuffer->resize(blobBufferSize);\n    char zero = '0';\n    for (size_t i = 0; i < blobBufferSize; i++)\n    {\n        (*blobBuffer)[i] = static_cast<unsigned char>(zero + i % 10);\n    }\n\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->title_storage_service().upload_blob(\n        blobMetadata,\n        blobBuffer,\n        eTagMatchCondition,\n        preferredUploadBlockSize\n    ).then(\n        [blobBuffer](xbox::services::xbox_live_result<xbox::services::title_storage::title_storage_blob_metadata> result)\n        {\n            HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n            LogToScreen(\"TitleStorageServiceUploadBlob: hr=%s\", ConvertHR(hr).c_str());\n\n            if (SUCCEEDED(hr))\n            {\n                Data()->blobMetadataCpp = result.payload();\n            }\n\n            CallLuaFunctionWithHr(hr, \"OnTitleStorageServiceUploadBlob\");\n        });\n#else\n    LogToFile(\"TitleStorageServiceUploadBlob is disabled for this platform.\");\n    CallLuaFunctionWithHr(S_OK, \"OnTitleStorageServiceUploadBlob\");\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_CppTitleStorage()\n{\n    lua_register(Data()->L, \"TitleStorageServiceGetQuota\", TitleStorageServiceGetQuota_Lua);\n    lua_register(Data()->L, \"TitleStorageServiceGetBlobMetadata\", TitleStorageServiceGetBlobMetadata_Lua);\n    lua_register(Data()->L, \"TitleStorageBlobMetadataResultHasNextCpp\", TitleStorageBlobMetadataResultHasNextCpp_Lua);\n    lua_register(Data()->L, \"TitleStorageBlobMetadataResultGetNextCpp\", TitleStorageBlobMetadataResultGetNextCpp_Lua);\n    lua_register(Data()->L, \"TitleStorageServiceDeleteBlob\", TitleStorageServiceDeleteBlob_Lua);\n    lua_register(Data()->L, \"TitleStorageServiceDownloadBlob\", TitleStorageServiceDownloadBlob_Lua);\n    lua_register(Data()->L, \"TitleStorageServiceUploadBlob\", TitleStorageServiceUploadBlob_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_docs.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\nvoid CodeSnippets()\n{\n    // Non-functional code used to illustrate examples in docs\n    {\n        auto asyncBlock = std::make_unique<XAsyncBlock>();\n\n        // CODE SNIPPET START: XblPresenceSetPresenceAsyncWithIDs_C\n        XblPresenceRichPresenceIds ids{};\n        pal::strcpy(ids.scid, sizeof(ids.scid), Data()->scid);\n        ids.presenceId = \"playingMap\";\n        std::vector<const char*> tokenIds{ \"CurrentMap\" };\n        ids.presenceTokenIds = tokenIds.data();\n        ids.presenceTokenIdsCount = tokenIds.size();\n\n        HRESULT hr = XblPresenceSetPresenceAsync(Data()->xboxLiveContext, true, &ids, asyncBlock.get());\n        // CODE SNIPPET END\n\n        UNREFERENCED_PARAMETER(hr);\n    }\n\n    {\n        std::string scid = \"123\";\n        std::string leaderboardName = \"123\";\n        // CODE SNIPPET START: XblLeaderboardGetLeaderboardAsync-Rank\n        XblLeaderboardQuery leaderboardQuery = {};\n        pal::strcpy(leaderboardQuery.scid, sizeof(leaderboardQuery.scid), scid.c_str());\n        leaderboardQuery.leaderboardName = leaderboardName.c_str();\n        leaderboardQuery.skipResultToRank = 100;\n        leaderboardQuery.maxItems = 100;\n        // CODE SNIPPET END\n    }\n\n    {\n        std::string scid = \"123\";\n        std::string leaderboardName = \"123\";\n        uint64_t xboxUserId = 123;\n        // CODE SNIPPET START: XblLeaderboardGetLeaderboardAsync-User\n        XblLeaderboardQuery leaderboardQuery = {};\n        pal::strcpy(leaderboardQuery.scid, sizeof(leaderboardQuery.scid), scid.c_str());\n        leaderboardQuery.leaderboardName = leaderboardName.c_str();\n        leaderboardQuery.skipToXboxUserId = xboxUserId;\n        leaderboardQuery.maxItems = 100;\n        // CODE SNIPPET END\n    }\n\n    {\n#if HC_PLATFORM != HC_PLATFORM_XDK\n        // CODE SNIPPET START: XblEventsWriteInGameEvent\n        HRESULT hr = XblEventsWriteInGameEvent(\n            Data()->xboxLiveContext,\n            \"PuzzleSolved\",\n            R\"({\"DifficultyLevelId\":100, \"GameplayModeId\":\"Adventure\"})\",\n            R\"({\"LocationX\":1,\"LocationY\":1})\"\n        );\n        // CODE SNIPPET END\n\n        UNREFERENCED_PARAMETER(hr);\n#endif\n    }\n\n    {\n        auto xblContextHandle = Data()->xboxLiveContext;\n        auto xboxUserId = Data()->xboxUserId;\n        auto scid = Data()->scid;\n\n        {\n            // CODE SNIPPET START: DocsSubscribeToStatisticChange\n            // Subscribe for statistic change events\n            std::string statisticName = \"totalPuzzlesSolved\";\n            XblRealTimeActivitySubscriptionHandle subscriptionHandle{ nullptr };\n            HRESULT hr = XblUserStatisticsSubscribeToStatisticChange(\n                xblContextHandle,\n                xboxUserId,\n                scid,\n                statisticName.c_str(),\n                &subscriptionHandle\n            );\n\n            // Add a statistic changed handler\n            void* context{ nullptr };\n            XblFunctionContext statisticChangedFunctionContext = XblUserStatisticsAddStatisticChangedHandler(\n                Data()->xboxLiveContext,\n                [](XblStatisticChangeEventArgs eventArgs, void* context)\n                {\n                    // Handle stat change \n                    LogToScreen(\"Statistic changed callback: stat changed (%s = %s)\",\n                        eventArgs.latestStatistic.statisticName,\n                        eventArgs.latestStatistic.value);\n                    UNREFERENCED_PARAMETER(context); // CODE SNIP SKIP\n                },\n                context\n                );\n            // CODE SNIPPET END\n\n            UNREFERENCED_PARAMETER(statisticChangedFunctionContext);\n            UNREFERENCED_PARAMETER(statisticName);\n            UNREFERENCED_PARAMETER(hr);\n        }\n\n        {\n            XblFunctionContext statisticChangedFunctionContext = 0;\n\n            // CODE SNIPPET START: DocsUnsubscribeFromStatisticChange\n            // Remove the statistic changed handler\n            XblUserStatisticsRemoveStatisticChangedHandler(\n                xblContextHandle,\n                statisticChangedFunctionContext\n            );\n\n            // Unsubscribe for statistic change events\n            HRESULT hr = XblUserStatisticsUnsubscribeFromStatisticChange(\n                Data()->xboxLiveContext,\n                Data()->statisticChangeSubscriptionHandle\n            );\n            // CODE SNIPPET END\n\n            UNREFERENCED_PARAMETER(statisticChangedFunctionContext);\n            UNREFERENCED_PARAMETER(hr);\n        }\n\n        {\n            // CODE SNIPPET START: DocsAddConnectionIdChangedHandler\n            void* context{ nullptr };\n            XblFunctionContext connectionIdChangedFunctionContext = XblMultiplayerAddConnectionIdChangedHandler(\n                xblContextHandle,\n                [](void* context) {\n                    UNREFERENCED_PARAMETER(context); // CODE SNIP SKIP\n                    XTaskQueueHandle queue{ nullptr }; // CODE SNIP SKIP\n                    auto xblContextHandle = Data()->xboxLiveContext; // CODE SNIP SKIP\n                    XblMultiplayerSessionHandle sessionHandle; // Retrieve the MPSD session to update\n                    sessionHandle = nullptr; // CODE SNIP SKIP\n                    XblMultiplayerSessionCurrentUserSetStatus(sessionHandle, XblMultiplayerSessionMemberStatus::Active);\n\n                    auto asyncBlock = std::make_unique<XAsyncBlock>();\n                    asyncBlock->queue = queue;\n                    asyncBlock->context = nullptr;\n                    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n                    {\n                        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock };\n\n                        XblMultiplayerSessionHandle sessionHandle;\n                        HRESULT hr = XblMultiplayerWriteSessionResult(asyncBlock, &sessionHandle);\n                        if (SUCCEEDED(hr))\n                        {\n                            // If the write call succeeds, the connection id has been updated and no further action is needed.\n                        }\n                        else\n                        {\n                            // If the write call fails, it is likely the user has been removed from the session.\n                        }\n                    };\n\n                    auto hr = XblMultiplayerWriteSessionAsync(xblContextHandle, sessionHandle, XblMultiplayerSessionWriteMode::UpdateExisting, asyncBlock.get());\n                    if (SUCCEEDED(hr))\n                    {\n                        asyncBlock.release();\n                    }\n                }, \n                context);\n            // CODE SNIPPET END\n            UNREFERENCED_PARAMETER(connectionIdChangedFunctionContext);\n        }\n    }\n}\n\nvoid DocsMultiplayerCreateSession()\n{\n    auto xblContextHandle = Data()->xboxLiveContext;\n    auto XUID = Data()->xboxUserId;\n    const char* SCID{ Data()->scid };\n    const char* SESSION_TEMPLATE_NAME{ \"MinGameSession\" };\n    const char* SESSION_NAME{ \"\" };\n\n    auto queue = Data()->queue;\n\n    // CODE SNIPPET START: DocsMultiplayerCreateSession_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock };\n\n        XblMultiplayerSessionHandle sessionHandle;\n        HRESULT hr = XblMultiplayerWriteSessionResult(asyncBlock, &sessionHandle);\n        if (SUCCEEDED(hr))\n        {\n            // Process multiplayer session handle\n        }\n        else\n        {\n            // Handle failure\n        }\n    };\n\n    XblMultiplayerSessionReference ref;\n    pal::strcpy(ref.Scid, sizeof(ref.Scid), SCID);\n    pal::strcpy(ref.SessionTemplateName, sizeof(ref.SessionTemplateName), SESSION_TEMPLATE_NAME);\n    pal::strcpy(ref.SessionName, sizeof(ref.SessionName), SESSION_NAME);\n\n    XblMultiplayerSessionInitArgs args = {};\n\n    XblMultiplayerSessionHandle sessionHandle = XblMultiplayerSessionCreateHandle(XUID, &ref, &args);\n\n    auto hr = XblMultiplayerWriteSessionAsync(xblContextHandle, sessionHandle, XblMultiplayerSessionWriteMode::CreateNew, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n}\n\nvoid DocsMultiplayerJoinSessionFromSearchHandle()\n{\n    auto xblContextHandle = Data()->xboxLiveContext;\n    auto scid = Data()->scid;\n\n    // CODE SNIPPET START: DocsMultiplayerJoinSessionFromSearchHandle_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock };\n        size_t resultCount{ 0 };\n        auto hr = XblMultiplayerGetSearchHandlesResultCount(asyncBlock, &resultCount);\n        if (SUCCEEDED(hr) && resultCount > 0)\n        {\n            auto handles = new XblMultiplayerSearchHandle[resultCount];\n\n            hr = XblMultiplayerGetSearchHandlesResult(asyncBlock, handles, resultCount);\n\n            if (SUCCEEDED(hr))\n            {\n                // Join the game session\n                const char* handleId{ nullptr };\n                XblMultiplayerSearchHandleGetId(handles[0], &handleId);\n                \n                XblMultiplayerSessionReference multiplayerSessionReference;\n                XblMultiplayerSearchHandleGetSessionReference(handles[0], &multiplayerSessionReference);\n\n                XblMultiplayerSessionHandle gameSession =\n                    XblMultiplayerSessionCreateHandle(Data()->xboxUserId, &multiplayerSessionReference, nullptr);\n\n                XblMultiplayerSessionJoin(gameSession, nullptr, true, true);\n\n                // TODO finish\n//                XblMultiplayerWriteSessionByHandleAsync(Data()->xboxLiveContext, gameSession, XblMultiplayerSessionWriteMode::UpdateExisting, handleId, async);\n\n//                 XblMultiplayerManagerJoinGame(handleId, Data()->xalUser);\n\n                // Close handles\n                for (auto i = 0u; i < resultCount; ++i)\n                {\n                    XblMultiplayerSearchHandleCloseHandle(handles[i]);\n                }\n            }\n        }\n\n    };\n\n    const char* sessionName{ \"MinGameSession\" };\n    const char* orderByAttribute{ nullptr };\n    bool orderAscending{ false };\n    const char* searchFilter{ nullptr };\n    const char* socialGroup{ nullptr };\n\n    HRESULT hr = XblMultiplayerGetSearchHandlesAsync(\n        xblContextHandle,\n        scid,\n        sessionName,\n        orderByAttribute,\n        orderAscending,\n        searchFilter,\n        socialGroup,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n}\n\nvoid DocsMultiplayerManagerAddLocalUser_Single()\n{\n    auto xblUserHandle = Data()->xalUser;\n    void* context = nullptr;\n\n    // CODE SNIPPET START: DocsMultiplayerManagerAddLocalUser_Single_C\n    HRESULT hr = XblMultiplayerManagerLobbySessionAddLocalUser(xblUserHandle);\n\n    if (!SUCCEEDED(hr))\n    {\n        // Handle failure\n    }\n\n    // Set member connection address\n    const char* connectionAddress = \"1.1.1.1\";\n    hr = XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n        xblUserHandle, connectionAddress, context);\n\n    if (!SUCCEEDED(hr))\n    {\n        // Handle failure\n    }\n\n    // Set custom member properties\n    const char* propName = \"Name\";\n    const char* propValueJson = \"{}\";\n    hr = XblMultiplayerManagerLobbySessionSetProperties(propName, propValueJson, context);\n\n    if (!SUCCEEDED(hr))\n    {\n        // Handle failure\n    }\n    // DOTS\n    // CODE SNIPPET END\n}\n\nvoid DocsMultiplayerManagerAddLocalUser_Multiple()\n{\n    void* context = nullptr;\n\n    // CODE SNIPPET START: DocsMultiplayerManagerAddLocalUser_Multiple_C\n    std::vector<XblUserHandle> xblUsers;\n    for (XblUserHandle xblUserHandle : xblUsers)\n    {\n        HRESULT hr = XblMultiplayerManagerLobbySessionAddLocalUser(xblUserHandle);\n\n        if (!SUCCEEDED(hr))\n        {\n            // Handle failure\n        }\n\n        // Set member connection address\n        const char* connectionAddress = \"1.1.1.1\";\n        hr = XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n            xblUserHandle, connectionAddress, context);\n\n        if (!SUCCEEDED(hr))\n        {\n            // Handle failure\n        }\n\n        // Set custom member properties\n        const char* propName = \"Name\";\n        const char* propValueJson = \"{}\";\n        hr = XblMultiplayerManagerLobbySessionSetProperties(propName, propValueJson, context);\n\n        if (!SUCCEEDED(hr))\n        {\n            // Handle failure\n        }\n        // DOTS\n    }\n    // CODE SNIPPET END\n}\n\nvoid DocsMultiplayerManagerJoinLobby()\n{\n    auto xblUserHandle = Data()->xalUser;\n    auto inviteHandleId = \"8907df69-558a-43cc-93ce-34a0a219da63\";\n    void* context = nullptr;\n\n    // CODE SNIPPET START: DocsMultiplayerManagerJoinLobby_C\n    HRESULT hr = XblMultiplayerManagerJoinLobby(inviteHandleId, xblUserHandle);\n    if (!SUCCEEDED(hr))\n    {\n        // Handle failure\n    }\n    \n    // Set member connection address\n    const char* connectionAddress = \"1.1.1.1\";\n    hr = XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n        xblUserHandle, connectionAddress, context);\n    // CODE SNIPPET END\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_grts_gameinvite.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include \"XGameInvite.h\"\n\nXTaskQueueRegistrationToken g_token = { 0 };\n\nvoid CALLBACK MyXGameInviteEventCallback(\n    _In_opt_ void* context,\n    _In_ const char* inviteUri)\n{\n    UNREFERENCED_PARAMETER(context);\n    if (inviteUri != nullptr)\n    {\n        LogToScreen(\"GRTS: Game: MyXGameInviteEventCallback inviteUri:%s\\n\", inviteUri);\n        std::string inviteString(inviteUri);\n        auto pos = inviteString.find(\"handle=\");\n        auto handleString = inviteString.substr(pos + 7, 36);\n        Data()->inviteHandle = handleString;\n        CallLuaFunctionWithHr(S_OK, \"OnXGameInviteRegisterForEvent\");\n    }\n    else\n    {\n        LogToScreen(\"GRTS: Game: MyXGameInviteEventCallback inviteUri:nullptr\\n\");\n    }\n}\n\nint XGameInviteRegisterForEvent_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n\n    HRESULT hr = XGameInviteRegisterForEvent(\n        Data()->queue,\n        nullptr,\n        MyXGameInviteEventCallback,\n        &g_token);\n    LogToFile(\"GRTS: Game: XGameInviteRegisterForEvent hr=%s\", ConvertHR(hr).c_str()); \n\n    return LuaReturnHR(L, hr);\n}\n\nint XGameInviteUnregisterForEvent_Lua(lua_State* L)\n{\n    bool result = XGameInviteUnregisterForEvent(g_token, true);\n    LogToFile(\"GRTS: Game: XGameInviteUnregisterForEvent result=%d\", result);\n\n    return LuaReturnHR(L, S_OK);\n}\n#endif\n\nvoid SetupAPIs_GrtsGameInvite()\n{\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    lua_register(Data()->L, \"XGameInviteRegisterForEvent\", XGameInviteRegisterForEvent_Lua);\n    lua_register(Data()->L, \"XGameInviteUnregisterForEvent\", XGameInviteUnregisterForEvent_Lua);\n#endif\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_libhttp.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint HCInitialize_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCInitialize\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    HRESULT hr = HCInitialize(&(Data()->initArgs));\n#else\n    HRESULT hr = HCInitialize(nullptr);\n#endif\n    // CODE SNIPPET END\n\n    HCSettingsSetTraceLevel(HCTraceLevel::Verbose);\n    HCTraceSetTraceToDebugger(true);\n\n    LogToFile(\"HCInitialize: hr=%s\", ConvertHR(hr).c_str()); \n    return LuaReturnHR(L, hr);\n}\n\nint HCCleanup_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCCleanup\n    HCCleanup();\n    // CODE SNIPPET END\n\n    LogToFile(\"HCCleanup\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCCleanupAsync_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: HCCleanupAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"HCCleanupAsync result: hr=%s\", ConvertHR(hr).c_str());\n        CallLuaFunctionWithHr(hr, \"OnHCCleanupAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = HCCleanupAsync(asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"HCCleanupAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCGetLibVersion_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCGetLibVersion\n    const char* ver = nullptr;\n    HRESULT hr = HCGetLibVersion(&ver);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCGetLibVersion: hr=%s %s\", ConvertHR(hr).c_str(), ver); \n    return LuaReturnHR(L, hr);\n}\n\nint HCTrace_Lua(lua_State* L)\n{\n    LogToFile(\"HCTrace: testing small message\");\n\n    HCTraceImplArea apiExplorerArea{ \"ApiExplorer\", HCTraceLevel::Important };\n    HCTraceImplMessage(&apiExplorerArea, apiExplorerArea.Verbosity, \"testing small message\");\n    LogToFile(\"HCTrace: succeeded with small message\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCTraceLarge_Lua(lua_State* L)\n{\n    LogToFile(\"HCTraceLarge: testing large message\");\n\n    HCTraceImplArea apiExplorerArea{ \"ApiExplorer\", HCTraceLevel::Important };\n    std::vector<char> largeMessage(8192, 'w');\n    HCTraceImplMessage(&apiExplorerArea, apiExplorerArea.Verbosity, largeMessage.data());\n    LogToFile(\"HCTraceLarge: succeeded with large message\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCHttpCallCreate_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallCreate\n    HCCallHandle call = nullptr;\n    HRESULT hr = HCHttpCallCreate(&call);\n    // CODE SNIPPET END\n    Data()->httpCall = call;\n\n    LogToFile(\"HCHttpCallCreate: hr=%s\", ConvertHR(hr).c_str()); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallPerformAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: HCHttpCallPerformAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = Data()->httpCall;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"HCHttpCallPerformAsync result: hr=%s\", ConvertHR(hr).c_str()); \n        CallLuaFunctionWithHr(hr, \"OnHCHttpCallPerformAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = HCHttpCallPerformAsync(Data()->httpCall, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallPerformAsync: hr=%s\", ConvertHR(hr).c_str()); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallDuplicateHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallDuplicateHandle\n    HCCallHandle newHttpCall = HCHttpCallDuplicateHandle(Data()->httpCall);\n    // CODE SNIPPET END\n    HCHttpCallCloseHandle(newHttpCall);\n\n    LogToFile(\"HCHttpCallDuplicateHandle\"); \n    return LuaReturnHR(L, S_OK);\n}\n\nint HCHttpCallCloseHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallCloseHandle\n    HCHttpCallCloseHandle(Data()->httpCall);\n    // CODE SNIPPET END\n\n    Data()->httpCall = nullptr;\n    LogToFile(\"HCHttpCallCloseHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCHttpCallGetId_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallGetId\n    uint64_t httpId = HCHttpCallGetId(Data()->httpCall);\n    // CODE SNIPPET END\n    UNREFERENCED_PARAMETER(httpId);\n\n    LogToFile(\"HCHttpCallGetId\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCHttpCallSetTracing_Lua(lua_State *L)\n{\n    bool traceCall = GetBoolFromLua(L, 1, true);\n\n    // CODE SNIPPET START: HCHttpCallSetTracing\n    HRESULT hr = HCHttpCallSetTracing(Data()->httpCall, traceCall);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallSetTracing: hr=%s\", ConvertHR(hr).c_str()); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallGetRequestUrl_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallGetRequestUrl\n    const char* url = nullptr;\n    HRESULT hr = HCHttpCallGetRequestUrl(Data()->httpCall, &url);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallGetRequestUrl: hr=%s %s\", ConvertHR(hr).c_str(), url); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetUrl_Lua(lua_State *L)\n{\n    std::string methodName = GetStringFromLua(L, 1, \"GET\");\n    std::string url = GetStringFromLua(L, 2, \"https://www.bing.com\");\n    // CODE SNIPPET START: HCHttpCallRequestSetUrl\n    HRESULT hr = HCHttpCallRequestSetUrl(Data()->httpCall, methodName.c_str(), url.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetUrl: hr=%s %s\", ConvertHR(hr).c_str(), url.c_str()); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetRequestBodyString_Lua(lua_State *L)\n{\n    std::string requestBodyString = GetStringFromLua(L, 1, \"Test\");\n    // CODE SNIPPET START: HCHttpCallRequestSetRequestBodyString\n    HRESULT hr = HCHttpCallRequestSetRequestBodyString(Data()->httpCall, requestBodyString.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetRequestBodyString: hr=%s %s\", ConvertHR(hr).c_str(), requestBodyString.c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetHeader_Lua(lua_State *L)\n{\n    std::string headerName = GetStringFromLua(L, 1, \"TestName\");\n    std::string headerValue = GetStringFromLua(L, 2, \"TestValue\");\n    bool allowTracing = GetBoolFromLua(L, 3, true);\n    // CODE SNIPPET START: HCHttpCallRequestSetHeader\n    HRESULT hr = HCHttpCallRequestSetHeader(Data()->httpCall, headerName.c_str(), headerValue.c_str(), allowTracing);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetHeader: hr=%s %s:%s allowTracing=%d\", ConvertHR(hr).c_str(), headerName.c_str(), headerValue.c_str(), allowTracing);\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetTimeout_Lua(lua_State *L)\n{\n    uint32_t timeoutInSeconds = GetUint32FromLua(L, 1, 100);\n    // CODE SNIPPET START: HCHttpCallRequestSetTimeout\n    HRESULT hr = HCHttpCallRequestSetTimeout(Data()->httpCall, timeoutInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetTimeout: hr=%s %d\", ConvertHR(hr).c_str(), timeoutInSeconds); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetRetryDelay_Lua(lua_State *L)\n{\n    uint32_t retryDelayInSeconds = GetUint32FromLua(L, 1, 100);\n    // CODE SNIPPET START: HCHttpCallRequestSetRetryDelay\n    HRESULT hr = HCHttpCallRequestSetRetryDelay(Data()->httpCall, retryDelayInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetRetryDelay: hr=%s %d\", ConvertHR(hr).c_str(), retryDelayInSeconds); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetTimeoutWindow_Lua(lua_State *L)\n{\n    uint32_t timeoutWindowInSeconds = GetUint32FromLua(L, 1, 100);\n    // CODE SNIPPET START: HCHttpCallRequestSetTimeoutWindow\n    HRESULT hr = HCHttpCallRequestSetTimeoutWindow(Data()->httpCall, timeoutWindowInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetTimeoutWindow: hr=%s %d\", ConvertHR(hr).c_str(), timeoutWindowInSeconds); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetRetryCacheId_Lua(lua_State *L)\n{\n    uint32_t retryAfterCacheId = GetUint32FromLua(L, 1, 1);\n    // CODE SNIPPET START: HCHttpCallRequestSetRetryCacheId\n    HRESULT hr = HCHttpCallRequestSetRetryCacheId(Data()->httpCall, retryAfterCacheId);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetRetryCacheId: hr=%s %d\", ConvertHR(hr).c_str(), retryAfterCacheId); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallRequestSetRetryAllowed_Lua(lua_State *L)\n{\n    bool retryAllowed = GetBoolFromLua(L, 1, true);\n    // CODE SNIPPET START: HCHttpCallRequestSetRetryAllowed\n    HRESULT hr = HCHttpCallRequestSetRetryAllowed(Data()->httpCall, retryAllowed);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallRequestSetRetryAllowed: hr=%s %d\", ConvertHR(hr).c_str(), retryAllowed); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetResponseString_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallResponseGetResponseString\n    const char* response = nullptr;\n    HRESULT hr = HCHttpCallResponseGetResponseString(Data()->httpCall, &response);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetResponseString: hr=%s %s\", ConvertHR(hr).c_str(), response); \n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetResponseBodyBytesSize_Lua(lua_State *L)\n{\n    size_t bufferSize = 0;\n    // CODE SNIPPET START: HCHttpCallResponseGetResponseBodyBytesSize\n    HRESULT hr = HCHttpCallResponseGetResponseBodyBytesSize(Data()->httpCall, &bufferSize);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetResponseBodyBytesSize: hr=%s %zu\", ConvertHR(hr).c_str(), bufferSize);\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetStatusCode_Lua(lua_State *L)\n{\n    uint32_t statusCode = 0;\n    // CODE SNIPPET START: HCHttpCallResponseGetStatusCode\n    HRESULT hr = HCHttpCallResponseGetStatusCode(Data()->httpCall, &statusCode);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetStatusCode: hr=%s %d\", ConvertHR(hr).c_str(), statusCode);\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetNetworkErrorCode_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCHttpCallResponseGetNetworkErrorCode\n    HRESULT networkErrorCode = S_OK;\n    uint32_t platErrorCode = 0;\n    HRESULT hr = HCHttpCallResponseGetNetworkErrorCode(Data()->httpCall, &networkErrorCode, &platErrorCode);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetNetworkErrorCode: hr=%s networkError=%d platError=%d\", ConvertHR(hr).c_str(), networkErrorCode, platErrorCode);\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetHeader_Lua(lua_State *L)\n{\n    std::string headerName = GetStringFromLua(L, 1, \"UserAgent\");\n    // CODE SNIPPET START: HCHttpCallResponseGetHeader\n    const char* headerValue = nullptr;\n    HRESULT hr = HCHttpCallResponseGetHeader(Data()->httpCall, headerName.c_str(), &headerValue);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetHeader: hr=%s %s:%s\", ConvertHR(hr).c_str(), headerName.c_str(), headerValue);\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetNumHeaders_Lua(lua_State *L)\n{\n    uint32_t numHeaders = 0;\n    // CODE SNIPPET START: HCHttpCallResponseGetNumHeaders\n    HRESULT hr = HCHttpCallResponseGetNumHeaders(Data()->httpCall, &numHeaders);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetNumHeaders: hr=%s %d\", ConvertHR(hr).c_str(), numHeaders);\n    return LuaReturnHR(L, hr);\n}\n\nint HCHttpCallResponseGetHeaderAtIndex_Lua(lua_State *L)\n{\n    uint32_t headerIndex = GetUint32FromLua(L, 1, 0);\n    // CODE SNIPPET START: HCHttpCallResponseGetHeaderAtIndex\n    const char* headerName = nullptr;\n    const char* headerValue = nullptr;\n    HRESULT hr = HCHttpCallResponseGetHeaderAtIndex(Data()->httpCall, headerIndex, &headerName, &headerValue);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCHttpCallResponseGetHeaderAtIndex: hr=%s %d=%s:%s\", ConvertHR(hr).c_str(), headerIndex, headerName, headerValue);\n    return LuaReturnHR(L, hr);\n}\n\nvoid CALLBACK ExampleWebsocketMessageReceived(\n    _In_ HCWebsocketHandle websocket,\n    _In_z_ const char* incomingBodyString,\n    _In_ void* functionContext\n)\n{\n    UNREFERENCED_PARAMETER(websocket);\n    UNREFERENCED_PARAMETER(functionContext);\n    LogToFile(\"Received message from websocket: %s\", incomingBodyString);\n    CallLuaFunction(\"OnHCWebsocketMessageReceived\");\n}\n\nvoid CALLBACK ExampleWebsocketClosed(\n    _In_ HCWebsocketHandle websocket,\n    _In_ HCWebSocketCloseStatus closeStatus,\n    _In_ void* functionContext\n)\n{\n    UNREFERENCED_PARAMETER(websocket);\n    UNREFERENCED_PARAMETER(functionContext);\n    LogToFile(\"Websocket closed with status %u\", closeStatus);\n    CallLuaFunction(\"OnHCWebsocketClosed\");\n}\n\nint HCWebSocketCreate_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCWebSocketCreate\n    HCWebsocketHandle websocket = nullptr;\n    HRESULT hr = HCWebSocketCreate(&websocket, ExampleWebsocketMessageReceived, nullptr, ExampleWebsocketClosed, nullptr);\n    // CODE SNIPPET END\n\n    Data()->websocket = websocket;\n    LogToFile(\"HCWebSocketCreate: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCWebSocketSetProxyUri_Lua(lua_State *L)\n{\n    std::string proxyUri = GetStringFromLua(L, 1, \"Proxy\");\n    // CODE SNIPPET START: HCWebSocketSetProxyUri\n    HRESULT hr = HCWebSocketSetProxyUri(Data()->websocket, proxyUri.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"HCWebSocketSetProxyUri: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCWebSocketSetHeader_Lua(lua_State *L)\n{\n    std::string headerName = GetStringFromLua(L, 1, \"TestName\");\n    std::string headerValue = GetStringFromLua(L, 2, \"TestValue\");\n    // CODE SNIPPET START: HCWebSocketSetHeader\n    HRESULT hr = HCWebSocketSetHeader(Data()->websocket, headerName.c_str(), headerValue.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"HCWebSocketSetHeader: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCWebSocketConnectAsync_Lua(lua_State *L)\n{\n    std::string uri = GetStringFromLua(L, 1, \"ws://localhost:9002\");\n    std::string subProtocol = GetStringFromLua(L, 2, \"\");\n\n    // CODE SNIPPET START: HCWebSocketConnectAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        WebSocketCompletionResult result{};\n        HRESULT hr = HCGetWebSocketConnectResult(asyncBlock, &result);\n        LogToFile(\"HCGetWebSocketConnectResult: hr=%s errorCode=0x%0.8x\", ConvertHR(hr).c_str(), result.errorCode); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnHCWebSocketConnectAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = HCWebSocketConnectAsync(uri.c_str(), subProtocol.c_str(), Data()->websocket, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"HCWebSocketConnectAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCWebSocketSendMessageAsync_Lua(lua_State *L)\n{\n    std::string message = GetStringFromLua(L, 1, \"Test\");\n\n    // CODE SNIPPET START: HCWebSocketSendMessageAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        WebSocketCompletionResult result{};\n        HRESULT hr = HCGetWebSocketSendMessageResult(asyncBlock, &result);\n        LogToFile(\"HCGetWebSocketSendMessageResult: hr=%s errorCode=0x%0.8x\", ConvertHR(hr).c_str(), result.errorCode); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnHCWebSocketSendMessageAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = HCWebSocketSendMessageAsync(Data()->websocket, message.c_str(), asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"HCWebSocketSendMessageAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCWebSocketDisconnect_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCWebSocketDisconnect\n    HRESULT hr = HCWebSocketDisconnect(Data()->websocket);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCWebSocketDisconnect: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCWebSocketDuplicateHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCWebSocketDuplicateHandle\n    HCWebsocketHandle newWebsocket = HCWebSocketDuplicateHandle(Data()->websocket);\n    // CODE SNIPPET END\n    HCWebSocketCloseHandle(newWebsocket);\n\n    LogToFile(\"HCWebSocketDuplicateHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCWebSocketCloseHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCWebSocketCloseHandle\n    HRESULT hr = HCWebSocketCloseHandle(Data()->websocket);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCWebSocketCloseHandle: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint HCTraceSetTraceToDebugger_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCTraceSetTraceToDebugger\n    HCSettingsSetTraceLevel(HCTraceLevel::Verbose); // See HCTraceLevel enum for various levels\n    // TODO: jasonsa - confirm works\n    HCTraceSetTraceToDebugger(true);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCTraceSetTraceToDebugger\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCSettingsSetTraceLevel_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCSettingsSetTraceLevel\n    HCSettingsSetTraceLevel(HCTraceLevel::Verbose);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCSettingsSetTraceLevel\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint HCMockCallCreate_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCMockCallCreate\n    HRESULT hr = HCMockCallCreate(&Data()->mockHttpCall);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCMockCallCreate\");\n    return LuaReturnHR(L, hr);\n}\n\nint HCMockAddMock_Lua(lua_State *L)\n{\n    auto method = GetStringFromLua(L, 1, std::string{});\n    auto url = GetStringFromLua(L, 2, std::string{});\n\n    // CODE SNIPPET START: HCMockAddMock\n    HRESULT hr = HCMockAddMock(\n        Data()->mockHttpCall,\n        method.empty() ? nullptr : method.data(),\n        url.empty() ? nullptr : url.data(),\n        nullptr,\n        0\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"HCMockAddMock\");\n    return LuaReturnHR(L, hr);\n}\n\nint HCMockClearMocks_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: HCMockClearMocks\n    HRESULT hr = HCMockClearMocks();\n    // CODE SNIPPET END\n\n    Data()->mockHttpCall = nullptr;\n    LogToFile(\"HCMockClearMocks\");\n    return LuaReturnHR(L, hr);\n}\n\nint HCMockResponseSetNetworkErrorCode_Lua(lua_State *L)\n{\n    auto platformErrorCode = GetUint32FromLua(L, 1, 0);\n\n    // CODE SNIPPET START: HCMockResponseSetNetworkErrorCode\n    HRESULT hr = HCMockResponseSetNetworkErrorCode(Data()->mockHttpCall, E_FAIL, platformErrorCode);\n    // CODE SNIPPET END\n\n    LogToFile(\"HCMockResponseSetNetworkErrorCode\");\n    return LuaReturnHR(L, hr);\n}\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\nnamespace xbox\n{\nnamespace httpclient\n{\nextern void HCWinHttpSuspend();\nextern void HCWinHttpResume();\n}\n}\n\nint HCWinHttpSuspend_lua(lua_State *L)\n{\n    UNREFERENCED_PARAMETER(L);\n    xbox::httpclient::HCWinHttpSuspend();\n    return 0;\n}\n\nint HCWinHttpResume_lua(lua_State *L)\n{\n    UNREFERENCED_PARAMETER(L);\n    xbox::httpclient::HCWinHttpResume();\n    return 0;\n}\n#endif\n\nvoid SetupAPIs_LibHttp()\n{\n    //lua_register(Data()->L, \"HCMemSetFunctions\", HCMemSetFunctions_Lua);\n    //lua_register(Data()->L, \"HCMemGetFunctions\", HCMemGetFunctions_Lua);\n\n    lua_register(Data()->L, \"HCInitialize\", HCInitialize_Lua);\n    lua_register(Data()->L, \"HCCleanup\", HCCleanup_Lua);\n    lua_register(Data()->L, \"HCCleanupAsync\", HCCleanupAsync_Lua);\n    lua_register(Data()->L, \"HCGetLibVersion\", HCGetLibVersion_Lua);\n    lua_register(Data()->L, \"HCTrace\", HCTrace_Lua);\n    lua_register(Data()->L, \"HCTraceLarge\", HCTraceLarge_Lua);\n    //lua_register(Data()->L, \"HCAddCallRoutedHandler\", HCAddCallRoutedHandler_Lua);\n    //lua_register(Data()->L, \"HCRemoveCallRoutedHandler\", HCRemoveCallRoutedHandler_Lua);\n    lua_register(Data()->L, \"HCHttpCallCreate\", HCHttpCallCreate_Lua);\n    lua_register(Data()->L, \"HCHttpCallPerformAsync\", HCHttpCallPerformAsync_Lua);\n    lua_register(Data()->L, \"HCHttpCallDuplicateHandle\", HCHttpCallDuplicateHandle_Lua);\n    lua_register(Data()->L, \"HCHttpCallCloseHandle\", HCHttpCallCloseHandle_Lua);\n    lua_register(Data()->L, \"HCHttpCallGetId\", HCHttpCallGetId_Lua);\n    lua_register(Data()->L, \"HCHttpCallSetTracing\", HCHttpCallSetTracing_Lua);\n    lua_register(Data()->L, \"HCHttpCallGetRequestUrl\", HCHttpCallGetRequestUrl_Lua);\n\n    lua_register(Data()->L, \"HCHttpCallRequestSetUrl\", HCHttpCallRequestSetUrl_Lua);\n    //lua_register(Data()->L, \"HCHttpCallRequestSetRequestBodyBytes\", HCHttpCallRequestSetRequestBodyBytes_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetRequestBodyString\", HCHttpCallRequestSetRequestBodyString_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetHeader\", HCHttpCallRequestSetHeader_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetRetryAllowed\", HCHttpCallRequestSetRetryAllowed_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetRetryCacheId\", HCHttpCallRequestSetRetryCacheId_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetTimeout\", HCHttpCallRequestSetTimeout_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetRetryDelay\", HCHttpCallRequestSetRetryDelay_Lua);\n    lua_register(Data()->L, \"HCHttpCallRequestSetTimeoutWindow\", HCHttpCallRequestSetTimeoutWindow_Lua);\n\n    lua_register(Data()->L, \"HCHttpCallResponseGetResponseString\", HCHttpCallResponseGetResponseString_Lua);\n    lua_register(Data()->L, \"HCHttpCallResponseGetResponseBodyBytesSize\", HCHttpCallResponseGetResponseBodyBytesSize_Lua);\n    //lua_register(Data()->L, \"HCHttpCallResponseGetResponseBodyBytes\", HCHttpCallResponseGetResponseBodyBytes_Lua);\n    lua_register(Data()->L, \"HCHttpCallResponseGetStatusCode\", HCHttpCallResponseGetStatusCode_Lua);\n    lua_register(Data()->L, \"HCHttpCallResponseGetNetworkErrorCode\", HCHttpCallResponseGetNetworkErrorCode_Lua);\n    lua_register(Data()->L, \"HCHttpCallResponseGetHeader\", HCHttpCallResponseGetHeader_Lua);\n    lua_register(Data()->L, \"HCHttpCallResponseGetNumHeaders\", HCHttpCallResponseGetNumHeaders_Lua);\n    lua_register(Data()->L, \"HCHttpCallResponseGetHeaderAtIndex\", HCHttpCallResponseGetHeaderAtIndex_Lua);\n\n    lua_register(Data()->L, \"HCWebSocketCreate\", HCWebSocketCreate_Lua);\n    lua_register(Data()->L, \"HCWebSocketSetProxyUri\", HCWebSocketSetProxyUri_Lua);\n    lua_register(Data()->L, \"HCWebSocketSetHeader\", HCWebSocketSetHeader_Lua);\n    lua_register(Data()->L, \"HCWebSocketConnectAsync\", HCWebSocketConnectAsync_Lua);\n    lua_register(Data()->L, \"HCWebSocketSendMessageAsync\", HCWebSocketSendMessageAsync_Lua);\n    lua_register(Data()->L, \"HCWebSocketDisconnect\", HCWebSocketDisconnect_Lua);\n    lua_register(Data()->L, \"HCWebSocketDuplicateHandle\", HCWebSocketDuplicateHandle_Lua);\n    lua_register(Data()->L, \"HCWebSocketCloseHandle\", HCWebSocketCloseHandle_Lua);\n\n    lua_register(Data()->L, \"HCTraceSetTraceToDebugger\", HCTraceSetTraceToDebugger_Lua);\n    lua_register(Data()->L, \"HCSettingsSetTraceLevel\", HCSettingsSetTraceLevel_Lua);\n\n    lua_register(Data()->L, \"HCMockCallCreate\", HCMockCallCreate_Lua);\n    lua_register(Data()->L, \"HCMockAddMock\", HCMockAddMock_Lua);\n    lua_register(Data()->L, \"HCMockClearMocks\", HCMockClearMocks_Lua);\n    lua_register(Data()->L, \"HCMockResponseSetNetworkErrorCode\", HCMockResponseSetNetworkErrorCode_Lua);\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    lua_register(Data()->L, \"HCWinHttpSuspend\", HCWinHttpSuspend_lua);\n    lua_register(Data()->L, \"HCWinHttpResume\", HCWinHttpResume_lua);\n#endif\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xal.cpp",
    "content": "// Copyright (c) Microsoft Corporation\r\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\r\n#include \"pch.h\"\r\nint XalCleanupAsync_Lua(lua_State *L)\r\n{\r\n    if (!Data()->m_isXalInitialized)\r\n        return LuaReturnHR(L, S_OK);\r\n\r\n    if (Data()->nsalMockCall != nullptr)\r\n    {\r\n        HCMockRemoveMock(Data()->nsalMockCall);\r\n        //Close the handle we're holding onto for API runner state\r\n        HCMockCallCloseHandle(Data()->nsalMockCall);\r\n        Data()->nsalMockCall = nullptr;\r\n\r\n        if (Data()->libHttpClientInit) // Set on GDK where XAL is just a wrapper around XUser\r\n        {\r\n            HCCleanup();\r\n            Data()->libHttpClientInit = false;\r\n        }\r\n    }\r\n\r\n#if CPP_TESTS_ENABLED\r\n    Data()->blobMetadataResultCpp = xbox::services::title_storage::title_storage_blob_metadata_result{};\r\n    Data()->blobMetadataCpp = xbox::services::title_storage::title_storage_blob_metadata{};\r\n#endif\r\n\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    HRESULT hr = XalCleanupAsync(asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // Synchronously wait for cleanup to complete\r\n        hr = XAsyncGetStatus(asyncBlock.get(), true);\r\n        Data()->m_isXalInitialized = false;\r\n    }\r\n\r\n    LogToFile(\"XalCleanup: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nvoid SetupXalNsalMock()\r\n{\r\n    // Mock the NSAL call so XAL doesn't 429 due to repeated fast XAL init/cleanup during testing\r\n\r\n    // GET https://title.mgt.xboxlive.com/titles/current/endpoints HTTP/1.1\r\n    // HTTP/1.1 200 OK\r\n    // {\"EndPoints\":[{\"Protocol\":\"http\",\"Host\":\"*\",\"HostType\":\"wildcard\"},{\"Protocol\":\"https\",\"Host\":\"*\",\"HostType\":\"wildcard\"}]}\r\n\r\n    if (Data()->nsalMockCall != nullptr)\r\n    {\r\n        HCMockRemoveMock(Data()->nsalMockCall);\r\n        Data()->nsalMockCall = nullptr;\r\n    }\r\n\r\n    HRESULT hr = HCMockCallCreate(&(Data()->nsalMockCall));\r\n    if (hr == E_HC_NOT_INITIALISED)\r\n    {\r\n        // This happens on GDK where XAL is just a wrapper around XUser\r\n        LogToScreen(\"Calling HCInitialize()\");\r\n\r\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\r\n        hr = HCInitialize(&(Data()->initArgs));\r\n#else\r\n        hr = HCInitialize(nullptr);\r\n#endif\r\n        LogToScreen(\"HCInitialize done\");\r\n        assert(SUCCEEDED(hr));\r\n        Data()->libHttpClientInit = true;\r\n        hr = HCMockCallCreate(&(Data()->nsalMockCall));\r\n    }\r\n    assert(SUCCEEDED(hr));\r\n\r\n    hr = HCMockAddMock(Data()->nsalMockCall, \"GET\", \"https://title.mgt.xboxlive.com/titles/current/endpoints\", nullptr, 0);\r\n    assert(SUCCEEDED(hr));\r\n\r\n    hr = HCMockResponseSetStatusCode(Data()->nsalMockCall, 200);\r\n    assert(SUCCEEDED(hr));\r\n\r\n    std::string responseBodyString = \"{\\\"EndPoints\\\":[{\\\"Protocol\\\":\\\"http\\\",\\\"Host\\\":\\\"*\\\",\\\"HostType\\\":\\\"wildcard\\\"},{\\\"Protocol\\\":\\\"https\\\",\\\"Host\\\":\\\"*\\\",\\\"HostType\\\":\\\"wildcard\\\"}]}\";\r\n    std::vector<uint8_t> bodyBytes{ responseBodyString.begin(), responseBodyString.end() };\r\n    hr = HCMockResponseSetResponseBodyBytes(Data()->nsalMockCall, bodyBytes.data(), static_cast<uint32_t>(bodyBytes.size()));\r\n    assert(SUCCEEDED(hr));\r\n}\r\n\r\n\r\nint XalInitialize_Lua(lua_State *L)\r\n{\r\n    std::string clientId = GetStringFromLua(L, 1, \"000000004C251635\");\r\n    uint32_t titleId = (uint32_t)GetUint64FromLua(L, 2, 1626464874);\r\n    std::string sandbox = GetStringFromLua(L, 3, \"RETAIL\");\r\n\r\n    // Alternate config for XboxLiveE2E Stats 2017\r\n    //std::string clientId = GetStringFromLua(L, 1, \"0000000044296E10\");\r\n    //uint32_t titleId = (uint32_t)GetUint64FromLua(L, 2, 2025855259);\r\n\r\n    Data()->titleId = titleId;\r\n\r\n    CreateQueueIfNeeded();\r\n\r\n    // CODE SNIPPET START: XalInitialize\r\n\r\n    XalInitArgs xalInitArgs = {};\r\n#if HC_PLATFORM == HC_PLATFORM_UWP\r\n\r\n    xalInitArgs.titleId = titleId;\r\n    xalInitArgs.packageFamilyName = u8\"41336MicrosoftATG.XboxLiveE2E_dspnxghe87tn0\";\r\n    //xalInitArgs.correlationVector; // optional\r\n    //xalInitArgs.flags; // optional\r\n    //xalInitArgs.launchUser; // optional\r\n    //xalInitArgs.mainWindow; // optional\r\n\r\n#elif HC_PLATFORM == HC_PLATFORM_GDK || HC_PLATFORM == HC_PLATFORM_XDK\r\n    // No args on GDK / XDK\r\n\r\n#else\r\n\r\n    // Args for iOS / Android / Win32 \r\n    xalInitArgs.clientId = clientId.c_str();\r\n    xalInitArgs.titleId = titleId;\r\n    xalInitArgs.sandbox = sandbox.c_str();\r\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\r\n    // Extra args on Mobile\r\n    std::string redirectUri{ \"ms-xal-\" + clientId + \"://auth\" };\r\n    xalInitArgs.redirectUri = redirectUri.data();\r\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\r\n    // Extra args on Android\r\n    xalInitArgs.disableDiagnosticTelemetry = false;\r\n\r\n    JNIEnv* jniEnv = nullptr;\r\n    jint result = Data()->javaVM->GetEnv(reinterpret_cast<void**>(&jniEnv), JNI_VERSION_1_6);\r\n    if (result != JNI_OK)\r\n    {\r\n        LogToScreen(\"Failed to retrieve the JNIEnv from the JavaVM.\");\r\n    }\r\n\r\n    assert(jniEnv != nullptr);\r\n\r\n    jobject res = jniEnv->CallObjectMethod(Data()->m_mainActivityClassInstance, Data()->m_getApplicationContext);\r\n\r\n    xalInitArgs.javaVM = Data()->javaVM;\r\n    xalInitArgs.appContext = res;\r\n#endif\r\n#endif\r\n#endif\r\n\r\n    HCTraceSetTraceToDebugger(true);\r\n    HCSettingsSetTraceLevel(HCTraceLevel::Verbose);\r\n\r\n    HRESULT hr = XalInitialize(&xalInitArgs, Data()->queue);\r\n    // CODE SNIPPET END\r\n    Data()->m_isXalInitialized = true;\r\n\r\n    LogToScreen(\"XalInitialize: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalInitialize: hr=%s\", ConvertHR(hr).c_str());\r\n\r\n    SetupXalNsalMock();\r\n\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalTryAddFirstUserSilentlyAsync_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    // CODE SNIPPET START: XalTryAddFirstUserSilentlyAsync\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\r\n    {\r\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\r\n        XalUserHandle newUser = nullptr;\r\n        HRESULT hr = XalTryAddDefaultUserSilentlyResult(asyncBlock, &newUser);\r\n\r\n        // TODO: Store and use newUser\r\n        LogToScreen(\"XalTryAddFirstUserSilentlyResult: hr=%s user=0x%0.8x\", ConvertHR(hr).c_str(), newUser);\r\n        LogToFile(\"XalTryAddFirstUserSilentlyResult: hr=%s user=0x%0.8x\", ConvertHR(hr).c_str(), newUser); // CODE SNIP SKIP\r\n        if (Data()->xalUser != nullptr)\r\n        {\r\n            XalUserCloseHandle(Data()->xalUser);\r\n            Data()->xalUser = nullptr;\r\n        }\r\n        Data()->xalUser = newUser; // CODE SNIP SKIP\r\n        if (Data()->xalUser) // CODE SNIP SKIP\r\n        { // CODE SNIP SKIP\r\n            Data()->gotXalUser = true; // CODE SNIP SKIP\r\n        } // CODE SNIP SKIP\r\n        LuaStopTestIfFailed(hr);\r\n        CallLuaString(\"common = require 'common'; common.OnXalTryAddFirstUserSilentlyAsync()\"); // CODE SNIP SKIP\r\n    };\r\n\r\n    HRESULT hr = XalTryAddDefaultUserSilentlyAsync(0u, asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\r\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\r\n        asyncBlock.release();\r\n    }\r\n    // CODE SNIPPET END\r\n    LogToScreen(\"XalTryAddFirstUserSilentlyAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalTryAddFirstUserSilentlyAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalGetMaxUsers_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalGetMaxUsers\r\n    uint32_t maxUsers = 0;\r\n    HRESULT hr = XalGetMaxUsers(&maxUsers);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalGetMaxUsers: hr=%s. result=%d\", ConvertHR(hr).c_str(), maxUsers);\r\n    LogToFile(\"XalGetMaxUsers: hr=%s. result=%d\", ConvertHR(hr).c_str(), maxUsers); // CODE SNIP SKIP\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalAddUserWithUiAsync_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    // CODE SNIPPET START: XalAddUserWithUiAsync\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\r\n    {\r\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\r\n        XalUserHandle newUser = nullptr;\r\n        HRESULT hr = XalAddUserWithUiResult(asyncBlock, &newUser);\r\n        \r\n        // TODO: Store and use newUser\r\n        LogToScreen(\"XalAddUserWithUiResult: hr=%s user=0x%0.8x\", ConvertHR(hr).c_str(), newUser);\r\n        LogToFile(\"XalAddUserWithUiResult: hr=%s user=0x%0.8x\", ConvertHR(hr).c_str(), newUser); // CODE SNIP SKIP\r\n        if (Data()->xalUser != nullptr)\r\n        {\r\n            XalUserCloseHandle(Data()->xalUser);\r\n            Data()->xalUser = nullptr;\r\n        }\r\n        Data()->xalUser = newUser; // CODE SNIP SKIP\r\n        if (Data()->xalUser) // CODE SNIP SKIP\r\n        { // CODE SNIP SKIP\r\n            Data()->gotXalUser = true; // CODE SNIP SKIP\r\n        } // CODE SNIP SKIP\r\n        CallLuaFunctionWithHr(hr, \"OnXalAddUserWithUiAsync\"); // CODE SNIP SKIP\r\n    };\r\n\r\n    HRESULT hr = XalAddUserWithUiAsync(0u, asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\r\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\r\n        asyncBlock.release();\r\n    }\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalAddUserWithUiAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalAddUserWithUiAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalGetDeviceUserIsPresent_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalGetDeviceUserIsPresent\r\n    bool result = XalGetDeviceUserIsPresent();\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalGetDeviceUserIsPresent: result=%d\", result);\r\n    LogToFile(\"XalGetDeviceUserIsPresent: result=%d\", result);\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n\r\nint XalGetDeviceUser_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalGetDeviceUser\r\n    XalUserHandle deviceUser = nullptr;\r\n    HRESULT hr = XalGetDeviceUser(&deviceUser);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalGetDeviceUser: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalGetDeviceUser: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalSignOutUserAsyncIsPresent_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalSignOutUserAsyncIsPresent\r\n    bool result = XalSignOutUserAsyncIsPresent();\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalSignOutUserAsyncIsPresent: result=%d\", result);\r\n    LogToFile(\"XalSignOutUserAsyncIsPresent: result=%d\", result);\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n\r\nint XalSignOutUserAsync_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    // CODE SNIPPET START: XalSignOutUserAsync\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\r\n    {\r\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\r\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\r\n\r\n        // TODO: Store and use newUser\r\n        LogToScreen(\"OnXalSignOutUserAsync: hr=%s\", ConvertHR(hr).c_str());\r\n        LogToFile(\"OnXalSignOutUserAsync: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\r\n        XalUserCloseHandle(Data()->xalUser); // CODE SNIP SKIP\r\n        Data()->xalUser = nullptr; // CODE SNIP SKIP\r\n        CallLuaFunctionWithHr(hr, \"OnXalSignOutUserAsync\"); // CODE SNIP SKIP\r\n    };\r\n\r\n    HRESULT hr = XalSignOutUserAsync(Data()->xalUser, asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\r\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\r\n        asyncBlock.release();\r\n    }\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalSignOutUserAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalSignOutUserAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserDuplicateHandle_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserDuplicateHandle\r\n    XalUserHandle dupUser = nullptr;\r\n    HRESULT hr = XalUserDuplicateHandle(Data()->xalUser, &dupUser);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserDuplicateHandle: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserDuplicateHandle: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserCloseHandle_Lua(lua_State *L)\r\n{\r\n    XalUserHandle xalUser = Data()->xalUser;\r\n    if (xalUser != nullptr)\r\n    {\r\n        // CODE SNIPPET START: XalUserCloseHandle\r\n        XalUserCloseHandle(xalUser);\r\n        xalUser = nullptr;\r\n        // CODE SNIPPET END\r\n        Data()->xalUser = nullptr;\r\n\r\n        LogToScreen(\"XalUserCloseHandle\");\r\n        LogToFile(\"XalUserCloseHandle\");\r\n    }\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n\r\nint XalUserGetId_Lua(lua_State *L)\r\n{\r\n    if (Data()->xalUser == nullptr)\r\n    {\r\n        return LuaReturnHR(L, S_OK);\r\n    }\r\n\r\n    // CODE SNIPPET START: XalUserGetId\r\n    uint64_t xboxUserId = 0;\r\n    HRESULT hr = XalUserGetId(Data()->xalUser, &xboxUserId);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserGetId: hr=%s xboxUserId=%llu\", ConvertHR(hr).c_str(), xboxUserId);\r\n    LogToFile(\"XalUserGetId: hr=%s xboxUserId=%llu\", ConvertHR(hr).c_str(), xboxUserId);\r\n    Data()->xboxUserId = xboxUserId;\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserIsDevice_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserIsDevice\r\n    bool result = XalUserIsDevice(Data()->xalUser);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserIsDevice: result=%d\", result);\r\n    LogToFile(\"XalUserIsDevice: result=%d\", result);\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n\r\nint XalUserIsGuest_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserIsGuest\r\n    bool result = XalUserIsGuest(Data()->xalUser);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserIsGuest: result=%d\", result);\r\n    LogToFile(\"XalUserIsGuest: result=%d\", result);\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n\r\nint XalUserGetState_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserGetState\r\n    XalUserState state = {};\r\n    HRESULT hr = XalUserGetState(Data()->xalUser, &state);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserGetState: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserGetState: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserGetGamertag_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserGetGamertag\r\n    size_t gamerTagSize = XalUserGetGamertagSize(Data()->xalUser, XalGamertagComponent_Classic);\r\n    std::vector<char> gamerTag(gamerTagSize, '\\0');\r\n\r\n    size_t bufferUsed;\r\n    HRESULT hr = XalUserGetGamertag(Data()->xalUser, XalGamertagComponent_Classic, gamerTagSize, gamerTag.data(), &bufferUsed);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserGetGamertag %s: hr=%s gamerTag=%s\", gamerTag.data(), ConvertHR(hr).c_str(), gamerTag.data());\r\n    LogToFile(\"XalUserGetGamertag %s: hr=%s gamerTag=%s\", gamerTag.data(), ConvertHR(hr).c_str(), gamerTag.data());\r\n\r\n    Data()->gamertag = std::string(gamerTag.data());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserGetAgeGroup_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserGetAgeGroup\r\n    XalAgeGroup ageGroup = {};\r\n    HRESULT hr = XalUserGetAgeGroup(Data()->xalUser, &ageGroup);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserGetAgeGroup: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserGetAgeGroup: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserCheckPrivilege_Lua(lua_State *L)\r\n{\r\n    // CODE SNIPPET START: XalUserCheckPrivilege\r\n    XalPrivilege privilege = XalPrivilege_Multiplayer;\r\n    bool hasPrivilege = false;\r\n    XalPrivilegeCheckDenyReasons reasons = { };\r\n    HRESULT hr = XalUserCheckPrivilege(Data()->xalUser, privilege, &hasPrivilege, &reasons);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserCheckPrivilege: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserCheckPrivilege: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserGetGamerPictureAsync_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    // CODE SNIPPET START: XalUserGetGamerPictureAsync\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\r\n    {\r\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\r\n        size_t bufferSize;\r\n        HRESULT hr = XalUserGetGamerPictureResultSize(asyncBlock, &bufferSize);\r\n        LogToScreen(\"XalUserGetGamerPictureResultSize: hr=%s bufferSize=%d\", ConvertHR(hr).c_str(), bufferSize);\r\n        LogToFile(\"XalUserGetGamerPictureResultSize: hr=%s bufferSize=%d\", ConvertHR(hr).c_str(), bufferSize); // CODE SNIP SKIP\r\n        \r\n        std::vector<byte> buffer(bufferSize);\r\n        hr = XalUserGetGamerPictureResult(asyncBlock, bufferSize, buffer.data());\r\n        LogToScreen(\"XalUserGetGamerPictureResult: hr=%s\", ConvertHR(hr).c_str());\r\n        LogToFile(\"XalUserGetGamerPictureResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\r\n        CallLuaFunctionWithHr(hr, \"OnXalUserGetGamerPictureAsync\"); // CODE SNIP SKIP\r\n    };\r\n\r\n    HRESULT hr = XalUserGetGamerPictureAsync(Data()->xalUser, XalGamerPictureSize_Small, asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\r\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\r\n        asyncBlock.release();\r\n    }\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserGetGamerPictureAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserGetGamerPictureAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserGetTokenAndSignatureSilentlyAsync_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    std::string method = GetStringFromLua(L, 1, \"\");\r\n    std::string url = GetStringFromLua(L, 2, \"\");\r\n\r\n    // CODE SNIPPET START: XalUserGetTokenAndSignatureSilentlyAsync\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\r\n    {\r\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\r\n        size_t bufferSize;\r\n        HRESULT hr = XalUserGetTokenAndSignatureSilentlyResultSize(asyncBlock, &bufferSize);\r\n        LogToScreen(\"XalUserGetTokenAndSignatureSilentlyResultSize: hr=%s bufferSize=%d\", ConvertHR(hr).c_str(), bufferSize);\r\n        LogToFile(\"XalUserGetTokenAndSignatureSilentlyResultSize: hr=%s bufferSize=%d\", ConvertHR(hr).c_str(), bufferSize); // CODE SNIP SKIP\r\n        \r\n        std::vector<byte> buffer(bufferSize);\r\n        XalUserGetTokenAndSignatureData* result;\r\n        hr = XalUserGetTokenAndSignatureSilentlyResult(asyncBlock, bufferSize, buffer.data(), &result, nullptr);\r\n        LogToScreen(\"XalUserGetTokenAndSignatureSilentlyResult: hr=%s\", ConvertHR(hr).c_str());\r\n        LogToFile(\"XalUserGetTokenAndSignatureSilentlyResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\r\n        CallLuaFunctionWithHr(hr, \"OnXalUserGetTokenAndSignatureSilentlyAsync\"); // CODE SNIP SKIP\r\n    };\r\n\r\n    XalUserGetTokenAndSignatureArgs args{};\r\n    args.method = method.data();\r\n    args.url = url.data();\r\n\r\n    HRESULT hr = XalUserGetTokenAndSignatureSilentlyAsync(Data()->xalUser, &args, asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\r\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\r\n        asyncBlock.release();\r\n    }\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserCheckPrivilegesWithUiAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserCheckPrivilegesWithUiAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserResolveIssueWithUiAsync_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    // CODE SNIPPET START: XalUserResolveIssueWithUiAsync\r\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \r\n    asyncBlock->queue = Data()->queue;\r\n    asyncBlock->context = nullptr;\r\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\r\n    {\r\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\r\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\r\n        LogToScreen(\"XAsyncGetStatus: hr=%s\", ConvertHR(hr).c_str());\r\n        LogToFile(\"XAsyncGetStatus: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\r\n        CallLuaFunctionWithHr(hr, \"OnXalUserResolveIssueWithUiAsync\"); // CODE SNIP SKIP\r\n    };\r\n\r\n    HRESULT hr = XalUserResolveIssueWithUiAsync(Data()->xalUser, \"https://www.xboxlive.com\", asyncBlock.get());\r\n    if (SUCCEEDED(hr))\r\n    {\r\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\r\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\r\n        asyncBlock.release();\r\n    }\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserResolveIssueWithUiAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserResolveIssueWithUiAsync: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\n// CODE SNIPPET START: XalUserRegisterChangeEventHandler\r\nvoid OnXalUserChangeEventHandler(\r\n    _In_opt_ void* context,\r\n    _In_ XalUserLocalId userId,\r\n    _In_ XalUserChangeType change)\r\n{\r\n    UNREFERENCED_PARAMETER(context);\r\n    UNREFERENCED_PARAMETER(userId);\r\n    UNREFERENCED_PARAMETER(change);\r\n}\r\n\r\n#if HC_PLATFORM == HC_PLATFORM_GDK\r\nvoid CALLBACK OnXalUserChangeEventHandler_GDK(\r\n    _In_opt_ void* context,\r\n    _In_ XUserLocalId userLocalId,\r\n    _In_ XUserChangeEvent event)\r\n{\r\n    UNREFERENCED_PARAMETER(context);\r\n    UNREFERENCED_PARAMETER(userLocalId);\r\n    UNREFERENCED_PARAMETER(event);\r\n}\r\n#endif\r\n// CODE SNIPPET END\r\n\r\nint XalUserRegisterChangeEventHandler_Lua(lua_State *L)\r\n{\r\n    CreateQueueIfNeeded();\r\n\r\n    void* context = nullptr;\r\n    XalRegistrationToken token = { 0 };\r\n\r\n    // CODE SNIPPET START: XalUserRegisterChangeEventHandler\r\n#if HC_PLATFORM == HC_PLATFORM_GDK\r\n    HRESULT hr = XalUserRegisterChangeEventHandler(Data()->queue, context, OnXalUserChangeEventHandler_GDK, &token);\r\n#else\r\n    HRESULT hr = XalUserRegisterChangeEventHandler(Data()->queue, context, OnXalUserChangeEventHandler, &token);\r\n#endif\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserRegisterChangeEventHandler: hr=%s\", ConvertHR(hr).c_str());\r\n    LogToFile(\"XalUserRegisterChangeEventHandler: hr=%s\", ConvertHR(hr).c_str());\r\n    return LuaReturnHR(L, hr);\r\n}\r\n\r\nint XalUserUnregisterChangeEventHandler_Lua(lua_State *L)\r\n{\r\n    XalRegistrationToken token{0};\r\n\r\n    // CODE SNIPPET START: XalUserUnregisterChangeEventHandler\r\n    XalUserUnregisterChangeEventHandler(token);\r\n    // CODE SNIPPET END\r\n\r\n    LogToScreen(\"XalUserUnregisterChangeEventHandler\");\r\n    LogToFile(\"XalUserUnregisterChangeEventHandler\");\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n\r\n\r\n#if HC_PLATFORM == HC_PLATFORM_GDK || HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_UWP || HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_ANDROID\r\nint XalPlatformWebSetEventHandler_Lua(lua_State *L)\r\n{\r\n     return LuaReturnHR(L, S_OK);\r\n}\r\n\r\nint XalPlatformStorageSetEventHandlers_Lua(lua_State *L)\r\n{\r\n    return LuaReturnHR(L, S_OK);\r\n}\r\n#endif\r\n\r\nvoid SetupAPIs_Xal()\r\n{\r\n    lua_register(Data()->L, \"XalInitialize\", XalInitialize_Lua);\r\n    lua_register(Data()->L, \"XalCleanupAsync\", XalCleanupAsync_Lua);\r\n\r\n    lua_register(Data()->L, \"XalPlatformWebSetEventHandler\", XalPlatformWebSetEventHandler_Lua);\r\n    lua_register(Data()->L, \"XalPlatformStorageSetEventHandlers\", XalPlatformStorageSetEventHandlers_Lua);\r\n    \r\n    lua_register(Data()->L, \"XalGetMaxUsers\", XalGetMaxUsers_Lua);\r\n\r\n    lua_register(Data()->L, \"XalTryAddFirstUserSilentlyAsync\", XalTryAddFirstUserSilentlyAsync_Lua);\r\n    lua_register(Data()->L, \"XalAddUserWithUiAsync\", XalAddUserWithUiAsync_Lua);\r\n    lua_register(Data()->L, \"XalGetDeviceUserIsPresent\", XalGetDeviceUserIsPresent_Lua);\r\n    lua_register(Data()->L, \"XalGetDeviceUser\", XalGetDeviceUser_Lua);\r\n    lua_register(Data()->L, \"XalSignOutUserAsyncIsPresent\", XalSignOutUserAsyncIsPresent_Lua);\r\n    lua_register(Data()->L, \"XalSignOutUserAsync\", XalSignOutUserAsync_Lua);\r\n\r\n    lua_register(Data()->L, \"XalUserDuplicateHandle\", XalUserDuplicateHandle_Lua);\r\n    lua_register(Data()->L, \"XalUserCloseHandle\", XalUserCloseHandle_Lua);\r\n    lua_register(Data()->L, \"XalUserGetId\", XalUserGetId_Lua);\r\n    lua_register(Data()->L, \"XalUserIsDevice\", XalUserIsDevice_Lua);\r\n    lua_register(Data()->L, \"XalUserIsGuest\", XalUserIsGuest_Lua);\r\n    lua_register(Data()->L, \"XalUserGetState\", XalUserGetState_Lua);\r\n    lua_register(Data()->L, \"XalUserGetGamertag\", XalUserGetGamertag_Lua);\r\n    lua_register(Data()->L, \"XalUserGetGamerPictureAsync\", XalUserGetGamerPictureAsync_Lua);\r\n    lua_register(Data()->L, \"XalUserGetAgeGroup\", XalUserGetAgeGroup_Lua);\r\n    lua_register(Data()->L, \"XalUserCheckPrivilege\", XalUserCheckPrivilege_Lua);\r\n    lua_register(Data()->L, \"XalUserGetTokenAndSignatureSilentlyAsync\", XalUserGetTokenAndSignatureSilentlyAsync_Lua);\r\n    lua_register(Data()->L, \"XalUserResolveIssueWithUiAsync\", XalUserResolveIssueWithUiAsync_Lua);\r\n    lua_register(Data()->L, \"XalUserRegisterChangeEventHandler\", XalUserRegisterChangeEventHandler_Lua);\r\n    lua_register(Data()->L, \"XalUserUnregisterChangeEventHandler\", XalUserUnregisterChangeEventHandler_Lua);\r\n}\r\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nvoid StopSocialManagerDoWorkHelper();\nvoid StopAchievementsManagerDoWorkHelper();\n#if CPP_TESTS_ENABLED\nvoid StopSocialManagerDoWorkHelperCpp();\n#endif\n\nint XblInitialize_Lua(lua_State *L)\n{\n    bool bSetQueue = GetBoolFromLua(L, 1, true);\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblInitialize\n    XblInitArgs args = { };\n    args.queue = Data()->queue;\n\n    // CODE SKIP START\n    if(!bSetQueue)\n    {\n        //Use a default task queue. If the global task queue has been initialized to null,\n        //trying to use a default task queue for XblInitialize will return E_NO_TASK_QUEUE.\n        args.queue = nullptr;\n    }\n    // CODE SKIP END\n#if !(HC_PLATFORM == HC_PLATFORM_XDK || HC_PLATFORM == HC_PLATFORM_UWP)\n    args.scid = \"00000000-0000-0000-0000-000076029b4d\";\n    // Alternate SCID for XboxLiveE2E Stats 2017 config\n    // args.scid = \"00000000-0000-0000-0000-000078c0191b\"\n#endif\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    char pathArray[MAX_PATH + 1];\n    GetCurrentDirectoryA(MAX_PATH + 1, pathArray);\n    auto pathString = std::string{ pathArray } + '\\\\';\n    args.localStoragePath = pathString.data();\n#endif\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    args.applicationContext = Data()->applicationContext;\n    args.javaVM = Data()->javaVM;\n#endif\n    HRESULT hr = XblInitialize(&args);\n    // CODE SNIPPET END\n\n    if (SUCCEEDED(hr))\n    {\n        XblDisableAssertsForXboxLiveThrottlingInDevSandboxes(XblConfigSetting::ThisCodeNeedsToBeChanged);\n    }\n\n    LogToFile(\"XblInitialize: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblGetScid_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblGetScid\n    HRESULT hr = XblGetScid(&Data()->scid);\n    // CODE SNIPPET END\n    LogToFile(\"XblGetScid: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblDisableAssertsForXboxLiveThrottlingInDevSandboxes_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblDisableAssertsForXboxLiveThrottlingInDevSandboxes\n    XblDisableAssertsForXboxLiveThrottlingInDevSandboxes(XblConfigSetting::ThisCodeNeedsToBeChanged);\n    // CODE SNIPPET END\n    LogToFile(\"XblDisableAssertsForXboxLiveThrottlingInDevSandboxes Complete.\");\n    return LuaReturnHR(L, S_OK);\n}\n\n_Ret_maybenull_ _Post_writable_byte_size_(size) void* STDAPIVCALLTYPE ApiRunnerMemAlloc(\n    _In_ size_t size,\n    _In_ HCMemoryType\n    )\n{\n    return new (std::nothrow) char[size];\n}\n\nvoid STDAPIVCALLTYPE ApiRunnerMemFree(\n    _In_ _Post_invalid_ void* pointer,\n    _In_ HCMemoryType\n    )\n{\n    delete[] pointer;\n}\n\nXblMemAllocFunction g_apiRunnerMemAllocFunc = nullptr;\nXblMemFreeFunction g_apiRunnerMemFreeFunc = nullptr;\n\n\nint XblMemSetFunctions_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMemSetFunctions\n    HRESULT hr = XblMemSetFunctions(&ApiRunnerMemAlloc, &ApiRunnerMemFree);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMemSetFunctions: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMemGetFunctions_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMemGetFunctions\n    XblMemAllocFunction memAllocFunc = nullptr;\n    XblMemFreeFunction memFreeFunc = nullptr;\n    HRESULT hr = XblMemGetFunctions(&memAllocFunc, &memFreeFunc);\n    // CODE SNIPPET END\n\n    g_apiRunnerMemAllocFunc = memAllocFunc;\n    g_apiRunnerMemFreeFunc = memFreeFunc;\n    LogToFile(\"XblMemGetFunctions: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblCleanupAsync_Lua(lua_State *L)\n{\n#if HC_PLATFORM == HC_PLATFORM_UWP\n    Sleep(1000);\n#endif\n\n    // CODE SNIPPET START: XblCleanupAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n\n    HRESULT hr = XblCleanupAsync(asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // Synchronously wait for cleanup to complete\n        hr = XAsyncGetStatus(asyncBlock.get(), true);\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblCleanup: hr=%s\", ConvertHR(hr).data());\n\n    // Ignore not init'd error\n    if (hr == E_XBL_NOT_INITIALIZED)\n    {\n        hr = S_OK;\n    }\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblGetErrorCondition_Lua(lua_State *L)\n{\n    HRESULT hrIn = static_cast<HRESULT>(GetUint32FromLua(L, 1, static_cast<uint32_t>(E_FAIL)));\n    XblErrorCondition errc = XblGetErrorCondition(hrIn);\n    lua_pushinteger(L, (int)errc);\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint XblContextCreateHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextCreateHandle\n    XblContextHandle contextHandle{ nullptr };\n    HRESULT hr = XblContextCreateHandle(Data()->xalUser, &contextHandle);\n    // CODE SNIPPET END\n\n    // Cache the created handle for use in other APIs if we don't have one already\n    if (Data()->xboxLiveContext == nullptr)\n    {\n        Data()->xboxLiveContext = contextHandle;\n    }\n    else\n    {\n        LogToFile(\"XblContextCreateHandle called but an existing handle was cached\");\n    }\n\n    lua_pushinteger(L, (int64_t)contextHandle);\n\n    LogToFile(\"XblContextCreateHandle: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblContextDuplicateHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextCreateHandle\n    XblContextHandle duplicate{};\n    HRESULT hr = XblContextDuplicateHandle(Data()->xboxLiveContext, &duplicate);\n    // CODE SNIPPET END\n\n    if (SUCCEEDED(hr))\n    {\n        XblContextCloseHandle(Data()->xboxLiveContext);\n        Data()->xboxLiveContext = duplicate;\n    }\n\n    LogToFile(\"XblContextDuplicateHandle: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextCloseHandle_Lua(lua_State *L)\n{\n    StopSocialManagerDoWorkHelper();\n    StopAchievementsManagerDoWorkHelper();\n#if CPP_TESTS_ENABLED\n    StopSocialManagerDoWorkHelperCpp();\n#endif\n\n    // Get the XblContextHandle\n    XblContextHandle handleToClose = (XblContextHandle)GetUint64FromLua(L, 1, (uint64_t)Data()->xboxLiveContext);\n\n    // CODE SNIPPET START: XblContextCloseHandle\n    if (handleToClose != nullptr)\n    {\n        XblContextCloseHandle(handleToClose);\n    }\n    // CODE SNIPPET END\n\n    if (handleToClose == Data()->xboxLiveContext)\n    {\n        Data()->xboxLiveContext = nullptr;\n    }\n\n    LogToFile(\"OnXblContextCloseHandle called.\");\n    return LuaReturnHR(L, S_OK);\n}\n\n// CODE SNIPPET START: XblCallRoutedHandler\nvoid Test_XblCallRoutedHandler(\n    _In_ XblServiceCallRoutedArgs,\n    _In_ void*)\n{\n}\n// CODE SNIPPET START: XblCallRoutedHandler\n\n\nint XblAddServiceCallRoutedHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsAddServiceCallRoutedHandler\n    XblFunctionContext fn = XblAddServiceCallRoutedHandler(Test_XblCallRoutedHandler, nullptr);\n    // CODE SNIPPET END\n    Data()->fnAddServiceCallRoutedHandler = fn;\n\n    LogToFile(\"XblContextSettingsAddServiceCallRoutedHandler_Lua\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblSetOverrideLocale_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSetOverrideLocale\n    XblSetOverrideLocale(\"fr-FR\");\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSetOverrideLocale_Lua\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRemoveServiceCallRoutedHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsRemoveServiceCallRoutedHandler\n    XblRemoveServiceCallRoutedHandler(Data()->fnAddServiceCallRoutedHandler);\n    // CODE SNIPPET END\n    Data()->fnAddServiceCallRoutedHandler = 0;\n\n    LogToFile(\"XblContextSettingsRemoveServiceCallRoutedHandler_Lua\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblContextSettingsGetLongHttpTimeout_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsGetLongHttpTimeout_Lua\n    uint32_t timeoutInSeconds = 0;\n    XblContextSettingsGetLongHttpTimeout(Data()->xboxLiveContext, &timeoutInSeconds);\n    // CODE SNIPPET END\n        \n    LogToFile(\"XblContextSettingsGetLongHttpTimeout_Lua: %d\", timeoutInSeconds);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblContextSettingsSetLongHttpTimeout_Lua(lua_State *L)\n{\n    uint32_t timeoutInSeconds = GetUint32FromLua(L, 1, 500);\n    // CODE SNIPPET START: XblContextSettingsSetLongHttpTimeout_Lua\n    HRESULT hr = XblContextSettingsSetLongHttpTimeout(Data()->xboxLiveContext, timeoutInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblContextSettingsSetLongHttpTimeout_Lua\");\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextSettingsGetHttpRetryDelay_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsGetHttpRetryDelay_Lua\n    uint32_t delayInSeconds = 0;\n    HRESULT hr = XblContextSettingsGetHttpRetryDelay(Data()->xboxLiveContext, &delayInSeconds);\n    // CODE SNIPPET END\n\n    UNREFERENCED_PARAMETER(hr);\n    LogToFile(\"XblContextSettingsGetHttpRetryDelay_Lua: %ul\", delayInSeconds);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblContextSettingsSetHttpRetryDelay_Lua(lua_State *L)\n{\n    uint32_t delayInSeconds = GetUint32FromLua(L, 1, 300);\n    // CODE SNIPPET START: XblContextSettingsSetHttpRetryDelay_Lua\n    HRESULT hr = XblContextSettingsSetHttpRetryDelay(Data()->xboxLiveContext, delayInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblContextSettingsSetHttpRetryDelay_Lua\");\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextSettingsGetHttpTimeoutWindow_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsGetHttpTimeoutWindow_Lua\n    uint32_t delayInSeconds = 0;\n    HRESULT hr = XblContextSettingsGetHttpTimeoutWindow(Data()->xboxLiveContext, &delayInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblContextSettingsGetHttpTimeoutWindow_Lua %d\", delayInSeconds);\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextSettingsSetHttpTimeoutWindow_Lua(lua_State *L)\n{\n    uint32_t timeoutWindowInSeconds = GetUint32FromLua(L, 1, 200);\n    // CODE SNIPPET START: XblContextSettingsSetHttpTimeoutWindow_Lua\n    HRESULT hr = XblContextSettingsSetHttpTimeoutWindow(Data()->xboxLiveContext, timeoutWindowInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblContextSettingsSetHttpTimeoutWindow_Lua: %d\", timeoutWindowInSeconds);\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextSettingsGetWebsocketTimeoutWindow_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsGetWebsocketTimeoutWindow_Lua\n    uint32_t timeoutWindowInSeconds = 0;\n    HRESULT hr = XblContextSettingsGetHttpTimeoutWindow(Data()->xboxLiveContext, &timeoutWindowInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblContextSettingsGetWebsocketTimeoutWindow_Lua: %d\", timeoutWindowInSeconds);\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextSettingsSetWebsocketTimeoutWindow_Lua(lua_State *L)\n{\n    uint32_t timeoutWindowInSeconds = GetUint32FromLua(L, 1, 200);\n    // CODE SNIPPET START: XblContextSettingsSetWebsocketTimeoutWindow_Lua\n    HRESULT hr = XblContextSettingsSetWebsocketTimeoutWindow(Data()->xboxLiveContext, timeoutWindowInSeconds);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblContextSettingsSetWebsocketTimeoutWindow_Lua\");\n    return LuaReturnHR(L, hr);\n}\n\nint XblContextSettingsGetUseCrossPlatformQosServers_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblContextSettingsGetUseCrossPlatformQosServers_Lua\n    bool useQosServers = 0;\n    HRESULT hr = XblContextSettingsGetUseCrossPlatformQosServers(Data()->xboxLiveContext, &useQosServers);\n    // CODE SNIPPET END\n\n    UNREFERENCED_PARAMETER(hr);\n    LogToFile(\"XblContextSettingsGetUseCrossPlatformQosServers_Lua: %d\", useQosServers);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblContextSettingsSetUseCrossPlatformQosServers_Lua(lua_State *L)\n{\n    bool useQosServers = GetBoolFromLua(L, 1, true);\n    // CODE SNIPPET START: XblContextSettingsSetUseCrossPlatformQosServers_Lua\n    HRESULT hr = XblContextSettingsGetUseCrossPlatformQosServers(Data()->xboxLiveContext, &useQosServers);\n    // CODE SNIPPET END\n\n    UNREFERENCED_PARAMETER(hr);\n    LogToFile(\"XblContextSettingsSetUseCrossPlatformQosServers_Lua\");\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_Xbl()\n{\n    // xbox_live_global_c.h\n    lua_register(Data()->L, \"XblInitialize\", XblInitialize_Lua);\n    lua_register(Data()->L, \"XblGetScid\", XblGetScid_Lua);\n    lua_register(Data()->L, \"XblCleanupAsync\", XblCleanupAsync_Lua);\n    lua_register(Data()->L, \"XblMemSetFunctions\", XblMemSetFunctions_Lua);\n    lua_register(Data()->L, \"XblMemGetFunctions\", XblMemGetFunctions_Lua);\n    lua_register(Data()->L, \"XblDisableAssertsForXboxLiveThrottlingInDevSandboxes\", XblDisableAssertsForXboxLiveThrottlingInDevSandboxes_Lua);\n    lua_register(Data()->L, \"XblAddServiceCallRoutedHandler\", XblAddServiceCallRoutedHandler_Lua);\n    lua_register(Data()->L, \"XblRemoveServiceCallRoutedHandler\", XblRemoveServiceCallRoutedHandler_Lua);\n    lua_register(Data()->L, \"XblSetOverrideLocale\", XblSetOverrideLocale_Lua);\n\n    // errors_c.h\n    lua_register(Data()->L, \"XblGetErrorCondition\", XblGetErrorCondition_Lua);\n\n    // xbox_live_context_c.h\n    lua_register(Data()->L, \"XblContextCreateHandle\", XblContextCreateHandle_Lua);\n    lua_register(Data()->L, \"XblContextDuplicateHandle\", XblContextDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XblContextCloseHandle\", XblContextCloseHandle_Lua);\n    // TBD: XblContextGetUser\n    // TBD: XblContextGetXboxUserId\n\n    // xbox_live_context_settings_c.h\n    lua_register(Data()->L, \"XblContextSettingsGetLongHttpTimeout\", XblContextSettingsGetLongHttpTimeout_Lua);\n    lua_register(Data()->L, \"XblContextSettingsSetLongHttpTimeout\", XblContextSettingsSetLongHttpTimeout_Lua);\n    lua_register(Data()->L, \"XblContextSettingsGetHttpRetryDelay\", XblContextSettingsGetHttpRetryDelay_Lua);\n    lua_register(Data()->L, \"XblContextSettingsSetHttpRetryDelay\", XblContextSettingsSetHttpRetryDelay_Lua);\n    lua_register(Data()->L, \"XblContextSettingsGetHttpTimeoutWindow\", XblContextSettingsGetHttpTimeoutWindow_Lua);\n    lua_register(Data()->L, \"XblContextSettingsSetHttpTimeoutWindow\", XblContextSettingsSetHttpTimeoutWindow_Lua);\n    lua_register(Data()->L, \"XblContextSettingsGetWebsocketTimeoutWindow\", XblContextSettingsGetWebsocketTimeoutWindow_Lua);\n    lua_register(Data()->L, \"XblContextSettingsSetWebsocketTimeoutWindow\", XblContextSettingsSetWebsocketTimeoutWindow_Lua);\n    lua_register(Data()->L, \"XblContextSettingsGetUseCrossPlatformQosServers\", XblContextSettingsGetUseCrossPlatformQosServers_Lua);\n    lua_register(Data()->L, \"XblContextSettingsSetUseCrossPlatformQosServers\", XblContextSettingsSetUseCrossPlatformQosServers_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_achievement_unlock_notification.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#if HC_PLATFORM == HC_PLATFORM_WIN32\nnamespace xbl\n{\nnamespace apirunner\n{\n\nenum status\n{\n    OK = 0,\n    ERROR_NO_MSG\n};\n\nstatic status errorCode;\n\n\nHRESULT GetAchievementLockStatus(const std::string& id, bool& isLocked)\n{\n    LogToScreen(\"GetAchievement [%s]\", id.c_str());\n\n    CreateQueueIfNeeded();\n\n    std::unique_ptr<XAsyncBlock>    asyncBlock = std::make_unique<XAsyncBlock>();\n    \n    HRESULT hr = XblAchievementsGetAchievementAsync( Data()->xboxLiveContext,\n                                                     Data()->xboxUserId,\n                                                     Data()->scid,\n                                                     id.c_str(),\n                                                     asyncBlock.get());\n\n    // wait for get achievement to complete\n    XAsyncGetStatus(asyncBlock.get(), true);\n\n    XblAchievementsResultHandle resultHandle;\n\n    hr = XblAchievementsGetAchievementResult(asyncBlock.get(), &resultHandle);\n\n    if (hr < 0) \n    {\n        return hr;\n    }\n\n    const XblAchievement*   achievements = nullptr;\n    size_t                  achievementsCount = 0;\n\n    hr = XblAchievementsResultGetAchievements(resultHandle, &achievements, &achievementsCount);\n\n    LogToFile(\"Got achievementsCount: %d\", achievementsCount);\n\n    if (achievementsCount != 1)\n    {\n        return hr;\n    }\n\n    if (achievements[0].progressState == XblAchievementProgressState::Achieved)\n    {\n        isLocked = false;\n    }\n    else\n    {\n        isLocked = true;\n    }\n    \n    const char * state = (isLocked) ? \"Not achieved\" : \"Achieved\";\n    LogToScreen( \"Achievement id=[%s] name=[%s] state[%s]\",\n                 achievements[0].id,\n                 achievements[0].name,\n                 state);\n\n    return hr;\n}\n\n\nHRESULT UnlockAchievement(std::string id)\n{\n    LogToScreen(\"UnlockAchievement [%s]\", id.c_str());\n\n    CreateQueueIfNeeded();\n\n    std::unique_ptr<XAsyncBlock>    asyncBlock = std::make_unique<XAsyncBlock>();\n\n    \n    uint32_t percent = 100;\n    HRESULT hr =  XblAchievementsUpdateAchievementAsync( Data()->xboxLiveContext,\n                                                         Data()->xboxUserId,\n                                                         id.c_str(),\n                                                         percent,\n                                                         asyncBlock.get());\n\n    XAsyncGetStatus(asyncBlock.get(), true);\n\n    XblAchievementsResultHandle resultHandle;\n    hr = XblAchievementsGetAchievementResult(asyncBlock.get(), &resultHandle);\n\n    return hr;\n}\n\n\nvoid CALLBACK AchievementUnlockHandler(const XblAchievementUnlockEvent* args, void* context)\n{\n    UNREFERENCED_PARAMETER(context);\n    LogToScreen(\"Achievement Unlock Notification\");\n    LogToScreen(\"titleId: %u\", args->titleId);\n    LogToScreen(\"achievementName: %s\", args->achievementName);\n    LogToScreen(\"achievementIcon: %s\", args->achievementIcon);\n    LogToScreen(\"gamerscore: %u\", args->gamerscore);\n    LogToScreen(\"rarityPercentage: %f\", args->rarityPercentage);\n    LogToScreen(\"rarityCategory: %u\", static_cast<uint32_t>(args->rarityCategory));\n\n    errorCode = status::OK;\n}\n\n\nXblFunctionContext SetHandler()\n{\n    XblFunctionContext id = XblAchievementUnlockAddNotificationHandler(Data()->xboxLiveContext,\n        AchievementUnlockHandler,\n        nullptr);\n    return id;\n}\n\n\nvoid UnsetHandler(XblFunctionContext id)\n{\n    XblAchievementUnlockRemoveNotificationHandler(Data()->xboxLiveContext, id);\n}\n\n\nnamespace lua\n{\n    int XblAchievementUnlockAddNotificationHandler(lua_State *L)\n    {\n        auto id = SetHandler();\n        lua_pushinteger(L, id);\n        LuaReturnHR(L, S_OK, 1);\n        return 0;\n    }\n\n    int XblAchievementUnlockRemoveNotificationHandler(lua_State *L)\n    {\n        uint32_t id = GetUint32FromLua(L, 1, 0);\n        UnsetHandler(id);\n        return 0;\n    }\n\n    int RunAchievementUnlock(lua_State *L)\n    {\n        std::string achievementId = luaL_checkstring(L, 1);\n\n        HRESULT hr = 0;\n        errorCode = status::ERROR_NO_MSG;\n\n        Sleep(1000);\n\n        hr = UnlockAchievement(achievementId);\n\n        return LuaReturnHR(L, hr);\n    }\n\n\n    int Cleanup(lua_State *L)\n    {\n        uint32_t id = GetUint32FromLua(L, 1, 0);\n        LogToScreen(\"Got %d\", id);\n        UnsetHandler(id);\n        return 0;\n    }\n\n\n    int CheckStatus(lua_State *L)\n    {\n        lua_pushinteger(L, errorCode);\n        return 1;\n    }\n\n\n    int IsAchievementLocked(lua_State *L)\n    {\n        std::string achievementId = luaL_checkstring(L, 1);\n\n        bool isLocked = false;\n\n        HRESULT hr = GetAchievementLockStatus(achievementId, isLocked);\n\n        lua_pushboolean(L, isLocked);\n\n        return LuaReturnHR(L, hr, 1);\n    }\n\n}\n}\n}\n\n\nvoid SetupAPIs_XblAchievementUnlockNotification()\n{\n    lua_register(Data()->L, \"RunAchievementUnlock\", xbl::apirunner::lua::RunAchievementUnlock);\n    lua_register(Data()->L, \"Cleanup\", xbl::apirunner::lua::Cleanup);\n    lua_register(Data()->L, \"CheckStatus\", xbl::apirunner::lua::CheckStatus);\n    lua_register(Data()->L, \"IsAchievementLocked\", xbl::apirunner::lua::IsAchievementLocked);\n    lua_register(Data()->L, \"XblAchievementUnlockAddNotificationHandler\", xbl::apirunner::lua::XblAchievementUnlockAddNotificationHandler);\n    lua_register(Data()->L, \"XblAchievementUnlockRemoveNotificationHandler\", xbl::apirunner::lua::XblAchievementUnlockRemoveNotificationHandler);\n}\n\n#endif"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_achievements.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nstd::string AchievementProgressToString(XblAchievement achievement)\n{\n    std::stringstream stream;\n\n    if (achievement.progressState == XblAchievementProgressState::Achieved)\n    {\n        stream << \"Achieved (\" << achievement.progression.timeUnlocked << \")\";\n    }\n    else if (achievement.progressState == XblAchievementProgressState::InProgress)\n    {\n        stream << \"Started\";\n        stream << \"(\" << achievement.progression.requirements[0].currentProgressValue << \"/\" << achievement.progression.requirements[0].targetProgressValue << \")\";\n    }\n    else if (achievement.progressState == XblAchievementProgressState::NotStarted)\n    {\n        stream << \"Not Started\";\n    }\n    else if (achievement.progressState == XblAchievementProgressState::Unknown)\n    {\n        stream << \"Unknown\";\n    }\n\n    return stream.str();\n}\n\nXblAchievementType ConvertStringToXblAchievementType(const char* str)\n{\n    XblAchievementType type = XblAchievementType::Unknown;\n\n    if (pal::stricmp(str, \"XblAchievementType::Unknown\") == 0) type = XblAchievementType::Unknown;\n    else if (pal::stricmp(str, \"XblAchievementType::All\") == 0) type = XblAchievementType::All;\n    else if (pal::stricmp(str, \"XblAchievementType::Persistent\") == 0) type = XblAchievementType::Persistent;\n    else if (pal::stricmp(str, \"XblAchievementType::Challenge\") == 0) type = XblAchievementType::Challenge;\n\n    return type;\n}\n\nXblAchievementOrderBy ConvertStringToXblAchievementOrderBy(const char* str)\n{\n    XblAchievementOrderBy orderBy = XblAchievementOrderBy::DefaultOrder;\n\n    if (pal::stricmp(str, \"XblAchievementOrderBy::DefaultOrder\") == 0) orderBy = XblAchievementOrderBy::DefaultOrder;\n    else if (pal::stricmp(str, \"XblAchievementOrderBy::TitleId\") == 0) orderBy = XblAchievementOrderBy::TitleId;\n    else if (pal::stricmp(str, \"XblAchievementOrderBy::UnlockTime\") == 0) orderBy = XblAchievementOrderBy::UnlockTime;\n\n    return orderBy;\n}\n\n// commands\n\nint XblAchievementsResultGetAchievements_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblAchievementsResultGetAchievements\n    const XblAchievement* achievements;\n    size_t achievementsCount;\n    HRESULT hr = XblAchievementsResultGetAchievements(Data()->achievementsResult, &achievements, &achievementsCount);\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsResultGetAchievements: hr=%s\", ConvertHR(hr).c_str());\n\n    if (SUCCEEDED(hr))\n    {\n        std::stringstream stream;\n        for (uint32_t i = 0; i < achievementsCount; i++)\n        {\n            stream << \"\\t\" << achievements[i].name << \"(\" << AchievementProgressToString(achievements[i]) << \")\\n\";\n        }\n        LogToFile(stream.str().c_str());\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsResultHasNext_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblAchievementsResultHasNext\n    HRESULT hr = S_OK;\n    bool hasNext = false;\n    if (Data()->achievementsResult != nullptr)\n    {\n        hr = XblAchievementsResultHasNext(Data()->achievementsResult, &hasNext);\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsResultHasNext: hr=%s hasNext=%s\", ConvertHR(hr).c_str(), hasNext ? \"true\" : \"false\");\n\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblAchievementsResultGetNextAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    uint32_t maxItems = GetUint32FromLua(L, 1, 100);\n    LogToFile(\"XblAchievementsResultGetNextAsync: MaxItems: %d\", maxItems);\n\n    // CODE SNIPPET START: XblAchievementsResultGetNextAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblAchievementsResultHandle resultHandle;\n        auto hr = XblAchievementsResultGetNextResult(asyncBlock, &resultHandle);\n        LogToFile(\"XblAchievementsResultGetNextResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        if (SUCCEEDED(hr))\n        {\n            // CODE SKIP START\n            if (Data()->achievementsResult)\n            {\n                XblAchievementsResultCloseHandle(Data()->achievementsResult);\n            }\n            XblAchievementsResultDuplicateHandle(resultHandle, &Data()->achievementsResult);\n            // CODE SKIP END            \n            const XblAchievement* achievements = nullptr;\n            size_t achievementsCount = 0;\n            hr = XblAchievementsResultGetAchievements(resultHandle, &achievements, &achievementsCount);\n\n            LogToFile(\"OnXblAchievementsGetAchievementsForTitleIdAsync: Got achievementsCount: %d\", achievementsCount); // CODE SNIP SKIP\n            for (size_t i = 0; i < achievementsCount; i++)\n            {\n                LogToScreen(\"Achievement %s: %s = %s\",\n                    achievements[i].id,\n                    achievements[i].name,\n                    (achievements[i].progressState == XblAchievementProgressState::Achieved) ? \"Achieved\" : \"Not achieved\");\n            }\n\n            XblAchievementsResultCloseHandle(resultHandle); // when done with handle, close it\n            achievements = nullptr; // Clear array after calling XblAchievementsResultCloseHandle to pointer to freed memory\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblAchievementsResultGetNextAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblAchievementsResultGetNextAsync(\n        Data()->achievementsResult,\n        maxItems,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsResultGetNextAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsGetAchievementsForTitleIdAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    XblAchievementType achievementType = ConvertStringToXblAchievementType(GetStringFromLua(L, 1, \"XblAchievementType::All\").c_str());\n    bool unlockedOnly = GetBoolFromLua(L, 2, false);\n    XblAchievementOrderBy orderBy = ConvertStringToXblAchievementOrderBy(GetStringFromLua(L, 3, \"XblAchievementOrderBy::DefaultOrder\").c_str());\n    uint32_t skipItems = GetUint32FromLua(L, 4, 0);\n    uint32_t maxItems = GetUint32FromLua(L, 5, 100);\n\n    LogToFile(\"XblAchievementsGetAchievementsForTitleIdAsync: AchievementType: %d\", achievementType);\n    LogToFile(\"XblAchievementsGetAchievementsForTitleIdAsync: unlockedOnly: %s\", unlockedOnly ? \"true\" : \"false\");\n    LogToFile(\"XblAchievementsGetAchievementsForTitleIdAsync: OrderBy: %d\", orderBy);\n    LogToFile(\"XblAchievementsGetAchievementsForTitleIdAsync: SkipItems: %d\", skipItems);\n    LogToFile(\"XblAchievementsGetAchievementsForTitleIdAsync: MaxItems: %d\", maxItems);\n\n    // CODE SNIPPET START: XblAchievementsGetAchievementsForTitleIdAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n\n        XblAchievementsResultHandle resultHandle;\n        auto hr = XblAchievementsGetAchievementsForTitleIdResult(asyncBlock, &resultHandle);\n        LogToFile(\"XblAchievementsGetAchievementsForTitleIdResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        if (SUCCEEDED(hr))\n        {\n            // CODE SKIP START\n            if (Data()->achievementsResult)\n            {\n                XblAchievementsResultCloseHandle(Data()->achievementsResult);\n            }\n            XblAchievementsResultDuplicateHandle(resultHandle, &Data()->achievementsResult);\n            // CODE SKIP END            \n            const XblAchievement* achievements = nullptr;\n            size_t achievementsCount = 0;\n            hr = XblAchievementsResultGetAchievements(resultHandle, &achievements, &achievementsCount);\n\n            LogToFile(\"OnXblAchievementsGetAchievementsForTitleIdAsync: Got achievementsCount: %d\", achievementsCount); // CODE SNIP SKIP\n            for (size_t i = 0; i < achievementsCount; i++)\n            {\n                LogToScreen(\"Achievement %s: %s = %s\", \n                    achievements[i].id, \n                    achievements[i].name,\n                    (achievements[i].progressState == XblAchievementProgressState::Achieved) ? \"Achieved\" : \"Not achieved\");\n            }\n\n            XblAchievementsResultCloseHandle(resultHandle); // when done with handle, close it\n            achievements = nullptr; // Clear array after calling XblAchievementsResultCloseHandle to pointer to freed memory\n            // Instead you could not close the handle and store it.  Then \n            // if you needed to copy the handle, call XblAchievementsResultDuplicateHandle()\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblAchievementsGetAchievementsForTitleIdAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblAchievementsGetAchievementsForTitleIdAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        Data()->titleId,\n        achievementType,\n        unlockedOnly,\n        orderBy,\n        skipItems,\n        maxItems,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release(); \n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsGetAchievementsForTitleIdAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsResultCloseHandle_Lua(lua_State *L)\n{\n    if (Data()->achievementsResult)\n    {\n        XblAchievementsResultCloseHandle(Data()->achievementsResult);\n        Data()->achievementsResult = nullptr;\n    }\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblAchievementsGetAchievementAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto achievementId = GetStringFromLua(L, 1, \"1\");\n    LogToFile(\"XblAchievementsGetAchievementAsync: AchievementId: %s\", achievementId.c_str());\n\n    // CODE SNIPPET START: XblAchievementsGetAchievementAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblAchievementsResultHandle resultHandle;\n        auto hr = XblAchievementsGetAchievementResult(asyncBlock, &resultHandle);\n\n        LogToFile(\"XblAchievementsGetAchievementResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            // CODE SKIP START\n            if (Data()->achievementsResult)\n            {\n                XblAchievementsResultCloseHandle(Data()->achievementsResult);\n            }\n            XblAchievementsResultDuplicateHandle(resultHandle, &Data()->achievementsResult);\n            // CODE SKIP END\n            const XblAchievement* achievements = nullptr;\n            size_t achievementsCount = 0;\n            hr = XblAchievementsResultGetAchievements( resultHandle, &achievements, &achievementsCount );\n\n            for (size_t i = 0; i < achievementsCount; i++)\n            {\n                LogToScreen(\"Achievement %s: %s = %s\",\n                    achievements[i].id,\n                    achievements[i].name,\n                    (achievements[i].progressState == XblAchievementProgressState::Achieved) ? \"Achieved\" : \"Not achieved\");\n            }\n\n            XblAchievementsResultCloseHandle(resultHandle); // when done with handle, close it\n            achievements = nullptr; // Clear array after calling XblAchievementsResultCloseHandle to pointer to freed memory\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblAchievementsGetAchievementAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblAchievementsGetAchievementAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        Data()->scid,\n        achievementId.c_str(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsGetAchievementAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsUpdateAchievementAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto achievementId = GetStringFromLua(L, 1, \"1\");\n    uint32_t percentComplete = GetUint32FromLua(L, 2, 100);\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: AchievementId: %s\", achievementId.c_str());\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: PercentComplete: %d\", percentComplete);\n\n    // CODE SNIPPET START: XblAchievementsUpdateAchievementAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        auto result = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"XAsyncGetStatus: hr=%s\", ConvertHR(result).c_str()); // CODE SNIP SKIP\n        if (SUCCEEDED(result))\n        {\n            // Achievement updated\n        }\n        else if (result == HTTP_E_STATUS_NOT_MODIFIED)\n        {\n            // Achievement not modified\n        }\n        else\n        {\n            // Achievement failed to update\n        }\n        CallLuaFunctionWithHr(result, \"OnXblAchievementsUpdateAchievementAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblAchievementsUpdateAchievementAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        achievementId.c_str(),\n        percentComplete,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsUpdateAchievementAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsUpdateAchievementForTitleIdAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto achievementId = GetStringFromLua(L, 1, \"1\");\n    uint32_t percentComplete = GetUint32FromLua(L, 2, 100);\n    LogToFile(\"XblAchievementsGetAchievementAsync: AchievementId: %s\", achievementId.c_str());\n    LogToFile(\"XblAchievementsGetAchievementAsync: PercentComplete: %d\", percentComplete);\n\n    // CODE SNIPPET START: XblAchievementsUpdateAchievementForTitleIdAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        auto result = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"XAsyncGetStatus: hr=%s\", ConvertHR(result).c_str()); // CODE SNIP SKIP\n        if (SUCCEEDED(result))\n        {\n            // Achievement updated\n        }\n        else if (result == HTTP_E_STATUS_NOT_MODIFIED)\n        {\n            // Achievement not modified\n        }\n        else\n        {\n            // Achievement failed to update\n        }\n        CallLuaFunctionWithHr(result, \"OnXblAchievementsUpdateAchievementForTitleIdAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblAchievementsUpdateAchievementForTitleIdAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        Data()->titleId,\n        Data()->scid,\n        achievementId.c_str(),\n        percentComplete,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblAchievementsUpdateAchievementForTitleIdAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblAchievements()\n{\n    lua_register(Data()->L, \"XblAchievementsResultGetAchievements\", XblAchievementsResultGetAchievements_Lua);\n    lua_register(Data()->L, \"XblAchievementsResultGetNextAsync\", XblAchievementsResultGetNextAsync_Lua);\n    lua_register(Data()->L, \"XblAchievementsResultHasNext\", XblAchievementsResultHasNext_Lua);\n    lua_register(Data()->L, \"XblAchievementsResultCloseHandle\", XblAchievementsResultCloseHandle_Lua);\n    lua_register(Data()->L, \"XblAchievementsGetAchievementAsync\", XblAchievementsGetAchievementAsync_Lua);\n    lua_register(Data()->L, \"XblAchievementsGetAchievementsForTitleIdAsync\", XblAchievementsGetAchievementsForTitleIdAsync_Lua);\n    lua_register(Data()->L, \"XblAchievementsUpdateAchievementAsync\", XblAchievementsUpdateAchievementAsync_Lua);\n    lua_register(Data()->L, \"XblAchievementsUpdateAchievementForTitleIdAsync\", XblAchievementsUpdateAchievementForTitleIdAsync_Lua);    \n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_achievements_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include <chrono>\n\nstatic struct AchievementsManagerState\n{\n    // TODO move doWork logic into this state class\n    AchievementsManagerState() = default;\n    ~AchievementsManagerState()\n    {\n        // Validate that our tests cleaned up correctly\n        assert(!doWork);\n    }\n\n    std::thread doWorkThread{};\n    std::atomic<bool> doWork{ false };\n    std::atomic<bool> doWorkJoinWhenDone{ false };\n    XblAchievementsManagerResultHandle achievementsResultHandle{ nullptr };\n\n    HCMockCallHandle mockHandle{ nullptr };\n} achievementsState;\n\nHRESULT AchievementsManagerDoWork()\n{\n    const XblAchievementsManagerEvent* events{ nullptr };\n    size_t eventCount{ 0 };\n    HRESULT hr = XblAchievementsManagerDoWork(&events, &eventCount);\n    \n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    for (size_t i = 0; i < eventCount; ++i)\n    {\n        auto& achievementEvent = events[i];\n        // CODE SKIP START\n        static std::unordered_map<XblAchievementsManagerEventType, std::string> eventTypesMap\n        {\n            { XblAchievementsManagerEventType::AchievementProgressUpdated, \"AchievementProgressUpdated\" },\n            { XblAchievementsManagerEventType::AchievementUnlocked, \"AchievementUnlocked\" },\n            { XblAchievementsManagerEventType::LocalUserInitialStateSynced, \"LocalUserInitialStateSynced\" },\n        };\n        // CODE SKIP END\n\n        std::stringstream ss;\n        ss << \"XblAchievementsManagerDoWork: Event of type \" << eventTypesMap[achievementEvent.eventType] << std::endl;\n        LogToScreen(ss.str().c_str());\n\n        switch (achievementEvent.eventType)\n        {\n        case XblAchievementsManagerEventType::LocalUserInitialStateSynced:\n            LogToScreen(\"XblAchievementsManagerDoWork: LocalUserInitialStateSynced event\");\n            CallLuaFunctionWithHr(hr, \"OnXblAchievementsManagerDoWork_LocalUserAddedEvent\");\n            break;\n        case XblAchievementsManagerEventType::AchievementProgressUpdated:\n            LogToScreen(\"XblAchievementsManagerDoWork: AchievementProgressUpdated event\");\n            CallLuaFunctionWithHr(hr, \"OnXblAchievementsManagerDoWork_AchievementProgressUpdatedEvent\");\n            break;\n        case XblAchievementsManagerEventType::AchievementUnlocked:\n            LogToScreen(\"XblAchievementsManagerDoWork: AchievementUnlocked event\");\n            CallLuaFunctionWithHr(hr, \"OnXblAchievementsManagerDoWork_AchievementUnlockedEvent\");\n            break;\n        default:\n            break;\n        }\n\n    }\n    return hr;\n}\n\nint StartAchievementsManagerDoWorkLoop_Lua(lua_State* L)\n{\n    achievementsState.doWork = true;\n    achievementsState.doWorkJoinWhenDone = true;\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    achievementsState.doWorkThread = std::thread([]()\n        {\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n            JNIEnv* jniEnv = nullptr;\n\n            // This should be a background thread that MUST attach a new java thread.\n            Data()->javaVM->GetEnv(reinterpret_cast<void**>(&jniEnv), JNI_VERSION_1_6);\n            Data()->javaVM->AttachCurrentThread(&jniEnv, nullptr);\n\n#endif\n            Data()->m_achievementsDoWorkDone = false;\n            while (achievementsState.doWork && !Data()->m_quit)\n            {\n                {\n                    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n                    AchievementsManagerDoWork();\n                }\n                pal::Sleep(10);\n            }\n            Data()->m_achievementsDoWorkDone = true;\n            LogToScreen(\"Exiting do work thread\");\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n           Data()->javaVM->DetachCurrentThread();\n#endif\n        });\n    return LuaReturnHR(L, S_OK);\n}\n\nint StopAchievementsManagerDoWorkLoop_Lua(lua_State* L)\n{\n    LogToScreen(\"StopAchievementsManagerDoWorkLoop_Lua\");\n    achievementsState.doWorkJoinWhenDone = true;\n    achievementsState.doWork = false;\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid StopAchievementsManagerDoWorkHelper()\n{\n    if (achievementsState.doWorkJoinWhenDone)\n    {\n        achievementsState.doWork = false;\n        achievementsState.doWorkJoinWhenDone = false;\n        achievementsState.doWorkThread.join();\n    }\n}\n\nint SetupAchievementsManagerPerformanceTestMock_Lua(lua_State *L)\n{\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    std::string addUserMockResponse = ReadFile(\"PerformanceTestMockResponse.json\");\n#else\n    std::string addUserMockResponse = ReadFile(\"achievements\\\\PerformanceTestMockResponse.json\");\n#endif\n    assert(!addUserMockResponse.empty());\n    \n    auto hr = HCMockCallCreate(&achievementsState.mockHandle);\n    assert(SUCCEEDED(hr));\n\n    hr = HCMockAddMock(achievementsState.mockHandle, \"GET\", \"https://achievements.xboxlive.com\", nullptr, 0);\n    assert(SUCCEEDED(hr));\n\n    hr = HCMockResponseSetStatusCode(achievementsState.mockHandle, 200);\n    assert(SUCCEEDED(hr));\n\n    std::vector<uint8_t> bodyBytes{ addUserMockResponse.begin(), addUserMockResponse.end() };\n    hr = HCMockResponseSetResponseBodyBytes(achievementsState.mockHandle, bodyBytes.data(), static_cast<uint32_t>(bodyBytes.size()));\n    assert(SUCCEEDED(hr));\n\n    return LuaReturnHR(L, hr);\n}\n\n// commands\n\n// handles\n\nint XblAchievementsManagerResultGetAchievements_Lua(lua_State *L)\n{\n    auto resultHandle{ reinterpret_cast<XblAchievementsManagerResultHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(achievementsState.achievementsResultHandle))) };\n    if (resultHandle != nullptr) // might be null if original call fails\n    {\n        // CODE SNIPPET START: XblAchievementsManagerResultGetAchievements_C\n        const XblAchievement* achievements = nullptr;\n        uint64_t achievementsCount = 0;\n        HRESULT hr = XblAchievementsManagerResultGetAchievements(resultHandle, &achievements, &achievementsCount);\n\n        LogToScreen(\"Got %u Achievements:\", achievementsCount);\n        // CODE SNIPPET END\n        lua_pushinteger(L, static_cast<lua_Integer>(achievementsCount));\n        LogToScreen(\"XblAchievementsManagerResultGetAchievements: hr=%s\", ConvertHR(hr).c_str());\n        return LuaReturnHR(L, hr, 1);\n    }\n    else\n    {\n        HRESULT hr = S_OK;\n        lua_pushinteger(L, static_cast<lua_Integer>(0));\n        LogToScreen(\"XblAchievementsManagerResultGetAchievements: hr=%s\", ConvertHR(hr).c_str());\n        return LuaReturnHR(L, hr, 1);\n    }\n\n}\n\nint XblAchievementsManagerResultDuplicateHandle_Lua(lua_State *L)\n{\n    auto resultHandle{ reinterpret_cast<XblAchievementsManagerResultHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(achievementsState.achievementsResultHandle))) };\n    // CODE SNIPPET START: XblAchievementsRelationshipResultDuplicateHandle_C\n    XblAchievementsManagerResultHandle handle{};\n    XblAchievementsManagerResultDuplicateHandle(resultHandle, &handle);\n    // CODE SNIPPET END\n\n    XblAchievementsManagerResultCloseHandle(handle);\n    LogToScreen(\"XblAchievementsManagerResultDuplicateHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblAchievementsManagerResultCloseHandle_Lua(lua_State *L)\n{\n    auto resultHandle{ reinterpret_cast<XblAchievementsManagerResultHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(achievementsState.achievementsResultHandle))) };\n    // CODE SNIPPET START: XblAchievementsRelationshipResultCloseHandle_C\n    if (resultHandle == achievementsState.achievementsResultHandle)\n    {\n        achievementsState.achievementsResultHandle = nullptr;\n    }\n    XblAchievementsManagerResultCloseHandle(resultHandle);\n    // CODE SNIPPET END\n    LogToScreen(\"XblAchievementsManagerResultCloseHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\n// manager \n\nint XblAchievementsManagerAddLocalUser_Lua(lua_State *L)\n{\n    XalUserHandle user = Data()->xalUser;\n    \n    HRESULT hr = XblAchievementsManagerAddLocalUser(user, nullptr);\n\n    LogToScreen(\"XblAchievementsManagerAddLocalUser: %s\", ConvertHR(hr).c_str(), nullptr);\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsManagerRemoveLocalUser_Lua(lua_State *L)\n{\n    XalUserHandle user = Data()->xalUser;\n\n    HRESULT hr = XblAchievementsManagerRemoveLocalUser(user);\n\n    LogToScreen(\"XblAchievementsManagerAddLocalUser: %s\", ConvertHR(hr).c_str(), nullptr);\n    return LuaReturnHR(L, hr);\n}\n\nint XblAchievementsManagerGetAchievement_Lua(lua_State *L)\n{\n    auto achievementId{ GetStringFromLua(L, 1, \"1\") };\n    \n    HRESULT hr = XblAchievementsManagerGetAchievement(Data()->xboxUserId, achievementId.c_str(), &achievementsState.achievementsResultHandle);\n    if (FAILED(hr))\n    {\n        lua_pushinteger(L, 0);\n        return LuaReturnHR(L, hr, 1);\n    }\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(achievementsState.achievementsResultHandle));\n\n    LogToScreen(\"XblAchievementsManagerGetAchievement: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblAchievementsManagerGetAchievements_Lua(lua_State *L)\n{\n    HRESULT hr = XblAchievementsManagerGetAchievements(\n        Data()->xboxUserId,\n        XblAchievementOrderBy::DefaultOrder,\n        XblAchievementsManagerSortOrder::Unsorted,\n        &achievementsState.achievementsResultHandle);\n    \n    if (FAILED(hr))\n    {\n        lua_pushinteger(L, 0);\n        return LuaReturnHR(L, hr, 1);\n    }\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(achievementsState.achievementsResultHandle));\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblAchievementsManagerGetAchievementsPerfTest_Lua(lua_State *L)\n{\n    auto startTime = std::chrono::high_resolution_clock::now();\n    HRESULT hr = XblAchievementsManagerGetAchievements(\n        Data()->xboxUserId, \n        XblAchievementOrderBy::DefaultOrder,\n        XblAchievementsManagerSortOrder::Unsorted,\n        &achievementsState.achievementsResultHandle);\n    auto endTime = std::chrono::high_resolution_clock::now();\n    \n    if (FAILED(hr))\n    {\n        lua_pushinteger(L, 0);\n        return LuaReturnHR(L, hr, 1);\n    }\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(achievementsState.achievementsResultHandle));\n    \n    std::chrono::duration<double> duration = endTime - startTime;\n    LogToScreen(\"XblAchievementsManagerGetAchievements: %s\", ConvertHR(hr).c_str());\n    LogToScreen(\"XblAchievementsManagerGetAchievements Performance Test Duration: %f milliseconds\", duration.count() * 1000);\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblAchievementsManagerGetAchievementsByState_Lua(lua_State *L)\n{\n    HRESULT hr = XblAchievementsManagerGetAchievementsByState(\n        Data()->xboxUserId,\n        XblAchievementOrderBy::DefaultOrder,\n        XblAchievementsManagerSortOrder::Unsorted,\n        XblAchievementProgressState::Achieved,\n        &achievementsState.achievementsResultHandle\n    );\n    if (FAILED(hr))\n    {\n        return LuaReturnHR(L, hr, 1);\n    }\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(achievementsState.achievementsResultHandle));\n\n    LogToScreen(\"XblAchievementsManagerGetAchievementsByState: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblAchievementsManagerUpdateAchievement_Lua(lua_State *L)\n{\n    auto achievementId{ GetStringFromLua(L, 1, \"1\") };\n    uint8_t newProgress{ static_cast<uint8_t>(GetUint32FromLua(L, 2, 100)) };\n\n    HRESULT hr = XblAchievementsManagerUpdateAchievement(Data()->xboxUserId, achievementId.c_str(), newProgress);\n    LogToScreen(\"XblAchievementsManagerUpdateAchievement: %s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblAchievementsManager()\n{\n    // Non XSAPI APIs\n    lua_register(Data()->L, \"StartAchievementsManagerDoWorkLoop\", StartAchievementsManagerDoWorkLoop_Lua);\n    lua_register(Data()->L, \"StopAchievementsManagerDoWorkLoop\", StopAchievementsManagerDoWorkLoop_Lua);\n    lua_register(Data()->L, \"SetupAchievementsManagerPerformanceTestMock\", SetupAchievementsManagerPerformanceTestMock_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerGetAchievementsPerfTest\", XblAchievementsManagerGetAchievementsPerfTest_Lua);\n\n    // XSAPI APIs\n    lua_register(Data()->L, \"XblAchievementsManagerAddLocalUser\", XblAchievementsManagerAddLocalUser_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerRemoveLocalUser\", XblAchievementsManagerRemoveLocalUser_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerGetAchievement\", XblAchievementsManagerGetAchievement_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerGetAchievements\", XblAchievementsManagerGetAchievements_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerGetAchievementsByState\", XblAchievementsManagerGetAchievementsByState_Lua);\n    \n    lua_register(Data()->L, \"XblAchievementsManagerResultGetAchievements\", XblAchievementsManagerResultGetAchievements_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerResultDuplicateHandle\", XblAchievementsManagerResultDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XblAchievementsManagerResultCloseHandle\", XblAchievementsManagerResultCloseHandle_Lua);\n\n    lua_register(Data()->L, \"XblAchievementsManagerUpdateAchievement\", XblAchievementsManagerUpdateAchievement_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_achievements_progress_notification.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nstd::string ConvertXblAchievementProgressStateToString(XblAchievementProgressState state)\n{\n    std::string stateStr;\n    switch (state)\n    {\n    case XblAchievementProgressState::Unknown:\n        stateStr = \"XblAchievementProgressState::Unknown\";\n    case XblAchievementProgressState::Achieved:\n        stateStr = \"XblAchievementProgressState::Achieved\";\n    case XblAchievementProgressState::NotStarted:\n        stateStr = \"XblAchievementProgressState::NotStarted\";\n    case XblAchievementProgressState::InProgress:\n        stateStr = \"XblAchievementProgressState::InProgress\";\n    }\n    return stateStr;\n}\n\nint XblAchievementsAddAchievementProgressChangeHandler_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    void* context = nullptr;\n    auto xblContext = Data()->xboxLiveContext;\n    XblFunctionContext achievementProgressContext = XblAchievementsAddAchievementProgressChangeHandler(\n        xblContext,\n        [](_In_ const XblAchievementProgressChangeEventArgs* args, _In_opt_ void*)\n        {\n            LogToScreen(\"XblAchievementsAddAchievementProgressChangeHandler\");\n            for (uint32_t progressIndex = 0; progressIndex < args->entryCount; ++progressIndex)\n            {\n                \n                LogToScreen(\"Achievement ID:\");\n                LogToScreen(args->updatedAchievementEntries[progressIndex].achievementId);\n                LogToScreen(\"Achievement State:\");\n                LogToScreen(ConvertXblAchievementProgressStateToString(args->updatedAchievementEntries[progressIndex].progressState).c_str());\n                for (uint32_t requirementIndex = 0; requirementIndex < args->updatedAchievementEntries[progressIndex].progression.requirementsCount; ++requirementIndex)\n                {\n                    char response[256];\n                    SPRINTF(response, 256, \"Achievement Requirement %u\", requirementIndex);\n                    LogToScreen(response);\n                    LogToScreen(\"Requirement Id:\");\n                    LogToScreen(args->updatedAchievementEntries[progressIndex].progression.requirements[requirementIndex].id);\n                    LogToScreen(\"Requirement Progress:\");\n                    LogToScreen(args->updatedAchievementEntries[progressIndex].progression.requirements[requirementIndex].currentProgressValue);\n                }\n            }\n            CallLuaFunctionWithHr(S_OK, \"OnXblAchievementsAddAchievementProgressHandler\");\n        },\n        context\n    );\n\n    Data()->m_achievementProgressNotificationFunctionContext = achievementProgressContext;\n    LogToScreen(\"XblAchievementsAddAchievementProgressChangeHandler: done\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblAchievementsRemoveAchievementProgressChangeHandler_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    \n    XblAchievementsRemoveAchievementProgressChangeHandler(Data()->xboxLiveContext, Data()->m_achievementProgressNotificationFunctionContext);\n    Data()->m_achievementProgressNotificationFunctionContext = 0;\n\n    LogToScreen(\"XblAchievementsRemoveAchievementProgressChangeHandler: done\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\n\nvoid SetupAPIs_XblAchievementsProgressNotifications()\n{\n    lua_register(Data()->L, \"XblAchievementsAddAchievementProgressChangeHandler\", XblAchievementsAddAchievementProgressChangeHandler_Lua);\n    lua_register(Data()->L, \"XblAchievementsRemoveAchievementProgressChangeHandler\", XblAchievementsRemoveAchievementProgressChangeHandler_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_events.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n#include <Shlwapi.h>\n#endif\n\nint XblEventsWriteInGameEvent_Lua(lua_State *L)\n{\n#if HC_PLATFORM != HC_PLATFORM_XDK\n    auto eventName = GetStringFromLua(L, 1, \"PuzzleSolved\");\n    auto dimensionsJson = GetStringFromLua(L, 2, \"{\\\"DifficultyLevelId\\\":100,\\\"EnemyRoleId\\\":3,\\\"GameplayModeId\\\":\\\"gameplay mode id\\\",\\\"KillTypeId\\\":4,\\\"MultiplayerCorrelationId\\\":\\\"multiplayer correlation id\\\",\\\"PlayerRoleId\\\":1,\\\"PlayerWeaponId\\\":2,\\\"RoundId\\\":1}\");\n    auto measurementsJson = GetStringFromLua(L, 3, \"{\\\"LocationX\\\":1,\\\"LocationY\\\":2.12121,\\\"LocationZ\\\":-90909093}\");\n\n    HRESULT hr = XblEventsWriteInGameEvent(\n        Data()->xboxLiveContext,\n        eventName.c_str(),\n        dimensionsJson.c_str(),\n        measurementsJson.c_str()\n    );\n\n    LogToFile(\"XblEventsWriteInGameEvent: hr=%s\", ConvertHR(hr).c_str());\n#else\n    HRESULT hr = S_OK;\n#endif\n\n    return LuaReturnHR(L, hr);\n}\n\nint ValidateOfflineEventsDirectoryFileExistsAndDelete_Lua(lua_State *L)\n{\n    HRESULT hr = S_OK;\n\n    // Location of the offline events file is not exposed from XSAPI. We could hard code\n    // it here but it may not always be the same, depending on platform\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    char pathArray[MAX_PATH + 1];\n    GetCurrentDirectoryA(MAX_PATH + 1, pathArray);\n    std::string path{ pathArray };\n    std::string searchPath{ path + \"\\\\XblEvents*\" };\n\n    WIN32_FIND_DATAA fd{};\n    HANDLE hFind = FindFirstFileA(searchPath.data(), &fd);\n    if (hFind != INVALID_HANDLE_VALUE)\n    {\n        do\n        {\n            DeleteFileA(std::string{ path + \"\\\\\" + fd.cFileName }.data());\n        } while (FindNextFileA(hFind, &fd));\n    }\n    else\n    {\n        hr = E_FAIL;\n    }\n#endif\n    LogToFile(\"Validating that XblEvents.dir exists: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblEvents()\n{\n    lua_register(Data()->L, \"XblEventsWriteInGameEvent\", XblEventsWriteInGameEvent_Lua);\n    lua_register(Data()->L, \"ValidateOfflineEventsDirectoryFileExistsAndDelete\", ValidateOfflineEventsDirectoryFileExistsAndDelete_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_gameinvite_notifications.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n\nint XblGameInviteAddNotificationHandler_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblGameInviteAddNotificationHandler\n    void* context = nullptr;\n    auto t = Data()->xboxLiveContext;\n    XblFunctionContext gameinviteFunctionContext = XblGameInviteAddNotificationHandler(\n        t,\n        [](_In_ const XblGameInviteNotificationEventArgs* args, _In_opt_ void*)\n        {\n            LogToScreen(\"XblGameInviteAddNotificationHandler\");\n            LogToScreen(\"Invite Handle ID:\");\n            LogToScreen(args->inviteHandleId);\n            LogToScreen(\"Invite Protocol:\");\n            LogToScreen(args->inviteProtocol);\n            LogToScreen(\"Invite Context:\");\n            LogToScreen(args->inviteContext);\n            LogToScreen(\"Sender Gamertag:\");\n            LogToScreen(args->senderGamertag);\n            LogToScreen(\"Modern Gamertag:\");\n            LogToScreen(args->senderModernGamertag);\n            LogToScreen(\"Modern Gamertag Suffix:\");\n            LogToScreen(args->senderModernGamertagSuffix);\n            LogToScreen(\"Unique Modern Gamertag:\");\n            LogToScreen(args->senderUniqueModernGamertag);\n            LogToScreen(\"Sender Gamertag:\");\n            LogToScreen(args->senderGamertag);\n            LogToScreen(\"Sender Image URL:\");\n            LogToScreen(args->senderImageUrl);\n            std::string s2 = std::to_string(args->senderXboxUserId);\n            LogToScreen(\"Sender Xbox User ID:\");\n            LogToScreen(s2.c_str());\n            CallLuaFunctionWithHr(S_OK, \"OnXblGameInviteAddNotificationHandler\"); // CODE SNIP SKIP\n        },\n        context\n    );\n    // CODE SNIPPET END\n    \n    Data()->gameInviteNotificationFunctionContext = gameinviteFunctionContext;\n\n    LogToScreen(\"XblGameInviteAddNotificationHandler: done\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblGameInviteRemoveNotificationHandler_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblGameInviteRemoveNotificationHandler\n    XblGameInviteRemoveNotificationHandler(\n        Data()->xboxLiveContext,\n        Data()->gameInviteNotificationFunctionContext\n    );\n    Data()->gameInviteNotificationFunctionContext = 0;\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblGameInviteRemoveNotificationHandler: done\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblGameInviteRegisterForEventAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblGameInviteRegisterForEventAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblRealTimeActivitySubscriptionHandle subscriptionHandle{ nullptr };\n        HRESULT hr = XblGameInviteRegisterForEventResult(asyncBlock, &subscriptionHandle);\n        Data()->gameInviteNotificationSubscriptionHandle = subscriptionHandle; // CODE SNIP SKIP\n        \n        LogToFile(\"XblGameInviteRegisterForEventResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblGameInviteRegisterForEventAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblGameInviteRegisterForEventAsync(\n        Data()->xboxLiveContext,\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblGameInviteRegisterForEventAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblGameInviteUnregisterForEventAsync_Lua(lua_State *L)\n{\n    XblRealTimeActivitySubscriptionHandle subscriptionHandle{ nullptr };\n    if (Data()->gameInviteNotificationSubscriptionHandle)\n    {\n        subscriptionHandle = Data()->gameInviteNotificationSubscriptionHandle;\n    }\n\n    if (subscriptionHandle)\n    {\n        // CODE SNIPPET START: XblGameInviteUnregisterForEventAsync\n        auto asyncBlock = std::make_unique<XAsyncBlock>();\n        asyncBlock->queue = Data()->queue;\n        asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n        {\n            std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n            HRESULT hr = XAsyncGetStatus(asyncBlock, true);\n            Data()->gameInviteNotificationSubscriptionHandle = nullptr; // CODE SNIP SKIP\n\n            LogToFile(\"XblGameInviteUnregisterForEventAsync Result: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n            CallLuaFunctionWithHr(hr, \"OnXblGameInviteUnregisterForEventAsync\"); // CODE SNIP SKIP\n        };\n\n        HRESULT hr = XblGameInviteUnregisterForEventAsync(Data()->xboxLiveContext, subscriptionHandle, asyncBlock.get());\n\n        if (SUCCEEDED(hr))\n        {\n            // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n            // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n            asyncBlock.release();\n        }\n        // CODE SNIPPET END\n        LogToScreen(\"XblGameInviteUnregisterForEventAsync: hr=%s\", ConvertHR(hr).c_str());\n    }\n\n    LogToScreen(\"XblGameInviteUnregisterForEventAsync: done\");\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupupAPIs_XblGameInviteNotifications()\n{\n    lua_register(Data()->L, \"XblGameInviteAddNotificationHandler\", XblGameInviteAddNotificationHandler_Lua);\n    lua_register(Data()->L, \"XblGameInviteRemoveNotificationHandler\", XblGameInviteRemoveNotificationHandler_Lua);\n    lua_register(Data()->L, \"XblGameInviteRegisterForEventAsync\", XblGameInviteRegisterForEventAsync_Lua);\n    lua_register(Data()->L, \"XblGameInviteUnregisterForEventAsync\", XblGameInviteUnregisterForEventAsync_Lua);\n}\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_grts.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include <XGameUI.h>\n#endif\n\nHRESULT XGameUiShowSendGameInviteAsyncHelper(\n    const std::string& sessionTemplateName,\n    const std::string& sessionId,\n    const std::string& inviteText,\n    const std::string& customActivationContext\n)\n{\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XGameUiShowSendGameInviteResult(asyncBlock);\n        CallLuaFunctionWithHr(hr, \"OnXGameUiShowSendGameInviteAsync\");\n    };\n\n    HRESULT hr = XGameUiShowSendGameInviteAsync(asyncBlock.get(), \n        Data()->xalUser, \n        Data()->scid,\n        sessionTemplateName.c_str(), \n        sessionId.c_str(),\n        inviteText.c_str(),\n        customActivationContext.c_str()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n#else \n    UNREFERENCED_PARAMETER(sessionTemplateName);\n    UNREFERENCED_PARAMETER(sessionId);\n    UNREFERENCED_PARAMETER(inviteText);\n    UNREFERENCED_PARAMETER(customActivationContext);\n    HRESULT hr = S_OK;\n#endif\n    return hr;\n}\n\nint XGameUiShowSendGameInviteAsyncToMPMLobby_Lua(lua_State* L)\n{\n    std::string inviteText = GetStringFromLua(L, 1, \"//MPSD/custominvitestrings_JoinMyGame\");\n    std::string customActivationContext = GetStringFromLua(L, 2, \"MyCustomActivationContext\");\n\n    XblMultiplayerSessionReference sessionReference{};\n    HRESULT hr = XblMultiplayerManagerLobbySessionSessionReference(&sessionReference);\n\n    hr = XGameUiShowSendGameInviteAsyncHelper(\n        sessionReference.SessionTemplateName,\n        sessionReference.SessionName, \n        inviteText, \n        customActivationContext);\n    return LuaReturnHR(L, hr);\n}\n\nint XGameUiShowSendGameInviteAsync_Lua(lua_State* L)\n{\n    std::string sessionTemplateName = GetStringFromLua(L, 1, \"MinGameSession\");\n    std::string sessionId = GetStringFromLua(L, 2, \"GameSession-0\");\n    std::string inviteText = GetStringFromLua(L, 3, \"Join Me In My Game!\");\n    std::string customActivationContext = GetStringFromLua(L, 4, \"MyCustomActivationContext\");\n\n    HRESULT hr = XGameUiShowSendGameInviteAsyncHelper(sessionTemplateName, sessionId, inviteText, customActivationContext);\n    return LuaReturnHR(L, hr);\n}\n\nint XGameUiShowMultiplayerActivityGameInviteAsync_Lua(lua_State* L)\n{\n#if HC_PLATFORM == HC_PLATFORM_GDK\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        //HRESULT hr = XGameUiShowMultiplayerActivityGameInviteResult(asyncBlock);\n        HRESULT hr = E_NOTIMPL; // requires GDK 2203+\n        CallLuaFunctionWithHr(hr, \"OnXGameUiShowMultiplayerActivityGameInviteAsync\");\n    };\n\n    //HRESULT hr = XGameUiShowMultiplayerActivityGameInviteAsync(asyncBlock.get(), Data()->xalUser);\n    HRESULT hr = E_NOTIMPL; // requires GDK 2203+\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n#else \n    HRESULT hr = S_OK;\n#endif\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_GRTS()\n{\n    lua_register(Data()->L, \"XGameUiShowMultiplayerActivityGameInviteAsync\", XGameUiShowMultiplayerActivityGameInviteAsync_Lua);\n    lua_register(Data()->L, \"XGameUiShowSendGameInviteAsync\", XGameUiShowSendGameInviteAsync_Lua);\n    lua_register(Data()->L, \"XGameUiShowSendGameInviteAsyncToMPMLobby\", XGameUiShowSendGameInviteAsyncToMPMLobby_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXblSocialGroupType ConvertStringToXblSocialGroupType(const char* str)\n{\n    XblSocialGroupType type = XblSocialGroupType::None;\n\n    if (pal::stricmp(str, \"XblSocialGroupType::None\") == 0) type = XblSocialGroupType::None;\n    else if (pal::stricmp(str, \"XblSocialGroupType::People\") == 0) type = XblSocialGroupType::People;\n    else if (pal::stricmp(str, \"XblSocialGroupType::Favorites\") == 0) type = XblSocialGroupType::Favorites;\n\n    return type;\n}\n\nXblLeaderboardSortOrder ConvertStringToXblLeaderboardSortOrder(const char* str)\n{\n    XblLeaderboardSortOrder type = XblLeaderboardSortOrder::Descending;\n\n    if (pal::stricmp(str, \"XblLeaderboardSortOrder::Descending\") == 0) type = XblLeaderboardSortOrder::Descending;\n    else if (pal::stricmp(str, \"XblLeaderboardSortOrder::Ascending\") == 0) type = XblLeaderboardSortOrder::Ascending;\n\n    return type;\n}\n\nXblLeaderboardQueryType ConvertStringToXblLeaderboardQueryType(const std::string& queryType)\n{\n    if (queryType == \"XblLeaderboardQueryType::TitleManagedStatBackedGlobal\")\n    {\n        return XblLeaderboardQueryType::TitleManagedStatBackedGlobal;\n    }\n    else if (queryType == \"XblLeaderboardQueryType::TitleManagedStatBackedSocial\")\n    {\n        return XblLeaderboardQueryType::TitleManagedStatBackedSocial;\n    }\n    else\n    {\n        return XblLeaderboardQueryType::UserStatBacked;\n    }\n}\n\nint XblLeaderboardGetLeaderboardAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto leaderboardName = GetStringFromLua(L, 1, \"TotalPuzzlesSolvedLB\");\n    auto statName = GetStringFromLua(L, 2, \"\");\n    XblSocialGroupType socialGroup = ConvertStringToXblSocialGroupType(GetStringFromLua(L, 3, \"XblSocialGroupType::None\").c_str());\n    auto queryType = ConvertStringToXblLeaderboardQueryType(GetStringFromLua(L, 4, \"XblLeaderboardQueryType::UserStatBacked\"));\n    XblLeaderboardSortOrder order = ConvertStringToXblLeaderboardSortOrder(GetStringFromLua(L, 5, \"XblLeaderboardSortOrder::Descending\").c_str());\n    auto scid = GetStringFromLua(L, 6, Data()->scid);\n    auto xboxUserId = GetUint64FromLua(L, 7, Data()->xboxUserId);\n    uint32_t maxItems = GetUint32FromLua(L, 8, 0);\n    uint64_t skipToXboxUserId = GetUint64FromLua(L, 9, 0);\n    uint32_t skipResultToRank = GetUint32FromLua(L, 10, 0);\n\n    // _Field_z_ const char** additionalColumnleaderboardNames;\n    // size_t additionalColumnleaderboardNamesCount;\n\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: xboxUserId: %d\", xboxUserId);\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: scid: %s\", scid.c_str());\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: leaderboardName: %s\", leaderboardName.c_str());\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: statName: %s\", statName.c_str());\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: maxItems: %d\", maxItems);\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: skipToXboxUserId: %d\", skipToXboxUserId);\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: skipResultToRank: %d\", skipResultToRank);\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: socialGroup: %d\", socialGroup);\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: order: %d\", order);\n\n    // CODE SNIPPET START: XblLeaderboardGetLeaderboardAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblLeaderboardGetLeaderboardResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            Data()->leaderboardBuffer.resize(resultSize);\n            XblLeaderboardResult* leaderboard{};\n\n            hr = XblLeaderboardGetLeaderboardResult(asyncBlock, resultSize, Data()->leaderboardBuffer.data(), &leaderboard, nullptr);\n            LogToFile(\"XblLeaderboardGetLeaderboardResult: %s columnsCount=%d rowsCount=%d\", ConvertHR(hr).c_str(), leaderboard->columnsCount, leaderboard->rowsCount); // CODE SNIP SKIP\n\n            if (SUCCEEDED(hr))\n            {\n                // Use XblLeaderboardResult in result\n                LogToScreen(\"Got %d rows in leaderboard\", leaderboard->rowsCount); // CODE SNIP SKIP\n                for (auto row = 0u; row < leaderboard->rowsCount; ++row)\n                {\n                    std::stringstream rowText;\n                    rowText << leaderboard->rows[row].xboxUserId << \"\\t\";\n\n                    for (auto column = 0u; column < leaderboard->rows[row].columnValuesCount; ++column)\n                    {\n                        // Each column value is in JSON format\n                        rowText << leaderboard->rows[row].columnValues[column] << \"\\t\";\n                    }\n                    LogToFile(rowText.str().data()); // CODE SNIP SKIP\n                }\n                Data()->leaderboardResult = leaderboard; // CODE SNIP SKIP\n            }\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblLeaderboardGetLeaderboardAsync\"); // CODE SNIP SKIP\n    };\n\n    XblLeaderboardQuery leaderboardQuery = {}; \n    pal::strcpy(leaderboardQuery.scid, sizeof(leaderboardQuery.scid), scid.c_str()); \n    leaderboardQuery.leaderboardName = leaderboardName.empty() ? nullptr : leaderboardName.c_str();\n    // See below on more options in XblLeaderboardQuery\n    leaderboardQuery.xboxUserId = xboxUserId; // CODE SNIP SKIP\n    leaderboardQuery.statName = statName.c_str(); // CODE SNIP SKIP\n    leaderboardQuery.maxItems = maxItems; // CODE SNIP SKIP\n    leaderboardQuery.skipToXboxUserId = skipToXboxUserId; // CODE SNIP SKIP\n    leaderboardQuery.skipResultToRank = skipResultToRank; // CODE SNIP SKIP\n    leaderboardQuery.socialGroup = socialGroup; // CODE SNIP SKIP\n    leaderboardQuery.order = order; // CODE SNIP SKIP\n    leaderboardQuery.queryType = queryType; // CODE SNIP SKIP\n\n    HRESULT hr = XblLeaderboardGetLeaderboardAsync(\n        Data()->xboxLiveContext,\n        leaderboardQuery,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblLeaderboardResultHasNext_Lua(lua_State *L)\n{\n    HRESULT hr = S_OK;\n    bool hasNext = false;\n    if (Data()->leaderboardResult != nullptr)\n    {\n        hasNext = Data()->leaderboardResult->hasNext;\n    }\n\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblLeaderboardResultGetNextAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    uint32_t maxItems = GetUint32FromLua(L, 1, 0);\n    LogToFile(\"XblLeaderboardGetLeaderboardAsync: maxItems: %d\", maxItems);\n\n    // CODE SNIPPET START: XblLeaderboardResultGetNextAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblLeaderboardResultGetNextResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            Data()->leaderboardBuffer.resize(resultSize);\n            XblLeaderboardResult* result{};\n\n            hr = XblLeaderboardResultGetNextResult(asyncBlock, resultSize, Data()->leaderboardBuffer.data(), &result, nullptr);\n            // Use result to read the leaderboard results\n            // CODE SKIP START\n            LogToFile(\"XblLeaderboardResultGetNextResult: %s columnsCount=%d rowsCount=%d\", ConvertHR(hr).c_str(), result->columnsCount, result->rowsCount);\n            LogToScreen(\"LeaderboardName = %s\", result->nextQuery.leaderboardName);\n\n            Data()->leaderboardResult = result; \n            // CODE SKIP END\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblLeaderboardResultGetNextAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblLeaderboardResultGetNextAsync(\n        Data()->xboxLiveContext,\n        Data()->leaderboardResult,\n        maxItems,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblLeaderboardResultGetNextAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblLeaderboard()\n{\n    lua_register(Data()->L, \"XblLeaderboardGetLeaderboardAsync\", XblLeaderboardGetLeaderboardAsync_Lua);\n    lua_register(Data()->L, \"XblLeaderboardResultGetNextAsync\", XblLeaderboardResultGetNextAsync_Lua);\n    lua_register(Data()->L, \"XblLeaderboardResultHasNext\", XblLeaderboardResultHasNext_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_multiplayer.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nstruct MultiplayerState\n{\n    std::vector<XblMultiplayerSessionHandle> sessionHandles;\n    XblMultiplayerSessionReference sessionRef{};\n    XblMultiplayerSearchHandle searchHandle{ nullptr };\n    XblMultiplayerInviteHandle inviteHandle{};\n    XblFunctionContext sessionChange{ 0 };\n    XblFunctionContext lostHandler{ 0 };\n    std::string activityHandle;\n\n    static std::string GetSessionName(uint64_t sessionId = 0) noexcept\n    {\n        // ID to make session names unique per API runner run\n#if HC_PLATFORM == HC_PLATFORM_GDK\n        ULARGE_INTEGER largeInt;\n        FILETIME fileTime;\n        GetSystemTimeAsFileTime(&fileTime);\n\n        largeInt.LowPart = fileTime.dwLowDateTime;\n        largeInt.HighPart = fileTime.dwHighDateTime;\n\n        static uint64_t runId{ largeInt.QuadPart };\n#else\n        static uint64_t runId{ utility::datetime::utc_now().to_interval() };\n#endif\n\n        std::stringstream ss;\n        ss << \"GameSession-\" << runId << \"-ID\" << sessionId;\n        return ss.str();\n    }\n};\nstd::unique_ptr<MultiplayerState> g_multiplayerState;\n\n\nMultiplayerState* MPState()\n{\n    if (g_multiplayerState == nullptr)\n    {\n        g_multiplayerState = std::make_unique<MultiplayerState>();\n        g_multiplayerState->sessionHandles.resize(10);\n    }\n    return g_multiplayerState.get();\n}\n\nXblMultiplayerSessionHandle GetSessionHandleFromArg(lua_State *L, int paramNum, uint64_t* sessionIndexOut = nullptr)\n{\n    auto sessionIndex{ GetUint64FromLua(L, paramNum, 0) };\n    assert(MPState()->sessionHandles.size() > sessionIndex);\n    if (sessionIndexOut != nullptr)\n    {\n        *sessionIndexOut = sessionIndex;\n    }\n    return MPState()->sessionHandles[static_cast<std::vector<XblMultiplayerSessionHandle>::size_type>(sessionIndex)];\n}\n\nint XblMultiplayerSessionCreateHandle_Lua(lua_State *L)\n{\n    uint64_t xuid = Data()->xboxUserId;\n\n    std::string scid = GetStringFromLua(L, 1, Data()->scid);\n    std::string sessionTemplateName = GetStringFromLua(L, 2, \"MinGameSession\");\n    std::string sessionName = GetStringFromLua(L, 3, \"\");\n    auto sessionIndex{ GetUint64FromLua(L, 4, 0) };\n\n    if (sessionName.empty())\n    {\n        sessionName = MultiplayerState::GetSessionName(sessionIndex);\n    }\n\n    // CODE SNIPPET START: XblMultiplayerSessionCreateHandle\n    XblMultiplayerSessionReference ref;\n    pal::strcpy(ref.Scid, sizeof(ref.Scid), scid.c_str());\n    pal::strcpy(ref.SessionTemplateName, sizeof(ref.SessionTemplateName), sessionTemplateName.c_str());\n    pal::strcpy(ref.SessionName, sizeof(ref.SessionName), sessionName.c_str());\n\n    XblMultiplayerSessionInitArgs args = {};\n\n    XblMultiplayerSessionHandle sessionHandle = XblMultiplayerSessionCreateHandle(xuid, &ref, &args);\n    // CODE SNIPPET END\n\n    auto state{ MPState() };\n    auto& session{ state->sessionHandles[static_cast<size_t>(sessionIndex)] };\n    if (session)\n    {\n        XblMultiplayerSessionCloseHandle(session);\n    }\n    state->sessionHandles[static_cast<unsigned int>(sessionIndex)] = sessionHandle;\n\n    lua_pushinteger(L, static_cast<lua_Integer>(sessionIndex));\n\n    LogToFile(\"XblMultiplayerSessionCreateHandle\");\n    return LuaReturnHR(L, S_OK, 1);\n}\n\nint XblMultiplayerSessionJoin_Lua(lua_State *L)\n{\n    // Params:\n    // 1) Session handle id returned when the session was created\n    // 2) member custom constants json\n    // 3) initialize requested\n    // 4) join with active status\n\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    std::string memberCustomConstantsJson = GetStringFromLua(L, 2, \"{}\");\n    bool initializeRequested = GetBoolFromLua(L, 3, true);\n    bool joinWithActiveStatus = GetBoolFromLua(L, 4, true);\n\n    // CODE SNIPPET START: XblMultiplayerSessionJoin\n    auto hr = XblMultiplayerSessionJoin(\n        sessionHandle,\n        memberCustomConstantsJson.c_str(),\n        initializeRequested,\n        joinWithActiveStatus);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionJoin: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nXblMultiplayerSessionWriteMode ConvertStringToXblMultiplayerSessionWriteMode(const char* str)\n{\n    XblMultiplayerSessionWriteMode writeMode = XblMultiplayerSessionWriteMode::UpdateOrCreateNew;\n\n    if (pal::stricmp(str, \"XblMultiplayerSessionWriteMode::SynchronizedUpdate\") == 0) writeMode = XblMultiplayerSessionWriteMode::SynchronizedUpdate;\n    else if (pal::stricmp(str, \"XblMultiplayerSessionWriteMode::CreateNew\") == 0) writeMode = XblMultiplayerSessionWriteMode::CreateNew;\n    else if (pal::stricmp(str, \"XblMultiplayerSessionWriteMode::UpdateExisting\") == 0) writeMode = XblMultiplayerSessionWriteMode::UpdateExisting;\n\n    return writeMode;\n}\n\nint XblMultiplayerWriteSessionAsync_Lua(lua_State *L)\n{\n    // Params:\n    // 1) Session handle id returned when the session was created\n    // 2) XblContextHandle to use. Defaults to Data()->xboxLiveContextse\n\n    CreateQueueIfNeeded();\n    auto sessionIndex{ GetUint64FromLua(L, 1, 0) };\n    assert(MPState()->sessionHandles.size() > sessionIndex);\n\n    XblContextHandle xboxLiveContext = (XblContextHandle)GetUint64FromLua(L, 2, (uint64_t)Data()->xboxLiveContext);\n\n    ENSURE_IS_TRUE(MPState()->sessionHandles[static_cast<uint32_t>(sessionIndex)] != nullptr, \"No valid multiplayer session.\");\n\n    XblMultiplayerSessionWriteMode writeMode = ConvertStringToXblMultiplayerSessionWriteMode(GetStringFromLua(L, 2, \"XblMultiplayerSessionWriteMode::UpdateOrCreateNew\").c_str());\n\n    // CODE SNIPPET START: XblMultiplayerWriteSessionAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    auto contextPtr = std::make_unique<size_t>(static_cast<size_t>(sessionIndex));\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = contextPtr.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        std::unique_ptr<size_t> sessionIndexPtr{ static_cast<size_t*>(asyncBlock->context) };\n        auto sessionIndex{ *sessionIndexPtr };\n        assert(MPState()->sessionHandles.size() > sessionIndex);\n        auto& session{ MPState()->sessionHandles[sessionIndex] };\n\n        if (session)\n        {\n            XblMultiplayerSessionCloseHandle(session);\n            MPState()->sessionHandles[sessionIndex] = nullptr;\n        }\n\n        HRESULT hr = XblMultiplayerWriteSessionResult(asyncBlock, &session);\n        if (SUCCEEDED(hr) && hr != 0x80070714) // HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n        {\n            auto status = XblMultiplayerSessionWriteStatus(session);\n            MPState()->sessionHandles[sessionIndex] = session;\n            LogToFile(\"XblMultiplayerWriteSessionResult: hr=%s writeResult=%d\", ConvertHR(hr).c_str(), status); // CODE SNIP SKIP\n        }\n        else\n        {\n            LogToFile(\"XblMultiplayerWriteSessionResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerWriteSessionAsync\"); // CODE SNIP SKIP\n    };\n\n    auto hr = XblMultiplayerWriteSessionAsync(xboxLiveContext, MPState()->sessionHandles[static_cast<uint32_t>(sessionIndex)], writeMode, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        contextPtr.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerWriteSessionAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCloseHandle_Lua(lua_State *L)\n{\n    uint64_t sessionIndex = 0;\n    auto sessionHandle = GetSessionHandleFromArg(L, 1, &sessionIndex);\n    // CODE SNIPPET START: XblMultiplayerWriteSessionAsync\n    XblMultiplayerSessionCloseHandle(sessionHandle);\n    // CODE SNIPPET END\n    MPState()->sessionHandles[static_cast<unsigned int>(sessionIndex)] = nullptr;\n\n    LogToFile(\"XblMultiplayerSessionCloseHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionAddMemberReservation_Lua(lua_State *L)\n{\n    uint64_t xuid = GetUint64FromLua(L, 1, 2814636782672891);\n    bool initializeRequested = GetBoolFromLua(L, 2, true);\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    // CODE SNIPPET START: XblMultiplayerWriteSessionAsync\n    auto hr = XblMultiplayerSessionAddMemberReservation(sessionHandle, xuid, nullptr, initializeRequested);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionAddMemberReservation: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid LogSessionRef(const XblMultiplayerSessionReference* sessionRef)\n{\n    LogToFile(\"Scid:%s\", sessionRef->Scid);\n    LogToFile(\"SessionName:%s\", sessionRef->SessionName);\n    LogToFile(\"SessionTemplateName:%s\", sessionRef->SessionTemplateName);\n}\n\n\nint XblMultiplayerSessionReferenceCreate_Lua(lua_State *L)\n{\n    std::string scid = GetStringFromLua(L, 1, Data()->scid);\n    std::string sessionTemplateName = GetStringFromLua(L, 2, \"MinGameSession\");\n    std::string sessionName = GetStringFromLua(L, 3, MultiplayerState::GetSessionName());\n\n    // CODE SNIPPET START: XblMultiplayerSessionReferenceCreate\n    MPState()->sessionRef = XblMultiplayerSessionReferenceCreate(scid.c_str(), sessionTemplateName.c_str(), sessionName.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionReferenceCreate\");\n    LogSessionRef(&MPState()->sessionRef);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionReferenceParseFromUriPath_Lua(lua_State* L)\n{\n    std::string path = GetStringFromLua(L, 1, \"\");\n    if (path.empty())\n    {\n        std::stringstream ss;\n        ss << \"/serviceconfigs/00000000-0000-0000-0000-000076029b4d/sessionTemplates/MinGameSession/sessions/\";\n        ss << MultiplayerState::GetSessionName();\n        path = ss.str();\n    }\n\n    // CODE SNIPPET START: XblMultiplayerSessionReferenceParseFromUriPath\n    HRESULT hr = XblMultiplayerSessionReferenceParseFromUriPath(path.c_str(), &MPState()->sessionRef);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionReferenceParseFromUriPath: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"Scid:%s\", MPState()->sessionRef.Scid);\n    LogToFile(\"SessionName:%s\", MPState()->sessionRef.SessionName);\n    LogToFile(\"SessionTemplateName:%s\", MPState()->sessionRef.SessionTemplateName);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionReferenceIsValid_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSessionReferenceIsValid\n    bool isValid = XblMultiplayerSessionReferenceIsValid(&MPState()->sessionRef);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionReferenceIsValid isValid:%d\", isValid);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionDuplicateHandle_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionDuplicateHandle\n    XblMultiplayerSessionHandle newHandle{};\n    HRESULT hr = XblMultiplayerSessionDuplicateHandle(sessionHandle, &newHandle);\n    // CODE SNIPPET END\n    XblMultiplayerSessionCloseHandle(newHandle);\n\n    LogToFile(\"XblMultiplayerSessionDuplicateHandle\");\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionTimeOfSession_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionTimeOfSession\n    time_t timeOfSession = XblMultiplayerSessionTimeOfSession(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionTimeOfSession timeOfSession:%d\", timeOfSession);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionGetInitializationInfo_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionGetInitializationInfo\n    const XblMultiplayerSessionInitializationInfo* info = XblMultiplayerSessionGetInitializationInfo(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionGetInitializationInfo\");\n    LogToFile(\"Stage: %d\", info->Stage);\n    LogToFile(\"StageStartTime: %ul\", info->StageStartTime);\n    LogToFile(\"Episode: %d\", info->Episode);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSubscribedChangeTypes_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionSubscribedChangeTypes\n    XblMultiplayerSessionChangeTypes changeTypes = XblMultiplayerSessionSubscribedChangeTypes(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSubscribedChangeTypes\");\n    LogToFile(\"changeTypes: 0x%0.4x\", changeTypes);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionHostCandidates_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionHostCandidates\n    const XblDeviceToken* deviceTokens = nullptr;\n    size_t deviceTokensCount = 0;\n    HRESULT hr = XblMultiplayerSessionHostCandidates(sessionHandle, &deviceTokens, &deviceTokensCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionHostCandidates: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionSessionReference_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionSessionReference\n    const XblMultiplayerSessionReference* sessionRef = XblMultiplayerSessionSessionReference(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSessionReference\");\n    LogToFile(\"Scid:%s\", sessionRef->Scid);\n    LogToFile(\"SessionName:%s\", sessionRef->SessionName);\n    LogToFile(\"SessionTemplateName:%s\", sessionRef->SessionTemplateName);\n    memcpy(&MPState()->sessionRef, sessionRef, sizeof(XblMultiplayerSessionReference));\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSessionConstants_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionSessionConstants\n    const XblMultiplayerSessionConstants* consts = XblMultiplayerSessionSessionConstants(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSessionConstants\");\n    LogToFile(\"MaxMembersInSession: %d\", consts->MaxMembersInSession);\n    LogToFile(\"Visibility: %d\", consts->Visibility);\n    //uint64_t* InitiatorXuids;\n    LogToFile(\"InitiatorXuidsCount: %ul\", consts->InitiatorXuidsCount);\n    if (consts->CustomJson) LogToFile(\"CustomJson: %s\", consts->CustomJson);\n    if (consts->SessionCloudComputePackageConstantsJson) LogToFile(\"SessionCloudComputePackageConstantsJson: %s\", consts->SessionCloudComputePackageConstantsJson);\n    LogToFile(\"MemberReservedTimeout: %ul\", consts->MemberReservedTimeout);\n    LogToFile(\"MemberInactiveTimeout: %ul\", consts->MemberInactiveTimeout);\n    LogToFile(\"MemberReadyTimeout: %ul\", consts->MemberReadyTimeout);\n    LogToFile(\"SessionEmptyTimeout: %ul\", consts->SessionEmptyTimeout);\n    LogToFile(\"EnableMetricsLatency: %d\", consts->EnableMetricsLatency);\n    LogToFile(\"EnableMetricsBandwidthDown: %d\", consts->EnableMetricsBandwidthDown);\n    LogToFile(\"EnableMetricsBandwidthUp: %d\", consts->EnableMetricsBandwidthUp);\n    LogToFile(\"EnableMetricsCustom: %d\", consts->EnableMetricsCustom);\n    //XblMultiplayerMemberInitialization* MemberInitialization;\n    LogToFile(\"PeerToPeerRequirements->LatencyMaximum: %ul\", consts->PeerToPeerRequirements.LatencyMaximum);\n    LogToFile(\"PeerToPeerRequirements->BandwidthMinimumInKbps: %ul\", consts->PeerToPeerRequirements.BandwidthMinimumInKbps);\n    LogToFile(\"PeerToHostRequirements->LatencyMaximum: %ul\", consts->PeerToHostRequirements.LatencyMaximum);\n    LogToFile(\"PeerToHostRequirements->BandwidthMinimumInKbps: %ul\", consts->PeerToHostRequirements.BandwidthDownMinimumInKbps);\n    LogToFile(\"PeerToHostRequirements->BandwidthUpMinimumInKbps: %ul\", consts->PeerToHostRequirements.BandwidthUpMinimumInKbps);\n    LogToFile(\"PeerToHostRequirements->HostSelectionMetric: %ul\", consts->PeerToHostRequirements.HostSelectionMetric);\n    if (consts->MeasurementServerAddressesJson) LogToFile(\"MeasurementServerAddressesJson: %s\", consts->MeasurementServerAddressesJson);\n    LogToFile(\"ClientMatchmakingCapable: %d\", consts->ClientMatchmakingCapable);\n    LogToFile(\"EnableMetricsCustom: %d\", consts->EnableMetricsCustom);\n    LogToFile(\"SessionCapabilities->Connectivity: %d\", consts->SessionCapabilities.Connectivity);\n    LogToFile(\"SessionCapabilities->SuppressPresenceActivityCheck: %d\", consts->SessionCapabilities.SuppressPresenceActivityCheck);\n    LogToFile(\"SessionCapabilities->Gameplay: %d\", consts->SessionCapabilities.Gameplay);\n    LogToFile(\"SessionCapabilities->Large: %d\", consts->SessionCapabilities.Large);\n    LogToFile(\"SessionCapabilities->ConnectionRequiredForActiveMembers: %d\", consts->SessionCapabilities.ConnectionRequiredForActiveMembers);\n    LogToFile(\"SessionCapabilities->UserAuthorizationStyle: %d\", consts->SessionCapabilities.UserAuthorizationStyle);\n    LogToFile(\"SessionCapabilities->Crossplay: %d\", consts->SessionCapabilities.Crossplay);\n    LogToFile(\"SessionCapabilities->Searchable: %d\", consts->SessionCapabilities.Searchable);\n    LogToFile(\"SessionCapabilities->HasOwners: %d\", consts->SessionCapabilities.HasOwners);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionConstantsSetMaxMembersInSession_Lua(lua_State *L)\n{\n    uint32_t maxMembersInSession = GetUint32FromLua(L, 1, 10);\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetMaxMembersInSession\n    XblMultiplayerSessionConstantsSetMaxMembersInSession(sessionHandle, maxMembersInSession);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetMaxMembersInSession\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionConstantsSetVisibility_Lua(lua_State *L)\n{\n    XblMultiplayerSessionVisibility visibility = static_cast<XblMultiplayerSessionVisibility>(GetUint32FromLua(L, 1, 3));\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetVisibility\n    XblMultiplayerSessionConstantsSetVisibility(sessionHandle, visibility);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetVisibility\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionConstantsSetTimeouts_Lua(lua_State *L)\n{\n    uint64_t memberReservedTimeout = GetUint64FromLua(L, 1, 100);\n    uint64_t memberInactiveTimeout = GetUint64FromLua(L, 2, 100);\n    uint64_t memberReadyTimeout = GetUint64FromLua(L, 3, 100);\n    uint64_t sessionEmptyTimeout = GetUint64FromLua(L, 4, 100);\n    auto sessionHandle = GetSessionHandleFromArg(L, 5);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetTimeouts\n    HRESULT hr = XblMultiplayerSessionConstantsSetTimeouts(\n        sessionHandle,\n        memberReservedTimeout,\n        memberInactiveTimeout,\n        memberReadyTimeout,\n        sessionEmptyTimeout);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetTimeouts: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetQosConnectivityMetrics_Lua(lua_State *L)\n{\n    bool enableLatencyMetric = GetBoolFromLua(L, 1, false);\n    bool enableBandwidthDownMetric = GetBoolFromLua(L, 2, false);\n    bool enableBandwidthUpMetric = GetBoolFromLua(L, 3, false);\n    bool enableCustomMetric = GetBoolFromLua(L, 4, false);\n    auto sessionHandle = GetSessionHandleFromArg(L, 5);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetQosConnectivityMetrics\n    HRESULT hr = XblMultiplayerSessionConstantsSetQosConnectivityMetrics(\n        sessionHandle,\n        enableLatencyMetric,\n        enableBandwidthDownMetric,\n        enableBandwidthUpMetric,\n        enableCustomMetric);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetQosConnectivityMetrics: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetMemberInitialization_Lua(lua_State *L)\n{\n    XblMultiplayerMemberInitialization init = {};\n    init.JoinTimeout = GetUint64FromLua(L, 1, 100);\n    init.MeasurementTimeout = GetUint64FromLua(L, 2, 100);\n    init.EvaluationTimeout = GetUint64FromLua(L, 3, 100);\n    init.ExternalEvaluation = GetBoolFromLua(L, 4, false);\n    init.MembersNeededToStart = GetUint32FromLua(L, 5, 2);\n    auto sessionHandle = GetSessionHandleFromArg(L, 6);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetMemberInitialization\n    HRESULT hr = XblMultiplayerSessionConstantsSetMemberInitialization(sessionHandle, init);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetMemberInitialization: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetPeerToPeerRequirements_Lua(lua_State *L)\n{\n    XblMultiplayerPeerToPeerRequirements requirements = {};\n    requirements.LatencyMaximum = GetUint64FromLua(L, 1, 100);\n    requirements.BandwidthMinimumInKbps = GetUint64FromLua(L, 2, 100);\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetPeerToPeerRequirements\n    HRESULT hr = XblMultiplayerSessionConstantsSetPeerToPeerRequirements(sessionHandle, requirements);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetPeerToPeerRequirements: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetPeerToHostRequirements_Lua(lua_State *L)\n{\n    XblMultiplayerPeerToHostRequirements requirements = {};\n    requirements.LatencyMaximum = GetUint64FromLua(L, 1, 100);\n    requirements.BandwidthDownMinimumInKbps = GetUint64FromLua(L, 2, 10);\n    requirements.BandwidthUpMinimumInKbps = GetUint64FromLua(L, 3, 10);\n    requirements.HostSelectionMetric = static_cast<XblMultiplayerMetrics>(GetUint64FromLua(L, 4, 1));\n    auto sessionHandle = GetSessionHandleFromArg(L, 5);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetPeerToHostRequirements\n    HRESULT hr = XblMultiplayerSessionConstantsSetPeerToHostRequirements(sessionHandle, requirements);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetPeerToHostRequirements: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson_Lua(lua_State *L)\n{\n    std::string measurementServerAddressesJson = GetStringFromLua(L, 1, \"{}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson\n    HRESULT hr = XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson(\n        sessionHandle,\n        measurementServerAddressesJson.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetCapabilities_Lua(lua_State *L)\n{\n    XblMultiplayerSessionCapabilities caps = {};\n    caps.Connectivity = GetBoolFromLua(L, 1, false);\n    caps.SuppressPresenceActivityCheck = GetBoolFromLua(L, 4, false);\n    caps.Gameplay = GetBoolFromLua(L, 5, false);\n    caps.Large = GetBoolFromLua(L, 6, true);\n    caps.ConnectionRequiredForActiveMembers = GetBoolFromLua(L, 7, false);\n    caps.UserAuthorizationStyle = GetBoolFromLua(L, 8, false);\n    caps.Crossplay = GetBoolFromLua(L, 9, false);\n    caps.Searchable = GetBoolFromLua(L, 10, false);\n    caps.HasOwners = GetBoolFromLua(L, 11, false);\n    auto sessionHandle = GetSessionHandleFromArg(L, 12);\n\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetCapabilities\n    HRESULT hr = XblMultiplayerSessionConstantsSetCapabilities(\n        sessionHandle,\n        caps);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetCapabilities: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionConstantsSetCloudComputePackageJson_Lua(lua_State *L)\n{\n    std::string sessionCloudComputePackageConstantsJson = GetStringFromLua(L, 1, \"{}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionConstantsSetCloudComputePackageJson\n    HRESULT hr = XblMultiplayerSessionConstantsSetCloudComputePackageJson(\n        sessionHandle,\n        sessionCloudComputePackageConstantsJson.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionConstantsSetCloudComputePackageJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionSessionProperties_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionSessionProperties\n    const XblMultiplayerSessionProperties* props = XblMultiplayerSessionSessionProperties(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSessionProperties\");\n    for (size_t i = 0; i < props->KeywordCount; i++)\n    {\n        LogToFile(\"Keywords[%ul]: %s\", i, props->Keywords[i]);\n    }\n    LogToFile(\"KeywordCount: %ul\", props->KeywordCount);\n    LogToFile(\"JoinRestriction: %d\", props->JoinRestriction);\n    LogToFile(\"ReadRestriction: %d\", props->ReadRestriction);\n    for (size_t i = 0; i < props->TurnCollectionCount; i++)\n    {\n        LogToFile(\"TurnCollection[%d]: %ul\", i, props->TurnCollection[i]);\n    }\n    LogToFile(\"TurnCollectionCount: %ul\", props->TurnCollectionCount);\n    LogToFile(\"MatchmakingTargetSessionConstantsJson: %s\", props->MatchmakingTargetSessionConstantsJson);\n    LogToFile(\"SessionCustomPropertiesJson: %s\", props->SessionCustomPropertiesJson);\n    LogToFile(\"MatchmakingServerConnectionString: %s\", props->MatchmakingServerConnectionString);\n    for (size_t i = 0; i < props->ServerConnectionStringCandidatesCount; i++)\n    {\n        LogToFile(\"ServerConnectionStringCandidates[%ul]: %s\", i, props->ServerConnectionStringCandidates[i]);\n    }\n    LogToFile(\"ServerConnectionStringCandidatesCount: %ul\", props->ServerConnectionStringCandidatesCount);\n    for (size_t i = 0; i < props->SessionOwnerMemberIdsCount; i++)\n    {\n        LogToFile(\"SessionOwnerMemberIds[%ul]: %s\", i, props->SessionOwnerMemberIds[i]);\n    }\n    LogToFile(\"SessionOwnerMemberIdsCount: %ul\", props->SessionOwnerMemberIdsCount);\n    LogToFile(\"HostDeviceToken: %s\", props->HostDeviceToken.Value);\n    LogToFile(\"Closed: %d\", props->Closed);\n    LogToFile(\"Locked: %d\", props->Locked);\n    LogToFile(\"AllocateCloudCompute: %d\", props->AllocateCloudCompute);\n    LogToFile(\"MatchmakingResubmit: %d\", props->MatchmakingResubmit);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionPropertiesSetKeywords_Lua(lua_State *L)\n{\n    std::string key1 = GetStringFromLua(L, 1, \"Keyword1\");\n    std::string key2 = GetStringFromLua(L, 2, \"Keyword2\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n    // CODE SNIPPET START: XblMultiplayerSessionPropertiesSetKeywords\n    const char* keywords[2] = {};\n    keywords[0] = key1.c_str();\n    keywords[1] = key2.c_str();\n    size_t keywordsCount = 2;\n\n    HRESULT hr = XblMultiplayerSessionPropertiesSetKeywords(\n        sessionHandle,\n        keywords,\n        keywordsCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionPropertiesSetKeywords: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionPropertiesSetJoinRestriction_Lua(lua_State *L)\n{\n    XblMultiplayerSessionRestriction joinRestriction = static_cast<XblMultiplayerSessionRestriction>(GetUint64FromLua(L, 1, static_cast<int>(XblMultiplayerSessionRestriction::Followed)));\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionPropertiesSetJoinRestriction\n    XblMultiplayerSessionPropertiesSetJoinRestriction(\n        sessionHandle,\n        joinRestriction);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionPropertiesSetJoinRestriction\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionPropertiesSetReadRestriction_Lua(lua_State *L)\n{\n    XblMultiplayerSessionRestriction readRestriction = static_cast<XblMultiplayerSessionRestriction>(GetUint64FromLua(L, 1, static_cast<int>(XblMultiplayerSessionRestriction::Followed)));\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionPropertiesSetReadRestriction\n    XblMultiplayerSessionPropertiesSetReadRestriction(\n        sessionHandle,\n        readRestriction\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionPropertiesSetReadRestriction\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionPropertiesSetTurnCollection_Lua(lua_State *L)\n{\n    uint32_t turnId1 = GetUint32FromLua(L, 1, 0);\n    uint32_t turnId2 = GetUint32FromLua(L, 2, 1);\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n    // CODE SNIPPET START: XblMultiplayerSessionPropertiesSetTurnCollection\n    uint32_t turnCollectionMemberIds[2] = {};\n    turnCollectionMemberIds[0] = turnId1;\n    turnCollectionMemberIds[1] = turnId2;\n    size_t turnCollectionMemberIdsCount = 2;\n    HRESULT hr = XblMultiplayerSessionPropertiesSetTurnCollection(\n        sessionHandle,\n        turnCollectionMemberIds,\n        turnCollectionMemberIdsCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionPropertiesSetTurnCollection: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionRoleTypes_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionRoleTypes\n    const XblMultiplayerRoleType* roleTypes = nullptr;\n    size_t roleTypesCount = 0;\n\n    HRESULT hr = XblMultiplayerSessionRoleTypes(\n        sessionHandle,\n        &roleTypes,\n        &roleTypesCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionRoleTypes: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionGetRoleByName_Lua(lua_State *L)\n{\n    std::string roleTypeName = GetStringFromLua(L, 1, \"Role1\");\n    std::string roleName = GetStringFromLua(L, 2, \"RoleName1\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n    // CODE SNIPPET START: XblMultiplayerSessionGetRoleByName\n    const XblMultiplayerRole* role = nullptr;\n    HRESULT hr = XblMultiplayerSessionGetRoleByName(\n        sessionHandle,\n        roleTypeName.c_str(),\n        roleName.c_str(),\n        &role);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionGetRoleByName: hr=%s\", ConvertHR(hr).c_str());\n    if (role == nullptr)\n    {\n        return LuaReturnHR(L, S_OK);\n    }\n\n    //XblMultiplayerRoleType* RoleType;\n    LogToFile(\"role.Name: %s\", role->Name);\n    for (uint32_t i = 0; i < role->MemberCount; i++)\n    {\n        LogToFile(\"role.MemberXuids[%ul]: %ul\", i, role->MemberXuids[i]);\n    }\n    LogToFile(\"role.MemberCount: %d\", role->MemberCount);\n    LogToFile(\"role.TargetCount: %d\", role->TargetCount);\n    LogToFile(\"role.MaxMemberCount: %d\", role->MaxMemberCount);\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionSetMutableRoleSettings_Lua(lua_State *L)\n{\n    std::string roleTypeName = GetStringFromLua(L, 1, \"Role1\");\n    std::string roleName = GetStringFromLua(L, 2, \"RoleName1\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n    // CODE SNIPPET START: XblMultiplayerSessionSetMutableRoleSettings\n    uint32_t maxMemberCount = 0;\n    uint32_t targetMemberCount = 0;\n\n    HRESULT hr = XblMultiplayerSessionSetMutableRoleSettings(\n        sessionHandle,\n        roleTypeName.c_str(),\n        roleName.c_str(),\n        &maxMemberCount,\n        &targetMemberCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetMutableRoleSettings: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"maxMemberCount: %d\", maxMemberCount);\n    LogToFile(\"targetMemberCount: %d\", targetMemberCount);\n    return LuaReturnHR(L, hr);\n}\n\nvoid LogSessionMember(const XblMultiplayerSessionMember* member)\n{\n    // TODO\n    LogToFile(\"member->MemberId: %d\", member->MemberId);\n    LogToFile(\"member->InitialTeam: %s\", member->InitialTeam);\n    LogToFile(\"member->Xuid: %ul\", member->Xuid);\n    LogToFile(\"member->CustomConstantsJson: %s\", member->CustomConstantsJson);\n    LogToFile(\"member->SecureDeviceBaseAddress64: %s\", member->SecureDeviceBaseAddress64);\n    for (size_t i = 0; i < member->RolesCount; i++)\n    {\n        LogToFile(\"member->Roles[%ul].roleTypeName %s\", i, member->Roles[i].roleTypeName);\n        LogToFile(\"member->Roles[%ul].roleName %s\", i, member->Roles[i].roleName);\n    }\n    LogToFile(\"member->RolesCount: %ul\", member->RolesCount);\n    LogToFile(\"member->CustomPropertiesJson: %s\", member->CustomPropertiesJson);\n    LogToFile(\"member->Gamertag: %s\", member->Gamertag);\n    LogToFile(\"member->XblMultiplayerSessionMemberStatus: %d\", member->Status);\n    LogToFile(\"member->IsTurnAvailable: %d\", member->IsTurnAvailable);\n    LogToFile(\"member->IsCurrentUser: %d\", member->IsCurrentUser);\n    LogToFile(\"member->InitializeRequested: %d\", member->InitializeRequested);\n    LogToFile(\"member->MatchmakingResultServerMeasurementsJson: %s\", member->MatchmakingResultServerMeasurementsJson);\n    LogToFile(\"member->ServerMeasurementsJson: %s\", member->ServerMeasurementsJson);\n    for (size_t i = 0; i < member->MembersInGroupCount; i++)\n    {\n        LogToFile(\"member->MembersInGroupIds[%d]: %ul\", i, member->MembersInGroupIds[i]);\n    }\n    LogToFile(\"member->MembersInGroupCount: %ul\", member->MembersInGroupCount);\n    LogToFile(\"member->QosMeasurementsJson: %s\", member->QosMeasurementsJson);\n    LogToFile(\"member->DeviceToken: %s\", member->DeviceToken.Value);\n    LogToFile(\"member->Nat: %d\", member->Nat);\n    LogToFile(\"member->ActiveTitleId: %d\", member->ActiveTitleId);\n    LogToFile(\"member->InitializationEpisode: %d\", member->InitializationEpisode);\n    LogToFile(\"member->JoinTime: %ul\", member->JoinTime);\n    LogToFile(\"member->InitializationFailureCause: %d\", member->InitializationFailureCause);\n    for (size_t i = 0; i < member->GroupsCount; i++)\n    {\n        LogToFile(\"member->Groups[%d]: %s\", i, member->Groups[i]);\n    }\n    LogToFile(\"member->GroupsCount: %ul\", member->GroupsCount);\n    for (size_t i = 0; i < member->EncountersCount; i++)\n    {\n        LogToFile(\"member->Encounters[%d]: %s\", i, member->Encounters[i]);\n    }\n    LogToFile(\"member->EncountersCount: %ul\", member->EncountersCount);\n}\n\nint XblMultiplayerSessionMembers_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionMembers\n    const XblMultiplayerSessionMember* members = nullptr;\n    size_t membersCount = 0;\n    HRESULT hr = XblMultiplayerSessionMembers(\n        sessionHandle,\n        &members,\n        &membersCount\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionMembers: hr=%s\", ConvertHR(hr).c_str());\n    for (size_t i = 0; i < membersCount; i++)\n    {\n        LogSessionMember(&members[i]);\n    }\n\n    LogToFile(\"membersCount: %d\", membersCount);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionGetMember_Lua(lua_State *L)\n{\n    uint32_t memberId = GetUint32FromLua(L, 1, 0);\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionGetMember\n    const XblMultiplayerSessionMember* member = XblMultiplayerSessionGetMember(\n        sessionHandle,\n        memberId);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionGetMember\");\n    LogSessionMember(member);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionMatchmakingServer_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionMatchmakingServer\n    const XblMultiplayerMatchmakingServer* server = XblMultiplayerSessionMatchmakingServer(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionMatchmakingServer\");\n    if (server == nullptr)\n    {\n        LogToFile(\"server == nullptr\");\n        return LuaReturnHR(L, S_OK);\n    }\n\n    LogToFile(\"server->Status: %d\", server->Status);\n    LogToFile(\"server->StatusDetails: %s\", server->StatusDetails);\n    LogToFile(\"server->TypicalWaitInSeconds: %d\", server->TypicalWaitInSeconds);\n    LogSessionRef(&server->TargetSessionRef);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionMembersAccepted_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionMembersAccepted\n    uint32_t membersAccepted = XblMultiplayerSessionMembersAccepted(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionMembersAccepted\");\n    LogToFile(\"membersAccepted: %d\", membersAccepted);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionRawServersJson_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionRawServersJson\n    const char* json = XblMultiplayerSessionRawServersJson(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionRawServersJson\");\n    LogToFile(\"json: %s\", json);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetRawServersJson_Lua(lua_State *L)\n{\n    std::string json = GetStringFromLua(L, 1, \"{}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetRawServersJson\n    HRESULT hr = XblMultiplayerSessionSetRawServersJson(sessionHandle, json.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetRawServersJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionEtag_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionEtag\n    const char* etag = XblMultiplayerSessionEtag(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionEtag\");\n    LogToFile(\"etag: %s\", etag);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionCurrentUser_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUser\n    const XblMultiplayerSessionMember* member = XblMultiplayerSessionCurrentUser(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUser\");\n    if (member == nullptr)\n    {\n        LogToFile(\"member == nullptr\");\n        return LuaReturnHR(L, S_OK);\n    }\n\n    LogSessionMember(member);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionGetInfo_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionGetInfo\n    const XblMultiplayerSessionInfo * sessionInfo = XblMultiplayerSessionGetInfo(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionGetInfo\");\n    LogToFile(\"sessionInfo->ContractVersion: %d\", sessionInfo->ContractVersion);\n    LogToFile(\"sessionInfo->Branch: %s\", sessionInfo->Branch);\n    LogToFile(\"sessionInfo->ChangeNumber: %ul\", sessionInfo->ChangeNumber);\n    LogToFile(\"sessionInfo->CorrelationId: %s\", sessionInfo->CorrelationId);\n    LogToFile(\"sessionInfo->StartTime: %ul\", sessionInfo->StartTime);\n    LogToFile(\"sessionInfo->NextTimer: %ul\", sessionInfo->NextTimer);\n    LogToFile(\"sessionInfo->SearchHandleId: %s\", sessionInfo->SearchHandleId);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionWriteStatus_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionWriteStatus\n    XblWriteSessionStatus status = XblMultiplayerSessionWriteStatus(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionWriteStatus\");\n    LogToFile(\"status: %d\", status);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetInitializationSucceeded_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    bool initSucceded = GetBoolFromLua(L, 1, false);\n    // CODE SNIPPET START: XblMultiplayerSessionSetInitializationSucceeded\n    XblMultiplayerSessionSetInitializationSucceeded(sessionHandle, initSucceded);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetInitializationSucceeded %d\", initSucceded);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetHostDeviceToken_Lua(lua_State *L)\n{\n    std::string host = GetStringFromLua(L, 1, \"DefaultHost\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetHostDeviceToken\n    XblDeviceToken hostDeviceToken = {};\n    pal::strcpy(hostDeviceToken.Value, sizeof(hostDeviceToken.Value), host.c_str());\n    XblMultiplayerSessionSetHostDeviceToken(sessionHandle, hostDeviceToken);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetHostDeviceToken host:%s\", host.c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetMatchmakingServerConnectionPath_Lua(lua_State *L)\n{\n    std::string path = GetStringFromLua(L, 1, \"DefaultPath\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetMatchmakingServerConnectionPath\n    XblMultiplayerSessionSetMatchmakingServerConnectionPath(\n        sessionHandle, path.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetMatchmakingServerConnectionPath path:%s\", path.c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetClosed_Lua(lua_State *L)\n{\n    bool closed = GetBoolFromLua(L, 1, true);\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetClosed\n    XblMultiplayerSessionSetClosed(sessionHandle, closed);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetClosed %d\", closed);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetLocked_Lua(lua_State *L)\n{\n    bool locked = GetBoolFromLua(L, 1, false);\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetLocked\n    XblMultiplayerSessionSetLocked(sessionHandle, locked);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetLocked %d\", locked);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetAllocateCloudCompute_Lua(lua_State *L)\n{\n    bool allocate = GetBoolFromLua(L, 1, false);\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetAllocateCloudCompute\n    XblMultiplayerSessionSetAllocateCloudCompute(sessionHandle, allocate);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetAllocateCloudCompute %d\", allocate);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetMatchmakingResubmit_Lua(lua_State *L)\n{\n    bool matchResubmit = GetBoolFromLua(L, 1, false);\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetMatchmakingResubmit\n    XblMultiplayerSessionSetMatchmakingResubmit(sessionHandle, matchResubmit);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetMatchmakingResubmit %d\", matchResubmit);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionSetServerConnectionStringCandidates_Lua(lua_State *L)\n{\n    std::string candidate1 = GetStringFromLua(L, 1, \"Candidate1\");\n    std::string candidate2 = GetStringFromLua(L, 2, \"Candidate1\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n    HRESULT hr = S_OK;\n    if (sessionHandle != nullptr) // might be null if previous call fails\n    {\n        // CODE SNIPPET START: XblMultiplayerSessionSetServerConnectionStringCandidates\n        const char* serverConnectionStringCandidates[2] = {};\n        serverConnectionStringCandidates[0] = candidate1.c_str();\n        serverConnectionStringCandidates[1] = candidate2.c_str();\n        size_t serverConnectionStringCandidatesCount = 2;\n\n        hr = XblMultiplayerSessionSetServerConnectionStringCandidates(\n            sessionHandle,\n            serverConnectionStringCandidates,\n            serverConnectionStringCandidatesCount);\n        // CODE SNIPPET END\n    }\n\n    LogToFile(\"XblMultiplayerSessionSetServerConnectionStringCandidates: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionSetSessionChangeSubscription_Lua(lua_State *L)\n{\n    XblMultiplayerSessionChangeTypes changeTypes = static_cast<XblMultiplayerSessionChangeTypes>(GetUint32FromLua(L, 1, static_cast<int>(XblMultiplayerSessionChangeTypes::Everything)));\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionSetSessionChangeSubscription\n    HRESULT hr = XblMultiplayerSessionSetSessionChangeSubscription(\n        sessionHandle,\n        changeTypes);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetSessionChangeSubscription: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionLeave_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    // CODE SNIPPET START: XblMultiplayerSessionLeave\n    HRESULT hr = XblMultiplayerSessionLeave(sessionHandle);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionLeave: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetStatus_Lua(lua_State *L)\n{\n    XblMultiplayerSessionMemberStatus status = static_cast<XblMultiplayerSessionMemberStatus>(GetUint32FromLua(L, 1, 3));\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetStatus\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetStatus(\n        sessionHandle,\n        status);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetStatus: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64_Lua(lua_State *L)\n{\n    std::string deviceAddress = GetStringFromLua(L, 1, \"ExampleDeviceAddress\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64(\n        sessionHandle,\n        deviceAddress.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblFormatSecureDeviceAddress_Lua(lua_State *L)\n{\n#if HC_PLATFORM != HC_PLATFORM_XDK && HC_PLATFORM != HC_PLATFORM_UWP\n    std::string deviceIdStr = GetStringFromLua(L, 1, \"ExampleDeviceAddress\");\n    auto deviceId = deviceIdStr.c_str();\n\n    // CODE SNIPPET START: XblFormatSecureDeviceAddress\n    XblFormattedSecureDeviceAddress address{ };\n    HRESULT hr = XblFormatSecureDeviceAddress(deviceId, &address);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblFormatSecureDeviceAddress: hr=%s sda=%s\", hr, address.value);\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSessionCurrentUserSetRoles_Lua(lua_State *L)\n{\n    std::string roleTypeName1 = \"roleTypeName1\";\n    std::string roleName1 = \"roleName1\";\n    std::string roleTypeName2 = \"roleTypeName2\";\n    std::string roleName2 = \"roleName2\";\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetRoles\n    XblMultiplayerSessionMemberRole roles[2] = {};\n    roles[0].roleTypeName = roleTypeName1.c_str();\n    roles[0].roleName = roleName1.c_str();\n    roles[1].roleTypeName = roleTypeName2.c_str();\n    roles[1].roleName = roleName2.c_str();\n    size_t rolesCount = 2;\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetRoles(\n        sessionHandle,\n        roles,\n        rolesCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetRoles: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetMembersInGroup_Lua(lua_State *L)\n{\n    uint32_t memberId1 = GetUint32FromLua(L, 1, 0);\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetMembersInGroup\n    uint32_t memberIds[1] = {};\n    memberIds[0] = memberId1;\n    size_t memberIdsCount = 1;\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetMembersInGroup(\n        sessionHandle,\n        memberIds,\n        memberIdsCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetMembersInGroup: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetGroups_Lua(lua_State *L)\n{\n    std::string group1 = GetStringFromLua(L, 1, \"group1\");\n    std::string group2 = GetStringFromLua(L, 2, \"group2\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetGroups\n    const char* groups[2] = {};\n    groups[0] = group1.c_str();\n    groups[1] = group2.c_str();\n    size_t groupsCount = 2;\n\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetGroups(\n        sessionHandle,\n        groups,\n        groupsCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetGroups: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetEncounters_Lua(lua_State *L)\n{\n    std::string encounter1 = GetStringFromLua(L, 1, \"encounter1\");\n    std::string encounter2 = GetStringFromLua(L, 2, \"encounter2\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetEncounters\n    const char* encounters[2] = {};\n    encounters[0] = encounter1.c_str();\n    encounters[1] = encounter2.c_str();\n    size_t encountersCount = 2;\n\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetEncounters(\n        sessionHandle,\n        encounters,\n        encountersCount);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetEncounters: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetQosMeasurements_Lua(lua_State *L)\n{\n    std::string measurements = GetStringFromLua(L, 1, \"{\\\"measurements1\\\":5}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetQosMeasurements\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetQosMeasurements(\n        sessionHandle,\n        measurements.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetQosMeasurements: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetServerQosMeasurements_Lua(lua_State *L)\n{\n    std::string measurements = GetStringFromLua(L, 1, \"{\\\"measurements1\\\":5}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetServerQosMeasurements\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetServerQosMeasurements(\n        sessionHandle,\n        measurements.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetServerQosMeasurements: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserSetCustomPropertyJson_Lua(lua_State *L)\n{\n    std::string name = GetStringFromLua(L, 1, \"name1\");\n    std::string json = GetStringFromLua(L, 2, \"{\\\"myscore\\\":123}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    ENSURE_IS_TRUE(sessionHandle != nullptr, \"No valid multiplayer session.\");\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserSetCustomPropertyJson\n    HRESULT hr = XblMultiplayerSessionCurrentUserSetCustomPropertyJson(\n        sessionHandle,\n        name.c_str(),\n        json.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserSetCustomPropertyJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson_Lua(lua_State *L)\n{\n    std::string name = GetStringFromLua(L, 1, \"name1\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    // CODE SNIPPET START: XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson\n    HRESULT hr = XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(\n        sessionHandle,\n        name.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson_Lua(lua_State *L)\n{\n    std::string consts = GetStringFromLua(L, 1, \"{}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    HRESULT hr = S_OK;\n    if (sessionHandle != nullptr) // might be null if previous call fails\n    {\n        // CODE SNIPPET START: XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson\n        hr = XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson(\n            sessionHandle,\n            consts.c_str());\n        // CODE SNIPPET END\n    }\n\n    LogToFile(\"XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionSetCustomPropertyJson_Lua(lua_State *L)\n{\n    std::string name = GetStringFromLua(L, 1, \"name1\");\n    std::string json = GetStringFromLua(L, 2, \"{}\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    // CODE SNIPPET START: XblMultiplayerSessionSetCustomPropertyJson\n    HRESULT hr = XblMultiplayerSessionSetCustomPropertyJson(\n        sessionHandle,\n        name.c_str(),\n        json.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionSetCustomPropertyJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionDeleteCustomPropertyJson_Lua(lua_State *L)\n{\n    std::string name = GetStringFromLua(L, 1, \"name1\");\n    auto sessionHandle = GetSessionHandleFromArg(L, 2);\n\n    // CODE SNIPPET START: XblMultiplayerSessionDeleteCustomPropertyJson\n    HRESULT hr = XblMultiplayerSessionDeleteCustomPropertyJson(\n        sessionHandle,\n        name.c_str());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSessionDeleteCustomPropertyJson: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSessionCompare_Lua(lua_State *L)\n{\n    auto sessionHandle = GetSessionHandleFromArg(L, 1);\n    XblMultiplayerSessionHandle sessionHandle2{};\n    XblMultiplayerSessionDuplicateHandle(sessionHandle, &sessionHandle2);\n\n    // CODE SNIPPET START: XblMultiplayerSessionCompare\n    XblMultiplayerSessionChangeTypes changeTypes = XblMultiplayerSessionCompare(\n        sessionHandle,\n        sessionHandle2);\n    // CODE SNIPPET END\n\n    XblMultiplayerSessionCloseHandle(sessionHandle2);\n    LogToFile(\"XblMultiplayerSessionCompare\");\n    LogToFile(\"changeTypes: %d\", changeTypes);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerWriteSessionByHandleAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    XblMultiplayerSessionWriteMode writeMode = static_cast<XblMultiplayerSessionWriteMode>(GetUint32FromLua(L, 1, \n        static_cast<int>(XblMultiplayerSessionWriteMode::UpdateExisting)));\n    std::string handleId = GetStringFromLua(L, 2, MPState()->activityHandle);\n    auto sessionHandle = GetSessionHandleFromArg(L, 3);\n\n    // CODE SNIPPET START: XblMultiplayerWriteSessionByHandleAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblMultiplayerSessionHandle sessionHandle;\n        auto hr = XblMultiplayerWriteSessionByHandleResult(asyncBlock, &sessionHandle);\n        LogToFile(\"XblMultiplayerWriteSessionByHandleResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerWriteSessionByHandleAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerWriteSessionByHandleAsync(\n        Data()->xboxLiveContext,\n        sessionHandle,\n        writeMode,\n        handleId.c_str(),\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblMultiplayerWriteSessionByHandleAsync: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"writeMode: %d\", writeMode);\n    LogToFile(\"handleId: %s\", handleId.c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerGetSessionAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    XblMultiplayerSessionReference sessionRef;\n    std::string scid = GetStringFromLua(L, 1, Data()->scid);\n    std::string sessionTemplateName = GetStringFromLua(L, 2, \"MinGameSession\");\n    auto sessionIndex{ GetUint64FromLua(L, 4, 0) };\n    std::string sessionName = GetStringFromLua(L, 3, MultiplayerState::GetSessionName(sessionIndex));\n\n    pal::strcpy(sessionRef.Scid, sizeof(sessionRef.Scid), scid.c_str());\n    pal::strcpy(sessionRef.SessionName, sizeof(sessionRef.SessionName), sessionName.c_str());\n    pal::strcpy(sessionRef.SessionTemplateName, sizeof(sessionRef.SessionTemplateName), sessionTemplateName.c_str());\n\n    // CODE SNIPPET START: XblMultiplayerWriteSessionByHandleAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    auto contextPtr = std::make_unique<size_t>(static_cast<size_t>(sessionIndex));\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = contextPtr.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        std::unique_ptr<size_t> sessionIndexPtr{ static_cast<size_t*>(asyncBlock->context) };\n        auto sessionIndex{ *sessionIndexPtr };\n\n        auto& session{ MPState()->sessionHandles[sessionIndex] }; //CODE SNIP SKIP\n        if (session) //CODE SNIP SKIP\n        {\n            XblMultiplayerSessionCloseHandle(session); //CODE SNIP SKIP\n            MPState()->sessionHandles[sessionIndex] = nullptr; //CODE SNIP SKIP\n        }\n\n        XblMultiplayerSessionHandle sessionHandle = nullptr;\n        auto hr = XblMultiplayerGetSessionResult(asyncBlock, &sessionHandle);\n        LogToFile(\"XblMultiplayerGetSessionResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        MPState()->sessionHandles[sessionIndex] = sessionHandle; // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetSessionAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerGetSessionAsync(\n        Data()->xboxLiveContext,\n        &sessionRef,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        contextPtr.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblMultiplayerGetSessionAsync: hr=%s\", ConvertHR(hr).c_str());\n    LogSessionRef(&sessionRef);\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerGetSessionByHandleAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    std::string handleId = GetStringFromLua(L, 1, MPState()->inviteHandle.Data);\n    auto sessionIndex{ GetUint64FromLua(L, 2, 0) };\n\n    if (handleId.empty())\n    {\n        handleId = \"86191619-4002-044f-4846-f8f903c71512\";\n    }\n\n    // CODE SNIPPET START: XblMultiplayerGetSessionByHandleAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    auto contextPtr = std::make_unique<size_t>(static_cast<size_t>(sessionIndex));\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = contextPtr.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        std::unique_ptr<size_t> sessionIndexPtr{ static_cast<size_t*>(asyncBlock->context) };\n        auto sessionIndex{ *sessionIndexPtr };\n\n        auto& session{ MPState()->sessionHandles[sessionIndex] }; //CODE SNIP SKIP\n        if (session) //CODE SNIP SKIP\n        {\n            XblMultiplayerSessionCloseHandle(session); //CODE SNIP SKIP\n            MPState()->sessionHandles[sessionIndex] = nullptr; //CODE SNIP SKIP\n        }\n\n        XblMultiplayerSessionHandle sessionHandle = nullptr;\n        auto hr = XblMultiplayerGetSessionByHandleResult(asyncBlock, &sessionHandle);\n        LogToFile(\"XblMultiplayerGetSessionByHandleResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        MPState()->sessionHandles[sessionIndex] = sessionHandle; // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetSessionByHandleAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerGetSessionByHandleAsync(\n        Data()->xboxLiveContext,\n        handleId.c_str(),\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        contextPtr.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblMultiplayerGetSessionAsync: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"handleId: %s\", handleId.c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerQuerySessionsAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    std::string Scid = GetStringFromLua(L, 1, Data()->scid);\n    uint32_t MaxItems = GetUint32FromLua(L, 2, 0);\n    bool IncludePrivateSessions = GetBoolFromLua(L, 3, false);\n    bool IncludeReservations = GetBoolFromLua(L, 4, false);\n    bool IncludeInactiveSessions = GetBoolFromLua(L, 5, false);\n    std::string KeywordFilter = GetStringFromLua(L, 6, \"killzone\");\n    std::string SessionTemplateNameFilter = GetStringFromLua(L, 7, \"\");\n    XblMultiplayerSessionVisibility VisibilityFilter = static_cast<XblMultiplayerSessionVisibility>(GetUint32FromLua(L, 8, 5));\n    uint32_t ContractVersionFilter = GetUint32FromLua(L, 9, 0);\n    //uint64_t* XuidFilters;\n    //size_t XuidFiltersCount;\n\n    // CODE SNIPPET START: XblMultiplayerQuerySessionsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t sessionCount = 0;\n        HRESULT hr = XblMultiplayerQuerySessionsResultCount(asyncBlock, &sessionCount);\n        LogToFile(\"sessionCount %d\", sessionCount);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<XblMultiplayerSessionQueryResult> sessions(sessionCount);\n            hr = XblMultiplayerQuerySessionsResult(asyncBlock, sessionCount, sessions.data());\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerQuerySessionsAsync\"); // CODE SNIP SKIP\n    };\n\n    XblMultiplayerSessionQuery sessionQuery = {};\n    pal::strcpy(sessionQuery.Scid, sizeof(sessionQuery.Scid), Scid.c_str());\n    sessionQuery.MaxItems = MaxItems;\n    sessionQuery.IncludePrivateSessions = IncludePrivateSessions;\n    sessionQuery.IncludeReservations = IncludeReservations;\n    sessionQuery.IncludeInactiveSessions = IncludeInactiveSessions;\n    sessionQuery.KeywordFilter = KeywordFilter.c_str();\n    pal::strcpy(sessionQuery.SessionTemplateNameFilter, sizeof(sessionQuery.SessionTemplateNameFilter), SessionTemplateNameFilter.c_str());\n    sessionQuery.VisibilityFilter = VisibilityFilter;\n    sessionQuery.ContractVersionFilter = ContractVersionFilter;\n    //sessionQuery.XuidFilters\n    //sessionQuery.XuidFiltersCount \n\n    HRESULT hr = XblMultiplayerQuerySessionsAsync(\n        Data()->xboxLiveContext,\n        &sessionQuery,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblMultiplayerQuerySessionsAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSetActivityAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSetActivityAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerSetActivityAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerSetActivityAsync(\n        Data()->xboxLiveContext,\n        &MPState()->sessionRef,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSetActivityAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerClearActivityAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerClearActivityAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerClearActivityAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerClearActivityAsync(\n        Data()->xboxLiveContext,\n        Data()->scid, // TODO: fix type\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerClearActivityAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSendInvitesAsync_Lua(lua_State *L)\n{\n    std::string contextStringIdStr = GetStringFromLua(L, 1, \"contextStringId1\");\n    std::string customActivationContextStr = GetStringFromLua(L, 2, \"customActivationContext1\");\n    uint64_t targetXuid = GetUint64FromLua(L, 3, 2814679169942680);\n\n    auto xblContextHandle = Data()->xboxLiveContext;\n    auto sessionReference = MPState()->sessionRef;\n    auto titleId = Data()->titleId;\n    auto contextStringId = contextStringIdStr.c_str();\n    auto customActivationContext = customActivationContextStr.c_str();\n\n    // CODE SNIPPET START: XblMultiplayerSendInvitesAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t handlesCount = 1; // must be equal to invites requested\n        XblMultiplayerInviteHandle handles[1] = {};\n        HRESULT hr = XblMultiplayerSendInvitesResult(asyncBlock, handlesCount, handles);\n        MPState()->inviteHandle = handles[0]; // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerSendInvitesAsync\"); // CODE SNIP SKIP\n    };\n\n    uint64_t xuids[1] = {};\n    xuids[0] = targetXuid;\n    size_t xuidsCount = 1;\n\n    HRESULT hr = XblMultiplayerSendInvitesAsync(\n        xblContextHandle,\n        &sessionReference,\n        xuids,\n        xuidsCount,\n        titleId,\n        contextStringId,\n        customActivationContext,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSendInvitesAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerGetActivitiesForSocialGroupAsync_Lua(lua_State *L)\n{\n    uint64_t socialGroupOwnerXuid = GetUint64FromLua(L, 1, 2814632956486799);\n    std::string socialGroup = GetStringFromLua(L, 2, \"people\");\n\n    // CODE SNIPPET START: XblMultiplayerGetActivitiesForSocialGroupAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultCount{ 0 };\n        HRESULT hr = XblMultiplayerGetActivitiesForSocialGroupResultCount(asyncBlock, &resultCount);\n        LogToFile(\"activityCount %d\", resultCount); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            std::vector<XblMultiplayerActivityDetails> activityDetails(resultCount);\n            hr = XblMultiplayerGetActivitiesForSocialGroupResult(asyncBlock, resultCount, activityDetails.data());\n        }\n        else if (hr == HTTP_E_STATUS_SERVICE_UNAVAIL)\n        {\n            CallLuaFunctionWithHr(S_OK, \"OnXblMultiplayerGetActivitiesForSocialGroupAsyncRetry\");\n            return;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetActivitiesForSocialGroupAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerGetActivitiesForSocialGroupAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        socialGroupOwnerXuid,\n        socialGroup.c_str(),\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerGetActivitiesForSocialGroupAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync_Lua(lua_State *L)\n{\n    uint64_t socialGroupOwnerXuid = GetUint64FromLua(L, 1, 2814632956486799);\n    std::string socialGroup = GetStringFromLua(L, 2, \"people\");\n\n    // CODE SNIPPET START: XblMultiplayerGetActivitiesForSocialGroupAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize{ 0 };\n        HRESULT hr = XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize(asyncBlock, &resultSize);\n        LogToFile(\"activityCount %d\", resultSize); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            if (resultSize > 0)\n            {\n                size_t count{ 0 };\n                std::vector<char> buffer(resultSize, 0);\n                XblMultiplayerActivityDetails* activityDetails{};\n                hr = XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResult(asyncBlock, resultSize, buffer.data(), &activityDetails, &count, nullptr);\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        socialGroupOwnerXuid,\n        socialGroup.c_str(),\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerGetActivitiesForUsersAsync_Lua(lua_State *L)\n{\n    uint64_t xuid1 = GetUint64FromLua(L, 1, Data()->m_multiDeviceManager->GetRemoteXuid());\n    if (xuid1 == 0) xuid1 = 2814636782672891;\n\n    // CODE SNIPPET START: XblMultiplayerGetActivitiesForUsersAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (SUCCEEDED(hr))\n        {\n            size_t resultCount{ 0 };\n            hr = XblMultiplayerGetActivitiesForUsersResultCount(asyncBlock, &resultCount);\n            if (SUCCEEDED(hr))\n            {\n                std::vector<XblMultiplayerActivityDetails> activityDetails(resultCount);\n                hr = XblMultiplayerGetActivitiesForUsersResult(asyncBlock, resultCount, activityDetails.data());\n                if (SUCCEEDED(hr))\n                {\n                    if (resultCount > 0)\n                    {\n                        std::string handleIdStr = activityDetails[0].HandleId;\n                        LogToScreen(\"Joining lobby via handle %s\", handleIdStr.c_str());\n                        MPState()->activityHandle = handleIdStr; // CODE SNIP SKIP\n                    }\n                    else\n                    {\n                        if (Data()->m_multiDeviceManager->GetRemoteXuid() != 0)\n                        {\n                            LogToScreen(\"No activity handle to join.  Failing...\");\n                            hr = E_FAIL;\n                        }\n                    }\n                }\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetActivitiesForUsersAsync\"); // CODE SNIP SKIP\n    };\n\n    uint64_t xuids[1] = {};\n    xuids[0] = xuid1;\n    size_t xuidsCount = 1;\n\n    HRESULT hr = XblMultiplayerGetActivitiesForUsersAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        xuids,\n        xuidsCount,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerGetActivitiesForUsersAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerGetActivitiesWithPropertiesForUsersAsync_Lua(lua_State *L)\n{\n    uint64_t xuid1 = GetUint64FromLua(L, 1, Data()->m_multiDeviceManager->GetRemoteXuid());\n    if (xuid1 == 0) xuid1 = 2814636782672891;\n\n    // CODE SNIPPET START: XblMultiplayerGetActivitiesForUsersAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (SUCCEEDED(hr))\n        {\n            size_t resultSize{ 0 };\n            hr = XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize(asyncBlock, &resultSize);\n            if (SUCCEEDED(hr))\n            {\n                size_t count{ 0 };\n                std::vector<char> buffer(resultSize);\n                XblMultiplayerActivityDetails* activityDetails{};\n                if (resultSize > 0)\n                {\n                    hr = XblMultiplayerGetActivitiesWithPropertiesForUsersResult(asyncBlock, resultSize, buffer.data(), &activityDetails, &count, nullptr);\n                    if (SUCCEEDED(hr))\n                    {\n                            std::string handleIdStr = activityDetails[0].HandleId;\n                            LogToScreen(\"Joining lobby via handle %s\", handleIdStr.c_str());\n                            MPState()->activityHandle = handleIdStr; // CODE SNIP SKIP\n                    }\n                }\n                else\n                {\n                    if (Data()->m_multiDeviceManager->GetRemoteXuid() != 0)\n                    {\n                        LogToScreen(\"No activity handle to join.  Failing...\");\n                        hr = E_FAIL;\n                    }\n                }\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetActivitiesWithPropertiesForUsersAsync\"); // CODE SNIP SKIP\n    };\n\n    uint64_t xuids[1] = {};\n    xuids[0] = xuid1;\n    size_t xuidsCount = 1;\n\n    HRESULT hr = XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        xuids,\n        xuidsCount,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerGetActivitiesWithPropertiesForUsersAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSetSubscriptionsEnabled_Lua(lua_State *L)\n{\n\n    bool enabled = GetBoolFromLua(L, 1, true);\n    XblContextHandle xboxLiveContext = (XblContextHandle)GetUint64FromLua(L, 2, (uint64_t)Data()->xboxLiveContext);\n\n    // CODE SNIPPET START: XblMultiplayerSetSubscriptionsEnabled\n    HRESULT hr = XblMultiplayerSetSubscriptionsEnabled(xboxLiveContext, enabled);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSetSubscriptionsEnabled: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"enabled: %d\", enabled);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSubscriptionsEnabled_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSubscriptionsEnabled\n    bool enabled = XblMultiplayerSubscriptionsEnabled(Data()->xboxLiveContext);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSubscriptionsEnabled\");\n    LogToFile(\"enabled: %d\", enabled);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerAddSessionChangedHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerAddSessionChangedHandler\n    void* context = nullptr;\n    XblFunctionContext fnContext = XblMultiplayerAddSessionChangedHandler(\n        Data()->xboxLiveContext,\n        [](_In_opt_ void*, _In_ XblMultiplayerSessionChangeEventArgs args)\n    {\n        LogToFile(\"XblMultiplayerAddSessionChangedHandler\");\n        LogToFile(\"ChangeNumber: %d\", args.ChangeNumber);\n        CallLuaFunctionWithHr(S_OK, \"OnXblMultiplayerAddSessionChangedHandler\"); // CODE SNIP SKIP\n    },\n        context);\n    // CODE SNIPPET END\n    MPState()->sessionChange = fnContext;\n\n    LogToFile(\"XblMultiplayerAddSessionChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerRemoveSessionChangedHandler_Lua(lua_State *L)\n{\n    XblFunctionContext fnContext = MPState()->sessionChange;\n    // CODE SNIPPET START: XblMultiplayerRemoveSessionChangedHandler\n    XblMultiplayerRemoveSessionChangedHandler(Data()->xboxLiveContext, fnContext);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerRemoveSessionChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerAddSubscriptionLostHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerAddSubscriptionLostHandler\n    void* context = nullptr;\n    XblFunctionContext fnContext = XblMultiplayerAddSubscriptionLostHandler(\n        Data()->xboxLiveContext,\n        [](_In_opt_ void*)\n    {\n        LogToFile(\"XblMultiplayerAddSubscriptionLostHandler\");\n        CallLuaFunctionWithHr(S_OK, \"OnXblMultiplayerAddSubscriptionLostHandler\"); // CODE SNIP SKIP\n    },\n        context);\n    // CODE SNIPPET END\n    MPState()->lostHandler = fnContext;\n\n    LogToFile(\"XblMultiplayerAddSubscriptionLostHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerRemoveSubscriptionLostHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerRemoveSubscriptionLostHandler\n    XblMultiplayerRemoveSubscriptionLostHandler(\n        Data()->xboxLiveContext,\n        MPState()->lostHandler);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerRemoveSubscriptionLostHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSearchHandleDuplicateHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleDuplicateHandle\n    XblMultiplayerSearchHandle duplicate{ nullptr };\n\n    HRESULT hr = XblMultiplayerSearchHandleDuplicateHandle(\n        MPState()->searchHandle,\n        &duplicate\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        XblMultiplayerSearchHandleCloseHandle(duplicate);\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleDuplicateHandle: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleCloseHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleCloseHandle\n    XblMultiplayerSearchHandleCloseHandle(MPState()->searchHandle);\n    MPState()->searchHandle = nullptr;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleCloseHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerSearchHandleGetSessionReference_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetSessionReference\n    XblMultiplayerSessionReference sessionRef{};\n\n    HRESULT hr = XblMultiplayerSearchHandleGetSessionReference(\n        MPState()->searchHandle,\n        &sessionRef\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetSessionReference: hr=%s\", ConvertHR(hr).c_str());\n    LogSessionRef(&sessionRef);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetId_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetId\n    const char* handleId{ nullptr };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetId(\n        MPState()->searchHandle,\n        &handleId\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetId: hr=%s\", ConvertHR(hr).data());\n    LogToFile(\"Search Handle Id: %s\", handleId);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetSessionOwnerXuids_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetSessionOwnerXuids\n    const uint64_t* xuids{ nullptr };\n    size_t xuidsCount{ 0 };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetSessionOwnerXuids(\n        MPState()->searchHandle,\n        &xuids,\n        &xuidsCount\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetSessionOwnerXuids: hr=%s\", ConvertHR(hr).data());\n    LogToFile(\"There are %u session owners:\", xuidsCount);\n    for (auto i = 0u; i < xuidsCount; ++i)\n    {\n        LogToFile(\"\\t%u\", xuids[i]);\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetTags_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetTags\n    const XblMultiplayerSessionTag* tags{ nullptr };\n    size_t tagsCount{ 0 };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetTags(\n        MPState()->searchHandle,\n        &tags,\n        &tagsCount\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetTags: hr=%s\", ConvertHR(hr).data());\n    LogToFile(\"There are %u tags for the session:\", tagsCount);\n    for (auto i = 0u; i < tagsCount; ++i)\n    {\n        LogToFile(\"\\t%s\", tags[i].value);\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetStringAttributes_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetStringAttributes\n    const XblMultiplayerSessionStringAttribute* attributes{ nullptr };\n    size_t attributesCount{ 0 };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetStringAttributes(\n        MPState()->searchHandle,\n        &attributes,\n        &attributesCount\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetStringAttributes: hr=%s\", ConvertHR(hr).data());\n    LogToFile(\"There are %u string attributes for the session:\", attributesCount);\n    for (auto i = 0u; i < attributesCount; ++i)\n    {\n        LogToFile(\"\\t%s : %s\", attributes[i].name, attributes[i].value);\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetNumberAttributes_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetNumberAttributes\n    const XblMultiplayerSessionNumberAttribute* attributes{ nullptr };\n    size_t attributesCount{ 0 };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetNumberAttributes(\n        MPState()->searchHandle,\n        &attributes,\n        &attributesCount\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetNumberAttributes: hr=%s\", ConvertHR(hr).data());\n    LogToFile(\"There are %u number attributes for the session:\", attributesCount);\n    for (auto i = 0u; i < attributesCount; ++i)\n    {\n        LogToFile(\"\\t%s : %f\", attributes[i].name, attributes[i].value);\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetVisibility_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetVisibility\n    XblMultiplayerSessionVisibility visibility{ XblMultiplayerSessionVisibility::Unknown };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetVisibility(\n        MPState()->searchHandle,\n        &visibility\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetVisibility: visibility=%u, hr=%s\", visibility, ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetJoinRestriction_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetJoinRestriction\n    XblMultiplayerSessionRestriction joinRestriction{ XblMultiplayerSessionRestriction::Unknown };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetJoinRestriction(\n        MPState()->searchHandle,\n        &joinRestriction\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetJoinRestriction: restriction=%u, hr=%s\", joinRestriction, ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetSessionClosed_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetSessionClosed\n    bool closed{ false };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetSessionClosed(\n        MPState()->searchHandle,\n        &closed\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetSessionClosed: closed=%d, hr=%s\", closed, ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetMemberCounts_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetMemberCounts\n    size_t currentMembers{ 0 };\n    size_t maxMembers{ 0 };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetMemberCounts(\n        MPState()->searchHandle,\n        &maxMembers,\n        &currentMembers\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetMemberCounts: max members=%u, current members=%u hr=%s\", maxMembers, currentMembers, ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetCreationTime_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetCreationTime\n    time_t creationTime{ 0 };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetCreationTime(\n        MPState()->searchHandle,\n        &creationTime\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetCreationTime: creation time=%u hr=%s\", creationTime, ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSearchHandleGetCustomSessionPropertiesJson_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerSearchHandleGetCustomSessionPropertiesJson\n    const char* properties{ nullptr };\n\n    HRESULT hr = XblMultiplayerSearchHandleGetCustomSessionPropertiesJson(\n        MPState()->searchHandle,\n        &properties\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerSearchHandleGetCustomSessionPropertiesJson: properties=%s hr=%s\", properties, ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerCreateSearchHandleAsync_Lua(lua_State *L)\n{\n    auto xblContextHandle = Data()->xboxLiveContext;\n    auto xblMultiplayerSessionReference = MPState()->sessionRef;\n\n    // CODE SNIPPET START: XblMultiplayerCreateSearchHandleAsync_C\n    size_t tagsCount = 1;\n    XblMultiplayerSessionTag tags[1] = {};\n    tags[0] = XblMultiplayerSessionTag{ \"SessionTag\" };\n\n    size_t numberAttributesCount = 1;\n    XblMultiplayerSessionNumberAttribute numberAttributes[1] = {};\n    numberAttributes[0] = XblMultiplayerSessionNumberAttribute{ \"numberattributename\", 1.1 };\n\n    size_t strAttributesCount = 1;\n    XblMultiplayerSessionStringAttribute strAttributes[1] = {};\n    strAttributes[0] = XblMultiplayerSessionStringAttribute{ \"stringattributename\", \"string attribute value\" };\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblMultiplayerSearchHandle searchHandle{ nullptr };\n        HRESULT hr = XblMultiplayerCreateSearchHandleResult(asyncBlock, &searchHandle);\n        MPState()->searchHandle = searchHandle; // CODE SNIP SKIP\n\n        LogToFile(\"XblMultiplayerCreateSearchHandleResult completed with result=%s\", ConvertHR(hr).data()); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            const char* handleId{ nullptr };\n            XblMultiplayerSearchHandleGetId(searchHandle, &handleId);\n            LogToFile(\"Search handle id = %s\", handleId); // CODE SNIP SKIP\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerCreateSearchHandleAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMultiplayerCreateSearchHandleAsync(\n        xblContextHandle,\n        &xblMultiplayerSessionReference,\n        tags,\n        tagsCount,\n        numberAttributes,\n        numberAttributesCount,\n        strAttributes,\n        strAttributesCount,\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerCreateSearchHandleAsync: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerDeleteSearchHandleAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblMultiplayerDeleteSearchHandleAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, true);\n        LogToFile(\"XblMultiplayerDeleteSearchHandleAsync completed with result = %s\", ConvertHR(hr).data());\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerDeleteSearchHandleAsync\"); // CODE SNIP SKIP\n    };\n\n    const char* handleId{ nullptr };\n    XblMultiplayerSearchHandleGetId(MPState()->searchHandle, &handleId);\n\n    HRESULT hr = XblMultiplayerDeleteSearchHandleAsync(\n        Data()->xboxLiveContext,\n        handleId,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerDeleteSearchHandleAsync: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerGetSearchHandlesAsync_Lua(lua_State *L)\n{\n    auto xblContextHandle = Data()->xboxLiveContext;\n    auto scid = Data()->scid;\n\n    // CODE SNIPPET START: XblMultiplayerGetSearchHandlesAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultCount{ 0 };\n        auto hr = XblMultiplayerGetSearchHandlesResultCount(asyncBlock, &resultCount);\n        if (SUCCEEDED(hr) && resultCount > 0)\n        {\n            auto handles = new XblMultiplayerSearchHandle[resultCount];\n\n            hr = XblMultiplayerGetSearchHandlesResult(asyncBlock, handles, resultCount);\n            LogToFile(\"XblMultiplayerGetSearchHandlesResult: hr=%s\", ConvertHR(hr).data()); // CODE SNIP SKIP\n\n            if (SUCCEEDED(hr))\n            {\n                LogToFile(\"Got %u search handles:\", resultCount); // CODE SNIP SKIP\n\n                // Process handles\n                for (auto i = 0u; i < resultCount; ++i)\n                {\n                    const char* handleId{ nullptr };\n                    XblMultiplayerSearchHandleGetId(handles[i], &handleId);\n                    LogToFile(\"\\t%s\", handleId); // CODE SNIP SKIP\n\n                    XblMultiplayerSearchHandleCloseHandle(handles[i]);\n                }\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetSearchHandlesAsync\"); // CODE SNIP SKIP\n    };\n\n    const char* sessionName{ \"MinGameSession\" };\n    const char* orderByAttribute{ nullptr };\n    bool orderAscending{ false };\n    const char* searchFilter{ nullptr };\n    const char* socialGroup{ nullptr };\n\n    HRESULT hr = XblMultiplayerGetSearchHandlesAsync(\n        xblContextHandle,\n        scid,\n        sessionName,\n        orderByAttribute,\n        orderAscending,\n        searchFilter,\n        socialGroup,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblMultiplayerGetSearchHandlesAsync: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerSetTransferHandleAsync_Lua(lua_State* L)\n{\n    // Params:\n    // 1) Target session index\n    // 2) Origin session index\n    auto targetIndex{ GetUint64FromLua(L, 1, 0) };\n    auto originIndex{ GetUint64FromLua(L, 2, 0) };\n\n    // CODE SNIPPET START: XblMultiplayerSetTransferHandleAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblMultiplayerSessionHandleId id{};\n        auto hr = XblMultiplayerSetTransferHandleResult(asyncBlock, &id);\n        if (SUCCEEDED(hr))\n        {\n            LogToFile(\"Sucessfully set transfer handle, ID = %s\", id.value);\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerSetTransferHandleAsync\"); // CODE SNIP SKIP\n    };\n\n    auto targetReference = XblMultiplayerSessionSessionReference(MPState()->sessionHandles[static_cast<uint32_t>(targetIndex)]);\n    auto originReference = XblMultiplayerSessionSessionReference(MPState()->sessionHandles[static_cast<uint32_t>(originIndex)]);\n\n    HRESULT hr = S_OK;\n    if (originReference != nullptr && targetReference != nullptr)\n    {\n        hr = XblMultiplayerSetTransferHandleAsync(\n            Data()->xboxLiveContext,\n            *targetReference,\n            *originReference,\n            asyncBlock.get()\n        );\n        if (SUCCEEDED(hr))\n        {\n            // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n            // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n            asyncBlock.release();\n        }\n    }\n\n    // CODE SNIP END\n\n    LogToFile(\"XblMultiplayerSetTransferHandleAsync: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMatchmakingCreateTicket_Lua(lua_State* L)\n{\n    // Params:\n    // 1) matchmaking hopper name\n    // 2) attributes json\n    // 3) SCID\n    // 4) session template name\n    // 5) session name\n    // 6) timeout in seconds\n    auto hopperName{ GetStringFromLua(L, 1, \"PlayerSkillNoQoS\") };\n    auto attributesJson{ GetStringFromLua(L, 2, \"{}\") };\n    uint32_t timeoutInSeconds = GetUint32FromLua(L, 6, 100);\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblMatchmakingCreateMatchTicketAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblCreateMatchTicketResponse result{};\n\n        auto hr = XblMatchmakingCreateMatchTicketResult(asyncBlock, &result);\n        LogToScreen(\"XblMatchmakingCreateMatchTicketResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            if (Data()->matchTicketResponse) { // CODE SNIP SKIP\n                delete(Data()->matchTicketResponse); // CODE SNIP SKIP\n            } // CODE SNIP SKIP\n\n            Data()->matchTicketResponse = new XblCreateMatchTicketResponse(result); // CODE SNIP SKIP\n            LogToScreen(\"CreateMatchTicketResponse->matchTicketId: %s\", result.matchTicketId); // CODE SNIP SKIP\n            LogToScreen(\"CreateMatchTicketResponse->estimatedWaitTime: %d\", result.estimatedWaitTime); // CODE SNIP SKIP\t\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMatchmakingCreateTicket\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMatchmakingCreateMatchTicketAsync(\n        Data()->xboxLiveContext,\n        MPState()->sessionRef,\n        Data()->scid,\n        hopperName.c_str(),\n        timeoutInSeconds,\n        XblPreserveSessionMode::Never,\n        attributesJson.c_str(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblMatchmakingCreateMatchTicketAsync: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMatchmakingGetMatchTicketDetails_Lua(lua_State* L)\n{\n    // Params:\n    // 1) matchmaking hopper name\n    // 2) SCID\n    // 3) match ticket ID\n    std::string hopperName{ GetStringFromLua(L, 1, \"PlayerSkillNoQoS\") };\n    std::string scid = GetStringFromLua(L, 2, Data()->scid);\n    std::string ticketId = GetStringFromLua(L, 3, Data()->matchTicketResponse->matchTicketId);\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblMatchmakingGetMatchTicketDetailsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t bufferSize;\n        auto hr = XblMatchmakingGetMatchTicketDetailsResultSize(asyncBlock, &bufferSize);\n        LogToFile(\"XblMatchmakingGetMatchTicketDetailsResultSize: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(bufferSize, 0);\n            XblMatchTicketDetailsResponse* resultPtr;\n            hr = XblMatchmakingGetMatchTicketDetailsResult(asyncBlock, bufferSize, buffer.data(), &resultPtr, nullptr);\n            LogToScreen(\"XblMatchmakingGetMatchTicketDetailsResult: hr= %s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n            if (SUCCEEDED(hr)) // CODE SNIP SKIP\n            { // CODE SNIP SKIP\n                LogToScreen(\"XblMatchTicketDetailsResponse->matchStatus: %d\", resultPtr->matchStatus); // CODE SNIP SKIP\n                LogToScreen(\"XblMatchTicketDetailsResponse->estimatedWaitTime: %d\", resultPtr->estimatedWaitTime); // CODE SNIP SKIP\n                LogToScreen(\"XblMatchTicketDetailsResponse->preserveSession: %d\", resultPtr->preserveSession); // CODE SNIP SKIP\n                LogToScreen(\"XblMatchTicketDetailsResponse->ticketSession: SCID: %s, Session Name: %s, Session Template Name: %s\", resultPtr->ticketSession.Scid, resultPtr->ticketSession.SessionName, resultPtr->ticketSession.SessionTemplateName); // CODE SNIP SKIP\n                LogToScreen(\"XblMatchTicketDetailsResponse->targetSession: SCID: %s, Session Name: %s, Session Template Name: %s\", resultPtr->targetSession.Scid, resultPtr->targetSession.SessionName, resultPtr->targetSession.SessionTemplateName); // CODE SNIP SKIP\n                \n                if (resultPtr->ticketAttributes != nullptr)\n                {\n                    LogToScreen(\"XblMatchTicketDetailsResponse->TicketAttributes: %d\", resultPtr->ticketAttributes); // CODE SNIP SKIP\n                }\n            } // CODE SNIP SKIP\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMatchmakingGetMatchTicketDetails\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMatchmakingGetMatchTicketDetailsAsync(\n        Data()->xboxLiveContext,\n        scid.c_str(),\n        hopperName.c_str(),\n        ticketId.c_str(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblMatchmakingGetMatchTicketDetailsAsync: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMatchmakingGetHopperStatistics_Lua(lua_State* L)\n{\n    // Params:\n    // 1) matchmaking hopper name\n    // 2) SCID\n    std::string hopperName{ GetStringFromLua(L, 1, \"PlayerSkillNoQoS\") };\n    std::string scid = GetStringFromLua(L, 2, Data()->scid);\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblMatchmakingGetHopperStatisticsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t bufferSize;\n        HRESULT hr = XblMatchmakingGetHopperStatisticsResultSize(asyncBlock, &bufferSize);\n        LogToScreen(\"XblMatchmakingGetHopperStatisticsResultSize: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(bufferSize, 0);\n            XblHopperStatisticsResponse* result{};\n            hr = XblMatchmakingGetHopperStatisticsResult(asyncBlock, bufferSize, buffer.data(), &result, nullptr);\n            LogToScreen(\"XblMatchmakingGetHopperStatisticsResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n            if (SUCCEEDED(hr)) // CODE SNIP SKIP\n            { // CODE SNIP SKIP\n                LogToScreen(\"XblHopperStatisticsResponse->hopperName: %s\", result->hopperName); // CODE SNIP SKIP\n                LogToScreen(\"XblHopperStatisticsResponse->estimatedWaitTime: %d\", result->estimatedWaitTime); // CODE SNIP SKIP\n                LogToScreen(\"XblHopperStatisticsResponse->playersWaitingToMatch: %d\", result->playersWaitingToMatch); // CODE SNIP SKIP\n\n            } // CODE SNIP SKIP\n\n            CallLuaFunctionWithHr(hr, \"OnXblMatchmakingGetHopperStatistics\"); // CODE SNIP SKIP\n        }\n    };\n\n    HRESULT hr = XblMatchmakingGetHopperStatisticsAsync(\n        Data()->xboxLiveContext,\n        scid.c_str(),\n        hopperName.c_str(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblMatchmakingGetHopperStatisticsAsync: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMatchmakingDeleteMatchTicket_Lua(lua_State* L)\n{\n    // Params:\n    // 1) matchmaking hopper name\n    // 2) SCID\n    // 3) ticket ID\n    std::string hopperName{ GetStringFromLua(L, 1, \"PlayerSkillNoQoS\") };\n    std::string scid = GetStringFromLua(L, 2, Data()->scid);\n    std::string ticketId = GetStringFromLua(L, 3, Data()->matchTicketResponse->matchTicketId);\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblMatchmakingDeleteMatchTicketAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        CallLuaFunctionWithHr(S_OK, \"OnXblMatchmakingDeleteMatchTicket\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblMatchmakingDeleteMatchTicketAsync(\n        Data()->xboxLiveContext,\n        scid.c_str(),\n        hopperName.c_str(),\n        ticketId.c_str(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblMatchmakingDeleteMatchTicketAsync: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblMultiplayer()\n{\n    lua_register(Data()->L, \"XblMultiplayerSessionReferenceCreate\", XblMultiplayerSessionReferenceCreate_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionReferenceParseFromUriPath\", XblMultiplayerSessionReferenceParseFromUriPath_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionReferenceIsValid\", XblMultiplayerSessionReferenceIsValid_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCreateHandle\", XblMultiplayerSessionCreateHandle_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionDuplicateHandle\", XblMultiplayerSessionDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCloseHandle\", XblMultiplayerSessionCloseHandle_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionTimeOfSession\", XblMultiplayerSessionTimeOfSession_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionGetInitializationInfo\", XblMultiplayerSessionGetInitializationInfo_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSubscribedChangeTypes\", XblMultiplayerSessionSubscribedChangeTypes_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionHostCandidates\", XblMultiplayerSessionHostCandidates_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSessionReference\", XblMultiplayerSessionSessionReference_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSessionConstants\", XblMultiplayerSessionSessionConstants_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetMaxMembersInSession\", XblMultiplayerSessionConstantsSetMaxMembersInSession_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetVisibility\", XblMultiplayerSessionConstantsSetVisibility_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetTimeouts\", XblMultiplayerSessionConstantsSetTimeouts_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetQosConnectivityMetrics\", XblMultiplayerSessionConstantsSetQosConnectivityMetrics_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetMemberInitialization\", XblMultiplayerSessionConstantsSetMemberInitialization_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetPeerToPeerRequirements\", XblMultiplayerSessionConstantsSetPeerToPeerRequirements_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetPeerToHostRequirements\", XblMultiplayerSessionConstantsSetPeerToHostRequirements_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson\", XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetCapabilities\", XblMultiplayerSessionConstantsSetCapabilities_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionConstantsSetCloudComputePackageJson\", XblMultiplayerSessionConstantsSetCloudComputePackageJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSessionProperties\", XblMultiplayerSessionSessionProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionPropertiesSetKeywords\", XblMultiplayerSessionPropertiesSetKeywords_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionPropertiesSetJoinRestriction\", XblMultiplayerSessionPropertiesSetJoinRestriction_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionPropertiesSetReadRestriction\", XblMultiplayerSessionPropertiesSetReadRestriction_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionPropertiesSetTurnCollection\", XblMultiplayerSessionPropertiesSetTurnCollection_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionRoleTypes\", XblMultiplayerSessionRoleTypes_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionGetRoleByName\", XblMultiplayerSessionGetRoleByName_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetMutableRoleSettings\", XblMultiplayerSessionSetMutableRoleSettings_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionMembers\", XblMultiplayerSessionMembers_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionGetMember\", XblMultiplayerSessionGetMember_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionMatchmakingServer\", XblMultiplayerSessionMatchmakingServer_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionMembersAccepted\", XblMultiplayerSessionMembersAccepted_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionRawServersJson\", XblMultiplayerSessionRawServersJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetRawServersJson\", XblMultiplayerSessionSetRawServersJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionEtag\", XblMultiplayerSessionEtag_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUser\", XblMultiplayerSessionCurrentUser_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionGetInfo\", XblMultiplayerSessionGetInfo_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionWriteStatus\", XblMultiplayerSessionWriteStatus_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionAddMemberReservation\", XblMultiplayerSessionAddMemberReservation_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionJoin\", XblMultiplayerSessionJoin_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetInitializationSucceeded\", XblMultiplayerSessionSetInitializationSucceeded_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetHostDeviceToken\", XblMultiplayerSessionSetHostDeviceToken_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetMatchmakingServerConnectionPath\", XblMultiplayerSessionSetMatchmakingServerConnectionPath_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetClosed\", XblMultiplayerSessionSetClosed_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetLocked\", XblMultiplayerSessionSetLocked_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetAllocateCloudCompute\", XblMultiplayerSessionSetAllocateCloudCompute_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetMatchmakingResubmit\", XblMultiplayerSessionSetMatchmakingResubmit_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetServerConnectionStringCandidates\", XblMultiplayerSessionSetServerConnectionStringCandidates_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetSessionChangeSubscription\", XblMultiplayerSessionSetSessionChangeSubscription_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionLeave\", XblMultiplayerSessionLeave_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetStatus\", XblMultiplayerSessionCurrentUserSetStatus_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64\", XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64_Lua);\n    lua_register(Data()->L, \"XblFormatSecureDeviceAddress\", XblFormatSecureDeviceAddress_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetRoles\", XblMultiplayerSessionCurrentUserSetRoles_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetMembersInGroup\", XblMultiplayerSessionCurrentUserSetMembersInGroup_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetGroups\", XblMultiplayerSessionCurrentUserSetGroups_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetEncounters\", XblMultiplayerSessionCurrentUserSetEncounters_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetQosMeasurements\", XblMultiplayerSessionCurrentUserSetQosMeasurements_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetServerQosMeasurements\", XblMultiplayerSessionCurrentUserSetServerQosMeasurements_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserSetCustomPropertyJson\", XblMultiplayerSessionCurrentUserSetCustomPropertyJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson\", XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson\", XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionSetCustomPropertyJson\", XblMultiplayerSessionSetCustomPropertyJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionDeleteCustomPropertyJson\", XblMultiplayerSessionDeleteCustomPropertyJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSessionCompare\", XblMultiplayerSessionCompare_Lua);\n    lua_register(Data()->L, \"XblMultiplayerWriteSessionAsync\", XblMultiplayerWriteSessionAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerWriteSessionByHandleAsync\", XblMultiplayerWriteSessionByHandleAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetSessionAsync\", XblMultiplayerGetSessionAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetSessionByHandleAsync\", XblMultiplayerGetSessionByHandleAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerQuerySessionsAsync\", XblMultiplayerQuerySessionsAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSetActivityAsync\", XblMultiplayerSetActivityAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerClearActivityAsync\", XblMultiplayerClearActivityAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSendInvitesAsync\", XblMultiplayerSendInvitesAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetActivitiesForSocialGroupAsync\", XblMultiplayerGetActivitiesForSocialGroupAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetActivitiesForUsersAsync\", XblMultiplayerGetActivitiesForUsersAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync\", XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetActivitiesWithPropertiesForUsersAsync\", XblMultiplayerGetActivitiesWithPropertiesForUsersAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSetSubscriptionsEnabled\", XblMultiplayerSetSubscriptionsEnabled_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSubscriptionsEnabled\", XblMultiplayerSubscriptionsEnabled_Lua);\n    lua_register(Data()->L, \"XblMultiplayerAddSessionChangedHandler\", XblMultiplayerAddSessionChangedHandler_Lua);\n    lua_register(Data()->L, \"XblMultiplayerRemoveSessionChangedHandler\", XblMultiplayerRemoveSessionChangedHandler_Lua);\n    lua_register(Data()->L, \"XblMultiplayerAddSubscriptionLostHandler\", XblMultiplayerAddSubscriptionLostHandler_Lua);\n    lua_register(Data()->L, \"XblMultiplayerRemoveSubscriptionLostHandler\", XblMultiplayerRemoveSubscriptionLostHandler_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleDuplicateHandle\", XblMultiplayerSearchHandleDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleCloseHandle\", XblMultiplayerSearchHandleCloseHandle_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetSessionReference\", XblMultiplayerSearchHandleGetSessionReference_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetId\", XblMultiplayerSearchHandleGetId_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetSessionOwnerXuids\", XblMultiplayerSearchHandleGetSessionOwnerXuids_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetTags\", XblMultiplayerSearchHandleGetTags_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetStringAttributes\", XblMultiplayerSearchHandleGetStringAttributes_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetNumberAttributes\", XblMultiplayerSearchHandleGetNumberAttributes_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetVisibility\", XblMultiplayerSearchHandleGetVisibility_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetJoinRestriction\", XblMultiplayerSearchHandleGetJoinRestriction_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetSessionClosed\", XblMultiplayerSearchHandleGetSessionClosed_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetMemberCounts\", XblMultiplayerSearchHandleGetMemberCounts_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetCreationTime\", XblMultiplayerSearchHandleGetCreationTime_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSearchHandleGetCustomSessionPropertiesJson\", XblMultiplayerSearchHandleGetCustomSessionPropertiesJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerCreateSearchHandleAsync\", XblMultiplayerCreateSearchHandleAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerDeleteSearchHandleAsync\", XblMultiplayerDeleteSearchHandleAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerGetSearchHandlesAsync\", XblMultiplayerGetSearchHandlesAsync_Lua);\n    lua_register(Data()->L, \"XblMultiplayerSetTransferHandleAsync\", XblMultiplayerSetTransferHandleAsync_Lua);\n\n\n    // XSAPI Matchmaking APIs\n    lua_register(Data()->L, \"XblMatchmakingCreateTicket\", XblMatchmakingCreateTicket_Lua);\n    lua_register(Data()->L, \"XblMatchmakingGetMatchTicketDetails\", XblMatchmakingGetMatchTicketDetails_Lua);\n    lua_register(Data()->L, \"XblMatchmakingGetHopperStatistics\", XblMatchmakingGetHopperStatistics_Lua);\n    lua_register(Data()->L, \"XblMatchmakingDeleteMatchTicket\", XblMatchmakingDeleteMatchTicket_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_multiplayer_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include <atomic>\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 4365 )\n#pragma warning( disable : 4061 )\n#pragma warning( disable : 4996 )\n#endif\n\n#include \"rapidjson/document.h\"\n\nstatic std::thread s_doWorkThread{};\nstatic std::atomic<bool> s_doWork{ false };\n\nvoid CheckMemberFound(XblMultiplayerSessionType sessionType, uint64_t xuid)\n{\n    size_t count{};\n    std::vector<XblMultiplayerManagerMember> members{};\n    if (sessionType == XblMultiplayerSessionType::LobbySession)\n    {\n        count = XblMultiplayerManagerLobbySessionMembersCount();\n        assert(count > 0);\n        members = std::vector<XblMultiplayerManagerMember>(count);\n        XblMultiplayerManagerLobbySessionMembers(count, members.data());\n    }\n    else\n    {\n        count = XblMultiplayerManagerGameSessionMembersCount();\n        assert(count > 0);\n        members = std::vector<XblMultiplayerManagerMember>(count);\n        XblMultiplayerManagerGameSessionMembers(count, members.data());\n    }\n\n    bool memberFound{ false };\n    for (auto member : members)\n    {\n        if (member.Xuid == xuid)\n        {\n            memberFound = true;\n            break;\n        }\n    }\n\n    assert(memberFound);\n}\n\nstd::vector<XblMultiplayerManagerMember> GetSessionMembers(XblMultiplayerSessionType sessionType)\n{\n    size_t count{};\n    std::vector<XblMultiplayerManagerMember> members{};\n    if (sessionType == XblMultiplayerSessionType::LobbySession)\n    {\n        count = XblMultiplayerManagerLobbySessionMembersCount();\n        members = std::vector<XblMultiplayerManagerMember>(count);\n        if (count > 0)\n        {\n            XblMultiplayerManagerLobbySessionMembers(count, members.data());\n        }\n    }\n    else\n    {\n        count = XblMultiplayerManagerGameSessionMembersCount();\n        members = std::vector<XblMultiplayerManagerMember>(count);\n        if (count > 0)\n        {\n            XblMultiplayerManagerGameSessionMembers(count, members.data());\n        }\n    }\n\n    return members;\n}\n\nHRESULT MultiplayerManagerDoWork()\n{\n    // CODE SNIPPET START: XblMultiplayerManagerDoWork_C\n    size_t eventCount{ 0 };\n    const XblMultiplayerEvent* events{ nullptr };\n    HRESULT hr = XblMultiplayerManagerDoWork(&events, &eventCount);\n    if (FAILED(hr))\n    {\n        // Handle failure\n        return hr; // CODE SNIP SKIP\n    }\n\n    for (auto i = 0u; i < eventCount; ++i)\n    {\n        switch (events[i].EventType)\n        {\n            case XblMultiplayerEventType::MemberJoined:\n            {\n                // Handle MemberJoined\n                size_t memberCount = 0;\n                hr = XblMultiplayerEventArgsMembersCount(events[i].EventArgsHandle, &memberCount);\n                assert(SUCCEEDED(hr));\n\n                std::vector<XblMultiplayerManagerMember> eventMembers(memberCount);\n                hr = XblMultiplayerEventArgsMembers(events[i].EventArgsHandle, memberCount, eventMembers.data());\n                assert(SUCCEEDED(hr));\n                // DOTS\n\n                auto sessionMembers{ GetSessionMembers(events[i].SessionType) };\n                assert(memberCount <= sessionMembers.size());\n\n                for (auto eventMember : eventMembers)\n                {\n                    bool memberFound{ false };\n                    for (auto sessionMember : sessionMembers)\n                    {\n                        if (eventMember.Xuid == sessionMember.Xuid)\n                        {\n                            memberFound = true;\n                            break;\n                        }\n                    }\n\n                    assert(memberFound);\n                }\n\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::MemberJoined\"); // CODE SNIP SKIP\n                for (auto& member : eventMembers)\n                {\n                    LogToScreen(\"    member %llu\", static_cast<unsigned long long>(member.Xuid));\n                }\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_MemberJoined\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::SessionPropertyChanged:\n            {\n                // Handle SessionPropertyChanged\n                const char* changedProperty{ nullptr };\n                hr = XblMultiplayerEventArgsPropertiesJson(events[i].EventArgsHandle, &changedProperty);\n                assert(SUCCEEDED(hr));\n                // DOTS\n\n                rapidjson::Document changedDoc;\n                changedDoc.Parse(changedProperty);\n\n                rapidjson::Document doc;\n                if (events[i].SessionType == XblMultiplayerSessionType::LobbySession)\n                {\n                    doc.Parse(XblMultiplayerManagerLobbySessionPropertiesJson());\n                }\n                else\n                {\n                    doc.Parse(XblMultiplayerManagerGameSessionPropertiesJson());\n                }\n\n                for (auto& member : changedDoc.GetObject())\n                {\n                    assert(doc.HasMember(member.name));\n                    assert(doc[member.name] == member.value);\n                    UNREFERENCED_PARAMETER(member);\n                }\n\n                // CODE SKIP START\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::SessionPropertyChanged\"); // CODE SNIP SKIP\n                if (events[i].SessionType == XblMultiplayerSessionType::GameSession)\n                {\n                    CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_GameSessionPropertyChanged\"); // CODE SNIP SKIP\n                }\n                else\n                {\n                    CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_LobbySessionPropertyChanged\"); // CODE SNIP SKIP\n                }\n                // CODE SKIP END\n                break;\n            }\n            // DOTS\n            // CODE SKIP START\n\n            case XblMultiplayerEventType::UserAdded:\n            {\n                auto h = events[i].Result;\n                if (SUCCEEDED(h))\n                {\n                    // Handle UserAdded\n                    uint64_t xuid = 0;\n                    hr = XblMultiplayerEventArgsXuid(events[i].EventArgsHandle, &xuid);\n                    assert(SUCCEEDED(hr));\n\n                    CheckMemberFound(events[i].SessionType, xuid);\n                    LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::UserAdded. XUID: %llu\", static_cast<unsigned long long>(xuid)); // CODE SNIP SKIP\n                }\n           \n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_UserAdded\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::UserRemoved:\n            {\n                // Handle UserRemoved\n                hr = events[i].Result == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND) ? S_OK : events[i].Result;\n                if (SUCCEEDED(hr))\n                {\n                    uint64_t xuid = 0;\n                    hr = XblMultiplayerEventArgsXuid(events[i].EventArgsHandle, &xuid);\n                    assert(SUCCEEDED(hr));\n\n                    auto members{ GetSessionMembers(events[i].SessionType) };\n\n                    for (auto member : members)\n                    {\n                        assert(xuid != member.Xuid);\n                    }\n                }\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::UserRemoved\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(hr, \"OnXblMultiplayerEventType_UserRemoved\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::JoinLobbyCompleted:\n            {\n                // Handle JoinLobbyCompleted\n                uint64_t xuid = 0;\n                hr = XblMultiplayerEventArgsXuid(events[i].EventArgsHandle, &xuid);\n                assert(SUCCEEDED(hr));\n\n                if (SUCCEEDED(events[i].Result))\n                {\n                    CheckMemberFound(events[i].SessionType, xuid);\n\n                    hr = events[i].Result == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND) ? S_OK : events[i].Result;\n                    LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::JoinLobbyCompleted\"); // CODE SNIP SKIP\n                }\n                CallLuaFunctionWithHr(hr, \"OnXblMultiplayerEventType_JoinLobbyCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::JoinGameCompleted:\n            {\n                // Handle JoinGameCompleted\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::JoinGameCompleted\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_JoinGameCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::LeaveGameCompleted:\n            {\n                // Handle LeaveGameCompleted\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::LeaveGameCompleted\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_LeaveGameCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::LocalMemberPropertyWriteCompleted:\n            {\n                // Handle LocalMemberPropertyWriteCompleted\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::LocalMemberPropertyWriteCompleted\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_LocalMemberPropertyWriteCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::InviteSent:\n            {\n                // Handle InviteSent\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::InviteSent\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_InviteSent\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::MemberLeft:\n            {\n                // Handle MemberLeft\n                size_t memberCount = 0;\n                hr = XblMultiplayerEventArgsMembersCount(events[i].EventArgsHandle, &memberCount);\n                assert(SUCCEEDED(hr));\n                assert(memberCount > 0);\n\n                std::vector<XblMultiplayerManagerMember> members(memberCount);\n                hr = XblMultiplayerEventArgsMembers(events[i].EventArgsHandle, memberCount, members.data());\n                assert(SUCCEEDED(hr));\n\n                auto sessionMembers{ GetSessionMembers(events[i].SessionType) };\n\n                for (auto remainingMember : sessionMembers)\n                {\n                    for (auto member : members)\n                    {\n                        assert(member.Xuid != remainingMember.Xuid);\n                    }\n                }\n\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::MemberLeft\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_MemberLeft\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::JoinabilityStateChanged:\n            {\n                // Handle JoinabilityStateChanged\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::JoinabilityStateChanged\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_JoinabilityStateChanged\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::HostChanged:\n            {\n                XblMultiplayerManagerMember member{};\n                hr = XblMultiplayerEventArgsMember(events[i].EventArgsHandle, &member);\n\n                XblMultiplayerManagerMember host{};\n                HRESULT hr2 = XblMultiplayerManagerLobbySessionHost(&host);\n                (void)(hr2); //suppress unused warning\n                //If a host leaves and there is no new host, XblMultiplayerEventArgsMember returns 0x80070714 HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n                //Likewise, since there is no host, XblMultiplayerManagerLobbySessionHost returns 0x80070525 HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER)\n                assert((SUCCEEDED(hr) && SUCCEEDED(hr2)) || (hr == 0x80070714 && hr2 == 0x80070525));\n\n                assert(member.Xuid == host.Xuid);\n\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::HostChanged\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_HostChanged\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::MemberPropertyChanged:\n            {\n                XblMultiplayerManagerMember member;\n                hr = XblMultiplayerEventArgsMember(events[i].EventArgsHandle, &member);\n                assert(SUCCEEDED(hr));\n\n                const char* propertiesJson = nullptr;\n                hr = XblMultiplayerEventArgsPropertiesJson(events[i].EventArgsHandle, &propertiesJson);\n                assert(SUCCEEDED(hr));\n\n                auto sessionMembers{ GetSessionMembers(events[i].SessionType) };\n\n                XblMultiplayerManagerMember sessionMember{};\n                for (size_t j = 0; j < sessionMembers.size(); ++j)\n                {\n                    if (member.Xuid == sessionMembers[j].Xuid)\n                    {\n                        sessionMember = sessionMembers[j];\n                        break;\n                    }\n                }\n                \n                assert(sessionMember.Xuid == member.Xuid);\n                assert(strcmp(sessionMember.PropertiesJson, member.PropertiesJson) == 0);\n\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::MemberPropertyChanged\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_MemberPropertyChanged\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::FindMatchCompleted:\n            {\n                XblMultiplayerMatchStatus matchStatus;\n                XblMultiplayerMeasurementFailure initializationFailureCause;\n                hr = XblMultiplayerEventArgsFindMatchCompleted(events[i].EventArgsHandle, &matchStatus, &initializationFailureCause);\n                assert(SUCCEEDED(hr));\n                assert(initializationFailureCause == XblMultiplayerMeasurementFailure::None);\n                assert(matchStatus == XblMultiplayerMatchStatus::Completed);\n                assert(XblMultiplayerManagerMatchStatus() == matchStatus);\n\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::FindMatchCompleted\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_FindMatchCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::PerformQosMeasurements:\n            {\n                XblMultiplayerPerformQoSMeasurementsArgs performQoSMeasurementsArgs;\n                hr = XblMultiplayerEventArgsPerformQoSMeasurements(events[i].EventArgsHandle, &performQoSMeasurementsArgs);\n                assert(SUCCEEDED(hr));\n\n                auto sessionMembers{ GetSessionMembers(events[i].SessionType) };\n\n                assert(performQoSMeasurementsArgs.remoteClientsSize == sessionMembers.size() - 1);\n\n                for (size_t j = 0; j < performQoSMeasurementsArgs.remoteClientsSize; ++j)\n                {\n                    bool clientFound{ false };\n                    for (size_t k = 0; k < sessionMembers.size(); ++k)\n                    {\n                        if (strcmp(sessionMembers[k].ConnectionAddress, performQoSMeasurementsArgs.remoteClients[j].connectionAddress) == 0)\n                        {\n                            clientFound = true;\n                            assert(strcmp(sessionMembers[k].DeviceToken, performQoSMeasurementsArgs.remoteClients[j].deviceToken.Value) == 0);\n                        }\n                    }\n\n                    assert(clientFound);\n                }\n\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::PerformQosMeasurements\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_PerformQosMeasurements\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted:\n            {\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_LocalMemberConnectionAddressWriteCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::SessionPropertyWriteCompleted:\n            {\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::SessionPropertyWriteCompleted\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_SessionPropertyWriteCompleted\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted:\n            {\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted\"); // CODE SNIP SKIP\n                if (events[i].Result == HTTP_E_STATUS_PRECOND_FAILED)\n                {\n                    // Request rejected due to session conflict. Evaluate the need to write again and re-submit if needed.\n                    auto fnName = events[i].SessionType == XblMultiplayerSessionType::LobbySession ? \"OnXblMultiplayerEventType_SessionSynchronizedPropertyWriteCompleted_412_LobbySession\" // CODE SNIP SKIP\n                                                                                                   : \"OnXblMultiplayerEventType_SessionSynchronizedPropertyWriteCompleted_412_GameSession\"; // CODE SNIP SKIP\n                    CallLuaFunctionWithHr(S_OK, fnName); // CODE SNIP SKIP\n                }\n                else\n                {\n                    CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_SessionSynchronizedPropertyWriteCompleted\"); // CODE SNIP SKIP\n                }\n                break;\n            }\n\n            case XblMultiplayerEventType::SynchronizedHostWriteCompleted:\n            {\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::SynchronizedHostWriteCompleted\"); // CODE SNIP SKIP\n                if (events[i].Result == HTTP_E_STATUS_PRECOND_FAILED)\n                {\n                    // Request rejected due to session conflict. Evaluate the need to write again and re-submit if needed.\n                    auto fnName = events[i].SessionType == XblMultiplayerSessionType::LobbySession ? \"OnXblMultiplayerEventType_SynchronizedHostWriteCompleted_412_LobbySession\" // CODE SNIP SKIP\n                                                                                                   : \"OnXblMultiplayerEventType_SynchronizedHostWriteCompleted_412_GameSession\"; // CODE SNIP SKIP\n                    CallLuaFunctionWithHr(S_OK, fnName); // CODE SNIP SKIP\n                }\n                else\n                {\n                    CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_SynchronizedHostWriteCompleted\"); // CODE SNIP SKIP\n                }\n                break;\n            }\n\n            case XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService:\n            {\n                LogToScreen(\"XblMultiplayerManagerDoWork event XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService\"); // CODE SNIP SKIP\n                CallLuaFunctionWithHr(events[i].Result, \"OnXblMultiplayerEventType_ClientDisconnectedFromMultiplayerService\"); // CODE SNIP SKIP\n                break;\n            }\n\n            case XblMultiplayerEventType::TournamentRegistrationStateChanged:\n            case XblMultiplayerEventType::TournamentGameSessionReady:\n            case XblMultiplayerEventType::ArbitrationComplete:\n            default:\n            {\n                LogToScreen(\"Received MPM event of type %u, hr=%s\", events[i].EventType, ConvertHR(events[i].Result).data()); // CODE SNIP SKIP\n                LogToScreen(\"XblMultiplayerManagerDoWork event Other\"); // CODE SNIP SKIP\n                break;\n            }\n        // CODE SKIP END\n        }\n    }\n    // CODE SNIPPET END\n\n    return hr;\n}\n\nint StartDoWorkLoop_Lua(lua_State* L)\n{\n    if (!s_doWork)\n    {\n        s_doWork = true;\n        s_doWorkThread = std::thread([]()\n        {\n            Data()->m_mpmDoWorkDone = false;\n            while (s_doWork && !Data()->m_quit)\n            {\n                MultiplayerManagerDoWork();\n                pal::Sleep(10);\n            }\n            Data()->m_mpmDoWorkDone = true;\n            LogToScreen(\"Exiting MPM DoWork thread\");\n        });\n    }\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid MPMStopDoWorkHelper()\n{\n    if (s_doWork)\n    {\n        s_doWork = false;\n        s_doWorkThread.join();\n    }\n}\n\nint StopDoWorkLoop_Lua(lua_State* L)\n{\n    MPMStopDoWorkHelper();\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerInitialize_Lua(lua_State* L)\n{\n    const char* lobbySessionTemplateName = \"LobbySession\";\n    auto queueUsedByMultiplayerManager = Data()->queue;\n    // CODE SNIPPET START: XblMultiplayerManagerInitialize_C\n    HRESULT hr = XblMultiplayerManagerInitialize(lobbySessionTemplateName, queueUsedByMultiplayerManager);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerInitialize: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerDoWork_Lua(lua_State* L)\n{\n    HRESULT hr = MultiplayerManagerDoWork();\n    LogToScreen(\"XblMultiplayerManagerDoWork: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionAddLocalUser_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionAddLocalUser\n    HRESULT hr = XblMultiplayerManagerLobbySessionAddLocalUser(Data()->xalUser);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionAddLocalUser: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionRemoveLocalUser_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionAddLocalUser\n    HRESULT hr = XblMultiplayerManagerLobbySessionRemoveLocalUser(Data()->xalUser);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionRemoveLocalUser: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionCorrelationId_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionAddLocalUser\n    XblGuid correlationId;\n    HRESULT hr = XblMultiplayerManagerLobbySessionCorrelationId(&correlationId);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionCorrelationId: id=%s\", correlationId.value);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionSessionReference_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionAddLocalUser\n    XblMultiplayerSessionReference sessionReference{};\n    HRESULT hr = XblMultiplayerManagerLobbySessionSessionReference(&sessionReference);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionSessionReference: scid = %s, sessionName = %s\", sessionReference.Scid, sessionReference.SessionName);\n    return LuaReturnHR(L, hr);\n}\n\nvoid LogMultiplayerSessionMember(const XblMultiplayerManagerMember& member)\n{\n    LogToScreen(\"XblMultiplayerManagerMember: \\n\\tMemberId = %u\\n\\tXuid = %llu\\n\\tDebugGamertag = %s\\n\\tIsLocal = %u\\n\\tIsInLobby = %u\\n\\tIsInGame = %u\\n\\tStatus = %u\",\n        member.MemberId,\n        static_cast<unsigned long long>(member.Xuid),\n        member.DebugGamertag,\n        member.IsLocal,\n        member.IsInLobby,\n        member.IsInGame,\n        member.Status\n    );\n}\n\nint XblMultiplayerManagerLobbySessionLocalMembers_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionLocalMembers\n    size_t localMembersCount = XblMultiplayerManagerLobbySessionLocalMembersCount();\n    std::vector<XblMultiplayerManagerMember> localMembers(localMembersCount, XblMultiplayerManagerMember{});\n    HRESULT hr = XblMultiplayerManagerLobbySessionLocalMembers(localMembersCount, localMembers.data());\n    // CODE SNIPPET END\n    if (SUCCEEDED(hr))\n    {\n        for (const auto& member : localMembers)\n        {\n            LogMultiplayerSessionMember(member);\n        }\n    }\n    LogToScreen(\"XblMultiplayerManagerLobbySessionLocalMembers: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionSetLocalMemberProperties_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionSetLocalMemberProperties\n    HRESULT hr = XblMultiplayerManagerLobbySessionSetLocalMemberProperties(Data()->xalUser, \"Health\", \"1\", nullptr);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionSetLocalMemberProperties: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionInviteFriends_Lua(lua_State* L)\n{\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    HRESULT hr = XblMultiplayerManagerLobbySessionInviteFriends(Data()->xalUser, nullptr, \"//MPSD/custominvitestrings_JoinMyGame\");\n#else\n    HRESULT hr = S_OK;\n#endif\n    LogToScreen(\"XblMultiplayerManagerLobbySessionInviteFriends: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerJoinGameFromLobby_Lua(lua_State* L)\n{\n    const char* gameSessionTemplateName = \"GameSession\";\n    // CODE SNIPPET START: XblMultiplayerManagerJoinGameFromLobby_C\n    HRESULT hr = XblMultiplayerManagerJoinGameFromLobby(gameSessionTemplateName);\n    if (!SUCCEEDED(hr))\n    {\n        // Handle error\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerJoinGameFromLobby: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerGameSessionActive_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionActive\n    bool isGameSessionAcive = XblMultiplayerManagerGameSessionActive();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionActive: active = %d\", isGameSessionAcive);\n    lua_pushboolean(L, isGameSessionAcive);\n    return 1;\n}\n\nint XblMultiplayerManagerGameSessionMembers_Lua(lua_State* L)\n{\n    HRESULT hr = S_OK;\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionMembers\n    size_t memberCount = XblMultiplayerManagerGameSessionMembersCount();\n    if (memberCount > 0)\n    {\n        std::vector<XblMultiplayerManagerMember> gameSessionMembers(memberCount, XblMultiplayerManagerMember{});\n        hr = XblMultiplayerManagerGameSessionMembers(memberCount, gameSessionMembers.data());\n        if (SUCCEEDED(hr))\n        {\n            for (const auto& member : gameSessionMembers)\n            {\n                LogMultiplayerSessionMember(member);\n            }\n        }\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionMembers: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerGameSessionSetProperties_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionSetProperties\n    HRESULT hr = XblMultiplayerManagerGameSessionSetProperties(\"CustomProperty\", \"\\\"CustomPropertyValue\\\"\", nullptr);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionSetProperties: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLeaveGame_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLeaveGame\n    HRESULT hr = XblMultiplayerManagerLeaveGame();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLeaveGame: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerJoinLobbyViaActivity_Lua(lua_State* L)\n{\n    uint64_t xuid1 = GetUint64FromLua(L, 1, Data()->m_multiDeviceManager->GetRemoteXuid());\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (SUCCEEDED(hr))\n        {\n            size_t resultSize{ 0 };\n            hr = XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize(asyncBlock, &resultSize);\n            if (SUCCEEDED(hr))\n            {\n                size_t count{ 0 };\n                std::vector<char> buffer(resultSize, 0);\n                XblMultiplayerActivityDetails* activityDetails{};\n                hr = XblMultiplayerGetActivitiesWithPropertiesForUsersResult(asyncBlock, resultSize, buffer.data(), &activityDetails, &count, nullptr);\n                if (SUCCEEDED(hr))\n                {\n                    if (resultSize > 0)\n                    {\n                        std::string handleIdStr = activityDetails[0].HandleId;\n                        LogToScreen(\"Joining lobby via handle %s\", handleIdStr.c_str());\n\n                        auto handleId = handleIdStr.c_str();\n                        auto xblUserHandle = Data()->xalUser;\n                        // CODE SNIPPET START: XblMultiplayerManagerJoinLobby_C\n                        hr = XblMultiplayerManagerJoinLobby(handleId, xblUserHandle);\n                        // CODE SNIPPET END\n                    }\n                    else\n                    {\n                        LogToScreen(\"No activity handle to join.  Failing...\");\n                        hr = E_FAIL;\n                    }\n                }\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblMultiplayerGetActivitiesForUsersAsync\");\n    };\n\n    uint64_t xuids[1] = {};\n    xuids[0] = xuid1;\n    size_t xuidsCount = 1;\n\n    HRESULT hr = XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        xuids,\n        xuidsCount,\n        asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerJoinLobby_lua(lua_State* L)\n{\n    std::string handleId = { GetStringFromLua(L, 1, \"GameSessionName\") };\n    HRESULT hr = XblMultiplayerManagerJoinLobby(handleId.c_str(), Data()->xalUser);\n    LogToScreen(\"XblMultiplayerManagerJoinLobby: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerJoinGame_Lua(lua_State* L)\n{\n    // Params:\n    // 1) Session name\n    // 2) Session template name\n    auto sessionName{ GetStringFromLua(L, 1, \"GameSessionName\") };\n    auto sessionTemplateName{ GetStringFromLua(L, 2, \"GameSession\") };\n\n    // CODE SNIPPET START: XblMultiplayerManagerJoinGame\n    HRESULT hr = XblMultiplayerManagerJoinGame(sessionName.data(), sessionTemplateName.data(), &Data()->xboxUserId, 1);\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerSetJoinability_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerSetJoinability\n    HRESULT hr = XblMultiplayerManagerSetJoinability(XblMultiplayerJoinability::JoinableByFriends, nullptr);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerSetJoinability: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerMemberAreMembersOnSameDevice_Lua(lua_State* L)\n{\n    const XblMultiplayerManagerMember* first = nullptr;\n    const XblMultiplayerManagerMember* second = nullptr;\n\n    // CODE SNIPPET START: XblMultiplayerManagerMemberAreMembersOnSameDevice\n    bool areOnSameDevice = XblMultiplayerManagerMemberAreMembersOnSameDevice(first, second);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerMemberAreMembersOnSameDevice\");\n    LogToScreen(\"areOnSameDevice: %d\", areOnSameDevice);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerLobbySessionMembersCount_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionMembersCount\n    size_t count = XblMultiplayerManagerLobbySessionMembersCount();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionMembersCount\");\n    LogToScreen(\"count: %d\", count);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerLobbySessionMembers_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionMembers\n    size_t count = XblMultiplayerManagerLobbySessionMembersCount();\n    std::vector<XblMultiplayerManagerMember> members(count);\n    HRESULT hr = XblMultiplayerManagerLobbySessionMembers(count, members.data());\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionMembers: hr = %s\", ConvertHR(hr).c_str());\n    LogToScreen(\"count: %d\", count);\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionHost_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionHost\n    XblMultiplayerManagerMember hostMember;\n    HRESULT hr = XblMultiplayerManagerLobbySessionHost(&hostMember);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionHost: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionPropertiesJson_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionPropertiesJson\n    const char* json = XblMultiplayerManagerLobbySessionPropertiesJson();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionPropertiesJson\");\n    LogToScreen(\"json: %s\", json);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerLobbySessionConstants_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionConstants\n    const XblMultiplayerSessionConstants* consts = XblMultiplayerManagerLobbySessionConstants();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionConstants:\\n\"\n        \"ClientMatchmakingCapable = %d\\n\"\n        \"EnableMetricsBandwidthDown = %d\\n\"\n        \"EnableMetricsBandwidthUp = %d\\n\"\n        \"EnableMetricsCustom = %d\\n\"\n        \"EnableMetricsLatency = %d\\n\"\n        \"MaxMembersInSession = %d\\n\"\n        \"Visibility = %d\\n\"\n        \"InitiatorXuidsCount = %z\\n\"\n        \"MemberInactiveTimeout = %l\\n\"\n        \"MemberReadyTimeout = %l\\n\"\n        \"MemberReservedTimeout = %l\\n\"\n        \"SessionEmptyTimeout = %l\\n\"\n        \"MeasurementServerAddressesJson = %s\\n\"\n        \"SessionCloudComputePackageConstantsJson = %s\\n\"\n        \"CustomJson = %s\",\n        consts->ClientMatchmakingCapable,\n        consts->EnableMetricsBandwidthDown,\n        consts->EnableMetricsBandwidthUp,\n        consts->EnableMetricsCustom,\n        consts->EnableMetricsLatency,\n        consts->MaxMembersInSession,\n        consts->InitiatorXuidsCount,\n        consts->MemberInactiveTimeout,\n        consts->MemberReadyTimeout,\n        consts->MemberReservedTimeout,\n        consts->SessionEmptyTimeout,\n        consts->Visibility,\n        consts->MeasurementServerAddressesJson,\n        consts->SessionCloudComputePackageConstantsJson,\n        consts->CustomJson);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties_Lua(lua_State* L)\n{\n    std::string name = \"name\";\n    void* context = nullptr;\n\n#if HC_PLATFORM != HC_PLATFORM_UWP\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties\n    HRESULT hr = XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(\n        Data()->xalUser, name.c_str(), context);\n    // CODE SNIPPET END\n#else\n    HRESULT hr = S_OK;\n#endif\n    LogToScreen(\"XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress_Lua(lua_State* L)\n{\n    auto connectionAddressStr = GetStringFromLua(L, 1, \"connectionAddress1\");\n    auto connectionAddress = connectionAddressStr.c_str();\n    void* context = nullptr;\n\n    auto xblUserHandle = Data()->xalUser;\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress_C\n    HRESULT hr = XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\n        xblUserHandle, connectionAddress, context);\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionIsHost_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionIsHost\n    bool isHost = XblMultiplayerManagerLobbySessionIsHost(Data()->xboxUserId);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionIsHost: isHost = %d\", isHost);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerLobbySessionSetProperties_Lua(lua_State* L)\n{\n    std::string name = GetStringFromLua(L, 1, \"role\");\n    std::string valueJson = GetStringFromLua(L, 1, \"{\\\"class\\\":\\\"fighter\\\"}\");\n    void* context = nullptr;\n\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionSetProperties\n    HRESULT hr = XblMultiplayerManagerLobbySessionSetProperties(name.c_str(), valueJson.c_str(), context);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionSetProperties: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionSetSynchronizedProperties_Lua(lua_State* L)\n{\n    std::string name = GetStringFromLua(L, 1, \"name1\");\n    std::string valueJson = GetStringFromLua(L, 1, \"{}\");\n    void* context = nullptr;\n\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionSetSynchronizedProperties\n    HRESULT hr = XblMultiplayerManagerLobbySessionSetSynchronizedProperties(name.c_str(), valueJson.c_str(), context);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionSetSynchronizedProperties: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionSetSynchronizedHost_Lua(lua_State* L)\n{\n    size_t membersCount = XblMultiplayerManagerLobbySessionMembersCount();\n    std::vector<XblMultiplayerManagerMember> members(membersCount);\n    XblMultiplayerManagerLobbySessionMembers(membersCount, members.data());\n\n    std::string defaultDeviceToken = \"\";\n\n    for (auto member : members)\n    {\n        if (member.Xuid == Data()->xboxUserId)\n        {\n            defaultDeviceToken = member.DeviceToken;\n            break;\n        }\n    }\n\n    std::string deviceToken = GetStringFromLua(L, 1, defaultDeviceToken.empty() ? \"deviceToken1\" : defaultDeviceToken);\n    void* context = nullptr;\n\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionSetSynchronizedHost\n    HRESULT hr = XblMultiplayerManagerLobbySessionSetSynchronizedHost(deviceToken.c_str(), context);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionSetSynchronizedHost: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerLobbySessionInviteUsers_Lua(lua_State* L)\n{\n    //TODOs: Change XUID to whatever account is used in XblGameInviteAddNotificationHandler_Lua\n    // to test sending and receiving invites\n\n    auto xblUserHandle = Data()->xalUser;\n    // CODE SNIPPET START: XblMultiplayerManagerLobbySessionInviteUsers_C\n    size_t xuidsCount = 1;\n    uint64_t xuids[1] = {};\n    xuids[0] = 1234567891234567;\n    xuids[0] = 2814620188564745; // CODE SNIP SKIP\n    HRESULT hr = XblMultiplayerManagerLobbySessionInviteUsers(\n        xblUserHandle, \n        xuids, \n        xuidsCount, \n        nullptr,    // ContextStringId \n        nullptr     // CustomActivationContext\n    );\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerLobbySessionInviteUsers: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerGameSessionCorrelationId_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionCorrelationId\n    const char* id = XblMultiplayerManagerGameSessionCorrelationId();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionCorrelationId: id = %s\", id);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerGameSessionSessionReference_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionSessionReference\n    const XblMultiplayerSessionReference* session = XblMultiplayerManagerGameSessionSessionReference();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionSessionReference: scid = %s\", session->Scid);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerGameSessionHost_Lua(lua_State* L)\n{\n    XblMultiplayerManagerMember hostMember;\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionHost\n    HRESULT hr = XblMultiplayerManagerGameSessionHost(&hostMember);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionHost: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerGameSessionPropertiesJson_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionPropertiesJson\n    const char* json = XblMultiplayerManagerGameSessionPropertiesJson();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionPropertiesJson: json = %s\", json);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerGameSessionConstants_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionConstants\n    const XblMultiplayerSessionConstants* consts = XblMultiplayerManagerGameSessionConstants();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionConstants:\\n\"\n        \"ClientMatchmakingCapable = %d\\n\"\n        \"EnableMetricsBandwidthDown = %d\\n\"\n        \"EnableMetricsBandwidthUp = %d\\n\"\n        \"EnableMetricsCustom = %d\\n\"\n        \"EnableMetricsLatency = %d\\n\"\n        \"MaxMembersInSession = %d\",\n        consts->ClientMatchmakingCapable,\n        consts->EnableMetricsBandwidthDown,\n        consts->EnableMetricsBandwidthUp,\n        consts->EnableMetricsCustom,\n        consts->EnableMetricsLatency,\n        consts->MaxMembersInSession\n        );\n    LogToScreen(\n        \"InitiatorXuidsCount = %llu\\n\"\n        \"MemberInactiveTimeout = %llu\\n\"\n        \"MemberReadyTimeout = %llu\\n\"\n        \"MemberReservedTimeout = %llu\\n\"\n        \"SessionEmptyTimeout = %llu\",\n        static_cast<unsigned long long>(consts->InitiatorXuidsCount),\n        static_cast<unsigned long long>(consts->MemberInactiveTimeout),\n        static_cast<unsigned long long>(consts->MemberReadyTimeout),\n        static_cast<unsigned long long>(consts->MemberReservedTimeout),\n        static_cast<unsigned long long>(consts->SessionEmptyTimeout)\n    );\n    LogToScreen(\"MeasurementServerAddressesJson = %s\", consts->MeasurementServerAddressesJson);\n    LogToScreen(\"SessionCloudComputePackageConstantsJson = %s\", consts->SessionCloudComputePackageConstantsJson);\n    LogToScreen(\"CustomJson = %s\", consts->CustomJson); \n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerGameSessionIsHost_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionIsHost\n    bool isHost = XblMultiplayerManagerGameSessionIsHost(Data()->xboxUserId);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionIsHost: isHost = %d\", isHost);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerGameSessionSetSynchronizedProperties_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionSetSynchronizedProperties\n    HRESULT hr = XblMultiplayerManagerGameSessionSetSynchronizedProperties(\"CustomSyncProperty\", \"\\\"CustomSyncPropertyValue\\\"\", nullptr);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionSetSynchronizedProperties: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerGameSessionSetSynchronizedHost_Lua(lua_State* L)\n{\n    std::string deviceToken = GetStringFromLua(L, 1, \"deviceToken1\");\n    void* context = nullptr;\n\n    // CODE SNIPPET START: XblMultiplayerManagerGameSessionSetSynchronizedHost\n    HRESULT hr = XblMultiplayerManagerGameSessionSetSynchronizedHost(deviceToken.c_str(), context);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerGameSessionSetSynchronizedHost: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerFindMatch_Lua(lua_State* L)\n{\n    // Params:\n    // 1) matchmaking hopper name\n    // 2) attributes json\n    auto hopperNameStr{ GetStringFromLua(L, 1, \"\") };\n    auto attributesJsonStr{ GetStringFromLua(L, 2, \"\") };\n\n    const char* hopperName = hopperNameStr.c_str();\n    const char* attributesJson = attributesJsonStr.c_str();\n\n    // CODE SNIPPET START: XblMultiplayerManagerFindMatch_C\n    uint32_t timeoutInSeconds = 30;\n    HRESULT hr = XblMultiplayerManagerFindMatch(hopperName, attributesJson, timeoutInSeconds);\n    if (!SUCCEEDED(hr))\n    {\n        // Handle failure\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerFindMatch: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerCancelMatch_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerCancelMatch\n    XblMultiplayerManagerCancelMatch();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerCancelMatch\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerMatchStatus_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerMatchStatus\n    XblMultiplayerMatchStatus status = XblMultiplayerManagerMatchStatus();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerMatchStatus: status = %d\", status);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerEstimatedMatchWaitTime_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerEstimatedMatchWaitTime\n    uint32_t waitTime = XblMultiplayerManagerEstimatedMatchWaitTime();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerEstimatedMatchWaitTime: waitTime = %d\", waitTime);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerAutoFillMembersDuringMatchmaking_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerAutoFillMembersDuringMatchmaking\n    bool autoFill = XblMultiplayerManagerAutoFillMembersDuringMatchmaking();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerAutoFillMembersDuringMatchmaking: autoFill = %d\", autoFill);\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\n    XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking(true);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblMultiplayerManagerSetQosMeasurements_Lua(lua_State* L)\n{\n    const char* qosJson = \"{\\\"e69c43a8\\\": {\"\n        \"\\\"latency\\\": 5953,\"\n        \"\\\"bandwidthDown\\\" : 19342,\"\n        \"\\\"bandwidthUp\\\" : 944,\"\n        \"\\\"customProperty\\\" : \\\"customVal\\\"}}\";\n\n    // CODE SNIPPET START: XblMultiplayerManagerSetQosMeasurements\n    HRESULT hr = XblMultiplayerManagerSetQosMeasurements(qosJson);\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerSetQosMeasurements: hr = %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblMultiplayerManagerJoinability_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblMultiplayerManagerJoinability\n    XblMultiplayerJoinability joinability = XblMultiplayerManagerJoinability();\n    // CODE SNIPPET END\n    LogToScreen(\"XblMultiplayerManagerJoinability: joinability = %d\", joinability);\n    return LuaReturnHR(L, S_OK);\n}\n\nint VerifyMPMGameSessionProperites_Lua(lua_State* L)\n{\n    bool isActive = XblMultiplayerManagerGameSessionActive();\n    assert(isActive);\n    UNREFERENCED_PARAMETER(isActive);\n\n    const XblMultiplayerSessionConstants* consts = XblMultiplayerManagerGameSessionConstants();\n    assert(consts != nullptr);\n    assert(consts->MaxMembersInSession == 20); // defined by template\n    UNREFERENCED_PARAMETER(consts);\n\n    const char* corr = XblMultiplayerManagerGameSessionCorrelationId();\n    assert(corr != nullptr);\n    assert(strlen(corr) > 0);\n    UNREFERENCED_PARAMETER(corr);\n\n    XblMultiplayerManagerMember hostMember;\n    HRESULT hr = XblMultiplayerManagerGameSessionHost(&hostMember);\n    assert(SUCCEEDED(hr) || hr == __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER));\n    UNREFERENCED_PARAMETER(hr);\n\n    bool isHost = XblMultiplayerManagerGameSessionIsHost(Data()->xboxUserId);\n    UNREFERENCED_PARAMETER(isHost);\n\n    size_t membersCount = XblMultiplayerManagerGameSessionMembersCount();\n    std::vector<XblMultiplayerManagerMember> members(membersCount);\n    hr = XblMultiplayerManagerGameSessionMembers(membersCount, members.data());\n    assert(SUCCEEDED(hr));\n    assert(membersCount == 2);\n    assert(strlen(members[0].DebugGamertag) > 0);\n    assert(strlen(members[1].DebugGamertag) > 0);\n    UNREFERENCED_PARAMETER(membersCount);\n    UNREFERENCED_PARAMETER(members);\n\n    bool sameDevice = XblMultiplayerManagerMemberAreMembersOnSameDevice(&members[0], &members[1]);\n    assert(sameDevice == false);\n    UNREFERENCED_PARAMETER(sameDevice);\n\n    const char* props = XblMultiplayerManagerGameSessionPropertiesJson();\n    assert(props != nullptr);\n    assert(strlen(props) > 0);\n    UNREFERENCED_PARAMETER(props);\n\n    const XblMultiplayerSessionReference* sessionRef = XblMultiplayerManagerGameSessionSessionReference();\n    assert(sessionRef != nullptr);\n    assert(strlen(sessionRef->Scid) > 0);\n    assert(strlen(sessionRef->SessionName) > 0);\n    assert(strlen(sessionRef->SessionTemplateName) > 0);\n    UNREFERENCED_PARAMETER(sessionRef);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint VerifyMPMLobbySessionProperites_Lua(lua_State* L)\n{\n    const XblMultiplayerSessionConstants* consts = XblMultiplayerManagerGameSessionConstants();\n    assert(consts != nullptr);\n    assert(consts->MaxMembersInSession == 20); // defined by template\n    UNREFERENCED_PARAMETER(consts);\n\n    XblGuid correlationId;\n    HRESULT hr = XblMultiplayerManagerLobbySessionCorrelationId(&correlationId);\n    assert(SUCCEEDED(hr));\n    assert(correlationId.value[0] != 0);\n    UNREFERENCED_PARAMETER(correlationId);\n\n    XblMultiplayerManagerMember hostMember;\n    hr = XblMultiplayerManagerLobbySessionHost(&hostMember);\n    assert(SUCCEEDED(hr) || hr == __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER));\n    \n    bool isHost = XblMultiplayerManagerLobbySessionIsHost(Data()->xboxUserId);\n    UNREFERENCED_PARAMETER(isHost);\n\n    size_t localMembersCount = XblMultiplayerManagerLobbySessionLocalMembersCount();\n    std::vector<XblMultiplayerManagerMember> localmembers(localMembersCount);\n    hr = XblMultiplayerManagerLobbySessionLocalMembers(localMembersCount, localmembers.data());\n    assert(SUCCEEDED(hr));\n    assert(localMembersCount == 1);\n    assert(strlen(localmembers[0].DebugGamertag) > 0);\n    UNREFERENCED_PARAMETER(localmembers);\n\n    size_t membersCount = XblMultiplayerManagerLobbySessionMembersCount();\n    std::vector<XblMultiplayerManagerMember> members(membersCount);\n    hr = XblMultiplayerManagerLobbySessionMembers(membersCount, members.data());\n    assert(SUCCEEDED(hr));\n    assert(membersCount >= 1);\n    assert(strlen(members[0].DebugGamertag) > 0);\n    UNREFERENCED_PARAMETER(members);\n\n    const char* props = XblMultiplayerManagerLobbySessionPropertiesJson();\n    assert(props != nullptr);\n    assert(strlen(props) > 0);\n    UNREFERENCED_PARAMETER(props);\n\n    XblMultiplayerSessionReference sessionRef{};\n    hr = XblMultiplayerManagerLobbySessionSessionReference(&sessionRef);\n    assert(SUCCEEDED(hr));\n    assert(strlen(sessionRef.Scid) > 0);\n    assert(strlen(sessionRef.SessionName) > 0);\n    assert(strlen(sessionRef.SessionTemplateName) > 0);\n    UNREFERENCED_PARAMETER(sessionRef);\n\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_XblMultiplayerManager()\n{\n    // Non XSAPI APIs\n    lua_register(Data()->L, \"StartDoWorkLoop\", StartDoWorkLoop_Lua);\n    lua_register(Data()->L, \"StopDoWorkLoop\", StopDoWorkLoop_Lua);\n\n    // XSAPI MPM APIs\n    lua_register(Data()->L, \"XblMultiplayerManagerMemberAreMembersOnSameDevice\", XblMultiplayerManagerMemberAreMembersOnSameDevice_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerInitialize\", XblMultiplayerManagerInitialize_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerDoWork\", XblMultiplayerManagerDoWork_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionCorrelationId\", XblMultiplayerManagerLobbySessionCorrelationId_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionSessionReference\", XblMultiplayerManagerLobbySessionSessionReference_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionLocalMembers\", XblMultiplayerManagerLobbySessionLocalMembers_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionMembersCount\", XblMultiplayerManagerLobbySessionMembersCount_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionMembers\", XblMultiplayerManagerLobbySessionMembers_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionHost\", XblMultiplayerManagerLobbySessionHost_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionPropertiesJson\", XblMultiplayerManagerLobbySessionPropertiesJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionConstants\", XblMultiplayerManagerLobbySessionConstants_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionAddLocalUser\", XblMultiplayerManagerLobbySessionAddLocalUser_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionRemoveLocalUser\", XblMultiplayerManagerLobbySessionRemoveLocalUser_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionSetLocalMemberProperties\", XblMultiplayerManagerLobbySessionSetLocalMemberProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties\", XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress\", XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionIsHost\", XblMultiplayerManagerLobbySessionIsHost_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionSetProperties\", XblMultiplayerManagerLobbySessionSetProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionSetSynchronizedProperties\", XblMultiplayerManagerLobbySessionSetSynchronizedProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionSetSynchronizedHost\", XblMultiplayerManagerLobbySessionSetSynchronizedHost_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionInviteFriends\", XblMultiplayerManagerLobbySessionInviteFriends_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLobbySessionInviteUsers\", XblMultiplayerManagerLobbySessionInviteUsers_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionActive\", XblMultiplayerManagerGameSessionActive_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionCorrelationId\", XblMultiplayerManagerGameSessionCorrelationId_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionSessionReference\", XblMultiplayerManagerGameSessionSessionReference_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionMembers\", XblMultiplayerManagerGameSessionMembers_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionHost\", XblMultiplayerManagerGameSessionHost_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionPropertiesJson\", XblMultiplayerManagerGameSessionPropertiesJson_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionConstants\", XblMultiplayerManagerGameSessionConstants_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionIsHost\", XblMultiplayerManagerGameSessionIsHost_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionSetProperties\", XblMultiplayerManagerGameSessionSetProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionSetSynchronizedProperties\", XblMultiplayerManagerGameSessionSetSynchronizedProperties_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerGameSessionSetSynchronizedHost\", XblMultiplayerManagerGameSessionSetSynchronizedHost_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerJoinLobby\", XblMultiplayerManagerJoinLobby_lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerJoinLobbyViaActivity\", XblMultiplayerManagerJoinLobbyViaActivity_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerJoinGameFromLobby\", XblMultiplayerManagerJoinGameFromLobby_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerJoinGame\", XblMultiplayerManagerJoinGame_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerLeaveGame\", XblMultiplayerManagerLeaveGame_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerFindMatch\", XblMultiplayerManagerFindMatch_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerCancelMatch\", XblMultiplayerManagerCancelMatch_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerMatchStatus\", XblMultiplayerManagerMatchStatus_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerEstimatedMatchWaitTime\", XblMultiplayerManagerEstimatedMatchWaitTime_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerAutoFillMembersDuringMatchmaking\", XblMultiplayerManagerAutoFillMembersDuringMatchmaking_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking\", XblMultiplayerManagerSetAutoFillMembersDuringMatchmaking_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerSetQosMeasurements\", XblMultiplayerManagerSetQosMeasurements_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerJoinability\", XblMultiplayerManagerJoinability_Lua);\n    lua_register(Data()->L, \"XblMultiplayerManagerSetJoinability\", XblMultiplayerManagerSetJoinability_Lua);\n    lua_register(Data()->L, \"VerifyMPMGameSessionProperites\", VerifyMPMGameSessionProperites_Lua);\n    lua_register(Data()->L, \"VerifyMPMLobbySessionProperites\", VerifyMPMLobbySessionProperites_Lua);\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_presence.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\nstatic struct PresenceState\n{\n    PresenceState() = default;\n    ~PresenceState()\n    {\n        assert(!presenceRecord);\n        assert(!devicePresenceChangeSubscription);\n        assert(!titlePresenceChangeSubscription);\n        assert(!devicePresenceChangedHandlerToken);\n        assert(!titlePresenceChangedHandlerToken);\n    }\n\n    XblPresenceRecordHandle presenceRecord{ nullptr };\n    XblRealTimeActivitySubscriptionHandle devicePresenceChangeSubscription{ nullptr };\n    XblRealTimeActivitySubscriptionHandle titlePresenceChangeSubscription{ nullptr };\n    XblFunctionContext devicePresenceChangedHandlerToken{ 0 };\n    XblFunctionContext titlePresenceChangedHandlerToken{ 0 };\n} state;\n\nint XblPresenceRecordGetXuid_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceRecordGetXuid\n    uint64_t xuid;\n    HRESULT hr = XblPresenceRecordGetXuid(state.presenceRecord, &xuid);\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblPresenceRecordGetXuid: hr=%s, xuid=%llu\", ConvertHR(hr).c_str(), static_cast<unsigned long long>(xuid));\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceRecordGetUserState_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceRecordGetXuid\n    XblPresenceUserState userState{ XblPresenceUserState::Unknown };\n    HRESULT hr = XblPresenceRecordGetUserState(state.presenceRecord, &userState);\n    // CODE SNIPPET END\n\n    LogToScreen(\"XblPresenceRecordGetUserState: hr=%s, state=%u\", ConvertHR(hr).c_str(), userState);\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceRecordGetDeviceRecords_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceRecordGetDeviceRecords_C\n    const XblPresenceDeviceRecord* deviceRecords{ nullptr };\n    size_t deviceRecordsCount{ 0 };\n    HRESULT hr = XblPresenceRecordGetDeviceRecords(state.presenceRecord, &deviceRecords, &deviceRecordsCount);\n\n    for (auto i = 0u; i < deviceRecordsCount; ++i)\n    {\n        auto& deviceRecord{ deviceRecords[i] };\n        LogToScreen(\"Got XblDeviceRecord with device type %u and %u title records\", deviceRecord.deviceType, deviceRecord.titleRecordsCount);\n\n        for (auto j = 0u; j < deviceRecord.titleRecordsCount; ++j)\n        {\n            auto& titleRecord{ deviceRecord.titleRecords[j] };\n            // Display rich presence string\n            LogToScreen(\"Rich presence string for titleId %u: %s\", titleRecord.titleId, titleRecord.richPresenceString);\n        }\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceRecordGetDeviceRecords: hr=%s\", ConvertHR(hr).data());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceRecordCloseHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceRecordCloseHandle_C\n    XblPresenceRecordCloseHandle(state.presenceRecord);\n    state.presenceRecord = nullptr;\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblPresenceSetPresenceAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceSetPresenceAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        // CODE SKIP START\n        if (hr == HTTP_E_STATUS_429_TOO_MANY_REQUESTS)\n        {\n            LogToFile(\"XblPresenceSetPresence returned 429.  Ignoring failure\");\n            hr = S_OK;\n        }\n        CallLuaFunctionWithHr(hr, \"OnXblPresenceSetPresenceAsync\");\n        // CODE SKIP END\n    };\n\n    std::vector<const char*> tokens{ \"0\" };\n    XblPresenceRichPresenceIds ids\n    {\n        {},\n        \"PuzzlesPresence\",\n        tokens.data(),\n        tokens.size()\n    };\n    pal::strcpy(ids.scid, sizeof(ids.scid), Data()->scid);\n\n    HRESULT hr = XblPresenceSetPresenceAsync(Data()->xboxLiveContext, true, &ids, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceSetPresenceAsync: hr=%s\", ConvertHR(hr).data());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceGetPresenceAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceGetPresenceAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        assert(state.presenceRecord == nullptr); // CODE SNIP SKIP\n        HRESULT hr = XblPresenceGetPresenceResult(asyncBlock, &state.presenceRecord);\n        \n        // Be sure to call XblPresenceRecordCloseHandle when the presence record is no longer needed.\n        LogToFile(\"XblPresenceGetPresenceResult hr=%s\", ConvertHR(hr).data()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblPresenceGetPresenceAsync\"); // CODE SNIP SKIP\n    };\n\n    uint64_t xuid = Data()->xboxUserId;\n    if (Data()->m_multiDeviceManager->GetRemoteXuid() != 0)\n    {\n        xuid = Data()->m_multiDeviceManager->GetRemoteXuid();\n    }\n\n    HRESULT hr = XblPresenceGetPresenceAsync(Data()->xboxLiveContext, xuid, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblPresenceGetPresenceAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceGetPresenceForMultipleUsersAsync_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceGetPresenceForMultipleUsersAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultCount{ 0 };\n        HRESULT hr = XblPresenceGetPresenceForMultipleUsersResultCount(asyncBlock, &resultCount);\n\n        if (SUCCEEDED(hr) && resultCount > 0)\n        {\n            std::vector<XblPresenceRecordHandle> handles(resultCount, nullptr);\n            hr = XblPresenceGetPresenceForMultipleUsersResult(asyncBlock, handles.data(), resultCount);\n\n            // Be sure to call XblPresenceRecordCloseHandle for each presence record when they are\n            // no longer needed.\n            // CODE SKIP START\n            LogToFile(\"XblPresenceGetPresenceForMultipleUsersResult hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                for (auto i = 0u; i < resultCount; ++i)\n                {\n                    XblPresenceRecordCloseHandle(handles[i]);\n                }\n            }\n            // CODE SKIP END\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblPresenceGetPresenceForMultipleUsersAsync\"); // CODE SNIP SKIP\n    };\n\n    std::vector<uint64_t> xuids{ Data()->xboxUserId };\n\n    // Filter results to only online users\n    XblPresenceQueryFilters filters{};\n    filters.onlineOnly = true;\n    filters.detailLevel = XblPresenceDetailLevel::All;\n\n    HRESULT hr = XblPresenceGetPresenceForMultipleUsersAsync(Data()->xboxLiveContext, xuids.data(), xuids.size(), &filters, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblPresenceGetPresenceForMultipleUsersAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceGetPresenceForSocialGroupAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblPresenceGetPresenceForSocialGroupAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultCount{ 0 };\n        HRESULT hr = XblPresenceGetPresenceForSocialGroupResultCount(asyncBlock, &resultCount);\n\n        if (SUCCEEDED(hr) && resultCount > 0)\n        {\n            std::vector<XblPresenceRecordHandle> handles(resultCount, nullptr);\n            hr = XblPresenceGetPresenceForSocialGroupResult(asyncBlock, handles.data(), resultCount);\n\n            // Be sure to call XblPresenceRecordCloseHandle for each presence record when they are\n            // no longer needed.\n            // CODE SKIP START\n            LogToFile(\"XblPresenceGetPresenceForSocialGroupResult hr=%s\", ConvertHR(hr).data());\n\n            if (SUCCEEDED(hr))\n            {\n                for (auto i = 0u; i < resultCount; ++i)\n                {\n                    XblPresenceRecordCloseHandle(handles[i]);\n                }\n            }\n            // CODE SKIP END\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblPresenceGetPresenceForSocialGroupAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblPresenceGetPresenceForSocialGroupAsync(Data()->xboxLiveContext, \"Favorites\", nullptr, nullptr, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblPresenceGetPresenceForSocialGroupAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceSubscribeToDevicePresenceChange_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceSubscribeToDevicePresenceChange_C\n    uint64_t xuid{ 2814639011617876 };\n\n    HRESULT hr = XblPresenceSubscribeToDevicePresenceChange(\n        Data()->xboxLiveContext,\n        xuid,\n        &state.devicePresenceChangeSubscription\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceSubscribeToDevicePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceUnsubscribeFromDevicePresenceChange_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceUnsubscribeFromDevicePresenceChange_C\n    HRESULT hr = XblPresenceUnsubscribeFromDevicePresenceChange(\n        Data()->xboxLiveContext,\n        state.devicePresenceChangeSubscription\n    );\n\n    state.devicePresenceChangeSubscription = nullptr;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceUnsubscribeFromDevicePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceSubscribeToTitlePresenceChange_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceSubscribeToTitlePresenceChange_C\n    uint64_t xuid{ 2814639011617876 };\n\n    HRESULT hr = XblPresenceSubscribeToTitlePresenceChange(\n        Data()->xboxLiveContext,\n        xuid,\n        Data()->titleId,\n        &state.titlePresenceChangeSubscription\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceSubscribeToTitlePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceUnsubscribeFromTitlePresenceChange_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceUnsubscribeFromTitlePresenceChange_C\n    HRESULT hr = XblPresenceUnsubscribeFromTitlePresenceChange(\n        Data()->xboxLiveContext,\n        state.titlePresenceChangeSubscription\n    );\n\n    state.titlePresenceChangeSubscription = nullptr;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceUnsubscribeFromTitlePresenceChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceTrackUsers_Lua(lua_State* L)\n{\n    auto xuid{ GetUint64FromLua(L, 1, 2814639011617876) };\n\n    // CODE SNIPPET START: XblPresenceTrackUsers_C\n    HRESULT hr = XblPresenceTrackUsers(\n        Data()->xboxLiveContext,\n        &xuid,\n        1\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceTrackUsers: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceStopTrackingUsers_Lua(lua_State* L)\n{\n    auto xuid{ GetUint64FromLua(L, 1, 2814639011617876) };\n\n    // CODE SNIPPET START: XblPresenceStopTrackingUsers_C\n    HRESULT hr = XblPresenceStopTrackingUsers(\n        Data()->xboxLiveContext,\n        &xuid,\n        1\n    );\n\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceStopTrackingUsers: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceTrackAdditionalTitles_Lua(lua_State* L)\n{\n    auto titleId{ GetUint32FromLua(L, 1, Data()->titleId) };\n    // CODE SNIPPET START: XblPresenceTrackTitles_C\n\n    HRESULT hr = XblPresenceTrackAdditionalTitles(\n        Data()->xboxLiveContext,\n        &titleId,\n        1\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceTrackTitles: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceStopTrackingAdditionalTitles_Lua(lua_State* L)\n{\n    auto titleId{ GetUint32FromLua(L, 1, Data()->titleId) };\n\n    // CODE SNIPPET START: XblPresenceStopTrackingTitles_C\n    HRESULT hr = XblPresenceStopTrackingAdditionalTitles(\n        Data()->xboxLiveContext,\n        &titleId,\n        1\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceStopTrackingTitles: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceAddDevicePresenceChangedHandler_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceAddDevicePresenceChangedHandler_C\n    state.devicePresenceChangedHandlerToken = XblPresenceAddDevicePresenceChangedHandler(\n        Data()->xboxLiveContext,\n        [](void* context, uint64_t xuid, XblPresenceDeviceType deviceType, bool isUserLoggedOnDevice)\n        {\n            UNREFERENCED_PARAMETER(context);\n            LogToFile(\"Device presence change notification received:\");\n            LogToFile(\"Xuid = %u, deviceType = %u, isUserLoggedOnDevice = %u\", xuid, deviceType, isUserLoggedOnDevice);\n            CallLuaFunction(\"OnDevicePresenceChanged\"); // CODE SNIP SKIP\n        },\n        nullptr\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceAddDevicePresenceChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblPresenceRemoveDevicePresenceChangedHandler_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceRemoveDevicePresenceChangedHandler_C\n    HRESULT hr = XblPresenceRemoveDevicePresenceChangedHandler(\n        Data()->xboxLiveContext,\n        state.devicePresenceChangedHandlerToken\n    );\n\n    state.devicePresenceChangedHandlerToken = 0;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceRemoveDevicePresenceChangedHandler: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPresenceAddTitlePresenceChangedHandler_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceAddTitlePresenceChangedHandler_C\n    state.titlePresenceChangedHandlerToken =  XblPresenceAddTitlePresenceChangedHandler(\n        Data()->xboxLiveContext,\n        [](void* context, uint64_t xuid, uint32_t titleId, XblPresenceTitleState titleState)\n        {\n            UNREFERENCED_PARAMETER(context);\n            LogToFile(\"Title presence change notification received:\");\n            LogToFile(\"Xuid = %u, titleId = %u, titleState = %u\", xuid, titleId, titleState);\n            CallLuaFunction(\"OnTitlePresenceChanged\"); // CODE SNIP SKIP\n        },\n        nullptr\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceAddTitlePresenceChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblPresenceRemoveTitlePresenceChangedHandler_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblPresenceRemoveTitlePresenceChangedHandler_C\n    HRESULT hr = XblPresenceRemoveTitlePresenceChangedHandler(\n        Data()->xboxLiveContext,\n        state.titlePresenceChangedHandlerToken\n    );\n\n    state.titlePresenceChangedHandlerToken = 0;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblPresenceRemoveTitlePresenceChangedHandler: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblPresence()\n{\n    lua_register(Data()->L, \"XblPresenceRecordGetXuid\", XblPresenceRecordGetXuid_Lua);\n    lua_register(Data()->L, \"XblPresenceRecordGetUserState\", XblPresenceRecordGetUserState_Lua);\n    lua_register(Data()->L, \"XblPresenceRecordGetDeviceRecords\", XblPresenceRecordGetDeviceRecords_Lua);\n    lua_register(Data()->L, \"XblPresenceRecordCloseHandle\", XblPresenceRecordCloseHandle_Lua);\n    lua_register(Data()->L, \"XblPresenceSetPresenceAsync\", XblPresenceSetPresenceAsync_Lua);\n    lua_register(Data()->L, \"XblPresenceGetPresenceAsync\", XblPresenceGetPresenceAsync_Lua);\n    lua_register(Data()->L, \"XblPresenceGetPresenceForSocialGroupAsync\", XblPresenceGetPresenceForSocialGroupAsync_Lua);\n    lua_register(Data()->L, \"XblPresenceGetPresenceForMultipleUsersAsync\", XblPresenceGetPresenceForMultipleUsersAsync_Lua);\n    lua_register(Data()->L, \"XblPresenceSubscribeToDevicePresenceChange\", XblPresenceSubscribeToDevicePresenceChange_Lua);\n    lua_register(Data()->L, \"XblPresenceUnsubscribeFromDevicePresenceChange\", XblPresenceUnsubscribeFromDevicePresenceChange_Lua);\n    lua_register(Data()->L, \"XblPresenceSubscribeToTitlePresenceChange\", XblPresenceSubscribeToTitlePresenceChange_Lua);\n    lua_register(Data()->L, \"XblPresenceUnsubscribeFromTitlePresenceChange\", XblPresenceUnsubscribeFromTitlePresenceChange_Lua);\n    lua_register(Data()->L, \"XblPresenceTrackUsers\", XblPresenceTrackUsers_Lua);\n    lua_register(Data()->L, \"XblPresenceStopTrackingUsers\", XblPresenceStopTrackingUsers_Lua);\n    lua_register(Data()->L, \"XblPresenceTrackAdditionalTitles\", XblPresenceTrackAdditionalTitles_Lua);\n    lua_register(Data()->L, \"XblPresenceStopTrackingAdditionalTitles\", XblPresenceStopTrackingAdditionalTitles_Lua);\n    lua_register(Data()->L, \"XblPresenceAddDevicePresenceChangedHandler\", XblPresenceAddDevicePresenceChangedHandler_Lua);\n    lua_register(Data()->L, \"XblPresenceRemoveDevicePresenceChangedHandler\", XblPresenceRemoveDevicePresenceChangedHandler_Lua);\n    lua_register(Data()->L, \"XblPresenceAddTitlePresenceChangedHandler\", XblPresenceAddTitlePresenceChangedHandler_Lua);\n    lua_register(Data()->L, \"XblPresenceRemoveTitlePresenceChangedHandler\", XblPresenceRemoveTitlePresenceChangedHandler_Lua);\n\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_privacy.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#ifndef _countof\n#define _countof(array) (sizeof(array) / sizeof(array[0]))\n#endif\nint XblPrivacyGetAvoidListAsync_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblPrivacyGetAvoidListAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultCount{};\n        HRESULT hr = XblPrivacyGetAvoidListResultCount(asyncBlock, &resultCount);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<uint64_t> avoidedXuids(resultCount);\n            hr = XblPrivacyGetAvoidListResult(asyncBlock, resultCount, avoidedXuids.data());\n        }\n\n        LogToFile(\"XblPrivacyGetAvoidListResult: hr=%s avoided xuids count=%d\", ConvertHR(hr).c_str(), resultCount); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblPrivacyGetAvoidListAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblPrivacyGetAvoidListAsync(Data()->xboxLiveContext, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblPrivacyGetAvoidListAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPrivacyCheckPermissionAsync_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n\n    XblPermission permissionToCheck{ static_cast<XblPermission>(GetUint32FromLua(L, 1, (uint32_t)XblPermission::ViewTargetProfile)) };\n    uint64_t targetXuid{ GetUint64FromLua(L, 2, 2743710844428572) };\n\n    LogToFile(\"XblPrivacyCheckPermissionAsync: permissionToCheck = %d, targetXuid = %llu\", permissionToCheck, static_cast<unsigned long long>(targetXuid));\n\n    // CODE SNIPPET START: XblPrivacyCheckPermissionAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblPrivacyCheckPermissionResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblPermissionCheckResult* result{};\n\n            hr = XblPrivacyCheckPermissionResult(asyncBlock, resultSize, buffer.data(), &result, nullptr);\n\n            if (SUCCEEDED(hr)) // CODE SNIP SKIP\n            { // CODE SNIP SKIP\n                LogToFile(\"XblPrivacyCheckPermissionResult: hr=%s isAllowed=%d\", ConvertHR(hr).c_str(), result->isAllowed); // CODE SNIP SKIP\n            } // CODE SNIP SKIP\n        }\n\n        if (FAILED(hr)) // CODE SNIP SKIP\n        { // CODE SNIP SKIP\n            LogToFile(\"XblPrivacyCheckPermissionResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        } // CODE SNIP SKIP\n\n        CallLuaFunctionWithHr(hr, \"OnXblPrivacyCheckPermissionAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblPrivacyCheckPermissionAsync(Data()->xboxLiveContext, permissionToCheck, targetXuid, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblPrivacyGetAvoidListAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPrivacyCheckPermissionForAnonymousUserAsync_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n    XblPermission permissionToCheck{ static_cast<XblPermission>(GetUint32FromLua(L, 1, (uint32_t)XblPermission::CommunicateUsingText)) };\n    XblAnonymousUserType userType{ static_cast<XblAnonymousUserType>(GetUint32FromLua(L, 2, (uint32_t)XblAnonymousUserType::CrossNetworkUser)) };\n\n    LogToFile(\"XblPrivacyCheckPermissionForAnonymousUserAsync: permissionToCheck = %d, target = %d\", permissionToCheck, userType);\n\n    // CODE SNIPPET START: XblPrivacyCheckPermissionForAnonymousUserAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblPrivacyCheckPermissionForAnonymousUserResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblPermissionCheckResult* result{};\n\n            hr = XblPrivacyCheckPermissionForAnonymousUserResult(asyncBlock, resultSize, buffer.data(), &result, nullptr);\n\n            if (SUCCEEDED(hr)) // CODE SNIP SKIP\n            { // CODE SNIP SKIP\n                LogToFile(\"XblPrivacyCheckPermissionResult: hr=%s isAllowed=%d\", ConvertHR(hr).c_str(), result->isAllowed); // CODE SNIP SKIP\n            } // CODE SNIP SKIP\n        }\n\n        if (FAILED(hr)) // CODE SNIP SKIP\n        { // CODE SNIP SKIP\n            LogToFile(\"XblPrivacyCheckPermissionResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        } // CODE SNIP SKIP\n\n        CallLuaFunctionWithHr(hr, \"OnXblPrivacyCheckPermissionForAnonymousUserAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblPrivacyCheckPermissionForAnonymousUserAsync(Data()->xboxLiveContext, permissionToCheck, userType, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblPrivacyGetAvoidListAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblPrivacyBatchCheckPermissionAsync_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n\n    // Only using default values for params, very difficult to parse variable arrays from lua\n    XblPermission permissionsToCheck[] {\n        XblPermission::CommunicateUsingText,\n        XblPermission::CommunicateUsingVideo,\n        XblPermission::CommunicateUsingVoice,\n        XblPermission::ViewTargetProfile,\n        XblPermission::ViewTargetGameHistory,\n        XblPermission::ViewTargetVideoHistory,\n        XblPermission::ViewTargetMusicHistory,\n        XblPermission::ViewTargetExerciseInfo,\n        XblPermission::ViewTargetPresence,\n        XblPermission::ViewTargetVideoStatus,\n        XblPermission::ViewTargetMusicStatus,\n        XblPermission::PlayMultiplayer,\n        XblPermission::ViewTargetUserCreatedContent,\n        XblPermission::BroadcastWithTwitch,\n        XblPermission::WriteComment,\n        XblPermission::ShareItem,\n        XblPermission::ShareTargetContentToExternalNetworks\n    };\n    uint64_t targetXuids[] { 2743710844428572, 2533274819720636 };\n    XblAnonymousUserType targetUserTypes[]{ XblAnonymousUserType::CrossNetworkUser, XblAnonymousUserType::CrossNetworkFriend };\n\n    size_t expectedResultCount{ _countof(permissionsToCheck) * (_countof(targetXuids) + _countof(targetUserTypes)) };\n\n    // CODE SNIPPET START: XblPrivacyBatchCheckPermissionAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    auto contextPtr = std::make_unique<size_t>(expectedResultCount);\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = contextPtr.get(); \n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        std::unique_ptr<size_t> expectedCount{ static_cast<size_t*>(asyncBlock->context) };\n        size_t resultSize;\n        HRESULT hr = XblPrivacyBatchCheckPermissionResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            size_t resultCount{};\n            XblPermissionCheckResult* results{};\n\n            hr = XblPrivacyBatchCheckPermissionResult(asyncBlock, resultSize, buffer.data(), &results, &resultCount, nullptr);\n            if (SUCCEEDED(hr))\n            {\n                assert(resultCount == *expectedCount);\n            }\n        }\n\n        LogToFile(\"XblPrivacyBatchCheckPermissionResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblPrivacyBatchCheckPermissionAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblPrivacyBatchCheckPermissionAsync(\n        Data()->xboxLiveContext,\n        permissionsToCheck,\n        _countof(permissionsToCheck),\n        targetXuids,\n        _countof(targetXuids),\n        targetUserTypes,\n        _countof(targetUserTypes),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        contextPtr.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblPrivacyBatchCheckPermissionAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblPrivacy()\n{\n    lua_register(Data()->L, \"XblPrivacyGetAvoidListAsync\", XblPrivacyGetAvoidListAsync_Lua);\n    lua_register(Data()->L, \"XblPrivacyCheckPermissionAsync\", XblPrivacyCheckPermissionAsync_Lua);\n    lua_register(Data()->L, \"XblPrivacyCheckPermissionForAnonymousUserAsync\", XblPrivacyCheckPermissionForAnonymousUserAsync_Lua);\n    lua_register(Data()->L, \"XblPrivacyBatchCheckPermissionAsync\", XblPrivacyBatchCheckPermissionAsync_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_profile.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint XblProfileGetUserProfileAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblProfileGetUserProfileAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblUserProfile profile = { 0 };\n        HRESULT hr = XblProfileGetUserProfileResult(asyncBlock, &profile);\n        LogToFile(\"XblProfileGetUserProfileResult: hr=%s gamertag=%s\", ConvertHR(hr).c_str(), profile.gamertag); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblProfileGetUserProfileAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblProfileGetUserProfileAsync(Data()->xboxLiveContext, Data()->xboxUserId, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblProfileGetUserProfileAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblProfileGetUserProfilesAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblProfileGetUserProfilesAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        uint32_t profilesCount = 1;\n        XblUserProfile profiles[1] = { 0 };\n        HRESULT hr = XblProfileGetUserProfilesResult(asyncBlock, profilesCount, profiles);\n        LogToFile(\"XblProfileGetUserProfilesResult: hr=%s gamertag=%s\", ConvertHR(hr).c_str(), profiles[0].gamertag); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblProfileGetUserProfilesAsync\"); // CODE SNIP SKIP\n    };\n\n    uint64_t xboxUserIds[1];\n    xboxUserIds[0] = Data()->xboxUserId;\n    size_t xboxUserIdsCount = 1;\n\n    HRESULT hr = XblProfileGetUserProfilesAsync(Data()->xboxLiveContext, xboxUserIds, xboxUserIdsCount, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblProfileGetUserProfilesAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblProfileGetUserProfilesForSocialGroupAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    auto socialGroup = GetStringFromLua(L, 1, \"People\");\n\n    // CODE SNIPPET START: XblProfileGetUserProfilesForSocialGroupAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t profilesCount = 0;\n        HRESULT hr = XblProfileGetUserProfilesForSocialGroupResultCount(asyncBlock, &profilesCount);\n        if (SUCCEEDED(hr) && profilesCount > 0)\n        {\n            std::vector<XblUserProfile> profiles(profilesCount);\n            hr = XblProfileGetUserProfilesForSocialGroupResult(asyncBlock, profilesCount, profiles.data());\n            LogToFile(\"XblProfileGetUserProfilesForSocialGroupResult: hr=%s profilesCount=%d gamertag=%s\", ConvertHR(hr).c_str(), profilesCount, profiles[0].gamertag); // CODE SNIP SKIP\n        }\n        else if (hr == HTTP_E_STATUS_429_TOO_MANY_REQUESTS)\n        {\n            CallLuaFunctionWithHr(S_OK, \"OnXblProfileGetUserProfilesForSocialGroupAsyncRetry\");\n            return;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblProfileGetUserProfilesForSocialGroupAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblProfileGetUserProfilesForSocialGroupAsync(Data()->xboxLiveContext, socialGroup.c_str(), asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblProfileGetUserProfilesForSocialGroupAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblProfile()\n{\n    lua_register(Data()->L, \"XblProfileGetUserProfileAsync\", XblProfileGetUserProfileAsync_Lua);\n    lua_register(Data()->L, \"XblProfileGetUserProfilesAsync\", XblProfileGetUserProfilesAsync_Lua);\n    lua_register(Data()->L, \"XblProfileGetUserProfilesForSocialGroupAsync\", XblProfileGetUserProfilesForSocialGroupAsync_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_real_time_activity.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\nstatic XblFunctionContext s_connectionStateHandlerContext{ 0 };\nstatic XblFunctionContext s_subscriptionErrorHandlerContext{ 0 };\nstatic XblFunctionContext s_resyncHandlerContext{ 0 };\n\nint XblRealTimeActivityActivate_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityActivate\n    HRESULT hr = XblRealTimeActivityActivate(Data()->xboxLiveContext);\n    // CODE SNIPPET END\n    LogToFile(\"XblRealTimeActivityActivate: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblRealTimeActivityDeactivate_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityDeactivate\n    HRESULT hr = XblRealTimeActivityDeactivate(Data()->xboxLiveContext);\n    // CODE SNIPPET END\n    LogToFile(\"XblRealTimeActivityDeactivate: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblRealTimeActivityAddConnectionStateChangeHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityAddConnectionStateChangeHandler\n    s_connectionStateHandlerContext = XblRealTimeActivityAddConnectionStateChangeHandler(Data()->xboxLiveContext,\n        [](void *context, XblRealTimeActivityConnectionState connectionState)\n    {\n        UNREFERENCED_PARAMETER(context); // CODE SNIP SKIP\n        LogToFile(\"XblRealTimeActivityConnectionState changed to %d\", connectionState);\n\n        // Handle connection state change\n        switch (connectionState)\n        {\n        case XblRealTimeActivityConnectionState::Connected:\n            // Handle connected state\n            LogToFile(\"XblRealTimeActivityAddConnectionStateChangeHandler: Connected\\n\"); // CODE SNIP SKIP\n            CallLuaFunction(\"OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected\"); // CODE SNIP SKIP\n            break;\n        case XblRealTimeActivityConnectionState::Connecting:\n            // Handle connecting state\n            LogToFile(\"XblRealTimeActivityAddConnectionStateChangeHandler: Connecting\\n\"); // CODE SNIP SKIP\n            CallLuaFunction(\"OnXblRealTimeActivityAddConnectionStateChangeHandler_Connecting\"); // CODE SNIP SKIP\n            break;\n        case XblRealTimeActivityConnectionState::Disconnected:\n            // Handle disconnected state\n            LogToFile(\"XblRealTimeActivityAddConnectionStateChangeHandler: Disconnected\\n\"); // CODE SNIP SKIP\n            CallLuaFunction(\"OnXblRealTimeActivityAddConnectionStateChangeHandler_Disconnected\"); // CODE SNIP SKIP\n            break;\n        }\n\n    }, nullptr);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblRealTimeActivityAddConnectionStateChangeHandler complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivityRemoveConnectionStateChangeHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityAddConnectionStateChangeHandler\n    if (s_connectionStateHandlerContext != 0)\n    {\n        XblRealTimeActivityRemoveConnectionStateChangeHandler(Data()->xboxLiveContext, s_connectionStateHandlerContext);\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblRealTimeActivityRemoveConnectionStateChangeHandler complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivityAddSubscriptionErrorHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityAddSubscriptionErrorHandler\n    s_subscriptionErrorHandlerContext = XblRealTimeActivityAddSubscriptionErrorHandler(Data()->xboxLiveContext,\n        [](void* context, _In_ XblRealTimeActivitySubscriptionHandle subscription, HRESULT subscriptionError)\n    {\n        UNREFERENCED_PARAMETER(context); // CODE SNIP SKIP\n        UNREFERENCED_PARAMETER(subscription); // CODE SNIP SKIP\n        // Handle subscription error\n        LogToFile(\"Rta subscription error %s\", ConvertHR(subscriptionError).c_str());\n    }, nullptr);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblRealTimeActivityAddSubscriptionErrorHandler complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivityRemoveSubscriptionErrorHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityRemoveConnectionStateChangeHandler\n    if (s_subscriptionErrorHandlerContext != 0)\n    {\n        XblRealTimeActivityRemoveConnectionStateChangeHandler(Data()->xboxLiveContext, s_subscriptionErrorHandlerContext);\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblRealTimeActivityRemoveConnectionStateChangeHandler complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivityAddResyncHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityAddResyncHandler\n    s_resyncHandlerContext = XblRealTimeActivityAddResyncHandler(Data()->xboxLiveContext,\n        [](void* context)\n    {\n        UNREFERENCED_PARAMETER(context); // CODE SNIP SKIP\n        // Handle resync\n        LogToFile(\"XblResyncHandler called\");\n    }, nullptr);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblRealTimeActivityAddResyncHandler complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivityRemoveResyncHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblRealTimeActivityRemoveConnectionStateChangeHandler\n    if (s_resyncHandlerContext != 0)\n    {\n        XblRealTimeActivityRemoveResyncHandler(Data()->xboxLiveContext, s_resyncHandlerContext);\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblRealTimeActivityRemoveResyncHandler complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivitySubscriptionGetState_Lua(lua_State *L)\n{\n    XblRealTimeActivitySubscriptionHandle rtaSubscriptionHandle{ nullptr };\n    if (Data()->statisticChangeSubscriptionHandle)\n    {\n        rtaSubscriptionHandle = Data()->statisticChangeSubscriptionHandle;\n    }\n\n    if (rtaSubscriptionHandle)\n    {\n        // CODE SNIPPET START: XblRealTimeActivitySubscriptionGetState\n        XblRealTimeActivitySubscriptionState state;\n        XblRealTimeActivitySubscriptionGetState(Data()->statisticChangeSubscriptionHandle, &state);\n        // CODE SNIPPET END\n    }\n\n    LogToFile(\"XblRealTimeActivitySubscriptionGetState complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRealTimeActivitySubscriptionGetId_Lua(lua_State *L)\n{\n    XblRealTimeActivitySubscriptionHandle rtaSubscriptionHandle{ nullptr };\n    if (Data()->statisticChangeSubscriptionHandle)\n    {\n        rtaSubscriptionHandle = Data()->statisticChangeSubscriptionHandle;\n    }\n\n    if (rtaSubscriptionHandle)\n    {\n        // CODE SNIPPET START: XblRealTimeActivitySubscriptionGetId\n        uint32_t subscriptionId;\n        XblRealTimeActivitySubscriptionGetId(rtaSubscriptionHandle, &subscriptionId);\n        // CODE SNIPPET END\n    }\n\n    LogToFile(\"XblRealTimeActivitySubscriptionGetId complete\");\n    return LuaReturnHR(L, S_OK);\n}\n\n// Declare test hook\nHRESULT XblTestHooksTriggerRTAResync();\n\nint XblTestHooksTriggerRTAResync_Lua(lua_State *L)\n{\n    HRESULT hr = S_OK;\n#if HC_PLATFORM != HC_PLATFORM_IOS\n    // For some reason XCode complaining about link errors with this test hook. Disabling on iOS until that can be investigated\n    hr = XblTestHooksTriggerRTAResync();\n#endif\n    return LuaReturnHR(L, hr);\n}\n\n#if !XSAPI_NO_PPL && HC_PLATFORM_IS_MICROSOFT && HC_PLATFORM != HC_PLATFORM_GDK\n#include \"combaseapi.h\"\n#include \"xsapi-cpp/services.h\"\n\nstruct RealTimeActivityState\n{\n    std::shared_ptr<xbox::services::xbox_live_context> xblContext;\n    std::shared_ptr<xbox::services::multiplayer::multiplayer_session> session;\n};\nstd::unique_ptr<RealTimeActivityState> g_multiplayerState;\n\nRealTimeActivityState* RTAState()\n{\n    if (g_multiplayerState == nullptr)\n    {\n        g_multiplayerState = std::make_unique<RealTimeActivityState>();\n    }\n    return g_multiplayerState.get();\n}\n\nint XblRtaMultiplayerInit_Lua(lua_State *L)\n{\n    using namespace xbox::services;\n    using namespace xbox::services::multiplayer;\n\n    stringstream_t stream;\n    stream << Data()->scid;\n    string_t SCID = stream.str();\n    string_t SessionTemplate = L\"GameSession\";\n    GUID guid;\n    CoCreateGuid(&guid);\n    OLECHAR* guidString;\n    StringFromCLSID(guid, &guidString);\n    string_t SessionName = guidString;\n    SessionName = SessionName.substr(1, SessionName.length() - 2);\n\n    stringstream_t xuidStream;\n    xuidStream << Data()->xboxUserId;\n\n\n    auto context = RTAState();\n\n    std::shared_ptr<xbox_live_context> xblContext = std::make_shared<xbox_live_context>(Data()->xalUser);\n\n    context->xblContext = xblContext;\n    auto multiplayerSessionReference = std::make_shared<multiplayer_session_reference>(SCID, SessionTemplate, SessionName);\n    context->session = std::make_shared<multiplayer_session>(xuidStream.str(), *multiplayerSessionReference);\n    auto session = context->session;\n\n    xblContext->multiplayer_service().enable_multiplayer_subscriptions();\n\n    xblContext->multiplayer_service().add_multiplayer_connection_id_changed_handler([]() {\n        LogToFile(\"add_multiplayer_connection_id_changed_handler\");\n        auto context = RTAState();\n        auto xblContext = context->xblContext;\n        auto session = context->session;\n\n        LogToFile(\"updating mpsd connection id\");\n        xblContext->multiplayer_service().get_current_session(session->session_reference())\n            .then([context](xbox_live_result<std::shared_ptr<multiplayer_session>> result) {\n\n            if (result.err())\n            {\n                LogToFile(\"you've been kicked\");\n            }\n            else if (auto session{ result.payload() })\n            {\n                context->session = session;\n                context->session->set_current_user_status(multiplayer_session_member_status::active);\n                context->xblContext->multiplayer_service().write_session(context->session, multiplayer_session_write_mode::update_or_create_new)\n                    .then([context](xbox_live_result<std::shared_ptr<multiplayer_session>> result2) {\n\n                    if (result2.err())\n                    {\n                        LogToFile(\"you've been kicked 2\");\n                    }\n                    else\n                    {\n                        context->session = result2.payload();\n                    }\n                });\n            }\n        });\n    });\n\n    int count = 0;\n\n    LogToFile(\"creating the session\");\n    session->join();\n    session->set_current_user_member_custom_property_json(L\"count\", web::json::value(count));\n    xblContext->multiplayer_service().write_session(session, multiplayer_session_write_mode::update_or_create_new)\n        .then([context](xbox_live_result<std::shared_ptr<multiplayer_session>> result) {\n\n        if (result.err())\n        {\n            LogToFile(\"get_current_session err\");\n        }\n        else\n        {\n            context->session = result.payload();\n        }\n    });\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblRtaMultiplayerOnConnected_Lua(lua_State *L)\n{\n    return LuaReturnHR(L, S_OK);\n}\n#endif //!XSAPI_NO_PPL && HC_PLATFORM_IS_MICROSOFT\n\nvoid SetupAPIs_XblRta()\n{\n    lua_register(Data()->L, \"XblRealTimeActivityActivate\", XblRealTimeActivityActivate_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityDeactivate\", XblRealTimeActivityDeactivate_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityAddConnectionStateChangeHandler\", XblRealTimeActivityAddConnectionStateChangeHandler_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityRemoveConnectionStateChangeHandler\", XblRealTimeActivityRemoveConnectionStateChangeHandler_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityAddSubscriptionErrorHandler\", XblRealTimeActivityAddSubscriptionErrorHandler_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityRemoveSubscriptionErrorHandler\", XblRealTimeActivityRemoveSubscriptionErrorHandler_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityAddResyncHandler\", XblRealTimeActivityAddResyncHandler_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivityRemoveResyncHandler\", XblRealTimeActivityRemoveResyncHandler_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivitySubscriptionGetState\", XblRealTimeActivitySubscriptionGetState_Lua);\n    lua_register(Data()->L, \"XblRealTimeActivitySubscriptionGetId\", XblRealTimeActivitySubscriptionGetId_Lua);\n    lua_register(Data()->L, \"XblTestHooksTriggerRTAResync\", XblTestHooksTriggerRTAResync_Lua);\n\n#if !XSAPI_NO_PPL && HC_PLATFORM_IS_MICROSOFT && HC_PLATFORM != HC_PLATFORM_GDK\n    lua_register(Data()->L, \"XblRtaMultiplayerInit\", XblRtaMultiplayerInit_Lua);\n    lua_register(Data()->L, \"XblRtaMultiplayerOnConnected\", XblRtaMultiplayerOnConnected_Lua);\n#endif\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_social.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\nstatic struct SocialState\n{\n    SocialState() = default;\n    ~SocialState()\n    {\n        // Validate that our tests cleaned up properly\n        assert(!socialResultHandle);\n        assert(!socialSubscriptionHandle);\n        assert(!socialRelationshipChangedHandlerToken);\n    }\n\n    XblSocialRelationshipResultHandle socialResultHandle{ nullptr };\n    XblRealTimeActivitySubscriptionHandle socialSubscriptionHandle{ nullptr };\n    XblFunctionContext socialRelationshipChangedHandlerToken{ 0 };\n    XblFunctionContext friendRequestCountChangedHandlerToken{ 0 };\n} state;\n\nXblSocialRelationshipFilter ConvertStringToXblSocialRelationshipFilter(const char* str)\n{\n    XblSocialRelationshipFilter filter = XblSocialRelationshipFilter::All;\n\n    if (pal::stricmp(str, \"XblSocialRelationshipFilter::All\") == 0) filter = XblSocialRelationshipFilter::All;\n    else if (pal::stricmp(str, \"XblSocialRelationshipFilter::Favorite\") == 0) filter = XblSocialRelationshipFilter::Favorite;\n    else if (pal::stricmp(str, \"XblSocialRelationshipFilter::LegacyXboxLiveFriends\") == 0) filter = XblSocialRelationshipFilter::LegacyXboxLiveFriends;\n\n    return filter;\n}\n\nint XblSocialGetSocialRelationshipsAsync_Lua(lua_State *L)\n{\n    XblSocialRelationshipFilter socialRelationshipFilter = ConvertStringToXblSocialRelationshipFilter(GetStringFromLua(L, 1, \"XblSocialRelationshipFilter::All\").c_str());\n\n    // CODE SNIPPET START: XblSocialGetSocialRelationshipsAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XblSocialGetSocialRelationshipsResult(asyncBlock, &state.socialResultHandle);\n\n        // Be sure to call XblSocialRelationshipResultCloseHandle when the result object is no longer needed\n        LogToFile(\"XblSocialGetSocialRelationshipsResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblSocialGetSocialRelationshipsAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblSocialGetSocialRelationshipsAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        socialRelationshipFilter,\n        0,\n        0,\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialGetSocialRelationshipsAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialRelationshipResultGetRelationships_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialRelationshipResultGetRelationships_C\n    const XblSocialRelationship* relationships = nullptr;\n    size_t relationshipsCount = 0;\n    HRESULT hr = XblSocialRelationshipResultGetRelationships(state.socialResultHandle, &relationships, &relationshipsCount);\n\n    LogToFile(\"Got %u SocialRelationships:\", relationshipsCount);\n    for (size_t i = 0; i < relationshipsCount; ++i)\n    {\n        LogToFile(\"Xuid = %u, isFollowingCaller = %u\", relationships[i].xboxUserId, relationships[i].isFollowingCaller);\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialRelationshipResultGetRelationships: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialRelationshipResultHasNext_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialRelationshipResultHasNext_C\n    bool hasNext{ false };\n    HRESULT hr = XblSocialRelationshipResultHasNext(state.socialResultHandle, &hasNext);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialRelationshipResultHasNext: hr=%s hasNext=%s\", ConvertHR(hr).c_str(), hasNext ? \"true\" : \"false\");\n    lua_pushnumber(L, (int)hasNext);\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblSocialRelationshipResultGetNextAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialRelationshipResultGetNextAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        // Close handle to previous page of results\n        if (state.socialResultHandle)\n        {\n            XblSocialRelationshipResultCloseHandle(state.socialResultHandle);\n        }\n        HRESULT hr = XblSocialRelationshipResultGetNextResult(asyncBlock, &state.socialResultHandle);\n        LogToFile(\"XblSocialRelationshipResultGetNextResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblSocialRelationshipResultGetNextAsync\"); // CODE SNIP SKIP\n    };\n\n    uint32_t maxItems = 100;\n    HRESULT hr = XblSocialRelationshipResultGetNextAsync(Data()->xboxLiveContext, state.socialResultHandle, maxItems, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToFile(\"XblSocialRelationshipResultGetNextAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialRelationshipResultDuplicateHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialRelationshipResultDuplicateHandle_C\n    XblSocialRelationshipResultHandle handle{};\n    XblSocialRelationshipResultDuplicateHandle(state.socialResultHandle, &handle);\n    // CODE SNIPPET END\n\n    XblSocialRelationshipResultCloseHandle(handle);\n    LogToFile(\"XblSocialRelationshipResultDuplicateHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblSocialRelationshipResultCloseHandle_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialRelationshipResultCloseHandle_C\n    XblSocialRelationshipResultCloseHandle(state.socialResultHandle);\n    state.socialResultHandle = nullptr;\n    // CODE SNIPPET END\n    LogToFile(\"XblSocialRelationshipResultCloseHandle\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblSocialSubscribeToSocialRelationshipChange_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialSubscribeToSocialRelationshipChange_C\n#if XSAPI_BUILT_FROM_SOURCE // CODE SNIP SKIP // TODO Remove when new GDK bins are generated\n    HRESULT hr = XblSocialSubscribeToSocialRelationshipChange(\n        Data()->xboxLiveContext, \n        Data()->xboxUserId, \n        &state.socialSubscriptionHandle\n    );\n    // CODE SNIPPET END\n    LogToFile(\"XblSocialSubscribeToSocialRelationshipChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint XblSocialUnsubscribeFromSocialRelationshipChange_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialUnsubscribeFromSocialRelationshipChange_C\n#if XSAPI_BUILT_FROM_SOURCE // CODE SNIP SKIP // TODO Remove when new GDK bins are generated\n    HRESULT hr = XblSocialUnsubscribeFromSocialRelationshipChange(\n        Data()->xboxLiveContext,\n        state.socialSubscriptionHandle\n    );\n\n    state.socialSubscriptionHandle = nullptr;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialUnsubscribeFromSocialRelationshipChange: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n#else\n    return LuaReturnHR(L, S_OK);\n#endif\n}\n\nint XblSocialAddSocialRelationshipChangedHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialAddSocialRelationshipChangedHandler_C\n    state.socialRelationshipChangedHandlerToken = XblSocialAddSocialRelationshipChangedHandler(\n        Data()->xboxLiveContext,\n        [](const XblSocialRelationshipChangeEventArgs* args, void* context)\n        {\n            UNREFERENCED_PARAMETER(context);\n            LogToFile(\"Social relationship changed:\");\n            std::stringstream ss;\n            for (size_t i = 0; i < args->xboxUserIdsCount; ++i)\n            {\n                if (i > 0) \n                {\n                    ss << \", \";\n                }\n                ss << args->xboxUserIds[i];\n            }\n            LogToFile(\"socialNotification = %u, affectedXuids = %s\", args->socialNotification, ss.str().data());\n            CallLuaFunction(\"OnSocialRelationshipChanged\"); // CODE SNIP SKIP\n        },\n        nullptr\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialAddSocialRelationshipChangedHandler\");\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblSocialRemoveSocialRelationshipChangedHandler_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialRemoveSocialRelationshipChangedHandler_C\n    HRESULT hr = XblSocialRemoveSocialRelationshipChangedHandler(Data()->xboxLiveContext, state.socialRelationshipChangedHandlerToken);\n\n    state.socialRelationshipChangedHandlerToken = 0;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialRemoveSocialRelationshipChangedHandler: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialAddFriendRequestCountChangedHandler_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblSocialAddSocialRelationshipChangedHandler_C\n    HRESULT hr = XblSocialAddFriendRequestCountChangedHandler(\n        Data()->xboxLiveContext,\n        [](const XblSocialFriendRequestCountChangedEventArgs* args, void* context)\n    {\n        UNREFERENCED_PARAMETER(context);\n        LogToFile(\"Incoming friend request count changed: %u\", args->incomingFriendRequestCount);\n        CallLuaFunction(\"OnFriendRequestCountChanged\"); // CODE SNIP SKIP\n    },\n        nullptr,\n        &state.friendRequestCountChangedHandlerToken\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialAddFriendRequestCountChangedHandler: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialRemoveFriendRequestCountChangedHandler_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblSocialRemoveSocialRelationshipChangedHandler_C\n    HRESULT hr = XblSocialRemoveFriendRequestCountChangedHandler(Data()->xboxLiveContext, state.friendRequestCountChangedHandlerToken);\n\n    state.friendRequestCountChangedHandlerToken = 0;\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialRemoveFriendRequestCountChangedHandler: hr=%s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialSubmitReputationFeedbackAsync_Lua(lua_State* L)\n{\n    // CODE SNIPPET START: XblSocialSubmitReputationFeedbackAsync_C\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"XblSocialSubmitReputationFeedbackAsync: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblSocialSubmitReputationFeedbackAsync\"); // CODE SNIP SKIP\n    };\n\n    uint64_t xuid{ 2814639011617876 };\n    HRESULT hr = XblSocialSubmitReputationFeedbackAsync(\n        Data()->xboxLiveContext,\n        xuid,\n        XblReputationFeedbackType::PositiveHelpfulPlayer,\n        nullptr,\n        \"Helpful player\",\n        nullptr,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialSubmitBatchReputationFeedbackAsync_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialSubmitBatchReputationFeedbackAsync_C\n    std::vector<XblReputationFeedbackItem> feedbackItems;\n    feedbackItems.push_back(XblReputationFeedbackItem\n        {\n            2814639011617876,\n            XblReputationFeedbackType::PositiveHelpfulPlayer,\n            nullptr,\n            \"Helpful player\",\n            nullptr\n        });\n    // Add any additional feedback items here\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"XblSocialSubmitBatchReputationFeedbackAsync: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblSocialSubmitBatchReputationFeedbackAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblSocialSubmitBatchReputationFeedbackAsync(\n        Data()->xboxLiveContext,\n        feedbackItems.data(),\n        feedbackItems.size(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\n\nint profile_service_get_user_profile_Lua(lua_State *L)\n{\n    HRESULT hr = S_OK;\n\n#if XSAPI_BUILT_FROM_SOURCE && HC_PLATFORM != HC_PLATFORM_UWP && HC_PLATFORM != HC_PLATFORM_GDK\n    std::shared_ptr<xbox::services::xbox_live_context> xblc = std::make_shared<xbox::services::xbox_live_context>(Data()->xalUser);\n    xblc->profile_service().get_user_profile(L\"1234\")\n        .then([](xbox::services::xbox_live_result<xbox::services::social::xbox_user_profile> result)\n    {\n        HRESULT hr = ConvertXboxLiveErrorCodeToHresult(result.err());\n        LogToFile(\"get_user_profile: hr=%s\", ConvertHR(hr).c_str()); \n        CallLuaFunctionWithHr(S_OK, \"On_profile_service_get_user_profile\"); \n    });\n#endif\n\n    return LuaReturnHR(L, hr);\n}\n\nint UnsubscribeToTitleAndDevicePresenceChangeForFriends_Lua(lua_State *L)\n{\n    HRESULT hr = S_OK;\n\n    for (XblRealTimeActivitySubscriptionHandle subscriptionHandleDevice : Data()->subscriptionHandleDeviceList)\n    {\n        hr = XblPresenceUnsubscribeFromDevicePresenceChange(\n            Data()->xboxLiveContext,\n            subscriptionHandleDevice\n        );\n        LuaStopTestIfFailed(hr);\n        assert(SUCCEEDED(hr));\n    }\n\n    for (XblRealTimeActivitySubscriptionHandle subscriptionHandleTitle : Data()->subscriptionHandleTitleList)\n    {\n        hr = XblPresenceUnsubscribeFromTitlePresenceChange(\n            Data()->xboxLiveContext,\n            subscriptionHandleTitle\n        );\n    }\n\n    Data()->subscriptionHandleTitleList.clear();\n    Data()->subscriptionHandleDeviceList.clear();\n\n    LogToScreen(\"UnsubscribeToTitleAndDevicePresenceChangeForFriends: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint SubscribeToTitleAndDevicePresenceChangeForFriends_Lua(lua_State *L)\n{\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XblSocialGetSocialRelationshipsResult(asyncBlock, &state.socialResultHandle);\n\n        const XblSocialRelationship* relationships = nullptr;\n        size_t relationshipsCount = 0;\n        hr = XblSocialRelationshipResultGetRelationships(state.socialResultHandle, &relationships, &relationshipsCount);\n\n        Data()->subscriptionHandleTitleList.clear();\n        Data()->subscriptionHandleDeviceList.clear();\n\n        XblRealTimeActivitySubscriptionHandle subscriptionHandleDevice;\n        XblRealTimeActivitySubscriptionHandle subscriptionHandleTitle;\n        LogToScreen(\"Got %u SocialRelationships:\", relationshipsCount);\n        for (size_t i = 0; i < relationshipsCount; ++i)\n        {\n            if (i % 100 == 0)\n            {\n                LogToScreen(\"Sub'ing to friend %d\", i);\n            }\n\n            hr = XblPresenceSubscribeToDevicePresenceChange(\n                Data()->xboxLiveContext,\n                relationships[i].xboxUserId,\n                &subscriptionHandleDevice);\n            LuaStopTestIfFailed(hr);\n            assert(SUCCEEDED(hr));\n\n            hr = XblPresenceSubscribeToTitlePresenceChange(\n                Data()->xboxLiveContext,\n                relationships[i].xboxUserId,\n                Data()->titleId,\n                &subscriptionHandleTitle);\n            LuaStopTestIfFailed(hr);\n            assert(SUCCEEDED(hr));\n\n            Data()->subscriptionHandleDeviceList.push_back(subscriptionHandleDevice);\n            Data()->subscriptionHandleTitleList.push_back(subscriptionHandleTitle);\n        }\n\n        LogToScreen(\"SubscribeToTitleAndDevicePresenceChangeForFriends: hr=%s\", ConvertHR(hr).c_str());\n        CallLuaFunctionWithHr(hr, \"OnSubscribeToTitleAndDevicePresenceChangeForFriends\"); \n    };\n\n    HRESULT hr = XblSocialGetSocialRelationshipsAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        XblSocialRelationshipFilter::All,\n        0,\n        0,\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    LogToFile(\"SubscribeToTitleAndDevicePresenceChangeForFriends: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblSocial()\n{\n    lua_register(Data()->L, \"XblSocialGetSocialRelationshipsAsync\", XblSocialGetSocialRelationshipsAsync_Lua);\n    lua_register(Data()->L, \"XblSocialRelationshipResultGetRelationships\", XblSocialRelationshipResultGetRelationships_Lua);\n    lua_register(Data()->L, \"XblSocialRelationshipResultHasNext\", XblSocialRelationshipResultHasNext_Lua);\n    lua_register(Data()->L, \"XblSocialRelationshipResultGetNextAsync\", XblSocialRelationshipResultGetNextAsync_Lua);\n    lua_register(Data()->L, \"XblSocialRelationshipResultDuplicateHandle\", XblSocialRelationshipResultDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XblSocialRelationshipResultCloseHandle\", XblSocialRelationshipResultCloseHandle_Lua);\n    \n    lua_register(Data()->L, \"XblSocialSubscribeToSocialRelationshipChange\", XblSocialSubscribeToSocialRelationshipChange_Lua);\n    lua_register(Data()->L, \"XblSocialUnsubscribeFromSocialRelationshipChange\", XblSocialUnsubscribeFromSocialRelationshipChange_Lua);\n    lua_register(Data()->L, \"XblSocialAddSocialRelationshipChangedHandler\", XblSocialAddSocialRelationshipChangedHandler_Lua);\n    lua_register(Data()->L, \"XblSocialRemoveSocialRelationshipChangedHandler\", XblSocialRemoveSocialRelationshipChangedHandler_Lua);\n    lua_register(Data()->L, \"XblSocialAddFriendRequestCountChangedHandler\", XblSocialAddFriendRequestCountChangedHandler_Lua);\n    lua_register(Data()->L, \"XblSocialRemoveFriendRequestCountChangedHandler\", XblSocialRemoveFriendRequestCountChangedHandler_Lua);\n\n    lua_register(Data()->L, \"XblSocialSubmitReputationFeedbackAsync\", XblSocialSubmitReputationFeedbackAsync_Lua);\n    lua_register(Data()->L, \"XblSocialSubmitBatchReputationFeedbackAsync\", XblSocialSubmitBatchReputationFeedbackAsync_Lua);\n\n    lua_register(Data()->L, \"SubscribeToTitleAndDevicePresenceChangeForFriends\", SubscribeToTitleAndDevicePresenceChangeForFriends_Lua);\n    lua_register(Data()->L, \"UnsubscribeToTitleAndDevicePresenceChangeForFriends\", UnsubscribeToTitleAndDevicePresenceChangeForFriends_Lua);\n\n    lua_register(Data()->L, \"profile_service_get_user_profile\", profile_service_get_user_profile_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_social_manager.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include <atomic>\n\nstatic struct SocialManagerState\n{\n    // TODO move doWork logic into this state class\n    SocialManagerState() = default;\n    ~SocialManagerState()\n    {\n        // Validate that our tests cleaned up correctly\n        assert(!doWork);\n        assert(groups.empty());\n    }\n\n    std::set<XblSocialManagerUserGroupHandle> groups;\n    std::thread doWorkThread{};\n    std::atomic<bool> doWork{ false };\n    std::atomic<bool> doWorkJoinWhenDone{ false };\n} state;\n\nHRESULT SocialManagerDoWork()\n{\n    // CODE SNIPPET START: XblSocialManagerDoWork_C\n    const XblSocialManagerEvent* events{ nullptr };\n    size_t eventCount{ 0 };\n    HRESULT hr = XblSocialManagerDoWork(&events, &eventCount);\n    if (SUCCEEDED(hr))\n    {\n        for (size_t i = 0; i < eventCount; i++)\n        {\n            // Act on the event\n            auto& socialEvent = events[i];\n            // CODE SKIP START\n            static std::unordered_map<XblSocialManagerEventType, std::string> eventTypesMap\n            {\n                { XblSocialManagerEventType::UsersAddedToSocialGraph, \"UsersAddedToSocialGraph\" },\n                { XblSocialManagerEventType::UsersRemovedFromSocialGraph, \"UsersRemovedFromSocialGraph\" },\n                { XblSocialManagerEventType::PresenceChanged, \"PresenceChanged\" },\n                { XblSocialManagerEventType::ProfilesChanged, \"ProfilesChanged\" },\n                { XblSocialManagerEventType::SocialRelationshipsChanged, \"SocialRelationshipsChanged\" },\n                { XblSocialManagerEventType::LocalUserAdded, \"LocalUserAdded\" },\n                { XblSocialManagerEventType::SocialUserGroupLoaded, \"SocialUserGroupLoaded\" },\n                { XblSocialManagerEventType::SocialUserGroupUpdated, \"SocialUserGroupUpdated\" },\n                { XblSocialManagerEventType::UnknownEvent, \"UnknownEvent\" }\n            };\n            // CODE SKIP END\n            std::stringstream ss;\n            ss << \"XblSocialManagerDoWork: Event of type \" << eventTypesMap[socialEvent.eventType] << std::endl;\n            for (size_t j = 0; j < XBL_SOCIAL_MANAGER_MAX_AFFECTED_USERS_PER_EVENT; j++)\n            {\n                if (socialEvent.usersAffected[j] != nullptr)\n                {\n                    if (j == 0)\n                    {\n                        ss << \"Users affected: \" << std::endl;\n                    }\n                    ss << \"\\t\" << socialEvent.usersAffected[j]->gamertag << std::endl;\n                }\n            }\n            LogToFile(ss.str().c_str());\n            // CODE SKIP START\n            switch (socialEvent.eventType)\n            {\n            case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                LogToFile(\"XblSocialManagerDoWork: UsersAddedToSocialGraph event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_UsersAddedToSocialGraphEvent\");\n                break;\n            case XblSocialManagerEventType::UsersRemovedFromSocialGraph:\n                LogToFile(\"XblSocialManagerDoWork: UsersRemovedFromSocialGraph event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_UsersRemovedFromSocialGraphEvent\");\n                break;\n            case XblSocialManagerEventType::PresenceChanged:\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_PresenceChangedEvent\");\n                break;\n            case XblSocialManagerEventType::ProfilesChanged:\n                LogToFile(\"XblSocialManagerDoWork: ProfilesChanged event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_ProfilesChangedEvent\");\n                break;\n            case XblSocialManagerEventType::SocialRelationshipsChanged:\n                LogToFile(\"XblSocialManagerDoWork: SocialRelationshipsChanged event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_SocialRelationshipsChangedEvent\");\n                break;\n            case XblSocialManagerEventType::LocalUserAdded:\n                LogToFile(\"XblSocialManagerDoWork: LocalUserAdded event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_LocalUserAddedEvent\");\n                break;\n            case XblSocialManagerEventType::SocialUserGroupLoaded:\n                LogToFile(\"XblSocialManagerDoWork: SocialUserGroupLoaded event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent\");\n                break;\n            case XblSocialManagerEventType::SocialUserGroupUpdated:\n                LogToFile(\"XblSocialManagerDoWork: SocialUserGroupUpdated event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent\");\n                break;\n            case XblSocialManagerEventType::UnknownEvent:\n            default:\n                LogToFile(\"XblSocialManagerDoWork: Unknown event\");\n                CallLuaFunctionWithHr(hr, \"OnXblSocialManagerDoWork_UnknownEvent\");\n                break;\n            }\n            // CODE SKIP END\n        }\n    }\n    // CODE SNIPPET END\n    return hr;\n}\n\nint StartSocialManagerDoWorkLoop_Lua(lua_State* L)\n{\n    state.doWork = true;\n    state.doWorkJoinWhenDone = true;\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    state.doWorkThread = std::thread([]()\n    {\n        Data()->m_socialDoWorkDone = false;\n        while (state.doWork && !Data()->m_quit)\n        {\n            {\n                std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n                SocialManagerDoWork();\n            }\n            pal::Sleep(10);\n        }\n        Data()->m_socialDoWorkDone = true;\n        LogToFile(\"Exiting do work thread\");\n    });\n    return LuaReturnHR(L, S_OK);\n}\n\nint StopSocialManagerDoWorkLoop_Lua(lua_State* L)\n{\n    LogToFile(\"StopSocialManagerDoWorkLoop_Lua\");\n    state.doWorkJoinWhenDone = true;\n    state.doWork = false;\n\n#if ENABLE_PERF_PROFILING\n    LogToFile(xbox::services::detail::PerfTester::Instance().FormatStats().data());\n#endif\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid StopSocialManagerDoWorkHelper()\n{\n    if (state.doWorkJoinWhenDone)\n    {\n        state.doWork = false;\n        state.doWorkJoinWhenDone = false;\n        state.doWorkThread.join();\n    }\n}\n\nXblSocialManagerExtraDetailLevel ConvertStringToXblSocialManagerExtraDetailLevel(const char* str)\n{\n    XblSocialManagerExtraDetailLevel detailLevel = XblSocialManagerExtraDetailLevel::NoExtraDetail;\n\n    if (pal::stricmp(str, \"XblSocialManagerExtraDetailLevel::TitleHistoryLevel\") == 0) detailLevel = XblSocialManagerExtraDetailLevel::TitleHistoryLevel;\n    else if (pal::stricmp(str, \"XblSocialManagerExtraDetailLevel::PreferredColorLevel\") == 0) detailLevel = XblSocialManagerExtraDetailLevel::PreferredColorLevel;\n    else if (pal::stricmp(str, \"XblSocialManagerExtraDetailLevel::All\") == 0) detailLevel = XblSocialManagerExtraDetailLevel::All;\n\n    return detailLevel;\n}\n\nXblPresenceFilter ConvertStringToXblPresenceFilter(const std::string& filterString)\n{\n    XblPresenceFilter filter = XblPresenceFilter::Unknown;\n    auto str{ filterString.data() };\n\n    if (pal::stricmp(str, \"XblPresenceFilter::TitleOnline\") == 0) filter = XblPresenceFilter::TitleOnline;\n    else if (pal::stricmp(str, \"XblPresenceFilter::TitleOffline\") == 0) filter = XblPresenceFilter::TitleOffline;\n#if XSAPI_BUILT_FROM_SOURCE\n    else if (pal::stricmp(str, \"XblPresenceFilter::TitleOnlineOutsideTitle\") == 0) filter = XblPresenceFilter::TitleOnlineOutsideTitle;\n#endif\n    else if (pal::stricmp(str, \"XblPresenceFilter::AllOnline\") == 0) filter = XblPresenceFilter::AllOnline;\n    else if (pal::stricmp(str, \"XblPresenceFilter::AllOffline\") == 0) filter = XblPresenceFilter::AllOffline;\n    else if (pal::stricmp(str, \"XblPresenceFilter::AllTitle\") == 0) filter = XblPresenceFilter::AllTitle;\n    else if (pal::stricmp(str, \"XblPresenceFilter::All\") == 0) filter = XblPresenceFilter::All;\n\n    return filter;\n}\n\nXblRelationshipFilter ConvertStringToXblRelationshipFilter(const std::string& filterString)\n{\n    XblRelationshipFilter filter = XblRelationshipFilter::Friends;\n    auto str{ filterString.data() };\n\n    if (pal::stricmp(str, \"XblRelationshipFilter::Friends\") == 0) filter = XblRelationshipFilter::Friends;\n    else if (pal::stricmp(str, \"XblRelationshipFilter::Favorite\") == 0) filter = XblRelationshipFilter::Favorite;\n\n    return filter;\n}\n\n// commands\n\nint XblSocialManagerPresenceRecordIsUserPlayingTitle_Lua(lua_State *L)\n{\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n    uint32_t titleId = GetUint32FromLua(L, 1, 174925616);\n\n    if (group == nullptr)\n    {\n        LogToFile(\"XblSocialManagerPresenceRecordIsUserPlayingTitle: No XblSocialManagerUserGroup Loaded\");\n        return S_OK;\n    }\n\n    XblSocialManagerUserPtrArray users{ nullptr };\n    size_t count{ 0 };\n    HRESULT result = XblSocialManagerUserGroupGetUsers(group, &users, &count);\n\n    bool playingTitle{ false };\n    if (SUCCEEDED(result) && count > 0)\n    {\n        XblSocialManagerPresenceRecord presenceRecord = users[0]->presenceRecord;\n        // CODE SNIPPET START: XblSocialManagerPresenceRecordIsUserPlayingTitle\n        playingTitle = XblSocialManagerPresenceRecordIsUserPlayingTitle(&presenceRecord, Data()->titleId);\n        // CODE SNIPPET END\n\n        LogToFile(\"XblSocialManagerPresenceRecordIsUserPlayingTitle: TitleId: %d, playing: %u\", titleId, playingTitle);\n    }\n\n    LogToFile(\"XblSocialManagerPresenceRecordIsUserPlayingTitle: hr=%s\", ConvertHR(result).c_str());\n    return LuaReturnHR(L, result);\n}\n\nint XblSocialManagerUserGroupGetType_Lua(lua_State* L)\n{\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n\n    if (group == nullptr)\n    {\n        LogToFile(\"XblSocialManagerUserGroupGetUsers: No XblSocialManagerUserGroup Loaded\");\n        return S_OK;\n    }\n\n    // CODE SNIPPET START: XblSocialManagerUserGroupGetType\n    XblSocialUserGroupType type{ XblSocialUserGroupType::FilterType };\n    HRESULT hr = XblSocialManagerUserGroupGetType(group, &type);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerUserGroupGetType: type=%u, hr=%s\", type, ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerUserGroupGetLocalUser_Lua(lua_State* L)\n{\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n\n    // CODE SNIPPET START: XblSocialManagerUserGroupGetLocalUser\n    XblUserHandle user{ nullptr };\n    HRESULT hr = XblSocialManagerUserGroupGetLocalUser(group, &user);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerUserGroupGetLocalUser: user=%llu, hr=%s\", user, ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerUserGroupGetFilters_Lua(lua_State* L)\n{\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n\n    // CODE SNIPPET START: XblSocialManagerUserGroupGetFilters\n    XblPresenceFilter presenceFilter{ XblPresenceFilter::Unknown };\n    XblRelationshipFilter relationshipFilter{ XblRelationshipFilter::Unknown };\n    HRESULT hr = XblSocialManagerUserGroupGetFilters(group, &presenceFilter, &relationshipFilter);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerUserGroupGetFilters: presenceFilter=%u, relationshipFilter=%u, hr=%s\", presenceFilter, relationshipFilter, ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerUserGroupGetUsers_Lua(lua_State *L)\n{\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n\n    if (group == nullptr)\n    {\n        LogToFile(\"XblSocialManagerUserGroupGetUsers: No XblSocialManagerUserGroup Loaded\");\n        return S_OK;\n    }\n\n    // CODE SNIPPET START: XblSocialManagerUserGroupGetUsers_C\n    XblSocialManagerUserPtrArray users{ nullptr };\n    size_t userCount{ 0 };\n    HRESULT hr = XblSocialManagerUserGroupGetUsers(group, &users, &userCount);\n    LogToFile(\"XblSocialManagerUserGroupGetUsers: %s usersCount: %d\", ConvertHR(hr).c_str(), userCount); // CODE SNIP SKIP\n\n    for (size_t i = 0; i < userCount; ++i)\n    {\n        // Display user info etc.\n        // CODE SKIP START\n        LogToFile(\"\\t%s\", users[i]->gamertag);\n        // CODE SKIP END\n    }\n    // CODE SNIPPET END\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerUserGroupGetUsersTrackedByGroup_Lua(lua_State *L)\n{\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n\n    if (group == nullptr)\n    {\n        LogToFile(\"XblSocialManagerUserGroupGetUsersTrackedByGroup: No XblSocialManagerUserGroup Loaded\");\n        return S_OK;\n    }\n\n    // CODE SNIPPET START: XblSocialManagerUserGroupGetUsersTrackedByGroup\n    const uint64_t* xuids{ nullptr };\n    size_t count{ 0 };\n\n    HRESULT hr = XblSocialManagerUserGroupGetUsersTrackedByGroup(\n        group,\n        &xuids,\n        &count\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerUserGroupGetUsersTrackedByGroup: %s trackedUsersCount: %d\", ConvertHR(hr).c_str(), count);\n\n    for (size_t i = 0; i < count; ++i)\n    {\n        LogToFile(\"\\t%llu\", static_cast<unsigned long long>(xuids[i]));\n    }\n    LogToFile(\"XblSocialManagerUserGroupGetUsersTrackedByGroup: %s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerAddLocalUser_Lua(lua_State *L)\n{\n    XblSocialManagerExtraDetailLevel extraLevelDetail = ConvertStringToXblSocialManagerExtraDetailLevel(\n        GetStringFromLua(L, 1, \"XblSocialManagerExtraDetailLevel::NoExtraDetail\").c_str());\n    LogToFile(\"XblSocialManagerAddLocalUser: ExtraLevelDetail: %d\", extraLevelDetail);\n\n    XalUserHandle user = Data()->xalUser;\n    // CODE SNIPPET START: XblSocialManagerAddLocalUser\n    HRESULT hr = XblSocialManagerAddLocalUser(user, extraLevelDetail, nullptr);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerAddLocalUser: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerRemoveLocalUser_Lua(lua_State *L)\n{\n    XalUserHandle user = Data()->xalUser;\n    // CODE SNIPPET START: XblSocialManagerRemoveLocalUser_C\n    HRESULT hr = XblSocialManagerRemoveLocalUser(user);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerRemoveLocalUser: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblSocialManagerCreateSocialUserGroupFromFilters_Lua(lua_State *L)\n{\n    XalUserHandle user = Data()->xalUser;\n\n    // CODE SNIPPET START: XblSocialManagerCreateSocialUserGroupFromFilters_C\n    XblPresenceFilter presenceFilter{ XblPresenceFilter::All };\n    XblRelationshipFilter relationshipFilter{ XblRelationshipFilter::Friends };\n    // CODE SKIP START\n    XblPresenceFilter presenceFilterArg = ConvertStringToXblPresenceFilter(GetStringFromLua(L, 1, std::string{}));\n    if (presenceFilter != XblPresenceFilter::Unknown)\n    {\n        presenceFilter = presenceFilterArg;\n    }\n    XblRelationshipFilter relationshipFilterArg = ConvertStringToXblRelationshipFilter(GetStringFromLua(L, 2, std::string{}));\n    if (relationshipFilterArg != XblRelationshipFilter::Unknown)\n    {\n        relationshipFilter = relationshipFilterArg;\n    }\n\n    LogToFile(\"XblSocialManagerCreateSocialUserGroupFromFilters: PresenceFilter: %d\", presenceFilter);\n    LogToFile(\"XblSocialManagerCreateSocialUserGroupFromFilters: RelationshipFilter: %d\", relationshipFilter);\n    // CODE SKIP END\n\n    XblSocialManagerUserGroupHandle groupHandle{ nullptr };\n    HRESULT hr = XblSocialManagerCreateSocialUserGroupFromFilters(user, presenceFilter, relationshipFilter, &groupHandle);\n\n    if (SUCCEEDED(hr))\n    {\n        state.groups.insert(groupHandle);\n    }\n    // CODE SNIPPET END\n\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(groupHandle));\n\n    LogToFile(\"XblSocialManagerCreateSocialUserGroupFromFilters: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblSocialManagerDestroySocialUserGroup_Lua(lua_State* L)\n{\n    auto groupHandle{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n\n    // CODE SNIPPET START: XblSocialManagerDestroySocialUserGroup_C\n    HRESULT hr = XblSocialManagerDestroySocialUserGroup(groupHandle);\n    if (SUCCEEDED(hr))\n    {\n        state.groups.erase(groupHandle);\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerDestroySocialUserGroup: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\n// Pool of XDKS.1 xuids to create social groups from\nstd::vector<uint64_t> listXuids\n{\n    2814639011617876,2814641789541994,2814644008675844,2814644210052185,2814645164579523,2814646075485729,2814649783195402,2814650260879943,\n    2814652370182940,2814652714045777,2814654391560620,2814654975417728,2814656000993855,2814660006763195,2814666715930430,2814667316080600,\n    2814669550092398,2814669684179632,2814669733667211,2814671180786692,2814679901432274,2814613501048225,2814614352529204,2814615856126401,\n    2814616641363830,2814617883586813,2814618053453081,2814629752527080,2814631255161151,2814632477267887,2814633284389038,2814635732495522,\n    2814635779785472,2814635974475208,2814636979708499,2814618092438397,2814618260480530,2814618319551907,2814619559360314,2814620368929739,\n    2814620769042115,2814621007349381,2814623088399025,2814623825448960,2814624220291971,2814624961587858,2814626394212372,2814626639518570,\n    2814628203722867,2814629143923154,2814614382301082,2814614959737919,2814615558140392,2814618401629514,2814618701087902,2814619300882392,\n    2814623785189962,2814623956387698,2814625066090704,2814625471782204,2814626946705530,2814627006318591,2814628046127456,2814631487749991,\n    2814631517599783,2814632798310691,2814633582140204,2814634204785789,2814634895412664,2814635439049207,2814638609354868,2814639589885754,\n    2814641670947751,2814643512602566,2814646137630843,2814648499394446,2814651465227139,2814652150012664,2814653926747608,2814655098938516,\n    2814655264861214,2814655417678099,2814655883565306,2814656031821923,2814656159501072,2814656780954834,2814660657970845,2814661604435490,\n    2814663444319727,2814663818015575,2814665274839967,2814667273133504,2814670761542037,2814672762886609,2814673772488023,2814674096344056,\n    2814674229538758,2814678943953289,2814680898042782\n};\n\nint XblSocialManagerCreateSocialUserGroupFromList_Lua(lua_State *L)\n{\n    // Params:\n    // 1) number of xuids to include in list\n    // 2) offset in the above vector of first xuid\n    auto count{ GetUint64FromLua(L, 1, 10) };\n    auto offset{ GetUint64FromLua(L, 2, 0) };\n\n    assert(offset + count <= listXuids.size());\n\n    XalUserHandle user = Data()->xalUser;\n    // CODE SNIPPET START: XblSocialManagerCreateSocialUserGroupFromList_C\n    std::vector<uint64_t> xuids\n    {\n        listXuids.begin() + static_cast<int>(offset),\n        listXuids.begin() + static_cast<int>(offset + count) \n    };\n\n    XblSocialManagerUserGroupHandle groupHandle{ nullptr };\n    HRESULT hr = XblSocialManagerCreateSocialUserGroupFromList(user, xuids.data(), xuids.size(), &groupHandle);\n\n    if (SUCCEEDED(hr))\n    {\n        state.groups.insert(groupHandle);\n    }\n    // CODE SNIPPET END\n\n    lua_pushinteger(L, reinterpret_cast<lua_Integer>(groupHandle));\n\n    LogToFile(\"XblSocialManagerCreateSocialUserGroupFromList: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr, 1);\n}\n\nint XblSocialManagerGetLocalUsers_Lua(lua_State *L)\n{\n    // CODE SNIPPET START: XblSocialManagerGetLocalUsers\n    size_t localUsersCount = XblSocialManagerGetLocalUserCount();\n    std::vector<XblUserHandle> localUsers(localUsersCount, nullptr);\n    HRESULT hr = XblSocialManagerGetLocalUsers(localUsersCount, &localUsers[0]);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerGetLocalUsers: %s localUsersCount: %d\", ConvertHR(hr).c_str(), localUsersCount);\n\n    for (uint32_t i = 0; i < localUsersCount; i++)\n    {\n        size_t gamerTagSize = XalUserGetGamertagSize(localUsers[i], XalGamertagComponent_Classic);\n        std::vector<char> gamerTag(gamerTagSize, '\\0');\n\n        size_t bufferUsed;\n        hr = XalUserGetGamertag(localUsers[i], XalGamertagComponent_Classic, gamerTagSize, gamerTag.data(), &bufferUsed);\n        if (SUCCEEDED(hr))\n        {\n            LogToFile(\"\\t%s\", gamerTag.data());\n        }\n    }\n\n    LogToFile(\"XblSocialManagerGetLocalUsers: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerUpdateSocialUserGroup_Lua(lua_State *L)\n{\n    // Params:\n    // 1) group pointer\n    // 1) number of xuids to include in list\n    // 2) offset in the above vector of first xuid\n    auto group{ reinterpret_cast<XblSocialManagerUserGroupHandle>(GetUint64FromLua(L, 1, reinterpret_cast<uint64_t>(*state.groups.begin()))) };\n    auto count{ GetUint64FromLua(L, 2, 15) };\n    auto offset{ GetUint64FromLua(L, 3, 0) };\n\n    // CODE SNIPPET START: XblSocialManagerUpdateSocialUserGroup_C\n    std::vector<uint64_t> xuids\n    { \n        listXuids.begin() + static_cast<int>(offset),\n        listXuids.begin() + static_cast<int>(offset + count)\n    };\n\n    HRESULT hr = XblSocialManagerUpdateSocialUserGroup(group, xuids.data(), xuids.size());\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerUpdateSocialUserGroup: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerSetRichPresencePollingStatus_Lua(lua_State *L)\n{\n    bool shouldEnablePolling = GetBoolFromLua(L, 1, false);\n    LogToFile(\"XblSocialManagerSetRichPresencePollingStatus: ShouldEnablePolling: %s\", shouldEnablePolling ? \"true\" : \"false\");\n\n    XalUserHandle user = Data()->xalUser;\n    // CODE SNIPPET START: XblSocialManagerSetRichPresencePollingStatus\n    HRESULT hr = XblSocialManagerSetRichPresencePollingStatus(user, shouldEnablePolling);\n    // CODE SNIPPET END\n\n    LogToFile(\"XblSocialManagerSetRichPresencePollingStatus: %s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblSocialManagerDoWork_Lua(lua_State *L)\n{\n    HRESULT hr = SocialManagerDoWork();\n    LogToFile(\"XblSocialManagerDoWork: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblSocialManager()\n{\n    // Non XSAPI APIs\n    lua_register(Data()->L, \"StartSocialManagerDoWorkLoop\", StartSocialManagerDoWorkLoop_Lua);\n    lua_register(Data()->L, \"StopSocialManagerDoWorkLoop\", StopSocialManagerDoWorkLoop_Lua);\n\n    // XSAPI APIs\n    lua_register(Data()->L, \"XblSocialManagerPresenceRecordIsUserPlayingTitle\", XblSocialManagerPresenceRecordIsUserPlayingTitle_Lua);\n    lua_register(Data()->L, \"XblSocialManagerUserGroupGetType\", XblSocialManagerUserGroupGetType_Lua);\n    lua_register(Data()->L, \"XblSocialManagerUserGroupGetLocalUser\", XblSocialManagerUserGroupGetLocalUser_Lua);\n    lua_register(Data()->L, \"XblSocialManagerUserGroupGetFilters\", XblSocialManagerUserGroupGetFilters_Lua);\n    lua_register(Data()->L, \"XblSocialManagerUserGroupGetUsers\", XblSocialManagerUserGroupGetUsers_Lua);\n    lua_register(Data()->L, \"XblSocialManagerUserGroupGetUsersTrackedByGroup\", XblSocialManagerUserGroupGetUsersTrackedByGroup_Lua);\n    lua_register(Data()->L, \"XblSocialManagerAddLocalUser\", XblSocialManagerAddLocalUser_Lua);\n    lua_register(Data()->L, \"XblSocialManagerRemoveLocalUser\", XblSocialManagerRemoveLocalUser_Lua);\n    lua_register(Data()->L, \"XblSocialManagerCreateSocialUserGroupFromFilters\", XblSocialManagerCreateSocialUserGroupFromFilters_Lua);\n    lua_register(Data()->L, \"XblSocialManagerCreateSocialUserGroupFromList\", XblSocialManagerCreateSocialUserGroupFromList_Lua);\n    lua_register(Data()->L, \"XblSocialManagerGetLocalUsers\", XblSocialManagerGetLocalUsers_Lua);\n    lua_register(Data()->L, \"XblSocialManagerUpdateSocialUserGroup\", XblSocialManagerUpdateSocialUserGroup_Lua);\n    lua_register(Data()->L, \"XblSocialManagerSetRichPresencePollingStatus\", XblSocialManagerSetRichPresencePollingStatus_Lua);\n    lua_register(Data()->L, \"XblSocialManagerDoWork\", XblSocialManagerDoWork_Lua);\n    lua_register(Data()->L, \"XblSocialManagerDestroySocialUserGroup\", XblSocialManagerDestroySocialUserGroup_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_statistics.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nXBL_WARNING_DISABLE_DEPRECATED\n\nint GetLastStat_Lua(lua_State *L)\n{\n    long long n = Data()->lastUserStat;\n    lua_pushinteger(L, static_cast<lua_Integer>(n));\n    return 1;\n}\n\nint XblUserStatisticsGetSingleUserStatisticAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n    \n    auto statisticName = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\"); \n    LogToFile(\"XblUserStatisticsGetSingleUserStatisticAsync: statisticName: %s\", statisticName.c_str());\n    \n    // CODE SNIPPET START: XblUserStatisticsGetSingleUserStatisticAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblUserStatisticsGetSingleUserStatisticResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblUserStatisticsResult* result{};\n\n            hr = XblUserStatisticsGetSingleUserStatisticResult(asyncBlock, resultSize, buffer.data(), &result, nullptr);\n            VERIFY_IS_TRUE(result != nullptr, \"null\");// CODE SNIP SKIP\n            VERIFY_IS_TRUE(result->xboxUserId != 0, \"xuid\");// CODE SNIP SKIP\n            VERIFY_IS_TRUE(result->serviceConfigStatisticsCount == 1, \"serviceConfigStatisticsCount\");// CODE SNIP SKIP\n            VERIFY_IS_TRUE(result->serviceConfigStatistics[0].statisticsCount == 1, \"statisticsCount\");// CODE SNIP SKIP\n            VERIFY_IS_TRUE(strcmp(result->serviceConfigStatistics[0].statistics[0].statisticType, \"Integer\")==0, \"statisticType\");// CODE SNIP SKIP\n\n            if (SUCCEEDED(hr) && result->serviceConfigStatisticsCount > 0 && result->serviceConfigStatistics->statisticsCount > 0)\n            {\n                int64_t userStatValue = atoll(result->serviceConfigStatistics[0].statistics[0].value);\n                // Now you can show or store userStatValue\n                Data()->lastUserStat = userStatValue; // CODE SNIP SKIP\n                LogToScreen(\"%s's stat %s is %lld.  Note: With GDK, ensure fiddler isn't running for stat upload to work\", // CODE SNIP SKIP\n                    Data()->gamertag.c_str(), // CODE SNIP SKIP\n                    result->serviceConfigStatistics[0].statistics[0].statisticName, // CODE SNIP SKIP\n                    Data()->lastUserStat); // CODE SNIP SKIP\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblUserStatisticsGetSingleUserStatisticAsync\"); // CODE SNIP SKIP\n    };\n    \n    HRESULT hr = XblUserStatisticsGetSingleUserStatisticAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        Data()->scid,\n        statisticName.c_str(),\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblUserStatisticsGetSingleUserStatisticAsync: hr=%s\", ConvertHR(hr).c_str());\n    \n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsGetSingleUserStatisticsAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto statisticName1 = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\");\n    auto statisticName2 = GetStringFromLua(L, 2, \"TotalRoundsStarted\");\n    LogToFile(\"XblUserStatisticsGetSingleUserStatisticsAsync: statisticName1: %s\", statisticName1.c_str());\n    LogToFile(\"XblUserStatisticsGetSingleUserStatisticsAsync: statisticName2: %s\", statisticName2.c_str());\n\n    // CODE SNIPPET START: XblUserStatisticsGetSingleUserStatisticsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblUserStatisticsGetSingleUserStatisticsResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblUserStatisticsResult* results{};\n\n            hr = XblUserStatisticsGetSingleUserStatisticsResult(asyncBlock, resultSize, buffer.data(), &results, nullptr);\n            if (SUCCEEDED(hr))\n            {\n                // Now you can use the XblUserStatisticsResult array in results\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblUserStatisticsGetSingleUserStatisticsAsync\"); // CODE SNIP SKIP\n    };\n\n    const char* statisticNames[2] = {};\n    statisticNames[0] = statisticName1.c_str();\n    statisticNames[1] = statisticName2.c_str();\n\n    HRESULT hr = XblUserStatisticsGetSingleUserStatisticsAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        Data()->scid,\n        statisticNames, 2, \n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblUserStatisticsGetSingleUserStatisticsAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsGetMultipleUserStatisticsAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto statisticName1 = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\");\n    auto statisticName2 = GetStringFromLua(L, 2, \"TotalRoundsStarted\");\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsAsync: statisticName1: %s\", statisticName1.c_str());\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsAsync: statisticName2: %s\", statisticName2.c_str());\n\n    auto xuid1 = GetUint64FromLua(L, 3, Data()->xboxUserId);\n    auto xuid2 = GetUint64FromLua(L, 4, 2814634367189975);\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsAsync: xuid1: %ul\", xuid1);\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsAsync: xuid2: %ul\", xuid2);\n\n    // CODE SNIPPET START: XblUserStatisticsGetMultipleUserStatisticsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblUserStatisticsGetMultipleUserStatisticsResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblUserStatisticsResult* results{};\n            size_t resultsCount = 0;\n\n            hr = XblUserStatisticsGetMultipleUserStatisticsResult(asyncBlock, resultSize, buffer.data(), &results, &resultsCount, nullptr);\n\n            // Process results array to read the user stats data\n            for (size_t iResult = 0; iResult < resultsCount; iResult++)\n            {\n                LogToFile(\"%d\", results[iResult].xboxUserId);\n                for (size_t iScid = 0; iScid < results[iResult].serviceConfigStatisticsCount; iScid++)\n                {\n                    LogToFile(\"SCID: %s\", results[iResult].serviceConfigStatistics[iScid].serviceConfigurationId);\n                    for (size_t iStat = 0; iStat < results[iResult].serviceConfigStatistics[iScid].statisticsCount; iStat++)\n                    {\n                        LogToFile(\"Stat %d: name:%s value:%s type:%s\", iResult,\n                            results[iResult].serviceConfigStatistics[iScid].statistics[iStat].statisticName,\n                            results[iResult].serviceConfigStatistics[iScid].statistics[iStat].value,\n                            results[iResult].serviceConfigStatistics[iScid].statistics[iStat].statisticType );\n                    }\n                }\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblUserStatisticsGetMultipleUserStatisticsAsync\"); // CODE SNIP SKIP\n    };\n\n    const char* statisticNames[2] = {};\n    statisticNames[0] = statisticName1.c_str();\n    statisticNames[1] = statisticName2.c_str();\n\n    uint64_t xuids[2] = {};\n    xuids[0] = xuid1;\n    xuids[1] = xuid2;\n\n    HRESULT hr = XblUserStatisticsGetMultipleUserStatisticsAsync(\n        Data()->xboxLiveContext,\n        xuids, 2,\n        Data()->scid,\n        statisticNames, 2,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    auto statisticName1 = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\");\n    auto statisticName2 = GetStringFromLua(L, 2, \"TotalRoundsStarted\");\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync: statisticName1: %s\", statisticName1.c_str());\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync: statisticName2: %s\", statisticName2.c_str());\n\n    auto xuid1 = GetUint64FromLua(L, 3, Data()->xboxUserId);\n    auto xuid2 = GetUint64FromLua(L, 4, 2814634367189975);\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync: xuid1: %ul\", xuid1);\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync: xuid2: %ul\", xuid2);\n\n    // CODE SNIPPET START: XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize(asyncBlock, &resultSize);\n\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblUserStatisticsResult* results{};\n            size_t resultsCount = 0;\n\n            hr = XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult(asyncBlock, resultSize, buffer.data(), &results, &resultsCount, nullptr);\n            LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult: hr=%s count=%d\", ConvertHR(hr).c_str(), resultsCount); // CODE SNIP SKIP\n\n            if (SUCCEEDED(hr))\n            {\n                for (size_t i = 0; i < resultsCount; i++)\n                {\n                    // Log results\n                    std::stringstream stream;\n                    stream << \"XUID: \" << results[i].xboxUserId << std::endl;;\n\n                    for (size_t j = 0; j < results[i].serviceConfigStatisticsCount; j++)\n                    {\n                        stream << \" \" << results[i].serviceConfigStatistics[j].serviceConfigurationId << \": \" << std::endl;\n                        for (size_t k = 0; k < results[i].serviceConfigStatistics[j].statisticsCount; k++)\n                        {\n                            stream << \" \" << results[i].serviceConfigStatistics[j].statistics[k].statisticName << \"=\" << results[i].serviceConfigStatistics[j].statistics[k].value << std::endl;\n                        }\n                    }\n                    LogToScreen(stream.str().c_str()); // CODE SNIP SKIP\n                }\n            }\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\"); // CODE SNIP SKIP\n    };\n\n    const char* requestedStatsNames1[2] = {};\n    requestedStatsNames1[0] = statisticName1.c_str();\n    requestedStatsNames1[1] = statisticName2.c_str();\n\n    XblRequestedStatistics requestedStats[1] = {};\n    pal::strcpy(requestedStats[0].serviceConfigurationId, sizeof(XblRequestedStatistics::serviceConfigurationId), Data()->scid);\n    requestedStats[0].statistics = requestedStatsNames1;\n    requestedStats[0].statisticsCount = 2;\n\n    uint64_t xuids[2] = {};\n    xuids[0] = xuid1;\n    xuids[1] = xuid2;\n        \n    HRESULT hr = XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(\n        Data()->xboxLiveContext,\n        xuids, 2,\n        requestedStats, 1,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    LogToFile(\"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsTrackStatistics_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    auto statisticName = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\");\n    LogToFile(\"XblUserStatisticsTrackStatistics: statisticName: %s\", statisticName.c_str());\n    std::vector<const char*> statisticNames{ statisticName.data() };\n\n    // CODE SNIPPET START: XblUserStatisticsTrackStatistics\n    HRESULT hr = XblUserStatisticsTrackStatistics(\n        Data()->xboxLiveContext,\n        &Data()->xboxUserId,\n        1,\n        Data()->scid,\n        statisticNames.data(),\n        statisticNames.size()\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblUserStatisticsTrackStatistics: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsStopTrackingStatistics_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    auto statisticName = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\");\n    LogToFile(\"XblUserStatisticsTrackStatistics: statisticName: %s\", statisticName.c_str());\n    std::vector<const char*> statisticNames{ statisticName.data() };\n\n    // CODE SNIPPET START: XblUserStatisticsStopTrackingStatistics\n    HRESULT hr = XblUserStatisticsStopTrackingStatistics(\n        Data()->xboxLiveContext,\n        &Data()->xboxUserId,\n        1,\n        Data()->scid,\n        statisticNames.data(),\n        statisticNames.size()\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblUserStatisticsStopTrackingStatistics: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsStopTrackingUsers_Lua(lua_State* L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    // CODE SNIPPET START: XblUserStatisticsStopTrackingStatistics\n    HRESULT hr = XblUserStatisticsStopTrackingUsers(\n        Data()->xboxLiveContext,\n        &Data()->xboxUserId,\n        1\n    );\n    // CODE SNIPPET END\n\n    LogToFile(\"XblUserStatisticsStopTrackingUsers: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsSubscribeToStatisticChange_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n    if (Data()->statisticChangeSubscriptionHandle != nullptr)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    auto statisticName = GetStringFromLua(L, 1, \"TotalPuzzlesSolved\");\n    LogToFile(\"XblUserStatisticsSubscribeToStatisticChange: statisticName: %s\", statisticName.c_str());\n\n    // CODE SNIPPET START: XblUserStatisticsSubscribeToStatisticChange\n    XblRealTimeActivitySubscriptionHandle subscriptionHandle{ nullptr };\n\n    HRESULT hr = XblUserStatisticsSubscribeToStatisticChange(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        Data()->scid,\n        statisticName.c_str(),\n        &subscriptionHandle\n    );\n    // CODE SNIPPET END\n    Data()->statisticChangeSubscriptionHandle = subscriptionHandle;\n\n    LogToFile(\"XblUserStatisticsSubscribeToStatisticChange: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsUnsubscribeFromStatisticChange_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    HRESULT hr = S_OK;\n    if (Data()->statisticChangeSubscriptionHandle != nullptr)\n    {\n        // CODE SNIPPET START: XblUserStatisticsUnsubscribeFromStatisticChange\n        hr = XblUserStatisticsUnsubscribeFromStatisticChange(\n            Data()->xboxLiveContext,\n            Data()->statisticChangeSubscriptionHandle\n        );\n        // CODE SNIPPET END\n        Data()->statisticChangeSubscriptionHandle = nullptr;\n    }\n\n    LogToFile(\"XblUserStatisticsUnsubscribeFromStatisticChange: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblUserStatisticsAddStatisticChangedHandler_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    // CODE SNIPPET START: XblUserStatisticsAddStatisticChangedHandler\n    void* context{ nullptr };\n    XblFunctionContext statisticChangedFunctionContext = XblUserStatisticsAddStatisticChangedHandler(\n        Data()->xboxLiveContext,\n        [](XblStatisticChangeEventArgs eventArgs, void* context) \n        {\n            // Handle stat change \n            LogToScreen(\"Statistic changed callback: stat changed (%s = %s)\",\n                eventArgs.latestStatistic.statisticName, \n                eventArgs.latestStatistic.value); \n            CallLuaFunctionWithHr(S_OK, \"OnStatisticChangedHandler\"); // CODE SNIP SKIP\n            UNREFERENCED_PARAMETER(context); // CODE SNIP SKIP\n        },\n        context\n        );\n    // CODE SNIPPET END\n    Data()->statisticChangedFunctionContext = statisticChangedFunctionContext;\n\n    LogToFile(\"XblUserStatisticsAddStatisticChangedHandler: done\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblUserStatisticsRemoveStatisticChangedHandler_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    if (Data()->xboxUserId == 0)\n    {\n        return LuaReturnHR(L, E_FAIL);\n    }\n\n    // CODE SNIPPET START: XblUserStatisticsRemoveStatisticChangedHandler\n    XblUserStatisticsRemoveStatisticChangedHandler(\n            Data()->xboxLiveContext,\n            Data()->statisticChangedFunctionContext\n        );\n    // CODE SNIPPET END\n    Data()->statisticChangedFunctionContext = 0;\n\n    LogToFile(\"XblUserStatisticsRemoveStatisticChangedHandler: done\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nvoid SetupAPIs_XblStatistics()\n{\n    lua_register(Data()->L, \"GetLastStat\", GetLastStat_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsGetSingleUserStatisticAsync\", XblUserStatisticsGetSingleUserStatisticAsync_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsGetSingleUserStatisticsAsync\", XblUserStatisticsGetSingleUserStatisticsAsync_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsGetMultipleUserStatisticsAsync\", XblUserStatisticsGetMultipleUserStatisticsAsync_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\", XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsTrackStatistics\", XblUserStatisticsTrackStatistics_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsStopTrackingStatistics\", XblUserStatisticsStopTrackingStatistics_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsStopTrackingUsers\", XblUserStatisticsStopTrackingUsers_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsSubscribeToStatisticChange\", XblUserStatisticsSubscribeToStatisticChange_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsUnsubscribeFromStatisticChange\", XblUserStatisticsUnsubscribeFromStatisticChange_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsAddStatisticChangedHandler\", XblUserStatisticsAddStatisticChangedHandler_Lua);\n    lua_register(Data()->L, \"XblUserStatisticsRemoveStatisticChangedHandler\", XblUserStatisticsRemoveStatisticChangedHandler_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_stats2017.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 4365 )\n#pragma warning( disable : 4061 )\n#pragma warning( disable : 4996 )\n#endif\n#include \"rapidjson/writer.h\"\n#include \"rapidjson/stringbuffer.h\"\n#include \"rapidjson/document.h\"\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n\nusing namespace utility;\n\nstruct StatsValueDocument\n{\npublic:\n    StatsValueDocument(rapidjson::Document&& svd) noexcept\n        : m_svd{ std::move(svd) }\n    {\n        assert(m_svd.HasMember(\"stats\"));\n        assert(m_svd[\"stats\"].HasMember(\"title\"));\n    }\n\n    StatsValueDocument(const StatsValueDocument& other) noexcept\n    {\n        m_svd.CopyFrom(other.m_svd, m_svd.GetAllocator());\n    }\n\n    StatsValueDocument(StatsValueDocument&& other) noexcept\n        : m_svd{ std::move(other.m_svd) }\n    {\n    }\n\n    StatsValueDocument& operator=(const StatsValueDocument& other) noexcept\n    {\n        m_svd.CopyFrom(other.m_svd, m_svd.GetAllocator());\n        return *this;\n    }\n\n    StatsValueDocument() noexcept = default;\n    ~StatsValueDocument() noexcept = default;\n\n    bool operator==(const StatsValueDocument& other) const noexcept\n    {\n        return m_svd[\"stats\"][\"title\"] == other.m_svd[\"stats\"][\"title\"];\n    }\n\n    std::vector<XblTitleManagedStatistic> Stats() const noexcept\n    {\n        std::vector<XblTitleManagedStatistic> stats;\n\n        auto& titleJson{ m_svd[\"stats\"][\"title\"] };\n        for (auto it = titleJson.MemberBegin(); it != titleJson.MemberEnd(); ++it)\n        {\n            auto& value{ it->value[\"value\"] };\n            stats.push_back(XblTitleManagedStatistic\n                {\n                    it->name.GetString(),\n                    value.IsString() ? XblTitleManagedStatType::String : XblTitleManagedStatType::Number,\n                    value.IsNumber() ? value.GetDouble() : 0,\n                    value.IsString() ? value.GetString() : nullptr\n                });\n        }\n        return stats;\n    }\n\n    std::string Serialize() const noexcept\n    {\n        rapidjson::StringBuffer buffer;\n        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n        m_svd[\"stats\"][\"title\"].Accept(writer);\n        return buffer.GetString();\n    }\n\n    void SetStat(const std::string& name, const std::string& value) noexcept\n    {\n        SetStat(name, rapidjson::Value{ value.data(), m_svd.GetAllocator() }.Move());\n    }\n\n    void SetStat(const std::string& name, double value) noexcept\n    {\n        SetStat(name, rapidjson::Value{ value }.Move());\n    }\n\n    void DeleteStat(const std::string& name) noexcept\n    {\n        m_svd[\"stats\"][\"title\"].EraseMember(name.data());\n    }\n\n    void ClearStats() noexcept\n    {\n        m_svd[\"stats\"][\"title\"] = rapidjson::Value{ rapidjson::kObjectType };\n    }\n\nprivate:\n    void SetStat(const std::string& name, rapidjson::Value& value) noexcept\n    {\n        auto& titleJson{ m_svd[\"stats\"][\"title\"] };\n        if (titleJson.HasMember(name.data()))\n        {\n            titleJson[name.data()][\"value\"] = value.Move();\n        }\n        else\n        {\n            auto& a{ m_svd.GetAllocator() };\n            rapidjson::Value statJson{ rapidjson::kObjectType };\n            statJson.AddMember(\"value\", value.Move(), a);\n            titleJson.AddMember(rapidjson::Value{ name.data(), a }, statJson.Move(), a);\n        }\n    }\n\n    rapidjson::Document m_svd{};\n};\n\nstatic std::unique_ptr<StatsValueDocument> s_svd{ nullptr };\n\nStatsValueDocument GetStatsValueDocument(uint64_t xuid, HRESULT* resultHr)\n{\n    XblHttpCallHandle call{};\n\n    std::stringstream uri;\n    uri << \"https://statsread.xboxlive.com/stats/users/\" << xuid << \"/scids/\" << Data()->scid;\n\n    HRESULT hr = XblHttpCallCreate(Data()->xboxLiveContext, \"GET\", uri.str().data(), &call);\n    assert(SUCCEEDED(hr));\n\n    XAsyncBlock async{};\n    hr = XblHttpCallPerformAsync(call, XblHttpCallResponseBodyType::String, &async);\n    assert(SUCCEEDED(hr));\n\n    hr = XAsyncGetStatus(&async, true);\n    if (SUCCEEDED(hr))\n    {\n        assert(SUCCEEDED(hr));\n\n        const char* responseString{ nullptr };\n        hr = XblHttpCallGetResponseString(call, &responseString);\n        assert(SUCCEEDED(hr));\n\n        rapidjson::Document svd{};\n        svd.Parse(responseString);\n        assert(!svd.HasParseError());\n\n        *resultHr = S_OK;\n        return StatsValueDocument{ std::move(svd) };\n    }\n    else\n    {\n        *resultHr = E_FAIL;\n        return StatsValueDocument();\n    }\n}\n\nint XblTitleManagedStatsWriteAsyncWithSVD_Lua(lua_State *L)\n{\n    if (!s_svd)\n    {\n        HRESULT hr = S_OK;\n        s_svd = std::make_unique<StatsValueDocument>(GetStatsValueDocument(Data()->xboxUserId, &hr));\n        if (FAILED(hr))\n        {\n            LogToFile(\"XblTitleManagedStatsWriteAsyncWithSVD: hr = %s\", ConvertHR(hr).data());\n            s_svd = nullptr;\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return LuaReturnHR(L, S_OK);\n        }\n    }\n\n    auto now = datetime::utc_now();\n    auto timeString = conversions::to_utf8string(now.to_string(datetime::date_format::ISO_8601));\n\n    s_svd->SetStat(\"TimeString\", timeString.data());\n    s_svd->SetStat(\"NumericStat\", 100.0);\n\n    std::vector<XblTitleManagedStatistic> statList{ s_svd->Stats() };\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (hr == E_FAIL)\n        {\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleManagedStatsWriteAsyncWithSVD\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleManagedStatsWriteAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        statList.data(), statList.size(),\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    LogToFile(\"XblTitleManagedStatsWriteAsyncWithSVD: hr = %s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleManagedStatsWriteAsync_Lua(lua_State *L)\n{   \n    static double s_stat1Value = 0.0;\n    s_stat1Value++;\n\n    // CODE SNIPPET START: XblTitleManagedStatsWriteAsync\n    XblTitleManagedStatistic stat1{};\n    std::string stat1Name = \"TestStat1\";\n    stat1.statisticName = stat1Name.c_str();\n    stat1.statisticType = XblTitleManagedStatType::Number;\n    stat1.numberValue = s_stat1Value;\n\n    XblTitleManagedStatistic stat2{};\n    std::string stat2Name = \"TestStat2\";\n    std::string stat2Value = \"TestValue1234\";\n    stat2.statisticName = stat2Name.c_str();\n    stat2.statisticType = XblTitleManagedStatType::String;\n    stat2.stringValue = stat2Value.c_str();\n    std::vector<XblTitleManagedStatistic> statList{ stat1, stat2 };\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        if (hr != HTTP_E_STATUS_429_TOO_MANY_REQUESTS)\n        {\n            LogToScreen(\"XblTitleManagedStatsWriteAsync: 0x%0.8x\", hr);\n        }\n\n        if (hr == E_FAIL)\n        {\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleManagedStatsWriteAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleManagedStatsWriteAsync(\n        Data()->xboxLiveContext,\n        Data()->xboxUserId,\n        statList.data(), statList.size(),\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblTitleManagedStatsWriteAsync: hr = %s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleManagedStatsUpdateStatsAsync_Lua(lua_State* L)\n{\n    if (!s_svd)\n    {\n        HRESULT hr = S_OK;\n        s_svd = std::make_unique<StatsValueDocument>(GetStatsValueDocument(Data()->xboxUserId, &hr));\n        if (FAILED(hr))\n        {\n            LogToFile(\"XblTitleManagedStatsWriteAsyncWithSVD: hr = %s\", ConvertHR(hr).data());\n            s_svd = nullptr;\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return LuaReturnHR(L, S_OK);\n        }\n    }\n\n    auto timeString = conversions::to_utf8string(datetime::utc_now().to_string(datetime::date_format::ISO_8601));\n    s_svd->SetStat(\"AddedStat\",timeString.data());\n    s_svd->SetStat(\"NumericStat\", 85.0);\n\n    // CODE SNIPPET START: XblTitleManagedStatsUpdateStatsAsync\n    std::vector<XblTitleManagedStatistic> stats{ s_svd->Stats() };\n    std::vector<XblTitleManagedStatistic> updatedStats;\n    for (const XblTitleManagedStatistic& stat : stats)\n    {\n        if (std::string{ \"AddedStat\" } == stat.statisticName ||\n            std::string{ \"NumericStat\" } == stat.statisticName)\n        {\n            updatedStats.push_back(stat);\n        }\n    }\n    auto stat1 = updatedStats.begin();\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (hr == E_FAIL)\n        {\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleManagedStatsUpdateStatsAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleManagedStatsUpdateStatsAsync(\n        Data()->xboxLiveContext,\n        &(*stat1),\n        updatedStats.size(),\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblTitleManagedStatsUpdateStatsAsync: hr = %s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleManagedStatsDeleteStatsAsync_Lua(lua_State* L)\n{\n    if (!s_svd)\n    {\n        HRESULT hr = S_OK;\n        s_svd = std::make_unique<StatsValueDocument>(GetStatsValueDocument(Data()->xboxUserId, &hr));\n        if (FAILED(hr))\n        {\n            LogToFile(\"XblTitleManagedStatsWriteAsyncWithSVD: hr = %s\", ConvertHR(hr).data());\n            s_svd = nullptr;\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return LuaReturnHR(L, S_OK);\n        }\n    }\n\n    // CODE SNIPPET START: XblTitleManagedStatsDeleteStats\n    const char* statName{ \"TimeString\" };\n    s_svd->DeleteStat(statName); // CODE SNIP SKIP\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (hr == E_FAIL)\n        {\n            CallLuaFunction(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\");\n            return;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleManagedStatsDeleteStatsAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleManagedStatsDeleteStatsAsync(\n        Data()->xboxLiveContext,\n        &statName,\n        1,\n        asyncBlock.get()\n    );\n\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n\n    LogToFile(\"XblTitleManagedStatsDeleteStatsAsync: hr = %s\", ConvertHR(hr).data());\n    return LuaReturnHR(L, hr);\n}\n\nint ValidateSVD_Lua(lua_State* L)\n{\n    UNREFERENCED_PARAMETER(L);\n\n    // statsread enpoint has very aggressive throttling, so we shouldn't read the SVD after each\n    // update. Just make sure we are in sync once at the end of the test.\n    if (s_svd)\n    {\n\n        HRESULT hr = S_OK;\n        auto updatedSVD{ GetStatsValueDocument(Data()->xboxUserId, &hr) };\n        if (FAILED(hr))\n        {\n            return 0;\n        }\n\n        LogToFile(\"Service SVD: %s\", updatedSVD.Serialize().data());\n        LogToFile(\"Local SVD: %s\", s_svd->Serialize().data());\n        assert(*s_svd == updatedSVD);\n    }\n\n    return 0;\n}\n\nint ClearSVD_Lua(lua_State* L)\n{\n    UNREFERENCED_PARAMETER(L);\n\n    if (!s_svd)\n    {\n        HRESULT hr = S_OK;\n        s_svd = std::make_unique<StatsValueDocument>(GetStatsValueDocument(Data()->xboxUserId, &hr));\n        if (FAILED(hr))\n        {\n            LogToFile(\"XblTitleManagedStatsWriteAsyncWithSVD: hr = %s\", ConvertHR(hr).data());\n            s_svd = nullptr;\n            lua_pushnumber(L, 1);\n            return 1;\n        }\n    }\n    s_svd->ClearStats();\n    return 0;\n}\n\nvoid SetupAPIs_XblTitleManagedStats()\n{\n    lua_register(Data()->L, \"XblTitleManagedStatsWriteAsyncWithSVD\", XblTitleManagedStatsWriteAsyncWithSVD_Lua);\n    lua_register(Data()->L, \"XblTitleManagedStatsWriteAsync\", XblTitleManagedStatsWriteAsync_Lua);\n    lua_register(Data()->L, \"XblTitleManagedStatsUpdateStatsAsync\", XblTitleManagedStatsUpdateStatsAsync_Lua);\n    lua_register(Data()->L, \"XblTitleManagedStatsDeleteStatsAsync\", XblTitleManagedStatsDeleteStatsAsync_Lua);\n\n    // Test helpers\n    lua_register(Data()->L, \"ValidateSVD\", ValidateSVD_Lua);\n    lua_register(Data()->L, \"ClearSVD\", ClearSVD_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_stringVerify.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\nint XblStringVerifyStringAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    char testString[] = { 'F', 'u', 'c', 'k', 's', 't', 'r', 'i', 'n', 'g', '\\0' }; \n\n    // CODE SNIPPET START: XblStringVerifyStringAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblStringVerifyStringResultSize(asyncBlock, &resultSize);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblVerifyStringResult* result{};\n\n            hr = XblStringVerifyStringResult(asyncBlock, resultSize, buffer.data(), &result, nullptr);\n            LogToFile(\n                \"Result: Result Code: %d - First Offending String: %s\",\n                result->resultCode,\n                (result->resultCode == XblVerifyStringResultCode::Offensive) ? result->firstOffendingSubstring : \"\"); // CODE SNIP SKIP\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnTestStringVerify\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblStringVerifyStringAsync(\n        Data()->xboxLiveContext,\n        testString,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    return LuaReturnHR(L, hr);\n}\n\nint XblStringVerifyStringsAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    char testString1[] = { 'S', 'h', 'i', 't', 's', 't', 'r', 'i', 'n', 'g', '\\0' }; // CODE SNIP SKIP\n    char testString2[] = { 'G', 'o', 'o', 'd', 's', 't', 'r', 'i', 'n', 'g', '\\0' }; // CODE SNIP SKIP\n    char testString3[] = { 'S', 'h', 'i', 't', 's', 't', 'r', 'i', 'n', 'g', '2', '\\0' }; // CODE SNIP SKIP\n    const char* testStrings[] = { testString1, testString2, testString3 };\n\n    // CODE SNIPPET START: XblStringVerifyStringsAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t resultSize;\n        HRESULT hr = XblStringVerifyStringsResultSize(asyncBlock, &resultSize);\n        if (SUCCEEDED(hr))\n        {\n            std::vector<char> buffer(resultSize, 0);\n            XblVerifyStringResult* result{};\n            size_t resultCount = 0;\n            hr = XblStringVerifyStringsResult(asyncBlock, resultSize, buffer.data(), &result, &resultCount, nullptr);\n            LogToScreen(\"XblStringVerifyStringsResult: %s count=%d\", ConvertHR(hr).c_str(), resultCount); // CODE SNIP SKIP\n            if (SUCCEEDED(hr)) // CODE SNIP SKIP\n            { // CODE SNIP SKIP\n                assert(resultCount == 3); // CODE SNIP SKIP\n            }\n            \n            for (uint64_t i = 0; i < resultCount; i++) // CODE SNIP SKIP\n            { // CODE SNIP SKIP\n                LogToFile(\n                    \"Result [%d]: Result Code: %d - First Offending String: %s\", \n                    i, \n                    result->resultCode, \n                    (result->resultCode == XblVerifyStringResultCode::Offensive)? result->firstOffendingSubstring: \"\" ); // CODE SNIP SKIP\n                result++; // CODE SNIP SKIP \n            } // CODE SNIP SKIP\n        }\n    };\n    HRESULT hr = XblStringVerifyStringsAsync(\n        Data()->xboxLiveContext,\n        testStrings,\n        3,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    // CODE SNIPPET END\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblStringVerify()\n{\n    lua_register(Data()->L, \"XblStringVerifyStringAsync\", XblStringVerifyStringAsync_Lua);\n    lua_register(Data()->L, \"XblStringVerifyStringsAsync\", XblStringVerifyStringsAsync_Lua);\n}"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_title_storage.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"rapidjson/document.h\"\n\n#define CHECKHR(hr) if (FAILED(hr)) goto Cleanup;\n// <summary>\n/// Metadata about a blob.\n/// </summary>\ntypedef struct JsonStorageBlobMetadata\n{\n    /// <summary>\n    /// Blob path is a unique string that conforms to a SubPath\\file format (example: \"foo\\bar\\blob.txt\").\n    /// </summary>\n    std::string blobPath;\n\n    /// <summary>\n    /// [optional] Friendly display name to show in app UI.\n    /// </summary>\n    std::string displayName;\n\n    /// <summary>\n    /// Gets the number of bytes of the blob data.\n    /// </summary>\n    size_t length;\n\n    /// <summary>\n    /// Gets the position in the list of blob metadata\n    /// </summary>\n    size_t positionInList;\n\n} JsonStorageBlobMetadata;\n\n\nstruct JsonBlobMetadataResult : public std::enable_shared_from_this<JsonBlobMetadataResult>\n{\n    std::string m_scid;\n    uint64_t m_xuid;\n    std::string m_blobPath;\n\n    std::vector<JsonStorageBlobMetadata> m_items;\n    std::string m_continuationToken;\n};\n\nJsonBlobMetadataResult DeserializeResult(std::string blobPathRoot, std::string json)\n{\n    rapidjson::Document document;\n    document.Parse(json.c_str());\n\n    JsonBlobMetadataResult result;\n\n    // Deserialize blobs\n    std::vector<JsonStorageBlobMetadata> metadataList;\n\n    size_t index = 0;\n    for (const auto& blobJson : document[\"blobs\"].GetArray())\n    {\n        JsonStorageBlobMetadata metadata;\n        metadata.blobPath = blobPathRoot + blobJson[\"fileName\"].GetString();\n        if (blobJson.HasMember(\"displayName\"))\n        {\n            metadata.displayName = blobJson[\"displayName\"].GetString();\n        }\n        metadata.length = static_cast<size_t>(blobJson[\"size\"].GetInt());\n        metadata.positionInList = index;\n        index++;\n        result.m_items.push_back(metadata);\n    }\n    \n    return result;\n}\n\nXblTitleStorageType ConvertStringToXblTitleStorageType(const char* str)\n{\n    XblTitleStorageType type = XblTitleStorageType::TrustedPlatformStorage;\n\n    if (pal::stricmp(str, \"XblTitleStorageType::TrustedPlatformStorage\") == 0) type = XblTitleStorageType::TrustedPlatformStorage;\n    else if (pal::stricmp(str, \"XblTitleStorageType::GlobalStorage\") == 0) type = XblTitleStorageType::GlobalStorage;\n    else if (pal::stricmp(str, \"XblTitleStorageType::Universal\") == 0) type = XblTitleStorageType::Universal;\n\n    return type;\n}\n\nXblTitleStorageBlobType ConvertStringToXblTitleStorageBlobType(const char* str)\n{\n    XblTitleStorageBlobType type = XblTitleStorageBlobType::Unknown;\n\n    if (pal::stricmp(str, \"XblTitleStorageBlobType::Binary\") == 0) type = XblTitleStorageBlobType::Binary;\n    else if (pal::stricmp(str, \"XblTitleStorageBlobType::Json\") == 0) type = XblTitleStorageBlobType::Json;\n    else if (pal::stricmp(str, \"XblTitleStorageBlobType::Config\") == 0) type = XblTitleStorageBlobType::Config;\n\n    return type;\n}\n\nXblTitleStorageETagMatchCondition ConvertStringToXblTitleStorageETagMatchCondition(const char* str)\n{\n    XblTitleStorageETagMatchCondition matchCondition = XblTitleStorageETagMatchCondition::NotUsed;\n\n    if (pal::stricmp(str, \"XblTitleStorageETagMatchCondition::IfMatch\") == 0) matchCondition = XblTitleStorageETagMatchCondition::IfMatch;\n    else if (pal::stricmp(str, \"XblTitleStorageETagMatchCondition::IfNotMatch\") == 0) matchCondition = XblTitleStorageETagMatchCondition::IfNotMatch;\n\n    return matchCondition;\n}\n\nint XblTitleStorageBlobMetadataResultGetItems_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblTitleStorageBlobMetadataResultGetItems\n    XblTitleStorageBlobMetadataResultHandle handle = Data()->blobMetadataResultHandle;\n\n    const XblTitleStorageBlobMetadata* items;\n    size_t itemsSize;\n\n    HRESULT hr = XblTitleStorageBlobMetadataResultGetItems(handle, &items, &itemsSize);\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageBlobMetadataResultGetItems: hr=%s\", ConvertHR(hr).c_str());\n\n    if (itemsSize > 0)\n    {\n        Data()->binaryBlobMetadata = items[0];\n        Data()->jsonBlobMetadata = items[1];\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageBlobMetadataResultHasNext_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblTitleStorageBlobMetadataResultHasNext\n    XblTitleStorageBlobMetadataResultHandle handle = Data()->blobMetadataResultHandle;\n\n    bool hasNext;\n    HRESULT hr = XblTitleStorageBlobMetadataResultHasNext(handle, &hasNext);\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageBlobMetadataResultHasNext: hr=%s hasNext=%s\", ConvertHR(hr).c_str(), hasNext ? \"true\" : \"false\");\n    \n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageBlobMetadataResultGetNextAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    \n    uint32_t maxItems = GetUint32FromLua(L, 1, 0);\n\n    // CODE SNIPPET START: XblTitleStorageBlobMetadataResultGetNextAsync\n    XblTitleStorageBlobMetadataResultHandle handle = Data()->blobMetadataResultHandle;\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblTitleStorageBlobMetadataResultHandle handle{ nullptr };\n        \n        HRESULT hr = XblTitleStorageBlobMetadataResultGetNextResult(asyncBlock, &handle);\n        if (Data()->blobMetadataResultHandle != nullptr) // CODE SNIP SKIP\n        { // CODE SNIP SKIP\n            XblTitleStorageBlobMetadataResultCloseHandle(Data()->blobMetadataResultHandle); // CODE SNIP SKIP\n        } // CODE SNIP SKIP\n        Data()->blobMetadataResultHandle = handle; // CODE SNIP SKIP\n        LogToScreen(\"XblTitleStorageBlobMetadataResultGetNextResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageBlobMetadataResultGetNextAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleStorageBlobMetadataResultGetNextAsync(handle, maxItems, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageBlobMetadataResultGetNextAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageBlobMetadataResultDuplicateHandle_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblTitleStorageBlobMetadataResultDuplicateHandle\n    XblTitleStorageBlobMetadataResultHandle handle = Data()->blobMetadataResultHandle;\n    XblTitleStorageBlobMetadataResultHandle duplicatedHandle;\n\n    HRESULT hr = XblTitleStorageBlobMetadataResultDuplicateHandle(handle, &duplicatedHandle);\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageBlobMetadataResultDuplicateHandle: hr=%s\", ConvertHR(hr).c_str());\n\n    // Cleanup\n    XblTitleStorageBlobMetadataResultCloseHandle(duplicatedHandle);\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageBlobMetadataResultCloseHandle_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    // CODE SNIPPET START: XblTitleStorageBlobMetadataResultCloseHandle\n    XblTitleStorageBlobMetadataResultHandle handle = Data()->blobMetadataResultHandle;\n    XblTitleStorageBlobMetadataResultCloseHandle(handle);\n    Data()->blobMetadataResultHandle = nullptr;\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageBlobMetadataResultCloseHandle done\");\n\n    return LuaReturnHR(L, S_OK);\n}\n\nint XblTitleStorageGetQuotaAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    XblTitleStorageType storageType = ConvertStringToXblTitleStorageType(GetStringFromLua(L, 1, \"XblTitleStorageType::Universal\").c_str());\n\n    // CODE SNIPPET START: XblTitleStorageGetQuotaAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        size_t usedBytes;\n        size_t quotaBytes;\n        HRESULT hr = XblTitleStorageGetQuotaResult(asyncBlock, &usedBytes, &quotaBytes);\n        LogToScreen(\"XblTitleStorageGetQuotaResult: usedBytes=%u quotaBytes=%u\", usedBytes, quotaBytes); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageGetQuotaAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleStorageGetQuotaAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        storageType,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageGetQuotaAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageGetBlobMetadataAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    XblTitleStorageType storageType = ConvertStringToXblTitleStorageType(GetStringFromLua(L, 1, \"XblTitleStorageType::Universal\").c_str());\n    std::string blobPath = GetStringFromLua(L, 2, \"\");\n    uint64_t xboxUserId = GetUint64FromLua(L, 3, 0);\n    uint32_t skipItems = GetUint32FromLua(L, 4, 0);\n    uint32_t maxItems = GetUint32FromLua(L, 5, 0);\n\n    // CODE SNIPPET START: XblTitleStorageGetBlobMetadataAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        XblTitleStorageBlobMetadataResultHandle handle;\n        HRESULT hr = XblTitleStorageGetBlobMetadataResult(asyncBlock, &handle);\n        LogToScreen(\"XblTitleStorageGetBlobMetadataResult: hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        if (SUCCEEDED(hr))\n        {\n            if (Data()->blobMetadataResultHandle != nullptr)\n            {\n                XblTitleStorageBlobMetadataResultCloseHandle(Data()->blobMetadataResultHandle);\n            }\n\n            Data()->blobMetadataResultHandle = handle;\n        }\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageGetBlobMetadataAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleStorageGetBlobMetadataAsync(\n        Data()->xboxLiveContext,\n        Data()->scid,\n        storageType,\n        blobPath.c_str(),\n        xboxUserId,\n        skipItems,\n        maxItems,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageGetBlobMetadataAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageDeleteBinaryBlobAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    bool deleteOnlyIfEtagMatches = GetBoolFromLua(L, 1, false);\n\n    // CODE SNIPPET START: XblTitleStorageDeleteBlobAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToScreen(\"XblTitleStorageDeleteBlobAsync result (BINARY): hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageDeleteBinaryBlobAsync\"); // CODE SNIP SKIP\n    };\n    \n    HRESULT hr = XblTitleStorageDeleteBlobAsync(\n        Data()->xboxLiveContext,\n        Data()->binaryBlobMetadata,\n        deleteOnlyIfEtagMatches,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageDeleteBlobAsync (BINARY): hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\n\nint XblTitleStorageDeleteJsonBlobAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    bool deleteOnlyIfEtagMatches = GetBoolFromLua(L, 1, false);\n\n    // CODE SNIPPET START: XblTitleStorageDeleteBlobAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToScreen(\"XblTitleStorageDeleteBlobAsync result (JSON): hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageDeleteJsonBlobAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleStorageDeleteBlobAsync(\n        Data()->xboxLiveContext,\n        Data()->jsonBlobMetadata,\n        deleteOnlyIfEtagMatches,\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageDeleteBlobAsync (JSON): hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageDownloadBinaryBlobAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    std::string selectQuery = GetStringFromLua(L, 1, \"\");\n    uint32_t preferredDownloadBlockSize = GetUint32FromLua(L, 1, 1024*256);\n\n    // CODE SNIPPET START: XblTitleStorageDownloadBlobAsync\n    std::unique_ptr<std::vector<uint8_t>> downloadBlobBuffer = std::make_unique<std::vector<uint8_t>>(Data()->binaryBlobMetadata.length);\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = downloadBlobBuffer.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        std::unique_ptr<std::vector<uint8_t>> downloadBlobBuffer{ static_cast<std::vector<uint8_t>*>(asyncBlock->context) };\n        HRESULT hr = XblTitleStorageDownloadBlobResult(asyncBlock, &Data()->binaryBlobMetadata);\n        LogToScreen(\"XblTitleStorageDownloadBlobResult (BINARY): hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageDownloadBinaryBlobAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleStorageDownloadBlobAsync(\n        Data()->xboxLiveContext,\n        Data()->binaryBlobMetadata,\n        downloadBlobBuffer->data(),\n        Data()->binaryBlobMetadata.length,\n        XblTitleStorageETagMatchCondition::NotUsed,\n        selectQuery.c_str(), // optional\n        preferredDownloadBlockSize, // optional\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        downloadBlobBuffer.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageDownloadBlobAsync (BINARY): hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageDownloadJsonBlobAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    std::string selectQuery = GetStringFromLua(L, 1, \"\");\n    uint32_t preferredDownloadBlockSize = GetUint32FromLua(L, 1, 1024);\n    size_t length = Data()->jsonBlobMetadata.length;\n    std::unique_ptr<std::vector<uint8_t>> downloadBlobBuffer = std::make_unique<std::vector<uint8_t>>(length);\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = downloadBlobBuffer.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock };\n        std::unique_ptr<std::vector<uint8_t>> downloadBlobBuffer{ static_cast<std::vector<uint8_t>*>(asyncBlock->context) };\n        HRESULT hr = XblTitleStorageDownloadBlobResult(asyncBlock, &Data()->jsonBlobMetadata);\n        LogToScreen(\"XblTitleStorageDownloadBlobResult (JSON): hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageDownloadJsonBlobAsync\"); // CODE SNIP SKIP\n    };\n\n    HRESULT hr = XblTitleStorageDownloadBlobAsync(\n        Data()->xboxLiveContext,\n        Data()->jsonBlobMetadata,\n        downloadBlobBuffer->data(),\n        Data()->jsonBlobMetadata.length,\n        XblTitleStorageETagMatchCondition::NotUsed,\n        selectQuery.c_str(), // optional\n        preferredDownloadBlockSize, // optional\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        downloadBlobBuffer.release();\n    }\n\n    LogToScreen(\"XblTitleStorageDownloadBlobAsync (JSON): hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageUploadJsonBlobAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    std::string displayName = GetStringFromLua(L, 1, \"Test Name 4\");\n    std::string blobPath = GetStringFromLua(L, 2, \"apirunner/test/path/json.txt\");\n    std::string blobBufferParam = GetStringFromLua(L, 3, \"{}\");\n    XblTitleStorageType storageType = ConvertStringToXblTitleStorageType(GetStringFromLua(L, 4, \"XblTitleStorageType::Universal\").c_str());\n    XblTitleStorageBlobType blobType = ConvertStringToXblTitleStorageBlobType(GetStringFromLua(L, 5, \"XblTitleStorageBlobType::Json\").c_str());\n    uint32_t preferredUploadBlockSize = GetUint32FromLua(L, 6, 1024);\n    XblTitleStorageETagMatchCondition eTagMatchCondition = ConvertStringToXblTitleStorageETagMatchCondition(GetStringFromLua(L, 7, \"XblTitleStorageETagMatchCondition::NotUsed\").c_str());\n    std::unique_ptr<std::vector<char>> blobBuffer = std::make_unique<std::vector<char>>();\n\n    size_t blobBufferSize;\n    blobBufferSize = blobBufferParam.size() + 1;\n    blobBuffer->resize(blobBufferSize);\n    pal::strcpy(blobBuffer->data(), blobBufferSize, blobBufferParam.c_str());\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = blobBuffer.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; \n        HRESULT hr = XblTitleStorageUploadBlobResult(asyncBlock, &Data()->jsonBlobMetadata);\n        LogToScreen(\"XblTitleStorageUploadBlobResult (JSON): hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageUploadJsonBlobAsync\"); // CODE SNIP SKIP\n    };\n\n    XblTitleStorageBlobMetadata blobMetadata{};\n    pal::strcpy(blobMetadata.displayName, displayName.size() + 1, displayName.c_str());\n    pal::strcpy(blobMetadata.serviceConfigurationId, XBL_SCID_LENGTH, Data()->scid);\n    pal::strcpy(blobMetadata.blobPath, blobPath.size() + 1, blobPath.c_str());\n    blobMetadata.storageType = storageType;\n    blobMetadata.blobType = blobType;\n    time(&blobMetadata.clientTimestamp);\n\n    HRESULT hr = XblTitleStorageUploadBlobAsync(\n        Data()->xboxLiveContext,\n        blobMetadata,\n        reinterpret_cast<const uint8_t*>(blobBuffer->data()),\n        blobBufferSize,\n        eTagMatchCondition,\n        preferredUploadBlockSize, // optional\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        blobBuffer.release();\n    }\n    LogToScreen(\"XblTitleStorageUploadBlobAsync (JSON): hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblTitleStorageUploadBinaryBlobAsync_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n\n    std::string displayName = GetStringFromLua(L, 1, \"Test Binary Data\");\n    std::string blobPath = GetStringFromLua(L, 2, \"apirunner/test/path.txt\");\n    XblTitleStorageType storageType = ConvertStringToXblTitleStorageType(GetStringFromLua(L, 3, \"XblTitleStorageType::Universal\").c_str());\n    XblTitleStorageBlobType blobType = ConvertStringToXblTitleStorageBlobType(GetStringFromLua(L, 4, \"XblTitleStorageBlobType::Binary\").c_str());\n    XblTitleStorageETagMatchCondition eTagMatchCondition = ConvertStringToXblTitleStorageETagMatchCondition(GetStringFromLua(L, 5, \"XblTitleStorageETagMatchCondition::NotUsed\").c_str());\n    std::unique_ptr<std::vector<char>> blobBuffer = std::make_unique<std::vector<char>>();\n\n    size_t preferredUploadBlockSize = 1024 * 256;\n    size_t blobBufferSize = 1024 * 600; // requires 3 chunk uploads\n    blobBuffer->resize(blobBufferSize);\n    char zero = '0';\n    for (size_t i = 0; i < blobBufferSize; i++)\n    {\n        (*blobBuffer)[i] = (char)(zero + i % 10);\n    }\n\n    // CODE SNIPPET START: XblTitleStorageUploadBlobAsync\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = blobBuffer.get();\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XblTitleStorageUploadBlobResult(asyncBlock, &Data()->binaryBlobMetadata);\n        LogToScreen(\"XblTitleStorageUploadBlobResult (Binary): hr=%s\", ConvertHR(hr).c_str()); // CODE SNIP SKIP\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageUploadBinaryBlobAsync\"); // CODE SNIP SKIP\n    };\n\n    XblTitleStorageBlobMetadata blobMetadata{};\n    pal::strcpy(blobMetadata.displayName, displayName.size() + 1, displayName.c_str());\n    pal::strcpy(blobMetadata.serviceConfigurationId, XBL_SCID_LENGTH, Data()->scid);\n    pal::strcpy(blobMetadata.blobPath, blobPath.size() + 1, blobPath.c_str());\n    blobMetadata.storageType = storageType;\n    blobMetadata.blobType = blobType;\n    time(&blobMetadata.clientTimestamp);\n    \n    HRESULT hr = XblTitleStorageUploadBlobAsync(\n        Data()->xboxLiveContext,\n        blobMetadata,\n        reinterpret_cast<const uint8_t*>(blobBuffer->data()),\n        blobBufferSize,\n        eTagMatchCondition,\n        preferredUploadBlockSize, // optional\n        asyncBlock.get()\n    );\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        blobBuffer.release();\n    }\n    // CODE SNIPPET END\n    LogToScreen(\"XblTitleStorageUploadBlobAsync: hr=%s\", ConvertHR(hr).c_str());\n\n    return LuaReturnHR(L, hr);\n}\n\nint RestCallToDownloadJsonBlob_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    auto response = Data()->metadataResponseString;\n    HRESULT hr = S_OK;\n\n    std::string methodName = GetStringFromLua(L, 1, \"GET\");\n    char url[300];\n    sprintf_s(url, \"https://titlestorage.xboxlive.com/json/users/xuid(%\" PRIu64 \")/scids/00000000-0000-0000-0000-000076029b4d/data/\", Data()->xboxUserId);\n\n    auto result = DeserializeResult(url, response);\n    for (const auto& blobMetadata : result.m_items)\n    {\n        // Download the blob\n        XblHttpCallHandle httpCallHandle;\n        hr = XblHttpCallCreate(Data()->xboxLiveContext, \"GET\", blobMetadata.blobPath.c_str(), &httpCallHandle);\n        XblHttpCallRequestSetHeader(httpCallHandle, \"Content-Type\", \"application/json; charset=utf-8\", true);\n        XblHttpCallRequestSetHeader(httpCallHandle, \"Accept-Language\", \"en-US,en\", true);\n        XblHttpCallRequestSetHeader(httpCallHandle, \"x-xbl-contract-version\", \"2\", true);\n        Data()->titleStorageHttpCalls.push_back(httpCallHandle);\n\n        auto asyncBlock = std::make_unique<XAsyncBlock>();\n        asyncBlock->queue = Data()->queue;\n        asyncBlock->context = Data()->titleStorageHttpCalls[blobMetadata.positionInList];\n        asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n        {\n            std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n            HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n            if (SUCCEEDED(hr))\n            {\n                auto httpCall = static_cast<XblHttpCallHandle>(asyncBlock->context);\n\n                const char* responseString;\n                hr = XblHttpCallGetResponseString(httpCall, &responseString);\n\n                LogToFile(\"Response String: length %d, hr=%s\", strlen(responseString), ConvertHR(hr).c_str());\n                LogToFile(\"Response: %s\", responseString);\n                CHECKHR(hr);\n\n                Data()->blobResponseStrings.push_back(responseString);\n\n                uint32_t statusCode;\n                hr = XblHttpCallGetStatusCode(httpCall, &statusCode);\n                LogToScreen(\"Status Code: %d, hr=%s\", statusCode, ConvertHR(hr).c_str());\n                CHECKHR(hr);\n            }\n\n        Cleanup:\n            Data()->titleStorageCompletedHttpCalls++;\n            if (Data()->titleStorageCompletedHttpCalls == Data()->titleStorageHttpCalls.size())\n            {\n                CallLuaFunctionWithHr(hr, \"OnDownloadBlobs\");\n            }\n\n            LogToScreen(\"XblHttpCallPerformAsync Completion: hr=%s\", ConvertHR(hr).c_str());\n        };\n\n        LogToScreen(\"Downloading %s\", blobMetadata.blobPath.c_str());\n        hr = XblHttpCallPerformAsync(httpCallHandle, XblHttpCallResponseBodyType::String, asyncBlock.get());\n        if (SUCCEEDED(hr))\n        {\n            // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n            // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n            asyncBlock.release();\n        }\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint RestCallToUploadJsonBlob_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    auto response = Data()->metadataResponseString;\n    HRESULT hr = S_OK;\n\n    std::string methodName = GetStringFromLua(L, 1, \"GET\");\n    char url[300];\n    sprintf_s(url, \"https://titlestorage.xboxlive.com/json/users/xuid(%\" PRIu64 \")/scids/00000000-0000-0000-0000-000076029b4d/data/apirunner/test/json/file.json,json\", Data()->xboxUserId);\n\n    std::string blobContent = GetStringFromLua(L, 1, \"{}\");\n\n    // Upload the blob\n    XblHttpCallHandle httpCallHandle;\n    hr = XblHttpCallCreate(Data()->xboxLiveContext, \"PUT\", url, &httpCallHandle);\n    XblHttpCallRequestSetHeader(httpCallHandle, \"Content-Type\", \"application/json; charset=utf-8\", true);\n    XblHttpCallRequestSetHeader(httpCallHandle, \"Accept-Language\", \"en-US,en\", true);\n    XblHttpCallRequestSetHeader(httpCallHandle, \"x-xbl-contract-version\", \"2\", true);\n\n    XblHttpCallRequestSetRequestBodyString(httpCallHandle, blobContent.c_str());\n\n    Data()->xblHttpCall = httpCallHandle;\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = Data()->xblHttpCall;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n\n        if (SUCCEEDED(hr))\n        {\n            auto httpCall = static_cast<XblHttpCallHandle>(asyncBlock->context);\n\n            uint32_t statusCode;\n            hr = XblHttpCallGetStatusCode(httpCall, &statusCode);\n            LogToScreen(\"Status Code: %d, hr=%s\", statusCode, ConvertHR(hr).c_str());\n            CHECKHR(hr);\n        }\n\n    Cleanup:\n        CallLuaFunctionWithHr(hr, \"OnXblTitleStorageRestUpload\");\n        LogToScreen(\"XblHttpCallPerformAsync Completion: hr=%s\", ConvertHR(hr).c_str());\n    };\n\n    LogToScreen(\"Uploading %s\", url);\n    hr = XblHttpCallPerformAsync(httpCallHandle, XblHttpCallResponseBodyType::String, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\nint RestCallForJsonMetadata_Lua(lua_State *L)\n{\n    CreateQueueIfNeeded();\n    std::string methodName = GetStringFromLua(L, 1, \"GET\");\n    char url[300];\n    sprintf_s(url, \"https://titlestorage.xboxlive.com/json/users/xuid(%\" PRIu64 \")/scids/00000000-0000-0000-0000-000076029b4d/data/apirunner/test/json?maxItems=100\", Data()->xboxUserId);\n\n    XblHttpCallHandle httpCallHandle;\n    HRESULT hr = XblHttpCallCreate(Data()->xboxLiveContext, methodName.c_str(), url, &httpCallHandle);\n    XblHttpCallRequestSetHeader(httpCallHandle, \"Content-Type\", \"application/json; charset=utf-8\", true);\n    XblHttpCallRequestSetHeader(httpCallHandle, \"Accept-Language\", \"en-US,en\", true);\n    XblHttpCallRequestSetHeader(httpCallHandle, \"x-xbl-contract-version\", \"2\", true);\n    Data()->xblHttpCall = httpCallHandle;\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = Data()->xblHttpCall;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToScreen(\"XblHttpCallPerformAsync result: hr=%s\", ConvertHR(hr).c_str());\n\n        if (SUCCEEDED(hr))\n        {\n            const char* responseString;\n            hr = XblHttpCallGetResponseString(Data()->xblHttpCall, &responseString);\n            Data()->metadataResponseString = responseString;\n\n            LogToScreen(\"XblHttpCallResponseGetResponseString: length %d, hr=%s\", strlen(responseString), ConvertHR(hr).c_str());\n            CHECKHR(hr);\n\n            uint32_t statusCode;\n            hr = XblHttpCallGetStatusCode(Data()->xblHttpCall, &statusCode);\n            LogToScreen(\"XblHttpCallResponseGetStatusCode: %d, hr=%s\", statusCode, ConvertHR(hr).c_str());\n            CHECKHR(hr);\n        }\n\n    Cleanup:\n        LogToScreen(\"XblHttpCallPerformAsync Completion: hr=%s\", ConvertHR(hr).c_str());\n        CallLuaFunctionWithHr(hr, \"OnDownloadMetadataBlobs\");\n    };\n\n    hr = XblHttpCallPerformAsync(Data()->xblHttpCall, XblHttpCallResponseBodyType::String, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n\n    return LuaReturnHR(L, hr);\n}\n\n\n\nvoid SetupAPIs_XblTitleStorage()\n{\n    lua_register(Data()->L, \"RestCallForJsonMetadata\", RestCallForJsonMetadata_Lua);\n    lua_register(Data()->L, \"RestCallToDownloadJsonBlob\", RestCallToDownloadJsonBlob_Lua);\n    lua_register(Data()->L, \"RestCallToUploadJsonBlob\", RestCallToUploadJsonBlob_Lua);\n    lua_register(Data()->L, \"XblTitleStorageBlobMetadataResultGetItems\", XblTitleStorageBlobMetadataResultGetItems_Lua);\n    lua_register(Data()->L, \"XblTitleStorageBlobMetadataResultHasNext\", XblTitleStorageBlobMetadataResultHasNext_Lua);\n    lua_register(Data()->L, \"XblTitleStorageBlobMetadataResultGetNextAsync\", XblTitleStorageBlobMetadataResultGetNextAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageBlobMetadataResultDuplicateHandle\", XblTitleStorageBlobMetadataResultDuplicateHandle_Lua);\n    lua_register(Data()->L, \"XblTitleStorageBlobMetadataResultCloseHandle\", XblTitleStorageBlobMetadataResultCloseHandle_Lua);\n    lua_register(Data()->L, \"XblTitleStorageUploadJsonBlobAsync\", XblTitleStorageUploadJsonBlobAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageGetQuotaAsync\", XblTitleStorageGetQuotaAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageGetBlobMetadataAsync\", XblTitleStorageGetBlobMetadataAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageDeleteBinaryBlobAsync\", XblTitleStorageDeleteBinaryBlobAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageDeleteJsonBlobAsync\", XblTitleStorageDeleteJsonBlobAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageDownloadBinaryBlobAsync\", XblTitleStorageDownloadBinaryBlobAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageDownloadJsonBlobAsync\", XblTitleStorageDownloadJsonBlobAsync_Lua);\n    lua_register(Data()->L, \"XblTitleStorageUploadBinaryBlobAsync\", XblTitleStorageUploadBinaryBlobAsync_Lua);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/APIs/apis_xblc_xblhttp.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include <inttypes.h>\n\n#define CHECKHR(hr) if (FAILED(hr)) goto Cleanup;\n\nint XblHttpCallCreate_Lua(lua_State *L)\n{\n    std::string methodName = GetStringFromLua(L, 1, \"GET\");\n    char url[300];\n    sprintf_s(url, \"https://achievements.xboxlive.com/users/xuid(%\" PRIu64 \")/achievements?titleId=1979882317&maxItems=100\", Data()->xboxUserId);\n\n    XblHttpCallHandle output;\n    HRESULT hr = XblHttpCallCreate(Data()->xboxLiveContext, methodName.c_str(), url, &output);\n    XblHttpCallRequestSetHeader(output, \"Content-Type\", \"application/json; charset=utf-8\", true);\n    XblHttpCallRequestSetHeader(output, \"Accept-Language\", \"en-US,en\", true);\n    XblHttpCallRequestSetHeader(output, \"x-xbl-contract-version\", \"2\", true);\n\n    Data()->xblHttpCall = output;\n    LogToFile(\"XblHttpCallCreate: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblHttpCallPerform_Lua(lua_State *L)\n{\n    auto asyncBlock = std::make_unique<XAsyncBlock>(); \n    asyncBlock->queue = Data()->queue;\n    asyncBlock->context = Data()->xblHttpCall;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        LogToFile(\"XblHttpCallPerformAsync result: hr=%s\", ConvertHR(hr).c_str());\n\n        if (SUCCEEDED(hr))\n        {\n            const char* responseString;\n            hr = XblHttpCallGetResponseString(Data()->xblHttpCall, &responseString);\n            LogToFile(\"XblHttpCallResponseGetResponseString: length %d, hr=%s\", strlen(responseString), ConvertHR(hr).c_str());\n            CHECKHR(hr);\n\n            uint32_t statusCode;\n            hr = XblHttpCallGetStatusCode(Data()->xblHttpCall, &statusCode);\n            LogToFile(\"XblHttpCallResponseGetStatusCode: %d, hr=%s\", statusCode, ConvertHR(hr).c_str());\n            CHECKHR(hr);\n\n            HRESULT networkErrorCode;\n            uint32_t platformNetworkErrorCode;\n            hr = XblHttpCallGetNetworkErrorCode(Data()->xblHttpCall, &networkErrorCode, &platformNetworkErrorCode);\n            LogToFile(\"XblHttpCallResponseGetNetworkErrorCode: codehr=%s, rawcode=%d, hr=%s\",\n                ConvertHR(networkErrorCode).c_str(),\n                platformNetworkErrorCode,\n                ConvertHR(hr).c_str());\n            CHECKHR(hr);\n\n            const char* errorMsg;\n            hr = XblHttpCallGetPlatformNetworkErrorMessage(Data()->xblHttpCall, &errorMsg);\n            LogToFile(\"XblHttpCallResponseGetPlatformNetworkErrorMessage: hr=%s, msg=%s\", ConvertHR(hr).c_str(), errorMsg);\n            CHECKHR(hr);\n\n            const char* cv;\n            hr = XblHttpCallGetHeader(Data()->xblHttpCall, \"MS-CV\", &cv);\n            LogToFile(\"XblHttpCallResponseGetHeader: cv=%s, hr=%s\", cv, ConvertHR(hr).c_str());\n            CHECKHR(hr);\n\n            uint32_t numHeaders;\n            hr = XblHttpCallGetNumHeaders(Data()->xblHttpCall, &numHeaders);\n            LogToFile(\"XblHttpCallResponseGetNumHeaders: num=%d, hr=%s\", numHeaders, ConvertHR(hr).c_str());\n            CHECKHR(hr);\n\n            if (numHeaders > 0)\n            {\n                const char* headerName;\n                const char* headerValue;\n\n                hr = XblHttpCallGetHeaderAtIndex(Data()->xblHttpCall, 0, &headerName, &headerValue);\n                LogToFile(\"XblHttpCallResponseGetHeaderAtIndex: name: %s, val: %s, hr: %s\", headerName, headerValue, ConvertHR(hr).c_str());\n                CHECKHR(hr);\n            }\n        }\n\n    Cleanup:\n        LogToFile(\"XblHttpCallPerformAsync Completion: hr=%s\", ConvertHR(hr).c_str());\n        CallLuaFunctionWithHr(hr, \"XblHttpCallPerformCompleted\");\n    };\n\n    HRESULT hr = XblHttpCallPerformAsync(Data()->xblHttpCall, XblHttpCallResponseBodyType::String, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    LogToFile(\"XblHttpCallPerformAsync: hr=%s\", ConvertHR(hr).c_str());\n    return LuaReturnHR(L, hr);\n}\n\nint XblHttpCallDuplicate_Lua(lua_State *L)\n{\n    LogToFile(\"Starting duplicate testing...\");\n    XblHttpCallHandle duplicatedHandle;\n    HRESULT hr = XblHttpCallDuplicateHandle(Data()->xblHttpCall, &duplicatedHandle);\n    LogToFile(\"XblHttpCallDuplicateHandle: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"  orig: %p dup: %p\", Data()->xblHttpCall, duplicatedHandle);\n    XblHttpCallCloseHandle(duplicatedHandle);\n    LogToFile(\"Closed duplicate handle\", ConvertHR(hr).c_str());\n    LogToFile(\"  orig: %p dup: %p\", Data()->xblHttpCall, duplicatedHandle);\n\n    return LuaReturnHR(L, hr);\n}\n\nint XblHttpCallValidateSetters_Lua(lua_State *L)\n{\n    LogToFile(\"Starting setters testing...\");\n    uint8_t bodyBytes[] = { 0xD, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF };\n\n    HRESULT hr = XblHttpCallSetTracing(Data()->xblHttpCall, false);\n    LogToFile(\"XblHttpCallSetTracing: hr=%s\", ConvertHR(hr).c_str());\n    CHECKHR(hr);\n\n    hr = XblHttpCallRequestSetRequestBodyBytes(\n        Data()->xblHttpCall,\n        bodyBytes,\n        sizeof(bodyBytes)\n    );\n    LogToFile(\"XblHttpCallRequestSetRequestBodyBytes: hr=%s\", ConvertHR(hr).c_str());\n    CHECKHR(hr);\n\n    hr = XblHttpCallRequestSetRequestBodyString(Data()->xblHttpCall, \"requestBodyStringContent\");\n    LogToFile(\"XblHttpCallRequestSetRequestBodyString: hr=%s\", ConvertHR(hr).c_str());\n    CHECKHR(hr);\n\n    hr = XblHttpCallRequestSetRetryAllowed(Data()->xblHttpCall, false);\n    LogToFile(\"XblHttpCallRequestSetRetryAllowed: hr=%s\", ConvertHR(hr).c_str());\n    CHECKHR(hr);\n\n    hr = XblHttpCallRequestSetRetryCacheId(Data()->xblHttpCall, 12345);\n    LogToFile(\"XblHttpCallRequestSetRetryCacheId: hr=%s\", ConvertHR(hr).c_str());\n    CHECKHR(hr);\n\n    hr = XblHttpCallRequestSetLongHttpCall(Data()->xblHttpCall, true);\n    LogToFile(\"XblHttpCallRequestSetLongHttpCall: hr=%s\", ConvertHR(hr).c_str());\n    CHECKHR(hr);\n\nCleanup:\n    return LuaReturnHR(L, hr);\n}\n\nint XblHttpCallValidateGetters_Lua(lua_State *L)\n{\n    LogToFile(\"Starting getters testing...\");\n\n    const char* url;\n    HRESULT hr = XblHttpCallGetRequestUrl(Data()->xblHttpCall, &url);\n    LogToFile(\"XblHttpCallGetRequestUrl: hr=%s\", ConvertHR(hr).c_str());\n    LogToFile(\"  url length: %d\", strlen(url));\n\n    return LuaReturnHR(L, hr);\n}\n\nvoid SetupAPIs_XblHttp()\n{\n    lua_register(Data()->L, \"XblHttpCallCreate\", XblHttpCallCreate_Lua);\n    lua_register(Data()->L, \"XblHttpCallPerform\", XblHttpCallPerform_Lua);\n    lua_register(Data()->L, \"XblHttpCallDuplicate\", XblHttpCallDuplicate_Lua);\n    lua_register(Data()->L, \"XblHttpCallValidateGetters\", XblHttpCallValidateGetters_Lua);\n    lua_register(Data()->L, \"XblHttpCallValidateSetters\", XblHttpCallValidateSetters_Lua);\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/Android/pch.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\n#include \"pch_common.h\"\n\n#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, \"AndroidAPIExplorerJni\", __VA_ARGS__))\n#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, \"AndroidAPIExplorerJni\", __VA_ARGS__))\n#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"AndroidAPIExplorerJni\", __VA_ARGS__))\n#define UNREFERENCED_PARAMETER(P) (P)\n#define RETURN_STRING_FROM_ENUM(e) case(e): return #e;"
  },
  {
    "path": "Tests/ApiExplorer/Include/api_explorer.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"multidevice.h\"\n#endif\n\n#include \"lua.h\"\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n\n// C++ is not currently supported in IOS Framework. In the future, this should be updated to allow C++ tests in iOS API Explorer\n#define IOS_CPP_ENABLED 0\n#define CPP_TESTS_ENABLED (HC_PLATFORM != HC_PLATFORM_IOS || IOS_CPP_ENABLED)\n\nstruct ApiCommand;\ntypedef void (*CommandCallbackType)(const std::vector<std::string>& cmdLineTokens);\ntypedef HRESULT (*ApiCallbackType)(ApiCommand*);\n\nstruct Command\n{\n    char name[256];\n    CommandCallbackType cmdCallback;\n    bool hideFromHelp;\n};\n\nstruct SubCommand\n{\n    char name[256];\n    char subname[256];\n    CommandCallbackType cmdCallback;\n    bool hideFromHelp;\n};\n\nstruct ApiExplorerData\n{\n    ~ApiExplorerData()\n    {\n        if (L != nullptr)\n        {\n            lua_close(L); // cleanup Lua\n        }\n\n        if (queue)\n        {\n            XTaskQueueCloseHandle(queue);\n        }\n    }\n\n    std::recursive_mutex m_luaLock;\n    lua_State* L{ nullptr }; // the Lua interpreter \n    bool m_quit{ false };\n    bool m_socialDoWorkDone{ true };\n    bool m_mpmDoWorkDone{ true };\n    bool m_achievementsDoWorkDone{ true };\n\n    std::vector<Command> m_commands;\n    std::vector<std::string> m_cmdLineLog;\n    std::vector<std::string> m_tutorial;\n    std::string m_tutorialWaitFor;\n    std::vector<HRESULT> m_ignoreHRs;\n    std::string m_testsPath;\n    HRESULT m_testHR{ S_OK };\n    bool m_stopTest{ false };\n    bool m_callUpdate{ false };\n    HRESULT m_lastError{ S_OK };\n    bool m_tutorialWait{ false };\n    bool m_runningTests{ false };\n    int m_onlyFileNumber{ 0 };\n    int m_minFileNumber{ 0 };\n    int m_maxFileNumber{ 0 };\n    bool m_checkHR{ true };\n    HRESULT m_runTestsHR{ S_OK };\n    bool m_isXalInitialized{ false };\n    std::string m_onXalTryAddFirstUserSilentlyAsync;\n    std::string m_onTaskQueueTerminateWithAsyncWait;\n    bool m_repeatJsonCmds{ false };\n    bool m_wasTestSkipped{ false };\n    bool m_trackUnhookedMemory{ false };\n\n    std::mutex m_catMessageLock;\n    std::string m_catMessage;\n\n    // ApiRunnerState\n    XalUserHandle xalUser{ nullptr };\n    bool gotXalUser{ false };\n    XTaskQueueHandle queue{ nullptr };\n    XblContextHandle xboxLiveContext{ nullptr };\n    std::vector<XblRealTimeActivitySubscriptionHandle> subscriptionHandleDeviceList;\n    std::vector<XblRealTimeActivitySubscriptionHandle> subscriptionHandleTitleList;\n    std::string gamertag;\n    uint64_t xboxUserId{ 0 };\n    uint32_t titleId{ 0 };\n    const char* scid{ nullptr };\n    XblFunctionContext fnAddServiceCallRoutedHandler{ 0 };\n    HCMockCallHandle nsalMockCall{ nullptr };\n    bool libHttpClientInit{ false };\n\n    // Android Specific Data\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    JavaVM *javaVM;\n    jobject applicationContext;\n    HCInitArgs initArgs;\n\n    /// <summary>The Java Application Context.</summary>\n    jclass m_mainActivityClass;\n    jobject m_mainActivityClassInstance;\n    jmethodID m_getApplicationContext;\n#endif\n\n    // Achievements Data\n    XblAchievementsResultHandle achievementsResult{ nullptr };\n#if CPP_TESTS_ENABLED\n    xbox::services::achievements::achievements_result achievementsResultCpp{};\n#endif\n\n    // libHttpClient Data\n    HCCallHandle httpCall{ nullptr };\n    HCMockCallHandle mockHttpCall{ nullptr };\n    HCWebsocketHandle websocket{ nullptr };\n\n    // XblHttpCall Data\n    XblHttpCallHandle xblHttpCall{ nullptr };\n\n    // Leaderboard Data\n    std::vector<char> leaderboardBuffer;\n    XblLeaderboardResult* leaderboardResult{ nullptr };\n#if  CPP_TESTS_ENABLED\n    xbox::services::leaderboard::leaderboard_result leaderboardResultCpp{};\n#endif\n\n    //Social Data\n#if CPP_TESTS_ENABLED\n    xbox::services::social::xbox_social_relationship_result socialRelationshipResult;\n    std::shared_ptr<xbox::services::social::social_relationship_change_subscription> socialRelationshipChangeSubscription;\n    function_context socialRelationshipChangedHandlerContext;\n#endif\n\n    // Matchmaking Data\n    XblCreateMatchTicketResponse* matchTicketResponse;\n#if CPP_TESTS_ENABLED\n    xbox::services::matchmaking::create_match_ticket_response matchTicketResponseCpp;\n#endif\n\n    // User Statistic Data\n    XblRealTimeActivitySubscriptionHandle statisticChangeSubscriptionHandle{ nullptr };\n    XblFunctionContext statisticChangedFunctionContext{ 0 };\n    long long lastUserStat = 0;\n#if CPP_TESTS_ENABLED\n    std::shared_ptr<xbox::services::user_statistics::statistic_change_subscription> statisticChangeSubscriptionCpp{ nullptr };\n    function_context statisticChangedFunctionContextCpp{ nullptr };\n#endif\n\n    // Title Storage Data\n    XblTitleStorageBlobMetadataResultHandle blobMetadataResultHandle{ nullptr };\n    XblTitleStorageBlobMetadata binaryBlobMetadata{};\n    XblTitleStorageBlobMetadata jsonBlobMetadata{};\n#if CPP_TESTS_ENABLED\n    xbox::services::title_storage::title_storage_blob_metadata_result blobMetadataResultCpp{};\n    xbox::services::title_storage::title_storage_blob_metadata blobMetadataCpp{};\n#endif\n\n    // Title Storage Rest API Calls Data\n    std::vector<std::string> blobResponseStrings;\n    std::string metadataResponseString;\n    std::vector<XblHttpCallHandle> titleStorageHttpCalls;\n    size_t titleStorageCompletedHttpCalls = 0;\n    size_t filesToDownload = 0;\n\n    // MP\n    std::string inviteHandle;\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\n    std::string apnsToken;\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_UWP\n    Windows::UI::Core::CoreDispatcher^ m_dispatcher;\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32\n    XblRealTimeActivitySubscriptionHandle gameInviteNotificationSubscriptionHandle{ nullptr };\n    XblFunctionContext gameInviteNotificationFunctionContext{ 0 };\n#endif\n\n    std::shared_ptr<ApiRunnerMultiDeviceManager> m_multiDeviceManager;\n    XblFunctionContext m_achievementProgressNotificationFunctionContext{ 0 };\n    \n};\n\nenum TypeType\n{\n    TypeType_None,\n    TypeType_Command,\n    TypeType_Event,\n    TypeType_API\n};\n\nstd::vector<std::string> TokenizeString(const std::string& input);\nvoid LogCat(bool logToFile, _Printf_format_string_ char const* format, ...);\nApiExplorerData* Data();\n"
  },
  {
    "path": "Tests/ApiExplorer/Include/multidevice.h",
    "content": "#pragma once\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 4365 )\n#pragma warning( disable : 4266 )\n#endif\n#include \"cpprest/http_msg.h\"\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n\nstruct ServerState \n{\n    std::string client1xuid;\n    std::string client1gt;\n    std::string client2xuid;\n    std::string client2gt;\n    std::string id;\n    std::map<std::string, std::string> propmap;\n};\n\nclass ApiRunnerMultiDeviceManager\n{\nprivate:\n    std::mutex m_mutex;\n    ServerState m_state;\n    std::string m_sessionId;\n    std::string m_sessionName;\n    bool m_hosted{ false };\n    bool m_isInitialized{ false };\n    bool m_isHCInitialized{ false };\n    bool m_isJoinable{ false };\n    std::string m_sessionState;\n    std::function<void(const std::string& key, const std::string& value)> m_onStateChangedHandler;\n    std::atomic<bool> m_doPoll;\n    std::atomic<bool> m_isJoined;\n    std::atomic<bool> m_isAbort;\n    utility::datetime m_nextCallTime;\n    bool m_callGetJoinable;\n\npublic:\n    ~ApiRunnerMultiDeviceManager();\n    HRESULT Init(_In_ std::function<void(const std::string& key, const std::string& value)> onStateChangedHandler);\n\n    bool IsInitialized() { return m_isInitialized; }\n    bool IsJoinable() { return m_isJoinable; }\n    bool Joined() { return m_isJoined; }\n    bool Abort() { return m_isAbort; }\n    std::string SessionId() { return m_sessionId; }\n    const ServerState& GetSessionState() { return m_state; }\n    bool IsHost() { return m_hosted; }\n    uint64_t GetLocalXuid();\n    uint64_t GetRemoteXuid();\n\n    HRESULT HostSession(\n        _In_ const std::string& name,\n        _In_ const std::string& xuid,\n        _In_ const std::string& gamertag,\n        _In_ std::function<void(HRESULT hr)> onResponse);\n\n    HRESULT WaitTillPeerConnects();\n\n    HRESULT JoinOpenSession(\n        _In_ const std::string& name,\n        _In_ const std::string& xuid,\n        _In_ const std::string& gamertag,\n        _In_ std::function<void(HRESULT hr)> handler);\n\n    HRESULT GetJoinable(\n        _In_ const std::string& name,\n        _In_ std::function<void(HRESULT hr, uint32_t statusCode, const std::string& joinableSessionId, const std::string& xuid, const std::string& gt)> handler\n        );\n\n    HRESULT JoinSession(\n        _In_ const std::string& sessionId,\n        _In_ const std::string& xuid,\n        _In_ const std::string& gamertag,\n        _In_ std::function<void(HRESULT hr)> handler);\n\n    HRESULT SetSessionState(\n        _In_ const std::string& key,\n        _In_ const std::string& value,\n        _In_ std::function<void(HRESULT)> handler);\n\n    HRESULT StartSessionStateChangePolling();\n    HRESULT StopSessionStateChangePolling();\n    HRESULT RefreshSessionState();\n    std::string GetSessionStateString() { return m_sessionState; }\n    std::string GetStateValueFromKey(std::string key);\n    bool IsDoPoll() { return m_doPoll; }\n    void ParseState(const std::string& responseString);\n\n    HRESULT MakeCall(\n        _In_ const std::string& method,\n        _In_ const std::string& url,\n        _In_ const std::vector<std::vector<std::string>>& headers,\n        _In_ std::function<void(HRESULT hr, uint32_t statusCode, const std::string& responseString)> handler);\n};\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Include/runner.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\nenum TestSet\n{\n    SingleDevice,\n    MultiDevice,\n    SingleDeviceBVTs\n};\n\n// Call these by runner\nvoid ApiRunnerSetupApiExplorer();\nvoid ApiRunnerSetupApiExplorerTestsPath(std::string testsPath);\nHRESULT ApiRunnerRunTest(std::string testName);\nHRESULT ApiRunnerRunTestWithSetup(std::string testName, bool repeat);\nvoid ApiRunnerSetRunTestsParams(int onlyFileNumber, int minFileNumber, int maxFileNumber);\nHRESULT ApiRunnerRunTests(TestSet set);\nvoid ApiRunnerProcessCmdLine(const std::string& cmdLine);\nstd::string ApiRunnerReadFile(std::string fileName);\nHRESULT ApiRunnerProcessJsonCmds(std::string json);\nbool ApiRunnerIsRunningTests();\nHRESULT ApiRunnerGetTestResult();\n\n// These functions need to be implemented by each runner\nvoid LogToFile(_Printf_format_string_ char const* format, ...);\nvoid LogToScreen(_Printf_format_string_ char const* format, ...);\n\n// These functions are specific to APIExplorer on iOS\n#if HC_PLATFORM == HC_PLATFORM_IOS\nvoid SetupAPNSRegistrationToken(std::string registrationToken);\n#endif\n\n// These functions are specific to APIExplorer on Android\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\nvoid SetupAndroidContext( JavaVM *javaVM, jobject context, jclass mainActivityClass, jobject mainActivityInstance, jmethodID getApplicationContext);\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/Win/pal.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n#ifndef max\n#define max(a,b)            (((a) > (b)) ? (a) : (b))\n#endif\n\n#ifndef min\n#define min(a,b)            (((a) < (b)) ? (a) : (b))\n#endif\n\nnamespace pal\n{\n    void strcpy(char * dst, size_t size, const char* src)\n    {\n        strcpy_s(dst, size, src);\n    }\n\n    int stricmp(const char* left, const char* right)\n    {\n        return _stricmp(left, right);\n    }\n\n    int vsprintf(char* message, size_t size, char const* format, va_list varArgs)\n    {\n        int result = vsnprintf(message, size, format, varArgs);\n        result = max(result, 0); // result is negative on error\n        result = min(static_cast<int>(size) - 1, result); // don't let it go past size-1\n        message[result] = 0;\n        return result;\n    }\n\n    char* strtok(char* str, char const* delimiter, char** context)\n    {\n        return strtok_s(str, delimiter, context);\n    }\n\n    void Sleep(unsigned long duration)\n    {\n        ::Sleep(duration);\n    }\n\n    bool FileExists(std::string fileName)\n    {\n        struct stat fileInfo;\n        return stat(fileName.c_str(), &fileInfo) == 0;\n    }\n\n    std::vector<std::string> EnumFolders(std::string folder)\n    {\n        std::vector<std::string> folders;\n        std::string searchFolder = folder + \"\\\\*\";\n\n        folders.push_back(folder);\n\n        WIN32_FIND_DATAA fd;\n        HANDLE hFind = ::FindFirstFileA(searchFolder.c_str(), &fd);\n        if (hFind != INVALID_HANDLE_VALUE)\n        {\n            do\n            {\n                if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n                {\n                    std::string subFolder = fd.cFileName;\n                    if (subFolder != \".\" &&\n                        subFolder != \"..\" &&\n                        subFolder != \"shared\")\n                    {\n                        subFolder = folder;\n                        subFolder += \"\\\\\";\n                        subFolder += fd.cFileName;\n                        folders.push_back(subFolder);\n                    }\n                }\n            } while (::FindNextFileA(hFind, &fd));\n            ::FindClose(hFind);\n        }\n\n        return folders;\n    }\n\n    std::vector<std::string> EnumFilesInFolderHelper(std::string folder, std::string spec)\n    {\n        std::vector<std::string> files;\n        std::string searchFolder = folder + \"\\\\\" + spec;\n\n        WIN32_FIND_DATAA fd;\n        HANDLE hFind = ::FindFirstFileA(searchFolder.c_str(), &fd);\n        if (hFind != INVALID_HANDLE_VALUE)\n        {\n            do\n            {\n                if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n                {\n                    std::string filePath = folder;\n                    filePath += \"\\\\\";\n                    filePath += fd.cFileName;\n                    files.push_back(filePath);\n                }\n            } while (::FindNextFileA(hFind, &fd));\n            ::FindClose(hFind);\n        }\n\n        return files;\n    }\n\n\n    std::vector<std::string> EnumFilesInFolder(std::string folder, std::string spec)\n    {\n        std::vector<std::string> folders = EnumFolders(folder);\n        std::vector<std::string> files;\n        for (std::string iFolder : folders)\n        {\n            std::vector<std::string> filesHelper;\n            filesHelper = EnumFilesInFolderHelper(iFolder, spec);\n            for (std::string f : filesHelper)\n            {\n                files.push_back(f);\n            }\n        }\n\n        return files;\n    }\n\n    std::string FindFile(std::string fileName)\n    {\n        if (FileExists(fileName))\n        {\n            return fileName;\n        }\n\n        char strBasePath[MAX_PATH] = { 0 };\n        GetModuleFileNameA(NULL, strBasePath, MAX_PATH);\n        char* lastSlash = strrchr(strBasePath, '\\\\');\n        if (lastSlash != nullptr)\n        {\n            *lastSlash = 0;\n        }\n\n        std::string testFilePath = Data()->m_testsPath + \"\\\\\" + fileName;\n        if (FileExists(testFilePath))\n        {\n            return testFilePath;\n        }\n\n        testFilePath = Data()->m_testsPath + \"\\\\..\\\\\" + fileName;\n        if (FileExists(testFilePath))\n        {\n            return testFilePath;\n        }\n\n        std::string fullPath;\n        std::string newPath = strBasePath;\n        newPath += \"\\\\\";\n        for (int i = 0; i < 5; i++)\n        {\n            newPath += \"..\\\\\";\n            testFilePath = newPath + fileName;\n            if (FileExists(testFilePath))\n            {\n                return testFilePath;\n            }\n\n            testFilePath = newPath + \"Tests\\\\APIExplorer\\\\\" + fileName;\n            if (FileExists(testFilePath))\n            {\n                return testFilePath;\n            }\n\n            testFilePath = newPath + \"..\\\\..\\\\..\\\\..\\\\Tests\\\\APIExplorer\\\\\" + fileName;\n            if (FileExists(testFilePath))\n            {\n                return testFilePath;\n            }\n        }\n        return fullPath;\n    }\n\n    std::string GetLuaPath()\n    {\n        std::string path{};\n\n        auto utestPath = FindFile(\"_luasetup_\\\\u-test\\\\u-test.lua\");\n        path += utestPath.substr(0, utestPath.find_last_of('\\\\')) + \"\\\\?.lua\";\n\n        auto commonPath = FindFile(\"_luasetup_\\\\xal\\\\common.lua\");\n        path += \";\" + commonPath.substr(0, commonPath.find_last_of('\\\\')) + \"\\\\?.lua\";\n\n        return path;\n    }\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/commands.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"utils.h\"\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"api_explorer.h\"\n#include \"pal.h\"\n#include \"runner.h\"\n#endif\n#include \"cpprest/json.h\"\n#include \"mem_hook.h\"\n\n#include <iostream>\n#include <string>\n\n\n#if HC_PLATFORM == HC_PLATFORM_IOS || HC_PLATFORM == HC_PLATFORM_ANDROID\n#define E_NOT_VALID_STATE E_FAIL\n#endif\n\nstd::shared_ptr<ApiCommand> GetApiFromCmdLine(const std::vector<std::string>& cmdLineTokens, std::string apiName, bool log);\nvoid SetupLua();\nvoid CleanupLua();\nvoid RegisterLuaAPIs();\nvoid SetupCommands();\nvoid ReplayCommands(const std::vector<std::string>& lineLogs);\nvoid ApiRunnerProcessCmdLine(const std::string& cmdLine);\nvoid Log(_Printf_format_string_ char const* format, ...);\nvoid LogInit();\nHRESULT CallLuaFunctionWithStringArgs(std::string fnName, std::vector<std::string> strs);\nHRESULT RunSetupScript();\n#if API_EXPLORER_EDITOR\nvoid StoreCmdLineInLog(std::string cmdLine, const std::vector<std::string>& tokens);\nvoid ClearScreen();\n#endif\nvoid MPMStopDoWorkHelper();\n\nstd::unique_ptr<ApiExplorerData> g_data;\n\nvoid InitApiExplorerData()\n{\n    g_data = std::make_unique<ApiExplorerData>();\n    g_data->m_runTestsHR = S_OK;\n    g_data->m_runningTests = false;\n    g_data->m_checkHR = true;\n    g_data->m_lastError = S_OK;\n    g_data->m_callUpdate = false;\n\n    if (g_data->m_testsPath.empty())\n    {\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n        auto rootFile = pal::FindFile(\"tests/tests.root\");\n#else\n        auto rootFile = pal::FindFile(\"tests.root\");\n#endif\n        assert(!rootFile.empty());\n        g_data->m_testsPath = rootFile.substr(0, rootFile.find_last_of(\"/\"));\n\n    }\n}\n\nApiExplorerData* Data()\n{\n    return g_data.get();\n}\n\nvoid ReplayCommands(const std::vector<std::string>& lineLogs)\n{\n    for (auto& cmd : lineLogs)\n    {\n        Log(\">> %s\", cmd.c_str());\n        ApiRunnerProcessCmdLine(cmd);\n    }\n}\n\nvoid ApiRunnerProcessCmdLine(const std::string& cmdLine)\n{\n    std::vector<std::string> tokens = TokenizeString(cmdLine);\n    if (tokens.size() == 0)\n    {\n        return;\n    }\n\n#if API_EXPLORER_EDITOR\n    StoreCmdLineInLog(cmdLine, tokens);\n#endif\n\n    for (auto& cmd : Data()->m_commands)\n    {\n        if (cmd.name == tokens[0])\n        {\n            cmd.cmdCallback(tokens);\n            return;\n        }\n    }\n}\n\n#if !API_EXPLORER_EDITOR\nvoid Log(_Printf_format_string_ char const* format, ...)\n{\n    char message[4096] = {};    \n\n    va_list varArgs{};\n    va_start(varArgs, format);\n    pal::vsprintf(message, 4096, format, varArgs);\n    va_end(varArgs);\n\n    LogToScreen(message);\n    LogToFile(message);\n}\n#endif\n\nstatic inline void rtrim(std::string &s)\n{\n    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch)\n         {\n             return !std::isspace(ch);\n         }).base(), s.end());\n}\n\nstd::vector<std::string> TokenizeString(const std::string& input)\n{\n    std::vector<std::string> tokens;\n    const char seperators[32] = \" \\r\\n\";\n    char* tok;\n    char *next_token = NULL;\n    char szInput[1024] = { 0 };\n    pal::strcpy(szInput, 1024, input.c_str());\n    \n    if (strchr(szInput, '\\\"') != nullptr)\n    {\n        tok = pal::strtok(szInput, \"\\\"\", &next_token);\n        while (tok != nullptr)\n        {\n            std::string strTok = tok;\n            rtrim(strTok);\n            tokens.push_back(strTok);\n            tok = pal::strtok(0, \"\\\"\", &next_token);\n        }\n    }\n    else\n    {\n        tok = pal::strtok(szInput, seperators, &next_token);\n        while (tok != nullptr)\n        {\n            tokens.push_back(tok);\n            tok = pal::strtok(0, seperators, &next_token);\n        }\n    }\n    \n    return tokens;\n}\n\n#if API_EXPLORER_EDITOR\nvoid OnCmdHelp(const std::vector<std::string>& cmdLineTokens)\n{\n    UNREFERENCED_PARAMETER(cmdLineTokens);\n    for (auto& cmd : Data()->m_commands)\n    {\n        if (!cmd.hideFromHelp) Log(\"  %s\", cmd.name);\n    }\n}\n#endif\n\nvoid OnCmdQuit(const std::vector<std::string>&)\n{\n    Data()->m_quit = true;\n}\n\nvoid MultiDeviceInit()\n{\n    Data()->m_multiDeviceManager->Init(\n        [](const std::string& key, const std::string& value) // onStateChangedHandler\n        {\n            UNREFERENCED_PARAMETER(key);\n            UNREFERENCED_PARAMETER(value);\n            // note: don't call into LUA as we're not in LUA file processing thread\n        });\n}\n\nvoid OnCmdHost(const std::vector<std::string>& cmdLineTokens)\n{\n    if (cmdLineTokens.size() < 2)\n    {\n        LogToScreen(\"Try: host name.  eg host youralias\");\n        return;\n    }\n\n    SetupLua();\n    RunSetupScript();\n    CleanupLua();\n\n    uint64_t xuid = Data()->xboxUserId;\n    char xuidStr[128];\n    sprintf_s(xuidStr, \"%llu\", static_cast<unsigned long long>(xuid));\n    std::string gamertag = Data()->gamertag;\n\n    LogToScreen(\"Local XUID: %s GamerTag: %s\", xuidStr, gamertag.c_str());\n    MultiDeviceInit();\n    bool hostedSession = false;\n    std::string name = cmdLineTokens[1];\n\n    Data()->m_multiDeviceManager->HostSession(\n        name,\n        xuidStr,\n        gamertag,\n        [&hostedSession](HRESULT hr)\n        {\n            if (SUCCEEDED(hr))\n            {\n                hr = Data()->m_multiDeviceManager->WaitTillPeerConnects();\n                if (SUCCEEDED(hr))\n                {\n                    hostedSession = true;\n                }\n            }\n        });\n\n    while (!hostedSession)\n    {\n        pal::Sleep(100);\n    }\n}\n\nvoid OnCmdMemTrack(const std::vector<std::string>& cmdLineTokens)\n{\n    if (cmdLineTokens.size() < 2)\n    {\n        LogToScreen(\"Try: memtrack bool.  eg memtrack true\");\n        return;\n    }\n\n    std::string enabledStr = cmdLineTokens[1];\n    bool enabled = (enabledStr == \"true\");\n    Data()->m_trackUnhookedMemory = enabled;\n    LogToScreen(\"TrackUnhookedMemory: %d\", enabled);\n}\n\nvoid OnCmdJoin(const std::vector<std::string>& cmdLineTokens)\n{\n    if (cmdLineTokens.size() < 2)\n    {\n        LogToScreen(\"Try: join name.  eg join youralias\");\n        return;\n    }\n\n    SetupLua();\n    RunSetupScript();\n    CleanupLua();\n\n    uint64_t xuid = Data()->xboxUserId;\n    char xuidStr[128];\n    sprintf_s(xuidStr, \"%llu\", static_cast<unsigned long long>(xuid));\n    std::string gamertag = Data()->gamertag;\n\n    LogToScreen(\"Local XUID: %s GamerTag: %s\", xuidStr, gamertag.c_str());\n    MultiDeviceInit();\n    bool joinedSession = false;\n    std::string name = cmdLineTokens[1];\n\n    Data()->m_multiDeviceManager->JoinOpenSession(\n        name,\n        xuidStr,\n        gamertag,\n        [&joinedSession](HRESULT hr)\n        {\n            if (SUCCEEDED(hr))\n            {\n                joinedSession = true;\n            }\n        });\n\n    while (!joinedSession)\n    {\n        pal::Sleep(100);\n    }\n}\n\nbool LoadFile(const std::string& fileNameInput)\n{\n    std::string strFilePath = pal::FindFile(fileNameInput);\n    if (strFilePath.empty())\n    {\n        std::string testPath = \"Tests\\\\\" + fileNameInput;\n        strFilePath = pal::FindFile(testPath);\n    }\n\n    if (!strFilePath.empty())\n    {\n        std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n        if (Data()->L == nullptr)\n        {\n            return false;\n        }\n\n        int result = luaL_dofile(Data()->L, strFilePath.c_str()); // load the script\n        if (result == LUA_OK)\n        {\n            return true;\n        }\n        else\n        {\n            const char * error = lua_tostring(Data()->L, -1);\n            LogToScreen(\"Couldn't load %s, error = %s\", fileNameInput.c_str(), error);\n        }\n    }\n    else\n    {\n        LogToFile(\"Couldn't find %s\", fileNameInput.c_str());\n    }\n\n    return false;\n}\n\nHRESULT WaitForTestResult()\n{\n    while (!Data()->m_stopTest)\n    {\n        if(Data()->m_callUpdate)\n        {\n            CallLuaFunction(\"update\");\n        }\n        pal::Sleep(10);\n    }\n\n    Data()->m_callUpdate = false;\n    return Data()->m_testHR;\n}\n\nvoid WaitForXalCleanup()\n{\n    while (Data()->m_isXalInitialized)\n    {\n        pal::Sleep(10);\n    }\n}\n\nvoid APIRunner_CleanupLeakCheck()\n{\n    auto memHook = GetApiRunnerMemHook();\n    memHook->LogStats(\"CleanupLeakCheck\");\n    memHook->LogLeaks();\n}\n\nHRESULT RunTestWithoutCleanup(const std::string& scriptName)\n{\n    Data()->m_stopTest = false;\n    assert(!scriptName.empty());\n\n    bool testLoaded = LoadFile(scriptName);\n    if (!testLoaded)\n    {\n        std::string scriptFailure = \"Failed to load \" + scriptName;\n        Log(scriptFailure.c_str());\n        return E_FAIL;\n    }\n\n    return WaitForTestResult();\n}\n\nHRESULT RunTestInternal(std::string testName, bool overrideSkip)\n{\n    if (!testName.empty())\n    {\n        Data()->m_stopTest = false;\n        Data()->m_testHR = S_OK;\n        Data()->m_ignoreHRs.clear();\n        Data()->m_onXalTryAddFirstUserSilentlyAsync = \"\";\n        Data()->m_onTaskQueueTerminateWithAsyncWait = \"\";\n\n        if (overrideSkip)\n        {\n            // Tell test harness not to skip test if because it was directly run\n            CallLuaString(\"api = require 'u-test'; api.skipOverride = true;\");\n        }\n        else\n        {\n            CallLuaString(\"api = require 'u-test'; api.skipOverride = false;\");\n        }\n\n        RunTestWithoutCleanup(testName);\n    }\n\n    std::this_thread::sleep_for(std::chrono::milliseconds{ 500 });\n    CallLuaString(\"common = require 'common'; common.cleanup()\");\n    WaitForXalCleanup();\n\n    return S_OK;\n}\n\nHRESULT ApiRunnerRunTest(std::string testName)\n{\n    return RunTestInternal(testName, true);\n}\n\nHRESULT RunSetupScript()\n{\n    char message[4096] = {};\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n    std::string sharedFolder = \"_luasetup_\\\\xal\";\n    sprintf_s(message, \"tests\\\\%s\\\\setup.lua\", sharedFolder.c_str());\n#else\n    std::string sharedFolder = \"xal\";\n    sprintf_s(message, \"%s/setup.lua\", sharedFolder.c_str());\n#endif\n    std::string strFilePath = pal::FindFile(message);\n    if (strFilePath.empty() || strFilePath.length() < 5)\n    {\n        Log(\"Can't find setup.lua\");\n        return E_NOINTERFACE;\n    }\n\n    return RunTestInternal(message, true);\n}\n\nvoid OnCmdRepeatRunTest(const std::vector<std::string>& cmdLineTokens)\n{\n    if (cmdLineTokens.size() < 2)\n    {\n        std::string jsonFileContents = ApiRunnerReadFile(\"cmds.json\");\n        ApiRunnerProcessJsonCmds(jsonFileContents);\n    }\n    else\n    {\n        ApiRunnerRunTestWithSetup(cmdLineTokens[1], true);\n    }\n}\n\nvoid OnCmdRunTest(const std::vector<std::string>& cmdLineTokens)\n{\n    if (cmdLineTokens.size() < 2)\n    {\n        LogToScreen(\"Try: runtest testName\");\n    }\n    else\n    {\n        ApiRunnerRunTestWithSetup(cmdLineTokens[1], false);\n    }\n}\n\nvoid EnableTestSet(TestSet set)\n{\n    if (set == MultiDevice)\n    {\n        CallLuaString(\"api = require 'u-test'; api.enablebvts = false; api.enablemultidevice = true;\");\n    }\n    else if (set == SingleDeviceBVTs)\n    {\n        CallLuaString(\"api = require 'u-test'; api.enablebvts = true; api.enablemultidevice = false;\");\n    }\n    else\n    {\n        CallLuaString(\"api = require 'u-test'; api.enablebvts = false; api.enablemultidevice = false;\");\n    }\n}\n\nvoid OnCmdFaultInjection(const std::vector<std::string>& cmdLineTokens)\n{\n    assert(cmdLineTokens.size() >= 2);\n    if (pal::stricmp(cmdLineTokens[1].c_str(), \"user\") == 0)\n    {\n        XblEnableFaultInjection(INJECTION_FEATURE_USER);\n    }\n    if (pal::stricmp(cmdLineTokens[1].c_str(), \"http\") == 0)\n    {\n        XblEnableFaultInjection(INJECTION_FEATURE_HTTP);\n    }\n    if (pal::stricmp(cmdLineTokens[1].c_str(), \"options\") == 0)\n    {\n        assert(cmdLineTokens.size() == 5);\n        int64_t failFreq = static_cast<int64_t>(atoi(cmdLineTokens[2].c_str()));\n        uint64_t freqChangeSpeed = static_cast<uint64_t>(atoi(cmdLineTokens[3].c_str()));\n        int64_t freqChangeAmount = static_cast<int64_t>(atoi(cmdLineTokens[4].c_str()));\n        XblSetFaultInjectOptions(failFreq, freqChangeSpeed, freqChangeAmount);\n    }\n}\n\nvoid OnCmdRunScript(const std::vector<std::string>& cmdLineTokens)\n{\n    assert(cmdLineTokens.size() == 2);\n    SetupLua();\n    RunTestWithoutCleanup(cmdLineTokens[1]);\n    CleanupLua();\n}\n\nbool DoesTestContainsSetMaker(std::string test, TestSet set)\n{\n    std::string strFilePath = pal::FindFile(test);\n    if (strFilePath.empty())\n    {\n        std::string testPath = \"Tests\\\\\" + test;\n        strFilePath = pal::FindFile(testPath);\n    }\n    std::string fileContents = ApiRunnerReadFile(strFilePath);\n\n    std::string marker;\n    bool avoid = false;\n    switch (set)\n    {\n        case MultiDevice: marker = \"test.ismultidevice\"; break;\n        case SingleDevice: marker = \"test.ismultidevice\"; avoid = true; break;\n        case SingleDeviceBVTs: marker = \"test.isbvt\"; break;\n    }\n\n    bool found = false;\n    if (fileContents.find(marker) != std::string::npos)\n    {\n        found = true;\n    }\n\n    if (avoid) found = !found;\n    return found;\n}\n\nHRESULT RunTestsHelper(TestSet set)\n{\n    SetupLua();\n\n    LogToScreen(\"Signing in silent if possible\");\n    if (Data()->m_trackUnhookedMemory)\n    {\n        auto memHook = GetApiRunnerMemHook();\n        memHook->StartMemTracking();\n    }\n\n    HRESULT hr = RunSetupScript();\n    if (FAILED(hr))\n    {\n        LogToScreen(\"RunSetupScript() failed with HR = %s\", ConvertHR(hr).c_str());\n        return hr;\n    }\n    if (!Data()->gotXalUser)\n    {\n        LogToScreen(\"Data()->GotXalUser was invalid\");\n        return E_NOT_VALID_STATE;\n    }\n\n    Data()->m_runTestsHR = S_OK;\n    Data()->m_runningTests = true;\n\n    LogToScreen(\"Running tests in %s\", Data()->m_testsPath.c_str());\n    LogToScreen(\"See debug output & log file for detail\");\n    LogToScreen(\" \");\n\n    EnableTestSet(set);\n    std::vector<std::string> tests = pal::EnumFilesInFolder(Data()->m_testsPath, \"*.lua\");\n\n    int iFileNumber = 0;\n    for (auto& test : tests)\n    {\n        if (Data()->m_quit)\n            return S_OK;\n\n        if (test.find(\"u-test.lua\") != std::string::npos)\n            continue;\n\n        iFileNumber++;\n        if (Data()->m_onlyFileNumber > 0) \n        {\n            // Skip every file except the one at a specific index\n            if (iFileNumber != Data()->m_onlyFileNumber)\n                continue;\n        }\n\n        if (Data()->m_minFileNumber > 0 || Data()->m_maxFileNumber > 0)\n        {\n            // Skip files outside range\n            if (iFileNumber < Data()->m_minFileNumber ||\n                iFileNumber > Data()->m_maxFileNumber)\n            {\n                continue;\n            }\n        }\n\n        std::string testName = test;\n        std::size_t found = testName.find_last_of('\\\\');\n        if (found == std::string::npos)\n        {\n            found = testName.find_last_of('/');\n        }\n        if (found != std::string::npos)\n        {\n            testName = testName.substr(found + 1);\n        }\n\n        if (!DoesTestContainsSetMaker(test, set))\n        {\n            continue;\n        }\n\n        LogToFile(\"***************************************\");\n        LogToScreen(\"[FILE] Processing %s.  File #%d\", testName.c_str(), iFileNumber);\n        LogToFile(\"***************************************\");\n        \n        hr = RunTestInternal(test, false);\n        if (FAILED(hr))\n        {\n            LogToScreen(\"FAILED: hr=%s (0x%0.8x)\", ConvertHR(hr).c_str(), hr);\n            return hr;\n        }\n\n#if HC_PLATFORM != HC_PLATFORM_GDK\n        if (!Data()->m_wasTestSkipped)\n        {\n            pal::Sleep(6000); // For in-proc SDK (Win32/Mobile, etc.), need to delay between each test otherwise you'll get 429 from https://title.mgt.xboxlive.com/titles/current/endpoints which only allows 50 requests per 300 seconds\n        }\n#endif\n        Data()->m_wasTestSkipped = false;\n    }\n\n    if (Data()->m_trackUnhookedMemory)\n    {\n        auto memHook = GetApiRunnerMemHook();\n        memHook->LogUnhookedStats();\n        APIRunner_CleanupLeakCheck();\n    }\n\n    CallLuaString(\"test.summary()\");\n    CleanupLua();\n\n    Data()->m_runningTests = false;\n\n    return S_OK;\n}\n\nHRESULT WaitTillDone()\n{\n    Data()->m_quit = true;\n    while (\n        Data()->m_runningTests ||\n        !Data()->m_socialDoWorkDone ||\n        !Data()->m_mpmDoWorkDone)\n    {\n        pal::Sleep(50);\n    }\n\n    return S_OK;\n}\n\n#if HC_PLATFORM_IS_MICROSOFT\ntypedef wchar_t char_t;\ntypedef std::wstring string_t;\ntypedef std::wstringstream stringstream_t;\n#else\ntypedef char char_t;\ntypedef std::string string_t;\ntypedef std::stringstream stringstream_t;\n#endif\n\nstatic int CharTFromUft8(\n    _In_z_ const char* inArray,\n    _Out_writes_z_(cchOutArray) char_t* outArray,\n    _In_ int cchOutArray\n)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    // query for the buffer size\n    auto queryResult = MultiByteToWideChar(\n        CP_UTF8, MB_ERR_INVALID_CHARS,\n        inArray, -1,\n        nullptr, 0\n    );\n\n    if (queryResult > cchOutArray && cchOutArray == 0)\n    {\n        return queryResult;\n    }\n    else if (queryResult == 0 || queryResult > cchOutArray)\n    {\n        throw std::exception(\"char_t_from_utf8 failed\");\n    }\n\n    auto conversionResult = MultiByteToWideChar(\n        CP_UTF8, MB_ERR_INVALID_CHARS,\n        inArray, -1,\n        outArray, cchOutArray\n    );\n    if (conversionResult == 0)\n    {\n        throw std::exception(\"char_t_from_utf8 failed\");\n    }\n\n    return conversionResult;\n#else\n    int len = (int)strlen(inArray);\n    if (len < cchOutArray && outArray != nullptr)\n    {\n        strlcpy(outArray, inArray, len + 1);\n    }\n    else if (cchOutArray > 0)\n    {\n        return 0;\n    }\n    return len + 1;\n#endif\n}\n\nstatic string_t StringTFromUtf8(_In_z_ const char* utf8)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    uint64_t cchOutString = static_cast<uint64_t>(CharTFromUft8(utf8, nullptr, 0));\n    string_t out(static_cast<unsigned int>(cchOutString - 1), '\\0');\n    CharTFromUft8(utf8, &out[0], static_cast<int>(cchOutString));\n    return out;\n#else\n    return string_t(utf8);\n#endif\n}\n\n\nstatic int Utf8FromCharT(\n    _In_z_ const char_t* inArray,\n    _Out_writes_z_(cchOutArray) char* outArray,\n    _In_ int cchOutArray\n)\n{\n#if HC_PLATFORM_IS_MICROSOFT\n    // query for the buffer size\n    auto queryResult = WideCharToMultiByte(\n        CP_UTF8, WC_ERR_INVALID_CHARS,\n        inArray, -1,\n        nullptr, 0,\n        nullptr, nullptr\n    );\n\n    if (queryResult > cchOutArray && cchOutArray == 0)\n    {\n        return queryResult;\n    }\n    else if (queryResult == 0 || queryResult > cchOutArray)\n    {\n        throw std::exception(\"utf8_from_char_t failed\");\n    }\n\n    auto conversionResult = WideCharToMultiByte(\n        CP_UTF8, WC_ERR_INVALID_CHARS,\n        inArray, -1,\n        outArray, cchOutArray,\n        nullptr, nullptr\n    );\n    if (conversionResult == 0)\n    {\n        throw std::exception(\"utf8_from_char_t failed\");\n    }\n\n    return conversionResult;\n#else\n    int len = (int)strlen(inArray);\n    if (len < cchOutArray && outArray != nullptr)\n    {\n        strlcpy(outArray, inArray, len + 1);\n    }\n    else if (cchOutArray > 0)\n    {\n        return 0;\n    }\n    return len + 1;\n#endif\n}\n\n#if HC_PLATFORM != HC_PLATFORM_IOS\nweb::json::value extract_json_field(\n    _In_ const web::json::value& json,\n    _In_ const string_t& name)\n{\n    if (json.is_object())\n    {\n        auto& jsonObj = json.as_object();\n        auto it = jsonObj.find(name);\n        if (it != jsonObj.end())\n        {\n            return it->second;\n        }\n    }\n\n    return web::json::value::null();\n}\n\nweb::json::array extract_json_array(\n    _In_ const web::json::value& jsonValue,\n    _In_ const string_t& arrayName\n)\n{\n    web::json::value field(extract_json_field(jsonValue, arrayName));\n    if ((!field.is_array()) || field.is_null()) { return web::json::value::array().as_array(); }\n    return field.as_array();\n}\n#endif\n\nstd::string ApiRunnerReadFile(std::string fileName)\n{\n    assert(Data() != nullptr); // call ApiRunnerSetupApiExplorer() first\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    // In Android, the test files are considered assets.\n    // These files are copied from the assets folder into the external storage\n    // when the app is installed and launched on a device.\n    // Searching for the file is then done using the filename and doesn't use paths like other platforms\n    std::string fileNameEdited = fileName.substr(0, fileName.find_last_of(\"\\\\\"));\n    std::string strFilePath = pal::FindFile(fileNameEdited);\n#else\n    std::string strFilePath = pal::FindFile(fileName);\n#endif\n    if (strFilePath.empty())\n    {\n        std::string testPath = \"Tests\\\\\" + fileName;\n        strFilePath = pal::FindFile(testPath);\n    }\n\n    if (strFilePath.empty())\n    {\n        return \"\";\n    }\n\n    std::ifstream fileStream(strFilePath);\n    std::string str;\n\n    fileStream.seekg(0, std::ios::end);\n    str.reserve(static_cast<unsigned int>(fileStream.tellg()));\n    fileStream.seekg(0, std::ios::beg);\n\n    str.assign((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());\n    return str;\n}\n\nHRESULT ApiRunnerProcessJsonCmds(std::string json)\n{\n#if HC_PLATFORM == HC_PLATFORM_IOS\n    ApiRunnerProcessCmdLine(\"runtests\");\n#else\n    assert(Data() != nullptr); // call ApiRunnerSetupApiExplorer() first\n\n    web::json::value jsonCmds = web::json::value::parse(StringTFromUtf8(json.c_str()));\n    auto commands = extract_json_array(jsonCmds, _T(\"commands\"));\n\n    do\n    {\n        for (const auto& command : commands)\n        {\n            char cmdStr[1024] = { 0 };\n            Utf8FromCharT(command.as_string().data(), cmdStr, sizeof(cmdStr));\n            ApiRunnerProcessCmdLine(std::string(cmdStr));\n        }\n    } while (Data()->m_repeatJsonCmds);\n#endif\n    return S_OK;\n}\n\nvoid ApiRunnerSetRunTestsParams(int onlyFileNumber, int minFileNumber, int maxFileNumber)\n{\n    Data()->m_onlyFileNumber = onlyFileNumber;\n    Data()->m_minFileNumber = minFileNumber;\n    Data()->m_maxFileNumber = maxFileNumber;\n}\n\nHRESULT ApiRunnerRunTests(TestSet set)\n{\n    assert(Data() != nullptr); // call ApiRunnerSetupApiExplorer() first\n\n    if (Data()->m_runningTests)\n    {\n        LogToFile(\"Tests in progress\");\n        return S_OK;\n    }\n\n    HRESULT hr = RunTestsHelper(set);\n    Data()->m_runTestsHR = hr;\n    Data()->m_runningTests = false;\n    \n    return hr;\n}\n\nvoid OnCmdMultiDeviceTests(const std::vector<std::string>&)\n{\n    ApiRunnerRunTests(TestSet::MultiDevice);\n}\n\nvoid OnCmdRunBvts(const std::vector<std::string>&)\n{\n    ApiRunnerRunTests(TestSet::SingleDeviceBVTs);\n}\n\nvoid OnCmdRunTests(const std::vector<std::string>&)\n{\n    ApiRunnerRunTests(TestSet::SingleDevice);\n}\n\nHRESULT ApiRunnerRunTestWithSetup(std::string testName, bool repeat)\n{\n    if (Data()->m_runningTests)\n    {\n        LogToFile(\"Tests in progress\");\n        return E_UNEXPECTED;\n    }\n\n\n    Data()->m_runningTests = true;\n    SetupLua();\n    if (Data()->m_trackUnhookedMemory)\n    {\n        auto memHook = GetApiRunnerMemHook();\n        memHook->StartMemTracking();\n    }\n    HRESULT hr = RunSetupScript();\n    if (SUCCEEDED(hr))\n    {\n        auto testFullPath = pal::FindFile(testName);\n        if (testFullPath.empty())\n        {\n            LogToScreen(\"Can't find %s\", testName.c_str());\n        }\n        if (repeat)\n        {\n            while (true)\n            {\n                hr = RunTestInternal(testName, true);\n                if (FAILED(hr))\n                {\n                    break;\n                }\n            }\n        }\n        else\n        {\n            hr = RunTestInternal(testName, true);\n        }\n    }\n\n    if (Data()->m_trackUnhookedMemory)\n    {\n        auto memHook = GetApiRunnerMemHook();\n        memHook->LogUnhookedStats();\n        APIRunner_CleanupLeakCheck();\n    }\n\n    CleanupLua();\n    Data()->m_runningTests = false;\n\n    return hr;\n}\n\nvoid OnCmdClear(const std::vector<std::string>&)\n{\n#if API_EXPLORER_EDITOR\n    ClearScreen();\n#endif\n}\n\nvoid OnCmdLoop(const std::vector<std::string>&)\n{\n    Data()->m_repeatJsonCmds = true;\n}\n\nbool IsFailHr(HRESULT hr)\n{\n    if (SUCCEEDED(hr))\n    {\n        return false;\n    }\n\n    for (auto hrIgnore : Data()->m_ignoreHRs)\n    {\n        if (hrIgnore == hr)\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nvoid OutputDebugStackTrace(std::vector<std::string> stackTrace)\n{   \n    LogToScreen(\"----------- BEGIN STACK TRACE -----------\");\n    for (std::string stack_string : stackTrace)\n    {\n        LogToScreen(stack_string.c_str());\n    }\n    LogToScreen(\"----------- END STACK TRACE -----------\");\n}\n\nvoid LuaStopTestIfFailed(HRESULT hr)\n{\n    Data()->m_lastError = hr;\n    if (FAILED(hr) && Data()->m_checkHR)\n    {\n        char text[1024];\n\n        auto memHook = GetApiRunnerMemHook();\n        std::vector<std::string> stackTrace = memHook->GetStackLogLine();\n        OutputDebugStackTrace(stackTrace);\n\n        sprintf_s(text, \"local hr = 0x%0.8x; test.equal_no_log(hr, 0); test.stopTest();\", hr);\n        std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n        if (Data()->L != nullptr)\n        {\n            luaL_dostring(Data()->L, text);\n\n            StopTestFile_Lua(Data()->L);\n        }\n    }\n}\n\nint LuaReturnHR(lua_State *L, HRESULT hr, int extraParams)\n{\n    LuaStopTestIfFailed(hr);\n    lua_pushnumber(L, hr);\n    return 1 + extraParams;\n}\n\nHRESULT CallLuaStringWithDefault(std::string customFn, std::string defaultFn)\n{\n    Log(customFn.c_str());\n    if (!customFn.empty()) \n    { \n        return CallLuaString(customFn);\n    } \n    else \n    { \n        return CallLuaString(defaultFn);\n    }\n}\n\n\nHRESULT CallLuaString(std::string str)\n{\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    if (Data()->L != nullptr)\n    {\n        luaL_dostring(Data()->L, str.c_str());\n    }\n    return S_OK;\n}\n\nHRESULT CallLuaFunctionWithHr(HRESULT hr, std::string fnName)\n{\n    LuaStopTestIfFailed(hr);\n    if (FAILED(hr) && Data()->m_checkHR)\n    {\n        return hr;\n    }\n\n    return CallLuaFunction(fnName);\n}\n\nHRESULT CallLuaFunction(std::string fnName)\n{\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    if (Data()->L == nullptr)\n    {\n        return E_NOINTERFACE;\n    }\n\n    lua_getglobal(Data()->L, fnName.c_str()); // get function \n    if (lua_isfunction(Data()->L, lua_gettop(Data()->L)))\n    {\n        lua_call(Data()->L, 0, 0); // call the function with 0 arguments, return 0 results\n    }\n    else\n    {\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\nHRESULT CallLuaFunctionWithStringArgs(std::string fnName, std::vector<std::string> strs)\n{\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    if (Data()->L == nullptr)\n    {\n        return E_NOINTERFACE;\n    }\n\n    lua_getglobal(Data()->L, fnName.c_str()); // get function \n    if (lua_isfunction(Data()->L, lua_gettop(Data()->L)))\n    {\n        for (const auto& s : strs)\n        {\n            lua_pushstring(Data()->L, s.c_str());\n        }\n        lua_call(Data()->L, static_cast<int>(strs.size()), 0);\n    }\n    else\n    {\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\nvoid ApiRunnerSetupApiExplorerTestsPath(std::string testsPath)\n{\n    Data()->m_testsPath = testsPath;\n}\n\nvoid CleanupLua()\n{\n    MPMStopDoWorkHelper();\n    if (Data()->m_multiDeviceManager)\n    {\n        Data()->m_multiDeviceManager->StopSessionStateChangePolling();\n    }\n\n    {\n        std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n        lua_close(Data()->L); // cleanup Lua\n        Data()->L = nullptr;\n    }\n}\n\nvoid SetupLua()\n{\n    std::lock_guard<std::recursive_mutex> lock(Data()->m_luaLock);\n    Data()->L = luaL_newstate();\n    assert(Data()->L != nullptr);\n    luaL_openlibs(Data()->L); // load Lua base libraries\n    \n    // Setup paths\n    std::string luaPath = pal::GetLuaPath();\n    \n    lua_getglobal(Data()->L, \"package\");\n    lua_getfield(Data()->L, -1, \"path\"); // get field \"path\" from table at top of stack (-1)\n    std::string cur_path = lua_tostring(Data()->L, -1); // grab path string from top of stack\n    cur_path.append(\";\");\n    cur_path.append(luaPath);\n    lua_pop(Data()->L, 1); // get rid of the string on the stack we just pushed on line 5\n    lua_pushstring(Data()->L, cur_path.c_str()); // push the new one\n    lua_setfield(Data()->L, -2, \"path\"); // set the field \"path\" in table at -2 with value at top of stack\n    lua_pop(Data()->L, 1); // get rid of package table from top of stack\n    \n    RegisterLuaAPIs();\n}\n\nvoid ApiRunnerSetupApiExplorer()\n{\n    LogInit();\n    InitApiExplorerData();\n    SetupCommands();\n\n    Data()->m_multiDeviceManager = std::make_shared<ApiRunnerMultiDeviceManager>();\n}\n\nvoid SetupCommands()\n{\n#if API_EXPLORER_EDITOR\n    Data()->m_commands.push_back({ \"help\", OnCmdHelp, true });\n    Data()->m_commands.push_back({ \"?\", OnCmdHelp, true });\n#endif\n    Data()->m_commands.push_back({ \"exit\", OnCmdQuit, false });\n    Data()->m_commands.push_back({ \"quit\", OnCmdQuit, true });\n    Data()->m_commands.push_back({ \"q\", OnCmdQuit, true });\n    Data()->m_commands.push_back({ \"cls\", OnCmdClear, true });\n    Data()->m_commands.push_back({ \"clear\", OnCmdClear, false });\n    Data()->m_commands.push_back({ \"loop\", OnCmdLoop, false });\n      \n    Data()->m_commands.push_back({ \"runtest\", OnCmdRunTest, true });\n    Data()->m_commands.push_back({ \"rt\", OnCmdRunTest, false });\n    Data()->m_commands.push_back({ \"repeat\", OnCmdRepeatRunTest, true });\n\n    Data()->m_commands.push_back({ \"runtests\", OnCmdRunTests, false });\n    Data()->m_commands.push_back({ \"rts\", OnCmdRunTests, true });\n    Data()->m_commands.push_back({ \"run\", OnCmdRunTests, true });\n    Data()->m_commands.push_back({ \"runbvts\", OnCmdRunBvts, false });\n    Data()->m_commands.push_back({ \"runbarescript\", OnCmdRunScript, true });\n    Data()->m_commands.push_back({ \"faultinjection\", OnCmdFaultInjection, true });\n\n    Data()->m_commands.push_back({ \"host\", OnCmdHost, true });\n    Data()->m_commands.push_back({ \"join\", OnCmdJoin, true });\n    Data()->m_commands.push_back({ \"runmultidevicetests\", OnCmdMultiDeviceTests, true });\n    Data()->m_commands.push_back({ \"memtrack\", OnCmdMemTrack, true });\n}\n\nbool ApiRunnerIsRunningTests()\n{\n    return !Data()->m_runningTests;\n}\n\nHRESULT ApiRunnerGetTestResult()\n{\n    return Data()->m_runTestsHR;\n}\n\nuint64_t GetUint64FromLua(lua_State *L, int paramNum, uint64_t defaultArg)\n{\n    uint64_t t = defaultArg;\n    if (lua_gettop(L) >= paramNum)\n    {\n        t = (uint64_t)lua_tointeger(L, paramNum);\n    }\n    return t;\n}\n\nuint32_t GetUint32FromLua(lua_State *L, int paramNum, uint32_t defaultArg)\n{\n    return (uint32_t)GetUint64FromLua(L, paramNum, defaultArg);\n}\n\nbool GetBoolFromLua(lua_State *L, int paramNum, bool defaultArg)\n{\n    bool t = defaultArg;\n    if (lua_gettop(L) >= paramNum)\n    {\n        t = (bool)lua_tonumber(L, paramNum);\n    }\n    return t;\n}\n\nstd::string GetStringFromLua(lua_State *L, int paramNum, std::string defaultArg)\n{\n    std::string t = defaultArg;\n    if (lua_gettop(L) >= paramNum)\n    {\n        t = lua_tostring(L, paramNum);\n    }\n    return t;\n}\n\nvoid LogCat(bool logToFile, _Printf_format_string_ char const* format, ...)\n{\n    char message[8000] = {};\n\n    va_list varArgs{};\n    va_start(varArgs, format);\n    pal::vsprintf(message, 8000, format, varArgs);\n    va_end(varArgs);\n\n    std::string catMessage = message;\n    {\n        std::lock_guard<std::mutex> lock(Data()->m_catMessageLock);\n        Data()->m_catMessage += catMessage;\n        if (Data()->m_catMessage.find_first_of('\\n') != std::string::npos)\n        {\n            std::vector<std::string> tokens;\n            const char seperators[32] = \"\\n\";\n            char* tok;\n            char *next_token = NULL;\n            char szInput[16000] = { 0 };\n            pal::strcpy(szInput, 16000, Data()->m_catMessage.c_str());\n\n            tok = pal::strtok(szInput, seperators, &next_token);\n            while (tok != nullptr)\n            {\n                tokens.push_back(tok);\n                tok = pal::strtok(0, seperators, &next_token);\n            }\n\n            for (size_t iToken = 0; iToken < tokens.size(); iToken++)\n            {\n                if (logToFile)\n                {\n                    LogToFile(tokens[iToken].c_str());\n                }\n                else\n                {\n                    LogToScreen(tokens[iToken].c_str());\n                }\n            }\n            Data()->m_catMessage = \"\";\n        }\n    }\n}\n\n#if HC_PLATFORM == HC_PLATFORM_IOS\nvoid SetupAPNSRegistrationToken(std::string registrationToken)\n{\n    Data()->apnsToken = registrationToken;\n}\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\nvoid SetupAndroidContext( JavaVM *javaVM, jobject context, jclass mainActivityClass, jobject mainActivityInstance, jmethodID getApplicationContext)\n{\n    Data()->javaVM = javaVM;\n    Data()->m_mainActivityClass = mainActivityClass;\n    Data()->m_getApplicationContext = getApplicationContext;\n    Data()->m_mainActivityClassInstance = mainActivityInstance;\n    Data()->applicationContext = context;\n    Data()->initArgs = {};\n    Data()->initArgs.applicationContext = context;\n    Data()->initArgs.javaVM = javaVM;\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/log.cpp",
    "content": "#include \"pch.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 \n#include <shlobj.h>\n#endif\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"pal.h\"\n#endif\n\n#include <stdio.h>\n\nstd::string g_logFilePath;\n\nvoid LogInit()\n{\n#if HC_PLATFORM == HC_PLATFORM_WIN32 \n    char path[MAX_PATH + 1] = {0};\n    SHGetFolderPathA(NULL, CSIDL_DESKTOP, NULL, 0, path);\n    g_logFilePath = path;\n    g_logFilePath += \"\\\\\";\n#endif\n#if HC_PLATFORM == HC_PLATFORM_UWP\n    Platform::String^ localfolder = Windows::Storage::ApplicationData::Current->LocalFolder->Path;\t//for local saving for future\n\n    //convert folder name from wchar to ascii\n    std::wstring folderNameW(localfolder->Begin());\n    std::string folderNameA(folderNameW.begin(), folderNameW.end());\n    g_logFilePath = folderNameA;\n    g_logFilePath += \"\\\\\";\n#endif\n\n    g_logFilePath += \"apirunner-log.txt\";\n    if (!g_logFilePath.empty())\n    {\n        std::remove(g_logFilePath.c_str()); // erase existing file\n    }\n}\n\nvoid LogToFile(_Printf_format_string_ char const* format, ...)\n{\n    char message[4096] = {};\n    va_list varArgs{};\n    va_start(varArgs, format);\n    pal::vsprintf(message, 4096, format, varArgs);\n    va_end(varArgs);\n\n    if (!g_logFilePath.empty())\n    {\n        std::ofstream file{ g_logFilePath.c_str(), std::ios::app };\n        if (file.is_open())\n        {\n            file << message << std::endl;\n            file.close();\n        }\n    }\n\n#if HC_PLATFORM_IS_MICROSOFT\n    OutputDebugStringA(message);\n    OutputDebugStringA(\"\\r\\n\");\n#endif\n}\n\n#if HC_PLATFORM != HC_PLATFORM_UWP && HC_PLATFORM != HC_PLATFORM_WIN32 && HC_PLATFORM != HC_PLATFORM_GDK && HC_PLATFORM != HC_PLATFORM_XDK && HC_PLATFORM != HC_PLATFORM_IOS && HC_PLATFORM != HC_PLATFORM_ANDROID\n\nvoid LogToScreen(_Printf_format_string_ char const* format, ...)\n{\n    // Stock impl that just logs to file\n    // Hook up UI logs for each platform based on platform specific UI display calls\n\n    char message[8000] = {};\n\n    va_list varArgs{};\n    va_start(varArgs, format);\n    pal::vsprintf(message, 4096, format, varArgs);\n    va_end(varArgs);\n\n    LogToFile(message);\n}\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/lua-include.cpp",
    "content": "#define  _CRT_SECURE_NO_WARNINGS\n#include \"pch.h\"\n\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning (push)\n#pragma warning(disable : 4334)\n#pragma warning(disable : 4365)\n#pragma warning(disable : 4242)\n#pragma warning(disable : 4061)\n#pragma warning(disable : 4191)\n#pragma warning(disable : 4310)\n#endif\n\n#include \"lapi.c\"\n#include \"lauxlib.c\"\n#include \"lbaselib.c\"\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#include \"lbitlib.c\"\n#endif\n#include \"lcode.c\"\n#include \"lcorolib.c\"\n#include \"lctype.c\"\n#include \"ldblib.c\"\n#include \"ldebug.c\"\n#include \"ldo.c\"\n#include \"ldump.c\"\n#include \"lfunc.c\"\n#include \"lgc.c\"\n#include \"linit.c\"\n#include \"liolib.c\"\n#include \"llex.c\"\n#include \"lmathlib.c\"\n#include \"lmem.c\"\n#include \"loadlib.c\"\n#include \"lobject.c\"\n#include \"lopcodes.c\"\n#include \"loslib.c\"\n#include \"lparser.c\"\n#include \"lstate.c\"\n#include \"lstring.c\"\n#include \"lstrlib.c\"\n#include \"ltable.c\"\n#include \"ltablib.c\"\n#include \"ltm.c\"\n#include \"lundump.c\"\n#include \"lutf8lib.c\"\n#include \"lvm.c\"\n#include \"lzio.c\"\n\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n#pragma warning (pop)\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/mem_hook.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"mem_hook.h\"\n\n#define TRACK_UNHOOKED_ALLOCS 1\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)\n#include <process.h>\n#include <iostream>\n#include <Windows.h>\n#include <DbgHelp.h>\n\n#define TRACE_MAX_STACK_FRAMES 1024\n#define TRACE_MAX_FUNCTION_NAME_LENGTH 1024\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"runner.h\"\n#endif\n\nApiRunerMemHook* g_mem = new ApiRunerMemHook();\nbool g_rawMemHookInitTracking{ false };\n\nApiRunerMemHook* GetApiRunnerMemHook()\n{\n    return g_mem;\n}\n\n_Ret_maybenull_ _Post_writable_byte_size_(size) void* STDAPIVCALLTYPE ApiRunnerMemManagerMemAlloc(_In_ size_t size, _In_ HCMemoryType)\n{\n    auto mem = GetApiRunnerMemHook();\n    return mem->AllocMem(size);\n}\n\nvoid STDAPIVCALLTYPE ApiRunnerMemManagerMemFree(_In_ _Post_invalid_ void* pointer, _In_ HCMemoryType)\n{\n    auto mem = GetApiRunnerMemHook();\n    mem->DeleteMem(pointer);\n}\n\n_Ret_maybenull_ _Post_writable_byte_size_(size) void* ApiRunnerMemManagerXalMemAlloc(size_t size, uint32_t)\n{\n    auto mem = GetApiRunnerMemHook();\n    return mem->AllocMem(size);\n}\n\nvoid ApiRunnerMemManagerXalMemFree(_In_ _Post_invalid_ void* pointer, uint32_t)\n{\n    auto mem = GetApiRunnerMemHook();\n    mem->DeleteMem(pointer);\n}\n\nbool ApiRunerMemHook::IsMemTrackingStarted()\n{\n    return m_startMemTracking && m_refCountInsideAlloc == 0;\n}\n\nApiRunerMemHook::ApiRunerMemHook()\n{\n    m_refCountInsideAlloc = 0;\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK\n    m_process = GetCurrentProcess();\n    SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEBUG | SYMOPT_DEFERRED_LOADS | SYMOPT_CASE_INSENSITIVE);\n    SymInitialize(m_process, NULL, TRUE);\n#endif\n}\n\nHRESULT ApiRunerMemHook::StartMemTracking()\n{\n    if (m_startMemTracking)\n        return S_OK;\n\n    // libHttpClient hooks does not need to be called if XBL or XAL is hooked but for extra insurance during tests\n    HRESULT hr = HCMemSetFunctions(&ApiRunnerMemManagerXalMemAlloc, &ApiRunnerMemManagerXalMemFree);\n    assert(SUCCEEDED(hr));\n    if (FAILED(hr))\n        return hr;\n\n    hr = XblMemSetFunctions(&ApiRunnerMemManagerMemAlloc, &ApiRunnerMemManagerMemFree);\n    assert(SUCCEEDED(hr));\n    if (FAILED(hr))\n        return hr;\n\n    ResetStats();\n\n    m_startMemTracking = true;\n    g_rawMemHookInitTracking = true;\n\n    return S_OK;\n}\n\n\nHRESULT ApiRunerMemHook::StopMemTracking()\n{\n    if (!m_startMemTracking)\n        return S_OK;\n\n    HRESULT hr = HCMemSetFunctions(nullptr, nullptr);\n    assert(SUCCEEDED(hr));\n    if (FAILED(hr))\n        return hr;\n\n    hr = XblMemSetFunctions(nullptr, nullptr);\n    assert(SUCCEEDED(hr));\n    if (FAILED(hr))\n        return hr;\n\n    m_startMemTracking = false;\n    g_rawMemHookInitTracking = false;\n\n    return S_OK;\n}\n\n\nstd::vector<std::string> ApiRunerMemHook::GetStackLogLine()\n{\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK\n    StackInfo stackInfo{ 0 };\n    GetStackTrace(stackInfo);\n\n    std::vector<std::string> logs;\n    logs.reserve(static_cast<size_t>(stackInfo.stackSize));\n    for (int i = 0; i < stackInfo.stackSize; i++)\n    {\n        char sz[1024];\n        if (stackInfo.szStack[i][0] != 0)\n        {\n            sprintf_s(sz, \"%.32s in %s: line: %lu\", stackInfo.szStack[i], stackInfo.szFileNames[i], stackInfo.lineNumber[i]);\n        }\n\n        logs.push_back(sz);\n    }\n    return logs;\n#else\n    return std::vector<std::string>();\n#endif\n}\n\nvoid ApiRunerMemHook::AssertOnAllocOfId(uint64_t id)\n{\n    m_assertId = id;\n}\n\nvoid* ApiRunerMemHook::AllocMem(_In_ size_t size)\n{\n#if TRACK_UNHOOKED_ALLOCS == 1\n    m_refCountInsideAlloc++;\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n#endif\n\n    void* ptr = malloc(size);\n\n#if TRACK_UNHOOKED_ALLOCS == 1\n    m_allocSizeMap[ptr] = size;\n    m_allocated += size;\n    m_allocId++;\n    m_allocIdMap[ptr] = m_allocId;\n\n    if (m_allocId == m_assertId)\n    {\n        LogToFile(\"Breakpoint here\");\n    }\n\n    m_mapStackLog[ptr] = GetStackLogLine();\n    m_refCountInsideAlloc--;\n#endif\n\n    return ptr;\n}\n\n\nbool ApiRunerMemHook::IsMemHooked(void* p)\n{\n#if TRACK_UNHOOKED_ALLOCS == 1\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n    auto it = m_allocSizeMap.find(p);\n    return (it != m_allocSizeMap.end());\n#else\n    return false;\n#endif\n}\n\nvoid ApiRunerMemHook::DeleteMem(_In_ _Post_invalid_ void* pointer)\n{\n#if TRACK_UNHOOKED_ALLOCS == 1\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n    uint64_t size = 0;\n    auto it = m_allocSizeMap.find(pointer);\n    if (it != m_allocSizeMap.end())\n    {\n        size = it->second;\n        m_allocSizeMap.erase(it);\n    }\n    else\n    {\n       // assert(false);\n        // Add the following ifdef above line 53 in internal_mem.h \n        // if this assertion is reached. This will help track down what process\n        // is being freed incorrectly.\n#if 0\n        static int s_id = 0;\n        std::wstringstream msg;\n        msg << L\"s_id:\" << s_id << L\" p: 0x\" << std::hex << p << \"\\n\";\n        OutputDebugString(msg.str().c_str());\n        s_id++;\n#endif\n    }\n    m_allocDeleted += size;\n#endif\n\n    free(pointer);\n}\n\nvoid ApiRunerMemHook::ResetStats()\n{\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n    m_allocated = 0;\n    m_allocDeleted = 0;\n    m_allocId = 0;\n    m_allocSizeMap.clear();\n    m_mapStackLog.clear();\n}\n\nvoid MemHookLog(_Printf_format_string_ char const* format, ...)\n{\n    // Stock impl that just logs to file\n    // Hook up UI logs for each platform based on platform specific UI display calls\n\n#if HC_PLATFORM_IS_MICROSOFT\n    char message[8000] = {};\n\n    va_list varArgs{};\n    va_start(varArgs, format);\n    pal::vsprintf(message, 4096, format, varArgs);\n    va_end(varArgs);\n\n    OutputDebugStringA(message);\n    OutputDebugStringA(\"\\n\");\n#else\n    UNREFERENCED_PARAMETER(format);\n#endif\n}\n\nvoid ApiRunerMemHook::LogLeaks()\n{\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n    LogToScreen(\"Leaks: %d mem leaks found\", m_allocSizeMap.size());\n\n    // Using MemHookLog since long LogToScreen lines can causes mem allocations and thus doesn't work well in this module\n    MemHookLog(\"Leaks: -- START --\");\n    for (auto& it : m_allocSizeMap)\n    {\n        void* ptr = it.first;\n        uint64_t size = it.second;\n        auto& stackLog = m_mapStackLog[ptr];\n        auto& id = m_allocIdMap[ptr];\n        if (stackLog.size() >= 4)\n            MemHookLog(\"[%d] %0.8x: %d from %s\", id, ptr, size, stackLog[4].c_str());\n        else\n            MemHookLog(\"[%d] %0.8x: %d\", id, ptr, size);\n    }\n    MemHookLog(\"Leaks: -- END --\");\n\n    MemHookLog(\"== Leak CSV Start ==\");\n    for (auto& it : m_allocSizeMap)\n    {\n        void* ptr = it.first;\n        uint64_t size = it.second;\n        auto& stackLog = m_mapStackLog[ptr];\n        auto& id = m_allocIdMap[ptr];\n        int stackLineId{ 0 };\n        for (auto& stackLine : stackLog)\n        {\n            stackLineId++;\n            MemHookLog(\"%d,%0.8x,%d,%d,%s\", id, ptr, size, stackLineId, stackLine.c_str());\n        }\n    }\n    MemHookLog(\"== Leak CSV End ==\");\n\n}\n\nvoid ApiRunerMemHook::LogStats(const std::string& name)\n{\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n    MemHookLog(\"%s mem: %u outstanding alloc, (%u total / %u deleted)\", name.c_str(), m_allocated - m_allocDeleted, m_allocated, m_allocDeleted);\n}\n\n// IsStackInsideCallback() needs non-allocating case insenstive string compare so using manual impl\nchar* stristr(const char* str1, const char* str2)\n{\n    const char* p1 = str1;\n    const char* p2 = str2;\n    const char* r = *p2 == 0 ? str1 : 0;\n\n    while (*p1 != 0 && *p2 != 0)\n    {\n        if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2))\n        {\n            if (r == 0)\n            {\n                r = p1;\n            }\n\n            p2++;\n        }\n        else\n        {\n            p2 = str2;\n            if (r != 0)\n            {\n                p1 = r + 1;\n            }\n\n            if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2))\n            {\n                r = p1;\n                p2++;\n            }\n            else\n            {\n                r = 0;\n            }\n        }\n\n        p1++;\n    }\n\n    return *p2 == 0 ? (char*)r : 0;\n}\n\nbool ApiRunerMemHook::IsStackInsideCallback(const char* stackSymbolName, const char* filePath)\n{\n    const char* found;\n\n    found = stristr(stackSymbolName, \"ExampleWebsocketMessageReceived\");\n    if (found != nullptr)\n        return true;\n    found = stristr(stackSymbolName, \"ExampleWebsocketClosed\");\n    if (found != nullptr)\n        return true;\n    found = stristr(stackSymbolName, \"WaitForTestResult\");\n    if (found != nullptr)\n        return true;\n    found = stristr(filePath, \"\\\\Include\\\\xsapi-cpp\\\\\");\n    if (found != nullptr)\n        return true;\n    found = stristr(stackSymbolName, \"<lambda\");\n    if (found != nullptr)\n    {\n        found = stristr(filePath, \"\\\\apiexplorer\\\\\");\n        if (found != nullptr)\n            return true;\n        found = stristr(filePath, \"apis_xblc_social_manager.cpp\");\n        if (found != nullptr)\n            return true;\n    }\n\n    return false;\n}\n\nbool ApiRunerMemHook::IsFilePathInXSAPI(const char* filePath)\n{\n    const char* found = stristr(filePath, \"ource\\\\\");\n    if (found != nullptr)\n    {\n        found = stristr(filePath, \"\\\\Source\\\\Services\\\\\");\n        if (found != nullptr)\n            return true;\n        found = stristr(filePath, \"\\\\Source\\\\Shared\\\\\");\n        if (found != nullptr)\n            return true;\n        found = stristr(filePath, \"\\\\Source\\\\System\\\\\");\n        if (found != nullptr)\n            return true;\n        found = stristr(filePath, \"\\\\libhttpclient\\\\source\\\\\");\n        if (found != nullptr)\n        {\n            found = stristr(filePath, \"\\\\libhttpclient\\\\source\\\\global\\\\mem.cpp\");\n            if (found == nullptr)\n            {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid ApiRunerMemHook::LogUnhookedStats()\n{\n    g_rawMemHookInitTracking = false;\n    LogToScreen(\"%d memory unhooked in XSAPI and libHttpClient across %d alloc calls\", m_rawAllocMemory, m_rawAllocMemorySpots);\n    std::vector<std::string> list;\n    for (int i = 0; i < m_rawAllocMemorySpots; i++)\n    {\n        std::stringstream msg;\n        msg << m_allocTrace[i] << \"(\" << m_allocTraceLine[i] << \")\";\n        list.push_back(msg.str());\n    }\n\n    std::sort(list.begin(), list.end());\n    list.erase(std::unique(list.begin(), list.end()), list.end());\n\n    for(std::string s : list)\n    {\n        LogToScreen(s.c_str());\n    }\n    g_rawMemHookInitTracking = true;\n}\n\nbool ApiRunerMemHook::IsStackInXSAPI(StackInfo& stackInfo)\n{\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)\n    GetStackTrace(stackInfo);\n\n    bool foundInXsapi = false;\n    for (int i = 0; i < stackInfo.stackSize; i++)\n    {\n        stackInfo.isInXsapi[i] = IsFilePathInXSAPI(stackInfo.szFileNames[i]);\n        if (stackInfo.isInXsapi[i])\n        {\n            foundInXsapi = true;\n        }\n    }\n\n    if (foundInXsapi)\n    {\n        bool foundCallback = IsStackFramesInsideCallback(&stackInfo);\n        if (foundCallback)\n        {\n            return false;\n        }\n\n        bool foundTestCodeFirst = IsStackFramesInsideTestCode(&stackInfo);\n        if (foundTestCodeFirst)\n        {\n            return false;\n        }\n\n        return true;\n    }\n#else\n    UNREFERENCED_PARAMETER(stackInfo);\n#endif\n\n    return false;\n}\n\nvoid ApiRunerMemHook::GetStackTrace(StackInfo &stackInfo)\n{\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)\n    std::lock_guard<std::recursive_mutex> guard(m_lock);\n    void* stack[TRACE_MAX_STACK_FRAMES] = { 0 };\n    WORD numberOfFrames = CaptureStackBackTrace(0, TRACE_MAX_STACK_FRAMES, stack, NULL);\n    stackInfo.stackSize = numberOfFrames < 64 ? numberOfFrames : 64;\n    for (int i = 0; i < stackInfo.stackSize; i++)\n    {\n        stackInfo.szFileNames[i][0] = 0;\n        stackInfo.szStack[i][0] = 0;\n        stackInfo.lineNumber[i] = 0;\n        DWORD64 address = (DWORD64)(stack[i]);\n\n        char buffer[sizeof(SYMBOL_INFO) + TRACE_MAX_FUNCTION_NAME_LENGTH * sizeof(CHAR)] = { 0 };\n        PSYMBOL_INFO symbolInfo = (PSYMBOL_INFO)buffer;\n        symbolInfo->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH - 1;\n        symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO);\n        SymFromAddr(m_process, address, NULL, symbolInfo);\n\n        DWORD displacement;\n        char line64Buffer[sizeof(IMAGEHLP_LINE64)] = { 0 };\n        IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64*)line64Buffer;\n        line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);\n\n        if (SymGetLineFromAddr64(m_process, address, &displacement, line))\n        {\n#if HC_PLATFORM_IS_MICROSOFT\n            strcpy_s(stackInfo.szFileNames[i], line->FileName);\n            strcpy_s(stackInfo.szStack[i], symbolInfo->Name);\n#else\n            strcpy(stackInfo.szFileNames[i], line->FileName);\n            strcpy(stackInfo.szStack[i], symbolInfo->Name);\n#endif\n            stackInfo.lineNumber[i] = line->LineNumber;\n        }\n    }\n#else\n    memset(&stackInfo, 0, sizeof(StackInfo));\n#endif\n}\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX)\nbool ApiRunerMemHook::IsStackFramesInsideTestCode(StackInfo* pStackInfo)\n{\n    for (int i = 0; i < pStackInfo->stackSize; i++)\n    {\n        if (pStackInfo->isInXsapi[i])\n            return false;\n\n        const char* found = stristr(pStackInfo->szFileNames[i], \"\\\\apiexplorer\\\\\");\n        if (found != nullptr)\n            return true;\n    }\n    return false;\n}\n\nbool ApiRunerMemHook::IsStackFramesInsideCallback(StackInfo* pStackInfo)\n{\n    for (int i = 0; i < pStackInfo->stackSize; i++)\n    {\n        if (IsStackInsideCallback(pStackInfo->szStack[i], pStackInfo->szFileNames[i]))\n        {\n            return true;\n        }\n    }\n    return false;\n}\n#endif\n\n#if TRACK_UNHOOKED_ALLOCS == 1\nusing namespace std;\nvoid* operator new(size_t size)\n{\n    if (g_rawMemHookInitTracking)\n    {\n        auto mem = GetApiRunnerMemHook();\n        if (mem->IsMemTrackingStarted())\n        {\n            StackInfo stackInfo{ 0 };\n            bool isInXSAPI = mem->IsStackInXSAPI(stackInfo);\n            if (isInXSAPI)\n            {\n                for (int i = 0; i < stackInfo.stackSize; i++)\n                {\n                    if (stackInfo.isInXsapi[i])\n                    {\n#if HC_PLATFORM_IS_MICROSOFT\n                        strcpy_s(mem->m_allocTrace[mem->m_rawAllocMemorySpots], stackInfo.szFileNames[i]);\n#else\n                        strcpy(mem->m_allocTrace[mem->m_rawAllocMemorySpots], stackInfo.szFileNames[i]);\n#endif\n                        mem->m_allocTraceLine[mem->m_rawAllocMemorySpots] = stackInfo.lineNumber[i];\n                        break;\n                    }\n                }\n\n                mem->m_rawAllocMemory += size;\n                mem->m_rawAllocMemorySpots++;\n                if (mem->m_rawAllocMemorySpots >= APIRUNNER_MAX_UNHOOKED_MEM_TRACKED)\n                {\n                    mem->m_rawAllocMemorySpots = APIRUNNER_MAX_UNHOOKED_MEM_TRACKED - 1;\n                }\n            }\n        }\n    }\n\n    void* p = malloc(size);\n    return p;\n}\n\nvoid operator delete(void * p)\n{\n    if (g_rawMemHookInitTracking)\n    {\n        auto mem = GetApiRunnerMemHook();\n        if (mem->IsMemHooked(p))\n        {\n            // This shouldn't be mem hooked\n            assert(false);\n        }\n    }\n\n    free(p);\n}\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/mem_hook.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n#include \"pch.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK\n#include <DbgHelp.h>\n#endif\n\nstruct StackInfo\n{\n    int stackSize;\n    bool isInXsapi[64];\n    DWORD lineNumber[64];\n    char szFileNames[64][1024];\n    char szStack[64][1024];\n};\n\n#define APIRUNNER_MAX_UNHOOKED_MEM_TRACKED 1024 \nclass ApiRunerMemHook\n{\npublic:\n    ApiRunerMemHook();\n\n    HRESULT StartMemTracking();\n    HRESULT StopMemTracking();\n\n    bool IsMemTrackingStarted();\n    void ResetStats();\n    void LogStats(const std::string& name);\n    void LogLeaks();\n    void AssertOnAllocOfId(uint64_t id);\n\n    _Ret_maybenull_ _Post_writable_byte_size_(size) void* AllocMem(_In_ size_t size);\n    void DeleteMem(_In_ _Post_invalid_ void* pointer);\n    std::vector<std::string> GetStackLogLine();\n\n    bool IsStackInXSAPI(StackInfo& stackInfo);\n    bool IsMemHooked(void* p);\n    void GetStackTrace(StackInfo &stackInfo);\n\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK\n    bool IsStackFramesInsideTestCode(StackInfo* pStackInfo);\n    bool IsStackFramesInsideCallback(StackInfo* pStackInfo);\n#endif\n\n    bool IsFilePathInXSAPI(const char* filePath);\n    bool IsStackInsideCallback(const char* stackSymbolName, const char* filePath);\n    void LogUnhookedStats();\n    uint64_t m_rawAllocMemory{ 0 };\n    uint64_t m_rawAllocMemorySpots{ 0 };\n    char m_allocTrace[APIRUNNER_MAX_UNHOOKED_MEM_TRACKED][1024] { 0 };\n    unsigned long m_allocTraceLine[APIRUNNER_MAX_UNHOOKED_MEM_TRACKED] { 0 };\n\nprivate:\n#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK\n    HANDLE m_process{ nullptr };\n#endif\n    bool m_startMemTracking{ false };\n    uint64_t m_allocated{ 0 };\n    uint64_t m_allocDeleted{ 0 };\n    uint64_t m_unhookedAllocated{ 0 };\n    uint64_t m_unhookedDeleted{ 0 };\n    uint64_t m_allocId{ 0 };\n    uint64_t m_assertId{ 0 };\n    std::recursive_mutex m_lock;\n    std::map< void*, uint64_t > m_allocSizeMap;\n    std::map< void*, uint64_t > m_allocIdMap;\n    std::map< void*, std::vector<std::string> > m_mapStackLog;\n    std::atomic<int> m_refCountInsideAlloc;\n};\n\nApiRunerMemHook* GetApiRunnerMemHook();\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/multidevice.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 4365 )\n#pragma warning( disable : 4061 )\n#pragma warning( disable : 4996 )\n#endif\n#include \"rapidjson/document.h\"\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include <thread>\n#include \"multidevice.h\"\n#include \"api_explorer.h\"\n#include \"runner.h\"\n#include \"pal.h\"\n#endif\n#if __has_include(\"apirunnercloudfns.h\")\n#include \"apirunnercloudfns.h\"\n#else\n#define APIRUNNER_GET_JOINABLE \"\"\n#define APIRUNNER_HOST_SESSION \"\"\n#define APIRUNNER_JOIN_SESSION \"\"\n#define APIRUNNER_SET_STATE \"\"\n#define APIRUNNER_GET_STATE \"\"\n#endif\n\n#define RETURN_HR_IF_FAILED(expr) { HRESULT exprResult{ expr }; if (FAILED(exprResult)) { return exprResult; } }\n\n#if HC_PLATFORM_IS_MICROSOFT\n    #define SPRINTF_XPLAT sprintf_s\n#else\n    #define SPRINTF_XPLAT sprintf\n#endif\n\nusing namespace utility;\n\nstatic std::thread s_watchThread{};\n\nApiRunnerMultiDeviceManager::~ApiRunnerMultiDeviceManager()\n{\n    // TODO: add back when HC init and cleanup is ref counted\n    //if (m_isHCInitialized)\n    //{\n    //    HCCleanup();\n    //}\n}\n\nstd::string ExtractJsonString(\n    _In_ const rapidjson::Document& jsonDoc,\n    _In_ const std::string& stringName)\n{\n    if (jsonDoc.IsObject() && jsonDoc.HasMember(stringName.c_str()))\n    {\n        const rapidjson::Value& field = jsonDoc[stringName.c_str()];\n        if (field.IsString())\n        {\n            return field.GetString();\n        }\n    }\n\n    return \"\";\n}\n\nHRESULT ApiRunnerMultiDeviceManager::JoinOpenSession(\n    _In_ const std::string& name,\n    _In_ const std::string& xuid,\n    _In_ const std::string& gamertag,\n    _In_ std::function<void(HRESULT hr)> handler)\n{\n    auto manager = Data()->m_multiDeviceManager;\n    manager->m_nextCallTime = datetime::utc_now() - datetime::from_seconds(1);\n    manager->m_callGetJoinable = true;\n    LogToScreen(\"MultiDevice: Looking for test session to join...\");\n    while (!manager->Joined())\n    {\n        int64_t delta = static_cast<int64_t>(manager->m_nextCallTime.to_interval()) - static_cast<int64_t>(datetime::utc_now().to_interval());\n        if (delta < 0 && manager->m_callGetJoinable)\n        {\n            manager->m_callGetJoinable = false;\n            manager->GetJoinable(\n                name,\n                [xuid, gamertag, handler](HRESULT, uint32_t, const std::string& joinableSessionId, const std::string& client1xuid, const std::string& client1gt)\n                {\n                    auto manager = Data()->m_multiDeviceManager;\n                    if (!joinableSessionId.empty() && !xuid.empty() && !client1gt.empty())\n                    {\n                        LogToScreen(\"MultiDevice: Found test session: %s\", joinableSessionId.c_str());\n                        LogToScreen(\"MultiDevice: Remote XUID: %s GamerTag: %s\", client1xuid.c_str(), client1gt.c_str());\n                        manager->JoinSession(joinableSessionId, xuid, gamertag, \n                            [handler](HRESULT hr) \n                            {\n                                if (SUCCEEDED(hr))\n                                {\n                                    handler(hr);\n                                }\n                                else\n                                {\n                                    auto manager = Data()->m_multiDeviceManager;\n                                    manager->m_nextCallTime = datetime::utc_now() + datetime::from_seconds(1);\n                                    manager->m_callGetJoinable = true;\n                                }\n                            });\n                    }\n                    else\n                    {\n                        manager->m_nextCallTime = datetime::utc_now() + datetime::from_seconds(1);\n                        manager->m_callGetJoinable = true;\n                    }\n                });\n        }\n\n        pal::Sleep(100);\n    }\n\n    return S_OK;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::GetJoinable(\n    _In_ const std::string& name,\n    _In_ std::function<void(HRESULT hr, uint32_t statusCode, const std::string& joinableSessionId, const std::string& xuid, const std::string& gt)> handler\n)\n{\n    std::vector<std::vector<std::string>> headers;\n    headers.push_back(std::vector<std::string>{\"name\", name});\n    HRESULT hr = MakeCall(\"GET\", APIRUNNER_GET_JOINABLE, headers,\n        [handler](HRESULT hr, uint32_t statusCode, const std::string& responseString)\n        {\n            std::string sessionId;\n            std::string xuid;\n            std::string gt;\n\n            if (SUCCEEDED(hr) && statusCode == 200 && responseString.length() > 0)\n            {\n                rapidjson::Document jsonDoc;\n                jsonDoc.Parse(responseString.c_str());\n                if (!jsonDoc.HasParseError())\n                {\n                    // Example response:\n                    //{\n                    //    \"id\": \"637123016212526708\",\n                    //    \"client1xuid\" : \"123\",\n                    //    \"client1gt\" : \"ninja\",\n                    //    \"client2xuid\" : null,\n                    //    \"client2gt\" : null,\n                    //    \"props\" : null\n                    //}\n\n                    sessionId = ExtractJsonString(jsonDoc, \"id\");\n                    xuid = ExtractJsonString(jsonDoc, \"client1xuid\");\n                    gt = ExtractJsonString(jsonDoc, \"client1gt\");\n                }\n            }\n\n            auto manager = Data()->m_multiDeviceManager;\n            manager->m_isInitialized = true;\n            if (handler)\n            {\n                handler(hr, statusCode, sessionId, xuid, gt);\n            }\n        });\n    if (FAILED(hr))\n    {\n        LogToScreen(\"MultiDevice: Get joinable test session failed %0.8x\", hr);\n    }\n    return hr;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::Init(\n    _In_ std::function<void(const std::string& key, const std::string& value)> onStateChangedHandler\n    )\n{\n    m_doPoll = false;\n    m_onStateChangedHandler = std::move(onStateChangedHandler);\n\n    RETURN_HR_IF_FAILED(HCInitialize(nullptr));\n    m_isHCInitialized = true;\n\n    return S_OK;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::WaitTillPeerConnects()\n{\n    auto manager = Data()->m_multiDeviceManager;\n    manager->m_nextCallTime = datetime::utc_now() - datetime::from_seconds(1);\n    manager->m_callGetJoinable = true;\n    std::string curSessionId = manager->m_sessionId;\n    std::string name = manager->m_sessionName;\n    LogToScreen(\"MultiDevice: Waiting for peer to connect to test session...\");\n    while (!manager->Joined())\n    {\n        int64_t delta = static_cast<int64_t>(manager->m_nextCallTime.to_interval()) - static_cast<int64_t>(datetime::utc_now().to_interval());\n        if (delta < 0)\n        {\n            manager->m_nextCallTime = datetime::utc_now() + datetime::from_seconds(1);\n            std::string state = manager->GetSessionStateString();\n            if (state.length() > 0)\n            {\n                rapidjson::Document jsonDoc;\n                jsonDoc.Parse(state.c_str());\n                if (!jsonDoc.HasParseError())\n                {\n                    std::string client2xuid = ExtractJsonString(jsonDoc, \"client2xuid\");\n                    if (!client2xuid.empty())\n                    {\n                        std::string client2gt = ExtractJsonString(jsonDoc, \"client2gt\");\n                        LogToScreen(\"MultiDevice: Connected to peer XUID: %s GamerTag: %s...\", client2xuid.c_str(), client2gt.c_str());\n                        manager->m_isJoined = true;\n                    }\n                }\n            }\n        }\n\n        pal::Sleep(100);\n    }\n\n    if (manager->Abort())\n    {\n        return E_ABORT;\n    }\n    return S_OK;\n}\n\nuint64_t ApiRunnerMultiDeviceManager::GetLocalXuid()\n{\n    std::string xuid = IsHost() ? m_state.client1xuid : m_state.client2xuid;\n    return strtoull(xuid.c_str(), nullptr, 0);\n}\n\nuint64_t ApiRunnerMultiDeviceManager::GetRemoteXuid()\n{\n    std::string xuid = IsHost() ? m_state.client2xuid : m_state.client1xuid;\n    return strtoull(xuid.c_str(), nullptr, 0);\n}\n\nHRESULT ApiRunnerMultiDeviceManager::HostSession(\n    _In_ const std::string& name,\n    _In_ const std::string& xuid,\n    _In_ const std::string& gamertag,\n    _In_ std::function<void(HRESULT)> onResponse)\n{\n    LogToScreen(\"MultiDevice: Hosting test session as XUID: %s GamerTag: %s...\", xuid.c_str(), gamertag.c_str());\n    std::vector<std::vector<std::string>> headers;\n    headers.push_back(std::vector<std::string>{\"name\", name});\n    headers.push_back(std::vector<std::string>{\"xuid\", xuid});\n    headers.push_back(std::vector<std::string>{\"gt\", gamertag});\n    HRESULT hr = MakeCall(\"POST\", APIRUNNER_HOST_SESSION, headers,\n        [onResponse, name](HRESULT hr, uint32_t statusCode, const std::string& responseString)\n        {\n            auto manager = Data()->m_multiDeviceManager;\n            if (SUCCEEDED(hr) && statusCode == 200 && responseString.length() > 0)\n            {\n                rapidjson::Document jsonDoc;\n                jsonDoc.Parse(responseString.c_str());\n                if (!jsonDoc.HasParseError())\n                {\n                    // Example response:\n                    //{\n                    //    \"id\": \"637123065073534386\",\n                    //    \"client1xuid\" : \"123\",\n                    //    \"client1gt\" : \"ninja\",\n                    //    \"log\" : \"Deleted: 1\"\n                    //}\n\n                    {\n                        std::lock_guard<std::mutex> lock(manager->m_mutex);\n                        manager->m_sessionId = ExtractJsonString(jsonDoc, \"id\");\n                        manager->m_sessionState = responseString;\n                        manager->m_sessionName = name;\n                        manager->m_hosted = true;\n                        LogToScreen(\"MultiDevice: Hosted test session %s\", manager->m_sessionId.c_str());\n                    }\n                    manager->StartSessionStateChangePolling();\n                    if (onResponse)\n                    {\n                        onResponse(S_OK);\n                    }\n                }\n            }\n            else \n            {\n                LogToScreen(\"MultiDevice: Hosting test session failed. 0x%0.8x. HTTP status: %d\", hr, statusCode);\n                if (onResponse)\n                {\n                    onResponse(E_FAIL);\n                }\n            }\n        });\n    if (FAILED(hr))\n    {\n        LogToScreen(\"MultiDevice: Hosting test session failed %0.8x\", hr);\n        if (onResponse)\n        {\n            onResponse(hr);\n        }\n    }\n    return hr;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::JoinSession(\n    _In_ const std::string& sessionId,\n    _In_ const std::string& xuid,\n    _In_ const std::string& gamertag,\n    _In_ std::function<void(HRESULT)> handler)\n{\n    std::vector<std::vector<std::string>> headers;\n    headers.push_back(std::vector<std::string>{\"id\", sessionId});\n    headers.push_back(std::vector<std::string>{\"xuid\", xuid});\n    headers.push_back(std::vector<std::string>{\"gt\", gamertag});\n    HRESULT hr = MakeCall(\"POST\", APIRUNNER_JOIN_SESSION, headers,\n        [handler](HRESULT hr, uint32_t statusCode, const std::string& responseString)\n        {\n            // Could return 409 if there's another client joined \n\n            auto manager = Data()->m_multiDeviceManager;\n            if (SUCCEEDED(hr) && statusCode == 200 && responseString.length() > 0)\n            {\n                rapidjson::Document jsonDoc;\n                jsonDoc.Parse(responseString.c_str());\n                if (!jsonDoc.HasParseError())\n                {\n                    // Example:\n                    //{\n                    //    \"id\": \"637123065073534386\",\n                    //    \"client1xuid\" : \"123\",\n                    //    \"client1gt\" : \"ninja\",\n                    //    \"client2xuid\" : \"456\",\n                    //    \"client2gt\" : \"karate\",\n                    //    \"props\" : null\n                    //}\n\n                    {\n                        std::lock_guard<std::mutex> lock(manager->m_mutex);\n                        manager->m_sessionId = ExtractJsonString(jsonDoc, \"id\");\n                        manager->m_sessionState = responseString;\n                        manager->m_sessionName = ExtractJsonString(jsonDoc, \"name\");\n                        LogToScreen(\"MultiDevice: Joining test session %s\", manager->m_sessionId.c_str());\n                        manager->StartSessionStateChangePolling();\n                        manager->m_isJoined = true;\n                        manager->m_hosted = false;\n                    }\n                    if (handler)\n                    {\n                        handler(S_OK);\n                    }\n                }\n            }\n\n            if (manager->m_sessionId.empty())\n            {\n                LogToScreen(\"MultiDevice: Joining test session failed. 0x%0.8x. HTTP status: %d\", hr, statusCode);\n                if (handler)\n                {\n                    handler(E_FAIL);\n                }\n            }\n        });\n    if (FAILED(hr))\n    {\n        LogToScreen(\"MultiDevice: Joining test session failed %0.8x\", hr);\n        if (handler)\n        {\n            handler(hr);\n        }\n    }\n\n    return hr;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::SetSessionState(\n    _In_ const std::string& key,\n    _In_ const std::string& value,\n    _In_ std::function<void(HRESULT)> /*handler*/)\n{\n    std::vector<std::vector<std::string>> headers;\n    if (value.length() == 0)\n    {\n        LogToScreen(\"MultiDevice: Deleting %s key in cloud DB\", key.c_str());\n    }\n    else\n    {\n        LogToScreen(\"MultiDevice: Setting %s key to %s in cloud DB\", key.c_str(), value.c_str());\n    }\n\n    headers.push_back(std::vector<std::string>{\"id\", m_sessionId});\n    headers.push_back(std::vector<std::string>{\"key\", key});\n    headers.push_back(std::vector<std::string>{\"value\", value});\n    HRESULT hr = MakeCall(\"POST\", APIRUNNER_SET_STATE, headers,\n        [](HRESULT hr, uint32_t statusCode, const std::string& responseString)\n        {\n            auto manager = Data()->m_multiDeviceManager;\n            if (SUCCEEDED(hr) && statusCode == 200 && responseString.length() > 0)\n            {\n                rapidjson::Document jsonDoc;\n                jsonDoc.Parse(responseString.c_str());\n                if (!jsonDoc.HasParseError())\n                {\n                    std::lock_guard<std::mutex> lock(manager->m_mutex);\n                    manager->m_sessionState = responseString;\n                }\n            }\n            else\n            {\n                LogToScreen(\"Set test session state failed %0.8x %d\", hr, statusCode);\n            }\n        });\n    if (FAILED(hr))\n    {\n        LogToScreen(\"Set test session state failed %0.8x\", hr);\n    }\n    return hr;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::StartSessionStateChangePolling()\n{\n    if (!m_doPoll)\n    {\n        LogToScreen(\"Watching test session for changes\");\n        m_doPoll = true;\n        s_watchThread = std::thread([]()\n            {\n                auto manager = Data()->m_multiDeviceManager;\n                while (manager->IsDoPoll())\n                {\n                    manager->RefreshSessionState();\n                    pal::Sleep(1000);\n                }\n                LogToScreen(\"Stopping watch thread\");\n            });\n    }\n    return S_OK;\n}\n\nHRESULT ApiRunnerMultiDeviceManager::StopSessionStateChangePolling()\n{\n    if (m_doPoll)\n    {\n        LogToScreen(\"Stopped watching for test session changes\");\n        m_doPoll = false;\n        s_watchThread.join();\n    }\n    return S_OK;\n}\n\n\nvoid ApiRunnerMultiDeviceManager::ParseState(const std::string& responseString)\n{\n    rapidjson::Document jsonDoc;\n    jsonDoc.Parse(responseString.c_str());\n\n    ServerState oldState;\n    {\n        std::lock_guard<std::mutex> lock(m_mutex);\n        oldState = std::move(m_state);\n\n        m_state.client1xuid = ExtractJsonString(jsonDoc, \"client1xuid\");\n        m_state.client1gt = ExtractJsonString(jsonDoc, \"client1gt\");\n        m_state.client2xuid = ExtractJsonString(jsonDoc, \"client2xuid\");\n        m_state.client2gt = ExtractJsonString(jsonDoc, \"client2gt\");\n        m_state.id = ExtractJsonString(jsonDoc, \"id\");\n    }\n\n    std::string props = ExtractJsonString(jsonDoc, \"props\");\n    rapidjson::Document jsonDocProps;\n    jsonDocProps.Parse(props.c_str());\n    if (!jsonDocProps.HasParseError())\n    {\n        for (auto& m : jsonDocProps.GetObject())\n        {\n            std::string key = m.name.GetString();\n            std::string value = m.value.GetString();\n            {\n                std::lock_guard<std::mutex> lock(m_mutex);\n                m_state.propmap[key] = value;\n            }\n\n            if (value != oldState.propmap[key])\n            {\n                m_onStateChangedHandler(key, value);\n            }\n        }\n    }\n}\n\nstd::string ApiRunnerMultiDeviceManager::GetStateValueFromKey(std::string key)\n{\n    std::lock_guard<std::mutex> lock(m_mutex);\n    return m_state.propmap[key];\n}\n\nHRESULT ApiRunnerMultiDeviceManager::RefreshSessionState()\n{\n    std::vector<std::vector<std::string>> headers;\n    headers.push_back(std::vector<std::string>{\"id\", m_sessionId});\n    HRESULT hr = MakeCall(\"GET\", APIRUNNER_GET_STATE, headers,\n        [](HRESULT hr, uint32_t statusCode, const std::string& responseString)\n        {\n            auto manager = Data()->m_multiDeviceManager;\n            if (SUCCEEDED(hr) && statusCode == 200 && responseString.length() > 0)\n            { \n                rapidjson::Document jsonDoc;\n                jsonDoc.Parse(responseString.c_str());\n                if (!jsonDoc.HasParseError())\n                {\n                    std::string oldState;\n                    {\n                        std::lock_guard<std::mutex> lock(manager->m_mutex);\n                        oldState = std::move(manager->m_sessionState);\n                        manager->m_sessionState = responseString;\n                    }\n                    if(oldState != responseString)\n                    {\n                        manager->ParseState(responseString);\n                    }\n                }\n            }\n            else\n            {\n                LogToScreen(\"Get test session state failed %0.8x %d\", hr, statusCode);\n            }\n        });\n    if (FAILED(hr))\n    {\n        LogToScreen(\"Get test session state failed %0.8x\", hr);\n    }\n    return hr;\n}\n\nclass HCCallHandleRAII\n{\npublic:\n    ~HCCallHandleRAII()\n    {\n        if (handle != nullptr)\n        {\n            HCHttpCallCloseHandle(handle);\n        }\n    }\n\n    HCCallHandle handle{ nullptr };\n};\n\nstruct ApiRunnerMultiDeviceManagerCallContext\n{\n    HCCallHandleRAII call;\n    std::function<void(HRESULT hr, uint32_t statusCode, const std::string& responseString)> handler;\n};\n\nHRESULT ApiRunnerMultiDeviceManager::MakeCall(\n    _In_ const std::string& method,\n    _In_ const std::string& url,\n    _In_ const std::vector<std::vector<std::string>>& headers,\n    _In_ std::function<void(HRESULT hr, uint32_t statusCode, const std::string& responseString)> handler)\n{\n    auto contextPtr = std::unique_ptr<ApiRunnerMultiDeviceManagerCallContext>(\n        new ApiRunnerMultiDeviceManagerCallContext{ nullptr, handler }\n    );\n\n    HRESULT hr = HCHttpCallCreate(&contextPtr->call.handle);\n    if (hr == E_HC_NOT_INITIALISED)\n    {\n        // TODO: remove when HC init/cleanup is ref counted\n        RETURN_HR_IF_FAILED(HCInitialize(nullptr));\n        RETURN_HR_IF_FAILED(HCHttpCallCreate(&contextPtr->call.handle));\n    }\n    RETURN_HR_IF_FAILED(HCHttpCallRequestSetUrl(contextPtr->call.handle, method.c_str(), url.c_str()));\n\n    for (auto& header : headers)\n    {\n        std::string headerName = header[0];\n        std::string headerValue = header[1];\n        RETURN_HR_IF_FAILED(HCHttpCallRequestSetHeader(contextPtr->call.handle, headerName.c_str(), headerValue.c_str(), true));\n    }\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->context = contextPtr.get();\n    XTaskQueueHandle queue = nullptr;\n    hr = XTaskQueueCreate(\n        XTaskQueueDispatchMode::ThreadPool,\n        XTaskQueueDispatchMode::ThreadPool,\n        &queue);\n    RETURN_HR_IF_FAILED(hr);\n    asyncBlock->queue = queue;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        std::string responseString;\n        uint32_t statusCode{ 0 };\n        HRESULT networkErrorCode{ S_OK };\n        uint32_t platErrCode{ 0 };\n\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*\n        std::unique_ptr<ApiRunnerMultiDeviceManagerCallContext> contextPtr{ static_cast<ApiRunnerMultiDeviceManagerCallContext*>(asyncBlock->context) };\n        HRESULT hr = XAsyncGetStatus(asyncBlock, false);\n        if (SUCCEEDED(hr))\n        {\n            hr = HCHttpCallResponseGetNetworkErrorCode(contextPtr->call.handle, &networkErrorCode, &platErrCode);\n            if (SUCCEEDED(hr))\n            {\n                hr = HCHttpCallResponseGetStatusCode(contextPtr->call.handle, &statusCode);\n                if (SUCCEEDED(hr))\n                {\n                    const char* response{ nullptr }; \n                    hr = HCHttpCallResponseGetResponseString(contextPtr->call.handle, &response);\n                    if (response != nullptr && SUCCEEDED(hr))\n                    {\n                        responseString = response; // ptr memory is only alive while call handle isn't closed, so copy to std::string\n                    }\n                }\n            }\n        }\n        if (FAILED(hr))\n        {\n            networkErrorCode = hr;\n        }\n\n        if (contextPtr->handler)\n        {\n            contextPtr->handler(networkErrorCode, statusCode, responseString);\n        }\n\n        // HCHttpCallCloseHandle will get called will context gets freed since it'll dtor HCCallHandleRAII\n    };\n\n    hr = HCHttpCallPerformAsync(contextPtr->call.handle, asyncBlock.get());\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n        contextPtr.release();\n    }\n\n    return hr;\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/pal.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\ntypedef unsigned char byte;\n#if !HC_PLATFORM_IS_MICROSOFT\ntypedef char CHAR;\ntypedef unsigned long DWORD;\n\nconstexpr auto sprintf_s = sprintf;\n\n#define MAX_PATH 260\n#define WINAPI\n#define LPVOID void*\n\n#ifndef UNREFERENCED_PARAMETER\n#define UNREFERENCED_PARAMETER(x)\n#endif\n\n#else // Windows Platforms\n\n#endif\n\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\ntypedef unsigned long DWORD, *PDWORD, *LPDWORD;\n#endif\n\n\nnamespace pal\n{\n    void strcpy(char * dst, size_t size, const char* src);\n    int stricmp(const char* left, const char* right);\n    int vsprintf(char* message, size_t size,char const* format, va_list varArgs);\n    char* strtok(char* str, char const* delimiter, char** context);\n\n    // Due to java not supporting unsigned numeric values, we have to do regular long on Android\n#if HC_PLATFORM != HC_PLATFORM_ANDROID\n    void Sleep(unsigned long duration);\n#else\n    void Sleep(long duration);\n#endif\n\n    bool FileExists(std::string fileName); // TODO might only be used on win32\n    std::vector<std::string> EnumFilesInFolder(std::string folder, std::string spec);\n    std::string FindFile(std::string fileName);\n    std::string GetLuaPath();\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n    std::string OpenFile(std::string filePath);\n#endif\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/pch_apicommon.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch_common.h\"\n#if HC_PLATFORM != HC_PLATFORM_IOS\n#include <rapidjson/allocators.hpp>\n#endif"
  },
  {
    "path": "Tests/ApiExplorer/Shared/pch_common.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"pch_common.h\"\n\n// APIRunner uses cpprestsdk and XSAPI lib doesn't on non-GDK platforms\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include \"cpprestsdk_impl.h\"\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/pch_common.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\n#ifdef _WIN32\n    #ifndef _WIN32_WINNT_WIN10\n    #define _WIN32_WINNT_WIN10 0x0A00\n    #endif\n#endif //#ifdef _WIN32\n\n#include <iostream>\n#include <vector>\n#include <assert.h>\n#include <httpClient/httpClient.h>\n#if HC_PLATFORM != HC_PLATFORM_UWP\n    #include <Xal/xal.h>\n    #if HC_PLATFORM != HC_PLATFORM_GDK\n    #include <Xal/xal_platform.h>\n    #endif\n#endif\n\n#include <stdlib.h>\n#include <map>\n#include <set>\n#include <string>\n#include <fstream>\n#include <mutex>\n#include <algorithm>\n#include <cctype>\n#include <sstream>\n#include <thread>\n#include <cinttypes>\n#include <unordered_map>\n\n#if HC_PLATFORM != HC_PLATFORM_IOS\n#include <xsapi-cpp/services.h>\n#endif\n\n#include <xsapi-c/services_c.h>\n\n#include \"pal.h\"\n#include \"utils.h\"\n#include \"mem_hook.h\"\n\n#include \"lua.h\"\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n\n#if XSAPI_BUILT_FROM_SOURCE\n#undef RAPIDJSON_NAMESPACE\n#undef RAPIDJSON_NAMESPACE_BEGIN\n#undef RAPIDJSON_NAMESPACE_END\n#endif\n#pragma warning( push )\n#pragma warning( disable : 4365 )\n#include \"../../../External/rapidjson/include/rapidjson/document.h\"\n#pragma warning( pop )\n\n#include \"../Include/multidevice.h\"\n#include \"../Include/api_explorer.h\"\n#include \"../Include/runner.h\"\n#include \"../APIs/apis.h\"\n\n#if HC_PLATFORM_IS_MICROSOFT\n    #define SPRINTF(buffer, size, format, ...) sprintf_s(buffer, size, format, __VA_ARGS__)\n#else\n    #define SPRINTF(buffer, size, format, ...) snprintf(buffer, size, format, __VA_ARGS__)\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/utils.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"utils.h\"\n\n#if HC_PLATFORM == HC_PLATFORM_ANDROID\n#include \"runner.h\"\n#include \"pal.h\"\n#include \"api_explorer.h\"\n#endif\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n#include <XGameErr.h>\n#endif\n\nHRESULT VerifyIsTrue(bool condition, const char* pszCondition)\n{\n    if (!condition)\n    {\n        LogToFile(\"Failure: \");\n        LogToFile(pszCondition);\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n#define RETURN_STRING_FROM_HR(e) case (e): return #e\n#pragma warning (push)\n#pragma warning (disable: 4061)\n\nstd::string ConvertHRtoString(HRESULT hr)\n{\n    switch (hr)\n    {\n        RETURN_STRING_FROM_HR(S_OK);\n        RETURN_STRING_FROM_HR(E_FAIL);\n        RETURN_STRING_FROM_HR(E_POINTER);\n        RETURN_STRING_FROM_HR(E_INVALIDARG);\n        RETURN_STRING_FROM_HR(E_OUTOFMEMORY);\n        RETURN_STRING_FROM_HR(E_NOT_SUFFICIENT_BUFFER);\n        RETURN_STRING_FROM_HR(E_NOT_SUPPORTED);\n        RETURN_STRING_FROM_HR(E_ABORT);\n        RETURN_STRING_FROM_HR(E_NOTIMPL);\n        RETURN_STRING_FROM_HR(E_ACCESSDENIED);\n        RETURN_STRING_FROM_HR(E_PENDING);\n        RETURN_STRING_FROM_HR(E_UNEXPECTED);\n        RETURN_STRING_FROM_HR(E_TIME_CRITICAL_THREAD);\n        RETURN_STRING_FROM_HR(E_NOINTERFACE);\n        RETURN_STRING_FROM_HR(E_BOUNDS);\n        RETURN_STRING_FROM_HR(E_NO_TASK_QUEUE);\n\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_AMBIGUOUS);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_BAD_GATEWAY);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_BAD_METHOD);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_BAD_REQUEST);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_CONFLICT);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_DENIED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_EXPECTATION_FAILED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_FORBIDDEN);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_GATEWAY_TIMEOUT);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_GONE);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_LENGTH_REQUIRED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_MOVED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_NONE_ACCEPTABLE);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_NOT_FOUND);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_NOT_MODIFIED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_NOT_SUPPORTED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_PAYMENT_REQ);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_PRECOND_FAILED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_PROXY_AUTH_REQ);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_RANGE_NOT_SATISFIABLE);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_REDIRECT);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_REDIRECT_KEEP_VERB);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_REDIRECT_METHOD);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_REQUEST_TIMEOUT);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_REQUEST_TOO_LARGE);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_SERVER_ERROR);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_SERVICE_UNAVAIL);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_UNEXPECTED);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_UNSUPPORTED_MEDIA);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_URI_TOO_LONG);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_USE_PROXY);\n        RETURN_STRING_FROM_HR(HTTP_E_STATUS_VERSION_NOT_SUP);\n        RETURN_STRING_FROM_HR(ONL_E_ACTION_REQUIRED);\n        RETURN_STRING_FROM_HR(WEB_E_INVALID_JSON_STRING);\n        RETURN_STRING_FROM_HR(WEB_E_UNEXPECTED_CONTENT);\n\n#if HC_PLATFORM != HC_PLATFORM_UWP\n        RETURN_STRING_FROM_HR(E_XAL_NOTINITIALIZED);\n        RETURN_STRING_FROM_HR(E_XAL_ALREADYINITIALIZED);\n        RETURN_STRING_FROM_HR(E_XAL_USERSETNOTEMPTY);\n        RETURN_STRING_FROM_HR(E_XAL_USERSETFULL);\n        RETURN_STRING_FROM_HR(E_XAL_USERSIGNEDOUT);\n        RETURN_STRING_FROM_HR(E_XAL_DUPLICATEDUSER);\n        RETURN_STRING_FROM_HR(E_XAL_NETWORK);\n        RETURN_STRING_FROM_HR(E_XAL_CLIENTERROR);\n        RETURN_STRING_FROM_HR(E_XAL_UIREQUIRED);\n        RETURN_STRING_FROM_HR(E_XAL_HANDLERALREADYREGISTERED);\n        RETURN_STRING_FROM_HR(E_XAL_UNEXPECTEDUSERSIGNEDIN);\n        RETURN_STRING_FROM_HR(E_XAL_NOTATTACHEDTOJVM);\n        RETURN_STRING_FROM_HR(E_XAL_DEVICEUSER);\n        RETURN_STRING_FROM_HR(E_XAL_DEFERRALNOTAVAILABLE);\n#if HC_PLATFORM != HC_PLATFORM_GDK\n        RETURN_STRING_FROM_HR(E_XAL_MISSINGPLATFORMEVENTHANDLER);\n#endif\n        RETURN_STRING_FROM_HR(E_XAL_USERNOTFOUND);\n        RETURN_STRING_FROM_HR(E_XAL_NOTOKENREQUIRED);\n        RETURN_STRING_FROM_HR(E_XAL_NODEFAULTUSER);\n        RETURN_STRING_FROM_HR(E_XAL_FAILEDTORESOLVE);\n#endif\n\n        RETURN_STRING_FROM_HR(E_XBL_RUNTIME_ERROR);\n        RETURN_STRING_FROM_HR(E_XBL_RTA_GENERIC_ERROR);\n        RETURN_STRING_FROM_HR(E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED);\n        RETURN_STRING_FROM_HR(E_XBL_RTA_ACCESS_DENIED);\n        RETURN_STRING_FROM_HR(E_XBL_AUTH_UNKNOWN_ERROR);\n        RETURN_STRING_FROM_HR(E_XBL_AUTH_RUNTIME_ERROR);\n        RETURN_STRING_FROM_HR(E_XBL_AUTH_NO_TOKEN);\n        RETURN_STRING_FROM_HR(E_XBL_ALREADY_INITIALIZED);\n\n        RETURN_STRING_FROM_HR(__HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW));\n        RETURN_STRING_FROM_HR(__HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION));\n        RETURN_STRING_FROM_HR(__HRESULT_FROM_WIN32(ERROR_BAD_LENGTH));\n        RETURN_STRING_FROM_HR(__HRESULT_FROM_WIN32(ERROR_CANCELLED));\n        RETURN_STRING_FROM_HR(__HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER));\n        RETURN_STRING_FROM_HR(__HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND));\n\n        RETURN_STRING_FROM_HR(E_HC_PERFORM_ALREADY_CALLED);\n        RETURN_STRING_FROM_HR(E_HC_ALREADY_INITIALISED);\n        RETURN_STRING_FROM_HR(E_HC_CONNECT_ALREADY_CALLED);\n        RETURN_STRING_FROM_HR(E_HC_NO_NETWORK);\n\n#if HC_PLATFORM == HC_PLATFORM_GDK\n        RETURN_STRING_FROM_HR(E_GAMERUNTIME_NOT_INITIALIZED);\n        RETURN_STRING_FROM_HR(E_GAMERUNTIME_DLL_NOT_FOUND);\n        RETURN_STRING_FROM_HR(E_GAMERUNTIME_VERSION_MISMATCH);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_MAX_USERS_ADDED);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_SIGNED_OUT);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_RESOLVE_USER_ISSUE_REQUIRED);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_DEFERRAL_NOT_AVAILABLE);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_USER_NOT_FOUND);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_NO_TOKEN_REQUIRED);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_NO_DEFAULT_USER);\n        //RETURN_STRING_FROM_HR(E_GAMEUSER_FAILED_TO_RESOLVE);\n        RETURN_STRING_FROM_HR(E_GAMEUSER_NO_TITLE_ID);\n        RETURN_STRING_FROM_HR(E_GAMEUSER_UNKNOWN_GAME_IDENTITY);\n        RETURN_STRING_FROM_HR(E_GAMEUSER_NO_PACKAGE_IDENTITY);\n        RETURN_STRING_FROM_HR(E_GAMEUSER_FAILED_TO_GET_TOKEN);\n        RETURN_STRING_FROM_HR(E_GAMEPACKAGE_APP_NOT_PACKAGED);\n        RETURN_STRING_FROM_HR(E_GAMEPACKAGE_NO_INSTALLED_LANGUAGES);\n        RETURN_STRING_FROM_HR(E_GAMESTORE_LICENSE_ACTION_NOT_APPLICABLE_TO_PRODUCT);\n        RETURN_STRING_FROM_HR(E_GAMESTORE_NETWORK_ERROR);\n        RETURN_STRING_FROM_HR(E_GAMESTORE_SERVER_ERROR);\n        RETURN_STRING_FROM_HR(E_GAMESTORE_INSUFFICIENT_QUANTITY);\n        RETURN_STRING_FROM_HR(E_GAMESTORE_ALREADY_PURCHASED);\n#endif\n\n        default: return \"Unknown error\";\n    }\n}\n\nstd::string ConvertHR(HRESULT hr)\n{\n    CHAR sz[256];\n#if HC_PLATFORM_IS_MICROSOFT\n    sprintf_s(sz, \"%s (0x%0.8x)\", ConvertHRtoString(hr).c_str(), hr);\n#else\n    sprintf(sz, \"%s (0x%0.8x)\", ConvertHRtoString(hr).c_str(), hr);\n#endif\n    return sz;\n}\n\nstd::string ReadFile(std::string fileName)\n{\n\n    std::string filePath = pal::FindFile(fileName);\n    if (filePath.empty())\n    {\n        std::string testPath = \"Tests\\\\\" + fileName;\n        filePath = pal::FindFile(testPath);\n    }\n\n    if (filePath.empty())\n    {\n        return std::string();\n    }\n\n    std::ifstream inputStream(filePath.c_str());\n\n    return std::string(std::istreambuf_iterator<char>(inputStream), std::istreambuf_iterator<char>());\n}\n\nuint64_t ConvertStringToUInt64(std::string str)\n{\n    return std::stoull(str);\n}\n\nHRESULT CreateQueueIfNeeded()\n{\n    HRESULT hr = S_OK;\n    if (Data()->queue == nullptr)\n    {\n        hr = XTaskQueueCreate(\n            XTaskQueueDispatchMode::ThreadPool,\n            XTaskQueueDispatchMode::ThreadPool,\n            &Data()->queue);\n\n        assert(SUCCEEDED(hr));\n    }\n\n    return hr;\n}\n\n#if CPP_TESTS_ENABLED\n\nusing namespace xbox::services;\n\nHRESULT ConvertHttpStatusToHresult(_In_ uint32_t httpStatusCode)\n{\n    xbox::services::xbox_live_error_code errCode = static_cast<xbox::services::xbox_live_error_code>(httpStatusCode);\n    HRESULT hr = HTTP_E_STATUS_UNEXPECTED;\n\n    // 2xx are http success codes\n    if ((httpStatusCode >= 200) && (httpStatusCode < 300))\n    {\n        hr = S_OK;\n    }\n\n    // MSXML XHR bug: get_status() returns HTTP/1223 for HTTP/204:\n    // http://blogs.msdn.com/b/ieinternals/archive/2009/07/23/the-ie8-native-xmlhttprequest-object.aspx\n    // treat it as success code as well\n    else if (httpStatusCode == 1223)\n    {\n        hr = S_OK;\n    }\n    else\n    {\n        switch (errCode)\n        {\n        case xbox_live_error_code::http_status_300_multiple_choices: hr = HTTP_E_STATUS_AMBIGUOUS; break;\n        case xbox_live_error_code::http_status_301_moved_permanently: hr = HTTP_E_STATUS_MOVED; break;\n        case xbox_live_error_code::http_status_302_found: hr = HTTP_E_STATUS_REDIRECT; break;\n        case xbox_live_error_code::http_status_303_see_other: hr = HTTP_E_STATUS_REDIRECT_METHOD; break;\n        case xbox_live_error_code::http_status_304_not_modified: hr = HTTP_E_STATUS_NOT_MODIFIED; break;\n        case xbox_live_error_code::http_status_305_use_proxy: hr = HTTP_E_STATUS_USE_PROXY; break;\n        case xbox_live_error_code::http_status_307_temporary_redirect: hr = HTTP_E_STATUS_REDIRECT_KEEP_VERB; break;\n\n        case xbox_live_error_code::http_status_400_bad_request: hr = HTTP_E_STATUS_BAD_REQUEST; break;\n        case xbox_live_error_code::http_status_401_unauthorized: hr = HTTP_E_STATUS_DENIED; break;\n        case xbox_live_error_code::http_status_402_payment_required: hr = HTTP_E_STATUS_PAYMENT_REQ; break;\n        case xbox_live_error_code::http_status_403_forbidden: hr = HTTP_E_STATUS_FORBIDDEN; break;\n        case xbox_live_error_code::http_status_404_not_found: hr = HTTP_E_STATUS_NOT_FOUND; break;\n        case xbox_live_error_code::http_status_405_method_not_allowed: hr = HTTP_E_STATUS_BAD_METHOD; break;\n        case xbox_live_error_code::http_status_406_not_acceptable: hr = HTTP_E_STATUS_NONE_ACCEPTABLE; break;\n        case xbox_live_error_code::http_status_407_proxy_authentication_required: hr = HTTP_E_STATUS_PROXY_AUTH_REQ; break;\n        case xbox_live_error_code::http_status_408_request_timeout: hr = HTTP_E_STATUS_REQUEST_TIMEOUT; break;\n        case xbox_live_error_code::http_status_409_conflict: hr = HTTP_E_STATUS_CONFLICT; break;\n        case xbox_live_error_code::http_status_410_gone: hr = HTTP_E_STATUS_GONE; break;\n        case xbox_live_error_code::http_status_411_length_required: hr = HTTP_E_STATUS_LENGTH_REQUIRED; break;\n        case xbox_live_error_code::http_status_412_precondition_failed: hr = HTTP_E_STATUS_PRECOND_FAILED; break;\n        case xbox_live_error_code::http_status_413_request_entity_too_large: hr = HTTP_E_STATUS_REQUEST_TOO_LARGE; break;\n        case xbox_live_error_code::http_status_414_request_uri_too_long: hr = HTTP_E_STATUS_URI_TOO_LONG; break;\n        case xbox_live_error_code::http_status_415_unsupported_media_type: hr = HTTP_E_STATUS_UNSUPPORTED_MEDIA; break;\n        case xbox_live_error_code::http_status_416_requested_range_not_satisfiable: hr = HTTP_E_STATUS_RANGE_NOT_SATISFIABLE; break;\n        case xbox_live_error_code::http_status_417_expectation_failed: hr = HTTP_E_STATUS_EXPECTATION_FAILED; break;\n        case xbox_live_error_code::http_status_421_misdirected_request: hr = MAKE_HTTP_HRESULT(421); break;\n        case xbox_live_error_code::http_status_422_unprocessable_entity: hr = MAKE_HTTP_HRESULT(422); break;\n        case xbox_live_error_code::http_status_423_locked: hr = MAKE_HTTP_HRESULT(423); break;\n        case xbox_live_error_code::http_status_424_failed_dependency: hr = MAKE_HTTP_HRESULT(424); break;\n        case xbox_live_error_code::http_status_426_upgrade_required: hr = MAKE_HTTP_HRESULT(426); break;\n        case xbox_live_error_code::http_status_428_precondition_required: hr = MAKE_HTTP_HRESULT(428); break;\n        case xbox_live_error_code::http_status_429_too_many_requests: hr = MAKE_HTTP_HRESULT(429); break;\n        case xbox_live_error_code::http_status_431_request_header_fields_too_large: hr = MAKE_HTTP_HRESULT(431); break;\n        case xbox_live_error_code::http_status_449_retry_with:hr = MAKE_HTTP_HRESULT(449); break;\n        case xbox_live_error_code::http_status_451_unavailable_for_legal_reasons: hr = MAKE_HTTP_HRESULT(451); break;\n\n        case xbox_live_error_code::http_status_500_internal_server_error: hr = HTTP_E_STATUS_SERVER_ERROR; break;\n        case xbox_live_error_code::http_status_501_not_implemented: hr = HTTP_E_STATUS_NOT_SUPPORTED; break;\n        case xbox_live_error_code::http_status_502_bad_gateway: hr = HTTP_E_STATUS_BAD_GATEWAY; break;\n        case xbox_live_error_code::http_status_503_service_unavailable: hr = HTTP_E_STATUS_SERVICE_UNAVAIL; break;\n        case xbox_live_error_code::http_status_504_gateway_timeout: hr = HTTP_E_STATUS_GATEWAY_TIMEOUT; break;\n        case xbox_live_error_code::http_status_505_http_version_not_supported: hr = HTTP_E_STATUS_VERSION_NOT_SUP; break;\n        case xbox_live_error_code::http_status_506_variant_also_negotiates: hr = MAKE_HTTP_HRESULT(506); break;\n        case xbox_live_error_code::http_status_507_insufficient_storage: hr = MAKE_HTTP_HRESULT(507); break;\n        case xbox_live_error_code::http_status_508_loop_detected: hr = MAKE_HTTP_HRESULT(508); break;\n        case xbox_live_error_code::http_status_510_not_extended: hr = MAKE_HTTP_HRESULT(510); break;\n        case xbox_live_error_code::http_status_511_network_authentication_required: hr = MAKE_HTTP_HRESULT(511); break;\n\n        default:\n            hr = HTTP_E_STATUS_UNEXPECTED;\n            break;\n        }\n    }\n\n    return hr;\n}\n\nHRESULT ConvertXboxLiveErrorCodeToHresult(_In_ const std::error_code& errCode)\n{\n    int err = static_cast<int>(errCode.value());\n    xbox_live_error_code xblErr = static_cast<xbox_live_error_code>(err);\n\n    if (err == 204)\n    {\n        return __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND);\n    }\n    else if (err >= 300 && err <= 505)\n    {\n        return (HRESULT)ConvertHttpStatusToHresult(static_cast<uint32_t>(err));\n    }\n    else if (err >= 1000 && err <= 9999)\n    {\n        switch (xblErr)\n        {\n        case xbox_live_error_code::bad_alloc: return E_OUTOFMEMORY;\n        case xbox_live_error_code::invalid_argument: return E_INVALIDARG;\n        case xbox_live_error_code::runtime_error: return E_XBL_RUNTIME_ERROR;\n        case xbox_live_error_code::length_error: return __HRESULT_FROM_WIN32(ERROR_BAD_LENGTH);\n        case xbox_live_error_code::out_of_range: return E_BOUNDS;\n        case xbox_live_error_code::range_error: return E_BOUNDS;\n        case xbox_live_error_code::bad_cast: return E_NOINTERFACE;\n        case xbox_live_error_code::logic_error: return E_UNEXPECTED;\n        case xbox_live_error_code::json_error: return WEB_E_INVALID_JSON_STRING;\n        case xbox_live_error_code::uri_error: return WEB_E_UNEXPECTED_CONTENT;\n        case xbox_live_error_code::websocket_error: return WEB_E_UNEXPECTED_CONTENT;\n        case xbox_live_error_code::auth_user_interaction_required: return ONL_E_ACTION_REQUIRED;\n        case xbox_live_error_code::rta_generic_error: return E_XBL_RTA_GENERIC_ERROR;\n        case xbox_live_error_code::rta_subscription_limit_reached: return E_XBL_RTA_SUBSCRIPTION_LIMIT_REACHED;\n        case xbox_live_error_code::rta_access_denied: return E_XBL_RTA_ACCESS_DENIED;\n        case xbox_live_error_code::auth_unknown_error: return E_XBL_AUTH_UNKNOWN_ERROR;\n        case xbox_live_error_code::auth_runtime_error: return E_XBL_AUTH_RUNTIME_ERROR;\n        case xbox_live_error_code::auth_no_token_error: return E_XBL_AUTH_NO_TOKEN;\n        case xbox_live_error_code::auth_user_not_signed_in: return __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);\n        case xbox_live_error_code::auth_user_cancel: return __HRESULT_FROM_WIN32(ERROR_CANCELLED);\n        case xbox_live_error_code::auth_user_switched: return __HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);\n        case xbox_live_error_code::invalid_config: return __HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION);\n        case xbox_live_error_code::unsupported: return E_NOTIMPL;\n\n        default: return E_FAIL;\n        }\n    }\n    else if ((err & 0x87DD0000) == 0x87D8000)\n    {\n        return HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR;\n    }\n    else return err; //return the original error code if can't be translated.\n}\n#endif\n\n#pragma warning (pop)\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/utils.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n#if HC_PLATFORM != HC_PLATFORM_UWP\n#include <Xal/xal.h>\n#endif\n\n// internal test-only APIs\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN                     namespace xbox { namespace services {\n#define NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END                       }}\n#include \"../../../Source/Shared/fault_injection.h\"\n\n#define VERIFY_IS_TRUE(x, y) if (SUCCEEDED(hr)) { hr = VerifyIsTrue(x, y); }\n#define ENSURE_IS_TRUE(x, y) if (FAILED(VerifyIsTrue(x, y))) return LuaReturnHR(L, E_ABORT);\n\nstd::string ConvertHRtoString(HRESULT hr);\nstd::string ConvertHR(HRESULT hr);\nstd::string ReadFile(std::string fileName);\nuint64_t ConvertStringToUInt64(std::string str);\nHRESULT CreateQueueIfNeeded();\nHRESULT VerifyIsTrue(bool condition, const char* pszCondition);\nHRESULT ConvertXboxLiveErrorCodeToHresult(_In_ const std::error_code& errCode);\n"
  },
  {
    "path": "Tests/ApiExplorer/Shared/xboxservices.config",
    "content": "{\n    \"TitleId\" : 1979882317,\n    \"PrimaryServiceConfigId\" : \"00000000-0000-0000-0000-000076029b4d\"\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/MultiplayerActivity/receive_invite_gsdk.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestReceiveInvite_Handler()\n    XGameInviteRegisterForEvent();\n    MultiDeviceSyncAndWait(\"SendInvite\");\nend\n\nfunction OnXGameInviteRegisterForEvent()\n    MultiDeviceSyncAndWait(\"Complete\");\n    test.stopTest();\nend\n\ntest.ismultidevice = true\ntest.TestReceiveInvite = function()\n    common.init(TestReceiveInvite_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/MultiplayerActivity/receive_invite_win32.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestReceiveInvite_Handler()\n    XblGameInviteRegisterForEventAsync()\nend\n\nfunction OnXblGameInviteRegisterForEventAsync()\n    XblMultiplayerActivityAddInviteHandler();\n    MultiDeviceSyncAndWait(\"SendInvite\");\nend\n\nfunction OnMultiplayerActivityGameInvite()\n    XblMultiplayerActivityRemoveInviteHandler()\n    XblGameInviteUnregisterForEventAsync()\n    MultiDeviceSyncAndWait(\"Complete\");\n    test.stopTest();\nend\n\ntest.ismultidevice = true;\ntest.TestReceiveInvite = function()\n    common.init(TestReceiveInvite_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/MultiplayerActivity/send_invite.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestSendInvite_Handler()\n    --MultiDeviceSyncAndWait(\"SendInvite\");\n    XblMultiplayerActivitySendInvitesAsync(MultiDeviceGetRemoteXuid())\nend\n\nfunction OnXblMultiplayerActivitySendInvitesAsync()\n    --MultiDeviceSyncAndWait(\"Complete\")\n    test.stopTest()\nend\n\ntest.ismultidevice = true;\ntest.TestSendInvite = function()\n    common.init(TestSendInvite_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/MultiplayerActivity/set_activity.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SetActivity_Handler()\n    XblMultiplayerActivitySetActivityAsync()\nend\n\nfunction OnXblMultiplayerActivitySetActivityAsync()\n    print(\"SetActivity call complete\")\nend\n\ntest.skip = true\ntest.SetActivity = function()\n    common.init(SetActivity_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/MultiplayerActivity/update_activity.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction UpdateActivity_Handler()\n    print(\"UpdateActivity_Handler\")\n    XblMultiplayerActivitySetActivityAsync()\nend\n\nfunction OnXblMultiplayerActivitySetActivityAsync()\n    print(\"OnXblMultiplayerActivitySetActivityAsync\")\n    XblMultiplayerActivityGetActivityAsync()\nend\n\nfunction OnXblMultiplayerActivityGetActivityAsync()\n    print(\"OnXblMultiplayerActivityGetActivityAsync\")\n    XblMultiplayerActivityDeleteActivityAsync()\nend\n\nfunction OnXblMultiplayerActivityDeleteActivityAsync()\n    print(\"OnXblMultiplayerActivityDeleteActivityAsync\")\n    test.stopTest()\nend\n\ntest.UpdateActivity = function()\n    common.init(UpdateActivity_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/MultiplayerActivity/update_recent_players.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction UpdateRecentPlayers_Handler()\n    print(\"UpdateRecentPlayers_Handler\")\n    XblMultiplayerActivityUpdateRecentPlayers(0)\n    XblMultiplayerActivityUpdateRecentPlayers(1)\n    XblMultiplayerActivityUpdateRecentPlayers(2)\n    XblMultiplayerActivityFlushRecentPlayersAsync()\nend\n\nfunction OnXblMultiplayerActivityFlushRecentPlayersAsync()\n    print(\"OnXblMultiplayerActivityFlushRecentPlayersAsync\")\n    test.stopTest();\nend\n\ntest.UpdateRecentPlayers = function()\n    common.init(UpdateRecentPlayers_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/_luasetup_/u-test/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-2018 Ilia Udalov <UdalovIlia@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/_luasetup_/u-test/README.md",
    "content": "# u-test\n[![License](http://img.shields.io/badge/License-MIT-green.svg)](LICENSE.txt)\n\n**u-test** is a sane and simple unit testing framework for Lua. It has all essential unit test framework features:\ndefining test cases, test suites, set of build-in assertions, configurable tests output, protected calls and etc.\n\n### Top features that are not present in other lua test frameworks\n1. Nice command line interface (like gtest).\n1. Backtrace in failed assertions.\n1. Ordered test execution (as written in source file). \n1. Support 5.1/5.2/5.3 and LuaJIT.\n1. Select particular tests with regexp.\n\n### How to install\n#### GitHub\nJust copy `u-test.lua` to your projct or add this repo as submodule.\n```\n$ git clone git://github.com/iudalov/u-test\n```\n#### [LuaRocks](https://luarocks.org)\nJust run:\n```\n$ luarocks install u-test\n```\n\n### How to use\n```lua\nlocal test = require 'u-test'\n\n-- You can use 'assert' to check invariants.\ntest.hello_world = function ()\n    test.assert(true)\n    test.assert(1 ~= 2)\nend\n\n-- This is how you can crete your first test case \ntest.addition = function ()\n    test.equal(1 + 1, 2)\n    test.not_equal(\"1 + 1\", \"2\")\n    test.almost_equal(1 + 1, 2.1, 0.2)\nend\n\n-- You can enable custom start_up and tear_down actions \n-- Thse actions will be invoked:\n-- start_up - before test case\n-- tear_down - after test case\nlocal global_state = 0\ntest.start_up = function () global_state = 1 end\ntest.tear_down = function () global_state = 0 end\n\ntest.dummy1 = function()\n    test.equal(global_state, 1)\n    test.is_number(global_state)\nend\n\n-- You can separate tests by test suites\ntest.string.format = function ()\n    test.equal(string.format(\"%d + %d\", 1, 1), \"1 + 1\")\n    test.not_equal(string.format(\"Sparky %s\", \"bark\"), \"Fluffy bark\")\nend\n\ntest.string.find = function ()\n    test.is_nil(string.find(\"u-test\", \"banana\"))\n    test.is_not_nil(string.find(\"u-test\", \"u\"))\nend\n\n-- You can declare test case with parameters\ntest.string.starts_with = function (str, prefix)\n    test.equal(string.find(str, prefix), 1)\nend\n\n-- Then, run it with multiple parameters\ntest.string.starts_with(\"Lua rocks\", \"Lua\")\ntest.string.starts_with(\"Wow\", \"Wow\")\n\nlocal global_table = {}\n\n-- Each test suite can be customized by start_up and tear_down\ntest.table.start_up = function ()\n    global_table = { 1, 2, \"three\", 4, \"five\" }\nend\ntest.table.tear_down = function () \n    global_table = {}\nend\n\ntest.table.concat = function ()\n    test.equal(table.concat(global_table, \", \"), \"1, 2, three, 4, five\")\nend\n\n-- you can disabe broken test case like this\ntest.broken.skip = true\ntest.broken.bad_case = function ()\n    test.equal(1, 2)\n    there_is_no_such_function()\nend\n\n-- obtain total number of tests and numer of failed tests\nlocal ntests, nfailed = test.result()\n\n-- this code prints tests summary and invokes os.exit with 0 or 1\ntest.summary()\n```\n\n![Output](https://raw.githubusercontent.com/iudalov/u-test/master/res/ui.png)\n\n### List of all assertions\n```lua\ntest.assert(true)\ntest.equal(1, 1)\ntest.not_equal(1, 2)\ntest.is_false(false)\ntest.is_true(true)\ntest.is_not_nil(\"Something\")\ntest.is_nil(nil)\ntest.is_boolean(true)\ntest.is_boolean(false)\ntest.is_string(\"I am string! look at me!\")\ntest.is_number(3)\ntest.is_table({\"I am table now\"})\ntest.is_function(function () end)\ntest.is_userdata(userdata_value)\n```\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/_luasetup_/u-test/u-test.lua",
    "content": "-- COMMAND LINE ----------------------------------------------------------------\n\nprint = function(...)\n    LogToScreen(...)\nend\n\nlocal quiet, grey, test_regex\n\n-- UTILS -----------------------------------------------------------------------\nlocal function red(str)    return grey and str or \"\" .. str .. \" \" end\nlocal function blue(str)   return grey and str or \"\" .. str .. \" \" end\nlocal function green(str)  return grey and str or \"\" .. str .. \" \" end\nlocal function yellow(str) return grey and str or \"\" .. str .. \" \" end\n\nlocal tab_tag      = blue   \"[----------]\"\nlocal done_tag     = blue   \"[==========]\"\nlocal run_tag      = blue   \"[ RUN      ]\"\nlocal ok_tag       = green  \"[       OK ]\"\nlocal fail_tag     = red    \"[      FAIL]\"\nlocal disabled_tag = yellow \"[ DISABLED ]\"\nlocal passed_tag   = green  \"[  PASSED  ]\"\nlocal failed_tag   = red    \"[  FAILED  ]\"\n\nlocal ntests = 0\nlocal failed = false\nlocal failed_list = {}\n\nlocal function log(msg)\n    if not quiet then\n        LogToScreen(msg)\n    end\nend\n\nlocal function trace(start_frame)\n    log(\"Trace:\")\n    local frame = start_frame\n    while true do\n        local info = debug.getinfo(frame, \"Sl\")\n        if not info then break end\n        if info.what == \"C\" then\n            -- log(\"??????\")\n        else\n            log(info.short_src .. \":\" .. info.currentline .. \" \")\n        end\n        frame = frame + 1\n    end\nend\n\nlocal function fail(msg, start_frame)\n    failed = true\n    log(\"Fail: \" .. msg)\n    trace(start_frame or 4)\nend\n\nlocal function fail_no_log(msg, start_frame)\n    failed = true\nend\n\nlocal function stringize_var_arg(varg, ...)\n    if varg then\n        local rest = stringize_var_arg(...)\n        if rest ~= \"\" then\n            return tostring(varg) .. \", \".. rest\n        else\n            return tostring(varg)\n        end\n    else\n        return \"\"\n    end\nend\n\nlocal function test_pretty_name(suite_name, test_name)\n    if suite_name == \"__root\" then\n        return test_name\n    else\n        return suite_name .. \".\" .. test_name\n    end\nend\n\n-- PUBLIC API -----------------------------------------------------------------\nlocal api = \n{ \n    test_suite_name = \"__root\", \n\n    enablebvts = false, \n    enablemultidevice = false, \n    skipOverride = false, \n\n    skip = false, \n    isbvt = false,\n    ismultidevice = false\n}\n\napi.assert = function (cond)\n    if not cond then\n        fail(\"assertion \" .. tostring(cond) .. \" failed\")\n    end\nend\n\napi.equal_no_log = function (l, r)\n    if l ~= r then\n        fail_no_log(tostring(l) .. \" ~= \" .. tostring(r))\n    end\nend\n\napi.equal = function (l, r)\n    if l ~= r then\n        fail(tostring(l) .. \" ~= \" .. tostring(r))\n    end\nend\n\napi.not_equal = function (l, r)\n    if l == r then\n        fail(tostring(l) .. \" == \" .. tostring(r))\n    end\nend\n\napi.almost_equal = function (l, r, diff)\n    if require(\"math\").abs(l - r) > diff then\n        fail(\"|\" .. tostring(l) .. \" - \" .. tostring(r) ..\"| > \" .. tostring(diff))\n    end\nend\n\napi.is_false = function (maybe_false)\n    if maybe_false or type(maybe_false) ~= \"boolean\" then\n        fail(\"got \" .. tostring(maybe_false) .. \" instead of false\")\n    end\nend\n\napi.is_true = function (maybe_true)\n    if not maybe_true or type(maybe_true) ~= \"boolean\" then\n        fail(\"got \" .. tostring(maybe_true) .. \" instead of true\")\n    end\nend\n\napi.is_not_nil = function (maybe_not_nil)\n    if type(maybe_not_nil) == \"nil\" then\n        fail(\"got nil\")\n    end\nend\n\nlocal function skip_test(test_suite)\n    failed = false\n\n    -- return back to default for future tests\n    test_suite.ismultidevice = false\n    test_suite.isbvt = false \n    test_suite.skip = false \n    SetTestWasSkipped()\n    api.stopTest()\nend\n\nlocal last_test_suite\nlocal function run_test(test_suite, test_name, test_function, ...)\n    local suite_name = test_suite.test_suite_name\n    full_test_name = test_pretty_name(suite_name, test_name)\n\n    if test_regex and not string.match(full_test_name, test_regex) then\n        return\n    end\n\n    start = os.time()  \n\n    -- uncomment for extra debug logs\n    -- if api.skipOverride then log(\"skipOverride true\") else log(\"skipOverride false\") end\n    -- if api.enablemultidevice then log(\"enablemultidevice true\") else log(\"enablemultidevice false\") end\n    -- if api.enablebvts then log(\"enablebvts true\") else log(\"enablebvts false\") end\n    -- if test_suite.skip then log(\"skip true\") else log(\"skip false\") end\n    -- if test_suite.ismultidevice then log(\"ismultidevice true\") else log(\"ismultidevice false\") end\n    -- if test_suite.isbvt then log(\"isbvt true\") else log(\"isbvt false\") end\n\n    if test_suite.skip and not api.skipOverride then\n        log(disabled_tag .. \" \" .. full_test_name)\n        skip_test(test_suite) -- doesnt match filter, so stop test early\n        return\n    end\n\n    if api.enablemultidevice then\n        if not test_suite.ismultidevice then\n            skip_test(test_suite) -- doesnt match filter, so stop test early\n            return\n        end\n    else\n        if test_suite.ismultidevice and not api.skipOverride then\nlog(\"spot3\")\n            skip_test(test_suite) -- doesnt match filter, so stop test early\n            return\n        end\n    end\n    \n    if api.enablebvts then\n        if not test_suite.isbvt then\n            skip_test(test_suite) -- doesnt match filter, so stop test early\n            return\n        end\n    end\n\n    -- return back to default for future tests\n    test_suite.ismultidevice = false\n    test_suite.isbvt = false \n\n    if suite_name ~= last_test_suite then\n        log(tab_tag)\n        last_test_suite = suite_name\n    end\n\n    ntests = ntests + 1\n    failed = false\n\n    log(run_tag .. \" \" .. full_test_name)\n    \n    status = true\n\n    for _, f in ipairs({test_suite.start_up,  test_function, test_suite.tear_down}) do\n        status, err = pcall(f, ...)\n        if status == nil then\n          status = true\n        end        \n        if not status then\n            failed = true\n            log(tostring(err))\n        end\n    end    \nend\n\napi.stopTest = function()\n    local stop = os.time()\n\n    local is_test_failed = not status or failed\n    log(string.format(\"%s %s %d sec\",\n                            is_test_failed and fail_tag or ok_tag,\n                            full_test_name,\n                            os.difftime(stop, start)))\n\n    if is_test_failed then\n        table.insert(failed_list, full_test_name)\n    end\n\n    StopTestFile();\nend\n\napi.summary = function ()\n    log(done_tag)\n    local nfailed = #failed_list\n    if nfailed == 0 then\n        log(passed_tag .. \" \" .. ntests .. \" test(s)\")\n    else\n        log(failed_tag .. \" \" .. nfailed .. \" out of \" .. ntests .. \":\")\n        for _, test_name in ipairs(failed_list) do\n            log(failed_tag .. \"\\t\" .. test_name)\n        end\n    end\nend\n\napi.result = function ( ... )\n    return ntests, #failed_list\nend\n\nlocal default_start_up = function () end\nlocal default_tear_down = function () collectgarbage() end\n\napi.start_up = default_start_up\napi.tear_down = default_tear_down\n\nlocal all_test_cases = { __root = {} }\nlocal function handle_new_test(suite, test_name, test_function)\n    local suite_name = suite.test_suite_name\n    if not all_test_cases[suite_name] then\n        all_test_cases[suite_name] = {}\n    end\n    all_test_cases[suite_name][test_name] = test_function\n\n    local info = debug.getinfo(test_function)\n    if info.nparams == nil and\n            string.sub(test_name, #test_name - 1, #test_name) ~= \"_p\"\n            or info.nparams == 0 then\n        run_test(suite, test_name, test_function)\n    end\nend\n\nlocal function lookup_test_with_params(suite, test_name)\n    local suite_name = suite.test_suite_name\n\n    if all_test_cases[suite_name] and all_test_cases[suite_name][test_name] then\n        return function (...)\n            run_test(suite\n                , test_name .. \"(\" .. stringize_var_arg(...) .. \")\"\n                , all_test_cases[suite_name][test_name], ...)\n        end\n    else\n        local full_test_name = test_pretty_name(suite_name, test_name)\n        table.insert(failed_list, full_test_name)\n        ntests = ntests + 1\n        log(fail_tag .. \" No \" .. full_test_name .. \" parametrized test case!\")\n    end\nend\n\nlocal function new_test_suite(_, name)\n    local test_suite = {\n        test_suite_name = name,\n        start_up = default_start_up,\n        tear_down = default_tear_down,\n        skip = false,\n        isbvt = false,\n        ismultidevice = false }\n\n    setmetatable(test_suite, {\n        __newindex = handle_new_test,\n        __index = lookup_test_with_params })\n    return test_suite\nend\n\nlocal test_suites = {}\nsetmetatable(api, {\n    __index = function (tbl, name)\n        if all_test_cases.__root[name] then\n            return lookup_test_with_params(tbl, name)\n        end\n\n        if not test_suites[name] then\n            test_suites[name] = new_test_suite(tbl, name)\n        end\n        return test_suites[name]\n    end,\n    __newindex = handle_new_test\n})\n\nreturn api"
  },
  {
    "path": "Tests/ApiExplorer/Tests/_luasetup_/uwp/setup.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction LuaSetupHandler()\n    local hr = GetLastError()\n    print(\"LuaSetupHandler: hr=\" .. hr)\n    SetCheckHR(1)\n    if hr ~= 0 then\n        print(\"LuaSetupHandler: hr != 0. Calling UwpXblSigninAsync\")\n        common.doCallbackOnError = false\n        UwpXblSigninAsync()\n    else\n        print(\"LuaSetupHandler: stopping test\")\n        common.doCallbackOnError = false\n        test.stopTest();\n    end\nend\n\ntest.StartSetupTest = function()\n    SetCheckHR(0)\n    common.doCallbackOnError = true\n    common.init(LuaSetupHandler)\nend\n\nfunction OnUwpXblSigninAsync()\n    local hr = GetLastError()\n    print(\"OnUwpXblSigninAsync: hr \" .. hr )\n    if hr == 0 then\n        UwpXblContextCreateHandle()\n    end\n    test.stopTest();\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/_luasetup_/xal/common.lua",
    "content": "local common = {}\n\nfunction common.init(fn)\n    common.functionAddFirstAsync = fn\n    XalPlatformWebSetEventHandler()\n    XalPlatformStorageSetEventHandlers()\n    XalInitialize()\n    XblInitialize()\n    XblGetScid()\n    XalTryAddFirstUserSilentlyAsync()\nend\n\nfunction common.cleanup()\n    XblContextCloseHandle();\n    XalUserCloseHandle()\n    XblCleanupAsync()\n    XalCleanupAsync()\n    XTaskQueueCloseHandle()\nend\n\nfunction common.OnXalTryAddFirstUserSilentlyAsync()\n    local hr = GetLastError()\n    local handle = 0\n    if hr == 0 then\n        print(\"SignInSilently Succeeded. Creating XblContext\")\n        handle, hr = XblContextCreateHandle()\n        print(\"hr \" .. hr)\n        print(\"handle \" .. handle)\n        if hr == 0 then\n            XalUserGetGamertag()\n            XalUserGetId()\n        else\n            if GetCheckHR() == true then \n                test.stopTest();\n            else\n                SetCheckHR(1)\n            end\n        end\n        common.functionAddFirstAsync()\n    else \n        print(\"SignInSilently Failed\")\n        if GetCheckHR() == true then \n            test.stopTest();\n        else\n            SetCheckHR(1)\n            common.functionAddFirstAsync()\n        end\n    end\nend\n\nreturn common\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/_luasetup_/xal/setup.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction SetupTest_Handler()\n    print(\"SetupTest_Handler\")\n    local hr = GetLastError()\n    SetCheckHR(1)\n    if hr ~= 0 then\n        print(\"Calling XalAddUserWithUiAsync\")\n        XalAddUserWithUiAsync()\n    else\n        test.stopTest();\n    end\nend\n\ntest.StartSetupTest = function()\n    print(\"Running shared test.StartSetupTest\")\n    SetCheckHR(0)\n    common.init(SetupTest_Handler)\nend\n\nfunction OnXalAddUserWithUiAsync()\n    print(\"In OnXalAddUserWithUiAsync\")\n    XblContextCreateHandle()\n    XalUserGetGamertag()\n    XalUserGetId()\n    test.stopTest();\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/PerformanceTestMockResponse.json",
    "content": "{\n    \"achievements\": [\n        {\n            \"id\": \"1\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 1\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789001\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 1\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 1\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 1\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 1\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"2\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 2\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789002\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 2\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 2\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 2\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 2\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"3\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789003\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"4\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 4\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789004\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 4\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 4\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 4\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 4\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"5\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 5\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789005\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 5\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 5\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 5\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 5\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"6\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 6\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789006\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 6\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 6\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 6\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 6\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"7\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 7\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789007\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 7\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 7\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 7\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 7\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"8\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 8\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789008\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 8\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 8\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 8\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 8\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"9\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 9\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789009\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 9\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 9\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 9\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 9\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"10\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 10\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789010\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 10\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 10\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 10\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 10\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"11\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 11\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789011\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 11\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 11\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 11\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 11\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"12\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 12\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789012\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 12\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 12\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 12\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 12\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"13\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 13\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789013\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 13\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 13\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 13\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 13\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"14\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 14\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789014\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 14\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 14\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 14\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 14\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"15\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 15\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789015\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 15\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 15\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 15\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 15\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"16\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 16\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789016\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 16\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 16\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 16\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 16\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"17\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 17\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789017\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 17\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 17\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 17\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 17\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"18\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 18\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789018\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 18\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 18\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 18\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 18\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"19\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 19\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789019\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 19\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 19\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 19\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 19\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"20\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 20\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789020\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 20\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 20\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 20\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 20\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"21\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 21\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789021\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 21\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 21\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 21\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 21\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"22\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 22\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789022\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 22\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 22\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 22\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 22\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"23\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 23\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789023\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 23\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 23\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 23\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 23\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"24\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 24\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789024\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 24\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 24\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 24\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 24\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"25\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 25\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789025\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 25\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 25\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 25\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 25\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"26\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 26\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789026\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 26\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 26\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 26\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 26\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"27\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 27\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789027\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 27\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 27\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 27\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 27\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"28\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 28\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789028\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 28\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 28\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 28\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 28\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"29\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 29\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789029\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 29\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 29\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 29\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 29\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"30\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 30\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789030\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 30\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 30\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 30\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 30\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"31\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 31\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789031\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 31\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 31\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 31\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 31\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"32\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 32\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789032\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 32\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 32\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 32\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 32\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"33\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 33\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789033\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 33\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 33\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 33\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 33\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"34\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 34\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789034\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 34\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 34\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 34\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 34\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"35\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 35\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789035\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 35\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 35\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 35\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 35\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"36\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 36\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789036\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 36\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 36\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 36\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 36\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"37\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 37\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789037\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 37\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 37\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 37\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 37\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"38\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 38\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789038\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 38\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 38\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 38\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 38\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"39\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 39\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789039\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 39\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 39\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 39\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 39\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"40\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 40\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789040\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 40\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 40\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 40\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 40\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"41\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 41\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789041\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 41\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 41\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 41\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 41\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"42\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 42\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789042\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 42\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 42\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 42\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 42\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"43\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 43\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789043\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 43\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 43\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 43\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 43\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"44\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 44\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789044\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 44\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 44\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 44\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 44\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"45\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 45\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789045\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 45\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 45\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 45\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 45\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"46\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 46\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789046\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 46\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 46\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 46\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 46\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"47\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 47\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789047\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 47\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 47\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 47\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 47\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"48\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 48\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789048\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 48\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 48\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 48\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 48\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"49\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 49\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789049\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 49\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 49\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 49\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 49\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"50\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 50\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789050\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 50\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 50\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 50\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 50\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"51\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 51\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789051\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 51\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 51\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 51\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 51\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"52\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 52\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789052\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 52\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 52\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 52\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 52\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"53\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 53\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789053\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 53\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 53\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 53\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 53\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"54\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 54\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789054\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 54\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 54\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 54\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 54\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"55\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 55\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789055\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 55\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 55\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 55\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 55\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"56\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 56\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789056\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 56\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 56\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 56\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 56\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"57\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 57\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789057\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 57\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 57\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 57\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 57\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"58\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 58\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789058\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 58\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 58\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 58\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 58\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"59\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 59\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789059\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 59\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 59\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 59\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 59\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"60\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 60\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789060\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 60\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 60\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 60\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 60\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"61\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 61\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789061\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 61\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 61\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 61\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 61\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"62\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 62\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789062\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 62\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 62\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 62\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 62\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"63\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 63\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789063\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 63\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 63\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 63\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 63\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"64\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 64\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789064\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 64\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 64\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 64\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 64\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"65\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 65\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789065\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 65\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 65\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 65\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 65\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"66\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 66\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789066\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 66\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 66\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 66\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 66\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"67\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 67\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789067\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 67\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 67\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 67\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 67\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"68\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 68\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789068\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 68\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 68\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 68\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 68\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"69\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 69\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789069\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 69\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 69\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 69\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 69\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"70\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 70\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789070\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 70\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 70\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 70\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 70\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"71\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 71\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789071\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 71\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 71\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 71\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 71\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"72\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 72\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789072\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 72\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 72\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 72\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 72\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"73\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 73\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789073\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 73\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 73\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 73\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 73\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"74\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 74\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789074\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 74\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 74\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 74\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 74\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"75\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 75\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789075\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 75\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 75\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 75\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 75\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"76\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 76\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789076\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 76\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 76\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 76\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 76\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"77\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 77\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789077\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 77\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 77\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 77\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 77\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"78\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 78\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789078\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 78\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 78\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 78\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 78\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"79\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 79\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789079\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 79\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 79\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 79\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 79\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"80\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 80\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789080\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 80\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 80\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 80\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 80\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"81\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 81\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789081\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 81\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 81\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 81\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 81\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"82\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 82\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789082\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 82\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 82\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 82\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 82\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"83\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 83\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789083\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 83\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 83\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 83\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 83\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"84\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 84\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789084\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 84\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 84\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 84\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 84\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"85\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 85\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789085\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 85\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 85\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 85\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 85\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"86\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 86\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789086\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 86\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 86\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 86\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 86\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"87\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 87\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789087\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 87\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 87\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 87\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 87\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"88\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 88\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789088\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 88\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 88\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 88\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 88\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"89\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 89\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789089\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 89\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 89\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 89\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 89\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"90\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 90\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789090\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 90\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 90\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 90\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 90\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"91\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 91\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789091\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 91\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 91\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 91\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 91\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"92\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 92\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789092\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 92\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 92\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 92\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 92\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"93\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 93\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789093\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 93\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 93\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 93\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 93\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"94\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 94\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789094\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 94\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 94\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 94\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 94\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"95\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 95\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789095\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 95\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 95\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 95\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 95\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"96\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 96\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789096\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 96\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 96\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 96\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 96\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"97\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 97\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789097\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 97\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 97\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 97\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 97\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"98\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 98\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789098\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 98\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 98\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 98\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 98\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"99\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 99\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789099\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 99\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 99\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 99\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 99\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        },\n        {\n            \"id\": \"100\",\n            \"serviceConfigId\": \"b5dd9daf-0000-0000-0000-000000000000\",\n            \"name\": \"Default NameString for Microsoft Achievements Sample Achievement 100\",\n            \"titleAssociations\": [\n                {\n                    \"name\": \"Microsoft Achievements Sample\",\n                    \"id\": 3051199919,\n                    \"version\": \"abc\"\n                }\n            ],\n            \"progressState\": \"NotStarted\",\n            \"progression\": {\n                \"requirements\": [\n                    {\n                        \"id\": \"12345678-1234-1234-1234-123456789100\",\n                        \"current\": null,\n                        \"target\": \"100\",\n                        \"operationType\": \"sum\",\n                        \"ruleParticipationType\": \"Individual\"\n                    }\n                ],\n                \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n            },\n            \"mediaAssets\": [\n                {\n                    \"name\": \"Icon Name\",\n                    \"type\": \"Icon\",\n                    \"url\": \"http://www.xbox.com/\"\n                }\n            ],\n            \"platforms\": [ \"Durango\", \"Xbox360\" ],\n            \"isSecret\": true,\n            \"description\": \"Default DescriptionString for Microsoft Achievements Sample Achievement 100\",\n            \"lockedDescription\": \"Default UnachievedString for Microsoft Achievements Sample Achievement 100\",\n            \"productId\": \"12345678-1234-1234-1234-123456789012\",\n            \"achievementType\": \"Challenge\",\n            \"participationType\": \"Individual\",\n            \"timeWindow\": {\n                \"startDate\": \"2013-02-01T00:00:00Z\",\n                \"endDate\": \"2100-07-01T00:00:00Z\"\n            },\n            \"rewards\": [\n                {\n                    \"name\": null,\n                    \"description\": null,\n                    \"value\": \"10\",\n                    \"type\": \"Gamerscore\",\n                    \"valueType\": \"Int\",\n                    \"mediaAsset\": null\n                },\n                {\n                    \"name\": \"Default Name for InAppReward for Microsoft Achievements Sample Achievement 100\",\n                    \"description\": \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 100\",\n                    \"value\": \"1\",\n                    \"type\": \"InApp\",\n                    \"valueType\": \"String\",\n                    \"mediaAsset\": {\n                        \"name\": \"Icon Name\",\n                        \"type\": \"Icon\",\n                        \"url\": \"http://www.xbox.com\"\n                    }\n                }\n            ],\n            \"estimatedTime\": \"06:12:14\",\n            \"deeplink\": \"aWFtYWRlZXBsaW5r\",\n            \"isRevoked\": false\n        }\n    ]\n}"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/achievements-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction GetAchievementsForTitleIdCpp_Handler()\n    print(\"GetAchievementsForTitleIdCpp_Handler\")\n    AchievementsServiceGetAchievementsForTitleId()\nend\n\nfunction OnAchievementsServiceGetAchievementsForTitleId()\n    hr, hasNext = AchievementsResultHasNextCpp()\n    print(\"hasNext \" .. hr)\n    print(\"hr \" .. hr)\n    if hasNext ~= 0 then\n        AchievementsResultGetNextCpp()\n    else\n        test.stopTest();\n    end\nend\n\nfunction OnAchievementsResultGetNextCpp()\n    print(\"OnAchievementsResultGetNextCpp\")\n    OnAchievementsServiceGetAchievementsForTitleId()\nend\n\ntest.TestGetAchievementsForTitleCpp = function()\n    common.init(GetAchievementsForTitleIdCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/achievements.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction GetAchievementsForTitleId_Handler()\n    print(\"GetAchievementsForTitleId_Handler\")\n    XblAchievementsGetAchievementsForTitleIdAsync()\nend\n\nfunction OnXblAchievementsGetAchievementsForTitleIdAsync()\n    XblAchievementsResultGetAchievements()\n    hr, hasNext = XblAchievementsResultHasNext()\n    print(\"hasNext \" .. hr)\n    print(\"hr \" .. hr)\n    if hasNext ~= 0 then\n        XblAchievementsResultGetNextAsync()\n    else\n        XblAchievementsResultCloseHandle();\n        test.stopTest();\n    end\nend\n\nfunction OnXblAchievementsResultGetNextAsync()\n    print(\"OnXblAchievementsResultGetNextAsync\")\n    XblAchievementsGetAchievementsForTitleIdAsync()\nend\n\ntest.isbvt = true\ntest.TestGetAchievementsForTitle = function()\n    common.init(GetAchievementsForTitleId_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/achievements_manager.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nlocal function VerifySuccess(hr)\n    SetCheckHR(1)\n    if hr ~= 0 then\n        test.equal(hr, 0)\n        print(\"Failure. hr=\" .. hr)\n        test.stopTest()\n    end\n    return true\nend\n\nfunction AchievementsManager_Handler()\n    print(\"AchievementsManager_Handler\")\n    StartAchievementsManagerDoWorkLoop()\n    XblAchievementsManagerAddLocalUser()\nend\n\nfunction OnXblAchievementsManagerDoWork_LocalUserAddedEvent()\n    print(\"OnXblAchievementsManagerDoWork_LocalUserAddedEvent\")\n    handle, hr = XblAchievementsManagerGetAchievement(\"1\")\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements(handle)\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    \n    handle, hr = XblAchievementsManagerGetAchievements()\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements(handle)\n    if count ~= 2 then\n       test.equal(hr, 0);\n       print(\"Failure. Number of achievements found (\" .. count .. \") different from expected (2). hr=\" .. hr)\n       test.stopTest()\n    end\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    handle, hr = XblAchievementsManagerGetAchievements()\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements()\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n    \n    handle, hr = XblAchievementsManagerGetAchievementsByState()\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements()\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    XblAchievementsManagerRemoveLocalUser()\n    StopAchievementsManagerDoWorkLoop()\n    test.stopTest()\nend\n\nfunction OnXblAchievementsManagerDoWork_AchievementProgressUpdatedEvent()\n    print(\"OnXblAchievementsManagerDoWork_AchievementProgressUpdatedEvent\")\nend\n\nfunction OnXblAchievementsManagerDoWork_AchievementUnlockedEvent()\n    print(\"OnXblAchievementsManagerDoWork_AchievementUnlockedEvent\")\nend\n\ntest.isbvt = true\ntest.TestAchievementsManager = function()\n    common.init(AchievementsManager_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/achievements_manager_performance_test.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nlocal function VerifySuccess(hr)\n    SetCheckHR(1)\n    if hr ~= 0 then\n        test.equal(hr, 0)\n        print(\"Failure. hr=\" .. hr)\n        test.stopTest()\n    end\n    return true\nend\n\nfunction AchievementsManagerPerformance_Handler( ... )\n    print(\"AchievementsManagerPerformance_Handler\")\n    -- start test\n    SetupAchievementsManagerPerformanceTestMock()\n    StartAchievementsManagerDoWorkLoop()\n    XblAchievementsManagerAddLocalUser()\nend\n\nfunction OnXblAchievementsManagerDoWork_LocalUserAddedEvent()\n    print(\"OnXblAchievementsManagerDoWork_LocalUserAddedEvent\")\n    -- call get achievements performance test\n\n    handle, hr = XblAchievementsManagerGetAchievementsPerfTest()\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements(handle)\n    if count ~= 100 then\n       test.equal(hr, 0);\n       print(\"Failure. Number of achievements found (\" .. count .. \") different from expected (100). hr=\" .. hr)\n       test.stopTest()\n    end\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    XblAchievementsManagerRemoveLocalUser()\n    StopAchievementsManagerDoWorkLoop()\n    test.stopTest()    \nend\n\n\ntest.isbvt = true\ntest.TestAchievementsManager = function()\n    common.init(AchievementsManagerPerformance_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/achievements_manager_update_achievements.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n-- Note: This test requires an account with achievement id 2 locked with no progress, and can only be run \n-- one time on that account as we currently have no way to programmatically reset the unlock\n-- status of an achievement from API Explorer. To successfully run the test again you will have \n-- to run the XblPlayerDataReset tool to reset the user or sign in with a different account.\n\nlocal function VerifySuccess(hr)\n    SetCheckHR(1)\n    if hr ~= 0 then\n        test.equal(hr, 0)\n        print(\"Failure. hr=\" .. hr)\n        test.stopTest()\n    end\n    return true\nend\n\nlocal unlockeReceived = false\nlocal updateReceived = 0\nlocal originalUnlockCount = 0\nlocal testUpdate = true -- if false, then Unlock is being tested\n\nlocal function IsUpdateTestCompleted()\n    if updateReceived >= 2 and testUpdate then\n        updateReceived = 0\n        return true\n    end\n    return false\nend\n\nlocal function IsUnlockTestCompleted()\n    if unlockReceived and updateReceived >= 1 and not testUpdate then\n        unlockReceived = false\n        updateReceived = 0\n        return true\n    end\n    return false\nend\n\n-- Order of unlock and update events getting processed isn't guaranteed, so moving\n-- the test completion logic to a separate function.\nlocal function EndTestIfUnlockComplete()\n    if IsUnlockTestCompleted() then\n        XblAchievementsManagerRemoveLocalUser()\n        StopAchievementsManagerDoWorkLoop()\n        test.stopTest()\n    end\nend\n\nfunction AchievementsManagerUpdateAchievements_Handler()\n    print(\"AchievementsManagerUpdateAchievements_Handler\")\n    StartAchievementsManagerDoWorkLoop()\n    XblAchievementsManagerAddLocalUser()\nend\n\nfunction OnXblAchievementsManagerDoWork_LocalUserAddedEvent()\n    print(\"OnXblAchievementsManagerDoWork_LocalUserAddedEvent\")\n    handle, hr = XblAchievementsManagerGetAchievementsByState()\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements()\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    originalUnlockCount = count\n    testUpdate = true\n    \n    XblAchievementsManagerUpdateAchievement(\"2\", 90)\n    XblAchievementsManagerUpdateAchievement(\"1\", 50)\nend\n\nfunction OnXblAchievementsManagerDoWork_AchievementProgressUpdatedEvent()\n    print(\"OnXblAchievementsManagerDoWork_AchievementProgressUpdatedEvent\")\n    handle, hr = XblAchievementsManagerGetAchievement(\"2\")\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements()\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    updateReceived = updateReceived + 1\n    \n    if IsUpdateTestCompleted() then\n        updateReceived = 0\n        testUpdate = false\n        XblAchievementsManagerUpdateAchievement(\"2\", 100)\n    end\n    EndTestIfUnlockComplete()\nend\n\nfunction OnXblAchievementsManagerDoWork_AchievementUnlockedEvent()\n    print(\"OnXblAchievementsManagerDoWork_AchievementUnlockedEvent\")\n    handle, hr = XblAchievementsManagerGetAchievementsByState()\n    VerifySuccess(hr)\n    count, hr = XblAchievementsManagerResultGetAchievements()\n    VerifySuccess(hr)\n    XblAchievementsManagerResultCloseHandle(handle)\n\n    unlockReceived = true\n    if count ~= originalUnlockCount + 1 then\n        test.equal(count, originalUnlockCount + 1)\n        print(\"Failure. Number of unlocked achievements (\" .. count .. \") differs from expected (\" .. originalUnlockCount + 1 .. \").\")\n        test.stopTest()\n    end\n    EndTestIfUnlockComplete()\nend\n\ntest.skip = true\ntest.TestAchievementsManager = function()\n    common.init(AchievementsManagerUpdateAchievements_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/achievements_progress_notification.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction AchievementProgressNotifications_Handler()\n    print ('AchievementProgressNotifications_Handler')\n    XblAchievementsAddAchievementProgressChangeHandler()\n    SetCheckHR(0)\n\tSleep(5000)\n    XblAchievementsUpdateAchievementAsync(\"2\", 20)\nend\n\nfunction OnXblAchievementsAddAchievementProgressHandler()\n    print ('OnXblAchievementsAddAchievementProgressHandler')\n    XblAchievementsRemoveAchievementProgressChangeHandler()\n    test.stopTest();\nend\n\nfunction OnXblAchievementsUpdateAchievementAsync()\n    print (\"OnXblAchievementsUpdateAchievementAsync\")\n    local hr = GetLastError()\n    SetCheckHR(1)\n\tif hr == -2145844944 then -- -2145844944 == 0x80190130 == HTTP_E_STATUS_NOT_MODIFIED\n\t\tprint(\"Achievement not modified.\")\n\t\tXblAchievementsRemoveAchievementProgressChangeHandler()\n\t\ttest.stopTest()\n    elseif hr ~= 0 then \n        test.equal(hr, 0);\n        print(\"Failure.  hr=\" .. hr)\n        test.stopTest()\n    else\n\t    print (\"Waiting to receive notification.\")\n\tend\nend\n\ntest.skip = true;\ntest.TestAchievementProgressNotification = function()\n    common.init(AchievementProgressNotifications_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/update-achievements-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction AchievementsServiceUpdateAchievement_Handler()\n    print(\"AchievementsServiceUpdateAchievement_Handler\")\n    SetCheckHR(0)\n    AchievementsServiceUpdateAchievement()\nend\n\nfunction OnAchievementsServiceUpdateAchievement()\n    local hr = GetLastError()\n    SetCheckHR(1)\n    if hr ~= 0 and hr ~= -2145844944 then -- -2145844944 == 0x80190130 == HTTP_E_STATUS_NOT_MODIFIED\n        test.equal(hr, 0);\n        print(\"Failure.  hr=\" .. hr)\n    end\n    test.stopTest();\nend\n\ntest.TestAchievementsServiceUpdateAchievementCpp = function()\n    common.init(AchievementsServiceUpdateAchievement_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/achievements/update-achievements.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction XblAchievementsUpdateAchievementAsync_Handler()\n    print(\"XblAchievementsUpdateAchievementAsync_Handler\")\n    SetCheckHR(0)\n    XblAchievementsUpdateAchievementAsync()\nend\n\nfunction OnXblAchievementsUpdateAchievementAsync()\n    local hr = GetLastError()\n    SetCheckHR(1)\n    if hr ~= 0 and hr ~= -2145844944 then -- -2145844944 == 0x80190130 == HTTP_E_STATUS_NOT_MODIFIED\n        test.equal(hr, 0);\n        print(\"Failure.  hr=\" .. hr)\n    end\n    test.stopTest();\nend\n\ntest.isbvt = true\ntest.TestXblAchievementsUpdateAchievementAsync = function()\n    common.init(XblAchievementsUpdateAchievementAsync_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/cmds.json",
    "content": "{\n  \"commands\": [\n    // remove \"rem\" from lines below to uncomment\n\n    // multi-device examples\n    // one device should host, and one device should join\n    \"rem host changetoyouralias\",\n    \"rem join changetoyouralias\",\n    \"rem runmultidevicetests\",\n    \"rem rt mp\\\\MP_JoinLobbyViaActivity.lua\",\n    \"rem rt multiplayerManager\\\\MPM_JoinLobbyViaActivity.lua\",\n    \"rem rt multiplayerManager\\\\MPM_JoinFixedGameSession.lua\",\n    \"rem rt multiplayerManager\\\\MPM_Match.lua\",\n    \"rem rt multiplayerManager\\\\MPM_Invite.lua\",\n    \"rem rt multiplayerManager\\\\MPM_InviteUI.lua\",\n\n    // fault injection\n    \"rem faultinjection options 1 7 1\", // faultinjection options failFreq freqChangeSpeed freqChangeAmount\n    \"rem faultinjection user\", // \"faultinjection\" enables specific fault injection on specific features\n    \"rem faultinjection http\", // \"faultinjection\" enables specific fault injection on specific features\n\n    // mem hook tracking\n    \"rem memtrack true\", // result logged after runtests or rt command ends\n\n    // single-device command examples\n    \"rem runbarescript misc\\\\global_state.lua\", // \"runbarescript\" will run the script without any XBL/XAL initializtion for special test needs\n    \"rem rt achievements\\\\achievements_progress_notification.lua\",\n    \"rem rt achievements\\\\achievements_manager_performance_test.lua\",\n    \"rem rt achievements\\\\achievements_manager_update_achievements.lua\",\n    \"rem rt gdk-gameinvite\\\\game-invite.lua\", // rt will run a single test\n    \"rem repeat social\\\\social_manager_2.lua\", // \"repeat\" will repeat this single test without cleanup forever\n    \"rem loop\", // \"loop\" will loop the entire cmds.json file including cleanup, forever\n    \"rt multiplayerActivity\\\\send_invite.lua\"\n  ]\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/events/events-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestWriteEventCpp_Handler()\n    print(\"TestWriteEventCpp_Handler\")\n    EventsServiceWriteInGameEvent()\n    test.stopTest();\nend\n\ntest.TestWriteEventCpp = function()\n    common.init(TestWriteEventCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/events/events.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestWriteEvent_Handler()\n    print(\"TestWriteEvent_Handler\")\n    XblEventsWriteInGameEvent()\n    test.stopTest();\nend\n\ntest.TestWriteEvent = function()\n    common.init(TestWriteEvent_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/events/offline-cpp.lua",
    "content": "-- Writes some events while offline, regains connection and uploads the events\n\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestOfflineEventsCpp_Handler()\n    print(\"TestOfflineEventsCpp_Handler\")\n    LeaderboardServiceGetLeaderboard()\nend\n\nlocal count = 0;\n\nfunction OnLeaderboardServiceGetLeaderboard()\n    print(\"OnLeaderboardServiceGetLeaderboard\")\n    count = count + 1\n    if count == 1 then\n        UploadEventsAndWait(1)\n        LeaderboardServiceGetLeaderboard()\n    elseif count == 2 then\n        SetupEventUploadMock()\n        UploadEventsAndWait(9)\n        HCMockClearMocks()\n        --Clear mocks and events should upload automatically\n        Sleep(5000)\n        LeaderboardServiceGetLeaderboard()\n    elseif count == 3 then\n        test.stopTest()\n    end\nend\n\nfunction SetupEventUploadMock()\n    --Force event uploads to fail\n    HCMockCallCreate()\n    HCMockResponseSetNetworkErrorCode()\n    HCMockAddMock(\"POST\", \"https://vortex.data.microsoft.com/collect/v1\")\nend\n\nfunction UploadEventsAndWait(count)\n    while count > 0 do\n        EventsServiceWriteInGameEvent()\n        count = count - 1\n    end\n    Sleep(5000)\nend\n\ntest.TestOfflineEventsCpp = function()\n    common.init(TestOfflineEventsCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/events/offline.lua",
    "content": "-- Writes some events while offline, regains connection and uploads the events\n\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestOfflineEvents_Handler()\n    print(\"TestOfflineEvents_Handler\")\n    XblLeaderboardGetLeaderboardAsync()\nend\n\nlocal count = 0;\n\nfunction OnXblLeaderboardGetLeaderboardAsync()\n    print(\"OnXblLeaderboardGetLeaderboardAsync\")\n    count = count + 1\n    if count == 1 then\n        UploadEventsAndWait(1)\n        XblLeaderboardGetLeaderboardAsync()\n    elseif count == 2 then\n        SetupEventUploadMock()\n        UploadEventsAndWait(9)\n        HCMockClearMocks()\n        --Clear mocks and events should upload automatically\n        Sleep(5000)\n        XblLeaderboardGetLeaderboardAsync()\n    elseif count == 3 then\n        test.stopTest()\n    end\nend\n\nfunction SetupEventUploadMock()\n    --Force event uploads to fail\n    HCMockCallCreate()\n    HCMockResponseSetNetworkErrorCode()\n    HCMockAddMock(\"POST\", \"https://vortex.data.microsoft.com/collect/v1\")\nend\n\nfunction UploadEventsAndWait(count)\n    while count > 0 do\n        XblEventsWriteInGameEvent()\n        count = count - 1\n    end\n    Sleep(5000)\nend\n\ntest.TestOfflineEvents = function()\n    common.init(TestOfflineEvents_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/events/offline2-cpp.lua",
    "content": "-- Write 10 events while offline. An offline events file with 10 events should be written during this test, and then deleted at the end of this test.\n\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestOfflineEventsCpp_Handler()\n    print(\"TestOfflineEventsCpp_Handler\")\n    SetupEventUploadMock()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    EventsServiceWriteInGameEvent()\n    XblContextCloseHandle()\n    Sleep(2000)\n    ValidateOfflineEventsDirectoryFileExistsAndDelete()\n    test.stopTest()\nend\n\nfunction SetupEventUploadMock()\n    --Force event uploads to fail\n    HCMockCallCreate()\n    HCMockResponseSetNetworkErrorCode()\n    HCMockAddMock(\"POST\", \"https://vortex.data.microsoft.com/collect/v1\")\nend\n\ntest.TestOfflineEvents2Cpp = function()\n    common.init(TestOfflineEventsCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/events/offline2.lua",
    "content": "-- Write 10 events while offline. An offline events file with 10 events should be leftover after this test.\n\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestOfflineEvents_Handler()\n    print(\"TestOfflineEvents_Handler\")\n    SetupEventUploadMock()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblEventsWriteInGameEvent()\n    XblContextCloseHandle()\n    Sleep(2000)\n    ValidateOfflineEventsDirectoryFileExistsAndDelete()\n    test.stopTest()\nend\n\nfunction SetupEventUploadMock()\n    --Force event uploads to fail\n    HCMockCallCreate()\n    HCMockResponseSetNetworkErrorCode()\n    HCMockAddMock(\"POST\", \"https://vortex.data.microsoft.com/collect/v1\")\nend\n\ntest.TestOfflineEvents2 = function()\n    common.init(TestOfflineEvents_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/gdk-gameinvite/game-invite-listen.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestGameInvite_Handler()\n    print(\"LUA: calling XGameInviteRegisterForEvent\")\n    XGameInviteRegisterForEvent();\n    print(\"LUA: called XGameInviteRegisterForEvent\")\nend\n\nfunction OnXGameInviteRegisterForEvent()\n    print(\"LUA: OnXGameInviteRegisterForEvent\");\n    XblMultiplayerGetSessionByHandleAsync();\nend\n\ntest.skip = true\ntest.TestGameInvite = function()\n    common.init(TestGameInvite_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/gdk-gameinvite/game-invite-send.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestGameInviteSend_Handler()\n    XblMultiplayerSessionCreateHandle()\n    XblMultiplayerSessionJoin()\n    XblMultiplayerWriteSessionAsync()\nend\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    XblMultiplayerSessionReferenceCreate();\n    XblMultiplayerSetActivityAsync();\nend\n\nfunction OnXblMultiplayerSetActivityAsync()\n    XGameUiShowSendGameInviteAsync();\nend\n\nfunction OnXGameUiShowSendGameInviteAsync()\n    test.stopTest();\nend\n\ntest.skip = true\ntest.TestGameInviteSend = function()\n    common.init(TestGameInviteSend_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/gdk-gameinvite/game-mpainvite-send.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestGameMpaInviteSend_Handler()\n    XblMultiplayerActivitySetActivityAsync()\n\n    print(\"LUA: calling XGameInviteRegisterForEvent\")\n    XGameInviteRegisterForEvent();\n    print(\"LUA: called XGameInviteRegisterForEvent\")\nend\n\nfunction OnXblMultiplayerActivitySetActivityAsync()\n    XGameUiShowMultiplayerActivityGameInviteAsync();\nend\n\nfunction OnXGameUiShowMultiplayerActivityGameInviteAsync()\n    print(\"XGameUiShowMultiplayerActivityGameInviteAsync completed\");\nend\n\n\nfunction OnXGameInviteRegisterForEvent()\n    print(\"LUA: OnXGameInviteRegisterForEvent\");\nend\n\ntest.skip = true\ntest.TestGameMpaInviteSend = function()\n    common.init(TestGameMpaInviteSend_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/leaderboard/leaderboard-2017.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestLeaderboard2017_Handler()\n    print(\"TestLeaderboard_Handler\")\n    XblTitleManagedStatsWriteAsync()\nend\n\nfunction OnXblTitleManagedStatsWriteAsync()\n    XblLeaderboardGetLeaderboardAsync(\"\", \"TestStat1\", \"XblSocialGroupType::People\", \"XblLeaderboardQueryType::TitleManagedStatBackedGlobal\")\nend\n\nlocal leaderboardQueryCompleteCount = 0\nfunction OnXblLeaderboardGetLeaderboardAsync()\n    leaderboardQueryCompleteCount = leaderboardQueryCompleteCount + 1\n    if leaderboardQueryCompleteCount == 2 then\n        test.stopTest()\n    else\n        XblLeaderboardGetLeaderboardAsync(\"\", \"TestStat1\", \"XblSocialGroupType::People\", \"XblLeaderboardQueryType::TitleManagedStatBackedSocial\")\n    end\nend\n\ntest.skip = true\ntest.TestLeaderboard2017 = function()\n    common.init(TestLeaderboard2017_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/leaderboard/leaderboard-bvt.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestLeaderboardBvt_Handler()\n    print(\"TestLeaderboardBvt_Handler\")\n    XblLeaderboardGetLeaderboardAsync()\nend\n\nfunction OnXblLeaderboardGetLeaderboardAsync()\n    print('OnXblLeaderboardGetLeaderboardAsync')\n    test.stopTest();\nend\n\ntest.isbvt = true\ntest.TestLeaderboardBvt = function()\n    common.init(TestLeaderboardBvt_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/leaderboard/leaderboard-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestLeaderboardCpp_Handler()\n    print(\"TestLeaderboardCpp_Handler\")\n    LeaderboardServiceGetLeaderboard()\nend\n\nfunction OnLeaderboardServiceGetLeaderboard()\n    print('OnLeaderboardServiceGetLeaderboard')\n    hasNext, hr = LeaderboardResultHasNextCpp()\n    if hasNext == 0 then print(\"hasNext: false\"); else print(\"hasNext: true\"); end\n    print(\"hr \" .. hr)\n    if hasNext ~= 0 then\n        LeaderboardResultGetNextCpp()\n    else\n        test.stopTest();\n    end\nend\n\nfunction OnLeaderboardResultGetNextCpp()\n    print(\"OnLeaderboardResultGetNextCpp\")\n\ttest.stopTest();\nend\n\ntest.TestLeaderboardCpp = function()\n    common.init(TestLeaderboardCpp_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/leaderboard/leaderboard.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestLeaderboard_Handler()\n    print(\"TestLeaderboard_Handler\")\n    XblLeaderboardGetLeaderboardAsync(\"TotalPuzzlesSolvedLB\")\nend\n\nlocal leaderboardQueryCompleteCount = 0\nfunction OnXblLeaderboardGetLeaderboardAsync()\n    print('OnXblLeaderboardGetLeaderboardAsync')\n    hasNext, hr = XblLeaderboardResultHasNext()\n    if hasNext == 0 then print(\"hasNext: false\"); else print(\"hasNext: true\"); end\n    print(\"hr \" .. hr)\n    if hasNext ~= 0 then\n        XblLeaderboardResultGetNextAsync()\n    else\n        leaderboardQueryCompleteCount = leaderboardQueryCompleteCount + 1\n        if leaderboardQueryCompleteCount == 2 then\n            test.stopTest();\n        else\n            XblLeaderboardGetLeaderboardAsync(\"\", \"TotalPuzzlesSolved\")\n        end\n    end\nend\n\nfunction OnXblLeaderboardResultGetNextAsync()\n    print(\"OnXblLeaderboardResultGetNextAsync\")\n    OnXblLeaderboardGetLeaderboardAsync()\nend\n\ntest.TestLeaderboard = function()\n    common.init(TestLeaderboard_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/httpHandle.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\ntest.testHttpHandle = function()\n    print(\"testHttpHandle\")\n\n    HCInitialize();\n    HCGetLibVersion();\n    HCHttpCallCreate();\n    HCHttpCallDuplicateHandle();\n    HCHttpCallGetId();\n    HCHttpCallSetTracing();\n    HCHttpCallRequestSetUrl();\n    HCHttpCallGetRequestUrl();\n    HCHttpCallRequestSetRequestBodyString();\n    HCHttpCallRequestSetHeader();\n    HCHttpCallRequestSetRetryAllowed();\n    HCHttpCallRequestSetRetryCacheId();\n    HCHttpCallRequestSetTimeout();\n    HCHttpCallRequestSetRetryDelay();\n    HCHttpCallRequestSetTimeoutWindow();\n    -- HCHttpCallRequestSetRequestBodyBytes\n    HCHttpCallCloseHandle();\n    HCCleanup();\n\n    test.stopTest();\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/httpPerform.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction OnHCHttpCallPerformAsync()\n    print(\"OnHCHttpCallPerformAsync\")\n    HCHttpCallResponseGetResponseString();\n    HCHttpCallResponseGetStatusCode();\n    HCHttpCallResponseGetNetworkErrorCode();\n    HCHttpCallResponseGetHeader();\n    HCHttpCallResponseGetNumHeaders();\n    HCHttpCallResponseGetHeaderAtIndex();\n    --HCHttpCallResponseGetResponseBodyBytes\n    --HCHttpCallResponseGetResponseBodyBytesSize\n\n    HCHttpCallCloseHandle();\n    test.stopTest();\nend\n\ntest.testHttpPerform = function()\n    print(\"testHttpPerform\")\n\n    HCInitialize();\n    --HCAddCallRoutedHandler\n    --HCRemoveCallRoutedHandler\n    HCHttpCallCreate();\n    HCHttpCallRequestSetUrl();\n    HCHttpCallGetRequestUrl();\n    HCHttpCallRequestSetRequestBodyString();\n    HCHttpCallRequestSetHeader();\n    HCHttpCallPerformAsync();\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/libHCTrace.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\ntest.testlibHCTrace = function()\n    print(\"test LHC trace\")\n\n    HCInitialize();\n\n    HCTrace();\n    HCTraceLarge();\n\n    HCCleanup();\n\n    test.stopTest();\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/manualDispatchTest.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\ncallCompleted=false;\n\nfunction OnHCHttpCallPerformAsync()\n    print(\"HCHttpCallPerformAsync Complete\")\n    HCHttpCallCloseHandle();\n    callCompleted=true;\n    SetCheckHR(1);\nend\n\nfunction OnHCCleanupAsync()\n    print(\"HCCleanupAsync Complete\")\n    StopManualDispatchThread();\n    test.assert(callCompleted)\n    test.stopTest();\nend\n\ntest.skip = true\ntest.ManualDispatchTest = function()\n    HCInitialize();\n    XTaskQueueCreate()\n    StartManualDispatchThread();\n    HCHttpCallCreate();\n    HCHttpCallRequestSetUrl();\n    HCHttpCallGetRequestUrl();\n    HCHttpCallRequestSetRequestBodyString();\n    HCHttpCallRequestSetHeader();\n    SetCheckHR(0); -- PerformAsync should fail here\n    HCHttpCallPerformAsync();\n    HCCleanupAsync();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/websocket_cleanup_while_connected.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\n-- Requires manually running local echo server\ntest.skip = true\ntest.websocketCleanupWhileConnected = function()\n    print(\"websocketCleanupWhileConnected\")\n\n    HCInitialize();\n    HCWebSocketCreate();\n    HCWebSocketConnectAsync();\nend\n\nfunction OnHCWebSocketConnectAsync()\n    print(\"OnHCWebSocketConnectAsync\")\n    HCCleanupAsync();\nend\n\nfunction OnHCWebsocketClosed()\n    print(\"OnHCWebsocketClosed\");  \n    HCWebSocketCloseHandle();\nend\n\nfunction OnHCCleanupAsync()\n    print(\"OnHCCleanupAsync\");\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/websocket_cleanup_while_connecting.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\n-- Requires manually running local echo server\ntest.skip = true\ntest.websocketCleanupWhileConnecting = function()\n    print(\"websocketCleanupWhileConnecting\")\n\n    HCInitialize();\n    HCWebSocketCreate();\n    HCWebSocketConnectAsync();\n    HCCleanupAsync();\nend\n\nfunction OnHCWebSocketConnectAsync()\n    print(\"OnHCWebSocketConnectAsync\")\n    HCWebSocketCloseHandle();\nend\n\nfunction OnHCWebsocketClosed()\n    print(\"OnHCWebsocketClosed\");  \nend\n\nfunction OnHCCleanupAsync()\n    print(\"OnHCCleanupAsync\");\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/websocket_closehandle_while_connected.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\n--Bug 35915673 Disabling websocket tests due to websocket.org no longer in service\ntest.skip = true\ntest.testWebsocketCloseHandleWhileConnected = function()\n    print(\"testWebsocketCloseHandleWhileConnected\")\n\n    HCInitialize();\n    HCWebSocketCreate();\n    HCWebSocketConnectAsync();\nend\n\nfunction OnHCWebSocketConnectAsync()\n    print(\"OnHCWebSocketConnectAsync\")\n    HCWebSocketCloseHandle();\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/websocket_disconnect_while_connecting.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\n--Bug 35915673 Disabling websocket tests due to websocket.org no longer in service\ntest.skip = true\ntest.testWebsocketDisconnectWhileConnecting = function()\n    print(\"testWebsocketDisconnectWhileConnecting\")\n\n    HCInitialize();\n    HCWebSocketCreate();\n    HCWebSocketConnectAsync();\n\tSetCheckHR(0);\n    HCWebSocketDisconnect();\n\tlocal hr = GetLastError();\n\tSetCheckHR(1);\n\tif hr ~= -2147418113 then -- -2147418113 == 0x8000FFFF == E_UNEXPECTED\n\t    test.equal(hr, 0);\n        print(\"Failure.  hr=\" .. hr)\n    end\n    HCWebSocketCloseHandle();\nend\n\nfunction OnHCWebSocketConnectAsync()\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/libHttp/websocket_send.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\n--Bug 35915673 Disabling websocket tests due to websocket.org no longer in service\ntest.skip = true\ntest.testWebsocketSend = function()\n    print(\"testWebsocketSend\")\n\n    HCInitialize();\n    HCWebSocketCreate();\n    HCWebSocketConnectAsync();\nend\n\nfunction OnHCWebSocketConnectAsync()\n    print(\"OnHCWebSocketConnectAsync\")\n    HCWebSocketSendMessageAsync();\nend\n\nfunction OnHCWebsocketMessageReceived()\n    HCWebSocketDisconnect();\nend\n\nfunction OnHCWebsocketClosed()\n    HCWebSocketCloseHandle();\n    HCCleanup();\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/misc/global_state.lua",
    "content": "\ntest = require 'u-test'\n\n-- Test that initializes XAL + XSAPI, adds a user and then shuts down\n-- without calling cleanup, making sure the global state cleanup happens correctly\ntest.skip = true\ntest.globalState = function()\n    XalPlatformWebSetEventHandler()\n    XalPlatformStorageSetEventHandlers()\n    XalInitialize()\n    XblInitialize()\n    XalAddUserWithUiAsync()\nend\n\nfunction OnXalAddUserWithUiAsync()\n    test.stopTest()\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/misc/null_task_queue.lua",
    "content": "test = require 'u-test'\n\n-- Ensure we properly handle a null process queue\n-- XblInitialize should fail with E_NO_TASK_QUEUE if the process task queue is set to nullptr\n-- and we try and get a default queue (XblInitArgs queue is set to nullptr)\n\ntest.nullTaskQueue = function()\n    local taskQueue = XTaskQueueGetCurrentProcessTaskQueue()\n    XTaskQueueSetCurrentProcessTaskQueue(0)\n    XalPlatformWebSetEventHandler()\n    XalPlatformStorageSetEventHandlers()\n    XalInitialize()\n    SetCheckHR(0)\n    XblInitialize(0)\n    local hr = GetLastError()\n    print(\"XblInitialize: hr=\" .. hr)\n    print(\"Expected:          -2147024469 (E_NO_TASK_QUEUE)\")\n    SetCheckHR(1)\n    test.equal(hr, -2147024469)\n    if hr ~= -2147024469 then -- -2147024469 == 0x800701AB == E_NO_TASK_QUEUE\n        print(\"Failure. hr=\" .. hr)\n    else\n        print(\"Succeeded.\")\n    end\n    XTaskQueueSetCurrentProcessTaskQueue(taskQueue)\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/misc/override_locale.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n-- Ensure we properly handle overriding locales\nfunction OverrideLocale()\n    print(\"OverrideLocale\");\n    XblSetOverrideLocale();\n    test.stopTest();\nend\n\ntest.OverrideLocale = function()\n    common.init(OverrideLocale)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/misc/simpletest.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\ntest.simpletest = function()\n    test.assert(2 == 2)\n    test.stopTest();\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/misc/xbox_live_context.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestXblContextCreate_Handler()\n    XblAddServiceCallRoutedHandler()\n    XblRemoveServiceCallRoutedHandler()\n    XblContextSettingsGetLongHttpTimeout()\n    XblContextSettingsSetLongHttpTimeout()\n    XblContextSettingsGetHttpRetryDelay()\n    XblContextSettingsSetHttpRetryDelay()\n    XblContextSettingsGetHttpTimeoutWindow()\n    XblContextSettingsSetHttpTimeoutWindow()\n    XblContextSettingsGetWebsocketTimeoutWindow()\n    XblContextSettingsSetWebsocketTimeoutWindow()\n    XblContextSettingsGetUseCrossPlatformQosServers()\n    XblContextSettingsSetUseCrossPlatformQosServers()\n    test.stopTest();\nend\n\ntest.TestXblContextCreate = function()\n    common.init(TestXblContextCreate_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/MP_JoinLobbyViaActivity.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MP_JoinLobbyViaActivity_Handler()\n    print(\"MP_JoinLobbyViaActivity\")\n    MultiDeviceSyncAndWait(\"MP_JoinLobbyViaActivity\");\n\n    XblRealTimeActivityActivate()\n    XblMultiplayerSetSubscriptionsEnabled()\n    XblMultiplayerAddSessionChangedHandler()\n    XblMultiplayerAddSubscriptionLostHandler()\n\n    if MultiDeviceIsHost() > 0 then \n        XblMultiplayerSessionCreateHandle()\n        XblMultiplayerSessionJoin()\n        XblMultiplayerSessionSetClosed(0)\n        XblMultiplayerSessionPropertiesSetJoinRestriction();\n        XblMultiplayerSessionPropertiesSetReadRestriction();\n        XblMultiplayerWriteSessionAsync()\n    else\n        MultiDeviceSyncAndWait(\"SessionCreated\");\n        print(\"Joining lobby of remote player. NOTE: Ensure remote is a friend or join will fail\")\n        XblMultiplayerGetActivitiesForUsersAsync();\n    end\nend\n\nfunction OnXblMultiplayerGetActivitiesForUsersAsync()\n    if MultiDeviceIsHost() > 0 then \n    else\n        print(\"Calling XblMultiplayerWriteSessionByHandleAsync\");\n        XblMultiplayerSessionCreateHandle()\n        XblMultiplayerSessionJoin()\n        XblMultiplayerWriteSessionByHandleAsync()\n    end\nend\n\nfunction OnXblMultiplayerWriteSessionByHandleAsync()\n    MultiDeviceSyncAndWait(\"SessionJoined\");\n    XblPresenceGetPresenceAsync()\nend\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    if MultiDeviceIsHost() > 0 then \n        XblMultiplayerSessionSessionReference();\n        XblMultiplayerSetActivityAsync()\n    end\nend\n\nfunction OnXblMultiplayerSetActivityAsync()\n    if MultiDeviceIsHost() > 0 then \n        MultiDeviceSyncAndWait(\"SessionCreated\");\n        MultiDeviceSyncAndWait(\"SessionJoined\");\n        XblPresenceGetPresenceAsync()\n    end\nend\n\nfunction OnXblPresenceGetPresenceAsync()\n    XblPresenceRecordGetXuid()\n    XblPresenceRecordGetDeviceRecords()\n    XblPresenceRecordGetUserState()\n    XblPresenceRecordCloseHandle()\n    test.stopTest();\nend\n\ntest.ismultidevice = true\ntest.MP_JoinLobbyViaActivity = function()\n    common.init(MP_JoinLobbyViaActivity_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/matchmaking_single_device-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestMatchmakingCpp_Handler()\n    print(\"TestMatchmakingCpp_Handler\")\n    HCTraceSetTraceToDebugger()\n    HCSettingsSetTraceLevel()\n\n    MultiplayerSessionReferenceCreateCpp();\n    MultiplayerSessionReferenceIsValidCpp();\n\n    MultiplayerSessionCreateCpp()\n\n    MultiplayerSessionJoinCpp()\n    MultiplayerServiceWriteSession()\nend\n\nlocal writeCount = 0;\nfunction OnMultiplayerServiceWriteSession()    \n    writeCount = writeCount + 1\n    if writeCount == 1 then\n        -- triggers from TestMatchmaking_Handler\n        print(\"OnMultiplayerServiceWriteSession 1\")\n        MatchmakingServiceCreateTicket();\n        MultiplayerSessionSetMatchmakingResubmitCpp()\n        MultiplayerSessionSetServerConnectionStringCandidatesCpp() \n        MultiplayerSessionSetMatchmakingServerConnectionPathCpp()\n        MultiplayerSessionSetMatchmakingTargetSessionConstantsJsonCpp()\n        MultiplayerServiceWriteSession()\n    elseif writeCount == 2 then\n        -- triggers from OnXblMultiplayerWriteSessionAsync when writeCount == 1\n        print(\"OnMultiplayerServiceWriteSession 2\")\n        MultiplayerSessionHostCandidatesCpp()\n        MultiplayerSessionMatchmakingServerCpp()\n    elseif writeCount == 3 then\n        -- triggers from OnXblMatchmakingDeleteMatchTicket\n        print(\"OnMultiplayerServiceWriteSession 3\")\n        local hr = GetLastError()\n        SetCheckHR(1)\n        if hr ~= 0 and hr ~= -2147023084 then -- --2147023084 == 0x80070714 == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n            test.equal(hr, 0);\n        end\n        test.stopTest();\n    end\nend\nfunction OnMatchmakingServiceCreateTicket()\n    print(\"OnMatchmakingServiceCreateTicket\")\n    MatchmakingServiceGetMatchTicketDetails();\nend\n\nfunction OnMatchmakingServiceGetMatchTicketDetails()\n    print(\"OnMatchmakingServiceGetMatchTicketDetails\")\n    MatchmakingServiceGetHopperStatistics();\nend\n\nfunction OnMatchmakingServiceGetHopperStatistics()\n    print(\"OnMatchmakingServiceGetHopperStatistics\")\n    MatchmakingServiceDeleteMatchTicket();\nend\n\nfunction OnMatchmakingServiceDeleteMatchTicket()\n    print(\"OnMatchmakingServiceDeleteMatchTicket\")\n    MultiplayerSessionLeaveCpp()\n    MultiplayerServiceWriteSession()\n    SetCheckHR(0)\nend\n\ntest.TestMatchmaking_SingleDevice_Cpp = function()\n    common.init(TestMatchmakingCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/matchmaking_single_device.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestMatchmaking_Handler()\n    print(\"TestMP_Handler\")\n    HCTraceSetTraceToDebugger()\n    HCSettingsSetTraceLevel()\n\n    XblMultiplayerSessionReferenceCreate();\n    XblMultiplayerSessionReferenceIsValid();\n\n    XblMultiplayerSessionCreateHandle()\n\n    XblMultiplayerSessionJoin()\n    XblMultiplayerWriteSessionAsync()\nend\n\nlocal writeCount = 0;\nfunction OnXblMultiplayerWriteSessionAsync()    \n    writeCount = writeCount + 1\n    if writeCount == 1 then\n        -- triggers from TestMatchmaking_Handler\n        print(\"OnXblMultiplayerWriteSessionAsync 1\")\n        XblMatchmakingCreateTicket();\n        XblMultiplayerSessionSetMatchmakingResubmit()\n        XblMultiplayerSessionSetServerConnectionStringCandidates() \n        XblMultiplayerSessionSetMatchmakingServerConnectionPath()\n        XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson()\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 2 then\n        -- triggers from OnXblMultiplayerWriteSessionAsync when writeCount == 1\n        print(\"OnXblMultiplayerWriteSessionAsync 2\")\n        XblMultiplayerSessionHostCandidates()\n        XblMultiplayerSessionMatchmakingServer()\n    elseif writeCount == 3 then\n        -- triggers from OnXblMatchmakingDeleteMatchTicket\n        print(\"OnXblMultiplayerWriteSessionAsync 3\")\n        local hr = GetLastError()\n        SetCheckHR(1)\n        if hr ~= 0 and hr ~= -2147023084 then -- --2147023084 == 0x80070714 == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n            test.equal(hr, 0);\n        end\n        XblMultiplayerSessionCloseHandle()\n        test.stopTest();\n    end\nend\nfunction OnXblMatchmakingCreateTicket()\n    print(\"OnXblMatchmakingCreateTicket\")\n    XblMatchmakingGetMatchTicketDetails();\nend\n\nfunction OnXblMatchmakingGetMatchTicketDetails()\n    print(\"OnXblMatchmakingGetMatchTicketDetails\")\n    XblMatchmakingGetHopperStatistics();\nend\n\nfunction OnXblMatchmakingGetHopperStatistics()\n    print(\"OnXblMatchmakingGetHopperStatistics\")\n    XblMatchmakingDeleteMatchTicket();\nend\n\nfunction OnXblMatchmakingDeleteMatchTicket()\n    print(\"OnXblMatchmakingGetHopperStatistics\")\n    XblMultiplayerSessionLeave()\n    XblMultiplayerWriteSessionAsync()\n    SetCheckHR(0)\nend\n\ntest.TestMatchmaking_SingleDevice = function()\n    common.init(TestMatchmaking_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestMPCpp_Handler()\n    print(\"TestMPCpp_Handler\")\n    HCTraceSetTraceToDebugger()\n    HCSettingsSetTraceLevel()\n\n    MultiplayerSessionReferenceCreateCpp()\n    MultiplayerSessionReferenceIsValidCpp()\n\n    MultiplayerSessionCreateCpp()\n\n    RealTimeActivityServiceActivate()\n    MultiplayerServiceMultiplayerSubscriptionsEnabled()\n    MultiplayerServiceEnableMultiplayerSubscriptions()\n    MultiplayerServiceMultiplayerSubscriptionsEnabled()\n\n    MultiplayerSessionCreateCpp()\n\n    MultiplayerServiceAddMultiplayerSessionChangedHandler()\n    MultiplayerServiceAddMultiplayerSubscriptionLostHandler()\n    MultiplayerServiceAddMultiplayerConnectionIdChangedHandler()\n    MultiplayerServiceRemoveMultiplayerSessionChangedHandler()\n    MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler()\n    MultiplayerServiceRemoveMultiplayerConnectionIdChangedHandler()\n\n    MultiplayerServiceAddMultiplayerSessionChangedHandler()\n    MultiplayerServiceAddMultiplayerSubscriptionLostHandler()\n\n    MultiplayerSessionReferenceParseFromUriPathCpp()\n\n    MultiplayerSessionJoinCpp()\n    MultiplayerServiceWriteSession()\nend\n\nlocal writeCount = 0;\n\nfunction OnMultiplayerServiceWriteSession()\n    writeCount = writeCount + 1\n    if writeCount == 1 then\n        print(\"OnMultiplayerServiceWriteSession 1\")\n        MultiplayerSessionCurrentUserCpp()\n        MultiplayerSessionSetCurrentUserMemberCustomPropertyJsonCpp()\n        MultiplayerSessionCurrentUserSetEncountersCpp()\n        MultiplayerSessionCurrentUserSetGroupsCpp()\n        MultiplayerSessionSetCurrentUserStatusCpp()\n        MultiplayerSessionSetCurrentUserSecureDeviceAddressBase64Cpp()\n        MultiplayerServiceWriteSession()\n    elseif writeCount == 2 then\n        print(\"OnMultiplayerServiceWriteSession 2\")\n        MultiplayerSessionDeleteCurrentUserMemberCustomPropertyJsonCpp()\n\n        MultiplayerSessionSetClosedCpp()\n        MultiplayerSessionSetSessionCustomPropertyJsonCpp()\n        MultiplayerSessionSetAllocateCloudComputeCpp()\n        MultiplayerSessionSetHostDeviceTokenCpp()\n        MultiplayerSessionSetLockedCpp()\n        MultiplayerSessionSetSessionChangeSubscriptionCpp()\n        \n        MultiplayerSessionPropertiesSetJoinRestrictionCpp()\n        MultiplayerSessionPropertiesSetReadRestrictionCpp()\n        MultiplayerSessionPropertiesSetKeywordsCpp()\n\n        MultiplayerServiceWriteSession()\n    elseif writeCount == 3 then\n        print(\"OnMultiplayerServiceWriteSession 3\")\n        MultiplayerSessionDeleteSessionCustomPropertyJsonCpp()\n\n        MultiplayerSessionEtagCpp()\n        MultiplayerSessionGetInfoCpp()\n        MultiplayerSessionGetInitializationInfoCpp()\n        MultiplayerSessionGetMemberCpp()\n        MultiplayerSessionMembersCpp()\n        MultiplayerSessionMembersAcceptedCpp()\n        MultiplayerSessionServersJsonCpp()\n        MultiplayerSessionRoleTypesCpp()\n        MultiplayerSessionSessionConstantsCpp()\n        MultiplayerSessionSessionPropertiesCpp()\n        MultiplayerSessionSessionReferenceCpp()\n        MultiplayerSessionSubscribedChangeTypesCpp()\n        MultiplayerSessionTimeOfSessionCpp()\n\n        MultiplayerServiceWriteSession()\n    elseif writeCount == 4 then\n        print(\"OnMultiplayerServiceWriteSession 4\")\n        MultiplayerSessionLeaveCpp()\n        MultiplayerServiceWriteSession()\n        SetCheckHR(0)\n    elseif writeCount == 5 then\n        print(\"OnMultiplayerServiceWriteSession 5\")\n        local hr = GetLastError()\n        SetCheckHR(1)\n        if hr ~= 0 and hr ~= -2147023084 then -- --2147023084 == 0x80070714 == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n            test.equal(hr, 0);\n        end\n        MultiplayerSessionCreateCpp()\n        MultiplayerSessionJoinCpp()\n        MultiplayerServiceWriteSession()\n    elseif writeCount == 6 then\n        print(\"OnMultiplayerServiceWriteSession 6\")\n        MultiplayerServiceWriteSession()\n    elseif writeCount == 7 then\n        print(\"OnMultiplayerServiceWriteSession 7\")\n        MultiplayerServiceSetActivity()\n    elseif writeCount == 8 then\n        print(\"OnMultiplayerServiceWriteSession 8\")\n        local hr = GetLastError()\n        SetCheckHR(1)\n        if hr ~= 0 and hr ~= -2147023084 then -- --2147023084 == 0x80070714 == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n            test.equal(hr, 0);\n        end\n        MultiplayerServiceRemoveMultiplayerSessionChangedHandler()\n        MultiplayerServiceRemoveMultiplayerSubscriptionLostHandler()\n        test.stopTest();\n    end\nend\n\nfunction OnMultiplayerServiceSetActivity()\n    print(\"OnMultiplayerServiceSetActivity\")\n    MultiplayerServiceClearActivity()\nend\n\nfunction OnMultiplayerServiceClearActivity()\n    print(\"OnMultiplayerServiceClearActivity\")\n    MultiplayerServiceGetCurrentSession()\nend\n\nfunction OnMultiplayerServiceGetCurrentSession()\n    print(\"OnMultiplayerServiceGetCurrentSession\")\n\n    MultiplayerSessionHostCandidatesCpp()\n    MultiplayerSessionMatchmakingServerCpp()\n    MultiplayerSessionEtagCpp()\n    MultiplayerSessionGetInfoCpp()\n    MultiplayerSessionGetInitializationInfoCpp()\n    MultiplayerSessionGetMemberCpp()\n    MultiplayerSessionMembersCpp()\n    MultiplayerSessionMembersAcceptedCpp()\n    MultiplayerSessionServersJsonCpp()\n    MultiplayerSessionRoleTypesCpp()\n    MultiplayerSessionSessionConstantsCpp()\n    MultiplayerSessionSessionPropertiesCpp()\n    MultiplayerSessionSessionReferenceCpp()\n    MultiplayerSessionSubscribedChangeTypesCpp()\n    MultiplayerSessionTimeOfSessionCpp()\n\n    MultiplayerSessionCompareCpp()\n\n    MultiplayerServiceGetSessions()\nend\n\nfunction OnMultiplayerServiceGetSessions()\n    print('OnMultiplayerServiceGetSessions')\n    MultiplayerServiceGetActivitiesForUsers()\nend\n\nfunction OnMultiplayerServiceGetActivitiesForUsers()\n    print('OnMultiplayerServiceGetActivitiesForUsers')\n    MultiplayerServiceGetActivitiesForSocialGroup()\nend\n\nfunction OnMultiplayerServiceGetActivitiesForSocialGroup()\n    print('OnMultiplayerServiceGetActivitiesForSocialGroup')\n    --MultiplayerServiceWriteSessionByHandle()\n\tMultiplayerServiceSendInvites()\nend\n\nfunction OnMultiplayerServiceWriteSessionByHandle()\n    print('OnMultiplayerServiceWriteSessionByHandle')\n    MultiplayerServiceGetCurrentSessionByHandle()\nend\n\nfunction OnMultiplayerServiceGetCurrentSessionByHandle()\n    print('OnMultiplayerServiceGetCurrentSessionByHandle')\n    MultiplayerServiceSendInvites()\nend\n\nfunction OnMultiplayerServiceSendInvites()\n    print('OnMultiplayerServiceSendInvites')\n    MultiplayerSessionLeaveCpp()\n    MultiplayerServiceWriteSession()\n    SetCheckHR(0)\nend\n\ntest.TestMPCpp = function()\n    common.init(TestMPCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestMP_Handler()\n    print(\"TestMP_Handler\")\n    HCTraceSetTraceToDebugger()\n    HCSettingsSetTraceLevel()\n    XblFormatSecureDeviceAddress()\n\n    XblMultiplayerSessionReferenceCreate()\n    XblMultiplayerSessionReferenceIsValid()\n\n    XblMultiplayerSessionCreateHandle()\n    XblMultiplayerSessionDuplicateHandle()\n    XblMultiplayerSessionCloseHandle()\n\n    --XblRealTimeActivityActivate()\n    XblMultiplayerSubscriptionsEnabled()\n    --XblMultiplayerSetSubscriptionsEnabled()\n    XblMultiplayerSubscriptionsEnabled()\n\n    XblMultiplayerSessionCreateHandle()\n\n    -- XblMultiplayerSessionSetInitializationSucceeded() --The session's 'initializationSucceeded' property can only be set during the 'evaluating' stage of initialization.\n    -- XblMultiplayerSessionSetRawServersJson() -- The request body can't contain a 'servers' collection because the authentication principal doesn't include a server.\n\n    -- The constant field **** is specified in the request, but the value conflicts with the one in the session.\n    --XblMultiplayerSessionConstantsSetMaxMembersInSession()\n    --XblMultiplayerSessionConstantsSetCapabilities()\n    --XblMultiplayerSessionConstantsSetCloudComputePackageJson()\n    --XblMultiplayerSessionConstantsSetMeasurementServerAddressesJson()\n    --XblMultiplayerSessionConstantsSetMemberInitialization()\n    --XblMultiplayerSessionConstantsSetPeerToHostRequirements()\n    --XblMultiplayerSessionConstantsSetPeerToPeerRequirements()\n    --XblMultiplayerSessionConstantsSetQosConnectivityMetrics()\n    --XblMultiplayerSessionConstantsSetTimeouts()\n    --XblMultiplayerSessionConstantsSetVisibility()\n\n    XblMultiplayerAddSessionChangedHandler()\n    XblMultiplayerAddSubscriptionLostHandler()\n    XblMultiplayerRemoveSessionChangedHandler()\n    XblMultiplayerRemoveSubscriptionLostHandler()\n\n    XblMultiplayerAddSessionChangedHandler()\n    XblMultiplayerAddSubscriptionLostHandler()\n\n    XblMultiplayerSessionReferenceParseFromUriPath()\n\n    XblMultiplayerSessionJoin()\n    XblMultiplayerWriteSessionAsync()\nend\n\nlocal writeCount = 0;\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    writeCount = writeCount + 1\n    if writeCount == 1 then\n        print(\"OnXblMultiplayerWriteSessionAsync 1\")\n\n        XblMultiplayerSessionCurrentUser()\n        XblMultiplayerSessionCurrentUserSetCustomPropertyJson()\n        XblMultiplayerSessionCurrentUserSetEncounters()\n        XblMultiplayerSessionCurrentUserSetGroups()\n        XblMultiplayerSessionCurrentUserSetStatus()\n        XblMultiplayerSessionCurrentUserSetMembersInGroup()\n        XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64()\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 2 then\n        print(\"OnXblMultiplayerWriteSessionAsync 2\")\n        XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson()\n\n        XblMultiplayerSessionSetClosed()\n        XblMultiplayerSessionSetCustomPropertyJson()\n        XblMultiplayerSessionSetAllocateCloudCompute()\n        XblMultiplayerSessionSetHostDeviceToken()\n        XblMultiplayerSessionSetLocked()\n        XblMultiplayerSessionSetSessionChangeSubscription()\n        \n        XblMultiplayerSessionPropertiesSetJoinRestriction()\n        XblMultiplayerSessionPropertiesSetReadRestriction()\n        XblMultiplayerSessionPropertiesSetKeywords()\n        -- XblMultiplayerSessionCurrentUserSetRoles() -- A member's 'roles' section contains a role type with an invalid name: roleTypeName1\n        -- XblMultiplayerSessionSetMutableRoleSettings() -- need properly formated JSON to call\n        -- XblMultiplayerSessionPropertiesSetReadRestriction() -- Invalid session 'readRestriction' provided, cannot be set to none on sessions with the 'userAuthorizationStyle' capability.\n        -- XblMultiplayerSessionPropertiesSetTurnCollection() -- The session's 'turn' property must be an array of numbers representing the indicies of the member(s) in the session whose turn it is.\n        --XblMultiplayerSessionCurrentUserSetQosMeasurements() -- Invalid member 'measurements' provided, measurements can only be uploaded if session 'metrics' are configured.\n        --XblMultiplayerSessionCurrentUserSetServerQosMeasurements() -- Invalid member property serverMeasurements 'measurements1' provided, must be a JSON object.\n\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 3 then\n        print(\"OnXblMultiplayerWriteSessionAsync 3\")\n\n        XblMultiplayerSessionSetSessionChangeSubscription(0)\n\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 4 then\n        print(\"OnXblMultiplayerWriteSessionAsync 4\")\n\n        XblMultiplayerSessionDeleteCustomPropertyJson()\n\n        XblMultiplayerSessionEtag()\n        XblMultiplayerSessionGetInfo()\n        XblMultiplayerSessionGetInitializationInfo()\n        XblMultiplayerSessionGetMember()\n        XblMultiplayerSessionGetRoleByName()\n        XblMultiplayerSessionMembers()\n        XblMultiplayerSessionMembersAccepted()\n        XblMultiplayerSessionRawServersJson()\n        XblMultiplayerSessionRoleTypes()\n        XblMultiplayerSessionSessionConstants()\n        XblMultiplayerSessionSessionProperties()\n        XblMultiplayerSessionSessionReference()\n        XblMultiplayerSessionSubscribedChangeTypes()\n        XblMultiplayerSessionTimeOfSession()\n\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 5 then\n        print(\"OnXblMultiplayerWriteSessionAsync 5\")\n        XblMultiplayerSessionLeave()\n        XblMultiplayerWriteSessionAsync()\n        SetCheckHR(0)\n    elseif writeCount == 6 then\n        local hr = GetLastError()\n        SetCheckHR(1)\n        if hr ~= 0 and hr ~= -2147023084 then -- --2147023084 == 0x80070714 == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n            test.equal(hr, 0);\n        end\n        XblMultiplayerSessionCloseHandle()\n        print(\"OnXblMultiplayerWriteSessionAsync 6\")\n        XblMultiplayerSessionCreateHandle()\n        XblMultiplayerSessionJoin()\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 7 then\n        print(\"OnXblMultiplayerWriteSessionAsync 7\")\n        -- XblMultiplayerSessionAddMemberReservation() -- The requested session cannot be accessed. The calling user must have the multiplayer privilege and must be a member of the session if the session either isn't open or has a join restriction on it that the user doesn't satisfy, multi-user requests aren't allowed for large sessions, banned xuids can't access the session, users must have the communicate permission to access sessions that require it, users must qualify to access club sessions based on the club rules, and devices other than an Xbox One can only access sessions with user-style authorization.\n        XblMultiplayerWriteSessionAsync()\n    elseif writeCount == 8 then\n        print(\"OnXblMultiplayerWriteSessionAsync 8\")\n        XblMultiplayerSetActivityAsync()\n    elseif writeCount == 9 then\n        print(\"OnXblMultiplayerWriteSessionAsync 9\")\n        local hr = GetLastError()\n        SetCheckHR(1)\n        if hr ~= 0 and hr ~= -2147023084 then -- --2147023084 == 0x80070714 == __HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND)\n            test.equal(hr, 0);\n        end\n        XblMultiplayerSessionCloseHandle()\n        XblMultiplayerRemoveSessionChangedHandler()\n        XblMultiplayerRemoveSubscriptionLostHandler()\n        test.stopTest();\n    end\nend\n\nfunction OnXblMultiplayerSetActivityAsync()\n    print(\"OnXblMultiplayerSetActivityAsync\")\n    XblMultiplayerClearActivityAsync()\nend\n\nfunction OnXblMultiplayerClearActivityAsync()\n    print(\"OnXblMultiplayerClearActivityAsync\")\n    XblMultiplayerGetSessionAsync()\nend\n\nfunction OnXblMultiplayerGetSessionAsync()\n    print(\"OnXblMultiplayerGetSessionAsync\")\n\n    XblMultiplayerSessionHostCandidates()\n    XblMultiplayerSessionMatchmakingServer()\n    XblMultiplayerSessionEtag()\n    XblMultiplayerSessionGetInfo()\n    XblMultiplayerSessionGetInitializationInfo()\n    XblMultiplayerSessionGetMember()\n    XblMultiplayerSessionGetRoleByName()\n    XblMultiplayerSessionMembers()\n    XblMultiplayerSessionMembersAccepted()\n    XblMultiplayerSessionRawServersJson()\n    XblMultiplayerSessionRoleTypes()\n    XblMultiplayerSessionSessionConstants()\n    XblMultiplayerSessionSessionProperties()\n    XblMultiplayerSessionSessionReference()\n    XblMultiplayerSessionSubscribedChangeTypes()\n    XblMultiplayerSessionTimeOfSession()\n\n    XblMultiplayerSessionCompare();\n\n    XblMultiplayerQuerySessionsAsync()\nend\n\nfunction OnXblMultiplayerQuerySessionsAsync()\n    print('OnXblMultiplayerQuerySessionsAsync')\n    XblMultiplayerGetActivitiesForUsersAsync()\nend\n\nfunction OnXblMultiplayerGetActivitiesForUsersAsync()\n    print('OnXblMultiplayerGetActivitiesForUsersAsync')\n    XblMultiplayerGetActivitiesWithPropertiesForUsersAsync()\nend\n\nfunction OnXblMultiplayerGetActivitiesWithPropertiesForUsersAsync()\n    print('OnXblMultiplayerGetActivitiesWithPropertiesForUsersAsync')\n    XblMultiplayerGetActivitiesForSocialGroupAsync()\nend\n\nfunction OnXblMultiplayerGetActivitiesForSocialGroupAsyncRetry()\n    print('OnXblMultiplayerGetActivitiesForSocialGroupAsyncRetry')\n    XblMultiplayerGetActivitiesForSocialGroupAsync()\nend\n\nfunction OnXblMultiplayerGetActivitiesForSocialGroupAsync()\n    print('OnXblMultiplayerGetActivitiesForSocialGroupAsync')\n    XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync()\nend\n\nfunction OnXblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync()\n    print('OnXblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync')\n    XblMultiplayerSendInvitesAsync()\n    -- XblMultiplayerWriteSessionByHandleAsync() -- The request URI contains an invalid handle ID. It may contain invalid characters or be all zeroes.\nend\n\nfunction OnXblMultiplayerWriteSessionByHandleAsync()\n    print('OnXblMultiplayerWriteSessionByHandleAsync')\n    XblMultiplayerGetSessionByHandleAsync()\nend\n\nfunction OnXblMultiplayerGetSessionByHandleAsync()\n    print('OnXblMultiplayerGetSessionByHandleAsync')\n    XblMultiplayerSendInvitesAsync()\nend\n\nfunction OnXblMultiplayerSendInvitesAsync()\n    print('OnXblMultiplayerSendInvitesAsync')\n    XblMultiplayerSessionLeave()\n    XblMultiplayerWriteSessionAsync()\n    SetCheckHR(0)\nend\n\ntest.TestMP = function()\n    common.init(TestMP_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp_multiple_contexts.lua",
    "content": "local xblContext = 0\n\nfunction TestFunc()\n    XblMultiplayerSetSubscriptionsEnabled(1)\n    XblMultiplayerSessionReferenceCreate()\n    XblMultiplayerSessionCreateHandle()\n    XblMultiplayerSessionJoin()\n    XblMultiplayerWriteSessionAsync()\nend\n\nlocal writeCount = 0;\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    writeCount = writeCount + 1\n    if writeCount == 1 then\n        print(\"OnXblMultiplayerWriteSessionAsync 1\")\n        -- first write made using default XblContext should complete successfully\n        -- change the session and attempt to write with second XblContext\n        xblContext = XblContextCreateHandle()\n        XblMultiplayerSetSubscriptionsEnabled(1, xblContext)\n        XblMultiplayerSessionCurrentUserSetStatus()\n        XblMultiplayerWriteSessionAsync(0, xblContext)\n    elseif writeCount == 2 then\n        print(\"OnXblMultiplayerWriteSessionAsync 2\")\n        XblMultiplayerSessionCloseHandle()\n        XblContextCloseHandle(xblContext)\n        test.stopTest();\n    end\nend\n\ntest.TestMPMultipleContexts = function()\n    common.init(TestFunc)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp_partial_invite_flow.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestMPInviteFlow_Handler()\n    print(\"TestMPInviteFlow_Handler\")\n    XblMultiplayerSessionReferenceCreate();\n    session, hr = XblMultiplayerSessionCreateHandle(\"00000000-0000-0000-0000-000076029b4d\", \"MinGameSession\", \"\", 0)\n    XblMultiplayerSessionJoin(session)\n    XblMultiplayerWriteSessionAsync(session)\nend\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    XblMultiplayerSendInvitesAsync()\nend\n\nfunction OnXblMultiplayerSendInvitesAsync()\n    XblMultiplayerGetSessionByHandleAsync()\nend\n\nfunction OnXblMultiplayerGetSessionByHandleAsync()\n    XblMultiplayerSessionCloseHandle()\n    test.stopTest();\nend\n\ntest.TestMPInviteFlow = function()\n    common.init(TestMPInviteFlow_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp_search-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestMPSearchCpp_Handler()\n    print(\"TestMPSearchCpp_Handler\")\n    MultiplayerSessionReferenceCreateCpp()\n    MultiplayerSessionCreateCpp()\n    MultiplayerSessionJoinCpp()\n    MultiplayerSessionSetSessionCustomPropertyJsonCpp()\n    MultiplayerServiceWriteSession()\nend\n\nfunction OnMultiplayerServiceWriteSession()\n    MultiplayerServiceSetSearchHandle()\nend\n\nfunction OnMultiplayerServiceSetSearchHandle()\n    MultiplayerServiceGetSearchHandles()\nend\n\nfunction OnMultiplayerServiceGetSearchHandles()\n    MultiplayerSearchHandleDetailsSessionOwnerXuids()\n    MultiplayerSearchHandleDetailsTags()\n    MultiplayerSearchHandleDetailsStringsMetadata()\n    MultiplayerSearchHandleDetailsNumbersMetadata()\n    MultiplayerSearchHandleDetailsVisibility()\n    MultiplayerSearchHandleDetailsJoinRestriction()\n    MultiplayerSearchHandleDetailsClosed()\n    MultiplayerSearchHandleDetailsMemberCounts()\n    MultiplayerSearchHandleDetailsHandleCreationTime()\n    MultiplayerSearchHandleDetailsCustomSessionPropertiesJson()\n    MultiplayerSearchHandleDetailsCloseHandle()\n    test.stopTest();\nend\n\ntest.TestMPSearchCpp = function()\n    common.init(TestMPSearchCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp_search.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestMPSearch_Handler()\n    print(\"TestMPSearch_Handler\")\n    XblMultiplayerSessionReferenceCreate()\n    XblMultiplayerSessionCreateHandle()\n    XblMultiplayerSessionJoin()\n    XblMultiplayerSessionSetCustomPropertyJson()\n    XblMultiplayerWriteSessionAsync()\nend\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    XblMultiplayerCreateSearchHandleAsync()\nend\n\nfunction OnXblMultiplayerCreateSearchHandleAsync()\n    XblMultiplayerSearchHandleGetSessionOwnerXuids()\n    XblMultiplayerSearchHandleGetTags()\n    XblMultiplayerSearchHandleGetStringAttributes()\n    XblMultiplayerSearchHandleGetNumberAttributes()\n    XblMultiplayerSearchHandleGetVisibility()\n    XblMultiplayerSearchHandleGetJoinRestriction()\n    XblMultiplayerSearchHandleGetSessionClosed()\n    XblMultiplayerSearchHandleGetMemberCounts()\n    XblMultiplayerSearchHandleGetCreationTime()\n    XblMultiplayerSearchHandleGetCustomSessionPropertiesJson()\n    XblMultiplayerGetSearchHandlesAsync()\nend\n\nfunction OnXblMultiplayerGetSearchHandlesAsync()\n    XblMultiplayerDeleteSearchHandleAsync()\nend\n\nfunction OnXblMultiplayerDeleteSearchHandleAsync()\n    XblMultiplayerSearchHandleCloseHandle()\n    XblMultiplayerSessionCloseHandle()\n    test.stopTest();\nend\n\ntest.TestMPSearch = function()\n    common.init(TestMPSearch_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp_transfer-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestMPTransferCpp_Handler()\n    print(\"TestMPTransferCpp_Handler\")\n    session1, hr = MultiplayerSessionCreateCpp(\"00000000-0000-0000-0000-000076029b4d\", \"MinGameSession\", \"\", 0)\n    session2, hr = MultiplayerSessionCreateCpp(\"00000000-0000-0000-0000-000076029b4d\", \"MinGameSession\", \"\", 1)\n    MultiplayerSessionJoinCpp(session1)\n    MultiplayerSessionJoinCpp(session2)\n    MultiplayerServiceWriteSession(session1)\n    MultiplayerServiceWriteSession(session2)\nend\n\nlocal sessionsWritten = 0\n\nfunction OnMultiplayerServiceWriteSession()\n    sessionsWritten = sessionsWritten + 1;\n    if sessionsWritten == 2 then\n        MultiplayerServiceSetTransferHandle(session1, session2)\n    end\nend\n\nfunction OnMultiplayerServiceSetTransferHandle()\n    test.stopTest();\nend\n\ntest.TestMPTransferCpp = function()\n    common.init(TestMPTransferCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/mp/mp_transfer.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction TestMPTransfer_Handler()\n    print(\"TestMPSearch_Handler\")\n    session1, hr = XblMultiplayerSessionCreateHandle(\"00000000-0000-0000-0000-000076029b4d\", \"MinGameSession\", \"\", 0)\n    session2, hr = XblMultiplayerSessionCreateHandle(\"00000000-0000-0000-0000-000076029b4d\", \"MinGameSession\", \"\", 1)\n    XblMultiplayerSessionJoin(session1)\n    XblMultiplayerSessionJoin(session2)\n    XblMultiplayerWriteSessionAsync(session1)\n    XblMultiplayerWriteSessionAsync(session2)\nend\n\nlocal sessionsWritten = 0\n\nfunction OnXblMultiplayerWriteSessionAsync()\n    sessionsWritten = sessionsWritten + 1;\n    if sessionsWritten == 2 then\n        XblMultiplayerSetTransferHandleAsync(session1, session2)\n    end\nend\n\nfunction OnXblMultiplayerSetTransferHandleAsync()\n    XblMultiplayerSessionCloseHandle(session1)\n    XblMultiplayerSessionCloseHandle(session2)\n    test.stopTest();\nend\n\ntest.TestMPTransfer = function()\n    common.init(TestMPTransfer_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_Invite.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MPM_InviteTest_Handler()\n    print(\"MPM_InviteTest_Handler\")\n    MultiDeviceSyncAndWait(\"MPM_InviteTest_Handler\");\n\n    XblMultiplayerManagerInitialize();\n    StartDoWorkLoop();\n    XblMultiplayerManagerLobbySessionAddLocalUser();\nend\n\nfunction OnXGameUiShowSendGameInviteAsync()\n    print(\"OnXGameUiShowSendGameInviteAsync\");\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    if MultiDeviceIsHost() then \n        XblMultiplayerManagerSetJoinability();\n    else\n        XblMultiplayerManagerJoinGame();\n    end\nend\n\n function OnXblMultiplayerEventType_JoinabilityStateChanged()\n    if MultiDeviceIsHost() then \n        XGameUiShowSendGameInviteAsyncToMPMLobby(); -- TODO change to non-ui version\n    end\n end\n\nfunction OnXblMultiplayerEventType_JoinGameCompleted()\n    MultiDeviceSyncAndWait(\"OnXblMultiplayerEventType_JoinGameCompleted\");\n\n    test.stopTest();\nend\n\nfunction OnXblMultiplayerEventType_MemberJoined()\n    XblMultiplayerManagerGameSessionMembers();\nend\n\ntest.skip = true\ntest.ismultidevice = true\ntest.MPM_InviteTest = function()\n    common.init(MPM_InviteTest_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_InviteUI.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MPM_InviteUITest_Handler()\n    print(\"MPM_InviteUITest_Handler\")\n    MultiDeviceSyncAndWait(\"MPM_InviteUITest_Handler\");\n\n    XblMultiplayerManagerInitialize();\n    StartDoWorkLoop();\n    XblMultiplayerManagerLobbySessionAddLocalUser();\nend\n\nfunction OnXGameUiShowSendGameInviteAsync()\n    print(\"OnXGameUiShowSendGameInviteAsync\");\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    if MultiDeviceIsHost() then \n        XblMultiplayerManagerSetJoinability();\n    else\n        XblMultiplayerManagerJoinGame();\n    end\nend\n\n function OnXblMultiplayerEventType_JoinabilityStateChanged()\n    if MultiDeviceIsHost() then \n        XGameUiShowSendGameInviteAsyncToMPMLobby();\n    end\n end\n\nfunction OnXblMultiplayerEventType_JoinGameCompleted()\n    MultiDeviceSyncAndWait(\"OnXblMultiplayerEventType_JoinGameCompleted\");\n\n    test.stopTest();\nend\n\nfunction OnXblMultiplayerEventType_MemberJoined()\n    XblMultiplayerManagerGameSessionMembers();\nend\n\ntest.skip = true\ntest.ismultidevice = true\ntest.MPM_InviteUITest = function()\n    common.init(MPM_InviteUITest_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_JoinFixedGameSession.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MPM_JoinFixedGameSession_Handler()\n    print(\"MPM_JoinFixedGameSession\")\n    MultiDeviceSyncAndWait(\"MPM_JoinFixedGameSession\");\n\n    XblMultiplayerManagerInitialize();\n    StartDoWorkLoop();\n    XblMultiplayerManagerLobbySessionAddLocalUser();\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    if MultiDeviceIsHost() > 0 then \n        local sessionName = MultiDeviceGetRemoteXuid() .. \"-session\";\n        MultiDeviceSetLocalState(\"session\", sessionName);\n        MultiDeviceSyncAndWait(\"SessionName\");\n        XblMultiplayerManagerJoinGame(sessionName);\n    else\n        MultiDeviceSyncAndWait(\"SessionName\");\n        local sessionName = MultiDeviceGetRemoteState(\"session\");\n        XblMultiplayerManagerJoinGame(sessionName);\n    end    \nend\n\nfunction OnXblMultiplayerEventType_MemberJoined()\n    MultiDeviceSyncAndWait(\"MemberJoinedLobby\");\n    \n    test.stopTest();\nend\n\ntest.ismultidevice = true\ntest.MPM_JoinFixedGameSession = function()\n    common.init(MPM_JoinFixedGameSession_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_JoinLobbyViaActivity.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MPM_JoinLobbyViaActivity_Handler()\n    print(\"MPM_JoinLobbyViaActivity\")\n    MultiDeviceSyncAndWait(\"MPM_JoinLobbyViaActivity\");\n\n    XblMultiplayerManagerInitialize();\n    StartDoWorkLoop();\n\n    if MultiDeviceIsHost() > 0 then \n        XblMultiplayerManagerLobbySessionAddLocalUser();\n        XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\"1111111111111111\");\n    else\n        MultiDeviceWaitTillRemoteState(\"stage\", \"JoinabilityStateChanged\");\n        print(\"Joining lobby of remote player. NOTE: Ensure remote is a friend or join will fail\")\n        XblMultiplayerManagerJoinLobbyViaActivity();\n        XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\"2222222222222222\");\n    end\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    if MultiDeviceIsHost() > 0 then \n        XblMultiplayerManagerSetJoinability(); -- sets it to XblMultiplayerJoinability::JoinableByFriends\n    end\nend\n\nfunction OnXblMultiplayerEventType_JoinabilityStateChanged()\n    XblMultiplayerManagerJoinability(); -- not needed just for coverage\n    if MultiDeviceIsHost() > 0 then \n        XblMultiplayerManagerLobbySessionSetSynchronizedHost();\n    end\nend\n\nfunction OnXblMultiplayerEventType_SynchronizedHostWriteCompleted()\n    MultiDeviceSetLocalState(\"stage\", \"JoinabilityStateChanged\");\n    -- waiting till we get a OnXblMultiplayerEventType_JoinLobbyCompleted\nend\n\nfunction OnXblMultiplayerEventType_JoinLobbyCompleted()\n    MultiDeviceSyncAndWait(\"MemberJoinedLobby\");\n    XblMultiplayerManagerLobbySessionIsHost();\n    XblMultiplayerManagerLobbySessionHost();\nend\n\nfunction OnXblMultiplayerEventType_MemberJoined()\n    MultiDeviceSyncAndWait(\"MemberJoinedLobby\");\n    XblMultiplayerManagerLobbySessionIsHost();\n    XblMultiplayerManagerLobbySessionHost();\n\n    print(\"XblMultiplayerManagerLobbySessionSetProperties as host\")\n    XblMultiplayerManagerLobbySessionSetProperties();\nend\n\nfunction OnXblMultiplayerEventType_LocalMemberPropertyWriteCompleted()\n    print('OnXblMultiplayerEventType_LocalMemberPropertyWriteCompleted');\n\n    print(\"Joining game from lobby\")\n    XblMultiplayerManagerJoinGameFromLobby();\nend\n\nfunction OnXblMultiplayerEventType_MemberPropertyChanged()\n    print('OnXblMultiplayerEventType_MemberPropertyChanged');\n\n    print(\"Joining game from lobby\")\n    XblMultiplayerManagerJoinGameFromLobby();\nend\n\nfunction OnXblMultiplayerEventType_SessionPropertyWriteCompleted()\n    print('OnXblMultiplayerEventType_SessionPropertyWriteCompleted');\n    MultiDeviceSyncAndWait(\"MemberJoinedLobbyPropsChanged\");\n\n    print(\"XblMultiplayerManagerLobbySessionSetLocalMemberProperties\")\n    XblMultiplayerManagerLobbySessionSetLocalMemberProperties();\nend\n\nfunction OnXblMultiplayerEventType_LobbySessionPropertyChanged()\n    print('OnXblMultiplayerEventType_LobbySessionPropertyChanged');\n    MultiDeviceSyncAndWait(\"MemberJoinedLobbyPropsChanged\");\nend\n\nfunction OnXblMultiplayerEventType_MemberLeft()\n    if MultiDeviceIsHost() > 0 then \n        print(\"OnXblMultiplayerEventType_MemberLeft as host\")\n        MultiDeviceSyncAndWait(\"PeerUserRemoved\");\n        print(\"Removing local user from MPM\")\n        XblMultiplayerManagerLobbySessionRemoveLocalUser();\n    else \n        print(\"OnXblMultiplayerEventType_MemberLeft as client\")\n    end\n    \nend\n\nfunction OnXblMultiplayerEventType_JoinGameCompleted()\n    MultiDeviceSyncAndWait(\"JoinGameCompleted\");\n\t\n    if MultiDeviceIsHost() == 0 then \n        print(\"Removing local user from MPM\")\n        XblMultiplayerManagerLobbySessionRemoveLocalUser();\n    end\nend\n\nfunction OnXblMultiplayerEventType_UserRemoved()\n    if MultiDeviceIsHost() > 0 then \n        test.stopTest();\n    else\n        MultiDeviceSyncAndWait(\"PeerUserRemoved\");\n        test.stopTest();\n    end\nend\n\ntest.ismultidevice = true\ntest.MPM_JoinLobbyViaActivity = function()\n    common.init(MPM_JoinLobbyViaActivity_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_Match.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MPM_Match_Handler()\n    print(\"MPM_Match\")\n    MultiDeviceSyncAndWait(\"MPM_Match\");\n\n    XblMultiplayerManagerInitialize();\n    StartDoWorkLoop();\n    XblMultiplayerManagerLobbySessionAddLocalUser();\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    MultiDeviceSyncAndWait(\"UserAdded\");\n    XblMultiplayerManagerFindMatch(\"PlayerSkillNoQoS\");\nend\n\nfunction OnXblMultiplayerEventType_FindMatchCompleted()\n    VerifyMPMGameSessionProperites();\n    VerifyMPMLobbySessionProperites();\n    MultiDeviceSyncAndWait(\"FindMatch\");\n\n    XblMultiplayerManagerLeaveGame()\nend\n\nfunction OnXblMultiplayerEventType_JoinGameCompleted()\n    MultiDeviceSyncAndWait(\"JoinGameCompleted\");\n\n    test.stopTest();\nend\n\nfunction OnXblMultiplayerEventType_LeaveGameCompleted()\n    MultiDeviceSyncAndWait(\"LeaveGameCompleted\");\n\n    test.stopTest();\nend\n\ntest.ismultidevice = true\ntest.MPM_Match = function()\n    common.init(MPM_Match_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_SingleDevice_JoinLeaveGame.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction MPM_SingleDevice_JoinLeaveGame_Handler()\n    print(\"MPM_SingleDevice_JoinLeaveGame_Handler\")\n    XblMultiplayerManagerInitialize();\n    XblMultiplayerManagerLobbySessionAddLocalUser();\n    XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(\"1234567890\");\n    StartDoWorkLoop();\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_UserAdded\")\n    XblMultiplayerManagerLobbySessionCorrelationId();\n    XblMultiplayerManagerLobbySessionLocalMembers();\n    XblMultiplayerManagerJoinability();\n\n    XblMultiplayerManagerJoinGameFromLobby();\nend\n\nfunction OnXblMultiplayerEventType_JoinGameCompleted()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_JoinGameCompleted\")\n\n    XblMultiplayerManagerGameSessionActive()\n    XblMultiplayerManagerGameSessionCorrelationId();\n    XblMultiplayerManagerGameSessionMembers();\n    XblMultiplayerManagerGameSessionConstants();\n    XblMultiplayerManagerGameSessionSessionReference();\n\n    XblMultiplayerManagerLeaveGame();\nend\n\nfunction OnXblMultiplayerEventType_LeaveGameCompleted()\n    print(\" \");\n    print(\"Recived OnXblMultiplayerEventType_LeaveGameCompleted\")\n    XblMultiplayerManagerLobbySessionRemoveLocalUser();\nend\n\nfunction OnXblMultiplayerEventType_UserRemoved()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_UserRemoved\")\n    test.stopTest();\nend\n\ntest.MPM_SingleDevice_JoinLeaveGame = function()\n    common.init(MPM_SingleDevice_JoinLeaveGame_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/multiplayerManager/MPM_SingleDevice_SyncHostWrite.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nmaxRetries = 3\nsyncGameHostRetries = 0\nsyncGamePropRetries = 0\n\nfunction MPM_SingleDeviceWriteTest_Handler()\n    print(\"MPM_SingleDeviceWriteTest_Handler\")\n    XblMultiplayerManagerInitialize();\n    StartDoWorkLoop();\n    XblMultiplayerManagerLobbySessionAddLocalUser();\nend\n\nfunction OnXblMultiplayerEventType_UserAdded()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_UserAdded\")\n    XblMultiplayerManagerJoinGameFromLobby();\nend\n\nfunction OnXblMultiplayerEventType_JoinGameCompleted()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_JoinGameCompleted\")\n\t\n    -- this call often results in a 412 due to a AdvertiseGameSessionDoWork which is writing the transfer handle to the MPSD doc.\n    XblMultiplayerManagerGameSessionSetSynchronizedHost();\nend\n\nfunction OnXblMultiplayerEventType_SynchronizedHostWriteCompleted_412_GameSession()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_SynchronizedHostWriteCompleted_412_GameSession\")\n    syncGameHostRetries = syncGameHostRetries + 1\n    print(\"GameSessionSetSynchronizedHost Retry \" .. syncGameHostRetries)\n    test.assert(syncGameHostRetries <= maxRetries)\n    if( syncGameHostRetries <= maxRetries ) then\n        XblMultiplayerManagerGameSessionSetSynchronizedHost();\n    else\n        test.stopTest();\n    end\nend\n\nfunction OnXblMultiplayerEventType_SynchronizedHostWriteCompleted()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_SynchronizedHostWriteCompleted\")\n    XblMultiplayerManagerGameSessionSetSynchronizedProperties();\nend\n\nfunction OnXblMultiplayerEventType_SessionSynchronizedPropertyWriteCompleted_412_GameSession()\n    print(\"Received OnXblMultiplayerEventType_SessionSynchronizedPropertyWriteCompleted_412_GameSession\")\n    syncGamePropRetries = syncGamePropRetries + 1\n    print(\"GameSessionSynchronizedPropertyWriteCompleted Retry \" .. syncGamePropRetries)\n    test.assert(syncGamePropRetries <= maxRetries)\n    if( syncGamePropRetries <= maxRetries ) then\n        XblMultiplayerManagerGameSessionSetSynchronizedProperties();\n    else\n        test.stopTest();\n    end\nend\n\nfunction OnXblMultiplayerEventType_GameSessionPropertyChanged()\n    print(\"Received OnXblMultiplayerEventType_GameSessionPropertyChanged\")\n    XblMultiplayerManagerLeaveGame();\nend\n\nfunction OnXblMultiplayerEventType_LeaveGameCompleted()\n    print(\" \");\n    print(\"Recived OnXblMultiplayerEventType_LeaveGameCompleted\")\n    XblMultiplayerManagerLobbySessionRemoveLocalUser();\nend\n\nfunction OnXblMultiplayerEventType_UserRemoved()\n    print(\" \");\n    print(\"Received OnXblMultiplayerEventType_UserRemoved\")\n    test.stopTest();\nend\n\ntest.MPM_SingleDeviceWriteTest = function()\n    common.init(MPM_SingleDeviceWriteTest_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/notification/achievement_unlock_notification.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n-- Note: This test requires an account with achievement id 1 locked, and can only be run \n-- one time on that account as we currently have no way to programmatically reset the unlock\n-- status of an achievement from API Explorer. To successfully run the test again you will have \n-- to run the XblPlayerDataReset tool to reset the user or sign in with a different account.\n\nfunction achievement_unlock_notification_test()\n    print(\"achievement_unlock_notification_test\")\n\t\n\tlocal achievementId = \"1\";\n\n\tlocal isLocked = IsAchievementLocked(achievementId);\n\n\t-- make sure there is something to do\n\ttest.is_true(isLocked);\n\t\n\tif not isLocked then\n\t\tprint(\"achievement is already unlocked\");\n\t\ttest.stopTest();\n\t\treturn;\n\tend\n\n    -- register achievement unlock handler invite handler\n    local id = XblAchievementUnlockAddNotificationHandler()\n    XblGameInviteAddNotificationHandler()\n\n\t-- unlock achievement\n\tRunAchievementUnlock(achievementId);\n\t\n\tlocal status;\n\n\tfor i=1,10 do\n\t\tSleep(500);\n\t\tstatus = CheckStatus();\n\t\tif status == 0 then\n\t\t\tbreak;\n\t\tend\n\tend\n\n\t-- anything other than 0 is an error\n\ttest.equal(status,0);\n\t\n\t-- unregister handlers\n\tXblAchievementUnlockRemoveNotificationHandler(id);\n    XblGameInviteRemoveNotificationHandler()\n\n\ttest.stopTest();\nend\n\n\nfunction achievement_unlock_notification_test_end()\n    print(\"Ending test\");\n    test.stopTest();\nend\n\n\ntest.skip = true; -- skipping because of special account requirements\ntest.TestAchievementUnlockNotification = function()\n    common.init(achievement_unlock_notification_test)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/notification/gameinvitenotifications.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestGameInviteNotifications_Handler()\n    print(\"TestGameInviteNotifications_Handler\")\n    MultiDeviceSyncAndWait(\"TestGameInviteNotifications\");\n    \n    if MultiDeviceIsHost() > 0 then \n        XblGameInviteRegisterForEventAsync()\n    else\n        MultiDeviceSyncAndWait(\"SendInvite\");\n        XblMultiplayerSessionReferenceCreate();\n        session, hr = XblMultiplayerSessionCreateHandle(\"00000000-0000-0000-0000-000076029b4d\", \"MinGameSession\", \"\", 0)\n        XblMultiplayerSessionJoin(session)\n        XblMultiplayerWriteSessionAsync(session)\n    end    \nend\n\n-- First Device - Notification Receiver --\nfunction OnXblGameInviteRegisterForEventAsync()\n    print(\"OnXblGameInviteRegisterForEventAsync\")\n    XblGameInviteAddNotificationHandler();\n    MultiDeviceSyncAndWait(\"SendInvite\");\nend\n\nfunction OnXblGameInviteAddNotificationHandler()\n    print(\"OnXblGameInviteAddNotificationHandler\")\n    MultiDeviceSyncAndWait(\"WaitForInvite\");\n    XblGameInviteRemoveNotificationHandler();\n    XblGameInviteUnregisterForEventAsync();\nend\n\nfunction OnXblGameInviteUnregisterForEventAsync()\n    print(\"OnXblGameInviteUnregisterForEventAsync\")\n    test.stopTest();\nend\n\n-- Second Device - Invite Sender --\nfunction OnXblMultiplayerWriteSessionAsync()\n    XblMultiplayerSendInvitesAsync(\"\", \"\", MultiDeviceGetRemoteXuid())\nend\n\nfunction OnXblMultiplayerSendInvitesAsync()\n    MultiDeviceSyncAndWait(\"WaitForInvite\");\n    test.stopTest();\nend\n\ntest.ismultidevice = true;\ntest.TestGameInviteNotifications = function()\n    common.init(TestGameInviteNotifications_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/notification/multiple_notification_subscriptions.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestGameInviteNotifications_Handler()\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    print(\"OnXblSocialManagerDoWork_LocalUserAddedEvent\")\n    Sleep(5000)\n    XblSocialManagerRemoveLocalUser()\n    StopSocialManagerDoWorkLoop()\n    --print(\"stopping test\")\n    --test.stopTest();\nend\n\ntest.skip = true;\ntest.TestMultipleNotificationSubscriptions = function()\n    common.init(TestGameInviteNotifications_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/presence/presence-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestPresenceCppHandler()\n    print(\"TestPresenceCppHandler\")\n  \n    PresenceServiceSetPresence()\nend\n\nfunction OnPresenceServiceSetPresence()\n    PresenceServiceGetPresence()\nend\n\nfunction OnPresenceServiceGetPresence()\n    PresenceRecordGetXuidCpp()\n    PresenceRecordGetUserStateCpp()\n    PresenceRecordGetDeviceRecordsCpp()\n\tPresenceRecordCloseHandleCpp()\n    PresenceServiceGetPresenceForSocialGroup()\nend\n\nfunction OnPresenceServiceGetPresenceForSocialGroup()\n    PresenceServiceGetPresenceForMultipleUsers()\nend\n\nfunction OnPresenceServiceGetPresenceForMultipleUsers()\n    test.stopTest();\nend\n\ntest.TestPresenceCpp = function()\n    common.init(TestPresenceCppHandler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/presence/presence.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestPresenceHandler()\n    print(\"TestPresenceHandler\")\n    XblPresenceSetPresenceAsync()\nend\n\nfunction OnXblPresenceSetPresenceAsync()\n    XblPresenceGetPresenceAsync()\nend\n\nfunction OnXblPresenceGetPresenceAsync()\n    XblPresenceRecordGetXuid()\n    XblPresenceRecordGetUserState()\n    XblPresenceRecordGetDeviceRecords()\n    XblPresenceRecordCloseHandle()\n    XblPresenceGetPresenceForSocialGroupAsync()\nend\n\nfunction OnXblPresenceGetPresenceForSocialGroupAsync()\n    XblPresenceGetPresenceForMultipleUsersAsync()\nend\n\nfunction OnXblPresenceGetPresenceForMultipleUsersAsync()\n    test.stopTest();\nend\n\ntest.TestPresence = function()\n    common.init(TestPresenceHandler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/presence/presence_rta.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestPresenceRTA_Handler()\n    print(\"TestPresenceRTA_Handler\")\n    XblPresenceTrackUsers(2814656696817462)\n    XblPresenceAddDevicePresenceChangedHandler()\n    XblPresenceAddTitlePresenceChangedHandler()()\nend\n\nfunction OnDevicePresenceChanged()\n    print(\"DevicePresenceChanged\")\nend\n\nfunction OnTitlePresenceChanged()\n    print(\"TitlePresenceChanged\")\nend\n\ntest.skip = true\ntest.TestPresenceRTA = function()\n    common.init(TestPresenceRTA_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/privacy/privacy-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction PrivacyTestsCpp_Handler()\n    print(\"PrivacyTestsCpp_Handler\")\n    PrivacyServiceGetAvoidList()\nend\n\nfunction OnPrivacyServiceGetAvoidList()\n    print(\"OnPrivacyServiceGetAvoidList\")\n    PrivacyServiceCheckPermissionWithTargetUser()\nend\n\nfunction OnPrivacyServiceCheckPermissionWithTargetUser()\n    print(\"OnPrivacyServiceCheckPermissionWithTargetUser\")\n    PrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers()\nend\n\nfunction OnPrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers()\n    print(\"OnPrivacyServiceCheckMultiplePermissionsWithMultipleTargetUsers\")\n    PrivacyServiceGetMuteList()\nend\n\nfunction OnPrivacyServiceGetMuteList()\n    print(\"OnPrivacyServiceGetMuteList\")\n    PrivacyServiceGetAvoidOrMuteList()\nend\n\nfunction OnPrivacyServiceGetAvoidOrMuteList()\n    print(\"OnPrivacyServiceGetAvoidOrMuteList\")\n    test.stopTest();\nend\n\ntest.PrivacyTestsCpp = function()\n    common.init(PrivacyTestsCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/privacy/privacy.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction PrivacyTests_Handler()\n    print(\"PrivacyTests_Handler\")\n    XblPrivacyGetAvoidListAsync()\nend\n\nfunction OnXblPrivacyGetAvoidListAsync()\n    print(\"OnXblPrivacyGetAvoidListAsync\")\n    XblPrivacyCheckPermissionAsync()\nend\n\nfunction OnXblPrivacyCheckPermissionAsync()\n    print(\"OnXblPrivacyCheckPermissionAsync\")\n    XblPrivacyCheckPermissionForAnonymousUserAsync()\nend\n\nfunction OnXblPrivacyCheckPermissionForAnonymousUserAsync()\n    print(\"OnOnXblPrivacyCheckPermissionForAnonymousUserAsync\")\n    XblPrivacyBatchCheckPermissionAsync()\nend\n\nfunction OnXblPrivacyBatchCheckPermissionAsync()\n    print(\"OnXblPrivacyBatchCheckPermissionAsync\")\n    test.stopTest();\nend\n\ntest.PrivacyTests = function()\n    common.init(PrivacyTests_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/profile/GetUserProfile-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction GetUserProfileCpp_Handler()\n    print(\"GetUserProfileCpp_Handler\")\n    ProfileServiceGetUserProfile()\nend\n\nfunction OnProfileServiceGetUserProfile()\n    print(\"OnProfileServiceGetUserProfile\")\n    test.stopTest();\nend\n\ntest.GetUserProfileCpp = function()\n    common.init(GetUserProfileCpp_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/profile/GetUserProfile.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction GetUserProfile_Handler()\n    print(\"GetUserProfile_Handler\")\n    XblProfileGetUserProfileAsync()\nend\n\nfunction OnXblProfileGetUserProfileAsync()\n    print(\"OnXblProfileGetUserProfileAsync\")\n    test.stopTest();\nend\n\ntest.GetUserProfile = function()\n    common.init(GetUserProfile_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/profile/GetUserProfiles-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction GetUserProfilesCpp_Handler()\n    print(\"GetUserProfilesCpp_Handler\")\n    ProfileServiceGetUserProfiles()\nend\n\nfunction OnProfileServiceGetUserProfiles()\n    print(\"OnProfileServiceGetUserProfiles\")\n    test.stopTest();\nend\n\ntest.GetUserProfilesCpp = function()\n    common.init(GetUserProfilesCpp_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/profile/GetUserProfiles.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction GetUserProfiles_Handler()\n    print(\"GetUserProfiles_Handler\")\n    XblProfileGetUserProfilesAsync()\nend\n\nfunction OnXblProfileGetUserProfilesAsync()\n    print(\"OnXblProfileGetUserProfilesAsync\")\n    test.stopTest();\nend\n\ntest.GetUserProfiles = function()\n    common.init(GetUserProfiles_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/profile/GetUserProfilesForSocialGroup-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction GetUserProfilesForSocialGroupCpp_Handler()\n    print(\"GetUserProfilesForSocialGroupCpp_Handler\")\n    ProfileServiceGetUserProfilesForSocialGroup()\nend\n\nfunction OnProfileServiceGetUserProfilesForSocialGroup()\n    print(\"OnProfileServiceGetUserProfilesForSocialGroup\")\n    test.stopTest();\nend\n\ntest.GetUserProfilesForSocialGroupCpp = function()\n    common.init(GetUserProfilesForSocialGroupCpp_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/profile/GetUserProfilesForSocialGroupAsync.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction GetUserProfilesForSocialGroupAsync_Handler()\n    print(\"GetUserProfilesForSocialGroupAsync_Handler\")\n    XblProfileGetUserProfilesForSocialGroupAsync()\nend\n\nfunction OnXblProfileGetUserProfilesForSocialGroupAsync()\n    print(\"OnXblProfileGetUserProfilesForSocialGroupAsyncRetry\")\n    XblProfileGetUserProfilesForSocialGroupAsync()\nend\n\nfunction OnXblProfileGetUserProfilesForSocialGroupAsync()\n    print(\"OnXblProfileGetUserProfilesForSocialGroupAsync\")\n    test.stopTest();\nend\n\ntest.GetUserProfilesForSocialGroupAsync = function()\n    common.init(GetUserProfilesForSocialGroupAsync_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/RTAResync.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction RTAResync_Handler()\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    XblTestHooksTriggerRTAResync()\n    Sleep(5000)\n    XblSocialManagerRemoveLocalUser()\n    StopSocialManagerDoWorkLoop()\n    test.stopTest();\nend\n\ntest.RTAResync = function()\n    common.init(RTAResync_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/RTASuspendResume.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction RTASuspendResume_Handler()\n    isGdk = IsGDKPlatform()\n    if isGdk then\n        XblRealTimeActivityAddConnectionStateChangeHandler();\n        -- Add a real-time handler to force RTA connection\n        XblSocialAddSocialRelationshipChangedHandler();\n    else\n        test.stopTest()\n    end\nend\n\nconnectCount = 0\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    connectCount = connectCount + 1\n\n    if connectCount == 1 then\n        --HCWinHttpSuspend();\n    else\n        --XblRealTimeActivityRemoveConnectionStateChangeHandler();\n        --XblSocialRemoveSocialRelationshipChangedHandler();\n        test.stopTest()\n    end\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA connection disconnected\");\n    HCWinHttpResume();\nend\n\ntest.skip = true;\ntest.RTASuspendResume = function()\n    common.init(RTASuspendResume_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/RTA_MP_SM.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\nfirstConnect = true\n\n-- Creates a MPSD session and ensures client can update RTA connection ID to prevent \n-- getting kicked from the session. To force a connection ID changed you can disconnect network\n-- or wait for RTA timeout\nfunction CreateSessionAndWait_Handler()\n    StartSocialManagerDoWorkLoop();\n    XblSocialManagerAddLocalUser();\n    XblRtaMultiplayerInit();\nend\n\ntest.skip = true\ntest.CreateSessionAndWait = function()\n    common.init(CreateSessionAndWait_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/RTA_activation.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n-- Test RTA connection state based on various states of SM, Client handlers, and Legacy Activation\n\nfunction RTAActivation_Handler()\n    print(\"RTAActivation_Handler\")\n\n    -- Test isn't valid on all platforms (i.e. on Win32 we set up a notification service subscription by default so the RTA connection\n    -- won't be torn down just by removing the social relationship changed handler).\n    isGdk = IsGDKPlatform()\n    if isGdk then\n        StartSocialManagerDoWorkLoop()\n        XblRealTimeActivityAddConnectionStateChangeHandler()\n        XblSocialAddSocialRelationshipChangedHandler()\n    else\n        test.stopTest()\n    end\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connecting()\n    print(\"RTA Connecting\");\nend\n\nconnectCount = 0\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected()\n    print(\"RTA Connected\");\n    connectCount = connectCount + 1\n\n    if connectCount == 1 then\n        -- Removing the only handler should cause disconnection\n        XblSocialRemoveSocialRelationshipChangedHandler()\n    elseif connectCount == 2 then\n        XblSocialManagerRemoveLocalUser()\n    elseif connectCount == 3 then\n        -- User will be removed from SM in response to the LocalUserAdded event, which should cause a disconnect\n        XblSocialManagerAddLocalUser()\n        XblRealTimeActivityDeactivate()\n    end\nend\n\ndisconnectCount = 0\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA Disconnected\")\n    disconnectCount = disconnectCount + 1\n\n    if disconnectCount == 1 then\n        -- Adding user to SM will cause connection to be established again. There is not a guaranteed ordering\n        -- between the RTA connected event and the SM local user added event. That said, we can always remove the local\n        -- from SM when the RTA connected event happens, because of the fact that it is valid to remove a user from \n        -- SocialManager even before the LocalUserAdded event is received\n        XblSocialManagerAddLocalUser()\n    elseif disconnectCount == 2 then\n        XblRealTimeActivityActivate()\n    elseif disconnectCount == 3 then\n        test.stopTest()\n    end\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    print(\"SocialManager LocalUserAdded\")\n    if connectCount == 3 then\n        XblSocialManagerRemoveLocalUser()\n    end\nend\n\ntest.RTAActivation = function()\n    common.init(RTAActivation_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/simpleRTA-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction RtaActivateDeactivateCpp()\n    print(\"RtaActivateDeactivateCpp\");\n\n    -- Test isn't valid on all platforms (i.e. on Win32 we set up a notification service subscription by default so the RTA connection\n    -- won't be torn down just by removing the social relationship changed handler).\n    isGdk = IsGDKPlatform()\n    if isGdk then\n        RealTimeActivityServiceAddConnectionStateChangeHandler();\n        RealTimeActivityServiceActivate();\n    else\n        test.stopTest()\n    end\nend\n\nfunction OnRealTimeActivityServiceAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    RealTimeActivityServiceDeactivate();\nend\n\nfunction OnRealTimeActivityServiceAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA connection disconnected\");\n    test.stopTest();\nend\n\nfunction OnRealTimeActivityServiceAddConnectionStateChangeHandler_Disabled()\n    test.stopTest();\nend\n\ntest.SimpleRTACpp = function()\n    common.init(RtaActivateDeactivateCpp)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/simpleRTA.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SimpleRTA_Handler()\n    print(\"SimpleRTA\");\n\n    -- Test isn't valid on all platforms (i.e. on Win32 we set up a notification service subscription by default so the RTA connection\n    -- won't be torn down just by removing the social relationship changed handler).\n    isGdk = IsGDKPlatform()\n    if isGdk then\n        XblRealTimeActivityAddConnectionStateChangeHandler();\n        -- Add a real-time handler to force RTA connection\n        XblSocialAddSocialRelationshipChangedHandler();\n    else\n        test.stopTest()\n    end\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    XblSocialRemoveSocialRelationshipChangedHandler();\n    XblContextCloseHandle();\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA connection disconnected\");\n    -- RTA connection will be torn down here since the last handler was removed\n    test.stopTest();\nend\n\ntest.SimpleRTA = function()\n    common.init(SimpleRTA_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/rta/simpleRTA_legacy.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n-- Test ensuring legacy RTA calling patters are still functional\n\nfunction SimpleRTALegacy_Handler()\n    print(\"SimpleRTALegacy_Handler\");\n\n    -- Test isn't valid on all platforms (i.e. on Win32 we set up a notification service subscription by default so the RTA connection\n    -- won't be torn down just by removing the social relationship changed handler).\n    isGdk = IsGDKPlatform()\n    if isGdk then\n        XblRealTimeActivityAddConnectionStateChangeHandler();\n        XblRealTimeActivityActivate();\n    else\n        test.stopTest()\n    end\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    XblRealTimeActivityDeactivate();\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA connection disconnected\");\n    test.stopTest();\nend\n\ntest.SimpleRTALegacy = function()\n    common.init(SimpleRTALegacy_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/reputation-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction ReputationServiceSubmitReputationFeedback_Handler()\n    print(\"ReputationServiceSubmitReputationFeedback_Handler\")\n    ReputationServiceSubmitReputationFeedback()\nend\n\nfunction OnReputationServiceSubmitReputationFeedback()\n    print(\"OnReputationServiceSubmitReputationFeedback\")\n    ReputationServiceSubmitBatchReputationFeedback()\nend\n\nfunction OnReputationServiceSubmitBatchReputationFeedback()\n    print(\"OnReputationServiceSubmitBatchReputationFeedback\")\n    test.stopTest()\nend\n\ntest.SubmitReputationFeedbackCpp = function()\n    common.init(ReputationServiceSubmitReputationFeedback_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/reputation.lua",
    "content": "\ntest = require 'u-test'\ncommon = require 'common'\n\nfunction SubmitReputationFeedback_Handler()\n    print(\"GetUserProfile_Handler\")\n    XblSocialSubmitReputationFeedbackAsync()\nend\n\nfunction OnXblSocialSubmitReputationFeedbackAsync()\n    print(\"OnXblProfileGetUserProfileAsync\")\n    XblSocialSubmitBatchReputationFeedbackAsync()\nend\n\nfunction OnXblSocialSubmitBatchReputationFeedbackAsync()\n    print(\"OnXblSocialSubmitBatchReputationFeedbackAsync\")\n    test.stopTest()\nend\n\ntest.SubmitReputationFeedback = function()\n    common.init(SubmitReputationFeedback_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialServiceGetSocialRelationships_Handler()\n    print(\"SocialServiceGetSocialRelationships_Handler\")\n    SocialServiceGetSocialRelationships()\n\t--OnSocialServiceGetSocialRelationships()\nend\n\nfunction OnSocialServiceGetSocialRelationships()\n    hr, hasNext = SocialRelationshipResultHasNextCpp()\n    print(\"hasNext \" .. hr)\n    print(\"hr \" .. hr)\n    if hasNext ~= 0 then\n        SocialRelationshipResultGetNextCpp()\n    else\n        SocialRelationshipResultCloseHandleCpp()\n        test.stopTest();\n    end\nend\n\nfunction OnSocialRelationshipGetNextCpp()\n    print(\"OnSocialRelationshipGetNextCpp\")\n    OnSocialServiceGetSocialRelationships()\nend\n\ntest.GetSocialRelationshipsCpp = function()\n    common.init(SocialServiceGetSocialRelationships_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction GetSocialRelationships_Handler()\n    print(\"GetSocialRelationships_Handler\")\n    XblSocialGetSocialRelationshipsAsync()\nend\n\nfunction OnXblSocialGetSocialRelationshipsAsync()\n    print(\"OnXblProfileGetUserProfileAsync\")\n    XblSocialRelationshipResultGetRelationships()\n    XblSocialRelationshipResultCloseHandle()\n    test.stopTest();\nend\n\ntest.GetSocialRelationships = function()\n    common.init(GetSocialRelationships_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_1-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManager1Cpp_Handler()\n    StartSocialManagerDoWorkLoopCpp()\n    Sleep(1000)\n    StopSocialManagerDoWorkLoopCpp()\n    test.stopTest();\nend\n\ntest.SocialManager1Cpp = function()\n    common.init(SocialManager1Cpp_Handler)\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserRemovedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_UsersAddedToSocialGraphEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_UsersRemovedFromSocialGraphEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_PresenceChangedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_ProfilesChangedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialRelationshipsChangedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserAddedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserRemovedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupUpdatedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_UnknownEvent()\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_1.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManager1_Handler()\n    StartSocialManagerDoWorkLoop()\n    Sleep(1000)\n    StopSocialManagerDoWorkLoop()\n    test.stopTest();\nend\n\ntest.SocialManager1 = function()\n    common.init(SocialManager1_Handler)\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserRemovedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UsersAddedToSocialGraphEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UsersRemovedFromSocialGraphEvent()\nend\n\nfunction OnXblSocialManagerDoWork_PresenceChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_ProfilesChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialRelationshipsChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserRemovedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UnknownEvent()\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_2-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManager2Cpp_Handler()\n    StartSocialManagerDoWorkLoopCpp()\n    SocialManagerAddLocalUserCpp()\nend\n\ntest.SocialManager2Cpp = function()\n    common.init(SocialManager2Cpp_Handler)\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserAddedEvent()\n    SocialManagerGetLocalUsersCpp()\n    Sleep(1000)\n    StopSocialManagerDoWorkLoopCpp()\n    test.stopTest();\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserRemovedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_UsersAddedToSocialGraphEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_UsersRemovedFromSocialGraphEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_PresenceChangedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_ProfilesChangedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialRelationshipsChangedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupUpdatedEvent()\nend\n\nfunction OnSocialManagerDoWorkCpp_UnknownEvent()\nend\n\nfunction OnStartSocialManagerDoWorkLoopCppDisabled()\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_2.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManager2_Handler()\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\ntest.SocialManager2 = function()\n    common.init(SocialManager2_Handler)\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    XblSocialManagerGetLocalUsers()\n    Sleep(1000)\n    StopSocialManagerDoWorkLoop()\n    test.stopTest();\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserRemovedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UsersAddedToSocialGraphEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UsersRemovedFromSocialGraphEvent()\nend\n\nfunction OnXblSocialManagerDoWork_PresenceChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_ProfilesChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialRelationshipsChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UnknownEvent()\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_filter-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerFilterCpp_Handler()\n    StartSocialManagerDoWorkLoopCpp()\n    SocialManagerAddLocalUserCpp()\nend\n\ntest.SocialManagerFilterCpp = function()\n    common.init(SocialManagerFilterCpp_Handler)\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserAddedEvent()\n    SocialManagerGetLocalUsersCpp()\n    SocialManagerSetRichPresencePollingStatusCpp()\n    group, hr = SocialManagerCreateSocialUserGroupFromFiltersCpp()\n    print(\"group \" .. group)\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent()\n    SocialManagerUserGroupGetUsersCpp()\n    SocialManagerPresenceRecordIsUserPlayingTitleCpp()\n    SocialManagerDestroySocialUserGroupCpp(group)\n    SocialManagerRemoveLocalUserCpp()\n    StopSocialManagerDoWorkLoopCpp()\n    test.stopTest();\nend\n\nfunction OnStartSocialManagerDoWorkLoopCppDisabled()\n    test.stopTest();\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_filter.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerFilter_Handler()\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\ntest.SocialManagerFilter = function()\n    common.init(SocialManagerFilter_Handler)\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    XblSocialManagerGetLocalUsers()\n    XblSocialManagerSetRichPresencePollingStatus()\n    group, hr = XblSocialManagerCreateSocialUserGroupFromFilters()\n    XblSocialManagerUserGroupGetUsers()\n    print(\"group \" .. group)\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent()\n    XblSocialManagerUserGroupGetUsers()\n    XblSocialManagerPresenceRecordIsUserPlayingTitle()\n    XblSocialManagerDestroySocialUserGroup(group)\n    XblSocialManagerRemoveLocalUser()\n    StopSocialManagerDoWorkLoop()\n    test.stopTest();\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_list-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerListCpp_Handler()\n    print(\"SocialManagerListCpp_Handler\")\n    StartSocialManagerDoWorkLoopCpp()\n    SocialManagerAddLocalUserCpp()\nend\n\ntest.skip = true\ntest.SocialManagerListCpp = function()\n    common.init(SocialManagerListCpp_Handler)\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserAddedEvent()\n    print(\"OnSocialManagerDoWorkCpp_LocalUserAddedEvent\")\n    PresenceServiceSetPresence()\nend\n\nfunction OnPresenceServiceSetPresence()\n    print(\"OnPresenceServiceSetPresence\")\n    SocialManagerGetLocalUsersCpp()\n    group, hr = SocialManagerCreateSocialUserGroupFromListCpp()\n    print(\"group \" .. group)\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent()\n    print(\"OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent\")\n    SocialManagerUserGroupGetUsersCpp()\n    SocialManagerUpdateSocialUserGroupCpp()\nend\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupUpdatedEvent()\n    print(\"OnSocialManagerDoWorkCpp_SocialUserGroupUpdatedEvent\")\n    SocialManagerUserGroupGetUsersTrackedByGroupCpp()\n    SocialManagerDestroySocialUserGroupCpp(group)\n    SocialManagerRemoveLocalUserCpp()\n    StopSocialManagerDoWorkLoopCpp()\n    print(\"stopping test\")\n    test.stopTest();\nend\n\nfunction OnStartSocialManagerDoWorkLoopCppDisabled()\n    test.stopTest();\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_list.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerList_Handler()\n    print(\"SocialManagerList_Handler\")\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\ntest.SocialManagerList = function()\n    common.init(SocialManagerList_Handler)\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    print(\"OnXblSocialManagerDoWork_LocalUserAddedEvent\")\n    XblPresenceSetPresenceAsync()\nend\n\nfunction OnXblPresenceSetPresenceAsync()\n    print(\"OnXblPresenceSetPresenceAsync\")\n    XblSocialManagerGetLocalUsers()\n    group, hr = XblSocialManagerCreateSocialUserGroupFromList()\n    print(\"group \" .. group)\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent()\n    print(\"OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent\")\n    XblSocialManagerUserGroupGetUsers()\n    XblSocialManagerUpdateSocialUserGroup()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent()\n    print(\"OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent\")\n    XblSocialManagerUserGroupGetUsersTrackedByGroup()\n    XblSocialManagerDestroySocialUserGroup(group)\n    XblSocialManagerRemoveLocalUser()\n    StopSocialManagerDoWorkLoop()\n    print(\"stopping test\")\n    test.stopTest();\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_remove_realloc-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerRemoveReallocCpp_Handler()\n    print(\"SocialManagerListCpp_Handler\")\n    StartSocialManagerDoWorkLoopCpp()\n    SocialManagerAddLocalUserCpp()\nend\n\ntest.SocialManagerRemoveReallocCpp = function()\n    common.init(SocialManagerRemoveReallocCpp_Handler)\nend\n\nfunction OnSocialManagerDoWorkCpp_LocalUserAddedEvent()\n    group1, hr = SocialManagerCreateSocialUserGroupFromListCpp(15, 0)\n    print(\"group1 = \" .. group1)\nend\n\nlocal groupLoaded = 0\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupLoadedEvent()\n    groupLoaded = groupLoaded + 1;\n    if groupLoaded == 1 then\n        print(\"group1 loaded\")\n        SocialManagerUserGroupGetUsersCpp(group1)\n        SocialManagerUpdateSocialUserGroupCpp(group1, 10, 5)\n    elseif groupLoaded == 2 then\n        print(\"group2 loaded\")\n        print(\"group1 users:\")\n        SocialManagerUserGroupGetUsersCpp(group1)\n        print(\"group2 users:\")\n        SocialManagerUserGroupGetUsersCpp(group2)\n        SocialManagerDestroySocialUserGroupCpp(group1)\n        SocialManagerDestroySocialUserGroupCpp(group2)\n        SocialManagerRemoveLocalUserCpp()\n        StopSocialManagerDoWorkLoopCpp()\n        test.stopTest();\n    end\nend\n\nlocal groupUpdate = 0;\n\nfunction OnSocialManagerDoWorkCpp_SocialUserGroupUpdatedEvent()\n    groupUpdate = groupUpdate + 1;\n    if groupUpdate == 1 then\n        group2, hr = SocialManagerCreateSocialUserGroupFromListCpp(20, 15) -- group needs to be large enough to force realloc\n        print(\"group2 = \" .. group2)\n    else\n        print(\"Unexpected GroupUpdatedEvent\")\n    end\nend\n\nfunction OnStartSocialManagerDoWorkLoopCppDisabled()\n    test.stopTest();\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_remove_realloc.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerRemoveRealloc_Handler()\n    print(\"SocialManagerList_Handler\")\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\ntest.SocialManagerRemoveRealloc = function()\n    common.init(SocialManagerRemoveRealloc_Handler)\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    group1, hr = XblSocialManagerCreateSocialUserGroupFromList(15, 0)\n    print(\"group1 = \" .. group1)\nend\n\nlocal groupLoaded = 0\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent()\n    groupLoaded = groupLoaded + 1;\n    if groupLoaded == 1 then\n        print(\"group1 loaded\")\n        XblSocialManagerUserGroupGetUsers(group1)\n        XblSocialManagerUpdateSocialUserGroup(group1, 10, 5)\n    elseif groupLoaded == 2 then\n        print(\"group2 loaded\")\n        print(\"group1 users:\")\n        XblSocialManagerUserGroupGetUsers(group1)\n        print(\"group2 users:\")\n        XblSocialManagerUserGroupGetUsers(group2)\n        XblSocialManagerDestroySocialUserGroup(group1)\n        XblSocialManagerDestroySocialUserGroup(group2)\n        XblSocialManagerRemoveLocalUser()\n        StopSocialManagerDoWorkLoop()\n        test.stopTest();\n    end\nend\n\nlocal groupUpdate = 0;\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent()\n    groupUpdate = groupUpdate + 1;\n    if groupUpdate == 1 then\n        group2, hr = XblSocialManagerCreateSocialUserGroupFromList(20, 15) -- group needs to be large enough to force realloc\n        print(\"group2 = \" .. group2)\n    else\n        print(\"Unexpected GroupUpdatedEvent\")\n    end\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_manager_wait.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialManagerWait_Handler()\n    StartSocialManagerDoWorkLoop()\n    XblSocialManagerAddLocalUser()\nend\n\ntest.skip = true;\ntest.SocialManagerWait = function()\n    common.init(SocialManagerWait_Handler)\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserAddedEvent()\n    XblSocialManagerGetLocalUsers()\n    XblSocialManagerSetRichPresencePollingStatus()\n    XblSocialManagerCreateSocialUserGroupFromFilters()\nend\n\nfunction OnXblSocialManagerDoWork_LocalUserRemovedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UsersAddedToSocialGraphEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UsersRemovedFromSocialGraphEvent()\nend\n\nfunction OnXblSocialManagerDoWork_PresenceChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_ProfilesChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialRelationshipsChangedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupLoadedEvent()\n    XblSocialManagerUserGroupGetUsers()\n    XblSocialManagerPresenceRecordIsUserPlayingTitle()\nend\n\nfunction OnXblSocialManagerDoWork_SocialUserGroupUpdatedEvent()\nend\n\nfunction OnXblSocialManagerDoWork_UnknownEvent()\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_relationship_changed.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialRelationshipChanged_Handler()\n    print(\"SocialRelationshipChanged_Handler\")\n    XblSocialAddSocialRelationshipChangedHandler()\n    XblSocialAddFriendRequestCountChangedHandler()\nend\n\nfunction OnSocialRelationshipChanged()\n    print(\"OnSocialRelationshipChanged\")\n    XblSocialRemoveSocialRelationshipChangedHandler()\n    test.stopTest();\nend\n\nfunction OnFriendRequestCountChanged()\n    print(\"OnFriendRequestCountChanged\")\n    --XblSocialRemoveFriendRequestCountChangedHandler()\nend\n\ntest.skip = true\ntest.SocialRelationshipChanged = function()\n    common.init(SocialRelationshipChanged_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/social/social_sub_unsub.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SocialSubUnSub_Handler()\n    XblRealTimeActivityAddConnectionStateChangeHandler();\n    XblPresenceAddDevicePresenceChangedHandler()\n    XblPresenceAddTitlePresenceChangedHandler()\n    XblRealTimeActivityActivate();\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    TestLoop()\nend\n\nfunction OnDevicePresenceChanged()\nend\n\nfunction OnTitlePresenceChanged()\nend\n\nfunction TestLoop()\n    SubscribeToTitleAndDevicePresenceChangeForFriends();\nend\n\nloopCount = 0\nfunction OnSubscribeToTitleAndDevicePresenceChangeForFriends()\n    loopCount = loopCount + 1\n    if loopCount == 3 then\n        Sleep(500);\n        UnsubscribeToTitleAndDevicePresenceChangeForFriends();\n        Sleep(500);\n        test.stopTest();\n    else\n        print(\"OnSubscribeToTitleAndDevicePresenceChangeForFriends\")\n        Sleep(500);\n        UnsubscribeToTitleAndDevicePresenceChangeForFriends();\n        Sleep(500);\n        TestLoop()\n    end\nend\n\ntest.SocialSubUnSub = function()\n    common.init(SocialSubUnSub_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stats/stats-bvt.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nuserStatistic1 = 0;\nchangeHandleCalledCount = 0;\nuserStatResultCount = 0;\n\nfunction TestStatsBvt_Handler()\n    print(\"TestStatsBvt_Handler\")\n\n    XblUserStatisticsTrackStatistics();\n    XblUserStatisticsAddStatisticChangedHandler();\n    XblUserStatisticsGetSingleUserStatisticAsync();\nend\n\nfunction OnXblUserStatisticsGetSingleUserStatisticAsync()\n    print(\"OnXblUserStatisticsGetSingleUserStatisticAsync\")\n\n    userStatResultCount = userStatResultCount + 1\n    if userStatResultCount == 1 then\n\n        userStatistic1 = GetLastStat();\n        print(\"UserStatistic1 \" .. userStatistic1 );\n\n        XblEventsWriteInGameEvent();\n\n    elseif userStatResultCount == 2 then\n\n        local userStatistic2 = GetLastStat();\n        print(\"UserStatistic1 \" .. userStatistic1 );\n        print(\"UserStatistic2 \" .. userStatistic2 );\n        test.assert(userStatistic2 > userStatistic1);\n        test.stopTest();\n    end\nend\n\nfunction OnStatisticChangedHandler()\n    print(\"OnStatisticChangedHandler\")\n\n    changeHandleCalledCount = changeHandleCalledCount + 1\n    if changeHandleCalledCount == 2 then\n        XblUserStatisticsGetSingleUserStatisticAsync();\n    end\nend\n\ntest.isbvt = true;\ntest.TestStatsBvt = function()\n    common.init(TestStatsBvt_Handler)\nend\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stats/stats-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\ninitalSubscription = true\ncallDeactivate = false\n\nfunction TestStatsCpp_Handler()\n    print(\"TestStatsCpp_Handler\")\n    SetCallUpdate();\n    RealTimeActivityServiceAddConnectionStateChangeHandler();\n    RealTimeActivityServiceActivate();\nend\n\nfunction OnRealTimeActivityServiceAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    \n    UserStatisticsServiceSubscribeToStatisticChange();\n    UserStatisticsServiceAddStatisticChangedHandler();\n    UserStatisticsServiceGetSingleUserStatistic();\nend\n\nfunction OnUserStatisticsServiceGetSingleUserStatistic()\n    print(\"OnUserStatisticsServiceGetSingleUserStatistic\")\n    UserStatisticsServiceGetSingleUserStatistics();\nend\n\nfunction OnUserStatisticsServiceGetSingleUserStatistics()\n    print(\"OnUserStatisticsServiceGetSingleUserStatistics\")\n    UserStatisticsServiceGetMultipleUserStatistics();\nend\n\nfunction OnUserStatisticsServiceGetMultipleUserStatistics()\n    print(\"OnUserStatisticsServiceGetMultipleUserStatistics\")\n    UserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations();\nend\n\nfunction OnUserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations()\n    print(\"OnUserStatisticsServiceGetMultipleUserStatisticsForMultipleServiceConfigurations\")\n    EventsServiceWriteInGameEvent();\n    initalSubscription = false;\nend\n\nfunction OnStatisticChangedHandlerCpp()\n    print(\"OnStatisticChangedHandlerCpp\")\n    StatisticChangeSubscriptionGetStateCpp();\n    StatisticChangeSubscriptionGetIdCpp();\n    if initalSubscription then\n        initalSubscription = false;\n    else\n        callDeactivate = true;\n    end\nend\n\nfunction update()\n    if callDeactivate then\n        UserStatisticsServiceRemoveStatisticChangedHandler();\n        UserStatisticsServiceUnsubscribeFromStatisticChange();\n        RealTimeActivityServiceDeactivate();\n    end\nend\n\nfunction OnRealTimeActivityServiceAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA connection disconnected\");\n    test.stopTest();\nend\n\nfunction OnRealTimeActivityServiceAddConnectionStateChangeHandler_Disabled()\n    test.stopTest();\nend\n\ntest.TestStatsCpp = function()\n    common.init(TestStatsCpp_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stats/stats.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\ninitalSubscription = true\nfunction TestStats_Handler()\n    print(\"TestStats_Handler\")\n    XblUserStatisticsTrackStatistics();\n    XblUserStatisticsAddStatisticChangedHandler();\n    XblUserStatisticsGetSingleUserStatisticAsync();\nend\n\nfunction OnXblUserStatisticsGetSingleUserStatisticAsync()\n    print(\"OnXblUserStatisticsGetSingleUserStatisticAsync\")\n    XblUserStatisticsGetSingleUserStatisticsAsync();\nend\n\nfunction OnXblUserStatisticsGetSingleUserStatisticsAsync()\n    print(\"OnXblUserStatisticsGetSingleUserStatisticsAsync\")\n    XblUserStatisticsGetMultipleUserStatisticsAsync();\nend\n\nfunction OnXblUserStatisticsGetMultipleUserStatisticsAsync()\n    print(\"OnXblUserStatisticsGetMultipleUserStatisticsAsync\")\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync();\nend\n\nfunction OnXblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync()\n    print(\"OnXblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\")\n    XblEventsWriteInGameEvent();\n    initalSubscription = false;\nend\n\nfunction OnStatisticChangedHandler()\n    print(\"OnStatisticChangedHandler\")\n    if initalSubscription then\n        initalSubscription = false;\n    else\n        test.stopTest();\n    end\nend\n\ntest.TestStats = function()\n    common.init(TestStats_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stats/stats_legacy.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n-- Test ensuring legacy RTA calling patters are still functional\n\ninitalSubscription = true\ncallDeactivate = false\nfunction TestStatsLegacy_Handler()\n    print(\"TestStatsLegacy_Handler\")\n    SetCallUpdate();\n    XblRealTimeActivityAddConnectionStateChangeHandler();\n    XblRealTimeActivityActivate();\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Connected()\n    print(\"RTA connection connected\");\n    \n    XblUserStatisticsSubscribeToStatisticChange();\n    XblUserStatisticsAddStatisticChangedHandler();\n    \n    XblUserStatisticsGetSingleUserStatisticAsync();\nend\n\nfunction OnXblUserStatisticsGetSingleUserStatisticAsync()\n    print(\"OnXblUserStatisticsGetSingleUserStatisticAsync\")\n    XblUserStatisticsGetSingleUserStatisticsAsync();\nend\n\nfunction OnXblUserStatisticsGetSingleUserStatisticsAsync()\n    print(\"OnXblUserStatisticsGetSingleUserStatisticsAsync\")\n    XblUserStatisticsGetMultipleUserStatisticsAsync();\nend\n\nfunction OnXblUserStatisticsGetMultipleUserStatisticsAsync()\n    print(\"OnXblUserStatisticsGetMultipleUserStatisticsAsync\")\n    XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync();\nend\n\nfunction OnXblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync()\n    print(\"OnXblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync\")\n    XblEventsWriteInGameEvent();\n    initalSubscription = false;\nend\n\nfunction OnStatisticChangedHandler()\n    print(\"OnStatisticChangedHandler\")\n    XblRealTimeActivitySubscriptionGetState();\n    XblRealTimeActivitySubscriptionGetId();\n    if initalSubscription then\n        initalSubscription = false;\n    else\n        callDeactivate = true;\n    end\nend\n\nfunction update()\n    if callDeactivate then\n        XblUserStatisticsRemoveStatisticChangedHandler();\n        XblUserStatisticsUnsubscribeFromStatisticChange();\n        XblRealTimeActivityDeactivate();\n    end\nend\n\nfunction OnXblRealTimeActivityAddConnectionStateChangeHandler_Disconnected()\n    print(\"RTA connection disconnected\");\n    test.stopTest();\nend\n\ntest.TestStatsLegacy = function()\n    common.init(TestStatsLegacy_Handler)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stats2017/stats2017-test429.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction OnXblTitleManagedStatsWriteAsync()\n    -- this fast loop will trigger 429s\n    XblTitleManagedStatsWriteAsync();\nend\n\nfunction TitleManagedStatsNoSVD_Handler()\n    XblTitleManagedStatsWriteAsync()\nend\n\ntest.skip = true\ntest.TitleManagedStatsNoSVD = function()\n    SetCheckHR(0)\n    common.init(TitleManagedStatsNoSVD_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stats2017/stats2017.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction OnXblTitleManagedStatsWriteAsyncWithSVD()\n    XblTitleManagedStatsUpdateStatsAsync()\nend\n\nfunction OnXblTitleManagedStatsUpdateStatsAsync()\n    XblTitleManagedStatsDeleteStatsAsync()\nend\n\nfunction OnXblTitleManagedStatsDeleteStatsAsync()\n    ValidateSVD()\n    test.stopTest()\nend\n\nfunction OnXblTitleManagedStatsUnableToGetTokenAndSignature()\n    print(\"OnXblTitleManagedStatsUnableToGetTokenAndSignature\")\n    test.stopTest()\nend\n\nfunction TitleManagedStats_Handler()\n    if ClearSVD() == 1 then\n        OnXblTitleManagedStatsUnableToGetTokenAndSignature()\n    else\n        XblTitleManagedStatsWriteAsyncWithSVD()\n    end\nend\n\ntest.TitleManagedStats = function()\n    common.init(TitleManagedStats_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stringVerify/stringVerify-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestStringVerifyCpp_Handler()\n    print(\"TestStringVerifyCpp_Handler\")\n    StringServiceVerifyString()\nend\n\nfunction OnStringServiceVerifyString()\n    print(\"OnStringServiceVerifyString\")\n    StringServiceVerifyStrings()\nend\n\nfunction OnStringServiceVerifyStrings()\n    print(\"OnStringServiceVerifyStrings\")\n    test.stopTest();\nend\n\ntest.TestStringVerifyCpp = function()\n    common.init(TestStringVerifyCpp_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/stringVerify/stringVerify.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TestStringVerify_Handler()\n    print(\"TestStringVerify_Handler\")\n    XblStringVerifyStringAsync()\nend\n\nfunction OnTestStringVerify()\n    XblStringVerifyStringsAsync()\n    test.stopTest()\nend\n\ntest.TestStringVerify = function()\n    common.init(TestStringVerify_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/tests.root",
    "content": ""
  },
  {
    "path": "Tests/ApiExplorer/Tests/titleStorage/title_storage-cpp.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TitleStorageCpp()\n    print(\"TitleStorageCpp\");\n    TitleStorageServiceGetQuota();\nend\n\nfunction OnTitleStorageServiceGetQuota()\n    print('OnTitleStorageServiceGetQuota')\n    print('Calling TitleStorageServiceUploadBlob')\n    TitleStorageServiceUploadBlob(\n        \"title_storage_type::universal\", \n        \"apirunner/test/path.txt\", \n        \"title_storage_blob_type::binary\",\n        \"Test Binary Blob Upload\", \n        \"title_storage_e_tag_match_condition::not_used\"\n    );\nend\n\nfunction OnTitleStorageServiceUploadBlob()\n    print('OnTitleStorageServiceUploadBlob')\n    print('Getting blob metadata')\n    TitleStorageServiceGetBlobMetadata(\n        \"title_storage_type::universal\",\n        \"\",\n        0,\n        0,\n        2\n    );\nend\n\nfunction OnTitleStorageServiceGetBlobMetadata()\n    print('OnTitleStorageServiceGetBlobMetadata')\n    hr, hasNext = TitleStorageBlobMetadataResultHasNextCpp()\n    print(\"hasNext \" .. hr)\n    print(\"hr \" .. hr)\n    if hasNext ~= 0 then\n        TitleStorageBlobMetadataResultGetNextCpp(2)\n    else\n        OnTitleStorageBlobMetadataResultGetNextCpp()\n    end\nend\n\nfunction OnTitleStorageBlobMetadataResultGetNextCpp()\n    print('OnTitleStorageBlobMetadataResultGetNextCpp')\n    print('Calling TitleStorageServiceDownloadBlob')\n    TitleStorageServiceDownloadBlob(\"\")\nend\n\nfunction OnTitleStorageServiceDownloadBlob()\n    print('OnTitleStorageServiceDownloadBlob')\n    print('Calling TitleStorageServiceDeleteBlobAsync')\n    TitleStorageServiceDeleteBlob();\nend\n\nfunction OnTitleStorageServiceDeleteBlob()\n    print('OnTitleStorageServiceDeleteBlob')\n    test.stopTest();\nend\n\ntest.TitleStorageCpp = function()\n    common.init(TitleStorageCpp)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/titleStorage/title_storage-restCalls.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TitleStorageRestAPI()\n    print(\"TitleStorage\");\n    RestCallToUploadJsonBlob(\n        \"{\\\"difficulty\\\":1,\\\"level\\\":[{\\\"number\\\":\\\"1\\\",\\\"quest\\\":\\\"swords\\\"},{\\\"number\\\":\\\"2\\\",\\\"quest\\\":\\\"iron\\\"},{\\\"number\\\":\\\"3\\\",\\\"quest\\\":\\\"gold\\\"}],\\\"weapon\\\":{\\\"name\\\":\\\"poison\\\",\\\"timeleft\\\":\\\"2mins\\\"}}\"\n    );\nend\n\nfunction OnXblTitleStorageRestUpload()\n    print('Calling RestCallToUploadJsonBlob')\n    RestCallForJsonMetadata();\nend\n\nfunction OnDownloadMetadataBlobs()\n    print('OnUploadBlobs')\n    RestCallToDownloadJsonBlob();\nend\n\nfunction OnDownloadBlobs()\n    print('OnDownloadBlobs')\n    test.stopTest();\nend\n\ntest.TitleStorageRestAPI = function()\n    common.init(TitleStorageRestAPI)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/titleStorage/title_storage.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction TitleStorage()\n    print(\"TitleStorage\");\n    XblTitleStorageGetQuotaAsync();\nend\n\nfunction OnXblTitleStorageGetQuotaAsync()\n    print('Calling XblTitleStorageUploadJsonBlobAsync')\n    XblTitleStorageUploadJsonBlobAsync(\n        \"Json Blob Upload\",\n        \"apirunner/test/path/json.txt\",\n        \"{\\\"difficulty\\\":1,\\\"level\\\":[{\\\"number\\\":\\\"1\\\",\\\"quest\\\":\\\"swords\\\"},{\\\"number\\\":\\\"2\\\",\\\"quest\\\":\\\"iron\\\"},{\\\"number\\\":\\\"3\\\",\\\"quest\\\":\\\"gold\\\"}],\\\"weapon\\\":{\\\"name\\\":\\\"poison\\\",\\\"timeleft\\\":\\\"2mins\\\"}}\",\n        \"XblTitleStorageType::Universal\", \n        \"XblTitleStorageBlobType::Json\", \n        1024, \n        \"XblTitleStorageETagMatchCondition::NotUsed\"\n    );\n\nend\n\nfunction OnXblTitleStorageUploadJsonBlobAsync()\n    print('OnXblTitleStorageUploadJsonBlobAsync')\n    print('Calling XblTitleStorageUploadBinaryBlobAsync')\n    XblTitleStorageUploadBinaryBlobAsync(\n        \"Test Name 2\", \n        \"apirunner/test/path.txt\", \n        \"XblTitleStorageType::Universal\", \n        \"XblTitleStorageBlobType::Binary\", \n        \"XblTitleStorageETagMatchCondition::NotUsed\"\n    );\nend\n\nfunction OnXblTitleStorageUploadBinaryBlobAsync()\n    print('OnXblTitleStorageUploadBinaryBlobAsync')\n    print('Getting blob metadata')\n    XblTitleStorageGetBlobMetadataAsync(\n        \"XblTitleStorageType::Universal\",\n        \"\",\n        0,\n        0,\n        2\n    );\nend\n\nfunction OnXblTitleStorageGetBlobMetadataAsync()\n    print('OnXblTitleStorageGetBlobMetadataAsync')\n    XblTitleStorageBlobMetadataResultHasNext();\n    print('Calling XblTitleStorageBlobMetadataResultGetNextAsync')\n    XblTitleStorageBlobMetadataResultGetNextAsync(2);\nend\n\nfunction OnXblTitleStorageBlobMetadataResultGetNextAsync()\n    print('OnXblTitleStorageBlobMetadataResultGetNextAsync')\n    XblTitleStorageBlobMetadataResultGetItems();\n    XblTitleStorageBlobMetadataResultDuplicateHandle();\n\n    print('Calling XblTitleStorageDownloadJsonBlobAsync')\n    XblTitleStorageDownloadJsonBlobAsync(\"weapon.name\");\nend\n\nfunction OnXblTitleStorageDownloadJsonBlobAsync()\n    print('OnXblTitleStorageDownloadJsonBlobAsync')\n    print('Calling XblTitleStorageDownloadBinaryBlobAsync')\n    XblTitleStorageDownloadBinaryBlobAsync();\nend\n\nfunction OnXblTitleStorageDownloadBinaryBlobAsync()\n    print('OnXblTitleStorageDownloadBinaryBlobAsync')\n    print('Calling XblTitleStorageDeleteJsonBlobAsync')\n    XblTitleStorageDeleteJsonBlobAsync();\nend\n\nfunction OnXblTitleStorageDeleteJsonBlobAsync()\n    print('OnXblTitleStorageDeleteJsonBlobAsync')\n    print('Calling XblTitleStorageDeleteBinaryBlobAsync')\n    XblTitleStorageDeleteBinaryBlobAsync();\nend\n\nfunction OnXblTitleStorageDeleteBinaryBlobAsync()\n    print('OnXblTitleStorageDeleteBinaryBlobAsync')\n    XblTitleStorageBlobMetadataResultCloseHandle();\n    test.stopTest();\nend\n\ntest.TitleStorage = function()\n    common.init(TitleStorage)\nend"
  },
  {
    "path": "Tests/ApiExplorer/Tests/xal/addfirst.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction AddFirst_Handler()\n    print(\"AddFirst_Handler\")\n    test.stopTest();\nend\n\ntest.addfirst = function()\n    common.init(AddFirst_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/xal/signOut.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction SignOut_Handler()\n    print(\"SignOut_Handler\")\n    if XalSignOutUserAsyncIsPresent then\n        XalSignOutUserAsync();\n    else\n        test.stopTest();\n    end\nend\n\nfunction OnXalSignOutUserAsync()\n    print(\"OnXalSignOutUserAsync\")\n    XblContextCloseHandle();\n    XalUserCloseHandle();\n    Sleep(1000);\n    XalAddUserWithUiAsync();\nend\n\nfunction OnXalAddUserWithUiAsync()\n    print(\"OnXalAddUserWithUiAsync\")\n    test.stopTest();\nend\n\ntest.skip = true\ntest.signOut = function()\n    common.init(SignOut_Handler)\nend\n\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/xblHttp/XBLHttpCall.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\n\nfunction testXblHttpCall_Handler()\n    XblHttpCallCreate();\n    XblHttpCallDuplicate();\n    XblHttpCallValidateSetters();\n    XblHttpCallValidateGetters();\n\n    test.stopTest();\nend\n\ntest.testXblHttpCall = function()\n    print(\"testXblHttpCall\")\n    common.init(testXblHttpCall_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/Tests/xblHttp/XBLHttpCallPerform.lua",
    "content": "test = require 'u-test'\ncommon = require 'common'\n\nfunction XblHttpCallPerformCompleted()\n    test.stopTest();\nend\n\nfunction testXblHttpCallPerform_Handler()\n    XblHttpCallCreate();\n    XblHttpCallPerform();\nend\n\ntest.testXblHttpCallPerform = function()\n    print(\"testXblHttpCallPerform\")\n    common.init(testXblHttpCallPerform_Handler)\nend\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/Makefile",
    "content": "# Makefile for installing Lua\n# See doc/readme.html for installation and customization instructions.\n\n# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================\n\n# Your platform. See PLATS for possible values.\nPLAT= none\n\n# Where to install. The installation starts in the src and doc directories,\n# so take care if INSTALL_TOP is not an absolute path. See the local target.\n# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with\n# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.\nINSTALL_TOP= /usr/local\nINSTALL_BIN= $(INSTALL_TOP)/bin\nINSTALL_INC= $(INSTALL_TOP)/include\nINSTALL_LIB= $(INSTALL_TOP)/lib\nINSTALL_MAN= $(INSTALL_TOP)/man/man1\nINSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V\nINSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V\n\n# How to install. If your install program does not support \"-p\", then\n# you may have to run ranlib on the installed liblua.a.\nINSTALL= install -p\nINSTALL_EXEC= $(INSTALL) -m 0755\nINSTALL_DATA= $(INSTALL) -m 0644\n#\n# If you don't have \"install\" you can use \"cp\" instead.\n# INSTALL= cp -p\n# INSTALL_EXEC= $(INSTALL)\n# INSTALL_DATA= $(INSTALL)\n\n# Other utilities.\nMKDIR= mkdir -p\nRM= rm -f\n\n# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======\n\n# Convenience platforms targets.\nPLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris\n\n# What to install.\nTO_BIN= lua luac\nTO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp\nTO_LIB= liblua.a\nTO_MAN= lua.1 luac.1\n\n# Lua version and release.\nV= 5.3\nR= $V.4\n\n# Targets start here.\nall:\t$(PLAT)\n\n$(PLATS) clean:\n\tcd src && $(MAKE) $@\n\ntest:\tdummy\n\tsrc/lua -v\n\ninstall: dummy\n\tcd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)\n\tcd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)\n\tcd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)\n\tcd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)\n\tcd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)\n\nuninstall:\n\tcd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)\n\tcd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)\n\tcd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)\n\tcd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)\n\nlocal:\n\t$(MAKE) install INSTALL_TOP=../install\n\nnone:\n\t@echo \"Please do 'make PLATFORM' where PLATFORM is one of these:\"\n\t@echo \"   $(PLATS)\"\n\t@echo \"See doc/readme.html for complete instructions.\"\n\n# make may get confused with test/ and install/\ndummy:\n\n# echo config parameters\necho:\n\t@cd src && $(MAKE) -s echo\n\t@echo \"PLAT= $(PLAT)\"\n\t@echo \"V= $V\"\n\t@echo \"R= $R\"\n\t@echo \"TO_BIN= $(TO_BIN)\"\n\t@echo \"TO_INC= $(TO_INC)\"\n\t@echo \"TO_LIB= $(TO_LIB)\"\n\t@echo \"TO_MAN= $(TO_MAN)\"\n\t@echo \"INSTALL_TOP= $(INSTALL_TOP)\"\n\t@echo \"INSTALL_BIN= $(INSTALL_BIN)\"\n\t@echo \"INSTALL_INC= $(INSTALL_INC)\"\n\t@echo \"INSTALL_LIB= $(INSTALL_LIB)\"\n\t@echo \"INSTALL_MAN= $(INSTALL_MAN)\"\n\t@echo \"INSTALL_LMOD= $(INSTALL_LMOD)\"\n\t@echo \"INSTALL_CMOD= $(INSTALL_CMOD)\"\n\t@echo \"INSTALL_EXEC= $(INSTALL_EXEC)\"\n\t@echo \"INSTALL_DATA= $(INSTALL_DATA)\"\n\n# echo pkg-config data\npc:\n\t@echo \"version=$R\"\n\t@echo \"prefix=$(INSTALL_TOP)\"\n\t@echo \"libdir=$(INSTALL_LIB)\"\n\t@echo \"includedir=$(INSTALL_INC)\"\n\n# list targets that do not create files (but not all makes understand .PHONY)\n.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho\n\n# (end of Makefile)\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/README",
    "content": "\nThis is Lua 5.3.5, released on 26 Jun 2018.\n\nFor installation instructions, license details, and\nfurther information about Lua, see doc/readme.html.\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/contents.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<HTML>\n<HEAD>\n<TITLE>Lua 5.3 Reference Manual - contents</TITLE>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"lua.css\">\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"index.css\">\n<META HTTP-EQUIV=\"content-type\" CONTENT=\"text/html; charset=iso-8859-1\">\n</HEAD>\n\n<BODY>\n\n<H1>\n<A HREF=\"http://www.lua.org/\"><IMG SRC=\"logo.gif\" ALT=\"Lua\"></A>\nLua 5.3 Reference Manual\n</H1>\n\n<P>\nThe reference manual is the official definition of the Lua language.\n<BR>\nFor a complete introduction to Lua programming, see the book\n<A HREF=\"http://www.lua.org/pil/\">Programming in Lua</A>.\n\n<DIV CLASS=\"menubar\">\n<A HREF=\"manual.html\">start</A>\n&middot;\n<A HREF=\"#contents\">contents</A>\n&middot;\n<A HREF=\"#index\">index</A>\n&middot;\n<A HREF=\"http://www.lua.org/manual/\">other versions</A>\n</DIV>\n\n<P>\n<SMALL>\nCopyright &copy; 2015&ndash;2018 Lua.org, PUC-Rio.\nFreely available under the terms of the\n<A HREF=\"http://www.lua.org/license.html\">Lua license</A>.\n</SMALL>\n\n<H2><A NAME=\"contents\">Contents</A></H2>\n<UL CLASS=\"contents menubar\">\n<LI><A HREF=\"manual.html\">1 &ndash; Introduction</A>\n<P>\n<LI><A HREF=\"manual.html#2\">2 &ndash; Basic Concepts</A>\n<UL>\n<LI><A HREF=\"manual.html#2.1\">2.1 &ndash; Values and Types</A>\n<LI><A HREF=\"manual.html#2.2\">2.2 &ndash; Environments and the Global Environment</A>\n<LI><A HREF=\"manual.html#2.3\">2.3 &ndash; Error Handling</A>\n<LI><A HREF=\"manual.html#2.4\">2.4 &ndash; Metatables and Metamethods</A>\n<LI><A HREF=\"manual.html#2.5\">2.5 &ndash; Garbage Collection</A>\n<UL>\n<LI><A HREF=\"manual.html#2.5.1\">2.5.1 &ndash; Garbage-Collection Metamethods</A>\n<LI><A HREF=\"manual.html#2.5.2\">2.5.2 &ndash; Weak Tables</A>\n</UL>\n<LI><A HREF=\"manual.html#2.6\">2.6 &ndash; Coroutines</A>\n</UL>\n<P>\n<LI><A HREF=\"manual.html#3\">3 &ndash; The Language</A>\n<UL>\n<LI><A HREF=\"manual.html#3.1\">3.1 &ndash; Lexical Conventions</A>\n<LI><A HREF=\"manual.html#3.2\">3.2 &ndash; Variables</A>\n<LI><A HREF=\"manual.html#3.3\">3.3 &ndash; Statements</A>\n<UL>\n<LI><A HREF=\"manual.html#3.3.1\">3.3.1 &ndash; Blocks</A>\n<LI><A HREF=\"manual.html#3.3.2\">3.3.2 &ndash; Chunks</A>\n<LI><A HREF=\"manual.html#3.3.3\">3.3.3 &ndash; Assignment</A>\n<LI><A HREF=\"manual.html#3.3.4\">3.3.4 &ndash; Control Structures</A>\n<LI><A HREF=\"manual.html#3.3.5\">3.3.5 &ndash; For Statement</A>\n<LI><A HREF=\"manual.html#3.3.6\">3.3.6 &ndash; Function Calls as Statements</A>\n<LI><A HREF=\"manual.html#3.3.7\">3.3.7 &ndash; Local Declarations</A>\n</UL>\n<LI><A HREF=\"manual.html#3.4\">3.4 &ndash; Expressions</A>\n<UL>\n<LI><A HREF=\"manual.html#3.4.1\">3.4.1 &ndash; Arithmetic Operators</A>\n<LI><A HREF=\"manual.html#3.4.2\">3.4.2 &ndash; Bitwise Operators</A>\n<LI><A HREF=\"manual.html#3.4.3\">3.4.3 &ndash; Coercions and Conversions</A>\n<LI><A HREF=\"manual.html#3.4.4\">3.4.4 &ndash; Relational Operators</A>\n<LI><A HREF=\"manual.html#3.4.5\">3.4.5 &ndash; Logical Operators</A>\n<LI><A HREF=\"manual.html#3.4.6\">3.4.6 &ndash; Concatenation</A>\n<LI><A HREF=\"manual.html#3.4.7\">3.4.7 &ndash; The Length Operator</A>\n<LI><A HREF=\"manual.html#3.4.8\">3.4.8 &ndash; Precedence</A>\n<LI><A HREF=\"manual.html#3.4.9\">3.4.9 &ndash; Table Constructors</A>\n<LI><A HREF=\"manual.html#3.4.10\">3.4.10 &ndash; Function Calls</A>\n<LI><A HREF=\"manual.html#3.4.11\">3.4.11 &ndash; Function Definitions</A>\n</UL>\n<LI><A HREF=\"manual.html#3.5\">3.5 &ndash; Visibility Rules</A>\n</UL>\n<P>\n<LI><A HREF=\"manual.html#4\">4 &ndash; The Application Program Interface</A>\n<UL>\n<LI><A HREF=\"manual.html#4.1\">4.1 &ndash; The Stack</A>\n<LI><A HREF=\"manual.html#4.2\">4.2 &ndash; Stack Size</A>\n<LI><A HREF=\"manual.html#4.3\">4.3 &ndash; Valid and Acceptable Indices</A>\n<LI><A HREF=\"manual.html#4.4\">4.4 &ndash; C Closures</A>\n<LI><A HREF=\"manual.html#4.5\">4.5 &ndash; Registry</A>\n<LI><A HREF=\"manual.html#4.6\">4.6 &ndash; Error Handling in C</A>\n<LI><A HREF=\"manual.html#4.7\">4.7 &ndash; Handling Yields in C</A>\n<LI><A HREF=\"manual.html#4.8\">4.8 &ndash; Functions and Types</A>\n<LI><A HREF=\"manual.html#4.9\">4.9 &ndash; The Debug Interface</A>\n</UL>\n<P>\n<LI><A HREF=\"manual.html#5\">5 &ndash; The Auxiliary Library</A>\n<UL>\n<LI><A HREF=\"manual.html#5.1\">5.1 &ndash; Functions and Types</A>\n</UL>\n<P>\n<LI><A HREF=\"manual.html#6\">6 &ndash; Standard Libraries</A>\n<UL>\n<LI><A HREF=\"manual.html#6.1\">6.1 &ndash; Basic Functions</A>\n<LI><A HREF=\"manual.html#6.2\">6.2 &ndash; Coroutine Manipulation</A>\n<LI><A HREF=\"manual.html#6.3\">6.3 &ndash; Modules</A>\n<LI><A HREF=\"manual.html#6.4\">6.4 &ndash; String Manipulation</A>\n<UL>\n<LI><A HREF=\"manual.html#6.4.1\">6.4.1 &ndash; Patterns</A>\n<LI><A HREF=\"manual.html#6.4.2\">6.4.2 &ndash; Format Strings for Pack and Unpack</A>\n</UL>\n<LI><A HREF=\"manual.html#6.5\">6.5 &ndash; UTF-8 Support</A>\n<LI><A HREF=\"manual.html#6.6\">6.6 &ndash; Table Manipulation</A>\n<LI><A HREF=\"manual.html#6.7\">6.7 &ndash; Mathematical Functions</A>\n<LI><A HREF=\"manual.html#6.8\">6.8 &ndash; Input and Output Facilities</A>\n<LI><A HREF=\"manual.html#6.9\">6.9 &ndash; Operating System Facilities</A>\n<LI><A HREF=\"manual.html#6.10\">6.10 &ndash; The Debug Library</A>\n</UL>\n<P>\n<LI><A HREF=\"manual.html#7\">7 &ndash; Lua Standalone</A>\n<P>\n<LI><A HREF=\"manual.html#8\">8 &ndash; Incompatibilities with the Previous Version</A>\n<UL>\n<LI><A HREF=\"manual.html#8.1\">8.1 &ndash; Changes in the Language</A>\n<LI><A HREF=\"manual.html#8.2\">8.2 &ndash; Changes in the Libraries</A>\n<LI><A HREF=\"manual.html#8.3\">8.3 &ndash; Changes in the API</A>\n</UL>\n<P>\n<LI><A HREF=\"manual.html#9\">9 &ndash; The Complete Syntax of Lua</A>\n</UL>\n\n<H2><A NAME=\"index\">Index</A></H2>\n<TABLE CLASS=\"menubar\" WIDTH=\"100%\">\n<TR>\n<TD>\n<H3><A NAME=\"functions\">Lua functions</A></H3>\n<P>\n<A HREF=\"manual.html#6.1\">basic</A><BR>\n<A HREF=\"manual.html#pdf-_G\">_G</A><BR>\n<A HREF=\"manual.html#pdf-_VERSION\">_VERSION</A><BR>\n<A HREF=\"manual.html#pdf-assert\">assert</A><BR>\n<A HREF=\"manual.html#pdf-collectgarbage\">collectgarbage</A><BR>\n<A HREF=\"manual.html#pdf-dofile\">dofile</A><BR>\n<A HREF=\"manual.html#pdf-error\">error</A><BR>\n<A HREF=\"manual.html#pdf-getmetatable\">getmetatable</A><BR>\n<A HREF=\"manual.html#pdf-ipairs\">ipairs</A><BR>\n<A HREF=\"manual.html#pdf-load\">load</A><BR>\n<A HREF=\"manual.html#pdf-loadfile\">loadfile</A><BR>\n<A HREF=\"manual.html#pdf-next\">next</A><BR>\n<A HREF=\"manual.html#pdf-pairs\">pairs</A><BR>\n<A HREF=\"manual.html#pdf-pcall\">pcall</A><BR>\n<A HREF=\"manual.html#pdf-print\">print</A><BR>\n<A HREF=\"manual.html#pdf-rawequal\">rawequal</A><BR>\n<A HREF=\"manual.html#pdf-rawget\">rawget</A><BR>\n<A HREF=\"manual.html#pdf-rawlen\">rawlen</A><BR>\n<A HREF=\"manual.html#pdf-rawset\">rawset</A><BR>\n<A HREF=\"manual.html#pdf-require\">require</A><BR>\n<A HREF=\"manual.html#pdf-select\">select</A><BR>\n<A HREF=\"manual.html#pdf-setmetatable\">setmetatable</A><BR>\n<A HREF=\"manual.html#pdf-tonumber\">tonumber</A><BR>\n<A HREF=\"manual.html#pdf-tostring\">tostring</A><BR>\n<A HREF=\"manual.html#pdf-type\">type</A><BR>\n<A HREF=\"manual.html#pdf-xpcall\">xpcall</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.2\">coroutine</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.create\">coroutine.create</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.isyieldable\">coroutine.isyieldable</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.resume\">coroutine.resume</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.running\">coroutine.running</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.status\">coroutine.status</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.wrap\">coroutine.wrap</A><BR>\n<A HREF=\"manual.html#pdf-coroutine.yield\">coroutine.yield</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.10\">debug</A><BR>\n<A HREF=\"manual.html#pdf-debug.debug\">debug.debug</A><BR>\n<A HREF=\"manual.html#pdf-debug.gethook\">debug.gethook</A><BR>\n<A HREF=\"manual.html#pdf-debug.getinfo\">debug.getinfo</A><BR>\n<A HREF=\"manual.html#pdf-debug.getlocal\">debug.getlocal</A><BR>\n<A HREF=\"manual.html#pdf-debug.getmetatable\">debug.getmetatable</A><BR>\n<A HREF=\"manual.html#pdf-debug.getregistry\">debug.getregistry</A><BR>\n<A HREF=\"manual.html#pdf-debug.getupvalue\">debug.getupvalue</A><BR>\n<A HREF=\"manual.html#pdf-debug.getuservalue\">debug.getuservalue</A><BR>\n<A HREF=\"manual.html#pdf-debug.sethook\">debug.sethook</A><BR>\n<A HREF=\"manual.html#pdf-debug.setlocal\">debug.setlocal</A><BR>\n<A HREF=\"manual.html#pdf-debug.setmetatable\">debug.setmetatable</A><BR>\n<A HREF=\"manual.html#pdf-debug.setupvalue\">debug.setupvalue</A><BR>\n<A HREF=\"manual.html#pdf-debug.setuservalue\">debug.setuservalue</A><BR>\n<A HREF=\"manual.html#pdf-debug.traceback\">debug.traceback</A><BR>\n<A HREF=\"manual.html#pdf-debug.upvalueid\">debug.upvalueid</A><BR>\n<A HREF=\"manual.html#pdf-debug.upvaluejoin\">debug.upvaluejoin</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.8\">io</A><BR>\n<A HREF=\"manual.html#pdf-io.close\">io.close</A><BR>\n<A HREF=\"manual.html#pdf-io.flush\">io.flush</A><BR>\n<A HREF=\"manual.html#pdf-io.input\">io.input</A><BR>\n<A HREF=\"manual.html#pdf-io.lines\">io.lines</A><BR>\n<A HREF=\"manual.html#pdf-io.open\">io.open</A><BR>\n<A HREF=\"manual.html#pdf-io.output\">io.output</A><BR>\n<A HREF=\"manual.html#pdf-io.popen\">io.popen</A><BR>\n<A HREF=\"manual.html#pdf-io.read\">io.read</A><BR>\n<A HREF=\"manual.html#pdf-io.stderr\">io.stderr</A><BR>\n<A HREF=\"manual.html#pdf-io.stdin\">io.stdin</A><BR>\n<A HREF=\"manual.html#pdf-io.stdout\">io.stdout</A><BR>\n<A HREF=\"manual.html#pdf-io.tmpfile\">io.tmpfile</A><BR>\n<A HREF=\"manual.html#pdf-io.type\">io.type</A><BR>\n<A HREF=\"manual.html#pdf-io.write\">io.write</A><BR>\n\n<A HREF=\"manual.html#pdf-file:close\">file:close</A><BR>\n<A HREF=\"manual.html#pdf-file:flush\">file:flush</A><BR>\n<A HREF=\"manual.html#pdf-file:lines\">file:lines</A><BR>\n<A HREF=\"manual.html#pdf-file:read\">file:read</A><BR>\n<A HREF=\"manual.html#pdf-file:seek\">file:seek</A><BR>\n<A HREF=\"manual.html#pdf-file:setvbuf\">file:setvbuf</A><BR>\n<A HREF=\"manual.html#pdf-file:write\">file:write</A><BR>\n\n</TD>\n<TD>\n<H3>&nbsp;</H3>\n<P>\n<A HREF=\"manual.html#6.7\">math</A><BR>\n<A HREF=\"manual.html#pdf-math.abs\">math.abs</A><BR>\n<A HREF=\"manual.html#pdf-math.acos\">math.acos</A><BR>\n<A HREF=\"manual.html#pdf-math.asin\">math.asin</A><BR>\n<A HREF=\"manual.html#pdf-math.atan\">math.atan</A><BR>\n<A HREF=\"manual.html#pdf-math.ceil\">math.ceil</A><BR>\n<A HREF=\"manual.html#pdf-math.cos\">math.cos</A><BR>\n<A HREF=\"manual.html#pdf-math.deg\">math.deg</A><BR>\n<A HREF=\"manual.html#pdf-math.exp\">math.exp</A><BR>\n<A HREF=\"manual.html#pdf-math.floor\">math.floor</A><BR>\n<A HREF=\"manual.html#pdf-math.fmod\">math.fmod</A><BR>\n<A HREF=\"manual.html#pdf-math.huge\">math.huge</A><BR>\n<A HREF=\"manual.html#pdf-math.log\">math.log</A><BR>\n<A HREF=\"manual.html#pdf-math.max\">math.max</A><BR>\n<A HREF=\"manual.html#pdf-math.maxinteger\">math.maxinteger</A><BR>\n<A HREF=\"manual.html#pdf-math.min\">math.min</A><BR>\n<A HREF=\"manual.html#pdf-math.mininteger\">math.mininteger</A><BR>\n<A HREF=\"manual.html#pdf-math.modf\">math.modf</A><BR>\n<A HREF=\"manual.html#pdf-math.pi\">math.pi</A><BR>\n<A HREF=\"manual.html#pdf-math.rad\">math.rad</A><BR>\n<A HREF=\"manual.html#pdf-math.random\">math.random</A><BR>\n<A HREF=\"manual.html#pdf-math.randomseed\">math.randomseed</A><BR>\n<A HREF=\"manual.html#pdf-math.sin\">math.sin</A><BR>\n<A HREF=\"manual.html#pdf-math.sqrt\">math.sqrt</A><BR>\n<A HREF=\"manual.html#pdf-math.tan\">math.tan</A><BR>\n<A HREF=\"manual.html#pdf-math.tointeger\">math.tointeger</A><BR>\n<A HREF=\"manual.html#pdf-math.type\">math.type</A><BR>\n<A HREF=\"manual.html#pdf-math.ult\">math.ult</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.9\">os</A><BR>\n<A HREF=\"manual.html#pdf-os.clock\">os.clock</A><BR>\n<A HREF=\"manual.html#pdf-os.date\">os.date</A><BR>\n<A HREF=\"manual.html#pdf-os.difftime\">os.difftime</A><BR>\n<A HREF=\"manual.html#pdf-os.execute\">os.execute</A><BR>\n<A HREF=\"manual.html#pdf-os.exit\">os.exit</A><BR>\n<A HREF=\"manual.html#pdf-os.getenv\">os.getenv</A><BR>\n<A HREF=\"manual.html#pdf-os.remove\">os.remove</A><BR>\n<A HREF=\"manual.html#pdf-os.rename\">os.rename</A><BR>\n<A HREF=\"manual.html#pdf-os.setlocale\">os.setlocale</A><BR>\n<A HREF=\"manual.html#pdf-os.time\">os.time</A><BR>\n<A HREF=\"manual.html#pdf-os.tmpname\">os.tmpname</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.3\">package</A><BR>\n<A HREF=\"manual.html#pdf-package.config\">package.config</A><BR>\n<A HREF=\"manual.html#pdf-package.cpath\">package.cpath</A><BR>\n<A HREF=\"manual.html#pdf-package.loaded\">package.loaded</A><BR>\n<A HREF=\"manual.html#pdf-package.loadlib\">package.loadlib</A><BR>\n<A HREF=\"manual.html#pdf-package.path\">package.path</A><BR>\n<A HREF=\"manual.html#pdf-package.preload\">package.preload</A><BR>\n<A HREF=\"manual.html#pdf-package.searchers\">package.searchers</A><BR>\n<A HREF=\"manual.html#pdf-package.searchpath\">package.searchpath</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.4\">string</A><BR>\n<A HREF=\"manual.html#pdf-string.byte\">string.byte</A><BR>\n<A HREF=\"manual.html#pdf-string.char\">string.char</A><BR>\n<A HREF=\"manual.html#pdf-string.dump\">string.dump</A><BR>\n<A HREF=\"manual.html#pdf-string.find\">string.find</A><BR>\n<A HREF=\"manual.html#pdf-string.format\">string.format</A><BR>\n<A HREF=\"manual.html#pdf-string.gmatch\">string.gmatch</A><BR>\n<A HREF=\"manual.html#pdf-string.gsub\">string.gsub</A><BR>\n<A HREF=\"manual.html#pdf-string.len\">string.len</A><BR>\n<A HREF=\"manual.html#pdf-string.lower\">string.lower</A><BR>\n<A HREF=\"manual.html#pdf-string.match\">string.match</A><BR>\n<A HREF=\"manual.html#pdf-string.pack\">string.pack</A><BR>\n<A HREF=\"manual.html#pdf-string.packsize\">string.packsize</A><BR>\n<A HREF=\"manual.html#pdf-string.rep\">string.rep</A><BR>\n<A HREF=\"manual.html#pdf-string.reverse\">string.reverse</A><BR>\n<A HREF=\"manual.html#pdf-string.sub\">string.sub</A><BR>\n<A HREF=\"manual.html#pdf-string.unpack\">string.unpack</A><BR>\n<A HREF=\"manual.html#pdf-string.upper\">string.upper</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.6\">table</A><BR>\n<A HREF=\"manual.html#pdf-table.concat\">table.concat</A><BR>\n<A HREF=\"manual.html#pdf-table.insert\">table.insert</A><BR>\n<A HREF=\"manual.html#pdf-table.move\">table.move</A><BR>\n<A HREF=\"manual.html#pdf-table.pack\">table.pack</A><BR>\n<A HREF=\"manual.html#pdf-table.remove\">table.remove</A><BR>\n<A HREF=\"manual.html#pdf-table.sort\">table.sort</A><BR>\n<A HREF=\"manual.html#pdf-table.unpack\">table.unpack</A><BR>\n\n<P>\n<A HREF=\"manual.html#6.5\">utf8</A><BR>\n<A HREF=\"manual.html#pdf-utf8.char\">utf8.char</A><BR>\n<A HREF=\"manual.html#pdf-utf8.charpattern\">utf8.charpattern</A><BR>\n<A HREF=\"manual.html#pdf-utf8.codepoint\">utf8.codepoint</A><BR>\n<A HREF=\"manual.html#pdf-utf8.codes\">utf8.codes</A><BR>\n<A HREF=\"manual.html#pdf-utf8.len\">utf8.len</A><BR>\n<A HREF=\"manual.html#pdf-utf8.offset\">utf8.offset</A><BR>\n\n<H3><A NAME=\"env\">environment<BR>variables</A></H3>\n<P>\n<A HREF=\"manual.html#pdf-LUA_CPATH\">LUA_CPATH</A><BR>\n<A HREF=\"manual.html#pdf-LUA_CPATH_5_3\">LUA_CPATH_5_3</A><BR>\n<A HREF=\"manual.html#pdf-LUA_INIT\">LUA_INIT</A><BR>\n<A HREF=\"manual.html#pdf-LUA_INIT_5_3\">LUA_INIT_5_3</A><BR>\n<A HREF=\"manual.html#pdf-LUA_PATH\">LUA_PATH</A><BR>\n<A HREF=\"manual.html#pdf-LUA_PATH_5_3\">LUA_PATH_5_3</A><BR>\n\n</TD>\n<TD>\n<H3><A NAME=\"api\">C API</A></H3>\n<P>\n<A HREF=\"manual.html#lua_Alloc\">lua_Alloc</A><BR>\n<A HREF=\"manual.html#lua_CFunction\">lua_CFunction</A><BR>\n<A HREF=\"manual.html#lua_Debug\">lua_Debug</A><BR>\n<A HREF=\"manual.html#lua_Hook\">lua_Hook</A><BR>\n<A HREF=\"manual.html#lua_Integer\">lua_Integer</A><BR>\n<A HREF=\"manual.html#lua_KContext\">lua_KContext</A><BR>\n<A HREF=\"manual.html#lua_KFunction\">lua_KFunction</A><BR>\n<A HREF=\"manual.html#lua_Number\">lua_Number</A><BR>\n<A HREF=\"manual.html#lua_Reader\">lua_Reader</A><BR>\n<A HREF=\"manual.html#lua_State\">lua_State</A><BR>\n<A HREF=\"manual.html#lua_Unsigned\">lua_Unsigned</A><BR>\n<A HREF=\"manual.html#lua_Writer\">lua_Writer</A><BR>\n\n<P>\n<A HREF=\"manual.html#lua_absindex\">lua_absindex</A><BR>\n<A HREF=\"manual.html#lua_arith\">lua_arith</A><BR>\n<A HREF=\"manual.html#lua_atpanic\">lua_atpanic</A><BR>\n<A HREF=\"manual.html#lua_call\">lua_call</A><BR>\n<A HREF=\"manual.html#lua_callk\">lua_callk</A><BR>\n<A HREF=\"manual.html#lua_checkstack\">lua_checkstack</A><BR>\n<A HREF=\"manual.html#lua_close\">lua_close</A><BR>\n<A HREF=\"manual.html#lua_compare\">lua_compare</A><BR>\n<A HREF=\"manual.html#lua_concat\">lua_concat</A><BR>\n<A HREF=\"manual.html#lua_copy\">lua_copy</A><BR>\n<A HREF=\"manual.html#lua_createtable\">lua_createtable</A><BR>\n<A HREF=\"manual.html#lua_dump\">lua_dump</A><BR>\n<A HREF=\"manual.html#lua_error\">lua_error</A><BR>\n<A HREF=\"manual.html#lua_gc\">lua_gc</A><BR>\n<A HREF=\"manual.html#lua_getallocf\">lua_getallocf</A><BR>\n<A HREF=\"manual.html#lua_getextraspace\">lua_getextraspace</A><BR>\n<A HREF=\"manual.html#lua_getfield\">lua_getfield</A><BR>\n<A HREF=\"manual.html#lua_getglobal\">lua_getglobal</A><BR>\n<A HREF=\"manual.html#lua_gethook\">lua_gethook</A><BR>\n<A HREF=\"manual.html#lua_gethookcount\">lua_gethookcount</A><BR>\n<A HREF=\"manual.html#lua_gethookmask\">lua_gethookmask</A><BR>\n<A HREF=\"manual.html#lua_geti\">lua_geti</A><BR>\n<A HREF=\"manual.html#lua_getinfo\">lua_getinfo</A><BR>\n<A HREF=\"manual.html#lua_getlocal\">lua_getlocal</A><BR>\n<A HREF=\"manual.html#lua_getmetatable\">lua_getmetatable</A><BR>\n<A HREF=\"manual.html#lua_getstack\">lua_getstack</A><BR>\n<A HREF=\"manual.html#lua_gettable\">lua_gettable</A><BR>\n<A HREF=\"manual.html#lua_gettop\">lua_gettop</A><BR>\n<A HREF=\"manual.html#lua_getupvalue\">lua_getupvalue</A><BR>\n<A HREF=\"manual.html#lua_getuservalue\">lua_getuservalue</A><BR>\n<A HREF=\"manual.html#lua_insert\">lua_insert</A><BR>\n<A HREF=\"manual.html#lua_isboolean\">lua_isboolean</A><BR>\n<A HREF=\"manual.html#lua_iscfunction\">lua_iscfunction</A><BR>\n<A HREF=\"manual.html#lua_isfunction\">lua_isfunction</A><BR>\n<A HREF=\"manual.html#lua_isinteger\">lua_isinteger</A><BR>\n<A HREF=\"manual.html#lua_islightuserdata\">lua_islightuserdata</A><BR>\n<A HREF=\"manual.html#lua_isnil\">lua_isnil</A><BR>\n<A HREF=\"manual.html#lua_isnone\">lua_isnone</A><BR>\n<A HREF=\"manual.html#lua_isnoneornil\">lua_isnoneornil</A><BR>\n<A HREF=\"manual.html#lua_isnumber\">lua_isnumber</A><BR>\n<A HREF=\"manual.html#lua_isstring\">lua_isstring</A><BR>\n<A HREF=\"manual.html#lua_istable\">lua_istable</A><BR>\n<A HREF=\"manual.html#lua_isthread\">lua_isthread</A><BR>\n<A HREF=\"manual.html#lua_isuserdata\">lua_isuserdata</A><BR>\n<A HREF=\"manual.html#lua_isyieldable\">lua_isyieldable</A><BR>\n<A HREF=\"manual.html#lua_len\">lua_len</A><BR>\n<A HREF=\"manual.html#lua_load\">lua_load</A><BR>\n<A HREF=\"manual.html#lua_newstate\">lua_newstate</A><BR>\n<A HREF=\"manual.html#lua_newtable\">lua_newtable</A><BR>\n<A HREF=\"manual.html#lua_newthread\">lua_newthread</A><BR>\n<A HREF=\"manual.html#lua_newuserdata\">lua_newuserdata</A><BR>\n<A HREF=\"manual.html#lua_next\">lua_next</A><BR>\n<A HREF=\"manual.html#lua_numbertointeger\">lua_numbertointeger</A><BR>\n<A HREF=\"manual.html#lua_pcall\">lua_pcall</A><BR>\n<A HREF=\"manual.html#lua_pcallk\">lua_pcallk</A><BR>\n<A HREF=\"manual.html#lua_pop\">lua_pop</A><BR>\n<A HREF=\"manual.html#lua_pushboolean\">lua_pushboolean</A><BR>\n<A HREF=\"manual.html#lua_pushcclosure\">lua_pushcclosure</A><BR>\n<A HREF=\"manual.html#lua_pushcfunction\">lua_pushcfunction</A><BR>\n<A HREF=\"manual.html#lua_pushfstring\">lua_pushfstring</A><BR>\n<A HREF=\"manual.html#lua_pushglobaltable\">lua_pushglobaltable</A><BR>\n<A HREF=\"manual.html#lua_pushinteger\">lua_pushinteger</A><BR>\n<A HREF=\"manual.html#lua_pushlightuserdata\">lua_pushlightuserdata</A><BR>\n<A HREF=\"manual.html#lua_pushliteral\">lua_pushliteral</A><BR>\n<A HREF=\"manual.html#lua_pushlstring\">lua_pushlstring</A><BR>\n<A HREF=\"manual.html#lua_pushnil\">lua_pushnil</A><BR>\n<A HREF=\"manual.html#lua_pushnumber\">lua_pushnumber</A><BR>\n<A HREF=\"manual.html#lua_pushstring\">lua_pushstring</A><BR>\n<A HREF=\"manual.html#lua_pushthread\">lua_pushthread</A><BR>\n<A HREF=\"manual.html#lua_pushvalue\">lua_pushvalue</A><BR>\n<A HREF=\"manual.html#lua_pushvfstring\">lua_pushvfstring</A><BR>\n<A HREF=\"manual.html#lua_rawequal\">lua_rawequal</A><BR>\n<A HREF=\"manual.html#lua_rawget\">lua_rawget</A><BR>\n<A HREF=\"manual.html#lua_rawgeti\">lua_rawgeti</A><BR>\n<A HREF=\"manual.html#lua_rawgetp\">lua_rawgetp</A><BR>\n<A HREF=\"manual.html#lua_rawlen\">lua_rawlen</A><BR>\n<A HREF=\"manual.html#lua_rawset\">lua_rawset</A><BR>\n<A HREF=\"manual.html#lua_rawseti\">lua_rawseti</A><BR>\n<A HREF=\"manual.html#lua_rawsetp\">lua_rawsetp</A><BR>\n<A HREF=\"manual.html#lua_register\">lua_register</A><BR>\n<A HREF=\"manual.html#lua_remove\">lua_remove</A><BR>\n<A HREF=\"manual.html#lua_replace\">lua_replace</A><BR>\n<A HREF=\"manual.html#lua_resume\">lua_resume</A><BR>\n<A HREF=\"manual.html#lua_rotate\">lua_rotate</A><BR>\n<A HREF=\"manual.html#lua_setallocf\">lua_setallocf</A><BR>\n<A HREF=\"manual.html#lua_setfield\">lua_setfield</A><BR>\n<A HREF=\"manual.html#lua_setglobal\">lua_setglobal</A><BR>\n<A HREF=\"manual.html#lua_sethook\">lua_sethook</A><BR>\n<A HREF=\"manual.html#lua_seti\">lua_seti</A><BR>\n<A HREF=\"manual.html#lua_setlocal\">lua_setlocal</A><BR>\n<A HREF=\"manual.html#lua_setmetatable\">lua_setmetatable</A><BR>\n<A HREF=\"manual.html#lua_settable\">lua_settable</A><BR>\n<A HREF=\"manual.html#lua_settop\">lua_settop</A><BR>\n<A HREF=\"manual.html#lua_setupvalue\">lua_setupvalue</A><BR>\n<A HREF=\"manual.html#lua_setuservalue\">lua_setuservalue</A><BR>\n<A HREF=\"manual.html#lua_status\">lua_status</A><BR>\n<A HREF=\"manual.html#lua_stringtonumber\">lua_stringtonumber</A><BR>\n<A HREF=\"manual.html#lua_toboolean\">lua_toboolean</A><BR>\n<A HREF=\"manual.html#lua_tocfunction\">lua_tocfunction</A><BR>\n<A HREF=\"manual.html#lua_tointeger\">lua_tointeger</A><BR>\n<A HREF=\"manual.html#lua_tointegerx\">lua_tointegerx</A><BR>\n<A HREF=\"manual.html#lua_tolstring\">lua_tolstring</A><BR>\n<A HREF=\"manual.html#lua_tonumber\">lua_tonumber</A><BR>\n<A HREF=\"manual.html#lua_tonumberx\">lua_tonumberx</A><BR>\n<A HREF=\"manual.html#lua_topointer\">lua_topointer</A><BR>\n<A HREF=\"manual.html#lua_tostring\">lua_tostring</A><BR>\n<A HREF=\"manual.html#lua_tothread\">lua_tothread</A><BR>\n<A HREF=\"manual.html#lua_touserdata\">lua_touserdata</A><BR>\n<A HREF=\"manual.html#lua_type\">lua_type</A><BR>\n<A HREF=\"manual.html#lua_typename\">lua_typename</A><BR>\n<A HREF=\"manual.html#lua_upvalueid\">lua_upvalueid</A><BR>\n<A HREF=\"manual.html#lua_upvalueindex\">lua_upvalueindex</A><BR>\n<A HREF=\"manual.html#lua_upvaluejoin\">lua_upvaluejoin</A><BR>\n<A HREF=\"manual.html#lua_version\">lua_version</A><BR>\n<A HREF=\"manual.html#lua_xmove\">lua_xmove</A><BR>\n<A HREF=\"manual.html#lua_yield\">lua_yield</A><BR>\n<A HREF=\"manual.html#lua_yieldk\">lua_yieldk</A><BR>\n\n</TD>\n<TD>\n<H3><A NAME=\"auxlib\">auxiliary library</A></H3>\n<P>\n<A HREF=\"manual.html#luaL_Buffer\">luaL_Buffer</A><BR>\n<A HREF=\"manual.html#luaL_Reg\">luaL_Reg</A><BR>\n<A HREF=\"manual.html#luaL_Stream\">luaL_Stream</A><BR>\n\n<P>\n<A HREF=\"manual.html#luaL_addchar\">luaL_addchar</A><BR>\n<A HREF=\"manual.html#luaL_addlstring\">luaL_addlstring</A><BR>\n<A HREF=\"manual.html#luaL_addsize\">luaL_addsize</A><BR>\n<A HREF=\"manual.html#luaL_addstring\">luaL_addstring</A><BR>\n<A HREF=\"manual.html#luaL_addvalue\">luaL_addvalue</A><BR>\n<A HREF=\"manual.html#luaL_argcheck\">luaL_argcheck</A><BR>\n<A HREF=\"manual.html#luaL_argerror\">luaL_argerror</A><BR>\n<A HREF=\"manual.html#luaL_buffinit\">luaL_buffinit</A><BR>\n<A HREF=\"manual.html#luaL_buffinitsize\">luaL_buffinitsize</A><BR>\n<A HREF=\"manual.html#luaL_callmeta\">luaL_callmeta</A><BR>\n<A HREF=\"manual.html#luaL_checkany\">luaL_checkany</A><BR>\n<A HREF=\"manual.html#luaL_checkinteger\">luaL_checkinteger</A><BR>\n<A HREF=\"manual.html#luaL_checklstring\">luaL_checklstring</A><BR>\n<A HREF=\"manual.html#luaL_checknumber\">luaL_checknumber</A><BR>\n<A HREF=\"manual.html#luaL_checkoption\">luaL_checkoption</A><BR>\n<A HREF=\"manual.html#luaL_checkstack\">luaL_checkstack</A><BR>\n<A HREF=\"manual.html#luaL_checkstring\">luaL_checkstring</A><BR>\n<A HREF=\"manual.html#luaL_checktype\">luaL_checktype</A><BR>\n<A HREF=\"manual.html#luaL_checkudata\">luaL_checkudata</A><BR>\n<A HREF=\"manual.html#luaL_checkversion\">luaL_checkversion</A><BR>\n<A HREF=\"manual.html#luaL_dofile\">luaL_dofile</A><BR>\n<A HREF=\"manual.html#luaL_dostring\">luaL_dostring</A><BR>\n<A HREF=\"manual.html#luaL_error\">luaL_error</A><BR>\n<A HREF=\"manual.html#luaL_execresult\">luaL_execresult</A><BR>\n<A HREF=\"manual.html#luaL_fileresult\">luaL_fileresult</A><BR>\n<A HREF=\"manual.html#luaL_getmetafield\">luaL_getmetafield</A><BR>\n<A HREF=\"manual.html#luaL_getmetatable\">luaL_getmetatable</A><BR>\n<A HREF=\"manual.html#luaL_getsubtable\">luaL_getsubtable</A><BR>\n<A HREF=\"manual.html#luaL_gsub\">luaL_gsub</A><BR>\n<A HREF=\"manual.html#luaL_len\">luaL_len</A><BR>\n<A HREF=\"manual.html#luaL_loadbuffer\">luaL_loadbuffer</A><BR>\n<A HREF=\"manual.html#luaL_loadbufferx\">luaL_loadbufferx</A><BR>\n<A HREF=\"manual.html#luaL_loadfile\">luaL_loadfile</A><BR>\n<A HREF=\"manual.html#luaL_loadfilex\">luaL_loadfilex</A><BR>\n<A HREF=\"manual.html#luaL_loadstring\">luaL_loadstring</A><BR>\n<A HREF=\"manual.html#luaL_newlib\">luaL_newlib</A><BR>\n<A HREF=\"manual.html#luaL_newlibtable\">luaL_newlibtable</A><BR>\n<A HREF=\"manual.html#luaL_newmetatable\">luaL_newmetatable</A><BR>\n<A HREF=\"manual.html#luaL_newstate\">luaL_newstate</A><BR>\n<A HREF=\"manual.html#luaL_openlibs\">luaL_openlibs</A><BR>\n<A HREF=\"manual.html#luaL_opt\">luaL_opt</A><BR>\n<A HREF=\"manual.html#luaL_optinteger\">luaL_optinteger</A><BR>\n<A HREF=\"manual.html#luaL_optlstring\">luaL_optlstring</A><BR>\n<A HREF=\"manual.html#luaL_optnumber\">luaL_optnumber</A><BR>\n<A HREF=\"manual.html#luaL_optstring\">luaL_optstring</A><BR>\n<A HREF=\"manual.html#luaL_prepbuffer\">luaL_prepbuffer</A><BR>\n<A HREF=\"manual.html#luaL_prepbuffsize\">luaL_prepbuffsize</A><BR>\n<A HREF=\"manual.html#luaL_pushresult\">luaL_pushresult</A><BR>\n<A HREF=\"manual.html#luaL_pushresultsize\">luaL_pushresultsize</A><BR>\n<A HREF=\"manual.html#luaL_ref\">luaL_ref</A><BR>\n<A HREF=\"manual.html#luaL_requiref\">luaL_requiref</A><BR>\n<A HREF=\"manual.html#luaL_setfuncs\">luaL_setfuncs</A><BR>\n<A HREF=\"manual.html#luaL_setmetatable\">luaL_setmetatable</A><BR>\n<A HREF=\"manual.html#luaL_testudata\">luaL_testudata</A><BR>\n<A HREF=\"manual.html#luaL_tolstring\">luaL_tolstring</A><BR>\n<A HREF=\"manual.html#luaL_traceback\">luaL_traceback</A><BR>\n<A HREF=\"manual.html#luaL_typename\">luaL_typename</A><BR>\n<A HREF=\"manual.html#luaL_unref\">luaL_unref</A><BR>\n<A HREF=\"manual.html#luaL_where\">luaL_where</A><BR>\n\n<H3><A NAME=\"library\">standard library</A></H3>\n<P>\n<A HREF=\"manual.html#pdf-luaopen_base\">luaopen_base</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_coroutine\">luaopen_coroutine</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_debug\">luaopen_debug</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_io\">luaopen_io</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_math\">luaopen_math</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_os\">luaopen_os</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_package\">luaopen_package</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_string\">luaopen_string</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_table\">luaopen_table</A><BR>\n<A HREF=\"manual.html#pdf-luaopen_utf8\">luaopen_utf8</A><BR>\n\n<H3><A NAME=\"constants\">constants</A></H3>\n<P>\n<A HREF=\"manual.html#pdf-LUA_ERRERR\">LUA_ERRERR</A><BR>\n<A HREF=\"manual.html#pdf-LUA_ERRFILE\">LUA_ERRFILE</A><BR>\n<A HREF=\"manual.html#pdf-LUA_ERRGCMM\">LUA_ERRGCMM</A><BR>\n<A HREF=\"manual.html#pdf-LUA_ERRMEM\">LUA_ERRMEM</A><BR>\n<A HREF=\"manual.html#pdf-LUA_ERRRUN\">LUA_ERRRUN</A><BR>\n<A HREF=\"manual.html#pdf-LUA_ERRSYNTAX\">LUA_ERRSYNTAX</A><BR>\n<A HREF=\"manual.html#pdf-LUA_HOOKCALL\">LUA_HOOKCALL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_HOOKCOUNT\">LUA_HOOKCOUNT</A><BR>\n<A HREF=\"manual.html#pdf-LUA_HOOKLINE\">LUA_HOOKLINE</A><BR>\n<A HREF=\"manual.html#pdf-LUA_HOOKRET\">LUA_HOOKRET</A><BR>\n<A HREF=\"manual.html#pdf-LUA_HOOKTAILCALL\">LUA_HOOKTAILCALL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MASKCALL\">LUA_MASKCALL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MASKCOUNT\">LUA_MASKCOUNT</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MASKLINE\">LUA_MASKLINE</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MASKRET\">LUA_MASKRET</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MAXINTEGER\">LUA_MAXINTEGER</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MININTEGER\">LUA_MININTEGER</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MINSTACK\">LUA_MINSTACK</A><BR>\n<A HREF=\"manual.html#pdf-LUA_MULTRET\">LUA_MULTRET</A><BR>\n<A HREF=\"manual.html#pdf-LUA_NOREF\">LUA_NOREF</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OK\">LUA_OK</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPADD\">LUA_OPADD</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPBAND\">LUA_OPBAND</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPBNOT\">LUA_OPBNOT</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPBOR\">LUA_OPBOR</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPBXOR\">LUA_OPBXOR</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPDIV\">LUA_OPDIV</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPEQ\">LUA_OPEQ</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPIDIV\">LUA_OPIDIV</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPLE\">LUA_OPLE</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPLT\">LUA_OPLT</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPMOD\">LUA_OPMOD</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPMUL\">LUA_OPMUL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPPOW\">LUA_OPPOW</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPSHL\">LUA_OPSHL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPSHR\">LUA_OPSHR</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPSUB\">LUA_OPSUB</A><BR>\n<A HREF=\"manual.html#pdf-LUA_OPUNM\">LUA_OPUNM</A><BR>\n<A HREF=\"manual.html#pdf-LUA_REFNIL\">LUA_REFNIL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_REGISTRYINDEX\">LUA_REGISTRYINDEX</A><BR>\n<A HREF=\"manual.html#pdf-LUA_RIDX_GLOBALS\">LUA_RIDX_GLOBALS</A><BR>\n<A HREF=\"manual.html#pdf-LUA_RIDX_MAINTHREAD\">LUA_RIDX_MAINTHREAD</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TBOOLEAN\">LUA_TBOOLEAN</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TFUNCTION\">LUA_TFUNCTION</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TLIGHTUSERDATA\">LUA_TLIGHTUSERDATA</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TNIL\">LUA_TNIL</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TNONE\">LUA_TNONE</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TNUMBER\">LUA_TNUMBER</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TSTRING\">LUA_TSTRING</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TTABLE\">LUA_TTABLE</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TTHREAD\">LUA_TTHREAD</A><BR>\n<A HREF=\"manual.html#pdf-LUA_TUSERDATA\">LUA_TUSERDATA</A><BR>\n<A HREF=\"manual.html#pdf-LUA_USE_APICHECK\">LUA_USE_APICHECK</A><BR>\n<A HREF=\"manual.html#pdf-LUA_YIELD\">LUA_YIELD</A><BR>\n<A HREF=\"manual.html#pdf-LUAL_BUFFERSIZE\">LUAL_BUFFERSIZE</A><BR>\n\n</TD>\n</TR>\n</TABLE>\n\n<P CLASS=\"footer\">\nLast update:\nMon Jun 18 22:56:06 -03 2018\n</P>\n<!--\nLast change: revised for Lua 5.3.5\n-->\n\n</BODY>\n</HTML>\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/index.css",
    "content": "ul {\n\tlist-style-type: none ;\n}\n\nul.contents {\n\tpadding: 0 ;\n}\n\ntable {\n\tborder: none ;\n\tborder-spacing: 0 ;\n\tborder-collapse: collapse ;\n}\n\ntd {\n\tvertical-align: top ;\n\tpadding: 0 ;\n\ttext-align: left ;\n\tline-height: 1.25 ;\n\twidth: 15% ;\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/lua.1",
    "content": ".\\\" $Id: lua.man,v 1.14 2016/10/17 15:43:50 lhf Exp $\n.TH LUA 1 \"$Date: 2016/10/17 15:43:50 $\"\n.SH NAME\nlua \\- Lua interpreter\n.SH SYNOPSIS\n.B lua\n[\n.I options\n]\n[\n.I script\n[\n.I args\n]\n]\n.SH DESCRIPTION\n.B lua\nis the standalone Lua interpreter.\nIt loads and executes Lua programs,\neither in textual source form or\nin precompiled binary form.\n(Precompiled binaries are output by\n.BR luac ,\nthe Lua compiler.)\n.B lua\ncan be used as a batch interpreter and also interactively.\n.LP\nThe given\n.I options\nare handled in order and then\nthe Lua program in file\n.I script\nis loaded and executed.\nThe given\n.I args\nare available to\n.I script\nas strings in a global table named\n.BR arg .\nIf no options or arguments are given,\nthen\n.B \"\\-v \\-i\"\nis assumed when the standard input is a terminal;\notherwise,\n.B \"\\-\"\nis assumed.\n.LP\nIn interactive mode,\n.B lua\nprompts the user,\nreads lines from the standard input,\nand executes them as they are read.\nIf the line contains an expression or list of expressions,\nthen the line is evaluated and the results are printed.\nIf a line does not contain a complete statement,\nthen a secondary prompt is displayed and\nlines are read until a complete statement is formed or\na syntax error is found.\n.LP\nAt the very start,\nbefore even handling the command line,\n.B lua\nchecks the contents of the environment variables\n.B LUA_INIT_5_3\nor\n.BR LUA_INIT ,\nin that order.\nIf the contents is of the form\n.RI '@ filename ',\nthen\n.I filename\nis executed.\nOtherwise, the string is assumed to be a Lua statement and is executed.\n.SH OPTIONS\n.TP\n.BI \\-e \" stat\"\nexecute statement\n.IR stat .\n.TP\n.B \\-i\nenter interactive mode after executing\n.IR script .\n.TP\n.BI \\-l \" name\"\nexecute the equivalent of\n.IB name =require(' name ')\nbefore executing\n.IR script .\n.TP\n.B \\-v\nshow version information.\n.TP\n.B \\-E\nignore environment variables.\n.TP\n.B \\-\\-\nstop handling options.\n.TP\n.B \\-\nstop handling options and execute the standard input as a file.\n.SH \"SEE ALSO\"\n.BR luac (1)\n.br\nThe documentation at lua.org,\nespecially section 7 of the reference manual.\n.SH DIAGNOSTICS\nError messages should be self explanatory.\n.SH AUTHORS\nR. Ierusalimschy,\nL. H. de Figueiredo,\nW. Celes\n.\\\" EOF\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/lua.css",
    "content": "html {\n\tbackground-color: #F8F8F8 ;\n}\n\nbody {\n\tbackground-color: #FFFFFF ;\n\tcolor: #000000 ;\n\tfont-family: Helvetica, Arial, sans-serif ;\n\ttext-align: justify ;\n\tline-height: 1.25 ;\n\tmargin: 16px auto ;\n\tpadding: 32px ;\n\tborder: solid #ccc 1px ;\n\tborder-radius: 20px ;\n\tmax-width: 70em ;\n\twidth: 90% ;\n}\n\nh1, h2, h3, h4 {\n\tcolor: #000080 ;\n\tfont-family: Verdana, Geneva, sans-serif ;\n\tfont-weight: normal ;\n\tfont-style: normal ;\n\ttext-align: left ;\n}\n\nh1 {\n\tfont-size: 28pt ;\n}\n\nh1 img {\n\tvertical-align: text-bottom ;\n}\n\nh2:before {\n\tcontent: \"\\2756\" ;\n\tpadding-right: 0.5em ;\n}\n\na {\n\ttext-decoration: none ;\n}\n\na:link {\n\tcolor: #000080 ;\n}\n\na:link:hover, a:visited:hover {\n\tbackground-color: #D0D0FF ;\n\tcolor: #000080 ;\n\tborder-radius: 4px ;\n}\n\na:link:active, a:visited:active {\n\tcolor: #FF0000 ;\n}\n\ndiv.menubar {\n\tpadding-bottom: 0.5em ;\n}\n\np.menubar {\n\tmargin-left: 2.5em ;\n}\n\n.menubar a:hover  {\n\tmargin: -3px -3px -3px -3px ;\n\tpadding: 3px  3px  3px  3px ;\n\tborder-radius: 4px ;\n}\n\n:target {\n\tbackground-color: #F0F0F0 ;\n\tmargin: -8px ;\n\tpadding: 8px ;\n\tborder-radius: 8px ;\n\toutline: none ;\n}\n\nhr {\n\tdisplay: none ;\n}\n\ntable hr {\n\tbackground-color: #a0a0a0 ;\n\tcolor: #a0a0a0 ;\n\tborder: 0 ;\n\theight: 1px ;\n\tdisplay: block ;\n}\n\n.footer {\n\tcolor: gray ;\n\tfont-size: x-small ;\n\ttext-transform: lowercase ;\n}\n\ninput[type=text] {\n\tborder: solid #a0a0a0 2px ;\n\tborder-radius: 2em ;\n\tbackground-image: url('images/search.png') ;\n\tbackground-repeat: no-repeat ;\n\tbackground-position: 4px center ;\n\tpadding-left: 20px ;\n\theight: 2em ;\n}\n\npre.session {\n\tbackground-color: #F8F8F8 ;\n\tpadding: 1em ;\n\tborder-radius: 8px ;\n}\n\ntable {\n\tborder: none ;\n\tborder-spacing: 0 ;\n\tborder-collapse: collapse ;\n}\n\ntd {\n\tpadding: 0 ;\n\tmargin: 0 ;\n}\n\ntd.gutter {\n\twidth: 4% ;\n}\n\ntable.columns td {\n\tvertical-align: top ;\n\tpadding-bottom: 1em ;\n\ttext-align: justify ;\n\tline-height: 1.25 ;\n}\n\ntable.book td {\n\tvertical-align: top ;\n}\n\ntable.book td.cover {\n\tpadding-right: 1em ;\n}\n\ntable.book img {\n\tborder: solid #000080 1px ;\n}\n\ntable.book span {\n\tfont-size: small ;\n\ttext-align: left ;\n\tdisplay: block ;\n\tmargin-top: 0.25em ;\n}\n\np.logos a:link:hover, p.logos a:visited:hover {\n\tbackground-color: inherit ;\n}\n\nimg {\n\tbackground-color: white ;\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/luac.1",
    "content": ".\\\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $\n.TH LUAC 1 \"$Date: 2011/11/16 13:53:40 $\"\n.SH NAME\nluac \\- Lua compiler\n.SH SYNOPSIS\n.B luac\n[\n.I options\n] [\n.I filenames\n]\n.SH DESCRIPTION\n.B luac\nis the Lua compiler.\nIt translates programs written in the Lua programming language\ninto binary files containing precompiled chunks\nthat can be later loaded and executed.\n.LP\nThe main advantages of precompiling chunks are:\nfaster loading,\nprotecting source code from accidental user changes,\nand\noff-line syntax checking.\nPrecompiling does not imply faster execution\nbecause in Lua chunks are always compiled into bytecodes before being executed.\n.B luac\nsimply allows those bytecodes to be saved in a file for later execution.\nPrecompiled chunks are not necessarily smaller than the corresponding source.\nThe main goal in precompiling is faster loading.\n.LP\nIn the command line,\nyou can mix\ntext files containing Lua source and\nbinary files containing precompiled chunks.\n.B luac\nproduces a single output file containing the combined bytecodes\nfor all files given.\nExecuting the combined file is equivalent to executing the given files.\nBy default,\nthe output file is named\n.BR luac.out ,\nbut you can change this with the\n.B \\-o\noption.\n.LP\nPrecompiled chunks are\n.I not\nportable across different architectures.\nMoreover,\nthe internal format of precompiled chunks\nis likely to change when a new version of Lua is released.\nMake sure you save the source files of all Lua programs that you precompile.\n.LP\n.SH OPTIONS\n.TP\n.B \\-l\nproduce a listing of the compiled bytecode for Lua's virtual machine.\nListing bytecodes is useful to learn about Lua's virtual machine.\nIf no files are given, then\n.B luac\nloads\n.B luac.out\nand lists its contents.\nUse\n.B \\-l \\-l\nfor a full listing.\n.TP\n.BI \\-o \" file\"\noutput to\n.IR file ,\ninstead of the default\n.BR luac.out .\n(You can use\n.B \"'\\-'\"\nfor standard output,\nbut not on platforms that open standard output in text mode.)\nThe output file may be one of the given files because\nall files are loaded before the output file is written.\nBe careful not to overwrite precious files.\n.TP\n.B \\-p\nload files but do not generate any output file.\nUsed mainly for syntax checking and for testing precompiled chunks:\ncorrupted files will probably generate errors when loaded.\nIf no files are given, then\n.B luac\nloads\n.B luac.out\nand tests its contents.\nNo messages are displayed if the file loads without errors.\n.TP\n.B \\-s\nstrip debug information before writing the output file.\nThis saves some space in very large chunks,\nbut if errors occur when running a stripped chunk,\nthen the error messages may not contain the full information they usually do.\nIn particular,\nline numbers and names of local variables are lost.\n.TP\n.B \\-v\nshow version information.\n.TP\n.B \\-\\-\nstop handling options.\n.TP\n.B \\-\nstop handling options and process standard input.\n.SH \"SEE ALSO\"\n.BR lua (1)\n.br\nThe documentation at lua.org.\n.SH DIAGNOSTICS\nError messages should be self explanatory.\n.SH AUTHORS\nR. Ierusalimschy,\nL. H. de Figueiredo,\nW. Celes\n.\\\" EOF\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/manual.css",
    "content": "h3 code {\n\tfont-family: inherit ;\n\tfont-size: inherit ;\n}\n\npre, code {\n\tfont-size: 12pt ;\n}\n\nspan.apii {\n\tcolor: gray ;\n\tfloat: right ;\n\tfont-family: inherit ;\n\tfont-style: normal ;\n\tfont-size: small ;\n}\n\nh2:before {\n\tcontent: \"\" ;\n\tpadding-right: 0em ;\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/manual.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<HTML>\n<HEAD>\n<TITLE>Lua 5.3 Reference Manual</TITLE>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"lua.css\">\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"manual.css\">\n<META HTTP-EQUIV=\"content-type\" CONTENT=\"text/html; charset=iso-8859-1\">\n</HEAD>\n\n<BODY>\n\n<H1>\n<A HREF=\"http://www.lua.org/\"><IMG SRC=\"logo.gif\" ALT=\"Lua\"></A>\nLua 5.3 Reference Manual\n</H1>\n\n<P>\nby Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes\n\n<P>\n<SMALL>\nCopyright &copy; 2015&ndash;2018 Lua.org, PUC-Rio.\nFreely available under the terms of the\n<a href=\"http://www.lua.org/license.html\">Lua license</a>.\n</SMALL>\n\n<DIV CLASS=\"menubar\">\n<A HREF=\"contents.html#contents\">contents</A>\n&middot;\n<A HREF=\"contents.html#index\">index</A>\n&middot;\n<A HREF=\"http://www.lua.org/manual/\">other versions</A>\n</DIV>\n\n<!-- ====================================================================== -->\n<p>\n\n<!-- $Id: manual.of,v 1.167.1.2 2018/06/26 15:49:07 roberto Exp $ -->\n\n\n\n\n<h1>1 &ndash; <a name=\"1\">Introduction</a></h1>\n\n<p>\nLua is a powerful, efficient, lightweight, embeddable scripting language.\nIt supports procedural programming,\nobject-oriented programming, functional programming,\ndata-driven programming, and data description.\n\n\n<p>\nLua combines simple procedural syntax with powerful data description\nconstructs based on associative arrays and extensible semantics.\nLua is dynamically typed,\nruns by interpreting bytecode with a register-based\nvirtual machine,\nand has automatic memory management with\nincremental garbage collection,\nmaking it ideal for configuration, scripting,\nand rapid prototyping.\n\n\n<p>\nLua is implemented as a library, written in <em>clean C</em>,\nthe common subset of Standard&nbsp;C and C++.\nThe Lua distribution includes a host program called <code>lua</code>,\nwhich uses the Lua library to offer a complete,\nstandalone Lua interpreter,\nfor interactive or batch use.\nLua is intended to be used both as a powerful, lightweight,\nembeddable scripting language for any program that needs one,\nand as a powerful but lightweight and efficient stand-alone language.\n\n\n<p>\nAs an extension language, Lua has no notion of a \"main\" program:\nit works <em>embedded</em> in a host client,\ncalled the <em>embedding program</em> or simply the <em>host</em>.\n(Frequently, this host is the stand-alone <code>lua</code> program.)\nThe host program can invoke functions to execute a piece of Lua code,\ncan write and read Lua variables,\nand can register C&nbsp;functions to be called by Lua code.\nThrough the use of C&nbsp;functions, Lua can be augmented to cope with\na wide range of different domains,\nthus creating customized programming languages sharing a syntactical framework.\n\n\n<p>\nLua is free software,\nand is provided as usual with no guarantees,\nas stated in its license.\nThe implementation described in this manual is available\nat Lua's official web site, <code>www.lua.org</code>.\n\n\n<p>\nLike any other reference manual,\nthis document is dry in places.\nFor a discussion of the decisions behind the design of Lua,\nsee the technical papers available at Lua's web site.\nFor a detailed introduction to programming in Lua,\nsee Roberto's book, <em>Programming in Lua</em>.\n\n\n\n<h1>2 &ndash; <a name=\"2\">Basic Concepts</a></h1>\n\n<p>\nThis section describes the basic concepts of the language.\n\n\n\n<h2>2.1 &ndash; <a name=\"2.1\">Values and Types</a></h2>\n\n<p>\nLua is a <em>dynamically typed language</em>.\nThis means that\nvariables do not have types; only values do.\nThere are no type definitions in the language.\nAll values carry their own type.\n\n\n<p>\nAll values in Lua are <em>first-class values</em>.\nThis means that all values can be stored in variables,\npassed as arguments to other functions, and returned as results.\n\n\n<p>\nThere are eight basic types in Lua:\n<em>nil</em>, <em>boolean</em>, <em>number</em>,\n<em>string</em>, <em>function</em>, <em>userdata</em>,\n<em>thread</em>, and <em>table</em>.\nThe type <em>nil</em> has one single value, <b>nil</b>,\nwhose main property is to be different from any other value;\nit usually represents the absence of a useful value.\nThe type <em>boolean</em> has two values, <b>false</b> and <b>true</b>.\nBoth <b>nil</b> and <b>false</b> make a condition false;\nany other value makes it true.\nThe type <em>number</em> represents both\ninteger numbers and real (floating-point) numbers.\nThe type <em>string</em> represents immutable sequences of bytes.\n\nLua is 8-bit clean:\nstrings can contain any 8-bit value,\nincluding embedded zeros ('<code>\\0</code>').\nLua is also encoding-agnostic;\nit makes no assumptions about the contents of a string.\n\n\n<p>\nThe type <em>number</em> uses two internal representations,\nor two subtypes,\none called <em>integer</em> and the other called <em>float</em>.\nLua has explicit rules about when each representation is used,\nbut it also converts between them automatically as needed (see <a href=\"#3.4.3\">&sect;3.4.3</a>).\nTherefore,\nthe programmer may choose to mostly ignore the difference\nbetween integers and floats\nor to assume complete control over the representation of each number.\nStandard Lua uses 64-bit integers and double-precision (64-bit) floats,\nbut you can also compile Lua so that it\nuses 32-bit integers and/or single-precision (32-bit) floats.\nThe option with 32 bits for both integers and floats\nis particularly attractive\nfor small machines and embedded systems.\n(See macro <code>LUA_32BITS</code> in file <code>luaconf.h</code>.)\n\n\n<p>\nLua can call (and manipulate) functions written in Lua and\nfunctions written in C (see <a href=\"#3.4.10\">&sect;3.4.10</a>).\nBoth are represented by the type <em>function</em>.\n\n\n<p>\nThe type <em>userdata</em> is provided to allow arbitrary C&nbsp;data to\nbe stored in Lua variables.\nA userdata value represents a block of raw memory.\nThere are two kinds of userdata:\n<em>full userdata</em>,\nwhich is an object with a block of memory managed by Lua,\nand <em>light userdata</em>,\nwhich is simply a C&nbsp;pointer value.\nUserdata has no predefined operations in Lua,\nexcept assignment and identity test.\nBy using <em>metatables</em>,\nthe programmer can define operations for full userdata values\n(see <a href=\"#2.4\">&sect;2.4</a>).\nUserdata values cannot be created or modified in Lua,\nonly through the C&nbsp;API.\nThis guarantees the integrity of data owned by the host program.\n\n\n<p>\nThe type <em>thread</em> represents independent threads of execution\nand it is used to implement coroutines (see <a href=\"#2.6\">&sect;2.6</a>).\nLua threads are not related to operating-system threads.\nLua supports coroutines on all systems,\neven those that do not support threads natively.\n\n\n<p>\nThe type <em>table</em> implements associative arrays,\nthat is, arrays that can have as indices not only numbers,\nbut any Lua value except <b>nil</b> and NaN.\n(<em>Not a Number</em> is a special value used to represent\nundefined or unrepresentable numerical results, such as <code>0/0</code>.)\nTables can be <em>heterogeneous</em>;\nthat is, they can contain values of all types (except <b>nil</b>).\nAny key with value <b>nil</b> is not considered part of the table.\nConversely, any key that is not part of a table has\nan associated value <b>nil</b>.\n\n\n<p>\nTables are the sole data-structuring mechanism in Lua;\nthey can be used to represent ordinary arrays, lists,\nsymbol tables, sets, records, graphs, trees, etc.\nTo represent records, Lua uses the field name as an index.\nThe language supports this representation by\nproviding <code>a.name</code> as syntactic sugar for <code>a[\"name\"]</code>.\nThere are several convenient ways to create tables in Lua\n(see <a href=\"#3.4.9\">&sect;3.4.9</a>).\n\n\n<p>\nLike indices,\nthe values of table fields can be of any type.\nIn particular,\nbecause functions are first-class values,\ntable fields can contain functions.\nThus tables can also carry <em>methods</em> (see <a href=\"#3.4.11\">&sect;3.4.11</a>).\n\n\n<p>\nThe indexing of tables follows\nthe definition of raw equality in the language.\nThe expressions <code>a[i]</code> and <code>a[j]</code>\ndenote the same table element\nif and only if <code>i</code> and <code>j</code> are raw equal\n(that is, equal without metamethods).\nIn particular, floats with integral values\nare equal to their respective integers\n(e.g., <code>1.0 == 1</code>).\nTo avoid ambiguities,\nany float with integral value used as a key\nis converted to its respective integer.\nFor instance, if you write <code>a[2.0] = true</code>,\nthe actual key inserted into the table will be the\ninteger <code>2</code>.\n(On the other hand,\n2 and \"<code>2</code>\" are different Lua values and therefore\ndenote different table entries.)\n\n\n<p>\nTables, functions, threads, and (full) userdata values are <em>objects</em>:\nvariables do not actually <em>contain</em> these values,\nonly <em>references</em> to them.\nAssignment, parameter passing, and function returns\nalways manipulate references to such values;\nthese operations do not imply any kind of copy.\n\n\n<p>\nThe library function <a href=\"#pdf-type\"><code>type</code></a> returns a string describing the type\nof a given value (see <a href=\"#6.1\">&sect;6.1</a>).\n\n\n\n\n\n<h2>2.2 &ndash; <a name=\"2.2\">Environments and the Global Environment</a></h2>\n\n<p>\nAs will be discussed in <a href=\"#3.2\">&sect;3.2</a> and <a href=\"#3.3.3\">&sect;3.3.3</a>,\nany reference to a free name\n(that is, a name not bound to any declaration) <code>var</code>\nis syntactically translated to <code>_ENV.var</code>.\nMoreover, every chunk is compiled in the scope of\nan external local variable named <code>_ENV</code> (see <a href=\"#3.3.2\">&sect;3.3.2</a>),\nso <code>_ENV</code> itself is never a free name in a chunk.\n\n\n<p>\nDespite the existence of this external <code>_ENV</code> variable and\nthe translation of free names,\n<code>_ENV</code> is a completely regular name.\nIn particular,\nyou can define new variables and parameters with that name.\nEach reference to a free name uses the <code>_ENV</code> that is\nvisible at that point in the program,\nfollowing the usual visibility rules of Lua (see <a href=\"#3.5\">&sect;3.5</a>).\n\n\n<p>\nAny table used as the value of <code>_ENV</code> is called an <em>environment</em>.\n\n\n<p>\nLua keeps a distinguished environment called the <em>global environment</em>.\nThis value is kept at a special index in the C registry (see <a href=\"#4.5\">&sect;4.5</a>).\nIn Lua, the global variable <a href=\"#pdf-_G\"><code>_G</code></a> is initialized with this same value.\n(<a href=\"#pdf-_G\"><code>_G</code></a> is never used internally.)\n\n\n<p>\nWhen Lua loads a chunk,\nthe default value for its <code>_ENV</code> upvalue\nis the global environment (see <a href=\"#pdf-load\"><code>load</code></a>).\nTherefore, by default,\nfree names in Lua code refer to entries in the global environment\n(and, therefore, they are also called <em>global variables</em>).\nMoreover, all standard libraries are loaded in the global environment\nand some functions there operate on that environment.\nYou can use <a href=\"#pdf-load\"><code>load</code></a> (or <a href=\"#pdf-loadfile\"><code>loadfile</code></a>)\nto load a chunk with a different environment.\n(In C, you have to load the chunk and then change the value\nof its first upvalue.)\n\n\n\n\n\n<h2>2.3 &ndash; <a name=\"2.3\">Error Handling</a></h2>\n\n<p>\nBecause Lua is an embedded extension language,\nall Lua actions start from C&nbsp;code in the host program\ncalling a function from the Lua library.\n(When you use Lua standalone,\nthe <code>lua</code> application is the host program.)\nWhenever an error occurs during\nthe compilation or execution of a Lua chunk,\ncontrol returns to the host,\nwhich can take appropriate measures\n(such as printing an error message).\n\n\n<p>\nLua code can explicitly generate an error by calling the\n<a href=\"#pdf-error\"><code>error</code></a> function.\nIf you need to catch errors in Lua,\nyou can use <a href=\"#pdf-pcall\"><code>pcall</code></a> or <a href=\"#pdf-xpcall\"><code>xpcall</code></a>\nto call a given function in <em>protected mode</em>.\n\n\n<p>\nWhenever there is an error,\nan <em>error object</em> (also called an <em>error message</em>)\nis propagated with information about the error.\nLua itself only generates errors whose error object is a string,\nbut programs may generate errors with\nany value as the error object.\nIt is up to the Lua program or its host to handle such error objects.\n\n\n<p>\nWhen you use <a href=\"#pdf-xpcall\"><code>xpcall</code></a> or <a href=\"#lua_pcall\"><code>lua_pcall</code></a>,\nyou may give a <em>message handler</em>\nto be called in case of errors.\nThis function is called with the original error object\nand returns a new error object.\nIt is called before the error unwinds the stack,\nso that it can gather more information about the error,\nfor instance by inspecting the stack and creating a stack traceback.\nThis message handler is still protected by the protected call;\nso, an error inside the message handler\nwill call the message handler again.\nIf this loop goes on for too long,\nLua breaks it and returns an appropriate message.\n(The message handler is called only for regular runtime errors.\nIt is not called for memory-allocation errors\nnor for errors while running finalizers.)\n\n\n\n\n\n<h2>2.4 &ndash; <a name=\"2.4\">Metatables and Metamethods</a></h2>\n\n<p>\nEvery value in Lua can have a <em>metatable</em>.\nThis <em>metatable</em> is an ordinary Lua table\nthat defines the behavior of the original value\nunder certain special operations.\nYou can change several aspects of the behavior\nof operations over a value by setting specific fields in its metatable.\nFor instance, when a non-numeric value is the operand of an addition,\nLua checks for a function in the field \"<code>__add</code>\" of the value's metatable.\nIf it finds one,\nLua calls this function to perform the addition.\n\n\n<p>\nThe key for each event in a metatable is a string\nwith the event name prefixed by two underscores;\nthe corresponding values are called <em>metamethods</em>.\nIn the previous example, the key is \"<code>__add</code>\"\nand the metamethod is the function that performs the addition.\nUnless stated otherwise,\nmetamethods should be function values.\n\n\n<p>\nYou can query the metatable of any value\nusing the <a href=\"#pdf-getmetatable\"><code>getmetatable</code></a> function.\nLua queries metamethods in metatables using a raw access (see <a href=\"#pdf-rawget\"><code>rawget</code></a>).\nSo, to retrieve the metamethod for event <code>ev</code> in object <code>o</code>,\nLua does the equivalent to the following code:\n\n<pre>\n     rawget(getmetatable(<em>o</em>) or {}, \"__<em>ev</em>\")\n</pre>\n\n<p>\nYou can replace the metatable of tables\nusing the <a href=\"#pdf-setmetatable\"><code>setmetatable</code></a> function.\nYou cannot change the metatable of other types from Lua code\n(except by using the debug library (<a href=\"#6.10\">&sect;6.10</a>));\nyou should use the C&nbsp;API for that.\n\n\n<p>\nTables and full userdata have individual metatables\n(although multiple tables and userdata can share their metatables).\nValues of all other types share one single metatable per type;\nthat is, there is one single metatable for all numbers,\none for all strings, etc.\nBy default, a value has no metatable,\nbut the string library sets a metatable for the string type (see <a href=\"#6.4\">&sect;6.4</a>).\n\n\n<p>\nA metatable controls how an object behaves in\narithmetic operations, bitwise operations,\norder comparisons, concatenation, length operation, calls, and indexing.\nA metatable also can define a function to be called\nwhen a userdata or a table is garbage collected (<a href=\"#2.5\">&sect;2.5</a>).\n\n\n<p>\nFor the unary operators (negation, length, and bitwise NOT),\nthe metamethod is computed and called with a dummy second operand,\nequal to the first one.\nThis extra operand is only to simplify Lua's internals\n(by making these operators behave like a binary operation)\nand may be removed in future versions.\n(For most uses this extra operand is irrelevant.)\n\n\n<p>\nA detailed list of events controlled by metatables is given next.\nEach operation is identified by its corresponding key.\n\n\n\n<ul>\n\n<li><b><code>__add</code>: </b>\nthe addition (<code>+</code>) operation.\nIf any operand for an addition is not a number\n(nor a string coercible to a number),\nLua will try to call a metamethod.\nFirst, Lua will check the first operand (even if it is valid).\nIf that operand does not define a metamethod for <code>__add</code>,\nthen Lua will check the second operand.\nIf Lua can find a metamethod,\nit calls the metamethod with the two operands as arguments,\nand the result of the call\n(adjusted to one value)\nis the result of the operation.\nOtherwise,\nit raises an error.\n</li>\n\n<li><b><code>__sub</code>: </b>\nthe subtraction (<code>-</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__mul</code>: </b>\nthe multiplication (<code>*</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__div</code>: </b>\nthe division (<code>/</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__mod</code>: </b>\nthe modulo (<code>%</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__pow</code>: </b>\nthe exponentiation (<code>^</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__unm</code>: </b>\nthe negation (unary <code>-</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__idiv</code>: </b>\nthe floor division (<code>//</code>) operation.\nBehavior similar to the addition operation.\n</li>\n\n<li><b><code>__band</code>: </b>\nthe bitwise AND (<code>&amp;</code>) operation.\nBehavior similar to the addition operation,\nexcept that Lua will try a metamethod\nif any operand is neither an integer\nnor a value coercible to an integer (see <a href=\"#3.4.3\">&sect;3.4.3</a>).\n</li>\n\n<li><b><code>__bor</code>: </b>\nthe bitwise OR (<code>|</code>) operation.\nBehavior similar to the bitwise AND operation.\n</li>\n\n<li><b><code>__bxor</code>: </b>\nthe bitwise exclusive OR (binary <code>~</code>) operation.\nBehavior similar to the bitwise AND operation.\n</li>\n\n<li><b><code>__bnot</code>: </b>\nthe bitwise NOT (unary <code>~</code>) operation.\nBehavior similar to the bitwise AND operation.\n</li>\n\n<li><b><code>__shl</code>: </b>\nthe bitwise left shift (<code>&lt;&lt;</code>) operation.\nBehavior similar to the bitwise AND operation.\n</li>\n\n<li><b><code>__shr</code>: </b>\nthe bitwise right shift (<code>&gt;&gt;</code>) operation.\nBehavior similar to the bitwise AND operation.\n</li>\n\n<li><b><code>__concat</code>: </b>\nthe concatenation (<code>..</code>) operation.\nBehavior similar to the addition operation,\nexcept that Lua will try a metamethod\nif any operand is neither a string nor a number\n(which is always coercible to a string).\n</li>\n\n<li><b><code>__len</code>: </b>\nthe length (<code>#</code>) operation.\nIf the object is not a string,\nLua will try its metamethod.\nIf there is a metamethod,\nLua calls it with the object as argument,\nand the result of the call\n(always adjusted to one value)\nis the result of the operation.\nIf there is no metamethod but the object is a table,\nthen Lua uses the table length operation (see <a href=\"#3.4.7\">&sect;3.4.7</a>).\nOtherwise, Lua raises an error.\n</li>\n\n<li><b><code>__eq</code>: </b>\nthe equal (<code>==</code>) operation.\nBehavior similar to the addition operation,\nexcept that Lua will try a metamethod only when the values\nbeing compared are either both tables or both full userdata\nand they are not primitively equal.\nThe result of the call is always converted to a boolean.\n</li>\n\n<li><b><code>__lt</code>: </b>\nthe less than (<code>&lt;</code>) operation.\nBehavior similar to the addition operation,\nexcept that Lua will try a metamethod only when the values\nbeing compared are neither both numbers nor both strings.\nThe result of the call is always converted to a boolean.\n</li>\n\n<li><b><code>__le</code>: </b>\nthe less equal (<code>&lt;=</code>) operation.\nUnlike other operations,\nthe less-equal operation can use two different events.\nFirst, Lua looks for the <code>__le</code> metamethod in both operands,\nlike in the less than operation.\nIf it cannot find such a metamethod,\nthen it will try the <code>__lt</code> metamethod,\nassuming that <code>a &lt;= b</code> is equivalent to <code>not (b &lt; a)</code>.\nAs with the other comparison operators,\nthe result is always a boolean.\n(This use of the <code>__lt</code> event can be removed in future versions;\nit is also slower than a real <code>__le</code> metamethod.)\n</li>\n\n<li><b><code>__index</code>: </b>\nThe indexing access operation <code>table[key]</code>.\nThis event happens when <code>table</code> is not a table or\nwhen <code>key</code> is not present in <code>table</code>.\nThe metamethod is looked up in <code>table</code>.\n\n\n<p>\nDespite the name,\nthe metamethod for this event can be either a function or a table.\nIf it is a function,\nit is called with <code>table</code> and <code>key</code> as arguments,\nand the result of the call\n(adjusted to one value)\nis the result of the operation.\nIf it is a table,\nthe final result is the result of indexing this table with <code>key</code>.\n(This indexing is regular, not raw,\nand therefore can trigger another metamethod.)\n</li>\n\n<li><b><code>__newindex</code>: </b>\nThe indexing assignment <code>table[key] = value</code>.\nLike the index event,\nthis event happens when <code>table</code> is not a table or\nwhen <code>key</code> is not present in <code>table</code>.\nThe metamethod is looked up in <code>table</code>.\n\n\n<p>\nLike with indexing,\nthe metamethod for this event can be either a function or a table.\nIf it is a function,\nit is called with <code>table</code>, <code>key</code>, and <code>value</code> as arguments.\nIf it is a table,\nLua does an indexing assignment to this table with the same key and value.\n(This assignment is regular, not raw,\nand therefore can trigger another metamethod.)\n\n\n<p>\nWhenever there is a <code>__newindex</code> metamethod,\nLua does not perform the primitive assignment.\n(If necessary,\nthe metamethod itself can call <a href=\"#pdf-rawset\"><code>rawset</code></a>\nto do the assignment.)\n</li>\n\n<li><b><code>__call</code>: </b>\nThe call operation <code>func(args)</code>.\nThis event happens when Lua tries to call a non-function value\n(that is, <code>func</code> is not a function).\nThe metamethod is looked up in <code>func</code>.\nIf present,\nthe metamethod is called with <code>func</code> as its first argument,\nfollowed by the arguments of the original call (<code>args</code>).\nAll results of the call\nare the result of the operation.\n(This is the only metamethod that allows multiple results.)\n</li>\n\n</ul>\n\n<p>\nIt is a good practice to add all needed metamethods to a table\nbefore setting it as a metatable of some object.\nIn particular, the <code>__gc</code> metamethod works only when this order\nis followed (see <a href=\"#2.5.1\">&sect;2.5.1</a>).\n\n\n<p>\nBecause metatables are regular tables,\nthey can contain arbitrary fields,\nnot only the event names defined above.\nSome functions in the standard library\n(e.g., <a href=\"#pdf-tostring\"><code>tostring</code></a>)\nuse other fields in metatables for their own purposes.\n\n\n\n\n\n<h2>2.5 &ndash; <a name=\"2.5\">Garbage Collection</a></h2>\n\n<p>\nLua performs automatic memory management.\nThis means that\nyou do not have to worry about allocating memory for new objects\nor freeing it when the objects are no longer needed.\nLua manages memory automatically by running\na <em>garbage collector</em> to collect all <em>dead objects</em>\n(that is, objects that are no longer accessible from Lua).\nAll memory used by Lua is subject to automatic management:\nstrings, tables, userdata, functions, threads, internal structures, etc.\n\n\n<p>\nLua implements an incremental mark-and-sweep collector.\nIt uses two numbers to control its garbage-collection cycles:\nthe <em>garbage-collector pause</em> and\nthe <em>garbage-collector step multiplier</em>.\nBoth use percentage points as units\n(e.g., a value of 100 means an internal value of 1).\n\n\n<p>\nThe garbage-collector pause\ncontrols how long the collector waits before starting a new cycle.\nLarger values make the collector less aggressive.\nValues smaller than 100 mean the collector will not wait to\nstart a new cycle.\nA value of 200 means that the collector waits for the total memory in use\nto double before starting a new cycle.\n\n\n<p>\nThe garbage-collector step multiplier\ncontrols the relative speed of the collector relative to\nmemory allocation.\nLarger values make the collector more aggressive but also increase\nthe size of each incremental step.\nYou should not use values smaller than 100,\nbecause they make the collector too slow and\ncan result in the collector never finishing a cycle.\nThe default is 200,\nwhich means that the collector runs at \"twice\"\nthe speed of memory allocation.\n\n\n<p>\nIf you set the step multiplier to a very large number\n(larger than 10% of the maximum number of\nbytes that the program may use),\nthe collector behaves like a stop-the-world collector.\nIf you then set the pause to 200,\nthe collector behaves as in old Lua versions,\ndoing a complete collection every time Lua doubles its\nmemory usage.\n\n\n<p>\nYou can change these numbers by calling <a href=\"#lua_gc\"><code>lua_gc</code></a> in C\nor <a href=\"#pdf-collectgarbage\"><code>collectgarbage</code></a> in Lua.\nYou can also use these functions to control\nthe collector directly (e.g., stop and restart it).\n\n\n\n<h3>2.5.1 &ndash; <a name=\"2.5.1\">Garbage-Collection Metamethods</a></h3>\n\n<p>\nYou can set garbage-collector metamethods for tables\nand, using the C&nbsp;API,\nfor full userdata (see <a href=\"#2.4\">&sect;2.4</a>).\nThese metamethods are also called <em>finalizers</em>.\nFinalizers allow you to coordinate Lua's garbage collection\nwith external resource management\n(such as closing files, network or database connections,\nor freeing your own memory).\n\n\n<p>\nFor an object (table or userdata) to be finalized when collected,\nyou must <em>mark</em> it for finalization.\n\nYou mark an object for finalization when you set its metatable\nand the metatable has a field indexed by the string \"<code>__gc</code>\".\nNote that if you set a metatable without a <code>__gc</code> field\nand later create that field in the metatable,\nthe object will not be marked for finalization.\n\n\n<p>\nWhen a marked object becomes garbage,\nit is not collected immediately by the garbage collector.\nInstead, Lua puts it in a list.\nAfter the collection,\nLua goes through that list.\nFor each object in the list,\nit checks the object's <code>__gc</code> metamethod:\nIf it is a function,\nLua calls it with the object as its single argument;\nif the metamethod is not a function,\nLua simply ignores it.\n\n\n<p>\nAt the end of each garbage-collection cycle,\nthe finalizers for objects are called in\nthe reverse order that the objects were marked for finalization,\namong those collected in that cycle;\nthat is, the first finalizer to be called is the one associated\nwith the object marked last in the program.\nThe execution of each finalizer may occur at any point during\nthe execution of the regular code.\n\n\n<p>\nBecause the object being collected must still be used by the finalizer,\nthat object (and other objects accessible only through it)\nmust be <em>resurrected</em> by Lua.\nUsually, this resurrection is transient,\nand the object memory is freed in the next garbage-collection cycle.\nHowever, if the finalizer stores the object in some global place\n(e.g., a global variable),\nthen the resurrection is permanent.\nMoreover, if the finalizer marks a finalizing object for finalization again,\nits finalizer will be called again in the next cycle where the\nobject is unreachable.\nIn any case,\nthe object memory is freed only in a GC cycle where\nthe object is unreachable and not marked for finalization.\n\n\n<p>\nWhen you close a state (see <a href=\"#lua_close\"><code>lua_close</code></a>),\nLua calls the finalizers of all objects marked for finalization,\nfollowing the reverse order that they were marked.\nIf any finalizer marks objects for collection during that phase,\nthese marks have no effect.\n\n\n\n\n\n<h3>2.5.2 &ndash; <a name=\"2.5.2\">Weak Tables</a></h3>\n\n<p>\nA <em>weak table</em> is a table whose elements are\n<em>weak references</em>.\nA weak reference is ignored by the garbage collector.\nIn other words,\nif the only references to an object are weak references,\nthen the garbage collector will collect that object.\n\n\n<p>\nA weak table can have weak keys, weak values, or both.\nA table with weak values allows the collection of its values,\nbut prevents the collection of its keys.\nA table with both weak keys and weak values allows the collection of\nboth keys and values.\nIn any case, if either the key or the value is collected,\nthe whole pair is removed from the table.\nThe weakness of a table is controlled by the\n<code>__mode</code> field of its metatable.\nIf the <code>__mode</code> field is a string containing the character&nbsp;'<code>k</code>',\nthe keys in the table are weak.\nIf <code>__mode</code> contains '<code>v</code>',\nthe values in the table are weak.\n\n\n<p>\nA table with weak keys and strong values\nis also called an <em>ephemeron table</em>.\nIn an ephemeron table,\na value is considered reachable only if its key is reachable.\nIn particular,\nif the only reference to a key comes through its value,\nthe pair is removed.\n\n\n<p>\nAny change in the weakness of a table may take effect only\nat the next collect cycle.\nIn particular, if you change the weakness to a stronger mode,\nLua may still collect some items from that table\nbefore the change takes effect.\n\n\n<p>\nOnly objects that have an explicit construction\nare removed from weak tables.\nValues, such as numbers and light C&nbsp;functions,\nare not subject to garbage collection,\nand therefore are not removed from weak tables\n(unless their associated values are collected).\nAlthough strings are subject to garbage collection,\nthey do not have an explicit construction,\nand therefore are not removed from weak tables.\n\n\n<p>\nResurrected objects\n(that is, objects being finalized\nand objects accessible only through objects being finalized)\nhave a special behavior in weak tables.\nThey are removed from weak values before running their finalizers,\nbut are removed from weak keys only in the next collection\nafter running their finalizers, when such objects are actually freed.\nThis behavior allows the finalizer to access properties\nassociated with the object through weak tables.\n\n\n<p>\nIf a weak table is among the resurrected objects in a collection cycle,\nit may not be properly cleared until the next cycle.\n\n\n\n\n\n\n\n<h2>2.6 &ndash; <a name=\"2.6\">Coroutines</a></h2>\n\n<p>\nLua supports coroutines,\nalso called <em>collaborative multithreading</em>.\nA coroutine in Lua represents an independent thread of execution.\nUnlike threads in multithread systems, however,\na coroutine only suspends its execution by explicitly calling\na yield function.\n\n\n<p>\nYou create a coroutine by calling <a href=\"#pdf-coroutine.create\"><code>coroutine.create</code></a>.\nIts sole argument is a function\nthat is the main function of the coroutine.\nThe <code>create</code> function only creates a new coroutine and\nreturns a handle to it (an object of type <em>thread</em>);\nit does not start the coroutine.\n\n\n<p>\nYou execute a coroutine by calling <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a>.\nWhen you first call <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a>,\npassing as its first argument\na thread returned by <a href=\"#pdf-coroutine.create\"><code>coroutine.create</code></a>,\nthe coroutine starts its execution by\ncalling its main function.\nExtra arguments passed to <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a> are passed\nas arguments to that function.\nAfter the coroutine starts running,\nit runs until it terminates or <em>yields</em>.\n\n\n<p>\nA coroutine can terminate its execution in two ways:\nnormally, when its main function returns\n(explicitly or implicitly, after the last instruction);\nand abnormally, if there is an unprotected error.\nIn case of normal termination,\n<a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a> returns <b>true</b>,\nplus any values returned by the coroutine main function.\nIn case of errors, <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a> returns <b>false</b>\nplus an error object.\n\n\n<p>\nA coroutine yields by calling <a href=\"#pdf-coroutine.yield\"><code>coroutine.yield</code></a>.\nWhen a coroutine yields,\nthe corresponding <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a> returns immediately,\neven if the yield happens inside nested function calls\n(that is, not in the main function,\nbut in a function directly or indirectly called by the main function).\nIn the case of a yield, <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a> also returns <b>true</b>,\nplus any values passed to <a href=\"#pdf-coroutine.yield\"><code>coroutine.yield</code></a>.\nThe next time you resume the same coroutine,\nit continues its execution from the point where it yielded,\nwith the call to <a href=\"#pdf-coroutine.yield\"><code>coroutine.yield</code></a> returning any extra\narguments passed to <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a>.\n\n\n<p>\nLike <a href=\"#pdf-coroutine.create\"><code>coroutine.create</code></a>,\nthe <a href=\"#pdf-coroutine.wrap\"><code>coroutine.wrap</code></a> function also creates a coroutine,\nbut instead of returning the coroutine itself,\nit returns a function that, when called, resumes the coroutine.\nAny arguments passed to this function\ngo as extra arguments to <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a>.\n<a href=\"#pdf-coroutine.wrap\"><code>coroutine.wrap</code></a> returns all the values returned by <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a>,\nexcept the first one (the boolean error code).\nUnlike <a href=\"#pdf-coroutine.resume\"><code>coroutine.resume</code></a>,\n<a href=\"#pdf-coroutine.wrap\"><code>coroutine.wrap</code></a> does not catch errors;\nany error is propagated to the caller.\n\n\n<p>\nAs an example of how coroutines work,\nconsider the following code:\n\n<pre>\n     function foo (a)\n       print(\"foo\", a)\n       return coroutine.yield(2*a)\n     end\n     \n     co = coroutine.create(function (a,b)\n           print(\"co-body\", a, b)\n           local r = foo(a+1)\n           print(\"co-body\", r)\n           local r, s = coroutine.yield(a+b, a-b)\n           print(\"co-body\", r, s)\n           return b, \"end\"\n     end)\n     \n     print(\"main\", coroutine.resume(co, 1, 10))\n     print(\"main\", coroutine.resume(co, \"r\"))\n     print(\"main\", coroutine.resume(co, \"x\", \"y\"))\n     print(\"main\", coroutine.resume(co, \"x\", \"y\"))\n</pre><p>\nWhen you run it, it produces the following output:\n\n<pre>\n     co-body 1       10\n     foo     2\n     main    true    4\n     co-body r\n     main    true    11      -9\n     co-body x       y\n     main    true    10      end\n     main    false   cannot resume dead coroutine\n</pre>\n\n<p>\nYou can also create and manipulate coroutines through the C API:\nsee functions <a href=\"#lua_newthread\"><code>lua_newthread</code></a>, <a href=\"#lua_resume\"><code>lua_resume</code></a>,\nand <a href=\"#lua_yield\"><code>lua_yield</code></a>.\n\n\n\n\n\n<h1>3 &ndash; <a name=\"3\">The Language</a></h1>\n\n<p>\nThis section describes the lexis, the syntax, and the semantics of Lua.\nIn other words,\nthis section describes\nwhich tokens are valid,\nhow they can be combined,\nand what their combinations mean.\n\n\n<p>\nLanguage constructs will be explained using the usual extended BNF notation,\nin which\n{<em>a</em>}&nbsp;means&nbsp;0 or more <em>a</em>'s, and\n[<em>a</em>]&nbsp;means an optional <em>a</em>.\nNon-terminals are shown like non-terminal,\nkeywords are shown like <b>kword</b>,\nand other terminal symbols are shown like &lsquo;<b>=</b>&rsquo;.\nThe complete syntax of Lua can be found in <a href=\"#9\">&sect;9</a>\nat the end of this manual.\n\n\n\n<h2>3.1 &ndash; <a name=\"3.1\">Lexical Conventions</a></h2>\n\n<p>\nLua is a free-form language.\nIt ignores spaces (including new lines) and comments\nbetween lexical elements (tokens),\nexcept as delimiters between names and keywords.\n\n\n<p>\n<em>Names</em>\n(also called <em>identifiers</em>)\nin Lua can be any string of letters,\ndigits, and underscores,\nnot beginning with a digit and\nnot being a reserved word.\nIdentifiers are used to name variables, table fields, and labels.\n\n\n<p>\nThe following <em>keywords</em> are reserved\nand cannot be used as names:\n\n\n<pre>\n     and       break     do        else      elseif    end\n     false     for       function  goto      if        in\n     local     nil       not       or        repeat    return\n     then      true      until     while\n</pre>\n\n<p>\nLua is a case-sensitive language:\n<code>and</code> is a reserved word, but <code>And</code> and <code>AND</code>\nare two different, valid names.\nAs a convention,\nprograms should avoid creating\nnames that start with an underscore followed by\none or more uppercase letters (such as <a href=\"#pdf-_VERSION\"><code>_VERSION</code></a>).\n\n\n<p>\nThe following strings denote other tokens:\n\n<pre>\n     +     -     *     /     %     ^     #\n     &amp;     ~     |     &lt;&lt;    &gt;&gt;    //\n     ==    ~=    &lt;=    &gt;=    &lt;     &gt;     =\n     (     )     {     }     [     ]     ::\n     ;     :     ,     .     ..    ...\n</pre>\n\n<p>\nA <em>short literal string</em>\ncan be delimited by matching single or double quotes,\nand can contain the following C-like escape sequences:\n'<code>\\a</code>' (bell),\n'<code>\\b</code>' (backspace),\n'<code>\\f</code>' (form feed),\n'<code>\\n</code>' (newline),\n'<code>\\r</code>' (carriage return),\n'<code>\\t</code>' (horizontal tab),\n'<code>\\v</code>' (vertical tab),\n'<code>\\\\</code>' (backslash),\n'<code>\\\"</code>' (quotation mark [double quote]),\nand '<code>\\'</code>' (apostrophe [single quote]).\nA backslash followed by a line break\nresults in a newline in the string.\nThe escape sequence '<code>\\z</code>' skips the following span\nof white-space characters,\nincluding line breaks;\nit is particularly useful to break and indent a long literal string\ninto multiple lines without adding the newlines and spaces\ninto the string contents.\nA short literal string cannot contain unescaped line breaks\nnor escapes not forming a valid escape sequence.\n\n\n<p>\nWe can specify any byte in a short literal string by its numeric value\n(including embedded zeros).\nThis can be done\nwith the escape sequence <code>\\x<em>XX</em></code>,\nwhere <em>XX</em> is a sequence of exactly two hexadecimal digits,\nor with the escape sequence <code>\\<em>ddd</em></code>,\nwhere <em>ddd</em> is a sequence of up to three decimal digits.\n(Note that if a decimal escape sequence is to be followed by a digit,\nit must be expressed using exactly three digits.)\n\n\n<p>\nThe UTF-8 encoding of a Unicode character\ncan be inserted in a literal string with\nthe escape sequence <code>\\u{<em>XXX</em>}</code>\n(note the mandatory enclosing brackets),\nwhere <em>XXX</em> is a sequence of one or more hexadecimal digits\nrepresenting the character code point.\n\n\n<p>\nLiteral strings can also be defined using a long format\nenclosed by <em>long brackets</em>.\nWe define an <em>opening long bracket of level <em>n</em></em> as an opening\nsquare bracket followed by <em>n</em> equal signs followed by another\nopening square bracket.\nSo, an opening long bracket of level&nbsp;0 is written as <code>[[</code>, \nan opening long bracket of level&nbsp;1 is written as <code>[=[</code>, \nand so on.\nA <em>closing long bracket</em> is defined similarly;\nfor instance,\na closing long bracket of level&nbsp;4 is written as  <code>]====]</code>.\nA <em>long literal</em> starts with an opening long bracket of any level and\nends at the first closing long bracket of the same level.\nIt can contain any text except a closing bracket of the same level.\nLiterals in this bracketed form can run for several lines,\ndo not interpret any escape sequences,\nand ignore long brackets of any other level.\nAny kind of end-of-line sequence\n(carriage return, newline, carriage return followed by newline,\nor newline followed by carriage return)\nis converted to a simple newline.\n\n\n<p>\nFor convenience,\nwhen the opening long bracket is immediately followed by a newline,\nthe newline is not included in the string.\nAs an example, in a system using ASCII\n(in which '<code>a</code>' is coded as&nbsp;97,\nnewline is coded as&nbsp;10, and '<code>1</code>' is coded as&nbsp;49),\nthe five literal strings below denote the same string:\n\n<pre>\n     a = 'alo\\n123\"'\n     a = \"alo\\n123\\\"\"\n     a = '\\97lo\\10\\04923\"'\n     a = [[alo\n     123\"]]\n     a = [==[\n     alo\n     123\"]==]\n</pre>\n\n<p>\nAny byte in a literal string not\nexplicitly affected by the previous rules represents itself.\nHowever, Lua opens files for parsing in text mode,\nand the system file functions may have problems with\nsome control characters.\nSo, it is safer to represent\nnon-text data as a quoted literal with\nexplicit escape sequences for the non-text characters.\n\n\n<p>\nA <em>numeric constant</em> (or <em>numeral</em>)\ncan be written with an optional fractional part\nand an optional decimal exponent,\nmarked by a letter '<code>e</code>' or '<code>E</code>'.\nLua also accepts hexadecimal constants,\nwhich start with <code>0x</code> or <code>0X</code>.\nHexadecimal constants also accept an optional fractional part\nplus an optional binary exponent,\nmarked by a letter '<code>p</code>' or '<code>P</code>'.\nA numeric constant with a radix point or an exponent\ndenotes a float;\notherwise,\nif its value fits in an integer,\nit denotes an integer.\nExamples of valid integer constants are\n\n<pre>\n     3   345   0xff   0xBEBADA\n</pre><p>\nExamples of valid float constants are\n\n<pre>\n     3.0     3.1416     314.16e-2     0.31416E1     34e1\n     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1\n</pre>\n\n<p>\nA <em>comment</em> starts with a double hyphen (<code>--</code>)\nanywhere outside a string.\nIf the text immediately after <code>--</code> is not an opening long bracket,\nthe comment is a <em>short comment</em>,\nwhich runs until the end of the line.\nOtherwise, it is a <em>long comment</em>,\nwhich runs until the corresponding closing long bracket.\nLong comments are frequently used to disable code temporarily.\n\n\n\n\n\n<h2>3.2 &ndash; <a name=\"3.2\">Variables</a></h2>\n\n<p>\nVariables are places that store values.\nThere are three kinds of variables in Lua:\nglobal variables, local variables, and table fields.\n\n\n<p>\nA single name can denote a global variable or a local variable\n(or a function's formal parameter,\nwhich is a particular kind of local variable):\n\n<pre>\n\tvar ::= Name\n</pre><p>\nName denotes identifiers, as defined in <a href=\"#3.1\">&sect;3.1</a>.\n\n\n<p>\nAny variable name is assumed to be global unless explicitly declared\nas a local (see <a href=\"#3.3.7\">&sect;3.3.7</a>).\nLocal variables are <em>lexically scoped</em>:\nlocal variables can be freely accessed by functions\ndefined inside their scope (see <a href=\"#3.5\">&sect;3.5</a>).\n\n\n<p>\nBefore the first assignment to a variable, its value is <b>nil</b>.\n\n\n<p>\nSquare brackets are used to index a table:\n\n<pre>\n\tvar ::= prefixexp &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo;\n</pre><p>\nThe meaning of accesses to table fields can be changed via metatables\n(see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n<p>\nThe syntax <code>var.Name</code> is just syntactic sugar for\n<code>var[\"Name\"]</code>:\n\n<pre>\n\tvar ::= prefixexp &lsquo;<b>.</b>&rsquo; Name\n</pre>\n\n<p>\nAn access to a global variable <code>x</code>\nis equivalent to <code>_ENV.x</code>.\nDue to the way that chunks are compiled,\n<code>_ENV</code> is never a global name (see <a href=\"#2.2\">&sect;2.2</a>).\n\n\n\n\n\n<h2>3.3 &ndash; <a name=\"3.3\">Statements</a></h2>\n\n<p>\nLua supports an almost conventional set of statements,\nsimilar to those in Pascal or C.\nThis set includes\nassignments, control structures, function calls,\nand variable declarations.\n\n\n\n<h3>3.3.1 &ndash; <a name=\"3.3.1\">Blocks</a></h3>\n\n<p>\nA block is a list of statements,\nwhich are executed sequentially:\n\n<pre>\n\tblock ::= {stat}\n</pre><p>\nLua has <em>empty statements</em>\nthat allow you to separate statements with semicolons,\nstart a block with a semicolon\nor write two semicolons in sequence:\n\n<pre>\n\tstat ::= &lsquo;<b>;</b>&rsquo;\n</pre>\n\n<p>\nFunction calls and assignments\ncan start with an open parenthesis.\nThis possibility leads to an ambiguity in Lua's grammar.\nConsider the following fragment:\n\n<pre>\n     a = b + c\n     (print or io.write)('done')\n</pre><p>\nThe grammar could see it in two ways:\n\n<pre>\n     a = b + c(print or io.write)('done')\n     \n     a = b + c; (print or io.write)('done')\n</pre><p>\nThe current parser always sees such constructions\nin the first way,\ninterpreting the open parenthesis\nas the start of the arguments to a call.\nTo avoid this ambiguity,\nit is a good practice to always precede with a semicolon\nstatements that start with a parenthesis:\n\n<pre>\n     ;(print or io.write)('done')\n</pre>\n\n<p>\nA block can be explicitly delimited to produce a single statement:\n\n<pre>\n\tstat ::= <b>do</b> block <b>end</b>\n</pre><p>\nExplicit blocks are useful\nto control the scope of variable declarations.\nExplicit blocks are also sometimes used to\nadd a <b>return</b> statement in the middle\nof another block (see <a href=\"#3.3.4\">&sect;3.3.4</a>).\n\n\n\n\n\n<h3>3.3.2 &ndash; <a name=\"3.3.2\">Chunks</a></h3>\n\n<p>\nThe unit of compilation of Lua is called a <em>chunk</em>.\nSyntactically,\na chunk is simply a block:\n\n<pre>\n\tchunk ::= block\n</pre>\n\n<p>\nLua handles a chunk as the body of an anonymous function\nwith a variable number of arguments\n(see <a href=\"#3.4.11\">&sect;3.4.11</a>).\nAs such, chunks can define local variables,\nreceive arguments, and return values.\nMoreover, such anonymous function is compiled as in the\nscope of an external local variable called <code>_ENV</code> (see <a href=\"#2.2\">&sect;2.2</a>).\nThe resulting function always has <code>_ENV</code> as its only upvalue,\neven if it does not use that variable.\n\n\n<p>\nA chunk can be stored in a file or in a string inside the host program.\nTo execute a chunk,\nLua first <em>loads</em> it,\nprecompiling the chunk's code into instructions for a virtual machine,\nand then Lua executes the compiled code\nwith an interpreter for the virtual machine.\n\n\n<p>\nChunks can also be precompiled into binary form;\nsee program <code>luac</code> and function <a href=\"#pdf-string.dump\"><code>string.dump</code></a> for details.\nPrograms in source and compiled forms are interchangeable;\nLua automatically detects the file type and acts accordingly (see <a href=\"#pdf-load\"><code>load</code></a>).\n\n\n\n\n\n<h3>3.3.3 &ndash; <a name=\"3.3.3\">Assignment</a></h3>\n\n<p>\nLua allows multiple assignments.\nTherefore, the syntax for assignment\ndefines a list of variables on the left side\nand a list of expressions on the right side.\nThe elements in both lists are separated by commas:\n\n<pre>\n\tstat ::= varlist &lsquo;<b>=</b>&rsquo; explist\n\tvarlist ::= var {&lsquo;<b>,</b>&rsquo; var}\n\texplist ::= exp {&lsquo;<b>,</b>&rsquo; exp}\n</pre><p>\nExpressions are discussed in <a href=\"#3.4\">&sect;3.4</a>.\n\n\n<p>\nBefore the assignment,\nthe list of values is <em>adjusted</em> to the length of\nthe list of variables.\nIf there are more values than needed,\nthe excess values are thrown away.\nIf there are fewer values than needed,\nthe list is extended with as many  <b>nil</b>'s as needed.\nIf the list of expressions ends with a function call,\nthen all values returned by that call enter the list of values,\nbefore the adjustment\n(except when the call is enclosed in parentheses; see <a href=\"#3.4\">&sect;3.4</a>).\n\n\n<p>\nThe assignment statement first evaluates all its expressions\nand only then the assignments are performed.\nThus the code\n\n<pre>\n     i = 3\n     i, a[i] = i+1, 20\n</pre><p>\nsets <code>a[3]</code> to 20, without affecting <code>a[4]</code>\nbecause the <code>i</code> in <code>a[i]</code> is evaluated (to 3)\nbefore it is assigned&nbsp;4.\nSimilarly, the line\n\n<pre>\n     x, y = y, x\n</pre><p>\nexchanges the values of <code>x</code> and <code>y</code>,\nand\n\n<pre>\n     x, y, z = y, z, x\n</pre><p>\ncyclically permutes the values of <code>x</code>, <code>y</code>, and <code>z</code>.\n\n\n<p>\nAn assignment to a global name <code>x = val</code>\nis equivalent to the assignment\n<code>_ENV.x = val</code> (see <a href=\"#2.2\">&sect;2.2</a>).\n\n\n<p>\nThe meaning of assignments to table fields and\nglobal variables (which are actually table fields, too)\ncan be changed via metatables (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n\n\n\n<h3>3.3.4 &ndash; <a name=\"3.3.4\">Control Structures</a></h3><p>\nThe control structures\n<b>if</b>, <b>while</b>, and <b>repeat</b> have the usual meaning and\nfamiliar syntax:\n\n\n\n\n<pre>\n\tstat ::= <b>while</b> exp <b>do</b> block <b>end</b>\n\tstat ::= <b>repeat</b> block <b>until</b> exp\n\tstat ::= <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b>\n</pre><p>\nLua also has a <b>for</b> statement, in two flavors (see <a href=\"#3.3.5\">&sect;3.3.5</a>).\n\n\n<p>\nThe condition expression of a\ncontrol structure can return any value.\nBoth <b>false</b> and <b>nil</b> are considered false.\nAll values different from <b>nil</b> and <b>false</b> are considered true\n(in particular, the number 0 and the empty string are also true).\n\n\n<p>\nIn the <b>repeat</b>&ndash;<b>until</b> loop,\nthe inner block does not end at the <b>until</b> keyword,\nbut only after the condition.\nSo, the condition can refer to local variables\ndeclared inside the loop block.\n\n\n<p>\nThe <b>goto</b> statement transfers the program control to a label.\nFor syntactical reasons,\nlabels in Lua are considered statements too:\n\n\n\n<pre>\n\tstat ::= <b>goto</b> Name\n\tstat ::= label\n\tlabel ::= &lsquo;<b>::</b>&rsquo; Name &lsquo;<b>::</b>&rsquo;\n</pre>\n\n<p>\nA label is visible in the entire block where it is defined,\nexcept\ninside nested blocks where a label with the same name is defined and\ninside nested functions.\nA goto may jump to any visible label as long as it does not\nenter into the scope of a local variable.\n\n\n<p>\nLabels and empty statements are called <em>void statements</em>,\nas they perform no actions.\n\n\n<p>\nThe <b>break</b> statement terminates the execution of a\n<b>while</b>, <b>repeat</b>, or <b>for</b> loop,\nskipping to the next statement after the loop:\n\n\n<pre>\n\tstat ::= <b>break</b>\n</pre><p>\nA <b>break</b> ends the innermost enclosing loop.\n\n\n<p>\nThe <b>return</b> statement is used to return values\nfrom a function or a chunk\n(which is an anonymous function).\n\nFunctions can return more than one value,\nso the syntax for the <b>return</b> statement is\n\n<pre>\n\tstat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]\n</pre>\n\n<p>\nThe <b>return</b> statement can only be written\nas the last statement of a block.\nIf it is really necessary to <b>return</b> in the middle of a block,\nthen an explicit inner block can be used,\nas in the idiom <code>do return end</code>,\nbecause now <b>return</b> is the last statement in its (inner) block.\n\n\n\n\n\n<h3>3.3.5 &ndash; <a name=\"3.3.5\">For Statement</a></h3>\n\n<p>\n\nThe <b>for</b> statement has two forms:\none numerical and one generic.\n\n\n<p>\nThe numerical <b>for</b> loop repeats a block of code while a\ncontrol variable runs through an arithmetic progression.\nIt has the following syntax:\n\n<pre>\n\tstat ::= <b>for</b> Name &lsquo;<b>=</b>&rsquo; exp &lsquo;<b>,</b>&rsquo; exp [&lsquo;<b>,</b>&rsquo; exp] <b>do</b> block <b>end</b>\n</pre><p>\nThe <em>block</em> is repeated for <em>name</em> starting at the value of\nthe first <em>exp</em>, until it passes the second <em>exp</em> by steps of the\nthird <em>exp</em>.\nMore precisely, a <b>for</b> statement like\n\n<pre>\n     for v = <em>e1</em>, <em>e2</em>, <em>e3</em> do <em>block</em> end\n</pre><p>\nis equivalent to the code:\n\n<pre>\n     do\n       local <em>var</em>, <em>limit</em>, <em>step</em> = tonumber(<em>e1</em>), tonumber(<em>e2</em>), tonumber(<em>e3</em>)\n       if not (<em>var</em> and <em>limit</em> and <em>step</em>) then error() end\n       <em>var</em> = <em>var</em> - <em>step</em>\n       while true do\n         <em>var</em> = <em>var</em> + <em>step</em>\n         if (<em>step</em> &gt;= 0 and <em>var</em> &gt; <em>limit</em>) or (<em>step</em> &lt; 0 and <em>var</em> &lt; <em>limit</em>) then\n           break\n         end\n         local v = <em>var</em>\n         <em>block</em>\n       end\n     end\n</pre>\n\n<p>\nNote the following:\n\n<ul>\n\n<li>\nAll three control expressions are evaluated only once,\nbefore the loop starts.\nThey must all result in numbers.\n</li>\n\n<li>\n<code><em>var</em></code>, <code><em>limit</em></code>, and <code><em>step</em></code> are invisible variables.\nThe names shown here are for explanatory purposes only.\n</li>\n\n<li>\nIf the third expression (the step) is absent,\nthen a step of&nbsp;1 is used.\n</li>\n\n<li>\nYou can use <b>break</b> and <b>goto</b> to exit a <b>for</b> loop.\n</li>\n\n<li>\nThe loop variable <code>v</code> is local to the loop body.\nIf you need its value after the loop,\nassign it to another variable before exiting the loop.\n</li>\n\n</ul>\n\n<p>\nThe generic <b>for</b> statement works over functions,\ncalled <em>iterators</em>.\nOn each iteration, the iterator function is called to produce a new value,\nstopping when this new value is <b>nil</b>.\nThe generic <b>for</b> loop has the following syntax:\n\n<pre>\n\tstat ::= <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b>\n\tnamelist ::= Name {&lsquo;<b>,</b>&rsquo; Name}\n</pre><p>\nA <b>for</b> statement like\n\n<pre>\n     for <em>var_1</em>, &middot;&middot;&middot;, <em>var_n</em> in <em>explist</em> do <em>block</em> end\n</pre><p>\nis equivalent to the code:\n\n<pre>\n     do\n       local <em>f</em>, <em>s</em>, <em>var</em> = <em>explist</em>\n       while true do\n         local <em>var_1</em>, &middot;&middot;&middot;, <em>var_n</em> = <em>f</em>(<em>s</em>, <em>var</em>)\n         if <em>var_1</em> == nil then break end\n         <em>var</em> = <em>var_1</em>\n         <em>block</em>\n       end\n     end\n</pre><p>\nNote the following:\n\n<ul>\n\n<li>\n<code><em>explist</em></code> is evaluated only once.\nIts results are an <em>iterator</em> function,\na <em>state</em>,\nand an initial value for the first <em>iterator variable</em>.\n</li>\n\n<li>\n<code><em>f</em></code>, <code><em>s</em></code>, and <code><em>var</em></code> are invisible variables.\nThe names are here for explanatory purposes only.\n</li>\n\n<li>\nYou can use <b>break</b> to exit a <b>for</b> loop.\n</li>\n\n<li>\nThe loop variables <code><em>var_i</em></code> are local to the loop;\nyou cannot use their values after the <b>for</b> ends.\nIf you need these values,\nthen assign them to other variables before breaking or exiting the loop.\n</li>\n\n</ul>\n\n\n\n\n<h3>3.3.6 &ndash; <a name=\"3.3.6\">Function Calls as Statements</a></h3><p>\nTo allow possible side-effects,\nfunction calls can be executed as statements:\n\n<pre>\n\tstat ::= functioncall\n</pre><p>\nIn this case, all returned values are thrown away.\nFunction calls are explained in <a href=\"#3.4.10\">&sect;3.4.10</a>.\n\n\n\n\n\n<h3>3.3.7 &ndash; <a name=\"3.3.7\">Local Declarations</a></h3><p>\nLocal variables can be declared anywhere inside a block.\nThe declaration can include an initial assignment:\n\n<pre>\n\tstat ::= <b>local</b> namelist [&lsquo;<b>=</b>&rsquo; explist]\n</pre><p>\nIf present, an initial assignment has the same semantics\nof a multiple assignment (see <a href=\"#3.3.3\">&sect;3.3.3</a>).\nOtherwise, all variables are initialized with <b>nil</b>.\n\n\n<p>\nA chunk is also a block (see <a href=\"#3.3.2\">&sect;3.3.2</a>),\nand so local variables can be declared in a chunk outside any explicit block.\n\n\n<p>\nThe visibility rules for local variables are explained in <a href=\"#3.5\">&sect;3.5</a>.\n\n\n\n\n\n\n\n<h2>3.4 &ndash; <a name=\"3.4\">Expressions</a></h2>\n\n<p>\nThe basic expressions in Lua are the following:\n\n<pre>\n\texp ::= prefixexp\n\texp ::= <b>nil</b> | <b>false</b> | <b>true</b>\n\texp ::= Numeral\n\texp ::= LiteralString\n\texp ::= functiondef\n\texp ::= tableconstructor\n\texp ::= &lsquo;<b>...</b>&rsquo;\n\texp ::= exp binop exp\n\texp ::= unop exp\n\tprefixexp ::= var | functioncall | &lsquo;<b>(</b>&rsquo; exp &lsquo;<b>)</b>&rsquo;\n</pre>\n\n<p>\nNumerals and literal strings are explained in <a href=\"#3.1\">&sect;3.1</a>;\nvariables are explained in <a href=\"#3.2\">&sect;3.2</a>;\nfunction definitions are explained in <a href=\"#3.4.11\">&sect;3.4.11</a>;\nfunction calls are explained in <a href=\"#3.4.10\">&sect;3.4.10</a>;\ntable constructors are explained in <a href=\"#3.4.9\">&sect;3.4.9</a>.\nVararg expressions,\ndenoted by three dots ('<code>...</code>'), can only be used when\ndirectly inside a vararg function;\nthey are explained in <a href=\"#3.4.11\">&sect;3.4.11</a>.\n\n\n<p>\nBinary operators comprise arithmetic operators (see <a href=\"#3.4.1\">&sect;3.4.1</a>),\nbitwise operators (see <a href=\"#3.4.2\">&sect;3.4.2</a>),\nrelational operators (see <a href=\"#3.4.4\">&sect;3.4.4</a>), logical operators (see <a href=\"#3.4.5\">&sect;3.4.5</a>),\nand the concatenation operator (see <a href=\"#3.4.6\">&sect;3.4.6</a>).\nUnary operators comprise the unary minus (see <a href=\"#3.4.1\">&sect;3.4.1</a>),\nthe unary bitwise NOT (see <a href=\"#3.4.2\">&sect;3.4.2</a>),\nthe unary logical <b>not</b> (see <a href=\"#3.4.5\">&sect;3.4.5</a>),\nand the unary <em>length operator</em> (see <a href=\"#3.4.7\">&sect;3.4.7</a>).\n\n\n<p>\nBoth function calls and vararg expressions can result in multiple values.\nIf a function call is used as a statement (see <a href=\"#3.3.6\">&sect;3.3.6</a>),\nthen its return list is adjusted to zero elements,\nthus discarding all returned values.\nIf an expression is used as the last (or the only) element\nof a list of expressions,\nthen no adjustment is made\n(unless the expression is enclosed in parentheses).\nIn all other contexts,\nLua adjusts the result list to one element,\neither discarding all values except the first one\nor adding a single <b>nil</b> if there are no values.\n\n\n<p>\nHere are some examples:\n\n<pre>\n     f()                -- adjusted to 0 results\n     g(f(), x)          -- f() is adjusted to 1 result\n     g(x, f())          -- g gets x plus all results from f()\n     a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)\n     a,b = ...          -- a gets the first vararg argument, b gets\n                        -- the second (both a and b can get nil if there\n                        -- is no corresponding vararg argument)\n     \n     a,b,c = x, f()     -- f() is adjusted to 2 results\n     a,b,c = f()        -- f() is adjusted to 3 results\n     return f()         -- returns all results from f()\n     return ...         -- returns all received vararg arguments\n     return x,y,f()     -- returns x, y, and all results from f()\n     {f()}              -- creates a list with all results from f()\n     {...}              -- creates a list with all vararg arguments\n     {f(), nil}         -- f() is adjusted to 1 result\n</pre>\n\n<p>\nAny expression enclosed in parentheses always results in only one value.\nThus,\n<code>(f(x,y,z))</code> is always a single value,\neven if <code>f</code> returns several values.\n(The value of <code>(f(x,y,z))</code> is the first value returned by <code>f</code>\nor <b>nil</b> if <code>f</code> does not return any values.)\n\n\n\n<h3>3.4.1 &ndash; <a name=\"3.4.1\">Arithmetic Operators</a></h3><p>\nLua supports the following arithmetic operators:\n\n<ul>\n<li><b><code>+</code>: </b>addition</li>\n<li><b><code>-</code>: </b>subtraction</li>\n<li><b><code>*</code>: </b>multiplication</li>\n<li><b><code>/</code>: </b>float division</li>\n<li><b><code>//</code>: </b>floor division</li>\n<li><b><code>%</code>: </b>modulo</li>\n<li><b><code>^</code>: </b>exponentiation</li>\n<li><b><code>-</code>: </b>unary minus</li>\n</ul>\n\n<p>\nWith the exception of exponentiation and float division,\nthe arithmetic operators work as follows:\nIf both operands are integers,\nthe operation is performed over integers and the result is an integer.\nOtherwise, if both operands are numbers\nor strings that can be converted to\nnumbers (see <a href=\"#3.4.3\">&sect;3.4.3</a>),\nthen they are converted to floats,\nthe operation is performed following the usual rules\nfor floating-point arithmetic\n(usually the IEEE 754 standard),\nand the result is a float.\n\n\n<p>\nExponentiation and float division (<code>/</code>)\nalways convert their operands to floats\nand the result is always a float.\nExponentiation uses the ISO&nbsp;C function <code>pow</code>,\nso that it works for non-integer exponents too.\n\n\n<p>\nFloor division (<code>//</code>) is a division\nthat rounds the quotient towards minus infinity,\nthat is, the floor of the division of its operands.\n\n\n<p>\nModulo is defined as the remainder of a division\nthat rounds the quotient towards minus infinity (floor division).\n\n\n<p>\nIn case of overflows in integer arithmetic,\nall operations <em>wrap around</em>,\naccording to the usual rules of two-complement arithmetic.\n(In other words,\nthey return the unique representable integer\nthat is equal modulo <em>2<sup>64</sup></em> to the mathematical result.)\n\n\n\n<h3>3.4.2 &ndash; <a name=\"3.4.2\">Bitwise Operators</a></h3><p>\nLua supports the following bitwise operators:\n\n<ul>\n<li><b><code>&amp;</code>: </b>bitwise AND</li>\n<li><b><code>&#124;</code>: </b>bitwise OR</li>\n<li><b><code>~</code>: </b>bitwise exclusive OR</li>\n<li><b><code>&gt;&gt;</code>: </b>right shift</li>\n<li><b><code>&lt;&lt;</code>: </b>left shift</li>\n<li><b><code>~</code>: </b>unary bitwise NOT</li>\n</ul>\n\n<p>\nAll bitwise operations convert its operands to integers\n(see <a href=\"#3.4.3\">&sect;3.4.3</a>),\noperate on all bits of those integers,\nand result in an integer.\n\n\n<p>\nBoth right and left shifts fill the vacant bits with zeros.\nNegative displacements shift to the other direction;\ndisplacements with absolute values equal to or higher than\nthe number of bits in an integer\nresult in zero (as all bits are shifted out).\n\n\n\n\n\n<h3>3.4.3 &ndash; <a name=\"3.4.3\">Coercions and Conversions</a></h3><p>\nLua provides some automatic conversions between some\ntypes and representations at run time.\nBitwise operators always convert float operands to integers.\nExponentiation and float division\nalways convert integer operands to floats.\nAll other arithmetic operations applied to mixed numbers\n(integers and floats) convert the integer operand to a float;\nthis is called the <em>usual rule</em>.\nThe C API also converts both integers to floats and\nfloats to integers, as needed.\nMoreover, string concatenation accepts numbers as arguments,\nbesides strings.\n\n\n<p>\nLua also converts strings to numbers,\nwhenever a number is expected.\n\n\n<p>\nIn a conversion from integer to float,\nif the integer value has an exact representation as a float,\nthat is the result.\nOtherwise,\nthe conversion gets the nearest higher or\nthe nearest lower representable value.\nThis kind of conversion never fails.\n\n\n<p>\nThe conversion from float to integer\nchecks whether the float has an exact representation as an integer\n(that is, the float has an integral value and\nit is in the range of integer representation).\nIf it does, that representation is the result.\nOtherwise, the conversion fails.\n\n\n<p>\nThe conversion from strings to numbers goes as follows:\nFirst, the string is converted to an integer or a float,\nfollowing its syntax and the rules of the Lua lexer.\n(The string may have also leading and trailing spaces and a sign.)\nThen, the resulting number (float or integer)\nis converted to the type (float or integer) required by the context\n(e.g., the operation that forced the conversion).\n\n\n<p>\nAll conversions from strings to numbers\naccept both a dot and the current locale mark\nas the radix character.\n(The Lua lexer, however, accepts only a dot.)\n\n\n<p>\nThe conversion from numbers to strings uses a\nnon-specified human-readable format.\nFor complete control over how numbers are converted to strings,\nuse the <code>format</code> function from the string library\n(see <a href=\"#pdf-string.format\"><code>string.format</code></a>).\n\n\n\n\n\n<h3>3.4.4 &ndash; <a name=\"3.4.4\">Relational Operators</a></h3><p>\nLua supports the following relational operators:\n\n<ul>\n<li><b><code>==</code>: </b>equality</li>\n<li><b><code>~=</code>: </b>inequality</li>\n<li><b><code>&lt;</code>: </b>less than</li>\n<li><b><code>&gt;</code>: </b>greater than</li>\n<li><b><code>&lt;=</code>: </b>less or equal</li>\n<li><b><code>&gt;=</code>: </b>greater or equal</li>\n</ul><p>\nThese operators always result in <b>false</b> or <b>true</b>.\n\n\n<p>\nEquality (<code>==</code>) first compares the type of its operands.\nIf the types are different, then the result is <b>false</b>.\nOtherwise, the values of the operands are compared.\nStrings are compared in the obvious way.\nNumbers are equal if they denote the same mathematical value.\n\n\n<p>\nTables, userdata, and threads\nare compared by reference:\ntwo objects are considered equal only if they are the same object.\nEvery time you create a new object\n(a table, userdata, or thread),\nthis new object is different from any previously existing object.\nA closure is always equal to itself.\nClosures with any detectable difference\n(different behavior, different definition) are always different.\nClosures created at different times but with no detectable differences\nmay be classified as equal or not\n(depending on internal caching details).\n\n\n<p>\nYou can change the way that Lua compares tables and userdata\nby using the \"eq\" metamethod (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n<p>\nEquality comparisons do not convert strings to numbers\nor vice versa.\nThus, <code>\"0\"==0</code> evaluates to <b>false</b>,\nand <code>t[0]</code> and <code>t[\"0\"]</code> denote different\nentries in a table.\n\n\n<p>\nThe operator <code>~=</code> is exactly the negation of equality (<code>==</code>).\n\n\n<p>\nThe order operators work as follows.\nIf both arguments are numbers,\nthen they are compared according to their mathematical values\n(regardless of their subtypes).\nOtherwise, if both arguments are strings,\nthen their values are compared according to the current locale.\nOtherwise, Lua tries to call the \"lt\" or the \"le\"\nmetamethod (see <a href=\"#2.4\">&sect;2.4</a>).\nA comparison <code>a &gt; b</code> is translated to <code>b &lt; a</code>\nand <code>a &gt;= b</code> is translated to <code>b &lt;= a</code>.\n\n\n<p>\nFollowing the IEEE 754 standard,\nNaN is considered neither smaller than,\nnor equal to, nor greater than any value (including itself).\n\n\n\n\n\n<h3>3.4.5 &ndash; <a name=\"3.4.5\">Logical Operators</a></h3><p>\nThe logical operators in Lua are\n<b>and</b>, <b>or</b>, and <b>not</b>.\nLike the control structures (see <a href=\"#3.3.4\">&sect;3.3.4</a>),\nall logical operators consider both <b>false</b> and <b>nil</b> as false\nand anything else as true.\n\n\n<p>\nThe negation operator <b>not</b> always returns <b>false</b> or <b>true</b>.\nThe conjunction operator <b>and</b> returns its first argument\nif this value is <b>false</b> or <b>nil</b>;\notherwise, <b>and</b> returns its second argument.\nThe disjunction operator <b>or</b> returns its first argument\nif this value is different from <b>nil</b> and <b>false</b>;\notherwise, <b>or</b> returns its second argument.\nBoth <b>and</b> and <b>or</b> use short-circuit evaluation;\nthat is,\nthe second operand is evaluated only if necessary.\nHere are some examples:\n\n<pre>\n     10 or 20            --&gt; 10\n     10 or error()       --&gt; 10\n     nil or \"a\"          --&gt; \"a\"\n     nil and 10          --&gt; nil\n     false and error()   --&gt; false\n     false and nil       --&gt; false\n     false or nil        --&gt; nil\n     10 and 20           --&gt; 20\n</pre><p>\n(In this manual,\n<code>--&gt;</code> indicates the result of the preceding expression.)\n\n\n\n\n\n<h3>3.4.6 &ndash; <a name=\"3.4.6\">Concatenation</a></h3><p>\nThe string concatenation operator in Lua is\ndenoted by two dots ('<code>..</code>').\nIf both operands are strings or numbers, then they are converted to\nstrings according to the rules described in <a href=\"#3.4.3\">&sect;3.4.3</a>.\nOtherwise, the <code>__concat</code> metamethod is called (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n\n\n\n<h3>3.4.7 &ndash; <a name=\"3.4.7\">The Length Operator</a></h3>\n\n<p>\nThe length operator is denoted by the unary prefix operator <code>#</code>.\n\n\n<p>\nThe length of a string is its number of bytes\n(that is, the usual meaning of string length when each\ncharacter is one byte).\n\n\n<p>\nThe length operator applied on a table\nreturns a border in that table.\nA <em>border</em> in a table <code>t</code> is any natural number\nthat satisfies the following condition:\n\n<pre>\n     (border == 0 or t[border] ~= nil) and t[border + 1] == nil\n</pre><p>\nIn words,\na border is any (natural) index in a table\nwhere a non-nil value is followed by a nil value\n(or zero, when index 1 is nil).\n\n\n<p>\nA table with exactly one border is called a <em>sequence</em>.\nFor instance, the table <code>{10, 20, 30, 40, 50}</code> is a sequence,\nas it has only one border (5).\nThe table <code>{10, 20, 30, nil, 50}</code> has two borders (3 and 5),\nand therefore it is not a sequence.\nThe table <code>{nil, 20, 30, nil, nil, 60, nil}</code>\nhas three borders (0, 3, and 6),\nso it is not a sequence, too.\nThe table <code>{}</code> is a sequence with border 0.\nNote that non-natural keys do not interfere\nwith whether a table is a sequence.\n\n\n<p>\nWhen <code>t</code> is a sequence,\n<code>#t</code> returns its only border,\nwhich corresponds to the intuitive notion of the length of the sequence.\nWhen <code>t</code> is not a sequence,\n<code>#t</code> can return any of its borders.\n(The exact one depends on details of\nthe internal representation of the table,\nwhich in turn can depend on how the table was populated and\nthe memory addresses of its non-numeric keys.)\n\n\n<p>\nThe computation of the length of a table\nhas a guaranteed worst time of <em>O(log n)</em>,\nwhere <em>n</em> is the largest natural key in the table.\n\n\n<p>\nA program can modify the behavior of the length operator for\nany value but strings through the <code>__len</code> metamethod (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n\n\n\n<h3>3.4.8 &ndash; <a name=\"3.4.8\">Precedence</a></h3><p>\nOperator precedence in Lua follows the table below,\nfrom lower to higher priority:\n\n<pre>\n     or\n     and\n     &lt;     &gt;     &lt;=    &gt;=    ~=    ==\n     |\n     ~\n     &amp;\n     &lt;&lt;    &gt;&gt;\n     ..\n     +     -\n     *     /     //    %\n     unary operators (not   #     -     ~)\n     ^\n</pre><p>\nAs usual,\nyou can use parentheses to change the precedences of an expression.\nThe concatenation ('<code>..</code>') and exponentiation ('<code>^</code>')\noperators are right associative.\nAll other binary operators are left associative.\n\n\n\n\n\n<h3>3.4.9 &ndash; <a name=\"3.4.9\">Table Constructors</a></h3><p>\nTable constructors are expressions that create tables.\nEvery time a constructor is evaluated, a new table is created.\nA constructor can be used to create an empty table\nor to create a table and initialize some of its fields.\nThe general syntax for constructors is\n\n<pre>\n\ttableconstructor ::= &lsquo;<b>{</b>&rsquo; [fieldlist] &lsquo;<b>}</b>&rsquo;\n\tfieldlist ::= field {fieldsep field} [fieldsep]\n\tfield ::= &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; &lsquo;<b>=</b>&rsquo; exp | Name &lsquo;<b>=</b>&rsquo; exp | exp\n\tfieldsep ::= &lsquo;<b>,</b>&rsquo; | &lsquo;<b>;</b>&rsquo;\n</pre>\n\n<p>\nEach field of the form <code>[exp1] = exp2</code> adds to the new table an entry\nwith key <code>exp1</code> and value <code>exp2</code>.\nA field of the form <code>name = exp</code> is equivalent to\n<code>[\"name\"] = exp</code>.\nFinally, fields of the form <code>exp</code> are equivalent to\n<code>[i] = exp</code>, where <code>i</code> are consecutive integers\nstarting with 1.\nFields in the other formats do not affect this counting.\nFor example,\n\n<pre>\n     a = { [f(1)] = g; \"x\", \"y\"; x = 1, f(x), [30] = 23; 45 }\n</pre><p>\nis equivalent to\n\n<pre>\n     do\n       local t = {}\n       t[f(1)] = g\n       t[1] = \"x\"         -- 1st exp\n       t[2] = \"y\"         -- 2nd exp\n       t.x = 1            -- t[\"x\"] = 1\n       t[3] = f(x)        -- 3rd exp\n       t[30] = 23\n       t[4] = 45          -- 4th exp\n       a = t\n     end\n</pre>\n\n<p>\nThe order of the assignments in a constructor is undefined.\n(This order would be relevant only when there are repeated keys.)\n\n\n<p>\nIf the last field in the list has the form <code>exp</code>\nand the expression is a function call or a vararg expression,\nthen all values returned by this expression enter the list consecutively\n(see <a href=\"#3.4.10\">&sect;3.4.10</a>).\n\n\n<p>\nThe field list can have an optional trailing separator,\nas a convenience for machine-generated code.\n\n\n\n\n\n<h3>3.4.10 &ndash; <a name=\"3.4.10\">Function Calls</a></h3><p>\nA function call in Lua has the following syntax:\n\n<pre>\n\tfunctioncall ::= prefixexp args\n</pre><p>\nIn a function call,\nfirst prefixexp and args are evaluated.\nIf the value of prefixexp has type <em>function</em>,\nthen this function is called\nwith the given arguments.\nOtherwise, the prefixexp \"call\" metamethod is called,\nhaving as first argument the value of prefixexp,\nfollowed by the original call arguments\n(see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n<p>\nThe form\n\n<pre>\n\tfunctioncall ::= prefixexp &lsquo;<b>:</b>&rsquo; Name args\n</pre><p>\ncan be used to call \"methods\".\nA call <code>v:name(<em>args</em>)</code>\nis syntactic sugar for <code>v.name(v,<em>args</em>)</code>,\nexcept that <code>v</code> is evaluated only once.\n\n\n<p>\nArguments have the following syntax:\n\n<pre>\n\targs ::= &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo;\n\targs ::= tableconstructor\n\targs ::= LiteralString\n</pre><p>\nAll argument expressions are evaluated before the call.\nA call of the form <code>f{<em>fields</em>}</code> is\nsyntactic sugar for <code>f({<em>fields</em>})</code>;\nthat is, the argument list is a single new table.\nA call of the form <code>f'<em>string</em>'</code>\n(or <code>f\"<em>string</em>\"</code> or <code>f[[<em>string</em>]]</code>)\nis syntactic sugar for <code>f('<em>string</em>')</code>;\nthat is, the argument list is a single literal string.\n\n\n<p>\nA call of the form <code>return <em>functioncall</em></code> is called\na <em>tail call</em>.\nLua implements <em>proper tail calls</em>\n(or <em>proper tail recursion</em>):\nin a tail call,\nthe called function reuses the stack entry of the calling function.\nTherefore, there is no limit on the number of nested tail calls that\na program can execute.\nHowever, a tail call erases any debug information about the\ncalling function.\nNote that a tail call only happens with a particular syntax,\nwhere the <b>return</b> has one single function call as argument;\nthis syntax makes the calling function return exactly\nthe returns of the called function.\nSo, none of the following examples are tail calls:\n\n<pre>\n     return (f(x))        -- results adjusted to 1\n     return 2 * f(x)\n     return x, f(x)       -- additional results\n     f(x); return         -- results discarded\n     return x or f(x)     -- results adjusted to 1\n</pre>\n\n\n\n\n<h3>3.4.11 &ndash; <a name=\"3.4.11\">Function Definitions</a></h3>\n\n<p>\nThe syntax for function definition is\n\n<pre>\n\tfunctiondef ::= <b>function</b> funcbody\n\tfuncbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>\n</pre>\n\n<p>\nThe following syntactic sugar simplifies function definitions:\n\n<pre>\n\tstat ::= <b>function</b> funcname funcbody\n\tstat ::= <b>local</b> <b>function</b> Name funcbody\n\tfuncname ::= Name {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; Name]\n</pre><p>\nThe statement\n\n<pre>\n     function f () <em>body</em> end\n</pre><p>\ntranslates to\n\n<pre>\n     f = function () <em>body</em> end\n</pre><p>\nThe statement\n\n<pre>\n     function t.a.b.c.f () <em>body</em> end\n</pre><p>\ntranslates to\n\n<pre>\n     t.a.b.c.f = function () <em>body</em> end\n</pre><p>\nThe statement\n\n<pre>\n     local function f () <em>body</em> end\n</pre><p>\ntranslates to\n\n<pre>\n     local f; f = function () <em>body</em> end\n</pre><p>\nnot to\n\n<pre>\n     local f = function () <em>body</em> end\n</pre><p>\n(This only makes a difference when the body of the function\ncontains references to <code>f</code>.)\n\n\n<p>\nA function definition is an executable expression,\nwhose value has type <em>function</em>.\nWhen Lua precompiles a chunk,\nall its function bodies are precompiled too.\nThen, whenever Lua executes the function definition,\nthe function is <em>instantiated</em> (or <em>closed</em>).\nThis function instance (or <em>closure</em>)\nis the final value of the expression.\n\n\n<p>\nParameters act as local variables that are\ninitialized with the argument values:\n\n<pre>\n\tparlist ::= namelist [&lsquo;<b>,</b>&rsquo; &lsquo;<b>...</b>&rsquo;] | &lsquo;<b>...</b>&rsquo;\n</pre><p>\nWhen a function is called,\nthe list of arguments is adjusted to\nthe length of the list of parameters,\nunless the function is a <em>vararg function</em>,\nwhich is indicated by three dots ('<code>...</code>')\nat the end of its parameter list.\nA vararg function does not adjust its argument list;\ninstead, it collects all extra arguments and supplies them\nto the function through a <em>vararg expression</em>,\nwhich is also written as three dots.\nThe value of this expression is a list of all actual extra arguments,\nsimilar to a function with multiple results.\nIf a vararg expression is used inside another expression\nor in the middle of a list of expressions,\nthen its return list is adjusted to one element.\nIf the expression is used as the last element of a list of expressions,\nthen no adjustment is made\n(unless that last expression is enclosed in parentheses).\n\n\n<p>\nAs an example, consider the following definitions:\n\n<pre>\n     function f(a, b) end\n     function g(a, b, ...) end\n     function r() return 1,2,3 end\n</pre><p>\nThen, we have the following mapping from arguments to parameters and\nto the vararg expression:\n\n<pre>\n     CALL            PARAMETERS\n     \n     f(3)             a=3, b=nil\n     f(3, 4)          a=3, b=4\n     f(3, 4, 5)       a=3, b=4\n     f(r(), 10)       a=1, b=10\n     f(r())           a=1, b=2\n     \n     g(3)             a=3, b=nil, ... --&gt;  (nothing)\n     g(3, 4)          a=3, b=4,   ... --&gt;  (nothing)\n     g(3, 4, 5, 8)    a=3, b=4,   ... --&gt;  5  8\n     g(5, r())        a=5, b=1,   ... --&gt;  2  3\n</pre>\n\n<p>\nResults are returned using the <b>return</b> statement (see <a href=\"#3.3.4\">&sect;3.3.4</a>).\nIf control reaches the end of a function\nwithout encountering a <b>return</b> statement,\nthen the function returns with no results.\n\n\n<p>\n\nThere is a system-dependent limit on the number of values\nthat a function may return.\nThis limit is guaranteed to be larger than 1000.\n\n\n<p>\nThe <em>colon</em> syntax\nis used for defining <em>methods</em>,\nthat is, functions that have an implicit extra parameter <code>self</code>.\nThus, the statement\n\n<pre>\n     function t.a.b.c:f (<em>params</em>) <em>body</em> end\n</pre><p>\nis syntactic sugar for\n\n<pre>\n     t.a.b.c.f = function (self, <em>params</em>) <em>body</em> end\n</pre>\n\n\n\n\n\n\n<h2>3.5 &ndash; <a name=\"3.5\">Visibility Rules</a></h2>\n\n<p>\n\nLua is a lexically scoped language.\nThe scope of a local variable begins at the first statement after\nits declaration and lasts until the last non-void statement\nof the innermost block that includes the declaration.\nConsider the following example:\n\n<pre>\n     x = 10                -- global variable\n     do                    -- new block\n       local x = x         -- new 'x', with value 10\n       print(x)            --&gt; 10\n       x = x+1\n       do                  -- another block\n         local x = x+1     -- another 'x'\n         print(x)          --&gt; 12\n       end\n       print(x)            --&gt; 11\n     end\n     print(x)              --&gt; 10  (the global one)\n</pre>\n\n<p>\nNotice that, in a declaration like <code>local x = x</code>,\nthe new <code>x</code> being declared is not in scope yet,\nand so the second <code>x</code> refers to the outside variable.\n\n\n<p>\nBecause of the lexical scoping rules,\nlocal variables can be freely accessed by functions\ndefined inside their scope.\nA local variable used by an inner function is called\nan <em>upvalue</em>, or <em>external local variable</em>,\ninside the inner function.\n\n\n<p>\nNotice that each execution of a <b>local</b> statement\ndefines new local variables.\nConsider the following example:\n\n<pre>\n     a = {}\n     local x = 20\n     for i=1,10 do\n       local y = 0\n       a[i] = function () y=y+1; return x+y end\n     end\n</pre><p>\nThe loop creates ten closures\n(that is, ten instances of the anonymous function).\nEach of these closures uses a different <code>y</code> variable,\nwhile all of them share the same <code>x</code>.\n\n\n\n\n\n<h1>4 &ndash; <a name=\"4\">The Application Program Interface</a></h1>\n\n<p>\n\nThis section describes the C&nbsp;API for Lua, that is,\nthe set of C&nbsp;functions available to the host program to communicate\nwith Lua.\nAll API functions and related types and constants\nare declared in the header file <a name=\"pdf-lua.h\"><code>lua.h</code></a>.\n\n\n<p>\nEven when we use the term \"function\",\nany facility in the API may be provided as a macro instead.\nExcept where stated otherwise,\nall such macros use each of their arguments exactly once\n(except for the first argument, which is always a Lua state),\nand so do not generate any hidden side-effects.\n\n\n<p>\nAs in most C&nbsp;libraries,\nthe Lua API functions do not check their arguments for validity or consistency.\nHowever, you can change this behavior by compiling Lua\nwith the macro <a name=\"pdf-LUA_USE_APICHECK\"><code>LUA_USE_APICHECK</code></a> defined.\n\n\n<p>\nThe Lua library is fully reentrant:\nit has no global variables.\nIt keeps all information it needs in a dynamic structure,\ncalled the <em>Lua state</em>.\n\n\n<p>\nEach Lua state has one or more threads,\nwhich correspond to independent, cooperative lines of execution.\nThe type <a href=\"#lua_State\"><code>lua_State</code></a> (despite its name) refers to a thread.\n(Indirectly, through the thread, it also refers to the\nLua state associated to the thread.)\n\n\n<p>\nA pointer to a thread must be passed as the first argument to\nevery function in the library, except to <a href=\"#lua_newstate\"><code>lua_newstate</code></a>,\nwhich creates a Lua state from scratch and returns a pointer\nto the <em>main thread</em> in the new state.\n\n\n\n<h2>4.1 &ndash; <a name=\"4.1\">The Stack</a></h2>\n\n<p>\nLua uses a <em>virtual stack</em> to pass values to and from C.\nEach element in this stack represents a Lua value\n(<b>nil</b>, number, string, etc.).\nFunctions in the API can access this stack through the\nLua state parameter that they receive.\n\n\n<p>\nWhenever Lua calls C, the called function gets a new stack,\nwhich is independent of previous stacks and of stacks of\nC&nbsp;functions that are still active.\nThis stack initially contains any arguments to the C&nbsp;function\nand it is where the C&nbsp;function can store temporary\nLua values and must push its results\nto be returned to the caller (see <a href=\"#lua_CFunction\"><code>lua_CFunction</code></a>).\n\n\n<p>\nFor convenience,\nmost query operations in the API do not follow a strict stack discipline.\nInstead, they can refer to any element in the stack\nby using an <em>index</em>:\nA positive index represents an absolute stack position\n(starting at&nbsp;1);\na negative index represents an offset relative to the top of the stack.\nMore specifically, if the stack has <em>n</em> elements,\nthen index&nbsp;1 represents the first element\n(that is, the element that was pushed onto the stack first)\nand\nindex&nbsp;<em>n</em> represents the last element;\nindex&nbsp;-1 also represents the last element\n(that is, the element at the&nbsp;top)\nand index <em>-n</em> represents the first element.\n\n\n\n\n\n<h2>4.2 &ndash; <a name=\"4.2\">Stack Size</a></h2>\n\n<p>\nWhen you interact with the Lua API,\nyou are responsible for ensuring consistency.\nIn particular,\n<em>you are responsible for controlling stack overflow</em>.\nYou can use the function <a href=\"#lua_checkstack\"><code>lua_checkstack</code></a>\nto ensure that the stack has enough space for pushing new elements.\n\n\n<p>\nWhenever Lua calls C,\nit ensures that the stack has space for\nat least <a name=\"pdf-LUA_MINSTACK\"><code>LUA_MINSTACK</code></a> extra slots.\n<code>LUA_MINSTACK</code> is defined as 20,\nso that usually you do not have to worry about stack space\nunless your code has loops pushing elements onto the stack.\n\n\n<p>\nWhen you call a Lua function\nwithout a fixed number of results (see <a href=\"#lua_call\"><code>lua_call</code></a>),\nLua ensures that the stack has enough space for all results,\nbut it does not ensure any extra space.\nSo, before pushing anything in the stack after such a call\nyou should use <a href=\"#lua_checkstack\"><code>lua_checkstack</code></a>.\n\n\n\n\n\n<h2>4.3 &ndash; <a name=\"4.3\">Valid and Acceptable Indices</a></h2>\n\n<p>\nAny function in the API that receives stack indices\nworks only with <em>valid indices</em> or <em>acceptable indices</em>.\n\n\n<p>\nA <em>valid index</em> is an index that refers to a\nposition that stores a modifiable Lua value.\nIt comprises stack indices between&nbsp;1 and the stack top\n(<code>1 &le; abs(index) &le; top</code>)\n\nplus <em>pseudo-indices</em>,\nwhich represent some positions that are accessible to C&nbsp;code\nbut that are not in the stack.\nPseudo-indices are used to access the registry (see <a href=\"#4.5\">&sect;4.5</a>)\nand the upvalues of a C&nbsp;function (see <a href=\"#4.4\">&sect;4.4</a>).\n\n\n<p>\nFunctions that do not need a specific mutable position,\nbut only a value (e.g., query functions),\ncan be called with acceptable indices.\nAn <em>acceptable index</em> can be any valid index,\nbut it also can be any positive index after the stack top\nwithin the space allocated for the stack,\nthat is, indices up to the stack size.\n(Note that 0 is never an acceptable index.)\nExcept when noted otherwise,\nfunctions in the API work with acceptable indices.\n\n\n<p>\nAcceptable indices serve to avoid extra tests\nagainst the stack top when querying the stack.\nFor instance, a C&nbsp;function can query its third argument\nwithout the need to first check whether there is a third argument,\nthat is, without the need to check whether 3 is a valid index.\n\n\n<p>\nFor functions that can be called with acceptable indices,\nany non-valid index is treated as if it\ncontains a value of a virtual type <a name=\"pdf-LUA_TNONE\"><code>LUA_TNONE</code></a>,\nwhich behaves like a nil value.\n\n\n\n\n\n<h2>4.4 &ndash; <a name=\"4.4\">C Closures</a></h2>\n\n<p>\nWhen a C&nbsp;function is created,\nit is possible to associate some values with it,\nthus creating a <em>C&nbsp;closure</em>\n(see <a href=\"#lua_pushcclosure\"><code>lua_pushcclosure</code></a>);\nthese values are called <em>upvalues</em> and are\naccessible to the function whenever it is called.\n\n\n<p>\nWhenever a C&nbsp;function is called,\nits upvalues are located at specific pseudo-indices.\nThese pseudo-indices are produced by the macro\n<a href=\"#lua_upvalueindex\"><code>lua_upvalueindex</code></a>.\nThe first upvalue associated with a function is at index\n<code>lua_upvalueindex(1)</code>, and so on.\nAny access to <code>lua_upvalueindex(<em>n</em>)</code>,\nwhere <em>n</em> is greater than the number of upvalues of the\ncurrent function\n(but not greater than 256,\nwhich is one plus the maximum number of upvalues in a closure),\nproduces an acceptable but invalid index.\n\n\n\n\n\n<h2>4.5 &ndash; <a name=\"4.5\">Registry</a></h2>\n\n<p>\nLua provides a <em>registry</em>,\na predefined table that can be used by any C&nbsp;code to\nstore whatever Lua values it needs to store.\nThe registry table is always located at pseudo-index\n<a name=\"pdf-LUA_REGISTRYINDEX\"><code>LUA_REGISTRYINDEX</code></a>.\nAny C&nbsp;library can store data into this table,\nbut it must take care to choose keys\nthat are different from those used\nby other libraries, to avoid collisions.\nTypically, you should use as key a string containing your library name,\nor a light userdata with the address of a C&nbsp;object in your code,\nor any Lua object created by your code.\nAs with variable names,\nstring keys starting with an underscore followed by\nuppercase letters are reserved for Lua.\n\n\n<p>\nThe integer keys in the registry are used\nby the reference mechanism (see <a href=\"#luaL_ref\"><code>luaL_ref</code></a>)\nand by some predefined values.\nTherefore, integer keys must not be used for other purposes.\n\n\n<p>\nWhen you create a new Lua state,\nits registry comes with some predefined values.\nThese predefined values are indexed with integer keys\ndefined as constants in <code>lua.h</code>.\nThe following constants are defined:\n\n<ul>\n<li><b><a name=\"pdf-LUA_RIDX_MAINTHREAD\"><code>LUA_RIDX_MAINTHREAD</code></a>: </b> At this index the registry has\nthe main thread of the state.\n(The main thread is the one created together with the state.)\n</li>\n\n<li><b><a name=\"pdf-LUA_RIDX_GLOBALS\"><code>LUA_RIDX_GLOBALS</code></a>: </b> At this index the registry has\nthe global environment.\n</li>\n</ul>\n\n\n\n\n<h2>4.6 &ndash; <a name=\"4.6\">Error Handling in C</a></h2>\n\n<p>\nInternally, Lua uses the C <code>longjmp</code> facility to handle errors.\n(Lua will use exceptions if you compile it as C++;\nsearch for <code>LUAI_THROW</code> in the source code for details.)\nWhen Lua faces any error\n(such as a memory allocation error or a type error)\nit <em>raises</em> an error;\nthat is, it does a long jump.\nA <em>protected environment</em> uses <code>setjmp</code>\nto set a recovery point;\nany error jumps to the most recent active recovery point.\n\n\n<p>\nInside a C&nbsp;function you can raise an error by calling <a href=\"#lua_error\"><code>lua_error</code></a>.\n\n\n<p>\nMost functions in the API can raise an error,\nfor instance due to a memory allocation error.\nThe documentation for each function indicates whether\nit can raise errors.\n\n\n<p>\nIf an error happens outside any protected environment,\nLua calls a <em>panic function</em> (see <a href=\"#lua_atpanic\"><code>lua_atpanic</code></a>)\nand then calls <code>abort</code>,\nthus exiting the host application.\nYour panic function can avoid this exit by\nnever returning\n(e.g., doing a long jump to your own recovery point outside Lua).\n\n\n<p>\nThe panic function,\nas its name implies,\nis a mechanism of last resort.\nPrograms should avoid it.\nAs a general rule,\nwhen a C&nbsp;function is called by Lua with a Lua state,\nit can do whatever it wants on that Lua state,\nas it should be already protected.\nHowever,\nwhen C code operates on other Lua states\n(e.g., a Lua argument to the function,\na Lua state stored in the registry, or\nthe result of <a href=\"#lua_newthread\"><code>lua_newthread</code></a>),\nit should use them only in API calls that cannot raise errors.\n\n\n<p>\nThe panic function runs as if it were a message handler (see <a href=\"#2.3\">&sect;2.3</a>);\nin particular, the error object is at the top of the stack.\nHowever, there is no guarantee about stack space.\nTo push anything on the stack,\nthe panic function must first check the available space (see <a href=\"#4.2\">&sect;4.2</a>).\n\n\n\n\n\n<h2>4.7 &ndash; <a name=\"4.7\">Handling Yields in C</a></h2>\n\n<p>\nInternally, Lua uses the C <code>longjmp</code> facility to yield a coroutine.\nTherefore, if a C&nbsp;function <code>foo</code> calls an API function\nand this API function yields\n(directly or indirectly by calling another function that yields),\nLua cannot return to <code>foo</code> any more,\nbecause the <code>longjmp</code> removes its frame from the C stack.\n\n\n<p>\nTo avoid this kind of problem,\nLua raises an error whenever it tries to yield across an API call,\nexcept for three functions:\n<a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>, <a href=\"#lua_callk\"><code>lua_callk</code></a>, and <a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>.\nAll those functions receive a <em>continuation function</em>\n(as a parameter named <code>k</code>) to continue execution after a yield.\n\n\n<p>\nWe need to set some terminology to explain continuations.\nWe have a C&nbsp;function called from Lua which we will call\nthe <em>original function</em>.\nThis original function then calls one of those three functions in the C API,\nwhich we will call the <em>callee function</em>,\nthat then yields the current thread.\n(This can happen when the callee function is <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>,\nor when the callee function is either <a href=\"#lua_callk\"><code>lua_callk</code></a> or <a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>\nand the function called by them yields.)\n\n\n<p>\nSuppose the running thread yields while executing the callee function.\nAfter the thread resumes,\nit eventually will finish running the callee function.\nHowever,\nthe callee function cannot return to the original function,\nbecause its frame in the C stack was destroyed by the yield.\nInstead, Lua calls a <em>continuation function</em>,\nwhich was given as an argument to the callee function.\nAs the name implies,\nthe continuation function should continue the task\nof the original function.\n\n\n<p>\nAs an illustration, consider the following function:\n\n<pre>\n     int original_function (lua_State *L) {\n       ...     /* code 1 */\n       status = lua_pcall(L, n, m, h);  /* calls Lua */\n       ...     /* code 2 */\n     }\n</pre><p>\nNow we want to allow\nthe Lua code being run by <a href=\"#lua_pcall\"><code>lua_pcall</code></a> to yield.\nFirst, we can rewrite our function like here:\n\n<pre>\n     int k (lua_State *L, int status, lua_KContext ctx) {\n       ...  /* code 2 */\n     }\n     \n     int original_function (lua_State *L) {\n       ...     /* code 1 */\n       return k(L, lua_pcall(L, n, m, h), ctx);\n     }\n</pre><p>\nIn the above code,\nthe new function <code>k</code> is a\n<em>continuation function</em> (with type <a href=\"#lua_KFunction\"><code>lua_KFunction</code></a>),\nwhich should do all the work that the original function\nwas doing after calling <a href=\"#lua_pcall\"><code>lua_pcall</code></a>.\nNow, we must inform Lua that it must call <code>k</code> if the Lua code\nbeing executed by <a href=\"#lua_pcall\"><code>lua_pcall</code></a> gets interrupted in some way\n(errors or yielding),\nso we rewrite the code as here,\nreplacing <a href=\"#lua_pcall\"><code>lua_pcall</code></a> by <a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>:\n\n<pre>\n     int original_function (lua_State *L) {\n       ...     /* code 1 */\n       return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);\n     }\n</pre><p>\nNote the external, explicit call to the continuation:\nLua will call the continuation only if needed, that is,\nin case of errors or resuming after a yield.\nIf the called function returns normally without ever yielding,\n<a href=\"#lua_pcallk\"><code>lua_pcallk</code></a> (and <a href=\"#lua_callk\"><code>lua_callk</code></a>) will also return normally.\n(Of course, instead of calling the continuation in that case,\nyou can do the equivalent work directly inside the original function.)\n\n\n<p>\nBesides the Lua state,\nthe continuation function has two other parameters:\nthe final status of the call plus the context value (<code>ctx</code>) that\nwas passed originally to <a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>.\n(Lua does not use this context value;\nit only passes this value from the original function to the\ncontinuation function.)\nFor <a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>,\nthe status is the same value that would be returned by <a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>,\nexcept that it is <a href=\"#pdf-LUA_YIELD\"><code>LUA_YIELD</code></a> when being executed after a yield\n(instead of <a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a>).\nFor <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a> and <a href=\"#lua_callk\"><code>lua_callk</code></a>,\nthe status is always <a href=\"#pdf-LUA_YIELD\"><code>LUA_YIELD</code></a> when Lua calls the continuation.\n(For these two functions,\nLua will not call the continuation in case of errors,\nbecause they do not handle errors.)\nSimilarly, when using <a href=\"#lua_callk\"><code>lua_callk</code></a>,\nyou should call the continuation function\nwith <a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a> as the status.\n(For <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>, there is not much point in calling\ndirectly the continuation function,\nbecause <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a> usually does not return.)\n\n\n<p>\nLua treats the continuation function as if it were the original function.\nThe continuation function receives the same Lua stack\nfrom the original function,\nin the same state it would be if the callee function had returned.\n(For instance,\nafter a <a href=\"#lua_callk\"><code>lua_callk</code></a> the function and its arguments are\nremoved from the stack and replaced by the results from the call.)\nIt also has the same upvalues.\nWhatever it returns is handled by Lua as if it were the return\nof the original function.\n\n\n\n\n\n<h2>4.8 &ndash; <a name=\"4.8\">Functions and Types</a></h2>\n\n<p>\nHere we list all functions and types from the C&nbsp;API in\nalphabetical order.\nEach function has an indicator like this:\n<span class=\"apii\">[-o, +p, <em>x</em>]</span>\n\n\n<p>\nThe first field, <code>o</code>,\nis how many elements the function pops from the stack.\nThe second field, <code>p</code>,\nis how many elements the function pushes onto the stack.\n(Any function always pushes its results after popping its arguments.)\nA field in the form <code>x|y</code> means the function can push (or pop)\n<code>x</code> or <code>y</code> elements,\ndepending on the situation;\nan interrogation mark '<code>?</code>' means that\nwe cannot know how many elements the function pops/pushes\nby looking only at its arguments\n(e.g., they may depend on what is on the stack).\nThe third field, <code>x</code>,\ntells whether the function may raise errors:\n'<code>-</code>' means the function never raises any error;\n'<code>m</code>' means the function may raise out-of-memory errors\nand errors running a <code>__gc</code> metamethod;\n'<code>e</code>' means the function may raise any errors\n(it can run arbitrary Lua code,\neither directly or through metamethods);\n'<code>v</code>' means the function may raise an error on purpose.\n\n\n\n<hr><h3><a name=\"lua_absindex\"><code>lua_absindex</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_absindex (lua_State *L, int idx);</pre>\n\n<p>\nConverts the acceptable index <code>idx</code>\ninto an equivalent absolute index\n(that is, one that does not depend on the stack top).\n\n\n\n\n\n<hr><h3><a name=\"lua_Alloc\"><code>lua_Alloc</code></a></h3>\n<pre>typedef void * (*lua_Alloc) (void *ud,\n                             void *ptr,\n                             size_t osize,\n                             size_t nsize);</pre>\n\n<p>\nThe type of the memory-allocation function used by Lua states.\nThe allocator function must provide a\nfunctionality similar to <code>realloc</code>,\nbut not exactly the same.\nIts arguments are\n<code>ud</code>, an opaque pointer passed to <a href=\"#lua_newstate\"><code>lua_newstate</code></a>;\n<code>ptr</code>, a pointer to the block being allocated/reallocated/freed;\n<code>osize</code>, the original size of the block or some code about what\nis being allocated;\nand <code>nsize</code>, the new size of the block.\n\n\n<p>\nWhen <code>ptr</code> is not <code>NULL</code>,\n<code>osize</code> is the size of the block pointed by <code>ptr</code>,\nthat is, the size given when it was allocated or reallocated.\n\n\n<p>\nWhen <code>ptr</code> is <code>NULL</code>,\n<code>osize</code> encodes the kind of object that Lua is allocating.\n<code>osize</code> is any of\n<a href=\"#pdf-LUA_TSTRING\"><code>LUA_TSTRING</code></a>, <a href=\"#pdf-LUA_TTABLE\"><code>LUA_TTABLE</code></a>, <a href=\"#pdf-LUA_TFUNCTION\"><code>LUA_TFUNCTION</code></a>,\n<a href=\"#pdf-LUA_TUSERDATA\"><code>LUA_TUSERDATA</code></a>, or <a href=\"#pdf-LUA_TTHREAD\"><code>LUA_TTHREAD</code></a> when (and only when)\nLua is creating a new object of that type.\nWhen <code>osize</code> is some other value,\nLua is allocating memory for something else.\n\n\n<p>\nLua assumes the following behavior from the allocator function:\n\n\n<p>\nWhen <code>nsize</code> is zero,\nthe allocator must behave like <code>free</code>\nand return <code>NULL</code>.\n\n\n<p>\nWhen <code>nsize</code> is not zero,\nthe allocator must behave like <code>realloc</code>.\nThe allocator returns <code>NULL</code>\nif and only if it cannot fulfill the request.\nLua assumes that the allocator never fails when\n<code>osize &gt;= nsize</code>.\n\n\n<p>\nHere is a simple implementation for the allocator function.\nIt is used in the auxiliary library by <a href=\"#luaL_newstate\"><code>luaL_newstate</code></a>.\n\n<pre>\n     static void *l_alloc (void *ud, void *ptr, size_t osize,\n                                                size_t nsize) {\n       (void)ud;  (void)osize;  /* not used */\n       if (nsize == 0) {\n         free(ptr);\n         return NULL;\n       }\n       else\n         return realloc(ptr, nsize);\n     }\n</pre><p>\nNote that Standard&nbsp;C ensures\nthat <code>free(NULL)</code> has no effect and that\n<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>.\nThis code assumes that <code>realloc</code> does not fail when shrinking a block.\n(Although Standard&nbsp;C does not ensure this behavior,\nit seems to be a safe assumption.)\n\n\n\n\n\n<hr><h3><a name=\"lua_arith\"><code>lua_arith</code></a></h3><p>\n<span class=\"apii\">[-(2|1), +1, <em>e</em>]</span>\n<pre>void lua_arith (lua_State *L, int op);</pre>\n\n<p>\nPerforms an arithmetic or bitwise operation over the two values\n(or one, in the case of negations)\nat the top of the stack,\nwith the value at the top being the second operand,\npops these values, and pushes the result of the operation.\nThe function follows the semantics of the corresponding Lua operator\n(that is, it may call metamethods).\n\n\n<p>\nThe value of <code>op</code> must be one of the following constants:\n\n<ul>\n\n<li><b><a name=\"pdf-LUA_OPADD\"><code>LUA_OPADD</code></a>: </b> performs addition (<code>+</code>)</li>\n<li><b><a name=\"pdf-LUA_OPSUB\"><code>LUA_OPSUB</code></a>: </b> performs subtraction (<code>-</code>)</li>\n<li><b><a name=\"pdf-LUA_OPMUL\"><code>LUA_OPMUL</code></a>: </b> performs multiplication (<code>*</code>)</li>\n<li><b><a name=\"pdf-LUA_OPDIV\"><code>LUA_OPDIV</code></a>: </b> performs float division (<code>/</code>)</li>\n<li><b><a name=\"pdf-LUA_OPIDIV\"><code>LUA_OPIDIV</code></a>: </b> performs floor division (<code>//</code>)</li>\n<li><b><a name=\"pdf-LUA_OPMOD\"><code>LUA_OPMOD</code></a>: </b> performs modulo (<code>%</code>)</li>\n<li><b><a name=\"pdf-LUA_OPPOW\"><code>LUA_OPPOW</code></a>: </b> performs exponentiation (<code>^</code>)</li>\n<li><b><a name=\"pdf-LUA_OPUNM\"><code>LUA_OPUNM</code></a>: </b> performs mathematical negation (unary <code>-</code>)</li>\n<li><b><a name=\"pdf-LUA_OPBNOT\"><code>LUA_OPBNOT</code></a>: </b> performs bitwise NOT (<code>~</code>)</li>\n<li><b><a name=\"pdf-LUA_OPBAND\"><code>LUA_OPBAND</code></a>: </b> performs bitwise AND (<code>&amp;</code>)</li>\n<li><b><a name=\"pdf-LUA_OPBOR\"><code>LUA_OPBOR</code></a>: </b> performs bitwise OR (<code>|</code>)</li>\n<li><b><a name=\"pdf-LUA_OPBXOR\"><code>LUA_OPBXOR</code></a>: </b> performs bitwise exclusive OR (<code>~</code>)</li>\n<li><b><a name=\"pdf-LUA_OPSHL\"><code>LUA_OPSHL</code></a>: </b> performs left shift (<code>&lt;&lt;</code>)</li>\n<li><b><a name=\"pdf-LUA_OPSHR\"><code>LUA_OPSHR</code></a>: </b> performs right shift (<code>&gt;&gt;</code>)</li>\n\n</ul>\n\n\n\n\n<hr><h3><a name=\"lua_atpanic\"><code>lua_atpanic</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);</pre>\n\n<p>\nSets a new panic function and returns the old one (see <a href=\"#4.6\">&sect;4.6</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_call\"><code>lua_call</code></a></h3><p>\n<span class=\"apii\">[-(nargs+1), +nresults, <em>e</em>]</span>\n<pre>void lua_call (lua_State *L, int nargs, int nresults);</pre>\n\n<p>\nCalls a function.\n\n\n<p>\nTo call a function you must use the following protocol:\nfirst, the function to be called is pushed onto the stack;\nthen, the arguments to the function are pushed\nin direct order;\nthat is, the first argument is pushed first.\nFinally you call <a href=\"#lua_call\"><code>lua_call</code></a>;\n<code>nargs</code> is the number of arguments that you pushed onto the stack.\nAll arguments and the function value are popped from the stack\nwhen the function is called.\nThe function results are pushed onto the stack when the function returns.\nThe number of results is adjusted to <code>nresults</code>,\nunless <code>nresults</code> is <a name=\"pdf-LUA_MULTRET\"><code>LUA_MULTRET</code></a>.\nIn this case, all results from the function are pushed;\nLua takes care that the returned values fit into the stack space,\nbut it does not ensure any extra space in the stack.\nThe function results are pushed onto the stack in direct order\n(the first result is pushed first),\nso that after the call the last result is on the top of the stack.\n\n\n<p>\nAny error inside the called function is propagated upwards\n(with a <code>longjmp</code>).\n\n\n<p>\nThe following example shows how the host program can do the\nequivalent to this Lua code:\n\n<pre>\n     a = f(\"how\", t.x, 14)\n</pre><p>\nHere it is in&nbsp;C:\n\n<pre>\n     lua_getglobal(L, \"f\");                  /* function to be called */\n     lua_pushliteral(L, \"how\");                       /* 1st argument */\n     lua_getglobal(L, \"t\");                    /* table to be indexed */\n     lua_getfield(L, -1, \"x\");        /* push result of t.x (2nd arg) */\n     lua_remove(L, -2);                  /* remove 't' from the stack */\n     lua_pushinteger(L, 14);                          /* 3rd argument */\n     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */\n     lua_setglobal(L, \"a\");                         /* set global 'a' */\n</pre><p>\nNote that the code above is <em>balanced</em>:\nat its end, the stack is back to its original configuration.\nThis is considered good programming practice.\n\n\n\n\n\n<hr><h3><a name=\"lua_callk\"><code>lua_callk</code></a></h3><p>\n<span class=\"apii\">[-(nargs + 1), +nresults, <em>e</em>]</span>\n<pre>void lua_callk (lua_State *L,\n                int nargs,\n                int nresults,\n                lua_KContext ctx,\n                lua_KFunction k);</pre>\n\n<p>\nThis function behaves exactly like <a href=\"#lua_call\"><code>lua_call</code></a>,\nbut allows the called function to yield (see <a href=\"#4.7\">&sect;4.7</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_CFunction\"><code>lua_CFunction</code></a></h3>\n<pre>typedef int (*lua_CFunction) (lua_State *L);</pre>\n\n<p>\nType for C&nbsp;functions.\n\n\n<p>\nIn order to communicate properly with Lua,\na C&nbsp;function must use the following protocol,\nwhich defines the way parameters and results are passed:\na C&nbsp;function receives its arguments from Lua in its stack\nin direct order (the first argument is pushed first).\nSo, when the function starts,\n<code>lua_gettop(L)</code> returns the number of arguments received by the function.\nThe first argument (if any) is at index 1\nand its last argument is at index <code>lua_gettop(L)</code>.\nTo return values to Lua, a C&nbsp;function just pushes them onto the stack,\nin direct order (the first result is pushed first),\nand returns the number of results.\nAny other value in the stack below the results will be properly\ndiscarded by Lua.\nLike a Lua function, a C&nbsp;function called by Lua can also return\nmany results.\n\n\n<p>\nAs an example, the following function receives a variable number\nof numeric arguments and returns their average and their sum:\n\n<pre>\n     static int foo (lua_State *L) {\n       int n = lua_gettop(L);    /* number of arguments */\n       lua_Number sum = 0.0;\n       int i;\n       for (i = 1; i &lt;= n; i++) {\n         if (!lua_isnumber(L, i)) {\n           lua_pushliteral(L, \"incorrect argument\");\n           lua_error(L);\n         }\n         sum += lua_tonumber(L, i);\n       }\n       lua_pushnumber(L, sum/n);        /* first result */\n       lua_pushnumber(L, sum);         /* second result */\n       return 2;                   /* number of results */\n     }\n</pre>\n\n\n\n\n<hr><h3><a name=\"lua_checkstack\"><code>lua_checkstack</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_checkstack (lua_State *L, int n);</pre>\n\n<p>\nEnsures that the stack has space for at least <code>n</code> extra slots\n(that is, that you can safely push up to <code>n</code> values into it).\nIt returns false if it cannot fulfill the request,\neither because it would cause the stack\nto be larger than a fixed maximum size\n(typically at least several thousand elements) or\nbecause it cannot allocate memory for the extra space.\nThis function never shrinks the stack;\nif the stack already has space for the extra slots,\nit is left unchanged.\n\n\n\n\n\n<hr><h3><a name=\"lua_close\"><code>lua_close</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void lua_close (lua_State *L);</pre>\n\n<p>\nDestroys all objects in the given Lua state\n(calling the corresponding garbage-collection metamethods, if any)\nand frees all dynamic memory used by this state.\nIn several platforms, you may not need to call this function,\nbecause all resources are naturally released when the host program ends.\nOn the other hand, long-running programs that create multiple states,\nsuch as daemons or web servers,\nwill probably need to close states as soon as they are not needed.\n\n\n\n\n\n<hr><h3><a name=\"lua_compare\"><code>lua_compare</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>e</em>]</span>\n<pre>int lua_compare (lua_State *L, int index1, int index2, int op);</pre>\n\n<p>\nCompares two Lua values.\nReturns 1 if the value at index <code>index1</code> satisfies <code>op</code>\nwhen compared with the value at index <code>index2</code>,\nfollowing the semantics of the corresponding Lua operator\n(that is, it may call metamethods).\nOtherwise returns&nbsp;0.\nAlso returns&nbsp;0 if any of the indices is not valid.\n\n\n<p>\nThe value of <code>op</code> must be one of the following constants:\n\n<ul>\n\n<li><b><a name=\"pdf-LUA_OPEQ\"><code>LUA_OPEQ</code></a>: </b> compares for equality (<code>==</code>)</li>\n<li><b><a name=\"pdf-LUA_OPLT\"><code>LUA_OPLT</code></a>: </b> compares for less than (<code>&lt;</code>)</li>\n<li><b><a name=\"pdf-LUA_OPLE\"><code>LUA_OPLE</code></a>: </b> compares for less or equal (<code>&lt;=</code>)</li>\n\n</ul>\n\n\n\n\n<hr><h3><a name=\"lua_concat\"><code>lua_concat</code></a></h3><p>\n<span class=\"apii\">[-n, +1, <em>e</em>]</span>\n<pre>void lua_concat (lua_State *L, int n);</pre>\n\n<p>\nConcatenates the <code>n</code> values at the top of the stack,\npops them, and leaves the result at the top.\nIf <code>n</code>&nbsp;is&nbsp;1, the result is the single value on the stack\n(that is, the function does nothing);\nif <code>n</code> is 0, the result is the empty string.\nConcatenation is performed following the usual semantics of Lua\n(see <a href=\"#3.4.6\">&sect;3.4.6</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_copy\"><code>lua_copy</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void lua_copy (lua_State *L, int fromidx, int toidx);</pre>\n\n<p>\nCopies the element at index <code>fromidx</code>\ninto the valid index <code>toidx</code>,\nreplacing the value at that position.\nValues at other positions are not affected.\n\n\n\n\n\n<hr><h3><a name=\"lua_createtable\"><code>lua_createtable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void lua_createtable (lua_State *L, int narr, int nrec);</pre>\n\n<p>\nCreates a new empty table and pushes it onto the stack.\nParameter <code>narr</code> is a hint for how many elements the table\nwill have as a sequence;\nparameter <code>nrec</code> is a hint for how many other elements\nthe table will have.\nLua may use these hints to preallocate memory for the new table.\nThis preallocation is useful for performance when you know in advance\nhow many elements the table will have.\nOtherwise you can use the function <a href=\"#lua_newtable\"><code>lua_newtable</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_dump\"><code>lua_dump</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_dump (lua_State *L,\n                        lua_Writer writer,\n                        void *data,\n                        int strip);</pre>\n\n<p>\nDumps a function as a binary chunk.\nReceives a Lua function on the top of the stack\nand produces a binary chunk that,\nif loaded again,\nresults in a function equivalent to the one dumped.\nAs it produces parts of the chunk,\n<a href=\"#lua_dump\"><code>lua_dump</code></a> calls function <code>writer</code> (see <a href=\"#lua_Writer\"><code>lua_Writer</code></a>)\nwith the given <code>data</code>\nto write them.\n\n\n<p>\nIf <code>strip</code> is true,\nthe binary representation may not include all debug information\nabout the function,\nto save space.\n\n\n<p>\nThe value returned is the error code returned by the last\ncall to the writer;\n0&nbsp;means no errors.\n\n\n<p>\nThis function does not pop the Lua function from the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_error\"><code>lua_error</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>v</em>]</span>\n<pre>int lua_error (lua_State *L);</pre>\n\n<p>\nGenerates a Lua error,\nusing the value at the top of the stack as the error object.\nThis function does a long jump,\nand therefore never returns\n(see <a href=\"#luaL_error\"><code>luaL_error</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_gc\"><code>lua_gc</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>m</em>]</span>\n<pre>int lua_gc (lua_State *L, int what, int data);</pre>\n\n<p>\nControls the garbage collector.\n\n\n<p>\nThis function performs several tasks,\naccording to the value of the parameter <code>what</code>:\n\n<ul>\n\n<li><b><code>LUA_GCSTOP</code>: </b>\nstops the garbage collector.\n</li>\n\n<li><b><code>LUA_GCRESTART</code>: </b>\nrestarts the garbage collector.\n</li>\n\n<li><b><code>LUA_GCCOLLECT</code>: </b>\nperforms a full garbage-collection cycle.\n</li>\n\n<li><b><code>LUA_GCCOUNT</code>: </b>\nreturns the current amount of memory (in Kbytes) in use by Lua.\n</li>\n\n<li><b><code>LUA_GCCOUNTB</code>: </b>\nreturns the remainder of dividing the current amount of bytes of\nmemory in use by Lua by 1024.\n</li>\n\n<li><b><code>LUA_GCSTEP</code>: </b>\nperforms an incremental step of garbage collection.\n</li>\n\n<li><b><code>LUA_GCSETPAUSE</code>: </b>\nsets <code>data</code> as the new value\nfor the <em>pause</em> of the collector (see <a href=\"#2.5\">&sect;2.5</a>)\nand returns the previous value of the pause.\n</li>\n\n<li><b><code>LUA_GCSETSTEPMUL</code>: </b>\nsets <code>data</code> as the new value for the <em>step multiplier</em> of\nthe collector (see <a href=\"#2.5\">&sect;2.5</a>)\nand returns the previous value of the step multiplier.\n</li>\n\n<li><b><code>LUA_GCISRUNNING</code>: </b>\nreturns a boolean that tells whether the collector is running\n(i.e., not stopped).\n</li>\n\n</ul>\n\n<p>\nFor more details about these options,\nsee <a href=\"#pdf-collectgarbage\"><code>collectgarbage</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_getallocf\"><code>lua_getallocf</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_Alloc lua_getallocf (lua_State *L, void **ud);</pre>\n\n<p>\nReturns the memory-allocation function of a given state.\nIf <code>ud</code> is not <code>NULL</code>, Lua stores in <code>*ud</code> the\nopaque pointer given when the memory-allocator function was set.\n\n\n\n\n\n<hr><h3><a name=\"lua_getfield\"><code>lua_getfield</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>int lua_getfield (lua_State *L, int index, const char *k);</pre>\n\n<p>\nPushes onto the stack the value <code>t[k]</code>,\nwhere <code>t</code> is the value at the given index.\nAs in Lua, this function may trigger a metamethod\nfor the \"index\" event (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n<p>\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"lua_getextraspace\"><code>lua_getextraspace</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void *lua_getextraspace (lua_State *L);</pre>\n\n<p>\nReturns a pointer to a raw memory area associated with the\ngiven Lua state.\nThe application can use this area for any purpose;\nLua does not use it for anything.\n\n\n<p>\nEach new thread has this area initialized with a copy\nof the area of the main thread.\n\n\n<p>\nBy default, this area has the size of a pointer to void,\nbut you can recompile Lua with a different size for this area.\n(See <code>LUA_EXTRASPACE</code> in <code>luaconf.h</code>.)\n\n\n\n\n\n<hr><h3><a name=\"lua_getglobal\"><code>lua_getglobal</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>int lua_getglobal (lua_State *L, const char *name);</pre>\n\n<p>\nPushes onto the stack the value of the global <code>name</code>.\nReturns the type of that value.\n\n\n\n\n\n<hr><h3><a name=\"lua_geti\"><code>lua_geti</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>int lua_geti (lua_State *L, int index, lua_Integer i);</pre>\n\n<p>\nPushes onto the stack the value <code>t[i]</code>,\nwhere <code>t</code> is the value at the given index.\nAs in Lua, this function may trigger a metamethod\nfor the \"index\" event (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n<p>\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"lua_getmetatable\"><code>lua_getmetatable</code></a></h3><p>\n<span class=\"apii\">[-0, +(0|1), &ndash;]</span>\n<pre>int lua_getmetatable (lua_State *L, int index);</pre>\n\n<p>\nIf the value at the given index has a metatable,\nthe function pushes that metatable onto the stack and returns&nbsp;1.\nOtherwise,\nthe function returns&nbsp;0 and pushes nothing on the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_gettable\"><code>lua_gettable</code></a></h3><p>\n<span class=\"apii\">[-1, +1, <em>e</em>]</span>\n<pre>int lua_gettable (lua_State *L, int index);</pre>\n\n<p>\nPushes onto the stack the value <code>t[k]</code>,\nwhere <code>t</code> is the value at the given index\nand <code>k</code> is the value at the top of the stack.\n\n\n<p>\nThis function pops the key from the stack,\npushing the resulting value in its place.\nAs in Lua, this function may trigger a metamethod\nfor the \"index\" event (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n<p>\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"lua_gettop\"><code>lua_gettop</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_gettop (lua_State *L);</pre>\n\n<p>\nReturns the index of the top element in the stack.\nBecause indices start at&nbsp;1,\nthis result is equal to the number of elements in the stack;\nin particular, 0&nbsp;means an empty stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_getuservalue\"><code>lua_getuservalue</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int lua_getuservalue (lua_State *L, int index);</pre>\n\n<p>\nPushes onto the stack the Lua value associated with the full userdata\nat the given index.\n\n\n<p>\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"lua_insert\"><code>lua_insert</code></a></h3><p>\n<span class=\"apii\">[-1, +1, &ndash;]</span>\n<pre>void lua_insert (lua_State *L, int index);</pre>\n\n<p>\nMoves the top element into the given valid index,\nshifting up the elements above this index to open space.\nThis function cannot be called with a pseudo-index,\nbecause a pseudo-index is not an actual stack position.\n\n\n\n\n\n<hr><h3><a name=\"lua_Integer\"><code>lua_Integer</code></a></h3>\n<pre>typedef ... lua_Integer;</pre>\n\n<p>\nThe type of integers in Lua.\n\n\n<p>\nBy default this type is <code>long long</code>,\n(usually a 64-bit two-complement integer),\nbut that can be changed to <code>long</code> or <code>int</code>\n(usually a 32-bit two-complement integer).\n(See <code>LUA_INT_TYPE</code> in <code>luaconf.h</code>.)\n\n\n<p>\nLua also defines the constants\n<a name=\"pdf-LUA_MININTEGER\"><code>LUA_MININTEGER</code></a> and <a name=\"pdf-LUA_MAXINTEGER\"><code>LUA_MAXINTEGER</code></a>,\nwith the minimum and the maximum values that fit in this type.\n\n\n\n\n\n<hr><h3><a name=\"lua_isboolean\"><code>lua_isboolean</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isboolean (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a boolean,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_iscfunction\"><code>lua_iscfunction</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_iscfunction (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a C&nbsp;function,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isfunction\"><code>lua_isfunction</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isfunction (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a function\n(either C or Lua), and 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isinteger\"><code>lua_isinteger</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isinteger (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is an integer\n(that is, the value is a number and is represented as an integer),\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_islightuserdata\"><code>lua_islightuserdata</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_islightuserdata (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a light userdata,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isnil\"><code>lua_isnil</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isnil (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is <b>nil</b>,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isnone\"><code>lua_isnone</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isnone (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the given index is not valid,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isnoneornil\"><code>lua_isnoneornil</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isnoneornil (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the given index is not valid\nor if the value at this index is <b>nil</b>,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isnumber\"><code>lua_isnumber</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isnumber (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a number\nor a string convertible to a number,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isstring\"><code>lua_isstring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isstring (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a string\nor a number (which is always convertible to a string),\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_istable\"><code>lua_istable</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_istable (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a table,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isthread\"><code>lua_isthread</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isthread (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a thread,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isuserdata\"><code>lua_isuserdata</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isuserdata (lua_State *L, int index);</pre>\n\n<p>\nReturns 1 if the value at the given index is a userdata\n(either full or light), and 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_isyieldable\"><code>lua_isyieldable</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_isyieldable (lua_State *L);</pre>\n\n<p>\nReturns 1 if the given coroutine can yield,\nand 0&nbsp;otherwise.\n\n\n\n\n\n<hr><h3><a name=\"lua_KContext\"><code>lua_KContext</code></a></h3>\n<pre>typedef ... lua_KContext;</pre>\n\n<p>\nThe type for continuation-function contexts.\nIt must be a numeric type.\nThis type is defined as <code>intptr_t</code>\nwhen <code>intptr_t</code> is available,\nso that it can store pointers too.\nOtherwise, it is defined as <code>ptrdiff_t</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_KFunction\"><code>lua_KFunction</code></a></h3>\n<pre>typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);</pre>\n\n<p>\nType for continuation functions (see <a href=\"#4.7\">&sect;4.7</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_len\"><code>lua_len</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>void lua_len (lua_State *L, int index);</pre>\n\n<p>\nReturns the length of the value at the given index.\nIt is equivalent to the '<code>#</code>' operator in Lua (see <a href=\"#3.4.7\">&sect;3.4.7</a>) and\nmay trigger a metamethod for the \"length\" event (see <a href=\"#2.4\">&sect;2.4</a>).\nThe result is pushed on the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_load\"><code>lua_load</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int lua_load (lua_State *L,\n              lua_Reader reader,\n              void *data,\n              const char *chunkname,\n              const char *mode);</pre>\n\n<p>\nLoads a Lua chunk without running it.\nIf there are no errors,\n<code>lua_load</code> pushes the compiled chunk as a Lua\nfunction on top of the stack.\nOtherwise, it pushes an error message.\n\n\n<p>\nThe return values of <code>lua_load</code> are:\n\n<ul>\n\n<li><b><a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a>: </b> no errors;</li>\n\n<li><b><a name=\"pdf-LUA_ERRSYNTAX\"><code>LUA_ERRSYNTAX</code></a>: </b>\nsyntax error during precompilation;</li>\n\n<li><b><a href=\"#pdf-LUA_ERRMEM\"><code>LUA_ERRMEM</code></a>: </b>\nmemory allocation (out-of-memory) error;</li>\n\n<li><b><a href=\"#pdf-LUA_ERRGCMM\"><code>LUA_ERRGCMM</code></a>: </b>\nerror while running a <code>__gc</code> metamethod.\n(This error has no relation with the chunk being loaded.\nIt is generated by the garbage collector.)\n</li>\n\n</ul>\n\n<p>\nThe <code>lua_load</code> function uses a user-supplied <code>reader</code> function\nto read the chunk (see <a href=\"#lua_Reader\"><code>lua_Reader</code></a>).\nThe <code>data</code> argument is an opaque value passed to the reader function.\n\n\n<p>\nThe <code>chunkname</code> argument gives a name to the chunk,\nwhich is used for error messages and in debug information (see <a href=\"#4.9\">&sect;4.9</a>).\n\n\n<p>\n<code>lua_load</code> automatically detects whether the chunk is text or binary\nand loads it accordingly (see program <code>luac</code>).\nThe string <code>mode</code> works as in function <a href=\"#pdf-load\"><code>load</code></a>,\nwith the addition that\na <code>NULL</code> value is equivalent to the string \"<code>bt</code>\".\n\n\n<p>\n<code>lua_load</code> uses the stack internally,\nso the reader function must always leave the stack\nunmodified when returning.\n\n\n<p>\nIf the resulting function has upvalues,\nits first upvalue is set to the value of the global environment\nstored at index <code>LUA_RIDX_GLOBALS</code> in the registry (see <a href=\"#4.5\">&sect;4.5</a>).\nWhen loading main chunks,\nthis upvalue will be the <code>_ENV</code> variable (see <a href=\"#2.2\">&sect;2.2</a>).\nOther upvalues are initialized with <b>nil</b>.\n\n\n\n\n\n<hr><h3><a name=\"lua_newstate\"><code>lua_newstate</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_State *lua_newstate (lua_Alloc f, void *ud);</pre>\n\n<p>\nCreates a new thread running in a new, independent state.\nReturns <code>NULL</code> if it cannot create the thread or the state\n(due to lack of memory).\nThe argument <code>f</code> is the allocator function;\nLua does all memory allocation for this state\nthrough this function (see <a href=\"#lua_Alloc\"><code>lua_Alloc</code></a>).\nThe second argument, <code>ud</code>, is an opaque pointer that Lua\npasses to the allocator in every call.\n\n\n\n\n\n<hr><h3><a name=\"lua_newtable\"><code>lua_newtable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void lua_newtable (lua_State *L);</pre>\n\n<p>\nCreates a new empty table and pushes it onto the stack.\nIt is equivalent to <code>lua_createtable(L, 0, 0)</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_newthread\"><code>lua_newthread</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>lua_State *lua_newthread (lua_State *L);</pre>\n\n<p>\nCreates a new thread, pushes it on the stack,\nand returns a pointer to a <a href=\"#lua_State\"><code>lua_State</code></a> that represents this new thread.\nThe new thread returned by this function shares with the original thread\nits global environment,\nbut has an independent execution stack.\n\n\n<p>\nThere is no explicit function to close or to destroy a thread.\nThreads are subject to garbage collection,\nlike any Lua object.\n\n\n\n\n\n<hr><h3><a name=\"lua_newuserdata\"><code>lua_newuserdata</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void *lua_newuserdata (lua_State *L, size_t size);</pre>\n\n<p>\nThis function allocates a new block of memory with the given size,\npushes onto the stack a new full userdata with the block address,\nand returns this address.\nThe host program can freely use this memory.\n\n\n\n\n\n<hr><h3><a name=\"lua_next\"><code>lua_next</code></a></h3><p>\n<span class=\"apii\">[-1, +(2|0), <em>e</em>]</span>\n<pre>int lua_next (lua_State *L, int index);</pre>\n\n<p>\nPops a key from the stack,\nand pushes a key&ndash;value pair from the table at the given index\n(the \"next\" pair after the given key).\nIf there are no more elements in the table,\nthen <a href=\"#lua_next\"><code>lua_next</code></a> returns 0 (and pushes nothing).\n\n\n<p>\nA typical traversal looks like this:\n\n<pre>\n     /* table is in the stack at index 't' */\n     lua_pushnil(L);  /* first key */\n     while (lua_next(L, t) != 0) {\n       /* uses 'key' (at index -2) and 'value' (at index -1) */\n       printf(\"%s - %s\\n\",\n              lua_typename(L, lua_type(L, -2)),\n              lua_typename(L, lua_type(L, -1)));\n       /* removes 'value'; keeps 'key' for next iteration */\n       lua_pop(L, 1);\n     }\n</pre>\n\n<p>\nWhile traversing a table,\ndo not call <a href=\"#lua_tolstring\"><code>lua_tolstring</code></a> directly on a key,\nunless you know that the key is actually a string.\nRecall that <a href=\"#lua_tolstring\"><code>lua_tolstring</code></a> may change\nthe value at the given index;\nthis confuses the next call to <a href=\"#lua_next\"><code>lua_next</code></a>.\n\n\n<p>\nSee function <a href=\"#pdf-next\"><code>next</code></a> for the caveats of modifying\nthe table during its traversal.\n\n\n\n\n\n<hr><h3><a name=\"lua_Number\"><code>lua_Number</code></a></h3>\n<pre>typedef ... lua_Number;</pre>\n\n<p>\nThe type of floats in Lua.\n\n\n<p>\nBy default this type is double,\nbut that can be changed to a single float or a long double.\n(See <code>LUA_FLOAT_TYPE</code> in <code>luaconf.h</code>.)\n\n\n\n\n\n<hr><h3><a name=\"lua_numbertointeger\"><code>lua_numbertointeger</code></a></h3>\n<pre>int lua_numbertointeger (lua_Number n, lua_Integer *p);</pre>\n\n<p>\nConverts a Lua float to a Lua integer.\nThis macro assumes that <code>n</code> has an integral value.\nIf that value is within the range of Lua integers,\nit is converted to an integer and assigned to <code>*p</code>.\nThe macro results in a boolean indicating whether the\nconversion was successful.\n(Note that this range test can be tricky to do\ncorrectly without this macro,\ndue to roundings.)\n\n\n<p>\nThis macro may evaluate its arguments more than once.\n\n\n\n\n\n<hr><h3><a name=\"lua_pcall\"><code>lua_pcall</code></a></h3><p>\n<span class=\"apii\">[-(nargs + 1), +(nresults|1), &ndash;]</span>\n<pre>int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);</pre>\n\n<p>\nCalls a function in protected mode.\n\n\n<p>\nBoth <code>nargs</code> and <code>nresults</code> have the same meaning as\nin <a href=\"#lua_call\"><code>lua_call</code></a>.\nIf there are no errors during the call,\n<a href=\"#lua_pcall\"><code>lua_pcall</code></a> behaves exactly like <a href=\"#lua_call\"><code>lua_call</code></a>.\nHowever, if there is any error,\n<a href=\"#lua_pcall\"><code>lua_pcall</code></a> catches it,\npushes a single value on the stack (the error object),\nand returns an error code.\nLike <a href=\"#lua_call\"><code>lua_call</code></a>,\n<a href=\"#lua_pcall\"><code>lua_pcall</code></a> always removes the function\nand its arguments from the stack.\n\n\n<p>\nIf <code>msgh</code> is 0,\nthen the error object returned on the stack\nis exactly the original error object.\nOtherwise, <code>msgh</code> is the stack index of a\n<em>message handler</em>.\n(This index cannot be a pseudo-index.)\nIn case of runtime errors,\nthis function will be called with the error object\nand its return value will be the object\nreturned on the stack by <a href=\"#lua_pcall\"><code>lua_pcall</code></a>.\n\n\n<p>\nTypically, the message handler is used to add more debug\ninformation to the error object, such as a stack traceback.\nSuch information cannot be gathered after the return of <a href=\"#lua_pcall\"><code>lua_pcall</code></a>,\nsince by then the stack has unwound.\n\n\n<p>\nThe <a href=\"#lua_pcall\"><code>lua_pcall</code></a> function returns one of the following constants\n(defined in <code>lua.h</code>):\n\n<ul>\n\n<li><b><a name=\"pdf-LUA_OK\"><code>LUA_OK</code></a> (0): </b>\nsuccess.</li>\n\n<li><b><a name=\"pdf-LUA_ERRRUN\"><code>LUA_ERRRUN</code></a>: </b>\na runtime error.\n</li>\n\n<li><b><a name=\"pdf-LUA_ERRMEM\"><code>LUA_ERRMEM</code></a>: </b>\nmemory allocation error.\nFor such errors, Lua does not call the message handler.\n</li>\n\n<li><b><a name=\"pdf-LUA_ERRERR\"><code>LUA_ERRERR</code></a>: </b>\nerror while running the message handler.\n</li>\n\n<li><b><a name=\"pdf-LUA_ERRGCMM\"><code>LUA_ERRGCMM</code></a>: </b>\nerror while running a <code>__gc</code> metamethod.\nFor such errors, Lua does not call the message handler\n(as this kind of error typically has no relation\nwith the function being called).\n</li>\n\n</ul>\n\n\n\n\n<hr><h3><a name=\"lua_pcallk\"><code>lua_pcallk</code></a></h3><p>\n<span class=\"apii\">[-(nargs + 1), +(nresults|1), &ndash;]</span>\n<pre>int lua_pcallk (lua_State *L,\n                int nargs,\n                int nresults,\n                int msgh,\n                lua_KContext ctx,\n                lua_KFunction k);</pre>\n\n<p>\nThis function behaves exactly like <a href=\"#lua_pcall\"><code>lua_pcall</code></a>,\nbut allows the called function to yield (see <a href=\"#4.7\">&sect;4.7</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_pop\"><code>lua_pop</code></a></h3><p>\n<span class=\"apii\">[-n, +0, &ndash;]</span>\n<pre>void lua_pop (lua_State *L, int n);</pre>\n\n<p>\nPops <code>n</code> elements from the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushboolean\"><code>lua_pushboolean</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushboolean (lua_State *L, int b);</pre>\n\n<p>\nPushes a boolean value with value <code>b</code> onto the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushcclosure\"><code>lua_pushcclosure</code></a></h3><p>\n<span class=\"apii\">[-n, +1, <em>m</em>]</span>\n<pre>void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);</pre>\n\n<p>\nPushes a new C&nbsp;closure onto the stack.\n\n\n<p>\nWhen a C&nbsp;function is created,\nit is possible to associate some values with it,\nthus creating a C&nbsp;closure (see <a href=\"#4.4\">&sect;4.4</a>);\nthese values are then accessible to the function whenever it is called.\nTo associate values with a C&nbsp;function,\nfirst these values must be pushed onto the stack\n(when there are multiple values, the first value is pushed first).\nThen <a href=\"#lua_pushcclosure\"><code>lua_pushcclosure</code></a>\nis called to create and push the C&nbsp;function onto the stack,\nwith the argument <code>n</code> telling how many values will be\nassociated with the function.\n<a href=\"#lua_pushcclosure\"><code>lua_pushcclosure</code></a> also pops these values from the stack.\n\n\n<p>\nThe maximum value for <code>n</code> is 255.\n\n\n<p>\nWhen <code>n</code> is zero,\nthis function creates a <em>light C&nbsp;function</em>,\nwhich is just a pointer to the C&nbsp;function.\nIn that case, it never raises a memory error.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushcfunction\"><code>lua_pushcfunction</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushcfunction (lua_State *L, lua_CFunction f);</pre>\n\n<p>\nPushes a C&nbsp;function onto the stack.\nThis function receives a pointer to a C&nbsp;function\nand pushes onto the stack a Lua value of type <code>function</code> that,\nwhen called, invokes the corresponding C&nbsp;function.\n\n\n<p>\nAny function to be callable by Lua must\nfollow the correct protocol to receive its parameters\nand return its results (see <a href=\"#lua_CFunction\"><code>lua_CFunction</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_pushfstring\"><code>lua_pushfstring</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>const char *lua_pushfstring (lua_State *L, const char *fmt, ...);</pre>\n\n<p>\nPushes onto the stack a formatted string\nand returns a pointer to this string.\nIt is similar to the ISO&nbsp;C function <code>sprintf</code>,\nbut has some important differences:\n\n<ul>\n\n<li>\nYou do not have to allocate space for the result:\nthe result is a Lua string and Lua takes care of memory allocation\n(and deallocation, through garbage collection).\n</li>\n\n<li>\nThe conversion specifiers are quite restricted.\nThere are no flags, widths, or precisions.\nThe conversion specifiers can only be\n'<code>%%</code>' (inserts the character '<code>%</code>'),\n'<code>%s</code>' (inserts a zero-terminated string, with no size restrictions),\n'<code>%f</code>' (inserts a <a href=\"#lua_Number\"><code>lua_Number</code></a>),\n'<code>%I</code>' (inserts a <a href=\"#lua_Integer\"><code>lua_Integer</code></a>),\n'<code>%p</code>' (inserts a pointer as a hexadecimal numeral),\n'<code>%d</code>' (inserts an <code>int</code>),\n'<code>%c</code>' (inserts an <code>int</code> as a one-byte character), and\n'<code>%U</code>' (inserts a <code>long int</code> as a UTF-8 byte sequence).\n</li>\n\n</ul>\n\n<p>\nUnlike other push functions,\nthis function checks for the stack space it needs,\nincluding the slot for its result.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushglobaltable\"><code>lua_pushglobaltable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushglobaltable (lua_State *L);</pre>\n\n<p>\nPushes the global environment onto the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushinteger\"><code>lua_pushinteger</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushinteger (lua_State *L, lua_Integer n);</pre>\n\n<p>\nPushes an integer with value <code>n</code> onto the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushlightuserdata\"><code>lua_pushlightuserdata</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushlightuserdata (lua_State *L, void *p);</pre>\n\n<p>\nPushes a light userdata onto the stack.\n\n\n<p>\nUserdata represent C&nbsp;values in Lua.\nA <em>light userdata</em> represents a pointer, a <code>void*</code>.\nIt is a value (like a number):\nyou do not create it, it has no individual metatable,\nand it is not collected (as it was never created).\nA light userdata is equal to \"any\"\nlight userdata with the same C&nbsp;address.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushliteral\"><code>lua_pushliteral</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>const char *lua_pushliteral (lua_State *L, const char *s);</pre>\n\n<p>\nThis macro is equivalent to <a href=\"#lua_pushstring\"><code>lua_pushstring</code></a>,\nbut should be used only when <code>s</code> is a literal string.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushlstring\"><code>lua_pushlstring</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>const char *lua_pushlstring (lua_State *L, const char *s, size_t len);</pre>\n\n<p>\nPushes the string pointed to by <code>s</code> with size <code>len</code>\nonto the stack.\nLua makes (or reuses) an internal copy of the given string,\nso the memory at <code>s</code> can be freed or reused immediately after\nthe function returns.\nThe string can contain any binary data,\nincluding embedded zeros.\n\n\n<p>\nReturns a pointer to the internal copy of the string.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushnil\"><code>lua_pushnil</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushnil (lua_State *L);</pre>\n\n<p>\nPushes a nil value onto the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushnumber\"><code>lua_pushnumber</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushnumber (lua_State *L, lua_Number n);</pre>\n\n<p>\nPushes a float with value <code>n</code> onto the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushstring\"><code>lua_pushstring</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>const char *lua_pushstring (lua_State *L, const char *s);</pre>\n\n<p>\nPushes the zero-terminated string pointed to by <code>s</code>\nonto the stack.\nLua makes (or reuses) an internal copy of the given string,\nso the memory at <code>s</code> can be freed or reused immediately after\nthe function returns.\n\n\n<p>\nReturns a pointer to the internal copy of the string.\n\n\n<p>\nIf <code>s</code> is <code>NULL</code>, pushes <b>nil</b> and returns <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushthread\"><code>lua_pushthread</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int lua_pushthread (lua_State *L);</pre>\n\n<p>\nPushes the thread represented by <code>L</code> onto the stack.\nReturns 1 if this thread is the main thread of its state.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushvalue\"><code>lua_pushvalue</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>void lua_pushvalue (lua_State *L, int index);</pre>\n\n<p>\nPushes a copy of the element at the given index\nonto the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_pushvfstring\"><code>lua_pushvfstring</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>const char *lua_pushvfstring (lua_State *L,\n                              const char *fmt,\n                              va_list argp);</pre>\n\n<p>\nEquivalent to <a href=\"#lua_pushfstring\"><code>lua_pushfstring</code></a>, except that it receives a <code>va_list</code>\ninstead of a variable number of arguments.\n\n\n\n\n\n<hr><h3><a name=\"lua_rawequal\"><code>lua_rawequal</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_rawequal (lua_State *L, int index1, int index2);</pre>\n\n<p>\nReturns 1 if the two values in indices <code>index1</code> and\n<code>index2</code> are primitively equal\n(that is, without calling the <code>__eq</code> metamethod).\nOtherwise returns&nbsp;0.\nAlso returns&nbsp;0 if any of the indices are not valid.\n\n\n\n\n\n<hr><h3><a name=\"lua_rawget\"><code>lua_rawget</code></a></h3><p>\n<span class=\"apii\">[-1, +1, &ndash;]</span>\n<pre>int lua_rawget (lua_State *L, int index);</pre>\n\n<p>\nSimilar to <a href=\"#lua_gettable\"><code>lua_gettable</code></a>, but does a raw access\n(i.e., without metamethods).\n\n\n\n\n\n<hr><h3><a name=\"lua_rawgeti\"><code>lua_rawgeti</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int lua_rawgeti (lua_State *L, int index, lua_Integer n);</pre>\n\n<p>\nPushes onto the stack the value <code>t[n]</code>,\nwhere <code>t</code> is the table at the given index.\nThe access is raw,\nthat is, it does not invoke the <code>__index</code> metamethod.\n\n\n<p>\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"lua_rawgetp\"><code>lua_rawgetp</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int lua_rawgetp (lua_State *L, int index, const void *p);</pre>\n\n<p>\nPushes onto the stack the value <code>t[k]</code>,\nwhere <code>t</code> is the table at the given index and\n<code>k</code> is the pointer <code>p</code> represented as a light userdata.\nThe access is raw;\nthat is, it does not invoke the <code>__index</code> metamethod.\n\n\n<p>\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"lua_rawlen\"><code>lua_rawlen</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>size_t lua_rawlen (lua_State *L, int index);</pre>\n\n<p>\nReturns the raw \"length\" of the value at the given index:\nfor strings, this is the string length;\nfor tables, this is the result of the length operator ('<code>#</code>')\nwith no metamethods;\nfor userdata, this is the size of the block of memory allocated\nfor the userdata;\nfor other values, it is&nbsp;0.\n\n\n\n\n\n<hr><h3><a name=\"lua_rawset\"><code>lua_rawset</code></a></h3><p>\n<span class=\"apii\">[-2, +0, <em>m</em>]</span>\n<pre>void lua_rawset (lua_State *L, int index);</pre>\n\n<p>\nSimilar to <a href=\"#lua_settable\"><code>lua_settable</code></a>, but does a raw assignment\n(i.e., without metamethods).\n\n\n\n\n\n<hr><h3><a name=\"lua_rawseti\"><code>lua_rawseti</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>m</em>]</span>\n<pre>void lua_rawseti (lua_State *L, int index, lua_Integer i);</pre>\n\n<p>\nDoes the equivalent of <code>t[i] = v</code>,\nwhere <code>t</code> is the table at the given index\nand <code>v</code> is the value at the top of the stack.\n\n\n<p>\nThis function pops the value from the stack.\nThe assignment is raw,\nthat is, it does not invoke the <code>__newindex</code> metamethod.\n\n\n\n\n\n<hr><h3><a name=\"lua_rawsetp\"><code>lua_rawsetp</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>m</em>]</span>\n<pre>void lua_rawsetp (lua_State *L, int index, const void *p);</pre>\n\n<p>\nDoes the equivalent of <code>t[p] = v</code>,\nwhere <code>t</code> is the table at the given index,\n<code>p</code> is encoded as a light userdata,\nand <code>v</code> is the value at the top of the stack.\n\n\n<p>\nThis function pops the value from the stack.\nThe assignment is raw,\nthat is, it does not invoke <code>__newindex</code> metamethod.\n\n\n\n\n\n<hr><h3><a name=\"lua_Reader\"><code>lua_Reader</code></a></h3>\n<pre>typedef const char * (*lua_Reader) (lua_State *L,\n                                    void *data,\n                                    size_t *size);</pre>\n\n<p>\nThe reader function used by <a href=\"#lua_load\"><code>lua_load</code></a>.\nEvery time it needs another piece of the chunk,\n<a href=\"#lua_load\"><code>lua_load</code></a> calls the reader,\npassing along its <code>data</code> parameter.\nThe reader must return a pointer to a block of memory\nwith a new piece of the chunk\nand set <code>size</code> to the block size.\nThe block must exist until the reader function is called again.\nTo signal the end of the chunk,\nthe reader must return <code>NULL</code> or set <code>size</code> to zero.\nThe reader function may return pieces of any size greater than zero.\n\n\n\n\n\n<hr><h3><a name=\"lua_register\"><code>lua_register</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>e</em>]</span>\n<pre>void lua_register (lua_State *L, const char *name, lua_CFunction f);</pre>\n\n<p>\nSets the C&nbsp;function <code>f</code> as the new value of global <code>name</code>.\nIt is defined as a macro:\n\n<pre>\n     #define lua_register(L,n,f) \\\n            (lua_pushcfunction(L, f), lua_setglobal(L, n))\n</pre>\n\n\n\n\n<hr><h3><a name=\"lua_remove\"><code>lua_remove</code></a></h3><p>\n<span class=\"apii\">[-1, +0, &ndash;]</span>\n<pre>void lua_remove (lua_State *L, int index);</pre>\n\n<p>\nRemoves the element at the given valid index,\nshifting down the elements above this index to fill the gap.\nThis function cannot be called with a pseudo-index,\nbecause a pseudo-index is not an actual stack position.\n\n\n\n\n\n<hr><h3><a name=\"lua_replace\"><code>lua_replace</code></a></h3><p>\n<span class=\"apii\">[-1, +0, &ndash;]</span>\n<pre>void lua_replace (lua_State *L, int index);</pre>\n\n<p>\nMoves the top element into the given valid index\nwithout shifting any element\n(therefore replacing the value at that given index),\nand then pops the top element.\n\n\n\n\n\n<hr><h3><a name=\"lua_resume\"><code>lua_resume</code></a></h3><p>\n<span class=\"apii\">[-?, +?, &ndash;]</span>\n<pre>int lua_resume (lua_State *L, lua_State *from, int nargs);</pre>\n\n<p>\nStarts and resumes a coroutine in the given thread <code>L</code>.\n\n\n<p>\nTo start a coroutine,\nyou push onto the thread stack the main function plus any arguments;\nthen you call <a href=\"#lua_resume\"><code>lua_resume</code></a>,\nwith <code>nargs</code> being the number of arguments.\nThis call returns when the coroutine suspends or finishes its execution.\nWhen it returns, the stack contains all values passed to <a href=\"#lua_yield\"><code>lua_yield</code></a>,\nor all values returned by the body function.\n<a href=\"#lua_resume\"><code>lua_resume</code></a> returns\n<a href=\"#pdf-LUA_YIELD\"><code>LUA_YIELD</code></a> if the coroutine yields,\n<a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a> if the coroutine finishes its execution\nwithout errors,\nor an error code in case of errors (see <a href=\"#lua_pcall\"><code>lua_pcall</code></a>).\n\n\n<p>\nIn case of errors,\nthe stack is not unwound,\nso you can use the debug API over it.\nThe error object is on the top of the stack.\n\n\n<p>\nTo resume a coroutine,\nyou remove any results from the last <a href=\"#lua_yield\"><code>lua_yield</code></a>,\nput on its stack only the values to\nbe passed as results from <code>yield</code>,\nand then call <a href=\"#lua_resume\"><code>lua_resume</code></a>.\n\n\n<p>\nThe parameter <code>from</code> represents the coroutine that is resuming <code>L</code>.\nIf there is no such coroutine,\nthis parameter can be <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_rotate\"><code>lua_rotate</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void lua_rotate (lua_State *L, int idx, int n);</pre>\n\n<p>\nRotates the stack elements between the valid index <code>idx</code>\nand the top of the stack.\nThe elements are rotated <code>n</code> positions in the direction of the top,\nfor a positive <code>n</code>,\nor <code>-n</code> positions in the direction of the bottom,\nfor a negative <code>n</code>.\nThe absolute value of <code>n</code> must not be greater than the size\nof the slice being rotated.\nThis function cannot be called with a pseudo-index,\nbecause a pseudo-index is not an actual stack position.\n\n\n\n\n\n<hr><h3><a name=\"lua_setallocf\"><code>lua_setallocf</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);</pre>\n\n<p>\nChanges the allocator function of a given state to <code>f</code>\nwith user data <code>ud</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_setfield\"><code>lua_setfield</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>e</em>]</span>\n<pre>void lua_setfield (lua_State *L, int index, const char *k);</pre>\n\n<p>\nDoes the equivalent to <code>t[k] = v</code>,\nwhere <code>t</code> is the value at the given index\nand <code>v</code> is the value at the top of the stack.\n\n\n<p>\nThis function pops the value from the stack.\nAs in Lua, this function may trigger a metamethod\nfor the \"newindex\" event (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_setglobal\"><code>lua_setglobal</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>e</em>]</span>\n<pre>void lua_setglobal (lua_State *L, const char *name);</pre>\n\n<p>\nPops a value from the stack and\nsets it as the new value of global <code>name</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_seti\"><code>lua_seti</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>e</em>]</span>\n<pre>void lua_seti (lua_State *L, int index, lua_Integer n);</pre>\n\n<p>\nDoes the equivalent to <code>t[n] = v</code>,\nwhere <code>t</code> is the value at the given index\nand <code>v</code> is the value at the top of the stack.\n\n\n<p>\nThis function pops the value from the stack.\nAs in Lua, this function may trigger a metamethod\nfor the \"newindex\" event (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_setmetatable\"><code>lua_setmetatable</code></a></h3><p>\n<span class=\"apii\">[-1, +0, &ndash;]</span>\n<pre>void lua_setmetatable (lua_State *L, int index);</pre>\n\n<p>\nPops a table from the stack and\nsets it as the new metatable for the value at the given index.\n\n\n\n\n\n<hr><h3><a name=\"lua_settable\"><code>lua_settable</code></a></h3><p>\n<span class=\"apii\">[-2, +0, <em>e</em>]</span>\n<pre>void lua_settable (lua_State *L, int index);</pre>\n\n<p>\nDoes the equivalent to <code>t[k] = v</code>,\nwhere <code>t</code> is the value at the given index,\n<code>v</code> is the value at the top of the stack,\nand <code>k</code> is the value just below the top.\n\n\n<p>\nThis function pops both the key and the value from the stack.\nAs in Lua, this function may trigger a metamethod\nfor the \"newindex\" event (see <a href=\"#2.4\">&sect;2.4</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_settop\"><code>lua_settop</code></a></h3><p>\n<span class=\"apii\">[-?, +?, &ndash;]</span>\n<pre>void lua_settop (lua_State *L, int index);</pre>\n\n<p>\nAccepts any index, or&nbsp;0,\nand sets the stack top to this index.\nIf the new top is larger than the old one,\nthen the new elements are filled with <b>nil</b>.\nIf <code>index</code> is&nbsp;0, then all stack elements are removed.\n\n\n\n\n\n<hr><h3><a name=\"lua_setuservalue\"><code>lua_setuservalue</code></a></h3><p>\n<span class=\"apii\">[-1, +0, &ndash;]</span>\n<pre>void lua_setuservalue (lua_State *L, int index);</pre>\n\n<p>\nPops a value from the stack and sets it as\nthe new value associated to the full userdata at the given index.\n\n\n\n\n\n<hr><h3><a name=\"lua_State\"><code>lua_State</code></a></h3>\n<pre>typedef struct lua_State lua_State;</pre>\n\n<p>\nAn opaque structure that points to a thread and indirectly\n(through the thread) to the whole state of a Lua interpreter.\nThe Lua library is fully reentrant:\nit has no global variables.\nAll information about a state is accessible through this structure.\n\n\n<p>\nA pointer to this structure must be passed as the first argument to\nevery function in the library, except to <a href=\"#lua_newstate\"><code>lua_newstate</code></a>,\nwhich creates a Lua state from scratch.\n\n\n\n\n\n<hr><h3><a name=\"lua_status\"><code>lua_status</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_status (lua_State *L);</pre>\n\n<p>\nReturns the status of the thread <code>L</code>.\n\n\n<p>\nThe status can be 0 (<a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a>) for a normal thread,\nan error code if the thread finished the execution\nof a <a href=\"#lua_resume\"><code>lua_resume</code></a> with an error,\nor <a name=\"pdf-LUA_YIELD\"><code>LUA_YIELD</code></a> if the thread is suspended.\n\n\n<p>\nYou can only call functions in threads with status <a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a>.\nYou can resume threads with status <a href=\"#pdf-LUA_OK\"><code>LUA_OK</code></a>\n(to start a new coroutine) or <a href=\"#pdf-LUA_YIELD\"><code>LUA_YIELD</code></a>\n(to resume a coroutine).\n\n\n\n\n\n<hr><h3><a name=\"lua_stringtonumber\"><code>lua_stringtonumber</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>size_t lua_stringtonumber (lua_State *L, const char *s);</pre>\n\n<p>\nConverts the zero-terminated string <code>s</code> to a number,\npushes that number into the stack,\nand returns the total size of the string,\nthat is, its length plus one.\nThe conversion can result in an integer or a float,\naccording to the lexical conventions of Lua (see <a href=\"#3.1\">&sect;3.1</a>).\nThe string may have leading and trailing spaces and a sign.\nIf the string is not a valid numeral,\nreturns 0 and pushes nothing.\n(Note that the result can be used as a boolean,\ntrue if the conversion succeeds.)\n\n\n\n\n\n<hr><h3><a name=\"lua_toboolean\"><code>lua_toboolean</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_toboolean (lua_State *L, int index);</pre>\n\n<p>\nConverts the Lua value at the given index to a C&nbsp;boolean\nvalue (0&nbsp;or&nbsp;1).\nLike all tests in Lua,\n<a href=\"#lua_toboolean\"><code>lua_toboolean</code></a> returns true for any Lua value\ndifferent from <b>false</b> and <b>nil</b>;\notherwise it returns false.\n(If you want to accept only actual boolean values,\nuse <a href=\"#lua_isboolean\"><code>lua_isboolean</code></a> to test the value's type.)\n\n\n\n\n\n<hr><h3><a name=\"lua_tocfunction\"><code>lua_tocfunction</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_CFunction lua_tocfunction (lua_State *L, int index);</pre>\n\n<p>\nConverts a value at the given index to a C&nbsp;function.\nThat value must be a C&nbsp;function;\notherwise, returns <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_tointeger\"><code>lua_tointeger</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_Integer lua_tointeger (lua_State *L, int index);</pre>\n\n<p>\nEquivalent to <a href=\"#lua_tointegerx\"><code>lua_tointegerx</code></a> with <code>isnum</code> equal to <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_tointegerx\"><code>lua_tointegerx</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);</pre>\n\n<p>\nConverts the Lua value at the given index\nto the signed integral type <a href=\"#lua_Integer\"><code>lua_Integer</code></a>.\nThe Lua value must be an integer,\nor a number or string convertible to an integer (see <a href=\"#3.4.3\">&sect;3.4.3</a>);\notherwise, <code>lua_tointegerx</code> returns&nbsp;0.\n\n\n<p>\nIf <code>isnum</code> is not <code>NULL</code>,\nits referent is assigned a boolean value that\nindicates whether the operation succeeded.\n\n\n\n\n\n<hr><h3><a name=\"lua_tolstring\"><code>lua_tolstring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>m</em>]</span>\n<pre>const char *lua_tolstring (lua_State *L, int index, size_t *len);</pre>\n\n<p>\nConverts the Lua value at the given index to a C&nbsp;string.\nIf <code>len</code> is not <code>NULL</code>,\nit sets <code>*len</code> with the string length.\nThe Lua value must be a string or a number;\notherwise, the function returns <code>NULL</code>.\nIf the value is a number,\nthen <code>lua_tolstring</code> also\n<em>changes the actual value in the stack to a string</em>.\n(This change confuses <a href=\"#lua_next\"><code>lua_next</code></a>\nwhen <code>lua_tolstring</code> is applied to keys during a table traversal.)\n\n\n<p>\n<code>lua_tolstring</code> returns a pointer\nto a string inside the Lua state.\nThis string always has a zero ('<code>\\0</code>')\nafter its last character (as in&nbsp;C),\nbut can contain other zeros in its body.\n\n\n<p>\nBecause Lua has garbage collection,\nthere is no guarantee that the pointer returned by <code>lua_tolstring</code>\nwill be valid after the corresponding Lua value is removed from the stack.\n\n\n\n\n\n<hr><h3><a name=\"lua_tonumber\"><code>lua_tonumber</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_Number lua_tonumber (lua_State *L, int index);</pre>\n\n<p>\nEquivalent to <a href=\"#lua_tonumberx\"><code>lua_tonumberx</code></a> with <code>isnum</code> equal to <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_tonumberx\"><code>lua_tonumberx</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);</pre>\n\n<p>\nConverts the Lua value at the given index\nto the C&nbsp;type <a href=\"#lua_Number\"><code>lua_Number</code></a> (see <a href=\"#lua_Number\"><code>lua_Number</code></a>).\nThe Lua value must be a number or a string convertible to a number\n(see <a href=\"#3.4.3\">&sect;3.4.3</a>);\notherwise, <a href=\"#lua_tonumberx\"><code>lua_tonumberx</code></a> returns&nbsp;0.\n\n\n<p>\nIf <code>isnum</code> is not <code>NULL</code>,\nits referent is assigned a boolean value that\nindicates whether the operation succeeded.\n\n\n\n\n\n<hr><h3><a name=\"lua_topointer\"><code>lua_topointer</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>const void *lua_topointer (lua_State *L, int index);</pre>\n\n<p>\nConverts the value at the given index to a generic\nC&nbsp;pointer (<code>void*</code>).\nThe value can be a userdata, a table, a thread, or a function;\notherwise, <code>lua_topointer</code> returns <code>NULL</code>.\nDifferent objects will give different pointers.\nThere is no way to convert the pointer back to its original value.\n\n\n<p>\nTypically this function is used only for hashing and debug information.\n\n\n\n\n\n<hr><h3><a name=\"lua_tostring\"><code>lua_tostring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>m</em>]</span>\n<pre>const char *lua_tostring (lua_State *L, int index);</pre>\n\n<p>\nEquivalent to <a href=\"#lua_tolstring\"><code>lua_tolstring</code></a> with <code>len</code> equal to <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_tothread\"><code>lua_tothread</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_State *lua_tothread (lua_State *L, int index);</pre>\n\n<p>\nConverts the value at the given index to a Lua thread\n(represented as <code>lua_State*</code>).\nThis value must be a thread;\notherwise, the function returns <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_touserdata\"><code>lua_touserdata</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void *lua_touserdata (lua_State *L, int index);</pre>\n\n<p>\nIf the value at the given index is a full userdata,\nreturns its block address.\nIf the value is a light userdata,\nreturns its pointer.\nOtherwise, returns <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_type\"><code>lua_type</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_type (lua_State *L, int index);</pre>\n\n<p>\nReturns the type of the value in the given valid index,\nor <code>LUA_TNONE</code> for a non-valid (but acceptable) index.\nThe types returned by <a href=\"#lua_type\"><code>lua_type</code></a> are coded by the following constants\ndefined in <code>lua.h</code>:\n<a name=\"pdf-LUA_TNIL\"><code>LUA_TNIL</code></a> (0),\n<a name=\"pdf-LUA_TNUMBER\"><code>LUA_TNUMBER</code></a>,\n<a name=\"pdf-LUA_TBOOLEAN\"><code>LUA_TBOOLEAN</code></a>,\n<a name=\"pdf-LUA_TSTRING\"><code>LUA_TSTRING</code></a>,\n<a name=\"pdf-LUA_TTABLE\"><code>LUA_TTABLE</code></a>,\n<a name=\"pdf-LUA_TFUNCTION\"><code>LUA_TFUNCTION</code></a>,\n<a name=\"pdf-LUA_TUSERDATA\"><code>LUA_TUSERDATA</code></a>,\n<a name=\"pdf-LUA_TTHREAD\"><code>LUA_TTHREAD</code></a>,\nand\n<a name=\"pdf-LUA_TLIGHTUSERDATA\"><code>LUA_TLIGHTUSERDATA</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_typename\"><code>lua_typename</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>const char *lua_typename (lua_State *L, int tp);</pre>\n\n<p>\nReturns the name of the type encoded by the value <code>tp</code>,\nwhich must be one the values returned by <a href=\"#lua_type\"><code>lua_type</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_Unsigned\"><code>lua_Unsigned</code></a></h3>\n<pre>typedef ... lua_Unsigned;</pre>\n\n<p>\nThe unsigned version of <a href=\"#lua_Integer\"><code>lua_Integer</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_upvalueindex\"><code>lua_upvalueindex</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_upvalueindex (int i);</pre>\n\n<p>\nReturns the pseudo-index that represents the <code>i</code>-th upvalue of\nthe running function (see <a href=\"#4.4\">&sect;4.4</a>).\n\n\n\n\n\n<hr><h3><a name=\"lua_version\"><code>lua_version</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>const lua_Number *lua_version (lua_State *L);</pre>\n\n<p>\nReturns the address of the version number\n(a C static variable)\nstored in the Lua core.\nWhen called with a valid <a href=\"#lua_State\"><code>lua_State</code></a>,\nreturns the address of the version used to create that state.\nWhen called with <code>NULL</code>,\nreturns the address of the version running the call.\n\n\n\n\n\n<hr><h3><a name=\"lua_Writer\"><code>lua_Writer</code></a></h3>\n<pre>typedef int (*lua_Writer) (lua_State *L,\n                           const void* p,\n                           size_t sz,\n                           void* ud);</pre>\n\n<p>\nThe type of the writer function used by <a href=\"#lua_dump\"><code>lua_dump</code></a>.\nEvery time it produces another piece of chunk,\n<a href=\"#lua_dump\"><code>lua_dump</code></a> calls the writer,\npassing along the buffer to be written (<code>p</code>),\nits size (<code>sz</code>),\nand the <code>data</code> parameter supplied to <a href=\"#lua_dump\"><code>lua_dump</code></a>.\n\n\n<p>\nThe writer returns an error code:\n0&nbsp;means no errors;\nany other value means an error and stops <a href=\"#lua_dump\"><code>lua_dump</code></a> from\ncalling the writer again.\n\n\n\n\n\n<hr><h3><a name=\"lua_xmove\"><code>lua_xmove</code></a></h3><p>\n<span class=\"apii\">[-?, +?, &ndash;]</span>\n<pre>void lua_xmove (lua_State *from, lua_State *to, int n);</pre>\n\n<p>\nExchange values between different threads of the same state.\n\n\n<p>\nThis function pops <code>n</code> values from the stack <code>from</code>,\nand pushes them onto the stack <code>to</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_yield\"><code>lua_yield</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>e</em>]</span>\n<pre>int lua_yield (lua_State *L, int nresults);</pre>\n\n<p>\nThis function is equivalent to <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>,\nbut it has no continuation (see <a href=\"#4.7\">&sect;4.7</a>).\nTherefore, when the thread resumes,\nit continues the function that called\nthe function calling <code>lua_yield</code>.\n\n\n\n\n\n<hr><h3><a name=\"lua_yieldk\"><code>lua_yieldk</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>e</em>]</span>\n<pre>int lua_yieldk (lua_State *L,\n                int nresults,\n                lua_KContext ctx,\n                lua_KFunction k);</pre>\n\n<p>\nYields a coroutine (thread).\n\n\n<p>\nWhen a C&nbsp;function calls <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>,\nthe running coroutine suspends its execution,\nand the call to <a href=\"#lua_resume\"><code>lua_resume</code></a> that started this coroutine returns.\nThe parameter <code>nresults</code> is the number of values from the stack\nthat will be passed as results to <a href=\"#lua_resume\"><code>lua_resume</code></a>.\n\n\n<p>\nWhen the coroutine is resumed again,\nLua calls the given continuation function <code>k</code> to continue\nthe execution of the C&nbsp;function that yielded (see <a href=\"#4.7\">&sect;4.7</a>).\nThis continuation function receives the same stack\nfrom the previous function,\nwith the <code>n</code> results removed and\nreplaced by the arguments passed to <a href=\"#lua_resume\"><code>lua_resume</code></a>.\nMoreover,\nthe continuation function receives the value <code>ctx</code>\nthat was passed to <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>.\n\n\n<p>\nUsually, this function does not return;\nwhen the coroutine eventually resumes,\nit continues executing the continuation function.\nHowever, there is one special case,\nwhich is when this function is called\nfrom inside a line or a count hook (see <a href=\"#4.9\">&sect;4.9</a>).\nIn that case, <code>lua_yieldk</code> should be called with no continuation\n(probably in the form of <a href=\"#lua_yield\"><code>lua_yield</code></a>) and no results,\nand the hook should return immediately after the call.\nLua will yield and,\nwhen the coroutine resumes again,\nit will continue the normal execution\nof the (Lua) function that triggered the hook.\n\n\n<p>\nThis function can raise an error if it is called from a thread\nwith a pending C call with no continuation function,\nor it is called from a thread that is not running inside a resume\n(e.g., the main thread).\n\n\n\n\n\n\n\n<h2>4.9 &ndash; <a name=\"4.9\">The Debug Interface</a></h2>\n\n<p>\nLua has no built-in debugging facilities.\nInstead, it offers a special interface\nby means of functions and <em>hooks</em>.\nThis interface allows the construction of different\nkinds of debuggers, profilers, and other tools\nthat need \"inside information\" from the interpreter.\n\n\n\n<hr><h3><a name=\"lua_Debug\"><code>lua_Debug</code></a></h3>\n<pre>typedef struct lua_Debug {\n  int event;\n  const char *name;           /* (n) */\n  const char *namewhat;       /* (n) */\n  const char *what;           /* (S) */\n  const char *source;         /* (S) */\n  int currentline;            /* (l) */\n  int linedefined;            /* (S) */\n  int lastlinedefined;        /* (S) */\n  unsigned char nups;         /* (u) number of upvalues */\n  unsigned char nparams;      /* (u) number of parameters */\n  char isvararg;              /* (u) */\n  char istailcall;            /* (t) */\n  char short_src[LUA_IDSIZE]; /* (S) */\n  /* private part */\n  <em>other fields</em>\n} lua_Debug;</pre>\n\n<p>\nA structure used to carry different pieces of\ninformation about a function or an activation record.\n<a href=\"#lua_getstack\"><code>lua_getstack</code></a> fills only the private part\nof this structure, for later use.\nTo fill the other fields of <a href=\"#lua_Debug\"><code>lua_Debug</code></a> with useful information,\ncall <a href=\"#lua_getinfo\"><code>lua_getinfo</code></a>.\n\n\n<p>\nThe fields of <a href=\"#lua_Debug\"><code>lua_Debug</code></a> have the following meaning:\n\n<ul>\n\n<li><b><code>source</code>: </b>\nthe name of the chunk that created the function.\nIf <code>source</code> starts with a '<code>@</code>',\nit means that the function was defined in a file where\nthe file name follows the '<code>@</code>'.\nIf <code>source</code> starts with a '<code>=</code>',\nthe remainder of its contents describe the source in a user-dependent manner.\nOtherwise,\nthe function was defined in a string where\n<code>source</code> is that string.\n</li>\n\n<li><b><code>short_src</code>: </b>\na \"printable\" version of <code>source</code>, to be used in error messages.\n</li>\n\n<li><b><code>linedefined</code>: </b>\nthe line number where the definition of the function starts.\n</li>\n\n<li><b><code>lastlinedefined</code>: </b>\nthe line number where the definition of the function ends.\n</li>\n\n<li><b><code>what</code>: </b>\nthe string <code>\"Lua\"</code> if the function is a Lua function,\n<code>\"C\"</code> if it is a C&nbsp;function,\n<code>\"main\"</code> if it is the main part of a chunk.\n</li>\n\n<li><b><code>currentline</code>: </b>\nthe current line where the given function is executing.\nWhen no line information is available,\n<code>currentline</code> is set to -1.\n</li>\n\n<li><b><code>name</code>: </b>\na reasonable name for the given function.\nBecause functions in Lua are first-class values,\nthey do not have a fixed name:\nsome functions can be the value of multiple global variables,\nwhile others can be stored only in a table field.\nThe <code>lua_getinfo</code> function checks how the function was\ncalled to find a suitable name.\nIf it cannot find a name,\nthen <code>name</code> is set to <code>NULL</code>.\n</li>\n\n<li><b><code>namewhat</code>: </b>\nexplains the <code>name</code> field.\nThe value of <code>namewhat</code> can be\n<code>\"global\"</code>, <code>\"local\"</code>, <code>\"method\"</code>,\n<code>\"field\"</code>, <code>\"upvalue\"</code>, or <code>\"\"</code> (the empty string),\naccording to how the function was called.\n(Lua uses the empty string when no other option seems to apply.)\n</li>\n\n<li><b><code>istailcall</code>: </b>\ntrue if this function invocation was called by a tail call.\nIn this case, the caller of this level is not in the stack.\n</li>\n\n<li><b><code>nups</code>: </b>\nthe number of upvalues of the function.\n</li>\n\n<li><b><code>nparams</code>: </b>\nthe number of fixed parameters of the function\n(always 0&nbsp;for C&nbsp;functions).\n</li>\n\n<li><b><code>isvararg</code>: </b>\ntrue if the function is a vararg function\n(always true for C&nbsp;functions).\n</li>\n\n</ul>\n\n\n\n\n<hr><h3><a name=\"lua_gethook\"><code>lua_gethook</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_Hook lua_gethook (lua_State *L);</pre>\n\n<p>\nReturns the current hook function.\n\n\n\n\n\n<hr><h3><a name=\"lua_gethookcount\"><code>lua_gethookcount</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_gethookcount (lua_State *L);</pre>\n\n<p>\nReturns the current hook count.\n\n\n\n\n\n<hr><h3><a name=\"lua_gethookmask\"><code>lua_gethookmask</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_gethookmask (lua_State *L);</pre>\n\n<p>\nReturns the current hook mask.\n\n\n\n\n\n<hr><h3><a name=\"lua_getinfo\"><code>lua_getinfo</code></a></h3><p>\n<span class=\"apii\">[-(0|1), +(0|1|2), <em>e</em>]</span>\n<pre>int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);</pre>\n\n<p>\nGets information about a specific function or function invocation.\n\n\n<p>\nTo get information about a function invocation,\nthe parameter <code>ar</code> must be a valid activation record that was\nfilled by a previous call to <a href=\"#lua_getstack\"><code>lua_getstack</code></a> or\ngiven as argument to a hook (see <a href=\"#lua_Hook\"><code>lua_Hook</code></a>).\n\n\n<p>\nTo get information about a function, you push it onto the stack\nand start the <code>what</code> string with the character '<code>&gt;</code>'.\n(In that case,\n<code>lua_getinfo</code> pops the function from the top of the stack.)\nFor instance, to know in which line a function <code>f</code> was defined,\nyou can write the following code:\n\n<pre>\n     lua_Debug ar;\n     lua_getglobal(L, \"f\");  /* get global 'f' */\n     lua_getinfo(L, \"&gt;S\", &amp;ar);\n     printf(\"%d\\n\", ar.linedefined);\n</pre>\n\n<p>\nEach character in the string <code>what</code>\nselects some fields of the structure <code>ar</code> to be filled or\na value to be pushed on the stack:\n\n<ul>\n\n<li><b>'<code>n</code>': </b> fills in the field <code>name</code> and <code>namewhat</code>;\n</li>\n\n<li><b>'<code>S</code>': </b>\nfills in the fields <code>source</code>, <code>short_src</code>,\n<code>linedefined</code>, <code>lastlinedefined</code>, and <code>what</code>;\n</li>\n\n<li><b>'<code>l</code>': </b> fills in the field <code>currentline</code>;\n</li>\n\n<li><b>'<code>t</code>': </b> fills in the field <code>istailcall</code>;\n</li>\n\n<li><b>'<code>u</code>': </b> fills in the fields\n<code>nups</code>, <code>nparams</code>, and <code>isvararg</code>;\n</li>\n\n<li><b>'<code>f</code>': </b>\npushes onto the stack the function that is\nrunning at the given level;\n</li>\n\n<li><b>'<code>L</code>': </b>\npushes onto the stack a table whose indices are the\nnumbers of the lines that are valid on the function.\n(A <em>valid line</em> is a line with some associated code,\nthat is, a line where you can put a break point.\nNon-valid lines include empty lines and comments.)\n\n\n<p>\nIf this option is given together with option '<code>f</code>',\nits table is pushed after the function.\n</li>\n\n</ul>\n\n<p>\nThis function returns 0 on error\n(for instance, an invalid option in <code>what</code>).\n\n\n\n\n\n<hr><h3><a name=\"lua_getlocal\"><code>lua_getlocal</code></a></h3><p>\n<span class=\"apii\">[-0, +(0|1), &ndash;]</span>\n<pre>const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);</pre>\n\n<p>\nGets information about a local variable of\na given activation record or a given function.\n\n\n<p>\nIn the first case,\nthe parameter <code>ar</code> must be a valid activation record that was\nfilled by a previous call to <a href=\"#lua_getstack\"><code>lua_getstack</code></a> or\ngiven as argument to a hook (see <a href=\"#lua_Hook\"><code>lua_Hook</code></a>).\nThe index <code>n</code> selects which local variable to inspect;\nsee <a href=\"#pdf-debug.getlocal\"><code>debug.getlocal</code></a> for details about variable indices\nand names.\n\n\n<p>\n<a href=\"#lua_getlocal\"><code>lua_getlocal</code></a> pushes the variable's value onto the stack\nand returns its name.\n\n\n<p>\nIn the second case, <code>ar</code> must be <code>NULL</code> and the function\nto be inspected must be at the top of the stack.\nIn this case, only parameters of Lua functions are visible\n(as there is no information about what variables are active)\nand no values are pushed onto the stack.\n\n\n<p>\nReturns <code>NULL</code> (and pushes nothing)\nwhen the index is greater than\nthe number of active local variables.\n\n\n\n\n\n<hr><h3><a name=\"lua_getstack\"><code>lua_getstack</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>int lua_getstack (lua_State *L, int level, lua_Debug *ar);</pre>\n\n<p>\nGets information about the interpreter runtime stack.\n\n\n<p>\nThis function fills parts of a <a href=\"#lua_Debug\"><code>lua_Debug</code></a> structure with\nan identification of the <em>activation record</em>\nof the function executing at a given level.\nLevel&nbsp;0 is the current running function,\nwhereas level <em>n+1</em> is the function that has called level <em>n</em>\n(except for tail calls, which do not count on the stack).\nWhen there are no errors, <a href=\"#lua_getstack\"><code>lua_getstack</code></a> returns 1;\nwhen called with a level greater than the stack depth,\nit returns 0.\n\n\n\n\n\n<hr><h3><a name=\"lua_getupvalue\"><code>lua_getupvalue</code></a></h3><p>\n<span class=\"apii\">[-0, +(0|1), &ndash;]</span>\n<pre>const char *lua_getupvalue (lua_State *L, int funcindex, int n);</pre>\n\n<p>\nGets information about the <code>n</code>-th upvalue\nof the closure at index <code>funcindex</code>.\nIt pushes the upvalue's value onto the stack\nand returns its name.\nReturns <code>NULL</code> (and pushes nothing)\nwhen the index <code>n</code> is greater than the number of upvalues.\n\n\n<p>\nFor C&nbsp;functions, this function uses the empty string <code>\"\"</code>\nas a name for all upvalues.\n(For Lua functions,\nupvalues are the external local variables that the function uses,\nand that are consequently included in its closure.)\n\n\n<p>\nUpvalues have no particular order,\nas they are active through the whole function.\nThey are numbered in an arbitrary order.\n\n\n\n\n\n<hr><h3><a name=\"lua_Hook\"><code>lua_Hook</code></a></h3>\n<pre>typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);</pre>\n\n<p>\nType for debugging hook functions.\n\n\n<p>\nWhenever a hook is called, its <code>ar</code> argument has its field\n<code>event</code> set to the specific event that triggered the hook.\nLua identifies these events with the following constants:\n<a name=\"pdf-LUA_HOOKCALL\"><code>LUA_HOOKCALL</code></a>, <a name=\"pdf-LUA_HOOKRET\"><code>LUA_HOOKRET</code></a>,\n<a name=\"pdf-LUA_HOOKTAILCALL\"><code>LUA_HOOKTAILCALL</code></a>, <a name=\"pdf-LUA_HOOKLINE\"><code>LUA_HOOKLINE</code></a>,\nand <a name=\"pdf-LUA_HOOKCOUNT\"><code>LUA_HOOKCOUNT</code></a>.\nMoreover, for line events, the field <code>currentline</code> is also set.\nTo get the value of any other field in <code>ar</code>,\nthe hook must call <a href=\"#lua_getinfo\"><code>lua_getinfo</code></a>.\n\n\n<p>\nFor call events, <code>event</code> can be <code>LUA_HOOKCALL</code>,\nthe normal value, or <code>LUA_HOOKTAILCALL</code>, for a tail call;\nin this case, there will be no corresponding return event.\n\n\n<p>\nWhile Lua is running a hook, it disables other calls to hooks.\nTherefore, if a hook calls back Lua to execute a function or a chunk,\nthis execution occurs without any calls to hooks.\n\n\n<p>\nHook functions cannot have continuations,\nthat is, they cannot call <a href=\"#lua_yieldk\"><code>lua_yieldk</code></a>,\n<a href=\"#lua_pcallk\"><code>lua_pcallk</code></a>, or <a href=\"#lua_callk\"><code>lua_callk</code></a> with a non-null <code>k</code>.\n\n\n<p>\nHook functions can yield under the following conditions:\nOnly count and line events can yield;\nto yield, a hook function must finish its execution\ncalling <a href=\"#lua_yield\"><code>lua_yield</code></a> with <code>nresults</code> equal to zero\n(that is, with no values).\n\n\n\n\n\n<hr><h3><a name=\"lua_sethook\"><code>lua_sethook</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre>\n\n<p>\nSets the debugging hook function.\n\n\n<p>\nArgument <code>f</code> is the hook function.\n<code>mask</code> specifies on which events the hook will be called:\nit is formed by a bitwise OR of the constants\n<a name=\"pdf-LUA_MASKCALL\"><code>LUA_MASKCALL</code></a>,\n<a name=\"pdf-LUA_MASKRET\"><code>LUA_MASKRET</code></a>,\n<a name=\"pdf-LUA_MASKLINE\"><code>LUA_MASKLINE</code></a>,\nand <a name=\"pdf-LUA_MASKCOUNT\"><code>LUA_MASKCOUNT</code></a>.\nThe <code>count</code> argument is only meaningful when the mask\nincludes <code>LUA_MASKCOUNT</code>.\nFor each event, the hook is called as explained below:\n\n<ul>\n\n<li><b>The call hook: </b> is called when the interpreter calls a function.\nThe hook is called just after Lua enters the new function,\nbefore the function gets its arguments.\n</li>\n\n<li><b>The return hook: </b> is called when the interpreter returns from a function.\nThe hook is called just before Lua leaves the function.\nThere is no standard way to access the values\nto be returned by the function.\n</li>\n\n<li><b>The line hook: </b> is called when the interpreter is about to\nstart the execution of a new line of code,\nor when it jumps back in the code (even to the same line).\n(This event only happens while Lua is executing a Lua function.)\n</li>\n\n<li><b>The count hook: </b> is called after the interpreter executes every\n<code>count</code> instructions.\n(This event only happens while Lua is executing a Lua function.)\n</li>\n\n</ul>\n\n<p>\nA hook is disabled by setting <code>mask</code> to zero.\n\n\n\n\n\n<hr><h3><a name=\"lua_setlocal\"><code>lua_setlocal</code></a></h3><p>\n<span class=\"apii\">[-(0|1), +0, &ndash;]</span>\n<pre>const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);</pre>\n\n<p>\nSets the value of a local variable of a given activation record.\nIt assigns the value at the top of the stack\nto the variable and returns its name.\nIt also pops the value from the stack.\n\n\n<p>\nReturns <code>NULL</code> (and pops nothing)\nwhen the index is greater than\nthe number of active local variables.\n\n\n<p>\nParameters <code>ar</code> and <code>n</code> are as in function <a href=\"#lua_getlocal\"><code>lua_getlocal</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_setupvalue\"><code>lua_setupvalue</code></a></h3><p>\n<span class=\"apii\">[-(0|1), +0, &ndash;]</span>\n<pre>const char *lua_setupvalue (lua_State *L, int funcindex, int n);</pre>\n\n<p>\nSets the value of a closure's upvalue.\nIt assigns the value at the top of the stack\nto the upvalue and returns its name.\nIt also pops the value from the stack.\n\n\n<p>\nReturns <code>NULL</code> (and pops nothing)\nwhen the index <code>n</code> is greater than the number of upvalues.\n\n\n<p>\nParameters <code>funcindex</code> and <code>n</code> are as in function <a href=\"#lua_getupvalue\"><code>lua_getupvalue</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"lua_upvalueid\"><code>lua_upvalueid</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void *lua_upvalueid (lua_State *L, int funcindex, int n);</pre>\n\n<p>\nReturns a unique identifier for the upvalue numbered <code>n</code>\nfrom the closure at index <code>funcindex</code>.\n\n\n<p>\nThese unique identifiers allow a program to check whether different\nclosures share upvalues.\nLua closures that share an upvalue\n(that is, that access a same external local variable)\nwill return identical ids for those upvalue indices.\n\n\n<p>\nParameters <code>funcindex</code> and <code>n</code> are as in function <a href=\"#lua_getupvalue\"><code>lua_getupvalue</code></a>,\nbut <code>n</code> cannot be greater than the number of upvalues.\n\n\n\n\n\n<hr><h3><a name=\"lua_upvaluejoin\"><code>lua_upvaluejoin</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,\n                                    int funcindex2, int n2);</pre>\n\n<p>\nMake the <code>n1</code>-th upvalue of the Lua closure at index <code>funcindex1</code>\nrefer to the <code>n2</code>-th upvalue of the Lua closure at index <code>funcindex2</code>.\n\n\n\n\n\n\n\n<h1>5 &ndash; <a name=\"5\">The Auxiliary Library</a></h1>\n\n<p>\n\nThe <em>auxiliary library</em> provides several convenient functions\nto interface C with Lua.\nWhile the basic API provides the primitive functions for all\ninteractions between C and Lua,\nthe auxiliary library provides higher-level functions for some\ncommon tasks.\n\n\n<p>\nAll functions and types from the auxiliary library\nare defined in header file <code>lauxlib.h</code> and\nhave a prefix <code>luaL_</code>.\n\n\n<p>\nAll functions in the auxiliary library are built on\ntop of the basic API,\nand so they provide nothing that cannot be done with that API.\nNevertheless, the use of the auxiliary library ensures\nmore consistency to your code.\n\n\n<p>\nSeveral functions in the auxiliary library use internally some\nextra stack slots.\nWhen a function in the auxiliary library uses less than five slots,\nit does not check the stack size;\nit simply assumes that there are enough slots.\n\n\n<p>\nSeveral functions in the auxiliary library are used to\ncheck C&nbsp;function arguments.\nBecause the error message is formatted for arguments\n(e.g., \"<code>bad argument #1</code>\"),\nyou should not use these functions for other stack values.\n\n\n<p>\nFunctions called <code>luaL_check*</code>\nalways raise an error if the check is not satisfied.\n\n\n\n<h2>5.1 &ndash; <a name=\"5.1\">Functions and Types</a></h2>\n\n<p>\nHere we list all functions and types from the auxiliary library\nin alphabetical order.\n\n\n\n<hr><h3><a name=\"luaL_addchar\"><code>luaL_addchar</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>m</em>]</span>\n<pre>void luaL_addchar (luaL_Buffer *B, char c);</pre>\n\n<p>\nAdds the byte <code>c</code> to the buffer <code>B</code>\n(see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_addlstring\"><code>luaL_addlstring</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>m</em>]</span>\n<pre>void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);</pre>\n\n<p>\nAdds the string pointed to by <code>s</code> with length <code>l</code> to\nthe buffer <code>B</code>\n(see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>).\nThe string can contain embedded zeros.\n\n\n\n\n\n<hr><h3><a name=\"luaL_addsize\"><code>luaL_addsize</code></a></h3><p>\n<span class=\"apii\">[-?, +?, &ndash;]</span>\n<pre>void luaL_addsize (luaL_Buffer *B, size_t n);</pre>\n\n<p>\nAdds to the buffer <code>B</code> (see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>)\na string of length <code>n</code> previously copied to the\nbuffer area (see <a href=\"#luaL_prepbuffer\"><code>luaL_prepbuffer</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_addstring\"><code>luaL_addstring</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>m</em>]</span>\n<pre>void luaL_addstring (luaL_Buffer *B, const char *s);</pre>\n\n<p>\nAdds the zero-terminated string pointed to by <code>s</code>\nto the buffer <code>B</code>\n(see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_addvalue\"><code>luaL_addvalue</code></a></h3><p>\n<span class=\"apii\">[-1, +?, <em>m</em>]</span>\n<pre>void luaL_addvalue (luaL_Buffer *B);</pre>\n\n<p>\nAdds the value at the top of the stack\nto the buffer <code>B</code>\n(see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>).\nPops the value.\n\n\n<p>\nThis is the only function on string buffers that can (and must)\nbe called with an extra element on the stack,\nwhich is the value to be added to the buffer.\n\n\n\n\n\n<hr><h3><a name=\"luaL_argcheck\"><code>luaL_argcheck</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>void luaL_argcheck (lua_State *L,\n                    int cond,\n                    int arg,\n                    const char *extramsg);</pre>\n\n<p>\nChecks whether <code>cond</code> is true.\nIf it is not, raises an error with a standard message (see <a href=\"#luaL_argerror\"><code>luaL_argerror</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_argerror\"><code>luaL_argerror</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>int luaL_argerror (lua_State *L, int arg, const char *extramsg);</pre>\n\n<p>\nRaises an error reporting a problem with argument <code>arg</code>\nof the C&nbsp;function that called it,\nusing a standard message\nthat includes <code>extramsg</code> as a comment:\n\n<pre>\n     bad argument #<em>arg</em> to '<em>funcname</em>' (<em>extramsg</em>)\n</pre><p>\nThis function never returns.\n\n\n\n\n\n<hr><h3><a name=\"luaL_Buffer\"><code>luaL_Buffer</code></a></h3>\n<pre>typedef struct luaL_Buffer luaL_Buffer;</pre>\n\n<p>\nType for a <em>string buffer</em>.\n\n\n<p>\nA string buffer allows C&nbsp;code to build Lua strings piecemeal.\nIts pattern of use is as follows:\n\n<ul>\n\n<li>First declare a variable <code>b</code> of type <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>.</li>\n\n<li>Then initialize it with a call <code>luaL_buffinit(L, &amp;b)</code>.</li>\n\n<li>\nThen add string pieces to the buffer calling any of\nthe <code>luaL_add*</code> functions.\n</li>\n\n<li>\nFinish by calling <code>luaL_pushresult(&amp;b)</code>.\nThis call leaves the final string on the top of the stack.\n</li>\n\n</ul>\n\n<p>\nIf you know beforehand the total size of the resulting string,\nyou can use the buffer like this:\n\n<ul>\n\n<li>First declare a variable <code>b</code> of type <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>.</li>\n\n<li>Then initialize it and preallocate a space of\nsize <code>sz</code> with a call <code>luaL_buffinitsize(L, &amp;b, sz)</code>.</li>\n\n<li>Then copy the string into that space.</li>\n\n<li>\nFinish by calling <code>luaL_pushresultsize(&amp;b, sz)</code>,\nwhere <code>sz</code> is the total size of the resulting string\ncopied into that space.\n</li>\n\n</ul>\n\n<p>\nDuring its normal operation,\na string buffer uses a variable number of stack slots.\nSo, while using a buffer, you cannot assume that you know where\nthe top of the stack is.\nYou can use the stack between successive calls to buffer operations\nas long as that use is balanced;\nthat is,\nwhen you call a buffer operation,\nthe stack is at the same level\nit was immediately after the previous buffer operation.\n(The only exception to this rule is <a href=\"#luaL_addvalue\"><code>luaL_addvalue</code></a>.)\nAfter calling <a href=\"#luaL_pushresult\"><code>luaL_pushresult</code></a> the stack is back to its\nlevel when the buffer was initialized,\nplus the final string on its top.\n\n\n\n\n\n<hr><h3><a name=\"luaL_buffinit\"><code>luaL_buffinit</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void luaL_buffinit (lua_State *L, luaL_Buffer *B);</pre>\n\n<p>\nInitializes a buffer <code>B</code>.\nThis function does not allocate any space;\nthe buffer must be declared as a variable\n(see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_buffinitsize\"><code>luaL_buffinitsize</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>m</em>]</span>\n<pre>char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);</pre>\n\n<p>\nEquivalent to the sequence\n<a href=\"#luaL_buffinit\"><code>luaL_buffinit</code></a>, <a href=\"#luaL_prepbuffsize\"><code>luaL_prepbuffsize</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_callmeta\"><code>luaL_callmeta</code></a></h3><p>\n<span class=\"apii\">[-0, +(0|1), <em>e</em>]</span>\n<pre>int luaL_callmeta (lua_State *L, int obj, const char *e);</pre>\n\n<p>\nCalls a metamethod.\n\n\n<p>\nIf the object at index <code>obj</code> has a metatable and this\nmetatable has a field <code>e</code>,\nthis function calls this field passing the object as its only argument.\nIn this case this function returns true and pushes onto the\nstack the value returned by the call.\nIf there is no metatable or no metamethod,\nthis function returns false (without pushing any value on the stack).\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkany\"><code>luaL_checkany</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>void luaL_checkany (lua_State *L, int arg);</pre>\n\n<p>\nChecks whether the function has an argument\nof any type (including <b>nil</b>) at position <code>arg</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkinteger\"><code>luaL_checkinteger</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>lua_Integer luaL_checkinteger (lua_State *L, int arg);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> is an integer\n(or can be converted to an integer)\nand returns this integer cast to a <a href=\"#lua_Integer\"><code>lua_Integer</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_checklstring\"><code>luaL_checklstring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>const char *luaL_checklstring (lua_State *L, int arg, size_t *l);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> is a string\nand returns this string;\nif <code>l</code> is not <code>NULL</code> fills <code>*l</code>\nwith the string's length.\n\n\n<p>\nThis function uses <a href=\"#lua_tolstring\"><code>lua_tolstring</code></a> to get its result,\nso all conversions and caveats of that function apply here.\n\n\n\n\n\n<hr><h3><a name=\"luaL_checknumber\"><code>luaL_checknumber</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>lua_Number luaL_checknumber (lua_State *L, int arg);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> is a number\nand returns this number.\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkoption\"><code>luaL_checkoption</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>int luaL_checkoption (lua_State *L,\n                      int arg,\n                      const char *def,\n                      const char *const lst[]);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> is a string and\nsearches for this string in the array <code>lst</code>\n(which must be NULL-terminated).\nReturns the index in the array where the string was found.\nRaises an error if the argument is not a string or\nif the string cannot be found.\n\n\n<p>\nIf <code>def</code> is not <code>NULL</code>,\nthe function uses <code>def</code> as a default value when\nthere is no argument <code>arg</code> or when this argument is <b>nil</b>.\n\n\n<p>\nThis is a useful function for mapping strings to C&nbsp;enums.\n(The usual convention in Lua libraries is\nto use strings instead of numbers to select options.)\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkstack\"><code>luaL_checkstack</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>void luaL_checkstack (lua_State *L, int sz, const char *msg);</pre>\n\n<p>\nGrows the stack size to <code>top + sz</code> elements,\nraising an error if the stack cannot grow to that size.\n<code>msg</code> is an additional text to go into the error message\n(or <code>NULL</code> for no additional text).\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkstring\"><code>luaL_checkstring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>const char *luaL_checkstring (lua_State *L, int arg);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> is a string\nand returns this string.\n\n\n<p>\nThis function uses <a href=\"#lua_tolstring\"><code>lua_tolstring</code></a> to get its result,\nso all conversions and caveats of that function apply here.\n\n\n\n\n\n<hr><h3><a name=\"luaL_checktype\"><code>luaL_checktype</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>void luaL_checktype (lua_State *L, int arg, int t);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> has type <code>t</code>.\nSee <a href=\"#lua_type\"><code>lua_type</code></a> for the encoding of types for <code>t</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkudata\"><code>luaL_checkudata</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>void *luaL_checkudata (lua_State *L, int arg, const char *tname);</pre>\n\n<p>\nChecks whether the function argument <code>arg</code> is a userdata\nof the type <code>tname</code> (see <a href=\"#luaL_newmetatable\"><code>luaL_newmetatable</code></a>) and\nreturns the userdata address (see <a href=\"#lua_touserdata\"><code>lua_touserdata</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_checkversion\"><code>luaL_checkversion</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>void luaL_checkversion (lua_State *L);</pre>\n\n<p>\nChecks whether the core running the call,\nthe core that created the Lua state,\nand the code making the call are all using the same version of Lua.\nAlso checks whether the core running the call\nand the core that created the Lua state\nare using the same address space.\n\n\n\n\n\n<hr><h3><a name=\"luaL_dofile\"><code>luaL_dofile</code></a></h3><p>\n<span class=\"apii\">[-0, +?, <em>e</em>]</span>\n<pre>int luaL_dofile (lua_State *L, const char *filename);</pre>\n\n<p>\nLoads and runs the given file.\nIt is defined as the following macro:\n\n<pre>\n     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))\n</pre><p>\nIt returns false if there are no errors\nor true in case of errors.\n\n\n\n\n\n<hr><h3><a name=\"luaL_dostring\"><code>luaL_dostring</code></a></h3><p>\n<span class=\"apii\">[-0, +?, &ndash;]</span>\n<pre>int luaL_dostring (lua_State *L, const char *str);</pre>\n\n<p>\nLoads and runs the given string.\nIt is defined as the following macro:\n\n<pre>\n     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))\n</pre><p>\nIt returns false if there are no errors\nor true in case of errors.\n\n\n\n\n\n<hr><h3><a name=\"luaL_error\"><code>luaL_error</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>int luaL_error (lua_State *L, const char *fmt, ...);</pre>\n\n<p>\nRaises an error.\nThe error message format is given by <code>fmt</code>\nplus any extra arguments,\nfollowing the same rules of <a href=\"#lua_pushfstring\"><code>lua_pushfstring</code></a>.\nIt also adds at the beginning of the message the file name and\nthe line number where the error occurred,\nif this information is available.\n\n\n<p>\nThis function never returns,\nbut it is an idiom to use it in C&nbsp;functions\nas <code>return luaL_error(<em>args</em>)</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_execresult\"><code>luaL_execresult</code></a></h3><p>\n<span class=\"apii\">[-0, +3, <em>m</em>]</span>\n<pre>int luaL_execresult (lua_State *L, int stat);</pre>\n\n<p>\nThis function produces the return values for\nprocess-related functions in the standard library\n(<a href=\"#pdf-os.execute\"><code>os.execute</code></a> and <a href=\"#pdf-io.close\"><code>io.close</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_fileresult\"><code>luaL_fileresult</code></a></h3><p>\n<span class=\"apii\">[-0, +(1|3), <em>m</em>]</span>\n<pre>int luaL_fileresult (lua_State *L, int stat, const char *fname);</pre>\n\n<p>\nThis function produces the return values for\nfile-related functions in the standard library\n(<a href=\"#pdf-io.open\"><code>io.open</code></a>, <a href=\"#pdf-os.rename\"><code>os.rename</code></a>, <a href=\"#pdf-file:seek\"><code>file:seek</code></a>, etc.).\n\n\n\n\n\n<hr><h3><a name=\"luaL_getmetafield\"><code>luaL_getmetafield</code></a></h3><p>\n<span class=\"apii\">[-0, +(0|1), <em>m</em>]</span>\n<pre>int luaL_getmetafield (lua_State *L, int obj, const char *e);</pre>\n\n<p>\nPushes onto the stack the field <code>e</code> from the metatable\nof the object at index <code>obj</code> and returns the type of the pushed value.\nIf the object does not have a metatable,\nor if the metatable does not have this field,\npushes nothing and returns <code>LUA_TNIL</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_getmetatable\"><code>luaL_getmetatable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>int luaL_getmetatable (lua_State *L, const char *tname);</pre>\n\n<p>\nPushes onto the stack the metatable associated with name <code>tname</code>\nin the registry (see <a href=\"#luaL_newmetatable\"><code>luaL_newmetatable</code></a>)\n(<b>nil</b> if there is no metatable associated with that name).\nReturns the type of the pushed value.\n\n\n\n\n\n<hr><h3><a name=\"luaL_getsubtable\"><code>luaL_getsubtable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>int luaL_getsubtable (lua_State *L, int idx, const char *fname);</pre>\n\n<p>\nEnsures that the value <code>t[fname]</code>,\nwhere <code>t</code> is the value at index <code>idx</code>,\nis a table,\nand pushes that table onto the stack.\nReturns true if it finds a previous table there\nand false if it creates a new table.\n\n\n\n\n\n<hr><h3><a name=\"luaL_gsub\"><code>luaL_gsub</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>const char *luaL_gsub (lua_State *L,\n                       const char *s,\n                       const char *p,\n                       const char *r);</pre>\n\n<p>\nCreates a copy of string <code>s</code> by replacing\nany occurrence of the string <code>p</code>\nwith the string <code>r</code>.\nPushes the resulting string on the stack and returns it.\n\n\n\n\n\n<hr><h3><a name=\"luaL_len\"><code>luaL_len</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>e</em>]</span>\n<pre>lua_Integer luaL_len (lua_State *L, int index);</pre>\n\n<p>\nReturns the \"length\" of the value at the given index\nas a number;\nit is equivalent to the '<code>#</code>' operator in Lua (see <a href=\"#3.4.7\">&sect;3.4.7</a>).\nRaises an error if the result of the operation is not an integer.\n(This case only can happen through metamethods.)\n\n\n\n\n\n<hr><h3><a name=\"luaL_loadbuffer\"><code>luaL_loadbuffer</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int luaL_loadbuffer (lua_State *L,\n                     const char *buff,\n                     size_t sz,\n                     const char *name);</pre>\n\n<p>\nEquivalent to <a href=\"#luaL_loadbufferx\"><code>luaL_loadbufferx</code></a> with <code>mode</code> equal to <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_loadbufferx\"><code>luaL_loadbufferx</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int luaL_loadbufferx (lua_State *L,\n                      const char *buff,\n                      size_t sz,\n                      const char *name,\n                      const char *mode);</pre>\n\n<p>\nLoads a buffer as a Lua chunk.\nThis function uses <a href=\"#lua_load\"><code>lua_load</code></a> to load the chunk in the\nbuffer pointed to by <code>buff</code> with size <code>sz</code>.\n\n\n<p>\nThis function returns the same results as <a href=\"#lua_load\"><code>lua_load</code></a>.\n<code>name</code> is the chunk name,\nused for debug information and error messages.\nThe string <code>mode</code> works as in function <a href=\"#lua_load\"><code>lua_load</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_loadfile\"><code>luaL_loadfile</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>int luaL_loadfile (lua_State *L, const char *filename);</pre>\n\n<p>\nEquivalent to <a href=\"#luaL_loadfilex\"><code>luaL_loadfilex</code></a> with <code>mode</code> equal to <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_loadfilex\"><code>luaL_loadfilex</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>int luaL_loadfilex (lua_State *L, const char *filename,\n                                            const char *mode);</pre>\n\n<p>\nLoads a file as a Lua chunk.\nThis function uses <a href=\"#lua_load\"><code>lua_load</code></a> to load the chunk in the file\nnamed <code>filename</code>.\nIf <code>filename</code> is <code>NULL</code>,\nthen it loads from the standard input.\nThe first line in the file is ignored if it starts with a <code>#</code>.\n\n\n<p>\nThe string <code>mode</code> works as in function <a href=\"#lua_load\"><code>lua_load</code></a>.\n\n\n<p>\nThis function returns the same results as <a href=\"#lua_load\"><code>lua_load</code></a>,\nbut it has an extra error code <a name=\"pdf-LUA_ERRFILE\"><code>LUA_ERRFILE</code></a>\nfor file-related errors\n(e.g., it cannot open or read the file).\n\n\n<p>\nAs <a href=\"#lua_load\"><code>lua_load</code></a>, this function only loads the chunk;\nit does not run it.\n\n\n\n\n\n<hr><h3><a name=\"luaL_loadstring\"><code>luaL_loadstring</code></a></h3><p>\n<span class=\"apii\">[-0, +1, &ndash;]</span>\n<pre>int luaL_loadstring (lua_State *L, const char *s);</pre>\n\n<p>\nLoads a string as a Lua chunk.\nThis function uses <a href=\"#lua_load\"><code>lua_load</code></a> to load the chunk in\nthe zero-terminated string <code>s</code>.\n\n\n<p>\nThis function returns the same results as <a href=\"#lua_load\"><code>lua_load</code></a>.\n\n\n<p>\nAlso as <a href=\"#lua_load\"><code>lua_load</code></a>, this function only loads the chunk;\nit does not run it.\n\n\n\n\n\n<hr><h3><a name=\"luaL_newlib\"><code>luaL_newlib</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void luaL_newlib (lua_State *L, const luaL_Reg l[]);</pre>\n\n<p>\nCreates a new table and registers there\nthe functions in list <code>l</code>.\n\n\n<p>\nIt is implemented as the following macro:\n\n<pre>\n     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))\n</pre><p>\nThe array <code>l</code> must be the actual array,\nnot a pointer to it.\n\n\n\n\n\n<hr><h3><a name=\"luaL_newlibtable\"><code>luaL_newlibtable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);</pre>\n\n<p>\nCreates a new table with a size optimized\nto store all entries in the array <code>l</code>\n(but does not actually store them).\nIt is intended to be used in conjunction with <a href=\"#luaL_setfuncs\"><code>luaL_setfuncs</code></a>\n(see <a href=\"#luaL_newlib\"><code>luaL_newlib</code></a>).\n\n\n<p>\nIt is implemented as a macro.\nThe array <code>l</code> must be the actual array,\nnot a pointer to it.\n\n\n\n\n\n<hr><h3><a name=\"luaL_newmetatable\"><code>luaL_newmetatable</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>int luaL_newmetatable (lua_State *L, const char *tname);</pre>\n\n<p>\nIf the registry already has the key <code>tname</code>,\nreturns 0.\nOtherwise,\ncreates a new table to be used as a metatable for userdata,\nadds to this new table the pair <code>__name = tname</code>,\nadds to the registry the pair <code>[tname] = new table</code>,\nand returns 1.\n(The entry <code>__name</code> is used by some error-reporting functions.)\n\n\n<p>\nIn both cases pushes onto the stack the final value associated\nwith <code>tname</code> in the registry.\n\n\n\n\n\n<hr><h3><a name=\"luaL_newstate\"><code>luaL_newstate</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>lua_State *luaL_newstate (void);</pre>\n\n<p>\nCreates a new Lua state.\nIt calls <a href=\"#lua_newstate\"><code>lua_newstate</code></a> with an\nallocator based on the standard&nbsp;C <code>realloc</code> function\nand then sets a panic function (see <a href=\"#4.6\">&sect;4.6</a>) that prints\nan error message to the standard error output in case of fatal\nerrors.\n\n\n<p>\nReturns the new state,\nor <code>NULL</code> if there is a memory allocation error.\n\n\n\n\n\n<hr><h3><a name=\"luaL_openlibs\"><code>luaL_openlibs</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>e</em>]</span>\n<pre>void luaL_openlibs (lua_State *L);</pre>\n\n<p>\nOpens all standard Lua libraries into the given state.\n\n\n\n\n\n<hr><h3><a name=\"luaL_opt\"><code>luaL_opt</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>e</em>]</span>\n<pre>T luaL_opt (L, func, arg, dflt);</pre>\n\n<p>\nThis macro is defined as follows:\n\n<pre>\n     (lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg)))\n</pre><p>\nIn words, if the argument <code>arg</code> is nil or absent,\nthe macro results in the default <code>dflt</code>.\nOtherwise, it results in the result of calling <code>func</code>\nwith the state <code>L</code> and the argument index <code>arg</code> as\narguments.\nNote that it evaluates the expression <code>dflt</code> only if needed.\n\n\n\n\n\n<hr><h3><a name=\"luaL_optinteger\"><code>luaL_optinteger</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>lua_Integer luaL_optinteger (lua_State *L,\n                             int arg,\n                             lua_Integer d);</pre>\n\n<p>\nIf the function argument <code>arg</code> is an integer\n(or convertible to an integer),\nreturns this integer.\nIf this argument is absent or is <b>nil</b>,\nreturns <code>d</code>.\nOtherwise, raises an error.\n\n\n\n\n\n<hr><h3><a name=\"luaL_optlstring\"><code>luaL_optlstring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>const char *luaL_optlstring (lua_State *L,\n                             int arg,\n                             const char *d,\n                             size_t *l);</pre>\n\n<p>\nIf the function argument <code>arg</code> is a string,\nreturns this string.\nIf this argument is absent or is <b>nil</b>,\nreturns <code>d</code>.\nOtherwise, raises an error.\n\n\n<p>\nIf <code>l</code> is not <code>NULL</code>,\nfills the position <code>*l</code> with the result's length.\nIf the result is <code>NULL</code>\n(only possible when returning <code>d</code> and <code>d == NULL</code>),\nits length is considered zero.\n\n\n<p>\nThis function uses <a href=\"#lua_tolstring\"><code>lua_tolstring</code></a> to get its result,\nso all conversions and caveats of that function apply here.\n\n\n\n\n\n<hr><h3><a name=\"luaL_optnumber\"><code>luaL_optnumber</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);</pre>\n\n<p>\nIf the function argument <code>arg</code> is a number,\nreturns this number.\nIf this argument is absent or is <b>nil</b>,\nreturns <code>d</code>.\nOtherwise, raises an error.\n\n\n\n\n\n<hr><h3><a name=\"luaL_optstring\"><code>luaL_optstring</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>v</em>]</span>\n<pre>const char *luaL_optstring (lua_State *L,\n                            int arg,\n                            const char *d);</pre>\n\n<p>\nIf the function argument <code>arg</code> is a string,\nreturns this string.\nIf this argument is absent or is <b>nil</b>,\nreturns <code>d</code>.\nOtherwise, raises an error.\n\n\n\n\n\n<hr><h3><a name=\"luaL_prepbuffer\"><code>luaL_prepbuffer</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>m</em>]</span>\n<pre>char *luaL_prepbuffer (luaL_Buffer *B);</pre>\n\n<p>\nEquivalent to <a href=\"#luaL_prepbuffsize\"><code>luaL_prepbuffsize</code></a>\nwith the predefined size <a name=\"pdf-LUAL_BUFFERSIZE\"><code>LUAL_BUFFERSIZE</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_prepbuffsize\"><code>luaL_prepbuffsize</code></a></h3><p>\n<span class=\"apii\">[-?, +?, <em>m</em>]</span>\n<pre>char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);</pre>\n\n<p>\nReturns an address to a space of size <code>sz</code>\nwhere you can copy a string to be added to buffer <code>B</code>\n(see <a href=\"#luaL_Buffer\"><code>luaL_Buffer</code></a>).\nAfter copying the string into this space you must call\n<a href=\"#luaL_addsize\"><code>luaL_addsize</code></a> with the size of the string to actually add\nit to the buffer.\n\n\n\n\n\n<hr><h3><a name=\"luaL_pushresult\"><code>luaL_pushresult</code></a></h3><p>\n<span class=\"apii\">[-?, +1, <em>m</em>]</span>\n<pre>void luaL_pushresult (luaL_Buffer *B);</pre>\n\n<p>\nFinishes the use of buffer <code>B</code> leaving the final string on\nthe top of the stack.\n\n\n\n\n\n<hr><h3><a name=\"luaL_pushresultsize\"><code>luaL_pushresultsize</code></a></h3><p>\n<span class=\"apii\">[-?, +1, <em>m</em>]</span>\n<pre>void luaL_pushresultsize (luaL_Buffer *B, size_t sz);</pre>\n\n<p>\nEquivalent to the sequence <a href=\"#luaL_addsize\"><code>luaL_addsize</code></a>, <a href=\"#luaL_pushresult\"><code>luaL_pushresult</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_ref\"><code>luaL_ref</code></a></h3><p>\n<span class=\"apii\">[-1, +0, <em>m</em>]</span>\n<pre>int luaL_ref (lua_State *L, int t);</pre>\n\n<p>\nCreates and returns a <em>reference</em>,\nin the table at index <code>t</code>,\nfor the object at the top of the stack (and pops the object).\n\n\n<p>\nA reference is a unique integer key.\nAs long as you do not manually add integer keys into table <code>t</code>,\n<a href=\"#luaL_ref\"><code>luaL_ref</code></a> ensures the uniqueness of the key it returns.\nYou can retrieve an object referred by reference <code>r</code>\nby calling <code>lua_rawgeti(L, t, r)</code>.\nFunction <a href=\"#luaL_unref\"><code>luaL_unref</code></a> frees a reference and its associated object.\n\n\n<p>\nIf the object at the top of the stack is <b>nil</b>,\n<a href=\"#luaL_ref\"><code>luaL_ref</code></a> returns the constant <a name=\"pdf-LUA_REFNIL\"><code>LUA_REFNIL</code></a>.\nThe constant <a name=\"pdf-LUA_NOREF\"><code>LUA_NOREF</code></a> is guaranteed to be different\nfrom any reference returned by <a href=\"#luaL_ref\"><code>luaL_ref</code></a>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_Reg\"><code>luaL_Reg</code></a></h3>\n<pre>typedef struct luaL_Reg {\n  const char *name;\n  lua_CFunction func;\n} luaL_Reg;</pre>\n\n<p>\nType for arrays of functions to be registered by\n<a href=\"#luaL_setfuncs\"><code>luaL_setfuncs</code></a>.\n<code>name</code> is the function name and <code>func</code> is a pointer to\nthe function.\nAny array of <a href=\"#luaL_Reg\"><code>luaL_Reg</code></a> must end with a sentinel entry\nin which both <code>name</code> and <code>func</code> are <code>NULL</code>.\n\n\n\n\n\n<hr><h3><a name=\"luaL_requiref\"><code>luaL_requiref</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>void luaL_requiref (lua_State *L, const char *modname,\n                    lua_CFunction openf, int glb);</pre>\n\n<p>\nIf <code>modname</code> is not already present in <a href=\"#pdf-package.loaded\"><code>package.loaded</code></a>,\ncalls function <code>openf</code> with string <code>modname</code> as an argument\nand sets the call result in <code>package.loaded[modname]</code>,\nas if that function has been called through <a href=\"#pdf-require\"><code>require</code></a>.\n\n\n<p>\nIf <code>glb</code> is true,\nalso stores the module into global <code>modname</code>.\n\n\n<p>\nLeaves a copy of the module on the stack.\n\n\n\n\n\n<hr><h3><a name=\"luaL_setfuncs\"><code>luaL_setfuncs</code></a></h3><p>\n<span class=\"apii\">[-nup, +0, <em>m</em>]</span>\n<pre>void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);</pre>\n\n<p>\nRegisters all functions in the array <code>l</code>\n(see <a href=\"#luaL_Reg\"><code>luaL_Reg</code></a>) into the table on the top of the stack\n(below optional upvalues, see next).\n\n\n<p>\nWhen <code>nup</code> is not zero,\nall functions are created sharing <code>nup</code> upvalues,\nwhich must be previously pushed on the stack\non top of the library table.\nThese values are popped from the stack after the registration.\n\n\n\n\n\n<hr><h3><a name=\"luaL_setmetatable\"><code>luaL_setmetatable</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void luaL_setmetatable (lua_State *L, const char *tname);</pre>\n\n<p>\nSets the metatable of the object at the top of the stack\nas the metatable associated with name <code>tname</code>\nin the registry (see <a href=\"#luaL_newmetatable\"><code>luaL_newmetatable</code></a>).\n\n\n\n\n\n<hr><h3><a name=\"luaL_Stream\"><code>luaL_Stream</code></a></h3>\n<pre>typedef struct luaL_Stream {\n  FILE *f;\n  lua_CFunction closef;\n} luaL_Stream;</pre>\n\n<p>\nThe standard representation for file handles,\nwhich is used by the standard I/O library.\n\n\n<p>\nA file handle is implemented as a full userdata,\nwith a metatable called <code>LUA_FILEHANDLE</code>\n(where <code>LUA_FILEHANDLE</code> is a macro with the actual metatable's name).\nThe metatable is created by the I/O library\n(see <a href=\"#luaL_newmetatable\"><code>luaL_newmetatable</code></a>).\n\n\n<p>\nThis userdata must start with the structure <code>luaL_Stream</code>;\nit can contain other data after this initial structure.\nField <code>f</code> points to the corresponding C stream\n(or it can be <code>NULL</code> to indicate an incompletely created handle).\nField <code>closef</code> points to a Lua function\nthat will be called to close the stream\nwhen the handle is closed or collected;\nthis function receives the file handle as its sole argument and\nmust return either <b>true</b> (in case of success)\nor <b>nil</b> plus an error message (in case of error).\nOnce Lua calls this field,\nit changes the field value to <code>NULL</code>\nto signal that the handle is closed.\n\n\n\n\n\n<hr><h3><a name=\"luaL_testudata\"><code>luaL_testudata</code></a></h3><p>\n<span class=\"apii\">[-0, +0, <em>m</em>]</span>\n<pre>void *luaL_testudata (lua_State *L, int arg, const char *tname);</pre>\n\n<p>\nThis function works like <a href=\"#luaL_checkudata\"><code>luaL_checkudata</code></a>,\nexcept that, when the test fails,\nit returns <code>NULL</code> instead of raising an error.\n\n\n\n\n\n<hr><h3><a name=\"luaL_tolstring\"><code>luaL_tolstring</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>e</em>]</span>\n<pre>const char *luaL_tolstring (lua_State *L, int idx, size_t *len);</pre>\n\n<p>\nConverts any Lua value at the given index to a C&nbsp;string\nin a reasonable format.\nThe resulting string is pushed onto the stack and also\nreturned by the function.\nIf <code>len</code> is not <code>NULL</code>,\nthe function also sets <code>*len</code> with the string length.\n\n\n<p>\nIf the value has a metatable with a <code>__tostring</code> field,\nthen <code>luaL_tolstring</code> calls the corresponding metamethod\nwith the value as argument,\nand uses the result of the call as its result.\n\n\n\n\n\n<hr><h3><a name=\"luaL_traceback\"><code>luaL_traceback</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,\n                     int level);</pre>\n\n<p>\nCreates and pushes a traceback of the stack <code>L1</code>.\nIf <code>msg</code> is not <code>NULL</code> it is appended\nat the beginning of the traceback.\nThe <code>level</code> parameter tells at which level\nto start the traceback.\n\n\n\n\n\n<hr><h3><a name=\"luaL_typename\"><code>luaL_typename</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>const char *luaL_typename (lua_State *L, int index);</pre>\n\n<p>\nReturns the name of the type of the value at the given index.\n\n\n\n\n\n<hr><h3><a name=\"luaL_unref\"><code>luaL_unref</code></a></h3><p>\n<span class=\"apii\">[-0, +0, &ndash;]</span>\n<pre>void luaL_unref (lua_State *L, int t, int ref);</pre>\n\n<p>\nReleases reference <code>ref</code> from the table at index <code>t</code>\n(see <a href=\"#luaL_ref\"><code>luaL_ref</code></a>).\nThe entry is removed from the table,\nso that the referred object can be collected.\nThe reference <code>ref</code> is also freed to be used again.\n\n\n<p>\nIf <code>ref</code> is <a href=\"#pdf-LUA_NOREF\"><code>LUA_NOREF</code></a> or <a href=\"#pdf-LUA_REFNIL\"><code>LUA_REFNIL</code></a>,\n<a href=\"#luaL_unref\"><code>luaL_unref</code></a> does nothing.\n\n\n\n\n\n<hr><h3><a name=\"luaL_where\"><code>luaL_where</code></a></h3><p>\n<span class=\"apii\">[-0, +1, <em>m</em>]</span>\n<pre>void luaL_where (lua_State *L, int lvl);</pre>\n\n<p>\nPushes onto the stack a string identifying the current position\nof the control at level <code>lvl</code> in the call stack.\nTypically this string has the following format:\n\n<pre>\n     <em>chunkname</em>:<em>currentline</em>:\n</pre><p>\nLevel&nbsp;0 is the running function,\nlevel&nbsp;1 is the function that called the running function,\netc.\n\n\n<p>\nThis function is used to build a prefix for error messages.\n\n\n\n\n\n\n\n<h1>6 &ndash; <a name=\"6\">Standard Libraries</a></h1>\n\n<p>\nThe standard Lua libraries provide useful functions\nthat are implemented directly through the C&nbsp;API.\nSome of these functions provide essential services to the language\n(e.g., <a href=\"#pdf-type\"><code>type</code></a> and <a href=\"#pdf-getmetatable\"><code>getmetatable</code></a>);\nothers provide access to \"outside\" services (e.g., I/O);\nand others could be implemented in Lua itself,\nbut are quite useful or have critical performance requirements that\ndeserve an implementation in C (e.g., <a href=\"#pdf-table.sort\"><code>table.sort</code></a>).\n\n\n<p>\nAll libraries are implemented through the official C&nbsp;API\nand are provided as separate C&nbsp;modules.\nCurrently, Lua has the following standard libraries:\n\n<ul>\n\n<li>basic library (<a href=\"#6.1\">&sect;6.1</a>);</li>\n\n<li>coroutine library (<a href=\"#6.2\">&sect;6.2</a>);</li>\n\n<li>package library (<a href=\"#6.3\">&sect;6.3</a>);</li>\n\n<li>string manipulation (<a href=\"#6.4\">&sect;6.4</a>);</li>\n\n<li>basic UTF-8 support (<a href=\"#6.5\">&sect;6.5</a>);</li>\n\n<li>table manipulation (<a href=\"#6.6\">&sect;6.6</a>);</li>\n\n<li>mathematical functions (<a href=\"#6.7\">&sect;6.7</a>) (sin, log, etc.);</li>\n\n<li>input and output (<a href=\"#6.8\">&sect;6.8</a>);</li>\n\n<li>operating system facilities (<a href=\"#6.9\">&sect;6.9</a>);</li>\n\n<li>debug facilities (<a href=\"#6.10\">&sect;6.10</a>).</li>\n\n</ul><p>\nExcept for the basic and the package libraries,\neach library provides all its functions as fields of a global table\nor as methods of its objects.\n\n\n<p>\nTo have access to these libraries,\nthe C&nbsp;host program should call the <a href=\"#luaL_openlibs\"><code>luaL_openlibs</code></a> function,\nwhich opens all standard libraries.\nAlternatively,\nthe host program can open them individually by using\n<a href=\"#luaL_requiref\"><code>luaL_requiref</code></a> to call\n<a name=\"pdf-luaopen_base\"><code>luaopen_base</code></a> (for the basic library),\n<a name=\"pdf-luaopen_package\"><code>luaopen_package</code></a> (for the package library),\n<a name=\"pdf-luaopen_coroutine\"><code>luaopen_coroutine</code></a> (for the coroutine library),\n<a name=\"pdf-luaopen_string\"><code>luaopen_string</code></a> (for the string library),\n<a name=\"pdf-luaopen_utf8\"><code>luaopen_utf8</code></a> (for the UTF8 library),\n<a name=\"pdf-luaopen_table\"><code>luaopen_table</code></a> (for the table library),\n<a name=\"pdf-luaopen_math\"><code>luaopen_math</code></a> (for the mathematical library),\n<a name=\"pdf-luaopen_io\"><code>luaopen_io</code></a> (for the I/O library),\n<a name=\"pdf-luaopen_os\"><code>luaopen_os</code></a> (for the operating system library),\nand <a name=\"pdf-luaopen_debug\"><code>luaopen_debug</code></a> (for the debug library).\nThese functions are declared in <a name=\"pdf-lualib.h\"><code>lualib.h</code></a>.\n\n\n\n<h2>6.1 &ndash; <a name=\"6.1\">Basic Functions</a></h2>\n\n<p>\nThe basic library provides core functions to Lua.\nIf you do not include this library in your application,\nyou should check carefully whether you need to provide\nimplementations for some of its facilities.\n\n\n<p>\n<hr><h3><a name=\"pdf-assert\"><code>assert (v [, message])</code></a></h3>\n\n\n<p>\nCalls <a href=\"#pdf-error\"><code>error</code></a> if\nthe value of its argument <code>v</code> is false (i.e., <b>nil</b> or <b>false</b>);\notherwise, returns all its arguments.\nIn case of error,\n<code>message</code> is the error object;\nwhen absent, it defaults to \"<code>assertion failed!</code>\"\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-collectgarbage\"><code>collectgarbage ([opt [, arg]])</code></a></h3>\n\n\n<p>\nThis function is a generic interface to the garbage collector.\nIt performs different functions according to its first argument, <code>opt</code>:\n\n<ul>\n\n<li><b>\"<code>collect</code>\": </b>\nperforms a full garbage-collection cycle.\nThis is the default option.\n</li>\n\n<li><b>\"<code>stop</code>\": </b>\nstops automatic execution of the garbage collector.\nThe collector will run only when explicitly invoked,\nuntil a call to restart it.\n</li>\n\n<li><b>\"<code>restart</code>\": </b>\nrestarts automatic execution of the garbage collector.\n</li>\n\n<li><b>\"<code>count</code>\": </b>\nreturns the total memory in use by Lua in Kbytes.\nThe value has a fractional part,\nso that it multiplied by 1024\ngives the exact number of bytes in use by Lua\n(except for overflows).\n</li>\n\n<li><b>\"<code>step</code>\": </b>\nperforms a garbage-collection step.\nThe step \"size\" is controlled by <code>arg</code>.\nWith a zero value,\nthe collector will perform one basic (indivisible) step.\nFor non-zero values,\nthe collector will perform as if that amount of memory\n(in KBytes) had been allocated by Lua.\nReturns <b>true</b> if the step finished a collection cycle.\n</li>\n\n<li><b>\"<code>setpause</code>\": </b>\nsets <code>arg</code> as the new value for the <em>pause</em> of\nthe collector (see <a href=\"#2.5\">&sect;2.5</a>).\nReturns the previous value for <em>pause</em>.\n</li>\n\n<li><b>\"<code>setstepmul</code>\": </b>\nsets <code>arg</code> as the new value for the <em>step multiplier</em> of\nthe collector (see <a href=\"#2.5\">&sect;2.5</a>).\nReturns the previous value for <em>step</em>.\n</li>\n\n<li><b>\"<code>isrunning</code>\": </b>\nreturns a boolean that tells whether the collector is running\n(i.e., not stopped).\n</li>\n\n</ul>\n\n\n\n<p>\n<hr><h3><a name=\"pdf-dofile\"><code>dofile ([filename])</code></a></h3>\nOpens the named file and executes its contents as a Lua chunk.\nWhen called without arguments,\n<code>dofile</code> executes the contents of the standard input (<code>stdin</code>).\nReturns all values returned by the chunk.\nIn case of errors, <code>dofile</code> propagates the error\nto its caller (that is, <code>dofile</code> does not run in protected mode).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-error\"><code>error (message [, level])</code></a></h3>\nTerminates the last protected function called\nand returns <code>message</code> as the error object.\nFunction <code>error</code> never returns.\n\n\n<p>\nUsually, <code>error</code> adds some information about the error position\nat the beginning of the message, if the message is a string.\nThe <code>level</code> argument specifies how to get the error position.\nWith level&nbsp;1 (the default), the error position is where the\n<code>error</code> function was called.\nLevel&nbsp;2 points the error to where the function\nthat called <code>error</code> was called; and so on.\nPassing a level&nbsp;0 avoids the addition of error position information\nto the message.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-_G\"><code>_G</code></a></h3>\nA global variable (not a function) that\nholds the global environment (see <a href=\"#2.2\">&sect;2.2</a>).\nLua itself does not use this variable;\nchanging its value does not affect any environment,\nnor vice versa.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-getmetatable\"><code>getmetatable (object)</code></a></h3>\n\n\n<p>\nIf <code>object</code> does not have a metatable, returns <b>nil</b>.\nOtherwise,\nif the object's metatable has a <code>__metatable</code> field,\nreturns the associated value.\nOtherwise, returns the metatable of the given object.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-ipairs\"><code>ipairs (t)</code></a></h3>\n\n\n<p>\nReturns three values (an iterator function, the table <code>t</code>, and 0)\nso that the construction\n\n<pre>\n     for i,v in ipairs(t) do <em>body</em> end\n</pre><p>\nwill iterate over the key&ndash;value pairs\n(<code>1,t[1]</code>), (<code>2,t[2]</code>), ...,\nup to the first nil value.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-load\"><code>load (chunk [, chunkname [, mode [, env]]])</code></a></h3>\n\n\n<p>\nLoads a chunk.\n\n\n<p>\nIf <code>chunk</code> is a string, the chunk is this string.\nIf <code>chunk</code> is a function,\n<code>load</code> calls it repeatedly to get the chunk pieces.\nEach call to <code>chunk</code> must return a string that concatenates\nwith previous results.\nA return of an empty string, <b>nil</b>, or no value signals the end of the chunk.\n\n\n<p>\nIf there are no syntactic errors,\nreturns the compiled chunk as a function;\notherwise, returns <b>nil</b> plus the error message.\n\n\n<p>\nIf the resulting function has upvalues,\nthe first upvalue is set to the value of <code>env</code>,\nif that parameter is given,\nor to the value of the global environment.\nOther upvalues are initialized with <b>nil</b>.\n(When you load a main chunk,\nthe resulting function will always have exactly one upvalue,\nthe <code>_ENV</code> variable (see <a href=\"#2.2\">&sect;2.2</a>).\nHowever,\nwhen you load a binary chunk created from a function (see <a href=\"#pdf-string.dump\"><code>string.dump</code></a>),\nthe resulting function can have an arbitrary number of upvalues.)\nAll upvalues are fresh, that is,\nthey are not shared with any other function.\n\n\n<p>\n<code>chunkname</code> is used as the name of the chunk for error messages\nand debug information (see <a href=\"#4.9\">&sect;4.9</a>).\nWhen absent,\nit defaults to <code>chunk</code>, if <code>chunk</code> is a string,\nor to \"<code>=(load)</code>\" otherwise.\n\n\n<p>\nThe string <code>mode</code> controls whether the chunk can be text or binary\n(that is, a precompiled chunk).\nIt may be the string \"<code>b</code>\" (only binary chunks),\n\"<code>t</code>\" (only text chunks),\nor \"<code>bt</code>\" (both binary and text).\nThe default is \"<code>bt</code>\".\n\n\n<p>\nLua does not check the consistency of binary chunks.\nMaliciously crafted binary chunks can crash\nthe interpreter.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-loadfile\"><code>loadfile ([filename [, mode [, env]]])</code></a></h3>\n\n\n<p>\nSimilar to <a href=\"#pdf-load\"><code>load</code></a>,\nbut gets the chunk from file <code>filename</code>\nor from the standard input,\nif no file name is given.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-next\"><code>next (table [, index])</code></a></h3>\n\n\n<p>\nAllows a program to traverse all fields of a table.\nIts first argument is a table and its second argument\nis an index in this table.\n<code>next</code> returns the next index of the table\nand its associated value.\nWhen called with <b>nil</b> as its second argument,\n<code>next</code> returns an initial index\nand its associated value.\nWhen called with the last index,\nor with <b>nil</b> in an empty table,\n<code>next</code> returns <b>nil</b>.\nIf the second argument is absent, then it is interpreted as <b>nil</b>.\nIn particular,\nyou can use <code>next(t)</code> to check whether a table is empty.\n\n\n<p>\nThe order in which the indices are enumerated is not specified,\n<em>even for numeric indices</em>.\n(To traverse a table in numerical order,\nuse a numerical <b>for</b>.)\n\n\n<p>\nThe behavior of <code>next</code> is undefined if,\nduring the traversal,\nyou assign any value to a non-existent field in the table.\nYou may however modify existing fields.\nIn particular, you may clear existing fields.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-pairs\"><code>pairs (t)</code></a></h3>\n\n\n<p>\nIf <code>t</code> has a metamethod <code>__pairs</code>,\ncalls it with <code>t</code> as argument and returns the first three\nresults from the call.\n\n\n<p>\nOtherwise,\nreturns three values: the <a href=\"#pdf-next\"><code>next</code></a> function, the table <code>t</code>, and <b>nil</b>,\nso that the construction\n\n<pre>\n     for k,v in pairs(t) do <em>body</em> end\n</pre><p>\nwill iterate over all key&ndash;value pairs of table <code>t</code>.\n\n\n<p>\nSee function <a href=\"#pdf-next\"><code>next</code></a> for the caveats of modifying\nthe table during its traversal.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-pcall\"><code>pcall (f [, arg1, &middot;&middot;&middot;])</code></a></h3>\n\n\n<p>\nCalls function <code>f</code> with\nthe given arguments in <em>protected mode</em>.\nThis means that any error inside&nbsp;<code>f</code> is not propagated;\ninstead, <code>pcall</code> catches the error\nand returns a status code.\nIts first result is the status code (a boolean),\nwhich is true if the call succeeds without errors.\nIn such case, <code>pcall</code> also returns all results from the call,\nafter this first result.\nIn case of any error, <code>pcall</code> returns <b>false</b> plus the error message.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-print\"><code>print (&middot;&middot;&middot;)</code></a></h3>\nReceives any number of arguments\nand prints their values to <code>stdout</code>,\nusing the <a href=\"#pdf-tostring\"><code>tostring</code></a> function to convert each argument to a string.\n<code>print</code> is not intended for formatted output,\nbut only as a quick way to show a value,\nfor instance for debugging.\nFor complete control over the output,\nuse <a href=\"#pdf-string.format\"><code>string.format</code></a> and <a href=\"#pdf-io.write\"><code>io.write</code></a>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-rawequal\"><code>rawequal (v1, v2)</code></a></h3>\nChecks whether <code>v1</code> is equal to <code>v2</code>,\nwithout invoking the <code>__eq</code> metamethod.\nReturns a boolean.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-rawget\"><code>rawget (table, index)</code></a></h3>\nGets the real value of <code>table[index]</code>,\nwithout invoking the <code>__index</code> metamethod.\n<code>table</code> must be a table;\n<code>index</code> may be any value.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-rawlen\"><code>rawlen (v)</code></a></h3>\nReturns the length of the object <code>v</code>,\nwhich must be a table or a string,\nwithout invoking the <code>__len</code> metamethod.\nReturns an integer.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-rawset\"><code>rawset (table, index, value)</code></a></h3>\nSets the real value of <code>table[index]</code> to <code>value</code>,\nwithout invoking the <code>__newindex</code> metamethod.\n<code>table</code> must be a table,\n<code>index</code> any value different from <b>nil</b> and NaN,\nand <code>value</code> any Lua value.\n\n\n<p>\nThis function returns <code>table</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-select\"><code>select (index, &middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nIf <code>index</code> is a number,\nreturns all arguments after argument number <code>index</code>;\na negative number indexes from the end (-1 is the last argument).\nOtherwise, <code>index</code> must be the string <code>\"#\"</code>,\nand <code>select</code> returns the total number of extra arguments it received.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-setmetatable\"><code>setmetatable (table, metatable)</code></a></h3>\n\n\n<p>\nSets the metatable for the given table.\n(To change the metatable of other types from Lua code,\nyou must use the debug library (<a href=\"#6.10\">&sect;6.10</a>).)\nIf <code>metatable</code> is <b>nil</b>,\nremoves the metatable of the given table.\nIf the original metatable has a <code>__metatable</code> field,\nraises an error.\n\n\n<p>\nThis function returns <code>table</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-tonumber\"><code>tonumber (e [, base])</code></a></h3>\n\n\n<p>\nWhen called with no <code>base</code>,\n<code>tonumber</code> tries to convert its argument to a number.\nIf the argument is already a number or\na string convertible to a number,\nthen <code>tonumber</code> returns this number;\notherwise, it returns <b>nil</b>.\n\n\n<p>\nThe conversion of strings can result in integers or floats,\naccording to the lexical conventions of Lua (see <a href=\"#3.1\">&sect;3.1</a>).\n(The string may have leading and trailing spaces and a sign.)\n\n\n<p>\nWhen called with <code>base</code>,\nthen <code>e</code> must be a string to be interpreted as\nan integer numeral in that base.\nThe base may be any integer between 2 and 36, inclusive.\nIn bases above&nbsp;10, the letter '<code>A</code>' (in either upper or lower case)\nrepresents&nbsp;10, '<code>B</code>' represents&nbsp;11, and so forth,\nwith '<code>Z</code>' representing 35.\nIf the string <code>e</code> is not a valid numeral in the given base,\nthe function returns <b>nil</b>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-tostring\"><code>tostring (v)</code></a></h3>\nReceives a value of any type and\nconverts it to a string in a human-readable format.\n(For complete control of how numbers are converted,\nuse <a href=\"#pdf-string.format\"><code>string.format</code></a>.)\n\n\n<p>\nIf the metatable of <code>v</code> has a <code>__tostring</code> field,\nthen <code>tostring</code> calls the corresponding value\nwith <code>v</code> as argument,\nand uses the result of the call as its result.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-type\"><code>type (v)</code></a></h3>\nReturns the type of its only argument, coded as a string.\nThe possible results of this function are\n\"<code>nil</code>\" (a string, not the value <b>nil</b>),\n\"<code>number</code>\",\n\"<code>string</code>\",\n\"<code>boolean</code>\",\n\"<code>table</code>\",\n\"<code>function</code>\",\n\"<code>thread</code>\",\nand \"<code>userdata</code>\".\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-_VERSION\"><code>_VERSION</code></a></h3>\n\n\n<p>\nA global variable (not a function) that\nholds a string containing the running Lua version.\nThe current value of this variable is \"<code>Lua 5.3</code>\".\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-xpcall\"><code>xpcall (f, msgh [, arg1, &middot;&middot;&middot;])</code></a></h3>\n\n\n<p>\nThis function is similar to <a href=\"#pdf-pcall\"><code>pcall</code></a>,\nexcept that it sets a new message handler <code>msgh</code>.\n\n\n\n\n\n\n\n<h2>6.2 &ndash; <a name=\"6.2\">Coroutine Manipulation</a></h2>\n\n<p>\nThis library comprises the operations to manipulate coroutines,\nwhich come inside the table <a name=\"pdf-coroutine\"><code>coroutine</code></a>.\nSee <a href=\"#2.6\">&sect;2.6</a> for a general description of coroutines.\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.create\"><code>coroutine.create (f)</code></a></h3>\n\n\n<p>\nCreates a new coroutine, with body <code>f</code>.\n<code>f</code> must be a function.\nReturns this new coroutine,\nan object with type <code>\"thread\"</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.isyieldable\"><code>coroutine.isyieldable ()</code></a></h3>\n\n\n<p>\nReturns true when the running coroutine can yield.\n\n\n<p>\nA running coroutine is yieldable if it is not the main thread and\nit is not inside a non-yieldable C&nbsp;function.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.resume\"><code>coroutine.resume (co [, val1, &middot;&middot;&middot;])</code></a></h3>\n\n\n<p>\nStarts or continues the execution of coroutine <code>co</code>.\nThe first time you resume a coroutine,\nit starts running its body.\nThe values <code>val1</code>, ... are passed\nas the arguments to the body function.\nIf the coroutine has yielded,\n<code>resume</code> restarts it;\nthe values <code>val1</code>, ... are passed\nas the results from the yield.\n\n\n<p>\nIf the coroutine runs without any errors,\n<code>resume</code> returns <b>true</b> plus any values passed to <code>yield</code>\n(when the coroutine yields) or any values returned by the body function\n(when the coroutine terminates).\nIf there is any error,\n<code>resume</code> returns <b>false</b> plus the error message.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.running\"><code>coroutine.running ()</code></a></h3>\n\n\n<p>\nReturns the running coroutine plus a boolean,\ntrue when the running coroutine is the main one.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.status\"><code>coroutine.status (co)</code></a></h3>\n\n\n<p>\nReturns the status of coroutine <code>co</code>, as a string:\n<code>\"running\"</code>,\nif the coroutine is running (that is, it called <code>status</code>);\n<code>\"suspended\"</code>, if the coroutine is suspended in a call to <code>yield</code>,\nor if it has not started running yet;\n<code>\"normal\"</code> if the coroutine is active but not running\n(that is, it has resumed another coroutine);\nand <code>\"dead\"</code> if the coroutine has finished its body function,\nor if it has stopped with an error.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.wrap\"><code>coroutine.wrap (f)</code></a></h3>\n\n\n<p>\nCreates a new coroutine, with body <code>f</code>.\n<code>f</code> must be a function.\nReturns a function that resumes the coroutine each time it is called.\nAny arguments passed to the function behave as the\nextra arguments to <code>resume</code>.\nReturns the same values returned by <code>resume</code>,\nexcept the first boolean.\nIn case of error, propagates the error.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-coroutine.yield\"><code>coroutine.yield (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nSuspends the execution of the calling coroutine.\nAny arguments to <code>yield</code> are passed as extra results to <code>resume</code>.\n\n\n\n\n\n\n\n<h2>6.3 &ndash; <a name=\"6.3\">Modules</a></h2>\n\n<p>\nThe package library provides basic\nfacilities for loading modules in Lua.\nIt exports one function directly in the global environment:\n<a href=\"#pdf-require\"><code>require</code></a>.\nEverything else is exported in a table <a name=\"pdf-package\"><code>package</code></a>.\n\n\n<p>\n<hr><h3><a name=\"pdf-require\"><code>require (modname)</code></a></h3>\n\n\n<p>\nLoads the given module.\nThe function starts by looking into the <a href=\"#pdf-package.loaded\"><code>package.loaded</code></a> table\nto determine whether <code>modname</code> is already loaded.\nIf it is, then <code>require</code> returns the value stored\nat <code>package.loaded[modname]</code>.\nOtherwise, it tries to find a <em>loader</em> for the module.\n\n\n<p>\nTo find a loader,\n<code>require</code> is guided by the <a href=\"#pdf-package.searchers\"><code>package.searchers</code></a> sequence.\nBy changing this sequence,\nwe can change how <code>require</code> looks for a module.\nThe following explanation is based on the default configuration\nfor <a href=\"#pdf-package.searchers\"><code>package.searchers</code></a>.\n\n\n<p>\nFirst <code>require</code> queries <code>package.preload[modname]</code>.\nIf it has a value,\nthis value (which must be a function) is the loader.\nOtherwise <code>require</code> searches for a Lua loader using the\npath stored in <a href=\"#pdf-package.path\"><code>package.path</code></a>.\nIf that also fails, it searches for a C&nbsp;loader using the\npath stored in <a href=\"#pdf-package.cpath\"><code>package.cpath</code></a>.\nIf that also fails,\nit tries an <em>all-in-one</em> loader (see <a href=\"#pdf-package.searchers\"><code>package.searchers</code></a>).\n\n\n<p>\nOnce a loader is found,\n<code>require</code> calls the loader with two arguments:\n<code>modname</code> and an extra value dependent on how it got the loader.\n(If the loader came from a file,\nthis extra value is the file name.)\nIf the loader returns any non-nil value,\n<code>require</code> assigns the returned value to <code>package.loaded[modname]</code>.\nIf the loader does not return a non-nil value and\nhas not assigned any value to <code>package.loaded[modname]</code>,\nthen <code>require</code> assigns <b>true</b> to this entry.\nIn any case, <code>require</code> returns the\nfinal value of <code>package.loaded[modname]</code>.\n\n\n<p>\nIf there is any error loading or running the module,\nor if it cannot find any loader for the module,\nthen <code>require</code> raises an error.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.config\"><code>package.config</code></a></h3>\n\n\n<p>\nA string describing some compile-time configurations for packages.\nThis string is a sequence of lines:\n\n<ul>\n\n<li>The first line is the directory separator string.\nDefault is '<code>\\</code>' for Windows and '<code>/</code>' for all other systems.</li>\n\n<li>The second line is the character that separates templates in a path.\nDefault is '<code>;</code>'.</li>\n\n<li>The third line is the string that marks the\nsubstitution points in a template.\nDefault is '<code>?</code>'.</li>\n\n<li>The fourth line is a string that, in a path in Windows,\nis replaced by the executable's directory.\nDefault is '<code>!</code>'.</li>\n\n<li>The fifth line is a mark to ignore all text after it\nwhen building the <code>luaopen_</code> function name.\nDefault is '<code>-</code>'.</li>\n\n</ul>\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.cpath\"><code>package.cpath</code></a></h3>\n\n\n<p>\nThe path used by <a href=\"#pdf-require\"><code>require</code></a> to search for a C&nbsp;loader.\n\n\n<p>\nLua initializes the C&nbsp;path <a href=\"#pdf-package.cpath\"><code>package.cpath</code></a> in the same way\nit initializes the Lua path <a href=\"#pdf-package.path\"><code>package.path</code></a>,\nusing the environment variable <a name=\"pdf-LUA_CPATH_5_3\"><code>LUA_CPATH_5_3</code></a>,\nor the environment variable <a name=\"pdf-LUA_CPATH\"><code>LUA_CPATH</code></a>,\nor a default path defined in <code>luaconf.h</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.loaded\"><code>package.loaded</code></a></h3>\n\n\n<p>\nA table used by <a href=\"#pdf-require\"><code>require</code></a> to control which\nmodules are already loaded.\nWhen you require a module <code>modname</code> and\n<code>package.loaded[modname]</code> is not false,\n<a href=\"#pdf-require\"><code>require</code></a> simply returns the value stored there.\n\n\n<p>\nThis variable is only a reference to the real table;\nassignments to this variable do not change the\ntable used by <a href=\"#pdf-require\"><code>require</code></a>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.loadlib\"><code>package.loadlib (libname, funcname)</code></a></h3>\n\n\n<p>\nDynamically links the host program with the C&nbsp;library <code>libname</code>.\n\n\n<p>\nIf <code>funcname</code> is \"<code>*</code>\",\nthen it only links with the library,\nmaking the symbols exported by the library\navailable to other dynamically linked libraries.\nOtherwise,\nit looks for a function <code>funcname</code> inside the library\nand returns this function as a C&nbsp;function.\nSo, <code>funcname</code> must follow the <a href=\"#lua_CFunction\"><code>lua_CFunction</code></a> prototype\n(see <a href=\"#lua_CFunction\"><code>lua_CFunction</code></a>).\n\n\n<p>\nThis is a low-level function.\nIt completely bypasses the package and module system.\nUnlike <a href=\"#pdf-require\"><code>require</code></a>,\nit does not perform any path searching and\ndoes not automatically adds extensions.\n<code>libname</code> must be the complete file name of the C&nbsp;library,\nincluding if necessary a path and an extension.\n<code>funcname</code> must be the exact name exported by the C&nbsp;library\n(which may depend on the C&nbsp;compiler and linker used).\n\n\n<p>\nThis function is not supported by Standard&nbsp;C.\nAs such, it is only available on some platforms\n(Windows, Linux, Mac OS X, Solaris, BSD,\nplus other Unix systems that support the <code>dlfcn</code> standard).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.path\"><code>package.path</code></a></h3>\n\n\n<p>\nThe path used by <a href=\"#pdf-require\"><code>require</code></a> to search for a Lua loader.\n\n\n<p>\nAt start-up, Lua initializes this variable with\nthe value of the environment variable <a name=\"pdf-LUA_PATH_5_3\"><code>LUA_PATH_5_3</code></a> or\nthe environment variable <a name=\"pdf-LUA_PATH\"><code>LUA_PATH</code></a> or\nwith a default path defined in <code>luaconf.h</code>,\nif those environment variables are not defined.\nAny \"<code>;;</code>\" in the value of the environment variable\nis replaced by the default path.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.preload\"><code>package.preload</code></a></h3>\n\n\n<p>\nA table to store loaders for specific modules\n(see <a href=\"#pdf-require\"><code>require</code></a>).\n\n\n<p>\nThis variable is only a reference to the real table;\nassignments to this variable do not change the\ntable used by <a href=\"#pdf-require\"><code>require</code></a>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.searchers\"><code>package.searchers</code></a></h3>\n\n\n<p>\nA table used by <a href=\"#pdf-require\"><code>require</code></a> to control how to load modules.\n\n\n<p>\nEach entry in this table is a <em>searcher function</em>.\nWhen looking for a module,\n<a href=\"#pdf-require\"><code>require</code></a> calls each of these searchers in ascending order,\nwith the module name (the argument given to <a href=\"#pdf-require\"><code>require</code></a>) as its\nsole parameter.\nThe function can return another function (the module <em>loader</em>)\nplus an extra value that will be passed to that loader,\nor a string explaining why it did not find that module\n(or <b>nil</b> if it has nothing to say).\n\n\n<p>\nLua initializes this table with four searcher functions.\n\n\n<p>\nThe first searcher simply looks for a loader in the\n<a href=\"#pdf-package.preload\"><code>package.preload</code></a> table.\n\n\n<p>\nThe second searcher looks for a loader as a Lua library,\nusing the path stored at <a href=\"#pdf-package.path\"><code>package.path</code></a>.\nThe search is done as described in function <a href=\"#pdf-package.searchpath\"><code>package.searchpath</code></a>.\n\n\n<p>\nThe third searcher looks for a loader as a C&nbsp;library,\nusing the path given by the variable <a href=\"#pdf-package.cpath\"><code>package.cpath</code></a>.\nAgain,\nthe search is done as described in function <a href=\"#pdf-package.searchpath\"><code>package.searchpath</code></a>.\nFor instance,\nif the C&nbsp;path is the string\n\n<pre>\n     \"./?.so;./?.dll;/usr/local/?/init.so\"\n</pre><p>\nthe searcher for module <code>foo</code>\nwill try to open the files <code>./foo.so</code>, <code>./foo.dll</code>,\nand <code>/usr/local/foo/init.so</code>, in that order.\nOnce it finds a C&nbsp;library,\nthis searcher first uses a dynamic link facility to link the\napplication with the library.\nThen it tries to find a C&nbsp;function inside the library to\nbe used as the loader.\nThe name of this C&nbsp;function is the string \"<code>luaopen_</code>\"\nconcatenated with a copy of the module name where each dot\nis replaced by an underscore.\nMoreover, if the module name has a hyphen,\nits suffix after (and including) the first hyphen is removed.\nFor instance, if the module name is <code>a.b.c-v2.1</code>,\nthe function name will be <code>luaopen_a_b_c</code>.\n\n\n<p>\nThe fourth searcher tries an <em>all-in-one loader</em>.\nIt searches the C&nbsp;path for a library for\nthe root name of the given module.\nFor instance, when requiring <code>a.b.c</code>,\nit will search for a C&nbsp;library for <code>a</code>.\nIf found, it looks into it for an open function for\nthe submodule;\nin our example, that would be <code>luaopen_a_b_c</code>.\nWith this facility, a package can pack several C&nbsp;submodules\ninto one single library,\nwith each submodule keeping its original open function.\n\n\n<p>\nAll searchers except the first one (preload) return as the extra value\nthe file name where the module was found,\nas returned by <a href=\"#pdf-package.searchpath\"><code>package.searchpath</code></a>.\nThe first searcher returns no extra value.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-package.searchpath\"><code>package.searchpath (name, path [, sep [, rep]])</code></a></h3>\n\n\n<p>\nSearches for the given <code>name</code> in the given <code>path</code>.\n\n\n<p>\nA path is a string containing a sequence of\n<em>templates</em> separated by semicolons.\nFor each template,\nthe function replaces each interrogation mark (if any)\nin the template with a copy of <code>name</code>\nwherein all occurrences of <code>sep</code>\n(a dot, by default)\nwere replaced by <code>rep</code>\n(the system's directory separator, by default),\nand then tries to open the resulting file name.\n\n\n<p>\nFor instance, if the path is the string\n\n<pre>\n     \"./?.lua;./?.lc;/usr/local/?/init.lua\"\n</pre><p>\nthe search for the name <code>foo.a</code>\nwill try to open the files\n<code>./foo/a.lua</code>, <code>./foo/a.lc</code>, and\n<code>/usr/local/foo/a/init.lua</code>, in that order.\n\n\n<p>\nReturns the resulting name of the first file that it can\nopen in read mode (after closing the file),\nor <b>nil</b> plus an error message if none succeeds.\n(This error message lists all file names it tried to open.)\n\n\n\n\n\n\n\n<h2>6.4 &ndash; <a name=\"6.4\">String Manipulation</a></h2>\n\n<p>\nThis library provides generic functions for string manipulation,\nsuch as finding and extracting substrings, and pattern matching.\nWhen indexing a string in Lua, the first character is at position&nbsp;1\n(not at&nbsp;0, as in C).\nIndices are allowed to be negative and are interpreted as indexing backwards,\nfrom the end of the string.\nThus, the last character is at position -1, and so on.\n\n\n<p>\nThe string library provides all its functions inside the table\n<a name=\"pdf-string\"><code>string</code></a>.\nIt also sets a metatable for strings\nwhere the <code>__index</code> field points to the <code>string</code> table.\nTherefore, you can use the string functions in object-oriented style.\nFor instance, <code>string.byte(s,i)</code>\ncan be written as <code>s:byte(i)</code>.\n\n\n<p>\nThe string library assumes one-byte character encodings.\n\n\n<p>\n<hr><h3><a name=\"pdf-string.byte\"><code>string.byte (s [, i [, j]])</code></a></h3>\nReturns the internal numeric codes of the characters <code>s[i]</code>,\n<code>s[i+1]</code>, ..., <code>s[j]</code>.\nThe default value for <code>i</code> is&nbsp;1;\nthe default value for <code>j</code> is&nbsp;<code>i</code>.\nThese indices are corrected\nfollowing the same rules of function <a href=\"#pdf-string.sub\"><code>string.sub</code></a>.\n\n\n<p>\nNumeric codes are not necessarily portable across platforms.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.char\"><code>string.char (&middot;&middot;&middot;)</code></a></h3>\nReceives zero or more integers.\nReturns a string with length equal to the number of arguments,\nin which each character has the internal numeric code equal\nto its corresponding argument.\n\n\n<p>\nNumeric codes are not necessarily portable across platforms.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.dump\"><code>string.dump (function [, strip])</code></a></h3>\n\n\n<p>\nReturns a string containing a binary representation\n(a <em>binary chunk</em>)\nof the given function,\nso that a later <a href=\"#pdf-load\"><code>load</code></a> on this string returns\na copy of the function (but with new upvalues).\nIf <code>strip</code> is a true value,\nthe binary representation may not include all debug information\nabout the function,\nto save space.\n\n\n<p>\nFunctions with upvalues have only their number of upvalues saved.\nWhen (re)loaded,\nthose upvalues receive fresh instances containing <b>nil</b>.\n(You can use the debug library to serialize\nand reload the upvalues of a function\nin a way adequate to your needs.)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.find\"><code>string.find (s, pattern [, init [, plain]])</code></a></h3>\n\n\n<p>\nLooks for the first match of\n<code>pattern</code> (see <a href=\"#6.4.1\">&sect;6.4.1</a>) in the string <code>s</code>.\nIf it finds a match, then <code>find</code> returns the indices of&nbsp;<code>s</code>\nwhere this occurrence starts and ends;\notherwise, it returns <b>nil</b>.\nA third, optional numeric argument <code>init</code> specifies\nwhere to start the search;\nits default value is&nbsp;1 and can be negative.\nA value of <b>true</b> as a fourth, optional argument <code>plain</code>\nturns off the pattern matching facilities,\nso the function does a plain \"find substring\" operation,\nwith no characters in <code>pattern</code> being considered magic.\nNote that if <code>plain</code> is given, then <code>init</code> must be given as well.\n\n\n<p>\nIf the pattern has captures,\nthen in a successful match\nthe captured values are also returned,\nafter the two indices.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.format\"><code>string.format (formatstring, &middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReturns a formatted version of its variable number of arguments\nfollowing the description given in its first argument (which must be a string).\nThe format string follows the same rules as the ISO&nbsp;C function <code>sprintf</code>.\nThe only differences are that the options/modifiers\n<code>*</code>, <code>h</code>, <code>L</code>, <code>l</code>, <code>n</code>,\nand <code>p</code> are not supported\nand that there is an extra option, <code>q</code>.\n\n\n<p>\nThe <code>q</code> option formats a string between double quotes,\nusing escape sequences when necessary to ensure that\nit can safely be read back by the Lua interpreter.\nFor instance, the call\n\n<pre>\n     string.format('%q', 'a string with \"quotes\" and \\n new line')\n</pre><p>\nmay produce the string:\n\n<pre>\n     \"a string with \\\"quotes\\\" and \\\n      new line\"\n</pre>\n\n<p>\nOptions\n<code>A</code>, <code>a</code>, <code>E</code>, <code>e</code>, <code>f</code>,\n<code>G</code>, and <code>g</code> all expect a number as argument.\nOptions <code>c</code>, <code>d</code>,\n<code>i</code>, <code>o</code>, <code>u</code>, <code>X</code>, and <code>x</code>\nexpect an integer.\nWhen Lua is compiled with a C89 compiler,\noptions <code>A</code> and <code>a</code> (hexadecimal floats)\ndo not support any modifier (flags, width, length).\n\n\n<p>\nOption <code>s</code> expects a string;\nif its argument is not a string,\nit is converted to one following the same rules of <a href=\"#pdf-tostring\"><code>tostring</code></a>.\nIf the option has any modifier (flags, width, length),\nthe string argument should not contain embedded zeros.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.gmatch\"><code>string.gmatch (s, pattern)</code></a></h3>\nReturns an iterator function that,\neach time it is called,\nreturns the next captures from <code>pattern</code> (see <a href=\"#6.4.1\">&sect;6.4.1</a>)\nover the string <code>s</code>.\nIf <code>pattern</code> specifies no captures,\nthen the whole match is produced in each call.\n\n\n<p>\nAs an example, the following loop\nwill iterate over all the words from string <code>s</code>,\nprinting one per line:\n\n<pre>\n     s = \"hello world from Lua\"\n     for w in string.gmatch(s, \"%a+\") do\n       print(w)\n     end\n</pre><p>\nThe next example collects all pairs <code>key=value</code> from the\ngiven string into a table:\n\n<pre>\n     t = {}\n     s = \"from=world, to=Lua\"\n     for k, v in string.gmatch(s, \"(%w+)=(%w+)\") do\n       t[k] = v\n     end\n</pre>\n\n<p>\nFor this function, a caret '<code>^</code>' at the start of a pattern does not\nwork as an anchor, as this would prevent the iteration.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.gsub\"><code>string.gsub (s, pattern, repl [, n])</code></a></h3>\nReturns a copy of <code>s</code>\nin which all (or the first <code>n</code>, if given)\noccurrences of the <code>pattern</code> (see <a href=\"#6.4.1\">&sect;6.4.1</a>) have been\nreplaced by a replacement string specified by <code>repl</code>,\nwhich can be a string, a table, or a function.\n<code>gsub</code> also returns, as its second value,\nthe total number of matches that occurred.\nThe name <code>gsub</code> comes from <em>Global SUBstitution</em>.\n\n\n<p>\nIf <code>repl</code> is a string, then its value is used for replacement.\nThe character&nbsp;<code>%</code> works as an escape character:\nany sequence in <code>repl</code> of the form <code>%<em>d</em></code>,\nwith <em>d</em> between 1 and 9,\nstands for the value of the <em>d</em>-th captured substring.\nThe sequence <code>%0</code> stands for the whole match.\nThe sequence <code>%%</code> stands for a single&nbsp;<code>%</code>.\n\n\n<p>\nIf <code>repl</code> is a table, then the table is queried for every match,\nusing the first capture as the key.\n\n\n<p>\nIf <code>repl</code> is a function, then this function is called every time a\nmatch occurs, with all captured substrings passed as arguments,\nin order.\n\n\n<p>\nIn any case,\nif the pattern specifies no captures,\nthen it behaves as if the whole pattern was inside a capture.\n\n\n<p>\nIf the value returned by the table query or by the function call\nis a string or a number,\nthen it is used as the replacement string;\notherwise, if it is <b>false</b> or <b>nil</b>,\nthen there is no replacement\n(that is, the original match is kept in the string).\n\n\n<p>\nHere are some examples:\n\n<pre>\n     x = string.gsub(\"hello world\", \"(%w+)\", \"%1 %1\")\n     --&gt; x=\"hello hello world world\"\n     \n     x = string.gsub(\"hello world\", \"%w+\", \"%0 %0\", 1)\n     --&gt; x=\"hello hello world\"\n     \n     x = string.gsub(\"hello world from Lua\", \"(%w+)%s*(%w+)\", \"%2 %1\")\n     --&gt; x=\"world hello Lua from\"\n     \n     x = string.gsub(\"home = $HOME, user = $USER\", \"%$(%w+)\", os.getenv)\n     --&gt; x=\"home = /home/roberto, user = roberto\"\n     \n     x = string.gsub(\"4+5 = $return 4+5$\", \"%$(.-)%$\", function (s)\n           return load(s)()\n         end)\n     --&gt; x=\"4+5 = 9\"\n     \n     local t = {name=\"lua\", version=\"5.3\"}\n     x = string.gsub(\"$name-$version.tar.gz\", \"%$(%w+)\", t)\n     --&gt; x=\"lua-5.3.tar.gz\"\n</pre>\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.len\"><code>string.len (s)</code></a></h3>\nReceives a string and returns its length.\nThe empty string <code>\"\"</code> has length 0.\nEmbedded zeros are counted,\nso <code>\"a\\000bc\\000\"</code> has length 5.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.lower\"><code>string.lower (s)</code></a></h3>\nReceives a string and returns a copy of this string with all\nuppercase letters changed to lowercase.\nAll other characters are left unchanged.\nThe definition of what an uppercase letter is depends on the current locale.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.match\"><code>string.match (s, pattern [, init])</code></a></h3>\nLooks for the first <em>match</em> of\n<code>pattern</code> (see <a href=\"#6.4.1\">&sect;6.4.1</a>) in the string <code>s</code>.\nIf it finds one, then <code>match</code> returns\nthe captures from the pattern;\notherwise it returns <b>nil</b>.\nIf <code>pattern</code> specifies no captures,\nthen the whole match is returned.\nA third, optional numeric argument <code>init</code> specifies\nwhere to start the search;\nits default value is&nbsp;1 and can be negative.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.pack\"><code>string.pack (fmt, v1, v2, &middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReturns a binary string containing the values <code>v1</code>, <code>v2</code>, etc.\npacked (that is, serialized in binary form)\naccording to the format string <code>fmt</code> (see <a href=\"#6.4.2\">&sect;6.4.2</a>).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.packsize\"><code>string.packsize (fmt)</code></a></h3>\n\n\n<p>\nReturns the size of a string resulting from <a href=\"#pdf-string.pack\"><code>string.pack</code></a>\nwith the given format.\nThe format string cannot have the variable-length options\n'<code>s</code>' or '<code>z</code>' (see <a href=\"#6.4.2\">&sect;6.4.2</a>).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.rep\"><code>string.rep (s, n [, sep])</code></a></h3>\nReturns a string that is the concatenation of <code>n</code> copies of\nthe string <code>s</code> separated by the string <code>sep</code>.\nThe default value for <code>sep</code> is the empty string\n(that is, no separator).\nReturns the empty string if <code>n</code> is not positive.\n\n\n<p>\n(Note that it is very easy to exhaust the memory of your machine\nwith a single call to this function.)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.reverse\"><code>string.reverse (s)</code></a></h3>\nReturns a string that is the string <code>s</code> reversed.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.sub\"><code>string.sub (s, i [, j])</code></a></h3>\nReturns the substring of <code>s</code> that\nstarts at <code>i</code>  and continues until <code>j</code>;\n<code>i</code> and <code>j</code> can be negative.\nIf <code>j</code> is absent, then it is assumed to be equal to -1\n(which is the same as the string length).\nIn particular,\nthe call <code>string.sub(s,1,j)</code> returns a prefix of <code>s</code>\nwith length <code>j</code>,\nand <code>string.sub(s, -i)</code> (for a positive <code>i</code>)\nreturns a suffix of <code>s</code>\nwith length <code>i</code>.\n\n\n<p>\nIf, after the translation of negative indices,\n<code>i</code> is less than 1,\nit is corrected to 1.\nIf <code>j</code> is greater than the string length,\nit is corrected to that length.\nIf, after these corrections,\n<code>i</code> is greater than <code>j</code>,\nthe function returns the empty string.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.unpack\"><code>string.unpack (fmt, s [, pos])</code></a></h3>\n\n\n<p>\nReturns the values packed in string <code>s</code> (see <a href=\"#pdf-string.pack\"><code>string.pack</code></a>)\naccording to the format string <code>fmt</code> (see <a href=\"#6.4.2\">&sect;6.4.2</a>).\nAn optional <code>pos</code> marks where\nto start reading in <code>s</code> (default is 1).\nAfter the read values,\nthis function also returns the index of the first unread byte in <code>s</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-string.upper\"><code>string.upper (s)</code></a></h3>\nReceives a string and returns a copy of this string with all\nlowercase letters changed to uppercase.\nAll other characters are left unchanged.\nThe definition of what a lowercase letter is depends on the current locale.\n\n\n\n\n\n<h3>6.4.1 &ndash; <a name=\"6.4.1\">Patterns</a></h3>\n\n<p>\nPatterns in Lua are described by regular strings,\nwhich are interpreted as patterns by the pattern-matching functions\n<a href=\"#pdf-string.find\"><code>string.find</code></a>,\n<a href=\"#pdf-string.gmatch\"><code>string.gmatch</code></a>,\n<a href=\"#pdf-string.gsub\"><code>string.gsub</code></a>,\nand <a href=\"#pdf-string.match\"><code>string.match</code></a>.\nThis section describes the syntax and the meaning\n(that is, what they match) of these strings.\n\n\n\n<h4>Character Class:</h4><p>\nA <em>character class</em> is used to represent a set of characters.\nThe following combinations are allowed in describing a character class:\n\n<ul>\n\n<li><b><em>x</em>: </b>\n(where <em>x</em> is not one of the <em>magic characters</em>\n<code>^$()%.[]*+-?</code>)\nrepresents the character <em>x</em> itself.\n</li>\n\n<li><b><code>.</code>: </b> (a dot) represents all characters.</li>\n\n<li><b><code>%a</code>: </b> represents all letters.</li>\n\n<li><b><code>%c</code>: </b> represents all control characters.</li>\n\n<li><b><code>%d</code>: </b> represents all digits.</li>\n\n<li><b><code>%g</code>: </b> represents all printable characters except space.</li>\n\n<li><b><code>%l</code>: </b> represents all lowercase letters.</li>\n\n<li><b><code>%p</code>: </b> represents all punctuation characters.</li>\n\n<li><b><code>%s</code>: </b> represents all space characters.</li>\n\n<li><b><code>%u</code>: </b> represents all uppercase letters.</li>\n\n<li><b><code>%w</code>: </b> represents all alphanumeric characters.</li>\n\n<li><b><code>%x</code>: </b> represents all hexadecimal digits.</li>\n\n<li><b><code>%<em>x</em></code>: </b> (where <em>x</em> is any non-alphanumeric character)\nrepresents the character <em>x</em>.\nThis is the standard way to escape the magic characters.\nAny non-alphanumeric character\n(including all punctuation characters, even the non-magical)\ncan be preceded by a '<code>%</code>'\nwhen used to represent itself in a pattern.\n</li>\n\n<li><b><code>[<em>set</em>]</code>: </b>\nrepresents the class which is the union of all\ncharacters in <em>set</em>.\nA range of characters can be specified by\nseparating the end characters of the range,\nin ascending order, with a '<code>-</code>'.\nAll classes <code>%</code><em>x</em> described above can also be used as\ncomponents in <em>set</em>.\nAll other characters in <em>set</em> represent themselves.\nFor example, <code>[%w_]</code> (or <code>[_%w]</code>)\nrepresents all alphanumeric characters plus the underscore,\n<code>[0-7]</code> represents the octal digits,\nand <code>[0-7%l%-]</code> represents the octal digits plus\nthe lowercase letters plus the '<code>-</code>' character.\n\n\n<p>\nYou can put a closing square bracket in a set\nby positioning it as the first character in the set.\nYou can put a hyphen in a set\nby positioning it as the first or the last character in the set.\n(You can also use an escape for both cases.)\n\n\n<p>\nThe interaction between ranges and classes is not defined.\nTherefore, patterns like <code>[%a-z]</code> or <code>[a-%%]</code>\nhave no meaning.\n</li>\n\n<li><b><code>[^<em>set</em>]</code>: </b>\nrepresents the complement of <em>set</em>,\nwhere <em>set</em> is interpreted as above.\n</li>\n\n</ul><p>\nFor all classes represented by single letters (<code>%a</code>, <code>%c</code>, etc.),\nthe corresponding uppercase letter represents the complement of the class.\nFor instance, <code>%S</code> represents all non-space characters.\n\n\n<p>\nThe definitions of letter, space, and other character groups\ndepend on the current locale.\nIn particular, the class <code>[a-z]</code> may not be equivalent to <code>%l</code>.\n\n\n\n\n\n<h4>Pattern Item:</h4><p>\nA <em>pattern item</em> can be\n\n<ul>\n\n<li>\na single character class,\nwhich matches any single character in the class;\n</li>\n\n<li>\na single character class followed by '<code>*</code>',\nwhich matches zero or more repetitions of characters in the class.\nThese repetition items will always match the longest possible sequence;\n</li>\n\n<li>\na single character class followed by '<code>+</code>',\nwhich matches one or more repetitions of characters in the class.\nThese repetition items will always match the longest possible sequence;\n</li>\n\n<li>\na single character class followed by '<code>-</code>',\nwhich also matches zero or more repetitions of characters in the class.\nUnlike '<code>*</code>',\nthese repetition items will always match the shortest possible sequence;\n</li>\n\n<li>\na single character class followed by '<code>?</code>',\nwhich matches zero or one occurrence of a character in the class.\nIt always matches one occurrence if possible;\n</li>\n\n<li>\n<code>%<em>n</em></code>, for <em>n</em> between 1 and 9;\nsuch item matches a substring equal to the <em>n</em>-th captured string\n(see below);\n</li>\n\n<li>\n<code>%b<em>xy</em></code>, where <em>x</em> and <em>y</em> are two distinct characters;\nsuch item matches strings that start with&nbsp;<em>x</em>, end with&nbsp;<em>y</em>,\nand where the <em>x</em> and <em>y</em> are <em>balanced</em>.\nThis means that, if one reads the string from left to right,\ncounting <em>+1</em> for an <em>x</em> and <em>-1</em> for a <em>y</em>,\nthe ending <em>y</em> is the first <em>y</em> where the count reaches 0.\nFor instance, the item <code>%b()</code> matches expressions with\nbalanced parentheses.\n</li>\n\n<li>\n<code>%f[<em>set</em>]</code>, a <em>frontier pattern</em>;\nsuch item matches an empty string at any position such that\nthe next character belongs to <em>set</em>\nand the previous character does not belong to <em>set</em>.\nThe set <em>set</em> is interpreted as previously described.\nThe beginning and the end of the subject are handled as if\nthey were the character '<code>\\0</code>'.\n</li>\n\n</ul>\n\n\n\n\n<h4>Pattern:</h4><p>\nA <em>pattern</em> is a sequence of pattern items.\nA caret '<code>^</code>' at the beginning of a pattern anchors the match at the\nbeginning of the subject string.\nA '<code>$</code>' at the end of a pattern anchors the match at the\nend of the subject string.\nAt other positions,\n'<code>^</code>' and '<code>$</code>' have no special meaning and represent themselves.\n\n\n\n\n\n<h4>Captures:</h4><p>\nA pattern can contain sub-patterns enclosed in parentheses;\nthey describe <em>captures</em>.\nWhen a match succeeds, the substrings of the subject string\nthat match captures are stored (<em>captured</em>) for future use.\nCaptures are numbered according to their left parentheses.\nFor instance, in the pattern <code>\"(a*(.)%w(%s*))\"</code>,\nthe part of the string matching <code>\"a*(.)%w(%s*)\"</code> is\nstored as the first capture (and therefore has number&nbsp;1);\nthe character matching \"<code>.</code>\" is captured with number&nbsp;2,\nand the part matching \"<code>%s*</code>\" has number&nbsp;3.\n\n\n<p>\nAs a special case, the empty capture <code>()</code> captures\nthe current string position (a number).\nFor instance, if we apply the pattern <code>\"()aa()\"</code> on the\nstring <code>\"flaaap\"</code>, there will be two captures: 3&nbsp;and&nbsp;5.\n\n\n\n\n\n\n\n<h3>6.4.2 &ndash; <a name=\"6.4.2\">Format Strings for Pack and Unpack</a></h3>\n\n<p>\nThe first argument to <a href=\"#pdf-string.pack\"><code>string.pack</code></a>,\n<a href=\"#pdf-string.packsize\"><code>string.packsize</code></a>, and <a href=\"#pdf-string.unpack\"><code>string.unpack</code></a>\nis a format string,\nwhich describes the layout of the structure being created or read.\n\n\n<p>\nA format string is a sequence of conversion options.\nThe conversion options are as follows:\n\n<ul>\n<li><b><code>&lt;</code>: </b>sets little endian</li>\n<li><b><code>&gt;</code>: </b>sets big endian</li>\n<li><b><code>=</code>: </b>sets native endian</li>\n<li><b><code>![<em>n</em>]</code>: </b>sets maximum alignment to <code>n</code>\n(default is native alignment)</li>\n<li><b><code>b</code>: </b>a signed byte (<code>char</code>)</li>\n<li><b><code>B</code>: </b>an unsigned byte (<code>char</code>)</li>\n<li><b><code>h</code>: </b>a signed <code>short</code> (native size)</li>\n<li><b><code>H</code>: </b>an unsigned <code>short</code> (native size)</li>\n<li><b><code>l</code>: </b>a signed <code>long</code> (native size)</li>\n<li><b><code>L</code>: </b>an unsigned <code>long</code> (native size)</li>\n<li><b><code>j</code>: </b>a <code>lua_Integer</code></li>\n<li><b><code>J</code>: </b>a <code>lua_Unsigned</code></li>\n<li><b><code>T</code>: </b>a <code>size_t</code> (native size)</li>\n<li><b><code>i[<em>n</em>]</code>: </b>a signed <code>int</code> with <code>n</code> bytes\n(default is native size)</li>\n<li><b><code>I[<em>n</em>]</code>: </b>an unsigned <code>int</code> with <code>n</code> bytes\n(default is native size)</li>\n<li><b><code>f</code>: </b>a <code>float</code> (native size)</li>\n<li><b><code>d</code>: </b>a <code>double</code> (native size)</li>\n<li><b><code>n</code>: </b>a <code>lua_Number</code></li>\n<li><b><code>c<em>n</em></code>: </b>a fixed-sized string with <code>n</code> bytes</li>\n<li><b><code>z</code>: </b>a zero-terminated string</li>\n<li><b><code>s[<em>n</em>]</code>: </b>a string preceded by its length\ncoded as an unsigned integer with <code>n</code> bytes\n(default is a <code>size_t</code>)</li>\n<li><b><code>x</code>: </b>one byte of padding</li>\n<li><b><code>X<em>op</em></code>: </b>an empty item that aligns\naccording to option <code>op</code>\n(which is otherwise ignored)</li>\n<li><b>'<code> </code>': </b>(empty space) ignored</li>\n</ul><p>\n(A \"<code>[<em>n</em>]</code>\" means an optional integral numeral.)\nExcept for padding, spaces, and configurations\n(options \"<code>xX &lt;=&gt;!</code>\"),\neach option corresponds to an argument (in <a href=\"#pdf-string.pack\"><code>string.pack</code></a>)\nor a result (in <a href=\"#pdf-string.unpack\"><code>string.unpack</code></a>).\n\n\n<p>\nFor options \"<code>!<em>n</em></code>\", \"<code>s<em>n</em></code>\", \"<code>i<em>n</em></code>\", and \"<code>I<em>n</em></code>\",\n<code>n</code> can be any integer between 1 and 16.\nAll integral options check overflows;\n<a href=\"#pdf-string.pack\"><code>string.pack</code></a> checks whether the given value fits in the given size;\n<a href=\"#pdf-string.unpack\"><code>string.unpack</code></a> checks whether the read value fits in a Lua integer.\n\n\n<p>\nAny format string starts as if prefixed by \"<code>!1=</code>\",\nthat is,\nwith maximum alignment of 1 (no alignment)\nand native endianness.\n\n\n<p>\nAlignment works as follows:\nFor each option,\nthe format gets extra padding until the data starts\nat an offset that is a multiple of the minimum between the\noption size and the maximum alignment;\nthis minimum must be a power of 2.\nOptions \"<code>c</code>\" and \"<code>z</code>\" are not aligned;\noption \"<code>s</code>\" follows the alignment of its starting integer.\n\n\n<p>\nAll padding is filled with zeros by <a href=\"#pdf-string.pack\"><code>string.pack</code></a>\n(and ignored by <a href=\"#pdf-string.unpack\"><code>string.unpack</code></a>).\n\n\n\n\n\n\n\n<h2>6.5 &ndash; <a name=\"6.5\">UTF-8 Support</a></h2>\n\n<p>\nThis library provides basic support for UTF-8 encoding.\nIt provides all its functions inside the table <a name=\"pdf-utf8\"><code>utf8</code></a>.\nThis library does not provide any support for Unicode other\nthan the handling of the encoding.\nAny operation that needs the meaning of a character,\nsuch as character classification, is outside its scope.\n\n\n<p>\nUnless stated otherwise,\nall functions that expect a byte position as a parameter\nassume that the given position is either the start of a byte sequence\nor one plus the length of the subject string.\nAs in the string library,\nnegative indices count from the end of the string.\n\n\n<p>\n<hr><h3><a name=\"pdf-utf8.char\"><code>utf8.char (&middot;&middot;&middot;)</code></a></h3>\nReceives zero or more integers,\nconverts each one to its corresponding UTF-8 byte sequence\nand returns a string with the concatenation of all these sequences.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-utf8.charpattern\"><code>utf8.charpattern</code></a></h3>\nThe pattern (a string, not a function) \"<code>[\\0-\\x7F\\xC2-\\xF4][\\x80-\\xBF]*</code>\"\n(see <a href=\"#6.4.1\">&sect;6.4.1</a>),\nwhich matches exactly one UTF-8 byte sequence,\nassuming that the subject is a valid UTF-8 string.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-utf8.codes\"><code>utf8.codes (s)</code></a></h3>\n\n\n<p>\nReturns values so that the construction\n\n<pre>\n     for p, c in utf8.codes(s) do <em>body</em> end\n</pre><p>\nwill iterate over all characters in string <code>s</code>,\nwith <code>p</code> being the position (in bytes) and <code>c</code> the code point\nof each character.\nIt raises an error if it meets any invalid byte sequence.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-utf8.codepoint\"><code>utf8.codepoint (s [, i [, j]])</code></a></h3>\nReturns the codepoints (as integers) from all characters in <code>s</code>\nthat start between byte position <code>i</code> and <code>j</code> (both included).\nThe default for <code>i</code> is 1 and for <code>j</code> is <code>i</code>.\nIt raises an error if it meets any invalid byte sequence.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-utf8.len\"><code>utf8.len (s [, i [, j]])</code></a></h3>\nReturns the number of UTF-8 characters in string <code>s</code>\nthat start between positions <code>i</code> and <code>j</code> (both inclusive).\nThe default for <code>i</code> is 1 and for <code>j</code> is -1.\nIf it finds any invalid byte sequence,\nreturns a false value plus the position of the first invalid byte.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-utf8.offset\"><code>utf8.offset (s, n [, i])</code></a></h3>\nReturns the position (in bytes) where the encoding of the\n<code>n</code>-th character of <code>s</code>\n(counting from position <code>i</code>) starts.\nA negative <code>n</code> gets characters before position <code>i</code>.\nThe default for <code>i</code> is 1 when <code>n</code> is non-negative\nand <code>#s + 1</code> otherwise,\nso that <code>utf8.offset(s, -n)</code> gets the offset of the\n<code>n</code>-th character from the end of the string.\nIf the specified character is neither in the subject\nnor right after its end,\nthe function returns <b>nil</b>.\n\n\n<p>\nAs a special case,\nwhen <code>n</code> is 0 the function returns the start of the encoding\nof the character that contains the <code>i</code>-th byte of <code>s</code>.\n\n\n<p>\nThis function assumes that <code>s</code> is a valid UTF-8 string.\n\n\n\n\n\n\n\n<h2>6.6 &ndash; <a name=\"6.6\">Table Manipulation</a></h2>\n\n<p>\nThis library provides generic functions for table manipulation.\nIt provides all its functions inside the table <a name=\"pdf-table\"><code>table</code></a>.\n\n\n<p>\nRemember that, whenever an operation needs the length of a table,\nall caveats about the length operator apply (see <a href=\"#3.4.7\">&sect;3.4.7</a>).\nAll functions ignore non-numeric keys\nin the tables given as arguments.\n\n\n<p>\n<hr><h3><a name=\"pdf-table.concat\"><code>table.concat (list [, sep [, i [, j]]])</code></a></h3>\n\n\n<p>\nGiven a list where all elements are strings or numbers,\nreturns the string <code>list[i]..sep..list[i+1] &middot;&middot;&middot; sep..list[j]</code>.\nThe default value for <code>sep</code> is the empty string,\nthe default for <code>i</code> is 1,\nand the default for <code>j</code> is <code>#list</code>.\nIf <code>i</code> is greater than <code>j</code>, returns the empty string.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-table.insert\"><code>table.insert (list, [pos,] value)</code></a></h3>\n\n\n<p>\nInserts element <code>value</code> at position <code>pos</code> in <code>list</code>,\nshifting up the elements\n<code>list[pos], list[pos+1], &middot;&middot;&middot;, list[#list]</code>.\nThe default value for <code>pos</code> is <code>#list+1</code>,\nso that a call <code>table.insert(t,x)</code> inserts <code>x</code> at the end\nof list <code>t</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-table.move\"><code>table.move (a1, f, e, t [,a2])</code></a></h3>\n\n\n<p>\nMoves elements from table <code>a1</code> to table <code>a2</code>,\nperforming the equivalent to the following\nmultiple assignment:\n<code>a2[t],&middot;&middot;&middot; = a1[f],&middot;&middot;&middot;,a1[e]</code>.\nThe default for <code>a2</code> is <code>a1</code>.\nThe destination range can overlap with the source range.\nThe number of elements to be moved must fit in a Lua integer.\n\n\n<p>\nReturns the destination table <code>a2</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-table.pack\"><code>table.pack (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReturns a new table with all arguments stored into keys 1, 2, etc.\nand with a field \"<code>n</code>\" with the total number of arguments.\nNote that the resulting table may not be a sequence.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-table.remove\"><code>table.remove (list [, pos])</code></a></h3>\n\n\n<p>\nRemoves from <code>list</code> the element at position <code>pos</code>,\nreturning the value of the removed element.\nWhen <code>pos</code> is an integer between 1 and <code>#list</code>,\nit shifts down the elements\n<code>list[pos+1], list[pos+2], &middot;&middot;&middot;, list[#list]</code>\nand erases element <code>list[#list]</code>;\nThe index <code>pos</code> can also be 0 when <code>#list</code> is 0,\nor <code>#list + 1</code>;\nin those cases, the function erases the element <code>list[pos]</code>.\n\n\n<p>\nThe default value for <code>pos</code> is <code>#list</code>,\nso that a call <code>table.remove(l)</code> removes the last element\nof list <code>l</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-table.sort\"><code>table.sort (list [, comp])</code></a></h3>\n\n\n<p>\nSorts list elements in a given order, <em>in-place</em>,\nfrom <code>list[1]</code> to <code>list[#list]</code>.\nIf <code>comp</code> is given,\nthen it must be a function that receives two list elements\nand returns true when the first element must come\nbefore the second in the final order\n(so that, after the sort,\n<code>i &lt; j</code> implies <code>not comp(list[j],list[i])</code>).\nIf <code>comp</code> is not given,\nthen the standard Lua operator <code>&lt;</code> is used instead.\n\n\n<p>\nNote that the <code>comp</code> function must define\na strict partial order over the elements in the list;\nthat is, it must be asymmetric and transitive.\nOtherwise, no valid sort may be possible.\n\n\n<p>\nThe sort algorithm is not stable:\nelements considered equal by the given order\nmay have their relative positions changed by the sort.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-table.unpack\"><code>table.unpack (list [, i [, j]])</code></a></h3>\n\n\n<p>\nReturns the elements from the given list.\nThis function is equivalent to\n\n<pre>\n     return list[i], list[i+1], &middot;&middot;&middot;, list[j]\n</pre><p>\nBy default, <code>i</code> is&nbsp;1 and <code>j</code> is <code>#list</code>.\n\n\n\n\n\n\n\n<h2>6.7 &ndash; <a name=\"6.7\">Mathematical Functions</a></h2>\n\n<p>\nThis library provides basic mathematical functions.\nIt provides all its functions and constants inside the table <a name=\"pdf-math\"><code>math</code></a>.\nFunctions with the annotation \"<code>integer/float</code>\" give\ninteger results for integer arguments\nand float results for float (or mixed) arguments.\nRounding functions\n(<a href=\"#pdf-math.ceil\"><code>math.ceil</code></a>, <a href=\"#pdf-math.floor\"><code>math.floor</code></a>, and <a href=\"#pdf-math.modf\"><code>math.modf</code></a>)\nreturn an integer when the result fits in the range of an integer,\nor a float otherwise.\n\n\n<p>\n<hr><h3><a name=\"pdf-math.abs\"><code>math.abs (x)</code></a></h3>\n\n\n<p>\nReturns the absolute value of <code>x</code>. (integer/float)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.acos\"><code>math.acos (x)</code></a></h3>\n\n\n<p>\nReturns the arc cosine of <code>x</code> (in radians).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.asin\"><code>math.asin (x)</code></a></h3>\n\n\n<p>\nReturns the arc sine of <code>x</code> (in radians).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.atan\"><code>math.atan (y [, x])</code></a></h3>\n\n\n<p>\n\nReturns the arc tangent of <code>y/x</code> (in radians),\nbut uses the signs of both arguments to find the\nquadrant of the result.\n(It also handles correctly the case of <code>x</code> being zero.)\n\n\n<p>\nThe default value for <code>x</code> is 1,\nso that the call <code>math.atan(y)</code>\nreturns the arc tangent of <code>y</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.ceil\"><code>math.ceil (x)</code></a></h3>\n\n\n<p>\nReturns the smallest integral value larger than or equal to <code>x</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.cos\"><code>math.cos (x)</code></a></h3>\n\n\n<p>\nReturns the cosine of <code>x</code> (assumed to be in radians).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.deg\"><code>math.deg (x)</code></a></h3>\n\n\n<p>\nConverts the angle <code>x</code> from radians to degrees.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.exp\"><code>math.exp (x)</code></a></h3>\n\n\n<p>\nReturns the value <em>e<sup>x</sup></em>\n(where <code>e</code> is the base of natural logarithms).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.floor\"><code>math.floor (x)</code></a></h3>\n\n\n<p>\nReturns the largest integral value smaller than or equal to <code>x</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.fmod\"><code>math.fmod (x, y)</code></a></h3>\n\n\n<p>\nReturns the remainder of the division of <code>x</code> by <code>y</code>\nthat rounds the quotient towards zero. (integer/float)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.huge\"><code>math.huge</code></a></h3>\n\n\n<p>\nThe float value <code>HUGE_VAL</code>,\na value larger than any other numeric value.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.log\"><code>math.log (x [, base])</code></a></h3>\n\n\n<p>\nReturns the logarithm of <code>x</code> in the given base.\nThe default for <code>base</code> is <em>e</em>\n(so that the function returns the natural logarithm of <code>x</code>).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.max\"><code>math.max (x, &middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReturns the argument with the maximum value,\naccording to the Lua operator <code>&lt;</code>. (integer/float)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.maxinteger\"><code>math.maxinteger</code></a></h3>\nAn integer with the maximum value for an integer.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.min\"><code>math.min (x, &middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReturns the argument with the minimum value,\naccording to the Lua operator <code>&lt;</code>. (integer/float)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.mininteger\"><code>math.mininteger</code></a></h3>\nAn integer with the minimum value for an integer.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.modf\"><code>math.modf (x)</code></a></h3>\n\n\n<p>\nReturns the integral part of <code>x</code> and the fractional part of <code>x</code>.\nIts second result is always a float.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.pi\"><code>math.pi</code></a></h3>\n\n\n<p>\nThe value of <em>&pi;</em>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.rad\"><code>math.rad (x)</code></a></h3>\n\n\n<p>\nConverts the angle <code>x</code> from degrees to radians.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.random\"><code>math.random ([m [, n]])</code></a></h3>\n\n\n<p>\nWhen called without arguments,\nreturns a pseudo-random float with uniform distribution\nin the range  <em>[0,1)</em>.  \nWhen called with two integers <code>m</code> and <code>n</code>,\n<code>math.random</code> returns a pseudo-random integer\nwith uniform distribution in the range <em>[m, n]</em>.\n(The value <em>n-m</em> cannot be negative and must fit in a Lua integer.)\nThe call <code>math.random(n)</code> is equivalent to <code>math.random(1,n)</code>.\n\n\n<p>\nThis function is an interface to the underling\npseudo-random generator function provided by C.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.randomseed\"><code>math.randomseed (x)</code></a></h3>\n\n\n<p>\nSets <code>x</code> as the \"seed\"\nfor the pseudo-random generator:\nequal seeds produce equal sequences of numbers.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.sin\"><code>math.sin (x)</code></a></h3>\n\n\n<p>\nReturns the sine of <code>x</code> (assumed to be in radians).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.sqrt\"><code>math.sqrt (x)</code></a></h3>\n\n\n<p>\nReturns the square root of <code>x</code>.\n(You can also use the expression <code>x^0.5</code> to compute this value.)\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.tan\"><code>math.tan (x)</code></a></h3>\n\n\n<p>\nReturns the tangent of <code>x</code> (assumed to be in radians).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.tointeger\"><code>math.tointeger (x)</code></a></h3>\n\n\n<p>\nIf the value <code>x</code> is convertible to an integer,\nreturns that integer.\nOtherwise, returns <b>nil</b>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.type\"><code>math.type (x)</code></a></h3>\n\n\n<p>\nReturns \"<code>integer</code>\" if <code>x</code> is an integer,\n\"<code>float</code>\" if it is a float,\nor <b>nil</b> if <code>x</code> is not a number.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-math.ult\"><code>math.ult (m, n)</code></a></h3>\n\n\n<p>\nReturns a boolean,\ntrue if and only if integer <code>m</code> is below integer <code>n</code> when\nthey are compared as unsigned integers.\n\n\n\n\n\n\n\n<h2>6.8 &ndash; <a name=\"6.8\">Input and Output Facilities</a></h2>\n\n<p>\nThe I/O library provides two different styles for file manipulation.\nThe first one uses implicit file handles;\nthat is, there are operations to set a default input file and a\ndefault output file,\nand all input/output operations are over these default files.\nThe second style uses explicit file handles.\n\n\n<p>\nWhen using implicit file handles,\nall operations are supplied by table <a name=\"pdf-io\"><code>io</code></a>.\nWhen using explicit file handles,\nthe operation <a href=\"#pdf-io.open\"><code>io.open</code></a> returns a file handle\nand then all operations are supplied as methods of the file handle.\n\n\n<p>\nThe table <code>io</code> also provides\nthree predefined file handles with their usual meanings from C:\n<a name=\"pdf-io.stdin\"><code>io.stdin</code></a>, <a name=\"pdf-io.stdout\"><code>io.stdout</code></a>, and <a name=\"pdf-io.stderr\"><code>io.stderr</code></a>.\nThe I/O library never closes these files.\n\n\n<p>\nUnless otherwise stated,\nall I/O functions return <b>nil</b> on failure\n(plus an error message as a second result and\na system-dependent error code as a third result)\nand some value different from <b>nil</b> on success.\nIn non-POSIX systems,\nthe computation of the error message and error code\nin case of errors\nmay be not thread safe,\nbecause they rely on the global C variable <code>errno</code>.\n\n\n<p>\n<hr><h3><a name=\"pdf-io.close\"><code>io.close ([file])</code></a></h3>\n\n\n<p>\nEquivalent to <code>file:close()</code>.\nWithout a <code>file</code>, closes the default output file.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.flush\"><code>io.flush ()</code></a></h3>\n\n\n<p>\nEquivalent to <code>io.output():flush()</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.input\"><code>io.input ([file])</code></a></h3>\n\n\n<p>\nWhen called with a file name, it opens the named file (in text mode),\nand sets its handle as the default input file.\nWhen called with a file handle,\nit simply sets this file handle as the default input file.\nWhen called without arguments,\nit returns the current default input file.\n\n\n<p>\nIn case of errors this function raises the error,\ninstead of returning an error code.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.lines\"><code>io.lines ([filename, &middot;&middot;&middot;])</code></a></h3>\n\n\n<p>\nOpens the given file name in read mode\nand returns an iterator function that\nworks like <code>file:lines(&middot;&middot;&middot;)</code> over the opened file.\nWhen the iterator function detects the end of file,\nit returns no values (to finish the loop) and automatically closes the file.\n\n\n<p>\nThe call <code>io.lines()</code> (with no file name) is equivalent\nto <code>io.input():lines(\"*l\")</code>;\nthat is, it iterates over the lines of the default input file.\nIn this case, the iterator does not close the file when the loop ends.\n\n\n<p>\nIn case of errors this function raises the error,\ninstead of returning an error code.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.open\"><code>io.open (filename [, mode])</code></a></h3>\n\n\n<p>\nThis function opens a file,\nin the mode specified in the string <code>mode</code>.\nIn case of success,\nit returns a new file handle.\n\n\n<p>\nThe <code>mode</code> string can be any of the following:\n\n<ul>\n<li><b>\"<code>r</code>\": </b> read mode (the default);</li>\n<li><b>\"<code>w</code>\": </b> write mode;</li>\n<li><b>\"<code>a</code>\": </b> append mode;</li>\n<li><b>\"<code>r+</code>\": </b> update mode, all previous data is preserved;</li>\n<li><b>\"<code>w+</code>\": </b> update mode, all previous data is erased;</li>\n<li><b>\"<code>a+</code>\": </b> append update mode, previous data is preserved,\n  writing is only allowed at the end of file.</li>\n</ul><p>\nThe <code>mode</code> string can also have a '<code>b</code>' at the end,\nwhich is needed in some systems to open the file in binary mode.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.output\"><code>io.output ([file])</code></a></h3>\n\n\n<p>\nSimilar to <a href=\"#pdf-io.input\"><code>io.input</code></a>, but operates over the default output file.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.popen\"><code>io.popen (prog [, mode])</code></a></h3>\n\n\n<p>\nThis function is system dependent and is not available\non all platforms.\n\n\n<p>\nStarts program <code>prog</code> in a separated process and returns\na file handle that you can use to read data from this program\n(if <code>mode</code> is <code>\"r\"</code>, the default)\nor to write data to this program\n(if <code>mode</code> is <code>\"w\"</code>).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.read\"><code>io.read (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nEquivalent to <code>io.input():read(&middot;&middot;&middot;)</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.tmpfile\"><code>io.tmpfile ()</code></a></h3>\n\n\n<p>\nIn case of success,\nreturns a handle for a temporary file.\nThis file is opened in update mode\nand it is automatically removed when the program ends.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.type\"><code>io.type (obj)</code></a></h3>\n\n\n<p>\nChecks whether <code>obj</code> is a valid file handle.\nReturns the string <code>\"file\"</code> if <code>obj</code> is an open file handle,\n<code>\"closed file\"</code> if <code>obj</code> is a closed file handle,\nor <b>nil</b> if <code>obj</code> is not a file handle.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-io.write\"><code>io.write (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nEquivalent to <code>io.output():write(&middot;&middot;&middot;)</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:close\"><code>file:close ()</code></a></h3>\n\n\n<p>\nCloses <code>file</code>.\nNote that files are automatically closed when\ntheir handles are garbage collected,\nbut that takes an unpredictable amount of time to happen.\n\n\n<p>\nWhen closing a file handle created with <a href=\"#pdf-io.popen\"><code>io.popen</code></a>,\n<a href=\"#pdf-file:close\"><code>file:close</code></a> returns the same values\nreturned by <a href=\"#pdf-os.execute\"><code>os.execute</code></a>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:flush\"><code>file:flush ()</code></a></h3>\n\n\n<p>\nSaves any written data to <code>file</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:lines\"><code>file:lines (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReturns an iterator function that,\neach time it is called,\nreads the file according to the given formats.\nWhen no format is given,\nuses \"<code>l</code>\" as a default.\nAs an example, the construction\n\n<pre>\n     for c in file:lines(1) do <em>body</em> end\n</pre><p>\nwill iterate over all characters of the file,\nstarting at the current position.\nUnlike <a href=\"#pdf-io.lines\"><code>io.lines</code></a>, this function does not close the file\nwhen the loop ends.\n\n\n<p>\nIn case of errors this function raises the error,\ninstead of returning an error code.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:read\"><code>file:read (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nReads the file <code>file</code>,\naccording to the given formats, which specify what to read.\nFor each format,\nthe function returns a string or a number with the characters read,\nor <b>nil</b> if it cannot read data with the specified format.\n(In this latter case,\nthe function does not read subsequent formats.)\nWhen called without formats,\nit uses a default format that reads the next line\n(see below).\n\n\n<p>\nThe available formats are\n\n<ul>\n\n<li><b>\"<code>n</code>\": </b>\nreads a numeral and returns it as a float or an integer,\nfollowing the lexical conventions of Lua.\n(The numeral may have leading spaces and a sign.)\nThis format always reads the longest input sequence that\nis a valid prefix for a numeral;\nif that prefix does not form a valid numeral\n(e.g., an empty string, \"<code>0x</code>\", or \"<code>3.4e-</code>\"),\nit is discarded and the function returns <b>nil</b>.\n</li>\n\n<li><b>\"<code>a</code>\": </b>\nreads the whole file, starting at the current position.\nOn end of file, it returns the empty string.\n</li>\n\n<li><b>\"<code>l</code>\": </b>\nreads the next line skipping the end of line,\nreturning <b>nil</b> on end of file.\nThis is the default format.\n</li>\n\n<li><b>\"<code>L</code>\": </b>\nreads the next line keeping the end-of-line character (if present),\nreturning <b>nil</b> on end of file.\n</li>\n\n<li><b><em>number</em>: </b>\nreads a string with up to this number of bytes,\nreturning <b>nil</b> on end of file.\nIf <code>number</code> is zero,\nit reads nothing and returns an empty string,\nor <b>nil</b> on end of file.\n</li>\n\n</ul><p>\nThe formats \"<code>l</code>\" and \"<code>L</code>\" should be used only for text files.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:seek\"><code>file:seek ([whence [, offset]])</code></a></h3>\n\n\n<p>\nSets and gets the file position,\nmeasured from the beginning of the file,\nto the position given by <code>offset</code> plus a base\nspecified by the string <code>whence</code>, as follows:\n\n<ul>\n<li><b>\"<code>set</code>\": </b> base is position 0 (beginning of the file);</li>\n<li><b>\"<code>cur</code>\": </b> base is current position;</li>\n<li><b>\"<code>end</code>\": </b> base is end of file;</li>\n</ul><p>\nIn case of success, <code>seek</code> returns the final file position,\nmeasured in bytes from the beginning of the file.\nIf <code>seek</code> fails, it returns <b>nil</b>,\nplus a string describing the error.\n\n\n<p>\nThe default value for <code>whence</code> is <code>\"cur\"</code>,\nand for <code>offset</code> is 0.\nTherefore, the call <code>file:seek()</code> returns the current\nfile position, without changing it;\nthe call <code>file:seek(\"set\")</code> sets the position to the\nbeginning of the file (and returns 0);\nand the call <code>file:seek(\"end\")</code> sets the position to the\nend of the file, and returns its size.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:setvbuf\"><code>file:setvbuf (mode [, size])</code></a></h3>\n\n\n<p>\nSets the buffering mode for an output file.\nThere are three available modes:\n\n<ul>\n\n<li><b>\"<code>no</code>\": </b>\nno buffering; the result of any output operation appears immediately.\n</li>\n\n<li><b>\"<code>full</code>\": </b>\nfull buffering; output operation is performed only\nwhen the buffer is full or when\nyou explicitly <code>flush</code> the file (see <a href=\"#pdf-io.flush\"><code>io.flush</code></a>).\n</li>\n\n<li><b>\"<code>line</code>\": </b>\nline buffering; output is buffered until a newline is output\nor there is any input from some special files\n(such as a terminal device).\n</li>\n\n</ul><p>\nFor the last two cases, <code>size</code>\nspecifies the size of the buffer, in bytes.\nThe default is an appropriate size.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-file:write\"><code>file:write (&middot;&middot;&middot;)</code></a></h3>\n\n\n<p>\nWrites the value of each of its arguments to <code>file</code>.\nThe arguments must be strings or numbers.\n\n\n<p>\nIn case of success, this function returns <code>file</code>.\nOtherwise it returns <b>nil</b> plus a string describing the error.\n\n\n\n\n\n\n\n<h2>6.9 &ndash; <a name=\"6.9\">Operating System Facilities</a></h2>\n\n<p>\nThis library is implemented through table <a name=\"pdf-os\"><code>os</code></a>.\n\n\n<p>\n<hr><h3><a name=\"pdf-os.clock\"><code>os.clock ()</code></a></h3>\n\n\n<p>\nReturns an approximation of the amount in seconds of CPU time\nused by the program.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.date\"><code>os.date ([format [, time]])</code></a></h3>\n\n\n<p>\nReturns a string or a table containing date and time,\nformatted according to the given string <code>format</code>.\n\n\n<p>\nIf the <code>time</code> argument is present,\nthis is the time to be formatted\n(see the <a href=\"#pdf-os.time\"><code>os.time</code></a> function for a description of this value).\nOtherwise, <code>date</code> formats the current time.\n\n\n<p>\nIf <code>format</code> starts with '<code>!</code>',\nthen the date is formatted in Coordinated Universal Time.\nAfter this optional character,\nif <code>format</code> is the string \"<code>*t</code>\",\nthen <code>date</code> returns a table with the following fields:\n<code>year</code>, <code>month</code> (1&ndash;12), <code>day</code> (1&ndash;31),\n<code>hour</code> (0&ndash;23), <code>min</code> (0&ndash;59), <code>sec</code> (0&ndash;61),\n<code>wday</code> (weekday, 1&ndash;7, Sunday is&nbsp;1),\n<code>yday</code> (day of the year, 1&ndash;366),\nand <code>isdst</code> (daylight saving flag, a boolean).\nThis last field may be absent\nif the information is not available.\n\n\n<p>\nIf <code>format</code> is not \"<code>*t</code>\",\nthen <code>date</code> returns the date as a string,\nformatted according to the same rules as the ISO&nbsp;C function <code>strftime</code>.\n\n\n<p>\nWhen called without arguments,\n<code>date</code> returns a reasonable date and time representation that depends on\nthe host system and on the current locale.\n(More specifically, <code>os.date()</code> is equivalent to <code>os.date(\"%c\")</code>.)\n\n\n<p>\nIn non-POSIX systems,\nthis function may be not thread safe\nbecause of its reliance on C&nbsp;function <code>gmtime</code> and C&nbsp;function <code>localtime</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.difftime\"><code>os.difftime (t2, t1)</code></a></h3>\n\n\n<p>\nReturns the difference, in seconds,\nfrom time <code>t1</code> to time <code>t2</code>\n(where the times are values returned by <a href=\"#pdf-os.time\"><code>os.time</code></a>).\nIn POSIX, Windows, and some other systems,\nthis value is exactly <code>t2</code><em>-</em><code>t1</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.execute\"><code>os.execute ([command])</code></a></h3>\n\n\n<p>\nThis function is equivalent to the ISO&nbsp;C function <code>system</code>.\nIt passes <code>command</code> to be executed by an operating system shell.\nIts first result is <b>true</b>\nif the command terminated successfully,\nor <b>nil</b> otherwise.\nAfter this first result\nthe function returns a string plus a number,\nas follows:\n\n<ul>\n\n<li><b>\"<code>exit</code>\": </b>\nthe command terminated normally;\nthe following number is the exit status of the command.\n</li>\n\n<li><b>\"<code>signal</code>\": </b>\nthe command was terminated by a signal;\nthe following number is the signal that terminated the command.\n</li>\n\n</ul>\n\n<p>\nWhen called without a <code>command</code>,\n<code>os.execute</code> returns a boolean that is true if a shell is available.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.exit\"><code>os.exit ([code [, close]])</code></a></h3>\n\n\n<p>\nCalls the ISO&nbsp;C function <code>exit</code> to terminate the host program.\nIf <code>code</code> is <b>true</b>,\nthe returned status is <code>EXIT_SUCCESS</code>;\nif <code>code</code> is <b>false</b>,\nthe returned status is <code>EXIT_FAILURE</code>;\nif <code>code</code> is a number,\nthe returned status is this number.\nThe default value for <code>code</code> is <b>true</b>.\n\n\n<p>\nIf the optional second argument <code>close</code> is true,\ncloses the Lua state before exiting.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.getenv\"><code>os.getenv (varname)</code></a></h3>\n\n\n<p>\nReturns the value of the process environment variable <code>varname</code>,\nor <b>nil</b> if the variable is not defined.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.remove\"><code>os.remove (filename)</code></a></h3>\n\n\n<p>\nDeletes the file (or empty directory, on POSIX systems)\nwith the given name.\nIf this function fails, it returns <b>nil</b>,\nplus a string describing the error and the error code.\nOtherwise, it returns true.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.rename\"><code>os.rename (oldname, newname)</code></a></h3>\n\n\n<p>\nRenames the file or directory named <code>oldname</code> to <code>newname</code>.\nIf this function fails, it returns <b>nil</b>,\nplus a string describing the error and the error code.\nOtherwise, it returns true.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.setlocale\"><code>os.setlocale (locale [, category])</code></a></h3>\n\n\n<p>\nSets the current locale of the program.\n<code>locale</code> is a system-dependent string specifying a locale;\n<code>category</code> is an optional string describing which category to change:\n<code>\"all\"</code>, <code>\"collate\"</code>, <code>\"ctype\"</code>,\n<code>\"monetary\"</code>, <code>\"numeric\"</code>, or <code>\"time\"</code>;\nthe default category is <code>\"all\"</code>.\nThe function returns the name of the new locale,\nor <b>nil</b> if the request cannot be honored.\n\n\n<p>\nIf <code>locale</code> is the empty string,\nthe current locale is set to an implementation-defined native locale.\nIf <code>locale</code> is the string \"<code>C</code>\",\nthe current locale is set to the standard C locale.\n\n\n<p>\nWhen called with <b>nil</b> as the first argument,\nthis function only returns the name of the current locale\nfor the given category.\n\n\n<p>\nThis function may be not thread safe\nbecause of its reliance on C&nbsp;function <code>setlocale</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.time\"><code>os.time ([table])</code></a></h3>\n\n\n<p>\nReturns the current time when called without arguments,\nor a time representing the local date and time specified by the given table.\nThis table must have fields <code>year</code>, <code>month</code>, and <code>day</code>,\nand may have fields\n<code>hour</code> (default is 12),\n<code>min</code> (default is 0),\n<code>sec</code> (default is 0),\nand <code>isdst</code> (default is <b>nil</b>).\nOther fields are ignored.\nFor a description of these fields, see the <a href=\"#pdf-os.date\"><code>os.date</code></a> function.\n\n\n<p>\nThe values in these fields do not need to be inside their valid ranges.\nFor instance, if <code>sec</code> is -10,\nit means -10 seconds from the time specified by the other fields;\nif <code>hour</code> is 1000,\nit means +1000 hours from the time specified by the other fields.\n\n\n<p>\nThe returned value is a number, whose meaning depends on your system.\nIn POSIX, Windows, and some other systems,\nthis number counts the number\nof seconds since some given start time (the \"epoch\").\nIn other systems, the meaning is not specified,\nand the number returned by <code>time</code> can be used only as an argument to\n<a href=\"#pdf-os.date\"><code>os.date</code></a> and <a href=\"#pdf-os.difftime\"><code>os.difftime</code></a>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-os.tmpname\"><code>os.tmpname ()</code></a></h3>\n\n\n<p>\nReturns a string with a file name that can\nbe used for a temporary file.\nThe file must be explicitly opened before its use\nand explicitly removed when no longer needed.\n\n\n<p>\nIn POSIX systems,\nthis function also creates a file with that name,\nto avoid security risks.\n(Someone else might create the file with wrong permissions\nin the time between getting the name and creating the file.)\nYou still have to open the file to use it\nand to remove it (even if you do not use it).\n\n\n<p>\nWhen possible,\nyou may prefer to use <a href=\"#pdf-io.tmpfile\"><code>io.tmpfile</code></a>,\nwhich automatically removes the file when the program ends.\n\n\n\n\n\n\n\n<h2>6.10 &ndash; <a name=\"6.10\">The Debug Library</a></h2>\n\n<p>\nThis library provides\nthe functionality of the debug interface (<a href=\"#4.9\">&sect;4.9</a>) to Lua programs.\nYou should exert care when using this library.\nSeveral of its functions\nviolate basic assumptions about Lua code\n(e.g., that variables local to a function\ncannot be accessed from outside;\nthat userdata metatables cannot be changed by Lua code;\nthat Lua programs do not crash)\nand therefore can compromise otherwise secure code.\nMoreover, some functions in this library may be slow.\n\n\n<p>\nAll functions in this library are provided\ninside the <a name=\"pdf-debug\"><code>debug</code></a> table.\nAll functions that operate over a thread\nhave an optional first argument which is the\nthread to operate over.\nThe default is always the current thread.\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.debug\"><code>debug.debug ()</code></a></h3>\n\n\n<p>\nEnters an interactive mode with the user,\nrunning each string that the user enters.\nUsing simple commands and other debug facilities,\nthe user can inspect global and local variables,\nchange their values, evaluate expressions, and so on.\nA line containing only the word <code>cont</code> finishes this function,\nso that the caller continues its execution.\n\n\n<p>\nNote that commands for <code>debug.debug</code> are not lexically nested\nwithin any function and so have no direct access to local variables.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.gethook\"><code>debug.gethook ([thread])</code></a></h3>\n\n\n<p>\nReturns the current hook settings of the thread, as three values:\nthe current hook function, the current hook mask,\nand the current hook count\n(as set by the <a href=\"#pdf-debug.sethook\"><code>debug.sethook</code></a> function).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.getinfo\"><code>debug.getinfo ([thread,] f [, what])</code></a></h3>\n\n\n<p>\nReturns a table with information about a function.\nYou can give the function directly\nor you can give a number as the value of <code>f</code>,\nwhich means the function running at level <code>f</code> of the call stack\nof the given thread:\nlevel&nbsp;0 is the current function (<code>getinfo</code> itself);\nlevel&nbsp;1 is the function that called <code>getinfo</code>\n(except for tail calls, which do not count on the stack);\nand so on.\nIf <code>f</code> is a number larger than the number of active functions,\nthen <code>getinfo</code> returns <b>nil</b>.\n\n\n<p>\nThe returned table can contain all the fields returned by <a href=\"#lua_getinfo\"><code>lua_getinfo</code></a>,\nwith the string <code>what</code> describing which fields to fill in.\nThe default for <code>what</code> is to get all information available,\nexcept the table of valid lines.\nIf present,\nthe option '<code>f</code>'\nadds a field named <code>func</code> with the function itself.\nIf present,\nthe option '<code>L</code>'\nadds a field named <code>activelines</code> with the table of\nvalid lines.\n\n\n<p>\nFor instance, the expression <code>debug.getinfo(1,\"n\").name</code> returns\na name for the current function,\nif a reasonable name can be found,\nand the expression <code>debug.getinfo(print)</code>\nreturns a table with all available information\nabout the <a href=\"#pdf-print\"><code>print</code></a> function.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.getlocal\"><code>debug.getlocal ([thread,] f, local)</code></a></h3>\n\n\n<p>\nThis function returns the name and the value of the local variable\nwith index <code>local</code> of the function at level <code>f</code> of the stack.\nThis function accesses not only explicit local variables,\nbut also parameters, temporaries, etc.\n\n\n<p>\nThe first parameter or local variable has index&nbsp;1, and so on,\nfollowing the order that they are declared in the code,\ncounting only the variables that are active\nin the current scope of the function.\nNegative indices refer to vararg arguments;\n-1 is the first vararg argument.\nThe function returns <b>nil</b> if there is no variable with the given index,\nand raises an error when called with a level out of range.\n(You can call <a href=\"#pdf-debug.getinfo\"><code>debug.getinfo</code></a> to check whether the level is valid.)\n\n\n<p>\nVariable names starting with '<code>(</code>' (open parenthesis) \nrepresent variables with no known names\n(internal variables such as loop control variables,\nand variables from chunks saved without debug information).\n\n\n<p>\nThe parameter <code>f</code> may also be a function.\nIn that case, <code>getlocal</code> returns only the name of function parameters.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.getmetatable\"><code>debug.getmetatable (value)</code></a></h3>\n\n\n<p>\nReturns the metatable of the given <code>value</code>\nor <b>nil</b> if it does not have a metatable.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.getregistry\"><code>debug.getregistry ()</code></a></h3>\n\n\n<p>\nReturns the registry table (see <a href=\"#4.5\">&sect;4.5</a>).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.getupvalue\"><code>debug.getupvalue (f, up)</code></a></h3>\n\n\n<p>\nThis function returns the name and the value of the upvalue\nwith index <code>up</code> of the function <code>f</code>.\nThe function returns <b>nil</b> if there is no upvalue with the given index.\n\n\n<p>\nVariable names starting with '<code>(</code>' (open parenthesis) \nrepresent variables with no known names\n(variables from chunks saved without debug information).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.getuservalue\"><code>debug.getuservalue (u)</code></a></h3>\n\n\n<p>\nReturns the Lua value associated to <code>u</code>.\nIf <code>u</code> is not a full userdata,\nreturns <b>nil</b>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.sethook\"><code>debug.sethook ([thread,] hook, mask [, count])</code></a></h3>\n\n\n<p>\nSets the given function as a hook.\nThe string <code>mask</code> and the number <code>count</code> describe\nwhen the hook will be called.\nThe string mask may have any combination of the following characters,\nwith the given meaning:\n\n<ul>\n<li><b>'<code>c</code>': </b> the hook is called every time Lua calls a function;</li>\n<li><b>'<code>r</code>': </b> the hook is called every time Lua returns from a function;</li>\n<li><b>'<code>l</code>': </b> the hook is called every time Lua enters a new line of code.</li>\n</ul><p>\nMoreover,\nwith a <code>count</code> different from zero,\nthe hook is called also after every <code>count</code> instructions.\n\n\n<p>\nWhen called without arguments,\n<a href=\"#pdf-debug.sethook\"><code>debug.sethook</code></a> turns off the hook.\n\n\n<p>\nWhen the hook is called, its first argument is a string\ndescribing the event that has triggered its call:\n<code>\"call\"</code> (or <code>\"tail call\"</code>),\n<code>\"return\"</code>,\n<code>\"line\"</code>, and <code>\"count\"</code>.\nFor line events,\nthe hook also gets the new line number as its second parameter.\nInside a hook,\nyou can call <code>getinfo</code> with level&nbsp;2 to get more information about\nthe running function\n(level&nbsp;0 is the <code>getinfo</code> function,\nand level&nbsp;1 is the hook function).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.setlocal\"><code>debug.setlocal ([thread,] level, local, value)</code></a></h3>\n\n\n<p>\nThis function assigns the value <code>value</code> to the local variable\nwith index <code>local</code> of the function at level <code>level</code> of the stack.\nThe function returns <b>nil</b> if there is no local\nvariable with the given index,\nand raises an error when called with a <code>level</code> out of range.\n(You can call <code>getinfo</code> to check whether the level is valid.)\nOtherwise, it returns the name of the local variable.\n\n\n<p>\nSee <a href=\"#pdf-debug.getlocal\"><code>debug.getlocal</code></a> for more information about\nvariable indices and names.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.setmetatable\"><code>debug.setmetatable (value, table)</code></a></h3>\n\n\n<p>\nSets the metatable for the given <code>value</code> to the given <code>table</code>\n(which can be <b>nil</b>).\nReturns <code>value</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.setupvalue\"><code>debug.setupvalue (f, up, value)</code></a></h3>\n\n\n<p>\nThis function assigns the value <code>value</code> to the upvalue\nwith index <code>up</code> of the function <code>f</code>.\nThe function returns <b>nil</b> if there is no upvalue\nwith the given index.\nOtherwise, it returns the name of the upvalue.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.setuservalue\"><code>debug.setuservalue (udata, value)</code></a></h3>\n\n\n<p>\nSets the given <code>value</code> as\nthe Lua value associated to the given <code>udata</code>.\n<code>udata</code> must be a full userdata.\n\n\n<p>\nReturns <code>udata</code>.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.traceback\"><code>debug.traceback ([thread,] [message [, level]])</code></a></h3>\n\n\n<p>\nIf <code>message</code> is present but is neither a string nor <b>nil</b>,\nthis function returns <code>message</code> without further processing.\nOtherwise,\nit returns a string with a traceback of the call stack.\nThe optional <code>message</code> string is appended\nat the beginning of the traceback.\nAn optional <code>level</code> number tells at which level\nto start the traceback\n(default is 1, the function calling <code>traceback</code>).\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.upvalueid\"><code>debug.upvalueid (f, n)</code></a></h3>\n\n\n<p>\nReturns a unique identifier (as a light userdata)\nfor the upvalue numbered <code>n</code>\nfrom the given function.\n\n\n<p>\nThese unique identifiers allow a program to check whether different\nclosures share upvalues.\nLua closures that share an upvalue\n(that is, that access a same external local variable)\nwill return identical ids for those upvalue indices.\n\n\n\n\n<p>\n<hr><h3><a name=\"pdf-debug.upvaluejoin\"><code>debug.upvaluejoin (f1, n1, f2, n2)</code></a></h3>\n\n\n<p>\nMake the <code>n1</code>-th upvalue of the Lua closure <code>f1</code>\nrefer to the <code>n2</code>-th upvalue of the Lua closure <code>f2</code>.\n\n\n\n\n\n\n\n<h1>7 &ndash; <a name=\"7\">Lua Standalone</a></h1>\n\n<p>\nAlthough Lua has been designed as an extension language,\nto be embedded in a host C&nbsp;program,\nit is also frequently used as a standalone language.\nAn interpreter for Lua as a standalone language,\ncalled simply <code>lua</code>,\nis provided with the standard distribution.\nThe standalone interpreter includes\nall standard libraries, including the debug library.\nIts usage is:\n\n<pre>\n     lua [options] [script [args]]\n</pre><p>\nThe options are:\n\n<ul>\n<li><b><code>-e <em>stat</em></code>: </b> executes string <em>stat</em>;</li>\n<li><b><code>-l <em>mod</em></code>: </b> \"requires\" <em>mod</em> and assigns the\n  result to global @<em>mod</em>;</li>\n<li><b><code>-i</code>: </b> enters interactive mode after running <em>script</em>;</li>\n<li><b><code>-v</code>: </b> prints version information;</li>\n<li><b><code>-E</code>: </b> ignores environment variables;</li>\n<li><b><code>--</code>: </b> stops handling options;</li>\n<li><b><code>-</code>: </b> executes <code>stdin</code> as a file and stops handling options.</li>\n</ul><p>\nAfter handling its options, <code>lua</code> runs the given <em>script</em>.\nWhen called without arguments,\n<code>lua</code> behaves as <code>lua -v -i</code>\nwhen the standard input (<code>stdin</code>) is a terminal,\nand as <code>lua -</code> otherwise.\n\n\n<p>\nWhen called without option <code>-E</code>,\nthe interpreter checks for an environment variable <a name=\"pdf-LUA_INIT_5_3\"><code>LUA_INIT_5_3</code></a>\n(or <a name=\"pdf-LUA_INIT\"><code>LUA_INIT</code></a> if the versioned name is not defined)\nbefore running any argument.\nIf the variable content has the format <code>@<em>filename</em></code>,\nthen <code>lua</code> executes the file.\nOtherwise, <code>lua</code> executes the string itself.\n\n\n<p>\nWhen called with option <code>-E</code>,\nbesides ignoring <code>LUA_INIT</code>,\nLua also ignores\nthe values of <code>LUA_PATH</code> and <code>LUA_CPATH</code>,\nsetting the values of\n<a href=\"#pdf-package.path\"><code>package.path</code></a> and <a href=\"#pdf-package.cpath\"><code>package.cpath</code></a>\nwith the default paths defined in <code>luaconf.h</code>.\n\n\n<p>\nAll options are handled in order, except <code>-i</code> and <code>-E</code>.\nFor instance, an invocation like\n\n<pre>\n     $ lua -e'a=1' -e 'print(a)' script.lua\n</pre><p>\nwill first set <code>a</code> to 1, then print the value of <code>a</code>,\nand finally run the file <code>script.lua</code> with no arguments.\n(Here <code>$</code> is the shell prompt. Your prompt may be different.)\n\n\n<p>\nBefore running any code,\n<code>lua</code> collects all command-line arguments\nin a global table called <code>arg</code>.\nThe script name goes to index 0,\nthe first argument after the script name goes to index 1,\nand so on.\nAny arguments before the script name\n(that is, the interpreter name plus its options)\ngo to negative indices.\nFor instance, in the call\n\n<pre>\n     $ lua -la b.lua t1 t2\n</pre><p>\nthe table is like this:\n\n<pre>\n     arg = { [-2] = \"lua\", [-1] = \"-la\",\n             [0] = \"b.lua\",\n             [1] = \"t1\", [2] = \"t2\" }\n</pre><p>\nIf there is no script in the call,\nthe interpreter name goes to index 0,\nfollowed by the other arguments.\nFor instance, the call\n\n<pre>\n     $ lua -e \"print(arg[1])\"\n</pre><p>\nwill print \"<code>-e</code>\".\nIf there is a script,\nthe script is called with arguments\n<code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>.\n(Like all chunks in Lua,\nthe script is compiled as a vararg function.)\n\n\n<p>\nIn interactive mode,\nLua repeatedly prompts and waits for a line.\nAfter reading a line,\nLua first try to interpret the line as an expression.\nIf it succeeds, it prints its value.\nOtherwise, it interprets the line as a statement.\nIf you write an incomplete statement,\nthe interpreter waits for its completion\nby issuing a different prompt.\n\n\n<p>\nIf the global variable <a name=\"pdf-_PROMPT\"><code>_PROMPT</code></a> contains a string,\nthen its value is used as the prompt.\nSimilarly, if the global variable <a name=\"pdf-_PROMPT2\"><code>_PROMPT2</code></a> contains a string,\nits value is used as the secondary prompt\n(issued during incomplete statements).\n\n\n<p>\nIn case of unprotected errors in the script,\nthe interpreter reports the error to the standard error stream.\nIf the error object is not a string but\nhas a metamethod <code>__tostring</code>,\nthe interpreter calls this metamethod to produce the final message.\nOtherwise, the interpreter converts the error object to a string\nand adds a stack traceback to it.\n\n\n<p>\nWhen finishing normally,\nthe interpreter closes its main Lua state\n(see <a href=\"#lua_close\"><code>lua_close</code></a>).\nThe script can avoid this step by\ncalling <a href=\"#pdf-os.exit\"><code>os.exit</code></a> to terminate.\n\n\n<p>\nTo allow the use of Lua as a\nscript interpreter in Unix systems,\nthe standalone interpreter skips\nthe first line of a chunk if it starts with <code>#</code>.\nTherefore, Lua scripts can be made into executable programs\nby using <code>chmod +x</code> and the&nbsp;<code>#!</code> form,\nas in\n\n<pre>\n     #!/usr/local/bin/lua\n</pre><p>\n(Of course,\nthe location of the Lua interpreter may be different in your machine.\nIf <code>lua</code> is in your <code>PATH</code>,\nthen\n\n<pre>\n     #!/usr/bin/env lua\n</pre><p>\nis a more portable solution.)\n\n\n\n<h1>8 &ndash; <a name=\"8\">Incompatibilities with the Previous Version</a></h1>\n\n<p>\nHere we list the incompatibilities that you may find when moving a program\nfrom Lua&nbsp;5.2 to Lua&nbsp;5.3.\nYou can avoid some incompatibilities by compiling Lua with\nappropriate options (see file <code>luaconf.h</code>).\nHowever,\nall these compatibility options will be removed in the future.\n\n\n<p>\nLua versions can always change the C API in ways that\ndo not imply source-code changes in a program,\nsuch as the numeric values for constants\nor the implementation of functions as macros.\nTherefore,\nyou should not assume that binaries are compatible between\ndifferent Lua versions.\nAlways recompile clients of the Lua API when\nusing a new version.\n\n\n<p>\nSimilarly, Lua versions can always change the internal representation\nof precompiled chunks;\nprecompiled chunks are not compatible between different Lua versions.\n\n\n<p>\nThe standard paths in the official distribution may\nchange between versions.\n\n\n\n<h2>8.1 &ndash; <a name=\"8.1\">Changes in the Language</a></h2>\n<ul>\n\n<li>\nThe main difference between Lua&nbsp;5.2 and Lua&nbsp;5.3 is the\nintroduction of an integer subtype for numbers.\nAlthough this change should not affect \"normal\" computations,\nsome computations\n(mainly those that involve some kind of overflow)\ncan give different results.\n\n\n<p>\nYou can fix these differences by forcing a number to be a float\n(in Lua&nbsp;5.2 all numbers were float),\nin particular writing constants with an ending <code>.0</code>\nor using <code>x = x + 0.0</code> to convert a variable.\n(This recommendation is only for a quick fix\nfor an occasional incompatibility;\nit is not a general guideline for good programming.\nFor good programming,\nuse floats where you need floats\nand integers where you need integers.)\n</li>\n\n<li>\nThe conversion of a float to a string now adds a <code>.0</code> suffix\nto the result if it looks like an integer.\n(For instance, the float 2.0 will be printed as <code>2.0</code>,\nnot as <code>2</code>.)\nYou should always use an explicit format\nwhen you need a specific format for numbers.\n\n\n<p>\n(Formally this is not an incompatibility,\nbecause Lua does not specify how numbers are formatted as strings,\nbut some programs assumed a specific format.)\n</li>\n\n<li>\nThe generational mode for the garbage collector was removed.\n(It was an experimental feature in Lua&nbsp;5.2.)\n</li>\n\n</ul>\n\n\n\n\n<h2>8.2 &ndash; <a name=\"8.2\">Changes in the Libraries</a></h2>\n<ul>\n\n<li>\nThe <code>bit32</code> library has been deprecated.\nIt is easy to require a compatible external library or,\nbetter yet, to replace its functions with appropriate bitwise operations.\n(Keep in mind that <code>bit32</code> operates on 32-bit integers,\nwhile the bitwise operators in Lua&nbsp;5.3 operate on Lua integers,\nwhich by default have 64&nbsp;bits.)\n</li>\n\n<li>\nThe Table library now respects metamethods\nfor setting and getting elements.\n</li>\n\n<li>\nThe <a href=\"#pdf-ipairs\"><code>ipairs</code></a> iterator now respects metamethods and\nits <code>__ipairs</code> metamethod has been deprecated.\n</li>\n\n<li>\nOption names in <a href=\"#pdf-io.read\"><code>io.read</code></a> do not have a starting '<code>*</code>' anymore.\nFor compatibility, Lua will continue to accept (and ignore) this character.\n</li>\n\n<li>\nThe following functions were deprecated in the mathematical library:\n<code>atan2</code>, <code>cosh</code>, <code>sinh</code>, <code>tanh</code>, <code>pow</code>,\n<code>frexp</code>, and <code>ldexp</code>.\nYou can replace <code>math.pow(x,y)</code> with <code>x^y</code>;\nyou can replace <code>math.atan2</code> with <code>math.atan</code>,\nwhich now accepts one or two arguments;\nyou can replace <code>math.ldexp(x,exp)</code> with <code>x * 2.0^exp</code>.\nFor the other operations,\nyou can either use an external library or\nimplement them in Lua.\n</li>\n\n<li>\nThe searcher for C loaders used by <a href=\"#pdf-require\"><code>require</code></a>\nchanged the way it handles versioned names.\nNow, the version should come after the module name\n(as is usual in most other tools).\nFor compatibility, that searcher still tries the old format\nif it cannot find an open function according to the new style.\n(Lua&nbsp;5.2 already worked that way,\nbut it did not document the change.)\n</li>\n\n<li>\nThe call <code>collectgarbage(\"count\")</code> now returns only one result.\n(You can compute that second result from the fractional part\nof the first result.)\n</li>\n\n</ul>\n\n\n\n\n<h2>8.3 &ndash; <a name=\"8.3\">Changes in the API</a></h2>\n\n\n<ul>\n\n<li>\nContinuation functions now receive as arguments what they needed\nto get through <code>lua_getctx</code>,\nso <code>lua_getctx</code> has been removed.\nAdapt your code accordingly.\n</li>\n\n<li>\nFunction <a href=\"#lua_dump\"><code>lua_dump</code></a> has an extra parameter, <code>strip</code>.\nUse 0 as the value of this parameter to get the old behavior.\n</li>\n\n<li>\nFunctions to inject/project unsigned integers\n(<code>lua_pushunsigned</code>, <code>lua_tounsigned</code>, <code>lua_tounsignedx</code>,\n<code>luaL_checkunsigned</code>, <code>luaL_optunsigned</code>)\nwere deprecated.\nUse their signed equivalents with a type cast.\n</li>\n\n<li>\nMacros to project non-default integer types\n(<code>luaL_checkint</code>, <code>luaL_optint</code>, <code>luaL_checklong</code>, <code>luaL_optlong</code>)\nwere deprecated.\nUse their equivalent over <a href=\"#lua_Integer\"><code>lua_Integer</code></a> with a type cast\n(or, when possible, use <a href=\"#lua_Integer\"><code>lua_Integer</code></a> in your code).\n</li>\n\n</ul>\n\n\n\n\n<h1>9 &ndash; <a name=\"9\">The Complete Syntax of Lua</a></h1>\n\n<p>\nHere is the complete syntax of Lua in extended BNF.\nAs usual in extended BNF,\n{A} means 0 or more As,\nand [A] means an optional A.\n(For operator precedences, see <a href=\"#3.4.8\">&sect;3.4.8</a>;\nfor a description of the terminals\nName, Numeral,\nand LiteralString, see <a href=\"#3.1\">&sect;3.1</a>.)\n\n\n\n\n<pre>\n\n\tchunk ::= block\n\n\tblock ::= {stat} [retstat]\n\n\tstat ::=  &lsquo;<b>;</b>&rsquo; | \n\t\t varlist &lsquo;<b>=</b>&rsquo; explist | \n\t\t functioncall | \n\t\t label | \n\t\t <b>break</b> | \n\t\t <b>goto</b> Name | \n\t\t <b>do</b> block <b>end</b> | \n\t\t <b>while</b> exp <b>do</b> block <b>end</b> | \n\t\t <b>repeat</b> block <b>until</b> exp | \n\t\t <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b> | \n\t\t <b>for</b> Name &lsquo;<b>=</b>&rsquo; exp &lsquo;<b>,</b>&rsquo; exp [&lsquo;<b>,</b>&rsquo; exp] <b>do</b> block <b>end</b> | \n\t\t <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> | \n\t\t <b>function</b> funcname funcbody | \n\t\t <b>local</b> <b>function</b> Name funcbody | \n\t\t <b>local</b> namelist [&lsquo;<b>=</b>&rsquo; explist] \n\n\tretstat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]\n\n\tlabel ::= &lsquo;<b>::</b>&rsquo; Name &lsquo;<b>::</b>&rsquo;\n\n\tfuncname ::= Name {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; Name]\n\n\tvarlist ::= var {&lsquo;<b>,</b>&rsquo; var}\n\n\tvar ::=  Name | prefixexp &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; | prefixexp &lsquo;<b>.</b>&rsquo; Name \n\n\tnamelist ::= Name {&lsquo;<b>,</b>&rsquo; Name}\n\n\texplist ::= exp {&lsquo;<b>,</b>&rsquo; exp}\n\n\texp ::=  <b>nil</b> | <b>false</b> | <b>true</b> | Numeral | LiteralString | &lsquo;<b>...</b>&rsquo; | functiondef | \n\t\t prefixexp | tableconstructor | exp binop exp | unop exp \n\n\tprefixexp ::= var | functioncall | &lsquo;<b>(</b>&rsquo; exp &lsquo;<b>)</b>&rsquo;\n\n\tfunctioncall ::=  prefixexp args | prefixexp &lsquo;<b>:</b>&rsquo; Name args \n\n\targs ::=  &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo; | tableconstructor | LiteralString \n\n\tfunctiondef ::= <b>function</b> funcbody\n\n\tfuncbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>\n\n\tparlist ::= namelist [&lsquo;<b>,</b>&rsquo; &lsquo;<b>...</b>&rsquo;] | &lsquo;<b>...</b>&rsquo;\n\n\ttableconstructor ::= &lsquo;<b>{</b>&rsquo; [fieldlist] &lsquo;<b>}</b>&rsquo;\n\n\tfieldlist ::= field {fieldsep field} [fieldsep]\n\n\tfield ::= &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; &lsquo;<b>=</b>&rsquo; exp | Name &lsquo;<b>=</b>&rsquo; exp | exp\n\n\tfieldsep ::= &lsquo;<b>,</b>&rsquo; | &lsquo;<b>;</b>&rsquo;\n\n\tbinop ::=  &lsquo;<b>+</b>&rsquo; | &lsquo;<b>-</b>&rsquo; | &lsquo;<b>*</b>&rsquo; | &lsquo;<b>/</b>&rsquo; | &lsquo;<b>//</b>&rsquo; | &lsquo;<b>^</b>&rsquo; | &lsquo;<b>%</b>&rsquo; | \n\t\t &lsquo;<b>&amp;</b>&rsquo; | &lsquo;<b>~</b>&rsquo; | &lsquo;<b>|</b>&rsquo; | &lsquo;<b>&gt;&gt;</b>&rsquo; | &lsquo;<b>&lt;&lt;</b>&rsquo; | &lsquo;<b>..</b>&rsquo; | \n\t\t &lsquo;<b>&lt;</b>&rsquo; | &lsquo;<b>&lt;=</b>&rsquo; | &lsquo;<b>&gt;</b>&rsquo; | &lsquo;<b>&gt;=</b>&rsquo; | &lsquo;<b>==</b>&rsquo; | &lsquo;<b>~=</b>&rsquo; | \n\t\t <b>and</b> | <b>or</b>\n\n\tunop ::= &lsquo;<b>-</b>&rsquo; | <b>not</b> | &lsquo;<b>#</b>&rsquo; | &lsquo;<b>~</b>&rsquo;\n\n</pre>\n\n<p>\n\n\n\n\n\n\n\n\n<P CLASS=\"footer\">\nLast update:\nTue Jun 26 13:16:37 -03 2018\n</P>\n<!--\nLast change: revised for Lua 5.3.5\n-->\n\n</body></html>\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/doc/readme.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<HTML>\n<HEAD>\n<TITLE>Lua 5.3 readme</TITLE>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"lua.css\">\n<META HTTP-EQUIV=\"content-type\" CONTENT=\"text/html; charset=iso-8859-1\">\n<STYLE TYPE=\"text/css\">\nblockquote, .display {\n\tborder: solid #a0a0a0 2px ;\n\tborder-radius: 8px ;\n\tpadding: 1em ;\n\tmargin: 0px ;\n}\n\n.display {\n\tword-spacing: 0.25em ;\n}\n\ndl.display dd {\n\tpadding-bottom: 0.2em ;\n}\n\ntt, kbd, code {\n\tfont-size: 12pt ;\n}\n</STYLE>\n</HEAD>\n\n<BODY>\n\n<H1>\n<A HREF=\"http://www.lua.org/\"><IMG SRC=\"logo.gif\" ALT=\"Lua\"></A>\nWelcome to Lua 5.3\n</H1>\n\n<DIV CLASS=\"menubar\">\n<A HREF=\"#about\">about</A>\n&middot;\n<A HREF=\"#install\">installation</A>\n&middot;\n<A HREF=\"#changes\">changes</A>\n&middot;\n<A HREF=\"#license\">license</A>\n&middot;\n<A HREF=\"contents.html\">reference manual</A>\n</DIV>\n\n<H2><A NAME=\"about\">About Lua</A></H2>\n<P>\nLua is a powerful, fast, lightweight, embeddable scripting language\ndeveloped by a\n<A HREF=\"http://www.lua.org/authors.html\">team</A>\nat\n<A HREF=\"http://www.puc-rio.br/\">PUC-Rio</A>,\nthe Pontifical Catholic University of Rio de Janeiro in Brazil.\nLua is\n<A HREF=\"#license\">free software</A>\nused in many products and projects around the world.\n\n<P>\nLua's\n<A HREF=\"http://www.lua.org/\">official web site</A>\nprovides complete information\nabout Lua,\nincluding\nan\n<A HREF=\"http://www.lua.org/about.html\">executive summary</A>\nand\nupdated\n<A HREF=\"http://www.lua.org/docs.html\">documentation</A>,\nespecially the\n<A HREF=\"http://www.lua.org/manual/5.3/\">reference manual</A>,\nwhich may differ slightly from the\n<A HREF=\"contents.html\">local copy</A>\ndistributed in this package.\n\n<H2><A NAME=\"install\">Installing Lua</A></H2>\n<P>\nLua is distributed in\n<A HREF=\"http://www.lua.org/ftp/\">source</A>\nform.\nYou need to build it before using it.\nBuilding Lua should be straightforward\nbecause\nLua is implemented in pure ANSI C and compiles unmodified in all known\nplatforms that have an ANSI C compiler.\nLua also compiles unmodified as C++.\nThe instructions given below for building Lua are for Unix-like platforms.\nSee also\n<A HREF=\"#other\">instructions for other systems</A>\nand\n<A HREF=\"#customization\">customization options</A>.\n\n<P>\nIf you don't have the time or the inclination to compile Lua yourself,\nget a binary from\n<A HREF=\"http://lua-users.org/wiki/LuaBinaries\">LuaBinaries</A>.\nTry also\n<A HREF=\"http://luadist.org/\">LuaDist</A>,\na multi-platform distribution of Lua that includes batteries.\n\n<H3>Building Lua</H3>\n<P>\nIn most Unix-like platforms, simply do \"<KBD>make</KBD>\" with a suitable target.\nHere are the details.\n\n<OL>\n<LI>\nOpen a terminal window and move to\nthe top-level directory, which is named <TT>lua-5.3.5</TT>.\nThe <TT>Makefile</TT> there controls both the build process and the installation process.\n<P>\n<LI>\n  Do \"<KBD>make</KBD>\" and see if your platform is listed.\n  The platforms currently supported are:\n<P>\n<P CLASS=\"display\">\n   aix bsd c89 freebsd generic linux macosx mingw posix solaris\n</P>\n<P>\n  If your platform is listed, just do \"<KBD>make xxx</KBD>\", where xxx\n  is your platform name.\n<P>\n  If your platform is not listed, try the closest one or posix, generic,\n  c89, in this order.\n<P>\n<LI>\nThe compilation takes only a few moments\nand produces three files in the <TT>src</TT> directory:\nlua (the interpreter),\nluac (the compiler),\nand liblua.a (the library).\n<P>\n<LI>\n  To check that Lua has been built correctly, do \"<KBD>make test</KBD>\"\n  after building Lua. This will run the interpreter and print its version.\n</OL>\n<P>\nIf you're running Linux and get compilation errors,\nmake sure you have installed the <TT>readline</TT> development package\n(which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>).\nIf you get link errors after that,\nthen try \"<KBD>make linux MYLIBS=-ltermcap</KBD>\".\n\n<H3>Installing Lua</H3>\n<P>\n  Once you have built Lua, you may want to install it in an official\n  place in your system. In this case, do \"<KBD>make install</KBD>\". The official\n  place and the way to install files are defined in the <TT>Makefile</TT>. You'll\n  probably need the right permissions to install files.\n\n<P>\n  To build and install Lua in one step, do \"<KBD>make xxx install</KBD>\",\n  where xxx is your platform name.\n\n<P>\n  To install Lua locally, do \"<KBD>make local</KBD>\".\n  This will create a directory <TT>install</TT> with subdirectories\n  <TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>,\n  and install Lua as listed below.\n\n  To install Lua locally, but in some other directory, do\n  \"<KBD>make install INSTALL_TOP=xxx</KBD>\", where xxx is your chosen directory.\n  The installation starts in the <TT>src</TT> and <TT>doc</TT> directories,\n  so take care if <TT>INSTALL_TOP</TT> is not an absolute path.\n\n<DL CLASS=\"display\">\n<DT>\n    bin:\n<DD>\n    lua luac\n<DT>\n    include:\n<DD>\n    lua.h luaconf.h lualib.h lauxlib.h lua.hpp\n<DT>\n    lib:\n<DD>\n    liblua.a\n<DT>\n    man/man1:\n<DD>\n    lua.1 luac.1\n</DL>\n\n<P>\n  These are the only directories you need for development.\n  If you only want to run Lua programs,\n  you only need the files in <TT>bin</TT> and <TT>man</TT>.\n  The files in <TT>include</TT> and <TT>lib</TT> are needed for\n  embedding Lua in C or C++ programs.\n\n<H3><A NAME=\"customization\">Customization</A></H3>\n<P>\n  Three kinds of things can be customized by editing a file:\n<UL>\n    <LI> Where and how to install Lua &mdash; edit <TT>Makefile</TT>.\n    <LI> How to build Lua &mdash; edit <TT>src/Makefile</TT>.\n    <LI> Lua features &mdash; edit <TT>src/luaconf.h</TT>.\n</UL>\n\n<P>\n  You don't actually need to edit the Makefiles because you may set the\n  relevant variables in the command line when invoking make.\n  Nevertheless, it's probably best to edit and save the Makefiles to\n  record the changes you've made.\n\n<P>\n  On the other hand, if you need to customize some Lua features, you'll need\n  to edit <TT>src/luaconf.h</TT> before building and installing Lua.\n  The edited file will be the one installed, and\n  it will be used by any Lua clients that you build, to ensure consistency.\n  Further customization is available to experts by editing the Lua sources.\n\n<H3><A NAME=\"other\">Building Lua on other systems</A></H3>\n<P>\n  If you're not using the usual Unix tools, then the instructions for\n  building Lua depend on the compiler you use. You'll need to create\n  projects (or whatever your compiler uses) for building the library,\n  the interpreter, and the compiler, as follows:\n\n<DL CLASS=\"display\">\n<DT>\nlibrary:\n<DD>\nlapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c\nlmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c\nltm.c lundump.c lvm.c lzio.c\nlauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c\nlmathlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c loadlib.c linit.c\n<DT>\ninterpreter:\n<DD>\n  library, lua.c\n<DT>\ncompiler:\n<DD>\n  library, luac.c\n</DL>\n\n<P>\n  To use Lua as a library in your own programs you'll need to know how to\n  create and use libraries with your compiler. Moreover, to dynamically load\n  C libraries for Lua you'll need to know how to create dynamic libraries\n  and you'll need to make sure that the Lua API functions are accessible to\n  those dynamic libraries &mdash; but <EM>don't</EM> link the Lua library\n  into each dynamic library. For Unix, we recommend that the Lua library\n  be linked statically into the host program and its symbols exported for\n  dynamic linking; <TT>src/Makefile</TT> does this for the Lua interpreter.\n  For Windows, we recommend that the Lua library be a DLL.\n  In all cases, the compiler luac should be linked statically.\n\n<P>\n  As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize\n  some features before building Lua.\n\n<H2><A NAME=\"changes\">Changes since Lua 5.2</A></H2>\n<P>\nHere are the main changes introduced in Lua 5.3.\nThe\n<A HREF=\"contents.html\">reference manual</A>\nlists the\n<A HREF=\"manual.html#8\">incompatibilities</A> that had to be introduced.\n\n<H3>Main changes</H3>\n<UL>\n<LI> integers (64-bit by default)\n<LI> official support for 32-bit numbers\n<LI> bitwise operators\n<LI> basic utf-8 support\n<LI> functions for packing and unpacking values\n\n</UL>\n\nHere are the other changes introduced in Lua 5.3:\n<H3>Language</H3>\n<UL>\n<LI> userdata can have any Lua value as uservalue\n<LI> floor division\n<LI> more flexible rules for some metamethods\n</UL>\n\n<H3>Libraries</H3>\n<UL>\n<LI> <CODE>ipairs</CODE> and the table library respect metamethods\n<LI> strip option in <CODE>string.dump</CODE>\n<LI> table library respects metamethods\n<LI> new function <CODE>table.move</CODE>\n<LI> new function <CODE>string.pack</CODE>\n<LI> new function <CODE>string.unpack</CODE>\n<LI> new function <CODE>string.packsize</CODE>\n</UL>\n\n<H3>C API</H3>\n<UL>\n<LI> simpler API for continuation functions in C\n<LI> <CODE>lua_gettable</CODE> and similar functions return type of resulted value\n<LI> strip option in <CODE>lua_dump</CODE>\n<LI> new function: <CODE>lua_geti</CODE>\n<LI> new function: <CODE>lua_seti</CODE>\n<LI> new function: <CODE>lua_isyieldable</CODE>\n<LI> new function: <CODE>lua_numbertointeger</CODE>\n<LI> new function: <CODE>lua_rotate</CODE>\n<LI> new function: <CODE>lua_stringtonumber</CODE>\n</UL>\n\n<H3>Lua standalone interpreter</H3>\n<UL>\n<LI> can be used as calculator; no need to prefix with '='\n<LI> <CODE>arg</CODE> table available to all code\n</UL>\n\n<H2><A NAME=\"license\">License</A></H2>\n<P>\n<A HREF=\"http://www.opensource.org/docs/definition.php\">\n<IMG SRC=\"osi-certified-72x60.png\" ALIGN=\"right\" ALT=\"[osi certified]\" STYLE=\"padding-left: 30px ;\">\n</A>\nLua is free software distributed under the terms of the\n<A HREF=\"http://www.opensource.org/licenses/mit-license.html\">MIT license</A>\nreproduced below;\nit may be used for any purpose, including commercial purposes,\nat absolutely no cost without having to ask us.\n\nThe only requirement is that if you do use Lua,\nthen you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.\n\nFor details, see\n<A HREF=\"http://www.lua.org/license.html\">this</A>.\n\n<BLOCKQUOTE STYLE=\"padding-bottom: 0em\">\nCopyright &copy; 1994&ndash;2017 Lua.org, PUC-Rio.\n\n<P>\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\n<P>\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\n<P>\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n</BLOCKQUOTE>\n<P>\n\n<P CLASS=\"footer\">\nLast update:\nMon Jun 18 22:57:33 -03 2018\n</P>\n<!--\nLast change: revised for Lua 5.3.5\n-->\n\n</BODY>\n</HTML>\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/Makefile",
    "content": "# Makefile for building Lua\n# See ../doc/readme.html for installation and customization instructions.\n\n# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================\n\n# Your platform. See PLATS for possible values.\nPLAT= none\n\nCC= gcc -std=gnu99\nCFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS)\nLDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)\nLIBS= -lm $(SYSLIBS) $(MYLIBS)\n\nAR= ar rcu\nRANLIB= ranlib\nRM= rm -f\n\nSYSCFLAGS=\nSYSLDFLAGS=\nSYSLIBS=\n\nMYCFLAGS=\nMYLDFLAGS=\nMYLIBS=\nMYOBJS=\n\n# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======\n\nPLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris\n\nLUA_A=\tliblua.a\nCORE_O=\tlapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \\\n\tlmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \\\n\tltm.o lundump.o lvm.o lzio.o\nLIB_O=\tlauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \\\n\tlmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o\nBASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)\n\nLUA_T=\tlua\nLUA_O=\tlua.o\n\nLUAC_T=\tluac\nLUAC_O=\tluac.o\n\nALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)\nALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)\nALL_A= $(LUA_A)\n\n# Targets start here.\ndefault: $(PLAT)\n\nall:\t$(ALL_T)\n\no:\t$(ALL_O)\n\na:\t$(ALL_A)\n\n$(LUA_A): $(BASE_O)\n\t$(AR) $@ $(BASE_O)\n\t$(RANLIB) $@\n\n$(LUA_T): $(LUA_O) $(LUA_A)\n\t$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)\n\n$(LUAC_T): $(LUAC_O) $(LUA_A)\n\t$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)\n\nclean:\n\t$(RM) $(ALL_T) $(ALL_O)\n\ndepend:\n\t@$(CC) $(CFLAGS) -MM l*.c\n\necho:\n\t@echo \"PLAT= $(PLAT)\"\n\t@echo \"CC= $(CC)\"\n\t@echo \"CFLAGS= $(CFLAGS)\"\n\t@echo \"LDFLAGS= $(SYSLDFLAGS)\"\n\t@echo \"LIBS= $(LIBS)\"\n\t@echo \"AR= $(AR)\"\n\t@echo \"RANLIB= $(RANLIB)\"\n\t@echo \"RM= $(RM)\"\n\n# Convenience targets for popular platforms\nALL= all\n\nnone:\n\t@echo \"Please do 'make PLATFORM' where PLATFORM is one of these:\"\n\t@echo \"   $(PLATS)\"\n\naix:\n\t$(MAKE) $(ALL) CC=\"xlc\" CFLAGS=\"-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN\" SYSLIBS=\"-ldl\" SYSLDFLAGS=\"-brtl -bexpall\"\n\nbsd:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_POSIX -DLUA_USE_DLOPEN\" SYSLIBS=\"-Wl,-E\"\n\nc89:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_C89\" CC=\"gcc -std=c89\"\n\t@echo ''\n\t@echo '*** C89 does not guarantee 64-bit integers for Lua.'\n\t@echo ''\n\n\nfreebsd:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_LINUX -DLUA_USE_READLINE -I/usr/include/edit\" SYSLIBS=\"-Wl,-E -ledit\" CC=\"cc\"\n\ngeneric: $(ALL)\n\nlinux:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_LINUX\" SYSLIBS=\"-Wl,-E -ldl -lreadline\"\n\nmacosx:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_MACOSX\" SYSLIBS=\"-lreadline\"\n\nmingw:\n\t$(MAKE) \"LUA_A=lua53.dll\" \"LUA_T=lua.exe\" \\\n\t\"AR=$(CC) -shared -o\" \"RANLIB=strip --strip-unneeded\" \\\n\t\"SYSCFLAGS=-DLUA_BUILD_AS_DLL\" \"SYSLIBS=\" \"SYSLDFLAGS=-s\" lua.exe\n\t$(MAKE) \"LUAC_T=luac.exe\" luac.exe\n\nposix:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_POSIX\"\n\nsolaris:\n\t$(MAKE) $(ALL) SYSCFLAGS=\"-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT\" SYSLIBS=\"-ldl\"\n\n# list targets that do not create files (but not all makes understand .PHONY)\n.PHONY: all $(PLATS) default o a clean depend echo none\n\n# DO NOT DELETE\n\nlapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \\\n lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \\\n ltable.h lundump.h lvm.h\nlauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h\nlbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \\\n llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \\\n ldo.h lgc.h lstring.h ltable.h lvm.h\nlcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h\nldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \\\n lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \\\n ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h\nldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \\\n lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \\\n lparser.h lstring.h ltable.h lundump.h lvm.h\nldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \\\n ltm.h lzio.h lmem.h lundump.h\nlfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \\\n lgc.h lstate.h ltm.h lzio.h lmem.h\nlgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \\\n llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h\nlinit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h\nliolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nllex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \\\n lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \\\n lstring.h ltable.h\nlmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \\\n llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h\nloadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \\\n ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \\\n lvm.h\nlopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h\nloslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \\\n llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \\\n ldo.h lfunc.h lstring.h lgc.h ltable.h\nlstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \\\n lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \\\n lstring.h ltable.h\nlstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \\\n lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h\nlstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \\\n llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h\nltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \\\n llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h\nlua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nluac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h \\\n lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h\nlundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \\\n lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \\\n lundump.h\nlutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h\nlvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \\\n llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \\\n ltable.h lvm.h\nlzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \\\n lobject.h ltm.h lzio.h\n\n# (end of Makefile)\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lapi.c",
    "content": "/*\n** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $\n** Lua API\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 6011)\n#pragma warning(disable: 4244)\n#define lapi_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stdarg.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lapi.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lgc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n#include \"lundump.h\"\n#include \"lvm.h\"\n\n\n\nconst char lua_ident[] =\n  \"$LuaVersion: \" LUA_COPYRIGHT \" $\"\n  \"$LuaAuthors: \" LUA_AUTHORS \" $\";\n\n\n/* value at a non-valid index */\n#define NONVALIDVALUE\t\tcast(TValue *, luaO_nilobject)\n\n/* corresponding test */\n#define isvalid(o)\t((o) != luaO_nilobject)\n\n/* test for pseudo index */\n#define ispseudo(i)\t\t((i) <= LUA_REGISTRYINDEX)\n\n/* test for upvalue */\n#define isupvalue(i)\t\t((i) < LUA_REGISTRYINDEX)\n\n/* test for valid but not pseudo index */\n#define isstackindex(i, o)\t(isvalid(o) && !ispseudo(i))\n\n#define api_checkvalidindex(l,o)  api_check(l, isvalid(o), \"invalid index\")\n\n#define api_checkstackindex(l, i, o)  \\\n\tapi_check(l, isstackindex(i, o), \"index not in the stack\")\n\n\nstatic TValue *index2addr (lua_State *L, int idx) {\n  CallInfo *ci = L->ci;\n  if (idx > 0) {\n    TValue *o = ci->func + idx;\n    api_check(L, idx <= ci->top - (ci->func + 1), \"unacceptable index\");\n    if (o >= L->top) return NONVALIDVALUE;\n    else return o;\n  }\n  else if (!ispseudo(idx)) {  /* negative index */\n    api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), \"invalid index\");\n    return L->top + idx;\n  }\n  else if (idx == LUA_REGISTRYINDEX)\n    return &G(L)->l_registry;\n  else {  /* upvalues */\n    idx = LUA_REGISTRYINDEX - idx;\n    api_check(L, idx <= MAXUPVAL + 1, \"upvalue index too large\");\n    if (ttislcf(ci->func))  /* light C function? */\n      return NONVALIDVALUE;  /* it has no upvalues */\n    else {\n      CClosure *func = clCvalue(ci->func);\n      return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE;\n    }\n  }\n}\n\n\n/*\n** to be called by 'lua_checkstack' in protected mode, to grow stack\n** capturing memory errors\n*/\nstatic void growstack (lua_State *L, void *ud) {\n  int size = *(int *)ud;\n  luaD_growstack(L, size);\n}\n\n\nLUA_API int lua_checkstack (lua_State *L, int n) {\n  int res;\n  CallInfo *ci = L->ci;\n  lua_lock(L);\n  api_check(L, n >= 0, \"negative 'n'\");\n  if (L->stack_last - L->top > n)  /* stack large enough? */\n    res = 1;  /* yes; check is OK */\n  else {  /* no; need to grow stack */\n    int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;\n    if (inuse > LUAI_MAXSTACK - n)  /* can grow without overflow? */\n      res = 0;  /* no */\n    else  /* try to grow stack */\n      res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK);\n  }\n  if (res && ci->top < L->top + n)\n    ci->top = L->top + n;  /* adjust frame top */\n  lua_unlock(L);\n  return res;\n}\n\n\nLUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {\n  int i;\n  if (from == to) return;\n  lua_lock(to);\n  api_checknelems(from, n);\n  api_check(from, G(from) == G(to), \"moving among independent states\");\n  api_check(from, to->ci->top - to->top >= n, \"stack overflow\");\n  from->top -= n;\n  for (i = 0; i < n; i++) {\n    setobj2s(to, to->top, from->top + i);\n    to->top++;  /* stack already checked by previous 'api_check' */\n  }\n  lua_unlock(to);\n}\n\n\nLUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {\n  lua_CFunction old;\n  lua_lock(L);\n  old = G(L)->panic;\n  G(L)->panic = panicf;\n  lua_unlock(L);\n  return old;\n}\n\n\nLUA_API const lua_Number *lua_version (lua_State *L) {\n  static const lua_Number version = LUA_VERSION_NUM;\n  if (L == NULL) return &version;\n  else return G(L)->version;\n}\n\n\n\n/*\n** basic stack manipulation\n*/\n\n\n/*\n** convert an acceptable stack index into an absolute index\n*/\nLUA_API int lua_absindex (lua_State *L, int idx) {\n  return (idx > 0 || ispseudo(idx))\n         ? idx\n         : cast_int(L->top - L->ci->func) + idx;\n}\n\n\nLUA_API int lua_gettop (lua_State *L) {\n  return cast_int(L->top - (L->ci->func + 1));\n}\n\n\nLUA_API void lua_settop (lua_State *L, int idx) {\n  StkId func = L->ci->func;\n  lua_lock(L);\n  if (idx >= 0) {\n    api_check(L, idx <= L->stack_last - (func + 1), \"new top too large\");\n    while (L->top < (func + 1) + idx)\n      setnilvalue(L->top++);\n    L->top = (func + 1) + idx;\n  }\n  else {\n    api_check(L, -(idx+1) <= (L->top - (func + 1)), \"invalid new top\");\n    L->top += idx+1;  /* 'subtract' index (index is negative) */\n  }\n  lua_unlock(L);\n}\n\n\n/*\n** Reverse the stack segment from 'from' to 'to'\n** (auxiliary to 'lua_rotate')\n*/\nstatic void reverse (lua_State *L, StkId from, StkId to) {\n  for (; from < to; from++, to--) {\n    TValue temp;\n    setobj(L, &temp, from);\n    setobjs2s(L, from, to);\n    setobj2s(L, to, &temp);\n  }\n}\n\n\n/*\n** Let x = AB, where A is a prefix of length 'n'. Then,\n** rotate x n == BA. But BA == (A^r . B^r)^r.\n*/\nLUA_API void lua_rotate (lua_State *L, int idx, int n) {\n  StkId p, t, m;\n  lua_lock(L);\n  t = L->top - 1;  /* end of stack segment being rotated */\n  p = index2addr(L, idx);  /* start of segment */\n  api_checkstackindex(L, idx, p);\n  api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), \"invalid 'n'\");\n  m = (n >= 0 ? t - n : p - n - 1);  /* end of prefix */\n  reverse(L, p, m);  /* reverse the prefix with length 'n' */\n  reverse(L, m + 1, t);  /* reverse the suffix */\n  reverse(L, p, t);  /* reverse the entire segment */\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {\n  TValue *fr, *to;\n  lua_lock(L);\n  fr = index2addr(L, fromidx);\n  to = index2addr(L, toidx);\n  api_checkvalidindex(L, to);\n  setobj(L, to, fr);\n  if (isupvalue(toidx))  /* function upvalue? */\n    luaC_barrier(L, clCvalue(L->ci->func), fr);\n  /* LUA_REGISTRYINDEX does not need gc barrier\n     (collector revisits it before finishing collection) */\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_pushvalue (lua_State *L, int idx) {\n  lua_lock(L);\n  setobj2s(L, L->top, index2addr(L, idx));\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\n\n/*\n** access functions (stack -> C)\n*/\n\n\nLUA_API int lua_type (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  return (isvalid(o) ? ttnov(o) : LUA_TNONE);\n}\n\n\nLUA_API const char *lua_typename (lua_State *L, int t) {\n  UNUSED(L);\n  api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, \"invalid tag\");\n  return ttypename(t);\n}\n\n\nLUA_API int lua_iscfunction (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  return (ttislcf(o) || (ttisCclosure(o)));\n}\n\n\nLUA_API int lua_isinteger (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  return ttisinteger(o);\n}\n\n\nLUA_API int lua_isnumber (lua_State *L, int idx) {\n  lua_Number n;\n  const TValue *o = index2addr(L, idx);\n  return tonumber(o, &n);\n}\n\n\nLUA_API int lua_isstring (lua_State *L, int idx) {\n  const TValue *o = index2addr(L, idx);\n  return (ttisstring(o) || cvt2str(o));\n}\n\n\nLUA_API int lua_isuserdata (lua_State *L, int idx) {\n  const TValue *o = index2addr(L, idx);\n  return (ttisfulluserdata(o) || ttislightuserdata(o));\n}\n\n\nLUA_API int lua_rawequal (lua_State *L, int index1, int index2) {\n  StkId o1 = index2addr(L, index1);\n  StkId o2 = index2addr(L, index2);\n  return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0;\n}\n\n\nLUA_API void lua_arith (lua_State *L, int op) {\n  lua_lock(L);\n  if (op != LUA_OPUNM && op != LUA_OPBNOT)\n    api_checknelems(L, 2);  /* all other operations expect two operands */\n  else {  /* for unary operations, add fake 2nd operand */\n    api_checknelems(L, 1);\n    setobjs2s(L, L->top, L->top - 1);\n    api_incr_top(L);\n  }\n  /* first operand at top - 2, second at top - 1; result go to top - 2 */\n  luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2);\n  L->top--;  /* remove second operand */\n  lua_unlock(L);\n}\n\n\nLUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {\n  StkId o1, o2;\n  int i = 0;\n  lua_lock(L);  /* may call tag method */\n  o1 = index2addr(L, index1);\n  o2 = index2addr(L, index2);\n  if (isvalid(o1) && isvalid(o2)) {\n    switch (op) {\n      case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break;\n      case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;\n      case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break;\n      default: api_check(L, 0, \"invalid option\");\n    }\n  }\n  lua_unlock(L);\n  return i;\n}\n\n\nLUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {\n  size_t sz = luaO_str2num(s, L->top);\n  if (sz != 0)\n    api_incr_top(L);\n  return sz;\n}\n\n\nLUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) {\n  lua_Number n;\n  const TValue *o = index2addr(L, idx);\n  int isnum = tonumber(o, &n);\n  if (!isnum)\n    n = 0;  /* call to 'tonumber' may change 'n' even if it fails */\n  if (pisnum) *pisnum = isnum;\n  return n;\n}\n\n\nLUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {\n  lua_Integer res;\n  const TValue *o = index2addr(L, idx);\n  int isnum = tointeger(o, &res);\n  if (!isnum)\n    res = 0;  /* call to 'tointeger' may change 'n' even if it fails */\n  if (pisnum) *pisnum = isnum;\n  return res;\n}\n\n\nLUA_API int lua_toboolean (lua_State *L, int idx) {\n  const TValue *o = index2addr(L, idx);\n  return !l_isfalse(o);\n}\n\n\nLUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {\n  StkId o = index2addr(L, idx);\n  if (!ttisstring(o)) {\n    if (!cvt2str(o)) {  /* not convertible? */\n      if (len != NULL) *len = 0;\n      return NULL;\n    }\n    lua_lock(L);  /* 'luaO_tostring' may create a new string */\n    luaO_tostring(L, o);\n    luaC_checkGC(L);\n    o = index2addr(L, idx);  /* previous call may reallocate the stack */\n    lua_unlock(L);\n  }\n  if (len != NULL)\n    *len = vslen(o);\n  return svalue(o);\n}\n\n\nLUA_API size_t lua_rawlen (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  switch (ttype(o)) {\n    case LUA_TSHRSTR: return tsvalue(o)->shrlen;\n    case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;\n    case LUA_TUSERDATA: return uvalue(o)->len;\n    case LUA_TTABLE: return (size_t)luaH_getn(hvalue(o));\n    default: return 0;\n  }\n}\n\n\nLUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  if (ttislcf(o)) return fvalue(o);\n  else if (ttisCclosure(o))\n    return clCvalue(o)->f;\n  else return NULL;  /* not a C function */\n}\n\n\nLUA_API void *lua_touserdata (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  switch (ttnov(o)) {\n    case LUA_TUSERDATA: return getudatamem(uvalue(o));\n    case LUA_TLIGHTUSERDATA: return pvalue(o);\n    default: return NULL;\n  }\n}\n\n\nLUA_API lua_State *lua_tothread (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  return (!ttisthread(o)) ? NULL : thvalue(o);\n}\n\n\nLUA_API const void *lua_topointer (lua_State *L, int idx) {\n  StkId o = index2addr(L, idx);\n  switch (ttype(o)) {\n    case LUA_TTABLE: return hvalue(o);\n    case LUA_TLCL: return clLvalue(o);\n    case LUA_TCCL: return clCvalue(o);\n    case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));\n    case LUA_TTHREAD: return thvalue(o);\n    case LUA_TUSERDATA: return getudatamem(uvalue(o));\n    case LUA_TLIGHTUSERDATA: return pvalue(o);\n    default: return NULL;\n  }\n}\n\n\n\n/*\n** push functions (C -> stack)\n*/\n\n\nLUA_API void lua_pushnil (lua_State *L) {\n  lua_lock(L);\n  setnilvalue(L->top);\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_pushnumber (lua_State *L, lua_Number n) {\n  lua_lock(L);\n  setfltvalue(L->top, n);\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {\n  lua_lock(L);\n  setivalue(L->top, n);\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\n/*\n** Pushes on the stack a string with given length. Avoid using 's' when\n** 'len' == 0 (as 's' can be NULL in that case), due to later use of\n** 'memcmp' and 'memcpy'.\n*/\nLUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {\n  TString *ts;\n  lua_lock(L);\n  ts = (len == 0) ? luaS_new(L, \"\") : luaS_newlstr(L, s, len);\n  setsvalue2s(L, L->top, ts);\n  api_incr_top(L);\n  luaC_checkGC(L);\n  lua_unlock(L);\n  return getstr(ts);\n}\n\n\nLUA_API const char *lua_pushstring (lua_State *L, const char *s) {\n  lua_lock(L);\n  if (s == NULL)\n    setnilvalue(L->top);\n  else {\n    TString *ts;\n    ts = luaS_new(L, s);\n    setsvalue2s(L, L->top, ts);\n    s = getstr(ts);  /* internal copy's address */\n  }\n  api_incr_top(L);\n  luaC_checkGC(L);\n  lua_unlock(L);\n  return s;\n}\n\n\nLUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,\n                                      va_list argp) {\n  const char *ret;\n  lua_lock(L);\n  ret = luaO_pushvfstring(L, fmt, argp);\n  luaC_checkGC(L);\n  lua_unlock(L);\n  return ret;\n}\n\n\nLUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {\n  const char *ret;\n  va_list argp;\n  lua_lock(L);\n  va_start(argp, fmt);\n  ret = luaO_pushvfstring(L, fmt, argp);\n  va_end(argp);\n  luaC_checkGC(L);\n  lua_unlock(L);\n  return ret;\n}\n\n\nLUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {\n  lua_lock(L);\n  if (n == 0) {\n    setfvalue(L->top, fn);\n    api_incr_top(L);\n  }\n  else {\n    CClosure *cl;\n    api_checknelems(L, n);\n    api_check(L, n <= MAXUPVAL, \"upvalue index too large\");\n    cl = luaF_newCclosure(L, n);\n    cl->f = fn;\n    L->top -= n;\n    while (n--) {\n      setobj2n(L, &cl->upvalue[n], L->top + n);\n      /* does not need barrier because closure is white */\n    }\n    setclCvalue(L, L->top, cl);\n    api_incr_top(L);\n    luaC_checkGC(L);\n  }\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_pushboolean (lua_State *L, int b) {\n  lua_lock(L);\n  setbvalue(L->top, (b != 0));  /* ensure that true is 1 */\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_pushlightuserdata (lua_State *L, void *p) {\n  lua_lock(L);\n  setpvalue(L->top, p);\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\nLUA_API int lua_pushthread (lua_State *L) {\n  lua_lock(L);\n  setthvalue(L, L->top, L);\n  api_incr_top(L);\n  lua_unlock(L);\n  return (G(L)->mainthread == L);\n}\n\n\n\n/*\n** get functions (Lua -> stack)\n*/\n\n\nstatic int auxgetstr (lua_State *L, const TValue *t, const char *k) {\n  const TValue *slot;\n  TString *str = luaS_new(L, k);\n  if (luaV_fastget(L, t, str, slot, luaH_getstr)) {\n    setobj2s(L, L->top, slot);\n    api_incr_top(L);\n  }\n  else {\n    setsvalue2s(L, L->top, str);\n    api_incr_top(L);\n    luaV_finishget(L, t, L->top - 1, L->top - 1, slot);\n  }\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\nLUA_API int lua_getglobal (lua_State *L, const char *name) {\n  Table *reg = hvalue(&G(L)->l_registry);\n  lua_lock(L);\n  return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);\n}\n\n\nLUA_API int lua_gettable (lua_State *L, int idx) {\n  StkId t;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  luaV_gettable(L, t, L->top - 1, L->top - 1);\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\nLUA_API int lua_getfield (lua_State *L, int idx, const char *k) {\n  lua_lock(L);\n  return auxgetstr(L, index2addr(L, idx), k);\n}\n\n\nLUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {\n  StkId t;\n  const TValue *slot;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  if (luaV_fastget(L, t, n, slot, luaH_getint)) {\n    setobj2s(L, L->top, slot);\n    api_incr_top(L);\n  }\n  else {\n    setivalue(L->top, n);\n    api_incr_top(L);\n    luaV_finishget(L, t, L->top - 1, L->top - 1, slot);\n  }\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\nLUA_API int lua_rawget (lua_State *L, int idx) {\n  StkId t;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  api_check(L, ttistable(t), \"table expected\");\n  setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\nLUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {\n  StkId t;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  api_check(L, ttistable(t), \"table expected\");\n  setobj2s(L, L->top, luaH_getint(hvalue(t), n));\n  api_incr_top(L);\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\nLUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {\n  StkId t;\n  TValue k;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  api_check(L, ttistable(t), \"table expected\");\n  setpvalue(&k, cast(void *, p));\n  setobj2s(L, L->top, luaH_get(hvalue(t), &k));\n  api_incr_top(L);\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\nLUA_API void lua_createtable (lua_State *L, int narray, int nrec) {\n  Table *t;\n  lua_lock(L);\n  t = luaH_new(L);\n  sethvalue(L, L->top, t);\n  api_incr_top(L);\n  if (narray > 0 || nrec > 0)\n    luaH_resize(L, t, narray, nrec);\n  luaC_checkGC(L);\n  lua_unlock(L);\n}\n\n\nLUA_API int lua_getmetatable (lua_State *L, int objindex) {\n  const TValue *obj;\n  Table *mt;\n  int res = 0;\n  lua_lock(L);\n  obj = index2addr(L, objindex);\n  switch (ttnov(obj)) {\n    case LUA_TTABLE:\n      mt = hvalue(obj)->metatable;\n      break;\n    case LUA_TUSERDATA:\n      mt = uvalue(obj)->metatable;\n      break;\n    default:\n      mt = G(L)->mt[ttnov(obj)];\n      break;\n  }\n  if (mt != NULL) {\n    sethvalue(L, L->top, mt);\n    api_incr_top(L);\n    res = 1;\n  }\n  lua_unlock(L);\n  return res;\n}\n\n\nLUA_API int lua_getuservalue (lua_State *L, int idx) {\n  StkId o;\n  lua_lock(L);\n  o = index2addr(L, idx);\n  api_check(L, ttisfulluserdata(o), \"full userdata expected\");\n  getuservalue(L, uvalue(o), L->top);\n  api_incr_top(L);\n  lua_unlock(L);\n  return ttnov(L->top - 1);\n}\n\n\n/*\n** set functions (stack -> Lua)\n*/\n\n/*\n** t[k] = value at the top of the stack (where 'k' is a string)\n*/\nstatic void auxsetstr (lua_State *L, const TValue *t, const char *k) {\n  const TValue *slot;\n  TString *str = luaS_new(L, k);\n  api_checknelems(L, 1);\n  if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))\n    L->top--;  /* pop value */\n  else {\n    setsvalue2s(L, L->top, str);  /* push 'str' (to make it a TValue) */\n    api_incr_top(L);\n    luaV_finishset(L, t, L->top - 1, L->top - 2, slot);\n    L->top -= 2;  /* pop value and key */\n  }\n  lua_unlock(L);  /* lock done by caller */\n}\n\n\nLUA_API void lua_setglobal (lua_State *L, const char *name) {\n  Table *reg = hvalue(&G(L)->l_registry);\n  lua_lock(L);  /* unlock done in 'auxsetstr' */\n  auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);\n}\n\n\nLUA_API void lua_settable (lua_State *L, int idx) {\n  StkId t;\n  lua_lock(L);\n  api_checknelems(L, 2);\n  t = index2addr(L, idx);\n  luaV_settable(L, t, L->top - 2, L->top - 1);\n  L->top -= 2;  /* pop index and value */\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_setfield (lua_State *L, int idx, const char *k) {\n  lua_lock(L);  /* unlock done in 'auxsetstr' */\n  auxsetstr(L, index2addr(L, idx), k);\n}\n\n\nLUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {\n  StkId t;\n  const TValue *slot;\n  lua_lock(L);\n  api_checknelems(L, 1);\n  t = index2addr(L, idx);\n  if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))\n    L->top--;  /* pop value */\n  else {\n    setivalue(L->top, n);\n    api_incr_top(L);\n    luaV_finishset(L, t, L->top - 1, L->top - 2, slot);\n    L->top -= 2;  /* pop value and key */\n  }\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_rawset (lua_State *L, int idx) {\n  StkId o;\n  TValue *slot;\n  lua_lock(L);\n  api_checknelems(L, 2);\n  o = index2addr(L, idx);\n  api_check(L, ttistable(o), \"table expected\");\n  slot = luaH_set(L, hvalue(o), L->top - 2);\n  setobj2t(L, slot, L->top - 1);\n  invalidateTMcache(hvalue(o));\n  luaC_barrierback(L, hvalue(o), L->top-1);\n  L->top -= 2;\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {\n  StkId o;\n  lua_lock(L);\n  api_checknelems(L, 1);\n  o = index2addr(L, idx);\n  api_check(L, ttistable(o), \"table expected\");\n  luaH_setint(L, hvalue(o), n, L->top - 1);\n  luaC_barrierback(L, hvalue(o), L->top-1);\n  L->top--;\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {\n  StkId o;\n  TValue k, *slot;\n  lua_lock(L);\n  api_checknelems(L, 1);\n  o = index2addr(L, idx);\n  api_check(L, ttistable(o), \"table expected\");\n  setpvalue(&k, cast(void *, p));\n  slot = luaH_set(L, hvalue(o), &k);\n  setobj2t(L, slot, L->top - 1);\n  luaC_barrierback(L, hvalue(o), L->top - 1);\n  L->top--;\n  lua_unlock(L);\n}\n\n\nLUA_API int lua_setmetatable (lua_State *L, int objindex) {\n  TValue *obj;\n  Table *mt;\n  lua_lock(L);\n  api_checknelems(L, 1);\n  obj = index2addr(L, objindex);\n  if (ttisnil(L->top - 1))\n    mt = NULL;\n  else {\n    api_check(L, ttistable(L->top - 1), \"table expected\");\n    mt = hvalue(L->top - 1);\n  }\n  switch (ttnov(obj)) {\n    case LUA_TTABLE: {\n      hvalue(obj)->metatable = mt;\n      if (mt) {\n        luaC_objbarrier(L, gcvalue(obj), mt);\n        luaC_checkfinalizer(L, gcvalue(obj), mt);\n      }\n      break;\n    }\n    case LUA_TUSERDATA: {\n      uvalue(obj)->metatable = mt;\n      if (mt) {\n        luaC_objbarrier(L, uvalue(obj), mt);\n        luaC_checkfinalizer(L, gcvalue(obj), mt);\n      }\n      break;\n    }\n    default: {\n      G(L)->mt[ttnov(obj)] = mt;\n      break;\n    }\n  }\n  L->top--;\n  lua_unlock(L);\n  return 1;\n}\n\n\nLUA_API void lua_setuservalue (lua_State *L, int idx) {\n  StkId o;\n  lua_lock(L);\n  api_checknelems(L, 1);\n  o = index2addr(L, idx);\n  api_check(L, ttisfulluserdata(o), \"full userdata expected\");\n  setuservalue(L, uvalue(o), L->top - 1);\n  luaC_barrier(L, gcvalue(o), L->top - 1);\n  L->top--;\n  lua_unlock(L);\n}\n\n\n/*\n** 'load' and 'call' functions (run Lua code)\n*/\n\n\n#define checkresults(L,na,nr) \\\n     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \\\n\t\"results from function overflow current stack size\")\n\n\nLUA_API void lua_callk (lua_State *L, int nargs, int nresults,\n                        lua_KContext ctx, lua_KFunction k) {\n  StkId func;\n  lua_lock(L);\n  api_check(L, k == NULL || !isLua(L->ci),\n    \"cannot use continuations inside hooks\");\n  api_checknelems(L, nargs+1);\n  api_check(L, L->status == LUA_OK, \"cannot do calls on non-normal thread\");\n  checkresults(L, nargs, nresults);\n  func = L->top - (nargs+1);\n  if (k != NULL && L->nny == 0) {  /* need to prepare continuation? */\n    L->ci->u.c.k = k;  /* save continuation */\n    L->ci->u.c.ctx = ctx;  /* save context */\n    luaD_call(L, func, nresults);  /* do the call */\n  }\n  else  /* no continuation or no yieldable */\n    luaD_callnoyield(L, func, nresults);  /* just do the call */\n  adjustresults(L, nresults);\n  lua_unlock(L);\n}\n\n\n\n/*\n** Execute a protected call.\n*/\nstruct CallS {  /* data to 'f_call' */\n  StkId func;\n  int nresults;\n};\n\n\nstatic void f_call (lua_State *L, void *ud) {\n  struct CallS *c = cast(struct CallS *, ud);\n  luaD_callnoyield(L, c->func, c->nresults);\n}\n\n\n\nLUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,\n                        lua_KContext ctx, lua_KFunction k) {\n  struct CallS c;\n  int status;\n  ptrdiff_t func;\n  lua_lock(L);\n  api_check(L, k == NULL || !isLua(L->ci),\n    \"cannot use continuations inside hooks\");\n  api_checknelems(L, nargs+1);\n  api_check(L, L->status == LUA_OK, \"cannot do calls on non-normal thread\");\n  checkresults(L, nargs, nresults);\n  if (errfunc == 0)\n    func = 0;\n  else {\n    StkId o = index2addr(L, errfunc);\n    api_checkstackindex(L, errfunc, o);\n    func = savestack(L, o);\n  }\n  c.func = L->top - (nargs+1);  /* function to be called */\n  if (k == NULL || L->nny > 0) {  /* no continuation or no yieldable? */\n    c.nresults = nresults;  /* do a 'conventional' protected call */\n    status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);\n  }\n  else {  /* prepare continuation (call is already protected by 'resume') */\n    CallInfo *ci = L->ci;\n    ci->u.c.k = k;  /* save continuation */\n    ci->u.c.ctx = ctx;  /* save context */\n    /* save information for error recovery */\n    ci->extra = savestack(L, c.func);\n    ci->u.c.old_errfunc = L->errfunc;\n    L->errfunc = func;\n    setoah(ci->callstatus, L->allowhook);  /* save value of 'allowhook' */\n    ci->callstatus |= CIST_YPCALL;  /* function can do error recovery */\n    luaD_call(L, c.func, nresults);  /* do the call */\n    ci->callstatus &= ~CIST_YPCALL;\n    L->errfunc = ci->u.c.old_errfunc;\n    status = LUA_OK;  /* if it is here, there were no errors */\n  }\n  adjustresults(L, nresults);\n  lua_unlock(L);\n  return status;\n}\n\n\nLUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,\n                      const char *chunkname, const char *mode) {\n  ZIO z;\n  int status;\n  lua_lock(L);\n  if (!chunkname) chunkname = \"?\";\n  luaZ_init(L, &z, reader, data);\n  status = luaD_protectedparser(L, &z, chunkname, mode);\n  if (status == LUA_OK) {  /* no errors? */\n    LClosure *f = clLvalue(L->top - 1);  /* get newly created function */\n    if (f->nupvalues >= 1) {  /* does it have an upvalue? */\n      /* get global table from registry */\n      Table *reg = hvalue(&G(L)->l_registry);\n      const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);\n      /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */\n      setobj(L, f->upvals[0]->v, gt);\n      luaC_upvalbarrier(L, f->upvals[0]);\n    }\n  }\n  lua_unlock(L);\n  return status;\n}\n\n\nLUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {\n  int status;\n  TValue *o;\n  lua_lock(L);\n  api_checknelems(L, 1);\n  o = L->top - 1;\n  if (isLfunction(o))\n    status = luaU_dump(L, getproto(o), writer, data, strip);\n  else\n    status = 1;\n  lua_unlock(L);\n  return status;\n}\n\n\nLUA_API int lua_status (lua_State *L) {\n  return L->status;\n}\n\n\n/*\n** Garbage-collection function\n*/\n\nLUA_API int lua_gc (lua_State *L, int what, int data) {\n  int res = 0;\n  global_State *g;\n  lua_lock(L);\n  g = G(L);\n  switch (what) {\n    case LUA_GCSTOP: {\n      g->gcrunning = 0;\n      break;\n    }\n    case LUA_GCRESTART: {\n      luaE_setdebt(g, 0);\n      g->gcrunning = 1;\n      break;\n    }\n    case LUA_GCCOLLECT: {\n      luaC_fullgc(L, 0);\n      break;\n    }\n    case LUA_GCCOUNT: {\n      /* GC values are expressed in Kbytes: #bytes/2^10 */\n      res = cast_int(gettotalbytes(g) >> 10);\n      break;\n    }\n    case LUA_GCCOUNTB: {\n      res = cast_int(gettotalbytes(g) & 0x3ff);\n      break;\n    }\n    case LUA_GCSTEP: {\n      l_mem debt = 1;  /* =1 to signal that it did an actual step */\n      lu_byte oldrunning = g->gcrunning;\n      g->gcrunning = 1;  /* allow GC to run */\n      if (data == 0) {\n        luaE_setdebt(g, -GCSTEPSIZE);  /* to do a \"small\" step */\n        luaC_step(L);\n      }\n      else {  /* add 'data' to total debt */\n        debt = cast(l_mem, data) * 1024 + g->GCdebt;\n        luaE_setdebt(g, debt);\n        luaC_checkGC(L);\n      }\n      g->gcrunning = oldrunning;  /* restore previous state */\n      if (debt > 0 && g->gcstate == GCSpause)  /* end of cycle? */\n        res = 1;  /* signal it */\n      break;\n    }\n    case LUA_GCSETPAUSE: {\n      res = g->gcpause;\n      g->gcpause = data;\n      break;\n    }\n    case LUA_GCSETSTEPMUL: {\n      res = g->gcstepmul;\n      if (data < 40) data = 40;  /* avoid ridiculous low values (and 0) */\n      g->gcstepmul = data;\n      break;\n    }\n    case LUA_GCISRUNNING: {\n      res = g->gcrunning;\n      break;\n    }\n    default: res = -1;  /* invalid option */\n  }\n  lua_unlock(L);\n  return res;\n}\n\n\n\n/*\n** miscellaneous functions\n*/\n\n\nLUA_API int lua_error (lua_State *L) {\n  lua_lock(L);\n  api_checknelems(L, 1);\n  luaG_errormsg(L);\n  /* code unreachable; will unlock when control actually leaves the kernel */\n  return 0;  /* to avoid warnings */\n}\n\n\nLUA_API int lua_next (lua_State *L, int idx) {\n  StkId t;\n  int more;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  api_check(L, ttistable(t), \"table expected\");\n  more = luaH_next(L, hvalue(t), L->top - 1);\n  if (more) {\n    api_incr_top(L);\n  }\n  else  /* no more elements */\n    L->top -= 1;  /* remove key */\n  lua_unlock(L);\n  return more;\n}\n\n\nLUA_API void lua_concat (lua_State *L, int n) {\n  lua_lock(L);\n  api_checknelems(L, n);\n  if (n >= 2) {\n    luaV_concat(L, n);\n  }\n  else if (n == 0) {  /* push empty string */\n    setsvalue2s(L, L->top, luaS_newlstr(L, \"\", 0));\n    api_incr_top(L);\n  }\n  /* else n == 1; nothing to do */\n  luaC_checkGC(L);\n  lua_unlock(L);\n}\n\n\nLUA_API void lua_len (lua_State *L, int idx) {\n  StkId t;\n  lua_lock(L);\n  t = index2addr(L, idx);\n  luaV_objlen(L, L->top, t);\n  api_incr_top(L);\n  lua_unlock(L);\n}\n\n\nLUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) {\n  lua_Alloc f;\n  lua_lock(L);\n  if (ud) *ud = G(L)->ud;\n  f = G(L)->frealloc;\n  lua_unlock(L);\n  return f;\n}\n\n\nLUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {\n  lua_lock(L);\n  G(L)->ud = ud;\n  G(L)->frealloc = f;\n  lua_unlock(L);\n}\n\n\nLUA_API void *lua_newuserdata (lua_State *L, size_t size) {\n  Udata *u;\n  lua_lock(L);\n  u = luaS_newudata(L, size);\n  setuvalue(L, L->top, u);\n  api_incr_top(L);\n  luaC_checkGC(L);\n  lua_unlock(L);\n  return getudatamem(u);\n}\n\n\n\nstatic const char *aux_upvalue (StkId fi, int n, TValue **val,\n                                CClosure **owner, UpVal **uv) {\n  switch (ttype(fi)) {\n    case LUA_TCCL: {  /* C closure */\n      CClosure *f = clCvalue(fi);\n      if (!(1 <= n && n <= f->nupvalues)) return NULL;\n      *val = &f->upvalue[n-1];\n      if (owner) *owner = f;\n      return \"\";\n    }\n    case LUA_TLCL: {  /* Lua closure */\n      LClosure *f = clLvalue(fi);\n      TString *name;\n      Proto *p = f->p;\n      if (!(1 <= n && n <= p->sizeupvalues)) return NULL;\n      *val = f->upvals[n-1]->v;\n      if (uv) *uv = f->upvals[n - 1];\n      name = p->upvalues[n-1].name;\n      return (name == NULL) ? \"(*no name)\" : getstr(name);\n    }\n    default: return NULL;  /* not a closure */\n  }\n}\n\n\nLUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {\n  const char *name;\n  TValue *val = NULL;  /* to avoid warnings */\n  lua_lock(L);\n  name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL);\n  if (name) {\n    setobj2s(L, L->top, val);\n    api_incr_top(L);\n  }\n  lua_unlock(L);\n  return name;\n}\n\n\nLUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {\n  const char *name;\n  TValue *val = NULL;  /* to avoid warnings */\n  CClosure *owner = NULL;\n  UpVal *uv = NULL;\n  StkId fi;\n  lua_lock(L);\n  fi = index2addr(L, funcindex);\n  api_checknelems(L, 1);\n  name = aux_upvalue(fi, n, &val, &owner, &uv);\n  if (name) {\n    L->top--;\n    setobj(L, val, L->top);\n    if (owner) { luaC_barrier(L, owner, L->top); }\n    else if (uv) { luaC_upvalbarrier(L, uv); }\n  }\n  lua_unlock(L);\n  return name;\n}\n\n\nstatic UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {\n  LClosure *f;\n  StkId fi = index2addr(L, fidx);\n  api_check(L, ttisLclosure(fi), \"Lua function expected\");\n  f = clLvalue(fi);\n  api_check(L, (1 <= n && n <= f->p->sizeupvalues), \"invalid upvalue index\");\n  if (pf) *pf = f;\n  return &f->upvals[n - 1];  /* get its upvalue pointer */\n}\n\n\nLUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {\n  StkId fi = index2addr(L, fidx);\n  switch (ttype(fi)) {\n    case LUA_TLCL: {  /* lua closure */\n      return *getupvalref(L, fidx, n, NULL);\n    }\n    case LUA_TCCL: {  /* C closure */\n      CClosure *f = clCvalue(fi);\n      api_check(L, 1 <= n && n <= f->nupvalues, \"invalid upvalue index\");\n      return &f->upvalue[n - 1];\n    }\n    default: {\n      api_check(L, 0, \"closure expected\");\n      return NULL;\n    }\n  }\n}\n\n\nLUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,\n                                            int fidx2, int n2) {\n  LClosure *f1;\n  UpVal **up1 = getupvalref(L, fidx1, n1, &f1);\n  UpVal **up2 = getupvalref(L, fidx2, n2, NULL);\n  luaC_upvdeccount(L, *up1);\n  *up1 = *up2;\n  (*up1)->refcount++;\n  if (upisopen(*up1)) (*up1)->u.open.touched = 1;\n  luaC_upvalbarrier(L, *up1);\n}\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lapi.h",
    "content": "/*\n** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $\n** Auxiliary functions from Lua API\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lapi_h\n#define lapi_h\n\n\n#include \"llimits.h\"\n#include \"lstate.h\"\n\n#define api_incr_top(L)   {L->top++; api_check(L, L->top <= L->ci->top, \\\n\t\t\t\t\"stack overflow\");}\n\n#define adjustresults(L,nres) \\\n    { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }\n\n#define api_checknelems(L,n)\tapi_check(L, (n) < (L->top - L->ci->func), \\\n\t\t\t\t  \"not enough elements in the stack\")\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lauxlib.c",
    "content": "/*\n** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $\n** Auxiliary functions for building Lua libraries\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 4100)\n#pragma warning(disable: 4244)\n#define lauxlib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <errno.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n\n/*\n** This file uses only the official API of Lua.\n** Any function declared here could be written as an application function.\n*/\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n\n\n/*\n** {======================================================\n** Traceback\n** =======================================================\n*/\n\n\n#define LEVELS1\t10\t/* size of the first part of the stack */\n#define LEVELS2\t11\t/* size of the second part of the stack */\n\n\n\n/*\n** search for 'objidx' in table at index -1.\n** return 1 + string at top if find a good name.\n*/\nstatic int findfield (lua_State *L, int objidx, int level) {\n  if (level == 0 || !lua_istable(L, -1))\n    return 0;  /* not found */\n  lua_pushnil(L);  /* start 'next' loop */\n  while (lua_next(L, -2)) {  /* for each pair in table */\n    if (lua_type(L, -2) == LUA_TSTRING) {  /* ignore non-string keys */\n      if (lua_rawequal(L, objidx, -1)) {  /* found object? */\n        lua_pop(L, 1);  /* remove value (but keep name) */\n        return 1;\n      }\n      else if (findfield(L, objidx, level - 1)) {  /* try recursively */\n        lua_remove(L, -2);  /* remove table (but keep name) */\n        lua_pushliteral(L, \".\");\n        lua_insert(L, -2);  /* place '.' between the two names */\n        lua_concat(L, 3);\n        return 1;\n      }\n    }\n    lua_pop(L, 1);  /* remove value */\n  }\n  return 0;  /* not found */\n}\n\n\n/*\n** Search for a name for a function in all loaded modules\n*/\nstatic int pushglobalfuncname (lua_State *L, lua_Debug *ar) {\n  int top = lua_gettop(L);\n  lua_getinfo(L, \"f\", ar);  /* push function */\n  lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n  if (findfield(L, top + 1, 2)) {\n    const char *name = lua_tostring(L, -1);\n    if (strncmp(name, \"_G.\", 3) == 0) {  /* name start with '_G.'? */\n      lua_pushstring(L, name + 3);  /* push name without prefix */\n      lua_remove(L, -2);  /* remove original name */\n    }\n    lua_copy(L, -1, top + 1);  /* move name to proper place */\n    lua_pop(L, 2);  /* remove pushed values */\n    return 1;\n  }\n  else {\n    lua_settop(L, top);  /* remove function and global table */\n    return 0;\n  }\n}\n\n\nstatic void pushfuncname (lua_State *L, lua_Debug *ar) {\n  if (pushglobalfuncname(L, ar)) {  /* try first a global name */\n    lua_pushfstring(L, \"function '%s'\", lua_tostring(L, -1));\n    lua_remove(L, -2);  /* remove name */\n  }\n  else if (*ar->namewhat != '\\0')  /* is there a name from code? */\n    lua_pushfstring(L, \"%s '%s'\", ar->namewhat, ar->name);  /* use it */\n  else if (*ar->what == 'm')  /* main? */\n      lua_pushliteral(L, \"main chunk\");\n  else if (*ar->what != 'C')  /* for Lua functions, use <file:line> */\n    lua_pushfstring(L, \"function <%s:%d>\", ar->short_src, ar->linedefined);\n  else  /* nothing left... */\n    lua_pushliteral(L, \"?\");\n}\n\n\nstatic int lastlevel (lua_State *L) {\n  lua_Debug ar;\n  int li = 1, le = 1;\n  /* find an upper bound */\n  while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }\n  /* do a binary search */\n  while (li < le) {\n    int m = (li + le)/2;\n    if (lua_getstack(L, m, &ar)) li = m + 1;\n    else le = m;\n  }\n  return le - 1;\n}\n\n\nLUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,\n                                const char *msg, int level) {\n  lua_Debug ar;\n  int top = lua_gettop(L);\n  int last = lastlevel(L1);\n  int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;\n  if (msg)\n    lua_pushfstring(L, \"%s\\n\", msg);\n  luaL_checkstack(L, 10, NULL);\n  lua_pushliteral(L, \"stack traceback:\");\n  while (lua_getstack(L1, level++, &ar)) {\n    if (n1-- == 0) {  /* too many levels? */\n      lua_pushliteral(L, \"\\n\\t...\");  /* add a '...' */\n      level = last - LEVELS2 + 1;  /* and skip to last ones */\n    }\n    else {\n      lua_getinfo(L1, \"Slnt\", &ar);\n      lua_pushfstring(L, \"\\n\\t%s:\", ar.short_src);\n      if (ar.currentline > 0)\n        lua_pushfstring(L, \"%d:\", ar.currentline);\n      lua_pushliteral(L, \" in \");\n      pushfuncname(L, &ar);\n      if (ar.istailcall)\n        lua_pushliteral(L, \"\\n\\t(...tail calls...)\");\n      lua_concat(L, lua_gettop(L) - top);\n    }\n  }\n  lua_concat(L, lua_gettop(L) - top);\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Error-report functions\n** =======================================================\n*/\n\nLUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {\n  lua_Debug ar;\n  if (!lua_getstack(L, 0, &ar))  /* no stack frame? */\n    return luaL_error(L, \"bad argument #%d (%s)\", arg, extramsg);\n  lua_getinfo(L, \"n\", &ar);\n  if (strcmp(ar.namewhat, \"method\") == 0) {\n    arg--;  /* do not count 'self' */\n    if (arg == 0)  /* error is in the self argument itself? */\n      return luaL_error(L, \"calling '%s' on bad self (%s)\",\n                           ar.name, extramsg);\n  }\n  if (ar.name == NULL)\n    ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : \"?\";\n  return luaL_error(L, \"bad argument #%d to '%s' (%s)\",\n                        arg, ar.name, extramsg);\n}\n\n\nstatic int typeerror (lua_State *L, int arg, const char *tname) {\n  const char *msg;\n  const char *typearg;  /* name for the type of the actual argument */\n  if (luaL_getmetafield(L, arg, \"__name\") == LUA_TSTRING)\n    typearg = lua_tostring(L, -1);  /* use the given type name */\n  else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)\n    typearg = \"light userdata\";  /* special name for messages */\n  else\n    typearg = luaL_typename(L, arg);  /* standard name */\n  msg = lua_pushfstring(L, \"%s expected, got %s\", tname, typearg);\n  return luaL_argerror(L, arg, msg);\n}\n\n\nstatic void tag_error (lua_State *L, int arg, int tag) {\n  typeerror(L, arg, lua_typename(L, tag));\n}\n\n\n/*\n** The use of 'lua_pushfstring' ensures this function does not\n** need reserved stack space when called.\n*/\nLUALIB_API void luaL_where (lua_State *L, int level) {\n  lua_Debug ar;\n  if (lua_getstack(L, level, &ar)) {  /* check function at level */\n    lua_getinfo(L, \"Sl\", &ar);  /* get info about it */\n    if (ar.currentline > 0) {  /* is there info? */\n      lua_pushfstring(L, \"%s:%d: \", ar.short_src, ar.currentline);\n      return;\n    }\n  }\n  lua_pushfstring(L, \"\");  /* else, no information available... */\n}\n\n\n/*\n** Again, the use of 'lua_pushvfstring' ensures this function does\n** not need reserved stack space when called. (At worst, it generates\n** an error with \"stack overflow\" instead of the given message.)\n*/\nLUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {\n  va_list argp;\n  va_start(argp, fmt);\n  luaL_where(L, 1);\n  lua_pushvfstring(L, fmt, argp);\n  va_end(argp);\n  lua_concat(L, 2);\n  return lua_error(L);\n}\n\n\nLUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {\n  int en = errno;  /* calls to Lua API may change this value */\n  if (stat) {\n    lua_pushboolean(L, 1);\n    return 1;\n  }\n  else {\n    lua_pushnil(L);\n    if (fname)\n      lua_pushfstring(L, \"%s: %s\", fname, strerror(en));\n    else\n      lua_pushstring(L, strerror(en));\n    lua_pushinteger(L, en);\n    return 3;\n  }\n}\n\n\n#if !defined(l_inspectstat)\t/* { */\n\n#if defined(LUA_USE_POSIX)\n\n#include <sys/wait.h>\n\n/*\n** use appropriate macros to interpret 'pclose' return status\n*/\n#define l_inspectstat(stat,what)  \\\n   if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \\\n   else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = \"signal\"; }\n\n#else\n\n#define l_inspectstat(stat,what)  /* no op */\n\n#endif\n\n#endif\t\t\t\t/* } */\n\n\nLUALIB_API int luaL_execresult (lua_State *L, int stat) {\n  const char *what = \"exit\";  /* type of termination */\n  if (stat == -1)  /* error? */\n    return luaL_fileresult(L, 0, NULL);\n  else {\n    l_inspectstat(stat, what);  /* interpret result */\n    if (*what == 'e' && stat == 0)  /* successful termination? */\n      lua_pushboolean(L, 1);\n    else\n      lua_pushnil(L);\n    lua_pushstring(L, what);\n    lua_pushinteger(L, stat);\n    return 3;  /* return true/nil,what,code */\n  }\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Userdata's metatable manipulation\n** =======================================================\n*/\n\nLUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {\n  if (luaL_getmetatable(L, tname) != LUA_TNIL)  /* name already in use? */\n    return 0;  /* leave previous value on top, but return 0 */\n  lua_pop(L, 1);\n  lua_createtable(L, 0, 2);  /* create metatable */\n  lua_pushstring(L, tname);\n  lua_setfield(L, -2, \"__name\");  /* metatable.__name = tname */\n  lua_pushvalue(L, -1);\n  lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */\n  return 1;\n}\n\n\nLUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {\n  luaL_getmetatable(L, tname);\n  lua_setmetatable(L, -2);\n}\n\n\nLUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {\n  void *p = lua_touserdata(L, ud);\n  if (p != NULL) {  /* value is a userdata? */\n    if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */\n      luaL_getmetatable(L, tname);  /* get correct metatable */\n      if (!lua_rawequal(L, -1, -2))  /* not the same? */\n        p = NULL;  /* value is a userdata with wrong metatable */\n      lua_pop(L, 2);  /* remove both metatables */\n      return p;\n    }\n  }\n  return NULL;  /* value is not a userdata with a metatable */\n}\n\n\nLUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {\n  void *p = luaL_testudata(L, ud, tname);\n  if (p == NULL) typeerror(L, ud, tname);\n  return p;\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Argument check functions\n** =======================================================\n*/\n\nLUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,\n                                 const char *const lst[]) {\n  const char *name = (def) ? luaL_optstring(L, arg, def) :\n                             luaL_checkstring(L, arg);\n  int i;\n  for (i=0; lst[i]; i++)\n    if (strcmp(lst[i], name) == 0)\n      return i;\n  return luaL_argerror(L, arg,\n                       lua_pushfstring(L, \"invalid option '%s'\", name));\n}\n\n\n/*\n** Ensures the stack has at least 'space' extra slots, raising an error\n** if it cannot fulfill the request. (The error handling needs a few\n** extra slots to format the error message. In case of an error without\n** this extra space, Lua will generate the same 'stack overflow' error,\n** but without 'msg'.)\n*/\nLUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {\n  if (!lua_checkstack(L, space)) {\n    if (msg)\n      luaL_error(L, \"stack overflow (%s)\", msg);\n    else\n      luaL_error(L, \"stack overflow\");\n  }\n}\n\n\nLUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {\n  if (lua_type(L, arg) != t)\n    tag_error(L, arg, t);\n}\n\n\nLUALIB_API void luaL_checkany (lua_State *L, int arg) {\n  if (lua_type(L, arg) == LUA_TNONE)\n    luaL_argerror(L, arg, \"value expected\");\n}\n\n\nLUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {\n  const char *s = lua_tolstring(L, arg, len);\n  if (!s) tag_error(L, arg, LUA_TSTRING);\n  return s;\n}\n\n\nLUALIB_API const char *luaL_optlstring (lua_State *L, int arg,\n                                        const char *def, size_t *len) {\n  if (lua_isnoneornil(L, arg)) {\n    if (len)\n      *len = (def ? strlen(def) : 0);\n    return def;\n  }\n  else return luaL_checklstring(L, arg, len);\n}\n\n\nLUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {\n  int isnum;\n  lua_Number d = lua_tonumberx(L, arg, &isnum);\n  if (!isnum)\n    tag_error(L, arg, LUA_TNUMBER);\n  return d;\n}\n\n\nLUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) {\n  return luaL_opt(L, luaL_checknumber, arg, def);\n}\n\n\nstatic void interror (lua_State *L, int arg) {\n  if (lua_isnumber(L, arg))\n    luaL_argerror(L, arg, \"number has no integer representation\");\n  else\n    tag_error(L, arg, LUA_TNUMBER);\n}\n\n\nLUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {\n  int isnum;\n  lua_Integer d = lua_tointegerx(L, arg, &isnum);\n  if (!isnum) {\n    interror(L, arg);\n  }\n  return d;\n}\n\n\nLUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,\n                                                      lua_Integer def) {\n  return luaL_opt(L, luaL_checkinteger, arg, def);\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Generic Buffer manipulation\n** =======================================================\n*/\n\n/* userdata to box arbitrary data */\ntypedef struct UBox {\n  void *box;\n  size_t bsize;\n} UBox;\n\n\nstatic void *resizebox (lua_State *L, int idx, size_t newsize) {\n  void *ud;\n  lua_Alloc allocf = lua_getallocf(L, &ud);\n  UBox *box = (UBox *)lua_touserdata(L, idx);\n  void *temp = allocf(ud, box->box, box->bsize, newsize);\n  if (temp == NULL && newsize > 0) {  /* allocation error? */\n    resizebox(L, idx, 0);  /* free buffer */\n    luaL_error(L, \"not enough memory for buffer allocation\");\n  }\n  box->box = temp;\n  box->bsize = newsize;\n  return temp;\n}\n\n\nstatic int boxgc (lua_State *L) {\n  resizebox(L, 1, 0);\n  return 0;\n}\n\n\nstatic void *newbox (lua_State *L, size_t newsize) {\n  UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));\n  box->box = NULL;\n  box->bsize = 0;\n  if (luaL_newmetatable(L, \"LUABOX\")) {  /* creating metatable? */\n    lua_pushcfunction(L, boxgc);\n    lua_setfield(L, -2, \"__gc\");  /* metatable.__gc = boxgc */\n  }\n  lua_setmetatable(L, -2);\n  return resizebox(L, -1, newsize);\n}\n\n\n/*\n** check whether buffer is using a userdata on the stack as a temporary\n** buffer\n*/\n#define buffonstack(B)\t((B)->b != (B)->initb)\n\n\n/*\n** returns a pointer to a free area with at least 'sz' bytes\n*/\nLUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {\n  lua_State *L = B->L;\n  if (B->size - B->n < sz) {  /* not enough space? */\n    char *newbuff;\n    size_t newsize = B->size * 2;  /* double buffer size */\n    if (newsize - B->n < sz)  /* not big enough? */\n      newsize = B->n + sz;\n    if (newsize < B->n || newsize - B->n < sz)\n      luaL_error(L, \"buffer too large\");\n    /* create larger buffer */\n    if (buffonstack(B))\n      newbuff = (char *)resizebox(L, -1, newsize);\n    else {  /* no buffer yet */\n      newbuff = (char *)newbox(L, newsize);\n      memcpy(newbuff, B->b, B->n * sizeof(char));  /* copy original content */\n    }\n    B->b = newbuff;\n    B->size = newsize;\n  }\n  return &B->b[B->n];\n}\n\n\nLUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {\n  if (l > 0) {  /* avoid 'memcpy' when 's' can be NULL */\n    char *b = luaL_prepbuffsize(B, l);\n    memcpy(b, s, l * sizeof(char));\n    luaL_addsize(B, l);\n  }\n}\n\n\nLUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {\n  luaL_addlstring(B, s, strlen(s));\n}\n\n\nLUALIB_API void luaL_pushresult (luaL_Buffer *B) {\n  lua_State *L = B->L;\n  lua_pushlstring(L, B->b, B->n);\n  if (buffonstack(B)) {\n    resizebox(L, -2, 0);  /* delete old buffer */\n    lua_remove(L, -2);  /* remove its header from the stack */\n  }\n}\n\n\nLUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {\n  luaL_addsize(B, sz);\n  luaL_pushresult(B);\n}\n\n\nLUALIB_API void luaL_addvalue (luaL_Buffer *B) {\n  lua_State *L = B->L;\n  size_t l;\n  const char *s = lua_tolstring(L, -1, &l);\n  if (buffonstack(B))\n    lua_insert(L, -2);  /* put value below buffer */\n  luaL_addlstring(B, s, l);\n  lua_remove(L, (buffonstack(B)) ? -2 : -1);  /* remove value */\n}\n\n\nLUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {\n  B->L = L;\n  B->b = B->initb;\n  B->n = 0;\n  B->size = LUAL_BUFFERSIZE;\n}\n\n\nLUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {\n  luaL_buffinit(L, B);\n  return luaL_prepbuffsize(B, sz);\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Reference system\n** =======================================================\n*/\n\n/* index of free-list header */\n#define freelist\t0\n\n\nLUALIB_API int luaL_ref (lua_State *L, int t) {\n  int ref;\n  if (lua_isnil(L, -1)) {\n    lua_pop(L, 1);  /* remove from stack */\n    return LUA_REFNIL;  /* 'nil' has a unique fixed reference */\n  }\n  t = lua_absindex(L, t);\n  lua_rawgeti(L, t, freelist);  /* get first free element */\n  ref = (int)lua_tointeger(L, -1);  /* ref = t[freelist] */\n  lua_pop(L, 1);  /* remove it from stack */\n  if (ref != 0) {  /* any free element? */\n    lua_rawgeti(L, t, ref);  /* remove it from list */\n    lua_rawseti(L, t, freelist);  /* (t[freelist] = t[ref]) */\n  }\n  else  /* no free elements */\n    ref = (int)lua_rawlen(L, t) + 1;  /* get a new reference */\n  lua_rawseti(L, t, ref);\n  return ref;\n}\n\n\nLUALIB_API void luaL_unref (lua_State *L, int t, int ref) {\n  if (ref >= 0) {\n    t = lua_absindex(L, t);\n    lua_rawgeti(L, t, freelist);\n    lua_rawseti(L, t, ref);  /* t[ref] = t[freelist] */\n    lua_pushinteger(L, ref);\n    lua_rawseti(L, t, freelist);  /* t[freelist] = ref */\n  }\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Load functions\n** =======================================================\n*/\n\ntypedef struct LoadF {\n  int n;  /* number of pre-read characters */\n  FILE *f;  /* file being read */\n  char buff[BUFSIZ];  /* area for reading file */\n} LoadF;\n\n\nstatic const char *getF (lua_State *L, void *ud, size_t *size) {\n  LoadF *lf = (LoadF *)ud;\n  (void)L;  /* not used */\n  if (lf->n > 0) {  /* are there pre-read characters to be read? */\n    *size = lf->n;  /* return them (chars already in buffer) */\n    lf->n = 0;  /* no more pre-read characters */\n  }\n  else {  /* read a block from file */\n    /* 'fread' can return > 0 *and* set the EOF flag. If next call to\n       'getF' called 'fread', it might still wait for user input.\n       The next check avoids this problem. */\n    if (feof(lf->f)) return NULL;\n    *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  /* read block */\n  }\n  return lf->buff;\n}\n\n\nstatic int errfile (lua_State *L, const char *what, int fnameindex) {\n  const char *serr = strerror(errno);\n  const char *filename = lua_tostring(L, fnameindex) + 1;\n  lua_pushfstring(L, \"cannot %s %s: %s\", what, filename, serr);\n  lua_remove(L, fnameindex);\n  return LUA_ERRFILE;\n}\n\n\nstatic int skipBOM (LoadF *lf) {\n  const char *p = \"\\xEF\\xBB\\xBF\";  /* UTF-8 BOM mark */\n  int c;\n  lf->n = 0;\n  do {\n    c = getc(lf->f);\n    if (c == EOF || c != *(const unsigned char *)p++) return c;\n    lf->buff[lf->n++] = c;  /* to be read by the parser */\n  } while (*p != '\\0');\n  lf->n = 0;  /* prefix matched; discard it */\n  return getc(lf->f);  /* return next character */\n}\n\n\n/*\n** reads the first character of file 'f' and skips an optional BOM mark\n** in its beginning plus its first line if it starts with '#'. Returns\n** true if it skipped the first line.  In any case, '*cp' has the\n** first \"valid\" character of the file (after the optional BOM and\n** a first-line comment).\n*/\nstatic int skipcomment (LoadF *lf, int *cp) {\n  int c = *cp = skipBOM(lf);\n  if (c == '#') {  /* first line is a comment (Unix exec. file)? */\n    do {  /* skip first line */\n      c = getc(lf->f);\n    } while (c != EOF && c != '\\n');\n    *cp = getc(lf->f);  /* skip end-of-line, if present */\n    return 1;  /* there was a comment */\n  }\n  else return 0;  /* no comment */\n}\n\n\nLUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,\n                                             const char *mode) {\n  LoadF lf;\n  int status, readstatus;\n  int c;\n  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */\n  if (filename == NULL) {\n    lua_pushliteral(L, \"=stdin\");\n    lf.f = stdin;\n  }\n  else {\n    lua_pushfstring(L, \"@%s\", filename);\n    lf.f = fopen(filename, \"r\");\n    if (lf.f == NULL) return errfile(L, \"open\", fnameindex);\n  }\n  if (skipcomment(&lf, &c))  /* read initial portion */\n    lf.buff[lf.n++] = '\\n';  /* add line to correct line numbers */\n  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */\n    lf.f = freopen(filename, \"rb\", lf.f);  /* reopen in binary mode */\n    if (lf.f == NULL) return errfile(L, \"reopen\", fnameindex);\n    skipcomment(&lf, &c);  /* re-read initial portion */\n  }\n  if (c != EOF)\n    lf.buff[lf.n++] = c;  /* 'c' is the first character of the stream */\n  status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);\n  readstatus = ferror(lf.f);\n  if (filename) fclose(lf.f);  /* close file (even in case of errors) */\n  if (readstatus) {\n    lua_settop(L, fnameindex);  /* ignore results from 'lua_load' */\n    return errfile(L, \"read\", fnameindex);\n  }\n  lua_remove(L, fnameindex);\n  return status;\n}\n\n\ntypedef struct LoadS {\n  const char *s;\n  size_t size;\n} LoadS;\n\n\nstatic const char *getS (lua_State *L, void *ud, size_t *size) {\n  LoadS *ls = (LoadS *)ud;\n  (void)L;  /* not used */\n  if (ls->size == 0) return NULL;\n  *size = ls->size;\n  ls->size = 0;\n  return ls->s;\n}\n\n\nLUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,\n                                 const char *name, const char *mode) {\n  LoadS ls;\n  ls.s = buff;\n  ls.size = size;\n  return lua_load(L, getS, &ls, name, mode);\n}\n\n\nLUALIB_API int luaL_loadstring (lua_State *L, const char *s) {\n  return luaL_loadbuffer(L, s, strlen(s), s);\n}\n\n/* }====================================================== */\n\n\n\nLUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {\n  if (!lua_getmetatable(L, obj))  /* no metatable? */\n    return LUA_TNIL;\n  else {\n    int tt;\n    lua_pushstring(L, event);\n    tt = lua_rawget(L, -2);\n    if (tt == LUA_TNIL)  /* is metafield nil? */\n      lua_pop(L, 2);  /* remove metatable and metafield */\n    else\n      lua_remove(L, -2);  /* remove only metatable */\n    return tt;  /* return metafield type */\n  }\n}\n\n\nLUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {\n  obj = lua_absindex(L, obj);\n  if (luaL_getmetafield(L, obj, event) == LUA_TNIL)  /* no metafield? */\n    return 0;\n  lua_pushvalue(L, obj);\n  lua_call(L, 1, 1);\n  return 1;\n}\n\n\nLUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {\n  lua_Integer l;\n  int isnum;\n  lua_len(L, idx);\n  l = lua_tointegerx(L, -1, &isnum);\n  if (!isnum)\n    luaL_error(L, \"object length is not an integer\");\n  lua_pop(L, 1);  /* remove object */\n  return l;\n}\n\n\nLUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {\n  if (luaL_callmeta(L, idx, \"__tostring\")) {  /* metafield? */\n    if (!lua_isstring(L, -1))\n      luaL_error(L, \"'__tostring' must return a string\");\n  }\n  else {\n    switch (lua_type(L, idx)) {\n      case LUA_TNUMBER: {\n        if (lua_isinteger(L, idx))\n          lua_pushfstring(L, \"%I\", (LUAI_UACINT)lua_tointeger(L, idx));\n        else\n          lua_pushfstring(L, \"%f\", (LUAI_UACNUMBER)lua_tonumber(L, idx));\n        break;\n      }\n      case LUA_TSTRING:\n        lua_pushvalue(L, idx);\n        break;\n      case LUA_TBOOLEAN:\n        lua_pushstring(L, (lua_toboolean(L, idx) ? \"true\" : \"false\"));\n        break;\n      case LUA_TNIL:\n        lua_pushliteral(L, \"nil\");\n        break;\n      default: {\n        int tt = luaL_getmetafield(L, idx, \"__name\");  /* try name */\n        const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :\n                                                 luaL_typename(L, idx);\n        lua_pushfstring(L, \"%s: %p\", kind, lua_topointer(L, idx));\n        if (tt != LUA_TNIL)\n          lua_remove(L, -2);  /* remove '__name' */\n        break;\n      }\n    }\n  }\n  return lua_tolstring(L, -1, len);\n}\n\n\n/*\n** {======================================================\n** Compatibility with 5.1 module functions\n** =======================================================\n*/\n#if defined(LUA_COMPAT_MODULE)\n\nstatic const char *luaL_findtable (lua_State *L, int idx,\n                                   const char *fname, int szhint) {\n  const char *e;\n  if (idx) lua_pushvalue(L, idx);\n  do {\n    e = strchr(fname, '.');\n    if (e == NULL) e = fname + strlen(fname);\n    lua_pushlstring(L, fname, e - fname);\n    if (lua_rawget(L, -2) == LUA_TNIL) {  /* no such field? */\n      lua_pop(L, 1);  /* remove this nil */\n      lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */\n      lua_pushlstring(L, fname, e - fname);\n      lua_pushvalue(L, -2);\n      lua_settable(L, -4);  /* set new table into field */\n    }\n    else if (!lua_istable(L, -1)) {  /* field has a non-table value? */\n      lua_pop(L, 2);  /* remove table and value */\n      return fname;  /* return problematic part of the name */\n    }\n    lua_remove(L, -2);  /* remove previous table */\n    fname = e + 1;\n  } while (*e == '.');\n  return NULL;\n}\n\n\n/*\n** Count number of elements in a luaL_Reg list.\n*/\nstatic int libsize (const luaL_Reg *l) {\n  int size = 0;\n  for (; l && l->name; l++) size++;\n  return size;\n}\n\n\n/*\n** Find or create a module table with a given name. The function\n** first looks at the LOADED table and, if that fails, try a\n** global variable with that name. In any case, leaves on the stack\n** the module table.\n*/\nLUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,\n                                 int sizehint) {\n  luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);\n  if (lua_getfield(L, -1, modname) != LUA_TTABLE) {  /* no LOADED[modname]? */\n    lua_pop(L, 1);  /* remove previous result */\n    /* try global variable (and create one if it does not exist) */\n    lua_pushglobaltable(L);\n    if (luaL_findtable(L, 0, modname, sizehint) != NULL)\n      luaL_error(L, \"name conflict for module '%s'\", modname);\n    lua_pushvalue(L, -1);\n    lua_setfield(L, -3, modname);  /* LOADED[modname] = new table */\n  }\n  lua_remove(L, -2);  /* remove LOADED table */\n}\n\n\nLUALIB_API void luaL_openlib (lua_State *L, const char *libname,\n                               const luaL_Reg *l, int nup) {\n  luaL_checkversion(L);\n  if (libname) {\n    luaL_pushmodule(L, libname, libsize(l));  /* get/create library table */\n    lua_insert(L, -(nup + 1));  /* move library table to below upvalues */\n  }\n  if (l)\n    luaL_setfuncs(L, l, nup);\n  else\n    lua_pop(L, nup);  /* remove upvalues */\n}\n\n#endif\n/* }====================================================== */\n\n/*\n** set functions from list 'l' into table at top - 'nup'; each\n** function gets the 'nup' elements at the top as upvalues.\n** Returns with only the table at the stack.\n*/\nLUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {\n  luaL_checkstack(L, nup, \"too many upvalues\");\n  for (; l->name != NULL; l++) {  /* fill the table with given functions */\n    int i;\n    for (i = 0; i < nup; i++)  /* copy upvalues to the top */\n      lua_pushvalue(L, -nup);\n    lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */\n    lua_setfield(L, -(nup + 2), l->name);\n  }\n  lua_pop(L, nup);  /* remove upvalues */\n}\n\n\n/*\n** ensure that stack[idx][fname] has a table and push that table\n** into the stack\n*/\nLUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {\n  if (lua_getfield(L, idx, fname) == LUA_TTABLE)\n    return 1;  /* table already there */\n  else {\n    lua_pop(L, 1);  /* remove previous result */\n    idx = lua_absindex(L, idx);\n    lua_newtable(L);\n    lua_pushvalue(L, -1);  /* copy to be left at top */\n    lua_setfield(L, idx, fname);  /* assign new table to field */\n    return 0;  /* false, because did not find table there */\n  }\n}\n\n\n/*\n** Stripped-down 'require': After checking \"loaded\" table, calls 'openf'\n** to open a module, registers the result in 'package.loaded' table and,\n** if 'glb' is true, also registers the result in the global table.\n** Leaves resulting module on the top.\n*/\nLUALIB_API void luaL_requiref (lua_State *L, const char *modname,\n                               lua_CFunction openf, int glb) {\n  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n  lua_getfield(L, -1, modname);  /* LOADED[modname] */\n  if (!lua_toboolean(L, -1)) {  /* package not already loaded? */\n    lua_pop(L, 1);  /* remove field */\n    lua_pushcfunction(L, openf);\n    lua_pushstring(L, modname);  /* argument to open function */\n    lua_call(L, 1, 1);  /* call 'openf' to open module */\n    lua_pushvalue(L, -1);  /* make copy of module (call result) */\n    lua_setfield(L, -3, modname);  /* LOADED[modname] = module */\n  }\n  lua_remove(L, -2);  /* remove LOADED table */\n  if (glb) {\n    lua_pushvalue(L, -1);  /* copy of module */\n    lua_setglobal(L, modname);  /* _G[modname] = module */\n  }\n}\n\n\nLUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,\n                                                               const char *r) {\n  const char *wild;\n  size_t l = strlen(p);\n  luaL_Buffer b;\n  luaL_buffinit(L, &b);\n  while ((wild = strstr(s, p)) != NULL) {\n    luaL_addlstring(&b, s, wild - s);  /* push prefix */\n    luaL_addstring(&b, r);  /* push replacement in place of pattern */\n    s = wild + l;  /* continue after 'p' */\n  }\n  luaL_addstring(&b, s);  /* push last suffix */\n  luaL_pushresult(&b);\n  return lua_tostring(L, -1);\n}\n\n\nstatic void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {\n  (void)ud; (void)osize;  /* not used */\n  if (nsize == 0) {\n    free(ptr);\n    return NULL;\n  }\n  else\n    return realloc(ptr, nsize);\n}\n\n\nstatic int panic (lua_State *L) {\n  //lua_writestringerror(\"PANIC: unprotected error in call to Lua API (%s)\\n\", lua_tostring(L, -1));\n  lua_writestringerror(\"PANIC: unprotected error in call to Lua API\\n\");\n  return 0;  /* return to Lua to abort */\n}\n\n\nLUALIB_API lua_State *luaL_newstate (void) {\n  lua_State *L = lua_newstate(l_alloc, NULL);\n  if (L) lua_atpanic(L, &panic);\n  return L;\n}\n\n\nLUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {\n  const lua_Number *v = lua_version(L);\n  if (sz != LUAL_NUMSIZES)  /* check numeric types */\n    luaL_error(L, \"core and library have incompatible numeric types\");\n  if (v != lua_version(NULL))\n    luaL_error(L, \"multiple Lua VMs detected\");\n  else if (*v != ver)\n    luaL_error(L, \"version mismatch: app. needs %f, Lua core provides %f\",\n                  (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lauxlib.h",
    "content": "/*\n** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $\n** Auxiliary functions for building Lua libraries\n** See Copyright Notice in lua.h\n*/\n\n\n#ifndef lauxlib_h\n#define lauxlib_h\n\n\n#include <stddef.h>\n#include <stdio.h>\n\n#include \"lua.h\"\n\n\n\n/* extra error code for 'luaL_loadfilex' */\n#define LUA_ERRFILE     (LUA_ERRERR+1)\n\n\n/* key, in the registry, for table of loaded modules */\n#define LUA_LOADED_TABLE\t\"_LOADED\"\n\n\n/* key, in the registry, for table of preloaded loaders */\n#define LUA_PRELOAD_TABLE\t\"_PRELOAD\"\n\n\ntypedef struct luaL_Reg {\n  const char *name;\n  lua_CFunction func;\n} luaL_Reg;\n\n\n#define LUAL_NUMSIZES\t(sizeof(lua_Integer)*16 + sizeof(lua_Number))\n\nLUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);\n#define luaL_checkversion(L)  \\\n\t  luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)\n\nLUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);\nLUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);\nLUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);\nLUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);\nLUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,\n                                                          size_t *l);\nLUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,\n                                          const char *def, size_t *l);\nLUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);\nLUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);\n\nLUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);\nLUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,\n                                          lua_Integer def);\n\nLUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);\nLUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);\nLUALIB_API void (luaL_checkany) (lua_State *L, int arg);\n\nLUALIB_API int   (luaL_newmetatable) (lua_State *L, const char *tname);\nLUALIB_API void  (luaL_setmetatable) (lua_State *L, const char *tname);\nLUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);\nLUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);\n\nLUALIB_API void (luaL_where) (lua_State *L, int lvl);\nLUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);\n\nLUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,\n                                   const char *const lst[]);\n\nLUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);\nLUALIB_API int (luaL_execresult) (lua_State *L, int stat);\n\n/* predefined references */\n#define LUA_NOREF       (-2)\n#define LUA_REFNIL      (-1)\n\nLUALIB_API int (luaL_ref) (lua_State *L, int t);\nLUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);\n\nLUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,\n                                               const char *mode);\n\n#define luaL_loadfile(L,f)\tluaL_loadfilex(L,f,NULL)\n\nLUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,\n                                   const char *name, const char *mode);\nLUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);\n\nLUALIB_API lua_State *(luaL_newstate) (void);\n\nLUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);\n\nLUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,\n                                                  const char *r);\n\nLUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);\n\nLUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);\n\nLUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,\n                                  const char *msg, int level);\n\nLUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,\n                                 lua_CFunction openf, int glb);\n\n/*\n** ===============================================================\n** some useful macros\n** ===============================================================\n*/\n\n\n#define luaL_newlibtable(L,l)\t\\\n  lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)\n\n#define luaL_newlib(L,l)  \\\n  (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))\n\n#define luaL_argcheck(L, cond,arg,extramsg)\t\\\n\t\t((void)((cond) || luaL_argerror(L, (arg), (extramsg))))\n#define luaL_checkstring(L,n)\t(luaL_checklstring(L, (n), NULL))\n#define luaL_optstring(L,n,d)\t(luaL_optlstring(L, (n), (d), NULL))\n\n#define luaL_typename(L,i)\tlua_typename(L, lua_type(L,(i)))\n\n#define luaL_dofile(L, fn) \\\n\t(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))\n\n#define luaL_dostring(L, s) \\\n\t(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))\n\n#define luaL_getmetatable(L,n)\t(lua_getfield(L, LUA_REGISTRYINDEX, (n)))\n\n#define luaL_opt(L,f,n,d)\t(lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))\n\n#define luaL_loadbuffer(L,s,sz,n)\tluaL_loadbufferx(L,s,sz,n,NULL)\n\n\n/*\n** {======================================================\n** Generic Buffer manipulation\n** =======================================================\n*/\n\ntypedef struct luaL_Buffer {\n  char *b;  /* buffer address */\n  size_t size;  /* buffer size */\n  size_t n;  /* number of characters in buffer */\n  lua_State *L;\n  char initb[LUAL_BUFFERSIZE];  /* initial buffer */\n} luaL_Buffer;\n\n\n#define luaL_addchar(B,c) \\\n  ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \\\n   ((B)->b[(B)->n++] = (c)))\n\n#define luaL_addsize(B,s)\t((B)->n += (s))\n\nLUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);\nLUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);\nLUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);\nLUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);\nLUALIB_API void (luaL_addvalue) (luaL_Buffer *B);\nLUALIB_API void (luaL_pushresult) (luaL_Buffer *B);\nLUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);\nLUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);\n\n#define luaL_prepbuffer(B)\tluaL_prepbuffsize(B, LUAL_BUFFERSIZE)\n\n/* }====================================================== */\n\n\n\n/*\n** {======================================================\n** File handles for IO library\n** =======================================================\n*/\n\n/*\n** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and\n** initial structure 'luaL_Stream' (it may contain other fields\n** after that initial structure).\n*/\n\n#define LUA_FILEHANDLE          \"FILE*\"\n\n\ntypedef struct luaL_Stream {\n  FILE *f;  /* stream (NULL for incompletely created streams) */\n  lua_CFunction closef;  /* to close stream (NULL for closed streams) */\n} luaL_Stream;\n\n/* }====================================================== */\n\n\n\n/* compatibility with old module system */\n#if defined(LUA_COMPAT_MODULE)\n\nLUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,\n                                   int sizehint);\nLUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,\n                                const luaL_Reg *l, int nup);\n\n#define luaL_register(L,n,l)\t(luaL_openlib(L,(n),(l),0))\n\n#endif\n\n\n/*\n** {==================================================================\n** \"Abstraction Layer\" for basic report of messages and errors\n** ===================================================================\n*/\n\n/* print a string */\n#if !defined(lua_writestring)\n//#define lua_writestring(s,l)   fwrite((s), sizeof(char), (l), stdout)\n#define lua_writestring(s,l)   LogCat(true, s);\n#endif\n\n/* print a newline and flush the output */\n#if !defined(lua_writeline)\n#define lua_writeline()        LogCat(true, \"\\n\"); // (lua_writestring(\"\\n\", 1), fflush(stdout))\n#endif\n\n/* print an error message */\n#if !defined(lua_writestringerror)\n//#define lua_writestringerror(s,p) (fprintf(stderr, (s), (p)), fflush(stderr))\n#define lua_writestringerror(s) LogCat(true, s);\n#endif\n\n/* }================================================================== */\n\n\n/*\n** {============================================================\n** Compatibility with deprecated conversions\n** =============================================================\n*/\n#if defined(LUA_COMPAT_APIINTCASTS)\n\n#define luaL_checkunsigned(L,a)\t((lua_Unsigned)luaL_checkinteger(L,a))\n#define luaL_optunsigned(L,a,d)\t\\\n\t((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))\n\n#define luaL_checkint(L,n)\t((int)luaL_checkinteger(L, (n)))\n#define luaL_optint(L,n,d)\t((int)luaL_optinteger(L, (n), (d)))\n\n#define luaL_checklong(L,n)\t((long)luaL_checkinteger(L, (n)))\n#define luaL_optlong(L,n,d)\t((long)luaL_optinteger(L, (n), (d)))\n\n#endif\n/* }============================================================ */\n\n\n\n#endif\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lbaselib.c",
    "content": "/*\n** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $\n** Basic library\n** See Copyright Notice in lua.h\n*/\n\n#define lbaselib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <ctype.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\nstatic int luaB_print (lua_State *L) {\n  int n = lua_gettop(L);  /* number of arguments */\n  int i;\n  lua_getglobal(L, \"tostring\");\n  for (i=1; i<=n; i++) {\n    const char *s;\n    size_t l;\n    lua_pushvalue(L, -1);  /* function to be called */\n    lua_pushvalue(L, i);   /* value to print */\n    lua_call(L, 1, 1);\n    s = lua_tolstring(L, -1, &l);  /* get result */\n    if (s == NULL)\n      return luaL_error(L, \"'tostring' must return a string to 'print'\");\n    if (i>1) lua_writestring(\"\\t\", 1);\n    lua_writestring(s, l);\n    lua_pop(L, 1);  /* pop result */\n  }\n  lua_writeline();\n  return 0;\n}\n\n\n#define SPACECHARS\t\" \\f\\n\\r\\t\\v\"\n\nstatic const char *b_str2int (const char *s, int base, lua_Integer *pn) {\n  lua_Unsigned n = 0;\n  int neg = 0;\n  s += strspn(s, SPACECHARS);  /* skip initial spaces */\n  if (*s == '-') { s++; neg = 1; }  /* handle signal */\n  else if (*s == '+') s++;\n  if (!isalnum((unsigned char)*s))  /* no digit? */\n    return NULL;\n  do {\n    int digit = (isdigit((unsigned char)*s)) ? *s - '0'\n                   : (toupper((unsigned char)*s) - 'A') + 10;\n    if (digit >= base) return NULL;  /* invalid numeral */\n    n = n * base + digit;\n    s++;\n  } while (isalnum((unsigned char)*s));\n  s += strspn(s, SPACECHARS);  /* skip trailing spaces */\n  *pn = (lua_Integer)((neg) ? (0u - n) : n);\n  return s;\n}\n\n\nstatic int luaB_tonumber (lua_State *L) {\n  if (lua_isnoneornil(L, 2)) {  /* standard conversion? */\n    luaL_checkany(L, 1);\n    if (lua_type(L, 1) == LUA_TNUMBER) {  /* already a number? */\n      lua_settop(L, 1);  /* yes; return it */\n      return 1;\n    }\n    else {\n      size_t l;\n      const char *s = lua_tolstring(L, 1, &l);\n      if (s != NULL && lua_stringtonumber(L, s) == l + 1)\n        return 1;  /* successful conversion to number */\n      /* else not a number */\n    }\n  }\n  else {\n    size_t l;\n    const char *s;\n    lua_Integer n = 0;  /* to avoid warnings */\n    lua_Integer base = luaL_checkinteger(L, 2);\n    luaL_checktype(L, 1, LUA_TSTRING);  /* no numbers as strings */\n    s = lua_tolstring(L, 1, &l);\n    luaL_argcheck(L, 2 <= base && base <= 36, 2, \"base out of range\");\n    if (b_str2int(s, (int)base, &n) == s + l) {\n      lua_pushinteger(L, n);\n      return 1;\n    }  /* else not a number */\n  }  /* else not a number */\n  lua_pushnil(L);  /* not a number */\n  return 1;\n}\n\n\nstatic int luaB_error (lua_State *L) {\n  int level = (int)luaL_optinteger(L, 2, 1);\n  lua_settop(L, 1);\n  if (lua_type(L, 1) == LUA_TSTRING && level > 0) {\n    luaL_where(L, level);   /* add extra information */\n    lua_pushvalue(L, 1);\n    lua_concat(L, 2);\n  }\n  return lua_error(L);\n}\n\n\nstatic int luaB_getmetatable (lua_State *L) {\n  luaL_checkany(L, 1);\n  if (!lua_getmetatable(L, 1)) {\n    lua_pushnil(L);\n    return 1;  /* no metatable */\n  }\n  luaL_getmetafield(L, 1, \"__metatable\");\n  return 1;  /* returns either __metatable field (if present) or metatable */\n}\n\n\nstatic int luaB_setmetatable (lua_State *L) {\n  int t = lua_type(L, 2);\n  luaL_checktype(L, 1, LUA_TTABLE);\n  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,\n                    \"nil or table expected\");\n  if (luaL_getmetafield(L, 1, \"__metatable\") != LUA_TNIL)\n    return luaL_error(L, \"cannot change a protected metatable\");\n  lua_settop(L, 2);\n  lua_setmetatable(L, 1);\n  return 1;\n}\n\n\nstatic int luaB_rawequal (lua_State *L) {\n  luaL_checkany(L, 1);\n  luaL_checkany(L, 2);\n  lua_pushboolean(L, lua_rawequal(L, 1, 2));\n  return 1;\n}\n\n\nstatic int luaB_rawlen (lua_State *L) {\n  int t = lua_type(L, 1);\n  luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,\n                   \"table or string expected\");\n  lua_pushinteger(L, lua_rawlen(L, 1));\n  return 1;\n}\n\n\nstatic int luaB_rawget (lua_State *L) {\n  luaL_checktype(L, 1, LUA_TTABLE);\n  luaL_checkany(L, 2);\n  lua_settop(L, 2);\n  lua_rawget(L, 1);\n  return 1;\n}\n\nstatic int luaB_rawset (lua_State *L) {\n  luaL_checktype(L, 1, LUA_TTABLE);\n  luaL_checkany(L, 2);\n  luaL_checkany(L, 3);\n  lua_settop(L, 3);\n  lua_rawset(L, 1);\n  return 1;\n}\n\n\nstatic int luaB_collectgarbage (lua_State *L) {\n  static const char *const opts[] = {\"stop\", \"restart\", \"collect\",\n    \"count\", \"step\", \"setpause\", \"setstepmul\",\n    \"isrunning\", NULL};\n  static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,\n    LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,\n    LUA_GCISRUNNING};\n  int o = optsnum[luaL_checkoption(L, 1, \"collect\", opts)];\n  int ex = (int)luaL_optinteger(L, 2, 0);\n  int res = lua_gc(L, o, ex);\n  switch (o) {\n    case LUA_GCCOUNT: {\n      int b = lua_gc(L, LUA_GCCOUNTB, 0);\n      lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024));\n      return 1;\n    }\n    case LUA_GCSTEP: case LUA_GCISRUNNING: {\n      lua_pushboolean(L, res);\n      return 1;\n    }\n    default: {\n      lua_pushinteger(L, res);\n      return 1;\n    }\n  }\n}\n\n\nstatic int luaB_type (lua_State *L) {\n  int t = lua_type(L, 1);\n  luaL_argcheck(L, t != LUA_TNONE, 1, \"value expected\");\n  lua_pushstring(L, lua_typename(L, t));\n  return 1;\n}\n\n\nstatic int pairsmeta (lua_State *L, const char *method, int iszero,\n                      lua_CFunction iter) {\n  luaL_checkany(L, 1);\n  if (luaL_getmetafield(L, 1, method) == LUA_TNIL) {  /* no metamethod? */\n    lua_pushcfunction(L, iter);  /* will return generator, */\n    lua_pushvalue(L, 1);  /* state, */\n    if (iszero) lua_pushinteger(L, 0);  /* and initial value */\n    else lua_pushnil(L);\n  }\n  else {\n    lua_pushvalue(L, 1);  /* argument 'self' to metamethod */\n    lua_call(L, 1, 3);  /* get 3 values from metamethod */\n  }\n  return 3;\n}\n\n\nstatic int luaB_next (lua_State *L) {\n  luaL_checktype(L, 1, LUA_TTABLE);\n  lua_settop(L, 2);  /* create a 2nd argument if there isn't one */\n  if (lua_next(L, 1))\n    return 2;\n  else {\n    lua_pushnil(L);\n    return 1;\n  }\n}\n\n\nstatic int luaB_pairs (lua_State *L) {\n  return pairsmeta(L, \"__pairs\", 0, luaB_next);\n}\n\n\n/*\n** Traversal function for 'ipairs'\n*/\nstatic int ipairsaux (lua_State *L) {\n  lua_Integer i = luaL_checkinteger(L, 2) + 1;\n  lua_pushinteger(L, i);\n  return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;\n}\n\n\n/*\n** 'ipairs' function. Returns 'ipairsaux', given \"table\", 0.\n** (The given \"table\" may not be a table.)\n*/\nstatic int luaB_ipairs (lua_State *L) {\n#if defined(LUA_COMPAT_IPAIRS)\n  return pairsmeta(L, \"__ipairs\", 1, ipairsaux);\n#else\n  luaL_checkany(L, 1);\n  lua_pushcfunction(L, ipairsaux);  /* iteration function */\n  lua_pushvalue(L, 1);  /* state */\n  lua_pushinteger(L, 0);  /* initial value */\n  return 3;\n#endif\n}\n\n\nstatic int load_aux (lua_State *L, int status, int envidx) {\n  if (status == LUA_OK) {\n    if (envidx != 0) {  /* 'env' parameter? */\n      lua_pushvalue(L, envidx);  /* environment for loaded function */\n      if (!lua_setupvalue(L, -2, 1))  /* set it as 1st upvalue */\n        lua_pop(L, 1);  /* remove 'env' if not used by previous call */\n    }\n    return 1;\n  }\n  else {  /* error (message is on top of the stack) */\n    lua_pushnil(L);\n    lua_insert(L, -2);  /* put before error message */\n    return 2;  /* return nil plus error message */\n  }\n}\n\n\nstatic int luaB_loadfile (lua_State *L) {\n  const char *fname = luaL_optstring(L, 1, NULL);\n  const char *mode = luaL_optstring(L, 2, NULL);\n  int env = (!lua_isnone(L, 3) ? 3 : 0);  /* 'env' index or 0 if no 'env' */\n  int status = luaL_loadfilex(L, fname, mode);\n  return load_aux(L, status, env);\n}\n\n\n/*\n** {======================================================\n** Generic Read function\n** =======================================================\n*/\n\n\n/*\n** reserved slot, above all arguments, to hold a copy of the returned\n** string to avoid it being collected while parsed. 'load' has four\n** optional arguments (chunk, source name, mode, and environment).\n*/\n#define RESERVEDSLOT\t5\n\n\n/*\n** Reader for generic 'load' function: 'lua_load' uses the\n** stack for internal stuff, so the reader cannot change the\n** stack top. Instead, it keeps its resulting string in a\n** reserved slot inside the stack.\n*/\nstatic const char *generic_reader (lua_State *L, void *ud, size_t *size) {\n  (void)(ud);  /* not used */\n  luaL_checkstack(L, 2, \"too many nested functions\");\n  lua_pushvalue(L, 1);  /* get function */\n  lua_call(L, 0, 1);  /* call it */\n  if (lua_isnil(L, -1)) {\n    lua_pop(L, 1);  /* pop result */\n    *size = 0;\n    return NULL;\n  }\n  else if (!lua_isstring(L, -1))\n    luaL_error(L, \"reader function must return a string\");\n  lua_replace(L, RESERVEDSLOT);  /* save string in reserved slot */\n  return lua_tolstring(L, RESERVEDSLOT, size);\n}\n\n\nstatic int luaB_load (lua_State *L) {\n  int status;\n  size_t l;\n  const char *s = lua_tolstring(L, 1, &l);\n  const char *mode = luaL_optstring(L, 3, \"bt\");\n  int env = (!lua_isnone(L, 4) ? 4 : 0);  /* 'env' index or 0 if no 'env' */\n  if (s != NULL) {  /* loading a string? */\n    const char *chunkname = luaL_optstring(L, 2, s);\n    status = luaL_loadbufferx(L, s, l, chunkname, mode);\n  }\n  else {  /* loading from a reader function */\n    const char *chunkname = luaL_optstring(L, 2, \"=(load)\");\n    luaL_checktype(L, 1, LUA_TFUNCTION);\n    lua_settop(L, RESERVEDSLOT);  /* create reserved slot */\n    status = lua_load(L, generic_reader, NULL, chunkname, mode);\n  }\n  return load_aux(L, status, env);\n}\n\n/* }====================================================== */\n\n\nstatic int dofilecont (lua_State *L, int d1, lua_KContext d2) {\n  (void)d1;  (void)d2;  /* only to match 'lua_Kfunction' prototype */\n  return lua_gettop(L) - 1;\n}\n\n\nstatic int luaB_dofile (lua_State *L) {\n  const char *fname = luaL_optstring(L, 1, NULL);\n  lua_settop(L, 1);\n  if (luaL_loadfile(L, fname) != LUA_OK)\n    return lua_error(L);\n  lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);\n  return dofilecont(L, 0, 0);\n}\n\n\nstatic int luaB_assert (lua_State *L) {\n  if (lua_toboolean(L, 1))  /* condition is true? */\n    return lua_gettop(L);  /* return all arguments */\n  else {  /* error */\n    luaL_checkany(L, 1);  /* there must be a condition */\n    lua_remove(L, 1);  /* remove it */\n    lua_pushliteral(L, \"assertion failed!\");  /* default message */\n    lua_settop(L, 1);  /* leave only message (default if no other one) */\n    return luaB_error(L);  /* call 'error' */\n  }\n}\n\n\nstatic int luaB_select (lua_State *L) {\n  int n = lua_gettop(L);\n  if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {\n    lua_pushinteger(L, n-1);\n    return 1;\n  }\n  else {\n    lua_Integer i = luaL_checkinteger(L, 1);\n    if (i < 0) i = n + i;\n    else if (i > n) i = n;\n    luaL_argcheck(L, 1 <= i, 1, \"index out of range\");\n    return n - (int)i;\n  }\n}\n\n\n/*\n** Continuation function for 'pcall' and 'xpcall'. Both functions\n** already pushed a 'true' before doing the call, so in case of success\n** 'finishpcall' only has to return everything in the stack minus\n** 'extra' values (where 'extra' is exactly the number of items to be\n** ignored).\n*/\nstatic int finishpcall (lua_State *L, int status, lua_KContext extra) {\n  if (status != LUA_OK && status != LUA_YIELD) {  /* error? */\n    lua_pushboolean(L, 0);  /* first result (false) */\n    lua_pushvalue(L, -2);  /* error message */\n    return 2;  /* return false, msg */\n  }\n  else\n    return lua_gettop(L) - (int)extra;  /* return all results */\n}\n\n\nstatic int luaB_pcall (lua_State *L) {\n  int status;\n  luaL_checkany(L, 1);\n  lua_pushboolean(L, 1);  /* first result if no errors */\n  lua_insert(L, 1);  /* put it in place */\n  status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);\n  return finishpcall(L, status, 0);\n}\n\n\n/*\n** Do a protected call with error handling. After 'lua_rotate', the\n** stack will have <f, err, true, f, [args...]>; so, the function passes\n** 2 to 'finishpcall' to skip the 2 first values when returning results.\n*/\nstatic int luaB_xpcall (lua_State *L) {\n  int status;\n  int n = lua_gettop(L);\n  luaL_checktype(L, 2, LUA_TFUNCTION);  /* check error function */\n  lua_pushboolean(L, 1);  /* first result */\n  lua_pushvalue(L, 1);  /* function */\n  lua_rotate(L, 3, 2);  /* move them below function's arguments */\n  status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);\n  return finishpcall(L, status, 2);\n}\n\n\nstatic int luaB_tostring (lua_State *L) {\n  luaL_checkany(L, 1);\n  luaL_tolstring(L, 1, NULL);\n  return 1;\n}\n\n\nstatic const luaL_Reg base_funcs[] = {\n  {\"assert\", luaB_assert},\n  {\"collectgarbage\", luaB_collectgarbage},\n  {\"dofile\", luaB_dofile},\n  {\"error\", luaB_error},\n  {\"getmetatable\", luaB_getmetatable},\n  {\"ipairs\", luaB_ipairs},\n  {\"loadfile\", luaB_loadfile},\n  {\"load\", luaB_load},\n#if defined(LUA_COMPAT_LOADSTRING)\n  {\"loadstring\", luaB_load},\n#endif\n  {\"next\", luaB_next},\n  {\"pairs\", luaB_pairs},\n  {\"pcall\", luaB_pcall},\n  {\"print\", luaB_print},\n  {\"rawequal\", luaB_rawequal},\n  {\"rawlen\", luaB_rawlen},\n  {\"rawget\", luaB_rawget},\n  {\"rawset\", luaB_rawset},\n  {\"select\", luaB_select},\n  {\"setmetatable\", luaB_setmetatable},\n  {\"tonumber\", luaB_tonumber},\n  {\"tostring\", luaB_tostring},\n  {\"type\", luaB_type},\n  {\"xpcall\", luaB_xpcall},\n  /* placeholders */\n  {\"_G\", NULL},\n  {\"_VERSION\", NULL},\n  {NULL, NULL}\n};\n\n\nLUAMOD_API int luaopen_base (lua_State *L) {\n  /* open lib into global table */\n  lua_pushglobaltable(L);\n  luaL_setfuncs(L, base_funcs, 0);\n  /* set global _G */\n  lua_pushvalue(L, -1);\n  lua_setfield(L, -2, \"_G\");\n  /* set global _VERSION */\n  lua_pushliteral(L, LUA_VERSION);\n  lua_setfield(L, -2, \"_VERSION\");\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lbitlib.c",
    "content": "/*\n** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $\n** Standard library for bitwise operations\n** See Copyright Notice in lua.h\n*/\n\n#define lbitlib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n#if defined(LUA_COMPAT_BITLIB)\t\t/* { */\n\n\n#define pushunsigned(L,n)\tlua_pushinteger(L, (lua_Integer)(n))\n#define checkunsigned(L,i)\t((lua_Unsigned)luaL_checkinteger(L,i))\n\n\n/* number of bits to consider in a number */\n#if !defined(LUA_NBITS)\n#define LUA_NBITS\t32\n#endif\n\n\n/*\n** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must\n** be made in two parts to avoid problems when LUA_NBITS is equal to the\n** number of bits in a lua_Unsigned.)\n*/\n#define ALLONES\t\t(~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))\n\n\n/* macro to trim extra bits */\n#define trim(x)\t\t((x) & ALLONES)\n\n\n/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */\n#define mask(n)\t\t(~((ALLONES << 1) << ((n) - 1)))\n\n\n\nstatic lua_Unsigned andaux (lua_State *L) {\n  int i, n = lua_gettop(L);\n  lua_Unsigned r = ~(lua_Unsigned)0;\n  for (i = 1; i <= n; i++)\n    r &= checkunsigned(L, i);\n  return trim(r);\n}\n\n\nstatic int b_and (lua_State *L) {\n  lua_Unsigned r = andaux(L);\n  pushunsigned(L, r);\n  return 1;\n}\n\n\nstatic int b_test (lua_State *L) {\n  lua_Unsigned r = andaux(L);\n  lua_pushboolean(L, r != 0);\n  return 1;\n}\n\n\nstatic int b_or (lua_State *L) {\n  int i, n = lua_gettop(L);\n  lua_Unsigned r = 0;\n  for (i = 1; i <= n; i++)\n    r |= checkunsigned(L, i);\n  pushunsigned(L, trim(r));\n  return 1;\n}\n\n\nstatic int b_xor (lua_State *L) {\n  int i, n = lua_gettop(L);\n  lua_Unsigned r = 0;\n  for (i = 1; i <= n; i++)\n    r ^= checkunsigned(L, i);\n  pushunsigned(L, trim(r));\n  return 1;\n}\n\n\nstatic int b_not (lua_State *L) {\n  lua_Unsigned r = ~checkunsigned(L, 1);\n  pushunsigned(L, trim(r));\n  return 1;\n}\n\n\nstatic int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {\n  if (i < 0) {  /* shift right? */\n    i = -i;\n    r = trim(r);\n    if (i >= LUA_NBITS) r = 0;\n    else r >>= i;\n  }\n  else {  /* shift left */\n    if (i >= LUA_NBITS) r = 0;\n    else r <<= i;\n    r = trim(r);\n  }\n  pushunsigned(L, r);\n  return 1;\n}\n\n\nstatic int b_lshift (lua_State *L) {\n  return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2));\n}\n\n\nstatic int b_rshift (lua_State *L) {\n  return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2));\n}\n\n\nstatic int b_arshift (lua_State *L) {\n  lua_Unsigned r = checkunsigned(L, 1);\n  lua_Integer i = luaL_checkinteger(L, 2);\n  if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))\n    return b_shift(L, r, -i);\n  else {  /* arithmetic shift for 'negative' number */\n    if (i >= LUA_NBITS) r = ALLONES;\n    else\n      r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i));  /* add signal bit */\n    pushunsigned(L, r);\n    return 1;\n  }\n}\n\n\nstatic int b_rot (lua_State *L, lua_Integer d) {\n  lua_Unsigned r = checkunsigned(L, 1);\n  int i = d & (LUA_NBITS - 1);  /* i = d % NBITS */\n  r = trim(r);\n  if (i != 0)  /* avoid undefined shift of LUA_NBITS when i == 0 */\n    r = (r << i) | (r >> (LUA_NBITS - i));\n  pushunsigned(L, trim(r));\n  return 1;\n}\n\n\nstatic int b_lrot (lua_State *L) {\n  return b_rot(L, luaL_checkinteger(L, 2));\n}\n\n\nstatic int b_rrot (lua_State *L) {\n  return b_rot(L, -luaL_checkinteger(L, 2));\n}\n\n\n/*\n** get field and width arguments for field-manipulation functions,\n** checking whether they are valid.\n** ('luaL_error' called without 'return' to avoid later warnings about\n** 'width' being used uninitialized.)\n*/\nstatic int fieldargs (lua_State *L, int farg, int *width) {\n  lua_Integer f = luaL_checkinteger(L, farg);\n  lua_Integer w = luaL_optinteger(L, farg + 1, 1);\n  luaL_argcheck(L, 0 <= f, farg, \"field cannot be negative\");\n  luaL_argcheck(L, 0 < w, farg + 1, \"width must be positive\");\n  if (f + w > LUA_NBITS)\n    luaL_error(L, \"trying to access non-existent bits\");\n  *width = (int)w;\n  return (int)f;\n}\n\n\nstatic int b_extract (lua_State *L) {\n  int w;\n  lua_Unsigned r = trim(checkunsigned(L, 1));\n  int f = fieldargs(L, 2, &w);\n  r = (r >> f) & mask(w);\n  pushunsigned(L, r);\n  return 1;\n}\n\n\nstatic int b_replace (lua_State *L) {\n  int w;\n  lua_Unsigned r = trim(checkunsigned(L, 1));\n  lua_Unsigned v = trim(checkunsigned(L, 2));\n  int f = fieldargs(L, 3, &w);\n  lua_Unsigned m = mask(w);\n  r = (r & ~(m << f)) | ((v & m) << f);\n  pushunsigned(L, r);\n  return 1;\n}\n\n\nstatic const luaL_Reg bitlib[] = {\n  {\"arshift\", b_arshift},\n  {\"band\", b_and},\n  {\"bnot\", b_not},\n  {\"bor\", b_or},\n  {\"bxor\", b_xor},\n  {\"btest\", b_test},\n  {\"extract\", b_extract},\n  {\"lrotate\", b_lrot},\n  {\"lshift\", b_lshift},\n  {\"replace\", b_replace},\n  {\"rrotate\", b_rrot},\n  {\"rshift\", b_rshift},\n  {NULL, NULL}\n};\n\n\n\nLUAMOD_API int luaopen_bit32 (lua_State *L) {\n  luaL_newlib(L, bitlib);\n  return 1;\n}\n\n\n#else\t\t\t\t\t/* }{ */\n\n\nLUAMOD_API int luaopen_bit32 (lua_State *L) {\n  return luaL_error(L, \"library 'bit32' has been deprecated\");\n}\n\n#endif\t\t\t\t\t/* } */\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lcode.c",
    "content": "/*\n** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $\n** Code generator for Lua\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 4244)\n#define lcode_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <math.h>\n#include <stdlib.h>\n\n#include \"lua.h\"\n\n#include \"lcode.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lgc.h\"\n#include \"llex.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lopcodes.h\"\n#include \"lparser.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"lvm.h\"\n\n\n/* Maximum number of registers in a Lua function (must fit in 8 bits) */\n#define MAXREGS\t\t255\n\n\n#define hasjumps(e)\t((e)->t != (e)->f)\n\n\n/*\n** If expression is a numeric constant, fills 'v' with its value\n** and returns 1. Otherwise, returns 0.\n*/\nstatic int tonumeral(const expdesc *e, TValue *v) {\n  if (hasjumps(e))\n    return 0;  /* not a numeral */\n  switch (e->k) {\n    case VKINT:\n      if (v) setivalue(v, e->u.ival);\n      return 1;\n    case VKFLT:\n      if (v) setfltvalue(v, e->u.nval);\n      return 1;\n    default: return 0;\n  }\n}\n\n\n/*\n** Create a OP_LOADNIL instruction, but try to optimize: if the previous\n** instruction is also OP_LOADNIL and ranges are compatible, adjust\n** range of previous instruction instead of emitting a new one. (For\n** instance, 'local a; local b' will generate a single opcode.)\n*/\nvoid luaK_nil (FuncState *fs, int from, int n) {\n  Instruction *previous;\n  int l = from + n - 1;  /* last register to set nil */\n  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */\n    previous = &fs->f->code[fs->pc-1];\n    if (GET_OPCODE(*previous) == OP_LOADNIL) {  /* previous is LOADNIL? */\n      int pfrom = GETARG_A(*previous);  /* get previous range */\n      int pl = pfrom + GETARG_B(*previous);\n      if ((pfrom <= from && from <= pl + 1) ||\n          (from <= pfrom && pfrom <= l + 1)) {  /* can connect both? */\n        if (pfrom < from) from = pfrom;  /* from = min(from, pfrom) */\n        if (pl > l) l = pl;  /* l = max(l, pl) */\n        SETARG_A(*previous, from);\n        SETARG_B(*previous, l - from);\n        return;\n      }\n    }  /* else go through */\n  }\n  luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0);  /* else no optimization */\n}\n\n\n/*\n** Gets the destination address of a jump instruction. Used to traverse\n** a list of jumps.\n*/\nstatic int getjump (FuncState *fs, int pc) {\n  int offset = GETARG_sBx(fs->f->code[pc]);\n  if (offset == NO_JUMP)  /* point to itself represents end of list */\n    return NO_JUMP;  /* end of list */\n  else\n    return (pc+1)+offset;  /* turn offset into absolute position */\n}\n\n\n/*\n** Fix jump instruction at position 'pc' to jump to 'dest'.\n** (Jump addresses are relative in Lua)\n*/\nstatic void fixjump (FuncState *fs, int pc, int dest) {\n  Instruction *jmp = &fs->f->code[pc];\n  int offset = dest - (pc + 1);\n  lua_assert(dest != NO_JUMP);\n  if (abs(offset) > MAXARG_sBx)\n    luaX_syntaxerror(fs->ls, \"control structure too long\");\n  SETARG_sBx(*jmp, offset);\n}\n\n\n/*\n** Concatenate jump-list 'l2' into jump-list 'l1'\n*/\nvoid luaK_concat (FuncState *fs, int *l1, int l2) {\n  if (l2 == NO_JUMP) return;  /* nothing to concatenate? */\n  else if (*l1 == NO_JUMP)  /* no original list? */\n    *l1 = l2;  /* 'l1' points to 'l2' */\n  else {\n    int list = *l1;\n    int next;\n    while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */\n      list = next;\n    fixjump(fs, list, l2);  /* last element links to 'l2' */\n  }\n}\n\n\n/*\n** Create a jump instruction and return its position, so its destination\n** can be fixed later (with 'fixjump'). If there are jumps to\n** this position (kept in 'jpc'), link them all together so that\n** 'patchlistaux' will fix all them directly to the final destination.\n*/\nint luaK_jump (FuncState *fs) {\n  int jpc = fs->jpc;  /* save list of jumps to here */\n  int j;\n  fs->jpc = NO_JUMP;  /* no more jumps to here */\n  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);\n  luaK_concat(fs, &j, jpc);  /* keep them on hold */\n  return j;\n}\n\n\n/*\n** Code a 'return' instruction\n*/\nvoid luaK_ret (FuncState *fs, int first, int nret) {\n  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);\n}\n\n\n/*\n** Code a \"conditional jump\", that is, a test or comparison opcode\n** followed by a jump. Return jump position.\n*/\nstatic int condjump (FuncState *fs, OpCode op, int A, int B, int C) {\n  luaK_codeABC(fs, op, A, B, C);\n  return luaK_jump(fs);\n}\n\n\n/*\n** returns current 'pc' and marks it as a jump target (to avoid wrong\n** optimizations with consecutive instructions not in the same basic block).\n*/\nint luaK_getlabel (FuncState *fs) {\n  fs->lasttarget = fs->pc;\n  return fs->pc;\n}\n\n\n/*\n** Returns the position of the instruction \"controlling\" a given\n** jump (that is, its condition), or the jump itself if it is\n** unconditional.\n*/\nstatic Instruction *getjumpcontrol (FuncState *fs, int pc) {\n  Instruction *pi = &fs->f->code[pc];\n  if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))\n    return pi-1;\n  else\n    return pi;\n}\n\n\n/*\n** Patch destination register for a TESTSET instruction.\n** If instruction in position 'node' is not a TESTSET, return 0 (\"fails\").\n** Otherwise, if 'reg' is not 'NO_REG', set it as the destination\n** register. Otherwise, change instruction to a simple 'TEST' (produces\n** no register value)\n*/\nstatic int patchtestreg (FuncState *fs, int node, int reg) {\n  Instruction *i = getjumpcontrol(fs, node);\n  if (GET_OPCODE(*i) != OP_TESTSET)\n    return 0;  /* cannot patch other instructions */\n  if (reg != NO_REG && reg != GETARG_B(*i))\n    SETARG_A(*i, reg);\n  else {\n     /* no register to put value or register already has the value;\n        change instruction to simple test */\n    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));\n  }\n  return 1;\n}\n\n\n/*\n** Traverse a list of tests ensuring no one produces a value\n*/\nstatic void removevalues (FuncState *fs, int list) {\n  for (; list != NO_JUMP; list = getjump(fs, list))\n      patchtestreg(fs, list, NO_REG);\n}\n\n\n/*\n** Traverse a list of tests, patching their destination address and\n** registers: tests producing values jump to 'vtarget' (and put their\n** values in 'reg'), other tests jump to 'dtarget'.\n*/\nstatic void patchlistaux (FuncState *fs, int list, int vtarget, int reg,\n                          int dtarget) {\n  while (list != NO_JUMP) {\n    int next = getjump(fs, list);\n    if (patchtestreg(fs, list, reg))\n      fixjump(fs, list, vtarget);\n    else\n      fixjump(fs, list, dtarget);  /* jump to default target */\n    list = next;\n  }\n}\n\n\n/*\n** Ensure all pending jumps to current position are fixed (jumping\n** to current position with no values) and reset list of pending\n** jumps\n*/\nstatic void dischargejpc (FuncState *fs) {\n  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);\n  fs->jpc = NO_JUMP;\n}\n\n\n/*\n** Add elements in 'list' to list of pending jumps to \"here\"\n** (current position)\n*/\nvoid luaK_patchtohere (FuncState *fs, int list) {\n  luaK_getlabel(fs);  /* mark \"here\" as a jump target */\n  luaK_concat(fs, &fs->jpc, list);\n}\n\n\n/*\n** Path all jumps in 'list' to jump to 'target'.\n** (The assert means that we cannot fix a jump to a forward address\n** because we only know addresses once code is generated.)\n*/\nvoid luaK_patchlist (FuncState *fs, int list, int target) {\n  if (target == fs->pc)  /* 'target' is current position? */\n    luaK_patchtohere(fs, list);  /* add list to pending jumps */\n  else {\n    lua_assert(target < fs->pc);\n    patchlistaux(fs, list, target, NO_REG, target);\n  }\n}\n\n\n/*\n** Path all jumps in 'list' to close upvalues up to given 'level'\n** (The assertion checks that jumps either were closing nothing\n** or were closing higher levels, from inner blocks.)\n*/\nvoid luaK_patchclose (FuncState *fs, int list, int level) {\n  level++;  /* argument is +1 to reserve 0 as non-op */\n  for (; list != NO_JUMP; list = getjump(fs, list)) {\n    lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&\n                (GETARG_A(fs->f->code[list]) == 0 ||\n                 GETARG_A(fs->f->code[list]) >= level));\n    SETARG_A(fs->f->code[list], level);\n  }\n}\n\n\n/*\n** Emit instruction 'i', checking for array sizes and saving also its\n** line information. Return 'i' position.\n*/\nstatic int luaK_code (FuncState *fs, Instruction i) {\n  Proto *f = fs->f;\n  dischargejpc(fs);  /* 'pc' will change */\n  /* put new instruction in code array */\n  luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,\n                  MAX_INT, \"opcodes\");\n  f->code[fs->pc] = i;\n  /* save corresponding line information */\n  luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,\n                  MAX_INT, \"opcodes\");\n  f->lineinfo[fs->pc] = fs->ls->lastline;\n  return fs->pc++;\n}\n\n\n/*\n** Format and emit an 'iABC' instruction. (Assertions check consistency\n** of parameters versus opcode.)\n*/\nint luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {\n  lua_assert(getOpMode(o) == iABC);\n  lua_assert(getBMode(o) != OpArgN || b == 0);\n  lua_assert(getCMode(o) != OpArgN || c == 0);\n  lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);\n  return luaK_code(fs, CREATE_ABC(o, a, b, c));\n}\n\n\n/*\n** Format and emit an 'iABx' instruction.\n*/\nint luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {\n  lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);\n  lua_assert(getCMode(o) == OpArgN);\n  lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);\n  return luaK_code(fs, CREATE_ABx(o, a, bc));\n}\n\n\n/*\n** Emit an \"extra argument\" instruction (format 'iAx')\n*/\nstatic int codeextraarg (FuncState *fs, int a) {\n  lua_assert(a <= MAXARG_Ax);\n  return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));\n}\n\n\n/*\n** Emit a \"load constant\" instruction, using either 'OP_LOADK'\n** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'\n** instruction with \"extra argument\".\n*/\nint luaK_codek (FuncState *fs, int reg, int k) {\n  if (k <= MAXARG_Bx)\n    return luaK_codeABx(fs, OP_LOADK, reg, k);\n  else {\n    int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);\n    codeextraarg(fs, k);\n    return p;\n  }\n}\n\n\n/*\n** Check register-stack level, keeping track of its maximum size\n** in field 'maxstacksize'\n*/\nvoid luaK_checkstack (FuncState *fs, int n) {\n  int newstack = fs->freereg + n;\n  if (newstack > fs->f->maxstacksize) {\n    if (newstack >= MAXREGS)\n      luaX_syntaxerror(fs->ls,\n        \"function or expression needs too many registers\");\n    fs->f->maxstacksize = cast_byte(newstack);\n  }\n}\n\n\n/*\n** Reserve 'n' registers in register stack\n*/\nvoid luaK_reserveregs (FuncState *fs, int n) {\n  luaK_checkstack(fs, n);\n  fs->freereg += n;\n}\n\n\n/*\n** Free register 'reg', if it is neither a constant index nor\n** a local variable.\n)\n*/\nstatic void freereg (FuncState *fs, int reg) {\n  if (!ISK(reg) && reg >= fs->nactvar) {\n    fs->freereg--;\n    lua_assert(reg == fs->freereg);\n  }\n}\n\n\n/*\n** Free register used by expression 'e' (if any)\n*/\nstatic void freeexp (FuncState *fs, expdesc *e) {\n  if (e->k == VNONRELOC)\n    freereg(fs, e->u.info);\n}\n\n\n/*\n** Free registers used by expressions 'e1' and 'e2' (if any) in proper\n** order.\n*/\nstatic void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {\n  int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1;\n  int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1;\n  if (r1 > r2) {\n    freereg(fs, r1);\n    freereg(fs, r2);\n  }\n  else {\n    freereg(fs, r2);\n    freereg(fs, r1);\n  }\n}\n\n\n/*\n** Add constant 'v' to prototype's list of constants (field 'k').\n** Use scanner's table to cache position of constants in constant list\n** and try to reuse constants. Because some values should not be used\n** as keys (nil cannot be a key, integer keys can collapse with float\n** keys), the caller must provide a useful 'key' for indexing the cache.\n*/\nstatic int addk (FuncState *fs, TValue *key, TValue *v) {\n  lua_State *L = fs->ls->L;\n  Proto *f = fs->f;\n  TValue *idx = luaH_set(L, fs->ls->h, key);  /* index scanner table */\n  int k, oldsize;\n  if (ttisinteger(idx)) {  /* is there an index there? */\n    k = cast_int(ivalue(idx));\n    /* correct value? (warning: must distinguish floats from integers!) */\n    if (k < fs->nk && ttype(&f->k[k]) == ttype(v) &&\n                      luaV_rawequalobj(&f->k[k], v))\n      return k;  /* reuse index */\n  }\n  /* constant not found; create a new entry */\n  oldsize = f->sizek;\n  k = fs->nk;\n  /* numerical value does not need GC barrier;\n     table has no metatable, so it does not need to invalidate cache */\n  setivalue(idx, k);\n  luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, \"constants\");\n  while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);\n  setobj(L, &f->k[k], v);\n  fs->nk++;\n  luaC_barrier(L, f, v);\n  return k;\n}\n\n\n/*\n** Add a string to list of constants and return its index.\n*/\nint luaK_stringK (FuncState *fs, TString *s) {\n  TValue o;\n  setsvalue(fs->ls->L, &o, s);\n  return addk(fs, &o, &o);  /* use string itself as key */\n}\n\n\n/*\n** Add an integer to list of constants and return its index.\n** Integers use userdata as keys to avoid collision with floats with\n** same value; conversion to 'void*' is used only for hashing, so there\n** are no \"precision\" problems.\n*/\nint luaK_intK (FuncState *fs, lua_Integer n) {\n  TValue k, o;\n  setpvalue(&k, cast(void*, cast(size_t, n)));\n  setivalue(&o, n);\n  return addk(fs, &k, &o);\n}\n\n/*\n** Add a float to list of constants and return its index.\n*/\nstatic int luaK_numberK (FuncState *fs, lua_Number r) {\n  TValue o;\n  setfltvalue(&o, r);\n  return addk(fs, &o, &o);  /* use number itself as key */\n}\n\n\n/*\n** Add a boolean to list of constants and return its index.\n*/\nstatic int boolK (FuncState *fs, int b) {\n  TValue o;\n  setbvalue(&o, b);\n  return addk(fs, &o, &o);  /* use boolean itself as key */\n}\n\n\n/*\n** Add nil to list of constants and return its index.\n*/\nstatic int nilK (FuncState *fs) {\n  TValue k, v;\n  setnilvalue(&v);\n  /* cannot use nil as key; instead use table itself to represent nil */\n  sethvalue(fs->ls->L, &k, fs->ls->h);\n  return addk(fs, &k, &v);\n}\n\n\n/*\n** Fix an expression to return the number of results 'nresults'.\n** Either 'e' is a multi-ret expression (function call or vararg)\n** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).\n*/\nvoid luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {\n  if (e->k == VCALL) {  /* expression is an open function call? */\n    SETARG_C(getinstruction(fs, e), nresults + 1);\n  }\n  else if (e->k == VVARARG) {\n    Instruction *pc = &getinstruction(fs, e);\n    SETARG_B(*pc, nresults + 1);\n    SETARG_A(*pc, fs->freereg);\n    luaK_reserveregs(fs, 1);\n  }\n  else lua_assert(nresults == LUA_MULTRET);\n}\n\n\n/*\n** Fix an expression to return one result.\n** If expression is not a multi-ret expression (function call or\n** vararg), it already returns one result, so nothing needs to be done.\n** Function calls become VNONRELOC expressions (as its result comes\n** fixed in the base register of the call), while vararg expressions\n** become VRELOCABLE (as OP_VARARG puts its results where it wants).\n** (Calls are created returning one result, so that does not need\n** to be fixed.)\n*/\nvoid luaK_setoneret (FuncState *fs, expdesc *e) {\n  if (e->k == VCALL) {  /* expression is an open function call? */\n    /* already returns 1 value */\n    lua_assert(GETARG_C(getinstruction(fs, e)) == 2);\n    e->k = VNONRELOC;  /* result has fixed position */\n    e->u.info = GETARG_A(getinstruction(fs, e));\n  }\n  else if (e->k == VVARARG) {\n    SETARG_B(getinstruction(fs, e), 2);\n    e->k = VRELOCABLE;  /* can relocate its simple result */\n  }\n}\n\n\n/*\n** Ensure that expression 'e' is not a variable.\n*/\nvoid luaK_dischargevars (FuncState *fs, expdesc *e) {\n  switch (e->k) {\n    case VLOCAL: {  /* already in a register */\n      e->k = VNONRELOC;  /* becomes a non-relocatable value */\n      break;\n    }\n    case VUPVAL: {  /* move value to some (pending) register */\n      e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);\n      e->k = VRELOCABLE;\n      break;\n    }\n    case VINDEXED: {\n      OpCode op;\n      freereg(fs, e->u.ind.idx);\n      if (e->u.ind.vt == VLOCAL) {  /* is 't' in a register? */\n        freereg(fs, e->u.ind.t);\n        op = OP_GETTABLE;\n      }\n      else {\n        lua_assert(e->u.ind.vt == VUPVAL);\n        op = OP_GETTABUP;  /* 't' is in an upvalue */\n      }\n      e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);\n      e->k = VRELOCABLE;\n      break;\n    }\n    case VVARARG: case VCALL: {\n      luaK_setoneret(fs, e);\n      break;\n    }\n    default: break;  /* there is one value available (somewhere) */\n  }\n}\n\n\n/*\n** Ensures expression value is in register 'reg' (and therefore\n** 'e' will become a non-relocatable expression).\n*/\nstatic void discharge2reg (FuncState *fs, expdesc *e, int reg) {\n  luaK_dischargevars(fs, e);\n  switch (e->k) {\n    case VNIL: {\n      luaK_nil(fs, reg, 1);\n      break;\n    }\n    case VFALSE: case VTRUE: {\n      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);\n      break;\n    }\n    case VK: {\n      luaK_codek(fs, reg, e->u.info);\n      break;\n    }\n    case VKFLT: {\n      luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));\n      break;\n    }\n    case VKINT: {\n      luaK_codek(fs, reg, luaK_intK(fs, e->u.ival));\n      break;\n    }\n    case VRELOCABLE: {\n      Instruction *pc = &getinstruction(fs, e);\n      SETARG_A(*pc, reg);  /* instruction will put result in 'reg' */\n      break;\n    }\n    case VNONRELOC: {\n      if (reg != e->u.info)\n        luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);\n      break;\n    }\n    default: {\n      lua_assert(e->k == VJMP);\n      return;  /* nothing to do... */\n    }\n  }\n  e->u.info = reg;\n  e->k = VNONRELOC;\n}\n\n\n/*\n** Ensures expression value is in any register.\n*/\nstatic void discharge2anyreg (FuncState *fs, expdesc *e) {\n  if (e->k != VNONRELOC) {  /* no fixed register yet? */\n    luaK_reserveregs(fs, 1);  /* get a register */\n    discharge2reg(fs, e, fs->freereg-1);  /* put value there */\n  }\n}\n\n\nstatic int code_loadbool (FuncState *fs, int A, int b, int jump) {\n  luaK_getlabel(fs);  /* those instructions may be jump targets */\n  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);\n}\n\n\n/*\n** check whether list has any jump that do not produce a value\n** or produce an inverted value\n*/\nstatic int need_value (FuncState *fs, int list) {\n  for (; list != NO_JUMP; list = getjump(fs, list)) {\n    Instruction i = *getjumpcontrol(fs, list);\n    if (GET_OPCODE(i) != OP_TESTSET) return 1;\n  }\n  return 0;  /* not found */\n}\n\n\n/*\n** Ensures final expression result (including results from its jump\n** lists) is in register 'reg'.\n** If expression has jumps, need to patch these jumps either to\n** its final position or to \"load\" instructions (for those tests\n** that do not produce values).\n*/\nstatic void exp2reg (FuncState *fs, expdesc *e, int reg) {\n  discharge2reg(fs, e, reg);\n  if (e->k == VJMP)  /* expression itself is a test? */\n    luaK_concat(fs, &e->t, e->u.info);  /* put this jump in 't' list */\n  if (hasjumps(e)) {\n    int final;  /* position after whole expression */\n    int p_f = NO_JUMP;  /* position of an eventual LOAD false */\n    int p_t = NO_JUMP;  /* position of an eventual LOAD true */\n    if (need_value(fs, e->t) || need_value(fs, e->f)) {\n      int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);\n      p_f = code_loadbool(fs, reg, 0, 1);\n      p_t = code_loadbool(fs, reg, 1, 0);\n      luaK_patchtohere(fs, fj);\n    }\n    final = luaK_getlabel(fs);\n    patchlistaux(fs, e->f, final, reg, p_f);\n    patchlistaux(fs, e->t, final, reg, p_t);\n  }\n  e->f = e->t = NO_JUMP;\n  e->u.info = reg;\n  e->k = VNONRELOC;\n}\n\n\n/*\n** Ensures final expression result (including results from its jump\n** lists) is in next available register.\n*/\nvoid luaK_exp2nextreg (FuncState *fs, expdesc *e) {\n  luaK_dischargevars(fs, e);\n  freeexp(fs, e);\n  luaK_reserveregs(fs, 1);\n  exp2reg(fs, e, fs->freereg - 1);\n}\n\n\n/*\n** Ensures final expression result (including results from its jump\n** lists) is in some (any) register and return that register.\n*/\nint luaK_exp2anyreg (FuncState *fs, expdesc *e) {\n  luaK_dischargevars(fs, e);\n  if (e->k == VNONRELOC) {  /* expression already has a register? */\n    if (!hasjumps(e))  /* no jumps? */\n      return e->u.info;  /* result is already in a register */\n    if (e->u.info >= fs->nactvar) {  /* reg. is not a local? */\n      exp2reg(fs, e, e->u.info);  /* put final result in it */\n      return e->u.info;\n    }\n  }\n  luaK_exp2nextreg(fs, e);  /* otherwise, use next available register */\n  return e->u.info;\n}\n\n\n/*\n** Ensures final expression result is either in a register or in an\n** upvalue.\n*/\nvoid luaK_exp2anyregup (FuncState *fs, expdesc *e) {\n  if (e->k != VUPVAL || hasjumps(e))\n    luaK_exp2anyreg(fs, e);\n}\n\n\n/*\n** Ensures final expression result is either in a register or it is\n** a constant.\n*/\nvoid luaK_exp2val (FuncState *fs, expdesc *e) {\n  if (hasjumps(e))\n    luaK_exp2anyreg(fs, e);\n  else\n    luaK_dischargevars(fs, e);\n}\n\n\n/*\n** Ensures final expression result is in a valid R/K index\n** (that is, it is either in a register or in 'k' with an index\n** in the range of R/K indices).\n** Returns R/K index.\n*/\nint luaK_exp2RK (FuncState *fs, expdesc *e) {\n  luaK_exp2val(fs, e);\n  switch (e->k) {  /* move constants to 'k' */\n    case VTRUE: e->u.info = boolK(fs, 1); goto vk;\n    case VFALSE: e->u.info = boolK(fs, 0); goto vk;\n    case VNIL: e->u.info = nilK(fs); goto vk;\n    case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk;\n    case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk;\n    case VK:\n     vk:\n      e->k = VK;\n      if (e->u.info <= MAXINDEXRK)  /* constant fits in 'argC'? */\n        return RKASK(e->u.info);\n      else break;\n    default: break;\n  }\n  /* not a constant in the right range: put it in a register */\n  return luaK_exp2anyreg(fs, e);\n}\n\n\n/*\n** Generate code to store result of expression 'ex' into variable 'var'.\n*/\nvoid luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {\n  switch (var->k) {\n    case VLOCAL: {\n      freeexp(fs, ex);\n      exp2reg(fs, ex, var->u.info);  /* compute 'ex' into proper place */\n      return;\n    }\n    case VUPVAL: {\n      int e = luaK_exp2anyreg(fs, ex);\n      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);\n      break;\n    }\n    case VINDEXED: {\n      OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;\n      int e = luaK_exp2RK(fs, ex);\n      luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);\n      break;\n    }\n    default: lua_assert(0);  /* invalid var kind to store */\n  }\n  freeexp(fs, ex);\n}\n\n\n/*\n** Emit SELF instruction (convert expression 'e' into 'e:key(e,').\n*/\nvoid luaK_self (FuncState *fs, expdesc *e, expdesc *key) {\n  int ereg;\n  luaK_exp2anyreg(fs, e);\n  ereg = e->u.info;  /* register where 'e' was placed */\n  freeexp(fs, e);\n  e->u.info = fs->freereg;  /* base register for op_self */\n  e->k = VNONRELOC;  /* self expression has a fixed register */\n  luaK_reserveregs(fs, 2);  /* function and 'self' produced by op_self */\n  luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));\n  freeexp(fs, key);\n}\n\n\n/*\n** Negate condition 'e' (where 'e' is a comparison).\n*/\nstatic void negatecondition (FuncState *fs, expdesc *e) {\n  Instruction *pc = getjumpcontrol(fs, e->u.info);\n  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&\n                                           GET_OPCODE(*pc) != OP_TEST);\n  SETARG_A(*pc, !(GETARG_A(*pc)));\n}\n\n\n/*\n** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'\n** is true, code will jump if 'e' is true.) Return jump position.\n** Optimize when 'e' is 'not' something, inverting the condition\n** and removing the 'not'.\n*/\nstatic int jumponcond (FuncState *fs, expdesc *e, int cond) {\n  if (e->k == VRELOCABLE) {\n    Instruction ie = getinstruction(fs, e);\n    if (GET_OPCODE(ie) == OP_NOT) {\n      fs->pc--;  /* remove previous OP_NOT */\n      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);\n    }\n    /* else go through */\n  }\n  discharge2anyreg(fs, e);\n  freeexp(fs, e);\n  return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);\n}\n\n\n/*\n** Emit code to go through if 'e' is true, jump otherwise.\n*/\nvoid luaK_goiftrue (FuncState *fs, expdesc *e) {\n  int pc;  /* pc of new jump */\n  luaK_dischargevars(fs, e);\n  switch (e->k) {\n    case VJMP: {  /* condition? */\n      negatecondition(fs, e);  /* jump when it is false */\n      pc = e->u.info;  /* save jump position */\n      break;\n    }\n    case VK: case VKFLT: case VKINT: case VTRUE: {\n      pc = NO_JUMP;  /* always true; do nothing */\n      break;\n    }\n    default: {\n      pc = jumponcond(fs, e, 0);  /* jump when false */\n      break;\n    }\n  }\n  luaK_concat(fs, &e->f, pc);  /* insert new jump in false list */\n  luaK_patchtohere(fs, e->t);  /* true list jumps to here (to go through) */\n  e->t = NO_JUMP;\n}\n\n\n/*\n** Emit code to go through if 'e' is false, jump otherwise.\n*/\nvoid luaK_goiffalse (FuncState *fs, expdesc *e) {\n  int pc;  /* pc of new jump */\n  luaK_dischargevars(fs, e);\n  switch (e->k) {\n    case VJMP: {\n      pc = e->u.info;  /* already jump if true */\n      break;\n    }\n    case VNIL: case VFALSE: {\n      pc = NO_JUMP;  /* always false; do nothing */\n      break;\n    }\n    default: {\n      pc = jumponcond(fs, e, 1);  /* jump if true */\n      break;\n    }\n  }\n  luaK_concat(fs, &e->t, pc);  /* insert new jump in 't' list */\n  luaK_patchtohere(fs, e->f);  /* false list jumps to here (to go through) */\n  e->f = NO_JUMP;\n}\n\n\n/*\n** Code 'not e', doing constant folding.\n*/\nstatic void codenot (FuncState *fs, expdesc *e) {\n  luaK_dischargevars(fs, e);\n  switch (e->k) {\n    case VNIL: case VFALSE: {\n      e->k = VTRUE;  /* true == not nil == not false */\n      break;\n    }\n    case VK: case VKFLT: case VKINT: case VTRUE: {\n      e->k = VFALSE;  /* false == not \"x\" == not 0.5 == not 1 == not true */\n      break;\n    }\n    case VJMP: {\n      negatecondition(fs, e);\n      break;\n    }\n    case VRELOCABLE:\n    case VNONRELOC: {\n      discharge2anyreg(fs, e);\n      freeexp(fs, e);\n      e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);\n      e->k = VRELOCABLE;\n      break;\n    }\n    default: lua_assert(0);  /* cannot happen */\n  }\n  /* interchange true and false lists */\n  { int temp = e->f; e->f = e->t; e->t = temp; }\n  removevalues(fs, e->f);  /* values are useless when negated */\n  removevalues(fs, e->t);\n}\n\n\n/*\n** Create expression 't[k]'. 't' must have its final result already in a\n** register or upvalue.\n*/\nvoid luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {\n  lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));\n  t->u.ind.t = t->u.info;  /* register or upvalue index */\n  t->u.ind.idx = luaK_exp2RK(fs, k);  /* R/K index for key */\n  t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;\n  t->k = VINDEXED;\n}\n\n\n/*\n** Return false if folding can raise an error.\n** Bitwise operations need operands convertible to integers; division\n** operations cannot have 0 as divisor.\n*/\nstatic int validop (int op, TValue *v1, TValue *v2) {\n  switch (op) {\n    case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:\n    case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: {  /* conversion errors */\n      lua_Integer i;\n      return (tointeger(v1, &i) && tointeger(v2, &i));\n    }\n    case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD:  /* division by 0 */\n      return (nvalue(v2) != 0);\n    default: return 1;  /* everything else is valid */\n  }\n}\n\n\n/*\n** Try to \"constant-fold\" an operation; return 1 iff successful.\n** (In this case, 'e1' has the final result.)\n*/\nstatic int constfolding (FuncState *fs, int op, expdesc *e1,\n                                                const expdesc *e2) {\n  TValue v1, v2, res;\n  if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))\n    return 0;  /* non-numeric operands or not safe to fold */\n  luaO_arith(fs->ls->L, op, &v1, &v2, &res);  /* does operation */\n  if (ttisinteger(&res)) {\n    e1->k = VKINT;\n    e1->u.ival = ivalue(&res);\n  }\n  else {  /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */\n    lua_Number n = fltvalue(&res);\n    if (luai_numisnan(n) || n == 0)\n      return 0;\n    e1->k = VKFLT;\n    e1->u.nval = n;\n  }\n  return 1;\n}\n\n\n/*\n** Emit code for unary expressions that \"produce values\"\n** (everything but 'not').\n** Expression to produce final result will be encoded in 'e'.\n*/\nstatic void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {\n  int r = luaK_exp2anyreg(fs, e);  /* opcodes operate only on registers */\n  freeexp(fs, e);\n  e->u.info = luaK_codeABC(fs, op, 0, r, 0);  /* generate opcode */\n  e->k = VRELOCABLE;  /* all those operations are relocatable */\n  luaK_fixline(fs, line);\n}\n\n\n/*\n** Emit code for binary expressions that \"produce values\"\n** (everything but logical operators 'and'/'or' and comparison\n** operators).\n** Expression to produce final result will be encoded in 'e1'.\n** Because 'luaK_exp2RK' can free registers, its calls must be\n** in \"stack order\" (that is, first on 'e2', which may have more\n** recent registers to be released).\n*/\nstatic void codebinexpval (FuncState *fs, OpCode op,\n                           expdesc *e1, expdesc *e2, int line) {\n  int rk2 = luaK_exp2RK(fs, e2);  /* both operands are \"RK\" */\n  int rk1 = luaK_exp2RK(fs, e1);\n  freeexps(fs, e1, e2);\n  e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2);  /* generate opcode */\n  e1->k = VRELOCABLE;  /* all those operations are relocatable */\n  luaK_fixline(fs, line);\n}\n\n\n/*\n** Emit code for comparisons.\n** 'e1' was already put in R/K form by 'luaK_infix'.\n*/\nstatic void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {\n  int rk1 = (e1->k == VK) ? RKASK(e1->u.info)\n                          : check_exp(e1->k == VNONRELOC, e1->u.info);\n  int rk2 = luaK_exp2RK(fs, e2);\n  freeexps(fs, e1, e2);\n  switch (opr) {\n    case OPR_NE: {  /* '(a ~= b)' ==> 'not (a == b)' */\n      e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2);\n      break;\n    }\n    case OPR_GT: case OPR_GE: {\n      /* '(a > b)' ==> '(b < a)';  '(a >= b)' ==> '(b <= a)' */\n      OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);\n      e1->u.info = condjump(fs, op, 1, rk2, rk1);  /* invert operands */\n      break;\n    }\n    default: {  /* '==', '<', '<=' use their own opcodes */\n      OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);\n      e1->u.info = condjump(fs, op, 1, rk1, rk2);\n      break;\n    }\n  }\n  e1->k = VJMP;\n}\n\n\n/*\n** Aplly prefix operation 'op' to expression 'e'.\n*/\nvoid luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {\n  static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};\n  switch (op) {\n    case OPR_MINUS: case OPR_BNOT:  /* use 'ef' as fake 2nd operand */\n      if (constfolding(fs, op + LUA_OPUNM, e, &ef))\n        break;\n      /* FALLTHROUGH */\n    case OPR_LEN:\n      codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);\n      break;\n    case OPR_NOT: codenot(fs, e); break;\n    default: lua_assert(0);\n  }\n}\n\n\n/*\n** Process 1st operand 'v' of binary operation 'op' before reading\n** 2nd operand.\n*/\nvoid luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {\n  switch (op) {\n    case OPR_AND: {\n      luaK_goiftrue(fs, v);  /* go ahead only if 'v' is true */\n      break;\n    }\n    case OPR_OR: {\n      luaK_goiffalse(fs, v);  /* go ahead only if 'v' is false */\n      break;\n    }\n    case OPR_CONCAT: {\n      luaK_exp2nextreg(fs, v);  /* operand must be on the 'stack' */\n      break;\n    }\n    case OPR_ADD: case OPR_SUB:\n    case OPR_MUL: case OPR_DIV: case OPR_IDIV:\n    case OPR_MOD: case OPR_POW:\n    case OPR_BAND: case OPR_BOR: case OPR_BXOR:\n    case OPR_SHL: case OPR_SHR: {\n      if (!tonumeral(v, NULL))\n        luaK_exp2RK(fs, v);\n      /* else keep numeral, which may be folded with 2nd operand */\n      break;\n    }\n    default: {\n      luaK_exp2RK(fs, v);\n      break;\n    }\n  }\n}\n\n\n/*\n** Finalize code for binary operation, after reading 2nd operand.\n** For '(a .. b .. c)' (which is '(a .. (b .. c))', because\n** concatenation is right associative), merge second CONCAT into first\n** one.\n*/\nvoid luaK_posfix (FuncState *fs, BinOpr op,\n                  expdesc *e1, expdesc *e2, int line) {\n  switch (op) {\n    case OPR_AND: {\n      lua_assert(e1->t == NO_JUMP);  /* list closed by 'luK_infix' */\n      luaK_dischargevars(fs, e2);\n      luaK_concat(fs, &e2->f, e1->f);\n      *e1 = *e2;\n      break;\n    }\n    case OPR_OR: {\n      lua_assert(e1->f == NO_JUMP);  /* list closed by 'luK_infix' */\n      luaK_dischargevars(fs, e2);\n      luaK_concat(fs, &e2->t, e1->t);\n      *e1 = *e2;\n      break;\n    }\n    case OPR_CONCAT: {\n      luaK_exp2val(fs, e2);\n      if (e2->k == VRELOCABLE &&\n          GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {\n        lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1);\n        freeexp(fs, e1);\n        SETARG_B(getinstruction(fs, e2), e1->u.info);\n        e1->k = VRELOCABLE; e1->u.info = e2->u.info;\n      }\n      else {\n        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */\n        codebinexpval(fs, OP_CONCAT, e1, e2, line);\n      }\n      break;\n    }\n    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:\n    case OPR_IDIV: case OPR_MOD: case OPR_POW:\n    case OPR_BAND: case OPR_BOR: case OPR_BXOR:\n    case OPR_SHL: case OPR_SHR: {\n      if (!constfolding(fs, op + LUA_OPADD, e1, e2))\n        codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);\n      break;\n    }\n    case OPR_EQ: case OPR_LT: case OPR_LE:\n    case OPR_NE: case OPR_GT: case OPR_GE: {\n      codecomp(fs, op, e1, e2);\n      break;\n    }\n    default: lua_assert(0);\n  }\n}\n\n\n/*\n** Change line information associated with current position.\n*/\nvoid luaK_fixline (FuncState *fs, int line) {\n  fs->f->lineinfo[fs->pc - 1] = line;\n}\n\n\n/*\n** Emit a SETLIST instruction.\n** 'base' is register that keeps table;\n** 'nelems' is #table plus those to be stored now;\n** 'tostore' is number of values (in registers 'base + 1',...) to add to\n** table (or LUA_MULTRET to add up to stack top).\n*/\nvoid luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {\n  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;\n  int b = (tostore == LUA_MULTRET) ? 0 : tostore;\n  lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH);\n  if (c <= MAXARG_C)\n    luaK_codeABC(fs, OP_SETLIST, base, b, c);\n  else if (c <= MAXARG_Ax) {\n    luaK_codeABC(fs, OP_SETLIST, base, b, 0);\n    codeextraarg(fs, c);\n  }\n  else\n    luaX_syntaxerror(fs->ls, \"constructor too long\");\n  fs->freereg = base + 1;  /* free registers with list values */\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lcode.h",
    "content": "/*\n** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $\n** Code generator for Lua\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lcode_h\n#define lcode_h\n\n#include \"llex.h\"\n#include \"lobject.h\"\n#include \"lopcodes.h\"\n#include \"lparser.h\"\n\n\n/*\n** Marks the end of a patch list. It is an invalid value both as an absolute\n** address, and as a list link (would link an element to itself).\n*/\n#define NO_JUMP (-1)\n\n\n/*\n** grep \"ORDER OPR\" if you change these enums  (ORDER OP)\n*/\ntypedef enum BinOpr {\n  OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,\n  OPR_DIV,\n  OPR_IDIV,\n  OPR_BAND, OPR_BOR, OPR_BXOR,\n  OPR_SHL, OPR_SHR,\n  OPR_CONCAT,\n  OPR_EQ, OPR_LT, OPR_LE,\n  OPR_NE, OPR_GT, OPR_GE,\n  OPR_AND, OPR_OR,\n  OPR_NOBINOPR\n} BinOpr;\n\n\ntypedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;\n\n\n/* get (pointer to) instruction of given 'expdesc' */\n#define getinstruction(fs,e)\t((fs)->f->code[(e)->u.info])\n\n#define luaK_codeAsBx(fs,o,A,sBx)\tluaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)\n\n#define luaK_setmultret(fs,e)\tluaK_setreturns(fs, e, LUA_MULTRET)\n\n#define luaK_jumpto(fs,t)\tluaK_patchlist(fs, luaK_jump(fs), t)\n\nLUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);\nLUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);\nLUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);\nLUAI_FUNC void luaK_fixline (FuncState *fs, int line);\nLUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);\nLUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);\nLUAI_FUNC void luaK_checkstack (FuncState *fs, int n);\nLUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);\nLUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n);\nLUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);\nLUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);\nLUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);\nLUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);\nLUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);\nLUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);\nLUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);\nLUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);\nLUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);\nLUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);\nLUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);\nLUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);\nLUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);\nLUAI_FUNC int luaK_jump (FuncState *fs);\nLUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);\nLUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);\nLUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);\nLUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);\nLUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);\nLUAI_FUNC int luaK_getlabel (FuncState *fs);\nLUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);\nLUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);\nLUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,\n                            expdesc *v2, int line);\nLUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lcorolib.c",
    "content": "/*\n** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $\n** Coroutine Library\n** See Copyright Notice in lua.h\n*/\n\n#define lcorolib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <stdlib.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\nstatic lua_State *getco (lua_State *L) {\n  lua_State *co = lua_tothread(L, 1);\n  luaL_argcheck(L, co, 1, \"thread expected\");\n  return co;\n}\n\n\nstatic int auxresume (lua_State *L, lua_State *co, int narg) {\n  int status;\n  if (!lua_checkstack(co, narg)) {\n    lua_pushliteral(L, \"too many arguments to resume\");\n    return -1;  /* error flag */\n  }\n  if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {\n    lua_pushliteral(L, \"cannot resume dead coroutine\");\n    return -1;  /* error flag */\n  }\n  lua_xmove(L, co, narg);\n  status = lua_resume(co, L, narg);\n  if (status == LUA_OK || status == LUA_YIELD) {\n    int nres = lua_gettop(co);\n    if (!lua_checkstack(L, nres + 1)) {\n      lua_pop(co, nres);  /* remove results anyway */\n      lua_pushliteral(L, \"too many results to resume\");\n      return -1;  /* error flag */\n    }\n    lua_xmove(co, L, nres);  /* move yielded values */\n    return nres;\n  }\n  else {\n    lua_xmove(co, L, 1);  /* move error message */\n    return -1;  /* error flag */\n  }\n}\n\n\nstatic int luaB_coresume (lua_State *L) {\n  lua_State *co = getco(L);\n  int r;\n  r = auxresume(L, co, lua_gettop(L) - 1);\n  if (r < 0) {\n    lua_pushboolean(L, 0);\n    lua_insert(L, -2);\n    return 2;  /* return false + error message */\n  }\n  else {\n    lua_pushboolean(L, 1);\n    lua_insert(L, -(r + 1));\n    return r + 1;  /* return true + 'resume' returns */\n  }\n}\n\n\nstatic int luaB_auxwrap (lua_State *L) {\n  lua_State *co = lua_tothread(L, lua_upvalueindex(1));\n  int r = auxresume(L, co, lua_gettop(L));\n  if (r < 0) {\n    if (lua_type(L, -1) == LUA_TSTRING) {  /* error object is a string? */\n      luaL_where(L, 1);  /* add extra info */\n      lua_insert(L, -2);\n      lua_concat(L, 2);\n    }\n    return lua_error(L);  /* propagate error */\n  }\n  return r;\n}\n\n\nstatic int luaB_cocreate (lua_State *L) {\n  lua_State *NL;\n  luaL_checktype(L, 1, LUA_TFUNCTION);\n  NL = lua_newthread(L);\n  lua_pushvalue(L, 1);  /* move function to top */\n  lua_xmove(L, NL, 1);  /* move function from L to NL */\n  return 1;\n}\n\n\nstatic int luaB_cowrap (lua_State *L) {\n  luaB_cocreate(L);\n  lua_pushcclosure(L, luaB_auxwrap, 1);\n  return 1;\n}\n\n\nstatic int luaB_yield (lua_State *L) {\n  return lua_yield(L, lua_gettop(L));\n}\n\n\nstatic int luaB_costatus (lua_State *L) {\n  lua_State *co = getco(L);\n  if (L == co) lua_pushliteral(L, \"running\");\n  else {\n    switch (lua_status(co)) {\n      case LUA_YIELD:\n        lua_pushliteral(L, \"suspended\");\n        break;\n      case LUA_OK: {\n        lua_Debug ar;\n        if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */\n          lua_pushliteral(L, \"normal\");  /* it is running */\n        else if (lua_gettop(co) == 0)\n            lua_pushliteral(L, \"dead\");\n        else\n          lua_pushliteral(L, \"suspended\");  /* initial state */\n        break;\n      }\n      default:  /* some error occurred */\n        lua_pushliteral(L, \"dead\");\n        break;\n    }\n  }\n  return 1;\n}\n\n\nstatic int luaB_yieldable (lua_State *L) {\n  lua_pushboolean(L, lua_isyieldable(L));\n  return 1;\n}\n\n\nstatic int luaB_corunning (lua_State *L) {\n  int ismain = lua_pushthread(L);\n  lua_pushboolean(L, ismain);\n  return 2;\n}\n\n\nstatic const luaL_Reg co_funcs[] = {\n  {\"create\", luaB_cocreate},\n  {\"resume\", luaB_coresume},\n  {\"running\", luaB_corunning},\n  {\"status\", luaB_costatus},\n  {\"wrap\", luaB_cowrap},\n  {\"yield\", luaB_yield},\n  {\"isyieldable\", luaB_yieldable},\n  {NULL, NULL}\n};\n\n\n\nLUAMOD_API int luaopen_coroutine (lua_State *L) {\n  luaL_newlib(L, co_funcs);\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lctype.c",
    "content": "/*\n** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $\n** 'ctype' functions for Lua\n** See Copyright Notice in lua.h\n*/\n\n#define lctype_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include \"lctype.h\"\n\n#if !LUA_USE_CTYPE\t/* { */\n\n#include <limits.h>\n\nLUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {\n  0x00,  /* EOZ */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* 0. */\n  0x00,  0x08,  0x08,  0x08,  0x08,  0x08,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* 1. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x0c,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,\t/* 2. */\n  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,\n  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,\t/* 3. */\n  0x16,  0x16,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,\n  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,\t/* 4. */\n  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,\n  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,\t/* 5. */\n  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x05,\n  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,\t/* 6. */\n  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,\n  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,\t/* 7. */\n  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* 8. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* 9. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* a. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* b. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* c. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* d. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* e. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\t/* f. */\n  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,\n};\n\n#endif\t\t\t/* } */\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lctype.h",
    "content": "/*\n** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $\n** 'ctype' functions for Lua\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lctype_h\n#define lctype_h\n\n#include \"lua.h\"\n\n\n/*\n** WARNING: the functions defined here do not necessarily correspond\n** to the similar functions in the standard C ctype.h. They are\n** optimized for the specific needs of Lua\n*/\n\n#if !defined(LUA_USE_CTYPE)\n\n#if 'A' == 65 && '0' == 48\n/* ASCII case: can use its own tables; faster and fixed */\n#define LUA_USE_CTYPE\t0\n#else\n/* must use standard C ctype */\n#define LUA_USE_CTYPE\t1\n#endif\n\n#endif\n\n\n#if !LUA_USE_CTYPE\t/* { */\n\n#include <limits.h>\n\n#include \"llimits.h\"\n\n\n#define ALPHABIT\t0\n#define DIGITBIT\t1\n#define PRINTBIT\t2\n#define SPACEBIT\t3\n#define XDIGITBIT\t4\n\n\n#define MASK(B)\t\t(1 << (B))\n\n\n/*\n** add 1 to char to allow index -1 (EOZ)\n*/\n#define testprop(c,p)\t(luai_ctype_[(c)+1] & (p))\n\n/*\n** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'\n*/\n#define lislalpha(c)\ttestprop(c, MASK(ALPHABIT))\n#define lislalnum(c)\ttestprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))\n#define lisdigit(c)\ttestprop(c, MASK(DIGITBIT))\n#define lisspace(c)\ttestprop(c, MASK(SPACEBIT))\n#define lisprint(c)\ttestprop(c, MASK(PRINTBIT))\n#define lisxdigit(c)\ttestprop(c, MASK(XDIGITBIT))\n\n/*\n** this 'ltolower' only works for alphabetic characters\n*/\n#define ltolower(c)\t((c) | ('A' ^ 'a'))\n\n\n/* two more entries for 0 and -1 (EOZ) */\nLUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];\n\n\n#else\t\t\t/* }{ */\n\n/*\n** use standard C ctypes\n*/\n\n#include <ctype.h>\n\n\n#define lislalpha(c)\t(isalpha(c) || (c) == '_')\n#define lislalnum(c)\t(isalnum(c) || (c) == '_')\n#define lisdigit(c)\t(isdigit(c))\n#define lisspace(c)\t(isspace(c))\n#define lisprint(c)\t(isprint(c))\n#define lisxdigit(c)\t(isxdigit(c))\n\n#define ltolower(c)\t(tolower(c))\n\n#endif\t\t\t/* } */\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ldblib.c",
    "content": "/*\n** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $\n** Interface from Lua to its debug API\n** See Copyright Notice in lua.h\n*/\n\n#define ldblib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n/*\n** The hook table at registry[&HOOKKEY] maps threads to their current\n** hook function. (We only need the unique address of 'HOOKKEY'.)\n*/\nstatic const int HOOKKEY = 0;\n\n\n/*\n** If L1 != L, L1 can be in any state, and therefore there are no\n** guarantees about its stack space; any push in L1 must be\n** checked.\n*/\nstatic void checkstack (lua_State *L, lua_State *L1, int n) {\n  if (L != L1 && !lua_checkstack(L1, n))\n    luaL_error(L, \"stack overflow\");\n}\n\n\nstatic int db_getregistry (lua_State *L) {\n  lua_pushvalue(L, LUA_REGISTRYINDEX);\n  return 1;\n}\n\n\nstatic int db_getmetatable (lua_State *L) {\n  luaL_checkany(L, 1);\n  if (!lua_getmetatable(L, 1)) {\n    lua_pushnil(L);  /* no metatable */\n  }\n  return 1;\n}\n\n\nstatic int db_setmetatable (lua_State *L) {\n  int t = lua_type(L, 2);\n  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,\n                    \"nil or table expected\");\n  lua_settop(L, 2);\n  lua_setmetatable(L, 1);\n  return 1;  /* return 1st argument */\n}\n\n\nstatic int db_getuservalue (lua_State *L) {\n  if (lua_type(L, 1) != LUA_TUSERDATA)\n    lua_pushnil(L);\n  else\n    lua_getuservalue(L, 1);\n  return 1;\n}\n\n\nstatic int db_setuservalue (lua_State *L) {\n  luaL_checktype(L, 1, LUA_TUSERDATA);\n  luaL_checkany(L, 2);\n  lua_settop(L, 2);\n  lua_setuservalue(L, 1);\n  return 1;\n}\n\n\n/*\n** Auxiliary function used by several library functions: check for\n** an optional thread as function's first argument and set 'arg' with\n** 1 if this argument is present (so that functions can skip it to\n** access their other arguments)\n*/\nstatic lua_State *getthread (lua_State *L, int *arg) {\n  if (lua_isthread(L, 1)) {\n    *arg = 1;\n    return lua_tothread(L, 1);\n  }\n  else {\n    *arg = 0;\n    return L;  /* function will operate over current thread */\n  }\n}\n\n\n/*\n** Variations of 'lua_settable', used by 'db_getinfo' to put results\n** from 'lua_getinfo' into result table. Key is always a string;\n** value can be a string, an int, or a boolean.\n*/\nstatic void settabss (lua_State *L, const char *k, const char *v) {\n  lua_pushstring(L, v);\n  lua_setfield(L, -2, k);\n}\n\nstatic void settabsi (lua_State *L, const char *k, int v) {\n  lua_pushinteger(L, v);\n  lua_setfield(L, -2, k);\n}\n\nstatic void settabsb (lua_State *L, const char *k, int v) {\n  lua_pushboolean(L, v);\n  lua_setfield(L, -2, k);\n}\n\n\n/*\n** In function 'db_getinfo', the call to 'lua_getinfo' may push\n** results on the stack; later it creates the result table to put\n** these objects. Function 'treatstackoption' puts the result from\n** 'lua_getinfo' on top of the result table so that it can call\n** 'lua_setfield'.\n*/\nstatic void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {\n  if (L == L1)\n    lua_rotate(L, -2, 1);  /* exchange object and table */\n  else\n    lua_xmove(L1, L, 1);  /* move object to the \"main\" stack */\n  lua_setfield(L, -2, fname);  /* put object into table */\n}\n\n\n/*\n** Calls 'lua_getinfo' and collects all results in a new table.\n** L1 needs stack space for an optional input (function) plus\n** two optional outputs (function and line table) from function\n** 'lua_getinfo'.\n*/\nstatic int db_getinfo (lua_State *L) {\n  lua_Debug ar;\n  int arg;\n  lua_State *L1 = getthread(L, &arg);\n  const char *options = luaL_optstring(L, arg+2, \"flnStu\");\n  checkstack(L, L1, 3);\n  if (lua_isfunction(L, arg + 1)) {  /* info about a function? */\n    options = lua_pushfstring(L, \">%s\", options);  /* add '>' to 'options' */\n    lua_pushvalue(L, arg + 1);  /* move function to 'L1' stack */\n    lua_xmove(L, L1, 1);\n  }\n  else {  /* stack level */\n    if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {\n      lua_pushnil(L);  /* level out of range */\n      return 1;\n    }\n  }\n  if (!lua_getinfo(L1, options, &ar))\n    return luaL_argerror(L, arg+2, \"invalid option\");\n  lua_newtable(L);  /* table to collect results */\n  if (strchr(options, 'S')) {\n    settabss(L, \"source\", ar.source);\n    settabss(L, \"short_src\", ar.short_src);\n    settabsi(L, \"linedefined\", ar.linedefined);\n    settabsi(L, \"lastlinedefined\", ar.lastlinedefined);\n    settabss(L, \"what\", ar.what);\n  }\n  if (strchr(options, 'l'))\n    settabsi(L, \"currentline\", ar.currentline);\n  if (strchr(options, 'u')) {\n    settabsi(L, \"nups\", ar.nups);\n    settabsi(L, \"nparams\", ar.nparams);\n    settabsb(L, \"isvararg\", ar.isvararg);\n  }\n  if (strchr(options, 'n')) {\n    settabss(L, \"name\", ar.name);\n    settabss(L, \"namewhat\", ar.namewhat);\n  }\n  if (strchr(options, 't'))\n    settabsb(L, \"istailcall\", ar.istailcall);\n  if (strchr(options, 'L'))\n    treatstackoption(L, L1, \"activelines\");\n  if (strchr(options, 'f'))\n    treatstackoption(L, L1, \"func\");\n  return 1;  /* return table */\n}\n\n\nstatic int db_getlocal (lua_State *L) {\n  int arg;\n  lua_State *L1 = getthread(L, &arg);\n  lua_Debug ar;\n  const char *name;\n  int nvar = (int)luaL_checkinteger(L, arg + 2);  /* local-variable index */\n  if (lua_isfunction(L, arg + 1)) {  /* function argument? */\n    lua_pushvalue(L, arg + 1);  /* push function */\n    lua_pushstring(L, lua_getlocal(L, NULL, nvar));  /* push local name */\n    return 1;  /* return only name (there is no value) */\n  }\n  else {  /* stack-level argument */\n    int level = (int)luaL_checkinteger(L, arg + 1);\n    if (!lua_getstack(L1, level, &ar))  /* out of range? */\n      return luaL_argerror(L, arg+1, \"level out of range\");\n    checkstack(L, L1, 1);\n    name = lua_getlocal(L1, &ar, nvar);\n    if (name) {\n      lua_xmove(L1, L, 1);  /* move local value */\n      lua_pushstring(L, name);  /* push name */\n      lua_rotate(L, -2, 1);  /* re-order */\n      return 2;\n    }\n    else {\n      lua_pushnil(L);  /* no name (nor value) */\n      return 1;\n    }\n  }\n}\n\n\nstatic int db_setlocal (lua_State *L) {\n  int arg;\n  const char *name;\n  lua_State *L1 = getthread(L, &arg);\n  lua_Debug ar;\n  int level = (int)luaL_checkinteger(L, arg + 1);\n  int nvar = (int)luaL_checkinteger(L, arg + 2);\n  if (!lua_getstack(L1, level, &ar))  /* out of range? */\n    return luaL_argerror(L, arg+1, \"level out of range\");\n  luaL_checkany(L, arg+3);\n  lua_settop(L, arg+3);\n  checkstack(L, L1, 1);\n  lua_xmove(L, L1, 1);\n  name = lua_setlocal(L1, &ar, nvar);\n  if (name == NULL)\n    lua_pop(L1, 1);  /* pop value (if not popped by 'lua_setlocal') */\n  lua_pushstring(L, name);\n  return 1;\n}\n\n\n/*\n** get (if 'get' is true) or set an upvalue from a closure\n*/\nstatic int auxupvalue (lua_State *L, int get) {\n  const char *name;\n  int n = (int)luaL_checkinteger(L, 2);  /* upvalue index */\n  luaL_checktype(L, 1, LUA_TFUNCTION);  /* closure */\n  name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);\n  if (name == NULL) return 0;\n  lua_pushstring(L, name);\n  lua_insert(L, -(get+1));  /* no-op if get is false */\n  return get + 1;\n}\n\n\nstatic int db_getupvalue (lua_State *L) {\n  return auxupvalue(L, 1);\n}\n\n\nstatic int db_setupvalue (lua_State *L) {\n  luaL_checkany(L, 3);\n  return auxupvalue(L, 0);\n}\n\n\n/*\n** Check whether a given upvalue from a given closure exists and\n** returns its index\n*/\nstatic int checkupval (lua_State *L, int argf, int argnup) {\n  int nup = (int)luaL_checkinteger(L, argnup);  /* upvalue index */\n  luaL_checktype(L, argf, LUA_TFUNCTION);  /* closure */\n  luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,\n                   \"invalid upvalue index\");\n  return nup;\n}\n\n\nstatic int db_upvalueid (lua_State *L) {\n  int n = checkupval(L, 1, 2);\n  lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));\n  return 1;\n}\n\n\nstatic int db_upvaluejoin (lua_State *L) {\n  int n1 = checkupval(L, 1, 2);\n  int n2 = checkupval(L, 3, 4);\n  luaL_argcheck(L, !lua_iscfunction(L, 1), 1, \"Lua function expected\");\n  luaL_argcheck(L, !lua_iscfunction(L, 3), 3, \"Lua function expected\");\n  lua_upvaluejoin(L, 1, n1, 3, n2);\n  return 0;\n}\n\n\n/*\n** Call hook function registered at hook table for the current\n** thread (if there is one)\n*/\nstatic void hookf (lua_State *L, lua_Debug *ar) {\n  static const char *const hooknames[] =\n    {\"call\", \"return\", \"line\", \"count\", \"tail call\"};\n  lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);\n  lua_pushthread(L);\n  if (lua_rawget(L, -2) == LUA_TFUNCTION) {  /* is there a hook function? */\n    lua_pushstring(L, hooknames[(int)ar->event]);  /* push event name */\n    if (ar->currentline >= 0)\n      lua_pushinteger(L, ar->currentline);  /* push current line */\n    else lua_pushnil(L);\n    lua_assert(lua_getinfo(L, \"lS\", ar));\n    lua_call(L, 2, 0);  /* call hook function */\n  }\n}\n\n\n/*\n** Convert a string mask (for 'sethook') into a bit mask\n*/\nstatic int makemask (const char *smask, int count) {\n  int mask = 0;\n  if (strchr(smask, 'c')) mask |= LUA_MASKCALL;\n  if (strchr(smask, 'r')) mask |= LUA_MASKRET;\n  if (strchr(smask, 'l')) mask |= LUA_MASKLINE;\n  if (count > 0) mask |= LUA_MASKCOUNT;\n  return mask;\n}\n\n\n/*\n** Convert a bit mask (for 'gethook') into a string mask\n*/\nstatic char *unmakemask (int mask, char *smask) {\n  int i = 0;\n  if (mask & LUA_MASKCALL) smask[i++] = 'c';\n  if (mask & LUA_MASKRET) smask[i++] = 'r';\n  if (mask & LUA_MASKLINE) smask[i++] = 'l';\n  smask[i] = '\\0';\n  return smask;\n}\n\n\nstatic int db_sethook (lua_State *L) {\n  int arg, mask, count;\n  lua_Hook func;\n  lua_State *L1 = getthread(L, &arg);\n  if (lua_isnoneornil(L, arg+1)) {  /* no hook? */\n    lua_settop(L, arg+1);\n    func = NULL; mask = 0; count = 0;  /* turn off hooks */\n  }\n  else {\n    const char *smask = luaL_checkstring(L, arg+2);\n    luaL_checktype(L, arg+1, LUA_TFUNCTION);\n    count = (int)luaL_optinteger(L, arg + 3, 0);\n    func = hookf; mask = makemask(smask, count);\n  }\n  if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {\n    lua_createtable(L, 0, 2);  /* create a hook table */\n    lua_pushvalue(L, -1);\n    lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY);  /* set it in position */\n    lua_pushstring(L, \"k\");\n    lua_setfield(L, -2, \"__mode\");  /** hooktable.__mode = \"k\" */\n    lua_pushvalue(L, -1);\n    lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */\n  }\n  checkstack(L, L1, 1);\n  lua_pushthread(L1); lua_xmove(L1, L, 1);  /* key (thread) */\n  lua_pushvalue(L, arg + 1);  /* value (hook function) */\n  lua_rawset(L, -3);  /* hooktable[L1] = new Lua hook */\n  lua_sethook(L1, func, mask, count);\n  return 0;\n}\n\n\nstatic int db_gethook (lua_State *L) {\n  int arg;\n  lua_State *L1 = getthread(L, &arg);\n  char buff[5];\n  int mask = lua_gethookmask(L1);\n  lua_Hook hook = lua_gethook(L1);\n  if (hook == NULL)  /* no hook? */\n    lua_pushnil(L);\n  else if (hook != hookf)  /* external hook? */\n    lua_pushliteral(L, \"external hook\");\n  else {  /* hook table must exist */\n    lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);\n    checkstack(L, L1, 1);\n    lua_pushthread(L1); lua_xmove(L1, L, 1);\n    lua_rawget(L, -2);   /* 1st result = hooktable[L1] */\n    lua_remove(L, -2);  /* remove hook table */\n  }\n  lua_pushstring(L, unmakemask(mask, buff));  /* 2nd result = mask */\n  lua_pushinteger(L, lua_gethookcount(L1));  /* 3rd result = count */\n  return 3;\n}\n\n\nstatic int db_debug (lua_State *L) {\n  for (;;) {\n    char buffer[250];\n    //lua_writestringerror(\"%s\", \"lua_debug> \");\n    if (fgets(buffer, sizeof(buffer), stdin) == 0 ||\n        strcmp(buffer, \"cont\\n\") == 0)\n      return 0;\n    if (luaL_loadbuffer(L, buffer, strlen(buffer), \"=(debug command)\") ||\n        lua_pcall(L, 0, 0, 0))\n      //lua_writestringerror(\"%s\\n\", lua_tostring(L, -1));\n    lua_settop(L, 0);  /* remove eventual returns */\n  }\n}\n\n\nstatic int db_traceback (lua_State *L) {\n  int arg;\n  lua_State *L1 = getthread(L, &arg);\n  const char *msg = lua_tostring(L, arg + 1);\n  if (msg == NULL && !lua_isnoneornil(L, arg + 1))  /* non-string 'msg'? */\n    lua_pushvalue(L, arg + 1);  /* return it untouched */\n  else {\n    int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);\n    luaL_traceback(L, L1, msg, level);\n  }\n  return 1;\n}\n\n\nstatic const luaL_Reg dblib[] = {\n  {\"debug\", db_debug},\n  {\"getuservalue\", db_getuservalue},\n  {\"gethook\", db_gethook},\n  {\"getinfo\", db_getinfo},\n  {\"getlocal\", db_getlocal},\n  {\"getregistry\", db_getregistry},\n  {\"getmetatable\", db_getmetatable},\n  {\"getupvalue\", db_getupvalue},\n  {\"upvaluejoin\", db_upvaluejoin},\n  {\"upvalueid\", db_upvalueid},\n  {\"setuservalue\", db_setuservalue},\n  {\"sethook\", db_sethook},\n  {\"setlocal\", db_setlocal},\n  {\"setmetatable\", db_setmetatable},\n  {\"setupvalue\", db_setupvalue},\n  {\"traceback\", db_traceback},\n  {NULL, NULL}\n};\n\n\nLUAMOD_API int luaopen_debug (lua_State *L) {\n  luaL_newlib(L, dblib);\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ldebug.c",
    "content": "/*\n** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $\n** Debug Interface\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 6011)\n#define ldebug_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stdarg.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lapi.h\"\n#include \"lcode.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lobject.h\"\n#include \"lopcodes.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n#include \"lvm.h\"\n\n\n\n#define noLuaClosure(f)\t\t((f) == NULL || (f)->c.tt == LUA_TCCL)\n\n\n/* Active Lua function (given call info) */\n#define ci_func(ci)\t\t(clLvalue((ci)->func))\n\n\nstatic const char *funcnamefromcode (lua_State *L, CallInfo *ci,\n                                    const char **name);\n\n\nstatic int currentpc (CallInfo *ci) {\n  lua_assert(isLua(ci));\n  return pcRel(ci->u.l.savedpc, ci_func(ci)->p);\n}\n\n\nstatic int currentline (CallInfo *ci) {\n  return getfuncline(ci_func(ci)->p, currentpc(ci));\n}\n\n\n/*\n** If function yielded, its 'func' can be in the 'extra' field. The\n** next function restores 'func' to its correct value for debugging\n** purposes. (It exchanges 'func' and 'extra'; so, when called again,\n** after debugging, it also \"re-restores\" ** 'func' to its altered value.\n*/\nstatic void swapextra (lua_State *L) {\n  if (L->status == LUA_YIELD) {\n    CallInfo *ci = L->ci;  /* get function that yielded */\n    StkId temp = ci->func;  /* exchange its 'func' and 'extra' values */\n    ci->func = restorestack(L, ci->extra);\n    ci->extra = savestack(L, temp);\n  }\n}\n\n\n/*\n** This function can be called asynchronously (e.g. during a signal).\n** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by\n** 'resethookcount') are for debug only, and it is no problem if they\n** get arbitrary values (causes at most one wrong hook call). 'hookmask'\n** is an atomic value. We assume that pointers are atomic too (e.g., gcc\n** ensures that for all platforms where it runs). Moreover, 'hook' is\n** always checked before being called (see 'luaD_hook').\n*/\nLUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {\n  if (func == NULL || mask == 0) {  /* turn off hooks? */\n    mask = 0;\n    func = NULL;\n  }\n  if (isLua(L->ci))\n    L->oldpc = L->ci->u.l.savedpc;\n  L->hook = func;\n  L->basehookcount = count;\n  resethookcount(L);\n  L->hookmask = cast_byte(mask);\n}\n\n\nLUA_API lua_Hook lua_gethook (lua_State *L) {\n  return L->hook;\n}\n\n\nLUA_API int lua_gethookmask (lua_State *L) {\n  return L->hookmask;\n}\n\n\nLUA_API int lua_gethookcount (lua_State *L) {\n  return L->basehookcount;\n}\n\n\nLUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {\n  int status;\n  CallInfo *ci;\n  if (level < 0) return 0;  /* invalid (negative) level */\n  lua_lock(L);\n  for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)\n    level--;\n  if (level == 0 && ci != &L->base_ci) {  /* level found? */\n    status = 1;\n    ar->i_ci = ci;\n  }\n  else status = 0;  /* no such level */\n  lua_unlock(L);\n  return status;\n}\n\n\nstatic const char *upvalname (Proto *p, int uv) {\n  TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);\n  if (s == NULL) return \"?\";\n  else return getstr(s);\n}\n\n\nstatic const char *findvararg (CallInfo *ci, int n, StkId *pos) {\n  int nparams = clLvalue(ci->func)->p->numparams;\n  if (n >= cast_int(ci->u.l.base - ci->func) - nparams)\n    return NULL;  /* no such vararg */\n  else {\n    *pos = ci->func + nparams + n;\n    return \"(*vararg)\";  /* generic name for any vararg */\n  }\n}\n\n\nstatic const char *findlocal (lua_State *L, CallInfo *ci, int n,\n                              StkId *pos) {\n  const char *name = NULL;\n  StkId base;\n  if (isLua(ci)) {\n    if (n < 0)  /* access to vararg values? */\n      return findvararg(ci, -n, pos);\n    else {\n      base = ci->u.l.base;\n      name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));\n    }\n  }\n  else\n    base = ci->func + 1;\n  if (name == NULL) {  /* no 'standard' name? */\n    StkId limit = (ci == L->ci) ? L->top : ci->next->func;\n    if (limit - base >= n && n > 0)  /* is 'n' inside 'ci' stack? */\n      name = \"(*temporary)\";  /* generic name for any valid slot */\n    else\n      return NULL;  /* no name */\n  }\n  *pos = base + (n - 1);\n  return name;\n}\n\n\nLUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {\n  const char *name;\n  lua_lock(L);\n  swapextra(L);\n  if (ar == NULL) {  /* information about non-active function? */\n    if (!isLfunction(L->top - 1))  /* not a Lua function? */\n      name = NULL;\n    else  /* consider live variables at function start (parameters) */\n      name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);\n  }\n  else {  /* active function; get information through 'ar' */\n    StkId pos = NULL;  /* to avoid warnings */\n    name = findlocal(L, ar->i_ci, n, &pos);\n    if (name) {\n      setobj2s(L, L->top, pos);\n      api_incr_top(L);\n    }\n  }\n  swapextra(L);\n  lua_unlock(L);\n  return name;\n}\n\n\nLUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {\n  StkId pos = NULL;  /* to avoid warnings */\n  const char *name;\n  lua_lock(L);\n  swapextra(L);\n  name = findlocal(L, ar->i_ci, n, &pos);\n  if (name) {\n    setobjs2s(L, pos, L->top - 1);\n    L->top--;  /* pop value */\n  }\n  swapextra(L);\n  lua_unlock(L);\n  return name;\n}\n\n\nstatic void funcinfo (lua_Debug *ar, Closure *cl) {\n  if (noLuaClosure(cl)) {\n    ar->source = \"=[C]\";\n    ar->linedefined = -1;\n    ar->lastlinedefined = -1;\n    ar->what = \"C\";\n  }\n  else {\n    Proto *p = cl->l.p;\n    ar->source = p->source ? getstr(p->source) : \"=?\";\n    ar->linedefined = p->linedefined;\n    ar->lastlinedefined = p->lastlinedefined;\n    ar->what = (ar->linedefined == 0) ? \"main\" : \"Lua\";\n  }\n  luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);\n}\n\n\nstatic void collectvalidlines (lua_State *L, Closure *f) {\n  if (noLuaClosure(f)) {\n    setnilvalue(L->top);\n    api_incr_top(L);\n  }\n  else {\n    int i;\n    TValue v;\n    int *lineinfo = f->l.p->lineinfo;\n    Table *t = luaH_new(L);  /* new table to store active lines */\n    sethvalue(L, L->top, t);  /* push it on stack */\n    api_incr_top(L);\n    setbvalue(&v, 1);  /* boolean 'true' to be the value of all indices */\n    for (i = 0; i < f->l.p->sizelineinfo; i++)  /* for all lines with code */\n      luaH_setint(L, t, lineinfo[i], &v);  /* table[line] = true */\n  }\n}\n\n\nstatic const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {\n  if (ci == NULL)  /* no 'ci'? */\n    return NULL;  /* no info */\n  else if (ci->callstatus & CIST_FIN) {  /* is this a finalizer? */\n    *name = \"__gc\";\n    return \"metamethod\";  /* report it as such */\n  }\n  /* calling function is a known Lua function? */\n  else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))\n    return funcnamefromcode(L, ci->previous, name);\n  else return NULL;  /* no way to find a name */\n}\n\n\nstatic int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,\n                       Closure *f, CallInfo *ci) {\n  int status = 1;\n  for (; *what; what++) {\n    switch (*what) {\n      case 'S': {\n        funcinfo(ar, f);\n        break;\n      }\n      case 'l': {\n        ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;\n        break;\n      }\n      case 'u': {\n        ar->nups = (f == NULL) ? 0 : f->c.nupvalues;\n        if (noLuaClosure(f)) {\n          ar->isvararg = 1;\n          ar->nparams = 0;\n        }\n        else {\n          ar->isvararg = f->l.p->is_vararg;\n          ar->nparams = f->l.p->numparams;\n        }\n        break;\n      }\n      case 't': {\n        ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;\n        break;\n      }\n      case 'n': {\n        ar->namewhat = getfuncname(L, ci, &ar->name);\n        if (ar->namewhat == NULL) {\n          ar->namewhat = \"\";  /* not found */\n          ar->name = NULL;\n        }\n        break;\n      }\n      case 'L':\n      case 'f':  /* handled by lua_getinfo */\n        break;\n      default: status = 0;  /* invalid option */\n    }\n  }\n  return status;\n}\n\n\nLUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {\n  int status;\n  Closure *cl;\n  CallInfo *ci;\n  StkId func;\n  lua_lock(L);\n  swapextra(L);\n  if (*what == '>') {\n    ci = NULL;\n    func = L->top - 1;\n    api_check(L, ttisfunction(func), \"function expected\");\n    what++;  /* skip the '>' */\n    L->top--;  /* pop function */\n  }\n  else {\n    ci = ar->i_ci;\n    func = ci->func;\n    lua_assert(ttisfunction(ci->func));\n  }\n  cl = ttisclosure(func) ? clvalue(func) : NULL;\n  status = auxgetinfo(L, what, ar, cl, ci);\n  if (strchr(what, 'f')) {\n    setobjs2s(L, L->top, func);\n    api_incr_top(L);\n  }\n  swapextra(L);  /* correct before option 'L', which can raise a mem. error */\n  if (strchr(what, 'L'))\n    collectvalidlines(L, cl);\n  lua_unlock(L);\n  return status;\n}\n\n\n/*\n** {======================================================\n** Symbolic Execution\n** =======================================================\n*/\n\nstatic const char *getobjname (Proto *p, int lastpc, int reg,\n                               const char **name);\n\n\n/*\n** find a \"name\" for the RK value 'c'\n*/\nstatic void kname (Proto *p, int pc, int c, const char **name) {\n  if (ISK(c)) {  /* is 'c' a constant? */\n    TValue *kvalue = &p->k[INDEXK(c)];\n    if (ttisstring(kvalue)) {  /* literal constant? */\n      *name = svalue(kvalue);  /* it is its own name */\n      return;\n    }\n    /* else no reasonable name found */\n  }\n  else {  /* 'c' is a register */\n    const char *what = getobjname(p, pc, c, name); /* search for 'c' */\n    if (what && *what == 'c') {  /* found a constant name? */\n      return;  /* 'name' already filled */\n    }\n    /* else no reasonable name found */\n  }\n  *name = \"?\";  /* no reasonable name found */\n}\n\n\nstatic int filterpc (int pc, int jmptarget) {\n  if (pc < jmptarget)  /* is code conditional (inside a jump)? */\n    return -1;  /* cannot know who sets that register */\n  else return pc;  /* current position sets that register */\n}\n\n\n/*\n** try to find last instruction before 'lastpc' that modified register 'reg'\n*/\nstatic int findsetreg (Proto *p, int lastpc, int reg) {\n  int pc;\n  int setreg = -1;  /* keep last instruction that changed 'reg' */\n  int jmptarget = 0;  /* any code before this address is conditional */\n  for (pc = 0; pc < lastpc; pc++) {\n    Instruction i = p->code[pc];\n    OpCode op = GET_OPCODE(i);\n    int a = GETARG_A(i);\n    switch (op) {\n      case OP_LOADNIL: {\n        int b = GETARG_B(i);\n        if (a <= reg && reg <= a + b)  /* set registers from 'a' to 'a+b' */\n          setreg = filterpc(pc, jmptarget);\n        break;\n      }\n      case OP_TFORCALL: {\n        if (reg >= a + 2)  /* affect all regs above its base */\n          setreg = filterpc(pc, jmptarget);\n        break;\n      }\n      case OP_CALL:\n      case OP_TAILCALL: {\n        if (reg >= a)  /* affect all registers above base */\n          setreg = filterpc(pc, jmptarget);\n        break;\n      }\n      case OP_JMP: {\n        int b = GETARG_sBx(i);\n        int dest = pc + 1 + b;\n        /* jump is forward and do not skip 'lastpc'? */\n        if (pc < dest && dest <= lastpc) {\n          if (dest > jmptarget)\n            jmptarget = dest;  /* update 'jmptarget' */\n        }\n        break;\n      }\n      default:\n        if (testAMode(op) && reg == a)  /* any instruction that set A */\n          setreg = filterpc(pc, jmptarget);\n        break;\n    }\n  }\n  return setreg;\n}\n\n\nstatic const char *getobjname (Proto *p, int lastpc, int reg,\n                               const char **name) {\n  int pc;\n  *name = luaF_getlocalname(p, reg + 1, lastpc);\n  if (*name)  /* is a local? */\n    return \"local\";\n  /* else try symbolic execution */\n  pc = findsetreg(p, lastpc, reg);\n  if (pc != -1) {  /* could find instruction? */\n    Instruction i = p->code[pc];\n    OpCode op = GET_OPCODE(i);\n    switch (op) {\n      case OP_MOVE: {\n        int b = GETARG_B(i);  /* move from 'b' to 'a' */\n        if (b < GETARG_A(i))\n          return getobjname(p, pc, b, name);  /* get name for 'b' */\n        break;\n      }\n      case OP_GETTABUP:\n      case OP_GETTABLE: {\n        int k = GETARG_C(i);  /* key index */\n        int t = GETARG_B(i);  /* table index */\n        const char *vn = (op == OP_GETTABLE)  /* name of indexed variable */\n                         ? luaF_getlocalname(p, t + 1, pc)\n                         : upvalname(p, t);\n        kname(p, pc, k, name);\n        return (vn && strcmp(vn, LUA_ENV) == 0) ? \"global\" : \"field\";\n      }\n      case OP_GETUPVAL: {\n        *name = upvalname(p, GETARG_B(i));\n        return \"upvalue\";\n      }\n      case OP_LOADK:\n      case OP_LOADKX: {\n        int b = (op == OP_LOADK) ? GETARG_Bx(i)\n                                 : GETARG_Ax(p->code[pc + 1]);\n        if (ttisstring(&p->k[b])) {\n          *name = svalue(&p->k[b]);\n          return \"constant\";\n        }\n        break;\n      }\n      case OP_SELF: {\n        int k = GETARG_C(i);  /* key index */\n        kname(p, pc, k, name);\n        return \"method\";\n      }\n      default: break;  /* go through to return NULL */\n    }\n  }\n  return NULL;  /* could not find reasonable name */\n}\n\n\n/*\n** Try to find a name for a function based on the code that called it.\n** (Only works when function was called by a Lua function.)\n** Returns what the name is (e.g., \"for iterator\", \"method\",\n** \"metamethod\") and sets '*name' to point to the name.\n*/\nstatic const char *funcnamefromcode (lua_State *L, CallInfo *ci,\n                                     const char **name) {\n  TMS tm = (TMS)0;  /* (initial value avoids warnings) */\n  Proto *p = ci_func(ci)->p;  /* calling function */\n  int pc = currentpc(ci);  /* calling instruction index */\n  Instruction i = p->code[pc];  /* calling instruction */\n  if (ci->callstatus & CIST_HOOKED) {  /* was it called inside a hook? */\n    *name = \"?\";\n    return \"hook\";\n  }\n  switch (GET_OPCODE(i)) {\n    case OP_CALL:\n    case OP_TAILCALL:\n      return getobjname(p, pc, GETARG_A(i), name);  /* get function name */\n    case OP_TFORCALL: {  /* for iterator */\n      *name = \"for iterator\";\n       return \"for iterator\";\n    }\n    /* other instructions can do calls through metamethods */\n    case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:\n      tm = TM_INDEX;\n      break;\n    case OP_SETTABUP: case OP_SETTABLE:\n      tm = TM_NEWINDEX;\n      break;\n    case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:\n    case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND:\n    case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: {\n      int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD);  /* ORDER OP */\n      tm = cast(TMS, offset + cast_int(TM_ADD));  /* ORDER TM */\n      break;\n    }\n    case OP_UNM: tm = TM_UNM; break;\n    case OP_BNOT: tm = TM_BNOT; break;\n    case OP_LEN: tm = TM_LEN; break;\n    case OP_CONCAT: tm = TM_CONCAT; break;\n    case OP_EQ: tm = TM_EQ; break;\n    case OP_LT: tm = TM_LT; break;\n    case OP_LE: tm = TM_LE; break;\n    default:\n      return NULL;  /* cannot find a reasonable name */\n  }\n  *name = getstr(G(L)->tmname[tm]);\n  return \"metamethod\";\n}\n\n/* }====================================================== */\n\n\n\n/*\n** The subtraction of two potentially unrelated pointers is\n** not ISO C, but it should not crash a program; the subsequent\n** checks are ISO C and ensure a correct result.\n*/\nstatic int isinstack (CallInfo *ci, const TValue *o) {\n  ptrdiff_t i = o - ci->u.l.base;\n  return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o);\n}\n\n\n/*\n** Checks whether value 'o' came from an upvalue. (That can only happen\n** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on\n** upvalues.)\n*/\nstatic const char *getupvalname (CallInfo *ci, const TValue *o,\n                                 const char **name) {\n  LClosure *c = ci_func(ci);\n  int i;\n  for (i = 0; i < c->nupvalues; i++) {\n    if (c->upvals[i]->v == o) {\n      *name = upvalname(c->p, i);\n      return \"upvalue\";\n    }\n  }\n  return NULL;\n}\n\n\nstatic const char *varinfo (lua_State *L, const TValue *o) {\n  const char *name = NULL;  /* to avoid warnings */\n  CallInfo *ci = L->ci;\n  const char *kind = NULL;\n  if (isLua(ci)) {\n    kind = getupvalname(ci, o, &name);  /* check whether 'o' is an upvalue */\n    if (!kind && isinstack(ci, o))  /* no? try a register */\n      kind = getobjname(ci_func(ci)->p, currentpc(ci),\n                        cast_int(o - ci->u.l.base), &name);\n  }\n  return (kind) ? luaO_pushfstring(L, \" (%s '%s')\", kind, name) : \"\";\n}\n\n\nl_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {\n  const char *t = luaT_objtypename(L, o);\n  luaG_runerror(L, \"attempt to %s a %s value%s\", op, t, varinfo(L, o));\n}\n\n\nl_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {\n  if (ttisstring(p1) || cvt2str(p1)) p1 = p2;\n  luaG_typeerror(L, p1, \"concatenate\");\n}\n\n\nl_noret luaG_opinterror (lua_State *L, const TValue *p1,\n                         const TValue *p2, const char *msg) {\n  lua_Number temp;\n  if (!tonumber(p1, &temp))  /* first operand is wrong? */\n    p2 = p1;  /* now second is wrong */\n  luaG_typeerror(L, p2, msg);\n}\n\n\n/*\n** Error when both values are convertible to numbers, but not to integers\n*/\nl_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {\n  lua_Integer temp;\n  if (!tointeger(p1, &temp))\n    p2 = p1;\n  luaG_runerror(L, \"number%s has no integer representation\", varinfo(L, p2));\n}\n\n\nl_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {\n  const char *t1 = luaT_objtypename(L, p1);\n  const char *t2 = luaT_objtypename(L, p2);\n  if (strcmp(t1, t2) == 0)\n    luaG_runerror(L, \"attempt to compare two %s values\", t1);\n  else\n    luaG_runerror(L, \"attempt to compare %s with %s\", t1, t2);\n}\n\n\n/* add src:line information to 'msg' */\nconst char *luaG_addinfo (lua_State *L, const char *msg, TString *src,\n                                        int line) {\n  char buff[LUA_IDSIZE];\n  if (src)\n    luaO_chunkid(buff, getstr(src), LUA_IDSIZE);\n  else {  /* no source available; use \"?\" instead */\n    buff[0] = '?'; buff[1] = '\\0';\n  }\n  return luaO_pushfstring(L, \"%s:%d: %s\", buff, line, msg);\n}\n\n\nl_noret luaG_errormsg (lua_State *L) {\n  if (L->errfunc != 0) {  /* is there an error handling function? */\n    StkId errfunc = restorestack(L, L->errfunc);\n    setobjs2s(L, L->top, L->top - 1);  /* move argument */\n    setobjs2s(L, L->top - 1, errfunc);  /* push function */\n    L->top++;  /* assume EXTRA_STACK */\n    luaD_callnoyield(L, L->top - 2, 1);  /* call it */\n  }\n  luaD_throw(L, LUA_ERRRUN);\n}\n\n\nl_noret luaG_runerror (lua_State *L, const char *fmt, ...) {\n  CallInfo *ci = L->ci;\n  const char *msg;\n  va_list argp;\n  luaC_checkGC(L);  /* error message uses memory */\n  va_start(argp, fmt);\n  msg = luaO_pushvfstring(L, fmt, argp);  /* format message */\n  va_end(argp);\n  if (isLua(ci))  /* if Lua function, add source:line information */\n    luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));\n  luaG_errormsg(L);\n}\n\n\nvoid luaG_traceexec (lua_State *L) {\n  CallInfo *ci = L->ci;\n  lu_byte mask = L->hookmask;\n  int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));\n  if (counthook)\n    resethookcount(L);  /* reset count */\n  else if (!(mask & LUA_MASKLINE))\n    return;  /* no line hook and count != 0; nothing to be done */\n  if (ci->callstatus & CIST_HOOKYIELD) {  /* called hook last time? */\n    ci->callstatus &= ~CIST_HOOKYIELD;  /* erase mark */\n    return;  /* do not call hook again (VM yielded, so it did not move) */\n  }\n  if (counthook)\n    luaD_hook(L, LUA_HOOKCOUNT, -1);  /* call count hook */\n  if (mask & LUA_MASKLINE) {\n    Proto *p = ci_func(ci)->p;\n    int npc = pcRel(ci->u.l.savedpc, p);\n    int newline = getfuncline(p, npc);\n    if (npc == 0 ||  /* call linehook when enter a new function, */\n        ci->u.l.savedpc <= L->oldpc ||  /* when jump back (loop), or when */\n        newline != getfuncline(p, pcRel(L->oldpc, p)))  /* enter a new line */\n      luaD_hook(L, LUA_HOOKLINE, newline);  /* call line hook */\n  }\n  L->oldpc = ci->u.l.savedpc;\n  if (L->status == LUA_YIELD) {  /* did hook yield? */\n    if (counthook)\n      L->hookcount = 1;  /* undo decrement to zero */\n    ci->u.l.savedpc--;  /* undo increment (resume will increment it again) */\n    ci->callstatus |= CIST_HOOKYIELD;  /* mark that it yielded */\n    ci->func = L->top - 1;  /* protect stack below results */\n    luaD_throw(L, LUA_YIELD);\n  }\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ldebug.h",
    "content": "/*\n** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $\n** Auxiliary functions from Debug Interface module\n** See Copyright Notice in lua.h\n*/\n\n#ifndef ldebug_h\n#define ldebug_h\n\n\n#include \"lstate.h\"\n\n\n#define pcRel(pc, p)\t(cast(int, (pc) - (p)->code) - 1)\n\n#define getfuncline(f,pc)\t(((f)->lineinfo) ? (f)->lineinfo[pc] : -1)\n\n#define resethookcount(L)\t(L->hookcount = L->basehookcount)\n\n\nLUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,\n                                                const char *opname);\nLUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,\n                                                  const TValue *p2);\nLUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1,\n                                                 const TValue *p2,\n                                                 const char *msg);\nLUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,\n                                                 const TValue *p2);\nLUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,\n                                                 const TValue *p2);\nLUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);\nLUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,\n                                                  TString *src, int line);\nLUAI_FUNC l_noret luaG_errormsg (lua_State *L);\nLUAI_FUNC void luaG_traceexec (lua_State *L);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ldo.c",
    "content": "/*\n** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $\n** Stack and Call structure of Lua\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 6011)\n#pragma warning(disable: 4244)\n#define ldo_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <setjmp.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lapi.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lgc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lopcodes.h\"\n#include \"lparser.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n#include \"lundump.h\"\n#include \"lvm.h\"\n#include \"lzio.h\"\n\n\n\n#define errorstatus(s)\t((s) > LUA_YIELD)\n\n\n/*\n** {======================================================\n** Error-recovery functions\n** =======================================================\n*/\n\n/*\n** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By\n** default, Lua handles errors with exceptions when compiling as\n** C++ code, with _longjmp/_setjmp when asked to use them, and with\n** longjmp/setjmp otherwise.\n*/\n#if !defined(LUAI_THROW)\t\t\t\t/* { */\n\n#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)\t/* { */\n\n/* C++ exceptions */\n#define LUAI_THROW(L,c)\t\tthrow(c)\n#define LUAI_TRY(L,c,a) \\\n\ttry { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }\n#define luai_jmpbuf\t\tint  /* dummy variable */\n\n#elif defined(LUA_USE_POSIX)\t\t\t\t/* }{ */\n\n/* in POSIX, try _longjmp/_setjmp (more efficient) */\n#define LUAI_THROW(L,c)\t\t_longjmp((c)->b, 1)\n#define LUAI_TRY(L,c,a)\t\tif (_setjmp((c)->b) == 0) { a }\n#define luai_jmpbuf\t\tjmp_buf\n\n#else\t\t\t\t\t\t\t/* }{ */\n\n/* ISO C handling with long jumps */\n#define LUAI_THROW(L,c)\t\tlongjmp((c)->b, 1)\n#define LUAI_TRY(L,c,a)\t\tif (setjmp((c)->b) == 0) { a }\n#define luai_jmpbuf\t\tjmp_buf\n\n#endif\t\t\t\t\t\t\t/* } */\n\n#endif\t\t\t\t\t\t\t/* } */\n\n\n\n/* chain list of long jump buffers */\nstruct lua_longjmp {\n  struct lua_longjmp *previous;\n  luai_jmpbuf b;\n  volatile int status;  /* error code */\n};\n\n\nstatic void seterrorobj (lua_State *L, int errcode, StkId oldtop) {\n  switch (errcode) {\n    case LUA_ERRMEM: {  /* memory error? */\n      setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */\n      break;\n    }\n    case LUA_ERRERR: {\n      setsvalue2s(L, oldtop, luaS_newliteral(L, \"error in error handling\"));\n      break;\n    }\n    default: {\n      setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */\n      break;\n    }\n  }\n  L->top = oldtop + 1;\n}\n\n\nl_noret luaD_throw (lua_State *L, int errcode) {\n  if (L->errorJmp) {  /* thread has an error handler? */\n    L->errorJmp->status = errcode;  /* set status */\n    LUAI_THROW(L, L->errorJmp);  /* jump to it */\n  }\n  else {  /* thread has no error handler */\n    global_State *g = G(L);\n    L->status = cast_byte(errcode);  /* mark it as dead */\n    if (g->mainthread->errorJmp) {  /* main thread has a handler? */\n      setobjs2s(L, g->mainthread->top++, L->top - 1);  /* copy error obj. */\n      luaD_throw(g->mainthread, errcode);  /* re-throw in main thread */\n    }\n    else {  /* no handler at all; abort */\n      if (g->panic) {  /* panic function? */\n        seterrorobj(L, errcode, L->top);  /* assume EXTRA_STACK */\n        if (L->ci->top < L->top)\n          L->ci->top = L->top;  /* pushing msg. can break this invariant */\n        lua_unlock(L);\n        g->panic(L);  /* call panic function (last chance to jump out) */\n      }\n      abort();\n    }\n  }\n}\n\n\nint luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {\n  unsigned short oldnCcalls = L->nCcalls;\n  struct lua_longjmp lj;\n  lj.status = LUA_OK;\n  lj.previous = L->errorJmp;  /* chain new error handler */\n  L->errorJmp = &lj;\n  LUAI_TRY(L, &lj,\n    (*f)(L, ud);\n  );\n  L->errorJmp = lj.previous;  /* restore old error handler */\n  L->nCcalls = oldnCcalls;\n  return lj.status;\n}\n\n/* }====================================================== */\n\n\n/*\n** {==================================================================\n** Stack reallocation\n** ===================================================================\n*/\nstatic void correctstack (lua_State *L, TValue *oldstack) {\n  CallInfo *ci;\n  UpVal *up;\n  L->top = (L->top - oldstack) + L->stack;\n  for (up = L->openupval; up != NULL; up = up->u.open.next)\n    up->v = (up->v - oldstack) + L->stack;\n  for (ci = L->ci; ci != NULL; ci = ci->previous) {\n    ci->top = (ci->top - oldstack) + L->stack;\n    ci->func = (ci->func - oldstack) + L->stack;\n    if (isLua(ci))\n      ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;\n  }\n}\n\n\n/* some space for error handling */\n#define ERRORSTACKSIZE\t(LUAI_MAXSTACK + 200)\n\n\nvoid luaD_reallocstack (lua_State *L, int newsize) {\n  TValue *oldstack = L->stack;\n  int lim = L->stacksize;\n  lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);\n  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);\n  luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);\n  for (; lim < newsize; lim++)\n    setnilvalue(L->stack + lim); /* erase new segment */\n  L->stacksize = newsize;\n  L->stack_last = L->stack + newsize - EXTRA_STACK;\n  correctstack(L, oldstack);\n}\n\n\nvoid luaD_growstack (lua_State *L, int n) {\n  int size = L->stacksize;\n  if (size > LUAI_MAXSTACK)  /* error after extra size? */\n    luaD_throw(L, LUA_ERRERR);\n  else {\n    int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;\n    int newsize = 2 * size;\n    if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;\n    if (newsize < needed) newsize = needed;\n    if (newsize > LUAI_MAXSTACK) {  /* stack overflow? */\n      luaD_reallocstack(L, ERRORSTACKSIZE);\n      luaG_runerror(L, \"stack overflow\");\n    }\n    else\n      luaD_reallocstack(L, newsize);\n  }\n}\n\n\nstatic int stackinuse (lua_State *L) {\n  CallInfo *ci;\n  StkId lim = L->top;\n  for (ci = L->ci; ci != NULL; ci = ci->previous) {\n    if (lim < ci->top) lim = ci->top;\n  }\n  lua_assert(lim <= L->stack_last);\n  return cast_int(lim - L->stack) + 1;  /* part of stack in use */\n}\n\n\nvoid luaD_shrinkstack (lua_State *L) {\n  int inuse = stackinuse(L);\n  int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;\n  if (goodsize > LUAI_MAXSTACK)\n    goodsize = LUAI_MAXSTACK;  /* respect stack limit */\n  if (L->stacksize > LUAI_MAXSTACK)  /* had been handling stack overflow? */\n    luaE_freeCI(L);  /* free all CIs (list grew because of an error) */\n  else\n    luaE_shrinkCI(L);  /* shrink list */\n  /* if thread is currently not handling a stack overflow and its\n     good size is smaller than current size, shrink its stack */\n  if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&\n      goodsize < L->stacksize)\n    luaD_reallocstack(L, goodsize);\n  else  /* don't change stack */\n    condmovestack(L,{},{});  /* (change only for debugging) */\n}\n\n\nvoid luaD_inctop (lua_State *L) {\n  luaD_checkstack(L, 1);\n  L->top++;\n}\n\n/* }================================================================== */\n\n\n/*\n** Call a hook for the given event. Make sure there is a hook to be\n** called. (Both 'L->hook' and 'L->hookmask', which triggers this\n** function, can be changed asynchronously by signals.)\n*/\nvoid luaD_hook (lua_State *L, int event, int line) {\n  lua_Hook hook = L->hook;\n  if (hook && L->allowhook) {  /* make sure there is a hook */\n    CallInfo *ci = L->ci;\n    ptrdiff_t top = savestack(L, L->top);\n    ptrdiff_t ci_top = savestack(L, ci->top);\n    lua_Debug ar;\n    ar.event = event;\n    ar.currentline = line;\n    ar.i_ci = ci;\n    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */\n    ci->top = L->top + LUA_MINSTACK;\n    lua_assert(ci->top <= L->stack_last);\n    L->allowhook = 0;  /* cannot call hooks inside a hook */\n    ci->callstatus |= CIST_HOOKED;\n    lua_unlock(L);\n    (*hook)(L, &ar);\n    lua_lock(L);\n    lua_assert(!L->allowhook);\n    L->allowhook = 1;\n    ci->top = restorestack(L, ci_top);\n    L->top = restorestack(L, top);\n    ci->callstatus &= ~CIST_HOOKED;\n  }\n}\n\n\nstatic void callhook (lua_State *L, CallInfo *ci) {\n  int hook = LUA_HOOKCALL;\n  ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */\n  if (isLua(ci->previous) &&\n      GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {\n    ci->callstatus |= CIST_TAIL;\n    hook = LUA_HOOKTAILCALL;\n  }\n  luaD_hook(L, hook, -1);\n  ci->u.l.savedpc--;  /* correct 'pc' */\n}\n\n\nstatic StkId adjust_varargs (lua_State *L, Proto *p, int actual) {\n  int i;\n  int nfixargs = p->numparams;\n  StkId base, fixed;\n  /* move fixed parameters to final position */\n  fixed = L->top - actual;  /* first fixed argument */\n  base = L->top;  /* final position of first argument */\n  for (i = 0; i < nfixargs && i < actual; i++) {\n    setobjs2s(L, L->top++, fixed + i);\n    setnilvalue(fixed + i);  /* erase original copy (for GC) */\n  }\n  for (; i < nfixargs; i++)\n    setnilvalue(L->top++);  /* complete missing arguments */\n  return base;\n}\n\n\n/*\n** Check whether __call metafield of 'func' is a function. If so, put\n** it in stack below original 'func' so that 'luaD_precall' can call\n** it. Raise an error if __call metafield is not a function.\n*/\nstatic void tryfuncTM (lua_State *L, StkId func) {\n  const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);\n  StkId p;\n  if (!ttisfunction(tm))\n    luaG_typeerror(L, func, \"call\");\n  /* Open a hole inside the stack at 'func' */\n  for (p = L->top; p > func; p--)\n    setobjs2s(L, p, p-1);\n  L->top++;  /* slot ensured by caller */\n  setobj2s(L, func, tm);  /* tag method is the new function to be called */\n}\n\n\n/*\n** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.\n** Handle most typical cases (zero results for commands, one result for\n** expressions, multiple results for tail calls/single parameters)\n** separated.\n*/\nstatic int moveresults (lua_State *L, const TValue *firstResult, StkId res,\n                                      int nres, int wanted) {\n  switch (wanted) {  /* handle typical cases separately */\n    case 0: break;  /* nothing to move */\n    case 1: {  /* one result needed */\n      if (nres == 0)   /* no results? */\n        firstResult = luaO_nilobject;  /* adjust with nil */\n      setobjs2s(L, res, firstResult);  /* move it to proper place */\n      break;\n    }\n    case LUA_MULTRET: {\n      int i;\n      for (i = 0; i < nres; i++)  /* move all results to correct place */\n        setobjs2s(L, res + i, firstResult + i);\n      L->top = res + nres;\n      return 0;  /* wanted == LUA_MULTRET */\n    }\n    default: {\n      int i;\n      if (wanted <= nres) {  /* enough results? */\n        for (i = 0; i < wanted; i++)  /* move wanted results to correct place */\n          setobjs2s(L, res + i, firstResult + i);\n      }\n      else {  /* not enough results; use all of them plus nils */\n        for (i = 0; i < nres; i++)  /* move all results to correct place */\n          setobjs2s(L, res + i, firstResult + i);\n        for (; i < wanted; i++)  /* complete wanted number of results */\n          setnilvalue(res + i);\n      }\n      break;\n    }\n  }\n  L->top = res + wanted;  /* top points after the last result */\n  return 1;\n}\n\n\n/*\n** Finishes a function call: calls hook if necessary, removes CallInfo,\n** moves current number of results to proper place; returns 0 iff call\n** wanted multiple (variable number of) results.\n*/\nint luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {\n  StkId res;\n  int wanted = ci->nresults;\n  if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {\n    if (L->hookmask & LUA_MASKRET) {\n      ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */\n      luaD_hook(L, LUA_HOOKRET, -1);\n      firstResult = restorestack(L, fr);\n    }\n    L->oldpc = ci->previous->u.l.savedpc;  /* 'oldpc' for caller function */\n  }\n  res = ci->func;  /* res == final position of 1st result */\n  L->ci = ci->previous;  /* back to caller */\n  /* move results to proper place */\n  return moveresults(L, firstResult, res, nres, wanted);\n}\n\n\n\n#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))\n\n\n/* macro to check stack size, preserving 'p' */\n#define checkstackp(L,n,p)  \\\n  luaD_checkstackaux(L, n, \\\n    ptrdiff_t t__ = savestack(L, p);  /* save 'p' */ \\\n    luaC_checkGC(L),  /* stack grow uses memory */ \\\n    p = restorestack(L, t__))  /* 'pos' part: restore 'p' */\n\n\n/*\n** Prepares a function call: checks the stack, creates a new CallInfo\n** entry, fills in the relevant information, calls hook if needed.\n** If function is a C function, does the call, too. (Otherwise, leave\n** the execution ('luaV_execute') to the caller, to allow stackless\n** calls.) Returns true iff function has been executed (C function).\n*/\nint luaD_precall (lua_State *L, StkId func, int nresults) {\n  lua_CFunction f;\n  CallInfo *ci;\n  switch (ttype(func)) {\n    case LUA_TCCL:  /* C closure */\n      f = clCvalue(func)->f;\n      goto Cfunc;\n    case LUA_TLCF:  /* light C function */\n      f = fvalue(func);\n     Cfunc: {\n      int n;  /* number of returns */\n      checkstackp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */\n      ci = next_ci(L);  /* now 'enter' new function */\n      ci->nresults = nresults;\n      ci->func = func;\n      ci->top = L->top + LUA_MINSTACK;\n      lua_assert(ci->top <= L->stack_last);\n      ci->callstatus = 0;\n      if (L->hookmask & LUA_MASKCALL)\n        luaD_hook(L, LUA_HOOKCALL, -1);\n      lua_unlock(L);\n      n = (*f)(L);  /* do the actual call */\n      lua_lock(L);\n      api_checknelems(L, n);\n      luaD_poscall(L, ci, L->top - n, n);\n      return 1;\n    }\n    case LUA_TLCL: {  /* Lua function: prepare its call */\n      StkId base;\n      Proto *p = clLvalue(func)->p;\n      int n = cast_int(L->top - func) - 1;  /* number of real arguments */\n      int fsize = p->maxstacksize;  /* frame size */\n      checkstackp(L, fsize, func);\n      if (p->is_vararg)\n        base = adjust_varargs(L, p, n);\n      else {  /* non vararg function */\n        for (; n < p->numparams; n++)\n          setnilvalue(L->top++);  /* complete missing arguments */\n        base = func + 1;\n      }\n      ci = next_ci(L);  /* now 'enter' new function */\n      ci->nresults = nresults;\n      ci->func = func;\n      ci->u.l.base = base;\n      L->top = ci->top = base + fsize;\n      lua_assert(ci->top <= L->stack_last);\n      ci->u.l.savedpc = p->code;  /* starting point */\n      ci->callstatus = CIST_LUA;\n      if (L->hookmask & LUA_MASKCALL)\n        callhook(L, ci);\n      return 0;\n    }\n    default: {  /* not a function */\n      checkstackp(L, 1, func);  /* ensure space for metamethod */\n      tryfuncTM(L, func);  /* try to get '__call' metamethod */\n      return luaD_precall(L, func, nresults);  /* now it must be a function */\n    }\n  }\n}\n\n\n/*\n** Check appropriate error for stack overflow (\"regular\" overflow or\n** overflow while handling stack overflow). If 'nCalls' is larger than\n** LUAI_MAXCCALLS (which means it is handling a \"regular\" overflow) but\n** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to\n** allow overflow handling to work)\n*/\nstatic void stackerror (lua_State *L) {\n  if (L->nCcalls == LUAI_MAXCCALLS)\n    luaG_runerror(L, \"C stack overflow\");\n  else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))\n    luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */\n}\n\n\n/*\n** Call a function (C or Lua). The function to be called is at *func.\n** The arguments are on the stack, right after the function.\n** When returns, all the results are on the stack, starting at the original\n** function position.\n*/\nvoid luaD_call (lua_State *L, StkId func, int nResults) {\n  if (++L->nCcalls >= LUAI_MAXCCALLS)\n    stackerror(L);\n  if (!luaD_precall(L, func, nResults))  /* is a Lua function? */\n    luaV_execute(L);  /* call it */\n  L->nCcalls--;\n}\n\n\n/*\n** Similar to 'luaD_call', but does not allow yields during the call\n*/\nvoid luaD_callnoyield (lua_State *L, StkId func, int nResults) {\n  L->nny++;\n  luaD_call(L, func, nResults);\n  L->nny--;\n}\n\n\n/*\n** Completes the execution of an interrupted C function, calling its\n** continuation function.\n*/\nstatic void finishCcall (lua_State *L, int status) {\n  CallInfo *ci = L->ci;\n  int n;\n  /* must have a continuation and must be able to call it */\n  lua_assert(ci->u.c.k != NULL && L->nny == 0);\n  /* error status can only happen in a protected call */\n  lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);\n  if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */\n    ci->callstatus &= ~CIST_YPCALL;  /* continuation is also inside it */\n    L->errfunc = ci->u.c.old_errfunc;  /* with the same error function */\n  }\n  /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already\n     handled */\n  adjustresults(L, ci->nresults);\n  lua_unlock(L);\n  n = (*ci->u.c.k)(L, status, ci->u.c.ctx);  /* call continuation function */\n  lua_lock(L);\n  api_checknelems(L, n);\n  luaD_poscall(L, ci, L->top - n, n);  /* finish 'luaD_precall' */\n}\n\n\n/*\n** Executes \"full continuation\" (everything in the stack) of a\n** previously interrupted coroutine until the stack is empty (or another\n** interruption long-jumps out of the loop). If the coroutine is\n** recovering from an error, 'ud' points to the error status, which must\n** be passed to the first continuation function (otherwise the default\n** status is LUA_YIELD).\n*/\nstatic void unroll (lua_State *L, void *ud) {\n  if (ud != NULL)  /* error status? */\n    finishCcall(L, *(int *)ud);  /* finish 'lua_pcallk' callee */\n  while (L->ci != &L->base_ci) {  /* something in the stack */\n    if (!isLua(L->ci))  /* C function? */\n      finishCcall(L, LUA_YIELD);  /* complete its execution */\n    else {  /* Lua function */\n      luaV_finishOp(L);  /* finish interrupted instruction */\n      luaV_execute(L);  /* execute down to higher C 'boundary' */\n    }\n  }\n}\n\n\n/*\n** Try to find a suspended protected call (a \"recover point\") for the\n** given thread.\n*/\nstatic CallInfo *findpcall (lua_State *L) {\n  CallInfo *ci;\n  for (ci = L->ci; ci != NULL; ci = ci->previous) {  /* search for a pcall */\n    if (ci->callstatus & CIST_YPCALL)\n      return ci;\n  }\n  return NULL;  /* no pending pcall */\n}\n\n\n/*\n** Recovers from an error in a coroutine. Finds a recover point (if\n** there is one) and completes the execution of the interrupted\n** 'luaD_pcall'. If there is no recover point, returns zero.\n*/\nstatic int recover (lua_State *L, int status) {\n  StkId oldtop;\n  CallInfo *ci = findpcall(L);\n  if (ci == NULL) return 0;  /* no recovery point */\n  /* \"finish\" luaD_pcall */\n  oldtop = restorestack(L, ci->extra);\n  luaF_close(L, oldtop);\n  seterrorobj(L, status, oldtop);\n  L->ci = ci;\n  L->allowhook = getoah(ci->callstatus);  /* restore original 'allowhook' */\n  L->nny = 0;  /* should be zero to be yieldable */\n  luaD_shrinkstack(L);\n  L->errfunc = ci->u.c.old_errfunc;\n  return 1;  /* continue running the coroutine */\n}\n\n\n/*\n** Signal an error in the call to 'lua_resume', not in the execution\n** of the coroutine itself. (Such errors should not be handled by any\n** coroutine error handler and should not kill the coroutine.)\n*/\nstatic int resume_error (lua_State *L, const char *msg, int narg) {\n  L->top -= narg;  /* remove args from the stack */\n  setsvalue2s(L, L->top, luaS_new(L, msg));  /* push error message */\n  api_incr_top(L);\n  lua_unlock(L);\n  return LUA_ERRRUN;\n}\n\n\n/*\n** Do the work for 'lua_resume' in protected mode. Most of the work\n** depends on the status of the coroutine: initial state, suspended\n** inside a hook, or regularly suspended (optionally with a continuation\n** function), plus erroneous cases: non-suspended coroutine or dead\n** coroutine.\n*/\nstatic void resume (lua_State *L, void *ud) {\n  int n = *(cast(int*, ud));  /* number of arguments */\n  StkId firstArg = L->top - n;  /* first argument */\n  CallInfo *ci = L->ci;\n  if (L->status == LUA_OK) {  /* starting a coroutine? */\n    if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */\n      luaV_execute(L);  /* call it */\n  }\n  else {  /* resuming from previous yield */\n    lua_assert(L->status == LUA_YIELD);\n    L->status = LUA_OK;  /* mark that it is running (again) */\n    ci->func = restorestack(L, ci->extra);\n    if (isLua(ci))  /* yielded inside a hook? */\n      luaV_execute(L);  /* just continue running Lua code */\n    else {  /* 'common' yield */\n      if (ci->u.c.k != NULL) {  /* does it have a continuation function? */\n        lua_unlock(L);\n        n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */\n        lua_lock(L);\n        api_checknelems(L, n);\n        firstArg = L->top - n;  /* yield results come from continuation */\n      }\n      luaD_poscall(L, ci, firstArg, n);  /* finish 'luaD_precall' */\n    }\n    unroll(L, NULL);  /* run continuation */\n  }\n}\n\n\nLUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {\n  int status;\n  unsigned short oldnny = L->nny;  /* save \"number of non-yieldable\" calls */\n  lua_lock(L);\n  if (L->status == LUA_OK) {  /* may be starting a coroutine */\n    if (L->ci != &L->base_ci)  /* not in base level? */\n      return resume_error(L, \"cannot resume non-suspended coroutine\", nargs);\n  }\n  else if (L->status != LUA_YIELD)\n    return resume_error(L, \"cannot resume dead coroutine\", nargs);\n  L->nCcalls = (from) ? from->nCcalls + 1 : 1;\n  if (L->nCcalls >= LUAI_MAXCCALLS)\n    return resume_error(L, \"C stack overflow\", nargs);\n  luai_userstateresume(L, nargs);\n  L->nny = 0;  /* allow yields */\n  api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);\n  status = luaD_rawrunprotected(L, resume, &nargs);\n  if (status == -1)  /* error calling 'lua_resume'? */\n    status = LUA_ERRRUN;\n  else {  /* continue running after recoverable errors */\n    while (errorstatus(status) && recover(L, status)) {\n      /* unroll continuation */\n      status = luaD_rawrunprotected(L, unroll, &status);\n    }\n    if (errorstatus(status)) {  /* unrecoverable error? */\n      L->status = cast_byte(status);  /* mark thread as 'dead' */\n      seterrorobj(L, status, L->top);  /* push error message */\n      L->ci->top = L->top;\n    }\n    else lua_assert(status == L->status);  /* normal end or yield */\n  }\n  L->nny = oldnny;  /* restore 'nny' */\n  L->nCcalls--;\n  lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));\n  lua_unlock(L);\n  return status;\n}\n\n\nLUA_API int lua_isyieldable (lua_State *L) {\n  return (L->nny == 0);\n}\n\n\nLUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,\n                        lua_KFunction k) {\n  CallInfo *ci = L->ci;\n  luai_userstateyield(L, nresults);\n  lua_lock(L);\n  api_checknelems(L, nresults);\n  if (L->nny > 0) {\n    if (L != G(L)->mainthread)\n      luaG_runerror(L, \"attempt to yield across a C-call boundary\");\n    else\n      luaG_runerror(L, \"attempt to yield from outside a coroutine\");\n  }\n  L->status = LUA_YIELD;\n  ci->extra = savestack(L, ci->func);  /* save current 'func' */\n  if (isLua(ci)) {  /* inside a hook? */\n    api_check(L, k == NULL, \"hooks cannot continue after yielding\");\n  }\n  else {\n    if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */\n      ci->u.c.ctx = ctx;  /* save context */\n    ci->func = L->top - nresults - 1;  /* protect stack below results */\n    luaD_throw(L, LUA_YIELD);\n  }\n  lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */\n  lua_unlock(L);\n  return 0;  /* return to 'luaD_hook' */\n}\n\n\nint luaD_pcall (lua_State *L, Pfunc func, void *u,\n                ptrdiff_t old_top, ptrdiff_t ef) {\n  int status;\n  CallInfo *old_ci = L->ci;\n  lu_byte old_allowhooks = L->allowhook;\n  unsigned short old_nny = L->nny;\n  ptrdiff_t old_errfunc = L->errfunc;\n  L->errfunc = ef;\n  status = luaD_rawrunprotected(L, func, u);\n  if (status != LUA_OK) {  /* an error occurred? */\n    StkId oldtop = restorestack(L, old_top);\n    luaF_close(L, oldtop);  /* close possible pending closures */\n    seterrorobj(L, status, oldtop);\n    L->ci = old_ci;\n    L->allowhook = old_allowhooks;\n    L->nny = old_nny;\n    luaD_shrinkstack(L);\n  }\n  L->errfunc = old_errfunc;\n  return status;\n}\n\n\n\n/*\n** Execute a protected parser.\n*/\nstruct SParser {  /* data to 'f_parser' */\n  ZIO *z;\n  Mbuffer buff;  /* dynamic structure used by the scanner */\n  Dyndata dyd;  /* dynamic structures used by the parser */\n  const char *mode;\n  const char *name;\n};\n\n\nstatic void checkmode (lua_State *L, const char *mode, const char *x) {\n  if (mode && strchr(mode, x[0]) == NULL) {\n    luaO_pushfstring(L,\n       \"attempt to load a %s chunk (mode is '%s')\", x, mode);\n    luaD_throw(L, LUA_ERRSYNTAX);\n  }\n}\n\n\nstatic void f_parser (lua_State *L, void *ud) {\n  LClosure *cl;\n  struct SParser *p = cast(struct SParser *, ud);\n  int c = zgetc(p->z);  /* read first character */\n  if (c == LUA_SIGNATURE[0]) {\n    checkmode(L, p->mode, \"binary\");\n    cl = luaU_undump(L, p->z, p->name);\n  }\n  else {\n    checkmode(L, p->mode, \"text\");\n    cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);\n  }\n  lua_assert(cl->nupvalues == cl->p->sizeupvalues);\n  luaF_initupvals(L, cl);\n}\n\n\nint luaD_protectedparser (lua_State *L, ZIO *z, const char *name,\n                                        const char *mode) {\n  struct SParser p;\n  int status;\n  L->nny++;  /* cannot yield during parsing */\n  p.z = z; p.name = name; p.mode = mode;\n  p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;\n  p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;\n  p.dyd.label.arr = NULL; p.dyd.label.size = 0;\n  luaZ_initbuffer(L, &p.buff);\n  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);\n  luaZ_freebuffer(L, &p.buff);\n  luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);\n  luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);\n  luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);\n  L->nny--;\n  return status;\n}\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ldo.h",
    "content": "/*\n** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $\n** Stack and Call structure of Lua\n** See Copyright Notice in lua.h\n*/\n\n#ifndef ldo_h\n#define ldo_h\n\n\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lzio.h\"\n\n\n/*\n** Macro to check stack size and grow stack if needed.  Parameters\n** 'pre'/'pos' allow the macro to preserve a pointer into the\n** stack across reallocations, doing the work only when needed.\n** 'condmovestack' is used in heavy tests to force a stack reallocation\n** at every check.\n*/\n#define luaD_checkstackaux(L,n,pre,pos)  \\\n\tif (L->stack_last - L->top <= (n)) \\\n\t  { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }\n\n/* In general, 'pre'/'pos' are empty (nothing to save) */\n#define luaD_checkstack(L,n)\tluaD_checkstackaux(L,n,(void)0,(void)0)\n\n\n\n#define savestack(L,p)\t\t((char *)(p) - (char *)L->stack)\n#define restorestack(L,n)\t((TValue *)((char *)L->stack + (n)))\n\n\n/* type of protected functions, to be ran by 'runprotected' */\ntypedef void (*Pfunc) (lua_State *L, void *ud);\n\nLUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,\n                                                  const char *mode);\nLUAI_FUNC void luaD_hook (lua_State *L, int event, int line);\nLUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);\nLUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);\nLUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);\nLUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,\n                                        ptrdiff_t oldtop, ptrdiff_t ef);\nLUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,\n                                          int nres);\nLUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);\nLUAI_FUNC void luaD_growstack (lua_State *L, int n);\nLUAI_FUNC void luaD_shrinkstack (lua_State *L);\nLUAI_FUNC void luaD_inctop (lua_State *L);\n\nLUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);\nLUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ldump.c",
    "content": "/*\n** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $\n** save precompiled Lua chunks\n** See Copyright Notice in lua.h\n*/\n\n#define ldump_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stddef.h>\n\n#include \"lua.h\"\n\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lundump.h\"\n\n\ntypedef struct {\n  lua_State *L;\n  lua_Writer writer;\n  void *data;\n  int strip;\n  int status;\n} DumpState;\n\n\n/*\n** All high-level dumps go through DumpVector; you can change it to\n** change the endianness of the result\n*/\n#define DumpVector(v,n,D)\tDumpBlock(v,(n)*sizeof((v)[0]),D)\n\n#define DumpLiteral(s,D)\tDumpBlock(s, sizeof(s) - sizeof(char), D)\n\n\nstatic void DumpBlock (const void *b, size_t size, DumpState *D) {\n  if (D->status == 0 && size > 0) {\n    lua_unlock(D->L);\n    D->status = (*D->writer)(D->L, b, size, D->data);\n    lua_lock(D->L);\n  }\n}\n\n\n#define DumpVar(x,D)\t\tDumpVector(&x,1,D)\n\n\nstatic void DumpByte (int y, DumpState *D) {\n  lu_byte x = (lu_byte)y;\n  DumpVar(x, D);\n}\n\n\nstatic void DumpInt (int x, DumpState *D) {\n  DumpVar(x, D);\n}\n\n\nstatic void DumpNumber (lua_Number x, DumpState *D) {\n  DumpVar(x, D);\n}\n\n\nstatic void DumpInteger (lua_Integer x, DumpState *D) {\n  DumpVar(x, D);\n}\n\n\nstatic void DumpString (const TString *s, DumpState *D) {\n  if (s == NULL)\n    DumpByte(0, D);\n  else {\n    size_t size = tsslen(s) + 1;  /* include trailing '\\0' */\n    const char *str = getstr(s);\n    if (size < 0xFF)\n      DumpByte(cast_int(size), D);\n    else {\n      DumpByte(0xFF, D);\n      DumpVar(size, D);\n    }\n    DumpVector(str, size - 1, D);  /* no need to save '\\0' */\n  }\n}\n\n\nstatic void DumpCode (const Proto *f, DumpState *D) {\n  DumpInt(f->sizecode, D);\n  DumpVector(f->code, f->sizecode, D);\n}\n\n\nstatic void DumpFunction(const Proto *f, TString *psource, DumpState *D);\n\nstatic void DumpConstants (const Proto *f, DumpState *D) {\n  int i;\n  int n = f->sizek;\n  DumpInt(n, D);\n  for (i = 0; i < n; i++) {\n    const TValue *o = &f->k[i];\n    DumpByte(ttype(o), D);\n    switch (ttype(o)) {\n    case LUA_TNIL:\n      break;\n    case LUA_TBOOLEAN:\n      DumpByte(bvalue(o), D);\n      break;\n    case LUA_TNUMFLT:\n      DumpNumber(fltvalue(o), D);\n      break;\n    case LUA_TNUMINT:\n      DumpInteger(ivalue(o), D);\n      break;\n    case LUA_TSHRSTR:\n    case LUA_TLNGSTR:\n      DumpString(tsvalue(o), D);\n      break;\n    default:\n      lua_assert(0);\n    }\n  }\n}\n\n\nstatic void DumpProtos (const Proto *f, DumpState *D) {\n  int i;\n  int n = f->sizep;\n  DumpInt(n, D);\n  for (i = 0; i < n; i++)\n    DumpFunction(f->p[i], f->source, D);\n}\n\n\nstatic void DumpUpvalues (const Proto *f, DumpState *D) {\n  int i, n = f->sizeupvalues;\n  DumpInt(n, D);\n  for (i = 0; i < n; i++) {\n    DumpByte(f->upvalues[i].instack, D);\n    DumpByte(f->upvalues[i].idx, D);\n  }\n}\n\n\nstatic void DumpDebug (const Proto *f, DumpState *D) {\n  int i, n;\n  n = (D->strip) ? 0 : f->sizelineinfo;\n  DumpInt(n, D);\n  DumpVector(f->lineinfo, n, D);\n  n = (D->strip) ? 0 : f->sizelocvars;\n  DumpInt(n, D);\n  for (i = 0; i < n; i++) {\n    DumpString(f->locvars[i].varname, D);\n    DumpInt(f->locvars[i].startpc, D);\n    DumpInt(f->locvars[i].endpc, D);\n  }\n  n = (D->strip) ? 0 : f->sizeupvalues;\n  DumpInt(n, D);\n  for (i = 0; i < n; i++)\n    DumpString(f->upvalues[i].name, D);\n}\n\n\nstatic void DumpFunction (const Proto *f, TString *psource, DumpState *D) {\n  if (D->strip || f->source == psource)\n    DumpString(NULL, D);  /* no debug info or same source as its parent */\n  else\n    DumpString(f->source, D);\n  DumpInt(f->linedefined, D);\n  DumpInt(f->lastlinedefined, D);\n  DumpByte(f->numparams, D);\n  DumpByte(f->is_vararg, D);\n  DumpByte(f->maxstacksize, D);\n  DumpCode(f, D);\n  DumpConstants(f, D);\n  DumpUpvalues(f, D);\n  DumpProtos(f, D);\n  DumpDebug(f, D);\n}\n\n\nstatic void DumpHeader (DumpState *D) {\n  DumpLiteral(LUA_SIGNATURE, D);\n  DumpByte(LUAC_VERSION, D);\n  DumpByte(LUAC_FORMAT, D);\n  DumpLiteral(LUAC_DATA, D);\n  DumpByte(sizeof(int), D);\n  DumpByte(sizeof(size_t), D);\n  DumpByte(sizeof(Instruction), D);\n  DumpByte(sizeof(lua_Integer), D);\n  DumpByte(sizeof(lua_Number), D);\n  DumpInteger(LUAC_INT, D);\n  DumpNumber(LUAC_NUM, D);\n}\n\n\n/*\n** dump Lua function as precompiled chunk\n*/\nint luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,\n              int strip) {\n  DumpState D;\n  D.L = L;\n  D.writer = w;\n  D.data = data;\n  D.strip = strip;\n  D.status = 0;\n  DumpHeader(&D);\n  DumpByte(f->sizeupvalues, &D);\n  DumpFunction(f, NULL, &D);\n  return D.status;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lfunc.c",
    "content": "/*\n** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $\n** Auxiliary functions to manipulate prototypes and closures\n** See Copyright Notice in lua.h\n*/\n\n#define lfunc_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stddef.h>\n\n#include \"lua.h\"\n\n#include \"lfunc.h\"\n#include \"lgc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n\n\n\nCClosure *luaF_newCclosure (lua_State *L, int n) {\n  GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n));\n  CClosure *c = gco2ccl(o);\n  c->nupvalues = cast_byte(n);\n  return c;\n}\n\n\nLClosure *luaF_newLclosure (lua_State *L, int n) {\n  GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n));\n  LClosure *c = gco2lcl(o);\n  c->p = NULL;\n  c->nupvalues = cast_byte(n);\n  while (n--) c->upvals[n] = NULL;\n  return c;\n}\n\n/*\n** fill a closure with new closed upvalues\n*/\nvoid luaF_initupvals (lua_State *L, LClosure *cl) {\n  int i;\n  for (i = 0; i < cl->nupvalues; i++) {\n    UpVal *uv = luaM_new(L, UpVal);\n    uv->refcount = 1;\n    uv->v = &uv->u.value;  /* make it closed */\n    setnilvalue(uv->v);\n    cl->upvals[i] = uv;\n  }\n}\n\n\nUpVal *luaF_findupval (lua_State *L, StkId level) {\n  UpVal **pp = &L->openupval;\n  UpVal *p;\n  UpVal *uv;\n  lua_assert(isintwups(L) || L->openupval == NULL);\n  while (*pp != NULL && (p = *pp)->v >= level) {\n    lua_assert(upisopen(p));\n    if (p->v == level)  /* found a corresponding upvalue? */\n      return p;  /* return it */\n    pp = &p->u.open.next;\n  }\n  /* not found: create a new upvalue */\n  uv = luaM_new(L, UpVal);\n  uv->refcount = 0;\n  uv->u.open.next = *pp;  /* link it to list of open upvalues */\n  uv->u.open.touched = 1;\n  *pp = uv;\n  uv->v = level;  /* current value lives in the stack */\n  if (!isintwups(L)) {  /* thread not in list of threads with upvalues? */\n    L->twups = G(L)->twups;  /* link it to the list */\n    G(L)->twups = L;\n  }\n  return uv;\n}\n\n\nvoid luaF_close (lua_State *L, StkId level) {\n  UpVal *uv;\n  while (L->openupval != NULL && (uv = L->openupval)->v >= level) {\n    lua_assert(upisopen(uv));\n    L->openupval = uv->u.open.next;  /* remove from 'open' list */\n    if (uv->refcount == 0)  /* no references? */\n      luaM_free(L, uv);  /* free upvalue */\n    else {\n      setobj(L, &uv->u.value, uv->v);  /* move value to upvalue slot */\n      uv->v = &uv->u.value;  /* now current value lives here */\n      luaC_upvalbarrier(L, uv);\n    }\n  }\n}\n\n\nProto *luaF_newproto (lua_State *L) {\n  GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));\n  Proto *f = gco2p(o);\n  f->k = NULL;\n  f->sizek = 0;\n  f->p = NULL;\n  f->sizep = 0;\n  f->code = NULL;\n  f->cache = NULL;\n  f->sizecode = 0;\n  f->lineinfo = NULL;\n  f->sizelineinfo = 0;\n  f->upvalues = NULL;\n  f->sizeupvalues = 0;\n  f->numparams = 0;\n  f->is_vararg = 0;\n  f->maxstacksize = 0;\n  f->locvars = NULL;\n  f->sizelocvars = 0;\n  f->linedefined = 0;\n  f->lastlinedefined = 0;\n  f->source = NULL;\n  return f;\n}\n\n\nvoid luaF_freeproto (lua_State *L, Proto *f) {\n  luaM_freearray(L, f->code, f->sizecode);\n  luaM_freearray(L, f->p, f->sizep);\n  luaM_freearray(L, f->k, f->sizek);\n  luaM_freearray(L, f->lineinfo, f->sizelineinfo);\n  luaM_freearray(L, f->locvars, f->sizelocvars);\n  luaM_freearray(L, f->upvalues, f->sizeupvalues);\n  luaM_free(L, f);\n}\n\n\n/*\n** Look for n-th local variable at line 'line' in function 'func'.\n** Returns NULL if not found.\n*/\nconst char *luaF_getlocalname (const Proto *f, int local_number, int pc) {\n  int i;\n  for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {\n    if (pc < f->locvars[i].endpc) {  /* is variable active? */\n      local_number--;\n      if (local_number == 0)\n        return getstr(f->locvars[i].varname);\n    }\n  }\n  return NULL;  /* not found */\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lfunc.h",
    "content": "/*\n** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $\n** Auxiliary functions to manipulate prototypes and closures\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lfunc_h\n#define lfunc_h\n\n\n#include \"lobject.h\"\n\n\n#define sizeCclosure(n)\t(cast(int, sizeof(CClosure)) + \\\n                         cast(int, sizeof(TValue)*((n)-1)))\n\n#define sizeLclosure(n)\t(cast(int, sizeof(LClosure)) + \\\n                         cast(int, sizeof(TValue *)*((n)-1)))\n\n\n/* test whether thread is in 'twups' list */\n#define isintwups(L)\t(L->twups != L)\n\n\n/*\n** maximum number of upvalues in a closure (both C and Lua). (Value\n** must fit in a VM register.)\n*/\n#define MAXUPVAL\t255\n\n\n/*\n** Upvalues for Lua closures\n*/\nstruct UpVal {\n  TValue *v;  /* points to stack or to its own value */\n  lu_mem refcount;  /* reference counter */\n  union {\n    struct {  /* (when open) */\n      UpVal *next;  /* linked list */\n      int touched;  /* mark to avoid cycles with dead threads */\n    } open;\n    TValue value;  /* the value (when closed) */\n  } u;\n};\n\n#define upisopen(up)\t((up)->v != &(up)->u.value)\n\n\nLUAI_FUNC Proto *luaF_newproto (lua_State *L);\nLUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);\nLUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);\nLUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);\nLUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);\nLUAI_FUNC void luaF_close (lua_State *L, StkId level);\nLUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);\nLUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,\n                                         int pc);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lgc.c",
    "content": "/*\n** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $\n** Garbage Collector\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 6297)\n#define lgc_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lgc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n\n\n/*\n** internal state for collector while inside the atomic phase. The\n** collector should never be in this state while running regular code.\n*/\n#define GCSinsideatomic\t\t(GCSpause + 1)\n\n/*\n** cost of sweeping one element (the size of a small object divided\n** by some adjust for the sweep speed)\n*/\n#define GCSWEEPCOST\t((sizeof(TString) + 4) / 4)\n\n/* maximum number of elements to sweep in each single step */\n#define GCSWEEPMAX\t(cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))\n\n/* cost of calling one finalizer */\n#define GCFINALIZECOST\tGCSWEEPCOST\n\n\n/*\n** macro to adjust 'stepmul': 'stepmul' is actually used like\n** 'stepmul / STEPMULADJ' (value chosen by tests)\n*/\n#define STEPMULADJ\t\t200\n\n\n/*\n** macro to adjust 'pause': 'pause' is actually used like\n** 'pause / PAUSEADJ' (value chosen by tests)\n*/\n#define PAUSEADJ\t\t100\n\n\n/*\n** 'makewhite' erases all color bits then sets only the current white\n** bit\n*/\n#define maskcolors\t(~(bitmask(BLACKBIT) | WHITEBITS))\n#define makewhite(g,x)\t\\\n (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))\n\n#define white2gray(x)\tresetbits(x->marked, WHITEBITS)\n#define black2gray(x)\tresetbit(x->marked, BLACKBIT)\n\n\n#define valiswhite(x)   (iscollectable(x) && iswhite(gcvalue(x)))\n\n#define checkdeadkey(n)\tlua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))\n\n\n#define checkconsistency(obj)  \\\n  lua_longassert(!iscollectable(obj) || righttt(obj))\n\n\n#define markvalue(g,o) { checkconsistency(o); \\\n  if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }\n\n#define markobject(g,t)\t{ if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }\n\n/*\n** mark an object that can be NULL (either because it is really optional,\n** or it was stripped as debug info, or inside an uncompleted structure)\n*/\n#define markobjectN(g,t)\t{ if (t) markobject(g,t); }\n\nstatic void reallymarkobject (global_State *g, GCObject *o);\n\n\n/*\n** {======================================================\n** Generic functions\n** =======================================================\n*/\n\n\n/*\n** one after last element in a hash array\n*/\n#define gnodelast(h)\tgnode(h, cast(size_t, sizenode(h)))\n\n\n/*\n** link collectable object 'o' into list pointed by 'p'\n*/\n#define linkgclist(o,p)\t((o)->gclist = (p), (p) = obj2gco(o))\n\n\n/*\n** If key is not marked, mark its entry as dead. This allows key to be\n** collected, but keeps its entry in the table.  A dead node is needed\n** when Lua looks up for a key (it may be part of a chain) and when\n** traversing a weak table (key might be removed from the table during\n** traversal). Other places never manipulate dead keys, because its\n** associated nil value is enough to signal that the entry is logically\n** empty.\n*/\nstatic void removeentry (Node *n) {\n  lua_assert(ttisnil(gval(n)));\n  if (valiswhite(gkey(n)))\n    setdeadvalue(wgkey(n));  /* unused and unmarked key; remove it */\n}\n\n\n/*\n** tells whether a key or value can be cleared from a weak\n** table. Non-collectable objects are never removed from weak\n** tables. Strings behave as 'values', so are never removed too. for\n** other objects: if really collected, cannot keep them; for objects\n** being finalized, keep them in keys, but not in values\n*/\nstatic int iscleared (global_State *g, const TValue *o) {\n  if (!iscollectable(o)) return 0;\n  else if (ttisstring(o)) {\n    markobject(g, tsvalue(o));  /* strings are 'values', so are never weak */\n    return 0;\n  }\n  else return iswhite(gcvalue(o));\n}\n\n\n/*\n** barrier that moves collector forward, that is, mark the white object\n** being pointed by a black object. (If in sweep phase, clear the black\n** object to white [sweep it] to avoid other barrier calls for this\n** same object.)\n*/\nvoid luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {\n  global_State *g = G(L);\n  lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));\n  if (keepinvariant(g))  /* must keep invariant? */\n    reallymarkobject(g, v);  /* restore invariant */\n  else {  /* sweep phase */\n    lua_assert(issweepphase(g));\n    makewhite(g, o);  /* mark main obj. as white to avoid other barriers */\n  }\n}\n\n\n/*\n** barrier that moves collector backward, that is, mark the black object\n** pointing to a white object as gray again.\n*/\nvoid luaC_barrierback_ (lua_State *L, Table *t) {\n  global_State *g = G(L);\n  lua_assert(isblack(t) && !isdead(g, t));\n  black2gray(t);  /* make table gray (again) */\n  linkgclist(t, g->grayagain);\n}\n\n\n/*\n** barrier for assignments to closed upvalues. Because upvalues are\n** shared among closures, it is impossible to know the color of all\n** closures pointing to it. So, we assume that the object being assigned\n** must be marked.\n*/\nvoid luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {\n  global_State *g = G(L);\n  GCObject *o = gcvalue(uv->v);\n  lua_assert(!upisopen(uv));  /* ensured by macro luaC_upvalbarrier */\n  if (keepinvariant(g))\n    markobject(g, o);\n}\n\n\nvoid luaC_fix (lua_State *L, GCObject *o) {\n  global_State *g = G(L);\n  lua_assert(g->allgc == o);  /* object must be 1st in 'allgc' list! */\n  white2gray(o);  /* they will be gray forever */\n  g->allgc = o->next;  /* remove object from 'allgc' list */\n  o->next = g->fixedgc;  /* link it to 'fixedgc' list */\n  g->fixedgc = o;\n}\n\n\n/*\n** create a new collectable object (with given type and size) and link\n** it to 'allgc' list.\n*/\nGCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {\n  global_State *g = G(L);\n  GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));\n  o->marked = luaC_white(g);\n  o->tt = tt;\n  o->next = g->allgc;\n  g->allgc = o;\n  return o;\n}\n\n/* }====================================================== */\n\n\n\n/*\n** {======================================================\n** Mark functions\n** =======================================================\n*/\n\n\n/*\n** mark an object. Userdata, strings, and closed upvalues are visited\n** and turned black here. Other objects are marked gray and added\n** to appropriate list to be visited (and turned black) later. (Open\n** upvalues are already linked in 'headuv' list.)\n*/\nstatic void reallymarkobject (global_State *g, GCObject *o) {\n reentry:\n  white2gray(o);\n  switch (o->tt) {\n    case LUA_TSHRSTR: {\n      gray2black(o);\n      g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);\n      break;\n    }\n    case LUA_TLNGSTR: {\n      gray2black(o);\n      g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);\n      break;\n    }\n    case LUA_TUSERDATA: {\n      TValue uvalue;\n      markobjectN(g, gco2u(o)->metatable);  /* mark its metatable */\n      gray2black(o);\n      g->GCmemtrav += sizeudata(gco2u(o));\n      getuservalue(g->mainthread, gco2u(o), &uvalue);\n      if (valiswhite(&uvalue)) {  /* markvalue(g, &uvalue); */\n        o = gcvalue(&uvalue);\n        goto reentry;\n      }\n      break;\n    }\n    case LUA_TLCL: {\n      linkgclist(gco2lcl(o), g->gray);\n      break;\n    }\n    case LUA_TCCL: {\n      linkgclist(gco2ccl(o), g->gray);\n      break;\n    }\n    case LUA_TTABLE: {\n      linkgclist(gco2t(o), g->gray);\n      break;\n    }\n    case LUA_TTHREAD: {\n      linkgclist(gco2th(o), g->gray);\n      break;\n    }\n    case LUA_TPROTO: {\n      linkgclist(gco2p(o), g->gray);\n      break;\n    }\n    default: lua_assert(0); break;\n  }\n}\n\n\n/*\n** mark metamethods for basic types\n*/\nstatic void markmt (global_State *g) {\n  int i;\n  for (i=0; i < LUA_NUMTAGS; i++)\n    markobjectN(g, g->mt[i]);\n}\n\n\n/*\n** mark all objects in list of being-finalized\n*/\nstatic void markbeingfnz (global_State *g) {\n  GCObject *o;\n  for (o = g->tobefnz; o != NULL; o = o->next)\n    markobject(g, o);\n}\n\n\n/*\n** Mark all values stored in marked open upvalues from non-marked threads.\n** (Values from marked threads were already marked when traversing the\n** thread.) Remove from the list threads that no longer have upvalues and\n** not-marked threads.\n*/\nstatic void remarkupvals (global_State *g) {\n  lua_State *thread;\n  lua_State **p = &g->twups;\n  while ((thread = *p) != NULL) {\n    lua_assert(!isblack(thread));  /* threads are never black */\n    if (isgray(thread) && thread->openupval != NULL)\n      p = &thread->twups;  /* keep marked thread with upvalues in the list */\n    else {  /* thread is not marked or without upvalues */\n      UpVal *uv;\n      *p = thread->twups;  /* remove thread from the list */\n      thread->twups = thread;  /* mark that it is out of list */\n      for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {\n        if (uv->u.open.touched) {\n          markvalue(g, uv->v);  /* remark upvalue's value */\n          uv->u.open.touched = 0;\n        }\n      }\n    }\n  }\n}\n\n\n/*\n** mark root set and reset all gray lists, to start a new collection\n*/\nstatic void restartcollection (global_State *g) {\n  g->gray = g->grayagain = NULL;\n  g->weak = g->allweak = g->ephemeron = NULL;\n  markobject(g, g->mainthread);\n  markvalue(g, &g->l_registry);\n  markmt(g);\n  markbeingfnz(g);  /* mark any finalizing object left from previous cycle */\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Traverse functions\n** =======================================================\n*/\n\n/*\n** Traverse a table with weak values and link it to proper list. During\n** propagate phase, keep it in 'grayagain' list, to be revisited in the\n** atomic phase. In the atomic phase, if table has any white value,\n** put it in 'weak' list, to be cleared.\n*/\nstatic void traverseweakvalue (global_State *g, Table *h) {\n  Node *n, *limit = gnodelast(h);\n  /* if there is array part, assume it may have white values (it is not\n     worth traversing it now just to check) */\n  int hasclears = (h->sizearray > 0);\n  for (n = gnode(h, 0); n < limit; n++) {  /* traverse hash part */\n    checkdeadkey(n);\n    if (ttisnil(gval(n)))  /* entry is empty? */\n      removeentry(n);  /* remove it */\n    else {\n      lua_assert(!ttisnil(gkey(n)));\n      markvalue(g, gkey(n));  /* mark key */\n      if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */\n        hasclears = 1;  /* table will have to be cleared */\n    }\n  }\n  if (g->gcstate == GCSpropagate)\n    linkgclist(h, g->grayagain);  /* must retraverse it in atomic phase */\n  else if (hasclears)\n    linkgclist(h, g->weak);  /* has to be cleared later */\n}\n\n\n/*\n** Traverse an ephemeron table and link it to proper list. Returns true\n** iff any object was marked during this traversal (which implies that\n** convergence has to continue). During propagation phase, keep table\n** in 'grayagain' list, to be visited again in the atomic phase. In\n** the atomic phase, if table has any white->white entry, it has to\n** be revisited during ephemeron convergence (as that key may turn\n** black). Otherwise, if it has any white key, table has to be cleared\n** (in the atomic phase).\n*/\nstatic int traverseephemeron (global_State *g, Table *h) {\n  int marked = 0;  /* true if an object is marked in this traversal */\n  int hasclears = 0;  /* true if table has white keys */\n  int hasww = 0;  /* true if table has entry \"white-key -> white-value\" */\n  Node *n, *limit = gnodelast(h);\n  unsigned int i;\n  /* traverse array part */\n  for (i = 0; i < h->sizearray; i++) {\n    if (valiswhite(&h->array[i])) {\n      marked = 1;\n      reallymarkobject(g, gcvalue(&h->array[i]));\n    }\n  }\n  /* traverse hash part */\n  for (n = gnode(h, 0); n < limit; n++) {\n    checkdeadkey(n);\n    if (ttisnil(gval(n)))  /* entry is empty? */\n      removeentry(n);  /* remove it */\n    else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */\n      hasclears = 1;  /* table must be cleared */\n      if (valiswhite(gval(n)))  /* value not marked yet? */\n        hasww = 1;  /* white-white entry */\n    }\n    else if (valiswhite(gval(n))) {  /* value not marked yet? */\n      marked = 1;\n      reallymarkobject(g, gcvalue(gval(n)));  /* mark it now */\n    }\n  }\n  /* link table into proper list */\n  if (g->gcstate == GCSpropagate)\n    linkgclist(h, g->grayagain);  /* must retraverse it in atomic phase */\n  else if (hasww)  /* table has white->white entries? */\n    linkgclist(h, g->ephemeron);  /* have to propagate again */\n  else if (hasclears)  /* table has white keys? */\n    linkgclist(h, g->allweak);  /* may have to clean white keys */\n  return marked;\n}\n\n\nstatic void traversestrongtable (global_State *g, Table *h) {\n  Node *n, *limit = gnodelast(h);\n  unsigned int i;\n  for (i = 0; i < h->sizearray; i++)  /* traverse array part */\n    markvalue(g, &h->array[i]);\n  for (n = gnode(h, 0); n < limit; n++) {  /* traverse hash part */\n    checkdeadkey(n);\n    if (ttisnil(gval(n)))  /* entry is empty? */\n      removeentry(n);  /* remove it */\n    else {\n      lua_assert(!ttisnil(gkey(n)));\n      markvalue(g, gkey(n));  /* mark key */\n      markvalue(g, gval(n));  /* mark value */\n    }\n  }\n}\n\n\nstatic lu_mem traversetable (global_State *g, Table *h) {\n  const char *weakkey, *weakvalue;\n  const TValue *mode = gfasttm(g, h->metatable, TM_MODE);\n  markobjectN(g, h->metatable);\n  if (mode && ttisstring(mode) &&  /* is there a weak mode? */\n      ((weakkey = strchr(svalue(mode), 'k')),\n       (weakvalue = strchr(svalue(mode), 'v')),\n       (weakkey || weakvalue))) {  /* is really weak? */\n    black2gray(h);  /* keep table gray */\n    if (!weakkey)  /* strong keys? */\n      traverseweakvalue(g, h);\n    else if (!weakvalue)  /* strong values? */\n      traverseephemeron(g, h);\n    else  /* all weak */\n      linkgclist(h, g->allweak);  /* nothing to traverse now */\n  }\n  else  /* not weak */\n    traversestrongtable(g, h);\n  return sizeof(Table) + sizeof(TValue) * h->sizearray +\n                         sizeof(Node) * cast(size_t, allocsizenode(h));\n}\n\n\n/*\n** Traverse a prototype. (While a prototype is being build, its\n** arrays can be larger than needed; the extra slots are filled with\n** NULL, so the use of 'markobjectN')\n*/\nstatic int traverseproto (global_State *g, Proto *f) {\n  int i;\n  if (f->cache && iswhite(f->cache))\n    f->cache = NULL;  /* allow cache to be collected */\n  markobjectN(g, f->source);\n  for (i = 0; i < f->sizek; i++)  /* mark literals */\n    markvalue(g, &f->k[i]);\n  for (i = 0; i < f->sizeupvalues; i++)  /* mark upvalue names */\n    markobjectN(g, f->upvalues[i].name);\n  for (i = 0; i < f->sizep; i++)  /* mark nested protos */\n    markobjectN(g, f->p[i]);\n  for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */\n    markobjectN(g, f->locvars[i].varname);\n  return sizeof(Proto) + sizeof(Instruction) * f->sizecode +\n                         sizeof(Proto *) * f->sizep +\n                         sizeof(TValue) * f->sizek +\n                         sizeof(int) * f->sizelineinfo +\n                         sizeof(LocVar) * f->sizelocvars +\n                         sizeof(Upvaldesc) * f->sizeupvalues;\n}\n\n\nstatic lu_mem traverseCclosure (global_State *g, CClosure *cl) {\n  int i;\n  for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */\n    markvalue(g, &cl->upvalue[i]);\n  return sizeCclosure(cl->nupvalues);\n}\n\n/*\n** open upvalues point to values in a thread, so those values should\n** be marked when the thread is traversed except in the atomic phase\n** (because then the value cannot be changed by the thread and the\n** thread may not be traversed again)\n*/\nstatic lu_mem traverseLclosure (global_State *g, LClosure *cl) {\n  int i;\n  markobjectN(g, cl->p);  /* mark its prototype */\n  for (i = 0; i < cl->nupvalues; i++) {  /* mark its upvalues */\n    UpVal *uv = cl->upvals[i];\n    if (uv != NULL) {\n      if (upisopen(uv) && g->gcstate != GCSinsideatomic)\n        uv->u.open.touched = 1;  /* can be marked in 'remarkupvals' */\n      else\n        markvalue(g, uv->v);\n    }\n  }\n  return sizeLclosure(cl->nupvalues);\n}\n\n\nstatic lu_mem traversethread (global_State *g, lua_State *th) {\n  StkId o = th->stack;\n  if (o == NULL)\n    return 1;  /* stack not completely built yet */\n  lua_assert(g->gcstate == GCSinsideatomic ||\n             th->openupval == NULL || isintwups(th));\n  for (; o < th->top; o++)  /* mark live elements in the stack */\n    markvalue(g, o);\n  if (g->gcstate == GCSinsideatomic) {  /* final traversal? */\n    StkId lim = th->stack + th->stacksize;  /* real end of stack */\n    for (; o < lim; o++)  /* clear not-marked stack slice */\n      setnilvalue(o);\n    /* 'remarkupvals' may have removed thread from 'twups' list */\n    if (!isintwups(th) && th->openupval != NULL) {\n      th->twups = g->twups;  /* link it back to the list */\n      g->twups = th;\n    }\n  }\n  else if (g->gckind != KGC_EMERGENCY)\n    luaD_shrinkstack(th); /* do not change stack in emergency cycle */\n  return (sizeof(lua_State) + sizeof(TValue) * th->stacksize +\n          sizeof(CallInfo) * th->nci);\n}\n\n\n/*\n** traverse one gray object, turning it to black (except for threads,\n** which are always gray).\n*/\nstatic void propagatemark (global_State *g) {\n  lu_mem size;\n  GCObject *o = g->gray;\n  lua_assert(isgray(o));\n  gray2black(o);\n  switch (o->tt) {\n    case LUA_TTABLE: {\n      Table *h = gco2t(o);\n      g->gray = h->gclist;  /* remove from 'gray' list */\n      size = traversetable(g, h);\n      break;\n    }\n    case LUA_TLCL: {\n      LClosure *cl = gco2lcl(o);\n      g->gray = cl->gclist;  /* remove from 'gray' list */\n      size = traverseLclosure(g, cl);\n      break;\n    }\n    case LUA_TCCL: {\n      CClosure *cl = gco2ccl(o);\n      g->gray = cl->gclist;  /* remove from 'gray' list */\n      size = traverseCclosure(g, cl);\n      break;\n    }\n    case LUA_TTHREAD: {\n      lua_State *th = gco2th(o);\n      g->gray = th->gclist;  /* remove from 'gray' list */\n      linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */\n      black2gray(o);\n      size = traversethread(g, th);\n      break;\n    }\n    case LUA_TPROTO: {\n      Proto *p = gco2p(o);\n      g->gray = p->gclist;  /* remove from 'gray' list */\n      size = traverseproto(g, p);\n      break;\n    }\n    default: lua_assert(0); return;\n  }\n  g->GCmemtrav += size;\n}\n\n\nstatic void propagateall (global_State *g) {\n  while (g->gray) propagatemark(g);\n}\n\n\nstatic void convergeephemerons (global_State *g) {\n  int changed;\n  do {\n    GCObject *w;\n    GCObject *next = g->ephemeron;  /* get ephemeron list */\n    g->ephemeron = NULL;  /* tables may return to this list when traversed */\n    changed = 0;\n    while ((w = next) != NULL) {\n      next = gco2t(w)->gclist;\n      if (traverseephemeron(g, gco2t(w))) {  /* traverse marked some value? */\n        propagateall(g);  /* propagate changes */\n        changed = 1;  /* will have to revisit all ephemeron tables */\n      }\n    }\n  } while (changed);\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Sweep Functions\n** =======================================================\n*/\n\n\n/*\n** clear entries with unmarked keys from all weaktables in list 'l' up\n** to element 'f'\n*/\nstatic void clearkeys (global_State *g, GCObject *l, GCObject *f) {\n  for (; l != f; l = gco2t(l)->gclist) {\n    Table *h = gco2t(l);\n    Node *n, *limit = gnodelast(h);\n    for (n = gnode(h, 0); n < limit; n++) {\n      if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {\n        setnilvalue(gval(n));  /* remove value ... */\n      }\n      if (ttisnil(gval(n)))  /* is entry empty? */\n        removeentry(n);  /* remove entry from table */\n    }\n  }\n}\n\n\n/*\n** clear entries with unmarked values from all weaktables in list 'l' up\n** to element 'f'\n*/\nstatic void clearvalues (global_State *g, GCObject *l, GCObject *f) {\n  for (; l != f; l = gco2t(l)->gclist) {\n    Table *h = gco2t(l);\n    Node *n, *limit = gnodelast(h);\n    unsigned int i;\n    for (i = 0; i < h->sizearray; i++) {\n      TValue *o = &h->array[i];\n      if (iscleared(g, o))  /* value was collected? */\n        setnilvalue(o);  /* remove value */\n    }\n    for (n = gnode(h, 0); n < limit; n++) {\n      if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {\n        setnilvalue(gval(n));  /* remove value ... */\n        removeentry(n);  /* and remove entry from table */\n      }\n    }\n  }\n}\n\n\nvoid luaC_upvdeccount (lua_State *L, UpVal *uv) {\n  lua_assert(uv->refcount > 0);\n  uv->refcount--;\n  if (uv->refcount == 0 && !upisopen(uv))\n    luaM_free(L, uv);\n}\n\n\nstatic void freeLclosure (lua_State *L, LClosure *cl) {\n  int i;\n  for (i = 0; i < cl->nupvalues; i++) {\n    UpVal *uv = cl->upvals[i];\n    if (uv)\n      luaC_upvdeccount(L, uv);\n  }\n  luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));\n}\n\n\nstatic void freeobj (lua_State *L, GCObject *o) {\n  switch (o->tt) {\n    case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;\n    case LUA_TLCL: {\n      freeLclosure(L, gco2lcl(o));\n      break;\n    }\n    case LUA_TCCL: {\n      luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));\n      break;\n    }\n    case LUA_TTABLE: luaH_free(L, gco2t(o)); break;\n    case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;\n    case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;\n    case LUA_TSHRSTR:\n      luaS_remove(L, gco2ts(o));  /* remove it from hash table */\n      luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));\n      break;\n    case LUA_TLNGSTR: {\n      luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));\n      break;\n    }\n    default: lua_assert(0);\n  }\n}\n\n\n#define sweepwholelist(L,p)\tsweeplist(L,p,MAX_LUMEM)\nstatic GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);\n\n\n/*\n** sweep at most 'count' elements from a list of GCObjects erasing dead\n** objects, where a dead object is one marked with the old (non current)\n** white; change all non-dead objects back to white, preparing for next\n** collection cycle. Return where to continue the traversal or NULL if\n** list is finished.\n*/\nstatic GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {\n  global_State *g = G(L);\n  int ow = otherwhite(g);\n  int white = luaC_white(g);  /* current white */\n  while (*p != NULL && count-- > 0) {\n    GCObject *curr = *p;\n    int marked = curr->marked;\n    if (isdeadm(ow, marked)) {  /* is 'curr' dead? */\n      *p = curr->next;  /* remove 'curr' from list */\n      freeobj(L, curr);  /* erase 'curr' */\n    }\n    else {  /* change mark to 'white' */\n      curr->marked = cast_byte((marked & maskcolors) | white);\n      p = &curr->next;  /* go to next element */\n    }\n  }\n  return (*p == NULL) ? NULL : p;\n}\n\n\n/*\n** sweep a list until a live object (or end of list)\n*/\nstatic GCObject **sweeptolive (lua_State *L, GCObject **p) {\n  GCObject **old = p;\n  do {\n    p = sweeplist(L, p, 1);\n  } while (p == old);\n  return p;\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** Finalization\n** =======================================================\n*/\n\n/*\n** If possible, shrink string table\n*/\nstatic void checkSizes (lua_State *L, global_State *g) {\n  if (g->gckind != KGC_EMERGENCY) {\n    l_mem olddebt = g->GCdebt;\n    if (g->strt.nuse < g->strt.size / 4)  /* string table too big? */\n      luaS_resize(L, g->strt.size / 2);  /* shrink it a little */\n    g->GCestimate += g->GCdebt - olddebt;  /* update estimate */\n  }\n}\n\n\nstatic GCObject *udata2finalize (global_State *g) {\n  GCObject *o = g->tobefnz;  /* get first element */\n  lua_assert(tofinalize(o));\n  g->tobefnz = o->next;  /* remove it from 'tobefnz' list */\n  o->next = g->allgc;  /* return it to 'allgc' list */\n  g->allgc = o;\n  resetbit(o->marked, FINALIZEDBIT);  /* object is \"normal\" again */\n  if (issweepphase(g))\n    makewhite(g, o);  /* \"sweep\" object */\n  return o;\n}\n\n\nstatic void dothecall (lua_State *L, void *ud) {\n  UNUSED(ud);\n  luaD_callnoyield(L, L->top - 2, 0);\n}\n\n\nstatic void GCTM (lua_State *L, int propagateerrors) {\n  global_State *g = G(L);\n  const TValue *tm;\n  TValue v;\n  setgcovalue(L, &v, udata2finalize(g));\n  tm = luaT_gettmbyobj(L, &v, TM_GC);\n  if (tm != NULL && ttisfunction(tm)) {  /* is there a finalizer? */\n    int status;\n    lu_byte oldah = L->allowhook;\n    int running  = g->gcrunning;\n    L->allowhook = 0;  /* stop debug hooks during GC metamethod */\n    g->gcrunning = 0;  /* avoid GC steps */\n    setobj2s(L, L->top, tm);  /* push finalizer... */\n    setobj2s(L, L->top + 1, &v);  /* ... and its argument */\n    L->top += 2;  /* and (next line) call the finalizer */\n    L->ci->callstatus |= CIST_FIN;  /* will run a finalizer */\n    status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);\n    L->ci->callstatus &= ~CIST_FIN;  /* not running a finalizer anymore */\n    L->allowhook = oldah;  /* restore hooks */\n    g->gcrunning = running;  /* restore state */\n    if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */\n      if (status == LUA_ERRRUN) {  /* is there an error object? */\n        const char *msg = (ttisstring(L->top - 1))\n                            ? svalue(L->top - 1)\n                            : \"no message\";\n        luaO_pushfstring(L, \"error in __gc metamethod (%s)\", msg);\n        status = LUA_ERRGCMM;  /* error in __gc metamethod */\n      }\n      luaD_throw(L, status);  /* re-throw error */\n    }\n  }\n}\n\n\n/*\n** call a few (up to 'g->gcfinnum') finalizers\n*/\nstatic int runafewfinalizers (lua_State *L) {\n  global_State *g = G(L);\n  unsigned int i;\n  lua_assert(!g->tobefnz || g->gcfinnum > 0);\n  for (i = 0; g->tobefnz && i < g->gcfinnum; i++)\n    GCTM(L, 1);  /* call one finalizer */\n  g->gcfinnum = (!g->tobefnz) ? 0  /* nothing more to finalize? */\n                    : g->gcfinnum * 2;  /* else call a few more next time */\n  return i;\n}\n\n\n/*\n** call all pending finalizers\n*/\nstatic void callallpendingfinalizers (lua_State *L) {\n  global_State *g = G(L);\n  while (g->tobefnz)\n    GCTM(L, 0);\n}\n\n\n/*\n** find last 'next' field in list 'p' list (to add elements in its end)\n*/\nstatic GCObject **findlast (GCObject **p) {\n  while (*p != NULL)\n    p = &(*p)->next;\n  return p;\n}\n\n\n/*\n** move all unreachable objects (or 'all' objects) that need\n** finalization from list 'finobj' to list 'tobefnz' (to be finalized)\n*/\nstatic void separatetobefnz (global_State *g, int all) {\n  GCObject *curr;\n  GCObject **p = &g->finobj;\n  GCObject **lastnext = findlast(&g->tobefnz);\n  while ((curr = *p) != NULL) {  /* traverse all finalizable objects */\n    lua_assert(tofinalize(curr));\n    if (!(iswhite(curr) || all))  /* not being collected? */\n      p = &curr->next;  /* don't bother with it */\n    else {\n      *p = curr->next;  /* remove 'curr' from 'finobj' list */\n      curr->next = *lastnext;  /* link at the end of 'tobefnz' list */\n      *lastnext = curr;\n      lastnext = &curr->next;\n    }\n  }\n}\n\n\n/*\n** if object 'o' has a finalizer, remove it from 'allgc' list (must\n** search the list to find it) and link it in 'finobj' list.\n*/\nvoid luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {\n  global_State *g = G(L);\n  if (tofinalize(o) ||                 /* obj. is already marked... */\n      gfasttm(g, mt, TM_GC) == NULL)   /* or has no finalizer? */\n    return;  /* nothing to be done */\n  else {  /* move 'o' to 'finobj' list */\n    GCObject **p;\n    if (issweepphase(g)) {\n      makewhite(g, o);  /* \"sweep\" object 'o' */\n      if (g->sweepgc == &o->next)  /* should not remove 'sweepgc' object */\n        g->sweepgc = sweeptolive(L, g->sweepgc);  /* change 'sweepgc' */\n    }\n    /* search for pointer pointing to 'o' */\n    for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }\n    *p = o->next;  /* remove 'o' from 'allgc' list */\n    o->next = g->finobj;  /* link it in 'finobj' list */\n    g->finobj = o;\n    l_setbit(o->marked, FINALIZEDBIT);  /* mark it as such */\n  }\n}\n\n/* }====================================================== */\n\n\n\n/*\n** {======================================================\n** GC control\n** =======================================================\n*/\n\n\n/*\n** Set a reasonable \"time\" to wait before starting a new GC cycle; cycle\n** will start when memory use hits threshold. (Division by 'estimate'\n** should be OK: it cannot be zero (because Lua cannot even start with\n** less than PAUSEADJ bytes).\n*/\nstatic void setpause (global_State *g) {\n  l_mem threshold, debt;\n  l_mem estimate = g->GCestimate / PAUSEADJ;  /* adjust 'estimate' */\n  lua_assert(estimate > 0);\n  threshold = (g->gcpause < MAX_LMEM / estimate)  /* overflow? */\n            ? estimate * g->gcpause  /* no overflow */\n            : MAX_LMEM;  /* overflow; truncate to maximum */\n  debt = gettotalbytes(g) - threshold;\n  luaE_setdebt(g, debt);\n}\n\n\n/*\n** Enter first sweep phase.\n** The call to 'sweeplist' tries to make pointer point to an object\n** inside the list (instead of to the header), so that the real sweep do\n** not need to skip objects created between \"now\" and the start of the\n** real sweep.\n*/\nstatic void entersweep (lua_State *L) {\n  global_State *g = G(L);\n  g->gcstate = GCSswpallgc;\n  lua_assert(g->sweepgc == NULL);\n  g->sweepgc = sweeplist(L, &g->allgc, 1);\n}\n\n\nvoid luaC_freeallobjects (lua_State *L) {\n  global_State *g = G(L);\n  separatetobefnz(g, 1);  /* separate all objects with finalizers */\n  lua_assert(g->finobj == NULL);\n  callallpendingfinalizers(L);\n  lua_assert(g->tobefnz == NULL);\n  g->currentwhite = WHITEBITS; /* this \"white\" makes all objects look dead */\n  g->gckind = KGC_NORMAL;\n  sweepwholelist(L, &g->finobj);\n  sweepwholelist(L, &g->allgc);\n  sweepwholelist(L, &g->fixedgc);  /* collect fixed objects */\n  lua_assert(g->strt.nuse == 0);\n}\n\n\nstatic l_mem atomic (lua_State *L) {\n  global_State *g = G(L);\n  l_mem work;\n  GCObject *origweak, *origall;\n  GCObject *grayagain = g->grayagain;  /* save original list */\n  lua_assert(g->ephemeron == NULL && g->weak == NULL);\n  lua_assert(!iswhite(g->mainthread));\n  g->gcstate = GCSinsideatomic;\n  g->GCmemtrav = 0;  /* start counting work */\n  markobject(g, L);  /* mark running thread */\n  /* registry and global metatables may be changed by API */\n  markvalue(g, &g->l_registry);\n  markmt(g);  /* mark global metatables */\n  /* remark occasional upvalues of (maybe) dead threads */\n  remarkupvals(g);\n  propagateall(g);  /* propagate changes */\n  work = g->GCmemtrav;  /* stop counting (do not recount 'grayagain') */\n  g->gray = grayagain;\n  propagateall(g);  /* traverse 'grayagain' list */\n  g->GCmemtrav = 0;  /* restart counting */\n  convergeephemerons(g);\n  /* at this point, all strongly accessible objects are marked. */\n  /* Clear values from weak tables, before checking finalizers */\n  clearvalues(g, g->weak, NULL);\n  clearvalues(g, g->allweak, NULL);\n  origweak = g->weak; origall = g->allweak;\n  work += g->GCmemtrav;  /* stop counting (objects being finalized) */\n  separatetobefnz(g, 0);  /* separate objects to be finalized */\n  g->gcfinnum = 1;  /* there may be objects to be finalized */\n  markbeingfnz(g);  /* mark objects that will be finalized */\n  propagateall(g);  /* remark, to propagate 'resurrection' */\n  g->GCmemtrav = 0;  /* restart counting */\n  convergeephemerons(g);\n  /* at this point, all resurrected objects are marked. */\n  /* remove dead objects from weak tables */\n  clearkeys(g, g->ephemeron, NULL);  /* clear keys from all ephemeron tables */\n  clearkeys(g, g->allweak, NULL);  /* clear keys from all 'allweak' tables */\n  /* clear values from resurrected weak tables */\n  clearvalues(g, g->weak, origweak);\n  clearvalues(g, g->allweak, origall);\n  luaS_clearcache(g);\n  g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */\n  work += g->GCmemtrav;  /* complete counting */\n  return work;  /* estimate of memory marked by 'atomic' */\n}\n\n\nstatic lu_mem sweepstep (lua_State *L, global_State *g,\n                         int nextstate, GCObject **nextlist) {\n  if (g->sweepgc) {\n    l_mem olddebt = g->GCdebt;\n    g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);\n    g->GCestimate += g->GCdebt - olddebt;  /* update estimate */\n    if (g->sweepgc)  /* is there still something to sweep? */\n      return (GCSWEEPMAX * GCSWEEPCOST);\n  }\n  /* else enter next state */\n  g->gcstate = nextstate;\n  g->sweepgc = nextlist;\n  return 0;\n}\n\n\nstatic lu_mem singlestep (lua_State *L) {\n  global_State *g = G(L);\n  switch (g->gcstate) {\n    case GCSpause: {\n      g->GCmemtrav = g->strt.size * sizeof(GCObject*);\n      restartcollection(g);\n      g->gcstate = GCSpropagate;\n      return g->GCmemtrav;\n    }\n    case GCSpropagate: {\n      g->GCmemtrav = 0;\n      lua_assert(g->gray);\n      propagatemark(g);\n       if (g->gray == NULL)  /* no more gray objects? */\n        g->gcstate = GCSatomic;  /* finish propagate phase */\n      return g->GCmemtrav;  /* memory traversed in this step */\n    }\n    case GCSatomic: {\n      lu_mem work;\n      propagateall(g);  /* make sure gray list is empty */\n      work = atomic(L);  /* work is what was traversed by 'atomic' */\n      entersweep(L);\n      g->GCestimate = gettotalbytes(g);  /* first estimate */;\n      return work;\n    }\n    case GCSswpallgc: {  /* sweep \"regular\" objects */\n      return sweepstep(L, g, GCSswpfinobj, &g->finobj);\n    }\n    case GCSswpfinobj: {  /* sweep objects with finalizers */\n      return sweepstep(L, g, GCSswptobefnz, &g->tobefnz);\n    }\n    case GCSswptobefnz: {  /* sweep objects to be finalized */\n      return sweepstep(L, g, GCSswpend, NULL);\n    }\n    case GCSswpend: {  /* finish sweeps */\n      makewhite(g, g->mainthread);  /* sweep main thread */\n      checkSizes(L, g);\n      g->gcstate = GCScallfin;\n      return 0;\n    }\n    case GCScallfin: {  /* call remaining finalizers */\n      if (g->tobefnz && g->gckind != KGC_EMERGENCY) {\n        int n = runafewfinalizers(L);\n        return (n * GCFINALIZECOST);\n      }\n      else {  /* emergency mode or no more finalizers */\n        g->gcstate = GCSpause;  /* finish collection */\n        return 0;\n      }\n    }\n    default: lua_assert(0); return 0;\n  }\n}\n\n\n/*\n** advances the garbage collector until it reaches a state allowed\n** by 'statemask'\n*/\nvoid luaC_runtilstate (lua_State *L, int statesmask) {\n  global_State *g = G(L);\n  while (!testbit(statesmask, g->gcstate))\n    singlestep(L);\n}\n\n\n/*\n** get GC debt and convert it from Kb to 'work units' (avoid zero debt\n** and overflows)\n*/\nstatic l_mem getdebt (global_State *g) {\n  l_mem debt = g->GCdebt;\n  int stepmul = g->gcstepmul;\n  if (debt <= 0) return 0;  /* minimal debt */\n  else {\n    debt = (debt / STEPMULADJ) + 1;\n    debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;\n    return debt;\n  }\n}\n\n/*\n** performs a basic GC step when collector is running\n*/\nvoid luaC_step (lua_State *L) {\n  global_State *g = G(L);\n  l_mem debt = getdebt(g);  /* GC deficit (be paid now) */\n  if (!g->gcrunning) {  /* not running? */\n    luaE_setdebt(g, -GCSTEPSIZE * 10);  /* avoid being called too often */\n    return;\n  }\n  do {  /* repeat until pause or enough \"credit\" (negative debt) */\n    lu_mem work = singlestep(L);  /* perform one single step */\n    debt -= work;\n  } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);\n  if (g->gcstate == GCSpause)\n    setpause(g);  /* pause until next cycle */\n  else {\n    debt = (debt / g->gcstepmul) * STEPMULADJ;  /* convert 'work units' to Kb */\n    luaE_setdebt(g, debt);\n    runafewfinalizers(L);\n  }\n}\n\n\n/*\n** Performs a full GC cycle; if 'isemergency', set a flag to avoid\n** some operations which could change the interpreter state in some\n** unexpected ways (running finalizers and shrinking some structures).\n** Before running the collection, check 'keepinvariant'; if it is true,\n** there may be some objects marked as black, so the collector has\n** to sweep all objects to turn them back to white (as white has not\n** changed, nothing will be collected).\n*/\nvoid luaC_fullgc (lua_State *L, int isemergency) {\n  global_State *g = G(L);\n  lua_assert(g->gckind == KGC_NORMAL);\n  if (isemergency) g->gckind = KGC_EMERGENCY;  /* set flag */\n  if (keepinvariant(g)) {  /* black objects? */\n    entersweep(L); /* sweep everything to turn them back to white */\n  }\n  /* finish any pending sweep phase to start a new cycle */\n  luaC_runtilstate(L, bitmask(GCSpause));\n  luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */\n  luaC_runtilstate(L, bitmask(GCScallfin));  /* run up to finalizers */\n  /* estimate must be correct after a full GC cycle */\n  lua_assert(g->GCestimate == gettotalbytes(g));\n  luaC_runtilstate(L, bitmask(GCSpause));  /* finish collection */\n  g->gckind = KGC_NORMAL;\n  setpause(g);\n}\n\n/* }====================================================== */\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lgc.h",
    "content": "/*\n** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $\n** Garbage Collector\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lgc_h\n#define lgc_h\n\n\n#include \"lobject.h\"\n#include \"lstate.h\"\n\n/*\n** Collectable objects may have one of three colors: white, which\n** means the object is not marked; gray, which means the\n** object is marked, but its references may be not marked; and\n** black, which means that the object and all its references are marked.\n** The main invariant of the garbage collector, while marking objects,\n** is that a black object can never point to a white one. Moreover,\n** any gray object must be in a \"gray list\" (gray, grayagain, weak,\n** allweak, ephemeron) so that it can be visited again before finishing\n** the collection cycle. These lists have no meaning when the invariant\n** is not being enforced (e.g., sweep phase).\n*/\n\n\n\n/* how much to allocate before next GC step */\n#if !defined(GCSTEPSIZE)\n/* ~100 small strings */\n#define GCSTEPSIZE\t(cast_int(100 * sizeof(TString)))\n#endif\n\n\n/*\n** Possible states of the Garbage Collector\n*/\n#define GCSpropagate\t0\n#define GCSatomic\t1\n#define GCSswpallgc\t2\n#define GCSswpfinobj\t3\n#define GCSswptobefnz\t4\n#define GCSswpend\t5\n#define GCScallfin\t6\n#define GCSpause\t7\n\n\n#define issweepphase(g)  \\\n\t(GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)\n\n\n/*\n** macro to tell when main invariant (white objects cannot point to black\n** ones) must be kept. During a collection, the sweep\n** phase may break the invariant, as objects turned white may point to\n** still-black objects. The invariant is restored when sweep ends and\n** all objects are white again.\n*/\n\n#define keepinvariant(g)\t((g)->gcstate <= GCSatomic)\n\n\n/*\n** some useful bit tricks\n*/\n#define resetbits(x,m)\t\t((x) &= cast(lu_byte, ~(m)))\n#define setbits(x,m)\t\t((x) |= (m))\n#define testbits(x,m)\t\t((x) & (m))\n#define bitmask(b)\t\t(1<<(b))\n#define bit2mask(b1,b2)\t\t(bitmask(b1) | bitmask(b2))\n#define l_setbit(x,b)\t\tsetbits(x, bitmask(b))\n#define resetbit(x,b)\t\tresetbits(x, bitmask(b))\n#define testbit(x,b)\t\ttestbits(x, bitmask(b))\n\n\n/* Layout for bit use in 'marked' field: */\n#define WHITE0BIT\t0  /* object is white (type 0) */\n#define WHITE1BIT\t1  /* object is white (type 1) */\n#define BLACKBIT\t2  /* object is black */\n#define FINALIZEDBIT\t3  /* object has been marked for finalization */\n/* bit 7 is currently used by tests (luaL_checkmemory) */\n\n#define WHITEBITS\tbit2mask(WHITE0BIT, WHITE1BIT)\n\n\n#define iswhite(x)      testbits((x)->marked, WHITEBITS)\n#define isblack(x)      testbit((x)->marked, BLACKBIT)\n#define isgray(x)  /* neither white nor black */  \\\n\t(!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT)))\n\n#define tofinalize(x)\ttestbit((x)->marked, FINALIZEDBIT)\n\n#define otherwhite(g)\t((g)->currentwhite ^ WHITEBITS)\n#define isdeadm(ow,m)\t(!(((m) ^ WHITEBITS) & (ow)))\n#define isdead(g,v)\tisdeadm(otherwhite(g), (v)->marked)\n\n#define changewhite(x)\t((x)->marked ^= WHITEBITS)\n#define gray2black(x)\tl_setbit((x)->marked, BLACKBIT)\n\n#define luaC_white(g)\tcast(lu_byte, (g)->currentwhite & WHITEBITS)\n\n\n/*\n** Does one step of collection when debt becomes positive. 'pre'/'pos'\n** allows some adjustments to be done only when needed. macro\n** 'condchangemem' is used only for heavy tests (forcing a full\n** GC cycle on every opportunity)\n*/\n#define luaC_condGC(L,pre,pos) \\\n\t{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \\\n\t  condchangemem(L,pre,pos); }\n\n/* more often than not, 'pre'/'pos' are empty */\n#define luaC_checkGC(L)\t\tluaC_condGC(L,(void)0,(void)0)\n\n\n#define luaC_barrier(L,p,v) (  \\\n\t(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ?  \\\n\tluaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))\n\n#define luaC_barrierback(L,p,v) (  \\\n\t(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \\\n\tluaC_barrierback_(L,p) : cast_void(0))\n\n#define luaC_objbarrier(L,p,o) (  \\\n\t(isblack(p) && iswhite(o)) ? \\\n\tluaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))\n\n#define luaC_upvalbarrier(L,uv) ( \\\n\t(iscollectable((uv)->v) && !upisopen(uv)) ? \\\n         luaC_upvalbarrier_(L,uv) : cast_void(0))\n\nLUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);\nLUAI_FUNC void luaC_freeallobjects (lua_State *L);\nLUAI_FUNC void luaC_step (lua_State *L);\nLUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);\nLUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);\nLUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);\nLUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);\nLUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);\nLUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);\nLUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);\nLUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/linit.c",
    "content": "/*\n** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $\n** Initialization of libraries for lua.c and other clients\n** See Copyright Notice in lua.h\n*/\n\n\n#define linit_c\n#define LUA_LIB\n\n/*\n** If you embed Lua in your program and need to open the standard\n** libraries, call luaL_openlibs in your program. If you need a\n** different set of libraries, copy this file to your project and edit\n** it to suit your needs.\n**\n** You can also *preload* libraries, so that a later 'require' can\n** open the library, which is already linked to the application.\n** For that, do the following code:\n**\n**  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);\n**  lua_pushcfunction(L, luaopen_modname);\n**  lua_setfield(L, -2, modname);\n**  lua_pop(L, 1);  // remove PRELOAD table\n*/\n\n#include \"lprefix.h\"\n\n\n#include <stddef.h>\n\n#include \"lua.h\"\n\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n\n\n/*\n** these libs are loaded by lua.c and are readily available to any Lua\n** program\n*/\nstatic const luaL_Reg loadedlibs[] = {\n  {\"_G\", luaopen_base},\n  {LUA_LOADLIBNAME, luaopen_package},\n  {LUA_COLIBNAME, luaopen_coroutine},\n  {LUA_TABLIBNAME, luaopen_table},\n  {LUA_IOLIBNAME, luaopen_io},\n  {LUA_OSLIBNAME, luaopen_os},\n  {LUA_STRLIBNAME, luaopen_string},\n  {LUA_MATHLIBNAME, luaopen_math},\n  {LUA_UTF8LIBNAME, luaopen_utf8},\n  {LUA_DBLIBNAME, luaopen_debug},\n#if defined(LUA_COMPAT_BITLIB)\n  {LUA_BITLIBNAME, luaopen_bit32},\n#endif\n  {NULL, NULL}\n};\n\n\nLUALIB_API void luaL_openlibs (lua_State *L) {\n  const luaL_Reg *lib;\n  /* \"require\" functions from 'loadedlibs' and set results to global table */\n  for (lib = loadedlibs; lib->func; lib++) {\n    luaL_requiref(L, lib->name, lib->func, 1);\n    lua_pop(L, 1);  /* remove lib */\n  }\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/liolib.c",
    "content": "/*\n** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $\n** Standard I/O (and system) library\n** See Copyright Notice in lua.h\n*/\n\n#pragma warning(disable: 4244)\n#define liolib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <ctype.h>\n#include <errno.h>\n#include <locale.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n\n\n/*\n** Change this macro to accept other modes for 'fopen' besides\n** the standard ones.\n*/\n#if !defined(l_checkmode)\n\n/* accepted extensions to 'mode' in 'fopen' */\n#if !defined(L_MODEEXT)\n#define L_MODEEXT\t\"b\"\n#endif\n\n/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */\nstatic int l_checkmode (const char *mode) {\n  return (*mode != '\\0' && strchr(\"rwa\", *(mode++)) != NULL &&\n         (*mode != '+' || (++mode, 1)) &&  /* skip if char is '+' */\n         (strspn(mode, L_MODEEXT) == strlen(mode)));  /* check extensions */\n}\n\n#endif\n\n/*\n** {======================================================\n** l_popen spawns a new process connected to the current\n** one through the file streams.\n** =======================================================\n*/\n\n#if !defined(l_popen)\t\t/* { */\n\n#if defined(LUA_USE_POSIX)\t/* { */\n\n#define l_popen(L,c,m)\t\t(fflush(NULL), popen(c,m))\n#define l_pclose(L,file)\t(pclose(file))\n\n#if !APIEXPLORER_UWP\n#elif defined(LUA_USE_WINDOWS)\t/* }{ */\n\n#define l_popen(L,c,m)\t\t(_popen(c,m))\n#define l_pclose(L,file)\t(_pclose(file))\n#endif\n#else\t\t\t\t/* }{ */\n\n/* ISO C definitions */\n#define l_popen(L,c,m)  \\\n\t  ((void)((void)c, m), \\\n\t  luaL_error(L, \"'popen' not supported\"), \\\n\t  (FILE*)0)\n#define l_pclose(L,file)\t\t((void)L, (void)file, -1)\n\n#endif\t\t\t\t/* } */\n\n#endif\t\t\t\t/* } */\n\n/* }====================================================== */\n\n\n#if !defined(l_getc)\t\t/* { */\n\n#if defined(LUA_USE_POSIX)\n#define l_getc(f)\t\tgetc_unlocked(f)\n#define l_lockfile(f)\t\tflockfile(f)\n#define l_unlockfile(f)\t\tfunlockfile(f)\n#else\n#define l_getc(f)\t\tgetc(f)\n#define l_lockfile(f)\t\t((void)0)\n#define l_unlockfile(f)\t\t((void)0)\n#endif\n\n#endif\t\t\t\t/* } */\n\n\n/*\n** {======================================================\n** l_fseek: configuration for longer offsets\n** =======================================================\n*/\n\n#if !defined(l_fseek)\t\t/* { */\n\n#if defined(LUA_USE_POSIX)\t/* { */\n\n#include <sys/types.h>\n\n#define l_fseek(f,o,w)\t\tfseeko(f,o,w)\n#define l_ftell(f)\t\tftello(f)\n#define l_seeknum\t\toff_t\n\n#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \\\n   && defined(_MSC_VER) && (_MSC_VER >= 1400)\t/* }{ */\n\n/* Windows (but not DDK) and Visual C++ 2005 or higher */\n#define l_fseek(f,o,w)\t\t_fseeki64(f,o,w)\n#define l_ftell(f)\t\t_ftelli64(f)\n#define l_seeknum\t\t__int64\n\n#else\t\t\t\t/* }{ */\n\n/* ISO C definitions */\n#define l_fseek(f,o,w)\t\tfseek(f,o,w)\n#define l_ftell(f)\t\tftell(f)\n#define l_seeknum\t\tlong\n\n#endif\t\t\t\t/* } */\n\n#endif\t\t\t\t/* } */\n\n/* }====================================================== */\n\n\n#define IO_PREFIX\t\"_IO_\"\n#define IOPREF_LEN\t(sizeof(IO_PREFIX)/sizeof(char) - 1)\n#define IO_INPUT\t(IO_PREFIX \"input\")\n#define IO_OUTPUT\t(IO_PREFIX \"output\")\n\n\ntypedef luaL_Stream LStream;\n\n\n#define tolstream(L)\t((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))\n\n#define isclosed(p)\t((p)->closef == NULL)\n\n\nstatic int io_type (lua_State *L) {\n  LStream *p;\n  luaL_checkany(L, 1);\n  p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);\n  if (p == NULL)\n    lua_pushnil(L);  /* not a file */\n  else if (isclosed(p))\n    lua_pushliteral(L, \"closed file\");\n  else\n    lua_pushliteral(L, \"file\");\n  return 1;\n}\n\n\nstatic int f_tostring (lua_State *L) {\n  LStream *p = tolstream(L);\n  if (isclosed(p))\n    lua_pushliteral(L, \"file (closed)\");\n  else\n    lua_pushfstring(L, \"file (%p)\", p->f);\n  return 1;\n}\n\n\nstatic FILE *tofile (lua_State *L) {\n  LStream *p = tolstream(L);\n  if (isclosed(p))\n    luaL_error(L, \"attempt to use a closed file\");\n  lua_assert(p->f);\n  return p->f;\n}\n\n\n/*\n** When creating file handles, always creates a 'closed' file handle\n** before opening the actual file; so, if there is a memory error, the\n** handle is in a consistent state.\n*/\nstatic LStream *newprefile (lua_State *L) {\n  LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));\n  p->closef = NULL;  /* mark file handle as 'closed' */\n  luaL_setmetatable(L, LUA_FILEHANDLE);\n  return p;\n}\n\n\n/*\n** Calls the 'close' function from a file handle. The 'volatile' avoids\n** a bug in some versions of the Clang compiler (e.g., clang 3.0 for\n** 32 bits).\n*/\nstatic int aux_close (lua_State *L) {\n  LStream *p = tolstream(L);\n  volatile lua_CFunction cf = p->closef;\n  p->closef = NULL;  /* mark stream as closed */\n  return (*cf)(L);  /* close it */\n}\n\n\nstatic int f_close (lua_State *L) {\n  tofile(L);  /* make sure argument is an open stream */\n  return aux_close(L);\n}\n\n\nstatic int io_close (lua_State *L) {\n  if (lua_isnone(L, 1))  /* no argument? */\n    lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use standard output */\n  return f_close(L);\n}\n\n\nstatic int f_gc (lua_State *L) {\n  LStream *p = tolstream(L);\n  if (!isclosed(p) && p->f != NULL)\n    aux_close(L);  /* ignore closed and incompletely open files */\n  return 0;\n}\n\n\n/*\n** function to close regular files\n*/\nstatic int io_fclose (lua_State *L) {\n  LStream *p = tolstream(L);\n  int res = fclose(p->f);\n  return luaL_fileresult(L, (res == 0), NULL);\n}\n\n\nstatic LStream *newfile (lua_State *L) {\n  LStream *p = newprefile(L);\n  p->f = NULL;\n  p->closef = &io_fclose;\n  return p;\n}\n\n\nstatic void opencheck (lua_State *L, const char *fname, const char *mode) {\n  LStream *p = newfile(L);\n  p->f = fopen(fname, mode);\n  if (p->f == NULL)\n    luaL_error(L, \"cannot open file '%s' (%s)\", fname, strerror(errno));\n}\n\n\nstatic int io_open (lua_State *L) {\n  const char *filename = luaL_checkstring(L, 1);\n  const char *mode = luaL_optstring(L, 2, \"r\");\n  LStream *p = newfile(L);\n  const char *md = mode;  /* to traverse/check mode */\n  luaL_argcheck(L, l_checkmode(md), 2, \"invalid mode\");\n  p->f = fopen(filename, mode);\n  return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;\n}\n\n\n/*\n** function to close 'popen' files\n*/\nstatic int io_pclose (lua_State *L) {\n  LStream *p = tolstream(L);\n  return luaL_execresult(L, l_pclose(L, p->f));\n}\n\n\nstatic int io_popen (lua_State *L) {\n  const char *filename = luaL_checkstring(L, 1);\n  const char *mode = luaL_optstring(L, 2, \"r\");\n  LStream *p = newprefile(L);\n  p->f = l_popen(L, filename, mode);\n  p->closef = &io_pclose;\n  return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;\n}\n\n\nstatic int io_tmpfile (lua_State *L) {\n  LStream *p = newfile(L);\n  p->f = tmpfile();\n  return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;\n}\n\n\nstatic FILE *getiofile (lua_State *L, const char *findex) {\n  LStream *p;\n  lua_getfield(L, LUA_REGISTRYINDEX, findex);\n  p = (LStream *)lua_touserdata(L, -1);\n  if (isclosed(p))\n    luaL_error(L, \"standard %s file is closed\", findex + IOPREF_LEN);\n  return p->f;\n}\n\n\nstatic int g_iofile (lua_State *L, const char *f, const char *mode) {\n  if (!lua_isnoneornil(L, 1)) {\n    const char *filename = lua_tostring(L, 1);\n    if (filename)\n      opencheck(L, filename, mode);\n    else {\n      tofile(L);  /* check that it's a valid file handle */\n      lua_pushvalue(L, 1);\n    }\n    lua_setfield(L, LUA_REGISTRYINDEX, f);\n  }\n  /* return current value */\n  lua_getfield(L, LUA_REGISTRYINDEX, f);\n  return 1;\n}\n\n\nstatic int io_input (lua_State *L) {\n  return g_iofile(L, IO_INPUT, \"r\");\n}\n\n\nstatic int io_output (lua_State *L) {\n  return g_iofile(L, IO_OUTPUT, \"w\");\n}\n\n\nstatic int io_readline (lua_State *L);\n\n\n/*\n** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit\n** in the limit for upvalues of a closure)\n*/\n#define MAXARGLINE\t250\n\nstatic void aux_lines (lua_State *L, int toclose) {\n  int n = lua_gettop(L) - 1;  /* number of arguments to read */\n  luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, \"too many arguments\");\n  lua_pushinteger(L, n);  /* number of arguments to read */\n  lua_pushboolean(L, toclose);  /* close/not close file when finished */\n  lua_rotate(L, 2, 2);  /* move 'n' and 'toclose' to their positions */\n  lua_pushcclosure(L, io_readline, 3 + n);\n}\n\n\nstatic int f_lines (lua_State *L) {\n  tofile(L);  /* check that it's a valid file handle */\n  aux_lines(L, 0);\n  return 1;\n}\n\n\nstatic int io_lines (lua_State *L) {\n  int toclose;\n  if (lua_isnone(L, 1)) lua_pushnil(L);  /* at least one argument */\n  if (lua_isnil(L, 1)) {  /* no file name? */\n    lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT);  /* get default input */\n    lua_replace(L, 1);  /* put it at index 1 */\n    tofile(L);  /* check that it's a valid file handle */\n    toclose = 0;  /* do not close it after iteration */\n  }\n  else {  /* open a new file */\n    const char *filename = luaL_checkstring(L, 1);\n    opencheck(L, filename, \"r\");\n    lua_replace(L, 1);  /* put file at index 1 */\n    toclose = 1;  /* close it after iteration */\n  }\n  aux_lines(L, toclose);\n  return 1;\n}\n\n\n/*\n** {======================================================\n** READ\n** =======================================================\n*/\n\n\n/* maximum length of a numeral */\n#if !defined (L_MAXLENNUM)\n#define L_MAXLENNUM     200\n#endif\n\n\n/* auxiliary structure used by 'read_number' */\ntypedef struct {\n  FILE *f;  /* file being read */\n  int c;  /* current character (look ahead) */\n  int n;  /* number of elements in buffer 'buff' */\n  char buff[L_MAXLENNUM + 1];  /* +1 for ending '\\0' */\n} RN;\n\n\n/*\n** Add current char to buffer (if not out of space) and read next one\n*/\nstatic int nextc (RN *rn) {\n  if (rn->n >= L_MAXLENNUM) {  /* buffer overflow? */\n    rn->buff[0] = '\\0';  /* invalidate result */\n    return 0;  /* fail */\n  }\n  else {\n    rn->buff[rn->n++] = rn->c;  /* save current char */\n    rn->c = l_getc(rn->f);  /* read next one */\n    return 1;\n  }\n}\n\n\n/*\n** Accept current char if it is in 'set' (of size 2)\n*/\nstatic int test2 (RN *rn, const char *set) {\n  if (rn->c == set[0] || rn->c == set[1])\n    return nextc(rn);\n  else return 0;\n}\n\n\n/*\n** Read a sequence of (hex)digits\n*/\nstatic int readdigits (RN *rn, int hex) {\n  int count = 0;\n  while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn))\n    count++;\n  return count;\n}\n\n\n/*\n** Read a number: first reads a valid prefix of a numeral into a buffer.\n** Then it calls 'lua_stringtonumber' to check whether the format is\n** correct and to convert it to a Lua number\n*/\nstatic int read_number (lua_State *L, FILE *f) {\n  RN rn;\n  int count = 0;\n  int hex = 0;\n  char decp[2];\n  rn.f = f; rn.n = 0;\n  decp[0] = lua_getlocaledecpoint();  /* get decimal point from locale */\n  decp[1] = '.';  /* always accept a dot */\n  l_lockfile(rn.f);\n  do { rn.c = l_getc(rn.f); } while (isspace(rn.c));  /* skip spaces */\n  test2(&rn, \"-+\");  /* optional signal */\n  if (test2(&rn, \"00\")) {\n    if (test2(&rn, \"xX\")) hex = 1;  /* numeral is hexadecimal */\n    else count = 1;  /* count initial '0' as a valid digit */\n  }\n  count += readdigits(&rn, hex);  /* integral part */\n  if (test2(&rn, decp))  /* decimal point? */\n    count += readdigits(&rn, hex);  /* fractional part */\n  if (count > 0 && test2(&rn, (hex ? \"pP\" : \"eE\"))) {  /* exponent mark? */\n    test2(&rn, \"-+\");  /* exponent signal */\n    readdigits(&rn, 0);  /* exponent digits */\n  }\n  ungetc(rn.c, rn.f);  /* unread look-ahead char */\n  l_unlockfile(rn.f);\n  rn.buff[rn.n] = '\\0';  /* finish string */\n  if (lua_stringtonumber(L, rn.buff))  /* is this a valid number? */\n    return 1;  /* ok */\n  else {  /* invalid format */\n   lua_pushnil(L);  /* \"result\" to be removed */\n   return 0;  /* read fails */\n  }\n}\n\n\nstatic int test_eof (lua_State *L, FILE *f) {\n  int c = getc(f);\n  ungetc(c, f);  /* no-op when c == EOF */\n  lua_pushliteral(L, \"\");\n  return (c != EOF);\n}\n\n\nstatic int read_line (lua_State *L, FILE *f, int chop) {\n  luaL_Buffer b;\n  int c = '\\0';\n  luaL_buffinit(L, &b);\n  while (c != EOF && c != '\\n') {  /* repeat until end of line */\n    char *buff = luaL_prepbuffer(&b);  /* preallocate buffer */\n    int i = 0;\n    l_lockfile(f);  /* no memory errors can happen inside the lock */\n    while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\\n')\n      buff[i++] = c;\n    l_unlockfile(f);\n    luaL_addsize(&b, i);\n  }\n  if (!chop && c == '\\n')  /* want a newline and have one? */\n    luaL_addchar(&b, c);  /* add ending newline to result */\n  luaL_pushresult(&b);  /* close buffer */\n  /* return ok if read something (either a newline or something else) */\n  return (c == '\\n' || lua_rawlen(L, -1) > 0);\n}\n\n\nstatic void read_all (lua_State *L, FILE *f) {\n  size_t nr;\n  luaL_Buffer b;\n  luaL_buffinit(L, &b);\n  do {  /* read file in chunks of LUAL_BUFFERSIZE bytes */\n    char *p = luaL_prepbuffer(&b);\n    nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);\n    luaL_addsize(&b, nr);\n  } while (nr == LUAL_BUFFERSIZE);\n  luaL_pushresult(&b);  /* close buffer */\n}\n\n\nstatic int read_chars (lua_State *L, FILE *f, size_t n) {\n  size_t nr;  /* number of chars actually read */\n  char *p;\n  luaL_Buffer b;\n  luaL_buffinit(L, &b);\n  p = luaL_prepbuffsize(&b, n);  /* prepare buffer to read whole block */\n  nr = fread(p, sizeof(char), n, f);  /* try to read 'n' chars */\n  luaL_addsize(&b, nr);\n  luaL_pushresult(&b);  /* close buffer */\n  return (nr > 0);  /* true iff read something */\n}\n\n\nstatic int g_read (lua_State *L, FILE *f, int first) {\n  int nargs = lua_gettop(L) - 1;\n  int success;\n  int n;\n  clearerr(f);\n  if (nargs == 0) {  /* no arguments? */\n    success = read_line(L, f, 1);\n    n = first+1;  /* to return 1 result */\n  }\n  else {  /* ensure stack space for all results and for auxlib's buffer */\n    luaL_checkstack(L, nargs+LUA_MINSTACK, \"too many arguments\");\n    success = 1;\n    for (n = first; nargs-- && success; n++) {\n      if (lua_type(L, n) == LUA_TNUMBER) {\n        size_t l = (size_t)luaL_checkinteger(L, n);\n        success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);\n      }\n      else {\n        const char *p = luaL_checkstring(L, n);\n        if (*p == '*') p++;  /* skip optional '*' (for compatibility) */\n        switch (*p) {\n          case 'n':  /* number */\n            success = read_number(L, f);\n            break;\n          case 'l':  /* line */\n            success = read_line(L, f, 1);\n            break;\n          case 'L':  /* line with end-of-line */\n            success = read_line(L, f, 0);\n            break;\n          case 'a':  /* file */\n            read_all(L, f);  /* read entire file */\n            success = 1; /* always success */\n            break;\n          default:\n            return luaL_argerror(L, n, \"invalid format\");\n        }\n      }\n    }\n  }\n  if (ferror(f))\n    return luaL_fileresult(L, 0, NULL);\n  if (!success) {\n    lua_pop(L, 1);  /* remove last result */\n    lua_pushnil(L);  /* push nil instead */\n  }\n  return n - first;\n}\n\n\nstatic int io_read (lua_State *L) {\n  return g_read(L, getiofile(L, IO_INPUT), 1);\n}\n\n\nstatic int f_read (lua_State *L) {\n  return g_read(L, tofile(L), 2);\n}\n\n\nstatic int io_readline (lua_State *L) {\n  LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));\n  int i;\n  int n = (int)lua_tointeger(L, lua_upvalueindex(2));\n  if (isclosed(p))  /* file is already closed? */\n    return luaL_error(L, \"file is already closed\");\n  lua_settop(L , 1);\n  luaL_checkstack(L, n, \"too many arguments\");\n  for (i = 1; i <= n; i++)  /* push arguments to 'g_read' */\n    lua_pushvalue(L, lua_upvalueindex(3 + i));\n  n = g_read(L, p->f, 2);  /* 'n' is number of results */\n  lua_assert(n > 0);  /* should return at least a nil */\n  if (lua_toboolean(L, -n))  /* read at least one value? */\n    return n;  /* return them */\n  else {  /* first result is nil: EOF or error */\n    if (n > 1) {  /* is there error information? */\n      /* 2nd result is error message */\n      return luaL_error(L, \"%s\", lua_tostring(L, -n + 1));\n    }\n    if (lua_toboolean(L, lua_upvalueindex(3))) {  /* generator created file? */\n      lua_settop(L, 0);\n      lua_pushvalue(L, lua_upvalueindex(1));\n      aux_close(L);  /* close it */\n    }\n    return 0;\n  }\n}\n\n/* }====================================================== */\n\n\nstatic int g_write (lua_State *L, FILE *f, int arg) {\n  int nargs = lua_gettop(L) - arg;\n  int status = 1;\n  for (; nargs--; arg++) {\n    if (lua_type(L, arg) == LUA_TNUMBER) {\n      /* optimization: could be done exactly as for strings */\n      int len = lua_isinteger(L, arg)\n                ? fprintf(f, LUA_INTEGER_FMT,\n                             (LUAI_UACINT)lua_tointeger(L, arg))\n                : fprintf(f, LUA_NUMBER_FMT,\n                             (LUAI_UACNUMBER)lua_tonumber(L, arg));\n      status = status && (len > 0);\n    }\n    else {\n      size_t l;\n      const char *s = luaL_checklstring(L, arg, &l);\n      status = status && (fwrite(s, sizeof(char), l, f) == l);\n    }\n  }\n  if (status) return 1;  /* file handle already on stack top */\n  else return luaL_fileresult(L, status, NULL);\n}\n\n\nstatic int io_write (lua_State *L) {\n  return g_write(L, getiofile(L, IO_OUTPUT), 1);\n}\n\n\nstatic int f_write (lua_State *L) {\n  FILE *f = tofile(L);\n  lua_pushvalue(L, 1);  /* push file at the stack top (to be returned) */\n  return g_write(L, f, 2);\n}\n\n\nstatic int f_seek (lua_State *L) {\n  static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};\n  static const char *const modenames[] = {\"set\", \"cur\", \"end\", NULL};\n  FILE *f = tofile(L);\n  int op = luaL_checkoption(L, 2, \"cur\", modenames);\n  lua_Integer p3 = luaL_optinteger(L, 3, 0);\n  l_seeknum offset = (l_seeknum)p3;\n  luaL_argcheck(L, (lua_Integer)offset == p3, 3,\n                  \"not an integer in proper range\");\n  op = l_fseek(f, offset, mode[op]);\n  if (op)\n    return luaL_fileresult(L, 0, NULL);  /* error */\n  else {\n    lua_pushinteger(L, (lua_Integer)l_ftell(f));\n    return 1;\n  }\n}\n\n\nstatic int f_setvbuf (lua_State *L) {\n  static const int mode[] = {_IONBF, _IOFBF, _IOLBF};\n  static const char *const modenames[] = {\"no\", \"full\", \"line\", NULL};\n  FILE *f = tofile(L);\n  int op = luaL_checkoption(L, 2, NULL, modenames);\n  lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);\n  int res = setvbuf(f, NULL, mode[op], (size_t)sz);\n  return luaL_fileresult(L, res == 0, NULL);\n}\n\n\n\nstatic int io_flush (lua_State *L) {\n  return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);\n}\n\n\nstatic int f_flush (lua_State *L) {\n  return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);\n}\n\n\n/*\n** functions for 'io' library\n*/\nstatic const luaL_Reg iolib[] = {\n  {\"close\", io_close},\n  {\"flush\", io_flush},\n  {\"input\", io_input},\n  {\"lines\", io_lines},\n  {\"open\", io_open},\n  {\"output\", io_output},\n  {\"popen\", io_popen},\n  {\"read\", io_read},\n  {\"tmpfile\", io_tmpfile},\n  {\"type\", io_type},\n  {\"write\", io_write},\n  {NULL, NULL}\n};\n\n\n/*\n** methods for file handles\n*/\nstatic const luaL_Reg flib[] = {\n  {\"close\", f_close},\n  {\"flush\", f_flush},\n  {\"lines\", f_lines},\n  {\"read\", f_read},\n  {\"seek\", f_seek},\n  {\"setvbuf\", f_setvbuf},\n  {\"write\", f_write},\n  {\"__gc\", f_gc},\n  {\"__tostring\", f_tostring},\n  {NULL, NULL}\n};\n\n\nstatic void createmeta (lua_State *L) {\n  luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */\n  lua_pushvalue(L, -1);  /* push metatable */\n  lua_setfield(L, -2, \"__index\");  /* metatable.__index = metatable */\n  luaL_setfuncs(L, flib, 0);  /* add file methods to new metatable */\n  lua_pop(L, 1);  /* pop new metatable */\n}\n\n\n/*\n** function to (not) close the standard files stdin, stdout, and stderr\n*/\nstatic int io_noclose (lua_State *L) {\n  LStream *p = tolstream(L);\n  p->closef = &io_noclose;  /* keep file opened */\n  lua_pushnil(L);\n  lua_pushliteral(L, \"cannot close standard file\");\n  return 2;\n}\n\n\nstatic void createstdfile (lua_State *L, FILE *f, const char *k,\n                           const char *fname) {\n  LStream *p = newprefile(L);\n  p->f = f;\n  p->closef = &io_noclose;\n  if (k != NULL) {\n    lua_pushvalue(L, -1);\n    lua_setfield(L, LUA_REGISTRYINDEX, k);  /* add file to registry */\n  }\n  lua_setfield(L, -2, fname);  /* add file to module */\n}\n\n\nLUAMOD_API int luaopen_io (lua_State *L) {\n  luaL_newlib(L, iolib);  /* new module */\n  createmeta(L);\n  /* create (and set) default files */\n  createstdfile(L, stdin, IO_INPUT, \"stdin\");\n  createstdfile(L, stdout, IO_OUTPUT, \"stdout\");\n  createstdfile(L, stderr, NULL, \"stderr\");\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/llex.c",
    "content": "/*\n** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $\n** Lexical Analyzer\n** See Copyright Notice in lua.h\n*/\n\n#define llex_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <locale.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lctype.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lgc.h\"\n#include \"llex.h\"\n#include \"lobject.h\"\n#include \"lparser.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"lzio.h\"\n\n\n\n#define next(ls) (ls->current = zgetc(ls->z))\n\n\n\n#define currIsNewline(ls)\t(ls->current == '\\n' || ls->current == '\\r')\n\n\n/* ORDER RESERVED */\nstatic const char *const luaX_tokens [] = {\n    \"and\", \"break\", \"do\", \"else\", \"elseif\",\n    \"end\", \"false\", \"for\", \"function\", \"goto\", \"if\",\n    \"in\", \"local\", \"nil\", \"not\", \"or\", \"repeat\",\n    \"return\", \"then\", \"true\", \"until\", \"while\",\n    \"//\", \"..\", \"...\", \"==\", \">=\", \"<=\", \"~=\",\n    \"<<\", \">>\", \"::\", \"<eof>\",\n    \"<number>\", \"<integer>\", \"<name>\", \"<string>\"\n};\n\n\n#define save_and_next(ls) (save(ls, ls->current), next(ls))\n\n\nstatic l_noret lexerror (LexState *ls, const char *msg, int token);\n\n\nstatic void save (LexState *ls, int c) {\n  Mbuffer *b = ls->buff;\n  if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {\n    size_t newsize;\n    if (luaZ_sizebuffer(b) >= MAX_SIZE/2)\n      lexerror(ls, \"lexical element too long\", 0);\n    newsize = luaZ_sizebuffer(b) * 2;\n    luaZ_resizebuffer(ls->L, b, newsize);\n  }\n  b->buffer[luaZ_bufflen(b)++] = cast(char, c);\n}\n\n\nvoid luaX_init (lua_State *L) {\n  int i;\n  TString *e = luaS_newliteral(L, LUA_ENV);  /* create env name */\n  luaC_fix(L, obj2gco(e));  /* never collect this name */\n  for (i=0; i<NUM_RESERVED; i++) {\n    TString *ts = luaS_new(L, luaX_tokens[i]);\n    luaC_fix(L, obj2gco(ts));  /* reserved words are never collected */\n    ts->extra = cast_byte(i+1);  /* reserved word */\n  }\n}\n\n\nconst char *luaX_token2str (LexState *ls, int token) {\n  if (token < FIRST_RESERVED) {  /* single-byte symbols? */\n    lua_assert(token == cast_uchar(token));\n    return luaO_pushfstring(ls->L, \"'%c'\", token);\n  }\n  else {\n    const char *s = luaX_tokens[token - FIRST_RESERVED];\n    if (token < TK_EOS)  /* fixed format (symbols and reserved words)? */\n      return luaO_pushfstring(ls->L, \"'%s'\", s);\n    else  /* names, strings, and numerals */\n      return s;\n  }\n}\n\n\nstatic const char *txtToken (LexState *ls, int token) {\n  switch (token) {\n    case TK_NAME: case TK_STRING:\n    case TK_FLT: case TK_INT:\n      save(ls, '\\0');\n      return luaO_pushfstring(ls->L, \"'%s'\", luaZ_buffer(ls->buff));\n    default:\n      return luaX_token2str(ls, token);\n  }\n}\n\n\nstatic l_noret lexerror (LexState *ls, const char *msg, int token) {\n  msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);\n  if (token)\n    luaO_pushfstring(ls->L, \"%s near %s\", msg, txtToken(ls, token));\n  luaD_throw(ls->L, LUA_ERRSYNTAX);\n}\n\n\nl_noret luaX_syntaxerror (LexState *ls, const char *msg) {\n  lexerror(ls, msg, ls->t.token);\n}\n\n\n/*\n** creates a new string and anchors it in scanner's table so that\n** it will not be collected until the end of the compilation\n** (by that time it should be anchored somewhere)\n*/\nTString *luaX_newstring (LexState *ls, const char *str, size_t l) {\n  lua_State *L = ls->L;\n  TValue *o;  /* entry for 'str' */\n  TString *ts = luaS_newlstr(L, str, l);  /* create new string */\n  setsvalue2s(L, L->top++, ts);  /* temporarily anchor it in stack */\n  o = luaH_set(L, ls->h, L->top - 1);\n  if (ttisnil(o)) {  /* not in use yet? */\n    /* boolean value does not need GC barrier;\n       table has no metatable, so it does not need to invalidate cache */\n    setbvalue(o, 1);  /* t[string] = true */\n    luaC_checkGC(L);\n  }\n  else {  /* string already present */\n    ts = tsvalue(keyfromval(o));  /* re-use value previously stored */\n  }\n  L->top--;  /* remove string from stack */\n  return ts;\n}\n\n\n/*\n** increment line number and skips newline sequence (any of\n** \\n, \\r, \\n\\r, or \\r\\n)\n*/\nstatic void inclinenumber (LexState *ls) {\n  int old = ls->current;\n  lua_assert(currIsNewline(ls));\n  next(ls);  /* skip '\\n' or '\\r' */\n  if (currIsNewline(ls) && ls->current != old)\n    next(ls);  /* skip '\\n\\r' or '\\r\\n' */\n  if (++ls->linenumber >= MAX_INT)\n    lexerror(ls, \"chunk has too many lines\", 0);\n}\n\n\nvoid luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,\n                    int firstchar) {\n  ls->t.token = 0;\n  ls->L = L;\n  ls->current = firstchar;\n  ls->lookahead.token = TK_EOS;  /* no look-ahead token */\n  ls->z = z;\n  ls->fs = NULL;\n  ls->linenumber = 1;\n  ls->lastline = 1;\n  ls->source = source;\n  ls->envn = luaS_newliteral(L, LUA_ENV);  /* get env name */\n  luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */\n}\n\n\n\n/*\n** =======================================================\n** LEXICAL ANALYZER\n** =======================================================\n*/\n\n\nstatic int check_next1 (LexState *ls, int c) {\n  if (ls->current == c) {\n    next(ls);\n    return 1;\n  }\n  else return 0;\n}\n\n\n/*\n** Check whether current char is in set 'set' (with two chars) and\n** saves it\n*/\nstatic int check_next2 (LexState *ls, const char *set) {\n  lua_assert(set[2] == '\\0');\n  if (ls->current == set[0] || ls->current == set[1]) {\n    save_and_next(ls);\n    return 1;\n  }\n  else return 0;\n}\n\n\n/* LUA_NUMBER */\n/*\n** this function is quite liberal in what it accepts, as 'luaO_str2num'\n** will reject ill-formed numerals.\n*/\nstatic int read_numeral (LexState *ls, SemInfo *seminfo) {\n  TValue obj;\n  const char *expo = \"Ee\";\n  int first = ls->current;\n  lua_assert(lisdigit(ls->current));\n  save_and_next(ls);\n  if (first == '0' && check_next2(ls, \"xX\"))  /* hexadecimal? */\n    expo = \"Pp\";\n  for (;;) {\n    if (check_next2(ls, expo))  /* exponent part? */\n      check_next2(ls, \"-+\");  /* optional exponent sign */\n    if (lisxdigit(ls->current))\n      save_and_next(ls);\n    else if (ls->current == '.')\n      save_and_next(ls);\n    else break;\n  }\n  save(ls, '\\0');\n  if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0)  /* format error? */\n    lexerror(ls, \"malformed number\", TK_FLT);\n  if (ttisinteger(&obj)) {\n    seminfo->i = ivalue(&obj);\n    return TK_INT;\n  }\n  else {\n    lua_assert(ttisfloat(&obj));\n    seminfo->r = fltvalue(&obj);\n    return TK_FLT;\n  }\n}\n\n\n/*\n** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return\n** its number of '='s; otherwise, return a negative number (-1 iff there\n** are no '='s after initial bracket)\n*/\nstatic int skip_sep (LexState *ls) {\n  int count = 0;\n  int s = ls->current;\n  lua_assert(s == '[' || s == ']');\n  save_and_next(ls);\n  while (ls->current == '=') {\n    save_and_next(ls);\n    count++;\n  }\n  return (ls->current == s) ? count : (-count) - 1;\n}\n\n\nstatic void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {\n  int line = ls->linenumber;  /* initial line (for error message) */\n  save_and_next(ls);  /* skip 2nd '[' */\n  if (currIsNewline(ls))  /* string starts with a newline? */\n    inclinenumber(ls);  /* skip it */\n  for (;;) {\n    switch (ls->current) {\n      case EOZ: {  /* error */\n        const char *what = (seminfo ? \"string\" : \"comment\");\n        const char *msg = luaO_pushfstring(ls->L,\n                     \"unfinished long %s (starting at line %d)\", what, line);\n        lexerror(ls, msg, TK_EOS);\n        break;  /* to avoid warnings */\n      }\n      case ']': {\n        if (skip_sep(ls) == sep) {\n          save_and_next(ls);  /* skip 2nd ']' */\n          goto endloop;\n        }\n        break;\n      }\n      case '\\n': case '\\r': {\n        save(ls, '\\n');\n        inclinenumber(ls);\n        if (!seminfo) luaZ_resetbuffer(ls->buff);  /* avoid wasting space */\n        break;\n      }\n      default: {\n        if (seminfo) save_and_next(ls);\n        else next(ls);\n      }\n    }\n  } endloop:\n  if (seminfo)\n    seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),\n                                     luaZ_bufflen(ls->buff) - 2*(2 + sep));\n}\n\n\nstatic void esccheck (LexState *ls, int c, const char *msg) {\n  if (!c) {\n    if (ls->current != EOZ)\n      save_and_next(ls);  /* add current to buffer for error message */\n    lexerror(ls, msg, TK_STRING);\n  }\n}\n\n\nstatic int gethexa (LexState *ls) {\n  save_and_next(ls);\n  esccheck (ls, lisxdigit(ls->current), \"hexadecimal digit expected\");\n  return luaO_hexavalue(ls->current);\n}\n\n\nstatic int readhexaesc (LexState *ls) {\n  int r = gethexa(ls);\n  r = (r << 4) + gethexa(ls);\n  luaZ_buffremove(ls->buff, 2);  /* remove saved chars from buffer */\n  return r;\n}\n\n\nstatic unsigned long readutf8esc (LexState *ls) {\n  unsigned long r;\n  int i = 4;  /* chars to be removed: '\\', 'u', '{', and first digit */\n  save_and_next(ls);  /* skip 'u' */\n  esccheck(ls, ls->current == '{', \"missing '{'\");\n  r = gethexa(ls);  /* must have at least one digit */\n  while ((save_and_next(ls), lisxdigit(ls->current))) {\n    i++;\n    r = (r << 4) + luaO_hexavalue(ls->current);\n    esccheck(ls, r <= 0x10FFFF, \"UTF-8 value too large\");\n  }\n  esccheck(ls, ls->current == '}', \"missing '}'\");\n  next(ls);  /* skip '}' */\n  luaZ_buffremove(ls->buff, i);  /* remove saved chars from buffer */\n  return r;\n}\n\n\nstatic void utf8esc (LexState *ls) {\n  char buff[UTF8BUFFSZ];\n  int n = luaO_utf8esc(buff, readutf8esc(ls));\n  for (; n > 0; n--)  /* add 'buff' to string */\n    save(ls, buff[UTF8BUFFSZ - n]);\n}\n\n\nstatic int readdecesc (LexState *ls) {\n  int i;\n  int r = 0;  /* result accumulator */\n  for (i = 0; i < 3 && lisdigit(ls->current); i++) {  /* read up to 3 digits */\n    r = 10*r + ls->current - '0';\n    save_and_next(ls);\n  }\n  esccheck(ls, r <= UCHAR_MAX, \"decimal escape too large\");\n  luaZ_buffremove(ls->buff, i);  /* remove read digits from buffer */\n  return r;\n}\n\n\nstatic void read_string (LexState *ls, int del, SemInfo *seminfo) {\n  save_and_next(ls);  /* keep delimiter (for error messages) */\n  while (ls->current != del) {\n    switch (ls->current) {\n      case EOZ:\n        lexerror(ls, \"unfinished string\", TK_EOS);\n        break;  /* to avoid warnings */\n      case '\\n':\n      case '\\r':\n        lexerror(ls, \"unfinished string\", TK_STRING);\n        break;  /* to avoid warnings */\n      case '\\\\': {  /* escape sequences */\n        int c;  /* final character to be saved */\n        save_and_next(ls);  /* keep '\\\\' for error messages */\n        switch (ls->current) {\n          case 'a': c = '\\a'; goto read_save;\n          case 'b': c = '\\b'; goto read_save;\n          case 'f': c = '\\f'; goto read_save;\n          case 'n': c = '\\n'; goto read_save;\n          case 'r': c = '\\r'; goto read_save;\n          case 't': c = '\\t'; goto read_save;\n          case 'v': c = '\\v'; goto read_save;\n          case 'x': c = readhexaesc(ls); goto read_save;\n          case 'u': utf8esc(ls);  goto no_save;\n          case '\\n': case '\\r':\n            inclinenumber(ls); c = '\\n'; goto only_save;\n          case '\\\\': case '\\\"': case '\\'':\n            c = ls->current; goto read_save;\n          case EOZ: goto no_save;  /* will raise an error next loop */\n          case 'z': {  /* zap following span of spaces */\n            luaZ_buffremove(ls->buff, 1);  /* remove '\\\\' */\n            next(ls);  /* skip the 'z' */\n            while (lisspace(ls->current)) {\n              if (currIsNewline(ls)) inclinenumber(ls);\n              else next(ls);\n            }\n            goto no_save;\n          }\n          default: {\n            esccheck(ls, lisdigit(ls->current), \"invalid escape sequence\");\n            c = readdecesc(ls);  /* digital escape '\\ddd' */\n            goto only_save;\n          }\n        }\n       read_save:\n         next(ls);\n         /* go through */\n       only_save:\n         luaZ_buffremove(ls->buff, 1);  /* remove '\\\\' */\n         save(ls, c);\n         /* go through */\n       no_save: break;\n      }\n      default:\n        save_and_next(ls);\n    }\n  }\n  save_and_next(ls);  /* skip delimiter */\n  seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,\n                                   luaZ_bufflen(ls->buff) - 2);\n}\n\n\nstatic int llex (LexState *ls, SemInfo *seminfo) {\n  luaZ_resetbuffer(ls->buff);\n  for (;;) {\n    switch (ls->current) {\n      case '\\n': case '\\r': {  /* line breaks */\n        inclinenumber(ls);\n        break;\n      }\n      case ' ': case '\\f': case '\\t': case '\\v': {  /* spaces */\n        next(ls);\n        break;\n      }\n      case '-': {  /* '-' or '--' (comment) */\n        next(ls);\n        if (ls->current != '-') return '-';\n        /* else is a comment */\n        next(ls);\n        if (ls->current == '[') {  /* long comment? */\n          int sep = skip_sep(ls);\n          luaZ_resetbuffer(ls->buff);  /* 'skip_sep' may dirty the buffer */\n          if (sep >= 0) {\n            read_long_string(ls, NULL, sep);  /* skip long comment */\n            luaZ_resetbuffer(ls->buff);  /* previous call may dirty the buff. */\n            break;\n          }\n        }\n        /* else short comment */\n        while (!currIsNewline(ls) && ls->current != EOZ)\n          next(ls);  /* skip until end of line (or end of file) */\n        break;\n      }\n      case '[': {  /* long string or simply '[' */\n        int sep = skip_sep(ls);\n        if (sep >= 0) {\n          read_long_string(ls, seminfo, sep);\n          return TK_STRING;\n        }\n        else if (sep != -1)  /* '[=...' missing second bracket */\n          lexerror(ls, \"invalid long string delimiter\", TK_STRING);\n        return '[';\n      }\n      case '=': {\n        next(ls);\n        if (check_next1(ls, '=')) return TK_EQ;\n        else return '=';\n      }\n      case '<': {\n        next(ls);\n        if (check_next1(ls, '=')) return TK_LE;\n        else if (check_next1(ls, '<')) return TK_SHL;\n        else return '<';\n      }\n      case '>': {\n        next(ls);\n        if (check_next1(ls, '=')) return TK_GE;\n        else if (check_next1(ls, '>')) return TK_SHR;\n        else return '>';\n      }\n      case '/': {\n        next(ls);\n        if (check_next1(ls, '/')) return TK_IDIV;\n        else return '/';\n      }\n      case '~': {\n        next(ls);\n        if (check_next1(ls, '=')) return TK_NE;\n        else return '~';\n      }\n      case ':': {\n        next(ls);\n        if (check_next1(ls, ':')) return TK_DBCOLON;\n        else return ':';\n      }\n      case '\"': case '\\'': {  /* short literal strings */\n        read_string(ls, ls->current, seminfo);\n        return TK_STRING;\n      }\n      case '.': {  /* '.', '..', '...', or number */\n        save_and_next(ls);\n        if (check_next1(ls, '.')) {\n          if (check_next1(ls, '.'))\n            return TK_DOTS;   /* '...' */\n          else return TK_CONCAT;   /* '..' */\n        }\n        else if (!lisdigit(ls->current)) return '.';\n        else return read_numeral(ls, seminfo);\n      }\n      case '0': case '1': case '2': case '3': case '4':\n      case '5': case '6': case '7': case '8': case '9': {\n        return read_numeral(ls, seminfo);\n      }\n      case EOZ: {\n        return TK_EOS;\n      }\n      default: {\n        if (lislalpha(ls->current)) {  /* identifier or reserved word? */\n          TString *ts;\n          do {\n            save_and_next(ls);\n          } while (lislalnum(ls->current));\n          ts = luaX_newstring(ls, luaZ_buffer(ls->buff),\n                                  luaZ_bufflen(ls->buff));\n          seminfo->ts = ts;\n          if (isreserved(ts))  /* reserved word? */\n            return ts->extra - 1 + FIRST_RESERVED;\n          else {\n            return TK_NAME;\n          }\n        }\n        else {  /* single-char tokens (+ - / ...) */\n          int c = ls->current;\n          next(ls);\n          return c;\n        }\n      }\n    }\n  }\n}\n\n\nvoid luaX_next (LexState *ls) {\n  ls->lastline = ls->linenumber;\n  if (ls->lookahead.token != TK_EOS) {  /* is there a look-ahead token? */\n    ls->t = ls->lookahead;  /* use this one */\n    ls->lookahead.token = TK_EOS;  /* and discharge it */\n  }\n  else\n    ls->t.token = llex(ls, &ls->t.seminfo);  /* read next token */\n}\n\n\nint luaX_lookahead (LexState *ls) {\n  lua_assert(ls->lookahead.token == TK_EOS);\n  ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);\n  return ls->lookahead.token;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/llex.h",
    "content": "/*\n** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $\n** Lexical Analyzer\n** See Copyright Notice in lua.h\n*/\n\n#ifndef llex_h\n#define llex_h\n\n#include \"lobject.h\"\n#include \"lzio.h\"\n\n\n#define FIRST_RESERVED\t257\n\n\n#if !defined(LUA_ENV)\n#define LUA_ENV\t\t\"_ENV\"\n#endif\n\n\n/*\n* WARNING: if you change the order of this enumeration,\n* grep \"ORDER RESERVED\"\n*/\nenum RESERVED {\n  /* terminal symbols denoted by reserved words */\n  TK_AND = FIRST_RESERVED, TK_BREAK,\n  TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,\n  TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,\n  TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,\n  /* other terminal symbols */\n  TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,\n  TK_SHL, TK_SHR,\n  TK_DBCOLON, TK_EOS,\n  TK_FLT, TK_INT, TK_NAME, TK_STRING\n};\n\n/* number of reserved words */\n#define NUM_RESERVED\t(cast(int, TK_WHILE-FIRST_RESERVED+1))\n\n\ntypedef union {\n  lua_Number r;\n  lua_Integer i;\n  TString *ts;\n} SemInfo;  /* semantics information */\n\n\ntypedef struct Token {\n  int token;\n  SemInfo seminfo;\n} Token;\n\n\n/* state of the lexer plus state of the parser when shared by all\n   functions */\ntypedef struct LexState {\n  int current;  /* current character (charint) */\n  int linenumber;  /* input line counter */\n  int lastline;  /* line of last token 'consumed' */\n  Token t;  /* current token */\n  Token lookahead;  /* look ahead token */\n  struct FuncState *fs;  /* current function (parser) */\n  struct lua_State *L;\n  ZIO *z;  /* input stream */\n  Mbuffer *buff;  /* buffer for tokens */\n  Table *h;  /* to avoid collection/reuse strings */\n  struct Dyndata *dyd;  /* dynamic structures used by the parser */\n  TString *source;  /* current source name */\n  TString *envn;  /* environment variable name */\n} LexState;\n\n\nLUAI_FUNC void luaX_init (lua_State *L);\nLUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,\n                              TString *source, int firstchar);\nLUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);\nLUAI_FUNC void luaX_next (LexState *ls);\nLUAI_FUNC int luaX_lookahead (LexState *ls);\nLUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s);\nLUAI_FUNC const char *luaX_token2str (LexState *ls, int token);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/llimits.h",
    "content": "/*\n** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $\n** Limits, basic types, and some other 'installation-dependent' definitions\n** See Copyright Notice in lua.h\n*/\n\n#ifndef llimits_h\n#define llimits_h\n\n\n#include <limits.h>\n#include <stddef.h>\n\n\n#include \"lua.h\"\n\n/*\n** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count\n** the total memory used by Lua (in bytes). Usually, 'size_t' and\n** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.\n*/\n#if defined(LUAI_MEM)\t\t/* { external definitions? */\ntypedef LUAI_UMEM lu_mem;\ntypedef LUAI_MEM l_mem;\n#elif LUAI_BITSINT >= 32\t/* }{ */\ntypedef size_t lu_mem;\ntypedef ptrdiff_t l_mem;\n#else  /* 16-bit ints */\t/* }{ */\ntypedef unsigned long lu_mem;\ntypedef long l_mem;\n#endif\t\t\t\t/* } */\n\n\n/* chars used as small naturals (so that 'char' is reserved for characters) */\ntypedef unsigned char lu_byte;\n\n\n/* maximum value for size_t */\n#define MAX_SIZET\t((size_t)(~(size_t)0))\n\n/* maximum size visible for Lua (must be representable in a lua_Integer */\n#define MAX_SIZE\t(sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \\\n                          : (size_t)(LUA_MAXINTEGER))\n\n\n#define MAX_LUMEM\t((lu_mem)(~(lu_mem)0))\n\n#define MAX_LMEM\t((l_mem)(MAX_LUMEM >> 1))\n\n\n#define MAX_INT\t\tINT_MAX  /* maximum value of an int */\n\n\n/*\n** conversion of pointer to unsigned integer:\n** this is for hashing only; there is no problem if the integer\n** cannot hold the whole pointer value\n*/\n#define point2uint(p)\t((unsigned int)((size_t)(p) & UINT_MAX))\n\n\n\n/* type to ensure maximum alignment */\n#if defined(LUAI_USER_ALIGNMENT_T)\ntypedef LUAI_USER_ALIGNMENT_T L_Umaxalign;\n#else\ntypedef union {\n  lua_Number n;\n  double u;\n  void *s;\n  lua_Integer i;\n  long l;\n} L_Umaxalign;\n#endif\n\n\n\n/* types of 'usual argument conversions' for lua_Number and lua_Integer */\ntypedef LUAI_UACNUMBER l_uacNumber;\ntypedef LUAI_UACINT l_uacInt;\n\n\n/* internal assertions for in-house debugging */\n#if defined(lua_assert)\n#define check_exp(c,e)\t\t(lua_assert(c), (e))\n/* to avoid problems with conditions too long */\n#define lua_longassert(c)\t((c) ? (void)0 : lua_assert(0))\n#else\n#define lua_assert(c)\t\t((void)0)\n#define check_exp(c,e)\t\t(e)\n#define lua_longassert(c)\t((void)0)\n#endif\n\n/*\n** assertion for checking API calls\n*/\n#if !defined(luai_apicheck)\n#define luai_apicheck(l,e)\tlua_assert(e)\n#endif\n\n#define api_check(l,e,msg)\tluai_apicheck(l,(e) && msg)\n\n\n/* macro to avoid warnings about unused variables */\n#if !defined(UNUSED)\n#define UNUSED(x)\t((void)(x))\n#endif\n\n\n/* type casts (a macro highlights casts in the code) */\n#define cast(t, exp)\t((t)(exp))\n\n#define cast_void(i)\tcast(void, (i))\n#define cast_byte(i)\tcast(lu_byte, (i))\n#define cast_num(i)\tcast(lua_Number, (i))\n#define cast_int(i)\tcast(int, (i))\n#define cast_uchar(i)\tcast(unsigned char, (i))\n\n\n/* cast a signed lua_Integer to lua_Unsigned */\n#if !defined(l_castS2U)\n#define l_castS2U(i)\t((lua_Unsigned)(i))\n#endif\n\n/*\n** cast a lua_Unsigned to a signed lua_Integer; this cast is\n** not strict ISO C, but two-complement architectures should\n** work fine.\n*/\n#if !defined(l_castU2S)\n#define l_castU2S(i)\t((lua_Integer)(i))\n#endif\n\n\n/*\n** non-return type\n*/\n#if defined(__GNUC__)\n#define l_noret\t\tvoid __attribute__((noreturn))\n#elif defined(_MSC_VER) && _MSC_VER >= 1200\n#define l_noret\t\tvoid __declspec(noreturn)\n#else\n#define l_noret\t\tvoid\n#endif\n\n\n\n/*\n** maximum depth for nested C calls and syntactical nested non-terminals\n** in a program. (Value must fit in an unsigned short int.)\n*/\n#if !defined(LUAI_MAXCCALLS)\n#define LUAI_MAXCCALLS\t\t200\n#endif\n\n\n\n/*\n** type for virtual-machine instructions;\n** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)\n*/\n#if LUAI_BITSINT >= 32\ntypedef unsigned int Instruction;\n#else\ntypedef unsigned long Instruction;\n#endif\n\n\n\n/*\n** Maximum length for short strings, that is, strings that are\n** internalized. (Cannot be smaller than reserved words or tags for\n** metamethods, as these strings must be internalized;\n** #(\"function\") = 8, #(\"__newindex\") = 10.)\n*/\n#if !defined(LUAI_MAXSHORTLEN)\n#define LUAI_MAXSHORTLEN\t40\n#endif\n\n\n/*\n** Initial size for the string table (must be power of 2).\n** The Lua core alone registers ~50 strings (reserved words +\n** metaevent keys + a few others). Libraries would typically add\n** a few dozens more.\n*/\n#if !defined(MINSTRTABSIZE)\n#define MINSTRTABSIZE\t128\n#endif\n\n\n/*\n** Size of cache for strings in the API. 'N' is the number of\n** sets (better be a prime) and \"M\" is the size of each set (M == 1\n** makes a direct cache.)\n*/\n#if !defined(STRCACHE_N)\n#define STRCACHE_N\t\t53\n#define STRCACHE_M\t\t2\n#endif\n\n\n/* minimum size for string buffer */\n#if !defined(LUA_MINBUFFER)\n#define LUA_MINBUFFER\t32\n#endif\n\n\n/*\n** macros that are executed whenever program enters the Lua core\n** ('lua_lock') and leaves the core ('lua_unlock')\n*/\n#if !defined(lua_lock)\n#define lua_lock(L)\t((void) 0)\n#define lua_unlock(L)\t((void) 0)\n#endif\n\n/*\n** macro executed during Lua functions at points where the\n** function can yield.\n*/\n#if !defined(luai_threadyield)\n#define luai_threadyield(L)\t{lua_unlock(L); lua_lock(L);}\n#endif\n\n\n/*\n** these macros allow user-specific actions on threads when you defined\n** LUAI_EXTRASPACE and need to do something extra when a thread is\n** created/deleted/resumed/yielded.\n*/\n#if !defined(luai_userstateopen)\n#define luai_userstateopen(L)\t\t((void)L)\n#endif\n\n#if !defined(luai_userstateclose)\n#define luai_userstateclose(L)\t\t((void)L)\n#endif\n\n#if !defined(luai_userstatethread)\n#define luai_userstatethread(L,L1)\t((void)L)\n#endif\n\n#if !defined(luai_userstatefree)\n#define luai_userstatefree(L,L1)\t((void)L)\n#endif\n\n#if !defined(luai_userstateresume)\n#define luai_userstateresume(L,n)\t((void)L)\n#endif\n\n#if !defined(luai_userstateyield)\n#define luai_userstateyield(L,n)\t((void)L)\n#endif\n\n\n\n/*\n** The luai_num* macros define the primitive operations over numbers.\n*/\n\n/* floor division (defined as 'floor(a/b)') */\n#if !defined(luai_numidiv)\n#define luai_numidiv(L,a,b)     ((void)L, l_floor(luai_numdiv(L,a,b)))\n#endif\n\n/* float division */\n#if !defined(luai_numdiv)\n#define luai_numdiv(L,a,b)      ((a)/(b))\n#endif\n\n/*\n** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when\n** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of\n** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b)\n** ~= floor(a/b)'. That happens when the division has a non-integer\n** negative result, which is equivalent to the test below.\n*/\n#if !defined(luai_nummod)\n#define luai_nummod(L,a,b,m)  \\\n  { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }\n#endif\n\n/* exponentiation */\n#if !defined(luai_numpow)\n#define luai_numpow(L,a,b)      ((void)L, l_mathop(pow)(a,b))\n#endif\n\n/* the others are quite standard operations */\n#if !defined(luai_numadd)\n#define luai_numadd(L,a,b)      ((a)+(b))\n#define luai_numsub(L,a,b)      ((a)-(b))\n#define luai_nummul(L,a,b)      ((a)*(b))\n#define luai_numunm(L,a)        (-(a))\n#define luai_numeq(a,b)         ((a)==(b))\n#define luai_numlt(a,b)         ((a)<(b))\n#define luai_numle(a,b)         ((a)<=(b))\n#define luai_numisnan(a)        (!luai_numeq((a), (a)))\n#endif\n\n\n\n\n\n/*\n** macro to control inclusion of some hard tests on stack reallocation\n*/\n#if !defined(HARDSTACKTESTS)\n#define condmovestack(L,pre,pos)\t((void)0)\n#else\n/* realloc stack keeping its size */\n#define condmovestack(L,pre,pos)  \\\n\t{ int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; }\n#endif\n\n#if !defined(HARDMEMTESTS)\n#define condchangemem(L,pre,pos)\t((void)0)\n#else\n#define condchangemem(L,pre,pos)  \\\n\t{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }\n#endif\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lmathlib.c",
    "content": "/*\n** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $\n** Standard mathematical library\n** See Copyright Notice in lua.h\n*/\n\n#define lmathlib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <stdlib.h>\n#include <math.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n#undef PI\n#define PI\t(l_mathop(3.141592653589793238462643383279502884))\n\n\n#if !defined(l_rand)\t\t/* { */\n#if defined(LUA_USE_POSIX)\n#define l_rand()\trandom()\n#define l_srand(x)\tsrandom(x)\n#define L_RANDMAX\t2147483647\t/* (2^31 - 1), following POSIX */\n#else\n#define l_rand()\trand()\n#define l_srand(x)\tsrand(x)\n#define L_RANDMAX\tRAND_MAX\n#endif\n#endif\t\t\t\t/* } */\n\n\nstatic int math_abs (lua_State *L) {\n  if (lua_isinteger(L, 1)) {\n    lua_Integer n = lua_tointeger(L, 1);\n    if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);\n    lua_pushinteger(L, n);\n  }\n  else\n    lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_sin (lua_State *L) {\n  lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_cos (lua_State *L) {\n  lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_tan (lua_State *L) {\n  lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_asin (lua_State *L) {\n  lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_acos (lua_State *L) {\n  lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_atan (lua_State *L) {\n  lua_Number y = luaL_checknumber(L, 1);\n  lua_Number x = luaL_optnumber(L, 2, 1);\n  lua_pushnumber(L, l_mathop(atan2)(y, x));\n  return 1;\n}\n\n\nstatic int math_toint (lua_State *L) {\n  int valid;\n  lua_Integer n = lua_tointegerx(L, 1, &valid);\n  if (valid)\n    lua_pushinteger(L, n);\n  else {\n    luaL_checkany(L, 1);\n    lua_pushnil(L);  /* value is not convertible to integer */\n  }\n  return 1;\n}\n\n\nstatic void pushnumint (lua_State *L, lua_Number d) {\n  lua_Integer n;\n  if (lua_numbertointeger(d, &n))  /* does 'd' fit in an integer? */\n    lua_pushinteger(L, n);  /* result is integer */\n  else\n    lua_pushnumber(L, d);  /* result is float */\n}\n\n\nstatic int math_floor (lua_State *L) {\n  if (lua_isinteger(L, 1))\n    lua_settop(L, 1);  /* integer is its own floor */\n  else {\n    lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1));\n    pushnumint(L, d);\n  }\n  return 1;\n}\n\n\nstatic int math_ceil (lua_State *L) {\n  if (lua_isinteger(L, 1))\n    lua_settop(L, 1);  /* integer is its own ceil */\n  else {\n    lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));\n    pushnumint(L, d);\n  }\n  return 1;\n}\n\n\nstatic int math_fmod (lua_State *L) {\n  if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) {\n    lua_Integer d = lua_tointeger(L, 2);\n    if ((lua_Unsigned)d + 1u <= 1u) {  /* special cases: -1 or 0 */\n      luaL_argcheck(L, d != 0, 2, \"zero\");\n      lua_pushinteger(L, 0);  /* avoid overflow with 0x80000... / -1 */\n    }\n    else\n      lua_pushinteger(L, lua_tointeger(L, 1) % d);\n  }\n  else\n    lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),\n                                     luaL_checknumber(L, 2)));\n  return 1;\n}\n\n\n/*\n** next function does not use 'modf', avoiding problems with 'double*'\n** (which is not compatible with 'float*') when lua_Number is not\n** 'double'.\n*/\nstatic int math_modf (lua_State *L) {\n  if (lua_isinteger(L ,1)) {\n    lua_settop(L, 1);  /* number is its own integer part */\n    lua_pushnumber(L, 0);  /* no fractional part */\n  }\n  else {\n    lua_Number n = luaL_checknumber(L, 1);\n    /* integer part (rounds toward zero) */\n    lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n);\n    pushnumint(L, ip);\n    /* fractional part (test needed for inf/-inf) */\n    lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip));\n  }\n  return 2;\n}\n\n\nstatic int math_sqrt (lua_State *L) {\n  lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\n\nstatic int math_ult (lua_State *L) {\n  lua_Integer a = luaL_checkinteger(L, 1);\n  lua_Integer b = luaL_checkinteger(L, 2);\n  lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b);\n  return 1;\n}\n\nstatic int math_log (lua_State *L) {\n  lua_Number x = luaL_checknumber(L, 1);\n  lua_Number res;\n  if (lua_isnoneornil(L, 2))\n    res = l_mathop(log)(x);\n  else {\n    lua_Number base = luaL_checknumber(L, 2);\n#if !defined(LUA_USE_C89)\n    if (base == l_mathop(2.0))\n      res = l_mathop(log2)(x); else\n#endif\n    if (base == l_mathop(10.0))\n      res = l_mathop(log10)(x);\n    else\n      res = l_mathop(log)(x)/l_mathop(log)(base);\n  }\n  lua_pushnumber(L, res);\n  return 1;\n}\n\nstatic int math_exp (lua_State *L) {\n  lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_deg (lua_State *L) {\n  lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));\n  return 1;\n}\n\nstatic int math_rad (lua_State *L) {\n  lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));\n  return 1;\n}\n\n\nstatic int math_min (lua_State *L) {\n  int n = lua_gettop(L);  /* number of arguments */\n  int imin = 1;  /* index of current minimum value */\n  int i;\n  luaL_argcheck(L, n >= 1, 1, \"value expected\");\n  for (i = 2; i <= n; i++) {\n    if (lua_compare(L, i, imin, LUA_OPLT))\n      imin = i;\n  }\n  lua_pushvalue(L, imin);\n  return 1;\n}\n\n\nstatic int math_max (lua_State *L) {\n  int n = lua_gettop(L);  /* number of arguments */\n  int imax = 1;  /* index of current maximum value */\n  int i;\n  luaL_argcheck(L, n >= 1, 1, \"value expected\");\n  for (i = 2; i <= n; i++) {\n    if (lua_compare(L, imax, i, LUA_OPLT))\n      imax = i;\n  }\n  lua_pushvalue(L, imax);\n  return 1;\n}\n\n/*\n** This function uses 'double' (instead of 'lua_Number') to ensure that\n** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0'\n** will keep full precision (ensuring that 'r' is always less than 1.0.)\n*/\nstatic int math_random (lua_State *L) {\n  lua_Integer low, up;\n  double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0));\n  switch (lua_gettop(L)) {  /* check number of arguments */\n    case 0: {  /* no arguments */\n      lua_pushnumber(L, (lua_Number)r);  /* Number between 0 and 1 */\n      return 1;\n    }\n    case 1: {  /* only upper limit */\n      low = 1;\n      up = luaL_checkinteger(L, 1);\n      break;\n    }\n    case 2: {  /* lower and upper limits */\n      low = luaL_checkinteger(L, 1);\n      up = luaL_checkinteger(L, 2);\n      break;\n    }\n    default: return luaL_error(L, \"wrong number of arguments\");\n  }\n  /* random integer in the interval [low, up] */\n  luaL_argcheck(L, low <= up, 1, \"interval is empty\");\n  luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,\n                   \"interval too large\");\n  r *= (double)(up - low) + 1.0;\n  lua_pushinteger(L, (lua_Integer)r + low);\n  return 1;\n}\n\n\nstatic int math_randomseed (lua_State *L) {\n  l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));\n  (void)l_rand(); /* discard first value to avoid undesirable correlations */\n  return 0;\n}\n\n\nstatic int math_type (lua_State *L) {\n  if (lua_type(L, 1) == LUA_TNUMBER) {\n      if (lua_isinteger(L, 1))\n        lua_pushliteral(L, \"integer\");\n      else\n        lua_pushliteral(L, \"float\");\n  }\n  else {\n    luaL_checkany(L, 1);\n    lua_pushnil(L);\n  }\n  return 1;\n}\n\n\n/*\n** {==================================================================\n** Deprecated functions (for compatibility only)\n** ===================================================================\n*/\n#if defined(LUA_COMPAT_MATHLIB)\n\nstatic int math_cosh (lua_State *L) {\n  lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_sinh (lua_State *L) {\n  lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_tanh (lua_State *L) {\n  lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\nstatic int math_pow (lua_State *L) {\n  lua_Number x = luaL_checknumber(L, 1);\n  lua_Number y = luaL_checknumber(L, 2);\n  lua_pushnumber(L, l_mathop(pow)(x, y));\n  return 1;\n}\n\nstatic int math_frexp (lua_State *L) {\n  int e;\n  lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));\n  lua_pushinteger(L, e);\n  return 2;\n}\n\nstatic int math_ldexp (lua_State *L) {\n  lua_Number x = luaL_checknumber(L, 1);\n  int ep = (int)luaL_checkinteger(L, 2);\n  lua_pushnumber(L, l_mathop(ldexp)(x, ep));\n  return 1;\n}\n\nstatic int math_log10 (lua_State *L) {\n  lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));\n  return 1;\n}\n\n#endif\n/* }================================================================== */\n\n\n\nstatic const luaL_Reg mathlib[] = {\n  {\"abs\",   math_abs},\n  {\"acos\",  math_acos},\n  {\"asin\",  math_asin},\n  {\"atan\",  math_atan},\n  {\"ceil\",  math_ceil},\n  {\"cos\",   math_cos},\n  {\"deg\",   math_deg},\n  {\"exp\",   math_exp},\n  {\"tointeger\", math_toint},\n  {\"floor\", math_floor},\n  {\"fmod\",   math_fmod},\n  {\"ult\",   math_ult},\n  {\"log\",   math_log},\n  {\"max\",   math_max},\n  {\"min\",   math_min},\n  {\"modf\",   math_modf},\n  {\"rad\",   math_rad},\n  {\"random\",     math_random},\n  {\"randomseed\", math_randomseed},\n  {\"sin\",   math_sin},\n  {\"sqrt\",  math_sqrt},\n  {\"tan\",   math_tan},\n  {\"type\", math_type},\n#if defined(LUA_COMPAT_MATHLIB)\n  {\"atan2\", math_atan},\n  {\"cosh\",   math_cosh},\n  {\"sinh\",   math_sinh},\n  {\"tanh\",   math_tanh},\n  {\"pow\",   math_pow},\n  {\"frexp\", math_frexp},\n  {\"ldexp\", math_ldexp},\n  {\"log10\", math_log10},\n#endif\n  /* placeholders */\n  {\"pi\", NULL},\n  {\"huge\", NULL},\n  {\"maxinteger\", NULL},\n  {\"mininteger\", NULL},\n  {NULL, NULL}\n};\n\n\n/*\n** Open math library\n*/\nLUAMOD_API int luaopen_math (lua_State *L) {\n  luaL_newlib(L, mathlib);\n  lua_pushnumber(L, PI);\n  lua_setfield(L, -2, \"pi\");\n  lua_pushnumber(L, (lua_Number)HUGE_VAL);\n  lua_setfield(L, -2, \"huge\");\n  lua_pushinteger(L, LUA_MAXINTEGER);\n  lua_setfield(L, -2, \"maxinteger\");\n  lua_pushinteger(L, LUA_MININTEGER);\n  lua_setfield(L, -2, \"mininteger\");\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lmem.c",
    "content": "/*\n** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $\n** Interface to Memory Manager\n** See Copyright Notice in lua.h\n*/\n\n#define lmem_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stddef.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lgc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n\n\n\n/*\n** About the realloc function:\n** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);\n** ('osize' is the old size, 'nsize' is the new size)\n**\n** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no\n** matter 'x').\n**\n** * frealloc(ud, p, x, 0) frees the block 'p'\n** (in this specific case, frealloc must return NULL);\n** particularly, frealloc(ud, NULL, 0, 0) does nothing\n** (which is equivalent to free(NULL) in ISO C)\n**\n** frealloc returns NULL if it cannot create or reallocate the area\n** (any reallocation to an equal or smaller size cannot fail!)\n*/\n\n\n\n#define MINSIZEARRAY\t4\n\n\nvoid *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,\n                     int limit, const char *what) {\n  void *newblock;\n  int newsize;\n  if (*size >= limit/2) {  /* cannot double it? */\n    if (*size >= limit)  /* cannot grow even a little? */\n      luaG_runerror(L, \"too many %s (limit is %d)\", what, limit);\n    newsize = limit;  /* still have at least one free place */\n  }\n  else {\n    newsize = (*size)*2;\n    if (newsize < MINSIZEARRAY)\n      newsize = MINSIZEARRAY;  /* minimum size */\n  }\n  newblock = luaM_reallocv(L, block, *size, newsize, size_elems);\n  *size = newsize;  /* update only when everything else is OK */\n  return newblock;\n}\n\n\nl_noret luaM_toobig (lua_State *L) {\n  luaG_runerror(L, \"memory allocation error: block too big\");\n}\n\n\n\n/*\n** generic allocation routine.\n*/\nvoid *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {\n  void *newblock;\n  global_State *g = G(L);\n  size_t realosize = (block) ? osize : 0;\n  lua_assert((realosize == 0) == (block == NULL));\n#if defined(HARDMEMTESTS)\n  if (nsize > realosize && g->gcrunning)\n    luaC_fullgc(L, 1);  /* force a GC whenever possible */\n#endif\n  newblock = (*g->frealloc)(g->ud, block, osize, nsize);\n  if (newblock == NULL && nsize > 0) {\n    lua_assert(nsize > realosize);  /* cannot fail when shrinking a block */\n    if (g->version) {  /* is state fully built? */\n      luaC_fullgc(L, 1);  /* try to free some memory... */\n      newblock = (*g->frealloc)(g->ud, block, osize, nsize);  /* try again */\n    }\n    if (newblock == NULL)\n      luaD_throw(L, LUA_ERRMEM);\n  }\n  lua_assert((nsize == 0) == (newblock == NULL));\n  g->GCdebt = (g->GCdebt + nsize) - realosize;\n  return newblock;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lmem.h",
    "content": "/*\n** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $\n** Interface to Memory Manager\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lmem_h\n#define lmem_h\n\n\n#include <stddef.h>\n\n#include \"llimits.h\"\n#include \"lua.h\"\n\n\n/*\n** This macro reallocs a vector 'b' from 'on' to 'n' elements, where\n** each element has size 'e'. In case of arithmetic overflow of the\n** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because\n** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e).\n**\n** (The macro is somewhat complex to avoid warnings:  The 'sizeof'\n** comparison avoids a runtime comparison when overflow cannot occur.\n** The compiler should be able to optimize the real test by itself, but\n** when it does it, it may give a warning about \"comparison is always\n** false due to limited range of data type\"; the +1 tricks the compiler,\n** avoiding this warning but also this optimization.)\n*/\n#define luaM_reallocv(L,b,on,n,e) \\\n  (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \\\n      ? luaM_toobig(L) : cast_void(0)) , \\\n   luaM_realloc_(L, (b), (on)*(e), (n)*(e)))\n\n/*\n** Arrays of chars do not need any test\n*/\n#define luaM_reallocvchar(L,b,on,n)  \\\n    cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char)))\n\n#define luaM_freemem(L, b, s)\tluaM_realloc_(L, (b), (s), 0)\n#define luaM_free(L, b)\t\tluaM_realloc_(L, (b), sizeof(*(b)), 0)\n#define luaM_freearray(L, b, n)   luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0)\n\n#define luaM_malloc(L,s)\tluaM_realloc_(L, NULL, 0, (s))\n#define luaM_new(L,t)\t\tcast(t *, luaM_malloc(L, sizeof(t)))\n#define luaM_newvector(L,n,t) \\\n\t\tcast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))\n\n#define luaM_newobject(L,tag,s)\tluaM_realloc_(L, NULL, tag, (s))\n\n#define luaM_growvector(L,v,nelems,size,t,limit,e) \\\n          if ((nelems)+1 > (size)) \\\n            ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))\n\n#define luaM_reallocvector(L, v,oldn,n,t) \\\n   ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))\n\nLUAI_FUNC l_noret luaM_toobig (lua_State *L);\n\n/* not to be called directly */\nLUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,\n                                                          size_t size);\nLUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,\n                               size_t size_elem, int limit,\n                               const char *what);\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/loadlib.c",
    "content": "/*\n** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $\n** Dynamic library loader for Lua\n** See Copyright Notice in lua.h\n**\n** This module contains an implementation of loadlib for Unix systems\n** that have dlfcn, an implementation for Windows, and a stub for other\n** systems.\n*/\n\n#define loadlib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n/*\n** LUA_IGMARK is a mark to ignore all before it when building the\n** luaopen_ function name.\n*/\n#if !defined (LUA_IGMARK)\n#define LUA_IGMARK\t\t\"-\"\n#endif\n\n\n/*\n** LUA_CSUBSEP is the character that replaces dots in submodule names\n** when searching for a C loader.\n** LUA_LSUBSEP is the character that replaces dots in submodule names\n** when searching for a Lua loader.\n*/\n#if !defined(LUA_CSUBSEP)\n#define LUA_CSUBSEP\t\tLUA_DIRSEP\n#endif\n\n#if !defined(LUA_LSUBSEP)\n#define LUA_LSUBSEP\t\tLUA_DIRSEP\n#endif\n\n\n/* prefix for open functions in C libraries */\n#define LUA_POF\t\t\"luaopen_\"\n\n/* separator for open functions in C libraries */\n#define LUA_OFSEP\t\"_\"\n\n\n/*\n** unique key for table in the registry that keeps handles\n** for all loaded C libraries\n*/\nstatic const int CLIBS = 0;\n\n#define LIB_FAIL\t\"open\"\n\n\n#define setprogdir(L)           ((void)0)\n\n\n/*\n** system-dependent functions\n*/\n\n/*\n** unload library 'lib'\n*/\nstatic void lsys_unloadlib (void *lib);\n\n/*\n** load C library in file 'path'. If 'seeglb', load with all names in\n** the library global.\n** Returns the library; in case of error, returns NULL plus an\n** error string in the stack.\n*/\nstatic void *lsys_load (lua_State *L, const char *path, int seeglb);\n\n/*\n** Try to find a function named 'sym' in library 'lib'.\n** Returns the function; in case of error, returns NULL plus an\n** error string in the stack.\n*/\nstatic lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);\n\n\n\n\n#if defined(LUA_USE_DLOPEN)\t/* { */\n/*\n** {========================================================================\n** This is an implementation of loadlib based on the dlfcn interface.\n** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,\n** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least\n** as an emulation layer on top of native functions.\n** =========================================================================\n*/\n\n#include <dlfcn.h>\n\n/*\n** Macro to convert pointer-to-void* to pointer-to-function. This cast\n** is undefined according to ISO C, but POSIX assumes that it works.\n** (The '__extension__' in gnu compilers is only to avoid warnings.)\n*/\n#if defined(__GNUC__)\n#define cast_func(p) (__extension__ (lua_CFunction)(p))\n#else\n#define cast_func(p) ((lua_CFunction)(p))\n#endif\n\n\nstatic void lsys_unloadlib (void *lib) {\n  dlclose(lib);\n}\n\n\nstatic void *lsys_load (lua_State *L, const char *path, int seeglb) {\n  void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));\n  if (lib == NULL) lua_pushstring(L, dlerror());\n  return lib;\n}\n\n\nstatic lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {\n  lua_CFunction f = cast_func(dlsym(lib, sym));\n  if (f == NULL) lua_pushstring(L, dlerror());\n  return f;\n}\n\n/* }====================================================== */\n\n\n\n#elif defined(LUA_DL_DLL)\t/* }{ */\n/*\n** {======================================================================\n** This is an implementation of loadlib for Windows using native functions.\n** =======================================================================\n*/\n\n#include <windows.h>\n\n\n/*\n** optional flags for LoadLibraryEx\n*/\n#if !defined(LUA_LLE_FLAGS)\n#define LUA_LLE_FLAGS\t0\n#endif\n\n\n#undef setprogdir\n\n\n/*\n** Replace in the path (on the top of the stack) any occurrence\n** of LUA_EXEC_DIR with the executable's path.\n*/\nstatic void setprogdir (lua_State *L) {\n  char buff[MAX_PATH + 1];\n  char *lb;\n  DWORD nsize = sizeof(buff)/sizeof(char);\n  DWORD n = GetModuleFileNameA(NULL, buff, nsize);  /* get exec. name */\n  if (n == 0 || n == nsize || (lb = strrchr(buff, '\\\\')) == NULL)\n    luaL_error(L, \"unable to get ModuleFileName\");\n  else {\n    *lb = '\\0';  /* cut name on the last '\\\\' to get the path */\n    luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);\n    lua_remove(L, -2);  /* remove original string */\n  }\n}\n\n\n\n\nstatic void pusherror (lua_State *L) {\n  int error = GetLastError();\n#if HC_PLATFORM != HC_PLATFORM_XDK\n  char buffer[128];\n  if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,\n      NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL))\n    lua_pushstring(L, buffer);\n  else\n#endif\n    lua_pushfstring(L, \"system error %d\\n\", error);\n}\n\nstatic void lsys_unloadlib (void *lib) {\n  FreeLibrary((HMODULE)lib);\n}\n\n\nstatic void *lsys_load (lua_State *L, const char *path, int seeglb) {\n#if !APIEXPLORER_UWP\n  HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS);\n  (void)(seeglb);  /* not used: symbols are 'global' by default */\n  if (lib == NULL) pusherror(L);\n  return lib;\n#else\n    pusherror(L);\n    return nullptr;\n#endif\n}\n\n\nstatic lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {\n  lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym);\n  if (f == NULL) pusherror(L);\n  return f;\n}\n\n/* }====================================================== */\n\n\n#else\t\t\t\t/* }{ */\n/*\n** {======================================================\n** Fallback for other systems\n** =======================================================\n*/\n\n#undef LIB_FAIL\n#define LIB_FAIL\t\"absent\"\n\n\n#define DLMSG\t\"dynamic libraries not enabled; check your Lua installation\"\n\n\nstatic void lsys_unloadlib (void *lib) {\n  (void)(lib);  /* not used */\n}\n\n\nstatic void *lsys_load (lua_State *L, const char *path, int seeglb) {\n  (void)(path); (void)(seeglb);  /* not used */\n  lua_pushliteral(L, DLMSG);\n  return NULL;\n}\n\n\nstatic lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {\n  (void)(lib); (void)(sym);  /* not used */\n  lua_pushliteral(L, DLMSG);\n  return NULL;\n}\n\n/* }====================================================== */\n#endif\t\t\t\t/* } */\n\n\n/*\n** {==================================================================\n** Set Paths\n** ===================================================================\n*/\n\n/*\n** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment\n** variables that Lua check to set its paths.\n*/\n#if !defined(LUA_PATH_VAR)\n#define LUA_PATH_VAR    \"LUA_PATH\"\n#endif\n\n#if !defined(LUA_CPATH_VAR)\n#define LUA_CPATH_VAR   \"LUA_CPATH\"\n#endif\n\n\n#define AUXMARK         \"\\1\"\t/* auxiliary mark */\n\n\n/*\n** return registry.LUA_NOENV as a boolean\n*/\nstatic int noenv (lua_State *L) {\n  int b;\n  lua_getfield(L, LUA_REGISTRYINDEX, \"LUA_NOENV\");\n  b = lua_toboolean(L, -1);\n  lua_pop(L, 1);  /* remove value */\n  return b;\n}\n\n\n/*\n** Set a path\n*/\nstatic void setpath (lua_State *L, const char *fieldname,\n                                   const char *envname,\n                                   const char *dft) {\n  const char *nver = lua_pushfstring(L, \"%s%s\", envname, LUA_VERSUFFIX);\n#if HC_PLATFORM != HC_PLATFORM_XDK\n  const char *path = getenv(nver);  /* use versioned name */\n  if (path == NULL)  /* no environment variable? */\n    path = getenv(envname);  /* try unversioned name */\n#else\n  UNREFERENCED_PARAMETER(nver);\n  const char *path = NULL;\n#endif\n  if (path == NULL || noenv(L))  /* no environment variable? */\n    lua_pushstring(L, dft);  /* use default */\n  else {\n    /* replace \";;\" by \";AUXMARK;\" and then AUXMARK by default path */\n    path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,\n                              LUA_PATH_SEP AUXMARK LUA_PATH_SEP);\n    luaL_gsub(L, path, AUXMARK, dft);\n    lua_remove(L, -2); /* remove result from 1st 'gsub' */\n  }\n  setprogdir(L);\n  lua_setfield(L, -3, fieldname);  /* package[fieldname] = path value */\n  lua_pop(L, 1);  /* pop versioned variable name */\n}\n\n/* }================================================================== */\n\n\n/*\n** return registry.CLIBS[path]\n*/\nstatic void *checkclib (lua_State *L, const char *path) {\n  void *plib;\n  lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);\n  lua_getfield(L, -1, path);\n  plib = lua_touserdata(L, -1);  /* plib = CLIBS[path] */\n  lua_pop(L, 2);  /* pop CLIBS table and 'plib' */\n  return plib;\n}\n\n\n/*\n** registry.CLIBS[path] = plib        -- for queries\n** registry.CLIBS[#CLIBS + 1] = plib  -- also keep a list of all libraries\n*/\nstatic void addtoclib (lua_State *L, const char *path, void *plib) {\n  lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);\n  lua_pushlightuserdata(L, plib);\n  lua_pushvalue(L, -1);\n  lua_setfield(L, -3, path);  /* CLIBS[path] = plib */\n  lua_rawseti(L, -2, luaL_len(L, -2) + 1);  /* CLIBS[#CLIBS + 1] = plib */\n  lua_pop(L, 1);  /* pop CLIBS table */\n}\n\n\n/*\n** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib\n** handles in list CLIBS\n*/\nstatic int gctm (lua_State *L) {\n  lua_Integer n = luaL_len(L, 1);\n  for (; n >= 1; n--) {  /* for each handle, in reverse order */\n    lua_rawgeti(L, 1, n);  /* get handle CLIBS[n] */\n    lsys_unloadlib(lua_touserdata(L, -1));\n    lua_pop(L, 1);  /* pop handle */\n  }\n  return 0;\n}\n\n\n\n/* error codes for 'lookforfunc' */\n#define ERRLIB\t\t1\n#define ERRFUNC\t\t2\n\n/*\n** Look for a C function named 'sym' in a dynamically loaded library\n** 'path'.\n** First, check whether the library is already loaded; if not, try\n** to load it.\n** Then, if 'sym' is '*', return true (as library has been loaded).\n** Otherwise, look for symbol 'sym' in the library and push a\n** C function with that symbol.\n** Return 0 and 'true' or a function in the stack; in case of\n** errors, return an error code and an error message in the stack.\n*/\nstatic int lookforfunc (lua_State *L, const char *path, const char *sym) {\n  void *reg = checkclib(L, path);  /* check loaded C libraries */\n  if (reg == NULL) {  /* must load library? */\n    reg = lsys_load(L, path, *sym == '*');  /* global symbols if 'sym'=='*' */\n    if (reg == NULL) return ERRLIB;  /* unable to load library */\n    addtoclib(L, path, reg);\n  }\n  if (*sym == '*') {  /* loading only library (no function)? */\n    lua_pushboolean(L, 1);  /* return 'true' */\n    return 0;  /* no errors */\n  }\n  else {\n    lua_CFunction f = lsys_sym(L, reg, sym);\n    if (f == NULL)\n      return ERRFUNC;  /* unable to find function */\n    lua_pushcfunction(L, f);  /* else create new function */\n    return 0;  /* no errors */\n  }\n}\n\n\nstatic int ll_loadlib (lua_State *L) {\n  const char *path = luaL_checkstring(L, 1);\n  const char *init = luaL_checkstring(L, 2);\n  int stat = lookforfunc(L, path, init);\n  if (stat == 0)  /* no errors? */\n    return 1;  /* return the loaded function */\n  else {  /* error; error message is on stack top */\n    lua_pushnil(L);\n    lua_insert(L, -2);\n    lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : \"init\");\n    return 3;  /* return nil, error message, and where */\n  }\n}\n\n\n\n/*\n** {======================================================\n** 'require' function\n** =======================================================\n*/\n\n\nstatic int readable (const char *filename) {\n  FILE *f = fopen(filename, \"r\");  /* try to open file */\n  if (f == NULL) return 0;  /* open failed */\n  fclose(f);\n  return 1;\n}\n\n\nstatic const char *pushnexttemplate (lua_State *L, const char *path) {\n  const char *l;\n  while (*path == *LUA_PATH_SEP) path++;  /* skip separators */\n  if (*path == '\\0') return NULL;  /* no more templates */\n  l = strchr(path, *LUA_PATH_SEP);  /* find next separator */\n  if (l == NULL) l = path + strlen(path);\n  lua_pushlstring(L, path, l - path);  /* template */\n  return l;\n}\n\n\nstatic const char *searchpath (lua_State *L, const char *name,\n                                             const char *path,\n                                             const char *sep,\n                                             const char *dirsep) {\n  luaL_Buffer msg;  /* to build error message */\n  luaL_buffinit(L, &msg);\n  if (*sep != '\\0')  /* non-empty separator? */\n    name = luaL_gsub(L, name, sep, dirsep);  /* replace it by 'dirsep' */\n  while ((path = pushnexttemplate(L, path)) != NULL) {\n    const char *filename = luaL_gsub(L, lua_tostring(L, -1),\n                                     LUA_PATH_MARK, name);\n    lua_remove(L, -2);  /* remove path template */\n    if (readable(filename))  /* does file exist and is readable? */\n      return filename;  /* return that file name */\n    lua_pushfstring(L, \"\\n\\tno file '%s'\", filename);\n    lua_remove(L, -2);  /* remove file name */\n    luaL_addvalue(&msg);  /* concatenate error msg. entry */\n  }\n  luaL_pushresult(&msg);  /* create error message */\n  return NULL;  /* not found */\n}\n\n\nstatic int ll_searchpath (lua_State *L) {\n  const char *f = searchpath(L, luaL_checkstring(L, 1),\n                                luaL_checkstring(L, 2),\n                                luaL_optstring(L, 3, \".\"),\n                                luaL_optstring(L, 4, LUA_DIRSEP));\n  if (f != NULL) return 1;\n  else {  /* error message is on top of the stack */\n    lua_pushnil(L);\n    lua_insert(L, -2);\n    return 2;  /* return nil + error message */\n  }\n}\n\n\nstatic const char *findfile (lua_State *L, const char *name,\n                                           const char *pname,\n                                           const char *dirsep) {\n  const char *path;\n  lua_getfield(L, lua_upvalueindex(1), pname);\n  path = lua_tostring(L, -1);\n  if (path == NULL)\n    luaL_error(L, \"'package.%s' must be a string\", pname);\n  return searchpath(L, name, path, \".\", dirsep);\n}\n\n\nstatic int checkload (lua_State *L, int stat, const char *filename) {\n  if (stat) {  /* module loaded successfully? */\n    lua_pushstring(L, filename);  /* will be 2nd argument to module */\n    return 2;  /* return open function and file name */\n  }\n  else\n    return luaL_error(L, \"error loading module '%s' from file '%s':\\n\\t%s\",\n                          lua_tostring(L, 1), filename, lua_tostring(L, -1));\n}\n\n\nstatic int searcher_Lua (lua_State *L) {\n  const char *filename;\n  const char *name = luaL_checkstring(L, 1);\n  filename = findfile(L, name, \"path\", LUA_LSUBSEP);\n  if (filename == NULL) return 1;  /* module not found in this path */\n  return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);\n}\n\n\n/*\n** Try to find a load function for module 'modname' at file 'filename'.\n** First, change '.' to '_' in 'modname'; then, if 'modname' has\n** the form X-Y (that is, it has an \"ignore mark\"), build a function\n** name \"luaopen_X\" and look for it. (For compatibility, if that\n** fails, it also tries \"luaopen_Y\".) If there is no ignore mark,\n** look for a function named \"luaopen_modname\".\n*/\nstatic int loadfunc (lua_State *L, const char *filename, const char *modname) {\n  const char *openfunc;\n  const char *mark;\n  modname = luaL_gsub(L, modname, \".\", LUA_OFSEP);\n  mark = strchr(modname, *LUA_IGMARK);\n  if (mark) {\n    int stat;\n    openfunc = lua_pushlstring(L, modname, mark - modname);\n    openfunc = lua_pushfstring(L, LUA_POF\"%s\", openfunc);\n    stat = lookforfunc(L, filename, openfunc);\n    if (stat != ERRFUNC) return stat;\n    modname = mark + 1;  /* else go ahead and try old-style name */\n  }\n  openfunc = lua_pushfstring(L, LUA_POF\"%s\", modname);\n  return lookforfunc(L, filename, openfunc);\n}\n\n\nstatic int searcher_C (lua_State *L) {\n  const char *name = luaL_checkstring(L, 1);\n  const char *filename = findfile(L, name, \"cpath\", LUA_CSUBSEP);\n  if (filename == NULL) return 1;  /* module not found in this path */\n  return checkload(L, (loadfunc(L, filename, name) == 0), filename);\n}\n\n\nstatic int searcher_Croot (lua_State *L) {\n  const char *filename;\n  const char *name = luaL_checkstring(L, 1);\n  const char *p = strchr(name, '.');\n  int stat;\n  if (p == NULL) return 0;  /* is root */\n  lua_pushlstring(L, name, p - name);\n  filename = findfile(L, lua_tostring(L, -1), \"cpath\", LUA_CSUBSEP);\n  if (filename == NULL) return 1;  /* root not found */\n  if ((stat = loadfunc(L, filename, name)) != 0) {\n    if (stat != ERRFUNC)\n      return checkload(L, 0, filename);  /* real error */\n    else {  /* open function not found */\n      lua_pushfstring(L, \"\\n\\tno module '%s' in file '%s'\", name, filename);\n      return 1;\n    }\n  }\n  lua_pushstring(L, filename);  /* will be 2nd argument to module */\n  return 2;\n}\n\n\nstatic int searcher_preload (lua_State *L) {\n  const char *name = luaL_checkstring(L, 1);\n  lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);\n  if (lua_getfield(L, -1, name) == LUA_TNIL)  /* not found? */\n    lua_pushfstring(L, \"\\n\\tno field package.preload['%s']\", name);\n  return 1;\n}\n\n\nstatic void findloader (lua_State *L, const char *name) {\n  int i;\n  luaL_Buffer msg;  /* to build error message */\n  luaL_buffinit(L, &msg);\n  /* push 'package.searchers' to index 3 in the stack */\n  if (lua_getfield(L, lua_upvalueindex(1), \"searchers\") != LUA_TTABLE)\n    luaL_error(L, \"'package.searchers' must be a table\");\n  /*  iterate over available searchers to find a loader */\n  for (i = 1; ; i++) {\n    if (lua_rawgeti(L, 3, i) == LUA_TNIL) {  /* no more searchers? */\n      lua_pop(L, 1);  /* remove nil */\n      luaL_pushresult(&msg);  /* create error message */\n      luaL_error(L, \"module '%s' not found:%s\", name, lua_tostring(L, -1));\n    }\n    lua_pushstring(L, name);\n    lua_call(L, 1, 2);  /* call it */\n    if (lua_isfunction(L, -2))  /* did it find a loader? */\n      return;  /* module loader found */\n    else if (lua_isstring(L, -2)) {  /* searcher returned error message? */\n      lua_pop(L, 1);  /* remove extra return */\n      luaL_addvalue(&msg);  /* concatenate error message */\n    }\n    else\n      lua_pop(L, 2);  /* remove both returns */\n  }\n}\n\n\nstatic int ll_require (lua_State *L) {\n  const char *name = luaL_checkstring(L, 1);\n  lua_settop(L, 1);  /* LOADED table will be at index 2 */\n  lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n  lua_getfield(L, 2, name);  /* LOADED[name] */\n  if (lua_toboolean(L, -1))  /* is it there? */\n    return 1;  /* package is already loaded */\n  /* else must load package */\n  lua_pop(L, 1);  /* remove 'getfield' result */\n  findloader(L, name);\n  lua_pushstring(L, name);  /* pass name as argument to module loader */\n  lua_insert(L, -2);  /* name is 1st argument (before search data) */\n  lua_call(L, 2, 1);  /* run loader to load module */\n  if (!lua_isnil(L, -1))  /* non-nil return? */\n    lua_setfield(L, 2, name);  /* LOADED[name] = returned value */\n  if (lua_getfield(L, 2, name) == LUA_TNIL) {   /* module set no value? */\n    lua_pushboolean(L, 1);  /* use true as result */\n    lua_pushvalue(L, -1);  /* extra copy to be returned */\n    lua_setfield(L, 2, name);  /* LOADED[name] = true */\n  }\n  return 1;\n}\n\n/* }====================================================== */\n\n\n\n/*\n** {======================================================\n** 'module' function\n** =======================================================\n*/\n#if defined(LUA_COMPAT_MODULE)\n\n/*\n** changes the environment variable of calling function\n*/\nstatic void set_env (lua_State *L) {\n  lua_Debug ar;\n  if (lua_getstack(L, 1, &ar) == 0 ||\n      lua_getinfo(L, \"f\", &ar) == 0 ||  /* get calling function */\n      lua_iscfunction(L, -1))\n    luaL_error(L, \"'module' not called from a Lua function\");\n  lua_pushvalue(L, -2);  /* copy new environment table to top */\n  lua_setupvalue(L, -2, 1);\n  lua_pop(L, 1);  /* remove function */\n}\n\n\nstatic void dooptions (lua_State *L, int n) {\n  int i;\n  for (i = 2; i <= n; i++) {\n    if (lua_isfunction(L, i)) {  /* avoid 'calling' extra info. */\n      lua_pushvalue(L, i);  /* get option (a function) */\n      lua_pushvalue(L, -2);  /* module */\n      lua_call(L, 1, 0);\n    }\n  }\n}\n\n\nstatic void modinit (lua_State *L, const char *modname) {\n  const char *dot;\n  lua_pushvalue(L, -1);\n  lua_setfield(L, -2, \"_M\");  /* module._M = module */\n  lua_pushstring(L, modname);\n  lua_setfield(L, -2, \"_NAME\");\n  dot = strrchr(modname, '.');  /* look for last dot in module name */\n  if (dot == NULL) dot = modname;\n  else dot++;\n  /* set _PACKAGE as package name (full module name minus last part) */\n  lua_pushlstring(L, modname, dot - modname);\n  lua_setfield(L, -2, \"_PACKAGE\");\n}\n\n\nstatic int ll_module (lua_State *L) {\n  const char *modname = luaL_checkstring(L, 1);\n  int lastarg = lua_gettop(L);  /* last parameter */\n  luaL_pushmodule(L, modname, 1);  /* get/create module table */\n  /* check whether table already has a _NAME field */\n  if (lua_getfield(L, -1, \"_NAME\") != LUA_TNIL)\n    lua_pop(L, 1);  /* table is an initialized module */\n  else {  /* no; initialize it */\n    lua_pop(L, 1);\n    modinit(L, modname);\n  }\n  lua_pushvalue(L, -1);\n  set_env(L);\n  dooptions(L, lastarg);\n  return 1;\n}\n\n\nstatic int ll_seeall (lua_State *L) {\n  luaL_checktype(L, 1, LUA_TTABLE);\n  if (!lua_getmetatable(L, 1)) {\n    lua_createtable(L, 0, 1); /* create new metatable */\n    lua_pushvalue(L, -1);\n    lua_setmetatable(L, 1);\n  }\n  lua_pushglobaltable(L);\n  lua_setfield(L, -2, \"__index\");  /* mt.__index = _G */\n  return 0;\n}\n\n#endif\n/* }====================================================== */\n\n\n\nstatic const luaL_Reg pk_funcs[] = {\n  {\"loadlib\", ll_loadlib},\n  {\"searchpath\", ll_searchpath},\n#if defined(LUA_COMPAT_MODULE)\n  {\"seeall\", ll_seeall},\n#endif\n  /* placeholders */\n  {\"preload\", NULL},\n  {\"cpath\", NULL},\n  {\"path\", NULL},\n  {\"searchers\", NULL},\n  {\"loaded\", NULL},\n  {NULL, NULL}\n};\n\n\nstatic const luaL_Reg ll_funcs[] = {\n#if defined(LUA_COMPAT_MODULE)\n  {\"module\", ll_module},\n#endif\n  {\"require\", ll_require},\n  {NULL, NULL}\n};\n\n\nstatic void createsearcherstable (lua_State *L) {\n  static const lua_CFunction searchers[] =\n    {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};\n  int i;\n  /* create 'searchers' table */\n  lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);\n  /* fill it with predefined searchers */\n  for (i=0; searchers[i] != NULL; i++) {\n    lua_pushvalue(L, -2);  /* set 'package' as upvalue for all searchers */\n    lua_pushcclosure(L, searchers[i], 1);\n    lua_rawseti(L, -2, i+1);\n  }\n#if defined(LUA_COMPAT_LOADERS)\n  lua_pushvalue(L, -1);  /* make a copy of 'searchers' table */\n  lua_setfield(L, -3, \"loaders\");  /* put it in field 'loaders' */\n#endif\n  lua_setfield(L, -2, \"searchers\");  /* put it in field 'searchers' */\n}\n\n\n/*\n** create table CLIBS to keep track of loaded C libraries,\n** setting a finalizer to close all libraries when closing state.\n*/\nstatic void createclibstable (lua_State *L) {\n  lua_newtable(L);  /* create CLIBS table */\n  lua_createtable(L, 0, 1);  /* create metatable for CLIBS */\n  lua_pushcfunction(L, gctm);\n  lua_setfield(L, -2, \"__gc\");  /* set finalizer for CLIBS table */\n  lua_setmetatable(L, -2);\n  lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS);  /* set CLIBS table in registry */\n}\n\n\nLUAMOD_API int luaopen_package (lua_State *L) {\n  createclibstable(L);\n  luaL_newlib(L, pk_funcs);  /* create 'package' table */\n  createsearcherstable(L);\n  /* set paths */\n  setpath(L, \"path\", LUA_PATH_VAR, LUA_PATH_DEFAULT);\n  setpath(L, \"cpath\", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);\n  /* store config information */\n  lua_pushliteral(L, LUA_DIRSEP \"\\n\" LUA_PATH_SEP \"\\n\" LUA_PATH_MARK \"\\n\"\n                     LUA_EXEC_DIR \"\\n\" LUA_IGMARK \"\\n\");\n  lua_setfield(L, -2, \"config\");\n  /* set field 'loaded' */\n  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n  lua_setfield(L, -2, \"loaded\");\n  /* set field 'preload' */\n  luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);\n  lua_setfield(L, -2, \"preload\");\n  lua_pushglobaltable(L);\n  lua_pushvalue(L, -2);  /* set 'package' as upvalue for next lib */\n  luaL_setfuncs(L, ll_funcs, 1);  /* open lib into global table */\n  lua_pop(L, 1);  /* pop global table */\n  return 1;  /* return 'package' table */\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lobject.c",
    "content": "/*\n** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $\n** Some generic functions over Lua objects\n** See Copyright Notice in lua.h\n*/\n\n#define lobject_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <locale.h>\n#include <math.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lctype.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"lvm.h\"\n\n\n\nLUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};\n\n\n/*\n** converts an integer to a \"floating point byte\", represented as\n** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if\n** eeeee != 0 and (xxx) otherwise.\n*/\nint luaO_int2fb (unsigned int x) {\n  int e = 0;  /* exponent */\n  if (x < 8) return x;\n  while (x >= (8 << 4)) {  /* coarse steps */\n    x = (x + 0xf) >> 4;  /* x = ceil(x / 16) */\n    e += 4;\n  }\n  while (x >= (8 << 1)) {  /* fine steps */\n    x = (x + 1) >> 1;  /* x = ceil(x / 2) */\n    e++;\n  }\n  return ((e+1) << 3) | (cast_int(x) - 8);\n}\n\n\n/* converts back */\nint luaO_fb2int (int x) {\n  return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);\n}\n\n\n/*\n** Computes ceil(log2(x))\n*/\nint luaO_ceillog2 (unsigned int x) {\n  static const lu_byte log_2[256] = {  /* log_2[i] = ceil(log2(i - 1)) */\n    0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,\n    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,\n    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8\n  };\n  int l = 0;\n  x--;\n  while (x >= 256) { l += 8; x >>= 8; }\n  return l + log_2[x];\n}\n\n\nstatic lua_Integer intarith (lua_State *L, int op, lua_Integer v1,\n                                                   lua_Integer v2) {\n  switch (op) {\n    case LUA_OPADD: return intop(+, v1, v2);\n    case LUA_OPSUB:return intop(-, v1, v2);\n    case LUA_OPMUL:return intop(*, v1, v2);\n    case LUA_OPMOD: return luaV_mod(L, v1, v2);\n    case LUA_OPIDIV: return luaV_div(L, v1, v2);\n    case LUA_OPBAND: return intop(&, v1, v2);\n    case LUA_OPBOR: return intop(|, v1, v2);\n    case LUA_OPBXOR: return intop(^, v1, v2);\n    case LUA_OPSHL: return luaV_shiftl(v1, v2);\n    case LUA_OPSHR: return luaV_shiftl(v1, -v2);\n    case LUA_OPUNM: return intop(-, 0, v1);\n    case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);\n    default: lua_assert(0); return 0;\n  }\n}\n\n\nstatic lua_Number numarith (lua_State *L, int op, lua_Number v1,\n                                                  lua_Number v2) {\n  switch (op) {\n    case LUA_OPADD: return luai_numadd(L, v1, v2);\n    case LUA_OPSUB: return luai_numsub(L, v1, v2);\n    case LUA_OPMUL: return luai_nummul(L, v1, v2);\n    case LUA_OPDIV: return luai_numdiv(L, v1, v2);\n    case LUA_OPPOW: return luai_numpow(L, v1, v2);\n    case LUA_OPIDIV: return luai_numidiv(L, v1, v2);\n    case LUA_OPUNM: return luai_numunm(L, v1);\n    case LUA_OPMOD: {\n      lua_Number m;\n      luai_nummod(L, v1, v2, m);\n      return m;\n    }\n    default: lua_assert(0); return 0;\n  }\n}\n\n\nvoid luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,\n                 TValue *res) {\n  switch (op) {\n    case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:\n    case LUA_OPSHL: case LUA_OPSHR:\n    case LUA_OPBNOT: {  /* operate only on integers */\n      lua_Integer i1; lua_Integer i2;\n      if (tointeger(p1, &i1) && tointeger(p2, &i2)) {\n        setivalue(res, intarith(L, op, i1, i2));\n        return;\n      }\n      else break;  /* go to the end */\n    }\n    case LUA_OPDIV: case LUA_OPPOW: {  /* operate only on floats */\n      lua_Number n1; lua_Number n2;\n      if (tonumber(p1, &n1) && tonumber(p2, &n2)) {\n        setfltvalue(res, numarith(L, op, n1, n2));\n        return;\n      }\n      else break;  /* go to the end */\n    }\n    default: {  /* other operations */\n      lua_Number n1; lua_Number n2;\n      if (ttisinteger(p1) && ttisinteger(p2)) {\n        setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));\n        return;\n      }\n      else if (tonumber(p1, &n1) && tonumber(p2, &n2)) {\n        setfltvalue(res, numarith(L, op, n1, n2));\n        return;\n      }\n      else break;  /* go to the end */\n    }\n  }\n  /* could not perform raw operation; try metamethod */\n  lua_assert(L != NULL);  /* should not fail when folding (compile time) */\n  luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));\n}\n\n\nint luaO_hexavalue (int c) {\n  if (lisdigit(c)) return c - '0';\n  else return (ltolower(c) - 'a') + 10;\n}\n\n\nstatic int isneg (const char **s) {\n  if (**s == '-') { (*s)++; return 1; }\n  else if (**s == '+') (*s)++;\n  return 0;\n}\n\n\n\n/*\n** {==================================================================\n** Lua's implementation for 'lua_strx2number'\n** ===================================================================\n*/\n\n#if !defined(lua_strx2number)\n\n/* maximum number of significant digits to read (to avoid overflows\n   even with single floats) */\n#define MAXSIGDIG\t30\n\n/*\n** convert an hexadecimal numeric string to a number, following\n** C99 specification for 'strtod'\n*/\nstatic lua_Number lua_strx2number (const char *s, char **endptr) {\n  int dot = lua_getlocaledecpoint();\n  lua_Number r = 0.0;  /* result (accumulator) */\n  int sigdig = 0;  /* number of significant digits */\n  int nosigdig = 0;  /* number of non-significant digits */\n  int e = 0;  /* exponent correction */\n  int neg;  /* 1 if number is negative */\n  int hasdot = 0;  /* true after seen a dot */\n  *endptr = cast(char *, s);  /* nothing is valid yet */\n  while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */\n  neg = isneg(&s);  /* check signal */\n  if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */\n    return 0.0;  /* invalid format (no '0x') */\n  for (s += 2; ; s++) {  /* skip '0x' and read numeral */\n    if (*s == dot) {\n      if (hasdot) break;  /* second dot? stop loop */\n      else hasdot = 1;\n    }\n    else if (lisxdigit(cast_uchar(*s))) {\n      if (sigdig == 0 && *s == '0')  /* non-significant digit (zero)? */\n        nosigdig++;\n      else if (++sigdig <= MAXSIGDIG)  /* can read it without overflow? */\n          r = (r * cast_num(16.0)) + luaO_hexavalue(*s);\n      else e++; /* too many digits; ignore, but still count for exponent */\n      if (hasdot) e--;  /* decimal digit? correct exponent */\n    }\n    else break;  /* neither a dot nor a digit */\n  }\n  if (nosigdig + sigdig == 0)  /* no digits? */\n    return 0.0;  /* invalid format */\n  *endptr = cast(char *, s);  /* valid up to here */\n  e *= 4;  /* each digit multiplies/divides value by 2^4 */\n  if (*s == 'p' || *s == 'P') {  /* exponent part? */\n    int exp1 = 0;  /* exponent value */\n    int neg1;  /* exponent signal */\n    s++;  /* skip 'p' */\n    neg1 = isneg(&s);  /* signal */\n    if (!lisdigit(cast_uchar(*s)))\n      return 0.0;  /* invalid; must have at least one digit */\n    while (lisdigit(cast_uchar(*s)))  /* read exponent */\n      exp1 = exp1 * 10 + *(s++) - '0';\n    if (neg1) exp1 = -exp1;\n    e += exp1;\n    *endptr = cast(char *, s);  /* valid up to here */\n  }\n  if (neg) r = -r;\n  return l_mathop(ldexp)(r, e);\n}\n\n#endif\n/* }====================================================== */\n\n\n/* maximum length of a numeral */\n#if !defined (L_MAXLENNUM)\n#define L_MAXLENNUM\t200\n#endif\n\nstatic const char *l_str2dloc (const char *s, lua_Number *result, int mode) {\n  char *endptr;\n  *result = (mode == 'x') ? lua_strx2number(s, &endptr)  /* try to convert */\n                          : lua_str2number(s, &endptr);\n  if (endptr == s) return NULL;  /* nothing recognized? */\n  while (lisspace(cast_uchar(*endptr))) endptr++;  /* skip trailing spaces */\n  return (*endptr == '\\0') ? endptr : NULL;  /* OK if no trailing characters */\n}\n\n\n/*\n** Convert string 's' to a Lua number (put in 'result'). Return NULL\n** on fail or the address of the ending '\\0' on success.\n** 'pmode' points to (and 'mode' contains) special things in the string:\n** - 'x'/'X' means an hexadecimal numeral\n** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)\n** - '.' just optimizes the search for the common case (nothing special)\n** This function accepts both the current locale or a dot as the radix\n** mark. If the convertion fails, it may mean number has a dot but\n** locale accepts something else. In that case, the code copies 's'\n** to a buffer (because 's' is read-only), changes the dot to the\n** current locale radix mark, and tries to convert again.\n*/\nstatic const char *l_str2d (const char *s, lua_Number *result) {\n  const char *endptr;\n  const char *pmode = strpbrk(s, \".xXnN\");\n  int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;\n  if (mode == 'n')  /* reject 'inf' and 'nan' */\n    return NULL;\n  endptr = l_str2dloc(s, result, mode);  /* try to convert */\n  if (endptr == NULL) {  /* failed? may be a different locale */\n    char buff[L_MAXLENNUM + 1];\n    const char *pdot = strchr(s, '.');\n    if (strlen(s) > L_MAXLENNUM || pdot == NULL)\n      return NULL;  /* string too long or no dot; fail */\n    strcpy(buff, s);  /* copy string to buffer */\n    buff[pdot - s] = lua_getlocaledecpoint();  /* correct decimal point */\n    endptr = l_str2dloc(buff, result, mode);  /* try again */\n    if (endptr != NULL)\n      endptr = s + (endptr - buff);  /* make relative to 's' */\n  }\n  return endptr;\n}\n\n\n#define MAXBY10\t\tcast(lua_Unsigned, LUA_MAXINTEGER / 10)\n#define MAXLASTD\tcast_int(LUA_MAXINTEGER % 10)\n\nstatic const char *l_str2int (const char *s, lua_Integer *result) {\n  lua_Unsigned a = 0;\n  int empty = 1;\n  int neg;\n  while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */\n  neg = isneg(&s);\n  if (s[0] == '0' &&\n      (s[1] == 'x' || s[1] == 'X')) {  /* hex? */\n    s += 2;  /* skip '0x' */\n    for (; lisxdigit(cast_uchar(*s)); s++) {\n      a = a * 16 + luaO_hexavalue(*s);\n      empty = 0;\n    }\n  }\n  else {  /* decimal */\n    for (; lisdigit(cast_uchar(*s)); s++) {\n      int d = *s - '0';\n      if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg))  /* overflow? */\n        return NULL;  /* do not accept it (as integer) */\n      a = a * 10 + d;\n      empty = 0;\n    }\n  }\n  while (lisspace(cast_uchar(*s))) s++;  /* skip trailing spaces */\n  if (empty || *s != '\\0') return NULL;  /* something wrong in the numeral */\n  else {\n    *result = l_castU2S((neg) ? 0u - a : a);\n    return s;\n  }\n}\n\n\nsize_t luaO_str2num (const char *s, TValue *o) {\n  lua_Integer i; lua_Number n;\n  const char *e;\n  if ((e = l_str2int(s, &i)) != NULL) {  /* try as an integer */\n    setivalue(o, i);\n  }\n  else if ((e = l_str2d(s, &n)) != NULL) {  /* else try as a float */\n    setfltvalue(o, n);\n  }\n  else\n    return 0;  /* conversion failed */\n  return (e - s) + 1;  /* success; return string size */\n}\n\n\nint luaO_utf8esc (char *buff, unsigned long x) {\n  int n = 1;  /* number of bytes put in buffer (backwards) */\n  lua_assert(x <= 0x10FFFF);\n  if (x < 0x80)  /* ascii? */\n    buff[UTF8BUFFSZ - 1] = cast(char, x);\n  else {  /* need continuation bytes */\n    unsigned int mfb = 0x3f;  /* maximum that fits in first byte */\n    do {  /* add continuation bytes */\n      buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f));\n      x >>= 6;  /* remove added bits */\n      mfb >>= 1;  /* now there is one less bit available in first byte */\n    } while (x > mfb);  /* still needs continuation byte? */\n    buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x);  /* add first byte */\n  }\n  return n;\n}\n\n\n/* maximum length of the conversion of a number to a string */\n#define MAXNUMBER2STR\t50\n\n\n/*\n** Convert a number object to a string\n*/\nvoid luaO_tostring (lua_State *L, StkId obj) {\n  char buff[MAXNUMBER2STR];\n  size_t len;\n  lua_assert(ttisnumber(obj));\n  if (ttisinteger(obj))\n    len = lua_integer2str(buff, sizeof(buff), ivalue(obj));\n  else {\n    len = lua_number2str(buff, sizeof(buff), fltvalue(obj));\n#if !defined(LUA_COMPAT_FLOATSTRING)\n    if (buff[strspn(buff, \"-0123456789\")] == '\\0') {  /* looks like an int? */\n      buff[len++] = lua_getlocaledecpoint();\n      buff[len++] = '0';  /* adds '.0' to result */\n    }\n#endif\n  }\n  setsvalue2s(L, obj, luaS_newlstr(L, buff, len));\n}\n\n\nstatic void pushstr (lua_State *L, const char *str, size_t l) {\n  setsvalue2s(L, L->top, luaS_newlstr(L, str, l));\n  luaD_inctop(L);\n}\n\n\n/*\n** this function handles only '%d', '%c', '%f', '%p', and '%s'\n   conventional formats, plus Lua-specific '%I' and '%U'\n*/\nconst char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {\n  int n = 0;\n  for (;;) {\n    const char *e = strchr(fmt, '%');\n    if (e == NULL) break;\n    pushstr(L, fmt, e - fmt);\n    switch (*(e+1)) {\n      case 's': {  /* zero-terminated string */\n        const char *s = va_arg(argp, char *);\n        if (s == NULL) s = \"(null)\";\n        pushstr(L, s, strlen(s));\n        break;\n      }\n      case 'c': {  /* an 'int' as a character */\n        char buff = cast(char, va_arg(argp, int));\n        if (lisprint(cast_uchar(buff)))\n          pushstr(L, &buff, 1);\n        else  /* non-printable character; print its code */\n          luaO_pushfstring(L, \"<\\\\%d>\", cast_uchar(buff));\n        break;\n      }\n      case 'd': {  /* an 'int' */\n        setivalue(L->top, va_arg(argp, int));\n        goto top2str;\n      }\n      case 'I': {  /* a 'lua_Integer' */\n        setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));\n        goto top2str;\n      }\n      case 'f': {  /* a 'lua_Number' */\n        setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));\n      top2str:  /* convert the top element to a string */\n        luaD_inctop(L);\n        luaO_tostring(L, L->top - 1);\n        break;\n      }\n      case 'p': {  /* a pointer */\n        char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */\n        void *p = va_arg(argp, void *);\n        int l = lua_pointer2str(buff, sizeof(buff), p);\n        pushstr(L, buff, l);\n        break;\n      }\n      case 'U': {  /* an 'int' as a UTF-8 sequence */\n        char buff[UTF8BUFFSZ];\n        int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));\n        pushstr(L, buff + UTF8BUFFSZ - l, l);\n        break;\n      }\n      case '%': {\n        pushstr(L, \"%\", 1);\n        break;\n      }\n      default: {\n        luaG_runerror(L, \"invalid option '%%%c' to 'lua_pushfstring'\",\n                         *(e + 1));\n      }\n    }\n    n += 2;\n    fmt = e+2;\n  }\n  luaD_checkstack(L, 1);\n  pushstr(L, fmt, strlen(fmt));\n  if (n > 0) luaV_concat(L, n + 1);\n  return svalue(L->top - 1);\n}\n\n\nconst char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {\n  const char *msg;\n  va_list argp;\n  va_start(argp, fmt);\n  msg = luaO_pushvfstring(L, fmt, argp);\n  va_end(argp);\n  return msg;\n}\n\n\n/* number of chars of a literal string without the ending \\0 */\n#define LL(x)\t(sizeof(x)/sizeof(char) - 1)\n\n#define RETS\t\"...\"\n#define PRE\t\"[string \\\"\"\n#define POS\t\"\\\"]\"\n\n#define addstr(a,b,l)\t( memcpy(a,b,(l) * sizeof(char)), a += (l) )\n\nvoid luaO_chunkid (char *out, const char *source, size_t bufflen) {\n  size_t l = strlen(source);\n  if (*source == '=') {  /* 'literal' source */\n    if (l <= bufflen)  /* small enough? */\n      memcpy(out, source + 1, l * sizeof(char));\n    else {  /* truncate it */\n      addstr(out, source + 1, bufflen - 1);\n      *out = '\\0';\n    }\n  }\n  else if (*source == '@') {  /* file name */\n    if (l <= bufflen)  /* small enough? */\n      memcpy(out, source + 1, l * sizeof(char));\n    else {  /* add '...' before rest of name */\n      addstr(out, RETS, LL(RETS));\n      bufflen -= LL(RETS);\n      memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));\n    }\n  }\n  else {  /* string; format as [string \"source\"] */\n    const char *nl = strchr(source, '\\n');  /* find first new line (if any) */\n    addstr(out, PRE, LL(PRE));  /* add prefix */\n    bufflen -= LL(PRE RETS POS) + 1;  /* save space for prefix+suffix+'\\0' */\n    if (l < bufflen && nl == NULL) {  /* small one-line source? */\n      addstr(out, source, l);  /* keep it */\n    }\n    else {\n      if (nl != NULL) l = nl - source;  /* stop at first newline */\n      if (l > bufflen) l = bufflen;\n      addstr(out, source, l);\n      addstr(out, RETS, LL(RETS));\n    }\n    memcpy(out, POS, (LL(POS) + 1) * sizeof(char));\n  }\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lobject.h",
    "content": "/*\n** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $\n** Type definitions for Lua objects\n** See Copyright Notice in lua.h\n*/\n\n\n#ifndef lobject_h\n#define lobject_h\n\n\n#include <stdarg.h>\n\n\n#include \"llimits.h\"\n#include \"lua.h\"\n\n\n/*\n** Extra tags for non-values\n*/\n#define LUA_TPROTO\tLUA_NUMTAGS\t\t/* function prototypes */\n#define LUA_TDEADKEY\t(LUA_NUMTAGS+1)\t\t/* removed keys in tables */\n\n/*\n** number of all possible tags (including LUA_TNONE but excluding DEADKEY)\n*/\n#define LUA_TOTALTAGS\t(LUA_TPROTO + 2)\n\n\n/*\n** tags for Tagged Values have the following use of bits:\n** bits 0-3: actual tag (a LUA_T* value)\n** bits 4-5: variant bits\n** bit 6: whether value is collectable\n*/\n\n\n/*\n** LUA_TFUNCTION variants:\n** 0 - Lua function\n** 1 - light C function\n** 2 - regular C function (closure)\n*/\n\n/* Variant tags for functions */\n#define LUA_TLCL\t(LUA_TFUNCTION | (0 << 4))  /* Lua closure */\n#define LUA_TLCF\t(LUA_TFUNCTION | (1 << 4))  /* light C function */\n#define LUA_TCCL\t(LUA_TFUNCTION | (2 << 4))  /* C closure */\n\n\n/* Variant tags for strings */\n#define LUA_TSHRSTR\t(LUA_TSTRING | (0 << 4))  /* short strings */\n#define LUA_TLNGSTR\t(LUA_TSTRING | (1 << 4))  /* long strings */\n\n\n/* Variant tags for numbers */\n#define LUA_TNUMFLT\t(LUA_TNUMBER | (0 << 4))  /* float numbers */\n#define LUA_TNUMINT\t(LUA_TNUMBER | (1 << 4))  /* integer numbers */\n\n\n/* Bit mark for collectable types */\n#define BIT_ISCOLLECTABLE\t(1 << 6)\n\n/* mark a tag as collectable */\n#define ctb(t)\t\t\t((t) | BIT_ISCOLLECTABLE)\n\n\n/*\n** Common type for all collectable objects\n*/\ntypedef struct GCObject GCObject;\n\n\n/*\n** Common Header for all collectable objects (in macro form, to be\n** included in other objects)\n*/\n#define CommonHeader\tGCObject *next; lu_byte tt; lu_byte marked\n\n\n/*\n** Common type has only the common header\n*/\nstruct GCObject {\n  CommonHeader;\n};\n\n\n\n\n/*\n** Tagged Values. This is the basic representation of values in Lua,\n** an actual value plus a tag with its type.\n*/\n\n/*\n** Union of all Lua values\n*/\ntypedef union Value {\n  GCObject *gc;    /* collectable objects */\n  void *p;         /* light userdata */\n  int b;           /* booleans */\n  lua_CFunction f; /* light C functions */\n  lua_Integer i;   /* integer numbers */\n  lua_Number n;    /* float numbers */\n} Value;\n\n\n#define TValuefields\tValue value_; int tt_\n\n\ntypedef struct lua_TValue {\n  TValuefields;\n} TValue;\n\n\n\n/* macro defining a nil value */\n#define NILCONSTANT\t{NULL}, LUA_TNIL\n\n\n#define val_(o)\t\t((o)->value_)\n\n\n/* raw type tag of a TValue */\n#define rttype(o)\t((o)->tt_)\n\n/* tag with no variants (bits 0-3) */\n#define novariant(x)\t((x) & 0x0F)\n\n/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */\n#define ttype(o)\t(rttype(o) & 0x3F)\n\n/* type tag of a TValue with no variants (bits 0-3) */\n#define ttnov(o)\t(novariant(rttype(o)))\n\n\n/* Macros to test type */\n#define checktag(o,t)\t\t(rttype(o) == (t))\n#define checktype(o,t)\t\t(ttnov(o) == (t))\n#define ttisnumber(o)\t\tchecktype((o), LUA_TNUMBER)\n#define ttisfloat(o)\t\tchecktag((o), LUA_TNUMFLT)\n#define ttisinteger(o)\t\tchecktag((o), LUA_TNUMINT)\n#define ttisnil(o)\t\tchecktag((o), LUA_TNIL)\n#define ttisboolean(o)\t\tchecktag((o), LUA_TBOOLEAN)\n#define ttislightuserdata(o)\tchecktag((o), LUA_TLIGHTUSERDATA)\n#define ttisstring(o)\t\tchecktype((o), LUA_TSTRING)\n#define ttisshrstring(o)\tchecktag((o), ctb(LUA_TSHRSTR))\n#define ttislngstring(o)\tchecktag((o), ctb(LUA_TLNGSTR))\n#define ttistable(o)\t\tchecktag((o), ctb(LUA_TTABLE))\n#define ttisfunction(o)\t\tchecktype(o, LUA_TFUNCTION)\n#define ttisclosure(o)\t\t((rttype(o) & 0x1F) == LUA_TFUNCTION)\n#define ttisCclosure(o)\t\tchecktag((o), ctb(LUA_TCCL))\n#define ttisLclosure(o)\t\tchecktag((o), ctb(LUA_TLCL))\n#define ttislcf(o)\t\tchecktag((o), LUA_TLCF)\n#define ttisfulluserdata(o)\tchecktag((o), ctb(LUA_TUSERDATA))\n#define ttisthread(o)\t\tchecktag((o), ctb(LUA_TTHREAD))\n#define ttisdeadkey(o)\t\tchecktag((o), LUA_TDEADKEY)\n\n\n/* Macros to access values */\n#define ivalue(o)\tcheck_exp(ttisinteger(o), val_(o).i)\n#define fltvalue(o)\tcheck_exp(ttisfloat(o), val_(o).n)\n#define nvalue(o)\tcheck_exp(ttisnumber(o), \\\n\t(ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))\n#define gcvalue(o)\tcheck_exp(iscollectable(o), val_(o).gc)\n#define pvalue(o)\tcheck_exp(ttislightuserdata(o), val_(o).p)\n#define tsvalue(o)\tcheck_exp(ttisstring(o), gco2ts(val_(o).gc))\n#define uvalue(o)\tcheck_exp(ttisfulluserdata(o), gco2u(val_(o).gc))\n#define clvalue(o)\tcheck_exp(ttisclosure(o), gco2cl(val_(o).gc))\n#define clLvalue(o)\tcheck_exp(ttisLclosure(o), gco2lcl(val_(o).gc))\n#define clCvalue(o)\tcheck_exp(ttisCclosure(o), gco2ccl(val_(o).gc))\n#define fvalue(o)\tcheck_exp(ttislcf(o), val_(o).f)\n#define hvalue(o)\tcheck_exp(ttistable(o), gco2t(val_(o).gc))\n#define bvalue(o)\tcheck_exp(ttisboolean(o), val_(o).b)\n#define thvalue(o)\tcheck_exp(ttisthread(o), gco2th(val_(o).gc))\n/* a dead value may get the 'gc' field, but cannot access its contents */\n#define deadvalue(o)\tcheck_exp(ttisdeadkey(o), cast(void *, val_(o).gc))\n\n#define l_isfalse(o)\t(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))\n\n\n#define iscollectable(o)\t(rttype(o) & BIT_ISCOLLECTABLE)\n\n\n/* Macros for internal tests */\n#define righttt(obj)\t\t(ttype(obj) == gcvalue(obj)->tt)\n\n#define checkliveness(L,obj) \\\n\tlua_longassert(!iscollectable(obj) || \\\n\t\t(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))\n\n\n/* Macros to set values */\n#define settt_(o,t)\t((o)->tt_=(t))\n\n#define setfltvalue(obj,x) \\\n  { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }\n\n#define chgfltvalue(obj,x) \\\n  { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }\n\n#define setivalue(obj,x) \\\n  { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }\n\n#define chgivalue(obj,x) \\\n  { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }\n\n#define setnilvalue(obj) settt_(obj, LUA_TNIL)\n\n#define setfvalue(obj,x) \\\n  { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }\n\n#define setpvalue(obj,x) \\\n  { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }\n\n#define setbvalue(obj,x) \\\n  { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }\n\n#define setgcovalue(L,obj,x) \\\n  { TValue *io = (obj); GCObject *i_g=(x); \\\n    val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); }\n\n#define setsvalue(L,obj,x) \\\n  { TValue *io = (obj); TString *x_ = (x); \\\n    val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \\\n    checkliveness(L,io); }\n\n#define setuvalue(L,obj,x) \\\n  { TValue *io = (obj); Udata *x_ = (x); \\\n    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \\\n    checkliveness(L,io); }\n\n#define setthvalue(L,obj,x) \\\n  { TValue *io = (obj); lua_State *x_ = (x); \\\n    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \\\n    checkliveness(L,io); }\n\n#define setclLvalue(L,obj,x) \\\n  { TValue *io = (obj); LClosure *x_ = (x); \\\n    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \\\n    checkliveness(L,io); }\n\n#define setclCvalue(L,obj,x) \\\n  { TValue *io = (obj); CClosure *x_ = (x); \\\n    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \\\n    checkliveness(L,io); }\n\n#define sethvalue(L,obj,x) \\\n  { TValue *io = (obj); Table *x_ = (x); \\\n    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \\\n    checkliveness(L,io); }\n\n#define setdeadvalue(obj)\tsettt_(obj, LUA_TDEADKEY)\n\n\n\n#define setobj(L,obj1,obj2) \\\n\t{ TValue *io1=(obj1); *io1 = *(obj2); \\\n\t  (void)L; checkliveness(L,io1); }\n\n\n/*\n** different types of assignments, according to destination\n*/\n\n/* from stack to (same) stack */\n#define setobjs2s\tsetobj\n/* to stack (not from same stack) */\n#define setobj2s\tsetobj\n#define setsvalue2s\tsetsvalue\n#define sethvalue2s\tsethvalue\n#define setptvalue2s\tsetptvalue\n/* from table to same table */\n#define setobjt2t\tsetobj\n/* to new object */\n#define setobj2n\tsetobj\n#define setsvalue2n\tsetsvalue\n\n/* to table (define it as an expression to be used in macros) */\n#define setobj2t(L,o1,o2)  ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))\n\n\n\n\n/*\n** {======================================================\n** types and prototypes\n** =======================================================\n*/\n\n\ntypedef TValue *StkId;  /* index to stack elements */\n\n\n\n\n/*\n** Header for string value; string bytes follow the end of this structure\n** (aligned according to 'UTString'; see next).\n*/\ntypedef struct TString {\n  CommonHeader;\n  lu_byte extra;  /* reserved words for short strings; \"has hash\" for longs */\n  lu_byte shrlen;  /* length for short strings */\n  unsigned int hash;\n  union {\n    size_t lnglen;  /* length for long strings */\n    struct TString *hnext;  /* linked list for hash table */\n  } u;\n} TString;\n\n\n/*\n** Ensures that address after this type is always fully aligned.\n*/\ntypedef union UTString {\n  L_Umaxalign dummy;  /* ensures maximum alignment for strings */\n  TString tsv;\n} UTString;\n\n\n/*\n** Get the actual string (array of bytes) from a 'TString'.\n** (Access to 'extra' ensures that value is really a 'TString'.)\n*/\n#define getstr(ts)  \\\n  check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))\n\n\n/* get the actual string (array of bytes) from a Lua value */\n#define svalue(o)       getstr(tsvalue(o))\n\n/* get string length from 'TString *s' */\n#define tsslen(s)\t((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen)\n\n/* get string length from 'TValue *o' */\n#define vslen(o)\ttsslen(tsvalue(o))\n\n\n/*\n** Header for userdata; memory area follows the end of this structure\n** (aligned according to 'UUdata'; see next).\n*/\ntypedef struct Udata {\n  CommonHeader;\n  lu_byte ttuv_;  /* user value's tag */\n  struct Table *metatable;\n  size_t len;  /* number of bytes */\n  union Value user_;  /* user value */\n} Udata;\n\n\n/*\n** Ensures that address after this type is always fully aligned.\n*/\ntypedef union UUdata {\n  L_Umaxalign dummy;  /* ensures maximum alignment for 'local' udata */\n  Udata uv;\n} UUdata;\n\n\n/*\n**  Get the address of memory block inside 'Udata'.\n** (Access to 'ttuv_' ensures that value is really a 'Udata'.)\n*/\n#define getudatamem(u)  \\\n  check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata)))\n\n#define setuservalue(L,u,o) \\\n\t{ const TValue *io=(o); Udata *iu = (u); \\\n\t  iu->user_ = io->value_; iu->ttuv_ = rttype(io); \\\n\t  checkliveness(L,io); }\n\n\n#define getuservalue(L,u,o) \\\n\t{ TValue *io=(o); const Udata *iu = (u); \\\n\t  io->value_ = iu->user_; settt_(io, iu->ttuv_); \\\n\t  checkliveness(L,io); }\n\n\n/*\n** Description of an upvalue for function prototypes\n*/\ntypedef struct Upvaldesc {\n  TString *name;  /* upvalue name (for debug information) */\n  lu_byte instack;  /* whether it is in stack (register) */\n  lu_byte idx;  /* index of upvalue (in stack or in outer function's list) */\n} Upvaldesc;\n\n\n/*\n** Description of a local variable for function prototypes\n** (used for debug information)\n*/\ntypedef struct LocVar {\n  TString *varname;\n  int startpc;  /* first point where variable is active */\n  int endpc;    /* first point where variable is dead */\n} LocVar;\n\n\n/*\n** Function Prototypes\n*/\ntypedef struct Proto {\n  CommonHeader;\n  lu_byte numparams;  /* number of fixed parameters */\n  lu_byte is_vararg;\n  lu_byte maxstacksize;  /* number of registers needed by this function */\n  int sizeupvalues;  /* size of 'upvalues' */\n  int sizek;  /* size of 'k' */\n  int sizecode;\n  int sizelineinfo;\n  int sizep;  /* size of 'p' */\n  int sizelocvars;\n  int linedefined;  /* debug information  */\n  int lastlinedefined;  /* debug information  */\n  TValue *k;  /* constants used by the function */\n  Instruction *code;  /* opcodes */\n  struct Proto **p;  /* functions defined inside the function */\n  int *lineinfo;  /* map from opcodes to source lines (debug information) */\n  LocVar *locvars;  /* information about local variables (debug information) */\n  Upvaldesc *upvalues;  /* upvalue information */\n  struct LClosure *cache;  /* last-created closure with this prototype */\n  TString  *source;  /* used for debug information */\n  GCObject *gclist;\n} Proto;\n\n\n\n/*\n** Lua Upvalues\n*/\ntypedef struct UpVal UpVal;\n\n\n/*\n** Closures\n*/\n\n#define ClosureHeader \\\n\tCommonHeader; lu_byte nupvalues; GCObject *gclist\n\ntypedef struct CClosure {\n  ClosureHeader;\n  lua_CFunction f;\n  TValue upvalue[1];  /* list of upvalues */\n} CClosure;\n\n\ntypedef struct LClosure {\n  ClosureHeader;\n  struct Proto *p;\n  UpVal *upvals[1];  /* list of upvalues */\n} LClosure;\n\n\ntypedef union Closure {\n  CClosure c;\n  LClosure l;\n} Closure;\n\n\n#define isLfunction(o)\tttisLclosure(o)\n\n#define getproto(o)\t(clLvalue(o)->p)\n\n\n/*\n** Tables\n*/\n\ntypedef union TKey {\n  struct {\n    TValuefields;\n    int next;  /* for chaining (offset for next node) */\n  } nk;\n  TValue tvk;\n} TKey;\n\n\n/* copy a value into a key without messing up field 'next' */\n#define setnodekey(L,key,obj) \\\n\t{ TKey *k_=(key); const TValue *io_=(obj); \\\n\t  k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \\\n\t  (void)L; checkliveness(L,io_); }\n\n\ntypedef struct Node {\n  TValue i_val;\n  TKey i_key;\n} Node;\n\n\ntypedef struct Table {\n  CommonHeader;\n  lu_byte flags;  /* 1<<p means tagmethod(p) is not present */\n  lu_byte lsizenode;  /* log2 of size of 'node' array */\n  unsigned int sizearray;  /* size of 'array' array */\n  TValue *array;  /* array part */\n  Node *node;\n  Node *lastfree;  /* any free position is before this position */\n  struct Table *metatable;\n  GCObject *gclist;\n} Table;\n\n\n\n/*\n** 'module' operation for hashing (size is always a power of 2)\n*/\n#define lmod(s,size) \\\n\t(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))\n\n\n#define twoto(x)\t(1<<(x))\n#define sizenode(t)\t(twoto((t)->lsizenode))\n\n\n/*\n** (address of) a fixed nil value\n*/\n#define luaO_nilobject\t\t(&luaO_nilobject_)\n\n\nLUAI_DDEC const TValue luaO_nilobject_;\n\n/* size of buffer for 'luaO_utf8esc' function */\n#define UTF8BUFFSZ\t8\n\nLUAI_FUNC int luaO_int2fb (unsigned int x);\nLUAI_FUNC int luaO_fb2int (int x);\nLUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);\nLUAI_FUNC int luaO_ceillog2 (unsigned int x);\nLUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,\n                           const TValue *p2, TValue *res);\nLUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);\nLUAI_FUNC int luaO_hexavalue (int c);\nLUAI_FUNC void luaO_tostring (lua_State *L, StkId obj);\nLUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,\n                                                       va_list argp);\nLUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);\nLUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);\n\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lopcodes.c",
    "content": "/*\n** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $\n** Opcodes for Lua virtual machine\n** See Copyright Notice in lua.h\n*/\n\n#define lopcodes_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stddef.h>\n\n#include \"lopcodes.h\"\n\n\n/* ORDER OP */\n\nLUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {\n  \"MOVE\",\n  \"LOADK\",\n  \"LOADKX\",\n  \"LOADBOOL\",\n  \"LOADNIL\",\n  \"GETUPVAL\",\n  \"GETTABUP\",\n  \"GETTABLE\",\n  \"SETTABUP\",\n  \"SETUPVAL\",\n  \"SETTABLE\",\n  \"NEWTABLE\",\n  \"SELF\",\n  \"ADD\",\n  \"SUB\",\n  \"MUL\",\n  \"MOD\",\n  \"POW\",\n  \"DIV\",\n  \"IDIV\",\n  \"BAND\",\n  \"BOR\",\n  \"BXOR\",\n  \"SHL\",\n  \"SHR\",\n  \"UNM\",\n  \"BNOT\",\n  \"NOT\",\n  \"LEN\",\n  \"CONCAT\",\n  \"JMP\",\n  \"EQ\",\n  \"LT\",\n  \"LE\",\n  \"TEST\",\n  \"TESTSET\",\n  \"CALL\",\n  \"TAILCALL\",\n  \"RETURN\",\n  \"FORLOOP\",\n  \"FORPREP\",\n  \"TFORCALL\",\n  \"TFORLOOP\",\n  \"SETLIST\",\n  \"CLOSURE\",\n  \"VARARG\",\n  \"EXTRAARG\",\n  NULL\n};\n\n\n#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))\n\nLUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {\n/*       T  A    B       C     mode\t\t   opcode\t*/\n  opmode(0, 1, OpArgR, OpArgN, iABC)\t\t/* OP_MOVE */\n ,opmode(0, 1, OpArgK, OpArgN, iABx)\t\t/* OP_LOADK */\n ,opmode(0, 1, OpArgN, OpArgN, iABx)\t\t/* OP_LOADKX */\n ,opmode(0, 1, OpArgU, OpArgU, iABC)\t\t/* OP_LOADBOOL */\n ,opmode(0, 1, OpArgU, OpArgN, iABC)\t\t/* OP_LOADNIL */\n ,opmode(0, 1, OpArgU, OpArgN, iABC)\t\t/* OP_GETUPVAL */\n ,opmode(0, 1, OpArgU, OpArgK, iABC)\t\t/* OP_GETTABUP */\n ,opmode(0, 1, OpArgR, OpArgK, iABC)\t\t/* OP_GETTABLE */\n ,opmode(0, 0, OpArgK, OpArgK, iABC)\t\t/* OP_SETTABUP */\n ,opmode(0, 0, OpArgU, OpArgN, iABC)\t\t/* OP_SETUPVAL */\n ,opmode(0, 0, OpArgK, OpArgK, iABC)\t\t/* OP_SETTABLE */\n ,opmode(0, 1, OpArgU, OpArgU, iABC)\t\t/* OP_NEWTABLE */\n ,opmode(0, 1, OpArgR, OpArgK, iABC)\t\t/* OP_SELF */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_ADD */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_SUB */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_MUL */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_MOD */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_POW */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_DIV */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_IDIV */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_BAND */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_BOR */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_BXOR */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_SHL */\n ,opmode(0, 1, OpArgK, OpArgK, iABC)\t\t/* OP_SHR */\n ,opmode(0, 1, OpArgR, OpArgN, iABC)\t\t/* OP_UNM */\n ,opmode(0, 1, OpArgR, OpArgN, iABC)\t\t/* OP_BNOT */\n ,opmode(0, 1, OpArgR, OpArgN, iABC)\t\t/* OP_NOT */\n ,opmode(0, 1, OpArgR, OpArgN, iABC)\t\t/* OP_LEN */\n ,opmode(0, 1, OpArgR, OpArgR, iABC)\t\t/* OP_CONCAT */\n ,opmode(0, 0, OpArgR, OpArgN, iAsBx)\t\t/* OP_JMP */\n ,opmode(1, 0, OpArgK, OpArgK, iABC)\t\t/* OP_EQ */\n ,opmode(1, 0, OpArgK, OpArgK, iABC)\t\t/* OP_LT */\n ,opmode(1, 0, OpArgK, OpArgK, iABC)\t\t/* OP_LE */\n ,opmode(1, 0, OpArgN, OpArgU, iABC)\t\t/* OP_TEST */\n ,opmode(1, 1, OpArgR, OpArgU, iABC)\t\t/* OP_TESTSET */\n ,opmode(0, 1, OpArgU, OpArgU, iABC)\t\t/* OP_CALL */\n ,opmode(0, 1, OpArgU, OpArgU, iABC)\t\t/* OP_TAILCALL */\n ,opmode(0, 0, OpArgU, OpArgN, iABC)\t\t/* OP_RETURN */\n ,opmode(0, 1, OpArgR, OpArgN, iAsBx)\t\t/* OP_FORLOOP */\n ,opmode(0, 1, OpArgR, OpArgN, iAsBx)\t\t/* OP_FORPREP */\n ,opmode(0, 0, OpArgN, OpArgU, iABC)\t\t/* OP_TFORCALL */\n ,opmode(0, 1, OpArgR, OpArgN, iAsBx)\t\t/* OP_TFORLOOP */\n ,opmode(0, 0, OpArgU, OpArgU, iABC)\t\t/* OP_SETLIST */\n ,opmode(0, 1, OpArgU, OpArgN, iABx)\t\t/* OP_CLOSURE */\n ,opmode(0, 1, OpArgU, OpArgN, iABC)\t\t/* OP_VARARG */\n ,opmode(0, 0, OpArgU, OpArgU, iAx)\t\t/* OP_EXTRAARG */\n};\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lopcodes.h",
    "content": "/*\n** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $\n** Opcodes for Lua virtual machine\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lopcodes_h\n#define lopcodes_h\n\n#include \"llimits.h\"\n\n\n/*===========================================================================\n  We assume that instructions are unsigned numbers.\n  All instructions have an opcode in the first 6 bits.\n  Instructions can have the following fields:\n\t'A' : 8 bits\n\t'B' : 9 bits\n\t'C' : 9 bits\n\t'Ax' : 26 bits ('A', 'B', and 'C' together)\n\t'Bx' : 18 bits ('B' and 'C' together)\n\t'sBx' : signed Bx\n\n  A signed argument is represented in excess K; that is, the number\n  value is the unsigned value minus K. K is exactly the maximum value\n  for that argument (so that -max is represented by 0, and +max is\n  represented by 2*max), which is half the maximum for the corresponding\n  unsigned argument.\n===========================================================================*/\n\n\nenum OpMode {iABC, iABx, iAsBx, iAx};  /* basic instruction format */\n\n\n/*\n** size and position of opcode arguments.\n*/\n#define SIZE_C\t\t9\n#define SIZE_B\t\t9\n#define SIZE_Bx\t\t(SIZE_C + SIZE_B)\n#define SIZE_A\t\t8\n#define SIZE_Ax\t\t(SIZE_C + SIZE_B + SIZE_A)\n\n#define SIZE_OP\t\t6\n\n#define POS_OP\t\t0\n#define POS_A\t\t(POS_OP + SIZE_OP)\n#define POS_C\t\t(POS_A + SIZE_A)\n#define POS_B\t\t(POS_C + SIZE_C)\n#define POS_Bx\t\tPOS_C\n#define POS_Ax\t\tPOS_A\n\n\n/*\n** limits for opcode arguments.\n** we use (signed) int to manipulate most arguments,\n** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)\n*/\n#if SIZE_Bx < LUAI_BITSINT-1\n#define MAXARG_Bx        ((1<<SIZE_Bx)-1)\n#define MAXARG_sBx        (MAXARG_Bx>>1)         /* 'sBx' is signed */\n#else\n#define MAXARG_Bx        MAX_INT\n#define MAXARG_sBx        MAX_INT\n#endif\n\n#if SIZE_Ax < LUAI_BITSINT-1\n#define MAXARG_Ax\t((1<<SIZE_Ax)-1)\n#else\n#define MAXARG_Ax\tMAX_INT\n#endif\n\n\n#define MAXARG_A        ((1<<SIZE_A)-1)\n#define MAXARG_B        ((1<<SIZE_B)-1)\n#define MAXARG_C        ((1<<SIZE_C)-1)\n\n\n/* creates a mask with 'n' 1 bits at position 'p' */\n#define MASK1(n,p)\t((~((~(Instruction)0)<<(n)))<<(p))\n\n/* creates a mask with 'n' 0 bits at position 'p' */\n#define MASK0(n,p)\t(~MASK1(n,p))\n\n/*\n** the following macros help to manipulate instructions\n*/\n\n#define GET_OPCODE(i)\t(cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))\n#define SET_OPCODE(i,o)\t((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \\\n\t\t((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))\n\n#define getarg(i,pos,size)\t(cast(int, ((i)>>pos) & MASK1(size,0)))\n#define setarg(i,v,pos,size)\t((i) = (((i)&MASK0(size,pos)) | \\\n                ((cast(Instruction, v)<<pos)&MASK1(size,pos))))\n\n#define GETARG_A(i)\tgetarg(i, POS_A, SIZE_A)\n#define SETARG_A(i,v)\tsetarg(i, v, POS_A, SIZE_A)\n\n#define GETARG_B(i)\tgetarg(i, POS_B, SIZE_B)\n#define SETARG_B(i,v)\tsetarg(i, v, POS_B, SIZE_B)\n\n#define GETARG_C(i)\tgetarg(i, POS_C, SIZE_C)\n#define SETARG_C(i,v)\tsetarg(i, v, POS_C, SIZE_C)\n\n#define GETARG_Bx(i)\tgetarg(i, POS_Bx, SIZE_Bx)\n#define SETARG_Bx(i,v)\tsetarg(i, v, POS_Bx, SIZE_Bx)\n\n#define GETARG_Ax(i)\tgetarg(i, POS_Ax, SIZE_Ax)\n#define SETARG_Ax(i,v)\tsetarg(i, v, POS_Ax, SIZE_Ax)\n\n#define GETARG_sBx(i)\t(GETARG_Bx(i)-MAXARG_sBx)\n#define SETARG_sBx(i,b)\tSETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))\n\n\n#define CREATE_ABC(o,a,b,c)\t((cast(Instruction, o)<<POS_OP) \\\n\t\t\t| (cast(Instruction, a)<<POS_A) \\\n\t\t\t| (cast(Instruction, b)<<POS_B) \\\n\t\t\t| (cast(Instruction, c)<<POS_C))\n\n#define CREATE_ABx(o,a,bc)\t((cast(Instruction, o)<<POS_OP) \\\n\t\t\t| (cast(Instruction, a)<<POS_A) \\\n\t\t\t| (cast(Instruction, bc)<<POS_Bx))\n\n#define CREATE_Ax(o,a)\t\t((cast(Instruction, o)<<POS_OP) \\\n\t\t\t| (cast(Instruction, a)<<POS_Ax))\n\n\n/*\n** Macros to operate RK indices\n*/\n\n/* this bit 1 means constant (0 means register) */\n#define BITRK\t\t(1 << (SIZE_B - 1))\n\n/* test whether value is a constant */\n#define ISK(x)\t\t((x) & BITRK)\n\n/* gets the index of the constant */\n#define INDEXK(r)\t((int)(r) & ~BITRK)\n\n#if !defined(MAXINDEXRK)  /* (for debugging only) */\n#define MAXINDEXRK\t(BITRK - 1)\n#endif\n\n/* code a constant index as a RK value */\n#define RKASK(x)\t((x) | BITRK)\n\n\n/*\n** invalid register that fits in 8 bits\n*/\n#define NO_REG\t\tMAXARG_A\n\n\n/*\n** R(x) - register\n** Kst(x) - constant (in constant table)\n** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)\n*/\n\n\n/*\n** grep \"ORDER OP\" if you change these enums\n*/\n\ntypedef enum {\n/*----------------------------------------------------------------------\nname\t\targs\tdescription\n------------------------------------------------------------------------*/\nOP_MOVE,/*\tA B\tR(A) := R(B)\t\t\t\t\t*/\nOP_LOADK,/*\tA Bx\tR(A) := Kst(Bx)\t\t\t\t\t*/\nOP_LOADKX,/*\tA \tR(A) := Kst(extra arg)\t\t\t\t*/\nOP_LOADBOOL,/*\tA B C\tR(A) := (Bool)B; if (C) pc++\t\t\t*/\nOP_LOADNIL,/*\tA B\tR(A), R(A+1), ..., R(A+B) := nil\t\t*/\nOP_GETUPVAL,/*\tA B\tR(A) := UpValue[B]\t\t\t\t*/\n\nOP_GETTABUP,/*\tA B C\tR(A) := UpValue[B][RK(C)]\t\t\t*/\nOP_GETTABLE,/*\tA B C\tR(A) := R(B)[RK(C)]\t\t\t\t*/\n\nOP_SETTABUP,/*\tA B C\tUpValue[A][RK(B)] := RK(C)\t\t\t*/\nOP_SETUPVAL,/*\tA B\tUpValue[B] := R(A)\t\t\t\t*/\nOP_SETTABLE,/*\tA B C\tR(A)[RK(B)] := RK(C)\t\t\t\t*/\n\nOP_NEWTABLE,/*\tA B C\tR(A) := {} (size = B,C)\t\t\t\t*/\n\nOP_SELF,/*\tA B C\tR(A+1) := R(B); R(A) := R(B)[RK(C)]\t\t*/\n\nOP_ADD,/*\tA B C\tR(A) := RK(B) + RK(C)\t\t\t\t*/\nOP_SUB,/*\tA B C\tR(A) := RK(B) - RK(C)\t\t\t\t*/\nOP_MUL,/*\tA B C\tR(A) := RK(B) * RK(C)\t\t\t\t*/\nOP_MOD,/*\tA B C\tR(A) := RK(B) % RK(C)\t\t\t\t*/\nOP_POW,/*\tA B C\tR(A) := RK(B) ^ RK(C)\t\t\t\t*/\nOP_DIV,/*\tA B C\tR(A) := RK(B) / RK(C)\t\t\t\t*/\nOP_IDIV,/*\tA B C\tR(A) := RK(B) // RK(C)\t\t\t\t*/\nOP_BAND,/*\tA B C\tR(A) := RK(B) & RK(C)\t\t\t\t*/\nOP_BOR,/*\tA B C\tR(A) := RK(B) | RK(C)\t\t\t\t*/\nOP_BXOR,/*\tA B C\tR(A) := RK(B) ~ RK(C)\t\t\t\t*/\nOP_SHL,/*\tA B C\tR(A) := RK(B) << RK(C)\t\t\t\t*/\nOP_SHR,/*\tA B C\tR(A) := RK(B) >> RK(C)\t\t\t\t*/\nOP_UNM,/*\tA B\tR(A) := -R(B)\t\t\t\t\t*/\nOP_BNOT,/*\tA B\tR(A) := ~R(B)\t\t\t\t\t*/\nOP_NOT,/*\tA B\tR(A) := not R(B)\t\t\t\t*/\nOP_LEN,/*\tA B\tR(A) := length of R(B)\t\t\t\t*/\n\nOP_CONCAT,/*\tA B C\tR(A) := R(B).. ... ..R(C)\t\t\t*/\n\nOP_JMP,/*\tA sBx\tpc+=sBx; if (A) close all upvalues >= R(A - 1)\t*/\nOP_EQ,/*\tA B C\tif ((RK(B) == RK(C)) ~= A) then pc++\t\t*/\nOP_LT,/*\tA B C\tif ((RK(B) <  RK(C)) ~= A) then pc++\t\t*/\nOP_LE,/*\tA B C\tif ((RK(B) <= RK(C)) ~= A) then pc++\t\t*/\n\nOP_TEST,/*\tA C\tif not (R(A) <=> C) then pc++\t\t\t*/\nOP_TESTSET,/*\tA B C\tif (R(B) <=> C) then R(A) := R(B) else pc++\t*/\n\nOP_CALL,/*\tA B C\tR(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */\nOP_TAILCALL,/*\tA B C\treturn R(A)(R(A+1), ... ,R(A+B-1))\t\t*/\nOP_RETURN,/*\tA B\treturn R(A), ... ,R(A+B-2)\t(see note)\t*/\n\nOP_FORLOOP,/*\tA sBx\tR(A)+=R(A+2);\n\t\t\tif R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/\nOP_FORPREP,/*\tA sBx\tR(A)-=R(A+2); pc+=sBx\t\t\t\t*/\n\nOP_TFORCALL,/*\tA C\tR(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));\t*/\nOP_TFORLOOP,/*\tA sBx\tif R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/\n\nOP_SETLIST,/*\tA B C\tR(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B\t*/\n\nOP_CLOSURE,/*\tA Bx\tR(A) := closure(KPROTO[Bx])\t\t\t*/\n\nOP_VARARG,/*\tA B\tR(A), R(A+1), ..., R(A+B-2) = vararg\t\t*/\n\nOP_EXTRAARG/*\tAx\textra (larger) argument for previous opcode\t*/\n} OpCode;\n\n\n#define NUM_OPCODES\t(cast(int, OP_EXTRAARG) + 1)\n\n\n\n/*===========================================================================\n  Notes:\n  (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is\n  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,\n  OP_SETLIST) may use 'top'.\n\n  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and\n  set top (like in OP_CALL with C == 0).\n\n  (*) In OP_RETURN, if (B == 0) then return up to 'top'.\n\n  (*) In OP_SETLIST, if (B == 0) then B = 'top'; if (C == 0) then next\n  'instruction' is EXTRAARG(real C).\n\n  (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.\n\n  (*) For comparisons, A specifies what condition the test should accept\n  (true or false).\n\n  (*) All 'skips' (pc++) assume that next instruction is a jump.\n\n===========================================================================*/\n\n\n/*\n** masks for instruction properties. The format is:\n** bits 0-1: op mode\n** bits 2-3: C arg mode\n** bits 4-5: B arg mode\n** bit 6: instruction set register A\n** bit 7: operator is a test (next instruction must be a jump)\n*/\n\nenum OpArgMask {\n  OpArgN,  /* argument is not used */\n  OpArgU,  /* argument is used */\n  OpArgR,  /* argument is a register or a jump offset */\n  OpArgK   /* argument is a constant or register/constant */\n};\n\nLUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];\n\n#define getOpMode(m)\t(cast(enum OpMode, luaP_opmodes[m] & 3))\n#define getBMode(m)\t(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))\n#define getCMode(m)\t(cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))\n#define testAMode(m)\t(luaP_opmodes[m] & (1 << 6))\n#define testTMode(m)\t(luaP_opmodes[m] & (1 << 7))\n\n\nLUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1];  /* opcode names */\n\n\n/* number of list items to accumulate before a SETLIST instruction */\n#define LFIELDS_PER_FLUSH\t50\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/loslib.c",
    "content": "/*\n** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $\n** Standard Operating System library\n** See Copyright Notice in lua.h\n*/\n\n#define loslib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <errno.h>\n#include <locale.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n/*\n** {==================================================================\n** List of valid conversion specifiers for the 'strftime' function;\n** options are grouped by length; group of length 2 start with '||'.\n** ===================================================================\n*/\n#if !defined(LUA_STRFTIMEOPTIONS)\t/* { */\n\n/* options for ANSI C 89 (only 1-char options) */\n#define L_STRFTIMEC89\t\t\"aAbBcdHIjmMpSUwWxXyYZ%\"\n\n/* options for ISO C 99 and POSIX */\n#define L_STRFTIMEC99 \"aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%\" \\\n    \"||\" \"EcECExEXEyEY\" \"OdOeOHOIOmOMOSOuOUOVOwOWOy\"  /* two-char options */\n\n/* options for Windows */\n#define L_STRFTIMEWIN \"aAbBcdHIjmMpSUwWxXyYzZ%\" \\\n    \"||\" \"#c#x#d#H#I#j#m#M#S#U#w#W#y#Y\"  /* two-char options */\n\n#if defined(LUA_USE_WINDOWS)\n#define LUA_STRFTIMEOPTIONS\tL_STRFTIMEWIN\n#elif defined(LUA_USE_C89)\n#define LUA_STRFTIMEOPTIONS\tL_STRFTIMEC89\n#else  /* C99 specification */\n#define LUA_STRFTIMEOPTIONS\tL_STRFTIMEC99\n#endif\n\n#endif\t\t\t\t\t/* } */\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Configuration for time-related stuff\n** ===================================================================\n*/\n\n#if !defined(l_time_t)\t\t/* { */\n/*\n** type to represent time_t in Lua\n*/\n#define l_timet\t\t\tlua_Integer\n#define l_pushtime(L,t)\t\tlua_pushinteger(L,(lua_Integer)(t))\n\nstatic time_t l_checktime (lua_State *L, int arg) {\n  lua_Integer t = luaL_checkinteger(L, arg);\n  luaL_argcheck(L, (time_t)t == t, arg, \"time out-of-bounds\");\n  return (time_t)t;\n}\n\n#endif\t\t\t\t/* } */\n\n\n#if !defined(l_gmtime)\t\t/* { */\n/*\n** By default, Lua uses gmtime/localtime, except when POSIX is available,\n** where it uses gmtime_r/localtime_r\n*/\n\n#if defined(LUA_USE_POSIX)\t/* { */\n\n#define l_gmtime(t,r)\t\tgmtime_r(t,r)\n#define l_localtime(t,r)\tlocaltime_r(t,r)\n\n#else\t\t\t\t/* }{ */\n\n/* ISO C definitions */\n#define l_gmtime(t,r)\t\t((void)(r)->tm_sec, gmtime(t))\n#define l_localtime(t,r)  \t((void)(r)->tm_sec, localtime(t))\n\n#endif\t\t\t\t/* } */\n\n#endif\t\t\t\t/* } */\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Configuration for 'tmpnam':\n** By default, Lua uses tmpnam except when POSIX is available, where\n** it uses mkstemp.\n** ===================================================================\n*/\n#if !defined(lua_tmpnam)\t/* { */\n\n#if defined(LUA_USE_POSIX)\t/* { */\n\n#include <unistd.h>\n\n#define LUA_TMPNAMBUFSIZE\t32\n\n#if !defined(LUA_TMPNAMTEMPLATE)\n#define LUA_TMPNAMTEMPLATE\t\"/tmp/lua_XXXXXX\"\n#endif\n\n#define lua_tmpnam(b,e) { \\\n        strcpy(b, LUA_TMPNAMTEMPLATE); \\\n        e = mkstemp(b); \\\n        if (e != -1) close(e); \\\n        e = (e == -1); }\n\n#else\t\t\t\t/* }{ */\n\n/* ISO C definitions */\n#define LUA_TMPNAMBUFSIZE\tL_tmpnam\n#define lua_tmpnam(b,e)\t\t{ e = (tmpnam(b) == NULL); }\n\n#endif\t\t\t\t/* } */\n\n#endif\t\t\t\t/* } */\n/* }================================================================== */\n\n\n\n\nstatic int os_execute (lua_State *L) {\n  const char *cmd = luaL_optstring(L, 1, NULL);\n#if HC_PLATFORM_IS_MICROSOFT && HC_PLATFORM != HC_PLATFORM_XDK\n  int stat = system(cmd);\n#else\n  int stat = cmd == NULL ? 0 : -1;\n#endif\n  if (cmd != NULL)\n    return luaL_execresult(L, stat);\n  else {\n    lua_pushboolean(L, stat);  /* true if there is a shell */\n    return 1;\n  }\n}\n\n\nstatic int os_remove (lua_State *L) {\n  const char *filename = luaL_checkstring(L, 1);\n  return luaL_fileresult(L, remove(filename) == 0, filename);\n}\n\n\nstatic int os_rename (lua_State *L) {\n  const char *fromname = luaL_checkstring(L, 1);\n  const char *toname = luaL_checkstring(L, 2);\n  return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);\n}\n\n\nstatic int os_tmpname (lua_State *L) {\n  char buff[LUA_TMPNAMBUFSIZE];\n  int err;\n  lua_tmpnam(buff, err);\n  if (err)\n    return luaL_error(L, \"unable to generate a unique filename\");\n  lua_pushstring(L, buff);\n  return 1;\n}\n\n\nstatic int os_getenv (lua_State *L) {\n#if HC_PLATFORM != HC_PLATFORM_XDK\n    lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */\n#else\n    lua_pushstring(L, NULL);\n#endif\n  return 1;\n}\n\n\nstatic int os_clock (lua_State *L) {\n  lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);\n  return 1;\n}\n\n\n/*\n** {======================================================\n** Time/Date operations\n** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,\n**   wday=%w+1, yday=%j, isdst=? }\n** =======================================================\n*/\n\nstatic void setfield (lua_State *L, const char *key, int value) {\n  lua_pushinteger(L, value);\n  lua_setfield(L, -2, key);\n}\n\nstatic void setboolfield (lua_State *L, const char *key, int value) {\n  if (value < 0)  /* undefined? */\n    return;  /* does not set field */\n  lua_pushboolean(L, value);\n  lua_setfield(L, -2, key);\n}\n\n\n/*\n** Set all fields from structure 'tm' in the table on top of the stack\n*/\nstatic void setallfields (lua_State *L, struct tm *stm) {\n  setfield(L, \"sec\", stm->tm_sec);\n  setfield(L, \"min\", stm->tm_min);\n  setfield(L, \"hour\", stm->tm_hour);\n  setfield(L, \"day\", stm->tm_mday);\n  setfield(L, \"month\", stm->tm_mon + 1);\n  setfield(L, \"year\", stm->tm_year + 1900);\n  setfield(L, \"wday\", stm->tm_wday + 1);\n  setfield(L, \"yday\", stm->tm_yday + 1);\n  setboolfield(L, \"isdst\", stm->tm_isdst);\n}\n\n\nstatic int getboolfield (lua_State *L, const char *key) {\n  int res;\n  res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);\n  lua_pop(L, 1);\n  return res;\n}\n\n\n/* maximum value for date fields (to avoid arithmetic overflows with 'int') */\n#if !defined(L_MAXDATEFIELD)\n#define L_MAXDATEFIELD\t(INT_MAX / 2)\n#endif\n\nstatic int getfield (lua_State *L, const char *key, int d, int delta) {\n  int isnum;\n  int t = lua_getfield(L, -1, key);  /* get field and its type */\n  lua_Integer res = lua_tointegerx(L, -1, &isnum);\n  if (!isnum) {  /* field is not an integer? */\n    if (t != LUA_TNIL)  /* some other value? */\n      return luaL_error(L, \"field '%s' is not an integer\", key);\n    else if (d < 0)  /* absent field; no default? */\n      return luaL_error(L, \"field '%s' missing in date table\", key);\n    res = d;\n  }\n  else {\n    if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))\n      return luaL_error(L, \"field '%s' is out-of-bound\", key);\n    res -= delta;\n  }\n  lua_pop(L, 1);\n  return (int)res;\n}\n\n\nstatic const char *checkoption (lua_State *L, const char *conv,\n                                ptrdiff_t convlen, char *buff) {\n  const char *option = LUA_STRFTIMEOPTIONS;\n  int oplen = 1;  /* length of options being checked */\n  for (; *option != '\\0' && oplen <= convlen; option += oplen) {\n    if (*option == '|')  /* next block? */\n      oplen++;  /* will check options with next length (+1) */\n    else if (memcmp(conv, option, oplen) == 0) {  /* match? */\n      memcpy(buff, conv, oplen);  /* copy valid option to buffer */\n      buff[oplen] = '\\0';\n      return conv + oplen;  /* return next item */\n    }\n  }\n  luaL_argerror(L, 1,\n    lua_pushfstring(L, \"invalid conversion specifier '%%%s'\", conv));\n  return conv;  /* to avoid warnings */\n}\n\n\n/* maximum size for an individual 'strftime' item */\n#define SIZETIMEFMT\t250\n\n\nstatic int os_date (lua_State *L) {\n  size_t slen;\n  const char *s = luaL_optlstring(L, 1, \"%c\", &slen);\n  time_t t = luaL_opt(L, l_checktime, 2, time(NULL));\n  const char *se = s + slen;  /* 's' end */\n  struct tm tmr, *stm;\n  if (*s == '!') {  /* UTC? */\n    stm = l_gmtime(&t, &tmr);\n    s++;  /* skip '!' */\n  }\n  else\n    stm = l_localtime(&t, &tmr);\n  if (stm == NULL)  /* invalid date? */\n    return luaL_error(L,\n                 \"time result cannot be represented in this installation\");\n  if (strcmp(s, \"*t\") == 0) {\n    lua_createtable(L, 0, 9);  /* 9 = number of fields */\n    setallfields(L, stm);\n  }\n  else {\n    char cc[4];  /* buffer for individual conversion specifiers */\n    luaL_Buffer b;\n    cc[0] = '%';\n    luaL_buffinit(L, &b);\n    while (s < se) {\n      if (*s != '%')  /* not a conversion specifier? */\n        luaL_addchar(&b, *s++);\n      else {\n        size_t reslen;\n        char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);\n        s++;  /* skip '%' */\n        s = checkoption(L, s, se - s, cc + 1);  /* copy specifier to 'cc' */\n        reslen = strftime(buff, SIZETIMEFMT, cc, stm);\n        luaL_addsize(&b, reslen);\n      }\n    }\n    luaL_pushresult(&b);\n  }\n  return 1;\n}\n\n\nstatic int os_time (lua_State *L) {\n  time_t t;\n  if (lua_isnoneornil(L, 1))  /* called without args? */\n    t = time(NULL);  /* get current time */\n  else {\n    struct tm ts;\n    luaL_checktype(L, 1, LUA_TTABLE);\n    lua_settop(L, 1);  /* make sure table is at the top */\n    ts.tm_sec = getfield(L, \"sec\", 0, 0);\n    ts.tm_min = getfield(L, \"min\", 0, 0);\n    ts.tm_hour = getfield(L, \"hour\", 12, 0);\n    ts.tm_mday = getfield(L, \"day\", -1, 0);\n    ts.tm_mon = getfield(L, \"month\", -1, 1);\n    ts.tm_year = getfield(L, \"year\", -1, 1900);\n    ts.tm_isdst = getboolfield(L, \"isdst\");\n    t = mktime(&ts);\n    setallfields(L, &ts);  /* update fields with normalized values */\n  }\n  if (t != (time_t)(l_timet)t || t == (time_t)(-1))\n    return luaL_error(L,\n                  \"time result cannot be represented in this installation\");\n  l_pushtime(L, t);\n  return 1;\n}\n\n\nstatic int os_difftime (lua_State *L) {\n  time_t t1 = l_checktime(L, 1);\n  time_t t2 = l_checktime(L, 2);\n  lua_pushnumber(L, (lua_Number)difftime(t1, t2));\n  return 1;\n}\n\n/* }====================================================== */\n\n\nstatic int os_setlocale (lua_State *L) {\n  static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,\n                      LC_NUMERIC, LC_TIME};\n  static const char *const catnames[] = {\"all\", \"collate\", \"ctype\", \"monetary\",\n     \"numeric\", \"time\", NULL};\n  const char *l = luaL_optstring(L, 1, NULL);\n  int op = luaL_checkoption(L, 2, \"all\", catnames);\n  lua_pushstring(L, setlocale(cat[op], l));\n  return 1;\n}\n\n\nstatic int os_exit (lua_State *L) {\n  int status;\n  if (lua_isboolean(L, 1))\n    status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);\n  else\n    status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);\n  if (lua_toboolean(L, 2))\n    lua_close(L);\n  if (L) exit(status);  /* 'if' to avoid warnings for unreachable 'return' */\n  return 0;\n}\n\n\nstatic const luaL_Reg syslib[] = {\n  {\"clock\",     os_clock},\n  {\"date\",      os_date},\n  {\"difftime\",  os_difftime},\n  {\"execute\",   os_execute},\n  {\"exit\",      os_exit},\n  {\"getenv\",    os_getenv},\n  {\"remove\",    os_remove},\n  {\"rename\",    os_rename},\n  {\"setlocale\", os_setlocale},\n  {\"time\",      os_time},\n  {\"tmpname\",   os_tmpname},\n  {NULL, NULL}\n};\n\n/* }====================================================== */\n\n\n\nLUAMOD_API int luaopen_os (lua_State *L) {\n  luaL_newlib(L, syslib);\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lparser.c",
    "content": "/*\n** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $\n** Lua Parser\n** See Copyright Notice in lua.h\n*/\n\n#define lparser_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lcode.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"llex.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lopcodes.h\"\n#include \"lparser.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n\n\n\n/* maximum number of local variables per function (must be smaller\n   than 250, due to the bytecode format) */\n#define MAXVARS\t\t200\n\n\n#define hasmultret(k)\t\t((k) == VCALL || (k) == VVARARG)\n\n\n/* because all strings are unified by the scanner, the parser\n   can use pointer equality for string equality */\n#define eqstr(a,b)\t((a) == (b))\n\n\n/*\n** nodes for block list (list of active blocks)\n*/\ntypedef struct BlockCnt {\n  struct BlockCnt *previous;  /* chain */\n  int firstlabel;  /* index of first label in this block */\n  int firstgoto;  /* index of first pending goto in this block */\n  lu_byte nactvar;  /* # active locals outside the block */\n  lu_byte upval;  /* true if some variable in the block is an upvalue */\n  lu_byte isloop;  /* true if 'block' is a loop */\n} BlockCnt;\n\n\n\n/*\n** prototypes for recursive non-terminal functions\n*/\nstatic void statement (LexState *ls);\nstatic void expr (LexState *ls, expdesc *v);\n\n\n/* semantic error */\nstatic l_noret semerror (LexState *ls, const char *msg) {\n  ls->t.token = 0;  /* remove \"near <token>\" from final message */\n  luaX_syntaxerror(ls, msg);\n}\n\n\nstatic l_noret error_expected (LexState *ls, int token) {\n  luaX_syntaxerror(ls,\n      luaO_pushfstring(ls->L, \"%s expected\", luaX_token2str(ls, token)));\n}\n\n\nstatic l_noret errorlimit (FuncState *fs, int limit, const char *what) {\n  lua_State *L = fs->ls->L;\n  const char *msg;\n  int line = fs->f->linedefined;\n  const char *where = (line == 0)\n                      ? \"main function\"\n                      : luaO_pushfstring(L, \"function at line %d\", line);\n  msg = luaO_pushfstring(L, \"too many %s (limit is %d) in %s\",\n                             what, limit, where);\n  luaX_syntaxerror(fs->ls, msg);\n}\n\n\nstatic void checklimit (FuncState *fs, int v, int l, const char *what) {\n  if (v > l) errorlimit(fs, l, what);\n}\n\n\nstatic int testnext (LexState *ls, int c) {\n  if (ls->t.token == c) {\n    luaX_next(ls);\n    return 1;\n  }\n  else return 0;\n}\n\n\nstatic void check (LexState *ls, int c) {\n  if (ls->t.token != c)\n    error_expected(ls, c);\n}\n\n\nstatic void checknext (LexState *ls, int c) {\n  check(ls, c);\n  luaX_next(ls);\n}\n\n\n#define check_condition(ls,c,msg)\t{ if (!(c)) luaX_syntaxerror(ls, msg); }\n\n\n\nstatic void check_match (LexState *ls, int what, int who, int where) {\n  if (!testnext(ls, what)) {\n    if (where == ls->linenumber)\n      error_expected(ls, what);\n    else {\n      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,\n             \"%s expected (to close %s at line %d)\",\n              luaX_token2str(ls, what), luaX_token2str(ls, who), where));\n    }\n  }\n}\n\n\nstatic TString *str_checkname (LexState *ls) {\n  TString *ts;\n  check(ls, TK_NAME);\n  ts = ls->t.seminfo.ts;\n  luaX_next(ls);\n  return ts;\n}\n\n\nstatic void init_exp (expdesc *e, expkind k, int i) {\n  e->f = e->t = NO_JUMP;\n  e->k = k;\n  e->u.info = i;\n}\n\n\nstatic void codestring (LexState *ls, expdesc *e, TString *s) {\n  init_exp(e, VK, luaK_stringK(ls->fs, s));\n}\n\n\nstatic void checkname (LexState *ls, expdesc *e) {\n  codestring(ls, e, str_checkname(ls));\n}\n\n\nstatic int registerlocalvar (LexState *ls, TString *varname) {\n  FuncState *fs = ls->fs;\n  Proto *f = fs->f;\n  int oldsize = f->sizelocvars;\n  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,\n                  LocVar, SHRT_MAX, \"local variables\");\n  while (oldsize < f->sizelocvars)\n    f->locvars[oldsize++].varname = NULL;\n  f->locvars[fs->nlocvars].varname = varname;\n  luaC_objbarrier(ls->L, f, varname);\n  return fs->nlocvars++;\n}\n\n\nstatic void new_localvar (LexState *ls, TString *name) {\n  FuncState *fs = ls->fs;\n  Dyndata *dyd = ls->dyd;\n  int reg = registerlocalvar(ls, name);\n  checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,\n                  MAXVARS, \"local variables\");\n  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,\n                  dyd->actvar.size, Vardesc, MAX_INT, \"local variables\");\n  dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);\n}\n\n\nstatic void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {\n  new_localvar(ls, luaX_newstring(ls, name, sz));\n}\n\n#define new_localvarliteral(ls,v) \\\n\tnew_localvarliteral_(ls, \"\" v, (sizeof(v)/sizeof(char))-1)\n\n\nstatic LocVar *getlocvar (FuncState *fs, int i) {\n  int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;\n  lua_assert(idx < fs->nlocvars);\n  return &fs->f->locvars[idx];\n}\n\n\nstatic void adjustlocalvars (LexState *ls, int nvars) {\n  FuncState *fs = ls->fs;\n  fs->nactvar = cast_byte(fs->nactvar + nvars);\n  for (; nvars; nvars--) {\n    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;\n  }\n}\n\n\nstatic void removevars (FuncState *fs, int tolevel) {\n  fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);\n  while (fs->nactvar > tolevel)\n    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;\n}\n\n\nstatic int searchupvalue (FuncState *fs, TString *name) {\n  int i;\n  Upvaldesc *up = fs->f->upvalues;\n  for (i = 0; i < fs->nups; i++) {\n    if (eqstr(up[i].name, name)) return i;\n  }\n  return -1;  /* not found */\n}\n\n\nstatic int newupvalue (FuncState *fs, TString *name, expdesc *v) {\n  Proto *f = fs->f;\n  int oldsize = f->sizeupvalues;\n  checklimit(fs, fs->nups + 1, MAXUPVAL, \"upvalues\");\n  luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,\n                  Upvaldesc, MAXUPVAL, \"upvalues\");\n  while (oldsize < f->sizeupvalues)\n    f->upvalues[oldsize++].name = NULL;\n  f->upvalues[fs->nups].instack = (v->k == VLOCAL);\n  f->upvalues[fs->nups].idx = cast_byte(v->u.info);\n  f->upvalues[fs->nups].name = name;\n  luaC_objbarrier(fs->ls->L, f, name);\n  return fs->nups++;\n}\n\n\nstatic int searchvar (FuncState *fs, TString *n) {\n  int i;\n  for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {\n    if (eqstr(n, getlocvar(fs, i)->varname))\n      return i;\n  }\n  return -1;  /* not found */\n}\n\n\n/*\n  Mark block where variable at given level was defined\n  (to emit close instructions later).\n*/\nstatic void markupval (FuncState *fs, int level) {\n  BlockCnt *bl = fs->bl;\n  while (bl->nactvar > level)\n    bl = bl->previous;\n  bl->upval = 1;\n}\n\n\n/*\n  Find variable with given name 'n'. If it is an upvalue, add this\n  upvalue into all intermediate functions.\n*/\nstatic void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {\n  if (fs == NULL)  /* no more levels? */\n    init_exp(var, VVOID, 0);  /* default is global */\n  else {\n    int v = searchvar(fs, n);  /* look up locals at current level */\n    if (v >= 0) {  /* found? */\n      init_exp(var, VLOCAL, v);  /* variable is local */\n      if (!base)\n        markupval(fs, v);  /* local will be used as an upval */\n    }\n    else {  /* not found as local at current level; try upvalues */\n      int idx = searchupvalue(fs, n);  /* try existing upvalues */\n      if (idx < 0) {  /* not found? */\n        singlevaraux(fs->prev, n, var, 0);  /* try upper levels */\n        if (var->k == VVOID)  /* not found? */\n          return;  /* it is a global */\n        /* else was LOCAL or UPVAL */\n        idx  = newupvalue(fs, n, var);  /* will be a new upvalue */\n      }\n      init_exp(var, VUPVAL, idx);  /* new or old upvalue */\n    }\n  }\n}\n\n\nstatic void singlevar (LexState *ls, expdesc *var) {\n  TString *varname = str_checkname(ls);\n  FuncState *fs = ls->fs;\n  singlevaraux(fs, varname, var, 1);\n  if (var->k == VVOID) {  /* global name? */\n    expdesc key;\n    singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */\n    lua_assert(var->k != VVOID);  /* this one must exist */\n    codestring(ls, &key, varname);  /* key is variable name */\n    luaK_indexed(fs, var, &key);  /* env[varname] */\n  }\n}\n\n\nstatic void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {\n  FuncState *fs = ls->fs;\n  int extra = nvars - nexps;\n  if (hasmultret(e->k)) {\n    extra++;  /* includes call itself */\n    if (extra < 0) extra = 0;\n    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */\n    if (extra > 1) luaK_reserveregs(fs, extra-1);\n  }\n  else {\n    if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */\n    if (extra > 0) {\n      int reg = fs->freereg;\n      luaK_reserveregs(fs, extra);\n      luaK_nil(fs, reg, extra);\n    }\n  }\n  if (nexps > nvars)\n    ls->fs->freereg -= nexps - nvars;  /* remove extra values */\n}\n\n\nstatic void enterlevel (LexState *ls) {\n  lua_State *L = ls->L;\n  ++L->nCcalls;\n  checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, \"C levels\");\n}\n\n\n#define leavelevel(ls)\t((ls)->L->nCcalls--)\n\n\nstatic void closegoto (LexState *ls, int g, Labeldesc *label) {\n  int i;\n  FuncState *fs = ls->fs;\n  Labellist *gl = &ls->dyd->gt;\n  Labeldesc *gt = &gl->arr[g];\n  lua_assert(eqstr(gt->name, label->name));\n  if (gt->nactvar < label->nactvar) {\n    TString *vname = getlocvar(fs, gt->nactvar)->varname;\n    const char *msg = luaO_pushfstring(ls->L,\n      \"<goto %s> at line %d jumps into the scope of local '%s'\",\n      getstr(gt->name), gt->line, getstr(vname));\n    semerror(ls, msg);\n  }\n  luaK_patchlist(fs, gt->pc, label->pc);\n  /* remove goto from pending list */\n  for (i = g; i < gl->n - 1; i++)\n    gl->arr[i] = gl->arr[i + 1];\n  gl->n--;\n}\n\n\n/*\n** try to close a goto with existing labels; this solves backward jumps\n*/\nstatic int findlabel (LexState *ls, int g) {\n  int i;\n  BlockCnt *bl = ls->fs->bl;\n  Dyndata *dyd = ls->dyd;\n  Labeldesc *gt = &dyd->gt.arr[g];\n  /* check labels in current block for a match */\n  for (i = bl->firstlabel; i < dyd->label.n; i++) {\n    Labeldesc *lb = &dyd->label.arr[i];\n    if (eqstr(lb->name, gt->name)) {  /* correct label? */\n      if (gt->nactvar > lb->nactvar &&\n          (bl->upval || dyd->label.n > bl->firstlabel))\n        luaK_patchclose(ls->fs, gt->pc, lb->nactvar);\n      closegoto(ls, g, lb);  /* close it */\n      return 1;\n    }\n  }\n  return 0;  /* label not found; cannot close goto */\n}\n\n\nstatic int newlabelentry (LexState *ls, Labellist *l, TString *name,\n                          int line, int pc) {\n  int n = l->n;\n  luaM_growvector(ls->L, l->arr, n, l->size,\n                  Labeldesc, SHRT_MAX, \"labels/gotos\");\n  l->arr[n].name = name;\n  l->arr[n].line = line;\n  l->arr[n].nactvar = ls->fs->nactvar;\n  l->arr[n].pc = pc;\n  l->n = n + 1;\n  return n;\n}\n\n\n/*\n** check whether new label 'lb' matches any pending gotos in current\n** block; solves forward jumps\n*/\nstatic void findgotos (LexState *ls, Labeldesc *lb) {\n  Labellist *gl = &ls->dyd->gt;\n  int i = ls->fs->bl->firstgoto;\n  while (i < gl->n) {\n    if (eqstr(gl->arr[i].name, lb->name))\n      closegoto(ls, i, lb);\n    else\n      i++;\n  }\n}\n\n\n/*\n** export pending gotos to outer level, to check them against\n** outer labels; if the block being exited has upvalues, and\n** the goto exits the scope of any variable (which can be the\n** upvalue), close those variables being exited.\n*/\nstatic void movegotosout (FuncState *fs, BlockCnt *bl) {\n  int i = bl->firstgoto;\n  Labellist *gl = &fs->ls->dyd->gt;\n  /* correct pending gotos to current block and try to close it\n     with visible labels */\n  while (i < gl->n) {\n    Labeldesc *gt = &gl->arr[i];\n    if (gt->nactvar > bl->nactvar) {\n      if (bl->upval)\n        luaK_patchclose(fs, gt->pc, bl->nactvar);\n      gt->nactvar = bl->nactvar;\n    }\n    if (!findlabel(fs->ls, i))\n      i++;  /* move to next one */\n  }\n}\n\n\nstatic void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {\n  bl->isloop = isloop;\n  bl->nactvar = fs->nactvar;\n  bl->firstlabel = fs->ls->dyd->label.n;\n  bl->firstgoto = fs->ls->dyd->gt.n;\n  bl->upval = 0;\n  bl->previous = fs->bl;\n  fs->bl = bl;\n  lua_assert(fs->freereg == fs->nactvar);\n}\n\n\n/*\n** create a label named 'break' to resolve break statements\n*/\nstatic void breaklabel (LexState *ls) {\n  TString *n = luaS_new(ls->L, \"break\");\n  int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);\n  findgotos(ls, &ls->dyd->label.arr[l]);\n}\n\n/*\n** generates an error for an undefined 'goto'; choose appropriate\n** message when label name is a reserved word (which can only be 'break')\n*/\nstatic l_noret undefgoto (LexState *ls, Labeldesc *gt) {\n  const char *msg = isreserved(gt->name)\n                    ? \"<%s> at line %d not inside a loop\"\n                    : \"no visible label '%s' for <goto> at line %d\";\n  msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);\n  semerror(ls, msg);\n}\n\n\nstatic void leaveblock (FuncState *fs) {\n  BlockCnt *bl = fs->bl;\n  LexState *ls = fs->ls;\n  if (bl->previous && bl->upval) {\n    /* create a 'jump to here' to close upvalues */\n    int j = luaK_jump(fs);\n    luaK_patchclose(fs, j, bl->nactvar);\n    luaK_patchtohere(fs, j);\n  }\n  if (bl->isloop)\n    breaklabel(ls);  /* close pending breaks */\n  fs->bl = bl->previous;\n  removevars(fs, bl->nactvar);\n  lua_assert(bl->nactvar == fs->nactvar);\n  fs->freereg = fs->nactvar;  /* free registers */\n  ls->dyd->label.n = bl->firstlabel;  /* remove local labels */\n  if (bl->previous)  /* inner block? */\n    movegotosout(fs, bl);  /* update pending gotos to outer block */\n  else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */\n    undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */\n}\n\n\n/*\n** adds a new prototype into list of prototypes\n*/\nstatic Proto *addprototype (LexState *ls) {\n  Proto *clp;\n  lua_State *L = ls->L;\n  FuncState *fs = ls->fs;\n  Proto *f = fs->f;  /* prototype of current function */\n  if (fs->np >= f->sizep) {\n    int oldsize = f->sizep;\n    luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, \"functions\");\n    while (oldsize < f->sizep)\n      f->p[oldsize++] = NULL;\n  }\n  f->p[fs->np++] = clp = luaF_newproto(L);\n  luaC_objbarrier(L, f, clp);\n  return clp;\n}\n\n\n/*\n** codes instruction to create new closure in parent function.\n** The OP_CLOSURE instruction must use the last available register,\n** so that, if it invokes the GC, the GC knows which registers\n** are in use at that time.\n*/\nstatic void codeclosure (LexState *ls, expdesc *v) {\n  FuncState *fs = ls->fs->prev;\n  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));\n  luaK_exp2nextreg(fs, v);  /* fix it at the last register */\n}\n\n\nstatic void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {\n  Proto *f;\n  fs->prev = ls->fs;  /* linked list of funcstates */\n  fs->ls = ls;\n  ls->fs = fs;\n  fs->pc = 0;\n  fs->lasttarget = 0;\n  fs->jpc = NO_JUMP;\n  fs->freereg = 0;\n  fs->nk = 0;\n  fs->np = 0;\n  fs->nups = 0;\n  fs->nlocvars = 0;\n  fs->nactvar = 0;\n  fs->firstlocal = ls->dyd->actvar.n;\n  fs->bl = NULL;\n  f = fs->f;\n  f->source = ls->source;\n  f->maxstacksize = 2;  /* registers 0/1 are always valid */\n  enterblock(fs, bl, 0);\n}\n\n\nstatic void close_func (LexState *ls) {\n  lua_State *L = ls->L;\n  FuncState *fs = ls->fs;\n  Proto *f = fs->f;\n  luaK_ret(fs, 0, 0);  /* final return */\n  leaveblock(fs);\n  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);\n  f->sizecode = fs->pc;\n  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);\n  f->sizelineinfo = fs->pc;\n  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);\n  f->sizek = fs->nk;\n  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);\n  f->sizep = fs->np;\n  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);\n  f->sizelocvars = fs->nlocvars;\n  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);\n  f->sizeupvalues = fs->nups;\n  lua_assert(fs->bl == NULL);\n  ls->fs = fs->prev;\n  luaC_checkGC(L);\n}\n\n\n\n/*============================================================*/\n/* GRAMMAR RULES */\n/*============================================================*/\n\n\n/*\n** check whether current token is in the follow set of a block.\n** 'until' closes syntactical blocks, but do not close scope,\n** so it is handled in separate.\n*/\nstatic int block_follow (LexState *ls, int withuntil) {\n  switch (ls->t.token) {\n    case TK_ELSE: case TK_ELSEIF:\n    case TK_END: case TK_EOS:\n      return 1;\n    case TK_UNTIL: return withuntil;\n    default: return 0;\n  }\n}\n\n\nstatic void statlist (LexState *ls) {\n  /* statlist -> { stat [';'] } */\n  while (!block_follow(ls, 1)) {\n    if (ls->t.token == TK_RETURN) {\n      statement(ls);\n      return;  /* 'return' must be last statement */\n    }\n    statement(ls);\n  }\n}\n\n\nstatic void fieldsel (LexState *ls, expdesc *v) {\n  /* fieldsel -> ['.' | ':'] NAME */\n  FuncState *fs = ls->fs;\n  expdesc key;\n  luaK_exp2anyregup(fs, v);\n  luaX_next(ls);  /* skip the dot or colon */\n  checkname(ls, &key);\n  luaK_indexed(fs, v, &key);\n}\n\n\nstatic void yindex (LexState *ls, expdesc *v) {\n  /* index -> '[' expr ']' */\n  luaX_next(ls);  /* skip the '[' */\n  expr(ls, v);\n  luaK_exp2val(ls->fs, v);\n  checknext(ls, ']');\n}\n\n\n/*\n** {======================================================================\n** Rules for Constructors\n** =======================================================================\n*/\n\n\nstruct ConsControl {\n  expdesc v;  /* last list item read */\n  expdesc *t;  /* table descriptor */\n  int nh;  /* total number of 'record' elements */\n  int na;  /* total number of array elements */\n  int tostore;  /* number of array elements pending to be stored */\n};\n\n\nstatic void recfield (LexState *ls, struct ConsControl *cc) {\n  /* recfield -> (NAME | '['exp1']') = exp1 */\n  FuncState *fs = ls->fs;\n  int reg = ls->fs->freereg;\n  expdesc key, val;\n  int rkkey;\n  if (ls->t.token == TK_NAME) {\n    checklimit(fs, cc->nh, MAX_INT, \"items in a constructor\");\n    checkname(ls, &key);\n  }\n  else  /* ls->t.token == '[' */\n    yindex(ls, &key);\n  cc->nh++;\n  checknext(ls, '=');\n  rkkey = luaK_exp2RK(fs, &key);\n  expr(ls, &val);\n  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));\n  fs->freereg = reg;  /* free registers */\n}\n\n\nstatic void closelistfield (FuncState *fs, struct ConsControl *cc) {\n  if (cc->v.k == VVOID) return;  /* there is no list item */\n  luaK_exp2nextreg(fs, &cc->v);\n  cc->v.k = VVOID;\n  if (cc->tostore == LFIELDS_PER_FLUSH) {\n    luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);  /* flush */\n    cc->tostore = 0;  /* no more items pending */\n  }\n}\n\n\nstatic void lastlistfield (FuncState *fs, struct ConsControl *cc) {\n  if (cc->tostore == 0) return;\n  if (hasmultret(cc->v.k)) {\n    luaK_setmultret(fs, &cc->v);\n    luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);\n    cc->na--;  /* do not count last expression (unknown number of elements) */\n  }\n  else {\n    if (cc->v.k != VVOID)\n      luaK_exp2nextreg(fs, &cc->v);\n    luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);\n  }\n}\n\n\nstatic void listfield (LexState *ls, struct ConsControl *cc) {\n  /* listfield -> exp */\n  expr(ls, &cc->v);\n  checklimit(ls->fs, cc->na, MAX_INT, \"items in a constructor\");\n  cc->na++;\n  cc->tostore++;\n}\n\n\nstatic void field (LexState *ls, struct ConsControl *cc) {\n  /* field -> listfield | recfield */\n  switch(ls->t.token) {\n    case TK_NAME: {  /* may be 'listfield' or 'recfield' */\n      if (luaX_lookahead(ls) != '=')  /* expression? */\n        listfield(ls, cc);\n      else\n        recfield(ls, cc);\n      break;\n    }\n    case '[': {\n      recfield(ls, cc);\n      break;\n    }\n    default: {\n      listfield(ls, cc);\n      break;\n    }\n  }\n}\n\n\nstatic void constructor (LexState *ls, expdesc *t) {\n  /* constructor -> '{' [ field { sep field } [sep] ] '}'\n     sep -> ',' | ';' */\n  FuncState *fs = ls->fs;\n  int line = ls->linenumber;\n  int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);\n  struct ConsControl cc;\n  cc.na = cc.nh = cc.tostore = 0;\n  cc.t = t;\n  init_exp(t, VRELOCABLE, pc);\n  init_exp(&cc.v, VVOID, 0);  /* no value (yet) */\n  luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */\n  checknext(ls, '{');\n  do {\n    lua_assert(cc.v.k == VVOID || cc.tostore > 0);\n    if (ls->t.token == '}') break;\n    closelistfield(fs, &cc);\n    field(ls, &cc);\n  } while (testnext(ls, ',') || testnext(ls, ';'));\n  check_match(ls, '}', '{', line);\n  lastlistfield(fs, &cc);\n  SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */\n  SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */\n}\n\n/* }====================================================================== */\n\n\n\nstatic void parlist (LexState *ls) {\n  /* parlist -> [ param { ',' param } ] */\n  FuncState *fs = ls->fs;\n  Proto *f = fs->f;\n  int nparams = 0;\n  f->is_vararg = 0;\n  if (ls->t.token != ')') {  /* is 'parlist' not empty? */\n    do {\n      switch (ls->t.token) {\n        case TK_NAME: {  /* param -> NAME */\n          new_localvar(ls, str_checkname(ls));\n          nparams++;\n          break;\n        }\n        case TK_DOTS: {  /* param -> '...' */\n          luaX_next(ls);\n          f->is_vararg = 1;  /* declared vararg */\n          break;\n        }\n        default: luaX_syntaxerror(ls, \"<name> or '...' expected\");\n      }\n    } while (!f->is_vararg && testnext(ls, ','));\n  }\n  adjustlocalvars(ls, nparams);\n  f->numparams = cast_byte(fs->nactvar);\n  luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */\n}\n\n\nstatic void body (LexState *ls, expdesc *e, int ismethod, int line) {\n  /* body ->  '(' parlist ')' block END */\n  FuncState new_fs;\n  BlockCnt bl;\n  new_fs.f = addprototype(ls);\n  new_fs.f->linedefined = line;\n  open_func(ls, &new_fs, &bl);\n  checknext(ls, '(');\n  if (ismethod) {\n    new_localvarliteral(ls, \"self\");  /* create 'self' parameter */\n    adjustlocalvars(ls, 1);\n  }\n  parlist(ls);\n  checknext(ls, ')');\n  statlist(ls);\n  new_fs.f->lastlinedefined = ls->linenumber;\n  check_match(ls, TK_END, TK_FUNCTION, line);\n  codeclosure(ls, e);\n  close_func(ls);\n}\n\n\nstatic int explist (LexState *ls, expdesc *v) {\n  /* explist -> expr { ',' expr } */\n  int n = 1;  /* at least one expression */\n  expr(ls, v);\n  while (testnext(ls, ',')) {\n    luaK_exp2nextreg(ls->fs, v);\n    expr(ls, v);\n    n++;\n  }\n  return n;\n}\n\n\nstatic void funcargs (LexState *ls, expdesc *f, int line) {\n  FuncState *fs = ls->fs;\n  expdesc args;\n  int base, nparams;\n  switch (ls->t.token) {\n    case '(': {  /* funcargs -> '(' [ explist ] ')' */\n      luaX_next(ls);\n      if (ls->t.token == ')')  /* arg list is empty? */\n        args.k = VVOID;\n      else {\n        explist(ls, &args);\n        luaK_setmultret(fs, &args);\n      }\n      check_match(ls, ')', '(', line);\n      break;\n    }\n    case '{': {  /* funcargs -> constructor */\n      constructor(ls, &args);\n      break;\n    }\n    case TK_STRING: {  /* funcargs -> STRING */\n      codestring(ls, &args, ls->t.seminfo.ts);\n      luaX_next(ls);  /* must use 'seminfo' before 'next' */\n      break;\n    }\n    default: {\n      luaX_syntaxerror(ls, \"function arguments expected\");\n    }\n  }\n  lua_assert(f->k == VNONRELOC);\n  base = f->u.info;  /* base register for call */\n  if (hasmultret(args.k))\n    nparams = LUA_MULTRET;  /* open call */\n  else {\n    if (args.k != VVOID)\n      luaK_exp2nextreg(fs, &args);  /* close last argument */\n    nparams = fs->freereg - (base+1);\n  }\n  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));\n  luaK_fixline(fs, line);\n  fs->freereg = base+1;  /* call remove function and arguments and leaves\n                            (unless changed) one result */\n}\n\n\n\n\n/*\n** {======================================================================\n** Expression parsing\n** =======================================================================\n*/\n\n\nstatic void primaryexp (LexState *ls, expdesc *v) {\n  /* primaryexp -> NAME | '(' expr ')' */\n  switch (ls->t.token) {\n    case '(': {\n      int line = ls->linenumber;\n      luaX_next(ls);\n      expr(ls, v);\n      check_match(ls, ')', '(', line);\n      luaK_dischargevars(ls->fs, v);\n      return;\n    }\n    case TK_NAME: {\n      singlevar(ls, v);\n      return;\n    }\n    default: {\n      luaX_syntaxerror(ls, \"unexpected symbol\");\n    }\n  }\n}\n\n\nstatic void suffixedexp (LexState *ls, expdesc *v) {\n  /* suffixedexp ->\n       primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */\n  FuncState *fs = ls->fs;\n  int line = ls->linenumber;\n  primaryexp(ls, v);\n  for (;;) {\n    switch (ls->t.token) {\n      case '.': {  /* fieldsel */\n        fieldsel(ls, v);\n        break;\n      }\n      case '[': {  /* '[' exp1 ']' */\n        expdesc key;\n        luaK_exp2anyregup(fs, v);\n        yindex(ls, &key);\n        luaK_indexed(fs, v, &key);\n        break;\n      }\n      case ':': {  /* ':' NAME funcargs */\n        expdesc key;\n        luaX_next(ls);\n        checkname(ls, &key);\n        luaK_self(fs, v, &key);\n        funcargs(ls, v, line);\n        break;\n      }\n      case '(': case TK_STRING: case '{': {  /* funcargs */\n        luaK_exp2nextreg(fs, v);\n        funcargs(ls, v, line);\n        break;\n      }\n      default: return;\n    }\n  }\n}\n\n\nstatic void simpleexp (LexState *ls, expdesc *v) {\n  /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |\n                  constructor | FUNCTION body | suffixedexp */\n  switch (ls->t.token) {\n    case TK_FLT: {\n      init_exp(v, VKFLT, 0);\n      v->u.nval = ls->t.seminfo.r;\n      break;\n    }\n    case TK_INT: {\n      init_exp(v, VKINT, 0);\n      v->u.ival = ls->t.seminfo.i;\n      break;\n    }\n    case TK_STRING: {\n      codestring(ls, v, ls->t.seminfo.ts);\n      break;\n    }\n    case TK_NIL: {\n      init_exp(v, VNIL, 0);\n      break;\n    }\n    case TK_TRUE: {\n      init_exp(v, VTRUE, 0);\n      break;\n    }\n    case TK_FALSE: {\n      init_exp(v, VFALSE, 0);\n      break;\n    }\n    case TK_DOTS: {  /* vararg */\n      FuncState *fs = ls->fs;\n      check_condition(ls, fs->f->is_vararg,\n                      \"cannot use '...' outside a vararg function\");\n      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));\n      break;\n    }\n    case '{': {  /* constructor */\n      constructor(ls, v);\n      return;\n    }\n    case TK_FUNCTION: {\n      luaX_next(ls);\n      body(ls, v, 0, ls->linenumber);\n      return;\n    }\n    default: {\n      suffixedexp(ls, v);\n      return;\n    }\n  }\n  luaX_next(ls);\n}\n\n\nstatic UnOpr getunopr (int op) {\n  switch (op) {\n    case TK_NOT: return OPR_NOT;\n    case '-': return OPR_MINUS;\n    case '~': return OPR_BNOT;\n    case '#': return OPR_LEN;\n    default: return OPR_NOUNOPR;\n  }\n}\n\n\nstatic BinOpr getbinopr (int op) {\n  switch (op) {\n    case '+': return OPR_ADD;\n    case '-': return OPR_SUB;\n    case '*': return OPR_MUL;\n    case '%': return OPR_MOD;\n    case '^': return OPR_POW;\n    case '/': return OPR_DIV;\n    case TK_IDIV: return OPR_IDIV;\n    case '&': return OPR_BAND;\n    case '|': return OPR_BOR;\n    case '~': return OPR_BXOR;\n    case TK_SHL: return OPR_SHL;\n    case TK_SHR: return OPR_SHR;\n    case TK_CONCAT: return OPR_CONCAT;\n    case TK_NE: return OPR_NE;\n    case TK_EQ: return OPR_EQ;\n    case '<': return OPR_LT;\n    case TK_LE: return OPR_LE;\n    case '>': return OPR_GT;\n    case TK_GE: return OPR_GE;\n    case TK_AND: return OPR_AND;\n    case TK_OR: return OPR_OR;\n    default: return OPR_NOBINOPR;\n  }\n}\n\n\nstatic const struct {\n  lu_byte left;  /* left priority for each binary operator */\n  lu_byte right; /* right priority */\n} priority[] = {  /* ORDER OPR */\n   {10, 10}, {10, 10},           /* '+' '-' */\n   {11, 11}, {11, 11},           /* '*' '%' */\n   {14, 13},                  /* '^' (right associative) */\n   {11, 11}, {11, 11},           /* '/' '//' */\n   {6, 6}, {4, 4}, {5, 5},   /* '&' '|' '~' */\n   {7, 7}, {7, 7},           /* '<<' '>>' */\n   {9, 8},                   /* '..' (right associative) */\n   {3, 3}, {3, 3}, {3, 3},   /* ==, <, <= */\n   {3, 3}, {3, 3}, {3, 3},   /* ~=, >, >= */\n   {2, 2}, {1, 1}            /* and, or */\n};\n\n#define UNARY_PRIORITY\t12  /* priority for unary operators */\n\n\n/*\n** subexpr -> (simpleexp | unop subexpr) { binop subexpr }\n** where 'binop' is any binary operator with a priority higher than 'limit'\n*/\nstatic BinOpr subexpr (LexState *ls, expdesc *v, int limit) {\n  BinOpr op;\n  UnOpr uop;\n  enterlevel(ls);\n  uop = getunopr(ls->t.token);\n  if (uop != OPR_NOUNOPR) {\n    int line = ls->linenumber;\n    luaX_next(ls);\n    subexpr(ls, v, UNARY_PRIORITY);\n    luaK_prefix(ls->fs, uop, v, line);\n  }\n  else simpleexp(ls, v);\n  /* expand while operators have priorities higher than 'limit' */\n  op = getbinopr(ls->t.token);\n  while (op != OPR_NOBINOPR && priority[op].left > limit) {\n    expdesc v2;\n    BinOpr nextop;\n    int line = ls->linenumber;\n    luaX_next(ls);\n    luaK_infix(ls->fs, op, v);\n    /* read sub-expression with higher priority */\n    nextop = subexpr(ls, &v2, priority[op].right);\n    luaK_posfix(ls->fs, op, v, &v2, line);\n    op = nextop;\n  }\n  leavelevel(ls);\n  return op;  /* return first untreated operator */\n}\n\n\nstatic void expr (LexState *ls, expdesc *v) {\n  subexpr(ls, v, 0);\n}\n\n/* }==================================================================== */\n\n\n\n/*\n** {======================================================================\n** Rules for Statements\n** =======================================================================\n*/\n\n\nstatic void block (LexState *ls) {\n  /* block -> statlist */\n  FuncState *fs = ls->fs;\n  BlockCnt bl;\n  enterblock(fs, &bl, 0);\n  statlist(ls);\n  leaveblock(fs);\n}\n\n\n/*\n** structure to chain all variables in the left-hand side of an\n** assignment\n*/\nstruct LHS_assign {\n  struct LHS_assign *prev;\n  expdesc v;  /* variable (global, local, upvalue, or indexed) */\n};\n\n\n/*\n** check whether, in an assignment to an upvalue/local variable, the\n** upvalue/local variable is begin used in a previous assignment to a\n** table. If so, save original upvalue/local value in a safe place and\n** use this safe copy in the previous assignment.\n*/\nstatic void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {\n  FuncState *fs = ls->fs;\n  int extra = fs->freereg;  /* eventual position to save local variable */\n  int conflict = 0;\n  for (; lh; lh = lh->prev) {  /* check all previous assignments */\n    if (lh->v.k == VINDEXED) {  /* assigning to a table? */\n      /* table is the upvalue/local being assigned now? */\n      if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {\n        conflict = 1;\n        lh->v.u.ind.vt = VLOCAL;\n        lh->v.u.ind.t = extra;  /* previous assignment will use safe copy */\n      }\n      /* index is the local being assigned? (index cannot be upvalue) */\n      if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {\n        conflict = 1;\n        lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */\n      }\n    }\n  }\n  if (conflict) {\n    /* copy upvalue/local value to a temporary (in position 'extra') */\n    OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;\n    luaK_codeABC(fs, op, extra, v->u.info, 0);\n    luaK_reserveregs(fs, 1);\n  }\n}\n\n\nstatic void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {\n  expdesc e;\n  check_condition(ls, vkisvar(lh->v.k), \"syntax error\");\n  if (testnext(ls, ',')) {  /* assignment -> ',' suffixedexp assignment */\n    struct LHS_assign nv;\n    nv.prev = lh;\n    suffixedexp(ls, &nv.v);\n    if (nv.v.k != VINDEXED)\n      check_conflict(ls, lh, &nv.v);\n    checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,\n                    \"C levels\");\n    assignment(ls, &nv, nvars+1);\n  }\n  else {  /* assignment -> '=' explist */\n    int nexps;\n    checknext(ls, '=');\n    nexps = explist(ls, &e);\n    if (nexps != nvars)\n      adjust_assign(ls, nvars, nexps, &e);\n    else {\n      luaK_setoneret(ls->fs, &e);  /* close last expression */\n      luaK_storevar(ls->fs, &lh->v, &e);\n      return;  /* avoid default */\n    }\n  }\n  init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */\n  luaK_storevar(ls->fs, &lh->v, &e);\n}\n\n\nstatic int cond (LexState *ls) {\n  /* cond -> exp */\n  expdesc v;\n  expr(ls, &v);  /* read condition */\n  if (v.k == VNIL) v.k = VFALSE;  /* 'falses' are all equal here */\n  luaK_goiftrue(ls->fs, &v);\n  return v.f;\n}\n\n\nstatic void gotostat (LexState *ls, int pc) {\n  int line = ls->linenumber;\n  TString *label;\n  int g;\n  if (testnext(ls, TK_GOTO))\n    label = str_checkname(ls);\n  else {\n    luaX_next(ls);  /* skip break */\n    label = luaS_new(ls->L, \"break\");\n  }\n  g = newlabelentry(ls, &ls->dyd->gt, label, line, pc);\n  findlabel(ls, g);  /* close it if label already defined */\n}\n\n\n/* check for repeated labels on the same block */\nstatic void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {\n  int i;\n  for (i = fs->bl->firstlabel; i < ll->n; i++) {\n    if (eqstr(label, ll->arr[i].name)) {\n      const char *msg = luaO_pushfstring(fs->ls->L,\n                          \"label '%s' already defined on line %d\",\n                          getstr(label), ll->arr[i].line);\n      semerror(fs->ls, msg);\n    }\n  }\n}\n\n\n/* skip no-op statements */\nstatic void skipnoopstat (LexState *ls) {\n  while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)\n    statement(ls);\n}\n\n\nstatic void labelstat (LexState *ls, TString *label, int line) {\n  /* label -> '::' NAME '::' */\n  FuncState *fs = ls->fs;\n  Labellist *ll = &ls->dyd->label;\n  int l;  /* index of new label being created */\n  checkrepeated(fs, ll, label);  /* check for repeated labels */\n  checknext(ls, TK_DBCOLON);  /* skip double colon */\n  /* create new entry for this label */\n  l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));\n  skipnoopstat(ls);  /* skip other no-op statements */\n  if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */\n    /* assume that locals are already out of scope */\n    ll->arr[l].nactvar = fs->bl->nactvar;\n  }\n  findgotos(ls, &ll->arr[l]);\n}\n\n\nstatic void whilestat (LexState *ls, int line) {\n  /* whilestat -> WHILE cond DO block END */\n  FuncState *fs = ls->fs;\n  int whileinit;\n  int condexit;\n  BlockCnt bl;\n  luaX_next(ls);  /* skip WHILE */\n  whileinit = luaK_getlabel(fs);\n  condexit = cond(ls);\n  enterblock(fs, &bl, 1);\n  checknext(ls, TK_DO);\n  block(ls);\n  luaK_jumpto(fs, whileinit);\n  check_match(ls, TK_END, TK_WHILE, line);\n  leaveblock(fs);\n  luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */\n}\n\n\nstatic void repeatstat (LexState *ls, int line) {\n  /* repeatstat -> REPEAT block UNTIL cond */\n  int condexit;\n  FuncState *fs = ls->fs;\n  int repeat_init = luaK_getlabel(fs);\n  BlockCnt bl1, bl2;\n  enterblock(fs, &bl1, 1);  /* loop block */\n  enterblock(fs, &bl2, 0);  /* scope block */\n  luaX_next(ls);  /* skip REPEAT */\n  statlist(ls);\n  check_match(ls, TK_UNTIL, TK_REPEAT, line);\n  condexit = cond(ls);  /* read condition (inside scope block) */\n  if (bl2.upval)  /* upvalues? */\n    luaK_patchclose(fs, condexit, bl2.nactvar);\n  leaveblock(fs);  /* finish scope */\n  luaK_patchlist(fs, condexit, repeat_init);  /* close the loop */\n  leaveblock(fs);  /* finish loop */\n}\n\n\nstatic int exp1 (LexState *ls) {\n  expdesc e;\n  int reg;\n  expr(ls, &e);\n  luaK_exp2nextreg(ls->fs, &e);\n  lua_assert(e.k == VNONRELOC);\n  reg = e.u.info;\n  return reg;\n}\n\n\nstatic void forbody (LexState *ls, int base, int line, int nvars, int isnum) {\n  /* forbody -> DO block */\n  BlockCnt bl;\n  FuncState *fs = ls->fs;\n  int prep, endfor;\n  adjustlocalvars(ls, 3);  /* control variables */\n  checknext(ls, TK_DO);\n  prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);\n  enterblock(fs, &bl, 0);  /* scope for declared variables */\n  adjustlocalvars(ls, nvars);\n  luaK_reserveregs(fs, nvars);\n  block(ls);\n  leaveblock(fs);  /* end of scope for declared variables */\n  luaK_patchtohere(fs, prep);\n  if (isnum)  /* numeric for? */\n    endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);\n  else {  /* generic for */\n    luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);\n    luaK_fixline(fs, line);\n    endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);\n  }\n  luaK_patchlist(fs, endfor, prep + 1);\n  luaK_fixline(fs, line);\n}\n\n\nstatic void fornum (LexState *ls, TString *varname, int line) {\n  /* fornum -> NAME = exp1,exp1[,exp1] forbody */\n  FuncState *fs = ls->fs;\n  int base = fs->freereg;\n  new_localvarliteral(ls, \"(for index)\");\n  new_localvarliteral(ls, \"(for limit)\");\n  new_localvarliteral(ls, \"(for step)\");\n  new_localvar(ls, varname);\n  checknext(ls, '=');\n  exp1(ls);  /* initial value */\n  checknext(ls, ',');\n  exp1(ls);  /* limit */\n  if (testnext(ls, ','))\n    exp1(ls);  /* optional step */\n  else {  /* default step = 1 */\n    luaK_codek(fs, fs->freereg, luaK_intK(fs, 1));\n    luaK_reserveregs(fs, 1);\n  }\n  forbody(ls, base, line, 1, 1);\n}\n\n\nstatic void forlist (LexState *ls, TString *indexname) {\n  /* forlist -> NAME {,NAME} IN explist forbody */\n  FuncState *fs = ls->fs;\n  expdesc e;\n  int nvars = 4;  /* gen, state, control, plus at least one declared var */\n  int line;\n  int base = fs->freereg;\n  /* create control variables */\n  new_localvarliteral(ls, \"(for generator)\");\n  new_localvarliteral(ls, \"(for state)\");\n  new_localvarliteral(ls, \"(for control)\");\n  /* create declared variables */\n  new_localvar(ls, indexname);\n  while (testnext(ls, ',')) {\n    new_localvar(ls, str_checkname(ls));\n    nvars++;\n  }\n  checknext(ls, TK_IN);\n  line = ls->linenumber;\n  adjust_assign(ls, 3, explist(ls, &e), &e);\n  luaK_checkstack(fs, 3);  /* extra space to call generator */\n  forbody(ls, base, line, nvars - 3, 0);\n}\n\n\nstatic void forstat (LexState *ls, int line) {\n  /* forstat -> FOR (fornum | forlist) END */\n  FuncState *fs = ls->fs;\n  TString *varname;\n  BlockCnt bl;\n  enterblock(fs, &bl, 1);  /* scope for loop and control variables */\n  luaX_next(ls);  /* skip 'for' */\n  varname = str_checkname(ls);  /* first variable name */\n  switch (ls->t.token) {\n    case '=': fornum(ls, varname, line); break;\n    case ',': case TK_IN: forlist(ls, varname); break;\n    default: luaX_syntaxerror(ls, \"'=' or 'in' expected\");\n  }\n  check_match(ls, TK_END, TK_FOR, line);\n  leaveblock(fs);  /* loop scope ('break' jumps to this point) */\n}\n\n\nstatic void test_then_block (LexState *ls, int *escapelist) {\n  /* test_then_block -> [IF | ELSEIF] cond THEN block */\n  BlockCnt bl;\n  FuncState *fs = ls->fs;\n  expdesc v;\n  int jf;  /* instruction to skip 'then' code (if condition is false) */\n  luaX_next(ls);  /* skip IF or ELSEIF */\n  expr(ls, &v);  /* read condition */\n  checknext(ls, TK_THEN);\n  if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) {\n    luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */\n    enterblock(fs, &bl, 0);  /* must enter block before 'goto' */\n    gotostat(ls, v.t);  /* handle goto/break */\n    while (testnext(ls, ';')) {}  /* skip colons */\n    if (block_follow(ls, 0)) {  /* 'goto' is the entire block? */\n      leaveblock(fs);\n      return;  /* and that is it */\n    }\n    else  /* must skip over 'then' part if condition is false */\n      jf = luaK_jump(fs);\n  }\n  else {  /* regular case (not goto/break) */\n    luaK_goiftrue(ls->fs, &v);  /* skip over block if condition is false */\n    enterblock(fs, &bl, 0);\n    jf = v.f;\n  }\n  statlist(ls);  /* 'then' part */\n  leaveblock(fs);\n  if (ls->t.token == TK_ELSE ||\n      ls->t.token == TK_ELSEIF)  /* followed by 'else'/'elseif'? */\n    luaK_concat(fs, escapelist, luaK_jump(fs));  /* must jump over it */\n  luaK_patchtohere(fs, jf);\n}\n\n\nstatic void ifstat (LexState *ls, int line) {\n  /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */\n  FuncState *fs = ls->fs;\n  int escapelist = NO_JUMP;  /* exit list for finished parts */\n  test_then_block(ls, &escapelist);  /* IF cond THEN block */\n  while (ls->t.token == TK_ELSEIF)\n    test_then_block(ls, &escapelist);  /* ELSEIF cond THEN block */\n  if (testnext(ls, TK_ELSE))\n    block(ls);  /* 'else' part */\n  check_match(ls, TK_END, TK_IF, line);\n  luaK_patchtohere(fs, escapelist);  /* patch escape list to 'if' end */\n}\n\n\nstatic void localfunc (LexState *ls) {\n  expdesc b;\n  FuncState *fs = ls->fs;\n  new_localvar(ls, str_checkname(ls));  /* new local variable */\n  adjustlocalvars(ls, 1);  /* enter its scope */\n  body(ls, &b, 0, ls->linenumber);  /* function created in next register */\n  /* debug information will only see the variable after this point! */\n  getlocvar(fs, b.u.info)->startpc = fs->pc;\n}\n\n\nstatic void localstat (LexState *ls) {\n  /* stat -> LOCAL NAME {',' NAME} ['=' explist] */\n  int nvars = 0;\n  int nexps;\n  expdesc e;\n  do {\n    new_localvar(ls, str_checkname(ls));\n    nvars++;\n  } while (testnext(ls, ','));\n  if (testnext(ls, '='))\n    nexps = explist(ls, &e);\n  else {\n    e.k = VVOID;\n    nexps = 0;\n  }\n  adjust_assign(ls, nvars, nexps, &e);\n  adjustlocalvars(ls, nvars);\n}\n\n\nstatic int funcname (LexState *ls, expdesc *v) {\n  /* funcname -> NAME {fieldsel} [':' NAME] */\n  int ismethod = 0;\n  singlevar(ls, v);\n  while (ls->t.token == '.')\n    fieldsel(ls, v);\n  if (ls->t.token == ':') {\n    ismethod = 1;\n    fieldsel(ls, v);\n  }\n  return ismethod;\n}\n\n\nstatic void funcstat (LexState *ls, int line) {\n  /* funcstat -> FUNCTION funcname body */\n  int ismethod;\n  expdesc v, b;\n  luaX_next(ls);  /* skip FUNCTION */\n  ismethod = funcname(ls, &v);\n  body(ls, &b, ismethod, line);\n  luaK_storevar(ls->fs, &v, &b);\n  luaK_fixline(ls->fs, line);  /* definition \"happens\" in the first line */\n}\n\n\nstatic void exprstat (LexState *ls) {\n  /* stat -> func | assignment */\n  FuncState *fs = ls->fs;\n  struct LHS_assign v;\n  suffixedexp(ls, &v.v);\n  if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */\n    v.prev = NULL;\n    assignment(ls, &v, 1);\n  }\n  else {  /* stat -> func */\n    check_condition(ls, v.v.k == VCALL, \"syntax error\");\n    SETARG_C(getinstruction(fs, &v.v), 1);  /* call statement uses no results */\n  }\n}\n\n\nstatic void retstat (LexState *ls) {\n  /* stat -> RETURN [explist] [';'] */\n  FuncState *fs = ls->fs;\n  expdesc e;\n  int first, nret;  /* registers with returned values */\n  if (block_follow(ls, 1) || ls->t.token == ';')\n    first = nret = 0;  /* return no values */\n  else {\n    nret = explist(ls, &e);  /* optional return values */\n    if (hasmultret(e.k)) {\n      luaK_setmultret(fs, &e);\n      if (e.k == VCALL && nret == 1) {  /* tail call? */\n        SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);\n        lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);\n      }\n      first = fs->nactvar;\n      nret = LUA_MULTRET;  /* return all values */\n    }\n    else {\n      if (nret == 1)  /* only one single value? */\n        first = luaK_exp2anyreg(fs, &e);\n      else {\n        luaK_exp2nextreg(fs, &e);  /* values must go to the stack */\n        first = fs->nactvar;  /* return all active values */\n        lua_assert(nret == fs->freereg - first);\n      }\n    }\n  }\n  luaK_ret(fs, first, nret);\n  testnext(ls, ';');  /* skip optional semicolon */\n}\n\n\nstatic void statement (LexState *ls) {\n  int line = ls->linenumber;  /* may be needed for error messages */\n  enterlevel(ls);\n  switch (ls->t.token) {\n    case ';': {  /* stat -> ';' (empty statement) */\n      luaX_next(ls);  /* skip ';' */\n      break;\n    }\n    case TK_IF: {  /* stat -> ifstat */\n      ifstat(ls, line);\n      break;\n    }\n    case TK_WHILE: {  /* stat -> whilestat */\n      whilestat(ls, line);\n      break;\n    }\n    case TK_DO: {  /* stat -> DO block END */\n      luaX_next(ls);  /* skip DO */\n      block(ls);\n      check_match(ls, TK_END, TK_DO, line);\n      break;\n    }\n    case TK_FOR: {  /* stat -> forstat */\n      forstat(ls, line);\n      break;\n    }\n    case TK_REPEAT: {  /* stat -> repeatstat */\n      repeatstat(ls, line);\n      break;\n    }\n    case TK_FUNCTION: {  /* stat -> funcstat */\n      funcstat(ls, line);\n      break;\n    }\n    case TK_LOCAL: {  /* stat -> localstat */\n      luaX_next(ls);  /* skip LOCAL */\n      if (testnext(ls, TK_FUNCTION))  /* local function? */\n        localfunc(ls);\n      else\n        localstat(ls);\n      break;\n    }\n    case TK_DBCOLON: {  /* stat -> label */\n      luaX_next(ls);  /* skip double colon */\n      labelstat(ls, str_checkname(ls), line);\n      break;\n    }\n    case TK_RETURN: {  /* stat -> retstat */\n      luaX_next(ls);  /* skip RETURN */\n      retstat(ls);\n      break;\n    }\n    case TK_BREAK:   /* stat -> breakstat */\n    case TK_GOTO: {  /* stat -> 'goto' NAME */\n      gotostat(ls, luaK_jump(ls->fs));\n      break;\n    }\n    default: {  /* stat -> func | assignment */\n      exprstat(ls);\n      break;\n    }\n  }\n  lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&\n             ls->fs->freereg >= ls->fs->nactvar);\n  ls->fs->freereg = ls->fs->nactvar;  /* free registers */\n  leavelevel(ls);\n}\n\n/* }====================================================================== */\n\n\n/*\n** compiles the main function, which is a regular vararg function with an\n** upvalue named LUA_ENV\n*/\nstatic void mainfunc (LexState *ls, FuncState *fs) {\n  BlockCnt bl;\n  expdesc v;\n  open_func(ls, fs, &bl);\n  fs->f->is_vararg = 1;  /* main function is always declared vararg */\n  init_exp(&v, VLOCAL, 0);  /* create and... */\n  newupvalue(fs, ls->envn, &v);  /* ...set environment upvalue */\n  luaX_next(ls);  /* read first token */\n  statlist(ls);  /* parse main body */\n  check(ls, TK_EOS);\n  close_func(ls);\n}\n\n\nLClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,\n                       Dyndata *dyd, const char *name, int firstchar) {\n  LexState lexstate;\n  FuncState funcstate;\n  LClosure *cl = luaF_newLclosure(L, 1);  /* create main closure */\n  setclLvalue(L, L->top, cl);  /* anchor it (to avoid being collected) */\n  luaD_inctop(L);\n  lexstate.h = luaH_new(L);  /* create table for scanner */\n  sethvalue(L, L->top, lexstate.h);  /* anchor it */\n  luaD_inctop(L);\n  funcstate.f = cl->p = luaF_newproto(L);\n  funcstate.f->source = luaS_new(L, name);  /* create and anchor TString */\n  lua_assert(iswhite(funcstate.f));  /* do not need barrier here */\n  lexstate.buff = buff;\n  lexstate.dyd = dyd;\n  dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;\n  luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);\n  mainfunc(&lexstate, &funcstate);\n  lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);\n  /* all scopes should be correctly finished */\n  lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);\n  L->top--;  /* remove scanner's table */\n  return cl;  /* closure is on the stack, too */\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lparser.h",
    "content": "/*\n** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $\n** Lua Parser\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lparser_h\n#define lparser_h\n\n#include \"llimits.h\"\n#include \"lobject.h\"\n#include \"lzio.h\"\n\n\n/*\n** Expression and variable descriptor.\n** Code generation for variables and expressions can be delayed to allow\n** optimizations; An 'expdesc' structure describes a potentially-delayed\n** variable/expression. It has a description of its \"main\" value plus a\n** list of conditional jumps that can also produce its value (generated\n** by short-circuit operators 'and'/'or').\n*/\n\n/* kinds of variables/expressions */\ntypedef enum {\n  VVOID,  /* when 'expdesc' describes the last expression a list,\n             this kind means an empty list (so, no expression) */\n  VNIL,  /* constant nil */\n  VTRUE,  /* constant true */\n  VFALSE,  /* constant false */\n  VK,  /* constant in 'k'; info = index of constant in 'k' */\n  VKFLT,  /* floating constant; nval = numerical float value */\n  VKINT,  /* integer constant; nval = numerical integer value */\n  VNONRELOC,  /* expression has its value in a fixed register;\n                 info = result register */\n  VLOCAL,  /* local variable; info = local register */\n  VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' */\n  VINDEXED,  /* indexed variable;\n                ind.vt = whether 't' is register or upvalue;\n                ind.t = table register or upvalue;\n                ind.idx = key's R/K index */\n  VJMP,  /* expression is a test/comparison;\n            info = pc of corresponding jump instruction */\n  VRELOCABLE,  /* expression can put result in any register;\n                  info = instruction pc */\n  VCALL,  /* expression is a function call; info = instruction pc */\n  VVARARG  /* vararg expression; info = instruction pc */\n} expkind;\n\n\n#define vkisvar(k)\t(VLOCAL <= (k) && (k) <= VINDEXED)\n#define vkisinreg(k)\t((k) == VNONRELOC || (k) == VLOCAL)\n\ntypedef struct expdesc {\n  expkind k;\n  union {\n    lua_Integer ival;    /* for VKINT */\n    lua_Number nval;  /* for VKFLT */\n    int info;  /* for generic use */\n    struct {  /* for indexed variables (VINDEXED) */\n      short idx;  /* index (R/K) */\n      lu_byte t;  /* table (register or upvalue) */\n      lu_byte vt;  /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */\n    } ind;\n  } u;\n  int t;  /* patch list of 'exit when true' */\n  int f;  /* patch list of 'exit when false' */\n} expdesc;\n\n\n/* description of active local variable */\ntypedef struct Vardesc {\n  short idx;  /* variable index in stack */\n} Vardesc;\n\n\n/* description of pending goto statements and label statements */\ntypedef struct Labeldesc {\n  TString *name;  /* label identifier */\n  int pc;  /* position in code */\n  int line;  /* line where it appeared */\n  lu_byte nactvar;  /* local level where it appears in current block */\n} Labeldesc;\n\n\n/* list of labels or gotos */\ntypedef struct Labellist {\n  Labeldesc *arr;  /* array */\n  int n;  /* number of entries in use */\n  int size;  /* array size */\n} Labellist;\n\n\n/* dynamic structures used by the parser */\ntypedef struct Dyndata {\n  struct {  /* list of active local variables */\n    Vardesc *arr;\n    int n;\n    int size;\n  } actvar;\n  Labellist gt;  /* list of pending gotos */\n  Labellist label;   /* list of active labels */\n} Dyndata;\n\n\n/* control of blocks */\nstruct BlockCnt;  /* defined in lparser.c */\n\n\n/* state needed to generate code for a given function */\ntypedef struct FuncState {\n  Proto *f;  /* current function header */\n  struct FuncState *prev;  /* enclosing function */\n  struct LexState *ls;  /* lexical state */\n  struct BlockCnt *bl;  /* chain of current blocks */\n  int pc;  /* next position to code (equivalent to 'ncode') */\n  int lasttarget;   /* 'label' of last 'jump label' */\n  int jpc;  /* list of pending jumps to 'pc' */\n  int nk;  /* number of elements in 'k' */\n  int np;  /* number of elements in 'p' */\n  int firstlocal;  /* index of first local var (in Dyndata array) */\n  short nlocvars;  /* number of elements in 'f->locvars' */\n  lu_byte nactvar;  /* number of active local variables */\n  lu_byte nups;  /* number of upvalues */\n  lu_byte freereg;  /* first free register */\n} FuncState;\n\n\nLUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,\n                                 Dyndata *dyd, const char *name, int firstchar);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lprefix.h",
    "content": "/*\n** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $\n** Definitions for Lua code that must come before any other header file\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lprefix_h\n#define lprefix_h\n\n\n/*\n** Allows POSIX/XSI stuff\n*/\n#if !defined(LUA_USE_C89)\t/* { */\n\n#if !defined(_XOPEN_SOURCE)\n#define _XOPEN_SOURCE           600\n#elif _XOPEN_SOURCE == 0\n#undef _XOPEN_SOURCE  /* use -D_XOPEN_SOURCE=0 to undefine it */\n#endif\n\n/*\n** Allows manipulation of large files in gcc and some other compilers\n*/\n#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS)\n#define _LARGEFILE_SOURCE       1\n#define _FILE_OFFSET_BITS       64\n#endif\n\n#endif\t\t\t\t/* } */\n\n\n/*\n** Windows stuff\n*/\n#if defined(_WIN32) \t/* { */\n\n#if !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS  /* avoid warnings about ISO C functions */\n#endif\n\n#endif\t\t\t/* } */\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lstate.c",
    "content": "/*\n** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $\n** Global State\n** See Copyright Notice in lua.h\n*/\n\n#define lstate_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <stddef.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lapi.h\"\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lgc.h\"\n#include \"llex.h\"\n#include \"lmem.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n\n\n#if !defined(LUAI_GCPAUSE)\n#define LUAI_GCPAUSE\t200  /* 200% */\n#endif\n\n#if !defined(LUAI_GCMUL)\n#define LUAI_GCMUL\t200 /* GC runs 'twice the speed' of memory allocation */\n#endif\n\n\n/*\n** a macro to help the creation of a unique random seed when a state is\n** created; the seed is used to randomize hashes.\n*/\n#if !defined(luai_makeseed)\n#include <time.h>\n#define luai_makeseed()\t\tcast(unsigned int, time(NULL))\n#endif\n\n\n\n/*\n** thread state + extra space\n*/\ntypedef struct LX {\n  lu_byte extra_[LUA_EXTRASPACE];\n  lua_State l;\n} LX;\n\n\n/*\n** Main thread combines a thread state and the global state\n*/\ntypedef struct LG {\n  LX l;\n  global_State g;\n} LG;\n\n\n\n#define fromstate(L)\t(cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))\n\n\n/*\n** Compute an initial seed as random as possible. Rely on Address Space\n** Layout Randomization (if present) to increase randomness..\n*/\n#define addbuff(b,p,e) \\\n  { size_t t = cast(size_t, e); \\\n    memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }\n\nstatic unsigned int makeseed (lua_State *L) {\n  char buff[4 * sizeof(size_t)];\n  unsigned int h = luai_makeseed();\n  int p = 0;\n  addbuff(buff, p, L);  /* heap variable */\n  addbuff(buff, p, &h);  /* local variable */\n  addbuff(buff, p, luaO_nilobject);  /* global variable */\n  addbuff(buff, p, &lua_newstate);  /* public function */\n  lua_assert(p == sizeof(buff));\n  return luaS_hash(buff, p, h);\n}\n\n\n/*\n** set GCdebt to a new value keeping the value (totalbytes + GCdebt)\n** invariant (and avoiding underflows in 'totalbytes')\n*/\nvoid luaE_setdebt (global_State *g, l_mem debt) {\n  l_mem tb = gettotalbytes(g);\n  lua_assert(tb > 0);\n  if (debt < tb - MAX_LMEM)\n    debt = tb - MAX_LMEM;  /* will make 'totalbytes == MAX_LMEM' */\n  g->totalbytes = tb - debt;\n  g->GCdebt = debt;\n}\n\n\nCallInfo *luaE_extendCI (lua_State *L) {\n  CallInfo *ci = luaM_new(L, CallInfo);\n  lua_assert(L->ci->next == NULL);\n  L->ci->next = ci;\n  ci->previous = L->ci;\n  ci->next = NULL;\n  L->nci++;\n  return ci;\n}\n\n\n/*\n** free all CallInfo structures not in use by a thread\n*/\nvoid luaE_freeCI (lua_State *L) {\n  CallInfo *ci = L->ci;\n  CallInfo *next = ci->next;\n  ci->next = NULL;\n  while ((ci = next) != NULL) {\n    next = ci->next;\n    luaM_free(L, ci);\n    L->nci--;\n  }\n}\n\n\n/*\n** free half of the CallInfo structures not in use by a thread\n*/\nvoid luaE_shrinkCI (lua_State *L) {\n  CallInfo *ci = L->ci;\n  CallInfo *next2;  /* next's next */\n  /* while there are two nexts */\n  while (ci->next != NULL && (next2 = ci->next->next) != NULL) {\n    luaM_free(L, ci->next);  /* free next */\n    L->nci--;\n    ci->next = next2;  /* remove 'next' from the list */\n    next2->previous = ci;\n    ci = next2;  /* keep next's next */\n  }\n}\n\n\nstatic void stack_init (lua_State *L1, lua_State *L) {\n  int i; CallInfo *ci;\n  /* initialize stack array */\n  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);\n  L1->stacksize = BASIC_STACK_SIZE;\n  for (i = 0; i < BASIC_STACK_SIZE; i++)\n    setnilvalue(L1->stack + i);  /* erase new stack */\n  L1->top = L1->stack;\n  L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;\n  /* initialize first ci */\n  ci = &L1->base_ci;\n  ci->next = ci->previous = NULL;\n  ci->callstatus = 0;\n  ci->func = L1->top;\n  setnilvalue(L1->top++);  /* 'function' entry for this 'ci' */\n  ci->top = L1->top + LUA_MINSTACK;\n  L1->ci = ci;\n}\n\n\nstatic void freestack (lua_State *L) {\n  if (L->stack == NULL)\n    return;  /* stack not completely built yet */\n  L->ci = &L->base_ci;  /* free the entire 'ci' list */\n  luaE_freeCI(L);\n  lua_assert(L->nci == 0);\n  luaM_freearray(L, L->stack, L->stacksize);  /* free stack array */\n}\n\n\n/*\n** Create registry table and its predefined values\n*/\nstatic void init_registry (lua_State *L, global_State *g) {\n  TValue temp;\n  /* create registry */\n  Table *registry = luaH_new(L);\n  sethvalue(L, &g->l_registry, registry);\n  luaH_resize(L, registry, LUA_RIDX_LAST, 0);\n  /* registry[LUA_RIDX_MAINTHREAD] = L */\n  setthvalue(L, &temp, L);  /* temp = L */\n  luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);\n  /* registry[LUA_RIDX_GLOBALS] = table of globals */\n  sethvalue(L, &temp, luaH_new(L));  /* temp = new table (global table) */\n  luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);\n}\n\n\n/*\n** open parts of the state that may cause memory-allocation errors.\n** ('g->version' != NULL flags that the state was completely build)\n*/\nstatic void f_luaopen (lua_State *L, void *ud) {\n  global_State *g = G(L);\n  UNUSED(ud);\n  stack_init(L, L);  /* init stack */\n  init_registry(L, g);\n  luaS_init(L);\n  luaT_init(L);\n  luaX_init(L);\n  g->gcrunning = 1;  /* allow gc */\n  g->version = lua_version(NULL);\n  luai_userstateopen(L);\n}\n\n\n/*\n** preinitialize a thread with consistent values without allocating\n** any memory (to avoid errors)\n*/\nstatic void preinit_thread (lua_State *L, global_State *g) {\n  G(L) = g;\n  L->stack = NULL;\n  L->ci = NULL;\n  L->nci = 0;\n  L->stacksize = 0;\n  L->twups = L;  /* thread has no upvalues */\n  L->errorJmp = NULL;\n  L->nCcalls = 0;\n  L->hook = NULL;\n  L->hookmask = 0;\n  L->basehookcount = 0;\n  L->allowhook = 1;\n  resethookcount(L);\n  L->openupval = NULL;\n  L->nny = 1;\n  L->status = LUA_OK;\n  L->errfunc = 0;\n}\n\n\nstatic void close_state (lua_State *L) {\n  global_State *g = G(L);\n  luaF_close(L, L->stack);  /* close all upvalues for this thread */\n  luaC_freeallobjects(L);  /* collect all objects */\n  if (g->version)  /* closing a fully built state? */\n    luai_userstateclose(L);\n  luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);\n  freestack(L);\n  lua_assert(gettotalbytes(g) == sizeof(LG));\n  (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0);  /* free main block */\n}\n\n\nLUA_API lua_State *lua_newthread (lua_State *L) {\n  global_State *g = G(L);\n  lua_State *L1;\n  lua_lock(L);\n  luaC_checkGC(L);\n  /* create new thread */\n  L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;\n  L1->marked = luaC_white(g);\n  L1->tt = LUA_TTHREAD;\n  /* link it on list 'allgc' */\n  L1->next = g->allgc;\n  g->allgc = obj2gco(L1);\n  /* anchor it on L stack */\n  setthvalue(L, L->top, L1);\n  api_incr_top(L);\n  preinit_thread(L1, g);\n  L1->hookmask = L->hookmask;\n  L1->basehookcount = L->basehookcount;\n  L1->hook = L->hook;\n  resethookcount(L1);\n  /* initialize L1 extra space */\n  memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread),\n         LUA_EXTRASPACE);\n  luai_userstatethread(L, L1);\n  stack_init(L1, L);  /* init stack */\n  lua_unlock(L);\n  return L1;\n}\n\n\nvoid luaE_freethread (lua_State *L, lua_State *L1) {\n  LX *l = fromstate(L1);\n  luaF_close(L1, L1->stack);  /* close all upvalues for this thread */\n  lua_assert(L1->openupval == NULL);\n  luai_userstatefree(L, L1);\n  freestack(L1);\n  luaM_free(L, l);\n}\n\n\nLUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {\n  int i;\n  lua_State *L;\n  global_State *g;\n  LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));\n  if (l == NULL) return NULL;\n  L = &l->l.l;\n  g = &l->g;\n  L->next = NULL;\n  L->tt = LUA_TTHREAD;\n  g->currentwhite = bitmask(WHITE0BIT);\n  L->marked = luaC_white(g);\n  preinit_thread(L, g);\n  g->frealloc = f;\n  g->ud = ud;\n  g->mainthread = L;\n  g->seed = makeseed(L);\n  g->gcrunning = 0;  /* no GC while building state */\n  g->GCestimate = 0;\n  g->strt.size = g->strt.nuse = 0;\n  g->strt.hash = NULL;\n  setnilvalue(&g->l_registry);\n  g->panic = NULL;\n  g->version = NULL;\n  g->gcstate = GCSpause;\n  g->gckind = KGC_NORMAL;\n  g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;\n  g->sweepgc = NULL;\n  g->gray = g->grayagain = NULL;\n  g->weak = g->ephemeron = g->allweak = NULL;\n  g->twups = NULL;\n  g->totalbytes = sizeof(LG);\n  g->GCdebt = 0;\n  g->gcfinnum = 0;\n  g->gcpause = LUAI_GCPAUSE;\n  g->gcstepmul = LUAI_GCMUL;\n  for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;\n  if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {\n    /* memory allocation error: free partial state */\n    close_state(L);\n    L = NULL;\n  }\n  return L;\n}\n\n\nLUA_API void lua_close (lua_State *L) {\n  L = G(L)->mainthread;  /* only the main thread can be closed */\n  lua_lock(L);\n  close_state(L);\n}\n\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lstate.h",
    "content": "/*\n** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $\n** Global State\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lstate_h\n#define lstate_h\n\n#include \"lua.h\"\n\n#include \"lobject.h\"\n#include \"ltm.h\"\n#include \"lzio.h\"\n\n\n/*\n\n** Some notes about garbage-collected objects: All objects in Lua must\n** be kept somehow accessible until being freed, so all objects always\n** belong to one (and only one) of these lists, using field 'next' of\n** the 'CommonHeader' for the link:\n**\n** 'allgc': all objects not marked for finalization;\n** 'finobj': all objects marked for finalization;\n** 'tobefnz': all objects ready to be finalized;\n** 'fixedgc': all objects that are not to be collected (currently\n** only small strings, such as reserved words).\n**\n** Moreover, there is another set of lists that control gray objects.\n** These lists are linked by fields 'gclist'. (All objects that\n** can become gray have such a field. The field is not the same\n** in all objects, but it always has this name.)  Any gray object\n** must belong to one of these lists, and all objects in these lists\n** must be gray:\n**\n** 'gray': regular gray objects, still waiting to be visited.\n** 'grayagain': objects that must be revisited at the atomic phase.\n**   That includes\n**   - black objects got in a write barrier;\n**   - all kinds of weak tables during propagation phase;\n**   - all threads.\n** 'weak': tables with weak values to be cleared;\n** 'ephemeron': ephemeron tables with white->white entries;\n** 'allweak': tables with weak keys and/or weak values to be cleared.\n** The last three lists are used only during the atomic phase.\n\n*/\n\n\nstruct lua_longjmp;  /* defined in ldo.c */\n\n\n/*\n** Atomic type (relative to signals) to better ensure that 'lua_sethook'\n** is thread safe\n*/\n#if !defined(l_signalT)\n#include <signal.h>\n#define l_signalT\tsig_atomic_t\n#endif\n\n\n/* extra stack space to handle TM calls and some other extras */\n#define EXTRA_STACK   5\n\n\n#define BASIC_STACK_SIZE        (2*LUA_MINSTACK)\n\n\n/* kinds of Garbage Collection */\n#define KGC_NORMAL\t0\n#define KGC_EMERGENCY\t1\t/* gc was forced by an allocation failure */\n\n\ntypedef struct stringtable {\n  TString **hash;\n  int nuse;  /* number of elements */\n  int size;\n} stringtable;\n\n\n/*\n** Information about a call.\n** When a thread yields, 'func' is adjusted to pretend that the\n** top function has only the yielded values in its stack; in that\n** case, the actual 'func' value is saved in field 'extra'.\n** When a function calls another with a continuation, 'extra' keeps\n** the function index so that, in case of errors, the continuation\n** function can be called with the correct top.\n*/\ntypedef struct CallInfo {\n  StkId func;  /* function index in the stack */\n  StkId\ttop;  /* top for this function */\n  struct CallInfo *previous, *next;  /* dynamic call link */\n  union {\n    struct {  /* only for Lua functions */\n      StkId base;  /* base for this function */\n      const Instruction *savedpc;\n    } l;\n    struct {  /* only for C functions */\n      lua_KFunction k;  /* continuation in case of yields */\n      ptrdiff_t old_errfunc;\n      lua_KContext ctx;  /* context info. in case of yields */\n    } c;\n  } u;\n  ptrdiff_t extra;\n  short nresults;  /* expected number of results from this function */\n  unsigned short callstatus;\n} CallInfo;\n\n\n/*\n** Bits in CallInfo status\n*/\n#define CIST_OAH\t(1<<0)\t/* original value of 'allowhook' */\n#define CIST_LUA\t(1<<1)\t/* call is running a Lua function */\n#define CIST_HOOKED\t(1<<2)\t/* call is running a debug hook */\n#define CIST_FRESH\t(1<<3)\t/* call is running on a fresh invocation\n                                   of luaV_execute */\n#define CIST_YPCALL\t(1<<4)\t/* call is a yieldable protected call */\n#define CIST_TAIL\t(1<<5)\t/* call was tail called */\n#define CIST_HOOKYIELD\t(1<<6)\t/* last hook called yielded */\n#define CIST_LEQ\t(1<<7)  /* using __lt for __le */\n#define CIST_FIN\t(1<<8)  /* call is running a finalizer */\n\n#define isLua(ci)\t((ci)->callstatus & CIST_LUA)\n\n/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */\n#define setoah(st,v)\t((st) = ((st) & ~CIST_OAH) | (v))\n#define getoah(st)\t((st) & CIST_OAH)\n\n\n/*\n** 'global state', shared by all threads of this state\n*/\ntypedef struct global_State {\n  lua_Alloc frealloc;  /* function to reallocate memory */\n  void *ud;         /* auxiliary data to 'frealloc' */\n  l_mem totalbytes;  /* number of bytes currently allocated - GCdebt */\n  l_mem GCdebt;  /* bytes allocated not yet compensated by the collector */\n  lu_mem GCmemtrav;  /* memory traversed by the GC */\n  lu_mem GCestimate;  /* an estimate of the non-garbage memory in use */\n  stringtable strt;  /* hash table for strings */\n  TValue l_registry;\n  unsigned int seed;  /* randomized seed for hashes */\n  lu_byte currentwhite;\n  lu_byte gcstate;  /* state of garbage collector */\n  lu_byte gckind;  /* kind of GC running */\n  lu_byte gcrunning;  /* true if GC is running */\n  GCObject *allgc;  /* list of all collectable objects */\n  GCObject **sweepgc;  /* current position of sweep in list */\n  GCObject *finobj;  /* list of collectable objects with finalizers */\n  GCObject *gray;  /* list of gray objects */\n  GCObject *grayagain;  /* list of objects to be traversed atomically */\n  GCObject *weak;  /* list of tables with weak values */\n  GCObject *ephemeron;  /* list of ephemeron tables (weak keys) */\n  GCObject *allweak;  /* list of all-weak tables */\n  GCObject *tobefnz;  /* list of userdata to be GC */\n  GCObject *fixedgc;  /* list of objects not to be collected */\n  struct lua_State *twups;  /* list of threads with open upvalues */\n  unsigned int gcfinnum;  /* number of finalizers to call in each GC step */\n  int gcpause;  /* size of pause between successive GCs */\n  int gcstepmul;  /* GC 'granularity' */\n  lua_CFunction panic;  /* to be called in unprotected errors */\n  struct lua_State *mainthread;\n  const lua_Number *version;  /* pointer to version number */\n  TString *memerrmsg;  /* memory-error message */\n  TString *tmname[TM_N];  /* array with tag-method names */\n  struct Table *mt[LUA_NUMTAGS];  /* metatables for basic types */\n  TString *strcache[STRCACHE_N][STRCACHE_M];  /* cache for strings in API */\n} global_State;\n\n\n/*\n** 'per thread' state\n*/\nstruct lua_State {\n  CommonHeader;\n  unsigned short nci;  /* number of items in 'ci' list */\n  lu_byte status;\n  StkId top;  /* first free slot in the stack */\n  global_State *l_G;\n  CallInfo *ci;  /* call info for current function */\n  const Instruction *oldpc;  /* last pc traced */\n  StkId stack_last;  /* last free slot in the stack */\n  StkId stack;  /* stack base */\n  UpVal *openupval;  /* list of open upvalues in this stack */\n  GCObject *gclist;\n  struct lua_State *twups;  /* list of threads with open upvalues */\n  struct lua_longjmp *errorJmp;  /* current error recover point */\n  CallInfo base_ci;  /* CallInfo for first level (C calling Lua) */\n  volatile lua_Hook hook;\n  ptrdiff_t errfunc;  /* current error handling function (stack index) */\n  int stacksize;\n  int basehookcount;\n  int hookcount;\n  unsigned short nny;  /* number of non-yieldable calls in stack */\n  unsigned short nCcalls;  /* number of nested C calls */\n  l_signalT hookmask;\n  lu_byte allowhook;\n};\n\n\n#define G(L)\t(L->l_G)\n\n\n/*\n** Union of all collectable objects (only for conversions)\n*/\nunion GCUnion {\n  GCObject gc;  /* common header */\n  struct TString ts;\n  struct Udata u;\n  union Closure cl;\n  struct Table h;\n  struct Proto p;\n  struct lua_State th;  /* thread */\n};\n\n\n#define cast_u(o)\tcast(union GCUnion *, (o))\n\n/* macros to convert a GCObject into a specific value */\n#define gco2ts(o)  \\\n\tcheck_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))\n#define gco2u(o)  check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u))\n#define gco2lcl(o)  check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l))\n#define gco2ccl(o)  check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c))\n#define gco2cl(o)  \\\n\tcheck_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))\n#define gco2t(o)  check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))\n#define gco2p(o)  check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))\n#define gco2th(o)  check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))\n\n\n/* macro to convert a Lua object into a GCObject */\n#define obj2gco(v) \\\n\tcheck_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))\n\n\n/* actual number of total bytes allocated */\n#define gettotalbytes(g)\tcast(lu_mem, (g)->totalbytes + (g)->GCdebt)\n\nLUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);\nLUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);\nLUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);\nLUAI_FUNC void luaE_freeCI (lua_State *L);\nLUAI_FUNC void luaE_shrinkCI (lua_State *L);\n\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lstring.c",
    "content": "/*\n** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $\n** String table (keeps all strings handled by Lua)\n** See Copyright Notice in lua.h\n*/\n\n#define lstring_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n\n\n#define MEMERRMSG       \"not enough memory\"\n\n\n/*\n** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to\n** compute its hash\n*/\n#if !defined(LUAI_HASHLIMIT)\n#define LUAI_HASHLIMIT\t\t5\n#endif\n\n\n/*\n** equality for long strings\n*/\nint luaS_eqlngstr (TString *a, TString *b) {\n  size_t len = a->u.lnglen;\n  lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);\n  return (a == b) ||  /* same instance or... */\n    ((len == b->u.lnglen) &&  /* equal length and ... */\n     (memcmp(getstr(a), getstr(b), len) == 0));  /* equal contents */\n}\n\n\nunsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {\n  unsigned int h = seed ^ cast(unsigned int, l);\n  size_t step = (l >> LUAI_HASHLIMIT) + 1;\n  for (; l >= step; l -= step)\n    h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));\n  return h;\n}\n\n\nunsigned int luaS_hashlongstr (TString *ts) {\n  lua_assert(ts->tt == LUA_TLNGSTR);\n  if (ts->extra == 0) {  /* no hash? */\n    ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);\n    ts->extra = 1;  /* now it has its hash */\n  }\n  return ts->hash;\n}\n\n\n/*\n** resizes the string table\n*/\nvoid luaS_resize (lua_State *L, int newsize) {\n  int i;\n  stringtable *tb = &G(L)->strt;\n  if (newsize > tb->size) {  /* grow table if needed */\n    luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *);\n    for (i = tb->size; i < newsize; i++)\n      tb->hash[i] = NULL;\n  }\n  for (i = 0; i < tb->size; i++) {  /* rehash */\n    TString *p = tb->hash[i];\n    tb->hash[i] = NULL;\n    while (p) {  /* for each node in the list */\n      TString *hnext = p->u.hnext;  /* save next */\n      unsigned int h = lmod(p->hash, newsize);  /* new position */\n      p->u.hnext = tb->hash[h];  /* chain it */\n      tb->hash[h] = p;\n      p = hnext;\n    }\n  }\n  if (newsize < tb->size) {  /* shrink table if needed */\n    /* vanishing slice should be empty */\n    lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL);\n    luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *);\n  }\n  tb->size = newsize;\n}\n\n\n/*\n** Clear API string cache. (Entries cannot be empty, so fill them with\n** a non-collectable string.)\n*/\nvoid luaS_clearcache (global_State *g) {\n  int i, j;\n  for (i = 0; i < STRCACHE_N; i++)\n    for (j = 0; j < STRCACHE_M; j++) {\n    if (iswhite(g->strcache[i][j]))  /* will entry be collected? */\n      g->strcache[i][j] = g->memerrmsg;  /* replace it with something fixed */\n    }\n}\n\n\n/*\n** Initialize the string table and the string cache\n*/\nvoid luaS_init (lua_State *L) {\n  global_State *g = G(L);\n  int i, j;\n  luaS_resize(L, MINSTRTABSIZE);  /* initial size of string table */\n  /* pre-create memory-error message */\n  g->memerrmsg = luaS_newliteral(L, MEMERRMSG);\n  luaC_fix(L, obj2gco(g->memerrmsg));  /* it should never be collected */\n  for (i = 0; i < STRCACHE_N; i++)  /* fill cache with valid strings */\n    for (j = 0; j < STRCACHE_M; j++)\n      g->strcache[i][j] = g->memerrmsg;\n}\n\n\n\n/*\n** creates a new string object\n*/\nstatic TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {\n  TString *ts;\n  GCObject *o;\n  size_t totalsize;  /* total size of TString object */\n  totalsize = sizelstring(l);\n  o = luaC_newobj(L, tag, totalsize);\n  ts = gco2ts(o);\n  ts->hash = h;\n  ts->extra = 0;\n  getstr(ts)[l] = '\\0';  /* ending 0 */\n  return ts;\n}\n\n\nTString *luaS_createlngstrobj (lua_State *L, size_t l) {\n  TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);\n  ts->u.lnglen = l;\n  return ts;\n}\n\n\nvoid luaS_remove (lua_State *L, TString *ts) {\n  stringtable *tb = &G(L)->strt;\n  TString **p = &tb->hash[lmod(ts->hash, tb->size)];\n  while (*p != ts)  /* find previous element */\n    p = &(*p)->u.hnext;\n  *p = (*p)->u.hnext;  /* remove element from its list */\n  tb->nuse--;\n}\n\n\n/*\n** checks whether short string exists and reuses it or creates a new one\n*/\nstatic TString *internshrstr (lua_State *L, const char *str, size_t l) {\n  TString *ts;\n  global_State *g = G(L);\n  unsigned int h = luaS_hash(str, l, g->seed);\n  TString **list = &g->strt.hash[lmod(h, g->strt.size)];\n  lua_assert(str != NULL);  /* otherwise 'memcmp'/'memcpy' are undefined */\n  for (ts = *list; ts != NULL; ts = ts->u.hnext) {\n    if (l == ts->shrlen &&\n        (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {\n      /* found! */\n      if (isdead(g, ts))  /* dead (but not collected yet)? */\n        changewhite(ts);  /* resurrect it */\n      return ts;\n    }\n  }\n  if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {\n    luaS_resize(L, g->strt.size * 2);\n    list = &g->strt.hash[lmod(h, g->strt.size)];  /* recompute with new size */\n  }\n  ts = createstrobj(L, l, LUA_TSHRSTR, h);\n  memcpy(getstr(ts), str, l * sizeof(char));\n  ts->shrlen = cast_byte(l);\n  ts->u.hnext = *list;\n  *list = ts;\n  g->strt.nuse++;\n  return ts;\n}\n\n\n/*\n** new string (with explicit length)\n*/\nTString *luaS_newlstr (lua_State *L, const char *str, size_t l) {\n  if (l <= LUAI_MAXSHORTLEN)  /* short string? */\n    return internshrstr(L, str, l);\n  else {\n    TString *ts;\n    if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))\n      luaM_toobig(L);\n    ts = luaS_createlngstrobj(L, l);\n    memcpy(getstr(ts), str, l * sizeof(char));\n    return ts;\n  }\n}\n\n\n/*\n** Create or reuse a zero-terminated string, first checking in the\n** cache (using the string address as a key). The cache can contain\n** only zero-terminated strings, so it is safe to use 'strcmp' to\n** check hits.\n*/\nTString *luaS_new (lua_State *L, const char *str) {\n  unsigned int i = point2uint(str) % STRCACHE_N;  /* hash */\n  int j;\n  TString **p = G(L)->strcache[i];\n  for (j = 0; j < STRCACHE_M; j++) {\n    if (strcmp(str, getstr(p[j])) == 0)  /* hit? */\n      return p[j];  /* that is it */\n  }\n  /* normal route */\n  for (j = STRCACHE_M - 1; j > 0; j--)\n    p[j] = p[j - 1];  /* move out last element */\n  /* new element is first in the list */\n  p[0] = luaS_newlstr(L, str, strlen(str));\n  return p[0];\n}\n\n\nUdata *luaS_newudata (lua_State *L, size_t s) {\n  Udata *u;\n  GCObject *o;\n  if (s > MAX_SIZE - sizeof(Udata))\n    luaM_toobig(L);\n  o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s));\n  u = gco2u(o);\n  u->len = s;\n  u->metatable = NULL;\n  setuservalue(L, u, luaO_nilobject);\n  return u;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lstring.h",
    "content": "/*\n** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $\n** String table (keep all strings handled by Lua)\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lstring_h\n#define lstring_h\n\n#include \"lgc.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n\n\n#define sizelstring(l)  (sizeof(union UTString) + ((l) + 1) * sizeof(char))\n\n#define sizeludata(l)\t(sizeof(union UUdata) + (l))\n#define sizeudata(u)\tsizeludata((u)->len)\n\n#define luaS_newliteral(L, s)\t(luaS_newlstr(L, \"\" s, \\\n                                 (sizeof(s)/sizeof(char))-1))\n\n\n/*\n** test whether a string is a reserved word\n*/\n#define isreserved(s)\t((s)->tt == LUA_TSHRSTR && (s)->extra > 0)\n\n\n/*\n** equality for short strings, which are always internalized\n*/\n#define eqshrstr(a,b)\tcheck_exp((a)->tt == LUA_TSHRSTR, (a) == (b))\n\n\nLUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);\nLUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);\nLUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);\nLUAI_FUNC void luaS_resize (lua_State *L, int newsize);\nLUAI_FUNC void luaS_clearcache (global_State *g);\nLUAI_FUNC void luaS_init (lua_State *L);\nLUAI_FUNC void luaS_remove (lua_State *L, TString *ts);\nLUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);\nLUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);\nLUAI_FUNC TString *luaS_new (lua_State *L, const char *str);\nLUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lstrlib.c",
    "content": "#pragma warning(disable: 4310)\n/*\n** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $\n** Standard library for string operations and pattern-matching\n** See Copyright Notice in lua.h\n*/\n\n#define lstrlib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <ctype.h>\n#include <float.h>\n#include <limits.h>\n#include <locale.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n/*\n** maximum number of captures that a pattern can do during\n** pattern-matching. This limit is arbitrary, but must fit in\n** an unsigned char.\n*/\n#if !defined(LUA_MAXCAPTURES)\n#define LUA_MAXCAPTURES\t\t32\n#endif\n\n\n/* macro to 'unsign' a character */\n#define uchar(c)\t((unsigned char)(c))\n\n\n/*\n** Some sizes are better limited to fit in 'int', but must also fit in\n** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)\n*/\n#define MAX_SIZET\t((size_t)(~(size_t)0))\n\n#define MAXSIZE  \\\n\t(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))\n\n\n\n\nstatic int str_len (lua_State *L) {\n  size_t l;\n  luaL_checklstring(L, 1, &l);\n  lua_pushinteger(L, (lua_Integer)l);\n  return 1;\n}\n\n\n/* translate a relative string position: negative means back from end */\nstatic lua_Integer posrelat (lua_Integer pos, size_t len) {\n  if (pos >= 0) return pos;\n  else if (0u - (size_t)pos > len) return 0;\n  else return (lua_Integer)len + pos + 1;\n}\n\n\nstatic int str_sub (lua_State *L) {\n  size_t l;\n  const char *s = luaL_checklstring(L, 1, &l);\n  lua_Integer start = posrelat(luaL_checkinteger(L, 2), l);\n  lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l);\n  if (start < 1) start = 1;\n  if (end > (lua_Integer)l) end = l;\n  if (start <= end)\n    lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);\n  else lua_pushliteral(L, \"\");\n  return 1;\n}\n\n\nstatic int str_reverse (lua_State *L) {\n  size_t l, i;\n  luaL_Buffer b;\n  const char *s = luaL_checklstring(L, 1, &l);\n  char *p = luaL_buffinitsize(L, &b, l);\n  for (i = 0; i < l; i++)\n    p[i] = s[l - i - 1];\n  luaL_pushresultsize(&b, l);\n  return 1;\n}\n\n\nstatic int str_lower (lua_State *L) {\n  size_t l;\n  size_t i;\n  luaL_Buffer b;\n  const char *s = luaL_checklstring(L, 1, &l);\n  char *p = luaL_buffinitsize(L, &b, l);\n  for (i=0; i<l; i++)\n    p[i] = tolower(uchar(s[i]));\n  luaL_pushresultsize(&b, l);\n  return 1;\n}\n\n\nstatic int str_upper (lua_State *L) {\n  size_t l;\n  size_t i;\n  luaL_Buffer b;\n  const char *s = luaL_checklstring(L, 1, &l);\n  char *p = luaL_buffinitsize(L, &b, l);\n  for (i=0; i<l; i++)\n    p[i] = toupper(uchar(s[i]));\n  luaL_pushresultsize(&b, l);\n  return 1;\n}\n\n\nstatic int str_rep (lua_State *L) {\n  size_t l, lsep;\n  const char *s = luaL_checklstring(L, 1, &l);\n  lua_Integer n = luaL_checkinteger(L, 2);\n  const char *sep = luaL_optlstring(L, 3, \"\", &lsep);\n  if (n <= 0) lua_pushliteral(L, \"\");\n  else if (l + lsep < l || l + lsep > MAXSIZE / n)  /* may overflow? */\n    return luaL_error(L, \"resulting string too large\");\n  else {\n    size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;\n    luaL_Buffer b;\n    char *p = luaL_buffinitsize(L, &b, totallen);\n    while (n-- > 1) {  /* first n-1 copies (followed by separator) */\n      memcpy(p, s, l * sizeof(char)); p += l;\n      if (lsep > 0) {  /* empty 'memcpy' is not that cheap */\n        memcpy(p, sep, lsep * sizeof(char));\n        p += lsep;\n      }\n    }\n    memcpy(p, s, l * sizeof(char));  /* last copy (not followed by separator) */\n    luaL_pushresultsize(&b, totallen);\n  }\n  return 1;\n}\n\n\nstatic int str_byte (lua_State *L) {\n  size_t l;\n  const char *s = luaL_checklstring(L, 1, &l);\n  lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l);\n  lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l);\n  int n, i;\n  if (posi < 1) posi = 1;\n  if (pose > (lua_Integer)l) pose = l;\n  if (posi > pose) return 0;  /* empty interval; return no values */\n  if (pose - posi >= INT_MAX)  /* arithmetic overflow? */\n    return luaL_error(L, \"string slice too long\");\n  n = (int)(pose -  posi) + 1;\n  luaL_checkstack(L, n, \"string slice too long\");\n  for (i=0; i<n; i++)\n    lua_pushinteger(L, uchar(s[posi+i-1]));\n  return n;\n}\n\n\nstatic int str_char (lua_State *L) {\n  int n = lua_gettop(L);  /* number of arguments */\n  int i;\n  luaL_Buffer b;\n  char *p = luaL_buffinitsize(L, &b, n);\n  for (i=1; i<=n; i++) {\n    lua_Integer c = luaL_checkinteger(L, i);\n    luaL_argcheck(L, uchar(c) == c, i, \"value out of range\");\n    p[i - 1] = uchar(c);\n  }\n  luaL_pushresultsize(&b, n);\n  return 1;\n}\n\n\nstatic int writer (lua_State *L, const void *b, size_t size, void *B) {\n  (void)L;\n  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);\n  return 0;\n}\n\n\nstatic int str_dump (lua_State *L) {\n  luaL_Buffer b;\n  int strip = lua_toboolean(L, 2);\n  luaL_checktype(L, 1, LUA_TFUNCTION);\n  lua_settop(L, 1);\n  luaL_buffinit(L,&b);\n  if (lua_dump(L, writer, &b, strip) != 0)\n    return luaL_error(L, \"unable to dump given function\");\n  luaL_pushresult(&b);\n  return 1;\n}\n\n\n\n/*\n** {======================================================\n** PATTERN MATCHING\n** =======================================================\n*/\n\n\n#define CAP_UNFINISHED\t(-1)\n#define CAP_POSITION\t(-2)\n\n\ntypedef struct MatchState {\n  const char *src_init;  /* init of source string */\n  const char *src_end;  /* end ('\\0') of source string */\n  const char *p_end;  /* end ('\\0') of pattern */\n  lua_State *L;\n  int matchdepth;  /* control for recursive depth (to avoid C stack overflow) */\n  unsigned char level;  /* total number of captures (finished or unfinished) */\n  struct {\n    const char *init;\n    ptrdiff_t len;\n  } capture[LUA_MAXCAPTURES];\n} MatchState;\n\n\n/* recursive function */\nstatic const char *match (MatchState *ms, const char *s, const char *p);\n\n\n/* maximum recursion depth for 'match' */\n#if !defined(MAXCCALLS)\n#define MAXCCALLS\t200\n#endif\n\n\n#define L_ESC\t\t'%'\n#define SPECIALS\t\"^$*+?.([%-\"\n\n\nstatic int check_capture (MatchState *ms, int l) {\n  l -= '1';\n  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)\n    return luaL_error(ms->L, \"invalid capture index %%%d\", l + 1);\n  return l;\n}\n\n\nstatic int capture_to_close (MatchState *ms) {\n  int level = ms->level;\n  for (level--; level>=0; level--)\n    if (ms->capture[level].len == CAP_UNFINISHED) return level;\n  return luaL_error(ms->L, \"invalid pattern capture\");\n}\n\n\nstatic const char *classend (MatchState *ms, const char *p) {\n  switch (*p++) {\n    case L_ESC: {\n      if (p == ms->p_end)\n        luaL_error(ms->L, \"malformed pattern (ends with '%%')\");\n      return p+1;\n    }\n    case '[': {\n      if (*p == '^') p++;\n      do {  /* look for a ']' */\n        if (p == ms->p_end)\n          luaL_error(ms->L, \"malformed pattern (missing ']')\");\n        if (*(p++) == L_ESC && p < ms->p_end)\n          p++;  /* skip escapes (e.g. '%]') */\n      } while (*p != ']');\n      return p+1;\n    }\n    default: {\n      return p;\n    }\n  }\n}\n\n\nstatic int match_class (int c, int cl) {\n  int res;\n  switch (tolower(cl)) {\n    case 'a' : res = isalpha(c); break;\n    case 'c' : res = iscntrl(c); break;\n    case 'd' : res = isdigit(c); break;\n    case 'g' : res = isgraph(c); break;\n    case 'l' : res = islower(c); break;\n    case 'p' : res = ispunct(c); break;\n    case 's' : res = isspace(c); break;\n    case 'u' : res = isupper(c); break;\n    case 'w' : res = isalnum(c); break;\n    case 'x' : res = isxdigit(c); break;\n    case 'z' : res = (c == 0); break;  /* deprecated option */\n    default: return (cl == c);\n  }\n  return (islower(cl) ? res : !res);\n}\n\n\nstatic int matchbracketclass (int c, const char *p, const char *ec) {\n  int sig = 1;\n  if (*(p+1) == '^') {\n    sig = 0;\n    p++;  /* skip the '^' */\n  }\n  while (++p < ec) {\n    if (*p == L_ESC) {\n      p++;\n      if (match_class(c, uchar(*p)))\n        return sig;\n    }\n    else if ((*(p+1) == '-') && (p+2 < ec)) {\n      p+=2;\n      if (uchar(*(p-2)) <= c && c <= uchar(*p))\n        return sig;\n    }\n    else if (uchar(*p) == c) return sig;\n  }\n  return !sig;\n}\n\n\nstatic int singlematch (MatchState *ms, const char *s, const char *p,\n                        const char *ep) {\n  if (s >= ms->src_end)\n    return 0;\n  else {\n    int c = uchar(*s);\n    switch (*p) {\n      case '.': return 1;  /* matches any char */\n      case L_ESC: return match_class(c, uchar(*(p+1)));\n      case '[': return matchbracketclass(c, p, ep-1);\n      default:  return (uchar(*p) == c);\n    }\n  }\n}\n\n\nstatic const char *matchbalance (MatchState *ms, const char *s,\n                                   const char *p) {\n  if (p >= ms->p_end - 1)\n    luaL_error(ms->L, \"malformed pattern (missing arguments to '%%b')\");\n  if (*s != *p) return NULL;\n  else {\n    int b = *p;\n    int e = *(p+1);\n    int cont = 1;\n    while (++s < ms->src_end) {\n      if (*s == e) {\n        if (--cont == 0) return s+1;\n      }\n      else if (*s == b) cont++;\n    }\n  }\n  return NULL;  /* string ends out of balance */\n}\n\n\nstatic const char *max_expand (MatchState *ms, const char *s,\n                                 const char *p, const char *ep) {\n  ptrdiff_t i = 0;  /* counts maximum expand for item */\n  while (singlematch(ms, s + i, p, ep))\n    i++;\n  /* keeps trying to match with the maximum repetitions */\n  while (i>=0) {\n    const char *res = match(ms, (s+i), ep+1);\n    if (res) return res;\n    i--;  /* else didn't match; reduce 1 repetition to try again */\n  }\n  return NULL;\n}\n\n\nstatic const char *min_expand (MatchState *ms, const char *s,\n                                 const char *p, const char *ep) {\n  for (;;) {\n    const char *res = match(ms, s, ep+1);\n    if (res != NULL)\n      return res;\n    else if (singlematch(ms, s, p, ep))\n      s++;  /* try with one more repetition */\n    else return NULL;\n  }\n}\n\n\nstatic const char *start_capture (MatchState *ms, const char *s,\n                                    const char *p, int what) {\n  const char *res;\n  int level = ms->level;\n  if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, \"too many captures\");\n  ms->capture[level].init = s;\n  ms->capture[level].len = what;\n  ms->level = level+1;\n  if ((res=match(ms, s, p)) == NULL)  /* match failed? */\n    ms->level--;  /* undo capture */\n  return res;\n}\n\n\nstatic const char *end_capture (MatchState *ms, const char *s,\n                                  const char *p) {\n  int l = capture_to_close(ms);\n  const char *res;\n  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */\n  if ((res = match(ms, s, p)) == NULL)  /* match failed? */\n    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */\n  return res;\n}\n\n\nstatic const char *match_capture (MatchState *ms, const char *s, int l) {\n  size_t len;\n  l = check_capture(ms, l);\n  len = ms->capture[l].len;\n  if ((size_t)(ms->src_end-s) >= len &&\n      memcmp(ms->capture[l].init, s, len) == 0)\n    return s+len;\n  else return NULL;\n}\n\n\nstatic const char *match (MatchState *ms, const char *s, const char *p) {\n  if (ms->matchdepth-- == 0)\n    luaL_error(ms->L, \"pattern too complex\");\n  init: /* using goto's to optimize tail recursion */\n  if (p != ms->p_end) {  /* end of pattern? */\n    switch (*p) {\n      case '(': {  /* start capture */\n        if (*(p + 1) == ')')  /* position capture? */\n          s = start_capture(ms, s, p + 2, CAP_POSITION);\n        else\n          s = start_capture(ms, s, p + 1, CAP_UNFINISHED);\n        break;\n      }\n      case ')': {  /* end capture */\n        s = end_capture(ms, s, p + 1);\n        break;\n      }\n      case '$': {\n        if ((p + 1) != ms->p_end)  /* is the '$' the last char in pattern? */\n          goto dflt;  /* no; go to default */\n        s = (s == ms->src_end) ? s : NULL;  /* check end of string */\n        break;\n      }\n      case L_ESC: {  /* escaped sequences not in the format class[*+?-]? */\n        switch (*(p + 1)) {\n          case 'b': {  /* balanced string? */\n            s = matchbalance(ms, s, p + 2);\n            if (s != NULL) {\n              p += 4; goto init;  /* return match(ms, s, p + 4); */\n            }  /* else fail (s == NULL) */\n            break;\n          }\n          case 'f': {  /* frontier? */\n            const char *ep; char previous;\n            p += 2;\n            if (*p != '[')\n              luaL_error(ms->L, \"missing '[' after '%%f' in pattern\");\n            ep = classend(ms, p);  /* points to what is next */\n            previous = (s == ms->src_init) ? '\\0' : *(s - 1);\n            if (!matchbracketclass(uchar(previous), p, ep - 1) &&\n               matchbracketclass(uchar(*s), p, ep - 1)) {\n              p = ep; goto init;  /* return match(ms, s, ep); */\n            }\n            s = NULL;  /* match failed */\n            break;\n          }\n          case '0': case '1': case '2': case '3':\n          case '4': case '5': case '6': case '7':\n          case '8': case '9': {  /* capture results (%0-%9)? */\n            s = match_capture(ms, s, uchar(*(p + 1)));\n            if (s != NULL) {\n              p += 2; goto init;  /* return match(ms, s, p + 2) */\n            }\n            break;\n          }\n          default: goto dflt;\n        }\n        break;\n      }\n      default: dflt: {  /* pattern class plus optional suffix */\n        const char *ep = classend(ms, p);  /* points to optional suffix */\n        /* does not match at least once? */\n        if (!singlematch(ms, s, p, ep)) {\n          if (*ep == '*' || *ep == '?' || *ep == '-') {  /* accept empty? */\n            p = ep + 1; goto init;  /* return match(ms, s, ep + 1); */\n          }\n          else  /* '+' or no suffix */\n            s = NULL;  /* fail */\n        }\n        else {  /* matched once */\n          switch (*ep) {  /* handle optional suffix */\n            case '?': {  /* optional */\n              const char *res;\n              if ((res = match(ms, s + 1, ep + 1)) != NULL)\n                s = res;\n              else {\n                p = ep + 1; goto init;  /* else return match(ms, s, ep + 1); */\n              }\n              break;\n            }\n            case '+':  /* 1 or more repetitions */\n              s++;  /* 1 match already done */\n              /* FALLTHROUGH */\n            case '*':  /* 0 or more repetitions */\n              s = max_expand(ms, s, p, ep);\n              break;\n            case '-':  /* 0 or more repetitions (minimum) */\n              s = min_expand(ms, s, p, ep);\n              break;\n            default:  /* no suffix */\n              s++; p = ep; goto init;  /* return match(ms, s + 1, ep); */\n          }\n        }\n        break;\n      }\n    }\n  }\n  ms->matchdepth++;\n  return s;\n}\n\n\n\nstatic const char *lmemfind (const char *s1, size_t l1,\n                               const char *s2, size_t l2) {\n  if (l2 == 0) return s1;  /* empty strings are everywhere */\n  else if (l2 > l1) return NULL;  /* avoids a negative 'l1' */\n  else {\n    const char *init;  /* to search for a '*s2' inside 's1' */\n    l2--;  /* 1st char will be checked by 'memchr' */\n    l1 = l1-l2;  /* 's2' cannot be found after that */\n    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {\n      init++;   /* 1st char is already checked */\n      if (memcmp(init, s2+1, l2) == 0)\n        return init-1;\n      else {  /* correct 'l1' and 's1' to try again */\n        l1 -= init-s1;\n        s1 = init;\n      }\n    }\n    return NULL;  /* not found */\n  }\n}\n\n\nstatic void push_onecapture (MatchState *ms, int i, const char *s,\n                                                    const char *e) {\n  if (i >= ms->level) {\n    if (i == 0)  /* ms->level == 0, too */\n      lua_pushlstring(ms->L, s, e - s);  /* add whole match */\n    else\n      luaL_error(ms->L, \"invalid capture index %%%d\", i + 1);\n  }\n  else {\n    ptrdiff_t l = ms->capture[i].len;\n    if (l == CAP_UNFINISHED) luaL_error(ms->L, \"unfinished capture\");\n    if (l == CAP_POSITION)\n      lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);\n    else\n      lua_pushlstring(ms->L, ms->capture[i].init, l);\n  }\n}\n\n\nstatic int push_captures (MatchState *ms, const char *s, const char *e) {\n  int i;\n  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;\n  luaL_checkstack(ms->L, nlevels, \"too many captures\");\n  for (i = 0; i < nlevels; i++)\n    push_onecapture(ms, i, s, e);\n  return nlevels;  /* number of strings pushed */\n}\n\n\n/* check whether pattern has no special characters */\nstatic int nospecials (const char *p, size_t l) {\n  size_t upto = 0;\n  do {\n    if (strpbrk(p + upto, SPECIALS))\n      return 0;  /* pattern has a special character */\n    upto += strlen(p + upto) + 1;  /* may have more after \\0 */\n  } while (upto <= l);\n  return 1;  /* no special chars found */\n}\n\n\nstatic void prepstate (MatchState *ms, lua_State *L,\n                       const char *s, size_t ls, const char *p, size_t lp) {\n  ms->L = L;\n  ms->matchdepth = MAXCCALLS;\n  ms->src_init = s;\n  ms->src_end = s + ls;\n  ms->p_end = p + lp;\n}\n\n\nstatic void reprepstate (MatchState *ms) {\n  ms->level = 0;\n  lua_assert(ms->matchdepth == MAXCCALLS);\n}\n\n\nstatic int str_find_aux (lua_State *L, int find) {\n  size_t ls, lp;\n  const char *s = luaL_checklstring(L, 1, &ls);\n  const char *p = luaL_checklstring(L, 2, &lp);\n  lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls);\n  if (init < 1) init = 1;\n  else if (init > (lua_Integer)ls + 1) {  /* start after string's end? */\n    lua_pushnil(L);  /* cannot find anything */\n    return 1;\n  }\n  /* explicit request or no special characters? */\n  if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {\n    /* do a plain search */\n    const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);\n    if (s2) {\n      lua_pushinteger(L, (s2 - s) + 1);\n      lua_pushinteger(L, (s2 - s) + lp);\n      return 2;\n    }\n  }\n  else {\n    MatchState ms;\n    const char *s1 = s + init - 1;\n    int anchor = (*p == '^');\n    if (anchor) {\n      p++; lp--;  /* skip anchor character */\n    }\n    prepstate(&ms, L, s, ls, p, lp);\n    do {\n      const char *res;\n      reprepstate(&ms);\n      if ((res=match(&ms, s1, p)) != NULL) {\n        if (find) {\n          lua_pushinteger(L, (s1 - s) + 1);  /* start */\n          lua_pushinteger(L, res - s);   /* end */\n          return push_captures(&ms, NULL, 0) + 2;\n        }\n        else\n          return push_captures(&ms, s1, res);\n      }\n    } while (s1++ < ms.src_end && !anchor);\n  }\n  lua_pushnil(L);  /* not found */\n  return 1;\n}\n\n\nstatic int str_find (lua_State *L) {\n  return str_find_aux(L, 1);\n}\n\n\nstatic int str_match (lua_State *L) {\n  return str_find_aux(L, 0);\n}\n\n\n/* state for 'gmatch' */\ntypedef struct GMatchState {\n  const char *src;  /* current position */\n  const char *p;  /* pattern */\n  const char *lastmatch;  /* end of last match */\n  MatchState ms;  /* match state */\n} GMatchState;\n\n\nstatic int gmatch_aux (lua_State *L) {\n  GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));\n  const char *src;\n  gm->ms.L = L;\n  for (src = gm->src; src <= gm->ms.src_end; src++) {\n    const char *e;\n    reprepstate(&gm->ms);\n    if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {\n      gm->src = gm->lastmatch = e;\n      return push_captures(&gm->ms, src, e);\n    }\n  }\n  return 0;  /* not found */\n}\n\n\nstatic int gmatch (lua_State *L) {\n  size_t ls, lp;\n  const char *s = luaL_checklstring(L, 1, &ls);\n  const char *p = luaL_checklstring(L, 2, &lp);\n  GMatchState *gm;\n  lua_settop(L, 2);  /* keep them on closure to avoid being collected */\n  gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));\n  prepstate(&gm->ms, L, s, ls, p, lp);\n  gm->src = s; gm->p = p; gm->lastmatch = NULL;\n  lua_pushcclosure(L, gmatch_aux, 3);\n  return 1;\n}\n\n\nstatic void add_s (MatchState *ms, luaL_Buffer *b, const char *s,\n                                                   const char *e) {\n  size_t l, i;\n  lua_State *L = ms->L;\n  const char *news = lua_tolstring(L, 3, &l);\n  for (i = 0; i < l; i++) {\n    if (news[i] != L_ESC)\n      luaL_addchar(b, news[i]);\n    else {\n      i++;  /* skip ESC */\n      if (!isdigit(uchar(news[i]))) {\n        if (news[i] != L_ESC)\n          luaL_error(L, \"invalid use of '%c' in replacement string\", L_ESC);\n        luaL_addchar(b, news[i]);\n      }\n      else if (news[i] == '0')\n          luaL_addlstring(b, s, e - s);\n      else {\n        push_onecapture(ms, news[i] - '1', s, e);\n        luaL_tolstring(L, -1, NULL);  /* if number, convert it to string */\n        lua_remove(L, -2);  /* remove original value */\n        luaL_addvalue(b);  /* add capture to accumulated result */\n      }\n    }\n  }\n}\n\n\nstatic void add_value (MatchState *ms, luaL_Buffer *b, const char *s,\n                                       const char *e, int tr) {\n  lua_State *L = ms->L;\n  switch (tr) {\n    case LUA_TFUNCTION: {\n      int n;\n      lua_pushvalue(L, 3);\n      n = push_captures(ms, s, e);\n      lua_call(L, n, 1);\n      break;\n    }\n    case LUA_TTABLE: {\n      push_onecapture(ms, 0, s, e);\n      lua_gettable(L, 3);\n      break;\n    }\n    default: {  /* LUA_TNUMBER or LUA_TSTRING */\n      add_s(ms, b, s, e);\n      return;\n    }\n  }\n  if (!lua_toboolean(L, -1)) {  /* nil or false? */\n    lua_pop(L, 1);\n    lua_pushlstring(L, s, e - s);  /* keep original text */\n  }\n  else if (!lua_isstring(L, -1))\n    luaL_error(L, \"invalid replacement value (a %s)\", luaL_typename(L, -1));\n  luaL_addvalue(b);  /* add result to accumulator */\n}\n\n\nstatic int str_gsub (lua_State *L) {\n  size_t srcl, lp;\n  const char *src = luaL_checklstring(L, 1, &srcl);  /* subject */\n  const char *p = luaL_checklstring(L, 2, &lp);  /* pattern */\n  const char *lastmatch = NULL;  /* end of last match */\n  int tr = lua_type(L, 3);  /* replacement type */\n  lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);  /* max replacements */\n  int anchor = (*p == '^');\n  lua_Integer n = 0;  /* replacement count */\n  MatchState ms;\n  luaL_Buffer b;\n  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||\n                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,\n                      \"string/function/table expected\");\n  luaL_buffinit(L, &b);\n  if (anchor) {\n    p++; lp--;  /* skip anchor character */\n  }\n  prepstate(&ms, L, src, srcl, p, lp);\n  while (n < max_s) {\n    const char *e;\n    reprepstate(&ms);  /* (re)prepare state for new match */\n    if ((e = match(&ms, src, p)) != NULL && e != lastmatch) {  /* match? */\n      n++;\n      add_value(&ms, &b, src, e, tr);  /* add replacement to buffer */\n      src = lastmatch = e;\n    }\n    else if (src < ms.src_end)  /* otherwise, skip one character */\n      luaL_addchar(&b, *src++);\n    else break;  /* end of subject */\n    if (anchor) break;\n  }\n  luaL_addlstring(&b, src, ms.src_end-src);\n  luaL_pushresult(&b);\n  lua_pushinteger(L, n);  /* number of substitutions */\n  return 2;\n}\n\n/* }====================================================== */\n\n\n\n/*\n** {======================================================\n** STRING FORMAT\n** =======================================================\n*/\n\n#if !defined(lua_number2strx)\t/* { */\n\n/*\n** Hexadecimal floating-point formatter\n*/\n\n#include <math.h>\n\n#define SIZELENMOD\t(sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))\n\n\n/*\n** Number of bits that goes into the first digit. It can be any value\n** between 1 and 4; the following definition tries to align the number\n** to nibble boundaries by making what is left after that first digit a\n** multiple of 4.\n*/\n#define L_NBFD\t\t((l_mathlim(MANT_DIG) - 1)%4 + 1)\n\n\n/*\n** Add integer part of 'x' to buffer and return new 'x'\n*/\nstatic lua_Number adddigit (char *buff, int n, lua_Number x) {\n  lua_Number dd = l_mathop(floor)(x);  /* get integer part from 'x' */\n  int d = (int)dd;\n  buff[n] = (d < 10 ? d + '0' : d - 10 + 'a');  /* add to buffer */\n  return x - dd;  /* return what is left */\n}\n\n\nstatic int num2straux (char *buff, int sz, lua_Number x) {\n  /* if 'inf' or 'NaN', format it like '%g' */\n  if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)\n    return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);\n  else if (x == 0) {  /* can be -0... */\n    /* create \"0\" or \"-0\" followed by exponent */\n    return l_sprintf(buff, sz, LUA_NUMBER_FMT \"x0p+0\", (LUAI_UACNUMBER)x);\n  }\n  else {\n    int e;\n    lua_Number m = l_mathop(frexp)(x, &e);  /* 'x' fraction and exponent */\n    int n = 0;  /* character count */\n    if (m < 0) {  /* is number negative? */\n      buff[n++] = '-';  /* add signal */\n      m = -m;  /* make it positive */\n    }\n    buff[n++] = '0'; buff[n++] = 'x';  /* add \"0x\" */\n    m = adddigit(buff, n++, m * (1 << L_NBFD));  /* add first digit */\n    e -= L_NBFD;  /* this digit goes before the radix point */\n    if (m > 0) {  /* more digits? */\n      buff[n++] = lua_getlocaledecpoint();  /* add radix point */\n      do {  /* add as many digits as needed */\n        m = adddigit(buff, n++, m * 16);\n      } while (m > 0);\n    }\n    n += l_sprintf(buff + n, sz - n, \"p%+d\", e);  /* add exponent */\n    lua_assert(n < sz);\n    return n;\n  }\n}\n\n\nstatic int lua_number2strx (lua_State *L, char *buff, int sz,\n                            const char *fmt, lua_Number x) {\n  int n = num2straux(buff, sz, x);\n  if (fmt[SIZELENMOD] == 'A') {\n    int i;\n    for (i = 0; i < n; i++)\n      buff[i] = toupper(uchar(buff[i]));\n  }\n  else if (fmt[SIZELENMOD] != 'a')\n    return luaL_error(L, \"modifiers for format '%%a'/'%%A' not implemented\");\n  return n;\n}\n\n#endif\t\t\t\t/* } */\n\n\n/*\n** Maximum size of each formatted item. This maximum size is produced\n** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',\n** and '\\0') + number of decimal digits to represent maxfloat (which\n** is maximum exponent + 1). (99+3+1 then rounded to 120 for \"extra\n** expenses\", such as locale-dependent stuff)\n*/\n#define MAX_ITEM        (120 + l_mathlim(MAX_10_EXP))\n\n\n/* valid flags in a format specification */\n#define FLAGS\t\"-+ #0\"\n\n/*\n** maximum size of each format specification (such as \"%-099.99d\")\n*/\n#define MAX_FORMAT\t32\n\n\nstatic void addquoted (luaL_Buffer *b, const char *s, size_t len) {\n  luaL_addchar(b, '\"');\n  while (len--) {\n    if (*s == '\"' || *s == '\\\\' || *s == '\\n') {\n      luaL_addchar(b, '\\\\');\n      luaL_addchar(b, *s);\n    }\n    else if (iscntrl(uchar(*s))) {\n      char buff[10];\n      if (!isdigit(uchar(*(s+1))))\n        l_sprintf(buff, sizeof(buff), \"\\\\%d\", (int)uchar(*s));\n      else\n        l_sprintf(buff, sizeof(buff), \"\\\\%03d\", (int)uchar(*s));\n      luaL_addstring(b, buff);\n    }\n    else\n      luaL_addchar(b, *s);\n    s++;\n  }\n  luaL_addchar(b, '\"');\n}\n\n\n/*\n** Ensures the 'buff' string uses a dot as the radix character.\n*/\nstatic void checkdp (char *buff, int nb) {\n  if (memchr(buff, '.', nb) == NULL) {  /* no dot? */\n    char point = lua_getlocaledecpoint();  /* try locale point */\n    char *ppoint = (char *)memchr(buff, point, nb);\n    if (ppoint) *ppoint = '.';  /* change it to a dot */\n  }\n}\n\n\nstatic void addliteral (lua_State *L, luaL_Buffer *b, int arg) {\n  switch (lua_type(L, arg)) {\n    case LUA_TSTRING: {\n      size_t len;\n      const char *s = lua_tolstring(L, arg, &len);\n      addquoted(b, s, len);\n      break;\n    }\n    case LUA_TNUMBER: {\n      char *buff = luaL_prepbuffsize(b, MAX_ITEM);\n      int nb;\n      if (!lua_isinteger(L, arg)) {  /* float? */\n        lua_Number n = lua_tonumber(L, arg);  /* write as hexa ('%a') */\n        nb = lua_number2strx(L, buff, MAX_ITEM, \"%\" LUA_NUMBER_FRMLEN \"a\", n);\n        checkdp(buff, nb);  /* ensure it uses a dot */\n      }\n      else {  /* integers */\n        lua_Integer n = lua_tointeger(L, arg);\n        const char *format = (n == LUA_MININTEGER)  /* corner case? */\n                           ? \"0x%\" LUA_INTEGER_FRMLEN \"x\"  /* use hexa */\n                           : LUA_INTEGER_FMT;  /* else use default format */\n        nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);\n      }\n      luaL_addsize(b, nb);\n      break;\n    }\n    case LUA_TNIL: case LUA_TBOOLEAN: {\n      luaL_tolstring(L, arg, NULL);\n      luaL_addvalue(b);\n      break;\n    }\n    default: {\n      luaL_argerror(L, arg, \"value has no literal form\");\n    }\n  }\n}\n\n\nstatic const char *scanformat (lua_State *L, const char *strfrmt, char *form) {\n  const char *p = strfrmt;\n  while (*p != '\\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */\n  if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))\n    luaL_error(L, \"invalid format (repeated flags)\");\n  if (isdigit(uchar(*p))) p++;  /* skip width */\n  if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */\n  if (*p == '.') {\n    p++;\n    if (isdigit(uchar(*p))) p++;  /* skip precision */\n    if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */\n  }\n  if (isdigit(uchar(*p)))\n    luaL_error(L, \"invalid format (width or precision too long)\");\n  *(form++) = '%';\n  memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));\n  form += (p - strfrmt) + 1;\n  *form = '\\0';\n  return p;\n}\n\n\n/*\n** add length modifier into formats\n*/\nstatic void addlenmod (char *form, const char *lenmod) {\n  size_t l = strlen(form);\n  size_t lm = strlen(lenmod);\n  char spec = form[l - 1];\n  strcpy(form + l - 1, lenmod);\n  form[l + lm - 1] = spec;\n  form[l + lm] = '\\0';\n}\n\n\nstatic int str_format (lua_State *L) {\n  int top = lua_gettop(L);\n  int arg = 1;\n  size_t sfl;\n  const char *strfrmt = luaL_checklstring(L, arg, &sfl);\n  const char *strfrmt_end = strfrmt+sfl;\n  luaL_Buffer b;\n  luaL_buffinit(L, &b);\n  while (strfrmt < strfrmt_end) {\n    if (*strfrmt != L_ESC)\n      luaL_addchar(&b, *strfrmt++);\n    else if (*++strfrmt == L_ESC)\n      luaL_addchar(&b, *strfrmt++);  /* %% */\n    else { /* format item */\n      char form[MAX_FORMAT];  /* to store the format ('%...') */\n      char *buff = luaL_prepbuffsize(&b, MAX_ITEM);  /* to put formatted item */\n      int nb = 0;  /* number of bytes in added item */\n      if (++arg > top)\n        luaL_argerror(L, arg, \"no value\");\n      strfrmt = scanformat(L, strfrmt, form);\n      switch (*strfrmt++) {\n        case 'c': {\n          nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));\n          break;\n        }\n        case 'd': case 'i':\n        case 'o': case 'u': case 'x': case 'X': {\n          lua_Integer n = luaL_checkinteger(L, arg);\n          addlenmod(form, LUA_INTEGER_FRMLEN);\n          nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);\n          break;\n        }\n        case 'a': case 'A':\n          addlenmod(form, LUA_NUMBER_FRMLEN);\n          nb = lua_number2strx(L, buff, MAX_ITEM, form,\n                                  luaL_checknumber(L, arg));\n          break;\n        case 'e': case 'E': case 'f':\n        case 'g': case 'G': {\n          lua_Number n = luaL_checknumber(L, arg);\n          addlenmod(form, LUA_NUMBER_FRMLEN);\n          nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);\n          break;\n        }\n        case 'q': {\n          addliteral(L, &b, arg);\n          break;\n        }\n        case 's': {\n          size_t l;\n          const char *s = luaL_tolstring(L, arg, &l);\n          if (form[2] == '\\0')  /* no modifiers? */\n            luaL_addvalue(&b);  /* keep entire string */\n          else {\n            luaL_argcheck(L, l == strlen(s), arg, \"string contains zeros\");\n            if (!strchr(form, '.') && l >= 100) {\n              /* no precision and string is too long to be formatted */\n              luaL_addvalue(&b);  /* keep entire string */\n            }\n            else {  /* format the string into 'buff' */\n              nb = l_sprintf(buff, MAX_ITEM, form, s);\n              lua_pop(L, 1);  /* remove result from 'luaL_tolstring' */\n            }\n          }\n          break;\n        }\n        default: {  /* also treat cases 'pnLlh' */\n          return luaL_error(L, \"invalid option '%%%c' to 'format'\",\n                               *(strfrmt - 1));\n        }\n      }\n      lua_assert(nb < MAX_ITEM);\n      luaL_addsize(&b, nb);\n    }\n  }\n  luaL_pushresult(&b);\n  return 1;\n}\n\n/* }====================================================== */\n\n\n/*\n** {======================================================\n** PACK/UNPACK\n** =======================================================\n*/\n\n\n/* value used for padding */\n#if !defined(LUAL_PACKPADBYTE)\n#define LUAL_PACKPADBYTE\t\t0x00\n#endif\n\n/* maximum size for the binary representation of an integer */\n#define MAXINTSIZE\t16\n\n/* number of bits in a character */\n#define NB\tCHAR_BIT\n\n/* mask for one character (NB 1's) */\n#define MC\t((1 << NB) - 1)\n\n/* size of a lua_Integer */\n#define SZINT\t((int)sizeof(lua_Integer))\n\n\n/* dummy union to get native endianness */\nstatic const union {\n  int dummy;\n  char little;  /* true iff machine is little endian */\n} nativeendian = {1};\n\n\n/* dummy structure to get native alignment requirements */\nstruct cD {\n  char c;\n  union { double d; void *p; lua_Integer i; lua_Number n; } u;\n};\n\n#define MAXALIGN\t(offsetof(struct cD, u))\n\n\n/*\n** Union for serializing floats\n*/\ntypedef union Ftypes {\n  float f;\n  double d;\n  lua_Number n;\n  char buff[5 * sizeof(lua_Number)];  /* enough for any float type */\n} Ftypes;\n\n\n/*\n** information to pack/unpack stuff\n*/\ntypedef struct Header {\n  lua_State *L;\n  int islittle;\n  int maxalign;\n} Header;\n\n\n/*\n** options for pack/unpack\n*/\ntypedef enum KOption {\n  Kint,\t\t/* signed integers */\n  Kuint,\t/* unsigned integers */\n  Kfloat,\t/* floating-point numbers */\n  Kchar,\t/* fixed-length strings */\n  Kstring,\t/* strings with prefixed length */\n  Kzstr,\t/* zero-terminated strings */\n  Kpadding,\t/* padding */\n  Kpaddalign,\t/* padding for alignment */\n  Knop\t\t/* no-op (configuration or spaces) */\n} KOption;\n\n\n/*\n** Read an integer numeral from string 'fmt' or return 'df' if\n** there is no numeral\n*/\nstatic int digit (int c) { return '0' <= c && c <= '9'; }\n\nstatic int getnum (const char **fmt, int df) {\n  if (!digit(**fmt))  /* no number? */\n    return df;  /* return default value */\n  else {\n    int a = 0;\n    do {\n      a = a*10 + (*((*fmt)++) - '0');\n    } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);\n    return a;\n  }\n}\n\n\n/*\n** Read an integer numeral and raises an error if it is larger\n** than the maximum size for integers.\n*/\nstatic int getnumlimit (Header *h, const char **fmt, int df) {\n  int sz = getnum(fmt, df);\n  if (sz > MAXINTSIZE || sz <= 0)\n    return luaL_error(h->L, \"integral size (%d) out of limits [1,%d]\",\n                            sz, MAXINTSIZE);\n  return sz;\n}\n\n\n/*\n** Initialize Header\n*/\nstatic void initheader (lua_State *L, Header *h) {\n  h->L = L;\n  h->islittle = nativeendian.little;\n  h->maxalign = 1;\n}\n\n\n/*\n** Read and classify next option. 'size' is filled with option's size.\n*/\nstatic KOption getoption (Header *h, const char **fmt, int *size) {\n  int opt = *((*fmt)++);\n  *size = 0;  /* default */\n  switch (opt) {\n    case 'b': *size = sizeof(char); return Kint;\n    case 'B': *size = sizeof(char); return Kuint;\n    case 'h': *size = sizeof(short); return Kint;\n    case 'H': *size = sizeof(short); return Kuint;\n    case 'l': *size = sizeof(long); return Kint;\n    case 'L': *size = sizeof(long); return Kuint;\n    case 'j': *size = sizeof(lua_Integer); return Kint;\n    case 'J': *size = sizeof(lua_Integer); return Kuint;\n    case 'T': *size = sizeof(size_t); return Kuint;\n    case 'f': *size = sizeof(float); return Kfloat;\n    case 'd': *size = sizeof(double); return Kfloat;\n    case 'n': *size = sizeof(lua_Number); return Kfloat;\n    case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;\n    case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;\n    case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;\n    case 'c':\n      *size = getnum(fmt, -1);\n      if (*size == -1)\n        luaL_error(h->L, \"missing size for format option 'c'\");\n      return Kchar;\n    case 'z': return Kzstr;\n    case 'x': *size = 1; return Kpadding;\n    case 'X': return Kpaddalign;\n    case ' ': break;\n    case '<': h->islittle = 1; break;\n    case '>': h->islittle = 0; break;\n    case '=': h->islittle = nativeendian.little; break;\n    case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;\n    default: luaL_error(h->L, \"invalid format option '%c'\", opt);\n  }\n  return Knop;\n}\n\n\n/*\n** Read, classify, and fill other details about the next option.\n** 'psize' is filled with option's size, 'notoalign' with its\n** alignment requirements.\n** Local variable 'size' gets the size to be aligned. (Kpadal option\n** always gets its full alignment, other options are limited by\n** the maximum alignment ('maxalign'). Kchar option needs no alignment\n** despite its size.\n*/\nstatic KOption getdetails (Header *h, size_t totalsize,\n                           const char **fmt, int *psize, int *ntoalign) {\n  KOption opt = getoption(h, fmt, psize);\n  int align = *psize;  /* usually, alignment follows size */\n  if (opt == Kpaddalign) {  /* 'X' gets alignment from following option */\n    if (**fmt == '\\0' || getoption(h, fmt, &align) == Kchar || align == 0)\n      luaL_argerror(h->L, 1, \"invalid next option for option 'X'\");\n  }\n  if (align <= 1 || opt == Kchar)  /* need no alignment? */\n    *ntoalign = 0;\n  else {\n    if (align > h->maxalign)  /* enforce maximum alignment */\n      align = h->maxalign;\n    if ((align & (align - 1)) != 0)  /* is 'align' not a power of 2? */\n      luaL_argerror(h->L, 1, \"format asks for alignment not power of 2\");\n    *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);\n  }\n  return opt;\n}\n\n\n/*\n** Pack integer 'n' with 'size' bytes and 'islittle' endianness.\n** The final 'if' handles the case when 'size' is larger than\n** the size of a Lua integer, correcting the extra sign-extension\n** bytes if necessary (by default they would be zeros).\n*/\nstatic void packint (luaL_Buffer *b, lua_Unsigned n,\n                     int islittle, int size, int neg) {\n  char *buff = luaL_prepbuffsize(b, size);\n  int i;\n  buff[islittle ? 0 : size - 1] = (char)(n & MC);  /* first byte */\n  for (i = 1; i < size; i++) {\n    n >>= NB;\n    buff[islittle ? i : size - 1 - i] = (char)(n & MC);\n  }\n  if (neg && size > SZINT) {  /* negative number need sign extension? */\n    for (i = SZINT; i < size; i++)  /* correct extra bytes */\n      buff[islittle ? i : size - 1 - i] = (char)MC;\n  }\n  luaL_addsize(b, size);  /* add result to buffer */\n}\n\n\n/*\n** Copy 'size' bytes from 'src' to 'dest', correcting endianness if\n** given 'islittle' is different from native endianness.\n*/\nstatic void copywithendian (volatile char *dest, volatile const char *src,\n                            int size, int islittle) {\n  if (islittle == nativeendian.little) {\n    while (size-- != 0)\n      *(dest++) = *(src++);\n  }\n  else {\n    dest += size - 1;\n    while (size-- != 0)\n      *(dest--) = *(src++);\n  }\n}\n\n\nstatic int str_pack (lua_State *L) {\n  luaL_Buffer b;\n  Header h;\n  const char *fmt = luaL_checkstring(L, 1);  /* format string */\n  int arg = 1;  /* current argument to pack */\n  size_t totalsize = 0;  /* accumulate total size of result */\n  initheader(L, &h);\n  lua_pushnil(L);  /* mark to separate arguments from string buffer */\n  luaL_buffinit(L, &b);\n  while (*fmt != '\\0') {\n    int size, ntoalign;\n    KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);\n    totalsize += ntoalign + size;\n    while (ntoalign-- > 0)\n     luaL_addchar(&b, LUAL_PACKPADBYTE);  /* fill alignment */\n    arg++;\n    switch (opt) {\n      case Kint: {  /* signed integers */\n        lua_Integer n = luaL_checkinteger(L, arg);\n        if (size < SZINT) {  /* need overflow check? */\n          lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);\n          luaL_argcheck(L, -lim <= n && n < lim, arg, \"integer overflow\");\n        }\n        packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));\n        break;\n      }\n      case Kuint: {  /* unsigned integers */\n        lua_Integer n = luaL_checkinteger(L, arg);\n        if (size < SZINT)  /* need overflow check? */\n          luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),\n                           arg, \"unsigned overflow\");\n        packint(&b, (lua_Unsigned)n, h.islittle, size, 0);\n        break;\n      }\n      case Kfloat: {  /* floating-point options */\n        volatile Ftypes u;\n        char *buff = luaL_prepbuffsize(&b, size);\n        lua_Number n = luaL_checknumber(L, arg);  /* get argument */\n        if (size == sizeof(u.f)) u.f = (float)n;  /* copy it into 'u' */\n        else if (size == sizeof(u.d)) u.d = (double)n;\n        else u.n = n;\n        /* move 'u' to final result, correcting endianness if needed */\n        copywithendian(buff, u.buff, size, h.islittle);\n        luaL_addsize(&b, size);\n        break;\n      }\n      case Kchar: {  /* fixed-size string */\n        size_t len;\n        const char *s = luaL_checklstring(L, arg, &len);\n        luaL_argcheck(L, len <= (size_t)size, arg,\n                         \"string longer than given size\");\n        luaL_addlstring(&b, s, len);  /* add string */\n        while (len++ < (size_t)size)  /* pad extra space */\n          luaL_addchar(&b, LUAL_PACKPADBYTE);\n        break;\n      }\n      case Kstring: {  /* strings with length count */\n        size_t len;\n        const char *s = luaL_checklstring(L, arg, &len);\n        luaL_argcheck(L, size >= (int)sizeof(size_t) ||\n                         len < ((size_t)1 << (size * NB)),\n                         arg, \"string length does not fit in given size\");\n        packint(&b, (lua_Unsigned)len, h.islittle, size, 0);  /* pack length */\n        luaL_addlstring(&b, s, len);\n        totalsize += len;\n        break;\n      }\n      case Kzstr: {  /* zero-terminated string */\n        size_t len;\n        const char *s = luaL_checklstring(L, arg, &len);\n        luaL_argcheck(L, strlen(s) == len, arg, \"string contains zeros\");\n        luaL_addlstring(&b, s, len);\n        luaL_addchar(&b, '\\0');  /* add zero at the end */\n        totalsize += len + 1;\n        break;\n      }\n      case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE);  /* FALLTHROUGH */\n      case Kpaddalign: case Knop:\n        arg--;  /* undo increment */\n        break;\n    }\n  }\n  luaL_pushresult(&b);\n  return 1;\n}\n\n\nstatic int str_packsize (lua_State *L) {\n  Header h;\n  const char *fmt = luaL_checkstring(L, 1);  /* format string */\n  size_t totalsize = 0;  /* accumulate total size of result */\n  initheader(L, &h);\n  while (*fmt != '\\0') {\n    int size, ntoalign;\n    KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);\n    size += ntoalign;  /* total space used by option */\n    luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,\n                     \"format result too large\");\n    totalsize += size;\n    switch (opt) {\n      case Kstring:  /* strings with length count */\n      case Kzstr:    /* zero-terminated string */\n        luaL_argerror(L, 1, \"variable-length format\");\n        /* call never return, but to avoid warnings: *//* FALLTHROUGH */\n      default:  break;\n    }\n  }\n  lua_pushinteger(L, (lua_Integer)totalsize);\n  return 1;\n}\n\n\n/*\n** Unpack an integer with 'size' bytes and 'islittle' endianness.\n** If size is smaller than the size of a Lua integer and integer\n** is signed, must do sign extension (propagating the sign to the\n** higher bits); if size is larger than the size of a Lua integer,\n** it must check the unread bytes to see whether they do not cause an\n** overflow.\n*/\nstatic lua_Integer unpackint (lua_State *L, const char *str,\n                              int islittle, int size, int issigned) {\n  lua_Unsigned res = 0;\n  int i;\n  int limit = (size  <= SZINT) ? size : SZINT;\n  for (i = limit - 1; i >= 0; i--) {\n    res <<= NB;\n    res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i];\n  }\n  if (size < SZINT) {  /* real size smaller than lua_Integer? */\n    if (issigned) {  /* needs sign extension? */\n      lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1);\n      res = ((res ^ mask) - mask);  /* do sign extension */\n    }\n  }\n  else if (size > SZINT) {  /* must check unread bytes */\n    int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;\n    for (i = limit; i < size; i++) {\n      if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)\n        luaL_error(L, \"%d-byte integer does not fit into Lua Integer\", size);\n    }\n  }\n  return (lua_Integer)res;\n}\n\n\nstatic int str_unpack (lua_State *L) {\n  Header h;\n  const char *fmt = luaL_checkstring(L, 1);\n  size_t ld;\n  const char *data = luaL_checklstring(L, 2, &ld);\n  size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1;\n  int n = 0;  /* number of results */\n  luaL_argcheck(L, pos <= ld, 3, \"initial position out of string\");\n  initheader(L, &h);\n  while (*fmt != '\\0') {\n    int size, ntoalign;\n    KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);\n    if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld)\n      luaL_argerror(L, 2, \"data string too short\");\n    pos += ntoalign;  /* skip alignment */\n    /* stack space for item + next position */\n    luaL_checkstack(L, 2, \"too many results\");\n    n++;\n    switch (opt) {\n      case Kint:\n      case Kuint: {\n        lua_Integer res = unpackint(L, data + pos, h.islittle, size,\n                                       (opt == Kint));\n        lua_pushinteger(L, res);\n        break;\n      }\n      case Kfloat: {\n        volatile Ftypes u;\n        lua_Number num;\n        copywithendian(u.buff, data + pos, size, h.islittle);\n        if (size == sizeof(u.f)) num = (lua_Number)u.f;\n        else if (size == sizeof(u.d)) num = (lua_Number)u.d;\n        else num = u.n;\n        lua_pushnumber(L, num);\n        break;\n      }\n      case Kchar: {\n        lua_pushlstring(L, data + pos, size);\n        break;\n      }\n      case Kstring: {\n        size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);\n        luaL_argcheck(L, pos + len + size <= ld, 2, \"data string too short\");\n        lua_pushlstring(L, data + pos + size, len);\n        pos += len;  /* skip string */\n        break;\n      }\n      case Kzstr: {\n        size_t len = (int)strlen(data + pos);\n        lua_pushlstring(L, data + pos, len);\n        pos += len + 1;  /* skip string plus final '\\0' */\n        break;\n      }\n      case Kpaddalign: case Kpadding: case Knop:\n        n--;  /* undo increment */\n        break;\n    }\n    pos += size;\n  }\n  lua_pushinteger(L, pos + 1);  /* next position */\n  return n + 1;\n}\n\n/* }====================================================== */\n\n\nstatic const luaL_Reg strlib[] = {\n  {\"byte\", str_byte},\n  {\"char\", str_char},\n  {\"dump\", str_dump},\n  {\"find\", str_find},\n  {\"format\", str_format},\n  {\"gmatch\", gmatch},\n  {\"gsub\", str_gsub},\n  {\"len\", str_len},\n  {\"lower\", str_lower},\n  {\"match\", str_match},\n  {\"rep\", str_rep},\n  {\"reverse\", str_reverse},\n  {\"sub\", str_sub},\n  {\"upper\", str_upper},\n  {\"pack\", str_pack},\n  {\"packsize\", str_packsize},\n  {\"unpack\", str_unpack},\n  {NULL, NULL}\n};\n\n\nstatic void createmetatable (lua_State *L) {\n  lua_createtable(L, 0, 1);  /* table to be metatable for strings */\n  lua_pushliteral(L, \"\");  /* dummy string */\n  lua_pushvalue(L, -2);  /* copy table */\n  lua_setmetatable(L, -2);  /* set table as metatable for strings */\n  lua_pop(L, 1);  /* pop dummy string */\n  lua_pushvalue(L, -2);  /* get string library */\n  lua_setfield(L, -2, \"__index\");  /* metatable.__index = string */\n  lua_pop(L, 1);  /* pop metatable */\n}\n\n\n/*\n** Open string library\n*/\nLUAMOD_API int luaopen_string (lua_State *L) {\n  luaL_newlib(L, strlib);\n  createmetatable(L);\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ltable.c",
    "content": "/*\n** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $\n** Lua tables (hash)\n** See Copyright Notice in lua.h\n*/\n\n#define ltable_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n/*\n** Implementation of tables (aka arrays, objects, or hash tables).\n** Tables keep its elements in two parts: an array part and a hash part.\n** Non-negative integer keys are all candidates to be kept in the array\n** part. The actual size of the array is the largest 'n' such that\n** more than half the slots between 1 and n are in use.\n** Hash uses a mix of chained scatter table with Brent's variation.\n** A main invariant of these tables is that, if an element is not\n** in its main position (i.e. the 'original' position that its hash gives\n** to it), then the colliding element is in its own main position.\n** Hence even when the load factor reaches 100%, performance remains good.\n*/\n\n#include <math.h>\n#include <limits.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lgc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"lvm.h\"\n\n\n/*\n** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is\n** the largest integer such that MAXASIZE fits in an unsigned int.\n*/\n#define MAXABITS\tcast_int(sizeof(int) * CHAR_BIT - 1)\n#define MAXASIZE\t(1u << MAXABITS)\n\n/*\n** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest\n** integer such that 2^MAXHBITS fits in a signed int. (Note that the\n** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still\n** fits comfortably in an unsigned int.)\n*/\n#define MAXHBITS\t(MAXABITS - 1)\n\n\n#define hashpow2(t,n)\t\t(gnode(t, lmod((n), sizenode(t))))\n\n#define hashstr(t,str)\t\thashpow2(t, (str)->hash)\n#define hashboolean(t,p)\thashpow2(t, p)\n#define hashint(t,i)\t\thashpow2(t, i)\n\n\n/*\n** for some types, it is better to avoid modulus by power of 2, as\n** they tend to have many 2 factors.\n*/\n#define hashmod(t,n)\t(gnode(t, ((n) % ((sizenode(t)-1)|1))))\n\n\n#define hashpointer(t,p)\thashmod(t, point2uint(p))\n\n\n#define dummynode\t\t(&dummynode_)\n\nstatic const Node dummynode_ = {\n  {NILCONSTANT},  /* value */\n  {{NILCONSTANT, 0}}  /* key */\n};\n\n\n/*\n** Hash for floating-point numbers.\n** The main computation should be just\n**     n = frexp(n, &i); return (n * INT_MAX) + i\n** but there are some numerical subtleties.\n** In a two-complement representation, INT_MAX does not has an exact\n** representation as a float, but INT_MIN does; because the absolute\n** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the\n** absolute value of the product 'frexp * -INT_MIN' is smaller or equal\n** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when\n** adding 'i'; the use of '~u' (instead of '-u') avoids problems with\n** INT_MIN.\n*/\n#if !defined(l_hashfloat)\nstatic int l_hashfloat (lua_Number n) {\n  int i;\n  lua_Integer ni;\n  n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);\n  if (!lua_numbertointeger(n, &ni)) {  /* is 'n' inf/-inf/NaN? */\n    lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));\n    return 0;\n  }\n  else {  /* normal case */\n    unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni);\n    return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u);\n  }\n}\n#endif\n\n\n/*\n** returns the 'main' position of an element in a table (that is, the index\n** of its hash value)\n*/\nstatic Node *mainposition (const Table *t, const TValue *key) {\n  switch (ttype(key)) {\n    case LUA_TNUMINT:\n      return hashint(t, ivalue(key));\n    case LUA_TNUMFLT:\n      return hashmod(t, l_hashfloat(fltvalue(key)));\n    case LUA_TSHRSTR:\n      return hashstr(t, tsvalue(key));\n    case LUA_TLNGSTR:\n      return hashpow2(t, luaS_hashlongstr(tsvalue(key)));\n    case LUA_TBOOLEAN:\n      return hashboolean(t, bvalue(key));\n    case LUA_TLIGHTUSERDATA:\n      return hashpointer(t, pvalue(key));\n    case LUA_TLCF:\n      return hashpointer(t, fvalue(key));\n    default:\n      lua_assert(!ttisdeadkey(key));\n      return hashpointer(t, gcvalue(key));\n  }\n}\n\n\n/*\n** returns the index for 'key' if 'key' is an appropriate key to live in\n** the array part of the table, 0 otherwise.\n*/\nstatic unsigned int arrayindex (const TValue *key) {\n  if (ttisinteger(key)) {\n    lua_Integer k = ivalue(key);\n    if (0 < k && (lua_Unsigned)k <= MAXASIZE)\n      return cast(unsigned int, k);  /* 'key' is an appropriate array index */\n  }\n  return 0;  /* 'key' did not match some condition */\n}\n\n\n/*\n** returns the index of a 'key' for table traversals. First goes all\n** elements in the array part, then elements in the hash part. The\n** beginning of a traversal is signaled by 0.\n*/\nstatic unsigned int findindex (lua_State *L, Table *t, StkId key) {\n  unsigned int i;\n  if (ttisnil(key)) return 0;  /* first iteration */\n  i = arrayindex(key);\n  if (i != 0 && i <= t->sizearray)  /* is 'key' inside array part? */\n    return i;  /* yes; that's the index */\n  else {\n    int nx;\n    Node *n = mainposition(t, key);\n    for (;;) {  /* check whether 'key' is somewhere in the chain */\n      /* key may be dead already, but it is ok to use it in 'next' */\n      if (luaV_rawequalobj(gkey(n), key) ||\n            (ttisdeadkey(gkey(n)) && iscollectable(key) &&\n             deadvalue(gkey(n)) == gcvalue(key))) {\n        i = cast_int(n - gnode(t, 0));  /* key index in hash table */\n        /* hash elements are numbered after array ones */\n        return (i + 1) + t->sizearray;\n      }\n      nx = gnext(n);\n      if (nx == 0)\n        luaG_runerror(L, \"invalid key to 'next'\");  /* key not found */\n      else n += nx;\n    }\n  }\n}\n\n\nint luaH_next (lua_State *L, Table *t, StkId key) {\n  unsigned int i = findindex(L, t, key);  /* find original element */\n  for (; i < t->sizearray; i++) {  /* try first array part */\n    if (!ttisnil(&t->array[i])) {  /* a non-nil value? */\n      setivalue(key, i + 1);\n      setobj2s(L, key+1, &t->array[i]);\n      return 1;\n    }\n  }\n  for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) {  /* hash part */\n    if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */\n      setobj2s(L, key, gkey(gnode(t, i)));\n      setobj2s(L, key+1, gval(gnode(t, i)));\n      return 1;\n    }\n  }\n  return 0;  /* no more elements */\n}\n\n\n/*\n** {=============================================================\n** Rehash\n** ==============================================================\n*/\n\n/*\n** Compute the optimal size for the array part of table 't'. 'nums' is a\n** \"count array\" where 'nums[i]' is the number of integers in the table\n** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of\n** integer keys in the table and leaves with the number of keys that\n** will go to the array part; return the optimal size.\n*/\nstatic unsigned int computesizes (unsigned int nums[], unsigned int *pna) {\n  int i;\n  unsigned int twotoi;  /* 2^i (candidate for optimal size) */\n  unsigned int a = 0;  /* number of elements smaller than 2^i */\n  unsigned int na = 0;  /* number of elements to go to array part */\n  unsigned int optimal = 0;  /* optimal size for array part */\n  /* loop while keys can fill more than half of total size */\n  for (i = 0, twotoi = 1;\n       twotoi > 0 && *pna > twotoi / 2;\n       i++, twotoi *= 2) {\n    if (nums[i] > 0) {\n      a += nums[i];\n      if (a > twotoi/2) {  /* more than half elements present? */\n        optimal = twotoi;  /* optimal size (till now) */\n        na = a;  /* all elements up to 'optimal' will go to array part */\n      }\n    }\n  }\n  lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);\n  *pna = na;\n  return optimal;\n}\n\n\nstatic int countint (const TValue *key, unsigned int *nums) {\n  unsigned int k = arrayindex(key);\n  if (k != 0) {  /* is 'key' an appropriate array index? */\n    nums[luaO_ceillog2(k)]++;  /* count as such */\n    return 1;\n  }\n  else\n    return 0;\n}\n\n\n/*\n** Count keys in array part of table 't': Fill 'nums[i]' with\n** number of keys that will go into corresponding slice and return\n** total number of non-nil keys.\n*/\nstatic unsigned int numusearray (const Table *t, unsigned int *nums) {\n  int lg;\n  unsigned int ttlg;  /* 2^lg */\n  unsigned int ause = 0;  /* summation of 'nums' */\n  unsigned int i = 1;  /* count to traverse all array keys */\n  /* traverse each slice */\n  for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) {\n    unsigned int lc = 0;  /* counter */\n    unsigned int lim = ttlg;\n    if (lim > t->sizearray) {\n      lim = t->sizearray;  /* adjust upper limit */\n      if (i > lim)\n        break;  /* no more elements to count */\n    }\n    /* count elements in range (2^(lg - 1), 2^lg] */\n    for (; i <= lim; i++) {\n      if (!ttisnil(&t->array[i-1]))\n        lc++;\n    }\n    nums[lg] += lc;\n    ause += lc;\n  }\n  return ause;\n}\n\n\nstatic int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {\n  int totaluse = 0;  /* total number of elements */\n  int ause = 0;  /* elements added to 'nums' (can go to array part) */\n  int i = sizenode(t);\n  while (i--) {\n    Node *n = &t->node[i];\n    if (!ttisnil(gval(n))) {\n      ause += countint(gkey(n), nums);\n      totaluse++;\n    }\n  }\n  *pna += ause;\n  return totaluse;\n}\n\n\nstatic void setarrayvector (lua_State *L, Table *t, unsigned int size) {\n  unsigned int i;\n  luaM_reallocvector(L, t->array, t->sizearray, size, TValue);\n  for (i=t->sizearray; i<size; i++)\n     setnilvalue(&t->array[i]);\n  t->sizearray = size;\n}\n\n\nstatic void setnodevector (lua_State *L, Table *t, unsigned int size) {\n  if (size == 0) {  /* no elements to hash part? */\n    t->node = cast(Node *, dummynode);  /* use common 'dummynode' */\n    t->lsizenode = 0;\n    t->lastfree = NULL;  /* signal that it is using dummy node */\n  }\n  else {\n    int i;\n    int lsize = luaO_ceillog2(size);\n    if (lsize > MAXHBITS)\n      luaG_runerror(L, \"table overflow\");\n    size = twoto(lsize);\n    t->node = luaM_newvector(L, size, Node);\n    for (i = 0; i < (int)size; i++) {\n      Node *n = gnode(t, i);\n      gnext(n) = 0;\n      setnilvalue(wgkey(n));\n      setnilvalue(gval(n));\n    }\n    t->lsizenode = cast_byte(lsize);\n    t->lastfree = gnode(t, size);  /* all positions are free */\n  }\n}\n\n\ntypedef struct {\n  Table *t;\n  unsigned int nhsize;\n} AuxsetnodeT;\n\n\nstatic void auxsetnode (lua_State *L, void *ud) {\n  AuxsetnodeT *asn = cast(AuxsetnodeT *, ud);\n  setnodevector(L, asn->t, asn->nhsize);\n}\n\n\nvoid luaH_resize (lua_State *L, Table *t, unsigned int nasize,\n                                          unsigned int nhsize) {\n  unsigned int i;\n  int j;\n  AuxsetnodeT asn;\n  unsigned int oldasize = t->sizearray;\n  int oldhsize = allocsizenode(t);\n  Node *nold = t->node;  /* save old hash ... */\n  if (nasize > oldasize)  /* array part must grow? */\n    setarrayvector(L, t, nasize);\n  /* create new hash part with appropriate size */\n  asn.t = t; asn.nhsize = nhsize;\n  if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) {  /* mem. error? */\n    setarrayvector(L, t, oldasize);  /* array back to its original size */\n    luaD_throw(L, LUA_ERRMEM);  /* rethrow memory error */\n  }\n  if (nasize < oldasize) {  /* array part must shrink? */\n    t->sizearray = nasize;\n    /* re-insert elements from vanishing slice */\n    for (i=nasize; i<oldasize; i++) {\n      if (!ttisnil(&t->array[i]))\n        luaH_setint(L, t, i + 1, &t->array[i]);\n    }\n    /* shrink array */\n    luaM_reallocvector(L, t->array, oldasize, nasize, TValue);\n  }\n  /* re-insert elements from hash part */\n  for (j = oldhsize - 1; j >= 0; j--) {\n    Node *old = nold + j;\n    if (!ttisnil(gval(old))) {\n      /* doesn't need barrier/invalidate cache, as entry was\n         already present in the table */\n      setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));\n    }\n  }\n  if (oldhsize > 0)  /* not the dummy node? */\n    luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */\n}\n\n\nvoid luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {\n  int nsize = allocsizenode(t);\n  luaH_resize(L, t, nasize, nsize);\n}\n\n/*\n** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i\n*/\nstatic void rehash (lua_State *L, Table *t, const TValue *ek) {\n  unsigned int asize;  /* optimal size for array part */\n  unsigned int na;  /* number of keys in the array part */\n  unsigned int nums[MAXABITS + 1];\n  int i;\n  int totaluse;\n  for (i = 0; i <= MAXABITS; i++) nums[i] = 0;  /* reset counts */\n  na = numusearray(t, nums);  /* count keys in array part */\n  totaluse = na;  /* all those keys are integer keys */\n  totaluse += numusehash(t, nums, &na);  /* count keys in hash part */\n  /* count extra key */\n  na += countint(ek, nums);\n  totaluse++;\n  /* compute new size for array part */\n  asize = computesizes(nums, &na);\n  /* resize the table to new computed sizes */\n  luaH_resize(L, t, asize, totaluse - na);\n}\n\n\n\n/*\n** }=============================================================\n*/\n\n\nTable *luaH_new (lua_State *L) {\n  GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table));\n  Table *t = gco2t(o);\n  t->metatable = NULL;\n  t->flags = cast_byte(~0);\n  t->array = NULL;\n  t->sizearray = 0;\n  setnodevector(L, t, 0);\n  return t;\n}\n\n\nvoid luaH_free (lua_State *L, Table *t) {\n  if (!isdummy(t))\n    luaM_freearray(L, t->node, cast(size_t, sizenode(t)));\n  luaM_freearray(L, t->array, t->sizearray);\n  luaM_free(L, t);\n}\n\n\nstatic Node *getfreepos (Table *t) {\n  if (!isdummy(t)) {\n    while (t->lastfree > t->node) {\n      t->lastfree--;\n      if (ttisnil(gkey(t->lastfree)))\n        return t->lastfree;\n    }\n  }\n  return NULL;  /* could not find a free place */\n}\n\n\n\n/*\n** inserts a new key into a hash table; first, check whether key's main\n** position is free. If not, check whether colliding node is in its main\n** position or not: if it is not, move colliding node to an empty place and\n** put new key in its main position; otherwise (colliding node is in its main\n** position), new key goes to an empty position.\n*/\nTValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {\n  Node *mp;\n  TValue aux;\n  if (ttisnil(key)) luaG_runerror(L, \"table index is nil\");\n  else if (ttisfloat(key)) {\n    lua_Integer k;\n    if (luaV_tointeger(key, &k, 0)) {  /* does index fit in an integer? */\n      setivalue(&aux, k);\n      key = &aux;  /* insert it as an integer */\n    }\n    else if (luai_numisnan(fltvalue(key)))\n      luaG_runerror(L, \"table index is NaN\");\n  }\n  mp = mainposition(t, key);\n  if (!ttisnil(gval(mp)) || isdummy(t)) {  /* main position is taken? */\n    Node *othern;\n    Node *f = getfreepos(t);  /* get a free place */\n    if (f == NULL) {  /* cannot find a free place? */\n      rehash(L, t, key);  /* grow table */\n      /* whatever called 'newkey' takes care of TM cache */\n      return luaH_set(L, t, key);  /* insert key into grown table */\n    }\n    lua_assert(!isdummy(t));\n    othern = mainposition(t, gkey(mp));\n    if (othern != mp) {  /* is colliding node out of its main position? */\n      /* yes; move colliding node into free position */\n      while (othern + gnext(othern) != mp)  /* find previous */\n        othern += gnext(othern);\n      gnext(othern) = cast_int(f - othern);  /* rechain to point to 'f' */\n      *f = *mp;  /* copy colliding node into free pos. (mp->next also goes) */\n      if (gnext(mp) != 0) {\n        gnext(f) += cast_int(mp - f);  /* correct 'next' */\n        gnext(mp) = 0;  /* now 'mp' is free */\n      }\n      setnilvalue(gval(mp));\n    }\n    else {  /* colliding node is in its own main position */\n      /* new node will go into free position */\n      if (gnext(mp) != 0)\n        gnext(f) = cast_int((mp + gnext(mp)) - f);  /* chain new position */\n      else lua_assert(gnext(f) == 0);\n      gnext(mp) = cast_int(f - mp);\n      mp = f;\n    }\n  }\n  setnodekey(L, &mp->i_key, key);\n  luaC_barrierback(L, t, key);\n  lua_assert(ttisnil(gval(mp)));\n  return gval(mp);\n}\n\n\n/*\n** search function for integers\n*/\nconst TValue *luaH_getint (Table *t, lua_Integer key) {\n  /* (1 <= key && key <= t->sizearray) */\n  if (l_castS2U(key) - 1 < t->sizearray)\n    return &t->array[key - 1];\n  else {\n    Node *n = hashint(t, key);\n    for (;;) {  /* check whether 'key' is somewhere in the chain */\n      if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)\n        return gval(n);  /* that's it */\n      else {\n        int nx = gnext(n);\n        if (nx == 0) break;\n        n += nx;\n      }\n    }\n    return luaO_nilobject;\n  }\n}\n\n\n/*\n** search function for short strings\n*/\nconst TValue *luaH_getshortstr (Table *t, TString *key) {\n  Node *n = hashstr(t, key);\n  lua_assert(key->tt == LUA_TSHRSTR);\n  for (;;) {  /* check whether 'key' is somewhere in the chain */\n    const TValue *k = gkey(n);\n    if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))\n      return gval(n);  /* that's it */\n    else {\n      int nx = gnext(n);\n      if (nx == 0)\n        return luaO_nilobject;  /* not found */\n      n += nx;\n    }\n  }\n}\n\n\n/*\n** \"Generic\" get version. (Not that generic: not valid for integers,\n** which may be in array part, nor for floats with integral values.)\n*/\nstatic const TValue *getgeneric (Table *t, const TValue *key) {\n  Node *n = mainposition(t, key);\n  for (;;) {  /* check whether 'key' is somewhere in the chain */\n    if (luaV_rawequalobj(gkey(n), key))\n      return gval(n);  /* that's it */\n    else {\n      int nx = gnext(n);\n      if (nx == 0)\n        return luaO_nilobject;  /* not found */\n      n += nx;\n    }\n  }\n}\n\n\nconst TValue *luaH_getstr (Table *t, TString *key) {\n  if (key->tt == LUA_TSHRSTR)\n    return luaH_getshortstr(t, key);\n  else {  /* for long strings, use generic case */\n    TValue ko;\n    setsvalue(cast(lua_State *, NULL), &ko, key);\n    return getgeneric(t, &ko);\n  }\n}\n\n\n/*\n** main search function\n*/\nconst TValue *luaH_get (Table *t, const TValue *key) {\n  switch (ttype(key)) {\n    case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));\n    case LUA_TNUMINT: return luaH_getint(t, ivalue(key));\n    case LUA_TNIL: return luaO_nilobject;\n    case LUA_TNUMFLT: {\n      lua_Integer k;\n      if (luaV_tointeger(key, &k, 0)) /* index is int? */\n        return luaH_getint(t, k);  /* use specialized version */\n      /* else... */\n    }  /* FALLTHROUGH */\n    default:\n      return getgeneric(t, key);\n  }\n}\n\n\n/*\n** beware: when using this function you probably need to check a GC\n** barrier and invalidate the TM cache.\n*/\nTValue *luaH_set (lua_State *L, Table *t, const TValue *key) {\n  const TValue *p = luaH_get(t, key);\n  if (p != luaO_nilobject)\n    return cast(TValue *, p);\n  else return luaH_newkey(L, t, key);\n}\n\n\nvoid luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {\n  const TValue *p = luaH_getint(t, key);\n  TValue *cell;\n  if (p != luaO_nilobject)\n    cell = cast(TValue *, p);\n  else {\n    TValue k;\n    setivalue(&k, key);\n    cell = luaH_newkey(L, t, &k);\n  }\n  setobj2t(L, cell, value);\n}\n\n\nstatic lua_Unsigned unbound_search (Table *t, lua_Unsigned j) {\n  lua_Unsigned i = j;  /* i is zero or a present index */\n  j++;\n  /* find 'i' and 'j' such that i is present and j is not */\n  while (!ttisnil(luaH_getint(t, j))) {\n    i = j;\n    if (j > l_castS2U(LUA_MAXINTEGER) / 2) {  /* overflow? */\n      /* table was built with bad purposes: resort to linear search */\n      i = 1;\n      while (!ttisnil(luaH_getint(t, i))) i++;\n      return i - 1;\n    }\n    j *= 2;\n  }\n  /* now do a binary search between them */\n  while (j - i > 1) {\n    lua_Unsigned m = (i+j)/2;\n    if (ttisnil(luaH_getint(t, m))) j = m;\n    else i = m;\n  }\n  return i;\n}\n\n\n/*\n** Try to find a boundary in table 't'. A 'boundary' is an integer index\n** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).\n*/\nlua_Unsigned luaH_getn (Table *t) {\n  unsigned int j = t->sizearray;\n  if (j > 0 && ttisnil(&t->array[j - 1])) {\n    /* there is a boundary in the array part: (binary) search for it */\n    unsigned int i = 0;\n    while (j - i > 1) {\n      unsigned int m = (i+j)/2;\n      if (ttisnil(&t->array[m - 1])) j = m;\n      else i = m;\n    }\n    return i;\n  }\n  /* else must find a boundary in hash part */\n  else if (isdummy(t))  /* hash part is empty? */\n    return j;  /* that is easy... */\n  else return unbound_search(t, j);\n}\n\n\n\n#if defined(LUA_DEBUG)\n\nNode *luaH_mainposition (const Table *t, const TValue *key) {\n  return mainposition(t, key);\n}\n\nint luaH_isdummy (const Table *t) { return isdummy(t); }\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ltable.h",
    "content": "/*\n** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $\n** Lua tables (hash)\n** See Copyright Notice in lua.h\n*/\n\n#ifndef ltable_h\n#define ltable_h\n\n#include \"lobject.h\"\n\n\n#define gnode(t,i)\t(&(t)->node[i])\n#define gval(n)\t\t(&(n)->i_val)\n#define gnext(n)\t((n)->i_key.nk.next)\n\n\n/* 'const' to avoid wrong writings that can mess up field 'next' */\n#define gkey(n)\t\tcast(const TValue*, (&(n)->i_key.tvk))\n\n/*\n** writable version of 'gkey'; allows updates to individual fields,\n** but not to the whole (which has incompatible type)\n*/\n#define wgkey(n)\t\t(&(n)->i_key.nk)\n\n#define invalidateTMcache(t)\t((t)->flags = 0)\n\n\n/* true when 't' is using 'dummynode' as its hash part */\n#define isdummy(t)\t\t((t)->lastfree == NULL)\n\n\n/* allocated size for hash nodes */\n#define allocsizenode(t)\t(isdummy(t) ? 0 : sizenode(t))\n\n\n/* returns the key, given the value of a table entry */\n#define keyfromval(v) \\\n  (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))\n\n\nLUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);\nLUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,\n                                                    TValue *value);\nLUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);\nLUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);\nLUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);\nLUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);\nLUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);\nLUAI_FUNC Table *luaH_new (lua_State *L);\nLUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,\n                                                    unsigned int nhsize);\nLUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);\nLUAI_FUNC void luaH_free (lua_State *L, Table *t);\nLUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);\nLUAI_FUNC lua_Unsigned luaH_getn (Table *t);\n\n\n#if defined(LUA_DEBUG)\nLUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);\nLUAI_FUNC int luaH_isdummy (const Table *t);\n#endif\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ltablib.c",
    "content": "/*\n** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $\n** Library for Table Manipulation\n** See Copyright Notice in lua.h\n*/\n\n#define ltablib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <limits.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n\n/*\n** Operations that an object must define to mimic a table\n** (some functions only need some of them)\n*/\n#define TAB_R\t1\t\t\t/* read */\n#define TAB_W\t2\t\t\t/* write */\n#define TAB_L\t4\t\t\t/* length */\n#define TAB_RW\t(TAB_R | TAB_W)\t\t/* read/write */\n\n\n#define aux_getn(L,n,w)\t(checktab(L, n, (w) | TAB_L), luaL_len(L, n))\n\n\nstatic int checkfield (lua_State *L, const char *key, int n) {\n  lua_pushstring(L, key);\n  return (lua_rawget(L, -n) != LUA_TNIL);\n}\n\n\n/*\n** Check that 'arg' either is a table or can behave like one (that is,\n** has a metatable with the required metamethods)\n*/\nstatic void checktab (lua_State *L, int arg, int what) {\n  if (lua_type(L, arg) != LUA_TTABLE) {  /* is it not a table? */\n    int n = 1;  /* number of elements to pop */\n    if (lua_getmetatable(L, arg) &&  /* must have metatable */\n        (!(what & TAB_R) || checkfield(L, \"__index\", ++n)) &&\n        (!(what & TAB_W) || checkfield(L, \"__newindex\", ++n)) &&\n        (!(what & TAB_L) || checkfield(L, \"__len\", ++n))) {\n      lua_pop(L, n);  /* pop metatable and tested metamethods */\n    }\n    else\n      luaL_checktype(L, arg, LUA_TTABLE);  /* force an error */\n  }\n}\n\n\n#if defined(LUA_COMPAT_MAXN)\nstatic int maxn (lua_State *L) {\n  lua_Number max = 0;\n  luaL_checktype(L, 1, LUA_TTABLE);\n  lua_pushnil(L);  /* first key */\n  while (lua_next(L, 1)) {\n    lua_pop(L, 1);  /* remove value */\n    if (lua_type(L, -1) == LUA_TNUMBER) {\n      lua_Number v = lua_tonumber(L, -1);\n      if (v > max) max = v;\n    }\n  }\n  lua_pushnumber(L, max);\n  return 1;\n}\n#endif\n\n\nstatic int tinsert (lua_State *L) {\n  lua_Integer e = aux_getn(L, 1, TAB_RW) + 1;  /* first empty element */\n  lua_Integer pos;  /* where to insert new element */\n  switch (lua_gettop(L)) {\n    case 2: {  /* called with only 2 arguments */\n      pos = e;  /* insert new element at the end */\n      break;\n    }\n    case 3: {\n      lua_Integer i;\n      pos = luaL_checkinteger(L, 2);  /* 2nd argument is the position */\n      luaL_argcheck(L, 1 <= pos && pos <= e, 2, \"position out of bounds\");\n      for (i = e; i > pos; i--) {  /* move up elements */\n        lua_geti(L, 1, i - 1);\n        lua_seti(L, 1, i);  /* t[i] = t[i - 1] */\n      }\n      break;\n    }\n    default: {\n      return luaL_error(L, \"wrong number of arguments to 'insert'\");\n    }\n  }\n  lua_seti(L, 1, pos);  /* t[pos] = v */\n  return 0;\n}\n\n\nstatic int tremove (lua_State *L) {\n  lua_Integer size = aux_getn(L, 1, TAB_RW);\n  lua_Integer pos = luaL_optinteger(L, 2, size);\n  if (pos != size)  /* validate 'pos' if given */\n    luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, \"position out of bounds\");\n  lua_geti(L, 1, pos);  /* result = t[pos] */\n  for ( ; pos < size; pos++) {\n    lua_geti(L, 1, pos + 1);\n    lua_seti(L, 1, pos);  /* t[pos] = t[pos + 1] */\n  }\n  lua_pushnil(L);\n  lua_seti(L, 1, pos);  /* t[pos] = nil */\n  return 1;\n}\n\n\n/*\n** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever\n** possible, copy in increasing order, which is better for rehashing.\n** \"possible\" means destination after original range, or smaller\n** than origin, or copying to another table.\n*/\nstatic int tmove (lua_State *L) {\n  lua_Integer f = luaL_checkinteger(L, 2);\n  lua_Integer e = luaL_checkinteger(L, 3);\n  lua_Integer t = luaL_checkinteger(L, 4);\n  int tt = !lua_isnoneornil(L, 5) ? 5 : 1;  /* destination table */\n  checktab(L, 1, TAB_R);\n  checktab(L, tt, TAB_W);\n  if (e >= f) {  /* otherwise, nothing to move */\n    lua_Integer n, i;\n    luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,\n                  \"too many elements to move\");\n    n = e - f + 1;  /* number of elements to move */\n    luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,\n                  \"destination wrap around\");\n    if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {\n      for (i = 0; i < n; i++) {\n        lua_geti(L, 1, f + i);\n        lua_seti(L, tt, t + i);\n      }\n    }\n    else {\n      for (i = n - 1; i >= 0; i--) {\n        lua_geti(L, 1, f + i);\n        lua_seti(L, tt, t + i);\n      }\n    }\n  }\n  lua_pushvalue(L, tt);  /* return destination table */\n  return 1;\n}\n\n\nstatic void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {\n  lua_geti(L, 1, i);\n  if (!lua_isstring(L, -1))\n    luaL_error(L, \"invalid value (%s) at index %d in table for 'concat'\",\n                  luaL_typename(L, -1), i);\n  luaL_addvalue(b);\n}\n\n\nstatic int tconcat (lua_State *L) {\n  luaL_Buffer b;\n  lua_Integer last = aux_getn(L, 1, TAB_R);\n  size_t lsep;\n  const char *sep = luaL_optlstring(L, 2, \"\", &lsep);\n  lua_Integer i = luaL_optinteger(L, 3, 1);\n  last = luaL_optinteger(L, 4, last);\n  luaL_buffinit(L, &b);\n  for (; i < last; i++) {\n    addfield(L, &b, i);\n    luaL_addlstring(&b, sep, lsep);\n  }\n  if (i == last)  /* add last value (if interval was not empty) */\n    addfield(L, &b, i);\n  luaL_pushresult(&b);\n  return 1;\n}\n\n\n/*\n** {======================================================\n** Pack/unpack\n** =======================================================\n*/\n\nstatic int pack (lua_State *L) {\n  int i;\n  int n = lua_gettop(L);  /* number of elements to pack */\n  lua_createtable(L, n, 1);  /* create result table */\n  lua_insert(L, 1);  /* put it at index 1 */\n  for (i = n; i >= 1; i--)  /* assign elements */\n    lua_seti(L, 1, i);\n  lua_pushinteger(L, n);\n  lua_setfield(L, 1, \"n\");  /* t.n = number of elements */\n  return 1;  /* return table */\n}\n\n\nstatic int unpack (lua_State *L) {\n  lua_Unsigned n;\n  lua_Integer i = luaL_optinteger(L, 2, 1);\n  lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));\n  if (i > e) return 0;  /* empty range */\n  n = (lua_Unsigned)e - i;  /* number of elements minus 1 (avoid overflows) */\n  if (n >= (unsigned int)INT_MAX  || !lua_checkstack(L, (int)(++n)))\n    return luaL_error(L, \"too many results to unpack\");\n  for (; i < e; i++) {  /* push arg[i..e - 1] (to avoid overflows) */\n    lua_geti(L, 1, i);\n  }\n  lua_geti(L, 1, e);  /* push last element */\n  return (int)n;\n}\n\n/* }====================================================== */\n\n\n\n/*\n** {======================================================\n** Quicksort\n** (based on 'Algorithms in MODULA-3', Robert Sedgewick;\n**  Addison-Wesley, 1993.)\n** =======================================================\n*/\n\n\n/* type for array indices */\ntypedef unsigned int IdxT;\n\n\n/*\n** Produce a \"random\" 'unsigned int' to randomize pivot choice. This\n** macro is used only when 'sort' detects a big imbalance in the result\n** of a partition. (If you don't want/need this \"randomness\", ~0 is a\n** good choice.)\n*/\n#if !defined(l_randomizePivot)\t\t/* { */\n\n#include <time.h>\n\n/* size of 'e' measured in number of 'unsigned int's */\n#define sof(e)\t\t(sizeof(e) / sizeof(unsigned int))\n\n/*\n** Use 'time' and 'clock' as sources of \"randomness\". Because we don't\n** know the types 'clock_t' and 'time_t', we cannot cast them to\n** anything without risking overflows. A safe way to use their values\n** is to copy them to an array of a known type and use the array values.\n*/\nstatic unsigned int l_randomizePivot (void) {\n  clock_t c = clock();\n  time_t t = time(NULL);\n  unsigned int buff[sof(c) + sof(t)];\n  unsigned int i, rnd = 0;\n  memcpy(buff, &c, sof(c) * sizeof(unsigned int));\n  memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));\n  for (i = 0; i < sof(buff); i++)\n    rnd += buff[i];\n  return rnd;\n}\n\n#endif\t\t\t\t\t/* } */\n\n\n/* arrays larger than 'RANLIMIT' may use randomized pivots */\n#define RANLIMIT\t100u\n\n\nstatic void set2 (lua_State *L, IdxT i, IdxT j) {\n  lua_seti(L, 1, i);\n  lua_seti(L, 1, j);\n}\n\n\n/*\n** Return true iff value at stack index 'a' is less than the value at\n** index 'b' (according to the order of the sort).\n*/\nstatic int sort_comp (lua_State *L, int a, int b) {\n  if (lua_isnil(L, 2))  /* no function? */\n    return lua_compare(L, a, b, LUA_OPLT);  /* a < b */\n  else {  /* function */\n    int res;\n    lua_pushvalue(L, 2);    /* push function */\n    lua_pushvalue(L, a-1);  /* -1 to compensate function */\n    lua_pushvalue(L, b-2);  /* -2 to compensate function and 'a' */\n    lua_call(L, 2, 1);      /* call function */\n    res = lua_toboolean(L, -1);  /* get result */\n    lua_pop(L, 1);          /* pop result */\n    return res;\n  }\n}\n\n\n/*\n** Does the partition: Pivot P is at the top of the stack.\n** precondition: a[lo] <= P == a[up-1] <= a[up],\n** so it only needs to do the partition from lo + 1 to up - 2.\n** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]\n** returns 'i'.\n*/\nstatic IdxT partition (lua_State *L, IdxT lo, IdxT up) {\n  IdxT i = lo;  /* will be incremented before first use */\n  IdxT j = up - 1;  /* will be decremented before first use */\n  /* loop invariant: a[lo .. i] <= P <= a[j .. up] */\n  for (;;) {\n    /* next loop: repeat ++i while a[i] < P */\n    while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {\n      if (i == up - 1)  /* a[i] < P  but a[up - 1] == P  ?? */\n        luaL_error(L, \"invalid order function for sorting\");\n      lua_pop(L, 1);  /* remove a[i] */\n    }\n    /* after the loop, a[i] >= P and a[lo .. i - 1] < P */\n    /* next loop: repeat --j while P < a[j] */\n    while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {\n      if (j < i)  /* j < i  but  a[j] > P ?? */\n        luaL_error(L, \"invalid order function for sorting\");\n      lua_pop(L, 1);  /* remove a[j] */\n    }\n    /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */\n    if (j < i) {  /* no elements out of place? */\n      /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */\n      lua_pop(L, 1);  /* pop a[j] */\n      /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */\n      set2(L, up - 1, i);\n      return i;\n    }\n    /* otherwise, swap a[i] - a[j] to restore invariant and repeat */\n    set2(L, i, j);\n  }\n}\n\n\n/*\n** Choose an element in the middle (2nd-3th quarters) of [lo,up]\n** \"randomized\" by 'rnd'\n*/\nstatic IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {\n  IdxT r4 = (up - lo) / 4;  /* range/4 */\n  IdxT p = rnd % (r4 * 2) + (lo + r4);\n  lua_assert(lo + r4 <= p && p <= up - r4);\n  return p;\n}\n\n\n/*\n** QuickSort algorithm (recursive function)\n*/\nstatic void auxsort (lua_State *L, IdxT lo, IdxT up,\n                                   unsigned int rnd) {\n  while (lo < up) {  /* loop for tail recursion */\n    IdxT p;  /* Pivot index */\n    IdxT n;  /* to be used later */\n    /* sort elements 'lo', 'p', and 'up' */\n    lua_geti(L, 1, lo);\n    lua_geti(L, 1, up);\n    if (sort_comp(L, -1, -2))  /* a[up] < a[lo]? */\n      set2(L, lo, up);  /* swap a[lo] - a[up] */\n    else\n      lua_pop(L, 2);  /* remove both values */\n    if (up - lo == 1)  /* only 2 elements? */\n      return;  /* already sorted */\n    if (up - lo < RANLIMIT || rnd == 0)  /* small interval or no randomize? */\n      p = (lo + up)/2;  /* middle element is a good pivot */\n    else  /* for larger intervals, it is worth a random pivot */\n      p = choosePivot(lo, up, rnd);\n    lua_geti(L, 1, p);\n    lua_geti(L, 1, lo);\n    if (sort_comp(L, -2, -1))  /* a[p] < a[lo]? */\n      set2(L, p, lo);  /* swap a[p] - a[lo] */\n    else {\n      lua_pop(L, 1);  /* remove a[lo] */\n      lua_geti(L, 1, up);\n      if (sort_comp(L, -1, -2))  /* a[up] < a[p]? */\n        set2(L, p, up);  /* swap a[up] - a[p] */\n      else\n        lua_pop(L, 2);\n    }\n    if (up - lo == 2)  /* only 3 elements? */\n      return;  /* already sorted */\n    lua_geti(L, 1, p);  /* get middle element (Pivot) */\n    lua_pushvalue(L, -1);  /* push Pivot */\n    lua_geti(L, 1, up - 1);  /* push a[up - 1] */\n    set2(L, p, up - 1);  /* swap Pivot (a[p]) with a[up - 1] */\n    p = partition(L, lo, up);\n    /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */\n    if (p - lo < up - p) {  /* lower interval is smaller? */\n      auxsort(L, lo, p - 1, rnd);  /* call recursively for lower interval */\n      n = p - lo;  /* size of smaller interval */\n      lo = p + 1;  /* tail call for [p + 1 .. up] (upper interval) */\n    }\n    else {\n      auxsort(L, p + 1, up, rnd);  /* call recursively for upper interval */\n      n = up - p;  /* size of smaller interval */\n      up = p - 1;  /* tail call for [lo .. p - 1]  (lower interval) */\n    }\n    if ((up - lo) / 128 > n) /* partition too imbalanced? */\n      rnd = l_randomizePivot();  /* try a new randomization */\n  }  /* tail call auxsort(L, lo, up, rnd) */\n}\n\n\nstatic int sort (lua_State *L) {\n  lua_Integer n = aux_getn(L, 1, TAB_RW);\n  if (n > 1) {  /* non-trivial interval? */\n    luaL_argcheck(L, n < INT_MAX, 1, \"array too big\");\n    if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */\n      luaL_checktype(L, 2, LUA_TFUNCTION);  /* must be a function */\n    lua_settop(L, 2);  /* make sure there are two arguments */\n    auxsort(L, 1, (IdxT)n, 0);\n  }\n  return 0;\n}\n\n/* }====================================================== */\n\n\nstatic const luaL_Reg tab_funcs[] = {\n  {\"concat\", tconcat},\n#if defined(LUA_COMPAT_MAXN)\n  {\"maxn\", maxn},\n#endif\n  {\"insert\", tinsert},\n  {\"pack\", pack},\n  {\"unpack\", unpack},\n  {\"remove\", tremove},\n  {\"move\", tmove},\n  {\"sort\", sort},\n  {NULL, NULL}\n};\n\n\nLUAMOD_API int luaopen_table (lua_State *L) {\n  luaL_newlib(L, tab_funcs);\n#if defined(LUA_COMPAT_UNPACK)\n  /* _G.unpack = table.unpack */\n  lua_getfield(L, -1, \"unpack\");\n  lua_setglobal(L, \"unpack\");\n#endif\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ltm.c",
    "content": "/*\n** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $\n** Tag methods\n** See Copyright Notice in lua.h\n*/\n\n#define ltm_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lobject.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n#include \"lvm.h\"\n\n\nstatic const char udatatypename[] = \"userdata\";\n\nLUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {\n  \"no value\",\n  \"nil\", \"boolean\", udatatypename, \"number\",\n  \"string\", \"table\", \"function\", udatatypename, \"thread\",\n  \"proto\" /* this last case is used for tests only */\n};\n\n\nvoid luaT_init (lua_State *L) {\n  static const char *const luaT_eventname[] = {  /* ORDER TM */\n    \"__index\", \"__newindex\",\n    \"__gc\", \"__mode\", \"__len\", \"__eq\",\n    \"__add\", \"__sub\", \"__mul\", \"__mod\", \"__pow\",\n    \"__div\", \"__idiv\",\n    \"__band\", \"__bor\", \"__bxor\", \"__shl\", \"__shr\",\n    \"__unm\", \"__bnot\", \"__lt\", \"__le\",\n    \"__concat\", \"__call\"\n  };\n  int i;\n  for (i=0; i<TM_N; i++) {\n    G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);\n    luaC_fix(L, obj2gco(G(L)->tmname[i]));  /* never collect these names */\n  }\n}\n\n\n/*\n** function to be used with macro \"fasttm\": optimized for absence of\n** tag methods\n*/\nconst TValue *luaT_gettm (Table *events, TMS event, TString *ename) {\n  const TValue *tm = luaH_getshortstr(events, ename);\n  lua_assert(event <= TM_EQ);\n  if (ttisnil(tm)) {  /* no tag method? */\n    events->flags |= cast_byte(1u<<event);  /* cache this fact */\n    return NULL;\n  }\n  else return tm;\n}\n\n\nconst TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {\n  Table *mt;\n  switch (ttnov(o)) {\n    case LUA_TTABLE:\n      mt = hvalue(o)->metatable;\n      break;\n    case LUA_TUSERDATA:\n      mt = uvalue(o)->metatable;\n      break;\n    default:\n      mt = G(L)->mt[ttnov(o)];\n  }\n  return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject);\n}\n\n\n/*\n** Return the name of the type of an object. For tables and userdata\n** with metatable, use their '__name' metafield, if present.\n*/\nconst char *luaT_objtypename (lua_State *L, const TValue *o) {\n  Table *mt;\n  if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||\n      (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {\n    const TValue *name = luaH_getshortstr(mt, luaS_new(L, \"__name\"));\n    if (ttisstring(name))  /* is '__name' a string? */\n      return getstr(tsvalue(name));  /* use it as type name */\n  }\n  return ttypename(ttnov(o));  /* else use standard type name */\n}\n\n\nvoid luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,\n                  const TValue *p2, TValue *p3, int hasres) {\n  ptrdiff_t result = savestack(L, p3);\n  StkId func = L->top;\n  setobj2s(L, func, f);  /* push function (assume EXTRA_STACK) */\n  setobj2s(L, func + 1, p1);  /* 1st argument */\n  setobj2s(L, func + 2, p2);  /* 2nd argument */\n  L->top += 3;\n  if (!hasres)  /* no result? 'p3' is third argument */\n    setobj2s(L, L->top++, p3);  /* 3rd argument */\n  /* metamethod may yield only when called from Lua code */\n  if (isLua(L->ci))\n    luaD_call(L, func, hasres);\n  else\n    luaD_callnoyield(L, func, hasres);\n  if (hasres) {  /* if has result, move it to its place */\n    p3 = restorestack(L, result);\n    setobjs2s(L, p3, --L->top);\n  }\n}\n\n\nint luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2,\n                    StkId res, TMS event) {\n  const TValue *tm = luaT_gettmbyobj(L, p1, event);  /* try first operand */\n  if (ttisnil(tm))\n    tm = luaT_gettmbyobj(L, p2, event);  /* try second operand */\n  if (ttisnil(tm)) return 0;\n  luaT_callTM(L, tm, p1, p2, res, 1);\n  return 1;\n}\n\n\nvoid luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,\n                    StkId res, TMS event) {\n  if (!luaT_callbinTM(L, p1, p2, res, event)) {\n    switch (event) {\n      case TM_CONCAT:\n        luaG_concaterror(L, p1, p2);\n      /* call never returns, but to avoid warnings: *//* FALLTHROUGH */\n      case TM_BAND: case TM_BOR: case TM_BXOR:\n      case TM_SHL: case TM_SHR: case TM_BNOT: {\n        lua_Number dummy;\n        if (tonumber(p1, &dummy) && tonumber(p2, &dummy))\n          luaG_tointerror(L, p1, p2);\n        else\n          luaG_opinterror(L, p1, p2, \"perform bitwise operation on\");\n      }\n      /* calls never return, but to avoid warnings: *//* FALLTHROUGH */\n      default:\n        luaG_opinterror(L, p1, p2, \"perform arithmetic on\");\n    }\n  }\n}\n\n\nint luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,\n                      TMS event) {\n  if (!luaT_callbinTM(L, p1, p2, L->top, event))\n    return -1;  /* no metamethod */\n  else\n    return !l_isfalse(L->top);\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/ltm.h",
    "content": "/*\n** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $\n** Tag methods\n** See Copyright Notice in lua.h\n*/\n\n#ifndef ltm_h\n#define ltm_h\n\n\n#include \"lobject.h\"\n\n\n/*\n* WARNING: if you change the order of this enumeration,\n* grep \"ORDER TM\" and \"ORDER OP\"\n*/\ntypedef enum {\n  TM_INDEX,\n  TM_NEWINDEX,\n  TM_GC,\n  TM_MODE,\n  TM_LEN,\n  TM_EQ,  /* last tag method with fast access */\n  TM_ADD,\n  TM_SUB,\n  TM_MUL,\n  TM_MOD,\n  TM_POW,\n  TM_DIV,\n  TM_IDIV,\n  TM_BAND,\n  TM_BOR,\n  TM_BXOR,\n  TM_SHL,\n  TM_SHR,\n  TM_UNM,\n  TM_BNOT,\n  TM_LT,\n  TM_LE,\n  TM_CONCAT,\n  TM_CALL,\n  TM_N\t\t/* number of elements in the enum */\n} TMS;\n\n\n\n#define gfasttm(g,et,e) ((et) == NULL ? NULL : \\\n  ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))\n\n#define fasttm(l,et,e)\tgfasttm(G(l), et, e)\n\n#define ttypename(x)\tluaT_typenames_[(x) + 1]\n\nLUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];\n\n\nLUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);\n\nLUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);\nLUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,\n                                                       TMS event);\nLUAI_FUNC void luaT_init (lua_State *L);\n\nLUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,\n                            const TValue *p2, TValue *p3, int hasres);\nLUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2,\n                              StkId res, TMS event);\nLUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,\n                              StkId res, TMS event);\nLUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,\n                                const TValue *p2, TMS event);\n\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lua.h",
    "content": "/*\n** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $\n** Lua - A Scripting Language\n** Lua.org, PUC-Rio, Brazil (http://www.lua.org)\n** See Copyright Notice at the end of this file\n*/\n\n\n#ifndef lua_h\n#define lua_h\n\n#include <stdarg.h>\n#include <stddef.h>\n\n\n#include \"luaconf.h\"\n\n\n#define LUA_VERSION_MAJOR\t\"5\"\n#define LUA_VERSION_MINOR\t\"3\"\n#define LUA_VERSION_NUM\t\t503\n#define LUA_VERSION_RELEASE\t\"5\"\n\n#define LUA_VERSION\t\"Lua \" LUA_VERSION_MAJOR \".\" LUA_VERSION_MINOR\n#define LUA_RELEASE\tLUA_VERSION \".\" LUA_VERSION_RELEASE\n#define LUA_COPYRIGHT\tLUA_RELEASE \"  Copyright (C) 1994-2018 Lua.org, PUC-Rio\"\n#define LUA_AUTHORS\t\"R. Ierusalimschy, L. H. de Figueiredo, W. Celes\"\n\n\n/* mark for precompiled code ('<esc>Lua') */\n#define LUA_SIGNATURE\t\"\\x1bLua\"\n\n/* option for multiple returns in 'lua_pcall' and 'lua_call' */\n#define LUA_MULTRET\t(-1)\n\n\n/*\n** Pseudo-indices\n** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty\n** space after that to help overflow detection)\n*/\n#define LUA_REGISTRYINDEX\t(-LUAI_MAXSTACK - 1000)\n#define lua_upvalueindex(i)\t(LUA_REGISTRYINDEX - (i))\n\n\n/* thread status */\n#define LUA_OK\t\t0\n#define LUA_YIELD\t1\n#define LUA_ERRRUN\t2\n#define LUA_ERRSYNTAX\t3\n#define LUA_ERRMEM\t4\n#define LUA_ERRGCMM\t5\n#define LUA_ERRERR\t6\n\n\ntypedef struct lua_State lua_State;\n\n\n/*\n** basic types\n*/\n#define LUA_TNONE\t\t(-1)\n\n#define LUA_TNIL\t\t0\n#define LUA_TBOOLEAN\t\t1\n#define LUA_TLIGHTUSERDATA\t2\n#define LUA_TNUMBER\t\t3\n#define LUA_TSTRING\t\t4\n#define LUA_TTABLE\t\t5\n#define LUA_TFUNCTION\t\t6\n#define LUA_TUSERDATA\t\t7\n#define LUA_TTHREAD\t\t8\n\n#define LUA_NUMTAGS\t\t9\n\n\n\n/* minimum Lua stack available to a C function */\n#define LUA_MINSTACK\t20\n\n\n/* predefined values in the registry */\n#define LUA_RIDX_MAINTHREAD\t1\n#define LUA_RIDX_GLOBALS\t2\n#define LUA_RIDX_LAST\t\tLUA_RIDX_GLOBALS\n\n\n/* type of numbers in Lua */\ntypedef LUA_NUMBER lua_Number;\n\n\n/* type for integer functions */\ntypedef LUA_INTEGER lua_Integer;\n\n/* unsigned integer type */\ntypedef LUA_UNSIGNED lua_Unsigned;\n\n/* type for continuation-function contexts */\ntypedef LUA_KCONTEXT lua_KContext;\n\n\n/*\n** Type for C functions registered with Lua\n*/\ntypedef int (*lua_CFunction) (lua_State *L);\n\n/*\n** Type for continuation functions\n*/\ntypedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);\n\n\n/*\n** Type for functions that read/write blocks when loading/dumping Lua chunks\n*/\ntypedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);\n\ntypedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);\n\n\n/*\n** Type for memory-allocation functions\n*/\ntypedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);\n\n\n\n/*\n** generic extra include file\n*/\n#if defined(LUA_USER_H)\n#include LUA_USER_H\n#endif\n\n\n/*\n** RCS ident string\n*/\nextern const char lua_ident[];\n\n\n/*\n** state manipulation\n*/\nLUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);\nLUA_API void       (lua_close) (lua_State *L);\nLUA_API lua_State *(lua_newthread) (lua_State *L);\n\nLUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);\n\n\nLUA_API const lua_Number *(lua_version) (lua_State *L);\n\n\n/*\n** basic stack manipulation\n*/\nLUA_API int   (lua_absindex) (lua_State *L, int idx);\nLUA_API int   (lua_gettop) (lua_State *L);\nLUA_API void  (lua_settop) (lua_State *L, int idx);\nLUA_API void  (lua_pushvalue) (lua_State *L, int idx);\nLUA_API void  (lua_rotate) (lua_State *L, int idx, int n);\nLUA_API void  (lua_copy) (lua_State *L, int fromidx, int toidx);\nLUA_API int   (lua_checkstack) (lua_State *L, int n);\n\nLUA_API void  (lua_xmove) (lua_State *from, lua_State *to, int n);\n\n\n/*\n** access functions (stack -> C)\n*/\n\nLUA_API int             (lua_isnumber) (lua_State *L, int idx);\nLUA_API int             (lua_isstring) (lua_State *L, int idx);\nLUA_API int             (lua_iscfunction) (lua_State *L, int idx);\nLUA_API int             (lua_isinteger) (lua_State *L, int idx);\nLUA_API int             (lua_isuserdata) (lua_State *L, int idx);\nLUA_API int             (lua_type) (lua_State *L, int idx);\nLUA_API const char     *(lua_typename) (lua_State *L, int tp);\n\nLUA_API lua_Number      (lua_tonumberx) (lua_State *L, int idx, int *isnum);\nLUA_API lua_Integer     (lua_tointegerx) (lua_State *L, int idx, int *isnum);\nLUA_API int             (lua_toboolean) (lua_State *L, int idx);\nLUA_API const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len);\nLUA_API size_t          (lua_rawlen) (lua_State *L, int idx);\nLUA_API lua_CFunction   (lua_tocfunction) (lua_State *L, int idx);\nLUA_API void\t       *(lua_touserdata) (lua_State *L, int idx);\nLUA_API lua_State      *(lua_tothread) (lua_State *L, int idx);\nLUA_API const void     *(lua_topointer) (lua_State *L, int idx);\n\n\n/*\n** Comparison and arithmetic functions\n*/\n\n#define LUA_OPADD\t0\t/* ORDER TM, ORDER OP */\n#define LUA_OPSUB\t1\n#define LUA_OPMUL\t2\n#define LUA_OPMOD\t3\n#define LUA_OPPOW\t4\n#define LUA_OPDIV\t5\n#define LUA_OPIDIV\t6\n#define LUA_OPBAND\t7\n#define LUA_OPBOR\t8\n#define LUA_OPBXOR\t9\n#define LUA_OPSHL\t10\n#define LUA_OPSHR\t11\n#define LUA_OPUNM\t12\n#define LUA_OPBNOT\t13\n\nLUA_API void  (lua_arith) (lua_State *L, int op);\n\n#define LUA_OPEQ\t0\n#define LUA_OPLT\t1\n#define LUA_OPLE\t2\n\nLUA_API int   (lua_rawequal) (lua_State *L, int idx1, int idx2);\nLUA_API int   (lua_compare) (lua_State *L, int idx1, int idx2, int op);\n\n\n/*\n** push functions (C -> stack)\n*/\nLUA_API void        (lua_pushnil) (lua_State *L);\nLUA_API void        (lua_pushnumber) (lua_State *L, lua_Number n);\nLUA_API void        (lua_pushinteger) (lua_State *L, lua_Integer n);\nLUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);\nLUA_API const char *(lua_pushstring) (lua_State *L, const char *s);\nLUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,\n                                                      va_list argp);\nLUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);\nLUA_API void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);\nLUA_API void  (lua_pushboolean) (lua_State *L, int b);\nLUA_API void  (lua_pushlightuserdata) (lua_State *L, void *p);\nLUA_API int   (lua_pushthread) (lua_State *L);\n\n\n/*\n** get functions (Lua -> stack)\n*/\nLUA_API int (lua_getglobal) (lua_State *L, const char *name);\nLUA_API int (lua_gettable) (lua_State *L, int idx);\nLUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);\nLUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);\nLUA_API int (lua_rawget) (lua_State *L, int idx);\nLUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);\nLUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);\n\nLUA_API void  (lua_createtable) (lua_State *L, int narr, int nrec);\nLUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);\nLUA_API int   (lua_getmetatable) (lua_State *L, int objindex);\nLUA_API int  (lua_getuservalue) (lua_State *L, int idx);\n\n\n/*\n** set functions (stack -> Lua)\n*/\nLUA_API void  (lua_setglobal) (lua_State *L, const char *name);\nLUA_API void  (lua_settable) (lua_State *L, int idx);\nLUA_API void  (lua_setfield) (lua_State *L, int idx, const char *k);\nLUA_API void  (lua_seti) (lua_State *L, int idx, lua_Integer n);\nLUA_API void  (lua_rawset) (lua_State *L, int idx);\nLUA_API void  (lua_rawseti) (lua_State *L, int idx, lua_Integer n);\nLUA_API void  (lua_rawsetp) (lua_State *L, int idx, const void *p);\nLUA_API int   (lua_setmetatable) (lua_State *L, int objindex);\nLUA_API void  (lua_setuservalue) (lua_State *L, int idx);\n\n\n/*\n** 'load' and 'call' functions (load and run Lua code)\n*/\nLUA_API void  (lua_callk) (lua_State *L, int nargs, int nresults,\n                           lua_KContext ctx, lua_KFunction k);\n#define lua_call(L,n,r)\t\tlua_callk(L, (n), (r), 0, NULL)\n\nLUA_API int   (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,\n                            lua_KContext ctx, lua_KFunction k);\n#define lua_pcall(L,n,r,f)\tlua_pcallk(L, (n), (r), (f), 0, NULL)\n\nLUA_API int   (lua_load) (lua_State *L, lua_Reader reader, void *dt,\n                          const char *chunkname, const char *mode);\n\nLUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);\n\n\n/*\n** coroutine functions\n*/\nLUA_API int  (lua_yieldk)     (lua_State *L, int nresults, lua_KContext ctx,\n                               lua_KFunction k);\nLUA_API int  (lua_resume)     (lua_State *L, lua_State *from, int narg);\nLUA_API int  (lua_status)     (lua_State *L);\nLUA_API int (lua_isyieldable) (lua_State *L);\n\n#define lua_yield(L,n)\t\tlua_yieldk(L, (n), 0, NULL)\n\n\n/*\n** garbage-collection function and options\n*/\n\n#define LUA_GCSTOP\t\t0\n#define LUA_GCRESTART\t\t1\n#define LUA_GCCOLLECT\t\t2\n#define LUA_GCCOUNT\t\t3\n#define LUA_GCCOUNTB\t\t4\n#define LUA_GCSTEP\t\t5\n#define LUA_GCSETPAUSE\t\t6\n#define LUA_GCSETSTEPMUL\t7\n#define LUA_GCISRUNNING\t\t9\n\nLUA_API int (lua_gc) (lua_State *L, int what, int data);\n\n\n/*\n** miscellaneous functions\n*/\n\nLUA_API int   (lua_error) (lua_State *L);\n\nLUA_API int   (lua_next) (lua_State *L, int idx);\n\nLUA_API void  (lua_concat) (lua_State *L, int n);\nLUA_API void  (lua_len)    (lua_State *L, int idx);\n\nLUA_API size_t   (lua_stringtonumber) (lua_State *L, const char *s);\n\nLUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);\nLUA_API void      (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);\n\n\n\n/*\n** {==============================================================\n** some useful macros\n** ===============================================================\n*/\n\n#define lua_getextraspace(L)\t((void *)((char *)(L) - LUA_EXTRASPACE))\n\n#define lua_tonumber(L,i)\tlua_tonumberx(L,(i),NULL)\n#define lua_tointeger(L,i)\tlua_tointegerx(L,(i),NULL)\n\n#define lua_pop(L,n)\t\tlua_settop(L, -(n)-1)\n\n#define lua_newtable(L)\t\tlua_createtable(L, 0, 0)\n\n#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))\n\n#define lua_pushcfunction(L,f)\tlua_pushcclosure(L, (f), 0)\n\n#define lua_isfunction(L,n)\t(lua_type(L, (n)) == LUA_TFUNCTION)\n#define lua_istable(L,n)\t(lua_type(L, (n)) == LUA_TTABLE)\n#define lua_islightuserdata(L,n)\t(lua_type(L, (n)) == LUA_TLIGHTUSERDATA)\n#define lua_isnil(L,n)\t\t(lua_type(L, (n)) == LUA_TNIL)\n#define lua_isboolean(L,n)\t(lua_type(L, (n)) == LUA_TBOOLEAN)\n#define lua_isthread(L,n)\t(lua_type(L, (n)) == LUA_TTHREAD)\n#define lua_isnone(L,n)\t\t(lua_type(L, (n)) == LUA_TNONE)\n#define lua_isnoneornil(L, n)\t(lua_type(L, (n)) <= 0)\n\n#define lua_pushliteral(L, s)\tlua_pushstring(L, \"\" s)\n\n#define lua_pushglobaltable(L)  \\\n\t((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))\n\n#define lua_tostring(L,i)\tlua_tolstring(L, (i), NULL)\n\n\n#define lua_insert(L,idx)\tlua_rotate(L, (idx), 1)\n\n#define lua_remove(L,idx)\t(lua_rotate(L, (idx), -1), lua_pop(L, 1))\n\n#define lua_replace(L,idx)\t(lua_copy(L, -1, (idx)), lua_pop(L, 1))\n\n/* }============================================================== */\n\n\n/*\n** {==============================================================\n** compatibility macros for unsigned conversions\n** ===============================================================\n*/\n#if defined(LUA_COMPAT_APIINTCASTS)\n\n#define lua_pushunsigned(L,n)\tlua_pushinteger(L, (lua_Integer)(n))\n#define lua_tounsignedx(L,i,is)\t((lua_Unsigned)lua_tointegerx(L,i,is))\n#define lua_tounsigned(L,i)\tlua_tounsignedx(L,(i),NULL)\n\n#endif\n/* }============================================================== */\n\n/*\n** {======================================================================\n** Debug API\n** =======================================================================\n*/\n\n\n/*\n** Event codes\n*/\n#define LUA_HOOKCALL\t0\n#define LUA_HOOKRET\t1\n#define LUA_HOOKLINE\t2\n#define LUA_HOOKCOUNT\t3\n#define LUA_HOOKTAILCALL 4\n\n\n/*\n** Event masks\n*/\n#define LUA_MASKCALL\t(1 << LUA_HOOKCALL)\n#define LUA_MASKRET\t(1 << LUA_HOOKRET)\n#define LUA_MASKLINE\t(1 << LUA_HOOKLINE)\n#define LUA_MASKCOUNT\t(1 << LUA_HOOKCOUNT)\n\ntypedef struct lua_Debug lua_Debug;  /* activation record */\n\n\n/* Functions to be called by the debugger in specific events */\ntypedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);\n\n\nLUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);\nLUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);\nLUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);\nLUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);\nLUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);\nLUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);\n\nLUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);\nLUA_API void  (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,\n                                               int fidx2, int n2);\n\nLUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);\nLUA_API lua_Hook (lua_gethook) (lua_State *L);\nLUA_API int (lua_gethookmask) (lua_State *L);\nLUA_API int (lua_gethookcount) (lua_State *L);\n\n\nstruct lua_Debug {\n  int event;\n  const char *name;\t/* (n) */\n  const char *namewhat;\t/* (n) 'global', 'local', 'field', 'method' */\n  const char *what;\t/* (S) 'Lua', 'C', 'main', 'tail' */\n  const char *source;\t/* (S) */\n  int currentline;\t/* (l) */\n  int linedefined;\t/* (S) */\n  int lastlinedefined;\t/* (S) */\n  unsigned char nups;\t/* (u) number of upvalues */\n  unsigned char nparams;/* (u) number of parameters */\n  char isvararg;        /* (u) */\n  char istailcall;\t/* (t) */\n  char short_src[LUA_IDSIZE]; /* (S) */\n  /* private part */\n  struct CallInfo *i_ci;  /* active function */\n};\n\n/* }====================================================================== */\n\n\n/******************************************************************************\n* Copyright (C) 1994-2018 Lua.org, PUC-Rio.\n*\n* Permission is hereby granted, free of charge, to any person obtaining\n* a copy of this software and associated documentation files (the\n* \"Software\"), to deal in the Software without restriction, including\n* without limitation the rights to use, copy, modify, merge, publish,\n* distribute, sublicense, and/or sell copies of the Software, and to\n* permit persons to whom the Software is furnished to do so, subject to\n* the following conditions:\n*\n* The above copyright notice and this permission notice shall be\n* included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n******************************************************************************/\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lua.hpp",
    "content": "// lua.hpp\n// Lua header files for C++\n// <<extern \"C\">> not supplied automatically because Lua also compiles as C++\n\nextern \"C\" {\n#include \"lua.h\"\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n}\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/luaconf.h",
    "content": "/*\n** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $\n** Configuration file for Lua\n** See Copyright Notice in lua.h\n*/\n\n\n#ifndef luaconf_h\n#define luaconf_h\n\n#include <limits.h>\n#include <stddef.h>\n\n\n/*\n** ===================================================================\n** Search for \"@@\" to find all configurable definitions.\n** ===================================================================\n*/\n\n\n/*\n** {====================================================================\n** System Configuration: macros to adapt (if needed) Lua to some\n** particular platform, for instance compiling it with 32-bit numbers or\n** restricting it to C89.\n** =====================================================================\n*/\n\n/*\n@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You\n** can also define LUA_32BITS in the make file, but changing here you\n** ensure that all software connected to Lua will be compiled with the\n** same configuration.\n*/\n/* #define LUA_32BITS */\n\n\n/*\n@@ LUA_USE_C89 controls the use of non-ISO-C89 features.\n** Define it if you want Lua to avoid the use of a few C99 features\n** or Windows-specific features on Windows.\n*/\n/* #define LUA_USE_C89 */\n\n\n/*\n** By default, Lua on Windows use (some) specific Windows features\n*/\n#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)\n#define LUA_USE_WINDOWS  /* enable goodies for regular Windows */\n#endif\n\n\n#if defined(LUA_USE_WINDOWS)\n#define LUA_DL_DLL\t/* enable support for DLL */\n#define LUA_USE_C89\t/* broadly, Windows is C89 */\n#endif\n\n\n#if defined(LUA_USE_LINUX)\n#define LUA_USE_POSIX\n#define LUA_USE_DLOPEN\t\t/* needs an extra library: -ldl */\n#define LUA_USE_READLINE\t/* needs some extra libraries */\n#endif\n\n\n#if defined(LUA_USE_MACOSX)\n#define LUA_USE_POSIX\n#define LUA_USE_DLOPEN\t\t/* MacOS does not need -ldl */\n#define LUA_USE_READLINE\t/* needs an extra library: -lreadline */\n#endif\n\n\n/*\n@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for\n** C89 ('long' and 'double'); Windows always has '__int64', so it does\n** not need to use this case.\n*/\n#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)\n#define LUA_C89_NUMBERS\n#endif\n\n\n\n/*\n@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.\n*/\n/* avoid undefined shifts */\n#if ((INT_MAX >> 15) >> 15) >= 1\n#define LUAI_BITSINT\t32\n#else\n/* 'int' always must have at least 16 bits */\n#define LUAI_BITSINT\t16\n#endif\n\n\n/*\n@@ LUA_INT_TYPE defines the type for Lua integers.\n@@ LUA_FLOAT_TYPE defines the type for Lua floats.\n** Lua should work fine with any mix of these options (if supported\n** by your C compiler). The usual configurations are 64-bit integers\n** and 'double' (the default), 32-bit integers and 'float' (for\n** restricted platforms), and 'long'/'double' (for C compilers not\n** compliant with C99, which may not have support for 'long long').\n*/\n\n/* predefined options for LUA_INT_TYPE */\n#define LUA_INT_INT\t\t1\n#define LUA_INT_LONG\t\t2\n#define LUA_INT_LONGLONG\t3\n\n/* predefined options for LUA_FLOAT_TYPE */\n#define LUA_FLOAT_FLOAT\t\t1\n#define LUA_FLOAT_DOUBLE\t2\n#define LUA_FLOAT_LONGDOUBLE\t3\n\n#if defined(LUA_32BITS)\t\t/* { */\n/*\n** 32-bit integers and 'float'\n*/\n#if LUAI_BITSINT >= 32  /* use 'int' if big enough */\n#define LUA_INT_TYPE\tLUA_INT_INT\n#else  /* otherwise use 'long' */\n#define LUA_INT_TYPE\tLUA_INT_LONG\n#endif\n#define LUA_FLOAT_TYPE\tLUA_FLOAT_FLOAT\n\n#elif defined(LUA_C89_NUMBERS)\t/* }{ */\n/*\n** largest types available for C89 ('long' and 'double')\n*/\n#define LUA_INT_TYPE\tLUA_INT_LONG\n#define LUA_FLOAT_TYPE\tLUA_FLOAT_DOUBLE\n\n#endif\t\t\t\t/* } */\n\n\n/*\n** default configuration for 64-bit Lua ('long long' and 'double')\n*/\n#if !defined(LUA_INT_TYPE)\n#define LUA_INT_TYPE\tLUA_INT_LONGLONG\n#endif\n\n#if !defined(LUA_FLOAT_TYPE)\n#define LUA_FLOAT_TYPE\tLUA_FLOAT_DOUBLE\n#endif\n\n/* }================================================================== */\n\n\n\n\n/*\n** {==================================================================\n** Configuration for Paths.\n** ===================================================================\n*/\n\n/*\n** LUA_PATH_SEP is the character that separates templates in a path.\n** LUA_PATH_MARK is the string that marks the substitution points in a\n** template.\n** LUA_EXEC_DIR in a Windows path is replaced by the executable's\n** directory.\n*/\n#define LUA_PATH_SEP            \";\"\n#define LUA_PATH_MARK           \"?\"\n#define LUA_EXEC_DIR            \"!\"\n\n\n/*\n@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for\n** Lua libraries.\n@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for\n** C libraries.\n** CHANGE them if your machine has a non-conventional directory\n** hierarchy or if you want to install your libraries in\n** non-conventional directories.\n*/\n#define LUA_VDIR\tLUA_VERSION_MAJOR \".\" LUA_VERSION_MINOR\n#if defined(_WIN32)\t/* { */\n/*\n** In Windows, any exclamation mark ('!') in the path is replaced by the\n** path of the directory of the executable file of the current process.\n*/\n#define LUA_LDIR\t\"!\\\\lua\\\\\"\n#define LUA_CDIR\t\"!\\\\\"\n#define LUA_SHRDIR\t\"!\\\\..\\\\share\\\\lua\\\\\" LUA_VDIR \"\\\\\"\n#define LUA_PATH_DEFAULT  \\\n\t\tLUA_LDIR\"?.lua;\"  LUA_LDIR\"?\\\\init.lua;\" \\\n\t\tLUA_CDIR\"?.lua;\"  LUA_CDIR\"?\\\\init.lua;\" \\\n\t\tLUA_SHRDIR\"?.lua;\" LUA_SHRDIR\"?\\\\init.lua;\" \\\n\t\t\".\\\\?.lua;\" \".\\\\?\\\\init.lua\"\n#define LUA_CPATH_DEFAULT \\\n\t\tLUA_CDIR\"?.dll;\" \\\n\t\tLUA_CDIR\"..\\\\lib\\\\lua\\\\\" LUA_VDIR \"\\\\?.dll;\" \\\n\t\tLUA_CDIR\"loadall.dll;\" \".\\\\?.dll\"\n\n#else\t\t\t/* }{ */\n\n#define LUA_ROOT\t\"/usr/local/\"\n#define LUA_LDIR\tLUA_ROOT \"share/lua/\" LUA_VDIR \"/\"\n#define LUA_CDIR\tLUA_ROOT \"lib/lua/\" LUA_VDIR \"/\"\n#define LUA_PATH_DEFAULT  \\\n\t\tLUA_LDIR\"?.lua;\"  LUA_LDIR\"?/init.lua;\" \\\n\t\tLUA_CDIR\"?.lua;\"  LUA_CDIR\"?/init.lua;\" \\\n\t\t\"./?.lua;\" \"./?/init.lua\"\n#define LUA_CPATH_DEFAULT \\\n\t\tLUA_CDIR\"?.so;\" LUA_CDIR\"loadall.so;\" \"./?.so\"\n#endif\t\t\t/* } */\n\n\n/*\n@@ LUA_DIRSEP is the directory separator (for submodules).\n** CHANGE it if your machine does not use \"/\" as the directory separator\n** and is not Windows. (On Windows Lua automatically uses \"\\\".)\n*/\n#if defined(_WIN32)\n#define LUA_DIRSEP\t\"\\\\\"\n#else\n#define LUA_DIRSEP\t\"/\"\n#endif\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Marks for exported symbols in the C code\n** ===================================================================\n*/\n\n/*\n@@ LUA_API is a mark for all core API functions.\n@@ LUALIB_API is a mark for all auxiliary library functions.\n@@ LUAMOD_API is a mark for all standard library opening functions.\n** CHANGE them if you need to define those functions in some special way.\n** For instance, if you want to create one Windows DLL with the core and\n** the libraries, you may want to use the following definition (define\n** LUA_BUILD_AS_DLL to get it).\n*/\n#if defined(LUA_BUILD_AS_DLL)\t/* { */\n\n#if defined(LUA_CORE) || defined(LUA_LIB)\t/* { */\n#define LUA_API __declspec(dllexport)\n#else\t\t\t\t\t\t/* }{ */\n#define LUA_API __declspec(dllimport)\n#endif\t\t\t\t\t\t/* } */\n\n#else\t\t\t\t/* }{ */\n\n#define LUA_API\t\textern\n\n#endif\t\t\t\t/* } */\n\n\n/* more often than not the libs go together with the core */\n#define LUALIB_API\tLUA_API\n#define LUAMOD_API\tLUALIB_API\n\n\n/*\n@@ LUAI_FUNC is a mark for all extern functions that are not to be\n** exported to outside modules.\n@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables\n** that are not to be exported to outside modules (LUAI_DDEF for\n** definitions and LUAI_DDEC for declarations).\n** CHANGE them if you need to mark them in some special way. Elf/gcc\n** (versions 3.2 and later) mark them as \"hidden\" to optimize access\n** when Lua is compiled as a shared library. Not all elf targets support\n** this attribute. Unfortunately, gcc does not offer a way to check\n** whether the target offers that support, and those without support\n** give a warning about it. To avoid these warnings, change to the\n** default definition.\n*/\n#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \\\n    defined(__ELF__)\t\t/* { */\n#define LUAI_FUNC\t__attribute__((visibility(\"hidden\"))) extern\n#else\t\t\t\t/* }{ */\n#define LUAI_FUNC\textern\n#endif\t\t\t\t/* } */\n\n#define LUAI_DDEC\tLUAI_FUNC\n#define LUAI_DDEF\t/* empty */\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Compatibility with previous versions\n** ===================================================================\n*/\n\n/*\n@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.\n@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.\n** You can define it to get all options, or change specific options\n** to fit your specific needs.\n*/\n#if defined(LUA_COMPAT_5_2)\t/* { */\n\n/*\n@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated\n** functions in the mathematical library.\n*/\n#define LUA_COMPAT_MATHLIB\n\n/*\n@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.\n*/\n#define LUA_COMPAT_BITLIB\n\n/*\n@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.\n*/\n#define LUA_COMPAT_IPAIRS\n\n/*\n@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for\n** manipulating other integer types (lua_pushunsigned, lua_tounsigned,\n** luaL_checkint, luaL_checklong, etc.)\n*/\n#define LUA_COMPAT_APIINTCASTS\n\n#endif\t\t\t\t/* } */\n\n\n#if defined(LUA_COMPAT_5_1)\t/* { */\n\n/* Incompatibilities from 5.2 -> 5.3 */\n#define LUA_COMPAT_MATHLIB\n#define LUA_COMPAT_APIINTCASTS\n\n/*\n@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.\n** You can replace it with 'table.unpack'.\n*/\n#define LUA_COMPAT_UNPACK\n\n/*\n@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.\n** You can replace it with 'package.searchers'.\n*/\n#define LUA_COMPAT_LOADERS\n\n/*\n@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.\n** You can call your C function directly (with light C functions).\n*/\n#define lua_cpcall(L,f,u)  \\\n\t(lua_pushcfunction(L, (f)), \\\n\t lua_pushlightuserdata(L,(u)), \\\n\t lua_pcall(L,1,0,0))\n\n\n/*\n@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.\n** You can rewrite 'log10(x)' as 'log(x, 10)'.\n*/\n#define LUA_COMPAT_LOG10\n\n/*\n@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base\n** library. You can rewrite 'loadstring(s)' as 'load(s)'.\n*/\n#define LUA_COMPAT_LOADSTRING\n\n/*\n@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.\n*/\n#define LUA_COMPAT_MAXN\n\n/*\n@@ The following macros supply trivial compatibility for some\n** changes in the API. The macros themselves document how to\n** change your code to avoid using them.\n*/\n#define lua_strlen(L,i)\t\tlua_rawlen(L, (i))\n\n#define lua_objlen(L,i)\t\tlua_rawlen(L, (i))\n\n#define lua_equal(L,idx1,idx2)\t\tlua_compare(L,(idx1),(idx2),LUA_OPEQ)\n#define lua_lessthan(L,idx1,idx2)\tlua_compare(L,(idx1),(idx2),LUA_OPLT)\n\n/*\n@@ LUA_COMPAT_MODULE controls compatibility with previous\n** module functions 'module' (Lua) and 'luaL_register' (C).\n*/\n#define LUA_COMPAT_MODULE\n\n#endif\t\t\t\t/* } */\n\n\n/*\n@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a\n@@ a float mark ('.0').\n** This macro is not on by default even in compatibility mode,\n** because this is not really an incompatibility.\n*/\n/* #define LUA_COMPAT_FLOATSTRING */\n\n/* }================================================================== */\n\n\n\n/*\n** {==================================================================\n** Configuration for Numbers.\n** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*\n** satisfy your needs.\n** ===================================================================\n*/\n\n/*\n@@ LUA_NUMBER is the floating-point type used by Lua.\n@@ LUAI_UACNUMBER is the result of a 'default argument promotion'\n@@ over a floating number.\n@@ l_mathlim(x) corrects limit name 'x' to the proper float type\n** by prefixing it with one of FLT/DBL/LDBL.\n@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.\n@@ LUA_NUMBER_FMT is the format for writing floats.\n@@ lua_number2str converts a float to a string.\n@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.\n@@ l_floor takes the floor of a float.\n@@ lua_str2number converts a decimal numeric string to a number.\n*/\n\n\n/* The following definitions are good for most cases here */\n\n#define l_floor(x)\t\t(l_mathop(floor)(x))\n\n#define lua_number2str(s,sz,n)  \\\n\tl_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))\n\n/*\n@@ lua_numbertointeger converts a float number to an integer, or\n** returns 0 if float is not within the range of a lua_Integer.\n** (The range comparisons are tricky because of rounding. The tests\n** here assume a two-complement representation, where MININTEGER always\n** has an exact representation as a float; MAXINTEGER may not have one,\n** and therefore its conversion to float may have an ill-defined value.)\n*/\n#define lua_numbertointeger(n,p) \\\n  ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \\\n   (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \\\n      (*(p) = (LUA_INTEGER)(n), 1))\n\n\n/* now the variable definitions */\n\n#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT\t\t/* { single float */\n\n#define LUA_NUMBER\tfloat\n\n#define l_mathlim(n)\t\t(FLT_##n)\n\n#define LUAI_UACNUMBER\tdouble\n\n#define LUA_NUMBER_FRMLEN\t\"\"\n#define LUA_NUMBER_FMT\t\t\"%.7g\"\n\n#define l_mathop(op)\t\top##f\n\n#define lua_str2number(s,p)\tstrtof((s), (p))\n\n\n#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE\t/* }{ long double */\n\n#define LUA_NUMBER\tlong double\n\n#define l_mathlim(n)\t\t(LDBL_##n)\n\n#define LUAI_UACNUMBER\tlong double\n\n#define LUA_NUMBER_FRMLEN\t\"L\"\n#define LUA_NUMBER_FMT\t\t\"%.19Lg\"\n\n#define l_mathop(op)\t\top##l\n\n#define lua_str2number(s,p)\tstrtold((s), (p))\n\n#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE\t/* }{ double */\n\n#define LUA_NUMBER\tdouble\n\n#define l_mathlim(n)\t\t(DBL_##n)\n\n#define LUAI_UACNUMBER\tdouble\n\n#define LUA_NUMBER_FRMLEN\t\"\"\n#define LUA_NUMBER_FMT\t\t\"%.14g\"\n\n#define l_mathop(op)\t\top\n\n#define lua_str2number(s,p)\tstrtod((s), (p))\n\n#else\t\t\t\t\t\t/* }{ */\n\n#error \"numeric float type not defined\"\n\n#endif\t\t\t\t\t/* } */\n\n\n\n/*\n@@ LUA_INTEGER is the integer type used by Lua.\n**\n@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.\n**\n@@ LUAI_UACINT is the result of a 'default argument promotion'\n@@ over a lUA_INTEGER.\n@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.\n@@ LUA_INTEGER_FMT is the format for writing integers.\n@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.\n@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.\n@@ lua_integer2str converts an integer to a string.\n*/\n\n\n/* The following definitions are good for most cases here */\n\n#define LUA_INTEGER_FMT\t\t\"%\" LUA_INTEGER_FRMLEN \"d\"\n\n#define LUAI_UACINT\t\tLUA_INTEGER\n\n#define lua_integer2str(s,sz,n)  \\\n\tl_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))\n\n/*\n** use LUAI_UACINT here to avoid problems with promotions (which\n** can turn a comparison between unsigneds into a signed comparison)\n*/\n#define LUA_UNSIGNED\t\tunsigned LUAI_UACINT\n\n\n/* now the variable definitions */\n\n#if LUA_INT_TYPE == LUA_INT_INT\t\t/* { int */\n\n#define LUA_INTEGER\t\tint\n#define LUA_INTEGER_FRMLEN\t\"\"\n\n#define LUA_MAXINTEGER\t\tINT_MAX\n#define LUA_MININTEGER\t\tINT_MIN\n\n#elif LUA_INT_TYPE == LUA_INT_LONG\t/* }{ long */\n\n#define LUA_INTEGER\t\tlong\n#define LUA_INTEGER_FRMLEN\t\"l\"\n\n#define LUA_MAXINTEGER\t\tLONG_MAX\n#define LUA_MININTEGER\t\tLONG_MIN\n\n#elif LUA_INT_TYPE == LUA_INT_LONGLONG\t/* }{ long long */\n\n/* use presence of macro LLONG_MAX as proxy for C99 compliance */\n#if defined(LLONG_MAX)\t\t/* { */\n/* use ISO C99 stuff */\n\n#define LUA_INTEGER\t\tlong long\n#define LUA_INTEGER_FRMLEN\t\"ll\"\n\n#define LUA_MAXINTEGER\t\tLLONG_MAX\n#define LUA_MININTEGER\t\tLLONG_MIN\n\n#elif defined(LUA_USE_WINDOWS) /* }{ */\n/* in Windows, can use specific Windows types */\n\n#define LUA_INTEGER\t\t__int64\n#define LUA_INTEGER_FRMLEN\t\"I64\"\n\n#define LUA_MAXINTEGER\t\t_I64_MAX\n#define LUA_MININTEGER\t\t_I64_MIN\n\n#else\t\t\t\t/* }{ */\n\n#error \"Compiler does not support 'long long'. Use option '-DLUA_32BITS' \\\n  or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)\"\n\n#endif\t\t\t\t/* } */\n\n#else\t\t\t\t/* }{ */\n\n#error \"numeric integer type not defined\"\n\n#endif\t\t\t\t/* } */\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Dependencies with C99 and other C details\n** ===================================================================\n*/\n\n/*\n@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.\n** (All uses in Lua have only one format item.)\n*/\n#if !defined(LUA_USE_C89)\n#define l_sprintf(s,sz,f,i)\tsnprintf(s,sz,f,i)\n#else\n#define l_sprintf(s,sz,f,i)\t((void)(sz), sprintf(s,f,i))\n#endif\n\n\n/*\n@@ lua_strx2number converts an hexadecimal numeric string to a number.\n** In C99, 'strtod' does that conversion. Otherwise, you can\n** leave 'lua_strx2number' undefined and Lua will provide its own\n** implementation.\n*/\n#if !defined(LUA_USE_C89)\n#define lua_strx2number(s,p)\t\tlua_str2number(s,p)\n#endif\n\n\n/*\n@@ lua_pointer2str converts a pointer to a readable string in a\n** non-specified way.\n*/\n#define lua_pointer2str(buff,sz,p)\tl_sprintf(buff,sz,\"%p\",p)\n\n\n/*\n@@ lua_number2strx converts a float to an hexadecimal numeric string.\n** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.\n** Otherwise, you can leave 'lua_number2strx' undefined and Lua will\n** provide its own implementation.\n*/\n#if !defined(LUA_USE_C89)\n#define lua_number2strx(L,b,sz,f,n)  \\\n\t((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))\n#endif\n\n\n/*\n** 'strtof' and 'opf' variants for math functions are not valid in\n** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the\n** availability of these variants. ('math.h' is already included in\n** all files that use these macros.)\n*/\n#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))\n#undef l_mathop  /* variants not available */\n#undef lua_str2number\n#define l_mathop(op)\t\t(lua_Number)op  /* no variant */\n#define lua_str2number(s,p)\t((lua_Number)strtod((s), (p)))\n#endif\n\n\n/*\n@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation\n** functions.  It must be a numerical type; Lua will use 'intptr_t' if\n** available, otherwise it will use 'ptrdiff_t' (the nearest thing to\n** 'intptr_t' in C89)\n*/\n#define LUA_KCONTEXT\tptrdiff_t\n\n#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \\\n    __STDC_VERSION__ >= 199901L\n#include <stdint.h>\n#if defined(INTPTR_MAX)  /* even in C99 this type is optional */\n#undef LUA_KCONTEXT\n#define LUA_KCONTEXT\tintptr_t\n#endif\n#endif\n\n\n/*\n@@ lua_getlocaledecpoint gets the locale \"radix character\" (decimal point).\n** Change that if you do not want to use C locales. (Code using this\n** macro must include header 'locale.h'.)\n*/\n#if !defined(lua_getlocaledecpoint)\n#define lua_getlocaledecpoint()\t\t(localeconv()->decimal_point[0])\n#endif\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Language Variations\n** =====================================================================\n*/\n\n/*\n@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some\n** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from\n** numbers to strings. Define LUA_NOCVTS2N to turn off automatic\n** coercion from strings to numbers.\n*/\n/* #define LUA_NOCVTN2S */\n/* #define LUA_NOCVTS2N */\n\n\n/*\n@@ LUA_USE_APICHECK turns on several consistency checks on the C API.\n** Define it as a help when debugging C code.\n*/\n#if defined(LUA_USE_APICHECK)\n#include <assert.h>\n#define luai_apicheck(l,e)\tassert(e)\n#endif\n\n/* }================================================================== */\n\n\n/*\n** {==================================================================\n** Macros that affect the API and must be stable (that is, must be the\n** same when you compile Lua and when you compile code that links to\n** Lua). You probably do not want/need to change them.\n** =====================================================================\n*/\n\n/*\n@@ LUAI_MAXSTACK limits the size of the Lua stack.\n** CHANGE it if you need a different limit. This limit is arbitrary;\n** its only purpose is to stop Lua from consuming unlimited stack\n** space (and to reserve some numbers for pseudo-indices).\n*/\n#if LUAI_BITSINT >= 32\n#define LUAI_MAXSTACK\t\t1000000\n#else\n#define LUAI_MAXSTACK\t\t15000\n#endif\n\n\n/*\n@@ LUA_EXTRASPACE defines the size of a raw memory area associated with\n** a Lua state with very fast access.\n** CHANGE it if you need a different size.\n*/\n#define LUA_EXTRASPACE\t\t(sizeof(void *))\n\n\n/*\n@@ LUA_IDSIZE gives the maximum size for the description of the source\n@@ of a function in debug information.\n** CHANGE it if you want a different size.\n*/\n#define LUA_IDSIZE\t60\n\n\n/*\n@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.\n** CHANGE it if it uses too much C-stack space. (For long double,\n** 'string.format(\"%.99f\", -1e4932)' needs 5034 bytes, so a\n** smaller buffer would force a memory allocation for each call to\n** 'string.format'.)\n*/\n#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE\n#define LUAL_BUFFERSIZE\t\t8192\n#else\n#define LUAL_BUFFERSIZE   ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))\n#endif\n\n/* }================================================================== */\n\n\n/*\n@@ LUA_QL describes how error messages quote program elements.\n** Lua does not use these macros anymore; they are here for\n** compatibility only.\n*/\n#define LUA_QL(x)\t\"'\" x \"'\"\n#define LUA_QS\t\tLUA_QL(\"%s\")\n\n\n\n\n/* =================================================================== */\n\n/*\n** Local configuration. You can use this space to add your redefinitions\n** without modifying the main part of the file.\n*/\n\n\n\n\n\n#endif\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lualib.h",
    "content": "/*\n** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $\n** Lua standard libraries\n** See Copyright Notice in lua.h\n*/\n\n\n#ifndef lualib_h\n#define lualib_h\n\n#include \"lua.h\"\n\n\n/* version suffix for environment variable names */\n#define LUA_VERSUFFIX          \"_\" LUA_VERSION_MAJOR \"_\" LUA_VERSION_MINOR\n\n\nLUAMOD_API int (luaopen_base) (lua_State *L);\n\n#define LUA_COLIBNAME\t\"coroutine\"\nLUAMOD_API int (luaopen_coroutine) (lua_State *L);\n\n#define LUA_TABLIBNAME\t\"table\"\nLUAMOD_API int (luaopen_table) (lua_State *L);\n\n#define LUA_IOLIBNAME\t\"io\"\nLUAMOD_API int (luaopen_io) (lua_State *L);\n\n#define LUA_OSLIBNAME\t\"os\"\nLUAMOD_API int (luaopen_os) (lua_State *L);\n\n#define LUA_STRLIBNAME\t\"string\"\nLUAMOD_API int (luaopen_string) (lua_State *L);\n\n#define LUA_UTF8LIBNAME\t\"utf8\"\nLUAMOD_API int (luaopen_utf8) (lua_State *L);\n\n#define LUA_BITLIBNAME\t\"bit32\"\nLUAMOD_API int (luaopen_bit32) (lua_State *L);\n\n#define LUA_MATHLIBNAME\t\"math\"\nLUAMOD_API int (luaopen_math) (lua_State *L);\n\n#define LUA_DBLIBNAME\t\"debug\"\nLUAMOD_API int (luaopen_debug) (lua_State *L);\n\n#define LUA_LOADLIBNAME\t\"package\"\nLUAMOD_API int (luaopen_package) (lua_State *L);\n\n\n/* open all previous libraries */\nLUALIB_API void (luaL_openlibs) (lua_State *L);\n\n\n\n#if !defined(lua_assert)\n#define lua_assert(x)\t((void)0)\n#endif\n\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lundump.c",
    "content": "/*\n** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $\n** load precompiled Lua chunks\n** See Copyright Notice in lua.h\n*/\n\n#define lundump_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lmem.h\"\n#include \"lobject.h\"\n#include \"lstring.h\"\n#include \"lundump.h\"\n#include \"lzio.h\"\n\n\n#if !defined(luai_verifycode)\n#define luai_verifycode(L,b,f)  /* empty */\n#endif\n\n\ntypedef struct {\n  lua_State *L;\n  ZIO *Z;\n  const char *name;\n} LoadState;\n\n\nstatic l_noret error(LoadState *S, const char *why) {\n  luaO_pushfstring(S->L, \"%s: %s precompiled chunk\", S->name, why);\n  luaD_throw(S->L, LUA_ERRSYNTAX);\n}\n\n\n/*\n** All high-level loads go through LoadVector; you can change it to\n** adapt to the endianness of the input\n*/\n#define LoadVector(S,b,n)\tLoadBlock(S,b,(n)*sizeof((b)[0]))\n\nstatic void LoadBlock (LoadState *S, void *b, size_t size) {\n  if (luaZ_read(S->Z, b, size) != 0)\n    error(S, \"truncated\");\n}\n\n\n#define LoadVar(S,x)\t\tLoadVector(S,&x,1)\n\n\nstatic lu_byte LoadByte (LoadState *S) {\n  lu_byte x;\n  LoadVar(S, x);\n  return x;\n}\n\n\nstatic int LoadInt (LoadState *S) {\n  int x;\n  LoadVar(S, x);\n  return x;\n}\n\n\nstatic lua_Number LoadNumber (LoadState *S) {\n  lua_Number x;\n  LoadVar(S, x);\n  return x;\n}\n\n\nstatic lua_Integer LoadInteger (LoadState *S) {\n  lua_Integer x;\n  LoadVar(S, x);\n  return x;\n}\n\n\nstatic TString *LoadString (LoadState *S) {\n  size_t size = LoadByte(S);\n  if (size == 0xFF)\n    LoadVar(S, size);\n  if (size == 0)\n    return NULL;\n  else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */\n    char buff[LUAI_MAXSHORTLEN];\n    LoadVector(S, buff, size);\n    return luaS_newlstr(S->L, buff, size);\n  }\n  else {  /* long string */\n    TString *ts = luaS_createlngstrobj(S->L, size);\n    LoadVector(S, getstr(ts), size);  /* load directly in final place */\n    return ts;\n  }\n}\n\n\nstatic void LoadCode (LoadState *S, Proto *f) {\n  int n = LoadInt(S);\n  f->code = luaM_newvector(S->L, n, Instruction);\n  f->sizecode = n;\n  LoadVector(S, f->code, n);\n}\n\n\nstatic void LoadFunction(LoadState *S, Proto *f, TString *psource);\n\n\nstatic void LoadConstants (LoadState *S, Proto *f) {\n  int i;\n  int n = LoadInt(S);\n  f->k = luaM_newvector(S->L, n, TValue);\n  f->sizek = n;\n  for (i = 0; i < n; i++)\n    setnilvalue(&f->k[i]);\n  for (i = 0; i < n; i++) {\n    TValue *o = &f->k[i];\n    int t = LoadByte(S);\n    switch (t) {\n    case LUA_TNIL:\n      setnilvalue(o);\n      break;\n    case LUA_TBOOLEAN:\n      setbvalue(o, LoadByte(S));\n      break;\n    case LUA_TNUMFLT:\n      setfltvalue(o, LoadNumber(S));\n      break;\n    case LUA_TNUMINT:\n      setivalue(o, LoadInteger(S));\n      break;\n    case LUA_TSHRSTR:\n    case LUA_TLNGSTR:\n      setsvalue2n(S->L, o, LoadString(S));\n      break;\n    default:\n      lua_assert(0);\n    }\n  }\n}\n\n\nstatic void LoadProtos (LoadState *S, Proto *f) {\n  int i;\n  int n = LoadInt(S);\n  f->p = luaM_newvector(S->L, n, Proto *);\n  f->sizep = n;\n  for (i = 0; i < n; i++)\n    f->p[i] = NULL;\n  for (i = 0; i < n; i++) {\n    f->p[i] = luaF_newproto(S->L);\n    LoadFunction(S, f->p[i], f->source);\n  }\n}\n\n\nstatic void LoadUpvalues (LoadState *S, Proto *f) {\n  int i, n;\n  n = LoadInt(S);\n  f->upvalues = luaM_newvector(S->L, n, Upvaldesc);\n  f->sizeupvalues = n;\n  for (i = 0; i < n; i++)\n    f->upvalues[i].name = NULL;\n  for (i = 0; i < n; i++) {\n    f->upvalues[i].instack = LoadByte(S);\n    f->upvalues[i].idx = LoadByte(S);\n  }\n}\n\n\nstatic void LoadDebug (LoadState *S, Proto *f) {\n  int i, n;\n  n = LoadInt(S);\n  f->lineinfo = luaM_newvector(S->L, n, int);\n  f->sizelineinfo = n;\n  LoadVector(S, f->lineinfo, n);\n  n = LoadInt(S);\n  f->locvars = luaM_newvector(S->L, n, LocVar);\n  f->sizelocvars = n;\n  for (i = 0; i < n; i++)\n    f->locvars[i].varname = NULL;\n  for (i = 0; i < n; i++) {\n    f->locvars[i].varname = LoadString(S);\n    f->locvars[i].startpc = LoadInt(S);\n    f->locvars[i].endpc = LoadInt(S);\n  }\n  n = LoadInt(S);\n  for (i = 0; i < n; i++)\n    f->upvalues[i].name = LoadString(S);\n}\n\n\nstatic void LoadFunction (LoadState *S, Proto *f, TString *psource) {\n  f->source = LoadString(S);\n  if (f->source == NULL)  /* no source in dump? */\n    f->source = psource;  /* reuse parent's source */\n  f->linedefined = LoadInt(S);\n  f->lastlinedefined = LoadInt(S);\n  f->numparams = LoadByte(S);\n  f->is_vararg = LoadByte(S);\n  f->maxstacksize = LoadByte(S);\n  LoadCode(S, f);\n  LoadConstants(S, f);\n  LoadUpvalues(S, f);\n  LoadProtos(S, f);\n  LoadDebug(S, f);\n}\n\n\nstatic void checkliteral (LoadState *S, const char *s, const char *msg) {\n  char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */\n  size_t len = strlen(s);\n  LoadVector(S, buff, len);\n  if (memcmp(s, buff, len) != 0)\n    error(S, msg);\n}\n\n\nstatic void fchecksize (LoadState *S, size_t size, const char *tname) {\n  if (LoadByte(S) != size)\n    error(S, luaO_pushfstring(S->L, \"%s size mismatch in\", tname));\n}\n\n\n#define checksize(S,t)\tfchecksize(S,sizeof(t),#t)\n\nstatic void checkHeader (LoadState *S) {\n#if HC_PLATFORM != HC_PLATFORM_XDK && !APIEXPLORER_UWP // TODO: wrong, but not using compiled LUA files\n    checkliteral(S, LUA_SIGNATURE + 1, \"not a\");  /* 1st char already checked */\n#endif\n  if (LoadByte(S) != LUAC_VERSION)\n    error(S, \"version mismatch in\");\n  if (LoadByte(S) != LUAC_FORMAT)\n    error(S, \"format mismatch in\");\n  checkliteral(S, LUAC_DATA, \"corrupted\");\n  checksize(S, int);\n  checksize(S, size_t);\n  checksize(S, Instruction);\n  checksize(S, lua_Integer);\n  checksize(S, lua_Number);\n  if (LoadInteger(S) != LUAC_INT)\n    error(S, \"endianness mismatch in\");\n  if (LoadNumber(S) != LUAC_NUM)\n    error(S, \"float format mismatch in\");\n}\n\n\n/*\n** load precompiled chunk\n*/\nLClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {\n  LoadState S;\n  LClosure *cl;\n  if (*name == '@' || *name == '=')\n    S.name = name + 1;\n  else if (*name == LUA_SIGNATURE[0])\n    S.name = \"binary string\";\n  else\n    S.name = name;\n  S.L = L;\n  S.Z = Z;\n  checkHeader(&S);\n  cl = luaF_newLclosure(L, LoadByte(&S));\n  setclLvalue(L, L->top, cl);\n  luaD_inctop(L);\n  cl->p = luaF_newproto(L);\n  LoadFunction(&S, cl->p, NULL);\n  lua_assert(cl->nupvalues == cl->p->sizeupvalues);\n  luai_verifycode(L, buff, cl->p);\n  return cl;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lundump.h",
    "content": "/*\n** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $\n** load precompiled Lua chunks\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lundump_h\n#define lundump_h\n\n#include \"llimits.h\"\n#include \"lobject.h\"\n#include \"lzio.h\"\n\n\n/* data to catch conversion errors */\n#define LUAC_DATA\t\"\\x19\\x93\\r\\n\\x1a\\n\"\n\n#define LUAC_INT\t0x5678\n#define LUAC_NUM\tcast_num(370.5)\n\n#define MYINT(s)\t(s[0]-'0')\n#define LUAC_VERSION\t(MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))\n#define LUAC_FORMAT\t0\t/* this is the official format */\n\n/* load one chunk; from lundump.c */\nLUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);\n\n/* dump one chunk; from ldump.c */\nLUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,\n                         void* data, int strip);\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lutf8lib.c",
    "content": "/*\n** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $\n** Standard library for UTF-8 manipulation\n** See Copyright Notice in lua.h\n*/\n\n#define lutf8lib_c\n#define LUA_LIB\n\n#include \"lprefix.h\"\n\n\n#include <assert.h>\n#include <limits.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"lauxlib.h\"\n#include \"lualib.h\"\n\n#define MAXUNICODE\t0x10FFFF\n\n#define iscont(p)\t((*(p) & 0xC0) == 0x80)\n\n\n/* from strlib */\n/* translate a relative string position: negative means back from end */\nstatic lua_Integer u_posrelat (lua_Integer pos, size_t len) {\n  if (pos >= 0) return pos;\n  else if (0u - (size_t)pos > len) return 0;\n  else return (lua_Integer)len + pos + 1;\n}\n\n\n/*\n** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.\n*/\nstatic const char *utf8_decode (const char *o, int *val) {\n  static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};\n  const unsigned char *s = (const unsigned char *)o;\n  unsigned int c = s[0];\n  unsigned int res = 0;  /* final result */\n  if (c < 0x80)  /* ascii? */\n    res = c;\n  else {\n    int count = 0;  /* to count number of continuation bytes */\n    while (c & 0x40) {  /* still have continuation bytes? */\n      int cc = s[++count];  /* read next byte */\n      if ((cc & 0xC0) != 0x80)  /* not a continuation byte? */\n        return NULL;  /* invalid byte sequence */\n      res = (res << 6) | (cc & 0x3F);  /* add lower 6 bits from cont. byte */\n      c <<= 1;  /* to test next bit */\n    }\n    res |= ((c & 0x7F) << (count * 5));  /* add first byte */\n    if (count > 3 || res > MAXUNICODE || res <= limits[count])\n      return NULL;  /* invalid byte sequence */\n    s += count;  /* skip continuation bytes read */\n  }\n  if (val) *val = res;\n  return (const char *)s + 1;  /* +1 to include first byte */\n}\n\n\n/*\n** utf8len(s [, i [, j]]) --> number of characters that start in the\n** range [i,j], or nil + current position if 's' is not well formed in\n** that interval\n*/\nstatic int utflen (lua_State *L) {\n  int n = 0;\n  size_t len;\n  const char *s = luaL_checklstring(L, 1, &len);\n  lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);\n  lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);\n  luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,\n                   \"initial position out of string\");\n  luaL_argcheck(L, --posj < (lua_Integer)len, 3,\n                   \"final position out of string\");\n  while (posi <= posj) {\n    const char *s1 = utf8_decode(s + posi, NULL);\n    if (s1 == NULL) {  /* conversion error? */\n      lua_pushnil(L);  /* return nil ... */\n      lua_pushinteger(L, posi + 1);  /* ... and current position */\n      return 2;\n    }\n    posi = s1 - s;\n    n++;\n  }\n  lua_pushinteger(L, n);\n  return 1;\n}\n\n\n/*\n** codepoint(s, [i, [j]])  -> returns codepoints for all characters\n** that start in the range [i,j]\n*/\nstatic int codepoint (lua_State *L) {\n  size_t len;\n  const char *s = luaL_checklstring(L, 1, &len);\n  lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);\n  lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len);\n  int n;\n  const char *se;\n  luaL_argcheck(L, posi >= 1, 2, \"out of range\");\n  luaL_argcheck(L, pose <= (lua_Integer)len, 3, \"out of range\");\n  if (posi > pose) return 0;  /* empty interval; return no values */\n  if (pose - posi >= INT_MAX)  /* (lua_Integer -> int) overflow? */\n    return luaL_error(L, \"string slice too long\");\n  n = (int)(pose -  posi) + 1;\n  luaL_checkstack(L, n, \"string slice too long\");\n  n = 0;\n  se = s + pose;\n  for (s += posi - 1; s < se;) {\n    int code;\n    s = utf8_decode(s, &code);\n    if (s == NULL)\n      return luaL_error(L, \"invalid UTF-8 code\");\n    lua_pushinteger(L, code);\n    n++;\n  }\n  return n;\n}\n\n\nstatic void pushutfchar (lua_State *L, int arg) {\n  lua_Integer code = luaL_checkinteger(L, arg);\n  luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, \"value out of range\");\n  lua_pushfstring(L, \"%U\", (long)code);\n}\n\n\n/*\n** utfchar(n1, n2, ...)  -> char(n1)..char(n2)...\n*/\nstatic int utfchar (lua_State *L) {\n  int n = lua_gettop(L);  /* number of arguments */\n  if (n == 1)  /* optimize common case of single char */\n    pushutfchar(L, 1);\n  else {\n    int i;\n    luaL_Buffer b;\n    luaL_buffinit(L, &b);\n    for (i = 1; i <= n; i++) {\n      pushutfchar(L, i);\n      luaL_addvalue(&b);\n    }\n    luaL_pushresult(&b);\n  }\n  return 1;\n}\n\n\n/*\n** offset(s, n, [i])  -> index where n-th character counting from\n**   position 'i' starts; 0 means character at 'i'.\n*/\nstatic int byteoffset (lua_State *L) {\n  size_t len;\n  const char *s = luaL_checklstring(L, 1, &len);\n  lua_Integer n  = luaL_checkinteger(L, 2);\n  lua_Integer posi = (n >= 0) ? 1 : len + 1;\n  posi = u_posrelat(luaL_optinteger(L, 3, posi), len);\n  luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,\n                   \"position out of range\");\n  if (n == 0) {\n    /* find beginning of current byte sequence */\n    while (posi > 0 && iscont(s + posi)) posi--;\n  }\n  else {\n    if (iscont(s + posi))\n      return luaL_error(L, \"initial position is a continuation byte\");\n    if (n < 0) {\n       while (n < 0 && posi > 0) {  /* move back */\n         do {  /* find beginning of previous character */\n           posi--;\n         } while (posi > 0 && iscont(s + posi));\n         n++;\n       }\n     }\n     else {\n       n--;  /* do not move for 1st character */\n       while (n > 0 && posi < (lua_Integer)len) {\n         do {  /* find beginning of next character */\n           posi++;\n         } while (iscont(s + posi));  /* (cannot pass final '\\0') */\n         n--;\n       }\n     }\n  }\n  if (n == 0)  /* did it find given character? */\n    lua_pushinteger(L, posi + 1);\n  else  /* no such character */\n    lua_pushnil(L);\n  return 1;\n}\n\n\nstatic int iter_aux (lua_State *L) {\n  size_t len;\n  const char *s = luaL_checklstring(L, 1, &len);\n  lua_Integer n = lua_tointeger(L, 2) - 1;\n  if (n < 0)  /* first iteration? */\n    n = 0;  /* start from here */\n  else if (n < (lua_Integer)len) {\n    n++;  /* skip current byte */\n    while (iscont(s + n)) n++;  /* and its continuations */\n  }\n  if (n >= (lua_Integer)len)\n    return 0;  /* no more codepoints */\n  else {\n    int code;\n    const char *next = utf8_decode(s + n, &code);\n    if (next == NULL || iscont(next))\n      return luaL_error(L, \"invalid UTF-8 code\");\n    lua_pushinteger(L, n + 1);\n    lua_pushinteger(L, code);\n    return 2;\n  }\n}\n\n\nstatic int iter_codes (lua_State *L) {\n  luaL_checkstring(L, 1);\n  lua_pushcfunction(L, iter_aux);\n  lua_pushvalue(L, 1);\n  lua_pushinteger(L, 0);\n  return 3;\n}\n\n\n/* pattern to match a single UTF-8 character */\n#define UTF8PATT\t\"[\\0-\\x7F\\xC2-\\xF4][\\x80-\\xBF]*\"\n\n\nstatic const luaL_Reg funcs[] = {\n  {\"offset\", byteoffset},\n  {\"codepoint\", codepoint},\n  {\"char\", utfchar},\n  {\"len\", utflen},\n  {\"codes\", iter_codes},\n  /* placeholders */\n  {\"charpattern\", NULL},\n  {NULL, NULL}\n};\n\n\nLUAMOD_API int luaopen_utf8 (lua_State *L) {\n  luaL_newlib(L, funcs);\n  lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);\n  lua_setfield(L, -2, \"charpattern\");\n  return 1;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lvm.c",
    "content": "/*\n** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $\n** Lua virtual machine\n** See Copyright Notice in lua.h\n*/\n\n#define lvm_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n#include <float.h>\n#include <limits.h>\n#include <math.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"ldebug.h\"\n#include \"ldo.h\"\n#include \"lfunc.h\"\n#include \"lgc.h\"\n#include \"lobject.h\"\n#include \"lopcodes.h\"\n#include \"lstate.h\"\n#include \"lstring.h\"\n#include \"ltable.h\"\n#include \"ltm.h\"\n#include \"lvm.h\"\n\n\n/* limit for table tag-method chains (to avoid loops) */\n#define MAXTAGLOOP\t2000\n\n\n\n/*\n** 'l_intfitsf' checks whether a given integer can be converted to a\n** float without rounding. Used in comparisons. Left undefined if\n** all integers fit in a float precisely.\n*/\n#if !defined(l_intfitsf)\n\n/* number of bits in the mantissa of a float */\n#define NBM\t\t(l_mathlim(MANT_DIG))\n\n/*\n** Check whether some integers may not fit in a float, that is, whether\n** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).\n** (The shifts are done in parts to avoid shifting by more than the size\n** of an integer. In a worst case, NBM == 113 for long double and\n** sizeof(integer) == 32.)\n*/\n#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \\\n\t>> (NBM - (3 * (NBM / 4))))  >  0\n\n#define l_intfitsf(i)  \\\n  (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))\n\n#endif\n\n#endif\n\n\n\n/*\n** Try to convert a value to a float. The float case is already handled\n** by the macro 'tonumber'.\n*/\nint luaV_tonumber_ (const TValue *obj, lua_Number *n) {\n  TValue v;\n  if (ttisinteger(obj)) {\n    *n = cast_num(ivalue(obj));\n    return 1;\n  }\n  else if (cvt2num(obj) &&  /* string convertible to number? */\n            luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {\n    *n = nvalue(&v);  /* convert result of 'luaO_str2num' to a float */\n    return 1;\n  }\n  else\n    return 0;  /* conversion failed */\n}\n\n\n/*\n** try to convert a value to an integer, rounding according to 'mode':\n** mode == 0: accepts only integral values\n** mode == 1: takes the floor of the number\n** mode == 2: takes the ceil of the number\n*/\nint luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {\n  TValue v;\n again:\n  if (ttisfloat(obj)) {\n    lua_Number n = fltvalue(obj);\n    lua_Number f = l_floor(n);\n    if (n != f) {  /* not an integral value? */\n      if (mode == 0) return 0;  /* fails if mode demands integral value */\n      else if (mode > 1)  /* needs ceil? */\n        f += 1;  /* convert floor to ceil (remember: n != f) */\n    }\n    return lua_numbertointeger(f, p);\n  }\n  else if (ttisinteger(obj)) {\n    *p = ivalue(obj);\n    return 1;\n  }\n  else if (cvt2num(obj) &&\n            luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {\n    obj = &v;\n    goto again;  /* convert result from 'luaO_str2num' to an integer */\n  }\n  return 0;  /* conversion failed */\n}\n\n\n/*\n** Try to convert a 'for' limit to an integer, preserving the\n** semantics of the loop.\n** (The following explanation assumes a non-negative step; it is valid\n** for negative steps mutatis mutandis.)\n** If the limit can be converted to an integer, rounding down, that is\n** it.\n** Otherwise, check whether the limit can be converted to a number.  If\n** the number is too large, it is OK to set the limit as LUA_MAXINTEGER,\n** which means no limit.  If the number is too negative, the loop\n** should not run, because any initial integer value is larger than the\n** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects\n** the extreme case when the initial value is LUA_MININTEGER, in which\n** case the LUA_MININTEGER limit would still run the loop once.\n*/\nstatic int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,\n                     int *stopnow) {\n  *stopnow = 0;  /* usually, let loops run */\n  if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) {  /* not fit in integer? */\n    lua_Number n;  /* try to convert to float */\n    if (!tonumber(obj, &n)) /* cannot convert to float? */\n      return 0;  /* not a number */\n    if (luai_numlt(0, n)) {  /* if true, float is larger than max integer */\n      *p = LUA_MAXINTEGER;\n      if (step < 0) *stopnow = 1;\n    }\n    else {  /* float is smaller than min integer */\n      *p = LUA_MININTEGER;\n      if (step >= 0) *stopnow = 1;\n    }\n  }\n  return 1;\n}\n\n\n/*\n** Finish the table access 'val = t[key]'.\n** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to\n** t[k] entry (which must be nil).\n*/\nvoid luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,\n                      const TValue *slot) {\n  int loop;  /* counter to avoid infinite loops */\n  const TValue *tm;  /* metamethod */\n  for (loop = 0; loop < MAXTAGLOOP; loop++) {\n    if (slot == NULL) {  /* 't' is not a table? */\n      lua_assert(!ttistable(t));\n      tm = luaT_gettmbyobj(L, t, TM_INDEX);\n      if (ttisnil(tm))\n        luaG_typeerror(L, t, \"index\");  /* no metamethod */\n      /* else will try the metamethod */\n    }\n    else {  /* 't' is a table */\n      lua_assert(ttisnil(slot));\n      tm = fasttm(L, hvalue(t)->metatable, TM_INDEX);  /* table's metamethod */\n      if (tm == NULL) {  /* no metamethod? */\n        setnilvalue(val);  /* result is nil */\n        return;\n      }\n      /* else will try the metamethod */\n    }\n    if (ttisfunction(tm)) {  /* is metamethod a function? */\n      luaT_callTM(L, tm, t, key, val, 1);  /* call it */\n      return;\n    }\n    t = tm;  /* else try to access 'tm[key]' */\n    if (luaV_fastget(L,t,key,slot,luaH_get)) {  /* fast track? */\n      setobj2s(L, val, slot);  /* done */\n      return;\n    }\n    /* else repeat (tail call 'luaV_finishget') */\n  }\n  luaG_runerror(L, \"'__index' chain too long; possible loop\");\n}\n\n\n/*\n** Finish a table assignment 't[key] = val'.\n** If 'slot' is NULL, 't' is not a table.  Otherwise, 'slot' points\n** to the entry 't[key]', or to 'luaO_nilobject' if there is no such\n** entry.  (The value at 'slot' must be nil, otherwise 'luaV_fastset'\n** would have done the job.)\n*/\nvoid luaV_finishset (lua_State *L, const TValue *t, TValue *key,\n                     StkId val, const TValue *slot) {\n  int loop;  /* counter to avoid infinite loops */\n  for (loop = 0; loop < MAXTAGLOOP; loop++) {\n    const TValue *tm;  /* '__newindex' metamethod */\n    if (slot != NULL) {  /* is 't' a table? */\n      Table *h = hvalue(t);  /* save 't' table */\n      lua_assert(ttisnil(slot));  /* old value must be nil */\n      tm = fasttm(L, h->metatable, TM_NEWINDEX);  /* get metamethod */\n      if (tm == NULL) {  /* no metamethod? */\n        if (slot == luaO_nilobject)  /* no previous entry? */\n          slot = luaH_newkey(L, h, key);  /* create one */\n        /* no metamethod and (now) there is an entry with given key */\n        setobj2t(L, cast(TValue *, slot), val);  /* set its new value */\n        invalidateTMcache(h);\n        luaC_barrierback(L, h, val);\n        return;\n      }\n      /* else will try the metamethod */\n    }\n    else {  /* not a table; check metamethod */\n      if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))\n        luaG_typeerror(L, t, \"index\");\n    }\n    /* try the metamethod */\n    if (ttisfunction(tm)) {\n      luaT_callTM(L, tm, t, key, val, 0);\n      return;\n    }\n    t = tm;  /* else repeat assignment over 'tm' */\n    if (luaV_fastset(L, t, key, slot, luaH_get, val))\n      return;  /* done */\n    /* else loop */\n  }\n  luaG_runerror(L, \"'__newindex' chain too long; possible loop\");\n}\n\n\n/*\n** Compare two strings 'ls' x 'rs', returning an integer smaller-equal-\n** -larger than zero if 'ls' is smaller-equal-larger than 'rs'.\n** The code is a little tricky because it allows '\\0' in the strings\n** and it uses 'strcoll' (to respect locales) for each segments\n** of the strings.\n*/\nstatic int l_strcmp (const TString *ls, const TString *rs) {\n  const char *l = getstr(ls);\n  size_t ll = tsslen(ls);\n  const char *r = getstr(rs);\n  size_t lr = tsslen(rs);\n  for (;;) {  /* for each segment */\n    int temp = strcoll(l, r);\n    if (temp != 0)  /* not equal? */\n      return temp;  /* done */\n    else {  /* strings are equal up to a '\\0' */\n      size_t len = strlen(l);  /* index of first '\\0' in both strings */\n      if (len == lr)  /* 'rs' is finished? */\n        return (len == ll) ? 0 : 1;  /* check 'ls' */\n      else if (len == ll)  /* 'ls' is finished? */\n        return -1;  /* 'ls' is smaller than 'rs' ('rs' is not finished) */\n      /* both strings longer than 'len'; go on comparing after the '\\0' */\n      len++;\n      l += len; ll -= len; r += len; lr -= len;\n    }\n  }\n}\n\n\n/*\n** Check whether integer 'i' is less than float 'f'. If 'i' has an\n** exact representation as a float ('l_intfitsf'), compare numbers as\n** floats. Otherwise, if 'f' is outside the range for integers, result\n** is trivial. Otherwise, compare them as integers. (When 'i' has no\n** float representation, either 'f' is \"far away\" from 'i' or 'f' has\n** no precision left for a fractional part; either way, how 'f' is\n** truncated is irrelevant.) When 'f' is NaN, comparisons must result\n** in false.\n*/\nstatic int LTintfloat (lua_Integer i, lua_Number f) {\n#if defined(l_intfitsf)\n  if (!l_intfitsf(i)) {\n    if (f >= -cast_num(LUA_MININTEGER))  /* -minint == maxint + 1 */\n      return 1;  /* f >= maxint + 1 > i */\n    else if (f > cast_num(LUA_MININTEGER))  /* minint < f <= maxint ? */\n      return (i < cast(lua_Integer, f));  /* compare them as integers */\n    else  /* f <= minint <= i (or 'f' is NaN)  -->  not(i < f) */\n      return 0;\n  }\n#endif\n  return luai_numlt(cast_num(i), f);  /* compare them as floats */\n}\n\n\n/*\n** Check whether integer 'i' is less than or equal to float 'f'.\n** See comments on previous function.\n*/\nstatic int LEintfloat (lua_Integer i, lua_Number f) {\n#if defined(l_intfitsf)\n  if (!l_intfitsf(i)) {\n    if (f >= -cast_num(LUA_MININTEGER))  /* -minint == maxint + 1 */\n      return 1;  /* f >= maxint + 1 > i */\n    else if (f >= cast_num(LUA_MININTEGER))  /* minint <= f <= maxint ? */\n      return (i <= cast(lua_Integer, f));  /* compare them as integers */\n    else  /* f < minint <= i (or 'f' is NaN)  -->  not(i <= f) */\n      return 0;\n  }\n#endif\n  return luai_numle(cast_num(i), f);  /* compare them as floats */\n}\n\n\n/*\n** Return 'l < r', for numbers.\n*/\nstatic int LTnum (const TValue *l, const TValue *r) {\n  if (ttisinteger(l)) {\n    lua_Integer li = ivalue(l);\n    if (ttisinteger(r))\n      return li < ivalue(r);  /* both are integers */\n    else  /* 'l' is int and 'r' is float */\n      return LTintfloat(li, fltvalue(r));  /* l < r ? */\n  }\n  else {\n    lua_Number lf = fltvalue(l);  /* 'l' must be float */\n    if (ttisfloat(r))\n      return luai_numlt(lf, fltvalue(r));  /* both are float */\n    else if (luai_numisnan(lf))  /* 'r' is int and 'l' is float */\n      return 0;  /* NaN < i is always false */\n    else  /* without NaN, (l < r)  <-->  not(r <= l) */\n      return !LEintfloat(ivalue(r), lf);  /* not (r <= l) ? */\n  }\n}\n\n\n/*\n** Return 'l <= r', for numbers.\n*/\nstatic int LEnum (const TValue *l, const TValue *r) {\n  if (ttisinteger(l)) {\n    lua_Integer li = ivalue(l);\n    if (ttisinteger(r))\n      return li <= ivalue(r);  /* both are integers */\n    else  /* 'l' is int and 'r' is float */\n      return LEintfloat(li, fltvalue(r));  /* l <= r ? */\n  }\n  else {\n    lua_Number lf = fltvalue(l);  /* 'l' must be float */\n    if (ttisfloat(r))\n      return luai_numle(lf, fltvalue(r));  /* both are float */\n    else if (luai_numisnan(lf))  /* 'r' is int and 'l' is float */\n      return 0;  /*  NaN <= i is always false */\n    else  /* without NaN, (l <= r)  <-->  not(r < l) */\n      return !LTintfloat(ivalue(r), lf);  /* not (r < l) ? */\n  }\n}\n\n\n/*\n** Main operation less than; return 'l < r'.\n*/\nint luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {\n  int res;\n  if (ttisnumber(l) && ttisnumber(r))  /* both operands are numbers? */\n    return LTnum(l, r);\n  else if (ttisstring(l) && ttisstring(r))  /* both are strings? */\n    return l_strcmp(tsvalue(l), tsvalue(r)) < 0;\n  else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0)  /* no metamethod? */\n    luaG_ordererror(L, l, r);  /* error */\n  return res;\n}\n\n\n/*\n** Main operation less than or equal to; return 'l <= r'. If it needs\n** a metamethod and there is no '__le', try '__lt', based on\n** l <= r iff !(r < l) (assuming a total order). If the metamethod\n** yields during this substitution, the continuation has to know\n** about it (to negate the result of r<l); bit CIST_LEQ in the call\n** status keeps that information.\n*/\nint luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {\n  int res;\n  if (ttisnumber(l) && ttisnumber(r))  /* both operands are numbers? */\n    return LEnum(l, r);\n  else if (ttisstring(l) && ttisstring(r))  /* both are strings? */\n    return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;\n  else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0)  /* try 'le' */\n    return res;\n  else {  /* try 'lt': */\n    L->ci->callstatus |= CIST_LEQ;  /* mark it is doing 'lt' for 'le' */\n    res = luaT_callorderTM(L, r, l, TM_LT);\n    L->ci->callstatus ^= CIST_LEQ;  /* clear mark */\n    if (res < 0)\n      luaG_ordererror(L, l, r);\n    return !res;  /* result is negated */\n  }\n}\n\n\n/*\n** Main operation for equality of Lua values; return 't1 == t2'.\n** L == NULL means raw equality (no metamethods)\n*/\nint luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {\n  const TValue *tm;\n  if (ttype(t1) != ttype(t2)) {  /* not the same variant? */\n    if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER)\n      return 0;  /* only numbers can be equal with different variants */\n    else {  /* two numbers with different variants */\n      lua_Integer i1, i2;  /* compare them as integers */\n      return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);\n    }\n  }\n  /* values have same type and same variant */\n  switch (ttype(t1)) {\n    case LUA_TNIL: return 1;\n    case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2));\n    case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));\n    case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */\n    case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);\n    case LUA_TLCF: return fvalue(t1) == fvalue(t2);\n    case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));\n    case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));\n    case LUA_TUSERDATA: {\n      if (uvalue(t1) == uvalue(t2)) return 1;\n      else if (L == NULL) return 0;\n      tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);\n      if (tm == NULL)\n        tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);\n      break;  /* will try TM */\n    }\n    case LUA_TTABLE: {\n      if (hvalue(t1) == hvalue(t2)) return 1;\n      else if (L == NULL) return 0;\n      tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);\n      if (tm == NULL)\n        tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);\n      break;  /* will try TM */\n    }\n    default:\n      return gcvalue(t1) == gcvalue(t2);\n  }\n  if (tm == NULL)  /* no TM? */\n    return 0;  /* objects are different */\n  luaT_callTM(L, tm, t1, t2, L->top, 1);  /* call TM */\n  return !l_isfalse(L->top);\n}\n\n\n/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */\n#define tostring(L,o)  \\\n\t(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))\n\n#define isemptystr(o)\t(ttisshrstring(o) && tsvalue(o)->shrlen == 0)\n\n/* copy strings in stack from top - n up to top - 1 to buffer */\nstatic void copy2buff (StkId top, int n, char *buff) {\n  size_t tl = 0;  /* size already copied */\n  do {\n    size_t l = vslen(top - n);  /* length of string being copied */\n    memcpy(buff + tl, svalue(top - n), l * sizeof(char));\n    tl += l;\n  } while (--n > 0);\n}\n\n\n/*\n** Main operation for concatenation: concat 'total' values in the stack,\n** from 'L->top - total' up to 'L->top - 1'.\n*/\nvoid luaV_concat (lua_State *L, int total) {\n  lua_assert(total >= 2);\n  do {\n    StkId top = L->top;\n    int n = 2;  /* number of elements handled in this pass (at least 2) */\n    if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))\n      luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);\n    else if (isemptystr(top - 1))  /* second operand is empty? */\n      cast_void(tostring(L, top - 2));  /* result is first operand */\n    else if (isemptystr(top - 2)) {  /* first operand is an empty string? */\n      setobjs2s(L, top - 2, top - 1);  /* result is second op. */\n    }\n    else {\n      /* at least two non-empty string values; get as many as possible */\n      size_t tl = vslen(top - 1);\n      TString *ts;\n      /* collect total length and number of strings */\n      for (n = 1; n < total && tostring(L, top - n - 1); n++) {\n        size_t l = vslen(top - n - 1);\n        if (l >= (MAX_SIZE/sizeof(char)) - tl)\n          luaG_runerror(L, \"string length overflow\");\n        tl += l;\n      }\n      if (tl <= LUAI_MAXSHORTLEN) {  /* is result a short string? */\n        char buff[LUAI_MAXSHORTLEN];\n        copy2buff(top, n, buff);  /* copy strings to buffer */\n        ts = luaS_newlstr(L, buff, tl);\n      }\n      else {  /* long string; copy strings directly to final result */\n        ts = luaS_createlngstrobj(L, tl);\n        copy2buff(top, n, getstr(ts));\n      }\n      setsvalue2s(L, top - n, ts);  /* create result */\n    }\n    total -= n-1;  /* got 'n' strings to create 1 new */\n    L->top -= n-1;  /* popped 'n' strings and pushed one */\n  } while (total > 1);  /* repeat until only 1 result left */\n}\n\n\n/*\n** Main operation 'ra' = #rb'.\n*/\nvoid luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {\n  const TValue *tm;\n  switch (ttype(rb)) {\n    case LUA_TTABLE: {\n      Table *h = hvalue(rb);\n      tm = fasttm(L, h->metatable, TM_LEN);\n      if (tm) break;  /* metamethod? break switch to call it */\n      setivalue(ra, luaH_getn(h));  /* else primitive len */\n      return;\n    }\n    case LUA_TSHRSTR: {\n      setivalue(ra, tsvalue(rb)->shrlen);\n      return;\n    }\n    case LUA_TLNGSTR: {\n      setivalue(ra, tsvalue(rb)->u.lnglen);\n      return;\n    }\n    default: {  /* try metamethod */\n      tm = luaT_gettmbyobj(L, rb, TM_LEN);\n      if (ttisnil(tm))  /* no metamethod? */\n        luaG_typeerror(L, rb, \"get length of\");\n      break;\n    }\n  }\n  luaT_callTM(L, tm, rb, rb, ra, 1);\n}\n\n\n/*\n** Integer division; return 'm // n', that is, floor(m/n).\n** C division truncates its result (rounds towards zero).\n** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer,\n** otherwise 'floor(q) == trunc(q) - 1'.\n*/\nlua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {\n  if (l_castS2U(n) + 1u <= 1u) {  /* special cases: -1 or 0 */\n    if (n == 0)\n      luaG_runerror(L, \"attempt to divide by zero\");\n    return intop(-, 0, m);   /* n==-1; avoid overflow with 0x80000...//-1 */\n  }\n  else {\n    lua_Integer q = m / n;  /* perform C division */\n    if ((m ^ n) < 0 && m % n != 0)  /* 'm/n' would be negative non-integer? */\n      q -= 1;  /* correct result for different rounding */\n    return q;\n  }\n}\n\n\n/*\n** Integer modulus; return 'm % n'. (Assume that C '%' with\n** negative operands follows C99 behavior. See previous comment\n** about luaV_div.)\n*/\nlua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {\n  if (l_castS2U(n) + 1u <= 1u) {  /* special cases: -1 or 0 */\n    if (n == 0)\n      luaG_runerror(L, \"attempt to perform 'n%%0'\");\n    return 0;   /* m % -1 == 0; avoid overflow with 0x80000...%-1 */\n  }\n  else {\n    lua_Integer r = m % n;\n    if (r != 0 && (m ^ n) < 0)  /* 'm/n' would be non-integer negative? */\n      r += n;  /* correct result for different rounding */\n    return r;\n  }\n}\n\n\n/* number of bits in an integer */\n#define NBITS\tcast_int(sizeof(lua_Integer) * CHAR_BIT)\n\n/*\n** Shift left operation. (Shift right just negates 'y'.)\n*/\nlua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {\n  if (y < 0) {  /* shift right? */\n    if (y <= -NBITS) return 0;\n    else return intop(>>, x, -y);\n  }\n  else {  /* shift left */\n    if (y >= NBITS) return 0;\n    else return intop(<<, x, y);\n  }\n}\n\n\n/*\n** check whether cached closure in prototype 'p' may be reused, that is,\n** whether there is a cached closure with the same upvalues needed by\n** new closure to be created.\n*/\nstatic LClosure *getcached (Proto *p, UpVal **encup, StkId base) {\n  LClosure *c = p->cache;\n  if (c != NULL) {  /* is there a cached closure? */\n    int nup = p->sizeupvalues;\n    Upvaldesc *uv = p->upvalues;\n    int i;\n    for (i = 0; i < nup; i++) {  /* check whether it has right upvalues */\n      TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v;\n      if (c->upvals[i]->v != v)\n        return NULL;  /* wrong upvalue; cannot reuse closure */\n    }\n  }\n  return c;  /* return cached closure (or NULL if no cached closure) */\n}\n\n\n/*\n** create a new Lua closure, push it in the stack, and initialize\n** its upvalues. Note that the closure is not cached if prototype is\n** already black (which means that 'cache' was already cleared by the\n** GC).\n*/\nstatic void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,\n                         StkId ra) {\n  int nup = p->sizeupvalues;\n  Upvaldesc *uv = p->upvalues;\n  int i;\n  LClosure *ncl = luaF_newLclosure(L, nup);\n  ncl->p = p;\n  setclLvalue(L, ra, ncl);  /* anchor new closure in stack */\n  for (i = 0; i < nup; i++) {  /* fill in its upvalues */\n    if (uv[i].instack)  /* upvalue refers to local variable? */\n      ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx);\n    else  /* get upvalue from enclosing function */\n      ncl->upvals[i] = encup[uv[i].idx];\n    ncl->upvals[i]->refcount++;\n    /* new closure is white, so we do not need a barrier here */\n  }\n  if (!isblack(p))  /* cache will not break GC invariant? */\n    p->cache = ncl;  /* save it on cache for reuse */\n}\n\n\n/*\n** finish execution of an opcode interrupted by an yield\n*/\nvoid luaV_finishOp (lua_State *L) {\n  CallInfo *ci = L->ci;\n  StkId base = ci->u.l.base;\n  Instruction inst = *(ci->u.l.savedpc - 1);  /* interrupted instruction */\n  OpCode op = GET_OPCODE(inst);\n  switch (op) {  /* finish its execution */\n    case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV:\n    case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR:\n    case OP_MOD: case OP_POW:\n    case OP_UNM: case OP_BNOT: case OP_LEN:\n    case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: {\n      setobjs2s(L, base + GETARG_A(inst), --L->top);\n      break;\n    }\n    case OP_LE: case OP_LT: case OP_EQ: {\n      int res = !l_isfalse(L->top - 1);\n      L->top--;\n      if (ci->callstatus & CIST_LEQ) {  /* \"<=\" using \"<\" instead? */\n        lua_assert(op == OP_LE);\n        ci->callstatus ^= CIST_LEQ;  /* clear mark */\n        res = !res;  /* negate result */\n      }\n      lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);\n      if (res != GETARG_A(inst))  /* condition failed? */\n        ci->u.l.savedpc++;  /* skip jump instruction */\n      break;\n    }\n    case OP_CONCAT: {\n      StkId top = L->top - 1;  /* top when 'luaT_trybinTM' was called */\n      int b = GETARG_B(inst);      /* first element to concatenate */\n      int total = cast_int(top - 1 - (base + b));  /* yet to concatenate */\n      setobj2s(L, top - 2, top);  /* put TM result in proper position */\n      if (total > 1) {  /* are there elements to concat? */\n        L->top = top - 1;  /* top is one after last element (at top-2) */\n        luaV_concat(L, total);  /* concat them (may yield again) */\n      }\n      /* move final result to final position */\n      setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1);\n      L->top = ci->top;  /* restore top */\n      break;\n    }\n    case OP_TFORCALL: {\n      lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP);\n      L->top = ci->top;  /* correct top */\n      break;\n    }\n    case OP_CALL: {\n      if (GETARG_C(inst) - 1 >= 0)  /* nresults >= 0? */\n        L->top = ci->top;  /* adjust results */\n      break;\n    }\n    case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:\n      break;\n    default: lua_assert(0);\n  }\n}\n\n\n\n\n/*\n** {==================================================================\n** Function 'luaV_execute': main interpreter loop\n** ===================================================================\n*/\n\n\n/*\n** some macros for common tasks in 'luaV_execute'\n*/\n\n\n#define RA(i)\t(base+GETARG_A(i))\n#define RB(i)\tcheck_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))\n#define RC(i)\tcheck_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))\n#define RKB(i)\tcheck_exp(getBMode(GET_OPCODE(i)) == OpArgK, \\\n\tISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))\n#define RKC(i)\tcheck_exp(getCMode(GET_OPCODE(i)) == OpArgK, \\\n\tISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))\n\n\n/* execute a jump instruction */\n#define dojump(ci,i,e) \\\n  { int a = GETARG_A(i); \\\n    if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \\\n    ci->u.l.savedpc += GETARG_sBx(i) + e; }\n\n/* for test instructions, execute the jump instruction that follows it */\n#define donextjump(ci)\t{ i = *ci->u.l.savedpc; dojump(ci, i, 1); }\n\n\n#define Protect(x)\t{ {x;}; base = ci->u.l.base; }\n\n#define checkGC(L,c)  \\\n\t{ luaC_condGC(L, L->top = (c),  /* limit of live values */ \\\n                         Protect(L->top = ci->top));  /* restore top */ \\\n           luai_threadyield(L); }\n\n\n/* fetch an instruction and prepare its execution */\n#define vmfetch()\t{ \\\n  i = *(ci->u.l.savedpc++); \\\n  if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \\\n    Protect(luaG_traceexec(L)); \\\n  ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \\\n  lua_assert(base == ci->u.l.base); \\\n  lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \\\n}\n\n#define vmdispatch(o)\tswitch(o)\n#define vmcase(l)\tcase l:\n#define vmbreak\t\tbreak\n\n\n/*\n** copy of 'luaV_gettable', but protecting the call to potential\n** metamethod (which can reallocate the stack)\n*/\n#define gettableProtected(L,t,k,v)  { const TValue *slot; \\\n  if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \\\n  else Protect(luaV_finishget(L,t,k,v,slot)); }\n\n\n/* same for 'luaV_settable' */\n#define settableProtected(L,t,k,v) { const TValue *slot; \\\n  if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \\\n    Protect(luaV_finishset(L,t,k,v,slot)); }\n\n\n\nvoid luaV_execute (lua_State *L) {\n  CallInfo *ci = L->ci;\n  LClosure *cl;\n  TValue *k;\n  StkId base;\n  ci->callstatus |= CIST_FRESH;  /* fresh invocation of 'luaV_execute\" */\n newframe:  /* reentry point when frame changes (call/return) */\n  lua_assert(ci == L->ci);\n  cl = clLvalue(ci->func);  /* local reference to function's closure */\n  k = cl->p->k;  /* local reference to function's constant table */\n  base = ci->u.l.base;  /* local copy of function's base */\n  /* main loop of interpreter */\n  for (;;) {\n    Instruction i;\n    StkId ra;\n    vmfetch();\n    vmdispatch (GET_OPCODE(i)) {\n      vmcase(OP_MOVE) {\n        setobjs2s(L, ra, RB(i));\n        vmbreak;\n      }\n      vmcase(OP_LOADK) {\n        TValue *rb = k + GETARG_Bx(i);\n        setobj2s(L, ra, rb);\n        vmbreak;\n      }\n      vmcase(OP_LOADKX) {\n        TValue *rb;\n        lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);\n        rb = k + GETARG_Ax(*ci->u.l.savedpc++);\n        setobj2s(L, ra, rb);\n        vmbreak;\n      }\n      vmcase(OP_LOADBOOL) {\n        setbvalue(ra, GETARG_B(i));\n        if (GETARG_C(i)) ci->u.l.savedpc++;  /* skip next instruction (if C) */\n        vmbreak;\n      }\n      vmcase(OP_LOADNIL) {\n        int b = GETARG_B(i);\n        do {\n          setnilvalue(ra++);\n        } while (b--);\n        vmbreak;\n      }\n      vmcase(OP_GETUPVAL) {\n        int b = GETARG_B(i);\n        setobj2s(L, ra, cl->upvals[b]->v);\n        vmbreak;\n      }\n      vmcase(OP_GETTABUP) {\n        TValue *upval = cl->upvals[GETARG_B(i)]->v;\n        TValue *rc = RKC(i);\n        gettableProtected(L, upval, rc, ra);\n        vmbreak;\n      }\n      vmcase(OP_GETTABLE) {\n        StkId rb = RB(i);\n        TValue *rc = RKC(i);\n        gettableProtected(L, rb, rc, ra);\n        vmbreak;\n      }\n      vmcase(OP_SETTABUP) {\n        TValue *upval = cl->upvals[GETARG_A(i)]->v;\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        settableProtected(L, upval, rb, rc);\n        vmbreak;\n      }\n      vmcase(OP_SETUPVAL) {\n        UpVal *uv = cl->upvals[GETARG_B(i)];\n        setobj(L, uv->v, ra);\n        luaC_upvalbarrier(L, uv);\n        vmbreak;\n      }\n      vmcase(OP_SETTABLE) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        settableProtected(L, ra, rb, rc);\n        vmbreak;\n      }\n      vmcase(OP_NEWTABLE) {\n        int b = GETARG_B(i);\n        int c = GETARG_C(i);\n        Table *t = luaH_new(L);\n        sethvalue(L, ra, t);\n        if (b != 0 || c != 0)\n          luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));\n        checkGC(L, ra + 1);\n        vmbreak;\n      }\n      vmcase(OP_SELF) {\n        const TValue *aux;\n        StkId rb = RB(i);\n        TValue *rc = RKC(i);\n        TString *key = tsvalue(rc);  /* key must be a string */\n        setobjs2s(L, ra + 1, rb);\n        if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {\n          setobj2s(L, ra, aux);\n        }\n        else Protect(luaV_finishget(L, rb, rc, ra, aux));\n        vmbreak;\n      }\n      vmcase(OP_ADD) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (ttisinteger(rb) && ttisinteger(rc)) {\n          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);\n          setivalue(ra, intop(+, ib, ic));\n        }\n        else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          setfltvalue(ra, luai_numadd(L, nb, nc));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }\n        vmbreak;\n      }\n      vmcase(OP_SUB) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (ttisinteger(rb) && ttisinteger(rc)) {\n          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);\n          setivalue(ra, intop(-, ib, ic));\n        }\n        else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          setfltvalue(ra, luai_numsub(L, nb, nc));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); }\n        vmbreak;\n      }\n      vmcase(OP_MUL) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (ttisinteger(rb) && ttisinteger(rc)) {\n          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);\n          setivalue(ra, intop(*, ib, ic));\n        }\n        else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          setfltvalue(ra, luai_nummul(L, nb, nc));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); }\n        vmbreak;\n      }\n      vmcase(OP_DIV) {  /* float division (always with floats) */\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          setfltvalue(ra, luai_numdiv(L, nb, nc));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }\n        vmbreak;\n      }\n      vmcase(OP_BAND) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Integer ib; lua_Integer ic;\n        if (tointeger(rb, &ib) && tointeger(rc, &ic)) {\n          setivalue(ra, intop(&, ib, ic));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); }\n        vmbreak;\n      }\n      vmcase(OP_BOR) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Integer ib; lua_Integer ic;\n        if (tointeger(rb, &ib) && tointeger(rc, &ic)) {\n          setivalue(ra, intop(|, ib, ic));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); }\n        vmbreak;\n      }\n      vmcase(OP_BXOR) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Integer ib; lua_Integer ic;\n        if (tointeger(rb, &ib) && tointeger(rc, &ic)) {\n          setivalue(ra, intop(^, ib, ic));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); }\n        vmbreak;\n      }\n      vmcase(OP_SHL) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Integer ib; lua_Integer ic;\n        if (tointeger(rb, &ib) && tointeger(rc, &ic)) {\n          setivalue(ra, luaV_shiftl(ib, ic));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); }\n        vmbreak;\n      }\n      vmcase(OP_SHR) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Integer ib; lua_Integer ic;\n        if (tointeger(rb, &ib) && tointeger(rc, &ic)) {\n          setivalue(ra, luaV_shiftl(ib, -ic));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); }\n        vmbreak;\n      }\n      vmcase(OP_MOD) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (ttisinteger(rb) && ttisinteger(rc)) {\n          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);\n          setivalue(ra, luaV_mod(L, ib, ic));\n        }\n        else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          lua_Number m;\n          luai_nummod(L, nb, nc, m);\n          setfltvalue(ra, m);\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); }\n        vmbreak;\n      }\n      vmcase(OP_IDIV) {  /* floor division */\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (ttisinteger(rb) && ttisinteger(rc)) {\n          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);\n          setivalue(ra, luaV_div(L, ib, ic));\n        }\n        else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          setfltvalue(ra, luai_numidiv(L, nb, nc));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }\n        vmbreak;\n      }\n      vmcase(OP_POW) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        lua_Number nb; lua_Number nc;\n        if (tonumber(rb, &nb) && tonumber(rc, &nc)) {\n          setfltvalue(ra, luai_numpow(L, nb, nc));\n        }\n        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); }\n        vmbreak;\n      }\n      vmcase(OP_UNM) {\n        TValue *rb = RB(i);\n        lua_Number nb;\n        if (ttisinteger(rb)) {\n          lua_Integer ib = ivalue(rb);\n          setivalue(ra, intop(-, 0, ib));\n        }\n        else if (tonumber(rb, &nb)) {\n          setfltvalue(ra, luai_numunm(L, nb));\n        }\n        else {\n          Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));\n        }\n        vmbreak;\n      }\n      vmcase(OP_BNOT) {\n        TValue *rb = RB(i);\n        lua_Integer ib;\n        if (tointeger(rb, &ib)) {\n          setivalue(ra, intop(^, ~l_castS2U(0), ib));\n        }\n        else {\n          Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));\n        }\n        vmbreak;\n      }\n      vmcase(OP_NOT) {\n        TValue *rb = RB(i);\n        int res = l_isfalse(rb);  /* next assignment may change this value */\n        setbvalue(ra, res);\n        vmbreak;\n      }\n      vmcase(OP_LEN) {\n        Protect(luaV_objlen(L, ra, RB(i)));\n        vmbreak;\n      }\n      vmcase(OP_CONCAT) {\n        int b = GETARG_B(i);\n        int c = GETARG_C(i);\n        StkId rb;\n        L->top = base + c + 1;  /* mark the end of concat operands */\n        Protect(luaV_concat(L, c - b + 1));\n        ra = RA(i);  /* 'luaV_concat' may invoke TMs and move the stack */\n        rb = base + b;\n        setobjs2s(L, ra, rb);\n        checkGC(L, (ra >= rb ? ra + 1 : rb));\n        L->top = ci->top;  /* restore top */\n        vmbreak;\n      }\n      vmcase(OP_JMP) {\n        dojump(ci, i, 0);\n        vmbreak;\n      }\n      vmcase(OP_EQ) {\n        TValue *rb = RKB(i);\n        TValue *rc = RKC(i);\n        Protect(\n          if (luaV_equalobj(L, rb, rc) != GETARG_A(i))\n            ci->u.l.savedpc++;\n          else\n            donextjump(ci);\n        )\n        vmbreak;\n      }\n      vmcase(OP_LT) {\n        Protect(\n          if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i))\n            ci->u.l.savedpc++;\n          else\n            donextjump(ci);\n        )\n        vmbreak;\n      }\n      vmcase(OP_LE) {\n        Protect(\n          if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i))\n            ci->u.l.savedpc++;\n          else\n            donextjump(ci);\n        )\n        vmbreak;\n      }\n      vmcase(OP_TEST) {\n        if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))\n            ci->u.l.savedpc++;\n          else\n          donextjump(ci);\n        vmbreak;\n      }\n      vmcase(OP_TESTSET) {\n        TValue *rb = RB(i);\n        if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))\n          ci->u.l.savedpc++;\n        else {\n          setobjs2s(L, ra, rb);\n          donextjump(ci);\n        }\n        vmbreak;\n      }\n      vmcase(OP_CALL) {\n        int b = GETARG_B(i);\n        int nresults = GETARG_C(i) - 1;\n        if (b != 0) L->top = ra+b;  /* else previous instruction set top */\n        if (luaD_precall(L, ra, nresults)) {  /* C function? */\n          if (nresults >= 0)\n            L->top = ci->top;  /* adjust results */\n          Protect((void)0);  /* update 'base' */\n        }\n        else {  /* Lua function */\n          ci = L->ci;\n          goto newframe;  /* restart luaV_execute over new Lua function */\n        }\n        vmbreak;\n      }\n      vmcase(OP_TAILCALL) {\n        int b = GETARG_B(i);\n        if (b != 0) L->top = ra+b;  /* else previous instruction set top */\n        lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);\n        if (luaD_precall(L, ra, LUA_MULTRET)) {  /* C function? */\n          Protect((void)0);  /* update 'base' */\n        }\n        else {\n          /* tail call: put called frame (n) in place of caller one (o) */\n          CallInfo *nci = L->ci;  /* called frame */\n          CallInfo *oci = nci->previous;  /* caller frame */\n          StkId nfunc = nci->func;  /* called function */\n          StkId ofunc = oci->func;  /* caller function */\n          /* last stack slot filled by 'precall' */\n          StkId lim = nci->u.l.base + getproto(nfunc)->numparams;\n          int aux;\n          /* close all upvalues from previous call */\n          if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);\n          /* move new frame into old one */\n          for (aux = 0; nfunc + aux < lim; aux++)\n            setobjs2s(L, ofunc + aux, nfunc + aux);\n          oci->u.l.base = ofunc + (nci->u.l.base - nfunc);  /* correct base */\n          oci->top = L->top = ofunc + (L->top - nfunc);  /* correct top */\n          oci->u.l.savedpc = nci->u.l.savedpc;\n          oci->callstatus |= CIST_TAIL;  /* function was tail called */\n          ci = L->ci = oci;  /* remove new frame */\n          lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);\n          goto newframe;  /* restart luaV_execute over new Lua function */\n        }\n        vmbreak;\n      }\n      vmcase(OP_RETURN) {\n        int b = GETARG_B(i);\n        if (cl->p->sizep > 0) luaF_close(L, base);\n        b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));\n        if (ci->callstatus & CIST_FRESH)  /* local 'ci' still from callee */\n          return;  /* external invocation: return */\n        else {  /* invocation via reentry: continue execution */\n          ci = L->ci;\n          if (b) L->top = ci->top;\n          lua_assert(isLua(ci));\n          lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);\n          goto newframe;  /* restart luaV_execute over new Lua function */\n        }\n      }\n      vmcase(OP_FORLOOP) {\n        if (ttisinteger(ra)) {  /* integer loop? */\n          lua_Integer step = ivalue(ra + 2);\n          lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */\n          lua_Integer limit = ivalue(ra + 1);\n          if ((0 < step) ? (idx <= limit) : (limit <= idx)) {\n            ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */\n            chgivalue(ra, idx);  /* update internal index... */\n            setivalue(ra + 3, idx);  /* ...and external index */\n          }\n        }\n        else {  /* floating loop */\n          lua_Number step = fltvalue(ra + 2);\n          lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */\n          lua_Number limit = fltvalue(ra + 1);\n          if (luai_numlt(0, step) ? luai_numle(idx, limit)\n                                  : luai_numle(limit, idx)) {\n            ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */\n            chgfltvalue(ra, idx);  /* update internal index... */\n            setfltvalue(ra + 3, idx);  /* ...and external index */\n          }\n        }\n        vmbreak;\n      }\n      vmcase(OP_FORPREP) {\n        TValue *init = ra;\n        TValue *plimit = ra + 1;\n        TValue *pstep = ra + 2;\n        lua_Integer ilimit;\n        int stopnow;\n        if (ttisinteger(init) && ttisinteger(pstep) &&\n            forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {\n          /* all values are integer */\n          lua_Integer initv = (stopnow ? 0 : ivalue(init));\n          setivalue(plimit, ilimit);\n          setivalue(init, intop(-, initv, ivalue(pstep)));\n        }\n        else {  /* try making all values floats */\n          lua_Number ninit; lua_Number nlimit; lua_Number nstep;\n          if (!tonumber(plimit, &nlimit))\n            luaG_runerror(L, \"'for' limit must be a number\");\n          setfltvalue(plimit, nlimit);\n          if (!tonumber(pstep, &nstep))\n            luaG_runerror(L, \"'for' step must be a number\");\n          setfltvalue(pstep, nstep);\n          if (!tonumber(init, &ninit))\n            luaG_runerror(L, \"'for' initial value must be a number\");\n          setfltvalue(init, luai_numsub(L, ninit, nstep));\n        }\n        ci->u.l.savedpc += GETARG_sBx(i);\n        vmbreak;\n      }\n      vmcase(OP_TFORCALL) {\n        StkId cb = ra + 3;  /* call base */\n        setobjs2s(L, cb+2, ra+2);\n        setobjs2s(L, cb+1, ra+1);\n        setobjs2s(L, cb, ra);\n        L->top = cb + 3;  /* func. + 2 args (state and index) */\n        Protect(luaD_call(L, cb, GETARG_C(i)));\n        L->top = ci->top;\n        i = *(ci->u.l.savedpc++);  /* go to next instruction */\n        ra = RA(i);\n        lua_assert(GET_OPCODE(i) == OP_TFORLOOP);\n        goto l_tforloop;\n      }\n      vmcase(OP_TFORLOOP) {\n        l_tforloop:\n        if (!ttisnil(ra + 1)) {  /* continue loop? */\n          setobjs2s(L, ra, ra + 1);  /* save control variable */\n           ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */\n        }\n        vmbreak;\n      }\n      vmcase(OP_SETLIST) {\n        int n = GETARG_B(i);\n        int c = GETARG_C(i);\n        unsigned int last;\n        Table *h;\n        if (n == 0) n = cast_int(L->top - ra) - 1;\n        if (c == 0) {\n          lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);\n          c = GETARG_Ax(*ci->u.l.savedpc++);\n        }\n        h = hvalue(ra);\n        last = ((c-1)*LFIELDS_PER_FLUSH) + n;\n        if (last > h->sizearray)  /* needs more space? */\n          luaH_resizearray(L, h, last);  /* preallocate it at once */\n        for (; n > 0; n--) {\n          TValue *val = ra+n;\n          luaH_setint(L, h, last--, val);\n          luaC_barrierback(L, h, val);\n        }\n        L->top = ci->top;  /* correct top (in case of previous open call) */\n        vmbreak;\n      }\n      vmcase(OP_CLOSURE) {\n        Proto *p = cl->p->p[GETARG_Bx(i)];\n        LClosure *ncl = getcached(p, cl->upvals, base);  /* cached closure */\n        if (ncl == NULL)  /* no match? */\n          pushclosure(L, p, cl->upvals, base, ra);  /* create a new one */\n        else\n          setclLvalue(L, ra, ncl);  /* push cashed closure */\n        checkGC(L, ra + 1);\n        vmbreak;\n      }\n      vmcase(OP_VARARG) {\n        int b = GETARG_B(i) - 1;  /* required results */\n        int j;\n        int n = cast_int(base - ci->func) - cl->p->numparams - 1;\n        if (n < 0)  /* less arguments than parameters? */\n          n = 0;  /* no vararg arguments */\n        if (b < 0) {  /* B == 0? */\n          b = n;  /* get all var. arguments */\n          Protect(luaD_checkstack(L, n));\n          ra = RA(i);  /* previous call may change the stack */\n          L->top = ra + n;\n        }\n        for (j = 0; j < b && j < n; j++)\n          setobjs2s(L, ra + j, base - n + j);\n        for (; j < b; j++)  /* complete required results with nil */\n          setnilvalue(ra + j);\n        vmbreak;\n      }\n      vmcase(OP_EXTRAARG) {\n        lua_assert(0);\n        vmbreak;\n      }\n    }\n  }\n}\n\n/* }================================================================== */\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lvm.h",
    "content": "/*\n** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $\n** Lua virtual machine\n** See Copyright Notice in lua.h\n*/\n\n#ifndef lvm_h\n#define lvm_h\n\n\n#include \"ldo.h\"\n#include \"lobject.h\"\n#include \"ltm.h\"\n\n\n#if !defined(LUA_NOCVTN2S)\n#define cvt2str(o)\tttisnumber(o)\n#else\n#define cvt2str(o)\t0\t/* no conversion from numbers to strings */\n#endif\n\n\n#if !defined(LUA_NOCVTS2N)\n#define cvt2num(o)\tttisstring(o)\n#else\n#define cvt2num(o)\t0\t/* no conversion from strings to numbers */\n#endif\n\n\n/*\n** You can define LUA_FLOORN2I if you want to convert floats to integers\n** by flooring them (instead of raising an error if they are not\n** integral values)\n*/\n#if !defined(LUA_FLOORN2I)\n#define LUA_FLOORN2I\t\t0\n#endif\n\n\n#define tonumber(o,n) \\\n\t(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))\n\n#define tointeger(o,i) \\\n    (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))\n\n#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))\n\n#define luaV_rawequalobj(t1,t2)\t\tluaV_equalobj(NULL,t1,t2)\n\n\n/*\n** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,\n** return 1 with 'slot' pointing to 't[k]' (final result).  Otherwise,\n** return 0 (meaning it will have to check metamethod) with 'slot'\n** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).\n** 'f' is the raw get function to use.\n*/\n#define luaV_fastget(L,t,k,slot,f) \\\n  (!ttistable(t)  \\\n   ? (slot = NULL, 0)  /* not a table; 'slot' is NULL and result is 0 */  \\\n   : (slot = f(hvalue(t), k),  /* else, do raw access */  \\\n      !ttisnil(slot)))  /* result not nil? */\n\n/*\n** standard implementation for 'gettable'\n*/\n#define luaV_gettable(L,t,k,v) { const TValue *slot; \\\n  if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \\\n  else luaV_finishget(L,t,k,v,slot); }\n\n\n/*\n** Fast track for set table. If 't' is a table and 't[k]' is not nil,\n** call GC barrier, do a raw 't[k]=v', and return true; otherwise,\n** return false with 'slot' equal to NULL (if 't' is not a table) or\n** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro\n** returns true, there is no need to 'invalidateTMcache', because the\n** call is not creating a new entry.\n*/\n#define luaV_fastset(L,t,k,slot,f,v) \\\n  (!ttistable(t) \\\n   ? (slot = NULL, 0) \\\n   : (slot = f(hvalue(t), k), \\\n     ttisnil(slot) ? 0 \\\n     : (luaC_barrierback(L, hvalue(t), v), \\\n        setobj2t(L, cast(TValue *,slot), v), \\\n        1)))\n\n\n#define luaV_settable(L,t,k,v) { const TValue *slot; \\\n  if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \\\n    luaV_finishset(L,t,k,v,slot); }\n\n\n\nLUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);\nLUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);\nLUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);\nLUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);\nLUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);\nLUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,\n                               StkId val, const TValue *slot);\nLUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,\n                               StkId val, const TValue *slot);\nLUAI_FUNC void luaV_finishOp (lua_State *L);\nLUAI_FUNC void luaV_execute (lua_State *L);\nLUAI_FUNC void luaV_concat (lua_State *L, int total);\nLUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);\nLUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);\nLUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);\nLUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);\n\n#endif\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lzio.c",
    "content": "/*\n** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $\n** Buffered streams\n** See Copyright Notice in lua.h\n*/\n\n#define lzio_c\n#define LUA_CORE\n\n#include \"lprefix.h\"\n\n\n#include <string.h>\n\n#include \"lua.h\"\n\n#include \"llimits.h\"\n#include \"lmem.h\"\n#include \"lstate.h\"\n#include \"lzio.h\"\n\n\nint luaZ_fill (ZIO *z) {\n  size_t size;\n  lua_State *L = z->L;\n  const char *buff;\n  lua_unlock(L);\n  buff = z->reader(L, z->data, &size);\n  lua_lock(L);\n  if (buff == NULL || size == 0)\n    return EOZ;\n  z->n = size - 1;  /* discount char being returned */\n  z->p = buff;\n  return cast_uchar(*(z->p++));\n}\n\n\nvoid luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {\n  z->L = L;\n  z->reader = reader;\n  z->data = data;\n  z->n = 0;\n  z->p = NULL;\n}\n\n\n/* --------------------------------------------------------------- read --- */\nsize_t luaZ_read (ZIO *z, void *b, size_t n) {\n  while (n) {\n    size_t m;\n    if (z->n == 0) {  /* no bytes in buffer? */\n      if (luaZ_fill(z) == EOZ)  /* try to read more */\n        return n;  /* no more input; return number of missing bytes */\n      else {\n        z->n++;  /* luaZ_fill consumed first byte; put it back */\n        z->p--;\n      }\n    }\n    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */\n    memcpy(b, z->p, m);\n    z->n -= m;\n    z->p += m;\n    b = (char *)b + m;\n    n -= m;\n  }\n  return 0;\n}\n\n"
  },
  {
    "path": "Tests/ApiExplorer/lua/src/lzio.h",
    "content": "/*\n** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $\n** Buffered streams\n** See Copyright Notice in lua.h\n*/\n\n\n#ifndef lzio_h\n#define lzio_h\n\n#include \"lua.h\"\n\n#include \"lmem.h\"\n\n\n#define EOZ\t(-1)\t\t\t/* end of stream */\n\ntypedef struct Zio ZIO;\n\n#define zgetc(z)  (((z)->n--)>0 ?  cast_uchar(*(z)->p++) : luaZ_fill(z))\n\n\ntypedef struct Mbuffer {\n  char *buffer;\n  size_t n;\n  size_t buffsize;\n} Mbuffer;\n\n#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)\n\n#define luaZ_buffer(buff)\t((buff)->buffer)\n#define luaZ_sizebuffer(buff)\t((buff)->buffsize)\n#define luaZ_bufflen(buff)\t((buff)->n)\n\n#define luaZ_buffremove(buff,i)\t((buff)->n -= (i))\n#define luaZ_resetbuffer(buff) ((buff)->n = 0)\n\n\n#define luaZ_resizebuffer(L, buff, size) \\\n\t((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \\\n\t\t\t\t(buff)->buffsize, size), \\\n\t(buff)->buffsize = size)\n\n#define luaZ_freebuffer(L, buff)\tluaZ_resizebuffer(L, buff, 0)\n\n\nLUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,\n                                        void *data);\nLUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n);\t/* read next n bytes */\n\n\n\n/* --------- Private Part ------------------ */\n\nstruct Zio {\n  size_t n;\t\t\t/* bytes still unread */\n  const char *p;\t\t/* current position in buffer */\n  lua_Reader reader;\t\t/* reader function */\n  void *data;\t\t\t/* additional data */\n  lua_State *L;\t\t\t/* Lua state (for reader) */\n};\n\n\nLUAI_FUNC int luaZ_fill (ZIO *z);\n\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/.gitignore",
    "content": "Kits/DirectXTK12/Src/Shaders/Compiled/"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.143.GDK.Src.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Desktop.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Desktop.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Desktop.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <RootNamespace>APIRunner_GDK</RootNamespace>\n    <ProjectGuid>{46F31A54-4C74-41A8-B294-26B5689E51EF}</ProjectGuid>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <Keyword>Win32Proj</Keyword>\n    <!-- - - - -->\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <TargetRuntime>Native</TargetRuntime>\n    <GDKExtLibNames>Xbox.Services.API.C</GDKExtLibNames>\n    <PreferredToolArchitecture>x64</PreferredToolArchitecture>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Condition=\"Exists($(ATGBuildProps))\" Project=\"$(ATGBuildProps)\" />\n  <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\Build\\xsapi.gdk.bwoi.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v143</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n    <Import Project=\"..\\..\\APIExplorer\\APIExplorer.Shared.vcxitems\" Label=\"Shared\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <!-- XSAPI: add between these lines -->\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\DirectXTK12\\Inc;Kits\\ATGTK;Kits\\ATGTelemetry\\Gsdk;$(ProjectDir)..\\..\\APIExplorer\\lua\\src;$(ProjectDir)..\\..\\APIExplorer\\Shared;$(ProjectDir)..\\..\\APIExplorer\\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>SAMPLE_BUILD_WITH_CPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Platform)'=='Gaming.Desktop.x64'\">SAMPLE_BUILD_FOR_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <PropertyGroup>\n    <XblTraceBuildInfo>true</XblTraceBuildInfo>\n  </PropertyGroup>\n  <PropertyGroup>\n    <XsapiPropsFile>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), xsapi.staticlib.props))\\xsapi.staticlib.props</XsapiPropsFile>\n    <XsapiEnableCpp>1</XsapiEnableCpp>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiPropsFile)\" Condition=\"Exists($(XsapiPropsFile))\" />\n  <PropertyGroup>\n    <XsapiPathsFile>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), xsapi.paths.props))\\xsapi.paths.props</XsapiPathsFile>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiPathsFile)\" Condition=\"Exists($(XsapiPathsFile))\" />\n  <!-- XSAPI: add between these lines -->\n  <!-- BEGIN Shared pre-build / post-build events -->\n  <ItemDefinitionGroup>\n    <PreBuildEvent>\n      <Command>copy /Y \"$(ProjectDir)APIRunnerSrc143-MicrosoftGame.Config\" \"$(ProjectDir)MicrosoftGame.Config\"</Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>xcopy /Y /I /E \"$(ProjectDir)Assets\\*.*\" \"$(TargetDir)Assets\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\*.*\" \"$(TargetDir)Media\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Fonts\\*.*\" \"$(TargetDir)\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Textures\\*.*\" \"$(TargetDir)\"</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <!-- END Shared pre-build / post-build events -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <ShowIncludes>true</ShowIncludes>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"APIRunner.GDK.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\ControllerFont.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\CSVReader.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\d3dx12.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\SampleGUI.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\TextConsole.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\UITwist.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"StepTimer.h\" />\n    <ClInclude Include=\"DeviceResources.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\LiveInfoHUD.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\LiveResources.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\ATGColors.h\" />\n    <ClInclude Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\Json.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\StringUtil.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\FindMedia.h\" />\n    <ClInclude Include=\"UIConstants.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\APIExplorer\\Shared\\Win\\pal.cpp\" />\n    <ClCompile Include=\"APIRunner.GDK.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\SampleGUI.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\TextConsole.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\UITwist.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\LiveInfoHUD.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\LiveResources.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\StringUtil.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <MGCCompile Include=\"MicrosoftGame.Config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\">\n      <Project>{052c4858-c76f-4cea-8a1a-e8e5559e67c2}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Media\\Textures\\GamerPic.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Logo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SmallLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SplashScreen.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\StoreLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Mounted.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Owned.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Unmounted.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SampleUI.csv\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.143.GDK.Src.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Common\">\n      <UniqueIdentifier>916b6ff9-882e-4cf3-93d5-bea41c3e7cd0</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Assets\">\n      <UniqueIdentifier>0c10bab7-ebd0-49b3-89a5-df53a9e36cf4</UniqueIdentifier>\n      <Extensions>ico;cur;bmp;dds;dlg;fbx;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"ATG Tool Kit\">\n      <UniqueIdentifier>fa3bbbb4-fde4-4785-907e-fbb24dde6491</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Xbox Live Tool Kit\">\n      <UniqueIdentifier>83010d7a-d0f5-4911-9741-7529fae5301c</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"APIRunner.GDK.h\" />\n    <ClInclude Include=\"StepTimer.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DeviceResources.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\ATGColors.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\d3dx12.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\FindMedia.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\StringUtil.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\json.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"UIConstants.h\" />\n    <ClInclude Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\ControllerFont.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\CSVReader.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\SampleGUI.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\UITwist.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\LiveInfoHUD.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\LiveResources.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\TextConsole.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"pch.cpp\" />\n    <ClCompile Include=\"APIRunner.GDK.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\">\n      <Filter>Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\StringUtil.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\APIExplorer\\Shared\\Win\\pal.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\SampleGUI.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\UITwist.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\LiveInfoHUD.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\LiveResources.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\TextConsole.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <MGCCompile Include=\"MicrosoftGame.Config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Media\\Textures\\GamerPic.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Logo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SmallLogo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SplashScreen.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\StoreLogo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Mounted.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Owned.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Unmounted.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SampleUI.csv\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.GDK.Bin.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Desktop.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Desktop.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Desktop.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <RootNamespace>APIRunner_GDK</RootNamespace>\n    <ProjectGuid>{46F31A54-4C74-41A8-B294-26B5689E51EF}</ProjectGuid>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <Keyword>Win32Proj</Keyword>\n    <!-- - - - -->\n    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n    <TargetRuntime>Native</TargetRuntime>\n    <GDKExtLibNames>Xbox.Services.API.C</GDKExtLibNames>\n    <PreferredToolArchitecture>x64</PreferredToolArchitecture>\n  </PropertyGroup>\n  <Import Condition=\"Exists($(ATGBuildProps))\" Project=\"$(ATGBuildProps)\" />\n  <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\Build\\xsapi.gdk.bwoi.props\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n    <Import Project=\"..\\..\\APIExplorer\\APIExplorer.Shared.vcxitems\" Label=\"Shared\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <!-- XSAPI: add between these lines -->\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\DirectXTK12\\Inc;Kits\\ATGTK;Kits\\ATGTelemetry\\Gsdk;$(ProjectDir)..\\..\\APIExplorer\\lua\\src;$(ProjectDir)..\\..\\APIExplorer\\Shared;$(ProjectDir)..\\..\\APIExplorer\\Include;$(ProjectDir)..\\..\\..\\Include\\cpprestinclude\\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>SAMPLE_BUILD_WITH_BIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Platform)'=='Gaming.Desktop.x64'\">SAMPLE_BUILD_FOR_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <!-- XSAPI: add between these lines -->\n  <!-- BEGIN Shared pre-build / post-build events -->\n  <ItemDefinitionGroup>\n    <PreBuildEvent>\n      <Command>copy /Y \"$(ProjectDir)APIRunnerBin-MicrosoftGame.Config\" \"$(ProjectDir)MicrosoftGame.Config\"</Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>xcopy /Y /I /E \"$(ProjectDir)Assets\\*.*\" \"$(TargetDir)Assets\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\*.*\" \"$(TargetDir)Media\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Fonts\\*.*\" \"$(TargetDir)\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Textures\\*.*\" \"$(TargetDir)\"</Command>\n    </PostBuildEvent>\n    <ClCompile>\n      <AdditionalIncludeDirectories>..\\..\\..\\External\\rapidjson\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <!-- END Shared pre-build / post-build events -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"APIRunner.GDK.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\ControllerFont.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\CSVReader.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\d3dx12.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\SampleGUI.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\TextConsole.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\UITwist.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"StepTimer.h\" />\n    <ClInclude Include=\"DeviceResources.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\LiveInfoHUD.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\LiveResources.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\ATGColors.h\" />\n    <ClInclude Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\Json.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\StringUtil.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\FindMedia.h\" />\n    <ClInclude Include=\"UIConstants.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\APIExplorer\\Shared\\Win\\pal.cpp\" />\n    <ClCompile Include=\"APIRunner.GDK.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\SampleGUI.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\TextConsole.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\UITwist.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\LiveInfoHUD.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\LiveResources.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\StringUtil.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <MGCCompile Include=\"MicrosoftGame.Config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\">\n      <Project>{052c4858-c76f-4cea-8a1a-e8e5559e67c2}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Media\\Textures\\GamerPic.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Logo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SmallLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SplashScreen.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\StoreLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Mounted.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Owned.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Unmounted.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SampleUI.csv\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.GDK.Bin.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Common\">\n      <UniqueIdentifier>916b6ff9-882e-4cf3-93d5-bea41c3e7cd0</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Assets\">\n      <UniqueIdentifier>0c10bab7-ebd0-49b3-89a5-df53a9e36cf4</UniqueIdentifier>\n      <Extensions>ico;cur;bmp;dds;dlg;fbx;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"ATG Tool Kit\">\n      <UniqueIdentifier>fa3bbbb4-fde4-4785-907e-fbb24dde6491</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Xbox Live Tool Kit\">\n      <UniqueIdentifier>83010d7a-d0f5-4911-9741-7529fae5301c</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"APIRunner.GDK.h\" />\n    <ClInclude Include=\"StepTimer.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DeviceResources.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\ATGColors.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\d3dx12.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\FindMedia.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\StringUtil.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\json.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"UIConstants.h\" />\n    <ClInclude Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\ControllerFont.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\CSVReader.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\SampleGUI.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\UITwist.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\LiveInfoHUD.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\LiveResources.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\TextConsole.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"pch.cpp\" />\n    <ClCompile Include=\"APIRunner.GDK.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\">\n      <Filter>Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\StringUtil.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\APIExplorer\\Shared\\Win\\pal.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\SampleGUI.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\UITwist.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\LiveInfoHUD.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\LiveResources.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\TextConsole.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Assets\\SampleUI.csv\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"MicrosoftGame.Config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Media\\Textures\\GamerPic.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Logo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Mounted.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Owned.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\SmallLogo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\SplashScreen.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\StoreLogo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Unmounted.png\">\n      <Filter>Assets</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.GDK.Src.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{46F31A54-4C74-41A8-B294-26B5689E51EF}</ProjectGuid>\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove(xsapi.paths.props))\" />\n  <Import Project=\"$(XsapiSourceRoot)\\Build\\xsapi.gdk.props\" />\n  <Import Project=\"$(XsapiSourceRoot)\\xsapi.staticlib.props\" />\n  <Import Condition=\"Exists($(ATGBuildProps))\" Project=\"$(ATGBuildProps)\" />\n  <Import Project=\"..\\..\\APIExplorer\\APIExplorer.Shared.vcxitems\" Label=\"Shared\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <!-- XSAPI: add between these lines -->\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\DirectXTK12\\Inc;Kits\\ATGTK;Kits\\ATGTelemetry\\Gsdk;$(ProjectDir)..\\..\\APIExplorer\\lua\\src;$(ProjectDir)..\\..\\APIExplorer\\Shared;$(ProjectDir)..\\..\\APIExplorer\\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PreprocessorDefinitions>SAMPLE_BUILD_WITH_CPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(Platform)'=='Gaming.Desktop.x64'\">SAMPLE_BUILD_FOR_DESKTOP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <PropertyGroup>\n    <XblTraceBuildInfo>true</XblTraceBuildInfo>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiPropsFile)\" Condition=\"Exists($(XsapiPropsFile))\" />\n  <PropertyGroup>\n    <XsapiPathsFile>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), xsapi.paths.props))\\xsapi.paths.props</XsapiPathsFile>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiPathsFile)\" Condition=\"Exists($(XsapiPathsFile))\" />\n  <!-- XSAPI: add between these lines -->\n  <!-- BEGIN Shared pre-build / post-build events -->\n  <ItemDefinitionGroup>\n    <PreBuildEvent>\n      <Command>copy /Y \"$(ProjectDir)APIRunnerSrc-MicrosoftGame.Config\" \"$(ProjectDir)MicrosoftGame.Config\"</Command>\n    </PreBuildEvent>\n    <PostBuildEvent>\n      <Command>xcopy /Y /I /E \"$(ProjectDir)Assets\\*.*\" \"$(TargetDir)Assets\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\*.*\" \"$(TargetDir)Media\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Fonts\\*.*\" \"$(TargetDir)\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Textures\\*.*\" \"$(TargetDir)\"</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <!-- END Shared pre-build / post-build events -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\ATGTelemetry\\GDK;Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>dbghelp.lib;uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);Kits\\LiveTK;Kits\\DirectXTK12\\Inc;Kits\\ATGTK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"APIRunner.GDK.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\ControllerFont.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\CSVReader.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\d3dx12.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\SampleGUI.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\TextConsole.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\UITwist.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"StepTimer.h\" />\n    <ClInclude Include=\"DeviceResources.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\LiveInfoHUD.h\" />\n    <ClInclude Include=\"Kits\\LiveTK\\LiveResources.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\ATGColors.h\" />\n    <ClInclude Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\Json.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\StringUtil.h\" />\n    <ClInclude Include=\"Kits\\ATGTK\\FindMedia.h\" />\n    <ClInclude Include=\"UIConstants.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\..\\APIExplorer\\Shared\\Win\\pal.cpp\" />\n    <ClCompile Include=\"APIRunner.GDK.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\SampleGUI.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\TextConsole.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\UITwist.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\LiveInfoHUD.cpp\" />\n    <ClCompile Include=\"Kits\\LiveTK\\LiveResources.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTK\\StringUtil.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <MGCCompile Include=\"MicrosoftGame.Config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Link>%(Filename)%(Extension)</Link>\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\">\n      <Project>{052c4858-c76f-4cea-8a1a-e8e5559e67c2}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Media\\Textures\\GamerPic.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Logo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SmallLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SplashScreen.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\StoreLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Mounted.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Owned.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\Unmounted.png\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SampleUI.csv\">\n      <DeploymentContent>true</DeploymentContent>\n      <DestinationFileName>Assets\\%(Filename)%(Extension)</DestinationFileName>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.GDK.Src.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Common\">\n      <UniqueIdentifier>916b6ff9-882e-4cf3-93d5-bea41c3e7cd0</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Assets\">\n      <UniqueIdentifier>0c10bab7-ebd0-49b3-89a5-df53a9e36cf4</UniqueIdentifier>\n      <Extensions>ico;cur;bmp;dds;dlg;fbx;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"ATG Tool Kit\">\n      <UniqueIdentifier>fa3bbbb4-fde4-4785-907e-fbb24dde6491</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Xbox Live Tool Kit\">\n      <UniqueIdentifier>83010d7a-d0f5-4911-9741-7529fae5301c</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"APIRunner.GDK.h\" />\n    <ClInclude Include=\"StepTimer.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DeviceResources.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\ATGColors.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\d3dx12.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\FindMedia.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\StringUtil.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\json.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"UIConstants.h\" />\n    <ClInclude Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\ControllerFont.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\CSVReader.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\SampleGUI.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\UITwist.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\LiveInfoHUD.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\LiveTK\\LiveResources.h\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Kits\\ATGTK\\TextConsole.h\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"pch.cpp\" />\n    <ClCompile Include=\"APIRunner.GDK.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\">\n      <Filter>Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\StringUtil.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"..\\..\\APIExplorer\\Shared\\Win\\pal.cpp\" />\n    <ClCompile Include=\"Kits\\ATGTelemetry\\GDK\\ATGTelemetry.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\SampleGUI.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\UITwist.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\LiveInfoHUD.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\LiveTK\\LiveResources.cpp\">\n      <Filter>Xbox Live Tool Kit</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Kits\\ATGTK\\TextConsole.cpp\">\n      <Filter>ATG Tool Kit</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Assets\\SampleUI.csv\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"MicrosoftGame.Config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Media\\Textures\\GamerPic.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Logo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Mounted.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Owned.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\SmallLogo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\SplashScreen.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\StoreLogo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Unmounted.png\">\n      <Filter>Assets</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.GDK.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"APIRunner.GDK.h\"\n\n#include \"ATGColors.h\"\n#include \"FindMedia.h\"\n#include \"Kits\\ATGTK\\StringUtil.h\"\n\n#include <XGameErr.h>\n\nextern void ExitSample();\n\nusing namespace DirectX;\n\nusing Microsoft::WRL::ComPtr;\n\nSample* g_Sample = nullptr;\n\nnamespace\n{\n    const int c_sampleUIPanel = 2000;\n}\n\nSample::Sample() noexcept(false) :\n    m_frame(0),\n    m_asyncQueue(nullptr)\n{\n    g_Sample = this;\n\n    DX::ThrowIfFailed(\n        XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::Manual, &m_asyncQueue)\n    );\n\n    // Renders only 2D, so no need for a depth buffer.\n    m_deviceResources = std::make_unique<DX::DeviceResources>(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN);\n    m_liveResources = std::make_shared<ATG::LiveResources>(m_asyncQueue);\n    m_liveInfoHUD = std::make_unique<ATG::LiveInfoHUD>(\"Xbox Live API Runner GDK\");\n\n    ATG::UIConfig uiconfig;\n    m_ui = std::make_shared<ATG::UIManager>(uiconfig);\n    m_log = std::make_unique<DX::TextConsoleImage>();\n    ApiRunnerSetupApiExplorer();\n}\n\nSample::~Sample()\n{\n    if (m_deviceResources)\n    {\n        m_deviceResources->WaitForGpu();\n    }\n\n    if (m_asyncQueue)\n    {\n        XTaskQueueCloseHandle(m_asyncQueue);\n        m_asyncQueue = nullptr;\n    }\n}\n\n// Initialize the Direct3D resources required to run.\nvoid Sample::Initialize(HWND window, int width, int height)\n{\n    m_gamePad = std::make_unique<GamePad>();\n\n    m_keyboard = std::make_unique<Keyboard>();\n\n    m_mouse = std::make_unique<Mouse>();\n#ifdef _GAMING_DESKTOP\n    m_mouse->SetWindow(window);\n#endif\n\n\n#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n    // NOTE: When running the app from the Start Menu (required for\n    //    Store API's to work) the Current Working Directory will be\n    //    returned as C:\\Windows\\system32 unless you overwrite it.\n    //    The sample relies on the font and image files in the .exe's\n    //    directory and so we do the following to set the working\n    //    directory to what we want.\n    char dir[1024];\n    GetModuleFileNameA(NULL, dir, 1024);\n    std::string exe = dir;\n    exe = exe.substr(0, exe.find_last_of(\"\\\\\"));\n    SetCurrentDirectoryA(exe.c_str());\n#endif\n\n    m_ui->LoadLayout(L\".\\\\Assets\\\\SampleUI.csv\", L\".\\\\Assets\");\n\n    m_deviceResources->SetWindow(window, width, height);\n\n    m_deviceResources->CreateDeviceResources();      \n    CreateDeviceDependentResources();\n\n    m_deviceResources->CreateWindowSizeDependentResources();\n    CreateWindowSizeDependentResources();\n\n    uint32_t titleId = 0;\n    HRESULT hr = XGameGetXboxTitleId(&titleId);\n    if (FAILED(hr))\n    {\n        m_log->WriteLine(L\"Can not get title ID.  Ensure you are running inside a app package\");\n    }\n\n    m_liveResources->SetUserChangedCallback([this](XUserHandle user)\n        {\n            m_liveInfoHUD->SetUser(user, m_asyncQueue);\n            m_ui->FindPanel<ATG::IPanel>(c_sampleUIPanel)->Show();\n        });\n\n    m_liveResources->SetUserSignOutCompletedCallback([this](XUserHandle /*user*/)\n        {\n            m_liveInfoHUD->SetUser(nullptr, m_asyncQueue);\n            m_ui->FindPanel<ATG::IPanel>(c_sampleUIPanel)->Close();\n        });\n\n    m_liveResources->SetErrorHandler([this](HRESULT error)\n    {\n        if (error == E_XAL_UIREQUIRED)\n        {\n            m_liveResources->SignInWithUI();\n        }\n        else // Handle other error cases\n        {\n\n        }\n    });\n\n    m_liveResources->Initialize();\n    m_liveInfoHUD->Initialize();\n\n    SetupUI();\n\n    // Before we can make an Xbox Live call we need to ensure that the Game OS has initialized the network stack\n    // For sample purposes we block user interaction with the sample.  A game should wait for the network to be\n    // initialized before the main menu appears.  For samples, we will wait at the end of initialization.\n    while (!m_liveResources->IsNetworkAvailable())\n    {\n    }\n}\n\nDWORD WINAPI ApiRunnerDoWork(LPVOID )\n{\n    if (g_Sample->m_runBVTs)\n    {\n        ApiRunnerRunTests(TestSet::SingleDeviceBVTs);\n    }\n    else\n    {\n        std::string jsonFileContents = ApiRunnerReadFile(\"cmds.json\");\n        ApiRunnerProcessJsonCmds(jsonFileContents);\n    }\n    g_Sample->m_bRunningTests = false;\n    g_Sample->m_bTestsFinished = true;\n\n    return 0;\n}\n\n\nvoid Sample::StartRunTests()\n{\n    if (!m_bRunningTests && m_log)\n    {\n        m_bRunningTests = true;\n        m_log->Clear();\n        m_log->WriteLine(L\"Running tests\");\n        CreateThread(nullptr, 0, ApiRunnerDoWork, nullptr, 0, nullptr);\n    }\n}\n\n\n#pragma region UI Methods\nvoid Sample::SetupUI()\n{\n    using namespace ATG;\n\n}\n\n#pragma endregion\n\n#pragma region Frame Update\n// Executes basic render loop.\nvoid Sample::Tick()\n{\n    PIXBeginEvent(PIX_COLOR_DEFAULT, L\"Frame %I64u\", m_frame);\n\n    m_timer.Tick([&]()\n    {\n        Update(m_timer);\n    });\n\n    Render();\n\n    PIXEndEvent();\n    m_frame++;\n}\n\n// Updates the world.\nvoid Sample::Update(DX::StepTimer const& timer)\n{\n    PIXBeginEvent(PIX_COLOR_DEFAULT, L\"Update\");\n    float elapsedTime = float(timer.GetElapsedSeconds());\n\n    // Auto start tests after a small delay\n    m_startTimer -= elapsedTime;\n    if (m_startTimer < 0.0f && !m_bAutoStarted)\n    {\n        if (m_cmdLine.find(L\"/test:\") != std::wstring::npos)\n        {\n            std::wstring num = m_cmdLine.substr(m_cmdLine.find(L\"/test:\") + 6);\n            if (num.find(L\" \") != std::wstring::npos)\n            {\n                num = num.substr(0, num.find(L\" \"));\n            }\n            int testNum = _wtoi(num.c_str());\n            ApiRunnerSetRunTestsParams(testNum, 0, 0);\n        }\n\n        if (m_cmdLine.find(L\"/range:\") != std::wstring::npos)\n        {\n            std::wstring num = m_cmdLine.substr(m_cmdLine.find(L\"/range:\") + 7);\n            if (num.find(L\" \") != std::wstring::npos)\n            {\n                num = num.substr(0, num.find(L\" \"));\n            }\n            std::wstring num1 = num.substr(0, num.find(L\":\"));\n            std::wstring num2 = num.substr(num.find(L\":\")+1);\n            int minNum = _wtoi(num1.c_str());\n            int maxNum = _wtoi(num2.c_str());\n            ApiRunnerSetRunTestsParams(0, minNum, maxNum);\n        }\n\n        m_bAutoStarted = true;\n        m_runBVTs = false;\n        StartRunTests();\n    }\n\n    if (m_bTestsFinished)\n    {\n        if (m_cmdLine.find(L\"/exit\") != std::wstring::npos)\n        {\n            ExitSample();\n        }\n    }\n\n    auto pad = m_gamePad->GetState(0);\n    if (pad.IsConnected())\n    {\n        m_gamePadButtons.Update(pad);\n\n        if (pad.IsViewPressed())\n        {\n            ExitSample();\n        }\n\n        if (m_gamePadButtons.menu == GamePad::ButtonStateTracker::PRESSED)\n        {\n            if (!m_liveResources->IsUserSignedIn())\n            {\n                m_log->WriteLine(L\"Sign in silently\");\n                m_liveResources->SignInSilently();\n            }\n            else\n            {\n                m_log->WriteLine(L\"Sign in with UI\");\n                m_liveResources->SignInWithUI();\n            }\n        }\n\n        m_ui->Update(elapsedTime, pad);\n    }\n    else\n    {\n        m_gamePadButtons.Reset();\n    }\n\n    auto kb = m_keyboard->GetState();\n    m_keyboardButtons.Update(kb);\n\n    if (kb.Enter || kb.Space || kb.B)\n    {\n        m_runBVTs = true;\n        StartRunTests();        \n    }\n    if (kb.A)\n    {\n        m_runBVTs = false;\n        StartRunTests();\n    }\n    if (kb.Escape)\n    {\n        ExitSample();\n    }\n\n    // Process any completed tasks\n    while (XTaskQueueDispatch(m_asyncQueue, XTaskQueuePort::Completion, 0))\n    {\n    }\n\n    m_liveInfoHUD->Update(m_deviceResources->GetCommandQueue());\n\n    PIXEndEvent();\n}\n#pragma endregion\n\n#pragma region Frame Render\n// Draws the scene.\nvoid Sample::Render()\n{\n    // Don't try to render anything before the first Update.\n    if (m_timer.GetFrameCount() == 0)\n    {\n        return;\n    }\n\n    // Prepare the command list to render a new frame.\n    m_deviceResources->Prepare();\n    Clear();\n\n    auto commandList = m_deviceResources->GetCommandList();\n    PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L\"Render\");\n\n    ID3D12DescriptorHeap* heap = m_resourceDescriptors->Heap();\n    commandList->SetDescriptorHeaps(1, &heap);\n\n    m_liveInfoHUD->Render(commandList);\n\n    if (m_log) m_log->Render(commandList);\n    if (m_ui) m_ui->Render(commandList);\n\n    PIXEndEvent(commandList);\n\n    // Show the new frame.\n    PIXBeginEvent(m_deviceResources->GetCommandQueue(), PIX_COLOR_DEFAULT, L\"Present\");\n    m_deviceResources->Present();\n    m_graphicsMemory->Commit(m_deviceResources->GetCommandQueue());\n    PIXEndEvent(m_deviceResources->GetCommandQueue());\n}\n\n// Helper method to clear the back buffers.\nvoid Sample::Clear()\n{\n    auto commandList = m_deviceResources->GetCommandList();\n    PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L\"Clear\");\n\n    // Clear the views.\n    auto rtvDescriptor = m_deviceResources->GetRenderTargetView();\n\n    commandList->OMSetRenderTargets(1, &rtvDescriptor, FALSE, nullptr);\n    commandList->ClearRenderTargetView(rtvDescriptor, ATG::Colors::Background, 0, nullptr);\n\n    // Set the viewport and scissor rect.\n    auto viewport = m_deviceResources->GetScreenViewport();\n    auto scissorRect = m_deviceResources->GetScissorRect();\n    commandList->RSSetViewports(1, &viewport);\n    commandList->RSSetScissorRects(1, &scissorRect);\n\n    PIXEndEvent(commandList);\n}\n#pragma endregion\n\n#pragma region Message Handlers\n// Message handlers\nvoid Sample::OnActivated()\n{\n}\n\nvoid Sample::OnDeactivated()\n{\n}\n\nvoid Sample::OnSuspending()\n{\n    m_deviceResources->Suspend();\n}\n\nvoid Sample::OnResuming()\n{\n    m_deviceResources->Resume();\n    m_timer.ResetElapsedTime();\n    m_gamePadButtons.Reset();\n    m_keyboardButtons.Reset();\n    m_liveResources->Refresh();\n    m_ui->Reset();\n    m_log.reset();\n}\n\nvoid Sample::OnWindowMoved()\n{\n    auto r = m_deviceResources->GetOutputSize();\n    m_deviceResources->WindowSizeChanged(r.right, r.bottom);\n}\n\nvoid Sample::OnWindowSizeChanged(int width, int height)\n{\n    if (!m_deviceResources->WindowSizeChanged(width, height))\n        return;\n\n    CreateWindowSizeDependentResources();\n}\n\n// Properties\nvoid Sample::GetDefaultSize(int& width, int& height) const\n{\n    width = 1920;\n    height = 1080;\n}\n#pragma endregion\n\n#pragma region Direct3D Resources\n// These are the resources that depend on the device.\nvoid Sample::CreateDeviceDependentResources()\n{\n    auto device = m_deviceResources->GetD3DDevice();\n\n    m_graphicsMemory = std::make_unique<GraphicsMemory>(device);\n\n    RenderTargetState rtState(m_deviceResources->GetBackBufferFormat(), m_deviceResources->GetDepthBufferFormat());\n\n    ResourceUploadBatch resourceUpload(device);\n    resourceUpload.Begin();\n\n    m_resourceDescriptors = std::make_unique<DirectX::DescriptorPile>(device,\n        D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\n        D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,\n        Descriptors::Count,\n        Descriptors::Reserve\n        );\n\n    m_liveInfoHUD->RestoreDevice(device, rtState, resourceUpload, *m_resourceDescriptors);\n\n    m_log->RestoreDevice(\n        device,\n        resourceUpload,\n        rtState,\n        L\"Media\\\\Fonts\\\\SegoeUI_18.spritefont\",\n        L\"Assets\\\\ATGSampleBackground.DDS\",\n        m_resourceDescriptors->GetCpuHandle(Descriptors::Font),\n        m_resourceDescriptors->GetGpuHandle(Descriptors::Font),\n        m_resourceDescriptors->GetCpuHandle(Descriptors::Background),\n        m_resourceDescriptors->GetGpuHandle(Descriptors::Background)\n    );\n\n    m_ui->RestoreDevice(device, rtState, resourceUpload, *m_resourceDescriptors);\n\n    auto uploadResourcesFinished = resourceUpload.End(m_deviceResources->GetCommandQueue());\n    uploadResourcesFinished.wait();\n}\n\n// Allocate all memory resources that change on a window SizeChanged event.\nvoid Sample::CreateWindowSizeDependentResources()\n{\n    m_liveInfoHUD->SetViewport(m_deviceResources->GetScreenViewport());\n\n    auto viewport = m_deviceResources->GetScreenViewport();\n    static const RECT screenDisplay = { 50, 150, static_cast<LONG>(viewport.Width-50), static_cast<LONG>(viewport.Height-150) };\n    m_log->SetWindow(screenDisplay, false);\n    m_log->SetViewport(viewport);\n\n    RECT size = m_deviceResources->GetOutputSize();\n    m_ui->SetWindow(size);\n}\n\nvoid Sample::OnDeviceLost()\n{\n    m_graphicsMemory.reset();\n    m_liveInfoHUD->ReleaseDevice();\n    m_resourceDescriptors.reset();\n}\n\nvoid Sample::OnDeviceRestored()\n{\n    CreateDeviceDependentResources();\n    CreateWindowSizeDependentResources();\n}\n#pragma endregion\n\nvoid LogToScreen(_Printf_format_string_ char const* format, ...)\n{\n    char message[8000] = {};\n\n    va_list varArgs{};\n    va_start(varArgs, format);\n    pal::vsprintf(message, 4096, format, varArgs);\n    va_end(varArgs);\n\n    if (g_Sample && g_Sample->m_log != nullptr)\n    {\n        std::wstring wstr = DX::Utf8ToWide(message);\n        g_Sample->m_log->WriteLine(wstr.c_str());\n    }\n    else\n    {\n        std::cout << message;\n        std::cout << \"\\n\";\n    }\n\n    LogToFile(message);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunner.GDK.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\n#include \"DeviceResources.h\"\n#include \"Kits\\LiveTK\\LiveResources.h\"\n#include \"Kits\\LiveTK\\LiveInfoHUD.h\"\n#include \"StepTimer.h\"\n#include \"SampleGUI.h\"\n#include \"Kits\\ATGTK\\TextConsole.h\"\n\n\nclass Sample;\n\n// A basic sample implementation that creates a D3D12 device and\n// provides a render loop.\nclass Sample final : public DX::IDeviceNotify\n{\npublic:\n\n    Sample() noexcept(false);\n    ~Sample();\n\n    // Initialization and management\n    void Initialize(HWND window, int width, int height);\n\n    // Basic render loop\n    void Tick();\n\n    // IDeviceNotify\n    virtual void OnDeviceLost() override;\n    virtual void OnDeviceRestored() override;\n\n    // Messages\n    void OnActivated();\n    void OnDeactivated();\n    void OnSuspending();\n    void OnResuming();\n    void OnWindowMoved();\n    void OnWindowSizeChanged(int width, int height);\n\n    // Properties\n    void GetDefaultSize(int& width, int& height) const;\n\n    std::unique_ptr<DX::TextConsoleImage> m_log;\n    bool m_bAutoStarted = false;\n    bool m_bRunningTests = false;\n    bool m_bTestsFinished = false;\n    bool m_runBVTs = false;\n    std::wstring m_cmdLine;\n    float m_startTimer = 1.0f;\n    void StartRunTests();\n\nprivate:\n    void Update(DX::StepTimer const& timer);\n    void Render();\n\n    void Clear();\n\n    void CreateDeviceDependentResources();\n    void CreateWindowSizeDependentResources();\n\n    void SetupUI();\n\n    // Device resources.\n    std::unique_ptr<DX::DeviceResources>        m_deviceResources;\n\n    // Rendering loop timer.\n    uint64_t                                    m_frame;\n    DX::StepTimer                               m_timer;\n\n    // Input devices.\n    std::unique_ptr<DirectX::GamePad>           m_gamePad;\n    std::unique_ptr<DirectX::Keyboard>          m_keyboard;\n    std::unique_ptr<DirectX::Mouse>             m_mouse;\n\n    DirectX::GamePad::ButtonStateTracker        m_gamePadButtons;\n    DirectX::Keyboard::KeyboardStateTracker     m_keyboardButtons;\n\n    // DirectXTK objects.\n    std::unique_ptr<DirectX::GraphicsMemory>    m_graphicsMemory;\n    std::unique_ptr<DirectX::DescriptorPile>    m_resourceDescriptors;\n\n    // UI Objects\n    std::shared_ptr<ATG::UIManager>             m_ui;\n\n    // Xbox Live objects.\n    std::shared_ptr<ATG::LiveResources>         m_liveResources;\n\n    std::unique_ptr<ATG::LiveInfoHUD>           m_liveInfoHUD;\n\n    XTaskQueueHandle                            m_asyncQueue;\n\n    enum Descriptors\n    {\n        Font,\n        ConsoleFont,\n        Background,\n        ConsoleBackground,\n        Reserve,\n        Count = 32,\n    };\n};"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunnerBin-MicrosoftGame.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Game configVersion=\"1\">\n\n    <Identity Name=\"41336MicrosoftATG.XboxLiveE2E\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.7.0.0\" />\n\t\n    <ExecutableList>\n        <Executable Name=\"APIRunner.GDK.Bin.exe\" Id=\"APIRunner.GDK.Bin.exe\"/>\n    </ExecutableList>\n\n\t<MSAFullTrust>false</MSAFullTrust>\n\t<MSAAppId>000000004C26FED0</MSAAppId>\n\t<TitleId>76029B4D</TitleId>\n\t<PersistentLocalStorage>\n\t\t<SizeMB>1024</SizeMB>\n\t</PersistentLocalStorage>\n\n    <ShellVisuals\n            DefaultDisplayName=\"APIRunner Bin GDK Desktop Sample\"\n            PublisherDisplayName=\"Xbox Advanced Technology Group\"\n            Description=\"InGameStore Desktop Sample\"\n            Square150x150Logo=\"Assets\\Logo.png\"\n            Square44x44Logo=\"Assets\\SmallLogo.png\"\n            BackgroundColor=\"#000000\"\n            SplashScreenImage=\"Assets\\SplashScreen.png\"\n            StoreLogo=\"Assets\\StoreLogo.png\"\n    />\n\n</Game>\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunnerSrc-MicrosoftGame.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Game configVersion=\"1\">\n\n    <Identity Name=\"41336MicrosoftATG.XboxLiveE2E\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.7.0.0\" />\n    \n    <ExecutableList>\n        <Executable Name=\"APIRunner.GDK.Src.exe\" Id=\"Game1\"/>\n    </ExecutableList>\n\n    <MSAFullTrust>false</MSAFullTrust>\n    <MSAAppId>000000004C26FED0</MSAAppId>\n    <TitleId>76029B4D</TitleId>\n    <PersistentLocalStorage>\n        <SizeMB>1024</SizeMB>\n    </PersistentLocalStorage>\n\n    <ShellVisuals\n            DefaultDisplayName=\"APIRunner Src GDK Desktop Sample\"\n            PublisherDisplayName=\"Xbox Advanced Technology Group\"\n            Description=\"InGameStore Desktop Sample\"\n            Square150x150Logo=\"Assets\\Logo.png\"\n            Square44x44Logo=\"Assets\\SmallLogo.png\"\n            BackgroundColor=\"#000000\"\n            SplashScreenImage=\"Assets\\SplashScreen.png\"\n            StoreLogo=\"Assets\\StoreLogo.png\"\n    />\n\n</Game>\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunnerSrc143-MicrosoftGame.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Game configVersion=\"1\">\n\n    <Identity Name=\"41336MicrosoftATG.XboxLiveE2E\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.7.0.0\" />\n    \n    <ExecutableList>\n        <Executable Name=\"APIRunner.143.GDK.Src.exe\" Id=\"Game1\"/>\n    </ExecutableList>\n\n    <MSAFullTrust>false</MSAFullTrust>\n    <MSAAppId>000000004C26FED0</MSAAppId>\n    <TitleId>76029B4D</TitleId>\n    <PersistentLocalStorage>\n        <SizeMB>1024</SizeMB>\n    </PersistentLocalStorage>\n\n    <ShellVisuals\n            DefaultDisplayName=\"APIRunner Src GDK Desktop Sample\"\n            PublisherDisplayName=\"Xbox Advanced Technology Group\"\n            Description=\"InGameStore Desktop Sample\"\n            Square150x150Logo=\"Assets\\Logo.png\"\n            Square44x44Logo=\"Assets\\SmallLogo.png\"\n            BackgroundColor=\"#000000\"\n            SplashScreenImage=\"Assets\\SplashScreen.png\"\n            StoreLogo=\"Assets\\StoreLogo.png\"\n    />\n\n</Game>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/APIRunnerStats2017-MicrosoftGame.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Game configVersion=\"0\">\n\n    <Identity Name=\"41336MicrosoftATG.XboxLiveE2EStats2017\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.7.0.0\" />\n    \n    <ExecutableList>\n        <Executable Name=\"APIRunner.GDK.Src.exe\" Id=\"Game1\"/>\n    </ExecutableList>\n\n    <MSAFullTrust>false</MSAFullTrust>\n    <MSAAppId>0000000044296E10</MSAAppId>\n    <TitleId>78C0191B</TitleId>\n    <PersistentLocalStorage>\n        <SizeMB>1024</SizeMB>\n    </PersistentLocalStorage>\n\n    <ShellVisuals\n            DefaultDisplayName=\"APIRunner Src GDK Desktop Sample\"\n            PublisherDisplayName=\"Xbox Advanced Technology Group\"\n            Description=\"InGameStore Desktop Sample\"\n            Square150x150Logo=\"Assets\\Logo.png\"\n            Square44x44Logo=\"Assets\\SmallLogo.png\"\n            BackgroundColor=\"#000000\"\n            SplashScreenImage=\"Assets\\SplashScreen.png\"\n            StoreLogo=\"Assets\\StoreLogo.png\"\n    />\n\n</Game>\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/AppxManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Package\n   IgnorableNamespaces=\"uap rescap desktop6\"\n   xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\"\n   xmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\"\n   xmlns:rescap=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities\"\n   xmlns:desktop6=\"http://schemas.microsoft.com/appx/manifest/desktop/windows10/6\" >\n   \n  <Identity Name=\"41336MicrosoftATG.XboxLiveE2E\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.7.0.0\" />\n  \n  <Properties>\n    <DisplayName>APIRunner Src GDK Desktop Sample</DisplayName>\n    <PublisherDisplayName>Xbox Advanced Technology Group</PublisherDisplayName>\n    <Logo>Assets/Logo.png</Logo>\n    <Description>**REPLACE**</Description>\n  </Properties>\n  <Resources>\n    <Resource Language=\"en-US\" />\n  </Resources>\n  <Dependencies>\n    <TargetDeviceFamily Name=\"Windows.Desktop\" MinVersion=\"10.0.19041.0\" MaxVersionTested=\"10.0.19041.0\" />\n  </Dependencies>\n  <Applications>\n    <Application Id=\"Game1\" Executable=\"APIRunner.GDK.Src.exe\" EntryPoint=\"Windows.FullTrustApplication\">\n      <uap:VisualElements BackgroundColor=\"#000040\" DisplayName=\"DX11\" Square150x150Logo=\"Assets/Logo.png\" Square44x44Logo=\"Assets/SmallLogo.png\" Description=\"DX11\">\n        <uap:DefaultTile ShortName=\"**REPLACE**\" />\n        <uap:SplashScreen Image=\"Assets/SplashScreen.png\" />\n      </uap:VisualElements>\n    </Application>\n  </Applications>\n  <Capabilities>\n    <rescap:Capability Name=\"runFullTrust\"/>\n  </Capabilities>\n</Package>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Assets/SampleUI.csv",
    "content": "#ITEM,ID,X,Y,DX,DY,PARAMETERS\nCUSTOM_OVERLAY,2000,0,0,1920,1080,\nLABEL,2002,50,50,50,50,Log,LEFT;SMALL\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/CopyLogFromConsole.cmd",
    "content": "xbcp xd:\\titles\\41336MicrosoftATG.XboxLiveE2E_dspnxghe87tn0\\apirunner-log.txt"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/DeviceResources.cpp",
    "content": "﻿//\n// DeviceResources.cpp - A wrapper for the Direct3D 12/12.X device and swapchain\n//\n\n#include \"pch.h\"\n#include \"DeviceResources.h\"\n\nusing namespace DirectX;\nusing namespace DX;\n\nusing Microsoft::WRL::ComPtr;\n\n#ifndef _GAMING_XBOX\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#endif\n\n#pragma warning(disable : 4061)\n\nnamespace\n{\n    inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:   return DXGI_FORMAT_R8G8B8A8_UNORM;\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:   return DXGI_FORMAT_B8G8R8A8_UNORM;\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:   return DXGI_FORMAT_B8G8R8X8_UNORM;\n        default:                                return fmt;\n        }\n    }\n}\n#endif\n\n// Constructor for DeviceResources.\nDeviceResources::DeviceResources(\n    DXGI_FORMAT backBufferFormat,\n    DXGI_FORMAT depthBufferFormat,\n    UINT backBufferCount) noexcept(false) :\n        m_backBufferIndex(0),\n        m_fenceValues{},\n#ifdef _GAMING_XBOX\n        m_framePipelineToken{},\n#endif\n        m_rtvDescriptorSize(0),\n        m_screenViewport{},\n        m_scissorRect{},\n        m_backBufferFormat(backBufferFormat),\n        m_depthBufferFormat(depthBufferFormat),\n        m_backBufferCount(backBufferCount),\n        m_window(nullptr),\n        m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_0),\n        m_outputSize{ 0, 0, 1, 1 },\n        m_deviceNotify(nullptr)\n{\n    if (backBufferCount > MAX_BACK_BUFFER_COUNT)\n    {\n        throw std::out_of_range(\"backBufferCount too large\");\n    }\n}\n\n// Destructor for DeviceResources.\nDeviceResources::~DeviceResources()\n{\n    // Ensure that the GPU is no longer referencing resources that are about to be destroyed.\n    WaitForGpu();\n\n#ifdef _GAMING_XBOX\n    // Ensure we present a blank screen before cleaning up resources.\n    if (m_commandQueue)\n    {\n        (void)m_commandQueue->PresentX(0, nullptr, nullptr);\n    }\n#endif\n}\n\n// Configures the Direct3D device, and stores handles to it and the device context.\nvoid DeviceResources::CreateDeviceResources()\n{\n#ifdef _GAMING_XBOX\n\n    // Create the DX12 API device object.\n    D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {};\n    params.Version = D3D12_SDK_VERSION;\n\n#if defined(_DEBUG)\n    // Enable the debug layer.\n    params.ProcessDebugFlags = D3D12_PROCESS_DEBUG_FLAG_DEBUG_LAYER_ENABLED;\n#elif defined(PROFILE)\n    // Enable the instrumented driver.\n    params.ProcessDebugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_INSTRUMENTED;\n#endif\n\n    params.GraphicsCommandQueueRingSizeBytes = static_cast<UINT>(D3D12XBOX_DEFAULT_SIZE_BYTES);\n    params.GraphicsScratchMemorySizeBytes = static_cast<UINT>(D3D12XBOX_DEFAULT_SIZE_BYTES);\n    params.ComputeScratchMemorySizeBytes = static_cast<UINT>(D3D12XBOX_DEFAULT_SIZE_BYTES);\n\n    ThrowIfFailed(D3D12XboxCreateDevice(\n        nullptr,\n        &params,\n        IID_GRAPHICS_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf())\n        ));\n\n    m_d3dDevice->SetName(L\"DeviceResources\");\n\n    m_d3dFeatureLevel = D3D_FEATURE_LEVEL_12_0;\n\n#else\n\n    DWORD dxgiFactoryFlags = 0;\n\n#if defined(_DEBUG)\n    // Enable the debug layer (requires the Graphics Tools \"optional feature\").\n    //\n    // NOTE: Enabling the debug layer after device creation will invalidate the active device.\n    //{\n    //    ComPtr<ID3D12Debug> debugController;\n    //    if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf()))))\n    //    {\n    //        debugController->EnableDebugLayer();\n    //    }\n    //    else\n    //    {\n    //        OutputDebugStringA(\"WARNING: Direct3D Debug Device is not available\\n\");\n    //    }\n\n    //    ComPtr<IDXGIInfoQueue> dxgiInfoQueue;\n    //    if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf()))))\n    //    {\n    //        dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;\n\n    //        dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);\n    //        dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);\n\n    //        DXGI_INFO_QUEUE_MESSAGE_ID hide[] =\n    //        {\n    //            80 /* IDXGISwapChain::GetContainingOutput: The swapchain's adapter does not control the output on which the swapchain's window resides. */,\n    //        };\n    //        DXGI_INFO_QUEUE_FILTER filter = {};\n    //        filter.DenyList.NumIDs = _countof(hide);\n    //        filter.DenyList.pIDList = hide;\n    //        dxgiInfoQueue->AddStorageFilterEntries(DXGI_DEBUG_DXGI, &filter);\n    //    }\n    //}\n#endif\n\n    ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));\n\n    ComPtr<IDXGIAdapter1> adapter;\n    GetAdapter(adapter.GetAddressOf());\n\n    // Create the DX12 API device object.\n    ThrowIfFailed(D3D12CreateDevice(\n        adapter.Get(),\n        D3D_FEATURE_LEVEL_11_0,\n        IID_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf())\n        ));\n\n    m_d3dDevice->SetName(L\"DeviceResources\");\n\n#ifndef NDEBUG\n    // Configure debug device (if active).\n    ComPtr<ID3D12InfoQueue> d3dInfoQueue;\n    if (SUCCEEDED(m_d3dDevice.As(&d3dInfoQueue)))\n    {\n#ifdef _DEBUG\n        d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);\n        d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);\n#endif\n        D3D12_MESSAGE_ID hide[] =\n        {\n            D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE,\n            D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE,\n            D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE\n        };\n        D3D12_INFO_QUEUE_FILTER filter = {};\n        filter.DenyList.NumIDs = _countof(hide);\n        filter.DenyList.pIDList = hide;\n        d3dInfoQueue->AddStorageFilterEntries(&filter);\n    }\n#endif\n\n    // Determine maximum supported feature level for this device\n    static const D3D_FEATURE_LEVEL s_featureLevels[] =\n    {\n        D3D_FEATURE_LEVEL_12_1,\n        D3D_FEATURE_LEVEL_12_0,\n        D3D_FEATURE_LEVEL_11_1,\n        D3D_FEATURE_LEVEL_11_0,\n    };\n\n    D3D12_FEATURE_DATA_FEATURE_LEVELS featLevels =\n    {\n        _countof(s_featureLevels), s_featureLevels, D3D_FEATURE_LEVEL_11_0\n    };\n\n    HRESULT hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featLevels, sizeof(featLevels));\n    if (SUCCEEDED(hr))\n    {\n        m_d3dFeatureLevel = featLevels.MaxSupportedFeatureLevel;\n    }\n    else\n    {\n        m_d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0;\n    }\n\n#endif\n\n    // Create the command queue.\n    D3D12_COMMAND_QUEUE_DESC queueDesc = {};\n    queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n    queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;\n\n    ThrowIfFailed(m_d3dDevice->CreateCommandQueue(&queueDesc, IID_GRAPHICS_PPV_ARGS(m_commandQueue.ReleaseAndGetAddressOf())));\n\n    m_commandQueue->SetName(L\"DeviceResources\");\n\n    // Create descriptor heaps for render target views and depth stencil views.\n    D3D12_DESCRIPTOR_HEAP_DESC rtvDescriptorHeapDesc = {};\n    rtvDescriptorHeapDesc.NumDescriptors = m_backBufferCount;\n    rtvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;\n\n    ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&rtvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_rtvDescriptorHeap.ReleaseAndGetAddressOf())));\n\n    m_rtvDescriptorHeap->SetName(L\"DeviceResources\");\n\n    m_rtvDescriptorSize = m_d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);\n\n    if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)\n    {\n        D3D12_DESCRIPTOR_HEAP_DESC dsvDescriptorHeapDesc = {};\n        dsvDescriptorHeapDesc.NumDescriptors = 1;\n        dsvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;\n\n        ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&dsvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_dsvDescriptorHeap.ReleaseAndGetAddressOf())));\n\n        m_dsvDescriptorHeap->SetName(L\"DeviceResources\");\n    }\n\n    // Create a command allocator for each back buffer that will be rendered to.\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        ThrowIfFailed(m_d3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(m_commandAllocators[n].ReleaseAndGetAddressOf())));\n\n        wchar_t name[25] = {};\n        swprintf_s(name, L\"Render target %u\", n);\n        m_commandAllocators[n]->SetName(name);\n    }\n\n    // Create a command list for recording graphics commands.\n    ThrowIfFailed(m_d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[0].Get(), nullptr, IID_GRAPHICS_PPV_ARGS(m_commandList.ReleaseAndGetAddressOf())));\n    ThrowIfFailed(m_commandList->Close());\n\n    m_commandList->SetName(L\"DeviceResources\");\n\n    // Create a fence for tracking GPU execution progress.\n    ThrowIfFailed(m_d3dDevice->CreateFence(m_fenceValues[m_backBufferIndex], D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(m_fence.ReleaseAndGetAddressOf())));\n    m_fenceValues[m_backBufferIndex]++;\n\n    m_fence->SetName(L\"DeviceResources\");\n\n    m_fenceEvent.Attach(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n    if (!m_fenceEvent.IsValid())\n    {\n        throw std::exception(\"CreateEvent\");\n    }\n\n#ifdef _GAMING_XBOX\n    RegisterFrameEvents();\n#endif\n}\n\n// These resources need to be recreated every time the window size is changed.\nvoid DeviceResources::CreateWindowSizeDependentResources()\n{\n    if (!m_window)\n    {\n        throw std::exception(\"Call SetWindow with a valid window handle\");\n    }\n\n    // Wait until all previous GPU work is complete.\n    WaitForGpu();\n\n#ifdef _GAMING_XBOX\n    // Ensure we present a blank screen before cleaning up resources.\n    ThrowIfFailed(m_commandQueue->PresentX(0, nullptr, nullptr));\n#endif\n\n    // Release resources that are tied to the swap chain and update fence values.\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        m_renderTargets[n].Reset();\n        m_fenceValues[n] = m_fenceValues[m_backBufferIndex];\n    }\n\n    // Determine the render target size in pixels.\n    UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);\n    UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);\n\n#ifdef _GAMING_XBOX\n\n    // Obtain the back buffers for this window which will be the final render targets\n    // and create render target views for each of them.\n    CD3DX12_HEAP_PROPERTIES swapChainHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    D3D12_RESOURCE_DESC swapChainBufferDesc = CD3DX12_RESOURCE_DESC::Tex2D(\n        m_backBufferFormat,\n        backBufferWidth,\n        backBufferHeight,\n        1, // This resource has only one texture.\n        1  // Use a single mipmap level.\n    );\n    swapChainBufferDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;\n\n    D3D12_CLEAR_VALUE swapChainOptimizedClearValue = {};\n    swapChainOptimizedClearValue.Format = m_backBufferFormat;\n\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        ThrowIfFailed(m_d3dDevice->CreateCommittedResource(\n            &swapChainHeapProperties,\n            D3D12_HEAP_FLAG_ALLOW_DISPLAY,\n            &swapChainBufferDesc,\n            D3D12_RESOURCE_STATE_PRESENT,\n            &swapChainOptimizedClearValue,\n            IID_GRAPHICS_PPV_ARGS(m_renderTargets[n].GetAddressOf())));\n\n        wchar_t name[25] = {};\n        swprintf_s(name, L\"Render target %u\", n);\n        m_renderTargets[n]->SetName(name);\n\n        D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};\n        rtvDesc.Format = m_backBufferFormat;\n        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;\n\n        CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(\n            m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),\n            static_cast<INT>(n), m_rtvDescriptorSize);\n        m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor);\n    }\n\n    // Reset the index to the current back buffer.\n    m_backBufferIndex = 0;\n\n#else\n\n    DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);\n\n    // If the swap chain already exists, resize it, otherwise create one.\n    if (m_swapChain)\n    {\n        // If the swap chain already exists, resize it.\n        HRESULT hr = m_swapChain->ResizeBuffers(\n            m_backBufferCount,\n            backBufferWidth,\n            backBufferHeight,\n            backBufferFormat,\n            0\n        );\n\n        if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)\n        {\n#ifdef _DEBUG\n            char buff[64] = {};\n            sprintf_s(buff, \"Device Lost on ResizeBuffers: Reason code 0x%08X\\n\", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);\n            OutputDebugStringA(buff);\n#endif\n            // If the device was removed for any reason, a new device and swap chain will need to be created.\n            HandleDeviceLost();\n\n            // Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method\n            // and correctly set up the new device.\n            return;\n        }\n        else\n        {\n            ThrowIfFailed(hr);\n        }\n    }\n    else\n    {\n        // Create a descriptor for the swap chain.\n        DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};\n        swapChainDesc.Width = backBufferWidth;\n        swapChainDesc.Height = backBufferHeight;\n        swapChainDesc.Format = backBufferFormat;\n        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n        swapChainDesc.BufferCount = m_backBufferCount;\n        swapChainDesc.SampleDesc.Count = 1;\n        swapChainDesc.SampleDesc.Quality = 0;\n        swapChainDesc.Scaling = DXGI_SCALING_STRETCH;\n        swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;\n        swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;\n\n        DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {};\n        fsSwapChainDesc.Windowed = TRUE;\n\n        // Create a swap chain for the window.\n        ComPtr<IDXGISwapChain1> swapChain;\n        ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd(\n            m_commandQueue.Get(),\n            m_window,\n            &swapChainDesc,\n            &fsSwapChainDesc,\n            nullptr,\n            swapChain.GetAddressOf()\n        ));\n\n        ThrowIfFailed(swapChain.As(&m_swapChain));\n\n        // This class does not support exclusive full-screen mode and prevents DXGI from responding to the ALT+ENTER shortcut\n        ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window, DXGI_MWA_NO_ALT_ENTER));\n    }\n\n    // Obtain the back buffers for this window which will be the final render targets\n    // and create render target views for each of them.\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(m_renderTargets[n].GetAddressOf())));\n\n        wchar_t name[25] = {};\n        swprintf_s(name, L\"Render target %u\", n);\n        m_renderTargets[n]->SetName(name);\n\n        D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};\n        rtvDesc.Format = m_backBufferFormat;\n        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;\n\n        CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(\n            m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),\n            static_cast<INT>(n), m_rtvDescriptorSize);\n        m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor);\n    }\n\n    // Reset the index to the current back buffer.\n    m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex();\n\n#endif\n\n    if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)\n    {\n        // Allocate a 2-D surface as the depth/stencil buffer and create a depth/stencil view\n        // on this surface.\n        CD3DX12_HEAP_PROPERTIES depthHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        D3D12_RESOURCE_DESC depthStencilDesc = CD3DX12_RESOURCE_DESC::Tex2D(\n            m_depthBufferFormat,\n            backBufferWidth,\n            backBufferHeight,\n            1, // This depth stencil view has only one texture.\n            1  // Use a single mipmap level.\n            );\n        depthStencilDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;\n\n        D3D12_CLEAR_VALUE depthOptimizedClearValue = {};\n        depthOptimizedClearValue.Format = m_depthBufferFormat;\n        depthOptimizedClearValue.DepthStencil.Depth = 1.0f;\n        depthOptimizedClearValue.DepthStencil.Stencil = 0;\n\n        ThrowIfFailed(m_d3dDevice->CreateCommittedResource(\n            &depthHeapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &depthStencilDesc,\n            D3D12_RESOURCE_STATE_DEPTH_WRITE,\n            &depthOptimizedClearValue,\n            IID_GRAPHICS_PPV_ARGS(m_depthStencil.ReleaseAndGetAddressOf())\n            ));\n\n        m_depthStencil->SetName(L\"Depth stencil\");\n\n        D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};\n        dsvDesc.Format = m_depthBufferFormat;\n        dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;\n\n        m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());\n    }\n\n    // Set the 3D rendering viewport and scissor rectangle to target the entire window.\n    m_screenViewport.TopLeftX = m_screenViewport.TopLeftY = 0.f;\n    m_screenViewport.Width = static_cast<float>(backBufferWidth);\n    m_screenViewport.Height = static_cast<float>(backBufferHeight);\n    m_screenViewport.MinDepth = D3D12_MIN_DEPTH;\n    m_screenViewport.MaxDepth = D3D12_MAX_DEPTH;\n\n    m_scissorRect.left = m_scissorRect.top = 0;\n    m_scissorRect.right = static_cast<LONG>(backBufferWidth);\n    m_scissorRect.bottom = static_cast<LONG>(backBufferHeight);\n}\n\n// This method is called when the Win32 window is created (or re-created).\nvoid DeviceResources::SetWindow(HWND window, int width, int height)\n{\n    m_window = window;\n\n    m_outputSize.left = m_outputSize.top = 0;\n    m_outputSize.right = width;\n    m_outputSize.bottom = height;\n}\n\n// This method is called when the Win32 window changes size.\nbool DeviceResources::WindowSizeChanged(int width, int height)\n{\n    RECT newRc;\n    newRc.left = newRc.top = 0;\n    newRc.right = width;\n    newRc.bottom = height;\n    if (newRc.left == m_outputSize.left\n        && newRc.top == m_outputSize.top\n        && newRc.right == m_outputSize.right\n        && newRc.bottom == m_outputSize.bottom)\n    {\n        return false;\n    }\n\n    m_outputSize = newRc;\n    CreateWindowSizeDependentResources();\n    return true;\n}\n\n// Recreate all device resources and set them back to the current state.\nvoid DeviceResources::HandleDeviceLost()\n{\n#ifndef _GAMING_XBOX\n    if (m_deviceNotify)\n    {\n        m_deviceNotify->OnDeviceLost();\n    }\n\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        m_commandAllocators[n].Reset();\n        m_renderTargets[n].Reset();\n    }\n\n    m_depthStencil.Reset();\n    m_commandQueue.Reset();\n    m_commandList.Reset();\n    m_fence.Reset();\n    m_rtvDescriptorHeap.Reset();\n    m_dsvDescriptorHeap.Reset();\n    m_swapChain.Reset();\n    m_d3dDevice.Reset();\n    m_dxgiFactory.Reset();\n\n#ifdef _DEBUG\n    {\n        ComPtr<IDXGIDebug1> dxgiDebug;\n        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug))))\n        {\n            dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL));\n        }\n    }\n#endif\n\n    CreateDeviceResources();\n    CreateWindowSizeDependentResources();\n\n    if (m_deviceNotify)\n    {\n        m_deviceNotify->OnDeviceRestored();\n    }\n#endif\n}\n\n// Prepare the command list and render target for rendering.\nvoid DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState)\n{\n#ifdef _GAMING_XBOX\n    // Wait until frame start is signaled\n    m_framePipelineToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL;\n    ThrowIfFailed(m_d3dDevice->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, INFINITE, nullptr, D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &m_framePipelineToken));\n#endif\n\n    // Reset command list and allocator.\n    ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset());\n    ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr));\n\n    if (beforeState != D3D12_RESOURCE_STATE_RENDER_TARGET)\n    {\n        // Transition the render target into the correct state to allow for drawing into it.\n        D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(), beforeState, D3D12_RESOURCE_STATE_RENDER_TARGET);\n        m_commandList->ResourceBarrier(1, &barrier);\n    }\n}\n\n// Present the contents of the swap chain to the screen.\nvoid DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)\n{\n    if (beforeState != D3D12_RESOURCE_STATE_PRESENT)\n    {\n        // Transition the render target to the state that allows it to be presented to the display.\n        D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(), beforeState, D3D12_RESOURCE_STATE_PRESENT);\n        m_commandList->ResourceBarrier(1, &barrier);\n    }\n\n    // Send the command list off to the GPU for processing.\n    ThrowIfFailed(m_commandList->Close());\n    m_commandQueue->ExecuteCommandLists(1, CommandListCast(m_commandList.GetAddressOf()));\n\n#ifdef _GAMING_XBOX\n\n    // Present the backbuffer using the PresentX API.\n    D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParameters = {};\n    planeParameters.Token = m_framePipelineToken;\n    planeParameters.ResourceCount = 1;\n    planeParameters.ppResources = m_renderTargets[m_backBufferIndex].GetAddressOf();\n\n    ThrowIfFailed(\n        m_commandQueue->PresentX(1, &planeParameters, nullptr)\n    );\n\n    // Xbox One apps do not need to handle DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET.\n\n#else\n\n    // The first argument instructs DXGI to block until VSync, putting the application\n    // to sleep until the next VSync. This ensures we don't waste any cycles rendering\n    // frames that will never be displayed to the screen.\n    HRESULT hr = m_swapChain->Present(1, 0);\n\n    // If the device was reset we must completely reinitialize the renderer.\n    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)\n    {\n#ifdef _DEBUG\n        char buff[64] = {};\n        sprintf_s(buff, \"Device Lost on Present: Reason code 0x%08X\\n\", (hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr);\n        OutputDebugStringA(buff);\n#endif\n        HandleDeviceLost();\n    }\n    else\n    {\n        ThrowIfFailed(hr);\n    }\n\n#endif\n\n    MoveToNextFrame();\n}\n\n// Handle GPU suspend/resume\nvoid DeviceResources::Suspend()\n{\n#ifdef _GAMING_XBOX\n    m_commandQueue->SuspendX(0);\n#endif\n}\n\nvoid DeviceResources::Resume()\n{\n#ifdef _GAMING_XBOX\n    m_commandQueue->ResumeX();\n\n    RegisterFrameEvents();\n#endif\n}\n\n// Wait for pending GPU work to complete.\nvoid DeviceResources::WaitForGpu() noexcept\n{\n    if (m_commandQueue && m_fence && m_fenceEvent.IsValid())\n    {\n        // Schedule a Signal command in the GPU queue.\n        UINT64 fenceValue = m_fenceValues[m_backBufferIndex];\n        if (SUCCEEDED(m_commandQueue->Signal(m_fence.Get(), fenceValue)))\n        {\n            // Wait until the Signal has been processed.\n            if (SUCCEEDED(m_fence->SetEventOnCompletion(fenceValue, m_fenceEvent.Get())))\n            {\n                WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE);\n\n                // Increment the fence value for the current frame.\n                m_fenceValues[m_backBufferIndex]++;\n            }\n        }\n    }\n}\n\n// Prepare to render the next frame.\nvoid DeviceResources::MoveToNextFrame()\n{\n    // Schedule a Signal command in the queue.\n    const UINT64 currentFenceValue = m_fenceValues[m_backBufferIndex];\n    ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), currentFenceValue));\n\n    // Update the back buffer index.\n#ifdef _GAMING_XBOX\n    m_backBufferIndex = (m_backBufferIndex + 1) % m_backBufferCount;\n#else\n    m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex();\n#endif\n\n    // If the next frame is not ready to be rendered yet, wait until it is ready.\n    if (m_fence->GetCompletedValue() < m_fenceValues[m_backBufferIndex])\n    {\n        ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_backBufferIndex], m_fenceEvent.Get()));\n        WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE);\n    }\n\n    // Set the fence value for the next frame.\n    m_fenceValues[m_backBufferIndex] = currentFenceValue + 1;\n}\n\n#ifdef _GAMING_XBOX\n// Set frame interval and register for frame events\nvoid DeviceResources::RegisterFrameEvents()\n{\n    // First, retrieve the underlying DXGI device from the D3D device.\n    ComPtr<IDXGIDevice1> dxgiDevice;\n    ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));\n\n    // Identify the physical adapter (GPU or card) this device is running on.\n    ComPtr<IDXGIAdapter> dxgiAdapter;\n    ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));\n\n    // Retrieve the outputs for the adapter.\n    ComPtr<IDXGIOutput> dxgiOutput;\n    ThrowIfFailed(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));\n\n    // Set frame interval and register for frame events\n    ThrowIfFailed(m_d3dDevice->SetFrameIntervalX(\n        dxgiOutput.Get(),\n        D3D12XBOX_FRAME_INTERVAL_60_HZ,\n        2 /* Allow 2 frames of latency */,\n        D3D12XBOX_FRAME_INTERVAL_FLAG_NONE));\n\n    ThrowIfFailed(m_d3dDevice->ScheduleFrameEventX(\n        D3D12XBOX_FRAME_EVENT_ORIGIN,\n        0U,\n        nullptr,\n        D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE));\n}\n#else\n// This method acquires the first available hardware adapter that supports Direct3D 12.\n// If no such adapter can be found, try WARP. Otherwise throw an exception.\nvoid DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)\n{\n    *ppAdapter = nullptr;\n\n    ComPtr<IDXGIAdapter1> adapter;\n    for (UINT adapterIndex = 0;\n        SUCCEEDED(m_dxgiFactory->EnumAdapterByGpuPreference(\n            adapterIndex,\n            DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,\n            IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf())));\n        adapterIndex++)\n    {\n        DXGI_ADAPTER_DESC1 desc;\n        ThrowIfFailed(adapter->GetDesc1(&desc));\n\n        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)\n        {\n            // Don't select the Basic Render Driver adapter.\n            continue;\n        }\n\n        // Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.\n        if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))\n        {\n#ifdef _DEBUG\n            wchar_t buff[256] = {};\n            swprintf_s(buff, L\"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\\n\", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);\n            OutputDebugStringW(buff);\n#endif\n            break;\n        }\n    }\n\n#if !defined(NDEBUG)\n    if (!adapter)\n    {\n        // Try WARP12 instead\n        if (FAILED(m_dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf()))))\n        {\n            throw std::exception(\"WARP12 not available. Enable the 'Graphics Tools' optional feature\");\n        }\n\n        OutputDebugStringA(\"Direct3D Adapter - WARP12\\n\");\n    }\n#endif\n\n    if (!adapter)\n    {\n        throw std::exception(\"No Direct3D 12 device found\");\n    }\n\n    *ppAdapter = adapter.Detach();\n}\n#endif"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/DeviceResources.h",
    "content": "﻿//\n// DeviceResources.h - A wrapper for the Direct3D 12/12.X device and swapchain\n//\n\n#pragma once\n\nnamespace DX\n{\n    // Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created.\n    interface IDeviceNotify\n    {\n        virtual void OnDeviceLost() = 0;\n        virtual void OnDeviceRestored() = 0;\n\n    protected:\n        ~IDeviceNotify() = default;\n    };\n\n    // Controls all the DirectX device resources.\n    class DeviceResources\n    {\n    public:\n        DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM,\n                        DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT,\n                        UINT backBufferCount = 2) noexcept(false);\n        ~DeviceResources();\n\n        void CreateDeviceResources();\n        void CreateWindowSizeDependentResources();\n        void SetWindow(HWND window, int width, int height);\n        bool WindowSizeChanged(int width, int height);\n        void HandleDeviceLost();\n        void RegisterDeviceNotify(IDeviceNotify* deviceNotify) { m_deviceNotify = deviceNotify; }\n        void SetWindow(HWND window) { m_window = window; }\n        void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT);\n        void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET);\n        void Suspend();\n        void Resume();\n        void WaitForGpu() noexcept;\n\n        // Device Accessors.\n        RECT GetOutputSize() const { return m_outputSize; }\n\n        // Direct3D Accessors.\n        ID3D12Device*               GetD3DDevice() const            { return m_d3dDevice.Get(); }\n#ifndef _GAMING_XBOX\n        IDXGISwapChain3*            GetSwapChain() const            { return m_swapChain.Get(); }\n        IDXGIFactory6*              GetDXGIFactory() const          { return m_dxgiFactory.Get(); }\n#endif\n        D3D_FEATURE_LEVEL           GetDeviceFeatureLevel() const   { return m_d3dFeatureLevel; }\n        ID3D12Resource*             GetRenderTarget() const         { return m_renderTargets[m_backBufferIndex].Get(); }\n        ID3D12Resource*             GetDepthStencil() const         { return m_depthStencil.Get(); }\n        ID3D12CommandQueue*         GetCommandQueue() const         { return m_commandQueue.Get(); }\n        ID3D12CommandAllocator*     GetCommandAllocator() const     { return m_commandAllocators[m_backBufferIndex].Get(); }\n        ID3D12GraphicsCommandList*  GetCommandList() const          { return m_commandList.Get(); }\n        DXGI_FORMAT                 GetBackBufferFormat() const     { return m_backBufferFormat; }\n        DXGI_FORMAT                 GetDepthBufferFormat() const    { return m_depthBufferFormat; }\n        D3D12_VIEWPORT              GetScreenViewport() const       { return m_screenViewport; }\n        D3D12_RECT                  GetScissorRect() const          { return m_scissorRect; }\n        UINT                        GetCurrentFrameIndex() const    { return m_backBufferIndex; }\n        UINT                        GetBackBufferCount() const      { return m_backBufferCount; }\n\n        CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const\n        {\n            return CD3DX12_CPU_DESCRIPTOR_HANDLE(\n                m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),\n                static_cast<INT>(m_backBufferIndex), m_rtvDescriptorSize);\n        }\n        CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const\n        {\n            return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());\n        }\n\n    private:\n        void MoveToNextFrame();\n#ifdef _GAMING_XBOX\n        void RegisterFrameEvents();\n#else\n        void GetAdapter(IDXGIAdapter1** ppAdapter);\n#endif\n\n        static const size_t MAX_BACK_BUFFER_COUNT = 3;\n\n        UINT                                                m_backBufferIndex;\n\n        // Direct3D objects.\n        Microsoft::WRL::ComPtr<ID3D12Device>                m_d3dDevice;\n        Microsoft::WRL::ComPtr<ID3D12CommandQueue>          m_commandQueue;\n        Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList>   m_commandList;\n        Microsoft::WRL::ComPtr<ID3D12CommandAllocator>      m_commandAllocators[MAX_BACK_BUFFER_COUNT];\n\n        // Swap chain objects.\n#ifndef _GAMING_XBOX\n        Microsoft::WRL::ComPtr<IDXGIFactory6>               m_dxgiFactory;\n        Microsoft::WRL::ComPtr<IDXGISwapChain3>             m_swapChain;\n#endif\n        Microsoft::WRL::ComPtr<ID3D12Resource>              m_renderTargets[MAX_BACK_BUFFER_COUNT];\n        Microsoft::WRL::ComPtr<ID3D12Resource>              m_depthStencil;\n\n        // Presentation fence objects.\n        Microsoft::WRL::ComPtr<ID3D12Fence>                 m_fence;\n        UINT64                                              m_fenceValues[MAX_BACK_BUFFER_COUNT];\n        Microsoft::WRL::Wrappers::Event                     m_fenceEvent;\n#ifdef _GAMING_XBOX\n        D3D12XBOX_FRAME_PIPELINE_TOKEN                      m_framePipelineToken;\n#endif\n\n        // Direct3D rendering objects.\n        Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>        m_rtvDescriptorHeap;\n        Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>        m_dsvDescriptorHeap;\n        UINT                                                m_rtvDescriptorSize;\n        D3D12_VIEWPORT                                      m_screenViewport;\n        D3D12_RECT                                          m_scissorRect;\n\n        // Direct3D properties.\n        DXGI_FORMAT                                         m_backBufferFormat;\n        DXGI_FORMAT                                         m_depthBufferFormat;\n        UINT                                                m_backBufferCount;\n\n        // Cached device properties.\n        HWND                                                m_window;\n        D3D_FEATURE_LEVEL                                   m_d3dFeatureLevel;\n        RECT                                                m_outputSize;\n\n        // The IDeviceNotify can be held directly as it owns the DeviceResources.\n        IDeviceNotify*                                      m_deviceNotify;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/ATGColors.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: ATGColors.h\n//\n// Definitions of the standard ATG color palette.\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <DirectXMath.h>\n\n\nnamespace ATG\n{\n    namespace Colors\n    {\n        XMGLOBALCONST DirectX::XMVECTORF32 Background = { { { 0.254901975f, 0.254901975f, 0.254901975f, 1.f } } }; // #414141\n        XMGLOBALCONST DirectX::XMVECTORF32 Green      = { { { 0.062745102f, 0.486274511f, 0.062745102f, 1.f } } }; // #107c10\n        XMGLOBALCONST DirectX::XMVECTORF32 Blue       = { { { 0.019607844f, 0.372549027f, 0.803921580f, 1.f } } }; // #055fcd\n        XMGLOBALCONST DirectX::XMVECTORF32 Orange     = { { { 0.764705896f, 0.176470593f, 0.019607844f, 1.f } } }; // #c32d05\n        XMGLOBALCONST DirectX::XMVECTORF32 DarkGrey   = { { { 0.200000003f, 0.200000003f, 0.200000003f, 1.f } } }; // #333333\n        XMGLOBALCONST DirectX::XMVECTORF32 LightGrey  = { { { 0.478431374f, 0.478431374f, 0.478431374f, 1.f } } }; // #7a7a7a\n        XMGLOBALCONST DirectX::XMVECTORF32 OffWhite   = { { { 0.635294139f, 0.635294139f, 0.635294139f, 1.f } } }; // #a2a2a2\n        XMGLOBALCONST DirectX::XMVECTORF32 White      = { { { 0.980392158f, 0.980392158f, 0.980392158f, 1.f } } }; // #fafafa\n    };\n\n    namespace ColorsLinear\n    {\n        XMGLOBALCONST DirectX::XMVECTORF32 Background = { { { 0.052860655f, 0.052860655f, 0.052860655f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 Green      = { { { 0.005181516f, 0.201556236f, 0.005181516f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 Blue       = { { { 0.001517635f, 0.114435382f, 0.610495627f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 Orange     = { { { 0.545724571f, 0.026241219f, 0.001517635f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 DarkGrey   = { { { 0.033104762f, 0.033104762f, 0.033104762f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 LightGrey  = { { { 0.194617808f, 0.194617808f, 0.194617808f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 OffWhite   = { { { 0.361306787f, 0.361306787f, 0.361306787f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 White      = { { { 0.955973506f, 0.955973506f, 0.955973506f, 1.f } } };\n    };\n\n    namespace ColorsHDR\n    {\n        XMGLOBALCONST DirectX::XMVECTORF32 Background = { { { 0.052860655f * 2.f, 0.052860655f * 2.f, 0.052860655f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 Green      = { { { 0.005181516f * 2.f, 0.201556236f * 2.f, 0.005181516f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 Blue       = { { { 0.001517635f * 2.f, 0.114435382f * 2.f, 0.610495627f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 Orange     = { { { 0.545724571f * 2.f, 0.026241219f * 2.f, 0.001517635f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 DarkGrey   = { { { 0.033104762f * 2.f, 0.033104762f * 2.f, 0.033104762f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 LightGrey  = { { { 0.194617808f * 2.f, 0.194617808f * 2.f, 0.194617808f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 OffWhite   = { { { 0.361306787f * 2.f, 0.361306787f * 2.f, 0.361306787f * 2.f, 1.f } } };\n        XMGLOBALCONST DirectX::XMVECTORF32 White      = { { { 0.955973506f * 2.f, 0.955973506f * 2.f, 0.955973506f * 2.f, 1.f } } };\n    };\n}"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/CSVReader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: CSVReader.h\n//\n// Simple parser for .csv (Comma-Separated Values) files.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <exception>\n#include <memory>\n#include <vector>\n\n\nnamespace DX\n{\n    class CSVReader\n    {\n    public:\n        enum class Encoding\n        {\n            UTF16,  // File is Unicode UTF-16\n            UTF8,   // File is Unicode UTF-8\n        };\n\n        explicit CSVReader(_In_z_ const wchar_t* fileName, Encoding encoding = Encoding::UTF8, bool ignoreComments = false) :\n            m_end(nullptr),\n            m_currentChar(nullptr),\n            m_currentLine(0),\n            m_ignoreComments(ignoreComments)\n        {\n            assert(fileName != 0);\n\n#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)\n            ScopedHandle hFile(safe_handle(CreateFile2(fileName,\n                GENERIC_READ,\n                FILE_SHARE_READ,\n                OPEN_EXISTING,\n                nullptr)));\n#else\n            ScopedHandle hFile(safe_handle(CreateFileW(fileName,\n                GENERIC_READ,\n                FILE_SHARE_READ,\n                nullptr,\n                OPEN_EXISTING,\n                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,\n                nullptr)));\n#endif\n            if (!hFile)\n            {\n                throw std::exception(\"CreateFile\");\n            }\n\n            FILE_STANDARD_INFO fileInfo;\n            if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n            {\n                throw std::exception(\"GetFileInformationByHandleEx\");\n            }\n\n            if (fileInfo.EndOfFile.HighPart > 0 || fileInfo.EndOfFile.LowPart > 0x7ffffffd)\n            {\n                // File is 2 GBs or larger\n                throw std::exception(\"CSV too large\");\n            }\n\n            auto data = std::make_unique<uint8_t[]>(fileInfo.EndOfFile.LowPart + 2);\n\n            DWORD out;\n            if (!ReadFile(hFile.get(), data.get(), fileInfo.EndOfFile.LowPart, &out, nullptr)\n                || out != fileInfo.EndOfFile.LowPart)\n            {\n                throw std::exception(\"ReadFile\");\n            }\n\n            // Ensure buffer is nul terminated\n            data[out] = data[out + 1] = '\\0';\n\n            // Ignore lines in .csv that start with '#' character\n\n            // Handle text encoding\n            if (encoding == Encoding::UTF16)\n            {\n                m_data.reset(reinterpret_cast<wchar_t*>(data.release()));\n                m_end = reinterpret_cast<wchar_t*>(&data[out]);\n            }\n            else\n            {\n                // If we are not UTF16, we have to convert...\n                int cch = ::MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<LPCSTR>(data.get()), -1, nullptr, 0);\n\n                if (cch <= 0)\n                {\n                    throw std::exception(\"MultiByteToWideChar\");\n                }\n\n                m_data.reset(new wchar_t[size_t(cch)]);\n\n                int result = ::MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<LPCSTR>(data.get()), -1, m_data.get(), cch);\n\n                if (result <= 0)\n                {\n                    m_data.reset();\n                    throw std::exception(\"MultiByteToWideChar\");\n                }\n\n                m_end = &m_data[size_t(result - 1)];\n            }\n\n            // Locate the start of lines\n            bool newline = true;\n            for (const wchar_t* ptr = m_data.get(); *ptr != 0 && ptr < m_end; )\n            {\n                if (*ptr == '\\n' || *ptr == '\\r')\n                {\n                    ++ptr;\n                    newline = true;\n                }\n                else if (*ptr == '#' && m_ignoreComments && newline)\n                {\n                    // Skip to CR\n                    for (; *ptr != 0 && *ptr != '\\n' && ptr < m_end; ++ptr) {}\n                }\n                else if (*ptr == '\"')\n                {\n                    if (newline)\n                    {\n                        m_lines.push_back(ptr);\n                        newline = false;\n                    }\n\n                    // Skip to next \" (skipping \"\" escapes)\n                    for (ptr++; *ptr != 0 && ptr < m_end; ++ptr)\n                    {\n                        if (*ptr == '\"')\n                        {\n                            ++ptr;\n                            if (*ptr != '\"')\n                                break;\n                        }\n                    }\n                }\n                else if (newline)\n                {\n                    m_lines.push_back(ptr);\n                    newline = false;\n                    ++ptr;\n                }\n                else\n                    ++ptr;\n            }\n\n            TopOfFile();\n        }\n\n        CSVReader(const CSVReader&) = delete;\n        CSVReader& operator=(const CSVReader&) = delete;\n\n        // Return number of lines of data in CSV\n        size_t GetRecordCount() const { return m_lines.size(); }\n\n        // Check for end of file\n        bool EndOfFile() const { return m_currentChar == nullptr; }\n\n        // Return current record number (0-based)\n        size_t RecordIndex() const { return m_currentLine; }\n\n        // Set to top of file\n        void TopOfFile()\n        {\n            m_currentChar = (m_lines.empty()) ? nullptr : m_lines[0];\n            m_currentLine = 0;\n        }\n\n        // Start processing next record (returns false when out of data)\n        bool NextRecord()\n        {\n            if (!m_currentChar)\n                return false;\n\n            if (++m_currentLine >= m_lines.size())\n            {\n                m_currentChar = nullptr;\n                return false;\n            }\n\n            m_currentChar = m_lines[m_currentLine];\n\n            return true;\n        }\n\n        // Get next item in record (returns false when reached end of record)\n        bool NextItem(_Out_writes_(maxstr) wchar_t* str, _In_ size_t maxstr)\n        {\n            if (!str || !m_currentChar || !maxstr)\n                return false;\n\n            *str = L'\\0';\n\n            const wchar_t* end = ((m_currentLine + 1) >= m_lines.size()) ? m_end : (m_lines[(m_currentLine + 1)]);\n\n            if (m_currentChar >= end)\n                return false;\n\n            wchar_t* dest = str;\n            wchar_t* edest = str + maxstr;\n\n            for (const wchar_t* ptr = m_currentChar; ; )\n            {\n                if (*ptr == 0 || ptr >= end || *ptr == '\\n' || *ptr == '\\r')\n                {\n                    m_currentChar = end;\n                    break;\n                }\n                else if (*ptr == ',')\n                {\n                    m_currentChar = ptr + 1;\n                    break;\n                }\n                else if (*ptr == '\\t' || *ptr == ' ')\n                {\n                    // Whitespace\n                    ++ptr;\n                }\n                else if (*ptr == '\"')\n                {\n                    // Copy from \" to \", respecting \"\" as double-quotes\n                    for (ptr++; *ptr != 0 && ptr < end; ++ptr)\n                    {\n                        if (*ptr == '\"')\n                        {\n                            ++ptr;\n                            if (*ptr != '\"')\n                                break;\n                            else if (dest < edest)\n                                *(dest++) = '\"';\n                        }\n                        else if (dest < edest)\n                            *(dest++) = *ptr;\n                    }\n                }\n                else\n                {\n                    for (; *ptr != 0 && ptr < end; ++ptr)\n                    {\n                        if (*ptr == '\\n' || *ptr == '\\r' || *ptr == ',')\n                            break;\n                        else if (dest < edest)\n                            *(dest++) = *ptr;\n                    }\n                }\n            }\n\n            if (dest < edest)\n                *dest = 0;\n\n            return true;\n        }\n\n        template<size_t TNameLength>\n        bool NextItem(wchar_t(&name)[TNameLength])\n        {\n            return NextItem(name, TNameLength);\n        }\n\n    private:\n        struct handle_closer { void operator()(HANDLE h) { if (h) CloseHandle(h); } };\n\n        typedef std::unique_ptr<void, handle_closer> ScopedHandle;\n\n        inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }\n\n        std::unique_ptr<wchar_t[]>  m_data;\n        const wchar_t*              m_end;\n        const wchar_t*              m_currentChar;\n        size_t                      m_currentLine;\n        bool                        m_ignoreComments;\n        std::vector<const wchar_t*> m_lines;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/ControllerFont.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: ControllerFont.h\n//\n// Class for compositing text with Xbox controller font button sprites\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\n\nnamespace DX\n{\n    enum class ControllerFont : wchar_t\n    {\n        LeftThumb = L' ',\n        DPad = L'!',\n        RightThumb = L'\\\"',\n        View = L'#',\n        Nexus = L'$',\n        Menu = L'%',\n        XButton = L'&',\n        AButton = L'\\'',\n        YButton = L'(',\n        BButton = L')',\n        RightShoulder = L'*',\n        RightTrigger = L'+',\n        LeftTrigger = L',',\n        LeftShoulder = L'-',\n    };\n\n    inline void XM_CALLCONV DrawControllerString(_In_ DirectX::SpriteBatch* spriteBatch, _In_ DirectX::SpriteFont* textFont, _In_ DirectX::SpriteFont* butnFont,\n        _In_z_ wchar_t const* text, DirectX::XMFLOAT2 const& position, DirectX::FXMVECTOR color = DirectX::Colors::White, float scale = 1)\n    {\n        using namespace DirectX;\n\n        size_t textLen = wcslen(text);\n        if (textLen >= 4096)\n        {\n            throw std::out_of_range(\"String is too long\");\n        }\n\n        float buttonHeight = butnFont->GetLineSpacing();\n        float buttonScale = (textFont->GetLineSpacing() * scale) / buttonHeight;\n        float offsetY = buttonScale / 2.f;\n\n        size_t j = 0;\n        wchar_t strBuffer[4096] = {};\n\n        bool buttonText = false;\n\n        XMFLOAT2 outPos = position;\n\n        for (size_t ch = 0; ch < textLen; ++ch)\n        {\n            if (buttonText)\n            {\n                strBuffer[j++] = text[ch];\n\n                if (text[ch] == L']')\n                {\n                    wchar_t button[2] = {};\n\n                    if (_wcsicmp(strBuffer, L\"[A]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::AButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[B]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::BButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[X]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::XButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[Y]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::YButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[DPad]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::DPad);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[View]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::View);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[Menu]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::Menu);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[Nexus]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::Nexus);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[RThumb]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::RightThumb);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[LThumb]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::LeftThumb);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[RB]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::RightShoulder);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[LB]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::LeftShoulder);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[RT]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::RightTrigger);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[LT]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::LeftTrigger);\n                    }\n\n                    if (*button)\n                    {\n                        float bsize = XMVectorGetX(butnFont->MeasureString(button));\n                        float offsetX = (bsize * buttonScale / 2.f);\n\n                        outPos.x += offsetX;\n                        outPos.y -= offsetY;\n                        butnFont->DrawString(spriteBatch, button, outPos, Colors::White, 0.f, XMFLOAT2(0.f, 0.f), XMFLOAT2(buttonScale, buttonScale));\n                        outPos.x += bsize * buttonScale;\n                        outPos.y += offsetY;\n                    }\n\n                    memset(strBuffer, 0, sizeof(strBuffer));\n                    j = 0;\n\n                    buttonText = false;\n                }\n            }\n            else\n            {\n                switch (text[ch])\n                {\n                case '\\r':\n                    break;\n\n                case '[':\n                    if (*strBuffer)\n                    {\n                        textFont->DrawString(spriteBatch, strBuffer, outPos, color, 0.f, XMFLOAT2(0.f, 0.f), XMFLOAT2(scale, scale));\n                        outPos.x += XMVectorGetX(textFont->MeasureString(strBuffer)) * scale;\n                        memset(strBuffer, 0, sizeof(strBuffer));\n                        j = 0;\n                    }\n                    buttonText = true;\n                    *strBuffer = L'[';\n                    ++j;\n                    break;\n\n                case '\\n':\n                    if (*strBuffer)\n                    {\n                        textFont->DrawString(spriteBatch, strBuffer, outPos, color, 0.f, XMFLOAT2(0.f, 0.f), XMFLOAT2(scale, scale));\n                        memset(strBuffer, 0, sizeof(strBuffer));\n                        j = 0;\n                    }\n                    outPos.x = position.x;\n                    outPos.y += textFont->GetLineSpacing() * scale;\n                    break;\n\n                default:\n                    strBuffer[j++] = text[ch];\n                    break;\n                }\n            }\n        }\n\n        if (*strBuffer)\n        {\n            textFont->DrawString(spriteBatch, strBuffer, outPos, color, 0.f, XMFLOAT2(0.f, 0.f), XMFLOAT2(scale, scale));\n        }\n    }\n\n    inline RECT XM_CALLCONV MeasureControllerDrawBounds(_In_ DirectX::SpriteFont* textFont, _In_ DirectX::SpriteFont* butnFont,\n        _In_z_ wchar_t const* text, DirectX::XMFLOAT2 const& position, float scale = 1)\n    {\n        using namespace DirectX;\n\n        size_t textLen = wcslen(text);\n        if (textLen >= 4096)\n        {\n            throw std::out_of_range(\"String is too long\");\n        }\n\n        float buttonHeight = butnFont->GetLineSpacing();\n        float buttonScale = (textFont->GetLineSpacing() * scale) / buttonHeight;\n        float offsetY = buttonScale / 2.f;\n\n        size_t j = 0;\n        wchar_t strBuffer[4096] = {};\n\n        bool buttonText = false;\n\n        XMFLOAT2 outPos = position;\n\n        RECT result = { LONG_MAX, LONG_MAX, 0, 0 };\n        for (size_t ch = 0; ch < textLen; ++ch)\n        {\n            if (buttonText)\n            {\n                strBuffer[j++] = text[ch];\n\n                if (text[ch] == L']')\n                {\n                    wchar_t button[2] = {};\n\n                    if (_wcsicmp(strBuffer, L\"[A]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::AButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[B]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::BButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[X]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::XButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[Y]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::YButton);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[DPad]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::DPad);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[View]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::View);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[Menu]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::Menu);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[Nexus]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::Nexus);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[RThumb]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::RightThumb);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[LThumb]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::LeftThumb);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[RB]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::RightShoulder);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[LB]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::LeftShoulder);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[RT]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::RightTrigger);\n                    }\n                    else if (_wcsicmp(strBuffer, L\"[LT]\") == 0)\n                    {\n                        *button = static_cast<wchar_t>(ControllerFont::LeftTrigger);\n                    }\n\n                    if (*button)\n                    {\n                        float bsize = XMVectorGetX(butnFont->MeasureString(button));\n                        float offsetX = (bsize * buttonScale / 2.f);\n\n                        if (outPos.x < float(result.left))\n                            result.left = long(outPos.x);\n\n                        if (outPos.y < float(result.top))\n                            result.top = long(outPos.y);\n\n                        outPos.x += offsetX;\n                        outPos.y -= offsetY;\n\n                        if (outPos.x < float(result.left))\n                            result.left = long(outPos.x);\n\n                        if (outPos.y < float(result.top))\n                            result.top = long(outPos.y);\n\n                        outPos.x += bsize * buttonScale;\n                        outPos.y += offsetY;\n\n                        if (float(result.right) < outPos.x)\n                            result.right = long(outPos.x);\n\n                        if (float(result.bottom) < outPos.y)\n                            result.bottom = long(outPos.y);\n                    }\n\n                    memset(strBuffer, 0, sizeof(strBuffer));\n                    j = 0;\n\n                    buttonText = false;\n                }\n            }\n            else\n            {\n                switch (text[ch])\n                {\n                case '\\r':\n                    break;\n\n                case '[':\n                    if (*strBuffer)\n                    {\n                        if (outPos.x < float(result.left))\n                            result.left = long(outPos.x);\n\n                        if (outPos.y < float(result.top))\n                            result.top = long(outPos.y);\n\n                        outPos.x += XMVectorGetX(textFont->MeasureString(strBuffer)) * scale;\n\n                        if (float(result.right) < outPos.x)\n                            result.right = long(outPos.x);\n\n                        if (float(result.bottom) < outPos.y)\n                            result.bottom = long(outPos.y);\n\n                        memset(strBuffer, 0, sizeof(strBuffer));\n                        j = 0;\n                    }\n                    buttonText = true;\n                    *strBuffer = L'[';\n                    ++j;\n                    break;\n\n                case '\\n':\n                    if (*strBuffer)\n                    {\n                        if (outPos.x < float(result.left))\n                            result.left = long(outPos.x);\n\n                        if (outPos.y < float(result.top))\n                            result.top = long(outPos.y);\n\n                        outPos.x += XMVectorGetX(textFont->MeasureString(strBuffer)) * scale;\n\n                        if (float(result.right) < outPos.x)\n                            result.right = long(outPos.x);\n\n                        if (float(result.bottom) < outPos.y)\n                            result.bottom = long(outPos.y);\n\n                        memset(strBuffer, 0, sizeof(strBuffer));\n                        j = 0;\n                    }\n                    outPos.x = position.x;\n                    outPos.y += textFont->GetLineSpacing() * scale;\n                    break;\n\n                default:\n                    strBuffer[j++] = text[ch];\n                    break;\n                }\n            }\n        }\n\n        if (*strBuffer)\n        {\n            if (outPos.x < float(result.left))\n                result.left = long(outPos.x);\n\n            if (outPos.y < float(result.top))\n                result.top = long(outPos.y);\n\n            outPos.x += XMVectorGetX(textFont->MeasureString(strBuffer)) * scale;\n\n            if (float(result.right) < outPos.x)\n                result.right = long(outPos.x);\n\n            if (float(result.bottom) < outPos.y)\n                result.bottom = long(outPos.y);\n        }\n\n        if (result.left == LONG_MAX)\n        {\n            result.left = 0;\n            result.top = 0;\n        }\n\n        return result;\n    }\n}"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/FindMedia.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: FindMedia.h\n//\n// Helper function to find the location of a media file for Windows desktop apps\n// since they lack appx packaging support.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <exception>\n#include <string.h>\n\n\nnamespace DX\n{\n    inline void FindMediaFile(\n        _Out_writes_(cchDest) wchar_t* strDestPath,\n        _In_ int cchDest,\n        _In_z_ const wchar_t* strFilename,\n        _In_opt_ const wchar_t* const * searchFolders = nullptr)\n    {\n        if (!strFilename || strFilename[0] == 0 || !strDestPath || cchDest < 10)\n            throw std::invalid_argument(\"FindMediaFile\");\n\n        // Check CWD for quick out\n        wcscpy_s(strDestPath, size_t(cchDest), strFilename);\n        if (GetFileAttributesW(strDestPath) != 0xFFFFFFFF)\n            return;\n\n        // Search CWD with folder names\n        static const wchar_t* s_defSearchFolders[] =\n        {\n            L\"Assets\",\n            L\"Media\",\n            L\"Media\\\\Textures\",\n            L\"Media\\\\Fonts\",\n            L\"Media\\\\Meshes\",\n            L\"Media\\\\PBR\",\n            L\"Media\\\\CubeMaps\",\n            L\"Media\\\\HDR\",\n            L\"Media\\\\Sounds\",\n            L\"Media\\\\Videos\",\n            0\n        };\n\n        if (!searchFolders)\n            searchFolders = s_defSearchFolders;\n\n        wchar_t strFullFileName[MAX_PATH] = {};\n        for (const wchar_t* const * searchFolder = searchFolders; *searchFolder != 0; ++searchFolder)\n        {\n            swprintf_s(strFullFileName, MAX_PATH, L\"%ls\\\\%ls\", *searchFolder, strFilename);\n            if (GetFileAttributesW(strFullFileName) != 0xFFFFFFFF)\n            {\n                wcscpy_s(strDestPath, size_t(cchDest), strFullFileName);\n                return;\n            }\n        }\n\n        // Get the exe name, and exe path\n        wchar_t strExePath[MAX_PATH] = {};\n        GetModuleFileNameW(nullptr, strExePath, MAX_PATH);\n        strExePath[MAX_PATH - 1] = 0;\n\n        // Search all parent directories starting at .\\ and using strFilename as the leaf name\n        wchar_t strLeafName[MAX_PATH] = {};\n        wcscpy_s(strLeafName, MAX_PATH, strFilename);\n\n        wchar_t strFullPath[MAX_PATH] = {};\n        wchar_t strSearch[MAX_PATH] = {};\n        wchar_t* strFilePart = nullptr;\n\n        GetFullPathNameW(strExePath, MAX_PATH, strFullPath, &strFilePart);\n\n        while (strFilePart && *strFilePart != '\\0')\n        {\n            swprintf_s(strFullFileName, MAX_PATH, L\"%ls\\\\%ls\", strFullPath, strLeafName);\n            if (GetFileAttributesW(strFullFileName) != 0xFFFFFFFF)\n            {\n                wcscpy_s(strDestPath, size_t(cchDest), strFullFileName);\n                return;\n            }\n\n            for (const wchar_t* const * searchFolder = searchFolders; *searchFolder != 0; ++searchFolder)\n            {\n                swprintf_s(strFullFileName, MAX_PATH, L\"%ls\\\\%ls\\\\%ls\", strFullPath, *searchFolder, strLeafName);\n                if (GetFileAttributesW(strFullFileName) != 0xFFFFFFFF)\n                {\n                    wcscpy_s(strDestPath, size_t(cchDest), strFullFileName);\n                    return;\n                }\n            }\n\n            swprintf_s(strSearch, MAX_PATH, L\"%ls\\\\..\", strFullPath);\n            GetFullPathNameW(strSearch, MAX_PATH, strFullPath, &strFilePart);\n        }\n\n        // On failure, return the file as the path but also throw an error\n        wcscpy_s(strDestPath, size_t(cchDest), strFilename);\n\n        throw std::exception(\"File not found\");\n    }\n}"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/Json.h",
    "content": "//--------------------------------------------------------------------------------------\n// Json.h\n//\n// Header to include the JSON serializer/deserializer found @ https://github.com/nlohmann/json\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#endif\n\n#pragma warning(push)\n#pragma warning(disable : 4061)\n\n#include \"json/json.hpp\"\n\nusing json = nlohmann::json;\n\n#pragma warning(pop)\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/SampleGUI.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SampleGUI.cpp\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"SampleGUI.h\"\n\n#include <exception>\n#include <list>\n#include <map>\n#include <stdexcept>\n#include <string>\n#include <vector>\n\n#include <DirectXPackedVector.h>\n\n#include \"Effects.h\"\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n#include \"CommonStates.h\"\n#include \"DirectXHelpers.h\"\n#include \"RenderTargetState.h\"\n#endif\n\n#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n#include \"FindMedia.h\"\n#endif\n\n// Other required ATG Tool Kit components\n#include \"ControllerFont.h\"\n#include \"CSVReader.h\"\n\nusing namespace DirectX;\nusing namespace ATG;\n\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    const float c_HoldTimeStart = 1.f;\n    const float c_HoldTimeRepeat = .1f;\n    const float c_KeypressRepeatDelay = .05f;\n\n    const long c_ScrollWidth = 16;\n    const long c_MinThumbSize = 8;\n    const long c_BorderSize = 6;\n    const long c_MarginSize = 5;\n\n\n\n    inline void DebugTrace(_In_z_ _Printf_format_string_ const char* format, ...)\n    {\n#ifdef _DEBUG\n        va_list args;\n        va_start(args, format);\n\n        char buff[1024] = {};\n        vsprintf_s(buff, format, args);\n        OutputDebugStringA(buff);\n        va_end(args);\n#else\n        UNREFERENCED_PARAMETER(format);\n#endif\n    }\n\n    IControl* InitFocus(std::vector<IControl*>& controls)\n    {\n        IControl *firstCtrl = nullptr;\n        IControl* defaultCtrl = nullptr;\n\n        for (IControl* it : controls)\n        {\n            assert(it != nullptr);\n            _Analysis_assume_(it != nullptr);\n\n            if (!it->CanFocus())\n                continue;\n\n            if (!firstCtrl)\n            {\n                firstCtrl = it;\n            }\n\n            if (!defaultCtrl && it->DefaultFocus())\n            {\n                defaultCtrl = it;\n                break;\n            }\n        }\n\n        return (defaultCtrl) ? defaultCtrl : firstCtrl;\n    }\n\n    IControl* NextFocus(_In_opt_ IControl* currentFocus, std::vector<IControl*>& controls)\n    {\n        if (!currentFocus)\n            return nullptr;\n\n        auto it = std::find(controls.cbegin(), controls.cend(), currentFocus);\n        if (it == controls.cend())\n            throw std::exception(\"NextFocus\");\n\n        for (;;)\n        {\n            ++it;\n            if (it == controls.cend())\n                it = controls.cbegin();\n\n            if (currentFocus == *it)\n                return currentFocus;\n\n            if ( (*it)->CanFocus())\n            {\n                currentFocus->OnFocus(false);\n                (*it)->OnFocus(true);\n                return *it;\n            }\n        }\n    }\n\n    IControl* PrevFocus(_In_opt_ IControl* currentFocus, std::vector<IControl*>& controls)\n    {\n        if (!currentFocus)\n            return nullptr;\n\n        auto it = std::find(controls.cbegin(), controls.cend(), currentFocus);\n        if (it == controls.cend())\n            throw std::exception(\"PrevFocus\");\n\n        for (;;)\n        {\n            if (it == controls.cbegin())\n                it = controls.end() - 1;\n            else\n                --it;\n\n            if (currentFocus == *it)\n                return currentFocus;\n\n            if ((*it)->CanFocus())\n            {\n                currentFocus->OnFocus(false);\n                (*it)->OnFocus(true);\n                return *it;\n            }\n        }\n    }\n\n    IControl* MouseFocus(int x, int y, _In_opt_ IControl* currentFocus, std::vector<IControl*>& controls)\n    {\n        if (!currentFocus)\n            return nullptr;\n\n        for (auto it : controls)\n        {\n            assert(it != nullptr);\n            _Analysis_assume_(it != nullptr);\n\n            if (it->CanFocus() && it->Contains(x,y))\n            {\n                if (currentFocus != it)\n                {\n                    if (currentFocus)\n                    {\n                        currentFocus->OnFocus(false);\n                    }\n                    it->OnFocus(true);\n                    return it;\n                }\n            }\n        }\n\n        return currentFocus;\n    }\n\n    IControl* HotKeyFocus(_In_opt_ IControl* currentFocus, std::vector<IControl*>& controls, const Keyboard::KeyboardStateTracker& kbstate)\n    {\n        for (auto it : controls)\n        {\n            assert(it != nullptr);\n            _Analysis_assume_(it != nullptr);\n\n            unsigned hotkey = it->GetHotKey();\n            if (hotkey != 0)\n            {\n                if (kbstate.IsKeyPressed(static_cast<Keyboard::Keys>(hotkey)))\n                {\n                    if (currentFocus == it)\n                    {\n                        return it;\n                    }\n                    else if (it->CanFocus())\n                    {\n                        if (currentFocus)\n                        {\n                            currentFocus->OnFocus(false);\n                            it->OnFocus(true);\n                        }\n                        return it;\n                    }\n                }\n            }\n        }\n\n        return nullptr;\n    }\n\n    IControl* SetFocusCtrl(_In_opt_ IControl* currentFocus, _In_ IControl* newFocus)\n    {\n        if (!newFocus)\n            return currentFocus;\n\n        if (!newFocus->CanFocus())\n        {\n            DebugTrace(\"WARNING: SetFocus control (%u) cannot be focus, ignored.\\n\", newFocus->GetId());\n            return currentFocus;\n        }\n\n        if (currentFocus)\n        {\n            currentFocus->OnFocus(false);\n        }\n\n        newFocus->OnFocus(true);\n        return newFocus;\n    }\n\n    void ControlSelected(_In_opt_ IControl *ctrl, _In_ IPanel* panel)\n    {\n        if (!ctrl)\n            return;\n\n        if (ctrl->OnSelected(panel))\n        {\n            panel->Close();\n        }\n    }\n\n    void TrimTrailingWhitespace(_Inout_z_ wchar_t* str)\n    {\n        size_t len = wcslen(str);\n        for(wchar_t *ptr = str + len; len > 0; --len, --ptr)\n        {\n            if (!iswspace( *(ptr-1) ))\n            {\n                *ptr = 0;\n                break;\n            }\n        }\n    }\n\n    std::wstring WordWrap( _In_z_ const wchar_t* text, _In_ SpriteFont* font, const RECT& rect, std::vector<size_t>* lineStarts = nullptr)\n    {\n        if (lineStarts)\n        {\n            lineStarts->clear();\n            if (*text)\n                lineStarts->push_back(0);\n        }\n\n        std::wstring str;\n        str.reserve(wcslen(text));\n\n        size_t line_start = 0;\n        size_t last_line = 0;\n        size_t last_word = 0;\n        size_t extra = 0;\n\n        const wchar_t *ptr = text;\n\n        XMFLOAT2 pos(float(rect.left), float(rect.top));\n\n        wchar_t prevch = 0;\n        while (*ptr != L'\\0')\n        {\n            const wchar_t ch = *ptr;\n\n            str.push_back(ch);\n\n            if (iswspace(ch))\n            {\n                last_word = size_t(ptr - text);\n            }\n            else if (prevch == L'-')\n            {\n                last_word = size_t(ptr - text - 1);\n            }\n\n            RECT textrect = font->MeasureDrawBounds(str.c_str() + line_start, pos);\n\n            if (textrect.right > rect.right)\n            {\n                if (last_word > last_line)\n                {\n                    str.erase(str.cbegin() + ptrdiff_t(last_word + extra), str.cend());\n                    str.push_back(L'\\n');\n                    ++extra;\n                    last_line = last_word;\n                    ptr = text + last_word + 1;\n                }\n                else\n                {\n                    str.erase(str.cend() - 1);\n                    str.push_back(L'\\n');\n                    ++extra;\n                    last_line = last_word = str.length() - extra;\n                }\n\n                line_start = last_line + extra;\n\n                if (lineStarts)\n                {\n                    lineStarts->push_back(last_line + extra);\n                }\n\n                prevch = 0;\n                continue;\n            }\n\n            ++ptr;\n            prevch = ch;\n        }\n\n        return str;\n    }\n\n    void HandleEscapeCharacters(_Inout_z_ wchar_t* str)\n    {\n        for (wchar_t*ptr = str; *ptr != 0; ++ptr)\n        {\n            if (*ptr == L'|')\n                *ptr = L'\\n';\n        }\n    }\n\n    unsigned HandleVirtualKeys(_Inout_z_ wchar_t* str)\n    {\n        static const struct Map { const wchar_t* first; unsigned second; } s_map[] =\n        {\n            { L\"F1\", VK_F1 },\n            { L\"F2\", VK_F2 },\n            { L\"F3\", VK_F3 },\n            { L\"F4\", VK_F4 },\n            { L\"F5\", VK_F5 },\n            { L\"F6\", VK_F6 },\n            { L\"F7\", VK_F7 },\n            { L\"F8\", VK_F8 },\n            { L\"F9\", VK_F9 },\n            { L\"F10\", VK_F10 },\n        };\n\n        for(size_t j = 0; j < _countof(s_map); ++j)\n        {\n            if (_wcsicmp(s_map[j].first, str) == 0)\n            {\n                return s_map[j].second;\n            }\n        }\n\n        if (*(str + 1) == 0)\n        {\n            return unsigned(*str);\n        }\n\n        return 0;\n    }\n\n\n    bool UpdateScrollBar(RECT& thumbRect, const RECT& trackRect, int position, int start, int end, int pageSize)\n    {\n        assert(pageSize > 0);\n        if (end - start > pageSize)\n        {\n            int height = (trackRect.bottom - trackRect.top);\n\n            int thumbHeight = std::max<int>( height * pageSize / (end - start), c_MinThumbSize);\n            int maxPos = end - start - pageSize;\n\n            thumbRect.top = trackRect.top + (position - start) * (height - thumbHeight) / maxPos;\n            thumbRect.bottom = thumbRect.top + thumbHeight;\n\n            if (thumbRect.top < trackRect.top)\n                thumbRect.top = trackRect.top;\n\n            if (thumbRect.bottom > trackRect.bottom)\n                thumbRect.bottom = trackRect.bottom;\n\n            return true;\n        }\n        else\n        {\n            thumbRect.bottom = thumbRect.top;\n            return false;\n        }\n    }\n\n\n    void MessageYesNoCancel(IPanel* panel, unsigned id)\n    {\n        assert(panel != 0);\n        assert(panel->GetUser() != 0);\n\n        auto cb = reinterpret_cast<std::function<void(bool, bool)>*>(panel->GetUser());\n\n        if (id == 1)\n        {\n            (*cb)(true, false);\n        }\n        else if (id == 2)\n        {\n            (*cb)(false, false);\n        }\n        else\n        {\n            (*cb)(false, true);\n        }\n    }\n}\n\n\n//=====================================================================================\n// UIManager\n//=====================================================================================\nclass UIManager::Impl\n{\npublic:\n    Impl(const UIConfig& config) :\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        m_defaultTexDescriptor{},\n        m_commandList(nullptr),\n#endif\n        m_fullscreen{},\n        m_focusPanel(nullptr),\n        m_overlayPanel(nullptr),\n        m_hudPanel(nullptr),\n        m_heldTimer(0),\n        m_mouseLastX(-1),\n        m_mouseLastY(-1),\n        mConfig(config)\n    {\n        if (s_uiManager)\n        {\n            throw std::exception(\"UIManager is a singleton\");\n        }\n\n        s_uiManager = this;\n    }\n\n    ~Impl()\n    {\n        for (auto& it : m_panels)\n        {\n            delete it.second;\n        }\n        m_panels.clear();\n\n        m_focusPanel = nullptr;\n        m_overlayPanel = nullptr;\n        m_hudPanel = nullptr;\n\n        s_uiManager = nullptr;\n    }\n\n    void LoadLayout(const wchar_t* layoutFile, const wchar_t* imageDir, unsigned offset)\n    {\n        static const wchar_t* s_seps = L\" ,;|\";\n        static wchar_t s_text[4096] = {};\n\n        DX::CSVReader reader(layoutFile, DX::CSVReader::Encoding::UTF8, true);\n\n        IPanel* currentPanel = nullptr;\n\n        if (imageDir)\n            m_layoutImageDir = imageDir;\n        else\n            m_layoutImageDir.clear();\n\n        while (!reader.EndOfFile())\n        {\n            // Each record starts with ITEM,ID,RECTX,RECTY,DX,DY\n            wchar_t item[1024] = {};\n            if (!reader.NextItem(item))\n            {\n                reader.NextRecord();\n                continue;\n            }\n\n            TrimTrailingWhitespace(item);\n\n            unsigned id;\n            {\n                // IPanel object ids need to be globally unique\n                wchar_t tmp[16] = {};\n                if (!reader.NextItem(tmp))\n                {\n                    DebugTrace(\"ERROR: Expected an id for record %zu\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n                id = static_cast<unsigned>(_wtoi(tmp));\n            }\n\n            RECT rct = { 0, 0, 0, 0 };\n            {\n                wchar_t tmp[16] = {};\n                if (!reader.NextItem(tmp))\n                {\n                    DebugTrace(\"ERROR: Expected an rectx for record %zu\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                rct.left = _wtoi(tmp);\n\n                if (!reader.NextItem(tmp))\n                {\n                    DebugTrace(\"ERROR: Expected an recty for record %zu\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                rct.top = _wtoi(tmp);\n\n                if (!reader.NextItem(tmp))\n                {\n                    DebugTrace(\"ERROR: Expected an dx for record %zu\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                rct.right = rct.left + _wtoi(tmp);\n\n                if (!reader.NextItem(tmp))\n                {\n                    DebugTrace(\"ERROR: Expected an dy for record %zu\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                rct.bottom = rct.top + _wtoi(tmp);\n            }\n\n            // Create item\n            if (_wcsicmp(item, L\"POPUP\") == 0 || _wcsicmp(item, L\"CUSTOM_POPUP\") == 0)\n            {\n                id += offset;\n\n                auto it = m_panels.find(id);\n                if (it != m_panels.end())\n                {\n                    DebugTrace(\"ERROR: Duplicate panel id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned int styleFlags = (_wcsicmp(item, L\"CUSTOM_POPUP\") == 0) ? c_styleCustomPanel : 0;\n                wchar_t styleStr[128] = {};\n                if (reader.NextItem(styleStr))\n                {\n                    _wcsupr_s(styleStr);\n\n                    wchar_t* context = nullptr;\n                    const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                    while (tok)\n                    {\n                        if (wcscmp(tok, L\"EMPHASIS\") == 0)\n                        {\n                            styleFlags |= c_stylePopupEmphasis;\n                        }\n                        else if (wcscmp(tok, L\"SUPPRESS_CANCEL\") == 0)\n                        {\n                            styleFlags |= c_styleSuppressCancel;\n                        }\n                        tok = wcstok_s(nullptr, s_seps, &context);\n                    }\n                }\n\n                currentPanel = new Popup(rct, styleFlags);\n\n                m_panels[id] = currentPanel;\n            }\n            else if (_wcsicmp(item, L\"HUD\") == 0)\n            {\n                id += offset;\n\n                auto it = m_panels.find(id);\n                if (it != m_panels.end())\n                {\n                    DebugTrace(\"ERROR: Duplicate panel id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                currentPanel = new HUD(rct);\n\n                m_panels[id] = currentPanel;\n\n                if (!m_hudPanel)\n                {\n                    currentPanel->Show();\n                }\n            }\n            else if (_wcsicmp(item, L\"OVERLAY\") == 0 || _wcsicmp(item, L\"CUSTOM_OVERLAY\") == 0)\n            {\n                id += offset;\n\n                auto it = m_panels.find(id);\n                if (it != m_panels.end())\n                {\n                    DebugTrace(\"ERROR: Duplicate panel id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned int styleFlags = (_wcsicmp(item, L\"CUSTOM_OVERLAY\") == 0) ? c_styleCustomPanel : 0;\n                wchar_t styleStr[128] = {};\n                if (reader.NextItem(styleStr))\n                {\n                    _wcsupr_s(styleStr);\n\n                    wchar_t *context = nullptr;\n                    const wchar_t *tok = wcstok_s(styleStr, s_seps, &context);\n                    while (tok)\n                    {\n                        if (wcscmp(tok, L\"SUPPRESS_CANCEL\") == 0)\n                        {\n                            styleFlags |= c_styleSuppressCancel;\n                        }\n                        tok = wcstok_s(nullptr, s_seps, &context);\n                    }\n                }\n\n                currentPanel = new Overlay(rct, styleFlags);\n\n                m_panels[id] = currentPanel;\n            }\n            else if (_wcsicmp(item, L\"LABEL\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: LABEL found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                if (!reader.NextItem(s_text))\n                {\n                    DebugTrace(\"ERROR: LABEL missing text string [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                HandleEscapeCharacters(s_text);\n\n                unsigned style = 0;\n                XMVECTOR fgColor = Colors::White;\n                XMVECTOR bgColor = Colors::Transparent;\n\n                wchar_t styleStr[128] = {};\n                if (reader.NextItem(styleStr))\n                {\n                    _wcsupr_s(styleStr);\n\n                    wchar_t* context = nullptr;\n                    const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                    while (tok)\n                    {\n                        if (wcscmp(tok, L\"LEFT\") == 0)\n                        {\n                            style |= TextLabel::c_StyleAlignLeft | TextLabel::c_StyleAlignMiddle;\n                        }\n                        else if (wcscmp(tok, L\"CENTER\") == 0)\n                        {\n                            style |= TextLabel::c_StyleAlignCenter | TextLabel::c_StyleAlignMiddle;\n                        }\n                        else if (wcscmp(tok, L\"RIGHT\") == 0)\n                        {\n                            style |= TextLabel::c_StyleAlignRight | TextLabel::c_StyleAlignMiddle;\n                        }\n                        else if (wcscmp(tok, L\"LARGE\") == 0)\n                        {\n                            style |= TextLabel::c_StyleFontLarge;\n                        }\n                        else if (wcscmp(tok, L\"SMALL\") == 0)\n                        {\n                            style |= TextLabel::c_StyleFontSmall;\n                        }\n                        else if (wcscmp(tok, L\"BOLD\") == 0)\n                        {\n                            style |= TextLabel::c_StyleFontBold;\n                        }\n                        else if (wcscmp(tok, L\"ITALIC\") == 0)\n                        {\n                            style |= TextLabel::c_StyleFontItalic;\n                        }\n                        else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                        {\n                            style |= TextLabel::c_StyleTransparent;\n                        }\n                        else if (wcscmp(tok, L\"WORDWRAP\") == 0)\n                        {\n                            style |= TextLabel::c_StyleWordWrap;\n                        }\n\n                        tok = wcstok_s(nullptr, s_seps, &context);\n                    }\n\n                    wchar_t colorStr[32] = {};\n                    if (reader.NextItem(colorStr))\n                    {\n                        _wcsupr_s(colorStr);\n                        fgColor = LoadColorItem(colorStr, reader.RecordIndex());\n                    }\n\n                    if (reader.NextItem(colorStr))\n                    {\n                        _wcsupr_s(colorStr);\n                        bgColor = LoadColorItem(colorStr, reader.RecordIndex());\n                    }\n                }\n\n                if (id)\n                {\n                    // check for duplicates if nonzero ids used\n                    if (currentPanel->Find(id))\n                    {\n                        DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                        throw std::exception(\"LoadLayout\");\n                    }\n                }\n\n                auto label = new TextLabel(id, s_text, rct, style);\n                label->SetForegroundColor(fgColor);\n                label->SetBackgroundColor(bgColor);\n                currentPanel->Add(label);\n            }\n            else if (_wcsicmp(item, L\"LEGEND\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: LEGEND found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                if (!reader.NextItem(s_text))\n                {\n                    DebugTrace(\"ERROR: LEGEND missing text string [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                HandleEscapeCharacters(s_text);\n\n                unsigned style = 0;\n                XMVECTOR fgColor = Colors::White;\n                XMVECTOR bgColor = Colors::Transparent;\n\n                wchar_t styleStr[128] = {};\n                if (reader.NextItem(styleStr))\n                {\n                    _wcsupr_s(styleStr);\n\n                    wchar_t* context = nullptr;\n                    const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                    while (tok)\n                    {\n                        if (wcscmp(tok, L\"LEFT\") == 0)\n                        {\n                            style |= Legend::c_StyleAlignLeft | Legend::c_StyleAlignMiddle;\n                        }\n                        else if (wcscmp(tok, L\"CENTER\") == 0)\n                        {\n                            style |= Legend::c_StyleAlignCenter | Legend::c_StyleAlignMiddle;\n                        }\n                        else if (wcscmp(tok, L\"RIGHT\") == 0)\n                        {\n                            style |= Legend::c_StyleAlignRight | Legend::c_StyleAlignMiddle;\n                        }\n                        else if (wcscmp(tok, L\"LARGE\") == 0)\n                        {\n                            style |= Legend::c_StyleFontLarge;\n                        }\n                        else if (wcscmp(tok, L\"SMALL\") == 0)\n                        {\n                            style |= Legend::c_StyleFontSmall;\n                        }\n                        else if (wcscmp(tok, L\"BOLD\") == 0)\n                        {\n                            style |= Legend::c_StyleFontBold;\n                        }\n                        else if (wcscmp(tok, L\"ITALIC\") == 0)\n                        {\n                            style |= Legend::c_StyleFontItalic;\n                        }\n                        else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                        {\n                            style |= Legend::c_StyleTransparent;\n                        }\n\n                        tok = wcstok_s(nullptr, s_seps, &context);\n                    }\n\n                    wchar_t colorStr[32] = {};\n                    if (reader.NextItem(colorStr))\n                    {\n                        _wcsupr_s(colorStr);\n                        fgColor = LoadColorItem(colorStr, reader.RecordIndex());\n                    }\n\n                    if (reader.NextItem(colorStr))\n                    {\n                        _wcsupr_s(colorStr);\n                        bgColor = LoadColorItem(colorStr, reader.RecordIndex());\n                    }\n                }\n\n                if (id)\n                {\n                    // check for duplicates if nonzero ids used\n                    if (currentPanel->Find(id))\n                    {\n                        DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                        throw std::exception(\"LoadLayout\");\n                    }\n                }\n\n                auto legend = new Legend(id, s_text, rct, style);\n                legend->SetForegroundColor(fgColor);\n                legend->SetBackgroundColor(bgColor);\n                currentPanel->Add(legend);\n            }\n            else if (_wcsicmp(item, L\"IMAGE\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: IMAGE found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned imageId = 0;\n                wchar_t imageFile[MAX_PATH] = {};\n                if (reader.NextItem(imageFile))\n                {\n                    TrimTrailingWhitespace(imageFile);\n                    imageId = LoadImageItem(imageFile);\n                }\n                else\n                {\n                    DebugTrace(\"ERROR: IMAGE missing image file name [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                if (id)\n                {\n                    // check for duplicates if nonzero ids used\n                    if (currentPanel->Find(id))\n                    {\n                        DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                        throw std::exception(\"LoadLayout\");\n                    }\n                }\n\n                currentPanel->Add(new Image(id, imageId, rct));\n            }\n            else if (_wcsicmp(item, L\"BUTTON\") == 0 || _wcsicmp(item, L\"EXITBUTTON\") == 0 || _wcsicmp(item, L\"DEFBUTTON\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: BUTTON found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                if (!reader.NextItem(s_text))\n                {\n                    DebugTrace(\"ERROR: BUTTON missing text string [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned hotkey = 0;\n                wchar_t hotkeyStr[64] = {};\n                unsigned style = 0;\n                bool showBorder = false;\n                bool noFocusColor = false;\n                bool focusOnText = false;\n                XMVECTOR color = Colors::Black;\n\n                if (reader.NextItem(hotkeyStr))\n                {\n                    TrimTrailingWhitespace(hotkeyStr);\n\n                    hotkey = HandleVirtualKeys(hotkeyStr);\n\n                    // Optional style\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"LARGE\") == 0)\n                            {\n                                style |= Button::c_StyleFontLarge;\n                            }\n                            else if (wcscmp(tok, L\"SMALL\") == 0)\n                            {\n                                style |= Button::c_StyleFontSmall;\n                            }\n                            else if (wcscmp(tok, L\"BOLD\") == 0)\n                            {\n                                style |= Button::c_StyleFontBold;\n                            }\n                            else if (wcscmp(tok, L\"ITALIC\") == 0)\n                            {\n                                style |= Button::c_StyleFontItalic;\n                            }\n                            else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= Button::c_StyleTransparent;\n                            }\n                            else if (wcscmp(tok, L\"BORDER\") == 0)\n                            {\n                                showBorder = true;\n                            }\n                            else if (wcscmp(tok, L\"NO_FOCUS_COLOR\") == 0)\n                            {\n                                noFocusColor = true;\n                            }\n                            else if (wcscmp(tok, L\"FOCUS_ON_TEXT\") == 0)\n                            {\n                                focusOnText = true;\n                            }\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n\n                        wchar_t colorStr[32] = {};\n                        if (reader.NextItem(colorStr))\n                        {\n                            _wcsupr_s(colorStr);\n                            color = LoadColorItem(colorStr, reader.RecordIndex());\n                        }\n                    }\n                }\n\n                if (_wcsicmp(item, L\"EXITBUTTON\") == 0)\n                {\n                    style |= Button::c_StyleExit;\n                }\n                else if (_wcsicmp(item, L\"DEFBUTTON\") == 0)\n                {\n                    style |= Button::c_StyleExit | Button::c_StyleDefault;\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                auto *butn = new Button(id, s_text, rct);\n                butn->SetStyle(style);\n                butn->SetHotKey(hotkey);\n                butn->SetColor(color);\n                butn->ShowBorder(showBorder);\n                butn->NoFocusColor(noFocusColor);\n                butn->FocusOnText(focusOnText);\n                currentPanel->Add(butn);\n            }\n            else if (_wcsicmp(item, L\"IMAGEBUTTON\") == 0 || _wcsicmp(item, L\"EXITIMAGEBUTTON\") == 0 || _wcsicmp(item, L\"DEFIMAGEBUTTON\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: IMAGEBUTTON found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned imageId = 0;\n                wchar_t imageFile[MAX_PATH] = {};\n                if (reader.NextItem(imageFile))\n                {\n                    TrimTrailingWhitespace(imageFile);\n                    imageId = LoadImageItem(imageFile);\n                }\n                else\n                {\n                    DebugTrace(\"ERROR: IMAGEBUTTON missing image file name [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned hotkey = 0;\n                wchar_t hotkeyStr[64] = {};\n                unsigned style = 0;\n                if (reader.NextItem(hotkeyStr))\n                {\n                    TrimTrailingWhitespace(hotkeyStr);\n\n                    hotkey = HandleVirtualKeys(hotkeyStr);\n\n                    // Optional style\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"BACKGROUND\") == 0)\n                            {\n                                style |= ImageButton::c_StyleBackground;\n                            }\n                            else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= ImageButton::c_StyleTransparent | ImageButton::c_StyleBackground;\n                            }\n\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n                    }\n                }\n\n                if (_wcsicmp(item, L\"EXITIMAGEBUTTON\") == 0)\n                {\n                    style |= ImageButton::c_StyleExit;\n                }\n                else if (_wcsicmp(item, L\"DEFIMAGEBUTTON\") == 0)\n                {\n                    style |= ImageButton::c_StyleExit | ImageButton::c_StyleDefault;\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                auto *butn = new ImageButton(id, imageId, rct);\n                butn->SetStyle(style);\n                butn->SetHotKey(hotkey);\n                currentPanel->Add(butn);\n            }\n            else if (_wcsicmp(item, L\"CHECKBOX\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: CHECKBOX found outside of panel [record %zu]\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                if (!reader.NextItem(s_text))\n                {\n                    DebugTrace(\"ERROR: CHECKBOX missing text string [record %zu]\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned style = 0;\n                bool checked = false;\n                {\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"LARGE\") == 0)\n                            {\n                                style |= CheckBox::c_StyleFontLarge;\n                            }\n                            else if (wcscmp(tok, L\"SMALL\") == 0)\n                            {\n                                style |= CheckBox::c_StyleFontSmall;\n                            }\n                            else if (wcscmp(tok, L\"BOLD\") == 0)\n                            {\n                                style |= CheckBox::c_StyleFontBold;\n                            }\n                            else if (wcscmp(tok, L\"ITALIC\") == 0)\n                            {\n                                style |= CheckBox::c_StyleFontItalic;\n                            }\n                            else if (wcscmp(tok, L\"CHECKED\") == 0)\n                            {\n                                checked = true;\n                            }\n                            else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= CheckBox::c_StyleTransparent;\n                            }\n\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n                    }\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control id found [record %zu]\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                auto *box = new CheckBox(id, s_text, rct, checked);\n                box->SetStyle(style);\n                currentPanel->Add(box);\n            }\n            else if (_wcsicmp(item, L\"SLIDER\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: SLIDER found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                unsigned style = 0;\n                {\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= Slider::c_StyleTransparent;\n                            }\n\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n                    }\n                }\n\n                auto slider = new Slider(id, rct);\n                slider->SetStyle(style);\n                currentPanel->Add(slider);\n            }\n            else if (_wcsicmp(item, L\"PROGRESSBAR\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: PROGRESSBAR found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                currentPanel->Add(new ProgressBar(id, rct));\n            }\n            else if (_wcsicmp(item, L\"TEXTLIST\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: TEXTLIST found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                int itemHeight = 0;\n                wchar_t itemHeightStr[64] = {};\n                unsigned style = 0;\n                if (reader.NextItem(itemHeightStr))\n                {\n                    itemHeight = _wtoi(itemHeightStr);\n\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"LARGE\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontLarge;\n                            }\n                            else if (wcscmp(tok, L\"SMALL\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontSmall;\n                            }\n                            else if (wcscmp(tok, L\"BOLD\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontBold;\n                            }\n                            else if (wcscmp(tok, L\"ITALIC\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontItalic;\n                            }\n                            else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= ListBox::c_StyleTransparent;\n                            }\n\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n                    }\n                }\n\n                currentPanel->Add(new TextList(id, rct, style, itemHeight));\n            }\n            else if (_wcsicmp(item, L\"LISTBOX\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: LISTBOX found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                // check for duplicate id\n                if (currentPanel->Find(id))\n                {\n                    DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                int itemHeight = 0;\n                wchar_t itemHeightStr[64] = {};\n                unsigned style = 0;\n                if (reader.NextItem(itemHeightStr))\n                {\n                    itemHeight = _wtoi(itemHeightStr);\n\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"MULTISELECT\") == 0)\n                            {\n                                style |= ListBox::c_StyleMultiSelection;\n                            }\n                            else if (wcscmp(tok, L\"LARGE\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontLarge;\n                            }\n                            else if (wcscmp(tok, L\"SMALL\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontSmall;\n                            }\n                            else if (wcscmp(tok, L\"BOLD\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontBold;\n                            }\n                            else if (wcscmp(tok, L\"ITALIC\") == 0)\n                            {\n                                style |= ListBox::c_StyleFontItalic;\n                            }\n                            else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= ListBox::c_StyleTransparent;\n                            }\n                            else if (wcscmp(tok, L\"SCROLLBAR\") == 0)\n                            {\n                                style |= ListBox::c_StyleScrollBar;\n                            }\n\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n                    }\n                }\n\n                currentPanel->Add(new ListBox(id, rct, style, itemHeight));\n            }\n            else if (_wcsicmp(item, L\"TEXTBOX\") == 0)\n            {\n                if (!currentPanel)\n                {\n                    DebugTrace(\"ERROR: TEXTBOX found outside of panel [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                if (id)\n                {\n                    // check for duplicates if nonzero ids used\n                    if (currentPanel->Find(id))\n                    {\n                        DebugTrace(\"ERROR: Duplicate control id found [record %zu]\\n\", reader.RecordIndex() + 1);\n                        throw std::exception(\"LoadLayout\");\n                    }\n                }\n\n                if (!reader.NextItem(s_text))\n                {\n                    DebugTrace(\"ERROR: TEXTBOX missing text string [record %zu]\\n\", reader.RecordIndex() + 1);\n                    throw std::exception(\"LoadLayout\");\n                }\n\n                HandleEscapeCharacters(s_text);\n\n                unsigned style = 0;\n                {\n                    wchar_t styleStr[128] = {};\n                    if (reader.NextItem(styleStr))\n                    {\n                        _wcsupr_s(styleStr);\n\n                        wchar_t* context = nullptr;\n                        const wchar_t* tok = wcstok_s(styleStr, s_seps, &context);\n                        while (tok)\n                        {\n                            if (wcscmp(tok, L\"LARGE\") == 0)\n                            {\n                                style |= TextBox::c_StyleFontLarge;\n                            }\n                            else if (wcscmp(tok, L\"SMALL\") == 0)\n                            {\n                                style |= TextBox::c_StyleFontSmall;\n                            }\n                            else if (wcscmp(tok, L\"BOLD\") == 0)\n                            {\n                                style |= TextBox::c_StyleFontBold;\n                            }\n                            else if (wcscmp(tok, L\"ITALIC\") == 0)\n                            {\n                                style |= TextBox::c_StyleFontItalic;\n                            }\n                            else if (wcscmp(tok, L\"TRANSPARENT\") == 0)\n                            {\n                                style |= TextBox::c_StyleTransparent;\n                            }\n                            else if (wcscmp(tok, L\"SCROLLBAR\") == 0)\n                            {\n                                style |= TextBox::c_StyleScrollBar;\n                            }\n                            else if (wcscmp(tok, L\"NOBACKGROUND\") == 0)\n                            {\n                                style |= TextBox::c_StyleNoBackground;\n                            }\n\n                            tok = wcstok_s(nullptr, s_seps, &context);\n                        }\n                    }\n                }\n\n                currentPanel->Add(new TextBox(id, s_text, rct, style));\n            }\n\n            reader.NextRecord();\n        }\n    }\n\n    bool Update(float elapsedTime, const GamePad::State& pad)\n    {\n        if (m_heldTimer >= 0)\n        {\n            m_heldTimer -= elapsedTime;\n        }\n\n        m_padButtonState.Update(pad);\n\n        bool result = false;\n\n        if (m_focusPanel)\n        {\n            // Focus panel gets input processing\n            result = m_focusPanel->Update(elapsedTime, pad);\n        }\n\n        for (auto& it : m_panels)\n        {\n            if (it.second == m_overlayPanel || it.second == m_focusPanel)\n                continue;\n\n            if (it.second->IsVisible())\n            {\n                it.second->Update(elapsedTime);\n            }\n        }\n\n        // Overlay gets processed last\n        if (m_overlayPanel)\n        {\n            if (!result)\n            {\n                result = m_overlayPanel->Update(elapsedTime, pad);\n            }\n            else\n            {\n                m_overlayPanel->Update(elapsedTime);\n            }\n        }\n\n        // m_hudPanel never gets input, but does get Update for time\n\n        return result;\n    }\n\n    bool Update(float elapsedTime, Mouse& mouse, Keyboard& kb)\n    {\n        if (m_heldTimer >= 0)\n        {\n            m_heldTimer -= elapsedTime;\n        }\n\n        auto mstate = mouse.GetState();\n        m_mouseButtonState.Update(mstate);\n\n        auto kbstate = kb.GetState();\n        m_keyboardState.Update(kbstate);\n\n        bool result = false;\n\n        if (m_focusPanel)\n        {\n            // Focus panel gets input processing\n            result = m_focusPanel->Update(elapsedTime, mstate, kbstate);\n        }\n\n        for (auto& it : m_panels)\n        {\n            if (it.second == m_overlayPanel || it.second == m_focusPanel)\n                continue;\n\n            if (it.second->IsVisible())\n            {\n                if (!result)\n                {\n                    result = it.second->Update(elapsedTime, mstate, kbstate);\n                }\n                else\n                {\n                    it.second->Update(elapsedTime);\n                }\n            }\n        }\n\n        // Overlay is last (it's below all other panels)\n        if (m_overlayPanel)\n        {\n            if (!result)\n            {\n                result = m_overlayPanel->Update(elapsedTime, mstate, kbstate);\n            }\n            else\n            {\n                m_overlayPanel->Update(elapsedTime);\n            }\n        }\n\n        if (mstate.positionMode == Mouse::MODE_ABSOLUTE)\n        {\n            m_mouseLastX = mstate.x;\n            m_mouseLastY = mstate.y;\n        }\n        else\n        {\n            m_mouseLastX = m_mouseLastY = -1;\n        }\n\n        // m_hudPanel never gets input, but does get Update for time\n\n        return result;\n    }\n\n    void Render()\n    {\n        // HUD panel on buton\n        if (m_hudPanel)\n        {\n            m_hudPanel->Render();\n        }\n\n        // Overlay panel next\n        if (m_overlayPanel)\n        {\n            m_overlayPanel->Render();\n        }\n\n        // Non-focus visible panels\n        for (auto& it : m_panels)\n        {\n            if (it.second == m_hudPanel || it.second == m_overlayPanel || it.second == m_focusPanel)\n                continue;\n\n            if (it.second->IsVisible())\n            {\n                it.second->Render();\n            }\n        }\n\n        // Focus panel on top\n        if (m_focusPanel)\n        {\n            m_focusPanel->Render();\n        }\n    }\n\n    void ReleaseDevice()\n    {\n        m_images.clear();\n        m_batch.reset();\n        m_smallFont.reset();\n        m_smallItalicFont.reset();\n        m_smallBoldFont.reset();\n        m_midFont.reset();\n        m_midItalicFont.reset();\n        m_midBoldFont.reset();\n        m_largeFont.reset();\n        m_largeItalicFont.reset();\n        m_largeBoldFont.reset();\n        m_smallLegend.reset();\n        m_largeLegend.reset();\n        m_fxFactory.reset();\n        m_defaultTex.Reset();\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        m_blendState.Reset();\n        m_scissorState.Reset();\n        m_context.Reset();\n#endif\n    }\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    void RestoreDevice(_In_ ID3D12Device* device, const RenderTargetState& renderTarget, ResourceUploadBatch& resourceUpload, DescriptorPile& pile)\n    {\n        {\n            SpriteBatchPipelineStateDescription pd(renderTarget, (mConfig.pmAlpha) ? &CommonStates::AlphaBlend : &CommonStates::NonPremultiplied);\n\n            m_batch = std::make_unique<SpriteBatch>(device, resourceUpload, pd);\n        }\n\n        // Create 1x1 white default texture\n        D3D12_RESOURCE_DESC texDesc = {};\n        texDesc.Width = 1;\n        texDesc.Height = 1;\n        texDesc.MipLevels = texDesc.DepthOrArraySize = 1;\n        texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n        texDesc.SampleDesc.Count = 1;\n        texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n\n        CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        DX::ThrowIfFailed(\n            device->CreateCommittedResource(\n                &defaultHeapProperties,\n                D3D12_HEAP_FLAG_NONE,\n                &texDesc,\n                D3D12_RESOURCE_STATE_COPY_DEST,\n                nullptr,\n                IID_GRAPHICS_PPV_ARGS(m_defaultTex.GetAddressOf())));\n\n        static const uint32_t s_pixel = 0xffffffff;\n\n        D3D12_SUBRESOURCE_DATA initData = { &s_pixel, sizeof(uint32_t), 0 };\n\n        resourceUpload.Upload(m_defaultTex.Get(), 0, &initData, 1);\n\n        resourceUpload.Transition(\n            m_defaultTex.Get(),\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        size_t index = pile.Allocate();\n        device->CreateShaderResourceView(m_defaultTex.Get(), nullptr, pile.GetCpuHandle(index));\n\n        m_defaultTexDescriptor = pile.GetGpuHandle(index);\n\n        // Create fonts\n#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n        wchar_t buff[MAX_PATH] = {};\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallFontName);\n        index = pile.Allocate();\n        m_smallFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallItalicFontName);\n        index = pile.Allocate();\n        m_smallItalicFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallBoldFontName);\n        index = pile.Allocate();\n        m_smallBoldFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.midFontName);\n        index = pile.Allocate();\n        m_midFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.midItalicFontName);\n        index = pile.Allocate();\n        m_midItalicFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.midBoldFontName);\n        index = pile.Allocate();\n        m_midBoldFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeFontName);\n        index = pile.Allocate();\n        m_largeFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeItalicFontName);\n        index = pile.Allocate();\n        m_largeItalicFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeBoldFontName);\n        index = pile.Allocate();\n        m_largeBoldFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeLegendName);\n        index = pile.Allocate();\n        m_largeLegend = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallLegendName);\n        index = pile.Allocate();\n        m_smallLegend = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n#else\n        index = pile.Allocate();\n        m_smallFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.smallFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_smallItalicFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.smallItalicFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_smallBoldFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.smallBoldFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_midFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.midFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_midItalicFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.midItalicFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_midBoldFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.midBoldFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_largeFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.largeFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_largeItalicFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.largeItalicFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_largeBoldFont = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.largeBoldFontName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_largeLegend = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.largeLegendName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n        index = pile.Allocate();\n        m_smallLegend = std::make_unique<SpriteFont>(device, resourceUpload, mConfig.smallLegendName, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n#endif\n        m_smallFont->SetDefaultCharacter(L'?');\n        m_smallBoldFont->SetDefaultCharacter(L'?');\n        m_midFont->SetDefaultCharacter(L'?');\n        m_midItalicFont->SetDefaultCharacter(L'?');\n        m_midBoldFont->SetDefaultCharacter(L'?');\n        m_largeFont->SetDefaultCharacter(L'?');\n        m_largeItalicFont->SetDefaultCharacter(L'?');\n        m_largeBoldFont->SetDefaultCharacter(L'?');\n\n        // Create factory for images\n        m_fxFactory = std::make_unique<EffectTextureFactory>(device, resourceUpload, pile.Heap());\n        m_fxFactory->SetDirectory(m_layoutImageDir.c_str());\n        m_fxFactory->EnableForceSRGB(mConfig.forceSRGB);\n\n        unsigned imageId = c_LayoutImageIdStart;\n        if (!m_layoutImages.empty())\n        {\n            for (auto& it : m_layoutImages)\n            {\n                index = pile.Allocate();\n                size_t slot = m_fxFactory->CreateTexture(it.c_str(), static_cast<int>(index));\n\n                ComPtr<ID3D12Resource> tex;\n                m_fxFactory->GetResource(slot, tex.GetAddressOf());\n\n                std::pair<D3D12_GPU_DESCRIPTOR_HANDLE, XMUINT2> entry;\n                entry.first = pile.GetGpuHandle(index);\n                entry.second = GetTextureSize(tex.Get());\n                m_images[imageId] = entry;\n                ++imageId;\n            }\n        }\n    }\n#else\n    void RestoreDevice(_In_ ID3D11DeviceContext* context)\n    {\n        m_batch = std::make_unique<SpriteBatch>(context);\n\n        ComPtr<ID3D11Device> device;\n        context->GetDevice(device.GetAddressOf());\n\n        // Create 1x1 white default texture\n        {\n            static const uint32_t s_pixel = 0xffffffff;\n\n            D3D11_SUBRESOURCE_DATA initData = { &s_pixel, sizeof(uint32_t), 0 };\n\n            CD3D11_TEXTURE2D_DESC texDesc(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_IMMUTABLE);\n\n            ComPtr<ID3D11Texture2D> tex;\n            DX::ThrowIfFailed(device->CreateTexture2D(&texDesc, &initData, tex.GetAddressOf()));\n\n            DX::ThrowIfFailed(device->CreateShaderResourceView(tex.Get(), nullptr, m_defaultTex.ReleaseAndGetAddressOf()));\n        }\n\n        // Create blend state for sprites\n        {\n            CD3D11_DEFAULT def;\n            CD3D11_BLEND_DESC desc(def);\n            desc.RenderTarget[0].BlendEnable = TRUE;\n            desc.RenderTarget[0].SrcBlend = desc.RenderTarget[0].SrcBlendAlpha = (mConfig.pmAlpha) ? D3D11_BLEND_ONE : D3D11_BLEND_SRC_ALPHA;\n            desc.RenderTarget[0].DestBlend = desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;\n            DX::ThrowIfFailed(device->CreateBlendState(&desc, m_blendState.ReleaseAndGetAddressOf()));\n        }\n\n        // Create scissor rasterizer state for sprites\n        {\n            CD3D11_RASTERIZER_DESC rsDesc(D3D11_FILL_SOLID, D3D11_CULL_BACK, FALSE, 0, 0.f, 0.f, TRUE, TRUE, TRUE, FALSE);\n            DX::ThrowIfFailed(device->CreateRasterizerState(&rsDesc, m_scissorState.ReleaseAndGetAddressOf()));\n        }\n\n        // Create fonts\n#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n        wchar_t buff[MAX_PATH] = {};\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallFontName);\n        m_smallFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallItalicFontName);\n        m_smallItalicFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallBoldFontName);\n        m_smallBoldFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.midFontName);\n        m_midFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.midItalicFontName);\n        m_midItalicFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.midBoldFontName);\n        m_midBoldFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeFontName);\n        m_largeFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeItalicFontName);\n        m_largeItalicFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeBoldFontName);\n        m_largeBoldFont = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.largeLegendName);\n        m_largeLegend = std::make_unique<SpriteFont>(device.Get(), buff);\n\n        DX::FindMediaFile(buff, MAX_PATH, mConfig.smallLegendName);\n        m_smallLegend = std::make_unique<SpriteFont>(device.Get(), buff);\n#else\n        m_smallFont = std::make_unique<SpriteFont>(device.Get(), mConfig.smallFontName);\n        m_smallItalicFont = std::make_unique<SpriteFont>(device.Get(), mConfig.smallItalicFontName);\n        m_smallBoldFont = std::make_unique<SpriteFont>(device.Get(), mConfig.smallBoldFontName);\n\n        m_midFont = std::make_unique<SpriteFont>(device.Get(), mConfig.midFontName);\n        m_midItalicFont = std::make_unique<SpriteFont>(device.Get(), mConfig.midItalicFontName);\n        m_midBoldFont = std::make_unique<SpriteFont>(device.Get(), mConfig.midBoldFontName);\n\n        m_largeFont = std::make_unique<SpriteFont>(device.Get(), mConfig.largeFontName);\n        m_largeItalicFont = std::make_unique<SpriteFont>(device.Get(), mConfig.largeItalicFontName);\n        m_largeBoldFont = std::make_unique<SpriteFont>(device.Get(), mConfig.largeBoldFontName);\n\n        m_largeLegend = std::make_unique<SpriteFont>(device.Get(), mConfig.largeLegendName);\n        m_smallLegend = std::make_unique<SpriteFont>(device.Get(), mConfig.smallLegendName);\n\n#endif\n        m_smallFont->SetDefaultCharacter(L'?');\n        m_smallBoldFont->SetDefaultCharacter(L'?');\n        m_midFont->SetDefaultCharacter(L'?');\n        m_midItalicFont->SetDefaultCharacter(L'?');\n        m_midBoldFont->SetDefaultCharacter(L'?');\n        m_largeFont->SetDefaultCharacter(L'?');\n        m_largeItalicFont->SetDefaultCharacter(L'?');\n        m_largeBoldFont->SetDefaultCharacter(L'?');\n\n        // Create factory for images\n        m_fxFactory = std::make_unique<EffectFactory>(device.Get());\n        m_fxFactory->SetDirectory(m_layoutImageDir.c_str());\n        m_fxFactory->EnableForceSRGB(mConfig.forceSRGB);\n\n        unsigned imageId = c_LayoutImageIdStart;\n        if (!m_layoutImages.empty())\n        {\n            for (auto& it : m_layoutImages)\n            {\n                ComPtr<ID3D11ShaderResourceView> tex;\n                m_fxFactory->CreateTexture(it.c_str(), context, tex.GetAddressOf());\n                m_images[imageId] = tex;\n                ++imageId;\n            }\n        }\n\n        m_context = context;\n    }\n#endif\n\n    void Reset()\n    {\n        m_padButtonState.Reset();\n        m_mouseButtonState.Reset();\n        m_keyboardState.Reset();\n        m_mouseLastX = m_mouseLastX = -1;\n        m_heldTimer = 0;\n    }\n\n    SpriteFont* SelectFont(unsigned style)\n    {\n        static_assert(TextLabel::c_StyleFontSmall == Legend::c_StyleFontSmall, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontMid == Legend::c_StyleFontMid, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontLarge == Legend::c_StyleFontLarge, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontBold == Legend::c_StyleFontBold, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontItalic == Legend::c_StyleFontItalic, \"style flags mismatch\");\n\n        static_assert(TextLabel::c_StyleFontSmall == Button::c_StyleFontSmall, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontMid == Button::c_StyleFontMid, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontLarge == Button::c_StyleFontLarge, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontBold == Button::c_StyleFontBold, \"style flags mismatch\");\n        static_assert(TextLabel::c_StyleFontItalic == Button::c_StyleFontItalic, \"style flags mismatch\");\n\n        SpriteFont* font = nullptr;\n\n        if (style & TextLabel::c_StyleFontLarge)\n        {\n            if (style & TextLabel::c_StyleFontBold)\n            {\n                font = m_largeBoldFont.get();\n            }\n            else if (style & TextLabel::c_StyleFontItalic)\n            {\n                font = m_largeItalicFont.get();\n            }\n            else\n            {\n                font = m_largeFont.get();\n            }\n        }\n        else if (style & TextLabel::c_StyleFontSmall)\n        {\n            if (style & TextLabel::c_StyleFontBold)\n            {\n                font = m_smallBoldFont.get();\n            }\n            else if (style & TextLabel::c_StyleFontItalic)\n            {\n                font = m_smallItalicFont.get();\n            }\n            else\n            {\n                font = m_smallFont.get();\n            }\n        }\n        else if (style & TextLabel::c_StyleFontBold)\n        {\n            font = m_midBoldFont.get();\n        }\n        else if (style & TextLabel::c_StyleFontItalic)\n        {\n            font = m_midItalicFont.get();\n        }\n        else\n        {\n            font = m_midFont.get();\n        }\n        \n        assert(font != 0);\n\n        return font;\n    }\n\n    // Direct3D resources\n    std::unique_ptr<SpriteBatch>        m_batch;\n    std::unique_ptr<SpriteFont>         m_smallFont;\n    std::unique_ptr<SpriteFont>         m_smallItalicFont;\n    std::unique_ptr<SpriteFont>         m_smallBoldFont;\n    std::unique_ptr<SpriteFont>         m_midFont;\n    std::unique_ptr<SpriteFont>         m_midItalicFont;\n    std::unique_ptr<SpriteFont>         m_midBoldFont;\n    std::unique_ptr<SpriteFont>         m_largeFont;\n    std::unique_ptr<SpriteFont>         m_largeItalicFont;\n    std::unique_ptr<SpriteFont>         m_largeBoldFont;\n    std::unique_ptr<SpriteFont>         m_smallLegend;\n    std::unique_ptr<SpriteFont>         m_largeLegend;\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    std::unique_ptr<EffectTextureFactory>   m_fxFactory;\n    D3D12_GPU_DESCRIPTOR_HANDLE             m_defaultTexDescriptor;\n    ID3D12GraphicsCommandList*              m_commandList;\n    ComPtr<ID3D12Resource>                  m_defaultTex;\n\n    std::map<unsigned, std::pair<D3D12_GPU_DESCRIPTOR_HANDLE,DirectX::XMUINT2>> m_images;\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n    std::unique_ptr<EffectFactory>      m_fxFactory;\n    ComPtr<ID3D11ShaderResourceView>    m_defaultTex;\n    ComPtr<ID3D11BlendState>            m_blendState;\n    ComPtr<ID3D11RasterizerState>       m_scissorState;\n    ComPtr<ID3D11DeviceContext>         m_context;\n\n    std::map<unsigned, ComPtr<ID3D11ShaderResourceView>> m_images;\n#endif\n\n    // UI objects\n    RECT                                m_fullscreen;\n    IPanel*                             m_focusPanel;\n    IPanel*                             m_overlayPanel;\n    IPanel*                             m_hudPanel;\n    std::map<unsigned, IPanel*>         m_panels;\n\n    std::vector<std::wstring>           m_layoutImages;\n    std::wstring                        m_layoutImageDir;\n\n    GamePad::ButtonStateTracker         m_padButtonState;\n    Mouse::ButtonStateTracker           m_mouseButtonState;\n    Keyboard::KeyboardStateTracker      m_keyboardState;\n    float                               m_heldTimer;\n\n    int                                 m_mouseLastX;\n    int                                 m_mouseLastY;\n\n    // Common handler objects\n    std::list<std::function<void(bool,bool)>> m_stdyesno;\n\n    // Contains configuration data provided on setup\n    const UIConfig mConfig;\n\n    static UIManager::Impl* s_uiManager;\n\n    // Helpers\n    void RenderControls(std::vector<IControl*>& controls)\n    {\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        if (m_commandList == nullptr || m_batch == nullptr)\n            return;\n\n        for (auto it : controls)\n        {\n            if (it->IsVisible())\n            {\n                m_commandList->RSSetScissorRects(1, it->GetRectangle());\n\n                m_batch->Begin(m_commandList);\n\n                it->Render();\n\n                m_batch->End();\n            }\n        }\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        if (m_context == nullptr || m_batch == nullptr)\n            return;\n\n        for (auto it : controls)\n        {\n            if (it->IsVisible())\n            {\n                m_batch->Begin(SpriteSortMode_Deferred, m_blendState.Get(), nullptr, nullptr, m_scissorState.Get(), [=]()\n                {\n                    m_context->RSSetScissorRects(1, it->GetRectangle());\n                });\n\n                it->Render();\n\n                m_batch->End();\n            }\n        }\n#endif\n    }\n\n    void DrawRect(const RECT &rect, FXMVECTOR color)\n    {\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        if (m_commandList == nullptr || m_batch == nullptr)\n            return;\n\n        static const XMUINT2 s_unit(1, 1);\n\n        m_batch->Draw(m_defaultTexDescriptor, s_unit, rect, color);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        if (m_context == nullptr || m_batch == nullptr)\n            return;\n\n        m_batch->Draw(m_defaultTex.Get(), rect, color);\n#endif\n    }\n\n    void DrawImage(unsigned id, const RECT &rect, FXMVECTOR color)\n    {\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        D3D12_GPU_DESCRIPTOR_HANDLE tex;\n        XMUINT2 texSize;\n\n        auto it = m_images.find(id);\n        if (it == m_images.end())\n        {\n            // If not found, use default texture\n            tex = m_defaultTexDescriptor;\n            texSize.x = texSize.y = 1;\n        }\n        else\n        {\n            tex = it->second.first;\n            texSize = it->second.second;\n        }\n\n        m_batch->Draw(tex, texSize, rect, color);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        ID3D11ShaderResourceView* tex = nullptr;\n\n        auto it = m_images.find(id);\n        if (it == m_images.end())\n        {\n            // If not found, use default texture\n            tex = m_defaultTex.Get();\n        }\n        else\n        {\n            tex = it->second.Get();\n        }\n\n        m_batch->Draw(tex, rect, color);\n#endif\n    }\n\nprivate:\n    unsigned LoadImageItem(_In_z_ const wchar_t* imageFile)\n    {\n        assert(imageFile != 0);\n\n        unsigned imageId = 0;\n\n        std::wstring wname(imageFile);\n        auto it = std::find(m_layoutImages.cbegin(), m_layoutImages.cend(), wname);\n        if (it == m_layoutImages.end())\n        {\n            imageId = c_LayoutImageIdStart + unsigned(m_layoutImages.size());\n            m_layoutImages.push_back(wname);\n        }\n        else\n        {\n            imageId = c_LayoutImageIdStart + unsigned(it - m_layoutImages.cbegin());\n        }\n\n        return imageId;\n    }\n\n    XMVECTOR XM_CALLCONV LoadColorItem(_In_z_ const wchar_t* colorStr, size_t index)\n    {\n        assert(colorStr != 0);\n        XMVECTOR color = Colors::White;\n\n        if (*colorStr == L'#')\n        {\n            unsigned int bgra = 0xFFFFFF;\n            if (swscanf_s(colorStr + 1, L\"%x\", &bgra) == 1)\n            {\n                using namespace PackedVector;\n\n                bgra &= 0xFFFFFF;\n                XMVECTOR clr = XMLoadColor(reinterpret_cast<const XMCOLOR*>(&bgra));\n                color = XMVectorSelect(g_XMIdentityR3, clr, g_XMSelect1110);\n\n                if (mConfig.forceSRGB)\n                {\n                    color = XMColorSRGBToRGB(color);\n                }\n            }\n            else\n            {\n                DebugTrace(\"WARNING: Invalid color value [record %zu]\\n\", index + 1);\n            }\n        }\n        else if (*colorStr)\n        {\n            if (wcscmp(colorStr, L\"RED\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::RED]);\n            }\n            else if (wcscmp(colorStr, L\"GREEN\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::GREEN]);\n            }\n            else if (wcscmp(colorStr, L\"BLUE\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::BLUE]);\n            }\n            else if (wcscmp(colorStr, L\"ORANGE\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::ORANGE]);\n            }\n            else if (wcscmp(colorStr, L\"YELLOW\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::YELLOW]);\n            }\n            else if (wcscmp(colorStr, L\"DARKGREY\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::DARK_GREY]);\n            }\n            else if (wcscmp(colorStr, L\"LIGHTGREY\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::LIGHT_GREY]);\n            }\n            else if (wcscmp(colorStr, L\"OFFWHITE\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::OFF_WHITE]);\n            }\n            else if (wcscmp(colorStr, L\"WHITE\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::WHITE]);\n            }\n            else if (wcscmp(colorStr, L\"BLACK\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::BLACK]);\n            }\n            else if (wcscmp(colorStr, L\"MID_GREY\") == 0)\n            {\n                color = XMLoadFloat4(&mConfig.colorDictionary[UIConfig::MID_GREY]);\n            }\n            else\n            {\n                DebugTrace(\"WARNING: Invalid color value [record %zu]\\n\", index + 1);\n            }\n        }\n\n        return color;\n    }\n};\n\nUIManager::Impl* UIManager::Impl::s_uiManager = nullptr;\n\n// Public constructors\nUIManager::UIManager(const UIConfig& config) :\n    pImpl(new Impl(config))\n{\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nUIManager::UIManager(\n    _In_ ID3D12Device *device,\n    const RenderTargetState& renderTarget,\n    ResourceUploadBatch& resourceUpload,\n    DescriptorPile& pile,\n    const UIConfig& config) :\n        pImpl(new Impl(config))\n{\n    pImpl->RestoreDevice(device, renderTarget, resourceUpload, pile);\n}\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\nUIManager::UIManager(_In_ ID3D11DeviceContext* context, const UIConfig& config) :\n    pImpl(new Impl(config))\n{\n    pImpl->RestoreDevice(context);\n}\n#endif\n\n\n// Move constructor.\nUIManager::UIManager(UIManager&& moveFrom)\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nUIManager& UIManager::operator= (UIManager&& moveFrom)\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nUIManager::~UIManager()\n{\n}\n\n\n// Public methods.\nvoid UIManager::LoadLayout(const wchar_t* layoutFile, const wchar_t* imageDir, unsigned offset)\n{\n    pImpl->LoadLayout(layoutFile, imageDir, offset);\n}\n\nvoid UIManager::Add(unsigned id, _In_ IPanel* panel)\n{\n    auto it = pImpl->m_panels.find(id);\n    if (it != pImpl->m_panels.end())\n    {\n        if (pImpl->m_focusPanel == it->second)\n        {\n            // For now, no focus stack\n            pImpl->m_focusPanel = nullptr;\n        }\n        if (pImpl->m_overlayPanel == it->second)\n        {\n            pImpl->m_overlayPanel = nullptr;\n        }\n        if (pImpl->m_hudPanel == it->second)\n        {\n            pImpl->m_hudPanel = nullptr;\n        }\n        delete it->second;\n    }\n\n    pImpl->m_panels[id] = panel;\n}\n\nIPanel* UIManager::Find(unsigned id) const\n{\n    auto it = pImpl->m_panels.find(id);\n    if (it != pImpl->m_panels.end())\n        return it->second;\n\n    return nullptr;\n}\n\nvoid UIManager::CloseAll()\n{\n    std::for_each(pImpl->m_panels.begin(), pImpl->m_panels.end(), [](auto pair)\n    {\n        auto panel = pair.second;\n        if (panel->IsVisible())\n            panel->Close();\n    });\n}\n\nbool UIManager::Update(float elapsedTime, const GamePad::State& pad)\n{\n    return pImpl->Update(elapsedTime, pad);\n}\n\nbool UIManager::Update(float elapsedTime, Mouse& mouse, Keyboard& kb)\n{\n    return pImpl->Update(elapsedTime, mouse, kb);\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nvoid UIManager::Render(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->m_commandList = commandList;\n    pImpl->Render();\n    pImpl->m_commandList = nullptr;\n}\n#else\nvoid UIManager::Render()\n{\n    pImpl->Render();\n}\n#endif\n\nvoid UIManager::SetWindow(const RECT& layout)\n{\n    pImpl->m_fullscreen = layout;\n\n    for (auto it : pImpl->m_panels)\n    {\n        if (it.second->IsVisible())\n        {\n            it.second->OnWindowSize(layout);\n        }\n    }\n\n    auto width = std::max<LONG>(layout.right - layout.left, 1);\n    auto height = std::max<LONG>(layout.bottom - layout.top, 1);\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    D3D12_VIEWPORT vp = { 0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH };\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n    D3D11_VIEWPORT vp = { 0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height), D3D11_MIN_DEPTH, D3D11_MAX_DEPTH };\n#endif\n    pImpl->m_batch->SetViewport(vp);\n}\n\nvoid UIManager::SetRotation(DXGI_MODE_ROTATION rotation)\n{\n    if (pImpl->m_batch)\n    {\n        pImpl->m_batch->SetRotation(rotation);\n    }\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nvoid UIManager::RegisterImage(unsigned id, D3D12_GPU_DESCRIPTOR_HANDLE tex, XMUINT2 texSize)\n{\n    std::pair<D3D12_GPU_DESCRIPTOR_HANDLE, XMUINT2> entry;\n    entry.first = tex;\n    entry.second = texSize;\n    pImpl->m_images[id] = entry;\n}\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\nvoid UIManager::RegisterImage(unsigned id, _In_ ID3D11ShaderResourceView* tex)\n{\n    pImpl->m_images[id] = tex;\n}\n#endif\n\nvoid UIManager::UnregisterImage(unsigned id)\n{\n    auto it = pImpl->m_images.find(id);\n    if (it != pImpl->m_images.end())\n    {\n        pImpl->m_images.erase(it);\n    }\n}\n\nvoid UIManager::UnregisterAllImages()\n{\n    pImpl->m_images.clear();\n}\n\nvoid UIManager::ReleaseDevice()\n{\n    pImpl->ReleaseDevice();\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nvoid UIManager::RestoreDevice(\n    _In_ ID3D12Device* device,\n    const DirectX::RenderTargetState& renderTarget,\n    DirectX::ResourceUploadBatch& resourceUpload,\n    DirectX::DescriptorPile& pile)\n{\n    pImpl->RestoreDevice(device, renderTarget, resourceUpload, pile);\n}\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\nvoid UIManager::RestoreDevice(_In_ ID3D11DeviceContext* context)\n{\n    pImpl->RestoreDevice(context);\n}\n#endif\n\nvoid UIManager::Reset()\n{\n    pImpl->Reset();\n}\n\nvoid UIManager::Clear()\n{\n    UIConfig config = pImpl->mConfig;\n    pImpl.reset(); // have to release singleton first\n    pImpl.reset(new Impl(config));\n}\n\nvoid UIManager::Enumerate(std::function<void(unsigned id, IPanel*)> enumCallback)\n{\n    for (auto it = pImpl->m_panels.begin(); it != pImpl->m_panels.end(); ++it)\n    {\n        enumCallback(it->first, it->second);\n    }\n}\n\n// Common callback adapters.\nvoid UIManager::CallbackYesNoCancel(_In_ IPanel* panel, std::function<void(bool,bool)> callback)\n{\n    assert(panel != 0);\n    assert(panel->GetUser() == nullptr);\n\n    pImpl->m_stdyesno.push_back(callback);\n    panel->SetUser(&pImpl->m_stdyesno.back());\n    panel->SetCallback(MessageYesNoCancel);\n}\n\n\n//=====================================================================================\n// Base control\n//=====================================================================================\nvoid IControl::ComputeLayout(const RECT& parent)\n{\n    m_screenRect.top = m_layoutRect.top + parent.top;\n    m_screenRect.bottom = m_layoutRect.bottom + parent.top;\n\n    m_screenRect.left = m_layoutRect.left + parent.left;\n    m_screenRect.right = m_layoutRect.right + parent.left;\n\n    // Constrain to parent bound\n    if (m_screenRect.top < parent.top)\n        m_screenRect.top = parent.top;\n\n    if (m_screenRect.left < parent.left)\n        m_screenRect.left = parent.left;\n\n    if (m_screenRect.right > parent.right)\n        m_screenRect.right = parent.right;\n\n    if (m_screenRect.bottom > parent.bottom)\n        m_screenRect.bottom = parent.bottom;\n}\n\nvoid IControl::ComputeLayout(const RECT& bounds, float dx, float dy)\n{\n    m_screenRect.left = long(float(m_layoutRect.left) * dx);\n    m_screenRect.right = long(float(m_layoutRect.right ) * dx);\n\n    m_screenRect.top = long(float(m_layoutRect.top) * dy);\n    m_screenRect.bottom = long(float(m_layoutRect.bottom) * dy);\n\n    // Add any offset\n    m_screenRect.top = m_screenRect.top + bounds.top;\n    m_screenRect.bottom = m_screenRect.bottom + bounds.top;\n\n    m_screenRect.left = m_screenRect.left + bounds.left;\n    m_screenRect.right = m_screenRect.right + bounds.left;\n\n    // Constrain to bound\n    if (m_screenRect.top < bounds.top)\n        m_screenRect.top = bounds.top;\n\n    if (m_screenRect.left < bounds.left)\n        m_screenRect.left = bounds.left;\n\n    if (m_screenRect.right > bounds.right)\n        m_screenRect.right = bounds.right;\n\n    if (m_screenRect.bottom > bounds.bottom)\n        m_screenRect.bottom = bounds.bottom;\n}\n\nvoid IControl::SetVisible(bool visible)\n{\n#ifdef _DEBUG\n    if (!visible && m_focus)\n    {\n        OutputDebugStringA(\"WARNING: Control made invisible while it was in focus!\\n\");\n    }\n#endif\n\n    m_visible = visible;\n}\n\n\n//=====================================================================================\n// Text static label control\n//=====================================================================================\n_Use_decl_annotations_\nTextLabel::TextLabel(unsigned id, const wchar_t* text, const RECT& rect, unsigned style) :\n    IControl(rect, id),\n    m_style(style),\n    m_text(text)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    m_fgColor = mgr->mConfig.colorNormal;\n    m_bgColor = mgr->mConfig.colorBackground;\n}\n\nvoid TextLabel::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Determine font\n    SpriteFont* font = mgr->SelectFont(m_style);\n\n    const wchar_t * text = m_text.c_str();\n\n    if (m_style & c_StyleWordWrap)\n    {\n        if (m_wordWrap.empty()\n            && (m_screenRect.right != 0 && m_screenRect.bottom != 0\n                && m_screenRect.left != m_screenRect.right\n                && m_screenRect.top != m_screenRect.bottom))\n        {\n            m_wordWrap = WordWrap(text, font, m_screenRect);\n        }\n\n        text = m_wordWrap.c_str();\n    }\n        \n    // Determine layout\n    XMFLOAT2 pos(float(m_screenRect.left), float(m_screenRect.top));\n    if (m_style & (c_StyleAlignCenter | c_StyleAlignRight | c_StyleAlignMiddle | c_StyleAlignBottom))\n    {\n        XMVECTOR fsize = font->MeasureString(text);\n\n        if (m_style & c_StyleAlignCenter)\n        {\n            pos.x = float(m_screenRect.left) + float((m_screenRect.right - m_screenRect.left) / 2) - XMVectorGetX(fsize) / 2.f;\n            if (pos.x < float(m_screenRect.left))\n                pos.x = float(m_screenRect.left);\n        }\n        else if (m_style & c_StyleAlignRight)\n        {\n            pos.x = float(m_screenRect.right - 1) - XMVectorGetX(fsize);\n            if (pos.x < float(m_screenRect.left))\n                pos.x = float(m_screenRect.left);\n        }\n\n        if (m_style & c_StyleAlignMiddle)\n        {\n            pos.y = float(m_screenRect.top) + float((m_screenRect.bottom - m_screenRect.top) / 2) - XMVectorGetY(fsize) / 2.f;\n            if (pos.y < float(m_screenRect.top))\n                pos.y = float(m_screenRect.top);\n        }\n        else if (m_style & c_StyleAlignBottom)\n        {\n            pos.y = float(m_screenRect.bottom - 1) - XMVectorGetY(fsize);\n            if (pos.y < float(m_screenRect.top))\n                pos.y = float(m_screenRect.top);\n        }\n    }\n\n    // Draw\n    if (m_bgColor.w != 0.f)\n    {\n        XMVECTOR bgColor = m_style & c_StyleTransparent ?\n            XMLoadFloat4(&mgr->mConfig.colorTransparent) :\n            XMLoadFloat4(&m_bgColor);\n\n        mgr->DrawRect(m_screenRect, bgColor);\n    }\n    \n    XMVECTOR color = XMLoadFloat4(&m_fgColor);\n\n    font->DrawString(mgr->m_batch.get(), text, pos, color);\n}\n\nvoid TextLabel::SetText(const wchar_t* text)\n{\n    m_text = text;\n    m_wordWrap.clear();\n}\n\nvoid TextLabel::ComputeLayout(const RECT& parent)\n{\n    m_wordWrap.clear();\n    IControl::ComputeLayout(parent);\n}\n\nvoid TextLabel::ComputeLayout(const RECT& bounds, float dx, float dy)\n{\n    m_wordWrap.clear();\n    IControl::ComputeLayout(bounds, dx, dy);\n}\n\n\n\n//=====================================================================================\n// Image static control\n//=====================================================================================\nImage::Image(unsigned id, unsigned imageId, const RECT& rect) :\n    IControl(rect, id),\n    m_imageId(imageId)\n{\n}\n\nvoid Image::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    mgr->DrawImage(m_imageId, m_screenRect, Colors::White);\n}\n\n\n//=====================================================================================\n// Static text label that supports the controller font\n//=====================================================================================\n_Use_decl_annotations_\nLegend::Legend(unsigned id, const wchar_t* text, const RECT& rect, unsigned style) :\n    IControl(rect, id),\n    m_style(style),\n    m_text(text)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    m_fgColor = mgr->mConfig.colorNormal;\n    m_bgColor = mgr->mConfig.colorBackground;\n}\n\nvoid Legend::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Determine font\n    SpriteFont* font = mgr->SelectFont(m_style);\n\n    SpriteFont* ctrlFont = nullptr;\n    if (m_style & c_StyleFontLarge)\n    {\n        ctrlFont = mgr->m_largeLegend.get();\n    }\n    else if (m_style & c_StyleFontSmall)\n    {\n        ctrlFont = mgr->m_smallLegend.get();\n    }\n    else\n    {\n        ctrlFont = mgr->m_smallLegend.get();\n    }\n\n    assert(ctrlFont != 0);\n\n    // Determine layout\n    XMFLOAT2 pos(float(m_screenRect.left), float(m_screenRect.top));\n    if (m_style & (c_StyleAlignCenter | c_StyleAlignRight | c_StyleAlignMiddle | c_StyleAlignBottom))\n    {\n        RECT rect = DX::MeasureControllerDrawBounds(font, ctrlFont, m_text.c_str(), pos);\n\n        if (m_style & c_StyleAlignCenter)\n        {\n            pos.x = float(m_screenRect.left) + float((m_screenRect.right - m_screenRect.left) / 2) - float(rect.right - rect.left) / 2.f;\n            if (pos.x < float(m_screenRect.left))\n                pos.x = float(m_screenRect.left);\n        }\n        else if (m_style & c_StyleAlignRight)\n        {\n            pos.x = float(m_screenRect.right - 1) - float(rect.right - rect.left);\n            if (pos.x < float(m_screenRect.left))\n                pos.x = float(m_screenRect.left);\n        }\n\n        if (m_style & c_StyleAlignMiddle)\n        {\n            pos.y = float(m_screenRect.top) + float((m_screenRect.bottom - m_screenRect.top) / 2) - float(rect.bottom - rect.top) / 2.f;\n            if (pos.y < float(m_screenRect.top))\n                pos.y = float(m_screenRect.top);\n        }\n        else if (m_style & c_StyleAlignBottom)\n        {\n            pos.y = float(m_screenRect.bottom - 1) - float(rect.bottom - rect.top);\n            if (pos.y < float(m_screenRect.top))\n                pos.y = float(m_screenRect.top);\n        }\n    }\n\n    // Draw\n    if(m_bgColor.w != 0.f)\n    {\n        XMVECTOR bgColor = m_style & c_StyleTransparent ?\n            XMLoadFloat4(&mgr->mConfig.colorTransparent) :\n            XMLoadFloat4(&m_bgColor);\n\n        mgr->DrawRect(m_screenRect, bgColor);\n    }\n        \n\n    XMVECTOR color = XMLoadFloat4(&m_fgColor);\n    DX::DrawControllerString(mgr->m_batch.get(), font, ctrlFont, m_text.c_str(), pos, color);\n}\n\n\n//=====================================================================================\n// Button control\n//=====================================================================================\n_Use_decl_annotations_\nButton::Button(unsigned id, const wchar_t* text, const RECT& rect) :\n    IControl(rect, id),\n    m_enabled(true),\n    m_showBorder(false),\n    m_noFocusColor(false),\n    m_style(c_StyleFontMid),\n    m_text(text)\n{\n    DirectX::XMStoreFloat4(&m_color, Colors::Black);\n}\n\nvoid Button::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Determine font\n    SpriteFont* font = mgr->SelectFont(m_style);\n\n    // Determine layout\n    XMVECTOR fsize = font->MeasureString(m_text.c_str());\n    XMFLOAT2 pos(float(m_screenRect.left) + float((m_screenRect.right - m_screenRect.left) / 2) - XMVectorGetX(fsize) / 2.f,\n                 float(m_screenRect.top) + float((m_screenRect.bottom - m_screenRect.top) / 2) - XMVectorGetY(fsize) / 2.f);\n    if (pos.x < float(m_screenRect.left))\n        pos.x = float(m_screenRect.left);\n    if (pos.y < float(m_screenRect.top))\n        pos.y = float(m_screenRect.top);\n\n    int borderWidth = 5;\n    RECT buttonRect = { m_screenRect.left + borderWidth, m_screenRect.top + borderWidth, m_screenRect.right - borderWidth, m_screenRect.bottom - borderWidth };\n\n    auto batch = mgr->m_batch.get();\n\n    XMVECTOR buttonColor;\n    XMVECTOR borderColor;\n    XMVECTOR fontColor;\n\n    buttonColor = (m_focus) ? XMLoadFloat4(&mgr->mConfig.colorFocus) : XMLoadFloat4(&m_color);\n    \n    if (m_focus && !m_noFocusColor)\n    {\n        buttonColor = XMLoadFloat4(&mgr->mConfig.colorFocus);\n    }\n    else\n    {\n        buttonColor = XMLoadFloat4(&m_color);\n    }\n\n    borderColor = XMLoadFloat4(&mgr->mConfig.colorNormal);\n    fontColor = XMLoadFloat4(&mgr->mConfig.colorNormal);\n\n    if(!m_enabled)\n    {\n        buttonColor = XMVectorScale(buttonColor, 0.35f);\n        borderColor = XMVectorScale(borderColor, 0.35f);\n        fontColor = XMVectorScale(fontColor, 0.35f);\n    }\n\n    if (m_focusOnText && m_focus)\n    {\n        fontColor = XMLoadFloat4(&mgr->mConfig.colorFocus);\n    }\n\n    if (m_showBorder && m_focus)\n    {\n        mgr->DrawRect(m_screenRect, borderColor);\n        mgr->DrawRect(buttonRect, buttonColor);\n    }\n    else\n    {\n        mgr->DrawRect(m_screenRect, buttonColor);\n    }\n\n    if (m_focus)\n    {\n        float luminance = 0.2126f * mgr->mConfig.colorFocus.x * mgr->mConfig.colorFocus.x +\n            0.7152f * mgr->mConfig.colorFocus.y * mgr->mConfig.colorFocus.y +\n            0.0722f * mgr->mConfig.colorFocus.z * mgr->mConfig.colorFocus.z;\n\n        if (luminance > 0.0722f)\n        {\n            // black would be best contrast with focus color\n            font->DrawString(batch, m_text.c_str(), pos, Colors::Black);\n        }\n        else\n        {\n            font->DrawString(batch, m_text.c_str(), pos, fontColor);\n        }\n    }\n    else\n    {\n        float luminance = 0.2126f * m_color.x * m_color.x +\n            0.7152f * m_color.y * m_color.y +\n            0.0722f * m_color.z * m_color.z;\n\n        if (luminance > 0.0722f)\n        {\n            // black would be best contrast with button color\n            font->DrawString(batch, m_text.c_str(), pos, Colors::Black);\n        }\n        else\n        {\n            fontColor = XMVectorScale(fontColor, 0.6f);\n            font->DrawString(batch, m_text.c_str(), pos, fontColor);\n        }\n    }\n}\n\nbool Button::OnSelected(IPanel* panel)\n{\n    if (m_callBack)\n    {\n        m_callBack(panel, this);\n    }\n    \n    if (m_style & c_StyleExit)\n    {\n        return true;\n    }\n    return false;\n}\n\n//=====================================================================================\n// Image button control\n//=====================================================================================\nImageButton::ImageButton(unsigned id, unsigned imageId, const RECT& rect) :\n    IControl(rect, id),\n    m_enabled(true),\n    m_style(0),\n    m_imageId(imageId)\n{\n}\n\nvoid ImageButton::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (m_style & c_StyleBackground)\n    {\n        XMVECTOR bgColor;\n        if (m_focus)\n        {\n            bgColor = XMLoadFloat4(&mgr->mConfig.colorFocus);\n        }\n        else\n        {\n            bgColor = XMLoadFloat4((m_style & c_StyleTransparent) ? &mgr->mConfig.colorTransparent : &mgr->mConfig.colorBackground);\n        }\n\n        mgr->DrawRect(m_screenRect, bgColor);\n    }\n\n    XMVECTOR fgColor;\n    if (m_focus)\n    {\n        fgColor = XMLoadFloat4(&mgr->mConfig.colorSelected);\n    }\n    else\n    {\n        fgColor = XMLoadFloat4(m_enabled ? &mgr->mConfig.colorNormal : &mgr->mConfig.colorDisabled);\n    }\n\n    mgr->DrawImage(m_imageId, m_screenRect, fgColor);\n}\n\nbool ImageButton::OnSelected(IPanel* panel)\n{\n    if (m_callBack)\n    {\n        m_callBack(panel, this);\n    }\n\n    if (m_style & c_StyleExit)\n    {\n        return true;\n    }\n    return false;\n}\n\n\n//=====================================================================================\n// CheckBox control\n//=====================================================================================\n_Use_decl_annotations_\nCheckBox::CheckBox(unsigned id, const wchar_t* text, const RECT& rect, bool checked) :\n    IControl(rect, id),\n    m_enabled(true),\n    m_checked(checked),\n    m_style(c_StyleFontMid),\n    m_text(text)\n{\n}\n\nvoid CheckBox::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Determine font\n    SpriteFont* font = mgr->SelectFont(m_style);\n\n    float spacing = font->GetLineSpacing();\n\n    long boxThickness = std::max<long>(1, long(spacing * 0.1f));\n    long boxOuter = std::max<long>(2, long(spacing) - boxThickness * 2);\n\n    // Determine layout\n    RECT chkrct = { m_screenRect.left + boxThickness, m_screenRect.top + boxThickness, m_screenRect.left + boxOuter, m_screenRect.bottom - boxThickness };\n\n    XMFLOAT2 pos(float(m_screenRect.left) + boxOuter, float(m_screenRect.top));\n\n    // Draw\n    XMVECTOR bgColor;\n    if (m_focus)\n    {\n        bgColor = XMLoadFloat4(&mgr->mConfig.colorFocus);\n    }\n    else\n    {\n        bgColor = XMLoadFloat4((m_style & c_StyleTransparent) ? &mgr->mConfig.colorTransparent : &mgr->mConfig.colorBackground);\n    }\n\n    auto batch = mgr->m_batch.get();\n\n    mgr->DrawRect(m_screenRect, bgColor);\n\n    XMVECTOR fgColor = XMLoadFloat4(m_enabled ? &mgr->mConfig.colorNormal : &mgr->mConfig.colorDisabled);\n    XMVECTOR ckColor = XMLoadFloat4(&mgr->mConfig.colorBackground);\n\n    mgr->DrawRect(chkrct, fgColor);\n\n    chkrct.left += boxThickness;\n    chkrct.top += boxThickness;\n    chkrct.right -= boxThickness;\n    chkrct.bottom -= boxThickness;\n\n    mgr->DrawRect(chkrct, ckColor);\n    \n    font->DrawString(batch, m_text.c_str(), pos, fgColor);\n\n    if (m_checked)\n    {\n        chkrct.left += boxThickness;\n        chkrct.top += boxThickness;\n        chkrct.right -= boxThickness;\n        chkrct.bottom -= boxThickness;\n\n        mgr->DrawRect(chkrct, fgColor);\n    }\n}\n\nbool CheckBox::OnSelected(IPanel* panel)\n{\n    if (m_enabled)\n    {\n        m_checked = !m_checked;\n    }\n\n    if (m_callBack)\n    {\n        m_callBack(panel, this);\n    }\n\n    return false;\n}\n\n\n//=====================================================================================\n// Slider control\n//=====================================================================================\nSlider::Slider(unsigned id, const RECT& rect, int value, int minValue, int maxValue) :\n    IControl(rect, id),\n    m_enabled(true),\n    m_dragging(false),\n    m_style(0),\n    m_value(value),\n    m_minValue(minValue),\n    m_maxValue(maxValue),\n    m_thumbRect{}\n{\n}\n\nvoid Slider::SetValue(int value)\n{\n    value = std::max(std::min(m_maxValue, value), m_minValue);\n\n    if (value == m_value)\n        return;\n\n    m_value = value;\n\n    if (m_callBack)\n        m_callBack(m_parent, this);\n}\n\nvoid Slider::SetRange(int minValue, int maxValue)\n{\n    if (minValue >= maxValue)\n    {\n        throw std::out_of_range(\"Slider::SetRange\");\n    }\n\n    m_minValue = minValue;\n    m_maxValue = maxValue;\n\n    int value = std::max(std::min(m_maxValue, m_value), m_minValue);\n    if (value == m_value)\n        return;\n\n    m_value = value;\n\n    if (m_callBack)\n        m_callBack(m_parent, this);\n}\n\nvoid Slider::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Compute 'thumb' rectangle\n    float dy = float(m_screenRect.right - m_screenRect.left);\n\n    long boxThickness = std::max<long>(4, long(dy * 0.05f));\n\n    int thumbX = static_cast<int>( float( m_value - m_minValue ) * dy / float(m_maxValue - m_minValue));\n\n    m_thumbRect.top = m_screenRect.top + 2;\n    m_thumbRect.bottom = m_screenRect.bottom - 2;\n\n    m_thumbRect.left = m_screenRect.left + thumbX - boxThickness / 2;\n    m_thumbRect.right = m_thumbRect.left + boxThickness;\n\n    if (m_thumbRect.left < m_screenRect.left)\n        m_thumbRect.left = m_screenRect.left;\n    if (m_thumbRect.right > m_screenRect.right)\n        m_thumbRect.right = m_screenRect.right;\n\n    // Draw\n    XMVECTOR bgColor;\n    if (m_focus)\n    {\n        bgColor = XMLoadFloat4(&mgr->mConfig.colorFocus);\n    }\n    else\n    {\n        bgColor = XMLoadFloat4((m_style & c_StyleTransparent) ? &mgr->mConfig.colorTransparent : &mgr->mConfig.colorBackground);\n    }\n\n    mgr->DrawRect(m_screenRect, bgColor);\n\n    XMVECTOR fgColor = XMLoadFloat4(m_enabled ? &mgr->mConfig.colorHighlight : &mgr->mConfig.colorDisabled);\n\n    mgr->DrawRect(m_thumbRect, fgColor);\n}\n\nvoid Slider::OnFocus(bool in)\n{\n    IControl::OnFocus(in);\n\n    if (!in)\n    {\n        m_dragging = false;\n    }\n}\n\nbool Slider::Update(float elapsedTime, const DirectX::GamePad::State& pad)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (pad.IsLeftThumbStickLeft())\n    {\n        SetValue(m_value - 1);\n    }\n    else if ( pad.IsLeftThumbStickRight() )\n    {\n        SetValue(m_value + 1);\n    }\n\n    if (mgr->m_padButtonState.dpadLeft == GamePad::ButtonStateTracker::PRESSED)\n    {\n        SetValue(m_value - 1);\n    }\n    else if (mgr->m_padButtonState.dpadRight == GamePad::ButtonStateTracker::PRESSED)\n    {\n        SetValue(m_value + 1);\n    }\n\n    return false;\n}\n\nbool Slider::Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Handle mouse\n    if (m_dragging)\n    {\n        if (!mstate.leftButton)\n        {\n            m_dragging = false;\n        }\n        else\n        {\n            float dy = float(m_screenRect.right - m_screenRect.left);\n            float vpp = float(m_maxValue - m_minValue) / dy;\n\n            int x = mstate.x;\n\n            SetValue(int(0.5f + m_minValue + vpp * float(x - m_screenRect.left)));\n        }\n\n        return true;\n    }\n    else if (mstate.x >= m_screenRect.left && mstate.x < m_screenRect.right\n             && mstate.y >= m_screenRect.top && mstate.y < m_screenRect.bottom)\n    {\n        if (mgr->m_mouseButtonState.leftButton == Mouse::ButtonStateTracker::PRESSED)\n        {\n            if (mstate.x >= m_thumbRect.left && mstate.x < m_thumbRect.right\n                && mstate.y >= m_thumbRect.top && mstate.y < m_thumbRect.bottom)\n            {\n                m_dragging = true;\n                return true;\n            }\n            else if (mstate.x > m_thumbRect.right)\n            {\n                SetValue(m_value + 1);\n                return true;\n            }\n            else if (mstate.x < m_thumbRect.left)\n            {\n                SetValue(m_value - 1);\n                return true;\n            }\n        }\n    }\n\n    // Handle keyboard\n    if (kbstate.IsKeyDown(Keyboard::Left))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Left))\n        {\n            SetValue(m_value - 1);\n        }\n\n        return true;\n    }\n    else  if (kbstate.IsKeyDown(Keyboard::Right))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Right))\n        {\n            SetValue(m_value + 1);\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::Home))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Home))\n        {\n            SetValue(m_minValue);\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::End))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::End))\n        {\n            SetValue(m_maxValue);\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::PageUp))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::PageUp))\n        {\n            int tenth = std::min( 10, (m_maxValue - m_minValue) / 10 );\n            SetValue( m_value - tenth);\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::PageDown))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::PageDown))\n        {\n            int tenth = std::min(10, (m_maxValue - m_minValue) / 10);\n            SetValue(m_value + tenth);\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\n\n//=====================================================================================\n// Progress Bar\n//=====================================================================================\nProgressBar::ProgressBar(unsigned id, const RECT& rect, bool visible, float start) :\n    IControl(rect, id),\n    m_progress(start),\n    m_showPct(false)\n{\n    m_visible = visible;\n\n}\n\n\nProgressBar::~ProgressBar()\n{\n}\n\nvoid ProgressBar::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    auto batch = mgr->m_batch.get();\n    auto font = mgr->m_smallFont.get();\n\n    int border = 2;\n    long width = m_screenRect.left + long((m_screenRect.right - m_screenRect.left - 2 * border) * m_progress);\n    RECT inner = { m_screenRect.left + border, m_screenRect.top + border, m_screenRect.right - border, m_screenRect.bottom - border };\n    RECT bar = { m_screenRect.left + border, m_screenRect.top + border, width, m_screenRect.bottom - border };\n\n    mgr->DrawRect(m_screenRect, XMLoadFloat4(&mgr->mConfig.colorBackground));\n    mgr->DrawRect(inner, XMLoadFloat4(&mgr->mConfig.colorProgress));\n    mgr->DrawRect(bar, XMLoadFloat4(&mgr->mConfig.colorFocus));\n\n    if (m_showPct)\n    {\n        XMFLOAT2 pos;\n        pos.x = float(m_screenRect.left + 2);\n        pos.y = float(m_screenRect.top + 2);\n\n        wchar_t str[32];\n        swprintf_s(str, 32, L\"%.1f%%\", m_progress * 100.f);\n\n        font->DrawString(batch, str, pos, XMLoadFloat4(&mgr->mConfig.colorNormal));\n    }\n}\n\n\n//=====================================================================================\n// List Box\n//=====================================================================================\nListBox::ListBox(unsigned id, const RECT& rect, unsigned style, int itemHeight) :\n    IControl(rect, id),\n    m_enabled(true),\n    m_itemHeight(itemHeight),\n    m_style(style),\n    m_topItem(0),\n    m_focusItem(0),\n    m_itemRect{},\n    m_scrollRect{},\n    m_trackRect{},\n    m_thumbRect{},\n    m_lastHeight(0)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n}\n\nListBox::~ListBox()\n{\n}\n\n_Use_decl_annotations_\nvoid ListBox::AddItem(const wchar_t* text, void *user)\n{\n    Item item = {};\n    item.text = text;\n    item.user = user;\n\n    m_items.emplace_back(item);\n}\n\n_Use_decl_annotations_\nvoid ListBox::InsertItem(int index, const wchar_t* text, void *user)\n{\n    Item item = {};\n    item.text = text;\n    item.user = user;\n\n    int item_size = static_cast<int>(m_items.size());\n    if ((item_size != 0) && (index >= item_size))\n    {\n        m_items[size_t(index)] = item;\n    }\n    else\n    {\n        m_items.emplace(m_items.cbegin() + index, item);\n    }\n}\n\nvoid ListBox::RemoveItem(int index)\n{\n    if (index < 0 || index >= static_cast<int>(m_items.size()))\n        throw std::out_of_range(\"RemoveItem\");\n\n    auto it = m_items.begin() + index;\n\n    bool selected = it->selected;\n\n    m_items.erase(it);\n\n    if (m_topItem >= static_cast<int>(m_items.size()))\n        --m_topItem;\n\n    if (m_focusItem >= static_cast<int>(m_items.size()))\n        --m_focusItem;\n\n    if (selected && m_callBack)\n        m_callBack(m_parent, this);\n}\n\nvoid ListBox::RemoveAllItems()\n{\n    m_items.clear();\n    m_topItem = m_focusItem = 0;\n}\n\nint ListBox::GetSelectedItem() const\n{\n    for(auto it = m_items.cbegin(); it != m_items.cend(); ++it)\n    {\n        if (it->selected)\n            return static_cast<int>(it - m_items.cbegin());\n    }\n\n    return -1;\n}\n\nstd::vector<int> ListBox::GetSelectedItems() const\n{\n    std::vector <int> selected;\n\n    for (auto it = m_items.cbegin(); it != m_items.cend(); ++it)\n    {\n        if (it->selected)\n            selected.push_back(static_cast<int>(it - m_items.cbegin()));\n    }\n\n    return selected;\n}\n\nvoid ListBox::ClearSelection()\n{\n    bool changed = false;\n\n    for (auto&i : m_items)\n    {\n        if (i.selected)\n        {\n            i.selected = false;\n            changed = true;\n        }\n    }\n\n    if (changed && m_callBack)\n        m_callBack(m_parent, this);\n}\n\nvoid ListBox::SelectItem(int index)\n{\n    if (index < 0 || index >= static_cast<int>(m_items.size()))\n        throw std::out_of_range(\"SelectItem\");\n\n    auto it = m_items.begin() + index;\n\n    bool changed = false;\n\n    if (m_style & c_StyleMultiSelection)\n    {\n        it->selected = !it->selected;\n        changed = true;\n    }\n    else if (!it->selected)\n    {\n        for (auto& i : m_items)\n        {\n            i.selected = false;\n        }\n\n        it->selected = true;\n\n        changed = true;\n    }\n\n    if (m_callBack && changed)\n        m_callBack(m_parent, this);\n}\n\nvoid ListBox::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    m_itemRect.left = m_screenRect.left + c_BorderSize;\n    m_itemRect.top = m_screenRect.top + c_BorderSize;\n\n    m_itemRect.right = m_screenRect.right - c_BorderSize;\n    if (m_style & c_StyleScrollBar)\n        m_itemRect.right -= c_ScrollWidth;\n    m_itemRect.bottom = m_screenRect.bottom - c_BorderSize;\n\n    if (m_itemRect.top < m_screenRect.top)\n        m_itemRect.top = m_screenRect.top;\n\n    if (m_itemRect.left < m_screenRect.left)\n        m_itemRect.left = m_screenRect.left;\n\n    if (m_itemRect.right > m_screenRect.right)\n        m_itemRect.right = m_screenRect.right;\n\n    if (m_itemRect.bottom > m_screenRect.bottom)\n        m_itemRect.bottom = m_screenRect.bottom;\n\n    m_scrollRect.left = m_screenRect.right - c_ScrollWidth - c_BorderSize;\n    m_scrollRect.right = m_screenRect.right - c_BorderSize;\n    m_scrollRect.top = m_screenRect.top + c_BorderSize;\n    m_scrollRect.bottom = m_screenRect.bottom - c_BorderSize;\n\n    UpdateRects();\n\n    auto batch = mgr->m_batch.get();\n\n    XMVECTOR bgColor = XMLoadFloat4((m_style & c_StyleTransparent) ? &mgr->mConfig.colorTransparent : &mgr->mConfig.colorBackground);\n    mgr->DrawRect(m_screenRect, bgColor);\n\n    if (!m_items.empty())\n    {\n        SpriteFont* font = mgr->SelectFont(m_style);\n\n        m_lastHeight = (m_itemHeight <= 0) ? static_cast<int>(font->GetLineSpacing()) : m_itemHeight;\n        int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize*2) / float(m_lastHeight));\n\n        if (m_focusItem < m_topItem)\n            m_topItem = m_focusItem;\n\n        if (m_focusItem >= (m_topItem + maxl))\n            m_topItem = m_focusItem;\n\n        XMFLOAT2 pos = { float(m_itemRect.left), float(m_itemRect.top) };\n\n        RECT selectRect = { m_itemRect.left, m_itemRect.top, m_itemRect.right, m_itemRect.top + m_lastHeight };\n\n        for (int j = m_topItem; j < static_cast<int>(m_items.size()); ++j)\n        {\n            if (pos.y + float(m_lastHeight) >= (m_itemRect.bottom - c_MarginSize))\n                break;\n\n            auto& item = m_items[size_t(j)];\n\n            if (m_focus && m_focusItem == j)\n            {\n                XMVECTOR color = XMLoadFloat4(&mgr->mConfig.colorFocus);\n                XMVECTOR fgColor = XMLoadFloat4((item.selected) ? &mgr->mConfig.colorHighlight : &mgr->mConfig.colorNormal);\n\n                mgr->DrawRect(selectRect, color);\n                font->DrawString(batch, item.text.c_str(), pos, fgColor);\n            }\n            else\n            {\n                XMVECTOR fgColor = XMLoadFloat4(m_enabled ? &mgr->mConfig.colorNormal : &mgr->mConfig.colorDisabled);\n\n                if (item.selected)\n                {\n                    XMVECTOR color = XMLoadFloat4(&mgr->mConfig.colorSelected);\n                    mgr->DrawRect(selectRect, color);\n                }\n\n                font->DrawString(batch, item.text.c_str(), pos, fgColor);\n            }\n\n            pos.y += float(m_lastHeight);\n            selectRect.top += m_lastHeight;\n            selectRect.bottom += m_lastHeight;\n        }\n    }\n\n    if (m_style & c_StyleScrollBar)\n    {\n        XMVECTOR scrollColor = XMLoadFloat4(&mgr->mConfig.colorNormal);\n\n        mgr->DrawRect(m_scrollRect, scrollColor);\n        mgr->DrawRect(m_trackRect, bgColor);\n        if (m_thumbRect.top != m_thumbRect.bottom)\n        {\n            mgr->DrawRect(m_thumbRect, scrollColor);\n        }\n    }\n}\n\nbool ListBox::Update(float elapsedTime, const DirectX::GamePad::State& pad)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n    UNREFERENCED_PARAMETER(pad);\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    assert(m_focusItem >= 0 && m_focusItem < static_cast<int>(m_items.size()));\n\n    if (mgr->m_padButtonState.a == GamePad::ButtonStateTracker::PRESSED)\n    {\n        if (!m_items.empty())\n        {\n            SelectItem(m_focusItem);\n        }\n        return true;\n    }\n    else  if (mgr->m_padButtonState.y == GamePad::ButtonStateTracker::PRESSED)\n    {\n        if (m_style & c_StyleMultiSelection)\n        {\n            ClearSelection();\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickUp == GamePad::ButtonStateTracker::PRESSED)\n    {\n        mgr->m_heldTimer = c_HoldTimeStart;\n        if (!m_items.empty())\n        {\n            --m_focusItem;\n            if (m_focusItem < 0)\n            {\n                m_focusItem = static_cast<int>(m_items.size() - 1);\n            }\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickUp == GamePad::ButtonStateTracker::HELD)\n    {\n        if (!m_items.empty() && mgr->m_heldTimer <= 0.f)\n        {\n            --m_focusItem;\n            if (m_focusItem < 0)\n            {\n                m_focusItem = static_cast<int>(m_items.size() - 1);\n            }\n            mgr->m_heldTimer = c_HoldTimeRepeat;\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickDown == GamePad::ButtonStateTracker::PRESSED)\n    {\n        mgr->m_heldTimer = c_HoldTimeStart;\n        if (!m_items.empty())\n        {\n            ++m_focusItem;\n            if (m_focusItem >= static_cast<int>(m_items.size()))\n            {\n                m_focusItem = 0;\n            }\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickDown == GamePad::ButtonStateTracker::HELD)\n    {\n        if (!m_items.empty() && mgr->m_heldTimer <= 0.f)\n        {\n            ++m_focusItem;\n            if (m_focusItem >= static_cast<int>(m_items.size()))\n            {\n                m_focusItem = 0;\n            }\n            mgr->m_heldTimer = c_HoldTimeRepeat;\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStick == GamePad::ButtonStateTracker::PRESSED)\n    {\n        if (!m_items.empty())\n        {\n            m_focusItem = 0;\n        }\n    }\n\n    return false;\n}\n\nbool ListBox::Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    assert(m_focusItem >= 0 && m_focusItem < static_cast<int>(m_items.size()));\n\n    // Handle mouse\n    if (mstate.x >= m_itemRect.left && mstate.x < m_itemRect.right\n        && mstate.y >= m_itemRect.top && mstate.y < m_itemRect.bottom)\n    {\n        if (m_lastHeight > 0)\n        {\n            int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n            int item = static_cast<int>(float(mstate.y - m_itemRect.top - c_MarginSize) / float(m_lastHeight));\n            if (item >= 0 && item < maxl)\n            {\n                item = m_topItem + item;\n                if (item >= 0 && item < static_cast<int>(m_items.size()))\n                {\n                    m_focusItem = item;\n\n                    if (mgr->m_mouseButtonState.leftButton == Mouse::ButtonStateTracker::PRESSED)\n                    {\n                        SelectItem(m_focusItem);\n                    }\n                }\n            }\n        }\n        return true;\n    }\n\n    if ((m_style & c_StyleScrollBar) && (m_thumbRect.top != m_thumbRect.bottom))\n    {\n        if (mstate.x >= m_scrollRect.left && mstate.x < m_scrollRect.right\n            && mstate.y >= m_scrollRect.top && mstate.y < m_scrollRect.bottom)\n        {\n            if (mgr->m_mouseButtonState.leftButton == Mouse::ButtonStateTracker::PRESSED)\n            {\n                if (mstate.y < m_thumbRect.top)\n                {\n                    if (!m_items.empty() && (m_lastHeight > 0))\n                    {\n                        int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n                        m_focusItem -= maxl;\n                        if (m_focusItem < 0)\n                            m_focusItem = 0;\n                    }\n                }\n                else if (mstate.y > m_thumbRect.bottom)\n                {\n                    if (!m_items.empty() && (m_lastHeight > 0))\n                    {\n                        int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n                        m_focusItem += maxl;\n                        if (m_focusItem >= static_cast<int>(m_items.size()))\n                            m_focusItem = static_cast<int>(m_items.size() - 1);\n                    }\n                }\n            }\n            return true;\n        }\n    }\n\n    // Handle keyboard\n\n    if (kbstate.IsKeyDown(Keyboard::Space))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Space))\n        {\n            if (!m_items.empty())\n            {\n                SelectItem(m_focusItem);\n            }\n        }\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::W))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::W))\n        {\n            if (!m_items.empty())\n            {\n                --m_focusItem;\n                if (m_focusItem < 0)\n                {\n                    m_focusItem = static_cast<int>(m_items.size() - 1);\n                }\n            }\n        }\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::S))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::S))\n        {\n            if (!m_items.empty())\n            {\n                ++m_focusItem;\n                if (m_focusItem >= static_cast<int>(m_items.size()))\n                {\n                    m_focusItem = 0;\n                }\n            }\n        }\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::Home))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Home))\n        {\n            m_focusItem = 0;\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::End))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::End))\n        {\n            if (!m_items.empty())\n            {\n                m_focusItem = static_cast<int>(m_items.size() - 1);\n            }\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::PageUp))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::PageUp))\n        {\n            if (!m_items.empty() && (m_lastHeight > 0))\n            {\n                int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n                m_focusItem -= maxl;\n                if (m_focusItem < 0)\n                    m_focusItem = 0;\n            }\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::PageDown))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::PageDown))\n        {\n            if (!m_items.empty() && (m_lastHeight > 0))\n            {\n                int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n                m_focusItem += maxl;\n                if (m_focusItem >= static_cast<int>(m_items.size()))\n                    m_focusItem = static_cast<int>(m_items.size() - 1);\n            }\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\nvoid ListBox::UpdateRects()\n{\n    m_trackRect.top = m_scrollRect.top + 1;\n    m_trackRect.left = m_scrollRect.left + 1;\n    m_trackRect.right = m_scrollRect.right - 1;\n    m_trackRect.bottom = m_scrollRect.bottom - 1;\n\n    m_thumbRect.left = m_trackRect.left;\n    m_thumbRect.right = m_trackRect.right;\n\n    if (m_items.empty() || !m_lastHeight)\n    {\n        m_thumbRect.bottom = m_thumbRect.top;\n        return;\n    }\n\n    int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n\n    UpdateScrollBar(m_thumbRect, m_trackRect, m_topItem, 0, static_cast<int>(m_items.size()), maxl);\n}\n\n//=====================================================================================\n// Text List\n//=====================================================================================\nTextList::TextList(unsigned id, const RECT& rect, unsigned style, int itemHeight) :\n    IControl(rect, id),\n    m_itemHeight(itemHeight),\n    m_style(style),\n    m_topItem(0),\n    m_itemRect{},\n    m_lastHeight(0)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n}\n\nTextList::~TextList()\n{\n\n}\n\n_Use_decl_annotations_\nvoid XM_CALLCONV TextList::AddItem(const wchar_t* text, FXMVECTOR color)\n{\n    Item item = {};\n    item.text = text;\n    XMStoreFloat4(&item.color, color);\n    m_items.emplace_back(item);\n}\n\n_Use_decl_annotations_\nvoid XM_CALLCONV TextList::InsertItem(int index, const wchar_t* text, FXMVECTOR color)\n{\n    Item item = {};\n    item.text = text;\n    XMStoreFloat4(&item.color, color);\n    int item_size = static_cast<int>(m_items.size());\n    if ((item_size != 0) && (index >= item_size))\n    {\n        m_items[size_t(index)] = item;\n    }\n    else\n    {\n        m_items.emplace(m_items.cbegin() + index, item);\n    }\n}\n\nvoid TextList::RemoveItem(int index)\n{\n    if (index < 0 || index >= static_cast<int>(m_items.size()))\n        throw std::out_of_range(\"RemoveItem\");\n\n    auto it = m_items.begin() + index;\n    m_items.erase(it);\n    if (m_topItem >= static_cast<int>(m_items.size()))\n        --m_topItem;    \n}\n\nvoid TextList::RemoveAllItems()\n{\n    m_items.clear();\n    m_topItem = 0;\n}\n\nvoid TextList::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    m_itemRect.left = m_screenRect.left + c_BorderSize;\n    m_itemRect.top = m_screenRect.top + c_BorderSize;\n    m_itemRect.right = m_screenRect.right - c_BorderSize;\n    m_itemRect.bottom = m_screenRect.bottom - c_BorderSize;\n\n    if (m_itemRect.top < m_screenRect.top)\n        m_itemRect.top = m_screenRect.top;\n\n    if (m_itemRect.left < m_screenRect.left)\n        m_itemRect.left = m_screenRect.left;\n\n    if (m_itemRect.right > m_screenRect.right)\n        m_itemRect.right = m_screenRect.right;\n\n    if (m_itemRect.bottom > m_screenRect.bottom)\n        m_itemRect.bottom = m_screenRect.bottom;\n\n    if (!m_items.empty())\n    {\n        SpriteFont* font = mgr->SelectFont(m_style);\n\n        m_lastHeight = (m_itemHeight <= 0) ? static_cast<int>(font->GetLineSpacing()) : m_itemHeight;\n                \n        XMFLOAT2 pos = { float(m_itemRect.left), float(m_itemRect.top) };\n\n        RECT selectRect = { m_itemRect.left, m_itemRect.top, m_itemRect.right, m_itemRect.top + m_lastHeight };\n\n        for (int j = m_topItem; j < static_cast<int>(m_items.size()); ++j)\n        {\n            if (pos.y + float(m_lastHeight) >= (m_itemRect.bottom - c_MarginSize))\n                break;\n\n            auto& item = m_items[size_t(j)];\n\n            font->DrawString(mgr->m_batch.get(), item.text.c_str(), pos, XMLoadFloat4(&(item.color)));\n\n            pos.y += float(m_lastHeight);\n            selectRect.top += m_lastHeight;\n            selectRect.bottom += m_lastHeight;\n        }\n    }\n}\n\nbool TextList::Update(float elapsedTime, const DirectX::GamePad::State& pad)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n    UNREFERENCED_PARAMETER(pad);\n\n    return false;\n}\n\nbool TextList::Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n    UNREFERENCED_PARAMETER(mstate);\n    UNREFERENCED_PARAMETER(kbstate);\n    return false;\n}\n\n\n//=====================================================================================\n// Text Box\n//=====================================================================================\nTextBox::TextBox(unsigned id, _In_z_ const wchar_t* text, const RECT& rect, unsigned style) :\n    IControl(rect, id),\n    m_style(style),\n    m_topLine(0),\n    m_itemRect{},\n    m_scrollRect{},\n    m_trackRect{},\n    m_thumbRect{},\n    m_lastHeight(0),\n    m_text(text),\n    m_lastWheelValue(0)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    m_color = mgr->mConfig.colorNormal;\n}\n\nTextBox::~TextBox()\n{\n}\n\nvoid TextBox::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    m_itemRect.left = m_screenRect.left + c_BorderSize;\n    m_itemRect.top = m_screenRect.top + c_BorderSize;\n\n    m_itemRect.right = m_screenRect.right - c_BorderSize;\n    if (m_style & c_StyleScrollBar)\n        m_itemRect.right -= c_ScrollWidth;\n    m_itemRect.bottom = m_screenRect.bottom - c_BorderSize;\n\n    if (m_itemRect.top < m_screenRect.top)\n        m_itemRect.top = m_screenRect.top;\n\n    if (m_itemRect.left < m_screenRect.left)\n        m_itemRect.left = m_screenRect.left;\n\n    if (m_itemRect.right > m_screenRect.right)\n        m_itemRect.right = m_screenRect.right;\n\n    if (m_itemRect.bottom > m_screenRect.bottom)\n        m_itemRect.bottom = m_screenRect.bottom;\n\n    m_scrollRect.left = m_screenRect.right - c_ScrollWidth - c_BorderSize;\n    m_scrollRect.right = m_screenRect.right - c_BorderSize;\n    m_scrollRect.top = m_screenRect.top + c_BorderSize;\n    m_scrollRect.bottom = m_screenRect.bottom - c_BorderSize;\n\n    UpdateRects();\n\n    XMVECTOR bgColor;\n    if (m_focus)\n    {\n        XMVECTOR fgColor = XMLoadFloat4(&mgr->mConfig.colorSelected);\n        bgColor = XMLoadFloat4((m_style & c_StyleTransparent) ? &mgr->mConfig.colorTransparent : &mgr->mConfig.colorBackground);\n\n        if(!(m_style & c_StyleNoBackground))\n        {\n            mgr->DrawRect(m_screenRect, fgColor);\n\n            RECT rect;\n            rect.left = m_screenRect.left + 1;\n            rect.top = m_screenRect.top + 1;\n            rect.right = m_screenRect.right - 1;\n            rect.bottom = m_screenRect.bottom - 1;\n\n            mgr->DrawRect(rect, bgColor);\n        }\n    }\n    else\n    {\n        bgColor = XMLoadFloat4((m_style & c_StyleTransparent) ? &mgr->mConfig.colorTransparent : &mgr->mConfig.colorBackground);\n\n        if(!(m_style & c_StyleNoBackground))\n        {\n            mgr->DrawRect(m_screenRect, bgColor);\n        }\n    }\n\n    if (!m_text.empty())\n    {\n        SpriteFont* font = mgr->SelectFont(m_style);\n\n        m_lastHeight = static_cast<int>(font->GetLineSpacing());\n\n        const wchar_t * text = m_text.c_str();\n\n        if (m_wordWrap.empty()\n            && (m_itemRect.right != 0 && m_itemRect.bottom != 0\n                && m_itemRect.left != m_itemRect.right\n                && m_itemRect.top != m_itemRect.bottom))\n        {\n            m_wordWrap = WordWrap(text, font, m_itemRect, &m_wordWrapLines);\n        }\n\n        if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n            m_topLine = static_cast<int>(m_wordWrapLines.size()) - 1;\n        m_topLine = std::max(m_topLine, 0);\n\n        XMFLOAT2 pos = { float(m_itemRect.left), float(m_itemRect.top) };\n\n        XMVECTOR color = XMLoadFloat4(&m_color);\n\n        font->DrawString(mgr->m_batch.get(), &m_wordWrap.c_str()[m_wordWrapLines[size_t(m_topLine)]], pos, color);\n    }\n\n    if (m_style & c_StyleScrollBar)\n    {\n        XMVECTOR scrollColor = XMLoadFloat4(&mgr->mConfig.colorNormal);\n\n        mgr->DrawRect(m_scrollRect, scrollColor);\n        mgr->DrawRect(m_trackRect, bgColor);\n        if (m_thumbRect.top != m_thumbRect.bottom)\n        {\n            mgr->DrawRect(m_thumbRect, scrollColor);\n        }\n    }\n}\n\nbool TextBox::Update(float elapsedTime, const DirectX::GamePad::State& pad)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n    UNREFERENCED_PARAMETER(pad);\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_padButtonState.leftStickUp == GamePad::ButtonStateTracker::PRESSED)\n    {\n        mgr->m_heldTimer = c_HoldTimeStart;\n        if (!m_wordWrapLines.empty())\n        {\n            if (m_topLine > 0)\n            {\n                --m_topLine;\n            }\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickUp == GamePad::ButtonStateTracker::HELD)\n    {\n        if (!m_wordWrapLines.empty() && mgr->m_heldTimer <= 0.f)\n        {\n            if (m_topLine > 0)\n            {\n                --m_topLine;\n            }\n            mgr->m_heldTimer = c_HoldTimeRepeat;\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickDown == GamePad::ButtonStateTracker::PRESSED)\n    {\n        mgr->m_heldTimer = c_HoldTimeStart;\n        if (!m_wordWrapLines.empty())\n        {\n            ++m_topLine;\n            if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n                m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStickDown == GamePad::ButtonStateTracker::HELD)\n    {\n        if (!m_wordWrapLines.empty() && mgr->m_heldTimer <= 0.f)\n        {\n            ++m_topLine;\n            if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n                m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n            mgr->m_heldTimer = c_HoldTimeRepeat;\n        }\n        return true;\n    }\n    else if (mgr->m_padButtonState.leftStick == GamePad::ButtonStateTracker::PRESSED)\n    {\n        if (!m_wordWrapLines.empty())\n        {\n            m_topLine = 0;\n        }\n    }\n\n    return false;\n}\n\nbool TextBox::Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate)\n{\n    UNREFERENCED_PARAMETER(elapsedTime);\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    // Handle mouse\n    if ((m_style & c_StyleScrollBar) && (m_thumbRect.top != m_thumbRect.bottom))\n    {\n        if (mstate.x >= m_scrollRect.left && mstate.x < m_scrollRect.right\n            && mstate.y >= m_scrollRect.top && mstate.y < m_scrollRect.bottom)\n        {\n            if (mgr->m_mouseButtonState.leftButton == Mouse::ButtonStateTracker::PRESSED)\n            {\n                if (mstate.y < m_thumbRect.top)\n                {\n                    if (!m_wordWrapLines.empty() && (m_lastHeight > 0))\n                    {\n                        int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n                        m_topLine -= maxl;\n                        if (m_topLine < 0)\n                            m_topLine = 0;\n                    }\n                }\n                else if (mstate.y > m_thumbRect.bottom)\n                {\n                    if (!m_wordWrapLines.empty() && (m_lastHeight > 0))\n                    {\n                        int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n                        m_topLine += maxl;\n                        if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n                            m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n                    }\n                }\n            }\n            return true;\n        }\n    }\n\n    if (mstate.scrollWheelValue > m_lastWheelValue)\n    {\n        if (!m_wordWrapLines.empty())\n        {\n            if (m_topLine > 0)\n            {\n                --m_topLine;\n            }\n        }\n        m_lastWheelValue = mstate.scrollWheelValue;\n        return true;\n    }\n\n    if (mstate.scrollWheelValue < m_lastWheelValue)\n    {\n        if (!m_wordWrapLines.empty())\n        {\n            ++m_topLine;\n            if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n                m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n        }\n        m_lastWheelValue = mstate.scrollWheelValue;\n        return true;\n    }\n\n    // Handle keyboard\n\n    if (kbstate.IsKeyDown(Keyboard::W) || kbstate.IsKeyDown(Keyboard::Up))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::W) || mgr->m_keyboardState.IsKeyPressed(Keyboard::Up))\n        {\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n\n        if (!m_wordWrapLines.empty() && mgr->m_heldTimer <= 0.f)\n        {\n            if (m_topLine > 0)\n            {\n                --m_topLine;\n            }\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::S) || kbstate.IsKeyDown(Keyboard::Down))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::S) || mgr->m_keyboardState.IsKeyPressed(Keyboard::Down))\n        {\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n\n        if (!m_wordWrapLines.empty() && mgr->m_heldTimer <= 0.f)\n        {\n            ++m_topLine;\n            if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n                m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::Home))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Home))\n        {\n            m_topLine = 0;\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::End))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::End))\n        {\n            if (!m_wordWrapLines.empty())\n            {\n                m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n            }\n        }\n\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::PageUp))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::PageUp))\n        {\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n\n        if (!m_wordWrapLines.empty() && (m_lastHeight > 0) && mgr->m_heldTimer <= 0.f)\n        {\n            int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n            m_topLine -= maxl;\n            if (m_topLine < 0)\n                m_topLine = 0;\n\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n        return true;\n    }\n    else if (kbstate.IsKeyDown(Keyboard::PageDown))\n    {\n        if (mgr->m_keyboardState.IsKeyPressed(Keyboard::PageDown))\n        {\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n\n        if (!m_wordWrapLines.empty() && (m_lastHeight > 0) && mgr->m_heldTimer <= 0.f)\n        {\n            int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n            m_topLine += maxl;\n            if (m_topLine >= static_cast<int>(m_wordWrapLines.size()))\n                m_topLine = static_cast<int>(m_wordWrapLines.size() - 1);\n\n            mgr->m_heldTimer = c_KeypressRepeatDelay;\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\nvoid TextBox::ComputeLayout(const RECT& parent)\n{\n    m_wordWrap.clear();\n    m_wordWrapLines.clear();\n    IControl::ComputeLayout(parent);\n}\n\nvoid TextBox::ComputeLayout(const RECT& bounds, float dx, float dy)\n{\n    m_wordWrap.clear();\n    m_wordWrapLines.clear();\n    IControl::ComputeLayout(bounds, dx, dy);\n}\n\nvoid TextBox::SetText(const wchar_t* text)\n{\n    m_text = text;\n    m_wordWrapLines.clear();\n    m_wordWrap.clear();\n    m_topLine = 0;\n}\n\nvoid TextBox::UpdateRects()\n{\n    m_trackRect.top = m_scrollRect.top + 1;\n    m_trackRect.left = m_scrollRect.left + 1;\n    m_trackRect.right = m_scrollRect.right - 1;\n    m_trackRect.bottom = m_scrollRect.bottom - 1;\n\n    m_thumbRect.left = m_trackRect.left;\n    m_thumbRect.right = m_trackRect.right;\n\n    if (m_wordWrapLines.empty() || !m_lastHeight)\n    {\n        m_thumbRect.bottom = m_thumbRect.top;\n        return;\n    }\n\n    int maxl = static_cast<int>(float(m_itemRect.bottom - m_itemRect.top - c_MarginSize * 2) / float(m_lastHeight));\n\n    UpdateScrollBar(m_thumbRect, m_trackRect, m_topLine, 0, static_cast<int>(m_wordWrapLines.size()), maxl);\n}\n\n\n//=====================================================================================\n// Popup\n//=====================================================================================\n\nPopup::Popup(const RECT& rect, unsigned int styleFlags) :\n    IPanel(rect),\n    m_select(false),\n    m_cancel(false),\n    m_suppressCancel((styleFlags & c_styleSuppressCancel) == c_styleSuppressCancel),\n    m_emphasis((styleFlags & c_stylePopupEmphasis) == c_stylePopupEmphasis),\n    m_custom((styleFlags & c_styleCustomPanel) == c_styleCustomPanel),\n    m_focusControl(nullptr)\n{\n}\n\nPopup::~Popup()\n{\n    for (IControl* it : m_controls)\n    {\n        delete it;\n    }\n    m_controls.clear();\n\n    m_focusControl = nullptr;\n}\n\nvoid Popup::Show()\n{\n    if (m_visible)\n        return;\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    OnWindowSize(mgr->m_fullscreen);\n\n    m_focusControl = InitFocus(m_controls);\n    if (m_focusControl)\n    {\n        m_focusControl->OnFocus(true);\n    }\n    else if (!m_custom)\n    {\n        throw std::exception(\"No usable controls\");\n    }\n\n    // Make visible\n    m_visible = true;\n\n    // Clear any pending action\n    m_select = false;\n    m_cancel = false;\n\n    // For now, no focus stack. Just grab focus for a popup\n    mgr->m_focusPanel = this;\n}\n\nvoid Popup::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    auto batch = mgr->m_batch.get();\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    mgr->m_commandList->RSSetScissorRects(1, &mgr->m_fullscreen);\n    batch->Begin(mgr->m_commandList);\n#else\n    batch->Begin(SpriteSortMode_Deferred, mgr->m_blendState.Get());\n#endif\n\n    if (m_emphasis)\n    {\n        // fade out all other elements to emphasize popup\n        XMFLOAT4 color = mgr->mConfig.colorBackground;\n        color.w *= 0.5f;\n        mgr->DrawRect(mgr->m_fullscreen, XMLoadFloat4(&color));\n    }\n\n    XMVECTOR bgColor = XMLoadFloat4(&mgr->mConfig.colorBackground);\n    mgr->DrawRect(m_screenRect, bgColor);\n\n    batch->End();\n\n    mgr->RenderControls(m_controls);\n\n    // Restore scissors to full screen\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    mgr->m_commandList->RSSetScissorRects(1, &mgr->m_fullscreen);\n#else\n    mgr->m_context->RSSetScissorRects(1, &mgr->m_fullscreen);\n#endif\n}\n\nbool Popup::Update(float elapsedTime, const GamePad::State& pad)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    bool result = false;\n\n    if (!m_focusControl)\n    {\n        m_focusControl = InitFocus(m_controls);\n        if (m_focusControl)\n            m_focusControl->OnFocus(true);\n    }\n\n    if (m_focusControl)\n    {\n        result = m_focusControl->Update(elapsedTime, pad);\n    }\n\n    if (!result)\n    {\n        if (pad.IsDPadDownPressed())\n        {\n            if (mgr->m_padButtonState.dpadDown == GamePad::ButtonStateTracker::PRESSED)\n            {\n                m_focusControl = NextFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (pad.IsDPadUpPressed())\n        {\n            if (mgr->m_padButtonState.dpadUp == GamePad::ButtonStateTracker::PRESSED)\n            {\n                m_focusControl = PrevFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (pad.IsBPressed())\n        {\n            if (mgr->m_padButtonState.b == GamePad::ButtonStateTracker::PRESSED)\n            {\n                Cancel();\n            }\n        }\n        else if (pad.IsAPressed())\n        {\n            m_select = true;\n        }\n        else if (m_select && !pad.IsAPressed())\n        {\n            ControlSelected(m_focusControl, this);\n            m_select = false;\n        }\n    }\n\n    return true;\n}\n\nbool Popup::Update(float elapsedTime, const Mouse::State& mstate, const Keyboard::State& kbstate)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    bool result = false;\n\n    if (!m_focusControl)\n    {\n        m_focusControl = InitFocus(m_controls);\n        if (m_focusControl)\n            m_focusControl->OnFocus(true);\n    }\n\n    if (m_focusControl)\n    {\n        result = m_focusControl->Update(elapsedTime, mstate, kbstate);\n    }\n\n    if (!result)\n    {\n        // Handle mouse\n        if (mstate.positionMode == Mouse::MODE_ABSOLUTE)\n        {\n            if ((m_screenRect.left < mstate.x) && (mstate.x < m_screenRect.right) && (m_screenRect.top < mstate.y) && (mstate.y < m_screenRect.bottom))\n            {\n                if (mgr->m_mouseLastX != mstate.x || mgr->m_mouseLastY != mstate.y)\n                {\n                    m_focusControl = MouseFocus(mstate.x, mstate.y, m_focusControl, m_controls);\n                }\n            }\n\n            if (mgr->m_mouseButtonState.leftButton == Mouse::ButtonStateTracker::PRESSED)\n            {\n                if (m_focusControl && m_focusControl->Contains(mstate.x, mstate.y))\n                {\n                    m_select = true;\n                }\n            }\n            else if (m_select && !mstate.leftButton)\n            {\n                ControlSelected(m_focusControl, this);\n                m_select = false;\n            }\n        }\n\n        // Handle keyboard\n        if (kbstate.IsKeyDown(Keyboard::Down))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Down))\n            {\n                m_focusControl = NextFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (kbstate.IsKeyDown(Keyboard::Up))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Up))\n            {\n                m_focusControl = PrevFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (kbstate.IsKeyDown(Keyboard::Space))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Space))\n            {\n                ControlSelected(m_focusControl, this);\n            }\n        }\n        else if (kbstate.IsKeyDown(Keyboard::Enter))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Enter))\n            {\n                ControlSelected(m_focusControl, this);\n            }\n        }\n        else if (kbstate.Escape)\n        {\n            m_cancel = true;\n        }\n        else if (m_cancel && !kbstate.Escape)\n        {\n            Cancel();\n            m_cancel = false;\n        }\n        else if (m_focusControl)\n        {\n            auto ctrl = HotKeyFocus(m_focusControl, m_controls, mgr->m_keyboardState);\n            if (ctrl)\n            {\n                m_focusControl = ctrl;\n                ControlSelected(ctrl, this);\n            }\n        }\n    }\n\n    return true;\n}\n\nvoid Popup::Close()\n{\n    if (!m_visible)\n        return;\n\n    unsigned ctrlId = 0;\n    if (m_focusControl)\n    {\n        ctrlId = m_focusControl->GetId();\n    }\n\n    if (m_callBack)\n        m_callBack(this, ctrlId);\n\n    if (m_focusControl)\n    {\n        m_focusControl->OnFocus(false);\n        m_focusControl = nullptr;\n    }\n\n    m_visible = false;\n\n    // For now, no focus stack. \n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_focusPanel == this)\n    {\n        mgr->m_focusPanel = nullptr;\n    }\n}\n\nvoid Popup::Cancel()\n{\n    if (m_suppressCancel)\n        return;\n\n    if (m_callBack)\n        m_callBack(this, unsigned(-1));\n\n    if (m_focusControl)\n    {\n        m_focusControl->OnFocus(false);\n        m_focusControl = nullptr;\n    }\n\n    m_visible = false;\n\n    // For now, no focus stack. \n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_focusPanel == this)\n    {\n        mgr->m_focusPanel = nullptr;\n    }\n}\n\nvoid Popup::Add(_In_ IControl* ctrl)\n{\n    if (ctrl)\n    {\n        m_controls.push_back(ctrl);\n        ctrl->SetParent(this);\n    }\n}\n\nIControl* Popup::Find(unsigned id)\n{\n    for (auto it : m_controls)\n    {\n        if (it->GetId() == id)\n            return it;\n    }\n\n    return nullptr;\n}\n\nvoid Popup::SetFocus(_In_ IControl* ctrl)\n{\n    m_focusControl = ::SetFocusCtrl(m_focusControl, ctrl);\n}\n\nvoid Popup::OnWindowSize(const RECT& layout)\n{\n    // Popups should center automatically\n    long dx = (m_layoutRect.right - m_layoutRect.left);\n    long dy = (m_layoutRect.bottom - m_layoutRect.top);\n\n    m_screenRect.left = layout.left + (layout.right - layout.left) / 2 - dx / 2;\n    m_screenRect.top = layout.top + (layout.bottom - layout.top) / 2 - dy / 2;\n\n    m_screenRect.right = m_screenRect.left + dx;\n    m_screenRect.bottom = m_screenRect.top + dy;\n\n    for (IControl* it : m_controls)\n    {\n        it->ComputeLayout(m_screenRect);\n    }\n}\n\n\n\n//=====================================================================================\n// HUD\n//=====================================================================================\n\nHUD::HUD(const RECT& rect) :\n    IPanel(rect)\n{\n}\n\n\nHUD::~HUD()\n{\n    for (IControl* it : m_controls)\n    {\n        delete it;\n    }\n    m_controls.clear();\n}\n\nvoid HUD::Show()\n{\n    if (m_visible)\n        return;\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_hudPanel)\n    {\n        mgr->m_hudPanel->Close();\n    }\n\n    OnWindowSize(mgr->m_fullscreen);\n\n    mgr->m_hudPanel = this;\n\n    m_visible = true;\n}\n\nvoid HUD::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    mgr->RenderControls(m_controls);\n}\n\nvoid HUD::Close()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_hudPanel == this)\n    {\n        mgr->m_hudPanel = nullptr;\n    }\n\n    m_visible = false;\n}\n\nvoid HUD::Add(_In_ IControl* ctrl)\n{\n    if (ctrl)\n    {\n        m_controls.push_back(ctrl);\n        ctrl->SetParent(this);\n    }\n}\n\nIControl* HUD::Find(unsigned id)\n{\n    for (auto it : m_controls)\n    {\n        if (it->GetId() == id)\n            return it;\n    }\n\n    return nullptr;\n}\n\nvoid HUD::OnWindowSize(const RECT& layout)\n{\n    float dx = float(layout.right - layout.left) / float(m_screenRect.right - m_screenRect.left);\n    float dy = float(layout.bottom - layout.top) / float(m_screenRect.bottom - m_screenRect.top);\n\n    for (IControl* it : m_controls)\n    {\n        it->ComputeLayout(layout, dx, dy);\n    }\n}\n\n\n//=====================================================================================\n// Overlay\n//=====================================================================================\n\nOverlay::Overlay(const RECT& rect, unsigned int styleFlags) :\n    IPanel(rect),\n    m_select(false),\n    m_cancel(false),\n    m_suppressCancel((styleFlags & c_styleSuppressCancel) == c_styleSuppressCancel),\n    m_custom((styleFlags & c_styleCustomPanel) == c_styleCustomPanel),\n    m_focusControl(nullptr)\n{\n}\n\n\nOverlay::~Overlay()\n{\n    for (IControl* it : m_controls)\n    {\n        delete it;\n    }\n    m_controls.clear();\n\n    m_focusControl = nullptr;\n}\n\nvoid Overlay::Show()\n{\n    if (m_visible)\n        return;\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_overlayPanel)\n    {\n        mgr->m_overlayPanel->Close();\n    }\n\n    OnWindowSize(mgr->m_fullscreen);\n\n    m_focusControl = InitFocus(m_controls);\n    if (m_focusControl)\n    {\n        m_focusControl->OnFocus(true);\n    }\n    else if (!m_custom)\n    {\n        throw std::exception(\"No usable controls\");\n    }\n\n    // Make visible\n    m_visible = true;\n\n    // Clear any pending action\n    m_select = false;\n    m_cancel = false;\n\n    mgr->m_overlayPanel = this;\n}\n\nvoid Overlay::Render()\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    mgr->RenderControls(m_controls);\n}\n\nbool Overlay::Update(float elapsedTime, const GamePad::State& pad)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    bool result = false;\n\n    if (!m_focusControl)\n    {\n        m_focusControl = InitFocus(m_controls);\n        if (m_focusControl)\n            m_focusControl->OnFocus(true);\n    }\n\n    if (m_focusControl)\n    {\n        result = m_focusControl->Update(elapsedTime, pad);\n    }\n\n    if (!result)\n    {\n        if (pad.IsDPadDownPressed())\n        {\n            if (mgr->m_padButtonState.dpadDown == GamePad::ButtonStateTracker::PRESSED)\n            {\n                m_focusControl = NextFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (pad.IsDPadUpPressed())\n        {\n            if (mgr->m_padButtonState.dpadUp == GamePad::ButtonStateTracker::PRESSED)\n            {\n                m_focusControl = PrevFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (pad.IsBPressed())\n        {\n            if (mgr->m_padButtonState.b == GamePad::ButtonStateTracker::PRESSED)\n            {\n                Cancel();\n           }\n        }\n        else if (pad.IsAPressed())\n        {\n            m_select = true;\n        }\n        else if (m_select && !pad.IsAPressed())\n        {\n            ControlSelected(m_focusControl, this);\n            m_select = false;\n        }\n    }\n\n    return result;\n}\n\nbool Overlay::Update(float elapsedTime, const Mouse::State& mstate, const Keyboard::State& kbstate)\n{\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    bool result = false;\n\n    if (!m_focusControl)\n    {\n        m_focusControl = InitFocus(m_controls);\n        if (m_focusControl)\n            m_focusControl->OnFocus(true);\n    }\n\n    if (m_focusControl)\n    {\n        result = m_focusControl->Update(elapsedTime, mstate, kbstate);\n    }\n\n    if (!result)\n    {\n        // Handle mouse\n        if (mstate.positionMode == Mouse::MODE_ABSOLUTE)\n        {\n            if ((m_screenRect.left < mstate.x) && (mstate.x < m_screenRect.right) && (m_screenRect.top < mstate.y) && (mstate.y < m_screenRect.bottom))\n            {\n                if (mgr->m_mouseLastX != mstate.x || mgr->m_mouseLastY != mstate.y)\n                {\n                    m_focusControl = MouseFocus(mstate.x, mstate.y, m_focusControl, m_controls);\n                }\n            }\n\n            if (mgr->m_mouseButtonState.leftButton == Mouse::ButtonStateTracker::PRESSED)\n            {\n                if (m_focusControl && m_focusControl->Contains(mstate.x, mstate.y))\n                {\n                    m_select = true;\n                }\n            }\n            else if (m_select && !mstate.leftButton)\n            {\n                ControlSelected(m_focusControl, this);\n                m_select = false;\n            }\n        }\n\n        // Handle keyboard\n        if (kbstate.IsKeyDown(Keyboard::Down))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Down))\n            {\n                m_focusControl = NextFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (kbstate.IsKeyDown(Keyboard::Up))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Up))\n            {\n                m_focusControl = PrevFocus(m_focusControl, m_controls);\n            }\n        }\n        else if (kbstate.IsKeyDown(Keyboard::Space))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Space))\n            {\n                ControlSelected(m_focusControl, this);\n            }\n        }\n        else if (kbstate.IsKeyDown(Keyboard::Enter))\n        {\n            if (mgr->m_keyboardState.IsKeyPressed(Keyboard::Enter))\n            {\n                ControlSelected(m_focusControl, this);\n            }\n        }\n        else if (kbstate.Escape)\n        {\n            m_cancel = true;\n        }\n        else if (m_cancel && !kbstate.Escape)\n        {\n            Cancel();\n            m_cancel = false;\n        }\n        else if (m_focusControl)\n        {\n            auto ctrl = HotKeyFocus(m_focusControl, m_controls, mgr->m_keyboardState);\n            if (ctrl)\n            {\n                m_focusControl = ctrl;\n                ControlSelected(ctrl, this);\n            }\n        }\n    }\n\n    return true;\n}\n\nvoid Overlay::Close()\n{\n    if (!m_visible)\n        return;\n\n    unsigned ctrlId = 0;\n    if (m_focusControl)\n    {\n        ctrlId = m_focusControl->GetId();\n    }\n\n    if (m_callBack)\n        m_callBack(this, ctrlId);\n\n    if (m_focusControl)\n    {\n        m_focusControl->OnFocus(false);\n        m_focusControl = nullptr;\n    }\n\n    m_visible = false;\n\n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_overlayPanel == this)\n    {\n        mgr->m_overlayPanel = nullptr;\n    }\n}\n\nvoid Overlay::Cancel()\n{\n    if (m_suppressCancel)\n        return;\n\n    if (m_callBack)\n        m_callBack(this, unsigned(-1));\n\n    if (m_focusControl)\n    {\n        m_focusControl->OnFocus(false);\n        m_focusControl = nullptr;\n    }\n\n    m_visible = false;\n\n    // For now, no focus stack. \n    auto mgr = UIManager::Impl::s_uiManager;\n    if (!mgr)\n    {\n        throw std::exception(\"UIManager\");\n    }\n\n    if (mgr->m_overlayPanel == this)\n    {\n        mgr->m_overlayPanel = nullptr;\n    }\n}\n\nvoid Overlay::Add(_In_ IControl* ctrl)\n{\n    if (ctrl)\n    {\n        m_controls.push_back(ctrl);\n        ctrl->SetParent(this);\n    }\n}\n\nIControl* Overlay::Find(unsigned id)\n{\n    for (auto it : m_controls)\n    {\n        if (it->GetId() == id)\n            return it;\n    }\n\n    return nullptr;\n}\n\nvoid Overlay::SetFocus(_In_ IControl* ctrl)\n{\n    m_focusControl = ::SetFocusCtrl(m_focusControl, ctrl);\n}\n\nvoid Overlay::OnWindowSize(const RECT& layout)\n{\n    float dx = float(layout.right - layout.left) / float(m_screenRect.right - m_screenRect.left);\n    float dy = float(layout.bottom - layout.top) / float(m_screenRect.bottom - m_screenRect.top);\n\n    for (IControl* it : m_controls)\n    {\n        it->ComputeLayout(layout, dx, dy);\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/SampleGUI.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: SampleGUI.h\n//\n// A simple set of UI widgets for use in ATG samples\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"GamePad.h\"\n#include \"Keyboard.h\"\n#include \"Mouse.h\"\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n#include \"DescriptorHeap.h\"\n#include \"ResourceUploadBatch.h\"\n#endif\n\n#include <wchar.h>\n\n#include <algorithm>\n#include <functional>\n#include <memory>\n#include <string>\n#include <vector>\n\n#ifndef _CPPRTTI \n#error ATG Sample GUI requires RTTI\n#endif\n\nnamespace ATG\n{\n    class IPanel;\n\n    //----------------------------------------------------------------------------------\n    // A control is an individual UI element\n    class IControl\n    {\n    public:\n        virtual ~IControl() {}\n\n        // Methods\n        virtual void Render() = 0;\n\n        virtual bool Contains(long x, long y) const\n        {\n            return (m_screenRect.left <= x) && (x < m_screenRect.right) && (m_screenRect.top <= y) && (y < m_screenRect.bottom);\n        }\n\n        virtual void ComputeLayout(const RECT& parent);\n        virtual void ComputeLayout(const RECT& bounds, float dx, float dy);\n\n        virtual bool CanFocus() const { return false;  }\n        virtual bool DefaultFocus() const { return false; }\n        virtual void OnFocus(bool in)\n        { \n            m_focus = in;\n            if (in && m_focusCb)\n            {\n                m_focusCb(nullptr, this);\n            }\n        }\n\n        virtual bool OnSelected(IPanel*) { return false; }\n\n        virtual bool Update(float /*elapsedTime*/, const DirectX::GamePad::State&) { return false; }\n        virtual bool Update(float /*elapsedTime*/, const DirectX::Mouse::State&, const DirectX::Keyboard::State&) { return false; }\n\n        // Properties\n        using callback_t = std::function<void(_In_ IPanel*, _In_ IControl*)>;\n\n        void SetCallback(_In_opt_ callback_t callback)\n        {\n            m_callBack = callback;\n        }\n\n        void SetFocusCb(_In_opt_ callback_t callback)\n        {\n            m_focusCb = callback;\n        }\n\n        unsigned GetHotKey() const { return m_hotKey; }\n        void SetHotKey(unsigned hotkey) { m_hotKey = hotkey;  }\n\n        void SetId(unsigned id) { m_id = id; }\n        unsigned GetId() const { return m_id; }\n\n        void SetUser(void* user) { m_user = user; }\n        void* GetUser() const { return m_user; }\n\n        void SetParent(IPanel* panel) { m_parent = panel; }\n\n        void SetVisible(bool visible = true);\n        bool IsVisible() const { return m_visible; }\n\n        const RECT* GetRectangle() const { return &m_screenRect; }\n\n    protected:\n        IControl(const RECT& rect, unsigned id) :\n            m_visible(true),\n            m_focus(false),\n            m_layoutRect(rect),\n            m_screenRect(rect),\n            m_hotKey(0),\n            m_id(id),\n            m_user(nullptr),\n            m_parent(nullptr)\n        {\n        }\n\n        bool        m_visible;\n        bool        m_focus;\n        RECT        m_layoutRect;\n        RECT        m_screenRect;\n        callback_t  m_callBack;\n        callback_t  m_focusCb;\n        unsigned    m_hotKey;\n        unsigned    m_id;\n        void*       m_user;\n        IPanel*     m_parent;\n    };\n\n    // Static text label\n    class TextLabel : public IControl\n    {\n    public:\n        TextLabel(unsigned id, _In_z_ const wchar_t* text, const RECT& rect, unsigned style = 0);\n\n        // Properties\n        void XM_CALLCONV SetForegroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_fgColor, color); }\n        void XM_CALLCONV SetBackgroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_bgColor, color); }\n\n        static const unsigned c_StyleAlignLeft = 0;\n        static const unsigned c_StyleAlignCenter = 0x1;\n        static const unsigned c_StyleAlignRight = 0x2;\n        static const unsigned c_StyleAlignTop = 0x0;\n        static const unsigned c_StyleAlignMiddle = 0x4;\n        static const unsigned c_StyleAlignBottom = 0x8;\n        static const unsigned c_StyleTransparent = 0x10;\n        static const unsigned c_StyleWordWrap = 0x20;\n\n        static const unsigned c_StyleFontSmall = 0x10000;\n        static const unsigned c_StyleFontMid = 0;\n        static const unsigned c_StyleFontLarge = 0x20000;\n        static const unsigned c_StyleFontBold = 0x40000;\n        static const unsigned c_StyleFontItalic = 0x80000;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetText(const wchar_t* text);\n        const wchar_t* GetText() const { return m_text.c_str(); }\n\n        // IControl\n        void Render() override;\n        void ComputeLayout(const RECT& parent) override;\n        void ComputeLayout(const RECT& bounds, float dx, float dy) override;\n        bool Contains(long, long) const override { return false; }\n\n    private:\n        unsigned            m_style;\n        DirectX::XMFLOAT4   m_fgColor;\n        DirectX::XMFLOAT4   m_bgColor;\n        std::wstring        m_text;\n        std::wstring        m_wordWrap;\n    };\n    \n    // Static image\n    class Image : public IControl\n    {\n    public:\n        Image(unsigned id, unsigned imageId, const RECT& rect);\n\n        void SetImageId(unsigned imageId) { m_imageId = imageId; }\n        unsigned GetImageId() const { return m_imageId; }\n\n        // IControl\n        void Render() override;\n        bool Contains(long, long) const override { return false; }\n\n    private:\n        unsigned m_imageId;\n    };\n\n    // Static text label that supports the controller font\n    class Legend : public IControl\n    {\n    public:\n        Legend(unsigned id, _In_z_ const wchar_t* text, const RECT& rect, unsigned style = 0);\n\n        // Properties\n        void XM_CALLCONV SetForegroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_fgColor, color); }\n        void XM_CALLCONV SetBackgroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_bgColor, color); }\n\n        static const unsigned c_StyleAlignLeft = 0;\n        static const unsigned c_StyleAlignCenter = 0x1;\n        static const unsigned c_StyleAlignRight = 0x2;\n        static const unsigned c_StyleAlignTop = 0x0;\n        static const unsigned c_StyleAlignMiddle = 0x4;\n        static const unsigned c_StyleAlignBottom = 0x8;\n        static const unsigned c_StyleTransparent = 0x10;\n\n        static const unsigned c_StyleFontSmall = 0x10000;\n        static const unsigned c_StyleFontMid = 0;\n        static const unsigned c_StyleFontLarge = 0x20000;\n        static const unsigned c_StyleFontBold = 0x40000;\n        static const unsigned c_StyleFontItalic = 0x80000;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetText(const wchar_t* text) { m_text = text; }\n        const wchar_t* GetText() const { return m_text.c_str(); }\n\n        // IControl\n        void Render() override;\n        bool Contains(long, long) const override { return false; }\n\n    private:\n        unsigned            m_style;\n        DirectX::XMFLOAT4   m_bgColor;\n        DirectX::XMFLOAT4   m_fgColor;\n        std::wstring        m_text;\n    };\n\n    // Pressable button\n    class Button : public IControl\n    {\n    public:\n        Button(unsigned id, _In_z_ const wchar_t* text, const RECT& rect);\n\n        // Properties\n        void ShowBorder(bool show = true) { m_showBorder = show; }\n        void NoFocusColor(bool noFocusColor = true) { m_noFocusColor = noFocusColor; }\n        void FocusOnText(bool focusOnText = true ) { m_focusOnText = focusOnText; }\n\n        void SetEnabled(bool enabled = true) { m_enabled = enabled; }\n        bool IsEnabled() const { return m_enabled; }\n\n        void XM_CALLCONV SetColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_color, color); }\n\n        static const unsigned c_StyleExit = 0x1;\n        static const unsigned c_StyleDefault = 0x2;\n        static const unsigned c_StyleTransparent = 0x4;\n\n        static const unsigned c_StyleFontSmall = 0x10000;\n        static const unsigned c_StyleFontMid = 0;\n        static const unsigned c_StyleFontLarge = 0x20000;\n        static const unsigned c_StyleFontBold = 0x40000;\n        static const unsigned c_StyleFontItalic = 0x80000;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetText(const wchar_t* text) { m_text = text; }\n        const wchar_t* GetText() const { return m_text.c_str(); }\n\n        // IControl\n        void Render() override;\n        bool CanFocus() const override { return m_enabled; }\n        bool DefaultFocus() const override { return (m_style & c_StyleDefault) != 0; }\n        bool OnSelected(IPanel* panel) override;\n\n    private:\n        bool               m_enabled;\n        bool               m_showBorder;\n        bool               m_noFocusColor;\n        bool               m_focusOnText;\n        unsigned           m_style;\n        std::wstring       m_text;\n        DirectX::XMFLOAT4  m_color;\n    };\n\n    // Pressable image\n    class ImageButton : public IControl\n    {\n    public:\n        ImageButton(unsigned id, unsigned imageId, const RECT& rect);\n\n        // Properties\n        void SetEnabled(bool enabled = true) { m_enabled = enabled; }\n        bool IsEnabled() const { return m_enabled; }\n\n        static const unsigned c_StyleExit = 0x1;\n        static const unsigned c_StyleDefault = 0x2;\n        static const unsigned c_StyleBackground = 0x4;\n        static const unsigned c_StyleTransparent = 0x8;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetImageId(unsigned imageId) { m_imageId = imageId; }\n        unsigned GetImageId() const { return m_imageId; }\n\n        // IControl\n        void Render() override;\n        bool CanFocus() const override { return m_enabled; }\n        bool DefaultFocus() const override { return (m_style & c_StyleDefault) != 0; }\n        bool OnSelected(IPanel* panel) override;\n\n    private:\n        bool        m_enabled;\n        unsigned    m_style;\n        unsigned    m_imageId;\n    };\n\n    // Two-state check box\n    class CheckBox : public IControl\n    {\n    public:\n        CheckBox(unsigned id, _In_z_ const wchar_t* text, const RECT& rect, bool checked = false);\n\n        // Properties\n        void SetEnabled(bool enabled = true) { m_enabled = enabled; }\n        bool IsEnabled() const { return m_enabled; }\n\n        void SetChecked(bool checked = true) { m_checked = checked; }\n        bool IsChecked() const { return m_checked; }\n\n        static const unsigned c_StyleTransparent = 0x1;\n\n        static const unsigned c_StyleFontSmall = 0x10000;\n        static const unsigned c_StyleFontMid = 0;\n        static const unsigned c_StyleFontLarge = 0x20000;\n        static const unsigned c_StyleFontBold = 0x40000;\n        static const unsigned c_StyleFontItalic = 0x80000;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetText(const wchar_t* text) { m_text = text; }\n        const wchar_t* GetText() const { return m_text.c_str(); }\n\n        // IControl\n        void Render() override;\n        bool CanFocus() const override { return m_enabled; }\n        bool OnSelected(IPanel* panel) override;\n\n    private:\n        bool            m_enabled;\n        bool            m_checked;\n        unsigned        m_style;\n        std::wstring    m_text;\n    };\n\n    // Slider\n    class Slider : public IControl\n    {\n    public:\n        Slider(unsigned id, const RECT& rect, int value = 50, int minValue = 0, int maxValue = 100);\n\n        // Properties\n        void SetEnabled(bool enabled = true) { m_enabled = enabled; if (!enabled) m_dragging = false; }\n        bool IsEnabled() const { return m_enabled; }\n\n        static const unsigned c_StyleTransparent = 0x1;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetValue(int value);\n        int GetValue() const { return m_value; }\n\n        void SetRange(int minValue, int maxValue);\n        void GetRange(int& minValue, int& maxValue) const { minValue = m_minValue; maxValue = m_maxValue; }\n\n        // IControl\n        void Render() override;\n        bool CanFocus() const override { return m_enabled; }\n        void OnFocus(bool in) override;\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad) override;\n        bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) override;\n\n    private:\n        bool        m_enabled;\n        bool        m_dragging;\n        unsigned    m_style;\n        int         m_value;\n        int         m_minValue;\n        int         m_maxValue;\n        RECT        m_thumbRect;\n    };\n\n    // Progress bar that goes from 0.0 to 1.0\n    class ProgressBar : public IControl\n    {\n    public:\n        ProgressBar(unsigned id, const RECT& rect, bool visible = false, float start = 0.f);\n        ~ProgressBar();\n\n        // Properties\n        void SetProgress(float progress) { m_progress = std::min( std::max(progress, 0.f), 1.f); }\n        float GetProgress() const { return m_progress; }\n        void ShowPercentage(bool show = true) { m_showPct = show; }\n\n        // IControl\n        void Render() override;\n\n    private:\n        float m_progress;\n        bool m_showPct;\n    };\n\n    // TextList\n    class TextList : public IControl\n    {\n    public:\n        TextList(unsigned id, const RECT& rect, unsigned style = 0, int itemHeight = 0);\n        ~TextList();\n\n        // Items\n        struct Item\n        {\n            std::wstring    text;\n            DirectX::XMFLOAT4 color;\n        };\n\n        void XM_CALLCONV AddItem(_In_z_ const wchar_t* text, DirectX::FXMVECTOR color = DirectX::Colors::White);\n        void XM_CALLCONV InsertItem(int index, _In_z_ const wchar_t* text, DirectX::FXMVECTOR color = DirectX::Colors::White);\n        void RemoveItem(int index);\n        void RemoveAllItems();\n\n        // IControl\n        void Render() override;\n        bool CanFocus() const override { return false; }\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad) override;\n        bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) override;\n    \n    private:\n        int                 m_itemHeight;\n        unsigned            m_style;\n        int                 m_topItem;\n        RECT                m_itemRect;\n        int                 m_lastHeight;\n        std::vector<Item>   m_items;\n    };\n\n\n    // List box\n    class ListBox : public IControl\n    {\n    public:\n        ListBox(unsigned id, const RECT& rect, unsigned style = 0, int itemHeight = 0);\n        ~ListBox();\n\n        // Items\n        struct Item\n        {\n            std::wstring    text;\n            void*           user;\n            bool            selected;\n\n            Item() : user(nullptr), selected(false) {}\n\n            // TODO - add optional image\n        };\n\n        void AddItem(_In_z_ const wchar_t* text, _In_opt_ void *user = nullptr);\n\n        void InsertItem(int index, _In_z_ const wchar_t* text, _In_opt_ void *user = nullptr);\n\n        void RemoveItem(int index);\n\n        void RemoveAllItems();\n\n        int GetSelectedItem() const;\n        std::vector<int> GetSelectedItems() const;\n\n        void ClearSelection();\n\n        void SelectItem(int index);\n\n        const Item* GetItem(int index) const { return &m_items[size_t(index)]; }\n        Item* GetItem(int index) { return &m_items[size_t(index)]; }\n\n        // Properties\n        void SetEnabled(bool enabled = true) { m_enabled = enabled; }\n        bool IsEnabled() const { return m_enabled; }\n\n        static const unsigned c_StyleMultiSelection = 0x1;\n        static const unsigned c_StyleTransparent = 0x2;\n        static const unsigned c_StyleScrollBar = 0x4;\n\n        static const unsigned c_StyleFontSmall = 0x10000;\n        static const unsigned c_StyleFontMid = 0;\n        static const unsigned c_StyleFontLarge = 0x20000;\n        static const unsigned c_StyleFontBold = 0x40000;\n        static const unsigned c_StyleFontItalic = 0x80000;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        // IControl\n        void Render() override;\n        bool CanFocus() const override { return m_enabled; }\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad) override;\n        bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) override;\n\n    private:\n        bool                m_enabled;\n        int                 m_itemHeight;\n        unsigned            m_style;\n        int                 m_topItem;\n        int                 m_focusItem;\n        RECT                m_itemRect;\n        RECT                m_scrollRect;\n        RECT                m_trackRect;\n        RECT                m_thumbRect;\n        int                 m_lastHeight;\n        std::vector<Item>   m_items;\n\n        void UpdateRects();\n    };\n\n    // Text box\n    class TextBox : public IControl\n    {\n    public:\n        TextBox(unsigned id, _In_z_ const wchar_t* text, const RECT& rect, unsigned style = 0);\n        ~TextBox();\n\n        // Properties\n        void XM_CALLCONV SetForegroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_color, color); }\n\n        static const unsigned c_StyleTransparent = 0x1;\n        static const unsigned c_StyleScrollBar = 0x2;\n        static const unsigned c_StyleNoBackground = 0x4;\n\n        static const unsigned c_StyleFontSmall = 0x10000;\n        static const unsigned c_StyleFontMid = 0;\n        static const unsigned c_StyleFontLarge = 0x20000;\n        static const unsigned c_StyleFontBold = 0x40000;\n        static const unsigned c_StyleFontItalic = 0x80000;\n\n        void SetStyle(unsigned style) { m_style = style; }\n        unsigned GetStyle() const { return m_style; }\n\n        void SetText(const wchar_t* text);\n        const wchar_t* GetText() const { return m_text.c_str(); }\n\n        // IControl\n        void Render() override;\n        void ComputeLayout(const RECT& parent) override;\n        void ComputeLayout(const RECT& bounds, float dx, float dy) override;\n        bool CanFocus() const override { return true; }\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad) override;\n        bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) override;\n\n    private:\n        unsigned            m_style;\n        int                 m_topLine;\n        RECT                m_itemRect;\n        RECT                m_scrollRect;\n        RECT                m_trackRect;\n        RECT                m_thumbRect;\n        int                 m_lastHeight;\n        DirectX::XMFLOAT4   m_color;\n        std::wstring        m_text;\n        std::wstring        m_wordWrap;\n        std::vector<size_t> m_wordWrapLines;\n        int                 m_lastWheelValue;\n\n        void UpdateRects();\n    };\n\n    //----------------------------------------------------------------------------------\n    // A panel is a container for UI controls\n    class IPanel\n    {\n    public:\n        virtual ~IPanel() {}\n\n        // Methods\n        virtual void Show() =  0;\n\n        virtual void Render() = 0;\n\n        virtual bool Update(float elapsedTime, const DirectX::GamePad::State& pad) = 0;\n        virtual bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) = 0;\n        virtual void Update(float /*elapsedTime*/) { };\n\n        virtual void Close() = 0;\n        virtual void Cancel() {}\n\n        virtual void Add(_In_ IControl* ctrl) = 0;\n        virtual IControl* Find(unsigned id) = 0;\n\n        virtual void SetFocus(_In_ IControl*) {}\n\n        virtual void OnWindowSize(const RECT& layout) = 0;\n\n        // Properties\n        using callback_t = std::function<void(_In_ IPanel*, unsigned)>;\n\n        void SetCallback(_In_opt_ callback_t callback)\n        {\n            m_callBack = callback;\n        }\n\n        void SetUser(void* user) { m_user = user; }\n        void* GetUser() const { return m_user; }\n\n        bool IsVisible() const { return m_visible; }\n\n    protected:\n        IPanel(const RECT& rect) :\n            m_visible(false),\n            m_layoutRect(rect),\n            m_screenRect(rect),\n            m_user(nullptr)\n        {\n        }\n\n        bool        m_visible;\n        RECT        m_layoutRect;\n        RECT        m_screenRect;\n        callback_t  m_callBack;\n        void*       m_user;\n    };\n\n    // Style flags for Popup and Overlay\n    const unsigned int c_styleCustomPanel = 1;       // Use this if you want a custom panel where you add controls programatically\n    const unsigned int c_stylePopupEmphasis = 2;     // Fades out other UI elements when rendering the popup in order to give it emphasis\n    const unsigned int c_styleSuppressCancel = 4;    // Suppress the default cancel behavior that would normally occur when 'B' is pressed\n\n    class Popup : public IPanel\n    {\n    public:\n        Popup(const RECT& rect, unsigned int styleFlags = 0);\n        ~Popup();\n\n        // IPanel\n        void Show() override;\n        void Render() override;\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad) override;\n        bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) override;\n        void Update(float) override {}\n        void Close() override;\n        void Cancel() override;\n        void Add(_In_ IControl* ctrl) override;\n        IControl* Find(unsigned id) override;\n        void SetFocus(_In_ IControl* ctrl) override;\n        void OnWindowSize(const RECT& layout) override;\n        \n    private:\n        bool                    m_select;\n        bool                    m_cancel;\n        bool                    m_suppressCancel;\n        bool                    m_emphasis;\n        const bool              m_custom;\n        IControl*               m_focusControl;\n        std::vector<IControl*>  m_controls;\n    };\n\n    class HUD : public IPanel\n    {\n    public:\n        HUD(const RECT& rect);\n        ~HUD();\n\n        // IPanel\n        void Show() override;\n        void Render() override;\n        bool Update(float, const DirectX::GamePad::State&) override { return false; }\n        bool Update(float, const DirectX::Mouse::State&, const DirectX::Keyboard::State&) override { return false; }\n        void Update(float) override {}\n        void Close() override;\n        void Add(_In_ IControl* ctrl) override;\n        IControl* Find(unsigned id) override;\n        void OnWindowSize(const RECT& layout) override;\n\n    private:\n        std::vector<IControl*>  m_controls;\n    };\n\n    class Overlay : public IPanel\n    {\n    public:\n        Overlay(const RECT& rect, unsigned int styleFlags = 0);\n        ~Overlay();\n\n        // IPanel\n        void Show() override;\n        void Render() override;\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad) override;\n        bool Update(float elapsedTime, const DirectX::Mouse::State& mstate, const DirectX::Keyboard::State& kbstate) override;\n        void Update(float) override {}\n        void Close() override;\n        void Cancel() override;\n        void Add(_In_ IControl* ctrl) override;\n        IControl* Find(unsigned id) override;\n        void SetFocus(_In_ IControl* ctrl) override;\n        void OnWindowSize(const RECT& layout) override;\n\n    private:\n        bool                    m_select;\n        bool                    m_cancel;\n        bool                    m_suppressCancel;\n        const bool              m_custom;\n        IControl*               m_focusControl;\n        std::vector<IControl*>  m_controls;\n    };\n\n    //----------------------------------------------------------------------------------\n    struct UIConfig\n    {\n        bool forceSRGB;\n        bool pmAlpha;\n\n        wchar_t largeFontName[MAX_PATH];\n        wchar_t largeItalicFontName[MAX_PATH];\n        wchar_t largeBoldFontName[MAX_PATH];\n\n        wchar_t midFontName[MAX_PATH];\n        wchar_t midItalicFontName[MAX_PATH];\n        wchar_t midBoldFontName[MAX_PATH];\n\n        wchar_t smallFontName[MAX_PATH];\n        wchar_t smallItalicFontName[MAX_PATH];\n        wchar_t smallBoldFontName[MAX_PATH];\n\n        wchar_t largeLegendName[MAX_PATH];\n        wchar_t smallLegendName[MAX_PATH];\n\n        DirectX::XMFLOAT4 colorNormal;\n        DirectX::XMFLOAT4 colorDisabled;\n        DirectX::XMFLOAT4 colorHighlight;\n        DirectX::XMFLOAT4 colorSelected;\n        DirectX::XMFLOAT4 colorFocus;\n        DirectX::XMFLOAT4 colorBackground;\n        DirectX::XMFLOAT4 colorTransparent;\n        DirectX::XMFLOAT4 colorProgress;\n\n        enum COLORS\n        {\n            RED,\n            GREEN,\n            BLUE,\n            ORANGE,\n            YELLOW,\n            DARK_GREY,\n            MID_GREY,\n            LIGHT_GREY,\n            OFF_WHITE,\n            WHITE,\n            BLACK,\n            MAX_COLORS,\n            \n        };\n\n        DirectX::XMFLOAT4 colorDictionary[MAX_COLORS];\n\n        UIConfig(bool linear = false, bool pmalpha = true) :\n            forceSRGB(linear),\n            pmAlpha(pmalpha)\n        {\n            using DirectX::XMFLOAT4;\n\n            wcscpy_s(largeFontName, L\"SegoeUI_36.spritefont\");\n            wcscpy_s(largeItalicFontName, L\"SegoeUI_36_Italic.spritefont\");\n            wcscpy_s(largeBoldFontName, L\"SegoeUI_36_Bold.spritefont\");\n\n            wcscpy_s(midFontName, L\"SegoeUI_22.spritefont\");\n            wcscpy_s(midItalicFontName, L\"SegoeUI_22_Italic.spritefont\");\n            wcscpy_s(midBoldFontName, L\"SegoeUI_22_Bold.spritefont\");\n\n            wcscpy_s(smallFontName, L\"SegoeUI_18.spritefont\");\n            wcscpy_s(smallItalicFontName, L\"SegoeUI_18_Italic.spritefont\");\n            wcscpy_s(smallBoldFontName, L\"SegoeUI_18_Bold.spritefont\");\n\n            wcscpy_s(largeLegendName, L\"XboxOneControllerLegend.spritefont\");\n            wcscpy_s(smallLegendName, L\"XboxOneControllerLegendSmall.spritefont\");\n\n            if (linear)\n            {\n                colorNormal = XMFLOAT4(0.361306787f, 0.361306787f, 0.361306787f, 1.f);              // OffWhite\n                colorDisabled = XMFLOAT4(0.194617808f, 0.194617808f, 0.194617808f, 1.f);            // LightGrey\n                colorHighlight = XMFLOAT4(0.545724571f, 0.026241219f, 0.001517635f, 1.f);           // Orange\n                colorSelected = XMFLOAT4(0.955973506f, 0.955973506f, 0.955973506f, 1.f);            // White\n                colorFocus = XMFLOAT4(0.005181516f, 0.201556236f, 0.005181516f, 1.f);               // Green\n                colorBackground = XMFLOAT4(0.f, 0.f, 0.f, 1.f);                                     // Black\n                colorTransparent = XMFLOAT4(0.033105f, 0.033105f, 0.033105f, 0.5f);\n                colorProgress = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.f);                                    // MidGrey\n\n                colorDictionary[RED] = XMFLOAT4(1.f, 0.f, 0.f, 1.f);\n                colorDictionary[GREEN] = XMFLOAT4(0.005181516f, 0.201556236f, 0.005181516f, 1.f);\n                colorDictionary[BLUE] = XMFLOAT4(0.001517635f, 0.114435382f, 0.610495627f, 1.f);\n                colorDictionary[ORANGE] = XMFLOAT4(0.545724571f, 0.026241219f, 0.001517635f, 1.f);\n                colorDictionary[YELLOW] = XMFLOAT4(1.f, 1.f, 0.f, 1.f);\n                colorDictionary[DARK_GREY] = XMFLOAT4(0.033104762f, 0.033104762f, 0.033104762f, 1.f);\n                colorDictionary[MID_GREY] = XMFLOAT4(0.113861285f, 0.113861285f, 0.113861285f, 1.f);\n                colorDictionary[LIGHT_GREY] = XMFLOAT4(0.194617808f, 0.194617808f, 0.194617808f, 1.f);\n                colorDictionary[OFF_WHITE] = XMFLOAT4(0.361306787f, 0.361306787f, 0.361306787f, 1.f);\n                colorDictionary[WHITE] = XMFLOAT4(0.955973506f, 0.955973506f, 0.955973506f, 1.f);\n                colorDictionary[BLACK] = XMFLOAT4(0.f, 0.f, 0.f, 1.f);\n            }\n            else\n            {\n                colorNormal = XMFLOAT4(0.635294139f, 0.635294139f, 0.635294139f, 1.f);              // OffWhite\n                colorDisabled = XMFLOAT4(0.478431374f, 0.478431374f, 0.478431374f, 1.f);            // LightGrey\n                colorHighlight = XMFLOAT4(0.764705896f, 0.176470593f, 0.019607844f, 1.f);           // Orange\n                colorSelected = XMFLOAT4(0.980392158f, 0.980392158f, 0.980392158f, 1.f);            // White\n                colorFocus = XMFLOAT4(0.062745102f, 0.486274511f, 0.062745102f, 1.f);               // Green\n                colorBackground = XMFLOAT4(0.f, 0.f, 0.f, 1.f);                                     // Black\n                colorTransparent = XMFLOAT4(0.2f, 0.2f, 0.2f, 0.5f);\n                colorProgress = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.f);                                    // MidGrey\n\n                colorDictionary[RED] = XMFLOAT4(1.f, 0.f, 0.f, 1.f);\n                colorDictionary[GREEN] = XMFLOAT4(0.062745102f, 0.486274511f, 0.062745102f, 1.f);\n                colorDictionary[BLUE] = XMFLOAT4(0.019607844f, 0.372549027f, 0.803921580f, 1.f);\n                colorDictionary[ORANGE] = XMFLOAT4(0.764705896f, 0.176470593f, 0.019607844f, 1.f);\n                colorDictionary[YELLOW] = XMFLOAT4(1.f, 1.f, 0.f, 1.f);\n                colorDictionary[DARK_GREY] = XMFLOAT4(0.200000003f, 0.200000003f, 0.200000003f, 1.f);\n                colorDictionary[MID_GREY] = XMFLOAT4(0.371653974f, 0.371653974f, 0.371653974f, 1.f);\n                colorDictionary[LIGHT_GREY] = XMFLOAT4(0.478431374f, 0.478431374f, 0.478431374f, 1.f);\n                colorDictionary[OFF_WHITE] = XMFLOAT4(0.635294139f, 0.635294139f, 0.635294139f, 1.f);\n                colorDictionary[WHITE] = XMFLOAT4(0.980392158f, 0.980392158f, 0.980392158f, 1.f);\n                colorDictionary[BLACK] = XMFLOAT4(0.f, 0.f, 0.f, 1.f);\n            }\n        }\n    };\n\n    class UIManager\n    {\n    public:\n        UIManager(const UIConfig& config);\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        UIManager(_In_ ID3D12Device *device,\n            const DirectX::RenderTargetState& renderTarget,\n            DirectX::ResourceUploadBatch& resourceUpload,\n            DirectX::DescriptorPile& pile,\n            const UIConfig& config);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        UIManager(_In_ ID3D11DeviceContext* context, const UIConfig& config);\n#else\n#   error Please #include <d3d11.h> or <d3d12.h>\n#endif\n\n        UIManager(UIManager&& moveFrom);\n        UIManager& operator= (UIManager&& moveFrom);\n\n        UIManager(UIManager const&) = delete;\n        UIManager& operator=(UIManager const&) = delete;\n\n        virtual ~UIManager();\n\n        // Load UI layout from disk\n        void LoadLayout(const wchar_t* layoutFile, const wchar_t* imageDir = nullptr, unsigned offset = 0);\n\n        // Add a panel (takes ownership)\n        void Add(unsigned id, _In_ IPanel* panel);\n\n        // Find a panel\n        IPanel* Find(unsigned id) const;\n\n        template<class T>\n        T* FindPanel(unsigned id) const\n        {\n            auto panel = dynamic_cast<T*>(Find(id));\n            if (panel)\n            {\n                return panel;\n            }\n\n            throw std::exception(\"Find (panel)\");\n        }\n\n        // Find a control\n        template<class T>\n        T* FindControl(unsigned panelId, unsigned ctrlId) const\n        {\n            auto panel = Find(panelId);\n            if (panel)\n            {\n                auto ctrl = dynamic_cast<T*>(panel->Find(ctrlId));\n                if (ctrl)\n                    return ctrl;\n            }\n\n            throw std::exception(\"Find (control)\");\n        }\n\n        // Close all visible panels\n        void CloseAll();\n\n        // Process user input for gamepad controls\n        bool Update(float elapsedTime, const DirectX::GamePad::State& pad);\n\n        // Process user input for keyboard & mouse controls\n        bool Update(float elapsedTime, DirectX::Mouse& mouse, DirectX::Keyboard& kb);\n\n        // Render the visible UI panels\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void Render(_In_ ID3D12GraphicsCommandList* commandList);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        void Render();\n#endif\n\n        // Set the screen viewport\n        void SetWindow(const RECT& layout);\n\n        // Set view rotation\n        void SetRotation(DXGI_MODE_ROTATION rotation);\n\n        // Texture registry for images (used by controls)\n        static const unsigned c_LayoutImageIdStart = 0x10000;\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void RegisterImage(unsigned id, D3D12_GPU_DESCRIPTOR_HANDLE tex, DirectX::XMUINT2 texSize);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        void RegisterImage(unsigned id, _In_ ID3D11ShaderResourceView* tex);\n#endif\n\n        void UnregisterImage(unsigned id);\n        void UnregisterAllImages();\n\n        // Direct3D device management\n        void ReleaseDevice();\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void RestoreDevice(_In_ ID3D12Device* device,\n            const DirectX::RenderTargetState& renderTarget,\n            DirectX::ResourceUploadBatch& resourceUpload,\n            DirectX::DescriptorPile& pile);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        void RestoreDevice(_In_ ID3D11DeviceContext* context);\n#endif\n\n        // Reset UI state (such as coming back from suspend)\n        void Reset();\n\n        // Release all objects\n        void Clear();\n\n        // Enumerators\n        void Enumerate(std::function<void(unsigned id, IPanel*)> enumCallback);\n                \n        // Common callback adapters\n        void CallbackYesNoCancel(_In_ IPanel* panel, std::function<void(bool, bool)> yesnocallback);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        friend class IControl;\n        friend class TextLabel;\n        friend class Image;\n        friend class Legend;\n        friend class Button;\n        friend class ImageButton;\n        friend class CheckBox;\n        friend class Slider;\n        friend class ProgressBar;\n        friend class ListBox;\n        friend class TextBox;\n        friend class TextList;\n        friend class Popup;\n        friend class HUD;\n        friend class Overlay;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/StringUtil.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// StringUtil.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"StringUtil.h\"\n#include <cctype>\n#include <string>\n\nnamespace\n{\n    constexpr DWORD MBConversionFlags = MB_ERR_INVALID_CHARS;\n    constexpr DWORD WCConversionFlags = WC_ERR_INVALID_CHARS;\n}\n\n// Get the wchar length of a utf8 string\nsize_t DX::GetWideLength(const char* utf8String, size_t utf8Length)\n{\n    const int newLen = ::MultiByteToWideChar(\n        CP_UTF8,\n        MBConversionFlags,\n        utf8String,\n        static_cast<int>(utf8Length),\n        nullptr,\n        0\n    );\n\n    return static_cast<size_t>(newLen);\n}\n\n// Get the utf8 length of a wchar string\nsize_t DX::GetUtf8Length(const wchar_t* wideString, size_t wideLength)\n{\n    const int newLen = ::WideCharToMultiByte(\n        CP_UTF8,\n        WCConversionFlags,\n        wideString,\n        static_cast<int>(wideLength),\n        nullptr,\n        0,\n        nullptr,\n        nullptr\n    );\n\n    return static_cast<size_t>(newLen);\n}\n\nstd::wstring DX::Utf8ToWide(const char* utf8String, size_t utf8Length)\n{\n    std::wstring dest;\n    const size_t wideLength = GetWideLength(utf8String, utf8Length);\n    dest.resize(wideLength);\n    ::MultiByteToWideChar(\n        CP_UTF8,\n        MBConversionFlags,\n        utf8String,\n        static_cast<int>(utf8Length),\n        &dest[0],\n        static_cast<int>(wideLength)\n    );\n\n    return dest;\n}\n\nstd::string DX::WideToUtf8(const wchar_t* wideString, size_t wideLength)\n{\n    std::string dest;\n    const size_t utf8Length = GetUtf8Length(wideString, wideLength);\n    dest.resize(utf8Length);\n\n    ::WideCharToMultiByte(\n        CP_UTF8,\n        WCConversionFlags,\n        wideString,\n        static_cast<int>(wideLength),\n        &dest[0],\n        static_cast<int>(utf8Length),\n        nullptr,\n        nullptr\n    );\n\n    return dest;\n}\n\nstd::wstring DX::Utf8ToWide(const std::string& utf8String)\n{\n    return Utf8ToWide(utf8String.c_str(), utf8String.length());\n}\n\nstd::string DX::WideToUtf8(const std::wstring& wideString)\n{\n    return WideToUtf8(wideString.c_str(), wideString.length());\n}\n\nstd::string DX::ToLower(const std::string & utf8String)\n{\n    std::string lower = utf8String;\n    ToLowerInPlace(lower);\n    return lower;\n}\n\nvoid DX::ToLowerInPlace(std::string& utf8String)\n{\n    std::transform(\n        utf8String.begin(),\n        utf8String.end(),\n        utf8String.begin(),\n        [](char c) { return static_cast<char>(std::tolower(static_cast<unsigned char>(c))); }\n    );\n}\n\nstd::wstring DX::ToLower(const std::wstring & wideString)\n{\n    std::wstring lower = wideString;\n    ToLowerInPlace(lower);\n    return lower;\n}\n\nvoid DX::ToLowerInPlace(std::wstring & wideString)\n{\n    std::transform(\n        wideString.begin(),\n        wideString.end(),\n        wideString.begin(),\n        [](wchar_t c) { return static_cast<wchar_t>(std::tolower(static_cast<wchar_t>(c))); }\n    );\n}\n\nstd::string DX::ToUpper(const std::string & utf8String)\n{\n    std::string lower = utf8String;\n    ToUpperInPlace(lower);\n    return lower;\n}\n\nvoid DX::ToUpperInPlace(std::string& utf8String)\n{\n    std::transform(\n        utf8String.begin(),\n        utf8String.end(),\n        utf8String.begin(),\n        [](char c) { return static_cast<char>(std::toupper(static_cast<unsigned char>(c))); }\n    );\n}\n\nstd::wstring DX::ToUpper(const std::wstring & wideString)\n{\n    std::wstring lower = wideString;\n    ToUpperInPlace(lower);\n    return lower;\n}\n\nvoid DX::ToUpperInPlace(std::wstring & wideString)\n{\n    std::transform(\n        wideString.begin(),\n        wideString.end(),\n        wideString.begin(),\n        [](wchar_t c) { return static_cast<wchar_t>(std::toupper(static_cast<wchar_t>(c))); }\n    );\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/StringUtil.h",
    "content": "//--------------------------------------------------------------------------------------\n// StringUtil.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//--------------------------------------------------------------------------------------\n\n#pragma once\n#include <string>\n\nnamespace DX\n{\n    size_t GetWideLength(const char* utf8String, size_t utf8Length);\n    size_t GetUtf8Length(const wchar_t* wideString, size_t wideLength);\n\n    std::wstring Utf8ToWide(const char* utf8String, size_t utf8Length);\n    std::string WideToUtf8(const wchar_t* wideString, size_t wideLength);\n\n    std::wstring Utf8ToWide(const std::string& utf8String);\n    std::string WideToUtf8(const std::wstring& wideString);\n\n    std::string ToLower(const std::string& utf8String);\n    void ToLowerInPlace(std::string& utf8String);\n    std::wstring ToLower(const std::wstring& wideString);\n    void ToLowerInPlace(std::wstring& wideString);\n\n    std::string ToUpper(const std::string& utf8String);\n    void ToUpperInPlace(std::string& utf8String);\n    std::wstring ToUpper(const std::wstring& wideString);\n    void ToUpperInPlace(std::wstring& wideString);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/TextConsole.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: TextConsole.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"TextConsole.h\"\n\n#include \"SimpleMath.h\"\n#include \"DDSTextureLoader.h\"\n#include \"WICTextureLoader.h\"\n\n#include <assert.h>\n\nusing Microsoft::WRL::ComPtr;\n\nusing namespace DirectX;\nusing namespace DX;\n\nconst XMVECTORF32 TextConsole::Line::s_defaultColor = Colors::Transparent;\n\nTextConsole::TextConsole() noexcept\n    : m_layout{},\n    m_foregroundColor(1.f, 1.f, 1.f, 1.f),\n    m_debugOutput(false),\n    m_columns(0),\n    m_rows(0)\n{\n    Clear();\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n_Use_decl_annotations_\nTextConsole::TextConsole(\n    ID3D12Device* device,\n    ResourceUploadBatch& upload,\n    const RenderTargetState& rtState,\n    const wchar_t* fontName,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor) noexcept(false)\n    : m_layout{},\n    m_foregroundColor(1.f, 1.f, 1.f, 1.f),\n    m_debugOutput(false),\n    m_columns(0),\n    m_rows(0)\n{\n    RestoreDevice(device, upload, rtState, fontName, cpuDescriptor, gpuDescriptor);\n\n    Clear();\n}\n#else\n_Use_decl_annotations_\nTextConsole::TextConsole(ID3D11DeviceContext* context, const wchar_t* fontName) noexcept(false)\n    : m_layout{},\n    m_foregroundColor(1.f, 1.f, 1.f, 1.f),\n    m_debugOutput(false),\n    m_columns(0),\n    m_rows(0)\n{\n    RestoreDevice(context, fontName);\n\n    Clear();\n}\n#endif\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nvoid TextConsole::Render(_In_ ID3D12GraphicsCommandList* commandList)\n#else\nvoid TextConsole::Render()\n#endif\n{\n    if (!m_lines)\n        return;\n\n    std::lock_guard<std::mutex> lock(m_mutex);\n\n    float lineSpacing = m_font->GetLineSpacing();\n\n    float x = float(m_layout.left);\n    float y = float(m_layout.top);\n\n    XMVECTOR foregroundColor = XMLoadFloat4(&m_foregroundColor);\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    m_batch->Begin(commandList);\n#else\n    m_batch->Begin();\n#endif\n\n    auto textLine = static_cast<unsigned int>(m_currentLine + 1) % m_rows;\n\n    for (unsigned int line = 0; line < m_rows; ++line)\n    {\n        XMFLOAT2 pos(x, y + lineSpacing * float(line));\n\n        if (*(m_lines[textLine].m_text))\n        {\n            XMVECTOR lineColor = XMLoadFloat4(&m_lines[textLine].m_textColor);\n            m_font->DrawString(m_batch.get(), m_lines[textLine].m_text, pos, XMColorEqual(lineColor, Line::s_defaultColor) ? foregroundColor : lineColor);\n        }\n\n        textLine = static_cast<unsigned int>(textLine + 1) % m_rows;\n    }\n\n    m_batch->End();\n}\n\nvoid TextConsole::Clear() noexcept\n{\n    std::lock_guard<std::mutex> lock(m_mutex);\n\n    if (m_buffer)\n    {\n        memset(m_buffer.get(), 0, sizeof(wchar_t) * (m_columns + 1) * m_rows);\n    }\n\n    if (m_lines)\n    {\n        for (unsigned int line = 0; line < m_rows; ++line)\n        {\n            m_lines[line].SetColor();\n        }\n    }\n\n    m_currentColumn = m_currentLine = 0;\n}\n\n_Use_decl_annotations_\nvoid TextConsole::Write(const wchar_t* str)\n{\n    Write(Line::s_defaultColor, str);\n}\n\n_Use_decl_annotations_\nvoid XM_CALLCONV TextConsole::Write(FXMVECTOR color, const wchar_t* str)\n{\n    std::lock_guard<std::mutex> lock(m_mutex);\n\n    ProcessString(color, str);\n\n#ifndef NDEBUG\n    if (m_debugOutput)\n    {\n        OutputDebugStringW(str);\n    }\n#endif\n}\n\n_Use_decl_annotations_\nvoid TextConsole::WriteLine(const wchar_t* str)\n{\n    WriteLine(Line::s_defaultColor, str);\n}\n\n_Use_decl_annotations_\nvoid XM_CALLCONV TextConsole::WriteLine(FXMVECTOR color, const wchar_t* str)\n{\n    std::lock_guard<std::mutex> lock(m_mutex);\n\n    ProcessString(color, str);\n    IncrementLine();\n\n#ifndef NDEBUG\n    if (m_debugOutput)\n    {\n        OutputDebugStringW(str);\n        OutputDebugStringW(L\"\\n\");\n    }\n#endif\n}\n\n_Use_decl_annotations_\nvoid TextConsole::Format(const wchar_t* strFormat, ...)\n{\n    va_list argList;\n    va_start(argList, strFormat);\n\n    FormatImpl(Line::s_defaultColor, strFormat, argList);\n\n    va_end(argList);\n}\n\n_Use_decl_annotations_\nvoid TextConsole::Format(CXMVECTOR color, const wchar_t* strFormat, ...)\n{\n    va_list argList;\n    va_start(argList, strFormat);\n\n    FormatImpl(color, strFormat, argList);\n\n    va_end(argList);\n}\n\n_Use_decl_annotations_\nvoid TextConsole::FormatImpl(CXMVECTOR color, const wchar_t* strFormat, va_list args)\n{\n    std::lock_guard<std::mutex> lock(m_mutex);\n\n    auto len = size_t(_vscwprintf(strFormat, args) + 1);\n\n    if (m_tempBuffer.size() < len)\n        m_tempBuffer.resize(len);\n\n    memset(m_tempBuffer.data(), 0, sizeof(wchar_t) * len);\n\n    vswprintf_s(m_tempBuffer.data(), m_tempBuffer.size(), strFormat, args);\n\n    ProcessString(color, m_tempBuffer.data());\n\n#ifndef NDEBUG\n    if (m_debugOutput)\n    {\n        OutputDebugStringW(m_tempBuffer.data());\n    }\n#endif\n}\n\nvoid TextConsole::SetWindow(const RECT& layout)\n{\n    std::lock_guard<std::mutex> lock(m_mutex);\n\n    m_layout = layout;\n\n    assert(m_font != nullptr);\n\n    float lineSpacing = m_font->GetLineSpacing();\n    unsigned int rows = std::max<unsigned int>(1, static_cast<unsigned int>(float(layout.bottom - layout.top) / lineSpacing));\n\n    RECT fontLayout = m_font->MeasureDrawBounds(L\"X\", XMFLOAT2(0, 0));\n    unsigned int columns = std::max<unsigned int>(1, static_cast<unsigned int>(float(layout.right - layout.left) / float(fontLayout.right - fontLayout.left)));\n\n    auto buffer = std::make_unique<wchar_t[]>((columns + 1) * rows);\n    memset(buffer.get(), 0, sizeof(wchar_t) * (columns + 1) * rows);\n\n    auto lines = std::make_unique<Line[]>(rows);\n    for (unsigned int line = 0; line < rows; ++line)\n    {\n        lines[line].m_text = buffer.get() + (columns + 1) * line;\n    }\n\n    if (m_lines)\n    {\n        unsigned int c = std::min<unsigned int>(columns, m_columns);\n        unsigned int r = std::min<unsigned int>(rows, m_rows);\n\n        for (unsigned int line = 0; line < r; ++line)\n        {\n            memcpy(lines[line].m_text, m_lines[line].m_text, c * sizeof(wchar_t));\n            lines[line].m_textColor = m_lines[line].m_textColor;\n        }\n    }\n\n    std::swap(columns, m_columns);\n    std::swap(rows, m_rows);\n    std::swap(buffer, m_buffer);\n    std::swap(lines, m_lines);\n\n    if ((m_currentColumn >= m_columns) || (m_currentLine >= m_rows))\n    {\n        IncrementLine();\n    }\n}\n\nvoid TextConsole::ReleaseDevice() noexcept\n{\n    m_batch.reset();\n    m_font.reset();\n#if defined(__d3d11_h__) || defined(__d3d11_x_h__)\n    m_context.Reset();\n#endif\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n_Use_decl_annotations_\nvoid TextConsole::RestoreDevice(\n    ID3D12Device* device,\n    ResourceUploadBatch& upload,\n    const RenderTargetState& rtState,\n    const wchar_t* fontName,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor)\n\n{\n    {\n        SpriteBatchPipelineStateDescription pd(rtState);\n        m_batch = std::make_unique<SpriteBatch>(device, upload, pd);\n    }\n\n    m_font = std::make_unique<SpriteFont>(device, upload, fontName, cpuDescriptor, gpuDescriptor);\n\n    m_font->SetDefaultCharacter(L' ');\n}\n\nvoid TextConsole::SetViewport(const D3D12_VIEWPORT& viewPort)\n{\n    if (m_batch)\n    {\n        m_batch->SetViewport(viewPort);\n    }\n}\n#else\nvoid TextConsole::RestoreDevice(ID3D11DeviceContext* context, const wchar_t* fontName)\n{\n    m_context = context;\n\n    m_batch = std::make_unique<SpriteBatch>(context);\n\n    ComPtr<ID3D11Device> device;\n    context->GetDevice(device.GetAddressOf());\n\n    m_font = std::make_unique<SpriteFont>(device.Get(), fontName);\n\n    m_font->SetDefaultCharacter(L' ');\n}\n\nvoid TextConsole::SetViewport(const D3D11_VIEWPORT& viewPort)\n{\n    if (m_batch)\n    {\n        m_batch->SetViewport(viewPort);\n    }\n}\n#endif\n\nvoid TextConsole::SetRotation(DXGI_MODE_ROTATION rotation)\n{\n    if (m_batch)\n    {\n        m_batch->SetRotation(rotation);\n    }\n}\n\n_Use_decl_annotations_\nvoid TextConsole::ProcessString(FXMVECTOR color, const wchar_t* str)\n{\n    if (!m_lines)\n        return;\n\n    m_lines[m_currentLine].SetColor(color);\n\n    float width = float(m_layout.right - m_layout.left);\n\n    for (const wchar_t* ch = str; *ch != 0; ++ch)\n    {\n        if (*ch == '\\n')\n        {\n            IncrementLine();\n            m_lines[m_currentLine].SetColor(color);\n            continue;\n        }\n\n        bool increment = false;\n\n        if (m_currentColumn >= m_columns)\n        {\n            increment = true;\n        }\n        else\n        {\n            m_lines[m_currentLine].m_text[m_currentColumn] = *ch;\n\n            auto fontSize = m_font->MeasureString(m_lines[m_currentLine].m_text);\n            if (XMVectorGetX(fontSize) > width)\n            {\n                m_lines[m_currentLine].m_text[m_currentColumn] = L'\\0';\n\n                increment = true;\n            }\n        }\n\n        if (increment)\n        {\n            IncrementLine();\n            m_lines[m_currentLine].m_text[0] = *ch;\n            m_lines[m_currentLine].SetColor(color);\n        }\n\n        ++m_currentColumn;\n    }\n}\n\nvoid TextConsole::IncrementLine()\n{\n    if (!m_lines)\n        return;\n\n    m_currentLine = (m_currentLine + 1) % m_rows;\n    m_currentColumn = 0;\n    memset(m_lines[m_currentLine].m_text, 0, sizeof(wchar_t) * (m_columns + 1));\n}\n\n//--------------------------------------------------------------------------------------\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nTextConsoleImage::TextConsoleImage() noexcept :\n    TextConsole(),\n    m_bgGpuDescriptor{},\n    m_bgSize{}\n{\n}\n#else\nTextConsoleImage::TextConsoleImage() noexcept :\n    TextConsole()\n{\n}\n#endif\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n_Use_decl_annotations_\nTextConsoleImage::TextConsoleImage(\n    ID3D12Device* device,\n    ResourceUploadBatch& upload,\n    const RenderTargetState& rtState,\n    const wchar_t* fontName,\n    const wchar_t* image,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorFont, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorFont,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorImage, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorImage) noexcept(false) :\n    TextConsole(),\n    m_bgGpuDescriptor{},\n    m_bgSize{}\n{\n    RestoreDevice(device, upload, rtState, fontName, image,\n        cpuDescriptorFont, gpuDescriptorFont,\n        cpuDescriptorImage, gpuDescriptorImage);\n}\n#else\n_Use_decl_annotations_\nTextConsoleImage::TextConsoleImage(ID3D11DeviceContext* context, const wchar_t* fontName, const wchar_t* image) noexcept(false) :\n    TextConsole()\n{\n    RestoreDevice(context, fontName, image);\n}\n#endif\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nvoid TextConsoleImage::Render(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    m_batch->Begin(commandList);\n\n    m_batch->Draw(m_bgGpuDescriptor, m_bgSize, m_fullscreen);\n\n    m_batch->End();\n\n    TextConsole::Render(commandList);\n}\n#else\nvoid TextConsoleImage::Render()\n{\n    m_batch->Begin();\n\n    m_batch->Draw(m_background.Get(), m_fullscreen);\n\n    m_batch->End();\n\n    TextConsole::Render();\n}\n#endif\n\nvoid TextConsoleImage::SetWindow(const RECT& fullscreen, bool useSafeRect)\n{\n    m_fullscreen = fullscreen;\n\n    if (useSafeRect)\n    {\n        TextConsole::SetWindow(\n            SimpleMath::Viewport::ComputeTitleSafeArea(UINT(fullscreen.right - fullscreen.left),\n                UINT(fullscreen.bottom - fullscreen.top)));\n    }\n    else\n    {\n        TextConsole::SetWindow(fullscreen);\n    }\n\n    auto width = UINT(std::max<LONG>(fullscreen.right - fullscreen.left, 1));\n    auto height = UINT(std::max<LONG>(fullscreen.bottom - fullscreen.top, 1));\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n    D3D12_VIEWPORT vp = { 0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height),\n        D3D12_DEFAULT_VIEWPORT_MIN_DEPTH, D3D12_DEFAULT_VIEWPORT_MAX_DEPTH };\n    m_batch->SetViewport(vp);\n#else\n    auto vp = CD3D11_VIEWPORT(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height));\n    m_batch->SetViewport(vp);\n#endif\n}\n\nvoid TextConsoleImage::ReleaseDevice() noexcept\n{\n    TextConsole::ReleaseDevice();\n\n    m_background.Reset();\n}\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n_Use_decl_annotations_\nvoid TextConsoleImage::RestoreDevice(\n    ID3D12Device* device,\n    DirectX::ResourceUploadBatch& upload,\n    const DirectX::RenderTargetState& rtState,\n    const wchar_t* fontName,\n    const wchar_t* image,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorFont, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorFont,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorImage, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorImage)\n{\n    TextConsole::RestoreDevice(device, upload, rtState, fontName, cpuDescriptorFont, gpuDescriptorFont);\n\n    wchar_t ext[_MAX_EXT];\n    _wsplitpath_s(image, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT);\n\n    if (_wcsicmp(ext, L\".dds\") == 0)\n    {\n        DX::ThrowIfFailed(CreateDDSTextureFromFile(device, upload, image, m_background.ReleaseAndGetAddressOf()));\n    }\n    else\n    {\n        DX::ThrowIfFailed(CreateWICTextureFromFile(device, upload, image, m_background.ReleaseAndGetAddressOf()));\n    }\n\n    auto desc = m_background->GetDesc();\n    if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)\n    {\n        throw std::exception(\"Only supports 2D images\");\n    }\n\n    D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};\n    SRVDesc.Format = desc.Format;\n    SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n    SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n    SRVDesc.Texture2D.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n\n    device->CreateShaderResourceView(m_background.Get(), &SRVDesc, cpuDescriptorImage);\n\n    m_bgGpuDescriptor = gpuDescriptorImage;\n    m_bgSize = XMUINT2(static_cast<uint32_t>(desc.Width), desc.Height);\n}\n#else\n_Use_decl_annotations_\nvoid TextConsoleImage::RestoreDevice(ID3D11DeviceContext* context, const wchar_t* fontName, const wchar_t* image)\n{\n    TextConsole::RestoreDevice(context, fontName);\n\n    ComPtr<ID3D11Device> device;\n    context->GetDevice(device.GetAddressOf());\n\n    wchar_t ext[_MAX_EXT];\n    _wsplitpath_s(image, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT);\n\n    if (_wcsicmp(ext, L\".dds\") == 0)\n    {\n        DX::ThrowIfFailed(CreateDDSTextureFromFile(device.Get(), image, nullptr, m_background.ReleaseAndGetAddressOf()));\n    }\n    else\n    {\n        DX::ThrowIfFailed(CreateWICTextureFromFile(device.Get(), image, nullptr, m_background.ReleaseAndGetAddressOf()));\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/TextConsole.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: TextConsole.h\n//\n// Renders a simple on screen console where you can output text information on a\n// Direct3D surface\n//\n// Note: This is best used with monospace rather than proportional fonts\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n#include \"RenderTargetState.h\"\n#include \"ResourceUploadBatch.h\"\n#endif\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\n#include <mutex>\n#include <vector>\n\n#include <wrl/client.h>\n\n\nnamespace DX\n{\n    class TextConsole\n    {\n    public:\n        TextConsole() noexcept;\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        TextConsole(\n            _In_ ID3D12Device* device,\n            DirectX::ResourceUploadBatch& upload,\n            const DirectX::RenderTargetState& rtState,\n            _In_z_ const wchar_t* fontName,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor) noexcept(false);\n#elif defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        TextConsole(_In_ ID3D11DeviceContext* context, _In_z_ const wchar_t* fontName) noexcept(false);\n#else\n#   error Please #include <d3d11.h> or <d3d12.h>\n#endif\n\n        TextConsole(TextConsole&&) = delete;\n        TextConsole& operator= (TextConsole&&) = delete;\n\n        TextConsole(TextConsole const&) = delete;\n        TextConsole& operator= (TextConsole const&) = delete;\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void Render(_In_ ID3D12GraphicsCommandList* commandList);\n#else\n        void Render();\n#endif\n\n        void Clear() noexcept;\n\n        void Write(_In_z_ const wchar_t* str);\n        void XM_CALLCONV Write(DirectX::FXMVECTOR color, _In_z_ const wchar_t* str);\n\n        void WriteLine(_In_z_ const wchar_t* str);\n        void XM_CALLCONV WriteLine(DirectX::FXMVECTOR color, _In_z_ const wchar_t* str);\n\n        void Format(_In_z_ _Printf_format_string_ const wchar_t* strFormat, ...);\n        void Format(DirectX::CXMVECTOR color, _In_z_ _Printf_format_string_ const wchar_t* strFormat, ...);\n\n        void SetWindow(const RECT& layout);\n\n        void XM_CALLCONV SetForegroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_foregroundColor, color); }\n\n        void SetDebugOutput(bool debug) { m_debugOutput = debug; }\n\n        void ReleaseDevice() noexcept;\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void RestoreDevice(\n            _In_ ID3D12Device* device,\n            DirectX::ResourceUploadBatch& upload,\n            const DirectX::RenderTargetState& rtState,\n            _In_z_ const wchar_t* fontName,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor);\n\n        void SetViewport(const D3D12_VIEWPORT& viewPort);\n#else\n        void RestoreDevice(ID3D11DeviceContext* context, const wchar_t* fontName);\n\n        void SetViewport(const D3D11_VIEWPORT& viewPort);\n#endif\n\n        void SetRotation(DXGI_MODE_ROTATION rotation);\n\n    protected:\n        void FormatImpl(DirectX::CXMVECTOR color, _In_z_ _Printf_format_string_ const wchar_t* strFormat, va_list args);\n        void XM_CALLCONV ProcessString(DirectX::FXMVECTOR color, _In_z_ const wchar_t* str);\n        void IncrementLine();\n\n        struct Line\n        {\n            wchar_t*\t\t\tm_text;\n            DirectX::XMFLOAT4\tm_textColor;\n\n            static const DirectX::XMVECTORF32 s_defaultColor;\n\n            Line() : m_text(nullptr), m_textColor(s_defaultColor) {}\n\n            void XM_CALLCONV SetColor(DirectX::FXMVECTOR color = s_defaultColor) { XMStoreFloat4(&m_textColor, color); }\n        };\n\n        RECT                                            m_layout;\n        DirectX::XMFLOAT4                               m_foregroundColor;\n\n        bool                                            m_debugOutput;\n\n        unsigned int                                    m_columns;\n        unsigned int                                    m_rows;\n        unsigned int                                    m_currentColumn;\n        unsigned int                                    m_currentLine;\n\n        std::unique_ptr<wchar_t[]>                      m_buffer;\n        std::unique_ptr<Line[]>                         m_lines;\n        std::vector<wchar_t>                            m_tempBuffer;\n\n        std::unique_ptr<DirectX::SpriteBatch>           m_batch;\n        std::unique_ptr<DirectX::SpriteFont>            m_font;\n#if defined(__d3d11_h__) || defined(__d3d11_x_h__)\n        Microsoft::WRL::ComPtr<ID3D11DeviceContext>     m_context;\n#endif\n\n        std::mutex                                      m_mutex;\n    };\n\n    class TextConsoleImage : public TextConsole\n    {\n    public:\n        TextConsoleImage() noexcept;\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        TextConsoleImage(\n            _In_ ID3D12Device* device,\n            DirectX::ResourceUploadBatch& upload,\n            const DirectX::RenderTargetState& rtState,\n            _In_z_ const wchar_t* fontName,\n            _In_z_ const wchar_t* image,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorFont, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorFont,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorImage, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorImage) noexcept(false);\n#else\n        TextConsoleImage(_In_ ID3D11DeviceContext* context, _In_z_ const wchar_t* fontName, _In_z_ const wchar_t* image) noexcept(false);\n#endif\n\n        TextConsoleImage(TextConsoleImage&&) = delete;\n        TextConsoleImage& operator= (TextConsoleImage&&) = delete;\n\n        TextConsoleImage(TextConsoleImage const&) = delete;\n        TextConsoleImage& operator= (TextConsoleImage const&) = delete;\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void Render(_In_ ID3D12GraphicsCommandList* commandList);\n#else\n        void Render();\n#endif\n\n        void SetWindow(const RECT& layout) = delete;\n        void SetWindow(const RECT& fullscreen, bool useSafeRect);\n\n        void ReleaseDevice() noexcept;\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        void RestoreDevice(\n            _In_ ID3D12Device* device,\n            DirectX::ResourceUploadBatch& upload,\n            const DirectX::RenderTargetState& rtState,\n            _In_z_ const wchar_t* fontName,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor) = delete;\n        void RestoreDevice(\n            _In_ ID3D12Device* device,\n            DirectX::ResourceUploadBatch& upload,\n            const DirectX::RenderTargetState& rtState,\n            _In_z_ const wchar_t* fontName,\n            _In_z_ const wchar_t* image,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorFont, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorFont,\n            D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorImage, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorImage);\n#else\n        void RestoreDevice(_In_ ID3D11DeviceContext* context, _In_z_ const wchar_t* fontName) = delete;\n        void RestoreDevice(_In_ ID3D11DeviceContext* context, _In_z_ const wchar_t* fontName, _In_z_ const wchar_t* image);\n#endif\n\n    private:\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n        D3D12_GPU_DESCRIPTOR_HANDLE                         m_bgGpuDescriptor;\n        DirectX::XMUINT2                                    m_bgSize;\n        Microsoft::WRL::ComPtr<ID3D12Resource>              m_background;\n#else\n        Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_background;\n#endif\n        RECT                                                m_fullscreen;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/d3dx12.h",
    "content": "//*********************************************************\n//\n// Copyright (c) Microsoft. All rights reserved.\n// This code is licensed under the MIT License (MIT).\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n\n#ifndef __D3DX12_H__\n#define __D3DX12_H__\n\n#include \"d3d12.h\"\n\n#if defined( __cplusplus )\n\nstruct CD3DX12_DEFAULT {};\nextern const DECLSPEC_SELECTANY CD3DX12_DEFAULT D3D12_DEFAULT;\n\n//------------------------------------------------------------------------------------------------\ninline bool operator==( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept\n{\n    return l.TopLeftX == r.TopLeftX && l.TopLeftY == r.TopLeftY && l.Width == r.Width &&\n        l.Height == r.Height && l.MinDepth == r.MinDepth && l.MaxDepth == r.MaxDepth;\n}\n\n//------------------------------------------------------------------------------------------------\ninline bool operator!=( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RECT : public D3D12_RECT\n{\n    CD3DX12_RECT() = default;\n    explicit CD3DX12_RECT( const D3D12_RECT& o ) noexcept :\n        D3D12_RECT( o )\n    {}\n    explicit CD3DX12_RECT(\n        LONG Left,\n        LONG Top,\n        LONG Right,\n        LONG Bottom ) noexcept\n    {\n        left = Left;\n        top = Top;\n        right = Right;\n        bottom = Bottom;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_VIEWPORT : public D3D12_VIEWPORT\n{\n    CD3DX12_VIEWPORT() = default;\n    explicit CD3DX12_VIEWPORT( const D3D12_VIEWPORT& o ) noexcept :\n        D3D12_VIEWPORT( o )\n    {}\n    explicit CD3DX12_VIEWPORT(\n        FLOAT topLeftX,\n        FLOAT topLeftY,\n        FLOAT width,\n        FLOAT height,\n        FLOAT minDepth = D3D12_MIN_DEPTH,\n        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept\n    {\n        TopLeftX = topLeftX;\n        TopLeftY = topLeftY;\n        Width = width;\n        Height = height;\n        MinDepth = minDepth;\n        MaxDepth = maxDepth;\n    }\n    explicit CD3DX12_VIEWPORT(\n        _In_ ID3D12Resource* pResource,\n        UINT mipSlice = 0,\n        FLOAT topLeftX = 0.0f,\n        FLOAT topLeftY = 0.0f,\n        FLOAT minDepth = D3D12_MIN_DEPTH,\n        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept\n    {\n        auto Desc = pResource->GetDesc();\n        const UINT64 SubresourceWidth = Desc.Width >> mipSlice;\n        const UINT64 SubresourceHeight = Desc.Height >> mipSlice;\n        switch (Desc.Dimension)\n        {\n        case D3D12_RESOURCE_DIMENSION_BUFFER:\n            TopLeftX = topLeftX;\n            TopLeftY = 0.0f;\n            Width = float(Desc.Width) - topLeftX;\n            Height = 1.0f;\n            break;\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            TopLeftX = topLeftX;\n            TopLeftY = 0.0f;\n            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;\n            Height = 1.0f;\n            break;\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            TopLeftX = topLeftX;\n            TopLeftY = topLeftY;\n            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;\n            Height = (SubresourceHeight ? float(SubresourceHeight) : 1.0f) - topLeftY;\n            break;\n        default: break;\n        }\n\n        MinDepth = minDepth;\n        MaxDepth = maxDepth;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_BOX : public D3D12_BOX\n{\n    CD3DX12_BOX() = default;\n    explicit CD3DX12_BOX( const D3D12_BOX& o ) noexcept :\n        D3D12_BOX( o )\n    {}\n    explicit CD3DX12_BOX(\n        LONG Left,\n        LONG Right ) noexcept\n    {\n        left = static_cast<UINT>(Left);\n        top = 0;\n        front = 0;\n        right = static_cast<UINT>(Right);\n        bottom = 1;\n        back = 1;\n    }\n    explicit CD3DX12_BOX(\n        LONG Left,\n        LONG Top,\n        LONG Right,\n        LONG Bottom ) noexcept\n    {\n        left = static_cast<UINT>(Left);\n        top = static_cast<UINT>(Top);\n        front = 0;\n        right = static_cast<UINT>(Right);\n        bottom = static_cast<UINT>(Bottom);\n        back = 1;\n    }\n    explicit CD3DX12_BOX(\n        LONG Left,\n        LONG Top,\n        LONG Front,\n        LONG Right,\n        LONG Bottom,\n        LONG Back ) noexcept\n    {\n        left = static_cast<UINT>(Left);\n        top = static_cast<UINT>(Top);\n        front = static_cast<UINT>(Front);\n        right = static_cast<UINT>(Right);\n        bottom = static_cast<UINT>(Bottom);\n        back = static_cast<UINT>(Back);\n    }\n};\ninline bool operator==( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept\n{\n    return l.left == r.left && l.top == r.top && l.front == r.front &&\n        l.right == r.right && l.bottom == r.bottom && l.back == r.back;\n}\ninline bool operator!=( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_DEPTH_STENCIL_DESC : public D3D12_DEPTH_STENCIL_DESC\n{\n    CD3DX12_DEPTH_STENCIL_DESC() = default;\n    explicit CD3DX12_DEPTH_STENCIL_DESC( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept :\n        D3D12_DEPTH_STENCIL_DESC( o )\n    {}\n    explicit CD3DX12_DEPTH_STENCIL_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        DepthEnable = TRUE;\n        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;\n        DepthFunc = D3D12_COMPARISON_FUNC_LESS;\n        StencilEnable = FALSE;\n        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;\n        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;\n        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =\n        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };\n        FrontFace = defaultStencilOp;\n        BackFace = defaultStencilOp;\n    }\n    explicit CD3DX12_DEPTH_STENCIL_DESC(\n        BOOL depthEnable,\n        D3D12_DEPTH_WRITE_MASK depthWriteMask,\n        D3D12_COMPARISON_FUNC depthFunc,\n        BOOL stencilEnable,\n        UINT8 stencilReadMask,\n        UINT8 stencilWriteMask,\n        D3D12_STENCIL_OP frontStencilFailOp,\n        D3D12_STENCIL_OP frontStencilDepthFailOp,\n        D3D12_STENCIL_OP frontStencilPassOp,\n        D3D12_COMPARISON_FUNC frontStencilFunc,\n        D3D12_STENCIL_OP backStencilFailOp,\n        D3D12_STENCIL_OP backStencilDepthFailOp,\n        D3D12_STENCIL_OP backStencilPassOp,\n        D3D12_COMPARISON_FUNC backStencilFunc ) noexcept\n    {\n        DepthEnable = depthEnable;\n        DepthWriteMask = depthWriteMask;\n        DepthFunc = depthFunc;\n        StencilEnable = stencilEnable;\n        StencilReadMask = stencilReadMask;\n        StencilWriteMask = stencilWriteMask;\n        FrontFace.StencilFailOp = frontStencilFailOp;\n        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;\n        FrontFace.StencilPassOp = frontStencilPassOp;\n        FrontFace.StencilFunc = frontStencilFunc;\n        BackFace.StencilFailOp = backStencilFailOp;\n        BackFace.StencilDepthFailOp = backStencilDepthFailOp;\n        BackFace.StencilPassOp = backStencilPassOp;\n        BackFace.StencilFunc = backStencilFunc;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\n// Requires the Windows 10 Creators Update SDK (15063)\n#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\nstruct CD3DX12_DEPTH_STENCIL_DESC1 : public D3D12_DEPTH_STENCIL_DESC1\n{\n    CD3DX12_DEPTH_STENCIL_DESC1() = default;\n    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC1& o ) noexcept :\n        D3D12_DEPTH_STENCIL_DESC1( o )\n    {}\n    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept\n    {\n        DepthEnable                  = o.DepthEnable;\n        DepthWriteMask               = o.DepthWriteMask;\n        DepthFunc                    = o.DepthFunc;\n        StencilEnable                = o.StencilEnable;\n        StencilReadMask              = o.StencilReadMask;\n        StencilWriteMask             = o.StencilWriteMask;\n        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;\n        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;\n        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;\n        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;\n        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;\n        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;\n        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;\n        BackFace.StencilFunc         = o.BackFace.StencilFunc;\n        DepthBoundsTestEnable        = FALSE;\n    }\n    explicit CD3DX12_DEPTH_STENCIL_DESC1( CD3DX12_DEFAULT ) noexcept\n    {\n        DepthEnable = TRUE;\n        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;\n        DepthFunc = D3D12_COMPARISON_FUNC_LESS;\n        StencilEnable = FALSE;\n        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;\n        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;\n        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =\n        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };\n        FrontFace = defaultStencilOp;\n        BackFace = defaultStencilOp;\n        DepthBoundsTestEnable = FALSE;\n    }\n    explicit CD3DX12_DEPTH_STENCIL_DESC1(\n        BOOL depthEnable,\n        D3D12_DEPTH_WRITE_MASK depthWriteMask,\n        D3D12_COMPARISON_FUNC depthFunc,\n        BOOL stencilEnable,\n        UINT8 stencilReadMask,\n        UINT8 stencilWriteMask,\n        D3D12_STENCIL_OP frontStencilFailOp,\n        D3D12_STENCIL_OP frontStencilDepthFailOp,\n        D3D12_STENCIL_OP frontStencilPassOp,\n        D3D12_COMPARISON_FUNC frontStencilFunc,\n        D3D12_STENCIL_OP backStencilFailOp,\n        D3D12_STENCIL_OP backStencilDepthFailOp,\n        D3D12_STENCIL_OP backStencilPassOp,\n        D3D12_COMPARISON_FUNC backStencilFunc,\n        BOOL depthBoundsTestEnable ) noexcept\n    {\n        DepthEnable = depthEnable;\n        DepthWriteMask = depthWriteMask;\n        DepthFunc = depthFunc;\n        StencilEnable = stencilEnable;\n        StencilReadMask = stencilReadMask;\n        StencilWriteMask = stencilWriteMask;\n        FrontFace.StencilFailOp = frontStencilFailOp;\n        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;\n        FrontFace.StencilPassOp = frontStencilPassOp;\n        FrontFace.StencilFunc = frontStencilFunc;\n        BackFace.StencilFailOp = backStencilFailOp;\n        BackFace.StencilDepthFailOp = backStencilDepthFailOp;\n        BackFace.StencilPassOp = backStencilPassOp;\n        BackFace.StencilFunc = backStencilFunc;\n        DepthBoundsTestEnable = depthBoundsTestEnable;\n    }\n    operator D3D12_DEPTH_STENCIL_DESC() const noexcept\n    {\n        D3D12_DEPTH_STENCIL_DESC D;\n        D.DepthEnable                  = DepthEnable;\n        D.DepthWriteMask               = DepthWriteMask;\n        D.DepthFunc                    = DepthFunc;\n        D.StencilEnable                = StencilEnable;\n        D.StencilReadMask              = StencilReadMask;\n        D.StencilWriteMask             = StencilWriteMask;\n        D.FrontFace.StencilFailOp      = FrontFace.StencilFailOp;\n        D.FrontFace.StencilDepthFailOp = FrontFace.StencilDepthFailOp;\n        D.FrontFace.StencilPassOp      = FrontFace.StencilPassOp;\n        D.FrontFace.StencilFunc        = FrontFace.StencilFunc;\n        D.BackFace.StencilFailOp       = BackFace.StencilFailOp;\n        D.BackFace.StencilDepthFailOp  = BackFace.StencilDepthFailOp;\n        D.BackFace.StencilPassOp       = BackFace.StencilPassOp;\n        D.BackFace.StencilFunc         = BackFace.StencilFunc;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_RS2\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_BLEND_DESC : public D3D12_BLEND_DESC\n{\n    CD3DX12_BLEND_DESC() = default;\n    explicit CD3DX12_BLEND_DESC( const D3D12_BLEND_DESC& o ) noexcept :\n        D3D12_BLEND_DESC( o )\n    {}\n    explicit CD3DX12_BLEND_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        AlphaToCoverageEnable = FALSE;\n        IndependentBlendEnable = FALSE;\n        const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =\n        {\n            FALSE,FALSE,\n            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,\n            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,\n            D3D12_LOGIC_OP_NOOP,\n            D3D12_COLOR_WRITE_ENABLE_ALL,\n        };\n        for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)\n            RenderTarget[ i ] = defaultRenderTargetBlendDesc;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RASTERIZER_DESC : public D3D12_RASTERIZER_DESC\n{\n    CD3DX12_RASTERIZER_DESC() = default;\n    explicit CD3DX12_RASTERIZER_DESC( const D3D12_RASTERIZER_DESC& o ) noexcept :\n        D3D12_RASTERIZER_DESC( o )\n    {}\n    explicit CD3DX12_RASTERIZER_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        FillMode = D3D12_FILL_MODE_SOLID;\n        CullMode = D3D12_CULL_MODE_BACK;\n        FrontCounterClockwise = FALSE;\n        DepthBias = D3D12_DEFAULT_DEPTH_BIAS;\n        DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;\n        SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;\n        DepthClipEnable = TRUE;\n        MultisampleEnable = FALSE;\n        AntialiasedLineEnable = FALSE;\n        ForcedSampleCount = 0;\n        ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;\n    }\n    explicit CD3DX12_RASTERIZER_DESC(\n        D3D12_FILL_MODE fillMode,\n        D3D12_CULL_MODE cullMode,\n        BOOL frontCounterClockwise,\n        INT depthBias,\n        FLOAT depthBiasClamp,\n        FLOAT slopeScaledDepthBias,\n        BOOL depthClipEnable,\n        BOOL multisampleEnable,\n        BOOL antialiasedLineEnable,\n        UINT forcedSampleCount,\n        D3D12_CONSERVATIVE_RASTERIZATION_MODE conservativeRaster) noexcept\n    {\n        FillMode = fillMode;\n        CullMode = cullMode;\n        FrontCounterClockwise = frontCounterClockwise;\n        DepthBias = depthBias;\n        DepthBiasClamp = depthBiasClamp;\n        SlopeScaledDepthBias = slopeScaledDepthBias;\n        DepthClipEnable = depthClipEnable;\n        MultisampleEnable = multisampleEnable;\n        AntialiasedLineEnable = antialiasedLineEnable;\n        ForcedSampleCount = forcedSampleCount;\n        ConservativeRaster = conservativeRaster;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RESOURCE_ALLOCATION_INFO : public D3D12_RESOURCE_ALLOCATION_INFO\n{\n    CD3DX12_RESOURCE_ALLOCATION_INFO() = default;\n    explicit CD3DX12_RESOURCE_ALLOCATION_INFO( const D3D12_RESOURCE_ALLOCATION_INFO& o ) noexcept :\n        D3D12_RESOURCE_ALLOCATION_INFO( o )\n    {}\n    CD3DX12_RESOURCE_ALLOCATION_INFO(\n        UINT64 size,\n        UINT64 alignment ) noexcept\n    {\n        SizeInBytes = size;\n        Alignment = alignment;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_HEAP_PROPERTIES : public D3D12_HEAP_PROPERTIES\n{\n    CD3DX12_HEAP_PROPERTIES() = default;\n    explicit CD3DX12_HEAP_PROPERTIES(const D3D12_HEAP_PROPERTIES &o) noexcept :\n        D3D12_HEAP_PROPERTIES(o)\n    {}\n    CD3DX12_HEAP_PROPERTIES(\n        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,\n        D3D12_MEMORY_POOL memoryPoolPreference,\n        UINT creationNodeMask = 1,\n        UINT nodeMask = 1 ) noexcept\n    {\n        Type = D3D12_HEAP_TYPE_CUSTOM;\n        CPUPageProperty = cpuPageProperty;\n        MemoryPoolPreference = memoryPoolPreference;\n        CreationNodeMask = creationNodeMask;\n        VisibleNodeMask = nodeMask;\n    }\n    explicit CD3DX12_HEAP_PROPERTIES(\n        D3D12_HEAP_TYPE type,\n        UINT creationNodeMask = 1,\n        UINT nodeMask = 1 ) noexcept\n    {\n        Type = type;\n        CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;\n        MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;\n        CreationNodeMask = creationNodeMask;\n        VisibleNodeMask = nodeMask;\n    }\n    bool IsCPUAccessible() const noexcept\n    {\n        return Type == D3D12_HEAP_TYPE_UPLOAD || Type == D3D12_HEAP_TYPE_READBACK || (Type == D3D12_HEAP_TYPE_CUSTOM &&\n            (CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE || CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK));\n    }\n};\ninline bool operator==( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept\n{\n    return l.Type == r.Type && l.CPUPageProperty == r.CPUPageProperty &&\n        l.MemoryPoolPreference == r.MemoryPoolPreference &&\n        l.CreationNodeMask == r.CreationNodeMask &&\n        l.VisibleNodeMask == r.VisibleNodeMask;\n}\ninline bool operator!=( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_HEAP_DESC : public D3D12_HEAP_DESC\n{\n    CD3DX12_HEAP_DESC() = default;\n    explicit CD3DX12_HEAP_DESC(const D3D12_HEAP_DESC &o) noexcept :\n        D3D12_HEAP_DESC(o)\n    {}\n    CD3DX12_HEAP_DESC(\n        UINT64 size,\n        D3D12_HEAP_PROPERTIES properties,\n        UINT64 alignment = 0,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = size;\n        Properties = properties;\n        Alignment = alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        UINT64 size,\n        D3D12_HEAP_TYPE type,\n        UINT64 alignment = 0,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = size;\n        Properties = CD3DX12_HEAP_PROPERTIES( type );\n        Alignment = alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        UINT64 size,\n        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,\n        D3D12_MEMORY_POOL memoryPoolPreference,\n        UINT64 alignment = 0,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = size;\n        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );\n        Alignment = alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_HEAP_PROPERTIES properties,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = resAllocInfo.SizeInBytes;\n        Properties = properties;\n        Alignment = resAllocInfo.Alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_HEAP_TYPE type,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = resAllocInfo.SizeInBytes;\n        Properties = CD3DX12_HEAP_PROPERTIES( type );\n        Alignment = resAllocInfo.Alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,\n        D3D12_MEMORY_POOL memoryPoolPreference,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = resAllocInfo.SizeInBytes;\n        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );\n        Alignment = resAllocInfo.Alignment;\n        Flags = flags;\n    }\n    bool IsCPUAccessible() const noexcept\n    { return static_cast< const CD3DX12_HEAP_PROPERTIES* >( &Properties )->IsCPUAccessible(); }\n};\ninline bool operator==( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept\n{\n    return l.SizeInBytes == r.SizeInBytes &&\n        l.Properties == r.Properties &&\n        l.Alignment == r.Alignment &&\n        l.Flags == r.Flags;\n}\ninline bool operator!=( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_CLEAR_VALUE : public D3D12_CLEAR_VALUE\n{\n    CD3DX12_CLEAR_VALUE() = default;\n    explicit CD3DX12_CLEAR_VALUE(const D3D12_CLEAR_VALUE &o) noexcept :\n        D3D12_CLEAR_VALUE(o)\n    {}\n    CD3DX12_CLEAR_VALUE(\n        DXGI_FORMAT format,\n        const FLOAT color[4] ) noexcept\n    {\n        Format = format;\n        memcpy( Color, color, sizeof( Color ) );\n    }\n    CD3DX12_CLEAR_VALUE(\n        DXGI_FORMAT format,\n        FLOAT depth,\n        UINT8 stencil ) noexcept\n    {\n        Format = format;\n        memset( &Color, 0, sizeof( Color ) );\n        /* Use memcpy to preserve NAN values */\n        memcpy( &DepthStencil.Depth, &depth, sizeof( depth ) );\n        DepthStencil.Stencil = stencil;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RANGE : public D3D12_RANGE\n{\n    CD3DX12_RANGE() = default;\n    explicit CD3DX12_RANGE(const D3D12_RANGE &o) noexcept :\n        D3D12_RANGE(o)\n    {}\n    CD3DX12_RANGE(\n        SIZE_T begin,\n        SIZE_T end ) noexcept\n    {\n        Begin = begin;\n        End = end;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\n#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\nstruct CD3DX12_RANGE_UINT64 : public D3D12_RANGE_UINT64\n{\n    CD3DX12_RANGE_UINT64() = default;\n    explicit CD3DX12_RANGE_UINT64(const D3D12_RANGE_UINT64 &o) noexcept :\n        D3D12_RANGE_UINT64(o)\n    {}\n    CD3DX12_RANGE_UINT64(\n        UINT64 begin,\n        UINT64 end ) noexcept\n    {\n        Begin = begin;\n        End = end;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SUBRESOURCE_RANGE_UINT64 : public D3D12_SUBRESOURCE_RANGE_UINT64\n{\n    CD3DX12_SUBRESOURCE_RANGE_UINT64() = default;\n    explicit CD3DX12_SUBRESOURCE_RANGE_UINT64(const D3D12_SUBRESOURCE_RANGE_UINT64 &o) noexcept :\n        D3D12_SUBRESOURCE_RANGE_UINT64(o)\n    {}\n    CD3DX12_SUBRESOURCE_RANGE_UINT64(\n        UINT subresource,\n        const D3D12_RANGE_UINT64& range ) noexcept\n    {\n        Subresource = subresource;\n        Range = range;\n    }\n    CD3DX12_SUBRESOURCE_RANGE_UINT64(\n        UINT subresource,\n        UINT64 begin,\n        UINT64 end ) noexcept\n    {\n        Subresource = subresource;\n        Range.Begin = begin;\n        Range.End = end;\n    }\n};\n#endif // NTDDI_WIN10_RS2\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SHADER_BYTECODE : public D3D12_SHADER_BYTECODE\n{\n    CD3DX12_SHADER_BYTECODE() = default;\n    explicit CD3DX12_SHADER_BYTECODE(const D3D12_SHADER_BYTECODE &o) noexcept :\n        D3D12_SHADER_BYTECODE(o)\n    {}\n    CD3DX12_SHADER_BYTECODE(\n        _In_ ID3DBlob* pShaderBlob ) noexcept\n    {\n        pShaderBytecode = pShaderBlob->GetBufferPointer();\n        BytecodeLength = pShaderBlob->GetBufferSize();\n    }\n    CD3DX12_SHADER_BYTECODE(\n        const void* _pShaderBytecode,\n        SIZE_T bytecodeLength ) noexcept\n    {\n        pShaderBytecode = _pShaderBytecode;\n        BytecodeLength = bytecodeLength;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TILED_RESOURCE_COORDINATE : public D3D12_TILED_RESOURCE_COORDINATE\n{\n    CD3DX12_TILED_RESOURCE_COORDINATE() = default;\n    explicit CD3DX12_TILED_RESOURCE_COORDINATE(const D3D12_TILED_RESOURCE_COORDINATE &o) noexcept :\n        D3D12_TILED_RESOURCE_COORDINATE(o)\n    {}\n    CD3DX12_TILED_RESOURCE_COORDINATE(\n        UINT x,\n        UINT y,\n        UINT z,\n        UINT subresource ) noexcept\n    {\n        X = x;\n        Y = y;\n        Z = z;\n        Subresource = subresource;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TILE_REGION_SIZE : public D3D12_TILE_REGION_SIZE\n{\n    CD3DX12_TILE_REGION_SIZE() = default;\n    explicit CD3DX12_TILE_REGION_SIZE(const D3D12_TILE_REGION_SIZE &o) noexcept :\n        D3D12_TILE_REGION_SIZE(o)\n    {}\n    CD3DX12_TILE_REGION_SIZE(\n        UINT numTiles,\n        BOOL useBox,\n        UINT width,\n        UINT16 height,\n        UINT16 depth ) noexcept\n    {\n        NumTiles = numTiles;\n        UseBox = useBox;\n        Width = width;\n        Height = height;\n        Depth = depth;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SUBRESOURCE_TILING : public D3D12_SUBRESOURCE_TILING\n{\n    CD3DX12_SUBRESOURCE_TILING() = default;\n    explicit CD3DX12_SUBRESOURCE_TILING(const D3D12_SUBRESOURCE_TILING &o) noexcept :\n        D3D12_SUBRESOURCE_TILING(o)\n    {}\n    CD3DX12_SUBRESOURCE_TILING(\n        UINT widthInTiles,\n        UINT16 heightInTiles,\n        UINT16 depthInTiles,\n        UINT startTileIndexInOverallResource ) noexcept\n    {\n        WidthInTiles = widthInTiles;\n        HeightInTiles = heightInTiles;\n        DepthInTiles = depthInTiles;\n        StartTileIndexInOverallResource = startTileIndexInOverallResource;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TILE_SHAPE : public D3D12_TILE_SHAPE\n{\n    CD3DX12_TILE_SHAPE() = default;\n    explicit CD3DX12_TILE_SHAPE(const D3D12_TILE_SHAPE &o) noexcept :\n        D3D12_TILE_SHAPE(o)\n    {}\n    CD3DX12_TILE_SHAPE(\n        UINT widthInTexels,\n        UINT heightInTexels,\n        UINT depthInTexels ) noexcept\n    {\n        WidthInTexels = widthInTexels;\n        HeightInTexels = heightInTexels;\n        DepthInTexels = depthInTexels;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RESOURCE_BARRIER : public D3D12_RESOURCE_BARRIER\n{\n    CD3DX12_RESOURCE_BARRIER() = default;\n    explicit CD3DX12_RESOURCE_BARRIER(const D3D12_RESOURCE_BARRIER &o) noexcept :\n        D3D12_RESOURCE_BARRIER(o)\n    {}\n    static inline CD3DX12_RESOURCE_BARRIER Transition(\n        _In_ ID3D12Resource* pResource,\n        D3D12_RESOURCE_STATES stateBefore,\n        D3D12_RESOURCE_STATES stateAfter,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,\n        D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE) noexcept\n    {\n        CD3DX12_RESOURCE_BARRIER result = {};\n        D3D12_RESOURCE_BARRIER &barrier = result;\n        result.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        result.Flags = flags;\n        barrier.Transition.pResource = pResource;\n        barrier.Transition.StateBefore = stateBefore;\n        barrier.Transition.StateAfter = stateAfter;\n        barrier.Transition.Subresource = subresource;\n        return result;\n    }\n    static inline CD3DX12_RESOURCE_BARRIER Aliasing(\n        _In_ ID3D12Resource* pResourceBefore,\n        _In_ ID3D12Resource* pResourceAfter) noexcept\n    {\n        CD3DX12_RESOURCE_BARRIER result = {};\n        D3D12_RESOURCE_BARRIER &barrier = result;\n        result.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;\n        barrier.Aliasing.pResourceBefore = pResourceBefore;\n        barrier.Aliasing.pResourceAfter = pResourceAfter;\n        return result;\n    }\n    static inline CD3DX12_RESOURCE_BARRIER UAV(\n        _In_ ID3D12Resource* pResource) noexcept\n    {\n        CD3DX12_RESOURCE_BARRIER result = {};\n        D3D12_RESOURCE_BARRIER &barrier = result;\n        result.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;\n        barrier.UAV.pResource = pResource;\n        return result;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_PACKED_MIP_INFO : public D3D12_PACKED_MIP_INFO\n{\n    CD3DX12_PACKED_MIP_INFO() = default;\n    explicit CD3DX12_PACKED_MIP_INFO(const D3D12_PACKED_MIP_INFO &o) noexcept :\n        D3D12_PACKED_MIP_INFO(o)\n    {}\n    CD3DX12_PACKED_MIP_INFO(\n        UINT8 numStandardMips,\n        UINT8 numPackedMips,\n        UINT numTilesForPackedMips,\n        UINT startTileIndexInOverallResource ) noexcept\n    {\n        NumStandardMips = numStandardMips;\n        NumPackedMips = numPackedMips;\n        NumTilesForPackedMips = numTilesForPackedMips;\n        StartTileIndexInOverallResource = startTileIndexInOverallResource;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SUBRESOURCE_FOOTPRINT : public D3D12_SUBRESOURCE_FOOTPRINT\n{\n    CD3DX12_SUBRESOURCE_FOOTPRINT() = default;\n    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(const D3D12_SUBRESOURCE_FOOTPRINT &o) noexcept :\n        D3D12_SUBRESOURCE_FOOTPRINT(o)\n    {}\n    CD3DX12_SUBRESOURCE_FOOTPRINT(\n        DXGI_FORMAT format,\n        UINT width,\n        UINT height,\n        UINT depth,\n        UINT rowPitch ) noexcept\n    {\n        Format = format;\n        Width = width;\n        Height = height;\n        Depth = depth;\n        RowPitch = rowPitch;\n    }\n    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(\n        const D3D12_RESOURCE_DESC& resDesc,\n        UINT rowPitch ) noexcept\n    {\n        Format = resDesc.Format;\n        Width = UINT( resDesc.Width );\n        Height = resDesc.Height;\n        Depth = (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? resDesc.DepthOrArraySize : 1);\n        RowPitch = rowPitch;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TEXTURE_COPY_LOCATION : public D3D12_TEXTURE_COPY_LOCATION\n{\n    CD3DX12_TEXTURE_COPY_LOCATION() = default;\n    explicit CD3DX12_TEXTURE_COPY_LOCATION(const D3D12_TEXTURE_COPY_LOCATION &o) noexcept :\n        D3D12_TEXTURE_COPY_LOCATION(o)\n    {}\n    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes) noexcept\n    {\n        pResource = pRes;\n        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n        PlacedFootprint = {};\n    }\n    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, D3D12_PLACED_SUBRESOURCE_FOOTPRINT const& Footprint) noexcept\n    {\n        pResource = pRes;\n        Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n        PlacedFootprint = Footprint;\n    }\n    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, UINT Sub) noexcept\n    {\n        pResource = pRes;\n        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n        PlacedFootprint = {};\n        SubresourceIndex = Sub;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_DESCRIPTOR_RANGE : public D3D12_DESCRIPTOR_RANGE\n{\n    CD3DX12_DESCRIPTOR_RANGE() = default;\n    explicit CD3DX12_DESCRIPTOR_RANGE(const D3D12_DESCRIPTOR_RANGE &o) noexcept :\n        D3D12_DESCRIPTOR_RANGE(o)\n    {}\n    CD3DX12_DESCRIPTOR_RANGE(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);\n    }\n\n    inline void Init(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_DESCRIPTOR_RANGE &range,\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        range.RangeType = rangeType;\n        range.NumDescriptors = numDescriptors;\n        range.BaseShaderRegister = baseShaderRegister;\n        range.RegisterSpace = registerSpace;\n        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR_TABLE : public D3D12_ROOT_DESCRIPTOR_TABLE\n{\n    CD3DX12_ROOT_DESCRIPTOR_TABLE() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE(const D3D12_ROOT_DESCRIPTOR_TABLE &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR_TABLE(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR_TABLE(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept\n    {\n        Init(numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    inline void Init(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept\n    {\n        Init(*this, numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE &rootDescriptorTable,\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept\n    {\n        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;\n        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_CONSTANTS : public D3D12_ROOT_CONSTANTS\n{\n    CD3DX12_ROOT_CONSTANTS() = default;\n    explicit CD3DX12_ROOT_CONSTANTS(const D3D12_ROOT_CONSTANTS &o) noexcept :\n        D3D12_ROOT_CONSTANTS(o)\n    {}\n    CD3DX12_ROOT_CONSTANTS(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(num32BitValues, shaderRegister, registerSpace);\n    }\n\n    inline void Init(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(*this, num32BitValues, shaderRegister, registerSpace);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_CONSTANTS &rootConstants,\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        rootConstants.Num32BitValues = num32BitValues;\n        rootConstants.ShaderRegister = shaderRegister;\n        rootConstants.RegisterSpace = registerSpace;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR : public D3D12_ROOT_DESCRIPTOR\n{\n    CD3DX12_ROOT_DESCRIPTOR() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR(const D3D12_ROOT_DESCRIPTOR &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR(\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(shaderRegister, registerSpace);\n    }\n\n    inline void Init(\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(*this, shaderRegister, registerSpace);\n    }\n\n    static inline void Init(_Out_ D3D12_ROOT_DESCRIPTOR &table, UINT shaderRegister, UINT registerSpace = 0) noexcept\n    {\n        table.ShaderRegister = shaderRegister;\n        table.RegisterSpace = registerSpace;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_PARAMETER : public D3D12_ROOT_PARAMETER\n{\n    CD3DX12_ROOT_PARAMETER() = default;\n    explicit CD3DX12_ROOT_PARAMETER(const D3D12_ROOT_PARAMETER &o) noexcept :\n        D3D12_ROOT_PARAMETER(o)\n    {}\n\n    static inline void InitAsDescriptorTable(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR_TABLE::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);\n    }\n\n    static inline void InitAsConstants(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsConstantBufferView(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsShaderResourceView(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsUnorderedAccessView(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);\n    }\n\n    inline void InitAsDescriptorTable(\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);\n    }\n\n    inline void InitAsConstants(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsConstantBufferView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstantBufferView(*this, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsShaderResourceView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsShaderResourceView(*this, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsUnorderedAccessView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, visibility);\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_STATIC_SAMPLER_DESC : public D3D12_STATIC_SAMPLER_DESC\n{\n    CD3DX12_STATIC_SAMPLER_DESC() = default;\n    explicit CD3DX12_STATIC_SAMPLER_DESC(const D3D12_STATIC_SAMPLER_DESC &o) noexcept :\n        D3D12_STATIC_SAMPLER_DESC(o)\n    {}\n    CD3DX12_STATIC_SAMPLER_DESC(\n         UINT shaderRegister,\n         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,\n         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         FLOAT mipLODBias = 0,\n         UINT maxAnisotropy = 16,\n         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,\n         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n         FLOAT minLOD = 0.f,\n         FLOAT maxLOD = D3D12_FLOAT32_MAX,\n         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,\n         UINT registerSpace = 0) noexcept\n    {\n        Init(\n            shaderRegister,\n            filter,\n            addressU,\n            addressV,\n            addressW,\n            mipLODBias,\n            maxAnisotropy,\n            comparisonFunc,\n            borderColor,\n            minLOD,\n            maxLOD,\n            shaderVisibility,\n            registerSpace);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_STATIC_SAMPLER_DESC &samplerDesc,\n         UINT shaderRegister,\n         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,\n         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         FLOAT mipLODBias = 0,\n         UINT maxAnisotropy = 16,\n         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,\n         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n         FLOAT minLOD = 0.f,\n         FLOAT maxLOD = D3D12_FLOAT32_MAX,\n         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,\n         UINT registerSpace = 0) noexcept\n    {\n        samplerDesc.ShaderRegister = shaderRegister;\n        samplerDesc.Filter = filter;\n        samplerDesc.AddressU = addressU;\n        samplerDesc.AddressV = addressV;\n        samplerDesc.AddressW = addressW;\n        samplerDesc.MipLODBias = mipLODBias;\n        samplerDesc.MaxAnisotropy = maxAnisotropy;\n        samplerDesc.ComparisonFunc = comparisonFunc;\n        samplerDesc.BorderColor = borderColor;\n        samplerDesc.MinLOD = minLOD;\n        samplerDesc.MaxLOD = maxLOD;\n        samplerDesc.ShaderVisibility = shaderVisibility;\n        samplerDesc.RegisterSpace = registerSpace;\n    }\n    inline void Init(\n         UINT shaderRegister,\n         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,\n         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         FLOAT mipLODBias = 0,\n         UINT maxAnisotropy = 16,\n         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,\n         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n         FLOAT minLOD = 0.f,\n         FLOAT maxLOD = D3D12_FLOAT32_MAX,\n         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,\n         UINT registerSpace = 0) noexcept\n    {\n        Init(\n            *this,\n            shaderRegister,\n            filter,\n            addressU,\n            addressV,\n            addressW,\n            mipLODBias,\n            maxAnisotropy,\n            comparisonFunc,\n            borderColor,\n            minLOD,\n            maxLOD,\n            shaderVisibility,\n            registerSpace);\n    }\n\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_SIGNATURE_DESC : public D3D12_ROOT_SIGNATURE_DESC\n{\n    CD3DX12_ROOT_SIGNATURE_DESC() = default;\n    explicit CD3DX12_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept :\n        D3D12_ROOT_SIGNATURE_DESC(o)\n    {}\n    CD3DX12_ROOT_SIGNATURE_DESC(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n    CD3DX12_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept\n    {\n        Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);\n    }\n\n    inline void Init(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_SIGNATURE_DESC &desc,\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        desc.NumParameters = numParameters;\n        desc.pParameters = _pParameters;\n        desc.NumStaticSamplers = numStaticSamplers;\n        desc.pStaticSamplers = _pStaticSamplers;\n        desc.Flags = flags;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_DESCRIPTOR_RANGE1 : public D3D12_DESCRIPTOR_RANGE1\n{\n    CD3DX12_DESCRIPTOR_RANGE1() = default;\n    explicit CD3DX12_DESCRIPTOR_RANGE1(const D3D12_DESCRIPTOR_RANGE1 &o) noexcept :\n        D3D12_DESCRIPTOR_RANGE1(o)\n    {}\n    CD3DX12_DESCRIPTOR_RANGE1(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);\n    }\n\n    inline void Init(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_DESCRIPTOR_RANGE1 &range,\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        range.RangeType = rangeType;\n        range.NumDescriptors = numDescriptors;\n        range.BaseShaderRegister = baseShaderRegister;\n        range.RegisterSpace = registerSpace;\n        range.Flags = flags;\n        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR_TABLE1 : public D3D12_ROOT_DESCRIPTOR_TABLE1\n{\n    CD3DX12_ROOT_DESCRIPTOR_TABLE1() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE1(const D3D12_ROOT_DESCRIPTOR_TABLE1 &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR_TABLE1(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR_TABLE1(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept\n    {\n        Init(numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    inline void Init(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept\n    {\n        Init(*this, numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE1 &rootDescriptorTable,\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept\n    {\n        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;\n        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR1 : public D3D12_ROOT_DESCRIPTOR1\n{\n    CD3DX12_ROOT_DESCRIPTOR1() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR1(const D3D12_ROOT_DESCRIPTOR1 &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR1(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR1(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept\n    {\n        Init(shaderRegister, registerSpace, flags);\n    }\n\n    inline void Init(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept\n    {\n        Init(*this, shaderRegister, registerSpace, flags);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_DESCRIPTOR1 &table,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept\n    {\n        table.ShaderRegister = shaderRegister;\n        table.RegisterSpace = registerSpace;\n        table.Flags = flags;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_PARAMETER1 : public D3D12_ROOT_PARAMETER1\n{\n    CD3DX12_ROOT_PARAMETER1() = default;\n    explicit CD3DX12_ROOT_PARAMETER1(const D3D12_ROOT_PARAMETER1 &o) noexcept :\n        D3D12_ROOT_PARAMETER1(o)\n    {}\n\n    static inline void InitAsDescriptorTable(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR_TABLE1::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);\n    }\n\n    static inline void InitAsConstants(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsConstantBufferView(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);\n    }\n\n    static inline void InitAsShaderResourceView(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);\n    }\n\n    static inline void InitAsUnorderedAccessView(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);\n    }\n\n    inline void InitAsDescriptorTable(\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);\n    }\n\n    inline void InitAsConstants(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsConstantBufferView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstantBufferView(*this, shaderRegister, registerSpace, flags, visibility);\n    }\n\n    inline void InitAsShaderResourceView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsShaderResourceView(*this, shaderRegister, registerSpace, flags, visibility);\n    }\n\n    inline void InitAsUnorderedAccessView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, flags, visibility);\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC : public D3D12_VERSIONED_ROOT_SIGNATURE_DESC\n{\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC() = default;\n    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC &o) noexcept :\n        D3D12_VERSIONED_ROOT_SIGNATURE_DESC(o)\n    {}\n    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept\n    {\n        Version = D3D_ROOT_SIGNATURE_VERSION_1_0;\n        Desc_1_0 = o;\n    }\n    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC1 &o) noexcept\n    {\n        Version = D3D_ROOT_SIGNATURE_VERSION_1_1;\n        Desc_1_1 = o;\n    }\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_0(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_1(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept\n    {\n        Init_1_1(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);\n    }\n\n    inline void Init_1_0(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_0(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n\n    static inline void Init_1_0(\n        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_0;\n        desc.Desc_1_0.NumParameters = numParameters;\n        desc.Desc_1_0.pParameters = _pParameters;\n        desc.Desc_1_0.NumStaticSamplers = numStaticSamplers;\n        desc.Desc_1_0.pStaticSamplers = _pStaticSamplers;\n        desc.Desc_1_0.Flags = flags;\n    }\n\n    inline void Init_1_1(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_1(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n\n    static inline void Init_1_1(\n        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;\n        desc.Desc_1_1.NumParameters = numParameters;\n        desc.Desc_1_1.pParameters = _pParameters;\n        desc.Desc_1_1.NumStaticSamplers = numStaticSamplers;\n        desc.Desc_1_1.pStaticSamplers = _pStaticSamplers;\n        desc.Desc_1_1.Flags = flags;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_CPU_DESCRIPTOR_HANDLE : public D3D12_CPU_DESCRIPTOR_HANDLE\n{\n    CD3DX12_CPU_DESCRIPTOR_HANDLE() = default;\n    explicit CD3DX12_CPU_DESCRIPTOR_HANDLE(const D3D12_CPU_DESCRIPTOR_HANDLE &o) noexcept :\n        D3D12_CPU_DESCRIPTOR_HANDLE(o)\n    {}\n    CD3DX12_CPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetScaledByIncrementSize);\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        ptr = SIZE_T(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n        return *this;\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept\n    {\n        ptr = SIZE_T(INT64(ptr) + INT64(offsetScaledByIncrementSize));\n        return *this;\n    }\n    bool operator==(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr == other.ptr);\n    }\n    bool operator!=(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr != other.ptr);\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE &operator=(const D3D12_CPU_DESCRIPTOR_HANDLE &other) noexcept\n    {\n        ptr = other.ptr;\n        return *this;\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetScaledByIncrementSize);\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_GPU_DESCRIPTOR_HANDLE : public D3D12_GPU_DESCRIPTOR_HANDLE\n{\n    CD3DX12_GPU_DESCRIPTOR_HANDLE() = default;\n    explicit CD3DX12_GPU_DESCRIPTOR_HANDLE(const D3D12_GPU_DESCRIPTOR_HANDLE &o) noexcept :\n        D3D12_GPU_DESCRIPTOR_HANDLE(o)\n    {}\n    CD3DX12_GPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetScaledByIncrementSize);\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        ptr = UINT64(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n        return *this;\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept\n    {\n        ptr = UINT64(INT64(ptr) + INT64(offsetScaledByIncrementSize));\n        return *this;\n    }\n    inline bool operator==(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr == other.ptr);\n    }\n    inline bool operator!=(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr != other.ptr);\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE &operator=(const D3D12_GPU_DESCRIPTOR_HANDLE &other) noexcept\n    {\n        ptr = other.ptr;\n        return *this;\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetScaledByIncrementSize);\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n    }\n};\n\n//------------------------------------------------------------------------------------------------\ninline constexpr UINT D3D12CalcSubresource( UINT MipSlice, UINT ArraySlice, UINT PlaneSlice, UINT MipLevels, UINT ArraySize ) noexcept\n{\n    return MipSlice + ArraySlice * MipLevels + PlaneSlice * MipLevels * ArraySize;\n}\n\n//------------------------------------------------------------------------------------------------\ntemplate <typename T, typename U, typename V>\ninline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept\n{\n    MipSlice = static_cast<T>(Subresource % MipLevels);\n    ArraySlice = static_cast<U>((Subresource / MipLevels) % ArraySize);\n    PlaneSlice = static_cast<V>(Subresource / (MipLevels * ArraySize));\n}\n\n//------------------------------------------------------------------------------------------------\ninline UINT8 D3D12GetFormatPlaneCount(\n    _In_ ID3D12Device* pDevice,\n    DXGI_FORMAT Format\n    ) noexcept\n{\n    D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = { Format, 0 };\n    if (FAILED(pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo))))\n    {\n        return 0;\n    }\n    return formatInfo.PlaneCount;\n}\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RESOURCE_DESC : public D3D12_RESOURCE_DESC\n{\n    CD3DX12_RESOURCE_DESC() = default;\n    explicit CD3DX12_RESOURCE_DESC( const D3D12_RESOURCE_DESC& o ) noexcept :\n        D3D12_RESOURCE_DESC( o )\n    {}\n    CD3DX12_RESOURCE_DESC(\n        D3D12_RESOURCE_DIMENSION dimension,\n        UINT64 alignment,\n        UINT64 width,\n        UINT height,\n        UINT16 depthOrArraySize,\n        UINT16 mipLevels,\n        DXGI_FORMAT format,\n        UINT sampleCount,\n        UINT sampleQuality,\n        D3D12_TEXTURE_LAYOUT layout,\n        D3D12_RESOURCE_FLAGS flags ) noexcept\n    {\n        Dimension = dimension;\n        Alignment = alignment;\n        Width = width;\n        Height = height;\n        DepthOrArraySize = depthOrArraySize;\n        MipLevels = mipLevels;\n        Format = format;\n        SampleDesc.Count = sampleCount;\n        SampleDesc.Quality = sampleQuality;\n        Layout = layout;\n        Flags = flags;\n    }\n    static inline CD3DX12_RESOURCE_DESC Buffer(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,\n            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Buffer(\n        UINT64 width,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,\n            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Tex1D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,\n            mipLevels, format, 1, 0, layout, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Tex2D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        UINT sampleCount = 1,\n        UINT sampleQuality = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,\n            mipLevels, format, sampleCount, sampleQuality, layout, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Tex3D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 depth,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,\n            mipLevels, format, 1, 0, layout, flags );\n    }\n    inline UINT16 Depth() const noexcept\n    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT16 ArraySize() const noexcept\n    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept\n    { return D3D12GetFormatPlaneCount(pDevice, Format); }\n    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept\n    { return MipLevels * ArraySize() * PlaneCount(pDevice); }\n    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept\n    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }\n};\ninline bool operator==( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept\n{\n    return l.Dimension == r.Dimension &&\n        l.Alignment == r.Alignment &&\n        l.Width == r.Width &&\n        l.Height == r.Height &&\n        l.DepthOrArraySize == r.DepthOrArraySize &&\n        l.MipLevels == r.MipLevels &&\n        l.Format == r.Format &&\n        l.SampleDesc.Count == r.SampleDesc.Count &&\n        l.SampleDesc.Quality == r.SampleDesc.Quality &&\n        l.Layout == r.Layout &&\n        l.Flags == r.Flags;\n}\ninline bool operator!=( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\n// Requires the Windows 10 SDK (19041)\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct CD3DX12_RESOURCE_DESC1 : public D3D12_RESOURCE_DESC1\n{\n    CD3DX12_RESOURCE_DESC1() = default;\n    explicit CD3DX12_RESOURCE_DESC1( const D3D12_RESOURCE_DESC1& o ) noexcept :\n        D3D12_RESOURCE_DESC1( o )\n    {}\n    CD3DX12_RESOURCE_DESC1(\n        D3D12_RESOURCE_DIMENSION dimension,\n        UINT64 alignment,\n        UINT64 width,\n        UINT height,\n        UINT16 depthOrArraySize,\n        UINT16 mipLevels,\n        DXGI_FORMAT format,\n        UINT sampleCount,\n        UINT sampleQuality,\n        D3D12_TEXTURE_LAYOUT layout,\n        D3D12_RESOURCE_FLAGS flags,\n        UINT samplerFeedbackMipRegionWidth = 0,\n        UINT samplerFeedbackMipRegionHeight = 0,\n        UINT samplerFeedbackMipRegionDepth = 0) noexcept\n    {\n        Dimension = dimension;\n        Alignment = alignment;\n        Width = width;\n        Height = height;\n        DepthOrArraySize = depthOrArraySize;\n        MipLevels = mipLevels;\n        Format = format;\n        SampleDesc.Count = sampleCount;\n        SampleDesc.Quality = sampleQuality;\n        Layout = layout;\n        Flags = flags;\n        SamplerFeedbackMipRegion.Width = samplerFeedbackMipRegionWidth;\n        SamplerFeedbackMipRegion.Height = samplerFeedbackMipRegionHeight;\n        SamplerFeedbackMipRegion.Depth = samplerFeedbackMipRegionDepth;\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Buffer(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,\n            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Buffer(\n        UINT64 width,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,\n            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Tex1D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,\n            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Tex2D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        UINT sampleCount = 1,\n        UINT sampleQuality = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0,\n        UINT samplerFeedbackMipRegionWidth = 0,\n        UINT samplerFeedbackMipRegionHeight = 0,\n        UINT samplerFeedbackMipRegionDepth = 0) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,\n            mipLevels, format, sampleCount, sampleQuality, layout, flags, samplerFeedbackMipRegionWidth,\n            samplerFeedbackMipRegionHeight, samplerFeedbackMipRegionDepth );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Tex3D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 depth,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,\n            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );\n    }\n    inline UINT16 Depth() const noexcept\n    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT16 ArraySize() const noexcept\n    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept\n    { return D3D12GetFormatPlaneCount(pDevice, Format); }\n    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept\n    { return MipLevels * ArraySize() * PlaneCount(pDevice); }\n    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept\n    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }\n};\ninline bool operator==( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept\n{\n    return l.Dimension == r.Dimension &&\n        l.Alignment == r.Alignment &&\n        l.Width == r.Width &&\n        l.Height == r.Height &&\n        l.DepthOrArraySize == r.DepthOrArraySize &&\n        l.MipLevels == r.MipLevels &&\n        l.Format == r.Format &&\n        l.SampleDesc.Count == r.SampleDesc.Count &&\n        l.SampleDesc.Quality == r.SampleDesc.Quality &&\n        l.Layout == r.Layout &&\n        l.Flags == r.Flags &&\n        l.SamplerFeedbackMipRegion.Width == r.SamplerFeedbackMipRegion.Width &&\n        l.SamplerFeedbackMipRegion.Height == r.SamplerFeedbackMipRegion.Height &&\n        l.SamplerFeedbackMipRegion.Depth == r.SamplerFeedbackMipRegion.Depth;\n}\ninline bool operator!=( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept\n{ return !( l == r ); }\n#endif // NTDDI_WIN10_VB\n\n//------------------------------------------------------------------------------------------------\n// Requires the Windows 10 Fall Creators Update SDK (16299)\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\nstruct CD3DX12_VIEW_INSTANCING_DESC : public D3D12_VIEW_INSTANCING_DESC\n{\n    CD3DX12_VIEW_INSTANCING_DESC() = default;\n    explicit CD3DX12_VIEW_INSTANCING_DESC( const D3D12_VIEW_INSTANCING_DESC& o ) noexcept :\n        D3D12_VIEW_INSTANCING_DESC( o )\n    {}\n    explicit CD3DX12_VIEW_INSTANCING_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        ViewInstanceCount = 0;\n        pViewInstanceLocations = nullptr;\n        Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;\n    }\n    explicit CD3DX12_VIEW_INSTANCING_DESC(\n        UINT InViewInstanceCount,\n        const D3D12_VIEW_INSTANCE_LOCATION* InViewInstanceLocations,\n        D3D12_VIEW_INSTANCING_FLAGS InFlags) noexcept\n    {\n        ViewInstanceCount = InViewInstanceCount;\n        pViewInstanceLocations = InViewInstanceLocations;\n        Flags = InFlags;\n    }\n};\n#endif // NTDDI_WIN10_RS3\n\n//------------------------------------------------------------------------------------------------\n// Row-by-row memcpy\ninline void MemcpySubresource(\n    _In_ const D3D12_MEMCPY_DEST* pDest,\n    _In_ const D3D12_SUBRESOURCE_DATA* pSrc,\n    SIZE_T RowSizeInBytes,\n    UINT NumRows,\n    UINT NumSlices) noexcept\n{\n    for (UINT z = 0; z < NumSlices; ++z)\n    {\n        auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;\n        auto pSrcSlice = static_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * LONG_PTR(z);\n        for (UINT y = 0; y < NumRows; ++y)\n        {\n            memcpy(pDestSlice + pDest->RowPitch * y,\n                   pSrcSlice + pSrc->RowPitch * LONG_PTR(y),\n                   RowSizeInBytes);\n        }\n    }\n}\n\n//------------------------------------------------------------------------------------------------\n// Returns required size of a buffer to be used for data upload\ninline UINT64 GetRequiredIntermediateSize(\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources) noexcept\n{\n    auto Desc = pDestinationResource->GetDesc();\n    UINT64 RequiredSize = 0;\n\n    ID3D12Device* pDevice = nullptr;\n    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));\n    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, 0, nullptr, nullptr, nullptr, &RequiredSize);\n    pDevice->Release();\n\n    return RequiredSize;\n}\n\n//------------------------------------------------------------------------------------------------\n// All arrays must be populated (e.g. by calling GetCopyableFootprints)\ninline UINT64 UpdateSubresources(\n    _In_ ID3D12GraphicsCommandList* pCmdList,\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_ ID3D12Resource* pIntermediate,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,\n    UINT64 RequiredSize,\n    _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,\n    _In_reads_(NumSubresources) const UINT* pNumRows,\n    _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,\n    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept\n{\n    // Minor validation\n    auto IntermediateDesc = pIntermediate->GetDesc();\n    auto DestinationDesc = pDestinationResource->GetDesc();\n    if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||\n        IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||\n        RequiredSize > SIZE_T(-1) ||\n        (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&\n            (FirstSubresource != 0 || NumSubresources != 1)))\n    {\n        return 0;\n    }\n\n    BYTE* pData;\n    HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));\n    if (FAILED(hr))\n    {\n        return 0;\n    }\n\n    for (UINT i = 0; i < NumSubresources; ++i)\n    {\n        if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;\n        D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };\n        MemcpySubresource(&DestData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);\n    }\n    pIntermediate->Unmap(0, nullptr);\n\n    if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)\n    {\n        pCmdList->CopyBufferRegion(\n            pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);\n    }\n    else\n    {\n        for (UINT i = 0; i < NumSubresources; ++i)\n        {\n            CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);\n            CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);\n            pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);\n        }\n    }\n    return RequiredSize;\n}\n\n//------------------------------------------------------------------------------------------------\n// Heap-allocating UpdateSubresources implementation\ninline UINT64 UpdateSubresources(\n    _In_ ID3D12GraphicsCommandList* pCmdList,\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_ ID3D12Resource* pIntermediate,\n    UINT64 IntermediateOffset,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,\n    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept\n{\n    UINT64 RequiredSize = 0;\n    UINT64 MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;\n    if (MemToAlloc > SIZE_MAX)\n    {\n       return 0;\n    }\n    void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));\n    if (pMem == nullptr)\n    {\n       return 0;\n    }\n    auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);\n    UINT64* pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);\n    UINT* pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);\n\n    auto Desc = pDestinationResource->GetDesc();\n    ID3D12Device* pDevice = nullptr;\n    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));\n    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);\n    pDevice->Release();\n\n    UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pSrcData);\n    HeapFree(GetProcessHeap(), 0, pMem);\n    return Result;\n}\n\n//------------------------------------------------------------------------------------------------\n// Stack-allocating UpdateSubresources implementation\ntemplate <UINT MaxSubresources>\ninline UINT64 UpdateSubresources(\n    _In_ ID3D12GraphicsCommandList* pCmdList,\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_ ID3D12Resource* pIntermediate,\n    UINT64 IntermediateOffset,\n    _In_range_(0, MaxSubresources) UINT FirstSubresource,\n    _In_range_(1, MaxSubresources - FirstSubresource) UINT NumSubresources,\n    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept\n{\n    UINT64 RequiredSize = 0;\n    D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];\n    UINT NumRows[MaxSubresources];\n    UINT64 RowSizesInBytes[MaxSubresources];\n\n    auto Desc = pDestinationResource->GetDesc();\n    ID3D12Device* pDevice = nullptr;\n    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));\n    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);\n    pDevice->Release();\n\n    return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pSrcData);\n}\n\n//------------------------------------------------------------------------------------------------\ninline constexpr bool D3D12IsLayoutOpaque( D3D12_TEXTURE_LAYOUT Layout ) noexcept\n{ return Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN || Layout == D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; }\n\n//------------------------------------------------------------------------------------------------\ntemplate <typename t_CommandListType>\ninline ID3D12CommandList * const * CommandListCast(t_CommandListType * const * pp) noexcept\n{\n    // This cast is useful for passing strongly typed command list pointers into\n    // ExecuteCommandLists.\n    // This cast is valid as long as the const-ness is respected. D3D12 APIs do\n    // respect the const-ness of their arguments.\n    return reinterpret_cast<ID3D12CommandList * const *>(pp);\n}\n\n//------------------------------------------------------------------------------------------------\n// D3D12 exports a new method for serializing root signatures in the Windows 10 Anniversary Update.\n// To help enable root signature 1.1 features when they are available and not require maintaining\n// two code paths for building root signatures, this helper method reconstructs a 1.0 signature when\n// 1.1 is not supported.\ninline HRESULT D3DX12SerializeVersionedRootSignature(\n    _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignatureDesc,\n    D3D_ROOT_SIGNATURE_VERSION MaxVersion,\n    _Outptr_ ID3DBlob** ppBlob,\n    _Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorBlob) noexcept\n{\n    if (ppErrorBlob != nullptr)\n    {\n        *ppErrorBlob = nullptr;\n    }\n\n    switch (MaxVersion)\n    {\n        case D3D_ROOT_SIGNATURE_VERSION_1_0:\n            switch (pRootSignatureDesc->Version)\n            {\n                case D3D_ROOT_SIGNATURE_VERSION_1_0:\n                    return D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);\n\n                case D3D_ROOT_SIGNATURE_VERSION_1_1:\n                {\n                    HRESULT hr = S_OK;\n                    const D3D12_ROOT_SIGNATURE_DESC1& desc_1_1 = pRootSignatureDesc->Desc_1_1;\n\n                    const SIZE_T ParametersSize = sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters;\n                    void* pParameters = (ParametersSize > 0) ? HeapAlloc(GetProcessHeap(), 0, ParametersSize) : nullptr;\n                    if (ParametersSize > 0 && pParameters == nullptr)\n                    {\n                        hr = E_OUTOFMEMORY;\n                    }\n                    auto pParameters_1_0 = static_cast<D3D12_ROOT_PARAMETER*>(pParameters);\n\n                    if (SUCCEEDED(hr))\n                    {\n                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)\n                        {\n                            __analysis_assume(ParametersSize == sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters);\n                            pParameters_1_0[n].ParameterType = desc_1_1.pParameters[n].ParameterType;\n                            pParameters_1_0[n].ShaderVisibility = desc_1_1.pParameters[n].ShaderVisibility;\n\n                            switch (desc_1_1.pParameters[n].ParameterType)\n                            {\n                            case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:\n                                pParameters_1_0[n].Constants.Num32BitValues = desc_1_1.pParameters[n].Constants.Num32BitValues;\n                                pParameters_1_0[n].Constants.RegisterSpace = desc_1_1.pParameters[n].Constants.RegisterSpace;\n                                pParameters_1_0[n].Constants.ShaderRegister = desc_1_1.pParameters[n].Constants.ShaderRegister;\n                                break;\n\n                            case D3D12_ROOT_PARAMETER_TYPE_CBV:\n                            case D3D12_ROOT_PARAMETER_TYPE_SRV:\n                            case D3D12_ROOT_PARAMETER_TYPE_UAV:\n                                pParameters_1_0[n].Descriptor.RegisterSpace = desc_1_1.pParameters[n].Descriptor.RegisterSpace;\n                                pParameters_1_0[n].Descriptor.ShaderRegister = desc_1_1.pParameters[n].Descriptor.ShaderRegister;\n                                break;\n\n                            case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:\n                                const D3D12_ROOT_DESCRIPTOR_TABLE1& table_1_1 = desc_1_1.pParameters[n].DescriptorTable;\n\n                                const SIZE_T DescriptorRangesSize = sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges;\n                                void* pDescriptorRanges = (DescriptorRangesSize > 0 && SUCCEEDED(hr)) ? HeapAlloc(GetProcessHeap(), 0, DescriptorRangesSize) : nullptr;\n                                if (DescriptorRangesSize > 0 && pDescriptorRanges == nullptr)\n                                {\n                                    hr = E_OUTOFMEMORY;\n                                }\n                                auto pDescriptorRanges_1_0 = static_cast<D3D12_DESCRIPTOR_RANGE*>(pDescriptorRanges);\n\n                                if (SUCCEEDED(hr))\n                                {\n                                    for (UINT x = 0; x < table_1_1.NumDescriptorRanges; x++)\n                                    {\n                                        __analysis_assume(DescriptorRangesSize == sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges);\n                                        pDescriptorRanges_1_0[x].BaseShaderRegister = table_1_1.pDescriptorRanges[x].BaseShaderRegister;\n                                        pDescriptorRanges_1_0[x].NumDescriptors = table_1_1.pDescriptorRanges[x].NumDescriptors;\n                                        pDescriptorRanges_1_0[x].OffsetInDescriptorsFromTableStart = table_1_1.pDescriptorRanges[x].OffsetInDescriptorsFromTableStart;\n                                        pDescriptorRanges_1_0[x].RangeType = table_1_1.pDescriptorRanges[x].RangeType;\n                                        pDescriptorRanges_1_0[x].RegisterSpace = table_1_1.pDescriptorRanges[x].RegisterSpace;\n                                    }\n                                }\n\n                                D3D12_ROOT_DESCRIPTOR_TABLE& table_1_0 = pParameters_1_0[n].DescriptorTable;\n                                table_1_0.NumDescriptorRanges = table_1_1.NumDescriptorRanges;\n                                table_1_0.pDescriptorRanges = pDescriptorRanges_1_0;\n                            }\n                        }\n                    }\n\n                    if (SUCCEEDED(hr))\n                    {\n                        CD3DX12_ROOT_SIGNATURE_DESC desc_1_0(desc_1_1.NumParameters, pParameters_1_0, desc_1_1.NumStaticSamplers, desc_1_1.pStaticSamplers, desc_1_1.Flags);\n                        hr = D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);\n                    }\n\n                    if (pParameters)\n                    {\n                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)\n                        {\n                            if (desc_1_1.pParameters[n].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)\n                            {\n                                HeapFree(GetProcessHeap(), 0, reinterpret_cast<void*>(const_cast<D3D12_DESCRIPTOR_RANGE*>(pParameters_1_0[n].DescriptorTable.pDescriptorRanges)));\n                            }\n                        }\n                        HeapFree(GetProcessHeap(), 0, pParameters);\n                    }\n                    return hr;\n                }\n            }\n            break;\n\n        case D3D_ROOT_SIGNATURE_VERSION_1_1:\n            return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob);\n    }\n\n    return E_INVALIDARG;\n}\n\n//------------------------------------------------------------------------------------------------\n#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\nstruct CD3DX12_RT_FORMAT_ARRAY : public D3D12_RT_FORMAT_ARRAY\n{\n    CD3DX12_RT_FORMAT_ARRAY() = default;\n    explicit CD3DX12_RT_FORMAT_ARRAY(const D3D12_RT_FORMAT_ARRAY& o) noexcept\n        : D3D12_RT_FORMAT_ARRAY(o)\n    {}\n    explicit CD3DX12_RT_FORMAT_ARRAY(_In_reads_(NumFormats) const DXGI_FORMAT* pFormats, UINT NumFormats) noexcept\n    {\n        NumRenderTargets = NumFormats;\n        memcpy(RTFormats, pFormats, sizeof(RTFormats));\n        // assumes ARRAY_SIZE(pFormats) == ARRAY_SIZE(RTFormats)\n    }\n};\n\n//------------------------------------------------------------------------------------------------\n// Pipeline State Stream Helpers\n//------------------------------------------------------------------------------------------------\n\n//------------------------------------------------------------------------------------------------\n// Stream Subobjects, i.e. elements of a stream\n\nstruct DefaultSampleMask { operator UINT() noexcept { return UINT_MAX; } };\nstruct DefaultSampleDesc { operator DXGI_SAMPLE_DESC() noexcept { return DXGI_SAMPLE_DESC{1, 0}; } };\n\n#pragma warning(push)\n#pragma warning(disable : 4324)\ntemplate <typename InnerStructType, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type, typename DefaultArg = InnerStructType>\nclass alignas(void*) CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT\n{\nprivate:\n    D3D12_PIPELINE_STATE_SUBOBJECT_TYPE _Type;\n    InnerStructType _Inner;\npublic:\n    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT() noexcept : _Type(Type), _Inner(DefaultArg()) {}\n    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT(InnerStructType const& i) noexcept : _Type(Type), _Inner(i) {}\n    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT& operator=(InnerStructType const& i) noexcept { _Type = Type; _Inner = i; return *this; }\n    operator InnerStructType const&() const noexcept { return _Inner; }\n    operator InnerStructType&() noexcept { return _Inner; }\n    InnerStructType* operator&() noexcept { return &_Inner; }\n    InnerStructType const* operator&() const noexcept { return &_Inner; }\n};\n#pragma warning(pop)\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PIPELINE_STATE_FLAGS,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS>                             CD3DX12_PIPELINE_STATE_STREAM_FLAGS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK>                         CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< ID3D12RootSignature*,               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE>                    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INPUT_LAYOUT_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT>                      CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE>                CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PRIMITIVE_TOPOLOGY_TYPE,      D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY>                CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS>                                CD3DX12_PIPELINE_STATE_STREAM_VS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS>                                CD3DX12_PIPELINE_STATE_STREAM_GS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_STREAM_OUTPUT_DESC,           D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT>                     CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS>                                CD3DX12_PIPELINE_STATE_STREAM_HS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS>                                CD3DX12_PIPELINE_STATE_STREAM_DS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS>                                CD3DX12_PIPELINE_STATE_STREAM_PS;\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS>                                CD3DX12_PIPELINE_STATE_STREAM_AS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS>                                CD3DX12_PIPELINE_STATE_STREAM_MS;\n#endif\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS>                                CD3DX12_PIPELINE_STATE_STREAM_CS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_BLEND_DESC,                 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND,          CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL,  CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC1,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_FORMAT,                        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT>              CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_RASTERIZER_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER,     CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_RT_FORMAT_ARRAY,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS>             CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_SAMPLE_DESC,                   D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC,    DefaultSampleDesc> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK,    DefaultSampleMask> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_CACHED_PIPELINE_STATE,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO>                        CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO;\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_VIEW_INSTANCING_DESC,       D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, CD3DX12_DEFAULT>  CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING;\n#endif\n\n//------------------------------------------------------------------------------------------------\n// Stream Parser Helpers\n\nstruct ID3DX12PipelineParserCallbacks\n{\n    // Subobject Callbacks\n    virtual void FlagsCb(D3D12_PIPELINE_STATE_FLAGS) {}\n    virtual void NodeMaskCb(UINT) {}\n    virtual void RootSignatureCb(ID3D12RootSignature*) {}\n    virtual void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC&) {}\n    virtual void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE) {}\n    virtual void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE) {}\n    virtual void VSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void GSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC&) {}\n    virtual void HSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void DSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void PSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void CSCb(const D3D12_SHADER_BYTECODE&) {}\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n    virtual void ASCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void MSCb(const D3D12_SHADER_BYTECODE&) {}\n#endif\n    virtual void BlendStateCb(const D3D12_BLEND_DESC&) {}\n    virtual void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC&) {}\n    virtual void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1&) {}\n    virtual void DSVFormatCb(DXGI_FORMAT) {}\n    virtual void RasterizerStateCb(const D3D12_RASTERIZER_DESC&) {}\n    virtual void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY&) {}\n    virtual void SampleDescCb(const DXGI_SAMPLE_DESC&) {}\n    virtual void SampleMaskCb(UINT) {}\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n    virtual void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC&) {}\n#endif\n    virtual void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE&) {}\n\n    // Error Callbacks\n    virtual void ErrorBadInputParameter(UINT /*ParameterIndex*/) {}\n    virtual void ErrorDuplicateSubobject(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE /*DuplicateType*/) {}\n    virtual void ErrorUnknownSubobject(UINT /*UnknownTypeValue*/) {}\n\n    virtual ~ID3DX12PipelineParserCallbacks() = default;\n};\n\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct D3DX12_MESH_SHADER_PIPELINE_STATE_DESC\n{\n    ID3D12RootSignature*          pRootSignature;\n    D3D12_SHADER_BYTECODE         AS;\n    D3D12_SHADER_BYTECODE         MS;\n    D3D12_SHADER_BYTECODE         PS;\n    D3D12_BLEND_DESC              BlendState;\n    UINT                          SampleMask;\n    D3D12_RASTERIZER_DESC         RasterizerState;\n    D3D12_DEPTH_STENCIL_DESC      DepthStencilState;\n    D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;\n    UINT                          NumRenderTargets;\n    DXGI_FORMAT                   RTVFormats[ D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT ];\n    DXGI_FORMAT                   DSVFormat;\n    DXGI_SAMPLE_DESC              SampleDesc;\n    UINT                          NodeMask;\n    D3D12_CACHED_PIPELINE_STATE   CachedPSO;\n    D3D12_PIPELINE_STATE_FLAGS    Flags;\n};\n\n// CD3DX12_PIPELINE_STATE_STREAM2 Works on OS Build 19041+ (where there is a new mesh shader pipeline).\n// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).\n// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.\nstruct CD3DX12_PIPELINE_STATE_STREAM2\n{\n    CD3DX12_PIPELINE_STATE_STREAM2() = default;\n    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC\n    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , InputLayout(Desc.InputLayout)\n        , IBStripCutValue(Desc.IBStripCutValue)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , VS(Desc.VS)\n        , GS(Desc.GS)\n        , StreamOutput(Desc.StreamOutput)\n        , HS(Desc.HS)\n        , DS(Desc.DS)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM2(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , PS(Desc.PS)\n        , AS(Desc.AS)\n        , MS(Desc.MS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))\n        , CachedPSO(Desc.CachedPSO)\n    {\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;\n    }\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;\n    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;\n    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;\n    CD3DX12_PIPELINE_STATE_STREAM_VS VS;\n    CD3DX12_PIPELINE_STATE_STREAM_GS GS;\n    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;\n    CD3DX12_PIPELINE_STATE_STREAM_HS HS;\n    CD3DX12_PIPELINE_STATE_STREAM_DS DS;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_AS AS;\n    CD3DX12_PIPELINE_STATE_STREAM_MS MS;\n    CD3DX12_PIPELINE_STATE_STREAM_CS CS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept\n    {\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.InputLayout           = this->InputLayout;\n        D.IBStripCutValue       = this->IBStripCutValue;\n        D.PrimitiveTopologyType = this->PrimitiveTopologyType;\n        D.VS                    = this->VS;\n        D.GS                    = this->GS;\n        D.StreamOutput          = this->StreamOutput;\n        D.HS                    = this->HS;\n        D.DS                    = this->DS;\n        D.PS                    = this->PS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept\n    {\n        D3D12_COMPUTE_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.CS                    = this->CS;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_VB\n\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n// CD3DX12_PIPELINE_STATE_STREAM1 Works on OS Build 16299+ (where there is a new view instancing subobject).\n// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.\nstruct CD3DX12_PIPELINE_STATE_STREAM1\n{\n    CD3DX12_PIPELINE_STATE_STREAM1() = default;\n    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC\n    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , InputLayout(Desc.InputLayout)\n        , IBStripCutValue(Desc.IBStripCutValue)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , VS(Desc.VS)\n        , GS(Desc.GS)\n        , StreamOutput(Desc.StreamOutput)\n        , HS(Desc.HS)\n        , DS(Desc.DS)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n    CD3DX12_PIPELINE_STATE_STREAM1(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n#endif\n    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))\n        , CachedPSO(Desc.CachedPSO)\n    {\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;\n    }\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;\n    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;\n    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;\n    CD3DX12_PIPELINE_STATE_STREAM_VS VS;\n    CD3DX12_PIPELINE_STATE_STREAM_GS GS;\n    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;\n    CD3DX12_PIPELINE_STATE_STREAM_HS HS;\n    CD3DX12_PIPELINE_STATE_STREAM_DS DS;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_CS CS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept\n    {\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.InputLayout           = this->InputLayout;\n        D.IBStripCutValue       = this->IBStripCutValue;\n        D.PrimitiveTopologyType = this->PrimitiveTopologyType;\n        D.VS                    = this->VS;\n        D.GS                    = this->GS;\n        D.StreamOutput          = this->StreamOutput;\n        D.HS                    = this->HS;\n        D.DS                    = this->DS;\n        D.PS                    = this->PS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept\n    {\n        D3D12_COMPUTE_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.CS                    = this->CS;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_RS3\n\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct CD3DX12_PIPELINE_MESH_STATE_STREAM\n{\n    CD3DX12_PIPELINE_MESH_STATE_STREAM() = default;\n    CD3DX12_PIPELINE_MESH_STATE_STREAM(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , PS(Desc.PS)\n        , AS(Desc.AS)\n        , MS(Desc.MS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_AS AS;\n    CD3DX12_PIPELINE_STATE_STREAM_MS MS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;\n    D3DX12_MESH_SHADER_PIPELINE_STATE_DESC MeshShaderDescV0() const noexcept\n    {\n        D3DX12_MESH_SHADER_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.PS                    = this->PS;\n        D.AS                    = this->AS;\n        D.MS                    = this->MS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_VB\n\n// CD3DX12_PIPELINE_STATE_STREAM works on OS Build 15063+ but does not support new subobject(s) added in OS Build 16299+.\n// See CD3DX12_PIPELINE_STATE_STREAM1 for instance.\nstruct CD3DX12_PIPELINE_STATE_STREAM\n{\n    CD3DX12_PIPELINE_STATE_STREAM() = default;\n    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , InputLayout(Desc.InputLayout)\n        , IBStripCutValue(Desc.IBStripCutValue)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , VS(Desc.VS)\n        , GS(Desc.GS)\n        , StreamOutput(Desc.StreamOutput)\n        , HS(Desc.HS)\n        , DS(Desc.DS)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))\n        , CachedPSO(Desc.CachedPSO)\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;\n    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;\n    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;\n    CD3DX12_PIPELINE_STATE_STREAM_VS VS;\n    CD3DX12_PIPELINE_STATE_STREAM_GS GS;\n    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;\n    CD3DX12_PIPELINE_STATE_STREAM_HS HS;\n    CD3DX12_PIPELINE_STATE_STREAM_DS DS;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_CS CS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept\n    {\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.InputLayout           = this->InputLayout;\n        D.IBStripCutValue       = this->IBStripCutValue;\n        D.PrimitiveTopologyType = this->PrimitiveTopologyType;\n        D.VS                    = this->VS;\n        D.GS                    = this->GS;\n        D.StreamOutput          = this->StreamOutput;\n        D.HS                    = this->HS;\n        D.DS                    = this->DS;\n        D.PS                    = this->PS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept\n    {\n        D3D12_COMPUTE_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.CS                    = this->CS;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER : public ID3DX12PipelineParserCallbacks\n{\n    CD3DX12_PIPELINE_STATE_STREAM2 PipelineStream;\n    CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER() noexcept\n        : SeenDSS(false)\n    {\n        // Adjust defaults to account for absent members.\n        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n\n        // Depth disabled if no DSV format specified.\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;\n    }\n\n    // ID3DX12PipelineParserCallbacks\n    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}\n    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}\n    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}\n    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}\n    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}\n    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}\n    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}\n    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}\n    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}\n    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}\n    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}\n    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}\n    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}\n    void ASCb(const D3D12_SHADER_BYTECODE& AS) override {PipelineStream.AS = AS;}\n    void MSCb(const D3D12_SHADER_BYTECODE& MS) override {PipelineStream.MS = MS;}\n    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}\n    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DSVFormatCb(DXGI_FORMAT DSVFormat) override\n    {\n        PipelineStream.DSVFormat = DSVFormat;\n        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)\n        {\n            // Re-enable depth for the default state.\n            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;\n        }\n    }\n    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}\n    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}\n    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}\n    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}\n    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}\n    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}\n\nprivate:\n    bool SeenDSS;\n};\n#endif // NTDDI_WIN10_VB\n\nstruct CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER : public ID3DX12PipelineParserCallbacks\n{\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n    CD3DX12_PIPELINE_STATE_STREAM1 PipelineStream;\n#else\n    CD3DX12_PIPELINE_STATE_STREAM PipelineStream;\n#endif\n    CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER() noexcept\n        : SeenDSS(false)\n    {\n        // Adjust defaults to account for absent members.\n        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n\n        // Depth disabled if no DSV format specified.\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;\n    }\n\n    // ID3DX12PipelineParserCallbacks\n    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}\n    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}\n    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}\n    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}\n    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}\n    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}\n    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}\n    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}\n    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}\n    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}\n    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}\n    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}\n    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}\n    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}\n    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DSVFormatCb(DXGI_FORMAT DSVFormat) override\n    {\n        PipelineStream.DSVFormat = DSVFormat;\n        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)\n        {\n            // Re-enable depth for the default state.\n            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;\n        }\n    }\n    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}\n    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}\n    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}\n    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}\n#endif\n    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}\n\nprivate:\n    bool SeenDSS;\n};\n\ninline D3D12_PIPELINE_STATE_SUBOBJECT_TYPE D3DX12GetBaseSubobjectType(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE SubobjectType) noexcept\n{\n    switch (SubobjectType)\n    {\n    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:\n        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;\n    default:\n        return SubobjectType;\n    }\n}\n\ninline HRESULT D3DX12ParsePipelineStream(const D3D12_PIPELINE_STATE_STREAM_DESC& Desc, ID3DX12PipelineParserCallbacks* pCallbacks)\n{\n    if (pCallbacks == nullptr)\n    {\n        return E_INVALIDARG;\n    }\n\n    if (Desc.SizeInBytes == 0 || Desc.pPipelineStateSubobjectStream == nullptr)\n    {\n        pCallbacks->ErrorBadInputParameter(1); // first parameter issue\n        return E_INVALIDARG;\n    }\n\n    bool SubobjectSeen[D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID] = {};\n    for (SIZE_T CurOffset = 0, SizeOfSubobject = 0; CurOffset < Desc.SizeInBytes; CurOffset += SizeOfSubobject)\n    {\n        BYTE* pStream = static_cast<BYTE*>(Desc.pPipelineStateSubobjectStream)+CurOffset;\n        auto SubobjectType = *reinterpret_cast<D3D12_PIPELINE_STATE_SUBOBJECT_TYPE*>(pStream);\n        if (SubobjectType < 0 || SubobjectType >= D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID)\n        {\n            pCallbacks->ErrorUnknownSubobject(SubobjectType);\n            return E_INVALIDARG;\n        }\n        if (SubobjectSeen[D3DX12GetBaseSubobjectType(SubobjectType)])\n        {\n            pCallbacks->ErrorDuplicateSubobject(SubobjectType);\n            return E_INVALIDARG; // disallow subobject duplicates in a stream\n        }\n        SubobjectSeen[SubobjectType] = true;\n        switch (SubobjectType)\n        {\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE:\n            pCallbacks->RootSignatureCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS:\n            pCallbacks->VSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::VS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::VS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS:\n            pCallbacks->PSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS:\n            pCallbacks->DSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS:\n            pCallbacks->HSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::HS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::HS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS:\n            pCallbacks->GSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::GS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::GS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS:\n            pCallbacks->CSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CS);\n            break;\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS:\n            pCallbacks->ASCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::AS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::AS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS:\n            pCallbacks->MSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::MS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::MS);\n            break;\n#endif\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT:\n            pCallbacks->StreamOutputCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND:\n            pCallbacks->BlendStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::BlendState)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::BlendState);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK:\n            pCallbacks->SampleMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleMask)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleMask);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER:\n            pCallbacks->RasterizerStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL:\n            pCallbacks->DepthStencilStateCb(*reinterpret_cast<CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:\n            pCallbacks->DepthStencilState1Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT:\n            pCallbacks->InputLayoutCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::InputLayout)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::InputLayout);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE:\n            pCallbacks->IBStripCutValueCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY:\n            pCallbacks->PrimitiveTopologyTypeCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS:\n            pCallbacks->RTVFormatsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT:\n            pCallbacks->DSVFormatCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC:\n            pCallbacks->SampleDescCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK:\n            pCallbacks->NodeMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::NodeMask)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::NodeMask);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO:\n            pCallbacks->CachedPSOCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS:\n            pCallbacks->FlagsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::Flags)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::Flags);\n            break;\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING:\n            pCallbacks->ViewInstancingCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc);\n            break;\n#endif\n        default:\n            pCallbacks->ErrorUnknownSubobject(SubobjectType);\n            return E_INVALIDARG;\n        }\n    }\n\n    return S_OK;\n}\n#endif // NTDDI_WIN10_RS2\n\n// Requires the Windows 10 October 2018 Update SDK (17763)\n#if defined(NTDDI_WIN10_RS5) && (NTDDI_VERSION >= NTDDI_WIN10_RS5)\n//------------------------------------------------------------------------------------------------\ninline bool operator==( const D3D12_CLEAR_VALUE &a, const D3D12_CLEAR_VALUE &b) noexcept\n{\n    if (a.Format != b.Format) return false;\n    if (a.Format == DXGI_FORMAT_D24_UNORM_S8_UINT\n     || a.Format == DXGI_FORMAT_D16_UNORM\n     || a.Format == DXGI_FORMAT_D32_FLOAT\n     || a.Format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT)\n    {\n        return (a.DepthStencil.Depth == b.DepthStencil.Depth) &&\n          (a.DepthStencil.Stencil == b.DepthStencil.Stencil);\n    } else {\n        return (a.Color[0] == b.Color[0]) &&\n               (a.Color[1] == b.Color[1]) &&\n               (a.Color[2] == b.Color[2]) &&\n               (a.Color[3] == b.Color[3]);\n    }\n}\ninline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &b) noexcept\n{\n    return a.ClearValue == b.ClearValue;\n}\ninline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &a, const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &b) noexcept\n{\n    if (a.pSrcResource != b.pSrcResource) return false;\n    if (a.pDstResource != b.pDstResource) return false;\n    if (a.SubresourceCount != b.SubresourceCount) return false;\n    if (a.Format != b.Format) return false;\n    if (a.ResolveMode != b.ResolveMode) return false;\n    if (a.PreserveResolveSource != b.PreserveResolveSource) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS &b) noexcept\n{\n    if (a.Type != b.Type) return false;\n    if (a.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR && !(a.Clear == b.Clear)) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS &a, const D3D12_RENDER_PASS_ENDING_ACCESS &b) noexcept\n{\n    if (a.Type != b.Type) return false;\n    if (a.Type == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE && !(a.Resolve == b.Resolve)) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_RENDER_TARGET_DESC &a, const D3D12_RENDER_PASS_RENDER_TARGET_DESC &b) noexcept\n{\n    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;\n    if (!(a.BeginningAccess == b.BeginningAccess)) return false;\n    if (!(a.EndingAccess == b.EndingAccess)) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &a, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &b) noexcept\n{\n    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;\n    if (!(a.DepthBeginningAccess == b.DepthBeginningAccess)) return false;\n    if (!(a.StencilBeginningAccess == b.StencilBeginningAccess)) return false;\n    if (!(a.DepthEndingAccess == b.DepthEndingAccess)) return false;\n    if (!(a.StencilEndingAccess == b.StencilEndingAccess)) return false;\n    return true;\n}\n\n\n#ifndef D3DX12_NO_STATE_OBJECT_HELPERS\n\n//================================================================================================\n// D3DX12 State Object Creation Helpers\n//\n// Helper classes for creating new style state objects out of an arbitrary set of subobjects.\n// Uses STL\n//\n// Start by instantiating CD3DX12_STATE_OBJECT_DESC (see it's public methods).\n// One of its methods is CreateSubobject(), which has a comment showing a couple of options for\n// defining subobjects using the helper classes for each subobject (CD3DX12_DXIL_LIBRARY_SUBOBJECT\n// etc.). The subobject helpers each have methods specific to the subobject for configuring it's\n// contents.\n//\n//================================================================================================\n#include <list>\n#include <vector>\n#include <string>\n#include <memory>\n#include <wrl/client.h>\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_STATE_OBJECT_DESC\n{\npublic:\n    CD3DX12_STATE_OBJECT_DESC() noexcept\n    {\n        Init(D3D12_STATE_OBJECT_TYPE_COLLECTION);\n    }\n    CD3DX12_STATE_OBJECT_DESC(D3D12_STATE_OBJECT_TYPE Type) noexcept\n    {\n        Init(Type);\n    }\n    void SetStateObjectType(D3D12_STATE_OBJECT_TYPE Type) noexcept { m_Desc.Type = Type; }\n    operator const D3D12_STATE_OBJECT_DESC&()\n    {\n        // Do final preparation work\n        m_RepointedAssociations.clear();\n        m_SubobjectArray.clear();\n        m_SubobjectArray.reserve(m_Desc.NumSubobjects);\n        // Flatten subobjects into an array (each flattened subobject still has a\n        // member that's a pointer to it's desc that's not flattened)\n        for (auto Iter = m_SubobjectList.begin();\n            Iter != m_SubobjectList.end(); Iter++)\n        {\n            m_SubobjectArray.push_back(*Iter);\n            // Store new location in array so we can redirect pointers contained in subobjects\n            Iter->pSubobjectArrayLocation = &m_SubobjectArray.back();\n        }\n        // For subobjects with pointer fields, create a new copy of those subobject definitions\n        // with fixed pointers\n        for (UINT i = 0; i < m_Desc.NumSubobjects; i++)\n        {\n            if (m_SubobjectArray[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION)\n            {\n                auto pOriginalSubobjectAssociation =\n                    static_cast<const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION*>(m_SubobjectArray[i].pDesc);\n                D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION Repointed = *pOriginalSubobjectAssociation;\n                auto pWrapper =\n                    static_cast<const SUBOBJECT_WRAPPER*>(pOriginalSubobjectAssociation->pSubobjectToAssociate);\n                Repointed.pSubobjectToAssociate = pWrapper->pSubobjectArrayLocation;\n                m_RepointedAssociations.push_back(Repointed);\n                m_SubobjectArray[i].pDesc = &m_RepointedAssociations.back();\n            }\n        }\n        // Below: using ugly way to get pointer in case .data() is not defined\n        m_Desc.pSubobjects = m_Desc.NumSubobjects ? &m_SubobjectArray[0] : nullptr;\n        return m_Desc;\n    }\n    operator const D3D12_STATE_OBJECT_DESC*()\n    {\n        // Cast calls the above final preparation work\n        return &static_cast<const D3D12_STATE_OBJECT_DESC&>(*this);\n    }\n\n    // CreateSubobject creates a sububject helper (e.g. CD3DX12_HIT_GROUP_SUBOBJECT)\n    // whose lifetime is owned by this class.\n    // e.g.\n    //\n    //    CD3DX12_STATE_OBJECT_DESC Collection1(D3D12_STATE_OBJECT_TYPE_COLLECTION);\n    //    auto Lib0 = Collection1.CreateSubobject<CD3DX12_DXIL_LIBRARY_SUBOBJECT>();\n    //    Lib0->SetDXILLibrary(&pMyAppDxilLibs[0]);\n    //    Lib0->DefineExport(L\"rayGenShader0\"); // in practice these export listings might be\n    //                                          // data/engine driven\n    //    etc.\n    //\n    // Alternatively, users can instantiate sububject helpers explicitly, such as via local\n    // variables instead, passing the state object desc that should point to it into the helper\n    // constructor (or call mySubobjectHelper.AddToStateObject(Collection1)).\n    // In this alternative scenario, the user must keep the subobject alive as long as the state\n    // object it is associated with is alive, else it's pointer references will be stale.\n    // e.g.\n    //\n    //    CD3DX12_STATE_OBJECT_DESC RaytracingState2(D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE);\n    //    CD3DX12_DXIL_LIBRARY_SUBOBJECT LibA(RaytracingState2);\n    //    LibA.SetDXILLibrary(&pMyAppDxilLibs[4]); // not manually specifying exports\n    //                                             // - meaning all exports in the libraries\n    //                                             // are exported\n    //    etc.\n\n    template<typename T>\n    T* CreateSubobject()\n    {\n        T* pSubobject = new T(*this);\n        m_OwnedSubobjectHelpers.emplace_back(pSubobject);\n        return pSubobject;\n    }\n\nprivate:\n    D3D12_STATE_SUBOBJECT* TrackSubobject(D3D12_STATE_SUBOBJECT_TYPE Type, void* pDesc)\n    {\n        SUBOBJECT_WRAPPER Subobject;\n        Subobject.pSubobjectArrayLocation = nullptr;\n        Subobject.Type = Type;\n        Subobject.pDesc = pDesc;\n        m_SubobjectList.push_back(Subobject);\n        m_Desc.NumSubobjects++;\n        return &m_SubobjectList.back();\n    }\n    void Init(D3D12_STATE_OBJECT_TYPE Type) noexcept\n    {\n        SetStateObjectType(Type);\n        m_Desc.pSubobjects = nullptr;\n        m_Desc.NumSubobjects = 0;\n        m_SubobjectList.clear();\n        m_SubobjectArray.clear();\n        m_RepointedAssociations.clear();\n    }\n    typedef struct SUBOBJECT_WRAPPER : public D3D12_STATE_SUBOBJECT\n    {\n        D3D12_STATE_SUBOBJECT* pSubobjectArrayLocation; // new location when flattened into array\n                                                        // for repointing pointers in subobjects\n    } SUBOBJECT_WRAPPER;\n    D3D12_STATE_OBJECT_DESC m_Desc;\n    std::list<SUBOBJECT_WRAPPER>   m_SubobjectList; // Pointers to list nodes handed out so\n                                                    // these can be edited live\n    std::vector<D3D12_STATE_SUBOBJECT> m_SubobjectArray; // Built at the end, copying list contents\n\n    std::list<D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION>\n            m_RepointedAssociations; // subobject type that contains pointers to other subobjects,\n                                     // repointed to flattened array\n\n    class StringContainer\n    {\n    public:\n        LPCWSTR LocalCopy(LPCWSTR string, bool bSingleString = false)\n        {\n            if (string)\n            {\n                if (bSingleString)\n                {\n                    m_Strings.clear();\n                    m_Strings.push_back(string);\n                }\n                else\n                {\n                    m_Strings.push_back(string);\n                }\n                return m_Strings.back().c_str();\n            }\n            else\n            {\n                return nullptr;\n            }\n        }\n        void clear() noexcept { m_Strings.clear(); }\n    private:\n        std::list<std::wstring> m_Strings;\n    };\n\n    class SUBOBJECT_HELPER_BASE\n    {\n    public:\n        SUBOBJECT_HELPER_BASE() noexcept { Init(); }\n        virtual ~SUBOBJECT_HELPER_BASE() = default;\n        virtual D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept = 0;\n        void AddToStateObject(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n        {\n            m_pSubobject = ContainingStateObject.TrackSubobject(Type(), Data());\n        }\n    protected:\n        virtual void* Data() noexcept = 0;\n        void Init() noexcept { m_pSubobject = nullptr; }\n        D3D12_STATE_SUBOBJECT* m_pSubobject;\n    };\n\n#if(__cplusplus >= 201103L)\n    std::list<std::unique_ptr<const SUBOBJECT_HELPER_BASE>> m_OwnedSubobjectHelpers;\n#else\n    class OWNED_HELPER\n    {\n    public:\n        OWNED_HELPER(const SUBOBJECT_HELPER_BASE* pHelper) noexcept { m_pHelper = pHelper; }\n        ~OWNED_HELPER() { delete m_pHelper; }\n        const SUBOBJECT_HELPER_BASE* m_pHelper;\n    };\n\n    std::list<OWNED_HELPER> m_OwnedSubobjectHelpers;\n#endif\n\n    friend class CD3DX12_DXIL_LIBRARY_SUBOBJECT;\n    friend class CD3DX12_EXISTING_COLLECTION_SUBOBJECT;\n    friend class CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT;\n    friend class CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;\n    friend class CD3DX12_HIT_GROUP_SUBOBJECT;\n    friend class CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT;\n    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT;\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT;\n#endif\n    friend class CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT;\n    friend class CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT;\n    friend class CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT;\n    friend class CD3DX12_NODE_MASK_SUBOBJECT;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_DXIL_LIBRARY_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_DXIL_LIBRARY_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_DXIL_LIBRARY_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetDXILLibrary(const D3D12_SHADER_BYTECODE* pCode) noexcept\n    {\n        static const D3D12_SHADER_BYTECODE Default = {};\n        m_Desc.DXILLibrary = pCode ? *pCode : Default;\n    }\n    void DefineExport(\n        LPCWSTR Name,\n        LPCWSTR ExportToRename = nullptr,\n        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)\n    {\n        D3D12_EXPORT_DESC Export;\n        Export.Name = m_Strings.LocalCopy(Name);\n        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);\n        Export.Flags = Flags;\n        m_Exports.push_back(Export);\n        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined\n        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());\n    }\n    template<size_t N>\n    void DefineExports(LPCWSTR(&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    void DefineExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_DXIL_LIBRARY_DESC&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_Strings.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_DXIL_LIBRARY_DESC m_Desc;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    std::vector<D3D12_EXPORT_DESC> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_EXISTING_COLLECTION_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_EXISTING_COLLECTION_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_EXISTING_COLLECTION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetExistingCollection(ID3D12StateObject*pExistingCollection) noexcept\n    {\n        m_Desc.pExistingCollection = pExistingCollection;\n        m_CollectionRef = pExistingCollection;\n    }\n    void DefineExport(\n        LPCWSTR Name,\n        LPCWSTR ExportToRename = nullptr,\n        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)\n    {\n        D3D12_EXPORT_DESC Export;\n        Export.Name = m_Strings.LocalCopy(Name);\n        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);\n        Export.Flags = Flags;\n        m_Exports.push_back(Export);\n        m_Desc.pExports = &m_Exports[0]; // using ugly way to get pointer in case .data() is not defined\n        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());\n    }\n    template<size_t N>\n    void DefineExports(LPCWSTR(&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    void DefineExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_EXISTING_COLLECTION_DESC&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_CollectionRef = nullptr;\n        m_Strings.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_EXISTING_COLLECTION_DESC m_Desc;\n    Microsoft::WRL::ComPtr<ID3D12StateObject> m_CollectionRef;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    std::vector<D3D12_EXPORT_DESC> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetSubobjectToAssociate(const D3D12_STATE_SUBOBJECT& SubobjectToAssociate) noexcept\n    {\n        m_Desc.pSubobjectToAssociate = &SubobjectToAssociate;\n    }\n    void AddExport(LPCWSTR Export)\n    {\n        m_Desc.NumExports++;\n        m_Exports.push_back(m_Strings.LocalCopy(Export));\n        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined\n    }\n    template<size_t N>\n    void AddExports(LPCWSTR (&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    void AddExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_Strings.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    std::vector<LPCWSTR> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION() noexcept\n    {\n        Init();\n    }\n    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetSubobjectNameToAssociate(LPCWSTR SubobjectToAssociate)\n    {\n        m_Desc.SubobjectToAssociate = m_SubobjectName.LocalCopy(SubobjectToAssociate, true);\n    }\n    void AddExport(LPCWSTR Export)\n    {\n        m_Desc.NumExports++;\n        m_Exports.push_back(m_Strings.LocalCopy(Export));\n        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined\n    }\n    template<size_t N>\n    void AddExports(LPCWSTR (&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    void AddExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_Strings.clear();\n        m_SubobjectName.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_SubobjectName;\n    std::vector<LPCWSTR> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_HIT_GROUP_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_HIT_GROUP_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_HIT_GROUP_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetHitGroupExport(LPCWSTR exportName)\n    {\n        m_Desc.HitGroupExport = m_Strings[0].LocalCopy(exportName, true);\n    }\n    void SetHitGroupType(D3D12_HIT_GROUP_TYPE Type) noexcept { m_Desc.Type = Type; }\n    void SetAnyHitShaderImport(LPCWSTR importName)\n    {\n        m_Desc.AnyHitShaderImport = m_Strings[1].LocalCopy(importName, true);\n    }\n    void SetClosestHitShaderImport(LPCWSTR importName)\n    {\n        m_Desc.ClosestHitShaderImport = m_Strings[2].LocalCopy(importName, true);\n    }\n    void SetIntersectionShaderImport(LPCWSTR importName)\n    {\n        m_Desc.IntersectionShaderImport = m_Strings[3].LocalCopy(importName, true);\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_HIT_GROUP_DESC&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        for (UINT i = 0; i < m_NumStrings; i++)\n        {\n            m_Strings[i].clear();\n        }\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_HIT_GROUP_DESC m_Desc;\n    static const UINT m_NumStrings = 4;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer\n        m_Strings[m_NumStrings]; // one string for every entrypoint name\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void Config(UINT MaxPayloadSizeInBytes, UINT MaxAttributeSizeInBytes) noexcept\n    {\n        m_Desc.MaxPayloadSizeInBytes = MaxPayloadSizeInBytes;\n        m_Desc.MaxAttributeSizeInBytes = MaxAttributeSizeInBytes;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_RAYTRACING_SHADER_CONFIG&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_RAYTRACING_SHADER_CONFIG m_Desc;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void Config(UINT MaxTraceRecursionDepth) noexcept\n    {\n        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_RAYTRACING_PIPELINE_CONFIG&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_RAYTRACING_PIPELINE_CONFIG m_Desc;\n};\n\n//------------------------------------------------------------------------------------------------\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nclass CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void Config(UINT MaxTraceRecursionDepth, D3D12_RAYTRACING_PIPELINE_FLAGS Flags) noexcept\n    {\n        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;\n        m_Desc.Flags = Flags;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_RAYTRACING_PIPELINE_CONFIG1&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_RAYTRACING_PIPELINE_CONFIG1 m_Desc;\n};\n#endif // NTDDI_WIN10_VB\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept\n    {\n        m_pRootSig = pRootSig;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator ID3D12RootSignature*() const noexcept { return m_pRootSig.Get(); }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_pRootSig = nullptr;\n    }\n    void* Data() noexcept override { return m_pRootSig.GetAddressOf(); }\n    Microsoft::WRL::ComPtr<ID3D12RootSignature> m_pRootSig;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept\n    {\n        m_pRootSig = pRootSig;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator ID3D12RootSignature*() const noexcept { return m_pRootSig.Get(); }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_pRootSig = nullptr;\n    }\n    void* Data() noexcept override { return m_pRootSig.GetAddressOf(); }\n    Microsoft::WRL::ComPtr<ID3D12RootSignature> m_pRootSig;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetFlags(D3D12_STATE_OBJECT_FLAGS Flags) noexcept\n    {\n        m_Desc.Flags = Flags;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_STATE_OBJECT_CONFIG&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_STATE_OBJECT_CONFIG m_Desc;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_NODE_MASK_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_NODE_MASK_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_NODE_MASK_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetNodeMask(UINT NodeMask) noexcept\n    {\n        m_Desc.NodeMask = NodeMask;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_NODE_MASK&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_NODE_MASK m_Desc;\n};\n\n#endif // #ifndef D3DX12_NO_STATE_OBJECT_HELPERS\n#endif // NTDDI_WIN10_RS5\n\n#endif // defined( __cplusplus )\n\n#endif //__D3DX12_H__\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/json/LICENSE.MIT",
    "content": "MIT License \n\nCopyright (c) 2013-2019 Niels Lohmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/json/commit_id.txt",
    "content": "e6e6805c6c80d6ec82ba719afd435fd2280535da"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/json/documentation.txt",
    "content": "https://nlohmann.github.io/json/"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/json/json.hpp",
    "content": "#pragma once\n\n/*\n\t__ _____ _____ _____\n __|  |   __|     |   | |  JSON for Modern C++\n|  |  |__   |  |  | | | |  version 3.6.1\n|_____|_____|_____|_|___|  https://github.com/nlohmann/json\n\nLicensed under the MIT License <http://opensource.org/licenses/MIT>.\nSPDX-License-Identifier: MIT\nCopyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.\n\nPermission is hereby  granted, free of charge, to any  person obtaining a copy\nof this software and associated  documentation files (the \"Software\"), to deal\nin the Software  without restriction, including without  limitation the rights\nto  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell\ncopies  of  the Software,  and  to  permit persons  to  whom  the Software  is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE  IS PROVIDED \"AS  IS\", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR\nIMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,\nFITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE\nAUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER\nLIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#ifndef INCLUDE_NLOHMANN_JSON_HPP_\n#define INCLUDE_NLOHMANN_JSON_HPP_\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3\n#define NLOHMANN_JSON_VERSION_MINOR 6\n#define NLOHMANN_JSON_VERSION_PATCH 1\n\n#include <algorithm> // all_of, find, for_each\n#include <cassert> // assert\n#include <ciso646> // and, not, or\n#include <cstddef> // nullptr_t, ptrdiff_t, size_t\n#include <functional> // hash, less\n#include <initializer_list> // initializer_list\n#include <iosfwd> // istream, ostream\n#include <iterator> // random_access_iterator_tag\n#include <memory> // unique_ptr\n#include <numeric> // accumulate\n#include <string> // string, stoi, to_string\n#include <utility> // declval, forward, move, pair, swap\n#include <vector> // vector\n\n// #include <nlohmann/adl_serializer.hpp>\n\n\n#include <utility>\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n\n#include <algorithm> // transform\n#include <array> // array\n#include <ciso646> // and, not\n#include <forward_list> // forward_list\n#include <iterator> // inserter, front_inserter, end\n#include <map> // map\n#include <string> // string\n#include <tuple> // tuple, make_tuple\n#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible\n#include <unordered_map> // unordered_map\n#include <utility> // pair, declval\n#include <valarray> // valarray\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n\n#include <exception> // exception\n#include <stdexcept> // runtime_error\n#include <string> // to_string\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n\n#include <cstddef> // size_t\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t/// struct to capture the start position of the current token\n\t\tstruct position_t\n\t\t{\n\t\t\t/// the total number of characters read\n\t\t\tstd::size_t chars_read_total = 0;\n\t\t\t/// the number of characters read in the current line\n\t\t\tstd::size_t chars_read_current_line = 0;\n\t\t\t/// the number of lines read\n\t\t\tstd::size_t lines_read = 0;\n\n\t\t\t/// conversion to size_t to preserve SAX interface\n\t\t\tconstexpr operator size_t() const\n\t\t\t{\n\t\t\t\treturn chars_read_total;\n\t\t\t}\n\t\t};\n\n\t} // namespace detail\n} // namespace nlohmann\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t////////////////\n\t\t// exceptions //\n\t\t////////////////\n\n\t\t/*!\n\t\t@brief general exception of the @ref basic_json class\n\n\t\tThis class is an extension of `std::exception` objects with a member @a id for\n\t\texception ids. It is used as the base class for all exceptions thrown by the\n\t\t@ref basic_json class. This class can hence be used as \"wildcard\" to catch\n\t\texceptions.\n\n\t\tSubclasses:\n\t\t- @ref parse_error for exceptions indicating a parse error\n\t\t- @ref invalid_iterator for exceptions indicating errors with iterators\n\t\t- @ref type_error for exceptions indicating executing a member function with\n\t\t\t\t\t\t  a wrong type\n\t\t- @ref out_of_range for exceptions indicating access out of the defined range\n\t\t- @ref other_error for exceptions indicating other library errors\n\n\t\t@internal\n\t\t@note To have nothrow-copy-constructible exceptions, we internally use\n\t\t\t  `std::runtime_error` which can cope with arbitrary-length error messages.\n\t\t\t  Intermediate strings are built with static functions and then passed to\n\t\t\t  the actual constructor.\n\t\t@endinternal\n\n\t\t@liveexample{The following code shows how arbitrary library exceptions can be\n\t\tcaught.,exception}\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tclass exception : public std::exception\n\t\t{\n\t\tpublic:\n\t\t\t/// returns the explanatory string\n\t\t\tconst char* what() const noexcept override\n\t\t\t{\n\t\t\t\treturn m.what();\n\t\t\t}\n\n\t\t\t/// the id of the exception\n\t\t\tconst int id;\n\n\t\tprotected:\n\t\t\texception(int id_, const char* what_arg) : id(id_), m(what_arg) {}\n\n\t\t\tstatic std::string name(const std::string& ename, int id_)\n\t\t\t{\n\t\t\t\treturn \"[json.exception.\" + ename + \".\" + std::to_string(id_) + \"] \";\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// an exception object as storage for error messages\n\t\t\tstd::runtime_error m;\n\t\t};\n\n\t\t/*!\n\t\t@brief exception indicating a parse error\n\n\t\tThis exception is thrown by the library when a parse error occurs. Parse errors\n\t\tcan occur during the deserialization of JSON text, CBOR, MessagePack, as well\n\t\tas when using JSON Patch.\n\n\t\tMember @a byte holds the byte index of the last read character in the input\n\t\tfile.\n\n\t\tExceptions have ids 1xx.\n\n\t\tname / id                      | example message | description\n\t\t------------------------------ | --------------- | -------------------------\n\t\tjson.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.\n\t\tjson.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\\uxxxx` entries (\"surrogate pairs\"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.\n\t\tjson.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.\n\t\tjson.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.\n\t\tjson.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one \"op\" member, whose value indicates the operation to perform. Its value must be one of \"add\", \"remove\", \"replace\", \"move\", \"copy\", or \"test\"; other values are errors.\n\t\tjson.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.\n\t\tjson.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.\n\t\tjson.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.\n\t\tjson.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.\n\t\tjson.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.\n\t\tjson.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.\n\t\tjson.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.\n\t\tjson.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).\n\n\t\t@note For an input with n bytes, 1 is the index of the first character and n+1\n\t\t\t  is the index of the terminating null byte or the end of file. This also\n\t\t\t  holds true when reading a byte vector (CBOR or MessagePack).\n\n\t\t@liveexample{The following code shows how a `parse_error` exception can be\n\t\tcaught.,parse_error}\n\n\t\t@sa - @ref exception for the base class of the library exceptions\n\t\t@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n\t\t@sa - @ref type_error for exceptions indicating executing a member function with\n\t\t\t\t\t\t\ta wrong type\n\t\t@sa - @ref out_of_range for exceptions indicating access out of the defined range\n\t\t@sa - @ref other_error for exceptions indicating other library errors\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tclass parse_error : public exception\n\t\t{\n\t\tpublic:\n\t\t\t/*!\n\t\t\t@brief create a parse error exception\n\t\t\t@param[in] id_       the id of the exception\n\t\t\t@param[in] pos       the position where the error occurred (or with\n\t\t\t\t\t\t\t\t chars_read_total=0 if the position cannot be\n\t\t\t\t\t\t\t\t determined)\n\t\t\t@param[in] what_arg  the explanatory string\n\t\t\t@return parse_error object\n\t\t\t*/\n\t\t\tstatic parse_error create(int id_, const position_t& pos, const std::string& what_arg)\n\t\t\t{\n\t\t\t\tstd::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n\t\t\t\t\tposition_string(pos) + \": \" + what_arg;\n\t\t\t\treturn parse_error(id_, pos.chars_read_total, w.c_str());\n\t\t\t}\n\n\t\t\tstatic parse_error create(int id_, std::size_t byte_, const std::string& what_arg)\n\t\t\t{\n\t\t\t\tstd::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n\t\t\t\t\t(byte_ != 0 ? (\" at byte \" + std::to_string(byte_)) : \"\") +\n\t\t\t\t\t\": \" + what_arg;\n\t\t\t\treturn parse_error(id_, byte_, w.c_str());\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief byte index of the parse error\n\n\t\t\tThe byte index of the last read character in the input file.\n\n\t\t\t@note For an input with n bytes, 1 is the index of the first character and\n\t\t\t\t  n+1 is the index of the terminating null byte or the end of file.\n\t\t\t\t  This also holds true when reading a byte vector (CBOR or MessagePack).\n\t\t\t*/\n\t\t\tconst std::size_t byte;\n\n\t\tprivate:\n\t\t\tparse_error(int id_, std::size_t byte_, const char* what_arg)\n\t\t\t\t: exception(id_, what_arg), byte(byte_) {}\n\n\t\t\tstatic std::string position_string(const position_t& pos)\n\t\t\t{\n\t\t\t\treturn \" at line \" + std::to_string(pos.lines_read + 1) +\n\t\t\t\t\t\", column \" + std::to_string(pos.chars_read_current_line);\n\t\t\t}\n\t\t};\n\n\t\t/*!\n\t\t@brief exception indicating errors with iterators\n\n\t\tThis exception is thrown if iterators passed to a library function do not match\n\t\tthe expected semantics.\n\n\t\tExceptions have ids 2xx.\n\n\t\tname / id                           | example message | description\n\t\t----------------------------------- | --------------- | -------------------------\n\t\tjson.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\n\t\tjson.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.\n\t\tjson.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.\n\t\tjson.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.\n\t\tjson.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.\n\t\tjson.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.\n\t\tjson.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.\n\t\tjson.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\n\t\tjson.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\n\t\tjson.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\n\t\tjson.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.\n\t\tjson.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.\n\t\tjson.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.\n\t\tjson.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().\n\n\t\t@liveexample{The following code shows how an `invalid_iterator` exception can be\n\t\tcaught.,invalid_iterator}\n\n\t\t@sa - @ref exception for the base class of the library exceptions\n\t\t@sa - @ref parse_error for exceptions indicating a parse error\n\t\t@sa - @ref type_error for exceptions indicating executing a member function with\n\t\t\t\t\t\t\ta wrong type\n\t\t@sa - @ref out_of_range for exceptions indicating access out of the defined range\n\t\t@sa - @ref other_error for exceptions indicating other library errors\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tclass invalid_iterator : public exception\n\t\t{\n\t\tpublic:\n\t\t\tstatic invalid_iterator create(int id_, const std::string& what_arg)\n\t\t\t{\n\t\t\t\tstd::string w = exception::name(\"invalid_iterator\", id_) + what_arg;\n\t\t\t\treturn invalid_iterator(id_, w.c_str());\n\t\t\t}\n\n\t\tprivate:\n\t\t\tinvalid_iterator(int id_, const char* what_arg)\n\t\t\t\t: exception(id_, what_arg) {}\n\t\t};\n\n\t\t/*!\n\t\t@brief exception indicating executing a member function with a wrong type\n\n\t\tThis exception is thrown in case of a type error; that is, a library function is\n\t\texecuted on a JSON value whose type does not match the expected semantics.\n\n\t\tExceptions have ids 3xx.\n\n\t\tname / id                     | example message | description\n\t\t----------------------------- | --------------- | -------------------------\n\t\tjson.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.\n\t\tjson.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.\n\t\tjson.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &.\n\t\tjson.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.\n\t\tjson.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.\n\t\tjson.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.\n\t\tjson.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.\n\t\tjson.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.\n\t\tjson.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |\n\t\tjson.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |\n\n\t\t@liveexample{The following code shows how a `type_error` exception can be\n\t\tcaught.,type_error}\n\n\t\t@sa - @ref exception for the base class of the library exceptions\n\t\t@sa - @ref parse_error for exceptions indicating a parse error\n\t\t@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n\t\t@sa - @ref out_of_range for exceptions indicating access out of the defined range\n\t\t@sa - @ref other_error for exceptions indicating other library errors\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tclass type_error : public exception\n\t\t{\n\t\tpublic:\n\t\t\tstatic type_error create(int id_, const std::string& what_arg)\n\t\t\t{\n\t\t\t\tstd::string w = exception::name(\"type_error\", id_) + what_arg;\n\t\t\t\treturn type_error(id_, w.c_str());\n\t\t\t}\n\n\t\tprivate:\n\t\t\ttype_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n\t\t};\n\n\t\t/*!\n\t\t@brief exception indicating access out of the defined range\n\n\t\tThis exception is thrown in case a library function is called on an input\n\t\tparameter that exceeds the expected range, for instance in case of array\n\t\tindices or nonexisting object keys.\n\n\t\tExceptions have ids 4xx.\n\n\t\tname / id                       | example message | description\n\t\t------------------------------- | --------------- | -------------------------\n\t\tjson.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.\n\t\tjson.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.\n\t\tjson.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.\n\t\tjson.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.\n\t\tjson.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.\n\t\tjson.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.\n\t\tjson.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. |\n\t\tjson.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |\n\t\tjson.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |\n\n\t\t@liveexample{The following code shows how an `out_of_range` exception can be\n\t\tcaught.,out_of_range}\n\n\t\t@sa - @ref exception for the base class of the library exceptions\n\t\t@sa - @ref parse_error for exceptions indicating a parse error\n\t\t@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n\t\t@sa - @ref type_error for exceptions indicating executing a member function with\n\t\t\t\t\t\t\ta wrong type\n\t\t@sa - @ref other_error for exceptions indicating other library errors\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tclass out_of_range : public exception\n\t\t{\n\t\tpublic:\n\t\t\tstatic out_of_range create(int id_, const std::string& what_arg)\n\t\t\t{\n\t\t\t\tstd::string w = exception::name(\"out_of_range\", id_) + what_arg;\n\t\t\t\treturn out_of_range(id_, w.c_str());\n\t\t\t}\n\n\t\tprivate:\n\t\t\tout_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}\n\t\t};\n\n\t\t/*!\n\t\t@brief exception indicating other library errors\n\n\t\tThis exception is thrown in case of errors that cannot be classified with the\n\t\tother exception types.\n\n\t\tExceptions have ids 5xx.\n\n\t\tname / id                      | example message | description\n\t\t------------------------------ | --------------- | -------------------------\n\t\tjson.exception.other_error.501 | unsuccessful: {\"op\":\"test\",\"path\":\"/baz\", \"value\":\"bar\"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.\n\n\t\t@sa - @ref exception for the base class of the library exceptions\n\t\t@sa - @ref parse_error for exceptions indicating a parse error\n\t\t@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n\t\t@sa - @ref type_error for exceptions indicating executing a member function with\n\t\t\t\t\t\t\ta wrong type\n\t\t@sa - @ref out_of_range for exceptions indicating access out of the defined range\n\n\t\t@liveexample{The following code shows how an `other_error` exception can be\n\t\tcaught.,other_error}\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tclass other_error : public exception\n\t\t{\n\t\tpublic:\n\t\t\tstatic other_error create(int id_, const std::string& what_arg)\n\t\t\t{\n\t\t\t\tstd::string w = exception::name(\"other_error\", id_) + what_arg;\n\t\t\t\treturn other_error(id_, w.c_str());\n\t\t\t}\n\n\t\tprivate:\n\t\t\tother_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\n#include <utility> // pair\n\n// This file contains all internal macro definitions\n// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them\n\n// exclude unsupported compilers\n#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)\n#if defined(__clang__)\n#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400\n#error \"unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers\"\n#endif\n#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))\n#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800\n#error \"unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers\"\n#endif\n#endif\n#endif\n\n// C++ language standard detection\n#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464\n#define JSON_HAS_CPP_17\n#define JSON_HAS_CPP_14\n#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)\n#define JSON_HAS_CPP_14\n#endif\n\n// disable float-equal warnings on GCC/clang\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n\n// disable documentation warnings on clang\n#if defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdocumentation\"\n#endif\n\n// allow for portable deprecation warnings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n#define JSON_DEPRECATED __attribute__((deprecated))\n#elif defined(_MSC_VER)\n#define JSON_DEPRECATED __declspec(deprecated)\n#else\n#define JSON_DEPRECATED\n#endif\n\n// allow for portable nodiscard warnings\n#if defined(__has_cpp_attribute)\n#if __has_cpp_attribute(nodiscard)\n#if defined(__clang__) && !defined(JSON_HAS_CPP_17) // issue #1535\n#define JSON_NODISCARD\n#else\n#define JSON_NODISCARD [[nodiscard]]\n#endif\n#elif __has_cpp_attribute(gnu::warn_unused_result)\n#define JSON_NODISCARD [[gnu::warn_unused_result]]\n#else\n#define JSON_NODISCARD\n#endif\n#else\n#define JSON_NODISCARD\n#endif\n\n// allow to disable exceptions\n#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)\n#define JSON_THROW(exception) throw exception\n#define JSON_TRY try\n#define JSON_CATCH(exception) catch(exception)\n#define JSON_INTERNAL_CATCH(exception) catch(exception)\n#else\n#include <cstdlib>\n#define JSON_THROW(exception) std::abort()\n#define JSON_TRY if(true)\n#define JSON_CATCH(exception) if(false)\n#define JSON_INTERNAL_CATCH(exception) if(false)\n#endif\n\n// override exception macros\n#if defined(JSON_THROW_USER)\n#undef JSON_THROW\n#define JSON_THROW JSON_THROW_USER\n#endif\n#if defined(JSON_TRY_USER)\n#undef JSON_TRY\n#define JSON_TRY JSON_TRY_USER\n#endif\n#if defined(JSON_CATCH_USER)\n#undef JSON_CATCH\n#define JSON_CATCH JSON_CATCH_USER\n#undef JSON_INTERNAL_CATCH\n#define JSON_INTERNAL_CATCH JSON_CATCH_USER\n#endif\n#if defined(JSON_INTERNAL_CATCH_USER)\n#undef JSON_INTERNAL_CATCH\n#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER\n#endif\n\n// manual branch prediction\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n#define JSON_LIKELY(x)      __builtin_expect(x, 1)\n#define JSON_UNLIKELY(x)    __builtin_expect(x, 0)\n#else\n#define JSON_LIKELY(x)      x\n#define JSON_UNLIKELY(x)    x\n#endif\n\n/*!\n@brief macro to briefly define a mapping between an enum and JSON\n@def NLOHMANN_JSON_SERIALIZE_ENUM\n@since version 3.4.0\n*/\n#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                           \\\n    template<typename BasicJsonType>                                                           \\\n    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                  \\\n    {                                                                                          \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");         \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                    \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                     \\\n                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                      \\\n            return ej_pair.first == e;                                                         \\\n        });                                                                                    \\\n        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                \\\n    }                                                                                          \\\n    template<typename BasicJsonType>                                                           \\\n    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                \\\n    {                                                                                          \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");         \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                    \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                     \\\n                               [j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                      \\\n            return ej_pair.second == j;                                                        \\\n        });                                                                                    \\\n        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                 \\\n    }\n\n// Ugly macros to avoid uglier copy-paste when specializing basic_json. They\n// may be removed in the future once the class is split.\n\n#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \\\n    template<template<typename, typename, typename...> class ObjectType,   \\\n             template<typename, typename...> class ArrayType,              \\\n             class StringType, class BooleanType, class NumberIntegerType, \\\n             class NumberUnsignedType, class NumberFloatType,              \\\n             template<typename> class AllocatorType,                       \\\n             template<typename, typename = void> class JSONSerializer>\n\n#define NLOHMANN_BASIC_JSON_TPL                                            \\\n    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \\\n    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \\\n    AllocatorType, JSONSerializer>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\n#include <ciso646> // not\n#include <cstddef> // size_t\n#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t// alias templates to reduce boilerplate\n\t\ttemplate<bool B, typename T = void>\n\t\tusing enable_if_t = typename std::enable_if<B, T>::type;\n\n\t\ttemplate<typename T>\n\t\tusing uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n\t\t// implementation of C++14 index_sequence and affiliates\n\t\t// source: https://stackoverflow.com/a/32223343\n\t\ttemplate<std::size_t... Ints>\n\t\tstruct index_sequence\n\t\t{\n\t\t\tusing type = index_sequence;\n\t\t\tusing value_type = std::size_t;\n\t\t\tstatic constexpr std::size_t size() noexcept\n\t\t\t{\n\t\t\t\treturn sizeof...(Ints);\n\t\t\t}\n\t\t};\n\n\t\ttemplate<class Sequence1, class Sequence2>\n\t\tstruct merge_and_renumber;\n\n\t\ttemplate<std::size_t... I1, std::size_t... I2>\n\t\tstruct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>\n\t\t\t: index_sequence < I1..., (sizeof...(I1) + I2)... > {};\n\n\t\ttemplate<std::size_t N>\n\t\tstruct make_index_sequence\n\t\t\t: merge_and_renumber < typename make_index_sequence < N / 2 >::type,\n\t\t\ttypename make_index_sequence < N - N / 2 >::type > {};\n\n\t\ttemplate<> struct make_index_sequence<0> : index_sequence<> {};\n\t\ttemplate<> struct make_index_sequence<1> : index_sequence<0> {};\n\n\t\ttemplate<typename... Ts>\n\t\tusing index_sequence_for = make_index_sequence<sizeof...(Ts)>;\n\n\t\t// dispatch utility (taken from ranges-v3)\n\t\ttemplate<unsigned N> struct priority_tag : priority_tag < N - 1 > {};\n\t\ttemplate<> struct priority_tag<0> {};\n\n\t\t// taken from ranges-v3\n\t\ttemplate<typename T>\n\t\tstruct static_const\n\t\t{\n\t\t\tstatic constexpr T value{};\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tconstexpr T static_const<T>::value;\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\n#include <ciso646> // not\n#include <limits> // numeric_limits\n#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type\n#include <utility> // declval\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n\n#include <iterator> // random_access_iterator_tag\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\ttemplate <typename ...Ts> struct make_void\n\t\t{\n\t\t\tusing type = void;\n\t\t};\n\t\ttemplate <typename ...Ts> using void_t = typename make_void<Ts...>::type;\n\t} // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\ttemplate <typename It, typename = void>\n\t\tstruct iterator_types {};\n\n\t\ttemplate <typename It>\n\t\tstruct iterator_types <\n\t\t\tIt,\n\t\t\tvoid_t<typename It::difference_type, typename It::value_type, typename It::pointer,\n\t\t\ttypename It::reference, typename It::iterator_category >>\n\t\t{\n\t\t\tusing difference_type = typename It::difference_type;\n\t\t\tusing value_type = typename It::value_type;\n\t\t\tusing pointer = typename It::pointer;\n\t\t\tusing reference = typename It::reference;\n\t\t\tusing iterator_category = typename It::iterator_category;\n\t\t};\n\n\t\t// This is required as some compilers implement std::iterator_traits in a way that\n\t\t// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.\n\t\ttemplate <typename T, typename = void>\n\t\tstruct iterator_traits\n\t\t{\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>\n\t\t\t: iterator_types<T>\n\t\t{\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>\n\t\t{\n\t\t\tusing iterator_category = std::random_access_iterator_tag;\n\t\t\tusing value_type = T;\n\t\t\tusing difference_type = ptrdiff_t;\n\t\t\tusing pointer = T * ;\n\t\t\tusing reference = T & ;\n\t\t};\n\t} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n\n#include <type_traits>\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\n// http://en.cppreference.com/w/cpp/experimental/is_detected\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\tstruct nonesuch\n\t\t{\n\t\t\tnonesuch() = delete;\n\t\t\t~nonesuch() = delete;\n\t\t\tnonesuch(nonesuch const&) = delete;\n\t\t\tnonesuch(nonesuch const&&) = delete;\n\t\t\tvoid operator=(nonesuch const&) = delete;\n\t\t\tvoid operator=(nonesuch&&) = delete;\n\t\t};\n\n\t\ttemplate <class Default,\n\t\t\tclass AlwaysVoid,\n\t\t\ttemplate <class...> class Op,\n\t\t\tclass... Args>\n\t\t\tstruct detector\n\t\t{\n\t\t\tusing value_t = std::false_type;\n\t\t\tusing type = Default;\n\t\t};\n\n\t\ttemplate <class Default, template <class...> class Op, class... Args>\n\t\tstruct detector<Default, void_t<Op<Args...>>, Op, Args...>\n\t\t{\n\t\t\tusing value_t = std::true_type;\n\t\t\tusing type = Op<Args...>;\n\t\t};\n\n\t\ttemplate <template <class...> class Op, class... Args>\n\t\tusing is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;\n\n\t\ttemplate <template <class...> class Op, class... Args>\n\t\tusing detected_t = typename detector<nonesuch, void, Op, Args...>::type;\n\n\t\ttemplate <class Default, template <class...> class Op, class... Args>\n\t\tusing detected_or = detector<Default, void, Op, Args...>;\n\n\t\ttemplate <class Default, template <class...> class Op, class... Args>\n\t\tusing detected_or_t = typename detected_or<Default, Op, Args...>::type;\n\n\t\ttemplate <class Expected, template <class...> class Op, class... Args>\n\t\tusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\n\t\ttemplate <class To, template <class...> class Op, class... Args>\n\t\tusing is_detected_convertible =\n\t\t\tstd::is_convertible<detected_t<Op, Args...>, To>;\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/json_fwd.hpp>\n#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_\n#define INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n\t/*!\n\t@brief default JSONSerializer template argument\n\n\tThis serializer ignores the template arguments and uses ADL\n\t([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\n\tfor serialization.\n\t*/\n\ttemplate<typename T = void, typename SFINAE = void>\n\tstruct adl_serializer;\n\n\ttemplate<template<typename U, typename V, typename... Args> class ObjectType =\n\t\tstd::map,\n\t\ttemplate<typename U, typename... Args> class ArrayType = std::vector,\n\t\tclass StringType = std::string, class BooleanType = bool,\n\t\tclass NumberIntegerType = std::int64_t,\n\t\tclass NumberUnsignedType = std::uint64_t,\n\t\tclass NumberFloatType = double,\n\t\ttemplate<typename U> class AllocatorType = std::allocator,\n\t\ttemplate<typename T, typename SFINAE = void> class JSONSerializer =\n\t\tadl_serializer>\n\t\tclass basic_json;\n\n\t/*!\n\t@brief JSON Pointer\n\n\tA JSON pointer defines a string syntax for identifying a specific value\n\twithin a JSON document. It can be used with functions `at` and\n\t`operator[]`. Furthermore, JSON pointers are the base for JSON patches.\n\n\t@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)\n\n\t@since version 2.0.0\n\t*/\n\ttemplate<typename BasicJsonType>\n\tclass json_pointer;\n\n\t/*!\n\t@brief default JSON class\n\n\tThis type is the default specialization of the @ref basic_json class which\n\tuses the standard template types.\n\n\t@since version 1.0.0\n\t*/\n\tusing json = basic_json<>;\n}  // namespace nlohmann\n\n#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n\nnamespace nlohmann\n{\n\t/*!\n\t@brief detail namespace with internal helper functions\n\n\tThis namespace collects functions that should not be exposed,\n\timplementations of some @ref basic_json methods, and meta-programming helpers.\n\n\t@since version 2.1.0\n\t*/\n\tnamespace detail\n\t{\n\t\t/////////////\n\t\t// helpers //\n\t\t/////////////\n\n\t\t// Note to maintainers:\n\t\t//\n\t\t// Every trait in this file expects a non CV-qualified type.\n\t\t// The only exceptions are in the 'aliases for detected' section\n\t\t// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))\n\t\t//\n\t\t// In this case, T has to be properly CV-qualified to constraint the function arguments\n\t\t// (e.g. to_json(BasicJsonType&, const T&))\n\n\t\ttemplate<typename> struct is_basic_json : std::false_type {};\n\n\t\tNLOHMANN_BASIC_JSON_TPL_DECLARATION\n\t\t\tstruct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};\n\n\t\t//////////////////////////\n\t\t// aliases for detected //\n\t\t//////////////////////////\n\n\t\ttemplate <typename T>\n\t\tusing mapped_type_t = typename T::mapped_type;\n\n\t\ttemplate <typename T>\n\t\tusing key_type_t = typename T::key_type;\n\n\t\ttemplate <typename T>\n\t\tusing value_type_t = typename T::value_type;\n\n\t\ttemplate <typename T>\n\t\tusing difference_type_t = typename T::difference_type;\n\n\t\ttemplate <typename T>\n\t\tusing pointer_t = typename T::pointer;\n\n\t\ttemplate <typename T>\n\t\tusing reference_t = typename T::reference;\n\n\t\ttemplate <typename T>\n\t\tusing iterator_category_t = typename T::iterator_category;\n\n\t\ttemplate <typename T>\n\t\tusing iterator_t = typename T::iterator;\n\n\t\ttemplate <typename T, typename... Args>\n\t\tusing to_json_function = decltype(T::to_json(std::declval<Args>()...));\n\n\t\ttemplate <typename T, typename... Args>\n\t\tusing from_json_function = decltype(T::from_json(std::declval<Args>()...));\n\n\t\ttemplate <typename T, typename U>\n\t\tusing get_template_function = decltype(std::declval<T>().template get<U>());\n\n\t\t// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists\n\t\ttemplate <typename BasicJsonType, typename T, typename = void>\n\t\tstruct has_from_json : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename T>\n\t\tstruct has_from_json<BasicJsonType, T,\n\t\t\tenable_if_t<not is_basic_json<T>::value>>\n\t\t{\n\t\t\tusing serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n\t\t\tstatic constexpr bool value =\n\t\t\t\tis_detected_exact<void, from_json_function, serializer,\n\t\t\t\tconst BasicJsonType&, T&>::value;\n\t\t};\n\n\t\t// This trait checks if JSONSerializer<T>::from_json(json const&) exists\n\t\t// this overload is used for non-default-constructible user-defined-types\n\t\ttemplate <typename BasicJsonType, typename T, typename = void>\n\t\tstruct has_non_default_from_json : std::false_type {};\n\n\t\ttemplate<typename BasicJsonType, typename T>\n\t\tstruct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>\n\t\t{\n\t\t\tusing serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n\t\t\tstatic constexpr bool value =\n\t\t\t\tis_detected_exact<T, from_json_function, serializer,\n\t\t\t\tconst BasicJsonType&>::value;\n\t\t};\n\n\t\t// This trait checks if BasicJsonType::json_serializer<T>::to_json exists\n\t\t// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.\n\t\ttemplate <typename BasicJsonType, typename T, typename = void>\n\t\tstruct has_to_json : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename T>\n\t\tstruct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>\n\t\t{\n\t\t\tusing serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n\t\t\tstatic constexpr bool value =\n\t\t\t\tis_detected_exact<void, to_json_function, serializer, BasicJsonType&,\n\t\t\t\tT>::value;\n\t\t};\n\n\n\t\t///////////////////\n\t\t// is_ functions //\n\t\t///////////////////\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct is_iterator_traits : std::false_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_iterator_traits<iterator_traits<T>>\n\t\t{\n\t\tprivate:\n\t\t\tusing traits = iterator_traits<T>;\n\n\t\tpublic:\n\t\t\tstatic constexpr auto value =\n\t\t\t\tis_detected<value_type_t, traits>::value &&\n\t\t\t\tis_detected<difference_type_t, traits>::value &&\n\t\t\t\tis_detected<pointer_t, traits>::value &&\n\t\t\t\tis_detected<iterator_category_t, traits>::value &&\n\t\t\t\tis_detected<reference_t, traits>::value;\n\t\t};\n\n\t\t// source: https://stackoverflow.com/a/37193089/4116453\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct is_complete_type : std::false_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleObjectType,\n\t\t\ttypename = void>\n\t\t\tstruct is_compatible_object_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleObjectType>\n\t\tstruct is_compatible_object_type_impl <\n\t\t\tBasicJsonType, CompatibleObjectType,\n\t\t\tenable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and\n\t\t\tis_detected<key_type_t, CompatibleObjectType>::value >>\n\t\t{\n\n\t\t\tusing object_t = typename BasicJsonType::object_t;\n\n\t\t\t// macOS's is_constructible does not play well with nonesuch...\n\t\t\tstatic constexpr bool value =\n\t\t\t\tstd::is_constructible<typename object_t::key_type,\n\t\t\t\ttypename CompatibleObjectType::key_type>::value and\n\t\t\t\tstd::is_constructible<typename object_t::mapped_type,\n\t\t\t\ttypename CompatibleObjectType::mapped_type>::value;\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleObjectType>\n\t\tstruct is_compatible_object_type\n\t\t\t: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleObjectType,\n\t\t\ttypename = void>\n\t\t\tstruct is_constructible_object_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleObjectType>\n\t\tstruct is_constructible_object_type_impl <\n\t\t\tBasicJsonType, ConstructibleObjectType,\n\t\t\tenable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and\n\t\t\tis_detected<key_type_t, ConstructibleObjectType>::value >>\n\t\t{\n\t\t\tusing object_t = typename BasicJsonType::object_t;\n\n\t\t\tstatic constexpr bool value =\n\t\t\t\t(std::is_default_constructible<ConstructibleObjectType>::value and\n\t\t\t\t(std::is_move_assignable<ConstructibleObjectType>::value or\n\t\t\t\t\tstd::is_copy_assignable<ConstructibleObjectType>::value) and\n\t\t\t\t\t(std::is_constructible<typename ConstructibleObjectType::key_type,\n\t\t\t\t\t\ttypename object_t::key_type>::value and\n\t\t\t\t\t\tstd::is_same <\n\t\t\t\t\t\ttypename object_t::mapped_type,\n\t\t\t\t\t\ttypename ConstructibleObjectType::mapped_type >::value)) or\n\t\t\t\t\t\t(has_from_json<BasicJsonType,\n\t\t\t\t\t\t\ttypename ConstructibleObjectType::mapped_type>::value or\n\t\t\t\t\t\t\thas_non_default_from_json <\n\t\t\t\t\t\t\tBasicJsonType,\n\t\t\t\t\t\t\ttypename ConstructibleObjectType::mapped_type >::value);\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleObjectType>\n\t\tstruct is_constructible_object_type\n\t\t\t: is_constructible_object_type_impl<BasicJsonType,\n\t\t\tConstructibleObjectType> {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleStringType,\n\t\t\ttypename = void>\n\t\t\tstruct is_compatible_string_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleStringType>\n\t\tstruct is_compatible_string_type_impl <\n\t\t\tBasicJsonType, CompatibleStringType,\n\t\t\tenable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n\t\t\tvalue_type_t, CompatibleStringType>::value >>\n\t\t{\n\t\t\tstatic constexpr auto value =\n\t\t\t\tstd::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleStringType>\n\t\tstruct is_compatible_string_type\n\t\t\t: is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleStringType,\n\t\t\ttypename = void>\n\t\t\tstruct is_constructible_string_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleStringType>\n\t\tstruct is_constructible_string_type_impl <\n\t\t\tBasicJsonType, ConstructibleStringType,\n\t\t\tenable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n\t\t\tvalue_type_t, ConstructibleStringType>::value >>\n\t\t{\n\t\t\tstatic constexpr auto value =\n\t\t\t\tstd::is_constructible<ConstructibleStringType,\n\t\t\t\ttypename BasicJsonType::string_t>::value;\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleStringType>\n\t\tstruct is_constructible_string_type\n\t\t\t: is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleArrayType, typename = void>\n\t\tstruct is_compatible_array_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleArrayType>\n\t\tstruct is_compatible_array_type_impl <\n\t\t\tBasicJsonType, CompatibleArrayType,\n\t\t\tenable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and\n\t\t\tis_detected<iterator_t, CompatibleArrayType>::value and\n\t\t\t// This is needed because json_reverse_iterator has a ::iterator type...\n\t\t\t// Therefore it is detected as a CompatibleArrayType.\n\t\t\t// The real fix would be to have an Iterable concept.\n\t\t\tnot is_iterator_traits<\n\t\t\titerator_traits<CompatibleArrayType>>::value >>\n\t\t{\n\t\t\tstatic constexpr bool value =\n\t\t\t\tstd::is_constructible<BasicJsonType,\n\t\t\t\ttypename CompatibleArrayType::value_type>::value;\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleArrayType>\n\t\tstruct is_compatible_array_type\n\t\t\t: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleArrayType, typename = void>\n\t\tstruct is_constructible_array_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleArrayType>\n\t\tstruct is_constructible_array_type_impl <\n\t\t\tBasicJsonType, ConstructibleArrayType,\n\t\t\tenable_if_t<std::is_same<ConstructibleArrayType,\n\t\t\ttypename BasicJsonType::value_type>::value >>\n\t\t\t: std::true_type {};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleArrayType>\n\t\tstruct is_constructible_array_type_impl <\n\t\t\tBasicJsonType, ConstructibleArrayType,\n\t\t\tenable_if_t<not std::is_same<ConstructibleArrayType,\n\t\t\ttypename BasicJsonType::value_type>::value and\n\t\t\tstd::is_default_constructible<ConstructibleArrayType>::value and\n\t\t\t(std::is_move_assignable<ConstructibleArrayType>::value or\n\t\t\t\tstd::is_copy_assignable<ConstructibleArrayType>::value) and\n\t\t\tis_detected<value_type_t, ConstructibleArrayType>::value and\n\t\t\tis_detected<iterator_t, ConstructibleArrayType>::value and\n\t\t\tis_complete_type<\n\t\t\tdetected_t<value_type_t, ConstructibleArrayType>>::value >>\n\t\t{\n\t\t\tstatic constexpr bool value =\n\t\t\t\t// This is needed because json_reverse_iterator has a ::iterator type,\n\t\t\t\t// furthermore, std::back_insert_iterator (and other iterators) have a\n\t\t\t\t// base class `iterator`... Therefore it is detected as a\n\t\t\t\t// ConstructibleArrayType. The real fix would be to have an Iterable\n\t\t\t\t// concept.\n\t\t\t\tnot is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value and\n\n\t\t\t\t(std::is_same<typename ConstructibleArrayType::value_type,\n\t\t\t\t\ttypename BasicJsonType::array_t::value_type>::value or\n\t\t\t\t\thas_from_json<BasicJsonType,\n\t\t\t\t\ttypename ConstructibleArrayType::value_type>::value or\n\t\t\t\t\thas_non_default_from_json <\n\t\t\t\t\tBasicJsonType, typename ConstructibleArrayType::value_type >::value);\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleArrayType>\n\t\tstruct is_constructible_array_type\n\t\t\t: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};\n\n\t\ttemplate <typename RealIntegerType, typename CompatibleNumberIntegerType,\n\t\t\ttypename = void>\n\t\t\tstruct is_compatible_integer_type_impl : std::false_type {};\n\n\t\ttemplate <typename RealIntegerType, typename CompatibleNumberIntegerType>\n\t\tstruct is_compatible_integer_type_impl <\n\t\t\tRealIntegerType, CompatibleNumberIntegerType,\n\t\t\tenable_if_t<std::is_integral<RealIntegerType>::value and\n\t\t\tstd::is_integral<CompatibleNumberIntegerType>::value and\n\t\t\tnot std::is_same<bool, CompatibleNumberIntegerType>::value >>\n\t\t{\n\t\t\t// is there an assert somewhere on overflows?\n\t\t\tusing RealLimits = std::numeric_limits<RealIntegerType>;\n\t\t\tusing CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;\n\n\t\t\tstatic constexpr auto value =\n\t\t\t\tstd::is_constructible<RealIntegerType,\n\t\t\t\tCompatibleNumberIntegerType>::value and\n\t\t\t\tCompatibleLimits::is_integer and\n\t\t\t\tRealLimits::is_signed == CompatibleLimits::is_signed;\n\t\t};\n\n\t\ttemplate <typename RealIntegerType, typename CompatibleNumberIntegerType>\n\t\tstruct is_compatible_integer_type\n\t\t\t: is_compatible_integer_type_impl<RealIntegerType,\n\t\t\tCompatibleNumberIntegerType> {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleType, typename = void>\n\t\tstruct is_compatible_type_impl : std::false_type {};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleType>\n\t\tstruct is_compatible_type_impl <\n\t\t\tBasicJsonType, CompatibleType,\n\t\t\tenable_if_t<is_complete_type<CompatibleType>::value >>\n\t\t{\n\t\t\tstatic constexpr bool value =\n\t\t\t\thas_to_json<BasicJsonType, CompatibleType>::value;\n\t\t};\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleType>\n\t\tstruct is_compatible_type\n\t\t\t: is_compatible_type_impl<BasicJsonType, CompatibleType> {};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\n#include <array> // array\n#include <ciso646> // and\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t\n#include <string> // string\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t///////////////////////////\n\t\t// JSON type enumeration //\n\t\t///////////////////////////\n\n\t\t/*!\n\t\t@brief the JSON type enumeration\n\n\t\tThis enumeration collects the different JSON types. It is internally used to\n\t\tdistinguish the stored values, and the functions @ref basic_json::is_null(),\n\t\t@ref basic_json::is_object(), @ref basic_json::is_array(),\n\t\t@ref basic_json::is_string(), @ref basic_json::is_boolean(),\n\t\t@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),\n\t\t@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),\n\t\t@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and\n\t\t@ref basic_json::is_structured() rely on it.\n\n\t\t@note There are three enumeration entries (number_integer, number_unsigned, and\n\t\tnumber_float), because the library distinguishes these three types for numbers:\n\t\t@ref basic_json::number_unsigned_t is used for unsigned integers,\n\t\t@ref basic_json::number_integer_t is used for signed integers, and\n\t\t@ref basic_json::number_float_t is used for floating-point numbers or to\n\t\tapproximate integers which do not fit in the limits of their respective type.\n\n\t\t@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON\n\t\tvalue with the default value for a given type\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tenum class value_t : std::uint8_t\n\t\t{\n\t\t\tnull,             ///< null value\n\t\t\tobject,           ///< object (unordered set of name/value pairs)\n\t\t\tarray,            ///< array (ordered collection of values)\n\t\t\tstring,           ///< string value\n\t\t\tboolean,          ///< boolean value\n\t\t\tnumber_integer,   ///< number value (signed integer)\n\t\t\tnumber_unsigned,  ///< number value (unsigned integer)\n\t\t\tnumber_float,     ///< number value (floating-point)\n\t\t\tdiscarded         ///< discarded by the the parser callback function\n\t\t};\n\n\t\t/*!\n\t\t@brief comparison operator for JSON types\n\n\t\tReturns an ordering that is similar to Python:\n\t\t- order: null < boolean < number < object < array < string\n\t\t- furthermore, each type is not smaller than itself\n\t\t- discarded values are not comparable\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tinline bool operator<(const value_t lhs, const value_t rhs) noexcept\n\t\t{\n\t\t\tstatic constexpr std::array<std::uint8_t, 8> order = { {\n\t\t\t\t\t0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,\n\t\t\t\t\t1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst auto l_index = static_cast<std::size_t>(lhs);\n\t\t\tconst auto r_index = static_cast<std::size_t>(rhs);\n\t\t\treturn l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];\n\t\t}\n\t}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json(const BasicJsonType& j, typename std::nullptr_t& n)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_null()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be null, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\tn = nullptr;\n\t\t}\n\n\t\t// overloads for basic_json template parameters\n\t\ttemplate<typename BasicJsonType, typename ArithmeticType,\n\t\t\tenable_if_t<std::is_arithmetic<ArithmeticType>::value and\n\t\t\tnot std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n\t\t\tint> = 0>\n\t\t\tvoid get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)\n\t\t{\n\t\t\tswitch (static_cast<value_t>(j))\n\t\t\t{\n\t\t\tcase value_t::number_unsigned:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase value_t::number_integer:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase value_t::number_float:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_boolean()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\tb = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_string()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\ts = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n\t\t}\n\n\t\ttemplate <\n\t\t\ttypename BasicJsonType, typename ConstructibleStringType,\n\t\t\tenable_if_t <\n\t\t\tis_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and\n\t\t\tnot std::is_same<typename BasicJsonType::string_t,\n\t\t\tConstructibleStringType>::value,\n\t\t\tint > = 0 >\n\t\t\tvoid from_json(const BasicJsonType& j, ConstructibleStringType& s)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_string()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n\t\t\t}\n\n\t\t\ts = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)\n\t\t{\n\t\t\tget_arithmetic_value(j, val);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)\n\t\t{\n\t\t\tget_arithmetic_value(j, val);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)\n\t\t{\n\t\t\tget_arithmetic_value(j, val);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename EnumType,\n\t\t\tenable_if_t<std::is_enum<EnumType>::value, int> = 0>\n\t\t\tvoid from_json(const BasicJsonType& j, EnumType& e)\n\t\t{\n\t\t\ttypename std::underlying_type<EnumType>::type val;\n\t\t\tget_arithmetic_value(j, val);\n\t\t\te = static_cast<EnumType>(val);\n\t\t}\n\n\t\t// forward_list doesn't have an insert method\n\t\ttemplate<typename BasicJsonType, typename T, typename Allocator,\n\t\t\tenable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>\n\t\t\tvoid from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\tl.clear();\n\t\t\tstd::transform(j.rbegin(), j.rend(),\n\t\t\t\tstd::front_inserter(l), [](const BasicJsonType & i)\n\t\t\t\t{\n\t\t\t\t\treturn i.template get<T>();\n\t\t\t\t});\n\t\t}\n\n\t\t// valarray doesn't have an insert method\n\t\ttemplate<typename BasicJsonType, typename T,\n\t\t\tenable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>\n\t\t\tvoid from_json(const BasicJsonType& j, std::valarray<T>& l)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\tl.resize(j.size());\n\t\t\tstd::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename T, std::size_t N>\n\t\tauto from_json(const BasicJsonType& j, T(&arr)[N])\n\t\t\t-> decltype(j.template get<T>(), void())\n\t\t{\n\t\t\tfor (std::size_t i = 0; i < N; ++i)\n\t\t\t{\n\t\t\t\tarr[i] = j.at(i).template get<T>();\n\t\t\t}\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)\n\t\t{\n\t\t\tarr = *j.template get_ptr<const typename BasicJsonType::array_t*>();\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename T, std::size_t N>\n\t\tauto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,\n\t\t\tpriority_tag<2> /*unused*/)\n\t\t\t-> decltype(j.template get<T>(), void())\n\t\t{\n\t\t\tfor (std::size_t i = 0; i < N; ++i)\n\t\t\t{\n\t\t\t\tarr[i] = j.at(i).template get<T>();\n\t\t\t}\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename ConstructibleArrayType>\n\t\tauto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)\n\t\t\t-> decltype(\n\t\t\t\tarr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),\n\t\t\t\tj.template get<typename ConstructibleArrayType::value_type>(),\n\t\t\t\tvoid())\n\t\t{\n\t\t\tusing std::end;\n\n\t\t\tConstructibleArrayType ret;\n\t\t\tret.reserve(j.size());\n\t\t\tstd::transform(j.begin(), j.end(),\n\t\t\t\tstd::inserter(ret, end(ret)), [](const BasicJsonType & i)\n\t\t\t\t{\n\t\t\t\t\t// get<BasicJsonType>() returns *this, this won't call a from_json\n\t\t\t\t\t// method when value_type is BasicJsonType\n\t\t\t\t\treturn i.template get<typename ConstructibleArrayType::value_type>();\n\t\t\t\t});\n\t\t\tarr = std::move(ret);\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleArrayType>\n\t\tvoid from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,\n\t\t\tpriority_tag<0> /*unused*/)\n\t\t{\n\t\t\tusing std::end;\n\n\t\t\tConstructibleArrayType ret;\n\t\t\tstd::transform(\n\t\t\t\tj.begin(), j.end(), std::inserter(ret, end(ret)),\n\t\t\t\t[](const BasicJsonType & i)\n\t\t\t\t{\n\t\t\t\t\t// get<BasicJsonType>() returns *this, this won't call a from_json\n\t\t\t\t\t// method when value_type is BasicJsonType\n\t\t\t\t\treturn i.template get<typename ConstructibleArrayType::value_type>();\n\t\t\t\t});\n\t\t\tarr = std::move(ret);\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename ConstructibleArrayType,\n\t\t\tenable_if_t <\n\t\t\tis_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and\n\t\t\tnot is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and\n\t\t\tnot is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and\n\t\t\tnot is_basic_json<ConstructibleArrayType>::value,\n\t\t\tint > = 0 >\n\n\t\t\tauto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)\n\t\t\t-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),\n\t\t\t\tj.template get<typename ConstructibleArrayType::value_type>(),\n\t\t\t\tvoid())\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" +\n\t\t\t\t\tstd::string(j.type_name())));\n\t\t\t}\n\n\t\t\tfrom_json_array_impl(j, arr, priority_tag<3> {});\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename ConstructibleObjectType,\n\t\t\tenable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>\n\t\t\tvoid from_json(const BasicJsonType& j, ConstructibleObjectType& obj)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be object, but is \" + std::string(j.type_name())));\n\t\t\t}\n\n\t\t\tConstructibleObjectType ret;\n\t\t\tauto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();\n\t\t\tusing value_type = typename ConstructibleObjectType::value_type;\n\t\t\tstd::transform(\n\t\t\t\tinner_object->begin(), inner_object->end(),\n\t\t\t\tstd::inserter(ret, ret.begin()),\n\t\t\t\t[](typename BasicJsonType::object_t::value_type const & p)\n\t\t\t\t{\n\t\t\t\t\treturn value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());\n\t\t\t\t});\n\t\t\tobj = std::move(ret);\n\t\t}\n\n\t\t// overload for arithmetic types, not chosen for basic_json template arguments\n\t\t// (BooleanType, etc..); note: Is it really necessary to provide explicit\n\t\t// overloads for boolean_t etc. in case of a custom BooleanType which is not\n\t\t// an arithmetic type?\n\t\ttemplate<typename BasicJsonType, typename ArithmeticType,\n\t\t\tenable_if_t <\n\t\t\tstd::is_arithmetic<ArithmeticType>::value and\n\t\t\tnot std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and\n\t\t\tnot std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and\n\t\t\tnot std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and\n\t\t\tnot std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n\t\t\tint> = 0>\n\t\t\tvoid from_json(const BasicJsonType& j, ArithmeticType& val)\n\t\t{\n\t\t\tswitch (static_cast<value_t>(j))\n\t\t\t{\n\t\t\tcase value_t::number_unsigned:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase value_t::number_integer:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase value_t::number_float:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase value_t::boolean:\n\t\t\t{\n\t\t\t\tval = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename A1, typename A2>\n\t\tvoid from_json(const BasicJsonType& j, std::pair<A1, A2>& p)\n\t\t{\n\t\t\tp = { j.at(0).template get<A1>(), j.at(1).template get<A2>() };\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\n\t\tvoid from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)\n\t\t{\n\t\t\tt = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename... Args>\n\t\tvoid from_json(const BasicJsonType& j, std::tuple<Args...>& t)\n\t\t{\n\t\t\tfrom_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,\n\t\t\ttypename = enable_if_t<not std::is_constructible<\n\t\t\ttypename BasicJsonType::string_t, Key>::value>>\n\t\t\tvoid from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\tm.clear();\n\t\t\tfor (const auto& p : j)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not p.is_array()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n\t\t\t\t}\n\t\t\t\tm.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,\n\t\t\ttypename = enable_if_t<not std::is_constructible<\n\t\t\ttypename BasicJsonType::string_t, Key>::value>>\n\t\t\tvoid from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not j.is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n\t\t\t}\n\t\t\tm.clear();\n\t\t\tfor (const auto& p : j)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not p.is_array()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n\t\t\t\t}\n\t\t\t\tm.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n\t\t\t}\n\t\t}\n\n\t\tstruct from_json_fn\n\t\t{\n\t\t\ttemplate<typename BasicJsonType, typename T>\n\t\t\tauto operator()(const BasicJsonType& j, T& val) const\n\t\t\t\tnoexcept(noexcept(from_json(j, val)))\n\t\t\t\t-> decltype(from_json(j, val), void())\n\t\t\t{\n\t\t\t\treturn from_json(j, val);\n\t\t\t}\n\t\t};\n\t}  // namespace detail\n\n\t/// namespace to hold default `from_json` function\n\t/// to see why this is required:\n\t/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\n\tnamespace\n\t{\n\t\tconstexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;\n\t} // namespace\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n\n#include <algorithm> // copy\n#include <ciso646> // or, and, not\n#include <iterator> // begin, end\n#include <string> // string\n#include <tuple> // tuple, get\n#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type\n#include <utility> // move, forward, declval, pair\n#include <valarray> // valarray\n#include <vector> // vector\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n\n#include <cstddef> // size_t\n#include <iterator> // input_iterator_tag\n#include <string> // string, to_string\n#include <tuple> // tuple_size, get, tuple_element\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\ttemplate <typename IteratorType> class iteration_proxy_value\n\t\t{\n\t\tpublic:\n\t\t\tusing difference_type = std::ptrdiff_t;\n\t\t\tusing value_type = iteration_proxy_value;\n\t\t\tusing pointer = value_type * ;\n\t\t\tusing reference = value_type & ;\n\t\t\tusing iterator_category = std::input_iterator_tag;\n\n\t\tprivate:\n\t\t\t/// the iterator\n\t\t\tIteratorType anchor;\n\t\t\t/// an index for arrays (used to create key names)\n\t\t\tstd::size_t array_index = 0;\n\t\t\t/// last stringified array index\n\t\t\tmutable std::size_t array_index_last = 0;\n\t\t\t/// a string representation of the array index\n\t\t\tmutable std::string array_index_str = \"0\";\n\t\t\t/// an empty string (to return a reference for primitive values)\n\t\t\tconst std::string empty_str = \"\";\n\n\t\tpublic:\n\t\t\texplicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}\n\n\t\t\t/// dereference operator (needed for range-based for)\n\t\t\titeration_proxy_value& operator*()\n\t\t\t{\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\t/// increment operator (needed for range-based for)\n\t\t\titeration_proxy_value& operator++()\n\t\t\t{\n\t\t\t\t++anchor;\n\t\t\t\t++array_index;\n\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\t/// equality operator (needed for InputIterator)\n\t\t\tbool operator==(const iteration_proxy_value& o) const\n\t\t\t{\n\t\t\t\treturn anchor == o.anchor;\n\t\t\t}\n\n\t\t\t/// inequality operator (needed for range-based for)\n\t\t\tbool operator!=(const iteration_proxy_value& o) const\n\t\t\t{\n\t\t\t\treturn anchor != o.anchor;\n\t\t\t}\n\n\t\t\t/// return key of the iterator\n\t\t\tconst std::string& key() const\n\t\t\t{\n\t\t\t\tassert(anchor.m_object != nullptr);\n\n\t\t\t\tswitch (anchor.m_object->type())\n\t\t\t\t{\n\t\t\t\t\t// use integer array index as key\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (array_index != array_index_last)\n\t\t\t\t\t{\n\t\t\t\t\t\tarray_index_str = std::to_string(array_index);\n\t\t\t\t\t\tarray_index_last = array_index;\n\t\t\t\t\t}\n\t\t\t\t\treturn array_index_str;\n\t\t\t\t}\n\n\t\t\t\t// use key from the object\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn anchor.key();\n\n\t\t\t\t\t// use an empty key for all primitive types\n\t\t\t\tdefault:\n\t\t\t\t\treturn empty_str;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// return value of the iterator\n\t\t\ttypename IteratorType::reference value() const\n\t\t\t{\n\t\t\t\treturn anchor.value();\n\t\t\t}\n\t\t};\n\n\t\t/// proxy class for the items() function\n\t\ttemplate<typename IteratorType> class iteration_proxy\n\t\t{\n\t\tprivate:\n\t\t\t/// the container to iterate\n\t\t\ttypename IteratorType::reference container;\n\n\t\tpublic:\n\t\t\t/// construct iteration proxy from a container\n\t\t\texplicit iteration_proxy(typename IteratorType::reference cont) noexcept\n\t\t\t\t: container(cont) {}\n\n\t\t\t/// return iterator begin (needed for range-based for)\n\t\t\titeration_proxy_value<IteratorType> begin() noexcept\n\t\t\t{\n\t\t\t\treturn iteration_proxy_value<IteratorType>(container.begin());\n\t\t\t}\n\n\t\t\t/// return iterator end (needed for range-based for)\n\t\t\titeration_proxy_value<IteratorType> end() noexcept\n\t\t\t{\n\t\t\t\treturn iteration_proxy_value<IteratorType>(container.end());\n\t\t\t}\n\t\t};\n\t\t// Structured Bindings Support\n\t\t// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n\t\t// And see https://github.com/nlohmann/json/pull/1391\n\t\ttemplate <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>\n\t\tauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())\n\t\t{\n\t\t\treturn i.key();\n\t\t}\n\t\t// Structured Bindings Support\n\t\t// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n\t\t// And see https://github.com/nlohmann/json/pull/1391\n\t\ttemplate <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>\n\t\tauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())\n\t\t{\n\t\t\treturn i.value();\n\t\t}\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// The Addition to the STD Namespace is required to add\n// Structured Bindings Support to the iteration_proxy_value class\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\nnamespace std\n{\n#if defined(__clang__)\n\t// Fix: https://github.com/nlohmann/json/issues/1401\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wmismatched-tags\"\n#endif\n\ttemplate <typename IteratorType>\n\tclass tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>\n\t\t: public std::integral_constant<std::size_t, 2> {};\n\n\ttemplate <std::size_t N, typename IteratorType>\n\tclass tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>\n\t{\n\tpublic:\n\t\tusing type = decltype(\n\t\t\tget<N>(std::declval <\n\t\t\t\t::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));\n\t};\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n} // namespace std\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t//////////////////\n\t\t// constructors //\n\t\t//////////////////\n\n\t\ttemplate<value_t> struct external_constructor;\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::boolean>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept\n\t\t\t{\n\t\t\t\tj.m_type = value_t::boolean;\n\t\t\t\tj.m_value = b;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::string>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::string;\n\t\t\t\tj.m_value = s;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::string;\n\t\t\t\tj.m_value = std::move(s);\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType, typename CompatibleStringType,\n\t\t\t\tenable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,\n\t\t\t\tint> = 0>\n\t\t\t\tstatic void construct(BasicJsonType& j, const CompatibleStringType& str)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::string;\n\t\t\t\tj.m_value.string = j.template create<typename BasicJsonType::string_t>(str);\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::number_float>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept\n\t\t\t{\n\t\t\t\tj.m_type = value_t::number_float;\n\t\t\t\tj.m_value = val;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::number_unsigned>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept\n\t\t\t{\n\t\t\t\tj.m_type = value_t::number_unsigned;\n\t\t\t\tj.m_value = val;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::number_integer>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept\n\t\t\t{\n\t\t\t\tj.m_type = value_t::number_integer;\n\t\t\t\tj.m_value = val;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::array>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::array;\n\t\t\t\tj.m_value = arr;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::array;\n\t\t\t\tj.m_value = std::move(arr);\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType, typename CompatibleArrayType,\n\t\t\t\tenable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,\n\t\t\t\tint> = 0>\n\t\t\t\tstatic void construct(BasicJsonType& j, const CompatibleArrayType& arr)\n\t\t\t{\n\t\t\t\tusing std::begin;\n\t\t\t\tusing std::end;\n\t\t\t\tj.m_type = value_t::array;\n\t\t\t\tj.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, const std::vector<bool>& arr)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::array;\n\t\t\t\tj.m_value = value_t::array;\n\t\t\t\tj.m_value.array->reserve(arr.size());\n\t\t\t\tfor (const bool x : arr)\n\t\t\t\t{\n\t\t\t\t\tj.m_value.array->push_back(x);\n\t\t\t\t}\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType, typename T,\n\t\t\t\tenable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n\t\t\t\tstatic void construct(BasicJsonType& j, const std::valarray<T>& arr)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::array;\n\t\t\t\tj.m_value = value_t::array;\n\t\t\t\tj.m_value.array->resize(arr.size());\n\t\t\t\tstd::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct external_constructor<value_t::object>\n\t\t{\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::object;\n\t\t\t\tj.m_value = obj;\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType>\n\t\t\tstatic void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n\t\t\t{\n\t\t\t\tj.m_type = value_t::object;\n\t\t\t\tj.m_value = std::move(obj);\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\n\t\t\ttemplate<typename BasicJsonType, typename CompatibleObjectType,\n\t\t\t\tenable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>\n\t\t\t\tstatic void construct(BasicJsonType& j, const CompatibleObjectType& obj)\n\t\t\t{\n\t\t\t\tusing std::begin;\n\t\t\t\tusing std::end;\n\n\t\t\t\tj.m_type = value_t::object;\n\t\t\t\tj.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));\n\t\t\t\tj.assert_invariant();\n\t\t\t}\n\t\t};\n\n\t\t/////////////\n\t\t// to_json //\n\t\t/////////////\n\n\t\ttemplate<typename BasicJsonType, typename T,\n\t\t\tenable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, T b) noexcept\n\t\t{\n\t\t\texternal_constructor<value_t::boolean>::construct(j, b);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename CompatibleString,\n\t\t\tenable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, const CompatibleString& s)\n\t\t{\n\t\t\texternal_constructor<value_t::string>::construct(j, s);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n\t\t{\n\t\t\texternal_constructor<value_t::string>::construct(j, std::move(s));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename FloatType,\n\t\t\tenable_if_t<std::is_floating_point<FloatType>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, FloatType val) noexcept\n\t\t{\n\t\t\texternal_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename CompatibleNumberUnsignedType,\n\t\t\tenable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept\n\t\t{\n\t\t\texternal_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename CompatibleNumberIntegerType,\n\t\t\tenable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept\n\t\t{\n\t\t\texternal_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename EnumType,\n\t\t\tenable_if_t<std::is_enum<EnumType>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, EnumType e) noexcept\n\t\t{\n\t\t\tusing underlying_type = typename std::underlying_type<EnumType>::type;\n\t\t\texternal_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid to_json(BasicJsonType& j, const std::vector<bool>& e)\n\t\t{\n\t\t\texternal_constructor<value_t::array>::construct(j, e);\n\t\t}\n\n\t\ttemplate <typename BasicJsonType, typename CompatibleArrayType,\n\t\t\tenable_if_t<is_compatible_array_type<BasicJsonType,\n\t\t\tCompatibleArrayType>::value and\n\t\t\tnot is_compatible_object_type<\n\t\t\tBasicJsonType, CompatibleArrayType>::value and\n\t\t\tnot is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and\n\t\t\tnot is_basic_json<CompatibleArrayType>::value,\n\t\t\tint> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, const CompatibleArrayType& arr)\n\t\t{\n\t\t\texternal_constructor<value_t::array>::construct(j, arr);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename T,\n\t\t\tenable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, const std::valarray<T>& arr)\n\t\t{\n\t\t\texternal_constructor<value_t::array>::construct(j, std::move(arr));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n\t\t{\n\t\t\texternal_constructor<value_t::array>::construct(j, std::move(arr));\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename CompatibleObjectType,\n\t\t\tenable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, const CompatibleObjectType& obj)\n\t\t{\n\t\t\texternal_constructor<value_t::object>::construct(j, obj);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType>\n\t\tvoid to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n\t\t{\n\t\t\texternal_constructor<value_t::object>::construct(j, std::move(obj));\n\t\t}\n\n\t\ttemplate <\n\t\t\ttypename BasicJsonType, typename T, std::size_t N,\n\t\t\tenable_if_t<not std::is_constructible<typename BasicJsonType::string_t,\n\t\t\tconst T(&)[N]>::value,\n\t\t\tint> = 0 >\n\t\t\tvoid to_json(BasicJsonType& j, const T(&arr)[N])\n\t\t{\n\t\t\texternal_constructor<value_t::array>::construct(j, arr);\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename... Args>\n\t\tvoid to_json(BasicJsonType& j, const std::pair<Args...>& p)\n\t\t{\n\t\t\tj = { p.first, p.second };\n\t\t}\n\n\t\t// for https://github.com/nlohmann/json/pull/1134\n\t\ttemplate < typename BasicJsonType, typename T,\n\t\t\tenable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>\n\t\t\tvoid to_json(BasicJsonType& j, const T& b)\n\t\t{\n\t\t\tj = { {b.key(), b.value()} };\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\n\t\tvoid to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)\n\t\t{\n\t\t\tj = { std::get<Idx>(t)... };\n\t\t}\n\n\t\ttemplate<typename BasicJsonType, typename... Args>\n\t\tvoid to_json(BasicJsonType& j, const std::tuple<Args...>& t)\n\t\t{\n\t\t\tto_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n\t\t}\n\n\t\tstruct to_json_fn\n\t\t{\n\t\t\ttemplate<typename BasicJsonType, typename T>\n\t\t\tauto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))\n\t\t\t\t-> decltype(to_json(j, std::forward<T>(val)), void())\n\t\t\t{\n\t\t\t\treturn to_json(j, std::forward<T>(val));\n\t\t\t}\n\t\t};\n\t}  // namespace detail\n\n\t/// namespace to hold default `to_json` function\n\tnamespace\n\t{\n\t\tconstexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;\n\t} // namespace\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\n\n\ttemplate<typename, typename>\n\tstruct adl_serializer\n\t{\n\t\t/*!\n\t\t@brief convert a JSON value to any value type\n\n\t\tThis function is usually called by the `get()` function of the\n\t\t@ref basic_json class (either explicit or via conversion operators).\n\n\t\t@param[in] j        JSON value to read from\n\t\t@param[in,out] val  value to write to\n\t\t*/\n\t\ttemplate<typename BasicJsonType, typename ValueType>\n\t\tstatic auto from_json(BasicJsonType&& j, ValueType& val) noexcept(\n\t\t\tnoexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))\n\t\t\t-> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())\n\t\t{\n\t\t\t::nlohmann::from_json(std::forward<BasicJsonType>(j), val);\n\t\t}\n\n\t\t/*!\n\t\t@brief convert any value type to a JSON value\n\n\t\tThis function is usually called by the constructors of the @ref basic_json\n\t\tclass.\n\n\t\t@param[in,out] j  JSON value to write to\n\t\t@param[in] val    value to read from\n\t\t*/\n\t\ttemplate <typename BasicJsonType, typename ValueType>\n\t\tstatic auto to_json(BasicJsonType& j, ValueType&& val) noexcept(\n\t\t\tnoexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))\n\t\t\t-> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), void())\n\t\t{\n\t\t\t::nlohmann::to_json(j, std::forward<ValueType>(val));\n\t\t}\n\t};\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n\n#include <algorithm> // generate_n\n#include <array> // array\n#include <cassert> // assert\n#include <cmath> // ldexp\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstdio> // snprintf\n#include <cstring> // memcpy\n#include <iterator> // back_inserter\n#include <limits> // numeric_limits\n#include <string> // char_traits, string\n#include <utility> // make_pair, move\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n\n#include <array> // array\n#include <cassert> // assert\n#include <cstddef> // size_t\n#include <cstdio> //FILE *\n#include <cstring> // strlen\n#include <istream> // istream\n#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next\n#include <memory> // shared_ptr, make_shared, addressof\n#include <numeric> // accumulate\n#include <string> // string, char_traits\n#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer\n#include <utility> // pair, declval\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t/// the supported input formats\n\t\tenum class input_format_t { json, cbor, msgpack, ubjson, bson };\n\n\t\t////////////////////\n\t\t// input adapters //\n\t\t////////////////////\n\n\t\t/*!\n\t\t@brief abstract input adapter interface\n\n\t\tProduces a stream of std::char_traits<char>::int_type characters from a\n\t\tstd::istream, a buffer, or some other input type. Accepts the return of\n\t\texactly one non-EOF character for future input. The int_type characters\n\t\treturned consist of all valid char values as positive values (typically\n\t\tunsigned char), plus an EOF value outside that range, specified by the value\n\t\tof the function std::char_traits<char>::eof(). This value is typically -1, but\n\t\tcould be any arbitrary value which is not a valid char value.\n\t\t*/\n\t\tstruct input_adapter_protocol\n\t\t{\n\t\t\t/// get a character [0,255] or std::char_traits<char>::eof().\n\t\t\tvirtual std::char_traits<char>::int_type get_character() = 0;\n\t\t\tvirtual ~input_adapter_protocol() = default;\n\t\t};\n\n\t\t/// a type to simplify interfaces\n\t\tusing input_adapter_t = std::shared_ptr<input_adapter_protocol>;\n\n\t\t/*!\n\t\tInput adapter for stdio file access. This adapter read only 1 byte and do not use any\n\t\t buffer. This adapter is a very low level adapter.\n\t\t*/\n\t\tclass file_input_adapter : public input_adapter_protocol\n\t\t{\n\t\tpublic:\n\t\t\texplicit file_input_adapter(std::FILE* f)  noexcept\n\t\t\t\t: m_file(f)\n\t\t\t{}\n\n\t\t\t// make class move-only\n\t\t\tfile_input_adapter(const file_input_adapter&) = delete;\n\t\t\tfile_input_adapter(file_input_adapter&&) = default;\n\t\t\tfile_input_adapter& operator=(const file_input_adapter&) = delete;\n\t\t\tfile_input_adapter& operator=(file_input_adapter&&) = default;\n\t\t\t~file_input_adapter() override = default;\n\n\t\t\tstd::char_traits<char>::int_type get_character() noexcept override\n\t\t\t{\n\t\t\t\treturn std::fgetc(m_file);\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// the file pointer to read from\n\t\t\tstd::FILE* m_file;\n\t\t};\n\n\n\t\t/*!\n\t\tInput adapter for a (caching) istream. Ignores a UFT Byte Order Mark at\n\t\tbeginning of input. Does not support changing the underlying std::streambuf\n\t\tin mid-input. Maintains underlying std::istream and std::streambuf to support\n\t\tsubsequent use of standard std::istream operations to process any input\n\t\tcharacters following those used in parsing the JSON input.  Clears the\n\t\tstd::istream flags; any input errors (e.g., EOF) will be detected by the first\n\t\tsubsequent call for input from the std::istream.\n\t\t*/\n\t\tclass input_stream_adapter : public input_adapter_protocol\n\t\t{\n\t\tpublic:\n\t\t\t~input_stream_adapter() override\n\t\t\t{\n\t\t\t\t// clear stream flags; we use underlying streambuf I/O, do not\n\t\t\t\t// maintain ifstream flags, except eof\n\t\t\t\tis.clear(is.rdstate() & std::ios::eofbit);\n\t\t\t}\n\n\t\t\texplicit input_stream_adapter(std::istream& i)\n\t\t\t\t: is(i), sb(*i.rdbuf())\n\t\t\t{}\n\n\t\t\t// delete because of pointer members\n\t\t\tinput_stream_adapter(const input_stream_adapter&) = delete;\n\t\t\tinput_stream_adapter& operator=(input_stream_adapter&) = delete;\n\t\t\tinput_stream_adapter(input_stream_adapter&&) = delete;\n\t\t\tinput_stream_adapter& operator=(input_stream_adapter&&) = delete;\n\n\t\t\t// std::istream/std::streambuf use std::char_traits<char>::to_int_type, to\n\t\t\t// ensure that std::char_traits<char>::eof() and the character 0xFF do not\n\t\t\t// end up as the same value, eg. 0xFFFFFFFF.\n\t\t\tstd::char_traits<char>::int_type get_character() override\n\t\t\t{\n\t\t\t\tauto res = sb.sbumpc();\n\t\t\t\t// set eof manually, as we don't use the istream interface.\n\t\t\t\tif (res == EOF)\n\t\t\t\t{\n\t\t\t\t\tis.clear(is.rdstate() | std::ios::eofbit);\n\t\t\t\t}\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// the associated input stream\n\t\t\tstd::istream& is;\n\t\t\tstd::streambuf& sb;\n\t\t};\n\n\t\t/// input adapter for buffer input\n\t\tclass input_buffer_adapter : public input_adapter_protocol\n\t\t{\n\t\tpublic:\n\t\t\tinput_buffer_adapter(const char* b, const std::size_t l) noexcept\n\t\t\t\t: cursor(b), limit(b + l)\n\t\t\t{}\n\n\t\t\t// delete because of pointer members\n\t\t\tinput_buffer_adapter(const input_buffer_adapter&) = delete;\n\t\t\tinput_buffer_adapter& operator=(input_buffer_adapter&) = delete;\n\t\t\tinput_buffer_adapter(input_buffer_adapter&&) = delete;\n\t\t\tinput_buffer_adapter& operator=(input_buffer_adapter&&) = delete;\n\t\t\t~input_buffer_adapter() override = default;\n\n\t\t\tstd::char_traits<char>::int_type get_character() noexcept override\n\t\t\t{\n\t\t\t\tif (JSON_LIKELY(cursor < limit))\n\t\t\t\t{\n\t\t\t\t\treturn std::char_traits<char>::to_int_type(*(cursor++));\n\t\t\t\t}\n\n\t\t\t\treturn std::char_traits<char>::eof();\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// pointer to the current character\n\t\t\tconst char* cursor;\n\t\t\t/// pointer past the last character\n\t\t\tconst char* const limit;\n\t\t};\n\n\t\ttemplate<typename WideStringType, size_t T>\n\t\tstruct wide_string_input_helper\n\t\t{\n\t\t\t// UTF-32\n\t\t\tstatic void fill_buffer(const WideStringType& str,\n\t\t\t\tsize_t& current_wchar,\n\t\t\t\tstd::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n\t\t\t\tsize_t& utf8_bytes_index,\n\t\t\t\tsize_t& utf8_bytes_filled)\n\t\t\t{\n\t\t\t\tutf8_bytes_index = 0;\n\n\t\t\t\tif (current_wchar == str.size())\n\t\t\t\t{\n\t\t\t\t\tutf8_bytes[0] = std::char_traits<char>::eof();\n\t\t\t\t\tutf8_bytes_filled = 1;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// get the current character\n\t\t\t\t\tconst auto wc = static_cast<unsigned int>(str[current_wchar++]);\n\n\t\t\t\t\t// UTF-32 to UTF-8 encoding\n\t\t\t\t\tif (wc < 0x80)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n\t\t\t\t\t\tutf8_bytes_filled = 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (wc <= 0x7FF)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u) & 0x1Fu));\n\t\t\t\t\t\tutf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes_filled = 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (wc <= 0xFFFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u) & 0x0Fu));\n\t\t\t\t\t\tutf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes_filled = 3;\n\t\t\t\t\t}\n\t\t\t\t\telse if (wc <= 0x10FFFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((wc >> 18u) & 0x07u));\n\t\t\t\t\t\tutf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 12u) & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes_filled = 4;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// unknown character\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n\t\t\t\t\t\tutf8_bytes_filled = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename WideStringType>\n\t\tstruct wide_string_input_helper<WideStringType, 2>\n\t\t{\n\t\t\t// UTF-16\n\t\t\tstatic void fill_buffer(const WideStringType& str,\n\t\t\t\tsize_t& current_wchar,\n\t\t\t\tstd::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n\t\t\t\tsize_t& utf8_bytes_index,\n\t\t\t\tsize_t& utf8_bytes_filled)\n\t\t\t{\n\t\t\t\tutf8_bytes_index = 0;\n\n\t\t\t\tif (current_wchar == str.size())\n\t\t\t\t{\n\t\t\t\t\tutf8_bytes[0] = std::char_traits<char>::eof();\n\t\t\t\t\tutf8_bytes_filled = 1;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// get the current character\n\t\t\t\t\tconst auto wc = static_cast<unsigned int>(str[current_wchar++]);\n\n\t\t\t\t\t// UTF-16 to UTF-8 encoding\n\t\t\t\t\tif (wc < 0x80)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n\t\t\t\t\t\tutf8_bytes_filled = 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (wc <= 0x7FF)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u)));\n\t\t\t\t\t\tutf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes_filled = 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if (0xD800 > wc or wc >= 0xE000)\n\t\t\t\t\t{\n\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u)));\n\t\t\t\t\t\tutf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));\n\t\t\t\t\t\tutf8_bytes_filled = 3;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (current_wchar < str.size())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst auto wc2 = static_cast<unsigned int>(str[current_wchar++]);\n\t\t\t\t\t\t\tconst auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu));\n\t\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));\n\t\t\t\t\t\t\tutf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));\n\t\t\t\t\t\t\tutf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));\n\t\t\t\t\t\t\tutf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));\n\t\t\t\t\t\t\tutf8_bytes_filled = 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// unknown character\n\t\t\t\t\t\t\t++current_wchar;\n\t\t\t\t\t\t\tutf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n\t\t\t\t\t\t\tutf8_bytes_filled = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttemplate<typename WideStringType>\n\t\tclass wide_string_input_adapter : public input_adapter_protocol\n\t\t{\n\t\tpublic:\n\t\t\texplicit wide_string_input_adapter(const WideStringType& w) noexcept\n\t\t\t\t: str(w)\n\t\t\t{}\n\n\t\t\tstd::char_traits<char>::int_type get_character() noexcept override\n\t\t\t{\n\t\t\t\t// check if buffer needs to be filled\n\t\t\t\tif (utf8_bytes_index == utf8_bytes_filled)\n\t\t\t\t{\n\t\t\t\t\tfill_buffer<sizeof(typename WideStringType::value_type)>();\n\n\t\t\t\t\tassert(utf8_bytes_filled > 0);\n\t\t\t\t\tassert(utf8_bytes_index == 0);\n\t\t\t\t}\n\n\t\t\t\t// use buffer\n\t\t\t\tassert(utf8_bytes_filled > 0);\n\t\t\t\tassert(utf8_bytes_index < utf8_bytes_filled);\n\t\t\t\treturn utf8_bytes[utf8_bytes_index++];\n\t\t\t}\n\n\t\tprivate:\n\t\t\ttemplate<size_t T>\n\t\t\tvoid fill_buffer()\n\t\t\t{\n\t\t\t\twide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);\n\t\t\t}\n\n\t\t\t/// the wstring to process\n\t\t\tconst WideStringType& str;\n\n\t\t\t/// index of the current wchar in str\n\t\t\tstd::size_t current_wchar = 0;\n\n\t\t\t/// a buffer for UTF-8 bytes\n\t\t\tstd::array<std::char_traits<char>::int_type, 4> utf8_bytes = { {0, 0, 0, 0} };\n\n\t\t\t/// index to the utf8_codes array for the next valid byte\n\t\t\tstd::size_t utf8_bytes_index = 0;\n\t\t\t/// number of valid bytes in the utf8_codes array\n\t\t\tstd::size_t utf8_bytes_filled = 0;\n\t\t};\n\n\t\tclass input_adapter\n\t\t{\n\t\tpublic:\n\t\t\t// native support\n\t\t\tinput_adapter(std::FILE* file)\n\t\t\t\t: ia(std::make_shared<file_input_adapter>(file)) {}\n\t\t\t/// input adapter for input stream\n\t\t\tinput_adapter(std::istream& i)\n\t\t\t\t: ia(std::make_shared<input_stream_adapter>(i)) {}\n\n\t\t\t/// input adapter for input stream\n\t\t\tinput_adapter(std::istream&& i)\n\t\t\t\t: ia(std::make_shared<input_stream_adapter>(i)) {}\n\n\t\t\tinput_adapter(const std::wstring& ws)\n\t\t\t\t: ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}\n\n\t\t\tinput_adapter(const std::u16string& ws)\n\t\t\t\t: ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}\n\n\t\t\tinput_adapter(const std::u32string& ws)\n\t\t\t\t: ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}\n\n\t\t\t/// input adapter for buffer\n\t\t\ttemplate<typename CharT,\n\t\t\t\ttypename std::enable_if<\n\t\t\t\tstd::is_pointer<CharT>::value and\n\t\t\t\tstd::is_integral<typename std::remove_pointer<CharT>::type>::value and\n\t\t\t\tsizeof(typename std::remove_pointer<CharT>::type) == 1,\n\t\t\t\tint>::type = 0>\n\t\t\t\tinput_adapter(CharT b, std::size_t l)\n\t\t\t\t: ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}\n\n\t\t\t// derived support\n\n\t\t\t/// input adapter for string literal\n\t\t\ttemplate<typename CharT,\n\t\t\t\ttypename std::enable_if<\n\t\t\t\tstd::is_pointer<CharT>::value and\n\t\t\t\tstd::is_integral<typename std::remove_pointer<CharT>::type>::value and\n\t\t\t\tsizeof(typename std::remove_pointer<CharT>::type) == 1,\n\t\t\t\tint>::type = 0>\n\t\t\t\tinput_adapter(CharT b)\n\t\t\t\t: input_adapter(reinterpret_cast<const char*>(b),\n\t\t\t\t\tstd::strlen(reinterpret_cast<const char*>(b))) {}\n\n\t\t\t/// input adapter for iterator range with contiguous storage\n\t\t\ttemplate<class IteratorType,\n\t\t\t\ttypename std::enable_if<\n\t\t\t\tstd::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,\n\t\t\t\tint>::type = 0>\n\t\t\t\tinput_adapter(IteratorType first, IteratorType last)\n\t\t\t{\n#ifndef NDEBUG\n\t\t\t\t// assertion to check that the iterator range is indeed contiguous,\n\t\t\t\t// see http://stackoverflow.com/a/35008842/266378 for more discussion\n\t\t\t\tconst auto is_contiguous = std::accumulate(\n\t\t\t\t\tfirst, last, std::pair<bool, int>(true, 0),\n\t\t\t\t\t[&first](std::pair<bool, int> res, decltype(*first) val)\n\t\t\t\t\t{\n\t\t\t\t\t\tres.first &= (val == *(std::next(std::addressof(*first), res.second++)));\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t}).first;\n\t\t\t\tassert(is_contiguous);\n#endif\n\n\t\t\t\t// assertion to check that each element is 1 byte long\n\t\t\t\tstatic_assert(\n\t\t\t\t\tsizeof(typename iterator_traits<IteratorType>::value_type) == 1,\n\t\t\t\t\t\"each element in the iterator range must have the size of 1 byte\");\n\n\t\t\t\tconst auto len = static_cast<size_t>(std::distance(first, last));\n\t\t\t\tif (JSON_LIKELY(len > 0))\n\t\t\t\t{\n\t\t\t\t\t// there is at least one element: use the address of first\n\t\t\t\t\tia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// the address of first cannot be used: use nullptr\n\t\t\t\t\tia = std::make_shared<input_buffer_adapter>(nullptr, len);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// input adapter for array\n\t\t\ttemplate<class T, std::size_t N>\n\t\t\tinput_adapter(T(&array)[N])\n\t\t\t\t: input_adapter(std::begin(array), std::end(array)) {}\n\n\t\t\t/// input adapter for contiguous container\n\t\t\ttemplate<class ContiguousContainer, typename\n\t\t\t\tstd::enable_if<not std::is_pointer<ContiguousContainer>::value and\n\t\t\t\tstd::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,\n\t\t\t\tint>::type = 0>\n\t\t\t\tinput_adapter(const ContiguousContainer& c)\n\t\t\t\t: input_adapter(std::begin(c), std::end(c)) {}\n\n\t\t\toperator input_adapter_t()\n\t\t\t{\n\t\t\t\treturn ia;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// the actual adapter\n\t\t\tinput_adapter_t ia = nullptr;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n\n#include <cassert> // assert\n#include <cstddef>\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\n\t/*!\n\t@brief SAX interface\n\n\tThis class describes the SAX interface used by @ref nlohmann::json::sax_parse.\n\tEach function is called in different situations while the input is parsed. The\n\tboolean return value informs the parser whether to continue processing the\n\tinput.\n\t*/\n\ttemplate<typename BasicJsonType>\n\tstruct json_sax\n\t{\n\t\t/// type for (signed) integers\n\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t/// type for unsigned integers\n\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t/// type for floating-point numbers\n\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t/// type for strings\n\t\tusing string_t = typename BasicJsonType::string_t;\n\n\t\t/*!\n\t\t@brief a null value was read\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool null() = 0;\n\n\t\t/*!\n\t\t@brief a boolean value was read\n\t\t@param[in] val  boolean value\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool boolean(bool val) = 0;\n\n\t\t/*!\n\t\t@brief an integer number was read\n\t\t@param[in] val  integer value\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool number_integer(number_integer_t val) = 0;\n\n\t\t/*!\n\t\t@brief an unsigned integer number was read\n\t\t@param[in] val  unsigned integer value\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool number_unsigned(number_unsigned_t val) = 0;\n\n\t\t/*!\n\t\t@brief an floating-point number was read\n\t\t@param[in] val  floating-point value\n\t\t@param[in] s    raw token value\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool number_float(number_float_t val, const string_t& s) = 0;\n\n\t\t/*!\n\t\t@brief a string was read\n\t\t@param[in] val  string value\n\t\t@return whether parsing should proceed\n\t\t@note It is safe to move the passed string.\n\t\t*/\n\t\tvirtual bool string(string_t& val) = 0;\n\n\t\t/*!\n\t\t@brief the beginning of an object was read\n\t\t@param[in] elements  number of object elements or -1 if unknown\n\t\t@return whether parsing should proceed\n\t\t@note binary formats may report the number of elements\n\t\t*/\n\t\tvirtual bool start_object(std::size_t elements) = 0;\n\n\t\t/*!\n\t\t@brief an object key was read\n\t\t@param[in] val  object key\n\t\t@return whether parsing should proceed\n\t\t@note It is safe to move the passed string.\n\t\t*/\n\t\tvirtual bool key(string_t& val) = 0;\n\n\t\t/*!\n\t\t@brief the end of an object was read\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool end_object() = 0;\n\n\t\t/*!\n\t\t@brief the beginning of an array was read\n\t\t@param[in] elements  number of array elements or -1 if unknown\n\t\t@return whether parsing should proceed\n\t\t@note binary formats may report the number of elements\n\t\t*/\n\t\tvirtual bool start_array(std::size_t elements) = 0;\n\n\t\t/*!\n\t\t@brief the end of an array was read\n\t\t@return whether parsing should proceed\n\t\t*/\n\t\tvirtual bool end_array() = 0;\n\n\t\t/*!\n\t\t@brief a parse error occurred\n\t\t@param[in] position    the position in the input where the error occurs\n\t\t@param[in] last_token  the last read token\n\t\t@param[in] ex          an exception object describing the error\n\t\t@return whether parsing should proceed (must return false)\n\t\t*/\n\t\tvirtual bool parse_error(std::size_t position,\n\t\t\tconst std::string& last_token,\n\t\t\tconst detail::exception& ex) = 0;\n\n\t\tvirtual ~json_sax() = default;\n\t};\n\n\n\tnamespace detail\n\t{\n\t\t/*!\n\t\t@brief SAX implementation to create a JSON value from SAX events\n\n\t\tThis class implements the @ref json_sax interface and processes the SAX events\n\t\tto create a JSON value which makes it basically a DOM parser. The structure or\n\t\thierarchy of the JSON value is managed by the stack `ref_stack` which contains\n\t\ta pointer to the respective array or object for each recursion depth.\n\n\t\tAfter successful parsing, the value that is passed by reference to the\n\t\tconstructor contains the parsed value.\n\n\t\t@tparam BasicJsonType  the JSON type\n\t\t*/\n\t\ttemplate<typename BasicJsonType>\n\t\tclass json_sax_dom_parser\n\t\t{\n\t\tpublic:\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\n\t\t\t/*!\n\t\t\t@param[in, out] r  reference to a JSON value that is manipulated while\n\t\t\t\t\t\t\t   parsing\n\t\t\t@param[in] allow_exceptions_  whether parse errors yield exceptions\n\t\t\t*/\n\t\t\texplicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)\n\t\t\t\t: root(r), allow_exceptions(allow_exceptions_)\n\t\t\t{}\n\n\t\t\t// make class move-only\n\t\t\tjson_sax_dom_parser(const json_sax_dom_parser&) = delete;\n\t\t\tjson_sax_dom_parser(json_sax_dom_parser&&) = default;\n\t\t\tjson_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;\n\t\t\tjson_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;\n\t\t\t~json_sax_dom_parser() = default;\n\n\t\t\tbool null()\n\t\t\t{\n\t\t\t\thandle_value(nullptr);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool boolean(bool val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_integer(number_integer_t val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_unsigned(number_unsigned_t val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_float(number_float_t val, const string_t& /*unused*/)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool string(string_t& val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool start_object(std::size_t len)\n\t\t\t{\n\t\t\t\tref_stack.push_back(handle_value(BasicJsonType::value_t::object));\n\n\t\t\t\tif (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(408,\n\t\t\t\t\t\t\"excessive object size: \" + std::to_string(len)));\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool key(string_t& val)\n\t\t\t{\n\t\t\t\t// add null at given key and store the reference for later\n\t\t\t\tobject_element = &(ref_stack.back()->m_value.object->operator[](val));\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool end_object()\n\t\t\t{\n\t\t\t\tref_stack.pop_back();\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool start_array(std::size_t len)\n\t\t\t{\n\t\t\t\tref_stack.push_back(handle_value(BasicJsonType::value_t::array));\n\n\t\t\t\tif (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(408,\n\t\t\t\t\t\t\"excessive array size: \" + std::to_string(len)));\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool end_array()\n\t\t\t{\n\t\t\t\tref_stack.pop_back();\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n\t\t\t\tconst detail::exception& ex)\n\t\t\t{\n\t\t\t\terrored = true;\n\t\t\t\tif (allow_exceptions)\n\t\t\t\t{\n\t\t\t\t\t// determine the proper exception type from the id\n\t\t\t\t\tswitch ((ex.id / 100) % 100)\n\t\t\t\t\t{\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::parse_error*>(&ex));\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::out_of_range*>(&ex));\n\t\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::type_error*>(&ex));\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::other_error*>(&ex));\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tassert(false);\n\t\t\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconstexpr bool is_errored() const\n\t\t\t{\n\t\t\t\treturn errored;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/*!\n\t\t\t@invariant If the ref stack is empty, then the passed value will be the new\n\t\t\t\t\t   root.\n\t\t\t@invariant If the ref stack contains a value, then it is an array or an\n\t\t\t\t\t   object to which we can add elements\n\t\t\t*/\n\t\t\ttemplate<typename Value>\n\t\t\tBasicJsonType* handle_value(Value&& v)\n\t\t\t{\n\t\t\t\tif (ref_stack.empty())\n\t\t\t\t{\n\t\t\t\t\troot = BasicJsonType(std::forward<Value>(v));\n\t\t\t\t\treturn &root;\n\t\t\t\t}\n\n\t\t\t\tassert(ref_stack.back()->is_array() or ref_stack.back()->is_object());\n\n\t\t\t\tif (ref_stack.back()->is_array())\n\t\t\t\t{\n\t\t\t\t\tref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));\n\t\t\t\t\treturn &(ref_stack.back()->m_value.array->back());\n\t\t\t\t}\n\n\t\t\t\tassert(ref_stack.back()->is_object());\n\t\t\t\tassert(object_element);\n\t\t\t\t*object_element = BasicJsonType(std::forward<Value>(v));\n\t\t\t\treturn object_element;\n\t\t\t}\n\n\t\t\t/// the parsed JSON value\n\t\t\tBasicJsonType& root;\n\t\t\t/// stack to model hierarchy of values\n\t\t\tstd::vector<BasicJsonType*> ref_stack{};\n\t\t\t/// helper to hold the reference for the next object element\n\t\t\tBasicJsonType* object_element = nullptr;\n\t\t\t/// whether a syntax error occurred\n\t\t\tbool errored = false;\n\t\t\t/// whether to throw exceptions in case of errors\n\t\t\tconst bool allow_exceptions = true;\n\t\t};\n\n\t\ttemplate<typename BasicJsonType>\n\t\tclass json_sax_dom_callback_parser\n\t\t{\n\t\tpublic:\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\t\t\tusing parser_callback_t = typename BasicJsonType::parser_callback_t;\n\t\t\tusing parse_event_t = typename BasicJsonType::parse_event_t;\n\n\t\t\tjson_sax_dom_callback_parser(BasicJsonType& r,\n\t\t\t\tconst parser_callback_t cb,\n\t\t\t\tconst bool allow_exceptions_ = true)\n\t\t\t\t: root(r), callback(cb), allow_exceptions(allow_exceptions_)\n\t\t\t{\n\t\t\t\tkeep_stack.push_back(true);\n\t\t\t}\n\n\t\t\t// make class move-only\n\t\t\tjson_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;\n\t\t\tjson_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;\n\t\t\tjson_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;\n\t\t\tjson_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default;\n\t\t\t~json_sax_dom_callback_parser() = default;\n\n\t\t\tbool null()\n\t\t\t{\n\t\t\t\thandle_value(nullptr);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool boolean(bool val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_integer(number_integer_t val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_unsigned(number_unsigned_t val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_float(number_float_t val, const string_t& /*unused*/)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool string(string_t& val)\n\t\t\t{\n\t\t\t\thandle_value(val);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool start_object(std::size_t len)\n\t\t\t{\n\t\t\t\t// check callback for object start\n\t\t\t\tconst bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);\n\t\t\t\tkeep_stack.push_back(keep);\n\n\t\t\t\tauto val = handle_value(BasicJsonType::value_t::object, true);\n\t\t\t\tref_stack.push_back(val.second);\n\n\t\t\t\t// check object limit\n\t\t\t\tif (ref_stack.back() and JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(408, \"excessive object size: \" + std::to_string(len)));\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool key(string_t& val)\n\t\t\t{\n\t\t\t\tBasicJsonType k = BasicJsonType(val);\n\n\t\t\t\t// check callback for key\n\t\t\t\tconst bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);\n\t\t\t\tkey_keep_stack.push_back(keep);\n\n\t\t\t\t// add discarded value at given key and store the reference for later\n\t\t\t\tif (keep and ref_stack.back())\n\t\t\t\t{\n\t\t\t\t\tobject_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool end_object()\n\t\t\t{\n\t\t\t\tif (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))\n\t\t\t\t{\n\t\t\t\t\t// discard object\n\t\t\t\t\t*ref_stack.back() = discarded;\n\t\t\t\t}\n\n\t\t\t\tassert(not ref_stack.empty());\n\t\t\t\tassert(not keep_stack.empty());\n\t\t\t\tref_stack.pop_back();\n\t\t\t\tkeep_stack.pop_back();\n\n\t\t\t\tif (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_object())\n\t\t\t\t{\n\t\t\t\t\t// remove discarded value\n\t\t\t\t\tfor (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (it->is_discarded())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tref_stack.back()->erase(it);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool start_array(std::size_t len)\n\t\t\t{\n\t\t\t\tconst bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);\n\t\t\t\tkeep_stack.push_back(keep);\n\n\t\t\t\tauto val = handle_value(BasicJsonType::value_t::array, true);\n\t\t\t\tref_stack.push_back(val.second);\n\n\t\t\t\t// check array limit\n\t\t\t\tif (ref_stack.back() and JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(408, \"excessive array size: \" + std::to_string(len)));\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool end_array()\n\t\t\t{\n\t\t\t\tbool keep = true;\n\n\t\t\t\tif (ref_stack.back())\n\t\t\t\t{\n\t\t\t\t\tkeep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());\n\t\t\t\t\tif (not keep)\n\t\t\t\t\t{\n\t\t\t\t\t\t// discard array\n\t\t\t\t\t\t*ref_stack.back() = discarded;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tassert(not ref_stack.empty());\n\t\t\t\tassert(not keep_stack.empty());\n\t\t\t\tref_stack.pop_back();\n\t\t\t\tkeep_stack.pop_back();\n\n\t\t\t\t// remove discarded value\n\t\t\t\tif (not keep and not ref_stack.empty() and ref_stack.back()->is_array())\n\t\t\t\t{\n\t\t\t\t\tref_stack.back()->m_value.array->pop_back();\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n\t\t\t\tconst detail::exception& ex)\n\t\t\t{\n\t\t\t\terrored = true;\n\t\t\t\tif (allow_exceptions)\n\t\t\t\t{\n\t\t\t\t\t// determine the proper exception type from the id\n\t\t\t\t\tswitch ((ex.id / 100) % 100)\n\t\t\t\t\t{\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::parse_error*>(&ex));\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::out_of_range*>(&ex));\n\t\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::type_error*>(&ex));\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\tJSON_THROW(*static_cast<const detail::other_error*>(&ex));\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tassert(false);\n\t\t\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconstexpr bool is_errored() const\n\t\t\t{\n\t\t\t\treturn errored;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/*!\n\t\t\t@param[in] v  value to add to the JSON value we build during parsing\n\t\t\t@param[in] skip_callback  whether we should skip calling the callback\n\t\t\t\t\t   function; this is required after start_array() and\n\t\t\t\t\t   start_object() SAX events, because otherwise we would call the\n\t\t\t\t\t   callback function with an empty array or object, respectively.\n\n\t\t\t@invariant If the ref stack is empty, then the passed value will be the new\n\t\t\t\t\t   root.\n\t\t\t@invariant If the ref stack contains a value, then it is an array or an\n\t\t\t\t\t   object to which we can add elements\n\n\t\t\t@return pair of boolean (whether value should be kept) and pointer (to the\n\t\t\t\t\tpassed value in the ref_stack hierarchy; nullptr if not kept)\n\t\t\t*/\n\t\t\ttemplate<typename Value>\n\t\t\tstd::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)\n\t\t\t{\n\t\t\t\tassert(not keep_stack.empty());\n\n\t\t\t\t// do not handle this value if we know it would be added to a discarded\n\t\t\t\t// container\n\t\t\t\tif (not keep_stack.back())\n\t\t\t\t{\n\t\t\t\t\treturn { false, nullptr };\n\t\t\t\t}\n\n\t\t\t\t// create value\n\t\t\t\tauto value = BasicJsonType(std::forward<Value>(v));\n\n\t\t\t\t// check callback\n\t\t\t\tconst bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);\n\n\t\t\t\t// do not handle this value if we just learnt it shall be discarded\n\t\t\t\tif (not keep)\n\t\t\t\t{\n\t\t\t\t\treturn { false, nullptr };\n\t\t\t\t}\n\n\t\t\t\tif (ref_stack.empty())\n\t\t\t\t{\n\t\t\t\t\troot = std::move(value);\n\t\t\t\t\treturn { true, &root };\n\t\t\t\t}\n\n\t\t\t\t// skip this value if we already decided to skip the parent\n\t\t\t\t// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)\n\t\t\t\tif (not ref_stack.back())\n\t\t\t\t{\n\t\t\t\t\treturn { false, nullptr };\n\t\t\t\t}\n\n\t\t\t\t// we now only expect arrays and objects\n\t\t\t\tassert(ref_stack.back()->is_array() or ref_stack.back()->is_object());\n\n\t\t\t\t// array\n\t\t\t\tif (ref_stack.back()->is_array())\n\t\t\t\t{\n\t\t\t\t\tref_stack.back()->m_value.array->push_back(std::move(value));\n\t\t\t\t\treturn { true, &(ref_stack.back()->m_value.array->back()) };\n\t\t\t\t}\n\n\t\t\t\t// object\n\t\t\t\tassert(ref_stack.back()->is_object());\n\t\t\t\t// check if we should store an element for the current key\n\t\t\t\tassert(not key_keep_stack.empty());\n\t\t\t\tconst bool store_element = key_keep_stack.back();\n\t\t\t\tkey_keep_stack.pop_back();\n\n\t\t\t\tif (not store_element)\n\t\t\t\t{\n\t\t\t\t\treturn { false, nullptr };\n\t\t\t\t}\n\n\t\t\t\tassert(object_element);\n\t\t\t\t*object_element = std::move(value);\n\t\t\t\treturn { true, object_element };\n\t\t\t}\n\n\t\t\t/// the parsed JSON value\n\t\t\tBasicJsonType& root;\n\t\t\t/// stack to model hierarchy of values\n\t\t\tstd::vector<BasicJsonType*> ref_stack{};\n\t\t\t/// stack to manage which values to keep\n\t\t\tstd::vector<bool> keep_stack{};\n\t\t\t/// stack to manage which object keys to keep\n\t\t\tstd::vector<bool> key_keep_stack{};\n\t\t\t/// helper to hold the reference for the next object element\n\t\t\tBasicJsonType* object_element = nullptr;\n\t\t\t/// whether a syntax error occurred\n\t\t\tbool errored = false;\n\t\t\t/// callback function\n\t\t\tconst parser_callback_t callback = nullptr;\n\t\t\t/// whether to throw exceptions in case of errors\n\t\t\tconst bool allow_exceptions = true;\n\t\t\t/// a discarded value for the callback\n\t\t\tBasicJsonType discarded = BasicJsonType::value_t::discarded;\n\t\t};\n\n\t\ttemplate<typename BasicJsonType>\n\t\tclass json_sax_acceptor\n\t\t{\n\t\tpublic:\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\n\t\t\tbool null()\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool boolean(bool /*unused*/)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_integer(number_integer_t /*unused*/)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_unsigned(number_unsigned_t /*unused*/)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool number_float(number_float_t /*unused*/, const string_t& /*unused*/)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool string(string_t& /*unused*/)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool start_object(std::size_t  /*unused*/ = std::size_t(-1))\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool key(string_t& /*unused*/)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool end_object()\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool start_array(std::size_t  /*unused*/ = std::size_t(-1))\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool end_array()\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}  // namespace detail\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n\n#include <cstdint> // size_t\n#include <utility> // declval\n#include <string> // string\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\ttemplate <typename T>\n\t\tusing null_function_t = decltype(std::declval<T&>().null());\n\n\t\ttemplate <typename T>\n\t\tusing boolean_function_t =\n\t\t\tdecltype(std::declval<T&>().boolean(std::declval<bool>()));\n\n\t\ttemplate <typename T, typename Integer>\n\t\tusing number_integer_function_t =\n\t\t\tdecltype(std::declval<T&>().number_integer(std::declval<Integer>()));\n\n\t\ttemplate <typename T, typename Unsigned>\n\t\tusing number_unsigned_function_t =\n\t\t\tdecltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));\n\n\t\ttemplate <typename T, typename Float, typename String>\n\t\tusing number_float_function_t = decltype(std::declval<T&>().number_float(\n\t\t\tstd::declval<Float>(), std::declval<const String&>()));\n\n\t\ttemplate <typename T, typename String>\n\t\tusing string_function_t =\n\t\t\tdecltype(std::declval<T&>().string(std::declval<String&>()));\n\n\t\ttemplate <typename T>\n\t\tusing start_object_function_t =\n\t\t\tdecltype(std::declval<T&>().start_object(std::declval<std::size_t>()));\n\n\t\ttemplate <typename T, typename String>\n\t\tusing key_function_t =\n\t\t\tdecltype(std::declval<T&>().key(std::declval<String&>()));\n\n\t\ttemplate <typename T>\n\t\tusing end_object_function_t = decltype(std::declval<T&>().end_object());\n\n\t\ttemplate <typename T>\n\t\tusing start_array_function_t =\n\t\t\tdecltype(std::declval<T&>().start_array(std::declval<std::size_t>()));\n\n\t\ttemplate <typename T>\n\t\tusing end_array_function_t = decltype(std::declval<T&>().end_array());\n\n\t\ttemplate <typename T, typename Exception>\n\t\tusing parse_error_function_t = decltype(std::declval<T&>().parse_error(\n\t\t\tstd::declval<std::size_t>(), std::declval<const std::string&>(),\n\t\t\tstd::declval<const Exception&>()));\n\n\t\ttemplate <typename SAX, typename BasicJsonType>\n\t\tstruct is_sax\n\t\t{\n\t\tprivate:\n\t\t\tstatic_assert(is_basic_json<BasicJsonType>::value,\n\t\t\t\t\"BasicJsonType must be of type basic_json<...>\");\n\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\t\t\tusing exception_t = typename BasicJsonType::exception;\n\n\t\tpublic:\n\t\t\tstatic constexpr bool value =\n\t\t\t\tis_detected_exact<bool, null_function_t, SAX>::value &&\n\t\t\t\tis_detected_exact<bool, boolean_function_t, SAX>::value &&\n\t\t\t\tis_detected_exact<bool, number_integer_function_t, SAX,\n\t\t\t\tnumber_integer_t>::value &&\n\t\t\t\tis_detected_exact<bool, number_unsigned_function_t, SAX,\n\t\t\t\tnumber_unsigned_t>::value &&\n\t\t\t\tis_detected_exact<bool, number_float_function_t, SAX, number_float_t,\n\t\t\t\tstring_t>::value &&\n\t\t\t\tis_detected_exact<bool, string_function_t, SAX, string_t>::value &&\n\t\t\t\tis_detected_exact<bool, start_object_function_t, SAX>::value &&\n\t\t\t\tis_detected_exact<bool, key_function_t, SAX, string_t>::value &&\n\t\t\t\tis_detected_exact<bool, end_object_function_t, SAX>::value &&\n\t\t\t\tis_detected_exact<bool, start_array_function_t, SAX>::value &&\n\t\t\t\tis_detected_exact<bool, end_array_function_t, SAX>::value &&\n\t\t\t\tis_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;\n\t\t};\n\n\t\ttemplate <typename SAX, typename BasicJsonType>\n\t\tstruct is_sax_static_asserts\n\t\t{\n\t\tprivate:\n\t\t\tstatic_assert(is_basic_json<BasicJsonType>::value,\n\t\t\t\t\"BasicJsonType must be of type basic_json<...>\");\n\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\t\t\tusing exception_t = typename BasicJsonType::exception;\n\n\t\tpublic:\n\t\t\tstatic_assert(is_detected_exact<bool, null_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool null()\");\n\t\t\tstatic_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool boolean(bool)\");\n\t\t\tstatic_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool boolean(bool)\");\n\t\t\tstatic_assert(\n\t\t\t\tis_detected_exact<bool, number_integer_function_t, SAX,\n\t\t\t\tnumber_integer_t>::value,\n\t\t\t\t\"Missing/invalid function: bool number_integer(number_integer_t)\");\n\t\t\tstatic_assert(\n\t\t\t\tis_detected_exact<bool, number_unsigned_function_t, SAX,\n\t\t\t\tnumber_unsigned_t>::value,\n\t\t\t\t\"Missing/invalid function: bool number_unsigned(number_unsigned_t)\");\n\t\t\tstatic_assert(is_detected_exact<bool, number_float_function_t, SAX,\n\t\t\t\tnumber_float_t, string_t>::value,\n\t\t\t\t\"Missing/invalid function: bool number_float(number_float_t, const string_t&)\");\n\t\t\tstatic_assert(\n\t\t\t\tis_detected_exact<bool, string_function_t, SAX, string_t>::value,\n\t\t\t\t\"Missing/invalid function: bool string(string_t&)\");\n\t\t\tstatic_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool start_object(std::size_t)\");\n\t\t\tstatic_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,\n\t\t\t\t\"Missing/invalid function: bool key(string_t&)\");\n\t\t\tstatic_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool end_object()\");\n\t\t\tstatic_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool start_array(std::size_t)\");\n\t\t\tstatic_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,\n\t\t\t\t\"Missing/invalid function: bool end_array()\");\n\t\t\tstatic_assert(\n\t\t\t\tis_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,\n\t\t\t\t\"Missing/invalid function: bool parse_error(std::size_t, const \"\n\t\t\t\t\"std::string&, const exception&)\");\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t///////////////////\n\t\t// binary reader //\n\t\t///////////////////\n\n\t\t/*!\n\t\t@brief deserialization of CBOR, MessagePack, and UBJSON values\n\t\t*/\n\t\ttemplate<typename BasicJsonType, typename SAX = json_sax_dom_parser<BasicJsonType>>\n\t\tclass binary_reader\n\t\t{\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\t\t\tusing json_sax_t = SAX;\n\n\t\tpublic:\n\t\t\t/*!\n\t\t\t@brief create a binary reader\n\n\t\t\t@param[in] adapter  input adapter to read from\n\t\t\t*/\n\t\t\texplicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter))\n\t\t\t{\n\t\t\t\t(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n\t\t\t\tassert(ia);\n\t\t\t}\n\n\t\t\t// make class move-only\n\t\t\tbinary_reader(const binary_reader&) = delete;\n\t\t\tbinary_reader(binary_reader&&) = default;\n\t\t\tbinary_reader& operator=(const binary_reader&) = delete;\n\t\t\tbinary_reader& operator=(binary_reader&&) = default;\n\t\t\t~binary_reader() = default;\n\n\t\t\t/*!\n\t\t\t@param[in] format  the binary format to parse\n\t\t\t@param[in] sax_    a SAX event processor\n\t\t\t@param[in] strict  whether to expect the input to be consumed completed\n\n\t\t\t@return\n\t\t\t*/\n\t\t\tbool sax_parse(const input_format_t format,\n\t\t\t\tjson_sax_t* sax_,\n\t\t\t\tconst bool strict = true)\n\t\t\t{\n\t\t\t\tsax = sax_;\n\t\t\t\tbool result = false;\n\n\t\t\t\tswitch (format)\n\t\t\t\t{\n\t\t\t\tcase input_format_t::bson:\n\t\t\t\t\tresult = parse_bson_internal();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase input_format_t::cbor:\n\t\t\t\t\tresult = parse_cbor_internal();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase input_format_t::msgpack:\n\t\t\t\t\tresult = parse_msgpack_internal();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase input_format_t::ubjson:\n\t\t\t\t\tresult = parse_ubjson_internal();\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t}\n\n\t\t\t\t// strict mode: next byte must be EOF\n\t\t\t\tif (result and strict)\n\t\t\t\t{\n\t\t\t\t\tif (format == input_format_t::ubjson)\n\t\t\t\t\t{\n\t\t\t\t\t\tget_ignore_noop();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tget();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (JSON_UNLIKELY(current != std::char_traits<char>::eof()))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn sax->parse_error(chars_read, get_token_string(),\n\t\t\t\t\t\t\tparse_error::create(110, chars_read, exception_message(format, \"expected end of input; last byte: 0x\" + get_token_string(), \"value\")));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief determine system byte order\n\n\t\t\t@return true if and only if system's byte order is little endian\n\n\t\t\t@note from http://stackoverflow.com/a/1001328/266378\n\t\t\t*/\n\t\t\tstatic constexpr bool little_endianess(int num = 1) noexcept\n\t\t\t{\n\t\t\t\treturn *reinterpret_cast<char*>(&num) == 1;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t//////////\n\t\t\t// BSON //\n\t\t\t//////////\n\n\t\t\t/*!\n\t\t\t@brief Reads in a BSON-object and passes it to the SAX-parser.\n\t\t\t@return whether a valid BSON-value was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_bson_internal()\n\t\t\t{\n\t\t\t\tstd::int32_t document_size;\n\t\t\t\tget_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n\t\t\t\tif (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/false)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_object();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Parses a C-style string from the BSON input.\n\t\t\t@param[in, out] result  A reference to the string variable where the read\n\t\t\t\t\t\t\t\t\tstring is to be stored.\n\t\t\t@return `true` if the \\x00-byte indicating the end of the string was\n\t\t\t\t\t encountered before the EOF; false` indicates an unexpected EOF.\n\t\t\t*/\n\t\t\tbool get_bson_cstr(string_t& result)\n\t\t\t{\n\t\t\t\tauto out = std::back_inserter(result);\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, \"cstring\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (current == 0x00)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\t*out++ = static_cast<char>(current);\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Parses a zero-terminated string of length @a len from the BSON\n\t\t\t\t   input.\n\t\t\t@param[in] len  The length (including the zero-byte at the end) of the\n\t\t\t\t\t\t\tstring to be read.\n\t\t\t@param[in, out] result  A reference to the string variable where the read\n\t\t\t\t\t\t\t\t\tstring is to be stored.\n\t\t\t@tparam NumberType The type of the length @a len\n\t\t\t@pre len >= 1\n\t\t\t@return `true` if the string was successfully parsed\n\t\t\t*/\n\t\t\ttemplate<typename NumberType>\n\t\t\tbool get_bson_string(const NumberType len, string_t& result)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(len < 1))\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"string length must be at least 1, is \" + std::to_string(len), \"string\")));\n\t\t\t\t}\n\n\t\t\t\treturn get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) and get() != std::char_traits<char>::eof();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Read a BSON document element of the given @a element_type.\n\t\t\t@param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html\n\t\t\t@param[in] element_type_parse_position The position in the input stream,\n\t\t\t\t\t   where the `element_type` was read.\n\t\t\t@warning Not all BSON element types are supported yet. An unsupported\n\t\t\t\t\t @a element_type will give rise to a parse_error.114:\n\t\t\t\t\t Unsupported BSON record type 0x...\n\t\t\t@return whether a valid BSON-object/array was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_bson_element_internal(const int element_type,\n\t\t\t\tconst std::size_t element_type_parse_position)\n\t\t\t{\n\t\t\t\tswitch (element_type)\n\t\t\t\t{\n\t\t\t\tcase 0x01: // double\n\t\t\t\t{\n\t\t\t\t\tdouble number;\n\t\t\t\t\treturn get_number<double, true>(input_format_t::bson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 0x02: // string\n\t\t\t\t{\n\t\t\t\t\tstd::int32_t len;\n\t\t\t\t\tstring_t value;\n\t\t\t\t\treturn get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_string(len, value) and sax->string(value);\n\t\t\t\t}\n\n\t\t\t\tcase 0x03: // object\n\t\t\t\t{\n\t\t\t\t\treturn parse_bson_internal();\n\t\t\t\t}\n\n\t\t\t\tcase 0x04: // array\n\t\t\t\t{\n\t\t\t\t\treturn parse_bson_array();\n\t\t\t\t}\n\n\t\t\t\tcase 0x08: // boolean\n\t\t\t\t{\n\t\t\t\t\treturn sax->boolean(get() != 0);\n\t\t\t\t}\n\n\t\t\t\tcase 0x0A: // null\n\t\t\t\t{\n\t\t\t\t\treturn sax->null();\n\t\t\t\t}\n\n\t\t\t\tcase 0x10: // int32\n\t\t\t\t{\n\t\t\t\t\tstd::int32_t value;\n\t\t\t\t\treturn get_number<std::int32_t, true>(input_format_t::bson, value) and sax->number_integer(value);\n\t\t\t\t}\n\n\t\t\t\tcase 0x12: // int64\n\t\t\t\t{\n\t\t\t\t\tstd::int64_t value;\n\t\t\t\t\treturn get_number<std::int64_t, true>(input_format_t::bson, value) and sax->number_integer(value);\n\t\t\t\t}\n\n\t\t\t\tdefault: // anything else not supported (yet)\n\t\t\t\t{\n\t\t\t\t\tstd::array<char, 3> cr{ {} };\n\t\t\t\t\t(std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(element_type));\n\t\t\t\t\treturn sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, \"Unsupported BSON record type 0x\" + std::string(cr.data())));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Read a BSON element list (as specified in the BSON-spec)\n\n\t\t\tThe same binary layout is used for objects and arrays, hence it must be\n\t\t\tindicated with the argument @a is_array which one is expected\n\t\t\t(true --> array, false --> object).\n\n\t\t\t@param[in] is_array Determines if the element list being read is to be\n\t\t\t\t\t\t\t\ttreated as an object (@a is_array == false), or as an\n\t\t\t\t\t\t\t\tarray (@a is_array == true).\n\t\t\t@return whether a valid BSON-object/array was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_bson_element_list(const bool is_array)\n\t\t\t{\n\t\t\t\tstring_t key;\n\t\t\t\twhile (int element_type = get())\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, \"element list\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst std::size_t element_type_parse_position = chars_read;\n\t\t\t\t\tif (JSON_UNLIKELY(not get_bson_cstr(key)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (not is_array and not sax->key(key))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// get_bson_cstr only appends\n\t\t\t\t\tkey.clear();\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Reads an array from the BSON input and passes it to the SAX-parser.\n\t\t\t@return whether a valid BSON-array was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_bson_array()\n\t\t\t{\n\t\t\t\tstd::int32_t document_size;\n\t\t\t\tget_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n\t\t\t\tif (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/true)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_array();\n\t\t\t}\n\n\t\t\t//////////\n\t\t\t// CBOR //\n\t\t\t//////////\n\n\t\t\t/*!\n\t\t\t@param[in] get_char  whether a new character should be retrieved from the\n\t\t\t\t\t\t\t\t input (true, default) or whether the last read\n\t\t\t\t\t\t\t\t character should be considered instead\n\n\t\t\t@return whether a valid CBOR value was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_cbor_internal(const bool get_char = true)\n\t\t\t{\n\t\t\t\tswitch (get_char ? get() : current)\n\t\t\t\t{\n\t\t\t\t\t// EOF\n\t\t\t\tcase std::char_traits<char>::eof():\n\t\t\t\t\treturn unexpect_eof(input_format_t::cbor, \"value\");\n\n\t\t\t\t\t// Integer 0x00..0x17 (0..23)\n\t\t\t\tcase 0x00:\n\t\t\t\tcase 0x01:\n\t\t\t\tcase 0x02:\n\t\t\t\tcase 0x03:\n\t\t\t\tcase 0x04:\n\t\t\t\tcase 0x05:\n\t\t\t\tcase 0x06:\n\t\t\t\tcase 0x07:\n\t\t\t\tcase 0x08:\n\t\t\t\tcase 0x09:\n\t\t\t\tcase 0x0A:\n\t\t\t\tcase 0x0B:\n\t\t\t\tcase 0x0C:\n\t\t\t\tcase 0x0D:\n\t\t\t\tcase 0x0E:\n\t\t\t\tcase 0x0F:\n\t\t\t\tcase 0x10:\n\t\t\t\tcase 0x11:\n\t\t\t\tcase 0x12:\n\t\t\t\tcase 0x13:\n\t\t\t\tcase 0x14:\n\t\t\t\tcase 0x15:\n\t\t\t\tcase 0x16:\n\t\t\t\tcase 0x17:\n\t\t\t\t\treturn sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n\t\t\t\tcase 0x18: // Unsigned integer (one-byte uint8_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0x19: // Unsigned integer (two-byte uint16_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0x1A: // Unsigned integer (four-byte uint32_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0x1B: // Unsigned integer (eight-byte uint64_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint64_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\t// Negative integer -1-0x00..-1-0x17 (-1..-24)\n\t\t\t\tcase 0x20:\n\t\t\t\tcase 0x21:\n\t\t\t\tcase 0x22:\n\t\t\t\tcase 0x23:\n\t\t\t\tcase 0x24:\n\t\t\t\tcase 0x25:\n\t\t\t\tcase 0x26:\n\t\t\t\tcase 0x27:\n\t\t\t\tcase 0x28:\n\t\t\t\tcase 0x29:\n\t\t\t\tcase 0x2A:\n\t\t\t\tcase 0x2B:\n\t\t\t\tcase 0x2C:\n\t\t\t\tcase 0x2D:\n\t\t\t\tcase 0x2E:\n\t\t\t\tcase 0x2F:\n\t\t\t\tcase 0x30:\n\t\t\t\tcase 0x31:\n\t\t\t\tcase 0x32:\n\t\t\t\tcase 0x33:\n\t\t\t\tcase 0x34:\n\t\t\t\tcase 0x35:\n\t\t\t\tcase 0x36:\n\t\t\t\tcase 0x37:\n\t\t\t\t\treturn sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));\n\n\t\t\t\tcase 0x38: // Negative integer (one-byte uint8_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n\t\t\t\t}\n\n\t\t\t\tcase 0x39: // Negative integer -1-n (two-byte uint16_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n\t\t\t\t}\n\n\t\t\t\tcase 0x3A: // Negative integer -1-n (four-byte uint32_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n\t\t\t\t}\n\n\t\t\t\tcase 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint64_t number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)\n\t\t\t\t\t\t- static_cast<number_integer_t>(number));\n\t\t\t\t}\n\n\t\t\t\t// UTF-8 string (0x00..0x17 bytes follow)\n\t\t\t\tcase 0x60:\n\t\t\t\tcase 0x61:\n\t\t\t\tcase 0x62:\n\t\t\t\tcase 0x63:\n\t\t\t\tcase 0x64:\n\t\t\t\tcase 0x65:\n\t\t\t\tcase 0x66:\n\t\t\t\tcase 0x67:\n\t\t\t\tcase 0x68:\n\t\t\t\tcase 0x69:\n\t\t\t\tcase 0x6A:\n\t\t\t\tcase 0x6B:\n\t\t\t\tcase 0x6C:\n\t\t\t\tcase 0x6D:\n\t\t\t\tcase 0x6E:\n\t\t\t\tcase 0x6F:\n\t\t\t\tcase 0x70:\n\t\t\t\tcase 0x71:\n\t\t\t\tcase 0x72:\n\t\t\t\tcase 0x73:\n\t\t\t\tcase 0x74:\n\t\t\t\tcase 0x75:\n\t\t\t\tcase 0x76:\n\t\t\t\tcase 0x77:\n\t\t\t\tcase 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n\t\t\t\tcase 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n\t\t\t\tcase 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n\t\t\t\tcase 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n\t\t\t\tcase 0x7F: // UTF-8 string (indefinite length)\n\t\t\t\t{\n\t\t\t\t\tstring_t s;\n\t\t\t\t\treturn get_cbor_string(s) and sax->string(s);\n\t\t\t\t}\n\n\t\t\t\t// array (0x00..0x17 data items follow)\n\t\t\t\tcase 0x80:\n\t\t\t\tcase 0x81:\n\t\t\t\tcase 0x82:\n\t\t\t\tcase 0x83:\n\t\t\t\tcase 0x84:\n\t\t\t\tcase 0x85:\n\t\t\t\tcase 0x86:\n\t\t\t\tcase 0x87:\n\t\t\t\tcase 0x88:\n\t\t\t\tcase 0x89:\n\t\t\t\tcase 0x8A:\n\t\t\t\tcase 0x8B:\n\t\t\t\tcase 0x8C:\n\t\t\t\tcase 0x8D:\n\t\t\t\tcase 0x8E:\n\t\t\t\tcase 0x8F:\n\t\t\t\tcase 0x90:\n\t\t\t\tcase 0x91:\n\t\t\t\tcase 0x92:\n\t\t\t\tcase 0x93:\n\t\t\t\tcase 0x94:\n\t\t\t\tcase 0x95:\n\t\t\t\tcase 0x96:\n\t\t\t\tcase 0x97:\n\t\t\t\t\treturn get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));\n\n\t\t\t\tcase 0x98: // array (one-byte uint8_t for n follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0x99: // array (two-byte uint16_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0x9A: // array (four-byte uint32_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0x9B: // array (eight-byte uint64_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint64_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0x9F: // array (indefinite length)\n\t\t\t\t\treturn get_cbor_array(std::size_t(-1));\n\n\t\t\t\t\t// map (0x00..0x17 pairs of data items follow)\n\t\t\t\tcase 0xA0:\n\t\t\t\tcase 0xA1:\n\t\t\t\tcase 0xA2:\n\t\t\t\tcase 0xA3:\n\t\t\t\tcase 0xA4:\n\t\t\t\tcase 0xA5:\n\t\t\t\tcase 0xA6:\n\t\t\t\tcase 0xA7:\n\t\t\t\tcase 0xA8:\n\t\t\t\tcase 0xA9:\n\t\t\t\tcase 0xAA:\n\t\t\t\tcase 0xAB:\n\t\t\t\tcase 0xAC:\n\t\t\t\tcase 0xAD:\n\t\t\t\tcase 0xAE:\n\t\t\t\tcase 0xAF:\n\t\t\t\tcase 0xB0:\n\t\t\t\tcase 0xB1:\n\t\t\t\tcase 0xB2:\n\t\t\t\tcase 0xB3:\n\t\t\t\tcase 0xB4:\n\t\t\t\tcase 0xB5:\n\t\t\t\tcase 0xB6:\n\t\t\t\tcase 0xB7:\n\t\t\t\t\treturn get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));\n\n\t\t\t\tcase 0xB8: // map (one-byte uint8_t for n follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xB9: // map (two-byte uint16_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xBA: // map (four-byte uint32_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xBB: // map (eight-byte uint64_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint64_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xBF: // map (indefinite length)\n\t\t\t\t\treturn get_cbor_object(std::size_t(-1));\n\n\t\t\t\tcase 0xF4: // false\n\t\t\t\t\treturn sax->boolean(false);\n\n\t\t\t\tcase 0xF5: // true\n\t\t\t\t\treturn sax->boolean(true);\n\n\t\t\t\tcase 0xF6: // null\n\t\t\t\t\treturn sax->null();\n\n\t\t\t\tcase 0xF9: // Half-Precision Float (two-byte IEEE 754)\n\t\t\t\t{\n\t\t\t\t\tconst int byte1_raw = get();\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"number\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tconst int byte2_raw = get();\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"number\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst auto byte1 = static_cast<unsigned char>(byte1_raw);\n\t\t\t\t\tconst auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n\t\t\t\t\t// code from RFC 7049, Appendix D, Figure 3:\n\t\t\t\t\t// As half-precision floating-point numbers were only added\n\t\t\t\t\t// to IEEE 754 in 2008, today's programming platforms often\n\t\t\t\t\t// still only have limited support for them. It is very\n\t\t\t\t\t// easy to include at least decoding support for them even\n\t\t\t\t\t// without such support. An example of a small decoder for\n\t\t\t\t\t// half-precision floating-point numbers in the C language\n\t\t\t\t\t// is shown in Fig. 3.\n\t\t\t\t\tconst auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);\n\t\t\t\t\tconst double val = [&half]\n\t\t\t\t\t{\n\t\t\t\t\t\tconst int exp = (half >> 10u) & 0x1Fu;\n\t\t\t\t\t\tconst unsigned int mant = half & 0x3FFu;\n\t\t\t\t\t\tassert(0 <= exp and exp <= 32);\n\t\t\t\t\t\tassert(0 <= mant and mant <= 1024);\n\t\t\t\t\t\tswitch (exp)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase 0:\n\t\t\t\t\t\t\treturn std::ldexp(mant, -24);\n\t\t\t\t\t\tcase 31:\n\t\t\t\t\t\t\treturn (mant == 0)\n\t\t\t\t\t\t\t\t? std::numeric_limits<double>::infinity()\n\t\t\t\t\t\t\t\t: std::numeric_limits<double>::quiet_NaN();\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn std::ldexp(mant + 1024, exp - 25);\n\t\t\t\t\t\t}\n\t\t\t\t\t}();\n\t\t\t\t\treturn sax->number_float((half & 0x8000u) != 0\n\t\t\t\t\t\t? static_cast<number_float_t>(-val)\n\t\t\t\t\t\t: static_cast<number_float_t>(val), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 0xFA: // Single-Precision Float (four-byte IEEE 754)\n\t\t\t\t{\n\t\t\t\t\tfloat number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 0xFB: // Double-Precision Float (eight-byte IEEE 754)\n\t\t\t\t{\n\t\t\t\t\tdouble number;\n\t\t\t\t\treturn get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tdefault: // anything else (0xFF is handled inside the other types)\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\")));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief reads a CBOR string\n\n\t\t\tThis function first reads starting bytes to determine the expected\n\t\t\tstring length and then copies this number of bytes into a string.\n\t\t\tAdditionally, CBOR's strings with indefinite lengths are supported.\n\n\t\t\t@param[out] result  created string\n\n\t\t\t@return whether string creation completed\n\t\t\t*/\n\t\t\tbool get_cbor_string(string_t& result)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"string\")))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tswitch (current)\n\t\t\t\t{\n\t\t\t\t\t// UTF-8 string (0x00..0x17 bytes follow)\n\t\t\t\tcase 0x60:\n\t\t\t\tcase 0x61:\n\t\t\t\tcase 0x62:\n\t\t\t\tcase 0x63:\n\t\t\t\tcase 0x64:\n\t\t\t\tcase 0x65:\n\t\t\t\tcase 0x66:\n\t\t\t\tcase 0x67:\n\t\t\t\tcase 0x68:\n\t\t\t\tcase 0x69:\n\t\t\t\tcase 0x6A:\n\t\t\t\tcase 0x6B:\n\t\t\t\tcase 0x6C:\n\t\t\t\tcase 0x6D:\n\t\t\t\tcase 0x6E:\n\t\t\t\tcase 0x6F:\n\t\t\t\tcase 0x70:\n\t\t\t\tcase 0x71:\n\t\t\t\tcase 0x72:\n\t\t\t\tcase 0x73:\n\t\t\t\tcase 0x74:\n\t\t\t\tcase 0x75:\n\t\t\t\tcase 0x76:\n\t\t\t\tcase 0x77:\n\t\t\t\t{\n\t\t\t\t\treturn get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n\t\t\t\t{\n\t\t\t\t\tstd::uint64_t len;\n\t\t\t\t\treturn get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0x7F: // UTF-8 string (indefinite length)\n\t\t\t\t{\n\t\t\t\t\twhile (get() != 0xFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tstring_t chunk;\n\t\t\t\t\t\tif (not get_cbor_string(chunk))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult.append(chunk);\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x\" + last_token, \"string\")));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] len  the length of the array or std::size_t(-1) for an\n\t\t\t\t\t\t\tarray of indefinite size\n\t\t\t@return whether array creation completed\n\t\t\t*/\n\t\t\tbool get_cbor_array(const std::size_t len)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not sax->start_array(len)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (len != std::size_t(-1))\n\t\t\t\t{\n\t\t\t\t\tfor (std::size_t i = 0; i < len; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_cbor_internal()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twhile (get() != 0xFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_cbor_internal(false)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_array();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] len  the length of the object or std::size_t(-1) for an\n\t\t\t\t\t\t\tobject of indefinite size\n\t\t\t@return whether object creation completed\n\t\t\t*/\n\t\t\tbool get_cbor_object(const std::size_t len)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not sax->start_object(len)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tstring_t key;\n\t\t\t\tif (len != std::size_t(-1))\n\t\t\t\t{\n\t\t\t\t\tfor (std::size_t i = 0; i < len; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tget();\n\t\t\t\t\t\tif (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_cbor_internal()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tkey.clear();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twhile (get() != 0xFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_cbor_internal()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tkey.clear();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_object();\n\t\t\t}\n\n\t\t\t/////////////\n\t\t\t// MsgPack //\n\t\t\t/////////////\n\n\t\t\t/*!\n\t\t\t@return whether a valid MessagePack value was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_msgpack_internal()\n\t\t\t{\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\t\t// EOF\n\t\t\t\tcase std::char_traits<char>::eof():\n\t\t\t\t\treturn unexpect_eof(input_format_t::msgpack, \"value\");\n\n\t\t\t\t\t// positive fixint\n\t\t\t\tcase 0x00:\n\t\t\t\tcase 0x01:\n\t\t\t\tcase 0x02:\n\t\t\t\tcase 0x03:\n\t\t\t\tcase 0x04:\n\t\t\t\tcase 0x05:\n\t\t\t\tcase 0x06:\n\t\t\t\tcase 0x07:\n\t\t\t\tcase 0x08:\n\t\t\t\tcase 0x09:\n\t\t\t\tcase 0x0A:\n\t\t\t\tcase 0x0B:\n\t\t\t\tcase 0x0C:\n\t\t\t\tcase 0x0D:\n\t\t\t\tcase 0x0E:\n\t\t\t\tcase 0x0F:\n\t\t\t\tcase 0x10:\n\t\t\t\tcase 0x11:\n\t\t\t\tcase 0x12:\n\t\t\t\tcase 0x13:\n\t\t\t\tcase 0x14:\n\t\t\t\tcase 0x15:\n\t\t\t\tcase 0x16:\n\t\t\t\tcase 0x17:\n\t\t\t\tcase 0x18:\n\t\t\t\tcase 0x19:\n\t\t\t\tcase 0x1A:\n\t\t\t\tcase 0x1B:\n\t\t\t\tcase 0x1C:\n\t\t\t\tcase 0x1D:\n\t\t\t\tcase 0x1E:\n\t\t\t\tcase 0x1F:\n\t\t\t\tcase 0x20:\n\t\t\t\tcase 0x21:\n\t\t\t\tcase 0x22:\n\t\t\t\tcase 0x23:\n\t\t\t\tcase 0x24:\n\t\t\t\tcase 0x25:\n\t\t\t\tcase 0x26:\n\t\t\t\tcase 0x27:\n\t\t\t\tcase 0x28:\n\t\t\t\tcase 0x29:\n\t\t\t\tcase 0x2A:\n\t\t\t\tcase 0x2B:\n\t\t\t\tcase 0x2C:\n\t\t\t\tcase 0x2D:\n\t\t\t\tcase 0x2E:\n\t\t\t\tcase 0x2F:\n\t\t\t\tcase 0x30:\n\t\t\t\tcase 0x31:\n\t\t\t\tcase 0x32:\n\t\t\t\tcase 0x33:\n\t\t\t\tcase 0x34:\n\t\t\t\tcase 0x35:\n\t\t\t\tcase 0x36:\n\t\t\t\tcase 0x37:\n\t\t\t\tcase 0x38:\n\t\t\t\tcase 0x39:\n\t\t\t\tcase 0x3A:\n\t\t\t\tcase 0x3B:\n\t\t\t\tcase 0x3C:\n\t\t\t\tcase 0x3D:\n\t\t\t\tcase 0x3E:\n\t\t\t\tcase 0x3F:\n\t\t\t\tcase 0x40:\n\t\t\t\tcase 0x41:\n\t\t\t\tcase 0x42:\n\t\t\t\tcase 0x43:\n\t\t\t\tcase 0x44:\n\t\t\t\tcase 0x45:\n\t\t\t\tcase 0x46:\n\t\t\t\tcase 0x47:\n\t\t\t\tcase 0x48:\n\t\t\t\tcase 0x49:\n\t\t\t\tcase 0x4A:\n\t\t\t\tcase 0x4B:\n\t\t\t\tcase 0x4C:\n\t\t\t\tcase 0x4D:\n\t\t\t\tcase 0x4E:\n\t\t\t\tcase 0x4F:\n\t\t\t\tcase 0x50:\n\t\t\t\tcase 0x51:\n\t\t\t\tcase 0x52:\n\t\t\t\tcase 0x53:\n\t\t\t\tcase 0x54:\n\t\t\t\tcase 0x55:\n\t\t\t\tcase 0x56:\n\t\t\t\tcase 0x57:\n\t\t\t\tcase 0x58:\n\t\t\t\tcase 0x59:\n\t\t\t\tcase 0x5A:\n\t\t\t\tcase 0x5B:\n\t\t\t\tcase 0x5C:\n\t\t\t\tcase 0x5D:\n\t\t\t\tcase 0x5E:\n\t\t\t\tcase 0x5F:\n\t\t\t\tcase 0x60:\n\t\t\t\tcase 0x61:\n\t\t\t\tcase 0x62:\n\t\t\t\tcase 0x63:\n\t\t\t\tcase 0x64:\n\t\t\t\tcase 0x65:\n\t\t\t\tcase 0x66:\n\t\t\t\tcase 0x67:\n\t\t\t\tcase 0x68:\n\t\t\t\tcase 0x69:\n\t\t\t\tcase 0x6A:\n\t\t\t\tcase 0x6B:\n\t\t\t\tcase 0x6C:\n\t\t\t\tcase 0x6D:\n\t\t\t\tcase 0x6E:\n\t\t\t\tcase 0x6F:\n\t\t\t\tcase 0x70:\n\t\t\t\tcase 0x71:\n\t\t\t\tcase 0x72:\n\t\t\t\tcase 0x73:\n\t\t\t\tcase 0x74:\n\t\t\t\tcase 0x75:\n\t\t\t\tcase 0x76:\n\t\t\t\tcase 0x77:\n\t\t\t\tcase 0x78:\n\t\t\t\tcase 0x79:\n\t\t\t\tcase 0x7A:\n\t\t\t\tcase 0x7B:\n\t\t\t\tcase 0x7C:\n\t\t\t\tcase 0x7D:\n\t\t\t\tcase 0x7E:\n\t\t\t\tcase 0x7F:\n\t\t\t\t\treturn sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n\t\t\t\t\t// fixmap\n\t\t\t\tcase 0x80:\n\t\t\t\tcase 0x81:\n\t\t\t\tcase 0x82:\n\t\t\t\tcase 0x83:\n\t\t\t\tcase 0x84:\n\t\t\t\tcase 0x85:\n\t\t\t\tcase 0x86:\n\t\t\t\tcase 0x87:\n\t\t\t\tcase 0x88:\n\t\t\t\tcase 0x89:\n\t\t\t\tcase 0x8A:\n\t\t\t\tcase 0x8B:\n\t\t\t\tcase 0x8C:\n\t\t\t\tcase 0x8D:\n\t\t\t\tcase 0x8E:\n\t\t\t\tcase 0x8F:\n\t\t\t\t\treturn get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n\t\t\t\t\t// fixarray\n\t\t\t\tcase 0x90:\n\t\t\t\tcase 0x91:\n\t\t\t\tcase 0x92:\n\t\t\t\tcase 0x93:\n\t\t\t\tcase 0x94:\n\t\t\t\tcase 0x95:\n\t\t\t\tcase 0x96:\n\t\t\t\tcase 0x97:\n\t\t\t\tcase 0x98:\n\t\t\t\tcase 0x99:\n\t\t\t\tcase 0x9A:\n\t\t\t\tcase 0x9B:\n\t\t\t\tcase 0x9C:\n\t\t\t\tcase 0x9D:\n\t\t\t\tcase 0x9E:\n\t\t\t\tcase 0x9F:\n\t\t\t\t\treturn get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n\t\t\t\t\t// fixstr\n\t\t\t\tcase 0xA0:\n\t\t\t\tcase 0xA1:\n\t\t\t\tcase 0xA2:\n\t\t\t\tcase 0xA3:\n\t\t\t\tcase 0xA4:\n\t\t\t\tcase 0xA5:\n\t\t\t\tcase 0xA6:\n\t\t\t\tcase 0xA7:\n\t\t\t\tcase 0xA8:\n\t\t\t\tcase 0xA9:\n\t\t\t\tcase 0xAA:\n\t\t\t\tcase 0xAB:\n\t\t\t\tcase 0xAC:\n\t\t\t\tcase 0xAD:\n\t\t\t\tcase 0xAE:\n\t\t\t\tcase 0xAF:\n\t\t\t\tcase 0xB0:\n\t\t\t\tcase 0xB1:\n\t\t\t\tcase 0xB2:\n\t\t\t\tcase 0xB3:\n\t\t\t\tcase 0xB4:\n\t\t\t\tcase 0xB5:\n\t\t\t\tcase 0xB6:\n\t\t\t\tcase 0xB7:\n\t\t\t\tcase 0xB8:\n\t\t\t\tcase 0xB9:\n\t\t\t\tcase 0xBA:\n\t\t\t\tcase 0xBB:\n\t\t\t\tcase 0xBC:\n\t\t\t\tcase 0xBD:\n\t\t\t\tcase 0xBE:\n\t\t\t\tcase 0xBF:\n\t\t\t\t{\n\t\t\t\t\tstring_t s;\n\t\t\t\t\treturn get_msgpack_string(s) and sax->string(s);\n\t\t\t\t}\n\n\t\t\t\tcase 0xC0: // nil\n\t\t\t\t\treturn sax->null();\n\n\t\t\t\tcase 0xC2: // false\n\t\t\t\t\treturn sax->boolean(false);\n\n\t\t\t\tcase 0xC3: // true\n\t\t\t\t\treturn sax->boolean(true);\n\n\t\t\t\tcase 0xCA: // float 32\n\t\t\t\t{\n\t\t\t\t\tfloat number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 0xCB: // float 64\n\t\t\t\t{\n\t\t\t\t\tdouble number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 0xCC: // uint 8\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xCD: // uint 16\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xCE: // uint 32\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xCF: // uint 64\n\t\t\t\t{\n\t\t\t\t\tstd::uint64_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xD0: // int 8\n\t\t\t\t{\n\t\t\t\t\tstd::int8_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xD1: // int 16\n\t\t\t\t{\n\t\t\t\t\tstd::int16_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xD2: // int 32\n\t\t\t\t{\n\t\t\t\t\tstd::int32_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xD3: // int 64\n\t\t\t\t{\n\t\t\t\t\tstd::int64_t number;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 0xD9: // str 8\n\t\t\t\tcase 0xDA: // str 16\n\t\t\t\tcase 0xDB: // str 32\n\t\t\t\t{\n\t\t\t\t\tstring_t s;\n\t\t\t\t\treturn get_msgpack_string(s) and sax->string(s);\n\t\t\t\t}\n\n\t\t\t\tcase 0xDC: // array 16\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xDD: // array 32\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xDE: // map 16\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\tcase 0xDF: // map 32\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));\n\t\t\t\t}\n\n\t\t\t\t// negative fixint\n\t\t\t\tcase 0xE0:\n\t\t\t\tcase 0xE1:\n\t\t\t\tcase 0xE2:\n\t\t\t\tcase 0xE3:\n\t\t\t\tcase 0xE4:\n\t\t\t\tcase 0xE5:\n\t\t\t\tcase 0xE6:\n\t\t\t\tcase 0xE7:\n\t\t\t\tcase 0xE8:\n\t\t\t\tcase 0xE9:\n\t\t\t\tcase 0xEA:\n\t\t\t\tcase 0xEB:\n\t\t\t\tcase 0xEC:\n\t\t\t\tcase 0xED:\n\t\t\t\tcase 0xEE:\n\t\t\t\tcase 0xEF:\n\t\t\t\tcase 0xF0:\n\t\t\t\tcase 0xF1:\n\t\t\t\tcase 0xF2:\n\t\t\t\tcase 0xF3:\n\t\t\t\tcase 0xF4:\n\t\t\t\tcase 0xF5:\n\t\t\t\tcase 0xF6:\n\t\t\t\tcase 0xF7:\n\t\t\t\tcase 0xF8:\n\t\t\t\tcase 0xF9:\n\t\t\t\tcase 0xFA:\n\t\t\t\tcase 0xFB:\n\t\t\t\tcase 0xFC:\n\t\t\t\tcase 0xFD:\n\t\t\t\tcase 0xFE:\n\t\t\t\tcase 0xFF:\n\t\t\t\t\treturn sax->number_integer(static_cast<std::int8_t>(current));\n\n\t\t\t\tdefault: // anything else\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, \"invalid byte: 0x\" + last_token, \"value\")));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief reads a MessagePack string\n\n\t\t\tThis function first reads starting bytes to determine the expected\n\t\t\tstring length and then copies this number of bytes into a string.\n\n\t\t\t@param[out] result  created string\n\n\t\t\t@return whether string creation completed\n\t\t\t*/\n\t\t\tbool get_msgpack_string(string_t& result)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, \"string\")))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tswitch (current)\n\t\t\t\t{\n\t\t\t\t\t// fixstr\n\t\t\t\tcase 0xA0:\n\t\t\t\tcase 0xA1:\n\t\t\t\tcase 0xA2:\n\t\t\t\tcase 0xA3:\n\t\t\t\tcase 0xA4:\n\t\t\t\tcase 0xA5:\n\t\t\t\tcase 0xA6:\n\t\t\t\tcase 0xA7:\n\t\t\t\tcase 0xA8:\n\t\t\t\tcase 0xA9:\n\t\t\t\tcase 0xAA:\n\t\t\t\tcase 0xAB:\n\t\t\t\tcase 0xAC:\n\t\t\t\tcase 0xAD:\n\t\t\t\tcase 0xAE:\n\t\t\t\tcase 0xAF:\n\t\t\t\tcase 0xB0:\n\t\t\t\tcase 0xB1:\n\t\t\t\tcase 0xB2:\n\t\t\t\tcase 0xB3:\n\t\t\t\tcase 0xB4:\n\t\t\t\tcase 0xB5:\n\t\t\t\tcase 0xB6:\n\t\t\t\tcase 0xB7:\n\t\t\t\tcase 0xB8:\n\t\t\t\tcase 0xB9:\n\t\t\t\tcase 0xBA:\n\t\t\t\tcase 0xBB:\n\t\t\t\tcase 0xBC:\n\t\t\t\tcase 0xBD:\n\t\t\t\tcase 0xBE:\n\t\t\t\tcase 0xBF:\n\t\t\t\t{\n\t\t\t\t\treturn get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0xD9: // str 8\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0xDA: // str 16\n\t\t\t\t{\n\t\t\t\t\tstd::uint16_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 0xDB: // str 32\n\t\t\t\t{\n\t\t\t\t\tstd::uint32_t len;\n\t\t\t\t\treturn get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, \"expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x\" + last_token, \"string\")));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] len  the length of the array\n\t\t\t@return whether array creation completed\n\t\t\t*/\n\t\t\tbool get_msgpack_array(const std::size_t len)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not sax->start_array(len)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tfor (std::size_t i = 0; i < len; ++i)\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(not parse_msgpack_internal()))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_array();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] len  the length of the object\n\t\t\t@return whether object creation completed\n\t\t\t*/\n\t\t\tbool get_msgpack_object(const std::size_t len)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not sax->start_object(len)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tstring_t key;\n\t\t\t\tfor (std::size_t i = 0; i < len; ++i)\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t\tif (JSON_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (JSON_UNLIKELY(not parse_msgpack_internal()))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tkey.clear();\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_object();\n\t\t\t}\n\n\t\t\t////////////\n\t\t\t// UBJSON //\n\t\t\t////////////\n\n\t\t\t/*!\n\t\t\t@param[in] get_char  whether a new character should be retrieved from the\n\t\t\t\t\t\t\t\t input (true, default) or whether the last read\n\t\t\t\t\t\t\t\t character should be considered instead\n\n\t\t\t@return whether a valid UBJSON value was passed to the SAX parser\n\t\t\t*/\n\t\t\tbool parse_ubjson_internal(const bool get_char = true)\n\t\t\t{\n\t\t\t\treturn get_ubjson_value(get_char ? get_ignore_noop() : current);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief reads a UBJSON string\n\n\t\t\tThis function is either called after reading the 'S' byte explicitly\n\t\t\tindicating a string, or in case of an object key where the 'S' byte can be\n\t\t\tleft out.\n\n\t\t\t@param[out] result   created string\n\t\t\t@param[in] get_char  whether a new character should be retrieved from the\n\t\t\t\t\t\t\t\t input (true, default) or whether the last read\n\t\t\t\t\t\t\t\t character should be considered instead\n\n\t\t\t@return whether string creation completed\n\t\t\t*/\n\t\t\tbool get_ubjson_string(string_t& result, const bool get_char = true)\n\t\t\t{\n\t\t\t\tif (get_char)\n\t\t\t\t{\n\t\t\t\t\tget();  // TODO(niels): may we ignore N here?\n\t\t\t\t}\n\n\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"value\")))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tswitch (current)\n\t\t\t\t{\n\t\t\t\tcase 'U':\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t len;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 'i':\n\t\t\t\t{\n\t\t\t\t\tstd::int8_t len;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 'I':\n\t\t\t\t{\n\t\t\t\t\tstd::int16_t len;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 'l':\n\t\t\t\t{\n\t\t\t\t\tstd::int32_t len;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n\t\t\t\t}\n\n\t\t\t\tcase 'L':\n\t\t\t\t{\n\t\t\t\t\tstd::int64_t len;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L); last byte: 0x\" + last_token, \"string\")));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[out] result  determined size\n\t\t\t@return whether size determination completed\n\t\t\t*/\n\t\t\tbool get_ubjson_size_value(std::size_t& result)\n\t\t\t{\n\t\t\t\tswitch (get_ignore_noop())\n\t\t\t\t{\n\t\t\t\tcase 'U':\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t number;\n\t\t\t\t\tif (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tresult = static_cast<std::size_t>(number);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tcase 'i':\n\t\t\t\t{\n\t\t\t\t\tstd::int8_t number;\n\t\t\t\t\tif (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tresult = static_cast<std::size_t>(number);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tcase 'I':\n\t\t\t\t{\n\t\t\t\t\tstd::int16_t number;\n\t\t\t\t\tif (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tresult = static_cast<std::size_t>(number);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tcase 'l':\n\t\t\t\t{\n\t\t\t\t\tstd::int32_t number;\n\t\t\t\t\tif (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tresult = static_cast<std::size_t>(number);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tcase 'L':\n\t\t\t\t{\n\t\t\t\t\tstd::int64_t number;\n\t\t\t\t\tif (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tresult = static_cast<std::size_t>(number);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L) after '#'; last byte: 0x\" + last_token, \"size\")));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief determine the type and size for a container\n\n\t\t\tIn the optimized UBJSON format, a type and a size can be provided to allow\n\t\t\tfor a more compact representation.\n\n\t\t\t@param[out] result  pair of the size and the type\n\n\t\t\t@return whether pair creation completed\n\t\t\t*/\n\t\t\tbool get_ubjson_size_type(std::pair<std::size_t, int>& result)\n\t\t\t{\n\t\t\t\tresult.first = string_t::npos; // size\n\t\t\t\tresult.second = 0; // type\n\n\t\t\t\tget_ignore_noop();\n\n\t\t\t\tif (current == '$')\n\t\t\t\t{\n\t\t\t\t\tresult.second = get();  // must not ignore 'N', because 'N' maybe the type\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"type\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tget_ignore_noop();\n\t\t\t\t\tif (JSON_UNLIKELY(current != '#'))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"value\")))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"expected '#' after type information; last byte: 0x\" + last_token, \"size\")));\n\t\t\t\t\t}\n\n\t\t\t\t\treturn get_ubjson_size_value(result.first);\n\t\t\t\t}\n\n\t\t\t\tif (current == '#')\n\t\t\t\t{\n\t\t\t\t\treturn get_ubjson_size_value(result.first);\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param prefix  the previously read or set type prefix\n\t\t\t@return whether value creation completed\n\t\t\t*/\n\t\t\tbool get_ubjson_value(const int prefix)\n\t\t\t{\n\t\t\t\tswitch (prefix)\n\t\t\t\t{\n\t\t\t\tcase std::char_traits<char>::eof():  // EOF\n\t\t\t\t\treturn unexpect_eof(input_format_t::ubjson, \"value\");\n\n\t\t\t\tcase 'T':  // true\n\t\t\t\t\treturn sax->boolean(true);\n\t\t\t\tcase 'F':  // false\n\t\t\t\t\treturn sax->boolean(false);\n\n\t\t\t\tcase 'Z':  // null\n\t\t\t\t\treturn sax->null();\n\n\t\t\t\tcase 'U':\n\t\t\t\t{\n\t\t\t\t\tstd::uint8_t number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);\n\t\t\t\t}\n\n\t\t\t\tcase 'i':\n\t\t\t\t{\n\t\t\t\t\tstd::int8_t number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 'I':\n\t\t\t\t{\n\t\t\t\t\tstd::int16_t number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 'l':\n\t\t\t\t{\n\t\t\t\t\tstd::int32_t number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 'L':\n\t\t\t\t{\n\t\t\t\t\tstd::int64_t number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n\t\t\t\t}\n\n\t\t\t\tcase 'd':\n\t\t\t\t{\n\t\t\t\t\tfloat number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 'D':\n\t\t\t\t{\n\t\t\t\t\tdouble number;\n\t\t\t\t\treturn get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n\t\t\t\t}\n\n\t\t\t\tcase 'C':  // char\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"char\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (JSON_UNLIKELY(current > 127))\n\t\t\t\t\t{\n\t\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"byte after 'C' must be in range 0x00..0x7F; last byte: 0x\" + last_token, \"char\")));\n\t\t\t\t\t}\n\t\t\t\t\tstring_t s(1, static_cast<char>(current));\n\t\t\t\t\treturn sax->string(s);\n\t\t\t\t}\n\n\t\t\t\tcase 'S':  // string\n\t\t\t\t{\n\t\t\t\t\tstring_t s;\n\t\t\t\t\treturn get_ubjson_string(s) and sax->string(s);\n\t\t\t\t}\n\n\t\t\t\tcase '[':  // array\n\t\t\t\t\treturn get_ubjson_array();\n\n\t\t\t\tcase '{':  // object\n\t\t\t\t\treturn get_ubjson_object();\n\n\t\t\t\tdefault: // anything else\n\t\t\t\t{\n\t\t\t\t\tauto last_token = get_token_string();\n\t\t\t\t\treturn sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"invalid byte: 0x\" + last_token, \"value\")));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return whether array creation completed\n\t\t\t*/\n\t\t\tbool get_ubjson_array()\n\t\t\t{\n\t\t\t\tstd::pair<std::size_t, int> size_and_type;\n\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (size_and_type.first != string_t::npos)\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(not sax->start_array(size_and_type.first)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (size_and_type.second != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (size_and_type.second != 'N')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (std::size_t i = 0; i < size_and_type.first; ++i)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (std::size_t i = 0; i < size_and_type.first; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_ubjson_internal()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (current != ']')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_ubjson_internal(false)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tget_ignore_noop();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_array();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return whether object creation completed\n\t\t\t*/\n\t\t\tbool get_ubjson_object()\n\t\t\t{\n\t\t\t\tstd::pair<std::size_t, int> size_and_type;\n\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tstring_t key;\n\t\t\t\tif (size_and_type.first != string_t::npos)\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(not sax->start_object(size_and_type.first)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (size_and_type.second != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (std::size_t i = 0; i < size_and_type.first; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tkey.clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (std::size_t i = 0; i < size_and_type.first; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_ubjson_internal()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tkey.clear();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (current != '}')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (JSON_UNLIKELY(not parse_ubjson_internal()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tget_ignore_noop();\n\t\t\t\t\t\tkey.clear();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn sax->end_object();\n\t\t\t}\n\n\t\t\t///////////////////////\n\t\t\t// Utility functions //\n\t\t\t///////////////////////\n\n\t\t\t/*!\n\t\t\t@brief get next character from the input\n\n\t\t\tThis function provides the interface to the used input adapter. It does\n\t\t\tnot throw in case the input reached EOF, but returns a -'ve valued\n\t\t\t`std::char_traits<char>::eof()` in that case.\n\n\t\t\t@return character read from the input\n\t\t\t*/\n\t\t\tint get()\n\t\t\t{\n\t\t\t\t++chars_read;\n\t\t\t\treturn current = ia->get_character();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return character read from the input after ignoring all 'N' entries\n\t\t\t*/\n\t\t\tint get_ignore_noop()\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t} while (current == 'N');\n\n\t\t\t\treturn current;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t@brief read a number from the input\n\n\t\t\t@tparam NumberType the type of the number\n\t\t\t@param[in] format   the current format (for diagnostics)\n\t\t\t@param[out] result  number of type @a NumberType\n\n\t\t\t@return whether conversion completed\n\n\t\t\t@note This function needs to respect the system's endianess, because\n\t\t\t\t  bytes in CBOR, MessagePack, and UBJSON are stored in network order\n\t\t\t\t  (big endian) and therefore need reordering on little endian systems.\n\t\t\t*/\n\t\t\ttemplate<typename NumberType, bool InputIsLittleEndian = false>\n\t\t\tbool get_number(const input_format_t format, NumberType& result)\n\t\t\t{\n\t\t\t\t// step 1: read input into array with system's byte order\n\t\t\t\tstd::array<std::uint8_t, sizeof(NumberType)> vec;\n\t\t\t\tfor (std::size_t i = 0; i < sizeof(NumberType); ++i)\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(format, \"number\")))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// reverse byte order prior to conversion if necessary\n\t\t\t\t\tif (is_little_endian != InputIsLittleEndian)\n\t\t\t\t\t{\n\t\t\t\t\t\tvec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tvec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// step 2: convert array into number of type T and return\n\t\t\t\tstd::memcpy(&result, vec.data(), sizeof(NumberType));\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief create a string by reading characters from the input\n\n\t\t\t@tparam NumberType the type of the number\n\t\t\t@param[in] format the current format (for diagnostics)\n\t\t\t@param[in] len number of characters to read\n\t\t\t@param[out] result string created by reading @a len bytes\n\n\t\t\t@return whether string creation completed\n\n\t\t\t@note We can not reserve @a len bytes for the result, because @a len\n\t\t\t\t  may be too large. Usually, @ref unexpect_eof() detects the end of\n\t\t\t\t  the input before we run out of string memory.\n\t\t\t*/\n\t\t\ttemplate<typename NumberType>\n\t\t\tbool get_string(const input_format_t format,\n\t\t\t\tconst NumberType len,\n\t\t\t\tstring_t& result)\n\t\t\t{\n\t\t\t\tbool success = true;\n\t\t\t\tstd::generate_n(std::back_inserter(result), len, [this, &success, &format]()\n\t\t\t\t\t{\n\t\t\t\t\t\tget();\n\t\t\t\t\t\tif (JSON_UNLIKELY(not unexpect_eof(format, \"string\")))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsuccess = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn static_cast<char>(current);\n\t\t\t\t\t});\n\t\t\t\treturn success;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] format   the current format (for diagnostics)\n\t\t\t@param[in] context  further context information (for diagnostics)\n\t\t\t@return whether the last read character is not EOF\n\t\t\t*/\n\t\t\tbool unexpect_eof(const input_format_t format, const char* context) const\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(current == std::char_traits<char>::eof()))\n\t\t\t\t{\n\t\t\t\t\treturn sax->parse_error(chars_read, \"<end of file>\",\n\t\t\t\t\t\tparse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context)));\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return a string representation of the last read byte\n\t\t\t*/\n\t\t\tstd::string get_token_string() const\n\t\t\t{\n\t\t\t\tstd::array<char, 3> cr{ {} };\n\t\t\t\t(std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(current));\n\t\t\t\treturn std::string{ cr.data() };\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] format   the current format\n\t\t\t@param[in] detail   a detailed error message\n\t\t\t@param[in] context  further contect information\n\t\t\t@return a message string to use in the parse_error exceptions\n\t\t\t*/\n\t\t\tstd::string exception_message(const input_format_t format,\n\t\t\t\tconst std::string& detail,\n\t\t\t\tconst std::string& context) const\n\t\t\t{\n\t\t\t\tstd::string error_msg = \"syntax error while parsing \";\n\n\t\t\t\tswitch (format)\n\t\t\t\t{\n\t\t\t\tcase input_format_t::cbor:\n\t\t\t\t\terror_msg += \"CBOR\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase input_format_t::msgpack:\n\t\t\t\t\terror_msg += \"MessagePack\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase input_format_t::ubjson:\n\t\t\t\t\terror_msg += \"UBJSON\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase input_format_t::bson:\n\t\t\t\t\terror_msg += \"BSON\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t}\n\n\t\t\t\treturn error_msg + \" \" + context + \": \" + detail;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// input adapter\n\t\t\tinput_adapter_t ia = nullptr;\n\n\t\t\t/// the current character\n\t\t\tint current = std::char_traits<char>::eof();\n\n\t\t\t/// the number of characters read\n\t\t\tstd::size_t chars_read = 0;\n\n\t\t\t/// whether we can assume little endianess\n\t\t\tconst bool is_little_endian = little_endianess();\n\n\t\t\t/// the SAX parser\n\t\t\tjson_sax_t* sax = nullptr;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n\n#include <array> // array\n#include <clocale> // localeconv\n#include <cstddef> // size_t\n#include <cstdio> // snprintf\n#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull\n#include <initializer_list> // initializer_list\n#include <string> // char_traits, string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t///////////\n\t\t// lexer //\n\t\t///////////\n\n\t\t/*!\n\t\t@brief lexical analysis\n\n\t\tThis class organizes the lexical analysis during JSON deserialization.\n\t\t*/\n\t\ttemplate<typename BasicJsonType>\n\t\tclass lexer\n\t\t{\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\n\t\tpublic:\n\t\t\t/// token types for the parser\n\t\t\tenum class token_type\n\t\t\t{\n\t\t\t\tuninitialized,    ///< indicating the scanner is uninitialized\n\t\t\t\tliteral_true,     ///< the `true` literal\n\t\t\t\tliteral_false,    ///< the `false` literal\n\t\t\t\tliteral_null,     ///< the `null` literal\n\t\t\t\tvalue_string,     ///< a string -- use get_string() for actual value\n\t\t\t\tvalue_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value\n\t\t\t\tvalue_integer,    ///< a signed integer -- use get_number_integer() for actual value\n\t\t\t\tvalue_float,      ///< an floating point number -- use get_number_float() for actual value\n\t\t\t\tbegin_array,      ///< the character for array begin `[`\n\t\t\t\tbegin_object,     ///< the character for object begin `{`\n\t\t\t\tend_array,        ///< the character for array end `]`\n\t\t\t\tend_object,       ///< the character for object end `}`\n\t\t\t\tname_separator,   ///< the name separator `:`\n\t\t\t\tvalue_separator,  ///< the value separator `,`\n\t\t\t\tparse_error,      ///< indicating a parse error\n\t\t\t\tend_of_input,     ///< indicating the end of the input buffer\n\t\t\t\tliteral_or_value  ///< a literal or the begin of a value (only for diagnostics)\n\t\t\t};\n\n\t\t\t/// return name of values of type token_type (only used for errors)\n\t\t\tstatic const char* token_type_name(const token_type t) noexcept\n\t\t\t{\n\t\t\t\tswitch (t)\n\t\t\t\t{\n\t\t\t\tcase token_type::uninitialized:\n\t\t\t\t\treturn \"<uninitialized>\";\n\t\t\t\tcase token_type::literal_true:\n\t\t\t\t\treturn \"true literal\";\n\t\t\t\tcase token_type::literal_false:\n\t\t\t\t\treturn \"false literal\";\n\t\t\t\tcase token_type::literal_null:\n\t\t\t\t\treturn \"null literal\";\n\t\t\t\tcase token_type::value_string:\n\t\t\t\t\treturn \"string literal\";\n\t\t\t\tcase lexer::token_type::value_unsigned:\n\t\t\t\tcase lexer::token_type::value_integer:\n\t\t\t\tcase lexer::token_type::value_float:\n\t\t\t\t\treturn \"number literal\";\n\t\t\t\tcase token_type::begin_array:\n\t\t\t\t\treturn \"'['\";\n\t\t\t\tcase token_type::begin_object:\n\t\t\t\t\treturn \"'{'\";\n\t\t\t\tcase token_type::end_array:\n\t\t\t\t\treturn \"']'\";\n\t\t\t\tcase token_type::end_object:\n\t\t\t\t\treturn \"'}'\";\n\t\t\t\tcase token_type::name_separator:\n\t\t\t\t\treturn \"':'\";\n\t\t\t\tcase token_type::value_separator:\n\t\t\t\t\treturn \"','\";\n\t\t\t\tcase token_type::parse_error:\n\t\t\t\t\treturn \"<parse error>\";\n\t\t\t\tcase token_type::end_of_input:\n\t\t\t\t\treturn \"end of input\";\n\t\t\t\tcase token_type::literal_or_value:\n\t\t\t\t\treturn \"'[', '{', or a literal\";\n\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\tdefault: // catch non-enum values\n\t\t\t\t\treturn \"unknown token\";\n\t\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t\t}\n\t\t\t}\n\n\t\t\texplicit lexer(detail::input_adapter_t&& adapter)\n\t\t\t\t: ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}\n\n\t\t\t// delete because of pointer members\n\t\t\tlexer(const lexer&) = delete;\n\t\t\tlexer(lexer&&) = delete;\n\t\t\tlexer& operator=(lexer&) = delete;\n\t\t\tlexer& operator=(lexer&&) = delete;\n\t\t\t~lexer() = default;\n\n\t\tprivate:\n\t\t\t/////////////////////\n\t\t\t// locales\n\t\t\t/////////////////////\n\n\t\t\t/// return the locale-dependent decimal point\n\t\t\tstatic char get_decimal_point() noexcept\n\t\t\t{\n\t\t\t\tconst auto loc = localeconv();\n\t\t\t\tassert(loc != nullptr);\n\t\t\t\treturn (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);\n\t\t\t}\n\n\t\t\t/////////////////////\n\t\t\t// scan functions\n\t\t\t/////////////////////\n\n\t\t\t/*!\n\t\t\t@brief get codepoint from 4 hex characters following `\\u`\n\n\t\t\tFor input \"\\u c1 c2 c3 c4\" the codepoint is:\n\t\t\t  (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4\n\t\t\t= (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)\n\n\t\t\tFurthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'\n\t\t\tmust be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The\n\t\t\tconversion is done by subtracting the offset (0x30, 0x37, and 0x57)\n\t\t\tbetween the ASCII value of the character and the desired integer value.\n\n\t\t\t@return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or\n\t\t\t\t\tnon-hex character)\n\t\t\t*/\n\t\t\tint get_codepoint()\n\t\t\t{\n\t\t\t\t// this function only makes sense after reading `\\u`\n\t\t\t\tassert(current == 'u');\n\t\t\t\tint codepoint = 0;\n\n\t\t\t\tconst auto factors = { 12u, 8u, 4u, 0u };\n\t\t\t\tfor (const auto factor : factors)\n\t\t\t\t{\n\t\t\t\t\tget();\n\n\t\t\t\t\tif (current >= '0' and current <= '9')\n\t\t\t\t\t{\n\t\t\t\t\t\tcodepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);\n\t\t\t\t\t}\n\t\t\t\t\telse if (current >= 'A' and current <= 'F')\n\t\t\t\t\t{\n\t\t\t\t\t\tcodepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);\n\t\t\t\t\t}\n\t\t\t\t\telse if (current >= 'a' and current <= 'f')\n\t\t\t\t\t{\n\t\t\t\t\t\tcodepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tassert(0x0000 <= codepoint and codepoint <= 0xFFFF);\n\t\t\t\treturn codepoint;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief check if the next byte(s) are inside a given range\n\n\t\t\tAdds the current byte and, for each passed range, reads a new byte and\n\t\t\tchecks if it is inside the range. If a violation was detected, set up an\n\t\t\terror message and return false. Otherwise, return true.\n\n\t\t\t@param[in] ranges  list of integers; interpreted as list of pairs of\n\t\t\t\t\t\t\t   inclusive lower and upper bound, respectively\n\n\t\t\t@pre The passed list @a ranges must have 2, 4, or 6 elements; that is,\n\t\t\t\t 1, 2, or 3 pairs. This precondition is enforced by an assertion.\n\n\t\t\t@return true if and only if no range violation was detected\n\t\t\t*/\n\t\t\tbool next_byte_in_range(std::initializer_list<int> ranges)\n\t\t\t{\n\t\t\t\tassert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);\n\t\t\t\tadd(current);\n\n\t\t\t\tfor (auto range = ranges.begin(); range != ranges.end(); ++range)\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t\tif (JSON_LIKELY(*range <= current and current <= *(++range)))\n\t\t\t\t\t{\n\t\t\t\t\t\tadd(current);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: ill-formed UTF-8 byte\";\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief scan a string literal\n\n\t\t\tThis function scans a string according to Sect. 7 of RFC 7159. While\n\t\t\tscanning, bytes are escaped and copied into buffer token_buffer. Then the\n\t\t\tfunction returns successfully, token_buffer is *not* null-terminated (as it\n\t\t\tmay contain \\0 bytes), and token_buffer.size() is the number of bytes in the\n\t\t\tstring.\n\n\t\t\t@return token_type::value_string if string could be successfully scanned,\n\t\t\t\t\ttoken_type::parse_error otherwise\n\n\t\t\t@note In case of errors, variable error_message contains a textual\n\t\t\t\t  description.\n\t\t\t*/\n\t\t\ttoken_type scan_string()\n\t\t\t{\n\t\t\t\t// reset token_buffer (ignore opening quote)\n\t\t\t\treset();\n\n\t\t\t\t// we entered the function by reading an open quote\n\t\t\t\tassert(current == '\\\"');\n\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\t// get next character\n\t\t\t\t\tswitch (get())\n\t\t\t\t\t{\n\t\t\t\t\t\t// end of file while parsing string\n\t\t\t\t\tcase std::char_traits<char>::eof():\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: missing closing quote\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// closing quote\n\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t{\n\t\t\t\t\t\treturn token_type::value_string;\n\t\t\t\t\t}\n\n\t\t\t\t\t// escapes\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (get())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// quotation mark\n\t\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t\t\tadd('\\\"');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// reverse solidus\n\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\tadd('\\\\');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// solidus\n\t\t\t\t\t\tcase '/':\n\t\t\t\t\t\t\tadd('/');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// backspace\n\t\t\t\t\t\tcase 'b':\n\t\t\t\t\t\t\tadd('\\b');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// form feed\n\t\t\t\t\t\tcase 'f':\n\t\t\t\t\t\t\tadd('\\f');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// line feed\n\t\t\t\t\t\tcase 'n':\n\t\t\t\t\t\t\tadd('\\n');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// carriage return\n\t\t\t\t\t\tcase 'r':\n\t\t\t\t\t\t\tadd('\\r');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// tab\n\t\t\t\t\t\tcase 't':\n\t\t\t\t\t\t\tadd('\\t');\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t// unicode escapes\n\t\t\t\t\t\tcase 'u':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst int codepoint1 = get_codepoint();\n\t\t\t\t\t\t\tint codepoint = codepoint1; // start with codepoint1\n\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(codepoint1 == -1))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\terror_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n\t\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// check if code point is a high surrogate\n\t\t\t\t\t\t\tif (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// expect next \\uxxxx entry\n\t\t\t\t\t\t\t\tif (JSON_LIKELY(get() == '\\\\' and get() == 'u'))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst int codepoint2 = get_codepoint();\n\n\t\t\t\t\t\t\t\t\tif (JSON_UNLIKELY(codepoint2 == -1))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\terror_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n\t\t\t\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// check if codepoint2 is a low surrogate\n\t\t\t\t\t\t\t\t\tif (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// overwrite codepoint\n\t\t\t\t\t\t\t\t\t\tcodepoint = static_cast<int>(\n\t\t\t\t\t\t\t\t\t\t\t// high surrogate occupies the most significant 22 bits\n\t\t\t\t\t\t\t\t\t\t\t(static_cast<unsigned int>(codepoint1) << 10u)\n\t\t\t\t\t\t\t\t\t\t\t// low surrogate occupies the least significant 15 bits\n\t\t\t\t\t\t\t\t\t\t\t+ static_cast<unsigned int>(codepoint2)\n\t\t\t\t\t\t\t\t\t\t\t// there is still the 0xD800, 0xDC00 and 0x10000 noise\n\t\t\t\t\t\t\t\t\t\t\t// in the result so we have to subtract with:\n\t\t\t\t\t\t\t\t\t\t\t// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00\n\t\t\t\t\t\t\t\t\t\t\t-0x35FDC00u);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\terror_message = \"invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF\";\n\t\t\t\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\terror_message = \"invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF\";\n\t\t\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\terror_message = \"invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF\";\n\t\t\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// result of the above calculation yields a proper codepoint\n\t\t\t\t\t\t\tassert(0x00 <= codepoint and codepoint <= 0x10FFFF);\n\n\t\t\t\t\t\t\t// translate codepoint into bytes\n\t\t\t\t\t\t\tif (codepoint < 0x80)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// 1-byte characters: 0xxxxxxx (ASCII)\n\t\t\t\t\t\t\t\tadd(codepoint);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (codepoint <= 0x7FF)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// 2-byte characters: 110xxxxx 10xxxxxx\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (codepoint <= 0xFFFF)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n\t\t\t\t\t\t\t\tadd(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// other characters after escape\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\terror_message = \"invalid string: forbidden character after backslash\";\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// invalid control characters\n\t\t\t\t\tcase 0x00:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0000 (NUL) must be escaped to \\\\u0000\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x01:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0001 (SOH) must be escaped to \\\\u0001\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x02:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0002 (STX) must be escaped to \\\\u0002\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x03:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0003 (ETX) must be escaped to \\\\u0003\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x04:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0004 (EOT) must be escaped to \\\\u0004\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x05:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0005 (ENQ) must be escaped to \\\\u0005\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x06:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0006 (ACK) must be escaped to \\\\u0006\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x07:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0007 (BEL) must be escaped to \\\\u0007\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x08:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0008 (BS) must be escaped to \\\\u0008 or \\\\b\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x09:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0009 (HT) must be escaped to \\\\u0009 or \\\\t\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x0A:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+000A (LF) must be escaped to \\\\u000A or \\\\n\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x0B:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+000B (VT) must be escaped to \\\\u000B\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x0C:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+000C (FF) must be escaped to \\\\u000C or \\\\f\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x0D:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+000D (CR) must be escaped to \\\\u000D or \\\\r\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x0E:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+000E (SO) must be escaped to \\\\u000E\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x0F:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+000F (SI) must be escaped to \\\\u000F\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x10:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0010 (DLE) must be escaped to \\\\u0010\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x11:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0011 (DC1) must be escaped to \\\\u0011\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x12:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0012 (DC2) must be escaped to \\\\u0012\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x13:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0013 (DC3) must be escaped to \\\\u0013\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x14:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0014 (DC4) must be escaped to \\\\u0014\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x15:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0015 (NAK) must be escaped to \\\\u0015\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x16:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0016 (SYN) must be escaped to \\\\u0016\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x17:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0017 (ETB) must be escaped to \\\\u0017\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x18:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0018 (CAN) must be escaped to \\\\u0018\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x19:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+0019 (EM) must be escaped to \\\\u0019\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x1A:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+001A (SUB) must be escaped to \\\\u001A\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x1B:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+001B (ESC) must be escaped to \\\\u001B\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x1C:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+001C (FS) must be escaped to \\\\u001C\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x1D:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+001D (GS) must be escaped to \\\\u001D\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x1E:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+001E (RS) must be escaped to \\\\u001E\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 0x1F:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: control character U+001F (US) must be escaped to \\\\u001F\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))\n\t\t\t\t\tcase 0x20:\n\t\t\t\t\tcase 0x21:\n\t\t\t\t\tcase 0x23:\n\t\t\t\t\tcase 0x24:\n\t\t\t\t\tcase 0x25:\n\t\t\t\t\tcase 0x26:\n\t\t\t\t\tcase 0x27:\n\t\t\t\t\tcase 0x28:\n\t\t\t\t\tcase 0x29:\n\t\t\t\t\tcase 0x2A:\n\t\t\t\t\tcase 0x2B:\n\t\t\t\t\tcase 0x2C:\n\t\t\t\t\tcase 0x2D:\n\t\t\t\t\tcase 0x2E:\n\t\t\t\t\tcase 0x2F:\n\t\t\t\t\tcase 0x30:\n\t\t\t\t\tcase 0x31:\n\t\t\t\t\tcase 0x32:\n\t\t\t\t\tcase 0x33:\n\t\t\t\t\tcase 0x34:\n\t\t\t\t\tcase 0x35:\n\t\t\t\t\tcase 0x36:\n\t\t\t\t\tcase 0x37:\n\t\t\t\t\tcase 0x38:\n\t\t\t\t\tcase 0x39:\n\t\t\t\t\tcase 0x3A:\n\t\t\t\t\tcase 0x3B:\n\t\t\t\t\tcase 0x3C:\n\t\t\t\t\tcase 0x3D:\n\t\t\t\t\tcase 0x3E:\n\t\t\t\t\tcase 0x3F:\n\t\t\t\t\tcase 0x40:\n\t\t\t\t\tcase 0x41:\n\t\t\t\t\tcase 0x42:\n\t\t\t\t\tcase 0x43:\n\t\t\t\t\tcase 0x44:\n\t\t\t\t\tcase 0x45:\n\t\t\t\t\tcase 0x46:\n\t\t\t\t\tcase 0x47:\n\t\t\t\t\tcase 0x48:\n\t\t\t\t\tcase 0x49:\n\t\t\t\t\tcase 0x4A:\n\t\t\t\t\tcase 0x4B:\n\t\t\t\t\tcase 0x4C:\n\t\t\t\t\tcase 0x4D:\n\t\t\t\t\tcase 0x4E:\n\t\t\t\t\tcase 0x4F:\n\t\t\t\t\tcase 0x50:\n\t\t\t\t\tcase 0x51:\n\t\t\t\t\tcase 0x52:\n\t\t\t\t\tcase 0x53:\n\t\t\t\t\tcase 0x54:\n\t\t\t\t\tcase 0x55:\n\t\t\t\t\tcase 0x56:\n\t\t\t\t\tcase 0x57:\n\t\t\t\t\tcase 0x58:\n\t\t\t\t\tcase 0x59:\n\t\t\t\t\tcase 0x5A:\n\t\t\t\t\tcase 0x5B:\n\t\t\t\t\tcase 0x5D:\n\t\t\t\t\tcase 0x5E:\n\t\t\t\t\tcase 0x5F:\n\t\t\t\t\tcase 0x60:\n\t\t\t\t\tcase 0x61:\n\t\t\t\t\tcase 0x62:\n\t\t\t\t\tcase 0x63:\n\t\t\t\t\tcase 0x64:\n\t\t\t\t\tcase 0x65:\n\t\t\t\t\tcase 0x66:\n\t\t\t\t\tcase 0x67:\n\t\t\t\t\tcase 0x68:\n\t\t\t\t\tcase 0x69:\n\t\t\t\t\tcase 0x6A:\n\t\t\t\t\tcase 0x6B:\n\t\t\t\t\tcase 0x6C:\n\t\t\t\t\tcase 0x6D:\n\t\t\t\t\tcase 0x6E:\n\t\t\t\t\tcase 0x6F:\n\t\t\t\t\tcase 0x70:\n\t\t\t\t\tcase 0x71:\n\t\t\t\t\tcase 0x72:\n\t\t\t\t\tcase 0x73:\n\t\t\t\t\tcase 0x74:\n\t\t\t\t\tcase 0x75:\n\t\t\t\t\tcase 0x76:\n\t\t\t\t\tcase 0x77:\n\t\t\t\t\tcase 0x78:\n\t\t\t\t\tcase 0x79:\n\t\t\t\t\tcase 0x7A:\n\t\t\t\t\tcase 0x7B:\n\t\t\t\t\tcase 0x7C:\n\t\t\t\t\tcase 0x7D:\n\t\t\t\t\tcase 0x7E:\n\t\t\t\t\tcase 0x7F:\n\t\t\t\t\t{\n\t\t\t\t\t\tadd(current);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+0080..U+07FF: bytes C2..DF 80..BF\n\t\t\t\t\tcase 0xC2:\n\t\t\t\t\tcase 0xC3:\n\t\t\t\t\tcase 0xC4:\n\t\t\t\t\tcase 0xC5:\n\t\t\t\t\tcase 0xC6:\n\t\t\t\t\tcase 0xC7:\n\t\t\t\t\tcase 0xC8:\n\t\t\t\t\tcase 0xC9:\n\t\t\t\t\tcase 0xCA:\n\t\t\t\t\tcase 0xCB:\n\t\t\t\t\tcase 0xCC:\n\t\t\t\t\tcase 0xCD:\n\t\t\t\t\tcase 0xCE:\n\t\t\t\t\tcase 0xCF:\n\t\t\t\t\tcase 0xD0:\n\t\t\t\t\tcase 0xD1:\n\t\t\t\t\tcase 0xD2:\n\t\t\t\t\tcase 0xD3:\n\t\t\t\t\tcase 0xD4:\n\t\t\t\t\tcase 0xD5:\n\t\t\t\t\tcase 0xD6:\n\t\t\t\t\tcase 0xD7:\n\t\t\t\t\tcase 0xD8:\n\t\t\t\t\tcase 0xD9:\n\t\t\t\t\tcase 0xDA:\n\t\t\t\t\tcase 0xDB:\n\t\t\t\t\tcase 0xDC:\n\t\t\t\t\tcase 0xDD:\n\t\t\t\t\tcase 0xDE:\n\t\t\t\t\tcase 0xDF:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not next_byte_in_range({ 0x80, 0xBF })))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+0800..U+0FFF: bytes E0 A0..BF 80..BF\n\t\t\t\t\tcase 0xE0:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not (next_byte_in_range({ 0xA0, 0xBF, 0x80, 0xBF }))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF\n\t\t\t\t\t// U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF\n\t\t\t\t\tcase 0xE1:\n\t\t\t\t\tcase 0xE2:\n\t\t\t\t\tcase 0xE3:\n\t\t\t\t\tcase 0xE4:\n\t\t\t\t\tcase 0xE5:\n\t\t\t\t\tcase 0xE6:\n\t\t\t\t\tcase 0xE7:\n\t\t\t\t\tcase 0xE8:\n\t\t\t\t\tcase 0xE9:\n\t\t\t\t\tcase 0xEA:\n\t\t\t\t\tcase 0xEB:\n\t\t\t\t\tcase 0xEC:\n\t\t\t\t\tcase 0xEE:\n\t\t\t\t\tcase 0xEF:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not (next_byte_in_range({ 0x80, 0xBF, 0x80, 0xBF }))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+D000..U+D7FF: bytes ED 80..9F 80..BF\n\t\t\t\t\tcase 0xED:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not (next_byte_in_range({ 0x80, 0x9F, 0x80, 0xBF }))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF\n\t\t\t\t\tcase 0xF0:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not (next_byte_in_range({ 0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF }))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF\n\t\t\t\t\tcase 0xF1:\n\t\t\t\t\tcase 0xF2:\n\t\t\t\t\tcase 0xF3:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not (next_byte_in_range({ 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF }))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF\n\t\t\t\t\tcase 0xF4:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (JSON_UNLIKELY(not (next_byte_in_range({ 0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF }))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// remaining bytes (80..C1 and F5..FF) are ill-formed\n\t\t\t\t\tdefault:\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid string: ill-formed UTF-8 byte\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic void strtof(float& f, const char* str, char** endptr) noexcept\n\t\t\t{\n\t\t\t\tf = std::strtof(str, endptr);\n\t\t\t}\n\n\t\t\tstatic void strtof(double& f, const char* str, char** endptr) noexcept\n\t\t\t{\n\t\t\t\tf = std::strtod(str, endptr);\n\t\t\t}\n\n\t\t\tstatic void strtof(long double& f, const char* str, char** endptr) noexcept\n\t\t\t{\n\t\t\t\tf = std::strtold(str, endptr);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief scan a number literal\n\n\t\t\tThis function scans a string according to Sect. 6 of RFC 7159.\n\n\t\t\tThe function is realized with a deterministic finite state machine derived\n\t\t\tfrom the grammar described in RFC 7159. Starting in state \"init\", the\n\t\t\tinput is read and used to determined the next state. Only state \"done\"\n\t\t\taccepts the number. State \"error\" is a trap state to model errors. In the\n\t\t\ttable below, \"anything\" means any character but the ones listed before.\n\n\t\t\tstate    | 0        | 1-9      | e E      | +       | -       | .        | anything\n\t\t\t---------|----------|----------|----------|---------|---------|----------|-----------\n\t\t\tinit     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]\n\t\t\tminus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]\n\t\t\tzero     | done     | done     | exponent | done    | done    | decimal1 | done\n\t\t\tany1     | any1     | any1     | exponent | done    | done    | decimal1 | done\n\t\t\tdecimal1 | decimal2 | [error]  | [error]  | [error] | [error] | [error]  | [error]\n\t\t\tdecimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done\n\t\t\texponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]\n\t\t\tsign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]\n\t\t\tany2     | any2     | any2     | done     | done    | done    | done     | done\n\n\t\t\tThe state machine is realized with one label per state (prefixed with\n\t\t\t\"scan_number_\") and `goto` statements between them. The state machine\n\t\t\tcontains cycles, but any cycle can be left when EOF is read. Therefore,\n\t\t\tthe function is guaranteed to terminate.\n\n\t\t\tDuring scanning, the read bytes are stored in token_buffer. This string is\n\t\t\tthen converted to a signed integer, an unsigned integer, or a\n\t\t\tfloating-point number.\n\n\t\t\t@return token_type::value_unsigned, token_type::value_integer, or\n\t\t\t\t\ttoken_type::value_float if number could be successfully scanned,\n\t\t\t\t\ttoken_type::parse_error otherwise\n\n\t\t\t@note The scanner is independent of the current locale. Internally, the\n\t\t\t\t  locale's decimal point is used instead of `.` to work with the\n\t\t\t\t  locale-dependent converters.\n\t\t\t*/\n\t\t\ttoken_type scan_number()  // lgtm [cpp/use-of-goto]\n\t\t\t{\n\t\t\t\t// reset token_buffer to store the number's bytes\n\t\t\t\treset();\n\n\t\t\t\t// the type of the parsed number; initially set to unsigned; will be\n\t\t\t\t// changed if minus sign, decimal point or exponent is read\n\t\t\t\ttoken_type number_type = token_type::value_unsigned;\n\n\t\t\t\t// state (init): we just found out we need to scan a number\n\t\t\t\tswitch (current)\n\t\t\t\t{\n\t\t\t\tcase '-':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_minus;\n\t\t\t\t}\n\n\t\t\t\tcase '0':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_zero;\n\t\t\t\t}\n\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_any1;\n\t\t\t\t}\n\n\t\t\t\t// all other characters are rejected outside scan_number()\n\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t}\n\n\t\t\tscan_number_minus:\n\t\t\t\t// state: we just parsed a leading minus sign\n\t\t\t\tnumber_type = token_type::value_integer;\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_zero;\n\t\t\t\t}\n\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_any1;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\terror_message = \"invalid number; expected digit after '-'\";\n\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tscan_number_zero:\n\t\t\t\t// state: we just parse a zero (maybe with a leading minus sign)\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '.':\n\t\t\t\t{\n\t\t\t\t\tadd(decimal_point_char);\n\t\t\t\t\tgoto scan_number_decimal1;\n\t\t\t\t}\n\n\t\t\t\tcase 'e':\n\t\t\t\tcase 'E':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_exponent;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tgoto scan_number_done;\n\t\t\t\t}\n\n\t\t\tscan_number_any1:\n\t\t\t\t// state: we just parsed a number 0-9 (maybe with a leading minus sign)\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_any1;\n\t\t\t\t}\n\n\t\t\t\tcase '.':\n\t\t\t\t{\n\t\t\t\t\tadd(decimal_point_char);\n\t\t\t\t\tgoto scan_number_decimal1;\n\t\t\t\t}\n\n\t\t\t\tcase 'e':\n\t\t\t\tcase 'E':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_exponent;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tgoto scan_number_done;\n\t\t\t\t}\n\n\t\t\tscan_number_decimal1:\n\t\t\t\t// state: we just parsed a decimal point\n\t\t\t\tnumber_type = token_type::value_float;\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_decimal2;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\terror_message = \"invalid number; expected digit after '.'\";\n\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tscan_number_decimal2:\n\t\t\t\t// we just parsed at least one number after a decimal point\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_decimal2;\n\t\t\t\t}\n\n\t\t\t\tcase 'e':\n\t\t\t\tcase 'E':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_exponent;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tgoto scan_number_done;\n\t\t\t\t}\n\n\t\t\tscan_number_exponent:\n\t\t\t\t// we just parsed an exponent\n\t\t\t\tnumber_type = token_type::value_float;\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '+':\n\t\t\t\tcase '-':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_sign;\n\t\t\t\t}\n\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_any2;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\terror_message =\n\t\t\t\t\t\t\"invalid number; expected '+', '-', or digit after exponent\";\n\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tscan_number_sign:\n\t\t\t\t// we just parsed an exponent sign\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_any2;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\terror_message = \"invalid number; expected digit after exponent sign\";\n\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tscan_number_any2:\n\t\t\t\t// we just parsed a number after the exponent or exponent sign\n\t\t\t\tswitch (get())\n\t\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t{\n\t\t\t\t\tadd(current);\n\t\t\t\t\tgoto scan_number_any2;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tgoto scan_number_done;\n\t\t\t\t}\n\n\t\t\tscan_number_done:\n\t\t\t\t// unget the character after the number (we only read it to know that\n\t\t\t\t// we are done scanning a number)\n\t\t\t\tunget();\n\n\t\t\t\tchar* endptr = nullptr;\n\t\t\t\terrno = 0;\n\n\t\t\t\t// try to parse integers first and fall back to floats\n\t\t\t\tif (number_type == token_type::value_unsigned)\n\t\t\t\t{\n\t\t\t\t\tconst auto x = std::strtoull(token_buffer.data(), &endptr, 10);\n\n\t\t\t\t\t// we checked the number format before\n\t\t\t\t\tassert(endptr == token_buffer.data() + token_buffer.size());\n\n\t\t\t\t\tif (errno == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue_unsigned = static_cast<number_unsigned_t>(x);\n\t\t\t\t\t\tif (value_unsigned == x)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::value_unsigned;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (number_type == token_type::value_integer)\n\t\t\t\t{\n\t\t\t\t\tconst auto x = std::strtoll(token_buffer.data(), &endptr, 10);\n\n\t\t\t\t\t// we checked the number format before\n\t\t\t\t\tassert(endptr == token_buffer.data() + token_buffer.size());\n\n\t\t\t\t\tif (errno == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue_integer = static_cast<number_integer_t>(x);\n\t\t\t\t\t\tif (value_integer == x)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn token_type::value_integer;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// this code is reached if we parse a floating-point number or if an\n\t\t\t\t// integer conversion above failed\n\t\t\t\tstrtof(value_float, token_buffer.data(), &endptr);\n\n\t\t\t\t// we checked the number format before\n\t\t\t\tassert(endptr == token_buffer.data() + token_buffer.size());\n\n\t\t\t\treturn token_type::value_float;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] literal_text  the literal text to expect\n\t\t\t@param[in] length        the length of the passed literal text\n\t\t\t@param[in] return_type   the token type to return on success\n\t\t\t*/\n\t\t\ttoken_type scan_literal(const char* literal_text, const std::size_t length,\n\t\t\t\ttoken_type return_type)\n\t\t\t{\n\t\t\t\tassert(current == literal_text[0]);\n\t\t\t\tfor (std::size_t i = 1; i < length; ++i)\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(get() != literal_text[i]))\n\t\t\t\t\t{\n\t\t\t\t\t\terror_message = \"invalid literal\";\n\t\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn return_type;\n\t\t\t}\n\n\t\t\t/////////////////////\n\t\t\t// input management\n\t\t\t/////////////////////\n\n\t\t\t/// reset token_buffer; current character is beginning of token\n\t\t\tvoid reset() noexcept\n\t\t\t{\n\t\t\t\ttoken_buffer.clear();\n\t\t\t\ttoken_string.clear();\n\t\t\t\ttoken_string.push_back(std::char_traits<char>::to_char_type(current));\n\t\t\t}\n\n\t\t\t/*\n\t\t\t@brief get next character from the input\n\n\t\t\tThis function provides the interface to the used input adapter. It does\n\t\t\tnot throw in case the input reached EOF, but returns a\n\t\t\t`std::char_traits<char>::eof()` in that case.  Stores the scanned characters\n\t\t\tfor use in error messages.\n\n\t\t\t@return character read from the input\n\t\t\t*/\n\t\t\tstd::char_traits<char>::int_type get()\n\t\t\t{\n\t\t\t\t++position.chars_read_total;\n\t\t\t\t++position.chars_read_current_line;\n\n\t\t\t\tif (next_unget)\n\t\t\t\t{\n\t\t\t\t\t// just reset the next_unget variable and work with current\n\t\t\t\t\tnext_unget = false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcurrent = ia->get_character();\n\t\t\t\t}\n\n\t\t\t\tif (JSON_LIKELY(current != std::char_traits<char>::eof()))\n\t\t\t\t{\n\t\t\t\t\ttoken_string.push_back(std::char_traits<char>::to_char_type(current));\n\t\t\t\t}\n\n\t\t\t\tif (current == '\\n')\n\t\t\t\t{\n\t\t\t\t\t++position.lines_read;\n\t\t\t\t\tposition.chars_read_current_line = 0;\n\t\t\t\t}\n\n\t\t\t\treturn current;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief unget current character (read it again on next get)\n\n\t\t\tWe implement unget by setting variable next_unget to true. The input is not\n\t\t\tchanged - we just simulate ungetting by modifying chars_read_total,\n\t\t\tchars_read_current_line, and token_string. The next call to get() will\n\t\t\tbehave as if the unget character is read again.\n\t\t\t*/\n\t\t\tvoid unget()\n\t\t\t{\n\t\t\t\tnext_unget = true;\n\n\t\t\t\t--position.chars_read_total;\n\n\t\t\t\t// in case we \"unget\" a newline, we have to also decrement the lines_read\n\t\t\t\tif (position.chars_read_current_line == 0)\n\t\t\t\t{\n\t\t\t\t\tif (position.lines_read > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t--position.lines_read;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t--position.chars_read_current_line;\n\t\t\t\t}\n\n\t\t\t\tif (JSON_LIKELY(current != std::char_traits<char>::eof()))\n\t\t\t\t{\n\t\t\t\t\tassert(not token_string.empty());\n\t\t\t\t\ttoken_string.pop_back();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// add a character to token_buffer\n\t\t\tvoid add(int c)\n\t\t\t{\n\t\t\t\ttoken_buffer.push_back(std::char_traits<char>::to_char_type(c));\n\t\t\t}\n\n\t\tpublic:\n\t\t\t/////////////////////\n\t\t\t// value getters\n\t\t\t/////////////////////\n\n\t\t\t/// return integer value\n\t\t\tconstexpr number_integer_t get_number_integer() const noexcept\n\t\t\t{\n\t\t\t\treturn value_integer;\n\t\t\t}\n\n\t\t\t/// return unsigned integer value\n\t\t\tconstexpr number_unsigned_t get_number_unsigned() const noexcept\n\t\t\t{\n\t\t\t\treturn value_unsigned;\n\t\t\t}\n\n\t\t\t/// return floating-point value\n\t\t\tconstexpr number_float_t get_number_float() const noexcept\n\t\t\t{\n\t\t\t\treturn value_float;\n\t\t\t}\n\n\t\t\t/// return current string value (implicitly resets the token; useful only once)\n\t\t\tstring_t& get_string()\n\t\t\t{\n\t\t\t\treturn token_buffer;\n\t\t\t}\n\n\t\t\t/////////////////////\n\t\t\t// diagnostics\n\t\t\t/////////////////////\n\n\t\t\t/// return position of last read token\n\t\t\tconstexpr position_t get_position() const noexcept\n\t\t\t{\n\t\t\t\treturn position;\n\t\t\t}\n\n\t\t\t/// return the last read token (for errors only).  Will never contain EOF\n\t\t\t/// (an arbitrary value that is not a valid char value, often -1), because\n\t\t\t/// 255 may legitimately occur.  May contain NUL, which should be escaped.\n\t\t\tstd::string get_token_string() const\n\t\t\t{\n\t\t\t\t// escape control characters\n\t\t\t\tstd::string result;\n\t\t\t\tfor (const auto c : token_string)\n\t\t\t\t{\n\t\t\t\t\tif ('\\x00' <= c and c <= '\\x1F')\n\t\t\t\t\t{\n\t\t\t\t\t\t// escape control characters\n\t\t\t\t\t\tstd::array<char, 9> cs{ {} };\n\t\t\t\t\t\t(std::snprintf)(cs.data(), cs.size(), \"<U+%.4X>\", static_cast<unsigned char>(c));\n\t\t\t\t\t\tresult += cs.data();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// add character as is\n\t\t\t\t\t\tresult.push_back(c);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/// return syntax error message\n\t\t\tconstexpr const char* get_error_message() const noexcept\n\t\t\t{\n\t\t\t\treturn error_message;\n\t\t\t}\n\n\t\t\t/////////////////////\n\t\t\t// actual scanner\n\t\t\t/////////////////////\n\n\t\t\t/*!\n\t\t\t@brief skip the UTF-8 byte order mark\n\t\t\t@return true iff there is no BOM or the correct BOM has been skipped\n\t\t\t*/\n\t\t\tbool skip_bom()\n\t\t\t{\n\t\t\t\tif (get() == 0xEF)\n\t\t\t\t{\n\t\t\t\t\t// check if we completely parse the BOM\n\t\t\t\t\treturn get() == 0xBB and get() == 0xBF;\n\t\t\t\t}\n\n\t\t\t\t// the first character is not the beginning of the BOM; unget it to\n\t\t\t\t// process is later\n\t\t\t\tunget();\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttoken_type scan()\n\t\t\t{\n\t\t\t\t// initially, skip the BOM\n\t\t\t\tif (position.chars_read_total == 0 and not skip_bom())\n\t\t\t\t{\n\t\t\t\t\terror_message = \"invalid BOM; must be 0xEF 0xBB 0xBF if given\";\n\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t}\n\n\t\t\t\t// read next character and ignore whitespace\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tget();\n\t\t\t\t} while (current == ' ' or current == '\\t' or current == '\\n' or current == '\\r');\n\n\t\t\t\tswitch (current)\n\t\t\t\t{\n\t\t\t\t\t// structural characters\n\t\t\t\tcase '[':\n\t\t\t\t\treturn token_type::begin_array;\n\t\t\t\tcase ']':\n\t\t\t\t\treturn token_type::end_array;\n\t\t\t\tcase '{':\n\t\t\t\t\treturn token_type::begin_object;\n\t\t\t\tcase '}':\n\t\t\t\t\treturn token_type::end_object;\n\t\t\t\tcase ':':\n\t\t\t\t\treturn token_type::name_separator;\n\t\t\t\tcase ',':\n\t\t\t\t\treturn token_type::value_separator;\n\n\t\t\t\t\t// literals\n\t\t\t\tcase 't':\n\t\t\t\t\treturn scan_literal(\"true\", 4, token_type::literal_true);\n\t\t\t\tcase 'f':\n\t\t\t\t\treturn scan_literal(\"false\", 5, token_type::literal_false);\n\t\t\t\tcase 'n':\n\t\t\t\t\treturn scan_literal(\"null\", 4, token_type::literal_null);\n\n\t\t\t\t\t// string\n\t\t\t\tcase '\\\"':\n\t\t\t\t\treturn scan_string();\n\n\t\t\t\t\t// number\n\t\t\t\tcase '-':\n\t\t\t\tcase '0':\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t\treturn scan_number();\n\n\t\t\t\t\t// end of input (the null byte is needed when parsing from\n\t\t\t\t\t// string literals)\n\t\t\t\tcase '\\0':\n\t\t\t\tcase std::char_traits<char>::eof():\n\t\t\t\t\treturn token_type::end_of_input;\n\n\t\t\t\t\t// error\n\t\t\t\tdefault:\n\t\t\t\t\terror_message = \"invalid literal\";\n\t\t\t\t\treturn token_type::parse_error;\n\t\t\t\t}\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// input adapter\n\t\t\tdetail::input_adapter_t ia = nullptr;\n\n\t\t\t/// the current character\n\t\t\tstd::char_traits<char>::int_type current = std::char_traits<char>::eof();\n\n\t\t\t/// whether the next get() call should just return current\n\t\t\tbool next_unget = false;\n\n\t\t\t/// the start position of the current token\n\t\t\tposition_t position{};\n\n\t\t\t/// raw input token string (for error messages)\n\t\t\tstd::vector<char> token_string{};\n\n\t\t\t/// buffer for variable-length tokens (numbers, strings)\n\t\t\tstring_t token_buffer{};\n\n\t\t\t/// a description of occurred lexer errors\n\t\t\tconst char* error_message = \"\";\n\n\t\t\t// number values\n\t\t\tnumber_integer_t value_integer = 0;\n\t\t\tnumber_unsigned_t value_unsigned = 0;\n\t\t\tnumber_float_t value_float = 0;\n\n\t\t\t/// the decimal point\n\t\t\tconst char decimal_point_char = '.';\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/parser.hpp>\n\n\n#include <cassert> // assert\n#include <cmath> // isfinite\n#include <cstdint> // uint8_t\n#include <functional> // function\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t////////////\n\t\t// parser //\n\t\t////////////\n\n\t\t/*!\n\t\t@brief syntax analysis\n\n\t\tThis class implements a recursive decent parser.\n\t\t*/\n\t\ttemplate<typename BasicJsonType>\n\t\tclass parser\n\t\t{\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\t\t\tusing lexer_t = lexer<BasicJsonType>;\n\t\t\tusing token_type = typename lexer_t::token_type;\n\n\t\tpublic:\n\t\t\tenum class parse_event_t : uint8_t\n\t\t\t{\n\t\t\t\t/// the parser read `{` and started to process a JSON object\n\t\t\t\tobject_start,\n\t\t\t\t/// the parser read `}` and finished processing a JSON object\n\t\t\t\tobject_end,\n\t\t\t\t/// the parser read `[` and started to process a JSON array\n\t\t\t\tarray_start,\n\t\t\t\t/// the parser read `]` and finished processing a JSON array\n\t\t\t\tarray_end,\n\t\t\t\t/// the parser read a key of a value in an object\n\t\t\t\tkey,\n\t\t\t\t/// the parser finished reading a JSON value\n\t\t\t\tvalue\n\t\t\t};\n\n\t\t\tusing parser_callback_t =\n\t\t\t\tstd::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;\n\n\t\t\t/// a parser reading from an input adapter\n\t\t\texplicit parser(detail::input_adapter_t&& adapter,\n\t\t\t\tconst parser_callback_t cb = nullptr,\n\t\t\t\tconst bool allow_exceptions_ = true)\n\t\t\t\t: callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)\n\t\t\t{\n\t\t\t\t// read first token\n\t\t\t\tget_token();\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief public parser interface\n\n\t\t\t@param[in] strict      whether to expect the last token to be EOF\n\t\t\t@param[in,out] result  parsed JSON value\n\n\t\t\t@throw parse_error.101 in case of an unexpected token\n\t\t\t@throw parse_error.102 if to_unicode fails or surrogate error\n\t\t\t@throw parse_error.103 if to_unicode fails\n\t\t\t*/\n\t\t\tvoid parse(const bool strict, BasicJsonType& result)\n\t\t\t{\n\t\t\t\tif (callback)\n\t\t\t\t{\n\t\t\t\t\tjson_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);\n\t\t\t\t\tsax_parse_internal(&sdp);\n\t\t\t\t\tresult.assert_invariant();\n\n\t\t\t\t\t// in strict mode, input must be completely read\n\t\t\t\t\tif (strict and (get_token() != token_type::end_of_input))\n\t\t\t\t\t{\n\t\t\t\t\t\tsdp.parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\texception_message(token_type::end_of_input, \"value\")));\n\t\t\t\t\t}\n\n\t\t\t\t\t// in case of an error, return discarded value\n\t\t\t\t\tif (sdp.is_errored())\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = value_t::discarded;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// set top-level value to null if it was discarded by the callback\n\t\t\t\t\t// function\n\t\t\t\t\tif (result.is_discarded())\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = nullptr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tjson_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);\n\t\t\t\t\tsax_parse_internal(&sdp);\n\t\t\t\t\tresult.assert_invariant();\n\n\t\t\t\t\t// in strict mode, input must be completely read\n\t\t\t\t\tif (strict and (get_token() != token_type::end_of_input))\n\t\t\t\t\t{\n\t\t\t\t\t\tsdp.parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\texception_message(token_type::end_of_input, \"value\")));\n\t\t\t\t\t}\n\n\t\t\t\t\t// in case of an error, return discarded value\n\t\t\t\t\tif (sdp.is_errored())\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = value_t::discarded;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief public accept interface\n\n\t\t\t@param[in] strict  whether to expect the last token to be EOF\n\t\t\t@return whether the input is a proper JSON text\n\t\t\t*/\n\t\t\tbool accept(const bool strict = true)\n\t\t\t{\n\t\t\t\tjson_sax_acceptor<BasicJsonType> sax_acceptor;\n\t\t\t\treturn sax_parse(&sax_acceptor, strict);\n\t\t\t}\n\n\t\t\ttemplate <typename SAX>\n\t\t\tbool sax_parse(SAX* sax, const bool strict = true)\n\t\t\t{\n\t\t\t\t(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n\t\t\t\tconst bool result = sax_parse_internal(sax);\n\n\t\t\t\t// strict mode: next byte must be EOF\n\t\t\t\tif (result and strict and (get_token() != token_type::end_of_input))\n\t\t\t\t{\n\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\texception_message(token_type::end_of_input, \"value\")));\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\tprivate:\n\t\t\ttemplate <typename SAX>\n\t\t\tbool sax_parse_internal(SAX* sax)\n\t\t\t{\n\t\t\t\t// stack to remember the hierarchy of structured values we are parsing\n\t\t\t\t// true = array; false = object\n\t\t\t\tstd::vector<bool> states;\n\t\t\t\t// value to avoid a goto (see comment where set to true)\n\t\t\t\tbool skip_to_state_evaluation = false;\n\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (not skip_to_state_evaluation)\n\t\t\t\t\t{\n\t\t\t\t\t\t// invariant: get_token() was called before each iteration\n\t\t\t\t\t\tswitch (last_token)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase token_type::begin_object:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// closing } -> we are done\n\t\t\t\t\t\t\tif (get_token() == token_type::end_object)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->end_object()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// parse key\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(last_token != token_type::value_string))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\t\texception_message(token_type::value_string, \"object key\")));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// parse separator (:)\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(get_token() != token_type::name_separator))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\t\texception_message(token_type::name_separator, \"object separator\")));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// remember we are now inside an object\n\t\t\t\t\t\t\tstates.push_back(false);\n\n\t\t\t\t\t\t\t// parse values\n\t\t\t\t\t\t\tget_token();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::begin_array:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// closing ] -> we are done\n\t\t\t\t\t\t\tif (get_token() == token_type::end_array)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->end_array()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// remember we are now inside an array\n\t\t\t\t\t\t\tstates.push_back(true);\n\n\t\t\t\t\t\t\t// parse values (no need to call get_token)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::value_float:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst auto res = m_lexer.get_number_float();\n\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not std::isfinite(res)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\t\tout_of_range::create(406, \"number overflow parsing '\" + m_lexer.get_token_string() + \"'\"));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::literal_false:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->boolean(false)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::literal_null:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->null()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::literal_true:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->boolean(true)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::value_integer:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::value_string:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::value_unsigned:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase token_type::parse_error:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// using \"uninitialized\" to avoid \"expected\" message\n\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\texception_message(token_type::uninitialized, \"value\")));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault: // the last token was unexpected\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\texception_message(token_type::literal_or_value, \"value\")));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tskip_to_state_evaluation = false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// we reached this line after we successfully parsed a value\n\t\t\t\t\tif (states.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\t// empty stack: we reached the end of the hierarchy: done\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (states.back())  // array\n\t\t\t\t\t{\n\t\t\t\t\t\t// comma -> next value\n\t\t\t\t\t\tif (get_token() == token_type::value_separator)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// parse a new value\n\t\t\t\t\t\t\tget_token();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// closing ]\n\t\t\t\t\t\tif (JSON_LIKELY(last_token == token_type::end_array))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->end_array()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// We are done with this array. Before we can parse a\n\t\t\t\t\t\t\t// new value, we need to evaluate the new state first.\n\t\t\t\t\t\t\t// By setting skip_to_state_evaluation to false, we\n\t\t\t\t\t\t\t// are effectively jumping to the beginning of this if.\n\t\t\t\t\t\t\tassert(not states.empty());\n\t\t\t\t\t\t\tstates.pop_back();\n\t\t\t\t\t\t\tskip_to_state_evaluation = true;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\texception_message(token_type::end_array, \"array\")));\n\t\t\t\t\t}\n\t\t\t\t\telse  // object\n\t\t\t\t\t{\n\t\t\t\t\t\t// comma -> next value\n\t\t\t\t\t\tif (get_token() == token_type::value_separator)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// parse key\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(get_token() != token_type::value_string))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\t\texception_message(token_type::value_string, \"object key\")));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// parse separator (:)\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(get_token() != token_type::name_separator))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\t\t\texception_message(token_type::name_separator, \"object separator\")));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// parse values\n\t\t\t\t\t\t\tget_token();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// closing }\n\t\t\t\t\t\tif (JSON_LIKELY(last_token == token_type::end_object))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (JSON_UNLIKELY(not sax->end_object()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// We are done with this object. Before we can parse a\n\t\t\t\t\t\t\t// new value, we need to evaluate the new state first.\n\t\t\t\t\t\t\t// By setting skip_to_state_evaluation to false, we\n\t\t\t\t\t\t\t// are effectively jumping to the beginning of this if.\n\t\t\t\t\t\t\tassert(not states.empty());\n\t\t\t\t\t\t\tstates.pop_back();\n\t\t\t\t\t\t\tskip_to_state_evaluation = true;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn sax->parse_error(m_lexer.get_position(),\n\t\t\t\t\t\t\tm_lexer.get_token_string(),\n\t\t\t\t\t\t\tparse_error::create(101, m_lexer.get_position(),\n\t\t\t\t\t\t\t\texception_message(token_type::end_object, \"object\")));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// get next token from lexer\n\t\t\ttoken_type get_token()\n\t\t\t{\n\t\t\t\treturn last_token = m_lexer.scan();\n\t\t\t}\n\n\t\t\tstd::string exception_message(const token_type expected, const std::string& context)\n\t\t\t{\n\t\t\t\tstd::string error_msg = \"syntax error \";\n\n\t\t\t\tif (not context.empty())\n\t\t\t\t{\n\t\t\t\t\terror_msg += \"while parsing \" + context + \" \";\n\t\t\t\t}\n\n\t\t\t\terror_msg += \"- \";\n\n\t\t\t\tif (last_token == token_type::parse_error)\n\t\t\t\t{\n\t\t\t\t\terror_msg += std::string(m_lexer.get_error_message()) + \"; last read: '\" +\n\t\t\t\t\t\tm_lexer.get_token_string() + \"'\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terror_msg += \"unexpected \" + std::string(lexer_t::token_type_name(last_token));\n\t\t\t\t}\n\n\t\t\t\tif (expected != token_type::uninitialized)\n\t\t\t\t{\n\t\t\t\t\terror_msg += \"; expected \" + std::string(lexer_t::token_type_name(expected));\n\t\t\t\t}\n\n\t\t\t\treturn error_msg;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// callback function\n\t\t\tconst parser_callback_t callback = nullptr;\n\t\t\t/// the type of the last read token\n\t\t\ttoken_type last_token = token_type::uninitialized;\n\t\t\t/// the lexer\n\t\t\tlexer_t m_lexer;\n\t\t\t/// whether to throw exceptions in case of errors\n\t\t\tconst bool allow_exceptions = true;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <limits>  // numeric_limits\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t/*\n\t\t@brief an iterator for primitive JSON types\n\n\t\tThis class models an iterator for primitive JSON types (boolean, number,\n\t\tstring). It's only purpose is to allow the iterator/const_iterator classes\n\t\tto \"iterate\" over primitive values. Internally, the iterator is modeled by\n\t\ta `difference_type` variable. Value begin_value (`0`) models the begin,\n\t\tend_value (`1`) models past the end.\n\t\t*/\n\t\tclass primitive_iterator_t\n\t\t{\n\t\tprivate:\n\t\t\tusing difference_type = std::ptrdiff_t;\n\t\t\tstatic constexpr difference_type begin_value = 0;\n\t\t\tstatic constexpr difference_type end_value = begin_value + 1;\n\n\t\t\t/// iterator as signed integer type\n\t\t\tdifference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();\n\n\t\tpublic:\n\t\t\tconstexpr difference_type get_value() const noexcept\n\t\t\t{\n\t\t\t\treturn m_it;\n\t\t\t}\n\n\t\t\t/// set iterator to a defined beginning\n\t\t\tvoid set_begin() noexcept\n\t\t\t{\n\t\t\t\tm_it = begin_value;\n\t\t\t}\n\n\t\t\t/// set iterator to a defined past the end\n\t\t\tvoid set_end() noexcept\n\t\t\t{\n\t\t\t\tm_it = end_value;\n\t\t\t}\n\n\t\t\t/// return whether the iterator can be dereferenced\n\t\t\tconstexpr bool is_begin() const noexcept\n\t\t\t{\n\t\t\t\treturn m_it == begin_value;\n\t\t\t}\n\n\t\t\t/// return whether the iterator is at end\n\t\t\tconstexpr bool is_end() const noexcept\n\t\t\t{\n\t\t\t\treturn m_it == end_value;\n\t\t\t}\n\n\t\t\tfriend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n\t\t\t{\n\t\t\t\treturn lhs.m_it == rhs.m_it;\n\t\t\t}\n\n\t\t\tfriend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n\t\t\t{\n\t\t\t\treturn lhs.m_it < rhs.m_it;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t operator+(difference_type n) noexcept\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\tresult += n;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tfriend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n\t\t\t{\n\t\t\t\treturn lhs.m_it - rhs.m_it;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t& operator++() noexcept\n\t\t\t{\n\t\t\t\t++m_it;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t const operator++(int) noexcept\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\t++m_it;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t& operator--() noexcept\n\t\t\t{\n\t\t\t\t--m_it;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t const operator--(int) noexcept\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\t--m_it;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t& operator+=(difference_type n) noexcept\n\t\t\t{\n\t\t\t\tm_it += n;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tprimitive_iterator_t& operator-=(difference_type n) noexcept\n\t\t\t{\n\t\t\t\tm_it -= n;\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t/*!\n\t\t@brief an iterator value\n\n\t\t@note This structure could easily be a union, but MSVC currently does not allow\n\t\tunions members with complex constructors, see https://github.com/nlohmann/json/pull/105.\n\t\t*/\n\t\ttemplate<typename BasicJsonType> struct internal_iterator\n\t\t{\n\t\t\t/// iterator for JSON objects\n\t\t\ttypename BasicJsonType::object_t::iterator object_iterator{};\n\t\t\t/// iterator for JSON arrays\n\t\t\ttypename BasicJsonType::array_t::iterator array_iterator{};\n\t\t\t/// generic iterator for all other types\n\t\t\tprimitive_iterator_t primitive_iterator{};\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iter_impl.hpp>\n\n\n#include <ciso646> // not\n#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next\n#include <type_traits> // conditional, is_const, remove_const\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t// forward declare, to be able to friend it later on\n\t\ttemplate<typename IteratorType> class iteration_proxy;\n\t\ttemplate<typename IteratorType> class iteration_proxy_value;\n\n\t\t/*!\n\t\t@brief a template for a bidirectional iterator for the @ref basic_json class\n\t\tThis class implements a both iterators (iterator and const_iterator) for the\n\t\t@ref basic_json class.\n\t\t@note An iterator is called *initialized* when a pointer to a JSON value has\n\t\t\t  been set (e.g., by a constructor or a copy assignment). If the iterator is\n\t\t\t  default-constructed, it is *uninitialized* and most methods are undefined.\n\t\t\t  **The library uses assertions to detect calls on uninitialized iterators.**\n\t\t@requirement The class satisfies the following concept requirements:\n\t\t-\n\t\t[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n\t\t  The iterator that can be moved can be moved in both directions (i.e.\n\t\t  incremented and decremented).\n\t\t@since version 1.0.0, simplified in version 2.0.9, change to bidirectional\n\t\t\t   iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)\n\t\t*/\n\t\ttemplate<typename BasicJsonType>\n\t\tclass iter_impl\n\t\t{\n\t\t\t/// allow basic_json to access private members\n\t\t\tfriend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;\n\t\t\tfriend BasicJsonType;\n\t\t\tfriend iteration_proxy<iter_impl>;\n\t\t\tfriend iteration_proxy_value<iter_impl>;\n\n\t\t\tusing object_t = typename BasicJsonType::object_t;\n\t\t\tusing array_t = typename BasicJsonType::array_t;\n\t\t\t// make sure BasicJsonType is basic_json or const basic_json\n\t\t\tstatic_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,\n\t\t\t\t\"iter_impl only accepts (const) basic_json\");\n\n\t\tpublic:\n\n\t\t\t/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.\n\t\t\t/// The C++ Standard has never required user-defined iterators to derive from std::iterator.\n\t\t\t/// A user-defined iterator should provide publicly accessible typedefs named\n\t\t\t/// iterator_category, value_type, difference_type, pointer, and reference.\n\t\t\t/// Note that value_type is required to be non-const, even for constant iterators.\n\t\t\tusing iterator_category = std::bidirectional_iterator_tag;\n\n\t\t\t/// the type of the values when the iterator is dereferenced\n\t\t\tusing value_type = typename BasicJsonType::value_type;\n\t\t\t/// a type to represent differences between iterators\n\t\t\tusing difference_type = typename BasicJsonType::difference_type;\n\t\t\t/// defines a pointer to the type iterated over (value_type)\n\t\t\tusing pointer = typename std::conditional<std::is_const<BasicJsonType>::value,\n\t\t\t\ttypename BasicJsonType::const_pointer,\n\t\t\t\ttypename BasicJsonType::pointer>::type;\n\t\t\t/// defines a reference to the type iterated over (value_type)\n\t\t\tusing reference =\n\t\t\t\ttypename std::conditional<std::is_const<BasicJsonType>::value,\n\t\t\t\ttypename BasicJsonType::const_reference,\n\t\t\t\ttypename BasicJsonType::reference>::type;\n\n\t\t\t/// default constructor\n\t\t\titer_impl() = default;\n\n\t\t\t/*!\n\t\t\t@brief constructor for a given JSON instance\n\t\t\t@param[in] object  pointer to a JSON object for this iterator\n\t\t\t@pre object != nullptr\n\t\t\t@post The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\texplicit iter_impl(pointer object) noexcept : m_object(object)\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tm_it.object_iterator = typename object_t::iterator();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tm_it.array_iterator = typename array_t::iterator();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tm_it.primitive_iterator = primitive_iterator_t();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@note The conventional copy constructor and copy assignment are implicitly\n\t\t\t\t  defined. Combined with the following converting constructor and\n\t\t\t\t  assignment, they support: (1) copy from iterator to iterator, (2)\n\t\t\t\t  copy from const iterator to const iterator, and (3) conversion from\n\t\t\t\t  iterator to const iterator. However conversion from const iterator\n\t\t\t\t  to iterator is not defined.\n\t\t\t*/\n\n\t\t\t/*!\n\t\t\t@brief converting constructor\n\t\t\t@param[in] other  non-const iterator to copy from\n\t\t\t@note It is not checked whether @a other is initialized.\n\t\t\t*/\n\t\t\titer_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n\t\t\t\t: m_object(other.m_object), m_it(other.m_it) {}\n\n\t\t\t/*!\n\t\t\t@brief converting assignment\n\t\t\t@param[in,out] other  non-const iterator to copy from\n\t\t\t@return const/non-const iterator\n\t\t\t@note It is not checked whether @a other is initialized.\n\t\t\t*/\n\t\t\titer_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n\t\t\t{\n\t\t\t\tm_object = other.m_object;\n\t\t\t\tm_it = other.m_it;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/*!\n\t\t\t@brief set the iterator to the first value\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tvoid set_begin() noexcept\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tm_it.object_iterator = m_object->m_value.object->begin();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tm_it.array_iterator = m_object->m_value.array->begin();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t{\n\t\t\t\t\t// set to end so begin()==end() is true: null is empty\n\t\t\t\t\tm_it.primitive_iterator.set_end();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tm_it.primitive_iterator.set_begin();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief set the iterator past the last value\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tvoid set_end() noexcept\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tm_it.object_iterator = m_object->m_value.object->end();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tm_it.array_iterator = m_object->m_value.array->end();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tm_it.primitive_iterator.set_end();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tpublic:\n\t\t\t/*!\n\t\t\t@brief return a reference to the value pointed to by the iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\treference operator*() const\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tassert(m_it.object_iterator != m_object->m_value.object->end());\n\t\t\t\t\treturn m_it.object_iterator->second;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tassert(m_it.array_iterator != m_object->m_value.array->end());\n\t\t\t\t\treturn *m_it.array_iterator;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tif (JSON_LIKELY(m_it.primitive_iterator.is_begin()))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn *m_object;\n\t\t\t\t\t}\n\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief dereference the iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tpointer operator->() const\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tassert(m_it.object_iterator != m_object->m_value.object->end());\n\t\t\t\t\treturn &(m_it.object_iterator->second);\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tassert(m_it.array_iterator != m_object->m_value.array->end());\n\t\t\t\t\treturn &*m_it.array_iterator;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tif (JSON_LIKELY(m_it.primitive_iterator.is_begin()))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn m_object;\n\t\t\t\t\t}\n\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief post-increment (it++)\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl const operator++(int)\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\t++(*this);\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief pre-increment (++it)\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl& operator++()\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tstd::advance(m_it.object_iterator, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tstd::advance(m_it.array_iterator, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\t++m_it.primitive_iterator;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief post-decrement (it--)\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl const operator--(int)\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\t--(*this);\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief pre-decrement (--it)\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl& operator--()\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tstd::advance(m_it.object_iterator, -1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tstd::advance(m_it.array_iterator, -1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\t--m_it.primitive_iterator;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  comparison: equal\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tbool operator==(const iter_impl& other) const\n\t\t\t{\n\t\t\t\t// if objects are not the same, the comparison is undefined\n\t\t\t\tif (JSON_UNLIKELY(m_object != other.m_object))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n\t\t\t\t}\n\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn (m_it.object_iterator == other.m_it.object_iterator);\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn (m_it.array_iterator == other.m_it.array_iterator);\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn (m_it.primitive_iterator == other.m_it.primitive_iterator);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  comparison: not equal\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tbool operator!=(const iter_impl& other) const\n\t\t\t{\n\t\t\t\treturn not operator==(other);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  comparison: smaller\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tbool operator<(const iter_impl& other) const\n\t\t\t{\n\t\t\t\t// if objects are not the same, the comparison is undefined\n\t\t\t\tif (JSON_UNLIKELY(m_object != other.m_object))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n\t\t\t\t}\n\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(213, \"cannot compare order of object iterators\"));\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn (m_it.array_iterator < other.m_it.array_iterator);\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn (m_it.primitive_iterator < other.m_it.primitive_iterator);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  comparison: less than or equal\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tbool operator<=(const iter_impl& other) const\n\t\t\t{\n\t\t\t\treturn not other.operator < (*this);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  comparison: greater than\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tbool operator>(const iter_impl& other) const\n\t\t\t{\n\t\t\t\treturn not operator<=(other);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  comparison: greater than or equal\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tbool operator>=(const iter_impl& other) const\n\t\t\t{\n\t\t\t\treturn not operator<(other);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  add to iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl& operator+=(difference_type i)\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tstd::advance(m_it.array_iterator, i);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tm_it.primitive_iterator += i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  subtract from iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl& operator-=(difference_type i)\n\t\t\t{\n\t\t\t\treturn operator+=(-i);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  add to iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl operator+(difference_type i) const\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\tresult += i;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  addition of distance and iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tfriend iter_impl operator+(difference_type i, const iter_impl& it)\n\t\t\t{\n\t\t\t\tauto result = it;\n\t\t\t\tresult += i;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  subtract from iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\titer_impl operator-(difference_type i) const\n\t\t\t{\n\t\t\t\tauto result = *this;\n\t\t\t\tresult -= i;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  return difference\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tdifference_type operator-(const iter_impl& other) const\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn m_it.array_iterator - other.m_it.array_iterator;\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn m_it.primitive_iterator - other.m_it.primitive_iterator;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  access to successor\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\treference operator[](difference_type n) const\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tswitch (m_object->m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(208, \"cannot use operator[] for object iterators\"));\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn *std::next(m_it.array_iterator, n);\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tif (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn *m_object;\n\t\t\t\t\t}\n\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  return the key of an object iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\tconst typename object_t::key_type& key() const\n\t\t\t{\n\t\t\t\tassert(m_object != nullptr);\n\n\t\t\t\tif (JSON_LIKELY(m_object->is_object()))\n\t\t\t\t{\n\t\t\t\t\treturn m_it.object_iterator->first;\n\t\t\t\t}\n\n\t\t\t\tJSON_THROW(invalid_iterator::create(207, \"cannot use key() for non-object iterators\"));\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief  return the value of an iterator\n\t\t\t@pre The iterator is initialized; i.e. `m_object != nullptr`.\n\t\t\t*/\n\t\t\treference value() const\n\t\t\t{\n\t\t\t\treturn operator*();\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// associated JSON instance\n\t\t\tpointer m_object = nullptr;\n\t\t\t/// the actual iterator of the associated instance\n\t\t\tinternal_iterator<typename std::remove_const<BasicJsonType>::type> m_it{};\n\t\t};\n\t}  // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <iterator> // reverse_iterator\n#include <utility> // declval\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t//////////////////////\n\t\t// reverse_iterator //\n\t\t//////////////////////\n\n\t\t/*!\n\t\t@brief a template for a reverse iterator class\n\n\t\t@tparam Base the base iterator type to reverse. Valid types are @ref\n\t\titerator (to create @ref reverse_iterator) and @ref const_iterator (to\n\t\tcreate @ref const_reverse_iterator).\n\n\t\t@requirement The class satisfies the following concept requirements:\n\t\t-\n\t\t[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n\t\t  The iterator that can be moved can be moved in both directions (i.e.\n\t\t  incremented and decremented).\n\t\t- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):\n\t\t  It is possible to write to the pointed-to element (only if @a Base is\n\t\t  @ref iterator).\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<typename Base>\n\t\tclass json_reverse_iterator : public std::reverse_iterator<Base>\n\t\t{\n\t\tpublic:\n\t\t\tusing difference_type = std::ptrdiff_t;\n\t\t\t/// shortcut to the reverse iterator adapter\n\t\t\tusing base_iterator = std::reverse_iterator<Base>;\n\t\t\t/// the reference type for the pointed-to element\n\t\t\tusing reference = typename Base::reference;\n\n\t\t\t/// create reverse iterator from iterator\n\t\t\texplicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept\n\t\t\t\t: base_iterator(it) {}\n\n\t\t\t/// create reverse iterator from base class\n\t\t\texplicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}\n\n\t\t\t/// post-increment (it++)\n\t\t\tjson_reverse_iterator const operator++(int)\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator>(base_iterator::operator++(1));\n\t\t\t}\n\n\t\t\t/// pre-increment (++it)\n\t\t\tjson_reverse_iterator& operator++()\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator&>(base_iterator::operator++());\n\t\t\t}\n\n\t\t\t/// post-decrement (it--)\n\t\t\tjson_reverse_iterator const operator--(int)\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator>(base_iterator::operator--(1));\n\t\t\t}\n\n\t\t\t/// pre-decrement (--it)\n\t\t\tjson_reverse_iterator& operator--()\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator&>(base_iterator::operator--());\n\t\t\t}\n\n\t\t\t/// add to iterator\n\t\t\tjson_reverse_iterator& operator+=(difference_type i)\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));\n\t\t\t}\n\n\t\t\t/// add to iterator\n\t\t\tjson_reverse_iterator operator+(difference_type i) const\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator>(base_iterator::operator+(i));\n\t\t\t}\n\n\t\t\t/// subtract from iterator\n\t\t\tjson_reverse_iterator operator-(difference_type i) const\n\t\t\t{\n\t\t\t\treturn static_cast<json_reverse_iterator>(base_iterator::operator-(i));\n\t\t\t}\n\n\t\t\t/// return difference\n\t\t\tdifference_type operator-(const json_reverse_iterator& other) const\n\t\t\t{\n\t\t\t\treturn base_iterator(*this) - base_iterator(other);\n\t\t\t}\n\n\t\t\t/// access to successor\n\t\t\treference operator[](difference_type n) const\n\t\t\t{\n\t\t\t\treturn *(this->operator+(n));\n\t\t\t}\n\n\t\t\t/// return the key of an object iterator\n\t\t\tauto key() const -> decltype(std::declval<Base>().key())\n\t\t\t{\n\t\t\t\tauto it = --this->base();\n\t\t\t\treturn it.key();\n\t\t\t}\n\n\t\t\t/// return the value of an iterator\n\t\t\treference value() const\n\t\t\t{\n\t\t\t\tauto it = --this->base();\n\t\t\t\treturn it.operator * ();\n\t\t\t}\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/json_pointer.hpp>\n\n\n#include <algorithm> // all_of\n#include <cassert> // assert\n#include <numeric> // accumulate\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\ttemplate<typename BasicJsonType>\n\tclass json_pointer\n\t{\n\t\t// allow basic_json to access private members\n\t\tNLOHMANN_BASIC_JSON_TPL_DECLARATION\n\t\t\tfriend class basic_json;\n\n\tpublic:\n\t\t/*!\n\t\t@brief create JSON pointer\n\n\t\tCreate a JSON pointer according to the syntax described in\n\t\t[Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).\n\n\t\t@param[in] s  string representing the JSON pointer; if omitted, the empty\n\t\t\t\t\t  string is assumed which references the whole JSON value\n\n\t\t@throw parse_error.107 if the given JSON pointer @a s is nonempty and does\n\t\t\t\t\t\t\t   not begin with a slash (`/`); see example below\n\n\t\t@throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is\n\t\tnot followed by `0` (representing `~`) or `1` (representing `/`); see\n\t\texample below\n\n\t\t@liveexample{The example shows the construction several valid JSON pointers\n\t\tas well as the exceptional behavior.,json_pointer}\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\texplicit json_pointer(const std::string& s = \"\")\n\t\t\t: reference_tokens(split(s))\n\t\t{}\n\n\t\t/*!\n\t\t@brief return a string representation of the JSON pointer\n\n\t\t@invariant For each JSON pointer `ptr`, it holds:\n\t\t@code {.cpp}\n\t\tptr == json_pointer(ptr.to_string());\n\t\t@endcode\n\n\t\t@return a string representation of the JSON pointer\n\n\t\t@liveexample{The example shows the result of `to_string`.,json_pointer__to_string}\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tstd::string to_string() const\n\t\t{\n\t\t\treturn std::accumulate(reference_tokens.begin(), reference_tokens.end(),\n\t\t\t\tstd::string{},\n\t\t\t\t[](const std::string & a, const std::string & b)\n\t\t\t\t{\n\t\t\t\t\treturn a + \"/\" + escape(b);\n\t\t\t\t});\n\t\t}\n\n\t\t/// @copydoc to_string()\n\t\toperator std::string() const\n\t\t{\n\t\t\treturn to_string();\n\t\t}\n\n\t\t/*!\n\t\t@brief append another JSON pointer at the end of this JSON pointer\n\n\t\t@param[in] ptr  JSON pointer to append\n\t\t@return JSON pointer with @a ptr appended\n\n\t\t@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n\t\t@complexity Linear in the length of @a ptr.\n\n\t\t@sa @ref operator/=(std::string) to append a reference token\n\t\t@sa @ref operator/=(std::size_t) to append an array index\n\t\t@sa @ref operator/(const json_pointer&, const json_pointer&) for a binary operator\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tjson_pointer& operator/=(const json_pointer& ptr)\n\t\t{\n\t\t\treference_tokens.insert(reference_tokens.end(),\n\t\t\t\tptr.reference_tokens.begin(),\n\t\t\t\tptr.reference_tokens.end());\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief append an unescaped reference token at the end of this JSON pointer\n\n\t\t@param[in] token  reference token to append\n\t\t@return JSON pointer with @a token appended without escaping @a token\n\n\t\t@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n\t\t@complexity Amortized constant.\n\n\t\t@sa @ref operator/=(const json_pointer&) to append a JSON pointer\n\t\t@sa @ref operator/=(std::size_t) to append an array index\n\t\t@sa @ref operator/(const json_pointer&, std::size_t) for a binary operator\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tjson_pointer& operator/=(std::string token)\n\t\t{\n\t\t\tpush_back(std::move(token));\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief append an array index at the end of this JSON pointer\n\n\t\t@param[in] array_index  array index ot append\n\t\t@return JSON pointer with @a array_index appended\n\n\t\t@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n\t\t@complexity Amortized constant.\n\n\t\t@sa @ref operator/=(const json_pointer&) to append a JSON pointer\n\t\t@sa @ref operator/=(std::string) to append a reference token\n\t\t@sa @ref operator/(const json_pointer&, std::string) for a binary operator\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tjson_pointer& operator/=(std::size_t array_index)\n\t\t{\n\t\t\treturn *this /= std::to_string(array_index);\n\t\t}\n\n\t\t/*!\n\t\t@brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer\n\n\t\t@param[in] lhs  JSON pointer\n\t\t@param[in] rhs  JSON pointer\n\t\t@return a new JSON pointer with @a rhs appended to @a lhs\n\n\t\t@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n\t\t@complexity Linear in the length of @a lhs and @a rhs.\n\n\t\t@sa @ref operator/=(const json_pointer&) to append a JSON pointer\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tfriend json_pointer operator/(const json_pointer& lhs,\n\t\t\tconst json_pointer& rhs)\n\t\t{\n\t\t\treturn json_pointer(lhs) /= rhs;\n\t\t}\n\n\t\t/*!\n\t\t@brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer\n\n\t\t@param[in] ptr  JSON pointer\n\t\t@param[in] token  reference token\n\t\t@return a new JSON pointer with unescaped @a token appended to @a ptr\n\n\t\t@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n\t\t@complexity Linear in the length of @a ptr.\n\n\t\t@sa @ref operator/=(std::string) to append a reference token\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tfriend json_pointer operator/(const json_pointer& ptr, std::string token)\n\t\t{\n\t\t\treturn json_pointer(ptr) /= std::move(token);\n\t\t}\n\n\t\t/*!\n\t\t@brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer\n\n\t\t@param[in] ptr  JSON pointer\n\t\t@param[in] array_index  array index\n\t\t@return a new JSON pointer with @a array_index appended to @a ptr\n\n\t\t@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n\t\t@complexity Linear in the length of @a ptr.\n\n\t\t@sa @ref operator/=(std::size_t) to append an array index\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tfriend json_pointer operator/(const json_pointer& ptr, std::size_t array_index)\n\t\t{\n\t\t\treturn json_pointer(ptr) /= array_index;\n\t\t}\n\n\t\t/*!\n\t\t@brief returns the parent of this JSON pointer\n\n\t\t@return parent of this JSON pointer; in case this JSON pointer is the root,\n\t\t\t\tthe root itself is returned\n\n\t\t@complexity Linear in the length of the JSON pointer.\n\n\t\t@liveexample{The example shows the result of `parent_pointer` for different\n\t\tJSON Pointers.,json_pointer__parent_pointer}\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tjson_pointer parent_pointer() const\n\t\t{\n\t\t\tif (empty())\n\t\t\t{\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tjson_pointer res = *this;\n\t\t\tres.pop_back();\n\t\t\treturn res;\n\t\t}\n\n\t\t/*!\n\t\t@brief remove last reference token\n\n\t\t@pre not `empty()`\n\n\t\t@liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back}\n\n\t\t@complexity Constant.\n\n\t\t@throw out_of_range.405 if JSON pointer has no parent\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tvoid pop_back()\n\t\t{\n\t\t\tif (JSON_UNLIKELY(empty()))\n\t\t\t{\n\t\t\t\tJSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n\t\t\t}\n\n\t\t\treference_tokens.pop_back();\n\t\t}\n\n\t\t/*!\n\t\t@brief return last reference token\n\n\t\t@pre not `empty()`\n\t\t@return last reference token\n\n\t\t@liveexample{The example shows the usage of `back`.,json_pointer__back}\n\n\t\t@complexity Constant.\n\n\t\t@throw out_of_range.405 if JSON pointer has no parent\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tconst std::string& back()\n\t\t{\n\t\t\tif (JSON_UNLIKELY(empty()))\n\t\t\t{\n\t\t\t\tJSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n\t\t\t}\n\n\t\t\treturn reference_tokens.back();\n\t\t}\n\n\t\t/*!\n\t\t@brief append an unescaped token at the end of the reference pointer\n\n\t\t@param[in] token  token to add\n\n\t\t@complexity Amortized constant.\n\n\t\t@liveexample{The example shows the result of `push_back` for different\n\t\tJSON Pointers.,json_pointer__push_back}\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tvoid push_back(const std::string& token)\n\t\t{\n\t\t\treference_tokens.push_back(token);\n\t\t}\n\n\t\t/// @copydoc push_back(const std::string&)\n\t\tvoid push_back(std::string&& token)\n\t\t{\n\t\t\treference_tokens.push_back(std::move(token));\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether pointer points to the root document\n\n\t\t@return true iff the JSON pointer points to the root document\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@liveexample{The example shows the result of `empty` for different JSON\n\t\tPointers.,json_pointer__empty}\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\tbool empty() const noexcept\n\t\t{\n\t\t\treturn reference_tokens.empty();\n\t\t}\n\n\tprivate:\n\t\t/*!\n\t\t@param[in] s  reference token to be converted into an array index\n\n\t\t@return integer representation of @a s\n\n\t\t@throw out_of_range.404 if string @a s could not be converted to an integer\n\t\t*/\n\t\tstatic int array_index(const std::string& s)\n\t\t{\n\t\t\tstd::size_t processed_chars = 0;\n\t\t\tconst int res = std::stoi(s, &processed_chars);\n\n\t\t\t// check if the string was completely read\n\t\t\tif (JSON_UNLIKELY(processed_chars != s.size()))\n\t\t\t{\n\t\t\t\tJSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\"));\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\n\t\tjson_pointer top() const\n\t\t{\n\t\t\tif (JSON_UNLIKELY(empty()))\n\t\t\t{\n\t\t\t\tJSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n\t\t\t}\n\n\t\t\tjson_pointer result = *this;\n\t\t\tresult.reference_tokens = { reference_tokens[0] };\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief create and return a reference to the pointed to value\n\n\t\t@complexity Linear in the number of reference tokens.\n\n\t\t@throw parse_error.109 if array index is not a number\n\t\t@throw type_error.313 if value cannot be unflattened\n\t\t*/\n\t\tBasicJsonType& get_and_create(BasicJsonType& j) const\n\t\t{\n\t\t\tusing size_type = typename BasicJsonType::size_type;\n\t\t\tauto result = &j;\n\n\t\t\t// in case no reference tokens exist, return a reference to the JSON value\n\t\t\t// j which will be overwritten by a primitive value\n\t\t\tfor (const auto& reference_token : reference_tokens)\n\t\t\t{\n\t\t\t\tswitch (result->m_type)\n\t\t\t\t{\n\t\t\t\tcase detail::value_t::null:\n\t\t\t\t{\n\t\t\t\t\tif (reference_token == \"0\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// start a new array if reference token is 0\n\t\t\t\t\t\tresult = &result->operator[](0);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// start a new object otherwise\n\t\t\t\t\t\tresult = &result->operator[](reference_token);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase detail::value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// create an entry in the object\n\t\t\t\t\tresult = &result->operator[](reference_token);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase detail::value_t::array:\n\t\t\t\t{\n\t\t\t\t\t// create an entry in the array\n\t\t\t\t\tJSON_TRY\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = &result->operator[](static_cast<size_type>(array_index(reference_token)));\n\t\t\t\t\t}\n\t\t\t\t\t\tJSON_CATCH(std::invalid_argument&)\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\tThe following code is only reached if there exists a reference\n\t\t\t\ttoken _and_ the current value is primitive. In this case, we have\n\t\t\t\tan error situation, because primitive values may only occur as\n\t\t\t\tsingle value; that is, with an empty list of reference tokens.\n\t\t\t\t*/\n\t\t\t\tdefault:\n\t\t\t\t\tJSON_THROW(detail::type_error::create(313, \"invalid value to unflatten\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *result;\n\t\t}\n\n\t\t/*!\n\t\t@brief return a reference to the pointed to value\n\n\t\t@note This version does not throw if a value is not present, but tries to\n\t\t\t  create nested values instead. For instance, calling this function\n\t\t\t  with pointer `\"/this/that\"` on a null value is equivalent to calling\n\t\t\t  `operator[](\"this\").operator[](\"that\")` on that value, effectively\n\t\t\t  changing the null value to an object.\n\n\t\t@param[in] ptr  a JSON value\n\n\t\t@return reference to the JSON value pointed to by the JSON pointer\n\n\t\t@complexity Linear in the length of the JSON pointer.\n\n\t\t@throw parse_error.106   if an array index begins with '0'\n\t\t@throw parse_error.109   if an array index was not a number\n\t\t@throw out_of_range.404  if the JSON pointer can not be resolved\n\t\t*/\n\t\tBasicJsonType& get_unchecked(BasicJsonType* ptr) const\n\t\t{\n\t\t\tusing size_type = typename BasicJsonType::size_type;\n\t\t\tfor (const auto& reference_token : reference_tokens)\n\t\t\t{\n\t\t\t\t// convert null values to arrays or objects before continuing\n\t\t\t\tif (ptr->m_type == detail::value_t::null)\n\t\t\t\t{\n\t\t\t\t\t// check if reference token is a number\n\t\t\t\t\tconst bool nums =\n\t\t\t\t\t\tstd::all_of(reference_token.begin(), reference_token.end(),\n\t\t\t\t\t\t\t[](const char x)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn x >= '0' and x <= '9';\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t// change value to array for numbers or \"-\" or to object otherwise\n\t\t\t\t\t*ptr = (nums or reference_token == \"-\")\n\t\t\t\t\t\t? detail::value_t::array\n\t\t\t\t\t\t: detail::value_t::object;\n\t\t\t\t}\n\n\t\t\t\tswitch (ptr->m_type)\n\t\t\t\t{\n\t\t\t\tcase detail::value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// use unchecked object access\n\t\t\t\t\tptr = &ptr->operator[](reference_token);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase detail::value_t::array:\n\t\t\t\t{\n\t\t\t\t\t// error condition (cf. RFC 6901, Sect. 4)\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(106, 0,\n\t\t\t\t\t\t\t\"array index '\" + reference_token +\n\t\t\t\t\t\t\t\"' must not begin with '0'\"));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (reference_token == \"-\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// explicitly treat \"-\" as index beyond the end\n\t\t\t\t\t\tptr = &ptr->operator[](ptr->m_value.array->size());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// convert array index to number; unchecked access\n\t\t\t\t\t\tJSON_TRY\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tptr = &ptr->operator[](\n\t\t\t\t\t\t\t\tstatic_cast<size_type>(array_index(reference_token)));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\tJSON_CATCH(std::invalid_argument&)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tJSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *ptr;\n\t\t}\n\n\t\t/*!\n\t\t@throw parse_error.106   if an array index begins with '0'\n\t\t@throw parse_error.109   if an array index was not a number\n\t\t@throw out_of_range.402  if the array index '-' is used\n\t\t@throw out_of_range.404  if the JSON pointer can not be resolved\n\t\t*/\n\t\tBasicJsonType& get_checked(BasicJsonType* ptr) const\n\t\t{\n\t\t\tusing size_type = typename BasicJsonType::size_type;\n\t\t\tfor (const auto& reference_token : reference_tokens)\n\t\t\t{\n\t\t\t\tswitch (ptr->m_type)\n\t\t\t\t{\n\t\t\t\tcase detail::value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// note: at performs range check\n\t\t\t\t\tptr = &ptr->at(reference_token);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase detail::value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token == \"-\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t// \"-\" always fails the range check\n\t\t\t\t\t\tJSON_THROW(detail::out_of_range::create(402,\n\t\t\t\t\t\t\t\"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n\t\t\t\t\t\t\t\") is out of range\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// error condition (cf. RFC 6901, Sect. 4)\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(106, 0,\n\t\t\t\t\t\t\t\"array index '\" + reference_token +\n\t\t\t\t\t\t\t\"' must not begin with '0'\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// note: at performs range check\n\t\t\t\t\tJSON_TRY\n\t\t\t\t\t{\n\t\t\t\t\t\tptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));\n\t\t\t\t\t}\n\t\t\t\t\t\tJSON_CATCH(std::invalid_argument&)\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tJSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *ptr;\n\t\t}\n\n\t\t/*!\n\t\t@brief return a const reference to the pointed to value\n\n\t\t@param[in] ptr  a JSON value\n\n\t\t@return const reference to the JSON value pointed to by the JSON\n\t\tpointer\n\n\t\t@throw parse_error.106   if an array index begins with '0'\n\t\t@throw parse_error.109   if an array index was not a number\n\t\t@throw out_of_range.402  if the array index '-' is used\n\t\t@throw out_of_range.404  if the JSON pointer can not be resolved\n\t\t*/\n\t\tconst BasicJsonType& get_unchecked(const BasicJsonType* ptr) const\n\t\t{\n\t\t\tusing size_type = typename BasicJsonType::size_type;\n\t\t\tfor (const auto& reference_token : reference_tokens)\n\t\t\t{\n\t\t\t\tswitch (ptr->m_type)\n\t\t\t\t{\n\t\t\t\tcase detail::value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// use unchecked object access\n\t\t\t\t\tptr = &ptr->operator[](reference_token);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase detail::value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token == \"-\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t// \"-\" cannot be used for const access\n\t\t\t\t\t\tJSON_THROW(detail::out_of_range::create(402,\n\t\t\t\t\t\t\t\"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n\t\t\t\t\t\t\t\") is out of range\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// error condition (cf. RFC 6901, Sect. 4)\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(106, 0,\n\t\t\t\t\t\t\t\"array index '\" + reference_token +\n\t\t\t\t\t\t\t\"' must not begin with '0'\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// use unchecked array access\n\t\t\t\t\tJSON_TRY\n\t\t\t\t\t{\n\t\t\t\t\t\tptr = &ptr->operator[](\n\t\t\t\t\t\t\tstatic_cast<size_type>(array_index(reference_token)));\n\t\t\t\t\t}\n\t\t\t\t\t\tJSON_CATCH(std::invalid_argument&)\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tJSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *ptr;\n\t\t}\n\n\t\t/*!\n\t\t@throw parse_error.106   if an array index begins with '0'\n\t\t@throw parse_error.109   if an array index was not a number\n\t\t@throw out_of_range.402  if the array index '-' is used\n\t\t@throw out_of_range.404  if the JSON pointer can not be resolved\n\t\t*/\n\t\tconst BasicJsonType& get_checked(const BasicJsonType* ptr) const\n\t\t{\n\t\t\tusing size_type = typename BasicJsonType::size_type;\n\t\t\tfor (const auto& reference_token : reference_tokens)\n\t\t\t{\n\t\t\t\tswitch (ptr->m_type)\n\t\t\t\t{\n\t\t\t\tcase detail::value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// note: at performs range check\n\t\t\t\t\tptr = &ptr->at(reference_token);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase detail::value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token == \"-\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t// \"-\" always fails the range check\n\t\t\t\t\t\tJSON_THROW(detail::out_of_range::create(402,\n\t\t\t\t\t\t\t\"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n\t\t\t\t\t\t\t\") is out of range\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// error condition (cf. RFC 6901, Sect. 4)\n\t\t\t\t\tif (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(106, 0,\n\t\t\t\t\t\t\t\"array index '\" + reference_token +\n\t\t\t\t\t\t\t\"' must not begin with '0'\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// note: at performs range check\n\t\t\t\t\tJSON_TRY\n\t\t\t\t\t{\n\t\t\t\t\t\tptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));\n\t\t\t\t\t}\n\t\t\t\t\t\tJSON_CATCH(std::invalid_argument&)\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tJSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn *ptr;\n\t\t}\n\n\t\t/*!\n\t\t@brief split the string input to reference tokens\n\n\t\t@note This function is only called by the json_pointer constructor.\n\t\t\t  All exceptions below are documented there.\n\n\t\t@throw parse_error.107  if the pointer is not empty or begins with '/'\n\t\t@throw parse_error.108  if character '~' is not followed by '0' or '1'\n\t\t*/\n\t\tstatic std::vector<std::string> split(const std::string& reference_string)\n\t\t{\n\t\t\tstd::vector<std::string> result;\n\n\t\t\t// special case: empty reference string -> no reference tokens\n\t\t\tif (reference_string.empty())\n\t\t\t{\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\t// check if nonempty reference string begins with slash\n\t\t\tif (JSON_UNLIKELY(reference_string[0] != '/'))\n\t\t\t{\n\t\t\t\tJSON_THROW(detail::parse_error::create(107, 1,\n\t\t\t\t\t\"JSON pointer must be empty or begin with '/' - was: '\" +\n\t\t\t\t\treference_string + \"'\"));\n\t\t\t}\n\n\t\t\t// extract the reference tokens:\n\t\t\t// - slash: position of the last read slash (or end of string)\n\t\t\t// - start: position after the previous slash\n\t\t\tfor (\n\t\t\t\t// search for the first slash after the first character\n\t\t\t\tstd::size_t slash = reference_string.find_first_of('/', 1),\n\t\t\t\t// set the beginning of the first reference token\n\t\t\t\tstart = 1;\n\t\t\t\t// we can stop if start == 0 (if slash == std::string::npos)\n\t\t\t\tstart != 0;\n\t\t\t\t// set the beginning of the next reference token\n\t\t\t\t// (will eventually be 0 if slash == std::string::npos)\n\t\t\t\tstart = (slash == std::string::npos) ? 0 : slash + 1,\n\t\t\t\t// find next slash\n\t\t\t\tslash = reference_string.find_first_of('/', start))\n\t\t\t{\n\t\t\t\t// use the text between the beginning of the reference token\n\t\t\t\t// (start) and the last slash (slash).\n\t\t\t\tauto reference_token = reference_string.substr(start, slash - start);\n\n\t\t\t\t// check reference tokens are properly escaped\n\t\t\t\tfor (std::size_t pos = reference_token.find_first_of('~');\n\t\t\t\t\tpos != std::string::npos;\n\t\t\t\t\tpos = reference_token.find_first_of('~', pos + 1))\n\t\t\t\t{\n\t\t\t\t\tassert(reference_token[pos] == '~');\n\n\t\t\t\t\t// ~ must be followed by 0 or 1\n\t\t\t\t\tif (JSON_UNLIKELY(pos == reference_token.size() - 1 or\n\t\t\t\t\t\t(reference_token[pos + 1] != '0' and\n\t\t\t\t\t\t\treference_token[pos + 1] != '1')))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(detail::parse_error::create(108, 0, \"escape character '~' must be followed with '0' or '1'\"));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// finally, store the reference token\n\t\t\t\tunescape(reference_token);\n\t\t\t\tresult.push_back(reference_token);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief replace all occurrences of a substring by another string\n\n\t\t@param[in,out] s  the string to manipulate; changed so that all\n\t\t\t\t\t   occurrences of @a f are replaced with @a t\n\t\t@param[in]     f  the substring to replace with @a t\n\t\t@param[in]     t  the string to replace @a f\n\n\t\t@pre The search string @a f must not be empty. **This precondition is\n\t\tenforced with an assertion.**\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tstatic void replace_substring(std::string& s, const std::string& f,\n\t\t\tconst std::string& t)\n\t\t{\n\t\t\tassert(not f.empty());\n\t\t\tfor (auto pos = s.find(f);                // find first occurrence of f\n\t\t\t\tpos != std::string::npos;         // make sure f was found\n\t\t\t\ts.replace(pos, f.size(), t),      // replace with t, and\n\t\t\t\tpos = s.find(f, pos + t.size()))  // find next occurrence of f\n\t\t\t{\n\t\t\t}\n\t\t}\n\n\t\t/// escape \"~\" to \"~0\" and \"/\" to \"~1\"\n\t\tstatic std::string escape(std::string s)\n\t\t{\n\t\t\treplace_substring(s, \"~\", \"~0\");\n\t\t\treplace_substring(s, \"/\", \"~1\");\n\t\t\treturn s;\n\t\t}\n\n\t\t/// unescape \"~1\" to tilde and \"~0\" to slash (order is important!)\n\t\tstatic void unescape(std::string& s)\n\t\t{\n\t\t\treplace_substring(s, \"~1\", \"/\");\n\t\t\treplace_substring(s, \"~0\", \"~\");\n\t\t}\n\n\t\t/*!\n\t\t@param[in] reference_string  the reference string to the current value\n\t\t@param[in] value             the value to consider\n\t\t@param[in,out] result        the result object to insert values to\n\n\t\t@note Empty objects or arrays are flattened to `null`.\n\t\t*/\n\t\tstatic void flatten(const std::string& reference_string,\n\t\t\tconst BasicJsonType& value,\n\t\t\tBasicJsonType& result)\n\t\t{\n\t\t\tswitch (value.m_type)\n\t\t\t{\n\t\t\tcase detail::value_t::array:\n\t\t\t{\n\t\t\t\tif (value.m_value.array->empty())\n\t\t\t\t{\n\t\t\t\t\t// flatten empty array as null\n\t\t\t\t\tresult[reference_string] = nullptr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// iterate array and use index as reference string\n\t\t\t\t\tfor (std::size_t i = 0; i < value.m_value.array->size(); ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tflatten(reference_string + \"/\" + std::to_string(i),\n\t\t\t\t\t\t\tvalue.m_value.array->operator[](i), result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase detail::value_t::object:\n\t\t\t{\n\t\t\t\tif (value.m_value.object->empty())\n\t\t\t\t{\n\t\t\t\t\t// flatten empty object as null\n\t\t\t\t\tresult[reference_string] = nullptr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// iterate object and use keys as reference string\n\t\t\t\t\tfor (const auto& element : *value.m_value.object)\n\t\t\t\t\t{\n\t\t\t\t\t\tflatten(reference_string + \"/\" + escape(element.first), element.second, result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// add primitive value with its reference string\n\t\t\t\tresult[reference_string] = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@param[in] value  flattened JSON\n\n\t\t@return unflattened JSON\n\n\t\t@throw parse_error.109 if array index is not a number\n\t\t@throw type_error.314  if value is not an object\n\t\t@throw type_error.315  if object values are not primitive\n\t\t@throw type_error.313  if value cannot be unflattened\n\t\t*/\n\t\tstatic BasicJsonType\n\t\t\tunflatten(const BasicJsonType& value)\n\t\t{\n\t\t\tif (JSON_UNLIKELY(not value.is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(detail::type_error::create(314, \"only objects can be unflattened\"));\n\t\t\t}\n\n\t\t\tBasicJsonType result;\n\n\t\t\t// iterate the JSON object values\n\t\t\tfor (const auto& element : *value.m_value.object)\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not element.second.is_primitive()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(detail::type_error::create(315, \"values in object must be primitive\"));\n\t\t\t\t}\n\n\t\t\t\t// assign value to reference pointed to by JSON pointer; Note that if\n\t\t\t\t// the JSON pointer is \"\" (i.e., points to the whole value), function\n\t\t\t\t// get_and_create returns a reference to result itself. An assignment\n\t\t\t\t// will then create a primitive value.\n\t\t\t\tjson_pointer(element.first).get_and_create(result) = element.second;\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief compares two JSON pointers for equality\n\n\t\t@param[in] lhs  JSON pointer to compare\n\t\t@param[in] rhs  JSON pointer to compare\n\t\t@return whether @a lhs is equal to @a rhs\n\n\t\t@complexity Linear in the length of the JSON pointer\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\t\t*/\n\t\tfriend bool operator==(json_pointer const& lhs,\n\t\t\tjson_pointer const& rhs) noexcept\n\t\t{\n\t\t\treturn lhs.reference_tokens == rhs.reference_tokens;\n\t\t}\n\n\t\t/*!\n\t\t@brief compares two JSON pointers for inequality\n\n\t\t@param[in] lhs  JSON pointer to compare\n\t\t@param[in] rhs  JSON pointer to compare\n\t\t@return whether @a lhs is not equal @a rhs\n\n\t\t@complexity Linear in the length of the JSON pointer\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\t\t*/\n\t\tfriend bool operator!=(json_pointer const& lhs,\n\t\t\tjson_pointer const& rhs) noexcept\n\t\t{\n\t\t\treturn not (lhs == rhs);\n\t\t}\n\n\t\t/// the reference tokens\n\t\tstd::vector<std::string> reference_tokens;\n\t};\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/json_ref.hpp>\n\n\n#include <initializer_list>\n#include <utility>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\ttemplate<typename BasicJsonType>\n\t\tclass json_ref\n\t\t{\n\t\tpublic:\n\t\t\tusing value_type = BasicJsonType;\n\n\t\t\tjson_ref(value_type&& value)\n\t\t\t\t: owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)\n\t\t\t{}\n\n\t\t\tjson_ref(const value_type& value)\n\t\t\t\t: value_ref(const_cast<value_type*>(&value)), is_rvalue(false)\n\t\t\t{}\n\n\t\t\tjson_ref(std::initializer_list<json_ref> init)\n\t\t\t\t: owned_value(init), value_ref(&owned_value), is_rvalue(true)\n\t\t\t{}\n\n\t\t\ttemplate <\n\t\t\t\tclass... Args,\n\t\t\t\tenable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >\n\t\t\t\tjson_ref(Args && ... args)\n\t\t\t\t: owned_value(std::forward<Args>(args)...), value_ref(&owned_value),\n\t\t\t\tis_rvalue(true) {}\n\n\t\t\t// class should be movable only\n\t\t\tjson_ref(json_ref&&) = default;\n\t\t\tjson_ref(const json_ref&) = delete;\n\t\t\tjson_ref& operator=(const json_ref&) = delete;\n\t\t\tjson_ref& operator=(json_ref&&) = delete;\n\t\t\t~json_ref() = default;\n\n\t\t\tvalue_type moved_or_copied() const\n\t\t\t{\n\t\t\t\tif (is_rvalue)\n\t\t\t\t{\n\t\t\t\t\treturn std::move(*value_ref);\n\t\t\t\t}\n\t\t\t\treturn *value_ref;\n\t\t\t}\n\n\t\t\tvalue_type const& operator*() const\n\t\t\t{\n\t\t\t\treturn *static_cast<value_type const*>(value_ref);\n\t\t\t}\n\n\t\t\tvalue_type const* operator->() const\n\t\t\t{\n\t\t\t\treturn static_cast<value_type const*>(value_ref);\n\t\t\t}\n\n\t\tprivate:\n\t\t\tmutable value_type owned_value = nullptr;\n\t\t\tvalue_type* value_ref = nullptr;\n\t\t\tconst bool is_rvalue;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n\n#include <algorithm> // reverse\n#include <array> // array\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstring> // memcpy\n#include <limits> // numeric_limits\n#include <string> // string\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n\n#include <algorithm> // copy\n#include <cstddef> // size_t\n#include <ios> // streamsize\n#include <iterator> // back_inserter\n#include <memory> // shared_ptr, make_shared\n#include <ostream> // basic_ostream\n#include <string> // basic_string\n#include <vector> // vector\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t/// abstract output adapter interface\n\t\ttemplate<typename CharType> struct output_adapter_protocol\n\t\t{\n\t\t\tvirtual void write_character(CharType c) = 0;\n\t\t\tvirtual void write_characters(const CharType* s, std::size_t length) = 0;\n\t\t\tvirtual ~output_adapter_protocol() = default;\n\t\t};\n\n\t\t/// a type to simplify interfaces\n\t\ttemplate<typename CharType>\n\t\tusing output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;\n\n\t\t/// output adapter for byte vectors\n\t\ttemplate<typename CharType>\n\t\tclass output_vector_adapter : public output_adapter_protocol<CharType>\n\t\t{\n\t\tpublic:\n\t\t\texplicit output_vector_adapter(std::vector<CharType>& vec) noexcept\n\t\t\t\t: v(vec)\n\t\t\t{}\n\n\t\t\tvoid write_character(CharType c) override\n\t\t\t{\n\t\t\t\tv.push_back(c);\n\t\t\t}\n\n\t\t\tvoid write_characters(const CharType* s, std::size_t length) override\n\t\t\t{\n\t\t\t\tstd::copy(s, s + length, std::back_inserter(v));\n\t\t\t}\n\n\t\tprivate:\n\t\t\tstd::vector<CharType>& v;\n\t\t};\n\n\t\t/// output adapter for output streams\n\t\ttemplate<typename CharType>\n\t\tclass output_stream_adapter : public output_adapter_protocol<CharType>\n\t\t{\n\t\tpublic:\n\t\t\texplicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept\n\t\t\t\t: stream(s)\n\t\t\t{}\n\n\t\t\tvoid write_character(CharType c) override\n\t\t\t{\n\t\t\t\tstream.put(c);\n\t\t\t}\n\n\t\t\tvoid write_characters(const CharType* s, std::size_t length) override\n\t\t\t{\n\t\t\t\tstream.write(s, static_cast<std::streamsize>(length));\n\t\t\t}\n\n\t\tprivate:\n\t\t\tstd::basic_ostream<CharType>& stream;\n\t\t};\n\n\t\t/// output adapter for basic_string\n\t\ttemplate<typename CharType, typename StringType = std::basic_string<CharType>>\n\t\tclass output_string_adapter : public output_adapter_protocol<CharType>\n\t\t{\n\t\tpublic:\n\t\t\texplicit output_string_adapter(StringType& s) noexcept\n\t\t\t\t: str(s)\n\t\t\t{}\n\n\t\t\tvoid write_character(CharType c) override\n\t\t\t{\n\t\t\t\tstr.push_back(c);\n\t\t\t}\n\n\t\t\tvoid write_characters(const CharType* s, std::size_t length) override\n\t\t\t{\n\t\t\t\tstr.append(s, length);\n\t\t\t}\n\n\t\tprivate:\n\t\t\tStringType& str;\n\t\t};\n\n\t\ttemplate<typename CharType, typename StringType = std::basic_string<CharType>>\n\t\tclass output_adapter\n\t\t{\n\t\tpublic:\n\t\t\toutput_adapter(std::vector<CharType>& vec)\n\t\t\t\t: oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}\n\n\t\t\toutput_adapter(std::basic_ostream<CharType>& s)\n\t\t\t\t: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}\n\n\t\t\toutput_adapter(StringType& s)\n\t\t\t\t: oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}\n\n\t\t\toperator output_adapter_t<CharType>()\n\t\t\t{\n\t\t\t\treturn oa;\n\t\t\t}\n\n\t\tprivate:\n\t\t\toutput_adapter_t<CharType> oa = nullptr;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t///////////////////\n\t\t// binary writer //\n\t\t///////////////////\n\n\t\t/*!\n\t\t@brief serialization to CBOR and MessagePack values\n\t\t*/\n\t\ttemplate<typename BasicJsonType, typename CharType>\n\t\tclass binary_writer\n\t\t{\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\n\t\tpublic:\n\t\t\t/*!\n\t\t\t@brief create a binary writer\n\n\t\t\t@param[in] adapter  output adapter to write to\n\t\t\t*/\n\t\t\texplicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)\n\t\t\t{\n\t\t\t\tassert(oa);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] j  JSON value to serialize\n\t\t\t@pre       j.type() == value_t::object\n\t\t\t*/\n\t\t\tvoid write_bson(const BasicJsonType& j)\n\t\t\t{\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\twrite_bson_object(*j.m_value.object);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(type_error::create(317, \"to serialize to BSON, top-level type must be object, but is \" + std::string(j.type_name())));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] j  JSON value to serialize\n\t\t\t*/\n\t\t\tvoid write_cbor(const BasicJsonType& j)\n\t\t\t{\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::null:\n\t\t\t\t{\n\t\t\t\t\toa->write_character(to_char_type(0xF6));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t{\n\t\t\t\t\toa->write_character(j.m_value.boolean\n\t\t\t\t\t\t? to_char_type(0xF5)\n\t\t\t\t\t\t: to_char_type(0xF4));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t{\n\t\t\t\t\tif (j.m_value.number_integer >= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// CBOR does not differentiate between positive signed\n\t\t\t\t\t\t// integers and unsigned integers. Therefore, we used the\n\t\t\t\t\t\t// code from the value_t::number_unsigned case here.\n\t\t\t\t\t\tif (j.m_value.number_integer <= 0x17)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x18));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x19));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x1A));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x1B));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// The conversions below encode the sign in the first\n\t\t\t\t\t\t// byte, and the value is converted to a positive number.\n\t\t\t\t\t\tconst auto positive_number = -1 - j.m_value.number_integer;\n\t\t\t\t\t\tif (j.m_value.number_integer >= -24)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0x20 + positive_number));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x38));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(positive_number));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x39));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(positive_number));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x3A));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(positive_number));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toa->write_character(to_char_type(0x3B));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(positive_number));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t{\n\t\t\t\t\tif (j.m_value.number_unsigned <= 0x17)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x18));\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x19));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x1A));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x1B));\n\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t{\n\t\t\t\t\toa->write_character(get_cbor_float_prefix(j.m_value.number_float));\n\t\t\t\t\twrite_number(j.m_value.number_float);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t{\n\t\t\t\t\t// step 1: write control byte and the string length\n\t\t\t\t\tconst auto N = j.m_value.string->size();\n\t\t\t\t\tif (N <= 0x17)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0x60 + N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x78));\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x79));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x7A));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint64_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x7B));\n\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\t// LCOV_EXCL_STOP\n\n\t\t\t\t\t// step 2: write the string\n\t\t\t\t\toa->write_characters(\n\t\t\t\t\t\treinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n\t\t\t\t\t\tj.m_value.string->size());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\t// step 1: write control byte and the array size\n\t\t\t\t\tconst auto N = j.m_value.array->size();\n\t\t\t\t\tif (N <= 0x17)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0x80 + N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x98));\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x99));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x9A));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint64_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0x9B));\n\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\t// LCOV_EXCL_STOP\n\n\t\t\t\t\t// step 2: write each element\n\t\t\t\t\tfor (const auto& el : *j.m_value.array)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_cbor(el);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// step 1: write control byte and the object size\n\t\t\t\t\tconst auto N = j.m_value.object->size();\n\t\t\t\t\tif (N <= 0x17)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0xA0 + N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0xB8));\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0xB9));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0xBA));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint64_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(0xBB));\n\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\t// LCOV_EXCL_STOP\n\n\t\t\t\t\t// step 2: write each element\n\t\t\t\t\tfor (const auto& el : *j.m_value.object)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_cbor(el.first);\n\t\t\t\t\t\twrite_cbor(el.second);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] j  JSON value to serialize\n\t\t\t*/\n\t\t\tvoid write_msgpack(const BasicJsonType& j)\n\t\t\t{\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::null: // nil\n\t\t\t\t{\n\t\t\t\t\toa->write_character(to_char_type(0xC0));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::boolean: // true and false\n\t\t\t\t{\n\t\t\t\t\toa->write_character(j.m_value.boolean\n\t\t\t\t\t\t? to_char_type(0xC3)\n\t\t\t\t\t\t: to_char_type(0xC2));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t{\n\t\t\t\t\tif (j.m_value.number_integer >= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// MessagePack does not differentiate between positive\n\t\t\t\t\t\t// signed integers and unsigned integers. Therefore, we used\n\t\t\t\t\t\t// the code from the value_t::number_unsigned case here.\n\t\t\t\t\t\tif (j.m_value.number_unsigned < 128)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// positive fixnum\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// uint 8\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xCC));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// uint 16\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xCD));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// uint 32\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xCE));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// uint 64\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xCF));\n\t\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (j.m_value.number_integer >= -32)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// negative fixnum\n\t\t\t\t\t\t\twrite_number(static_cast<std::int8_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and\n\t\t\t\t\t\t\tj.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// int 8\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xD0));\n\t\t\t\t\t\t\twrite_number(static_cast<std::int8_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and\n\t\t\t\t\t\t\tj.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// int 16\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xD1));\n\t\t\t\t\t\t\twrite_number(static_cast<std::int16_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and\n\t\t\t\t\t\t\tj.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// int 32\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xD2));\n\t\t\t\t\t\t\twrite_number(static_cast<std::int32_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and\n\t\t\t\t\t\t\tj.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// int 64\n\t\t\t\t\t\t\toa->write_character(to_char_type(0xD3));\n\t\t\t\t\t\t\twrite_number(static_cast<std::int64_t>(j.m_value.number_integer));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t{\n\t\t\t\t\tif (j.m_value.number_unsigned < 128)\n\t\t\t\t\t{\n\t\t\t\t\t\t// positive fixnum\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// uint 8\n\t\t\t\t\t\toa->write_character(to_char_type(0xCC));\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// uint 16\n\t\t\t\t\t\toa->write_character(to_char_type(0xCD));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// uint 32\n\t\t\t\t\t\toa->write_character(to_char_type(0xCE));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n\t\t\t\t\t}\n\t\t\t\t\telse if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// uint 64\n\t\t\t\t\t\toa->write_character(to_char_type(0xCF));\n\t\t\t\t\t\twrite_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t{\n\t\t\t\t\toa->write_character(get_msgpack_float_prefix(j.m_value.number_float));\n\t\t\t\t\twrite_number(j.m_value.number_float);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t{\n\t\t\t\t\t// step 1: write control byte and the string length\n\t\t\t\t\tconst auto N = j.m_value.string->size();\n\t\t\t\t\tif (N <= 31)\n\t\t\t\t\t{\n\t\t\t\t\t\t// fixstr\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0xA0 | N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// str 8\n\t\t\t\t\t\toa->write_character(to_char_type(0xD9));\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// str 16\n\t\t\t\t\t\toa->write_character(to_char_type(0xDA));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// str 32\n\t\t\t\t\t\toa->write_character(to_char_type(0xDB));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(N));\n\t\t\t\t\t}\n\n\t\t\t\t\t// step 2: write the string\n\t\t\t\t\toa->write_characters(\n\t\t\t\t\t\treinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n\t\t\t\t\t\tj.m_value.string->size());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\t// step 1: write control byte and the array size\n\t\t\t\t\tconst auto N = j.m_value.array->size();\n\t\t\t\t\tif (N <= 15)\n\t\t\t\t\t{\n\t\t\t\t\t\t// fixarray\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0x90 | N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// array 16\n\t\t\t\t\t\toa->write_character(to_char_type(0xDC));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// array 32\n\t\t\t\t\t\toa->write_character(to_char_type(0xDD));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(N));\n\t\t\t\t\t}\n\n\t\t\t\t\t// step 2: write each element\n\t\t\t\t\tfor (const auto& el : *j.m_value.array)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_msgpack(el);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// step 1: write control byte and the object size\n\t\t\t\t\tconst auto N = j.m_value.object->size();\n\t\t\t\t\tif (N <= 15)\n\t\t\t\t\t{\n\t\t\t\t\t\t// fixmap\n\t\t\t\t\t\twrite_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// map 16\n\t\t\t\t\t\toa->write_character(to_char_type(0xDE));\n\t\t\t\t\t\twrite_number(static_cast<std::uint16_t>(N));\n\t\t\t\t\t}\n\t\t\t\t\telse if (N <= (std::numeric_limits<std::uint32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\t// map 32\n\t\t\t\t\t\toa->write_character(to_char_type(0xDF));\n\t\t\t\t\t\twrite_number(static_cast<std::uint32_t>(N));\n\t\t\t\t\t}\n\n\t\t\t\t\t// step 2: write each element\n\t\t\t\t\tfor (const auto& el : *j.m_value.object)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_msgpack(el.first);\n\t\t\t\t\t\twrite_msgpack(el.second);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] j  JSON value to serialize\n\t\t\t@param[in] use_count   whether to use '#' prefixes (optimized format)\n\t\t\t@param[in] use_type    whether to use '$' prefixes (optimized format)\n\t\t\t@param[in] add_prefix  whether prefixes need to be used for this value\n\t\t\t*/\n\t\t\tvoid write_ubjson(const BasicJsonType& j, const bool use_count,\n\t\t\t\tconst bool use_type, const bool add_prefix = true)\n\t\t\t{\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::null:\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('Z'));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(j.m_value.boolean\n\t\t\t\t\t\t\t? to_char_type('T')\n\t\t\t\t\t\t\t: to_char_type('F'));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t{\n\t\t\t\t\twrite_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t{\n\t\t\t\t\twrite_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t{\n\t\t\t\t\twrite_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('S'));\n\t\t\t\t\t}\n\t\t\t\t\twrite_number_with_ubjson_prefix(j.m_value.string->size(), true);\n\t\t\t\t\toa->write_characters(\n\t\t\t\t\t\treinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n\t\t\t\t\t\tj.m_value.string->size());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('['));\n\t\t\t\t\t}\n\n\t\t\t\t\tbool prefix_required = true;\n\t\t\t\t\tif (use_type and not j.m_value.array->empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tassert(use_count);\n\t\t\t\t\t\tconst CharType first_prefix = ubjson_prefix(j.front());\n\t\t\t\t\t\tconst bool same_prefix = std::all_of(j.begin() + 1, j.end(),\n\t\t\t\t\t\t\t[this, first_prefix](const BasicJsonType & v)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn ubjson_prefix(v) == first_prefix;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (same_prefix)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprefix_required = false;\n\t\t\t\t\t\t\toa->write_character(to_char_type('$'));\n\t\t\t\t\t\t\toa->write_character(first_prefix);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (use_count)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('#'));\n\t\t\t\t\t\twrite_number_with_ubjson_prefix(j.m_value.array->size(), true);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const auto& el : *j.m_value.array)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_ubjson(el, use_count, use_type, prefix_required);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (not use_count)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type(']'));\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('{'));\n\t\t\t\t\t}\n\n\t\t\t\t\tbool prefix_required = true;\n\t\t\t\t\tif (use_type and not j.m_value.object->empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tassert(use_count);\n\t\t\t\t\t\tconst CharType first_prefix = ubjson_prefix(j.front());\n\t\t\t\t\t\tconst bool same_prefix = std::all_of(j.begin(), j.end(),\n\t\t\t\t\t\t\t[this, first_prefix](const BasicJsonType & v)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn ubjson_prefix(v) == first_prefix;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (same_prefix)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprefix_required = false;\n\t\t\t\t\t\t\toa->write_character(to_char_type('$'));\n\t\t\t\t\t\t\toa->write_character(first_prefix);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (use_count)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('#'));\n\t\t\t\t\t\twrite_number_with_ubjson_prefix(j.m_value.object->size(), true);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const auto& el : *j.m_value.object)\n\t\t\t\t\t{\n\t\t\t\t\t\twrite_number_with_ubjson_prefix(el.first.size(), true);\n\t\t\t\t\t\toa->write_characters(\n\t\t\t\t\t\t\treinterpret_cast<const CharType*>(el.first.c_str()),\n\t\t\t\t\t\t\tel.first.size());\n\t\t\t\t\t\twrite_ubjson(el.second, use_count, use_type, prefix_required);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (not use_count)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('}'));\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\tprivate:\n\t\t\t//////////\n\t\t\t// BSON //\n\t\t\t//////////\n\n\t\t\t/*!\n\t\t\t@return The size of a BSON document entry header, including the id marker\n\t\t\t\t\tand the entry name size (and its null-terminator).\n\t\t\t*/\n\t\t\tstatic std::size_t calc_bson_entry_header_size(const string_t& name)\n\t\t\t{\n\t\t\t\tconst auto it = name.find(static_cast<typename string_t::value_type>(0));\n\t\t\t\tif (JSON_UNLIKELY(it != BasicJsonType::string_t::npos))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(409,\n\t\t\t\t\t\t\"BSON key cannot contain code point U+0000 (at byte \" + std::to_string(it) + \")\"));\n\t\t\t\t}\n\n\t\t\t\treturn /*id*/ 1ul + name.size() + /*zero-terminator*/1u;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes the given @a element_type and @a name to the output adapter\n\t\t\t*/\n\t\t\tvoid write_bson_entry_header(const string_t& name,\n\t\t\t\tconst std::uint8_t element_type)\n\t\t\t{\n\t\t\t\toa->write_character(to_char_type(element_type)); // boolean\n\t\t\t\toa->write_characters(\n\t\t\t\t\treinterpret_cast<const CharType*>(name.c_str()),\n\t\t\t\t\tname.size() + 1u);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and boolean value @a value\n\t\t\t*/\n\t\t\tvoid write_bson_boolean(const string_t& name,\n\t\t\t\tconst bool value)\n\t\t\t{\n\t\t\t\twrite_bson_entry_header(name, 0x08);\n\t\t\t\toa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and double value @a value\n\t\t\t*/\n\t\t\tvoid write_bson_double(const string_t& name,\n\t\t\t\tconst double value)\n\t\t\t{\n\t\t\t\twrite_bson_entry_header(name, 0x01);\n\t\t\t\twrite_number<double, true>(value);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return The size of the BSON-encoded string in @a value\n\t\t\t*/\n\t\t\tstatic std::size_t calc_bson_string_size(const string_t& value)\n\t\t\t{\n\t\t\t\treturn sizeof(std::int32_t) + value.size() + 1ul;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and string value @a value\n\t\t\t*/\n\t\t\tvoid write_bson_string(const string_t& name,\n\t\t\t\tconst string_t& value)\n\t\t\t{\n\t\t\t\twrite_bson_entry_header(name, 0x02);\n\n\t\t\t\twrite_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));\n\t\t\t\toa->write_characters(\n\t\t\t\t\treinterpret_cast<const CharType*>(value.c_str()),\n\t\t\t\t\tvalue.size() + 1);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and null value\n\t\t\t*/\n\t\t\tvoid write_bson_null(const string_t& name)\n\t\t\t{\n\t\t\t\twrite_bson_entry_header(name, 0x0A);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return The size of the BSON-encoded integer @a value\n\t\t\t*/\n\t\t\tstatic std::size_t calc_bson_integer_size(const std::int64_t value)\n\t\t\t{\n\t\t\t\treturn (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()\n\t\t\t\t\t? sizeof(std::int32_t)\n\t\t\t\t\t: sizeof(std::int64_t);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and integer @a value\n\t\t\t*/\n\t\t\tvoid write_bson_integer(const string_t& name,\n\t\t\t\tconst std::int64_t value)\n\t\t\t{\n\t\t\t\tif ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())\n\t\t\t\t{\n\t\t\t\t\twrite_bson_entry_header(name, 0x10); // int32\n\t\t\t\t\twrite_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twrite_bson_entry_header(name, 0x12); // int64\n\t\t\t\t\twrite_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return The size of the BSON-encoded unsigned integer in @a j\n\t\t\t*/\n\t\t\tstatic constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept\n\t\t\t{\n\t\t\t\treturn (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n\t\t\t\t\t? sizeof(std::int32_t)\n\t\t\t\t\t: sizeof(std::int64_t);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and unsigned @a value\n\t\t\t*/\n\t\t\tvoid write_bson_unsigned(const string_t& name,\n\t\t\t\tconst std::uint64_t value)\n\t\t\t{\n\t\t\t\tif (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\twrite_bson_entry_header(name, 0x10 /* int32 */);\n\t\t\t\t\twrite_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n\t\t\t\t}\n\t\t\t\telse if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\twrite_bson_entry_header(name, 0x12 /* int64 */);\n\t\t\t\t\twrite_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(value) + \" cannot be represented by BSON as it does not fit int64\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and object @a value\n\t\t\t*/\n\t\t\tvoid write_bson_object_entry(const string_t& name,\n\t\t\t\tconst typename BasicJsonType::object_t& value)\n\t\t\t{\n\t\t\t\twrite_bson_entry_header(name, 0x03); // object\n\t\t\t\twrite_bson_object(value);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@return The size of the BSON-encoded array @a value\n\t\t\t*/\n\t\t\tstatic std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)\n\t\t\t{\n\t\t\t\tstd::size_t embedded_document_size = 0ul;\n\t\t\t\tstd::size_t array_index = 0ul;\n\n\t\t\t\tfor (const auto& el : value)\n\t\t\t\t{\n\t\t\t\t\tembedded_document_size += calc_bson_element_size(std::to_string(array_index++), el);\n\t\t\t\t}\n\n\t\t\t\treturn sizeof(std::int32_t) + embedded_document_size + 1ul;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Writes a BSON element with key @a name and array @a value\n\t\t\t*/\n\t\t\tvoid write_bson_array(const string_t& name,\n\t\t\t\tconst typename BasicJsonType::array_t& value)\n\t\t\t{\n\t\t\t\twrite_bson_entry_header(name, 0x04); // array\n\t\t\t\twrite_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));\n\n\t\t\t\tstd::size_t array_index = 0ul;\n\n\t\t\t\tfor (const auto& el : value)\n\t\t\t\t{\n\t\t\t\t\twrite_bson_element(std::to_string(array_index++), el);\n\t\t\t\t}\n\n\t\t\t\toa->write_character(to_char_type(0x00));\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Calculates the size necessary to serialize the JSON value @a j with its @a name\n\t\t\t@return The calculated size for the BSON document entry for @a j with the given @a name.\n\t\t\t*/\n\t\t\tstatic std::size_t calc_bson_element_size(const string_t& name,\n\t\t\t\tconst BasicJsonType& j)\n\t\t\t{\n\t\t\t\tconst auto header_size = calc_bson_entry_header_size(name);\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn header_size + calc_bson_object_size(*j.m_value.object);\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn header_size + calc_bson_array_size(*j.m_value.array);\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t\treturn header_size + 1ul;\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t\treturn header_size + 8ul;\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t\treturn header_size + calc_bson_integer_size(j.m_value.number_integer);\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t\treturn header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t\treturn header_size + calc_bson_string_size(*j.m_value.string);\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t\treturn header_size + 0ul;\n\n\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\tdefault:\n\t\t\t\t\tassert(false);\n\t\t\t\t\treturn 0ul;\n\t\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Serializes the JSON value @a j to BSON and associates it with the\n\t\t\t\t   key @a name.\n\t\t\t@param name The name to associate with the JSON entity @a j within the\n\t\t\t\t\t\tcurrent BSON document\n\t\t\t@return The size of the BSON entry\n\t\t\t*/\n\t\t\tvoid write_bson_element(const string_t& name,\n\t\t\t\tconst BasicJsonType& j)\n\t\t\t{\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn write_bson_object_entry(name, *j.m_value.object);\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn write_bson_array(name, *j.m_value.array);\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t\treturn write_bson_boolean(name, j.m_value.boolean);\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t\treturn write_bson_double(name, j.m_value.number_float);\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t\treturn write_bson_integer(name, j.m_value.number_integer);\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t\treturn write_bson_unsigned(name, j.m_value.number_unsigned);\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t\treturn write_bson_string(name, *j.m_value.string);\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t\treturn write_bson_null(name);\n\n\t\t\t\t\t// LCOV_EXCL_START\n\t\t\t\tdefault:\n\t\t\t\t\tassert(false);\n\t\t\t\t\treturn;\n\t\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief Calculates the size of the BSON serialization of the given\n\t\t\t\t   JSON-object @a j.\n\t\t\t@param[in] j  JSON value to serialize\n\t\t\t@pre       j.type() == value_t::object\n\t\t\t*/\n\t\t\tstatic std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)\n\t\t\t{\n\t\t\t\tstd::size_t document_size = std::accumulate(value.begin(), value.end(), 0ul,\n\t\t\t\t\t[](size_t result, const typename BasicJsonType::object_t::value_type & el)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn result += calc_bson_element_size(el.first, el.second);\n\t\t\t\t\t});\n\n\t\t\t\treturn sizeof(std::int32_t) + document_size + 1ul;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@param[in] j  JSON value to serialize\n\t\t\t@pre       j.type() == value_t::object\n\t\t\t*/\n\t\t\tvoid write_bson_object(const typename BasicJsonType::object_t& value)\n\t\t\t{\n\t\t\t\twrite_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));\n\n\t\t\t\tfor (const auto& el : value)\n\t\t\t\t{\n\t\t\t\t\twrite_bson_element(el.first, el.second);\n\t\t\t\t}\n\n\t\t\t\toa->write_character(to_char_type(0x00));\n\t\t\t}\n\n\t\t\t//////////\n\t\t\t// CBOR //\n\t\t\t//////////\n\n\t\t\tstatic constexpr CharType get_cbor_float_prefix(float /*unused*/)\n\t\t\t{\n\t\t\t\treturn to_char_type(0xFA);  // Single-Precision Float\n\t\t\t}\n\n\t\t\tstatic constexpr CharType get_cbor_float_prefix(double /*unused*/)\n\t\t\t{\n\t\t\t\treturn to_char_type(0xFB);  // Double-Precision Float\n\t\t\t}\n\n\t\t\t/////////////\n\t\t\t// MsgPack //\n\t\t\t/////////////\n\n\t\t\tstatic constexpr CharType get_msgpack_float_prefix(float /*unused*/)\n\t\t\t{\n\t\t\t\treturn to_char_type(0xCA);  // float 32\n\t\t\t}\n\n\t\t\tstatic constexpr CharType get_msgpack_float_prefix(double /*unused*/)\n\t\t\t{\n\t\t\t\treturn to_char_type(0xCB);  // float 64\n\t\t\t}\n\n\t\t\t////////////\n\t\t\t// UBJSON //\n\t\t\t////////////\n\n\t\t\t// UBJSON: write number (floating point)\n\t\t\ttemplate<typename NumberType, typename std::enable_if<\n\t\t\t\tstd::is_floating_point<NumberType>::value, int>::type = 0>\n\t\t\t\tvoid write_number_with_ubjson_prefix(const NumberType n,\n\t\t\t\t\tconst bool add_prefix)\n\t\t\t{\n\t\t\t\tif (add_prefix)\n\t\t\t\t{\n\t\t\t\t\toa->write_character(get_ubjson_float_prefix(n));\n\t\t\t\t}\n\t\t\t\twrite_number(n);\n\t\t\t}\n\n\t\t\t// UBJSON: write number (unsigned integer)\n\t\t\ttemplate<typename NumberType, typename std::enable_if<\n\t\t\t\tstd::is_unsigned<NumberType>::value, int>::type = 0>\n\t\t\t\tvoid write_number_with_ubjson_prefix(const NumberType n,\n\t\t\t\t\tconst bool add_prefix)\n\t\t\t{\n\t\t\t\tif (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('i'));  // int8\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::uint8_t>(n));\n\t\t\t\t}\n\t\t\t\telse if (n <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('U'));  // uint8\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::uint8_t>(n));\n\t\t\t\t}\n\t\t\t\telse if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('I'));  // int16\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int16_t>(n));\n\t\t\t\t}\n\t\t\t\telse if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('l'));  // int32\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int32_t>(n));\n\t\t\t\t}\n\t\t\t\telse if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('L'));  // int64\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int64_t>(n));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(n) + \" cannot be represented by UBJSON as it does not fit int64\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// UBJSON: write number (signed integer)\n\t\t\ttemplate<typename NumberType, typename std::enable_if<\n\t\t\t\tstd::is_signed<NumberType>::value and\n\t\t\t\tnot std::is_floating_point<NumberType>::value, int>::type = 0>\n\t\t\t\tvoid write_number_with_ubjson_prefix(const NumberType n,\n\t\t\t\t\tconst bool add_prefix)\n\t\t\t{\n\t\t\t\tif ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)())\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('i'));  // int8\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int8_t>(n));\n\t\t\t\t}\n\t\t\t\telse if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('U'));  // uint8\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::uint8_t>(n));\n\t\t\t\t}\n\t\t\t\telse if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)())\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('I'));  // int16\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int16_t>(n));\n\t\t\t\t}\n\t\t\t\telse if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)())\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('l'));  // int32\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int32_t>(n));\n\t\t\t\t}\n\t\t\t\telse if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)())\n\t\t\t\t{\n\t\t\t\t\tif (add_prefix)\n\t\t\t\t\t{\n\t\t\t\t\t\toa->write_character(to_char_type('L'));  // int64\n\t\t\t\t\t}\n\t\t\t\t\twrite_number(static_cast<std::int64_t>(n));\n\t\t\t\t}\n\t\t\t\t// LCOV_EXCL_START\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(n) + \" cannot be represented by UBJSON as it does not fit int64\"));\n\t\t\t\t}\n\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief determine the type prefix of container values\n\n\t\t\t@note This function does not need to be 100% accurate when it comes to\n\t\t\t\t  integer limits. In case a number exceeds the limits of int64_t,\n\t\t\t\t  this will be detected by a later call to function\n\t\t\t\t  write_number_with_ubjson_prefix. Therefore, we return 'L' for any\n\t\t\t\t  value that does not fit the previous limits.\n\t\t\t*/\n\t\t\tCharType ubjson_prefix(const BasicJsonType& j) const noexcept\n\t\t\t{\n\t\t\t\tswitch (j.type())\n\t\t\t\t{\n\t\t\t\tcase value_t::null:\n\t\t\t\t\treturn 'Z';\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t\treturn j.m_value.boolean ? 'T' : 'F';\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t{\n\t\t\t\t\tif ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'i';\n\t\t\t\t\t}\n\t\t\t\t\tif ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'U';\n\t\t\t\t\t}\n\t\t\t\t\tif ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'I';\n\t\t\t\t\t}\n\t\t\t\t\tif ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'l';\n\t\t\t\t\t}\n\t\t\t\t\t// no check and assume int64_t (see note above)\n\t\t\t\t\treturn 'L';\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t{\n\t\t\t\t\tif (j.m_value.number_unsigned <= (std::numeric_limits<std::int8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'i';\n\t\t\t\t\t}\n\t\t\t\t\tif (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'U';\n\t\t\t\t\t}\n\t\t\t\t\tif (j.m_value.number_unsigned <= (std::numeric_limits<std::int16_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'I';\n\t\t\t\t\t}\n\t\t\t\t\tif (j.m_value.number_unsigned <= (std::numeric_limits<std::int32_t>::max)())\n\t\t\t\t\t{\n\t\t\t\t\t\treturn 'l';\n\t\t\t\t\t}\n\t\t\t\t\t// no check and assume int64_t (see note above)\n\t\t\t\t\treturn 'L';\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t\treturn get_ubjson_float_prefix(j.m_value.number_float);\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t\treturn 'S';\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn '[';\n\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn '{';\n\n\t\t\t\tdefault:  // discarded values\n\t\t\t\t\treturn 'N';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic constexpr CharType get_ubjson_float_prefix(float /*unused*/)\n\t\t\t{\n\t\t\t\treturn 'd';  // float 32\n\t\t\t}\n\n\t\t\tstatic constexpr CharType get_ubjson_float_prefix(double /*unused*/)\n\t\t\t{\n\t\t\t\treturn 'D';  // float 64\n\t\t\t}\n\n\t\t\t///////////////////////\n\t\t\t// Utility functions //\n\t\t\t///////////////////////\n\n\t\t\t/*\n\t\t\t@brief write a number to output input\n\t\t\t@param[in] n number of type @a NumberType\n\t\t\t@tparam NumberType the type of the number\n\t\t\t@tparam OutputIsLittleEndian Set to true if output data is\n\t\t\t\t\t\t\t\t\t\t required to be little endian\n\n\t\t\t@note This function needs to respect the system's endianess, because bytes\n\t\t\t\t  in CBOR, MessagePack, and UBJSON are stored in network order (big\n\t\t\t\t  endian) and therefore need reordering on little endian systems.\n\t\t\t*/\n\t\t\ttemplate<typename NumberType, bool OutputIsLittleEndian = false>\n\t\t\tvoid write_number(const NumberType n)\n\t\t\t{\n\t\t\t\t// step 1: write number to array of length NumberType\n\t\t\t\tstd::array<CharType, sizeof(NumberType)> vec;\n\t\t\t\tstd::memcpy(vec.data(), &n, sizeof(NumberType));\n\n\t\t\t\t// step 2: write array to output (with possible reordering)\n\t\t\t\tif (is_little_endian != OutputIsLittleEndian)\n\t\t\t\t{\n\t\t\t\t\t// reverse byte order prior to conversion if necessary\n\t\t\t\t\tstd::reverse(vec.begin(), vec.end());\n\t\t\t\t}\n\n\t\t\t\toa->write_characters(vec.data(), sizeof(NumberType));\n\t\t\t}\n\n\t\tpublic:\n\t\t\t// The following to_char_type functions are implement the conversion\n\t\t\t// between uint8_t and CharType. In case CharType is not unsigned,\n\t\t\t// such a conversion is required to allow values greater than 128.\n\t\t\t// See <https://github.com/nlohmann/json/issues/1286> for a discussion.\n\t\t\ttemplate < typename C = CharType,\n\t\t\t\tenable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >\n\t\t\t\tstatic constexpr CharType to_char_type(std::uint8_t x) noexcept\n\t\t\t{\n\t\t\t\treturn *reinterpret_cast<char*>(&x);\n\t\t\t}\n\n\t\t\ttemplate < typename C = CharType,\n\t\t\t\tenable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >\n\t\t\t\tstatic CharType to_char_type(std::uint8_t x) noexcept\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof(std::uint8_t) == sizeof(CharType), \"size of CharType must be equal to std::uint8_t\");\n\t\t\t\tstatic_assert(std::is_pod<CharType>::value, \"CharType must be POD\");\n\t\t\t\tCharType result;\n\t\t\t\tstd::memcpy(&result, &x, sizeof(x));\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\ttemplate<typename C = CharType,\n\t\t\t\tenable_if_t<std::is_unsigned<C>::value>* = nullptr>\n\t\t\t\tstatic constexpr CharType to_char_type(std::uint8_t x) noexcept\n\t\t\t{\n\t\t\t\treturn x;\n\t\t\t}\n\n\t\t\ttemplate < typename InputCharType, typename C = CharType,\n\t\t\t\tenable_if_t <\n\t\t\t\tstd::is_signed<C>::value and\n\t\t\t\tstd::is_signed<char>::value and\n\t\t\t\tstd::is_same<char, typename std::remove_cv<InputCharType>::type>::value\n\t\t\t> * = nullptr >\n\t\t\t\tstatic constexpr CharType to_char_type(InputCharType x) noexcept\n\t\t\t{\n\t\t\t\treturn x;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// whether we can assume little endianess\n\t\t\tconst bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();\n\n\t\t\t/// the output\n\t\t\toutput_adapter_t<CharType> oa = nullptr;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/output/serializer.hpp>\n\n\n#include <algorithm> // reverse, remove, fill, find, none_of\n#include <array> // array\n#include <cassert> // assert\n#include <ciso646> // and, or\n#include <clocale> // localeconv, lconv\n#include <cmath> // labs, isfinite, isnan, signbit\n#include <cstddef> // size_t, ptrdiff_t\n#include <cstdint> // uint8_t\n#include <cstdio> // snprintf\n#include <limits> // numeric_limits\n#include <string> // string\n#include <type_traits> // is_same\n#include <utility> // move\n\n// #include <nlohmann/detail/conversions/to_chars.hpp>\n\n\n#include <array> // array\n#include <cassert> // assert\n#include <ciso646> // or, and, not\n#include <cmath>   // signbit, isfinite\n#include <cstdint> // intN_t, uintN_t\n#include <cstring> // memcpy, memmove\n#include <limits> // numeric_limits\n#include <type_traits> // conditional\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\n\t\t/*!\n\t\t@brief implements the Grisu2 algorithm for binary to decimal floating-point\n\t\tconversion.\n\n\t\tThis implementation is a slightly modified version of the reference\n\t\timplementation which may be obtained from\n\t\thttp://florian.loitsch.com/publications (bench.tar.gz).\n\n\t\tThe code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.\n\n\t\tFor a detailed description of the algorithm see:\n\n\t\t[1] Loitsch, \"Printing Floating-Point Numbers Quickly and Accurately with\n\t\t\tIntegers\", Proceedings of the ACM SIGPLAN 2010 Conference on Programming\n\t\t\tLanguage Design and Implementation, PLDI 2010\n\t\t[2] Burger, Dybvig, \"Printing Floating-Point Numbers Quickly and Accurately\",\n\t\t\tProceedings of the ACM SIGPLAN 1996 Conference on Programming Language\n\t\t\tDesign and Implementation, PLDI 1996\n\t\t*/\n\t\tnamespace dtoa_impl\n\t\t{\n\n\t\t\ttemplate <typename Target, typename Source>\n\t\t\tTarget reinterpret_bits(const Source source)\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof(Target) == sizeof(Source), \"size mismatch\");\n\n\t\t\t\tTarget target;\n\t\t\t\tstd::memcpy(&target, &source, sizeof(Source));\n\t\t\t\treturn target;\n\t\t\t}\n\n\t\t\tstruct diyfp // f * 2^e\n\t\t\t{\n\t\t\t\tstatic constexpr int kPrecision = 64; // = q\n\n\t\t\t\tstd::uint64_t f = 0;\n\t\t\t\tint e = 0;\n\n\t\t\t\tconstexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}\n\n\t\t\t\t/*!\n\t\t\t\t@brief returns x - y\n\t\t\t\t@pre x.e == y.e and x.f >= y.f\n\t\t\t\t*/\n\t\t\t\tstatic diyfp sub(const diyfp& x, const diyfp& y) noexcept\n\t\t\t\t{\n\t\t\t\t\tassert(x.e == y.e);\n\t\t\t\t\tassert(x.f >= y.f);\n\n\t\t\t\t\treturn { x.f - y.f, x.e };\n\t\t\t\t}\n\n\t\t\t\t/*!\n\t\t\t\t@brief returns x * y\n\t\t\t\t@note The result is rounded. (Only the upper q bits are returned.)\n\t\t\t\t*/\n\t\t\t\tstatic diyfp mul(const diyfp& x, const diyfp& y) noexcept\n\t\t\t\t{\n\t\t\t\t\tstatic_assert(kPrecision == 64, \"internal error\");\n\n\t\t\t\t\t// Computes:\n\t\t\t\t\t//  f = round((x.f * y.f) / 2^q)\n\t\t\t\t\t//  e = x.e + y.e + q\n\n\t\t\t\t\t// Emulate the 64-bit * 64-bit multiplication:\n\t\t\t\t\t//\n\t\t\t\t\t// p = u * v\n\t\t\t\t\t//   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)\n\t\t\t\t\t//   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )\n\t\t\t\t\t//   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )\n\t\t\t\t\t//   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )\n\t\t\t\t\t//   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)\n\t\t\t\t\t//   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )\n\t\t\t\t\t//   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )\n\t\t\t\t\t//\n\t\t\t\t\t// (Since Q might be larger than 2^32 - 1)\n\t\t\t\t\t//\n\t\t\t\t\t//   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)\n\t\t\t\t\t//\n\t\t\t\t\t// (Q_hi + H does not overflow a 64-bit int)\n\t\t\t\t\t//\n\t\t\t\t\t//   = p_lo + 2^64 p_hi\n\n\t\t\t\t\tconst std::uint64_t u_lo = x.f & 0xFFFFFFFFu;\n\t\t\t\t\tconst std::uint64_t u_hi = x.f >> 32u;\n\t\t\t\t\tconst std::uint64_t v_lo = y.f & 0xFFFFFFFFu;\n\t\t\t\t\tconst std::uint64_t v_hi = y.f >> 32u;\n\n\t\t\t\t\tconst std::uint64_t p0 = u_lo * v_lo;\n\t\t\t\t\tconst std::uint64_t p1 = u_lo * v_hi;\n\t\t\t\t\tconst std::uint64_t p2 = u_hi * v_lo;\n\t\t\t\t\tconst std::uint64_t p3 = u_hi * v_hi;\n\n\t\t\t\t\tconst std::uint64_t p0_hi = p0 >> 32u;\n\t\t\t\t\tconst std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;\n\t\t\t\t\tconst std::uint64_t p1_hi = p1 >> 32u;\n\t\t\t\t\tconst std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;\n\t\t\t\t\tconst std::uint64_t p2_hi = p2 >> 32u;\n\n\t\t\t\t\tstd::uint64_t Q = p0_hi + p1_lo + p2_lo;\n\n\t\t\t\t\t// The full product might now be computed as\n\t\t\t\t\t//\n\t\t\t\t\t// p_hi = p3 + p2_hi + p1_hi + (Q >> 32)\n\t\t\t\t\t// p_lo = p0_lo + (Q << 32)\n\t\t\t\t\t//\n\t\t\t\t\t// But in this particular case here, the full p_lo is not required.\n\t\t\t\t\t// Effectively we only need to add the highest bit in p_lo to p_hi (and\n\t\t\t\t\t// Q_hi + 1 does not overflow).\n\n\t\t\t\t\tQ += std::uint64_t{ 1 } << (64u - 32u - 1u); // round, ties up\n\n\t\t\t\t\tconst std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);\n\n\t\t\t\t\treturn { h, x.e + y.e + 64 };\n\t\t\t\t}\n\n\t\t\t\t/*!\n\t\t\t\t@brief normalize x such that the significand is >= 2^(q-1)\n\t\t\t\t@pre x.f != 0\n\t\t\t\t*/\n\t\t\t\tstatic diyfp normalize(diyfp x) noexcept\n\t\t\t\t{\n\t\t\t\t\tassert(x.f != 0);\n\n\t\t\t\t\twhile ((x.f >> 63u) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tx.f <<= 1u;\n\t\t\t\t\t\tx.e--;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn x;\n\t\t\t\t}\n\n\t\t\t\t/*!\n\t\t\t\t@brief normalize x such that the result has the exponent E\n\t\t\t\t@pre e >= x.e and the upper e - x.e bits of x.f must be zero.\n\t\t\t\t*/\n\t\t\t\tstatic diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept\n\t\t\t\t{\n\t\t\t\t\tconst int delta = x.e - target_exponent;\n\n\t\t\t\t\tassert(delta >= 0);\n\t\t\t\t\tassert(((x.f << delta) >> delta) == x.f);\n\n\t\t\t\t\treturn { x.f << delta, target_exponent };\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstruct boundaries\n\t\t\t{\n\t\t\t\tdiyfp w;\n\t\t\t\tdiyfp minus;\n\t\t\t\tdiyfp plus;\n\t\t\t};\n\n\t\t\t/*!\n\t\t\tCompute the (normalized) diyfp representing the input number 'value' and its\n\t\t\tboundaries.\n\n\t\t\t@pre value must be finite and positive\n\t\t\t*/\n\t\t\ttemplate <typename FloatType>\n\t\t\tboundaries compute_boundaries(FloatType value)\n\t\t\t{\n\t\t\t\tassert(std::isfinite(value));\n\t\t\t\tassert(value > 0);\n\n\t\t\t\t// Convert the IEEE representation into a diyfp.\n\t\t\t\t//\n\t\t\t\t// If v is denormal:\n\t\t\t\t//      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))\n\t\t\t\t// If v is normalized:\n\t\t\t\t//      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))\n\n\t\t\t\tstatic_assert(std::numeric_limits<FloatType>::is_iec559,\n\t\t\t\t\t\"internal error: dtoa_short requires an IEEE-754 floating-point implementation\");\n\n\t\t\t\tconstexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)\n\t\t\t\tconstexpr int      kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);\n\t\t\t\tconstexpr int      kMinExp = 1 - kBias;\n\t\t\t\tconstexpr std::uint64_t kHiddenBit = std::uint64_t{ 1 } << (kPrecision - 1); // = 2^(p-1)\n\n\t\t\t\tusing bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;\n\n\t\t\t\tconst std::uint64_t bits = reinterpret_bits<bits_type>(value);\n\t\t\t\tconst std::uint64_t E = bits >> (kPrecision - 1);\n\t\t\t\tconst std::uint64_t F = bits & (kHiddenBit - 1);\n\n\t\t\t\tconst bool is_denormal = E == 0;\n\t\t\t\tconst diyfp v = is_denormal\n\t\t\t\t\t? diyfp(F, kMinExp)\n\t\t\t\t\t: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);\n\n\t\t\t\t// Compute the boundaries m- and m+ of the floating-point value\n\t\t\t\t// v = f * 2^e.\n\t\t\t\t//\n\t\t\t\t// Determine v- and v+, the floating-point predecessor and successor if v,\n\t\t\t\t// respectively.\n\t\t\t\t//\n\t\t\t\t//      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)\n\t\t\t\t//         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)\n\t\t\t\t//\n\t\t\t\t//      v+ = v + 2^e\n\t\t\t\t//\n\t\t\t\t// Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_\n\t\t\t\t// between m- and m+ round to v, regardless of how the input rounding\n\t\t\t\t// algorithm breaks ties.\n\t\t\t\t//\n\t\t\t\t//      ---+-------------+-------------+-------------+-------------+---  (A)\n\t\t\t\t//         v-            m-            v             m+            v+\n\t\t\t\t//\n\t\t\t\t//      -----------------+------+------+-------------+-------------+---  (B)\n\t\t\t\t//                       v-     m-     v             m+            v+\n\n\t\t\t\tconst bool lower_boundary_is_closer = F == 0 and E > 1;\n\t\t\t\tconst diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);\n\t\t\t\tconst diyfp m_minus = lower_boundary_is_closer\n\t\t\t\t\t? diyfp(4 * v.f - 1, v.e - 2)  // (B)\n\t\t\t\t\t: diyfp(2 * v.f - 1, v.e - 1); // (A)\n\n// Determine the normalized w+ = m+.\n\t\t\t\tconst diyfp w_plus = diyfp::normalize(m_plus);\n\n\t\t\t\t// Determine w- = m- such that e_(w-) = e_(w+).\n\t\t\t\tconst diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);\n\n\t\t\t\treturn { diyfp::normalize(v), w_minus, w_plus };\n\t\t\t}\n\n\t\t\t// Given normalized diyfp w, Grisu needs to find a (normalized) cached\n\t\t\t// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies\n\t\t\t// within a certain range [alpha, gamma] (Definition 3.2 from [1])\n\t\t\t//\n\t\t\t//      alpha <= e = e_c + e_w + q <= gamma\n\t\t\t//\n\t\t\t// or\n\t\t\t//\n\t\t\t//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q\n\t\t\t//                          <= f_c * f_w * 2^gamma\n\t\t\t//\n\t\t\t// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies\n\t\t\t//\n\t\t\t//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma\n\t\t\t//\n\t\t\t// or\n\t\t\t//\n\t\t\t//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)\n\t\t\t//\n\t\t\t// The choice of (alpha,gamma) determines the size of the table and the form of\n\t\t\t// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well\n\t\t\t// in practice:\n\t\t\t//\n\t\t\t// The idea is to cut the number c * w = f * 2^e into two parts, which can be\n\t\t\t// processed independently: An integral part p1, and a fractional part p2:\n\t\t\t//\n\t\t\t//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e\n\t\t\t//              = (f div 2^-e) + (f mod 2^-e) * 2^e\n\t\t\t//              = p1 + p2 * 2^e\n\t\t\t//\n\t\t\t// The conversion of p1 into decimal form requires a series of divisions and\n\t\t\t// modulos by (a power of) 10. These operations are faster for 32-bit than for\n\t\t\t// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be\n\t\t\t// achieved by choosing\n\t\t\t//\n\t\t\t//      -e >= 32   or   e <= -32 := gamma\n\t\t\t//\n\t\t\t// In order to convert the fractional part\n\t\t\t//\n\t\t\t//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...\n\t\t\t//\n\t\t\t// into decimal form, the fraction is repeatedly multiplied by 10 and the digits\n\t\t\t// d[-i] are extracted in order:\n\t\t\t//\n\t\t\t//      (10 * p2) div 2^-e = d[-1]\n\t\t\t//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...\n\t\t\t//\n\t\t\t// The multiplication by 10 must not overflow. It is sufficient to choose\n\t\t\t//\n\t\t\t//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.\n\t\t\t//\n\t\t\t// Since p2 = f mod 2^-e < 2^-e,\n\t\t\t//\n\t\t\t//      -e <= 60   or   e >= -60 := alpha\n\n\t\t\tconstexpr int kAlpha = -60;\n\t\t\tconstexpr int kGamma = -32;\n\n\t\t\tstruct cached_power // c = f * 2^e ~= 10^k\n\t\t\t{\n\t\t\t\tstd::uint64_t f;\n\t\t\t\tint e;\n\t\t\t\tint k;\n\t\t\t};\n\n\t\t\t/*!\n\t\t\tFor a normalized diyfp w = f * 2^e, this function returns a (normalized) cached\n\t\t\tpower-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c\n\t\t\tsatisfies (Definition 3.2 from [1])\n\n\t\t\t\t alpha <= e_c + e + q <= gamma.\n\t\t\t*/\n\t\t\tinline cached_power get_cached_power_for_binary_exponent(int e)\n\t\t\t{\n\t\t\t\t// Now\n\t\t\t\t//\n\t\t\t\t//      alpha <= e_c + e + q <= gamma                                    (1)\n\t\t\t\t//      ==> f_c * 2^alpha <= c * 2^e * 2^q\n\t\t\t\t//\n\t\t\t\t// and since the c's are normalized, 2^(q-1) <= f_c,\n\t\t\t\t//\n\t\t\t\t//      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)\n\t\t\t\t//      ==> 2^(alpha - e - 1) <= c\n\t\t\t\t//\n\t\t\t\t// If c were an exakt power of ten, i.e. c = 10^k, one may determine k as\n\t\t\t\t//\n\t\t\t\t//      k = ceil( log_10( 2^(alpha - e - 1) ) )\n\t\t\t\t//        = ceil( (alpha - e - 1) * log_10(2) )\n\t\t\t\t//\n\t\t\t\t// From the paper:\n\t\t\t\t// \"In theory the result of the procedure could be wrong since c is rounded,\n\t\t\t\t//  and the computation itself is approximated [...]. In practice, however,\n\t\t\t\t//  this simple function is sufficient.\"\n\t\t\t\t//\n\t\t\t\t// For IEEE double precision floating-point numbers converted into\n\t\t\t\t// normalized diyfp's w = f * 2^e, with q = 64,\n\t\t\t\t//\n\t\t\t\t//      e >= -1022      (min IEEE exponent)\n\t\t\t\t//           -52        (p - 1)\n\t\t\t\t//           -52        (p - 1, possibly normalize denormal IEEE numbers)\n\t\t\t\t//           -11        (normalize the diyfp)\n\t\t\t\t//         = -1137\n\t\t\t\t//\n\t\t\t\t// and\n\t\t\t\t//\n\t\t\t\t//      e <= +1023      (max IEEE exponent)\n\t\t\t\t//           -52        (p - 1)\n\t\t\t\t//           -11        (normalize the diyfp)\n\t\t\t\t//         = 960\n\t\t\t\t//\n\t\t\t\t// This binary exponent range [-1137,960] results in a decimal exponent\n\t\t\t\t// range [-307,324]. One does not need to store a cached power for each\n\t\t\t\t// k in this range. For each such k it suffices to find a cached power\n\t\t\t\t// such that the exponent of the product lies in [alpha,gamma].\n\t\t\t\t// This implies that the difference of the decimal exponents of adjacent\n\t\t\t\t// table entries must be less than or equal to\n\t\t\t\t//\n\t\t\t\t//      floor( (gamma - alpha) * log_10(2) ) = 8.\n\t\t\t\t//\n\t\t\t\t// (A smaller distance gamma-alpha would require a larger table.)\n\n\t\t\t\t// NB:\n\t\t\t\t// Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.\n\n\t\t\t\tconstexpr int kCachedPowersMinDecExp = -300;\n\t\t\t\tconstexpr int kCachedPowersDecStep = 8;\n\n\t\t\t\tstatic constexpr std::array<cached_power, 79> kCachedPowers =\n\t\t\t\t{\n\t\t\t\t\t{\n\t\t\t\t\t\t{ 0xAB70FE17C79AC6CA, -1060, -300 },\n\t\t\t\t\t\t{ 0xFF77B1FCBEBCDC4F, -1034, -292 },\n\t\t\t\t\t\t{ 0xBE5691EF416BD60C, -1007, -284 },\n\t\t\t\t\t\t{ 0x8DD01FAD907FFC3C,  -980, -276 },\n\t\t\t\t\t\t{ 0xD3515C2831559A83,  -954, -268 },\n\t\t\t\t\t\t{ 0x9D71AC8FADA6C9B5,  -927, -260 },\n\t\t\t\t\t\t{ 0xEA9C227723EE8BCB,  -901, -252 },\n\t\t\t\t\t\t{ 0xAECC49914078536D,  -874, -244 },\n\t\t\t\t\t\t{ 0x823C12795DB6CE57,  -847, -236 },\n\t\t\t\t\t\t{ 0xC21094364DFB5637,  -821, -228 },\n\t\t\t\t\t\t{ 0x9096EA6F3848984F,  -794, -220 },\n\t\t\t\t\t\t{ 0xD77485CB25823AC7,  -768, -212 },\n\t\t\t\t\t\t{ 0xA086CFCD97BF97F4,  -741, -204 },\n\t\t\t\t\t\t{ 0xEF340A98172AACE5,  -715, -196 },\n\t\t\t\t\t\t{ 0xB23867FB2A35B28E,  -688, -188 },\n\t\t\t\t\t\t{ 0x84C8D4DFD2C63F3B,  -661, -180 },\n\t\t\t\t\t\t{ 0xC5DD44271AD3CDBA,  -635, -172 },\n\t\t\t\t\t\t{ 0x936B9FCEBB25C996,  -608, -164 },\n\t\t\t\t\t\t{ 0xDBAC6C247D62A584,  -582, -156 },\n\t\t\t\t\t\t{ 0xA3AB66580D5FDAF6,  -555, -148 },\n\t\t\t\t\t\t{ 0xF3E2F893DEC3F126,  -529, -140 },\n\t\t\t\t\t\t{ 0xB5B5ADA8AAFF80B8,  -502, -132 },\n\t\t\t\t\t\t{ 0x87625F056C7C4A8B,  -475, -124 },\n\t\t\t\t\t\t{ 0xC9BCFF6034C13053,  -449, -116 },\n\t\t\t\t\t\t{ 0x964E858C91BA2655,  -422, -108 },\n\t\t\t\t\t\t{ 0xDFF9772470297EBD,  -396, -100 },\n\t\t\t\t\t\t{ 0xA6DFBD9FB8E5B88F,  -369,  -92 },\n\t\t\t\t\t\t{ 0xF8A95FCF88747D94,  -343,  -84 },\n\t\t\t\t\t\t{ 0xB94470938FA89BCF,  -316,  -76 },\n\t\t\t\t\t\t{ 0x8A08F0F8BF0F156B,  -289,  -68 },\n\t\t\t\t\t\t{ 0xCDB02555653131B6,  -263,  -60 },\n\t\t\t\t\t\t{ 0x993FE2C6D07B7FAC,  -236,  -52 },\n\t\t\t\t\t\t{ 0xE45C10C42A2B3B06,  -210,  -44 },\n\t\t\t\t\t\t{ 0xAA242499697392D3,  -183,  -36 },\n\t\t\t\t\t\t{ 0xFD87B5F28300CA0E,  -157,  -28 },\n\t\t\t\t\t\t{ 0xBCE5086492111AEB,  -130,  -20 },\n\t\t\t\t\t\t{ 0x8CBCCC096F5088CC,  -103,  -12 },\n\t\t\t\t\t\t{ 0xD1B71758E219652C,   -77,   -4 },\n\t\t\t\t\t\t{ 0x9C40000000000000,   -50,    4 },\n\t\t\t\t\t\t{ 0xE8D4A51000000000,   -24,   12 },\n\t\t\t\t\t\t{ 0xAD78EBC5AC620000,     3,   20 },\n\t\t\t\t\t\t{ 0x813F3978F8940984,    30,   28 },\n\t\t\t\t\t\t{ 0xC097CE7BC90715B3,    56,   36 },\n\t\t\t\t\t\t{ 0x8F7E32CE7BEA5C70,    83,   44 },\n\t\t\t\t\t\t{ 0xD5D238A4ABE98068,   109,   52 },\n\t\t\t\t\t\t{ 0x9F4F2726179A2245,   136,   60 },\n\t\t\t\t\t\t{ 0xED63A231D4C4FB27,   162,   68 },\n\t\t\t\t\t\t{ 0xB0DE65388CC8ADA8,   189,   76 },\n\t\t\t\t\t\t{ 0x83C7088E1AAB65DB,   216,   84 },\n\t\t\t\t\t\t{ 0xC45D1DF942711D9A,   242,   92 },\n\t\t\t\t\t\t{ 0x924D692CA61BE758,   269,  100 },\n\t\t\t\t\t\t{ 0xDA01EE641A708DEA,   295,  108 },\n\t\t\t\t\t\t{ 0xA26DA3999AEF774A,   322,  116 },\n\t\t\t\t\t\t{ 0xF209787BB47D6B85,   348,  124 },\n\t\t\t\t\t\t{ 0xB454E4A179DD1877,   375,  132 },\n\t\t\t\t\t\t{ 0x865B86925B9BC5C2,   402,  140 },\n\t\t\t\t\t\t{ 0xC83553C5C8965D3D,   428,  148 },\n\t\t\t\t\t\t{ 0x952AB45CFA97A0B3,   455,  156 },\n\t\t\t\t\t\t{ 0xDE469FBD99A05FE3,   481,  164 },\n\t\t\t\t\t\t{ 0xA59BC234DB398C25,   508,  172 },\n\t\t\t\t\t\t{ 0xF6C69A72A3989F5C,   534,  180 },\n\t\t\t\t\t\t{ 0xB7DCBF5354E9BECE,   561,  188 },\n\t\t\t\t\t\t{ 0x88FCF317F22241E2,   588,  196 },\n\t\t\t\t\t\t{ 0xCC20CE9BD35C78A5,   614,  204 },\n\t\t\t\t\t\t{ 0x98165AF37B2153DF,   641,  212 },\n\t\t\t\t\t\t{ 0xE2A0B5DC971F303A,   667,  220 },\n\t\t\t\t\t\t{ 0xA8D9D1535CE3B396,   694,  228 },\n\t\t\t\t\t\t{ 0xFB9B7CD9A4A7443C,   720,  236 },\n\t\t\t\t\t\t{ 0xBB764C4CA7A44410,   747,  244 },\n\t\t\t\t\t\t{ 0x8BAB8EEFB6409C1A,   774,  252 },\n\t\t\t\t\t\t{ 0xD01FEF10A657842C,   800,  260 },\n\t\t\t\t\t\t{ 0x9B10A4E5E9913129,   827,  268 },\n\t\t\t\t\t\t{ 0xE7109BFBA19C0C9D,   853,  276 },\n\t\t\t\t\t\t{ 0xAC2820D9623BF429,   880,  284 },\n\t\t\t\t\t\t{ 0x80444B5E7AA7CF85,   907,  292 },\n\t\t\t\t\t\t{ 0xBF21E44003ACDD2D,   933,  300 },\n\t\t\t\t\t\t{ 0x8E679C2F5E44FF8F,   960,  308 },\n\t\t\t\t\t\t{ 0xD433179D9C8CB841,   986,  316 },\n\t\t\t\t\t\t{ 0x9E19DB92B4E31BA9,  1013,  324 },\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// This computation gives exactly the same results for k as\n\t\t\t\t//      k = ceil((kAlpha - e - 1) * 0.30102999566398114)\n\t\t\t\t// for |e| <= 1500, but doesn't require floating-point operations.\n\t\t\t\t// NB: log_10(2) ~= 78913 / 2^18\n\t\t\t\tassert(e >= -1500);\n\t\t\t\tassert(e <= 1500);\n\t\t\t\tconst int f = kAlpha - e - 1;\n\t\t\t\tconst int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);\n\n\t\t\t\tconst int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;\n\t\t\t\tassert(index >= 0);\n\t\t\t\tassert(static_cast<std::size_t>(index) < kCachedPowers.size());\n\n\t\t\t\tconst cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];\n\t\t\t\tassert(kAlpha <= cached.e + e + 64);\n\t\t\t\tassert(kGamma >= cached.e + e + 64);\n\n\t\t\t\treturn cached;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\tFor n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.\n\t\t\tFor n == 0, returns 1 and sets pow10 := 1.\n\t\t\t*/\n\t\t\tinline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)\n\t\t\t{\n\t\t\t\t// LCOV_EXCL_START\n\t\t\t\tif (n >= 1000000000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 1000000000;\n\t\t\t\t\treturn 10;\n\t\t\t\t}\n\t\t\t\t// LCOV_EXCL_STOP\n\t\t\t\telse if (n >= 100000000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 100000000;\n\t\t\t\t\treturn  9;\n\t\t\t\t}\n\t\t\t\telse if (n >= 10000000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 10000000;\n\t\t\t\t\treturn  8;\n\t\t\t\t}\n\t\t\t\telse if (n >= 1000000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 1000000;\n\t\t\t\t\treturn  7;\n\t\t\t\t}\n\t\t\t\telse if (n >= 100000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 100000;\n\t\t\t\t\treturn  6;\n\t\t\t\t}\n\t\t\t\telse if (n >= 10000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 10000;\n\t\t\t\t\treturn  5;\n\t\t\t\t}\n\t\t\t\telse if (n >= 1000)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 1000;\n\t\t\t\t\treturn  4;\n\t\t\t\t}\n\t\t\t\telse if (n >= 100)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 100;\n\t\t\t\t\treturn  3;\n\t\t\t\t}\n\t\t\t\telse if (n >= 10)\n\t\t\t\t{\n\t\t\t\t\tpow10 = 10;\n\t\t\t\t\treturn  2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tpow10 = 1;\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,\n\t\t\t\tstd::uint64_t rest, std::uint64_t ten_k)\n\t\t\t{\n\t\t\t\tassert(len >= 1);\n\t\t\t\tassert(dist <= delta);\n\t\t\t\tassert(rest <= delta);\n\t\t\t\tassert(ten_k > 0);\n\n\t\t\t\t//               <--------------------------- delta ---->\n\t\t\t\t//                                  <---- dist --------->\n\t\t\t\t// --------------[------------------+-------------------]--------------\n\t\t\t\t//               M-                 w                   M+\n\t\t\t\t//\n\t\t\t\t//                                  ten_k\n\t\t\t\t//                                <------>\n\t\t\t\t//                                       <---- rest ---->\n\t\t\t\t// --------------[------------------+----+--------------]--------------\n\t\t\t\t//                                  w    V\n\t\t\t\t//                                       = buf * 10^k\n\t\t\t\t//\n\t\t\t\t// ten_k represents a unit-in-the-last-place in the decimal representation\n\t\t\t\t// stored in buf.\n\t\t\t\t// Decrement buf by ten_k while this takes buf closer to w.\n\n\t\t\t\t// The tests are written in this order to avoid overflow in unsigned\n\t\t\t\t// integer arithmetic.\n\n\t\t\t\twhile (rest < dist\n\t\t\t\t\tand delta - rest >= ten_k\n\t\t\t\t\tand (rest + ten_k < dist or dist - rest > rest + ten_k - dist))\n\t\t\t\t{\n\t\t\t\t\tassert(buf[len - 1] != '0');\n\t\t\t\t\tbuf[len - 1]--;\n\t\t\t\t\trest += ten_k;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\tGenerates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.\n\t\t\tM- and M+ must be normalized and share the same exponent -60 <= e <= -32.\n\t\t\t*/\n\t\t\tinline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,\n\t\t\t\tdiyfp M_minus, diyfp w, diyfp M_plus)\n\t\t\t{\n\t\t\t\tstatic_assert(kAlpha >= -60, \"internal error\");\n\t\t\t\tstatic_assert(kGamma <= -32, \"internal error\");\n\n\t\t\t\t// Generates the digits (and the exponent) of a decimal floating-point\n\t\t\t\t// number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's\n\t\t\t\t// w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.\n\t\t\t\t//\n\t\t\t\t//               <--------------------------- delta ---->\n\t\t\t\t//                                  <---- dist --------->\n\t\t\t\t// --------------[------------------+-------------------]--------------\n\t\t\t\t//               M-                 w                   M+\n\t\t\t\t//\n\t\t\t\t// Grisu2 generates the digits of M+ from left to right and stops as soon as\n\t\t\t\t// V is in [M-,M+].\n\n\t\t\t\tassert(M_plus.e >= kAlpha);\n\t\t\t\tassert(M_plus.e <= kGamma);\n\n\t\t\t\tstd::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)\n\t\t\t\tstd::uint64_t dist = diyfp::sub(M_plus, w).f; // (significand of (M+ - w ), implicit exponent is e)\n\n\t\t\t\t// Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):\n\t\t\t\t//\n\t\t\t\t//      M+ = f * 2^e\n\t\t\t\t//         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e\n\t\t\t\t//         = ((p1        ) * 2^-e + (p2        )) * 2^e\n\t\t\t\t//         = p1 + p2 * 2^e\n\n\t\t\t\tconst diyfp one(std::uint64_t{ 1 } << -M_plus.e, M_plus.e);\n\n\t\t\t\tauto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)\n\t\t\t\tstd::uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e\n\n\t\t\t\t// 1)\n\t\t\t\t//\n\t\t\t\t// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]\n\n\t\t\t\tassert(p1 > 0);\n\n\t\t\t\tstd::uint32_t pow10;\n\t\t\t\tconst int k = find_largest_pow10(p1, pow10);\n\n\t\t\t\t//      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)\n\t\t\t\t//\n\t\t\t\t//      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))\n\t\t\t\t//         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))\n\t\t\t\t//\n\t\t\t\t//      M+ = p1                                             + p2 * 2^e\n\t\t\t\t//         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e\n\t\t\t\t//         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e\n\t\t\t\t//         = d[k-1] * 10^(k-1) + (                         rest) * 2^e\n\t\t\t\t//\n\t\t\t\t// Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)\n\t\t\t\t//\n\t\t\t\t//      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]\n\t\t\t\t//\n\t\t\t\t// but stop as soon as\n\t\t\t\t//\n\t\t\t\t//      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e\n\n\t\t\t\tint n = k;\n\t\t\t\twhile (n > 0)\n\t\t\t\t{\n\t\t\t\t\t// Invariants:\n\t\t\t\t\t//      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)\n\t\t\t\t\t//      pow10 = 10^(n-1) <= p1 < 10^n\n\t\t\t\t\t//\n\t\t\t\t\tconst std::uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)\n\t\t\t\t\tconst std::uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)\n\t\t\t\t\t//\n\t\t\t\t\t//      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e\n\t\t\t\t\t//         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)\n\t\t\t\t\t//\n\t\t\t\t\tassert(d <= 9);\n\t\t\t\t\tbuffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n\t\t\t\t\t//\n\t\t\t\t\t//      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)\n\t\t\t\t\t//\n\t\t\t\t\tp1 = r;\n\t\t\t\t\tn--;\n\t\t\t\t\t//\n\t\t\t\t\t//      M+ = buffer * 10^n + (p1 + p2 * 2^e)\n\t\t\t\t\t//      pow10 = 10^n\n\t\t\t\t\t//\n\n\t\t\t\t\t// Now check if enough digits have been generated.\n\t\t\t\t\t// Compute\n\t\t\t\t\t//\n\t\t\t\t\t//      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e\n\t\t\t\t\t//\n\t\t\t\t\t// Note:\n\t\t\t\t\t// Since rest and delta share the same exponent e, it suffices to\n\t\t\t\t\t// compare the significands.\n\t\t\t\t\tconst std::uint64_t rest = (std::uint64_t{ p1 } << -one.e) + p2;\n\t\t\t\t\tif (rest <= delta)\n\t\t\t\t\t{\n\t\t\t\t\t\t// V = buffer * 10^n, with M- <= V <= M+.\n\n\t\t\t\t\t\tdecimal_exponent += n;\n\n\t\t\t\t\t\t// We may now just stop. But instead look if the buffer could be\n\t\t\t\t\t\t// decremented to bring V closer to w.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// pow10 = 10^n is now 1 ulp in the decimal representation V.\n\t\t\t\t\t\t// The rounding procedure works with diyfp's with an implicit\n\t\t\t\t\t\t// exponent of e.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t//      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e\n\t\t\t\t\t\t//\n\t\t\t\t\t\tconst std::uint64_t ten_n = std::uint64_t{ pow10 } << -one.e;\n\t\t\t\t\t\tgrisu2_round(buffer, length, dist, delta, rest, ten_n);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tpow10 /= 10;\n\t\t\t\t\t//\n\t\t\t\t\t//      pow10 = 10^(n-1) <= p1 < 10^n\n\t\t\t\t\t// Invariants restored.\n\t\t\t\t}\n\n\t\t\t\t// 2)\n\t\t\t\t//\n\t\t\t\t// The digits of the integral part have been generated:\n\t\t\t\t//\n\t\t\t\t//      M+ = d[k-1]...d[1]d[0] + p2 * 2^e\n\t\t\t\t//         = buffer            + p2 * 2^e\n\t\t\t\t//\n\t\t\t\t// Now generate the digits of the fractional part p2 * 2^e.\n\t\t\t\t//\n\t\t\t\t// Note:\n\t\t\t\t// No decimal point is generated: the exponent is adjusted instead.\n\t\t\t\t//\n\t\t\t\t// p2 actually represents the fraction\n\t\t\t\t//\n\t\t\t\t//      p2 * 2^e\n\t\t\t\t//          = p2 / 2^-e\n\t\t\t\t//          = d[-1] / 10^1 + d[-2] / 10^2 + ...\n\t\t\t\t//\n\t\t\t\t// Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)\n\t\t\t\t//\n\t\t\t\t//      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m\n\t\t\t\t//                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)\n\t\t\t\t//\n\t\t\t\t// using\n\t\t\t\t//\n\t\t\t\t//      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)\n\t\t\t\t//                = (                   d) * 2^-e + (                   r)\n\t\t\t\t//\n\t\t\t\t// or\n\t\t\t\t//      10^m * p2 * 2^e = d + r * 2^e\n\t\t\t\t//\n\t\t\t\t// i.e.\n\t\t\t\t//\n\t\t\t\t//      M+ = buffer + p2 * 2^e\n\t\t\t\t//         = buffer + 10^-m * (d + r * 2^e)\n\t\t\t\t//         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e\n\t\t\t\t//\n\t\t\t\t// and stop as soon as 10^-m * r * 2^e <= delta * 2^e\n\n\t\t\t\tassert(p2 > delta);\n\n\t\t\t\tint m = 0;\n\t\t\t\tfor (;;)\n\t\t\t\t{\n\t\t\t\t\t// Invariant:\n\t\t\t\t\t//      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e\n\t\t\t\t\t//         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e\n\t\t\t\t\t//         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e\n\t\t\t\t\t//         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e\n\t\t\t\t\t//\n\t\t\t\t\tassert(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);\n\t\t\t\t\tp2 *= 10;\n\t\t\t\t\tconst std::uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e\n\t\t\t\t\tconst std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e\n\t\t\t\t\t//\n\t\t\t\t\t//      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e\n\t\t\t\t\t//         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))\n\t\t\t\t\t//         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e\n\t\t\t\t\t//\n\t\t\t\t\tassert(d <= 9);\n\t\t\t\t\tbuffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n\t\t\t\t\t//\n\t\t\t\t\t//      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e\n\t\t\t\t\t//\n\t\t\t\t\tp2 = r;\n\t\t\t\t\tm++;\n\t\t\t\t\t//\n\t\t\t\t\t//      M+ = buffer * 10^-m + 10^-m * p2 * 2^e\n\t\t\t\t\t// Invariant restored.\n\n\t\t\t\t\t// Check if enough digits have been generated.\n\t\t\t\t\t//\n\t\t\t\t\t//      10^-m * p2 * 2^e <= delta * 2^e\n\t\t\t\t\t//              p2 * 2^e <= 10^m * delta * 2^e\n\t\t\t\t\t//                    p2 <= 10^m * delta\n\t\t\t\t\tdelta *= 10;\n\t\t\t\t\tdist *= 10;\n\t\t\t\t\tif (p2 <= delta)\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// V = buffer * 10^-m, with M- <= V <= M+.\n\n\t\t\t\tdecimal_exponent -= m;\n\n\t\t\t\t// 1 ulp in the decimal representation is now 10^-m.\n\t\t\t\t// Since delta and dist are now scaled by 10^m, we need to do the\n\t\t\t\t// same with ulp in order to keep the units in sync.\n\t\t\t\t//\n\t\t\t\t//      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e\n\t\t\t\t//\n\t\t\t\tconst std::uint64_t ten_m = one.f;\n\t\t\t\tgrisu2_round(buffer, length, dist, delta, p2, ten_m);\n\n\t\t\t\t// By construction this algorithm generates the shortest possible decimal\n\t\t\t\t// number (Loitsch, Theorem 6.2) which rounds back to w.\n\t\t\t\t// For an input number of precision p, at least\n\t\t\t\t//\n\t\t\t\t//      N = 1 + ceil(p * log_10(2))\n\t\t\t\t//\n\t\t\t\t// decimal digits are sufficient to identify all binary floating-point\n\t\t\t\t// numbers (Matula, \"In-and-Out conversions\").\n\t\t\t\t// This implies that the algorithm does not produce more than N decimal\n\t\t\t\t// digits.\n\t\t\t\t//\n\t\t\t\t//      N = 17 for p = 53 (IEEE double precision)\n\t\t\t\t//      N = 9  for p = 24 (IEEE single precision)\n\t\t\t}\n\n\t\t\t/*!\n\t\t\tv = buf * 10^decimal_exponent\n\t\t\tlen is the length of the buffer (number of decimal digits)\n\t\t\tThe buffer must be large enough, i.e. >= max_digits10.\n\t\t\t*/\n\t\t\tinline void grisu2(char* buf, int& len, int& decimal_exponent,\n\t\t\t\tdiyfp m_minus, diyfp v, diyfp m_plus)\n\t\t\t{\n\t\t\t\tassert(m_plus.e == m_minus.e);\n\t\t\t\tassert(m_plus.e == v.e);\n\n\t\t\t\t//  --------(-----------------------+-----------------------)--------    (A)\n\t\t\t\t//          m-                      v                       m+\n\t\t\t\t//\n\t\t\t\t//  --------------------(-----------+-----------------------)--------    (B)\n\t\t\t\t//                      m-          v                       m+\n\t\t\t\t//\n\t\t\t\t// First scale v (and m- and m+) such that the exponent is in the range\n\t\t\t\t// [alpha, gamma].\n\n\t\t\t\tconst cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);\n\n\t\t\t\tconst diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k\n\n\t\t\t\t// The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]\n\t\t\t\tconst diyfp w = diyfp::mul(v, c_minus_k);\n\t\t\t\tconst diyfp w_minus = diyfp::mul(m_minus, c_minus_k);\n\t\t\t\tconst diyfp w_plus = diyfp::mul(m_plus, c_minus_k);\n\n\t\t\t\t//  ----(---+---)---------------(---+---)---------------(---+---)----\n\t\t\t\t//          w-                      w                       w+\n\t\t\t\t//          = c*m-                  = c*v                   = c*m+\n\t\t\t\t//\n\t\t\t\t// diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and\n\t\t\t\t// w+ are now off by a small amount.\n\t\t\t\t// In fact:\n\t\t\t\t//\n\t\t\t\t//      w - v * 10^k < 1 ulp\n\t\t\t\t//\n\t\t\t\t// To account for this inaccuracy, add resp. subtract 1 ulp.\n\t\t\t\t//\n\t\t\t\t//  --------+---[---------------(---+---)---------------]---+--------\n\t\t\t\t//          w-  M-                  w                   M+  w+\n\t\t\t\t//\n\t\t\t\t// Now any number in [M-, M+] (bounds included) will round to w when input,\n\t\t\t\t// regardless of how the input rounding algorithm breaks ties.\n\t\t\t\t//\n\t\t\t\t// And digit_gen generates the shortest possible such number in [M-, M+].\n\t\t\t\t// Note that this does not mean that Grisu2 always generates the shortest\n\t\t\t\t// possible number in the interval (m-, m+).\n\t\t\t\tconst diyfp M_minus(w_minus.f + 1, w_minus.e);\n\t\t\t\tconst diyfp M_plus(w_plus.f - 1, w_plus.e);\n\n\t\t\t\tdecimal_exponent = -cached.k; // = -(-k) = k\n\n\t\t\t\tgrisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\tv = buf * 10^decimal_exponent\n\t\t\tlen is the length of the buffer (number of decimal digits)\n\t\t\tThe buffer must be large enough, i.e. >= max_digits10.\n\t\t\t*/\n\t\t\ttemplate <typename FloatType>\n\t\t\tvoid grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)\n\t\t\t{\n\t\t\t\tstatic_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,\n\t\t\t\t\t\"internal error: not enough precision\");\n\n\t\t\t\tassert(std::isfinite(value));\n\t\t\t\tassert(value > 0);\n\n\t\t\t\t// If the neighbors (and boundaries) of 'value' are always computed for double-precision\n\t\t\t\t// numbers, all float's can be recovered using strtod (and strtof). However, the resulting\n\t\t\t\t// decimal representations are not exactly \"short\".\n\t\t\t\t//\n\t\t\t\t// The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)\n\t\t\t\t// says \"value is converted to a string as if by std::sprintf in the default (\"C\") locale\"\n\t\t\t\t// and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'\n\t\t\t\t// does.\n\t\t\t\t// On the other hand, the documentation for 'std::to_chars' requires that \"parsing the\n\t\t\t\t// representation using the corresponding std::from_chars function recovers value exactly\". That\n\t\t\t\t// indicates that single precision floating-point numbers should be recovered using\n\t\t\t\t// 'std::strtof'.\n\t\t\t\t//\n\t\t\t\t// NB: If the neighbors are computed for single-precision numbers, there is a single float\n\t\t\t\t//     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision\n\t\t\t\t//     value is off by 1 ulp.\n#if 0\n\t\t\t\tconst boundaries w = compute_boundaries(static_cast<double>(value));\n#else\n\t\t\t\tconst boundaries w = compute_boundaries(value);\n#endif\n\n\t\t\t\tgrisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief appends a decimal representation of e to buf\n\t\t\t@return a pointer to the element following the exponent.\n\t\t\t@pre -1000 < e < 1000\n\t\t\t*/\n\t\t\tinline char* append_exponent(char* buf, int e)\n\t\t\t{\n\t\t\t\tassert(e > -1000);\n\t\t\t\tassert(e < 1000);\n\n\t\t\t\tif (e < 0)\n\t\t\t\t{\n\t\t\t\t\te = -e;\n\t\t\t\t\t*buf++ = '-';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t*buf++ = '+';\n\t\t\t\t}\n\n\t\t\t\tauto k = static_cast<std::uint32_t>(e);\n\t\t\t\tif (k < 10)\n\t\t\t\t{\n\t\t\t\t\t// Always print at least two digits in the exponent.\n\t\t\t\t\t// This is for compatibility with printf(\"%g\").\n\t\t\t\t\t*buf++ = '0';\n\t\t\t\t\t*buf++ = static_cast<char>('0' + k);\n\t\t\t\t}\n\t\t\t\telse if (k < 100)\n\t\t\t\t{\n\t\t\t\t\t*buf++ = static_cast<char>('0' + k / 10);\n\t\t\t\t\tk %= 10;\n\t\t\t\t\t*buf++ = static_cast<char>('0' + k);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t*buf++ = static_cast<char>('0' + k / 100);\n\t\t\t\t\tk %= 100;\n\t\t\t\t\t*buf++ = static_cast<char>('0' + k / 10);\n\t\t\t\t\tk %= 10;\n\t\t\t\t\t*buf++ = static_cast<char>('0' + k);\n\t\t\t\t}\n\n\t\t\t\treturn buf;\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief prettify v = buf * 10^decimal_exponent\n\n\t\t\tIf v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point\n\t\t\tnotation. Otherwise it will be printed in exponential notation.\n\n\t\t\t@pre min_exp < 0\n\t\t\t@pre max_exp > 0\n\t\t\t*/\n\t\t\tinline char* format_buffer(char* buf, int len, int decimal_exponent,\n\t\t\t\tint min_exp, int max_exp)\n\t\t\t{\n\t\t\t\tassert(min_exp < 0);\n\t\t\t\tassert(max_exp > 0);\n\n\t\t\t\tconst int k = len;\n\t\t\t\tconst int n = len + decimal_exponent;\n\n\t\t\t\t// v = buf * 10^(n-k)\n\t\t\t\t// k is the length of the buffer (number of decimal digits)\n\t\t\t\t// n is the position of the decimal point relative to the start of the buffer.\n\n\t\t\t\tif (k <= n and n <= max_exp)\n\t\t\t\t{\n\t\t\t\t\t// digits[000]\n\t\t\t\t\t// len <= max_exp + 2\n\n\t\t\t\t\tstd::memset(buf + k, '0', static_cast<size_t>(n - k));\n\t\t\t\t\t// Make it look like a floating-point number (#362, #378)\n\t\t\t\t\tbuf[n + 0] = '.';\n\t\t\t\t\tbuf[n + 1] = '0';\n\t\t\t\t\treturn buf + (n + 2);\n\t\t\t\t}\n\n\t\t\t\tif (0 < n and n <= max_exp)\n\t\t\t\t{\n\t\t\t\t\t// dig.its\n\t\t\t\t\t// len <= max_digits10 + 1\n\n\t\t\t\t\tassert(k > n);\n\n\t\t\t\t\tstd::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));\n\t\t\t\t\tbuf[n] = '.';\n\t\t\t\t\treturn buf + (k + 1);\n\t\t\t\t}\n\n\t\t\t\tif (min_exp < n and n <= 0)\n\t\t\t\t{\n\t\t\t\t\t// 0.[000]digits\n\t\t\t\t\t// len <= 2 + (-min_exp - 1) + max_digits10\n\n\t\t\t\t\tstd::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));\n\t\t\t\t\tbuf[0] = '0';\n\t\t\t\t\tbuf[1] = '.';\n\t\t\t\t\tstd::memset(buf + 2, '0', static_cast<size_t>(-n));\n\t\t\t\t\treturn buf + (2 + (-n) + k);\n\t\t\t\t}\n\n\t\t\t\tif (k == 1)\n\t\t\t\t{\n\t\t\t\t\t// dE+123\n\t\t\t\t\t// len <= 1 + 5\n\n\t\t\t\t\tbuf += 1;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// d.igitsE+123\n\t\t\t\t\t// len <= max_digits10 + 1 + 5\n\n\t\t\t\t\tstd::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));\n\t\t\t\t\tbuf[1] = '.';\n\t\t\t\t\tbuf += 1 + k;\n\t\t\t\t}\n\n\t\t\t\t*buf++ = 'e';\n\t\t\t\treturn append_exponent(buf, n - 1);\n\t\t\t}\n\n\t\t} // namespace dtoa_impl\n\n\t\t/*!\n\t\t@brief generates a decimal representation of the floating-point number value in [first, last).\n\n\t\tThe format of the resulting decimal representation is similar to printf's %g\n\t\tformat. Returns an iterator pointing past-the-end of the decimal representation.\n\n\t\t@note The input number must be finite, i.e. NaN's and Inf's are not supported.\n\t\t@note The buffer must be large enough.\n\t\t@note The result is NOT null-terminated.\n\t\t*/\n\t\ttemplate <typename FloatType>\n\t\tchar* to_chars(char* first, const char* last, FloatType value)\n\t\t{\n\t\t\tstatic_cast<void>(last); // maybe unused - fix warning\n\t\t\tassert(std::isfinite(value));\n\n\t\t\t// Use signbit(value) instead of (value < 0) since signbit works for -0.\n\t\t\tif (std::signbit(value))\n\t\t\t{\n\t\t\t\tvalue = -value;\n\t\t\t\t*first++ = '-';\n\t\t\t}\n\n\t\t\tif (value == 0) // +-0\n\t\t\t{\n\t\t\t\t*first++ = '0';\n\t\t\t\t// Make it look like a floating-point number (#362, #378)\n\t\t\t\t*first++ = '.';\n\t\t\t\t*first++ = '0';\n\t\t\t\treturn first;\n\t\t\t}\n\n\t\t\tassert(last - first >= std::numeric_limits<FloatType>::max_digits10);\n\n\t\t\t// Compute v = buffer * 10^decimal_exponent.\n\t\t\t// The decimal digits are stored in the buffer, which needs to be interpreted\n\t\t\t// as an unsigned decimal integer.\n\t\t\t// len is the length of the buffer, i.e. the number of decimal digits.\n\t\t\tint len = 0;\n\t\t\tint decimal_exponent = 0;\n\t\t\tdtoa_impl::grisu2(first, len, decimal_exponent, value);\n\n\t\t\tassert(len <= std::numeric_limits<FloatType>::max_digits10);\n\n\t\t\t// Format the buffer like printf(\"%.*g\", prec, value)\n\t\t\tconstexpr int kMinExp = -4;\n\t\t\t// Use digits10 here to increase compatibility with version 2.\n\t\t\tconstexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;\n\n\t\t\tassert(last - first >= kMaxExp + 2);\n\t\t\tassert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);\n\t\t\tassert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);\n\n\t\t\treturn dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);\n\t\t}\n\n\t} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\n\tnamespace detail\n\t{\n\t\t///////////////////\n\t\t// serialization //\n\t\t///////////////////\n\n\t\t/// how to treat decoding errors\n\t\tenum class error_handler_t\n\t\t{\n\t\t\tstrict,  ///< throw a type_error exception in case of invalid UTF-8\n\t\t\treplace, ///< replace invalid UTF-8 sequences with U+FFFD\n\t\t\tignore   ///< ignore invalid UTF-8 sequences\n\t\t};\n\n\t\ttemplate<typename BasicJsonType>\n\t\tclass serializer\n\t\t{\n\t\t\tusing string_t = typename BasicJsonType::string_t;\n\t\t\tusing number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tstatic constexpr std::uint8_t UTF8_ACCEPT = 0;\n\t\t\tstatic constexpr std::uint8_t UTF8_REJECT = 1;\n\n\t\tpublic:\n\t\t\t/*!\n\t\t\t@param[in] s  output stream to serialize to\n\t\t\t@param[in] ichar  indentation character to use\n\t\t\t@param[in] error_handler_  how to react on decoding errors\n\t\t\t*/\n\t\t\tserializer(output_adapter_t<char> s, const char ichar,\n\t\t\t\terror_handler_t error_handler_ = error_handler_t::strict)\n\t\t\t\t: o(std::move(s))\n\t\t\t\t, loc(std::localeconv())\n\t\t\t\t, thousands_sep(loc->thousands_sep == nullptr ? '\\0' : *(loc->thousands_sep))\n\t\t\t\t, decimal_point(loc->decimal_point == nullptr ? '\\0' : *(loc->decimal_point))\n\t\t\t\t, indent_char(ichar)\n\t\t\t\t, indent_string(512, indent_char)\n\t\t\t\t, error_handler(error_handler_)\n\t\t\t{}\n\n\t\t\t// delete because of pointer members\n\t\t\tserializer(const serializer&) = delete;\n\t\t\tserializer& operator=(const serializer&) = delete;\n\t\t\tserializer(serializer&&) = delete;\n\t\t\tserializer& operator=(serializer&&) = delete;\n\t\t\t~serializer() = default;\n\n\t\t\t/*!\n\t\t\t@brief internal implementation of the serialization function\n\n\t\t\tThis function is called by the public member function dump and organizes\n\t\t\tthe serialization internally. The indentation level is propagated as\n\t\t\tadditional parameter. In case of arrays and objects, the function is\n\t\t\tcalled recursively.\n\n\t\t\t- strings and object keys are escaped using `escape_string()`\n\t\t\t- integer numbers are converted implicitly via `operator<<`\n\t\t\t- floating-point numbers are converted to a string using `\"%g\"` format\n\n\t\t\t@param[in] val             value to serialize\n\t\t\t@param[in] pretty_print    whether the output shall be pretty-printed\n\t\t\t@param[in] indent_step     the indent level\n\t\t\t@param[in] current_indent  the current indent level (only used internally)\n\t\t\t*/\n\t\t\tvoid dump(const BasicJsonType& val, const bool pretty_print,\n\t\t\t\tconst bool ensure_ascii,\n\t\t\t\tconst unsigned int indent_step,\n\t\t\t\tconst unsigned int current_indent = 0)\n\t\t\t{\n\t\t\t\tswitch (val.m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tif (val.m_value.object->empty())\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(\"{}\", 2);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pretty_print)\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(\"{\\n\", 2);\n\n\t\t\t\t\t\t// variable to hold indentation for recursive calls\n\t\t\t\t\t\tconst auto new_indent = current_indent + indent_step;\n\t\t\t\t\t\tif (JSON_UNLIKELY(indent_string.size() < new_indent))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tindent_string.resize(indent_string.size() * 2, ' ');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// first n-1 elements\n\t\t\t\t\t\tauto i = val.m_value.object->cbegin();\n\t\t\t\t\t\tfor (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to->write_characters(indent_string.c_str(), new_indent);\n\t\t\t\t\t\t\to->write_character('\\\"');\n\t\t\t\t\t\t\tdump_escaped(i->first, ensure_ascii);\n\t\t\t\t\t\t\to->write_characters(\"\\\": \", 3);\n\t\t\t\t\t\t\tdump(i->second, true, ensure_ascii, indent_step, new_indent);\n\t\t\t\t\t\t\to->write_characters(\",\\n\", 2);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// last element\n\t\t\t\t\t\tassert(i != val.m_value.object->cend());\n\t\t\t\t\t\tassert(std::next(i) == val.m_value.object->cend());\n\t\t\t\t\t\to->write_characters(indent_string.c_str(), new_indent);\n\t\t\t\t\t\to->write_character('\\\"');\n\t\t\t\t\t\tdump_escaped(i->first, ensure_ascii);\n\t\t\t\t\t\to->write_characters(\"\\\": \", 3);\n\t\t\t\t\t\tdump(i->second, true, ensure_ascii, indent_step, new_indent);\n\n\t\t\t\t\t\to->write_character('\\n');\n\t\t\t\t\t\to->write_characters(indent_string.c_str(), current_indent);\n\t\t\t\t\t\to->write_character('}');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_character('{');\n\n\t\t\t\t\t\t// first n-1 elements\n\t\t\t\t\t\tauto i = val.m_value.object->cbegin();\n\t\t\t\t\t\tfor (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to->write_character('\\\"');\n\t\t\t\t\t\t\tdump_escaped(i->first, ensure_ascii);\n\t\t\t\t\t\t\to->write_characters(\"\\\":\", 2);\n\t\t\t\t\t\t\tdump(i->second, false, ensure_ascii, indent_step, current_indent);\n\t\t\t\t\t\t\to->write_character(',');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// last element\n\t\t\t\t\t\tassert(i != val.m_value.object->cend());\n\t\t\t\t\t\tassert(std::next(i) == val.m_value.object->cend());\n\t\t\t\t\t\to->write_character('\\\"');\n\t\t\t\t\t\tdump_escaped(i->first, ensure_ascii);\n\t\t\t\t\t\to->write_characters(\"\\\":\", 2);\n\t\t\t\t\t\tdump(i->second, false, ensure_ascii, indent_step, current_indent);\n\n\t\t\t\t\t\to->write_character('}');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (val.m_value.array->empty())\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(\"[]\", 2);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pretty_print)\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(\"[\\n\", 2);\n\n\t\t\t\t\t\t// variable to hold indentation for recursive calls\n\t\t\t\t\t\tconst auto new_indent = current_indent + indent_step;\n\t\t\t\t\t\tif (JSON_UNLIKELY(indent_string.size() < new_indent))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tindent_string.resize(indent_string.size() * 2, ' ');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// first n-1 elements\n\t\t\t\t\t\tfor (auto i = val.m_value.array->cbegin();\n\t\t\t\t\t\t\ti != val.m_value.array->cend() - 1; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to->write_characters(indent_string.c_str(), new_indent);\n\t\t\t\t\t\t\tdump(*i, true, ensure_ascii, indent_step, new_indent);\n\t\t\t\t\t\t\to->write_characters(\",\\n\", 2);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// last element\n\t\t\t\t\t\tassert(not val.m_value.array->empty());\n\t\t\t\t\t\to->write_characters(indent_string.c_str(), new_indent);\n\t\t\t\t\t\tdump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);\n\n\t\t\t\t\t\to->write_character('\\n');\n\t\t\t\t\t\to->write_characters(indent_string.c_str(), current_indent);\n\t\t\t\t\t\to->write_character(']');\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_character('[');\n\n\t\t\t\t\t\t// first n-1 elements\n\t\t\t\t\t\tfor (auto i = val.m_value.array->cbegin();\n\t\t\t\t\t\t\ti != val.m_value.array->cend() - 1; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdump(*i, false, ensure_ascii, indent_step, current_indent);\n\t\t\t\t\t\t\to->write_character(',');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// last element\n\t\t\t\t\t\tassert(not val.m_value.array->empty());\n\t\t\t\t\t\tdump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);\n\n\t\t\t\t\t\to->write_character(']');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t{\n\t\t\t\t\to->write_character('\\\"');\n\t\t\t\t\tdump_escaped(*val.m_value.string, ensure_ascii);\n\t\t\t\t\to->write_character('\\\"');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t{\n\t\t\t\t\tif (val.m_value.boolean)\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(\"true\", 4);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(\"false\", 5);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t{\n\t\t\t\t\tdump_integer(val.m_value.number_integer);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t{\n\t\t\t\t\tdump_integer(val.m_value.number_unsigned);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t{\n\t\t\t\t\tdump_float(val.m_value.number_float);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::discarded:\n\t\t\t\t{\n\t\t\t\t\to->write_characters(\"<discarded>\", 11);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t{\n\t\t\t\t\to->write_characters(\"null\", 4);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t}\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/*!\n\t\t\t@brief dump escaped string\n\n\t\t\tEscape a string by replacing certain special characters by a sequence of an\n\t\t\tescape character (backslash) and another character and other control\n\t\t\tcharacters by a sequence of \"\\u\" followed by a four-digit hex\n\t\t\trepresentation. The escaped string is written to output stream @a o.\n\n\t\t\t@param[in] s  the string to escape\n\t\t\t@param[in] ensure_ascii  whether to escape non-ASCII characters with\n\t\t\t\t\t\t\t\t\t \\uXXXX sequences\n\n\t\t\t@complexity Linear in the length of string @a s.\n\t\t\t*/\n\t\t\tvoid dump_escaped(const string_t& s, const bool ensure_ascii)\n\t\t\t{\n\t\t\t\tstd::uint32_t codepoint;\n\t\t\t\tstd::uint8_t state = UTF8_ACCEPT;\n\t\t\t\tstd::size_t bytes = 0;  // number of bytes written to string_buffer\n\n\t\t\t\t// number of bytes written at the point of the last valid byte\n\t\t\t\tstd::size_t bytes_after_last_accept = 0;\n\t\t\t\tstd::size_t undumped_chars = 0;\n\n\t\t\t\tfor (std::size_t i = 0; i < s.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tconst auto byte = static_cast<uint8_t>(s[i]);\n\n\t\t\t\t\tswitch (decode(state, codepoint, byte))\n\t\t\t\t\t{\n\t\t\t\t\tcase UTF8_ACCEPT:  // decode found a new code point\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (codepoint)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase 0x08: // backspace\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = 'b';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 0x09: // horizontal tab\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = 't';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 0x0A: // newline\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = 'n';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 0x0C: // formfeed\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = 'f';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 0x0D: // carriage return\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = 'r';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 0x22: // quotation mark\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\"';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 0x5C: // reverse solidus\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// escape control characters (0x00..0x1F) or, if\n\t\t\t\t\t\t\t// ensure_ascii parameter is used, non-ASCII characters\n\t\t\t\t\t\t\tif ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (codepoint <= 0xFFFF)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t(std::snprintf)(string_buffer.data() + bytes, 7, \"\\\\u%04x\",\n\t\t\t\t\t\t\t\t\t\tstatic_cast<std::uint16_t>(codepoint));\n\t\t\t\t\t\t\t\t\tbytes += 6;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t(std::snprintf)(string_buffer.data() + bytes, 13, \"\\\\u%04x\\\\u%04x\",\n\t\t\t\t\t\t\t\t\t\tstatic_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),\n\t\t\t\t\t\t\t\t\t\tstatic_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));\n\t\t\t\t\t\t\t\t\tbytes += 12;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// copy byte to buffer (all previous bytes\n\t\t\t\t\t\t\t\t// been copied have in default case above)\n\t\t\t\t\t\t\t\tstring_buffer[bytes++] = s[i];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// write buffer and reset index; there must be 13 bytes\n\t\t\t\t\t\t// left, as this is the maximal number of bytes to be\n\t\t\t\t\t\t// written (\"\\uxxxx\\uxxxx\\0\") for one code point\n\t\t\t\t\t\tif (string_buffer.size() - bytes < 13)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to->write_characters(string_buffer.data(), bytes);\n\t\t\t\t\t\t\tbytes = 0;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// remember the byte position of this accept\n\t\t\t\t\t\tbytes_after_last_accept = bytes;\n\t\t\t\t\t\tundumped_chars = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase UTF8_REJECT:  // decode found invalid UTF-8 byte\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (error_handler)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase error_handler_t::strict:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::string sn(3, '\\0');\n\t\t\t\t\t\t\t(std::snprintf)(&sn[0], sn.size(), \"%.2X\", byte);\n\t\t\t\t\t\t\tJSON_THROW(type_error::create(316, \"invalid UTF-8 byte at index \" + std::to_string(i) + \": 0x\" + sn));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase error_handler_t::ignore:\n\t\t\t\t\t\tcase error_handler_t::replace:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// in case we saw this character the first time, we\n\t\t\t\t\t\t\t// would like to read it again, because the byte\n\t\t\t\t\t\t\t// may be OK for itself, but just not OK for the\n\t\t\t\t\t\t\t// previous sequence\n\t\t\t\t\t\t\tif (undumped_chars > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t--i;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// reset length buffer to the last accepted index;\n\t\t\t\t\t\t\t// thus removing/ignoring the invalid characters\n\t\t\t\t\t\t\tbytes = bytes_after_last_accept;\n\n\t\t\t\t\t\t\tif (error_handler == error_handler_t::replace)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// add a replacement character\n\t\t\t\t\t\t\t\tif (ensure_ascii)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = '\\\\';\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = 'u';\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = 'f';\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = 'f';\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = 'f';\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = 'd';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xEF');\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBF');\n\t\t\t\t\t\t\t\t\tstring_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBD');\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// write buffer and reset index; there must be 13 bytes\n\t\t\t\t\t\t\t\t// left, as this is the maximal number of bytes to be\n\t\t\t\t\t\t\t\t// written (\"\\uxxxx\\uxxxx\\0\") for one code point\n\t\t\t\t\t\t\t\tif (string_buffer.size() - bytes < 13)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\to->write_characters(string_buffer.data(), bytes);\n\t\t\t\t\t\t\t\t\tbytes = 0;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbytes_after_last_accept = bytes;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tundumped_chars = 0;\n\n\t\t\t\t\t\t\t// continue processing the string\n\t\t\t\t\t\t\tstate = UTF8_ACCEPT;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault:  // decode found yet incomplete multi-byte code point\n\t\t\t\t\t{\n\t\t\t\t\t\tif (not ensure_ascii)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// code point will not be escaped - copy byte to buffer\n\t\t\t\t\t\t\tstring_buffer[bytes++] = s[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t++undumped_chars;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// we finished processing the string\n\t\t\t\tif (JSON_LIKELY(state == UTF8_ACCEPT))\n\t\t\t\t{\n\t\t\t\t\t// write buffer\n\t\t\t\t\tif (bytes > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\to->write_characters(string_buffer.data(), bytes);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we finish reading, but do not accept: string was incomplete\n\t\t\t\t\tswitch (error_handler)\n\t\t\t\t\t{\n\t\t\t\t\tcase error_handler_t::strict:\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string sn(3, '\\0');\n\t\t\t\t\t\t(std::snprintf)(&sn[0], sn.size(), \"%.2X\", static_cast<std::uint8_t>(s.back()));\n\t\t\t\t\t\tJSON_THROW(type_error::create(316, \"incomplete UTF-8 string; last byte: 0x\" + sn));\n\t\t\t\t\t}\n\n\t\t\t\t\tcase error_handler_t::ignore:\n\t\t\t\t\t{\n\t\t\t\t\t\t// write all accepted bytes\n\t\t\t\t\t\to->write_characters(string_buffer.data(), bytes_after_last_accept);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase error_handler_t::replace:\n\t\t\t\t\t{\n\t\t\t\t\t\t// write all accepted bytes\n\t\t\t\t\t\to->write_characters(string_buffer.data(), bytes_after_last_accept);\n\t\t\t\t\t\t// add a replacement character\n\t\t\t\t\t\tif (ensure_ascii)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to->write_characters(\"\\\\ufffd\", 6);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to->write_characters(\"\\xEF\\xBF\\xBD\", 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief count digits\n\n\t\t\tCount the number of decimal (base 10) digits for an input unsigned integer.\n\n\t\t\t@param[in] x  unsigned integer number to count its digits\n\t\t\t@return    number of decimal digits\n\t\t\t*/\n\t\t\tinline unsigned int count_digits(number_unsigned_t x) noexcept\n\t\t\t{\n\t\t\t\tunsigned int n_digits = 1;\n\t\t\t\tfor (;;)\n\t\t\t\t{\n\t\t\t\t\tif (x < 10)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn n_digits;\n\t\t\t\t\t}\n\t\t\t\t\tif (x < 100)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn n_digits + 1;\n\t\t\t\t\t}\n\t\t\t\t\tif (x < 1000)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn n_digits + 2;\n\t\t\t\t\t}\n\t\t\t\t\tif (x < 10000)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn n_digits + 3;\n\t\t\t\t\t}\n\t\t\t\t\tx = x / 10000u;\n\t\t\t\t\tn_digits += 4;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief dump an integer\n\n\t\t\tDump a given integer to output stream @a o. Works internally with\n\t\t\t@a number_buffer.\n\n\t\t\t@param[in] x  integer number (signed or unsigned) to dump\n\t\t\t@tparam NumberType either @a number_integer_t or @a number_unsigned_t\n\t\t\t*/\n\t\t\ttemplate<typename NumberType, detail::enable_if_t<\n\t\t\t\tstd::is_same<NumberType, number_unsigned_t>::value or\n\t\t\t\tstd::is_same<NumberType, number_integer_t>::value,\n\t\t\t\tint> = 0>\n\t\t\t\tvoid dump_integer(NumberType x)\n\t\t\t{\n\t\t\t\tstatic constexpr std::array<std::array<char, 2>, 100> digits_to_99\n\t\t\t\t{\n\t\t\t\t\t{\n\t\t\t\t\t\t{{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},\n\t\t\t\t\t\t{{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},\n\t\t\t\t\t\t{{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},\n\t\t\t\t\t\t{{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},\n\t\t\t\t\t\t{{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},\n\t\t\t\t\t\t{{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},\n\t\t\t\t\t\t{{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},\n\t\t\t\t\t\t{{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},\n\t\t\t\t\t\t{{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},\n\t\t\t\t\t\t{{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// special case for \"0\"\n\t\t\t\tif (x == 0)\n\t\t\t\t{\n\t\t\t\t\to->write_character('0');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// use a pointer to fill the buffer\n\t\t\t\tauto buffer_ptr = number_buffer.begin();\n\n\t\t\t\tconst bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755\n\t\t\t\tnumber_unsigned_t abs_value;\n\n\t\t\t\tunsigned int n_chars;\n\n\t\t\t\tif (is_negative)\n\t\t\t\t{\n\t\t\t\t\t*buffer_ptr = '-';\n\t\t\t\t\tabs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));\n\n\t\t\t\t\t// account one more byte for the minus sign\n\t\t\t\t\tn_chars = 1 + count_digits(abs_value);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tabs_value = static_cast<number_unsigned_t>(x);\n\t\t\t\t\tn_chars = count_digits(abs_value);\n\t\t\t\t}\n\n\t\t\t\t// spare 1 byte for '\\0'\n\t\t\t\tassert(n_chars < number_buffer.size() - 1);\n\n\t\t\t\t// jump to the end to generate the string from backward\n\t\t\t\t// so we later avoid reversing the result\n\t\t\t\tbuffer_ptr += n_chars;\n\n\t\t\t\t// Fast int2ascii implementation inspired by \"Fastware\" talk by Andrei Alexandrescu\n\t\t\t\t// See: https://www.youtube.com/watch?v=o4-CwDo2zpg\n\t\t\t\twhile (abs_value >= 100)\n\t\t\t\t{\n\t\t\t\t\tconst auto digits_index = static_cast<unsigned>((abs_value % 100));\n\t\t\t\t\tabs_value /= 100;\n\t\t\t\t\t*(--buffer_ptr) = digits_to_99[digits_index][1];\n\t\t\t\t\t*(--buffer_ptr) = digits_to_99[digits_index][0];\n\t\t\t\t}\n\n\t\t\t\tif (abs_value >= 10)\n\t\t\t\t{\n\t\t\t\t\tconst auto digits_index = static_cast<unsigned>(abs_value);\n\t\t\t\t\t*(--buffer_ptr) = digits_to_99[digits_index][1];\n\t\t\t\t\t*(--buffer_ptr) = digits_to_99[digits_index][0];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t*(--buffer_ptr) = static_cast<char>('0' + abs_value);\n\t\t\t\t}\n\n\t\t\t\to->write_characters(number_buffer.data(), n_chars);\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief dump a floating-point number\n\n\t\t\tDump a given floating-point number to output stream @a o. Works internally\n\t\t\twith @a number_buffer.\n\n\t\t\t@param[in] x  floating-point number to dump\n\t\t\t*/\n\t\t\tvoid dump_float(number_float_t x)\n\t\t\t{\n\t\t\t\t// NaN / inf\n\t\t\t\tif (not std::isfinite(x))\n\t\t\t\t{\n\t\t\t\t\to->write_characters(\"null\", 4);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If number_float_t is an IEEE-754 single or double precision number,\n\t\t\t\t// use the Grisu2 algorithm to produce short numbers which are\n\t\t\t\t// guaranteed to round-trip, using strtof and strtod, resp.\n\t\t\t\t//\n\t\t\t\t// NB: The test below works if <long double> == <double>.\n\t\t\t\tstatic constexpr bool is_ieee_single_or_double\n\t\t\t\t\t= (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or\n\t\t\t\t\t(std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);\n\n\t\t\t\tdump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());\n\t\t\t}\n\n\t\t\tvoid dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)\n\t\t\t{\n\t\t\t\tchar* begin = number_buffer.data();\n\t\t\t\tchar* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);\n\n\t\t\t\to->write_characters(begin, static_cast<size_t>(end - begin));\n\t\t\t}\n\n\t\t\tvoid dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)\n\t\t\t{\n\t\t\t\t// get number of digits for a float -> text -> float round-trip\n\t\t\t\tstatic constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;\n\n\t\t\t\t// the actual conversion\n\t\t\t\tstd::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), \"%.*g\", d, x);\n\n\t\t\t\t// negative value indicates an error\n\t\t\t\tassert(len > 0);\n\t\t\t\t// check if buffer was large enough\n\t\t\t\tassert(static_cast<std::size_t>(len) < number_buffer.size());\n\n\t\t\t\t// erase thousands separator\n\t\t\t\tif (thousands_sep != '\\0')\n\t\t\t\t{\n\t\t\t\t\tconst auto end = std::remove(number_buffer.begin(),\n\t\t\t\t\t\tnumber_buffer.begin() + len, thousands_sep);\n\t\t\t\t\tstd::fill(end, number_buffer.end(), '\\0');\n\t\t\t\t\tassert((end - number_buffer.begin()) <= len);\n\t\t\t\t\tlen = (end - number_buffer.begin());\n\t\t\t\t}\n\n\t\t\t\t// convert decimal point to '.'\n\t\t\t\tif (decimal_point != '\\0' and decimal_point != '.')\n\t\t\t\t{\n\t\t\t\t\tconst auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);\n\t\t\t\t\tif (dec_pos != number_buffer.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t*dec_pos = '.';\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\to->write_characters(number_buffer.data(), static_cast<std::size_t>(len));\n\n\t\t\t\t// determine if need to append \".0\"\n\t\t\t\tconst bool value_is_int_like =\n\t\t\t\t\tstd::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,\n\t\t\t\t\t\t[](char c)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn c == '.' or c == 'e';\n\t\t\t\t\t\t});\n\n\t\t\t\tif (value_is_int_like)\n\t\t\t\t{\n\t\t\t\t\to->write_characters(\".0\", 2);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*!\n\t\t\t@brief check whether a string is UTF-8 encoded\n\n\t\t\tThe function checks each byte of a string whether it is UTF-8 encoded. The\n\t\t\tresult of the check is stored in the @a state parameter. The function must\n\t\t\tbe called initially with state 0 (accept). State 1 means the string must\n\t\t\tbe rejected, because the current byte is not allowed. If the string is\n\t\t\tcompletely processed, but the state is non-zero, the string ended\n\t\t\tprematurely; that is, the last byte indicated more bytes should have\n\t\t\tfollowed.\n\n\t\t\t@param[in,out] state  the state of the decoding\n\t\t\t@param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)\n\t\t\t@param[in] byte       next byte to decode\n\t\t\t@return               new state\n\n\t\t\t@note The function has been edited: a std::array is used.\n\n\t\t\t@copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n\t\t\t@sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n\t\t\t*/\n\t\t\tstatic std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept\n\t\t\t{\n\t\t\t\tstatic const std::array<std::uint8_t, 400> utf8d =\n\t\t\t\t{\n\t\t\t\t\t{\n\t\t\t\t\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F\n\t\t\t\t\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F\n\t\t\t\t\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F\n\t\t\t\t\t\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F\n\t\t\t\t\t\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F\n\t\t\t\t\t\t7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF\n\t\t\t\t\t\t8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF\n\t\t\t\t\t\t0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF\n\t\t\t\t\t\t0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF\n\t\t\t\t\t\t0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0\n\t\t\t\t\t\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2\n\t\t\t\t\t\t1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4\n\t\t\t\t\t\t1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6\n\t\t\t\t\t\t1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst std::uint8_t type = utf8d[byte];\n\n\t\t\t\tcodep = (state != UTF8_ACCEPT)\n\t\t\t\t\t? (byte & 0x3fu) | (codep << 6u)\n\t\t\t\t\t: (0xFFu >> type) & (byte);\n\n\t\t\t\tstate = utf8d[256u + state * 16u + type];\n\t\t\t\treturn state;\n\t\t\t}\n\n\t\tprivate:\n\t\t\t/// the output of the serializer\n\t\t\toutput_adapter_t<char> o = nullptr;\n\n\t\t\t/// a (hopefully) large enough character buffer\n\t\t\tstd::array<char, 64> number_buffer{ {} };\n\n\t\t\t/// the locale\n\t\t\tconst std::lconv* loc = nullptr;\n\t\t\t/// the locale's thousand separator character\n\t\t\tconst char thousands_sep = '\\0';\n\t\t\t/// the locale's decimal point character\n\t\t\tconst char decimal_point = '\\0';\n\n\t\t\t/// string buffer\n\t\t\tstd::array<char, 512> string_buffer{ {} };\n\n\t\t\t/// the indentation character\n\t\t\tconst char indent_char;\n\t\t\t/// the indentation string\n\t\t\tstring_t indent_string;\n\n\t\t\t/// error_handler how to react on decoding errors\n\t\t\tconst error_handler_t error_handler;\n\t\t};\n\t}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n// #include <nlohmann/json_fwd.hpp>\n\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n\n\t/*!\n\t@brief a class to store JSON values\n\n\t@tparam ObjectType type for JSON objects (`std::map` by default; will be used\n\tin @ref object_t)\n\t@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used\n\tin @ref array_t)\n\t@tparam StringType type for JSON strings and object keys (`std::string` by\n\tdefault; will be used in @ref string_t)\n\t@tparam BooleanType type for JSON booleans (`bool` by default; will be used\n\tin @ref boolean_t)\n\t@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by\n\tdefault; will be used in @ref number_integer_t)\n\t@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c\n\t`uint64_t` by default; will be used in @ref number_unsigned_t)\n\t@tparam NumberFloatType type for JSON floating-point numbers (`double` by\n\tdefault; will be used in @ref number_float_t)\n\t@tparam AllocatorType type of the allocator to use (`std::allocator` by\n\tdefault)\n\t@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`\n\tand `from_json()` (@ref adl_serializer by default)\n\n\t@requirement The class satisfies the following concept requirements:\n\t- Basic\n\t - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n\t   JSON values can be default constructed. The result will be a JSON null\n\t   value.\n\t - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):\n\t   A JSON value can be constructed from an rvalue argument.\n\t - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):\n\t   A JSON value can be copy-constructed from an lvalue expression.\n\t - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):\n\t   A JSON value van be assigned from an rvalue argument.\n\t - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):\n\t   A JSON value can be copy-assigned from an lvalue expression.\n\t - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):\n\t   JSON values can be destructed.\n\t- Layout\n\t - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):\n\t   JSON values have\n\t   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):\n\t   All non-static data members are private and standard layout types, the\n\t   class has no virtual functions or (virtual) base classes.\n\t- Library-wide\n\t - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):\n\t   JSON values can be compared with `==`, see @ref\n\t   operator==(const_reference,const_reference).\n\t - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n\t   JSON values can be compared with `<`, see @ref\n\t   operator<(const_reference,const_reference).\n\t - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):\n\t   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of\n\t   other compatible types, using unqualified function call @ref swap().\n\t - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):\n\t   JSON values can be compared against `std::nullptr_t` objects which are used\n\t   to model the `null` value.\n\t- Container\n\t - [Container](https://en.cppreference.com/w/cpp/named_req/Container):\n\t   JSON values can be used like STL containers and provide iterator access.\n\t - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);\n\t   JSON values can be used like STL containers and provide reverse iterator\n\t   access.\n\n\t@invariant The member variables @a m_value and @a m_type have the following\n\trelationship:\n\t- If `m_type == value_t::object`, then `m_value.object != nullptr`.\n\t- If `m_type == value_t::array`, then `m_value.array != nullptr`.\n\t- If `m_type == value_t::string`, then `m_value.string != nullptr`.\n\tThe invariants are checked by member function assert_invariant().\n\n\t@internal\n\t@note ObjectType trick from http://stackoverflow.com/a/9860911\n\t@endinternal\n\n\t@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange\n\tFormat](http://rfc7159.net/rfc7159)\n\n\t@since version 1.0.0\n\n\t@nosubgrouping\n\t*/\n\tNLOHMANN_BASIC_JSON_TPL_DECLARATION\n\t\tclass basic_json\n\t{\n\tprivate:\n\t\ttemplate<detail::value_t> friend struct detail::external_constructor;\n\t\tfriend ::nlohmann::json_pointer<basic_json>;\n\t\tfriend ::nlohmann::detail::parser<basic_json>;\n\t\tfriend ::nlohmann::detail::serializer<basic_json>;\n\t\ttemplate<typename BasicJsonType>\n\t\tfriend class ::nlohmann::detail::iter_impl;\n\t\ttemplate<typename BasicJsonType, typename CharType>\n\t\tfriend class ::nlohmann::detail::binary_writer;\n\t\ttemplate<typename BasicJsonType, typename SAX>\n\t\tfriend class ::nlohmann::detail::binary_reader;\n\t\ttemplate<typename BasicJsonType>\n\t\tfriend class ::nlohmann::detail::json_sax_dom_parser;\n\t\ttemplate<typename BasicJsonType>\n\t\tfriend class ::nlohmann::detail::json_sax_dom_callback_parser;\n\n\t\t/// workaround type for MSVC\n\t\tusing basic_json_t = NLOHMANN_BASIC_JSON_TPL;\n\n\t\t// convenience aliases for types residing in namespace detail;\n\t\tusing lexer = ::nlohmann::detail::lexer<basic_json>;\n\t\tusing parser = ::nlohmann::detail::parser<basic_json>;\n\n\t\tusing primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;\n\t\ttemplate<typename BasicJsonType>\n\t\tusing internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;\n\t\ttemplate<typename BasicJsonType>\n\t\tusing iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;\n\t\ttemplate<typename Iterator>\n\t\tusing iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;\n\t\ttemplate<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;\n\n\t\ttemplate<typename CharType>\n\t\tusing output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;\n\n\t\tusing binary_reader = ::nlohmann::detail::binary_reader<basic_json>;\n\t\ttemplate<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;\n\n\t\tusing serializer = ::nlohmann::detail::serializer<basic_json>;\n\n\tpublic:\n\t\tusing value_t = detail::value_t;\n\t\t/// JSON Pointer, see @ref nlohmann::json_pointer\n\t\tusing json_pointer = ::nlohmann::json_pointer<basic_json>;\n\t\ttemplate<typename T, typename SFINAE>\n\t\tusing json_serializer = JSONSerializer<T, SFINAE>;\n\t\t/// how to treat decoding errors\n\t\tusing error_handler_t = detail::error_handler_t;\n\t\t/// helper type for initializer lists of basic_json values\n\t\tusing initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;\n\n\t\tusing input_format_t = detail::input_format_t;\n\t\t/// SAX interface type, see @ref nlohmann::json_sax\n\t\tusing json_sax_t = json_sax<basic_json>;\n\n\t\t////////////////\n\t\t// exceptions //\n\t\t////////////////\n\n\t\t/// @name exceptions\n\t\t/// Classes to implement user-defined exceptions.\n\t\t/// @{\n\n\t\t/// @copydoc detail::exception\n\t\tusing exception = detail::exception;\n\t\t/// @copydoc detail::parse_error\n\t\tusing parse_error = detail::parse_error;\n\t\t/// @copydoc detail::invalid_iterator\n\t\tusing invalid_iterator = detail::invalid_iterator;\n\t\t/// @copydoc detail::type_error\n\t\tusing type_error = detail::type_error;\n\t\t/// @copydoc detail::out_of_range\n\t\tusing out_of_range = detail::out_of_range;\n\t\t/// @copydoc detail::other_error\n\t\tusing other_error = detail::other_error;\n\n\t\t/// @}\n\n\n\t\t/////////////////////\n\t\t// container types //\n\t\t/////////////////////\n\n\t\t/// @name container types\n\t\t/// The canonic container types to use @ref basic_json like any other STL\n\t\t/// container.\n\t\t/// @{\n\n\t\t/// the type of elements in a basic_json container\n\t\tusing value_type = basic_json;\n\n\t\t/// the type of an element reference\n\t\tusing reference = value_type & ;\n\t\t/// the type of an element const reference\n\t\tusing const_reference = const value_type&;\n\n\t\t/// a type to represent differences between iterators\n\t\tusing difference_type = std::ptrdiff_t;\n\t\t/// a type to represent container sizes\n\t\tusing size_type = std::size_t;\n\n\t\t/// the allocator type\n\t\tusing allocator_type = AllocatorType<basic_json>;\n\n\t\t/// the type of an element pointer\n\t\tusing pointer = typename std::allocator_traits<allocator_type>::pointer;\n\t\t/// the type of an element const pointer\n\t\tusing const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;\n\n\t\t/// an iterator for a basic_json container\n\t\tusing iterator = iter_impl<basic_json>;\n\t\t/// a const iterator for a basic_json container\n\t\tusing const_iterator = iter_impl<const basic_json>;\n\t\t/// a reverse iterator for a basic_json container\n\t\tusing reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;\n\t\t/// a const reverse iterator for a basic_json container\n\t\tusing const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;\n\n\t\t/// @}\n\n\n\t\t/*!\n\t\t@brief returns the allocator associated with the container\n\t\t*/\n\t\tstatic allocator_type get_allocator()\n\t\t{\n\t\t\treturn allocator_type();\n\t\t}\n\n\t\t/*!\n\t\t@brief returns version information on the library\n\n\t\tThis function returns a JSON object with information about the library,\n\t\tincluding the version number and information on the platform and compiler.\n\n\t\t@return JSON object holding version information\n\t\tkey         | description\n\t\t----------- | ---------------\n\t\t`compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).\n\t\t`copyright` | The copyright line for the library as string.\n\t\t`name`      | The name of the library as string.\n\t\t`platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.\n\t\t`url`       | The URL of the project as string.\n\t\t`version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).\n\n\t\t@liveexample{The following code shows an example output of the `meta()`\n\t\tfunction.,meta}\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@since 2.1.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json meta()\n\t\t{\n\t\t\tbasic_json result;\n\n\t\t\tresult[\"copyright\"] = \"(C) 2013-2017 Niels Lohmann\";\n\t\t\tresult[\"name\"] = \"JSON for Modern C++\";\n\t\t\tresult[\"url\"] = \"https://github.com/nlohmann/json\";\n\t\t\tresult[\"version\"][\"string\"] =\n\t\t\t\tstd::to_string(NLOHMANN_JSON_VERSION_MAJOR) + \".\" +\n\t\t\t\tstd::to_string(NLOHMANN_JSON_VERSION_MINOR) + \".\" +\n\t\t\t\tstd::to_string(NLOHMANN_JSON_VERSION_PATCH);\n\t\t\tresult[\"version\"][\"major\"] = NLOHMANN_JSON_VERSION_MAJOR;\n\t\t\tresult[\"version\"][\"minor\"] = NLOHMANN_JSON_VERSION_MINOR;\n\t\t\tresult[\"version\"][\"patch\"] = NLOHMANN_JSON_VERSION_PATCH;\n\n#ifdef _WIN32\n\t\t\tresult[\"platform\"] = \"win32\";\n#elif defined __linux__\n\t\t\tresult[\"platform\"] = \"linux\";\n#elif defined __APPLE__\n\t\t\tresult[\"platform\"] = \"apple\";\n#elif defined __unix__\n\t\t\tresult[\"platform\"] = \"unix\";\n#else\n\t\t\tresult[\"platform\"] = \"unknown\";\n#endif\n\n#if defined(__ICC) || defined(__INTEL_COMPILER)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"icc\"}, {\"version\", __INTEL_COMPILER} };\n#elif defined(__clang__)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"clang\"}, {\"version\", __clang_version__} };\n#elif defined(__GNUC__) || defined(__GNUG__)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"gcc\"}, {\"version\", std::to_string(__GNUC__) + \".\" + std::to_string(__GNUC_MINOR__) + \".\" + std::to_string(__GNUC_PATCHLEVEL__)} };\n#elif defined(__HP_cc) || defined(__HP_aCC)\n\t\t\tresult[\"compiler\"] = \"hp\"\n#elif defined(__IBMCPP__)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"ilecpp\"}, {\"version\", __IBMCPP__} };\n#elif defined(_MSC_VER)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"msvc\"}, {\"version\", _MSC_VER} };\n#elif defined(__PGI)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"pgcpp\"}, {\"version\", __PGI} };\n#elif defined(__SUNPRO_CC)\n\t\t\tresult[\"compiler\"] = { {\"family\", \"sunpro\"}, {\"version\", __SUNPRO_CC} };\n#else\n\t\t\tresult[\"compiler\"] = { {\"family\", \"unknown\"}, {\"version\", \"unknown\"} };\n#endif\n\n#ifdef __cplusplus\n\t\t\tresult[\"compiler\"][\"c++\"] = std::to_string(__cplusplus);\n#else\n\t\t\tresult[\"compiler\"][\"c++\"] = \"unknown\";\n#endif\n\t\t\treturn result;\n\t\t}\n\n\n\t\t///////////////////////////\n\t\t// JSON value data types //\n\t\t///////////////////////////\n\n\t\t/// @name JSON value data types\n\t\t/// The data types to store a JSON value. These types are derived from\n\t\t/// the template arguments passed to class @ref basic_json.\n\t\t/// @{\n\n#if defined(JSON_HAS_CPP_14)\n\t// Use transparent comparator if possible, combined with perfect forwarding\n\t// on find() and count() calls prevents unnecessary string construction.\n\t\tusing object_comparator_t = std::less<>;\n#else\n\t\tusing object_comparator_t = std::less<StringType>;\n#endif\n\n\t\t/*!\n\t\t@brief a type for an object\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:\n\t\t> An object is an unordered collection of zero or more name/value pairs,\n\t\t> where a name is a string and a value is a string, number, boolean, null,\n\t\t> object, or array.\n\n\t\tTo store objects in C++, a type is defined by the template parameters\n\t\tdescribed below.\n\n\t\t@tparam ObjectType  the container to store objects (e.g., `std::map` or\n\t\t`std::unordered_map`)\n\t\t@tparam StringType the type of the keys or names (e.g., `std::string`).\n\t\tThe comparison function `std::less<StringType>` is used to order elements\n\t\tinside the container.\n\t\t@tparam AllocatorType the allocator to use for objects (e.g.,\n\t\t`std::allocator`)\n\n\t\t#### Default type\n\n\t\tWith the default values for @a ObjectType (`std::map`), @a StringType\n\t\t(`std::string`), and @a AllocatorType (`std::allocator`), the default\n\t\tvalue for @a object_t is:\n\n\t\t@code {.cpp}\n\t\tstd::map<\n\t\t  std::string, // key_type\n\t\t  basic_json, // value_type\n\t\t  std::less<std::string>, // key_compare\n\t\t  std::allocator<std::pair<const std::string, basic_json>> // allocator_type\n\t\t>\n\t\t@endcode\n\n\t\t#### Behavior\n\n\t\tThe choice of @a object_t influences the behavior of the JSON class. With\n\t\tthe default type, objects have the following behavior:\n\n\t\t- When all names are unique, objects will be interoperable in the sense\n\t\t  that all software implementations receiving that object will agree on\n\t\t  the name-value mappings.\n\t\t- When the names within an object are not unique, it is unspecified which\n\t\t  one of the values for a given key will be chosen. For instance,\n\t\t  `{\"key\": 2, \"key\": 1}` could be equal to either `{\"key\": 1}` or\n\t\t  `{\"key\": 2}`.\n\t\t- Internally, name/value pairs are stored in lexicographical order of the\n\t\t  names. Objects will also be serialized (see @ref dump) in this order.\n\t\t  For instance, `{\"b\": 1, \"a\": 2}` and `{\"a\": 2, \"b\": 1}` will be stored\n\t\t  and serialized as `{\"a\": 2, \"b\": 1}`.\n\t\t- When comparing objects, the order of the name/value pairs is irrelevant.\n\t\t  This makes objects interoperable in the sense that they will not be\n\t\t  affected by these differences. For instance, `{\"b\": 1, \"a\": 2}` and\n\t\t  `{\"a\": 2, \"b\": 1}` will be treated as equal.\n\n\t\t#### Limits\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) specifies:\n\t\t> An implementation may set limits on the maximum depth of nesting.\n\n\t\tIn this class, the object's limit of nesting is not explicitly constrained.\n\t\tHowever, a maximum depth of nesting may be introduced by the compiler or\n\t\truntime environment. A theoretical limit can be queried by calling the\n\t\t@ref max_size function of a JSON object.\n\n\t\t#### Storage\n\n\t\tObjects are stored as pointers in a @ref basic_json type. That is, for any\n\t\taccess to object values, a pointer of type `object_t*` must be\n\t\tdereferenced.\n\n\t\t@sa @ref array_t -- type for an array value\n\n\t\t@since version 1.0.0\n\n\t\t@note The order name/value pairs are added to the object is *not*\n\t\tpreserved by the library. Therefore, iterating an object may return\n\t\tname/value pairs in a different order than they were originally stored. In\n\t\tfact, keys will be traversed in alphabetical order as `std::map` with\n\t\t`std::less` is used by default. Please note this behavior conforms to [RFC\n\t\t7159](http://rfc7159.net/rfc7159), because any order implements the\n\t\tspecified \"unordered\" nature of JSON objects.\n\t\t*/\n\t\tusing object_t = ObjectType<StringType,\n\t\t\tbasic_json,\n\t\t\tobject_comparator_t,\n\t\t\tAllocatorType<std::pair<const StringType,\n\t\t\tbasic_json>>>;\n\n\t\t/*!\n\t\t@brief a type for an array\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:\n\t\t> An array is an ordered sequence of zero or more values.\n\n\t\tTo store objects in C++, a type is defined by the template parameters\n\t\texplained below.\n\n\t\t@tparam ArrayType  container type to store arrays (e.g., `std::vector` or\n\t\t`std::list`)\n\t\t@tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)\n\n\t\t#### Default type\n\n\t\tWith the default values for @a ArrayType (`std::vector`) and @a\n\t\tAllocatorType (`std::allocator`), the default value for @a array_t is:\n\n\t\t@code {.cpp}\n\t\tstd::vector<\n\t\t  basic_json, // value_type\n\t\t  std::allocator<basic_json> // allocator_type\n\t\t>\n\t\t@endcode\n\n\t\t#### Limits\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) specifies:\n\t\t> An implementation may set limits on the maximum depth of nesting.\n\n\t\tIn this class, the array's limit of nesting is not explicitly constrained.\n\t\tHowever, a maximum depth of nesting may be introduced by the compiler or\n\t\truntime environment. A theoretical limit can be queried by calling the\n\t\t@ref max_size function of a JSON array.\n\n\t\t#### Storage\n\n\t\tArrays are stored as pointers in a @ref basic_json type. That is, for any\n\t\taccess to array values, a pointer of type `array_t*` must be dereferenced.\n\n\t\t@sa @ref object_t -- type for an object value\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tusing array_t = ArrayType<basic_json, AllocatorType<basic_json>>;\n\n\t\t/*!\n\t\t@brief a type for a string\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:\n\t\t> A string is a sequence of zero or more Unicode characters.\n\n\t\tTo store objects in C++, a type is defined by the template parameter\n\t\tdescribed below. Unicode values are split by the JSON class into\n\t\tbyte-sized characters during deserialization.\n\n\t\t@tparam StringType  the container to store strings (e.g., `std::string`).\n\t\tNote this container is used for keys/names in objects, see @ref object_t.\n\n\t\t#### Default type\n\n\t\tWith the default values for @a StringType (`std::string`), the default\n\t\tvalue for @a string_t is:\n\n\t\t@code {.cpp}\n\t\tstd::string\n\t\t@endcode\n\n\t\t#### Encoding\n\n\t\tStrings are stored in UTF-8 encoding. Therefore, functions like\n\t\t`std::string::size()` or `std::string::length()` return the number of\n\t\tbytes in the string rather than the number of characters or glyphs.\n\n\t\t#### String comparison\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) states:\n\t\t> Software implementations are typically required to test names of object\n\t\t> members for equality. Implementations that transform the textual\n\t\t> representation into sequences of Unicode code units and then perform the\n\t\t> comparison numerically, code unit by code unit, are interoperable in the\n\t\t> sense that implementations will agree in all cases on equality or\n\t\t> inequality of two strings. For example, implementations that compare\n\t\t> strings with escaped characters unconverted may incorrectly find that\n\t\t> `\"a\\\\b\"` and `\"a\\u005Cb\"` are not equal.\n\n\t\tThis implementation is interoperable as it does compare strings code unit\n\t\tby code unit.\n\n\t\t#### Storage\n\n\t\tString values are stored as pointers in a @ref basic_json type. That is,\n\t\tfor any access to string values, a pointer of type `string_t*` must be\n\t\tdereferenced.\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tusing string_t = StringType;\n\n\t\t/*!\n\t\t@brief a type for a boolean\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a\n\t\ttype which differentiates the two literals `true` and `false`.\n\n\t\tTo store objects in C++, a type is defined by the template parameter @a\n\t\tBooleanType which chooses the type to use.\n\n\t\t#### Default type\n\n\t\tWith the default values for @a BooleanType (`bool`), the default value for\n\t\t@a boolean_t is:\n\n\t\t@code {.cpp}\n\t\tbool\n\t\t@endcode\n\n\t\t#### Storage\n\n\t\tBoolean values are stored directly inside a @ref basic_json type.\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tusing boolean_t = BooleanType;\n\n\t\t/*!\n\t\t@brief a type for a number (integer)\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n\t\t> The representation of numbers is similar to that used in most\n\t\t> programming languages. A number is represented in base 10 using decimal\n\t\t> digits. It contains an integer component that may be prefixed with an\n\t\t> optional minus sign, which may be followed by a fraction part and/or an\n\t\t> exponent part. Leading zeros are not allowed. (...) Numeric values that\n\t\t> cannot be represented in the grammar below (such as Infinity and NaN)\n\t\t> are not permitted.\n\n\t\tThis description includes both integer and floating-point numbers.\n\t\tHowever, C++ allows more precise storage if it is known whether the number\n\t\tis a signed integer, an unsigned integer or a floating-point number.\n\t\tTherefore, three different types, @ref number_integer_t, @ref\n\t\tnumber_unsigned_t and @ref number_float_t are used.\n\n\t\tTo store integer numbers in C++, a type is defined by the template\n\t\tparameter @a NumberIntegerType which chooses the type to use.\n\n\t\t#### Default type\n\n\t\tWith the default values for @a NumberIntegerType (`int64_t`), the default\n\t\tvalue for @a number_integer_t is:\n\n\t\t@code {.cpp}\n\t\tint64_t\n\t\t@endcode\n\n\t\t#### Default behavior\n\n\t\t- The restrictions about leading zeros is not enforced in C++. Instead,\n\t\t  leading zeros in integer literals lead to an interpretation as octal\n\t\t  number. Internally, the value will be stored as decimal number. For\n\t\t  instance, the C++ integer literal `010` will be serialized to `8`.\n\t\t  During deserialization, leading zeros yield an error.\n\t\t- Not-a-number (NaN) values will be serialized to `null`.\n\n\t\t#### Limits\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) specifies:\n\t\t> An implementation may set limits on the range and precision of numbers.\n\n\t\tWhen the default type is used, the maximal integer number that can be\n\t\tstored is `9223372036854775807` (INT64_MAX) and the minimal integer number\n\t\tthat can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers\n\t\tthat are out of range will yield over/underflow when used in a\n\t\tconstructor. During deserialization, too large or small integer numbers\n\t\twill be automatically be stored as @ref number_unsigned_t or @ref\n\t\tnumber_float_t.\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) further states:\n\t\t> Note that when such software is used, numbers that are integers and are\n\t\t> in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n\t\t> that implementations will agree exactly on their numeric values.\n\n\t\tAs this range is a subrange of the exactly supported range [INT64_MIN,\n\t\tINT64_MAX], this class's integer type is interoperable.\n\n\t\t#### Storage\n\n\t\tInteger number values are stored directly inside a @ref basic_json type.\n\n\t\t@sa @ref number_float_t -- type for number values (floating-point)\n\n\t\t@sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tusing number_integer_t = NumberIntegerType;\n\n\t\t/*!\n\t\t@brief a type for a number (unsigned)\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n\t\t> The representation of numbers is similar to that used in most\n\t\t> programming languages. A number is represented in base 10 using decimal\n\t\t> digits. It contains an integer component that may be prefixed with an\n\t\t> optional minus sign, which may be followed by a fraction part and/or an\n\t\t> exponent part. Leading zeros are not allowed. (...) Numeric values that\n\t\t> cannot be represented in the grammar below (such as Infinity and NaN)\n\t\t> are not permitted.\n\n\t\tThis description includes both integer and floating-point numbers.\n\t\tHowever, C++ allows more precise storage if it is known whether the number\n\t\tis a signed integer, an unsigned integer or a floating-point number.\n\t\tTherefore, three different types, @ref number_integer_t, @ref\n\t\tnumber_unsigned_t and @ref number_float_t are used.\n\n\t\tTo store unsigned integer numbers in C++, a type is defined by the\n\t\ttemplate parameter @a NumberUnsignedType which chooses the type to use.\n\n\t\t#### Default type\n\n\t\tWith the default values for @a NumberUnsignedType (`uint64_t`), the\n\t\tdefault value for @a number_unsigned_t is:\n\n\t\t@code {.cpp}\n\t\tuint64_t\n\t\t@endcode\n\n\t\t#### Default behavior\n\n\t\t- The restrictions about leading zeros is not enforced in C++. Instead,\n\t\t  leading zeros in integer literals lead to an interpretation as octal\n\t\t  number. Internally, the value will be stored as decimal number. For\n\t\t  instance, the C++ integer literal `010` will be serialized to `8`.\n\t\t  During deserialization, leading zeros yield an error.\n\t\t- Not-a-number (NaN) values will be serialized to `null`.\n\n\t\t#### Limits\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) specifies:\n\t\t> An implementation may set limits on the range and precision of numbers.\n\n\t\tWhen the default type is used, the maximal integer number that can be\n\t\tstored is `18446744073709551615` (UINT64_MAX) and the minimal integer\n\t\tnumber that can be stored is `0`. Integer numbers that are out of range\n\t\twill yield over/underflow when used in a constructor. During\n\t\tdeserialization, too large or small integer numbers will be automatically\n\t\tbe stored as @ref number_integer_t or @ref number_float_t.\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) further states:\n\t\t> Note that when such software is used, numbers that are integers and are\n\t\t> in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n\t\t> that implementations will agree exactly on their numeric values.\n\n\t\tAs this range is a subrange (when considered in conjunction with the\n\t\tnumber_integer_t type) of the exactly supported range [0, UINT64_MAX],\n\t\tthis class's integer type is interoperable.\n\n\t\t#### Storage\n\n\t\tInteger number values are stored directly inside a @ref basic_json type.\n\n\t\t@sa @ref number_float_t -- type for number values (floating-point)\n\t\t@sa @ref number_integer_t -- type for number values (integer)\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tusing number_unsigned_t = NumberUnsignedType;\n\n\t\t/*!\n\t\t@brief a type for a number (floating-point)\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n\t\t> The representation of numbers is similar to that used in most\n\t\t> programming languages. A number is represented in base 10 using decimal\n\t\t> digits. It contains an integer component that may be prefixed with an\n\t\t> optional minus sign, which may be followed by a fraction part and/or an\n\t\t> exponent part. Leading zeros are not allowed. (...) Numeric values that\n\t\t> cannot be represented in the grammar below (such as Infinity and NaN)\n\t\t> are not permitted.\n\n\t\tThis description includes both integer and floating-point numbers.\n\t\tHowever, C++ allows more precise storage if it is known whether the number\n\t\tis a signed integer, an unsigned integer or a floating-point number.\n\t\tTherefore, three different types, @ref number_integer_t, @ref\n\t\tnumber_unsigned_t and @ref number_float_t are used.\n\n\t\tTo store floating-point numbers in C++, a type is defined by the template\n\t\tparameter @a NumberFloatType which chooses the type to use.\n\n\t\t#### Default type\n\n\t\tWith the default values for @a NumberFloatType (`double`), the default\n\t\tvalue for @a number_float_t is:\n\n\t\t@code {.cpp}\n\t\tdouble\n\t\t@endcode\n\n\t\t#### Default behavior\n\n\t\t- The restrictions about leading zeros is not enforced in C++. Instead,\n\t\t  leading zeros in floating-point literals will be ignored. Internally,\n\t\t  the value will be stored as decimal number. For instance, the C++\n\t\t  floating-point literal `01.2` will be serialized to `1.2`. During\n\t\t  deserialization, leading zeros yield an error.\n\t\t- Not-a-number (NaN) values will be serialized to `null`.\n\n\t\t#### Limits\n\n\t\t[RFC 7159](http://rfc7159.net/rfc7159) states:\n\t\t> This specification allows implementations to set limits on the range and\n\t\t> precision of numbers accepted. Since software that implements IEEE\n\t\t> 754-2008 binary64 (double precision) numbers is generally available and\n\t\t> widely used, good interoperability can be achieved by implementations\n\t\t> that expect no more precision or range than these provide, in the sense\n\t\t> that implementations will approximate JSON numbers within the expected\n\t\t> precision.\n\n\t\tThis implementation does exactly follow this approach, as it uses double\n\t\tprecision floating-point numbers. Note values smaller than\n\t\t`-1.79769313486232e+308` and values greater than `1.79769313486232e+308`\n\t\twill be stored as NaN internally and be serialized to `null`.\n\n\t\t#### Storage\n\n\t\tFloating-point number values are stored directly inside a @ref basic_json\n\t\ttype.\n\n\t\t@sa @ref number_integer_t -- type for number values (integer)\n\n\t\t@sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tusing number_float_t = NumberFloatType;\n\n\t\t/// @}\n\n\tprivate:\n\n\t\t/// helper for exception-safe object creation\n\t\ttemplate<typename T, typename... Args>\n\t\tstatic T* create(Args&& ... args)\n\t\t{\n\t\t\tAllocatorType<T> alloc;\n\t\t\tusing AllocatorTraits = std::allocator_traits<AllocatorType<T>>;\n\n\t\t\tauto deleter = [&](T * object)\n\t\t\t{\n\t\t\t\tAllocatorTraits::deallocate(alloc, object, 1);\n\t\t\t};\n\t\t\tstd::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);\n\t\t\tAllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);\n\t\t\tassert(object != nullptr);\n\t\t\treturn object.release();\n\t\t}\n\n\t\t////////////////////////\n\t\t// JSON value storage //\n\t\t////////////////////////\n\n\t\t/*!\n\t\t@brief a JSON value\n\n\t\tThe actual storage for a JSON value of the @ref basic_json class. This\n\t\tunion combines the different storage types for the JSON value types\n\t\tdefined in @ref value_t.\n\n\t\tJSON type | value_t type    | used type\n\t\t--------- | --------------- | ------------------------\n\t\tobject    | object          | pointer to @ref object_t\n\t\tarray     | array           | pointer to @ref array_t\n\t\tstring    | string          | pointer to @ref string_t\n\t\tboolean   | boolean         | @ref boolean_t\n\t\tnumber    | number_integer  | @ref number_integer_t\n\t\tnumber    | number_unsigned | @ref number_unsigned_t\n\t\tnumber    | number_float    | @ref number_float_t\n\t\tnull      | null            | *no value is stored*\n\n\t\t@note Variable-length types (objects, arrays, and strings) are stored as\n\t\tpointers. The size of the union should not exceed 64 bits if the default\n\t\tvalue types are used.\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tunion json_value\n\t\t{\n\t\t\t/// object (stored with pointer to save storage)\n\t\t\tobject_t* object;\n\t\t\t/// array (stored with pointer to save storage)\n\t\t\tarray_t* array;\n\t\t\t/// string (stored with pointer to save storage)\n\t\t\tstring_t* string;\n\t\t\t/// boolean\n\t\t\tboolean_t boolean;\n\t\t\t/// number (integer)\n\t\t\tnumber_integer_t number_integer;\n\t\t\t/// number (unsigned integer)\n\t\t\tnumber_unsigned_t number_unsigned;\n\t\t\t/// number (floating-point)\n\t\t\tnumber_float_t number_float;\n\n\t\t\t/// default constructor (for null values)\n\t\t\tjson_value() = default;\n\t\t\t/// constructor for booleans\n\t\t\tjson_value(boolean_t v) noexcept : boolean(v) {}\n\t\t\t/// constructor for numbers (integer)\n\t\t\tjson_value(number_integer_t v) noexcept : number_integer(v) {}\n\t\t\t/// constructor for numbers (unsigned)\n\t\t\tjson_value(number_unsigned_t v) noexcept : number_unsigned(v) {}\n\t\t\t/// constructor for numbers (floating-point)\n\t\t\tjson_value(number_float_t v) noexcept : number_float(v) {}\n\t\t\t/// constructor for empty values of a given type\n\t\t\tjson_value(value_t t)\n\t\t\t{\n\t\t\t\tswitch (t)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tobject = create<object_t>();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tarray = create<array_t>();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t{\n\t\t\t\t\tstring = create<string_t>(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t{\n\t\t\t\t\tboolean = boolean_t(false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t{\n\t\t\t\t\tnumber_integer = number_integer_t(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t{\n\t\t\t\t\tnumber_unsigned = number_unsigned_t(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t{\n\t\t\t\t\tnumber_float = number_float_t(0.0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t{\n\t\t\t\t\tobject = nullptr;  // silence warning, see #821\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tobject = nullptr;  // silence warning, see #821\n\t\t\t\t\tif (JSON_UNLIKELY(t == value_t::null))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(other_error::create(500, \"961c151d2e87f2686a955a9be24d316f1362bf21 3.6.1\")); // LCOV_EXCL_LINE\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// constructor for strings\n\t\t\tjson_value(const string_t& value)\n\t\t\t{\n\t\t\t\tstring = create<string_t>(value);\n\t\t\t}\n\n\t\t\t/// constructor for rvalue strings\n\t\t\tjson_value(string_t&& value)\n\t\t\t{\n\t\t\t\tstring = create<string_t>(std::move(value));\n\t\t\t}\n\n\t\t\t/// constructor for objects\n\t\t\tjson_value(const object_t& value)\n\t\t\t{\n\t\t\t\tobject = create<object_t>(value);\n\t\t\t}\n\n\t\t\t/// constructor for rvalue objects\n\t\t\tjson_value(object_t&& value)\n\t\t\t{\n\t\t\t\tobject = create<object_t>(std::move(value));\n\t\t\t}\n\n\t\t\t/// constructor for arrays\n\t\t\tjson_value(const array_t& value)\n\t\t\t{\n\t\t\t\tarray = create<array_t>(value);\n\t\t\t}\n\n\t\t\t/// constructor for rvalue arrays\n\t\t\tjson_value(array_t&& value)\n\t\t\t{\n\t\t\t\tarray = create<array_t>(std::move(value));\n\t\t\t}\n\n\t\t\tvoid destroy(value_t t) noexcept\n\t\t\t{\n\t\t\t\tswitch (t)\n\t\t\t\t{\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\tAllocatorType<object_t> alloc;\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::destroy(alloc, object);\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tAllocatorType<array_t> alloc;\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::destroy(alloc, array);\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t{\n\t\t\t\t\tAllocatorType<string_t> alloc;\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::destroy(alloc, string);\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/*!\n\t\t@brief checks the class invariants\n\n\t\tThis function asserts the class invariants. It needs to be called at the\n\t\tend of every constructor to make sure that created objects respect the\n\t\tinvariant. Furthermore, it has to be called each time the type of a JSON\n\t\tvalue is changed, because the invariant expresses a relationship between\n\t\t@a m_type and @a m_value.\n\t\t*/\n\t\tvoid assert_invariant() const noexcept\n\t\t{\n\t\t\tassert(m_type != value_t::object or m_value.object != nullptr);\n\t\t\tassert(m_type != value_t::array or m_value.array != nullptr);\n\t\t\tassert(m_type != value_t::string or m_value.string != nullptr);\n\t\t}\n\n\tpublic:\n\t\t//////////////////////////\n\t\t// JSON parser callback //\n\t\t//////////////////////////\n\n\t\t/*!\n\t\t@brief parser event types\n\n\t\tThe parser callback distinguishes the following events:\n\t\t- `object_start`: the parser read `{` and started to process a JSON object\n\t\t- `key`: the parser read a key of a value in an object\n\t\t- `object_end`: the parser read `}` and finished processing a JSON object\n\t\t- `array_start`: the parser read `[` and started to process a JSON array\n\t\t- `array_end`: the parser read `]` and finished processing a JSON array\n\t\t- `value`: the parser finished reading a JSON value\n\n\t\t@image html callback_events.png \"Example when certain parse events are triggered\"\n\n\t\t@sa @ref parser_callback_t for more information and examples\n\t\t*/\n\t\tusing parse_event_t = typename parser::parse_event_t;\n\n\t\t/*!\n\t\t@brief per-element parser callback type\n\n\t\tWith a parser callback function, the result of parsing a JSON text can be\n\t\tinfluenced. When passed to @ref parse, it is called on certain events\n\t\t(passed as @ref parse_event_t via parameter @a event) with a set recursion\n\t\tdepth @a depth and context JSON value @a parsed. The return value of the\n\t\tcallback function is a boolean indicating whether the element that emitted\n\t\tthe callback shall be kept or not.\n\n\t\tWe distinguish six scenarios (determined by the event type) in which the\n\t\tcallback function can be called. The following table describes the values\n\t\tof the parameters @a depth, @a event, and @a parsed.\n\n\t\tparameter @a event | description | parameter @a depth | parameter @a parsed\n\t\t------------------ | ----------- | ------------------ | -------------------\n\t\tparse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded\n\t\tparse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key\n\t\tparse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object\n\t\tparse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded\n\t\tparse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array\n\t\tparse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value\n\n\t\t@image html callback_events.png \"Example when certain parse events are triggered\"\n\n\t\tDiscarding a value (i.e., returning `false`) has different effects\n\t\tdepending on the context in which function was called:\n\n\t\t- Discarded values in structured types are skipped. That is, the parser\n\t\t  will behave as if the discarded value was never read.\n\t\t- In case a value outside a structured type is skipped, it is replaced\n\t\t  with `null`. This case happens if the top-level element is skipped.\n\n\t\t@param[in] depth  the depth of the recursion during parsing\n\n\t\t@param[in] event  an event of type parse_event_t indicating the context in\n\t\tthe callback function has been called\n\n\t\t@param[in,out] parsed  the current intermediate parse result; note that\n\t\twriting to this value has no effect for parse_event_t::key events\n\n\t\t@return Whether the JSON value which called the function during parsing\n\t\tshould be kept (`true`) or not (`false`). In the latter case, it is either\n\t\tskipped completely or replaced by an empty discarded object.\n\n\t\t@sa @ref parse for examples\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tusing parser_callback_t = typename parser::parser_callback_t;\n\n\t\t//////////////////\n\t\t// constructors //\n\t\t//////////////////\n\n\t\t/// @name constructors and destructors\n\t\t/// Constructors of class @ref basic_json, copy/move constructor, copy\n\t\t/// assignment, static functions creating objects, and the destructor.\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief create an empty value with a given type\n\n\t\tCreate an empty JSON value with a given type. The value will be default\n\t\tinitialized with an empty value which depends on the type:\n\n\t\tValue type  | initial value\n\t\t----------- | -------------\n\t\tnull        | `null`\n\t\tboolean     | `false`\n\t\tstring      | `\"\"`\n\t\tnumber      | `0`\n\t\tobject      | `{}`\n\t\tarray       | `[]`\n\n\t\t@param[in] v  the type of the value to create\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@liveexample{The following code shows the constructor for different @ref\n\t\tvalue_t values,basic_json__value_t}\n\n\t\t@sa @ref clear() -- restores the postcondition of this constructor\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json(const value_t v)\n\t\t\t: m_type(v), m_value(v)\n\t\t{\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief create a null object\n\n\t\tCreate a `null` JSON value. It either takes a null pointer as parameter\n\t\t(explicitly creating `null`) or no parameter (implicitly creating `null`).\n\t\tThe passed null pointer itself is not read -- it is only used to choose\n\t\tthe right constructor.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this constructor never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code shows the constructor with and without a\n\t\tnull pointer parameter.,basic_json__nullptr_t}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json(std::nullptr_t = nullptr) noexcept\n\t\t\t: basic_json(value_t::null)\n\t\t{\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief create a JSON value\n\n\t\tThis is a \"catch all\" constructor for all compatible JSON types; that is,\n\t\ttypes for which a `to_json()` method exists. The constructor forwards the\n\t\tparameter @a val to that method (to `json_serializer<U>::to_json` method\n\t\twith `U = uncvref_t<CompatibleType>`, to be exact).\n\n\t\tTemplate type @a CompatibleType includes, but is not limited to, the\n\t\tfollowing types:\n\t\t- **arrays**: @ref array_t and all kinds of compatible containers such as\n\t\t  `std::vector`, `std::deque`, `std::list`, `std::forward_list`,\n\t\t  `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,\n\t\t  `std::multiset`, and `std::unordered_multiset` with a `value_type` from\n\t\t  which a @ref basic_json value can be constructed.\n\t\t- **objects**: @ref object_t and all kinds of compatible associative\n\t\t  containers such as `std::map`, `std::unordered_map`, `std::multimap`,\n\t\t  and `std::unordered_multimap` with a `key_type` compatible to\n\t\t  @ref string_t and a `value_type` from which a @ref basic_json value can\n\t\t  be constructed.\n\t\t- **strings**: @ref string_t, string literals, and all compatible string\n\t\t  containers can be used.\n\t\t- **numbers**: @ref number_integer_t, @ref number_unsigned_t,\n\t\t  @ref number_float_t, and all convertible number types such as `int`,\n\t\t  `size_t`, `int64_t`, `float` or `double` can be used.\n\t\t- **boolean**: @ref boolean_t / `bool` can be used.\n\n\t\tSee the examples below.\n\n\t\t@tparam CompatibleType a type such that:\n\t\t- @a CompatibleType is not derived from `std::istream`,\n\t\t- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move\n\t\t\t constructors),\n\t\t- @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)\n\t\t- @a CompatibleType is not a @ref basic_json nested type (e.g.,\n\t\t\t @ref json_pointer, @ref iterator, etc ...)\n\t\t- @ref @ref json_serializer<U> has a\n\t\t\t `to_json(basic_json_t&, CompatibleType&&)` method\n\n\t\t@tparam U = `uncvref_t<CompatibleType>`\n\n\t\t@param[in] val the value to be forwarded to the respective constructor\n\n\t\t@complexity Usually linear in the size of the passed @a val, also\n\t\t\t\t\tdepending on the implementation of the called `to_json()`\n\t\t\t\t\tmethod.\n\n\t\t@exceptionsafety Depends on the called constructor. For types directly\n\t\tsupported by the library (i.e., all types for which no `to_json()` function\n\t\twas provided), strong guarantee holds: if an exception is thrown, there are\n\t\tno changes to any JSON value.\n\n\t\t@liveexample{The following code shows the constructor with several\n\t\tcompatible types.,basic_json__CompatibleType}\n\n\t\t@since version 2.1.0\n\t\t*/\n\t\ttemplate <typename CompatibleType,\n\t\t\ttypename U = detail::uncvref_t<CompatibleType>,\n\t\t\tdetail::enable_if_t<\n\t\t\tnot detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>\n\t\t\tbasic_json(CompatibleType && val) noexcept(noexcept(\n\t\t\t\tJSONSerializer<U>::to_json(std::declval<basic_json_t&>(),\n\t\t\t\t\tstd::forward<CompatibleType>(val))))\n\t\t{\n\t\t\tJSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief create a JSON value from an existing one\n\n\t\tThis is a constructor for existing @ref basic_json types.\n\t\tIt does not hijack copy/move constructors, since the parameter has different\n\t\ttemplate arguments than the current ones.\n\n\t\tThe constructor tries to convert the internal @ref m_value of the parameter.\n\n\t\t@tparam BasicJsonType a type such that:\n\t\t- @a BasicJsonType is a @ref basic_json type.\n\t\t- @a BasicJsonType has different template arguments than @ref basic_json_t.\n\n\t\t@param[in] val the @ref basic_json value to be converted.\n\n\t\t@complexity Usually linear in the size of the passed @a val, also\n\t\t\t\t\tdepending on the implementation of the called `to_json()`\n\t\t\t\t\tmethod.\n\n\t\t@exceptionsafety Depends on the called constructor. For types directly\n\t\tsupported by the library (i.e., all types for which no `to_json()` function\n\t\twas provided), strong guarantee holds: if an exception is thrown, there are\n\t\tno changes to any JSON value.\n\n\t\t@since version 3.2.0\n\t\t*/\n\t\ttemplate <typename BasicJsonType,\n\t\t\tdetail::enable_if_t<\n\t\t\tdetail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>\n\t\t\tbasic_json(const BasicJsonType& val)\n\t\t{\n\t\t\tusing other_boolean_t = typename BasicJsonType::boolean_t;\n\t\t\tusing other_number_float_t = typename BasicJsonType::number_float_t;\n\t\t\tusing other_number_integer_t = typename BasicJsonType::number_integer_t;\n\t\t\tusing other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n\t\t\tusing other_string_t = typename BasicJsonType::string_t;\n\t\t\tusing other_object_t = typename BasicJsonType::object_t;\n\t\t\tusing other_array_t = typename BasicJsonType::array_t;\n\n\t\t\tswitch (val.type())\n\t\t\t{\n\t\t\tcase value_t::boolean:\n\t\t\t\tJSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::number_float:\n\t\t\t\tJSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::number_integer:\n\t\t\t\tJSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::number_unsigned:\n\t\t\t\tJSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::string:\n\t\t\t\tJSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::object:\n\t\t\t\tJSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::array:\n\t\t\t\tJSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());\n\t\t\t\tbreak;\n\t\t\tcase value_t::null:\n\t\t\t\t*this = nullptr;\n\t\t\t\tbreak;\n\t\t\tcase value_t::discarded:\n\t\t\t\tm_type = value_t::discarded;\n\t\t\t\tbreak;\n\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t}\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief create a container (array or object) from an initializer list\n\n\t\tCreates a JSON value of type array or object from the passed initializer\n\t\tlist @a init. In case @a type_deduction is `true` (default), the type of\n\t\tthe JSON value to be created is deducted from the initializer list @a init\n\t\taccording to the following rules:\n\n\t\t1. If the list is empty, an empty JSON object value `{}` is created.\n\t\t2. If the list consists of pairs whose first element is a string, a JSON\n\t\t   object value is created where the first elements of the pairs are\n\t\t   treated as keys and the second elements are as values.\n\t\t3. In all other cases, an array is created.\n\n\t\tThe rules aim to create the best fit between a C++ initializer list and\n\t\tJSON values. The rationale is as follows:\n\n\t\t1. The empty initializer list is written as `{}` which is exactly an empty\n\t\t   JSON object.\n\t\t2. C++ has no way of describing mapped types other than to list a list of\n\t\t   pairs. As JSON requires that keys must be of type string, rule 2 is the\n\t\t   weakest constraint one can pose on initializer lists to interpret them\n\t\t   as an object.\n\t\t3. In all other cases, the initializer list could not be interpreted as\n\t\t   JSON object type, so interpreting it as JSON array type is safe.\n\n\t\tWith the rules described above, the following JSON values cannot be\n\t\texpressed by an initializer list:\n\n\t\t- the empty array (`[]`): use @ref array(initializer_list_t)\n\t\t  with an empty initializer list in this case\n\t\t- arrays whose elements satisfy rule 2: use @ref\n\t\t  array(initializer_list_t) with the same initializer list\n\t\t  in this case\n\n\t\t@note When used without parentheses around an empty initializer list, @ref\n\t\tbasic_json() is called instead of this function, yielding the JSON null\n\t\tvalue.\n\n\t\t@param[in] init  initializer list with JSON values\n\n\t\t@param[in] type_deduction internal parameter; when set to `true`, the type\n\t\tof the JSON value is deducted from the initializer list @a init; when set\n\t\tto `false`, the type provided via @a manual_type is forced. This mode is\n\t\tused by the functions @ref array(initializer_list_t) and\n\t\t@ref object(initializer_list_t).\n\n\t\t@param[in] manual_type internal parameter; when @a type_deduction is set\n\t\tto `false`, the created JSON value will use the provided type (only @ref\n\t\tvalue_t::array and @ref value_t::object are valid); when @a type_deduction\n\t\tis set to `true`, this parameter has no effect\n\n\t\t@throw type_error.301 if @a type_deduction is `false`, @a manual_type is\n\t\t`value_t::object`, but @a init contains an element which is not a pair\n\t\twhose first element is a string. In this case, the constructor could not\n\t\tcreate an object. If @a type_deduction would have be `true`, an array\n\t\twould have been created. See @ref object(initializer_list_t)\n\t\tfor an example.\n\n\t\t@complexity Linear in the size of the initializer list @a init.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@liveexample{The example below shows how JSON values are created from\n\t\tinitializer lists.,basic_json__list_init_t}\n\n\t\t@sa @ref array(initializer_list_t) -- create a JSON array\n\t\tvalue from an initializer list\n\t\t@sa @ref object(initializer_list_t) -- create a JSON object\n\t\tvalue from an initializer list\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json(initializer_list_t init,\n\t\t\tbool type_deduction = true,\n\t\t\tvalue_t manual_type = value_t::array)\n\t\t{\n\t\t\t// check if each element is an array with two elements whose first\n\t\t\t// element is a string\n\t\t\tbool is_an_object = std::all_of(init.begin(), init.end(),\n\t\t\t\t[](const detail::json_ref<basic_json>& element_ref)\n\t\t\t\t{\n\t\t\t\t\treturn element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string();\n\t\t\t\t});\n\n\t\t\t// adjust type if type deduction is not wanted\n\t\t\tif (not type_deduction)\n\t\t\t{\n\t\t\t\t// if array is wanted, do not create an object though possible\n\t\t\t\tif (manual_type == value_t::array)\n\t\t\t\t{\n\t\t\t\t\tis_an_object = false;\n\t\t\t\t}\n\n\t\t\t\t// if object is wanted but impossible, throw an exception\n\t\t\t\tif (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(type_error::create(301, \"cannot create object from initializer list\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (is_an_object)\n\t\t\t{\n\t\t\t\t// the initializer list is a list of pairs -> create object\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value = value_t::object;\n\n\t\t\t\tstd::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto element = element_ref.moved_or_copied();\n\t\t\t\t\t\tm_value.object->emplace(\n\t\t\t\t\t\t\tstd::move(*((*element.m_value.array)[0].m_value.string)),\n\t\t\t\t\t\t\tstd::move((*element.m_value.array)[1]));\n\t\t\t\t\t});\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the initializer list describes an array -> create array\n\t\t\t\tm_type = value_t::array;\n\t\t\t\tm_value.array = create<array_t>(init.begin(), init.end());\n\t\t\t}\n\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief explicitly create an array from an initializer list\n\n\t\tCreates a JSON array value from a given initializer list. That is, given a\n\t\tlist of values `a, b, c`, creates the JSON value `[a, b, c]`. If the\n\t\tinitializer list is empty, the empty array `[]` is created.\n\n\t\t@note This function is only needed to express two edge cases that cannot\n\t\tbe realized with the initializer list constructor (@ref\n\t\tbasic_json(initializer_list_t, bool, value_t)). These cases\n\t\tare:\n\t\t1. creating an array whose elements are all pairs whose first element is a\n\t\tstring -- in this case, the initializer list constructor would create an\n\t\tobject, taking the first elements as keys\n\t\t2. creating an empty array -- passing the empty initializer list to the\n\t\tinitializer list constructor yields an empty object\n\n\t\t@param[in] init  initializer list with JSON values to create an array from\n\t\t(optional)\n\n\t\t@return JSON array value\n\n\t\t@complexity Linear in the size of @a init.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@liveexample{The following code shows an example for the `array`\n\t\tfunction.,array}\n\n\t\t@sa @ref basic_json(initializer_list_t, bool, value_t) --\n\t\tcreate a JSON value from an initializer list\n\t\t@sa @ref object(initializer_list_t) -- create a JSON object\n\t\tvalue from an initializer list\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json array(initializer_list_t init = {})\n\t\t{\n\t\t\treturn basic_json(init, false, value_t::array);\n\t\t}\n\n\t\t/*!\n\t\t@brief explicitly create an object from an initializer list\n\n\t\tCreates a JSON object value from a given initializer list. The initializer\n\t\tlists elements must be pairs, and their first elements must be strings. If\n\t\tthe initializer list is empty, the empty object `{}` is created.\n\n\t\t@note This function is only added for symmetry reasons. In contrast to the\n\t\trelated function @ref array(initializer_list_t), there are\n\t\tno cases which can only be expressed by this function. That is, any\n\t\tinitializer list @a init can also be passed to the initializer list\n\t\tconstructor @ref basic_json(initializer_list_t, bool, value_t).\n\n\t\t@param[in] init  initializer list to create an object from (optional)\n\n\t\t@return JSON object value\n\n\t\t@throw type_error.301 if @a init is not a list of pairs whose first\n\t\telements are strings. In this case, no object can be created. When such a\n\t\tvalue is passed to @ref basic_json(initializer_list_t, bool, value_t),\n\t\tan array would have been created from the passed initializer list @a init.\n\t\tSee example below.\n\n\t\t@complexity Linear in the size of @a init.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@liveexample{The following code shows an example for the `object`\n\t\tfunction.,object}\n\n\t\t@sa @ref basic_json(initializer_list_t, bool, value_t) --\n\t\tcreate a JSON value from an initializer list\n\t\t@sa @ref array(initializer_list_t) -- create a JSON array\n\t\tvalue from an initializer list\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json object(initializer_list_t init = {})\n\t\t{\n\t\t\treturn basic_json(init, false, value_t::object);\n\t\t}\n\n\t\t/*!\n\t\t@brief construct an array with count copies of given value\n\n\t\tConstructs a JSON array value by creating @a cnt copies of a passed value.\n\t\tIn case @a cnt is `0`, an empty array is created.\n\n\t\t@param[in] cnt  the number of JSON copies of @a val to create\n\t\t@param[in] val  the JSON value to copy\n\n\t\t@post `std::distance(begin(),end()) == cnt` holds.\n\n\t\t@complexity Linear in @a cnt.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@liveexample{The following code shows examples for the @ref\n\t\tbasic_json(size_type\\, const basic_json&)\n\t\tconstructor.,basic_json__size_type_basic_json}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json(size_type cnt, const basic_json& val)\n\t\t\t: m_type(value_t::array)\n\t\t{\n\t\t\tm_value.array = create<array_t>(cnt, val);\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief construct a JSON container given an iterator range\n\n\t\tConstructs the JSON value with the contents of the range `[first, last)`.\n\t\tThe semantics depends on the different types a JSON value can have:\n\t\t- In case of a null type, invalid_iterator.206 is thrown.\n\t\t- In case of other primitive types (number, boolean, or string), @a first\n\t\t  must be `begin()` and @a last must be `end()`. In this case, the value is\n\t\t  copied. Otherwise, invalid_iterator.204 is thrown.\n\t\t- In case of structured types (array, object), the constructor behaves as\n\t\t  similar versions for `std::vector` or `std::map`; that is, a JSON array\n\t\t  or object is constructed from the values in the range.\n\n\t\t@tparam InputIT an input iterator type (@ref iterator or @ref\n\t\tconst_iterator)\n\n\t\t@param[in] first begin of the range to copy from (included)\n\t\t@param[in] last end of the range to copy from (excluded)\n\n\t\t@pre Iterators @a first and @a last must be initialized. **This\n\t\t\t precondition is enforced with an assertion (see warning).** If\n\t\t\t assertions are switched off, a violation of this precondition yields\n\t\t\t undefined behavior.\n\n\t\t@pre Range `[first, last)` is valid. Usually, this precondition cannot be\n\t\t\t checked efficiently. Only certain edge cases are detected; see the\n\t\t\t description of the exceptions below. A violation of this precondition\n\t\t\t yields undefined behavior.\n\n\t\t@warning A precondition is enforced with a runtime assertion that will\n\t\t\t\t result in calling `std::abort` if this precondition is not met.\n\t\t\t\t Assertions can be disabled by defining `NDEBUG` at compile time.\n\t\t\t\t See https://en.cppreference.com/w/cpp/error/assert for more\n\t\t\t\t information.\n\n\t\t@throw invalid_iterator.201 if iterators @a first and @a last are not\n\t\tcompatible (i.e., do not belong to the same JSON value). In this case,\n\t\tthe range `[first, last)` is undefined.\n\t\t@throw invalid_iterator.204 if iterators @a first and @a last belong to a\n\t\tprimitive type (number, boolean, or string), but @a first does not point\n\t\tto the first element any more. In this case, the range `[first, last)` is\n\t\tundefined. See example code below.\n\t\t@throw invalid_iterator.206 if iterators @a first and @a last belong to a\n\t\tnull value. In this case, the range `[first, last)` is undefined.\n\n\t\t@complexity Linear in distance between @a first and @a last.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@liveexample{The example below shows several ways to create JSON values by\n\t\tspecifying a subrange with iterators.,basic_json__InputIt_InputIt}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<class InputIT, typename std::enable_if<\n\t\t\tstd::is_same<InputIT, typename basic_json_t::iterator>::value or\n\t\t\tstd::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>\n\t\t\tbasic_json(InputIT first, InputIT last)\n\t\t{\n\t\t\tassert(first.m_object != nullptr);\n\t\t\tassert(last.m_object != nullptr);\n\n\t\t\t// make sure iterator fits the current value\n\t\t\tif (JSON_UNLIKELY(first.m_object != last.m_object))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(201, \"iterators are not compatible\"));\n\t\t\t}\n\n\t\t\t// copy type from first iterator\n\t\t\tm_type = first.m_object->m_type;\n\n\t\t\t// check if iterator range is complete for primitive values\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::boolean:\n\t\t\tcase value_t::number_float:\n\t\t\tcase value_t::number_integer:\n\t\t\tcase value_t::number_unsigned:\n\t\t\tcase value_t::string:\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin()\n\t\t\t\t\tor not last.m_it.primitive_iterator.is_end()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::number_integer:\n\t\t\t{\n\t\t\t\tm_value.number_integer = first.m_object->m_value.number_integer;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_unsigned:\n\t\t\t{\n\t\t\t\tm_value.number_unsigned = first.m_object->m_value.number_unsigned;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_float:\n\t\t\t{\n\t\t\t\tm_value.number_float = first.m_object->m_value.number_float;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::boolean:\n\t\t\t{\n\t\t\t\tm_value.boolean = first.m_object->m_value.boolean;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::string:\n\t\t\t{\n\t\t\t\tm_value = *first.m_object->m_value.string;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\tm_value.object = create<object_t>(first.m_it.object_iterator,\n\t\t\t\t\tlast.m_it.object_iterator);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\tm_value.array = create<array_t>(first.m_it.array_iterator,\n\t\t\t\t\tlast.m_it.array_iterator);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tJSON_THROW(invalid_iterator::create(206, \"cannot construct with iterators from \" +\n\t\t\t\t\tstd::string(first.m_object->type_name())));\n\t\t\t}\n\n\t\t\tassert_invariant();\n\t\t}\n\n\n\t\t///////////////////////////////////////\n\t\t// other constructors and destructor //\n\t\t///////////////////////////////////////\n\n\t\t/// @private\n\t\tbasic_json(const detail::json_ref<basic_json>& ref)\n\t\t\t: basic_json(ref.moved_or_copied())\n\t\t{}\n\n\t\t/*!\n\t\t@brief copy constructor\n\n\t\tCreates a copy of a given JSON value.\n\n\t\t@param[in] other  the JSON value to copy\n\n\t\t@post `*this == other`\n\n\t\t@complexity Linear in the size of @a other.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges to any JSON value.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is linear.\n\t\t- As postcondition, it holds: `other == basic_json(other)`.\n\n\t\t@liveexample{The following code shows an example for the copy\n\t\tconstructor.,basic_json__basic_json}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json(const basic_json& other)\n\t\t\t: m_type(other.m_type)\n\t\t{\n\t\t\t// check of passed value is valid\n\t\t\tother.assert_invariant();\n\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\tm_value = *other.m_value.object;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\tm_value = *other.m_value.array;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::string:\n\t\t\t{\n\t\t\t\tm_value = *other.m_value.string;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::boolean:\n\t\t\t{\n\t\t\t\tm_value = other.m_value.boolean;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_integer:\n\t\t\t{\n\t\t\t\tm_value = other.m_value.number_integer;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_unsigned:\n\t\t\t{\n\t\t\t\tm_value = other.m_value.number_unsigned;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_float:\n\t\t\t{\n\t\t\t\tm_value = other.m_value.number_float;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief move constructor\n\n\t\tMove constructor. Constructs a JSON value with the contents of the given\n\t\tvalue @a other using move semantics. It \"steals\" the resources from @a\n\t\tother and leaves it as JSON null value.\n\n\t\t@param[in,out] other  value to move to this object\n\n\t\t@post `*this` has the same value as @a other before the call.\n\t\t@post @a other is a JSON null value.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this constructor never throws\n\t\texceptions.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)\n\t\trequirements.\n\n\t\t@liveexample{The code below shows the move constructor explicitly called\n\t\tvia std::move.,basic_json__moveconstructor}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json(basic_json&& other) noexcept\n\t\t\t: m_type(std::move(other.m_type)),\n\t\t\tm_value(std::move(other.m_value))\n\t\t{\n\t\t\t// check that passed value is valid\n\t\t\tother.assert_invariant();\n\n\t\t\t// invalidate payload\n\t\t\tother.m_type = value_t::null;\n\t\t\tother.m_value = {};\n\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief copy assignment\n\n\t\tCopy assignment operator. Copies a JSON value via the \"copy and swap\"\n\t\tstrategy: It is expressed in terms of the copy constructor, destructor,\n\t\tand the `swap()` member function.\n\n\t\t@param[in] other  value to copy from\n\n\t\t@complexity Linear.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is linear.\n\n\t\t@liveexample{The code below shows and example for the copy assignment. It\n\t\tcreates a copy of value `a` which is then swapped with `b`. Finally\\, the\n\t\tcopy of `a` (which is the null value after the swap) is\n\t\tdestroyed.,basic_json__copyassignment}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbasic_json& operator=(basic_json other) noexcept (\n\t\t\tstd::is_nothrow_move_constructible<value_t>::value and\n\t\t\tstd::is_nothrow_move_assignable<value_t>::value and\n\t\t\tstd::is_nothrow_move_constructible<json_value>::value and\n\t\t\tstd::is_nothrow_move_assignable<json_value>::value\n\t\t\t)\n\t\t{\n\t\t\t// check that passed value is valid\n\t\t\tother.assert_invariant();\n\n\t\t\tusing std::swap;\n\t\t\tswap(m_type, other.m_type);\n\t\t\tswap(m_value, other.m_value);\n\n\t\t\tassert_invariant();\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief destructor\n\n\t\tDestroys the JSON value and frees all allocated memory.\n\n\t\t@complexity Linear.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is linear.\n\t\t- All stored elements are destroyed and all memory is freed.\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\t~basic_json() noexcept\n\t\t{\n\t\t\tassert_invariant();\n\t\t\tm_value.destroy(m_type);\n\t\t}\n\n\t\t/// @}\n\n\tpublic:\n\t\t///////////////////////\n\t\t// object inspection //\n\t\t///////////////////////\n\n\t\t/// @name object inspection\n\t\t/// Functions to inspect the type of a JSON value.\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief serialization\n\n\t\tSerialization function for JSON values. The function tries to mimic\n\t\tPython's `json.dumps()` function, and currently supports its @a indent\n\t\tand @a ensure_ascii parameters.\n\n\t\t@param[in] indent If indent is nonnegative, then array elements and object\n\t\tmembers will be pretty-printed with that indent level. An indent level of\n\t\t`0` will only insert newlines. `-1` (the default) selects the most compact\n\t\trepresentation.\n\t\t@param[in] indent_char The character to use for indentation if @a indent is\n\t\tgreater than `0`. The default is ` ` (space).\n\t\t@param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n\t\tin the output are escaped with `\\uXXXX` sequences, and the result consists\n\t\tof ASCII characters only.\n\t\t@param[in] error_handler  how to react on decoding errors; there are three\n\t\tpossible values: `strict` (throws and exception in case a decoding error\n\t\toccurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),\n\t\tand `ignore` (ignore invalid UTF-8 sequences during serialization).\n\n\t\t@return string containing the serialization of the JSON value\n\n\t\t@throw type_error.316 if a string stored inside the JSON value is not\n\t\t\t\t\t\t\t  UTF-8 encoded\n\n\t\t@complexity Linear.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@liveexample{The following example shows the effect of different @a indent\\,\n\t\t@a indent_char\\, and @a ensure_ascii parameters to the result of the\n\t\tserialization.,dump}\n\n\t\t@see https://docs.python.org/2/library/json.html#json.dump\n\n\t\t@since version 1.0.0; indentation character @a indent_char, option\n\t\t\t   @a ensure_ascii and exceptions added in version 3.0.0; error\n\t\t\t   handlers added in version 3.4.0.\n\t\t*/\n\t\tstring_t dump(const int indent = -1,\n\t\t\tconst char indent_char = ' ',\n\t\t\tconst bool ensure_ascii = false,\n\t\t\tconst error_handler_t error_handler = error_handler_t::strict) const\n\t\t{\n\t\t\tstring_t result;\n\t\t\tserializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);\n\n\t\t\tif (indent >= 0)\n\t\t\t{\n\t\t\t\ts.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts.dump(*this, false, ensure_ascii, 0);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief return the type of the JSON value (explicit)\n\n\t\tReturn the type of the JSON value as a value from the @ref value_t\n\t\tenumeration.\n\n\t\t@return the type of the JSON value\n\t\t\t\tValue type                | return value\n\t\t\t\t------------------------- | -------------------------\n\t\t\t\tnull                      | value_t::null\n\t\t\t\tboolean                   | value_t::boolean\n\t\t\t\tstring                    | value_t::string\n\t\t\t\tnumber (integer)          | value_t::number_integer\n\t\t\t\tnumber (unsigned integer) | value_t::number_unsigned\n\t\t\t\tnumber (floating-point)   | value_t::number_float\n\t\t\t\tobject                    | value_t::object\n\t\t\t\tarray                     | value_t::array\n\t\t\t\tdiscarded                 | value_t::discarded\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `type()` for all JSON\n\t\ttypes.,type}\n\n\t\t@sa @ref operator value_t() -- return the type of the JSON value (implicit)\n\t\t@sa @ref type_name() -- return the type as string\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr value_t type() const noexcept\n\t\t{\n\t\t\treturn m_type;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether type is primitive\n\n\t\tThis function returns true if and only if the JSON type is primitive\n\t\t(string, number, boolean, or null).\n\n\t\t@return `true` if type is primitive (string, number, boolean, or null),\n\t\t`false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_primitive()` for all JSON\n\t\ttypes.,is_primitive}\n\n\t\t@sa @ref is_structured() -- returns whether JSON value is structured\n\t\t@sa @ref is_null() -- returns whether JSON value is `null`\n\t\t@sa @ref is_string() -- returns whether JSON value is a string\n\t\t@sa @ref is_boolean() -- returns whether JSON value is a boolean\n\t\t@sa @ref is_number() -- returns whether JSON value is a number\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_primitive() const noexcept\n\t\t{\n\t\t\treturn is_null() or is_string() or is_boolean() or is_number();\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether type is structured\n\n\t\tThis function returns true if and only if the JSON type is structured\n\t\t(array or object).\n\n\t\t@return `true` if type is structured (array or object), `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_structured()` for all JSON\n\t\ttypes.,is_structured}\n\n\t\t@sa @ref is_primitive() -- returns whether value is primitive\n\t\t@sa @ref is_array() -- returns whether value is an array\n\t\t@sa @ref is_object() -- returns whether value is an object\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_structured() const noexcept\n\t\t{\n\t\t\treturn is_array() or is_object();\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is null\n\n\t\tThis function returns true if and only if the JSON value is null.\n\n\t\t@return `true` if type is null, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_null()` for all JSON\n\t\ttypes.,is_null}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_null() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::null;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is a boolean\n\n\t\tThis function returns true if and only if the JSON value is a boolean.\n\n\t\t@return `true` if type is boolean, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_boolean()` for all JSON\n\t\ttypes.,is_boolean}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_boolean() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::boolean;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is a number\n\n\t\tThis function returns true if and only if the JSON value is a number. This\n\t\tincludes both integer (signed and unsigned) and floating-point values.\n\n\t\t@return `true` if type is number (regardless whether integer, unsigned\n\t\tinteger or floating-type), `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_number()` for all JSON\n\t\ttypes.,is_number}\n\n\t\t@sa @ref is_number_integer() -- check if value is an integer or unsigned\n\t\tinteger number\n\t\t@sa @ref is_number_unsigned() -- check if value is an unsigned integer\n\t\tnumber\n\t\t@sa @ref is_number_float() -- check if value is a floating-point number\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_number() const noexcept\n\t\t{\n\t\t\treturn is_number_integer() or is_number_float();\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is an integer number\n\n\t\tThis function returns true if and only if the JSON value is a signed or\n\t\tunsigned integer number. This excludes floating-point values.\n\n\t\t@return `true` if type is an integer or unsigned integer number, `false`\n\t\totherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_number_integer()` for all\n\t\tJSON types.,is_number_integer}\n\n\t\t@sa @ref is_number() -- check if value is a number\n\t\t@sa @ref is_number_unsigned() -- check if value is an unsigned integer\n\t\tnumber\n\t\t@sa @ref is_number_float() -- check if value is a floating-point number\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_number_integer() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::number_integer or m_type == value_t::number_unsigned;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is an unsigned integer number\n\n\t\tThis function returns true if and only if the JSON value is an unsigned\n\t\tinteger number. This excludes floating-point and signed integer values.\n\n\t\t@return `true` if type is an unsigned integer number, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_number_unsigned()` for all\n\t\tJSON types.,is_number_unsigned}\n\n\t\t@sa @ref is_number() -- check if value is a number\n\t\t@sa @ref is_number_integer() -- check if value is an integer or unsigned\n\t\tinteger number\n\t\t@sa @ref is_number_float() -- check if value is a floating-point number\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tconstexpr bool is_number_unsigned() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::number_unsigned;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is a floating-point number\n\n\t\tThis function returns true if and only if the JSON value is a\n\t\tfloating-point number. This excludes signed and unsigned integer values.\n\n\t\t@return `true` if type is a floating-point number, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_number_float()` for all\n\t\tJSON types.,is_number_float}\n\n\t\t@sa @ref is_number() -- check if value is number\n\t\t@sa @ref is_number_integer() -- check if value is an integer number\n\t\t@sa @ref is_number_unsigned() -- check if value is an unsigned integer\n\t\tnumber\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_number_float() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::number_float;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is an object\n\n\t\tThis function returns true if and only if the JSON value is an object.\n\n\t\t@return `true` if type is object, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_object()` for all JSON\n\t\ttypes.,is_object}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_object() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::object;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is an array\n\n\t\tThis function returns true if and only if the JSON value is an array.\n\n\t\t@return `true` if type is array, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_array()` for all JSON\n\t\ttypes.,is_array}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_array() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::array;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is a string\n\n\t\tThis function returns true if and only if the JSON value is a string.\n\n\t\t@return `true` if type is string, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_string()` for all JSON\n\t\ttypes.,is_string}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_string() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::string;\n\t\t}\n\n\t\t/*!\n\t\t@brief return whether value is discarded\n\n\t\tThis function returns true if and only if the JSON value was discarded\n\t\tduring parsing with a callback function (see @ref parser_callback_t).\n\n\t\t@note This function will always be `false` for JSON values after parsing.\n\t\tThat is, discarded values can only occur during parsing, but will be\n\t\tremoved when inside a structured value or replaced by null in other cases.\n\n\t\t@return `true` if type is discarded, `false` otherwise.\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies `is_discarded()` for all JSON\n\t\ttypes.,is_discarded}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr bool is_discarded() const noexcept\n\t\t{\n\t\t\treturn m_type == value_t::discarded;\n\t\t}\n\n\t\t/*!\n\t\t@brief return the type of the JSON value (implicit)\n\n\t\tImplicitly return the type of the JSON value as a value from the @ref\n\t\tvalue_t enumeration.\n\n\t\t@return the type of the JSON value\n\n\t\t@complexity Constant.\n\n\t\t@exceptionsafety No-throw guarantee: this member function never throws\n\t\texceptions.\n\n\t\t@liveexample{The following code exemplifies the @ref value_t operator for\n\t\tall JSON types.,operator__value_t}\n\n\t\t@sa @ref type() -- return the type of the JSON value (explicit)\n\t\t@sa @ref type_name() -- return the type as string\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconstexpr operator value_t() const noexcept\n\t\t{\n\t\t\treturn m_type;\n\t\t}\n\n\t\t/// @}\n\n\tprivate:\n\t\t//////////////////\n\t\t// value access //\n\t\t//////////////////\n\n\t\t/// get a boolean (explicit)\n\t\tboolean_t get_impl(boolean_t* /*unused*/) const\n\t\t{\n\t\t\tif (JSON_LIKELY(is_boolean()))\n\t\t\t{\n\t\t\t\treturn m_value.boolean;\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(type_name())));\n\t\t}\n\n\t\t/// get a pointer to the value (object)\n\t\tobject_t* get_impl_ptr(object_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_object() ? m_value.object : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (object)\n\t\tconstexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_object() ? m_value.object : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (array)\n\t\tarray_t* get_impl_ptr(array_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_array() ? m_value.array : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (array)\n\t\tconstexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_array() ? m_value.array : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (string)\n\t\tstring_t* get_impl_ptr(string_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_string() ? m_value.string : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (string)\n\t\tconstexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_string() ? m_value.string : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (boolean)\n\t\tboolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_boolean() ? &m_value.boolean : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (boolean)\n\t\tconstexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_boolean() ? &m_value.boolean : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (integer number)\n\t\tnumber_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_number_integer() ? &m_value.number_integer : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (integer number)\n\t\tconstexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_number_integer() ? &m_value.number_integer : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (unsigned number)\n\t\tnumber_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (unsigned number)\n\t\tconstexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (floating-point number)\n\t\tnumber_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept\n\t\t{\n\t\t\treturn is_number_float() ? &m_value.number_float : nullptr;\n\t\t}\n\n\t\t/// get a pointer to the value (floating-point number)\n\t\tconstexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept\n\t\t{\n\t\t\treturn is_number_float() ? &m_value.number_float : nullptr;\n\t\t}\n\n\t\t/*!\n\t\t@brief helper function to implement get_ref()\n\n\t\tThis function helps to implement get_ref() without code duplication for\n\t\tconst and non-const overloads\n\n\t\t@tparam ThisType will be deduced as `basic_json` or `const basic_json`\n\n\t\t@throw type_error.303 if ReferenceType does not match underlying value\n\t\ttype of the current JSON\n\t\t*/\n\t\ttemplate<typename ReferenceType, typename ThisType>\n\t\tstatic ReferenceType get_ref_impl(ThisType& obj)\n\t\t{\n\t\t\t// delegate the call to get_ptr<>()\n\t\t\tauto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();\n\n\t\t\tif (JSON_LIKELY(ptr != nullptr))\n\t\t\t{\n\t\t\t\treturn *ptr;\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(303, \"incompatible ReferenceType for get_ref, actual type is \" + std::string(obj.type_name())));\n\t\t}\n\n\tpublic:\n\t\t/// @name value access\n\t\t/// Direct access to the stored value of a JSON value.\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief get special-case overload\n\n\t\tThis overloads avoids a lot of template boilerplate, it can be seen as the\n\t\tidentity method\n\n\t\t@tparam BasicJsonType == @ref basic_json\n\n\t\t@return a copy of *this\n\n\t\t@complexity Constant.\n\n\t\t@since version 2.1.0\n\t\t*/\n\t\ttemplate<typename BasicJsonType, detail::enable_if_t<\n\t\t\tstd::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,\n\t\t\tint> = 0>\n\t\t\tbasic_json get() const\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief get special-case overload\n\n\t\tThis overloads converts the current @ref basic_json in a different\n\t\t@ref basic_json type\n\n\t\t@tparam BasicJsonType == @ref basic_json\n\n\t\t@return a copy of *this, converted into @tparam BasicJsonType\n\n\t\t@complexity Depending on the implementation of the called `from_json()`\n\t\t\t\t\tmethod.\n\n\t\t@since version 3.2.0\n\t\t*/\n\t\ttemplate<typename BasicJsonType, detail::enable_if_t<\n\t\t\tnot std::is_same<BasicJsonType, basic_json>::value and\n\t\t\tdetail::is_basic_json<BasicJsonType>::value, int> = 0>\n\t\t\tBasicJsonType get() const\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief get a value (explicit)\n\n\t\tExplicit type conversion between the JSON value and a compatible value\n\t\twhich is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n\t\tand [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n\t\tThe value is converted by calling the @ref json_serializer<ValueType>\n\t\t`from_json()` method.\n\n\t\tThe function is equivalent to executing\n\t\t@code {.cpp}\n\t\tValueType ret;\n\t\tJSONSerializer<ValueType>::from_json(*this, ret);\n\t\treturn ret;\n\t\t@endcode\n\n\t\tThis overloads is chosen if:\n\t\t- @a ValueType is not @ref basic_json,\n\t\t- @ref json_serializer<ValueType> has a `from_json()` method of the form\n\t\t  `void from_json(const basic_json&, ValueType&)`, and\n\t\t- @ref json_serializer<ValueType> does not have a `from_json()` method of\n\t\t  the form `ValueType from_json(const basic_json&)`\n\n\t\t@tparam ValueTypeCV the provided value type\n\t\t@tparam ValueType the returned value type\n\n\t\t@return copy of the JSON value, converted to @a ValueType\n\n\t\t@throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n\t\t@liveexample{The example below shows several conversions from JSON values\n\t\tto other types. There a few things to note: (1) Floating-point numbers can\n\t\tbe converted to integers\\, (2) A JSON array can be converted to a standard\n\t\t`std::vector<short>`\\, (3) A JSON object can be converted to C++\n\t\tassociative containers such as `std::unordered_map<std::string\\,\n\t\tjson>`.,get__ValueType_const}\n\n\t\t@since version 2.1.0\n\t\t*/\n\t\ttemplate<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n\t\t\tdetail::enable_if_t <\n\t\t\tnot detail::is_basic_json<ValueType>::value and\n\t\t\tdetail::has_from_json<basic_json_t, ValueType>::value and\n\t\t\tnot detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n\t\t\tint> = 0>\n\t\t\tValueType get() const noexcept(noexcept(\n\t\t\t\tJSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))\n\t\t{\n\t\t\t// we cannot static_assert on ValueTypeCV being non-const, because\n\t\t\t// there is support for get<const basic_json_t>(), which is why we\n\t\t\t// still need the uncvref\n\t\t\tstatic_assert(not std::is_reference<ValueTypeCV>::value,\n\t\t\t\t\"get() cannot be used with reference types, you might want to use get_ref()\");\n\t\t\tstatic_assert(std::is_default_constructible<ValueType>::value,\n\t\t\t\t\"types must be DefaultConstructible when used with get()\");\n\n\t\t\tValueType ret;\n\t\t\tJSONSerializer<ValueType>::from_json(*this, ret);\n\t\t\treturn ret;\n\t\t}\n\n\t\t/*!\n\t\t@brief get a value (explicit); special case\n\n\t\tExplicit type conversion between the JSON value and a compatible value\n\t\twhich is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n\t\tand **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n\t\tThe value is converted by calling the @ref json_serializer<ValueType>\n\t\t`from_json()` method.\n\n\t\tThe function is equivalent to executing\n\t\t@code {.cpp}\n\t\treturn JSONSerializer<ValueTypeCV>::from_json(*this);\n\t\t@endcode\n\n\t\tThis overloads is chosen if:\n\t\t- @a ValueType is not @ref basic_json and\n\t\t- @ref json_serializer<ValueType> has a `from_json()` method of the form\n\t\t  `ValueType from_json(const basic_json&)`\n\n\t\t@note If @ref json_serializer<ValueType> has both overloads of\n\t\t`from_json()`, this one is chosen.\n\n\t\t@tparam ValueTypeCV the provided value type\n\t\t@tparam ValueType the returned value type\n\n\t\t@return copy of the JSON value, converted to @a ValueType\n\n\t\t@throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n\t\t@since version 2.1.0\n\t\t*/\n\t\ttemplate<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n\t\t\tdetail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and\n\t\t\tdetail::has_non_default_from_json<basic_json_t, ValueType>::value,\n\t\t\tint> = 0>\n\t\t\tValueType get() const noexcept(noexcept(\n\t\t\t\tJSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))\n\t\t{\n\t\t\tstatic_assert(not std::is_reference<ValueTypeCV>::value,\n\t\t\t\t\"get() cannot be used with reference types, you might want to use get_ref()\");\n\t\t\treturn JSONSerializer<ValueTypeCV>::from_json(*this);\n\t\t}\n\n\t\t/*!\n\t\t@brief get a value (explicit)\n\n\t\tExplicit type conversion between the JSON value and a compatible value.\n\t\tThe value is filled into the input parameter by calling the @ref json_serializer<ValueType>\n\t\t`from_json()` method.\n\n\t\tThe function is equivalent to executing\n\t\t@code {.cpp}\n\t\tValueType v;\n\t\tJSONSerializer<ValueType>::from_json(*this, v);\n\t\t@endcode\n\n\t\tThis overloads is chosen if:\n\t\t- @a ValueType is not @ref basic_json,\n\t\t- @ref json_serializer<ValueType> has a `from_json()` method of the form\n\t\t  `void from_json(const basic_json&, ValueType&)`, and\n\n\t\t@tparam ValueType the input parameter type.\n\n\t\t@return the input parameter, allowing chaining calls.\n\n\t\t@throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n\t\t@liveexample{The example below shows several conversions from JSON values\n\t\tto other types. There a few things to note: (1) Floating-point numbers can\n\t\tbe converted to integers\\, (2) A JSON array can be converted to a standard\n\t\t`std::vector<short>`\\, (3) A JSON object can be converted to C++\n\t\tassociative containers such as `std::unordered_map<std::string\\,\n\t\tjson>`.,get_to}\n\n\t\t@since version 3.3.0\n\t\t*/\n\t\ttemplate<typename ValueType,\n\t\t\tdetail::enable_if_t <\n\t\t\tnot detail::is_basic_json<ValueType>::value and\n\t\t\tdetail::has_from_json<basic_json_t, ValueType>::value,\n\t\t\tint> = 0>\n\t\t\tValueType & get_to(ValueType& v) const noexcept(noexcept(\n\t\t\t\tJSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))\n\t\t{\n\t\t\tJSONSerializer<ValueType>::from_json(*this, v);\n\t\t\treturn v;\n\t\t}\n\n\t\ttemplate <\n\t\t\ttypename T, std::size_t N,\n\t\t\ttypename Array = T(&)[N],\n\t\t\tdetail::enable_if_t <\n\t\t\tdetail::has_from_json<basic_json_t, Array>::value, int > = 0 >\n\t\t\tArray get_to(T(&v)[N]) const\n\t\t\tnoexcept(noexcept(JSONSerializer<Array>::from_json(\n\t\t\t\tstd::declval<const basic_json_t&>(), v)))\n\t\t{\n\t\t\tJSONSerializer<Array>::from_json(*this, v);\n\t\t\treturn v;\n\t\t}\n\n\n\t\t/*!\n\t\t@brief get a pointer value (implicit)\n\n\t\tImplicit pointer access to the internally stored JSON value. No copies are\n\t\tmade.\n\n\t\t@warning Writing data to the pointee of the result yields an undefined\n\t\tstate.\n\n\t\t@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n\t\tobject_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n\t\t@ref number_unsigned_t, or @ref number_float_t. Enforced by a static\n\t\tassertion.\n\n\t\t@return pointer to the internally stored JSON value if the requested\n\t\tpointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how pointers to internal values of a\n\t\tJSON value can be requested. Note that no type conversions are made and a\n\t\t`nullptr` is returned if the value and the requested pointer type does not\n\t\tmatch.,get_ptr}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<typename PointerType, typename std::enable_if<\n\t\t\tstd::is_pointer<PointerType>::value, int>::type = 0>\n\t\t\tauto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n\t\t{\n\t\t\t// delegate the call to get_impl_ptr<>()\n\t\t\treturn get_impl_ptr(static_cast<PointerType>(nullptr));\n\t\t}\n\n\t\t/*!\n\t\t@brief get a pointer value (implicit)\n\t\t@copydoc get_ptr()\n\t\t*/\n\t\ttemplate<typename PointerType, typename std::enable_if<\n\t\t\tstd::is_pointer<PointerType>::value and\n\t\t\tstd::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>\n\t\t\tconstexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n\t\t{\n\t\t\t// delegate the call to get_impl_ptr<>() const\n\t\t\treturn get_impl_ptr(static_cast<PointerType>(nullptr));\n\t\t}\n\n\t\t/*!\n\t\t@brief get a pointer value (explicit)\n\n\t\tExplicit pointer access to the internally stored JSON value. No copies are\n\t\tmade.\n\n\t\t@warning The pointer becomes invalid if the underlying JSON object\n\t\tchanges.\n\n\t\t@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n\t\tobject_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n\t\t@ref number_unsigned_t, or @ref number_float_t.\n\n\t\t@return pointer to the internally stored JSON value if the requested\n\t\tpointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how pointers to internal values of a\n\t\tJSON value can be requested. Note that no type conversions are made and a\n\t\t`nullptr` is returned if the value and the requested pointer type does not\n\t\tmatch.,get__PointerType}\n\n\t\t@sa @ref get_ptr() for explicit pointer-member access\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<typename PointerType, typename std::enable_if<\n\t\t\tstd::is_pointer<PointerType>::value, int>::type = 0>\n\t\t\tauto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())\n\t\t{\n\t\t\t// delegate the call to get_ptr\n\t\t\treturn get_ptr<PointerType>();\n\t\t}\n\n\t\t/*!\n\t\t@brief get a pointer value (explicit)\n\t\t@copydoc get()\n\t\t*/\n\t\ttemplate<typename PointerType, typename std::enable_if<\n\t\t\tstd::is_pointer<PointerType>::value, int>::type = 0>\n\t\t\tconstexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())\n\t\t{\n\t\t\t// delegate the call to get_ptr\n\t\t\treturn get_ptr<PointerType>();\n\t\t}\n\n\t\t/*!\n\t\t@brief get a reference value (implicit)\n\n\t\tImplicit reference access to the internally stored JSON value. No copies\n\t\tare made.\n\n\t\t@warning Writing data to the referee of the result yields an undefined\n\t\tstate.\n\n\t\t@tparam ReferenceType reference type; must be a reference to @ref array_t,\n\t\t@ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or\n\t\t@ref number_float_t. Enforced by static assertion.\n\n\t\t@return reference to the internally stored JSON value if the requested\n\t\treference type @a ReferenceType fits to the JSON value; throws\n\t\ttype_error.303 otherwise\n\n\t\t@throw type_error.303 in case passed type @a ReferenceType is incompatible\n\t\twith the stored JSON value; see example below\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example shows several calls to `get_ref()`.,get_ref}\n\n\t\t@since version 1.1.0\n\t\t*/\n\t\ttemplate<typename ReferenceType, typename std::enable_if<\n\t\t\tstd::is_reference<ReferenceType>::value, int>::type = 0>\n\t\t\tReferenceType get_ref()\n\t\t{\n\t\t\t// delegate call to get_ref_impl\n\t\t\treturn get_ref_impl<ReferenceType>(*this);\n\t\t}\n\n\t\t/*!\n\t\t@brief get a reference value (implicit)\n\t\t@copydoc get_ref()\n\t\t*/\n\t\ttemplate<typename ReferenceType, typename std::enable_if<\n\t\t\tstd::is_reference<ReferenceType>::value and\n\t\t\tstd::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>\n\t\t\tReferenceType get_ref() const\n\t\t{\n\t\t\t// delegate call to get_ref_impl\n\t\t\treturn get_ref_impl<ReferenceType>(*this);\n\t\t}\n\n\t\t/*!\n\t\t@brief get a value (implicit)\n\n\t\tImplicit type conversion between the JSON value and a compatible value.\n\t\tThe call is realized by calling @ref get() const.\n\n\t\t@tparam ValueType non-pointer type compatible to the JSON value, for\n\t\tinstance `int` for JSON integer numbers, `bool` for JSON booleans, or\n\t\t`std::vector` types for JSON arrays. The character type of @ref string_t\n\t\tas well as an initializer list of this type is excluded to avoid\n\t\tambiguities as these types implicitly convert to `std::string`.\n\n\t\t@return copy of the JSON value, converted to type @a ValueType\n\n\t\t@throw type_error.302 in case passed type @a ValueType is incompatible\n\t\tto the JSON value type (e.g., the JSON value is of type boolean, but a\n\t\tstring is requested); see example below\n\n\t\t@complexity Linear in the size of the JSON value.\n\n\t\t@liveexample{The example below shows several conversions from JSON values\n\t\tto other types. There a few things to note: (1) Floating-point numbers can\n\t\tbe converted to integers\\, (2) A JSON array can be converted to a standard\n\t\t`std::vector<short>`\\, (3) A JSON object can be converted to C++\n\t\tassociative containers such as `std::unordered_map<std::string\\,\n\t\tjson>`.,operator__ValueType}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate < typename ValueType, typename std::enable_if <\n\t\t\tnot std::is_pointer<ValueType>::value and\n\t\t\tnot std::is_same<ValueType, detail::json_ref<basic_json>>::value and\n\t\t\tnot std::is_same<ValueType, typename string_t::value_type>::value and\n\t\t\tnot detail::is_basic_json<ValueType>::value\n\n#ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015\n\t\t\tand not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value\n#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) and _MSC_VER <= 1914))\n\t\t\tand not std::is_same<ValueType, typename std::string_view>::value\n#endif\n#endif\n\t\t\tand detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value\n\t\t\t, int >::type = 0 >\n\t\t\toperator ValueType() const\n\t\t{\n\t\t\t// delegate the call to get<>() const\n\t\t\treturn get<ValueType>();\n\t\t}\n\n\t\t/// @}\n\n\n\t\t////////////////////\n\t\t// element access //\n\t\t////////////////////\n\n\t\t/// @name element access\n\t\t/// Access to the JSON value.\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief access specified array element with bounds checking\n\n\t\tReturns a reference to the element at specified location @a idx, with\n\t\tbounds checking.\n\n\t\t@param[in] idx  index of the element to access\n\n\t\t@return reference to the element at index @a idx\n\n\t\t@throw type_error.304 if the JSON value is not an array; in this case,\n\t\tcalling `at` with an index makes no sense. See example below.\n\t\t@throw out_of_range.401 if the index @a idx is out of range of the array;\n\t\tthat is, `idx >= size()`. See example below.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@since version 1.0.0\n\n\t\t@liveexample{The example below shows how array elements can be read and\n\t\twritten using `at()`. It also demonstrates the different exceptions that\n\t\tcan be thrown.,at__size_type}\n\t\t*/\n\t\treference at(size_type idx)\n\t\t{\n\t\t\t// at only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\tJSON_TRY\n\t\t\t\t{\n\t\t\t\t\treturn m_value.array->at(idx);\n\t\t\t\t}\n\t\t\t\t\tJSON_CATCH(std::out_of_range&)\n\t\t\t\t{\n\t\t\t\t\t// create better exception explanation\n\t\t\t\t\tJSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified array element with bounds checking\n\n\t\tReturns a const reference to the element at specified location @a idx,\n\t\twith bounds checking.\n\n\t\t@param[in] idx  index of the element to access\n\n\t\t@return const reference to the element at index @a idx\n\n\t\t@throw type_error.304 if the JSON value is not an array; in this case,\n\t\tcalling `at` with an index makes no sense. See example below.\n\t\t@throw out_of_range.401 if the index @a idx is out of range of the array;\n\t\tthat is, `idx >= size()`. See example below.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@since version 1.0.0\n\n\t\t@liveexample{The example below shows how array elements can be read using\n\t\t`at()`. It also demonstrates the different exceptions that can be thrown.,\n\t\tat__size_type_const}\n\t\t*/\n\t\tconst_reference at(size_type idx) const\n\t\t{\n\t\t\t// at only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\tJSON_TRY\n\t\t\t\t{\n\t\t\t\t\treturn m_value.array->at(idx);\n\t\t\t\t}\n\t\t\t\t\tJSON_CATCH(std::out_of_range&)\n\t\t\t\t{\n\t\t\t\t\t// create better exception explanation\n\t\t\t\t\tJSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified object element with bounds checking\n\n\t\tReturns a reference to the element at with specified key @a key, with\n\t\tbounds checking.\n\n\t\t@param[in] key  key of the element to access\n\n\t\t@return reference to the element at key @a key\n\n\t\t@throw type_error.304 if the JSON value is not an object; in this case,\n\t\tcalling `at` with a key makes no sense. See example below.\n\t\t@throw out_of_range.403 if the key @a key is is not stored in the object;\n\t\tthat is, `find(key) == end()`. See example below.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@sa @ref operator[](const typename object_t::key_type&) for unchecked\n\t\taccess by reference\n\t\t@sa @ref value() for access by value with a default value\n\n\t\t@since version 1.0.0\n\n\t\t@liveexample{The example below shows how object elements can be read and\n\t\twritten using `at()`. It also demonstrates the different exceptions that\n\t\tcan be thrown.,at__object_t_key_type}\n\t\t*/\n\t\treference at(const typename object_t::key_type& key)\n\t\t{\n\t\t\t// at only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\tJSON_TRY\n\t\t\t\t{\n\t\t\t\t\treturn m_value.object->at(key);\n\t\t\t\t}\n\t\t\t\t\tJSON_CATCH(std::out_of_range&)\n\t\t\t\t{\n\t\t\t\t\t// create better exception explanation\n\t\t\t\t\tJSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified object element with bounds checking\n\n\t\tReturns a const reference to the element at with specified key @a key,\n\t\twith bounds checking.\n\n\t\t@param[in] key  key of the element to access\n\n\t\t@return const reference to the element at key @a key\n\n\t\t@throw type_error.304 if the JSON value is not an object; in this case,\n\t\tcalling `at` with a key makes no sense. See example below.\n\t\t@throw out_of_range.403 if the key @a key is is not stored in the object;\n\t\tthat is, `find(key) == end()`. See example below.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@sa @ref operator[](const typename object_t::key_type&) for unchecked\n\t\taccess by reference\n\t\t@sa @ref value() for access by value with a default value\n\n\t\t@since version 1.0.0\n\n\t\t@liveexample{The example below shows how object elements can be read using\n\t\t`at()`. It also demonstrates the different exceptions that can be thrown.,\n\t\tat__object_t_key_type_const}\n\t\t*/\n\t\tconst_reference at(const typename object_t::key_type& key) const\n\t\t{\n\t\t\t// at only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\tJSON_TRY\n\t\t\t\t{\n\t\t\t\t\treturn m_value.object->at(key);\n\t\t\t\t}\n\t\t\t\t\tJSON_CATCH(std::out_of_range&)\n\t\t\t\t{\n\t\t\t\t\t// create better exception explanation\n\t\t\t\t\tJSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified array element\n\n\t\tReturns a reference to the element at specified location @a idx.\n\n\t\t@note If @a idx is beyond the range of the array (i.e., `idx >= size()`),\n\t\tthen the array is silently filled up with `null` values to make `idx` a\n\t\tvalid reference to the last stored element.\n\n\t\t@param[in] idx  index of the element to access\n\n\t\t@return reference to the element at index @a idx\n\n\t\t@throw type_error.305 if the JSON value is not an array or null; in that\n\t\tcases, using the [] operator with an index makes no sense.\n\n\t\t@complexity Constant if @a idx is in the range of the array. Otherwise\n\t\tlinear in `idx - size()`.\n\n\t\t@liveexample{The example below shows how array elements can be read and\n\t\twritten using `[]` operator. Note the addition of `null`\n\t\tvalues.,operatorarray__size_type}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\treference operator[](size_type idx)\n\t\t{\n\t\t\t// implicitly convert null value to an empty array\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::array;\n\t\t\t\tm_value.array = create<array_t>();\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// operator[] only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\t// fill up array with null values if given idx is outside range\n\t\t\t\tif (idx >= m_value.array->size())\n\t\t\t\t{\n\t\t\t\t\tm_value.array->insert(m_value.array->end(),\n\t\t\t\t\t\tidx - m_value.array->size() + 1,\n\t\t\t\t\t\tbasic_json());\n\t\t\t\t}\n\n\t\t\t\treturn m_value.array->operator[](idx);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified array element\n\n\t\tReturns a const reference to the element at specified location @a idx.\n\n\t\t@param[in] idx  index of the element to access\n\n\t\t@return const reference to the element at index @a idx\n\n\t\t@throw type_error.305 if the JSON value is not an array; in that case,\n\t\tusing the [] operator with an index makes no sense.\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how array elements can be read using\n\t\tthe `[]` operator.,operatorarray__size_type_const}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconst_reference operator[](size_type idx) const\n\t\t{\n\t\t\t// const operator[] only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\treturn m_value.array->operator[](idx);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified object element\n\n\t\tReturns a reference to the element at with specified key @a key.\n\n\t\t@note If @a key is not found in the object, then it is silently added to\n\t\tthe object and filled with a `null` value to make `key` a valid reference.\n\t\tIn case the value was `null` before, it is converted to an object.\n\n\t\t@param[in] key  key of the element to access\n\n\t\t@return reference to the element at key @a key\n\n\t\t@throw type_error.305 if the JSON value is not an object or null; in that\n\t\tcases, using the [] operator with a key makes no sense.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@liveexample{The example below shows how object elements can be read and\n\t\twritten using the `[]` operator.,operatorarray__key_type}\n\n\t\t@sa @ref at(const typename object_t::key_type&) for access by reference\n\t\twith range checking\n\t\t@sa @ref value() for access by value with a default value\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\treference operator[](const typename object_t::key_type& key)\n\t\t{\n\t\t\t// implicitly convert null value to an empty object\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value.object = create<object_t>();\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// operator[] only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\treturn m_value.object->operator[](key);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief read-only access specified object element\n\n\t\tReturns a const reference to the element at with specified key @a key. No\n\t\tbounds checking is performed.\n\n\t\t@warning If the element with key @a key does not exist, the behavior is\n\t\tundefined.\n\n\t\t@param[in] key  key of the element to access\n\n\t\t@return const reference to the element at key @a key\n\n\t\t@pre The element with key @a key must exist. **This precondition is\n\t\t\t enforced with an assertion.**\n\n\t\t@throw type_error.305 if the JSON value is not an object; in that case,\n\t\tusing the [] operator with a key makes no sense.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@liveexample{The example below shows how object elements can be read using\n\t\tthe `[]` operator.,operatorarray__key_type_const}\n\n\t\t@sa @ref at(const typename object_t::key_type&) for access by reference\n\t\twith range checking\n\t\t@sa @ref value() for access by value with a default value\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconst_reference operator[](const typename object_t::key_type& key) const\n\t\t{\n\t\t\t// const operator[] only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\tassert(m_value.object->find(key) != m_value.object->end());\n\t\t\t\treturn m_value.object->find(key)->second;\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified object element\n\n\t\tReturns a reference to the element at with specified key @a key.\n\n\t\t@note If @a key is not found in the object, then it is silently added to\n\t\tthe object and filled with a `null` value to make `key` a valid reference.\n\t\tIn case the value was `null` before, it is converted to an object.\n\n\t\t@param[in] key  key of the element to access\n\n\t\t@return reference to the element at key @a key\n\n\t\t@throw type_error.305 if the JSON value is not an object or null; in that\n\t\tcases, using the [] operator with a key makes no sense.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@liveexample{The example below shows how object elements can be read and\n\t\twritten using the `[]` operator.,operatorarray__key_type}\n\n\t\t@sa @ref at(const typename object_t::key_type&) for access by reference\n\t\twith range checking\n\t\t@sa @ref value() for access by value with a default value\n\n\t\t@since version 1.1.0\n\t\t*/\n\t\ttemplate<typename T>\n\t\treference operator[](T* key)\n\t\t{\n\t\t\t// implicitly convert null to object\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value = value_t::object;\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// at only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\treturn m_value.object->operator[](key);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief read-only access specified object element\n\n\t\tReturns a const reference to the element at with specified key @a key. No\n\t\tbounds checking is performed.\n\n\t\t@warning If the element with key @a key does not exist, the behavior is\n\t\tundefined.\n\n\t\t@param[in] key  key of the element to access\n\n\t\t@return const reference to the element at key @a key\n\n\t\t@pre The element with key @a key must exist. **This precondition is\n\t\t\t enforced with an assertion.**\n\n\t\t@throw type_error.305 if the JSON value is not an object; in that case,\n\t\tusing the [] operator with a key makes no sense.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@liveexample{The example below shows how object elements can be read using\n\t\tthe `[]` operator.,operatorarray__key_type_const}\n\n\t\t@sa @ref at(const typename object_t::key_type&) for access by reference\n\t\twith range checking\n\t\t@sa @ref value() for access by value with a default value\n\n\t\t@since version 1.1.0\n\t\t*/\n\t\ttemplate<typename T>\n\t\tconst_reference operator[](T* key) const\n\t\t{\n\t\t\t// at only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\tassert(m_value.object->find(key) != m_value.object->end());\n\t\t\t\treturn m_value.object->find(key)->second;\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified object element with default value\n\n\t\tReturns either a copy of an object's element at the specified key @a key\n\t\tor a given default value if no element with key @a key exists.\n\n\t\tThe function is basically equivalent to executing\n\t\t@code {.cpp}\n\t\ttry {\n\t\t\treturn at(key);\n\t\t} catch(out_of_range) {\n\t\t\treturn default_value;\n\t\t}\n\t\t@endcode\n\n\t\t@note Unlike @ref at(const typename object_t::key_type&), this function\n\t\tdoes not throw if the given key @a key was not found.\n\n\t\t@note Unlike @ref operator[](const typename object_t::key_type& key), this\n\t\tfunction does not implicitly add an element to the position defined by @a\n\t\tkey. This function is furthermore also applicable to const objects.\n\n\t\t@param[in] key  key of the element to access\n\t\t@param[in] default_value  the value to return if @a key is not found\n\n\t\t@tparam ValueType type compatible to JSON values, for instance `int` for\n\t\tJSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n\t\tJSON arrays. Note the type of the expected value at @a key and the default\n\t\tvalue @a default_value must be compatible.\n\n\t\t@return copy of the element at key @a key or @a default_value if @a key\n\t\tis not found\n\n\t\t@throw type_error.306 if the JSON value is not an object; in that case,\n\t\tusing `value()` with a key makes no sense.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@liveexample{The example below shows how object elements can be queried\n\t\twith a default value.,basic_json__value}\n\n\t\t@sa @ref at(const typename object_t::key_type&) for access by reference\n\t\twith range checking\n\t\t@sa @ref operator[](const typename object_t::key_type&) for unchecked\n\t\taccess by reference\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<class ValueType, typename std::enable_if<\n\t\t\tstd::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>\n\t\t\tValueType value(const typename object_t::key_type& key, const ValueType& default_value) const\n\t\t{\n\t\t\t// at only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\t// if key is found, return value and given default value otherwise\n\t\t\t\tconst auto it = find(key);\n\t\t\t\tif (it != end())\n\t\t\t\t{\n\t\t\t\t\treturn *it;\n\t\t\t\t}\n\n\t\t\t\treturn default_value;\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief overload for a default value of type const char*\n\t\t@copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const\n\t\t*/\n\t\tstring_t value(const typename object_t::key_type& key, const char* default_value) const\n\t\t{\n\t\t\treturn value(key, string_t(default_value));\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified object element via JSON Pointer with default value\n\n\t\tReturns either a copy of an object's element at the specified key @a key\n\t\tor a given default value if no element with key @a key exists.\n\n\t\tThe function is basically equivalent to executing\n\t\t@code {.cpp}\n\t\ttry {\n\t\t\treturn at(ptr);\n\t\t} catch(out_of_range) {\n\t\t\treturn default_value;\n\t\t}\n\t\t@endcode\n\n\t\t@note Unlike @ref at(const json_pointer&), this function does not throw\n\t\tif the given key @a key was not found.\n\n\t\t@param[in] ptr  a JSON pointer to the element to access\n\t\t@param[in] default_value  the value to return if @a ptr found no value\n\n\t\t@tparam ValueType type compatible to JSON values, for instance `int` for\n\t\tJSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n\t\tJSON arrays. Note the type of the expected value at @a key and the default\n\t\tvalue @a default_value must be compatible.\n\n\t\t@return copy of the element at key @a key or @a default_value if @a key\n\t\tis not found\n\n\t\t@throw type_error.306 if the JSON value is not an object; in that case,\n\t\tusing `value()` with a key makes no sense.\n\n\t\t@complexity Logarithmic in the size of the container.\n\n\t\t@liveexample{The example below shows how object elements can be queried\n\t\twith a default value.,basic_json__value_ptr}\n\n\t\t@sa @ref operator[](const json_pointer&) for unchecked access by reference\n\n\t\t@since version 2.0.2\n\t\t*/\n\t\ttemplate<class ValueType, typename std::enable_if<\n\t\t\tstd::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>\n\t\t\tValueType value(const json_pointer& ptr, const ValueType& default_value) const\n\t\t{\n\t\t\t// at only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\t// if pointer resolves a value, return it or use default value\n\t\t\t\tJSON_TRY\n\t\t\t\t{\n\t\t\t\t\treturn ptr.get_checked(this);\n\t\t\t\t}\n\t\t\t\t\tJSON_INTERNAL_CATCH(out_of_range&)\n\t\t\t\t{\n\t\t\t\t\treturn default_value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief overload for a default value of type const char*\n\t\t@copydoc basic_json::value(const json_pointer&, ValueType) const\n\t\t*/\n\t\tstring_t value(const json_pointer& ptr, const char* default_value) const\n\t\t{\n\t\t\treturn value(ptr, string_t(default_value));\n\t\t}\n\n\t\t/*!\n\t\t@brief access the first element\n\n\t\tReturns a reference to the first element in the container. For a JSON\n\t\tcontainer `c`, the expression `c.front()` is equivalent to `*c.begin()`.\n\n\t\t@return In case of a structured type (array or object), a reference to the\n\t\tfirst element is returned. In case of number, string, or boolean values, a\n\t\treference to the value is returned.\n\n\t\t@complexity Constant.\n\n\t\t@pre The JSON value must not be `null` (would throw `std::out_of_range`)\n\t\tor an empty array or object (undefined behavior, **guarded by\n\t\tassertions**).\n\t\t@post The JSON value remains unchanged.\n\n\t\t@throw invalid_iterator.214 when called on `null` value\n\n\t\t@liveexample{The following code shows an example for `front()`.,front}\n\n\t\t@sa @ref back() -- access the last element\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\treference front()\n\t\t{\n\t\t\treturn *begin();\n\t\t}\n\n\t\t/*!\n\t\t@copydoc basic_json::front()\n\t\t*/\n\t\tconst_reference front() const\n\t\t{\n\t\t\treturn *cbegin();\n\t\t}\n\n\t\t/*!\n\t\t@brief access the last element\n\n\t\tReturns a reference to the last element in the container. For a JSON\n\t\tcontainer `c`, the expression `c.back()` is equivalent to\n\t\t@code {.cpp}\n\t\tauto tmp = c.end();\n\t\t--tmp;\n\t\treturn *tmp;\n\t\t@endcode\n\n\t\t@return In case of a structured type (array or object), a reference to the\n\t\tlast element is returned. In case of number, string, or boolean values, a\n\t\treference to the value is returned.\n\n\t\t@complexity Constant.\n\n\t\t@pre The JSON value must not be `null` (would throw `std::out_of_range`)\n\t\tor an empty array or object (undefined behavior, **guarded by\n\t\tassertions**).\n\t\t@post The JSON value remains unchanged.\n\n\t\t@throw invalid_iterator.214 when called on a `null` value. See example\n\t\tbelow.\n\n\t\t@liveexample{The following code shows an example for `back()`.,back}\n\n\t\t@sa @ref front() -- access the first element\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\treference back()\n\t\t{\n\t\t\tauto tmp = end();\n\t\t\t--tmp;\n\t\t\treturn *tmp;\n\t\t}\n\n\t\t/*!\n\t\t@copydoc basic_json::back()\n\t\t*/\n\t\tconst_reference back() const\n\t\t{\n\t\t\tauto tmp = cend();\n\t\t\t--tmp;\n\t\t\treturn *tmp;\n\t\t}\n\n\t\t/*!\n\t\t@brief remove element given an iterator\n\n\t\tRemoves the element specified by iterator @a pos. The iterator @a pos must\n\t\tbe valid and dereferenceable. Thus the `end()` iterator (which is valid,\n\t\tbut is not dereferenceable) cannot be used as a value for @a pos.\n\n\t\tIf called on a primitive type other than `null`, the resulting JSON value\n\t\twill be `null`.\n\n\t\t@param[in] pos iterator to the element to remove\n\t\t@return Iterator following the last removed element. If the iterator @a\n\t\tpos refers to the last element, the `end()` iterator is returned.\n\n\t\t@tparam IteratorType an @ref iterator or @ref const_iterator\n\n\t\t@post Invalidates iterators and references at or after the point of the\n\t\terase, including the `end()` iterator.\n\n\t\t@throw type_error.307 if called on a `null` value; example: `\"cannot use\n\t\terase() with null\"`\n\t\t@throw invalid_iterator.202 if called on an iterator which does not belong\n\t\tto the current JSON value; example: `\"iterator does not fit current\n\t\tvalue\"`\n\t\t@throw invalid_iterator.205 if called on a primitive type with invalid\n\t\titerator (i.e., any iterator which is not `begin()`); example: `\"iterator\n\t\tout of range\"`\n\n\t\t@complexity The complexity depends on the type:\n\t\t- objects: amortized constant\n\t\t- arrays: linear in distance between @a pos and the end of the container\n\t\t- strings: linear in the length of the string\n\t\t- other types: constant\n\n\t\t@liveexample{The example shows the result of `erase()` for different JSON\n\t\ttypes.,erase__IteratorType}\n\n\t\t@sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n\t\tthe given range\n\t\t@sa @ref erase(const typename object_t::key_type&) -- removes the element\n\t\tfrom an object at the given key\n\t\t@sa @ref erase(const size_type) -- removes the element from an array at\n\t\tthe given index\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<class IteratorType, typename std::enable_if<\n\t\t\tstd::is_same<IteratorType, typename basic_json_t::iterator>::value or\n\t\t\tstd::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type\n\t\t\t= 0>\n\t\t\tIteratorType erase(IteratorType pos)\n\t\t{\n\t\t\t// make sure iterator fits the current value\n\t\t\tif (JSON_UNLIKELY(this != pos.m_object))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n\t\t\t}\n\n\t\t\tIteratorType result = end();\n\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::boolean:\n\t\t\tcase value_t::number_float:\n\t\t\tcase value_t::number_integer:\n\t\t\tcase value_t::number_unsigned:\n\t\t\tcase value_t::string:\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(205, \"iterator out of range\"));\n\t\t\t\t}\n\n\t\t\t\tif (is_string())\n\t\t\t\t{\n\t\t\t\t\tAllocatorType<string_t> alloc;\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n\t\t\t\t\tm_value.string = nullptr;\n\t\t\t\t}\n\n\t\t\t\tm_type = value_t::null;\n\t\t\t\tassert_invariant();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\tresult.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\tresult.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tJSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief remove elements given an iterator range\n\n\t\tRemoves the element specified by the range `[first; last)`. The iterator\n\t\t@a first does not need to be dereferenceable if `first == last`: erasing\n\t\tan empty range is a no-op.\n\n\t\tIf called on a primitive type other than `null`, the resulting JSON value\n\t\twill be `null`.\n\n\t\t@param[in] first iterator to the beginning of the range to remove\n\t\t@param[in] last iterator past the end of the range to remove\n\t\t@return Iterator following the last removed element. If the iterator @a\n\t\tsecond refers to the last element, the `end()` iterator is returned.\n\n\t\t@tparam IteratorType an @ref iterator or @ref const_iterator\n\n\t\t@post Invalidates iterators and references at or after the point of the\n\t\terase, including the `end()` iterator.\n\n\t\t@throw type_error.307 if called on a `null` value; example: `\"cannot use\n\t\terase() with null\"`\n\t\t@throw invalid_iterator.203 if called on iterators which does not belong\n\t\tto the current JSON value; example: `\"iterators do not fit current value\"`\n\t\t@throw invalid_iterator.204 if called on a primitive type with invalid\n\t\titerators (i.e., if `first != begin()` and `last != end()`); example:\n\t\t`\"iterators out of range\"`\n\n\t\t@complexity The complexity depends on the type:\n\t\t- objects: `log(size()) + std::distance(first, last)`\n\t\t- arrays: linear in the distance between @a first and @a last, plus linear\n\t\t  in the distance between @a last and end of the container\n\t\t- strings: linear in the length of the string\n\t\t- other types: constant\n\n\t\t@liveexample{The example shows the result of `erase()` for different JSON\n\t\ttypes.,erase__IteratorType_IteratorType}\n\n\t\t@sa @ref erase(IteratorType) -- removes the element at a given position\n\t\t@sa @ref erase(const typename object_t::key_type&) -- removes the element\n\t\tfrom an object at the given key\n\t\t@sa @ref erase(const size_type) -- removes the element from an array at\n\t\tthe given index\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<class IteratorType, typename std::enable_if<\n\t\t\tstd::is_same<IteratorType, typename basic_json_t::iterator>::value or\n\t\t\tstd::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type\n\t\t\t= 0>\n\t\t\tIteratorType erase(IteratorType first, IteratorType last)\n\t\t{\n\t\t\t// make sure iterator fits the current value\n\t\t\tif (JSON_UNLIKELY(this != first.m_object or this != last.m_object))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(203, \"iterators do not fit current value\"));\n\t\t\t}\n\n\t\t\tIteratorType result = end();\n\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::boolean:\n\t\t\tcase value_t::number_float:\n\t\t\tcase value_t::number_integer:\n\t\t\tcase value_t::number_unsigned:\n\t\t\tcase value_t::string:\n\t\t\t{\n\t\t\t\tif (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin()\n\t\t\t\t\tor not last.m_it.primitive_iterator.is_end()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n\t\t\t\t}\n\n\t\t\t\tif (is_string())\n\t\t\t\t{\n\t\t\t\t\tAllocatorType<string_t> alloc;\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n\t\t\t\t\tstd::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n\t\t\t\t\tm_value.string = nullptr;\n\t\t\t\t}\n\n\t\t\t\tm_type = value_t::null;\n\t\t\t\tassert_invariant();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\tresult.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,\n\t\t\t\t\tlast.m_it.object_iterator);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\tresult.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,\n\t\t\t\t\tlast.m_it.array_iterator);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tJSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief remove element from a JSON object given a key\n\n\t\tRemoves elements from a JSON object with the key value @a key.\n\n\t\t@param[in] key value of the elements to remove\n\n\t\t@return Number of elements removed. If @a ObjectType is the default\n\t\t`std::map` type, the return value will always be `0` (@a key was not\n\t\tfound) or `1` (@a key was found).\n\n\t\t@post References and iterators to the erased elements are invalidated.\n\t\tOther references and iterators are not affected.\n\n\t\t@throw type_error.307 when called on a type other than JSON object;\n\t\texample: `\"cannot use erase() with null\"`\n\n\t\t@complexity `log(size()) + count(key)`\n\n\t\t@liveexample{The example shows the effect of `erase()`.,erase__key_type}\n\n\t\t@sa @ref erase(IteratorType) -- removes the element at a given position\n\t\t@sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n\t\tthe given range\n\t\t@sa @ref erase(const size_type) -- removes the element from an array at\n\t\tthe given index\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tsize_type erase(const typename object_t::key_type& key)\n\t\t{\n\t\t\t// this erase only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\treturn m_value.object->erase(key);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief remove element from a JSON array given an index\n\n\t\tRemoves element from a JSON array at the index @a idx.\n\n\t\t@param[in] idx index of the element to remove\n\n\t\t@throw type_error.307 when called on a type other than JSON object;\n\t\texample: `\"cannot use erase() with null\"`\n\t\t@throw out_of_range.401 when `idx >= size()`; example: `\"array index 17\n\t\tis out of range\"`\n\n\t\t@complexity Linear in distance between @a idx and the end of the container.\n\n\t\t@liveexample{The example shows the effect of `erase()`.,erase__size_type}\n\n\t\t@sa @ref erase(IteratorType) -- removes the element at a given position\n\t\t@sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n\t\tthe given range\n\t\t@sa @ref erase(const typename object_t::key_type&) -- removes the element\n\t\tfrom an object at the given key\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid erase(const size_type idx)\n\t\t{\n\t\t\t// this erase only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\tif (JSON_UNLIKELY(idx >= size()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n\t\t\t\t}\n\n\t\t\t\tm_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/// @}\n\n\n\t\t////////////\n\t\t// lookup //\n\t\t////////////\n\n\t\t/// @name lookup\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief find an element in a JSON object\n\n\t\tFinds an element in a JSON object with key equivalent to @a key. If the\n\t\telement is not found or the JSON value is not an object, end() is\n\t\treturned.\n\n\t\t@note This method always returns @ref end() when executed on a JSON type\n\t\t\t  that is not an object.\n\n\t\t@param[in] key key value of the element to search for.\n\n\t\t@return Iterator to an element with key equivalent to @a key. If no such\n\t\telement is found or the JSON value is not an object, past-the-end (see\n\t\t@ref end()) iterator is returned.\n\n\t\t@complexity Logarithmic in the size of the JSON object.\n\n\t\t@liveexample{The example shows how `find()` is used.,find__key_type}\n\n\t\t@sa @ref contains(KeyT&&) const -- checks whether a key exists\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<typename KeyT>\n\t\titerator find(KeyT&& key)\n\t\t{\n\t\t\tauto result = end();\n\n\t\t\tif (is_object())\n\t\t\t{\n\t\t\t\tresult.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief find an element in a JSON object\n\t\t@copydoc find(KeyT&&)\n\t\t*/\n\t\ttemplate<typename KeyT>\n\t\tconst_iterator find(KeyT&& key) const\n\t\t{\n\t\t\tauto result = cend();\n\n\t\t\tif (is_object())\n\t\t\t{\n\t\t\t\tresult.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief returns the number of occurrences of a key in a JSON object\n\n\t\tReturns the number of elements with key @a key. If ObjectType is the\n\t\tdefault `std::map` type, the return value will always be `0` (@a key was\n\t\tnot found) or `1` (@a key was found).\n\n\t\t@note This method always returns `0` when executed on a JSON type that is\n\t\t\t  not an object.\n\n\t\t@param[in] key key value of the element to count\n\n\t\t@return Number of elements with key @a key. If the JSON value is not an\n\t\tobject, the return value will be `0`.\n\n\t\t@complexity Logarithmic in the size of the JSON object.\n\n\t\t@liveexample{The example shows how `count()` is used.,count}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\ttemplate<typename KeyT>\n\t\tsize_type count(KeyT&& key) const\n\t\t{\n\t\t\t// return 0 for all nonobject types\n\t\t\treturn is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;\n\t\t}\n\n\t\t/*!\n\t\t@brief check the existence of an element in a JSON object\n\n\t\tCheck whether an element exists in a JSON object with key equivalent to\n\t\t@a key. If the element is not found or the JSON value is not an object,\n\t\tfalse is returned.\n\n\t\t@note This method always returns false when executed on a JSON type\n\t\t\t  that is not an object.\n\n\t\t@param[in] key key value to check its existence.\n\n\t\t@return true if an element with specified @a key exists. If no such\n\t\telement with such key is found or the JSON value is not an object,\n\t\tfalse is returned.\n\n\t\t@complexity Logarithmic in the size of the JSON object.\n\n\t\t@liveexample{The following code shows an example for `contains()`.,contains}\n\n\t\t@sa @ref find(KeyT&&) -- returns an iterator to an object element\n\n\t\t@since version 3.6.0\n\t\t*/\n\t\ttemplate<typename KeyT>\n\t\tbool contains(KeyT&& key) const\n\t\t{\n\t\t\treturn is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();\n\t\t}\n\n\t\t/// @}\n\n\n\t\t///////////////\n\t\t// iterators //\n\t\t///////////////\n\n\t\t/// @name iterators\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief returns an iterator to the first element\n\n\t\tReturns an iterator to the first element.\n\n\t\t@image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n\t\t@return iterator to the first element\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\n\t\t@liveexample{The following code shows an example for `begin()`.,begin}\n\n\t\t@sa @ref cbegin() -- returns a const iterator to the beginning\n\t\t@sa @ref end() -- returns an iterator to the end\n\t\t@sa @ref cend() -- returns a const iterator to the end\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\titerator begin() noexcept\n\t\t{\n\t\t\titerator result(this);\n\t\t\tresult.set_begin();\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@copydoc basic_json::cbegin()\n\t\t*/\n\t\tconst_iterator begin() const noexcept\n\t\t{\n\t\t\treturn cbegin();\n\t\t}\n\n\t\t/*!\n\t\t@brief returns a const iterator to the first element\n\n\t\tReturns a const iterator to the first element.\n\n\t\t@image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n\t\t@return const iterator to the first element\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `const_cast<const basic_json&>(*this).begin()`.\n\n\t\t@liveexample{The following code shows an example for `cbegin()`.,cbegin}\n\n\t\t@sa @ref begin() -- returns an iterator to the beginning\n\t\t@sa @ref end() -- returns an iterator to the end\n\t\t@sa @ref cend() -- returns a const iterator to the end\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconst_iterator cbegin() const noexcept\n\t\t{\n\t\t\tconst_iterator result(this);\n\t\t\tresult.set_begin();\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief returns an iterator to one past the last element\n\n\t\tReturns an iterator to one past the last element.\n\n\t\t@image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n\t\t@return iterator one past the last element\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\n\t\t@liveexample{The following code shows an example for `end()`.,end}\n\n\t\t@sa @ref cend() -- returns a const iterator to the end\n\t\t@sa @ref begin() -- returns an iterator to the beginning\n\t\t@sa @ref cbegin() -- returns a const iterator to the beginning\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\titerator end() noexcept\n\t\t{\n\t\t\titerator result(this);\n\t\t\tresult.set_end();\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@copydoc basic_json::cend()\n\t\t*/\n\t\tconst_iterator end() const noexcept\n\t\t{\n\t\t\treturn cend();\n\t\t}\n\n\t\t/*!\n\t\t@brief returns a const iterator to one past the last element\n\n\t\tReturns a const iterator to one past the last element.\n\n\t\t@image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n\t\t@return const iterator one past the last element\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `const_cast<const basic_json&>(*this).end()`.\n\n\t\t@liveexample{The following code shows an example for `cend()`.,cend}\n\n\t\t@sa @ref end() -- returns an iterator to the end\n\t\t@sa @ref begin() -- returns an iterator to the beginning\n\t\t@sa @ref cbegin() -- returns a const iterator to the beginning\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconst_iterator cend() const noexcept\n\t\t{\n\t\t\tconst_iterator result(this);\n\t\t\tresult.set_end();\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief returns an iterator to the reverse-beginning\n\n\t\tReturns an iterator to the reverse-beginning; that is, the last element.\n\n\t\t@image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `reverse_iterator(end())`.\n\n\t\t@liveexample{The following code shows an example for `rbegin()`.,rbegin}\n\n\t\t@sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\t\t@sa @ref rend() -- returns a reverse iterator to the end\n\t\t@sa @ref crend() -- returns a const reverse iterator to the end\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\treverse_iterator rbegin() noexcept\n\t\t{\n\t\t\treturn reverse_iterator(end());\n\t\t}\n\n\t\t/*!\n\t\t@copydoc basic_json::crbegin()\n\t\t*/\n\t\tconst_reverse_iterator rbegin() const noexcept\n\t\t{\n\t\t\treturn crbegin();\n\t\t}\n\n\t\t/*!\n\t\t@brief returns an iterator to the reverse-end\n\n\t\tReturns an iterator to the reverse-end; that is, one before the first\n\t\telement.\n\n\t\t@image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `reverse_iterator(begin())`.\n\n\t\t@liveexample{The following code shows an example for `rend()`.,rend}\n\n\t\t@sa @ref crend() -- returns a const reverse iterator to the end\n\t\t@sa @ref rbegin() -- returns a reverse iterator to the beginning\n\t\t@sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\treverse_iterator rend() noexcept\n\t\t{\n\t\t\treturn reverse_iterator(begin());\n\t\t}\n\n\t\t/*!\n\t\t@copydoc basic_json::crend()\n\t\t*/\n\t\tconst_reverse_iterator rend() const noexcept\n\t\t{\n\t\t\treturn crend();\n\t\t}\n\n\t\t/*!\n\t\t@brief returns a const reverse iterator to the last element\n\n\t\tReturns a const iterator to the reverse-beginning; that is, the last\n\t\telement.\n\n\t\t@image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.\n\n\t\t@liveexample{The following code shows an example for `crbegin()`.,crbegin}\n\n\t\t@sa @ref rbegin() -- returns a reverse iterator to the beginning\n\t\t@sa @ref rend() -- returns a reverse iterator to the end\n\t\t@sa @ref crend() -- returns a const reverse iterator to the end\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconst_reverse_iterator crbegin() const noexcept\n\t\t{\n\t\t\treturn const_reverse_iterator(cend());\n\t\t}\n\n\t\t/*!\n\t\t@brief returns a const reverse iterator to one before the first\n\n\t\tReturns a const reverse iterator to the reverse-end; that is, one before\n\t\tthe first element.\n\n\t\t@image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n\t\t@complexity Constant.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `const_cast<const basic_json&>(*this).rend()`.\n\n\t\t@liveexample{The following code shows an example for `crend()`.,crend}\n\n\t\t@sa @ref rend() -- returns a reverse iterator to the end\n\t\t@sa @ref rbegin() -- returns a reverse iterator to the beginning\n\t\t@sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tconst_reverse_iterator crend() const noexcept\n\t\t{\n\t\t\treturn const_reverse_iterator(cbegin());\n\t\t}\n\n\tpublic:\n\t\t/*!\n\t\t@brief wrapper to access iterator member functions in range-based for\n\n\t\tThis function allows to access @ref iterator::key() and @ref\n\t\titerator::value() during range-based for loops. In these loops, a\n\t\treference to the JSON values is returned, so there is no access to the\n\t\tunderlying iterator.\n\n\t\tFor loop without iterator_wrapper:\n\n\t\t@code{cpp}\n\t\tfor (auto it = j_object.begin(); it != j_object.end(); ++it)\n\t\t{\n\t\t\tstd::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\tRange-based for loop without iterator proxy:\n\n\t\t@code{cpp}\n\t\tfor (auto it : j_object)\n\t\t{\n\t\t\t// \"it\" is of type json::reference and has no key() member\n\t\t\tstd::cout << \"value: \" << it << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\tRange-based for loop with iterator proxy:\n\n\t\t@code{cpp}\n\t\tfor (auto it : json::iterator_wrapper(j_object))\n\t\t{\n\t\t\tstd::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\t@note When iterating over an array, `key()` will return the index of the\n\t\t\t  element as string (see example).\n\n\t\t@param[in] ref  reference to a JSON value\n\t\t@return iteration proxy object wrapping @a ref with an interface to use in\n\t\t\t\trange-based for loops\n\n\t\t@liveexample{The following code shows how the wrapper is used,iterator_wrapper}\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@note The name of this function is not yet final and may change in the\n\t\tfuture.\n\n\t\t@deprecated This stream operator is deprecated and will be removed in\n\t\t\t\t\tfuture 4.0.0 of the library. Please use @ref items() instead;\n\t\t\t\t\tthat is, replace `json::iterator_wrapper(j)` with `j.items()`.\n\t\t*/\n\t\tJSON_DEPRECATED\n\t\t\tstatic iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept\n\t\t{\n\t\t\treturn ref.items();\n\t\t}\n\n\t\t/*!\n\t\t@copydoc iterator_wrapper(reference)\n\t\t*/\n\t\tJSON_DEPRECATED\n\t\t\tstatic iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept\n\t\t{\n\t\t\treturn ref.items();\n\t\t}\n\n\t\t/*!\n\t\t@brief helper to access iterator member functions in range-based for\n\n\t\tThis function allows to access @ref iterator::key() and @ref\n\t\titerator::value() during range-based for loops. In these loops, a\n\t\treference to the JSON values is returned, so there is no access to the\n\t\tunderlying iterator.\n\n\t\tFor loop without `items()` function:\n\n\t\t@code{cpp}\n\t\tfor (auto it = j_object.begin(); it != j_object.end(); ++it)\n\t\t{\n\t\t\tstd::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\tRange-based for loop without `items()` function:\n\n\t\t@code{cpp}\n\t\tfor (auto it : j_object)\n\t\t{\n\t\t\t// \"it\" is of type json::reference and has no key() member\n\t\t\tstd::cout << \"value: \" << it << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\tRange-based for loop with `items()` function:\n\n\t\t@code{cpp}\n\t\tfor (auto& el : j_object.items())\n\t\t{\n\t\t\tstd::cout << \"key: \" << el.key() << \", value:\" << el.value() << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\tThe `items()` function also allows to use\n\t\t[structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)\n\t\t(C++17):\n\n\t\t@code{cpp}\n\t\tfor (auto& [key, val] : j_object.items())\n\t\t{\n\t\t\tstd::cout << \"key: \" << key << \", value:\" << val << '\\n';\n\t\t}\n\t\t@endcode\n\n\t\t@note When iterating over an array, `key()` will return the index of the\n\t\t\t  element as string (see example). For primitive types (e.g., numbers),\n\t\t\t  `key()` returns an empty string.\n\n\t\t@return iteration proxy object wrapping @a ref with an interface to use in\n\t\t\t\trange-based for loops\n\n\t\t@liveexample{The following code shows how the function is used.,items}\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@since version 3.1.0, structured bindings support since 3.5.0.\n\t\t*/\n\t\titeration_proxy<iterator> items() noexcept\n\t\t{\n\t\t\treturn iteration_proxy<iterator>(*this);\n\t\t}\n\n\t\t/*!\n\t\t@copydoc items()\n\t\t*/\n\t\titeration_proxy<const_iterator> items() const noexcept\n\t\t{\n\t\t\treturn iteration_proxy<const_iterator>(*this);\n\t\t}\n\n\t\t/// @}\n\n\n\t\t//////////////\n\t\t// capacity //\n\t\t//////////////\n\n\t\t/// @name capacity\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief checks whether the container is empty.\n\n\t\tChecks if a JSON value has no elements (i.e. whether its @ref size is `0`).\n\n\t\t@return The return value depends on the different types and is\n\t\t\t\tdefined as follows:\n\t\t\t\tValue type  | return value\n\t\t\t\t----------- | -------------\n\t\t\t\tnull        | `true`\n\t\t\t\tboolean     | `false`\n\t\t\t\tstring      | `false`\n\t\t\t\tnumber      | `false`\n\t\t\t\tobject      | result of function `object_t::empty()`\n\t\t\t\tarray       | result of function `array_t::empty()`\n\n\t\t@liveexample{The following code uses `empty()` to check if a JSON\n\t\tobject contains any elements.,empty}\n\n\t\t@complexity Constant, as long as @ref array_t and @ref object_t satisfy\n\t\tthe Container concept; that is, their `empty()` functions have constant\n\t\tcomplexity.\n\n\t\t@iterators No changes.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@note This function does not return whether a string stored as JSON value\n\t\tis empty - it returns whether the JSON container itself is empty which is\n\t\tfalse in the case of a string.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `begin() == end()`.\n\n\t\t@sa @ref size() -- returns the number of elements\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tbool empty() const noexcept\n\t\t{\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::null:\n\t\t\t{\n\t\t\t\t// null values are empty\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\t// delegate call to array_t::empty()\n\t\t\t\treturn m_value.array->empty();\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\t// delegate call to object_t::empty()\n\t\t\t\treturn m_value.object->empty();\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// all other types are nonempty\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief returns the number of elements\n\n\t\tReturns the number of elements in a JSON value.\n\n\t\t@return The return value depends on the different types and is\n\t\t\t\tdefined as follows:\n\t\t\t\tValue type  | return value\n\t\t\t\t----------- | -------------\n\t\t\t\tnull        | `0`\n\t\t\t\tboolean     | `1`\n\t\t\t\tstring      | `1`\n\t\t\t\tnumber      | `1`\n\t\t\t\tobject      | result of function object_t::size()\n\t\t\t\tarray       | result of function array_t::size()\n\n\t\t@liveexample{The following code calls `size()` on the different value\n\t\ttypes.,size}\n\n\t\t@complexity Constant, as long as @ref array_t and @ref object_t satisfy\n\t\tthe Container concept; that is, their size() functions have constant\n\t\tcomplexity.\n\n\t\t@iterators No changes.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@note This function does not return the length of a string stored as JSON\n\t\tvalue - it returns the number of elements in the JSON value which is 1 in\n\t\tthe case of a string.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of `std::distance(begin(), end())`.\n\n\t\t@sa @ref empty() -- checks whether the container is empty\n\t\t@sa @ref max_size() -- returns the maximal number of elements\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tsize_type size() const noexcept\n\t\t{\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::null:\n\t\t\t{\n\t\t\t\t// null values are empty\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\t// delegate call to array_t::size()\n\t\t\t\treturn m_value.array->size();\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\t// delegate call to object_t::size()\n\t\t\t\treturn m_value.object->size();\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// all other types have size 1\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief returns the maximum possible number of elements\n\n\t\tReturns the maximum number of elements a JSON value is able to hold due to\n\t\tsystem or library implementation limitations, i.e. `std::distance(begin(),\n\t\tend())` for the JSON value.\n\n\t\t@return The return value depends on the different types and is\n\t\t\t\tdefined as follows:\n\t\t\t\tValue type  | return value\n\t\t\t\t----------- | -------------\n\t\t\t\tnull        | `0` (same as `size()`)\n\t\t\t\tboolean     | `1` (same as `size()`)\n\t\t\t\tstring      | `1` (same as `size()`)\n\t\t\t\tnumber      | `1` (same as `size()`)\n\t\t\t\tobject      | result of function `object_t::max_size()`\n\t\t\t\tarray       | result of function `array_t::max_size()`\n\n\t\t@liveexample{The following code calls `max_size()` on the different value\n\t\ttypes. Note the output is implementation specific.,max_size}\n\n\t\t@complexity Constant, as long as @ref array_t and @ref object_t satisfy\n\t\tthe Container concept; that is, their `max_size()` functions have constant\n\t\tcomplexity.\n\n\t\t@iterators No changes.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@requirement This function helps `basic_json` satisfying the\n\t\t[Container](https://en.cppreference.com/w/cpp/named_req/Container)\n\t\trequirements:\n\t\t- The complexity is constant.\n\t\t- Has the semantics of returning `b.size()` where `b` is the largest\n\t\t  possible JSON value.\n\n\t\t@sa @ref size() -- returns the number of elements\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tsize_type max_size() const noexcept\n\t\t{\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\t// delegate call to array_t::max_size()\n\t\t\t\treturn m_value.array->max_size();\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\t// delegate call to object_t::max_size()\n\t\t\t\treturn m_value.object->max_size();\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// all other types have max_size() == size()\n\t\t\t\treturn size();\n\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// @}\n\n\n\t\t///////////////\n\t\t// modifiers //\n\t\t///////////////\n\n\t\t/// @name modifiers\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief clears the contents\n\n\t\tClears the content of a JSON value and resets it to the default value as\n\t\tif @ref basic_json(value_t) would have been called with the current value\n\t\ttype from @ref type():\n\n\t\tValue type  | initial value\n\t\t----------- | -------------\n\t\tnull        | `null`\n\t\tboolean     | `false`\n\t\tstring      | `\"\"`\n\t\tnumber      | `0`\n\t\tobject      | `{}`\n\t\tarray       | `[]`\n\n\t\t@post Has the same effect as calling\n\t\t@code {.cpp}\n\t\t*this = basic_json(type());\n\t\t@endcode\n\n\t\t@liveexample{The example below shows the effect of `clear()` to different\n\t\tJSON types.,clear}\n\n\t\t@complexity Linear in the size of the JSON value.\n\n\t\t@iterators All iterators, pointers and references related to this container\n\t\t\t\t   are invalidated.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@sa @ref basic_json(value_t) -- constructor that creates an object with the\n\t\t\tsame value than calling `clear()`\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid clear() noexcept\n\t\t{\n\t\t\tswitch (m_type)\n\t\t\t{\n\t\t\tcase value_t::number_integer:\n\t\t\t{\n\t\t\t\tm_value.number_integer = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_unsigned:\n\t\t\t{\n\t\t\t\tm_value.number_unsigned = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::number_float:\n\t\t\t{\n\t\t\t\tm_value.number_float = 0.0;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::boolean:\n\t\t\t{\n\t\t\t\tm_value.boolean = false;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::string:\n\t\t\t{\n\t\t\t\tm_value.string->clear();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\tm_value.array->clear();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\tm_value.object->clear();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an array\n\n\t\tAppends the given element @a val to the end of the JSON value. If the\n\t\tfunction is called on a JSON null value, an empty array is created before\n\t\tappending @a val.\n\n\t\t@param[in] val the value to add to the JSON array\n\n\t\t@throw type_error.308 when called on a type other than JSON array or\n\t\tnull; example: `\"cannot use push_back() with number\"`\n\n\t\t@complexity Amortized constant.\n\n\t\t@liveexample{The example shows how `push_back()` and `+=` can be used to\n\t\tadd elements to a JSON array. Note how the `null` value was silently\n\t\tconverted to a JSON array.,push_back}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid push_back(basic_json&& val)\n\t\t{\n\t\t\t// push_back only works for null objects or arrays\n\t\t\tif (JSON_UNLIKELY(not(is_null() or is_array())))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// transform null object into an array\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::array;\n\t\t\t\tm_value = value_t::array;\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// add element to array (move semantics)\n\t\t\tm_value.array->push_back(std::move(val));\n\t\t\t// invalidate object: mark it null so we do not call the destructor\n\t\t\t// cppcheck-suppress accessMoved\n\t\t\tval.m_type = value_t::null;\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an array\n\t\t@copydoc push_back(basic_json&&)\n\t\t*/\n\t\treference operator+=(basic_json&& val)\n\t\t{\n\t\t\tpush_back(std::move(val));\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an array\n\t\t@copydoc push_back(basic_json&&)\n\t\t*/\n\t\tvoid push_back(const basic_json& val)\n\t\t{\n\t\t\t// push_back only works for null objects or arrays\n\t\t\tif (JSON_UNLIKELY(not(is_null() or is_array())))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// transform null object into an array\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::array;\n\t\t\t\tm_value = value_t::array;\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// add element to array\n\t\t\tm_value.array->push_back(val);\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an array\n\t\t@copydoc push_back(basic_json&&)\n\t\t*/\n\t\treference operator+=(const basic_json& val)\n\t\t{\n\t\t\tpush_back(val);\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an object\n\n\t\tInserts the given element @a val to the JSON object. If the function is\n\t\tcalled on a JSON null value, an empty object is created before inserting\n\t\t@a val.\n\n\t\t@param[in] val the value to add to the JSON object\n\n\t\t@throw type_error.308 when called on a type other than JSON object or\n\t\tnull; example: `\"cannot use push_back() with number\"`\n\n\t\t@complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n\t\t@liveexample{The example shows how `push_back()` and `+=` can be used to\n\t\tadd elements to a JSON object. Note how the `null` value was silently\n\t\tconverted to a JSON object.,push_back__object_t__value}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid push_back(const typename object_t::value_type& val)\n\t\t{\n\t\t\t// push_back only works for null objects or objects\n\t\t\tif (JSON_UNLIKELY(not(is_null() or is_object())))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// transform null object into an object\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value = value_t::object;\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// add element to array\n\t\t\tm_value.object->insert(val);\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an object\n\t\t@copydoc push_back(const typename object_t::value_type&)\n\t\t*/\n\t\treference operator+=(const typename object_t::value_type& val)\n\t\t{\n\t\t\tpush_back(val);\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an object\n\n\t\tThis function allows to use `push_back` with an initializer list. In case\n\n\t\t1. the current value is an object,\n\t\t2. the initializer list @a init contains only two elements, and\n\t\t3. the first element of @a init is a string,\n\n\t\t@a init is converted into an object element and added using\n\t\t@ref push_back(const typename object_t::value_type&). Otherwise, @a init\n\t\tis converted to a JSON value and added using @ref push_back(basic_json&&).\n\n\t\t@param[in] init  an initializer list\n\n\t\t@complexity Linear in the size of the initializer list @a init.\n\n\t\t@note This function is required to resolve an ambiguous overload error,\n\t\t\t  because pairs like `{\"key\", \"value\"}` can be both interpreted as\n\t\t\t  `object_t::value_type` or `std::initializer_list<basic_json>`, see\n\t\t\t  https://github.com/nlohmann/json/issues/235 for more information.\n\n\t\t@liveexample{The example shows how initializer lists are treated as\n\t\tobjects when possible.,push_back__initializer_list}\n\t\t*/\n\t\tvoid push_back(initializer_list_t init)\n\t\t{\n\t\t\tif (is_object() and init.size() == 2 and (*init.begin())->is_string())\n\t\t\t{\n\t\t\t\tbasic_json&& key = init.begin()->moved_or_copied();\n\t\t\t\tpush_back(typename object_t::value_type(\n\t\t\t\t\tstd::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpush_back(basic_json(init));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an object\n\t\t@copydoc push_back(initializer_list_t)\n\t\t*/\n\t\treference operator+=(initializer_list_t init)\n\t\t{\n\t\t\tpush_back(init);\n\t\t\treturn *this;\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an array\n\n\t\tCreates a JSON value from the passed parameters @a args to the end of the\n\t\tJSON value. If the function is called on a JSON null value, an empty array\n\t\tis created before appending the value created from @a args.\n\n\t\t@param[in] args arguments to forward to a constructor of @ref basic_json\n\t\t@tparam Args compatible types to create a @ref basic_json object\n\n\t\t@throw type_error.311 when called on a type other than JSON array or\n\t\tnull; example: `\"cannot use emplace_back() with number\"`\n\n\t\t@complexity Amortized constant.\n\n\t\t@liveexample{The example shows how `push_back()` can be used to add\n\t\telements to a JSON array. Note how the `null` value was silently converted\n\t\tto a JSON array.,emplace_back}\n\n\t\t@since version 2.0.8\n\t\t*/\n\t\ttemplate<class... Args>\n\t\tvoid emplace_back(Args&& ... args)\n\t\t{\n\t\t\t// emplace_back only works for null objects or arrays\n\t\t\tif (JSON_UNLIKELY(not(is_null() or is_array())))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(311, \"cannot use emplace_back() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// transform null object into an array\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::array;\n\t\t\t\tm_value = value_t::array;\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// add element to array (perfect forwarding)\n\t\t\tm_value.array->emplace_back(std::forward<Args>(args)...);\n\t\t}\n\n\t\t/*!\n\t\t@brief add an object to an object if key does not exist\n\n\t\tInserts a new element into a JSON object constructed in-place with the\n\t\tgiven @a args if there is no element with the key in the container. If the\n\t\tfunction is called on a JSON null value, an empty object is created before\n\t\tappending the value created from @a args.\n\n\t\t@param[in] args arguments to forward to a constructor of @ref basic_json\n\t\t@tparam Args compatible types to create a @ref basic_json object\n\n\t\t@return a pair consisting of an iterator to the inserted element, or the\n\t\t\t\talready-existing element if no insertion happened, and a bool\n\t\t\t\tdenoting whether the insertion took place.\n\n\t\t@throw type_error.311 when called on a type other than JSON object or\n\t\tnull; example: `\"cannot use emplace() with number\"`\n\n\t\t@complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n\t\t@liveexample{The example shows how `emplace()` can be used to add elements\n\t\tto a JSON object. Note how the `null` value was silently converted to a\n\t\tJSON object. Further note how no value is added if there was already one\n\t\tvalue stored with the same key.,emplace}\n\n\t\t@since version 2.0.8\n\t\t*/\n\t\ttemplate<class... Args>\n\t\tstd::pair<iterator, bool> emplace(Args&& ... args)\n\t\t{\n\t\t\t// emplace only works for null objects or arrays\n\t\t\tif (JSON_UNLIKELY(not(is_null() or is_object())))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(311, \"cannot use emplace() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// transform null object into an object\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value = value_t::object;\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\t// add element to array (perfect forwarding)\n\t\t\tauto res = m_value.object->emplace(std::forward<Args>(args)...);\n\t\t\t// create result iterator and set iterator to the result of emplace\n\t\t\tauto it = begin();\n\t\t\tit.m_it.object_iterator = res.first;\n\n\t\t\t// return pair of iterator and boolean\n\t\t\treturn { it, res.second };\n\t\t}\n\n\t\t/// Helper for insertion of an iterator\n\t\t/// @note: This uses std::distance to support GCC 4.8,\n\t\t///        see https://github.com/nlohmann/json/pull/1257\n\t\ttemplate<typename... Args>\n\t\titerator insert_iterator(const_iterator pos, Args&& ... args)\n\t\t{\n\t\t\titerator result(this);\n\t\t\tassert(m_value.array != nullptr);\n\n\t\t\tauto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);\n\t\t\tm_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);\n\t\t\tresult.m_it.array_iterator = m_value.array->begin() + insert_pos;\n\n\t\t\t// This could have been written as:\n\t\t\t// result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);\n\t\t\t// but the return value of insert is missing in GCC 4.8, so it is written this way instead.\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief inserts element\n\n\t\tInserts element @a val before iterator @a pos.\n\n\t\t@param[in] pos iterator before which the content will be inserted; may be\n\t\tthe end() iterator\n\t\t@param[in] val element to insert\n\t\t@return iterator pointing to the inserted @a val.\n\n\t\t@throw type_error.309 if called on JSON values other than arrays;\n\t\texample: `\"cannot use insert() with string\"`\n\t\t@throw invalid_iterator.202 if @a pos is not an iterator of *this;\n\t\texample: `\"iterator does not fit current value\"`\n\n\t\t@complexity Constant plus linear in the distance between @a pos and end of\n\t\tthe container.\n\n\t\t@liveexample{The example shows how `insert()` is used.,insert}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\titerator insert(const_iterator pos, const basic_json& val)\n\t\t{\n\t\t\t// insert only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\t// check if iterator pos fits to this JSON value\n\t\t\t\tif (JSON_UNLIKELY(pos.m_object != this))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n\t\t\t\t}\n\n\t\t\t\t// insert to array and return iterator\n\t\t\t\treturn insert_iterator(pos, val);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief inserts element\n\t\t@copydoc insert(const_iterator, const basic_json&)\n\t\t*/\n\t\titerator insert(const_iterator pos, basic_json&& val)\n\t\t{\n\t\t\treturn insert(pos, val);\n\t\t}\n\n\t\t/*!\n\t\t@brief inserts elements\n\n\t\tInserts @a cnt copies of @a val before iterator @a pos.\n\n\t\t@param[in] pos iterator before which the content will be inserted; may be\n\t\tthe end() iterator\n\t\t@param[in] cnt number of copies of @a val to insert\n\t\t@param[in] val element to insert\n\t\t@return iterator pointing to the first element inserted, or @a pos if\n\t\t`cnt==0`\n\n\t\t@throw type_error.309 if called on JSON values other than arrays; example:\n\t\t`\"cannot use insert() with string\"`\n\t\t@throw invalid_iterator.202 if @a pos is not an iterator of *this;\n\t\texample: `\"iterator does not fit current value\"`\n\n\t\t@complexity Linear in @a cnt plus linear in the distance between @a pos\n\t\tand end of the container.\n\n\t\t@liveexample{The example shows how `insert()` is used.,insert__count}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\titerator insert(const_iterator pos, size_type cnt, const basic_json& val)\n\t\t{\n\t\t\t// insert only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\t// check if iterator pos fits to this JSON value\n\t\t\t\tif (JSON_UNLIKELY(pos.m_object != this))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n\t\t\t\t}\n\n\t\t\t\t// insert to array and return iterator\n\t\t\t\treturn insert_iterator(pos, cnt, val);\n\t\t\t}\n\n\t\t\tJSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n\t\t}\n\n\t\t/*!\n\t\t@brief inserts elements\n\n\t\tInserts elements from range `[first, last)` before iterator @a pos.\n\n\t\t@param[in] pos iterator before which the content will be inserted; may be\n\t\tthe end() iterator\n\t\t@param[in] first begin of the range of elements to insert\n\t\t@param[in] last end of the range of elements to insert\n\n\t\t@throw type_error.309 if called on JSON values other than arrays; example:\n\t\t`\"cannot use insert() with string\"`\n\t\t@throw invalid_iterator.202 if @a pos is not an iterator of *this;\n\t\texample: `\"iterator does not fit current value\"`\n\t\t@throw invalid_iterator.210 if @a first and @a last do not belong to the\n\t\tsame JSON value; example: `\"iterators do not fit\"`\n\t\t@throw invalid_iterator.211 if @a first or @a last are iterators into\n\t\tcontainer for which insert is called; example: `\"passed iterators may not\n\t\tbelong to container\"`\n\n\t\t@return iterator pointing to the first element inserted, or @a pos if\n\t\t`first==last`\n\n\t\t@complexity Linear in `std::distance(first, last)` plus linear in the\n\t\tdistance between @a pos and end of the container.\n\n\t\t@liveexample{The example shows how `insert()` is used.,insert__range}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\titerator insert(const_iterator pos, const_iterator first, const_iterator last)\n\t\t{\n\t\t\t// insert only works for arrays\n\t\t\tif (JSON_UNLIKELY(not is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// check if iterator pos fits to this JSON value\n\t\t\tif (JSON_UNLIKELY(pos.m_object != this))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n\t\t\t}\n\n\t\t\t// check if range iterators belong to the same JSON object\n\t\t\tif (JSON_UNLIKELY(first.m_object != last.m_object))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n\t\t\t}\n\n\t\t\tif (JSON_UNLIKELY(first.m_object == this))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(211, \"passed iterators may not belong to container\"));\n\t\t\t}\n\n\t\t\t// insert to array and return iterator\n\t\t\treturn insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);\n\t\t}\n\n\t\t/*!\n\t\t@brief inserts elements\n\n\t\tInserts elements from initializer list @a ilist before iterator @a pos.\n\n\t\t@param[in] pos iterator before which the content will be inserted; may be\n\t\tthe end() iterator\n\t\t@param[in] ilist initializer list to insert the values from\n\n\t\t@throw type_error.309 if called on JSON values other than arrays; example:\n\t\t`\"cannot use insert() with string\"`\n\t\t@throw invalid_iterator.202 if @a pos is not an iterator of *this;\n\t\texample: `\"iterator does not fit current value\"`\n\n\t\t@return iterator pointing to the first element inserted, or @a pos if\n\t\t`ilist` is empty\n\n\t\t@complexity Linear in `ilist.size()` plus linear in the distance between\n\t\t@a pos and end of the container.\n\n\t\t@liveexample{The example shows how `insert()` is used.,insert__ilist}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\titerator insert(const_iterator pos, initializer_list_t ilist)\n\t\t{\n\t\t\t// insert only works for arrays\n\t\t\tif (JSON_UNLIKELY(not is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// check if iterator pos fits to this JSON value\n\t\t\tif (JSON_UNLIKELY(pos.m_object != this))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n\t\t\t}\n\n\t\t\t// insert to array and return iterator\n\t\t\treturn insert_iterator(pos, ilist.begin(), ilist.end());\n\t\t}\n\n\t\t/*!\n\t\t@brief inserts elements\n\n\t\tInserts elements from range `[first, last)`.\n\n\t\t@param[in] first begin of the range of elements to insert\n\t\t@param[in] last end of the range of elements to insert\n\n\t\t@throw type_error.309 if called on JSON values other than objects; example:\n\t\t`\"cannot use insert() with string\"`\n\t\t@throw invalid_iterator.202 if iterator @a first or @a last does does not\n\t\tpoint to an object; example: `\"iterators first and last must point to\n\t\tobjects\"`\n\t\t@throw invalid_iterator.210 if @a first and @a last do not belong to the\n\t\tsame JSON value; example: `\"iterators do not fit\"`\n\n\t\t@complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number\n\t\tof elements to insert.\n\n\t\t@liveexample{The example shows how `insert()` is used.,insert__range_object}\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tvoid insert(const_iterator first, const_iterator last)\n\t\t{\n\t\t\t// insert only works for objects\n\t\t\tif (JSON_UNLIKELY(not is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// check if range iterators belong to the same JSON object\n\t\t\tif (JSON_UNLIKELY(first.m_object != last.m_object))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n\t\t\t}\n\n\t\t\t// passed iterators must belong to objects\n\t\t\tif (JSON_UNLIKELY(not first.m_object->is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n\t\t\t}\n\n\t\t\tm_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);\n\t\t}\n\n\t\t/*!\n\t\t@brief updates a JSON object from another object, overwriting existing keys\n\n\t\tInserts all values from JSON object @a j and overwrites existing keys.\n\n\t\t@param[in] j  JSON object to read values from\n\n\t\t@throw type_error.312 if called on JSON values other than objects; example:\n\t\t`\"cannot use update() with string\"`\n\n\t\t@complexity O(N*log(size() + N)), where N is the number of elements to\n\t\t\t\t\tinsert.\n\n\t\t@liveexample{The example shows how `update()` is used.,update}\n\n\t\t@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tvoid update(const_reference j)\n\t\t{\n\t\t\t// implicitly convert null value to an empty object\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value.object = create<object_t>();\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\tif (JSON_UNLIKELY(not is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n\t\t\t}\n\t\t\tif (JSON_UNLIKELY(not j.is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(j.type_name())));\n\t\t\t}\n\n\t\t\tfor (auto it = j.cbegin(); it != j.cend(); ++it)\n\t\t\t{\n\t\t\t\tm_value.object->operator[](it.key()) = it.value();\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief updates a JSON object from another object, overwriting existing keys\n\n\t\tInserts all values from from range `[first, last)` and overwrites existing\n\t\tkeys.\n\n\t\t@param[in] first begin of the range of elements to insert\n\t\t@param[in] last end of the range of elements to insert\n\n\t\t@throw type_error.312 if called on JSON values other than objects; example:\n\t\t`\"cannot use update() with string\"`\n\t\t@throw invalid_iterator.202 if iterator @a first or @a last does does not\n\t\tpoint to an object; example: `\"iterators first and last must point to\n\t\tobjects\"`\n\t\t@throw invalid_iterator.210 if @a first and @a last do not belong to the\n\t\tsame JSON value; example: `\"iterators do not fit\"`\n\n\t\t@complexity O(N*log(size() + N)), where N is the number of elements to\n\t\t\t\t\tinsert.\n\n\t\t@liveexample{The example shows how `update()` is used__range.,update}\n\n\t\t@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tvoid update(const_iterator first, const_iterator last)\n\t\t{\n\t\t\t// implicitly convert null value to an empty object\n\t\t\tif (is_null())\n\t\t\t{\n\t\t\t\tm_type = value_t::object;\n\t\t\t\tm_value.object = create<object_t>();\n\t\t\t\tassert_invariant();\n\t\t\t}\n\n\t\t\tif (JSON_UNLIKELY(not is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n\t\t\t}\n\n\t\t\t// check if range iterators belong to the same JSON object\n\t\t\tif (JSON_UNLIKELY(first.m_object != last.m_object))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n\t\t\t}\n\n\t\t\t// passed iterators must belong to objects\n\t\t\tif (JSON_UNLIKELY(not first.m_object->is_object()\n\t\t\t\tor not last.m_object->is_object()))\n\t\t\t{\n\t\t\t\tJSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n\t\t\t}\n\n\t\t\tfor (auto it = first; it != last; ++it)\n\t\t\t{\n\t\t\t\tm_value.object->operator[](it.key()) = it.value();\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief exchanges the values\n\n\t\tExchanges the contents of the JSON value with those of @a other. Does not\n\t\tinvoke any move, copy, or swap operations on individual elements. All\n\t\titerators and references remain valid. The past-the-end iterator is\n\t\tinvalidated.\n\n\t\t@param[in,out] other JSON value to exchange the contents with\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how JSON values can be swapped with\n\t\t`swap()`.,swap__reference}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid swap(reference other) noexcept (\n\t\t\tstd::is_nothrow_move_constructible<value_t>::value and\n\t\t\tstd::is_nothrow_move_assignable<value_t>::value and\n\t\t\tstd::is_nothrow_move_constructible<json_value>::value and\n\t\t\tstd::is_nothrow_move_assignable<json_value>::value\n\t\t\t)\n\t\t{\n\t\t\tstd::swap(m_type, other.m_type);\n\t\t\tstd::swap(m_value, other.m_value);\n\t\t\tassert_invariant();\n\t\t}\n\n\t\t/*!\n\t\t@brief exchanges the values\n\n\t\tExchanges the contents of a JSON array with those of @a other. Does not\n\t\tinvoke any move, copy, or swap operations on individual elements. All\n\t\titerators and references remain valid. The past-the-end iterator is\n\t\tinvalidated.\n\n\t\t@param[in,out] other array to exchange the contents with\n\n\t\t@throw type_error.310 when JSON value is not an array; example: `\"cannot\n\t\tuse swap() with string\"`\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how arrays can be swapped with\n\t\t`swap()`.,swap__array_t}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid swap(array_t& other)\n\t\t{\n\t\t\t// swap only works for arrays\n\t\t\tif (JSON_LIKELY(is_array()))\n\t\t\t{\n\t\t\t\tstd::swap(*(m_value.array), other);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief exchanges the values\n\n\t\tExchanges the contents of a JSON object with those of @a other. Does not\n\t\tinvoke any move, copy, or swap operations on individual elements. All\n\t\titerators and references remain valid. The past-the-end iterator is\n\t\tinvalidated.\n\n\t\t@param[in,out] other object to exchange the contents with\n\n\t\t@throw type_error.310 when JSON value is not an object; example:\n\t\t`\"cannot use swap() with string\"`\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how objects can be swapped with\n\t\t`swap()`.,swap__object_t}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid swap(object_t& other)\n\t\t{\n\t\t\t// swap only works for objects\n\t\t\tif (JSON_LIKELY(is_object()))\n\t\t\t{\n\t\t\t\tstd::swap(*(m_value.object), other);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/*!\n\t\t@brief exchanges the values\n\n\t\tExchanges the contents of a JSON string with those of @a other. Does not\n\t\tinvoke any move, copy, or swap operations on individual elements. All\n\t\titerators and references remain valid. The past-the-end iterator is\n\t\tinvalidated.\n\n\t\t@param[in,out] other string to exchange the contents with\n\n\t\t@throw type_error.310 when JSON value is not a string; example: `\"cannot\n\t\tuse swap() with boolean\"`\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The example below shows how strings can be swapped with\n\t\t`swap()`.,swap__string_t}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tvoid swap(string_t& other)\n\t\t{\n\t\t\t// swap only works for strings\n\t\t\tif (JSON_LIKELY(is_string()))\n\t\t\t{\n\t\t\t\tstd::swap(*(m_value.string), other);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tJSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n\t\t\t}\n\t\t}\n\n\t\t/// @}\n\n\tpublic:\n\t\t//////////////////////////////////////////\n\t\t// lexicographical comparison operators //\n\t\t//////////////////////////////////////////\n\n\t\t/// @name lexicographical comparison operators\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief comparison: equal\n\n\t\tCompares two JSON values for equality according to the following rules:\n\t\t- Two JSON values are equal if (1) they are from the same type and (2)\n\t\t  their stored values are the same according to their respective\n\t\t  `operator==`.\n\t\t- Integer and floating-point numbers are automatically converted before\n\t\t  comparison. Note than two NaN values are always treated as unequal.\n\t\t- Two JSON null values are equal.\n\n\t\t@note Floating-point inside JSON values numbers are compared with\n\t\t`json::number_float_t::operator==` which is `double::operator==` by\n\t\tdefault. To compare floating-point while respecting an epsilon, an alternative\n\t\t[comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)\n\t\tcould be used, for instance\n\t\t@code {.cpp}\n\t\ttemplate<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>\n\t\tinline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept\n\t\t{\n\t\t\treturn std::abs(a - b) <= epsilon;\n\t\t}\n\t\t@endcode\n\n\t\t@note NaN values never compare equal to themselves or to other NaN values.\n\n\t\t@param[in] lhs  first JSON value to consider\n\t\t@param[in] rhs  second JSON value to consider\n\t\t@return whether the values @a lhs and @a rhs are equal\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@complexity Linear.\n\n\t\t@liveexample{The example demonstrates comparing several JSON\n\t\ttypes.,operator__equal}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend bool operator==(const_reference lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\tconst auto lhs_type = lhs.type();\n\t\t\tconst auto rhs_type = rhs.type();\n\n\t\t\tif (lhs_type == rhs_type)\n\t\t\t{\n\t\t\t\tswitch (lhs_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn *lhs.m_value.array == *rhs.m_value.array;\n\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn *lhs.m_value.object == *rhs.m_value.object;\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t\treturn true;\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t\treturn *lhs.m_value.string == *rhs.m_value.string;\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t\treturn lhs.m_value.boolean == rhs.m_value.boolean;\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t\treturn lhs.m_value.number_integer == rhs.m_value.number_integer;\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t\treturn lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t\treturn lhs.m_value.number_float == rhs.m_value.number_float;\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)\n\t\t\t{\n\t\t\t\treturn static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)\n\t\t\t{\n\t\t\t\treturn lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)\n\t\t\t{\n\t\t\t\treturn static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)\n\t\t\t{\n\t\t\t\treturn lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)\n\t\t\t{\n\t\t\t\treturn static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)\n\t\t\t{\n\t\t\t\treturn lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: equal\n\t\t@copydoc operator==(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator==(const_reference lhs, const ScalarType rhs) noexcept\n\t\t{\n\t\t\treturn lhs == basic_json(rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: equal\n\t\t@copydoc operator==(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator==(const ScalarType lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn basic_json(lhs) == rhs;\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: not equal\n\n\t\tCompares two JSON values for inequality by calculating `not (lhs == rhs)`.\n\n\t\t@param[in] lhs  first JSON value to consider\n\t\t@param[in] rhs  second JSON value to consider\n\t\t@return whether the values @a lhs and @a rhs are not equal\n\n\t\t@complexity Linear.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@liveexample{The example demonstrates comparing several JSON\n\t\ttypes.,operator__notequal}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend bool operator!=(const_reference lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn not (lhs == rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: not equal\n\t\t@copydoc operator!=(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept\n\t\t{\n\t\t\treturn lhs != basic_json(rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: not equal\n\t\t@copydoc operator!=(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn basic_json(lhs) != rhs;\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: less than\n\n\t\tCompares whether one JSON value @a lhs is less than another JSON value @a\n\t\trhs according to the following rules:\n\t\t- If @a lhs and @a rhs have the same type, the values are compared using\n\t\t  the default `<` operator.\n\t\t- Integer and floating-point numbers are automatically converted before\n\t\t  comparison\n\t\t- In case @a lhs and @a rhs have different types, the values are ignored\n\t\t  and the order of the types is considered, see\n\t\t  @ref operator<(const value_t, const value_t).\n\n\t\t@param[in] lhs  first JSON value to consider\n\t\t@param[in] rhs  second JSON value to consider\n\t\t@return whether @a lhs is less than @a rhs\n\n\t\t@complexity Linear.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@liveexample{The example demonstrates comparing several JSON\n\t\ttypes.,operator__less}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend bool operator<(const_reference lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\tconst auto lhs_type = lhs.type();\n\t\t\tconst auto rhs_type = rhs.type();\n\n\t\t\tif (lhs_type == rhs_type)\n\t\t\t{\n\t\t\t\tswitch (lhs_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::array:\n\t\t\t\t\t// note parentheses are necessary, see\n\t\t\t\t\t// https://github.com/nlohmann/json/issues/1530\n\t\t\t\t\treturn (*lhs.m_value.array) < (*rhs.m_value.array);\n\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn *lhs.m_value.object < *rhs.m_value.object;\n\n\t\t\t\tcase value_t::null:\n\t\t\t\t\treturn false;\n\n\t\t\t\tcase value_t::string:\n\t\t\t\t\treturn *lhs.m_value.string < *rhs.m_value.string;\n\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t\treturn lhs.m_value.boolean < rhs.m_value.boolean;\n\n\t\t\t\tcase value_t::number_integer:\n\t\t\t\t\treturn lhs.m_value.number_integer < rhs.m_value.number_integer;\n\n\t\t\t\tcase value_t::number_unsigned:\n\t\t\t\t\treturn lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;\n\n\t\t\t\tcase value_t::number_float:\n\t\t\t\t\treturn lhs.m_value.number_float < rhs.m_value.number_float;\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)\n\t\t\t{\n\t\t\t\treturn static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)\n\t\t\t{\n\t\t\t\treturn lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)\n\t\t\t{\n\t\t\t\treturn static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)\n\t\t\t{\n\t\t\t\treturn lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)\n\t\t\t{\n\t\t\t\treturn lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n\t\t\t}\n\t\t\telse if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)\n\t\t\t{\n\t\t\t\treturn static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;\n\t\t\t}\n\n\t\t\t// We only reach this line if we cannot compare values. In that case,\n\t\t\t// we compare types. Note we have to call the operator explicitly,\n\t\t\t// because MSVC has problems otherwise.\n\t\t\treturn operator<(lhs_type, rhs_type);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: less than\n\t\t@copydoc operator<(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator<(const_reference lhs, const ScalarType rhs) noexcept\n\t\t{\n\t\t\treturn lhs < basic_json(rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: less than\n\t\t@copydoc operator<(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator<(const ScalarType lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn basic_json(lhs) < rhs;\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: less than or equal\n\n\t\tCompares whether one JSON value @a lhs is less than or equal to another\n\t\tJSON value by calculating `not (rhs < lhs)`.\n\n\t\t@param[in] lhs  first JSON value to consider\n\t\t@param[in] rhs  second JSON value to consider\n\t\t@return whether @a lhs is less than or equal to @a rhs\n\n\t\t@complexity Linear.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@liveexample{The example demonstrates comparing several JSON\n\t\ttypes.,operator__greater}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend bool operator<=(const_reference lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn not (rhs < lhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: less than or equal\n\t\t@copydoc operator<=(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept\n\t\t{\n\t\t\treturn lhs <= basic_json(rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: less than or equal\n\t\t@copydoc operator<=(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn basic_json(lhs) <= rhs;\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: greater than\n\n\t\tCompares whether one JSON value @a lhs is greater than another\n\t\tJSON value by calculating `not (lhs <= rhs)`.\n\n\t\t@param[in] lhs  first JSON value to consider\n\t\t@param[in] rhs  second JSON value to consider\n\t\t@return whether @a lhs is greater than to @a rhs\n\n\t\t@complexity Linear.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@liveexample{The example demonstrates comparing several JSON\n\t\ttypes.,operator__lessequal}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend bool operator>(const_reference lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn not (lhs <= rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: greater than\n\t\t@copydoc operator>(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator>(const_reference lhs, const ScalarType rhs) noexcept\n\t\t{\n\t\t\treturn lhs > basic_json(rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: greater than\n\t\t@copydoc operator>(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator>(const ScalarType lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn basic_json(lhs) > rhs;\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: greater than or equal\n\n\t\tCompares whether one JSON value @a lhs is greater than or equal to another\n\t\tJSON value by calculating `not (lhs < rhs)`.\n\n\t\t@param[in] lhs  first JSON value to consider\n\t\t@param[in] rhs  second JSON value to consider\n\t\t@return whether @a lhs is greater than or equal to @a rhs\n\n\t\t@complexity Linear.\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@liveexample{The example demonstrates comparing several JSON\n\t\ttypes.,operator__greaterequal}\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend bool operator>=(const_reference lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn not (lhs < rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: greater than or equal\n\t\t@copydoc operator>=(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept\n\t\t{\n\t\t\treturn lhs >= basic_json(rhs);\n\t\t}\n\n\t\t/*!\n\t\t@brief comparison: greater than or equal\n\t\t@copydoc operator>=(const_reference, const_reference)\n\t\t*/\n\t\ttemplate<typename ScalarType, typename std::enable_if<\n\t\t\tstd::is_scalar<ScalarType>::value, int>::type = 0>\n\t\t\tfriend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept\n\t\t{\n\t\t\treturn basic_json(lhs) >= rhs;\n\t\t}\n\n\t\t/// @}\n\n\t\t///////////////////\n\t\t// serialization //\n\t\t///////////////////\n\n\t\t/// @name serialization\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief serialize to stream\n\n\t\tSerialize the given JSON value @a j to the output stream @a o. The JSON\n\t\tvalue will be serialized using the @ref dump member function.\n\n\t\t- The indentation of the output can be controlled with the member variable\n\t\t  `width` of the output stream @a o. For instance, using the manipulator\n\t\t  `std::setw(4)` on @a o sets the indentation level to `4` and the\n\t\t  serialization result is the same as calling `dump(4)`.\n\n\t\t- The indentation character can be controlled with the member variable\n\t\t  `fill` of the output stream @a o. For instance, the manipulator\n\t\t  `std::setfill('\\\\t')` sets indentation to use a tab character rather than\n\t\t  the default space character.\n\n\t\t@param[in,out] o  stream to serialize to\n\t\t@param[in] j  JSON value to serialize\n\n\t\t@return the stream @a o\n\n\t\t@throw type_error.316 if a string stored inside the JSON value is not\n\t\t\t\t\t\t\t  UTF-8 encoded\n\n\t\t@complexity Linear.\n\n\t\t@liveexample{The example below shows the serialization with different\n\t\tparameters to `width` to adjust the indentation level.,operator_serialize}\n\n\t\t@since version 1.0.0; indentation character added in version 3.0.0\n\t\t*/\n\t\tfriend std::ostream& operator<<(std::ostream& o, const basic_json& j)\n\t\t{\n\t\t\t// read width member and use it as indentation parameter if nonzero\n\t\t\tconst bool pretty_print = o.width() > 0;\n\t\t\tconst auto indentation = pretty_print ? o.width() : 0;\n\n\t\t\t// reset width to 0 for subsequent calls to this stream\n\t\t\to.width(0);\n\n\t\t\t// do the actual serialization\n\t\t\tserializer s(detail::output_adapter<char>(o), o.fill());\n\t\t\ts.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));\n\t\t\treturn o;\n\t\t}\n\n\t\t/*!\n\t\t@brief serialize to stream\n\t\t@deprecated This stream operator is deprecated and will be removed in\n\t\t\t\t\tfuture 4.0.0 of the library. Please use\n\t\t\t\t\t@ref operator<<(std::ostream&, const basic_json&)\n\t\t\t\t\tinstead; that is, replace calls like `j >> o;` with `o << j;`.\n\t\t@since version 1.0.0; deprecated since version 3.0.0\n\t\t*/\n\t\tJSON_DEPRECATED\n\t\t\tfriend std::ostream& operator>>(const basic_json& j, std::ostream& o)\n\t\t{\n\t\t\treturn o << j;\n\t\t}\n\n\t\t/// @}\n\n\n\t\t/////////////////////\n\t\t// deserialization //\n\t\t/////////////////////\n\n\t\t/// @name deserialization\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief deserialize from a compatible input\n\n\t\tThis function reads from a compatible input. Examples are:\n\t\t- an array of 1-byte values\n\t\t- strings with character/literal type with size of 1 byte\n\t\t- input streams\n\t\t- container with contiguous storage of 1-byte values. Compatible container\n\t\t  types include `std::vector`, `std::string`, `std::array`,\n\t\t  `std::valarray`, and `std::initializer_list`. Furthermore, C-style\n\t\t  arrays can be used with `std::begin()`/`std::end()`. User-defined\n\t\t  containers can be used as long as they implement random-access iterators\n\t\t  and a contiguous storage.\n\n\t\t@pre Each element of the container has a size of 1 byte. Violating this\n\t\tprecondition yields undefined behavior. **This precondition is enforced\n\t\twith a static assertion.**\n\n\t\t@pre The container storage is contiguous. Violating this precondition\n\t\tyields undefined behavior. **This precondition is enforced with an\n\t\tassertion.**\n\n\t\t@warning There is no way to enforce all preconditions at compile-time. If\n\t\t\t\t the function is called with a noncompliant container and with\n\t\t\t\t assertions switched off, the behavior is undefined and will most\n\t\t\t\t likely yield segmentation violation.\n\n\t\t@param[in] i  input to read from\n\t\t@param[in] cb  a parser callback function of type @ref parser_callback_t\n\t\twhich is used to control the deserialization by filtering unwanted values\n\t\t(optional)\n\t\t@param[in] allow_exceptions  whether to throw exceptions in case of a\n\t\tparse error (optional, true by default)\n\n\t\t@return deserialized JSON value; in case of a parse error and\n\t\t\t\t@a allow_exceptions set to `false`, the return value will be\n\t\t\t\tvalue_t::discarded.\n\n\t\t@throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n\t\tof input; expected string literal\"\"`\n\t\t@throw parse_error.102 if to_unicode fails or surrogate error\n\t\t@throw parse_error.103 if to_unicode fails\n\n\t\t@complexity Linear in the length of the input. The parser is a predictive\n\t\tLL(1) parser. The complexity can be higher if the parser callback function\n\t\t@a cb has a super-linear complexity.\n\n\t\t@note A UTF-8 byte order mark is silently ignored.\n\n\t\t@liveexample{The example below demonstrates the `parse()` function reading\n\t\tfrom an array.,parse__array__parser_callback_t}\n\n\t\t@liveexample{The example below demonstrates the `parse()` function with\n\t\tand without callback function.,parse__string__parser_callback_t}\n\n\t\t@liveexample{The example below demonstrates the `parse()` function with\n\t\tand without callback function.,parse__istream__parser_callback_t}\n\n\t\t@liveexample{The example below demonstrates the `parse()` function reading\n\t\tfrom a contiguous container.,parse__contiguouscontainer__parser_callback_t}\n\n\t\t@since version 2.0.3 (contiguous containers)\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json parse(detail::input_adapter&& i,\n\t\t\t\tconst parser_callback_t cb = nullptr,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tparser(i, cb, allow_exceptions).parse(true, result);\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic bool accept(detail::input_adapter&& i)\n\t\t{\n\t\t\treturn parser(i).accept(true);\n\t\t}\n\n\t\t/*!\n\t\t@brief generate SAX events\n\n\t\tThe SAX event lister must follow the interface of @ref json_sax.\n\n\t\tThis function reads from a compatible input. Examples are:\n\t\t- an array of 1-byte values\n\t\t- strings with character/literal type with size of 1 byte\n\t\t- input streams\n\t\t- container with contiguous storage of 1-byte values. Compatible container\n\t\t  types include `std::vector`, `std::string`, `std::array`,\n\t\t  `std::valarray`, and `std::initializer_list`. Furthermore, C-style\n\t\t  arrays can be used with `std::begin()`/`std::end()`. User-defined\n\t\t  containers can be used as long as they implement random-access iterators\n\t\t  and a contiguous storage.\n\n\t\t@pre Each element of the container has a size of 1 byte. Violating this\n\t\tprecondition yields undefined behavior. **This precondition is enforced\n\t\twith a static assertion.**\n\n\t\t@pre The container storage is contiguous. Violating this precondition\n\t\tyields undefined behavior. **This precondition is enforced with an\n\t\tassertion.**\n\n\t\t@warning There is no way to enforce all preconditions at compile-time. If\n\t\t\t\t the function is called with a noncompliant container and with\n\t\t\t\t assertions switched off, the behavior is undefined and will most\n\t\t\t\t likely yield segmentation violation.\n\n\t\t@param[in] i  input to read from\n\t\t@param[in,out] sax  SAX event listener\n\t\t@param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)\n\t\t@param[in] strict  whether the input has to be consumed completely\n\n\t\t@return return value of the last processed SAX event\n\n\t\t@throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n\t\tof input; expected string literal\"\"`\n\t\t@throw parse_error.102 if to_unicode fails or surrogate error\n\t\t@throw parse_error.103 if to_unicode fails\n\n\t\t@complexity Linear in the length of the input. The parser is a predictive\n\t\tLL(1) parser. The complexity can be higher if the SAX consumer @a sax has\n\t\ta super-linear complexity.\n\n\t\t@note A UTF-8 byte order mark is silently ignored.\n\n\t\t@liveexample{The example below demonstrates the `sax_parse()` function\n\t\treading from string and processing the events with a user-defined SAX\n\t\tevent consumer.,sax_parse}\n\n\t\t@since version 3.2.0\n\t\t*/\n\t\ttemplate <typename SAX>\n\t\tstatic bool sax_parse(detail::input_adapter&& i, SAX* sax,\n\t\t\tinput_format_t format = input_format_t::json,\n\t\t\tconst bool strict = true)\n\t\t{\n\t\t\tassert(sax);\n\t\t\treturn format == input_format_t::json\n\t\t\t\t? parser(std::move(i)).sax_parse(sax, strict)\n\t\t\t\t: detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);\n\t\t}\n\n\t\t/*!\n\t\t@brief deserialize from an iterator range with contiguous storage\n\n\t\tThis function reads from an iterator range of a container with contiguous\n\t\tstorage of 1-byte values. Compatible container types include\n\t\t`std::vector`, `std::string`, `std::array`, `std::valarray`, and\n\t\t`std::initializer_list`. Furthermore, C-style arrays can be used with\n\t\t`std::begin()`/`std::end()`. User-defined containers can be used as long\n\t\tas they implement random-access iterators and a contiguous storage.\n\n\t\t@pre The iterator range is contiguous. Violating this precondition yields\n\t\tundefined behavior. **This precondition is enforced with an assertion.**\n\t\t@pre Each element in the range has a size of 1 byte. Violating this\n\t\tprecondition yields undefined behavior. **This precondition is enforced\n\t\twith a static assertion.**\n\n\t\t@warning There is no way to enforce all preconditions at compile-time. If\n\t\t\t\t the function is called with noncompliant iterators and with\n\t\t\t\t assertions switched off, the behavior is undefined and will most\n\t\t\t\t likely yield segmentation violation.\n\n\t\t@tparam IteratorType iterator of container with contiguous storage\n\t\t@param[in] first  begin of the range to parse (included)\n\t\t@param[in] last  end of the range to parse (excluded)\n\t\t@param[in] cb  a parser callback function of type @ref parser_callback_t\n\t\twhich is used to control the deserialization by filtering unwanted values\n\t\t(optional)\n\t\t@param[in] allow_exceptions  whether to throw exceptions in case of a\n\t\tparse error (optional, true by default)\n\n\t\t@return deserialized JSON value; in case of a parse error and\n\t\t\t\t@a allow_exceptions set to `false`, the return value will be\n\t\t\t\tvalue_t::discarded.\n\n\t\t@throw parse_error.101 in case of an unexpected token\n\t\t@throw parse_error.102 if to_unicode fails or surrogate error\n\t\t@throw parse_error.103 if to_unicode fails\n\n\t\t@complexity Linear in the length of the input. The parser is a predictive\n\t\tLL(1) parser. The complexity can be higher if the parser callback function\n\t\t@a cb has a super-linear complexity.\n\n\t\t@note A UTF-8 byte order mark is silently ignored.\n\n\t\t@liveexample{The example below demonstrates the `parse()` function reading\n\t\tfrom an iterator range.,parse__iteratortype__parser_callback_t}\n\n\t\t@since version 2.0.3\n\t\t*/\n\t\ttemplate<class IteratorType, typename std::enable_if<\n\t\t\tstd::is_base_of<\n\t\t\tstd::random_access_iterator_tag,\n\t\t\ttypename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n\t\t\tstatic basic_json parse(IteratorType first, IteratorType last,\n\t\t\t\tconst parser_callback_t cb = nullptr,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tparser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result);\n\t\t\treturn result;\n\t\t}\n\n\t\ttemplate<class IteratorType, typename std::enable_if<\n\t\t\tstd::is_base_of<\n\t\t\tstd::random_access_iterator_tag,\n\t\t\ttypename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n\t\t\tstatic bool accept(IteratorType first, IteratorType last)\n\t\t{\n\t\t\treturn parser(detail::input_adapter(first, last)).accept(true);\n\t\t}\n\n\t\ttemplate<class IteratorType, class SAX, typename std::enable_if<\n\t\t\tstd::is_base_of<\n\t\t\tstd::random_access_iterator_tag,\n\t\t\ttypename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n\t\t\tstatic bool sax_parse(IteratorType first, IteratorType last, SAX* sax)\n\t\t{\n\t\t\treturn parser(detail::input_adapter(first, last)).sax_parse(sax);\n\t\t}\n\n\t\t/*!\n\t\t@brief deserialize from stream\n\t\t@deprecated This stream operator is deprecated and will be removed in\n\t\t\t\t\tversion 4.0.0 of the library. Please use\n\t\t\t\t\t@ref operator>>(std::istream&, basic_json&)\n\t\t\t\t\tinstead; that is, replace calls like `j << i;` with `i >> j;`.\n\t\t@since version 1.0.0; deprecated since version 3.0.0\n\t\t*/\n\t\tJSON_DEPRECATED\n\t\t\tfriend std::istream& operator<<(basic_json& j, std::istream& i)\n\t\t{\n\t\t\treturn operator>>(i, j);\n\t\t}\n\n\t\t/*!\n\t\t@brief deserialize from stream\n\n\t\tDeserializes an input stream to a JSON value.\n\n\t\t@param[in,out] i  input stream to read a serialized JSON value from\n\t\t@param[in,out] j  JSON value to write the deserialized input to\n\n\t\t@throw parse_error.101 in case of an unexpected token\n\t\t@throw parse_error.102 if to_unicode fails or surrogate error\n\t\t@throw parse_error.103 if to_unicode fails\n\n\t\t@complexity Linear in the length of the input. The parser is a predictive\n\t\tLL(1) parser.\n\n\t\t@note A UTF-8 byte order mark is silently ignored.\n\n\t\t@liveexample{The example below shows how a JSON value is constructed by\n\t\treading a serialization from a stream.,operator_deserialize}\n\n\t\t@sa parse(std::istream&, const parser_callback_t) for a variant with a\n\t\tparser callback function to filter values while parsing\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tfriend std::istream& operator>>(std::istream& i, basic_json& j)\n\t\t{\n\t\t\tparser(detail::input_adapter(i)).parse(false, j);\n\t\t\treturn i;\n\t\t}\n\n\t\t/// @}\n\n\t\t///////////////////////////\n\t\t// convenience functions //\n\t\t///////////////////////////\n\n\t\t/*!\n\t\t@brief return the type as string\n\n\t\tReturns the type name as string to be used in error messages - usually to\n\t\tindicate that a function was called on a wrong JSON type.\n\n\t\t@return a string representation of a the @a m_type member:\n\t\t\t\tValue type  | return value\n\t\t\t\t----------- | -------------\n\t\t\t\tnull        | `\"null\"`\n\t\t\t\tboolean     | `\"boolean\"`\n\t\t\t\tstring      | `\"string\"`\n\t\t\t\tnumber      | `\"number\"` (for all number types)\n\t\t\t\tobject      | `\"object\"`\n\t\t\t\tarray       | `\"array\"`\n\t\t\t\tdiscarded   | `\"discarded\"`\n\n\t\t@exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n\t\t@complexity Constant.\n\n\t\t@liveexample{The following code exemplifies `type_name()` for all JSON\n\t\ttypes.,type_name}\n\n\t\t@sa @ref type() -- return the type of the JSON value\n\t\t@sa @ref operator value_t() -- return the type of the JSON value (implicit)\n\n\t\t@since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`\n\t\tsince 3.0.0\n\t\t*/\n\t\tconst char* type_name() const noexcept\n\t\t{\n\t\t\t{\n\t\t\t\tswitch (m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::null:\n\t\t\t\t\treturn \"null\";\n\t\t\t\tcase value_t::object:\n\t\t\t\t\treturn \"object\";\n\t\t\t\tcase value_t::array:\n\t\t\t\t\treturn \"array\";\n\t\t\t\tcase value_t::string:\n\t\t\t\t\treturn \"string\";\n\t\t\t\tcase value_t::boolean:\n\t\t\t\t\treturn \"boolean\";\n\t\t\t\tcase value_t::discarded:\n\t\t\t\t\treturn \"discarded\";\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"number\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\tprivate:\n\t\t//////////////////////\n\t\t// member variables //\n\t\t//////////////////////\n\n\t\t/// the type of the current element\n\t\tvalue_t m_type = value_t::null;\n\n\t\t/// the value of the current element\n\t\tjson_value m_value = {};\n\n\t\t//////////////////////////////////////////\n\t\t// binary serialization/deserialization //\n\t\t//////////////////////////////////////////\n\n\t\t/// @name binary serialization/deserialization support\n\t\t/// @{\n\n\tpublic:\n\t\t/*!\n\t\t@brief create a CBOR serialization of a given JSON value\n\n\t\tSerializes a given JSON value @a j to a byte vector using the CBOR (Concise\n\t\tBinary Object Representation) serialization format. CBOR is a binary\n\t\tserialization format which aims to be more compact than JSON itself, yet\n\t\tmore efficient to parse.\n\n\t\tThe library uses the following mapping from JSON values types to\n\t\tCBOR types according to the CBOR specification (RFC 7049):\n\n\t\tJSON value type | value/range                                | CBOR type                          | first byte\n\t\t--------------- | ------------------------------------------ | ---------------------------------- | ---------------\n\t\tnull            | `null`                                     | Null                               | 0xF6\n\t\tboolean         | `true`                                     | True                               | 0xF5\n\t\tboolean         | `false`                                    | False                              | 0xF4\n\t\tnumber_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B\n\t\tnumber_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A\n\t\tnumber_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39\n\t\tnumber_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38\n\t\tnumber_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37\n\t\tnumber_integer  | 0..23                                      | Integer                            | 0x00..0x17\n\t\tnumber_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n\t\tnumber_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n\t\tnumber_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n\t\tnumber_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n\t\tnumber_unsigned | 0..23                                      | Integer                            | 0x00..0x17\n\t\tnumber_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n\t\tnumber_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n\t\tnumber_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n\t\tnumber_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n\t\tnumber_float    | *any value*                                | Double-Precision Float             | 0xFB\n\t\tstring          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77\n\t\tstring          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78\n\t\tstring          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79\n\t\tstring          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A\n\t\tstring          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B\n\t\tarray           | *size*: 0..23                              | array                              | 0x80..0x97\n\t\tarray           | *size*: 23..255                            | array (1 byte follow)              | 0x98\n\t\tarray           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99\n\t\tarray           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A\n\t\tarray           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B\n\t\tobject          | *size*: 0..23                              | map                                | 0xA0..0xB7\n\t\tobject          | *size*: 23..255                            | map (1 byte follow)                | 0xB8\n\t\tobject          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9\n\t\tobject          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA\n\t\tobject          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB\n\n\t\t@note The mapping is **complete** in the sense that any JSON value type\n\t\t\t  can be converted to a CBOR value.\n\n\t\t@note If NaN or Infinity are stored inside a JSON number, they are\n\t\t\t  serialized properly. This behavior differs from the @ref dump()\n\t\t\t  function which serializes NaN or Infinity to `null`.\n\n\t\t@note The following CBOR types are not used in the conversion:\n\t\t\t  - byte strings (0x40..0x5F)\n\t\t\t  - UTF-8 strings terminated by \"break\" (0x7F)\n\t\t\t  - arrays terminated by \"break\" (0x9F)\n\t\t\t  - maps terminated by \"break\" (0xBF)\n\t\t\t  - date/time (0xC0..0xC1)\n\t\t\t  - bignum (0xC2..0xC3)\n\t\t\t  - decimal fraction (0xC4)\n\t\t\t  - bigfloat (0xC5)\n\t\t\t  - tagged items (0xC6..0xD4, 0xD8..0xDB)\n\t\t\t  - expected conversions (0xD5..0xD7)\n\t\t\t  - simple values (0xE0..0xF3, 0xF8)\n\t\t\t  - undefined (0xF7)\n\t\t\t  - half and single-precision floats (0xF9-0xFA)\n\t\t\t  - break (0xFF)\n\n\t\t@param[in] j  JSON value to serialize\n\t\t@return MessagePack serialization as byte vector\n\n\t\t@complexity Linear in the size of the JSON value @a j.\n\n\t\t@liveexample{The example shows the serialization of a JSON value to a byte\n\t\tvector in CBOR format.,to_cbor}\n\n\t\t@sa http://cbor.io\n\t\t@sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n\t\t\tanalogous deserialization\n\t\t@sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n\t\t@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n\t\t\t\t related UBJSON format\n\n\t\t@since version 2.0.9\n\t\t*/\n\t\tstatic std::vector<uint8_t> to_cbor(const basic_json& j)\n\t\t{\n\t\t\tstd::vector<uint8_t> result;\n\t\t\tto_cbor(j, result);\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)\n\t\t{\n\t\t\tbinary_writer<uint8_t>(o).write_cbor(j);\n\t\t}\n\n\t\tstatic void to_cbor(const basic_json& j, detail::output_adapter<char> o)\n\t\t{\n\t\t\tbinary_writer<char>(o).write_cbor(j);\n\t\t}\n\n\t\t/*!\n\t\t@brief create a MessagePack serialization of a given JSON value\n\n\t\tSerializes a given JSON value @a j to a byte vector using the MessagePack\n\t\tserialization format. MessagePack is a binary serialization format which\n\t\taims to be more compact than JSON itself, yet more efficient to parse.\n\n\t\tThe library uses the following mapping from JSON values types to\n\t\tMessagePack types according to the MessagePack specification:\n\n\t\tJSON value type | value/range                       | MessagePack type | first byte\n\t\t--------------- | --------------------------------- | ---------------- | ----------\n\t\tnull            | `null`                            | nil              | 0xC0\n\t\tboolean         | `true`                            | true             | 0xC3\n\t\tboolean         | `false`                           | false            | 0xC2\n\t\tnumber_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3\n\t\tnumber_integer  | -2147483648..-32769               | int32            | 0xD2\n\t\tnumber_integer  | -32768..-129                      | int16            | 0xD1\n\t\tnumber_integer  | -128..-33                         | int8             | 0xD0\n\t\tnumber_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF\n\t\tnumber_integer  | 0..127                            | positive fixint  | 0x00..0x7F\n\t\tnumber_integer  | 128..255                          | uint 8           | 0xCC\n\t\tnumber_integer  | 256..65535                        | uint 16          | 0xCD\n\t\tnumber_integer  | 65536..4294967295                 | uint 32          | 0xCE\n\t\tnumber_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF\n\t\tnumber_unsigned | 0..127                            | positive fixint  | 0x00..0x7F\n\t\tnumber_unsigned | 128..255                          | uint 8           | 0xCC\n\t\tnumber_unsigned | 256..65535                        | uint 16          | 0xCD\n\t\tnumber_unsigned | 65536..4294967295                 | uint 32          | 0xCE\n\t\tnumber_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF\n\t\tnumber_float    | *any value*                       | float 64         | 0xCB\n\t\tstring          | *length*: 0..31                   | fixstr           | 0xA0..0xBF\n\t\tstring          | *length*: 32..255                 | str 8            | 0xD9\n\t\tstring          | *length*: 256..65535              | str 16           | 0xDA\n\t\tstring          | *length*: 65536..4294967295       | str 32           | 0xDB\n\t\tarray           | *size*: 0..15                     | fixarray         | 0x90..0x9F\n\t\tarray           | *size*: 16..65535                 | array 16         | 0xDC\n\t\tarray           | *size*: 65536..4294967295         | array 32         | 0xDD\n\t\tobject          | *size*: 0..15                     | fix map          | 0x80..0x8F\n\t\tobject          | *size*: 16..65535                 | map 16           | 0xDE\n\t\tobject          | *size*: 65536..4294967295         | map 32           | 0xDF\n\n\t\t@note The mapping is **complete** in the sense that any JSON value type\n\t\t\t  can be converted to a MessagePack value.\n\n\t\t@note The following values can **not** be converted to a MessagePack value:\n\t\t\t  - strings with more than 4294967295 bytes\n\t\t\t  - arrays with more than 4294967295 elements\n\t\t\t  - objects with more than 4294967295 elements\n\n\t\t@note The following MessagePack types are not used in the conversion:\n\t\t\t  - bin 8 - bin 32 (0xC4..0xC6)\n\t\t\t  - ext 8 - ext 32 (0xC7..0xC9)\n\t\t\t  - float 32 (0xCA)\n\t\t\t  - fixext 1 - fixext 16 (0xD4..0xD8)\n\n\t\t@note Any MessagePack output created @ref to_msgpack can be successfully\n\t\t\t  parsed by @ref from_msgpack.\n\n\t\t@note If NaN or Infinity are stored inside a JSON number, they are\n\t\t\t  serialized properly. This behavior differs from the @ref dump()\n\t\t\t  function which serializes NaN or Infinity to `null`.\n\n\t\t@param[in] j  JSON value to serialize\n\t\t@return MessagePack serialization as byte vector\n\n\t\t@complexity Linear in the size of the JSON value @a j.\n\n\t\t@liveexample{The example shows the serialization of a JSON value to a byte\n\t\tvector in MessagePack format.,to_msgpack}\n\n\t\t@sa http://msgpack.org\n\t\t@sa @ref from_msgpack for the analogous deserialization\n\t\t@sa @ref to_cbor(const basic_json& for the related CBOR format\n\t\t@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n\t\t\t\t related UBJSON format\n\n\t\t@since version 2.0.9\n\t\t*/\n\t\tstatic std::vector<uint8_t> to_msgpack(const basic_json& j)\n\t\t{\n\t\t\tstd::vector<uint8_t> result;\n\t\t\tto_msgpack(j, result);\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)\n\t\t{\n\t\t\tbinary_writer<uint8_t>(o).write_msgpack(j);\n\t\t}\n\n\t\tstatic void to_msgpack(const basic_json& j, detail::output_adapter<char> o)\n\t\t{\n\t\t\tbinary_writer<char>(o).write_msgpack(j);\n\t\t}\n\n\t\t/*!\n\t\t@brief create a UBJSON serialization of a given JSON value\n\n\t\tSerializes a given JSON value @a j to a byte vector using the UBJSON\n\t\t(Universal Binary JSON) serialization format. UBJSON aims to be more compact\n\t\tthan JSON itself, yet more efficient to parse.\n\n\t\tThe library uses the following mapping from JSON values types to\n\t\tUBJSON types according to the UBJSON specification:\n\n\t\tJSON value type | value/range                       | UBJSON type | marker\n\t\t--------------- | --------------------------------- | ----------- | ------\n\t\tnull            | `null`                            | null        | `Z`\n\t\tboolean         | `true`                            | true        | `T`\n\t\tboolean         | `false`                           | false       | `F`\n\t\tnumber_integer  | -9223372036854775808..-2147483649 | int64       | `L`\n\t\tnumber_integer  | -2147483648..-32769               | int32       | `l`\n\t\tnumber_integer  | -32768..-129                      | int16       | `I`\n\t\tnumber_integer  | -128..127                         | int8        | `i`\n\t\tnumber_integer  | 128..255                          | uint8       | `U`\n\t\tnumber_integer  | 256..32767                        | int16       | `I`\n\t\tnumber_integer  | 32768..2147483647                 | int32       | `l`\n\t\tnumber_integer  | 2147483648..9223372036854775807   | int64       | `L`\n\t\tnumber_unsigned | 0..127                            | int8        | `i`\n\t\tnumber_unsigned | 128..255                          | uint8       | `U`\n\t\tnumber_unsigned | 256..32767                        | int16       | `I`\n\t\tnumber_unsigned | 32768..2147483647                 | int32       | `l`\n\t\tnumber_unsigned | 2147483648..9223372036854775807   | int64       | `L`\n\t\tnumber_float    | *any value*                       | float64     | `D`\n\t\tstring          | *with shortest length indicator*  | string      | `S`\n\t\tarray           | *see notes on optimized format*   | array       | `[`\n\t\tobject          | *see notes on optimized format*   | map         | `{`\n\n\t\t@note The mapping is **complete** in the sense that any JSON value type\n\t\t\t  can be converted to a UBJSON value.\n\n\t\t@note The following values can **not** be converted to a UBJSON value:\n\t\t\t  - strings with more than 9223372036854775807 bytes (theoretical)\n\t\t\t  - unsigned integer numbers above 9223372036854775807\n\n\t\t@note The following markers are not used in the conversion:\n\t\t\t  - `Z`: no-op values are not created.\n\t\t\t  - `C`: single-byte strings are serialized with `S` markers.\n\n\t\t@note Any UBJSON output created @ref to_ubjson can be successfully parsed\n\t\t\t  by @ref from_ubjson.\n\n\t\t@note If NaN or Infinity are stored inside a JSON number, they are\n\t\t\t  serialized properly. This behavior differs from the @ref dump()\n\t\t\t  function which serializes NaN or Infinity to `null`.\n\n\t\t@note The optimized formats for containers are supported: Parameter\n\t\t\t  @a use_size adds size information to the beginning of a container and\n\t\t\t  removes the closing marker. Parameter @a use_type further checks\n\t\t\t  whether all elements of a container have the same type and adds the\n\t\t\t  type marker to the beginning of the container. The @a use_type\n\t\t\t  parameter must only be used together with @a use_size = true. Note\n\t\t\t  that @a use_size = true alone may result in larger representations -\n\t\t\t  the benefit of this parameter is that the receiving side is\n\t\t\t  immediately informed on the number of elements of the container.\n\n\t\t@param[in] j  JSON value to serialize\n\t\t@param[in] use_size  whether to add size annotations to container types\n\t\t@param[in] use_type  whether to add type annotations to container types\n\t\t\t\t\t\t\t (must be combined with @a use_size = true)\n\t\t@return UBJSON serialization as byte vector\n\n\t\t@complexity Linear in the size of the JSON value @a j.\n\n\t\t@liveexample{The example shows the serialization of a JSON value to a byte\n\t\tvector in UBJSON format.,to_ubjson}\n\n\t\t@sa http://ubjson.org\n\t\t@sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n\t\t\tanalogous deserialization\n\t\t@sa @ref to_cbor(const basic_json& for the related CBOR format\n\t\t@sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n\n\t\t@since version 3.1.0\n\t\t*/\n\t\tstatic std::vector<uint8_t> to_ubjson(const basic_json& j,\n\t\t\tconst bool use_size = false,\n\t\t\tconst bool use_type = false)\n\t\t{\n\t\t\tstd::vector<uint8_t> result;\n\t\t\tto_ubjson(j, result, use_size, use_type);\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,\n\t\t\tconst bool use_size = false, const bool use_type = false)\n\t\t{\n\t\t\tbinary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);\n\t\t}\n\n\t\tstatic void to_ubjson(const basic_json& j, detail::output_adapter<char> o,\n\t\t\tconst bool use_size = false, const bool use_type = false)\n\t\t{\n\t\t\tbinary_writer<char>(o).write_ubjson(j, use_size, use_type);\n\t\t}\n\n\n\t\t/*!\n\t\t@brief Serializes the given JSON object `j` to BSON and returns a vector\n\t\t\t   containing the corresponding BSON-representation.\n\n\t\tBSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are\n\t\tstored as a single entity (a so-called document).\n\n\t\tThe library uses the following mapping from JSON values types to BSON types:\n\n\t\tJSON value type | value/range                       | BSON type   | marker\n\t\t--------------- | --------------------------------- | ----------- | ------\n\t\tnull            | `null`                            | null        | 0x0A\n\t\tboolean         | `true`, `false`                   | boolean     | 0x08\n\t\tnumber_integer  | -9223372036854775808..-2147483649 | int64       | 0x12\n\t\tnumber_integer  | -2147483648..2147483647           | int32       | 0x10\n\t\tnumber_integer  | 2147483648..9223372036854775807   | int64       | 0x12\n\t\tnumber_unsigned | 0..2147483647                     | int32       | 0x10\n\t\tnumber_unsigned | 2147483648..9223372036854775807   | int64       | 0x12\n\t\tnumber_unsigned | 9223372036854775808..18446744073709551615| --   | --\n\t\tnumber_float    | *any value*                       | double      | 0x01\n\t\tstring          | *any value*                       | string      | 0x02\n\t\tarray           | *any value*                       | document    | 0x04\n\t\tobject          | *any value*                       | document    | 0x03\n\n\t\t@warning The mapping is **incomplete**, since only JSON-objects (and things\n\t\tcontained therein) can be serialized to BSON.\n\t\tAlso, integers larger than 9223372036854775807 cannot be serialized to BSON,\n\t\tand the keys may not contain U+0000, since they are serialized a\n\t\tzero-terminated c-strings.\n\n\t\t@throw out_of_range.407  if `j.is_number_unsigned() && j.get<std::uint64_t>() > 9223372036854775807`\n\t\t@throw out_of_range.409  if a key in `j` contains a NULL (U+0000)\n\t\t@throw type_error.317    if `!j.is_object()`\n\n\t\t@pre The input `j` is required to be an object: `j.is_object() == true`.\n\n\t\t@note Any BSON output created via @ref to_bson can be successfully parsed\n\t\t\t  by @ref from_bson.\n\n\t\t@param[in] j  JSON value to serialize\n\t\t@return BSON serialization as byte vector\n\n\t\t@complexity Linear in the size of the JSON value @a j.\n\n\t\t@liveexample{The example shows the serialization of a JSON value to a byte\n\t\tvector in BSON format.,to_bson}\n\n\t\t@sa http://bsonspec.org/spec.html\n\t\t@sa @ref from_bson(detail::input_adapter&&, const bool strict) for the\n\t\t\tanalogous deserialization\n\t\t@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n\t\t\t\t related UBJSON format\n\t\t@sa @ref to_cbor(const basic_json&) for the related CBOR format\n\t\t@sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n\t\t*/\n\t\tstatic std::vector<uint8_t> to_bson(const basic_json& j)\n\t\t{\n\t\t\tstd::vector<uint8_t> result;\n\t\t\tto_bson(j, result);\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief Serializes the given JSON object `j` to BSON and forwards the\n\t\t\t   corresponding BSON-representation to the given output_adapter `o`.\n\t\t@param j The JSON object to convert to BSON.\n\t\t@param o The output adapter that receives the binary BSON representation.\n\t\t@pre The input `j` shall be an object: `j.is_object() == true`\n\t\t@sa @ref to_bson(const basic_json&)\n\t\t*/\n\t\tstatic void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)\n\t\t{\n\t\t\tbinary_writer<uint8_t>(o).write_bson(j);\n\t\t}\n\n\t\t/*!\n\t\t@copydoc to_bson(const basic_json&, detail::output_adapter<uint8_t>)\n\t\t*/\n\t\tstatic void to_bson(const basic_json& j, detail::output_adapter<char> o)\n\t\t{\n\t\t\tbinary_writer<char>(o).write_bson(j);\n\t\t}\n\n\n\t\t/*!\n\t\t@brief create a JSON value from an input in CBOR format\n\n\t\tDeserializes a given input @a i to a JSON value using the CBOR (Concise\n\t\tBinary Object Representation) serialization format.\n\n\t\tThe library maps CBOR types to JSON value types as follows:\n\n\t\tCBOR type              | JSON value type | first byte\n\t\t---------------------- | --------------- | ----------\n\t\tInteger                | number_unsigned | 0x00..0x17\n\t\tUnsigned integer       | number_unsigned | 0x18\n\t\tUnsigned integer       | number_unsigned | 0x19\n\t\tUnsigned integer       | number_unsigned | 0x1A\n\t\tUnsigned integer       | number_unsigned | 0x1B\n\t\tNegative integer       | number_integer  | 0x20..0x37\n\t\tNegative integer       | number_integer  | 0x38\n\t\tNegative integer       | number_integer  | 0x39\n\t\tNegative integer       | number_integer  | 0x3A\n\t\tNegative integer       | number_integer  | 0x3B\n\t\tNegative integer       | number_integer  | 0x40..0x57\n\t\tUTF-8 string           | string          | 0x60..0x77\n\t\tUTF-8 string           | string          | 0x78\n\t\tUTF-8 string           | string          | 0x79\n\t\tUTF-8 string           | string          | 0x7A\n\t\tUTF-8 string           | string          | 0x7B\n\t\tUTF-8 string           | string          | 0x7F\n\t\tarray                  | array           | 0x80..0x97\n\t\tarray                  | array           | 0x98\n\t\tarray                  | array           | 0x99\n\t\tarray                  | array           | 0x9A\n\t\tarray                  | array           | 0x9B\n\t\tarray                  | array           | 0x9F\n\t\tmap                    | object          | 0xA0..0xB7\n\t\tmap                    | object          | 0xB8\n\t\tmap                    | object          | 0xB9\n\t\tmap                    | object          | 0xBA\n\t\tmap                    | object          | 0xBB\n\t\tmap                    | object          | 0xBF\n\t\tFalse                  | `false`         | 0xF4\n\t\tTrue                   | `true`          | 0xF5\n\t\tNull                   | `null`          | 0xF6\n\t\tHalf-Precision Float   | number_float    | 0xF9\n\t\tSingle-Precision Float | number_float    | 0xFA\n\t\tDouble-Precision Float | number_float    | 0xFB\n\n\t\t@warning The mapping is **incomplete** in the sense that not all CBOR\n\t\t\t\t types can be converted to a JSON value. The following CBOR types\n\t\t\t\t are not supported and will yield parse errors (parse_error.112):\n\t\t\t\t - byte strings (0x40..0x5F)\n\t\t\t\t - date/time (0xC0..0xC1)\n\t\t\t\t - bignum (0xC2..0xC3)\n\t\t\t\t - decimal fraction (0xC4)\n\t\t\t\t - bigfloat (0xC5)\n\t\t\t\t - tagged items (0xC6..0xD4, 0xD8..0xDB)\n\t\t\t\t - expected conversions (0xD5..0xD7)\n\t\t\t\t - simple values (0xE0..0xF3, 0xF8)\n\t\t\t\t - undefined (0xF7)\n\n\t\t@warning CBOR allows map keys of any type, whereas JSON only allows\n\t\t\t\t strings as keys in object values. Therefore, CBOR maps with keys\n\t\t\t\t other than UTF-8 strings are rejected (parse_error.113).\n\n\t\t@note Any CBOR output created @ref to_cbor can be successfully parsed by\n\t\t\t  @ref from_cbor.\n\n\t\t@param[in] i  an input in CBOR format convertible to an input adapter\n\t\t@param[in] strict  whether to expect the input to be consumed until EOF\n\t\t\t\t\t\t   (true by default)\n\t\t@param[in] allow_exceptions  whether to throw exceptions in case of a\n\t\tparse error (optional, true by default)\n\n\t\t@return deserialized JSON value; in case of a parse error and\n\t\t\t\t@a allow_exceptions set to `false`, the return value will be\n\t\t\t\tvalue_t::discarded.\n\n\t\t@throw parse_error.110 if the given input ends prematurely or the end of\n\t\tfile was not reached when @a strict was set to true\n\t\t@throw parse_error.112 if unsupported features from CBOR were\n\t\tused in the given input @a v or if the input is not valid CBOR\n\t\t@throw parse_error.113 if a string was expected as map key, but not found\n\n\t\t@complexity Linear in the size of the input @a i.\n\n\t\t@liveexample{The example shows the deserialization of a byte vector in CBOR\n\t\tformat to a JSON value.,from_cbor}\n\n\t\t@sa http://cbor.io\n\t\t@sa @ref to_cbor(const basic_json&) for the analogous serialization\n\t\t@sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the\n\t\t\trelated MessagePack format\n\t\t@sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n\t\t\trelated UBJSON format\n\n\t\t@since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n\t\t\t   consume input adapters, removed start_index parameter, and added\n\t\t\t   @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n\t\t\t   since 3.2.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_cbor(detail::input_adapter&& i,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@copydoc from_cbor(detail::input_adapter&&, const bool, const bool)\n\t\t*/\n\t\ttemplate<typename A1, typename A2,\n\t\t\tdetail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n\t\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_cbor(A1 && a1, A2 && a2,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@brief create a JSON value from an input in MessagePack format\n\n\t\tDeserializes a given input @a i to a JSON value using the MessagePack\n\t\tserialization format.\n\n\t\tThe library maps MessagePack types to JSON value types as follows:\n\n\t\tMessagePack type | JSON value type | first byte\n\t\t---------------- | --------------- | ----------\n\t\tpositive fixint  | number_unsigned | 0x00..0x7F\n\t\tfixmap           | object          | 0x80..0x8F\n\t\tfixarray         | array           | 0x90..0x9F\n\t\tfixstr           | string          | 0xA0..0xBF\n\t\tnil              | `null`          | 0xC0\n\t\tfalse            | `false`         | 0xC2\n\t\ttrue             | `true`          | 0xC3\n\t\tfloat 32         | number_float    | 0xCA\n\t\tfloat 64         | number_float    | 0xCB\n\t\tuint 8           | number_unsigned | 0xCC\n\t\tuint 16          | number_unsigned | 0xCD\n\t\tuint 32          | number_unsigned | 0xCE\n\t\tuint 64          | number_unsigned | 0xCF\n\t\tint 8            | number_integer  | 0xD0\n\t\tint 16           | number_integer  | 0xD1\n\t\tint 32           | number_integer  | 0xD2\n\t\tint 64           | number_integer  | 0xD3\n\t\tstr 8            | string          | 0xD9\n\t\tstr 16           | string          | 0xDA\n\t\tstr 32           | string          | 0xDB\n\t\tarray 16         | array           | 0xDC\n\t\tarray 32         | array           | 0xDD\n\t\tmap 16           | object          | 0xDE\n\t\tmap 32           | object          | 0xDF\n\t\tnegative fixint  | number_integer  | 0xE0-0xFF\n\n\t\t@warning The mapping is **incomplete** in the sense that not all\n\t\t\t\t MessagePack types can be converted to a JSON value. The following\n\t\t\t\t MessagePack types are not supported and will yield parse errors:\n\t\t\t\t  - bin 8 - bin 32 (0xC4..0xC6)\n\t\t\t\t  - ext 8 - ext 32 (0xC7..0xC9)\n\t\t\t\t  - fixext 1 - fixext 16 (0xD4..0xD8)\n\n\t\t@note Any MessagePack output created @ref to_msgpack can be successfully\n\t\t\t  parsed by @ref from_msgpack.\n\n\t\t@param[in] i  an input in MessagePack format convertible to an input\n\t\t\t\t\t  adapter\n\t\t@param[in] strict  whether to expect the input to be consumed until EOF\n\t\t\t\t\t\t   (true by default)\n\t\t@param[in] allow_exceptions  whether to throw exceptions in case of a\n\t\tparse error (optional, true by default)\n\n\t\t@return deserialized JSON value; in case of a parse error and\n\t\t\t\t@a allow_exceptions set to `false`, the return value will be\n\t\t\t\tvalue_t::discarded.\n\n\t\t@throw parse_error.110 if the given input ends prematurely or the end of\n\t\tfile was not reached when @a strict was set to true\n\t\t@throw parse_error.112 if unsupported features from MessagePack were\n\t\tused in the given input @a i or if the input is not valid MessagePack\n\t\t@throw parse_error.113 if a string was expected as map key, but not found\n\n\t\t@complexity Linear in the size of the input @a i.\n\n\t\t@liveexample{The example shows the deserialization of a byte vector in\n\t\tMessagePack format to a JSON value.,from_msgpack}\n\n\t\t@sa http://msgpack.org\n\t\t@sa @ref to_msgpack(const basic_json&) for the analogous serialization\n\t\t@sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n\t\t\trelated CBOR format\n\t\t@sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for\n\t\t\tthe related UBJSON format\n\t\t@sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n\t\t\tthe related BSON format\n\n\t\t@since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n\t\t\t   consume input adapters, removed start_index parameter, and added\n\t\t\t   @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n\t\t\t   since 3.2.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_msgpack(detail::input_adapter&& i,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@copydoc from_msgpack(detail::input_adapter&&, const bool, const bool)\n\t\t*/\n\t\ttemplate<typename A1, typename A2,\n\t\t\tdetail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n\t\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_msgpack(A1 && a1, A2 && a2,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@brief create a JSON value from an input in UBJSON format\n\n\t\tDeserializes a given input @a i to a JSON value using the UBJSON (Universal\n\t\tBinary JSON) serialization format.\n\n\t\tThe library maps UBJSON types to JSON value types as follows:\n\n\t\tUBJSON type | JSON value type                         | marker\n\t\t----------- | --------------------------------------- | ------\n\t\tno-op       | *no value, next value is read*          | `N`\n\t\tnull        | `null`                                  | `Z`\n\t\tfalse       | `false`                                 | `F`\n\t\ttrue        | `true`                                  | `T`\n\t\tfloat32     | number_float                            | `d`\n\t\tfloat64     | number_float                            | `D`\n\t\tuint8       | number_unsigned                         | `U`\n\t\tint8        | number_integer                          | `i`\n\t\tint16       | number_integer                          | `I`\n\t\tint32       | number_integer                          | `l`\n\t\tint64       | number_integer                          | `L`\n\t\tstring      | string                                  | `S`\n\t\tchar        | string                                  | `C`\n\t\tarray       | array (optimized values are supported)  | `[`\n\t\tobject      | object (optimized values are supported) | `{`\n\n\t\t@note The mapping is **complete** in the sense that any UBJSON value can\n\t\t\t  be converted to a JSON value.\n\n\t\t@param[in] i  an input in UBJSON format convertible to an input adapter\n\t\t@param[in] strict  whether to expect the input to be consumed until EOF\n\t\t\t\t\t\t   (true by default)\n\t\t@param[in] allow_exceptions  whether to throw exceptions in case of a\n\t\tparse error (optional, true by default)\n\n\t\t@return deserialized JSON value; in case of a parse error and\n\t\t\t\t@a allow_exceptions set to `false`, the return value will be\n\t\t\t\tvalue_t::discarded.\n\n\t\t@throw parse_error.110 if the given input ends prematurely or the end of\n\t\tfile was not reached when @a strict was set to true\n\t\t@throw parse_error.112 if a parse error occurs\n\t\t@throw parse_error.113 if a string could not be parsed successfully\n\n\t\t@complexity Linear in the size of the input @a i.\n\n\t\t@liveexample{The example shows the deserialization of a byte vector in\n\t\tUBJSON format to a JSON value.,from_ubjson}\n\n\t\t@sa http://ubjson.org\n\t\t@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n\t\t\t\t analogous serialization\n\t\t@sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n\t\t\trelated CBOR format\n\t\t@sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n\t\t\tthe related MessagePack format\n\t\t@sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n\t\t\tthe related BSON format\n\n\t\t@since version 3.1.0; added @a allow_exceptions parameter since 3.2.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_ubjson(detail::input_adapter&& i,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@copydoc from_ubjson(detail::input_adapter&&, const bool, const bool)\n\t\t*/\n\t\ttemplate<typename A1, typename A2,\n\t\t\tdetail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n\t\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_ubjson(A1 && a1, A2 && a2,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@brief Create a JSON value from an input in BSON format\n\n\t\tDeserializes a given input @a i to a JSON value using the BSON (Binary JSON)\n\t\tserialization format.\n\n\t\tThe library maps BSON record types to JSON value types as follows:\n\n\t\tBSON type       | BSON marker byte | JSON value type\n\t\t--------------- | ---------------- | ---------------------------\n\t\tdouble          | 0x01             | number_float\n\t\tstring          | 0x02             | string\n\t\tdocument        | 0x03             | object\n\t\tarray           | 0x04             | array\n\t\tbinary          | 0x05             | still unsupported\n\t\tundefined       | 0x06             | still unsupported\n\t\tObjectId        | 0x07             | still unsupported\n\t\tboolean         | 0x08             | boolean\n\t\tUTC Date-Time   | 0x09             | still unsupported\n\t\tnull            | 0x0A             | null\n\t\tRegular Expr.   | 0x0B             | still unsupported\n\t\tDB Pointer      | 0x0C             | still unsupported\n\t\tJavaScript Code | 0x0D             | still unsupported\n\t\tSymbol          | 0x0E             | still unsupported\n\t\tJavaScript Code | 0x0F             | still unsupported\n\t\tint32           | 0x10             | number_integer\n\t\tTimestamp       | 0x11             | still unsupported\n\t\t128-bit decimal float | 0x13       | still unsupported\n\t\tMax Key         | 0x7F             | still unsupported\n\t\tMin Key         | 0xFF             | still unsupported\n\n\t\t@warning The mapping is **incomplete**. The unsupported mappings\n\t\t\t\t are indicated in the table above.\n\n\t\t@param[in] i  an input in BSON format convertible to an input adapter\n\t\t@param[in] strict  whether to expect the input to be consumed until EOF\n\t\t\t\t\t\t   (true by default)\n\t\t@param[in] allow_exceptions  whether to throw exceptions in case of a\n\t\tparse error (optional, true by default)\n\n\t\t@return deserialized JSON value; in case of a parse error and\n\t\t\t\t@a allow_exceptions set to `false`, the return value will be\n\t\t\t\tvalue_t::discarded.\n\n\t\t@throw parse_error.114 if an unsupported BSON record type is encountered\n\n\t\t@complexity Linear in the size of the input @a i.\n\n\t\t@liveexample{The example shows the deserialization of a byte vector in\n\t\tBSON format to a JSON value.,from_bson}\n\n\t\t@sa http://bsonspec.org/spec.html\n\t\t@sa @ref to_bson(const basic_json&) for the analogous serialization\n\t\t@sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n\t\t\trelated CBOR format\n\t\t@sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n\t\t\tthe related MessagePack format\n\t\t@sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n\t\t\trelated UBJSON format\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_bson(detail::input_adapter&& i,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::bson, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\t\t/*!\n\t\t@copydoc from_bson(detail::input_adapter&&, const bool, const bool)\n\t\t*/\n\t\ttemplate<typename A1, typename A2,\n\t\t\tdetail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n\t\t\tJSON_NODISCARD\n\t\t\tstatic basic_json from_bson(A1 && a1, A2 && a2,\n\t\t\t\tconst bool strict = true,\n\t\t\t\tconst bool allow_exceptions = true)\n\t\t{\n\t\t\tbasic_json result;\n\t\t\tdetail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n\t\t\tconst bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::bson, &sdp, strict);\n\t\t\treturn res ? result : basic_json(value_t::discarded);\n\t\t}\n\n\n\n\t\t/// @}\n\n\t\t//////////////////////////\n\t\t// JSON Pointer support //\n\t\t//////////////////////////\n\n\t\t/// @name JSON Pointer functions\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief access specified element via JSON Pointer\n\n\t\tUses a JSON pointer to retrieve a reference to the respective JSON value.\n\t\tNo bound checking is performed. Similar to @ref operator[](const typename\n\t\tobject_t::key_type&), `null` values are created in arrays and objects if\n\t\tnecessary.\n\n\t\tIn particular:\n\t\t- If the JSON pointer points to an object key that does not exist, it\n\t\t  is created an filled with a `null` value before a reference to it\n\t\t  is returned.\n\t\t- If the JSON pointer points to an array index that does not exist, it\n\t\t  is created an filled with a `null` value before a reference to it\n\t\t  is returned. All indices between the current maximum and the given\n\t\t  index are also filled with `null`.\n\t\t- The special value `-` is treated as a synonym for the index past the\n\t\t  end.\n\n\t\t@param[in] ptr  a JSON pointer\n\n\t\t@return reference to the element pointed to by @a ptr\n\n\t\t@complexity Constant.\n\n\t\t@throw parse_error.106   if an array index begins with '0'\n\t\t@throw parse_error.109   if an array index was not a number\n\t\t@throw out_of_range.404  if the JSON pointer can not be resolved\n\n\t\t@liveexample{The behavior is shown in the example.,operatorjson_pointer}\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\treference operator[](const json_pointer& ptr)\n\t\t{\n\t\t\treturn ptr.get_unchecked(this);\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified element via JSON Pointer\n\n\t\tUses a JSON pointer to retrieve a reference to the respective JSON value.\n\t\tNo bound checking is performed. The function does not change the JSON\n\t\tvalue; no `null` values are created. In particular, the the special value\n\t\t`-` yields an exception.\n\n\t\t@param[in] ptr  JSON pointer to the desired element\n\n\t\t@return const reference to the element pointed to by @a ptr\n\n\t\t@complexity Constant.\n\n\t\t@throw parse_error.106   if an array index begins with '0'\n\t\t@throw parse_error.109   if an array index was not a number\n\t\t@throw out_of_range.402  if the array index '-' is used\n\t\t@throw out_of_range.404  if the JSON pointer can not be resolved\n\n\t\t@liveexample{The behavior is shown in the example.,operatorjson_pointer_const}\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tconst_reference operator[](const json_pointer& ptr) const\n\t\t{\n\t\t\treturn ptr.get_unchecked(this);\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified element via JSON Pointer\n\n\t\tReturns a reference to the element at with specified JSON pointer @a ptr,\n\t\twith bounds checking.\n\n\t\t@param[in] ptr  JSON pointer to the desired element\n\n\t\t@return reference to the element pointed to by @a ptr\n\n\t\t@throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n\t\tbegins with '0'. See example below.\n\n\t\t@throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n\t\tis not a number. See example below.\n\n\t\t@throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n\t\tis out of range. See example below.\n\n\t\t@throw out_of_range.402 if the array index '-' is used in the passed JSON\n\t\tpointer @a ptr. As `at` provides checked access (and no elements are\n\t\timplicitly inserted), the index '-' is always invalid. See example below.\n\n\t\t@throw out_of_range.403 if the JSON pointer describes a key of an object\n\t\twhich cannot be found. See example below.\n\n\t\t@throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n\t\tSee example below.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@since version 2.0.0\n\n\t\t@liveexample{The behavior is shown in the example.,at_json_pointer}\n\t\t*/\n\t\treference at(const json_pointer& ptr)\n\t\t{\n\t\t\treturn ptr.get_checked(this);\n\t\t}\n\n\t\t/*!\n\t\t@brief access specified element via JSON Pointer\n\n\t\tReturns a const reference to the element at with specified JSON pointer @a\n\t\tptr, with bounds checking.\n\n\t\t@param[in] ptr  JSON pointer to the desired element\n\n\t\t@return reference to the element pointed to by @a ptr\n\n\t\t@throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n\t\tbegins with '0'. See example below.\n\n\t\t@throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n\t\tis not a number. See example below.\n\n\t\t@throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n\t\tis out of range. See example below.\n\n\t\t@throw out_of_range.402 if the array index '-' is used in the passed JSON\n\t\tpointer @a ptr. As `at` provides checked access (and no elements are\n\t\timplicitly inserted), the index '-' is always invalid. See example below.\n\n\t\t@throw out_of_range.403 if the JSON pointer describes a key of an object\n\t\twhich cannot be found. See example below.\n\n\t\t@throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n\t\tSee example below.\n\n\t\t@exceptionsafety Strong guarantee: if an exception is thrown, there are no\n\t\tchanges in the JSON value.\n\n\t\t@complexity Constant.\n\n\t\t@since version 2.0.0\n\n\t\t@liveexample{The behavior is shown in the example.,at_json_pointer_const}\n\t\t*/\n\t\tconst_reference at(const json_pointer& ptr) const\n\t\t{\n\t\t\treturn ptr.get_checked(this);\n\t\t}\n\n\t\t/*!\n\t\t@brief return flattened JSON value\n\n\t\tThe function creates a JSON object whose keys are JSON pointers (see [RFC\n\t\t6901](https://tools.ietf.org/html/rfc6901)) and whose values are all\n\t\tprimitive. The original JSON value can be restored using the @ref\n\t\tunflatten() function.\n\n\t\t@return an object that maps JSON pointers to primitive values\n\n\t\t@note Empty objects and arrays are flattened to `null` and will not be\n\t\t\t  reconstructed correctly by the @ref unflatten() function.\n\n\t\t@complexity Linear in the size the JSON value.\n\n\t\t@liveexample{The following code shows how a JSON object is flattened to an\n\t\tobject whose keys consist of JSON pointers.,flatten}\n\n\t\t@sa @ref unflatten() for the reverse function\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tbasic_json flatten() const\n\t\t{\n\t\t\tbasic_json result(value_t::object);\n\t\t\tjson_pointer::flatten(\"\", *this, result);\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief unflatten a previously flattened JSON value\n\n\t\tThe function restores the arbitrary nesting of a JSON value that has been\n\t\tflattened before using the @ref flatten() function. The JSON value must\n\t\tmeet certain constraints:\n\t\t1. The value must be an object.\n\t\t2. The keys must be JSON pointers (see\n\t\t   [RFC 6901](https://tools.ietf.org/html/rfc6901))\n\t\t3. The mapped values must be primitive JSON types.\n\n\t\t@return the original JSON from a flattened version\n\n\t\t@note Empty objects and arrays are flattened by @ref flatten() to `null`\n\t\t\t  values and can not unflattened to their original type. Apart from\n\t\t\t  this example, for a JSON value `j`, the following is always true:\n\t\t\t  `j == j.flatten().unflatten()`.\n\n\t\t@complexity Linear in the size the JSON value.\n\n\t\t@throw type_error.314  if value is not an object\n\t\t@throw type_error.315  if object values are not primitive\n\n\t\t@liveexample{The following code shows how a flattened JSON object is\n\t\tunflattened into the original nested JSON object.,unflatten}\n\n\t\t@sa @ref flatten() for the reverse function\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tbasic_json unflatten() const\n\t\t{\n\t\t\treturn json_pointer::unflatten(*this);\n\t\t}\n\n\t\t/// @}\n\n\t\t//////////////////////////\n\t\t// JSON Patch functions //\n\t\t//////////////////////////\n\n\t\t/// @name JSON Patch functions\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief applies a JSON patch\n\n\t\t[JSON Patch](http://jsonpatch.com) defines a JSON document structure for\n\t\texpressing a sequence of operations to apply to a JSON) document. With\n\t\tthis function, a JSON Patch is applied to the current JSON value by\n\t\texecuting all operations from the patch.\n\n\t\t@param[in] json_patch  JSON patch document\n\t\t@return patched document\n\n\t\t@note The application of a patch is atomic: Either all operations succeed\n\t\t\t  and the patched document is returned or an exception is thrown. In\n\t\t\t  any case, the original value is not changed: the patch is applied\n\t\t\t  to a copy of the value.\n\n\t\t@throw parse_error.104 if the JSON patch does not consist of an array of\n\t\tobjects\n\n\t\t@throw parse_error.105 if the JSON patch is malformed (e.g., mandatory\n\t\tattributes are missing); example: `\"operation add must have member path\"`\n\n\t\t@throw out_of_range.401 if an array index is out of range.\n\n\t\t@throw out_of_range.403 if a JSON pointer inside the patch could not be\n\t\tresolved successfully in the current JSON value; example: `\"key baz not\n\t\tfound\"`\n\n\t\t@throw out_of_range.405 if JSON pointer has no parent (\"add\", \"remove\",\n\t\t\"move\")\n\n\t\t@throw other_error.501 if \"test\" operation was unsuccessful\n\n\t\t@complexity Linear in the size of the JSON value and the length of the\n\t\tJSON patch. As usually only a fraction of the JSON value is affected by\n\t\tthe patch, the complexity can usually be neglected.\n\n\t\t@liveexample{The following code shows how a JSON patch is applied to a\n\t\tvalue.,patch}\n\n\t\t@sa @ref diff -- create a JSON patch by comparing two JSON values\n\n\t\t@sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n\t\t@sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tbasic_json patch(const basic_json& json_patch) const\n\t\t{\n\t\t\t// make a working copy to apply the patch to\n\t\t\tbasic_json result = *this;\n\n\t\t\t// the valid JSON Patch operations\n\t\t\tenum class patch_operations { add, remove, replace, move, copy, test, invalid };\n\n\t\t\tconst auto get_op = [](const std::string & op)\n\t\t\t{\n\t\t\t\tif (op == \"add\")\n\t\t\t\t{\n\t\t\t\t\treturn patch_operations::add;\n\t\t\t\t}\n\t\t\t\tif (op == \"remove\")\n\t\t\t\t{\n\t\t\t\t\treturn patch_operations::remove;\n\t\t\t\t}\n\t\t\t\tif (op == \"replace\")\n\t\t\t\t{\n\t\t\t\t\treturn patch_operations::replace;\n\t\t\t\t}\n\t\t\t\tif (op == \"move\")\n\t\t\t\t{\n\t\t\t\t\treturn patch_operations::move;\n\t\t\t\t}\n\t\t\t\tif (op == \"copy\")\n\t\t\t\t{\n\t\t\t\t\treturn patch_operations::copy;\n\t\t\t\t}\n\t\t\t\tif (op == \"test\")\n\t\t\t\t{\n\t\t\t\t\treturn patch_operations::test;\n\t\t\t\t}\n\n\t\t\t\treturn patch_operations::invalid;\n\t\t\t};\n\n\t\t\t// wrapper for \"add\" operation; add value at ptr\n\t\t\tconst auto operation_add = [&result](json_pointer & ptr, basic_json val)\n\t\t\t{\n\t\t\t\t// adding to the root of the target document means replacing it\n\t\t\t\tif (ptr.empty())\n\t\t\t\t{\n\t\t\t\t\tresult = val;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// make sure the top element of the pointer exists\n\t\t\t\tjson_pointer top_pointer = ptr.top();\n\t\t\t\tif (top_pointer != ptr)\n\t\t\t\t{\n\t\t\t\t\tresult.at(top_pointer);\n\t\t\t\t}\n\n\t\t\t\t// get reference to parent of JSON pointer ptr\n\t\t\t\tconst auto last_path = ptr.back();\n\t\t\t\tptr.pop_back();\n\t\t\t\tbasic_json& parent = result[ptr];\n\n\t\t\t\tswitch (parent.m_type)\n\t\t\t\t{\n\t\t\t\tcase value_t::null:\n\t\t\t\tcase value_t::object:\n\t\t\t\t{\n\t\t\t\t\t// use operator[] to add value\n\t\t\t\t\tparent[last_path] = val;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase value_t::array:\n\t\t\t\t{\n\t\t\t\t\tif (last_path == \"-\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// special case: append to back\n\t\t\t\t\t\tparent.push_back(val);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tconst auto idx = json_pointer::array_index(last_path);\n\t\t\t\t\t\tif (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// avoid undefined behavior\n\t\t\t\t\t\t\tJSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// default case: insert add offset\n\t\t\t\t\t\tparent.insert(parent.begin() + static_cast<difference_type>(idx), val);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// if there exists a parent it cannot be primitive\n\t\t\t\tdefault:            // LCOV_EXCL_LINE\n\t\t\t\t\tassert(false);  // LCOV_EXCL_LINE\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// wrapper for \"remove\" operation; remove value at ptr\n\t\t\tconst auto operation_remove = [&result](json_pointer & ptr)\n\t\t\t{\n\t\t\t\t// get reference to parent of JSON pointer ptr\n\t\t\t\tconst auto last_path = ptr.back();\n\t\t\t\tptr.pop_back();\n\t\t\t\tbasic_json& parent = result.at(ptr);\n\n\t\t\t\t// remove child\n\t\t\t\tif (parent.is_object())\n\t\t\t\t{\n\t\t\t\t\t// perform range check\n\t\t\t\t\tauto it = parent.find(last_path);\n\t\t\t\t\tif (JSON_LIKELY(it != parent.end()))\n\t\t\t\t\t{\n\t\t\t\t\t\tparent.erase(it);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(out_of_range::create(403, \"key '\" + last_path + \"' not found\"));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (parent.is_array())\n\t\t\t\t{\n\t\t\t\t\t// note erase performs range check\n\t\t\t\t\tparent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// type check: top level value must be an array\n\t\t\tif (JSON_UNLIKELY(not json_patch.is_array()))\n\t\t\t{\n\t\t\t\tJSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n\t\t\t}\n\n\t\t\t// iterate and apply the operations\n\t\t\tfor (const auto& val : json_patch)\n\t\t\t{\n\t\t\t\t// wrapper to get a value for an operation\n\t\t\t\tconst auto get_value = [&val](const std::string & op,\n\t\t\t\t\tconst std::string & member,\n\t\t\t\t\tbool string_type) -> basic_json &\n\t\t\t\t{\n\t\t\t\t\t// find value\n\t\t\t\t\tauto it = val.m_value.object->find(member);\n\n\t\t\t\t\t// context-sensitive error message\n\t\t\t\t\tconst auto error_msg = (op == \"op\") ? \"operation\" : \"operation '\" + op + \"'\";\n\n\t\t\t\t\t// check if desired value is present\n\t\t\t\t\tif (JSON_UNLIKELY(it == val.m_value.object->end()))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(parse_error::create(105, 0, error_msg + \" must have member '\" + member + \"'\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// check if result is of type string\n\t\t\t\t\tif (JSON_UNLIKELY(string_type and not it->second.is_string()))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(parse_error::create(105, 0, error_msg + \" must have string member '\" + member + \"'\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// no error: return value\n\t\t\t\t\treturn it->second;\n\t\t\t\t};\n\n\t\t\t\t// type check: every element of the array must be an object\n\t\t\t\tif (JSON_UNLIKELY(not val.is_object()))\n\t\t\t\t{\n\t\t\t\t\tJSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n\t\t\t\t}\n\n\t\t\t\t// collect mandatory members\n\t\t\t\tconst std::string op = get_value(\"op\", \"op\", true);\n\t\t\t\tconst std::string path = get_value(op, \"path\", true);\n\t\t\t\tjson_pointer ptr(path);\n\n\t\t\t\tswitch (get_op(op))\n\t\t\t\t{\n\t\t\t\tcase patch_operations::add:\n\t\t\t\t{\n\t\t\t\t\toperation_add(ptr, get_value(\"add\", \"value\", false));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase patch_operations::remove:\n\t\t\t\t{\n\t\t\t\t\toperation_remove(ptr);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase patch_operations::replace:\n\t\t\t\t{\n\t\t\t\t\t// the \"path\" location must exist - use at()\n\t\t\t\t\tresult.at(ptr) = get_value(\"replace\", \"value\", false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase patch_operations::move:\n\t\t\t\t{\n\t\t\t\t\tconst std::string from_path = get_value(\"move\", \"from\", true);\n\t\t\t\t\tjson_pointer from_ptr(from_path);\n\n\t\t\t\t\t// the \"from\" location must exist - use at()\n\t\t\t\t\tbasic_json v = result.at(from_ptr);\n\n\t\t\t\t\t// The move operation is functionally identical to a\n\t\t\t\t\t// \"remove\" operation on the \"from\" location, followed\n\t\t\t\t\t// immediately by an \"add\" operation at the target\n\t\t\t\t\t// location with the value that was just removed.\n\t\t\t\t\toperation_remove(from_ptr);\n\t\t\t\t\toperation_add(ptr, v);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase patch_operations::copy:\n\t\t\t\t{\n\t\t\t\t\tconst std::string from_path = get_value(\"copy\", \"from\", true);\n\t\t\t\t\tconst json_pointer from_ptr(from_path);\n\n\t\t\t\t\t// the \"from\" location must exist - use at()\n\t\t\t\t\tbasic_json v = result.at(from_ptr);\n\n\t\t\t\t\t// The copy is functionally identical to an \"add\"\n\t\t\t\t\t// operation at the target location using the value\n\t\t\t\t\t// specified in the \"from\" member.\n\t\t\t\t\toperation_add(ptr, v);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase patch_operations::test:\n\t\t\t\t{\n\t\t\t\t\tbool success = false;\n\t\t\t\t\tJSON_TRY\n\t\t\t\t\t{\n\t\t\t\t\t\t// check if \"value\" matches the one at \"path\"\n\t\t\t\t\t\t// the \"path\" location must exist - use at()\n\t\t\t\t\t\tsuccess = (result.at(ptr) == get_value(\"test\", \"value\", false));\n\t\t\t\t\t}\n\t\t\t\t\t\tJSON_INTERNAL_CATCH(out_of_range&)\n\t\t\t\t\t{\n\t\t\t\t\t\t// ignore out of range errors: success remains false\n\t\t\t\t\t}\n\n\t\t\t\t\t// throw an exception if test fails\n\t\t\t\t\tif (JSON_UNLIKELY(not success))\n\t\t\t\t\t{\n\t\t\t\t\t\tJSON_THROW(other_error::create(501, \"unsuccessful: \" + val.dump()));\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\t// op must be \"add\", \"remove\", \"replace\", \"move\", \"copy\", or\n\t\t\t\t\t// \"test\"\n\t\t\t\t\tJSON_THROW(parse_error::create(105, 0, \"operation value '\" + op + \"' is invalid\"));\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/*!\n\t\t@brief creates a diff as a JSON patch\n\n\t\tCreates a [JSON Patch](http://jsonpatch.com) so that value @a source can\n\t\tbe changed into the value @a target by calling @ref patch function.\n\n\t\t@invariant For two JSON values @a source and @a target, the following code\n\t\tyields always `true`:\n\t\t@code {.cpp}\n\t\tsource.patch(diff(source, target)) == target;\n\t\t@endcode\n\n\t\t@note Currently, only `remove`, `add`, and `replace` operations are\n\t\t\t  generated.\n\n\t\t@param[in] source  JSON value to compare from\n\t\t@param[in] target  JSON value to compare against\n\t\t@param[in] path    helper value to create JSON pointers\n\n\t\t@return a JSON patch to convert the @a source to @a target\n\n\t\t@complexity Linear in the lengths of @a source and @a target.\n\n\t\t@liveexample{The following code shows how a JSON patch is created as a\n\t\tdiff for two JSON values.,diff}\n\n\t\t@sa @ref patch -- apply a JSON patch\n\t\t@sa @ref merge_patch -- apply a JSON Merge Patch\n\n\t\t@sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n\n\t\t@since version 2.0.0\n\t\t*/\n\t\tJSON_NODISCARD\n\t\t\tstatic basic_json diff(const basic_json& source, const basic_json& target,\n\t\t\t\tconst std::string& path = \"\")\n\t\t{\n\t\t\t// the patch\n\t\t\tbasic_json result(value_t::array);\n\n\t\t\t// if the values are the same, return empty patch\n\t\t\tif (source == target)\n\t\t\t{\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif (source.type() != target.type())\n\t\t\t{\n\t\t\t\t// different types: replace value\n\t\t\t\tresult.push_back(\n\t\t\t\t\t{\n\t\t\t\t\t\t{\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n\t\t\t\t\t});\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tswitch (source.type())\n\t\t\t{\n\t\t\tcase value_t::array:\n\t\t\t{\n\t\t\t\t// first pass: traverse common elements\n\t\t\t\tstd::size_t i = 0;\n\t\t\t\twhile (i < source.size() and i < target.size())\n\t\t\t\t{\n\t\t\t\t\t// recursive call to compare array values at index i\n\t\t\t\t\tauto temp_diff = diff(source[i], target[i], path + \"/\" + std::to_string(i));\n\t\t\t\t\tresult.insert(result.end(), temp_diff.begin(), temp_diff.end());\n\t\t\t\t\t++i;\n\t\t\t\t}\n\n\t\t\t\t// i now reached the end of at least one array\n\t\t\t\t// in a second pass, traverse the remaining elements\n\n\t\t\t\t// remove my remaining elements\n\t\t\t\tconst auto end_index = static_cast<difference_type>(result.size());\n\t\t\t\twhile (i < source.size())\n\t\t\t\t{\n\t\t\t\t\t// add operations in reverse order to avoid invalid\n\t\t\t\t\t// indices\n\t\t\t\t\tresult.insert(result.begin() + end_index, object(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t{\"op\", \"remove\"},\n\t\t\t\t\t\t\t{\"path\", path + \"/\" + std::to_string(i)}\n\t\t\t\t\t\t}));\n\t\t\t\t\t++i;\n\t\t\t\t}\n\n\t\t\t\t// add other remaining elements\n\t\t\t\twhile (i < target.size())\n\t\t\t\t{\n\t\t\t\t\tresult.push_back(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t{\"op\", \"add\"},\n\t\t\t\t\t\t\t{\"path\", path + \"/\" + std::to_string(i)},\n\t\t\t\t\t\t\t{\"value\", target[i]}\n\t\t\t\t\t\t});\n\t\t\t\t\t++i;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase value_t::object:\n\t\t\t{\n\t\t\t\t// first pass: traverse this object's elements\n\t\t\t\tfor (auto it = source.cbegin(); it != source.cend(); ++it)\n\t\t\t\t{\n\t\t\t\t\t// escape the key name to be used in a JSON patch\n\t\t\t\t\tconst auto key = json_pointer::escape(it.key());\n\n\t\t\t\t\tif (target.find(it.key()) != target.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// recursive call to compare object values at key it\n\t\t\t\t\t\tauto temp_diff = diff(it.value(), target[it.key()], path + \"/\" + key);\n\t\t\t\t\t\tresult.insert(result.end(), temp_diff.begin(), temp_diff.end());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// found a key that is not in o -> remove it\n\t\t\t\t\t\tresult.push_back(object(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t{\"op\", \"remove\"}, {\"path\", path + \"/\" + key}\n\t\t\t\t\t\t\t}));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// second pass: traverse other object's elements\n\t\t\t\tfor (auto it = target.cbegin(); it != target.cend(); ++it)\n\t\t\t\t{\n\t\t\t\t\tif (source.find(it.key()) == source.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// found a key that is not in this -> add it\n\t\t\t\t\t\tconst auto key = json_pointer::escape(it.key());\n\t\t\t\t\t\tresult.push_back(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t{\"op\", \"add\"}, {\"path\", path + \"/\" + key},\n\t\t\t\t\t\t\t\t{\"value\", it.value()}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// both primitive type: replace value\n\t\t\t\tresult.push_back(\n\t\t\t\t\t{\n\t\t\t\t\t\t{\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n\t\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/// @}\n\n\t\t////////////////////////////////\n\t\t// JSON Merge Patch functions //\n\t\t////////////////////////////////\n\n\t\t/// @name JSON Merge Patch functions\n\t\t/// @{\n\n\t\t/*!\n\t\t@brief applies a JSON Merge Patch\n\n\t\tThe merge patch format is primarily intended for use with the HTTP PATCH\n\t\tmethod as a means of describing a set of modifications to a target\n\t\tresource's content. This function applies a merge patch to the current\n\t\tJSON value.\n\n\t\tThe function implements the following algorithm from Section 2 of\n\t\t[RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):\n\n\t\t```\n\t\tdefine MergePatch(Target, Patch):\n\t\t  if Patch is an Object:\n\t\t\tif Target is not an Object:\n\t\t\t  Target = {} // Ignore the contents and set it to an empty Object\n\t\t\tfor each Name/Value pair in Patch:\n\t\t\t  if Value is null:\n\t\t\t\tif Name exists in Target:\n\t\t\t\t  remove the Name/Value pair from Target\n\t\t\t  else:\n\t\t\t\tTarget[Name] = MergePatch(Target[Name], Value)\n\t\t\treturn Target\n\t\t  else:\n\t\t\treturn Patch\n\t\t```\n\n\t\tThereby, `Target` is the current object; that is, the patch is applied to\n\t\tthe current value.\n\n\t\t@param[in] apply_patch  the patch to apply\n\n\t\t@complexity Linear in the lengths of @a patch.\n\n\t\t@liveexample{The following code shows how a JSON Merge Patch is applied to\n\t\ta JSON document.,merge_patch}\n\n\t\t@sa @ref patch -- apply a JSON patch\n\t\t@sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)\n\n\t\t@since version 3.0.0\n\t\t*/\n\t\tvoid merge_patch(const basic_json& apply_patch)\n\t\t{\n\t\t\tif (apply_patch.is_object())\n\t\t\t{\n\t\t\t\tif (not is_object())\n\t\t\t\t{\n\t\t\t\t\t*this = object();\n\t\t\t\t}\n\t\t\t\tfor (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it.value().is_null())\n\t\t\t\t\t{\n\t\t\t\t\t\terase(it.key());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\toperator[](it.key()).merge_patch(it.value());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*this = apply_patch;\n\t\t\t}\n\t\t}\n\n\t\t/// @}\n\t};\n} // namespace nlohmann\n\n///////////////////////\n// nonmember support //\n///////////////////////\n\n// specialization of std::swap, and std::hash\nnamespace std\n{\n\n\t/// hash value for JSON objects\n\ttemplate<>\n\tstruct hash<nlohmann::json>\n\t{\n\t\t/*!\n\t\t@brief return a hash value for a JSON object\n\n\t\t@since version 1.0.0\n\t\t*/\n\t\tstd::size_t operator()(const nlohmann::json& j) const\n\t\t{\n\t\t\t// a naive hashing via the string representation\n\t\t\tconst auto& h = hash<nlohmann::json::string_t>();\n\t\t\treturn h(j.dump());\n\t\t}\n\t};\n\n\t/// specialization for std::less<value_t>\n\t/// @note: do not remove the space after '<',\n\t///        see https://github.com/nlohmann/json/pull/679\n\ttemplate<>\n\tstruct less< ::nlohmann::detail::value_t>\n\t{\n\t\t/*!\n\t\t@brief compare two value_t enum values\n\t\t@since version 3.0.0\n\t\t*/\n\t\tbool operator()(nlohmann::detail::value_t lhs,\n\t\t\tnlohmann::detail::value_t rhs) const noexcept\n\t\t{\n\t\t\treturn nlohmann::detail::operator<(lhs, rhs);\n\t\t}\n\t};\n\n\t/*!\n\t@brief exchanges the values of two JSON objects\n\n\t@since version 1.0.0\n\t*/\n\ttemplate<>\n\tinline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(\n\t\tis_nothrow_move_constructible<nlohmann::json>::value and\n\t\tis_nothrow_move_assignable<nlohmann::json>::value\n\t\t)\n\t{\n\t\tj1.swap(j2);\n\t}\n\n} // namespace std\n\n/*!\n@brief user-defined string literal for JSON values\n\nThis operator implements a user-defined string literal for JSON objects. It\ncan be used by adding `\"_json\"` to a string literal and returns a JSON object\nif no parse error occurred.\n\n@param[in] s  a string representation of a JSON object\n@param[in] n  the length of string @a s\n@return a JSON object\n\n@since version 1.0.0\n*/\ninline nlohmann::json operator \"\" _json(const char* s, std::size_t n)\n{\n\treturn nlohmann::json::parse(s, s + n);\n}\n\n/*!\n@brief user-defined string literal for JSON pointer\n\nThis operator implements a user-defined string literal for JSON Pointers. It\ncan be used by adding `\"_json_pointer\"` to a string literal and returns a JSON pointer\nobject if no parse error occurred.\n\n@param[in] s  a string representation of a JSON Pointer\n@param[in] n  the length of string @a s\n@return a JSON pointer object\n\n@since version 2.0.0\n*/\ninline nlohmann::json::json_pointer operator \"\" _json_pointer(const char* s, std::size_t n)\n{\n\treturn nlohmann::json::json_pointer(std::string(s, n));\n}\n\n// #include <nlohmann/detail/macro_unscope.hpp>\n\n\n// restore GCC/clang diagnostic settings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic pop\n#endif\n#if defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n// clean up\n#undef JSON_INTERNAL_CATCH\n#undef JSON_CATCH\n#undef JSON_THROW\n#undef JSON_TRY\n#undef JSON_LIKELY\n#undef JSON_UNLIKELY\n#undef JSON_DEPRECATED\n#undef JSON_NODISCARD\n#undef JSON_HAS_CPP_14\n#undef JSON_HAS_CPP_17\n#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION\n#undef NLOHMANN_BASIC_JSON_TPL\n\n\n#endif  // INCLUDE_NLOHMANN_JSON_HPP_"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTK/json/repo.txt",
    "content": "https://github.com/nlohmann/json/"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTelemetry/GDK/ATGTelemetry.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: ATGTelemetry.cpp\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright(c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//--------------------------------------------------------------------------------------\n#include \"pch.h\"\n\n#ifdef ATG_ENABLE_TELEMETRY\n#include \"ATGTelemetry.h\"\n\n#include <XGame.h>\n#include <XSystem.h>\n\n#include \"httpClient/httpClient.h\"\n#include \"StringUtil.h\"\n#include \"Json.h\"\n#include <sstream>\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n#include <fstream>\n#include \"Shlwapi.h\"\n#include \"Shlobj.h\"\n#endif\n\n#ifdef _GAMING_XBOX\n#pragma warning(disable : 4365)\n#include <ws2def.h>\n#include <ws2ipdef.h>\n#include <iphlpapi.h>\n#endif\n\nnamespace {\n    const char *LOGIN_URL = \"https://3436.playfabapi.com/Client/LoginWithCustomID\";\n    const char *EVENT_URL = \"https://3436.playfabapi.com/Event/WriteTelemetryEvents\";\n}\n\nusing namespace ATG;\n\nclass ATGTelemetry\n{\npublic:\n    ~ATGTelemetry()\n    {\n#if _GAMING_XBOX\n        if (m_notificationChangedHandle)\n        {\n            CancelMibChangeNotify2(m_notificationChangedHandle);\n            m_notificationChangedHandle = nullptr;\n        }\n#endif\n    }\n\n    void SendTelemetry()\n    {\n#if _GAMING_XBOX\n        NotifyNetworkConnectivityHintChange([](void* context, NL_NETWORK_CONNECTIVITY_HINT connectivityHint)\n            {\n                auto atgTelemetry = static_cast<ATGTelemetry*>(context);\n                if (connectivityHint.ConnectivityLevel == NL_NETWORK_CONNECTIVITY_LEVEL_HINT::NetworkConnectivityLevelHintInternetAccess\n                    || connectivityHint.ConnectivityLevel == NL_NETWORK_CONNECTIVITY_LEVEL_HINT::NetworkConnectivityLevelHintConstrainedInternetAccess)\n                {\n                    atgTelemetry->SendTelemetryInternal();\n                }\n            }, this, true, &m_notificationChangedHandle);\n#else\n        SendTelemetryInternal();\n#endif\n    }\n\nprivate:\n    void SendTelemetryInternal()\n    {\n        static bool sent = false;\n\n        if (!sent)\n        {\n            sent = true;\n            // Ensure the HTTP library is initialized\n            if (FAILED(HCInitialize(nullptr)))\n            {\n                return;\n            }\n\n            auto *async = new XAsyncBlock{};\n            async->queue = nullptr;\n\n            CollectBaseTelemetry();\n            UploadTelemetry(async);\n        }\n    }\n\n    std::string NewGuid()\n    {\n        GUID id = {};\n        char buf[64] = {};\n\n        CoCreateGuid(&id);\n\n        sprintf_s(buf, \"%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\",\n            id.Data1, id.Data2, id.Data3,\n            id.Data4[0], id.Data4[1], id.Data4[2], id.Data4[3],\n            id.Data4[4], id.Data4[5], id.Data4[6], id.Data4[7]);\n\n        return std::string(buf);\n    }\n\n    std::string GetTelemetryId()\n    {\n        using namespace std;\n        const int BUFSIZE = 64;\n        char buf[BUFSIZE] = {};\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n        size_t ignoreField;\n        XSystemGetConsoleId(XSystemConsoleIdBytes, buf, &ignoreField);\n\n        std::string clientId = buf;\n        clientId.erase(std::remove(clientId.begin(), clientId.end(), '.'), clientId.end());\n        return clientId;\n#else\n        wchar_t *folderPath;\n        string telemetryId;\n\n        if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_NO_PACKAGE_REDIRECTION, nullptr, &folderPath)))\n        {\n\n            // Path information\n            wstring path(folderPath);\n            path += L\"\\\\Microsoft\\\\ATGSamples\\\\\";\n            wstring fullPath = path + L\"telemetry.txt\";\n\n            bool createFile = CreateDirectoryW(path.c_str(), nullptr);\n\n            if (!createFile)\n            {\n                DWORD error = GetLastError();\n\n                // Sanity checking - Directory failed to create but that should mean it already exists\n                if (error != ERROR_ALREADY_EXISTS)\n                {\n                    return NewGuid();\n                }\n            }\n\n            int attempts = 0;\n            while (attempts++ < 2)\n            {\n                if (createFile)\n                {\n                    ofstream telFile;\n                    telFile.open(fullPath, ios::out | ios::trunc);\n                    telemetryId = NewGuid();\n\n                    telFile << telemetryId;\n                    telFile.close();\n                    break;\n                }\n                else\n                {\n                    ifstream telFile;\n                    telFile.open(fullPath);\n                    if (telFile.good())\n                    {\n                        telFile.get(buf, BUFSIZE);\n                        telFile.close();\n                        telemetryId = buf;\n\n                        if (telemetryId.size() >= 32)\n                        {\n                            break;\n                        }\n                    }\n\n                    createFile = true;\n                }\n            }\n        }\n\n        return telemetryId;\n#endif\n    }\n\n    // Collect the base telemetry for the system\n    void CollectBaseTelemetry()\n    {\n        const int BUFSIZE = 256;\n        size_t ignore;\n        char buf[BUFSIZE] = {};\n\n        m_telemetry = std::make_unique<TelemetryData>();\n\n        TelemetryData &data = *m_telemetry;\n\n        // OS and client information\n        {\n            auto info = XSystemGetAnalyticsInfo();\n\n            data.osVersion = XVersionToString(info.osVersion);\n            data.hostingOsVersion = XVersionToString(info.hostingOsVersion);\n            data.family = info.family;\n            data.form = info.form;\n\n            data.clientId = GetTelemetryId();\n\n            data.sandbox.reserve(XSystemXboxLiveSandboxIdMaxBytes);\n            XSystemGetXboxLiveSandboxId(XSystemXboxLiveSandboxIdMaxBytes, buf, &ignore);\n            data.sandbox = buf;\n        }\n\n        // Sample information\n        {\n            uint32_t titleId = 0;\n            XGameGetXboxTitleId(&titleId);\n            data.titleId = ToHexString(titleId);\n\n            wchar_t exePath[MAX_PATH + 1] = {};\n\n            if (!GetModuleFileNameW(nullptr, exePath, MAX_PATH))\n            {\n                data.exeName = \"Unknown\";\n            }\n            else\n            {\n                auto path = std::wstring(exePath);\n                auto off = path.find_last_of(L\"\\\\\");\n                auto exeOnly = path.substr(off + 1);\n                data.exeName = DX::WideToUtf8(exeOnly);\n            }\n        }\n\n        // This run information\n        data.sessionId = NewGuid();\n\n    }\n\n    void UploadTelemetry(XAsyncBlock *async)\n    {\n        if (m_authToken.length() == 0)\n        {\n            AuthPlayfab(async);\n            return;\n        }\n\n        async->callback = [](XAsyncBlock *async)\n        {\n            HCCallHandle httpCall = static_cast<HCCallHandle>(async->context);\n            auto response = PlayFabResponse::FromCall(httpCall);\n            HCHttpCallCloseHandle(httpCall);\n            delete async;\n        };\n\n\n        std::string payload = CreateEventPayload(*m_telemetry);\n\n        auto httpCall = CreateEventRequest(m_authToken, payload);\n\n        async->context = httpCall;\n        if (FAILED(HCHttpCallPerformAsync(httpCall, async)))\n        {\n            delete async;\n        }\n    }\n\n    void AuthPlayfab(XAsyncBlock *async)\n    {\n        struct AuthContext\n        {\n            ATGTelemetry *_this;\n            HCCallHandle httpCallHandle;\n        };\n\n        async->callback = [](XAsyncBlock *async)\n        {\n            auto ctx = static_cast<AuthContext *>(async->context);\n\n            HCCallHandle httpCall = ctx->httpCallHandle;\n\n            auto response = PlayFabResponse::FromCall(httpCall);\n\n            HCHttpCallCloseHandle(httpCall);\n\n            if (response.IsSuccessStatus())\n            {\n                auto respJs = response.AsJson();\n                ctx->_this->m_authToken = respJs[\"data\"][\"EntityToken\"][\"EntityToken\"].get<std::string>();\n                ctx->_this->UploadTelemetry(async);\n            }\n            else\n            {\n                delete async;\n            }\n        };\n\n        HCCallHandle httpCall = CreateAuthRequest(m_telemetry->clientId);\n        auto ctx = new AuthContext({ this, httpCall });\n        async->context = ctx;\n\n        if (FAILED(HCHttpCallPerformAsync(httpCall, async)))\n        {\n            delete async;\n        }\n    }\n\nprivate:\n    // Base telemetry data to capture and serialize\n    struct TelemetryData\n    {\n        std::string osVersion;\n        std::string hostingOsVersion;\n        std::string family;\n        std::string form;\n        std::string clientId;\n        std::string sandbox;\n        std::string titleId;\n        std::string exeName;\n        std::string sessionId;\n\n        json ToJson() const\n        {\n            json js;\n            js[\"osVersion\"] = osVersion;\n            js[\"hostingOsVersion\"] = hostingOsVersion;\n            js[\"family\"] = family;\n            js[\"form\"] = form;\n            js[\"clientId\"] = clientId;\n            js[\"sandboxId\"] = sandbox;\n            js[\"titleId\"] = titleId;\n            js[\"exeName\"] = exeName;\n            js[\"sessionId\"] = sessionId;\n\n            return js;\n        }\n    };\n\nprivate:\n    // HTTP response from a PlayFab API request\n    class PlayFabResponse\n    {\n    public:\n        static PlayFabResponse FromCall(HCCallHandle httpCall)\n        {\n            PlayFabResponse response;\n\n            HCHttpCallResponseGetStatusCode(httpCall, &response.status);\n\n            const char *responseString;\n            HCHttpCallResponseGetResponseString(httpCall, &responseString);\n            response.dataString = responseString;\n\n            return response;\n        }\n\n    public:\n        const std::string & AsString() const\n        {\n            return dataString;\n        }\n\n        json AsJson() const\n        {\n            return json::parse(dataString);\n        }\n\n        bool IsSuccessStatus() { return status >= 200 && status < 300; }\n\n    private:\n        PlayFabResponse() = default;\n\n        uint32_t status;\n        std::string dataString;\n    };\n\nprivate:\n    static std::string CreateAuthPayload(const std::string& clientId)\n    {\n        json payload;\n\n        payload[\"CreateAccount\"] = true;\n        payload[\"CustomId\"] = clientId;\n        payload[\"TitleId\"] = \"3436\";\n\n        return payload.dump();\n    }\n\n    static HCCallHandle CreateAuthRequest(const std::string& clientId)\n    {\n        HCCallHandle httpCall;\n        HCHttpCallCreate(&httpCall);\n        HCHttpCallRequestSetUrl(httpCall, \"POST\", LOGIN_URL);\n\n        std::string payload = CreateAuthPayload(clientId);\n\n        HCHttpCallRequestSetRequestBodyString(httpCall, payload.c_str());\n        HCHttpCallRequestSetHeader(httpCall, \"Content-Type\", \"application/json\", true);\n\n        return httpCall;\n    }\n\n    static std::string CreateEventPayload(const TelemetryData& data)\n    {\n        json ev;\n        ev[\"EventNamespace\"] = \"com.playfab.events.samples\";\n        ev[\"Name\"] = \"launch\";\n        ev[\"Payload\"] = data.ToJson();\n\n        json evJs;\n        evJs[\"Events\"] = json::array({ ev });\n\n        return evJs.dump();\n    }\n\n    static HCCallHandle CreateEventRequest(const std::string &authToken, const std::string &payload)\n    {\n        HCCallHandle httpCall;\n\n        HCHttpCallCreate(&httpCall);\n\n        HCHttpCallRequestSetUrl(httpCall, \"POST\", EVENT_URL);\n\n        HCHttpCallRequestSetRequestBodyString(httpCall, payload.c_str());\n        HCHttpCallRequestSetHeader(httpCall, \"Content-Type\", \"application/json\", true);\n        HCHttpCallRequestSetHeader(httpCall, \"X-EntityToken\", authToken.c_str(), false);\n\n        return httpCall;\n    }\n\n    static std::string XVersionToString(XVersion version)\n    {\n        std::stringstream ss;\n        ss << version.major << \".\" << version.minor << \".\" << version.build << \".\" << version.revision;\n        return ss.str();\n    }\n\n    static std::string ToHexString(uint32_t value)\n    {\n        std::stringstream ss;\n        ss << std::hex << value;\n        return ss.str();\n    }\n\nprivate:\n    std::string m_authToken;\n\n    std::unique_ptr<TelemetryData> m_telemetry;\n\n#if _GAMING_XBOX\n    HANDLE m_notificationChangedHandle = nullptr;\n#endif\n};\n\nstatic std::unique_ptr<ATGTelemetry> s_atgTelem;\nvoid ATG::SendLaunchTelemetry()\n{\n    if (!s_atgTelem)\n    {\n        s_atgTelem = std::make_unique<ATGTelemetry>();\n    }\n\n    s_atgTelem->SendTelemetry();\n}\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/ATGTelemetry/GDK/ATGTelemetry.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: ATGTelemetry.h\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright(c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\nnamespace ATG\n{\n// To opt-out of telemetry uncomment the following line\n// #undef ATG_ENABLE_TELEMETRY\n\n#ifdef ATG_ENABLE_TELEMETRY\n    // Sends sample launch telemetry\n    void SendLaunchTelemetry();\n#else\n    void SendLaunchTelemetry() {};\n#endif\n\n}"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/AudioEngine.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: AudioEngine.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Audio.h\"\n#include \"SoundCommon.h\"\n\n#include <unordered_map>\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n//#define VERBOSE_TRACE\n\n#ifdef VERBOSE_TRACE\n#pragma message(\"NOTE: Verbose tracing enabled\")\n#endif\n\nnamespace\n{\n    struct EngineCallback : public IXAudio2EngineCallback\n    {\n        EngineCallback() noexcept(false)\n        {\n            mCriticalError.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n            if (!mCriticalError)\n            {\n                throw std::exception(\"CreateEvent\");\n            }\n        }\n\n        EngineCallback(EngineCallback&&) = default;\n        EngineCallback& operator= (EngineCallback&&) = default;\n\n        EngineCallback(EngineCallback const&) = delete;\n        EngineCallback& operator= (EngineCallback const&) = delete;\n\n        virtual ~EngineCallback() = default;\n\n        STDMETHOD_(void, OnProcessingPassStart) () override {}\n        STDMETHOD_(void, OnProcessingPassEnd)() override {}\n\n        STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT error)\n        {\n        #ifndef _DEBUG\n            UNREFERENCED_PARAMETER(error);\n        #endif\n            DebugTrace(\"ERROR: AudioEngine encountered critical error (%08X)\\n\", static_cast<unsigned int>(error));\n            SetEvent(mCriticalError.get());\n        }\n\n        ScopedHandle mCriticalError;\n    };\n\n    struct VoiceCallback : public IXAudio2VoiceCallback\n    {\n        VoiceCallback() noexcept(false)\n        {\n            mBufferEnd.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n            if (!mBufferEnd)\n            {\n                throw std::exception(\"CreateEvent\");\n            }\n        }\n\n        VoiceCallback(VoiceCallback&&) = default;\n        VoiceCallback& operator=(VoiceCallback&&) = default;\n\n        VoiceCallback(const VoiceCallback&) = delete;\n        VoiceCallback& operator=(const VoiceCallback&) = delete;\n\n        virtual ~VoiceCallback()\n        {\n        }\n\n        STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) override {}\n        STDMETHOD_(void, OnVoiceProcessingPassEnd)() override {}\n        STDMETHOD_(void, OnStreamEnd)() override {}\n        STDMETHOD_(void, OnBufferStart)(void*) override {}\n\n        STDMETHOD_(void, OnBufferEnd)(void* context) override\n        {\n            if (context)\n            {\n                auto inotify = static_cast<IVoiceNotify*>(context);\n                inotify->OnBufferEnd();\n                SetEvent(mBufferEnd.get());\n            }\n        }\n\n        STDMETHOD_(void, OnLoopEnd)(void*) override {}\n        STDMETHOD_(void, OnVoiceError)(void*, HRESULT) override {}\n\n        ScopedHandle mBufferEnd;\n    };\n\n    static const XAUDIO2FX_REVERB_I3DL2_PARAMETERS gReverbPresets[] =\n    {\n        XAUDIO2FX_I3DL2_PRESET_DEFAULT,             // Reverb_Off\n        XAUDIO2FX_I3DL2_PRESET_DEFAULT,             // Reverb_Default\n        XAUDIO2FX_I3DL2_PRESET_GENERIC,             // Reverb_Generic\n        XAUDIO2FX_I3DL2_PRESET_FOREST,              // Reverb_Forest\n        XAUDIO2FX_I3DL2_PRESET_PADDEDCELL,          // Reverb_PaddedCell\n        XAUDIO2FX_I3DL2_PRESET_ROOM,                // Reverb_Room\n        XAUDIO2FX_I3DL2_PRESET_BATHROOM,            // Reverb_Bathroom\n        XAUDIO2FX_I3DL2_PRESET_LIVINGROOM,          // Reverb_LivingRoom\n        XAUDIO2FX_I3DL2_PRESET_STONEROOM,           // Reverb_StoneRoom\n        XAUDIO2FX_I3DL2_PRESET_AUDITORIUM,          // Reverb_Auditorium\n        XAUDIO2FX_I3DL2_PRESET_CONCERTHALL,         // Reverb_ConcertHall\n        XAUDIO2FX_I3DL2_PRESET_CAVE,                // Reverb_Cave\n        XAUDIO2FX_I3DL2_PRESET_ARENA,               // Reverb_Arena\n        XAUDIO2FX_I3DL2_PRESET_HANGAR,              // Reverb_Hangar\n        XAUDIO2FX_I3DL2_PRESET_CARPETEDHALLWAY,     // Reverb_CarpetedHallway\n        XAUDIO2FX_I3DL2_PRESET_HALLWAY,             // Reverb_Hallway\n        XAUDIO2FX_I3DL2_PRESET_STONECORRIDOR,       // Reverb_StoneCorridor\n        XAUDIO2FX_I3DL2_PRESET_ALLEY,               // Reverb_Alley\n        XAUDIO2FX_I3DL2_PRESET_CITY,                // Reverb_City\n        XAUDIO2FX_I3DL2_PRESET_MOUNTAINS,           // Reverb_Mountains\n        XAUDIO2FX_I3DL2_PRESET_QUARRY,              // Reverb_Quarry\n        XAUDIO2FX_I3DL2_PRESET_PLAIN,               // Reverb_Plain\n        XAUDIO2FX_I3DL2_PRESET_PARKINGLOT,          // Reverb_ParkingLot\n        XAUDIO2FX_I3DL2_PRESET_SEWERPIPE,           // Reverb_SewerPipe\n        XAUDIO2FX_I3DL2_PRESET_UNDERWATER,          // Reverb_Underwater\n        XAUDIO2FX_I3DL2_PRESET_SMALLROOM,           // Reverb_SmallRoom\n        XAUDIO2FX_I3DL2_PRESET_MEDIUMROOM,          // Reverb_MediumRoom\n        XAUDIO2FX_I3DL2_PRESET_LARGEROOM,           // Reverb_LargeRoom\n        XAUDIO2FX_I3DL2_PRESET_MEDIUMHALL,          // Reverb_MediumHall\n        XAUDIO2FX_I3DL2_PRESET_LARGEHALL,           // Reverb_LargeHall\n        XAUDIO2FX_I3DL2_PRESET_PLATE,               // Reverb_Plate\n    };\n\n    inline unsigned int makeVoiceKey(_In_ const WAVEFORMATEX* wfx) noexcept\n    {\n        assert(IsValid(wfx));\n\n        if (wfx->nChannels > 0x7F)\n            return 0;\n\n        // This hash does not use nSamplesPerSec because voice reuse can change the source sample rate.\n\n        // nAvgBytesPerSec and nBlockAlign are derived from other values in XAudio2 supported formats.\n\n        union KeyGen\n        {\n            struct\n            {\n                unsigned int tag : 9;\n                unsigned int channels : 7;\n                unsigned int bitsPerSample : 8;\n            } pcm;\n\n            struct\n            {\n                unsigned int tag : 9;\n                unsigned int channels : 7;\n                unsigned int samplesPerBlock : 16;\n            } adpcm;\n\n        #ifdef DIRECTX_ENABLE_XMA2\n            struct\n            {\n                unsigned int tag : 9;\n                unsigned int channels : 7;\n                unsigned int encoderVersion : 8;\n            } xma;\n        #endif\n\n            unsigned int key;\n        } result;\n\n        static_assert(sizeof(KeyGen) == sizeof(unsigned int), \"KeyGen is invalid\");\n\n        result.key = 0;\n\n        if (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)\n        {\n            // We reuse EXTENSIBLE only if it is equivalent to the standard form\n            auto wfex = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(wfx);\n            if (wfex->Samples.wValidBitsPerSample != 0 && wfex->Samples.wValidBitsPerSample != wfx->wBitsPerSample)\n                return 0;\n\n            if (wfex->dwChannelMask != 0 && wfex->dwChannelMask != GetDefaultChannelMask(wfx->nChannels))\n                return 0;\n        }\n\n        uint32_t tag = GetFormatTag(wfx);\n        switch (tag)\n        {\n            case WAVE_FORMAT_PCM:\n                static_assert(WAVE_FORMAT_PCM < 0x1ff, \"KeyGen tag is too small\");\n                result.pcm.tag = WAVE_FORMAT_PCM;\n                result.pcm.channels = wfx->nChannels;\n                result.pcm.bitsPerSample = wfx->wBitsPerSample;\n                break;\n\n            case WAVE_FORMAT_IEEE_FLOAT:\n                static_assert(WAVE_FORMAT_IEEE_FLOAT < 0x1ff, \"KeyGen tag is too small\");\n\n                if (wfx->wBitsPerSample != 32)\n                    return 0;\n\n                result.pcm.tag = WAVE_FORMAT_IEEE_FLOAT;\n                result.pcm.channels = wfx->nChannels;\n                result.pcm.bitsPerSample = 32;\n                break;\n\n            case WAVE_FORMAT_ADPCM:\n                static_assert(WAVE_FORMAT_ADPCM < 0x1ff, \"KeyGen tag is too small\");\n                result.adpcm.tag = WAVE_FORMAT_ADPCM;\n                result.adpcm.channels = wfx->nChannels;\n\n                {\n                    auto wfadpcm = reinterpret_cast<const ADPCMWAVEFORMAT*>(wfx);\n                    result.adpcm.samplesPerBlock = wfadpcm->wSamplesPerBlock;\n                }\n                break;\n\n            #ifdef DIRECTX_ENABLE_XMA2\n            case WAVE_FORMAT_XMA2:\n                static_assert(WAVE_FORMAT_XMA2 < 0x1ff, \"KeyGen tag is too small\");\n                result.xma.tag = WAVE_FORMAT_XMA2;\n                result.xma.channels = wfx->nChannels;\n\n                {\n                    auto xmaFmt = reinterpret_cast<const XMA2WAVEFORMATEX*>(wfx);\n\n                    if ((xmaFmt->LoopBegin > 0)\n                        || (xmaFmt->PlayBegin > 0))\n                        return 0;\n\n                    result.xma.encoderVersion = xmaFmt->EncoderVersion;\n                }\n                break;\n            #endif\n\n            default:\n                return 0;\n        }\n\n        return result.key;\n    }\n}\n\nstatic_assert(_countof(gReverbPresets) == Reverb_MAX, \"AUDIO_ENGINE_REVERB enum mismatch\");\n\n\n//======================================================================================\n// AudioEngine\n//======================================================================================\n\n#define SAFE_DESTROY_VOICE(voice) if ( voice ) { voice->DestroyVoice(); voice = nullptr; }\n\n// Internal object implementation class.\nclass AudioEngine::Impl\n{\npublic:\n    Impl() noexcept :\n        mMasterVoice(nullptr),\n        mReverbVoice(nullptr),\n        masterChannelMask(0),\n        masterChannels(0),\n        masterRate(0),\n        defaultRate(44100),\n        maxVoiceOneshots(SIZE_MAX),\n        maxVoiceInstances(SIZE_MAX),\n        mMasterVolume(1.f),\n        mX3DAudio{},\n        mCriticalError(false),\n        mReverbEnabled(false),\n        mEngineFlags(AudioEngine_Default),\n        mCategory(AudioCategory_GameEffects),\n        mVoiceInstances(0)\n    {\n    }\n\n    ~Impl() = default;\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    HRESULT Initialize(AUDIO_ENGINE_FLAGS flags,\n        _In_opt_ const WAVEFORMATEX* wfx,\n        _In_opt_z_ const wchar_t* deviceId,\n        AUDIO_STREAM_CATEGORY category);\n\n    HRESULT Reset(_In_opt_ const WAVEFORMATEX* wfx, _In_opt_z_ const wchar_t* deviceId);\n\n    void SetSilentMode();\n\n    void Shutdown() noexcept;\n\n    bool Update();\n\n    void SetReverb(_In_opt_ const XAUDIO2FX_REVERB_PARAMETERS* native) noexcept;\n\n    void SetMasteringLimit(int release, int loudness);\n\n    AudioStatistics GetStatistics() const;\n\n    void TrimVoicePool();\n\n    void AllocateVoice(_In_ const WAVEFORMATEX* wfx,\n        SOUND_EFFECT_INSTANCE_FLAGS flags, bool oneshot,\n        _Outptr_result_maybenull_ IXAudio2SourceVoice** voice);\n    void DestroyVoice(_In_ IXAudio2SourceVoice* voice) noexcept;\n\n    void RegisterNotify(_In_ IVoiceNotify* notify, bool usesUpdate);\n    void UnregisterNotify(_In_ IVoiceNotify* notify, bool oneshots, bool usesUpdate);\n\n    ComPtr<IXAudio2>                    xaudio2;\n    IXAudio2MasteringVoice*             mMasterVoice;\n    IXAudio2SubmixVoice*                mReverbVoice;\n\n    uint32_t                            masterChannelMask;\n    uint32_t                            masterChannels;\n    uint32_t                            masterRate;\n\n    int                                 defaultRate;\n    size_t                              maxVoiceOneshots;\n    size_t                              maxVoiceInstances;\n    float                               mMasterVolume;\n\n    X3DAUDIO_HANDLE                     mX3DAudio;\n\n    bool                                mCriticalError;\n    bool                                mReverbEnabled;\n\n    AUDIO_ENGINE_FLAGS                  mEngineFlags;\n\nprivate:\n    using notifylist_t = std::set<IVoiceNotify*>;\n    using oneshotlist_t = std::list<std::pair<unsigned int, IXAudio2SourceVoice*>>;\n    using voicepool_t = std::unordered_multimap<unsigned int, IXAudio2SourceVoice*>;\n\n    AUDIO_STREAM_CATEGORY               mCategory;\n    ComPtr<IUnknown>                    mReverbEffect;\n    ComPtr<IUnknown>                    mVolumeLimiter;\n    oneshotlist_t                       mOneShots;\n    voicepool_t                         mVoicePool;\n    notifylist_t                        mNotifyObjects;\n    notifylist_t                        mNotifyUpdates;\n    size_t                              mVoiceInstances;\n    VoiceCallback                       mVoiceCallback;\n    EngineCallback                      mEngineCallback;\n};\n\n\n_Use_decl_annotations_\nHRESULT AudioEngine::Impl::Initialize(\n    AUDIO_ENGINE_FLAGS flags,\n    const WAVEFORMATEX* wfx,\n    const wchar_t* deviceId,\n    AUDIO_STREAM_CATEGORY category)\n{\n    mEngineFlags = flags;\n    mCategory = category;\n\n    return Reset(wfx, deviceId);\n}\n\n\n_Use_decl_annotations_\nHRESULT AudioEngine::Impl::Reset(const WAVEFORMATEX* wfx, const wchar_t* deviceId)\n{\n    if (wfx)\n    {\n        if (wfx->wFormatTag != WAVE_FORMAT_PCM)\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n        if (!wfx->nChannels || wfx->nChannels > XAUDIO2_MAX_AUDIO_CHANNELS)\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n        if (wfx->nSamplesPerSec < XAUDIO2_MIN_SAMPLE_RATE || wfx->nSamplesPerSec > XAUDIO2_MAX_SAMPLE_RATE)\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n        // We don't use other data members of WAVEFORMATEX here to describe the device format, so no need to fully validate\n    }\n\n    assert(!xaudio2);\n    assert(mMasterVoice == nullptr);\n    assert(mReverbVoice == nullptr);\n\n    masterChannelMask = masterChannels = masterRate = 0;\n\n    memset(&mX3DAudio, 0, X3DAUDIO_HANDLE_BYTESIZE);\n\n    mCriticalError = false;\n    mReverbEnabled = false;\n\n    //\n    // Create XAudio2 engine\n    //\n    HRESULT hr = XAudio2Create(xaudio2.ReleaseAndGetAddressOf(), 0u);\n    if (FAILED(hr))\n        return hr;\n\n    if (mEngineFlags & AudioEngine_Debug)\n    {\n        XAUDIO2_DEBUG_CONFIGURATION debug = {};\n        debug.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;\n        debug.BreakMask = XAUDIO2_LOG_ERRORS;\n        xaudio2->SetDebugConfiguration(&debug, nullptr);\n    #ifdef USING_XAUDIO2_9\n        DebugTrace(\"INFO: XAudio 2.9 debugging enabled\\n\");\n    #else // USING_XAUDIO2_8\n            // To see the trace output, you need to view ETW logs for this application:\n            //    Go to Control Panel, Administrative Tools, Event Viewer.\n            //    View->Show Analytic and Debug Logs.\n            //    Applications and Services Logs / Microsoft / Windows / XAudio2. \n            //    Right click on Microsoft Windows XAudio2 debug logging, Properties, then Enable Logging, and hit OK \n        DebugTrace(\"INFO: XAudio 2.8 debugging enabled\\n\");\n    #endif\n    }\n\n    if (mEngineFlags & AudioEngine_DisableVoiceReuse)\n    {\n        DebugTrace(\"INFO: Voice reuse is disabled\\n\");\n    }\n\n    hr = xaudio2->RegisterForCallbacks(&mEngineCallback);\n    if (FAILED(hr))\n    {\n        xaudio2.Reset();\n        return hr;\n    }\n\n    //\n    // Create mastering voice for device\n    //\n    hr = xaudio2->CreateMasteringVoice(&mMasterVoice,\n        (wfx) ? wfx->nChannels : 0u /*XAUDIO2_DEFAULT_CHANNELS */,\n        (wfx) ? wfx->nSamplesPerSec : 0u /* XAUDIO2_DEFAULT_SAMPLERATE */,\n        0u, deviceId, nullptr, mCategory);\n    if (FAILED(hr))\n    {\n        xaudio2.Reset();\n        return hr;\n    }\n\n    DWORD dwChannelMask;\n    hr = mMasterVoice->GetChannelMask(&dwChannelMask);\n    if (FAILED(hr))\n    {\n        SAFE_DESTROY_VOICE(mMasterVoice)\n        xaudio2.Reset();\n        return hr;\n    }\n\n    XAUDIO2_VOICE_DETAILS details;\n    mMasterVoice->GetVoiceDetails(&details);\n\n    masterChannelMask = dwChannelMask;\n    masterChannels = details.InputChannels;\n    masterRate = details.InputSampleRate;\n\n    DebugTrace(\"INFO: mastering voice has %u channels, %u sample rate, %08X channel mask\\n\",\n        masterChannels, masterRate, masterChannelMask);\n\n    if (mMasterVolume != 1.f)\n    {\n        hr = mMasterVoice->SetVolume(mMasterVolume);\n        if (FAILED(hr))\n        {\n            SAFE_DESTROY_VOICE(mMasterVoice)\n            xaudio2.Reset();\n            return hr;\n        }\n    }\n\n    //\n    // Setup mastering volume limiter (optional)\n    //\n    if (mEngineFlags & AudioEngine_UseMasteringLimiter)\n    {\n        FXMASTERINGLIMITER_PARAMETERS params = {};\n        params.Release = FXMASTERINGLIMITER_DEFAULT_RELEASE;\n        params.Loudness = FXMASTERINGLIMITER_DEFAULT_LOUDNESS;\n\n        hr = CreateFX(__uuidof(FXMasteringLimiter), mVolumeLimiter.ReleaseAndGetAddressOf(), &params, sizeof(params));\n        if (FAILED(hr))\n        {\n            SAFE_DESTROY_VOICE(mMasterVoice)\n            xaudio2.Reset();\n            return hr;\n        }\n\n        XAUDIO2_EFFECT_DESCRIPTOR desc = {};\n        desc.InitialState = TRUE;\n        desc.OutputChannels = masterChannels;\n        desc.pEffect = mVolumeLimiter.Get();\n\n        XAUDIO2_EFFECT_CHAIN chain = { 1, &desc };\n        hr = mMasterVoice->SetEffectChain(&chain);\n        if (FAILED(hr))\n        {\n            SAFE_DESTROY_VOICE(mMasterVoice)\n            mVolumeLimiter.Reset();\n            xaudio2.Reset();\n            return hr;\n        }\n\n        DebugTrace(\"INFO: Mastering volume limiter enabled\\n\");\n    }\n\n    //\n    // Setup environmental reverb for 3D audio (optional)\n    //\n    if (mEngineFlags & AudioEngine_EnvironmentalReverb)\n    {\n        hr = XAudio2CreateReverb(mReverbEffect.ReleaseAndGetAddressOf(), 0u);\n        if (FAILED(hr))\n        {\n            SAFE_DESTROY_VOICE(mMasterVoice)\n            mVolumeLimiter.Reset();\n            xaudio2.Reset();\n            return hr;\n        }\n\n        XAUDIO2_EFFECT_DESCRIPTOR effects[] = { { mReverbEffect.Get(), TRUE, 1 } };\n        XAUDIO2_EFFECT_CHAIN effectChain = { 1, effects };\n\n        mReverbEnabled = true;\n\n        hr = xaudio2->CreateSubmixVoice(&mReverbVoice, 1, masterRate,\n            (mEngineFlags & AudioEngine_ReverbUseFilters) ? XAUDIO2_VOICE_USEFILTER : 0u, 0u,\n            nullptr, &effectChain);\n        if (FAILED(hr))\n        {\n            SAFE_DESTROY_VOICE(mMasterVoice)\n            mReverbEffect.Reset();\n            mVolumeLimiter.Reset();\n            xaudio2.Reset();\n            return hr;\n        }\n\n        XAUDIO2FX_REVERB_PARAMETERS native;\n        ReverbConvertI3DL2ToNative(&gReverbPresets[Reverb_Default], &native);\n        hr = mReverbVoice->SetEffectParameters(0, &native, sizeof(XAUDIO2FX_REVERB_PARAMETERS));\n        if (FAILED(hr))\n        {\n            SAFE_DESTROY_VOICE(mReverbVoice)\n            SAFE_DESTROY_VOICE(mMasterVoice)\n            mReverbEffect.Reset();\n            mVolumeLimiter.Reset();\n            xaudio2.Reset();\n            return hr;\n        }\n\n        DebugTrace(\"INFO: I3DL2 reverb effect enabled for 3D positional audio\\n\");\n    }\n\n    //\n    // Setup 3D audio\n    //\n    constexpr float SPEEDOFSOUND = X3DAUDIO_SPEED_OF_SOUND;\n\n    hr = X3DAudioInitialize(masterChannelMask, SPEEDOFSOUND, mX3DAudio);\n    if (FAILED(hr))\n    {\n        SAFE_DESTROY_VOICE(mReverbVoice)\n        SAFE_DESTROY_VOICE(mMasterVoice)\n        mReverbEffect.Reset();\n        mVolumeLimiter.Reset();\n        xaudio2.Reset();\n        return hr;\n    }\n\n    //\n    // Inform any notify objects we are ready to go again\n    //\n    for (auto it = mNotifyObjects.begin(); it != mNotifyObjects.end(); ++it)\n    {\n        assert(*it != nullptr);\n        (*it)->OnReset();\n    }\n\n    return S_OK;\n}\n\n\nvoid AudioEngine::Impl::SetSilentMode()\n{\n    for (auto it = mNotifyObjects.begin(); it != mNotifyObjects.end(); ++it)\n    {\n        assert(*it != nullptr);\n        (*it)->OnCriticalError();\n    }\n\n    for (auto it = mOneShots.begin(); it != mOneShots.end(); ++it)\n    {\n        assert(it->second != nullptr);\n        it->second->DestroyVoice();\n    }\n    mOneShots.clear();\n\n    for (auto it = mVoicePool.begin(); it != mVoicePool.end(); ++it)\n    {\n        assert(it->second != nullptr);\n        it->second->DestroyVoice();\n    }\n    mVoicePool.clear();\n\n    mVoiceInstances = 0;\n\n    SAFE_DESTROY_VOICE(mReverbVoice)\n    SAFE_DESTROY_VOICE(mMasterVoice)\n\n    mReverbEffect.Reset();\n    mVolumeLimiter.Reset();\n    xaudio2.Reset();\n}\n\n\nvoid AudioEngine::Impl::Shutdown() noexcept\n{\n    for (auto it = mNotifyObjects.begin(); it != mNotifyObjects.end(); ++it)\n    {\n        assert(*it != nullptr);\n        (*it)->OnDestroyEngine();\n    }\n\n    if (xaudio2)\n    {\n        xaudio2->UnregisterForCallbacks(&mEngineCallback);\n\n        xaudio2->StopEngine();\n\n        for (auto it = mOneShots.begin(); it != mOneShots.end(); ++it)\n        {\n            assert(it->second != nullptr);\n            it->second->DestroyVoice();\n        }\n        mOneShots.clear();\n\n        for (auto it = mVoicePool.begin(); it != mVoicePool.end(); ++it)\n        {\n            assert(it->second != nullptr);\n            it->second->DestroyVoice();\n        }\n        mVoicePool.clear();\n\n        mVoiceInstances = 0;\n\n        SAFE_DESTROY_VOICE(mReverbVoice)\n        SAFE_DESTROY_VOICE(mMasterVoice)\n\n        mReverbEffect.Reset();\n        mVolumeLimiter.Reset();\n        xaudio2.Reset();\n\n        masterChannelMask = masterChannels = masterRate = 0;\n\n        mCriticalError = false;\n        mReverbEnabled = false;\n\n        memset(&mX3DAudio, 0, X3DAUDIO_HANDLE_BYTESIZE);\n    }\n}\n\n\nbool AudioEngine::Impl::Update()\n{\n    if (!xaudio2)\n        return false;\n\n    HANDLE events[2] = { mEngineCallback.mCriticalError.get(), mVoiceCallback.mBufferEnd.get() };\n    switch (WaitForMultipleObjectsEx(_countof(events), events, FALSE, 0, FALSE))\n    {\n        default:\n        case WAIT_TIMEOUT:\n            break;\n\n        case WAIT_OBJECT_0:     // OnCritialError\n            mCriticalError = true;\n\n            SetSilentMode();\n            return false;\n\n        case WAIT_OBJECT_0 + 1: // OnBufferEnd\n            // Scan for completed one-shot voices\n            for (auto it = mOneShots.begin(); it != mOneShots.end(); )\n            {\n                assert(it->second != nullptr);\n\n                XAUDIO2_VOICE_STATE xstate;\n                it->second->GetState(&xstate, XAUDIO2_VOICE_NOSAMPLESPLAYED);\n\n                if (!xstate.BuffersQueued)\n                {\n                    (void)it->second->Stop(0);\n                    if (it->first)\n                    {\n                        // Put voice back into voice pool for reuse since it has a non-zero voiceKey\n                    #ifdef VERBOSE_TRACE\n                        DebugTrace(\"INFO: One-shot voice being saved for reuse (%08X)\\n\", it->first);\n                    #endif\n                        voicepool_t::value_type v(it->first, it->second);\n                        mVoicePool.emplace(v);\n                    }\n                    else\n                    {\n                        // Voice is to be destroyed rather than reused\n                    #ifdef VERBOSE_TRACE\n                        DebugTrace(\"INFO: Destroying one-shot voice\\n\");\n                    #endif\n                        it->second->DestroyVoice();\n                    }\n                    it = mOneShots.erase(it);\n                }\n                else\n                    ++it;\n            }\n            break;\n\n        case WAIT_FAILED:\n            throw std::exception(\"WaitForMultipleObjects\");\n    }\n\n    //\n    // Inform any notify objects of updates\n    //\n    for (auto it = mNotifyUpdates.begin(); it != mNotifyUpdates.end(); ++it)\n    {\n        assert(*it != nullptr);\n        (*it)->OnUpdate();\n    }\n\n    return true;\n}\n\n\n_Use_decl_annotations_\nvoid AudioEngine::Impl::SetReverb(const XAUDIO2FX_REVERB_PARAMETERS* native) noexcept\n{\n    if (!mReverbVoice)\n        return;\n\n    if (native)\n    {\n        if (!mReverbEnabled)\n        {\n            mReverbEnabled = true;\n            (void)mReverbVoice->EnableEffect(0);\n        }\n\n        (void)mReverbVoice->SetEffectParameters(0, native, sizeof(XAUDIO2FX_REVERB_PARAMETERS));\n    }\n    else if (mReverbEnabled)\n    {\n        mReverbEnabled = false;\n        (void)mReverbVoice->DisableEffect(0);\n    }\n}\n\n\nvoid AudioEngine::Impl::SetMasteringLimit(int release, int loudness)\n{\n    if (!mVolumeLimiter || !mMasterVoice)\n        return;\n\n    if ((release < FXMASTERINGLIMITER_MIN_RELEASE) || (release > FXMASTERINGLIMITER_MAX_RELEASE))\n        throw std::out_of_range(\"AudioEngine::SetMasteringLimit\");\n\n    if ((loudness < FXMASTERINGLIMITER_MIN_LOUDNESS) || (loudness > FXMASTERINGLIMITER_MAX_LOUDNESS))\n        throw std::out_of_range(\"AudioEngine::SetMasteringLimit\");\n\n    FXMASTERINGLIMITER_PARAMETERS params = {};\n    params.Release = static_cast<UINT32>(release);\n    params.Loudness = static_cast<UINT32>(loudness);\n\n    HRESULT hr = mMasterVoice->SetEffectParameters(0, &params, sizeof(params));\n    ThrowIfFailed(hr);\n}\n\n\nAudioStatistics AudioEngine::Impl::GetStatistics() const\n{\n    AudioStatistics stats = {};\n\n    stats.allocatedVoices = stats.allocatedVoicesOneShot = mOneShots.size() + mVoicePool.size();\n    stats.allocatedVoicesIdle = mVoicePool.size();\n\n    for (auto it = mNotifyObjects.begin(); it != mNotifyObjects.end(); ++it)\n    {\n        assert(*it != nullptr);\n        (*it)->GatherStatistics(stats);\n    }\n\n    assert(stats.allocatedVoices == (mOneShots.size() + mVoicePool.size() + mVoiceInstances));\n\n    return stats;\n}\n\n\nvoid AudioEngine::Impl::TrimVoicePool()\n{\n    for (auto it = mNotifyObjects.begin(); it != mNotifyObjects.end(); ++it)\n    {\n        assert(*it != nullptr);\n        (*it)->OnTrim();\n    }\n\n    for (auto it = mVoicePool.begin(); it != mVoicePool.end(); ++it)\n    {\n        assert(it->second != nullptr);\n        it->second->DestroyVoice();\n    }\n    mVoicePool.clear();\n}\n\n\n_Use_decl_annotations_\nvoid AudioEngine::Impl::AllocateVoice(\n    const WAVEFORMATEX* wfx,\n    SOUND_EFFECT_INSTANCE_FLAGS flags,\n    bool oneshot,\n    IXAudio2SourceVoice** voice)\n{\n    if (!wfx)\n        throw std::exception(\"Wave format is required\\n\");\n\n    // No need to call IsValid on wfx because CreateSourceVoice will do that\n\n    if (!voice)\n        throw std::exception(\"Voice pointer must be non-null\");\n\n    *voice = nullptr;\n\n    if (!xaudio2 || mCriticalError)\n        return;\n\n#ifndef NDEBUG\n    const float maxFrequencyRatio = XAudio2SemitonesToFrequencyRatio(12);\n    assert(maxFrequencyRatio <= XAUDIO2_DEFAULT_FREQ_RATIO);\n#endif\n\n    unsigned int voiceKey = 0;\n    if (oneshot)\n    {\n        if (flags & (SoundEffectInstance_Use3D | SoundEffectInstance_ReverbUseFilters | SoundEffectInstance_NoSetPitch))\n        {\n            DebugTrace((flags & SoundEffectInstance_NoSetPitch)\n                       ? \"ERROR: One-shot voices must support pitch-shifting for voice reuse\\n\"\n                       : \"ERROR: One-use voices cannot use 3D positional audio\\n\");\n            throw std::exception(\"Invalid flags for one-shot voice\");\n        }\n\n    #ifdef VERBOSE_TRACE\n        if (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)\n        {\n            DebugTrace(\"INFO: Requesting one-shot: Format Tag EXTENSIBLE %u, %u channels, %u-bit, %u blkalign, %u Hz\\n\",\n                GetFormatTag(wfx), wfx->nChannels, wfx->wBitsPerSample, wfx->nBlockAlign, wfx->nSamplesPerSec);\n        }\n        else\n        {\n            DebugTrace(\"INFO: Requesting one-shot: Format Tag %u, %u channels, %u-bit, %u blkalign, %u Hz\\n\",\n                wfx->wFormatTag, wfx->nChannels, wfx->wBitsPerSample, wfx->nBlockAlign, wfx->nSamplesPerSec);\n        }\n    #endif\n\n        if (!(mEngineFlags & AudioEngine_DisableVoiceReuse))\n        {\n            voiceKey = makeVoiceKey(wfx);\n            if (voiceKey != 0)\n            {\n                auto it = mVoicePool.find(voiceKey);\n                if (it != mVoicePool.end())\n                {\n                    // Found a matching (stopped) voice to reuse\n                    assert(it->second != nullptr);\n                    *voice = it->second;\n                    mVoicePool.erase(it);\n\n                    // Reset any volume/pitch-shifting\n                    HRESULT hr = (*voice)->SetVolume(1.f);\n                    ThrowIfFailed(hr);\n\n                    hr = (*voice)->SetFrequencyRatio(1.f);\n                    ThrowIfFailed(hr);\n\n                    if (wfx->nChannels == 1 || wfx->nChannels == 2)\n                    {\n                        // Reset any panning\n                        float matrix[16] = {};\n                        ComputePan(0.f, wfx->nChannels, matrix);\n\n                        hr = (*voice)->SetOutputMatrix(nullptr, wfx->nChannels, masterChannels, matrix);\n                        ThrowIfFailed(hr);\n                    }\n                }\n                else if ((mVoicePool.size() + mOneShots.size() + 1) >= maxVoiceOneshots)\n                {\n                    DebugTrace(\"WARNING: Too many one-shot voices in use (%zu + %zu >= %zu); one-shot not played\\n\",\n                               mVoicePool.size(), mOneShots.size() + 1, maxVoiceOneshots);\n                    return;\n                }\n                else\n                {\n                    // makeVoiceKey already constrained the supported wfx formats to those supported for reuse\n\n                    char buff[64] = {};\n                    auto wfmt = reinterpret_cast<WAVEFORMATEX*>(buff);\n\n                    uint32_t tag = GetFormatTag(wfx);\n                    switch (tag)\n                    {\n                        case WAVE_FORMAT_PCM:\n                            CreateIntegerPCM(wfmt, defaultRate, wfx->nChannels, wfx->wBitsPerSample);\n                            break;\n\n                        case WAVE_FORMAT_IEEE_FLOAT:\n                            CreateFloatPCM(wfmt, defaultRate, wfx->nChannels);\n                            break;\n\n                        case WAVE_FORMAT_ADPCM:\n                        {\n                            auto wfadpcm = reinterpret_cast<const ADPCMWAVEFORMAT*>(wfx);\n                            CreateADPCM(wfmt, sizeof(buff), defaultRate, wfx->nChannels, wfadpcm->wSamplesPerBlock);\n                        }\n                        break;\n\n                        #ifdef DIRECTX_ENABLE_XMA2\n                        case WAVE_FORMAT_XMA2:\n                            CreateXMA2(wfmt, sizeof(buff), defaultRate, wfx->nChannels, 65536, 2, 0);\n                            break;\n                        #endif\n                    }\n\n                #ifdef VERBOSE_TRACE\n                    DebugTrace(\"INFO: Allocate reuse voice: Format Tag %u, %u channels, %u-bit, %u blkalign, %u Hz\\n\",\n                        wfmt->wFormatTag, wfmt->nChannels, wfmt->wBitsPerSample, wfmt->nBlockAlign, wfmt->nSamplesPerSec);\n                #endif\n\n                    assert(voiceKey == makeVoiceKey(wfmt));\n\n                    HRESULT hr = xaudio2->CreateSourceVoice(voice, wfmt, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &mVoiceCallback, nullptr, nullptr);\n                    if (FAILED(hr))\n                    {\n                        DebugTrace(\"ERROR: CreateSourceVoice (reuse) failed with error %08X\\n\", static_cast<unsigned int>(hr));\n                        throw std::exception(\"CreateSourceVoice\");\n                    }\n                }\n\n                assert(*voice != nullptr);\n                HRESULT hr = (*voice)->SetSourceSampleRate(wfx->nSamplesPerSec);\n                if (FAILED(hr))\n                {\n                    DebugTrace(\"ERROR: SetSourceSampleRate failed with error %08X\\n\", static_cast<unsigned int>(hr));\n                    throw std::exception(\"SetSourceSampleRate\");\n                }\n            }\n        }\n    }\n\n    if (!*voice)\n    {\n        if (oneshot)\n        {\n            if ((mVoicePool.size() + mOneShots.size() + 1) >= maxVoiceOneshots)\n            {\n                DebugTrace(\"WARNING: Too many one-shot voices in use (%zu + %zu >= %zu); one-shot not played; see TrimVoicePool\\n\",\n                           mVoicePool.size(), mOneShots.size() + 1, maxVoiceOneshots);\n                return;\n            }\n        }\n        else if ((mVoiceInstances + 1) >= maxVoiceInstances)\n        {\n            DebugTrace(\"ERROR: Too many instance voices (%zu >= %zu); see TrimVoicePool\\n\",\n                mVoiceInstances + 1, maxVoiceInstances);\n            throw std::exception(\"Too many instance voices\");\n        }\n\n        UINT32 vflags = (flags & SoundEffectInstance_NoSetPitch) ? XAUDIO2_VOICE_NOPITCH : 0u;\n\n        HRESULT hr;\n        if (flags & SoundEffectInstance_Use3D)\n        {\n            XAUDIO2_SEND_DESCRIPTOR sendDescriptors[2] = {};\n            sendDescriptors[0].Flags = sendDescriptors[1].Flags = (flags & SoundEffectInstance_ReverbUseFilters)\n                ? XAUDIO2_SEND_USEFILTER : 0u;\n            sendDescriptors[0].pOutputVoice = mMasterVoice;\n            sendDescriptors[1].pOutputVoice = mReverbVoice;\n            const XAUDIO2_VOICE_SENDS sendList = { mReverbVoice ? 2U : 1U, sendDescriptors };\n\n        #ifdef VERBOSE_TRACE\n            DebugTrace(\"INFO: Allocate voice 3D: Format Tag %u, %u channels, %u-bit, %u blkalign, %u Hz\\n\",\n                wfx->wFormatTag, wfx->nChannels, wfx->wBitsPerSample, wfx->nBlockAlign, wfx->nSamplesPerSec);\n        #endif\n\n            hr = xaudio2->CreateSourceVoice(voice, wfx, vflags, XAUDIO2_DEFAULT_FREQ_RATIO, &mVoiceCallback, &sendList, nullptr);\n        }\n        else\n        {\n        #ifdef VERBOSE_TRACE\n            DebugTrace(\"INFO: Allocate voice: Format Tag %u, %u channels, %u-bit, %u blkalign, %u Hz\\n\",\n                wfx->wFormatTag, wfx->nChannels, wfx->wBitsPerSample, wfx->nBlockAlign, wfx->nSamplesPerSec);\n        #endif\n\n            hr = xaudio2->CreateSourceVoice(voice, wfx, vflags, XAUDIO2_DEFAULT_FREQ_RATIO, &mVoiceCallback, nullptr, nullptr);\n        }\n\n        if (FAILED(hr))\n        {\n            DebugTrace(\"ERROR: CreateSourceVoice failed with error %08X\\n\", static_cast<unsigned int>(hr));\n            throw std::exception(\"CreateSourceVoice\");\n        }\n        else if (!oneshot)\n        {\n            ++mVoiceInstances;\n        }\n    }\n\n    if (oneshot)\n    {\n        assert(*voice != nullptr);\n        mOneShots.emplace_back(std::make_pair(voiceKey, *voice));\n    }\n}\n\n\nvoid AudioEngine::Impl::DestroyVoice(_In_ IXAudio2SourceVoice* voice) noexcept\n{\n    if (!voice)\n        return;\n\n#ifndef NDEBUG\n    for (auto it = mOneShots.cbegin(); it != mOneShots.cend(); ++it)\n    {\n        if (it->second == voice)\n        {\n            DebugTrace(\"ERROR: DestroyVoice should not be called for a one-shot voice\\n\");\n            return;\n        }\n    }\n\n    for (auto it = mVoicePool.cbegin(); it != mVoicePool.cend(); ++it)\n    {\n        if (it->second == voice)\n        {\n            DebugTrace(\"ERROR: DestroyVoice should not be called for a one-shot voice; see TrimVoicePool\\n\");\n            return;\n        }\n    }\n#endif\n\n    assert(mVoiceInstances > 0);\n    --mVoiceInstances;\n    voice->DestroyVoice();\n}\n\n\nvoid AudioEngine::Impl::RegisterNotify(_In_ IVoiceNotify* notify, bool usesUpdate)\n{\n    assert(notify != nullptr);\n    mNotifyObjects.insert(notify);\n\n    if (usesUpdate)\n    {\n        mNotifyUpdates.insert(notify);\n    }\n}\n\n\nvoid AudioEngine::Impl::UnregisterNotify(_In_ IVoiceNotify* notify, bool usesOneShots, bool usesUpdate)\n{\n    assert(notify != nullptr);\n    mNotifyObjects.erase(notify);\n\n    // Check for any pending one-shots for this notification object\n    if (usesOneShots)\n    {\n        bool setevent = false;\n\n        for (auto it = mOneShots.begin(); it != mOneShots.end(); ++it)\n        {\n            assert(it->second != nullptr);\n\n            XAUDIO2_VOICE_STATE state;\n            it->second->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);\n\n            if (state.pCurrentBufferContext == notify)\n            {\n                (void)it->second->Stop(0);\n                (void)it->second->FlushSourceBuffers();\n                setevent = true;\n            }\n        }\n\n        if (setevent)\n        {\n            // Trigger scan on next call to Update...\n            SetEvent(mVoiceCallback.mBufferEnd.get());\n        }\n    }\n\n    if (usesUpdate)\n    {\n        mNotifyUpdates.erase(notify);\n    }\n}\n\n\n//--------------------------------------------------------------------------------------\n// AudioEngine\n//--------------------------------------------------------------------------------------\n\n// Public constructor.\n_Use_decl_annotations_\nAudioEngine::AudioEngine(\n    AUDIO_ENGINE_FLAGS flags,\n    const WAVEFORMATEX* wfx,\n    const wchar_t* deviceId,\n    AUDIO_STREAM_CATEGORY category) noexcept(false)\n    : pImpl(std::make_unique<Impl>())\n{\n    HRESULT hr = pImpl->Initialize(flags, wfx, deviceId, category);\n    if (FAILED(hr))\n    {\n        if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))\n        {\n            if (flags & AudioEngine_ThrowOnNoAudioHW)\n            {\n                DebugTrace(\"ERROR: AudioEngine found no default audio device\\n\");\n                throw std::exception(\"AudioEngineNoAudioHW\");\n            }\n            else\n            {\n                DebugTrace(\"WARNING: AudioEngine found no default audio device; running in 'silent mode'\\n\");\n            }\n        }\n        else\n        {\n            DebugTrace(\"ERROR: AudioEngine failed (%08X) to initialize using device [%ls]\\n\",\n                static_cast<unsigned int>(hr),\n                (deviceId) ? deviceId : L\"default\");\n            throw std::exception(\"AudioEngine\");\n        }\n    }\n}\n\n\n// Move constructor.\nAudioEngine::AudioEngine(AudioEngine&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nAudioEngine& AudioEngine::operator= (AudioEngine&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nAudioEngine::~AudioEngine()\n{\n    if (pImpl)\n    {\n        pImpl->Shutdown();\n    }\n}\n\n\n// Public methods.\nbool AudioEngine::Update()\n{\n    return pImpl->Update();\n}\n\n\n_Use_decl_annotations_\nbool AudioEngine::Reset(const WAVEFORMATEX* wfx, const wchar_t* deviceId)\n{\n    if (pImpl->xaudio2)\n    {\n        DebugTrace(\"WARNING: Called Reset for active audio graph; going silent in preparation for migration\\n\");\n        pImpl->SetSilentMode();\n    }\n\n    HRESULT hr = pImpl->Reset(wfx, deviceId);\n    if (FAILED(hr))\n    {\n        if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))\n        {\n            if (pImpl->mEngineFlags & AudioEngine_ThrowOnNoAudioHW)\n            {\n                DebugTrace(\"ERROR: AudioEngine found no default audio device on Reset\\n\");\n                throw std::exception(\"AudioEngineNoAudioHW\");\n            }\n            else\n            {\n                DebugTrace(\"WARNING: AudioEngine found no default audio device on Reset; running in 'silent mode'\\n\");\n                return false;\n            }\n        }\n        else\n        {\n            DebugTrace(\"ERROR: AudioEngine failed (%08X) to Reset using device [%ls]\\n\",\n                static_cast<unsigned int>(hr), (deviceId) ? deviceId : L\"default\");\n            throw std::exception(\"AudioEngine::Reset\");\n        }\n    }\n\n    DebugTrace(\"INFO: AudioEngine Reset using device [%ls]\\n\", (deviceId) ? deviceId : L\"default\");\n\n    return true;\n}\n\n\nvoid AudioEngine::Suspend() noexcept\n{\n    if (!pImpl->xaudio2)\n        return;\n\n    pImpl->xaudio2->StopEngine();\n}\n\n\nvoid AudioEngine::Resume()\n{\n    if (!pImpl->xaudio2)\n        return;\n\n    HRESULT hr = pImpl->xaudio2->StartEngine();\n    ThrowIfFailed(hr);\n}\n\n\nfloat AudioEngine::GetMasterVolume() const noexcept\n{\n    return pImpl->mMasterVolume;\n}\n\n\nvoid AudioEngine::SetMasterVolume(float volume)\n{\n    assert(volume >= -XAUDIO2_MAX_VOLUME_LEVEL && volume <= XAUDIO2_MAX_VOLUME_LEVEL);\n\n    pImpl->mMasterVolume = volume;\n\n    if (pImpl->mMasterVoice)\n    {\n        HRESULT hr = pImpl->mMasterVoice->SetVolume(volume);\n        ThrowIfFailed(hr);\n    }\n}\n\n\nvoid AudioEngine::SetReverb(AUDIO_ENGINE_REVERB reverb)\n{\n    if (reverb >= Reverb_MAX)\n        throw std::out_of_range(\"AudioEngine::SetReverb\");\n\n    if (reverb == Reverb_Off)\n    {\n        pImpl->SetReverb(nullptr);\n    }\n    else\n    {\n        XAUDIO2FX_REVERB_PARAMETERS native;\n        ReverbConvertI3DL2ToNative(&gReverbPresets[reverb], &native);\n        pImpl->SetReverb(&native);\n    }\n}\n\n\n_Use_decl_annotations_\nvoid AudioEngine::SetReverb(const XAUDIO2FX_REVERB_PARAMETERS* native)\n{\n    pImpl->SetReverb(native);\n}\n\n\nvoid AudioEngine::SetMasteringLimit(int release, int loudness)\n{\n    pImpl->SetMasteringLimit(release, loudness);\n}\n\n\n// Public accessors.\nAudioStatistics AudioEngine::GetStatistics() const\n{\n    return pImpl->GetStatistics();\n}\n\n\nWAVEFORMATEXTENSIBLE AudioEngine::GetOutputFormat() const noexcept\n{\n    WAVEFORMATEXTENSIBLE wfx = {};\n\n    if (!pImpl->xaudio2)\n        return wfx;\n\n    wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;\n    wfx.Format.wBitsPerSample = wfx.Samples.wValidBitsPerSample = 16; // This is a guess\n    wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);\n\n    wfx.Format.nChannels = static_cast<WORD>(pImpl->masterChannels);\n    wfx.Format.nSamplesPerSec = pImpl->masterRate;\n    wfx.dwChannelMask = pImpl->masterChannelMask;\n\n    wfx.Format.nBlockAlign = static_cast<WORD>(wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8);\n    wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;\n\n    static const GUID s_pcm = { WAVE_FORMAT_PCM, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 } };\n    memcpy(&wfx.SubFormat, &s_pcm, sizeof(GUID));\n\n    return wfx;\n}\n\n\nuint32_t AudioEngine::GetChannelMask() const noexcept\n{\n    return pImpl->masterChannelMask;\n}\n\n\nunsigned int AudioEngine::GetOutputChannels() const noexcept\n{\n    return pImpl->masterChannels;\n}\n\n\nbool AudioEngine::IsAudioDevicePresent() const noexcept\n{\n    return pImpl->xaudio2 && !pImpl->mCriticalError;\n}\n\n\nbool AudioEngine::IsCriticalError() const noexcept\n{\n    return pImpl->mCriticalError;\n}\n\n\n// Voice management.\nvoid AudioEngine::SetDefaultSampleRate(int sampleRate)\n{\n    if ((sampleRate < XAUDIO2_MIN_SAMPLE_RATE) || (sampleRate > XAUDIO2_MAX_SAMPLE_RATE))\n        throw std::exception(\"Default sample rate is out of range\");\n\n    pImpl->defaultRate = sampleRate;\n}\n\n\nvoid AudioEngine::SetMaxVoicePool(size_t maxOneShots, size_t maxInstances)\n{\n    if (maxOneShots > 0)\n        pImpl->maxVoiceOneshots = maxOneShots;\n\n    if (maxInstances > 0)\n        pImpl->maxVoiceInstances = maxInstances;\n}\n\n\nvoid AudioEngine::TrimVoicePool()\n{\n    pImpl->TrimVoicePool();\n}\n\n\n_Use_decl_annotations_\nvoid AudioEngine::AllocateVoice(\n    const WAVEFORMATEX* wfx,\n    SOUND_EFFECT_INSTANCE_FLAGS flags,\n    bool oneshot,\n    IXAudio2SourceVoice** voice)\n{\n    pImpl->AllocateVoice(wfx, flags, oneshot, voice);\n}\n\n\nvoid AudioEngine::DestroyVoice(_In_ IXAudio2SourceVoice* voice) noexcept\n{\n    pImpl->DestroyVoice(voice);\n}\n\n\nvoid AudioEngine::RegisterNotify(_In_ IVoiceNotify* notify, bool usesUpdate)\n{\n    pImpl->RegisterNotify(notify, usesUpdate);\n}\n\n\nvoid AudioEngine::UnregisterNotify(_In_ IVoiceNotify* notify, bool oneshots, bool usesUpdate)\n{\n    pImpl->UnregisterNotify(notify, oneshots, usesUpdate);\n}\n\n\nIXAudio2* AudioEngine::GetInterface() const noexcept\n{\n    return pImpl->xaudio2.Get();\n}\n\n\nIXAudio2MasteringVoice* AudioEngine::GetMasterVoice() const noexcept\n{\n    return pImpl->mMasterVoice;\n}\n\n\nIXAudio2SubmixVoice* AudioEngine::GetReverbVoice() const noexcept\n{\n    return pImpl->mReverbVoice;\n}\n\n\nX3DAUDIO_HANDLE& AudioEngine::Get3DHandle() const noexcept\n{\n    return pImpl->mX3DAudio;\n}\n\n\n// Static methods.\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n#include <mmdeviceapi.h>\n#elif defined(_XBOX_ONE)\n#include <Windows.Media.Devices.h>\n#include <wrl.h>\n#elif defined(USING_XAUDIO2_REDIST) || defined(_GAMING_DESKTOP)\n#include <mmdeviceapi.h>\n#include <functiondiscoverykeys_devpkey.h>\n#elif (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n#pragma comment(lib,\"runtimeobject.lib\")\n#pragma warning(push)\n#pragma warning(disable: 4471 5204)\n#include <windows.devices.enumeration.h>\n#pragma warning(pop)\n#include <wrl.h>\n#endif\n\nstd::vector<AudioEngine::RendererDetail> AudioEngine::GetRendererDetails()\n{\n    std::vector<RendererDetail> list;\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n\n    ComPtr<IMMDeviceEnumerator> devEnum;\n    HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(devEnum.GetAddressOf()));\n    ThrowIfFailed(hr);\n\n    ComPtr<IMMDeviceCollection> devices;\n    hr = devEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);\n    ThrowIfFailed(hr);\n\n    ComPtr<IMMDevice> endpoint;\n    ThrowIfFailed(devices->Item(0, endpoint.GetAddressOf()));\n\n    LPWSTR id = nullptr;\n    ThrowIfFailed(endpoint->GetId(&id));\n\n    RendererDetail device;\n    device.deviceId = id;\n    device.description = L\"Default\";\n\n    CoTaskMemFree(id);\n\n    list.emplace_back(device);\n\n#elif defined(_XBOX_ONE)\n\n    using namespace Microsoft::WRL;\n    using namespace Microsoft::WRL::Wrappers;\n    using namespace ABI::Windows::Foundation;\n    using namespace ABI::Windows::Media::Devices;\n\n    ComPtr<IMediaDeviceStatics> mdStatics;\n    HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Media_Devices_MediaDevice).Get(), &mdStatics);\n    ThrowIfFailed(hr);\n\n    HString id;\n    hr = mdStatics->GetDefaultAudioRenderId(AudioDeviceRole_Default, id.GetAddressOf());\n    ThrowIfFailed(hr);\n\n    RendererDetail device;\n    device.deviceId = id.GetRawBuffer(nullptr);\n    device.description = L\"Default\";\n    list.emplace_back(device);\n\n#elif defined(USING_XAUDIO2_REDIST) || defined(_GAMING_DESKTOP)\n\n    ComPtr<IMMDeviceEnumerator> devEnum;\n    HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(devEnum.GetAddressOf()));\n    ThrowIfFailed(hr);\n\n    ComPtr<IMMDeviceCollection> devices;\n    hr = devEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);\n    ThrowIfFailed(hr);\n\n    UINT count = 0;\n    ThrowIfFailed(devices->GetCount(&count));\n\n    if (!count)\n        return list;\n\n    for (UINT j = 0; j < count; ++j)\n    {\n        ComPtr<IMMDevice> endpoint;\n        hr = devices->Item(j, endpoint.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        LPWSTR id = nullptr;\n        ThrowIfFailed(endpoint->GetId(&id));\n\n        RendererDetail device;\n        device.deviceId = id;\n        CoTaskMemFree(id);\n\n        ComPtr<IPropertyStore> props;\n        if (SUCCEEDED(endpoint->OpenPropertyStore(STGM_READ, props.GetAddressOf())))\n        {\n            PROPVARIANT var;\n            PropVariantInit(&var);\n\n            if (SUCCEEDED(props->GetValue(PKEY_Device_FriendlyName, &var)))\n            {\n                if (var.vt == VT_LPWSTR)\n                {\n                    device.description = var.pwszVal;\n                }\n                PropVariantClear(&var);\n            }\n        }\n\n        list.emplace_back(device);\n    }\n\n#elif (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n\n#if defined(__cplusplus_winrt)\n\n    // Enumerating with WinRT using C++/CX (Windows Store apps)\n    using Windows::Devices::Enumeration::DeviceClass;\n    using Windows::Devices::Enumeration::DeviceInformation;\n    using Windows::Devices::Enumeration::DeviceInformationCollection;\n\n    auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);\n    while (operation->Status == Windows::Foundation::AsyncStatus::Started) { Sleep(100); }\n    if (operation->Status != Windows::Foundation::AsyncStatus::Completed)\n    {\n        throw std::exception(\"FindAllAsync\");\n    }\n\n    DeviceInformationCollection^ devices = operation->GetResults();\n\n    for (unsigned i = 0; i < devices->Size; ++i)\n    {\n        using Windows::Devices::Enumeration::DeviceInformation;\n\n        DeviceInformation^ d = devices->GetAt(i);\n\n        RendererDetail device;\n        device.deviceId = d->Id->Data();\n        device.description = d->Name->Data();\n        list.emplace_back(device);\n    }\n#else\n\n    // Enumerating with WinRT using WRL (Win32 desktop app for Windows 8.x)\n    using namespace Microsoft::WRL;\n    using namespace Microsoft::WRL::Wrappers;\n    using namespace ABI::Windows::Foundation;\n    using namespace ABI::Windows::Foundation::Collections;\n    using namespace ABI::Windows::Devices::Enumeration;\n\n#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);\n    ThrowIfFailed(initialize);\n#endif\n\n    ComPtr<IDeviceInformationStatics> diFactory;\n    HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &diFactory);\n    ThrowIfFailed(hr);\n\n    ComPtr<IAsyncOperation<DeviceInformationCollection*>> operation;\n    hr = diFactory->FindAllAsyncDeviceClass(DeviceClass_AudioRender, operation.GetAddressOf());\n    ThrowIfFailed(hr);\n\n    ComPtr<IAsyncInfo> asyncinfo;\n    hr = operation.As(&asyncinfo);\n    ThrowIfFailed(hr);\n\n    AsyncStatus status;\n    hr = asyncinfo->get_Status(&status);\n    ThrowIfFailed(hr);\n\n    while (status == ABI::Windows::Foundation::AsyncStatus::Started)\n    {\n        Sleep(100);\n        hr = asyncinfo->get_Status(&status);\n        ThrowIfFailed(hr);\n    }\n\n    if (status != ABI::Windows::Foundation::AsyncStatus::Completed)\n    {\n        throw std::exception(\"FindAllAsyncDeviceClass\");\n    }\n\n    ComPtr<IVectorView<DeviceInformation*>> devices;\n    hr = operation->GetResults(devices.GetAddressOf());\n    ThrowIfFailed(hr);\n\n    unsigned int count = 0;\n    hr = devices->get_Size(&count);\n    ThrowIfFailed(hr);\n\n    if (!count)\n        return list;\n\n    for (unsigned int j = 0; j < count; ++j)\n    {\n        ComPtr<IDeviceInformation> deviceInfo;\n        hr = devices->GetAt(j, deviceInfo.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            RendererDetail device;\n\n            HString id;\n            if (SUCCEEDED(deviceInfo->get_Id(id.GetAddressOf())))\n            {\n                device.deviceId = id.GetRawBuffer(nullptr);\n            }\n\n            HString name;\n            if (SUCCEEDED(deviceInfo->get_Name(name.GetAddressOf())))\n            {\n                device.description = name.GetRawBuffer(nullptr);\n            }\n\n            list.emplace_back(device);\n        }\n    }\n#endif\n#else\n#error DirectX Tool Kit for Audio not supported on this platform\n#endif\n\n    return list;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/DynamicSoundEffectInstance.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DynamicSoundEffectInstance.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"SoundCommon.h\"\n\nusing namespace DirectX;\n\n\n//======================================================================================\n// DynamicSoundEffectInstance\n//======================================================================================\n\n// Internal object implementation class.\nclass DynamicSoundEffectInstance::Impl : public IVoiceNotify\n{\npublic:\n    Impl(_In_ AudioEngine* engine,\n         _In_ DynamicSoundEffectInstance* object,\n        std::function<void(DynamicSoundEffectInstance*)>& bufferNeeded,\n         int sampleRate, int channels, int sampleBits,\n        SOUND_EFFECT_INSTANCE_FLAGS flags) :\n        mBase(),\n        mBufferNeeded(nullptr),\n        mObject(object)\n    {\n        if ((sampleRate < XAUDIO2_MIN_SAMPLE_RATE)\n            || (sampleRate > XAUDIO2_MAX_SAMPLE_RATE))\n        {\n            DebugTrace(\"DynamicSoundEffectInstance sampleRate must be in range %u...%u\\n\", XAUDIO2_MIN_SAMPLE_RATE, XAUDIO2_MAX_SAMPLE_RATE);\n            throw std::invalid_argument(\"DynamicSoundEffectInstance\");\n        }\n\n        if (!channels || (channels > 8))\n        {\n            DebugTrace(\"DynamicSoundEffectInstance channels must be in range 1...8\\n\");\n            throw std::invalid_argument(\"DynamicSoundEffectInstance\");\n        }\n\n        switch (sampleBits)\n        {\n            case 8:\n            case 16:\n                break;\n\n            default:\n                DebugTrace(\"DynamicSoundEffectInstance sampleBits must be 8-bit or 16-bit\\n\");\n                throw std::invalid_argument(\"DynamicSoundEffectInstance\");\n        }\n\n        mBufferEvent.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mBufferEvent)\n        {\n            throw std::exception(\"CreateEvent\");\n        }\n\n        CreateIntegerPCM(&mWaveFormat, sampleRate, channels, sampleBits);\n\n        assert(engine != nullptr);\n        engine->RegisterNotify(this, true);\n\n        mBase.Initialize(engine, &mWaveFormat, flags);\n\n        mBufferNeeded = bufferNeeded;\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl() override\n    {\n        mBase.DestroyVoice();\n\n        if (mBase.engine)\n        {\n            mBase.engine->UnregisterNotify(this, false, true);\n            mBase.engine = nullptr;\n        }\n    }\n\n    void Play();\n\n    void Resume();\n\n    void SubmitBuffer(_In_reads_bytes_(audioBytes) const uint8_t* pAudioData, uint32_t offset, size_t audioBytes);\n\n    const WAVEFORMATEX* GetFormat() const noexcept { return &mWaveFormat; }\n\n    // IVoiceNotify\n    void __cdecl OnBufferEnd() override\n    {\n        SetEvent(mBufferEvent.get());\n    }\n\n    void __cdecl OnCriticalError() override\n    {\n        mBase.OnCriticalError();\n    }\n\n    void __cdecl OnReset() override\n    {\n        mBase.OnReset();\n    }\n\n    void __cdecl OnUpdate() override;\n\n    void __cdecl OnDestroyEngine() noexcept override\n    {\n        mBase.OnDestroy();\n    }\n\n    void __cdecl OnTrim() override\n    {\n        mBase.OnTrim();\n    }\n\n    void __cdecl GatherStatistics(AudioStatistics& stats) const noexcept override\n    {\n        mBase.GatherStatistics(stats);\n    }\n\n    void __cdecl OnDestroyParent() noexcept override\n    {\n    }\n\n    SoundEffectInstanceBase                             mBase;\n\nprivate:\n    ScopedHandle                                        mBufferEvent;\n    std::function<void(DynamicSoundEffectInstance*)>    mBufferNeeded;\n    DynamicSoundEffectInstance*                         mObject;\n    WAVEFORMATEX                                        mWaveFormat;\n};\n\n\nvoid DynamicSoundEffectInstance::Impl::Play()\n{\n    if (!mBase.voice)\n    {\n        mBase.AllocateVoice(&mWaveFormat);\n    }\n\n    (void)mBase.Play();\n\n    if (mBase.voice && (mBase.state == PLAYING) && (mBase.GetPendingBufferCount() <= 2))\n    {\n        SetEvent(mBufferEvent.get());\n    }\n}\n\n\nvoid DynamicSoundEffectInstance::Impl::Resume()\n{\n    if (mBase.voice && (mBase.state == PAUSED))\n    {\n        mBase.Resume();\n\n        if ((mBase.state == PLAYING) && (mBase.GetPendingBufferCount() <= 2))\n        {\n            SetEvent(mBufferEvent.get());\n        }\n    }\n}\n\n\n_Use_decl_annotations_\nvoid DynamicSoundEffectInstance::Impl::SubmitBuffer(const uint8_t* pAudioData, uint32_t offset, size_t audioBytes)\n{\n    if (!pAudioData || !audioBytes)\n        throw std::exception(\"Invalid audio data buffer\");\n\n    if (audioBytes > UINT32_MAX)\n        throw std::out_of_range(\"SubmitBuffer\");\n\n    XAUDIO2_BUFFER buffer = {};\n    buffer.AudioBytes = static_cast<UINT32>(audioBytes);\n    buffer.pAudioData = pAudioData;\n\n    if (offset)\n    {\n        assert(mWaveFormat.wFormatTag == WAVE_FORMAT_PCM);\n        buffer.PlayBegin = offset / mWaveFormat.nBlockAlign;\n        buffer.PlayLength = static_cast<UINT32>((audioBytes - offset) / mWaveFormat.nBlockAlign);\n    }\n\n    buffer.pContext = this;\n\n    HRESULT hr = mBase.voice->SubmitSourceBuffer(&buffer, nullptr);\n    if (FAILED(hr))\n    {\n    #ifdef _DEBUG\n        DebugTrace(\"ERROR: DynamicSoundEffectInstance failed (%08X) when submitting buffer:\\n\", static_cast<unsigned int>(hr));\n\n        DebugTrace(\"\\tFormat Tag %u, %u channels, %u-bit, %u Hz, %zu bytes [%u offset)\\n\",\n            mWaveFormat.wFormatTag, mWaveFormat.nChannels, mWaveFormat.wBitsPerSample, mWaveFormat.nSamplesPerSec, audioBytes, offset);\n    #endif\n        throw std::exception(\"SubmitSourceBuffer\");\n    }\n}\n\n\nvoid DynamicSoundEffectInstance::Impl::OnUpdate()\n{\n    DWORD result = WaitForSingleObjectEx(mBufferEvent.get(), 0, FALSE);\n    switch (result)\n    {\n        case WAIT_TIMEOUT:\n            break;\n\n        case WAIT_OBJECT_0:\n            if (mBufferNeeded)\n            {\n                // This callback happens on the same thread that called AudioEngine::Update()\n                mBufferNeeded(mObject);\n            }\n            break;\n\n        case WAIT_FAILED:\n            throw std::exception(\"WaitForSingleObjectEx\");\n    }\n}\n\n\n\n//--------------------------------------------------------------------------------------\n// DynamicSoundEffectInstance\n//--------------------------------------------------------------------------------------\n\n#pragma warning( disable : 4355 )\n\n// Public constructors\n_Use_decl_annotations_\nDynamicSoundEffectInstance::DynamicSoundEffectInstance(\n    AudioEngine* engine,\n    std::function<void(DynamicSoundEffectInstance*)> bufferNeeded,\n    int sampleRate,\n    int channels,\n    int sampleBits,\n    SOUND_EFFECT_INSTANCE_FLAGS flags) :\n    pImpl(std::make_unique<Impl>(engine, this, bufferNeeded, sampleRate, channels, sampleBits, flags))\n{\n}\n\n\n// Move constructor.\nDynamicSoundEffectInstance::DynamicSoundEffectInstance(DynamicSoundEffectInstance&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nDynamicSoundEffectInstance& DynamicSoundEffectInstance::operator= (DynamicSoundEffectInstance&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nDynamicSoundEffectInstance::~DynamicSoundEffectInstance()\n{\n}\n\n\n// Public methods.\nvoid DynamicSoundEffectInstance::Play()\n{\n    pImpl->Play();\n}\n\n\nvoid DynamicSoundEffectInstance::Stop(bool immediate) noexcept\n{\n    bool looped = false;\n    pImpl->mBase.Stop(immediate, looped);\n}\n\n\nvoid DynamicSoundEffectInstance::Pause() noexcept\n{\n    pImpl->mBase.Pause();\n}\n\n\nvoid DynamicSoundEffectInstance::Resume()\n{\n    pImpl->Resume();\n}\n\n\nvoid DynamicSoundEffectInstance::SetVolume(float volume)\n{\n    pImpl->mBase.SetVolume(volume);\n}\n\n\nvoid DynamicSoundEffectInstance::SetPitch(float pitch)\n{\n    pImpl->mBase.SetPitch(pitch);\n}\n\n\nvoid DynamicSoundEffectInstance::SetPan(float pan)\n{\n    pImpl->mBase.SetPan(pan);\n}\n\n\nvoid DynamicSoundEffectInstance::Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords)\n{\n    pImpl->mBase.Apply3D(listener, emitter, rhcoords);\n}\n\n\n_Use_decl_annotations_\nvoid DynamicSoundEffectInstance::SubmitBuffer(const uint8_t* pAudioData, size_t audioBytes)\n{\n    pImpl->SubmitBuffer(pAudioData, 0, audioBytes);\n}\n\n\n_Use_decl_annotations_\nvoid DynamicSoundEffectInstance::SubmitBuffer(const uint8_t* pAudioData, uint32_t offset, size_t audioBytes)\n{\n    pImpl->SubmitBuffer(pAudioData, offset, audioBytes);\n}\n\n\n// Public accessors.\nSoundState DynamicSoundEffectInstance::GetState() noexcept\n{\n    return pImpl->mBase.GetState(false);\n}\n\n\nsize_t DynamicSoundEffectInstance::GetSampleDuration(size_t bytes) const noexcept\n{\n    auto wfx = pImpl->GetFormat();\n    if (!wfx || !wfx->wBitsPerSample || !wfx->nChannels)\n        return 0;\n\n    return static_cast<size_t>((uint64_t(bytes) * 8)\n                               / (uint64_t(wfx->wBitsPerSample) * uint64_t(wfx->nChannels)));\n}\n\n\nsize_t DynamicSoundEffectInstance::GetSampleDurationMS(size_t bytes) const noexcept\n{\n    auto wfx = pImpl->GetFormat();\n    if (!wfx || !wfx->nAvgBytesPerSec)\n        return 0;\n\n    return static_cast<size_t>((uint64_t(bytes) * 1000) / wfx->nAvgBytesPerSec);\n}\n\n\nsize_t DynamicSoundEffectInstance::GetSampleSizeInBytes(uint64_t duration) const noexcept\n{\n    auto wfx = pImpl->GetFormat();\n    if (!wfx || !wfx->nSamplesPerSec)\n        return 0;\n\n    return static_cast<size_t>(((duration * wfx->nSamplesPerSec) / 1000) * wfx->nBlockAlign);\n}\n\n\nint DynamicSoundEffectInstance::GetPendingBufferCount() const noexcept\n{\n    return pImpl->mBase.GetPendingBufferCount();\n}\n\n\nconst WAVEFORMATEX* DynamicSoundEffectInstance::GetFormat() const noexcept\n{\n    return pImpl->GetFormat();\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/SoundCommon.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SoundCommon.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"SoundCommon.h\"\n\nusing namespace DirectX;\n\n\nnamespace\n{\n    template <typename T> WORD ChannelsSpecifiedInMask(T x) noexcept\n    {\n        WORD bitCount = 0;\n        while (x) { ++bitCount; x &= (x - 1); }\n        return bitCount;\n    }\n}\n\n\n//======================================================================================\n// Wave format utilities\n//======================================================================================\n\nbool DirectX::IsValid(_In_ const WAVEFORMATEX* wfx) noexcept\n{\n    if (!wfx)\n        return false;\n\n    if (!wfx->nChannels)\n    {\n        DebugTrace(\"ERROR: Wave format must have at least 1 channel\\n\");\n        return false;\n    }\n\n    if (wfx->nChannels > XAUDIO2_MAX_AUDIO_CHANNELS)\n    {\n        DebugTrace(\"ERROR: Wave format must have less than %u channels (%u)\\n\", XAUDIO2_MAX_AUDIO_CHANNELS, wfx->nChannels);\n        return false;\n    }\n\n    if (!wfx->nSamplesPerSec)\n    {\n        DebugTrace(\"ERROR: Wave format cannot have a sample rate of 0\\n\");\n        return false;\n    }\n\n    if ((wfx->nSamplesPerSec < XAUDIO2_MIN_SAMPLE_RATE)\n        || (wfx->nSamplesPerSec > XAUDIO2_MAX_SAMPLE_RATE))\n    {\n        DebugTrace(\"ERROR: Wave format channel count must be in range %u..%u (%u)\\n\",\n            XAUDIO2_MIN_SAMPLE_RATE, XAUDIO2_MAX_SAMPLE_RATE, wfx->nSamplesPerSec);\n        return false;\n    }\n\n    switch (wfx->wFormatTag)\n    {\n        case WAVE_FORMAT_PCM:\n\n            switch (wfx->wBitsPerSample)\n            {\n                case 8:\n                case 16:\n                case 24:\n                case 32:\n                    break;\n\n                default:\n                    DebugTrace(\"ERROR: Wave format integer PCM must have 8, 16, 24, or 32 bits per sample (%u)\\n\", wfx->wBitsPerSample);\n                    return false;\n            }\n\n            if (wfx->nBlockAlign != (wfx->nChannels * wfx->wBitsPerSample / 8))\n            {\n                DebugTrace(\"ERROR: Wave format integer PCM - nBlockAlign (%u) != nChannels (%u) * wBitsPerSample (%u) / 8\\n\",\n                           wfx->nBlockAlign, wfx->nChannels, wfx->wBitsPerSample);\n                return false;\n            }\n\n            if (wfx->nAvgBytesPerSec != (wfx->nSamplesPerSec * wfx->nBlockAlign))\n            {\n                DebugTrace(\"ERROR: Wave format integer PCM - nAvgBytesPerSec (%lu) != nSamplesPerSec (%lu) * nBlockAlign (%u)\\n\",\n                           wfx->nAvgBytesPerSec, wfx->nSamplesPerSec, wfx->nBlockAlign);\n                return false;\n            }\n\n            return true;\n\n        case WAVE_FORMAT_IEEE_FLOAT:\n\n            if (wfx->wBitsPerSample != 32)\n            {\n                DebugTrace(\"ERROR: Wave format float PCM must have 32-bits per sample (%u)\\n\", wfx->wBitsPerSample);\n                return false;\n            }\n\n            if (wfx->nBlockAlign != (wfx->nChannels * wfx->wBitsPerSample / 8))\n            {\n                DebugTrace(\"ERROR: Wave format float PCM - nBlockAlign (%u) != nChannels (%u) * wBitsPerSample (%u) / 8\\n\",\n                           wfx->nBlockAlign, wfx->nChannels, wfx->wBitsPerSample);\n                return false;\n            }\n\n            if (wfx->nAvgBytesPerSec != (wfx->nSamplesPerSec * wfx->nBlockAlign))\n            {\n                DebugTrace(\"ERROR: Wave format float PCM - nAvgBytesPerSec (%lu) != nSamplesPerSec (%lu) * nBlockAlign (%u)\\n\",\n                           wfx->nAvgBytesPerSec, wfx->nSamplesPerSec, wfx->nBlockAlign);\n                return false;\n            }\n\n            return true;\n\n        case WAVE_FORMAT_ADPCM:\n\n            if ((wfx->nChannels != 1) && (wfx->nChannels != 2))\n            {\n                DebugTrace(\"ERROR: Wave format ADPCM must have 1 or 2 channels (%u)\\n\", wfx->nChannels);\n                return false;\n            }\n\n            if (wfx->wBitsPerSample != 4 /*MSADPCM_BITS_PER_SAMPLE*/)\n            {\n                DebugTrace(\"ERROR: Wave format ADPCM must have 4 bits per sample (%u)\\n\", wfx->wBitsPerSample);\n                return false;\n            }\n\n            if (wfx->cbSize != 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/)\n            {\n                DebugTrace(\"ERROR: Wave format ADPCM must have cbSize = 32 (%u)\\n\", wfx->cbSize);\n                return false;\n            }\n            else\n            {\n                auto wfadpcm = reinterpret_cast<const ADPCMWAVEFORMAT*>(wfx);\n\n                if (wfadpcm->wNumCoef != 7 /*MSADPCM_NUM_COEFFICIENTS*/)\n                {\n                    DebugTrace(\"ERROR: Wave format ADPCM must have 7 coefficients (%u)\\n\", wfadpcm->wNumCoef);\n                    return false;\n                }\n\n                bool valid = true;\n                for (int j = 0; j < 7 /*MSADPCM_NUM_COEFFICIENTS*/; ++j)\n                {\n                    // Microsoft ADPCM standard encoding coefficients\n                    static const short g_pAdpcmCoefficients1[] = { 256,  512, 0, 192, 240,  460,  392 };\n                    static const short g_pAdpcmCoefficients2[] = { 0, -256, 0,  64,   0, -208, -232 };\n\n                    if (wfadpcm->aCoef[j].iCoef1 != g_pAdpcmCoefficients1[j]\n                        || wfadpcm->aCoef[j].iCoef2 != g_pAdpcmCoefficients2[j])\n                    {\n                        valid = false;\n                    }\n                }\n\n                if (!valid)\n                {\n                    DebugTrace(\"ERROR: Wave formt ADPCM found non-standard coefficients\\n\");\n                    return false;\n                }\n\n                if ((wfadpcm->wSamplesPerBlock < 4 /*MSADPCM_MIN_SAMPLES_PER_BLOCK*/)\n                    || (wfadpcm->wSamplesPerBlock > 64000 /*MSADPCM_MAX_SAMPLES_PER_BLOCK*/))\n                {\n                    DebugTrace(\"ERROR: Wave format ADPCM wSamplesPerBlock must be 4..64000 (%u)\\n\", wfadpcm->wSamplesPerBlock);\n                    return false;\n                }\n\n                if (wfadpcm->wfx.nChannels == 1 && (wfadpcm->wSamplesPerBlock % 2))\n                {\n                    DebugTrace(\"ERROR: Wave format ADPCM mono files must have even wSamplesPerBlock\\n\");\n                    return false;\n                }\n\n                int nHeaderBytes = 7 /*MSADPCM_HEADER_LENGTH*/ * wfx->nChannels;\n                int nBitsPerFrame = 4 /*MSADPCM_BITS_PER_SAMPLE*/ * wfx->nChannels;\n                int nPcmFramesPerBlock = (wfx->nBlockAlign - nHeaderBytes) * 8 / nBitsPerFrame + 2;\n\n                if (wfadpcm->wSamplesPerBlock != nPcmFramesPerBlock)\n                {\n                    DebugTrace(\"ERROR: Wave format ADPCM %u-channel with nBlockAlign = %u must have wSamplesPerBlock = %d (%u)\\n\",\n                               wfx->nChannels, wfx->nBlockAlign, nPcmFramesPerBlock, wfadpcm->wSamplesPerBlock);\n                    return false;\n                }\n            }\n            return true;\n\n        case WAVE_FORMAT_WMAUDIO2:\n        case WAVE_FORMAT_WMAUDIO3:\n\n        #ifdef DIRECTX_ENABLE_XWMA\n\n            if (wfx->wBitsPerSample != 16)\n            {\n                DebugTrace(\"ERROR: Wave format xWMA only supports 16-bit data\\n\");\n                return false;\n            }\n\n            if (!wfx->nBlockAlign)\n            {\n                DebugTrace(\"ERROR: Wave format xWMA must have a non-zero nBlockAlign\\n\");\n                return false;\n            }\n\n            if (!wfx->nAvgBytesPerSec)\n            {\n                DebugTrace(\"ERROR: Wave format xWMA must have a non-zero nAvgBytesPerSec\\n\");\n                return false;\n            }\n\n            return true;\n\n        #else\n            DebugTrace(\"ERROR: Wave format xWMA not supported by this version of DirectXTK for Audio\\n\");\n            return false;\n        #endif\n\n        case 0x166 /* WAVE_FORMAT_XMA2 */:\n\n        #ifdef DIRECTX_ENABLE_XMA2\n\n            static_assert(WAVE_FORMAT_XMA2 == 0x166, \"Unrecognized XMA2 tag\");\n\n            if (wfx->nBlockAlign != wfx->nChannels * XMA_OUTPUT_SAMPLE_BYTES)\n            {\n                DebugTrace(\"ERROR: Wave format XMA2 - nBlockAlign (%u) != nChannels(%u) * %u\\n\", wfx->nBlockAlign, wfx->nChannels, XMA_OUTPUT_SAMPLE_BYTES);\n                return false;\n            }\n\n            if (wfx->wBitsPerSample != XMA_OUTPUT_SAMPLE_BITS)\n            {\n                DebugTrace(\"ERROR: Wave format XMA2 wBitsPerSample (%u) should be %u\\n\", wfx->wBitsPerSample, XMA_OUTPUT_SAMPLE_BITS);\n                return false;\n            }\n\n            if (wfx->cbSize != (sizeof(XMA2WAVEFORMATEX) - sizeof(WAVEFORMATEX)))\n            {\n                DebugTrace(\"ERROR: Wave format XMA2 - cbSize must be %zu (%u)\\n\", (sizeof(XMA2WAVEFORMATEX) - sizeof(WAVEFORMATEX)), wfx->cbSize);\n                return false;\n            }\n            else\n            {\n                auto xmaFmt = reinterpret_cast<const XMA2WAVEFORMATEX*>(wfx);\n\n                if (xmaFmt->EncoderVersion < 3)\n                {\n                    DebugTrace(\"ERROR: Wave format XMA2 encoder version (%u) - 3 or higher is required\\n\", xmaFmt->EncoderVersion);\n                    return false;\n                }\n\n                if (!xmaFmt->BlockCount)\n                {\n                    DebugTrace(\"ERROR: Wave format XMA2 BlockCount must be non-zero\\n\");\n                    return false;\n                }\n\n                if (!xmaFmt->BytesPerBlock || (xmaFmt->BytesPerBlock > XMA_READBUFFER_MAX_BYTES))\n                {\n                    DebugTrace(\"ERROR: Wave format XMA2 BytesPerBlock (%u) is invalid\\n\", xmaFmt->BytesPerBlock);\n                    return false;\n                }\n\n                if (xmaFmt->ChannelMask)\n                {\n                    auto channelBits = ChannelsSpecifiedInMask(xmaFmt->ChannelMask);\n                    if (channelBits != wfx->nChannels)\n                    {\n                        DebugTrace(\"ERROR: Wave format XMA2 - nChannels=%u but ChannelMask (%08X) has %u bits set\\n\",\n                                   xmaFmt->ChannelMask, wfx->nChannels, channelBits);\n                        return false;\n                    }\n                }\n\n                if (xmaFmt->NumStreams != ((wfx->nChannels + 1) / 2))\n                {\n                    DebugTrace(\"ERROR: Wave format XMA2 - NumStreams (%u) != ( nChannels(%u) + 1 ) / 2\\n\",\n                        xmaFmt->NumStreams, wfx->nChannels);\n                    return false;\n                }\n\n                if ((xmaFmt->PlayBegin + xmaFmt->PlayLength) > xmaFmt->SamplesEncoded)\n                {\n                    DebugTrace(\"ERROR: Wave format XMA2 play region too large (%u + %u > %u)\\n\",\n                        xmaFmt->PlayBegin, xmaFmt->PlayLength, xmaFmt->SamplesEncoded);\n                    return false;\n                }\n\n                if ((xmaFmt->LoopBegin + xmaFmt->LoopLength) > xmaFmt->SamplesEncoded)\n                {\n                    DebugTrace(\"ERROR: Wave format XMA2 loop region too large (%u + %u > %u)\\n\",\n                        xmaFmt->LoopBegin, xmaFmt->LoopLength, xmaFmt->SamplesEncoded);\n                    return false;\n                }\n            }\n            return true;\n\n        #else\n            DebugTrace(\"ERROR: Wave format XMA2 not supported by this version of DirectXTK for Audio\\n\");\n            return false;\n        #endif\n\n        case WAVE_FORMAT_EXTENSIBLE:\n            if (wfx->cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))\n            {\n                DebugTrace(\"ERROR: Wave format WAVE_FORMAT_EXTENSIBLE - cbSize must be %zu (%u)\\n\",\n                    (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)), wfx->cbSize);\n                return false;\n            }\n            else\n            {\n                static const GUID s_wfexBase = { 0x00000000, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 } };\n\n                auto wfex = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(wfx);\n\n                if (memcmp(reinterpret_cast<const BYTE*>(&wfex->SubFormat) + sizeof(DWORD),\n                    reinterpret_cast<const BYTE*>(&s_wfexBase) + sizeof(DWORD), sizeof(GUID) - sizeof(DWORD)) != 0)\n                {\n                    DebugTrace(\"ERROR: Wave format WAVEFORMATEXTENSIBLE encountered with unknown GUID ({%8.8lX-%4.4X-%4.4X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X})\\n\",\n                               wfex->SubFormat.Data1, wfex->SubFormat.Data2, wfex->SubFormat.Data3,\n                               wfex->SubFormat.Data4[0], wfex->SubFormat.Data4[1], wfex->SubFormat.Data4[2], wfex->SubFormat.Data4[3],\n                               wfex->SubFormat.Data4[4], wfex->SubFormat.Data4[5], wfex->SubFormat.Data4[6], wfex->SubFormat.Data4[7]);\n                    return false;\n                }\n\n                switch (wfex->SubFormat.Data1)\n                {\n                    case WAVE_FORMAT_PCM:\n\n                        switch (wfx->wBitsPerSample)\n                        {\n                            case 8:\n                            case 16:\n                            case 24:\n                            case 32:\n                                break;\n\n                            default:\n                                DebugTrace(\"ERROR: Wave format integer PCM must have 8, 16, 24, or 32 bits per sample (%u)\\n\",\n                                    wfx->wBitsPerSample);\n                                return false;\n                        }\n\n                        switch (wfex->Samples.wValidBitsPerSample)\n                        {\n                            case 0:\n                            case 8:\n                            case 16:\n                            case 20:\n                            case 24:\n                            case 32:\n                                break;\n\n                            default:\n                                DebugTrace(\"ERROR: Wave format integer PCM must have 8, 16, 20, 24, or 32 valid bits per sample (%u)\\n\",\n                                    wfex->Samples.wValidBitsPerSample);\n                                return false;\n                        }\n\n                        if (wfex->Samples.wValidBitsPerSample\n                            && (wfex->Samples.wValidBitsPerSample > wfx->wBitsPerSample))\n                        {\n                            DebugTrace(\"ERROR: Wave format ingter PCM wValidBitsPerSample (%u) is greater than wBitsPerSample (%u)\\n\",\n                                wfex->Samples.wValidBitsPerSample, wfx->wBitsPerSample);\n                            return false;\n                        }\n\n                        if (wfx->nBlockAlign != (wfx->nChannels * wfx->wBitsPerSample / 8))\n                        {\n                            DebugTrace(\"ERROR: Wave format integer PCM - nBlockAlign (%u) != nChannels (%u) * wBitsPerSample (%u) / 8\\n\",\n                                       wfx->nBlockAlign, wfx->nChannels, wfx->wBitsPerSample);\n                            return false;\n                        }\n\n                        if (wfx->nAvgBytesPerSec != (wfx->nSamplesPerSec * wfx->nBlockAlign))\n                        {\n                            DebugTrace(\"ERROR: Wave format integer PCM - nAvgBytesPerSec (%lu) != nSamplesPerSec (%lu) * nBlockAlign (%u)\\n\",\n                                       wfx->nAvgBytesPerSec, wfx->nSamplesPerSec, wfx->nBlockAlign);\n                            return false;\n                        }\n\n                        break;\n\n                    case WAVE_FORMAT_IEEE_FLOAT:\n\n                        if (wfx->wBitsPerSample != 32)\n                        {\n                            DebugTrace(\"ERROR: Wave format float PCM must have 32-bits per sample (%u)\\n\", wfx->wBitsPerSample);\n                            return false;\n                        }\n\n                        switch (wfex->Samples.wValidBitsPerSample)\n                        {\n                            case 0:\n                            case 32:\n                                break;\n\n                            default:\n                                DebugTrace(\"ERROR: Wave format float PCM must have 32 valid bits per sample (%u)\\n\",\n                                    wfex->Samples.wValidBitsPerSample);\n                                return false;\n                        }\n\n                        if (wfx->nBlockAlign != (wfx->nChannels * wfx->wBitsPerSample / 8))\n                        {\n                            DebugTrace(\"ERROR: Wave format float PCM - nBlockAlign (%u) != nChannels (%u) * wBitsPerSample (%u) / 8\\n\",\n                                       wfx->nBlockAlign, wfx->nChannels, wfx->wBitsPerSample);\n                            return false;\n                        }\n\n                        if (wfx->nAvgBytesPerSec != (wfx->nSamplesPerSec * wfx->nBlockAlign))\n                        {\n                            DebugTrace(\"ERROR: Wave format float PCM - nAvgBytesPerSec (%lu) != nSamplesPerSec (%lu) * nBlockAlign (%u)\\n\",\n                                       wfx->nAvgBytesPerSec, wfx->nSamplesPerSec, wfx->nBlockAlign);\n                            return false;\n                        }\n\n                        break;\n\n                    case WAVE_FORMAT_ADPCM:\n                        DebugTrace(\"ERROR: Wave format ADPCM is not supported as a WAVEFORMATEXTENSIBLE\\n\");\n                        return false;\n\n                    case WAVE_FORMAT_WMAUDIO2:\n                    case WAVE_FORMAT_WMAUDIO3:\n\n                    #ifdef DIRECTX_ENABLE_XWMA\n\n                        if (wfx->wBitsPerSample != 16)\n                        {\n                            DebugTrace(\"ERROR: Wave format xWMA only supports 16-bit data\\n\");\n                            return false;\n                        }\n\n                        if (!wfx->nBlockAlign)\n                        {\n                            DebugTrace(\"ERROR: Wave format xWMA must have a non-zero nBlockAlign\\n\");\n                            return false;\n                        }\n\n                        if (!wfx->nAvgBytesPerSec)\n                        {\n                            DebugTrace(\"ERROR: Wave format xWMA must have a non-zero nAvgBytesPerSec\\n\");\n                            return false;\n                        }\n\n                        break;\n\n                    #else\n                        DebugTrace(\"ERROR: Wave format xWMA not supported by this version of DirectXTK for Audio\\n\");\n                        return false;\n                    #endif\n\n                    case 0x166 /* WAVE_FORMAT_XMA2 */:\n                        DebugTrace(\"ERROR: Wave format XMA2 is not supported as a WAVEFORMATEXTENSIBLE\\n\");\n                        return false;\n\n                    default:\n                        DebugTrace(\"ERROR: Unknown WAVEFORMATEXTENSIBLE format tag (%u)\\n\", wfex->SubFormat.Data1);\n                        return false;\n                }\n\n                if (wfex->dwChannelMask)\n                {\n                    auto channelBits = ChannelsSpecifiedInMask(wfex->dwChannelMask);\n                    if (channelBits != wfx->nChannels)\n                    {\n                        DebugTrace(\"ERROR: WAVEFORMATEXTENSIBLE: nChannels=%u but ChannelMask has %u bits set\\n\",\n                                   wfx->nChannels, channelBits);\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n\n        default:\n            DebugTrace(\"ERROR: Unknown WAVEFORMATEX format tag (%u)\\n\", wfx->wFormatTag);\n            return false;\n    }\n}\n\n\nuint32_t DirectX::GetDefaultChannelMask(int channels) noexcept\n{\n    switch (channels)\n    {\n        case 1: return SPEAKER_MONO;\n        case 2: return SPEAKER_STEREO;\n        case 3: return SPEAKER_2POINT1;\n        case 4: return SPEAKER_QUAD;\n        case 5: return SPEAKER_4POINT1;\n        case 6: return SPEAKER_5POINT1;\n        case 7: return SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;\n        case 8: return SPEAKER_7POINT1;\n        default: return 0;\n    }\n}\n\n\n_Use_decl_annotations_\nvoid DirectX::CreateIntegerPCM(WAVEFORMATEX* wfx, int sampleRate, int channels, int sampleBits) noexcept\n{\n    int blockAlign = channels * sampleBits / 8;\n\n    wfx->wFormatTag = WAVE_FORMAT_PCM;\n    wfx->nChannels = static_cast<WORD>(channels);\n    wfx->nSamplesPerSec = static_cast<DWORD>(sampleRate);\n    wfx->nAvgBytesPerSec = static_cast<DWORD>(blockAlign * sampleRate);\n    wfx->nBlockAlign = static_cast<WORD>(blockAlign);\n    wfx->wBitsPerSample = static_cast<WORD>(sampleBits);\n    wfx->cbSize = 0;\n\n    assert(IsValid(wfx));\n}\n\n\n_Use_decl_annotations_\nvoid DirectX::CreateFloatPCM(WAVEFORMATEX* wfx, int sampleRate, int channels) noexcept\n{\n    int blockAlign = channels * 4;\n\n    wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;\n    wfx->nChannels = static_cast<WORD>(channels);\n    wfx->nSamplesPerSec = static_cast<DWORD>(sampleRate);\n    wfx->nAvgBytesPerSec = static_cast<DWORD>(blockAlign * sampleRate);\n    wfx->nBlockAlign = static_cast<WORD>(blockAlign);\n    wfx->wBitsPerSample = 32;\n    wfx->cbSize = 0;\n\n    assert(IsValid(wfx));\n}\n\n\n_Use_decl_annotations_\nvoid DirectX::CreateADPCM(WAVEFORMATEX* wfx, size_t wfxSize, int sampleRate, int channels, int samplesPerBlock) noexcept(false)\n{\n    if (wfxSize < (sizeof(WAVEFORMATEX) + 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/))\n    {\n        DebugTrace(\"CreateADPCM needs at least %zu bytes for the result\\n\",\n            (sizeof(WAVEFORMATEX) + 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/));\n        throw std::invalid_argument(\"ADPCMWAVEFORMAT\");\n    }\n\n    if (!samplesPerBlock)\n    {\n        DebugTrace(\"CreateADPCM needs a non-zero samples per block count\\n\");\n        throw std::invalid_argument(\"ADPCMWAVEFORMAT\");\n    }\n\n    int blockAlign = (7 /*MSADPCM_HEADER_LENGTH*/) * channels\n        + (samplesPerBlock - 2) * (4 /* MSADPCM_BITS_PER_SAMPLE */) * channels / 8;\n\n    wfx->wFormatTag = WAVE_FORMAT_ADPCM;\n    wfx->nChannels = static_cast<WORD>(channels);\n    wfx->nSamplesPerSec = static_cast<DWORD>(sampleRate);\n    wfx->nAvgBytesPerSec = static_cast<DWORD>(blockAlign * sampleRate / samplesPerBlock);\n    wfx->nBlockAlign = static_cast<WORD>(blockAlign);\n    wfx->wBitsPerSample = 4 /* MSADPCM_BITS_PER_SAMPLE */;\n    wfx->cbSize = 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/;\n\n    auto adpcm = reinterpret_cast<ADPCMWAVEFORMAT*>(wfx);\n    adpcm->wSamplesPerBlock = static_cast<WORD>(samplesPerBlock);\n    adpcm->wNumCoef = 7 /* MSADPCM_NUM_COEFFICIENTS */;\n\n    static ADPCMCOEFSET aCoef[7] = { { 256, 0}, {512, -256}, {0,0}, {192,64}, {240,0}, {460, -208}, {392,-232} };\n    memcpy(&adpcm->aCoef, aCoef, sizeof(aCoef));\n\n    assert(IsValid(wfx));\n}\n\n\n#ifdef DIRECTX_ENABLE_XWMA\n_Use_decl_annotations_\nvoid DirectX::CreateXWMA(WAVEFORMATEX* wfx, int sampleRate, int channels, int blockAlign, int avgBytes, bool wma3) noexcept\n{\n    wfx->wFormatTag = static_cast<WORD>((wma3) ? WAVE_FORMAT_WMAUDIO3 : WAVE_FORMAT_WMAUDIO2);\n    wfx->nChannels = static_cast<WORD>(channels);\n    wfx->nSamplesPerSec = static_cast<DWORD>(sampleRate);\n    wfx->nAvgBytesPerSec = static_cast<DWORD>(avgBytes);\n    wfx->nBlockAlign = static_cast<WORD>(blockAlign);\n    wfx->wBitsPerSample = 16;\n    wfx->cbSize = 0;\n\n    assert(IsValid(wfx));\n}\n#endif\n\n\n#ifdef DIRECTX_ENABLE_XMA2\n_Use_decl_annotations_\nvoid DirectX::CreateXMA2(WAVEFORMATEX* wfx, size_t wfxSize, int sampleRate, int channels, int bytesPerBlock, int blockCount, int samplesEncoded) noexcept(false)\n{\n    if (wfxSize < sizeof(XMA2WAVEFORMATEX))\n    {\n        DebugTrace(\"XMA2 needs at least %zu bytes for the result\\n\", sizeof(XMA2WAVEFORMATEX));\n        throw std::invalid_argument(\"XMA2WAVEFORMATEX\");\n    }\n\n    if ((bytesPerBlock < 1) || (bytesPerBlock > int(XMA_READBUFFER_MAX_BYTES)))\n    {\n        DebugTrace(\"XMA2 needs a valid bytes per block\\n\");\n        throw std::invalid_argument(\"XMA2WAVEFORMATEX\");\n    }\n\n    int blockAlign = (channels * (16 /*XMA_OUTPUT_SAMPLE_BITS*/) / 8);\n\n    wfx->wFormatTag = WAVE_FORMAT_XMA2;\n    wfx->nChannels = static_cast<WORD>(channels);\n    wfx->nSamplesPerSec = static_cast<WORD>(sampleRate);\n    wfx->nAvgBytesPerSec = static_cast<DWORD>(blockAlign * sampleRate);\n    wfx->nBlockAlign = static_cast<WORD>(blockAlign);\n    wfx->wBitsPerSample = 16 /* XMA_OUTPUT_SAMPLE_BITS */;\n    wfx->cbSize = sizeof(XMA2WAVEFORMATEX) - sizeof(WAVEFORMATEX);\n\n    auto xmaFmt = reinterpret_cast<XMA2WAVEFORMATEX*>(wfx);\n\n    xmaFmt->NumStreams = static_cast<WORD>((channels + 1) / 2);\n\n    xmaFmt->ChannelMask = GetDefaultChannelMask(channels);\n\n    xmaFmt->SamplesEncoded = static_cast<DWORD>(samplesEncoded);\n    xmaFmt->BytesPerBlock = static_cast<DWORD>(bytesPerBlock);\n    xmaFmt->PlayBegin = xmaFmt->PlayLength =\n        xmaFmt->LoopBegin = xmaFmt->LoopLength = xmaFmt->LoopCount = 0;\n    xmaFmt->EncoderVersion = 4 /* XMAENCODER_VERSION_XMA2 */;\n    xmaFmt->BlockCount = static_cast<WORD>(blockCount);\n\n    assert(IsValid(wfx));\n}\n#endif // XMA2\n\n\n_Use_decl_annotations_\nbool DirectX::ComputePan(float pan, unsigned int channels, float* matrix) noexcept\n{\n    memset(matrix, 0, sizeof(float) * 16);\n\n    if (channels == 1)\n    {\n        // Mono panning\n        float left = (pan >= 0) ? (1.f - pan) : 1.f;\n        left = std::min<float>(1.f, left);\n        left = std::max<float>(-1.f, left);\n\n        float right = (pan <= 0) ? (-pan - 1.f) : 1.f;\n        right = std::min<float>(1.f, right);\n        right = std::max<float>(-1.f, right);\n\n        matrix[0] = left;\n        matrix[1] = right;\n    }\n    else if (channels == 2)\n    {\n        // Stereo panning\n        if (-1.f <= pan && pan <= 0.f)\n        {\n            matrix[0] = .5f * pan + 1.f;    // .5 when pan is -1, 1 when pan is 0\n            matrix[1] = .5f * -pan;         // .5 when pan is -1, 0 when pan is 0\n            matrix[2] = 0.f;                //  0 when pan is -1, 0 when pan is 0\n            matrix[3] = pan + 1.f;          //  0 when pan is -1, 1 when pan is 0\n        }\n        else\n        {\n            matrix[0] = -pan + 1.f;         //  1 when pan is 0,   0 when pan is 1\n            matrix[1] = 0.f;                //  0 when pan is 0,   0 when pan is 1\n            matrix[2] = .5f * pan;          //  0 when pan is 0, .5f when pan is 1\n            matrix[3] = .5f * -pan + 1.f;   //  1 when pan is 0. .5f when pan is 1\n        }\n    }\n    else\n    {\n        if (pan != 0.f)\n        {\n            DebugTrace(\"WARNING: Only supports panning on mono or stereo source data, ignored\\n\");\n        }\n        return false;\n    }\n\n    return true;\n}\n\n\n//======================================================================================\n// SoundEffectInstanceBase\n//======================================================================================\n\nvoid SoundEffectInstanceBase::SetPan(float pan)\n{\n    assert(pan >= -1.f && pan <= 1.f);\n\n    mPan = pan;\n\n    if (!voice)\n        return;\n\n    float matrix[16];\n    if (ComputePan(pan, mDSPSettings.SrcChannelCount, matrix))\n    {\n        HRESULT hr = voice->SetOutputMatrix(nullptr, mDSPSettings.SrcChannelCount, mDSPSettings.DstChannelCount, matrix);\n        ThrowIfFailed(hr);\n    }\n}\n\n\nvoid SoundEffectInstanceBase::Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords)\n{\n    if (!voice)\n        return;\n\n    if (!(mFlags & SoundEffectInstance_Use3D))\n    {\n        DebugTrace(\"ERROR: Apply3D called for an instance created without SoundEffectInstance_Use3D set\\n\");\n        throw std::exception(\"Apply3D\");\n    }\n\n    DWORD dwCalcFlags = X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT;\n\n    if (mFlags & SoundEffectInstance_UseRedirectLFE)\n    {\n        // On devices with an LFE channel, allow the mono source data to be routed to the LFE destination channel.\n        dwCalcFlags |= X3DAUDIO_CALCULATE_REDIRECT_TO_LFE;\n    }\n\n    auto reverb = mReverbVoice;\n    if (reverb)\n    {\n        dwCalcFlags |= X3DAUDIO_CALCULATE_LPF_REVERB | X3DAUDIO_CALCULATE_REVERB;\n    }\n\n    float matrix[XAUDIO2_MAX_AUDIO_CHANNELS * 8] = {};\n    assert(mDSPSettings.SrcChannelCount <= XAUDIO2_MAX_AUDIO_CHANNELS);\n    assert(mDSPSettings.DstChannelCount <= 8);\n    mDSPSettings.pMatrixCoefficients = matrix;\n\n    assert(engine != nullptr);\n    if (rhcoords)\n    {\n        X3DAUDIO_EMITTER lhEmitter;\n        memcpy(&lhEmitter, &emitter, sizeof(X3DAUDIO_EMITTER));\n        lhEmitter.OrientFront.z = -emitter.OrientFront.z;\n        lhEmitter.OrientTop.z = -emitter.OrientTop.z;\n        lhEmitter.Position.z = -emitter.Position.z;\n        lhEmitter.Velocity.z = -emitter.Velocity.z;\n\n        X3DAUDIO_LISTENER lhListener;\n        memcpy(&lhListener, &listener, sizeof(X3DAUDIO_LISTENER));\n        lhListener.OrientFront.z = -listener.OrientFront.z;\n        lhListener.OrientTop.z = -listener.OrientTop.z;\n        lhListener.Position.z = -listener.Position.z;\n        lhListener.Velocity.z = -listener.Velocity.z;\n\n        X3DAudioCalculate(engine->Get3DHandle(), &lhListener, &lhEmitter, dwCalcFlags, &mDSPSettings);\n    }\n    else\n    {\n        X3DAudioCalculate(engine->Get3DHandle(), &listener, &emitter, dwCalcFlags, &mDSPSettings);\n    }\n\n    mDSPSettings.pMatrixCoefficients = nullptr;\n\n    (void)voice->SetFrequencyRatio(mFreqRatio * mDSPSettings.DopplerFactor);\n\n    auto direct = mDirectVoice;\n    assert(direct != nullptr);\n    (void)voice->SetOutputMatrix(direct, mDSPSettings.SrcChannelCount, mDSPSettings.DstChannelCount, matrix);\n\n    if (reverb)\n    {\n        for (size_t j = 0; (j < mDSPSettings.SrcChannelCount) && (j < XAUDIO2_MAX_AUDIO_CHANNELS); ++j)\n        {\n            matrix[j] = mDSPSettings.ReverbLevel;\n        }\n        (void)voice->SetOutputMatrix(reverb, mDSPSettings.SrcChannelCount, 1, matrix);\n    }\n\n    if (mFlags & SoundEffectInstance_ReverbUseFilters)\n    {\n        XAUDIO2_FILTER_PARAMETERS filterDirect = { LowPassFilter, 2.0f * sinf(X3DAUDIO_PI / 6.0f * mDSPSettings.LPFDirectCoefficient), 1.0f };\n        // see XAudio2CutoffFrequencyToRadians() in XAudio2.h for more information on the formula used here\n        (void)voice->SetOutputFilterParameters(direct, &filterDirect);\n\n        if (reverb)\n        {\n            XAUDIO2_FILTER_PARAMETERS filterReverb = { LowPassFilter, 2.0f * sinf(X3DAUDIO_PI / 6.0f * mDSPSettings.LPFReverbCoefficient), 1.0f };\n            // see XAudio2CutoffFrequencyToRadians() in XAudio2.h for more information on the formula used here\n            (void)voice->SetOutputFilterParameters(reverb, &filterReverb);\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/SoundCommon.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: SoundCommon.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"Audio.h\"\n#include \"PlatformHelpers.h\"\n\n#ifdef USING_XAUDIO2_9\n#define DIRECTX_ENABLE_XWMA\n#endif\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#define DIRECTX_ENABLE_XMA2\n#endif\n\n#if defined(DIRECTX_ENABLE_XWMA) || defined(DIRECTX_ENABLE_XMA2)\n#define DIRECTX_ENABLE_SEEK_TABLES\n#endif\n\nnamespace DirectX\n{\n    // Helper for getting a format tag from a WAVEFORMATEX\n    inline uint32_t GetFormatTag(const WAVEFORMATEX* wfx) noexcept\n    {\n        if (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)\n        {\n            if (wfx->cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))\n                return 0;\n\n            static const GUID s_wfexBase = { 0x00000000, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 } };\n\n            auto wfex = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(wfx);\n\n            if (memcmp(reinterpret_cast<const BYTE*>(&wfex->SubFormat) + sizeof(DWORD),\n                reinterpret_cast<const BYTE*>(&s_wfexBase) + sizeof(DWORD), sizeof(GUID) - sizeof(DWORD)) != 0)\n            {\n                return 0;\n            }\n\n            return wfex->SubFormat.Data1;\n        }\n        else\n        {\n            return wfx->wFormatTag;\n        }\n    }\n\n\n    // Helper for validating wave format structure\n    bool IsValid(_In_ const WAVEFORMATEX* wfx) noexcept;\n\n\n    // Helper for getting a default channel mask from channels\n    uint32_t GetDefaultChannelMask(int channels) noexcept;\n\n\n    // Helpers for creating various wave format structures\n    void CreateIntegerPCM(_Out_ WAVEFORMATEX* wfx, int sampleRate, int channels, int sampleBits) noexcept;\n    void CreateFloatPCM(_Out_ WAVEFORMATEX* wfx, int sampleRate, int channels) noexcept;\n    void CreateADPCM(_Out_writes_bytes_(wfxSize) WAVEFORMATEX* wfx, size_t wfxSize, int sampleRate, int channels, int samplesPerBlock) noexcept(false);\n#ifdef DIRECTX_ENABLE_XWMA\n    void CreateXWMA(_Out_ WAVEFORMATEX* wfx, int sampleRate, int channels, int blockAlign, int avgBytes, bool wma3) noexcept;\n#endif\n#ifdef DIRECTX_ENABLE_XMA2\n    void CreateXMA2(_Out_writes_bytes_(wfxSize) WAVEFORMATEX* wfx, size_t wfxSize, int sampleRate, int channels, int bytesPerBlock, int blockCount, int samplesEncoded) noexcept(false);\n#endif\n\n    // Helper for computing pan volume matrix\n    bool ComputePan(float pan, unsigned int channels, _Out_writes_(16) float* matrix) noexcept;\n\n    // Helper class for implementing SoundEffectInstance\n    class SoundEffectInstanceBase\n    {\n    public:\n        SoundEffectInstanceBase() noexcept :\n            voice(nullptr),\n            state(STOPPED),\n            engine(nullptr),\n            mVolume(1.f),\n            mPitch(0.f),\n            mFreqRatio(1.f),\n            mPan(0.f),\n            mFlags(SoundEffectInstance_Default),\n            mDirectVoice(nullptr),\n            mReverbVoice(nullptr),\n            mDSPSettings{}\n        {\n        }\n\n        SoundEffectInstanceBase(SoundEffectInstanceBase&&) = default;\n        SoundEffectInstanceBase& operator= (SoundEffectInstanceBase&&) = default;\n\n        SoundEffectInstanceBase(SoundEffectInstanceBase const&) = delete;\n        SoundEffectInstanceBase& operator= (SoundEffectInstanceBase const&) = delete;\n\n        ~SoundEffectInstanceBase()\n        {\n            assert(voice == nullptr);\n        }\n\n        void Initialize(_In_ AudioEngine* eng, _In_ const WAVEFORMATEX* wfx, SOUND_EFFECT_INSTANCE_FLAGS flags) noexcept\n        {\n            assert(eng != nullptr);\n            engine = eng;\n            mDirectVoice = eng->GetMasterVoice();\n            mReverbVoice = eng->GetReverbVoice();\n\n            if (eng->GetChannelMask() & SPEAKER_LOW_FREQUENCY)\n                mFlags = flags | SoundEffectInstance_UseRedirectLFE;\n            else\n                mFlags = flags & ~SoundEffectInstance_UseRedirectLFE;\n\n            memset(&mDSPSettings, 0, sizeof(X3DAUDIO_DSP_SETTINGS));\n            assert(wfx != nullptr);\n            mDSPSettings.SrcChannelCount = wfx->nChannels;\n            mDSPSettings.DstChannelCount = eng->GetOutputChannels();\n        }\n\n        void AllocateVoice(_In_ const WAVEFORMATEX* wfx)\n        {\n            if (voice)\n                return;\n\n            assert(engine != nullptr);\n            engine->AllocateVoice(wfx, mFlags, false, &voice);\n        }\n\n        void DestroyVoice() noexcept\n        {\n            if (voice)\n            {\n                assert(engine != nullptr);\n                engine->DestroyVoice(voice);\n                voice = nullptr;\n            }\n        }\n\n        bool Play() // Returns true if STOPPED -> PLAYING\n        {\n            if (voice)\n            {\n                if (state == PAUSED)\n                {\n                    HRESULT hr = voice->Start(0);\n                    ThrowIfFailed(hr);\n                    state = PLAYING;\n                }\n                else if (state != PLAYING)\n                {\n                    if (mVolume != 1.f)\n                    {\n                        HRESULT hr = voice->SetVolume(mVolume);\n                        ThrowIfFailed(hr);\n                    }\n\n                    if (mPitch != 0.f)\n                    {\n                        mFreqRatio = XAudio2SemitonesToFrequencyRatio(mPitch * 12.f);\n\n                        HRESULT hr = voice->SetFrequencyRatio(mFreqRatio);\n                        ThrowIfFailed(hr);\n                    }\n\n                    if (mPan != 0.f)\n                    {\n                        SetPan(mPan);\n                    }\n\n                    HRESULT hr = voice->Start(0);\n                    ThrowIfFailed(hr);\n                    state = PLAYING;\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        void Stop(bool immediate, bool& looped) noexcept\n        {\n            if (!voice)\n            {\n                state = STOPPED;\n                return;\n            }\n\n            if (immediate)\n            {\n                state = STOPPED;\n                (void)voice->Stop(0);\n                (void)voice->FlushSourceBuffers();\n            }\n            else if (looped)\n            {\n                looped = false;\n                (void)voice->ExitLoop();\n            }\n            else\n            {\n                (void)voice->Stop(XAUDIO2_PLAY_TAILS);\n            }\n        }\n\n        void Pause() noexcept \n        {\n            if (voice && state == PLAYING)\n            {\n                state = PAUSED;\n\n                (void)voice->Stop(0);\n            }\n        }\n\n        void Resume()\n        {\n            if (voice && state == PAUSED)\n            {\n                HRESULT hr = voice->Start(0);\n                ThrowIfFailed(hr);\n                state = PLAYING;\n            }\n        }\n\n        void SetVolume(float volume)\n        {\n            assert(volume >= -XAUDIO2_MAX_VOLUME_LEVEL && volume <= XAUDIO2_MAX_VOLUME_LEVEL);\n\n            mVolume = volume;\n\n            if (voice)\n            {\n                HRESULT hr = voice->SetVolume(volume);\n                ThrowIfFailed(hr);\n            }\n        }\n\n        void SetPitch(float pitch)\n        {\n            assert(pitch >= -1.f && pitch <= 1.f);\n\n            if ((mFlags & SoundEffectInstance_NoSetPitch) && pitch != 0.f)\n            {\n                DebugTrace(\"ERROR: Sound effect instance was created with the NoSetPitch flag\\n\");\n                throw std::exception(\"SetPitch\");\n            }\n\n            mPitch = pitch;\n\n            if (voice)\n            {\n                mFreqRatio = XAudio2SemitonesToFrequencyRatio(mPitch * 12.f);\n\n                HRESULT hr = voice->SetFrequencyRatio(mFreqRatio);\n                ThrowIfFailed(hr);\n            }\n        }\n\n        void SetPan(float pan);\n\n        void Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords);\n\n        SoundState GetState(bool autostop) noexcept\n        {\n            if (autostop && voice && (state == PLAYING))\n            {\n                XAUDIO2_VOICE_STATE xstate;\n                voice->GetState(&xstate, XAUDIO2_VOICE_NOSAMPLESPLAYED);\n\n                if (!xstate.BuffersQueued)\n                {\n                    // Automatic stop if the buffer has finished playing\n                    (void)voice->Stop();\n                    state = STOPPED;\n                }\n            }\n\n            return state;\n        }\n\n        int GetPendingBufferCount() const noexcept\n        {\n            if (!voice)\n                return 0;\n\n            XAUDIO2_VOICE_STATE xstate;\n            voice->GetState(&xstate, XAUDIO2_VOICE_NOSAMPLESPLAYED);\n            return static_cast<int>(xstate.BuffersQueued);\n        }\n\n        void OnCriticalError() noexcept\n        {\n            if (voice)\n            {\n                voice->DestroyVoice();\n                voice = nullptr;\n            }\n            state = STOPPED;\n            mDirectVoice = nullptr;\n            mReverbVoice = nullptr;\n        }\n\n        void OnReset() noexcept\n        {\n            assert(engine != nullptr);\n            mDirectVoice = engine->GetMasterVoice();\n            mReverbVoice = engine->GetReverbVoice();\n\n            if (engine->GetChannelMask() & SPEAKER_LOW_FREQUENCY)\n                mFlags = mFlags | SoundEffectInstance_UseRedirectLFE;\n            else\n                mFlags = mFlags & ~SoundEffectInstance_UseRedirectLFE;\n\n            mDSPSettings.DstChannelCount = engine->GetOutputChannels();\n        }\n\n        void OnDestroy() noexcept\n        {\n            if (voice)\n            {\n                (void)voice->Stop(0);\n                (void)voice->FlushSourceBuffers();\n                voice->DestroyVoice();\n                voice = nullptr;\n            }\n            state = STOPPED;\n            engine = nullptr;\n            mDirectVoice = nullptr;\n            mReverbVoice = nullptr;\n        }\n\n        void OnTrim()\n        {\n            if (voice && (state == STOPPED))\n            {\n                engine->DestroyVoice(voice);\n                voice = nullptr;\n            }\n        }\n\n        void GatherStatistics(AudioStatistics& stats) const noexcept\n        {\n            ++stats.allocatedInstances;\n            if (voice)\n            {\n                ++stats.allocatedVoices;\n\n                if (mFlags & SoundEffectInstance_Use3D)\n                    ++stats.allocatedVoices3d;\n\n                if (state == PLAYING)\n                    ++stats.playingInstances;\n            }\n        }\n\n        IXAudio2SourceVoice*        voice;\n        SoundState                  state;\n        AudioEngine*                engine;\n\n    private:\n        float                       mVolume;\n        float                       mPitch;\n        float                       mFreqRatio;\n        float                       mPan;\n        SOUND_EFFECT_INSTANCE_FLAGS mFlags;\n        IXAudio2Voice*              mDirectVoice;\n        IXAudio2Voice*              mReverbVoice;\n        X3DAUDIO_DSP_SETTINGS       mDSPSettings;\n    };\n\n    struct WaveBankSeekData\n    {\n        uint32_t        seekCount;\n        const uint32_t* seekTable;\n        uint32_t        tag;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/SoundEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SoundEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"WAVFileReader.h\"\n#include \"SoundCommon.h\"\n\n#include <list>\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <apu.h>\n#include <shapexmacontext.h>\n#endif\n\nusing namespace DirectX;\n\n\n//======================================================================================\n// SoundEffect\n//======================================================================================\n\n// Internal object implementation class.\nclass SoundEffect::Impl : public IVoiceNotify\n{\npublic:\n    explicit Impl(_In_ AudioEngine* engine) :\n        mWaveFormat(nullptr),\n        mStartAudio(nullptr),\n        mAudioBytes(0),\n        mLoopStart(0),\n        mLoopLength(0),\n        mEngine(engine),\n        mOneShots(0)\n    #ifdef DIRECTX_ENABLE_SEEK_TABLES\n        , mSeekCount(0)\n        , mSeekTable(nullptr)\n    #endif\n    #ifdef DIRECTX_ENABLE_XMA2\n        , mXMAMemory(nullptr)\n    #endif\n    {\n        assert(mEngine != nullptr);\n        mEngine->RegisterNotify(this, false);\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl() override\n    {\n        if (!mInstances.empty())\n        {\n            DebugTrace(\"WARNING: Destroying SoundEffect with %zu outstanding SoundEffectInstances\\n\", mInstances.size());\n\n            for (auto it = mInstances.begin(); it != mInstances.end(); ++it)\n            {\n                assert(*it != nullptr);\n                (*it)->OnDestroyParent();\n            }\n\n            mInstances.clear();\n        }\n\n        if (mOneShots > 0)\n        {\n            DebugTrace(\"WARNING: Destroying SoundEffect with %u outstanding one shot effects\\n\", mOneShots);\n        }\n\n        if (mEngine)\n        {\n            mEngine->UnregisterNotify(this, true, false);\n            mEngine = nullptr;\n        }\n\n    #ifdef DIRECTX_ENABLE_XMA2\n        if (mXMAMemory)\n        {\n            ApuFree(mXMAMemory);\n            mXMAMemory = nullptr;\n        }\n    #endif\n    }\n\n    HRESULT Initialize(_In_ AudioEngine* engine, _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n                       _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes,\n                   #ifdef DIRECTX_ENABLE_SEEK_TABLES\n                       _In_reads_opt_(seekCount) const uint32_t* seekTable, size_t seekCount,\n                   #endif\n                       uint32_t loopStart, uint32_t loopLength) noexcept;\n\n    void Play(float volume, float pitch, float pan);\n\n    // IVoiceNotify\n    void __cdecl OnBufferEnd() override\n    {\n        InterlockedDecrement(&mOneShots);\n    }\n\n    void __cdecl OnCriticalError() override\n    {\n        mOneShots = 0;\n    }\n\n    void __cdecl OnReset() override\n    {\n        // No action required\n    }\n\n    void __cdecl OnUpdate() override\n    {\n        // We do not register for update notification\n        assert(false);\n    }\n\n    void __cdecl OnDestroyEngine() noexcept override\n    {\n        mEngine = nullptr;\n        mOneShots = 0;\n    }\n\n    void __cdecl OnTrim() override\n    {\n        // No action required\n    }\n\n    void __cdecl GatherStatistics(AudioStatistics& stats) const noexcept override\n    {\n        stats.playingOneShots += mOneShots;\n        stats.audioBytes += mAudioBytes;\n\n    #ifdef DIRECTX_ENABLE_XMA2\n        if (mXMAMemory)\n            stats.xmaAudioBytes += mAudioBytes;\n    #endif\n    }\n\n    void __cdecl OnDestroyParent() noexcept override\n    {\n    }\n\n    const WAVEFORMATEX*                 mWaveFormat;\n    const uint8_t*                      mStartAudio;\n    uint32_t                            mAudioBytes;\n    uint32_t                            mLoopStart;\n    uint32_t                            mLoopLength;\n    AudioEngine*                        mEngine;\n    std::list<IVoiceNotify*>            mInstances;\n    uint32_t                            mOneShots;\n\n#ifdef DIRECTX_ENABLE_SEEK_TABLES\n    uint32_t                            mSeekCount;\n    const uint32_t*                     mSeekTable;\n#endif\n\nprivate:\n    std::unique_ptr<uint8_t[]>          mWavData;\n\n#ifdef DIRECTX_ENABLE_XMA2\n    void*                               mXMAMemory;\n#endif\n};\n\n\n_Use_decl_annotations_\nHRESULT SoundEffect::Impl::Initialize(AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,\n                                      const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes,\n                                  #ifdef DIRECTX_ENABLE_SEEK_TABLES\n                                      const uint32_t* seekTable, size_t seekCount,\n                                  #endif\n                                      uint32_t loopStart, uint32_t loopLength) noexcept\n{\n    if (!engine || !IsValid(wfx) || !startAudio || !audioBytes || !wavData)\n        return E_INVALIDARG;\n\n    if (audioBytes > UINT32_MAX)\n        return E_INVALIDARG;\n\n    switch (GetFormatTag(wfx))\n    {\n        case WAVE_FORMAT_PCM:\n        case WAVE_FORMAT_IEEE_FLOAT:\n        case WAVE_FORMAT_ADPCM:\n            // Take ownership of the buffer\n            mWavData.reset(wavData.release());\n\n            // WARNING: We assume the wfx and startAudio parameters are pointers into the wavData memory buffer\n            mWaveFormat = wfx;\n            mStartAudio = startAudio;\n            break;\n\n        #ifdef DIRECTX_ENABLE_XWMA\n\n        case WAVE_FORMAT_WMAUDIO2:\n        case WAVE_FORMAT_WMAUDIO3:\n            if (!seekCount || !seekTable)\n            {\n                DebugTrace(\"ERROR: SoundEffect format xWMA requires seek table\\n\");\n                return E_FAIL;\n            }\n\n            if (seekCount > UINT32_MAX)\n                return E_INVALIDARG;\n\n            // Take ownership of the buffer\n            mWavData.reset(wavData.release());\n\n            // WARNING: We assume the wfx, startAudio, and mSeekTable parameters are pointers into the wavData memory buffer\n            mWaveFormat = wfx;\n            mStartAudio = startAudio;\n            mSeekCount = static_cast<uint32_t>(seekCount);\n            mSeekTable = seekTable;\n            break;\n\n        #endif // xWMA\n\n        #ifdef DIRECTX_ENABLE_XMA2\n\n        case WAVE_FORMAT_XMA2:\n            if (!seekCount || !seekTable)\n            {\n                DebugTrace(\"ERROR: SoundEffect format XMA2 requires seek table\\n\");\n                return E_FAIL;\n            }\n\n            if (seekCount > UINT32_MAX)\n                return E_INVALIDARG;\n\n            {\n                HRESULT hr = ApuAlloc(&mXMAMemory, nullptr,\n                                      static_cast<UINT32>(audioBytes), SHAPE_XMA_INPUT_BUFFER_ALIGNMENT);\n                if (FAILED(hr))\n                {\n                    DebugTrace(\"ERROR: ApuAlloc failed. Did you allocate a large enough heap with ApuCreateHeap for all your XMA wave data?\\n\");\n                    return hr;\n                }\n            }\n\n            memcpy(mXMAMemory, startAudio, audioBytes);\n            mStartAudio = reinterpret_cast<const uint8_t*>(mXMAMemory);\n\n            mWavData.reset(new (std::nothrow) uint8_t[sizeof(XMA2WAVEFORMATEX) + (seekCount * sizeof(uint32_t))]);\n            if (!mWavData)\n                return E_OUTOFMEMORY;\n\n            memcpy(mWavData.get(), wfx, sizeof(XMA2WAVEFORMATEX));\n            mWaveFormat = reinterpret_cast<WAVEFORMATEX*>(mWavData.get());\n\n            // XMA seek table is Big-Endian\n            {\n                auto dest = reinterpret_cast<uint32_t*>(mWavData.get() + sizeof(XMA2WAVEFORMATEX));\n                for (size_t k = 0; k < seekCount; ++k)\n                {\n                    dest[k] = _byteswap_ulong(seekTable[k]);\n                }\n            }\n\n            mSeekCount = static_cast<uint32_t>(seekCount);\n            mSeekTable = reinterpret_cast<const uint32_t*>(mWavData.get() + sizeof(XMA2WAVEFORMATEX));\n\n            wavData.reset();\n            break;\n\n        #endif // XMA2\n\n        default:\n        {\n            DebugTrace(\"ERROR: SoundEffect encountered an unsupported format tag (%u)\\n\", wfx->wFormatTag);\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n    }\n\n    mAudioBytes = static_cast<uint32_t>(audioBytes);\n    mLoopStart = loopStart;\n    mLoopLength = loopLength;\n\n    return S_OK;\n}\n\n\nvoid SoundEffect::Impl::Play(float volume, float pitch, float pan)\n{\n    assert(volume >= -XAUDIO2_MAX_VOLUME_LEVEL && volume <= XAUDIO2_MAX_VOLUME_LEVEL);\n    assert(pitch >= -1.f && pitch <= 1.f);\n    assert(pan >= -1.f && pan <= 1.f);\n\n    IXAudio2SourceVoice* voice = nullptr;\n    mEngine->AllocateVoice(mWaveFormat, SoundEffectInstance_Default, true, &voice);\n\n    if (!voice)\n        return;\n\n    if (volume != 1.f)\n    {\n        HRESULT hr = voice->SetVolume(volume);\n        ThrowIfFailed(hr);\n    }\n\n    if (pitch != 0.f)\n    {\n        float fr = XAudio2SemitonesToFrequencyRatio(pitch * 12.f);\n\n        HRESULT hr = voice->SetFrequencyRatio(fr);\n        ThrowIfFailed(hr);\n    }\n\n    if (pan != 0.f)\n    {\n        float matrix[16];\n        if (ComputePan(pan, mWaveFormat->nChannels, matrix))\n        {\n            HRESULT hr = voice->SetOutputMatrix(nullptr, mWaveFormat->nChannels, mEngine->GetOutputChannels(), matrix);\n            ThrowIfFailed(hr);\n        }\n    }\n\n    HRESULT hr = voice->Start(0);\n    ThrowIfFailed(hr);\n\n    XAUDIO2_BUFFER buffer = {};\n    buffer.AudioBytes = mAudioBytes;\n    buffer.pAudioData = mStartAudio;\n    buffer.Flags = XAUDIO2_END_OF_STREAM;\n    buffer.pContext = this;\n\n    #ifdef DIRECTX_ENABLE_XWMA\n    uint32_t tag = GetFormatTag(mWaveFormat);\n    if (tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3)\n    {\n        XAUDIO2_BUFFER_WMA wmaBuffer = {};\n        wmaBuffer.PacketCount = mSeekCount;\n        wmaBuffer.pDecodedPacketCumulativeBytes = mSeekTable;\n\n        hr = voice->SubmitSourceBuffer(&buffer, &wmaBuffer);\n    }\n    else\n    #endif // xWMA\n    {\n        hr = voice->SubmitSourceBuffer(&buffer, nullptr);\n    }\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: SoundEffect failed (%08X) when submitting buffer:\\n\", static_cast<unsigned int>(hr));\n        DebugTrace(\"\\tFormat Tag %u, %u channels, %u-bit, %u Hz, %u bytes\\n\",\n            mWaveFormat->wFormatTag, mWaveFormat->nChannels, mWaveFormat->wBitsPerSample, mWaveFormat->nSamplesPerSec, mAudioBytes);\n        throw std::exception(\"SubmitSourceBuffer\");\n    }\n\n    InterlockedIncrement(&mOneShots);\n}\n\n\n//--------------------------------------------------------------------------------------\n// SoundEffect\n//--------------------------------------------------------------------------------------\n\n// Public constructors.\n_Use_decl_annotations_\nSoundEffect::SoundEffect(AudioEngine* engine, const wchar_t* waveFileName)\n    : pImpl(std::make_unique<Impl>(engine))\n{\n    WAVData wavInfo;\n    std::unique_ptr<uint8_t[]> wavData;\n    HRESULT hr = LoadWAVAudioFromFileEx(waveFileName, wavData, wavInfo);\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: SoundEffect failed (%08X) to load from .wav file \\\"%ls\\\"\\n\",\n            static_cast<unsigned int>(hr), waveFileName);\n        throw std::exception(\"SoundEffect\");\n    }\n\n#ifdef DIRECTX_ENABLE_SEEK_TABLES\n    hr = pImpl->Initialize(engine, wavData, wavInfo.wfx, wavInfo.startAudio, wavInfo.audioBytes,\n                           wavInfo.seek, wavInfo.seekCount,\n                           wavInfo.loopStart, wavInfo.loopLength);\n#else\n    hr = pImpl->Initialize(engine, wavData, wavInfo.wfx, wavInfo.startAudio, wavInfo.audioBytes,\n                           wavInfo.loopStart, wavInfo.loopLength);\n#endif\n\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: SoundEffect failed (%08X) to intialize from .wav file \\\"%ls\\\"\\n\",\n            static_cast<unsigned int>(hr), waveFileName);\n        throw std::exception(\"SoundEffect\");\n    }\n}\n\n\n_Use_decl_annotations_\nSoundEffect::SoundEffect(AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,\n                         const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes)\n    : pImpl(std::make_unique<Impl>(engine))\n{\n#ifdef DIRECTX_ENABLE_SEEK_TABLES\n    HRESULT hr = pImpl->Initialize(engine, wavData, wfx, startAudio, audioBytes, nullptr, 0, 0, 0);\n#else\n    HRESULT hr = pImpl->Initialize(engine, wavData, wfx, startAudio, audioBytes, 0, 0);\n#endif\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: SoundEffect failed (%08X) to intialize\\n\", static_cast<unsigned int>(hr));\n        throw std::exception(\"SoundEffect\");\n    }\n}\n\n\n_Use_decl_annotations_\nSoundEffect::SoundEffect(AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,\n                         const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes,\n                         uint32_t loopStart, uint32_t loopLength)\n    : pImpl(std::make_unique<Impl>(engine))\n{\n#ifdef DIRECTX_ENABLE_SEEK_TABLES\n    HRESULT hr = pImpl->Initialize(engine, wavData, wfx, startAudio, audioBytes, nullptr, 0, loopStart, loopLength);\n#else\n    HRESULT hr = pImpl->Initialize(engine, wavData, wfx, startAudio, audioBytes, loopStart, loopLength);\n#endif\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: SoundEffect failed (%08X) to intialize\\n\", static_cast<unsigned int>(hr));\n        throw std::exception(\"SoundEffect\");\n    }\n}\n\n\n#ifdef DIRECTX_ENABLE_SEEK_TABLES\n\n_Use_decl_annotations_\nSoundEffect::SoundEffect(AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,\n                         const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes,\n                         const uint32_t* seekTable, size_t seekCount)\n{\n    HRESULT hr = pImpl->Initialize(engine, wavData, wfx, startAudio, audioBytes, seekTable, seekCount, 0, 0);\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: SoundEffect failed (%08X) to intialize\\n\", static_cast<unsigned int>(hr));\n        throw std::exception(\"SoundEffect\");\n    }\n}\n\n#endif\n\n\n// Move constructor.\nSoundEffect::SoundEffect(SoundEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nSoundEffect& SoundEffect::operator= (SoundEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nSoundEffect::~SoundEffect()\n{\n}\n\n\n// Public methods.\nvoid SoundEffect::Play()\n{\n    pImpl->Play(1.f, 0.f, 0.f);\n}\n\n\nvoid SoundEffect::Play(float volume, float pitch, float pan)\n{\n    pImpl->Play(volume, pitch, pan);\n}\n\n\nstd::unique_ptr<SoundEffectInstance> SoundEffect::CreateInstance(SOUND_EFFECT_INSTANCE_FLAGS flags)\n{\n    auto effect = new SoundEffectInstance(pImpl->mEngine, this, flags);\n    assert(effect != nullptr);\n    pImpl->mInstances.emplace_back(effect->GetVoiceNotify());\n    return std::unique_ptr<SoundEffectInstance>(effect);\n}\n\n\nvoid SoundEffect::UnregisterInstance(_In_ IVoiceNotify* instance)\n{\n    auto it = std::find(pImpl->mInstances.begin(), pImpl->mInstances.end(), instance);\n    if (it == pImpl->mInstances.end())\n        return;\n\n    pImpl->mInstances.erase(it);\n}\n\n\n// Public accessors.\nbool SoundEffect::IsInUse() const noexcept\n{\n    return (pImpl->mOneShots > 0) || !pImpl->mInstances.empty();\n}\n\n\nsize_t SoundEffect::GetSampleSizeInBytes() const noexcept\n{\n    return pImpl->mAudioBytes;\n}\n\n\nsize_t SoundEffect::GetSampleDuration() const noexcept\n{\n    if (!pImpl->mWaveFormat || !pImpl->mWaveFormat->nChannels)\n        return 0;\n\n    switch (GetFormatTag(pImpl->mWaveFormat))\n    {\n        case WAVE_FORMAT_ADPCM:\n        {\n            auto adpcmFmt = reinterpret_cast<const ADPCMWAVEFORMAT*>(pImpl->mWaveFormat);\n\n            uint64_t duration = uint64_t(pImpl->mAudioBytes / adpcmFmt->wfx.nBlockAlign) * adpcmFmt->wSamplesPerBlock;\n            unsigned int partial = pImpl->mAudioBytes % adpcmFmt->wfx.nBlockAlign;\n            if (partial)\n            {\n                if (partial >= (7u * adpcmFmt->wfx.nChannels))\n                    duration += (uint64_t(partial) * 2 / uint64_t(adpcmFmt->wfx.nChannels - 12));\n            }\n            return static_cast<size_t>(duration);\n        }\n\n        #ifdef DIRECTX_ENABLE_XWMA\n\n        case WAVE_FORMAT_WMAUDIO2:\n        case WAVE_FORMAT_WMAUDIO3:\n            if (pImpl->mSeekTable && pImpl->mSeekCount > 0)\n            {\n                return pImpl->mSeekTable[pImpl->mSeekCount - 1] / uint32_t(2 * pImpl->mWaveFormat->nChannels);\n            }\n            break;\n\n        #endif\n\n        #ifdef DIRECTX_ENABLE_XMA2\n\n        case WAVE_FORMAT_XMA2:\n            return reinterpret_cast<const XMA2WAVEFORMATEX*>(pImpl->mWaveFormat)->SamplesEncoded;\n\n        #endif\n\n        default:\n            if (pImpl->mWaveFormat->wBitsPerSample > 0)\n            {\n                return static_cast<size_t>((uint64_t(pImpl->mAudioBytes) * 8)\n                                           / (uint64_t(pImpl->mWaveFormat->wBitsPerSample) * uint64_t(pImpl->mWaveFormat->nChannels)));\n            }\n    }\n\n    return 0;\n}\n\n\nsize_t SoundEffect::GetSampleDurationMS() const noexcept\n{\n    if (!pImpl->mWaveFormat || !pImpl->mWaveFormat->nSamplesPerSec)\n        return 0;\n\n    uint64_t samples = GetSampleDuration();\n    return static_cast<size_t>((samples * 1000) / pImpl->mWaveFormat->nSamplesPerSec);\n}\n\n\nconst WAVEFORMATEX* SoundEffect::GetFormat() const noexcept\n{\n    return pImpl->mWaveFormat;\n}\n\n\n#ifdef DIRECTX_ENABLE_XWMA\n\nbool SoundEffect::FillSubmitBuffer(_Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer) const\n{\n    memset(&buffer, 0, sizeof(buffer));\n    memset(&wmaBuffer, 0, sizeof(wmaBuffer));\n\n    buffer.AudioBytes = pImpl->mAudioBytes;\n    buffer.pAudioData = pImpl->mStartAudio;\n    buffer.LoopBegin = pImpl->mLoopStart;\n    buffer.LoopLength = pImpl->mLoopLength;\n\n    uint32_t tag = GetFormatTag(pImpl->mWaveFormat);\n    if (tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3)\n    {\n        wmaBuffer.PacketCount = pImpl->mSeekCount;\n        wmaBuffer.pDecodedPacketCumulativeBytes = pImpl->mSeekTable;\n        return true;\n    }\n\n    return false;\n}\n\n#else // !xWMA\n\nvoid SoundEffect::FillSubmitBuffer(_Out_ XAUDIO2_BUFFER& buffer) const\n{\n    memset(&buffer, 0, sizeof(buffer));\n    buffer.AudioBytes = pImpl->mAudioBytes;\n    buffer.pAudioData = pImpl->mStartAudio;\n    buffer.LoopBegin = pImpl->mLoopStart;\n    buffer.LoopLength = pImpl->mLoopLength;\n}\n\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/SoundEffectInstance.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SoundEffectInstance.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"SoundCommon.h\"\n\nusing namespace DirectX;\n\n\n//======================================================================================\n// SoundEffectInstance\n//======================================================================================\n\n// Internal object implementation class.\nclass SoundEffectInstance::Impl : public IVoiceNotify\n{\npublic:\n    Impl(_In_ AudioEngine* engine, _In_ SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags) :\n        mBase(),\n        mEffect(effect),\n        mWaveBank(nullptr),\n        mIndex(0),\n        mLooped(false)\n    {\n        assert(engine != nullptr);\n        engine->RegisterNotify(this, false);\n\n        assert(mEffect != nullptr);\n        mBase.Initialize(engine, effect->GetFormat(), flags);\n    }\n\n    Impl(_In_ AudioEngine* engine, _In_ WaveBank* waveBank, uint32_t index, SOUND_EFFECT_INSTANCE_FLAGS flags) :\n        mBase(),\n        mEffect(nullptr),\n        mWaveBank(waveBank),\n        mIndex(index),\n        mLooped(false)\n    {\n        assert(engine != nullptr);\n        engine->RegisterNotify(this, false);\n\n        char buff[64] = {};\n        auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);\n        assert(mWaveBank != nullptr);\n        mBase.Initialize(engine, mWaveBank->GetFormat(index, wfx, sizeof(buff)), flags);\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl() override\n    {\n        mBase.DestroyVoice();\n\n        if (mBase.engine)\n        {\n            mBase.engine->UnregisterNotify(this, false, false);\n            mBase.engine = nullptr;\n        }\n    }\n\n    void Play(bool loop);\n\n    // IVoiceNotify\n    void __cdecl OnBufferEnd() override\n    {\n        // We don't register for this notification for SoundEffectInstances, so this should not be invoked\n        assert(false);\n    }\n\n    void __cdecl OnCriticalError() override\n    {\n        mBase.OnCriticalError();\n    }\n\n    void __cdecl OnReset() override\n    {\n        mBase.OnReset();\n    }\n\n    void __cdecl OnUpdate() override\n    {\n        // We do not register for update notification\n        assert(false);\n    }\n\n    void __cdecl OnDestroyEngine() noexcept override\n    {\n        mBase.OnDestroy();\n    }\n\n    void __cdecl OnTrim() override\n    {\n        mBase.OnTrim();\n    }\n\n    void __cdecl GatherStatistics(AudioStatistics& stats) const noexcept override\n    {\n        mBase.GatherStatistics(stats);\n    }\n\n    void __cdecl OnDestroyParent() noexcept override\n    {\n        mBase.OnDestroy();\n        mWaveBank = nullptr;\n        mEffect = nullptr;\n    }\n\n    SoundEffectInstanceBase         mBase;\n    SoundEffect*                    mEffect;\n    WaveBank*                       mWaveBank;\n    uint32_t                        mIndex;\n    bool                            mLooped;\n};\n\n\nvoid SoundEffectInstance::Impl::Play(bool loop)\n{\n    if (!mBase.voice)\n    {\n        if (mWaveBank)\n        {\n            char buff[64] = {};\n            auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);\n            mBase.AllocateVoice(mWaveBank->GetFormat(mIndex, wfx, sizeof(buff)));\n        }\n        else\n        {\n            assert(mEffect != nullptr);\n            mBase.AllocateVoice(mEffect->GetFormat());\n        }\n    }\n\n    if (!mBase.Play())\n        return;\n\n    // Submit audio data for STOPPED -> PLAYING state transition\n    XAUDIO2_BUFFER buffer = {};\n\n#ifdef DIRECTX_ENABLE_XWMA\n\n    bool iswma = false;\n    XAUDIO2_BUFFER_WMA wmaBuffer = {};\n    if (mWaveBank)\n    {\n        iswma = mWaveBank->FillSubmitBuffer(mIndex, buffer, wmaBuffer);\n    }\n    else\n    {\n        assert(mEffect != nullptr);\n        iswma = mEffect->FillSubmitBuffer(buffer, wmaBuffer);\n    }\n\n#else // !xWMA\n\n    if (mWaveBank)\n    {\n        mWaveBank->FillSubmitBuffer(mIndex, buffer);\n    }\n    else\n    {\n        assert(mEffect != nullptr);\n        mEffect->FillSubmitBuffer(buffer);\n    }\n\n#endif\n\n    buffer.Flags = XAUDIO2_END_OF_STREAM;\n    if (loop)\n    {\n        mLooped = true;\n        buffer.LoopCount = XAUDIO2_LOOP_INFINITE;\n    }\n    else\n    {\n        mLooped = false;\n        buffer.LoopCount = buffer.LoopBegin = buffer.LoopLength = 0;\n    }\n    buffer.pContext = nullptr;\n\n    HRESULT hr;\n    #ifdef DIRECTX_ENABLE_XWMA\n    if (iswma)\n    {\n        hr = mBase.voice->SubmitSourceBuffer(&buffer, &wmaBuffer);\n    }\n    else\n    #endif\n    {\n        hr = mBase.voice->SubmitSourceBuffer(&buffer, nullptr);\n    }\n\n    if (FAILED(hr))\n    {\n    #ifdef _DEBUG\n        DebugTrace(\"ERROR: SoundEffectInstance failed (%08X) when submitting buffer:\\n\", static_cast<unsigned int>(hr));\n\n        char buff[64] = {};\n        auto wfx = (mWaveBank) ? mWaveBank->GetFormat(mIndex, reinterpret_cast<WAVEFORMATEX*>(buff), sizeof(buff))\n            : mEffect->GetFormat();\n\n        size_t length = (mWaveBank) ? mWaveBank->GetSampleSizeInBytes(mIndex) : mEffect->GetSampleSizeInBytes();\n\n        DebugTrace(\"\\tFormat Tag %u, %u channels, %u-bit, %u Hz, %zu bytes\\n\",\n            wfx->wFormatTag, wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec, length);\n    #endif\n        mBase.Stop(true, mLooped);\n        throw std::exception(\"SubmitSourceBuffer\");\n    }\n}\n\n\n//--------------------------------------------------------------------------------------\n// SoundEffectInstance\n//--------------------------------------------------------------------------------------\n\n// Private constructors\n_Use_decl_annotations_\nSoundEffectInstance::SoundEffectInstance(AudioEngine* engine, SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags) :\n    pImpl(std::make_unique<Impl>(engine, effect, flags))\n{\n}\n\n_Use_decl_annotations_\nSoundEffectInstance::SoundEffectInstance(AudioEngine* engine, WaveBank* waveBank, unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags) :\n    pImpl(std::make_unique<Impl>(engine, waveBank, index, flags))\n{\n}\n\n\n// Move constructor.\nSoundEffectInstance::SoundEffectInstance(SoundEffectInstance&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nSoundEffectInstance& SoundEffectInstance::operator= (SoundEffectInstance&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nSoundEffectInstance::~SoundEffectInstance()\n{\n    if (pImpl)\n    {\n        if (pImpl->mWaveBank)\n        {\n            pImpl->mWaveBank->UnregisterInstance(pImpl.get());\n            pImpl->mWaveBank = nullptr;\n        }\n\n        if (pImpl->mEffect)\n        {\n            pImpl->mEffect->UnregisterInstance(pImpl.get());\n            pImpl->mEffect = nullptr;\n        }\n    }\n}\n\n\n// Public methods.\nvoid SoundEffectInstance::Play(bool loop)\n{\n    pImpl->Play(loop);\n}\n\n\nvoid SoundEffectInstance::Stop(bool immediate) noexcept\n{\n    pImpl->mBase.Stop(immediate, pImpl->mLooped);\n}\n\n\nvoid SoundEffectInstance::Pause() noexcept\n{\n    pImpl->mBase.Pause();\n}\n\n\nvoid SoundEffectInstance::Resume()\n{\n    pImpl->mBase.Resume();\n}\n\n\nvoid SoundEffectInstance::SetVolume(float volume)\n{\n    pImpl->mBase.SetVolume(volume);\n}\n\n\nvoid SoundEffectInstance::SetPitch(float pitch)\n{\n    pImpl->mBase.SetPitch(pitch);\n}\n\n\nvoid SoundEffectInstance::SetPan(float pan)\n{\n    pImpl->mBase.SetPan(pan);\n}\n\n\nvoid SoundEffectInstance::Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords)\n{\n    pImpl->mBase.Apply3D(listener, emitter, rhcoords);\n}\n\n\n// Public accessors.\nbool SoundEffectInstance::IsLooped() const noexcept\n{\n    return pImpl->mLooped;\n}\n\n\nSoundState SoundEffectInstance::GetState() noexcept\n{\n    return pImpl->mBase.GetState(true);\n}\n\n\nIVoiceNotify* SoundEffectInstance::GetVoiceNotify() const noexcept\n{\n    return pImpl.get();\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/SoundStreamInstance.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SoundStreamInstance.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"DirectXHelpers.h\"\n#include \"WaveBankReader.h\"\n#include \"PlatformHelpers.h\"\n#include \"SoundCommon.h\"\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <apu.h>\n#include <shapexmacontext.h>\n#endif\n\nusing namespace DirectX;\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#endif\n\n#pragma warning(disable : 4061 4062)\n\n//#define VERBOSE_TRACE\n\n#ifdef VERBOSE_TRACE\n#pragma message(\"NOTE: Verbose tracing enabled\")\n#endif\n\nnamespace\n{\n    const size_t DVD_SECTOR_SIZE = 2048;\n    const size_t MEMORY_ALLOC_SIZE = 4096;\n    const size_t MAX_BUFFER_COUNT = 3;\n\n    #ifdef DIRECTX_ENABLE_SEEK_TABLES\n    const size_t MAX_STREAMING_SEEK_PACKETS = 2048;\n    #endif\n\n    #ifdef DIRECTX_ENABLE_XMA2\n    const size_t XMA2_64KBLOCKINBYTES = 65536;\n\n    struct apu_deleter { void operator()(void* p) noexcept { if (p) ApuFree(p); } };\n    #endif\n\n    size_t ComputeAsyncPacketSize(_In_ const WAVEFORMATEX* wfx, uint32_t tag)\n    {\n        if (!wfx)\n            return 0;\n\n        size_t buffer = size_t(wfx->nAvgBytesPerSec) * 2u;\n\n    #ifdef DIRECTX_ENABLE_XMA2\n        if (tag == WAVE_FORMAT_XMA2)\n        {\n            buffer = AlignUp(buffer, XMA2_64KBLOCKINBYTES);\n            buffer = std::max<size_t>(XMA2_64KBLOCKINBYTES, buffer);\n            return buffer;\n        }\n    #else\n        UNREFERENCED_PARAMETER(tag);\n    #endif\n\n        buffer = AlignUp(buffer, MEMORY_ALLOC_SIZE);\n        buffer = std::max<size_t>(65536u, buffer);\n        return buffer;\n    }\n\n    static_assert(MEMORY_ALLOC_SIZE >= DVD_SECTOR_SIZE, \"Memory size should be larger than sector size\");\n    static_assert(MEMORY_ALLOC_SIZE >= DVD_SECTOR_SIZE || (MEMORY_ALLOC_SIZE% DVD_SECTOR_SIZE) == 0, \"Memory size should be multiples of sector size\");\n}\n\n\n//======================================================================================\n// SoundStreamInstance\n//======================================================================================\n\n// Internal object implementation class.\nclass SoundStreamInstance::Impl : public IVoiceNotify\n{\npublic:\n    Impl(_In_ AudioEngine* engine,\n        WaveBank* waveBank,\n        uint32_t index,\n        SOUND_EFFECT_INSTANCE_FLAGS flags) noexcept(false) :\n        mBase(),\n        mWaveBank(waveBank),\n        mIndex(index),\n        mPlaying(false),\n        mLooped(false),\n        mEndStream(false),\n        mPrefetch(false),\n        mSitching(false),\n        mPackets{},\n        mCurrentDiskReadBuffer(0),\n        mCurrentPlayBuffer(0),\n        mBlockAlign(0),\n        mCurrentPosition(0),\n        mOffsetBytes(0),\n        mLengthInBytes(0),\n        mPacketSize(0),\n        mTotalSize(0)\n    #ifdef DIRECTX_ENABLE_SEEK_TABLES\n        , mSeekCount(0),\n        mSeekTable(nullptr),\n        mSeekTableCopy{}\n    #endif\n    {\n        assert(engine != nullptr);\n        engine->RegisterNotify(this, true);\n\n        char buff[64] = {};\n        auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);\n        assert(mWaveBank != nullptr);\n        mBase.Initialize(engine, mWaveBank->GetFormat(index, wfx, sizeof(buff)), flags);\n\n        WaveBankReader::Metadata metadata = {};\n        (void)mWaveBank->GetPrivateData(index, &metadata, sizeof(metadata));\n\n        mOffsetBytes = metadata.offsetBytes;\n        mLengthInBytes = metadata.lengthBytes;\n\n        #ifdef DIRECTX_ENABLE_SEEK_TABLES\n        WaveBankSeekData seekData = {};\n        (void)mWaveBank->GetPrivateData(index, &seekData, sizeof(seekData));\n        if (seekData.tag == WAVE_FORMAT_WMAUDIO2 || seekData.tag == WAVE_FORMAT_WMAUDIO3)\n        {\n            mSeekCount = seekData.seekCount;\n            mSeekTable = seekData.seekTable;\n        }\n        #endif\n\n        mBufferEnd.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        mBufferRead.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mBufferEnd || !mBufferRead)\n        {\n            throw std::exception(\"CreateEvent\");\n        }\n\n        ThrowIfFailed(AllocateStreamingBuffers(wfx));\n\n#ifdef VERBOSE_TRACE\n        DebugTrace(\"INFO (Streaming): packet size %zu, play length %zu\\n\", mPacketSize, mLengthInBytes);\n#endif\n\n        mPrefetch = true;\n        ThrowIfFailed(ReadBuffers());\n    }\n\n    virtual ~Impl() override\n    {\n        mBase.DestroyVoice();\n\n        if (mWaveBank && mWaveBank->GetAsyncHandle())\n        {\n            for (size_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n            {\n                (void)CancelIoEx(mWaveBank->GetAsyncHandle(), &mPackets[j].request);\n            }\n        }\n\n        if (mBase.engine)\n        {\n            mBase.engine->UnregisterNotify(this, false, true);\n            mBase.engine = nullptr;\n        }\n\n        for (size_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n        {\n            mPackets[j] = {};\n        }\n        mPacketSize = 0;\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    void Play(bool loop)\n    {\n        if (!mBase.voice)\n        {\n            if (!mWaveBank)\n                return;\n\n            char buff[64] = {};\n            auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);\n            mBase.AllocateVoice(mWaveBank->GetFormat(mIndex, wfx, sizeof(buff)));\n        }\n\n        if (!mBase.Play())\n            return;\n\n        mLooped = loop;\n        mEndStream = false;\n\n        if (!mPrefetch)\n        {\n            mCurrentPosition = 0;\n        }\n\n        ThrowIfFailed(PlayBuffers());\n    }\n\n    // IVoiceNotify\n    virtual void __cdecl OnBufferEnd() override\n    {\n        // Not used\n    }\n\n    virtual void __cdecl OnCriticalError() override\n    {\n        mBase.OnCriticalError();\n    }\n\n    virtual void __cdecl OnReset() override\n    {\n        mBase.OnReset();\n    }\n\n    virtual void __cdecl OnUpdate() override\n    {\n        if (!mPlaying)\n            return;\n\n        HANDLE events[] = { mBufferRead.get(), mBufferEnd.get() };\n        switch (WaitForMultipleObjectsEx(_countof(events), events, FALSE, 0, FALSE))\n        {\n        case WAIT_TIMEOUT:\n            break;\n\n        case WAIT_OBJECT_0: // Read completed\n#ifdef VERBOSE_TRACE\n            DebugTrace(\"INFO (Streaming): Playing... (readpos %zu) [\", mCurrentPosition);\n            for (uint32_t k = 0; k < MAX_BUFFER_COUNT; ++k)\n            {\n                DebugTrace(\"%ls \", s_debugState[static_cast<int>(mPackets[k].state)]);\n            }\n            DebugTrace(\"]\\n\");\n#endif\n            mPrefetch = false;\n            ThrowIfFailed(PlayBuffers());\n            break;\n\n        case (WAIT_OBJECT_0 + 1): // Play completed\n#ifdef VERBOSE_TRACE\n            DebugTrace(\"INFO (Streaming): Reading... (readpos %zu) [\", mCurrentPosition);\n            for (uint32_t k = 0; k < MAX_BUFFER_COUNT; ++k)\n            {\n                DebugTrace(\"%ls \", s_debugState[static_cast<int>(mPackets[k].state)]);\n            }\n            DebugTrace(\"]\\n\");\n#endif\n            ThrowIfFailed(ReadBuffers());\n            break;\n\n        case WAIT_FAILED:\n            throw std::exception(\"WaitForMultipleObjects\");\n        }\n    }\n\n    virtual void __cdecl OnDestroyEngine() noexcept override\n    {\n        mBase.OnDestroy();\n    }\n\n    virtual void __cdecl OnTrim() override\n    {\n        mBase.OnTrim();\n    }\n\n    virtual void __cdecl GatherStatistics(AudioStatistics& stats) const noexcept override\n    {\n        mBase.GatherStatistics(stats);\n\n        stats.streamingBytes += mPacketSize * MAX_BUFFER_COUNT;\n    }\n\n    virtual void __cdecl OnDestroyParent() noexcept override\n    {\n        mBase.OnDestroy();\n        mWaveBank = nullptr;\n    }\n\n    SoundEffectInstanceBase         mBase;\n    WaveBank*                       mWaveBank;\n    uint32_t                        mIndex;\n    bool                            mPlaying;\n    bool                            mLooped;\n    bool                            mEndStream;\n    bool                            mPrefetch;\n    bool                            mSitching;\n\n    ScopedHandle                    mBufferEnd;\n    ScopedHandle                    mBufferRead;\n\n    enum class State : uint32_t\n    {\n        FREE = 0,\n        PENDING,\n        READY,\n        PLAYING,\n    };\n\n#ifdef VERBOSE_TRACE\n    static const wchar_t* s_debugState[4];\n#endif\n\n    struct BufferNotify : public IVoiceNotify\n    {\n        BufferNotify() : mParent(nullptr), mIndex(0) {}\n\n        void Set(SoundStreamInstance::Impl* parent, size_t index) noexcept(true) { mParent = parent; mIndex = index; }\n\n        void __cdecl OnBufferEnd() override\n        {\n            assert(mParent != nullptr);\n            mParent->mPackets[mIndex].state = State::FREE;\n            SetEvent(mParent->mBufferEnd.get());\n        }\n\n        void __cdecl OnCriticalError() override { assert(mParent != nullptr); mParent->OnCriticalError(); }\n        void __cdecl OnReset() override { assert(mParent != nullptr); mParent->OnReset(); }\n        void __cdecl OnUpdate() override { assert(mParent != nullptr); mParent->OnUpdate(); }\n        void __cdecl OnDestroyEngine() noexcept override { assert(mParent != nullptr); mParent->OnDestroyEngine(); }\n        void __cdecl OnTrim() override { assert(mParent != nullptr); mParent->OnTrim(); }\n        void __cdecl GatherStatistics(AudioStatistics& stats) const override { assert(mParent != nullptr); mParent->GatherStatistics(stats); }\n        void __cdecl OnDestroyParent() noexcept override { assert(mParent != nullptr); mParent->OnDestroyParent(); }\n\n    private:\n        SoundStreamInstance::Impl* mParent;\n        size_t mIndex;\n    };\n\n    struct Packets\n    {\n        State       state;\n        uint8_t*    buffer;\n        uint8_t*    stitchBuffer;\n        uint32_t    valid;\n        uint32_t    audioBytes;\n        uint32_t    startPosition;\n        OVERLAPPED  request;\n        BufferNotify notify;\n\n        Packets() :\n            state(State::FREE),\n            buffer(nullptr),\n            stitchBuffer(nullptr),\n            valid(0),\n            audioBytes(0),\n            startPosition(0),\n            request{},\n            notify{} {}\n    };\n\n    Packets                         mPackets[MAX_BUFFER_COUNT];\n\nprivate:\n    uint32_t                        mCurrentDiskReadBuffer;\n    uint32_t                        mCurrentPlayBuffer;\n    uint32_t                        mBlockAlign;\n    size_t                          mCurrentPosition;\n    size_t                          mOffsetBytes;\n    size_t                          mLengthInBytes;\n\n    size_t                          mPacketSize;\n    size_t                          mTotalSize;\n    std::unique_ptr<uint8_t[], virtual_deleter> mStreamBuffer;\n\n#ifdef DIRECTX_ENABLE_SEEK_TABLES\n    uint32_t                        mSeekCount;\n    const uint32_t*                 mSeekTable;\n    uint32_t                        mSeekTableCopy[MAX_STREAMING_SEEK_PACKETS];\n#endif\n\n#ifdef DIRECTX_ENABLE_XMA2\n    std::unique_ptr<uint8_t[], apu_deleter> mXMAMemory;\n#endif\n\n    HRESULT AllocateStreamingBuffers(const WAVEFORMATEX* wfx) noexcept;\n    HRESULT ReadBuffers() noexcept;\n    HRESULT PlayBuffers() noexcept;\n};\n\n\nHRESULT SoundStreamInstance::Impl::AllocateStreamingBuffers(const WAVEFORMATEX* wfx) noexcept\n{\n    if (!wfx)\n        return E_INVALIDARG;\n\n    uint32_t tag = GetFormatTag(wfx);\n\n    size_t packetSize = ComputeAsyncPacketSize(wfx, tag);\n    if (!packetSize)\n        return E_UNEXPECTED;\n\n    uint64_t totalSize = uint64_t(packetSize) * uint64_t(MAX_BUFFER_COUNT);\n    if (totalSize > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n    mPacketSize = packetSize;\n    mBlockAlign = wfx->nBlockAlign;\n    mSitching = false;\n\n    size_t stitchSize = 0;\n    if ((packetSize % wfx->nBlockAlign) != 0)\n    {\n        mSitching = true;\n\n        stitchSize = AlignUp<size_t>(wfx->nBlockAlign, DVD_SECTOR_SIZE);\n        totalSize += uint64_t(stitchSize) * uint64_t(MAX_BUFFER_COUNT);\n        if (totalSize > UINT32_MAX)\n            return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n    }\n\n    #ifdef DIRECTX_ENABLE_XMA2\n    if ((mTotalSize < totalSize) || (tag == WAVE_FORMAT_XMA2 && !mXMAMemory) || (tag != WAVE_FORMAT_XMA2 && !mStreamBuffer))\n    #else\n    if (mTotalSize < totalSize)\n    #endif\n    {\n        mStreamBuffer.reset();\n    #ifdef DIRECTX_ENABLE_XMA2\n        mXMAMemory.reset();\n        if (tag == WAVE_FORMAT_XMA2)\n        {\n            void* xmaMemory = nullptr;\n            HRESULT hr = ApuAlloc(&xmaMemory, nullptr, static_cast<UINT32>(totalSize), SHAPE_XMA_INPUT_BUFFER_ALIGNMENT);\n            if (FAILED(hr))\n            {\n                DebugTrace(\"ERROR: ApuAlloc failed (%llu bytes). Did you allocate a large enough heap with ApuCreateHeap for all your XMA wave data?\\n\", totalSize);\n                return hr;\n            }\n            mXMAMemory.reset(static_cast<uint8_t*>(xmaMemory));\n        }\n        else\n    #endif\n        {\n            mStreamBuffer.reset(reinterpret_cast<uint8_t*>(\n                VirtualAlloc(nullptr, static_cast<SIZE_T>(totalSize), MEM_COMMIT, PAGE_READWRITE)\n                ));\n\n            if (!mStreamBuffer)\n            {\n                DebugTrace(\"ERROR: Failed allocating %llu bytes for SoundStreamInstance\\n\", totalSize);\n                mPacketSize = 0;\n                totalSize = 0;\n                return E_OUTOFMEMORY;\n            }\n        }\n\n        mTotalSize = static_cast<size_t>(totalSize);\n\n    #ifdef DIRECTX_ENABLE_XMA2\n        uint8_t* ptr = (tag == WAVE_FORMAT_XMA2) ? mXMAMemory.get() : mStreamBuffer.get();\n    #else\n        uint8_t* ptr = mStreamBuffer.get();\n    #endif\n        for (size_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n        {\n            mPackets[j].buffer = ptr;\n            mPackets[j].stitchBuffer = nullptr;\n            mPackets[j].request.hEvent = mBufferRead.get();\n            mPackets[j].notify.Set(this, j);\n            ptr += packetSize;\n        }\n\n        if (stitchSize > 0)\n        {\n            for (size_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n            {\n                mPackets[j].stitchBuffer = ptr;\n                ptr += stitchSize;\n            }\n        }\n    }\n\n    return S_OK;\n}\n\n\nHRESULT SoundStreamInstance::Impl::ReadBuffers() noexcept\n{\n    if (mCurrentPosition >= mLengthInBytes)\n    {\n        if (!mLooped)\n        {\n            mEndStream = true;\n            return S_FALSE;\n        }\n\n#ifdef VERBOSE_TRACE\n        DebugTrace(\"INFO (Streaming): Loop restart\\n\");\n#endif\n\n        mCurrentPosition = 0;\n    }\n\n    HANDLE async = mWaveBank->GetAsyncHandle();\n\n    uint32_t readBuffer = mCurrentDiskReadBuffer;\n    for (uint32_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n    {\n        uint32_t entry = (j + readBuffer) % uint32_t(MAX_BUFFER_COUNT);\n        if (mPackets[entry].state == State::FREE)\n        {\n            if (mCurrentPosition < mLengthInBytes)\n            {\n                auto cbValid = static_cast<uint32_t>(std::min(mPacketSize, mLengthInBytes - mCurrentPosition));\n\n                mPackets[entry].valid = cbValid;\n                mPackets[entry].audioBytes = 0;\n                mPackets[entry].startPosition = static_cast<uint32_t>(mCurrentPosition);\n                mPackets[entry].request.Offset = static_cast<DWORD>(mOffsetBytes + mCurrentPosition);\n\n                if (!ReadFile(async, mPackets[entry].buffer, uint32_t(mPacketSize), nullptr, &mPackets[entry].request))\n                {\n                    DWORD error = GetLastError();\n                    if (error != ERROR_IO_PENDING)\n                    {\n                        return HRESULT_FROM_WIN32(error);\n                    }\n                }\n\n                mCurrentPosition += cbValid;\n\n                mCurrentDiskReadBuffer = (entry + 1) % uint32_t(MAX_BUFFER_COUNT);\n\n                mPackets[entry].state = State::PENDING;\n\n                if ((cbValid < mPacketSize) && mLooped)\n                {\n#ifdef VERBOSE_TRACE\n                    DebugTrace(\"INFO (Streaming): Loop restart\\n\");\n#endif\n                    mCurrentPosition = 0;\n                }\n            }\n        }\n    }\n\n    return S_OK;\n}\n\n\nHRESULT SoundStreamInstance::Impl::PlayBuffers() noexcept\n{\n    HANDLE async = mWaveBank->GetAsyncHandle();\n\n    for (uint32_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n    {\n        if (mPackets[j].state == State::PENDING)\n        {\n            DWORD cb = 0;\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n            BOOL result = GetOverlappedResultEx(async, &mPackets[j].request, &cb, 0, FALSE);\n#else\n            BOOL result = GetOverlappedResult(async, &mPackets[j].request, &cb, FALSE);\n#endif\n            if (result)\n            {\n                mPackets[j].state = State::READY;\n            }\n            else\n            {\n                DWORD error = GetLastError();\n                if (error != ERROR_IO_INCOMPLETE)\n                {\n                    ThrowIfFailed(HRESULT_FROM_WIN32(error));\n                }\n            }\n        }\n    }\n\n    if (!mBase.voice || !mPlaying)\n        return S_FALSE;\n\n    for (uint32_t j = 0; j < MAX_BUFFER_COUNT; ++j)\n    {\n        if (mPackets[mCurrentPlayBuffer].state != State::READY)\n            break;\n\n        const uint8_t* ptr = mPackets[mCurrentPlayBuffer].buffer;\n        uint32_t valid = mPackets[mCurrentPlayBuffer].valid;\n\n        bool endstream = false;\n        if (valid < mPacketSize)\n        {\n            endstream = true;\n#ifdef VERBOSE_TRACE\n            DebugTrace(\"INFO (Streaming): End of stream (%u of %zu bytes)\\n\", mPackets[mCurrentPlayBuffer].valid, mPacketSize);\n#endif\n        }\n\n        uint32_t thisFrameStitch = 0;\n        if (mSitching)\n        {\n            // Compute how many left-over bytes at the end of the previous packet (if any, they form the head of a partial block).\n            uint32_t prevFrameStitch = (mPackets[mCurrentPlayBuffer].startPosition % mBlockAlign);\n\n            if (prevFrameStitch > 0)\n            {\n                auto buffer = mPackets[mCurrentPlayBuffer].stitchBuffer;\n\n                // Compute how many bytes at the start of our current packet are the tail of the partial block.\n                thisFrameStitch = mBlockAlign - prevFrameStitch;\n\n                uint32_t k = (mCurrentPlayBuffer + MAX_BUFFER_COUNT - 1) % MAX_BUFFER_COUNT;\n                if (mPackets[k].state == State::READY || mPackets[k].state == State::PLAYING)\n                {\n                    // Compute how many bytes at the start of the previous packet were the tail of the previous stitch block.\n                    uint32_t prevFrameStitchOffset = (mPackets[k].startPosition % mBlockAlign);\n                    prevFrameStitchOffset = (prevFrameStitchOffset > 0) ? (mBlockAlign - prevFrameStitchOffset) : 0u;\n\n                    // Point to the start of the partial block's head in the previous packet.\n                    auto prevBuffer = mPackets[k].buffer + prevFrameStitchOffset + mPackets[k].audioBytes;\n\n                    // Merge the the head partial block in the previous packet with the tail partial block at the start of our packet.\n                    memcpy(buffer, prevBuffer, prevFrameStitch);\n                    memcpy(buffer + prevFrameStitch, ptr, thisFrameStitch);\n\n                    // Submit stitch packet (only need to get notified if we aren't submitting another packet for this buffer).\n                    XAUDIO2_BUFFER buf = {};\n                    buf.AudioBytes = mBlockAlign;\n                    buf.pAudioData = buffer;\n\n                    if (endstream && (valid <= thisFrameStitch))\n                    {\n                        buf.Flags = XAUDIO2_END_OF_STREAM;\n                        buf.pContext = &mPackets[mCurrentPlayBuffer].notify;\n                    }\n#ifdef VERBOSE_TRACE\n                    DebugTrace(\"INFO (Streaming): Stitch packet (%u + %u = %u)\\n\", prevFrameStitch, thisFrameStitch, mBlockAlign);\n#endif\n                    #ifdef DIRECTX_ENABLE_XWMA\n                    if (mSeekCount > 0)\n                    {\n                        XAUDIO2_BUFFER_WMA wmaBuf = {};\n                        wmaBuf.pDecodedPacketCumulativeBytes = mSeekTableCopy;\n                        wmaBuf.PacketCount = 1;\n\n                        uint32_t seekOffset = (mPackets[k].startPosition + prevFrameStitchOffset + mPackets[k].audioBytes) / mBlockAlign;\n                        assert(seekOffset > 0);\n                        mSeekTableCopy[0] = mSeekTable[seekOffset] - mSeekTable[seekOffset - 1];\n\n                        ThrowIfFailed(mBase.voice->SubmitSourceBuffer(&buf, &wmaBuf));\n                    }\n                    else\n                    #endif // XWMA\n                    {\n                        ThrowIfFailed(mBase.voice->SubmitSourceBuffer(&buf));\n                    }\n                }\n\n                ptr += thisFrameStitch;\n            }\n\n            // Compute valid audio bytes in our current packet.\n            valid = ((valid - thisFrameStitch) / mBlockAlign) * mBlockAlign;\n        }\n\n        if (valid > 0)\n        {\n            // Record the audioBytes we actually submitted...\n            mPackets[mCurrentPlayBuffer].audioBytes = valid;\n\n            XAUDIO2_BUFFER buf = {};\n            buf.Flags = (endstream) ? XAUDIO2_END_OF_STREAM : 0;\n            buf.AudioBytes = valid;\n            buf.pAudioData = ptr;\n            buf.pContext = &mPackets[mCurrentPlayBuffer].notify;\n\n            #ifdef DIRECTX_ENABLE_XWMA\n            if (mSeekCount > 0)\n            {\n                XAUDIO2_BUFFER_WMA wmaBuf = {};\n\n                wmaBuf.PacketCount = valid / mBlockAlign;\n\n                uint32_t seekOffset = mPackets[mCurrentPlayBuffer].startPosition / mBlockAlign;\n                if (seekOffset > MAX_STREAMING_SEEK_PACKETS)\n                {\n                    DebugTrace(\"ERROR: xWMA packet seek count exceeds %zu\\n\", MAX_STREAMING_SEEK_PACKETS);\n                    return E_FAIL;\n                }\n                else if (seekOffset > 0)\n                {\n                    for (uint32_t i = 0; i < wmaBuf.PacketCount; ++i)\n                    {\n                        mSeekTableCopy[i] = mSeekTable[i + seekOffset] - mSeekTable[seekOffset - 1];\n                    }\n\n                    wmaBuf.pDecodedPacketCumulativeBytes = mSeekTableCopy;\n                }\n                else\n                {\n                    wmaBuf.pDecodedPacketCumulativeBytes = mSeekTable;\n                }\n\n                ThrowIfFailed(mBase.voice->SubmitSourceBuffer(&buf, &wmaBuf));\n            }\n            else\n            #endif // xWMA\n            {\n                ThrowIfFailed(mBase.voice->SubmitSourceBuffer(&buf));\n            }\n        }\n\n        mPackets[mCurrentPlayBuffer].state = State::PLAYING;\n        mCurrentPlayBuffer = (mCurrentPlayBuffer + 1) % uint32_t(MAX_BUFFER_COUNT);\n    }\n\n    return S_OK;\n}\n\n#ifdef VERBOSE_TRACE\nconst wchar_t* SoundStreamInstance::Impl::s_debugState[4] =\n{\n    L\"FREE\",\n    L\"PENDING\",\n    L\"READY\",\n    L\"PLAYING\"\n};\n#endif\n\n\n//--------------------------------------------------------------------------------------\n// SoundStreamInstance\n//--------------------------------------------------------------------------------------\n\n// Private constructors\n_Use_decl_annotations_\nSoundStreamInstance::SoundStreamInstance(AudioEngine* engine, WaveBank* waveBank, unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags) :\n    pImpl(std::make_unique<Impl>(engine, waveBank, index, flags))\n{\n}\n\n\n// Move constructor.\nSoundStreamInstance::SoundStreamInstance(SoundStreamInstance&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nSoundStreamInstance& SoundStreamInstance::operator= (SoundStreamInstance&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nSoundStreamInstance::~SoundStreamInstance()\n{\n    if (pImpl)\n    {\n        if (pImpl->mWaveBank)\n        {\n            pImpl->mWaveBank->UnregisterInstance(pImpl.get());\n            pImpl->mWaveBank = nullptr;\n        }\n    }\n}\n\n\n// Public methods.\nvoid SoundStreamInstance::Play(bool loop)\n{\n    pImpl->Play(loop);\n    pImpl->mPlaying = true;\n}\n\n\nvoid SoundStreamInstance::Stop(bool immediate) noexcept\n{\n    pImpl->mBase.Stop(immediate, pImpl->mLooped);\n    pImpl->mPlaying = !immediate;\n}\n\n\nvoid SoundStreamInstance::Pause() noexcept\n{\n    pImpl->mBase.Pause();\n}\n\n\nvoid SoundStreamInstance::Resume()\n{\n    pImpl->mBase.Resume();\n}\n\n\nvoid SoundStreamInstance::SetVolume(float volume)\n{\n    pImpl->mBase.SetVolume(volume);\n}\n\n\nvoid SoundStreamInstance::SetPitch(float pitch)\n{\n    pImpl->mBase.SetPitch(pitch);\n}\n\n\nvoid SoundStreamInstance::SetPan(float pan)\n{\n    pImpl->mBase.SetPan(pan);\n}\n\n\nvoid SoundStreamInstance::Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords)\n{\n    pImpl->mBase.Apply3D(listener, emitter, rhcoords);\n}\n\n\n// Public accessors.\nbool SoundStreamInstance::IsLooped() const noexcept\n{\n    return pImpl->mLooped;\n}\n\n\nSoundState SoundStreamInstance::GetState() noexcept\n{\n    SoundState state = pImpl->mBase.GetState(pImpl->mEndStream);\n    if (state == STOPPED)\n    {\n        pImpl->mPlaying = false;\n    }\n    return state;\n}\n\n\nIVoiceNotify* SoundStreamInstance::GetVoiceNotify() const noexcept\n{\n    return pImpl.get();\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/WAVFileReader.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: WAVFileReader.cpp\n//\n// Functions for loading WAV audio files\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"PlatformHelpers.h\"\n#include \"WAVFileReader.h\"\n\nusing namespace DirectX;\n\n\nnamespace\n{\n    //---------------------------------------------------------------------------------\n    // .WAV files\n    //---------------------------------------------------------------------------------\n    constexpr uint32_t FOURCC_RIFF_TAG = MAKEFOURCC('R', 'I', 'F', 'F');\n    constexpr uint32_t FOURCC_FORMAT_TAG = MAKEFOURCC('f', 'm', 't', ' ');\n    constexpr uint32_t FOURCC_DATA_TAG = MAKEFOURCC('d', 'a', 't', 'a');\n    constexpr uint32_t FOURCC_WAVE_FILE_TAG = MAKEFOURCC('W', 'A', 'V', 'E');\n    constexpr uint32_t FOURCC_XWMA_FILE_TAG = MAKEFOURCC('X', 'W', 'M', 'A');\n    constexpr uint32_t FOURCC_DLS_SAMPLE = MAKEFOURCC('w', 's', 'm', 'p');\n    constexpr uint32_t FOURCC_MIDI_SAMPLE = MAKEFOURCC('s', 'm', 'p', 'l');\n    constexpr uint32_t FOURCC_XWMA_DPDS = MAKEFOURCC('d', 'p', 'd', 's');\n    constexpr uint32_t FOURCC_XMA_SEEK = MAKEFOURCC('s', 'e', 'e', 'k');\n\n#pragma pack(push,1)\n    struct RIFFChunk\n    {\n        uint32_t tag;\n        uint32_t size;\n    };\n\n    struct RIFFChunkHeader\n    {\n        uint32_t tag;\n        uint32_t size;\n        uint32_t riff;\n    };\n\n    struct DLSLoop\n    {\n        static const uint32_t LOOP_TYPE_FORWARD = 0x00000000;\n        static const uint32_t LOOP_TYPE_RELEASE = 0x00000001;\n\n        uint32_t size;\n        uint32_t loopType;\n        uint32_t loopStart;\n        uint32_t loopLength;\n    };\n\n    struct RIFFDLSSample\n    {\n        static const uint32_t OPTIONS_NOTRUNCATION = 0x00000001;\n        static const uint32_t OPTIONS_NOCOMPRESSION = 0x00000002;\n\n        uint32_t    size;\n        uint16_t    unityNote;\n        int16_t     fineTune;\n        int32_t     gain;\n        uint32_t    options;\n        uint32_t    loopCount;\n    };\n\n    struct MIDILoop\n    {\n        static const uint32_t LOOP_TYPE_FORWARD = 0x00000000;\n        static const uint32_t LOOP_TYPE_ALTERNATING = 0x00000001;\n        static const uint32_t LOOP_TYPE_BACKWARD = 0x00000002;\n\n        uint32_t cuePointId;\n        uint32_t type;\n        uint32_t start;\n        uint32_t end;\n        uint32_t fraction;\n        uint32_t playCount;\n    };\n\n    struct RIFFMIDISample\n    {\n        uint32_t        manufacturerId;\n        uint32_t        productId;\n        uint32_t        samplePeriod;\n        uint32_t        unityNode;\n        uint32_t        pitchFraction;\n        uint32_t        SMPTEFormat;\n        uint32_t        SMPTEOffset;\n        uint32_t        loopCount;\n        uint32_t        samplerData;\n    };\n#pragma pack(pop)\n\n    static_assert(sizeof(RIFFChunk) == 8, \"structure size mismatch\");\n    static_assert(sizeof(RIFFChunkHeader) == 12, \"structure size mismatch\");\n    static_assert(sizeof(DLSLoop) == 16, \"structure size mismatch\");\n    static_assert(sizeof(RIFFDLSSample) == 20, \"structure size mismatch\");\n    static_assert(sizeof(MIDILoop) == 24, \"structure size mismatch\");\n    static_assert(sizeof(RIFFMIDISample) == 36, \"structure size mismatch\");\n\n    //---------------------------------------------------------------------------------\n    const RIFFChunk* FindChunk(\n        _In_reads_bytes_(sizeBytes) const uint8_t* data,\n        _In_ size_t sizeBytes,\n        _In_ uint32_t tag) noexcept\n    {\n        if (!data)\n            return nullptr;\n\n        const uint8_t* ptr = data;\n        const uint8_t* end = data + sizeBytes;\n\n        while (end > (ptr + sizeof(RIFFChunk)))\n        {\n            auto header = reinterpret_cast<const RIFFChunk*>(ptr);\n            if (header->tag == tag)\n                return header;\n\n            auto offset = header->size + sizeof(RIFFChunk);\n            ptr += offset;\n        }\n\n        return nullptr;\n    }\n\n\n    //---------------------------------------------------------------------------------\n    HRESULT WaveFindFormatAndData(\n        _In_reads_bytes_(wavDataSize) const uint8_t* wavData,\n        _In_ size_t wavDataSize,\n        _Outptr_ const WAVEFORMATEX** pwfx,\n        _Outptr_ const uint8_t** pdata,\n        _Out_ uint32_t* dataSize,\n        _Out_ bool& dpds,\n        _Out_ bool& seek) noexcept\n    {\n        if (!wavData || !pwfx)\n            return E_POINTER;\n\n        dpds = seek = false;\n\n        if (wavDataSize < (sizeof(RIFFChunk) * 2 + sizeof(uint32_t) + sizeof(WAVEFORMAT)))\n        {\n            return E_FAIL;\n        }\n\n        const uint8_t* wavEnd = wavData + wavDataSize;\n\n        // Locate RIFF 'WAVE'\n        auto riffChunk = FindChunk(wavData, wavDataSize, FOURCC_RIFF_TAG);\n        if (!riffChunk || riffChunk->size < 4)\n        {\n            return E_FAIL;\n        }\n\n        auto riffHeader = reinterpret_cast<const RIFFChunkHeader*>(riffChunk);\n        if (riffHeader->riff != FOURCC_WAVE_FILE_TAG && riffHeader->riff != FOURCC_XWMA_FILE_TAG)\n        {\n            return E_FAIL;\n        }\n\n        // Locate 'fmt '\n        auto ptr = reinterpret_cast<const uint8_t*>(riffHeader) + sizeof(RIFFChunkHeader);\n        if ((ptr + sizeof(RIFFChunk)) > wavEnd)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        auto fmtChunk = FindChunk(ptr, riffHeader->size, FOURCC_FORMAT_TAG);\n        if (!fmtChunk || fmtChunk->size < sizeof(PCMWAVEFORMAT))\n        {\n            return E_FAIL;\n        }\n\n        ptr = reinterpret_cast<const uint8_t*>(fmtChunk) + sizeof(RIFFChunk);\n        if (ptr + fmtChunk->size > wavEnd)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        auto wf = reinterpret_cast<const WAVEFORMAT*>(ptr);\n\n        // Validate WAVEFORMAT (focused on chunk size and format tag, not other data that XAUDIO2 will validate)\n        switch (wf->wFormatTag)\n        {\n            case WAVE_FORMAT_PCM:\n            case WAVE_FORMAT_IEEE_FLOAT:\n                // Can be a PCMWAVEFORMAT (16 bytes) or WAVEFORMATEX (18 bytes)\n                // We validiated chunk as at least sizeof(PCMWAVEFORMAT) above\n                break;\n\n            default:\n            {\n                if (fmtChunk->size < sizeof(WAVEFORMATEX))\n                {\n                    return E_FAIL;\n                }\n\n                auto wfx = reinterpret_cast<const WAVEFORMATEX*>(ptr);\n\n                if (fmtChunk->size < (sizeof(WAVEFORMATEX) + wfx->cbSize))\n                {\n                    return E_FAIL;\n                }\n\n                switch (wfx->wFormatTag)\n                {\n                    case WAVE_FORMAT_WMAUDIO2:\n                    case WAVE_FORMAT_WMAUDIO3:\n                        dpds = true;\n                        break;\n\n                    case  0x166 /*WAVE_FORMAT_XMA2*/: // XMA2 is supported by Xbox One\n                        if ((fmtChunk->size < 52 /*sizeof(XMA2WAVEFORMATEX)*/) || (wfx->cbSize < 34 /*( sizeof(XMA2WAVEFORMATEX) - sizeof(WAVEFORMATEX) )*/))\n                        {\n                            return E_FAIL;\n                        }\n                        seek = true;\n                        break;\n\n                    case WAVE_FORMAT_ADPCM:\n                        if ((fmtChunk->size < (sizeof(WAVEFORMATEX) + 32)) || (wfx->cbSize < 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/))\n                        {\n                            return E_FAIL;\n                        }\n                        break;\n\n                    case WAVE_FORMAT_EXTENSIBLE:\n                        if ((fmtChunk->size < sizeof(WAVEFORMATEXTENSIBLE)) || (wfx->cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))))\n                        {\n                            return E_FAIL;\n                        }\n                        else\n                        {\n                            static const GUID s_wfexBase = { 0x00000000, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 } };\n\n                            auto wfex = reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(ptr);\n\n                            if (memcmp(reinterpret_cast<const BYTE*>(&wfex->SubFormat) + sizeof(DWORD),\n                                reinterpret_cast<const BYTE*>(&s_wfexBase) + sizeof(DWORD), sizeof(GUID) - sizeof(DWORD)) != 0)\n                            {\n                                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                            }\n\n                            switch (wfex->SubFormat.Data1)\n                            {\n                                case WAVE_FORMAT_PCM:\n                                case WAVE_FORMAT_IEEE_FLOAT:\n                                    break;\n\n                                // MS-ADPCM and XMA2 are not supported as WAVEFORMATEXTENSIBLE\n\n                                case WAVE_FORMAT_WMAUDIO2:\n                                case WAVE_FORMAT_WMAUDIO3:\n                                    dpds = true;\n                                    break;\n\n                                default:\n                                    return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                            }\n\n                        }\n                        break;\n\n                    default:\n                        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                }\n            }\n        }\n\n        // Locate 'data'\n        ptr = reinterpret_cast<const uint8_t*>(riffHeader) + sizeof(RIFFChunkHeader);\n        if ((ptr + sizeof(RIFFChunk)) > wavEnd)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        auto dataChunk = FindChunk(ptr, riffChunk->size, FOURCC_DATA_TAG);\n        if (!dataChunk || !dataChunk->size)\n        {\n            return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n        }\n\n        ptr = reinterpret_cast<const uint8_t*>(dataChunk) + sizeof(RIFFChunk);\n        if (ptr + dataChunk->size > wavEnd)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        *pwfx = reinterpret_cast<const WAVEFORMATEX*>(wf);\n        *pdata = ptr;\n        *dataSize = dataChunk->size;\n        return S_OK;\n    }\n\n\n    //---------------------------------------------------------------------------------\n    HRESULT WaveFindLoopInfo(\n        _In_reads_bytes_(wavDataSize) const uint8_t* wavData,\n        _In_ size_t wavDataSize,\n        _Out_ uint32_t* pLoopStart,\n        _Out_ uint32_t* pLoopLength) noexcept\n    {\n        if (!wavData || !pLoopStart || !pLoopLength)\n            return E_POINTER;\n\n        if (wavDataSize < (sizeof(RIFFChunk) + sizeof(uint32_t)))\n        {\n            return E_FAIL;\n        }\n\n        *pLoopStart = 0;\n        *pLoopLength = 0;\n\n        const uint8_t* wavEnd = wavData + wavDataSize;\n\n        // Locate RIFF 'WAVE'\n        auto riffChunk = FindChunk(wavData, wavDataSize, FOURCC_RIFF_TAG);\n        if (!riffChunk || riffChunk->size < 4)\n        {\n            return E_FAIL;\n        }\n\n        auto riffHeader = reinterpret_cast<const RIFFChunkHeader*>(riffChunk);\n        if (riffHeader->riff == FOURCC_XWMA_FILE_TAG)\n        {\n            // xWMA files do not contain loop information\n            return S_OK;\n        }\n\n        if (riffHeader->riff != FOURCC_WAVE_FILE_TAG)\n        {\n            return E_FAIL;\n        }\n\n        // Locate 'wsmp' (DLS Chunk)\n        auto ptr = reinterpret_cast<const uint8_t*>(riffHeader) + sizeof(RIFFChunkHeader);\n        if ((ptr + sizeof(RIFFChunk)) > wavEnd)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        auto dlsChunk = FindChunk(ptr, riffChunk->size, FOURCC_DLS_SAMPLE);\n        if (dlsChunk)\n        {\n            ptr = reinterpret_cast<const uint8_t*>(dlsChunk) + sizeof(RIFFChunk);\n            if (ptr + dlsChunk->size > wavEnd)\n            {\n                return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n            }\n\n            if (dlsChunk->size >= sizeof(RIFFDLSSample))\n            {\n                auto dlsSample = reinterpret_cast<const RIFFDLSSample*>(ptr);\n\n                if (dlsChunk->size >= (dlsSample->size + dlsSample->loopCount * sizeof(DLSLoop)))\n                {\n                    auto loops = reinterpret_cast<const DLSLoop*>(ptr + dlsSample->size);\n                    for (uint32_t j = 0; j < dlsSample->loopCount; ++j)\n                    {\n                        if ((loops[j].loopType == DLSLoop::LOOP_TYPE_FORWARD || loops[j].loopType == DLSLoop::LOOP_TYPE_RELEASE))\n                        {\n                            // Return 'forward' loop\n                            *pLoopStart = loops[j].loopStart;\n                            *pLoopLength = loops[j].loopLength;\n                            return S_OK;\n                        }\n                    }\n                }\n            }\n        }\n\n        // Locate 'smpl' (Sample Chunk)\n        auto midiChunk = FindChunk(ptr, riffChunk->size, FOURCC_MIDI_SAMPLE);\n        if (midiChunk)\n        {\n            ptr = reinterpret_cast<const uint8_t*>(midiChunk) + sizeof(RIFFChunk);\n            if (ptr + midiChunk->size > wavEnd)\n            {\n                return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n            }\n\n            if (midiChunk->size >= sizeof(RIFFMIDISample))\n            {\n                auto midiSample = reinterpret_cast<const RIFFMIDISample*>(ptr);\n\n                if (midiChunk->size >= (sizeof(RIFFMIDISample) + midiSample->loopCount * sizeof(MIDILoop)))\n                {\n                    auto loops = reinterpret_cast<const MIDILoop*>(ptr + sizeof(RIFFMIDISample));\n                    for (uint32_t j = 0; j < midiSample->loopCount; ++j)\n                    {\n                        if (loops[j].type == MIDILoop::LOOP_TYPE_FORWARD)\n                        {\n                            // Return 'forward' loop\n                            *pLoopStart = loops[j].start;\n                            *pLoopLength = loops[j].end + loops[j].start + 1;\n                            return S_OK;\n                        }\n                    }\n                }\n            }\n        }\n\n        return S_OK;\n    }\n\n\n    //---------------------------------------------------------------------------------\n    HRESULT WaveFindTable(\n        _In_reads_bytes_(wavDataSize) const uint8_t* wavData,\n        _In_ size_t wavDataSize,\n        _In_ uint32_t tag,\n        _Outptr_result_maybenull_ const uint32_t** pData,\n        _Out_ uint32_t* dataCount) noexcept\n    {\n        if (!wavData || !pData || !dataCount)\n            return E_POINTER;\n\n        if (wavDataSize < (sizeof(RIFFChunk) + sizeof(uint32_t)))\n        {\n            return E_FAIL;\n        }\n\n        *pData = nullptr;\n        *dataCount = 0;\n\n        const uint8_t* wavEnd = wavData + wavDataSize;\n\n        // Locate RIFF 'WAVE'\n        auto riffChunk = FindChunk(wavData, wavDataSize, FOURCC_RIFF_TAG);\n        if (!riffChunk || riffChunk->size < 4)\n        {\n            return E_FAIL;\n        }\n\n        auto riffHeader = reinterpret_cast<const RIFFChunkHeader*>(riffChunk);\n        if (riffHeader->riff != FOURCC_WAVE_FILE_TAG && riffHeader->riff != FOURCC_XWMA_FILE_TAG)\n        {\n            return E_FAIL;\n        }\n\n        // Locate tag\n        auto ptr = reinterpret_cast<const uint8_t*>(riffHeader) + sizeof(RIFFChunkHeader);\n        if ((ptr + sizeof(RIFFChunk)) > wavEnd)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        auto tableChunk = FindChunk(ptr, riffChunk->size, tag);\n        if (tableChunk)\n        {\n            ptr = reinterpret_cast<const uint8_t*>(tableChunk) + sizeof(RIFFChunk);\n            if (ptr + tableChunk->size > wavEnd)\n            {\n                return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n            }\n\n            if ((tableChunk->size % sizeof(uint32_t)) != 0)\n            {\n                return E_FAIL;\n            }\n\n            *pData = reinterpret_cast<const uint32_t*>(ptr);\n            *dataCount = tableChunk->size / 4;\n        }\n\n        return S_OK;\n    }\n\n\n    //---------------------------------------------------------------------------------\n    HRESULT LoadAudioFromFile(\n        _In_z_ const wchar_t* szFileName,\n        _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n        _Out_ DWORD* bytesRead) noexcept\n    {\n        if (!szFileName)\n            return E_INVALIDARG;\n\n        // open the file\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n        ScopedHandle hFile(safe_handle(CreateFile2(szFileName,\n            GENERIC_READ,\n            FILE_SHARE_READ,\n            OPEN_EXISTING,\n            nullptr)));\n    #else\n        ScopedHandle hFile(safe_handle(CreateFileW(szFileName,\n            GENERIC_READ,\n            FILE_SHARE_READ,\n            nullptr,\n            OPEN_EXISTING,\n            FILE_ATTRIBUTE_NORMAL,\n            nullptr)));\n    #endif\n\n        if (!hFile)\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        // Get the file size\n        FILE_STANDARD_INFO fileInfo;\n        if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        // File is too big for 32-bit allocation, so reject read\n        if (fileInfo.EndOfFile.HighPart > 0)\n        {\n            return E_FAIL;\n        }\n\n        // Need at least enough data to have a valid minimal WAV file\n        if (fileInfo.EndOfFile.LowPart < (sizeof(RIFFChunk) * 2 + sizeof(DWORD) + sizeof(WAVEFORMAT)))\n        {\n            return E_FAIL;\n        }\n\n        // create enough space for the file data\n        wavData.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);\n        if (!wavData)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n        // read the data in\n        if (!ReadFile(hFile.get(),\n            wavData.get(),\n            fileInfo.EndOfFile.LowPart,\n            bytesRead,\n            nullptr\n            ))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        return (*bytesRead < fileInfo.EndOfFile.LowPart) ? E_FAIL : S_OK;\n    }\n}\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWAVAudioInMemory(\n    const uint8_t* wavData,\n    size_t wavDataSize,\n    const WAVEFORMATEX** wfx,\n    const uint8_t** startAudio,\n    uint32_t* audioBytes) noexcept\n{\n    if (!wavData || !wfx || !startAudio || !audioBytes)\n        return E_INVALIDARG;\n\n    *wfx = nullptr;\n    *startAudio = nullptr;\n    *audioBytes = 0;\n\n    // Need at least enough data to have a valid minimal WAV file\n    if (wavDataSize < (sizeof(RIFFChunk) * 2 + sizeof(DWORD) + sizeof(WAVEFORMAT)))\n    {\n        return E_FAIL;\n    }\n\n    bool dpds, seek;\n    HRESULT hr = WaveFindFormatAndData(wavData, wavDataSize, wfx, startAudio, audioBytes, dpds, seek);\n    if (FAILED(hr))\n        return hr;\n\n    return (dpds || seek) ? E_FAIL : S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWAVAudioFromFile(\n    const wchar_t* szFileName,\n    std::unique_ptr<uint8_t[]>& wavData,\n    const WAVEFORMATEX** wfx,\n    const uint8_t** startAudio,\n    uint32_t* audioBytes) noexcept\n{\n    if (!szFileName || !wfx || !startAudio || !audioBytes)\n        return E_INVALIDARG;\n\n    *wfx = nullptr;\n    *startAudio = nullptr;\n    *audioBytes = 0;\n\n    DWORD bytesRead = 0;\n    HRESULT hr = LoadAudioFromFile(szFileName, wavData, &bytesRead);\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    bool dpds, seek;\n    hr = WaveFindFormatAndData(wavData.get(), bytesRead, wfx, startAudio, audioBytes, dpds, seek);\n    if (FAILED(hr))\n        return hr;\n\n    return (dpds || seek) ? E_FAIL : S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWAVAudioInMemoryEx(\n    const uint8_t* wavData,\n    size_t wavDataSize,\n    DirectX::WAVData& result) noexcept\n{\n    if (!wavData)\n        return E_INVALIDARG;\n\n    memset(&result, 0, sizeof(result));\n\n    // Need at least enough data to have a valid minimal WAV file\n    if (wavDataSize < (sizeof(RIFFChunk) * 2 + sizeof(DWORD) + sizeof(WAVEFORMAT)))\n    {\n        return E_FAIL;\n    }\n\n    bool dpds, seek;\n    HRESULT hr = WaveFindFormatAndData(wavData, wavDataSize, &result.wfx, &result.startAudio, &result.audioBytes, dpds, seek);\n    if (FAILED(hr))\n        return hr;\n\n    hr = WaveFindLoopInfo(wavData, wavDataSize, &result.loopStart, &result.loopLength);\n    if (FAILED(hr))\n        return hr;\n\n    if (dpds)\n    {\n        hr = WaveFindTable(wavData, wavDataSize, FOURCC_XWMA_DPDS, &result.seek, &result.seekCount);\n        if (FAILED(hr))\n            return hr;\n    }\n    else if (seek)\n    {\n        hr = WaveFindTable(wavData, wavDataSize, FOURCC_XMA_SEEK, &result.seek, &result.seekCount);\n        if (FAILED(hr))\n            return hr;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWAVAudioFromFileEx(\n    const wchar_t* szFileName,\n    std::unique_ptr<uint8_t[]>& wavData,\n    DirectX::WAVData& result) noexcept\n{\n    if (!szFileName)\n        return E_INVALIDARG;\n\n    memset(&result, 0, sizeof(result));\n\n    DWORD bytesRead = 0;\n    HRESULT hr = LoadAudioFromFile(szFileName, wavData, &bytesRead);\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    bool dpds, seek;\n    hr = WaveFindFormatAndData(wavData.get(), bytesRead, &result.wfx, &result.startAudio, &result.audioBytes, dpds, seek);\n    if (FAILED(hr))\n        return hr;\n\n    hr = WaveFindLoopInfo(wavData.get(), bytesRead, &result.loopStart, &result.loopLength);\n    if (FAILED(hr))\n        return hr;\n\n    if (dpds)\n    {\n        hr = WaveFindTable(wavData.get(), bytesRead, FOURCC_XWMA_DPDS, &result.seek, &result.seekCount);\n        if (FAILED(hr))\n            return hr;\n    }\n    else if (seek)\n    {\n        hr = WaveFindTable(wavData.get(), bytesRead, FOURCC_XMA_SEEK, &result.seek, &result.seekCount);\n        if (FAILED(hr))\n            return hr;\n    }\n\n    return S_OK;\n}\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/WAVFileReader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: WAVFileReader.h\n//\n// Functions for loading WAV audio files\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <objbase.h>\n\n#include <cstdint>\n#include <memory>\n#include <mmreg.h>\n\n\nnamespace DirectX\n{\n    HRESULT LoadWAVAudioInMemory(\n        _In_reads_bytes_(wavDataSize) const uint8_t* wavData,\n        _In_ size_t wavDataSize,\n        _Outptr_ const WAVEFORMATEX** wfx,\n        _Outptr_ const uint8_t** startAudio,\n        _Out_ uint32_t* audioBytes) noexcept;\n\n    HRESULT LoadWAVAudioFromFile(\n        _In_z_ const wchar_t* szFileName,\n        _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n        _Outptr_ const WAVEFORMATEX** wfx,\n        _Outptr_ const uint8_t** startAudio,\n        _Out_ uint32_t* audioBytes) noexcept;\n\n    struct WAVData\n    {\n        const WAVEFORMATEX* wfx;\n        const uint8_t* startAudio;\n        uint32_t audioBytes;\n        uint32_t loopStart;\n        uint32_t loopLength;\n        const uint32_t* seek;       // Note: XMA Seek data is Big-Endian\n        uint32_t seekCount;\n    };\n\n    HRESULT LoadWAVAudioInMemoryEx(\n        _In_reads_bytes_(wavDataSize) const uint8_t* wavData,\n        _In_ size_t wavDataSize,\n        _Out_ WAVData& result) noexcept;\n\n    HRESULT LoadWAVAudioFromFileEx(\n        _In_z_ const wchar_t* szFileName,\n        _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n        _Out_ WAVData& result) noexcept;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/WaveBank.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: WaveBank.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Audio.h\"\n#include \"WaveBankReader.h\"\n#include \"SoundCommon.h\"\n#include \"PlatformHelpers.h\"\n\n#include <list>\n\nusing namespace DirectX;\n\n\n//======================================================================================\n// WaveBank\n//======================================================================================\n\n// Internal object implementation class.\nclass WaveBank::Impl : public IVoiceNotify\n{\npublic:\n    explicit Impl(_In_ AudioEngine* engine) :\n        mEngine(engine),\n        mOneShots(0),\n        mPrepared(false),\n        mStreaming(false)\n    {\n        assert(mEngine != nullptr);\n        mEngine->RegisterNotify(this, false);\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl() override\n    {\n        if (!mInstances.empty())\n        {\n            DebugTrace(\"WARNING: Destroying WaveBank \\\"%hs\\\" with %zu outstanding instances\\n\",\n                mReader.BankName(), mInstances.size());\n\n            for (auto it = mInstances.begin(); it != mInstances.end(); ++it)\n            {\n                assert(*it != nullptr);\n                (*it)->OnDestroyParent();\n            }\n\n            mInstances.clear();\n        }\n\n        if (mOneShots > 0)\n        {\n            DebugTrace(\"WARNING: Destroying WaveBank \\\"%hs\\\" with %u outstanding one shot effects\\n\",\n                mReader.BankName(), mOneShots);\n        }\n\n        if (mEngine)\n        {\n            mEngine->UnregisterNotify(this, true, false);\n            mEngine = nullptr;\n        }\n    }\n\n    HRESULT Initialize(_In_ AudioEngine* engine, _In_z_ const wchar_t* wbFileName) noexcept;\n\n    void Play(unsigned int index, float volume, float pitch, float pan);\n\n    // IVoiceNotify\n    void __cdecl OnBufferEnd() override\n    {\n        InterlockedDecrement(&mOneShots);\n    }\n\n    void __cdecl OnCriticalError() override\n    {\n        mOneShots = 0;\n    }\n\n    void __cdecl OnReset() override\n    {\n        // No action required\n    }\n\n    void __cdecl OnUpdate() override\n    {\n        // We do not register for update notification\n        assert(false);\n    }\n\n    void __cdecl OnDestroyEngine() noexcept override\n    {\n        mEngine = nullptr;\n        mOneShots = 0;\n    }\n\n    void __cdecl OnTrim() override\n    {\n        // No action required\n    }\n\n    void __cdecl GatherStatistics(AudioStatistics& stats) const noexcept override\n    {\n        stats.playingOneShots += mOneShots;\n\n        if (!mStreaming)\n        {\n            stats.audioBytes += mReader.BankAudioSize();\n\n        #ifdef DIRECTX_ENABLE_XMA2\n            if (mReader.HasXMA())\n                stats.xmaAudioBytes += mReader.BankAudioSize();\n        #endif\n        }\n    }\n\n    void __cdecl OnDestroyParent() noexcept override\n    {\n    }\n\n    AudioEngine*                        mEngine;\n    std::list<IVoiceNotify*>            mInstances;\n    WaveBankReader                      mReader;\n    uint32_t                            mOneShots;\n    bool                                mPrepared;\n    bool                                mStreaming;\n};\n\n\n_Use_decl_annotations_\nHRESULT WaveBank::Impl::Initialize(AudioEngine* engine, const wchar_t* wbFileName) noexcept\n{\n    if (!engine || !wbFileName)\n        return E_INVALIDARG;\n\n    HRESULT hr = mReader.Open(wbFileName);\n    if (FAILED(hr))\n        return hr;\n\n    mStreaming = mReader.IsStreamingBank();\n\n    return S_OK;\n}\n\n\nvoid WaveBank::Impl::Play(unsigned int index, float volume, float pitch, float pan)\n{\n    assert(volume >= -XAUDIO2_MAX_VOLUME_LEVEL && volume <= XAUDIO2_MAX_VOLUME_LEVEL);\n    assert(pitch >= -1.f && pitch <= 1.f);\n    assert(pan >= -1.f && pan <= 1.f);\n\n    if (mStreaming)\n    {\n        DebugTrace(\"ERROR: One-shots can only be created from an in-memory wave bank\\n\");\n        throw std::exception(\"WaveBank::Play\");\n    }\n\n    if (index >= mReader.Count())\n    {\n        DebugTrace(\"WARNING: Index %u not found in wave bank with only %u entries, one-shot not triggered\\n\",\n            index, mReader.Count());\n        return;\n    }\n\n    if (!mPrepared)\n    {\n        mReader.WaitOnPrepare();\n        mPrepared = true;\n    }\n\n    char wfxbuff[64] = {};\n    auto wfx = reinterpret_cast<WAVEFORMATEX*>(wfxbuff);\n    HRESULT hr = mReader.GetFormat(index, wfx, sizeof(wfxbuff));\n    ThrowIfFailed(hr);\n\n    IXAudio2SourceVoice* voice = nullptr;\n    mEngine->AllocateVoice(wfx, SoundEffectInstance_Default, true, &voice);\n\n    if (!voice)\n        return;\n\n    if (volume != 1.f)\n    {\n        hr = voice->SetVolume(volume);\n        ThrowIfFailed(hr);\n    }\n\n    if (pitch != 0.f)\n    {\n        float fr = XAudio2SemitonesToFrequencyRatio(pitch * 12.f);\n\n        hr = voice->SetFrequencyRatio(fr);\n        ThrowIfFailed(hr);\n    }\n\n    if (pan != 0.f)\n    {\n        float matrix[16];\n        if (ComputePan(pan, wfx->nChannels, matrix))\n        {\n            hr = voice->SetOutputMatrix(nullptr, wfx->nChannels, mEngine->GetOutputChannels(), matrix);\n            ThrowIfFailed(hr);\n        }\n    }\n\n    hr = voice->Start(0);\n    ThrowIfFailed(hr);\n\n    XAUDIO2_BUFFER buffer = {};\n    hr = mReader.GetWaveData(index, &buffer.pAudioData, buffer.AudioBytes);\n    ThrowIfFailed(hr);\n\n    WaveBankReader::Metadata metadata;\n    hr = mReader.GetMetadata(index, metadata);\n    ThrowIfFailed(hr);\n\n    buffer.Flags = XAUDIO2_END_OF_STREAM;\n    buffer.pContext = this;\n\n    #ifdef DIRECTX_ENABLE_XWMA\n\n    XAUDIO2_BUFFER_WMA wmaBuffer = {};\n\n    uint32_t tag;\n    hr = mReader.GetSeekTable(index, &wmaBuffer.pDecodedPacketCumulativeBytes, wmaBuffer.PacketCount, tag);\n    ThrowIfFailed(hr);\n\n    if (tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3)\n    {\n        hr = voice->SubmitSourceBuffer(&buffer, &wmaBuffer);\n    }\n    else\n    #endif // xWMA\n    {\n        hr = voice->SubmitSourceBuffer(&buffer, nullptr);\n    }\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: WaveBank failed (%08X) when submitting buffer:\\n\", static_cast<unsigned int>(hr));\n        DebugTrace(\"\\tFormat Tag %u, %u channels, %u-bit, %u Hz, %u bytes\\n\",\n            wfx->wFormatTag, wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec, metadata.lengthBytes);\n        throw std::exception(\"SubmitSourceBuffer\");\n    }\n\n    InterlockedIncrement(&mOneShots);\n}\n\n\n//--------------------------------------------------------------------------------------\n// WaveBank\n//--------------------------------------------------------------------------------------\n\n// Public constructors.\n_Use_decl_annotations_\nWaveBank::WaveBank(AudioEngine* engine, const wchar_t* wbFileName)\n    : pImpl(std::make_unique<Impl>(engine))\n{\n    HRESULT hr = pImpl->Initialize(engine, wbFileName);\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: WaveBank failed (%08X) to intialize from .xwb file \\\"%ls\\\"\\n\",\n            static_cast<unsigned int>(hr), wbFileName);\n        throw std::exception(\"WaveBank\");\n    }\n\n    DebugTrace(\"INFO: WaveBank \\\"%hs\\\" with %u entries loaded from .xwb file \\\"%ls\\\"\\n\",\n               pImpl->mReader.BankName(), pImpl->mReader.Count(), wbFileName);\n}\n\n\n// Move constructor.\nWaveBank::WaveBank(WaveBank&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nWaveBank& WaveBank::operator= (WaveBank&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nWaveBank::~WaveBank()\n{\n}\n\n\n// Public methods (one-shots)\nvoid WaveBank::Play(unsigned int index)\n{\n    pImpl->Play(index, 1.f, 0.f, 0.f);\n}\n\n\nvoid WaveBank::Play(unsigned int index, float volume, float pitch, float pan)\n{\n    pImpl->Play(index, volume, pitch, pan);\n}\n\n\nvoid WaveBank::Play(_In_z_ const char* name)\n{\n    unsigned int index = pImpl->mReader.Find(name);\n    if (index == unsigned(-1))\n    {\n        DebugTrace(\"WARNING: Name '%hs' not found in wave bank, one-shot not triggered\\n\", name);\n        return;\n    }\n\n    pImpl->Play(index, 1.f, 0.f, 0.f);\n}\n\n\nvoid WaveBank::Play(_In_z_ const char* name, float volume, float pitch, float pan)\n{\n    unsigned int index = pImpl->mReader.Find(name);\n    if (index == unsigned(-1))\n    {\n        DebugTrace(\"WARNING: Name '%hs' not found in wave bank, one-shot not triggered\\n\", name);\n        return;\n    }\n\n    pImpl->Play(index, volume, pitch, pan);\n}\n\n\n// Public methods (sound effect instance)\nstd::unique_ptr<SoundEffectInstance> WaveBank::CreateInstance(unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags)\n{\n    auto& wb = pImpl->mReader;\n\n    if (pImpl->mStreaming)\n    {\n        DebugTrace(\"ERROR: SoundEffectInstances can only be created from an in-memory wave bank\\n\");\n        throw std::exception(\"WaveBank::CreateInstance\");\n    }\n\n    if (index >= wb.Count())\n    {\n        // We don't throw an exception here as titles often simply ignore missing assets rather than fail\n        return std::unique_ptr<SoundEffectInstance>();\n    }\n\n    if (!pImpl->mPrepared)\n    {\n        wb.WaitOnPrepare();\n        pImpl->mPrepared = true;\n    }\n\n    auto effect = new SoundEffectInstance(pImpl->mEngine, this, index, flags);\n    assert(effect != nullptr);\n    pImpl->mInstances.emplace_back(effect->GetVoiceNotify());\n    return std::unique_ptr<SoundEffectInstance>(effect);\n}\n\n\nstd::unique_ptr<SoundEffectInstance> WaveBank::CreateInstance(_In_z_ const char* name, SOUND_EFFECT_INSTANCE_FLAGS flags)\n{\n    unsigned int index = pImpl->mReader.Find(name);\n    if (index == unsigned(-1))\n    {\n        // We don't throw an exception here as titles often simply ignore missing assets rather than fail\n        return std::unique_ptr<SoundEffectInstance>();\n    }\n\n    return CreateInstance(index, flags);\n}\n\n\n// Public methods (sound stream instance)\nstd::unique_ptr<SoundStreamInstance> WaveBank::CreateStreamInstance(unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags)\n{\n    auto& wb = pImpl->mReader;\n\n    if (!pImpl->mStreaming)\n    {\n        DebugTrace(\"ERROR: SoundStreamInstances can only be created from a streaming wave bank\\n\");\n        throw std::exception(\"WaveBank::CreateStreamInstance\");\n    }\n\n    if (index >= wb.Count())\n    {\n        // We don't throw an exception here as titles often simply ignore missing assets rather than fail\n        return std::unique_ptr<SoundStreamInstance>();\n    }\n\n    if (!pImpl->mPrepared)\n    {\n        wb.WaitOnPrepare();\n        pImpl->mPrepared = true;\n    }\n\n    auto effect = new SoundStreamInstance(pImpl->mEngine, this, index, flags);\n    assert(effect != nullptr);\n    pImpl->mInstances.emplace_back(effect->GetVoiceNotify());\n    return std::unique_ptr<SoundStreamInstance>(effect);\n}\n\n\nstd::unique_ptr<SoundStreamInstance> WaveBank::CreateStreamInstance(_In_z_ const char* name, SOUND_EFFECT_INSTANCE_FLAGS flags)\n{\n    unsigned int index = pImpl->mReader.Find(name);\n    if (index == unsigned(-1))\n    {\n        // We don't throw an exception here as titles often simply ignore missing assets rather than fail\n        return std::unique_ptr<SoundStreamInstance>();\n    }\n\n    return CreateStreamInstance(index, flags);\n}\n\n\nvoid WaveBank::UnregisterInstance(_In_ IVoiceNotify* instance)\n{\n    auto it = std::find(pImpl->mInstances.begin(), pImpl->mInstances.end(), instance);\n    if (it == pImpl->mInstances.end())\n        return;\n\n    pImpl->mInstances.erase(it);\n}\n\n\n// Public accessors.\nbool WaveBank::IsPrepared() const noexcept\n{\n    if (pImpl->mPrepared)\n        return true;\n\n    if (!pImpl->mReader.IsPrepared())\n        return false;\n\n    pImpl->mPrepared = true;\n    return true;\n}\n\n\nbool WaveBank::IsInUse() const noexcept\n{\n    return (pImpl->mOneShots > 0) || !pImpl->mInstances.empty();\n}\n\n\nbool WaveBank::IsStreamingBank() const noexcept\n{\n    return pImpl->mReader.IsStreamingBank();\n}\n\n\nsize_t WaveBank::GetSampleSizeInBytes(unsigned int index) const noexcept\n{\n    if (index >= pImpl->mReader.Count())\n        return 0;\n\n    WaveBankReader::Metadata metadata;\n    HRESULT hr = pImpl->mReader.GetMetadata(index, metadata);\n    if (FAILED(hr))\n        return 0;\n\n    return metadata.lengthBytes;\n}\n\n\nsize_t WaveBank::GetSampleDuration(unsigned int index) const noexcept\n{\n    if (index >= pImpl->mReader.Count())\n        return 0;\n\n    WaveBankReader::Metadata metadata;\n    HRESULT hr = pImpl->mReader.GetMetadata(index, metadata);\n    if (FAILED(hr))\n        return 0;\n\n    return metadata.duration;\n}\n\n\nsize_t WaveBank::GetSampleDurationMS(unsigned int index) const noexcept\n{\n    if (index >= pImpl->mReader.Count())\n        return 0;\n\n    char buff[64] = {};\n    auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);\n    HRESULT hr = pImpl->mReader.GetFormat(index, wfx, sizeof(buff));\n    if (FAILED(hr))\n        return 0;\n\n    WaveBankReader::Metadata metadata;\n    hr = pImpl->mReader.GetMetadata(index, metadata);\n    if (FAILED(hr))\n        return 0;\n\n    return static_cast<size_t>((uint64_t(metadata.duration) * 1000) / wfx->nSamplesPerSec);\n}\n\n\n_Use_decl_annotations_\nconst WAVEFORMATEX* WaveBank::GetFormat(unsigned int index, WAVEFORMATEX* wfx, size_t maxsize) const noexcept\n{\n    if (index >= pImpl->mReader.Count())\n        return nullptr;\n\n    HRESULT hr = pImpl->mReader.GetFormat(index, wfx, maxsize);\n    if (FAILED(hr))\n        return nullptr;\n\n    return wfx;\n}\n\n\n_Use_decl_annotations_\nint WaveBank::Find(const char* name) const\n{\n    return static_cast<int>(pImpl->mReader.Find(name));\n}\n\n\n#ifdef DIRECTX_ENABLE_XWMA\n\n_Use_decl_annotations_\nbool WaveBank::FillSubmitBuffer(unsigned int index, XAUDIO2_BUFFER& buffer, XAUDIO2_BUFFER_WMA& wmaBuffer) const\n{\n    memset(&buffer, 0, sizeof(buffer));\n    memset(&wmaBuffer, 0, sizeof(wmaBuffer));\n\n    HRESULT hr = pImpl->mReader.GetWaveData(index, &buffer.pAudioData, buffer.AudioBytes);\n    ThrowIfFailed(hr);\n\n    WaveBankReader::Metadata metadata;\n    hr = pImpl->mReader.GetMetadata(index, metadata);\n    ThrowIfFailed(hr);\n\n    buffer.LoopBegin = metadata.loopStart;\n    buffer.LoopLength = metadata.loopLength;\n\n    uint32_t tag;\n    hr = pImpl->mReader.GetSeekTable(index, &wmaBuffer.pDecodedPacketCumulativeBytes, wmaBuffer.PacketCount, tag);\n    ThrowIfFailed(hr);\n\n    return (tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3);\n}\n\n#else // !xWMA\n\n_Use_decl_annotations_\nvoid WaveBank::FillSubmitBuffer(unsigned int index, XAUDIO2_BUFFER& buffer) const\n{\n    memset(&buffer, 0, sizeof(buffer));\n\n    HRESULT hr = pImpl->mReader.GetWaveData(index, &buffer.pAudioData, buffer.AudioBytes);\n    ThrowIfFailed(hr);\n\n    WaveBankReader::Metadata metadata;\n    hr = pImpl->mReader.GetMetadata(index, metadata);\n    ThrowIfFailed(hr);\n\n    buffer.LoopBegin = metadata.loopStart;\n    buffer.LoopLength = metadata.loopLength;\n}\n\n#endif\n\n\nHANDLE WaveBank::GetAsyncHandle() const noexcept\n{\n    if (pImpl)\n    {\n        return pImpl->mReader.GetAsyncHandle();\n    }\n\n    return nullptr;\n}\n\n\n_Use_decl_annotations_\nbool WaveBank::GetPrivateData(unsigned int index, void* data, size_t datasize)\n{\n    if (index >= pImpl->mReader.Count())\n        return false;\n\n    if (!data)\n        return false;\n\n    switch (datasize)\n    {\n        case sizeof(WaveBankReader::Metadata):\n        {\n            auto ptr = reinterpret_cast<WaveBankReader::Metadata*>(data);\n            return SUCCEEDED(pImpl->mReader.GetMetadata(index, *ptr));\n        }\n\n        case sizeof(WaveBankSeekData):\n        {\n            auto ptr = reinterpret_cast<WaveBankSeekData*>(data);\n            return SUCCEEDED(pImpl->mReader.GetSeekTable(index, &ptr->seekTable, ptr->seekCount, ptr->tag));\n        }\n\n        default:\n            return false;\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/WaveBankReader.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: WaveBankReader.cpp\n//\n// Functions for loading audio data from Wave Banks\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"WaveBankReader.h\"\n#include \"Audio.h\"\n#include \"PlatformHelpers.h\"\n#include \"SoundCommon.h\"\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <apu.h>\n#include <shapexmacontext.h>\n#endif\n\n\nnamespace\n{\n#pragma pack(push, 1)\n\n    constexpr size_t DVD_SECTOR_SIZE = 2048;\n    constexpr size_t DVD_BLOCK_SIZE = DVD_SECTOR_SIZE * 16;\n\n    constexpr size_t ALIGNMENT_MIN = 4;\n    constexpr size_t ALIGNMENT_DVD = DVD_SECTOR_SIZE;\n\n    constexpr size_t MAX_DATA_SEGMENT_SIZE = 0xFFFFFFFF;\n    constexpr size_t MAX_COMPACT_DATA_SEGMENT_SIZE = 0x001FFFFF;\n\n    struct REGION\n    {\n        uint32_t    dwOffset;   // Region offset, in bytes.\n        uint32_t    dwLength;   // Region length, in bytes.\n\n        void BigEndian() noexcept\n        {\n            dwOffset = _byteswap_ulong(dwOffset);\n            dwLength = _byteswap_ulong(dwLength);\n        }\n    };\n\n    struct SAMPLEREGION\n    {\n        uint32_t    dwStartSample;  // Start sample for the region.\n        uint32_t    dwTotalSamples; // Region length in samples.\n\n        void BigEndian() noexcept\n        {\n            dwStartSample = _byteswap_ulong(dwStartSample);\n            dwTotalSamples = _byteswap_ulong(dwTotalSamples);\n        }\n    };\n\n    struct HEADER\n    {\n        static const uint32_t SIGNATURE = MAKEFOURCC('W', 'B', 'N', 'D');\n        static const uint32_t BE_SIGNATURE = MAKEFOURCC('D', 'N', 'B', 'W');\n        static const uint32_t VERSION = 44;\n\n        enum SEGIDX\n        {\n            SEGIDX_BANKDATA = 0,       // Bank data\n            SEGIDX_ENTRYMETADATA,      // Entry meta-data\n            SEGIDX_SEEKTABLES,         // Storage for seek tables for the encoded waves.\n            SEGIDX_ENTRYNAMES,         // Entry friendly names\n            SEGIDX_ENTRYWAVEDATA,      // Entry wave data\n            SEGIDX_COUNT\n        };\n\n        uint32_t    dwSignature;            // File signature\n        uint32_t    dwVersion;              // Version of the tool that created the file\n        uint32_t    dwHeaderVersion;        // Version of the file format\n        REGION      Segments[SEGIDX_COUNT]; // Segment lookup table\n\n        void BigEndian() noexcept\n        {\n            // Leave dwSignature alone as indicator of BE vs. LE\n\n            dwVersion = _byteswap_ulong(dwVersion);\n            dwHeaderVersion = _byteswap_ulong(dwHeaderVersion);\n            for (size_t j = 0; j < SEGIDX_COUNT; ++j)\n            {\n                Segments[j].BigEndian();\n            }\n        }\n    };\n\n#pragma warning( disable : 4201 4203 )\n\n    union MINIWAVEFORMAT\n    {\n        static const uint32_t TAG_PCM = 0x0;\n        static const uint32_t TAG_XMA = 0x1;\n        static const uint32_t TAG_ADPCM = 0x2;\n        static const uint32_t TAG_WMA = 0x3;\n\n        static const uint32_t BITDEPTH_8 = 0x0; // PCM only\n        static const uint32_t BITDEPTH_16 = 0x1; // PCM only\n\n        static const size_t ADPCM_BLOCKALIGN_CONVERSION_OFFSET = 22;\n\n        struct\n        {\n            uint32_t       wFormatTag : 2;        // Format tag\n            uint32_t       nChannels : 3;        // Channel count (1 - 6)\n            uint32_t       nSamplesPerSec : 18;       // Sampling rate\n            uint32_t       wBlockAlign : 8;        // Block alignment.  For WMA, lower 6 bits block alignment index, upper 2 bits bytes-per-second index.\n            uint32_t       wBitsPerSample : 1;        // Bits per sample (8 vs. 16, PCM only); WMAudio2/WMAudio3 (for WMA)\n        };\n\n        uint32_t           dwValue;\n\n        void BigEndian() noexcept\n        {\n            dwValue = _byteswap_ulong(dwValue);\n        }\n\n        WORD BitsPerSample() const noexcept\n        {\n            if (wFormatTag == TAG_XMA)\n                return 16; // XMA_OUTPUT_SAMPLE_BITS == 16\n            if (wFormatTag == TAG_WMA)\n                return 16;\n            if (wFormatTag == TAG_ADPCM)\n                return 4; // MSADPCM_BITS_PER_SAMPLE == 4\n\n            // wFormatTag must be TAG_PCM (2 bits can only represent 4 different values)\n            return (wBitsPerSample == BITDEPTH_16) ? 16u : 8u;\n        }\n\n        DWORD BlockAlign() const noexcept\n        {\n            switch (wFormatTag)\n            {\n                case TAG_PCM:\n                    return wBlockAlign;\n\n                case TAG_XMA:\n                    return (nChannels * 16 / 8); // XMA_OUTPUT_SAMPLE_BITS = 16\n\n                case TAG_ADPCM:\n                    return (wBlockAlign + ADPCM_BLOCKALIGN_CONVERSION_OFFSET) * nChannels;\n\n                case TAG_WMA:\n                {\n                    static const uint32_t aWMABlockAlign[] =\n                    {\n                        929,\n                        1487,\n                        1280,\n                        2230,\n                        8917,\n                        8192,\n                        4459,\n                        5945,\n                        2304,\n                        1536,\n                        1485,\n                        1008,\n                        2731,\n                        4096,\n                        6827,\n                        5462,\n                        1280\n                    };\n\n                    uint32_t dwBlockAlignIndex = wBlockAlign & 0x1F;\n                    if (dwBlockAlignIndex < _countof(aWMABlockAlign))\n                        return aWMABlockAlign[dwBlockAlignIndex];\n                }\n                break;\n            }\n\n            return 0;\n        }\n\n        DWORD AvgBytesPerSec() const noexcept\n        {\n            switch (wFormatTag)\n            {\n                case TAG_PCM:\n                    return nSamplesPerSec * wBlockAlign;\n\n                case TAG_XMA:\n                    return nSamplesPerSec * BlockAlign();\n\n                case TAG_ADPCM:\n                {\n                    uint32_t blockAlign = BlockAlign();\n                    uint32_t samplesPerAdpcmBlock = AdpcmSamplesPerBlock();\n                    return blockAlign * nSamplesPerSec / samplesPerAdpcmBlock;\n                }\n\n                case TAG_WMA:\n                {\n                    static const uint32_t aWMAAvgBytesPerSec[] =\n                    {\n                        12000,\n                        24000,\n                        4000,\n                        6000,\n                        8000,\n                        20000,\n                        2500\n                    };\n                    // bitrate = entry * 8\n\n                    uint32_t dwBytesPerSecIndex = wBlockAlign >> 5;\n                    if (dwBytesPerSecIndex < _countof(aWMAAvgBytesPerSec))\n                        return aWMAAvgBytesPerSec[dwBytesPerSecIndex];\n                }\n                break;\n            }\n\n            return 0;\n        }\n\n        DWORD AdpcmSamplesPerBlock() const noexcept\n        {\n            uint32_t nBlockAlign = (wBlockAlign + ADPCM_BLOCKALIGN_CONVERSION_OFFSET) * nChannels;\n            return nBlockAlign * 2 / uint32_t(nChannels) - 12;\n        }\n\n        void AdpcmFillCoefficientTable(ADPCMWAVEFORMAT *fmt) const noexcept\n        {\n            // These are fixed since we are always using MS ADPCM\n            fmt->wNumCoef = 7 /* MSADPCM_NUM_COEFFICIENTS */;\n\n            static ADPCMCOEFSET aCoef[7] = { { 256, 0}, {512, -256}, {0,0}, {192,64}, {240,0}, {460, -208}, {392,-232} };\n            memcpy(&fmt->aCoef, aCoef, sizeof(aCoef));\n        }\n    };\n\n    struct BANKDATA\n    {\n        static const size_t BANKNAME_LENGTH = 64;\n\n        static const uint32_t TYPE_BUFFER = 0x00000000;\n        static const uint32_t TYPE_STREAMING = 0x00000001;\n        static const uint32_t TYPE_MASK = 0x00000001;\n\n        static const uint32_t FLAGS_ENTRYNAMES = 0x00010000;\n        static const uint32_t FLAGS_COMPACT = 0x00020000;\n        static const uint32_t FLAGS_SYNC_DISABLED = 0x00040000;\n        static const uint32_t FLAGS_SEEKTABLES = 0x00080000;\n        static const uint32_t FLAGS_MASK = 0x000F0000;\n\n        uint32_t        dwFlags;                        // Bank flags\n        uint32_t        dwEntryCount;                   // Number of entries in the bank\n        char            szBankName[BANKNAME_LENGTH];    // Bank friendly name\n        uint32_t        dwEntryMetaDataElementSize;     // Size of each entry meta-data element, in bytes\n        uint32_t        dwEntryNameElementSize;         // Size of each entry name element, in bytes\n        uint32_t        dwAlignment;                    // Entry alignment, in bytes\n        MINIWAVEFORMAT  CompactFormat;                  // Format data for compact bank\n        FILETIME        BuildTime;                      // Build timestamp\n\n        void BigEndian() noexcept\n        {\n            dwFlags = _byteswap_ulong(dwFlags);\n            dwEntryCount = _byteswap_ulong(dwEntryCount);\n            dwEntryMetaDataElementSize = _byteswap_ulong(dwEntryMetaDataElementSize);\n            dwEntryNameElementSize = _byteswap_ulong(dwEntryNameElementSize);\n            dwAlignment = _byteswap_ulong(dwAlignment);\n            CompactFormat.BigEndian();\n            BuildTime.dwLowDateTime = _byteswap_ulong(BuildTime.dwLowDateTime);\n            BuildTime.dwHighDateTime = _byteswap_ulong(BuildTime.dwHighDateTime);\n        }\n    };\n\n    struct ENTRY\n    {\n        static const uint32_t FLAGS_READAHEAD = 0x00000001;     // Enable stream read-ahead\n        static const uint32_t FLAGS_LOOPCACHE = 0x00000002;     // One or more looping sounds use this wave\n        static const uint32_t FLAGS_REMOVELOOPTAIL = 0x00000004;// Remove data after the end of the loop region\n        static const uint32_t FLAGS_IGNORELOOP = 0x00000008;    // Used internally when the loop region can't be used\n        static const uint32_t FLAGS_MASK = 0x00000008;\n\n        union\n        {\n            struct\n            {\n                // Entry flags\n                uint32_t                   dwFlags : 4;\n\n                // Duration of the wave, in units of one sample.\n                // For instance, a ten second long wave sampled\n                // at 48KHz would have a duration of 480,000.\n                // This value is not affected by the number of\n                // channels, the number of bits per sample, or the\n                // compression format of the wave.\n                uint32_t                   Duration : 28;\n            };\n            uint32_t dwFlagsAndDuration;\n        };\n\n        MINIWAVEFORMAT  Format;         // Entry format.\n        REGION          PlayRegion;     // Region within the wave data segment that contains this entry.\n        SAMPLEREGION    LoopRegion;     // Region within the wave data (in samples) that should loop.\n\n        void BigEndian() noexcept\n        {\n            dwFlagsAndDuration = _byteswap_ulong(dwFlagsAndDuration);\n            Format.BigEndian();\n            PlayRegion.BigEndian();\n            LoopRegion.BigEndian();\n        }\n    };\n\n    struct ENTRYCOMPACT\n    {\n        uint32_t       dwOffset : 21;       // Data offset, in multiplies of the bank alignment\n        uint32_t       dwLengthDeviation : 11;       // Data length deviation, in bytes\n\n        void BigEndian() noexcept\n        {\n            *reinterpret_cast<uint32_t*>(this) = _byteswap_ulong(*reinterpret_cast<const uint32_t*>(this));\n        }\n\n        void ComputeLocations(DWORD& offset, DWORD& length, uint32_t index, const HEADER& header, const BANKDATA& data, const ENTRYCOMPACT* entries) const noexcept\n        {\n            offset = dwOffset * data.dwAlignment;\n\n            if (index < (data.dwEntryCount - 1))\n            {\n                length = (entries[index + 1].dwOffset * data.dwAlignment) - offset - dwLengthDeviation;\n            }\n            else\n            {\n                length = header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwLength - offset - dwLengthDeviation;\n            }\n        }\n\n        static uint32_t GetDuration(DWORD length, const BANKDATA& data, const uint32_t* seekTable) noexcept\n        {\n            switch (data.CompactFormat.wFormatTag)\n            {\n                case MINIWAVEFORMAT::TAG_ADPCM:\n                {\n                    uint32_t duration = (length / data.CompactFormat.BlockAlign()) * data.CompactFormat.AdpcmSamplesPerBlock();\n                    uint32_t partial = length % data.CompactFormat.BlockAlign();\n                    if (partial)\n                    {\n                        if (partial >= (7u * data.CompactFormat.nChannels))\n                            duration += (partial * 2 / data.CompactFormat.nChannels - 12);\n                    }\n                    return duration;\n                }\n\n                case MINIWAVEFORMAT::TAG_WMA:\n                    if (seekTable)\n                    {\n                        uint32_t seekCount = *seekTable;\n                        if (seekCount > 0)\n                        {\n                            return seekTable[seekCount] / uint32_t(2 * data.CompactFormat.nChannels);\n                        }\n                    }\n                    return 0;\n\n                case MINIWAVEFORMAT::TAG_XMA:\n                    if (seekTable)\n                    {\n                        uint32_t seekCount = *seekTable;\n                        if (seekCount > 0)\n                        {\n                            return seekTable[seekCount];\n                        }\n                    }\n                    return 0;\n\n                default:\n                    return uint32_t((uint64_t(length) * 8)\n                        / (uint64_t(data.CompactFormat.BitsPerSample()) * uint64_t(data.CompactFormat.nChannels)));\n            }\n        }\n    };\n\n#pragma pack(pop)\n\n    inline const uint32_t* FindSeekTable(uint32_t index, const uint8_t* seekTable, const HEADER& header, const BANKDATA& data) noexcept\n    {\n        if (!seekTable || index >= data.dwEntryCount)\n            return nullptr;\n\n        uint32_t seekSize = header.Segments[HEADER::SEGIDX_SEEKTABLES].dwLength;\n\n        if ((index * sizeof(uint32_t)) > seekSize)\n            return nullptr;\n\n        auto table = reinterpret_cast<const uint32_t*>(seekTable);\n        uint32_t offset = table[index];\n        if (offset == uint32_t(-1))\n            return nullptr;\n\n        offset += sizeof(uint32_t) * data.dwEntryCount;\n\n        if (offset > seekSize)\n            return nullptr;\n\n        return reinterpret_cast<const uint32_t*>(seekTable + offset);\n    }\n}\n\nstatic_assert(sizeof(REGION) == 8, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(SAMPLEREGION) == 8, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(HEADER) == 52, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(ENTRY) == 24, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(MINIWAVEFORMAT) == 4, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(ENTRY) == 24, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(ENTRYCOMPACT) == 4, \"Mismatch with xact3wb.h\");\nstatic_assert(sizeof(BANKDATA) == 96, \"Mismatch with xact3wb.h\");\n\nusing namespace DirectX;\n\n//--------------------------------------------------------------------------------------\nclass WaveBankReader::Impl\n{\npublic:\n    Impl() noexcept :\n        m_async(INVALID_HANDLE_VALUE),\n        m_request{},\n        m_prepared(false),\n        m_header{},\n        m_data{}\n    #ifdef DIRECTX_ENABLE_XMA2\n        , m_xmaMemory(nullptr)\n    #endif\n    {\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl() { Close(); }\n\n    HRESULT Open(_In_z_ const wchar_t* szFileName) noexcept(false);\n    void Close() noexcept;\n\n    HRESULT GetFormat(_In_ uint32_t index, _Out_writes_bytes_(maxsize) WAVEFORMATEX* pFormat, _In_ size_t maxsize) const noexcept;\n\n    HRESULT GetWaveData(_In_ uint32_t index, _Outptr_ const uint8_t** pData, _Out_ uint32_t& dataSize) const noexcept;\n\n    HRESULT GetSeekTable(_In_ uint32_t index, _Out_ const uint32_t** pData, _Out_ uint32_t& dataCount, _Out_ uint32_t& tag) const noexcept;\n\n    HRESULT GetMetadata(_In_ uint32_t index, _Out_ Metadata& metadata) const noexcept;\n\n    bool UpdatePrepared() noexcept;\n\n    void Clear() noexcept\n    {\n        memset(&m_header, 0, sizeof(HEADER));\n        memset(&m_data, 0, sizeof(BANKDATA));\n\n        m_names.clear();\n        m_entries.reset();\n        m_seekData.reset();\n        m_waveData.reset();\n\n    #ifdef DIRECTX_ENABLE_XMA2\n        if (m_xmaMemory)\n        {\n            ApuFree(m_xmaMemory);\n            m_xmaMemory = nullptr;\n        }\n    #endif\n    }\n\n    HANDLE                              m_async;\n    ScopedHandle                        m_event;\n    OVERLAPPED                          m_request;\n    bool                                m_prepared;\n\n    HEADER                              m_header;\n    BANKDATA                            m_data;\n    std::map<std::string, uint32_t>     m_names;\n\nprivate:\n    std::unique_ptr<uint8_t[]>          m_entries;\n    std::unique_ptr<uint8_t[]>          m_seekData;\n    std::unique_ptr<uint8_t[]>          m_waveData;\n\n#ifdef DIRECTX_ENABLE_XMA2\npublic:\n    void*                               m_xmaMemory;\n#endif\n};\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::Impl::Open(const wchar_t* szFileName) noexcept(false)\n{\n    Close();\n    Clear();\n\n    m_prepared = false;\n\n    m_event.reset(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));\n    if (!m_event)\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    CREATEFILE2_EXTENDED_PARAMETERS params = { sizeof(CREATEFILE2_EXTENDED_PARAMETERS), 0, 0, 0, {}, nullptr };\n    params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;\n    params.dwFileFlags = FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN;\n    ScopedHandle hFile(safe_handle(CreateFile2(szFileName,\n                       GENERIC_READ,\n                       FILE_SHARE_READ,\n                       OPEN_EXISTING,\n                       &params)));\n#else\n    ScopedHandle hFile(safe_handle(CreateFileW(szFileName,\n                       GENERIC_READ,\n                       FILE_SHARE_READ,\n                       nullptr,\n                       OPEN_EXISTING,\n                       FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN,\n                       nullptr)));\n#endif\n\n    if (!hFile)\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    // Read and verify header\n    OVERLAPPED request = {};\n    request.hEvent = m_event.get();\n\n    bool wait = false;\n    if (!ReadFile(hFile.get(), &m_header, sizeof(m_header), nullptr, &request))\n    {\n        DWORD error = GetLastError();\n        if (error != ERROR_IO_PENDING)\n            return HRESULT_FROM_WIN32(error);\n        wait = true;\n    }\n\n    DWORD bytes;\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    BOOL result = GetOverlappedResultEx(hFile.get(), &request, &bytes, INFINITE, FALSE);\n#else\n    if (wait)\n        (void)WaitForSingleObject(m_event.get(), INFINITE);\n\n    BOOL result = GetOverlappedResult(hFile.get(), &request, &bytes, FALSE);\n#endif\n\n    if (!result || (bytes != sizeof(m_header)))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    if (m_header.dwSignature != HEADER::SIGNATURE && m_header.dwSignature != HEADER::BE_SIGNATURE)\n    {\n        return E_FAIL;\n    }\n\n    bool be = (m_header.dwSignature == HEADER::BE_SIGNATURE);\n    if (be)\n    {\n        DebugTrace(\"INFO: \\\"%ls\\\" is a big-endian (Xbox 360) wave bank\\n\", szFileName);\n        m_header.BigEndian();\n    }\n\n    if (m_header.dwHeaderVersion != HEADER::VERSION)\n    {\n        return E_FAIL;\n    }\n\n    // Load bank data\n    memset(&request, 0, sizeof(request));\n    request.Offset = m_header.Segments[HEADER::SEGIDX_BANKDATA].dwOffset;\n    request.hEvent = m_event.get();\n\n    wait = false;\n    if (!ReadFile(hFile.get(), &m_data, sizeof(m_data), nullptr, &request))\n    {\n        DWORD error = GetLastError();\n        if (error != ERROR_IO_PENDING)\n            return HRESULT_FROM_WIN32(error);\n        wait = true;\n    }\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    result = GetOverlappedResultEx(hFile.get(), &request, &bytes, INFINITE, FALSE);\n#else\n    if (wait)\n        (void)WaitForSingleObject(m_event.get(), INFINITE);\n\n    result = GetOverlappedResult(hFile.get(), &request, &bytes, FALSE);\n#endif\n\n    if (!result || (bytes != sizeof(m_data)))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    if (be)\n        m_data.BigEndian();\n\n    if (!m_data.dwEntryCount)\n    {\n        return HRESULT_FROM_WIN32(ERROR_NO_DATA);\n    }\n\n    if (m_data.dwFlags & BANKDATA::TYPE_STREAMING)\n    {\n        if (m_data.dwAlignment < ALIGNMENT_DVD)\n            return E_FAIL;\n        if (m_data.dwAlignment % DVD_SECTOR_SIZE)\n            return E_FAIL;\n    }\n    else if (m_data.dwAlignment < ALIGNMENT_MIN)\n    {\n        return E_FAIL;\n    }\n\n    if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n    {\n        if (m_data.dwEntryMetaDataElementSize != sizeof(ENTRYCOMPACT))\n        {\n            return E_FAIL;\n        }\n\n        if (m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwLength > (MAX_COMPACT_DATA_SEGMENT_SIZE * m_data.dwAlignment))\n        {\n            // Data segment is too large to be valid compact wavebank\n            return E_FAIL;\n        }\n    }\n    else\n    {\n        if (m_data.dwEntryMetaDataElementSize != sizeof(ENTRY))\n        {\n            return E_FAIL;\n        }\n    }\n\n    DWORD metadataBytes = m_header.Segments[HEADER::SEGIDX_ENTRYMETADATA].dwLength;\n    if (metadataBytes != (m_data.dwEntryCount * m_data.dwEntryMetaDataElementSize))\n    {\n        return E_FAIL;\n    }\n\n    // Load names\n    DWORD namesBytes = m_header.Segments[HEADER::SEGIDX_ENTRYNAMES].dwLength;\n    if (namesBytes > 0)\n    {\n        if (namesBytes >= (m_data.dwEntryNameElementSize * m_data.dwEntryCount))\n        {\n            std::unique_ptr<char[]> temp(new (std::nothrow) char[namesBytes]);\n            if (!temp)\n                return E_OUTOFMEMORY;\n\n            memset(&request, 0, sizeof(request));\n            request.Offset = m_header.Segments[HEADER::SEGIDX_ENTRYNAMES].dwOffset;\n            request.hEvent = m_event.get();\n\n            wait = false;\n            if (!ReadFile(hFile.get(), temp.get(), namesBytes, nullptr, &request))\n            {\n                DWORD error = GetLastError();\n                if (error != ERROR_IO_PENDING)\n                    return HRESULT_FROM_WIN32(error);\n                wait = true;\n            }\n\n        #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n            result = GetOverlappedResultEx(hFile.get(), &request, &bytes, INFINITE, FALSE);\n        #else\n            if (wait)\n                (void)WaitForSingleObject(m_event.get(), INFINITE);\n\n            result = GetOverlappedResult(hFile.get(), &request, &bytes, FALSE);\n        #endif\n\n            if (!result || (namesBytes != bytes))\n            {\n                return HRESULT_FROM_WIN32(GetLastError());\n            }\n\n            for (uint32_t j = 0; j < m_data.dwEntryCount; ++j)\n            {\n                DWORD n = m_data.dwEntryNameElementSize * j;\n\n                char name[64] = {};\n                strncpy_s(name, &temp[n], sizeof(name));\n\n                m_names[name] = j;\n            }\n        }\n    }\n\n    // Load entries\n    if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n    {\n        m_entries.reset(reinterpret_cast<uint8_t*>(new (std::nothrow) ENTRYCOMPACT[m_data.dwEntryCount]));\n    }\n    else\n    {\n        m_entries.reset(reinterpret_cast<uint8_t*>(new (std::nothrow) ENTRY[m_data.dwEntryCount]));\n    }\n    if (!m_entries)\n        return E_OUTOFMEMORY;\n\n    memset(&request, 0, sizeof(request));\n    request.Offset = m_header.Segments[HEADER::SEGIDX_ENTRYMETADATA].dwOffset;\n    request.hEvent = m_event.get();\n\n    wait = false;\n    if (!ReadFile(hFile.get(), m_entries.get(), metadataBytes, nullptr, &request))\n    {\n        DWORD error = GetLastError();\n        if (error != ERROR_IO_PENDING)\n            return HRESULT_FROM_WIN32(error);\n        wait = true;\n    }\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    result = GetOverlappedResultEx(hFile.get(), &request, &bytes, INFINITE, FALSE);\n#else\n    if (wait)\n        (void)WaitForSingleObject(m_event.get(), INFINITE);\n\n    result = GetOverlappedResult(hFile.get(), &request, &bytes, FALSE);\n#endif\n\n    if (!result || (metadataBytes != bytes))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    if (be)\n    {\n        if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n        {\n            auto ptr = reinterpret_cast<ENTRYCOMPACT*>(m_entries.get());\n            for (size_t j = 0; j < m_data.dwEntryCount; ++j, ++ptr)\n                ptr->BigEndian();\n        }\n        else\n        {\n            auto ptr = reinterpret_cast<ENTRY*>(m_entries.get());\n            for (size_t j = 0; j < m_data.dwEntryCount; ++j, ++ptr)\n                ptr->BigEndian();\n        }\n    }\n\n    // Load seek tables (XMA2 / xWMA)\n    DWORD seekLen = m_header.Segments[HEADER::SEGIDX_SEEKTABLES].dwLength;\n    if (seekLen > 0)\n    {\n        m_seekData.reset(new (std::nothrow) uint8_t[seekLen]);\n        if (!m_seekData)\n            return E_OUTOFMEMORY;\n\n        memset(&request, 0, sizeof(OVERLAPPED));\n        request.Offset = m_header.Segments[HEADER::SEGIDX_SEEKTABLES].dwOffset;\n        request.hEvent = m_event.get();\n\n        wait = false;\n        if (!ReadFile(hFile.get(), m_seekData.get(), seekLen, nullptr, &request))\n        {\n            DWORD error = GetLastError();\n            if (error != ERROR_IO_PENDING)\n                return HRESULT_FROM_WIN32(error);\n            wait = true;\n        }\n\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n        result = GetOverlappedResultEx(hFile.get(), &request, &bytes, INFINITE, FALSE);\n    #else\n        if (wait)\n            (void)WaitForSingleObject(m_event.get(), INFINITE);\n\n        result = GetOverlappedResult(hFile.get(), &request, &bytes, FALSE);\n    #endif\n\n        if (!result || (seekLen != bytes))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        if (be)\n        {\n            auto ptr = reinterpret_cast<uint32_t*>(m_seekData.get());\n            for (size_t j = 0; j < seekLen; j += 4, ++ptr)\n            {\n                *ptr = _byteswap_ulong(*ptr);\n            }\n        }\n    }\n\n    DWORD waveLen = m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwLength;\n    if (!waveLen)\n    {\n        return HRESULT_FROM_WIN32(ERROR_NO_DATA);\n    }\n\n    if (m_data.dwFlags & BANKDATA::TYPE_STREAMING)\n    {\n        // If streaming, reopen without buffering\n        hFile.reset();\n\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n        CREATEFILE2_EXTENDED_PARAMETERS params2 = { sizeof(CREATEFILE2_EXTENDED_PARAMETERS), 0, 0, 0, {}, nullptr };\n        params2.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;\n        params2.dwFileFlags = FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;\n        m_async = CreateFile2(szFileName,\n                              GENERIC_READ,\n                              FILE_SHARE_READ,\n                              OPEN_EXISTING,\n                              &params2);\n    #else\n        m_async = CreateFileW(szFileName,\n                              GENERIC_READ,\n                              FILE_SHARE_READ,\n                              nullptr,\n                              OPEN_EXISTING,\n                              FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,\n                              nullptr);\n    #endif\n\n        if (m_async == INVALID_HANDLE_VALUE)\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        m_prepared = true;\n    }\n    else\n    {\n        // If in-memory, kick off read of wave data\n        void* dest = nullptr;\n\n    #ifdef DIRECTX_ENABLE_XMA2\n        bool xma = false;\n        if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n        {\n            if (m_data.CompactFormat.wFormatTag == MINIWAVEFORMAT::TAG_XMA)\n                xma = true;\n        }\n        else\n        {\n            for (uint32_t j = 0; j < m_data.dwEntryCount; ++j)\n            {\n                auto& entry = reinterpret_cast<const ENTRY*>(m_entries.get())[j];\n                if (entry.Format.wFormatTag == MINIWAVEFORMAT::TAG_XMA)\n                {\n                    xma = true;\n                    break;\n                }\n            }\n        }\n\n        if (xma)\n        {\n            HRESULT hr = ApuAlloc(&m_xmaMemory, nullptr, waveLen, SHAPE_XMA_INPUT_BUFFER_ALIGNMENT);\n            if (FAILED(hr))\n            {\n                DebugTrace(\"ERROR: ApuAlloc failed. Did you allocate a large enough heap with ApuCreateHeap for all your XMA wave data?\\n\");\n                return hr;\n            }\n\n            dest = m_xmaMemory;\n        }\n        else\n        #endif // XMA2\n        {\n            m_waveData.reset(new (std::nothrow) uint8_t[waveLen]);\n            if (!m_waveData)\n                return E_OUTOFMEMORY;\n\n            dest = m_waveData.get();\n        }\n\n        memset(&m_request, 0, sizeof(OVERLAPPED));\n        m_request.Offset = m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwOffset;\n        m_request.hEvent = m_event.get();\n\n        if (!ReadFile(hFile.get(), dest, waveLen, nullptr, &m_request))\n        {\n            DWORD error = GetLastError();\n            if (error != ERROR_IO_PENDING)\n                return HRESULT_FROM_WIN32(error);\n        }\n        else\n        {\n            m_prepared = true;\n            memset(&m_request, 0, sizeof(OVERLAPPED));\n        }\n\n        m_async = hFile.release();\n    }\n\n    return S_OK;\n}\n\n\nvoid WaveBankReader::Impl::Close() noexcept\n{\n    if (m_async != INVALID_HANDLE_VALUE)\n    {\n        if (m_request.hEvent)\n        {\n            DWORD bytes;\n        #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n            (void)GetOverlappedResultEx(m_async, &m_request, &bytes, INFINITE, FALSE);\n        #else\n            (void)WaitForSingleObject(m_request.hEvent, INFINITE);\n\n            (void)GetOverlappedResult(m_async, &m_request, &bytes, FALSE);\n        #endif\n        }\n\n        CloseHandle(m_async);\n        m_async = INVALID_HANDLE_VALUE;\n    }\n    m_event.reset();\n\n#ifdef DIRECTX_ENABLE_XMA2\n    if (m_xmaMemory)\n    {\n        ApuFree(m_xmaMemory);\n        m_xmaMemory = nullptr;\n    }\n#endif\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::Impl::GetFormat(uint32_t index, WAVEFORMATEX* pFormat, size_t maxsize) const noexcept\n{\n    if (!pFormat || !maxsize)\n        return E_INVALIDARG;\n\n    if (index >= m_data.dwEntryCount || !m_entries)\n    {\n        return E_FAIL;\n    }\n\n    auto& miniFmt = (m_data.dwFlags & BANKDATA::FLAGS_COMPACT) ? m_data.CompactFormat : (reinterpret_cast<const ENTRY*>(m_entries.get())[index].Format);\n\n    switch (miniFmt.wFormatTag)\n    {\n        case MINIWAVEFORMAT::TAG_PCM:\n            if (maxsize < sizeof(PCMWAVEFORMAT))\n                return HRESULT_FROM_WIN32(ERROR_MORE_DATA);\n\n            pFormat->wFormatTag = WAVE_FORMAT_PCM;\n\n            if (maxsize >= sizeof(WAVEFORMATEX))\n            {\n                pFormat->cbSize = 0;\n            }\n            break;\n\n        case MINIWAVEFORMAT::TAG_ADPCM:\n            if (maxsize < (sizeof(WAVEFORMATEX) + 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/))\n                return HRESULT_FROM_WIN32(ERROR_MORE_DATA);\n\n            pFormat->wFormatTag = WAVE_FORMAT_ADPCM;\n            pFormat->cbSize = 32 /*MSADPCM_FORMAT_EXTRA_BYTES*/;\n            {\n                auto adpcmFmt = reinterpret_cast<ADPCMWAVEFORMAT*>(pFormat);\n                adpcmFmt->wSamplesPerBlock = static_cast<WORD>(miniFmt.AdpcmSamplesPerBlock());\n                miniFmt.AdpcmFillCoefficientTable(adpcmFmt);\n            }\n            break;\n\n        case MINIWAVEFORMAT::TAG_WMA:\n            if (maxsize < sizeof(WAVEFORMATEX))\n                return HRESULT_FROM_WIN32(ERROR_MORE_DATA);\n\n            pFormat->wFormatTag = static_cast<WORD>((miniFmt.wBitsPerSample & 0x1) ? WAVE_FORMAT_WMAUDIO3 : WAVE_FORMAT_WMAUDIO2);\n            pFormat->cbSize = 0;\n            break;\n\n        case MINIWAVEFORMAT::TAG_XMA: // XMA2 is supported by Xbox One\n        #ifdef DIRECTX_ENABLE_XMA2\n            if (maxsize < sizeof(XMA2WAVEFORMATEX))\n                return HRESULT_FROM_WIN32(ERROR_MORE_DATA);\n\n            pFormat->wFormatTag = WAVE_FORMAT_XMA2;\n            pFormat->cbSize = sizeof(XMA2WAVEFORMATEX) - sizeof(WAVEFORMATEX);\n            {\n                auto xmaFmt = reinterpret_cast<XMA2WAVEFORMATEX*>(pFormat);\n\n                xmaFmt->NumStreams = static_cast<WORD>((miniFmt.nChannels + 1) / 2);\n                xmaFmt->BytesPerBlock = 65536 /* XACT_FIXED_XMA_BLOCK_SIZE */;\n                xmaFmt->EncoderVersion = 4 /* XMAENCODER_VERSION_XMA2 */;\n\n                auto seekTable = FindSeekTable(index, m_seekData.get(), m_header, m_data);\n                if (seekTable)\n                {\n                    xmaFmt->BlockCount = static_cast<WORD>(*seekTable);\n                }\n                else\n                {\n                    xmaFmt->BlockCount = 0;\n                }\n\n                switch (miniFmt.nChannels)\n                {\n                    case 1: xmaFmt->ChannelMask = SPEAKER_MONO; break;\n                    case 2: xmaFmt->ChannelMask = SPEAKER_STEREO; break;\n                    case 3: xmaFmt->ChannelMask = SPEAKER_2POINT1; break;\n                    case 4: xmaFmt->ChannelMask = SPEAKER_QUAD; break;\n                    case 5: xmaFmt->ChannelMask = SPEAKER_4POINT1; break;\n                    case 6: xmaFmt->ChannelMask = SPEAKER_5POINT1; break;\n                    case 7: xmaFmt->ChannelMask = SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; break;\n                    case 8: xmaFmt->ChannelMask = SPEAKER_7POINT1; break;\n                    default: xmaFmt->ChannelMask = DWORD(-1); break;\n                }\n\n                if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n                {\n                    auto& entry = reinterpret_cast<const ENTRYCOMPACT*>(m_entries.get())[index];\n\n                    DWORD dwOffset, dwLength;\n                    entry.ComputeLocations(dwOffset, dwLength, index, m_header, m_data, reinterpret_cast<const ENTRYCOMPACT*>(m_entries.get()));\n\n                    xmaFmt->SamplesEncoded = entry.GetDuration(dwLength, m_data, seekTable);\n\n                    xmaFmt->PlayBegin = xmaFmt->PlayLength =\n                        xmaFmt->LoopBegin = xmaFmt->LoopLength = xmaFmt->LoopCount = 0;\n                }\n                else\n                {\n                    auto& entry = reinterpret_cast<const ENTRY*>(m_entries.get())[index];\n\n                    xmaFmt->SamplesEncoded = entry.Duration;\n                    xmaFmt->PlayBegin = 0;\n                    xmaFmt->PlayLength = entry.PlayRegion.dwLength;\n\n                    if (entry.LoopRegion.dwTotalSamples > 0)\n                    {\n                        xmaFmt->LoopBegin = entry.LoopRegion.dwStartSample;\n                        xmaFmt->LoopLength = entry.LoopRegion.dwTotalSamples;\n                        xmaFmt->LoopCount = 0xff /* XACTLOOPCOUNT_INFINITE */;\n                    }\n                    else\n                    {\n                        xmaFmt->LoopBegin = xmaFmt->LoopLength = xmaFmt->LoopCount = 0;\n                    }\n                }\n            }\n            break;\n        #else\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        #endif\n\n        default:\n            return E_FAIL;\n    }\n\n    pFormat->nChannels = miniFmt.nChannels;\n    pFormat->wBitsPerSample = miniFmt.BitsPerSample();\n    pFormat->nBlockAlign = static_cast<WORD>(miniFmt.BlockAlign());\n    pFormat->nSamplesPerSec = miniFmt.nSamplesPerSec;\n    pFormat->nAvgBytesPerSec = miniFmt.AvgBytesPerSec();\n\n    return S_OK;\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::Impl::GetWaveData(uint32_t index, const uint8_t** pData, uint32_t& dataSize) const noexcept\n{\n    if (!pData)\n        return E_INVALIDARG;\n\n    if (index >= m_data.dwEntryCount || !m_entries)\n    {\n        return E_FAIL;\n    }\n\n#ifdef DIRECTX_ENABLE_XMA2\n    const uint8_t* waveData = (m_xmaMemory) ? reinterpret_cast<uint8_t*>(m_xmaMemory) : m_waveData.get();\n#else\n    const uint8_t* waveData = m_waveData.get();\n#endif\n\n    if (!waveData)\n        return E_FAIL;\n\n    if (m_data.dwFlags & BANKDATA::TYPE_STREAMING)\n    {\n        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n    }\n\n    if (!m_prepared)\n    {\n        return HRESULT_FROM_WIN32(ERROR_IO_INCOMPLETE);\n    }\n\n    if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n    {\n        auto& entry = reinterpret_cast<const ENTRYCOMPACT*>(m_entries.get())[index];\n\n        DWORD dwOffset, dwLength;\n        entry.ComputeLocations(dwOffset, dwLength, index, m_header, m_data, reinterpret_cast<const ENTRYCOMPACT*>(m_entries.get()));\n\n        if ((uint64_t(dwOffset) + uint64_t(dwLength)) > uint64_t(m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwLength))\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        *pData = &waveData[dwOffset];\n        dataSize = dwLength;\n    }\n    else\n    {\n        auto& entry = reinterpret_cast<const ENTRY*>(m_entries.get())[index];\n\n        if ((uint64_t(entry.PlayRegion.dwOffset) + uint64_t(entry.PlayRegion.dwLength)) > uint64_t(m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwLength))\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        *pData = &waveData[entry.PlayRegion.dwOffset];\n        dataSize = entry.PlayRegion.dwLength;\n    }\n\n    return S_OK;\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::Impl::GetSeekTable(uint32_t index, const uint32_t** pData, uint32_t& dataCount, uint32_t& tag) const noexcept\n{\n    if (!pData)\n        return E_INVALIDARG;\n\n    *pData = nullptr;\n    dataCount = 0;\n    tag = 0;\n\n    if (index >= m_data.dwEntryCount || !m_entries)\n    {\n        return E_FAIL;\n    }\n\n    if (!m_seekData)\n        return S_OK;\n\n    auto& miniFmt = (m_data.dwFlags & BANKDATA::FLAGS_COMPACT) ? m_data.CompactFormat : (reinterpret_cast<const ENTRY*>(m_entries.get())[index].Format);\n\n    switch (miniFmt.wFormatTag)\n    {\n        case MINIWAVEFORMAT::TAG_WMA:\n            tag = static_cast<uint32_t>((miniFmt.wBitsPerSample & 0x1) ? WAVE_FORMAT_WMAUDIO3 : WAVE_FORMAT_WMAUDIO2);\n            break;\n\n        case MINIWAVEFORMAT::TAG_XMA:\n            tag = 0x166 /* WAVE_FORMAT_XMA2 */;\n            break;\n\n        default:\n            return S_OK;\n    }\n\n    auto seekTable = FindSeekTable(index, m_seekData.get(), m_header, m_data);\n    if (!seekTable)\n        return S_OK;\n\n    dataCount = *seekTable;\n    *pData = seekTable + 1;\n\n    return S_OK;\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::Impl::GetMetadata(uint32_t index, Metadata& metadata) const noexcept\n{\n    if (index >= m_data.dwEntryCount || !m_entries)\n    {\n        return E_FAIL;\n    }\n\n    if (m_data.dwFlags & BANKDATA::FLAGS_COMPACT)\n    {\n        auto& entry = reinterpret_cast<const ENTRYCOMPACT*>(m_entries.get())[index];\n\n        DWORD dwOffset, dwLength;\n        entry.ComputeLocations(dwOffset, dwLength, index, m_header, m_data, reinterpret_cast<const ENTRYCOMPACT*>(m_entries.get()));\n\n        auto seekTable = FindSeekTable(index, m_seekData.get(), m_header, m_data);\n        metadata.duration = entry.GetDuration(dwLength, m_data, seekTable);\n        metadata.loopStart = metadata.loopLength = 0;\n        metadata.offsetBytes = dwOffset;\n        metadata.lengthBytes = dwLength;\n    }\n    else\n    {\n        auto& entry = reinterpret_cast<const ENTRY*>(m_entries.get())[index];\n\n        metadata.duration = entry.Duration;\n        metadata.loopStart = entry.LoopRegion.dwStartSample;\n        metadata.loopLength = entry.LoopRegion.dwTotalSamples;\n        metadata.offsetBytes = entry.PlayRegion.dwOffset;\n        metadata.lengthBytes = entry.PlayRegion.dwLength;\n    }\n\n    if (m_data.dwFlags & BANKDATA::TYPE_STREAMING)\n    {\n        uint64_t offset = uint64_t(metadata.offsetBytes) + uint64_t(m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwOffset);\n        if (offset > UINT32_MAX)\n            return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n        metadata.offsetBytes = static_cast<uint32_t>(offset);\n    }\n\n    return S_OK;\n}\n\n\nbool WaveBankReader::Impl::UpdatePrepared() noexcept\n{\n    if (m_prepared)\n        return true;\n\n    if (m_async == INVALID_HANDLE_VALUE)\n        return false;\n\n    if (m_request.hEvent)\n    {\n\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n        DWORD bytes;\n        BOOL result = GetOverlappedResultEx(m_async, &m_request, &bytes, 0, FALSE);\n    #else\n        bool result = HasOverlappedIoCompleted(&m_request);\n    #endif\n        if (result)\n        {\n            m_prepared = true;\n\n            memset(&m_request, 0, sizeof(OVERLAPPED));\n        }\n    }\n\n    return m_prepared;\n}\n\n\n\n//--------------------------------------------------------------------------------------\nWaveBankReader::WaveBankReader() noexcept(false) :\n    pImpl(std::make_unique<Impl>())\n{\n}\n\n\nWaveBankReader::~WaveBankReader()\n{\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::Open(const wchar_t* szFileName) noexcept\n{\n    return pImpl->Open(szFileName);\n}\n\n\n_Use_decl_annotations_\nuint32_t WaveBankReader::Find(const char* name) const\n{\n    auto it = pImpl->m_names.find(name);\n    if (it != pImpl->m_names.cend())\n    {\n        return it->second;\n    }\n\n    return uint32_t(-1);\n}\n\n\nbool WaveBankReader::IsPrepared() noexcept\n{\n    if (pImpl->m_prepared)\n        return true;\n\n    return pImpl->UpdatePrepared();\n}\n\n\nvoid WaveBankReader::WaitOnPrepare() noexcept\n{\n    if (pImpl->m_prepared)\n        return;\n\n    if (pImpl->m_request.hEvent)\n    {\n        (void)WaitForSingleObjectEx(pImpl->m_request.hEvent, INFINITE, FALSE);\n\n        pImpl->UpdatePrepared();\n    }\n}\n\n\nbool WaveBankReader::HasNames() const noexcept\n{\n    return !pImpl->m_names.empty();\n}\n\n\nbool WaveBankReader::IsStreamingBank() const noexcept\n{\n    return (pImpl->m_data.dwFlags  & BANKDATA::TYPE_STREAMING) != 0;\n}\n\n\n#ifdef DIRECTX_ENABLE_XMA2\nbool WaveBankReader::HasXMA() const noexcept\n{\n    return (pImpl->m_xmaMemory != nullptr);\n}\n#endif\n\n\nconst char* WaveBankReader::BankName() const noexcept\n{\n    return pImpl->m_data.szBankName;\n}\n\n\nuint32_t WaveBankReader::Count() const noexcept\n{\n    return pImpl->m_data.dwEntryCount;\n}\n\n\nuint32_t WaveBankReader::BankAudioSize() const noexcept\n{\n    return pImpl->m_header.Segments[HEADER::SEGIDX_ENTRYWAVEDATA].dwLength;\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::GetFormat(uint32_t index, WAVEFORMATEX* pFormat, size_t maxsize) const noexcept\n{\n    return pImpl->GetFormat(index, pFormat, maxsize);\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::GetWaveData(uint32_t index, const uint8_t** pData, uint32_t& dataSize) const noexcept\n{\n    return pImpl->GetWaveData(index, pData, dataSize);\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::GetSeekTable(uint32_t index, const uint32_t** pData, uint32_t& dataCount, uint32_t& tag) const noexcept\n{\n    return pImpl->GetSeekTable(index, pData, dataCount, tag);\n}\n\n\n_Use_decl_annotations_\nHRESULT WaveBankReader::GetMetadata(uint32_t index, Metadata& metadata) const noexcept\n{\n    return pImpl->GetMetadata(index, metadata);\n}\n\n\nHANDLE WaveBankReader::GetAsyncHandle() const noexcept\n{\n    return (pImpl->m_data.dwFlags & BANKDATA::TYPE_STREAMING) ? pImpl->m_async : INVALID_HANDLE_VALUE;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Audio/WaveBankReader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: WaveBankReader.h\n//\n// Functions for loading audio data from Wave Banks\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <objbase.h>\n#include <mmreg.h>\n\n#include <cstdint>\n#include <memory>\n\n\nnamespace DirectX\n{\n    class WaveBankReader\n    {\n    public:\n        WaveBankReader() noexcept(false);\n\n        WaveBankReader(WaveBankReader&&) = default;\n        WaveBankReader& operator= (WaveBankReader&&) = default;\n\n        WaveBankReader(WaveBankReader const&) = delete;\n        WaveBankReader& operator= (WaveBankReader const&) = delete;\n\n        ~WaveBankReader();\n\n        HRESULT Open(_In_z_ const wchar_t* szFileName) noexcept;\n\n        uint32_t Find(_In_z_ const char* name) const;\n\n        bool IsPrepared() noexcept;\n        void WaitOnPrepare() noexcept;\n\n        bool HasNames() const noexcept;\n        bool IsStreamingBank() const noexcept;\n\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        bool HasXMA() const noexcept;\n    #endif\n\n        const char* BankName() const noexcept;\n\n        uint32_t Count() const noexcept;\n\n        uint32_t BankAudioSize() const noexcept;\n\n        HRESULT GetFormat(_In_ uint32_t index, _Out_writes_bytes_(maxsize) WAVEFORMATEX* pFormat, _In_ size_t maxsize) const noexcept;\n\n        HRESULT GetWaveData(_In_ uint32_t index, _Outptr_ const uint8_t** pData, _Out_ uint32_t& dataSize) const noexcept;\n\n        HRESULT GetSeekTable(_In_ uint32_t index, _Out_ const uint32_t** pData, _Out_ uint32_t& dataCount, _Out_ uint32_t& tag) const noexcept;\n\n        HANDLE GetAsyncHandle() const noexcept;\n\n        struct Metadata\n        {\n            uint32_t    duration;\n            uint32_t    loopStart;\n            uint32_t    loopLength;\n            uint32_t    offsetBytes;\n            uint32_t    lengthBytes;\n        };\n        HRESULT GetMetadata(_In_ uint32_t index, _Out_ Metadata& metadata) const noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/DirectXTK12_GDK_2017.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Desktop.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Desktop.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Desktop.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectName>DirectXTK12</ProjectName>\n    <RootNamespace>DirectXTK12</RootNamespace>\n    <ProjectGuid>{052c4858-c76f-4cea-8a1a-e8e5559e67c2}</ProjectGuid>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <Keyword>Win32Proj</Keyword>\n    <!-- - - - -->\n    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n    <TargetRuntime>Native</TargetRuntime>\n    <PreferredToolArchitecture>x64</PreferredToolArchitecture>\n  </PropertyGroup>\n  <Import Condition=\"Exists($(ATGBuildProps))\" Project=\"$(ATGBuildProps)\" />\n  <Import Project=\"$(MSBuildThisFileDirectory)..\\..\\..\\..\\..\\Build\\xsapi.gdk.bwoi.props\" /> \n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <PlatformToolset>v141</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</OutDir>\n    <IntDir>Bin\\GDK_2017\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>DirectXTK12</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <CompileAsWinRT>false</CompileAsWinRT>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <CompileAsWinRT>false</CompileAsWinRT>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>NDEBUG;_LIB;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <CompileAsWinRT>false</CompileAsWinRT>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>NDEBUG;_LIB;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <CompileAsWinRT>false</CompileAsWinRT>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <CompileAsWinRT>false</CompileAsWinRT>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <ConformanceMode>true</ConformanceMode>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <CompileAsWinRT>false</CompileAsWinRT>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <FloatingPointModel>Fast</FloatingPointModel>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>NDEBUG;__WRL_NO_DEFAULT_LIB__;_LIB;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <FloatingPointModel>Fast</FloatingPointModel>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <WarningLevel>EnableAllWarnings</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;__WRL_NO_DEFAULT_LIB__;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(ProjectDir)Inc;$(ProjectDir)Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <FloatingPointModel>Fast</FloatingPointModel>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>5.1</ShaderModel>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Audio\\SoundCommon.h\" />\n    <ClInclude Include=\"Audio\\WaveBankReader.h\" />\n    <ClInclude Include=\"Audio\\WAVFileReader.h\" />\n    <ClInclude Include=\"Inc\\Audio.h\" />\n    <ClInclude Include=\"Inc\\BufferHelpers.h\" />\n    <ClInclude Include=\"Inc\\CommonStates.h\" />\n    <ClInclude Include=\"Inc\\DDSTextureLoader.h\" />\n    <ClInclude Include=\"Inc\\DescriptorHeap.h\" />\n    <ClInclude Include=\"Inc\\DirectXHelpers.h\" />\n    <ClInclude Include=\"Inc\\EffectPipelineStateDescription.h\" />\n    <ClInclude Include=\"Inc\\Effects.h\" />\n    <ClInclude Include=\"Inc\\GamePad.h\" />\n    <ClInclude Include=\"Inc\\GeometricPrimitive.h\" />\n    <ClInclude Include=\"Inc\\GraphicsMemory.h\" />\n    <ClInclude Include=\"Inc\\Keyboard.h\" />\n    <ClInclude Include=\"Inc\\Model.h\" />\n    <ClInclude Include=\"Inc\\Mouse.h\" />\n    <ClInclude Include=\"Inc\\PostProcess.h\" />\n    <ClInclude Include=\"Inc\\PrimitiveBatch.h\" />\n    <ClInclude Include=\"Inc\\RenderTargetState.h\" />\n    <ClInclude Include=\"Inc\\ResourceUploadBatch.h\" />\n    <ClInclude Include=\"Inc\\ScreenGrab.h\" />\n    <ClInclude Include=\"Inc\\SimpleMath.h\" />\n    <ClInclude Include=\"Inc\\SpriteBatch.h\" />\n    <ClInclude Include=\"Inc\\SpriteFont.h\" />\n    <ClInclude Include=\"Inc\\VertexTypes.h\" />\n    <ClInclude Include=\"Inc\\WICTextureLoader.h\" />\n    <ClInclude Include=\"Inc\\XboxDDSTextureLoader.h\">\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">true</ExcludedFromBuild>\n    </ClInclude>\n    <ClInclude Include=\"Src\\AlignedNew.h\" />\n    <ClInclude Include=\"Src\\Bezier.h\" />\n    <ClInclude Include=\"Src\\BinaryReader.h\" />\n    <ClInclude Include=\"Src\\d3dx12.h\">\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">true</ExcludedFromBuild>\n    </ClInclude>\n    <ClInclude Include=\"Src\\DDS.h\" />\n    <ClInclude Include=\"Src\\DemandCreate.h\" />\n    <ClInclude Include=\"Src\\EffectCommon.h\" />\n    <ClInclude Include=\"Src\\Geometry.h\" />\n    <ClInclude Include=\"Src\\LinearAllocator.h\" />\n    <ClInclude Include=\"Src\\LoaderHelpers.h\" />\n    <ClInclude Include=\"Src\\pch.h\" />\n    <ClInclude Include=\"Src\\PlatformHelpers.h\" />\n    <ClInclude Include=\"Src\\SDKMesh.h\" />\n    <ClInclude Include=\"Src\\SharedResourcePool.h\" />\n    <ClInclude Include=\"Src\\vbo.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Audio\\AudioEngine.cpp\" />\n    <ClCompile Include=\"Audio\\DynamicSoundEffectInstance.cpp\" />\n    <ClCompile Include=\"Audio\\SoundCommon.cpp\" />\n    <ClCompile Include=\"Audio\\SoundEffect.cpp\" />\n    <ClCompile Include=\"Audio\\SoundEffectInstance.cpp\" />\n    <ClCompile Include=\"Audio\\SoundStreamInstance.cpp\" />\n    <ClCompile Include=\"Audio\\WaveBank.cpp\" />\n    <ClCompile Include=\"Audio\\WaveBankReader.cpp\" />\n    <ClCompile Include=\"Audio\\WAVFileReader.cpp\" />\n    <ClCompile Include=\"Src\\AlphaTestEffect.cpp\" />\n    <ClCompile Include=\"Src\\BasicEffect.cpp\" />\n    <ClCompile Include=\"Src\\BasicPostProcess.cpp\" />\n    <ClCompile Include=\"Src\\BinaryReader.cpp\" />\n    <ClCompile Include=\"Src\\BufferHelpers.cpp\" />\n    <ClCompile Include=\"Src\\CommonStates.cpp\" />\n    <ClCompile Include=\"Src\\DDSTextureLoader.cpp\" />\n    <ClCompile Include=\"Src\\DebugEffect.cpp\" />\n    <ClCompile Include=\"Src\\DescriptorHeap.cpp\" />\n    <ClCompile Include=\"Src\\DirectXHelpers.cpp\" />\n    <ClCompile Include=\"Src\\DualPostProcess.cpp\" />\n    <ClCompile Include=\"Src\\DualTextureEffect.cpp\" />\n    <ClCompile Include=\"Src\\EffectCommon.cpp\" />\n    <ClCompile Include=\"Src\\EffectFactory.cpp\" />\n    <ClCompile Include=\"Src\\EffectPipelineStateDescription.cpp\" />\n    <ClCompile Include=\"Src\\EffectTextureFactory.cpp\" />\n    <ClCompile Include=\"Src\\EnvironmentMapEffect.cpp\" />\n    <ClCompile Include=\"Src\\GamePad.cpp\" />\n    <ClCompile Include=\"Src\\GeometricPrimitive.cpp\" />\n    <ClCompile Include=\"Src\\Geometry.cpp\" />\n    <ClCompile Include=\"Src\\GraphicsMemory.cpp\" />\n    <ClCompile Include=\"Src\\Keyboard.cpp\" />\n    <ClCompile Include=\"Src\\LinearAllocator.cpp\" />\n    <ClCompile Include=\"Src\\Model.cpp\" />\n    <ClCompile Include=\"Src\\ModelLoadSDKMESH.cpp\" />\n    <ClCompile Include=\"Src\\ModelLoadVBO.cpp\" />\n    <ClCompile Include=\"Src\\Mouse.cpp\" />\n    <ClCompile Include=\"Src\\NormalMapEffect.cpp\" />\n    <ClCompile Include=\"Src\\PBREffect.cpp\" />\n    <ClCompile Include=\"Src\\PBREffectFactory.cpp\" />\n    <ClCompile Include=\"Src\\pch.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"Src\\PrimitiveBatch.cpp\" />\n    <ClCompile Include=\"Src\\ResourceUploadBatch.cpp\" />\n    <ClCompile Include=\"Src\\ScreenGrab.cpp\" />\n    <ClCompile Include=\"Src\\SimpleMath.cpp\" />\n    <ClCompile Include=\"Src\\SkinnedEffect.cpp\" />\n    <ClCompile Include=\"Src\\SpriteBatch.cpp\" />\n    <ClCompile Include=\"Src\\SpriteFont.cpp\" />\n    <ClCompile Include=\"Src\\ToneMapPostProcess.cpp\" />\n    <ClCompile Include=\"Src\\VertexTypes.cpp\" />\n    <ClCompile Include=\"Src\\WICTextureLoader.cpp\" />\n    <ClCompile Include=\"Src\\XboxDDSTextureLoader.cpp\">\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">true</ExcludedFromBuild>\n      <ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">true</ExcludedFromBuild>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Inc\\SimpleMath.inl\" />\n    <None Include=\"README.md\" />\n    <None Include=\"Src\\Shaders\\Common.fxh\" />\n    <None Include=\"Src\\Shaders\\CompileShaders.cmd\" />\n    <None Include=\"Src\\Shaders\\Lighting.fxh\" />\n    <None Include=\"Src\\Shaders\\PBRCommon.fxh\" />\n    <None Include=\"Src\\Shaders\\PixelPacking_Velocity.hlsli\" />\n    <None Include=\"Src\\Shaders\\RootSig.fxh\" />\n    <None Include=\"Src\\Shaders\\Structures.fxh\" />\n    <None Include=\"Src\\Shaders\\Utilities.fxh\" />\n    <None Include=\"Src\\TeapotData.inc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Src\\Shaders\\AlphaTestEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\BasicEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\DebugEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\DualTextureEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\EnvironmentMapEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\GenerateMips.hlsl\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\NormalMapEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\PBREffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\PostProcess.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\SkinnedEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\SpriteEffect.fx\">\n      <FileType>Document</FileType>\n    </None>\n    <None Include=\"Src\\Shaders\\ToneMap.fx\">\n      <FileType>Document</FileType>\n    </None>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n  <Target Name=\"ATGEnsureShaders\" BeforeTargets=\"PrepareForBuild\" Condition=\"'$(Platform)'=='Gaming.Desktop.x64'\">\n    <PropertyGroup>\n      <_ATGFXCPath>$(WindowsSDK_ExecutablePath_x64.Split(';')[0])</_ATGFXCPath>\n      <_ATGFXCPath>$(_ATGFXCPath.Replace(\"x64\",\"\"))</_ATGFXCPath>\n      <_ATGFXCPath Condition=\"'$(_ATGFXCPath)' != '' and !HasTrailingSlash('$(_ATGFXCPath)')\">$(_ATGFXCPath)\\</_ATGFXCPath>\n    </PropertyGroup>\n    <Exec Condition=\"!Exists('src/Shaders/Compiled/SpriteEffect_SpriteVertexShader.inc')\" WorkingDirectory=\"$(ProjectDir)src/Shaders\" Command=\"CompileShaders\" EnvironmentVariables=\"WindowsSdkVerBinPath=$(_ATGFXCPath)\" />\n    <PropertyGroup>\n      <_ATGFXCPath />\n    </PropertyGroup>\n  </Target>\n  <Target Name=\"ATGDeleteShaders\" AfterTargets=\"Clean\" Condition=\"'$(Platform)'=='Gaming.Desktop.x64'\">\n    <ItemGroup>\n      <_ATGShaderHeaders Include=\"$(ProjectDir)src/Shaders/Compiled/*.inc\" Exclude=\"$(ProjectDir)src/Shaders/Compiled/*Xbox*.inc\" />\n      <_ATGShaderSymbols Include=\"$(ProjectDir)src/Shaders/Compiled/*.pdb\" Exclude=\"$(ProjectDir)src/Shaders/Compiled/*Xbox*.pdb\" />\n    </ItemGroup>\n    <Delete Files=\"@(_ATGShaderHeaders)\" />\n    <Delete Files=\"@(_ATGShaderSymbols)\" />\n  </Target>\n  <Target Name=\"ATGEnsureShadersXbox\" BeforeTargets=\"PrepareForBuild\" Condition=\"'$(Platform)'=='Gaming.Xbox.XboxOne.x64'\">\n    <Exec Condition=\"!Exists('src/Shaders/Compiled/XboxGamingXboxOneSpriteEffect_SpriteVertexShader.inc')\" WorkingDirectory=\"$(ProjectDir)src/Shaders\" Command=\"CompileShaders gxdk\" EnvironmentVariables=\"GameDKLatest=$(DurangoXdkInstallPath)\" />\n  </Target>\n  <Target Name=\"ATGDeleteShadersXbox\" AfterTargets=\"Clean\" Condition=\"'$(Platform)'=='Gaming.Xbox.XboxOne.x64'\">\n    <ItemGroup>\n      <_ATGShaderHeaders Include=\"$(ProjectDir)src/Shaders/Compiled/XboxGamingXboxOne*.inc\" />\n      <_ATGShaderSymbols Include=\"$(ProjectDir)src/Shaders/Compiled/XboxGamingXboxOne*.pdb\" />\n    </ItemGroup>\n    <Delete Files=\"@(_ATGShaderHeaders)\" />\n    <Delete Files=\"@(_ATGShaderSymbols)\" />\n  </Target>\n  <Target Name=\"ATGEnsureShadersXboxScarlett\" BeforeTargets=\"PrepareForBuild\" Condition=\"'$(Platform)'=='Gaming.Xbox.Scarlett.x64'\">\n    <Exec Condition=\"!Exists('src/Shaders/Compiled/XboxGamingScarlettSpriteEffect_SpriteVertexShader.inc')\" WorkingDirectory=\"$(ProjectDir)src/Shaders\" Command=\"CompileShaders gxdk scarlett\" EnvironmentVariables=\"GameDKLatest=$(DurangoXdkInstallPath)\" />\n  </Target>\n  <Target Name=\"ATGDeleteShadersXboxScarlett\" AfterTargets=\"Clean\" Condition=\"'$(Platform)'=='Gaming.Xbox.Scarlett.x64'\">\n    <ItemGroup>\n      <_ATGShaderHeaders Include=\"$(ProjectDir)src/Shaders/Compiled/XboxGamingScarlett*.inc\" />\n      <_ATGShaderSymbols Include=\"$(ProjectDir)src/Shaders/Compiled/XboxGamingScarlett*.pdb\" />\n    </ItemGroup>\n    <Delete Files=\"@(_ATGShaderHeaders)\" />\n    <Delete Files=\"@(_ATGShaderSymbols)\" />\n  </Target>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/DirectXTK12_GDK_2017.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Inc\">\n      <UniqueIdentifier>{bd781ce7-c4af-40f5-b970-3e18d4e427c6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Inc\\Shared\">\n      <UniqueIdentifier>{062bb847-bcd6-4e16-9ce5-d649301e796f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Src\">\n      <UniqueIdentifier>{1730fefa-08c9-458d-8563-e21b2119bb5f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Src\\Shared\">\n      <UniqueIdentifier>{82fb9d3e-dd70-42a8-ac9e-5fa0d2f0acbd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Src\\Shaders\">\n      <UniqueIdentifier>{c320f8fe-0223-436c-ab0b-4b5ae399bd76}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Src\\Shaders\\Shared\">\n      <UniqueIdentifier>{d2e931a3-a934-4d9c-bed4-b7b1137a6627}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Audio\">\n      <UniqueIdentifier>{0e862607-b322-421e-83d9-51aa055356c4}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Inc\\GamePad.h\">\n      <Filter>Inc\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\Keyboard.h\">\n      <Filter>Inc\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\Mouse.h\">\n      <Filter>Inc\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\SimpleMath.h\">\n      <Filter>Inc\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\CommonStates.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\DDSTextureLoader.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\DescriptorHeap.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\DirectXHelpers.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\EffectPipelineStateDescription.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\Effects.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\GeometricPrimitive.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\GraphicsMemory.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\Model.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\PostProcess.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\PrimitiveBatch.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\RenderTargetState.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\ResourceUploadBatch.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\ScreenGrab.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\SpriteBatch.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\SpriteFont.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\VertexTypes.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\WICTextureLoader.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\XboxDDSTextureLoader.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\Audio.h\">\n      <Filter>Audio</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Audio\\SoundCommon.h\">\n      <Filter>Audio</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Audio\\WaveBankReader.h\">\n      <Filter>Audio</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Audio\\WAVFileReader.h\">\n      <Filter>Audio</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\AlignedNew.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\Bezier.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\BinaryReader.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\DDS.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\DemandCreate.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\Geometry.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\LoaderHelpers.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\PlatformHelpers.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\SDKMesh.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\SharedResourcePool.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\vbo.h\">\n      <Filter>Src\\Shared</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\EffectCommon.h\">\n      <Filter>Src</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\LinearAllocator.h\">\n      <Filter>Src</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\pch.h\">\n      <Filter>Src</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Src\\d3dx12.h\">\n      <Filter>Src</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inc\\BufferHelpers.h\">\n      <Filter>Inc</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Audio\\AudioEngine.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\DynamicSoundEffectInstance.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\SoundCommon.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\SoundEffect.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\SoundEffectInstance.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\WaveBank.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\WaveBankReader.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\WAVFileReader.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\BinaryReader.cpp\">\n      <Filter>Src\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\GamePad.cpp\">\n      <Filter>Src\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\Geometry.cpp\">\n      <Filter>Src\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\Keyboard.cpp\">\n      <Filter>Src\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\Mouse.cpp\">\n      <Filter>Src\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\SimpleMath.cpp\">\n      <Filter>Src\\Shared</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\AlphaTestEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\BasicEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\BasicPostProcess.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\CommonStates.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\DDSTextureLoader.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\DebugEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\DescriptorHeap.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\DirectXHelpers.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\DualPostProcess.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\DualTextureEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\EffectCommon.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\EffectFactory.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\EffectPipelineStateDescription.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\EffectTextureFactory.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\EnvironmentMapEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\GeometricPrimitive.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\GraphicsMemory.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\LinearAllocator.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\Model.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\ModelLoadSDKMESH.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\ModelLoadVBO.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\NormalMapEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\PBREffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\PBREffectFactory.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\pch.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\PrimitiveBatch.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\ResourceUploadBatch.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\ScreenGrab.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\SkinnedEffect.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\SpriteBatch.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\SpriteFont.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\ToneMapPostProcess.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\VertexTypes.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\WICTextureLoader.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\XboxDDSTextureLoader.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Audio\\SoundStreamInstance.cpp\">\n      <Filter>Audio</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Src\\BufferHelpers.cpp\">\n      <Filter>Src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Src\\Shaders\\Common.fxh\">\n      <Filter>Src\\Shaders\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\Lighting.fxh\">\n      <Filter>Src\\Shaders\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\PBRCommon.fxh\">\n      <Filter>Src\\Shaders\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\Structures.fxh\">\n      <Filter>Src\\Shaders\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\Utilities.fxh\">\n      <Filter>Src\\Shaders\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\PixelPacking_Velocity.hlsli\">\n      <Filter>Src\\Shaders\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\RootSig.fxh\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\CompileShaders.cmd\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Inc\\SimpleMath.inl\">\n      <Filter>Inc\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\TeapotData.inc\">\n      <Filter>Src\\Shared</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\AlphaTestEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\BasicEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\DebugEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\DualTextureEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\EnvironmentMapEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\GenerateMips.hlsl\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\NormalMapEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\PBREffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\PostProcess.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\SkinnedEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\SpriteEffect.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"Src\\Shaders\\ToneMap.fx\">\n      <Filter>Src\\Shaders</Filter>\n    </None>\n    <None Include=\"README.md\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/Audio.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Audio.h\n//\n// DirectXTK for Audio header\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <objbase.h>\n#include <mmreg.h>\n#include <Audioclient.h>\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <xma2defs.h>\n#pragma comment(lib,\"acphal.lib\")\n#endif\n\n#ifndef XAUDIO2_HELPER_FUNCTIONS\n#define XAUDIO2_HELPER_FUNCTIONS\n#endif\n\n#if defined(USING_XAUDIO2_REDIST) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/) || defined(_XBOX_ONE)\n#define USING_XAUDIO2_9\n#elif (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)\n#define USING_XAUDIO2_8\n#elif (_WIN32_WINNT >= 0x0601 /*_WIN32_WINNT_WIN7*/)\n#error Windows 7 SP1 requires the XAudio2Redist NuGet package https://aka.ms/xaudio2redist\n#else\n#error DirectX Tool Kit for Audio not supported on this platform\n#endif\n\n#include <xaudio2.h>\n#include <xaudio2fx.h>\n#include <x3daudio.h>\n#include <xapofx.h>\n\n#ifndef USING_XAUDIO2_REDIST\n#pragma comment(lib,\"xaudio2.lib\")\n#endif\n\n#include <DirectXMath.h>\n\n\n#include <cstdint>\n#include <functional>\n#include <memory>\n#include <string>\n#include <vector>\n\n\nnamespace DirectX\n{\n    class SoundEffectInstance;\n    class SoundStreamInstance;\n\n    //----------------------------------------------------------------------------------\n    struct AudioStatistics\n    {\n        size_t  playingOneShots;        // Number of one-shot sounds currently playing\n        size_t  playingInstances;       // Number of sound effect instances currently playing\n        size_t  allocatedInstances;     // Number of SoundEffectInstance allocated\n        size_t  allocatedVoices;        // Number of XAudio2 voices allocated (standard, 3D, one-shots, and idle one-shots)\n        size_t  allocatedVoices3d;      // Number of XAudio2 voices allocated for 3D\n        size_t  allocatedVoicesOneShot; // Number of XAudio2 voices allocated for one-shot sounds\n        size_t  allocatedVoicesIdle;    // Number of XAudio2 voices allocated for one-shot sounds but not currently in use\n        size_t  audioBytes;             // Total wave data (in bytes) in SoundEffects and in-memory WaveBanks\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        size_t  xmaAudioBytes;          // Total wave data (in bytes) in SoundEffects and in-memory WaveBanks allocated with ApuAlloc\n#endif\n        size_t  streamingBytes;         // Total size of streaming buffers (in bytes) in streaming WaveBanks\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class IVoiceNotify\n    {\n    public:\n        virtual ~IVoiceNotify() = default;\n\n        IVoiceNotify(const IVoiceNotify&) = delete;\n        IVoiceNotify& operator=(const IVoiceNotify&) = delete;\n\n        IVoiceNotify(IVoiceNotify&&) = default;\n        IVoiceNotify& operator=(IVoiceNotify&&) = default;\n\n        virtual void __cdecl OnBufferEnd() = 0;\n            // Notfication that a voice buffer has finished\n            // Note this is called from XAudio2's worker thread, so it should perform very minimal and thread-safe operations\n\n        virtual void __cdecl OnCriticalError() = 0;\n            // Notification that the audio engine encountered a critical error\n\n        virtual void __cdecl OnReset() = 0;\n            // Notification of an audio engine reset\n\n        virtual void __cdecl OnUpdate() = 0;\n            // Notification of an audio engine per-frame update (opt-in)\n\n        virtual void __cdecl OnDestroyEngine() noexcept = 0;\n            // Notification that the audio engine is being destroyed\n\n        virtual void __cdecl OnTrim() = 0;\n            // Notification of a request to trim the voice pool\n\n        virtual void __cdecl GatherStatistics(AudioStatistics& stats) const = 0;\n            // Contribute to statistics request\n\n        virtual void __cdecl OnDestroyParent() noexcept = 0;\n            // Optional notification used by some objects\n\n    protected:\n        IVoiceNotify() = default;\n    };\n\n    //----------------------------------------------------------------------------------\n    enum AUDIO_ENGINE_FLAGS : uint32_t\n    {\n        AudioEngine_Default             = 0x0,\n\n        AudioEngine_EnvironmentalReverb = 0x1,\n        AudioEngine_ReverbUseFilters    = 0x2,\n        AudioEngine_UseMasteringLimiter = 0x4,\n\n        AudioEngine_Debug               = 0x10000,\n        AudioEngine_ThrowOnNoAudioHW    = 0x20000,\n        AudioEngine_DisableVoiceReuse   = 0x40000,\n    };\n\n    enum SOUND_EFFECT_INSTANCE_FLAGS : uint32_t\n    {\n        SoundEffectInstance_Default             = 0x0,\n\n        SoundEffectInstance_Use3D               = 0x1,\n        SoundEffectInstance_ReverbUseFilters    = 0x2,\n        SoundEffectInstance_NoSetPitch          = 0x4,\n\n        SoundEffectInstance_UseRedirectLFE      = 0x10000,\n    };\n\n    enum AUDIO_ENGINE_REVERB : unsigned int\n    {\n        Reverb_Off,\n        Reverb_Default,\n        Reverb_Generic,\n        Reverb_Forest,\n        Reverb_PaddedCell,\n        Reverb_Room,\n        Reverb_Bathroom,\n        Reverb_LivingRoom,\n        Reverb_StoneRoom,\n        Reverb_Auditorium,\n        Reverb_ConcertHall,\n        Reverb_Cave,\n        Reverb_Arena,\n        Reverb_Hangar,\n        Reverb_CarpetedHallway,\n        Reverb_Hallway,\n        Reverb_StoneCorridor,\n        Reverb_Alley,\n        Reverb_City,\n        Reverb_Mountains,\n        Reverb_Quarry,\n        Reverb_Plain,\n        Reverb_ParkingLot,\n        Reverb_SewerPipe,\n        Reverb_Underwater,\n        Reverb_SmallRoom,\n        Reverb_MediumRoom,\n        Reverb_LargeRoom,\n        Reverb_MediumHall,\n        Reverb_LargeHall,\n        Reverb_Plate,\n        Reverb_MAX\n    };\n\n    enum SoundState\n    {\n        STOPPED = 0,\n        PLAYING,\n        PAUSED\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class AudioEngine\n    {\n    public:\n        explicit AudioEngine(\n            AUDIO_ENGINE_FLAGS flags = AudioEngine_Default,\n            _In_opt_ const WAVEFORMATEX* wfx = nullptr,\n            _In_opt_z_ const wchar_t* deviceId = nullptr,\n            AUDIO_STREAM_CATEGORY category = AudioCategory_GameEffects) noexcept(false);\n\n        AudioEngine(AudioEngine&& moveFrom) noexcept;\n        AudioEngine& operator= (AudioEngine&& moveFrom) noexcept;\n\n        AudioEngine(AudioEngine const&) = delete;\n        AudioEngine& operator= (AudioEngine const&) = delete;\n\n        virtual ~AudioEngine();\n\n        bool __cdecl Update();\n            // Performs per-frame processing for the audio engine, returns false if in 'silent mode'\n\n        bool __cdecl Reset(_In_opt_ const WAVEFORMATEX* wfx = nullptr, _In_opt_z_ const wchar_t* deviceId = nullptr);\n            // Reset audio engine from critical error/silent mode using a new device; can also 'migrate' the graph\n            // Returns true if succesfully reset, false if in 'silent mode' due to no default device\n            // Note: One shots are lost, all SoundEffectInstances are in the STOPPED state after successful reset\n\n        void __cdecl Suspend() noexcept;\n        void __cdecl Resume();\n            // Suspend/resumes audio processing (i.e. global pause/resume)\n\n        float __cdecl GetMasterVolume() const noexcept;\n        void __cdecl SetMasterVolume(float volume);\n            // Master volume property for all sounds\n\n        void __cdecl SetReverb(AUDIO_ENGINE_REVERB reverb);\n        void __cdecl SetReverb(_In_opt_ const XAUDIO2FX_REVERB_PARAMETERS* native);\n            // Sets environmental reverb for 3D positional audio (if active)\n\n        void __cdecl SetMasteringLimit(int release, int loudness);\n            // Sets the mastering volume limiter properties (if active)\n\n        AudioStatistics __cdecl GetStatistics() const;\n            // Gathers audio engine statistics\n\n        WAVEFORMATEXTENSIBLE __cdecl GetOutputFormat() const noexcept;\n            // Returns the format consumed by the mastering voice (which is the same as the device output if defaults are used)\n\n        uint32_t __cdecl GetChannelMask() const noexcept;\n            // Returns the output channel mask\n\n        unsigned int __cdecl GetOutputChannels() const noexcept;\n            // Returns the number of output channels\n\n        bool __cdecl IsAudioDevicePresent() const noexcept;\n            // Returns true if the audio graph is operating normally, false if in 'silent mode'\n\n        bool __cdecl IsCriticalError() const noexcept;\n            // Returns true if the audio graph is halted due to a critical error (which also places the engine into 'silent mode')\n\n        // Voice pool management.\n        void __cdecl SetDefaultSampleRate(int sampleRate);\n            // Sample rate for voices in the reuse pool (defaults to 44100)\n\n        void __cdecl SetMaxVoicePool(size_t maxOneShots, size_t maxInstances);\n            // Maximum number of voices to allocate for one-shots and instances\n            // Note: one-shots over this limit are ignored; too many instance voices throws an exception\n\n        void __cdecl TrimVoicePool();\n            // Releases any currently unused voices\n\n        // Internal-use functions\n        void __cdecl AllocateVoice(_In_ const WAVEFORMATEX* wfx,\n            SOUND_EFFECT_INSTANCE_FLAGS flags, bool oneshot, _Outptr_result_maybenull_ IXAudio2SourceVoice** voice);\n\n        void __cdecl DestroyVoice(_In_ IXAudio2SourceVoice* voice) noexcept;\n            // Should only be called for instance voices, not one-shots\n\n        void __cdecl RegisterNotify(_In_ IVoiceNotify* notify, bool usesUpdate);\n        void __cdecl UnregisterNotify(_In_ IVoiceNotify* notify, bool usesOneShots, bool usesUpdate);\n\n        // XAudio2 interface access\n        IXAudio2* __cdecl GetInterface() const noexcept;\n        IXAudio2MasteringVoice* __cdecl GetMasterVoice() const noexcept;\n        IXAudio2SubmixVoice* __cdecl GetReverbVoice() const noexcept;\n        X3DAUDIO_HANDLE& __cdecl Get3DHandle() const noexcept;\n\n        // Static functions\n        struct RendererDetail\n        {\n            std::wstring deviceId;\n            std::wstring description;\n        };\n\n        static std::vector<RendererDetail> __cdecl GetRendererDetails();\n            // Returns a list of valid audio endpoint devices\n\n    private:\n        // Private implementation.\n        class Impl;\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class WaveBank\n    {\n    public:\n        WaveBank(_In_ AudioEngine* engine, _In_z_ const wchar_t* wbFileName);\n\n        WaveBank(WaveBank&& moveFrom) noexcept;\n        WaveBank& operator= (WaveBank&& moveFrom) noexcept;\n\n        WaveBank(WaveBank const&) = delete;\n        WaveBank& operator= (WaveBank const&) = delete;\n\n        virtual ~WaveBank();\n\n        void __cdecl Play(unsigned int index);\n        void __cdecl Play(unsigned int index, float volume, float pitch, float pan);\n\n        void __cdecl Play(_In_z_ const char* name);\n        void __cdecl Play(_In_z_ const char* name, float volume, float pitch, float pan);\n\n        std::unique_ptr<SoundEffectInstance> __cdecl CreateInstance(unsigned int index,\n            SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default);\n        std::unique_ptr<SoundEffectInstance> __cdecl CreateInstance(_In_z_ const char* name,\n            SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default);\n\n        std::unique_ptr<SoundStreamInstance> __cdecl CreateStreamInstance(unsigned int index,\n            SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default);\n        std::unique_ptr<SoundStreamInstance> __cdecl CreateStreamInstance(_In_z_ const char* name,\n            SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default);\n\n        bool __cdecl IsPrepared() const noexcept;\n        bool __cdecl IsInUse() const noexcept;\n        bool __cdecl IsStreamingBank() const noexcept;\n\n        size_t __cdecl GetSampleSizeInBytes(unsigned int index) const noexcept;\n        // Returns size of wave audio data\n\n        size_t __cdecl GetSampleDuration(unsigned int index) const noexcept;\n        // Returns the duration in samples\n\n        size_t __cdecl GetSampleDurationMS(unsigned int index) const noexcept;\n        // Returns the duration in milliseconds\n\n        const WAVEFORMATEX* __cdecl GetFormat(unsigned int index, _Out_writes_bytes_(maxsize) WAVEFORMATEX* wfx, size_t maxsize) const noexcept;\n\n        int __cdecl Find(_In_z_ const char* name) const;\n\n#ifdef USING_XAUDIO2_9\n        bool __cdecl FillSubmitBuffer(unsigned int index, _Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer) const;\n#else\n        void __cdecl FillSubmitBuffer(unsigned int index, _Out_ XAUDIO2_BUFFER& buffer) const;\n#endif\n\n        void __cdecl UnregisterInstance(_In_ IVoiceNotify* instance);\n\n        HANDLE __cdecl GetAsyncHandle() const noexcept;\n\n        bool __cdecl GetPrivateData(unsigned int index, _Out_writes_bytes_(datasize) void* data, size_t datasize);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class SoundEffect\n    {\n    public:\n        SoundEffect(_In_ AudioEngine* engine, _In_z_ const wchar_t* waveFileName);\n\n        SoundEffect(_In_ AudioEngine* engine, _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n            _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes);\n\n        SoundEffect(_In_ AudioEngine* engine, _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n            _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes,\n            uint32_t loopStart, uint32_t loopLength);\n\n#ifdef USING_XAUDIO2_9\n\n        SoundEffect(_In_ AudioEngine* engine, _Inout_ std::unique_ptr<uint8_t[]>& wavData,\n            _In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes,\n            _In_reads_(seekCount) const uint32_t* seekTable, size_t seekCount);\n\n#endif\n\n        SoundEffect(SoundEffect&& moveFrom) noexcept;\n        SoundEffect& operator= (SoundEffect&& moveFrom) noexcept;\n\n        SoundEffect(SoundEffect const&) = delete;\n        SoundEffect& operator= (SoundEffect const&) = delete;\n\n        virtual ~SoundEffect();\n\n        void __cdecl Play();\n        void __cdecl Play(float volume, float pitch, float pan);\n\n        std::unique_ptr<SoundEffectInstance> __cdecl CreateInstance(SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default);\n\n        bool __cdecl IsInUse() const noexcept;\n\n        size_t __cdecl GetSampleSizeInBytes() const noexcept;\n        // Returns size of wave audio data\n\n        size_t __cdecl GetSampleDuration() const noexcept;\n        // Returns the duration in samples\n\n        size_t __cdecl GetSampleDurationMS() const noexcept;\n        // Returns the duration in milliseconds\n\n        const WAVEFORMATEX* __cdecl GetFormat() const noexcept;\n\n#ifdef USING_XAUDIO2_9\n        bool __cdecl FillSubmitBuffer(_Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer) const;\n#else\n        void __cdecl FillSubmitBuffer(_Out_ XAUDIO2_BUFFER& buffer) const;\n#endif\n\n        void __cdecl UnregisterInstance(_In_ IVoiceNotify* instance);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    struct AudioListener : public X3DAUDIO_LISTENER\n    {\n        AudioListener() noexcept\n        {\n            memset(this, 0, sizeof(X3DAUDIO_LISTENER));\n\n            OrientFront.z = -1.f;\n\n            OrientTop.y = 1.f;\n        }\n\n        void XM_CALLCONV SetPosition(FXMVECTOR v) noexcept\n        {\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Position), v);\n        }\n        void __cdecl SetPosition(const XMFLOAT3& pos) noexcept\n        {\n            Position.x = pos.x;\n            Position.y = pos.y;\n            Position.z = pos.z;\n        }\n\n        void XM_CALLCONV SetVelocity(FXMVECTOR v) noexcept\n        {\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Velocity), v);\n        }\n        void __cdecl SetVelocity(const XMFLOAT3& vel) noexcept\n        {\n            Velocity.x = vel.x;\n            Velocity.y = vel.y;\n            Velocity.z = vel.z;\n        }\n\n        void XM_CALLCONV SetOrientation(FXMVECTOR forward, FXMVECTOR up) noexcept\n        {\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientFront), forward);\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientTop), up);\n        }\n        void __cdecl SetOrientation(const XMFLOAT3& forward, const XMFLOAT3& up) noexcept\n        {\n            OrientFront.x = forward.x;  OrientTop.x = up.x;\n            OrientFront.y = forward.y;  OrientTop.y = up.y;\n            OrientFront.z = forward.z;  OrientTop.z = up.z;\n        }\n\n        void XM_CALLCONV SetOrientationFromQuaternion(FXMVECTOR quat) noexcept\n        {\n            XMVECTOR forward = XMVector3Rotate(g_XMIdentityR2, quat);\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientFront), forward);\n\n            XMVECTOR up = XMVector3Rotate(g_XMIdentityR1, quat);\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientTop), up);\n        }\n\n        void XM_CALLCONV Update(FXMVECTOR newPos, XMVECTOR upDir, float dt) noexcept\n            // Updates velocity and orientation by tracking changes in position over time...\n        {\n            if (dt > 0.f)\n            {\n                XMVECTOR lastPos = XMLoadFloat3(reinterpret_cast<const XMFLOAT3*>(&Position));\n\n                XMVECTOR vDelta = XMVectorSubtract(newPos, lastPos);\n                XMVECTOR vt = XMVectorReplicate(dt);\n                XMVECTOR v = XMVectorDivide(vDelta, vt);\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Velocity), v);\n\n                vDelta = XMVector3Normalize(vDelta);\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientFront), vDelta);\n\n                v = XMVector3Cross(upDir, vDelta);\n                v = XMVector3Normalize(v);\n\n                v = XMVector3Cross(vDelta, v);\n                v = XMVector3Normalize(v);\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientTop), v);\n\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Position), newPos);\n            }\n        }\n    };\n\n\n    //----------------------------------------------------------------------------------\n    struct AudioEmitter : public X3DAUDIO_EMITTER\n    {\n        float       EmitterAzimuths[XAUDIO2_MAX_AUDIO_CHANNELS];\n\n        AudioEmitter() noexcept :\n            EmitterAzimuths{}\n        {\n            memset(this, 0, sizeof(X3DAUDIO_EMITTER));\n\n            OrientFront.z = -1.f;\n\n            OrientTop.y =\n                ChannelRadius =\n                CurveDistanceScaler =\n                DopplerScaler = 1.f;\n\n            ChannelCount = 1;\n            pChannelAzimuths = EmitterAzimuths;\n\n            InnerRadiusAngle = X3DAUDIO_PI / 4.0f;\n        }\n\n        void XM_CALLCONV SetPosition(FXMVECTOR v) noexcept\n        {\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Position), v);\n        }\n        void __cdecl SetPosition(const XMFLOAT3& pos) noexcept\n        {\n            Position.x = pos.x;\n            Position.y = pos.y;\n            Position.z = pos.z;\n        }\n\n        void XM_CALLCONV SetVelocity(FXMVECTOR v) noexcept\n        {\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Velocity), v);\n        }\n        void __cdecl SetVelocity(const XMFLOAT3& vel) noexcept\n        {\n            Velocity.x = vel.x;\n            Velocity.y = vel.y;\n            Velocity.z = vel.z;\n        }\n\n        void XM_CALLCONV SetOrientation(FXMVECTOR forward, FXMVECTOR up) noexcept\n        {\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientFront), forward);\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientTop), up);\n        }\n        void __cdecl SetOrientation(const XMFLOAT3& forward, const XMFLOAT3& up) noexcept\n        {\n            OrientFront.x = forward.x;  OrientTop.x = up.x;\n            OrientFront.y = forward.y;  OrientTop.y = up.y;\n            OrientFront.z = forward.z;  OrientTop.z = up.z;\n        }\n\n        void XM_CALLCONV SetOrientationFromQuaternion(FXMVECTOR quat) noexcept\n        {\n            XMVECTOR forward = XMVector3Rotate(g_XMIdentityR2, quat);\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientFront), forward);\n\n            XMVECTOR up = XMVector3Rotate(g_XMIdentityR1, quat);\n            XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientTop), up);\n        }\n\n        void XM_CALLCONV Update(FXMVECTOR newPos, XMVECTOR upDir, float dt) noexcept\n            // Updates velocity and orientation by tracking changes in position over time...\n        {\n            if (dt > 0.f)\n            {\n                XMVECTOR lastPos = XMLoadFloat3(reinterpret_cast<const XMFLOAT3*>(&Position));\n\n                XMVECTOR vDelta = XMVectorSubtract(newPos, lastPos);\n                XMVECTOR vt = XMVectorReplicate(dt);\n                XMVECTOR v = XMVectorDivide(vDelta, vt);\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Velocity), v);\n\n                vDelta = XMVector3Normalize(vDelta);\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientFront), vDelta);\n\n                v = XMVector3Cross(upDir, vDelta);\n                v = XMVector3Normalize(v);\n\n                v = XMVector3Cross(vDelta, v);\n                v = XMVector3Normalize(v);\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&OrientTop), v);\n\n                XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&Position), newPos);\n            }\n        }\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class SoundEffectInstance\n    {\n    public:\n        SoundEffectInstance(SoundEffectInstance&& moveFrom) noexcept;\n        SoundEffectInstance& operator= (SoundEffectInstance&& moveFrom) noexcept;\n\n        SoundEffectInstance(SoundEffectInstance const&) = delete;\n        SoundEffectInstance& operator= (SoundEffectInstance const&) = delete;\n\n        virtual ~SoundEffectInstance();\n\n        void __cdecl Play(bool loop = false);\n        void __cdecl Stop(bool immediate = true) noexcept;\n        void __cdecl Pause() noexcept;\n        void __cdecl Resume();\n\n        void __cdecl SetVolume(float volume);\n        void __cdecl SetPitch(float pitch);\n        void __cdecl SetPan(float pan);\n\n        void __cdecl Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true);\n\n        bool __cdecl IsLooped() const noexcept;\n\n        SoundState __cdecl GetState() noexcept;\n\n        IVoiceNotify* __cdecl GetVoiceNotify() const noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        // Private constructors\n        SoundEffectInstance(_In_ AudioEngine* engine, _In_ SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags);\n        SoundEffectInstance(_In_ AudioEngine* engine, _In_ WaveBank* effect, unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags);\n\n        friend std::unique_ptr<SoundEffectInstance> __cdecl SoundEffect::CreateInstance(SOUND_EFFECT_INSTANCE_FLAGS);\n        friend std::unique_ptr<SoundEffectInstance> __cdecl WaveBank::CreateInstance(unsigned int, SOUND_EFFECT_INSTANCE_FLAGS);\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class SoundStreamInstance\n    {\n    public:\n        SoundStreamInstance(SoundStreamInstance&& moveFrom) noexcept;\n        SoundStreamInstance& operator= (SoundStreamInstance&& moveFrom) noexcept;\n\n        SoundStreamInstance(SoundStreamInstance const&) = delete;\n        SoundStreamInstance& operator= (SoundStreamInstance const&) = delete;\n\n        virtual ~SoundStreamInstance();\n\n        void __cdecl Play(bool loop = false);\n        void __cdecl Stop(bool immediate = true) noexcept;\n        void __cdecl Pause() noexcept;\n        void __cdecl Resume();\n\n        void __cdecl SetVolume(float volume);\n        void __cdecl SetPitch(float pitch);\n        void __cdecl SetPan(float pan);\n\n        void __cdecl Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true);\n\n        bool __cdecl IsLooped() const noexcept;\n\n        SoundState __cdecl GetState() noexcept;\n\n        IVoiceNotify* __cdecl GetVoiceNotify() const noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        // Private constructors\n        SoundStreamInstance(_In_ AudioEngine* engine, _In_ WaveBank* effect, unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags);\n\n        friend std::unique_ptr<SoundStreamInstance> __cdecl WaveBank::CreateStreamInstance(unsigned int, SOUND_EFFECT_INSTANCE_FLAGS);\n    };\n\n\n    //----------------------------------------------------------------------------------\n    class DynamicSoundEffectInstance\n    {\n    public:\n        DynamicSoundEffectInstance(_In_ AudioEngine* engine,\n            _In_opt_ std::function<void __cdecl(DynamicSoundEffectInstance*)> bufferNeeded,\n            int sampleRate, int channels, int sampleBits = 16,\n            SOUND_EFFECT_INSTANCE_FLAGS flags = SoundEffectInstance_Default);\n        DynamicSoundEffectInstance(DynamicSoundEffectInstance&& moveFrom) noexcept;\n        DynamicSoundEffectInstance& operator= (DynamicSoundEffectInstance&& moveFrom) noexcept;\n\n        DynamicSoundEffectInstance(DynamicSoundEffectInstance const&) = delete;\n        DynamicSoundEffectInstance& operator= (DynamicSoundEffectInstance const&) = delete;\n\n        virtual ~DynamicSoundEffectInstance();\n\n        void __cdecl Play();\n        void __cdecl Stop(bool immediate = true) noexcept;\n        void __cdecl Pause() noexcept;\n        void __cdecl Resume();\n\n        void __cdecl SetVolume(float volume);\n        void __cdecl SetPitch(float pitch);\n        void __cdecl SetPan(float pan);\n\n        void __cdecl Apply3D(const AudioListener& listener, const AudioEmitter& emitter, bool rhcoords = true);\n\n        void __cdecl SubmitBuffer(_In_reads_bytes_(audioBytes) const uint8_t* pAudioData, size_t audioBytes);\n        void __cdecl SubmitBuffer(_In_reads_bytes_(audioBytes) const uint8_t* pAudioData, uint32_t offset, size_t audioBytes);\n\n        SoundState __cdecl GetState() noexcept;\n\n        size_t __cdecl GetSampleDuration(size_t bytes) const noexcept;\n        // Returns duration in samples of a buffer of a given size\n\n        size_t __cdecl GetSampleDurationMS(size_t bytes) const noexcept;\n        // Returns duration in milliseconds of a buffer of a given size\n\n        size_t __cdecl GetSampleSizeInBytes(uint64_t duration) const noexcept;\n        // Returns size of a buffer for a duration given in milliseconds\n\n        int __cdecl GetPendingBufferCount() const noexcept;\n\n        const WAVEFORMATEX* __cdecl GetFormat() const noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-dynamic-exception-spec\"\n#endif\n\n    DEFINE_ENUM_FLAG_OPERATORS(AUDIO_ENGINE_FLAGS);\n    DEFINE_ENUM_FLAG_OPERATORS(SOUND_EFFECT_INSTANCE_FLAGS);\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/BufferHelpers.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: BufferHelpers.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n\nnamespace DirectX\n{\n    class ResourceUploadBatch;\n\n    // Helpers for creating initialized Direct3D buffer resources.\n    HRESULT __cdecl CreateStaticBuffer(_In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        _In_reads_bytes_(count* stride) const void* ptr,\n        size_t count,\n        size_t stride,\n        D3D12_RESOURCE_STATES afterState,\n        _COM_Outptr_ ID3D12Resource** pBuffer,\n        D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE) noexcept;\n\n    template<typename T>\n    HRESULT CreateStaticBuffer(_In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        _In_reads_(count) T const* data,\n        size_t count,\n        D3D12_RESOURCE_STATES afterState,\n        _COM_Outptr_ ID3D12Resource** pBuffer,\n        D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE) noexcept\n    {\n        return CreateStaticBuffer(device, resourceUpload, data, count, sizeof(T), afterState, pBuffer, resFlags);\n    }\n\n    template<typename T>\n    HRESULT CreateStaticBuffer(_In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        T const& data,\n        D3D12_RESOURCE_STATES afterState,\n        _COM_Outptr_ ID3D12Resource** pBuffer,\n        D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE) noexcept\n    {\n        return CreateStaticBuffer(device, resourceUpload, data.data(), data.size(), sizeof(typename T::value_type),\n            afterState, pBuffer, resFlags);\n    }\n\n    // Helpers for creating texture from memory arrays.\n    HRESULT __cdecl CreateTextureFromMemory(_In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        size_t width,\n        DXGI_FORMAT format,\n        const D3D12_SUBRESOURCE_DATA& initData,\n        _COM_Outptr_ ID3D12Resource** texture,\n        D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,\n        D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE) noexcept;\n\n    HRESULT __cdecl CreateTextureFromMemory(_In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        size_t width, size_t height,\n        DXGI_FORMAT format,\n        const D3D12_SUBRESOURCE_DATA& initData,\n        _COM_Outptr_ ID3D12Resource** texture,\n        bool generateMips = false,\n        D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,\n        D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE) noexcept;\n\n    HRESULT __cdecl CreateTextureFromMemory(_In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        size_t width, size_t height, size_t depth,\n        DXGI_FORMAT format,\n        const D3D12_SUBRESOURCE_DATA& initData,\n        _COM_Outptr_ ID3D12Resource** texture,\n        D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,\n        D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE) noexcept;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/CommonStates.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: CommonStates.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <memory>\n\n\nnamespace DirectX\n{\n    class CommonStates\n    {\n    public:\n        explicit CommonStates(_In_ ID3D12Device* device);\n        CommonStates(CommonStates&& moveFrom) noexcept;\n        CommonStates& operator = (CommonStates&& moveFrom) noexcept;\n\n        CommonStates(const CommonStates&) = delete;\n        CommonStates& operator = (const CommonStates&) = delete;\n\n        virtual ~CommonStates();\n\n        // Blend states.\n        static const D3D12_BLEND_DESC Opaque;\n        static const D3D12_BLEND_DESC AlphaBlend;\n        static const D3D12_BLEND_DESC Additive;\n        static const D3D12_BLEND_DESC NonPremultiplied;\n        \n        // Depth stencil states.\n        static const D3D12_DEPTH_STENCIL_DESC DepthNone;\n        static const D3D12_DEPTH_STENCIL_DESC DepthDefault;\n        static const D3D12_DEPTH_STENCIL_DESC DepthRead;\n\n        // Rasterizer states.\n        static const D3D12_RASTERIZER_DESC CullNone;\n        static const D3D12_RASTERIZER_DESC CullClockwise;\n        static const D3D12_RASTERIZER_DESC CullCounterClockwise;\n        static const D3D12_RASTERIZER_DESC Wireframe;\n\n        // Static sampler states.\n        static const D3D12_STATIC_SAMPLER_DESC StaticPointWrap(unsigned int shaderRegister, D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL, unsigned int registerSpace = 0) noexcept;\n        static const D3D12_STATIC_SAMPLER_DESC StaticPointClamp(unsigned int shaderRegister, D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL, unsigned int registerSpace = 0) noexcept;\n        static const D3D12_STATIC_SAMPLER_DESC StaticLinearWrap(unsigned int shaderRegister, D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL, unsigned int registerSpace = 0) noexcept;\n        static const D3D12_STATIC_SAMPLER_DESC StaticLinearClamp(unsigned int shaderRegister, D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL, unsigned int registerSpace = 0) noexcept;\n        static const D3D12_STATIC_SAMPLER_DESC StaticAnisotropicWrap(unsigned int shaderRegister, D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL, unsigned int registerSpace = 0) noexcept;\n        static const D3D12_STATIC_SAMPLER_DESC StaticAnisotropicClamp(unsigned int shaderRegister, D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL, unsigned int registerSpace = 0) noexcept;\n\n        // Sampler states.\n        D3D12_GPU_DESCRIPTOR_HANDLE PointWrap() const;\n        D3D12_GPU_DESCRIPTOR_HANDLE PointClamp() const;\n        D3D12_GPU_DESCRIPTOR_HANDLE LinearWrap() const;\n        D3D12_GPU_DESCRIPTOR_HANDLE LinearClamp() const;\n        D3D12_GPU_DESCRIPTOR_HANDLE AnisotropicWrap() const;\n        D3D12_GPU_DESCRIPTOR_HANDLE AnisotropicClamp() const;\n\n        // These index into the heap returned by SamplerDescriptorHeap\n        enum class SamplerIndex\n        {\n            PointWrap,\n            PointClamp,\n            LinearWrap,\n            LinearClamp,\n            AnisotropicWrap,\n            AnisotropicClamp,\n            Count\n        };\n\n        ID3D12DescriptorHeap* Heap() const noexcept;\n\n    private:\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/DDSTextureLoader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: DDSTextureLoader.h\n//\n// Functions for loading a DDS texture and creating a Direct3D runtime resource for it\n//\n// Note these functions are useful as a light-weight runtime loader for DDS files. For\n// a full-featured DDS file reader, writer, and texture processing pipeline see\n// the 'Texconv' sample and the 'DirectXTex' library.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <cstdint>\n#include <memory>\n#include <vector>\n\n\nnamespace DirectX\n{\n    class ResourceUploadBatch;\n\n#ifndef DDS_ALPHA_MODE_DEFINED\n#define DDS_ALPHA_MODE_DEFINED\n    enum DDS_ALPHA_MODE : uint32_t\n    {\n        DDS_ALPHA_MODE_UNKNOWN       = 0,\n        DDS_ALPHA_MODE_STRAIGHT      = 1,\n        DDS_ALPHA_MODE_PREMULTIPLIED = 2,\n        DDS_ALPHA_MODE_OPAQUE        = 3,\n        DDS_ALPHA_MODE_CUSTOM        = 4,\n    };\n#endif\n\n    enum DDS_LOADER_FLAGS : uint32_t\n    {\n        DDS_LOADER_DEFAULT      = 0,\n        DDS_LOADER_FORCE_SRGB   = 0x1,\n        DDS_LOADER_MIP_AUTOGEN  = 0x8,\n        DDS_LOADER_MIP_RESERVE  = 0x10,\n    };\n\n    // Standard version\n    HRESULT __cdecl LoadDDSTextureFromMemory(\n        _In_ ID3D12Device* d3dDevice,\n        _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData,\n        size_t ddsDataSize,\n        _Outptr_ ID3D12Resource** texture,\n        std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n        size_t maxsize = 0,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    HRESULT __cdecl LoadDDSTextureFromFile(\n        _In_ ID3D12Device* d3dDevice,\n        _In_z_ const wchar_t* szFileName,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& ddsData,\n        std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n        size_t maxsize = 0,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    // Standard version with resource upload\n    HRESULT __cdecl CreateDDSTextureFromMemory(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData,\n        size_t ddsDataSize,\n        _Outptr_ ID3D12Resource** texture,\n        bool generateMipsIfMissing = false,\n        size_t maxsize = 0,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    HRESULT __cdecl CreateDDSTextureFromFile(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        _In_z_ const wchar_t* szFileName,\n        _Outptr_ ID3D12Resource** texture,\n        bool generateMipsIfMissing = false,\n        size_t maxsize = 0,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    // Extended version\n    HRESULT __cdecl LoadDDSTextureFromMemoryEx(\n        _In_ ID3D12Device* d3dDevice,\n        _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData,\n        size_t ddsDataSize,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        DDS_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    HRESULT __cdecl LoadDDSTextureFromFileEx(\n        _In_ ID3D12Device* d3dDevice,\n        _In_z_ const wchar_t* szFileName,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        DDS_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& ddsData,\n        std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    // Extended version with resource upload\n    HRESULT __cdecl CreateDDSTextureFromMemoryEx(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData,\n        size_t ddsDataSize,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        DDS_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n    HRESULT __cdecl CreateDDSTextureFromFileEx(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUpload,\n        _In_z_ const wchar_t* szFileName,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        DDS_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _Out_opt_ bool* isCubeMap = nullptr);\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-dynamic-exception-spec\"\n#endif\n\n    DEFINE_ENUM_FLAG_OPERATORS(DDS_LOADER_FLAGS);\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/DescriptorHeap.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: DescriptorHeap.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <cstdint>\n#include <stdexcept>\n\n#include <assert.h>\n\n#include <wrl/client.h>\n\n\nnamespace DirectX\n{\n    // A contiguous linear random-access descriptor heap\n    class DescriptorHeap\n    {\n    public:\n        DescriptorHeap(\n            _In_ ID3D12DescriptorHeap* pExistingHeap) noexcept;\n        DescriptorHeap(\n            _In_ ID3D12Device* device,\n            _In_ const D3D12_DESCRIPTOR_HEAP_DESC* pDesc) noexcept(false);\n        DescriptorHeap(\n            _In_ ID3D12Device* device,\n            D3D12_DESCRIPTOR_HEAP_TYPE type,\n            D3D12_DESCRIPTOR_HEAP_FLAGS flags,\n            size_t count) noexcept(false);\n        DescriptorHeap(\n            _In_ ID3D12Device* device,\n            size_t count) noexcept(false) :\n            DescriptorHeap(device,\n                D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\n                D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, count) {}\n\n        DescriptorHeap(DescriptorHeap&&) = default;\n        DescriptorHeap& operator=(DescriptorHeap&&) = default;\n\n        DescriptorHeap(const DescriptorHeap&) = delete;\n        DescriptorHeap& operator=(const DescriptorHeap&) = delete;\n\n        D3D12_GPU_DESCRIPTOR_HANDLE __cdecl WriteDescriptors(\n            _In_ ID3D12Device* device,\n            uint32_t offsetIntoHeap,\n            uint32_t totalDescriptorCount,\n            _In_reads_(descriptorRangeCount) const D3D12_CPU_DESCRIPTOR_HANDLE* pDescriptorRangeStarts,\n            _In_reads_(descriptorRangeCount) const uint32_t* pDescriptorRangeSizes,\n            uint32_t descriptorRangeCount);\n\n        D3D12_GPU_DESCRIPTOR_HANDLE __cdecl WriteDescriptors(\n            _In_ ID3D12Device* device,\n            uint32_t offsetIntoHeap,\n            _In_reads_(descriptorRangeCount) const D3D12_CPU_DESCRIPTOR_HANDLE* pDescriptorRangeStarts,\n            _In_reads_(descriptorRangeCount) const uint32_t* pDescriptorRangeSizes,\n            uint32_t descriptorRangeCount);\n\n        D3D12_GPU_DESCRIPTOR_HANDLE __cdecl WriteDescriptors(\n            _In_ ID3D12Device* device,\n            uint32_t offsetIntoHeap,\n            _In_reads_(descriptorCount) const D3D12_CPU_DESCRIPTOR_HANDLE* pDescriptors,\n            uint32_t descriptorCount);\n\n        D3D12_GPU_DESCRIPTOR_HANDLE GetFirstGpuHandle() const noexcept\n        {\n            assert(m_desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);\n            assert(m_pHeap != nullptr);\n            return m_hGPU;\n        }\n\n        D3D12_CPU_DESCRIPTOR_HANDLE GetFirstCpuHandle() const noexcept\n        {\n            assert(m_pHeap != nullptr);\n            return m_hCPU;\n        }\n\n        D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(_In_ size_t index) const\n        {\n            assert(m_pHeap != nullptr);\n            if (index >= m_desc.NumDescriptors)\n            {\n                throw std::out_of_range(\"D3DX12_GPU_DESCRIPTOR_HANDLE\");\n            }\n            assert(m_desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);\n\n            D3D12_GPU_DESCRIPTOR_HANDLE handle;\n            handle.ptr = m_hGPU.ptr + UINT64(index) * UINT64(m_increment);\n            return handle;\n        }\n\n        D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(_In_ size_t index) const\n        {\n            assert(m_pHeap != nullptr);\n            if (index >= m_desc.NumDescriptors)\n            {\n                throw std::out_of_range(\"D3DX12_CPU_DESCRIPTOR_HANDLE\");\n            }\n\n            D3D12_CPU_DESCRIPTOR_HANDLE handle;\n            handle.ptr = static_cast<SIZE_T>(m_hCPU.ptr + UINT64(index) * UINT64(m_increment));\n            return handle;\n        }\n\n        size_t Count() const noexcept { return m_desc.NumDescriptors; }\n        unsigned int Flags() const noexcept { return m_desc.Flags; }\n        D3D12_DESCRIPTOR_HEAP_TYPE Type() const noexcept { return m_desc.Type; }\n        size_t Increment() const noexcept { return m_increment; }\n        ID3D12DescriptorHeap* Heap() const noexcept { return m_pHeap.Get(); }\n\n        static void __cdecl DefaultDesc(\n            _In_ D3D12_DESCRIPTOR_HEAP_TYPE type,\n            _Out_ D3D12_DESCRIPTOR_HEAP_DESC* pDesc) noexcept;\n\n    private:\n        void Create(_In_ ID3D12Device* pDevice, _In_ const D3D12_DESCRIPTOR_HEAP_DESC* pDesc);\n\n        Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>    m_pHeap;\n        D3D12_DESCRIPTOR_HEAP_DESC                      m_desc;\n        D3D12_CPU_DESCRIPTOR_HANDLE                     m_hCPU;\n        D3D12_GPU_DESCRIPTOR_HANDLE                     m_hGPU;\n        uint32_t                                        m_increment;\n    };\n\n\n    // Helper class for dynamically allocating descriptor indices.\n    // The pile is statically sized and will throw an exception if it becomes full.\n    class DescriptorPile : public DescriptorHeap\n    {\n    public:\n        using IndexType = size_t;\n        static const IndexType INVALID_INDEX = size_t(-1);\n\n        DescriptorPile(\n            _In_ ID3D12DescriptorHeap* pExistingHeap,\n            size_t reserve = 0) noexcept(false)\n            : DescriptorHeap(pExistingHeap),\n            m_top(reserve)\n        {\n            if (reserve > 0 && m_top >= Count())\n            {\n                throw std::out_of_range(\"Reserve descriptor range is too large\");\n            }\n        }\n\n        DescriptorPile(\n            _In_ ID3D12Device* device,\n            _In_ const D3D12_DESCRIPTOR_HEAP_DESC* pDesc,\n            size_t reserve = 0) noexcept(false)\n            : DescriptorHeap(device, pDesc),\n            m_top(reserve)\n        {\n            if (reserve > 0 && m_top >= Count())\n            {\n                throw std::out_of_range(\"Reserve descriptor range is too large\");\n            }\n        }\n\n        DescriptorPile(\n            _In_ ID3D12Device* device,\n            D3D12_DESCRIPTOR_HEAP_TYPE type,\n            D3D12_DESCRIPTOR_HEAP_FLAGS flags,\n            size_t capacity,\n            size_t reserve = 0) noexcept(false)\n            : DescriptorHeap(device, type, flags, capacity),\n            m_top(reserve)\n        {\n            if (reserve > 0 && m_top >= Count())\n            {\n                throw std::out_of_range(\"Reserve descriptor range is too large\");\n            }\n        }\n\n        DescriptorPile(\n            _In_ ID3D12Device* device,\n            size_t count,\n            size_t reserve = 0) noexcept(false) :\n            DescriptorPile(device,\n                D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\n                D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, count, reserve) {}\n\n        DescriptorPile(const DescriptorPile&) = delete;\n        DescriptorPile& operator=(const DescriptorPile&) = delete;\n\n        DescriptorPile(DescriptorPile&&) = default;\n        DescriptorPile& operator=(DescriptorPile&&) = default;\n\n        IndexType Allocate()\n        {\n            IndexType start, end;\n            AllocateRange(1, start, end);\n\n            return start;\n        }\n\n        void AllocateRange(size_t numDescriptors, _Out_ IndexType& start, _Out_ IndexType& end);\n\n    private:\n        IndexType m_top;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/DirectXHelpers.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: DirectXHelpers.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <DirectXMath.h>\n\n#include <initializer_list>\n#include <utility>\n#include <vector>\n\n#include <assert.h>\n\n#include <wrl/client.h>\n\n#ifndef _GAMING_XBOX\n#pragma comment(lib,\"dxguid.lib\")\n#endif\n\n#ifndef IID_GRAPHICS_PPV_ARGS\n#define IID_GRAPHICS_PPV_ARGS(x) IID_PPV_ARGS(x)\n#endif\n\n//\n// The d3dx12.h header includes the following helper C++ classes and functions\n//  CD3DX12_RECT\n//  CD3DX12_BOX\n//  CD3DX12_DEPTH_STENCIL_DESC\n//  CD3DX12_BLEND_DESC\n//  CD3DX12_RASTERIZER_DESC\n//  CD3DX12_RESOURCE_ALLOCATION_INFO\n//  CD3DX12_HEAP_PROPERTIES\n//  CD3DX12_HEAP_DESC\n//  CD3DX12_CLEAR_VALUE\n//  CD3DX12_RANGE\n//  CD3DX12_SHADER_BYTECODE\n//  CD3DX12_TILED_RESOURCE_COORDINATE\n//  CD3DX12_TILE_REGION_SIZE\n//  CD3DX12_SUBRESOURCE_TILING\n//  CD3DX12_TILE_SHAPE\n//  CD3DX12_RESOURCE_BARRIER\n//  CD3DX12_PACKED_MIP_INFO\n//  CD3DX12_SUBRESOURCE_FOOTPRINT\n//  CD3DX12_TEXTURE_COPY_LOCATION\n//  CD3DX12_DESCRIPTOR_RANGE\n//  CD3DX12_ROOT_DESCRIPTOR_TABLE\n//  CD3DX12_ROOT_CONSTANTS\n//  CD3DX12_ROOT_DESCRIPTOR\n//  CD3DX12_ROOT_PARAMETER\n//  CD3DX12_STATIC_SAMPLER_DESC\n//  CD3DX12_ROOT_SIGNATURE_DESC\n//  CD3DX12_CPU_DESCRIPTOR_HANDLE\n//  CD3DX12_GPU_DESCRIPTOR_HANDLE\n//  CD3DX12_RESOURCE_DESC\n//  D3D12CalcSubresource\n//  D3D12DecomposeSubresource\n//  D3D12GetFormatPlaneCount\n//  MemcpySubresource\n//  GetRequiredIntermediateSize\n//  UpdateSubresources\n//  D3D12IsLayoutOpaque\n//  CommandListCast\n// \n\n\nnamespace DirectX\n{\n    constexpr D3D12_CPU_DESCRIPTOR_HANDLE D3D12_CPU_DESCRIPTOR_HANDLE_ZERO = {};\n\n    // Creates a shader resource view from an arbitrary resource\n    void __cdecl CreateShaderResourceView(\n        _In_ ID3D12Device* device,\n        _In_ ID3D12Resource* tex,\n        D3D12_CPU_DESCRIPTOR_HANDLE srvDescriptor,\n        bool isCubeMap = false);\n\n    // Shorthand for creating a root signature\n    inline HRESULT CreateRootSignature(\n        _In_ ID3D12Device* device,\n        _In_ const D3D12_ROOT_SIGNATURE_DESC* rootSignatureDesc,\n        _Out_ ID3D12RootSignature** rootSignature) noexcept\n    {\n        Microsoft::WRL::ComPtr<ID3DBlob> pSignature;\n        Microsoft::WRL::ComPtr<ID3DBlob> pError;\n        HRESULT hr = D3D12SerializeRootSignature(rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, pSignature.GetAddressOf(), pError.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            hr = device->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),\n                IID_GRAPHICS_PPV_ARGS(rootSignature)\n                );\n        }\n        return hr;\n    }\n\n    // Helper for obtaining texture size\n    inline XMUINT2 GetTextureSize(_In_ ID3D12Resource* tex) noexcept\n    {\n        const auto desc = tex->GetDesc();\n        return XMUINT2(static_cast<uint32_t>(desc.Width), static_cast<uint32_t>(desc.Height));\n    }\n\n#if defined(_PIX_H_) || defined(_PIX3_H_)\n    // Scoped PIX event.\n    class ScopedPixEvent\n    {\n    public:\n        ScopedPixEvent(_In_ ID3D12GraphicsCommandList* pCommandList, UINT64 /*metadata*/, PCWSTR pFormat) noexcept\n            : mCommandList(pCommandList)\n        {\n            PIXBeginEvent(pCommandList, 0, pFormat);\n        }\n        ~ScopedPixEvent()\n        {\n            PIXEndEvent(mCommandList);\n        }\n\n    private:\n        ID3D12GraphicsCommandList* mCommandList;\n    };\n#endif\n\n    // Helper sets a D3D resource name string (used by PIX and debug layer leak reporting).\n    template<UINT TNameLength>\n    inline void SetDebugObjectName(_In_ ID3D12DeviceChild* resource, _In_z_ const char(&name)[TNameLength]) noexcept\n    {\n    #if !defined(NO_D3D12_DEBUG_NAME) && (defined(_DEBUG) || defined(PROFILE))\n        wchar_t wname[MAX_PATH];\n        int result = MultiByteToWideChar(CP_UTF8, 0, name, TNameLength, wname, MAX_PATH);\n        if (result > 0)\n        {\n            resource->SetName(wname);\n        }\n    #else\n        UNREFERENCED_PARAMETER(resource);\n        UNREFERENCED_PARAMETER(name);\n    #endif\n    }\n\n    template<UINT TNameLength>\n    inline void SetDebugObjectName(_In_ ID3D12DeviceChild* resource, _In_z_ const wchar_t(&name)[TNameLength]) noexcept\n    {\n    #if !defined(NO_D3D12_DEBUG_NAME) && (defined(_DEBUG) || defined(PROFILE))\n        resource->SetName(name);\n    #else\n        UNREFERENCED_PARAMETER(resource);\n        UNREFERENCED_PARAMETER(name);\n    #endif\n    }\n\n    // Helper for resource barrier.\n    inline void TransitionResource(\n        _In_ ID3D12GraphicsCommandList* commandList,\n        _In_ ID3D12Resource* resource,\n        D3D12_RESOURCE_STATES stateBefore,\n        D3D12_RESOURCE_STATES stateAfter) noexcept\n    {\n        assert(commandList != nullptr);\n        assert(resource != nullptr);\n\n        if (stateBefore == stateAfter)\n            return;\n        \n        D3D12_RESOURCE_BARRIER desc = {};\n        desc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        desc.Transition.pResource = resource;\n        desc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n        desc.Transition.StateBefore = stateBefore;\n        desc.Transition.StateAfter = stateAfter;\n\n        commandList->ResourceBarrier(1, &desc);\n    }\n\n    // Helper which applies one or more resources barriers and then reverses them on destruction.\n    class ScopedBarrier\n    {\n    public:\n        ScopedBarrier(\n            _In_ ID3D12GraphicsCommandList* commandList,\n            std::initializer_list<D3D12_RESOURCE_BARRIER> barriers) noexcept(false)\n            : mCommandList(commandList),\n            mBarriers(barriers)\n        {\n            assert(mBarriers.size() <= UINT32_MAX);\n\n            // Set barriers\n            mCommandList->ResourceBarrier(static_cast<UINT>(mBarriers.size()), mBarriers.data());\n        }\n\n        ScopedBarrier(ScopedBarrier&&) = default;\n        ScopedBarrier& operator= (ScopedBarrier&&) = default;\n\n        ScopedBarrier(ScopedBarrier const&) = delete;\n        ScopedBarrier& operator= (ScopedBarrier const&) = delete;\n\n        ~ScopedBarrier()\n        {\n            // reverse barrier inputs and outputs\n            for (auto& b : mBarriers)\n            {\n                std::swap(b.Transition.StateAfter, b.Transition.StateBefore);\n            }\n\n            // Set barriers\n            mCommandList->ResourceBarrier(static_cast<UINT>(mBarriers.size()), mBarriers.data());\n        }\n\n    private:\n        ID3D12GraphicsCommandList* mCommandList;\n        std::vector<D3D12_RESOURCE_BARRIER> mBarriers;\n    };\n\n    // Helper to check for power-of-2\n    template<typename T>\n    constexpr bool IsPowerOf2(T x) noexcept { return ((x != 0) && !(x & (x - 1))); }\n\n    // Helpers for aligning values by a power of 2\n    template<typename T>\n    inline T AlignDown(T size, size_t alignment) noexcept\n    {\n        if (alignment > 0)\n        {\n            assert(((alignment - 1) & alignment) == 0);\n            auto mask = static_cast<T>(alignment - 1);\n            return size & ~mask;\n        }\n        return size;\n    }\n\n    template<typename T>\n    inline T AlignUp(T size, size_t alignment) noexcept\n    {\n        if (alignment > 0)\n        {\n            assert(((alignment - 1) & alignment) == 0);\n            auto mask = static_cast<T>(alignment - 1);\n            return (size + mask) & ~mask;\n        }\n        return size;\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/EffectPipelineStateDescription.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: EffectPipelineStateDescription.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgiformat.h>\n#endif\n\n#include <cstdint>\n\n#include \"RenderTargetState.h\"\n\n\nnamespace DirectX\n{\n    // Pipeline state information for creating effects.\n    struct EffectPipelineStateDescription\n    {\n        EffectPipelineStateDescription(\n            _In_opt_ const D3D12_INPUT_LAYOUT_DESC* iinputLayout,\n            const D3D12_BLEND_DESC& blend,\n            const D3D12_DEPTH_STENCIL_DESC& depthStencil,\n            const D3D12_RASTERIZER_DESC& rasterizer,\n            const RenderTargetState& renderTarget,\n            D3D12_PRIMITIVE_TOPOLOGY_TYPE iprimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,\n            D3D12_INDEX_BUFFER_STRIP_CUT_VALUE istripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED) noexcept\n            :\n            inputLayout{},\n            blendDesc(blend),\n            depthStencilDesc(depthStencil),\n            rasterizerDesc(rasterizer),\n            renderTargetState(renderTarget),\n            primitiveTopology(iprimitiveTopology),\n            stripCutValue(istripCutValue)\n        {\n            if (iinputLayout)\n                this->inputLayout = *iinputLayout;\n        }\n\n        EffectPipelineStateDescription(const EffectPipelineStateDescription&) = default;\n        EffectPipelineStateDescription& operator=(const EffectPipelineStateDescription&) = default;\n\n        EffectPipelineStateDescription(EffectPipelineStateDescription&&) = default;\n        EffectPipelineStateDescription& operator=(EffectPipelineStateDescription&&) = default;\n\n        void CreatePipelineState(\n            _In_ ID3D12Device* device,\n            _In_ ID3D12RootSignature* rootSignature,\n            const D3D12_SHADER_BYTECODE& vertexShader,\n            const D3D12_SHADER_BYTECODE& pixelShader,\n            _Outptr_ ID3D12PipelineState** pPipelineState) const;\n\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC GetDesc() const noexcept\n        {\n            D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};\n            psoDesc.BlendState = blendDesc;\n            psoDesc.SampleMask = renderTargetState.sampleMask;\n            psoDesc.RasterizerState = rasterizerDesc;\n            psoDesc.DepthStencilState = depthStencilDesc;\n            psoDesc.InputLayout = inputLayout;\n            psoDesc.IBStripCutValue = stripCutValue;\n            psoDesc.PrimitiveTopologyType = primitiveTopology;\n            psoDesc.NumRenderTargets = renderTargetState.numRenderTargets;\n            memcpy_s(psoDesc.RTVFormats, sizeof(psoDesc.RTVFormats), renderTargetState.rtvFormats, sizeof(DXGI_FORMAT) * D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);\n            psoDesc.DSVFormat = renderTargetState.dsvFormat;\n            psoDesc.SampleDesc = renderTargetState.sampleDesc;\n            psoDesc.NodeMask = renderTargetState.nodeMask;\n            return psoDesc;\n        }\n\n        uint32_t ComputeHash() const noexcept;\n\n        D3D12_INPUT_LAYOUT_DESC             inputLayout;\n        D3D12_BLEND_DESC                    blendDesc;\n        D3D12_DEPTH_STENCIL_DESC            depthStencilDesc;\n        D3D12_RASTERIZER_DESC               rasterizerDesc;\n        RenderTargetState                   renderTargetState;\n        D3D12_PRIMITIVE_TOPOLOGY_TYPE       primitiveTopology;\n        D3D12_INDEX_BUFFER_STRIP_CUT_VALUE  stripCutValue;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/Effects.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Effects.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <DirectXMath.h>\n#include <memory>\n#include <string>\n\n#include \"RenderTargetState.h\"\n#include \"EffectPipelineStateDescription.h\"\n\n\nnamespace DirectX\n{\n    class DescriptorHeap;\n    class ResourceUploadBatch;\n\n    //----------------------------------------------------------------------------------\n    // Abstract interface representing any effect which can be applied onto a D3D device context.\n    class IEffect\n    {\n    public:\n        virtual ~IEffect() = default;\n\n        IEffect(const IEffect&) = delete;\n        IEffect& operator=(const IEffect&) = delete;\n\n        IEffect(IEffect&&) = delete;\n        IEffect& operator=(IEffect&&) = delete;\n\n        virtual void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) = 0;\n\n    protected:\n        IEffect() = default;\n    };\n\n\n    // Abstract interface for effects with world, view, and projection matrices.\n    class IEffectMatrices\n    {\n    public:\n        virtual ~IEffectMatrices() = default;\n\n        IEffectMatrices(const IEffectMatrices&) = delete;\n        IEffectMatrices& operator=(const IEffectMatrices&) = delete;\n\n        IEffectMatrices(IEffectMatrices&&) = delete;\n        IEffectMatrices& operator=(IEffectMatrices&&) = delete;\n\n        virtual void XM_CALLCONV SetWorld(FXMMATRIX value) = 0;\n        virtual void XM_CALLCONV SetView(FXMMATRIX value) = 0;\n        virtual void XM_CALLCONV SetProjection(FXMMATRIX value) = 0;\n        virtual void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection);\n\n    protected:\n        IEffectMatrices() = default;\n    };\n\n\n    // Abstract interface for effects which support directional lighting.\n    class IEffectLights\n    {\n    public:\n        virtual ~IEffectLights() = default;\n\n        IEffectLights(const IEffectLights&) = delete;\n        IEffectLights& operator=(const IEffectLights&) = delete;\n\n        IEffectLights(IEffectLights&&) = delete;\n        IEffectLights& operator=(IEffectLights&&) = delete;\n\n        virtual void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) = 0;\n\n        virtual void __cdecl SetLightEnabled(int whichLight, bool value) = 0;\n        virtual void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) = 0;\n        virtual void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) = 0;\n        virtual void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) = 0;\n\n        virtual void __cdecl EnableDefaultLighting() = 0;\n\n        static constexpr int MaxDirectionalLights = 3;\n\n    protected:\n        IEffectLights() = default;\n    };\n\n\n    // Abstract interface for effects which support fog.\n    class IEffectFog\n    {\n    public:\n        virtual ~IEffectFog() = default;\n\n        IEffectFog(const IEffectFog&) = delete;\n        IEffectFog& operator=(const IEffectFog&) = delete;\n\n        IEffectFog(IEffectFog&&) = delete;\n        IEffectFog& operator=(IEffectFog&&) = delete;\n\n        virtual void __cdecl SetFogStart(float value) = 0;\n        virtual void __cdecl SetFogEnd(float value) = 0;\n        virtual void XM_CALLCONV SetFogColor(FXMVECTOR value) = 0;\n\n    protected:\n        IEffectFog() = default;\n    };\n\n\n    // Abstract interface for effects which support skinning\n    class IEffectSkinning\n    {\n    public:\n        virtual ~IEffectSkinning() = default;\n\n        IEffectSkinning(const IEffectSkinning&) = delete;\n        IEffectSkinning& operator=(const IEffectSkinning&) = delete;\n\n        IEffectSkinning(IEffectSkinning&&) = delete;\n        IEffectSkinning& operator=(IEffectSkinning&&) = delete;\n\n        virtual void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) = 0;\n        virtual void __cdecl ResetBoneTransforms() = 0;\n\n        static constexpr int MaxBones = 72;\n\n    protected:\n        IEffectSkinning() = default;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    namespace EffectFlags\n    {\n        constexpr uint32_t None                = 0x00;\n        constexpr uint32_t Fog                 = 0x01;\n        constexpr uint32_t Lighting            = 0x02;\n        constexpr uint32_t PerPixelLighting    = 0x04 | Lighting; // per pixel lighting implies lighting enabled\n        constexpr uint32_t VertexColor         = 0x08;\n        constexpr uint32_t Texture             = 0x10;\n\n        constexpr uint32_t Specular            = 0x100; // enable optional specular/specularMap feature\n        constexpr uint32_t Emissive            = 0x200; // enable optional emissive/emissiveMap feature\n        constexpr uint32_t Fresnel             = 0x400; // enable optional Fresnel feature\n        constexpr uint32_t Velocity            = 0x800; // enable optional velocity feature\n\n        constexpr uint32_t BiasedVertexNormals = 0x10000; // compressed vertex normals need x2 bias\n    }\n\n\n    //----------------------------------------------------------------------------------\n    // Built-in shader supports optional texture mapping, vertex coloring, directional lighting, and fog.\n    class BasicEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog\n    {\n    public:\n        BasicEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n        BasicEffect(BasicEffect&& moveFrom) noexcept;\n        BasicEffect& operator= (BasicEffect&& moveFrom) noexcept;\n\n        BasicEffect(BasicEffect const&) = delete;\n        BasicEffect& operator= (BasicEffect const&) = delete;\n\n        ~BasicEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Material settings.\n        void XM_CALLCONV SetDiffuseColor(FXMVECTOR value);\n        void XM_CALLCONV SetEmissiveColor(FXMVECTOR value);\n        void XM_CALLCONV SetSpecularColor(FXMVECTOR value);\n        void __cdecl SetSpecularPower(float value);\n        void __cdecl DisableSpecular();\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value);\n\n        // Light settings.\n        void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;\n\n        void __cdecl SetLightEnabled(int whichLight, bool value) override;\n        void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;\n\n        void __cdecl EnableDefaultLighting() override;\n\n        // Fog settings.\n        void __cdecl SetFogStart(float value) override;\n        void __cdecl SetFogEnd(float value) override;\n        void XM_CALLCONV SetFogColor(FXMVECTOR value) override;\n\n        // Texture setting.\n        void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    // Built-in shader supports per-pixel alpha testing.\n    class AlphaTestEffect : public IEffect, public IEffectMatrices, public IEffectFog\n    {\n    public:\n        AlphaTestEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription,\n            D3D12_COMPARISON_FUNC alphaFunction = D3D12_COMPARISON_FUNC_GREATER);\n        AlphaTestEffect(AlphaTestEffect&& moveFrom) noexcept;\n        AlphaTestEffect& operator= (AlphaTestEffect&& moveFrom) noexcept;\n\n        AlphaTestEffect(AlphaTestEffect const&) = delete;\n        AlphaTestEffect& operator= (AlphaTestEffect const&) = delete;\n\n        ~AlphaTestEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Material settings.\n        void XM_CALLCONV SetDiffuseColor(FXMVECTOR value);\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value);\n        \n        // Fog settings.\n        void __cdecl SetFogStart(float value) override;\n        void __cdecl SetFogEnd(float value) override;\n        void XM_CALLCONV SetFogColor(FXMVECTOR value) override;\n\n        // Texture setting.\n        void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n\n        // Alpha test settings.\n        void __cdecl SetReferenceAlpha(int value);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    // Built-in shader supports two layer multitexturing (eg. for lightmaps or detail textures).\n    class DualTextureEffect : public IEffect, public IEffectMatrices, public IEffectFog\n    {\n    public:\n        DualTextureEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n        DualTextureEffect(DualTextureEffect&& moveFrom) noexcept;\n        DualTextureEffect& operator= (DualTextureEffect&& moveFrom) noexcept;\n\n        DualTextureEffect(DualTextureEffect const&) = delete;\n        DualTextureEffect& operator= (DualTextureEffect const&) = delete;\n\n        ~DualTextureEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Material settings.\n        void XM_CALLCONV SetDiffuseColor(FXMVECTOR value);\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value);\n        \n        // Fog settings.\n        void __cdecl SetFogStart(float value) override;\n        void __cdecl SetFogEnd(float value) override;\n        void XM_CALLCONV SetFogColor(FXMVECTOR value) override;\n\n        // Texture settings.\n        void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n        void __cdecl SetTexture2(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n        \n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    // Built-in shader supports cubic environment mapping.\n    class EnvironmentMapEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog\n    {\n    public:\n        enum Mapping\n        {\n            Mapping_Cube = 0,       // Cubic environment map\n            Mapping_Sphere,         // Spherical environment map\n            Mapping_DualParabola,   // Dual-parabola environment map (requires Feature Level 10.0)\n        };\n\n        EnvironmentMapEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription,\n            Mapping mapping = Mapping_Cube);\n        EnvironmentMapEffect(EnvironmentMapEffect&& moveFrom) noexcept;\n        EnvironmentMapEffect& operator= (EnvironmentMapEffect&& moveFrom) noexcept;\n\n        EnvironmentMapEffect(EnvironmentMapEffect const&) = delete;\n        EnvironmentMapEffect& operator= (EnvironmentMapEffect const&) = delete;\n\n        ~EnvironmentMapEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Material settings.\n        void XM_CALLCONV SetDiffuseColor(FXMVECTOR value);\n        void XM_CALLCONV SetEmissiveColor(FXMVECTOR value);\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value);\n        \n        // Light settings.\n        void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;\n\n        void __cdecl SetLightEnabled(int whichLight, bool value) override;\n        void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override;\n\n        void __cdecl EnableDefaultLighting() override;\n\n        // Fog settings.\n        void __cdecl SetFogStart(float value) override;\n        void __cdecl SetFogEnd(float value) override;\n        void XM_CALLCONV SetFogColor(FXMVECTOR value) override;\n\n        // Texture setting.\n        void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE texture, D3D12_GPU_DESCRIPTOR_HANDLE sampler);\n\n        // Environment map settings.\n        void __cdecl SetEnvironmentMap(D3D12_GPU_DESCRIPTOR_HANDLE texture, D3D12_GPU_DESCRIPTOR_HANDLE sampler);\n        void __cdecl SetEnvironmentMapAmount(float value);\n        void XM_CALLCONV SetEnvironmentMapSpecular(FXMVECTOR value);\n        void __cdecl SetFresnelFactor(float value);\n        \n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        // Unsupported interface methods.\n        void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;\n    };\n\n\n    // Built-in shader supports skinned animation.\n    class SkinnedEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog, public IEffectSkinning\n    {\n    public:\n        SkinnedEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n        SkinnedEffect(SkinnedEffect&& moveFrom) noexcept;\n        SkinnedEffect& operator= (SkinnedEffect&& moveFrom) noexcept;\n\n        SkinnedEffect(SkinnedEffect const&) = delete;\n        SkinnedEffect& operator= (SkinnedEffect const&) = delete;\n\n        ~SkinnedEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Material settings.\n        void XM_CALLCONV SetDiffuseColor(FXMVECTOR value);\n        void XM_CALLCONV SetEmissiveColor(FXMVECTOR value);\n        void XM_CALLCONV SetSpecularColor(FXMVECTOR value);\n        void __cdecl SetSpecularPower(float value);\n        void __cdecl DisableSpecular();\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value);\n        \n        // Light settings.\n        void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;\n\n        void __cdecl SetLightEnabled(int whichLight, bool value) override;\n        void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;\n\n        void __cdecl EnableDefaultLighting() override;\n\n        // Fog settings.\n        void __cdecl SetFogStart(float value) override;\n        void __cdecl SetFogEnd(float value) override;\n        void XM_CALLCONV SetFogColor(FXMVECTOR value) override;\n\n        // Texture setting.\n        void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n        \n        // Animation settings.\n        void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override;\n        void __cdecl ResetBoneTransforms() override;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Built-in shader extends BasicEffect with normal map and optional specular map\n    class NormalMapEffect : public IEffect, public IEffectMatrices, public IEffectLights, public IEffectFog\n    {\n    public:\n        NormalMapEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n        NormalMapEffect(NormalMapEffect&& moveFrom) noexcept;\n        NormalMapEffect& operator= (NormalMapEffect&& moveFrom) noexcept;\n\n        NormalMapEffect(NormalMapEffect const&) = delete;\n        NormalMapEffect& operator= (NormalMapEffect const&) = delete;\n\n        ~NormalMapEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Material settings.\n        void XM_CALLCONV SetDiffuseColor(FXMVECTOR value);\n        void XM_CALLCONV SetEmissiveColor(FXMVECTOR value);\n        void XM_CALLCONV SetSpecularColor(FXMVECTOR value);\n        void __cdecl SetSpecularPower(float value);\n        void __cdecl DisableSpecular();\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value);\n\n        // Light settings.\n        void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;\n\n        void __cdecl SetLightEnabled(int whichLight, bool value) override;\n        void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;\n\n        void __cdecl EnableDefaultLighting() override;\n\n        // Fog settings.\n        void __cdecl SetFogStart(float value) override;\n        void __cdecl SetFogEnd(float value) override;\n        void XM_CALLCONV SetFogColor(FXMVECTOR value) override;\n\n        // Texture setting - albedo, normal and specular intensity\n        void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n        void __cdecl SetNormalTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n        void __cdecl SetSpecularTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Built-in shader for Physically-Based Rendering (Roughness/Metalness) with Image-based lighting\n    class PBREffect : public IEffect, public IEffectMatrices, public IEffectLights\n    {\n    public:\n        PBREffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n        PBREffect(PBREffect&& moveFrom) noexcept;\n        PBREffect& operator= (PBREffect&& moveFrom) noexcept;\n\n        PBREffect(PBREffect const&) = delete;\n        PBREffect& operator= (PBREffect const&) = delete;\n\n        ~PBREffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Light settings.\n        void __cdecl SetLightEnabled(int whichLight, bool value) override;\n        void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override;\n        void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override;\n\n        void __cdecl EnableDefaultLighting() override;\n\n        // PBR Settings.\n        void __cdecl SetAlpha(float value);\n        void XM_CALLCONV SetConstantAlbedo(FXMVECTOR value);\n        void __cdecl SetConstantMetallic(float value);\n        void __cdecl SetConstantRoughness(float value);\n\n        // Texture settings.\n        void __cdecl SetAlbedoTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor);\n        void __cdecl SetNormalTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n        void __cdecl SetRMATexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n\n        void __cdecl SetEmissiveTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n\n        void __cdecl SetSurfaceTextures(\n            D3D12_GPU_DESCRIPTOR_HANDLE albedo,\n            D3D12_GPU_DESCRIPTOR_HANDLE normal,\n            D3D12_GPU_DESCRIPTOR_HANDLE roughnessMetallicAmbientOcclusion,\n            D3D12_GPU_DESCRIPTOR_HANDLE sampler);\n\n        void __cdecl SetIBLTextures(\n            D3D12_GPU_DESCRIPTOR_HANDLE radiance,\n            int numRadianceMips,\n            D3D12_GPU_DESCRIPTOR_HANDLE irradiance,\n            D3D12_GPU_DESCRIPTOR_HANDLE sampler);\n\n        // Render target size, required for velocity buffer output.\n        void __cdecl SetRenderTargetSizeInPixels(int width, int height);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        // Unsupported interface methods.\n        void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;\n        void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Built-in shader for debug visualization of normals, tangents, etc.\n    class DebugEffect : public IEffect, public IEffectMatrices\n    {\n    public:\n        enum Mode\n        {\n            Mode_Default = 0,   // Hemispherical ambient lighting\n            Mode_Normals,       // RGB normals\n            Mode_Tangents,      // RGB tangents\n            Mode_BiTangents,    // RGB bi-tangents\n        };\n\n        DebugEffect(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription,\n            Mode debugMode = Mode_Default);\n        DebugEffect(DebugEffect&& moveFrom) noexcept;\n        DebugEffect& operator= (DebugEffect&& moveFrom) noexcept;\n\n        DebugEffect(DebugEffect const&) = delete;\n        DebugEffect& operator= (DebugEffect const&) = delete;\n\n        ~DebugEffect() override;\n\n        // IEffect methods.\n        void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Camera settings.\n        void XM_CALLCONV SetWorld(FXMMATRIX value) override;\n        void XM_CALLCONV SetView(FXMMATRIX value) override;\n        void XM_CALLCONV SetProjection(FXMMATRIX value) override;\n        void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override;\n\n        // Debug Settings.\n        void XM_CALLCONV SetHemisphericalAmbientColor(FXMVECTOR upper, FXMVECTOR lower);\n        void __cdecl SetAlpha(float value);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Abstract interface to factory texture resources\n    class IEffectTextureFactory\n    {\n    public:\n        virtual ~IEffectTextureFactory() = default;\n\n        IEffectTextureFactory(const IEffectTextureFactory&) = delete;\n        IEffectTextureFactory& operator=(const IEffectTextureFactory&) = delete;\n\n        IEffectTextureFactory(IEffectTextureFactory&&) = delete;\n        IEffectTextureFactory& operator=(IEffectTextureFactory&&) = delete;\n\n        virtual size_t __cdecl CreateTexture(_In_z_ const wchar_t* name, int descriptorIndex) = 0;\n\n    protected:\n        IEffectTextureFactory() = default;\n    };\n\n\n    // Factory for sharing texture resources\n    class EffectTextureFactory : public IEffectTextureFactory\n    {\n    public:\n        EffectTextureFactory(\n            _In_ ID3D12Device* device,\n            ResourceUploadBatch& resourceUploadBatch,\n            _In_ ID3D12DescriptorHeap* descriptorHeap) noexcept(false);\n\n        EffectTextureFactory(\n            _In_ ID3D12Device* device,\n            ResourceUploadBatch& resourceUploadBatch,\n            _In_ size_t numDescriptors,\n            _In_ D3D12_DESCRIPTOR_HEAP_FLAGS descriptorHeapFlags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) noexcept(false);\n\n        EffectTextureFactory(EffectTextureFactory&& moveFrom) noexcept;\n        EffectTextureFactory& operator= (EffectTextureFactory&& moveFrom) noexcept;\n\n        EffectTextureFactory(EffectTextureFactory const&) = delete;\n        EffectTextureFactory& operator= (EffectTextureFactory const&) = delete;\n\n        ~EffectTextureFactory() override;\n\n        size_t __cdecl CreateTexture(_In_z_ const wchar_t* name, int descriptorIndex) override;\n\n        ID3D12DescriptorHeap* __cdecl Heap() const noexcept;\n\n        // Shorthand accessors for the descriptor heap\n        D3D12_CPU_DESCRIPTOR_HANDLE __cdecl GetCpuDescriptorHandle(size_t index) const;\n        D3D12_GPU_DESCRIPTOR_HANDLE __cdecl GetGpuDescriptorHandle(size_t index) const;\n\n        // How many textures are there in this factory?\n        size_t __cdecl ResourceCount() const noexcept;\n\n        // Get a resource in a specific slot (note: increases reference count on resource)\n        void __cdecl GetResource(size_t slot, _Out_ ID3D12Resource** resource, _Out_opt_ bool* isCubeMap = nullptr);\n\n        // Settings.\n        void __cdecl ReleaseCache();\n\n        void __cdecl SetSharing(bool enabled) noexcept;\n\n        void __cdecl EnableForceSRGB(bool forceSRGB) noexcept;\n        void __cdecl EnableAutoGenMips(bool generateMips) noexcept;\n\n        void __cdecl SetDirectory(_In_opt_z_ const wchar_t* path) noexcept;\n\n    private:\n        // Private implementation\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Abstract interface to factory for sharing effects\n    class IEffectFactory\n    {\n    public:\n        virtual ~IEffectFactory() = default;\n\n        IEffectFactory(const IEffectFactory&) = delete;\n        IEffectFactory& operator=(const IEffectFactory&) = delete;\n\n        IEffectFactory(IEffectFactory&&) = delete;\n        IEffectFactory& operator=(IEffectFactory&&) = delete;\n\n        struct EffectInfo\n        {\n            std::wstring        name;\n            bool                perVertexColor;\n            bool                enableSkinning;\n            bool                enableDualTexture;\n            bool                enableNormalMaps;\n            bool                biasedVertexNormals;\n            float               specularPower;\n            float               alphaValue;\n            XMFLOAT3            ambientColor;\n            XMFLOAT3            diffuseColor;\n            XMFLOAT3            specularColor;\n            XMFLOAT3            emissiveColor;\n            int                 diffuseTextureIndex;\n            int                 specularTextureIndex;\n            int                 normalTextureIndex;\n            int                 emissiveTextureIndex;\n            int                 samplerIndex;\n            int                 samplerIndex2;\n\n            EffectInfo() noexcept\n                : perVertexColor(false)\n                , enableSkinning(false)\n                , enableDualTexture(false)\n                , enableNormalMaps(false)\n                , biasedVertexNormals(false)\n                , specularPower(0)\n                , alphaValue(0)\n                , ambientColor(0, 0, 0)\n                , diffuseColor(0, 0, 0)\n                , specularColor(0, 0, 0)\n                , emissiveColor(0, 0, 0)\n                , diffuseTextureIndex(-1)\n                , specularTextureIndex(-1)\n                , normalTextureIndex(-1)\n                , emissiveTextureIndex(-1)\n                , samplerIndex(-1)\n                , samplerIndex2(-1)\n            {\n            }\n        };\n\n        virtual std::shared_ptr<IEffect> __cdecl CreateEffect(\n            const EffectInfo& info, \n            const EffectPipelineStateDescription& opaquePipelineState,\n            const EffectPipelineStateDescription& alphaPipelineState,\n            const D3D12_INPUT_LAYOUT_DESC& inputLayout, \n            int textureDescriptorOffset = 0,\n            int samplerDescriptorOffset = 0) = 0;\n\n    protected:\n        IEffectFactory() = default;\n    };\n\n\n    // Factory for sharing effects\n    class EffectFactory : public IEffectFactory\n    {\n    public:\n        EffectFactory(_In_ ID3D12Device* device);\n        EffectFactory(\n            _In_ ID3D12DescriptorHeap* textureDescriptors,\n            _In_ ID3D12DescriptorHeap* samplerDescriptors);\n\n        EffectFactory(EffectFactory&& moveFrom) noexcept;\n        EffectFactory& operator= (EffectFactory&& moveFrom) noexcept;\n\n        EffectFactory(EffectFactory const&) = delete;\n        EffectFactory& operator= (EffectFactory const&) = delete;\n\n        ~EffectFactory() override;\n\n        // IEffectFactory methods.\n        virtual std::shared_ptr<IEffect> __cdecl CreateEffect(\n            const EffectInfo& info,\n            const EffectPipelineStateDescription& opaquePipelineState,\n            const EffectPipelineStateDescription& alphaPipelineState,\n            const D3D12_INPUT_LAYOUT_DESC& inputLayout,\n            int textureDescriptorOffset = 0,\n            int samplerDescriptorOffset = 0) override;\n\n        // Settings.\n        void __cdecl ReleaseCache();\n\n        void __cdecl SetSharing(bool enabled) noexcept;\n\n        void __cdecl EnablePerPixelLighting(bool enabled) noexcept;\n\n        void __cdecl EnableNormalMapEffect(bool enabled) noexcept;\n\n        void __cdecl EnableFogging(bool enabled) noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::shared_ptr<Impl> pImpl;\n    };\n\n\n    // Factory for Physically Based Rendering (PBR)\n    class PBREffectFactory : public IEffectFactory\n    {\n    public:\n        PBREffectFactory(_In_ ID3D12Device* device) noexcept(false);\n        PBREffectFactory(\n            _In_ ID3D12DescriptorHeap* textureDescriptors,\n            _In_ ID3D12DescriptorHeap* samplerDescriptors) noexcept(false);\n\n        PBREffectFactory(PBREffectFactory&& moveFrom) noexcept;\n        PBREffectFactory& operator= (PBREffectFactory&& moveFrom) noexcept;\n\n        PBREffectFactory(PBREffectFactory const&) = delete;\n        PBREffectFactory& operator= (PBREffectFactory const&) = delete;\n\n        ~PBREffectFactory() override;\n\n        // IEffectFactory methods.\n        virtual std::shared_ptr<IEffect> __cdecl CreateEffect(\n            const EffectInfo& info,\n            const EffectPipelineStateDescription& opaquePipelineState,\n            const EffectPipelineStateDescription& alphaPipelineState,\n            const D3D12_INPUT_LAYOUT_DESC& inputLayout,\n            int textureDescriptorOffset = 0,\n            int samplerDescriptorOffset = 0) override;\n\n        // Settings.\n        void __cdecl ReleaseCache();\n\n        void __cdecl SetSharing(bool enabled) noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::shared_ptr<Impl> pImpl;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/GamePad.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: GamePad.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#if (_WIN32_WINNT < 0x0A00 /*_WIN32_WINNT_WIN10*/) || defined(_GAMING_DESKTOP)\n#ifndef _XBOX_ONE\n#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)\n#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/ )\n#pragma comment(lib,\"xinput.lib\")\n#else\n#pragma comment(lib,\"xinput9_1_0.lib\")\n#endif\n#endif\n#endif\n#endif\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\ninterface IGameInputDevice;\n#endif\n\n#include <cstdint>\n#include <memory>\n\n#if (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/) && !defined(_GAMING_DESKTOP)\n#pragma comment(lib,\"runtimeobject.lib\")\n#include <string>\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#endif\n\n\nnamespace DirectX\n{\n    class GamePad\n    {\n    public:\n        GamePad() noexcept(false);\n        GamePad(GamePad&& moveFrom) noexcept;\n        GamePad& operator= (GamePad&& moveFrom) noexcept;\n\n        GamePad(GamePad const&) = delete;\n        GamePad& operator=(GamePad const&) = delete;\n\n        virtual ~GamePad();\n\n    #if ((_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/) && !defined(_GAMING_DESKTOP)) || defined(_XBOX_ONE)\n        static constexpr int MAX_PLAYER_COUNT = 8;\n    #else\n        static constexpr int MAX_PLAYER_COUNT = 4;\n    #endif\n\n        enum DeadZone\n        {\n            DEAD_ZONE_INDEPENDENT_AXES = 0,\n            DEAD_ZONE_CIRCULAR,\n            DEAD_ZONE_NONE,\n        };\n\n        struct Buttons\n        {\n            bool a;\n            bool b;\n            bool x;\n            bool y;\n            bool leftStick;\n            bool rightStick;\n            bool leftShoulder;\n            bool rightShoulder;\n            union\n            {\n                bool back;\n                bool view;\n            };\n            union\n            {\n                bool start;\n                bool menu;\n            };\n        };\n\n        struct DPad\n        {\n            bool up;\n            bool down;\n            bool right;\n            bool left;\n        };\n\n        struct ThumbSticks\n        {\n            float leftX;\n            float leftY;\n            float rightX;\n            float rightY;\n        };\n\n        struct Triggers\n        {\n            float left;\n            float right;\n        };\n\n        struct State\n        {\n            bool        connected;\n            uint64_t    packet;\n            Buttons     buttons;\n            DPad        dpad;\n            ThumbSticks thumbSticks;\n            Triggers    triggers;\n\n            bool __cdecl IsConnected() const noexcept { return connected; }\n\n            // Is the button pressed currently?\n            bool __cdecl IsAPressed() const noexcept { return buttons.a; }\n            bool __cdecl IsBPressed() const noexcept { return buttons.b; }\n            bool __cdecl IsXPressed() const noexcept { return buttons.x; }\n            bool __cdecl IsYPressed() const noexcept { return buttons.y; }\n\n            bool __cdecl IsLeftStickPressed() const noexcept { return buttons.leftStick; }\n            bool __cdecl IsRightStickPressed() const noexcept { return buttons.rightStick; }\n\n            bool __cdecl IsLeftShoulderPressed() const noexcept { return buttons.leftShoulder; }\n            bool __cdecl IsRightShoulderPressed() const noexcept { return buttons.rightShoulder; }\n\n            bool __cdecl IsBackPressed() const noexcept { return buttons.back; }\n            bool __cdecl IsViewPressed() const noexcept { return buttons.view; }\n            bool __cdecl IsStartPressed() const noexcept { return buttons.start; }\n            bool __cdecl IsMenuPressed() const noexcept { return buttons.menu; }\n\n            bool __cdecl IsDPadDownPressed() const noexcept { return dpad.down; }\n            bool __cdecl IsDPadUpPressed() const noexcept { return dpad.up; }\n            bool __cdecl IsDPadLeftPressed() const noexcept { return dpad.left; }\n            bool __cdecl IsDPadRightPressed() const noexcept { return dpad.right; }\n\n            bool __cdecl IsLeftThumbStickUp() const noexcept { return (thumbSticks.leftY > 0.5f) != 0; }\n            bool __cdecl IsLeftThumbStickDown() const noexcept { return (thumbSticks.leftY < -0.5f) != 0; }\n            bool __cdecl IsLeftThumbStickLeft() const noexcept { return (thumbSticks.leftX < -0.5f) != 0; }\n            bool __cdecl IsLeftThumbStickRight() const noexcept { return (thumbSticks.leftX > 0.5f) != 0; }\n\n            bool __cdecl IsRightThumbStickUp() const noexcept { return (thumbSticks.rightY > 0.5f) != 0; }\n            bool __cdecl IsRightThumbStickDown() const noexcept { return (thumbSticks.rightY < -0.5f) != 0; }\n            bool __cdecl IsRightThumbStickLeft() const noexcept { return (thumbSticks.rightX < -0.5f) != 0; }\n            bool __cdecl IsRightThumbStickRight() const noexcept { return (thumbSticks.rightX > 0.5f) != 0; }\n\n            bool __cdecl IsLeftTriggerPressed() const noexcept { return (triggers.left > 0.5f) != 0; }\n            bool __cdecl IsRightTriggerPressed() const noexcept { return (triggers.right > 0.5f) != 0; }\n        };\n\n        struct Capabilities\n        {\n            enum Type\n            {\n                UNKNOWN = 0,\n                GAMEPAD,\n                WHEEL,\n                ARCADE_STICK,\n                FLIGHT_STICK,\n                DANCE_PAD,\n                GUITAR,\n                GUITAR_ALTERNATE,\n                DRUM_KIT,\n                GUITAR_BASS = 11,\n                ARCADE_PAD = 19,\n            };\n\n            bool                connected;\n            Type                gamepadType;\n        #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n            APP_LOCAL_DEVICE_ID id;\n        #elif (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/) && !defined(_GAMING_DESKTOP)\n            std::wstring        id;\n        #else\n            uint64_t            id;\n        #endif\n            uint16_t            vid;\n            uint16_t            pid;\n\n            Capabilities() noexcept : connected(false), gamepadType(UNKNOWN), id{}, vid(0), pid(0) {}\n\n            bool __cdecl IsConnected() const noexcept { return connected; }\n        };\n\n        class ButtonStateTracker\n        {\n        public:\n            enum ButtonState\n            {\n                UP = 0,         // Button is up\n                HELD = 1,       // Button is held down\n                RELEASED = 2,   // Button was just released\n                PRESSED = 3,    // Buton was just pressed\n            };\n\n            ButtonState a;\n            ButtonState b;\n            ButtonState x;\n            ButtonState y;\n\n            ButtonState leftStick;\n            ButtonState rightStick;\n\n            ButtonState leftShoulder;\n            ButtonState rightShoulder;\n\n            union\n            {\n                ButtonState back;\n                ButtonState view;\n            };\n\n            union\n            {\n                ButtonState start;\n                ButtonState menu;\n            };\n\n            ButtonState dpadUp;\n            ButtonState dpadDown;\n            ButtonState dpadLeft;\n            ButtonState dpadRight;\n\n            ButtonState leftStickUp;\n            ButtonState leftStickDown;\n            ButtonState leftStickLeft;\n            ButtonState leftStickRight;\n\n            ButtonState rightStickUp;\n            ButtonState rightStickDown;\n            ButtonState rightStickLeft;\n            ButtonState rightStickRight;\n\n            ButtonState leftTrigger;\n            ButtonState rightTrigger;\n\n            #pragma prefast(suppress: 26495, \"Reset() performs the initialization\")\n            ButtonStateTracker() noexcept { Reset(); }\n\n            void __cdecl Update(const State& state) noexcept;\n\n            void __cdecl Reset() noexcept;\n\n            State __cdecl GetLastState() const noexcept { return lastState; }\n\n        private:\n            State lastState;\n        };\n\n        // Retrieve the current state of the gamepad of the associated player index\n        State __cdecl GetState(int player, DeadZone deadZoneMode = DEAD_ZONE_INDEPENDENT_AXES);\n\n        // Retrieve the current capabilities of the gamepad of the associated player index\n        Capabilities __cdecl GetCapabilities(int player);\n\n        // Set the vibration motor speeds of the gamepad\n        bool __cdecl SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger = 0.f, float rightTrigger = 0.f) noexcept;\n\n        // Handle suspending/resuming\n        void __cdecl Suspend() noexcept;\n        void __cdecl Resume() noexcept;\n\n    #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n        void __cdecl RegisterEvents(void* ctrlChanged) noexcept;\n    #elif ((_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/ ) && !defined(_GAMING_DESKTOP)) || defined(_XBOX_ONE)\n        void __cdecl RegisterEvents(void* ctrlChanged, void* userChanged) noexcept;\n    #endif\n\n    #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n        // Underlying device access\n        void __cdecl GetDevice(int player, _Outptr_ IGameInputDevice** device) noexcept;\n    #endif\n\n        // Singleton\n        static GamePad& __cdecl Get();\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/GeometricPrimitive.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: GeometricPrimitive.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"VertexTypes.h\"\n\n#include <memory>\n#include <vector>\n\n\nnamespace DirectX\n{\n    class IEffect;\n    class ResourceUploadBatch;\n\n    class GeometricPrimitive\n    {\n    public:\n        GeometricPrimitive(GeometricPrimitive&&) = default;\n        GeometricPrimitive& operator= (GeometricPrimitive&&) = default;\n\n        GeometricPrimitive(GeometricPrimitive const&) = delete;\n        GeometricPrimitive& operator= (GeometricPrimitive const&) = delete;\n\n        virtual ~GeometricPrimitive();\n\n        using VertexType = VertexPositionNormalTexture;\n\n        // Factory methods.\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateCube(float size = 1, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateBox(const XMFLOAT3& size, bool rhcoords = true, bool invertn = false, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateSphere(float diameter = 1, size_t tessellation = 16, bool rhcoords = true, bool invertn = false, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateGeoSphere(float diameter = 1, size_t tessellation = 3, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateCylinder(float height = 1, float diameter = 1, size_t tessellation = 32, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateCone(float diameter = 1, float height = 1, size_t tessellation = 32, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateTorus(float diameter = 1, float thickness = 0.333f, size_t tessellation = 32, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateTetrahedron(float size = 1, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateOctahedron(float size = 1, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateDodecahedron(float size = 1, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateIcosahedron(float size = 1, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateTeapot(float size = 1, size_t tessellation = 8, bool rhcoords = true, _In_opt_ ID3D12Device* device = nullptr);\n        static std::unique_ptr<GeometricPrimitive> __cdecl CreateCustom(const std::vector<VertexType>& vertices, const std::vector<uint16_t>& indices, _In_opt_ ID3D12Device* device = nullptr);\n\n        static void __cdecl CreateCube(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float size = 1, bool rhcoords = true);\n        static void __cdecl CreateBox(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, const XMFLOAT3& size, bool rhcoords = true, bool invertn = false);\n        static void __cdecl CreateSphere(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float diameter = 1, size_t tessellation = 16, bool rhcoords = true, bool invertn = false);\n        static void __cdecl CreateGeoSphere(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float diameter = 1, size_t tessellation = 3, bool rhcoords = true);\n        static void __cdecl CreateCylinder(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float height = 1, float diameter = 1, size_t tessellation = 32, bool rhcoords = true);\n        static void __cdecl CreateCone(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float diameter = 1, float height = 1, size_t tessellation = 32, bool rhcoords = true);\n        static void __cdecl CreateTorus(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float diameter = 1, float thickness = 0.333f, size_t tessellation = 32, bool rhcoords = true);\n        static void __cdecl CreateTetrahedron(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float size = 1, bool rhcoords = true);\n        static void __cdecl CreateOctahedron(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float size = 1, bool rhcoords = true);\n        static void __cdecl CreateDodecahedron(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float size = 1, bool rhcoords = true);\n        static void __cdecl CreateIcosahedron(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float size = 1, bool rhcoords = true);\n        static void __cdecl CreateTeapot(std::vector<VertexType>& vertices, std::vector<uint16_t>& indices, float size = 1, size_t tessellation = 8, bool rhcoords = true);\n\n        // Load VB/IB resources for static geometry.\n        void __cdecl LoadStaticBuffers(\n            _In_ ID3D12Device* device,\n            ResourceUploadBatch& resourceUploadBatch);\n\n        // Transition VB/IB resources for static geometry.\n        void __cdecl Transition(\n            _In_ ID3D12GraphicsCommandList* commandList,\n            D3D12_RESOURCE_STATES stateBeforeVB,\n            D3D12_RESOURCE_STATES stateAfterVB,\n            D3D12_RESOURCE_STATES stateBeforeIB,\n            D3D12_RESOURCE_STATES stateAfterIB);\n\n        // Draw the primitive.\n        void __cdecl Draw(_In_ ID3D12GraphicsCommandList* commandList) const;\n\n    private:\n        GeometricPrimitive() noexcept(false);\n\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/GraphicsMemory.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: GraphicsMemory.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <memory>\n\n\nnamespace DirectX\n{\n    class LinearAllocatorPage;\n\n    // Works a little like a smart pointer. The memory will only be fenced by the GPU once the pointer\n    // has been invalidated or the user explicitly marks it for fencing.\n    class GraphicsResource\n    {\n    public:\n        GraphicsResource() noexcept;\n        GraphicsResource(\n            _In_ LinearAllocatorPage* page,\n            _In_ D3D12_GPU_VIRTUAL_ADDRESS gpuAddress,\n            _In_ ID3D12Resource* resource,\n            _In_ void* memory, \n            _In_ size_t offset,\n            _In_ size_t size) noexcept;\n\n        GraphicsResource(GraphicsResource&& other) noexcept;\n        GraphicsResource&& operator= (GraphicsResource&&) noexcept;\n\n        GraphicsResource(const GraphicsResource&) = delete;\n        GraphicsResource& operator= (const GraphicsResource&) = delete;\n\n        ~GraphicsResource();\n\n        D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const noexcept { return mGpuAddress; }\n        ID3D12Resource* Resource() const noexcept { return mResource; }\n        void* Memory() const noexcept { return mMemory; }\n        size_t ResourceOffset() const noexcept { return mBufferOffset; }\n        size_t Size() const noexcept { return mSize; }\n        \n        explicit operator bool () const noexcept { return mResource != nullptr; }\n\n        // Clear the pointer. Using operator -> will produce bad results.\n        void __cdecl Reset() noexcept;\n        void __cdecl Reset(GraphicsResource&&) noexcept;\n\n    private:\n        LinearAllocatorPage*        mPage;\n        D3D12_GPU_VIRTUAL_ADDRESS   mGpuAddress;\n        ID3D12Resource*             mResource;\n        void*                       mMemory;\n        size_t                      mBufferOffset;\n        size_t                      mSize;\n    };\n\n    class SharedGraphicsResource\n    {\n    public:\n        SharedGraphicsResource() noexcept;\n\n        SharedGraphicsResource(SharedGraphicsResource&&) noexcept;\n        SharedGraphicsResource&& operator= (SharedGraphicsResource&&) noexcept;\n\n        SharedGraphicsResource(GraphicsResource&&);\n        SharedGraphicsResource&& operator= (GraphicsResource&&);\n\n        SharedGraphicsResource(const SharedGraphicsResource&) noexcept;\n        SharedGraphicsResource& operator= (const SharedGraphicsResource&) noexcept;\n\n        SharedGraphicsResource(const GraphicsResource&) = delete;\n        SharedGraphicsResource& operator= (const GraphicsResource&) = delete;\n\n        ~SharedGraphicsResource();\n\n        D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const noexcept { return mSharedResource->GpuAddress(); }\n        ID3D12Resource* Resource() const noexcept { return mSharedResource->Resource(); }\n        void* Memory() const noexcept { return mSharedResource->Memory(); }\n        size_t ResourceOffset() const noexcept { return mSharedResource->ResourceOffset(); }\n        size_t Size() const noexcept { return mSharedResource->Size(); }\n        \n        explicit operator bool () const noexcept { return mSharedResource != nullptr; }\n\n        bool operator == (const SharedGraphicsResource& other) const noexcept { return mSharedResource.get() == other.mSharedResource.get(); }\n        bool operator != (const SharedGraphicsResource& other) const noexcept { return mSharedResource.get() != other.mSharedResource.get(); }\n\n        // Clear the pointer. Using operator -> will produce bad results.\n        void __cdecl Reset() noexcept;\n        void __cdecl Reset(GraphicsResource&&);\n        void __cdecl Reset(SharedGraphicsResource&&) noexcept;\n        void __cdecl Reset(const SharedGraphicsResource& resource) noexcept;\n        \n    private:\n        std::shared_ptr<GraphicsResource> mSharedResource;\n    };\n\n    //----------------------------------------------------------------------------------\n    struct GraphicsMemoryStatistics\n    {\n        size_t committedMemory;     // Bytes of memory currently committed/in-flight\n        size_t totalMemory;         // Total bytes of memory used by the allocators\n        size_t totalPages;          // Total page count\n        size_t peakCommitedMemory;  // Peak commited memory value since last reset\n        size_t peakTotalMemory;     // Peak total bytes\n        size_t peakTotalPages;      // Peak total page count\n    };\n\n    //----------------------------------------------------------------------------------\n    class GraphicsMemory\n    {\n    public:\n        explicit GraphicsMemory(_In_ ID3D12Device* device);\n\n        GraphicsMemory(GraphicsMemory&& moveFrom) noexcept;\n        GraphicsMemory& operator= (GraphicsMemory&& moveFrom) noexcept;\n\n        GraphicsMemory(GraphicsMemory const&) = delete;\n        GraphicsMemory& operator=(GraphicsMemory const&) = delete;\n\n        virtual ~GraphicsMemory();\n\n        // Make sure to keep the GraphicsResource handle alive as long as you need to access\n        // the memory on the CPU. For example, do not simply cache GpuAddress() and discard\n        // the GraphicsResource object, or your memory may be overwritten later.\n        GraphicsResource __cdecl Allocate(size_t size, size_t alignment = 16);\n\n        // Special overload of Allocate that aligns to D3D12 constant buffer alignment requirements\n        template<typename T> GraphicsResource AllocateConstant()\n        {\n            const size_t alignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;\n            const size_t alignedSize = (sizeof(T) + alignment - 1) & ~(alignment - 1);\n            return Allocate(alignedSize, alignment);\n        }\n        template<typename T> GraphicsResource AllocateConstant(const T& setData)\n        {\n            GraphicsResource alloc = AllocateConstant<T>();\n            memcpy(alloc.Memory(), &setData, sizeof(T));\n            return alloc;\n        }\n\n        // Submits all the pending one-shot memory to the GPU. \n        // The memory will be recycled once the GPU is done with it.\n        void __cdecl Commit(_In_ ID3D12CommandQueue* commandQueue);\n\n        // This frees up any unused memory. \n        // If you want to make sure all memory is reclaimed, idle the GPU before calling this.\n        // It is not recommended that you call this unless absolutely necessary (e.g. your\n        // memory budget changes at run-time, or perhaps you're changing levels in your game.)\n        void __cdecl GarbageCollect();\n\n        // Memory statistics\n        GraphicsMemoryStatistics __cdecl GetStatistics();\n        void __cdecl ResetStatistics();\n\n        // Singleton\n        // Should only use nullptr for single GPU scenarios; mGPU requires a specific device\n        static GraphicsMemory& __cdecl Get(_In_opt_ ID3D12Device* device = nullptr);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/Keyboard.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Keyboard.h\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#if (defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) || (defined(_XBOX_ONE) && defined(_TITLE))\n#ifndef USING_COREWINDOW\n#define USING_COREWINDOW\n#endif\n#endif\n\n#include <cstdint>\n#include <memory>\n\n#ifdef USING_COREWINDOW\nnamespace ABI { namespace Windows { namespace UI { namespace Core { struct ICoreWindow; } } } }\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#endif\n\n\nnamespace DirectX\n{\n    class Keyboard\n    {\n    public:\n        Keyboard() noexcept(false);\n\n        Keyboard(Keyboard&&) noexcept;\n        Keyboard& operator= (Keyboard&&) noexcept;\n\n        Keyboard(Keyboard const&) = delete;\n        Keyboard& operator=(Keyboard const&) = delete;\n\n        virtual ~Keyboard();\n\n        enum Keys : unsigned char\n        {\n            None = 0,\n\n            Back = 0x8,\n            Tab = 0x9,\n\n            Enter = 0xd,\n\n            Pause = 0x13,\n            CapsLock = 0x14,\n            Kana = 0x15,\n            ImeOn = 0x16,\n\n            Kanji = 0x19,\n\n            ImeOff = 0x1a,\n            Escape = 0x1b,\n            ImeConvert = 0x1c,\n            ImeNoConvert = 0x1d,\n\n            Space = 0x20,\n            PageUp = 0x21,\n            PageDown = 0x22,\n            End = 0x23,\n            Home = 0x24,\n            Left = 0x25,\n            Up = 0x26,\n            Right = 0x27,\n            Down = 0x28,\n            Select = 0x29,\n            Print = 0x2a,\n            Execute = 0x2b,\n            PrintScreen = 0x2c,\n            Insert = 0x2d,\n            Delete = 0x2e,\n            Help = 0x2f,\n            D0 = 0x30,\n            D1 = 0x31,\n            D2 = 0x32,\n            D3 = 0x33,\n            D4 = 0x34,\n            D5 = 0x35,\n            D6 = 0x36,\n            D7 = 0x37,\n            D8 = 0x38,\n            D9 = 0x39,\n\n            A = 0x41,\n            B = 0x42,\n            C = 0x43,\n            D = 0x44,\n            E = 0x45,\n            F = 0x46,\n            G = 0x47,\n            H = 0x48,\n            I = 0x49,\n            J = 0x4a,\n            K = 0x4b,\n            L = 0x4c,\n            M = 0x4d,\n            N = 0x4e,\n            O = 0x4f,\n            P = 0x50,\n            Q = 0x51,\n            R = 0x52,\n            S = 0x53,\n            T = 0x54,\n            U = 0x55,\n            V = 0x56,\n            W = 0x57,\n            X = 0x58,\n            Y = 0x59,\n            Z = 0x5a,\n            LeftWindows = 0x5b,\n            RightWindows = 0x5c,\n            Apps = 0x5d,\n\n            Sleep = 0x5f,\n            NumPad0 = 0x60,\n            NumPad1 = 0x61,\n            NumPad2 = 0x62,\n            NumPad3 = 0x63,\n            NumPad4 = 0x64,\n            NumPad5 = 0x65,\n            NumPad6 = 0x66,\n            NumPad7 = 0x67,\n            NumPad8 = 0x68,\n            NumPad9 = 0x69,\n            Multiply = 0x6a,\n            Add = 0x6b,\n            Separator = 0x6c,\n            Subtract = 0x6d,\n\n            Decimal = 0x6e,\n            Divide = 0x6f,\n            F1 = 0x70,\n            F2 = 0x71,\n            F3 = 0x72,\n            F4 = 0x73,\n            F5 = 0x74,\n            F6 = 0x75,\n            F7 = 0x76,\n            F8 = 0x77,\n            F9 = 0x78,\n            F10 = 0x79,\n            F11 = 0x7a,\n            F12 = 0x7b,\n            F13 = 0x7c,\n            F14 = 0x7d,\n            F15 = 0x7e,\n            F16 = 0x7f,\n            F17 = 0x80,\n            F18 = 0x81,\n            F19 = 0x82,\n            F20 = 0x83,\n            F21 = 0x84,\n            F22 = 0x85,\n            F23 = 0x86,\n            F24 = 0x87,\n\n            NumLock = 0x90,\n            Scroll = 0x91,\n\n            LeftShift = 0xa0,\n            RightShift = 0xa1,\n            LeftControl = 0xa2,\n            RightControl = 0xa3,\n            LeftAlt = 0xa4,\n            RightAlt = 0xa5,\n            BrowserBack = 0xa6,\n            BrowserForward = 0xa7,\n            BrowserRefresh = 0xa8,\n            BrowserStop = 0xa9,\n            BrowserSearch = 0xaa,\n            BrowserFavorites = 0xab,\n            BrowserHome = 0xac,\n            VolumeMute = 0xad,\n            VolumeDown = 0xae,\n            VolumeUp = 0xaf,\n            MediaNextTrack = 0xb0,\n            MediaPreviousTrack = 0xb1,\n            MediaStop = 0xb2,\n            MediaPlayPause = 0xb3,\n            LaunchMail = 0xb4,\n            SelectMedia = 0xb5,\n            LaunchApplication1 = 0xb6,\n            LaunchApplication2 = 0xb7,\n\n            OemSemicolon = 0xba,\n            OemPlus = 0xbb,\n            OemComma = 0xbc,\n            OemMinus = 0xbd,\n            OemPeriod = 0xbe,\n            OemQuestion = 0xbf,\n            OemTilde = 0xc0,\n\n            OemOpenBrackets = 0xdb,\n            OemPipe = 0xdc,\n            OemCloseBrackets = 0xdd,\n            OemQuotes = 0xde,\n            Oem8 = 0xdf,\n\n            OemBackslash = 0xe2,\n\n            ProcessKey = 0xe5,\n\n            OemCopy = 0xf2,\n            OemAuto = 0xf3,\n            OemEnlW = 0xf4,\n\n            Attn = 0xf6,\n            Crsel = 0xf7,\n            Exsel = 0xf8,\n            EraseEof = 0xf9,\n            Play = 0xfa,\n            Zoom = 0xfb,\n\n            Pa1 = 0xfd,\n            OemClear = 0xfe,\n        };\n\n        struct State\n        {\n            bool Reserved0 : 8;\n            bool Back : 1;              // VK_BACK, 0x8\n            bool Tab : 1;               // VK_TAB, 0x9\n            bool Reserved1 : 3;\n            bool Enter : 1;             // VK_RETURN, 0xD\n            bool Reserved2 : 2;\n            bool Reserved3 : 3;\n            bool Pause : 1;             // VK_PAUSE, 0x13\n            bool CapsLock : 1;          // VK_CAPITAL, 0x14\n            bool Kana : 1;              // VK_KANA, 0x15\n            bool ImeOn : 1;             // VK_IME_ON, 0x16\n            bool Reserved4 : 1;\n            bool Reserved5 : 1;\n            bool Kanji : 1;             // VK_KANJI, 0x19\n            bool ImeOff : 1;            // VK_IME_OFF, 0X1A\n            bool Escape : 1;            // VK_ESCAPE, 0x1B\n            bool ImeConvert : 1;        // VK_CONVERT, 0x1C\n            bool ImeNoConvert : 1;      // VK_NONCONVERT, 0x1D\n            bool Reserved7 : 2;\n            bool Space : 1;             // VK_SPACE, 0x20\n            bool PageUp : 1;            // VK_PRIOR, 0x21\n            bool PageDown : 1;          // VK_NEXT, 0x22\n            bool End : 1;               // VK_END, 0x23\n            bool Home : 1;              // VK_HOME, 0x24\n            bool Left : 1;              // VK_LEFT, 0x25\n            bool Up : 1;                // VK_UP, 0x26\n            bool Right : 1;             // VK_RIGHT, 0x27\n            bool Down : 1;              // VK_DOWN, 0x28\n            bool Select : 1;            // VK_SELECT, 0x29\n            bool Print : 1;             // VK_PRINT, 0x2A\n            bool Execute : 1;           // VK_EXECUTE, 0x2B\n            bool PrintScreen : 1;       // VK_SNAPSHOT, 0x2C\n            bool Insert : 1;            // VK_INSERT, 0x2D\n            bool Delete : 1;            // VK_DELETE, 0x2E\n            bool Help : 1;              // VK_HELP, 0x2F\n            bool D0 : 1;                // 0x30\n            bool D1 : 1;                // 0x31\n            bool D2 : 1;                // 0x32\n            bool D3 : 1;                // 0x33\n            bool D4 : 1;                // 0x34\n            bool D5 : 1;                // 0x35\n            bool D6 : 1;                // 0x36\n            bool D7 : 1;                // 0x37\n            bool D8 : 1;                // 0x38\n            bool D9 : 1;                // 0x39\n            bool Reserved8 : 6;\n            bool Reserved9 : 1;\n            bool A : 1;                 // 0x41\n            bool B : 1;                 // 0x42\n            bool C : 1;                 // 0x43\n            bool D : 1;                 // 0x44\n            bool E : 1;                 // 0x45\n            bool F : 1;                 // 0x46\n            bool G : 1;                 // 0x47\n            bool H : 1;                 // 0x48\n            bool I : 1;                 // 0x49\n            bool J : 1;                 // 0x4A\n            bool K : 1;                 // 0x4B\n            bool L : 1;                 // 0x4C\n            bool M : 1;                 // 0x4D\n            bool N : 1;                 // 0x4E\n            bool O : 1;                 // 0x4F\n            bool P : 1;                 // 0x50\n            bool Q : 1;                 // 0x51\n            bool R : 1;                 // 0x52\n            bool S : 1;                 // 0x53\n            bool T : 1;                 // 0x54\n            bool U : 1;                 // 0x55\n            bool V : 1;                 // 0x56\n            bool W : 1;                 // 0x57\n            bool X : 1;                 // 0x58\n            bool Y : 1;                 // 0x59\n            bool Z : 1;                 // 0x5A\n            bool LeftWindows : 1;       // VK_LWIN, 0x5B\n            bool RightWindows : 1;      // VK_RWIN, 0x5C\n            bool Apps : 1;              // VK_APPS, 0x5D\n            bool Reserved10 : 1;\n            bool Sleep : 1;             // VK_SLEEP, 0x5F\n            bool NumPad0 : 1;           // VK_NUMPAD0, 0x60\n            bool NumPad1 : 1;           // VK_NUMPAD1, 0x61\n            bool NumPad2 : 1;           // VK_NUMPAD2, 0x62\n            bool NumPad3 : 1;           // VK_NUMPAD3, 0x63\n            bool NumPad4 : 1;           // VK_NUMPAD4, 0x64\n            bool NumPad5 : 1;           // VK_NUMPAD5, 0x65\n            bool NumPad6 : 1;           // VK_NUMPAD6, 0x66\n            bool NumPad7 : 1;           // VK_NUMPAD7, 0x67\n            bool NumPad8 : 1;           // VK_NUMPAD8, 0x68\n            bool NumPad9 : 1;           // VK_NUMPAD9, 0x69\n            bool Multiply : 1;          // VK_MULTIPLY, 0x6A\n            bool Add : 1;               // VK_ADD, 0x6B\n            bool Separator : 1;         // VK_SEPARATOR, 0x6C\n            bool Subtract : 1;          // VK_SUBTRACT, 0x6D\n            bool Decimal : 1;           // VK_DECIMANL, 0x6E\n            bool Divide : 1;            // VK_DIVIDE, 0x6F\n            bool F1 : 1;                // VK_F1, 0x70\n            bool F2 : 1;                // VK_F2, 0x71\n            bool F3 : 1;                // VK_F3, 0x72\n            bool F4 : 1;                // VK_F4, 0x73\n            bool F5 : 1;                // VK_F5, 0x74\n            bool F6 : 1;                // VK_F6, 0x75\n            bool F7 : 1;                // VK_F7, 0x76\n            bool F8 : 1;                // VK_F8, 0x77\n            bool F9 : 1;                // VK_F9, 0x78\n            bool F10 : 1;               // VK_F10, 0x79\n            bool F11 : 1;               // VK_F11, 0x7A\n            bool F12 : 1;               // VK_F12, 0x7B\n            bool F13 : 1;               // VK_F13, 0x7C\n            bool F14 : 1;               // VK_F14, 0x7D\n            bool F15 : 1;               // VK_F15, 0x7E\n            bool F16 : 1;               // VK_F16, 0x7F\n            bool F17 : 1;               // VK_F17, 0x80\n            bool F18 : 1;               // VK_F18, 0x81\n            bool F19 : 1;               // VK_F19, 0x82\n            bool F20 : 1;               // VK_F20, 0x83\n            bool F21 : 1;               // VK_F21, 0x84\n            bool F22 : 1;               // VK_F22, 0x85\n            bool F23 : 1;               // VK_F23, 0x86\n            bool F24 : 1;               // VK_F24, 0x87\n            bool Reserved11 : 8;\n            bool NumLock : 1;           // VK_NUMLOCK, 0x90\n            bool Scroll : 1;            // VK_SCROLL, 0x91\n            bool Reserved12 : 6;\n            bool Reserved13 : 8;\n            bool LeftShift : 1;         // VK_LSHIFT, 0xA0\n            bool RightShift : 1;        // VK_RSHIFT, 0xA1\n            bool LeftControl : 1;       // VK_LCONTROL, 0xA2\n            bool RightControl : 1;      // VK_RCONTROL, 0xA3\n            bool LeftAlt : 1;           // VK_LMENU, 0xA4\n            bool RightAlt : 1;          // VK_RMENU, 0xA5\n            bool BrowserBack : 1;       // VK_BROWSER_BACK, 0xA6\n            bool BrowserForward : 1;    // VK_BROWSER_FORWARD, 0xA7\n            bool BrowserRefresh : 1;    // VK_BROWSER_REFRESH, 0xA8\n            bool BrowserStop : 1;       // VK_BROWSER_STOP, 0xA9\n            bool BrowserSearch : 1;     // VK_BROWSER_SEARCH, 0xAA\n            bool BrowserFavorites : 1;  // VK_BROWSER_FAVORITES, 0xAB\n            bool BrowserHome : 1;       // VK_BROWSER_HOME, 0xAC\n            bool VolumeMute : 1;        // VK_VOLUME_MUTE, 0xAD\n            bool VolumeDown : 1;        // VK_VOLUME_DOWN, 0xAE\n            bool VolumeUp : 1;          // VK_VOLUME_UP, 0xAF\n            bool MediaNextTrack : 1;    // VK_MEDIA_NEXT_TRACK, 0xB0\n            bool MediaPreviousTrack : 1;// VK_MEDIA_PREV_TRACK, 0xB1\n            bool MediaStop : 1;         // VK_MEDIA_STOP, 0xB2\n            bool MediaPlayPause : 1;    // VK_MEDIA_PLAY_PAUSE, 0xB3\n            bool LaunchMail : 1;        // VK_LAUNCH_MAIL, 0xB4\n            bool SelectMedia : 1;       // VK_LAUNCH_MEDIA_SELECT, 0xB5\n            bool LaunchApplication1 : 1;// VK_LAUNCH_APP1, 0xB6\n            bool LaunchApplication2 : 1;// VK_LAUNCH_APP2, 0xB7\n            bool Reserved14 : 2;\n            bool OemSemicolon : 1;      // VK_OEM_1, 0xBA\n            bool OemPlus : 1;           // VK_OEM_PLUS, 0xBB\n            bool OemComma : 1;          // VK_OEM_COMMA, 0xBC\n            bool OemMinus : 1;          // VK_OEM_MINUS, 0xBD\n            bool OemPeriod : 1;         // VK_OEM_PERIOD, 0xBE\n            bool OemQuestion : 1;       // VK_OEM_2, 0xBF\n            bool OemTilde : 1;          // VK_OEM_3, 0xC0\n            bool Reserved15 : 7;\n            bool Reserved16 : 8;\n            bool Reserved17 : 8;\n            bool Reserved18 : 3;\n            bool OemOpenBrackets : 1;   // VK_OEM_4, 0xDB\n            bool OemPipe : 1;           // VK_OEM_5, 0xDC\n            bool OemCloseBrackets : 1;  // VK_OEM_6, 0xDD\n            bool OemQuotes : 1;         // VK_OEM_7, 0xDE\n            bool Oem8 : 1;              // VK_OEM_8, 0xDF\n            bool Reserved19 : 2;\n            bool OemBackslash : 1;      // VK_OEM_102, 0xE2\n            bool Reserved20 : 2;\n            bool ProcessKey : 1;        // VK_PROCESSKEY, 0xE5\n            bool Reserved21 : 2;\n            bool Reserved22 : 8;\n            bool Reserved23 : 2;\n            bool OemCopy : 1;           // 0XF2\n            bool OemAuto : 1;           // 0xF3\n            bool OemEnlW : 1;           // 0xF4\n            bool Reserved24 : 1;\n            bool Attn : 1;              // VK_ATTN, 0xF6\n            bool Crsel : 1;             // VK_CRSEL, 0xF7\n            bool Exsel : 1;             // VK_EXSEL, 0xF8\n            bool EraseEof : 1;          // VK_EREOF, 0xF9\n            bool Play : 1;              // VK_PLAY, 0xFA\n            bool Zoom : 1;              // VK_ZOOM, 0xFB\n            bool Reserved25 : 1;\n            bool Pa1 : 1;               // VK_PA1, 0xFD\n            bool OemClear : 1;          // VK_OEM_CLEAR, 0xFE\n            bool Reserved26 : 1;\n\n            bool __cdecl IsKeyDown(Keys key) const noexcept\n            {\n                if (key <= 0xfe)\n                {\n                    auto ptr = reinterpret_cast<const uint32_t*>(this);\n                    const unsigned int bf = 1u << (key & 0x1f);\n                    return (ptr[(key >> 5)] & bf) != 0;\n                }\n                return false;\n            }\n\n            bool __cdecl IsKeyUp(Keys key) const noexcept\n            {\n                if (key <= 0xfe)\n                {\n                    auto ptr = reinterpret_cast<const uint32_t*>(this);\n                    const unsigned int bf = 1u << (key & 0x1f);\n                    return (ptr[(key >> 5)] & bf) == 0;\n                }\n                return false;\n            }\n        };\n\n        class KeyboardStateTracker\n        {\n        public:\n            State released;\n            State pressed;\n\n        #pragma prefast(suppress: 26495, \"Reset() performs the initialization\")\n            KeyboardStateTracker() noexcept { Reset(); }\n\n            void __cdecl Update(const State& state) noexcept;\n\n            void __cdecl Reset() noexcept;\n\n            bool __cdecl IsKeyPressed(Keys key) const noexcept { return pressed.IsKeyDown(key); }\n            bool __cdecl IsKeyReleased(Keys key) const noexcept { return released.IsKeyDown(key); }\n\n            State __cdecl GetLastState() const noexcept { return lastState; }\n\n        public:\n            State lastState;\n        };\n\n        // Retrieve the current state of the keyboard\n        State __cdecl GetState() const;\n\n        // Reset the keyboard state\n        void __cdecl Reset() noexcept;\n\n        // Feature detection\n        bool __cdecl IsConnected() const;\n\n    #ifdef USING_COREWINDOW\n        void __cdecl SetWindow(ABI::Windows::UI::Core::ICoreWindow* window);\n    #ifdef __cplusplus_winrt\n        void __cdecl SetWindow(Windows::UI::Core::CoreWindow^ window)\n        {\n            // See https://msdn.microsoft.com/en-us/library/hh755802.aspx\n            SetWindow(reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow*>(window));\n        }\n    #endif\n    #ifdef CPPWINRT_VERSION\n        void __cdecl SetWindow(winrt::Windows::UI::Core::CoreWindow window)\n        {\n            // See https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi\n            SetWindow(reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow*>(winrt::get_abi(window)));\n        }\n    #endif\n    #elif defined(WM_USER)\n        static void __cdecl ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);\n    #endif\n\n        // Singleton\n        static Keyboard& __cdecl Get();\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/Model.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Model.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgiformat.h>\n#endif\n\n#include <DirectXMath.h>\n#include <DirectXCollision.h>\n\n#include <cstdint>\n#include <functional>\n#include <iterator>\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include <assert.h>\n\n#include <wrl/client.h>\n\n#include \"GraphicsMemory.h\"\n#include \"Effects.h\"\n\n\nnamespace DirectX\n{\n    class IEffect;\n    class IEffectFactory;\n    class ModelMesh;\n\n    //----------------------------------------------------------------------------------\n    // Model loading options\n    enum ModelLoaderFlags : uint32_t\n    {\n        ModelLoader_Default             = 0x0,\n        ModelLoader_MaterialColorsSRGB  = 0x1,\n        ModelLoader_AllowLargeModels    = 0x2,\n    };\n\n    //----------------------------------------------------------------------------------\n    // Each mesh part is a submesh with a single effect\n    class ModelMeshPart\n    {\n    public:\n        ModelMeshPart(uint32_t partIndex) noexcept;\n\n        ModelMeshPart(ModelMeshPart&&) = default;\n        ModelMeshPart& operator= (ModelMeshPart&&) = default;\n\n        ModelMeshPart(ModelMeshPart const&) = default;\n        ModelMeshPart& operator= (ModelMeshPart const&) = default;\n\n        virtual ~ModelMeshPart();\n\n        uint32_t                                                partIndex;      // Unique index assigned per-part in a model; used to index effects.\n        uint32_t                                                materialIndex;  // Index of the material spec to use\n        uint32_t                                                indexCount;\n        uint32_t                                                startIndex;\n        int32_t                                                 vertexOffset;\n        uint32_t                                                vertexStride;\n        uint32_t                                                vertexCount;\n        uint32_t                                                indexBufferSize;\n        uint32_t                                                vertexBufferSize;\n        D3D_PRIMITIVE_TOPOLOGY                                  primitiveType;\n        DXGI_FORMAT                                             indexFormat;\n        SharedGraphicsResource                                  indexBuffer;\n        SharedGraphicsResource                                  vertexBuffer;\n        Microsoft::WRL::ComPtr<ID3D12Resource>                  staticIndexBuffer;\n        Microsoft::WRL::ComPtr<ID3D12Resource>                  staticVertexBuffer;\n        std::shared_ptr<std::vector<D3D12_INPUT_ELEMENT_DESC>>  vbDecl;\n\n        using Collection = std::vector<std::unique_ptr<ModelMeshPart>>;\n        using DrawCallback = std::function<void(_In_ ID3D12GraphicsCommandList* commandList, _In_ const ModelMeshPart& part)>;\n\n        // Draw mesh part\n        void __cdecl Draw(_In_ ID3D12GraphicsCommandList* commandList) const;\n\n        void __cdecl DrawInstanced(_In_ ID3D12GraphicsCommandList* commandList, uint32_t instanceCount, uint32_t startInstanceLocation = 0) const;\n\n        //\n        // Utilities for drawing multiple mesh parts\n        //\n\n        // Draw the mesh\n        static void __cdecl DrawMeshParts(_In_ ID3D12GraphicsCommandList* commandList, _In_ const ModelMeshPart::Collection& meshParts);\n\n        // Draw the mesh with an effect\n        static void __cdecl DrawMeshParts(_In_ ID3D12GraphicsCommandList* commandList, _In_ const ModelMeshPart::Collection& meshParts, _In_ IEffect* effect);\n\n        // Draw the mesh with a callback for each mesh part\n        static void __cdecl DrawMeshParts(_In_ ID3D12GraphicsCommandList* commandList, _In_ const ModelMeshPart::Collection& meshParts, DrawCallback callback);\n\n        // Draw the mesh with a range of effects that mesh parts will index into. \n        // Effects can be any IEffect pointer type (including smart pointer). Value or reference types will not compile.\n        // The iterator passed to this method should have random access capabilities for best performance.\n        template<typename TEffectIterator, typename TEffectIteratorCategory = typename TEffectIterator::iterator_category>\n        static void DrawMeshParts(\n            _In_ ID3D12GraphicsCommandList* commandList,\n            _In_ const ModelMeshPart::Collection& meshParts,\n            TEffectIterator partEffects)\n        {\n            // This assert is here to prevent accidental use of containers that would cause undesirable performance penalties.\n            static_assert(\n                std::is_base_of<std::random_access_iterator_tag, TEffectIteratorCategory>::value,\n                \"Providing an iterator without random access capabilities -- such as from std::list -- is not supported.\");\n\n            for (auto it = std::begin(meshParts); it != std::end(meshParts); ++it)\n            {\n                auto part = it->get();\n                assert(part != nullptr);\n\n                // Get the effect at the location specified by the part's material\n                TEffectIterator effect_iterator = partEffects;\n                std::advance(effect_iterator, part->partIndex);\n\n                // Apply the effect and draw\n                (*effect_iterator)->Apply(commandList);\n                part->Draw(commandList);\n            }\n        }\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // A mesh consists of one or more model mesh parts\n    class ModelMesh\n    {\n    public:\n        ModelMesh() noexcept;\n\n        ModelMesh(ModelMesh&&) = default;\n        ModelMesh& operator= (ModelMesh&&) = default;\n\n        ModelMesh(ModelMesh const&) = default;\n        ModelMesh& operator= (ModelMesh const&) = default;\n\n        virtual ~ModelMesh();\n\n        BoundingSphere              boundingSphere;\n        BoundingBox                 boundingBox;\n        ModelMeshPart::Collection   opaqueMeshParts;\n        ModelMeshPart::Collection   alphaMeshParts;\n        std::wstring                name;\n\n        using Collection = std::vector<std::shared_ptr<ModelMesh>>;\n\n        // Draw the mesh\n        void __cdecl DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList) const;\n        void __cdecl DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList) const;\n\n        // Draw the mesh with an effect\n        void __cdecl DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList, _In_ IEffect* effect) const;\n        void __cdecl DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList, _In_ IEffect* effect) const;\n\n        // Draw the mesh with a callback for each mesh part\n        void __cdecl DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList, ModelMeshPart::DrawCallback callback) const;\n        void __cdecl DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList, ModelMeshPart::DrawCallback callback) const;\n\n        // Draw the mesh with a range of effects that mesh parts will index into. \n        // TEffectPtr can be any IEffect pointer type (including smart pointer). Value or reference types will not compile.\n        template<typename TEffectIterator, typename TEffectIteratorCategory = typename TEffectIterator::iterator_category>\n        void DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList, TEffectIterator effects) const\n        {\n            ModelMeshPart::DrawMeshParts<TEffectIterator, TEffectIteratorCategory>(commandList, opaqueMeshParts, effects);\n        }\n        template<typename TEffectIterator, typename TEffectIteratorCategory = typename TEffectIterator::iterator_category>\n        void DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList, TEffectIterator effects) const\n        {\n            ModelMeshPart::DrawMeshParts<TEffectIterator, TEffectIteratorCategory>(commandList, alphaMeshParts, effects);\n        }\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // A model consists of one or more meshes\n    class Model\n    {\n    public:\n        Model() noexcept;\n\n        Model(Model&&) = default;\n        Model& operator= (Model&&) = default;\n\n        Model(Model const&) = default;\n        Model& operator= (Model const&) = default;\n\n        virtual ~Model();\n\n        using ModelMaterialInfo = IEffectFactory::EffectInfo;\n        using ModelMaterialInfoCollection = std::vector<ModelMaterialInfo>;\n        using TextureCollection = std::vector<std::wstring>;\n\n        //\n        // NOTE\n        // \n        // The Model::Draw functions use variadic templates and perfect-forwarding in order to support future overloads to the ModelMesh::Draw\n        // family of functions. This means that a new ModelMesh::Draw overload can be added, removed or altered, but the Model::Draw* routines\n        // will still remain compatible. The correct ModelMesh::Draw overload will be selected by the compiler depending on the arguments you \n        // provide to Model::Draw*.\n        //\n\n        // Draw all the opaque meshes in the model\n        template<typename... TForwardArgs> void DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList, TForwardArgs&&... args) const\n        {\n            // Draw opaque parts\n            for (auto it = std::begin(meshes); it != std::end(meshes); ++it)\n            {\n                auto mesh = it->get();\n                assert(mesh != nullptr);\n\n                mesh->DrawOpaque(commandList, std::forward<TForwardArgs>(args)...);\n            }\n        }\n\n        // Draw all the alpha meshes in the model\n        template<typename... TForwardArgs> void DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList, TForwardArgs&&... args) const\n        {\n            // Draw opaque parts\n            for (auto it = std::begin(meshes); it != std::end(meshes); ++it)\n            {\n                auto mesh = it->get();\n                assert(mesh != nullptr);\n\n                mesh->DrawAlpha(commandList, std::forward<TForwardArgs>(args)...);\n            }\n        }\n\n        // Draw all the meshes in the model\n        template<typename... TForwardArgs> void Draw(_In_ ID3D12GraphicsCommandList* commandList, TForwardArgs&&... args) const\n        {\n            DrawOpaque(commandList, std::forward<TForwardArgs>(args)...);\n            DrawAlpha(commandList, std::forward<TForwardArgs>(args)...);\n        }\n\n        // Load texture resources into an existing Effect Texture Factory\n        int __cdecl LoadTextures(IEffectTextureFactory& texFactory, int destinationDescriptorOffset = 0) const;\n\n        // Load texture resources into a new Effect Texture Factory\n        std::unique_ptr<EffectTextureFactory> __cdecl LoadTextures(\n            _In_ ID3D12Device* device,\n            ResourceUploadBatch& resourceUploadBatch,\n            _In_opt_z_ const wchar_t* texturesPath = nullptr,\n            D3D12_DESCRIPTOR_HEAP_FLAGS flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) const;\n\n        // Load VB/IB resources for static geometry\n        void __cdecl LoadStaticBuffers(\n            _In_ ID3D12Device* device,\n            ResourceUploadBatch& resourceUploadBatch,\n            bool keepMemory = false);\n\n        // Create effects using the default effect factory\n        std::vector<std::shared_ptr<IEffect>> __cdecl CreateEffects(\n            const EffectPipelineStateDescription& opaquePipelineState,\n            const EffectPipelineStateDescription& alphaPipelineState,\n            _In_ ID3D12DescriptorHeap* textureDescriptorHeap,\n            _In_ ID3D12DescriptorHeap* samplerDescriptorHeap,\n            int textureDescriptorOffset = 0,\n            int samplerDescriptorOffset = 0) const;\n\n        // Create effects using a custom effect factory\n        std::vector<std::shared_ptr<IEffect>> __cdecl CreateEffects(\n            IEffectFactory& fxFactory,\n            const EffectPipelineStateDescription& opaquePipelineState,\n            const EffectPipelineStateDescription& alphaPipelineState,\n            int textureDescriptorOffset = 0,\n            int samplerDescriptorOffset = 0) const;\n\n        // Loads a model from a DirectX SDK .SDKMESH file\n        static std::unique_ptr<Model> __cdecl CreateFromSDKMESH(\n            _In_opt_ ID3D12Device* device,\n            _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize,\n            ModelLoaderFlags flags = ModelLoader_Default);\n        static std::unique_ptr<Model> __cdecl CreateFromSDKMESH(\n            _In_opt_ ID3D12Device* device,\n            _In_z_ const wchar_t* szFileName,\n            ModelLoaderFlags flags = ModelLoader_Default);\n\n        // Loads a model from a .VBO file\n        static std::unique_ptr<Model> __cdecl CreateFromVBO(\n            _In_opt_ ID3D12Device* device,\n            _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize,\n            ModelLoaderFlags flags = ModelLoader_Default);\n        static std::unique_ptr<Model> __cdecl CreateFromVBO(\n            _In_opt_ ID3D12Device* device,\n            _In_z_ const wchar_t* szFileName,\n            ModelLoaderFlags flags = ModelLoader_Default);\n\n        // Utility function for getting a GPU descriptor for a mesh part/material index. If there is no texture the \n        // descriptor will be zero.\n        D3D12_GPU_DESCRIPTOR_HANDLE __cdecl GetGpuTextureHandleForMaterialIndex(uint32_t materialIndex, _In_ ID3D12DescriptorHeap* heap, _In_ size_t descriptorSize, _In_ size_t descriptorOffset) const\n        {\n            D3D12_GPU_DESCRIPTOR_HANDLE handle = {};\n\n            if (materialIndex >= materials.size())\n                return handle;\n\n            int textureIndex = materials[materialIndex].diffuseTextureIndex;\n            if (textureIndex == -1)\n                return handle;\n\n            handle = heap->GetGPUDescriptorHandleForHeapStart();\n            handle.ptr += static_cast<UINT64>(descriptorSize * (UINT64(textureIndex) + UINT64(descriptorOffset)));\n\n            return handle;\n        }\n\n        // Utility function for updating the matrices in a list of effects. This will SetWorld, SetView and SetProjection\n        // on any effect in the list that derives from IEffectMatrices.\n        static void XM_CALLCONV UpdateEffectMatrices(\n            _In_ std::vector<std::shared_ptr<IEffect>>& effectList,\n            DirectX::FXMMATRIX world,\n            DirectX::CXMMATRIX view,\n            DirectX::CXMMATRIX proj);\n\n        // Utility function to transition VB/IB resources for static geometry.\n        void __cdecl Transition(\n            _In_ ID3D12GraphicsCommandList* commandList,\n            D3D12_RESOURCE_STATES stateBeforeVB,\n            D3D12_RESOURCE_STATES stateAfterVB,\n            D3D12_RESOURCE_STATES stateBeforeIB,\n            D3D12_RESOURCE_STATES stateAfterIB);\n\n        ModelMesh::Collection           meshes;\n        ModelMaterialInfoCollection     materials;\n        TextureCollection               textureNames;\n        std::wstring                    name;\n\n    private:\n        std::shared_ptr<IEffect> __cdecl CreateEffectForMeshPart(\n            IEffectFactory& fxFactory,\n            const EffectPipelineStateDescription& opaquePipelineState,\n            const EffectPipelineStateDescription& alphaPipelineState,\n            int textureDescriptorOffset,\n            int samplerDescriptorOffset,\n            _In_ const ModelMeshPart* part) const;\n    };\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-dynamic-exception-spec\"\n#endif\n\n    DEFINE_ENUM_FLAG_OPERATORS(ModelLoaderFlags);\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/Mouse.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Mouse.h\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#if (defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) || (defined(_XBOX_ONE) && defined(_TITLE))\n#ifndef USING_COREWINDOW\n#define USING_COREWINDOW\n#endif\n#endif\n\n#include <memory>\n\n#ifdef USING_COREWINDOW\nnamespace ABI { namespace Windows { namespace UI { namespace Core { struct ICoreWindow; } } } }\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#endif\n\n\nnamespace DirectX\n{\n    class Mouse\n    {\n    public:\n        Mouse() noexcept(false);\n\n        Mouse(Mouse&&) noexcept;\n        Mouse& operator= (Mouse&&) noexcept;\n\n        Mouse(Mouse const&) = delete;\n        Mouse& operator=(Mouse const&) = delete;\n\n        virtual ~Mouse();\n\n        enum Mode\n        {\n            MODE_ABSOLUTE = 0,\n            MODE_RELATIVE,\n        };\n\n        struct State\n        {\n            bool    leftButton;\n            bool    middleButton;\n            bool    rightButton;\n            bool    xButton1;\n            bool    xButton2;\n            int     x;\n            int     y;\n            int     scrollWheelValue;\n            Mode    positionMode;\n        };\n\n        class ButtonStateTracker\n        {\n        public:\n            enum ButtonState\n            {\n                UP = 0,         // Button is up\n                HELD = 1,       // Button is held down\n                RELEASED = 2,   // Button was just released\n                PRESSED = 3,    // Buton was just pressed\n            };\n\n            ButtonState leftButton;\n            ButtonState middleButton;\n            ButtonState rightButton;\n            ButtonState xButton1;\n            ButtonState xButton2;\n\n        #pragma prefast(suppress: 26495, \"Reset() performs the initialization\")\n            ButtonStateTracker() noexcept { Reset(); }\n\n            void __cdecl Update(const State& state) noexcept;\n\n            void __cdecl Reset() noexcept;\n\n            State __cdecl GetLastState() const noexcept { return lastState; }\n\n        private:\n            State lastState;\n        };\n\n        // Retrieve the current state of the mouse\n        State __cdecl GetState() const;\n\n        // Resets the accumulated scroll wheel value\n        void __cdecl ResetScrollWheelValue() noexcept;\n\n        // Sets mouse mode (defaults to absolute)\n        void __cdecl SetMode(Mode mode);\n\n        // Feature detection\n        bool __cdecl IsConnected() const;\n\n        // Cursor visibility\n        bool __cdecl IsVisible() const noexcept;\n        void __cdecl SetVisible(bool visible);\n\n    #ifdef USING_COREWINDOW\n        void __cdecl SetWindow(ABI::Windows::UI::Core::ICoreWindow* window);\n    #ifdef __cplusplus_winrt\n        void __cdecl SetWindow(Windows::UI::Core::CoreWindow^ window)\n        {\n            // See https://msdn.microsoft.com/en-us/library/hh755802.aspx\n            SetWindow(reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow*>(window));\n        }\n    #endif\n    #ifdef CPPWINRT_VERSION\n        void __cdecl SetWindow(winrt::Windows::UI::Core::CoreWindow window)\n        {\n            // See https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi\n            SetWindow(reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow*>(winrt::get_abi(window)));\n        }\n    #endif\n\n        static void __cdecl SetDpi(float dpi);\n    #elif defined(WM_USER)\n        void __cdecl SetWindow(HWND window);\n        static void __cdecl ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);\n\n    #ifdef _GAMING_XBOX\n        static void __cdecl SetResolution(float scale);\n    #endif\n    #endif\n\n        // Singleton\n        static Mouse& __cdecl Get();\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/PostProcess.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: PostProcess.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <DirectXMath.h>\n#include <memory>\n\n#include \"RenderTargetState.h\"\n\n\nnamespace DirectX\n{\n    //----------------------------------------------------------------------------------\n    // Abstract interface representing a post-process pass\n    class IPostProcess\n    {\n    public:\n        virtual ~IPostProcess() = default;\n\n        IPostProcess(const IPostProcess&) = delete;\n        IPostProcess& operator=(const IPostProcess&) = delete;\n\n        IPostProcess(IPostProcess&&) = delete;\n        IPostProcess& operator=(IPostProcess&&) = delete;\n\n        virtual void __cdecl Process(_In_ ID3D12GraphicsCommandList* commandList) = 0;\n\n    protected:\n        IPostProcess() = default;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Basic post-process\n    class BasicPostProcess : public IPostProcess\n    {\n    public:\n        enum Effect : unsigned int\n        {\n            Copy,\n            Monochrome,\n            Sepia,\n            DownScale_2x2,\n            DownScale_4x4,\n            GaussianBlur_5x5,\n            BloomExtract,\n            BloomBlur,\n            Effect_Max\n        };\n\n        explicit BasicPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect fx);\n        BasicPostProcess(BasicPostProcess&& moveFrom) noexcept;\n        BasicPostProcess& operator= (BasicPostProcess&& moveFrom) noexcept;\n\n        BasicPostProcess(BasicPostProcess const&) = delete;\n        BasicPostProcess& operator= (BasicPostProcess const&) = delete;\n\n        ~BasicPostProcess() override;\n\n        // IPostProcess methods.\n        void __cdecl Process(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Properties\n        void __cdecl SetSourceTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, _In_opt_ ID3D12Resource* resource);\n\n        // Sets multiplier for GaussianBlur_5x5\n        void __cdecl SetGaussianParameter(float multiplier);\n\n        // Sets parameters for BloomExtract\n        void __cdecl SetBloomExtractParameter(float threshold);\n\n        // Sets parameters for BloomBlur\n        void __cdecl SetBloomBlurParameters(bool horizontal, float size, float brightness);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Dual-texure post-process\n    class DualPostProcess : public IPostProcess\n    {\n    public:\n        enum Effect : unsigned int\n        {\n            Merge,\n            BloomCombine,\n            Effect_Max\n        };\n\n        explicit DualPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect fx);\n        DualPostProcess(DualPostProcess&& moveFrom) noexcept;\n        DualPostProcess& operator= (DualPostProcess&& moveFrom) noexcept;\n\n        DualPostProcess(DualPostProcess const&) = delete;\n        DualPostProcess& operator= (DualPostProcess const&) = delete;\n\n        ~DualPostProcess() override;\n\n        // IPostProcess methods.\n        void __cdecl Process(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Properties\n        void __cdecl SetSourceTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n        void __cdecl SetSourceTexture2(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n\n        // Sets parameters for Merge\n        void __cdecl SetMergeParameters(float weight1, float weight2);\n\n        // Sets parameters for BloomCombine\n        void __cdecl SetBloomCombineParameters(float bloom, float base, float bloomSaturation, float baseSaturation);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n\n\n    //----------------------------------------------------------------------------------\n    // Tone-map post-process\n    class ToneMapPostProcess : public IPostProcess\n    {\n    public:\n        // Tone-mapping operator\n        enum Operator : unsigned int\n        {\n            None,               // Pass-through\n            Saturate,           // Clamp [0,1]\n            Reinhard,           // x/(1+x)\n            ACESFilmic,\n            Operator_Max\n        };\n\n        // Electro-Optical Transfer Function (EOTF)\n        enum TransferFunction : unsigned int\n        {\n            Linear,             // Pass-through\n            SRGB,               // sRGB (Rec.709 and approximate sRGB display curve)\n            ST2084,             // HDR10 (Rec.2020 color primaries and ST.2084 display curve)\n            TransferFunction_Max\n        };\n\n        explicit ToneMapPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState,\n            Operator op, TransferFunction func\n        #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n            , bool mrt = false\n        #endif\n        );\n\n        ToneMapPostProcess(ToneMapPostProcess&& moveFrom) noexcept;\n        ToneMapPostProcess& operator= (ToneMapPostProcess&& moveFrom) noexcept;\n\n        ToneMapPostProcess(ToneMapPostProcess const&) = delete;\n        ToneMapPostProcess& operator= (ToneMapPostProcess const&) = delete;\n\n        ~ToneMapPostProcess() override;\n\n        // IPostProcess methods.\n        void __cdecl Process(_In_ ID3D12GraphicsCommandList* commandList) override;\n\n        // Properties\n        void __cdecl SetHDRSourceTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);\n\n        // Sets exposure value for LDR tonemap operators\n        void SetExposure(float exposureValue);\n\n        // Sets ST.2084 parameter for how bright white should be in nits\n        void SetST2084Parameter(float paperWhiteNits);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/PrimitiveBatch.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: PrimitiveBatch.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <cstdint>\n#include <memory>\n#include <utility>\n\n\nnamespace DirectX\n{\n    namespace Internal\n    {\n        // Base class, not to be used directly: clients should access this via the derived PrimitiveBatch<T>.\n        class PrimitiveBatchBase\n        {\n        protected:\n            PrimitiveBatchBase(_In_ ID3D12Device* device, size_t maxIndices, size_t maxVertices, size_t vertexSize);\n\n            PrimitiveBatchBase(PrimitiveBatchBase&& moveFrom) noexcept;\n            PrimitiveBatchBase& operator= (PrimitiveBatchBase&& moveFrom) noexcept;\n\n            PrimitiveBatchBase(PrimitiveBatchBase const&) = delete;\n            PrimitiveBatchBase& operator= (PrimitiveBatchBase const&) = delete;\n\n            virtual ~PrimitiveBatchBase();\n\n        public:\n            // Begin/End a batch of primitive drawing operations.\n            void __cdecl Begin(_In_ ID3D12GraphicsCommandList* cmdList);\n            void __cdecl End();\n\n        protected:\n            // Internal, untyped drawing method.\n            void __cdecl Draw(D3D_PRIMITIVE_TOPOLOGY topology, bool isIndexed, _In_opt_count_(indexCount) uint16_t const* indices, size_t indexCount, size_t vertexCount, _Outptr_ void** pMappedVertices);\n\n        private:\n            // Private implementation.\n            class Impl;\n\n            std::unique_ptr<Impl> pImpl;\n        };\n    }\n\n\n    // Template makes the API typesafe, eg. PrimitiveBatch<VertexPositionColor>.\n    template<typename TVertex>\n    class PrimitiveBatch : public Internal::PrimitiveBatchBase\n    {\n        static const size_t DefaultBatchSize = 4096;\n\n    public:\n        explicit PrimitiveBatch(_In_ ID3D12Device* device, size_t maxIndices = DefaultBatchSize * 3, size_t maxVertices = DefaultBatchSize)\n            : PrimitiveBatchBase(device, maxIndices, maxVertices, sizeof(TVertex))\n        { }\n\n        PrimitiveBatch(PrimitiveBatch&& moveFrom) noexcept\n            : PrimitiveBatchBase(std::move(moveFrom))\n        { }\n\n        PrimitiveBatch& operator= (PrimitiveBatch&& moveFrom) noexcept\n        {\n            PrimitiveBatchBase::operator=(std::move(moveFrom));\n            return *this;\n        }\n\n        PrimitiveBatch(PrimitiveBatch const&) = delete;\n        PrimitiveBatch& operator= (PrimitiveBatch const&) = delete;\n\n        // Similar to the D3D9 API DrawPrimitiveUP.\n        void Draw(D3D_PRIMITIVE_TOPOLOGY topology, _In_reads_(vertexCount) TVertex const* vertices, size_t vertexCount)\n        {\n            void* mappedVertices;\n\n            PrimitiveBatchBase::Draw(topology, false, nullptr, 0, vertexCount, &mappedVertices);\n\n            memcpy(mappedVertices, vertices, vertexCount * sizeof(TVertex));\n        }\n\n\n        // Similar to the D3D9 API DrawIndexedPrimitiveUP.\n        void DrawIndexed(D3D_PRIMITIVE_TOPOLOGY topology, _In_reads_(indexCount) uint16_t const* indices, size_t indexCount, _In_reads_(vertexCount) TVertex const* vertices, size_t vertexCount)\n        {\n            void* mappedVertices;\n\n            PrimitiveBatchBase::Draw(topology, true, indices, indexCount, vertexCount, &mappedVertices);\n\n            memcpy(mappedVertices, vertices, vertexCount * sizeof(TVertex));\n        }\n\n\n        void DrawLine(TVertex const& v1, TVertex const& v2)\n        {\n            TVertex* mappedVertices;\n\n            PrimitiveBatchBase::Draw(D3D_PRIMITIVE_TOPOLOGY_LINELIST, false, nullptr, 0, 2, reinterpret_cast<void**>(&mappedVertices));\n\n            mappedVertices[0] = v1;\n            mappedVertices[1] = v2;\n        }\n\n\n        void DrawTriangle(TVertex const& v1, TVertex const& v2, TVertex const& v3)\n        {\n            TVertex* mappedVertices;\n\n            PrimitiveBatchBase::Draw(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, false, nullptr, 0, 3, reinterpret_cast<void**>(&mappedVertices));\n\n            mappedVertices[0] = v1;\n            mappedVertices[1] = v2;\n            mappedVertices[2] = v3;\n        }\n\n\n        void DrawQuad(TVertex const& v1, TVertex const& v2, TVertex const& v3, TVertex const& v4)\n        {\n            static const uint16_t quadIndices[] = { 0, 1, 2, 0, 2, 3 };\n\n            TVertex* mappedVertices;\n\n            PrimitiveBatchBase::Draw(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, true, quadIndices, 6, 4, reinterpret_cast<void**>(&mappedVertices));\n\n            mappedVertices[0] = v1;\n            mappedVertices[1] = v2;\n            mappedVertices[2] = v3;\n            mappedVertices[3] = v4;\n        }\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/RenderTargetState.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: RenderTargetState.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgi.h>\n#endif\n\n#include <cstdint>\n\n\nnamespace DirectX\n{\n    // Encapsulates all render target state when creating pipeline state objects\n    class RenderTargetState\n    {\n    public:\n        RenderTargetState() noexcept\n            : sampleMask(~0U)\n            , numRenderTargets(0)\n            , rtvFormats{}\n            , dsvFormat(DXGI_FORMAT_UNKNOWN)\n            , sampleDesc{}\n            , nodeMask(0)\n        {\n        }\n\n        RenderTargetState(const RenderTargetState&) = default;\n        RenderTargetState& operator=(const RenderTargetState&) = default;\n\n        RenderTargetState(RenderTargetState&&) = default;\n        RenderTargetState& operator=(RenderTargetState&&) = default;\n\n        // Single render target convenience constructor\n        RenderTargetState(\n            _In_ DXGI_FORMAT rtFormat,\n            _In_ DXGI_FORMAT dsFormat) noexcept\n            : sampleMask(UINT_MAX)\n            , numRenderTargets(1)\n            , rtvFormats{}\n            , dsvFormat(dsFormat)\n            , sampleDesc{}\n            , nodeMask(0)\n        {\n            sampleDesc.Count = 1;\n            rtvFormats[0] = rtFormat;\n        }\n\n        // Convenience constructor converting from DXGI_SWAPCHAIN_DESC\n        RenderTargetState(\n            _In_ const DXGI_SWAP_CHAIN_DESC* desc,\n            _In_ DXGI_FORMAT dsFormat) noexcept\n            : sampleMask(UINT_MAX)\n            , numRenderTargets(1)\n            , rtvFormats{}\n            , dsvFormat(dsFormat)\n            , sampleDesc{}\n            , nodeMask(0)\n        {\n            rtvFormats[0] = desc->BufferDesc.Format;\n            sampleDesc = desc->SampleDesc;\n        }\n\n        uint32_t            sampleMask;\n        uint32_t            numRenderTargets;\n        DXGI_FORMAT         rtvFormats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];\n        DXGI_FORMAT         dsvFormat;\n        DXGI_SAMPLE_DESC    sampleDesc;\n        uint32_t            nodeMask;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/ResourceUploadBatch.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: ResourceUploadBatch.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgiformat.h>\n#endif\n\n#include <future>\n#include <memory>\n\n#include \"GraphicsMemory.h\"\n\n\nnamespace DirectX\n{\n    // Has a command list of it's own so it can upload at any time.\n    class ResourceUploadBatch\n    {\n    public:\n        explicit ResourceUploadBatch(_In_ ID3D12Device* device) noexcept(false);\n        ResourceUploadBatch(ResourceUploadBatch&& moveFrom) noexcept;\n        ResourceUploadBatch& operator= (ResourceUploadBatch&& moveFrom) noexcept;\n\n        ResourceUploadBatch(ResourceUploadBatch const&) = delete;\n        ResourceUploadBatch& operator= (ResourceUploadBatch const&) = delete;\n\n        virtual ~ResourceUploadBatch();\n\n        // Call this before your multiple calls to Upload.\n        void __cdecl Begin(D3D12_COMMAND_LIST_TYPE commandType = D3D12_COMMAND_LIST_TYPE_DIRECT);\n\n        // Asynchronously uploads a resource. The memory in subRes is copied.\n        // The resource must be in the COPY_DEST state.\n        void __cdecl Upload(\n            _In_ ID3D12Resource* resource,\n            uint32_t subresourceIndexStart,\n            _In_reads_(numSubresources) const D3D12_SUBRESOURCE_DATA* subRes,\n            uint32_t numSubresources);\n\n        void __cdecl Upload(\n            _In_ ID3D12Resource* resource,\n            const SharedGraphicsResource& buffer\n            );\n\n        // Asynchronously generate mips from a resource.\n        // Resource must be in the PIXEL_SHADER_RESOURCE state\n        void __cdecl GenerateMips(_In_ ID3D12Resource* resource);\n\n        // Transition a resource once you're done with it\n        void __cdecl Transition(\n            _In_ ID3D12Resource* resource,\n            D3D12_RESOURCE_STATES stateBefore,\n            D3D12_RESOURCE_STATES stateAfter);\n\n        // Submits all the uploads to the driver.\n        // No more uploads can happen after this call until Begin is called again.\n        // This returns a handle to an event that can be waited on.\n        std::future<void> __cdecl End(_In_ ID3D12CommandQueue* commandQueue);\n\n        // Validates if the given DXGI format is supported for autogen mipmaps\n        bool __cdecl IsSupportedForGenerateMips(DXGI_FORMAT format) noexcept;\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/ScreenGrab.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: ScreenGrab.h\n//\n// Function for capturing a 2D texture and saving it to a file (aka a 'screenshot'\n// when used on a Direct3D Render Target).\n//\n// Note these functions are useful as a light-weight runtime screen grabber. For\n// full-featured texture capture, DDS writer, and texture processing pipeline,\n// see the 'Texconv' sample and the 'DirectXTex' library.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <OCIdl.h>\n#include <functional>\n\n#pragma comment(lib,\"uuid.lib\")\n\n\nnamespace DirectX\n{\n    HRESULT __cdecl SaveDDSTextureToFile(\n        _In_ ID3D12CommandQueue* pCommandQueue,\n        _In_ ID3D12Resource* pSource,\n        _In_z_ const wchar_t* fileName,\n        D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET,\n        D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET) noexcept;\n\n    HRESULT __cdecl SaveWICTextureToFile(\n        _In_ ID3D12CommandQueue* pCommandQ,\n        _In_ ID3D12Resource* pSource,\n        REFGUID guidContainerFormat,\n        _In_z_ const wchar_t* fileName,\n        D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET,\n        D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET,\n        _In_opt_ const GUID* targetFormat = nullptr,\n        _In_opt_ std::function<void __cdecl(IPropertyBag2*)> setCustomProps = nullptr,\n        bool forceSRGB = false);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/SimpleMath.h",
    "content": "//-------------------------------------------------------------------------------------\n// SimpleMath.h -- Simplified C++ Math wrapper for DirectXMath\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#if !(defined(_XBOX_ONE) && defined(_TITLE)) && !defined(_GAMING_XBOX)\n#include <dxgi1_2.h>\n#endif\n\n#include <functional>\n\n#include <assert.h>\n#include <memory.h>\n\n#include <DirectXMath.h>\n#include <DirectXPackedVector.h>\n#include <DirectXCollision.h>\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wfloat-equal\"\n#endif\n\n\nnamespace DirectX\n{\n    namespace SimpleMath\n    {\n        struct Vector2;\n        struct Vector4;\n        struct Matrix;\n        struct Quaternion;\n        struct Plane;\n\n        //------------------------------------------------------------------------------\n        // 2D rectangle\n        struct Rectangle\n        {\n            long x;\n            long y;\n            long width;\n            long height;\n\n            // Creators\n            Rectangle() noexcept : x(0), y(0), width(0), height(0) {}\n            constexpr Rectangle(long ix, long iy, long iw, long ih) noexcept : x(ix), y(iy), width(iw), height(ih) {}\n            explicit Rectangle(const RECT& rct) noexcept : x(rct.left), y(rct.top), width(rct.right - rct.left), height(rct.bottom - rct.top) {}\n\n            Rectangle(const Rectangle&) = default;\n            Rectangle& operator=(const Rectangle&) = default;\n\n            Rectangle(Rectangle&&) = default;\n            Rectangle& operator=(Rectangle&&) = default;\n\n            operator RECT() noexcept { RECT rct; rct.left = x; rct.top = y; rct.right = (x + width); rct.bottom = (y + height); return rct; }\n        #ifdef __cplusplus_winrt\n            operator Windows::Foundation::Rect() noexcept { return Windows::Foundation::Rect(float(x), float(y), float(width), float(height)); }\n        #endif\n\n            // Comparison operators\n            bool operator == (const Rectangle& r) const noexcept { return (x == r.x) && (y == r.y) && (width == r.width) && (height == r.height); }\n            bool operator == (const RECT& rct) const noexcept { return (x == rct.left) && (y == rct.top) && (width == (rct.right - rct.left)) && (height == (rct.bottom - rct.top)); }\n\n            bool operator != (const Rectangle& r) const noexcept { return (x != r.x) || (y != r.y) || (width != r.width) || (height != r.height); }\n            bool operator != (const RECT& rct) const noexcept { return (x != rct.left) || (y != rct.top) || (width != (rct.right - rct.left)) || (height != (rct.bottom - rct.top)); }\n\n            // Assignment operators\n            Rectangle& operator=(_In_ const RECT& rct) noexcept { x = rct.left; y = rct.top; width = (rct.right - rct.left); height = (rct.bottom - rct.top); return *this; }\n\n            // Rectangle operations\n            Vector2 Location() const noexcept;\n            Vector2 Center() const noexcept;\n\n            bool IsEmpty() const noexcept { return (width == 0 && height == 0 && x == 0 && y == 0); }\n\n            bool Contains(long ix, long iy) const noexcept { return (x <= ix) && (ix < (x + width)) && (y <= iy) && (iy < (y + height)); }\n            bool Contains(const Vector2& point) const noexcept;\n            bool Contains(const Rectangle& r) const noexcept { return (x <= r.x) && ((r.x + r.width) <= (x + width)) && (y <= r.y) && ((r.y + r.height) <= (y + height)); }\n            bool Contains(const RECT& rct) const noexcept { return (x <= rct.left) && (rct.right <= (x + width)) && (y <= rct.top) && (rct.bottom <= (y + height)); }\n\n            void Inflate(long horizAmount, long vertAmount) noexcept;\n\n            bool Intersects(const Rectangle& r) const noexcept { return (r.x < (x + width)) && (x < (r.x + r.width)) && (r.y < (y + height)) && (y < (r.y + r.height)); }\n            bool Intersects(const RECT& rct) const noexcept { return (rct.left < (x + width)) && (x < rct.right) && (rct.top < (y + height)) && (y < rct.bottom); }\n\n            void Offset(long ox, long oy) noexcept { x += ox; y += oy; }\n\n            // Static functions\n            static Rectangle Intersect(const Rectangle& ra, const Rectangle& rb) noexcept;\n            static RECT Intersect(const RECT& rcta, const RECT& rctb) noexcept;\n\n            static Rectangle Union(const Rectangle& ra, const Rectangle& rb) noexcept;\n            static RECT Union(const RECT& rcta, const RECT& rctb) noexcept;\n        };\n\n        //------------------------------------------------------------------------------\n        // 2D vector\n        struct Vector2 : public XMFLOAT2\n        {\n            Vector2() noexcept : XMFLOAT2(0.f, 0.f) {}\n            constexpr explicit Vector2(float ix) noexcept : XMFLOAT2(ix, ix) {}\n            constexpr Vector2(float ix, float iy) noexcept : XMFLOAT2(ix, iy) {}\n            explicit Vector2(_In_reads_(2) const float *pArray) noexcept : XMFLOAT2(pArray) {}\n            Vector2(FXMVECTOR V) noexcept { XMStoreFloat2(this, V); }\n            Vector2(const XMFLOAT2& V) noexcept { this->x = V.x; this->y = V.y; }\n            explicit Vector2(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; }\n\n            Vector2(const Vector2&) = default;\n            Vector2& operator=(const Vector2&) = default;\n\n            Vector2(Vector2&&) = default;\n            Vector2& operator=(Vector2&&) = default;\n\n            operator XMVECTOR() const noexcept { return XMLoadFloat2(this); }\n\n            // Comparison operators\n            bool operator == (const Vector2& V) const noexcept;\n            bool operator != (const Vector2& V) const noexcept;\n\n            // Assignment operators\n            Vector2& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; return *this; }\n            Vector2& operator+= (const Vector2& V) noexcept;\n            Vector2& operator-= (const Vector2& V) noexcept;\n            Vector2& operator*= (const Vector2& V) noexcept;\n            Vector2& operator*= (float S) noexcept;\n            Vector2& operator/= (float S) noexcept;\n\n            // Unary operators\n            Vector2 operator+ () const noexcept { return *this; }\n            Vector2 operator- () const noexcept { return Vector2(-x, -y); }\n\n            // Vector operations\n            bool InBounds(const Vector2& Bounds) const noexcept;\n\n            float Length() const noexcept;\n            float LengthSquared() const noexcept;\n\n            float Dot(const Vector2& V) const noexcept;\n            void Cross(const Vector2& V, Vector2& result) const noexcept;\n            Vector2 Cross(const Vector2& V) const noexcept;\n\n            void Normalize() noexcept;\n            void Normalize(Vector2& result) const noexcept;\n\n            void Clamp(const Vector2& vmin, const Vector2& vmax) noexcept;\n            void Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const noexcept;\n\n            // Static functions\n            static float Distance(const Vector2& v1, const Vector2& v2) noexcept;\n            static float DistanceSquared(const Vector2& v1, const Vector2& v2) noexcept;\n\n            static void Min(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept;\n            static Vector2 Min(const Vector2& v1, const Vector2& v2) noexcept;\n\n            static void Max(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept;\n            static Vector2 Max(const Vector2& v1, const Vector2& v2) noexcept;\n\n            static void Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept;\n            static Vector2 Lerp(const Vector2& v1, const Vector2& v2, float t) noexcept;\n\n            static void SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept;\n            static Vector2 SmoothStep(const Vector2& v1, const Vector2& v2, float t) noexcept;\n\n            static void Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result) noexcept;\n            static Vector2 Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g) noexcept;\n\n            static void CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result) noexcept;\n            static Vector2 CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t) noexcept;\n\n            static void Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result) noexcept;\n            static Vector2 Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t) noexcept;\n\n            static void Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result) noexcept;\n            static Vector2 Reflect(const Vector2& ivec, const Vector2& nvec) noexcept;\n\n            static void Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result) noexcept;\n            static Vector2 Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex) noexcept;\n\n            static void Transform(const Vector2& v, const Quaternion& quat, Vector2& result) noexcept;\n            static Vector2 Transform(const Vector2& v, const Quaternion& quat) noexcept;\n\n            static void Transform(const Vector2& v, const Matrix& m, Vector2& result) noexcept;\n            static Vector2 Transform(const Vector2& v, const Matrix& m) noexcept;\n            static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray) noexcept;\n\n            static void Transform(const Vector2& v, const Matrix& m, Vector4& result) noexcept;\n            static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray) noexcept;\n\n            static void TransformNormal(const Vector2& v, const Matrix& m, Vector2& result) noexcept;\n            static Vector2 TransformNormal(const Vector2& v, const Matrix& m) noexcept;\n            static void TransformNormal(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray) noexcept;\n\n            // Constants\n            static const Vector2 Zero;\n            static const Vector2 One;\n            static const Vector2 UnitX;\n            static const Vector2 UnitY;\n        };\n\n        // Binary operators\n        Vector2 operator+ (const Vector2& V1, const Vector2& V2) noexcept;\n        Vector2 operator- (const Vector2& V1, const Vector2& V2) noexcept;\n        Vector2 operator* (const Vector2& V1, const Vector2& V2) noexcept;\n        Vector2 operator* (const Vector2& V, float S) noexcept;\n        Vector2 operator/ (const Vector2& V1, const Vector2& V2) noexcept;\n        Vector2 operator/ (const Vector2& V, float S) noexcept;\n        Vector2 operator* (float S, const Vector2& V) noexcept;\n\n        //------------------------------------------------------------------------------\n        // 3D vector\n        struct Vector3 : public XMFLOAT3\n        {\n            Vector3() noexcept : XMFLOAT3(0.f, 0.f, 0.f) {}\n            constexpr explicit Vector3(float ix) noexcept : XMFLOAT3(ix, ix, ix) {}\n            constexpr Vector3(float ix, float iy, float iz) noexcept : XMFLOAT3(ix, iy, iz) {}\n            explicit Vector3(_In_reads_(3) const float *pArray) noexcept : XMFLOAT3(pArray) {}\n            Vector3(FXMVECTOR V) noexcept { XMStoreFloat3(this, V); }\n            Vector3(const XMFLOAT3& V) noexcept { this->x = V.x; this->y = V.y; this->z = V.z; }\n            explicit Vector3(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; }\n\n            Vector3(const Vector3&) = default;\n            Vector3& operator=(const Vector3&) = default;\n\n            Vector3(Vector3&&) = default;\n            Vector3& operator=(Vector3&&) = default;\n\n            operator XMVECTOR() const noexcept { return XMLoadFloat3(this); }\n\n            // Comparison operators\n            bool operator == (const Vector3& V) const noexcept;\n            bool operator != (const Vector3& V) const noexcept;\n\n            // Assignment operators\n            Vector3& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; return *this; }\n            Vector3& operator+= (const Vector3& V) noexcept;\n            Vector3& operator-= (const Vector3& V) noexcept;\n            Vector3& operator*= (const Vector3& V) noexcept;\n            Vector3& operator*= (float S) noexcept;\n            Vector3& operator/= (float S) noexcept;\n\n            // Unary operators\n            Vector3 operator+ () const noexcept { return *this; }\n            Vector3 operator- () const noexcept;\n\n            // Vector operations\n            bool InBounds(const Vector3& Bounds) const noexcept;\n\n            float Length() const noexcept;\n            float LengthSquared() const noexcept;\n\n            float Dot(const Vector3& V) const noexcept;\n            void Cross(const Vector3& V, Vector3& result) const noexcept;\n            Vector3 Cross(const Vector3& V) const noexcept;\n\n            void Normalize() noexcept;\n            void Normalize(Vector3& result) const noexcept;\n\n            void Clamp(const Vector3& vmin, const Vector3& vmax) noexcept;\n            void Clamp(const Vector3& vmin, const Vector3& vmax, Vector3& result) const noexcept;\n\n            // Static functions\n            static float Distance(const Vector3& v1, const Vector3& v2) noexcept;\n            static float DistanceSquared(const Vector3& v1, const Vector3& v2) noexcept;\n\n            static void Min(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept;\n            static Vector3 Min(const Vector3& v1, const Vector3& v2) noexcept;\n\n            static void Max(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept;\n            static Vector3 Max(const Vector3& v1, const Vector3& v2) noexcept;\n\n            static void Lerp(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept;\n            static Vector3 Lerp(const Vector3& v1, const Vector3& v2, float t) noexcept;\n\n            static void SmoothStep(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept;\n            static Vector3 SmoothStep(const Vector3& v1, const Vector3& v2, float t) noexcept;\n\n            static void Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, Vector3& result) noexcept;\n            static Vector3 Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g) noexcept;\n\n            static void CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, Vector3& result) noexcept;\n            static Vector3 CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t) noexcept;\n\n            static void Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, Vector3& result) noexcept;\n            static Vector3 Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t) noexcept;\n\n            static void Reflect(const Vector3& ivec, const Vector3& nvec, Vector3& result) noexcept;\n            static Vector3 Reflect(const Vector3& ivec, const Vector3& nvec) noexcept;\n\n            static void Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result) noexcept;\n            static Vector3 Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex) noexcept;\n\n            static void Transform(const Vector3& v, const Quaternion& quat, Vector3& result) noexcept;\n            static Vector3 Transform(const Vector3& v, const Quaternion& quat) noexcept;\n\n            static void Transform(const Vector3& v, const Matrix& m, Vector3& result) noexcept;\n            static Vector3 Transform(const Vector3& v, const Matrix& m) noexcept;\n            static void Transform(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector3* resultArray) noexcept;\n\n            static void Transform(const Vector3& v, const Matrix& m, Vector4& result) noexcept;\n            static void Transform(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray) noexcept;\n\n            static void TransformNormal(const Vector3& v, const Matrix& m, Vector3& result) noexcept;\n            static Vector3 TransformNormal(const Vector3& v, const Matrix& m) noexcept;\n            static void TransformNormal(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector3* resultArray) noexcept;\n\n            // Constants\n            static const Vector3 Zero;\n            static const Vector3 One;\n            static const Vector3 UnitX;\n            static const Vector3 UnitY;\n            static const Vector3 UnitZ;\n            static const Vector3 Up;\n            static const Vector3 Down;\n            static const Vector3 Right;\n            static const Vector3 Left;\n            static const Vector3 Forward;\n            static const Vector3 Backward;\n        };\n\n        // Binary operators\n        Vector3 operator+ (const Vector3& V1, const Vector3& V2) noexcept;\n        Vector3 operator- (const Vector3& V1, const Vector3& V2) noexcept;\n        Vector3 operator* (const Vector3& V1, const Vector3& V2) noexcept;\n        Vector3 operator* (const Vector3& V, float S) noexcept;\n        Vector3 operator/ (const Vector3& V1, const Vector3& V2) noexcept;\n        Vector3 operator/ (const Vector3& V, float S) noexcept;\n        Vector3 operator* (float S, const Vector3& V) noexcept;\n\n        //------------------------------------------------------------------------------\n        // 4D vector\n        struct Vector4 : public XMFLOAT4\n        {\n            Vector4() noexcept : XMFLOAT4(0.f, 0.f, 0.f, 0.f) {}\n            constexpr explicit Vector4(float ix) noexcept : XMFLOAT4(ix, ix, ix, ix) {}\n            constexpr Vector4(float ix, float iy, float iz, float iw) noexcept : XMFLOAT4(ix, iy, iz, iw) {}\n            explicit Vector4(_In_reads_(4) const float *pArray) noexcept : XMFLOAT4(pArray) {}\n            Vector4(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }\n            Vector4(const XMFLOAT4& V) noexcept { this->x = V.x; this->y = V.y; this->z = V.z; this->w = V.w; }\n            explicit Vector4(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }\n\n            Vector4(const Vector4&) = default;\n            Vector4& operator=(const Vector4&) = default;\n\n            Vector4(Vector4&&) = default;\n            Vector4& operator=(Vector4&&) = default;\n\n            operator XMVECTOR() const  noexcept { return XMLoadFloat4(this); }\n\n            // Comparison operators\n            bool operator == (const Vector4& V) const noexcept;\n            bool operator != (const Vector4& V) const noexcept;\n\n            // Assignment operators\n            Vector4& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }\n            Vector4& operator+= (const Vector4& V) noexcept;\n            Vector4& operator-= (const Vector4& V) noexcept;\n            Vector4& operator*= (const Vector4& V) noexcept;\n            Vector4& operator*= (float S) noexcept;\n            Vector4& operator/= (float S) noexcept;\n\n            // Unary operators\n            Vector4 operator+ () const noexcept { return *this; }\n            Vector4 operator- () const noexcept;\n\n            // Vector operations\n            bool InBounds(const Vector4& Bounds) const noexcept;\n\n            float Length() const noexcept;\n            float LengthSquared() const noexcept;\n\n            float Dot(const Vector4& V) const noexcept;\n            void Cross(const Vector4& v1, const Vector4& v2, Vector4& result) const noexcept;\n            Vector4 Cross(const Vector4& v1, const Vector4& v2) const noexcept;\n\n            void Normalize() noexcept;\n            void Normalize(Vector4& result) const noexcept;\n\n            void Clamp(const Vector4& vmin, const Vector4& vmax) noexcept;\n            void Clamp(const Vector4& vmin, const Vector4& vmax, Vector4& result) const noexcept;\n\n            // Static functions\n            static float Distance(const Vector4& v1, const Vector4& v2) noexcept;\n            static float DistanceSquared(const Vector4& v1, const Vector4& v2) noexcept;\n\n            static void Min(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept;\n            static Vector4 Min(const Vector4& v1, const Vector4& v2) noexcept;\n\n            static void Max(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept;\n            static Vector4 Max(const Vector4& v1, const Vector4& v2) noexcept;\n\n            static void Lerp(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept;\n            static Vector4 Lerp(const Vector4& v1, const Vector4& v2, float t) noexcept;\n\n            static void SmoothStep(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept;\n            static Vector4 SmoothStep(const Vector4& v1, const Vector4& v2, float t) noexcept;\n\n            static void Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, Vector4& result) noexcept;\n            static Vector4 Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g) noexcept;\n             \n            static void CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, Vector4& result) noexcept;\n            static Vector4 CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t) noexcept;\n\n            static void Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, Vector4& result) noexcept;\n            static Vector4 Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t) noexcept;\n\n            static void Reflect(const Vector4& ivec, const Vector4& nvec, Vector4& result) noexcept;\n            static Vector4 Reflect(const Vector4& ivec, const Vector4& nvec) noexcept;\n\n            static void Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result) noexcept;\n            static Vector4 Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex) noexcept;\n\n            static void Transform(const Vector2& v, const Quaternion& quat, Vector4& result) noexcept;\n            static Vector4 Transform(const Vector2& v, const Quaternion& quat) noexcept;\n\n            static void Transform(const Vector3& v, const Quaternion& quat, Vector4& result) noexcept;\n            static Vector4 Transform(const Vector3& v, const Quaternion& quat) noexcept;\n\n            static void Transform(const Vector4& v, const Quaternion& quat, Vector4& result) noexcept;\n            static Vector4 Transform(const Vector4& v, const Quaternion& quat) noexcept;\n\n            static void Transform(const Vector4& v, const Matrix& m, Vector4& result) noexcept;\n            static Vector4 Transform(const Vector4& v, const Matrix& m) noexcept;\n            static void Transform(_In_reads_(count) const Vector4* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray) noexcept;\n\n            // Constants\n            static const Vector4 Zero;\n            static const Vector4 One;\n            static const Vector4 UnitX;\n            static const Vector4 UnitY;\n            static const Vector4 UnitZ;\n            static const Vector4 UnitW;\n        };\n\n        // Binary operators\n        Vector4 operator+ (const Vector4& V1, const Vector4& V2) noexcept;\n        Vector4 operator- (const Vector4& V1, const Vector4& V2) noexcept;\n        Vector4 operator* (const Vector4& V1, const Vector4& V2) noexcept;\n        Vector4 operator* (const Vector4& V, float S) noexcept;\n        Vector4 operator/ (const Vector4& V1, const Vector4& V2) noexcept;\n        Vector4 operator/ (const Vector4& V, float S) noexcept;\n        Vector4 operator* (float S, const Vector4& V) noexcept;\n\n        //------------------------------------------------------------------------------\n        // 4x4 Matrix (assumes right-handed cooordinates)\n        struct Matrix : public XMFLOAT4X4\n        {\n            Matrix() noexcept\n                : XMFLOAT4X4(1.f, 0, 0, 0,\n                            0, 1.f, 0, 0,\n                            0, 0, 1.f, 0,\n                            0, 0, 0, 1.f) {}\n            constexpr Matrix(float m00, float m01, float m02, float m03,\n                             float m10, float m11, float m12, float m13,\n                             float m20, float m21, float m22, float m23,\n                             float m30, float m31, float m32, float m33) noexcept\n                : XMFLOAT4X4(m00, m01, m02, m03,\n                             m10, m11, m12, m13,\n                             m20, m21, m22, m23,\n                             m30, m31, m32, m33) {}\n            explicit Matrix(const Vector3& r0, const Vector3& r1, const Vector3& r2) noexcept\n                : XMFLOAT4X4(r0.x, r0.y, r0.z, 0,\n                             r1.x, r1.y, r1.z, 0,\n                             r2.x, r2.y, r2.z, 0,\n                             0, 0, 0, 1.f) {}\n            explicit Matrix(const Vector4& r0, const Vector4& r1, const Vector4& r2, const Vector4& r3) noexcept\n                : XMFLOAT4X4(r0.x, r0.y, r0.z, r0.w,\n                             r1.x, r1.y, r1.z, r1.w,\n                             r2.x, r2.y, r2.z, r2.w,\n                             r3.x, r3.y, r3.z, r3.w) {}\n            Matrix(const XMFLOAT4X4& M) noexcept { memcpy_s(this, sizeof(float) * 16, &M, sizeof(XMFLOAT4X4)); }\n            Matrix(const XMFLOAT3X3& M) noexcept;\n            Matrix(const XMFLOAT4X3& M) noexcept;\n\n            explicit Matrix(_In_reads_(16) const float *pArray) noexcept : XMFLOAT4X4(pArray) {}\n            Matrix(CXMMATRIX M) noexcept { XMStoreFloat4x4(this, M); }\n\n            Matrix(const Matrix&) = default;\n            Matrix& operator=(const Matrix&) = default;\n\n            Matrix(Matrix&&) = default;\n            Matrix& operator=(Matrix&&) = default;\n\n            operator XMMATRIX() const noexcept { return XMLoadFloat4x4(this); }\n\n            // Comparison operators\n            bool operator == (const Matrix& M) const noexcept;\n            bool operator != (const Matrix& M) const noexcept;\n\n            // Assignment operators\n            Matrix& operator= (const XMFLOAT3X3& M) noexcept;\n            Matrix& operator= (const XMFLOAT4X3& M) noexcept;\n            Matrix& operator+= (const Matrix& M) noexcept;\n            Matrix& operator-= (const Matrix& M) noexcept;\n            Matrix& operator*= (const Matrix& M) noexcept;\n            Matrix& operator*= (float S) noexcept;\n            Matrix& operator/= (float S) noexcept;\n\n            Matrix& operator/= (const Matrix& M) noexcept;\n                // Element-wise divide\n\n            // Unary operators\n            Matrix operator+ () const noexcept { return *this; }\n            Matrix operator- () const noexcept;\n\n            // Properties\n            Vector3 Up() const noexcept { return Vector3(_21, _22, _23); }\n            void Up(const Vector3& v) noexcept { _21 = v.x; _22 = v.y; _23 = v.z; }\n\n            Vector3 Down() const  noexcept { return Vector3(-_21, -_22, -_23); }\n            void Down(const Vector3& v) noexcept { _21 = -v.x; _22 = -v.y; _23 = -v.z; }\n\n            Vector3 Right() const noexcept { return Vector3(_11, _12, _13); }\n            void Right(const Vector3& v) noexcept { _11 = v.x; _12 = v.y; _13 = v.z; }\n\n            Vector3 Left() const noexcept { return Vector3(-_11, -_12, -_13); }\n            void Left(const Vector3& v) noexcept { _11 = -v.x; _12 = -v.y; _13 = -v.z; }\n\n            Vector3 Forward() const noexcept { return Vector3(-_31, -_32, -_33); }\n            void Forward(const Vector3& v) noexcept { _31 = -v.x; _32 = -v.y; _33 = -v.z; }\n\n            Vector3 Backward() const noexcept { return Vector3(_31, _32, _33); }\n            void Backward(const Vector3& v) noexcept { _31 = v.x; _32 = v.y; _33 = v.z; }\n\n            Vector3 Translation() const  noexcept { return Vector3(_41, _42, _43); }\n            void Translation(const Vector3& v) noexcept { _41 = v.x; _42 = v.y; _43 = v.z; }\n\n            // Matrix operations\n            bool Decompose(Vector3& scale, Quaternion& rotation, Vector3& translation) noexcept;\n\n            Matrix Transpose() const noexcept;\n            void Transpose(Matrix& result) const noexcept;\n\n            Matrix Invert() const noexcept;\n            void Invert(Matrix& result) const noexcept;\n\n            float Determinant() const noexcept;\n\n            // Static functions\n            static Matrix CreateBillboard(\n                const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, _In_opt_ const Vector3* cameraForward = nullptr) noexcept;\n\n            static Matrix CreateConstrainedBillboard(\n                const Vector3& object, const Vector3& cameraPosition, const Vector3& rotateAxis,\n                _In_opt_ const Vector3* cameraForward = nullptr, _In_opt_ const Vector3* objectForward = nullptr) noexcept;\n\n            static Matrix CreateTranslation(const Vector3& position) noexcept;\n            static Matrix CreateTranslation(float x, float y, float z) noexcept;\n\n            static Matrix CreateScale(const Vector3& scales) noexcept;\n            static Matrix CreateScale(float xs, float ys, float zs) noexcept;\n            static Matrix CreateScale(float scale) noexcept;\n\n            static Matrix CreateRotationX(float radians) noexcept;\n            static Matrix CreateRotationY(float radians) noexcept;\n            static Matrix CreateRotationZ(float radians) noexcept;\n\n            static Matrix CreateFromAxisAngle(const Vector3& axis, float angle) noexcept;\n\n            static Matrix CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane, float farPlane) noexcept;\n            static Matrix CreatePerspective(float width, float height, float nearPlane, float farPlane) noexcept;\n            static Matrix CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlane, float farPlane) noexcept;\n            static Matrix CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) noexcept;\n            static Matrix CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) noexcept;\n\n            static Matrix CreateLookAt(const Vector3& position, const Vector3& target, const Vector3& up) noexcept;\n            static Matrix CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up) noexcept;\n\n            static Matrix CreateFromQuaternion(const Quaternion& quat) noexcept;\n\n            static Matrix CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept;\n\n            static Matrix CreateShadow(const Vector3& lightDir, const Plane& plane) noexcept;\n\n            static Matrix CreateReflection(const Plane& plane) noexcept;\n\n            static void Lerp(const Matrix& M1, const Matrix& M2, float t, Matrix& result) noexcept;\n            static Matrix Lerp(const Matrix& M1, const Matrix& M2, float t) noexcept;\n\n            static void Transform(const Matrix& M, const Quaternion& rotation, Matrix& result) noexcept;\n            static Matrix Transform(const Matrix& M, const Quaternion& rotation) noexcept;\n\n            // Constants\n            static const Matrix Identity;\n        };\n\n        // Binary operators\n        Matrix operator+ (const Matrix& M1, const Matrix& M2) noexcept;\n        Matrix operator- (const Matrix& M1, const Matrix& M2) noexcept;\n        Matrix operator* (const Matrix& M1, const Matrix& M2) noexcept;\n        Matrix operator* (const Matrix& M, float S) noexcept;\n        Matrix operator/ (const Matrix& M, float S) noexcept;\n        Matrix operator/ (const Matrix& M1, const Matrix& M2) noexcept;\n            // Element-wise divide\n        Matrix operator* (float S, const Matrix& M) noexcept;\n\n\n        //-----------------------------------------------------------------------------\n        // Plane\n        struct Plane : public XMFLOAT4\n        {\n            Plane() noexcept : XMFLOAT4(0.f, 1.f, 0.f, 0.f) {}\n            constexpr Plane(float ix, float iy, float iz, float iw) noexcept : XMFLOAT4(ix, iy, iz, iw) {}\n            Plane(const Vector3& normal, float d) noexcept : XMFLOAT4(normal.x, normal.y, normal.z, d) {}\n            Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3) noexcept;\n            Plane(const Vector3& point, const Vector3& normal) noexcept;\n            explicit Plane(const Vector4& v) noexcept : XMFLOAT4(v.x, v.y, v.z, v.w) {}\n            explicit Plane(_In_reads_(4) const float *pArray) noexcept : XMFLOAT4(pArray) {}\n            Plane(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }\n            Plane(const XMFLOAT4& p) noexcept { this->x = p.x; this->y = p.y; this->z = p.z; this->w = p.w; }\n            explicit Plane(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }\n\n            Plane(const Plane&) = default;\n            Plane& operator=(const Plane&) = default;\n\n            Plane(Plane&&) = default;\n            Plane& operator=(Plane&&) = default;\n\n            operator XMVECTOR() const noexcept { return XMLoadFloat4(this); }\n\n            // Comparison operators\n            bool operator == (const Plane& p) const noexcept;\n            bool operator != (const Plane& p) const noexcept;\n\n            // Assignment operators\n            Plane& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }\n\n            // Properties\n            Vector3 Normal() const noexcept { return Vector3(x, y, z); }\n            void Normal(const Vector3& normal) noexcept { x = normal.x; y = normal.y; z = normal.z; }\n\n            float D() const noexcept { return w; }\n            void D(float d) noexcept { w = d; }\n\n            // Plane operations\n            void Normalize() noexcept;\n            void Normalize(Plane& result) const noexcept;\n\n            float Dot(const Vector4& v) const noexcept;\n            float DotCoordinate(const Vector3& position) const noexcept;\n            float DotNormal(const Vector3& normal) const noexcept;\n\n            // Static functions\n            static void Transform(const Plane& plane, const Matrix& M, Plane& result) noexcept;\n            static Plane Transform(const Plane& plane, const Matrix& M) noexcept;\n\n            static void Transform(const Plane& plane, const Quaternion& rotation, Plane& result) noexcept;\n            static Plane Transform(const Plane& plane, const Quaternion& rotation) noexcept;\n                // Input quaternion must be the inverse transpose of the transformation\n        };\n\n        //------------------------------------------------------------------------------\n        // Quaternion\n        struct Quaternion : public XMFLOAT4\n        {\n            Quaternion() noexcept : XMFLOAT4(0, 0, 0, 1.f) {}\n            constexpr Quaternion(float ix, float iy, float iz, float iw) noexcept : XMFLOAT4(ix, iy, iz, iw) {}\n            Quaternion(const Vector3& v, float scalar) noexcept : XMFLOAT4(v.x, v.y, v.z, scalar) {}\n            explicit Quaternion(const Vector4& v) noexcept : XMFLOAT4(v.x, v.y, v.z, v.w) {}\n            explicit Quaternion(_In_reads_(4) const float *pArray) noexcept : XMFLOAT4(pArray) {}\n            Quaternion(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }\n            Quaternion(const XMFLOAT4& q) noexcept { this->x = q.x; this->y = q.y; this->z = q.z; this->w = q.w; }\n            explicit Quaternion(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }\n\n            Quaternion(const Quaternion&) = default;\n            Quaternion& operator=(const Quaternion&) = default;\n\n            Quaternion(Quaternion&&) = default;\n            Quaternion& operator=(Quaternion&&) = default;\n\n            operator XMVECTOR() const noexcept { return XMLoadFloat4(this); }\n\n            // Comparison operators\n            bool operator == (const Quaternion& q) const noexcept;\n            bool operator != (const Quaternion& q) const noexcept;\n\n            // Assignment operators\n            Quaternion& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }\n            Quaternion& operator+= (const Quaternion& q) noexcept;\n            Quaternion& operator-= (const Quaternion& q) noexcept;\n            Quaternion& operator*= (const Quaternion& q) noexcept;\n            Quaternion& operator*= (float S) noexcept;\n            Quaternion& operator/= (const Quaternion& q) noexcept;\n\n            // Unary operators\n            Quaternion operator+ () const  noexcept { return *this; }\n            Quaternion operator- () const noexcept;\n\n            // Quaternion operations\n            float Length() const noexcept;\n            float LengthSquared() const noexcept;\n\n            void Normalize() noexcept;\n            void Normalize(Quaternion& result) const noexcept;\n\n            void Conjugate() noexcept;\n            void Conjugate(Quaternion& result) const noexcept;\n\n            void Inverse(Quaternion& result) const noexcept;\n\n            float Dot(const Quaternion& Q) const noexcept;\n\n            // Static functions\n            static Quaternion CreateFromAxisAngle(const Vector3& axis, float angle) noexcept;\n            static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept;\n            static Quaternion CreateFromRotationMatrix(const Matrix& M) noexcept;\n\n            static void Lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept;\n            static Quaternion Lerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept;\n\n            static void Slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept;\n            static Quaternion Slerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept;\n\n            static void Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result) noexcept;\n            static Quaternion Concatenate(const Quaternion& q1, const Quaternion& q2) noexcept;\n\n            // Constants\n            static const Quaternion Identity;\n        };\n\n        // Binary operators\n        Quaternion operator+ (const Quaternion& Q1, const Quaternion& Q2) noexcept;\n        Quaternion operator- (const Quaternion& Q1, const Quaternion& Q2) noexcept;\n        Quaternion operator* (const Quaternion& Q1, const Quaternion& Q2) noexcept;\n        Quaternion operator* (const Quaternion& Q, float S) noexcept;\n        Quaternion operator/ (const Quaternion& Q1, const Quaternion& Q2) noexcept;\n        Quaternion operator* (float S, const Quaternion& Q) noexcept;\n\n        //------------------------------------------------------------------------------\n        // Color\n        struct Color : public XMFLOAT4\n        {\n            Color() noexcept : XMFLOAT4(0, 0, 0, 1.f) {}\n            constexpr Color(float _r, float _g, float _b) noexcept : XMFLOAT4(_r, _g, _b, 1.f) {}\n            constexpr Color(float _r, float _g, float _b, float _a) noexcept : XMFLOAT4(_r, _g, _b, _a) {}\n            explicit Color(const Vector3& clr) noexcept : XMFLOAT4(clr.x, clr.y, clr.z, 1.f) {}\n            explicit Color(const Vector4& clr) noexcept : XMFLOAT4(clr.x, clr.y, clr.z, clr.w) {}\n            explicit Color(_In_reads_(4) const float *pArray) noexcept : XMFLOAT4(pArray) {}\n            Color(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }\n            Color(const XMFLOAT4& c) noexcept { this->x = c.x; this->y = c.y; this->z = c.z; this->w = c.w; }\n            explicit Color(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }\n\n            explicit Color(const DirectX::PackedVector::XMCOLOR& Packed) noexcept;\n                // BGRA Direct3D 9 D3DCOLOR packed color\n\n            explicit Color(const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept;\n                // RGBA XNA Game Studio packed color\n\n            Color(const Color&) = default;\n            Color& operator=(const Color&) = default;\n\n            Color(Color&&) = default;\n            Color& operator=(Color&&) = default;\n\n            operator XMVECTOR() const noexcept { return XMLoadFloat4(this); }\n            operator const float*() const noexcept { return reinterpret_cast<const float*>(this); }\n\n            // Comparison operators\n            bool operator == (const Color& c) const noexcept;\n            bool operator != (const Color& c) const noexcept;\n\n            // Assignment operators\n            Color& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }\n            Color& operator= (const DirectX::PackedVector::XMCOLOR& Packed) noexcept;\n            Color& operator= (const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept;\n            Color& operator+= (const Color& c) noexcept;\n            Color& operator-= (const Color& c) noexcept;\n            Color& operator*= (const Color& c) noexcept;\n            Color& operator*= (float S) noexcept;\n            Color& operator/= (const Color& c) noexcept;\n\n            // Unary operators\n            Color operator+ () const noexcept { return *this; }\n            Color operator- () const noexcept;\n\n            // Properties\n            float R() const noexcept { return x; }\n            void R(float r) noexcept { x = r; }\n\n            float G() const noexcept { return y; }\n            void G(float g) noexcept { y = g; }\n\n            float B() const noexcept { return z; }\n            void B(float b) noexcept { z = b; }\n\n            float A() const noexcept { return w; }\n            void A(float a) noexcept { w = a; }\n\n            // Color operations\n            DirectX::PackedVector::XMCOLOR BGRA() const noexcept;\n            DirectX::PackedVector::XMUBYTEN4 RGBA() const noexcept;\n\n            Vector3 ToVector3() const noexcept;\n            Vector4 ToVector4() const noexcept;\n\n            void Negate() noexcept;\n            void Negate(Color& result) const noexcept;\n\n            void Saturate() noexcept;\n            void Saturate(Color& result) const noexcept;\n\n            void Premultiply() noexcept;\n            void Premultiply(Color& result) const noexcept;\n\n            void AdjustSaturation(float sat) noexcept;\n            void AdjustSaturation(float sat, Color& result) const noexcept;\n\n            void AdjustContrast(float contrast) noexcept;\n            void AdjustContrast(float contrast, Color& result) const noexcept;\n\n            // Static functions\n            static void Modulate(const Color& c1, const Color& c2, Color& result) noexcept;\n            static Color Modulate(const Color& c1, const Color& c2) noexcept;\n\n            static void Lerp(const Color& c1, const Color& c2, float t, Color& result) noexcept;\n            static Color Lerp(const Color& c1, const Color& c2, float t) noexcept;\n        };\n\n        // Binary operators\n        Color operator+ (const Color& C1, const Color& C2) noexcept;\n        Color operator- (const Color& C1, const Color& C2) noexcept;\n        Color operator* (const Color& C1, const Color& C2) noexcept;\n        Color operator* (const Color& C, float S) noexcept;\n        Color operator/ (const Color& C1, const Color& C2) noexcept;\n        Color operator* (float S, const Color& C) noexcept;\n\n        //------------------------------------------------------------------------------\n        // Ray\n        class Ray\n        {\n        public:\n            Vector3 position;\n            Vector3 direction;\n\n            Ray() noexcept : position(0, 0, 0), direction(0, 0, 1) {}\n            Ray(const Vector3& pos, const Vector3& dir) noexcept : position(pos), direction(dir) {}\n\n            Ray(const Ray&) = default;\n            Ray& operator=(const Ray&) = default;\n\n            Ray(Ray&&) = default;\n            Ray& operator=(Ray&&) = default;\n\n            // Comparison operators\n            bool operator == (const Ray& r) const noexcept;\n            bool operator != (const Ray& r) const noexcept;\n\n            // Ray operations\n            bool Intersects(const BoundingSphere& sphere, _Out_ float& Dist) const noexcept;\n            bool Intersects(const BoundingBox& box, _Out_ float& Dist) const noexcept;\n            bool Intersects(const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist) const noexcept;\n            bool Intersects(const Plane& plane, _Out_ float& Dist) const noexcept;\n        };\n\n        //------------------------------------------------------------------------------\n        // Viewport\n        class Viewport\n        {\n        public:\n            float x;\n            float y;\n            float width;\n            float height;\n            float minDepth;\n            float maxDepth;\n\n            Viewport() noexcept :\n                x(0.f), y(0.f), width(0.f), height(0.f), minDepth(0.f), maxDepth(1.f) {}\n            constexpr Viewport(float ix, float iy, float iw, float ih, float iminz = 0.f, float imaxz = 1.f) noexcept :\n                x(ix), y(iy), width(iw), height(ih), minDepth(iminz), maxDepth(imaxz) {}\n            explicit Viewport(const RECT& rct) noexcept :\n                x(float(rct.left)), y(float(rct.top)),\n                width(float(rct.right - rct.left)),\n                height(float(rct.bottom - rct.top)),\n                minDepth(0.f), maxDepth(1.f) {}\n\n        #if defined(__d3d11_h__) || defined(__d3d11_x_h__)\n            // Direct3D 11 interop\n            explicit Viewport(const D3D11_VIEWPORT& vp) noexcept :\n                x(vp.TopLeftX), y(vp.TopLeftY),\n                width(vp.Width), height(vp.Height),\n                minDepth(vp.MinDepth), maxDepth(vp.MaxDepth) {}\n\n            operator D3D11_VIEWPORT() noexcept { return *reinterpret_cast<const D3D11_VIEWPORT*>(this); }\n            const D3D11_VIEWPORT* Get11() const noexcept { return reinterpret_cast<const D3D11_VIEWPORT*>(this); }\n            Viewport& operator= (const D3D11_VIEWPORT& vp) noexcept;\n        #endif\n\n        #if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\n            // Direct3D 12 interop\n            explicit Viewport(const D3D12_VIEWPORT& vp) noexcept :\n                x(vp.TopLeftX), y(vp.TopLeftY),\n                width(vp.Width), height(vp.Height),\n                minDepth(vp.MinDepth), maxDepth(vp.MaxDepth) {}\n\n            operator D3D12_VIEWPORT() noexcept { return *reinterpret_cast<const D3D12_VIEWPORT*>(this); }\n            const D3D12_VIEWPORT* Get12() const noexcept { return reinterpret_cast<const D3D12_VIEWPORT*>(this); }\n            Viewport& operator= (const D3D12_VIEWPORT& vp) noexcept;\n        #endif\n\n            Viewport(const Viewport&) = default;\n            Viewport& operator=(const Viewport&) = default;\n\n            Viewport(Viewport&&) = default;\n            Viewport& operator=(Viewport&&) = default;\n\n            // Comparison operators\n            bool operator == (const Viewport& vp) const noexcept;\n            bool operator != (const Viewport& vp) const noexcept;\n\n            // Assignment operators\n            Viewport& operator= (const RECT& rct) noexcept;\n\n            // Viewport operations\n            float AspectRatio() const noexcept;\n\n            Vector3 Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept;\n            void Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept;\n\n            Vector3 Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept;\n            void Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept;\n\n            // Static methods\n            static RECT __cdecl ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, int outputWidth, int outputHeight) noexcept;\n            static RECT __cdecl ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight) noexcept;\n        };\n\n    #include \"SimpleMath.inl\"\n\n    } // namespace SimpleMath\n\n} // namespace DirectX\n\n//------------------------------------------------------------------------------\n// Support for SimpleMath and Standard C++ Library containers\nnamespace std\n{\n\n    template<> struct less<DirectX::SimpleMath::Rectangle>\n    {\n        bool operator()(const DirectX::SimpleMath::Rectangle& r1, const DirectX::SimpleMath::Rectangle& r2) const noexcept\n        {\n            return ((r1.x < r2.x)\n                    || ((r1.x == r2.x) && (r1.y < r2.y))\n                    || ((r1.x == r2.x) && (r1.y == r2.y) && (r1.width < r2.width))\n                    || ((r1.x == r2.x) && (r1.y == r2.y) && (r1.width == r2.width) && (r1.height < r2.height)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Vector2>\n    {\n        bool operator()(const DirectX::SimpleMath::Vector2& V1, const DirectX::SimpleMath::Vector2& V2) const noexcept\n        {\n            return ((V1.x < V2.x) || ((V1.x == V2.x) && (V1.y < V2.y)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Vector3>\n    {\n        bool operator()(const DirectX::SimpleMath::Vector3& V1, const DirectX::SimpleMath::Vector3& V2) const noexcept\n        {\n            return ((V1.x < V2.x)\n                    || ((V1.x == V2.x) && (V1.y < V2.y))\n                    || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Vector4>\n    {\n        bool operator()(const DirectX::SimpleMath::Vector4& V1, const DirectX::SimpleMath::Vector4& V2) const noexcept\n        {\n            return ((V1.x < V2.x)\n                    || ((V1.x == V2.x) && (V1.y < V2.y))\n                    || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z))\n                    || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z == V2.z) && (V1.w < V2.w)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Matrix>\n    {\n        bool operator()(const DirectX::SimpleMath::Matrix& M1, const DirectX::SimpleMath::Matrix& M2) const noexcept\n        {\n            if (M1._11 != M2._11) return M1._11 < M2._11;\n            if (M1._12 != M2._12) return M1._12 < M2._12;\n            if (M1._13 != M2._13) return M1._13 < M2._13;\n            if (M1._14 != M2._14) return M1._14 < M2._14;\n            if (M1._21 != M2._21) return M1._21 < M2._21;\n            if (M1._22 != M2._22) return M1._22 < M2._22;\n            if (M1._23 != M2._23) return M1._23 < M2._23;\n            if (M1._24 != M2._24) return M1._24 < M2._24;\n            if (M1._31 != M2._31) return M1._31 < M2._31;\n            if (M1._32 != M2._32) return M1._32 < M2._32;\n            if (M1._33 != M2._33) return M1._33 < M2._33;\n            if (M1._34 != M2._34) return M1._34 < M2._34;\n            if (M1._41 != M2._41) return M1._41 < M2._41;\n            if (M1._42 != M2._42) return M1._42 < M2._42;\n            if (M1._43 != M2._43) return M1._43 < M2._43;\n            if (M1._44 != M2._44) return M1._44 < M2._44;\n\n            return false;\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Plane>\n    {\n        bool operator()(const DirectX::SimpleMath::Plane& P1, const DirectX::SimpleMath::Plane& P2) const noexcept\n        {\n            return ((P1.x < P2.x)\n                    || ((P1.x == P2.x) && (P1.y < P2.y))\n                    || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z < P2.z))\n                    || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z == P2.z) && (P1.w < P2.w)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Quaternion>\n    {\n        bool operator()(const DirectX::SimpleMath::Quaternion& Q1, const DirectX::SimpleMath::Quaternion& Q2) const noexcept\n        {\n            return ((Q1.x < Q2.x)\n                    || ((Q1.x == Q2.x) && (Q1.y < Q2.y))\n                    || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z < Q2.z))\n                    || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z == Q2.z) && (Q1.w < Q2.w)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Color>\n    {\n        bool operator()(const DirectX::SimpleMath::Color& C1, const DirectX::SimpleMath::Color& C2) const noexcept\n        {\n            return ((C1.x < C2.x)\n                    || ((C1.x == C2.x) && (C1.y < C2.y))\n                    || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z < C2.z))\n                    || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z == C2.z) && (C1.w < C2.w)));\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Ray>\n    {\n        bool operator()(const DirectX::SimpleMath::Ray& R1, const DirectX::SimpleMath::Ray& R2) const noexcept\n        {\n            if (R1.position.x != R2.position.x) return R1.position.x < R2.position.x;\n            if (R1.position.y != R2.position.y) return R1.position.y < R2.position.y;\n            if (R1.position.z != R2.position.z) return R1.position.z < R2.position.z;\n\n            if (R1.direction.x != R2.direction.x) return R1.direction.x < R2.direction.x;\n            if (R1.direction.y != R2.direction.y) return R1.direction.y < R2.direction.y;\n            if (R1.direction.z != R2.direction.z) return R1.direction.z < R2.direction.z;\n\n            return false;\n        }\n    };\n\n    template<> struct less<DirectX::SimpleMath::Viewport>\n    {\n        bool operator()(const DirectX::SimpleMath::Viewport& vp1, const DirectX::SimpleMath::Viewport& vp2) const noexcept\n        {\n            if (vp1.x != vp2.x) return (vp1.x < vp2.x);\n            if (vp1.y != vp2.y) return (vp1.y < vp2.y);\n\n            if (vp1.width != vp2.width) return (vp1.width < vp2.width);\n            if (vp1.height != vp2.height) return (vp1.height < vp2.height);\n\n            if (vp1.minDepth != vp2.minDepth) return (vp1.minDepth < vp2.minDepth);\n            if (vp1.maxDepth != vp2.maxDepth) return (vp1.maxDepth < vp2.maxDepth);\n\n            return false;\n        }\n    };\n\n} // namespace std\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/SimpleMath.inl",
    "content": "//-------------------------------------------------------------------------------------\n// SimpleMath.inl -- Simplified C++ Math wrapper for DirectXMath\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n/****************************************************************************\n*\n* Rectangle\n*\n****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Rectangle operations\n//------------------------------------------------------------------------------\ninline Vector2 Rectangle::Location() const noexcept\n{\n    return Vector2(float(x), float(y));\n}\n\ninline Vector2 Rectangle::Center() const noexcept\n{\n    return Vector2(float(x) + (float(width) / 2.f), float(y) + (float(height) / 2.f));\n}\n\ninline bool Rectangle::Contains(const Vector2& point) const noexcept\n{\n    return (float(x) <= point.x) && (point.x < float(x + width)) && (float(y) <= point.y) && (point.y < float(y + height));\n}\n\ninline void Rectangle::Inflate(long horizAmount, long vertAmount) noexcept\n{\n    x -= horizAmount;\n    y -= vertAmount;\n    width += horizAmount;\n    height += vertAmount;\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline Rectangle Rectangle::Intersect(const Rectangle& ra, const Rectangle& rb) noexcept\n{\n    long righta = ra.x + ra.width;\n    long rightb = rb.x + rb.width;\n\n    long bottoma = ra.y + ra.height;\n    long bottomb = rb.y + rb.height;\n\n    long maxX = ra.x > rb.x ? ra.x : rb.x;\n    long maxY = ra.y > rb.y ? ra.y : rb.y;\n\n    long minRight = righta < rightb ? righta : rightb;\n    long minBottom = bottoma < bottomb ? bottoma : bottomb;\n\n    Rectangle result;\n\n    if ((minRight > maxX) && (minBottom > maxY))\n    {\n        result.x = maxX;\n        result.y = maxY;\n        result.width = minRight - maxX;\n        result.height = minBottom - maxY;\n    }\n    else\n    {\n        result.x = 0;\n        result.y = 0;\n        result.width = 0;\n        result.height = 0;\n    }\n\n    return result;\n}\n\ninline RECT Rectangle::Intersect(const RECT& rcta, const RECT& rctb) noexcept\n{\n    long maxX = rcta.left > rctb.left ? rcta.left : rctb.left;\n    long maxY = rcta.top > rctb.top ? rcta.top : rctb.top;\n\n    long minRight = rcta.right < rctb.right ? rcta.right : rctb.right;\n    long minBottom = rcta.bottom < rctb.bottom ? rcta.bottom : rctb.bottom;\n\n    RECT result;\n\n    if ((minRight > maxX) && (minBottom > maxY))\n    {\n        result.left = maxX;\n        result.top = maxY;\n        result.right = minRight;\n        result.bottom = minBottom;\n    }\n    else\n    {\n        result.left = 0;\n        result.top = 0;\n        result.right = 0;\n        result.bottom = 0;\n    }\n\n    return result;\n}\n\ninline Rectangle Rectangle::Union(const Rectangle& ra, const Rectangle& rb) noexcept\n{\n    long righta = ra.x + ra.width;\n    long rightb = rb.x + rb.width;\n\n    long bottoma = ra.y + ra.height;\n    long bottomb = rb.y + rb.height;\n\n    int minX = ra.x < rb.x ? ra.x : rb.x;\n    int minY = ra.y < rb.y ? ra.y : rb.y;\n\n    int maxRight = righta > rightb ? righta : rightb;\n    int maxBottom = bottoma > bottomb ? bottoma : bottomb;\n\n    Rectangle result;\n    result.x = minX;\n    result.y = minY;\n    result.width = maxRight - minX;\n    result.height = maxBottom - minY;\n    return result;\n}\n\ninline RECT Rectangle::Union(const RECT& rcta, const RECT& rctb) noexcept\n{\n    RECT result;\n    result.left = rcta.left < rctb.left ? rcta.left : rctb.left;\n    result.top = rcta.top < rctb.top ? rcta.top : rctb.top;\n    result.right = rcta.right > rctb.right ? rcta.right : rctb.right;\n    result.bottom = rcta.bottom > rctb.bottom ? rcta.bottom : rctb.bottom;\n    return result;\n}\n\n\n/****************************************************************************\n *\n * Vector2\n *\n ****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Vector2::operator == (const Vector2& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    return XMVector2Equal(v1, v2);\n}\n\ninline bool Vector2::operator != (const Vector2& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    return XMVector2NotEqual(v1, v2);\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Vector2& Vector2::operator+= (const Vector2& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVectorAdd(v1, v2);\n    XMStoreFloat2(this, X);\n    return *this;\n}\n\ninline Vector2& Vector2::operator-= (const Vector2& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVectorSubtract(v1, v2);\n    XMStoreFloat2(this, X);\n    return *this;\n}\n\ninline Vector2& Vector2::operator*= (const Vector2& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVectorMultiply(v1, v2);\n    XMStoreFloat2(this, X);\n    return *this;\n}\n\ninline Vector2& Vector2::operator*= (float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR X = XMVectorScale(v1, S);\n    XMStoreFloat2(this, X);\n    return *this;\n}\n\ninline Vector2& Vector2::operator/= (float S) noexcept\n{\n    using namespace DirectX;\n    assert(S != 0.0f);\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR X = XMVectorScale(v1, 1.f / S);\n    XMStoreFloat2(this, X);\n    return *this;\n}\n\n//------------------------------------------------------------------------------\n// Binary operators\n//------------------------------------------------------------------------------\n\ninline Vector2 operator+ (const Vector2& V1, const Vector2& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V1);\n    XMVECTOR v2 = XMLoadFloat2(&V2);\n    XMVECTOR X = XMVectorAdd(v1, v2);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\ninline Vector2 operator- (const Vector2& V1, const Vector2& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V1);\n    XMVECTOR v2 = XMLoadFloat2(&V2);\n    XMVECTOR X = XMVectorSubtract(v1, v2);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\ninline Vector2 operator* (const Vector2& V1, const Vector2& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V1);\n    XMVECTOR v2 = XMLoadFloat2(&V2);\n    XMVECTOR X = XMVectorMultiply(v1, v2);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\ninline Vector2 operator* (const Vector2& V, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVectorScale(v1, S);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\ninline Vector2 operator/ (const Vector2& V1, const Vector2& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V1);\n    XMVECTOR v2 = XMLoadFloat2(&V2);\n    XMVECTOR X = XMVectorDivide(v1, v2);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\ninline Vector2 operator/ (const Vector2& V, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVectorScale(v1, 1.f / S);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\ninline Vector2 operator* (float S, const Vector2& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVectorScale(v1, S);\n    Vector2 R;\n    XMStoreFloat2(&R, X);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Vector operations\n//------------------------------------------------------------------------------\n\ninline bool Vector2::InBounds(const Vector2& Bounds) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&Bounds);\n    return XMVector2InBounds(v1, v2);\n}\n\ninline float Vector2::Length() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR X = XMVector2Length(v1);\n    return XMVectorGetX(X);\n}\n\ninline float Vector2::LengthSquared() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR X = XMVector2LengthSq(v1);\n    return XMVectorGetX(X);\n}\n\ninline float Vector2::Dot(const Vector2& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    XMVECTOR X = XMVector2Dot(v1, v2);\n    return XMVectorGetX(X);\n}\n\ninline void Vector2::Cross(const Vector2& V, Vector2& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    XMVECTOR R = XMVector2Cross(v1, v2);\n    XMStoreFloat2(&result, R);\n}\n\ninline Vector2 Vector2::Cross(const Vector2& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&V);\n    XMVECTOR R = XMVector2Cross(v1, v2);\n\n    Vector2 result;\n    XMStoreFloat2(&result, R);\n    return result;\n}\n\ninline void Vector2::Normalize() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR X = XMVector2Normalize(v1);\n    XMStoreFloat2(this, X);\n}\n\ninline void Vector2::Normalize(Vector2& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR X = XMVector2Normalize(v1);\n    XMStoreFloat2(&result, X);\n}\n\ninline void Vector2::Clamp(const Vector2& vmin, const Vector2& vmax) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&vmin);\n    XMVECTOR v3 = XMLoadFloat2(&vmax);\n    XMVECTOR X = XMVectorClamp(v1, v2, v3);\n    XMStoreFloat2(this, X);\n}\n\ninline void Vector2::Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(this);\n    XMVECTOR v2 = XMLoadFloat2(&vmin);\n    XMVECTOR v3 = XMLoadFloat2(&vmax);\n    XMVECTOR X = XMVectorClamp(v1, v2, v3);\n    XMStoreFloat2(&result, X);\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline float Vector2::Distance(const Vector2& v1, const Vector2& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR V = XMVectorSubtract(x2, x1);\n    XMVECTOR X = XMVector2Length(V);\n    return XMVectorGetX(X);\n}\n\ninline float Vector2::DistanceSquared(const Vector2& v1, const Vector2& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR V = XMVectorSubtract(x2, x1);\n    XMVECTOR X = XMVector2LengthSq(V);\n    return XMVectorGetX(X);\n}\n\ninline void Vector2::Min(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorMin(x1, x2);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Min(const Vector2& v1, const Vector2& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorMin(x1, x2);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Max(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorMax(x1, x2);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Max(const Vector2& v1, const Vector2& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorMax(x1, x2);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Lerp(const Vector2& v1, const Vector2& v2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1\n    t = t * t*(3.f - 2.f*t);\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::SmoothStep(const Vector2& v1, const Vector2& v2, float t) noexcept\n{\n    using namespace DirectX;\n    t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1\n    t = t * t*(3.f - 2.f*t);\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR x3 = XMLoadFloat2(&v3);\n    XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR x3 = XMLoadFloat2(&v3);\n    XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR x3 = XMLoadFloat2(&v3);\n    XMVECTOR x4 = XMLoadFloat2(&v4);\n    XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&v2);\n    XMVECTOR x3 = XMLoadFloat2(&v3);\n    XMVECTOR x4 = XMLoadFloat2(&v4);\n    XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&t1);\n    XMVECTOR x3 = XMLoadFloat2(&v2);\n    XMVECTOR x4 = XMLoadFloat2(&t2);\n    XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat2(&v1);\n    XMVECTOR x2 = XMLoadFloat2(&t1);\n    XMVECTOR x3 = XMLoadFloat2(&v2);\n    XMVECTOR x4 = XMLoadFloat2(&t2);\n    XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat2(&ivec);\n    XMVECTOR n = XMLoadFloat2(&nvec);\n    XMVECTOR X = XMVector2Reflect(i, n);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Reflect(const Vector2& ivec, const Vector2& nvec) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat2(&ivec);\n    XMVECTOR n = XMLoadFloat2(&nvec);\n    XMVECTOR X = XMVector2Reflect(i, n);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat2(&ivec);\n    XMVECTOR n = XMLoadFloat2(&nvec);\n    XMVECTOR X = XMVector2Refract(i, n, refractionIndex);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat2(&ivec);\n    XMVECTOR n = XMLoadFloat2(&nvec);\n    XMVECTOR X = XMVector2Refract(i, n, refractionIndex);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Transform(const Vector2& v, const Quaternion& quat, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Transform(const Vector2& v, const Quaternion& quat) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\ninline void Vector2::Transform(const Vector2& v, const Matrix& m, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector2TransformCoord(v1, M);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::Transform(const Vector2& v, const Matrix& m) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector2TransformCoord(v1, M);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\n_Use_decl_annotations_\ninline void Vector2::Transform(const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector2TransformCoordStream(resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M);\n}\n\ninline void Vector2::Transform(const Vector2& v, const Matrix& m, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector2Transform(v1, M);\n    XMStoreFloat4(&result, X);\n}\n\n_Use_decl_annotations_\ninline void Vector2::Transform(const Vector2* varray, size_t count, const Matrix& m, Vector4* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector2TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT2), count, M);\n}\n\ninline void Vector2::TransformNormal(const Vector2& v, const Matrix& m, Vector2& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector2TransformNormal(v1, M);\n    XMStoreFloat2(&result, X);\n}\n\ninline Vector2 Vector2::TransformNormal(const Vector2& v, const Matrix& m) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector2TransformNormal(v1, M);\n\n    Vector2 result;\n    XMStoreFloat2(&result, X);\n    return result;\n}\n\n_Use_decl_annotations_\ninline void Vector2::TransformNormal(const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector2TransformNormalStream(resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M);\n}\n\n\n/****************************************************************************\n *\n * Vector3\n *\n ****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Vector3::operator == (const Vector3& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    return XMVector3Equal(v1, v2);\n}\n\ninline bool Vector3::operator != (const Vector3& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    return XMVector3NotEqual(v1, v2);\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Vector3& Vector3::operator+= (const Vector3& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVectorAdd(v1, v2);\n    XMStoreFloat3(this, X);\n    return *this;\n}\n\ninline Vector3& Vector3::operator-= (const Vector3& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVectorSubtract(v1, v2);\n    XMStoreFloat3(this, X);\n    return *this;\n}\n\ninline Vector3& Vector3::operator*= (const Vector3& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVectorMultiply(v1, v2);\n    XMStoreFloat3(this, X);\n    return *this;\n}\n\ninline Vector3& Vector3::operator*= (float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVectorScale(v1, S);\n    XMStoreFloat3(this, X);\n    return *this;\n}\n\ninline Vector3& Vector3::operator/= (float S) noexcept\n{\n    using namespace DirectX;\n    assert(S != 0.0f);\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVectorScale(v1, 1.f / S);\n    XMStoreFloat3(this, X);\n    return *this;\n}\n\n//------------------------------------------------------------------------------\n// Urnary operators\n//------------------------------------------------------------------------------\n\ninline Vector3 Vector3::operator- () const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVectorNegate(v1);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Binary operators\n//------------------------------------------------------------------------------\n\ninline Vector3 operator+ (const Vector3& V1, const Vector3& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V1);\n    XMVECTOR v2 = XMLoadFloat3(&V2);\n    XMVECTOR X = XMVectorAdd(v1, v2);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\ninline Vector3 operator- (const Vector3& V1, const Vector3& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V1);\n    XMVECTOR v2 = XMLoadFloat3(&V2);\n    XMVECTOR X = XMVectorSubtract(v1, v2);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\ninline Vector3 operator* (const Vector3& V1, const Vector3& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V1);\n    XMVECTOR v2 = XMLoadFloat3(&V2);\n    XMVECTOR X = XMVectorMultiply(v1, v2);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\ninline Vector3 operator* (const Vector3& V, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVectorScale(v1, S);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\ninline Vector3 operator/ (const Vector3& V1, const Vector3& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V1);\n    XMVECTOR v2 = XMLoadFloat3(&V2);\n    XMVECTOR X = XMVectorDivide(v1, v2);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\ninline Vector3 operator/ (const Vector3& V, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVectorScale(v1, 1.f / S);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\ninline Vector3 operator* (float S, const Vector3& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVectorScale(v1, S);\n    Vector3 R;\n    XMStoreFloat3(&R, X);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Vector operations\n//------------------------------------------------------------------------------\n\ninline bool Vector3::InBounds(const Vector3& Bounds) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&Bounds);\n    return XMVector3InBounds(v1, v2);\n}\n\ninline float Vector3::Length() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVector3Length(v1);\n    return XMVectorGetX(X);\n}\n\ninline float Vector3::LengthSquared() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVector3LengthSq(v1);\n    return XMVectorGetX(X);\n}\n\ninline float Vector3::Dot(const Vector3& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    XMVECTOR X = XMVector3Dot(v1, v2);\n    return XMVectorGetX(X);\n}\n\ninline void Vector3::Cross(const Vector3& V, Vector3& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    XMVECTOR R = XMVector3Cross(v1, v2);\n    XMStoreFloat3(&result, R);\n}\n\ninline Vector3 Vector3::Cross(const Vector3& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&V);\n    XMVECTOR R = XMVector3Cross(v1, v2);\n\n    Vector3 result;\n    XMStoreFloat3(&result, R);\n    return result;\n}\n\ninline void Vector3::Normalize() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVector3Normalize(v1);\n    XMStoreFloat3(this, X);\n}\n\ninline void Vector3::Normalize(Vector3& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR X = XMVector3Normalize(v1);\n    XMStoreFloat3(&result, X);\n}\n\ninline void Vector3::Clamp(const Vector3& vmin, const Vector3& vmax) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&vmin);\n    XMVECTOR v3 = XMLoadFloat3(&vmax);\n    XMVECTOR X = XMVectorClamp(v1, v2, v3);\n    XMStoreFloat3(this, X);\n}\n\ninline void Vector3::Clamp(const Vector3& vmin, const Vector3& vmax, Vector3& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(this);\n    XMVECTOR v2 = XMLoadFloat3(&vmin);\n    XMVECTOR v3 = XMLoadFloat3(&vmax);\n    XMVECTOR X = XMVectorClamp(v1, v2, v3);\n    XMStoreFloat3(&result, X);\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline float Vector3::Distance(const Vector3& v1, const Vector3& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR V = XMVectorSubtract(x2, x1);\n    XMVECTOR X = XMVector3Length(V);\n    return XMVectorGetX(X);\n}\n\ninline float Vector3::DistanceSquared(const Vector3& v1, const Vector3& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR V = XMVectorSubtract(x2, x1);\n    XMVECTOR X = XMVector3LengthSq(V);\n    return XMVectorGetX(X);\n}\n\ninline void Vector3::Min(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorMin(x1, x2);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Min(const Vector3& v1, const Vector3& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorMin(x1, x2);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Max(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorMax(x1, x2);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Max(const Vector3& v1, const Vector3& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorMax(x1, x2);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Lerp(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Lerp(const Vector3& v1, const Vector3& v2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::SmoothStep(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1\n    t = t * t*(3.f - 2.f*t);\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::SmoothStep(const Vector3& v1, const Vector3& v2, float t) noexcept\n{\n    using namespace DirectX;\n    t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1\n    t = t * t*(3.f - 2.f*t);\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR x3 = XMLoadFloat3(&v3);\n    XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR x3 = XMLoadFloat3(&v3);\n    XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR x3 = XMLoadFloat3(&v3);\n    XMVECTOR x4 = XMLoadFloat3(&v4);\n    XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&v2);\n    XMVECTOR x3 = XMLoadFloat3(&v3);\n    XMVECTOR x4 = XMLoadFloat3(&v4);\n    XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&t1);\n    XMVECTOR x3 = XMLoadFloat3(&v2);\n    XMVECTOR x4 = XMLoadFloat3(&t2);\n    XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat3(&v1);\n    XMVECTOR x2 = XMLoadFloat3(&t1);\n    XMVECTOR x3 = XMLoadFloat3(&v2);\n    XMVECTOR x4 = XMLoadFloat3(&t2);\n    XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Reflect(const Vector3& ivec, const Vector3& nvec, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat3(&ivec);\n    XMVECTOR n = XMLoadFloat3(&nvec);\n    XMVECTOR X = XMVector3Reflect(i, n);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Reflect(const Vector3& ivec, const Vector3& nvec) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat3(&ivec);\n    XMVECTOR n = XMLoadFloat3(&nvec);\n    XMVECTOR X = XMVector3Reflect(i, n);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat3(&ivec);\n    XMVECTOR n = XMLoadFloat3(&nvec);\n    XMVECTOR X = XMVector3Refract(i, n, refractionIndex);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat3(&ivec);\n    XMVECTOR n = XMLoadFloat3(&nvec);\n    XMVECTOR X = XMVector3Refract(i, n, refractionIndex);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Transform(const Vector3& v, const Quaternion& quat, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Transform(const Vector3& v, const Quaternion& quat) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\ninline void Vector3::Transform(const Vector3& v, const Matrix& m, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector3TransformCoord(v1, M);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::Transform(const Vector3& v, const Matrix& m) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector3TransformCoord(v1, M);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\n_Use_decl_annotations_\ninline void Vector3::Transform(const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector3TransformCoordStream(resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M);\n}\n\ninline void Vector3::Transform(const Vector3& v, const Matrix& m, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector3Transform(v1, M);\n    XMStoreFloat4(&result, X);\n}\n\n_Use_decl_annotations_\ninline void Vector3::Transform(const Vector3* varray, size_t count, const Matrix& m, Vector4* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector3TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT3), count, M);\n}\n\ninline void Vector3::TransformNormal(const Vector3& v, const Matrix& m, Vector3& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector3TransformNormal(v1, M);\n    XMStoreFloat3(&result, X);\n}\n\ninline Vector3 Vector3::TransformNormal(const Vector3& v, const Matrix& m) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector3TransformNormal(v1, M);\n\n    Vector3 result;\n    XMStoreFloat3(&result, X);\n    return result;\n}\n\n_Use_decl_annotations_\ninline void Vector3::TransformNormal(const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector3TransformNormalStream(resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M);\n}\n\n\n/****************************************************************************\n *\n * Vector4\n *\n ****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Vector4::operator == (const Vector4& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&V);\n    return XMVector4Equal(v1, v2);\n}\n\ninline bool Vector4::operator != (const Vector4& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&V);\n    return XMVector4NotEqual(v1, v2);\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Vector4& Vector4::operator+= (const Vector4& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVectorAdd(v1, v2);\n    XMStoreFloat4(this, X);\n    return *this;\n}\n\ninline Vector4& Vector4::operator-= (const Vector4& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVectorSubtract(v1, v2);\n    XMStoreFloat4(this, X);\n    return *this;\n}\n\ninline Vector4& Vector4::operator*= (const Vector4& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVectorMultiply(v1, v2);\n    XMStoreFloat4(this, X);\n    return *this;\n}\n\ninline Vector4& Vector4::operator*= (float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVectorScale(v1, S);\n    XMStoreFloat4(this, X);\n    return *this;\n}\n\ninline Vector4& Vector4::operator/= (float S) noexcept\n{\n    using namespace DirectX;\n    assert(S != 0.0f);\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVectorScale(v1, 1.f / S);\n    XMStoreFloat4(this, X);\n    return *this;\n}\n\n//------------------------------------------------------------------------------\n// Urnary operators\n//------------------------------------------------------------------------------\n\ninline Vector4 Vector4::operator- () const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVectorNegate(v1);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Binary operators\n//------------------------------------------------------------------------------\n\ninline Vector4 operator+ (const Vector4& V1, const Vector4& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V1);\n    XMVECTOR v2 = XMLoadFloat4(&V2);\n    XMVECTOR X = XMVectorAdd(v1, v2);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\ninline Vector4 operator- (const Vector4& V1, const Vector4& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V1);\n    XMVECTOR v2 = XMLoadFloat4(&V2);\n    XMVECTOR X = XMVectorSubtract(v1, v2);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\ninline Vector4 operator* (const Vector4& V1, const Vector4& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V1);\n    XMVECTOR v2 = XMLoadFloat4(&V2);\n    XMVECTOR X = XMVectorMultiply(v1, v2);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\ninline Vector4 operator* (const Vector4& V, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVectorScale(v1, S);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\ninline Vector4 operator/ (const Vector4& V1, const Vector4& V2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V1);\n    XMVECTOR v2 = XMLoadFloat4(&V2);\n    XMVECTOR X = XMVectorDivide(v1, v2);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\ninline Vector4 operator/ (const Vector4& V, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVectorScale(v1, 1.f / S);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\ninline Vector4 operator* (float S, const Vector4& V) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVectorScale(v1, S);\n    Vector4 R;\n    XMStoreFloat4(&R, X);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Vector operations\n//------------------------------------------------------------------------------\n\ninline bool Vector4::InBounds(const Vector4& Bounds) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&Bounds);\n    return XMVector4InBounds(v1, v2);\n}\n\ninline float Vector4::Length() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVector4Length(v1);\n    return XMVectorGetX(X);\n}\n\ninline float Vector4::LengthSquared() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVector4LengthSq(v1);\n    return XMVectorGetX(X);\n}\n\ninline float Vector4::Dot(const Vector4& V) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&V);\n    XMVECTOR X = XMVector4Dot(v1, v2);\n    return XMVectorGetX(X);\n}\n\ninline void Vector4::Cross(const Vector4& v1, const Vector4& v2, Vector4& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(this);\n    XMVECTOR x2 = XMLoadFloat4(&v1);\n    XMVECTOR x3 = XMLoadFloat4(&v2);\n    XMVECTOR R = XMVector4Cross(x1, x2, x3);\n    XMStoreFloat4(&result, R);\n}\n\ninline Vector4 Vector4::Cross(const Vector4& v1, const Vector4& v2) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(this);\n    XMVECTOR x2 = XMLoadFloat4(&v1);\n    XMVECTOR x3 = XMLoadFloat4(&v2);\n    XMVECTOR R = XMVector4Cross(x1, x2, x3);\n\n    Vector4 result;\n    XMStoreFloat4(&result, R);\n    return result;\n}\n\ninline void Vector4::Normalize() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVector4Normalize(v1);\n    XMStoreFloat4(this, X);\n}\n\ninline void Vector4::Normalize(Vector4& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR X = XMVector4Normalize(v1);\n    XMStoreFloat4(&result, X);\n}\n\ninline void Vector4::Clamp(const Vector4& vmin, const Vector4& vmax) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&vmin);\n    XMVECTOR v3 = XMLoadFloat4(&vmax);\n    XMVECTOR X = XMVectorClamp(v1, v2, v3);\n    XMStoreFloat4(this, X);\n}\n\ninline void Vector4::Clamp(const Vector4& vmin, const Vector4& vmax, Vector4& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(this);\n    XMVECTOR v2 = XMLoadFloat4(&vmin);\n    XMVECTOR v3 = XMLoadFloat4(&vmax);\n    XMVECTOR X = XMVectorClamp(v1, v2, v3);\n    XMStoreFloat4(&result, X);\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline float Vector4::Distance(const Vector4& v1, const Vector4& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR V = XMVectorSubtract(x2, x1);\n    XMVECTOR X = XMVector4Length(V);\n    return XMVectorGetX(X);\n}\n\ninline float Vector4::DistanceSquared(const Vector4& v1, const Vector4& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR V = XMVectorSubtract(x2, x1);\n    XMVECTOR X = XMVector4LengthSq(V);\n    return XMVectorGetX(X);\n}\n\ninline void Vector4::Min(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorMin(x1, x2);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Min(const Vector4& v1, const Vector4& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorMin(x1, x2);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Max(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorMax(x1, x2);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Max(const Vector4& v1, const Vector4& v2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorMax(x1, x2);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Lerp(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Lerp(const Vector4& v1, const Vector4& v2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::SmoothStep(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1\n    t = t * t*(3.f - 2.f*t);\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::SmoothStep(const Vector4& v1, const Vector4& v2, float t) noexcept\n{\n    using namespace DirectX;\n    t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1\n    t = t * t*(3.f - 2.f*t);\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR X = XMVectorLerp(x1, x2, t);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR x3 = XMLoadFloat4(&v3);\n    XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR x3 = XMLoadFloat4(&v3);\n    XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR x3 = XMLoadFloat4(&v3);\n    XMVECTOR x4 = XMLoadFloat4(&v4);\n    XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&v2);\n    XMVECTOR x3 = XMLoadFloat4(&v3);\n    XMVECTOR x4 = XMLoadFloat4(&v4);\n    XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&t1);\n    XMVECTOR x3 = XMLoadFloat4(&v2);\n    XMVECTOR x4 = XMLoadFloat4(&t2);\n    XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(&v1);\n    XMVECTOR x2 = XMLoadFloat4(&t1);\n    XMVECTOR x3 = XMLoadFloat4(&v2);\n    XMVECTOR x4 = XMLoadFloat4(&t2);\n    XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Reflect(const Vector4& ivec, const Vector4& nvec, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat4(&ivec);\n    XMVECTOR n = XMLoadFloat4(&nvec);\n    XMVECTOR X = XMVector4Reflect(i, n);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Reflect(const Vector4& ivec, const Vector4& nvec) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat4(&ivec);\n    XMVECTOR n = XMLoadFloat4(&nvec);\n    XMVECTOR X = XMVector4Reflect(i, n);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat4(&ivec);\n    XMVECTOR n = XMLoadFloat4(&nvec);\n    XMVECTOR X = XMVector4Refract(i, n, refractionIndex);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR i = XMLoadFloat4(&ivec);\n    XMVECTOR n = XMLoadFloat4(&nvec);\n    XMVECTOR X = XMVector4Refract(i, n, refractionIndex);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Transform(const Vector2& v, const Quaternion& quat, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Transform(const Vector2& v, const Quaternion& quat) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat2(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Transform(const Vector3& v, const Quaternion& quat, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Transform(const Vector3& v, const Quaternion& quat) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat3(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Transform(const Vector4& v, const Quaternion& quat, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    X = XMVectorSelect(v1, X, g_XMSelect1110); // result.w = v.w\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Transform(const Vector4& v, const Quaternion& quat) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&v);\n    XMVECTOR q = XMLoadFloat4(&quat);\n    XMVECTOR X = XMVector3Rotate(v1, q);\n    X = XMVectorSelect(v1, X, g_XMSelect1110); // result.w = v.w\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\ninline void Vector4::Transform(const Vector4& v, const Matrix& m, Vector4& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector4Transform(v1, M);\n    XMStoreFloat4(&result, X);\n}\n\ninline Vector4 Vector4::Transform(const Vector4& v, const Matrix& m) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(&v);\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVECTOR X = XMVector4Transform(v1, M);\n\n    Vector4 result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\n_Use_decl_annotations_\ninline void Vector4::Transform(const Vector4* varray, size_t count, const Matrix& m, Vector4* resultArray) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(&m);\n    XMVector4TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT4), count, M);\n}\n\n\n/****************************************************************************\n *\n * Matrix\n *\n ****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Matrix::operator == (const Matrix& M) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    return (XMVector4Equal(x1, y1)\n            && XMVector4Equal(x2, y2)\n            && XMVector4Equal(x3, y3)\n            && XMVector4Equal(x4, y4)) != 0;\n}\n\ninline bool Matrix::operator != (const Matrix& M) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    return (XMVector4NotEqual(x1, y1)\n            || XMVector4NotEqual(x2, y2)\n            || XMVector4NotEqual(x3, y3)\n            || XMVector4NotEqual(x4, y4)) != 0;\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Matrix::Matrix(const XMFLOAT3X3& M) noexcept\n{\n    _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;\n    _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;\n    _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;\n    _41 = 0.f;   _42 = 0.f;   _43 = 0.f;   _44 = 1.f;\n}\n\ninline Matrix::Matrix(const XMFLOAT4X3& M) noexcept\n{\n    _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;\n    _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;\n    _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;\n    _41 = M._41; _42 = M._42; _43 = M._43; _44 = 1.f;\n}\n\ninline Matrix& Matrix::operator= (const XMFLOAT3X3& M) noexcept\n{\n    _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;\n    _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;\n    _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;\n    _41 = 0.f;   _42 = 0.f;   _43 = 0.f;   _44 = 1.f;\n    return *this;\n}\n\ninline Matrix& Matrix::operator= (const XMFLOAT4X3& M) noexcept\n{\n    _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;\n    _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;\n    _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;\n    _41 = M._41; _42 = M._42; _43 = M._43; _44 = 1.f;\n    return *this;\n}\n\ninline Matrix& Matrix::operator+= (const Matrix& M) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    x1 = XMVectorAdd(x1, y1);\n    x2 = XMVectorAdd(x2, y2);\n    x3 = XMVectorAdd(x3, y3);\n    x4 = XMVectorAdd(x4, y4);\n\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);\n    return *this;\n}\n\ninline Matrix& Matrix::operator-= (const Matrix& M) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    x1 = XMVectorSubtract(x1, y1);\n    x2 = XMVectorSubtract(x2, y2);\n    x3 = XMVectorSubtract(x3, y3);\n    x4 = XMVectorSubtract(x4, y4);\n\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);\n    return *this;\n}\n\ninline Matrix& Matrix::operator*= (const Matrix& M) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M1 = XMLoadFloat4x4(this);\n    XMMATRIX M2 = XMLoadFloat4x4(&M);\n    XMMATRIX X = XMMatrixMultiply(M1, M2);\n    XMStoreFloat4x4(this, X);\n    return *this;\n}\n\ninline Matrix& Matrix::operator*= (float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    x1 = XMVectorScale(x1, S);\n    x2 = XMVectorScale(x2, S);\n    x3 = XMVectorScale(x3, S);\n    x4 = XMVectorScale(x4, S);\n\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);\n    return *this;\n}\n\ninline Matrix& Matrix::operator/= (float S) noexcept\n{\n    using namespace DirectX;\n    assert(S != 0.f);\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    float rs = 1.f / S;\n\n    x1 = XMVectorScale(x1, rs);\n    x2 = XMVectorScale(x2, rs);\n    x3 = XMVectorScale(x3, rs);\n    x4 = XMVectorScale(x4, rs);\n\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);\n    return *this;\n}\n\ninline Matrix& Matrix::operator/= (const Matrix& M) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    x1 = XMVectorDivide(x1, y1);\n    x2 = XMVectorDivide(x2, y2);\n    x3 = XMVectorDivide(x3, y3);\n    x4 = XMVectorDivide(x4, y4);\n\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);\n    return *this;\n}\n\n//------------------------------------------------------------------------------\n// Urnary operators\n//------------------------------------------------------------------------------\n\ninline Matrix Matrix::operator- () const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));\n    XMVECTOR v2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));\n    XMVECTOR v3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));\n    XMVECTOR v4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));\n\n    v1 = XMVectorNegate(v1);\n    v2 = XMVectorNegate(v2);\n    v3 = XMVectorNegate(v3);\n    v4 = XMVectorNegate(v4);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), v1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), v2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), v3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), v4);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Binary operators\n//------------------------------------------------------------------------------\n\ninline Matrix operator+ (const Matrix& M1, const Matrix& M2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));\n\n    x1 = XMVectorAdd(x1, y1);\n    x2 = XMVectorAdd(x2, y2);\n    x3 = XMVectorAdd(x3, y3);\n    x4 = XMVectorAdd(x4, y4);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);\n    return R;\n}\n\ninline Matrix operator- (const Matrix& M1, const Matrix& M2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));\n\n    x1 = XMVectorSubtract(x1, y1);\n    x2 = XMVectorSubtract(x2, y2);\n    x3 = XMVectorSubtract(x3, y3);\n    x4 = XMVectorSubtract(x4, y4);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);\n    return R;\n}\n\ninline Matrix operator* (const Matrix& M1, const Matrix& M2) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX m1 = XMLoadFloat4x4(&M1);\n    XMMATRIX m2 = XMLoadFloat4x4(&M2);\n    XMMATRIX X = XMMatrixMultiply(m1, m2);\n\n    Matrix R;\n    XMStoreFloat4x4(&R, X);\n    return R;\n}\n\ninline Matrix operator* (const Matrix& M, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    x1 = XMVectorScale(x1, S);\n    x2 = XMVectorScale(x2, S);\n    x3 = XMVectorScale(x3, S);\n    x4 = XMVectorScale(x4, S);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);\n    return R;\n}\n\ninline Matrix operator/ (const Matrix& M, float S) noexcept\n{\n    using namespace DirectX;\n    assert(S != 0.f);\n\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    float rs = 1.f / S;\n\n    x1 = XMVectorScale(x1, rs);\n    x2 = XMVectorScale(x2, rs);\n    x3 = XMVectorScale(x3, rs);\n    x4 = XMVectorScale(x4, rs);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);\n    return R;\n}\n\ninline Matrix operator/ (const Matrix& M1, const Matrix& M2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));\n\n    x1 = XMVectorDivide(x1, y1);\n    x2 = XMVectorDivide(x2, y2);\n    x3 = XMVectorDivide(x3, y3);\n    x4 = XMVectorDivide(x4, y4);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);\n    return R;\n}\n\ninline Matrix operator* (float S, const Matrix& M) noexcept\n{\n    using namespace DirectX;\n\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));\n\n    x1 = XMVectorScale(x1, S);\n    x2 = XMVectorScale(x2, S);\n    x3 = XMVectorScale(x3, S);\n    x4 = XMVectorScale(x4, S);\n\n    Matrix R;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Matrix operations\n//------------------------------------------------------------------------------\n\ninline bool Matrix::Decompose(Vector3& scale, Quaternion& rotation, Vector3& translation) noexcept\n{\n    using namespace DirectX;\n\n    XMVECTOR s, r, t;\n\n    if (!XMMatrixDecompose(&s, &r, &t, *this))\n        return false;\n\n    XMStoreFloat3(&scale, s);\n    XMStoreFloat4(&rotation, r);\n    XMStoreFloat3(&translation, t);\n\n    return true;\n}\n\ninline Matrix Matrix::Transpose() const noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(this);\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixTranspose(M));\n    return R;\n}\n\ninline void Matrix::Transpose(Matrix& result) const noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(this);\n    XMStoreFloat4x4(&result, XMMatrixTranspose(M));\n}\n\ninline Matrix Matrix::Invert() const noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(this);\n    Matrix R;\n    XMVECTOR det;\n    XMStoreFloat4x4(&R, XMMatrixInverse(&det, M));\n    return R;\n}\n\ninline void Matrix::Invert(Matrix& result) const noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(this);\n    XMVECTOR det;\n    XMStoreFloat4x4(&result, XMMatrixInverse(&det, M));\n}\n\ninline float Matrix::Determinant() const noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M = XMLoadFloat4x4(this);\n    return XMVectorGetX(XMMatrixDeterminant(M));\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\n_Use_decl_annotations_\ninline Matrix Matrix::CreateBillboard(\n    const Vector3& object,\n    const Vector3& cameraPosition,\n    const Vector3& cameraUp,\n    const Vector3* cameraForward) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR O = XMLoadFloat3(&object);\n    XMVECTOR C = XMLoadFloat3(&cameraPosition);\n    XMVECTOR Z = XMVectorSubtract(O, C);\n\n    XMVECTOR N = XMVector3LengthSq(Z);\n    if (XMVector3Less(N, g_XMEpsilon))\n    {\n        if (cameraForward)\n        {\n            XMVECTOR F = XMLoadFloat3(cameraForward);\n            Z = XMVectorNegate(F);\n        }\n        else\n            Z = g_XMNegIdentityR2;\n    }\n    else\n    {\n        Z = XMVector3Normalize(Z);\n    }\n\n    XMVECTOR up = XMLoadFloat3(&cameraUp);\n    XMVECTOR X = XMVector3Cross(up, Z);\n    X = XMVector3Normalize(X);\n\n    XMVECTOR Y = XMVector3Cross(Z, X);\n\n    XMMATRIX M;\n    M.r[0] = X;\n    M.r[1] = Y;\n    M.r[2] = Z;\n    M.r[3] = XMVectorSetW(O, 1.f);\n\n    Matrix R;\n    XMStoreFloat4x4(&R, M);\n    return R;\n}\n\n_Use_decl_annotations_\ninline Matrix Matrix::CreateConstrainedBillboard(\n    const Vector3& object,\n    const Vector3& cameraPosition,\n    const Vector3& rotateAxis,\n    const Vector3* cameraForward,\n    const Vector3* objectForward) noexcept\n{\n    using namespace DirectX;\n\n    static const XMVECTORF32 s_minAngle = { { { 0.99825467075f, 0.99825467075f, 0.99825467075f, 0.99825467075f } } }; // 1.0 - XMConvertToRadians( 0.1f );\n\n    XMVECTOR O = XMLoadFloat3(&object);\n    XMVECTOR C = XMLoadFloat3(&cameraPosition);\n    XMVECTOR faceDir = XMVectorSubtract(O, C);\n\n    XMVECTOR N = XMVector3LengthSq(faceDir);\n    if (XMVector3Less(N, g_XMEpsilon))\n    {\n        if (cameraForward)\n        {\n            XMVECTOR F = XMLoadFloat3(cameraForward);\n            faceDir = XMVectorNegate(F);\n        }\n        else\n            faceDir = g_XMNegIdentityR2;\n    }\n    else\n    {\n        faceDir = XMVector3Normalize(faceDir);\n    }\n\n    XMVECTOR Y = XMLoadFloat3(&rotateAxis);\n    XMVECTOR X, Z;\n\n    XMVECTOR dot = XMVectorAbs(XMVector3Dot(Y, faceDir));\n    if (XMVector3Greater(dot, s_minAngle))\n    {\n        if (objectForward)\n        {\n            Z = XMLoadFloat3(objectForward);\n            dot = XMVectorAbs(XMVector3Dot(Y, Z));\n            if (XMVector3Greater(dot, s_minAngle))\n            {\n                dot = XMVectorAbs(XMVector3Dot(Y, g_XMNegIdentityR2));\n                Z = (XMVector3Greater(dot, s_minAngle)) ? g_XMIdentityR0 : g_XMNegIdentityR2;\n            }\n        }\n        else\n        {\n            dot = XMVectorAbs(XMVector3Dot(Y, g_XMNegIdentityR2));\n            Z = (XMVector3Greater(dot, s_minAngle)) ? g_XMIdentityR0 : g_XMNegIdentityR2;\n        }\n\n        X = XMVector3Cross(Y, Z);\n        X = XMVector3Normalize(X);\n\n        Z = XMVector3Cross(X, Y);\n        Z = XMVector3Normalize(Z);\n    }\n    else\n    {\n        X = XMVector3Cross(Y, faceDir);\n        X = XMVector3Normalize(X);\n\n        Z = XMVector3Cross(X, Y);\n        Z = XMVector3Normalize(Z);\n    }\n\n    XMMATRIX M;\n    M.r[0] = X;\n    M.r[1] = Y;\n    M.r[2] = Z;\n    M.r[3] = XMVectorSetW(O, 1.f);\n\n    Matrix R;\n    XMStoreFloat4x4(&R, M);\n    return R;\n}\n\ninline Matrix Matrix::CreateTranslation(const Vector3& position) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixTranslation(position.x, position.y, position.z));\n    return R;\n}\n\ninline Matrix Matrix::CreateTranslation(float x, float y, float z) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixTranslation(x, y, z));\n    return R;\n}\n\ninline Matrix Matrix::CreateScale(const Vector3& scales) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixScaling(scales.x, scales.y, scales.z));\n    return R;\n}\n\ninline Matrix Matrix::CreateScale(float xs, float ys, float zs) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixScaling(xs, ys, zs));\n    return R;\n}\n\ninline Matrix Matrix::CreateScale(float scale) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixScaling(scale, scale, scale));\n    return R;\n}\n\ninline Matrix Matrix::CreateRotationX(float radians) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixRotationX(radians));\n    return R;\n}\n\ninline Matrix Matrix::CreateRotationY(float radians) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixRotationY(radians));\n    return R;\n}\n\ninline Matrix Matrix::CreateRotationZ(float radians) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixRotationZ(radians));\n    return R;\n}\n\ninline Matrix Matrix::CreateFromAxisAngle(const Vector3& axis, float angle) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMVECTOR a = XMLoadFloat3(&axis);\n    XMStoreFloat4x4(&R, XMMatrixRotationAxis(a, angle));\n    return R;\n}\n\ninline Matrix Matrix::CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane, float farPlane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));\n    return R;\n}\n\ninline Matrix Matrix::CreatePerspective(float width, float height, float nearPlane, float farPlane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));\n    return R;\n}\n\ninline Matrix Matrix::CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlane, float farPlane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixPerspectiveOffCenterRH(left, right, bottom, top, nearPlane, farPlane));\n    return R;\n}\n\ninline Matrix Matrix::CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixOrthographicRH(width, height, zNearPlane, zFarPlane));\n    return R;\n}\n\ninline Matrix Matrix::CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixOrthographicOffCenterRH(left, right, bottom, top, zNearPlane, zFarPlane));\n    return R;\n}\n\ninline Matrix Matrix::CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMVECTOR eyev = XMLoadFloat3(&eye);\n    XMVECTOR targetv = XMLoadFloat3(&target);\n    XMVECTOR upv = XMLoadFloat3(&up);\n    XMStoreFloat4x4(&R, XMMatrixLookAtRH(eyev, targetv, upv));\n    return R;\n}\n\ninline Matrix Matrix::CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR zaxis = XMVector3Normalize(XMVectorNegate(XMLoadFloat3(&forward)));\n    XMVECTOR yaxis = XMLoadFloat3(&up);\n    XMVECTOR xaxis = XMVector3Normalize(XMVector3Cross(yaxis, zaxis));\n    yaxis = XMVector3Cross(zaxis, xaxis);\n\n    Matrix R;\n    XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&R._11), xaxis);\n    XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&R._21), yaxis);\n    XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&R._31), zaxis);\n    R._14 = R._24 = R._34 = 0.f;\n    R._41 = position.x; R._42 = position.y; R._43 = position.z;\n    R._44 = 1.f;\n    return R;\n}\n\ninline Matrix Matrix::CreateFromQuaternion(const Quaternion& rotation) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMVECTOR quatv = XMLoadFloat4(&rotation);\n    XMStoreFloat4x4(&R, XMMatrixRotationQuaternion(quatv));\n    return R;\n}\n\ninline Matrix Matrix::CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMStoreFloat4x4(&R, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));\n    return R;\n}\n\ninline Matrix Matrix::CreateShadow(const Vector3& lightDir, const Plane& plane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMVECTOR light = XMLoadFloat3(&lightDir);\n    XMVECTOR planev = XMLoadFloat4(&plane);\n    XMStoreFloat4x4(&R, XMMatrixShadow(planev, light));\n    return R;\n}\n\ninline Matrix Matrix::CreateReflection(const Plane& plane) noexcept\n{\n    using namespace DirectX;\n    Matrix R;\n    XMVECTOR planev = XMLoadFloat4(&plane);\n    XMStoreFloat4x4(&R, XMMatrixReflect(planev));\n    return R;\n}\n\ninline void Matrix::Lerp(const Matrix& M1, const Matrix& M2, float t, Matrix& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));\n\n    x1 = XMVectorLerp(x1, y1, t);\n    x2 = XMVectorLerp(x2, y2, t);\n    x3 = XMVectorLerp(x3, y3, t);\n    x4 = XMVectorLerp(x4, y4, t);\n\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._41), x4);\n}\n\ninline Matrix Matrix::Lerp(const Matrix& M1, const Matrix& M2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));\n    XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));\n    XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));\n    XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));\n\n    XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));\n    XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));\n    XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));\n    XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));\n\n    x1 = XMVectorLerp(x1, y1, t);\n    x2 = XMVectorLerp(x2, y2, t);\n    x3 = XMVectorLerp(x3, y3, t);\n    x4 = XMVectorLerp(x4, y4, t);\n\n    Matrix result;\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._11), x1);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._21), x2);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._31), x3);\n    XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._41), x4);\n    return result;\n}\n\ninline void Matrix::Transform(const Matrix& M, const Quaternion& rotation, Matrix& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR quatv = XMLoadFloat4(&rotation);\n\n    XMMATRIX M0 = XMLoadFloat4x4(&M);\n    XMMATRIX M1 = XMMatrixRotationQuaternion(quatv);\n\n    XMStoreFloat4x4(&result, XMMatrixMultiply(M0, M1));\n}\n\ninline Matrix Matrix::Transform(const Matrix& M, const Quaternion& rotation) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR quatv = XMLoadFloat4(&rotation);\n\n    XMMATRIX M0 = XMLoadFloat4x4(&M);\n    XMMATRIX M1 = XMMatrixRotationQuaternion(quatv);\n\n    Matrix result;\n    XMStoreFloat4x4(&result, XMMatrixMultiply(M0, M1));\n    return result;\n}\n\n\n/****************************************************************************\n *\n * Plane\n *\n ****************************************************************************/\n\ninline Plane::Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR P0 = XMLoadFloat3(&point1);\n    XMVECTOR P1 = XMLoadFloat3(&point2);\n    XMVECTOR P2 = XMLoadFloat3(&point3);\n    XMStoreFloat4(this, XMPlaneFromPoints(P0, P1, P2));\n}\n\ninline Plane::Plane(const Vector3& point, const Vector3& normal) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR P = XMLoadFloat3(&point);\n    XMVECTOR N = XMLoadFloat3(&normal);\n    XMStoreFloat4(this, XMPlaneFromPointNormal(P, N));\n}\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Plane::operator == (const Plane& p) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p1 = XMLoadFloat4(this);\n    XMVECTOR p2 = XMLoadFloat4(&p);\n    return XMPlaneEqual(p1, p2);\n}\n\ninline bool Plane::operator != (const Plane& p) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p1 = XMLoadFloat4(this);\n    XMVECTOR p2 = XMLoadFloat4(&p);\n    return XMPlaneNotEqual(p1, p2);\n}\n\n//------------------------------------------------------------------------------\n// Plane operations\n//------------------------------------------------------------------------------\n\ninline void Plane::Normalize() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMPlaneNormalize(p));\n}\n\ninline void Plane::Normalize(Plane& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMPlaneNormalize(p));\n}\n\ninline float Plane::Dot(const Vector4& v) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(this);\n    XMVECTOR v0 = XMLoadFloat4(&v);\n    return XMVectorGetX(XMPlaneDot(p, v0));\n}\n\ninline float Plane::DotCoordinate(const Vector3& position) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(this);\n    XMVECTOR v0 = XMLoadFloat3(&position);\n    return XMVectorGetX(XMPlaneDotCoord(p, v0));\n}\n\ninline float Plane::DotNormal(const Vector3& normal) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(this);\n    XMVECTOR n0 = XMLoadFloat3(&normal);\n    return XMVectorGetX(XMPlaneDotNormal(p, n0));\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline void Plane::Transform(const Plane& plane, const Matrix& M, Plane& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(&plane);\n    XMMATRIX m0 = XMLoadFloat4x4(&M);\n    XMStoreFloat4(&result, XMPlaneTransform(p, m0));\n}\n\ninline Plane Plane::Transform(const Plane& plane, const Matrix& M) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(&plane);\n    XMMATRIX m0 = XMLoadFloat4x4(&M);\n\n    Plane result;\n    XMStoreFloat4(&result, XMPlaneTransform(p, m0));\n    return result;\n}\n\ninline void Plane::Transform(const Plane& plane, const Quaternion& rotation, Plane& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(&plane);\n    XMVECTOR q = XMLoadFloat4(&rotation);\n    XMVECTOR X = XMVector3Rotate(p, q);\n    X = XMVectorSelect(p, X, g_XMSelect1110); // result.d = plane.d\n    XMStoreFloat4(&result, X);\n}\n\ninline Plane Plane::Transform(const Plane& plane, const Quaternion& rotation) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR p = XMLoadFloat4(&plane);\n    XMVECTOR q = XMLoadFloat4(&rotation);\n    XMVECTOR X = XMVector3Rotate(p, q);\n    X = XMVectorSelect(p, X, g_XMSelect1110); // result.d = plane.d\n\n    Plane result;\n    XMStoreFloat4(&result, X);\n    return result;\n}\n\n\n/****************************************************************************\n *\n * Quaternion\n *\n ****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Quaternion::operator == (const Quaternion& q) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    return XMQuaternionEqual(q1, q2);\n}\n\ninline bool Quaternion::operator != (const Quaternion& q) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    return XMQuaternionNotEqual(q1, q2);\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Quaternion& Quaternion::operator+= (const Quaternion& q) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    XMStoreFloat4(this, XMVectorAdd(q1, q2));\n    return *this;\n}\n\ninline Quaternion& Quaternion::operator-= (const Quaternion& q) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    XMStoreFloat4(this, XMVectorSubtract(q1, q2));\n    return *this;\n}\n\ninline Quaternion& Quaternion::operator*= (const Quaternion& q) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    XMStoreFloat4(this, XMQuaternionMultiply(q1, q2));\n    return *this;\n}\n\ninline Quaternion& Quaternion::operator*= (float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMVectorScale(q, S));\n    return *this;\n}\n\ninline Quaternion& Quaternion::operator/= (const Quaternion& q) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    q2 = XMQuaternionInverse(q2);\n    XMStoreFloat4(this, XMQuaternionMultiply(q1, q2));\n    return *this;\n}\n\n//------------------------------------------------------------------------------\n// Urnary operators\n//------------------------------------------------------------------------------\n\ninline Quaternion Quaternion::operator- () const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMVectorNegate(q));\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Binary operators\n//------------------------------------------------------------------------------\n\ninline Quaternion operator+ (const Quaternion& Q1, const Quaternion& Q2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(&Q1);\n    XMVECTOR q2 = XMLoadFloat4(&Q2);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMVectorAdd(q1, q2));\n    return R;\n}\n\ninline Quaternion operator- (const Quaternion& Q1, const Quaternion& Q2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(&Q1);\n    XMVECTOR q2 = XMLoadFloat4(&Q2);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMVectorSubtract(q1, q2));\n    return R;\n}\n\ninline Quaternion operator* (const Quaternion& Q1, const Quaternion& Q2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(&Q1);\n    XMVECTOR q2 = XMLoadFloat4(&Q2);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMQuaternionMultiply(q1, q2));\n    return R;\n}\n\ninline Quaternion operator* (const Quaternion& Q, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(&Q);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMVectorScale(q, S));\n    return R;\n}\n\ninline Quaternion operator/ (const Quaternion& Q1, const Quaternion& Q2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(&Q1);\n    XMVECTOR q2 = XMLoadFloat4(&Q2);\n    q2 = XMQuaternionInverse(q2);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMQuaternionMultiply(q1, q2));\n    return R;\n}\n\ninline Quaternion operator* (float S, const Quaternion& Q) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(&Q);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMVectorScale(q1, S));\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Quaternion operations\n//------------------------------------------------------------------------------\n\ninline float Quaternion::Length() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    return XMVectorGetX(XMQuaternionLength(q));\n}\n\ninline float Quaternion::LengthSquared() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    return XMVectorGetX(XMQuaternionLengthSq(q));\n}\n\ninline void Quaternion::Normalize() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMQuaternionNormalize(q));\n}\n\ninline void Quaternion::Normalize(Quaternion& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMQuaternionNormalize(q));\n}\n\ninline void Quaternion::Conjugate() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMQuaternionConjugate(q));\n}\n\ninline void Quaternion::Conjugate(Quaternion& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMQuaternionConjugate(q));\n}\n\ninline void Quaternion::Inverse(Quaternion& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMQuaternionInverse(q));\n}\n\ninline float Quaternion::Dot(const Quaternion& q) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR q1 = XMLoadFloat4(this);\n    XMVECTOR q2 = XMLoadFloat4(&q);\n    return XMVectorGetX(XMQuaternionDot(q1, q2));\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline Quaternion Quaternion::CreateFromAxisAngle(const Vector3& axis, float angle) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR a = XMLoadFloat3(&axis);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMQuaternionRotationAxis(a, angle));\n    return R;\n}\n\ninline Quaternion Quaternion::CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept\n{\n    using namespace DirectX;\n    Quaternion R;\n    XMStoreFloat4(&R, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));\n    return R;\n}\n\ninline Quaternion Quaternion::CreateFromRotationMatrix(const Matrix& M) noexcept\n{\n    using namespace DirectX;\n    XMMATRIX M0 = XMLoadFloat4x4(&M);\n\n    Quaternion R;\n    XMStoreFloat4(&R, XMQuaternionRotationMatrix(M0));\n    return R;\n}\n\ninline void Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR Q0 = XMLoadFloat4(&q1);\n    XMVECTOR Q1 = XMLoadFloat4(&q2);\n\n    XMVECTOR dot = XMVector4Dot(Q0, Q1);\n\n    XMVECTOR R;\n    if (XMVector4GreaterOrEqual(dot, XMVectorZero()))\n    {\n        R = XMVectorLerp(Q0, Q1, t);\n    }\n    else\n    {\n        XMVECTOR tv = XMVectorReplicate(t);\n        XMVECTOR t1v = XMVectorReplicate(1.f - t);\n        XMVECTOR X0 = XMVectorMultiply(Q0, t1v);\n        XMVECTOR X1 = XMVectorMultiply(Q1, tv);\n        R = XMVectorSubtract(X0, X1);\n    }\n\n    XMStoreFloat4(&result, XMQuaternionNormalize(R));\n}\n\ninline Quaternion Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR Q0 = XMLoadFloat4(&q1);\n    XMVECTOR Q1 = XMLoadFloat4(&q2);\n\n    XMVECTOR dot = XMVector4Dot(Q0, Q1);\n\n    XMVECTOR R;\n    if (XMVector4GreaterOrEqual(dot, XMVectorZero()))\n    {\n        R = XMVectorLerp(Q0, Q1, t);\n    }\n    else\n    {\n        XMVECTOR tv = XMVectorReplicate(t);\n        XMVECTOR t1v = XMVectorReplicate(1.f - t);\n        XMVECTOR X0 = XMVectorMultiply(Q0, t1v);\n        XMVECTOR X1 = XMVectorMultiply(Q1, tv);\n        R = XMVectorSubtract(X0, X1);\n    }\n\n    Quaternion result;\n    XMStoreFloat4(&result, XMQuaternionNormalize(R));\n    return result;\n}\n\ninline void Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR Q0 = XMLoadFloat4(&q1);\n    XMVECTOR Q1 = XMLoadFloat4(&q2);\n    XMStoreFloat4(&result, XMQuaternionSlerp(Q0, Q1, t));\n}\n\ninline Quaternion Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR Q0 = XMLoadFloat4(&q1);\n    XMVECTOR Q1 = XMLoadFloat4(&q2);\n\n    Quaternion result;\n    XMStoreFloat4(&result, XMQuaternionSlerp(Q0, Q1, t));\n    return result;\n}\n\ninline void Quaternion::Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR Q0 = XMLoadFloat4(&q1);\n    XMVECTOR Q1 = XMLoadFloat4(&q2);\n    XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q0));\n}\n\ninline Quaternion Quaternion::Concatenate(const Quaternion& q1, const Quaternion& q2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR Q0 = XMLoadFloat4(&q1);\n    XMVECTOR Q1 = XMLoadFloat4(&q2);\n\n    Quaternion result;\n    XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q0));\n    return result;\n}\n\n\n/****************************************************************************\n *\n * Color\n *\n ****************************************************************************/\n\ninline Color::Color(const DirectX::PackedVector::XMCOLOR& Packed) noexcept\n{\n    using namespace DirectX;\n    XMStoreFloat4(this, PackedVector::XMLoadColor(&Packed));\n}\n\ninline Color::Color(const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept\n{\n    using namespace DirectX;\n    XMStoreFloat4(this, PackedVector::XMLoadUByteN4(&Packed));\n}\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\ninline bool Color::operator == (const Color& c) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(this);\n    XMVECTOR c2 = XMLoadFloat4(&c);\n    return XMColorEqual(c1, c2);\n}\n\ninline bool Color::operator != (const Color& c) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(this);\n    XMVECTOR c2 = XMLoadFloat4(&c);\n    return XMColorNotEqual(c1, c2);\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Color& Color::operator= (const DirectX::PackedVector::XMCOLOR& Packed) noexcept\n{\n    using namespace DirectX;\n    XMStoreFloat4(this, PackedVector::XMLoadColor(&Packed));\n    return *this;\n}\n\ninline Color& Color::operator= (const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept\n{\n    using namespace DirectX;\n    XMStoreFloat4(this, PackedVector::XMLoadUByteN4(&Packed));\n    return *this;\n}\n\ninline Color& Color::operator+= (const Color& c) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(this);\n    XMVECTOR c2 = XMLoadFloat4(&c);\n    XMStoreFloat4(this, XMVectorAdd(c1, c2));\n    return *this;\n}\n\ninline Color& Color::operator-= (const Color& c) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(this);\n    XMVECTOR c2 = XMLoadFloat4(&c);\n    XMStoreFloat4(this, XMVectorSubtract(c1, c2));\n    return *this;\n}\n\ninline Color& Color::operator*= (const Color& c) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(this);\n    XMVECTOR c2 = XMLoadFloat4(&c);\n    XMStoreFloat4(this, XMVectorMultiply(c1, c2));\n    return *this;\n}\n\ninline Color& Color::operator*= (float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMVectorScale(c, S));\n    return *this;\n}\n\ninline Color& Color::operator/= (const Color& c) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(this);\n    XMVECTOR c2 = XMLoadFloat4(&c);\n    XMStoreFloat4(this, XMVectorDivide(c1, c2));\n    return *this;\n}\n\n//------------------------------------------------------------------------------\n// Urnary operators\n//------------------------------------------------------------------------------\n\ninline Color Color::operator- () const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    Color R;\n    XMStoreFloat4(&R, XMVectorNegate(c));\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Binary operators\n//------------------------------------------------------------------------------\n\ninline Color operator+ (const Color& C1, const Color& C2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(&C1);\n    XMVECTOR c2 = XMLoadFloat4(&C2);\n    Color R;\n    XMStoreFloat4(&R, XMVectorAdd(c1, c2));\n    return R;\n}\n\ninline Color operator- (const Color& C1, const Color& C2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(&C1);\n    XMVECTOR c2 = XMLoadFloat4(&C2);\n    Color R;\n    XMStoreFloat4(&R, XMVectorSubtract(c1, c2));\n    return R;\n}\n\ninline Color operator* (const Color& C1, const Color& C2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(&C1);\n    XMVECTOR c2 = XMLoadFloat4(&C2);\n    Color R;\n    XMStoreFloat4(&R, XMVectorMultiply(c1, c2));\n    return R;\n}\n\ninline Color operator* (const Color& C, float S) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(&C);\n    Color R;\n    XMStoreFloat4(&R, XMVectorScale(c, S));\n    return R;\n}\n\ninline Color operator/ (const Color& C1, const Color& C2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(&C1);\n    XMVECTOR c2 = XMLoadFloat4(&C2);\n    Color R;\n    XMStoreFloat4(&R, XMVectorDivide(c1, c2));\n    return R;\n}\n\ninline Color operator* (float S, const Color& C) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c1 = XMLoadFloat4(&C);\n    Color R;\n    XMStoreFloat4(&R, XMVectorScale(c1, S));\n    return R;\n}\n\n//------------------------------------------------------------------------------\n// Color operations\n//------------------------------------------------------------------------------\n\ninline DirectX::PackedVector::XMCOLOR Color::BGRA() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR clr = XMLoadFloat4(this);\n    PackedVector::XMCOLOR Packed;\n    PackedVector::XMStoreColor(&Packed, clr);\n    return Packed;\n}\n\ninline DirectX::PackedVector::XMUBYTEN4 Color::RGBA() const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR clr = XMLoadFloat4(this);\n    PackedVector::XMUBYTEN4 Packed;\n    PackedVector::XMStoreUByteN4(&Packed, clr);\n    return Packed;\n}\n\ninline Vector3 Color::ToVector3() const noexcept\n{\n    return Vector3(x, y, z);\n}\n\ninline Vector4 Color::ToVector4() const noexcept\n{\n    return Vector4(x, y, z, w);\n}\n\ninline void Color::Negate() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMColorNegative(c));\n}\n\ninline void Color::Negate(Color& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMColorNegative(c));\n}\n\ninline void Color::Saturate() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMVectorSaturate(c));\n}\n\ninline void Color::Saturate(Color& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMVectorSaturate(c));\n}\n\ninline void Color::Premultiply() noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMVECTOR a = XMVectorSplatW(c);\n    a = XMVectorSelect(g_XMIdentityR3, a, g_XMSelect1110);\n    XMStoreFloat4(this, XMVectorMultiply(c, a));\n}\n\ninline void Color::Premultiply(Color& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMVECTOR a = XMVectorSplatW(c);\n    a = XMVectorSelect(g_XMIdentityR3, a, g_XMSelect1110);\n    XMStoreFloat4(&result, XMVectorMultiply(c, a));\n}\n\ninline void Color::AdjustSaturation(float sat) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMColorAdjustSaturation(c, sat));\n}\n\ninline void Color::AdjustSaturation(float sat, Color& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMColorAdjustSaturation(c, sat));\n}\n\ninline void Color::AdjustContrast(float contrast) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(this, XMColorAdjustContrast(c, contrast));\n}\n\ninline void Color::AdjustContrast(float contrast, Color& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR c = XMLoadFloat4(this);\n    XMStoreFloat4(&result, XMColorAdjustContrast(c, contrast));\n}\n\n//------------------------------------------------------------------------------\n// Static functions\n//------------------------------------------------------------------------------\n\ninline void Color::Modulate(const Color& c1, const Color& c2, Color& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR C0 = XMLoadFloat4(&c1);\n    XMVECTOR C1 = XMLoadFloat4(&c2);\n    XMStoreFloat4(&result, XMColorModulate(C0, C1));\n}\n\ninline Color Color::Modulate(const Color& c1, const Color& c2) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR C0 = XMLoadFloat4(&c1);\n    XMVECTOR C1 = XMLoadFloat4(&c2);\n\n    Color result;\n    XMStoreFloat4(&result, XMColorModulate(C0, C1));\n    return result;\n}\n\ninline void Color::Lerp(const Color& c1, const Color& c2, float t, Color& result) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR C0 = XMLoadFloat4(&c1);\n    XMVECTOR C1 = XMLoadFloat4(&c2);\n    XMStoreFloat4(&result, XMVectorLerp(C0, C1, t));\n}\n\ninline Color Color::Lerp(const Color& c1, const Color& c2, float t) noexcept\n{\n    using namespace DirectX;\n    XMVECTOR C0 = XMLoadFloat4(&c1);\n    XMVECTOR C1 = XMLoadFloat4(&c2);\n\n    Color result;\n    XMStoreFloat4(&result, XMVectorLerp(C0, C1, t));\n    return result;\n}\n\n\n/****************************************************************************\n *\n * Ray\n *\n ****************************************************************************/\n\n//-----------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\ninline bool Ray::operator == (const Ray& r) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR r1p = XMLoadFloat3(&position);\n    XMVECTOR r2p = XMLoadFloat3(&r.position);\n    XMVECTOR r1d = XMLoadFloat3(&direction);\n    XMVECTOR r2d = XMLoadFloat3(&r.direction);\n    return XMVector3Equal(r1p, r2p) && XMVector3Equal(r1d, r2d);\n}\n\ninline bool Ray::operator != (const Ray& r) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR r1p = XMLoadFloat3(&position);\n    XMVECTOR r2p = XMLoadFloat3(&r.position);\n    XMVECTOR r1d = XMLoadFloat3(&direction);\n    XMVECTOR r2d = XMLoadFloat3(&r.direction);\n    return XMVector3NotEqual(r1p, r2p) && XMVector3NotEqual(r1d, r2d);\n}\n\n//-----------------------------------------------------------------------------\n// Ray operators\n//------------------------------------------------------------------------------\n\ninline bool Ray::Intersects(const BoundingSphere& sphere, _Out_ float& Dist) const noexcept\n{\n    return sphere.Intersects(position, direction, Dist);\n}\n\ninline bool Ray::Intersects(const BoundingBox& box, _Out_ float& Dist) const noexcept\n{\n    return box.Intersects(position, direction, Dist);\n}\n\ninline bool Ray::Intersects(const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist) const noexcept\n{\n    return DirectX::TriangleTests::Intersects(position, direction, tri0, tri1, tri2, Dist);\n}\n\ninline bool Ray::Intersects(const Plane& plane, _Out_ float& Dist) const noexcept\n{\n    using namespace DirectX;\n\n    XMVECTOR p = XMLoadFloat4(&plane);\n    XMVECTOR dir = XMLoadFloat3(&direction);\n\n    XMVECTOR nd = XMPlaneDotNormal(p, dir);\n\n    if (XMVector3LessOrEqual(XMVectorAbs(nd), g_RayEpsilon))\n    {\n        Dist = 0.f;\n        return false;\n    }\n    else\n    {\n        // t = -(dot(n,origin) + D) / dot(n,dir)\n        XMVECTOR pos = XMLoadFloat3(&position);\n        XMVECTOR v = XMPlaneDotNormal(p, pos);\n        v = XMVectorAdd(v, XMVectorSplatW(p));\n        v = XMVectorDivide(v, nd);\n        float dist = -XMVectorGetX(v);\n        if (dist < 0)\n        {\n            Dist = 0.f;\n            return false;\n        }\n        else\n        {\n            Dist = dist;\n            return true;\n        }\n    }\n}\n\n\n/****************************************************************************\n *\n * Viewport\n *\n ****************************************************************************/\n\n//------------------------------------------------------------------------------\n// Comparision operators\n//------------------------------------------------------------------------------\n\ninline bool Viewport::operator == (const Viewport& vp) const noexcept\n{\n    return (x == vp.x && y == vp.y\n            && width == vp.width && height == vp.height\n            && minDepth == vp.minDepth && maxDepth == vp.maxDepth);\n}\n\ninline bool Viewport::operator != (const Viewport& vp) const noexcept\n{\n    return (x != vp.x || y != vp.y\n            || width != vp.width || height != vp.height\n            || minDepth != vp.minDepth || maxDepth != vp.maxDepth);\n}\n\n//------------------------------------------------------------------------------\n// Assignment operators\n//------------------------------------------------------------------------------\n\ninline Viewport& Viewport::operator= (const RECT& rct) noexcept\n{\n    x = float(rct.left); y = float(rct.top);\n    width = float(rct.right - rct.left);\n    height = float(rct.bottom - rct.top);\n    minDepth = 0.f; maxDepth = 1.f;\n    return *this;\n}\n\n#if defined(__d3d11_h__) || defined(__d3d11_x_h__)\ninline Viewport& Viewport::operator= (const D3D11_VIEWPORT& vp) noexcept\n{\n    x = vp.TopLeftX; y = vp.TopLeftY;\n    width = vp.Width; height = vp.Height;\n    minDepth = vp.MinDepth; maxDepth = vp.MaxDepth;\n    return *this;\n}\n#endif\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\ninline Viewport& Viewport::operator= (const D3D12_VIEWPORT& vp) noexcept\n{\n    x = vp.TopLeftX; y = vp.TopLeftY;\n    width = vp.Width; height = vp.Height;\n    minDepth = vp.MinDepth; maxDepth = vp.MaxDepth;\n    return *this;\n}\n#endif\n\n//------------------------------------------------------------------------------\n// Viewport operations\n//------------------------------------------------------------------------------\n\ninline float Viewport::AspectRatio() const noexcept\n{\n    if (width == 0.f || height == 0.f)\n        return 0.f;\n\n    return (width / height);\n}\n\ninline Vector3 Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v = XMLoadFloat3(&p);\n    XMMATRIX projection = XMLoadFloat4x4(&proj);\n    v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world);\n    Vector3 result;\n    XMStoreFloat3(&result, v);\n    return result;\n}\n\ninline void Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v = XMLoadFloat3(&p);\n    XMMATRIX projection = XMLoadFloat4x4(&proj);\n    v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world);\n    XMStoreFloat3(&result, v);\n}\n\ninline Vector3 Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v = XMLoadFloat3(&p);\n    XMMATRIX projection = XMLoadFloat4x4(&proj);\n    v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world);\n    Vector3 result;\n    XMStoreFloat3(&result, v);\n    return result;\n}\n\ninline void Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept\n{\n    using namespace DirectX;\n    XMVECTOR v = XMLoadFloat3(&p);\n    XMMATRIX projection = XMLoadFloat4x4(&proj);\n    v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world);\n    XMStoreFloat3(&result, v);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/SpriteBatch.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: SpriteBatch.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgi.h>\n#endif\n\n#include <DirectXMath.h>\n#include <DirectXColors.h>\n#include <functional>\n#include <memory>\n\n#include \"RenderTargetState.h\"\n\n\nnamespace DirectX\n{\n    class ResourceUploadBatch;\n\n    enum SpriteSortMode\n    {\n        SpriteSortMode_Deferred,\n        SpriteSortMode_Immediate,\n        SpriteSortMode_Texture,\n        SpriteSortMode_BackToFront,\n        SpriteSortMode_FrontToBack,\n    };\n\n    enum SpriteEffects : uint32_t\n    {\n        SpriteEffects_None = 0,\n        SpriteEffects_FlipHorizontally = 1,\n        SpriteEffects_FlipVertically = 2,\n        SpriteEffects_FlipBoth = SpriteEffects_FlipHorizontally | SpriteEffects_FlipVertically,\n    };\n\n    class SpriteBatchPipelineStateDescription\n    {\n    public:\n        explicit SpriteBatchPipelineStateDescription(\n            const RenderTargetState& renderTarget,\n            _In_opt_ const D3D12_BLEND_DESC* blend = nullptr,\n            _In_opt_ const D3D12_DEPTH_STENCIL_DESC* depthStencil = nullptr,\n            _In_opt_ const D3D12_RASTERIZER_DESC* rasterizer = nullptr,\n            _In_opt_ const D3D12_GPU_DESCRIPTOR_HANDLE* isamplerDescriptor = nullptr) noexcept\n            :\n            blendDesc(blend ? *blend : s_DefaultBlendDesc),\n            depthStencilDesc(depthStencil ? *depthStencil : s_DefaultDepthStencilDesc),\n            rasterizerDesc(rasterizer ? *rasterizer : s_DefaultRasterizerDesc),\n            renderTargetState(renderTarget),\n            samplerDescriptor{},\n            customRootSignature(nullptr),\n            customVertexShader{},\n            customPixelShader{}\n        {\n            if (isamplerDescriptor)\n                this->samplerDescriptor = *isamplerDescriptor;\n        }\n\n        D3D12_BLEND_DESC            blendDesc;\n        D3D12_DEPTH_STENCIL_DESC    depthStencilDesc;\n        D3D12_RASTERIZER_DESC       rasterizerDesc;\n        RenderTargetState           renderTargetState;\n        D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor;\n        ID3D12RootSignature*        customRootSignature;\n        D3D12_SHADER_BYTECODE       customVertexShader;\n        D3D12_SHADER_BYTECODE       customPixelShader;\n\n    private:\n        static const D3D12_BLEND_DESC           s_DefaultBlendDesc;\n        static const D3D12_RASTERIZER_DESC      s_DefaultRasterizerDesc;\n        static const D3D12_DEPTH_STENCIL_DESC   s_DefaultDepthStencilDesc;\n    };\n\n    class SpriteBatch\n    {\n    public:\n        SpriteBatch(_In_ ID3D12Device* device, ResourceUploadBatch& upload, const SpriteBatchPipelineStateDescription& psoDesc, _In_opt_ const D3D12_VIEWPORT* viewport = nullptr);\n        SpriteBatch(SpriteBatch&& moveFrom) noexcept;\n        SpriteBatch& operator= (SpriteBatch&& moveFrom) noexcept;\n\n        SpriteBatch(SpriteBatch const&) = delete;\n        SpriteBatch& operator= (SpriteBatch const&) = delete;\n\n        virtual ~SpriteBatch();\n\n        // Begin/End a batch of sprite drawing operations.\n        void XM_CALLCONV Begin(\n            _In_ ID3D12GraphicsCommandList* commandList,\n            SpriteSortMode sortMode = SpriteSortMode_Deferred,\n            FXMMATRIX transformMatrix = MatrixIdentity);\n        void XM_CALLCONV Begin(\n            _In_ ID3D12GraphicsCommandList* commandList,\n            D3D12_GPU_DESCRIPTOR_HANDLE sampler,\n            SpriteSortMode sortMode = SpriteSortMode_Deferred,\n            FXMMATRIX transformMatrix = MatrixIdentity);\n        void __cdecl End();\n\n        // Draw overloads specifying position, origin and scale as XMFLOAT2.\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, XMFLOAT2 const& position, FXMVECTOR color = Colors::White);\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, XMFLOAT2 const& position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0);\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, XMFLOAT2 const& position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0);\n\n        // Draw overloads specifying position, origin and scale via the first two components of an XMVECTOR.\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, FXMVECTOR position, FXMVECTOR color = Colors::White);\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, FXMVECTOR position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, FXMVECTOR origin = g_XMZero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0);\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, FXMVECTOR position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0);\n\n        // Draw overloads specifying position as a RECT.\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, RECT const& destinationRectangle, FXMVECTOR color = Colors::White);\n        void XM_CALLCONV Draw(D3D12_GPU_DESCRIPTOR_HANDLE textureSRV, XMUINT2 const& textureSize, RECT const& destinationRectangle, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0);\n\n        // Rotation mode to be applied to the sprite transformation\n        void __cdecl SetRotation(DXGI_MODE_ROTATION mode);\n        DXGI_MODE_ROTATION __cdecl GetRotation() const noexcept;\n\n        // Set viewport for sprite transformation\n        void __cdecl SetViewport(const D3D12_VIEWPORT& viewPort);\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        static const XMMATRIX MatrixIdentity;\n        static const XMFLOAT2 Float2Zero;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/SpriteFont.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: SpriteFont.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"SpriteBatch.h\"\n\n\nnamespace DirectX\n{\n    class SpriteFont\n    {\n    public:\n        struct Glyph;\n\n        SpriteFont(ID3D12Device* device, ResourceUploadBatch& upload, _In_z_ wchar_t const* fileName, D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorDest, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor, bool forceSRGB = false);\n        SpriteFont(ID3D12Device* device, ResourceUploadBatch& upload, _In_reads_bytes_(dataSize) uint8_t const* dataBlob, size_t dataSize, D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorDest, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptor, bool forceSRGB = false);\n        SpriteFont(D3D12_GPU_DESCRIPTOR_HANDLE texture, XMUINT2 textureSize, _In_reads_(glyphCount) Glyph const* glyphs, size_t glyphCount, float lineSpacing);\n\n        SpriteFont(SpriteFont&& moveFrom) noexcept;\n        SpriteFont& operator= (SpriteFont&& moveFrom) noexcept;\n\n        SpriteFont(SpriteFont const&) = delete;\n        SpriteFont& operator= (SpriteFont const&) = delete;\n\n        virtual ~SpriteFont();\n\n        // Wide-character / UTF-16LE\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, FXMVECTOR color = Colors::White, float rotation = 0, FXMVECTOR origin = g_XMZero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n\n        XMVECTOR XM_CALLCONV MeasureString(_In_z_ wchar_t const* text, bool ignoreWhitespace = true) const;\n\n        RECT __cdecl MeasureDrawBounds(_In_z_ wchar_t const* text, XMFLOAT2 const& position, bool ignoreWhitespace = true) const;\n        RECT XM_CALLCONV MeasureDrawBounds(_In_z_ wchar_t const* text, FXMVECTOR position, bool ignoreWhitespace = true) const;\n\n        // UTF-8\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, XMFLOAT2 const& position, FXMVECTOR color = Colors::White, float rotation = 0, XMFLOAT2 const& origin = Float2Zero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, FXMVECTOR position, FXMVECTOR color = Colors::White, float rotation = 0, FXMVECTOR origin = g_XMZero, float scale = 1, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n        void XM_CALLCONV DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0) const;\n\n        XMVECTOR XM_CALLCONV MeasureString(_In_z_ char const* text, bool ignoreWhitespace = true) const;\n\n        RECT __cdecl MeasureDrawBounds(_In_z_ char const* text, XMFLOAT2 const& position, bool ignoreWhitespace = true) const;\n        RECT XM_CALLCONV MeasureDrawBounds(_In_z_ char const* text, FXMVECTOR position, bool ignoreWhitespace = true) const;\n\n        // Spacing properties\n        float __cdecl GetLineSpacing() const noexcept;\n        void __cdecl SetLineSpacing(float spacing);\n\n        // Font properties\n        wchar_t __cdecl GetDefaultCharacter() const noexcept;\n        void __cdecl SetDefaultCharacter(wchar_t character);\n\n        bool __cdecl ContainsCharacter(wchar_t character) const;\n\n        // Custom layout/rendering\n        Glyph const* __cdecl FindGlyph(wchar_t character) const;\n        D3D12_GPU_DESCRIPTOR_HANDLE __cdecl GetSpriteSheet() const noexcept;\n        XMUINT2 __cdecl GetSpriteSheetSize() const noexcept;\n\n        // Describes a single character glyph.\n        struct Glyph\n        {\n            uint32_t Character;\n            RECT Subrect;\n            float XOffset;\n            float YOffset;\n            float XAdvance;\n        };\n\n\n    private:\n        // Private implementation.\n        class Impl;\n\n        std::unique_ptr<Impl> pImpl;\n\n        static const XMFLOAT2 Float2Zero;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/VertexTypes.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: VertexTypes.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <DirectXMath.h>\n\n\nnamespace DirectX\n{\n    // Vertex struct holding position information.\n    struct VertexPosition\n    {\n        VertexPosition() = default;\n\n        VertexPosition(const VertexPosition&) = default;\n        VertexPosition& operator=(const VertexPosition&) = default;\n\n        VertexPosition(VertexPosition&&) = default;\n        VertexPosition& operator=(VertexPosition&&) = default;\n\n        VertexPosition(XMFLOAT3 const& iposition) noexcept\n            : position(iposition)\n        { }\n\n        VertexPosition(FXMVECTOR iposition) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n        }\n\n        XMFLOAT3 position;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 1;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position and color information.\n    struct VertexPositionColor\n    {\n        VertexPositionColor() = default;\n\n        VertexPositionColor(const VertexPositionColor&) = default;\n        VertexPositionColor& operator=(const VertexPositionColor&) = default;\n\n        VertexPositionColor(VertexPositionColor&&) = default;\n        VertexPositionColor& operator=(VertexPositionColor&&) = default;\n\n        VertexPositionColor(XMFLOAT3 const& iposition, XMFLOAT4 const& icolor) noexcept\n            : position(iposition),\n            color(icolor)\n        { }\n\n        VertexPositionColor(FXMVECTOR iposition, FXMVECTOR icolor) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat4(&this->color, icolor);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT4 color;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 2;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position and texture mapping information.\n    struct VertexPositionTexture\n    {\n        VertexPositionTexture() = default;\n\n        VertexPositionTexture(const VertexPositionTexture&) = default;\n        VertexPositionTexture& operator=(const VertexPositionTexture&) = default;\n\n        VertexPositionTexture(VertexPositionTexture&&) = default;\n        VertexPositionTexture& operator=(VertexPositionTexture&&) = default;\n\n        VertexPositionTexture(XMFLOAT3 const& iposition, XMFLOAT2 const& itextureCoordinate) noexcept\n            : position(iposition),\n            textureCoordinate(itextureCoordinate)\n        { }\n\n        VertexPositionTexture(FXMVECTOR iposition, FXMVECTOR itextureCoordinate) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat2(&this->textureCoordinate, itextureCoordinate);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT2 textureCoordinate;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 2;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position and dual texture mapping information.\n    struct VertexPositionDualTexture\n    {\n        VertexPositionDualTexture() = default;\n\n        VertexPositionDualTexture(const VertexPositionDualTexture&) = default;\n        VertexPositionDualTexture& operator=(const VertexPositionDualTexture&) = default;\n\n        VertexPositionDualTexture(VertexPositionDualTexture&&) = default;\n        VertexPositionDualTexture& operator=(VertexPositionDualTexture&&) = default;\n\n        VertexPositionDualTexture(\n            XMFLOAT3 const& iposition,\n            XMFLOAT2 const& itextureCoordinate0,\n            XMFLOAT2 const& itextureCoordinate1) noexcept\n                : position(iposition),\n                  textureCoordinate0(itextureCoordinate0),\n                  textureCoordinate1(itextureCoordinate1)\n        { }\n\n        VertexPositionDualTexture(\n            FXMVECTOR iposition,\n            FXMVECTOR itextureCoordinate0,\n            FXMVECTOR itextureCoordinate1) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat2(&this->textureCoordinate0, itextureCoordinate0);\n            XMStoreFloat2(&this->textureCoordinate1, itextureCoordinate1);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT2 textureCoordinate0;\n        XMFLOAT2 textureCoordinate1;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 3;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position and normal vector.\n    struct VertexPositionNormal\n    {\n        VertexPositionNormal() = default;\n\n        VertexPositionNormal(const VertexPositionNormal&) = default;\n        VertexPositionNormal& operator=(const VertexPositionNormal&) = default;\n\n        VertexPositionNormal(VertexPositionNormal&&) = default;\n        VertexPositionNormal& operator=(VertexPositionNormal&&) = default;\n\n        VertexPositionNormal(XMFLOAT3 const& iposition, XMFLOAT3 const& inormal) noexcept\n            : position(iposition),\n            normal(inormal)\n        { }\n\n        VertexPositionNormal(FXMVECTOR iposition, FXMVECTOR inormal) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat3(&this->normal, inormal);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT3 normal;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 2;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position, color, and texture mapping information.\n    struct VertexPositionColorTexture\n    {\n        VertexPositionColorTexture() = default;\n\n        VertexPositionColorTexture(const VertexPositionColorTexture&) = default;\n        VertexPositionColorTexture& operator=(const VertexPositionColorTexture&) = default;\n\n        VertexPositionColorTexture(VertexPositionColorTexture&&) = default;\n        VertexPositionColorTexture& operator=(VertexPositionColorTexture&&) = default;\n\n        VertexPositionColorTexture(XMFLOAT3 const& iposition, XMFLOAT4 const& icolor, XMFLOAT2 const& itextureCoordinate) noexcept\n            : position(iposition),\n            color(icolor),\n            textureCoordinate(itextureCoordinate)\n        { }\n\n        VertexPositionColorTexture(FXMVECTOR iposition, FXMVECTOR icolor, FXMVECTOR itextureCoordinate) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat4(&this->color, icolor);\n            XMStoreFloat2(&this->textureCoordinate, itextureCoordinate);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT4 color;\n        XMFLOAT2 textureCoordinate;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 3;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position, normal vector, and color information.\n    struct VertexPositionNormalColor\n    {\n        VertexPositionNormalColor() = default;\n\n        VertexPositionNormalColor(const VertexPositionNormalColor&) = default;\n        VertexPositionNormalColor& operator=(const VertexPositionNormalColor&) = default;\n\n        VertexPositionNormalColor(VertexPositionNormalColor&&) = default;\n        VertexPositionNormalColor& operator=(VertexPositionNormalColor&&) = default;\n    \n        VertexPositionNormalColor(XMFLOAT3 const& iposition, XMFLOAT3 const& inormal, XMFLOAT4 const& icolor) noexcept\n            : position(iposition),\n            normal(inormal),\n            color(icolor)\n        { }\n\n        VertexPositionNormalColor(FXMVECTOR iposition, FXMVECTOR inormal, FXMVECTOR icolor) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat3(&this->normal, inormal);\n            XMStoreFloat4(&this->color, icolor);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT3 normal;\n        XMFLOAT4 color;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 3;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position, normal vector, and texture mapping information.\n    struct VertexPositionNormalTexture\n    {\n        VertexPositionNormalTexture() = default;\n\n        VertexPositionNormalTexture(const VertexPositionNormalTexture&) = default;\n        VertexPositionNormalTexture& operator=(const VertexPositionNormalTexture&) = default;\n\n        VertexPositionNormalTexture(VertexPositionNormalTexture&&) = default;\n        VertexPositionNormalTexture& operator=(VertexPositionNormalTexture&&) = default;\n\n        VertexPositionNormalTexture(XMFLOAT3 const& iposition, XMFLOAT3 const& inormal, XMFLOAT2 const& itextureCoordinate) noexcept\n            : position(iposition),\n            normal(inormal),\n            textureCoordinate(itextureCoordinate)\n        { }\n\n        VertexPositionNormalTexture(FXMVECTOR iposition, FXMVECTOR inormal, FXMVECTOR itextureCoordinate) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat3(&this->normal, inormal);\n            XMStoreFloat2(&this->textureCoordinate, itextureCoordinate);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT3 normal;\n        XMFLOAT2 textureCoordinate;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 3;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n\n\n    // Vertex struct holding position, normal vector, color, and texture mapping information.\n    struct VertexPositionNormalColorTexture\n    {\n        VertexPositionNormalColorTexture() = default;\n\n        VertexPositionNormalColorTexture(const VertexPositionNormalColorTexture&) = default;\n        VertexPositionNormalColorTexture& operator=(const VertexPositionNormalColorTexture&) = default;\n\n        VertexPositionNormalColorTexture(VertexPositionNormalColorTexture&&) = default;\n        VertexPositionNormalColorTexture& operator=(VertexPositionNormalColorTexture&&) = default;\n\n        VertexPositionNormalColorTexture(\n            XMFLOAT3 const& iposition,\n            XMFLOAT3 const& inormal,\n            XMFLOAT4 const& icolor,\n            XMFLOAT2 const& itextureCoordinate) noexcept\n                : position(iposition),\n                  normal(inormal),\n                  color(icolor),\n                  textureCoordinate(itextureCoordinate)\n        { }\n\n        VertexPositionNormalColorTexture(FXMVECTOR iposition, FXMVECTOR inormal, FXMVECTOR icolor, CXMVECTOR itextureCoordinate) noexcept\n        {\n            XMStoreFloat3(&this->position, iposition);\n            XMStoreFloat3(&this->normal, inormal);\n            XMStoreFloat4(&this->color, icolor);\n            XMStoreFloat2(&this->textureCoordinate, itextureCoordinate);\n        }\n\n        XMFLOAT3 position;\n        XMFLOAT3 normal;\n        XMFLOAT4 color;\n        XMFLOAT2 textureCoordinate;\n\n        static const D3D12_INPUT_LAYOUT_DESC InputLayout;\n\n    private:\n        static constexpr unsigned int InputElementCount = 4;\n        static const D3D12_INPUT_ELEMENT_DESC InputElements[InputElementCount];\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/WICTextureLoader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: WICTextureLoader.h\n//\n// Function for loading a WIC image and creating a Direct3D runtime texture for it\n// (auto-generating mipmaps if possible)\n//\n// Note: Assumes application has already called CoInitializeEx\n//\n// Note these functions are useful for images created as simple 2D textures. For\n// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.\n// For a full-featured DDS file reader, writer, and texture processing pipeline see\n// the 'Texconv' sample and the 'DirectXTex' library.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#else\n#include <d3d12.h>\n#endif\n\n#include <cstdint>\n#include <memory>\n\n#pragma comment(lib,\"uuid.lib\")\n\n\nnamespace DirectX\n{\n    enum WIC_LOADER_FLAGS : uint32_t\n    {\n        WIC_LOADER_DEFAULT      = 0,\n        WIC_LOADER_FORCE_SRGB   = 0x1,\n        WIC_LOADER_IGNORE_SRGB  = 0x2,\n        WIC_LOADER_SRGB_DEFAULT = 0x4,\n        WIC_LOADER_MIP_AUTOGEN  = 0x8,\n        WIC_LOADER_MIP_RESERVE  = 0x10,\n        WIC_LOADER_FIT_POW2     = 0x20,\n        WIC_LOADER_MAKE_SQUARE  = 0x40,\n        WIC_LOADER_FORCE_RGBA32 = 0x80,\n    };\n\n    class ResourceUploadBatch;\n\n    // Standard version\n    HRESULT __cdecl LoadWICTextureFromMemory(\n        _In_ ID3D12Device* d3dDevice,\n        _In_reads_bytes_(wicDataSize) const uint8_t* wicData,\n        size_t wicDataSize,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& decodedData,\n        D3D12_SUBRESOURCE_DATA& subresource,\n        size_t maxsize = 0) noexcept;\n\n    HRESULT __cdecl LoadWICTextureFromFile(\n        _In_ ID3D12Device* d3dDevice,\n        _In_z_ const wchar_t* szFileName,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& decodedData,\n        D3D12_SUBRESOURCE_DATA& subresource,\n        size_t maxsize = 0) noexcept;\n\n    // Standard version with resource upload\n    HRESULT __cdecl CreateWICTextureFromMemory(\n        _In_ ID3D12Device* d3dDevice,\n         ResourceUploadBatch& resourceUpload,\n        _In_reads_bytes_(wicDataSize) const uint8_t* wicData,\n        size_t wicDataSize,\n        _Outptr_ ID3D12Resource** texture,\n        bool generateMips = false,\n        size_t maxsize = 0);\n\n    HRESULT __cdecl CreateWICTextureFromFile(\n        _In_ ID3D12Device* d3dDevice,\n        ResourceUploadBatch& resourceUpload,\n        _In_z_ const wchar_t* szFileName,\n        _Outptr_ ID3D12Resource** texture,\n        bool generateMips = false,\n        size_t maxsize = 0);\n\n    // Extended version\n    HRESULT __cdecl LoadWICTextureFromMemoryEx(\n        _In_ ID3D12Device* d3dDevice,\n        _In_reads_bytes_(wicDataSize) const uint8_t* wicData,\n        size_t wicDataSize,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        WIC_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& decodedData,\n        D3D12_SUBRESOURCE_DATA& subresource) noexcept;\n\n    HRESULT __cdecl LoadWICTextureFromFileEx(\n        _In_ ID3D12Device* d3dDevice,\n        _In_z_ const wchar_t* szFileName,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        WIC_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& decodedData,\n        D3D12_SUBRESOURCE_DATA& subresource) noexcept;\n\n    // Extended version with resource upload\n    HRESULT __cdecl CreateWICTextureFromMemoryEx(\n        _In_ ID3D12Device* d3dDevice,\n        ResourceUploadBatch& resourceUpload,\n        _In_reads_bytes_(wicDataSize) const uint8_t* wicData,\n        size_t wicDataSize,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        WIC_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture);\n\n    HRESULT __cdecl CreateWICTextureFromFileEx(\n        _In_ ID3D12Device* d3dDevice,\n        ResourceUploadBatch& resourceUpload,\n        _In_z_ const wchar_t* szFileName,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        WIC_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture);\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-dynamic-exception-spec\"\n#endif\n\n    DEFINE_ENUM_FLAG_OPERATORS(WIC_LOADER_FLAGS);\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Inc/XboxDDSTextureLoader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: XboxDDSTextureLoader.h\n//\n// Functions for loading a DDS texture using the XBOX extended header and creating a\n// Direct3D12.X runtime resource for it via the CreatePlacedResourceX API\n//\n// Note these functions will not load standard DDS files. Use the DDSTextureLoader\n// module in the DirectXTex package or as part of the DirectXTK library to load\n// these files which use standard Direct3D resource creation APIs.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#if !(defined(_XBOX_ONE) && defined(_TITLE)) && !defined(_GAMING_XBOX)\n#error This module only supports Xbox exclusive apps\n#endif\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#else\n#include <d3d12_x.h>\n#endif\n\n#ifdef _GAMING_XBOX\n#pragma comment(lib,\"xmem.lib\")\n#endif\n\n#include <cstdint>\n\n#ifndef DDS_ALPHA_MODE_DEFINED\n#define DDS_ALPHA_MODE_DEFINED\nnamespace DirectX\n{\n    enum DDS_ALPHA_MODE : uint32_t\n    {\n        DDS_ALPHA_MODE_UNKNOWN = 0,\n        DDS_ALPHA_MODE_STRAIGHT = 1,\n        DDS_ALPHA_MODE_PREMULTIPLIED = 2,\n        DDS_ALPHA_MODE_OPAQUE = 3,\n        DDS_ALPHA_MODE_CUSTOM = 4,\n    };\n}\n#endif\n\nnamespace Xbox\n{\n    using DirectX::DDS_ALPHA_MODE;\n\n    //\n    //  NOTE: Flush the GPU caches before using textures created \n    //  with these functions.\n    //\n    //  The simplest means of doing this is:\n    //\n    //      // Load all your textures:\n    //      CreateDDSTextureFrom...\n    //      CreateDDSTextureFrom...\n    //      CreateDDSTextureFrom...\n    //      \n    //      // Flush the GPU caches\n    //      ID3D12CommandList::FlushPipelineX(D3D12XBOX_FLUSH_IDLE, 0, 0);\n    //\n    //      // Now it's safe to use the textures\n    //      ... Draw ...\n    //\n    //  You may wish to consider more fine-grained flushes if\n    //  creating textures at run-time. See the documentation for\n    //  FlushPipelineX.\n    //\n\n    HRESULT __cdecl CreateDDSTextureFromMemory(\n        _In_ ID3D12Device* d3dDevice,\n        _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData,\n        _In_ size_t ddsDataSize,\n        _Outptr_opt_ ID3D12Resource** texture,\n        _Outptr_ void** grfxMemory,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr, \n        _In_ bool forceSRGB = false,\n        _Out_opt_ bool* isCubeMap = nullptr) noexcept;\n\n    HRESULT __cdecl CreateDDSTextureFromFile( \n        _In_ ID3D12Device* d3dDevice,\n        _In_z_ const wchar_t* szFileName,\n        _Outptr_opt_ ID3D12Resource** texture,\n        _Outptr_ void** grfxMemory,\n        _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr,\n        _In_ bool forceSRGB = false,\n        _Out_opt_ bool* isCubeMap = nullptr) noexcept;\n\n    void FreeDDSTextureMemory(_In_opt_ void* grfxMemory) noexcept;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/README.md",
    "content": "![DirectX Logo](https://github.com/Microsoft/DirectXTK12/wiki/X_jpg.jpg)\n\n# DirectX Tool Kit for DirectX 12\n\nhttp://go.microsoft.com/fwlink/?LinkID=615561\n\nCopyright (c) Microsoft Corporation. All rights reserved.\n\n**August 15, 2020**\n\nThis package contains the \"DirectX Tool Kit\", a collection of helper classes for writing Direct3D 12 C++ code for Universal Windows Platform (UWP) apps, Win32 desktop applications for Windows 10, and Xbox.\n\nThis code is designed to build with Visual Studio 2017 ([15.9](https://walbourn.github.io/vs-2017-15-9-update/)), Visual Studio 2019, or clang for Windows v9 or later. It is recommended that you make use of the Windows 10 May 2020 Update SDK ([19041](https://walbourn.github.io/windows-10-may-2020-update-sdk/)).\n\nThese components are designed to work without requiring any content from the legacy DirectX SDK. For details, see [Where is the DirectX SDK?](https://aka.ms/dxsdk).\n\n## Directory Layout\n\n* ``Inc\\``\n\n  + Public Header Files (in the DirectX C++ namespace):\n\n    * Audio.h - low-level audio API using XAudio2 (DirectXTK for Audio public header)\n    * BufferHelpers.h - C++ helpers for creating D3D resources from CPU data\n    * CommonStates.h - common D3D state combinations\n    * DDSTextureLoader.h - light-weight DDS file texture loader\n    * DescriptorHeap.h - helper for managing DX12 descriptor heaps\n    * DirectXHelpers.h - misc C++ helpers for D3D programming\n    * EffectPipelineStateDescription.h - helper for creating PSOs\n    * Effects.h - set of built-in shaders for common rendering tasks\n    * GamePad.h - gamepad controller helper using XInput\n    * GeometricPrimitive.h - draws basic shapes such as cubes and spheres\n    * GraphicsMemory.h - helper for managing dynamic graphics memory allocation\n    * Keyboard.h - keyboard state tracking helper\n    * Model.h - draws meshes loaded from .SDKMESH or .VBO files\n    * Mouse.h - mouse helper\n    * PostProcess.h - set of built-in shaders for common post-processing operations\n    * PrimitiveBatch.h - simple and efficient way to draw user primitives\n    * RenderTargetState.h - helper for communicating render target requirements when creating PSOs\n    * ResourceUploadBatch.h - helper for managing texture resource upload to the GPU\n    * ScreenGrab.h - light-weight screen shot saver\n    * SimpleMath.h - simplified C++ wrapper for DirectXMath\n    * SpriteBatch.h - simple & efficient 2D sprite rendering\n    * SpriteFont.h - bitmap based text rendering\n    * VertexTypes.h - structures for commonly used vertex data formats\n    * WICTextureLoader.h - WIC-based image file texture loader\n    * XboxDDSTextureLoader.h - Xbox exclusive apps variant of DDSTextureLoader\n\n* ``Src\\``\n\n  + DirectXTK source files and internal implementation headers\n\n* ``Audio\\``\n\n  + DirectXTK for Audio source files and internal implementation headers\n\n> MakeSpriteFont and XWBTool can be found in the [DirectX Tool Kit for DirectX 11](https://github.com/microsoft/DirectXTK)\n\n# Documentation\n\nDocumentation is available on the [GitHub wiki](https://github.com/Microsoft/DirectXTK12/wiki).\n\n## Notices\n\nAll content and source code for this package are subject to the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\nFor the latest version of DirectXTK12, bug reports, etc. please visit the project site on [GitHub](https://github.com/microsoft/DirectXTK12).\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n\n## Comparisons to DirectX 11 Version\n\n* No support for loading ``.CMO`` models or DGSL effect shaders (i.e. *DGSLEffect*)\n\n* VertexTypes does not include VertexPositionNormalTangentColorTexture or VertexPositionNormalTangentColorTextureSkinning which were intended for use with the DGSL pipeline.\n\n* DirectX Tool Kit for DirectX 11 supports Feature Level 9.x, while DirectX 12 requires Direct3D Feature Level 11.0. There are no expected DirectX 12 drivers for any lower feature level devices.\n\n* The library assumes it is building for Windows 10 (aka ``_WIN32_WINNT=0x0A00``) so it makes use of XAudio 2.9 and WIC2 as well as DirectX 12.\n\n* DirectX Tool Kit for Audio, GamePad, Keyboard, Mouse, and SimpleMath are identical to the DirectX 11 version.\n\n## Release Notes\n\n* Starting with the June 2020 release, this library makes use of typed enum bitmask flags per the recommendation of the _C++ Standard_ section *17.5.2.1.3 Bitmask types*. This may have *breaking change* impacts to client code:\n\n  * You cannot pass the ``0`` literal as your flags value. Instead you must make use of the appropriate default enum value: ``AudioEngine_Default``, ``SoundEffectInstance_Default``, ``ModelLoader_Clockwise``, ``DDS_LOADER_DEFAULT``, or ``WIC_LOADER_DEFAULT``.\n\n  * Use the enum type instead of ``DWORD`` if building up flags values locally with bitmask operations. For example, ```WIC_LOADER_FLAGS flags = WIC_LOADER_DEFAULT; if (...) flags |= WIC_LOADER_FORCE_SRGB;```\n\n* The UWP projects and the VS 2019 Win10 classic desktop project include configurations for the ARM64 platform. These require VS 2017 (15.9 update) or VS 2019 to build, with the ARM64 toolset installed.\n\n* The ``CompileShaders.cmd`` script must have Windows-style (CRLF) line-endings. If it is changed to Linux-style (LF) line-endings, it can fail to build all the required shaders.\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/AlignedNew.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: AlignedNew.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <malloc.h>\n#include <exception>\n\n\nnamespace DirectX\n{\n    // Derive from this to customize operator new and delete for\n    // types that have special heap alignment requirements.\n    //\n    // Example usage:\n    //\n    //      __declspec(align(16)) struct MyAlignedType : public AlignedNew<MyAlignedType>\n\n    template<typename TDerived>\n    struct AlignedNew\n    {\n        // Allocate aligned memory.\n        static void* operator new (size_t size)\n        {\n            const size_t alignment = __alignof(TDerived);\n\n            static_assert(alignment > 8, \"AlignedNew is only useful for types with > 8 byte alignment. Did you forget a __declspec(align) on TDerived?\");\n\n            void* ptr = _aligned_malloc(size, alignment);\n\n            if (!ptr)\n                throw std::bad_alloc();\n\n            return ptr;\n        }\n\n\n        // Free aligned memory.\n        static void operator delete (void* ptr)\n        {\n            _aligned_free(ptr);\n        }\n\n\n        // Array overloads.\n        static void* operator new[](size_t size)\n        {\n            return operator new(size);\n        }\n\n\n        static void operator delete[](void* ptr)\n        {\n            operator delete(ptr);\n        }\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/AlphaTestEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: AlphaTestEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct AlphaTestEffectConstants\n    {\n        XMVECTOR diffuseColor;\n        XMVECTOR alphaTest;\n        XMVECTOR fogColor;\n        XMVECTOR fogVector;\n        XMMATRIX worldViewProj;\n    };\n\n    static_assert((sizeof(AlphaTestEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct AlphaTestEffectTraits\n    {\n        using ConstantBufferType = AlphaTestEffectConstants;\n\n        static constexpr int VertexShaderCount = 4;\n        static constexpr int PixelShaderCount = 4;\n        static constexpr int ShaderPermutationCount = 8;\n        static constexpr int RootSignatureCount = 1;\n    };\n}\n\n// Internal AlphaTestEffect implementation class.\nclass AlphaTestEffect::Impl : public EffectBase<AlphaTestEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription,\n        D3D12_COMPARISON_FUNC alphaFunction);\n\n    enum RootParameterIndex\n    {\n        ConstantBuffer,\n        TextureSRV,\n        TextureSampler,\n        RootParameterCount\n    };\n\n    D3D12_COMPARISON_FUNC mAlphaFunction;\n    int referenceAlpha;\n\n    EffectColor color;\n\n    D3D12_GPU_DESCRIPTOR_HANDLE texture;\n    D3D12_GPU_DESCRIPTOR_HANDLE textureSampler;\n    \n    int GetPipelineStatePermutation(bool vertexColorEnabled) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_VSAlphaTest.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_VSAlphaTestNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_VSAlphaTestVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_VSAlphaTestVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_PSAlphaTestLtGt.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_PSAlphaTestLtGtNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_PSAlphaTestEqNe.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettAlphaTestEffect_PSAlphaTestEqNeNoFog.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_VSAlphaTest.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_VSAlphaTestNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_VSAlphaTestVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_VSAlphaTestVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_PSAlphaTestLtGt.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_PSAlphaTestLtGtNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_PSAlphaTestEqNe.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneAlphaTestEffect_PSAlphaTestEqNeNoFog.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_VSAlphaTest.inc\"\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_VSAlphaTestNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_VSAlphaTestVc.inc\"\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_VSAlphaTestVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_PSAlphaTestLtGt.inc\"\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_PSAlphaTestLtGtNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_PSAlphaTestEqNe.inc\"\n    #include \"Shaders/Compiled/XboxOneAlphaTestEffect_PSAlphaTestEqNeNoFog.inc\"\n#else\n    #include \"Shaders/Compiled/AlphaTestEffect_VSAlphaTest.inc\"\n    #include \"Shaders/Compiled/AlphaTestEffect_VSAlphaTestNoFog.inc\"\n    #include \"Shaders/Compiled/AlphaTestEffect_VSAlphaTestVc.inc\"\n    #include \"Shaders/Compiled/AlphaTestEffect_VSAlphaTestVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/AlphaTestEffect_PSAlphaTestLtGt.inc\"\n    #include \"Shaders/Compiled/AlphaTestEffect_PSAlphaTestLtGtNoFog.inc\"\n    #include \"Shaders/Compiled/AlphaTestEffect_PSAlphaTestEqNe.inc\"\n    #include \"Shaders/Compiled/AlphaTestEffect_PSAlphaTestEqNeNoFog.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<AlphaTestEffectTraits>::VertexShaderBytecode[] =\n{\n    { AlphaTestEffect_VSAlphaTest,        sizeof(AlphaTestEffect_VSAlphaTest)        },\n    { AlphaTestEffect_VSAlphaTestNoFog,   sizeof(AlphaTestEffect_VSAlphaTestNoFog)   },\n    { AlphaTestEffect_VSAlphaTestVc,      sizeof(AlphaTestEffect_VSAlphaTestVc)      },\n    { AlphaTestEffect_VSAlphaTestVcNoFog, sizeof(AlphaTestEffect_VSAlphaTestVcNoFog) },\n};\n\n\ntemplate<>\nconst int EffectBase<AlphaTestEffectTraits>::VertexShaderIndices[] =\n{\n    0,      // lt/gt\n    1,      // lt/gt, no fog\n    2,      // lt/gt, vertex color\n    3,      // lt/gt, vertex color, no fog\n    \n    0,      // eq/ne\n    1,      // eq/ne, no fog\n    2,      // eq/ne, vertex color\n    3,      // eq/ne, vertex color, no fog\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<AlphaTestEffectTraits>::PixelShaderBytecode[] =\n{\n    { AlphaTestEffect_PSAlphaTestLtGt,      sizeof(AlphaTestEffect_PSAlphaTestLtGt)      },\n    { AlphaTestEffect_PSAlphaTestLtGtNoFog, sizeof(AlphaTestEffect_PSAlphaTestLtGtNoFog) },\n    { AlphaTestEffect_PSAlphaTestEqNe,      sizeof(AlphaTestEffect_PSAlphaTestEqNe)      },\n    { AlphaTestEffect_PSAlphaTestEqNeNoFog, sizeof(AlphaTestEffect_PSAlphaTestEqNeNoFog) },\n};\n\n\ntemplate<>\nconst int EffectBase<AlphaTestEffectTraits>::PixelShaderIndices[] =\n{\n    0,      // lt/gt\n    1,      // lt/gt, no fog\n    0,      // lt/gt, vertex color\n    1,      // lt/gt, vertex color, no fog\n    \n    2,      // eq/ne\n    3,      // eq/ne, no fog\n    2,      // eq/ne, vertex color\n    3,      // eq/ne, vertex color, no fog\n};\n\n\n// Global pool of per-device AlphaTestEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<AlphaTestEffectTraits>::DeviceResources> EffectBase<AlphaTestEffectTraits>::deviceResourcesPool = {};\n\n// Constructor.\nAlphaTestEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription,\n    D3D12_COMPARISON_FUNC alphaFunction)\n    : EffectBase(device),\n        mAlphaFunction(alphaFunction),\n        referenceAlpha(0),\n        texture{},\n        textureSampler{}\n{\n    static_assert(_countof(EffectBase<AlphaTestEffectTraits>::VertexShaderIndices) == AlphaTestEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<AlphaTestEffectTraits>::VertexShaderBytecode) == AlphaTestEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<AlphaTestEffectTraits>::PixelShaderBytecode) == AlphaTestEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<AlphaTestEffectTraits>::PixelShaderIndices) == AlphaTestEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_DESCRIPTOR_RANGE textureRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        CD3DX12_DESCRIPTOR_RANGE textureSamplerRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureRange, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSamplerRange, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n        mRootSignature = GetRootSignature(0, rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    fog.enabled = (effectFlags & EffectFlags::Fog) != 0;\n\n    if (effectFlags & EffectFlags::PerPixelLightingBit)\n    {\n        DebugTrace(\"ERROR: AlphaTestEffect does not implement EffectFlags::PerPixelLighting\\n\");\n        throw std::invalid_argument(\"AlphaTestEffect\");\n    }\n    else if (effectFlags & EffectFlags::Lighting)\n    {\n        DebugTrace(\"ERROR: DualTextureEffect does not implement EffectFlags::Lighting\\n\");\n        throw std::invalid_argument(\"AlphaTestEffect\");\n    }\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(\n        (effectFlags & EffectFlags::VertexColor) != 0);\n    assert(sp >= 0 && sp < AlphaTestEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < AlphaTestEffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<AlphaTestEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < AlphaTestEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < AlphaTestEffectTraits::VertexShaderCount);\n    int pi = EffectBase<AlphaTestEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < AlphaTestEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < AlphaTestEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<AlphaTestEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<AlphaTestEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"AlphaTestEffect\");\n}\n\n\nint AlphaTestEffect::Impl::GetPipelineStatePermutation(bool vertexColorEnabled) const noexcept\n{\n    int permutation = 0;\n\n    // Use optimized shaders if fog is disabled.\n    if (!fog.enabled)\n    {\n        permutation += 1;\n    }\n\n    // Support vertex coloring?\n    if (vertexColorEnabled)\n    {\n        permutation += 2;\n    }\n\n    // Which alpha compare mode?\n    if (mAlphaFunction == D3D12_COMPARISON_FUNC_EQUAL ||\n        mAlphaFunction == D3D12_COMPARISON_FUNC_NOT_EQUAL)\n    {\n        permutation += 4;\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid AlphaTestEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n    fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector);            \n    color.SetConstants(dirtyFlags, constants.diffuseColor);\n\n    UpdateConstants();\n\n    // Recompute the alpha test settings?\n    if (dirtyFlags & EffectDirtyFlags::AlphaTest)\n    {\n        // Convert reference alpha from 8 bit integer to 0-1 float format.\n        auto reference = static_cast<float>(referenceAlpha) / 255.0f;\n                \n        // Comparison tolerance of half the 8 bit integer precision.\n        const float threshold = 0.5f / 255.0f;\n\n        // What to do if the alpha comparison passes or fails. Positive accepts the pixel, negative clips it.\n        static const XMVECTORF32 selectIfTrue  = { { {  1, -1 } } };\n        static const XMVECTORF32 selectIfFalse = { { { -1,  1 } } };\n        static const XMVECTORF32 selectNever   = { { { -1, -1 } } };\n        static const XMVECTORF32 selectAlways  = { { {  1,  1 } } };\n\n        float compareTo;\n        XMVECTOR resultSelector;\n\n        switch (mAlphaFunction)\n        {\n            case D3D12_COMPARISON_FUNC_LESS:\n                // Shader will evaluate: clip((a < x) ? z : w)\n                compareTo = reference - threshold;\n                resultSelector = selectIfTrue;\n                break;\n\n            case D3D12_COMPARISON_FUNC_LESS_EQUAL:\n                // Shader will evaluate: clip((a < x) ? z : w)\n                compareTo = reference + threshold;\n                resultSelector = selectIfTrue;\n                break;\n\n            case D3D12_COMPARISON_FUNC_GREATER_EQUAL:\n                // Shader will evaluate: clip((a < x) ? z : w)\n                compareTo = reference - threshold;\n                resultSelector = selectIfFalse;\n                break;\n\n            case D3D12_COMPARISON_FUNC_GREATER:\n                // Shader will evaluate: clip((a < x) ? z : w)\n                compareTo = reference + threshold;\n                resultSelector = selectIfFalse;\n                break;\n\n            case D3D12_COMPARISON_FUNC_EQUAL:\n                // Shader will evaluate: clip((abs(a - x) < y) ? z : w)\n                compareTo = reference;\n                resultSelector = selectIfTrue;\n                break;\n\n            case D3D12_COMPARISON_FUNC_NOT_EQUAL:\n                // Shader will evaluate: clip((abs(a - x) < y) ? z : w)\n                compareTo = reference;\n                resultSelector = selectIfFalse;\n                break;\n\n            case D3D12_COMPARISON_FUNC_NEVER:\n                // Shader will evaluate: clip((a < x) ? z : w)\n                compareTo = 0;\n                resultSelector = selectNever;\n                break;\n\n            case D3D12_COMPARISON_FUNC_ALWAYS:\n                // Shader will evaluate: clip((a < x) ? z : w)\n                compareTo = 0;\n                resultSelector = selectAlways;\n                break;\n\n            default:\n                throw std::exception(\"Unknown alpha test function\");\n        }\n\n        // x = compareTo, y = threshold, zw = resultSelector.\n        constants.alphaTest = XMVectorPermute<0, 1, 4, 5>(XMVectorSet(compareTo, threshold, 0, 0), resultSelector);\n                \n        dirtyFlags &= ~EffectDirtyFlags::AlphaTest;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture\n    if (!texture.ptr || !textureSampler.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture or sampler for AlphaTestEffect (texture %llu, sampler %llu)\\n\", texture.ptr, textureSampler.ptr);\n        throw std::exception(\"AlphaTestEffect\");\n    }\n\n    // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, textureSampler);\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n// Public constructor.\nAlphaTestEffect::AlphaTestEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription,\n    D3D12_COMPARISON_FUNC alphaFunction)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription, alphaFunction))\n{\n}\n\n\n// Move constructor.\nAlphaTestEffect::AlphaTestEffect(AlphaTestEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nAlphaTestEffect& AlphaTestEffect::operator= (AlphaTestEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nAlphaTestEffect::~AlphaTestEffect()\n{\n}\n\n\n// IEffect methods\nvoid AlphaTestEffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings\nvoid XM_CALLCONV AlphaTestEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV AlphaTestEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV AlphaTestEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV AlphaTestEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\n// Material settings\nvoid XM_CALLCONV AlphaTestEffect::SetDiffuseColor(FXMVECTOR value)\n{\n    pImpl->color.diffuseColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid AlphaTestEffect::SetAlpha(float value)\n{\n    pImpl->color.alpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV AlphaTestEffect::SetColorAndAlpha(FXMVECTOR value)\n{\n    pImpl->color.diffuseColor = value;\n    pImpl->color.alpha = XMVectorGetW(value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\n// Fog settings.\nvoid AlphaTestEffect::SetFogStart(float value)\n{\n    pImpl->fog.start = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid AlphaTestEffect::SetFogEnd(float value)\n{\n    pImpl->fog.end = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV AlphaTestEffect::SetFogColor(FXMVECTOR value)\n{\n    pImpl->constants.fogColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid AlphaTestEffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->texture = srvDescriptor;\n    pImpl->textureSampler = samplerDescriptor;\n}\n\n\nvoid AlphaTestEffect::SetReferenceAlpha(int value)\n{\n    pImpl->referenceAlpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::AlphaTest;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/BasicEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: BasicEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct BasicEffectConstants\n    {\n        XMVECTOR diffuseColor;\n        XMVECTOR emissiveColor;\n        XMVECTOR specularColorAndPower;\n\n        XMVECTOR lightDirection[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightDiffuseColor[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightSpecularColor[IEffectLights::MaxDirectionalLights];\n\n        XMVECTOR eyePosition;\n\n        XMVECTOR fogColor;\n        XMVECTOR fogVector;\n\n        XMMATRIX world;\n        XMVECTOR worldInverseTranspose[3];\n        XMMATRIX worldViewProj;\n    };\n\n    static_assert((sizeof(BasicEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct BasicEffectTraits\n    {\n        using ConstantBufferType = BasicEffectConstants;\n\n        static constexpr int VertexShaderCount = 24;\n        static constexpr int PixelShaderCount = 10;\n        static constexpr int ShaderPermutationCount = 40;\n        static constexpr int RootSignatureCount = 2;\n    };\n}\n\n// Internal BasicEffect implementation class.\nclass BasicEffect::Impl : public EffectBase<BasicEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n\n    enum RootParameterIndex\n    {\n        ConstantBuffer,\n        TextureSRV,\n        TextureSampler,\n        RootParameterCount\n    };\n\n    bool lightingEnabled;\n    bool textureEnabled;\n\n    D3D12_GPU_DESCRIPTOR_HANDLE texture;\n    D3D12_GPU_DESCRIPTOR_HANDLE sampler;\n\n    EffectLights lights;\n\n    int GetPipelineStatePermutation(bool preferPerPixelLighting, bool vertexColorEnabled, bool biasedVertexNormals) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasic.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVcNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicTxNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicTxVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicTxVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingVcBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicVertexLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingVcBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_VSBasicPixelLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasic.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicVertexLightingTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettBasicEffect_PSBasicPixelLightingTx.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasic.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVcNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicTxNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicTxVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicTxVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingVcBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicVertexLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingVcBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_VSBasicPixelLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasic.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicVertexLightingTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneBasicEffect_PSBasicPixelLightingTx.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasic.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVc.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVcNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicTx.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicTxNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicTxVc.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicTxVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingVc.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingVc.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingBn.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingVcBn.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicVertexLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingBn.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingVcBn.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_VSBasicPixelLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasic.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicTx.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicVertexLightingTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneBasicEffect_PSBasicPixelLightingTx.inc\"\n#else\n    #include \"Shaders/Compiled/BasicEffect_VSBasic.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVc.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVcNoFog.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicTx.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicTxNoFog.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicTxVc.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicTxVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingVc.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingVc.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingTxVc.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingBn.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingVcBn.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingTxBn.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicVertexLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingBn.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingVcBn.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/BasicEffect_VSBasicPixelLightingTxVcBn.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_PSBasic.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicNoFog.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicTx.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_PSBasicVertexLighting.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicVertexLightingTx.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicVertexLightingTxNoFog.inc\"\n\n    #include \"Shaders/Compiled/BasicEffect_PSBasicPixelLighting.inc\"\n    #include \"Shaders/Compiled/BasicEffect_PSBasicPixelLightingTx.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<BasicEffectTraits>::VertexShaderBytecode[] =\n{\n    { BasicEffect_VSBasic,                     sizeof(BasicEffect_VSBasic)                     },\n    { BasicEffect_VSBasicNoFog,                sizeof(BasicEffect_VSBasicNoFog)                },\n    { BasicEffect_VSBasicVc,                   sizeof(BasicEffect_VSBasicVc)                   },\n    { BasicEffect_VSBasicVcNoFog,              sizeof(BasicEffect_VSBasicVcNoFog)              },\n    { BasicEffect_VSBasicTx,                   sizeof(BasicEffect_VSBasicTx)                   },\n    { BasicEffect_VSBasicTxNoFog,              sizeof(BasicEffect_VSBasicTxNoFog)              },\n    { BasicEffect_VSBasicTxVc,                 sizeof(BasicEffect_VSBasicTxVc)                 },\n    { BasicEffect_VSBasicTxVcNoFog,            sizeof(BasicEffect_VSBasicTxVcNoFog)            },\n\n    { BasicEffect_VSBasicVertexLighting,       sizeof(BasicEffect_VSBasicVertexLighting)       },\n    { BasicEffect_VSBasicVertexLightingVc,     sizeof(BasicEffect_VSBasicVertexLightingVc)     },\n    { BasicEffect_VSBasicVertexLightingTx,     sizeof(BasicEffect_VSBasicVertexLightingTx)     },\n    { BasicEffect_VSBasicVertexLightingTxVc,   sizeof(BasicEffect_VSBasicVertexLightingTxVc)   },\n\n    { BasicEffect_VSBasicPixelLighting,        sizeof(BasicEffect_VSBasicPixelLighting)        },\n    { BasicEffect_VSBasicPixelLightingVc,      sizeof(BasicEffect_VSBasicPixelLightingVc)      },\n    { BasicEffect_VSBasicPixelLightingTx,      sizeof(BasicEffect_VSBasicPixelLightingTx)      },\n    { BasicEffect_VSBasicPixelLightingTxVc,    sizeof(BasicEffect_VSBasicPixelLightingTxVc)    },\n\n    { BasicEffect_VSBasicVertexLightingBn,     sizeof(BasicEffect_VSBasicVertexLightingBn)     },\n    { BasicEffect_VSBasicVertexLightingVcBn,   sizeof(BasicEffect_VSBasicVertexLightingVcBn)   },\n    { BasicEffect_VSBasicVertexLightingTxBn,   sizeof(BasicEffect_VSBasicVertexLightingTxBn)   },\n    { BasicEffect_VSBasicVertexLightingTxVcBn, sizeof(BasicEffect_VSBasicVertexLightingTxVcBn) },\n\n    { BasicEffect_VSBasicPixelLightingBn,      sizeof(BasicEffect_VSBasicPixelLightingBn)      },\n    { BasicEffect_VSBasicPixelLightingVcBn,    sizeof(BasicEffect_VSBasicPixelLightingVcBn)    },\n    { BasicEffect_VSBasicPixelLightingTxBn,    sizeof(BasicEffect_VSBasicPixelLightingTxBn)    },\n    { BasicEffect_VSBasicPixelLightingTxVcBn,  sizeof(BasicEffect_VSBasicPixelLightingTxVcBn)  },\n};\n\n\ntemplate<>\nconst int EffectBase<BasicEffectTraits>::VertexShaderIndices[] =\n{\n    0,      // basic\n    1,      // no fog\n    2,      // vertex color\n    3,      // vertex color, no fog\n    4,      // texture\n    5,      // texture, no fog\n    6,      // texture + vertex color\n    7,      // texture + vertex color, no fog\n\n    8,      // vertex lighting\n    8,      // vertex lighting, no fog\n    9,      // vertex lighting + vertex color\n    9,      // vertex lighting + vertex color, no fog\n    10,     // vertex lighting + texture\n    10,     // vertex lighting + texture, no fog\n    11,     // vertex lighting + texture + vertex color\n    11,     // vertex lighting + texture + vertex color, no fog\n\n    12,     // pixel lighting\n    12,     // pixel lighting, no fog\n    13,     // pixel lighting + vertex color\n    13,     // pixel lighting + vertex color, no fog\n    14,     // pixel lighting + texture\n    14,     // pixel lighting + texture, no fog\n    15,     // pixel lighting + texture + vertex color\n    15,     // pixel lighting + texture + vertex color, no fog\n\n    16,     // vertex lighting (biased vertex normals)\n    16,     // vertex lighting (biased vertex normals), no fog\n    17,     // vertex lighting (biased vertex normals) + vertex color\n    17,     // vertex lighting (biased vertex normals) + vertex color, no fog\n    18,     // vertex lighting (biased vertex normals) + texture\n    18,     // vertex lighting (biased vertex normals) + texture, no fog\n    19,     // vertex lighting (biased vertex normals) + texture + vertex color\n    19,     // vertex lighting (biased vertex normals) + texture + vertex color, no fog\n\n    20,     // pixel lighting (biased vertex normals)\n    20,     // pixel lighting (biased vertex normals), no fog\n    21,     // pixel lighting (biased vertex normals) + vertex color\n    21,     // pixel lighting (biased vertex normals) + vertex color, no fog\n    22,     // pixel lighting (biased vertex normals) + texture\n    22,     // pixel lighting (biased vertex normals) + texture, no fog\n    23,     // pixel lighting (biased vertex normals) + texture + vertex color\n    23,     // pixel lighting (biased vertex normals) + texture + vertex color, no fog\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<BasicEffectTraits>::PixelShaderBytecode[] =\n{\n    { BasicEffect_PSBasic,                      sizeof(BasicEffect_PSBasic)                      },\n    { BasicEffect_PSBasicNoFog,                 sizeof(BasicEffect_PSBasicNoFog)                 },\n    { BasicEffect_PSBasicTx,                    sizeof(BasicEffect_PSBasicTx)                    },\n    { BasicEffect_PSBasicTxNoFog,               sizeof(BasicEffect_PSBasicTxNoFog)               },\n\n    { BasicEffect_PSBasicVertexLighting,        sizeof(BasicEffect_PSBasicVertexLighting)        },\n    { BasicEffect_PSBasicVertexLightingNoFog,   sizeof(BasicEffect_PSBasicVertexLightingNoFog)   },\n    { BasicEffect_PSBasicVertexLightingTx,      sizeof(BasicEffect_PSBasicVertexLightingTx)      },\n    { BasicEffect_PSBasicVertexLightingTxNoFog, sizeof(BasicEffect_PSBasicVertexLightingTxNoFog) },\n\n    { BasicEffect_PSBasicPixelLighting,         sizeof(BasicEffect_PSBasicPixelLighting)         },\n    { BasicEffect_PSBasicPixelLightingTx,       sizeof(BasicEffect_PSBasicPixelLightingTx)       },\n};\n\n\ntemplate<>\nconst int EffectBase<BasicEffectTraits>::PixelShaderIndices[] =\n{\n    0,      // basic\n    1,      // no fog\n    0,      // vertex color\n    1,      // vertex color, no fog\n    2,      // texture\n    3,      // texture, no fog\n    2,      // texture + vertex color\n    3,      // texture + vertex color, no fog\n\n    4,      // vertex lighting\n    5,      // vertex lighting, no fog\n    4,      // vertex lighting + vertex color\n    5,      // vertex lighting + vertex color, no fog\n    6,      // vertex lighting + texture\n    7,      // vertex lighting + texture, no fog\n    6,      // vertex lighting + texture + vertex color\n    7,      // vertex lighting + texture + vertex color, no fog\n\n    8,      // pixel lighting\n    8,      // pixel lighting, no fog\n    8,      // pixel lighting + vertex color\n    8,      // pixel lighting + vertex color, no fog\n    9,      // pixel lighting + texture\n    9,      // pixel lighting + texture, no fog\n    9,      // pixel lighting + texture + vertex color\n    9,      // pixel lighting + texture + vertex color, no fog\n\n    4,      // vertex lighting (biased vertex normals)\n    5,      // vertex lighting (biased vertex normals), no fog\n    4,      // vertex lighting (biased vertex normals) + vertex color\n    5,      // vertex lighting (biased vertex normals) + vertex color, no fog\n    6,      // vertex lighting (biased vertex normals) + texture\n    7,      // vertex lighting (biased vertex normals) + texture, no fog\n    6,      // vertex lighting (biased vertex normals) + texture + vertex color\n    7,      // vertex lighting (biased vertex normals) + texture + vertex color, no fog\n\n    8,      // pixel lighting (biased vertex normals)\n    8,      // pixel lighting (biased vertex normals), no fog\n    8,      // pixel lighting (biased vertex normals) + vertex color\n    8,      // pixel lighting (biased vertex normals) + vertex color, no fog\n    9,      // pixel lighting (biased vertex normals) + texture\n    9,      // pixel lighting (biased vertex normals) + texture, no fog\n    9,      // pixel lighting (biased vertex normals) + texture + vertex color\n    9,      // pixel lighting (biased vertex normals) + texture + vertex color, no fog\n};\n\n// Global pool of per-device BasicEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<BasicEffectTraits>::DeviceResources> EffectBase<BasicEffectTraits>::deviceResourcesPool = {};\n\n\n// Constructor.\nBasicEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : EffectBase(device),\n        texture{},\n        sampler{}\n{\n    static_assert(_countof(EffectBase<BasicEffectTraits>::VertexShaderIndices) == BasicEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<BasicEffectTraits>::VertexShaderBytecode) == BasicEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<BasicEffectTraits>::PixelShaderBytecode) == BasicEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<BasicEffectTraits>::PixelShaderIndices) == BasicEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    lights.InitializeConstants(constants.specularColorAndPower, constants.lightDirection, constants.lightDiffuseColor, constants.lightSpecularColor);\n\n    fog.enabled = (effectFlags & EffectFlags::Fog) != 0;\n    lightingEnabled = (effectFlags & EffectFlags::Lighting) != 0;\n    textureEnabled = (effectFlags & EffectFlags::Texture) != 0;\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        // Create root parameters and initialize first (constants)\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        // Root parameter descriptor - conditionally initialized\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n\n        if (textureEnabled)\n        {\n            // Include texture and srv\n            CD3DX12_DESCRIPTOR_RANGE textureSRV(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n            CD3DX12_DESCRIPTOR_RANGE textureSampler(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n\n            rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);\n            rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL);\n\n            // use all parameters\n            rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n            mRootSignature = GetRootSignature(1, rsigDesc);\n        }\n        else\n        {\n            // only use constant\n            rsigDesc.Init(1, rootParameters, 0, nullptr, rootSignatureFlags);\n\n            mRootSignature = GetRootSignature(0, rsigDesc);\n        }\n    }\n\n    assert(mRootSignature != nullptr);\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(\n        (effectFlags & EffectFlags::PerPixelLightingBit) != 0,\n        (effectFlags & EffectFlags::VertexColor) != 0,\n        (effectFlags & EffectFlags::BiasedVertexNormals) != 0);\n    assert(sp >= 0 && sp < BasicEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < BasicEffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<BasicEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < BasicEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < BasicEffectTraits::VertexShaderCount);\n    int pi = EffectBase<BasicEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < BasicEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < BasicEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<BasicEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<BasicEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"BasicEffect\");\n}\n\n\nint BasicEffect::Impl::GetPipelineStatePermutation(bool preferPerPixelLighting, bool vertexColorEnabled, bool biasedVertexNormals) const noexcept\n{\n    int permutation = 0;\n\n    // Use optimized shaders if fog is disabled.\n    if (!fog.enabled)\n    {\n        permutation += 1;\n    }\n\n    // Support vertex coloring?\n    if (vertexColorEnabled)\n    {\n        permutation += 2;\n    }\n\n    // Support texturing?\n    if (textureEnabled)\n    {\n        permutation += 4;\n    }\n\n    if (lightingEnabled)\n    {\n        if (preferPerPixelLighting)\n        {\n            // Do lighting in the pixel shader.\n            permutation += 16;\n        }\n        else\n        {\n            permutation += 8;\n        }\n\n        if (biasedVertexNormals)\n        {\n            // Compressed normals need to be scaled and biased in the vertex shader.\n            permutation += 16;\n        }\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid BasicEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n    fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector);\n    lights.SetConstants(dirtyFlags, matrices, constants.world, constants.worldInverseTranspose, constants.eyePosition, constants.diffuseColor, constants.emissiveColor, lightingEnabled);\n\n    UpdateConstants();\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture\n    if (textureEnabled)\n    {\n        if (!texture.ptr || !sampler.ptr)\n        {\n            DebugTrace(\"ERROR: Missing texture or sampler for BasicEffect (texture %llu, sampler %llu)\\n\", texture.ptr, sampler.ptr);\n            throw std::exception(\"BasicEffect\");\n        }\n\n        // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n        commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n        commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler);\n    }\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n\n// Public constructor.\nBasicEffect::BasicEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n  : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription))\n{\n}\n\n\n// Move constructor.\nBasicEffect::BasicEffect(BasicEffect&& moveFrom) noexcept\n  : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nBasicEffect& BasicEffect::operator= (BasicEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nBasicEffect::~BasicEffect()\n{\n}\n\n\n// IEffect methods\nvoid BasicEffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings\nvoid XM_CALLCONV BasicEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\n// Material settings\nvoid XM_CALLCONV BasicEffect::SetDiffuseColor(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetEmissiveColor(FXMVECTOR value)\n{\n    pImpl->lights.emissiveColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetSpecularColor(FXMVECTOR value)\n{\n    // Set xyz to new value, but preserve existing w (specular power).\n    pImpl->constants.specularColorAndPower = XMVectorSelect(pImpl->constants.specularColorAndPower, value, g_XMSelect1110);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid BasicEffect::SetSpecularPower(float value)\n{\n    // Set w to new value, but preserve existing xyz (specular color).\n    pImpl->constants.specularColorAndPower = XMVectorSetW(pImpl->constants.specularColorAndPower, value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid BasicEffect::DisableSpecular()\n{\n    // Set specular color to black, power to 1\n    // Note: Don't use a power of 0 or the shader will generate strange highlights on non-specular materials\n\n    pImpl->constants.specularColorAndPower = g_XMIdentityR3; \n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid BasicEffect::SetAlpha(float value)\n{\n    pImpl->lights.alpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetColorAndAlpha(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n    pImpl->lights.alpha = XMVectorGetW(value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\n// Light settings\nvoid XM_CALLCONV BasicEffect::SetAmbientLightColor(FXMVECTOR value)\n{\n    pImpl->lights.ambientLightColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid BasicEffect::SetLightEnabled(int whichLight, bool value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightEnabled(whichLight, value, pImpl->constants.lightDiffuseColor, pImpl->constants.lightSpecularColor);\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetLightDirection(int whichLight, FXMVECTOR value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->constants.lightDirection[whichLight] = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightDiffuseColor(whichLight, value, pImpl->constants.lightDiffuseColor);\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetLightSpecularColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightSpecularColor(whichLight, value, pImpl->constants.lightSpecularColor);\n}\n\n\nvoid BasicEffect::EnableDefaultLighting()\n{\n    EffectLights::EnableDefaultLighting(this);\n}\n\n\n// Fog settings.\nvoid BasicEffect::SetFogStart(float value)\n{\n    pImpl->fog.start = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid BasicEffect::SetFogEnd(float value)\n{\n    pImpl->fog.end = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV BasicEffect::SetFogColor(FXMVECTOR value)\n{\n    pImpl->constants.fogColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid BasicEffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->texture = srvDescriptor;\n    pImpl->sampler = samplerDescriptor;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/BasicPostProcess.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: BasicPostProcess.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"PostProcess.h\"\n\n#include \"AlignedNew.h\"\n#include \"CommonStates.h\"\n#include \"DemandCreate.h\"\n#include \"DirectXHelpers.h\"\n#include \"EffectPipelineStateDescription.h\"\n#include \"GraphicsMemory.h\"\n#include \"SharedResourcePool.h\"\n\nusing namespace DirectX;\n\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    constexpr int c_MaxSamples = 16;\n\n    constexpr int Dirty_ConstantBuffer  = 0x01;\n    constexpr int Dirty_Parameters      = 0x02;\n\n    constexpr int RootSignatureCount = 2;\n\n    // Constant buffer layout. Must match the shader!\n    __declspec(align(16)) struct PostProcessConstants\n    {\n        XMVECTOR sampleOffsets[c_MaxSamples];\n        XMVECTOR sampleWeights[c_MaxSamples];\n    };\n\n    static_assert((sizeof(PostProcessConstants) % 16) == 0, \"CB size not padded correctly\");\n\n    // 2-parameter Gaussian distribution given standard deviation (rho)\n    inline float GaussianDistribution(float x, float y, float rho) noexcept\n    {\n        return expf(-(x * x + y * y) / (2 * rho * rho)) / sqrtf(2 * XM_PI * rho * rho);\n    }\n}\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_VSQuadNoCB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSCopy.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSMonochrome.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSSepia.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSDownScale2x2.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSDownScale4x4.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSGaussianBlur5x5.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSBloomExtract.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSBloomBlur.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_VSQuadNoCB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSCopy.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSMonochrome.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSSepia.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSDownScale2x2.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSDownScale4x4.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSGaussianBlur5x5.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSBloomExtract.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSBloomBlur.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOnePostProcess_VSQuadNoCB.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSCopy.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSMonochrome.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSSepia.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSDownScale2x2.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSDownScale4x4.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSGaussianBlur5x5.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSBloomExtract.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSBloomBlur.inc\"\n#else\n    #include \"Shaders/Compiled/PostProcess_VSQuadNoCB.inc\"\n    #include \"Shaders/Compiled/PostProcess_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/PostProcess_PSCopy.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSMonochrome.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSSepia.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSDownScale2x2.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSDownScale4x4.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSGaussianBlur5x5.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSBloomExtract.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSBloomBlur.inc\"\n#endif\n}\n\nnamespace\n{\n    const D3D12_SHADER_BYTECODE vertexShader[] =\n    {\n        { PostProcess_VSQuadNoCB,               sizeof(PostProcess_VSQuadNoCB) },\n        { PostProcess_VSQuad,                   sizeof(PostProcess_VSQuad) },\n    };\n\n    const D3D12_SHADER_BYTECODE pixelShaders[] =\n    {\n        { PostProcess_PSCopy,                   sizeof(PostProcess_PSCopy) },\n        { PostProcess_PSMonochrome,             sizeof(PostProcess_PSMonochrome) },\n        { PostProcess_PSSepia,                  sizeof(PostProcess_PSSepia) },\n        { PostProcess_PSDownScale2x2,           sizeof(PostProcess_PSDownScale2x2) },\n        { PostProcess_PSDownScale4x4,           sizeof(PostProcess_PSDownScale4x4) },\n        { PostProcess_PSGaussianBlur5x5,        sizeof(PostProcess_PSGaussianBlur5x5) },\n        { PostProcess_PSBloomExtract,           sizeof(PostProcess_PSBloomExtract) },\n        { PostProcess_PSBloomBlur,              sizeof(PostProcess_PSBloomBlur) },\n    };\n\n    static_assert(_countof(pixelShaders) == BasicPostProcess::Effect_Max, \"array/max mismatch\");\n\n    // Factory for lazily instantiating shared root signatures.\n    class DeviceResources\n    {\n    public:\n        DeviceResources(_In_ ID3D12Device* device) noexcept\n            : mDevice(device),\n            mRootSignature{},\n            mMutex{}\n        { }\n\n        ID3D12RootSignature* GetRootSignature(int slot, const D3D12_ROOT_SIGNATURE_DESC& desc)\n        {\n            assert(slot >= 0 && slot < RootSignatureCount);\n            _Analysis_assume_(slot >= 0 && slot < RootSignatureCount);\n\n            return DemandCreate(mRootSignature[slot], mMutex, [&](ID3D12RootSignature** pResult) noexcept -> HRESULT\n            {\n                HRESULT hr = CreateRootSignature(mDevice.Get(), &desc, pResult);\n\n                if (SUCCEEDED(hr))\n                    SetDebugObjectName(*pResult, L\"BasicPostProcess\");\n\n                return hr;\n            });\n        }\n\n        ID3D12Device* GetDevice() const noexcept { return mDevice.Get(); }\n\n    protected:\n        ComPtr<ID3D12Device>                        mDevice;\n        Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature[RootSignatureCount];\n        std::mutex                                  mMutex;\n    };\n}\n\nclass BasicPostProcess::Impl : public AlignedNew<PostProcessConstants>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect ifx);\n\n    void Process(_In_ ID3D12GraphicsCommandList* commandList);\n\n    void SetDirtyFlag() noexcept { mDirtyFlags = INT_MAX; }\n\n    enum RootParameterIndex\n    {\n        TextureSRV,\n        ConstantBuffer,\n        RootParameterCount\n    };\n\n    // Fields.\n    BasicPostProcess::Effect                fx;\n    PostProcessConstants                    constants;\n    D3D12_GPU_DESCRIPTOR_HANDLE             texture;\n    unsigned                                texWidth;\n    unsigned                                texHeight;\n    float                                   guassianMultiplier;\n    float                                   bloomSize;\n    float                                   bloomBrightness;\n    float                                   bloomThreshold;\n    bool                                    bloomHorizontal;\n\nprivate:\n    bool                                    mUseConstants;\n    int                                     mDirtyFlags;\n\n    void                                    DownScale2x2();\n    void                                    DownScale4x4();\n    void                                    GaussianBlur5x5(float multiplier);\n    void                                    Bloom(bool horizontal, float size, float brightness);\n\n    // D3D constant buffer holds a copy of the same data as the public 'constants' field.\n    GraphicsResource mConstantBuffer;\n\n    // Per instance cache of PSOs, populated with variants for each shader & layout\n    Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;\n\n    // Per instance root signature\n    ID3D12RootSignature* mRootSignature;\n\n    // Per-device resources.\n    std::shared_ptr<DeviceResources> mDeviceResources;\n\n    static SharedResourcePool<ID3D12Device*, DeviceResources> deviceResourcesPool;\n};\n\n\n// Global pool of per-device BasicPostProcess resources.\nSharedResourcePool<ID3D12Device*, DeviceResources> BasicPostProcess::Impl::deviceResourcesPool;\n\n\n// Constructor.\nBasicPostProcess::Impl::Impl(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect ifx)\n    : fx(ifx),\n    constants{},\n    texture{},\n    texWidth(0),\n    texHeight(0),\n    guassianMultiplier(1.f),\n    bloomSize(1.f),\n    bloomBrightness(1.f),\n    bloomThreshold(0.25f),\n    bloomHorizontal(true),\n    mDirtyFlags(INT_MAX),\n    mDeviceResources(deviceResourcesPool.DemandCreate(device))\n{\n    if (ifx >= Effect_Max)\n        throw std::out_of_range(\"Effect not defined\");\n   \n    switch (ifx)\n    {\n    case Copy:\n    case Monochrome:\n    case Sepia:\n        // These shaders don't use the constant buffer\n        mUseConstants = false;\n        break;\n\n    default:\n        mUseConstants = true;\n        break;\n    }\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_DESCRIPTOR_RANGE textureSRVs(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n\n        // Same as CommonStates::StaticLinearClamp\n        CD3DX12_STATIC_SAMPLER_DESC sampler(\n            0, // register\n            D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            0.f,\n            16,\n            D3D12_COMPARISON_FUNC_LESS_EQUAL,\n            D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n            0.f,\n            D3D12_FLOAT32_MAX,\n            D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRVs, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Root parameter descriptor - conditionally initialized\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n\n        if (mUseConstants)\n        {\n            // Include constant buffer\n            rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_PIXEL);\n\n            // use all parameters\n            rsigDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags);\n\n            mRootSignature = mDeviceResources->GetRootSignature(1, rsigDesc);\n        }\n        else\n        {\n            // only use constant\n            rsigDesc.Init(1, rootParameters, 1, &sampler, rootSignatureFlags);\n\n            mRootSignature = mDeviceResources->GetRootSignature(0, rsigDesc);\n        }\n    }\n\n    assert(mRootSignature != nullptr);\n\n    // Create pipeline state.\n    EffectPipelineStateDescription psd(nullptr,\n        CommonStates::Opaque,\n        CommonStates::DepthNone,\n        CommonStates::CullNone,\n        rtState,\n        D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);\n\n    psd.CreatePipelineState(\n        device,\n        mRootSignature,\n        vertexShader[mUseConstants ? 1 : 0],\n        pixelShaders[ifx],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"BasicPostProcess\");\n}\n\n\n// Sets our state onto the D3D device.\nvoid BasicPostProcess::Impl::Process(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Set the root signature.\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture.\n    if (!texture.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture for BasicPostProcess (texture %llu)\\n\", texture.ptr);\n        throw std::exception(\"BasicPostProcess\");\n    }\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n\n    // Set constants.\n    if (mUseConstants)\n    {\n        if (mDirtyFlags & Dirty_Parameters)\n        {\n            mDirtyFlags &= ~Dirty_Parameters;\n            mDirtyFlags |= Dirty_ConstantBuffer;\n\n            switch (fx)\n            {\n            case DownScale_2x2:\n                DownScale2x2();\n                break;\n\n            case DownScale_4x4:\n                DownScale4x4();\n                break;\n\n            case GaussianBlur_5x5:\n                GaussianBlur5x5(guassianMultiplier);\n                break;\n\n            case BloomExtract:\n                constants.sampleWeights[0] = XMVectorReplicate(bloomThreshold);\n                break;\n\n            case BloomBlur:\n                Bloom(bloomHorizontal, bloomSize, bloomBrightness);\n                break;\n\n            default:\n                break;\n            }\n        }\n\n        if (mDirtyFlags & Dirty_ConstantBuffer)\n        {\n            mDirtyFlags &= ~Dirty_ConstantBuffer;\n            mConstantBuffer = GraphicsMemory::Get(mDeviceResources->GetDevice()).AllocateConstant(constants);\n        }\n\n        commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, mConstantBuffer.GpuAddress());\n    }\n\n    // Set the pipeline state.\n    commandList->SetPipelineState(mPipelineState.Get());\n\n    // Draw quad.\n    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n    commandList->DrawInstanced(3, 1, 0, 0);\n}\n\n\nvoid BasicPostProcess::Impl::DownScale2x2()\n{\n    mUseConstants = true;\n\n    if (!texWidth || !texHeight)\n    {\n        throw std::exception(\"Call SetSourceTexture before setting post-process effect\");\n    }\n\n    float tu = 1.0f / float(texWidth);\n    float tv = 1.0f / float(texHeight);\n\n    // Sample from the 4 surrounding points. Since the center point will be in the exact\n    // center of 4 texels, a 0.5f offset is needed to specify a texel center.\n    auto ptr = reinterpret_cast<XMFLOAT4*>(constants.sampleOffsets);\n    for (int y = 0; y < 2; ++y)\n    {\n        for (int x = 0; x < 2; ++x)\n        {\n            ptr->x = (float(x) - 0.5f) * tu;\n            ptr->y = (float(y) - 0.5f) * tv;\n            ++ptr;\n        }\n    }\n}\n\n\nvoid BasicPostProcess::Impl::DownScale4x4()\n{\n    mUseConstants = true;\n\n    if (!texWidth || !texHeight)\n    {\n        throw std::exception(\"Call SetSourceTexture before setting post-process effect\");\n    }\n\n    float tu = 1.0f / float(texWidth);\n    float tv = 1.0f / float(texHeight);\n\n    // Sample from the 16 surrounding points. Since the center point will be in the\n    // exact center of 16 texels, a 1.5f offset is needed to specify a texel center.\n    auto ptr = reinterpret_cast<XMFLOAT4*>(constants.sampleOffsets);\n    for (int y = 0; y < 4; ++y)\n    {\n        for (int x = 0; x < 4; ++x)\n        {\n            ptr->x = (float(x) - 1.5f) * tu;\n            ptr->y = (float(y) - 1.5f) * tv;\n            ++ptr;\n        }\n    }\n\n}\n\n\nvoid BasicPostProcess::Impl::GaussianBlur5x5(float multiplier)\n{\n    mUseConstants = true;\n\n    if (!texWidth || !texHeight)\n    {\n        throw std::exception(\"Call SetSourceTexture before setting post-process effect\");\n    }\n\n    float tu = 1.0f / float(texWidth);\n    float tv = 1.0f / float(texHeight);\n\n    float totalWeight = 0.0f;\n    size_t index = 0;\n    auto offsets = reinterpret_cast<XMFLOAT4*>(constants.sampleOffsets);\n    auto weights = constants.sampleWeights;\n    for (int x = -2; x <= 2; ++x)\n    {\n        for (int y = -2; y <= 2; ++y)\n        {\n            // Exclude pixels with a block distance greater than 2. This will\n            // create a kernel which approximates a 5x5 kernel using only 13\n            // sample points instead of 25; this is necessary since 2.0 shaders\n            // only support 16 texture grabs.\n            if (fabsf(float(x)) + fabsf(float(y)) > 2.0f)\n                continue;\n\n            // Get the unscaled Gaussian intensity for this offset\n            offsets[index].x = float(x) * tu;\n            offsets[index].y = float(y) * tv;\n            offsets[index].z = 0.0f;\n            offsets[index].w = 0.0f;\n\n            float g = GaussianDistribution(float(x), float(y), 1.0f);\n            weights[index] = XMVectorReplicate(g);\n\n            totalWeight += XMVectorGetX(weights[index]);\n\n            ++index;\n        }\n    }\n\n    // Divide the current weight by the total weight of all the samples; Gaussian\n    // blur kernels add to 1.0f to ensure that the intensity of the image isn't\n    // changed when the blur occurs. An optional multiplier variable is used to\n    // add or remove image intensity during the blur.\n    XMVECTOR vtw = XMVectorReplicate(totalWeight);\n    XMVECTOR vm = XMVectorReplicate(multiplier);\n    for (size_t i = 0; i < index; ++i)\n    {\n        XMVECTOR w = XMVectorDivide(weights[i], vtw);\n        weights[i] = XMVectorMultiply(w, vm);\n    }\n}\n\n\nvoid  BasicPostProcess::Impl::Bloom(bool horizontal, float size, float brightness)\n{\n    mUseConstants = true;\n\n    if (!texWidth || !texHeight)\n    {\n        throw std::exception(\"Call SetSourceTexture before setting post-process effect\");\n    }\n\n    float tu = 0.f;\n    float tv = 0.f;\n    if (horizontal)\n    {\n        tu = 1.f / float(texWidth);\n    }\n    else\n    {\n        tv = 1.f / float(texHeight);\n    }\n\n    auto weights = reinterpret_cast<XMFLOAT4*>(constants.sampleWeights);\n    auto offsets = reinterpret_cast<XMFLOAT4*>(constants.sampleOffsets);\n\n    // Fill the center texel\n    float weight = brightness * GaussianDistribution(0, 0, size);\n    weights[0] = XMFLOAT4(weight, weight, weight, 1.0f);\n    offsets[0].x = offsets[0].y = offsets[0].z = offsets[0].w = 0.f;\n\n    // Fill the first half\n    for (int i = 1; i < 8; ++i)\n    {\n        // Get the Gaussian intensity for this offset\n        weight = brightness * GaussianDistribution(float(i), 0, size);\n        weights[i] = XMFLOAT4(weight, weight, weight, 1.0f);\n        offsets[i] = XMFLOAT4(float(i) * tu, float(i) * tv, 0.f, 0.f);\n    }\n\n    // Mirror to the second half\n    for (int i = 8; i < 15; i++)\n    {\n        weights[i] = weights[i - 7];\n        offsets[i] = XMFLOAT4(-offsets[i - 7].x, -offsets[i - 7].y, 0.f, 0.f);\n    }\n}\n\n\n// Public constructor.\nBasicPostProcess::BasicPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect fx)\n  : pImpl(std::make_unique<Impl>(device, rtState, fx))\n{\n}\n\n\n// Move constructor.\nBasicPostProcess::BasicPostProcess(BasicPostProcess&& moveFrom) noexcept\n  : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nBasicPostProcess& BasicPostProcess::operator= (BasicPostProcess&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nBasicPostProcess::~BasicPostProcess()\n{\n}\n\n\n// IPostProcess methods.\nvoid BasicPostProcess::Process(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Process(commandList);\n}\n\n\n// Properties\nvoid BasicPostProcess::SetSourceTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, _In_opt_ ID3D12Resource* resource)\n{\n    pImpl->texture = srvDescriptor;\n\n    if (resource)\n    {\n        const auto desc = resource->GetDesc();\n        pImpl->texWidth = static_cast<unsigned>(desc.Width);\n        pImpl->texHeight = desc.Height;\n    }\n    else\n    {\n        pImpl->texWidth = pImpl->texHeight = 0;\n    }\n}\n\n\nvoid BasicPostProcess::SetGaussianParameter(float multiplier)\n{\n    pImpl->guassianMultiplier = multiplier;\n    pImpl->SetDirtyFlag();\n}\n\n\nvoid BasicPostProcess::SetBloomExtractParameter(float threshold)\n{\n    pImpl->bloomThreshold = threshold;\n    pImpl->SetDirtyFlag();\n}\n\n\nvoid BasicPostProcess::SetBloomBlurParameters(bool horizontal, float size, float brightness)\n{\n    pImpl->bloomSize = size;\n    pImpl->bloomBrightness = brightness;\n    pImpl->bloomHorizontal = horizontal;\n    pImpl->SetDirtyFlag();\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Bezier.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Bezier.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <array>\n#include <algorithm>\n#include <DirectXMath.h>\n\n\nnamespace Bezier\n{\n    // Performs a cubic bezier interpolation between four control points,\n    // returning the value at the specified time (t ranges 0 to 1).\n    template<typename T>\n    inline T CubicInterpolate(T const& p1, T const& p2, T const& p3, T const& p4, float t) noexcept\n    {\n        return p1 * (1 - t) * (1 - t) * (1 - t) +\n            p2 * 3 * t * (1 - t) * (1 - t) +\n            p3 * 3 * t * t * (1 - t) +\n            p4 * t * t * t;\n    }\n\n     template<>\n     inline DirectX::XMVECTOR CubicInterpolate(DirectX::XMVECTOR const& p1, DirectX::XMVECTOR const& p2, DirectX::XMVECTOR const& p3, DirectX::XMVECTOR const& p4, float t) noexcept\n    {\n        using namespace DirectX;\n\n        XMVECTOR T0 = XMVectorReplicate((1 - t) * (1 - t) * (1 - t));\n        XMVECTOR T1 = XMVectorReplicate(3 * t * (1 - t) * (1 - t));\n        XMVECTOR T2 = XMVectorReplicate(3 * t * t * (1 - t));\n        XMVECTOR T3 = XMVectorReplicate(t * t * t);\n\n        XMVECTOR Result = XMVectorMultiply(p1, T0);\n        Result = XMVectorMultiplyAdd(p2, T1, Result);\n        Result = XMVectorMultiplyAdd(p3, T2, Result);\n        Result = XMVectorMultiplyAdd(p4, T3, Result);\n\n        return Result;\n    }\n\n\n    // Computes the tangent of a cubic bezier curve at the specified time.\n    template<typename T>\n    inline T CubicTangent(T const& p1, T const& p2, T const& p3, T const& p4, float t) noexcept\n    {\n        using DirectX::operator*;\n        using DirectX::operator+;\n\n        return p1 * (-1 + 2 * t - t * t) +\n            p2 * (1 - 4 * t + 3 * t * t) +\n            p3 * (2 * t - 3 * t * t) +\n            p4 * (t * t);\n    }\n\n    template<>\n    inline DirectX::XMVECTOR CubicTangent(DirectX::XMVECTOR const& p1, DirectX::XMVECTOR const& p2, DirectX::XMVECTOR const& p3, DirectX::XMVECTOR const& p4, float t) noexcept\n    {\n        using namespace DirectX;\n\n        XMVECTOR T0 = XMVectorReplicate(-1 + 2 * t - t * t);\n        XMVECTOR T1 = XMVectorReplicate(1 - 4 * t + 3 * t * t);\n        XMVECTOR T2 = XMVectorReplicate(2 * t - 3 * t * t);\n        XMVECTOR T3 = XMVectorReplicate(t * t);\n\n        XMVECTOR Result = XMVectorMultiply(p1, T0);\n        Result = XMVectorMultiplyAdd(p2, T1, Result);\n        Result = XMVectorMultiplyAdd(p3, T2, Result);\n        Result = XMVectorMultiplyAdd(p4, T3, Result);\n\n        return Result;\n    }\n\n\n    // Creates vertices for a patch that is tessellated at the specified level.\n    // Calls the specified outputVertex function for each generated vertex,\n    // passing the position, normal, and texture coordinate as parameters.\n    template<typename TOutputFunc>\n    void CreatePatchVertices(_In_reads_(16) DirectX::XMVECTOR patch[16], size_t tessellation, bool isMirrored, TOutputFunc outputVertex)\n    {\n        using namespace DirectX;\n\n        for (size_t i = 0; i <= tessellation; i++)\n        {\n            float u = float(i) / float(tessellation);\n\n            for (size_t j = 0; j <= tessellation; j++)\n            {\n                float v = float(j) / float(tessellation);\n\n                // Perform four horizontal bezier interpolations\n                // between the control points of this patch.\n                XMVECTOR p1 = CubicInterpolate(patch[0], patch[1], patch[2], patch[3], u);\n                XMVECTOR p2 = CubicInterpolate(patch[4], patch[5], patch[6], patch[7], u);\n                XMVECTOR p3 = CubicInterpolate(patch[8], patch[9], patch[10], patch[11], u);\n                XMVECTOR p4 = CubicInterpolate(patch[12], patch[13], patch[14], patch[15], u);\n\n                // Perform a vertical interpolation between the results of the\n                // previous horizontal interpolations, to compute the position.\n                XMVECTOR position = CubicInterpolate(p1, p2, p3, p4, v);\n\n                // Perform another four bezier interpolations between the control\n                // points, but this time vertically rather than horizontally.\n                XMVECTOR q1 = CubicInterpolate(patch[0], patch[4], patch[8], patch[12], v);\n                XMVECTOR q2 = CubicInterpolate(patch[1], patch[5], patch[9], patch[13], v);\n                XMVECTOR q3 = CubicInterpolate(patch[2], patch[6], patch[10], patch[14], v);\n                XMVECTOR q4 = CubicInterpolate(patch[3], patch[7], patch[11], patch[15], v);\n\n                // Compute vertical and horizontal tangent vectors.\n                XMVECTOR tangent1 = CubicTangent(p1, p2, p3, p4, v);\n                XMVECTOR tangent2 = CubicTangent(q1, q2, q3, q4, u);\n\n                // Cross the two tangent vectors to compute the normal.\n                XMVECTOR normal = XMVector3Cross(tangent1, tangent2);\n\n                if (!XMVector3NearEqual(normal, XMVectorZero(), g_XMEpsilon))\n                {\n                    normal = XMVector3Normalize(normal);\n\n                    // If this patch is mirrored, we must invert the normal.\n                    if (isMirrored)\n                    {\n                        normal = XMVectorNegate(normal);\n                    }\n                }\n                else\n                {\n                    // In a tidy and well constructed bezier patch, the preceding\n                    // normal computation will always work. But the classic teapot\n                    // model is not tidy or well constructed! At the top and bottom\n                    // of the teapot, it contains degenerate geometry where a patch\n                    // has several control points in the same place, which causes\n                    // the tangent computation to fail and produce a zero normal.\n                    // We 'fix' these cases by just hard-coding a normal that points\n                    // either straight up or straight down, depending on whether we\n                    // are on the top or bottom of the teapot. This is not a robust\n                    // solution for all possible degenerate bezier patches, but hey,\n                    // it's good enough to make the teapot work correctly!\n\n                    normal = XMVectorSelect(g_XMIdentityR1, g_XMNegIdentityR1, XMVectorLess(position, XMVectorZero()));\n                }\n\n                // Compute the texture coordinate.\n                float mirroredU = isMirrored ? 1 - u : u;\n\n                XMVECTOR textureCoordinate = XMVectorSet(mirroredU, v, 0, 0);\n\n                // Output this vertex.\n                outputVertex(position, normal, textureCoordinate);\n            }\n        }\n    }\n\n\n    // Creates indices for a patch that is tessellated at the specified level.\n    // Calls the specified outputIndex function for each generated index value.\n    template<typename TOutputFunc>\n    void CreatePatchIndices(size_t tessellation, bool isMirrored, TOutputFunc outputIndex)\n    {\n        size_t stride = tessellation + 1;\n\n        for (size_t i = 0; i < tessellation; i++)\n        {\n            for (size_t j = 0; j < tessellation; j++)\n            {\n                // Make a list of six index values (two triangles).\n                std::array<size_t, 6> indices =\n                {\n                    i * stride + j,\n                    (i + 1) * stride + j,\n                    (i + 1) * stride + j + 1,\n\n                    i * stride + j,\n                    (i + 1) * stride + j + 1,\n                    i * stride + j + 1,\n                };\n\n                // If this patch is mirrored, reverse indices to fix the winding order.\n                if (isMirrored)\n                {\n                    std::reverse(indices.begin(), indices.end());\n                }\n\n                // Output these index values.\n                std::for_each(indices.begin(), indices.end(), outputIndex);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/BinaryReader.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: BinaryReader.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"BinaryReader.h\"\n\nusing namespace DirectX;\n\n\n// Constructor reads from the filesystem.\nBinaryReader::BinaryReader(_In_z_ wchar_t const* fileName) noexcept(false) :\n    mPos(nullptr),\n    mEnd(nullptr)\n{\n    size_t dataSize;\n\n    HRESULT hr = ReadEntireFile(fileName, mOwnedData, &dataSize);\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: BinaryReader failed (%08X) to load '%ls'\\n\",\n            static_cast<unsigned int>(hr), fileName);\n        throw std::exception(\"BinaryReader\");\n    }\n\n    mPos = mOwnedData.get();\n    mEnd = mOwnedData.get() + dataSize;\n}\n\n\n// Constructor reads from an existing memory buffer.\nBinaryReader::BinaryReader(_In_reads_bytes_(dataSize) uint8_t const* dataBlob, size_t dataSize) noexcept :\n    mPos(dataBlob),\n    mEnd(dataBlob + dataSize)\n{\n}\n\n\n// Reads from the filesystem into memory.\nHRESULT BinaryReader::ReadEntireFile(_In_z_ wchar_t const* fileName, _Inout_ std::unique_ptr<uint8_t[]>& data, _Out_ size_t* dataSize)\n{\n    // Open the file.\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    ScopedHandle hFile(safe_handle(CreateFile2(fileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));\n#else\n    ScopedHandle hFile(safe_handle(CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)));\n#endif\n\n    if (!hFile)\n        return HRESULT_FROM_WIN32(GetLastError());\n\n    // Get the file size.\n    FILE_STANDARD_INFO fileInfo;\n    if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    // File is too big for 32-bit allocation, so reject read.\n    if (fileInfo.EndOfFile.HighPart > 0)\n        return E_FAIL;\n\n    // Create enough space for the file data.\n    data.reset(new uint8_t[fileInfo.EndOfFile.LowPart]);\n\n    if (!data)\n        return E_OUTOFMEMORY;\n\n    // Read the data in.\n    DWORD bytesRead = 0;\n\n    if (!ReadFile(hFile.get(), data.get(), fileInfo.EndOfFile.LowPart, &bytesRead, nullptr))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    if (bytesRead < fileInfo.EndOfFile.LowPart)\n        return E_FAIL;\n\n    *dataSize = bytesRead;\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/BinaryReader.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: BinaryReader.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <memory>\n#include <exception>\n#include <stdexcept>\n#include <type_traits>\n\n#include \"PlatformHelpers.h\"\n\n\nnamespace DirectX\n{\n    // Helper for reading binary data, either from the filesystem a memory buffer.\n    class BinaryReader\n    {\n    public:\n        explicit BinaryReader(_In_z_ wchar_t const* fileName) noexcept(false);\n        BinaryReader(_In_reads_bytes_(dataSize) uint8_t const* dataBlob, size_t dataSize) noexcept;\n\n        BinaryReader(BinaryReader const&) = delete;\n        BinaryReader& operator= (BinaryReader const&) = delete;\n        \n        // Reads a single value.\n        template<typename T> T const& Read()\n        {\n            return *ReadArray<T>(1);\n        }\n\n\n        // Reads an array of values.\n        template<typename T> T const* ReadArray(size_t elementCount)\n        {\n            static_assert(std::is_pod<T>::value, \"Can only read plain-old-data types\");\n\n            uint8_t const* newPos = mPos + sizeof(T) * elementCount;\n\n            if (newPos < mPos)\n                throw std::overflow_error(\"ReadArray\");\n\n            if (newPos > mEnd)\n                throw std::exception(\"End of file\");\n\n            auto result = reinterpret_cast<T const*>(mPos);\n\n            mPos = newPos;\n\n            return result;\n        }\n\n\n        // Lower level helper reads directly from the filesystem into memory.\n        static HRESULT ReadEntireFile(_In_z_ wchar_t const* fileName, _Inout_ std::unique_ptr<uint8_t[]>& data, _Out_ size_t* dataSize);\n\n\n    private:\n        // The data currently being read.\n        uint8_t const* mPos;\n        uint8_t const* mEnd;\n\n        std::unique_ptr<uint8_t[]> mOwnedData;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/BufferHelpers.cpp",
    "content": "//------------------------------------- -------------------------------------------------\n// File: BufferHelpers.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"BufferHelpers.h\"\n#include \"DirectXHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"LoaderHelpers.h\"\n#include \"PlatformHelpers.h\"\n\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CreateStaticBuffer(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUpload,\n    const void* ptr,\n    size_t count,\n    size_t stride,\n    D3D12_RESOURCE_STATES afterState,\n    ID3D12Resource** pBuffer,\n    D3D12_RESOURCE_FLAGS resFlags) noexcept\n{\n    if (!pBuffer)\n        return E_INVALIDARG;\n\n    *pBuffer = nullptr;\n\n    if (!device || !ptr || !count || !stride)\n        return E_INVALIDARG;\n\n    uint64_t sizeInbytes = uint64_t(count) * uint64_t(stride);\n\n    static constexpr uint64_t c_maxBytes = D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u;\n\n    if (sizeInbytes > c_maxBytes)\n    {\n        DebugTrace(\"ERROR: Resource size too large for DirectX 12 (size %llu)\\n\", sizeInbytes);\n        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n    }\n\n    auto desc = CD3DX12_RESOURCE_DESC::Buffer(sizeInbytes, resFlags);\n\n    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    ComPtr<ID3D12Resource> res;\n    HRESULT hr = device->CreateCommittedResource(\n        &heapProperties,\n        D3D12_HEAP_FLAG_NONE,\n        &desc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(res.GetAddressOf()));\n    if (FAILED(hr))\n        return hr;\n\n    D3D12_SUBRESOURCE_DATA initData = { ptr, 0, 0 };\n\n    try\n    {\n        resourceUpload.Upload(res.Get(), 0, &initData, 1);\n\n        resourceUpload.Transition(res.Get(), D3D12_RESOURCE_STATE_COPY_DEST, afterState);\n    }\n    catch (com_exception e)\n    {\n        return e.get_result();\n    }\n    catch (...)\n    {\n        return E_FAIL;\n    }\n\n    *pBuffer = res.Detach();\n\n    return S_OK;\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CreateTextureFromMemory(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUpload,\n    size_t width,\n    DXGI_FORMAT format,\n    const D3D12_SUBRESOURCE_DATA& initData,\n    ID3D12Resource** texture,\n    D3D12_RESOURCE_STATES afterState,\n    D3D12_RESOURCE_FLAGS resFlags) noexcept\n{\n    if (!texture)\n        return E_INVALIDARG;\n\n    *texture = nullptr;\n\n    if (!device || !width || !initData.pData)\n        return E_INVALIDARG;\n\n    static_assert(D3D12_REQ_TEXTURE1D_U_DIMENSION <= UINT64_MAX, \"Exceeded integer limits\");\n\n    if (width > D3D12_REQ_TEXTURE1D_U_DIMENSION)\n    {\n        DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (1D: size %zu)\\n\", width);\n        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n    }\n\n    auto desc = CD3DX12_RESOURCE_DESC::Tex1D(format, static_cast<UINT64>(width), 1u, 1u, resFlags);\n\n    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    ComPtr<ID3D12Resource> res;\n    HRESULT hr = device->CreateCommittedResource(\n        &heapProperties,\n        D3D12_HEAP_FLAG_NONE,\n        &desc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(res.GetAddressOf()));\n    if (FAILED(hr))\n        return hr;\n\n    try\n    {\n        resourceUpload.Upload(res.Get(), 0, &initData, 1);\n\n        resourceUpload.Transition(res.Get(), D3D12_RESOURCE_STATE_COPY_DEST, afterState);\n    }\n    catch (com_exception e)\n    {\n        return e.get_result();\n    }\n    catch (...)\n    {\n        return E_FAIL;\n    }\n\n    *texture = res.Detach();\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateTextureFromMemory(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUpload,\n    size_t width,\n    size_t height,\n    DXGI_FORMAT format,\n    const D3D12_SUBRESOURCE_DATA& initData,\n    ID3D12Resource** texture,\n    bool generateMips,\n    D3D12_RESOURCE_STATES afterState,\n    D3D12_RESOURCE_FLAGS resFlags) noexcept\n{\n    if (!texture)\n        return E_INVALIDARG;\n\n    *texture = nullptr;\n\n    if (!device || !width || !height\n        || !initData.pData || !initData.RowPitch)\n        return E_INVALIDARG;\n\n    static_assert(D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION <= UINT32_MAX, \"Exceeded integer limits\");\n\n    if ((width > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION)\n        || (height > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION))\n    {\n        DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (2D: size %zu by %zu)\\n\", width, height);\n        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n    }\n\n    uint16_t mipCount = 1;\n    if (generateMips)\n    {\n        generateMips = resourceUpload.IsSupportedForGenerateMips(format);\n        if (generateMips)\n        {\n            mipCount = static_cast<uint16_t>(LoaderHelpers::CountMips(static_cast<uint32_t>(width), static_cast<uint32_t>(height)));\n        }\n    }\n\n    auto desc = CD3DX12_RESOURCE_DESC::Tex2D(format, static_cast<UINT64>(width), static_cast<UINT>(height),\n        1u, mipCount, 1u, 0u, resFlags);\n\n    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    ComPtr<ID3D12Resource> res;\n    HRESULT hr = device->CreateCommittedResource(\n        &heapProperties,\n        D3D12_HEAP_FLAG_NONE,\n        &desc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(res.GetAddressOf()));\n    if (FAILED(hr))\n        return hr;\n\n    try\n    {\n        resourceUpload.Upload(res.Get(), 0, &initData, 1);\n\n        resourceUpload.Transition(res.Get(), D3D12_RESOURCE_STATE_COPY_DEST, afterState);\n\n        if (generateMips)\n        {\n            resourceUpload.GenerateMips(res.Get());\n        }\n    }\n    catch (com_exception e)\n    {\n        return e.get_result();\n    }\n    catch (...)\n    {\n        return E_FAIL;\n    }\n\n    *texture = res.Detach();\n\n    return S_OK;\n}\n\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateTextureFromMemory(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUpload,\n    size_t width, size_t height, size_t depth,\n    DXGI_FORMAT format,\n    const D3D12_SUBRESOURCE_DATA& initData,\n    ID3D12Resource** texture,\n    D3D12_RESOURCE_STATES afterState,\n    D3D12_RESOURCE_FLAGS resFlags) noexcept\n{\n    if (!texture)\n        return E_INVALIDARG;\n\n    *texture = nullptr;\n\n    if (!device || !width || !height || !depth\n        || !initData.pData || !initData.RowPitch || !initData.SlicePitch)\n        return E_INVALIDARG;\n\n    static_assert(D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION <= UINT16_MAX, \"Exceeded integer limits\");\n\n    if ((width > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n        || (height > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n        || (depth > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))\n    {\n        DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (3D: size %zu by %zu by %zu)\\n\", width, height, depth);\n        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n    }\n\n    auto desc = CD3DX12_RESOURCE_DESC::Tex3D(format,\n        static_cast<UINT64>(width), static_cast<UINT>(height), static_cast<UINT16>(depth),\n        1u, resFlags);\n\n    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    ComPtr<ID3D12Resource> res;\n    HRESULT hr = device->CreateCommittedResource(\n        &heapProperties,\n        D3D12_HEAP_FLAG_NONE,\n        &desc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(res.GetAddressOf()));\n    if (FAILED(hr))\n        return hr;\n\n    try\n    {\n        resourceUpload.Upload(res.Get(), 0, &initData, 1);\n\n        resourceUpload.Transition(res.Get(), D3D12_RESOURCE_STATE_COPY_DEST, afterState);\n    }\n    catch (com_exception e)\n    {\n        return e.get_result();\n    }\n    catch (...)\n    {\n        return E_FAIL;\n    }\n\n    *texture = res.Detach();\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/CommonStates.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: CommonStates.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"CommonStates.h\"\n#include \"DirectXHelpers.h\"\n#include \"DescriptorHeap.h\"\n\nusing namespace DirectX;\n\n// --------------------------------------------------------------------------\n// Blend States\n// --------------------------------------------------------------------------\n\nconst D3D12_BLEND_DESC CommonStates::Opaque =\n{\n    FALSE, // AlphaToCoverageEnable\n    FALSE, // IndependentBlendEnable\n    { {\n        FALSE, // BlendEnable\n        FALSE, // LogicOpEnable\n        D3D12_BLEND_ONE, // SrcBlend\n        D3D12_BLEND_ZERO, // DestBlend\n        D3D12_BLEND_OP_ADD, // BlendOp\n        D3D12_BLEND_ONE, // SrcBlendAlpha\n        D3D12_BLEND_ZERO, // DestBlendAlpha\n        D3D12_BLEND_OP_ADD, // BlendOpAlpha\n        D3D12_LOGIC_OP_NOOP,\n        D3D12_COLOR_WRITE_ENABLE_ALL\n    } }\n};\n\nconst D3D12_BLEND_DESC CommonStates::AlphaBlend =\n{\n    FALSE, // AlphaToCoverageEnable\n    FALSE, // IndependentBlendEnable\n    { {\n        TRUE, // BlendEnable\n        FALSE, // LogicOpEnable\n        D3D12_BLEND_ONE, // SrcBlend\n        D3D12_BLEND_INV_SRC_ALPHA, // DestBlend\n        D3D12_BLEND_OP_ADD, // BlendOp\n        D3D12_BLEND_ONE, // SrcBlendAlpha\n        D3D12_BLEND_INV_SRC_ALPHA, // DestBlendAlpha\n        D3D12_BLEND_OP_ADD, // BlendOpAlpha\n        D3D12_LOGIC_OP_NOOP,\n        D3D12_COLOR_WRITE_ENABLE_ALL\n    } }\n};\n\nconst D3D12_BLEND_DESC CommonStates::Additive =\n{\n    FALSE, // AlphaToCoverageEnable\n    FALSE, // IndependentBlendEnable\n    { {\n        TRUE, // BlendEnable\n        FALSE, // LogicOpEnable\n        D3D12_BLEND_SRC_ALPHA, // SrcBlend\n        D3D12_BLEND_ONE, // DestBlend\n        D3D12_BLEND_OP_ADD, // BlendOp\n        D3D12_BLEND_SRC_ALPHA, // SrcBlendAlpha\n        D3D12_BLEND_ONE, // DestBlendAlpha\n        D3D12_BLEND_OP_ADD, // BlendOpAlpha\n        D3D12_LOGIC_OP_NOOP,\n        D3D12_COLOR_WRITE_ENABLE_ALL\n    } }\n};\n\nconst D3D12_BLEND_DESC CommonStates::NonPremultiplied =\n{\n    FALSE, // AlphaToCoverageEnable\n    FALSE, // IndependentBlendEnable\n    { {\n        TRUE, // BlendEnable\n        FALSE, // LogicOpEnable\n        D3D12_BLEND_SRC_ALPHA, // SrcBlend\n        D3D12_BLEND_INV_SRC_ALPHA, // DestBlend\n        D3D12_BLEND_OP_ADD, // BlendOp\n        D3D12_BLEND_SRC_ALPHA, // SrcBlendAlpha\n        D3D12_BLEND_INV_SRC_ALPHA, // DestBlendAlpha\n        D3D12_BLEND_OP_ADD, // BlendOpAlpha\n        D3D12_LOGIC_OP_NOOP,\n        D3D12_COLOR_WRITE_ENABLE_ALL\n    } }\n};\n\n\n// --------------------------------------------------------------------------\n// Depth-Stencil States\n// --------------------------------------------------------------------------\n\nconst D3D12_DEPTH_STENCIL_DESC CommonStates::DepthNone =\n{\n    FALSE, // DepthEnable\n    D3D12_DEPTH_WRITE_MASK_ZERO,\n    D3D12_COMPARISON_FUNC_LESS_EQUAL, // DepthFunc\n    FALSE, // StencilEnable\n    D3D12_DEFAULT_STENCIL_READ_MASK,\n    D3D12_DEFAULT_STENCIL_WRITE_MASK,\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    }, // FrontFace\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    } // BackFace\n};\n\nconst D3D12_DEPTH_STENCIL_DESC CommonStates::DepthDefault =\n{\n    TRUE, // DepthEnable\n    D3D12_DEPTH_WRITE_MASK_ALL,\n    D3D12_COMPARISON_FUNC_LESS_EQUAL, // DepthFunc\n    FALSE, // StencilEnable\n    D3D12_DEFAULT_STENCIL_READ_MASK,\n    D3D12_DEFAULT_STENCIL_WRITE_MASK,\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    }, // FrontFace\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    } // BackFace\n};\n\nconst D3D12_DEPTH_STENCIL_DESC CommonStates::DepthRead =\n{\n    TRUE, // DepthEnable\n    D3D12_DEPTH_WRITE_MASK_ZERO,\n    D3D12_COMPARISON_FUNC_LESS_EQUAL, // DepthFunc\n    FALSE, // StencilEnable\n    D3D12_DEFAULT_STENCIL_READ_MASK,\n    D3D12_DEFAULT_STENCIL_WRITE_MASK,\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    }, // FrontFace\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    } // BackFace\n};\n\n\n// --------------------------------------------------------------------------\n// Rasterizer States\n// --------------------------------------------------------------------------\n\nconst D3D12_RASTERIZER_DESC CommonStates::CullNone =\n{\n    D3D12_FILL_MODE_SOLID,\n    D3D12_CULL_MODE_NONE,\n    FALSE, // FrontCounterClockwise\n    D3D12_DEFAULT_DEPTH_BIAS,\n    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,\n    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,\n    TRUE, // DepthClipEnable\n    TRUE, // MultisampleEnable\n    FALSE, // AntialiasedLineEnable\n    0, // ForcedSampleCount\n    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF\n};\n\nconst D3D12_RASTERIZER_DESC CommonStates::CullClockwise =\n{\n    D3D12_FILL_MODE_SOLID,\n    D3D12_CULL_MODE_FRONT,\n    FALSE, // FrontCounterClockwise\n    D3D12_DEFAULT_DEPTH_BIAS,\n    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,\n    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,\n    TRUE, // DepthClipEnable\n    TRUE, // MultisampleEnable\n    FALSE, // AntialiasedLineEnable\n    0, // ForcedSampleCount\n    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF\n};\n\nconst D3D12_RASTERIZER_DESC CommonStates::CullCounterClockwise =\n{\n    D3D12_FILL_MODE_SOLID,\n    D3D12_CULL_MODE_BACK,\n    FALSE, // FrontCounterClockwise\n    D3D12_DEFAULT_DEPTH_BIAS,\n    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,\n    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,\n    TRUE, // DepthClipEnable\n    TRUE, // MultisampleEnable\n    FALSE, // AntialiasedLineEnable\n    0, // ForcedSampleCount\n    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF\n};\n\nconst D3D12_RASTERIZER_DESC CommonStates::Wireframe =\n{\n    D3D12_FILL_MODE_WIREFRAME,\n    D3D12_CULL_MODE_NONE,\n    FALSE, // FrontCounterClockwise\n    D3D12_DEFAULT_DEPTH_BIAS,\n    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,\n    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,\n    TRUE, // DepthClipEnable\n    TRUE, // MultisampleEnable\n    FALSE, // AntialiasedLineEnable\n    0, // ForcedSampleCount\n    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF\n};\n\n\n// --------------------------------------------------------------------------\n// Static sampler States\n// --------------------------------------------------------------------------\n\nconst D3D12_STATIC_SAMPLER_DESC CommonStates::StaticPointWrap(\n    unsigned int shaderRegister,\n    D3D12_SHADER_VISIBILITY shaderVisibility,\n    unsigned int registerSpace) noexcept\n{\n    static const D3D12_STATIC_SAMPLER_DESC s_desc = {\n        D3D12_FILTER_MIN_MAG_MIP_POINT,\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,\n        0, // MinLOD\n        FLT_MAX, // MaxLOD\n        0, // ShaderRegister\n        0, // RegisterSpace\n        D3D12_SHADER_VISIBILITY_ALL,\n    };\n\n    D3D12_STATIC_SAMPLER_DESC desc = s_desc;\n    desc.ShaderRegister = shaderRegister;\n    desc.ShaderVisibility = shaderVisibility;\n    desc.RegisterSpace = registerSpace;\n    return desc;\n}\n\nconst D3D12_STATIC_SAMPLER_DESC CommonStates::StaticPointClamp(\n    unsigned int shaderRegister,\n    D3D12_SHADER_VISIBILITY shaderVisibility,\n    unsigned int registerSpace) noexcept\n{\n    static const D3D12_STATIC_SAMPLER_DESC s_desc = {\n        D3D12_FILTER_MIN_MAG_MIP_POINT,\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,\n        0, // MinLOD\n        FLT_MAX, // MaxLOD\n        0, // ShaderRegister\n        0, // RegisterSpace\n        D3D12_SHADER_VISIBILITY_ALL,\n    };\n\n    D3D12_STATIC_SAMPLER_DESC desc = s_desc;\n    desc.ShaderRegister = shaderRegister;\n    desc.ShaderVisibility = shaderVisibility;\n    desc.RegisterSpace = registerSpace;\n    return desc;\n};\n\nconst D3D12_STATIC_SAMPLER_DESC CommonStates::StaticLinearWrap(\n    unsigned int shaderRegister,\n    D3D12_SHADER_VISIBILITY shaderVisibility,\n    unsigned int registerSpace) noexcept\n{\n    static const D3D12_STATIC_SAMPLER_DESC s_desc = {\n        D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,\n        0, // MinLOD\n        FLT_MAX, // MaxLOD\n        0, // ShaderRegister\n        0, // RegisterSpace\n        D3D12_SHADER_VISIBILITY_ALL,\n    };\n\n    D3D12_STATIC_SAMPLER_DESC desc = s_desc;\n    desc.ShaderRegister = shaderRegister;\n    desc.ShaderVisibility = shaderVisibility;\n    desc.RegisterSpace = registerSpace;\n    return desc;\n};\n\nconst D3D12_STATIC_SAMPLER_DESC CommonStates::StaticLinearClamp(\n    unsigned int shaderRegister,\n    D3D12_SHADER_VISIBILITY shaderVisibility,\n    unsigned int registerSpace) noexcept\n{\n    static const D3D12_STATIC_SAMPLER_DESC s_desc = {\n        D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,\n        0, // MinLOD\n        FLT_MAX, // MaxLOD\n        0, // ShaderRegister\n        0, // RegisterSpace\n        D3D12_SHADER_VISIBILITY_ALL,\n    };\n\n    D3D12_STATIC_SAMPLER_DESC desc = s_desc;\n    desc.ShaderRegister = shaderRegister;\n    desc.ShaderVisibility = shaderVisibility;\n    desc.RegisterSpace = registerSpace;\n    return desc;\n};\n\nconst D3D12_STATIC_SAMPLER_DESC CommonStates::StaticAnisotropicWrap(\n    unsigned int shaderRegister,\n    D3D12_SHADER_VISIBILITY shaderVisibility,\n    unsigned int registerSpace) noexcept\n{\n    static const D3D12_STATIC_SAMPLER_DESC s_desc = {\n        D3D12_FILTER_ANISOTROPIC,\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,\n        0, // MinLOD\n        FLT_MAX, // MaxLOD\n        0, // ShaderRegister\n        0, // RegisterSpace\n        D3D12_SHADER_VISIBILITY_ALL,\n    };\n\n    D3D12_STATIC_SAMPLER_DESC desc = s_desc;\n    desc.ShaderRegister = shaderRegister;\n    desc.ShaderVisibility = shaderVisibility;\n    desc.RegisterSpace = registerSpace;\n    return desc;\n};\n\nconst D3D12_STATIC_SAMPLER_DESC CommonStates::StaticAnisotropicClamp(\n    unsigned int shaderRegister,\n    D3D12_SHADER_VISIBILITY shaderVisibility,\n    unsigned int registerSpace) noexcept\n{\n    static const D3D12_STATIC_SAMPLER_DESC s_desc = {\n        D3D12_FILTER_ANISOTROPIC,\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK,\n        0, // MinLOD\n        FLT_MAX, // MaxLOD\n        0, // ShaderRegister\n        0, // RegisterSpace\n        D3D12_SHADER_VISIBILITY_ALL,\n    };\n\n    D3D12_STATIC_SAMPLER_DESC desc = s_desc;\n    desc.ShaderRegister = shaderRegister;\n    desc.ShaderVisibility = shaderVisibility;\n    desc.RegisterSpace = registerSpace;\n    return desc;\n};\n\n// --------------------------------------------------------------------------\n// Samplers\n// --------------------------------------------------------------------------\n\nclass CommonStates::Impl\n{\npublic:\n\n    static const D3D12_SAMPLER_DESC SamplerDescs[static_cast<int>(SamplerIndex::Count)];\n\n    Impl(_In_ ID3D12Device* device)\n        : mDescriptors(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, static_cast<size_t>(SamplerIndex::Count))\n    {\n        SetDebugObjectName(mDescriptors.Heap(), L\"CommonStates\");\n\n        for (size_t i = 0; i < static_cast<size_t>(SamplerIndex::Count); ++i)\n        {\n            device->CreateSampler(&SamplerDescs[i], mDescriptors.GetCpuHandle(i));\n        }\n    }\n\n    D3D12_GPU_DESCRIPTOR_HANDLE Get(SamplerIndex i) const\n    {\n        return mDescriptors.GetGpuHandle(static_cast<size_t>(i));\n    }\n\n    ID3D12DescriptorHeap* Heap() const noexcept\n    {\n        return mDescriptors.Heap();\n    }\n\nprivate:\n    DescriptorHeap mDescriptors;\n};\n\nconst D3D12_SAMPLER_DESC CommonStates::Impl::SamplerDescs[] =\n{\n    // PointWrap\n    {\n        D3D12_FILTER_MIN_MAG_MIP_POINT,\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        { 0, 0, 0, 0 }, // BorderColor\n        0, // MinLOD\n        FLT_MAX // MaxLOD\n    },\n    // PointClamp\n    {\n        D3D12_FILTER_MIN_MAG_MIP_POINT,\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        { 0, 0, 0, 0 }, // BorderColor\n        0, // MinLOD\n        FLT_MAX // MaxLOD\n    },\n    // LinearWrap\n    {\n        D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        { 0, 0, 0, 0 }, // BorderColor\n        0, // MinLOD\n        FLT_MAX // MaxLOD\n    },\n    // LinearClamp\n    {\n        D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        { 0, 0, 0, 0 }, // BorderColor\n        0, // MinLOD\n        FLT_MAX // MaxLOD\n    },\n    // AnisotropicWrap\n    {\n        D3D12_FILTER_ANISOTROPIC,\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_WRAP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        { 0, 0, 0, 0 }, // BorderColor\n        0, // MinLOD\n        FLT_MAX // MaxLOD\n    },\n    // AnisotropicClamp\n    {\n        D3D12_FILTER_ANISOTROPIC,\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressU\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressV\n        D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // AddressW\n        0, // MipLODBias\n        D3D12_MAX_MAXANISOTROPY,\n        D3D12_COMPARISON_FUNC_NEVER,\n        { 0, 0, 0, 0 }, // BorderColor\n        0, // MinLOD\n        FLT_MAX // MaxLOD\n    }\n};\n\n\n_Use_decl_annotations_\nCommonStates::CommonStates(ID3D12Device* device)\n{\n    pImpl = std::make_unique<Impl>(device);\n}\n\nCommonStates::CommonStates(CommonStates&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\nCommonStates::~CommonStates() {}\n\nCommonStates& CommonStates::operator = (CommonStates&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\nD3D12_GPU_DESCRIPTOR_HANDLE CommonStates::PointWrap() const { return pImpl->Get(SamplerIndex::PointWrap); }\nD3D12_GPU_DESCRIPTOR_HANDLE CommonStates::PointClamp() const { return pImpl->Get(SamplerIndex::PointClamp); }\nD3D12_GPU_DESCRIPTOR_HANDLE CommonStates::LinearWrap() const { return pImpl->Get(SamplerIndex::LinearWrap); }\nD3D12_GPU_DESCRIPTOR_HANDLE CommonStates::LinearClamp() const { return pImpl->Get(SamplerIndex::LinearClamp); }\nD3D12_GPU_DESCRIPTOR_HANDLE CommonStates::AnisotropicWrap() const { return pImpl->Get(SamplerIndex::AnisotropicWrap); }\nD3D12_GPU_DESCRIPTOR_HANDLE CommonStates::AnisotropicClamp() const { return pImpl->Get(SamplerIndex::AnisotropicClamp); }\n\nID3D12DescriptorHeap* CommonStates::Heap() const noexcept { return pImpl->Heap(); }\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DDS.h",
    "content": "//--------------------------------------------------------------------------------------\n// dds.h\n//\n// This header defines constants and structures that are useful when parsing \n// DDS files.  DDS files were originally designed to use several structures\n// and constants that are native to DirectDraw and are defined in ddraw.h,\n// such as DDSURFACEDESC2 and DDSCAPS2.  This file defines similar \n// (compatible) constants and structures so that one can use DDS files \n// without needing to include ddraw.h.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <cstdint>\n\nnamespace DirectX\n{\n\n#pragma pack(push,1)\n\nconstexpr uint32_t DDS_MAGIC = 0x20534444; // \"DDS \"\n\nstruct DDS_PIXELFORMAT\n{\n    uint32_t    size;\n    uint32_t    flags;\n    uint32_t    fourCC;\n    uint32_t    RGBBitCount;\n    uint32_t    RBitMask;\n    uint32_t    GBitMask;\n    uint32_t    BBitMask;\n    uint32_t    ABitMask;\n};\n\n#define DDS_FOURCC      0x00000004  // DDPF_FOURCC\n#define DDS_RGB         0x00000040  // DDPF_RGB\n#define DDS_RGBA        0x00000041  // DDPF_RGB | DDPF_ALPHAPIXELS\n#define DDS_LUMINANCE   0x00020000  // DDPF_LUMINANCE\n#define DDS_LUMINANCEA  0x00020001  // DDPF_LUMINANCE | DDPF_ALPHAPIXELS\n#define DDS_ALPHAPIXELS 0x00000001  // DDPF_ALPHAPIXELS\n#define DDS_ALPHA       0x00000002  // DDPF_ALPHA\n#define DDS_PAL8        0x00000020  // DDPF_PALETTEINDEXED8\n#define DDS_PAL8A       0x00000021  // DDPF_PALETTEINDEXED8 | DDPF_ALPHAPIXELS\n#define DDS_BUMPDUDV    0x00080000  // DDPF_BUMPDUDV\n// DDS_BUMPLUMINANCE 0x00040000\n\n#ifndef MAKEFOURCC\n    #define MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n                (static_cast<uint32_t>(static_cast<uint8_t>(ch0)) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch1)) << 8) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch2)) << 16) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch3)) << 24))\n#endif /* defined(MAKEFOURCC) */\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT3 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC4_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC4_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC5_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC5_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_YUY2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_UYVY =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G16R16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x0000ffff, 0xffff0000, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R5G6B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8R3G3B2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R3G3B2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A4L4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x0f, 0, 0, 0xf0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0,  8, 0xff, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_L16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0, 0, 0xff00 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8L8_ALT =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x00ff, 0, 0, 0xff00 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0, 0, 0, 0xff };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_V8U8 = \n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_Q8W8V8U8 = \n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_V16U16 = \n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 };\n\n// D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A2R10G10B10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 };\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A2B10G10R10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 };\n\n// We do not support the following legacy Direct3D 9 formats:\n// DDSPF_A2W10V10U10 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 };\n// DDSPF_L6V5U5 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 16, 0x001f, 0x03e0, 0xfc00, 0 };\n// DDSPF_X8L8V8U8 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 };\n\n// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)\nextern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DX10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 };\n\n#define DDS_HEADER_FLAGS_TEXTURE        0x00001007  // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT \n#define DDS_HEADER_FLAGS_MIPMAP         0x00020000  // DDSD_MIPMAPCOUNT\n#define DDS_HEADER_FLAGS_VOLUME         0x00800000  // DDSD_DEPTH\n#define DDS_HEADER_FLAGS_PITCH          0x00000008  // DDSD_PITCH\n#define DDS_HEADER_FLAGS_LINEARSIZE     0x00080000  // DDSD_LINEARSIZE\n\n#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT\n#define DDS_WIDTH  0x00000004 // DDSD_WIDTH\n\n#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE\n#define DDS_SURFACE_FLAGS_MIPMAP  0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\n#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX\n\n#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\n#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\n#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\n#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\n#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\n#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\\\n                               DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\\\n                               DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )\n\n#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP\n\n#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME\n\n// Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION\nenum DDS_RESOURCE_DIMENSION : uint32_t\n{\n    DDS_DIMENSION_TEXTURE1D\t= 2,\n    DDS_DIMENSION_TEXTURE2D\t= 3,\n    DDS_DIMENSION_TEXTURE3D\t= 4,\n};\n\n// Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG\nenum DDS_RESOURCE_MISC_FLAG : uint32_t\n{\n    DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L,\n};\n\nenum DDS_MISC_FLAGS2 : uint32_t\n{\n    DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,\n};\n\n#ifndef DDS_ALPHA_MODE_DEFINED\n#define DDS_ALPHA_MODE_DEFINED\nenum DDS_ALPHA_MODE : uint32_t\n{\n    DDS_ALPHA_MODE_UNKNOWN = 0,\n    DDS_ALPHA_MODE_STRAIGHT = 1,\n    DDS_ALPHA_MODE_PREMULTIPLIED = 2,\n    DDS_ALPHA_MODE_OPAQUE = 3,\n    DDS_ALPHA_MODE_CUSTOM = 4,\n};\n#endif\n\nstruct DDS_HEADER\n{\n    uint32_t        size;\n    uint32_t        flags;\n    uint32_t        height;\n    uint32_t        width;\n    uint32_t        pitchOrLinearSize;\n    uint32_t        depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags\n    uint32_t        mipMapCount;\n    uint32_t        reserved1[11];\n    DDS_PIXELFORMAT ddspf;\n    uint32_t        caps;\n    uint32_t        caps2;\n    uint32_t        caps3;\n    uint32_t        caps4;\n    uint32_t        reserved2;\n};\n\nstruct DDS_HEADER_DXT10\n{\n    DXGI_FORMAT     dxgiFormat;\n    uint32_t        resourceDimension;\n    uint32_t        miscFlag; // see D3D11_RESOURCE_MISC_FLAG\n    uint32_t        arraySize;\n    uint32_t        miscFlags2; // see DDS_MISC_FLAGS2\n};\n\n#pragma pack(pop)\n\nstatic_assert( sizeof(DDS_HEADER) == 124, \"DDS Header size mismatch\" );\nstatic_assert( sizeof(DDS_HEADER_DXT10) == 20, \"DDS DX10 Extended Header size mismatch\");\n\n} // namespace\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DDSTextureLoader.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DDSTextureLoader.cpp\n//\n// Functions for loading a DDS texture and creating a Direct3D runtime resource for it\n//\n// Note these functions are useful as a light-weight runtime loader for DDS files. For\n// a full-featured DDS file reader, writer, and texture processing pipeline see\n// the 'Texconv' sample and the 'DirectXTex' library.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"DDSTextureLoader.h\"\n\n#include \"PlatformHelpers.h\"\n#include \"DDS.h\"\n#include \"DirectXHelpers.h\"\n#include \"LoaderHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::LoaderHelpers;\n\nstatic_assert(static_cast<int>(DDS_DIMENSION_TEXTURE1D) == static_cast<int>(D3D12_RESOURCE_DIMENSION_TEXTURE1D), \"dds mismatch\");\nstatic_assert(static_cast<int>(DDS_DIMENSION_TEXTURE2D) == static_cast<int>(D3D12_RESOURCE_DIMENSION_TEXTURE2D), \"dds mismatch\");\nstatic_assert(static_cast<int>(DDS_DIMENSION_TEXTURE3D) == static_cast<int>(D3D12_RESOURCE_DIMENSION_TEXTURE3D), \"dds mismatch\");\n\nnamespace\n{\n    inline bool IsDepthStencil(DXGI_FORMAT fmt) noexcept\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_R32G8X24_TYPELESS:\n        case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n        case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n        case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n        case DXGI_FORMAT_D32_FLOAT:\n        case DXGI_FORMAT_R24G8_TYPELESS:\n        case DXGI_FORMAT_D24_UNORM_S8_UINT:\n        case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n        case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n        case DXGI_FORMAT_D16_UNORM:\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        case DXGI_FORMAT_D16_UNORM_S8_UINT:\n        case DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n        case DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n#endif\n            return true;\n\n        default:\n            return false;\n        }\n    }\n\n    //--------------------------------------------------------------------------------------\n    inline void AdjustPlaneResource(\n        _In_ DXGI_FORMAT fmt,\n        _In_ size_t height,\n        _In_ size_t slicePlane,\n        _Inout_ D3D12_SUBRESOURCE_DATA& res) noexcept\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_NV12:\n        case DXGI_FORMAT_P010:\n        case DXGI_FORMAT_P016:\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        case DXGI_FORMAT_D16_UNORM_S8_UINT:\n        case DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n        case DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n#endif\n            if (!slicePlane)\n            {\n                // Plane 0\n                res.SlicePitch = res.RowPitch * static_cast<LONG>(height);\n            }\n            else\n            {\n                // Plane 1\n                res.pData = static_cast<const uint8_t*>(res.pData) + uintptr_t(res.RowPitch) * height;\n                res.SlicePitch = res.RowPitch * ((static_cast<LONG>(height) + 1) >> 1);\n            }\n            break;\n\n        case DXGI_FORMAT_NV11:\n            if (!slicePlane)\n            {\n                // Plane 0\n                res.SlicePitch = res.RowPitch * static_cast<LONG>(height);\n            }\n            else\n            {\n                // Plane 1\n                res.pData = static_cast<const uint8_t*>(res.pData) + uintptr_t(res.RowPitch) * height;\n                res.RowPitch = (res.RowPitch >> 1);\n                res.SlicePitch = res.RowPitch * static_cast<LONG>(height);\n            }\n            break;\n\n        default:\n            break;\n        }\n    }\n\n    //--------------------------------------------------------------------------------------\n    HRESULT FillInitData(_In_ size_t width,\n        _In_ size_t height,\n        _In_ size_t depth,\n        _In_ size_t mipCount,\n        _In_ size_t arraySize,\n        _In_ size_t numberOfPlanes,\n        _In_ DXGI_FORMAT format,\n        _In_ size_t maxsize,\n        _In_ size_t bitSize,\n        _In_reads_bytes_(bitSize) const uint8_t* bitData,\n        _Out_ size_t& twidth,\n        _Out_ size_t& theight,\n        _Out_ size_t& tdepth,\n        _Out_ size_t& skipMip,\n        std::vector<D3D12_SUBRESOURCE_DATA>& initData)\n    {\n        if (!bitData)\n        {\n            return E_POINTER;\n        }\n\n        skipMip = 0;\n        twidth = 0;\n        theight = 0;\n        tdepth = 0;\n\n        size_t NumBytes = 0;\n        size_t RowBytes = 0;\n        const uint8_t* pEndBits = bitData + bitSize;\n\n        initData.clear();\n\n        for (size_t p = 0; p < numberOfPlanes; ++p)\n        {\n            const uint8_t* pSrcBits = bitData;\n\n            for (size_t j = 0; j < arraySize; j++)\n            {\n                size_t w = width;\n                size_t h = height;\n                size_t d = depth;\n                for (size_t i = 0; i < mipCount; i++)\n                {\n                    HRESULT hr = GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr);\n                    if (FAILED(hr))\n                        return hr;\n\n                    if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX)\n                        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n                    if ((mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize))\n                    {\n                        if (!twidth)\n                        {\n                            twidth = w;\n                            theight = h;\n                            tdepth = d;\n                        }\n\n                        D3D12_SUBRESOURCE_DATA res =\n                        {\n                            pSrcBits,\n                            static_cast<LONG_PTR>(RowBytes),\n                            static_cast<LONG_PTR>(NumBytes)\n                        };\n\n                        AdjustPlaneResource(format, h, p, res);\n\n                        initData.emplace_back(res);\n                    }\n                    else if (!j)\n                    {\n                        // Count number of skipped mipmaps (first item only)\n                        ++skipMip;\n                    }\n\n                    if (pSrcBits + (NumBytes*d) > pEndBits)\n                    {\n                        return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n                    }\n\n                    pSrcBits += NumBytes * d;\n\n                    w = w >> 1;\n                    h = h >> 1;\n                    d = d >> 1;\n                    if (w == 0)\n                    {\n                        w = 1;\n                    }\n                    if (h == 0)\n                    {\n                        h = 1;\n                    }\n                    if (d == 0)\n                    {\n                        d = 1;\n                    }\n                }\n            }\n        }\n\n        return initData.empty() ? E_FAIL : S_OK;\n    }\n\n    //--------------------------------------------------------------------------------------\n    HRESULT CreateTextureResource(\n        _In_ ID3D12Device* d3dDevice,\n        D3D12_RESOURCE_DIMENSION resDim,\n        size_t width,\n        size_t height,\n        size_t depth,\n        size_t mipCount,\n        size_t arraySize,\n        DXGI_FORMAT format,\n        D3D12_RESOURCE_FLAGS resFlags,\n        DDS_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture) noexcept\n    {\n        if (!d3dDevice)\n            return E_POINTER;\n\n        HRESULT hr = E_FAIL;\n\n        if (loadFlags & DDS_LOADER_FORCE_SRGB)\n        {\n            format = MakeSRGB(format);\n        }\n\n        D3D12_RESOURCE_DESC desc = {};\n        desc.Width = static_cast<UINT>(width);\n        desc.Height = static_cast<UINT>(height);\n        desc.MipLevels = static_cast<UINT16>(mipCount);\n        desc.DepthOrArraySize = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D) ? static_cast<UINT16>(depth) : static_cast<UINT16>(arraySize);\n        desc.Format = format;\n        desc.Flags = resFlags;\n        desc.SampleDesc.Count = 1;\n        desc.SampleDesc.Quality = 0;\n        desc.Dimension = resDim;\n\n        CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        hr = d3dDevice->CreateCommittedResource(\n            &defaultHeapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &desc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(texture));\n        if (SUCCEEDED(hr))\n        {\n            assert(texture != nullptr && *texture != nullptr);\n            _Analysis_assume_(texture != nullptr && *texture != nullptr);\n\n            SetDebugObjectName(*texture, L\"DDSTextureLoader\");\n        }\n\n        return hr;\n    }\n\n    //--------------------------------------------------------------------------------------\n    HRESULT CreateTextureFromDDS(_In_ ID3D12Device* d3dDevice,\n        _In_ const DDS_HEADER* header,\n        _In_reads_bytes_(bitSize) const uint8_t* bitData,\n        size_t bitSize,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        DDS_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n        _Out_opt_ bool* outIsCubeMap) noexcept(false)\n    {\n        HRESULT hr = S_OK;\n\n        UINT width = header->width;\n        UINT height = header->height;\n        UINT depth = header->depth;\n\n        D3D12_RESOURCE_DIMENSION resDim = D3D12_RESOURCE_DIMENSION_UNKNOWN;\n        UINT arraySize = 1;\n        DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;\n        bool isCubeMap = false;\n\n        size_t mipCount = header->mipMapCount;\n        if (0 == mipCount)\n        {\n            mipCount = 1;\n        }\n\n        if ((header->ddspf.flags & DDS_FOURCC) &&\n            (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))\n        {\n            auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>(reinterpret_cast<const char*>(header) + sizeof(DDS_HEADER));\n\n            arraySize = d3d10ext->arraySize;\n            if (arraySize == 0)\n            {\n                return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n            }\n\n            switch (d3d10ext->dxgiFormat)\n            {\n            case DXGI_FORMAT_AI44:\n            case DXGI_FORMAT_IA44:\n            case DXGI_FORMAT_P8:\n            case DXGI_FORMAT_A8P8:\n                DebugTrace(\"ERROR: DDSTextureLoader does not support video textures. Consider using DirectXTex instead.\\n\");\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n            default:\n                if (BitsPerPixel(d3d10ext->dxgiFormat) == 0)\n                {\n                    DebugTrace(\"ERROR: Unknown DXGI format (%u)\\n\", static_cast<uint32_t>(d3d10ext->dxgiFormat));\n                    return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                }\n                break;\n            }\n\n            format = d3d10ext->dxgiFormat;\n\n            switch (d3d10ext->resourceDimension)\n            {\n            case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n                // D3DX writes 1D textures with a fixed Height of 1\n                if ((header->flags & DDS_HEIGHT) && height != 1)\n                {\n                    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n                }\n                height = depth = 1;\n                break;\n\n            case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n                if (d3d10ext->miscFlag & 0x4 /* RESOURCE_MISC_TEXTURECUBE */)\n                {\n                    arraySize *= 6;\n                    isCubeMap = true;\n                }\n                depth = 1;\n                break;\n\n            case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n                if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))\n                {\n                    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n                }\n\n                if (arraySize > 1)\n                {\n                    DebugTrace(\"ERROR: Volume textures are not texture arrays\\n\");\n                    return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                }\n                break;\n\n            case D3D12_RESOURCE_DIMENSION_BUFFER:\n                DebugTrace(\"ERROR: Resource dimension buffer type not supported for textures\\n\");\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n            case D3D12_RESOURCE_DIMENSION_UNKNOWN:\n            default:\n                DebugTrace(\"ERROR: Unknown resource dimension (%u)\\n\", static_cast<uint32_t>(d3d10ext->resourceDimension));\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n\n            resDim = static_cast<D3D12_RESOURCE_DIMENSION>(d3d10ext->resourceDimension);\n        }\n        else\n        {\n            format = GetDXGIFormat(header->ddspf);\n\n            if (format == DXGI_FORMAT_UNKNOWN)\n            {\n                DebugTrace(\"ERROR: DDSTextureLoader does not support all legacy DDS formats. Consider using DirectXTex.\\n\");\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n\n            if (header->flags & DDS_HEADER_FLAGS_VOLUME)\n            {\n                resDim = D3D12_RESOURCE_DIMENSION_TEXTURE3D;\n            }\n            else\n            {\n                if (header->caps2 & DDS_CUBEMAP)\n                {\n                    // We require all six faces to be defined\n                    if ((header->caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)\n                    {\n                        DebugTrace(\"ERROR: DirectX 12 does not support partial cubemaps\\n\");\n                        return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                    }\n\n                    arraySize = 6;\n                    isCubeMap = true;\n                }\n\n                depth = 1;\n                resDim = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n\n                // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture\n            }\n\n            assert(BitsPerPixel(format) != 0);\n        }\n\n        // Bound sizes (for security purposes we don't trust DDS file metadata larger than the Direct3D hardware requirements)\n        if (mipCount > D3D12_REQ_MIP_LEVELS)\n        {\n            DebugTrace(\"ERROR: Too many mipmap levels defined for DirectX 12 (%zu).\\n\", mipCount);\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        switch (resDim)\n        {\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            if ((arraySize > D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||\n                (width > D3D12_REQ_TEXTURE1D_U_DIMENSION))\n            {\n                DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (1D: array %u, size %u)\\n\", arraySize, width);\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n            if (isCubeMap)\n            {\n                // This is the right bound because we set arraySize to (NumCubes*6) above\n                if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||\n                    (width > D3D12_REQ_TEXTURECUBE_DIMENSION) ||\n                    (height > D3D12_REQ_TEXTURECUBE_DIMENSION))\n                {\n                    DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (2D cubemap: array %u, size %u by %u)\\n\", arraySize, width, height);\n                    return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                }\n            }\n            else if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||\n                (width > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||\n                (height > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION))\n            {\n                DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (2D: array %u, size %u by %u)\\n\", arraySize, width, height);\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            if ((arraySize > 1) ||\n                (width > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||\n                (height > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||\n                (depth > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))\n            {\n                DebugTrace(\"ERROR: Resource dimensions too large for DirectX 12 (3D: array %u, size %u by %u by %u)\\n\", arraySize, width, height, depth);\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_BUFFER:\n            DebugTrace(\"ERROR: Resource dimension buffer type not supported for textures\\n\");\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n        default:\n            DebugTrace(\"ERROR: Unknown resource dimension (%u)\\n\", static_cast<uint32_t>(resDim));\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        UINT numberOfPlanes = D3D12GetFormatPlaneCount(d3dDevice, format);\n        if (!numberOfPlanes)\n            return E_INVALIDARG;\n\n        if ((numberOfPlanes > 1) && IsDepthStencil(format))\n        {\n            // DirectX 12 uses planes for stencil, DirectX 11 does not\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        if (outIsCubeMap != nullptr)\n        {\n            *outIsCubeMap = isCubeMap;\n        }\n\n        // Create the texture\n        size_t numberOfResources = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D)\n            ? 1 : arraySize;\n        numberOfResources *= mipCount;\n        numberOfResources *= numberOfPlanes;\n\n        if (numberOfResources > D3D12_REQ_SUBRESOURCES)\n            return E_INVALIDARG;\n\n        subresources.reserve(numberOfResources);\n\n        size_t skipMip = 0;\n        size_t twidth = 0;\n        size_t theight = 0;\n        size_t tdepth = 0;\n        hr = FillInitData(width, height, depth, mipCount, arraySize,\n            numberOfPlanes, format,\n            maxsize, bitSize, bitData,\n            twidth, theight, tdepth, skipMip, subresources);\n\n        if (SUCCEEDED(hr))\n        {\n            size_t reservedMips = mipCount;\n            if (loadFlags & (DDS_LOADER_MIP_AUTOGEN | DDS_LOADER_MIP_RESERVE))\n            {\n                reservedMips = std::min<size_t>(D3D12_REQ_MIP_LEVELS,\n                    LoaderHelpers::CountMips(width, height));\n            }\n\n            hr = CreateTextureResource(d3dDevice, resDim, twidth, theight, tdepth, reservedMips - skipMip, arraySize,\n                format, resFlags, loadFlags, texture);\n\n            if (FAILED(hr) && !maxsize && (mipCount > 1))\n            {\n                subresources.clear();\n\n                maxsize = static_cast<size_t>(\n                    (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D)\n                    ? D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION\n                    : D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION);\n\n                hr = FillInitData(width, height, depth, mipCount, arraySize,\n                    numberOfPlanes, format,\n                    maxsize, bitSize, bitData,\n                    twidth, theight, tdepth, skipMip, subresources);\n                if (SUCCEEDED(hr))\n                {\n                    hr = CreateTextureResource(d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize,\n                        format, resFlags, loadFlags, texture);\n                }\n            }\n        }\n\n        if (FAILED(hr))\n        {\n            subresources.clear();\n        }\n\n        return hr;\n    }\n\n    //--------------------------------------------------------------------------------------\n    void SetDebugTextureInfo(\n        _In_z_ const wchar_t* fileName,\n        _In_ ID3D12Resource** texture) noexcept\n    {\n#if !defined(NO_D3D12_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )\n        if (texture && *texture)\n        {\n            const wchar_t* pstrName = wcsrchr(fileName, '\\\\');\n            if (!pstrName)\n            {\n                pstrName = fileName;\n            }\n            else\n            {\n                pstrName++;\n            }\n\n            (*texture)->SetName(pstrName);\n        }\n#else\n        UNREFERENCED_PARAMETER(fileName);\n        UNREFERENCED_PARAMETER(texture);\n#endif\n    }\n\n    //--------------------------------------------------------------------------------------\n    DXGI_FORMAT GetPixelFormat(const DDS_HEADER* header) noexcept\n    {\n        if ((header->ddspf.flags & DDS_FOURCC) &&\n            (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))\n        {\n            auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>(reinterpret_cast<const char*>(header) + sizeof(DDS_HEADER));\n            return d3d10ext->dxgiFormat;\n        }\n        else\n            return GetDXGIFormat(header->ddspf);\n    }\n} // anonymous namespace\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadDDSTextureFromMemory(\n    ID3D12Device* d3dDevice,\n    const uint8_t* ddsData,\n    size_t ddsDataSize,\n    ID3D12Resource** texture,\n    std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n    size_t maxsize,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    return LoadDDSTextureFromMemoryEx(\n        d3dDevice,\n        ddsData,\n        ddsDataSize,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        DDS_LOADER_DEFAULT,\n        texture,\n        subresources,\n        alphaMode,\n        isCubeMap);\n}\n\n\n_Use_decl_annotations_\nHRESULT DirectX::LoadDDSTextureFromMemoryEx(\n    ID3D12Device* d3dDevice,\n    const uint8_t* ddsData,\n    size_t ddsDataSize,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    DDS_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture,\n    std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n    if (alphaMode)\n    {\n        *alphaMode = DDS_ALPHA_MODE_UNKNOWN;\n    }\n    if (isCubeMap)\n    {\n        *isCubeMap = false;\n    }\n\n    if (!d3dDevice || !ddsData || !texture)\n    {\n        return E_INVALIDARG;\n    }\n\n    // Validate DDS file in memory\n    const DDS_HEADER* header = nullptr;\n    const uint8_t* bitData = nullptr;\n    size_t bitSize = 0;\n\n    HRESULT hr = LoadTextureDataFromMemory(ddsData,\n        ddsDataSize,\n        &header,\n        &bitData,\n        &bitSize\n    );\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    hr = CreateTextureFromDDS(d3dDevice,\n        header, bitData, bitSize, maxsize,\n        resFlags, loadFlags,\n        texture, subresources, isCubeMap);\n    if (SUCCEEDED(hr))\n    {\n        if (texture && *texture)\n        {\n            SetDebugObjectName(*texture, L\"DDSTextureLoader\");\n        }\n\n        if (alphaMode)\n            *alphaMode = GetAlphaMode(header);\n    }\n\n    return hr;\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadDDSTextureFromFile(\n    ID3D12Device* d3dDevice,\n    const wchar_t* fileName,\n    ID3D12Resource** texture,\n    std::unique_ptr<uint8_t[]>& ddsData,\n    std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n    size_t maxsize,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    return LoadDDSTextureFromFileEx(\n        d3dDevice,\n        fileName,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        DDS_LOADER_DEFAULT,\n        texture,\n        ddsData,\n        subresources,\n        alphaMode,\n        isCubeMap);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::LoadDDSTextureFromFileEx(\n    ID3D12Device* d3dDevice,\n    const wchar_t* fileName,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    DDS_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture,\n    std::unique_ptr<uint8_t[]>& ddsData,\n    std::vector<D3D12_SUBRESOURCE_DATA>& subresources,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n    if (alphaMode)\n    {\n        *alphaMode = DDS_ALPHA_MODE_UNKNOWN;\n    }\n    if (isCubeMap)\n    {\n        *isCubeMap = false;\n    }\n\n    if (!d3dDevice || !fileName || !texture)\n    {\n        return E_INVALIDARG;\n    }\n\n    const DDS_HEADER* header = nullptr;\n    const uint8_t* bitData = nullptr;\n    size_t bitSize = 0;\n\n    HRESULT hr = LoadTextureDataFromFile(fileName,\n        ddsData,\n        &header,\n        &bitData,\n        &bitSize\n    );\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    hr = CreateTextureFromDDS(d3dDevice,\n        header, bitData, bitSize, maxsize,\n        resFlags, loadFlags,\n        texture, subresources, isCubeMap);\n\n    if (SUCCEEDED(hr))\n    {\n        SetDebugTextureInfo(fileName, texture);\n\n        if (alphaMode)\n            *alphaMode = GetAlphaMode(header);\n    }\n\n    return hr;\n}\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CreateDDSTextureFromMemory(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const uint8_t* ddsData,\n    size_t ddsDataSize,\n    ID3D12Resource** texture,\n    bool generateMipsIfMissing,\n    size_t maxsize,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    return CreateDDSTextureFromMemoryEx(\n        d3dDevice,\n        resourceUpload,\n        ddsData,\n        ddsDataSize,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        generateMipsIfMissing ? DDS_LOADER_MIP_AUTOGEN : DDS_LOADER_DEFAULT,\n        texture,\n        alphaMode,\n        isCubeMap);\n}\n\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateDDSTextureFromMemoryEx(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const uint8_t* ddsData,\n    size_t ddsDataSize,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    DDS_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n    if (alphaMode)\n    {\n        *alphaMode = DDS_ALPHA_MODE_UNKNOWN;\n    }\n    if (isCubeMap)\n    {\n        *isCubeMap = false;\n    }\n\n    if (!d3dDevice || !ddsData || !texture)\n    {\n        return E_INVALIDARG;\n    }\n\n    // Validate DDS file in memory\n    const DDS_HEADER* header = nullptr;\n    const uint8_t* bitData = nullptr;\n    size_t bitSize = 0;\n\n    HRESULT hr = LoadTextureDataFromMemory(ddsData,\n        ddsDataSize,\n        &header,\n        &bitData,\n        &bitSize\n    );\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    if (loadFlags & DDS_LOADER_MIP_AUTOGEN)\n    {\n        DXGI_FORMAT fmt = GetPixelFormat(header);\n        if (!resourceUpload.IsSupportedForGenerateMips(fmt))\n        {\n            DebugTrace(\"WARNING: Autogen of mips ignored (device doesn't support this format (%d) or trying to use a copy queue)\\n\", static_cast<int>(fmt));\n            loadFlags &= ~DDS_LOADER_MIP_AUTOGEN;\n        }\n    }\n\n    std::vector<D3D12_SUBRESOURCE_DATA> subresources;\n    hr = CreateTextureFromDDS(d3dDevice,\n        header, bitData, bitSize, maxsize,\n        resFlags, loadFlags,\n        texture, subresources, isCubeMap);\n\n    if (SUCCEEDED(hr))\n    {\n        if (texture && *texture)\n        {\n            SetDebugObjectName(*texture, L\"DDSTextureLoader\");\n        }\n\n        if (alphaMode)\n            *alphaMode = GetAlphaMode(header);\n\n        resourceUpload.Upload(\n            *texture,\n            0,\n            subresources.data(),\n            static_cast<UINT>(subresources.size()));\n\n        resourceUpload.Transition(\n            *texture,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        // If it's missing mips, let's generate them\n        if ((loadFlags & DDS_LOADER_MIP_AUTOGEN) && subresources.size() != (*texture)->GetDesc().MipLevels)\n        {\n            resourceUpload.GenerateMips(*texture);\n        }\n    }\n\n    return hr;\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CreateDDSTextureFromFile(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const wchar_t* fileName,\n    ID3D12Resource** texture,\n    bool generateMipsIfMissing,\n    size_t maxsize,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    return CreateDDSTextureFromFileEx(\n        d3dDevice,\n        resourceUpload,\n        fileName,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        generateMipsIfMissing ? DDS_LOADER_MIP_AUTOGEN : DDS_LOADER_DEFAULT,\n        texture,\n        alphaMode,\n        isCubeMap);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateDDSTextureFromFileEx(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const wchar_t* fileName,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    DDS_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture,\n    DDS_ALPHA_MODE* alphaMode,\n    bool* isCubeMap)\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n    if (alphaMode)\n    {\n        *alphaMode = DDS_ALPHA_MODE_UNKNOWN;\n    }\n    if (isCubeMap)\n    {\n        *isCubeMap = false;\n    }\n\n    if (!d3dDevice || !fileName || !texture)\n    {\n        return E_INVALIDARG;\n    }\n\n    const DDS_HEADER* header = nullptr;\n    const uint8_t* bitData = nullptr;\n    size_t bitSize = 0;\n\n    std::unique_ptr<uint8_t[]> ddsData;\n    HRESULT hr = LoadTextureDataFromFile(fileName,\n        ddsData,\n        &header,\n        &bitData,\n        &bitSize\n    );\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    if (loadFlags & DDS_LOADER_MIP_AUTOGEN)\n    {\n        DXGI_FORMAT fmt = GetPixelFormat(header);\n        if (!resourceUpload.IsSupportedForGenerateMips(fmt))\n        {\n            DebugTrace(\"WARNING: Autogen of mips ignored (device doesn't support this format (%d) or trying to use a copy queue)\\n\", static_cast<int>(fmt));\n            loadFlags &= ~DDS_LOADER_MIP_AUTOGEN;\n        }\n    }\n\n    std::vector<D3D12_SUBRESOURCE_DATA> subresources;\n    hr = CreateTextureFromDDS(d3dDevice,\n        header, bitData, bitSize, maxsize,\n        resFlags, loadFlags,\n        texture, subresources, isCubeMap);\n\n    if (SUCCEEDED(hr))\n    {\n        SetDebugTextureInfo(fileName, texture);\n\n        if (alphaMode)\n            *alphaMode = GetAlphaMode(header);\n\n        resourceUpload.Upload(\n            *texture,\n            0,\n            subresources.data(),\n            static_cast<UINT>(subresources.size()));\n\n        resourceUpload.Transition(\n            *texture,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        // If it's missing mips, let's generate them\n        if ((loadFlags & DDS_LOADER_MIP_AUTOGEN) && subresources.size() != (*texture)->GetDesc().MipLevels)\n        {\n            resourceUpload.GenerateMips(*texture);\n        }\n    }\n\n    return hr;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DebugEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DebugEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct DebugEffectConstants\n    {\n        XMVECTOR ambientDownAndAlpha;\n        XMVECTOR ambientRange;\n\n        XMMATRIX world;\n        XMVECTOR worldInverseTranspose[3];\n        XMMATRIX worldViewProj;\n    };\n\n    static_assert((sizeof(DebugEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct DebugEffectTraits\n    {\n        using ConstantBufferType = DebugEffectConstants;\n\n        static constexpr int VertexShaderCount = 4;\n        static constexpr int PixelShaderCount = 4;\n        static constexpr int ShaderPermutationCount = 16;\n        static constexpr int RootSignatureCount = 1;\n    };\n}\n\n// Internal DebugEffect implementation class.\nclass DebugEffect::Impl : public EffectBase<DebugEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription,\n        DebugEffect::Mode debugMode);\n\n    enum RootParameterIndex\n    {\n        ConstantBuffer,\n        RootParameterCount\n    };\n\n    int GetPipelineStatePermutation(bool vertexColorEnabled, DebugEffect::Mode debugMode, bool biasedVertexNormals) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_VSDebug.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_VSDebugVc.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_VSDebugBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_VSDebugVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_PSHemiAmbient.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_PSRGBNormals.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_PSRGBTangents.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDebugEffect_PSRGBBiTangents.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_VSDebug.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_VSDebugVc.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_VSDebugBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_VSDebugVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_PSHemiAmbient.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_PSRGBNormals.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_PSRGBTangents.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDebugEffect_PSRGBBiTangents.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneDebugEffect_VSDebug.inc\"\n    #include \"Shaders/Compiled/XboxOneDebugEffect_VSDebugVc.inc\"\n\n    #include \"Shaders/Compiled/XboxOneDebugEffect_VSDebugBn.inc\"\n    #include \"Shaders/Compiled/XboxOneDebugEffect_VSDebugVcBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOneDebugEffect_PSHemiAmbient.inc\"\n    #include \"Shaders/Compiled/XboxOneDebugEffect_PSRGBNormals.inc\"\n    #include \"Shaders/Compiled/XboxOneDebugEffect_PSRGBTangents.inc\"\n    #include \"Shaders/Compiled/XboxOneDebugEffect_PSRGBBiTangents.inc\"\n#else    \n    #include \"Shaders/Compiled/DebugEffect_VSDebug.inc\"\n    #include \"Shaders/Compiled/DebugEffect_VSDebugVc.inc\"\n\n    #include \"Shaders/Compiled/DebugEffect_VSDebugBn.inc\"\n    #include \"Shaders/Compiled/DebugEffect_VSDebugVcBn.inc\"\n\n    #include \"Shaders/Compiled/DebugEffect_PSHemiAmbient.inc\"\n    #include \"Shaders/Compiled/DebugEffect_PSRGBNormals.inc\"\n    #include \"Shaders/Compiled/DebugEffect_PSRGBTangents.inc\"\n    #include \"Shaders/Compiled/DebugEffect_PSRGBBiTangents.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<DebugEffectTraits>::VertexShaderBytecode[] =\n{    \n    { DebugEffect_VSDebug,      sizeof(DebugEffect_VSDebug)     },\n    { DebugEffect_VSDebugVc,    sizeof(DebugEffect_VSDebugVc)   },\n\n    { DebugEffect_VSDebugBn,    sizeof(DebugEffect_VSDebugBn)   },\n    { DebugEffect_VSDebugVcBn,  sizeof(DebugEffect_VSDebugVcBn) },\n};\n\n\ntemplate<>\nconst int EffectBase<DebugEffectTraits>::VertexShaderIndices[] =\n{    \n    0,      // default\n    0,      // normals\n    0,      // tangents\n    0,      // bitangents\n\n    1,      // vertex color + default\n    1,      // vertex color + normals\n    1,      // vertex color + tangents\n    1,      // vertex color + bitangents\n\n    2,      // default (biased vertex normal)\n    2,      // normals (biased vertex normal)\n    2,      // tangents (biased vertex normal)\n    2,      // bitangents (biased vertex normal)\n\n    3,      // vertex color (biased vertex normal)\n    3,      // vertex color (biased vertex normal) + normals\n    3,      // vertex color (biased vertex normal) + tangents\n    3,      // vertex color (biased vertex normal) + bitangents\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<DebugEffectTraits>::PixelShaderBytecode[] =\n{\n    { DebugEffect_PSHemiAmbient,    sizeof(DebugEffect_PSHemiAmbient)          },\n    { DebugEffect_PSRGBNormals,     sizeof(DebugEffect_PSRGBNormals)     },\n    { DebugEffect_PSRGBTangents,    sizeof(DebugEffect_PSRGBTangents)    },\n    { DebugEffect_PSRGBBiTangents,  sizeof(DebugEffect_PSRGBBiTangents) },\n};\n\n\ntemplate<>\nconst int EffectBase<DebugEffectTraits>::PixelShaderIndices[] =\n{    \n    0,      // default\n    1,      // normals\n    2,      // tangents\n    3,      // bitangents\n\n    0,      // vertex color + default\n    1,      // vertex color + normals\n    2,      // vertex color + tangents\n    3,      // vertex color + bitangents\n\n    0,      // default (biased vertex normal)\n    1,      // normals (biased vertex normal)\n    2,      // tangents (biased vertex normal)\n    3,      // bitangents (biased vertex normal)\n\n    0,      // vertex color (biased vertex normal)\n    1,      // vertex color (biased vertex normal) + normals\n    2,      // vertex color (biased vertex normal) + tangents\n    3,      // vertex color (biased vertex normal) + bitangents\n};\n\n\n// Global pool of per-deviceDebugEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<DebugEffectTraits>::DeviceResources> EffectBase<DebugEffectTraits>::deviceResourcesPool = {};\n\n\n// Constructor.\nDebugEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription,\n    DebugEffect::Mode debugMode)\n    : EffectBase(device)\n{\n    static_assert(_countof(EffectBase<DebugEffectTraits>::VertexShaderIndices) == DebugEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<DebugEffectTraits>::VertexShaderBytecode) == DebugEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<DebugEffectTraits>::PixelShaderBytecode) == DebugEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<DebugEffectTraits>::PixelShaderIndices) == DebugEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    static const XMVECTORF32 s_lower = { { { 0.f, 0.f, 0.f, 1.f } } };\n\n    constants.ambientDownAndAlpha = s_lower;\n    constants.ambientRange = g_XMOne;\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        // Create root parameters and initialize first (constants)\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        // Root parameter descriptor - conditionally initialized\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n\n        rsigDesc.Init(1, rootParameters, 0, nullptr, rootSignatureFlags);\n\n        mRootSignature = GetRootSignature(0, rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(\n        (effectFlags & EffectFlags::VertexColor) != 0,\n        debugMode,\n        (effectFlags & EffectFlags::BiasedVertexNormals) != 0);\n    assert(sp >= 0 && sp < DebugEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < DebugEffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<DebugEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < DebugEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < DebugEffectTraits::VertexShaderCount);\n    int pi = EffectBase<DebugEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < DebugEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < DebugEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<DebugEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<DebugEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"DebugEffect\");\n}\n\n\nint DebugEffect::Impl::GetPipelineStatePermutation(bool vertexColorEnabled, DebugEffect::Mode debugMode, bool biasedVertexNormals) const noexcept\n{\n    int permutation = static_cast<int>(debugMode);\n\n    // Support vertex coloring?\n    if (vertexColorEnabled)\n    {\n        permutation += 4;\n    }\n\n    if (biasedVertexNormals)\n    {\n        // Compressed normals need to be scaled and biased in the vertex shader.\n        permutation += 8;\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid DebugEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n\n    // World inverse transpose matrix.\n    if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose)\n    {\n        constants.world = XMMatrixTranspose(matrices.world);\n\n        XMMATRIX worldInverse = XMMatrixInverse(nullptr, matrices.world);\n\n        constants.worldInverseTranspose[0] = worldInverse.r[0];\n        constants.worldInverseTranspose[1] = worldInverse.r[1];\n        constants.worldInverseTranspose[2] = worldInverse.r[2];\n\n        dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n\n    UpdateConstants();\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n\n// Public constructor.\nDebugEffect::DebugEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription,\n    Mode debugMode)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription, debugMode))\n{\n}\n\n\n// Move constructor.\nDebugEffect::DebugEffect(DebugEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nDebugEffect& DebugEffect::operator= (DebugEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nDebugEffect::~DebugEffect()\n{\n}\n\n\n// IEffect methods.\nvoid DebugEffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings.\nvoid XM_CALLCONV DebugEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose;\n}\n\n\nvoid XM_CALLCONV DebugEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV DebugEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV DebugEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose;\n}\n\n\n// Material settings.\nvoid XM_CALLCONV DebugEffect::SetHemisphericalAmbientColor(FXMVECTOR upper, FXMVECTOR lower)\n{\n    // Set xyz to new value, but preserve existing w (alpha).\n    pImpl->constants.ambientDownAndAlpha = XMVectorSelect(pImpl->constants.ambientDownAndAlpha, lower, g_XMSelect1110);\n\n    pImpl->constants.ambientRange = XMVectorSubtract(upper, lower);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\nvoid DebugEffect::SetAlpha(float value)\n{\n    // Set w to new value, but preserve existing xyz (ambient down).\n    pImpl->constants.ambientDownAndAlpha = XMVectorSetW(pImpl->constants.ambientDownAndAlpha, value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DemandCreate.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: DemandCreate.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"PlatformHelpers.h\"\n\n\nnamespace DirectX\n{\n    // Helper for lazily creating a D3D resource.\n    template<typename T, typename TCreateFunc>\n    inline T* DemandCreate(Microsoft::WRL::ComPtr<T>& comPtr, std::mutex& mutex, TCreateFunc createFunc)\n    {\n        T* result = comPtr.Get();\n\n        // Double-checked lock pattern.\n        MemoryBarrier();\n\n        if (!result)\n        {\n            std::lock_guard<std::mutex> lock(mutex);\n\n            result = comPtr.Get();\n        \n            if (!result)\n            {\n                // Create the new object.\n                ThrowIfFailed(\n                    createFunc(&result)\n                );\n\n                MemoryBarrier();\n\n                comPtr.Attach(result);\n            }\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DescriptorHeap.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DescriptorHeap.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"PlatformHelpers.h\"\n#include \"DirectXHelpers.h\"\n#include \"DescriptorHeap.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    struct DescriptorHeapDesc\n    {\n        D3D12_DESCRIPTOR_HEAP_TYPE Type;\n        D3D12_DESCRIPTOR_HEAP_FLAGS Flags;\n    };\n\n    static const DescriptorHeapDesc c_DescriptorHeapDescs[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES] =\n    {\n        { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\tD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE },\n        { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,\t\tD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE },\n        { D3D12_DESCRIPTOR_HEAP_TYPE_RTV,\t\t\tD3D12_DESCRIPTOR_HEAP_FLAG_NONE },\n        { D3D12_DESCRIPTOR_HEAP_TYPE_DSV,\t\t\tD3D12_DESCRIPTOR_HEAP_FLAG_NONE }\n    };\n}\n\n_Use_decl_annotations_\nDescriptorHeap::DescriptorHeap(\n    ID3D12DescriptorHeap* pExistingHeap) noexcept\n    : m_pHeap(pExistingHeap)\n{\n    m_hCPU = pExistingHeap->GetCPUDescriptorHandleForHeapStart();\n    m_hGPU = pExistingHeap->GetGPUDescriptorHandleForHeapStart();\n    m_desc = pExistingHeap->GetDesc();\n\n    ComPtr<ID3D12Device> device;\n    pExistingHeap->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()));\n\n    m_increment = device->GetDescriptorHandleIncrementSize(m_desc.Type);\n}\n\n_Use_decl_annotations_\nDescriptorHeap::DescriptorHeap(\n    ID3D12Device* device,\n    const D3D12_DESCRIPTOR_HEAP_DESC* pDesc) noexcept(false) :\n    m_desc{},\n    m_hCPU{},\n    m_hGPU{},\n    m_increment(0)\n{\n    Create(device, pDesc);\n}\n\n_Use_decl_annotations_\nDescriptorHeap::DescriptorHeap(\n    ID3D12Device* device,\n    D3D12_DESCRIPTOR_HEAP_TYPE type,\n    D3D12_DESCRIPTOR_HEAP_FLAGS flags,\n    size_t count) noexcept(false) :\n    m_desc{},\n    m_hCPU{},\n    m_hGPU{},\n    m_increment(0)\n{\n    if (count > UINT32_MAX)\n        throw std::exception(\"Too many descriptors\");\n\n    D3D12_DESCRIPTOR_HEAP_DESC desc = {};\n    desc.Flags = flags;\n    desc.NumDescriptors = static_cast<UINT>(count);\n    desc.Type = type;\n    Create(device, &desc);\n}\n\n_Use_decl_annotations_\nD3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeap::WriteDescriptors(\n    ID3D12Device* device,\n    uint32_t offsetIntoHeap,\n    uint32_t totalDescriptorCount,\n    const D3D12_CPU_DESCRIPTOR_HANDLE* pDescriptorRangeStarts,\n    const uint32_t* pDescriptorRangeSizes,\n    uint32_t descriptorRangeCount)\n{\n    assert((size_t(offsetIntoHeap) + size_t(totalDescriptorCount)) <= size_t(m_desc.NumDescriptors));\n\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = GetCpuHandle(offsetIntoHeap);\n\n    device->CopyDescriptors(\n        1,\n        &cpuHandle,\n        &totalDescriptorCount,\n        descriptorRangeCount,\n        pDescriptorRangeStarts,\n        pDescriptorRangeSizes,\n        m_desc.Type);\n\n    auto gpuHandle = GetGpuHandle(offsetIntoHeap);\n\n    return gpuHandle;\n}\n\n_Use_decl_annotations_\nD3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeap::WriteDescriptors(\n    ID3D12Device* device,\n    uint32_t offsetIntoHeap,\n    const D3D12_CPU_DESCRIPTOR_HANDLE* pDescriptorRangeStarts,\n    const uint32_t* pDescriptorRangeSizes,\n    uint32_t descriptorRangeCount)\n{\n    uint32_t totalDescriptorCount = 0;\n    for (uint32_t i = 0; i < descriptorRangeCount; ++i)\n        totalDescriptorCount += pDescriptorRangeSizes[i];\n\n    return WriteDescriptors(\n        device,\n        offsetIntoHeap,\n        totalDescriptorCount,\n        pDescriptorRangeStarts,\n        pDescriptorRangeSizes,\n        descriptorRangeCount);\n}\n\n_Use_decl_annotations_\nD3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeap::WriteDescriptors(\n    ID3D12Device* device,\n    uint32_t offsetIntoHeap,\n    const D3D12_CPU_DESCRIPTOR_HANDLE* pDescriptors,\n    uint32_t descriptorCount)\n{\n    return WriteDescriptors(\n        device,\n        offsetIntoHeap,\n        descriptorCount,\n        pDescriptors,\n        &descriptorCount,\n        1);\n}\n\n_Use_decl_annotations_\nvoid DescriptorHeap::Create(\n    ID3D12Device* pDevice,\n    const D3D12_DESCRIPTOR_HEAP_DESC* pDesc)\n{\n    assert(pDesc != nullptr);\n\n    m_desc = *pDesc;\n    m_increment = pDevice->GetDescriptorHandleIncrementSize(pDesc->Type);\n\n    if (pDesc->NumDescriptors == 0)\n    {\n        m_pHeap.Reset();\n        m_hCPU.ptr = 0;\n        m_hGPU.ptr = 0;\n    }\n    else\n    {\n        ThrowIfFailed(pDevice->CreateDescriptorHeap(\n            pDesc,\n            IID_GRAPHICS_PPV_ARGS(m_pHeap.ReleaseAndGetAddressOf())));\n\n        SetDebugObjectName(m_pHeap.Get(), L\"DescriptorHeap\");\n\n        m_hCPU = m_pHeap->GetCPUDescriptorHandleForHeapStart();\n\n        if (pDesc->Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)\n            m_hGPU = m_pHeap->GetGPUDescriptorHandleForHeapStart();\n\n    }\n}\n\n_Use_decl_annotations_\nvoid DescriptorHeap::DefaultDesc(\n    D3D12_DESCRIPTOR_HEAP_TYPE type,\n    D3D12_DESCRIPTOR_HEAP_DESC* pDesc) noexcept\n{\n    assert(c_DescriptorHeapDescs[type].Type == type);\n    pDesc->Flags = c_DescriptorHeapDescs[type].Flags;\n    pDesc->NumDescriptors = 0;\n    pDesc->Type = type;\n}\n\n\n//======================================================================================\n// DescriptorPile\n//======================================================================================\n\nvoid DescriptorPile::AllocateRange(size_t numDescriptors, _Out_ IndexType& start, _Out_ IndexType& end)\n{\n    // make sure we didn't allocate zero\n    if (numDescriptors == 0)\n    {\n        throw std::out_of_range(\"Can't allocate zero descriptors\");\n    }\n\n    // get the current top\n    start = m_top;\n\n    // increment top with new request\n    m_top += numDescriptors;\n    end = m_top;\n\n    // make sure we have enough room\n    if (m_top > Count())\n    {\n        DebugTrace(\"DescriptorPile has %zu of %zu descriptors; failed request for %zu more\\n\", start, Count(), numDescriptors);\n        throw std::exception(\"Can't allocate more descriptors\");\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DirectXHelpers.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DirectXHelpers.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"DirectXHelpers.h\"\n#include \"GraphicsMemory.h\"\n#include \"PlatformHelpers.h\"\n\nusing namespace DirectX;\n\n_Use_decl_annotations_\nvoid DirectX::CreateShaderResourceView(\n    ID3D12Device* device,\n    ID3D12Resource* tex,\n    D3D12_CPU_DESCRIPTOR_HANDLE srvDescriptor,\n    bool isCubeMap)\n{\n    const auto desc = tex->GetDesc();\n\n    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};\n    srvDesc.Format = desc.Format;\n    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n\n    switch (desc.Dimension)\n    {\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            if (desc.DepthOrArraySize > 1)\n            {\n                srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;\n                srvDesc.Texture1DArray.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n                srvDesc.Texture1DArray.ArraySize = static_cast<UINT>(desc.DepthOrArraySize);\n            }\n            else\n            {\n                srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;\n                srvDesc.Texture1D.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n            if (isCubeMap)\n            {\n                if (desc.DepthOrArraySize > 6)\n                {\n                    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;\n                    srvDesc.TextureCubeArray.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n                    srvDesc.TextureCubeArray.NumCubes = static_cast<UINT>(desc.DepthOrArraySize / 6);\n                }\n                else\n                {\n                    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;\n                    srvDesc.TextureCube.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n                }\n            }\n            else if (desc.DepthOrArraySize > 1)\n            {\n                srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;\n                srvDesc.Texture2DArray.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n                srvDesc.Texture2DArray.ArraySize = static_cast<UINT>(desc.DepthOrArraySize);\n            }\n            else\n            {\n                srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n                srvDesc.Texture2D.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;\n            srvDesc.Texture3D.MipLevels = (!desc.MipLevels) ? UINT(-1) : desc.MipLevels;\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_BUFFER:\n            DebugTrace(\"ERROR: CreateShaderResourceView cannot be used with DIMENSION_BUFFER.\\n\");\n            throw std::exception(\"buffer resources not supported\");\n\n        case D3D12_RESOURCE_DIMENSION_UNKNOWN:\n        default:\n            DebugTrace(\"ERROR: CreateShaderResourceView cannot be used with DIMENSION_UNKNOWN (%d).\\n\", desc.Dimension);\n            throw std::exception(\"unknown resource dimension\");\n    }\n\n    device->CreateShaderResourceView(tex, &srvDesc, srvDescriptor);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DualPostProcess.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DualPostProcess.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"PostProcess.h\"\n\n#include \"AlignedNew.h\"\n#include \"CommonStates.h\"\n#include \"DemandCreate.h\"\n#include \"DirectXHelpers.h\"\n#include \"EffectPipelineStateDescription.h\"\n#include \"GraphicsMemory.h\"\n#include \"SharedResourcePool.h\"\n\nusing namespace DirectX;\n\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    constexpr int c_MaxSamples = 16;\n\n    constexpr int Dirty_ConstantBuffer  = 0x01;\n    constexpr int Dirty_Parameters      = 0x02;\n\n    // Constant buffer layout. Must match the shader!\n    __declspec(align(16)) struct PostProcessConstants\n    {\n        XMVECTOR sampleOffsets[c_MaxSamples];\n        XMVECTOR sampleWeights[c_MaxSamples];\n    };\n\n    static_assert((sizeof(PostProcessConstants) % 16) == 0, \"CB size not padded correctly\");\n}\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_VSQuadDual.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSMerge.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPostProcess_PSBloomCombine.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_VSQuadDual.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSMerge.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePostProcess_PSBloomCombine.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOnePostProcess_VSQuadDual.inc\"\n\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSMerge.inc\"\n    #include \"Shaders/Compiled/XboxOnePostProcess_PSBloomCombine.inc\"\n#else\n    #include \"Shaders/Compiled/PostProcess_VSQuadDual.inc\"\n\n    #include \"Shaders/Compiled/PostProcess_PSMerge.inc\"\n    #include \"Shaders/Compiled/PostProcess_PSBloomCombine.inc\"\n#endif\n}\n\nnamespace\n{\n    const D3D12_SHADER_BYTECODE vertexShader =\n        { PostProcess_VSQuadDual,       sizeof(PostProcess_VSQuadDual) };\n\n    const D3D12_SHADER_BYTECODE pixelShaders[] =\n    {\n        { PostProcess_PSMerge,          sizeof(PostProcess_PSMerge) },\n        { PostProcess_PSBloomCombine,   sizeof(PostProcess_PSBloomCombine) },\n    };\n\n    static_assert(_countof(pixelShaders) == DualPostProcess::Effect_Max, \"array/max mismatch\");\n\n    // Factory for lazily instantiating shared root signatures.\n    class DeviceResources\n    {\n    public:\n        DeviceResources(_In_ ID3D12Device* device) noexcept\n            : mDevice(device)\n        { }\n\n        ID3D12RootSignature* GetRootSignature(const D3D12_ROOT_SIGNATURE_DESC& desc)\n        {\n            return DemandCreate(mRootSignature, mMutex, [&](ID3D12RootSignature** pResult) noexcept -> HRESULT\n            {\n                HRESULT hr = CreateRootSignature(mDevice.Get(), &desc, pResult);\n\n                if (SUCCEEDED(hr))\n                    SetDebugObjectName(*pResult, L\"DualPostProcess\");\n\n                return hr;\n            });\n        }\n\n        ID3D12Device* GetDevice() const noexcept { return mDevice.Get(); }\n\n    protected:\n        ComPtr<ID3D12Device>                        mDevice;\n        Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature;\n        std::mutex                                  mMutex;\n    };\n}\n\nclass DualPostProcess::Impl : public AlignedNew<PostProcessConstants>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect ifx);\n\n    void Process(_In_ ID3D12GraphicsCommandList* commandList);\n\n    void SetDirtyFlag() noexcept { mDirtyFlags = INT_MAX; }\n\n    enum RootParameterIndex\n    {\n        TextureSRV,\n        TextureSRV2,\n        ConstantBuffer,\n        RootParameterCount\n    };\n\n    // Fields.\n    DualPostProcess::Effect                 fx;\n    PostProcessConstants                    constants;\n    D3D12_GPU_DESCRIPTOR_HANDLE             texture;\n    D3D12_GPU_DESCRIPTOR_HANDLE             texture2;\n    float                                   mergeWeight1;\n    float                                   mergeWeight2;\n    float                                   bloomIntensity;\n    float                                   bloomBaseIntensity;\n    float                                   bloomSaturation;\n    float                                   bloomBaseSaturation;\n\nprivate:\n    int                                     mDirtyFlags;\n\n   // D3D constant buffer holds a copy of the same data as the public 'constants' field.\n    GraphicsResource mConstantBuffer;\n\n    // Per instance cache of PSOs, populated with variants for each shader & layout\n    Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;\n\n    // Per instance root signature\n    ID3D12RootSignature* mRootSignature;\n\n    // Per-device resources.\n    std::shared_ptr<DeviceResources> mDeviceResources;\n\n    static SharedResourcePool<ID3D12Device*, DeviceResources> deviceResourcesPool;\n};\n\n\n// Global pool of per-device DualPostProcess resources.\nSharedResourcePool<ID3D12Device*, DeviceResources> DualPostProcess::Impl::deviceResourcesPool;\n\n\n// Constructor.\nDualPostProcess::Impl::Impl(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect ifx)\n    : fx(ifx),\n    constants{},\n    texture{},\n    texture2{},\n    mergeWeight1(0.5f),\n    mergeWeight2(0.5f),\n    bloomIntensity(1.25f),\n    bloomBaseIntensity(1.f),\n    bloomSaturation(1.f),\n    bloomBaseSaturation(1.f),\n    mDirtyFlags(INT_MAX),\n    mDeviceResources(deviceResourcesPool.DemandCreate(device))\n{\n    if (ifx >= Effect_Max)\n        throw std::out_of_range(\"Effect not defined\");\n   \n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        // Same as CommonStates::StaticLinearClamp\n        CD3DX12_STATIC_SAMPLER_DESC sampler(\n            0, // register\n            D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            0.f,\n            16,\n            D3D12_COMPARISON_FUNC_LESS_EQUAL,\n            D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n            0.f,\n            D3D12_FLOAT32_MAX,\n            D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n\n        CD3DX12_DESCRIPTOR_RANGE texture1Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &texture1Range, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_DESCRIPTOR_RANGE texture2Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);\n        rootParameters[RootParameterIndex::TextureSRV2].InitAsDescriptorTable(1, &texture2Range, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Root parameter descriptor\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n\n        // Constant buffer\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags);\n\n        mRootSignature = mDeviceResources->GetRootSignature(rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    // Create pipeline state.\n    EffectPipelineStateDescription psd(nullptr,\n        CommonStates::Opaque,\n        CommonStates::DepthNone,\n        CommonStates::CullNone,\n        rtState,\n        D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);\n\n    psd.CreatePipelineState(\n        device,\n        mRootSignature,\n        vertexShader,\n        pixelShaders[ifx],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"DualPostProcess\");\n}\n\n\n// Sets our state onto the D3D device.\nvoid DualPostProcess::Impl::Process(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Set the root signature.\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture.\n    if (!texture.ptr || !texture2.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture(s) for DualPostProcess (%llu, %llu)\\n\", texture.ptr, texture2.ptr);\n        throw std::exception(\"DualPostProcess\");\n    }\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV2, texture2);\n\n    // Set constants.\n    if (mDirtyFlags & Dirty_Parameters)\n    {\n        mDirtyFlags &= ~Dirty_Parameters;\n        mDirtyFlags |= Dirty_ConstantBuffer;\n\n        switch (fx)\n        {\n        case Merge:\n            constants.sampleWeights[0] = XMVectorReplicate(mergeWeight1);\n            constants.sampleWeights[1] = XMVectorReplicate(mergeWeight2);\n            break;\n\n        case BloomCombine:\n            constants.sampleWeights[0] = XMVectorSet(bloomBaseSaturation, bloomSaturation, 0.f, 0.f);\n            constants.sampleWeights[1] = XMVectorReplicate(bloomBaseIntensity);\n            constants.sampleWeights[2] = XMVectorReplicate(bloomIntensity);\n            break;\n\n        default:\n            break;\n        }\n    }\n\n    if (mDirtyFlags & Dirty_ConstantBuffer)\n    {\n        mDirtyFlags &= ~Dirty_ConstantBuffer;\n        mConstantBuffer = GraphicsMemory::Get(mDeviceResources->GetDevice()).AllocateConstant(constants);\n    }\n\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, mConstantBuffer.GpuAddress());\n\n    // Set the pipeline state.\n    commandList->SetPipelineState(mPipelineState.Get());\n\n    // Draw quad.\n    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n    commandList->DrawInstanced(3, 1, 0, 0);\n}\n\n\n// Public constructor.\nDualPostProcess::DualPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState, Effect fx)\n  : pImpl(std::make_unique<Impl>(device, rtState, fx))\n{\n}\n\n\n// Move constructor.\nDualPostProcess::DualPostProcess(DualPostProcess&& moveFrom) noexcept\n  : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nDualPostProcess& DualPostProcess::operator= (DualPostProcess&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nDualPostProcess::~DualPostProcess()\n{\n}\n\n\n// IPostProcess methods.\nvoid DualPostProcess::Process(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Process(commandList);\n}\n\n\n// Properties\nvoid DualPostProcess::SetSourceTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    pImpl->texture = srvDescriptor;\n}\n\n\nvoid DualPostProcess::SetSourceTexture2(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    pImpl->texture2 = srvDescriptor;\n}\n\n\nvoid DualPostProcess::SetMergeParameters(float weight1, float weight2)\n{\n    pImpl->mergeWeight1 = weight1;\n    pImpl->mergeWeight2 = weight2;\n    pImpl->SetDirtyFlag();\n}\n\n\nvoid DualPostProcess::SetBloomCombineParameters(float bloom, float base, float bloomSaturation, float baseSaturation)\n{\n    pImpl->bloomIntensity = bloom;\n    pImpl->bloomBaseIntensity = base;\n    pImpl->bloomSaturation = bloomSaturation;\n    pImpl->bloomBaseSaturation = baseSaturation;\n    pImpl->SetDirtyFlag();\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/DualTextureEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: DualTextureEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct DualTextureEffectConstants\n    {\n        XMVECTOR diffuseColor;\n        XMVECTOR fogColor;\n        XMVECTOR fogVector;\n        XMMATRIX worldViewProj;\n    };\n\n    static_assert((sizeof(DualTextureEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct DualTextureEffectTraits\n    {\n        using ConstantBufferType = DualTextureEffectConstants;\n\n        static constexpr int VertexShaderCount = 4;\n        static constexpr int PixelShaderCount = 2;\n        static constexpr int ShaderPermutationCount = 4;\n        static constexpr int RootSignatureCount = 1;\n    };\n}\n\n// Internal DualTextureEffect implementation class.\nclass DualTextureEffect::Impl : public EffectBase<DualTextureEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n    \n    enum RootParameterIndex\n    {\n        Texture1SRV,\n        Texture1Sampler,\n        Texture2SRV,\n        Texture2Sampler,\n        ConstantBuffer,\n        RootParameterCount\n    };\n\n    EffectColor color;\n\n    D3D12_GPU_DESCRIPTOR_HANDLE texture1;\n    D3D12_GPU_DESCRIPTOR_HANDLE texture1Sampler;\n    D3D12_GPU_DESCRIPTOR_HANDLE texture2;\n    D3D12_GPU_DESCRIPTOR_HANDLE texture2Sampler;\n\n    int GetPipelineStatePermutation(bool vertexColorEnabled) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettDualTextureEffect_VSDualTexture.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDualTextureEffect_VSDualTextureNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDualTextureEffect_VSDualTextureVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDualTextureEffect_VSDualTextureVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettDualTextureEffect_PSDualTexture.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettDualTextureEffect_PSDualTextureNoFog.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneDualTextureEffect_VSDualTexture.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDualTextureEffect_VSDualTextureNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDualTextureEffect_VSDualTextureVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDualTextureEffect_VSDualTextureVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneDualTextureEffect_PSDualTexture.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneDualTextureEffect_PSDualTextureNoFog.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneDualTextureEffect_VSDualTexture.inc\"\n    #include \"Shaders/Compiled/XboxOneDualTextureEffect_VSDualTextureNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneDualTextureEffect_VSDualTextureVc.inc\"\n    #include \"Shaders/Compiled/XboxOneDualTextureEffect_VSDualTextureVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneDualTextureEffect_PSDualTexture.inc\"\n    #include \"Shaders/Compiled/XboxOneDualTextureEffect_PSDualTextureNoFog.inc\"\n#else\n    #include \"Shaders/Compiled/DualTextureEffect_VSDualTexture.inc\"\n    #include \"Shaders/Compiled/DualTextureEffect_VSDualTextureNoFog.inc\"\n    #include \"Shaders/Compiled/DualTextureEffect_VSDualTextureVc.inc\"\n    #include \"Shaders/Compiled/DualTextureEffect_VSDualTextureVcNoFog.inc\"\n\n    #include \"Shaders/Compiled/DualTextureEffect_PSDualTexture.inc\"\n    #include \"Shaders/Compiled/DualTextureEffect_PSDualTextureNoFog.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<DualTextureEffectTraits>::VertexShaderBytecode[] =\n{\n    { DualTextureEffect_VSDualTexture,        sizeof(DualTextureEffect_VSDualTexture)        },\n    { DualTextureEffect_VSDualTextureNoFog,   sizeof(DualTextureEffect_VSDualTextureNoFog)   },\n    { DualTextureEffect_VSDualTextureVc,      sizeof(DualTextureEffect_VSDualTextureVc)      },\n    { DualTextureEffect_VSDualTextureVcNoFog, sizeof(DualTextureEffect_VSDualTextureVcNoFog) },\n\n};\n\n\ntemplate<>\nconst int EffectBase<DualTextureEffectTraits>::VertexShaderIndices[] =\n{\n    0,      // basic\n    1,      // no fog\n    2,      // vertex color\n    3,      // vertex color, no fog\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<DualTextureEffectTraits>::PixelShaderBytecode[] =\n{\n    { DualTextureEffect_PSDualTexture,        sizeof(DualTextureEffect_PSDualTexture)        },\n    { DualTextureEffect_PSDualTextureNoFog,   sizeof(DualTextureEffect_PSDualTextureNoFog)   },\n\n};\n\n\ntemplate<>\nconst int EffectBase<DualTextureEffectTraits>::PixelShaderIndices[] =\n{\n    0,      // basic\n    1,      // no fog\n    0,      // vertex color\n    1,      // vertex color, no fog\n};\n\n\n// Global pool of per-device DualTextureEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<DualTextureEffectTraits>::DeviceResources> EffectBase<DualTextureEffectTraits>::deviceResourcesPool = {};\n\n\n// Constructor.\nDualTextureEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : EffectBase(device),\n        texture1{},\n        texture1Sampler{},\n        texture2{},\n        texture2Sampler{}\n{\n    static_assert(_countof(EffectBase<DualTextureEffectTraits>::VertexShaderIndices) == DualTextureEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<DualTextureEffectTraits>::VertexShaderBytecode) == DualTextureEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<DualTextureEffectTraits>::PixelShaderBytecode) == DualTextureEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<DualTextureEffectTraits>::PixelShaderIndices) == DualTextureEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        // Texture 1\n        CD3DX12_DESCRIPTOR_RANGE texture1Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        CD3DX12_DESCRIPTOR_RANGE texture1SamplerRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n        rootParameters[RootParameterIndex::Texture1SRV].InitAsDescriptorTable(1, &texture1Range, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::Texture1Sampler].InitAsDescriptorTable(1, &texture1SamplerRange, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Texture 2\n        CD3DX12_DESCRIPTOR_RANGE texture2Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);\n        CD3DX12_DESCRIPTOR_RANGE texture2SamplerRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 1);\n        rootParameters[RootParameterIndex::Texture2SRV].InitAsDescriptorTable(1, &texture2Range, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::Texture2Sampler].InitAsDescriptorTable(1, &texture2SamplerRange, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Create the root signature\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n        mRootSignature = GetRootSignature(0, rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    // Validate flags & state.\n    fog.enabled = (effectFlags & EffectFlags::Fog) != 0;\n\n    if (effectFlags & EffectFlags::PerPixelLightingBit)\n    {\n        DebugTrace(\"ERROR: DualTextureEffect does not implement EffectFlags::PerPixelLighting\\n\");\n        throw std::invalid_argument(\"DualTextureEffect\");\n    }\n    else if (effectFlags & EffectFlags::Lighting)\n    {\n        DebugTrace(\"ERROR: DualTextureEffect does not implement EffectFlags::Lighting\\n\");\n        throw std::invalid_argument(\"DualTextureEffect\");\n    }\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(\n        (effectFlags & EffectFlags::VertexColor) != 0);\n    assert(sp >= 0 && sp < DualTextureEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < DualTextureEffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<DualTextureEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < DualTextureEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < DualTextureEffectTraits::VertexShaderCount);\n    int pi = EffectBase<DualTextureEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < DualTextureEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < DualTextureEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<DualTextureEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<DualTextureEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"DualTextureEffect\");\n}\n\n\nint DualTextureEffect::Impl::GetPipelineStatePermutation(bool vertexColorEnabled) const noexcept\n{\n    int permutation = 0;\n\n    // Use optimized shaders if fog is disabled.\n    if (!fog.enabled)\n    {\n        permutation += 1;\n    }\n\n    // Support vertex coloring?\n    if (vertexColorEnabled)\n    {\n        permutation += 2;\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid DualTextureEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n\n    fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector);\n\n    color.SetConstants(dirtyFlags, constants.diffuseColor);\n\n    UpdateConstants();\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the textures\n    if (!texture1.ptr || !texture2.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture(s) for DualTextureEffect (texture1 %llu, texture2 %llu)\\n\", texture1.ptr, texture2.ptr);\n        throw std::exception(\"DualTextureEffect\");\n    }\n    if (!texture1Sampler.ptr || !texture2Sampler.ptr)\n    {\n        DebugTrace(\"ERROR: Missing sampler(s) for DualTextureEffect (samplers1 %llu, samplers2 %llu)\\n\", texture2Sampler.ptr, texture2Sampler.ptr);\n        throw std::exception(\"DualTextureEffect\");\n    }\n\n    // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture1SRV, texture1);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture1Sampler, texture1Sampler);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture2SRV, texture2);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture2Sampler, texture2Sampler);\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n\n// Public constructor.\nDualTextureEffect::DualTextureEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription))\n{\n}\n\n\n// Move constructor.\nDualTextureEffect::DualTextureEffect(DualTextureEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nDualTextureEffect& DualTextureEffect::operator= (DualTextureEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nDualTextureEffect::~DualTextureEffect()\n{\n}\n\n\n// IEffect methods\nvoid DualTextureEffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings\nvoid XM_CALLCONV DualTextureEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV DualTextureEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV DualTextureEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV DualTextureEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\n// Material settings\nvoid XM_CALLCONV DualTextureEffect::SetDiffuseColor(FXMVECTOR value)\n{\n    pImpl->color.diffuseColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid DualTextureEffect::SetAlpha(float value)\n{\n    pImpl->color.alpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV DualTextureEffect::SetColorAndAlpha(FXMVECTOR value)\n{\n    pImpl->color.diffuseColor = value;\n    pImpl->color.alpha = XMVectorGetW(value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\n// Fog settings.\nvoid DualTextureEffect::SetFogStart(float value)\n{\n    pImpl->fog.start = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid DualTextureEffect::SetFogEnd(float value)\n{\n    pImpl->fog.end = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV DualTextureEffect::SetFogColor(FXMVECTOR value)\n{\n    pImpl->constants.fogColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid DualTextureEffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->texture1 = srvDescriptor;\n    pImpl->texture1Sampler = samplerDescriptor;\n}\n\n\nvoid DualTextureEffect::SetTexture2(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->texture2 = srvDescriptor;\n    pImpl->texture2Sampler = samplerDescriptor;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/EffectCommon.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: EffectCommon.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n#include \"DemandCreate.h\"\n#include \"ResourceUploadBatch.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n\n// IEffectMatrices default method\nvoid XM_CALLCONV IEffectMatrices::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    SetWorld(world);\n    SetView(view);\n    SetProjection(projection);\n}\n\n\n// Constructor initializes default matrix values.\nEffectMatrices::EffectMatrices() noexcept\n{\n    XMMATRIX id = XMMatrixIdentity();\n    world = id;\n    view = id;\n    projection = id;\n    worldView = id;\n}\n\n\n// Lazily recomputes the combined world+view+projection matrix.\n_Use_decl_annotations_ void EffectMatrices::SetConstants(int& dirtyFlags, XMMATRIX& worldViewProjConstant)\n{\n    if (dirtyFlags & EffectDirtyFlags::WorldViewProj)\n    {\n        worldView = XMMatrixMultiply(world, view);\n\n        worldViewProjConstant = XMMatrixTranspose(XMMatrixMultiply(worldView, projection));\n                \n        dirtyFlags &= ~EffectDirtyFlags::WorldViewProj;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n}\n\n\n// Constructor initializes default fog settings.\nEffectFog::EffectFog() noexcept :\n    enabled(false),\n    start(0),\n    end(1.f)\n{\n}\n\n\n// Lazily recomputes the derived vector used by shader fog calculations.\n_Use_decl_annotations_\nvoid XM_CALLCONV EffectFog::SetConstants(int& dirtyFlags, FXMMATRIX worldView, XMVECTOR& fogVectorConstant)\n{\n    if (enabled)\n    {\n        if (dirtyFlags & (EffectDirtyFlags::FogVector | EffectDirtyFlags::FogEnable))\n        {\n            if (start == end)\n            {\n                // Degenerate case: force everything to 100% fogged if start and end are the same.\n                static const XMVECTORF32 fullyFogged = { { { 0, 0, 0, 1 } } };\n\n                fogVectorConstant = fullyFogged;\n            }\n            else\n            {\n                // We want to transform vertex positions into view space, take the resulting\n                // Z value, then scale and offset according to the fog start/end distances.\n                // Because we only care about the Z component, the shader can do all this\n                // with a single dot product, using only the Z row of the world+view matrix.\n        \n                // _13, _23, _33, _43\n                XMVECTOR worldViewZ = XMVectorMergeXY(XMVectorMergeZW(worldView.r[0], worldView.r[2]),\n                                                      XMVectorMergeZW(worldView.r[1], worldView.r[3]));\n\n                // 0, 0, 0, fogStart\n                XMVECTOR wOffset = XMVectorSwizzle<1, 2, 3, 0>(XMLoadFloat(&start));\n\n                // (worldViewZ + wOffset) / (start - end);\n                fogVectorConstant = XMVectorDivide(XMVectorAdd(worldViewZ, wOffset), XMVectorReplicate(start - end));\n            }\n\n            dirtyFlags &= ~(EffectDirtyFlags::FogVector | EffectDirtyFlags::FogEnable);\n            dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n        }\n    }\n    else\n    {\n        // When fog is disabled, make sure the fog vector is reset to zero.\n        if (dirtyFlags & EffectDirtyFlags::FogEnable)\n        {\n            fogVectorConstant = g_XMZero;\n\n            dirtyFlags &= ~EffectDirtyFlags::FogEnable;\n            dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n        }\n    }\n}\n\n\n// Constructor initializes default material color settings.\nEffectColor::EffectColor() noexcept :\n    diffuseColor(g_XMOne),\n    alpha(1.f)\n{\n}\n\n\n// Lazily recomputes the material color parameter for shaders that do not support realtime lighting.\nvoid EffectColor::SetConstants(_Inout_ int& dirtyFlags, _Inout_ XMVECTOR& diffuseColorConstant)\n{\n    if (dirtyFlags & EffectDirtyFlags::MaterialColor)\n    {\n        XMVECTOR alphaVector = XMVectorReplicate(alpha);\n\n        // xyz = diffuse * alpha, w = alpha.\n        diffuseColorConstant = XMVectorSelect(alphaVector, XMVectorMultiply(diffuseColor, alphaVector), g_XMSelect1110);\n\n        dirtyFlags &= ~EffectDirtyFlags::MaterialColor;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n}\n\n\n// Constructor initializes default light settings.\nEffectLights::EffectLights() noexcept :\n    emissiveColor{},\n    ambientLightColor{},\n    lightEnabled{},\n    lightDiffuseColor{},\n    lightSpecularColor{}\n{\n    for (int i = 0; i < MaxDirectionalLights; i++)\n    {\n        lightEnabled[i] = (i == 0);\n        lightDiffuseColor[i] = g_XMOne;\n    }\n}\n\n\n#ifdef _PREFAST_\n#pragma prefast(push)\n#pragma prefast(disable:22103, \"PREFAST doesn't understand buffer is bounded by a static const value even with SAL\" )\n#endif\n\n// Initializes constant buffer fields to match the current lighting state.\n_Use_decl_annotations_ void EffectLights::InitializeConstants(XMVECTOR& specularColorAndPowerConstant, XMVECTOR* lightDirectionConstant, XMVECTOR* lightDiffuseConstant, XMVECTOR* lightSpecularConstant) const\n{\n    static const XMVECTORF32 defaultSpecular = { { { 1, 1, 1, 16 } } };\n    static const XMVECTORF32 defaultLightDirection = { { { 0, -1, 0, 0 } } };\n    \n    specularColorAndPowerConstant = defaultSpecular;\n\n    for (int i = 0; i < MaxDirectionalLights; i++)\n    {\n        lightDirectionConstant[i] = defaultLightDirection;\n\n        lightDiffuseConstant[i]  = lightEnabled[i] ? lightDiffuseColor[i]  : g_XMZero;\n        lightSpecularConstant[i] = lightEnabled[i] ? lightSpecularColor[i] : g_XMZero;\n    }\n}\n\n#ifdef _PREFAST_\n#pragma prefast(pop)\n#endif\n\n\n// Lazily recomputes derived parameter values used by shader lighting calculations.\n_Use_decl_annotations_\nvoid EffectLights::SetConstants(int& dirtyFlags, EffectMatrices const& matrices, XMMATRIX& worldConstant, XMVECTOR worldInverseTransposeConstant[3], XMVECTOR& eyePositionConstant, XMVECTOR& diffuseColorConstant, XMVECTOR& emissiveColorConstant, bool lightingEnabled)\n{\n    if (lightingEnabled)\n    {\n        // World inverse transpose matrix.\n        if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose)\n        {\n            worldConstant = XMMatrixTranspose(matrices.world);\n\n            XMMATRIX worldInverse = XMMatrixInverse(nullptr, matrices.world);\n\n            worldInverseTransposeConstant[0] = worldInverse.r[0];\n            worldInverseTransposeConstant[1] = worldInverse.r[1];\n            worldInverseTransposeConstant[2] = worldInverse.r[2];\n\n            dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose;\n            dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n        }\n\n        // Eye position vector.\n        if (dirtyFlags & EffectDirtyFlags::EyePosition)\n        {\n            XMMATRIX viewInverse = XMMatrixInverse(nullptr, matrices.view);\n        \n            eyePositionConstant = viewInverse.r[3];\n\n            dirtyFlags &= ~EffectDirtyFlags::EyePosition;\n            dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n        }\n    }\n\n    // Material color parameters. The desired lighting model is:\n    //\n    //     ((ambientLightColor + sum(diffuse directional light)) * diffuseColor) + emissiveColor\n    //\n    // When lighting is disabled, ambient and directional lights are ignored, leaving:\n    //\n    //     diffuseColor + emissiveColor\n    //\n    // For the lighting disabled case, we can save one shader instruction by precomputing\n    // diffuse+emissive on the CPU, after which the shader can use diffuseColor directly,\n    // ignoring its emissive parameter.\n    //\n    // When lighting is enabled, we can merge the ambient and emissive settings. If we\n    // set our emissive parameter to emissive+(ambient*diffuse), the shader no longer\n    // needs to bother adding the ambient contribution, simplifying its computation to:\n    //\n    //     (sum(diffuse directional light) * diffuseColor) + emissiveColor\n    //\n    // For futher optimization goodness, we merge material alpha with the diffuse\n    // color parameter, and premultiply all color values by this alpha.\n\n    if (dirtyFlags & EffectDirtyFlags::MaterialColor)\n    {\n        XMVECTOR diffuse = diffuseColor;\n        XMVECTOR alphaVector = XMVectorReplicate(alpha);\n\n        if (lightingEnabled)\n        {\n            // Merge emissive and ambient light contributions.\n            // (emissiveColor + ambientLightColor * diffuse) * alphaVector;\n            emissiveColorConstant = XMVectorMultiply(XMVectorMultiplyAdd(ambientLightColor, diffuse, emissiveColor), alphaVector);\n        }\n        else\n        {\n            // Merge diffuse and emissive light contributions.\n            diffuse = XMVectorAdd(diffuse, emissiveColor);\n        }\n\n        // xyz = diffuse * alpha, w = alpha.\n        diffuseColorConstant = XMVectorSelect(alphaVector, XMVectorMultiply(diffuse, alphaVector), g_XMSelect1110);\n\n        dirtyFlags &= ~EffectDirtyFlags::MaterialColor;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n}\n\n\n#ifdef _PREFAST_\n#pragma prefast(push)\n#pragma prefast(disable:26015, \"PREFAST doesn't understand that ValidateLightIndex bounds whichLight\" )\n#endif\n\n// Helper for turning one of the directional lights on or off.\n_Use_decl_annotations_ int EffectLights::SetLightEnabled(int whichLight, bool value, XMVECTOR* lightDiffuseConstant, XMVECTOR* lightSpecularConstant)\n{\n    ValidateLightIndex(whichLight);\n\n    if (lightEnabled[whichLight] == value)\n        return 0;\n\n    lightEnabled[whichLight] = value;\n\n    if (value)\n    {\n        // If this light is now on, store its color in the constant buffer.\n        lightDiffuseConstant[whichLight] = lightDiffuseColor[whichLight];\n        lightSpecularConstant[whichLight] = lightSpecularColor[whichLight];\n    }\n    else\n    {\n        // If the light is off, reset constant buffer colors to zero.\n        lightDiffuseConstant[whichLight] = g_XMZero;\n        lightSpecularConstant[whichLight] = g_XMZero;\n    }\n\n    return EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Helper for setting diffuse color of one of the directional lights.\n_Use_decl_annotations_\nint XM_CALLCONV EffectLights::SetLightDiffuseColor(int whichLight, FXMVECTOR value, XMVECTOR* lightDiffuseConstant)\n{\n    ValidateLightIndex(whichLight);\n\n    // Locally store the new color.\n    lightDiffuseColor[whichLight] = value;\n\n    // If this light is currently on, also update the constant buffer.\n    if (lightEnabled[whichLight])\n    {\n        lightDiffuseConstant[whichLight] = value;\n        \n        return EffectDirtyFlags::ConstantBuffer;\n    }\n\n    return 0;\n}\n\n\n// Helper for setting specular color of one of the directional lights.\n_Use_decl_annotations_\nint XM_CALLCONV EffectLights::SetLightSpecularColor(int whichLight, FXMVECTOR value, XMVECTOR* lightSpecularConstant)\n{\n    ValidateLightIndex(whichLight);\n\n    // Locally store the new color.\n    lightSpecularColor[whichLight] = value;\n\n    // If this light is currently on, also update the constant buffer.\n    if (lightEnabled[whichLight])\n    {\n        lightSpecularConstant[whichLight] = value;\n\n        return EffectDirtyFlags::ConstantBuffer;\n    }\n    \n    return 0;\n}\n\n#ifdef _PREFAST_\n#pragma prefast(pop)\n#endif\n\n\n// Parameter validation helper.\nvoid EffectLights::ValidateLightIndex(int whichLight)\n{\n    if (whichLight < 0 || whichLight >= MaxDirectionalLights)\n    {\n        throw std::out_of_range(\"whichLight parameter out of range\");\n    }\n}\n\n\n// Activates the default lighting rig (key, fill, and back lights).\nvoid EffectLights::EnableDefaultLighting(_In_ IEffectLights* effect)\n{\n    static const XMVECTORF32 defaultDirections[MaxDirectionalLights] =\n    {\n        { { { -0.5265408f, -0.5735765f, -0.6275069f, 0 } } },\n        { { {  0.7198464f,  0.3420201f,  0.6040227f, 0 } } },\n        { { {  0.4545195f, -0.7660444f,  0.4545195f, 0 } } },\n    };\n\n    static const XMVECTORF32 defaultDiffuse[MaxDirectionalLights] =\n    {\n        { { { 1.0000000f, 0.9607844f, 0.8078432f, 0 } } },\n        { { { 0.9647059f, 0.7607844f, 0.4078432f, 0 } } },\n        { { { 0.3231373f, 0.3607844f, 0.3937255f, 0 } } },\n    };\n\n    static const XMVECTORF32 defaultSpecular[MaxDirectionalLights] =\n    {\n        { { { 1.0000000f, 0.9607844f, 0.8078432f, 0 } } },\n        { { { 0.0000000f, 0.0000000f, 0.0000000f, 0 } } },\n        { { { 0.3231373f, 0.3607844f, 0.3937255f, 0 } } },\n    };\n\n    static const XMVECTORF32 defaultAmbient = { { { 0.05333332f, 0.09882354f, 0.1819608f, 0 } } };\n\n    effect->SetAmbientLightColor(defaultAmbient);\n\n    for (int i = 0; i < MaxDirectionalLights; i++)\n    {\n        effect->SetLightEnabled(i, true);\n        effect->SetLightDirection(i, defaultDirections[i]);\n        effect->SetLightDiffuseColor(i, defaultDiffuse[i]);\n        effect->SetLightSpecularColor(i, defaultSpecular[i]);\n    }\n}\n\n\n// Gets or lazily creates the specified root signature.\nID3D12RootSignature* EffectDeviceResources::DemandCreateRootSig(_Inout_ Microsoft::WRL::ComPtr<ID3D12RootSignature>& rootSig, D3D12_ROOT_SIGNATURE_DESC const& desc)\n{\n    return DemandCreate(rootSig, mMutex, [&](ID3D12RootSignature** pResult) noexcept -> HRESULT\n    {\n        HRESULT hr = CreateRootSignature(mDevice.Get(), &desc, pResult);\n\n        if (SUCCEEDED(hr))\n            SetDebugObjectName(*pResult, L\"DirectXTK:Effect\");\n\n        return hr;\n    });\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/EffectCommon.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: EffectCommon.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <memory>\n\n#include \"Effects.h\"\n#include \"PlatformHelpers.h\"\n#include \"SharedResourcePool.h\"\n#include \"AlignedNew.h\"\n#include \"DescriptorHeap.h\"\n#include \"GraphicsMemory.h\"\n#include \"DirectXHelpers.h\"\n#include \"RenderTargetState.h\"\n\n// BasicEffect, SkinnedEffect, et al, have many things in common, but also significant\n// differences (for instance, not all the effects support lighting). This header breaks\n// out common functionality into a set of helpers which can be assembled in different\n// combinations to build up whatever subset is needed by each effect.\n\n\nnamespace DirectX\n{\n    // Internal effect flags\n    namespace EffectFlags\n    {\n        constexpr int PerPixelLightingBit = 0x04;\n    }\n\n    static_assert(((EffectFlags::PerPixelLighting) & EffectFlags::PerPixelLightingBit) != 0, \"PerPixelLighting enum flags mismatch\");\n\n    // Bitfield tracks which derived parameter values need to be recomputed.\n    namespace EffectDirtyFlags\n    {\n        constexpr int ConstantBuffer        = 0x01;\n        constexpr int WorldViewProj         = 0x02;\n        constexpr int WorldInverseTranspose = 0x04;\n        constexpr int EyePosition           = 0x08;\n        constexpr int MaterialColor         = 0x10;\n        constexpr int FogVector             = 0x20;\n        constexpr int FogEnable             = 0x40;\n        constexpr int AlphaTest             = 0x80;\n    }\n\n    // Helper stores matrix parameter values, and computes derived matrices.\n    struct EffectMatrices\n    {\n        EffectMatrices() noexcept;\n\n        XMMATRIX world;\n        XMMATRIX view;\n        XMMATRIX projection;\n        XMMATRIX worldView;\n\n        void SetConstants(_Inout_ int& dirtyFlags, _Inout_ XMMATRIX& worldViewProjConstant);\n    };\n\n\n    // Helper stores the current fog settings, and computes derived shader parameters.\n    struct EffectFog\n    {\n        EffectFog() noexcept;\n\n        bool enabled;\n        float start;\n        float end;\n\n        void XM_CALLCONV SetConstants(_Inout_ int& dirtyFlags, _In_ FXMMATRIX worldView, _Inout_ XMVECTOR& fogVectorConstant);\n    };\n\n\n    // Helper stores material color settings, and computes derived parameters for shaders that do not support realtime lighting.\n    struct EffectColor\n    {\n        EffectColor() noexcept;\n\n        XMVECTOR diffuseColor;\n        float alpha;\n\n        void SetConstants(_Inout_ int& dirtyFlags, _Inout_ XMVECTOR& diffuseColorConstant);\n    };\n\n\n    // Helper stores the current light settings, and computes derived shader parameters.\n    struct EffectLights : public EffectColor\n    {\n        EffectLights() noexcept;\n\n        static constexpr int MaxDirectionalLights = IEffectLights::MaxDirectionalLights;\n\n\n        // Fields.\n        XMVECTOR emissiveColor;\n        XMVECTOR ambientLightColor;\n\n        bool lightEnabled[MaxDirectionalLights];\n        XMVECTOR lightDiffuseColor[MaxDirectionalLights];\n        XMVECTOR lightSpecularColor[MaxDirectionalLights];\n\n\n        // Methods.\n        void InitializeConstants(_Out_ XMVECTOR& specularColorAndPowerConstant, _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightDirectionConstant, _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant, _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant) const;\n        void SetConstants(_Inout_ int& dirtyFlags, _In_ EffectMatrices const& matrices, _Inout_ XMMATRIX& worldConstant, _Inout_updates_(3) XMVECTOR worldInverseTransposeConstant[3], _Inout_ XMVECTOR& eyePositionConstant, _Inout_ XMVECTOR& diffuseColorConstant, _Inout_ XMVECTOR& emissiveColorConstant, bool lightingEnabled);\n\n        int SetLightEnabled(int whichLight, bool value, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant);\n        int XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant);\n        int XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant);\n\n        static void ValidateLightIndex(int whichLight);\n        static void EnableDefaultLighting(_In_ IEffectLights* effect);\n    };\n\n    // Factory for lazily instantiating shared root signatures.\n    class EffectDeviceResources\n    {\n    public:\n        EffectDeviceResources(_In_ ID3D12Device* device) noexcept\n            : mDevice(device)\n        { }\n\n        ID3D12RootSignature* DemandCreateRootSig(_Inout_ Microsoft::WRL::ComPtr<ID3D12RootSignature>& rootSig, D3D12_ROOT_SIGNATURE_DESC const& desc);\n\n    protected:\n        Microsoft::WRL::ComPtr<ID3D12Device> mDevice;\n\n        std::mutex mMutex;\n    };\n\n    // Templated base class provides functionality common to all the built-in effects.\n    template<typename Traits>\n    class EffectBase : public AlignedNew<typename Traits::ConstantBufferType>\n    {\n    public:\n        typename Traits::ConstantBufferType constants;\n\n       // Constructor.\n        EffectBase(_In_ ID3D12Device* device)\n            : constants{},\n            dirtyFlags(INT_MAX),\n            mRootSignature(nullptr),\n            mDeviceResources(deviceResourcesPool.DemandCreate(device))\n        {\n            // Initialize the constant buffer data\n            mConstantBuffer = GraphicsMemory::Get(device).AllocateConstant(constants);\n        }\n\n        // Commits constants to the constant buffer memory\n        void UpdateConstants()\n        {\n            // Make sure the constant buffer is up to date.\n            if (dirtyFlags & EffectDirtyFlags::ConstantBuffer)\n            {\n                mConstantBuffer = GraphicsMemory::Get(mDeviceResources->GetDevice()).AllocateConstant(constants);\n\n                dirtyFlags &= ~EffectDirtyFlags::ConstantBuffer;\n            }\n        }\n\n        D3D12_GPU_VIRTUAL_ADDRESS GetConstantBufferGpuAddress() noexcept\n        {\n            return mConstantBuffer.GpuAddress();\n        }\n\n        ID3D12RootSignature* GetRootSignature(int slot, CD3DX12_ROOT_SIGNATURE_DESC const& rootSig)\n        {\n            return mDeviceResources->GetRootSignature(slot, rootSig);\n        }\n\n        // Fields.\n        EffectMatrices matrices;\n        EffectFog fog;\n        int dirtyFlags;\n\n    protected:\n        // Static arrays hold all the precompiled shader permutations.\n        static const D3D12_SHADER_BYTECODE VertexShaderBytecode[Traits::VertexShaderCount];\n        static const D3D12_SHADER_BYTECODE PixelShaderBytecode[Traits::PixelShaderCount];\n        // .. and shader entry points\n        static const int VertexShaderIndices[Traits::ShaderPermutationCount];\n        static const int PixelShaderIndices[Traits::ShaderPermutationCount];\n        // ... and vertex layout tables\n        static const D3D12_INPUT_LAYOUT_DESC VertexShaderInputLayouts[Traits::ShaderPermutationCount];\n\n        // Per instance cache of PSOs, populated with variants for each shader & layout\n        Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;\n\n        // Per instance root signature\n        ID3D12RootSignature* mRootSignature;\n\n    private:\n        // D3D constant buffer holds a copy of the same data as the public 'constants' field.\n        GraphicsResource mConstantBuffer;\n\n        // Only one of these helpers is allocated per D3D device, even if there are multiple effect instances.\n        class DeviceResources : public EffectDeviceResources\n        {\n        public:\n            DeviceResources(_In_ ID3D12Device* device) noexcept\n                : EffectDeviceResources(device),\n                mRootSignature{}\n            { }\n\n            // Gets or lazily creates the specified root signature\n            ID3D12RootSignature* GetRootSignature(int slot, D3D12_ROOT_SIGNATURE_DESC const& desc)\n            {\n                assert(slot >= 0 && slot < Traits::RootSignatureCount);\n                _Analysis_assume_(slot >= 0 && slot < Traits::RootSignatureCount);\n\n                return DemandCreateRootSig(mRootSignature[slot], desc);\n            }\n\n            ID3D12Device* GetDevice() const noexcept { return mDevice.Get(); }\n\n        private:\n            Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature[Traits::RootSignatureCount];\n        };\n\n        // Per-device resources.\n        std::shared_ptr<DeviceResources> mDeviceResources;\n\n        static SharedResourcePool<ID3D12Device*, DeviceResources> deviceResourcesPool;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/EffectFactory.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: EffectFactory.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Effects.h\"\n#include \"CommonStates.h\"\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"DescriptorHeap.h\"\n\n#include <mutex>\n\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n// Internal EffectFactory implementation class. Only one of these helpers is allocated\n// per D3D device, even if there are multiple public facing EffectFactory instances.\nclass EffectFactory::Impl\n{\npublic:\n    Impl(_In_ ID3D12Device* device, _In_ ID3D12DescriptorHeap* textureDescriptors, _In_ ID3D12DescriptorHeap* samplerDescriptors) noexcept(false)\n        : mTextureDescriptors(nullptr)\n        , mSamplerDescriptors(nullptr)\n        , mUseNormalMapEffect(true)\n        , mEnablePerPixelLighting(true)\n        , mEnableFog(false)\n        , mDevice(device)\n        , mSharing(true)\n    { \n        if (textureDescriptors)\n            mTextureDescriptors = std::make_unique<DescriptorHeap>(textureDescriptors);\n        if (samplerDescriptors)\n            mSamplerDescriptors = std::make_unique<DescriptorHeap>(samplerDescriptors);\n    }\n\n    std::shared_ptr<IEffect> CreateEffect(\n        const EffectInfo& info,\n        const EffectPipelineStateDescription& opaquePipelineState,\n        const EffectPipelineStateDescription& alphaPipelineState,\n        const D3D12_INPUT_LAYOUT_DESC& inputLayout,\n        int textureDescriptorOffset,\n        int samplerDescriptorOffset);\n\n    void ReleaseCache();\n    void SetSharing(bool enabled) noexcept { mSharing = enabled; }\n\n    std::unique_ptr<DescriptorHeap> mTextureDescriptors;\n    std::unique_ptr<DescriptorHeap> mSamplerDescriptors;\n\n    bool mUseNormalMapEffect;\n    bool mEnablePerPixelLighting;\n    bool mEnableFog;\n\nprivate:\n    ComPtr<ID3D12Device> mDevice;\n\n    using EffectCache = std::map< std::wstring, std::shared_ptr<IEffect> >;\n\n    EffectCache  mEffectCache;\n    EffectCache  mEffectCacheSkinning;\n    EffectCache  mEffectCacheDualTexture;\n    EffectCache  mEffectCacheNormalMap;\n\n    bool mSharing;\n\n    std::mutex mutex;\n};\n\n\nstd::shared_ptr<IEffect> EffectFactory::Impl::CreateEffect(\n    const EffectInfo& info,\n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    const D3D12_INPUT_LAYOUT_DESC& inputLayoutDesc,\n    int textureDescriptorOffset,\n    int samplerDescriptorOffset)\n{\n    // If textures are required, make sure we have a descriptor heap\n    if (!mTextureDescriptors && (info.diffuseTextureIndex != -1 || info.specularTextureIndex != -1 || info.normalTextureIndex != -1 || info.emissiveTextureIndex != -1))\n    {\n        DebugTrace(\"ERROR: EffectFactory created without texture descriptor heap with texture index set (diffuse %d, specular %d, normal %d, emissive %d)!\\n\",\n            info.diffuseTextureIndex, info.specularTextureIndex, info.normalTextureIndex, info.emissiveTextureIndex);\n        throw std::exception(\"EffectFactory\");\n    }\n    if (!mSamplerDescriptors && (info.samplerIndex != -1 || info.samplerIndex2 != -1))\n    {\n        DebugTrace(\"ERROR: EffectFactory created without sampler descriptor heap with sampler index set (samplerIndex %d, samplerIndex2 %d)!\\n\",\n            info.samplerIndex, info.samplerIndex2);\n        throw std::exception(\"EffectFactory\");\n    }\n\n    // If we have descriptors, make sure we have both texture and sampler descriptors\n    if ((mTextureDescriptors == nullptr) != (mSamplerDescriptors == nullptr))\n    {\n        DebugTrace(\"ERROR: A texture or sampler descriptor heap was provided, but both are required.\\n\");\n        throw std::exception(\"EffectFactory\");\n    }\n\n    // Validate the we have either both texture and sampler descriptors, or neither\n    if ((info.diffuseTextureIndex == -1) != (info.samplerIndex == -1))\n    {\n        DebugTrace(\"ERROR: Material provides either a texture or sampler, but both are required.\\n\");\n        throw std::exception(\"EffectFactory\");\n    }\n\n    int diffuseTextureIndex = (info.diffuseTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.diffuseTextureIndex + textureDescriptorOffset : -1;\n    int specularTextureIndex = (info.specularTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.specularTextureIndex + textureDescriptorOffset : -1;\n    int emissiveTextureIndex = (info.emissiveTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.emissiveTextureIndex + textureDescriptorOffset : -1;\n    int normalTextureIndex = (info.normalTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.normalTextureIndex + textureDescriptorOffset : -1;\n    int samplerIndex = (info.samplerIndex != -1 && mSamplerDescriptors != nullptr) ? info.samplerIndex + samplerDescriptorOffset : -1;\n    int samplerIndex2 = (info.samplerIndex2 != -1 && mSamplerDescriptors != nullptr) ? info.samplerIndex2 + samplerDescriptorOffset : -1;\n\n    // Modify base pipeline state\n    EffectPipelineStateDescription derivedPSD = (info.alphaValue < 1.0f) ? alphaPipelineState : opaquePipelineState;\n    derivedPSD.inputLayout = inputLayoutDesc;\n\n    std::wstring cacheName;\n    if (info.enableSkinning)\n    {\n        // SkinnedEffect\n        int effectflags = (mEnablePerPixelLighting) ? EffectFlags::PerPixelLighting : EffectFlags::Lighting;\n\n        if (mEnableFog)\n        {\n            effectflags |= EffectFlags::Fog;\n        }\n\n        if (info.biasedVertexNormals)\n        {\n            effectflags |= EffectFlags::BiasedVertexNormals;\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            uint32_t hash = derivedPSD.ComputeHash();\n            cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);\n\n            auto it = mEffectCacheSkinning.find(cacheName);\n            if (mSharing && it != mEffectCacheSkinning.end())\n            {\n                return it->second;\n            }\n        }\n\n        auto effect = std::make_shared<SkinnedEffect>(mDevice.Get(), effectflags, derivedPSD);\n\n        effect->EnableDefaultLighting();\n\n        effect->SetAlpha(info.alphaValue);\n\n        // Skinned Effect does not have an ambient material color, or per-vertex color support\n\n        XMVECTOR color = XMLoadFloat3(&info.diffuseColor);\n        effect->SetDiffuseColor(color);\n\n        if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)\n        {\n            color = XMLoadFloat3(&info.specularColor);\n            effect->SetSpecularColor(color);\n            effect->SetSpecularPower(info.specularPower);\n        }\n        else\n        {\n            effect->DisableSpecular();\n        }\n\n        if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)\n        {\n            color = XMLoadFloat3(&info.emissiveColor);\n            effect->SetEmissiveColor(color);\n        }\n\n        if (diffuseTextureIndex != -1)\n        {\n            effect->SetTexture(\n                mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),\n                mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            std::lock_guard<std::mutex> lock(mutex);\n            EffectCache::value_type v(cacheName, effect);\n            mEffectCacheSkinning.insert(v);\n        }\n\n        return std::move(effect);\n    }\n    else if (info.enableDualTexture)\n    {\n        // DualTextureEffect\n        int effectflags = EffectFlags::None;\n\n        if (mEnableFog)\n        {\n            effectflags |= EffectFlags::Fog;\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            uint32_t hash = derivedPSD.ComputeHash();\n            cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);\n\n            auto it = mEffectCacheDualTexture.find(cacheName);\n            if (mSharing && it != mEffectCacheDualTexture.end())\n            {\n                return it->second;\n            }\n        }\n\n        if (info.perVertexColor)\n        {\n            effectflags |= EffectFlags::VertexColor;\n        }\n\n        auto effect = std::make_shared<DualTextureEffect>(mDevice.Get(), effectflags, derivedPSD);\n\n        // Dual texture effect doesn't support lighting (usually it's lightmaps)\n        effect->SetAlpha(info.alphaValue);\n\n        XMVECTOR color = XMLoadFloat3(&info.diffuseColor);\n        effect->SetDiffuseColor(color);\n\n        if (diffuseTextureIndex != -1)\n        {\n            effect->SetTexture(\n                mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),\n                mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));\n        }\n\n        if (emissiveTextureIndex != -1)\n        {\n            if (samplerIndex2 == -1)\n            {\n                DebugTrace(\"ERROR: Dual-texture requires a second sampler (emissive %d)\\n\", emissiveTextureIndex);\n                throw std::exception(\"EffectFactory\");\n            }\n\n            effect->SetTexture2(\n                mTextureDescriptors->GetGpuHandle(static_cast<size_t>(emissiveTextureIndex)),\n                mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex2)));\n        }\n        else if (specularTextureIndex != -1)\n        {\n            // If there's no emissive texture specified, use the specular texture as the second texture\n            if (samplerIndex2 == -1)\n            {\n                DebugTrace(\"ERROR: Dual-texture requires a second sampler (specular %d)\\n\", specularTextureIndex);\n                throw std::exception(\"EffectFactory\");\n            }\n\n            effect->SetTexture2(\n                mTextureDescriptors->GetGpuHandle(static_cast<size_t>(specularTextureIndex)),\n                mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex2)));\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            std::lock_guard<std::mutex> lock(mutex);\n            EffectCache::value_type v(cacheName, effect);\n            mEffectCacheDualTexture.insert(v);\n        }\n\n        return std::move(effect);\n    }\n    else if (info.enableNormalMaps && mUseNormalMapEffect)\n    {\n        // NormalMapEffect\n        int effectflags = EffectFlags::None;\n\n        if (mEnableFog)\n        {\n            effectflags |= EffectFlags::Fog;\n        }\n\n        if (info.perVertexColor)\n        {\n            effectflags |= EffectFlags::VertexColor;\n        }\n\n        if (info.biasedVertexNormals)\n        {\n            effectflags |= EffectFlags::BiasedVertexNormals;\n        }\n\n        if (specularTextureIndex != -1)\n        {\n            effectflags |= EffectFlags::Specular;\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            uint32_t hash = derivedPSD.ComputeHash();\n            cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);\n\n            auto it = mEffectCacheNormalMap.find(cacheName);\n            if (mSharing && it != mEffectCacheNormalMap.end())\n            {\n                return it->second;\n            }\n        }\n\n        auto effect = std::make_shared<NormalMapEffect>(mDevice.Get(), effectflags, derivedPSD);\n\n        effect->EnableDefaultLighting();\n\n        effect->SetAlpha(info.alphaValue);\n\n        // NormalMap Effect does not have an ambient material color\n\n        XMVECTOR color = XMLoadFloat3(&info.diffuseColor);\n        effect->SetDiffuseColor(color);\n\n        if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)\n        {\n            color = XMLoadFloat3(&info.specularColor);\n            effect->SetSpecularColor(color);\n            effect->SetSpecularPower(info.specularPower);\n        }\n        else\n        {\n            effect->DisableSpecular();\n        }\n\n        if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)\n        {\n            color = XMLoadFloat3(&info.emissiveColor);\n            effect->SetEmissiveColor(color);\n        }\n\n        if (diffuseTextureIndex != -1)\n        {\n            effect->SetTexture(\n                mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),\n                mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));\n        }\n\n        if (specularTextureIndex != -1)\n        {\n            effect->SetSpecularTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(specularTextureIndex)));\n        }\n\n        if (normalTextureIndex != -1)\n        {\n            effect->SetNormalTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(normalTextureIndex)));\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            std::lock_guard<std::mutex> lock(mutex);\n            EffectCache::value_type v(cacheName, effect);\n            mEffectCacheNormalMap.insert(v);\n        }\n\n        return std::move(effect);\n    }\n    else\n    {\n        // set effect flags for creation\n        int effectflags = (mEnablePerPixelLighting) ? EffectFlags::PerPixelLighting : EffectFlags::Lighting;\n\n        if (mEnableFog)\n        {\n            effectflags |= EffectFlags::Fog;\n        }\n\n        if (info.perVertexColor)\n        {\n            effectflags |= EffectFlags::VertexColor;\n        }\n\n        if (diffuseTextureIndex != -1)\n        {\n            effectflags |= EffectFlags::Texture;\n        }\n\n        if (info.biasedVertexNormals)\n        {\n            effectflags |= EffectFlags::BiasedVertexNormals;\n        }\n\n        // BasicEffect\n        if (mSharing && !info.name.empty())\n        {\n            uint32_t hash = derivedPSD.ComputeHash();\n            cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);\n\n            auto it = mEffectCache.find(cacheName);\n            if (mSharing && it != mEffectCache.end())\n            {\n                return it->second;\n            }\n        }\n\n        auto effect = std::make_shared<BasicEffect>(mDevice.Get(), effectflags, derivedPSD);\n\n        effect->EnableDefaultLighting();\n\n        effect->SetAlpha(info.alphaValue);\n\n        // Basic Effect does not have an ambient material color\n        XMVECTOR color = XMLoadFloat3(&info.diffuseColor);\n        effect->SetDiffuseColor(color);\n\n        if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)\n        {\n            color = XMLoadFloat3(&info.specularColor);\n            effect->SetSpecularColor(color);\n            effect->SetSpecularPower(info.specularPower);\n        }\n        else\n        {\n            effect->DisableSpecular();\n        }\n\n        if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)\n        {\n            color = XMLoadFloat3(&info.emissiveColor);\n            effect->SetEmissiveColor(color);\n        }\n\n        if (diffuseTextureIndex != -1)\n        {\n            effect->SetTexture(\n                mTextureDescriptors->GetGpuHandle(static_cast<size_t>(diffuseTextureIndex)),\n                mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));\n        }\n\n        if (mSharing && !info.name.empty())\n        {\n            std::lock_guard<std::mutex> lock(mutex);\n            EffectCache::value_type v(cacheName, effect);\n            mEffectCache.insert(v);\n        }\n\n        return std::move(effect);\n    }\n}\n\nvoid EffectFactory::Impl::ReleaseCache()\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    mEffectCache.clear();\n    mEffectCacheSkinning.clear();\n    mEffectCacheDualTexture.clear();\n    mEffectCacheNormalMap.clear();\n}\n\n\n\n//--------------------------------------------------------------------------------------\n// EffectFactory\n//--------------------------------------------------------------------------------------\n\nEffectFactory::EffectFactory(_In_ ID3D12Device* device)\n{\n    pImpl = std::make_shared<Impl>(device, nullptr, nullptr);\n}\n\nEffectFactory::EffectFactory(_In_ ID3D12DescriptorHeap* textureDescriptors, _In_ ID3D12DescriptorHeap* samplerDescriptors)\n{\n    if (!textureDescriptors)\n    {\n        throw std::exception(\"Texture descriptor heap cannot be null if no device is provided. Use the alternative EffectFactory constructor instead.\");\n    }\n    if (!samplerDescriptors)\n    {\n        throw std::exception(\"Descriptor heap cannot be null if no device is provided. Use the alternative EffectFactory constructor instead.\");\n    }\n\n    if (textureDescriptors->GetDesc().Type != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)\n    {\n        throw std::exception(\"EffectFactory::CreateEffect requires a CBV_SRV_UAV descriptor heap for textureDescriptors.\");\n    }\n    if (samplerDescriptors->GetDesc().Type != D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)\n    {\n        throw std::exception(\"EffectFactory::CreateEffect requires a SAMPLER descriptor heap for samplerDescriptors.\");\n    }\n\n    ComPtr<ID3D12Device> device;\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    textureDescriptors->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()));\n#else\n    HRESULT hresult = textureDescriptors->GetDevice(IID_PPV_ARGS(device.GetAddressOf()));\n    if (FAILED(hresult))\n    {\n        throw com_exception(hresult);\n    }\n#endif\n\n    pImpl = std::make_shared<Impl>(device.Get(), textureDescriptors, samplerDescriptors);\n}\n\nEffectFactory::~EffectFactory()\n{\n}\n\n\nEffectFactory::EffectFactory(EffectFactory&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\nEffectFactory& EffectFactory::operator= (EffectFactory&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\nstd::shared_ptr<IEffect> EffectFactory::CreateEffect(\n    const EffectInfo& info, \n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    const D3D12_INPUT_LAYOUT_DESC& inputLayout, \n    int textureDescriptorOffset,\n    int samplerDescriptorOffset)\n{\n    return pImpl->CreateEffect(info, opaquePipelineState, alphaPipelineState, inputLayout, textureDescriptorOffset, samplerDescriptorOffset);\n}\n\nvoid EffectFactory::ReleaseCache()\n{\n    pImpl->ReleaseCache();\n}\n\nvoid EffectFactory::SetSharing(bool enabled) noexcept\n{\n    pImpl->SetSharing(enabled);\n}\n\nvoid EffectFactory::EnablePerPixelLighting(bool enabled) noexcept\n{\n    pImpl->mEnablePerPixelLighting = enabled;\n}\n\nvoid EffectFactory::EnableFogging(bool enabled) noexcept\n{\n    pImpl->mEnableFog = enabled;\n}\n\nvoid EffectFactory::EnableNormalMapEffect(bool enabled) noexcept\n{\n    pImpl->mUseNormalMapEffect = enabled;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/EffectPipelineStateDescription.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: EffectPipelineStateDescription.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectPipelineStateDescription.h\"\n\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n\n\nusing namespace DirectX;\n\nnamespace\n{\n    // 0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet\n    static const uint32_t s_crc32[] =\n    {\n        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\n        0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\n        0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\n        0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n        0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n        0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\n        0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\n        0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\n        0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\n        0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n        0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\n        0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n        0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\n        0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n        0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\n        0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\n        0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n        0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\n        0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\n        0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\n        0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\n        0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\n        0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\n        0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n        0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\n        0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\n        0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\n        0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\n        0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,\n    };\n}\n\n\nuint32_t EffectPipelineStateDescription::ComputeHash() const noexcept\n{\n    // Computes a CRC32 of the structure\n    uint32_t crc = 0xFFFFFFFF;\n\n    // Ignores the input layout which contains pointers\n    auto ptr = reinterpret_cast<const uint8_t*>(this) + sizeof(D3D12_INPUT_LAYOUT_DESC);\n    for (size_t j = 0; j < (sizeof(EffectPipelineStateDescription) - sizeof(D3D12_INPUT_LAYOUT_DESC)); ++j)\n    {\n        crc = (crc >> 8) ^ s_crc32[(crc & 0xff) ^ *ptr++];\n    }\n\n    return crc ^ 0xFFFFFFFF;\n}\n\n\nvoid EffectPipelineStateDescription::CreatePipelineState(\n    _In_ ID3D12Device* device,\n    _In_ ID3D12RootSignature* rootSignature,\n    const D3D12_SHADER_BYTECODE& vertexShader,\n    const D3D12_SHADER_BYTECODE& pixelShader,\n    _Outptr_ ID3D12PipelineState** pPipelineState) const\n{\n    auto psoDesc = GetDesc();\n    psoDesc.pRootSignature = rootSignature;\n    psoDesc.VS = vertexShader;\n    psoDesc.PS = pixelShader;\n\n    HRESULT hr = device->CreateGraphicsPipelineState(\n        &psoDesc,\n        IID_GRAPHICS_PPV_ARGS(pPipelineState));\n\n    if (FAILED(hr))\n    { \n        DebugTrace(\"ERROR: CreatePipelineState failed to create a PSO. Enable the Direct3D Debug Layer for more information (%08X)\\n\", static_cast<unsigned int>(hr));\n        throw std::exception(\"CreateGraphicsPipelineState\");\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/EffectTextureFactory.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: EffectTextureFactory.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"Effects.h\"\n#include \"DirectXHelpers.h\"\n#include \"DDSTextureLoader.h\"\n#include \"DescriptorHeap.h\"\n#include \"PlatformHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"WICTextureLoader.h\"\n\n#include <mutex>\n\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n\nclass EffectTextureFactory::Impl\n{\npublic:\n    struct TextureCacheEntry\n    {\n        ComPtr<ID3D12Resource> mResource;\n        bool mIsCubeMap;\n        size_t slot;\n\n        TextureCacheEntry() noexcept : mIsCubeMap(false), slot(0) {}\n    };\n\n    using TextureCache = std::map< std::wstring, TextureCacheEntry >;\n\n    Impl(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUploadBatch,\n        _In_ ID3D12DescriptorHeap* descriptorHeap)\n        : mPath{}\n        , mTextureDescriptorHeap(descriptorHeap)\n        , mDevice(device)\n        , mResourceUploadBatch(resourceUploadBatch)\n        , mSharing(true)\n        , mForceSRGB(false)\n        , mAutoGenMips(false)\n    { \n        *mPath = 0; \n    }\n\n    Impl(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUploadBatch,\n        _In_ size_t numDescriptors,\n        _In_ D3D12_DESCRIPTOR_HEAP_FLAGS descriptorHeapFlags)\n        : mPath{}\n        , mTextureDescriptorHeap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, descriptorHeapFlags, numDescriptors)\n        , mDevice(device)\n        , mResourceUploadBatch(resourceUploadBatch)\n        , mSharing(true)\n        , mForceSRGB(false)\n        , mAutoGenMips(false)\n    {\n        SetDebugObjectName(mTextureDescriptorHeap.Heap(), L\"EffectTextureFactory\");\n    }\n\n    size_t CreateTexture(_In_z_ const wchar_t* name, int descriptorSlot);\n\n    void ReleaseCache();\n    void SetSharing(bool enabled) noexcept { mSharing = enabled; }\n    void EnableForceSRGB(bool forceSRGB) noexcept { mForceSRGB = forceSRGB; }\n    void EnableAutoGenMips(bool generateMips) noexcept { mAutoGenMips = generateMips; }\n\n    wchar_t mPath[MAX_PATH];\n\n    ::DescriptorHeap               mTextureDescriptorHeap;\n    std::vector<TextureCacheEntry> mResources; // flat list of unique resources so we can index into it\n\nprivate:\n    ComPtr<ID3D12Device>           mDevice;\n    ResourceUploadBatch&           mResourceUploadBatch;\n\n    TextureCache                   mTextureCache;\n\n    bool                           mSharing;\n    bool                           mForceSRGB;\n    bool                           mAutoGenMips;\n\n    std::mutex                     mutex;\n};\n\n\n_Use_decl_annotations_\nsize_t EffectTextureFactory::Impl::CreateTexture(_In_z_ const wchar_t* name, int descriptorSlot)\n{\n    if (!name)\n        throw std::exception(\"invalid arguments\");\n\n    auto it = mTextureCache.find(name);\n\n    TextureCacheEntry textureEntry = {};\n\n    if (mSharing && it != mTextureCache.end())\n    {\n        textureEntry = it->second;\n    }\n    else\n    {\n        wchar_t fullName[MAX_PATH] = {};\n        wcscpy_s(fullName, mPath);\n        wcscat_s(fullName, name);\n\n        WIN32_FILE_ATTRIBUTE_DATA fileAttr = {};\n        if (!GetFileAttributesExW(fullName, GetFileExInfoStandard, &fileAttr))\n        {\n            // Try Current Working Directory (CWD)\n            wcscpy_s(fullName, name);\n            if (!GetFileAttributesExW(fullName, GetFileExInfoStandard, &fileAttr))\n            {\n                DebugTrace(\"ERROR: EffectTextureFactory could not find texture file '%ls'\\n\", name);\n                throw std::exception(\"CreateTexture\");\n            }\n        }\n\n        wchar_t ext[_MAX_EXT];\n        _wsplitpath_s(name, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT);\n\n        DDS_LOADER_FLAGS loadFlags = DDS_LOADER_DEFAULT;\n        if (mForceSRGB)\n            loadFlags |= DDS_LOADER_FORCE_SRGB;\n        if (mAutoGenMips)\n            loadFlags |= DDS_LOADER_MIP_AUTOGEN;\n\n        static_assert(static_cast<int>(DDS_LOADER_DEFAULT) == static_cast<int>(WIC_LOADER_DEFAULT), \"DDS/WIC Load flags mismatch\");\n        static_assert(static_cast<int>(DDS_LOADER_FORCE_SRGB) == static_cast<int>(WIC_LOADER_FORCE_SRGB), \"DDS/WIC Load flags mismatch\");\n        static_assert(static_cast<int>(DDS_LOADER_MIP_AUTOGEN) == static_cast<int>(WIC_LOADER_MIP_AUTOGEN), \"DDS/WIC Load flags mismatch\");\n        static_assert(static_cast<int>(DDS_LOADER_MIP_RESERVE) == static_cast<int>(WIC_LOADER_MIP_RESERVE), \"DDS/WIC Load flags mismatch\");\n\n        if (_wcsicmp(ext, L\".dds\") == 0)\n        {\n            HRESULT hr = CreateDDSTextureFromFileEx(\n                mDevice.Get(),\n                mResourceUploadBatch,\n                fullName,\n                0u,\n                D3D12_RESOURCE_FLAG_NONE,\n                loadFlags,\n                textureEntry.mResource.ReleaseAndGetAddressOf(),\n                nullptr,\n                &textureEntry.mIsCubeMap);\n            if (FAILED(hr))\n            {\n                DebugTrace(\"ERROR: CreateDDSTextureFromFile failed (%08X) for '%ls'\\n\",\n                    static_cast<unsigned int>(hr), fullName);\n                throw std::exception(\"CreateDDSTextureFromFile\");\n            }\n        }\n        else\n        {\n            textureEntry.mIsCubeMap = false;\n\n            HRESULT hr = CreateWICTextureFromFileEx(\n                mDevice.Get(),\n                mResourceUploadBatch,\n                fullName,\n                0u,\n                D3D12_RESOURCE_FLAG_NONE,\n                static_cast<WIC_LOADER_FLAGS>(loadFlags),\n                textureEntry.mResource.ReleaseAndGetAddressOf());\n            if (FAILED(hr))\n            {\n                DebugTrace(\"ERROR: CreateWICTextureFromFile failed (%08X) for '%ls'\\n\",\n                    static_cast<unsigned int>(hr), fullName);\n                throw std::exception(\"CreateWICTextureFromFile\");\n            }\n        }\n\n        std::lock_guard<std::mutex> lock(mutex);\n        textureEntry.slot = mResources.size();\n        if (mSharing)\n        {\n            TextureCache::value_type v(name, textureEntry);\n            mTextureCache.insert(v);\n        }\n        mResources.push_back(textureEntry);\n    }\n\n    assert(textureEntry.mResource != nullptr);\n\n    // bind a new descriptor in slot \n    auto textureDescriptor = mTextureDescriptorHeap.GetCpuHandle(static_cast<size_t>(descriptorSlot));\n    DirectX::CreateShaderResourceView(mDevice.Get(), textureEntry.mResource.Get(), textureDescriptor, textureEntry.mIsCubeMap);\n\n    return textureEntry.slot;\n}\n\nvoid EffectTextureFactory::Impl::ReleaseCache()\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    mTextureCache.clear();\n}\n\n\n\n//--------------------------------------------------------------------------------------\n// EffectTextureFactory\n//--------------------------------------------------------------------------------------\n\n_Use_decl_annotations_\nEffectTextureFactory::EffectTextureFactory(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUploadBatch,\n    ID3D12DescriptorHeap* descriptorHeap) noexcept(false)\n{\n    pImpl = std::make_unique<Impl>(device, resourceUploadBatch, descriptorHeap);\n}\n\n_Use_decl_annotations_\nEffectTextureFactory::EffectTextureFactory(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUploadBatch,\n    size_t numDescriptors,\n    D3D12_DESCRIPTOR_HEAP_FLAGS descriptorHeapFlags) noexcept(false)\n{\n    pImpl = std::make_unique<Impl>(device, resourceUploadBatch, numDescriptors, descriptorHeapFlags);\n}\n\nEffectTextureFactory::~EffectTextureFactory()\n{\n}\n\n\nEffectTextureFactory::EffectTextureFactory(EffectTextureFactory&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\nEffectTextureFactory& EffectTextureFactory::operator= (EffectTextureFactory&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n_Use_decl_annotations_\nsize_t EffectTextureFactory::CreateTexture(_In_z_ const wchar_t* name, int descriptorIndex)\n{\n    return pImpl->CreateTexture(name, descriptorIndex);\n}\n\nvoid EffectTextureFactory::ReleaseCache()\n{\n    pImpl->ReleaseCache();\n}\n\nvoid EffectTextureFactory::SetSharing(bool enabled) noexcept\n{\n    pImpl->SetSharing(enabled);\n}\n\nvoid EffectTextureFactory::EnableForceSRGB(bool forceSRGB) noexcept\n{\n    pImpl->EnableForceSRGB(forceSRGB);\n}\n\nvoid EffectTextureFactory::EnableAutoGenMips(bool generateMips) noexcept\n{\n    pImpl->EnableAutoGenMips(generateMips);\n}\n\nvoid EffectTextureFactory::SetDirectory(_In_opt_z_ const wchar_t* path) noexcept\n{\n    if (path && *path != 0)\n    {\n        wcscpy_s(pImpl->mPath, path);\n        size_t len = wcsnlen(pImpl->mPath, MAX_PATH);\n        if (len > 0 && len < (MAX_PATH - 1))\n        {\n            // Ensure it has a trailing slash\n            if (pImpl->mPath[len - 1] != L'\\\\')\n            {\n                pImpl->mPath[len] = L'\\\\';\n                pImpl->mPath[len + 1] = 0;\n            }\n        }\n    }\n    else\n        *pImpl->mPath = 0;\n}\n\nID3D12DescriptorHeap* EffectTextureFactory::Heap() const noexcept\n{\n    return pImpl->mTextureDescriptorHeap.Heap();\n}\n\n// Shorthand accessors for the descriptor heap\nD3D12_CPU_DESCRIPTOR_HANDLE EffectTextureFactory::GetCpuDescriptorHandle(size_t index) const\n{\n    return pImpl->mTextureDescriptorHeap.GetCpuHandle(index);\n}\n\nD3D12_GPU_DESCRIPTOR_HANDLE EffectTextureFactory::GetGpuDescriptorHandle(size_t index) const\n{\n    return pImpl->mTextureDescriptorHeap.GetGpuHandle(index);\n}\n\nsize_t EffectTextureFactory::ResourceCount() const noexcept\n{\n    return pImpl->mResources.size();\n}\n\n_Use_decl_annotations_\nvoid EffectTextureFactory::GetResource(size_t slot, ID3D12Resource** resource, bool* isCubeMap)\n{\n    if (slot >= pImpl->mResources.size())\n        throw std::exception(\"Accessing resource out of range.\");\n\n    const auto& textureEntry = pImpl->mResources[slot];\n\n    textureEntry.mResource.CopyTo(resource);\n\n    if (isCubeMap)\n    {\n        *isCubeMap = textureEntry.mIsCubeMap;\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/EnvironmentMapEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: EnvironmentMapEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct EnvironmentMapEffectConstants\n    {\n        XMVECTOR environmentMapSpecular;\n        float environmentMapAmount;\n        float fresnelFactor;\n        float pad[2];\n\n        XMVECTOR diffuseColor;\n        XMVECTOR emissiveColor;\n\n        XMVECTOR lightDirection[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightDiffuseColor[IEffectLights::MaxDirectionalLights];\n\n        XMVECTOR eyePosition;\n\n        XMVECTOR fogColor;\n        XMVECTOR fogVector;\n\n        XMMATRIX world;\n        XMVECTOR worldInverseTranspose[3];\n        XMMATRIX worldViewProj;\n    };\n\n    static_assert((sizeof(EnvironmentMapEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct EnvironmentMapEffectTraits\n    {\n        using ConstantBufferType = EnvironmentMapEffectConstants;\n\n        static constexpr int VertexShaderCount = 6;\n        static constexpr int PixelShaderCount = 16;\n        static constexpr int ShaderPermutationCount = 40;\n        static constexpr int RootSignatureCount = 1;\n    };\n}\n\n// Internal EnvironmentMapEffect implementation class.\nclass EnvironmentMapEffect::Impl : public EffectBase<EnvironmentMapEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device,\n         uint32_t effectFlags,\n         const EffectPipelineStateDescription& pipelineDescription,\n         EnvironmentMapEffect::Mapping mapping);\n\n    enum RootParameterIndex\n    {\n        TextureSRV,\n        TextureSampler,\n        CubemapSRV,\n        CubemapSampler,\n        ConstantBuffer,\n        RootParameterCount\n    };\n\n    EffectLights lights;\n\n    D3D12_GPU_DESCRIPTOR_HANDLE texture;\n    D3D12_GPU_DESCRIPTOR_HANDLE textureSampler;\n    D3D12_GPU_DESCRIPTOR_HANDLE environmentMap;\n    D3D12_GPU_DESCRIPTOR_HANDLE environmentMapSampler;\n\n    int GetPipelineStatePermutation(EnvironmentMapEffect::Mapping mapping, uint32_t effectFlags) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_VSEnvMap.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_VSEnvMapFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_VSEnvMapPixelLighting.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_VSEnvMapBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_VSEnvMapFresnelBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_VSEnvMapPixelLightingBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMap.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapSpecular.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapSpecularNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapPixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapSpherePixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapSpherePixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapDualParabolaPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnelNoFog.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_VSEnvMap.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_VSEnvMapFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_VSEnvMapPixelLighting.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_VSEnvMapBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_VSEnvMapFresnelBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_VSEnvMapPixelLightingBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMap.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapSpecular.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapSpecularNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapPixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnelNoFog.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_VSEnvMap.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_VSEnvMapFresnel.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_VSEnvMapPixelLighting.inc\"\n\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_VSEnvMapBn.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_VSEnvMapFresnelBn.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_VSEnvMapPixelLightingBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMap.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapSpecular.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapSpecularNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapPixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/XboxOneEnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnelNoFog.inc\"\n#else\n    #include \"Shaders/Compiled/EnvironmentMapEffect_VSEnvMap.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_VSEnvMapFresnel.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_VSEnvMapPixelLighting.inc\"\n\n    #include \"Shaders/Compiled/EnvironmentMapEffect_VSEnvMapBn.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_VSEnvMapFresnelBn.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_VSEnvMapPixelLightingBn.inc\"\n\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMap.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapNoFog.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapSpecular.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapSpecularNoFog.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapPixelLighting.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapPixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapSpherePixelLighting.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapSpherePixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnelNoFog.inc\"\n\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapDualParabolaPixelLighting.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingNoFog.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnel.inc\"\n    #include \"Shaders/Compiled/EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnelNoFog.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<EnvironmentMapEffectTraits>::VertexShaderBytecode[] =\n{\n    { EnvironmentMapEffect_VSEnvMap,                sizeof(EnvironmentMapEffect_VSEnvMap)                },\n    { EnvironmentMapEffect_VSEnvMapFresnel,         sizeof(EnvironmentMapEffect_VSEnvMapFresnel)         },\n    { EnvironmentMapEffect_VSEnvMapPixelLighting,   sizeof(EnvironmentMapEffect_VSEnvMapPixelLighting)   },\n\n    { EnvironmentMapEffect_VSEnvMapBn,              sizeof(EnvironmentMapEffect_VSEnvMapBn)              },\n    { EnvironmentMapEffect_VSEnvMapFresnelBn,       sizeof(EnvironmentMapEffect_VSEnvMapFresnelBn)       },\n    { EnvironmentMapEffect_VSEnvMapPixelLightingBn, sizeof(EnvironmentMapEffect_VSEnvMapPixelLightingBn) },\n};\n\n\ntemplate<>\nconst int EffectBase<EnvironmentMapEffectTraits>::VertexShaderIndices[] =\n{\n    0,      // basic\n    0,      // basic, no fog\n    1,      // fresnel\n    1,      // fresnel, no fog\n    0,      // specular\n    0,      // specular, no fog\n    1,      // fresnel + specular\n    1,      // fresnel + specular, no fog\n\n    2,      // pixel lighting\n    2,      // pixel lighting, no fog\n    2,      // pixel lighting, fresnel\n    2,      // pixel lighting, fresnel, no fog\n\n    3,      // basic (biased vertex normals)\n    3,      // basic (biased vertex normals), no fog\n    4,      // fresnel (biased vertex normals)\n    4,      // fresnel (biased vertex normals), no fog\n    3,      // specular (biased vertex normals)\n    3,      // specular (biased vertex normals), no fog\n    4,      // fresnel + specular (biased vertex normals)\n    4,      // fresnel + specular (biased vertex normals), no fog\n\n    5,      // pixel lighting (biased vertex normals)\n    5,      // pixel lighting (biased vertex normals), no fog\n    5,      // pixel lighting (biased vertex normals), fresnel\n    5,      // pixel lighting (biased vertex normals), fresnel, no fog\n\n    2,      // spheremap pixel lighting\n    2,      // spheremap pixel lighting, no fog\n    2,      // spheremap pixel lighting, fresnel\n    2,      // spheremap pixel lighting, fresnel, no fog\n\n    5,      // spheremap pixel lighting (biased vertex normals)\n    5,      // spheremap pixel lighting (biased vertex normals), no fog\n    5,      // spheremap pixel lighting (biased vertex normals), fresnel\n    5,      // spheremap pixel lighting (biased vertex normals), fresnel, no fog\n\n    2,      // dual-parabola pixel lighting\n    2,      // dual-parabola pixel lighting, no fog\n    2,      // dual-parabola pixel lighting, fresnel\n    2,      // dual-parabola pixel lighting, fresnel, no fog\n\n    5,      // dual-parabola pixel lighting (biased vertex normals)\n    5,      // dual-parabola pixel lighting (biased vertex normals), no fog\n    5,      // dual-parabola pixel lighting (biased vertex normals), fresnel\n    5,      // dual-parabola pixel lighting (biased vertex normals), fresnel, no fog\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<EnvironmentMapEffectTraits>::PixelShaderBytecode[] =\n{\n    { EnvironmentMapEffect_PSEnvMap,                          sizeof(EnvironmentMapEffect_PSEnvMap)                          },\n    { EnvironmentMapEffect_PSEnvMapNoFog,                     sizeof(EnvironmentMapEffect_PSEnvMapNoFog)                     },\n    { EnvironmentMapEffect_PSEnvMapSpecular,                  sizeof(EnvironmentMapEffect_PSEnvMapSpecular)                  },\n    { EnvironmentMapEffect_PSEnvMapSpecularNoFog,             sizeof(EnvironmentMapEffect_PSEnvMapSpecularNoFog)             },\n    { EnvironmentMapEffect_PSEnvMapPixelLighting,             sizeof(EnvironmentMapEffect_PSEnvMapPixelLighting)             },\n    { EnvironmentMapEffect_PSEnvMapPixelLightingNoFog,        sizeof(EnvironmentMapEffect_PSEnvMapPixelLightingNoFog)        },\n    { EnvironmentMapEffect_PSEnvMapPixelLightingFresnel,      sizeof(EnvironmentMapEffect_PSEnvMapPixelLightingFresnel)      },\n    { EnvironmentMapEffect_PSEnvMapPixelLightingFresnelNoFog, sizeof(EnvironmentMapEffect_PSEnvMapPixelLightingFresnelNoFog) },\n\n    { EnvironmentMapEffect_PSEnvMapSpherePixelLighting,             sizeof(EnvironmentMapEffect_PSEnvMapSpherePixelLighting) },\n    { EnvironmentMapEffect_PSEnvMapSpherePixelLightingNoFog,        sizeof(EnvironmentMapEffect_PSEnvMapSpherePixelLightingNoFog) },\n    { EnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnel,      sizeof(EnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnel) },\n    { EnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnelNoFog, sizeof(EnvironmentMapEffect_PSEnvMapSpherePixelLightingFresnelNoFog) },\n\n    { EnvironmentMapEffect_PSEnvMapDualParabolaPixelLighting,             sizeof(EnvironmentMapEffect_PSEnvMapDualParabolaPixelLighting) },\n    { EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingNoFog,        sizeof(EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingNoFog) },\n    { EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnel,      sizeof(EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnel) },\n    { EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnelNoFog, sizeof(EnvironmentMapEffect_PSEnvMapDualParabolaPixelLightingFresnelNoFog) },\n};\n\n\ntemplate<>\nconst int EffectBase<EnvironmentMapEffectTraits>::PixelShaderIndices[] =\n{\n    0,      // basic\n    1,      // basic, no fog\n    0,      // fresnel\n    1,      // fresnel, no fog\n    2,      // specular\n    3,      // specular, no fog\n    2,      // fresnel + specular\n    3,      // fresnel + specular, no fog\n\n    4,      // per pixel lighting\n    5,      // per pixel lighting, no fog\n    6,      // per pixel lighting, fresnel\n    7,      // per pixel lighting, fresnel, no fog\n\n    0,      // basic (biased vertex normals)\n    1,      // basic (biased vertex normals), no fog\n    0,      // fresnel (biased vertex normals)\n    1,      // fresnel (biased vertex normals), no fog\n    2,      // specular (biased vertex normals)\n    3,      // specular (biased vertex normals), no fog\n    2,      // fresnel + specular (biased vertex normals)\n    3,      // fresnel + specular (biased vertex normals), no fog\n\n    4,      // per pixel lighting (biased vertex normals)\n    5,      // per pixel lighting (biased vertex normals), no fog\n    6,      // per pixel lighting (biased vertex normals), fresnel\n    7,      // per pixel lighting (biased vertex normals), fresnel, no fog\n\n    8,      // spheremap pixel lighting\n    9,      // spheremap pixel lighting, no fog\n    10,     // spheremap pixel lighting, fresnel\n    11,     // spheremap pixel lighting, fresnel, no fog\n\n    8,      // spheremap pixel lighting (biased vertex normals)\n    9,      // spheremap pixel lighting (biased vertex normals), no fog\n    10,     // spheremap pixel lighting (biased vertex normals), fresnel\n    11,     // spheremap pixel lighting (biased vertex normals), fresnel, no fog\n\n    12,     // dual-parabola pixel lighting\n    13,     // dual-parabola pixel lighting, no fog\n    14,     // dual-parabola pixel lighting, fresnel\n    15,     // dual-parabola pixel lighting, fresnel, no fog\n\n    12,     // dual-parabola pixel lighting (biased vertex normals)\n    13,     // dual-parabola pixel lighting (biased vertex normals), no fog\n    14,     // dual-parabola pixel lighting (biased vertex normals), fresnel\n    15,     // dual-parabola pixel lighting (biased vertex normals), fresnel, no fog\n};\n\n\n// Global pool of per-device EnvironmentMapEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<EnvironmentMapEffectTraits>::DeviceResources> EffectBase<EnvironmentMapEffectTraits>::deviceResourcesPool = {};\n\n\n// Constructor.\nEnvironmentMapEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription,\n    EnvironmentMapEffect::Mapping mapping)\n    : EffectBase(device),\n        texture{},\n        textureSampler{},\n        environmentMap{},\n        environmentMapSampler{}\n{\n    static_assert(_countof(EffectBase<EnvironmentMapEffectTraits>::VertexShaderIndices) == EnvironmentMapEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<EnvironmentMapEffectTraits>::VertexShaderBytecode) == EnvironmentMapEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<EnvironmentMapEffectTraits>::PixelShaderBytecode) == EnvironmentMapEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<EnvironmentMapEffectTraits>::PixelShaderIndices) == EnvironmentMapEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        // Texture 1\n        CD3DX12_DESCRIPTOR_RANGE textureDescriptor(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        CD3DX12_DESCRIPTOR_RANGE textureSamplerDescriptor(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureDescriptor, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSamplerDescriptor, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Texture 2\n        CD3DX12_DESCRIPTOR_RANGE cubemapDescriptor(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);\n        CD3DX12_DESCRIPTOR_RANGE cubemapSamplerDescriptor(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 1);\n        rootParameters[RootParameterIndex::CubemapSRV].InitAsDescriptorTable(1, &cubemapDescriptor, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::CubemapSampler].InitAsDescriptorTable(1, &cubemapSamplerDescriptor, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Create the root signature\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n        mRootSignature = GetRootSignature(0, rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    fog.enabled = (effectFlags & EffectFlags::Fog) != 0;\n\n    if (effectFlags & EffectFlags::VertexColor)\n    {\n        DebugTrace(\"ERROR: EnvironmentMapEffect does not implement EffectFlags::VertexColor\\n\");\n        throw std::invalid_argument(\"EnvironmentMapEffect\");\n    }\n\n    constants.environmentMapAmount = 1;\n    constants.fresnelFactor = 1;\n\n    XMVECTOR unwantedOutput[MaxDirectionalLights];\n\n    lights.InitializeConstants(unwantedOutput[0], constants.lightDirection, constants.lightDiffuseColor, unwantedOutput);\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(mapping, effectFlags);\n\n    assert(sp >= 0 && sp < EnvironmentMapEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < EnvironmentMapEffectTraits::ShaderPermutationCount);\n    int vi = EffectBase<EnvironmentMapEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < EnvironmentMapEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < EnvironmentMapEffectTraits::VertexShaderCount);\n    int pi = EffectBase<EnvironmentMapEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < EnvironmentMapEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < EnvironmentMapEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<EnvironmentMapEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<EnvironmentMapEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"EnvironmentMapEffect\");\n}\n\n\nint EnvironmentMapEffect::Impl::GetPipelineStatePermutation(\n    EnvironmentMapEffect::Mapping mapping,\n    uint32_t effectFlags) const noexcept\n{\n    bool biasedVertexNormals = (effectFlags & EffectFlags::BiasedVertexNormals) != 0;\n\n    int permutation = 0;\n\n    // Use optimized shaders if fog is disabled.\n    if (!fog.enabled)\n    {\n        permutation += 1;\n    }\n\n    // Support fresnel?\n    if (effectFlags & EffectFlags::Fresnel)\n    {\n        permutation += 2;\n    }\n\n    if (mapping == Mapping_Sphere)\n    {\n        permutation += 24;\n\n        if (biasedVertexNormals)\n        {\n            permutation += 4;\n        }\n    }\n    else if (mapping == Mapping_DualParabola)\n    {\n        permutation += 32;\n\n        if (biasedVertexNormals)\n        {\n            permutation += 4;\n        }\n    }\n    else // Mapping_Cube\n    {\n        if (effectFlags & EffectFlags::PerPixelLightingBit)\n        {\n            permutation += 8;\n        }\n        else\n        {\n            if (effectFlags & EffectFlags::Specular)\n            {\n                permutation += 4;\n            }\n        }\n\n        if (biasedVertexNormals)\n        {\n            // Compressed normals need to be scaled and biased in the vertex shader.\n            permutation += 12;\n        }\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid EnvironmentMapEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n\n    fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector);\n            \n    lights.SetConstants(dirtyFlags, matrices, constants.world, constants.worldInverseTranspose, constants.eyePosition, constants.diffuseColor, constants.emissiveColor, true);\n\n    UpdateConstants();\n\n    // Set the resources and state\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the textures\n    if (!texture.ptr || !environmentMap.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture(s) for EnvironmentMapEffect (texture %llu, environmentMap %llu)\\n\", texture.ptr, environmentMap.ptr);\n        throw std::exception(\"EnvironmentMapEffect\");\n    }\n    if (!textureSampler.ptr || !environmentMapSampler.ptr)\n    {\n        DebugTrace(\"ERROR: Missing sampler(s) for EnvironmentMapEffect (sampler %llu, environmentMap %llu)\\n\", textureSampler.ptr, environmentMapSampler.ptr);\n        throw std::exception(\"EnvironmentMapEffect\");\n    }\n\n    // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, textureSampler);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::CubemapSRV, environmentMap);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::CubemapSampler, environmentMapSampler);\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n\n// Public constructor.\nEnvironmentMapEffect::EnvironmentMapEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription,\n    EnvironmentMapEffect::Mapping mapping)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription, mapping))\n{\n}\n\n\n// Move constructor.\nEnvironmentMapEffect::EnvironmentMapEffect(EnvironmentMapEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nEnvironmentMapEffect& EnvironmentMapEffect::operator= (EnvironmentMapEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nEnvironmentMapEffect::~EnvironmentMapEffect()\n{\n}\n\n\n// IEffect methods.\nvoid EnvironmentMapEffect::Apply(\n    _In_ ID3D12GraphicsCommandList* cmdList)\n{\n    pImpl->Apply(cmdList);\n}\n\n\n// Camera settings.\nvoid XM_CALLCONV EnvironmentMapEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\n// Material settings.\nvoid XM_CALLCONV EnvironmentMapEffect::SetDiffuseColor(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetEmissiveColor(FXMVECTOR value)\n{\n    pImpl->lights.emissiveColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid EnvironmentMapEffect::SetAlpha(float value)\n{\n    pImpl->lights.alpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetColorAndAlpha(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n    pImpl->lights.alpha = XMVectorGetW(value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\n// Light settings.\nvoid XM_CALLCONV EnvironmentMapEffect::SetAmbientLightColor(FXMVECTOR value)\n{\n    pImpl->lights.ambientLightColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid EnvironmentMapEffect::SetLightEnabled(int whichLight, bool value)\n{\n    XMVECTOR unwantedOutput[MaxDirectionalLights] = {};\n\n    pImpl->dirtyFlags |= pImpl->lights.SetLightEnabled(whichLight, value, pImpl->constants.lightDiffuseColor, unwantedOutput);\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetLightDirection(int whichLight, FXMVECTOR value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->constants.lightDirection[whichLight] = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightDiffuseColor(whichLight, value, pImpl->constants.lightDiffuseColor);\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetLightSpecularColor(int, FXMVECTOR)\n{\n    // Unsupported interface method.\n}\n\n\nvoid EnvironmentMapEffect::EnableDefaultLighting()\n{\n    EffectLights::EnableDefaultLighting(this);\n}\n\n\n// Fog settings.\nvoid EnvironmentMapEffect::SetFogStart(float value)\n{\n    pImpl->fog.start = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid EnvironmentMapEffect::SetFogEnd(float value)\n{\n    pImpl->fog.end = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetFogColor(FXMVECTOR value)\n{\n    pImpl->constants.fogColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid EnvironmentMapEffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE texture, D3D12_GPU_DESCRIPTOR_HANDLE sampler)\n{\n    pImpl->texture = texture;\n    pImpl->textureSampler = sampler;\n}\n\n\nvoid EnvironmentMapEffect::SetEnvironmentMap(D3D12_GPU_DESCRIPTOR_HANDLE texture, D3D12_GPU_DESCRIPTOR_HANDLE sampler)\n{\n    pImpl->environmentMap = texture;\n    pImpl->environmentMapSampler = sampler;\n}\n\n\n// Additional settings.\nvoid EnvironmentMapEffect::SetEnvironmentMapAmount(float value)\n{\n    pImpl->constants.environmentMapAmount = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV EnvironmentMapEffect::SetEnvironmentMapSpecular(FXMVECTOR value)\n{\n    pImpl->constants.environmentMapSpecular = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid EnvironmentMapEffect::SetFresnelFactor(float value)\n{\n    pImpl->constants.fresnelFactor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/GamePad.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: GamePad.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"GamePad.h\"\n#include \"PlatformHelpers.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n\nnamespace\n{\n    constexpr float c_XboxOneThumbDeadZone = .24f;  // Recommended Xbox One controller deadzone\n\n    float ApplyLinearDeadZone(float value, float maxValue, float deadZoneSize) noexcept\n    {\n        if (value < -deadZoneSize)\n        {\n            // Increase negative values to remove the deadzone discontinuity.\n            value += deadZoneSize;\n        }\n        else if (value > deadZoneSize)\n        {\n            // Decrease positive values to remove the deadzone discontinuity.\n            value -= deadZoneSize;\n        }\n        else\n        {\n            // Values inside the deadzone come out zero.\n            return 0;\n        }\n\n        // Scale into 0-1 range.\n        float scaledValue = value / (maxValue - deadZoneSize);\n        return std::max(-1.f, std::min(scaledValue, 1.f));\n    }\n\n    void ApplyStickDeadZone(\n        float x,\n        float y,\n        GamePad::DeadZone deadZoneMode,\n        float maxValue,\n        float deadZoneSize,\n        _Out_ float& resultX,\n        _Out_ float& resultY) noexcept\n    {\n        switch (deadZoneMode)\n        {\n            case GamePad::DEAD_ZONE_INDEPENDENT_AXES:\n                resultX = ApplyLinearDeadZone(x, maxValue, deadZoneSize);\n                resultY = ApplyLinearDeadZone(y, maxValue, deadZoneSize);\n                break;\n\n            case GamePad::DEAD_ZONE_CIRCULAR:\n            {\n                float dist = sqrtf(x*x + y * y);\n                float wanted = ApplyLinearDeadZone(dist, maxValue, deadZoneSize);\n\n                float scale = (wanted > 0.f) ? (wanted / dist) : 0.f;\n\n                resultX = std::max(-1.f, std::min(x * scale, 1.f));\n                resultY = std::max(-1.f, std::min(y * scale, 1.f));\n            }\n            break;\n\n            default: // GamePad::DEAD_ZONE_NONE\n                resultX = ApplyLinearDeadZone(x, maxValue, 0);\n                resultY = ApplyLinearDeadZone(y, maxValue, 0);\n                break;\n        }\n    }\n}\n\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\n\n#include <GameInput.h>\n\n//======================================================================================\n// GameInput\n//======================================================================================\n\nclass GamePad::Impl\n{\npublic:\n    Impl(GamePad* owner) :\n        mOwner(owner),\n        mCtrlChanged(INVALID_HANDLE_VALUE),\n        mDeviceToken(0),\n        mMostRecentGamepad(0)\n    {\n        if (s_gamePad)\n        {\n            throw std::exception(\"GamePad is a singleton\");\n        }\n\n        s_gamePad = this;\n\n        ThrowIfFailed(GameInputCreate(mGameInput.GetAddressOf()));\n\n        ThrowIfFailed(mGameInput->RegisterDeviceCallback(\n            nullptr,\n            GameInputKindGamepad,\n            GameInputDeviceConnected,\n            GameInputBlockingEnumeration,\n            this,\n            OnGameInputDevice,\n            &mDeviceToken));\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n        if (mDeviceToken)\n        {\n            if (mGameInput)\n            {\n                HRESULT hr = mGameInput->UnregisterCallback(mDeviceToken, UINT64_MAX);\n                if (FAILED(hr))\n                {\n                    DebugTrace(\"ERROR: GameInput::UnregisterCallback [gamepad] failed (%08X)\", static_cast<unsigned int>(hr));\n                }\n            }\n\n            mDeviceToken = 0;\n        }\n\n        s_gamePad = nullptr;\n    }\n\n    void GetState(int player, _Out_ State& state, DeadZone deadZoneMode)\n    {\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if (player >= 0 && player < MAX_PLAYER_COUNT)\n        {\n            IGameInputDevice* device = mInputDevices[player].Get();\n            if (device)\n            {\n                ComPtr<IGameInputReading> reading;\n                if (SUCCEEDED(mGameInput->GetCurrentReading(GameInputKindGamepad, device, reading.GetAddressOf())))\n                {\n                    GameInputGamepadState pad;\n                    if (reading->GetGamepadState(&pad))\n                    {\n                        state.connected = true;\n                        state.packet = reading->GetSequenceNumber(GameInputKindGamepad);\n\n                        state.buttons.a = (pad.buttons & GameInputGamepadA) != 0;\n                        state.buttons.b = (pad.buttons & GameInputGamepadB) != 0;\n                        state.buttons.x = (pad.buttons & GameInputGamepadX) != 0;\n                        state.buttons.y = (pad.buttons & GameInputGamepadY) != 0;\n                        state.buttons.leftStick = (pad.buttons & GameInputGamepadLeftThumbstick) != 0;\n                        state.buttons.rightStick = (pad.buttons & GameInputGamepadRightThumbstick) != 0;\n                        state.buttons.leftShoulder = (pad.buttons & GameInputGamepadLeftShoulder) != 0;\n                        state.buttons.rightShoulder = (pad.buttons & GameInputGamepadRightShoulder) != 0;\n                        state.buttons.view = (pad.buttons & GameInputGamepadView) != 0;\n                        state.buttons.menu = (pad.buttons & GameInputGamepadMenu) != 0;\n\n                        state.dpad.up = (pad.buttons & GameInputGamepadDPadUp) != 0;\n                        state.dpad.down = (pad.buttons & GameInputGamepadDPadDown) != 0;\n                        state.dpad.right = (pad.buttons & GameInputGamepadDPadRight) != 0;\n                        state.dpad.left = (pad.buttons & GameInputGamepadDPadLeft) != 0;\n\n                        ApplyStickDeadZone(pad.leftThumbstickX, pad.leftThumbstickY,\n                            deadZoneMode, 1.f, c_XboxOneThumbDeadZone,\n                            state.thumbSticks.leftX, state.thumbSticks.leftY);\n\n                        ApplyStickDeadZone(pad.rightThumbstickX, pad.rightThumbstickY,\n                            deadZoneMode, 1.f, c_XboxOneThumbDeadZone,\n                            state.thumbSticks.rightX, state.thumbSticks.rightY);\n\n                        state.triggers.left = pad.leftTrigger;\n                        state.triggers.right = pad.rightTrigger;\n                        return;\n                    }\n                }\n            }\n        }\n\n        memset(&state, 0, sizeof(State));\n    }\n\n    void GetCapabilities(int player, _Out_ Capabilities& caps)\n    {\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if (player >= 0 && player < MAX_PLAYER_COUNT)\n        {\n            IGameInputDevice* device = mInputDevices[player].Get();\n            if (device)\n            {\n                if (device->GetDeviceStatus() & GameInputDeviceConnected)\n                {\n                    auto deviceInfo = device->GetDeviceInfo();\n                    caps.connected = true;\n                    caps.gamepadType = Capabilities::GAMEPAD;\n                    caps.id = deviceInfo->deviceId;\n                    caps.vid = deviceInfo->vendorId;\n                    caps.pid = deviceInfo->productId;\n                    return;\n                }\n                else\n                {\n                    mInputDevices[player].Reset();\n                }\n            }\n        }\n\n        memset(&caps, 0, sizeof(Capabilities));\n    }\n\n    bool SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) noexcept\n    {\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if (player >= 0 && player < MAX_PLAYER_COUNT)\n        {\n            IGameInputDevice* device = mInputDevices[player].Get();\n            if (device)\n            {\n                GameInputRumbleParams const params =\n                {\n                    leftMotor,\n                    rightMotor,\n                    leftTrigger,\n                    rightTrigger\n                };\n\n                device->SetRumbleState(&params);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void Suspend() noexcept\n    {\n        for (int player = 0; player < MAX_PLAYER_COUNT; ++player)\n        {\n            IGameInputDevice* device = mInputDevices[player].Get();\n            if (device)\n            {\n                device->SetRumbleState(nullptr);\n            }\n        }\n    }\n\n    void Resume() noexcept\n    {\n        for (int player = 0; player < MAX_PLAYER_COUNT; ++player)\n        {\n            IGameInputDevice* device = mInputDevices[player].Get();\n            if (device)\n            {\n                if (!(device->GetDeviceStatus() & GameInputDeviceConnected))\n                {\n                    mInputDevices[player].Reset();\n                }\n            }\n        }\n    }\n\n    void GetDevice(int player, _Outptr_ IGameInputDevice** device) noexcept\n    {\n        if (!device)\n            return;\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        *device = nullptr;\n\n        if (player >= 0 && player < MAX_PLAYER_COUNT)\n        {\n            IGameInputDevice* dev = mInputDevices[player].Get();\n            if (dev)\n            {\n                dev->AddRef();\n                *device = dev;\n            }\n        }\n    }\n\n    GamePad*    mOwner;\n\n    static GamePad::Impl* s_gamePad;\n\n    HANDLE mCtrlChanged;\n\nprivate:\n    ComPtr<IGameInput>          mGameInput;\n    ComPtr<IGameInputDevice>    mInputDevices[MAX_PLAYER_COUNT];\n\n    GameInputCallbackToken      mDeviceToken;\n\n    int mMostRecentGamepad;\n\n    static void CALLBACK OnGameInputDevice(\n        _In_ GameInputCallbackToken,\n        _In_ void * context,\n        _In_ IGameInputDevice * device,\n        _In_ uint64_t,\n        _In_ GameInputDeviceStatus currentStatus,\n        _In_ GameInputDeviceStatus) noexcept\n    {\n        auto impl = reinterpret_cast<GamePad::Impl*>(context);\n\n        if (currentStatus & GameInputDeviceConnected)\n        {\n            size_t empty = MAX_PLAYER_COUNT;\n            size_t k = 0;\n            for (; k < MAX_PLAYER_COUNT; ++k)\n            {\n                if (impl->mInputDevices[k].Get() == device)\n                {\n                    impl->mMostRecentGamepad = static_cast<int>(k);\n                    break;\n                }\n                else if (!impl->mInputDevices[k])\n                {\n                    if (empty >= MAX_PLAYER_COUNT)\n                        empty = k;\n                }\n            }\n\n            if (k >= MAX_PLAYER_COUNT)\n            {\n                // Silently ignore \"extra\" gamepads as there's no hard limit\n                if (empty < MAX_PLAYER_COUNT)\n                {\n                    impl->mInputDevices[empty] = device;\n                    impl->mMostRecentGamepad = static_cast<int>(empty);\n                }\n            }\n        }\n        else\n        {\n            for (size_t k = 0; k < MAX_PLAYER_COUNT; ++k)\n            {\n                if (impl->mInputDevices[k].Get() == device)\n                {\n                    impl->mInputDevices[k].Reset();\n                    break;\n                }\n            }\n        }\n\n        if (impl->mCtrlChanged != INVALID_HANDLE_VALUE)\n        {\n            SetEvent(impl->mCtrlChanged);\n        }\n    }\n};\n\nGamePad::Impl* GamePad::Impl::s_gamePad = nullptr;\n\n\n#elif (_WIN32_WINNT >= _WIN32_WINNT_WIN10) && !defined(_GAMING_DESKTOP)\n\n//======================================================================================\n// Windows::Gaming::Input (Windows 10)\n//======================================================================================\n\n#pragma warning(push)\n#pragma warning(disable : 4471 5204)\n#include <windows.gaming.input.h>\n#pragma warning(pop)\n\nclass GamePad::Impl\n{\npublic:\n    Impl(GamePad* owner) :\n        mOwner(owner),\n        mCtrlChanged(INVALID_HANDLE_VALUE),\n        mUserChanged(INVALID_HANDLE_VALUE),\n        mMostRecentGamepad(0),\n        mStatics{},\n        mGamePad{},\n        mUserChangeToken{},\n        mAddedToken{},\n        mRemovedToken{},\n        mChanged{}\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Foundation;\n\n        if (s_gamePad)\n        {\n            throw std::exception(\"GamePad is a singleton\");\n        }\n\n        s_gamePad = this;\n\n        mChanged.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mChanged)\n        {\n            throw std::exception(\"CreateEventEx\");\n        }\n\n        ThrowIfFailed(GetActivationFactory(HStringReference(RuntimeClass_Windows_Gaming_Input_Gamepad).Get(), mStatics.GetAddressOf()));\n\n        typedef __FIEventHandler_1_Windows__CGaming__CInput__CGamepad AddedHandler;\n        ThrowIfFailed(mStatics->add_GamepadAdded(Callback<AddedHandler>(GamepadAdded).Get(), &mAddedToken));\n\n        typedef __FIEventHandler_1_Windows__CGaming__CInput__CGamepad RemovedHandler;\n        ThrowIfFailed(mStatics->add_GamepadRemoved(Callback<RemovedHandler>(GamepadRemoved).Get(), &mRemovedToken));\n\n        ScanGamePads();\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n        using namespace ABI::Windows::Gaming::Input;\n\n        for (size_t j = 0; j < MAX_PLAYER_COUNT; ++j)\n        {\n            if (mGamePad[j])\n            {\n                ComPtr<IGameController> ctrl;\n                HRESULT hr = mGamePad[j].As(&ctrl);\n                if (SUCCEEDED(hr) && ctrl)\n                {\n                    (void)ctrl->remove_UserChanged(mUserChangeToken[j]);\n                    mUserChangeToken[j].value = 0;\n                }\n\n                mGamePad[j].Reset();\n            }\n        }\n\n        if (mStatics)\n        {\n            (void)mStatics->remove_GamepadAdded(mAddedToken);\n            mAddedToken.value = 0;\n\n            (void)mStatics->remove_GamepadRemoved(mRemovedToken);\n            mRemovedToken.value = 0;\n\n            mStatics.Reset();\n        }\n\n        s_gamePad = nullptr;\n    }\n\n    void GetState(int player, _Out_ State& state, DeadZone deadZoneMode)\n    {\n        using namespace Microsoft::WRL;\n        using namespace ABI::Windows::Gaming::Input;\n\n        if (WaitForSingleObjectEx(mChanged.get(), 0, FALSE) == WAIT_OBJECT_0)\n        {\n            ScanGamePads();\n        }\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if ((player >= 0) && (player < MAX_PLAYER_COUNT))\n        {\n            if (mGamePad[player])\n            {\n                GamepadReading reading;\n                HRESULT hr = mGamePad[player]->GetCurrentReading(&reading);\n                if (SUCCEEDED(hr))\n                {\n                    state.connected = true;\n                    state.packet = reading.Timestamp;\n\n                    state.buttons.a = (reading.Buttons & GamepadButtons::GamepadButtons_A) != 0;\n                    state.buttons.b = (reading.Buttons & GamepadButtons::GamepadButtons_B) != 0;\n                    state.buttons.x = (reading.Buttons & GamepadButtons::GamepadButtons_X) != 0;\n                    state.buttons.y = (reading.Buttons & GamepadButtons::GamepadButtons_Y) != 0;\n\n                    state.buttons.leftStick = (reading.Buttons & GamepadButtons::GamepadButtons_LeftThumbstick) != 0;\n                    state.buttons.rightStick = (reading.Buttons & GamepadButtons::GamepadButtons_RightThumbstick) != 0;\n\n                    state.buttons.leftShoulder = (reading.Buttons & GamepadButtons::GamepadButtons_LeftShoulder) != 0;\n                    state.buttons.rightShoulder = (reading.Buttons & GamepadButtons::GamepadButtons_RightShoulder) != 0;\n\n                    state.buttons.back = (reading.Buttons & GamepadButtons::GamepadButtons_View) != 0;\n                    state.buttons.start = (reading.Buttons & GamepadButtons::GamepadButtons_Menu) != 0;\n\n                    state.dpad.up = (reading.Buttons & GamepadButtons::GamepadButtons_DPadUp) != 0;\n                    state.dpad.down = (reading.Buttons & GamepadButtons::GamepadButtons_DPadDown) != 0;\n                    state.dpad.right = (reading.Buttons & GamepadButtons::GamepadButtons_DPadRight) != 0;\n                    state.dpad.left = (reading.Buttons & GamepadButtons::GamepadButtons_DPadLeft) != 0;\n\n                    ApplyStickDeadZone(static_cast<float>(reading.LeftThumbstickX), static_cast<float>(reading.LeftThumbstickY),\n                                       deadZoneMode, 1.f, c_XboxOneThumbDeadZone,\n                                       state.thumbSticks.leftX, state.thumbSticks.leftY);\n\n                    ApplyStickDeadZone(static_cast<float>(reading.RightThumbstickX), static_cast<float>(reading.RightThumbstickY),\n                                       deadZoneMode, 1.f, c_XboxOneThumbDeadZone,\n                                       state.thumbSticks.rightX, state.thumbSticks.rightY);\n\n                    state.triggers.left = static_cast<float>(reading.LeftTrigger);\n                    state.triggers.right = static_cast<float>(reading.RightTrigger);\n\n                    return;\n                }\n            }\n        }\n\n        memset(&state, 0, sizeof(State));\n    }\n\n    void GetCapabilities(int player, Capabilities& caps)\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Foundation;\n        using namespace ABI::Windows::System;\n        using namespace ABI::Windows::Gaming::Input;\n\n        if (WaitForSingleObjectEx(mChanged.get(), 0, FALSE) == WAIT_OBJECT_0)\n        {\n            ScanGamePads();\n        }\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if ((player >= 0) && (player < MAX_PLAYER_COUNT))\n        {\n            if (mGamePad[player])\n            {\n                caps.connected = true;\n                caps.gamepadType = Capabilities::GAMEPAD;\n                caps.id.clear();\n                caps.vid = caps.pid = 0;\n\n                ComPtr<IGameController> ctrl;\n                HRESULT hr = mGamePad[player].As(&ctrl);\n                if (SUCCEEDED(hr) && ctrl)\n                {\n                    ComPtr<IUser> user;\n                    hr = ctrl->get_User(user.GetAddressOf());\n                    if (SUCCEEDED(hr) && user != nullptr)\n                    {\n                        HString str;\n                        hr = user->get_NonRoamableId(str.GetAddressOf());\n                        if (SUCCEEDED(hr))\n                        {\n                            caps.id = str.GetRawBuffer(nullptr);\n                        }\n                    }\n\n                // Requires the Windows 10 Creators Update SDK (15063)\n                #if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\n                    ComPtr<IRawGameControllerStatics> rawStatics;\n                    hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Gaming_Input_RawGameController).Get(), rawStatics.GetAddressOf());\n                    if (SUCCEEDED(hr))\n                    {\n                        ComPtr<IRawGameController> raw;\n                        hr = rawStatics->FromGameController(ctrl.Get(), raw.GetAddressOf());\n                        if (SUCCEEDED(hr) && raw)\n                        {\n                            if (FAILED(raw->get_HardwareVendorId(&caps.vid)))\n                                caps.vid = 0;\n\n                            if (FAILED(raw->get_HardwareProductId(&caps.pid)))\n                                caps.pid = 0;\n                        }\n                    }\n                #endif // NTDDI_WIN10_RS2\n                }\n                return;\n            }\n        }\n\n        caps.id.clear();\n        caps = {};\n    }\n\n    bool SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) noexcept\n    {\n        using namespace ABI::Windows::Gaming::Input;\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if ((player >= 0) && (player < MAX_PLAYER_COUNT))\n        {\n            if (mGamePad[player])\n            {\n                GamepadVibration vib;\n                vib.LeftMotor = double(leftMotor);\n                vib.RightMotor = double(rightMotor);\n                vib.LeftTrigger = double(leftTrigger);\n                vib.RightTrigger = double(rightTrigger);\n                HRESULT hr = mGamePad[player]->put_Vibration(vib);\n\n                if (SUCCEEDED(hr))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    void Suspend() noexcept\n    {\n        for (size_t j = 0; j < MAX_PLAYER_COUNT; ++j)\n        {\n            mGamePad[j].Reset();\n        }\n    }\n\n    void Resume() noexcept\n    {\n        // Make sure we rescan gamepads\n        SetEvent(mChanged.get());\n    }\n\n    GamePad*    mOwner;\n\n    static GamePad::Impl* s_gamePad;\n\n    HANDLE mCtrlChanged;\n    HANDLE mUserChanged;\n\nprivate:\n    int mMostRecentGamepad;\n\n    void ScanGamePads()\n    {\n        using namespace Microsoft::WRL;\n        using namespace ABI::Windows::Foundation::Collections;\n        using namespace ABI::Windows::Gaming::Input;\n\n        ComPtr<IVectorView<Gamepad*>> pads;\n        ThrowIfFailed(mStatics->get_Gamepads(pads.GetAddressOf()));\n\n        unsigned int count = 0;\n        ThrowIfFailed(pads->get_Size(&count));\n\n        // Check for removed gamepads\n        for (size_t j = 0; j < MAX_PLAYER_COUNT; ++j)\n        {\n            if (mGamePad[j])\n            {\n                unsigned int k = 0;\n                for (; k < count; ++k)\n                {\n                    ComPtr<IGamepad> pad;\n                    HRESULT hr = pads->GetAt(k, pad.GetAddressOf());\n                    if (SUCCEEDED(hr) && (pad == mGamePad[j]))\n                    {\n                        break;\n                    }\n                }\n\n                if (k >= count)\n                {\n                    ComPtr<IGameController> ctrl;\n                    HRESULT hr = mGamePad[j].As(&ctrl);\n                    if (SUCCEEDED(hr) && ctrl)\n                    {\n                        (void)ctrl->remove_UserChanged(mUserChangeToken[j]);\n                        mUserChangeToken[j].value = 0;\n                    }\n\n                    mGamePad[j].Reset();\n                }\n            }\n        }\n\n        // Check for added gamepads\n        for (unsigned int j = 0; j < count; ++j)\n        {\n            ComPtr<IGamepad> pad;\n            HRESULT hr = pads->GetAt(j, pad.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                size_t empty = MAX_PLAYER_COUNT;\n                size_t k = 0;\n                for (; k < MAX_PLAYER_COUNT; ++k)\n                {\n                    if (mGamePad[k] == pad)\n                    {\n                        if (j == (count - 1))\n                            mMostRecentGamepad = static_cast<int>(k);\n                        break;\n                    }\n                    else if (!mGamePad[k])\n                    {\n                        if (empty >= MAX_PLAYER_COUNT)\n                            empty = k;\n                    }\n                }\n\n                if (k >= MAX_PLAYER_COUNT)\n                {\n                    // Silently ignore \"extra\" gamepads as there's no hard limit\n                    if (empty < MAX_PLAYER_COUNT)\n                    {\n                        mGamePad[empty] = pad;\n                        if (j == (count - 1))\n                            mMostRecentGamepad = static_cast<int>(empty);\n\n                        ComPtr<IGameController> ctrl;\n                        hr = pad.As(&ctrl);\n                        if (SUCCEEDED(hr) && ctrl)\n                        {\n                            typedef __FITypedEventHandler_2_Windows__CGaming__CInput__CIGameController_Windows__CSystem__CUserChangedEventArgs UserHandler;\n                            ThrowIfFailed(ctrl->add_UserChanged(Callback<UserHandler>(UserChanged).Get(), &mUserChangeToken[empty]));\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    ComPtr<ABI::Windows::Gaming::Input::IGamepadStatics> mStatics;\n    ComPtr<ABI::Windows::Gaming::Input::IGamepad> mGamePad[MAX_PLAYER_COUNT];\n    EventRegistrationToken mUserChangeToken[MAX_PLAYER_COUNT];\n\n    EventRegistrationToken mAddedToken;\n    EventRegistrationToken mRemovedToken;\n\n    ScopedHandle mChanged;\n\n    static HRESULT GamepadAdded(IInspectable *, ABI::Windows::Gaming::Input::IGamepad*)\n    {\n        if (s_gamePad)\n        {\n            SetEvent(s_gamePad->mChanged.get());\n\n            if (s_gamePad->mCtrlChanged != INVALID_HANDLE_VALUE)\n            {\n                SetEvent(s_gamePad->mCtrlChanged);\n            }\n        }\n        return S_OK;\n    }\n\n    static HRESULT GamepadRemoved(IInspectable *, ABI::Windows::Gaming::Input::IGamepad*)\n    {\n        if (s_gamePad)\n        {\n            SetEvent(s_gamePad->mChanged.get());\n\n            if (s_gamePad->mCtrlChanged != INVALID_HANDLE_VALUE)\n            {\n                SetEvent(s_gamePad->mCtrlChanged);\n            }\n        }\n        return S_OK;\n    }\n\n    static HRESULT UserChanged(ABI::Windows::Gaming::Input::IGameController*, ABI::Windows::System::IUserChangedEventArgs*)\n    {\n        if (s_gamePad)\n        {\n            if (s_gamePad->mUserChanged != INVALID_HANDLE_VALUE)\n            {\n                SetEvent(s_gamePad->mUserChanged);\n            }\n        }\n        return S_OK;\n    }\n};\n\nGamePad::Impl* GamePad::Impl::s_gamePad = nullptr;\n\n\n#elif defined(_XBOX_ONE)\n\n//======================================================================================\n// Windows::Xbox::Input (Xbox One)\n//======================================================================================\n\n#include <Windows.Xbox.Input.h>\n\n#include <Windows.Foundation.Collections.h>\n\nclass GamePad::Impl\n{\npublic:\n    class GamepadAddedListener : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,\n        ABI::Windows::Foundation::IEventHandler<ABI::Windows::Xbox::Input::GamepadAddedEventArgs *>,\n        Microsoft::WRL::FtmBase>\n    {\n    public:\n        GamepadAddedListener(HANDLE event) : mEvent(event) {}\n\n        STDMETHOD(Invoke)(_In_ IInspectable *, _In_ ABI::Windows::Xbox::Input::IGamepadAddedEventArgs *) override\n        {\n            SetEvent(mEvent);\n\n            auto pad = GamePad::Impl::s_gamePad;\n\n            if (pad && pad->mCtrlChanged != INVALID_HANDLE_VALUE)\n            {\n                SetEvent(pad->mCtrlChanged);\n            }\n            return S_OK;\n        }\n\n    private:\n        HANDLE mEvent;\n    };\n\n    class GamepadRemovedListener : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,\n        ABI::Windows::Foundation::IEventHandler<ABI::Windows::Xbox::Input::GamepadRemovedEventArgs *>,\n        Microsoft::WRL::FtmBase>\n    {\n    public:\n        GamepadRemovedListener(HANDLE event) : mEvent(event) {}\n\n        STDMETHOD(Invoke)(_In_ IInspectable *, _In_ ABI::Windows::Xbox::Input::IGamepadRemovedEventArgs *) override\n        {\n            SetEvent(mEvent);\n\n            auto pad = GamePad::Impl::s_gamePad;\n\n            if (pad && pad->mCtrlChanged != INVALID_HANDLE_VALUE)\n            {\n                SetEvent(pad->mCtrlChanged);\n            }\n            return S_OK;\n        }\n\n    private:\n        HANDLE mEvent;\n    };\n\n    class UserPairingListener : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,\n        ABI::Windows::Foundation::IEventHandler<ABI::Windows::Xbox::Input::ControllerPairingChangedEventArgs *>,\n        Microsoft::WRL::FtmBase>\n    {\n    public:\n        UserPairingListener() noexcept {}\n\n        STDMETHOD(Invoke)(_In_ IInspectable *, _In_ ABI::Windows::Xbox::Input::IControllerPairingChangedEventArgs *) override\n        {\n            auto pad = GamePad::Impl::s_gamePad;\n\n            if (pad && pad->mUserChanged != INVALID_HANDLE_VALUE)\n            {\n                SetEvent(pad->mUserChanged);\n            }\n            return S_OK;\n        }\n    };\n\n    Impl(GamePad *owner) :\n        mOwner(owner),\n        mCtrlChanged(INVALID_HANDLE_VALUE),\n        mUserChanged(INVALID_HANDLE_VALUE),\n        mMostRecentGamepad(0),\n        mStatics{},\n        mStaticsCtrl{},\n        mGamePad{},\n        mAddedToken{},\n        mRemovedToken{},\n        mUserParingToken{},\n        mChanged{}\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Foundation;\n\n        if (s_gamePad)\n        {\n            throw std::exception(\"GamePad is a singleton\");\n        }\n\n        s_gamePad = this;\n\n        mChanged.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mChanged)\n        {\n            throw std::exception(\"CreateEventEx\");\n        }\n\n        ThrowIfFailed(GetActivationFactory(HStringReference(RuntimeClass_Windows_Xbox_Input_Gamepad).Get(), mStatics.GetAddressOf()));\n\n        ThrowIfFailed(GetActivationFactory(HStringReference(RuntimeClass_Windows_Xbox_Input_Controller).Get(), mStaticsCtrl.GetAddressOf()));\n\n        ThrowIfFailed(mStatics->add_GamepadAdded(Make<GamepadAddedListener>(mChanged.get()).Get(), &mAddedToken));\n\n        ThrowIfFailed(mStatics->add_GamepadRemoved(Make<GamepadRemovedListener>(mChanged.get()).Get(), &mRemovedToken));\n\n        ThrowIfFailed(mStaticsCtrl->add_ControllerPairingChanged(Make<UserPairingListener>().Get(), &mUserParingToken));\n\n        ScanGamePads();\n    }\n\n    ~Impl()\n    {\n        if (mStatics)\n        {\n            (void)mStatics->remove_GamepadAdded(mAddedToken);\n            mAddedToken.value = 0;\n\n            (void)mStatics->remove_GamepadRemoved(mRemovedToken);\n            mRemovedToken.value = 0;\n\n            mStatics.Reset();\n        }\n\n        if (mStaticsCtrl)\n        {\n            (void)mStaticsCtrl->remove_ControllerPairingChanged(mUserParingToken);\n            mUserParingToken.value = 0;\n\n            mStaticsCtrl.Reset();\n        }\n\n        s_gamePad = nullptr;\n    }\n\n    void GetState(int player, _Out_ State& state, DeadZone deadZoneMode)\n    {\n        using namespace Microsoft::WRL;\n        using namespace ABI::Windows::Xbox::Input;\n\n        if (WaitForSingleObjectEx(mChanged.get(), 0, FALSE) == WAIT_OBJECT_0)\n        {\n            ScanGamePads();\n        }\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if ((player >= 0) && (player < MAX_PLAYER_COUNT))\n        {\n            if (mGamePad[player])\n            {\n                RawGamepadReading reading;\n                HRESULT hr = mGamePad[player]->GetRawCurrentReading(&reading);\n                if (SUCCEEDED(hr))\n                {\n                    state.connected = true;\n                    state.packet = reading.Timestamp;\n\n                    state.buttons.a = (reading.Buttons & GamepadButtons::GamepadButtons_A) != 0;\n                    state.buttons.b = (reading.Buttons & GamepadButtons::GamepadButtons_B) != 0;\n                    state.buttons.x = (reading.Buttons & GamepadButtons::GamepadButtons_X) != 0;\n                    state.buttons.y = (reading.Buttons & GamepadButtons::GamepadButtons_Y) != 0;\n\n                    state.buttons.leftStick = (reading.Buttons & GamepadButtons::GamepadButtons_LeftThumbstick) != 0;\n                    state.buttons.rightStick = (reading.Buttons & GamepadButtons::GamepadButtons_RightThumbstick) != 0;\n\n                    state.buttons.leftShoulder = (reading.Buttons & GamepadButtons::GamepadButtons_LeftShoulder) != 0;\n                    state.buttons.rightShoulder = (reading.Buttons & GamepadButtons::GamepadButtons_RightShoulder) != 0;\n\n                    state.buttons.back = (reading.Buttons & GamepadButtons::GamepadButtons_View) != 0;\n                    state.buttons.start = (reading.Buttons & GamepadButtons::GamepadButtons_Menu) != 0;\n\n                    state.dpad.up = (reading.Buttons & GamepadButtons::GamepadButtons_DPadUp) != 0;\n                    state.dpad.down = (reading.Buttons & GamepadButtons::GamepadButtons_DPadDown) != 0;\n                    state.dpad.right = (reading.Buttons & GamepadButtons::GamepadButtons_DPadRight) != 0;\n                    state.dpad.left = (reading.Buttons & GamepadButtons::GamepadButtons_DPadLeft) != 0;\n\n                    ApplyStickDeadZone(reading.LeftThumbstickX, reading.LeftThumbstickY,\n                                       deadZoneMode, 1.f, c_XboxOneThumbDeadZone,\n                                       state.thumbSticks.leftX, state.thumbSticks.leftY);\n\n                    ApplyStickDeadZone(reading.RightThumbstickX, reading.RightThumbstickY,\n                                       deadZoneMode, 1.f, c_XboxOneThumbDeadZone,\n                                       state.thumbSticks.rightX, state.thumbSticks.rightY);\n\n                    state.triggers.left = reading.LeftTrigger;\n                    state.triggers.right = reading.RightTrigger;\n\n                    return;\n                }\n            }\n        }\n\n        memset(&state, 0, sizeof(State));\n    }\n\n    void GetCapabilities(int player, _Out_ Capabilities& caps)\n    {\n        using namespace Microsoft::WRL;\n        using namespace ABI::Windows::Xbox::Input;\n\n        if (WaitForSingleObjectEx(mChanged.get(), 0, FALSE) == WAIT_OBJECT_0)\n        {\n            ScanGamePads();\n        }\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if ((player >= 0) && (player < MAX_PLAYER_COUNT))\n        {\n            if (mGamePad[player])\n            {\n                caps.connected = true;\n                caps.gamepadType = Capabilities::UNKNOWN;\n                caps.id = 0;\n                caps.vid = caps.pid = 0;\n\n                ComPtr<IController> ctrl;\n                HRESULT hr = mGamePad[player].As(&ctrl);\n                if (SUCCEEDED(hr) && ctrl)\n                {\n                    hr = ctrl->get_Id(&caps.id);\n                    if (FAILED(hr))\n                        caps.id = 0;\n\n                    Wrappers::HString str;\n                    hr = ctrl->get_Type(str.GetAddressOf());\n                    if (SUCCEEDED(hr))\n                    {\n                        const wchar_t* typeStr = str.GetRawBuffer(nullptr);\n                        if (_wcsicmp(typeStr, L\"Windows.Xbox.Input.Gamepad\") == 0)\n                        {\n                            caps.gamepadType = Capabilities::GAMEPAD;\n                        }\n                        else if (_wcsicmp(typeStr, L\"Microsoft.Xbox.Input.ArcadeStick\") == 0)\n                        {\n                            caps.gamepadType = Capabilities::ARCADE_STICK;\n                        }\n                        else if (_wcsicmp(typeStr, L\"Microsoft.Xbox.Input.Wheel\") == 0)\n                        {\n                            caps.gamepadType = Capabilities::WHEEL;\n                        }\n                    }\n                }\n\n            #if _XDK_VER >= 0x42ED07E4 /* XDK Edition 180400 */\n                ComPtr<IController3> ctrl3;\n                hr = mGamePad[player].As(&ctrl3);\n                if (SUCCEEDED(hr) && ctrl3)\n                {\n                    if (FAILED(ctrl3->get_HardwareVendorId(&caps.vid)))\n                        caps.vid = 0;\n\n                    if (FAILED(ctrl3->get_HardwareProductId(&caps.pid)))\n                        caps.pid = 0;\n                }\n            #endif\n\n                return;\n            }\n        }\n\n        memset(&caps, 0, sizeof(Capabilities));\n    }\n\n    bool SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) noexcept\n    {\n        using namespace ABI::Windows::Xbox::Input;\n\n        if (player == -1)\n            player = mMostRecentGamepad;\n\n        if ((player >= 0) && (player < MAX_PLAYER_COUNT))\n        {\n            if (mGamePad[player])\n            {\n                HRESULT hr;\n                try\n                {\n                    GamepadVibration vib;\n                    vib.LeftMotorLevel = leftMotor;\n                    vib.RightMotorLevel = rightMotor;\n                    vib.LeftTriggerLevel = leftTrigger;\n                    vib.RightTriggerLevel = rightTrigger;\n                    hr = mGamePad[player]->SetVibration(vib);\n                }\n                catch (...)\n                {\n                    // Handle case where gamepad might be invalid\n                    hr = E_FAIL;\n                }\n\n                if (SUCCEEDED(hr))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    void Suspend() noexcept\n    {\n        for (size_t j = 0; j < MAX_PLAYER_COUNT; ++j)\n        {\n            mGamePad[j].Reset();\n        }\n    }\n\n    void Resume() noexcept\n    {\n        // Make sure we rescan gamepads\n        SetEvent(mChanged.get());\n    }\n\n    GamePad*    mOwner;\n\n    static GamePad::Impl* s_gamePad;\n\n    HANDLE mCtrlChanged;\n    HANDLE mUserChanged;\n\nprivate:\n    int mMostRecentGamepad;\n\n    void ScanGamePads()\n    {\n        using namespace ABI::Windows::Foundation::Collections;\n        using namespace ABI::Windows::Xbox::Input;\n\n        ComPtr<IVectorView<IGamepad*>> pads;\n        ThrowIfFailed(mStatics->get_Gamepads(pads.GetAddressOf()));\n\n        unsigned int count = 0;\n        ThrowIfFailed(pads->get_Size(&count));\n\n        // Check for removed gamepads\n        for (size_t j = 0; j < MAX_PLAYER_COUNT; ++j)\n        {\n            if (mGamePad[j])\n            {\n                unsigned int k = 0;\n                for (; k < count; ++k)\n                {\n                    ComPtr<IGamepad> pad;\n                    HRESULT hr = pads->GetAt(k, pad.GetAddressOf());\n                    if (SUCCEEDED(hr) && (pad == mGamePad[j]))\n                    {\n                        break;\n                    }\n                }\n\n                if (k >= count)\n                {\n                    mGamePad[j].Reset();\n                }\n            }\n        }\n\n        // Check for added gamepads\n        for (unsigned int j = 0; j < count; ++j)\n        {\n            ComPtr<IGamepad> pad;\n            HRESULT hr = pads->GetAt(j, pad.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                size_t empty = MAX_PLAYER_COUNT;\n                size_t k = 0;\n                for (; k < MAX_PLAYER_COUNT; ++k)\n                {\n                    if (mGamePad[k] == pad)\n                    {\n                        if (!j)\n                            mMostRecentGamepad = static_cast<int>(k);\n                        break;\n                    }\n                    else if (!mGamePad[k])\n                    {\n                        if (empty >= MAX_PLAYER_COUNT)\n                            empty = k;\n                    }\n                }\n\n                if (k >= MAX_PLAYER_COUNT)\n                {\n                    if (empty >= MAX_PLAYER_COUNT)\n                    {\n                        throw std::exception(\"Too many gamepads found\");\n                    }\n\n                    mGamePad[empty] = pad;\n                    if (!j)\n                        mMostRecentGamepad = static_cast<int>(empty);\n                }\n            }\n        }\n    }\n\n    ComPtr<ABI::Windows::Xbox::Input::IGamepadStatics> mStatics;\n    ComPtr<ABI::Windows::Xbox::Input::IControllerStatics> mStaticsCtrl;\n    ComPtr<ABI::Windows::Xbox::Input::IGamepad> mGamePad[MAX_PLAYER_COUNT];\n\n    EventRegistrationToken mAddedToken;\n    EventRegistrationToken mRemovedToken;\n    EventRegistrationToken mUserParingToken;\n\n    ScopedHandle mChanged;\n};\n\nGamePad::Impl* GamePad::Impl::s_gamePad = nullptr;\n\n#else\n\n//======================================================================================\n// XInput\n//======================================================================================\n\n#include <Xinput.h>\n\nstatic_assert(GamePad::MAX_PLAYER_COUNT == XUSER_MAX_COUNT, \"xinput.h mismatch\");\n\nclass GamePad::Impl\n{\npublic:\n    Impl(GamePad* owner) :\n        mOwner(owner),\n        mConnected{},\n        mLastReadTime{}\n    #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)\n        , mLeftMotor{}\n        , mRightMotor{}\n        , mSuspended(false)\n    #endif\n    {\n        for (int j = 0; j < XUSER_MAX_COUNT; ++j)\n        {\n            ClearSlot(j, 0);\n        }\n\n        if (s_gamePad)\n        {\n            throw std::exception(\"GamePad is a singleton\");\n        }\n\n        s_gamePad = this;\n    }\n\n    ~Impl()\n    {\n        s_gamePad = nullptr;\n    }\n\n    void GetState(int player, _Out_ State& state, DeadZone deadZoneMode)\n    {\n        if (player == -1)\n            player = GetMostRecent();\n\n        ULONGLONG time = GetTickCount64();\n\n        if (!ThrottleRetry(player, time))\n        {\n        #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)\n            if (mSuspended)\n            {\n                memset(&state, 0, sizeof(State));\n                state.connected = mConnected[player];\n                return;\n            }\n        #endif\n\n            XINPUT_STATE xstate;\n            DWORD result = XInputGetState(DWORD(player), &xstate);\n            if (result == ERROR_DEVICE_NOT_CONNECTED)\n            {\n                ClearSlot(player, time);\n            }\n            else\n            {\n                if (!mConnected[player])\n                    mLastReadTime[player] = time;\n\n                mConnected[player] = true;\n\n                state.connected = true;\n                state.packet = xstate.dwPacketNumber;\n\n                WORD xbuttons = xstate.Gamepad.wButtons;\n                state.buttons.a = (xbuttons & XINPUT_GAMEPAD_A) != 0;\n                state.buttons.b = (xbuttons & XINPUT_GAMEPAD_B) != 0;\n                state.buttons.x = (xbuttons & XINPUT_GAMEPAD_X) != 0;\n                state.buttons.y = (xbuttons & XINPUT_GAMEPAD_Y) != 0;\n                state.buttons.leftStick = (xbuttons & XINPUT_GAMEPAD_LEFT_THUMB) != 0;\n                state.buttons.rightStick = (xbuttons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0;\n                state.buttons.leftShoulder = (xbuttons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0;\n                state.buttons.rightShoulder = (xbuttons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0;\n                state.buttons.back = (xbuttons & XINPUT_GAMEPAD_BACK) != 0;\n                state.buttons.start = (xbuttons & XINPUT_GAMEPAD_START) != 0;\n\n                state.dpad.up = (xbuttons & XINPUT_GAMEPAD_DPAD_UP) != 0;\n                state.dpad.down = (xbuttons & XINPUT_GAMEPAD_DPAD_DOWN) != 0;\n                state.dpad.right = (xbuttons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0;\n                state.dpad.left = (xbuttons & XINPUT_GAMEPAD_DPAD_LEFT) != 0;\n\n                if (deadZoneMode == DEAD_ZONE_NONE)\n                {\n                    state.triggers.left = ApplyLinearDeadZone(float(xstate.Gamepad.bLeftTrigger), 255.f, 0.f);\n                    state.triggers.right = ApplyLinearDeadZone(float(xstate.Gamepad.bRightTrigger), 255.f, 0.f);\n                }\n                else\n                {\n                    state.triggers.left = ApplyLinearDeadZone(float(xstate.Gamepad.bLeftTrigger), 255.f, float(XINPUT_GAMEPAD_TRIGGER_THRESHOLD));\n                    state.triggers.right = ApplyLinearDeadZone(float(xstate.Gamepad.bRightTrigger), 255.f, float(XINPUT_GAMEPAD_TRIGGER_THRESHOLD));\n                }\n\n                ApplyStickDeadZone(float(xstate.Gamepad.sThumbLX), float(xstate.Gamepad.sThumbLY),\n                                   deadZoneMode, 32767.f, float(XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE),\n                                   state.thumbSticks.leftX, state.thumbSticks.leftY);\n\n                ApplyStickDeadZone(float(xstate.Gamepad.sThumbRX), float(xstate.Gamepad.sThumbRY),\n                                   deadZoneMode, 32767.f, float(XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE),\n                                   state.thumbSticks.rightX, state.thumbSticks.rightY);\n\n                return;\n            }\n        }\n\n        memset(&state, 0, sizeof(State));\n    }\n\n    void GetCapabilities(int player, _Out_ Capabilities& caps)\n    {\n        if (player == -1)\n            player = GetMostRecent();\n\n        ULONGLONG time = GetTickCount64();\n\n        if (!ThrottleRetry(player, time))\n        {\n            XINPUT_CAPABILITIES xcaps;\n            DWORD result = XInputGetCapabilities(DWORD(player), 0, &xcaps);\n            if (result == ERROR_DEVICE_NOT_CONNECTED)\n            {\n                ClearSlot(player, time);\n            }\n            else\n            {\n                if (!mConnected[player])\n                    mLastReadTime[player] = time;\n\n                mConnected[player] = true;\n\n                caps.connected = true;\n                caps.id = uint64_t(player);\n                if (xcaps.Type == XINPUT_DEVTYPE_GAMEPAD)\n                {\n                    static_assert(Capabilities::GAMEPAD == XINPUT_DEVSUBTYPE_GAMEPAD, \"xinput.h mismatch\");\n                #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n                    static_assert(XINPUT_DEVSUBTYPE_WHEEL == Capabilities::WHEEL, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_ARCADE_STICK == Capabilities::ARCADE_STICK, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_FLIGHT_STICK == Capabilities::FLIGHT_STICK, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_DANCE_PAD == Capabilities::DANCE_PAD, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_GUITAR == Capabilities::GUITAR, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE == Capabilities::GUITAR_ALTERNATE, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_DRUM_KIT == Capabilities::DRUM_KIT, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_GUITAR_BASS == Capabilities::GUITAR_BASS, \"xinput.h mismatch\");\n                    static_assert(XINPUT_DEVSUBTYPE_ARCADE_PAD == Capabilities::ARCADE_PAD, \"xinput.h mismatch\");\n                #endif\n\n                    caps.gamepadType = Capabilities::Type(xcaps.SubType);\n                }\n\n                // Hard-coded VID/PID\n                caps.vid = 0x045E;\n            #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n                caps.pid = (xcaps.Flags & XINPUT_CAPS_WIRELESS) ? 0x0719 : 0;\n            #else\n                caps.pid = 0;\n            #endif\n\n                return;\n            }\n        }\n\n        memset(&caps, 0, sizeof(Capabilities));\n    }\n\n    bool SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) noexcept\n    {\n        if (player == -1)\n            player = GetMostRecent();\n\n        ULONGLONG time = GetTickCount64();\n\n        if (ThrottleRetry(player, time))\n        {\n            return false;\n        }\n\n        // XInput does not provide a way to set the left/right trigger impulse motors on the Xbox One Controller,\n        // and these motors are not present on the Xbox 360 Common Controller\n        UNREFERENCED_PARAMETER(leftTrigger);\n        UNREFERENCED_PARAMETER(rightTrigger);\n\n    #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)\n        mLeftMotor[player] = leftMotor;\n        mRightMotor[player] = rightMotor;\n\n        if (mSuspended)\n            return mConnected[player];\n    #endif\n\n        XINPUT_VIBRATION xvibration;\n        xvibration.wLeftMotorSpeed = WORD(leftMotor * 0xFFFF);\n        xvibration.wRightMotorSpeed = WORD(rightMotor * 0xFFFF);\n        DWORD result = XInputSetState(DWORD(player), &xvibration);\n        if (result == ERROR_DEVICE_NOT_CONNECTED)\n        {\n            ClearSlot(player, time);\n            return false;\n        }\n        else\n        {\n            if (!mConnected[player])\n                mLastReadTime[player] = time;\n\n            mConnected[player] = true;\n            return (result == ERROR_SUCCESS);\n        }\n    }\n\n    void Suspend() noexcept\n    {\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n        // XInput focus is handled automatically on Windows 10\n    #elif (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n        XInputEnable(FALSE);\n    #else\n        // For XInput 9.1.0, we have to emulate the behavior of XInputEnable( FALSE )\n        if (!mSuspended)\n        {\n            for (size_t j = 0; j < XUSER_MAX_COUNT; ++j)\n            {\n                if (mConnected[j])\n                {\n                    XINPUT_VIBRATION xvibration;\n                    xvibration.wLeftMotorSpeed = xvibration.wRightMotorSpeed = 0;\n                    (void)XInputSetState(DWORD(j), &xvibration);\n                }\n            }\n\n            mSuspended = true;\n        }\n    #endif\n    }\n\n    void Resume() noexcept\n    {\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n        // XInput focus is handled automatically on Windows 10\n    #elif (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n        XInputEnable(TRUE);\n    #else\n        // For XInput 9.1.0, we have to emulate the behavior of XInputEnable( TRUE )\n        if (mSuspended)\n        {\n            ULONGLONG time = GetTickCount64();\n\n            for (int j = 0; j < XUSER_MAX_COUNT; ++j)\n            {\n                if (mConnected[j])\n                {\n                    XINPUT_VIBRATION xvibration;\n                    xvibration.wLeftMotorSpeed = WORD(mLeftMotor[j] * 0xFFFF);\n                    xvibration.wRightMotorSpeed = WORD(mRightMotor[j] * 0xFFFF);\n                    DWORD result = XInputSetState(DWORD(j), &xvibration);\n                    if (result == ERROR_DEVICE_NOT_CONNECTED)\n                    {\n                        ClearSlot(j, time);\n                    }\n                }\n            }\n\n            mSuspended = false;\n        }\n    #endif\n    }\n\n    GamePad*    mOwner;\n\n    static GamePad::Impl* s_gamePad;\n\nprivate:\n    bool        mConnected[XUSER_MAX_COUNT];\n    ULONGLONG   mLastReadTime[XUSER_MAX_COUNT];\n\n#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)\n    // Variables for emulating XInputEnable on XInput 9.1.0\n    float       mLeftMotor[XUSER_MAX_COUNT];\n    float       mRightMotor[XUSER_MAX_COUNT];\n    bool        mSuspended;\n#endif\n\n    bool ThrottleRetry(int player, ULONGLONG time)\n    {\n        // This function minimizes a potential performance issue with XInput on Windows when\n        // checking a disconnected controller slot which requires device enumeration.\n        // This throttling keeps checks for newly connected gamepads to about once a second\n\n        if ((player < 0) || (player >= XUSER_MAX_COUNT))\n            return true;\n\n        if (mConnected[player])\n            return false;\n\n        for (int j = 0; j < XUSER_MAX_COUNT; ++j)\n        {\n            if (!mConnected[j])\n            {\n                LONGLONG delta = LONGLONG(time) - LONGLONG(mLastReadTime[j]);\n\n                LONGLONG interval = 1000;\n                if (j != player)\n                    interval /= 4;\n\n                if ((delta >= 0) && (delta < interval))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    void ClearSlot(int player, ULONGLONG time)\n    {\n        mConnected[player] = false;\n        mLastReadTime[player] = time;\n    #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)\n        mLeftMotor[player] = mRightMotor[player] = 0.f;\n    #endif\n    }\n\n    int GetMostRecent()\n    {\n        int player = -1;\n        ULONGLONG time = 0;\n\n        for (size_t j = 0; j < XUSER_MAX_COUNT; ++j)\n        {\n            if (mConnected[j] && (mLastReadTime[j] > time))\n            {\n                time = mLastReadTime[j];\n                player = static_cast<int>(j);\n            }\n        }\n\n        return player;\n    }\n};\n\nGamePad::Impl* GamePad::Impl::s_gamePad = nullptr;\n\n#endif\n\n#pragma warning( disable : 4355 )\n\n// Public constructor.\nGamePad::GamePad() noexcept(false)\n    : pImpl(std::make_unique<Impl>(this))\n{\n}\n\n\n// Move constructor.\nGamePad::GamePad(GamePad&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n    pImpl->mOwner = this;\n}\n\n\n// Move assignment.\nGamePad& GamePad::operator= (GamePad&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    pImpl->mOwner = this;\n    return *this;\n}\n\n\n// Public destructor.\nGamePad::~GamePad()\n{\n}\n\n\nGamePad::State GamePad::GetState(int player, DeadZone deadZoneMode)\n{\n    State state;\n    pImpl->GetState(player, state, deadZoneMode);\n    return state;\n}\n\n\nGamePad::Capabilities GamePad::GetCapabilities(int player)\n{\n    Capabilities caps;\n    pImpl->GetCapabilities(player, caps);\n    return caps;\n}\n\n\nbool GamePad::SetVibration(int player, float leftMotor, float rightMotor, float leftTrigger, float rightTrigger) noexcept\n{\n    return pImpl->SetVibration(player, leftMotor, rightMotor, leftTrigger, rightTrigger);\n}\n\n\nvoid GamePad::Suspend() noexcept\n{\n    pImpl->Suspend();\n}\n\n\nvoid GamePad::Resume() noexcept\n{\n    pImpl->Resume();\n}\n\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)\nvoid GamePad::RegisterEvents(HANDLE ctrlChanged) noexcept\n{\n    pImpl->mCtrlChanged = (!ctrlChanged) ? INVALID_HANDLE_VALUE : ctrlChanged;\n}\n\nvoid GamePad::GetDevice(int player, _Outptr_ IGameInputDevice** device) noexcept\n{\n    pImpl->GetDevice(player, device);\n}\n#elif ((_WIN32_WINNT >= _WIN32_WINNT_WIN10) && !defined(_GAMING_DESKTOP)) || defined(_XBOX_ONE)\nvoid GamePad::RegisterEvents(HANDLE ctrlChanged, HANDLE userChanged) noexcept\n{\n    pImpl->mCtrlChanged = (!ctrlChanged) ? INVALID_HANDLE_VALUE : ctrlChanged;\n    pImpl->mUserChanged = (!userChanged) ? INVALID_HANDLE_VALUE : userChanged;\n}\n#endif\n\n\nGamePad& GamePad::Get()\n{\n    if (!Impl::s_gamePad || !Impl::s_gamePad->mOwner)\n        throw std::exception(\"GamePad is a singleton\");\n\n    return *Impl::s_gamePad->mOwner;\n}\n\n\n\n//======================================================================================\n// ButtonStateTracker\n//======================================================================================\n\n#define UPDATE_BUTTON_STATE(field) field = static_cast<ButtonState>( ( !!state.buttons.field ) | ( ( !!state.buttons.field ^ !!lastState.buttons.field ) << 1 ) );\n\nvoid GamePad::ButtonStateTracker::Update(const GamePad::State& state) noexcept\n{\n    UPDATE_BUTTON_STATE(a)\n\n    assert((!state.buttons.a && !lastState.buttons.a) == (a == UP));\n    assert((state.buttons.a && lastState.buttons.a) == (a == HELD));\n    assert((!state.buttons.a && lastState.buttons.a) == (a == RELEASED));\n    assert((state.buttons.a && !lastState.buttons.a) == (a == PRESSED));\n\n    UPDATE_BUTTON_STATE(b)\n    UPDATE_BUTTON_STATE(x)\n    UPDATE_BUTTON_STATE(y)\n\n    UPDATE_BUTTON_STATE(leftStick)\n    UPDATE_BUTTON_STATE(rightStick)\n\n    UPDATE_BUTTON_STATE(leftShoulder)\n    UPDATE_BUTTON_STATE(rightShoulder)\n\n    UPDATE_BUTTON_STATE(back)\n    UPDATE_BUTTON_STATE(start)\n\n    dpadUp = static_cast<ButtonState>((!!state.dpad.up) | ((!!state.dpad.up ^ !!lastState.dpad.up) << 1));\n    dpadDown = static_cast<ButtonState>((!!state.dpad.down) | ((!!state.dpad.down ^ !!lastState.dpad.down) << 1));\n    dpadLeft = static_cast<ButtonState>((!!state.dpad.left) | ((!!state.dpad.left ^ !!lastState.dpad.left) << 1));\n    dpadRight = static_cast<ButtonState>((!!state.dpad.right) | ((!!state.dpad.right ^ !!lastState.dpad.right) << 1));\n\n    assert((!state.dpad.up && !lastState.dpad.up) == (dpadUp == UP));\n    assert((state.dpad.up && lastState.dpad.up) == (dpadUp == HELD));\n    assert((!state.dpad.up && lastState.dpad.up) == (dpadUp == RELEASED));\n    assert((state.dpad.up && !lastState.dpad.up) == (dpadUp == PRESSED));\n\n    // Handle 'threshold' tests which emulate buttons\n\n    bool threshold = state.IsLeftThumbStickUp();\n    leftStickUp = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsLeftThumbStickUp()) << 1));\n\n    threshold = state.IsLeftThumbStickDown();\n    leftStickDown = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsLeftThumbStickDown()) << 1));\n\n    threshold = state.IsLeftThumbStickLeft();\n    leftStickLeft = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsLeftThumbStickLeft()) << 1));\n\n    threshold = state.IsLeftThumbStickRight();\n    leftStickRight = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsLeftThumbStickRight()) << 1));\n\n    threshold = state.IsRightThumbStickUp();\n    rightStickUp = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsRightThumbStickUp()) << 1));\n\n    threshold = state.IsRightThumbStickDown();\n    rightStickDown = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsRightThumbStickDown()) << 1));\n\n    threshold = state.IsRightThumbStickLeft();\n    rightStickLeft = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsRightThumbStickLeft()) << 1));\n\n    threshold = state.IsRightThumbStickRight();\n    rightStickRight = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsRightThumbStickRight()) << 1));\n\n    threshold = state.IsLeftTriggerPressed();\n    leftTrigger = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsLeftTriggerPressed()) << 1));\n\n    threshold = state.IsRightTriggerPressed();\n    rightTrigger = static_cast<ButtonState>((!!threshold) | ((!!threshold ^ !!lastState.IsRightTriggerPressed()) << 1));\n\n    lastState = state;\n}\n\n#undef UPDATE_BUTTON_STATE\n\n\nvoid GamePad::ButtonStateTracker::Reset() noexcept\n{\n    memset(this, 0, sizeof(ButtonStateTracker));\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/GeometricPrimitive.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: GeometricPrimitive.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"GeometricPrimitive.h\"\n\n#include \"CommonStates.h\"\n#include \"DirectXHelpers.h\"\n#include \"Effects.h\"\n#include \"Geometry.h\"\n#include \"GraphicsMemory.h\"\n#include \"PlatformHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n// Internal GeometricPrimitive implementation class.\nclass GeometricPrimitive::Impl\n{\npublic:\n    Impl() noexcept : mIndexCount(0), mVertexBufferView{}, mIndexBufferView{} {}\n\n    void Initialize(const VertexCollection& vertices, const IndexCollection& indices, _In_opt_ ID3D12Device* device);\n\n    void LoadStaticBuffers(\n        _In_ ID3D12Device* device,\n        ResourceUploadBatch& resourceUploadBatch);\n\n    void Transition(\n        _In_ ID3D12GraphicsCommandList* commandList,\n        D3D12_RESOURCE_STATES stateBeforeVB,\n        D3D12_RESOURCE_STATES stateAfterVB,\n        D3D12_RESOURCE_STATES stateBeforeIB,\n        D3D12_RESOURCE_STATES stateAfterIB);\n\n    void Draw(_In_ ID3D12GraphicsCommandList* commandList) const;\n    \n    UINT                        mIndexCount;\n    SharedGraphicsResource      mIndexBuffer;\n    SharedGraphicsResource      mVertexBuffer;\n    ComPtr<ID3D12Resource>      mStaticIndexBuffer;\n    ComPtr<ID3D12Resource>      mStaticVertexBuffer;\n    D3D12_VERTEX_BUFFER_VIEW    mVertexBufferView;\n    D3D12_INDEX_BUFFER_VIEW     mIndexBufferView;\n};\n\n\n// Initializes a geometric primitive instance that will draw the specified vertex and index data.\nvoid GeometricPrimitive::Impl::Initialize(\n    const VertexCollection& vertices,\n    const IndexCollection& indices,\n    _In_opt_ ID3D12Device* device)\n{\n    if (vertices.size() >= USHRT_MAX)\n        throw std::exception(\"Too many vertices for 16-bit index buffer\");\n\n    if (indices.size() > UINT32_MAX)\n        throw std::exception(\"Too many indices\");\n\n    // Vertex data\n    uint64_t sizeInBytes = uint64_t(vertices.size()) * sizeof(vertices[0]);\n    if (sizeInBytes > uint64_t(D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n        throw std::exception(\"VB too large for DirectX 12\");\n\n    auto vertSizeBytes = static_cast<size_t>(sizeInBytes);\n\n    mVertexBuffer = GraphicsMemory::Get(device).Allocate(vertSizeBytes);\n\n    auto verts = reinterpret_cast<const uint8_t*>(vertices.data());\n    memcpy(mVertexBuffer.Memory(), verts, vertSizeBytes);\n\n    // Index data\n    sizeInBytes = uint64_t(indices.size()) * sizeof(indices[0]);\n    if (sizeInBytes > uint64_t(D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n        throw std::exception(\"IB too large for DirectX 12\");\n\n    auto indSizeBytes = static_cast<size_t>(sizeInBytes);\n\n    mIndexBuffer = GraphicsMemory::Get(device).Allocate(indSizeBytes);\n\n    auto ind = reinterpret_cast<const uint8_t*>(indices.data());\n    memcpy(mIndexBuffer.Memory(), ind, indSizeBytes);\n\n    // Record index count for draw\n    mIndexCount = static_cast<UINT>(indices.size());\n\n    // Create views\n    mVertexBufferView.BufferLocation = mVertexBuffer.GpuAddress();\n    mVertexBufferView.StrideInBytes = static_cast<UINT>(sizeof(VertexCollection::value_type));\n    mVertexBufferView.SizeInBytes = static_cast<UINT>(mVertexBuffer.Size());\n\n    mIndexBufferView.BufferLocation = mIndexBuffer.GpuAddress();\n    mIndexBufferView.SizeInBytes = static_cast<UINT>(mIndexBuffer.Size());\n    mIndexBufferView.Format = DXGI_FORMAT_R16_UINT;\n}\n\n\n// Load VB/IB resources for static geometry.\n_Use_decl_annotations_\nvoid GeometricPrimitive::Impl::LoadStaticBuffers(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUploadBatch)\n{\n    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    // Convert dynamic VB to static VB\n    if (!mStaticVertexBuffer)\n    {\n        assert(mVertexBuffer);\n\n        auto desc = CD3DX12_RESOURCE_DESC::Buffer(mVertexBuffer.Size());\n\n        ThrowIfFailed(device->CreateCommittedResource(\n            &heapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &desc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(mStaticVertexBuffer.GetAddressOf())\n        ));\n\n        SetDebugObjectName(mStaticVertexBuffer.Get(), L\"GeometricPrimitive\");\n\n        resourceUploadBatch.Upload(mStaticVertexBuffer.Get(), mVertexBuffer);\n\n        resourceUploadBatch.Transition(mStaticVertexBuffer.Get(),\n            D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);\n\n        // Update view\n        mVertexBufferView.BufferLocation = mStaticVertexBuffer->GetGPUVirtualAddress();\n\n        mVertexBuffer.Reset();\n    }\n\n    // Convert dynamic IB to static IB\n    if (!mStaticIndexBuffer)\n    {\n        assert(mIndexBuffer);\n\n        auto desc = CD3DX12_RESOURCE_DESC::Buffer(mIndexBuffer.Size());\n\n        ThrowIfFailed(device->CreateCommittedResource(\n            &heapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &desc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(mStaticIndexBuffer.GetAddressOf())\n        ));\n\n        SetDebugObjectName(mStaticIndexBuffer.Get(), L\"GeometricPrimitive\");\n\n        resourceUploadBatch.Upload(mStaticIndexBuffer.Get(), mIndexBuffer);\n\n        resourceUploadBatch.Transition(mStaticIndexBuffer.Get(),\n            D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);\n\n        // Update view\n        mIndexBufferView.BufferLocation = mStaticIndexBuffer->GetGPUVirtualAddress();\n\n        mIndexBuffer.Reset();\n    }\n}\n\n\n// Transition VB/IB resources for static geometry.\n_Use_decl_annotations_\nvoid GeometricPrimitive::Impl::Transition(\n    ID3D12GraphicsCommandList* commandList,\n    D3D12_RESOURCE_STATES stateBeforeVB,\n    D3D12_RESOURCE_STATES stateAfterVB,\n    D3D12_RESOURCE_STATES stateBeforeIB,\n    D3D12_RESOURCE_STATES stateAfterIB)\n{\n    UINT start = 0;\n    UINT count = 0;\n\n    D3D12_RESOURCE_BARRIER barrier[2] = {};\n    barrier[0].Type = barrier[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    barrier[0].Transition.Subresource = barrier[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n    barrier[0].Transition.pResource = mStaticIndexBuffer.Get();\n    barrier[0].Transition.StateBefore = stateBeforeIB;\n    barrier[0].Transition.StateAfter = stateAfterIB;\n\n    barrier[1].Transition.pResource = mStaticVertexBuffer.Get();\n    barrier[1].Transition.StateBefore = stateBeforeVB;\n    barrier[1].Transition.StateAfter = stateAfterVB;\n\n    if (stateBeforeIB == stateAfterIB || !mStaticIndexBuffer)\n    {\n        ++start;\n    }\n    else\n    {\n        ++count;\n    }\n\n    if (stateBeforeVB != stateAfterVB && mStaticVertexBuffer)\n    {\n        ++count;\n    }\n\n    if (count > 0)\n    {\n        commandList->ResourceBarrier(count, &barrier[start]);\n    }\n}\n\n\n// Draws the primitive.\n_Use_decl_annotations_\nvoid GeometricPrimitive::Impl::Draw(ID3D12GraphicsCommandList* commandList) const\n{\n    commandList->IASetVertexBuffers(0, 1, &mVertexBufferView);\n    commandList->IASetIndexBuffer(&mIndexBufferView);\n    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n\n    commandList->DrawIndexedInstanced(mIndexCount, 1, 0, 0, 0);\n}\n\n//--------------------------------------------------------------------------------------\n// GeometricPrimitive\n//--------------------------------------------------------------------------------------\n\n// Constructor.\nGeometricPrimitive::GeometricPrimitive() noexcept(false)\n    : pImpl(std::make_unique<Impl>())\n{\n}\n\n\n// Destructor.\nGeometricPrimitive::~GeometricPrimitive()\n{\n}\n\n\n// Public entrypoints.\n_Use_decl_annotations_\nvoid GeometricPrimitive::LoadStaticBuffers(ID3D12Device* device, ResourceUploadBatch& resourceUploadBatch)\n{\n    pImpl->LoadStaticBuffers(device, resourceUploadBatch);\n}\n\n\nvoid GeometricPrimitive::Transition(\n    _In_ ID3D12GraphicsCommandList* commandList,\n    D3D12_RESOURCE_STATES stateBeforeVB,\n    D3D12_RESOURCE_STATES stateAfterVB,\n    D3D12_RESOURCE_STATES stateBeforeIB,\n    D3D12_RESOURCE_STATES stateAfterIB)\n{\n    pImpl->Transition(commandList, stateBeforeVB, stateAfterVB, stateBeforeIB, stateAfterIB);\n}\n\n\n\n_Use_decl_annotations_\nvoid GeometricPrimitive::Draw(ID3D12GraphicsCommandList* commandList) const\n{\n    pImpl->Draw(commandList);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Cube (aka a Hexahedron) or Box\n//--------------------------------------------------------------------------------------\n\n// Creates a cube primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateCube(\n    float size,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeBox(vertices, indices, XMFLOAT3(size, size, size), rhcoords, false);\n\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateCube(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float size,\n    bool rhcoords)\n{\n    ComputeBox(vertices, indices, XMFLOAT3(size, size, size), rhcoords, false);\n}\n\n\n// Creates a box primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateBox(\n    const XMFLOAT3& size,\n    bool rhcoords,\n    bool invertn,\n    _In_opt_ ID3D12Device* device)\n{\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeBox(vertices, indices, size, rhcoords, invertn);\n\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateBox(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    const XMFLOAT3& size,\n    bool rhcoords,\n    bool invertn)\n{\n    ComputeBox(vertices, indices, size, rhcoords, invertn);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Sphere\n//--------------------------------------------------------------------------------------\n\n// Creates a sphere primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateSphere(\n    float diameter,\n    size_t tessellation,\n    bool rhcoords,\n    bool invertn,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n\n    ComputeSphere(vertices, indices, diameter, tessellation, rhcoords, invertn);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateSphere(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices, \n    float diameter,\n    size_t tessellation,\n    bool rhcoords,\n    bool invertn)\n{\n    ComputeSphere(vertices, indices, diameter, tessellation, rhcoords, invertn);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Geodesic sphere\n//--------------------------------------------------------------------------------------\n\n// Creates a geosphere primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateGeoSphere(\n    float diameter,\n    size_t tessellation,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeGeoSphere(vertices, indices, diameter, tessellation, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateGeoSphere(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float diameter,\n    size_t tessellation,\n    bool rhcoords)\n{\n    ComputeGeoSphere(vertices, indices, diameter, tessellation, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Cylinder / Cone\n//--------------------------------------------------------------------------------------\n\n// Creates a cylinder primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateCylinder(\n    float height,\n    float diameter,\n    size_t tessellation,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeCylinder(vertices, indices, height, diameter, tessellation, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateCylinder(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float height, float diameter,\n    size_t tessellation,\n    bool rhcoords)\n{\n    ComputeCylinder(vertices, indices, height, diameter, tessellation, rhcoords);\n}\n\n\n// Creates a cone primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateCone(\n    float diameter,\n    float height,\n    size_t tessellation,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeCone(vertices, indices, diameter, height, tessellation, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateCone(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float diameter,\n    float height, \n    size_t tessellation,\n    bool rhcoords)\n{\n    ComputeCone(vertices, indices, diameter, height, tessellation, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Torus\n//--------------------------------------------------------------------------------------\n\n// Creates a torus primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateTorus(\n    float diameter,\n    float thickness,\n    size_t tessellation,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\t\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeTorus(vertices, indices, diameter, thickness, tessellation, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateTorus(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float diameter,\n    float thickness,\n    size_t tessellation,\n    bool rhcoords)\n{\n    ComputeTorus(vertices, indices, diameter, thickness, tessellation, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Tetrahedron\n//--------------------------------------------------------------------------------------\n\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateTetrahedron(\n    float size,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeTetrahedron(vertices, indices, size, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateTetrahedron(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float size,\n    bool rhcoords)\n{\n    ComputeTetrahedron(vertices, indices, size, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Octahedron\n//--------------------------------------------------------------------------------------\n\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateOctahedron(\n    float size,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeOctahedron(vertices, indices, size, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateOctahedron(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float size,\n    bool rhcoords)\n{\n    ComputeOctahedron(vertices, indices, size, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Dodecahedron\n//--------------------------------------------------------------------------------------\n\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateDodecahedron(\n    float size,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeDodecahedron(vertices, indices, size, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateDodecahedron(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float size,\n    bool rhcoords)\n{\n    ComputeDodecahedron(vertices, indices, size, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Icosahedron\n//--------------------------------------------------------------------------------------\n\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateIcosahedron(\n    float size,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeIcosahedron(vertices, indices, size, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateIcosahedron(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float size,\n    bool rhcoords)\n{\n    ComputeIcosahedron(vertices, indices, size, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Teapot\n//--------------------------------------------------------------------------------------\n\n// Creates a teapot primitive.\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateTeapot(\n    float size,\n    size_t tessellation,\n    bool rhcoords,\n    _In_opt_ ID3D12Device* device)\n{\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    VertexCollection vertices;\n    IndexCollection indices;\n    ComputeTeapot(vertices, indices, size, tessellation, rhcoords);\n\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n\nvoid GeometricPrimitive::CreateTeapot(\n    std::vector<VertexType>& vertices,\n    std::vector<uint16_t>& indices,\n    float size, size_t tessellation,\n    bool rhcoords)\n{\n    ComputeTeapot(vertices, indices, size, tessellation, rhcoords);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Custom\n//--------------------------------------------------------------------------------------\n\nstd::unique_ptr<GeometricPrimitive> GeometricPrimitive::CreateCustom(\n    const std::vector<VertexType>& vertices,\n    const std::vector<uint16_t>& indices,\n    _In_opt_ ID3D12Device* device)\n{\n    // Extra validation\n    if (vertices.empty() || indices.empty())\n        throw std::exception(\"Requires both vertices and indices\");\n\n    if (indices.size() % 3)\n        throw std::exception(\"Expected triangular faces\");\n\n    size_t nVerts = vertices.size();\n    if (nVerts >= USHRT_MAX)\n        throw std::exception(\"Too many vertices for 16-bit index buffer\");\n\n    for (auto it = indices.cbegin(); it != indices.cend(); ++it)\n    {\n        if (*it >= nVerts)\n        {\n            throw std::exception(\"Index not in vertices list\");\n        }\n    }\n    // Create the primitive object.\n    std::unique_ptr<GeometricPrimitive> primitive(new GeometricPrimitive());\n\n    // copy geometry\n    primitive->pImpl->Initialize(vertices, indices, device);\n\n    return primitive;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Geometry.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: Geometry.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Geometry.h\"\n#include \"Bezier.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    constexpr float SQRT2 = 1.41421356237309504880f;\n    constexpr float SQRT3 = 1.73205080756887729352f;\n    constexpr float SQRT6 = 2.44948974278317809820f;\n\n    inline void CheckIndexOverflow(size_t value)\n    {\n        // Use >=, not > comparison, because some D3D level 9_x hardware does not support 0xFFFF index values.\n        if (value >= USHRT_MAX)\n            throw std::exception(\"Index value out of range: cannot tesselate primitive so finely\");\n    }\n\n\n    // Collection types used when generating the geometry.\n    inline void index_push_back(IndexCollection& indices, size_t value)\n    {\n        CheckIndexOverflow(value);\n        indices.push_back(static_cast<uint16_t>(value));\n    }\n\n\n    // Helper for flipping winding of geometric primitives for LH vs. RH coords\n    inline void ReverseWinding(IndexCollection& indices, VertexCollection& vertices)\n    {\n        assert((indices.size() % 3) == 0);\n        for (auto it = indices.begin(); it != indices.end(); it += 3)\n        {\n            std::swap(*it, *(it + 2));\n        }\n\n        for (auto it = vertices.begin(); it != vertices.end(); ++it)\n        {\n            it->textureCoordinate.x = (1.f - it->textureCoordinate.x);\n        }\n    }\n\n\n    // Helper for inverting normals of geometric primitives for 'inside' vs. 'outside' viewing\n    inline void InvertNormals(VertexCollection& vertices)\n    {\n        for (auto it = vertices.begin(); it != vertices.end(); ++it)\n        {\n            it->normal.x = -it->normal.x;\n            it->normal.y = -it->normal.y;\n            it->normal.z = -it->normal.z;\n        }\n    }\n}\n\n\n//--------------------------------------------------------------------------------------\n// Cube (aka a Hexahedron) or Box\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeBox(VertexCollection& vertices, IndexCollection& indices, const XMFLOAT3& size, bool rhcoords, bool invertn)\n{\n    vertices.clear();\n    indices.clear();\n\n    // A box has six faces, each one pointing in a different direction.\n    constexpr int FaceCount = 6;\n\n    static const XMVECTORF32 faceNormals[FaceCount] =\n    {\n        { { {  0,  0,  1, 0 } } },\n        { { {  0,  0, -1, 0 } } },\n        { { {  1,  0,  0, 0 } } },\n        { { { -1,  0,  0, 0 } } },\n        { { {  0,  1,  0, 0 } } },\n        { { {  0, -1,  0, 0 } } },\n    };\n\n    static const XMVECTORF32 textureCoordinates[4] =\n    {\n        { { { 1, 0, 0, 0 } } },\n        { { { 1, 1, 0, 0 } } },\n        { { { 0, 1, 0, 0 } } },\n        { { { 0, 0, 0, 0 } } },\n    };\n\n    XMVECTOR tsize = XMLoadFloat3(&size);\n    tsize = XMVectorDivide(tsize, g_XMTwo);\n\n    // Create each face in turn.\n    for (int i = 0; i < FaceCount; i++)\n    {\n        XMVECTOR normal = faceNormals[i];\n\n        // Get two vectors perpendicular both to the face normal and to each other.\n        XMVECTOR basis = (i >= 4) ? g_XMIdentityR2 : g_XMIdentityR1;\n\n        XMVECTOR side1 = XMVector3Cross(normal, basis);\n        XMVECTOR side2 = XMVector3Cross(normal, side1);\n\n        // Six indices (two triangles) per face.\n        size_t vbase = vertices.size();\n        index_push_back(indices, vbase + 0);\n        index_push_back(indices, vbase + 1);\n        index_push_back(indices, vbase + 2);\n\n        index_push_back(indices, vbase + 0);\n        index_push_back(indices, vbase + 2);\n        index_push_back(indices, vbase + 3);\n\n        // Four vertices per face.\n        // (normal - side1 - side2) * tsize // normal // t0\n        vertices.push_back(VertexPositionNormalTexture(XMVectorMultiply(XMVectorSubtract(XMVectorSubtract(normal, side1), side2), tsize), normal, textureCoordinates[0]));\n\n        // (normal - side1 + side2) * tsize // normal // t1\n        vertices.push_back(VertexPositionNormalTexture(XMVectorMultiply(XMVectorAdd(XMVectorSubtract(normal, side1), side2), tsize), normal, textureCoordinates[1]));\n\n        // (normal + side1 + side2) * tsize // normal // t2\n        vertices.push_back(VertexPositionNormalTexture(XMVectorMultiply(XMVectorAdd(normal, XMVectorAdd(side1, side2)), tsize), normal, textureCoordinates[2]));\n\n        // (normal + side1 - side2) * tsize // normal // t3\n        vertices.push_back(VertexPositionNormalTexture(XMVectorMultiply(XMVectorSubtract(XMVectorAdd(normal, side1), side2), tsize), normal, textureCoordinates[3]));\n    }\n\n    // Build RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n\n    if (invertn)\n        InvertNormals(vertices);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Sphere\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeSphere(VertexCollection& vertices, IndexCollection& indices, float diameter, size_t tessellation, bool rhcoords, bool invertn)\n{\n    vertices.clear();\n    indices.clear();\n\n    if (tessellation < 3)\n        throw std::out_of_range(\"tesselation parameter out of range\");\n\n    size_t verticalSegments = tessellation;\n    size_t horizontalSegments = tessellation * 2;\n\n    float radius = diameter / 2;\n\n    // Create rings of vertices at progressively higher latitudes.\n    for (size_t i = 0; i <= verticalSegments; i++)\n    {\n        float v = 1 - float(i) / float(verticalSegments);\n\n        float latitude = (float(i) * XM_PI / float(verticalSegments)) - XM_PIDIV2;\n        float dy, dxz;\n\n        XMScalarSinCos(&dy, &dxz, latitude);\n\n        // Create a single ring of vertices at this latitude.\n        for (size_t j = 0; j <= horizontalSegments; j++)\n        {\n            float u = float(j) / float(horizontalSegments);\n\n            float longitude = float(j) * XM_2PI / float(horizontalSegments);\n            float dx, dz;\n\n            XMScalarSinCos(&dx, &dz, longitude);\n\n            dx *= dxz;\n            dz *= dxz;\n\n            XMVECTOR normal = XMVectorSet(dx, dy, dz, 0);\n            XMVECTOR textureCoordinate = XMVectorSet(u, v, 0, 0);\n\n            vertices.push_back(VertexPositionNormalTexture(XMVectorScale(normal, radius), normal, textureCoordinate));\n        }\n    }\n\n    // Fill the index buffer with triangles joining each pair of latitude rings.\n    size_t stride = horizontalSegments + 1;\n\n    for (size_t i = 0; i < verticalSegments; i++)\n    {\n        for (size_t j = 0; j <= horizontalSegments; j++)\n        {\n            size_t nextI = i + 1;\n            size_t nextJ = (j + 1) % stride;\n\n            index_push_back(indices, i * stride + j);\n            index_push_back(indices, nextI * stride + j);\n            index_push_back(indices, i * stride + nextJ);\n\n            index_push_back(indices, i * stride + nextJ);\n            index_push_back(indices, nextI * stride + j);\n            index_push_back(indices, nextI * stride + nextJ);\n        }\n    }\n\n    // Build RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n\n    if (invertn)\n        InvertNormals(vertices);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Geodesic sphere\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeGeoSphere(VertexCollection& vertices, IndexCollection& indices, float diameter, size_t tessellation, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    // An undirected edge between two vertices, represented by a pair of indexes into a vertex array.\n    // Becuse this edge is undirected, (a,b) is the same as (b,a).\n    using UndirectedEdge = std::pair<uint16_t, uint16_t>;\n\n    // Makes an undirected edge. Rather than overloading comparison operators to give us the (a,b)==(b,a) property,\n    // we'll just ensure that the larger of the two goes first. This'll simplify things greatly.\n    auto makeUndirectedEdge = [](uint16_t a, uint16_t b) noexcept\n    {\n        return std::make_pair(std::max(a, b), std::min(a, b));\n    };\n\n    // Key: an edge\n    // Value: the index of the vertex which lies midway between the two vertices pointed to by the key value\n    // This map is used to avoid duplicating vertices when subdividing triangles along edges.\n    using EdgeSubdivisionMap = std::map<UndirectedEdge, uint16_t>;\n\n\n    static const XMFLOAT3 OctahedronVertices[] =\n    {\n        // when looking down the negative z-axis (into the screen)\n        XMFLOAT3(0,  1,  0), // 0 top\n        XMFLOAT3(0,  0, -1), // 1 front\n        XMFLOAT3(1,  0,  0), // 2 right\n        XMFLOAT3(0,  0,  1), // 3 back\n        XMFLOAT3(-1,  0,  0), // 4 left\n        XMFLOAT3(0, -1,  0), // 5 bottom\n    };\n    static const uint16_t OctahedronIndices[] =\n    {\n        0, 1, 2, // top front-right face\n        0, 2, 3, // top back-right face\n        0, 3, 4, // top back-left face\n        0, 4, 1, // top front-left face\n        5, 1, 4, // bottom front-left face\n        5, 4, 3, // bottom back-left face\n        5, 3, 2, // bottom back-right face\n        5, 2, 1, // bottom front-right face\n    };\n\n    const float radius = diameter / 2.0f;\n\n    // Start with an octahedron; copy the data into the vertex/index collection.\n\n    std::vector<XMFLOAT3> vertexPositions(std::begin(OctahedronVertices), std::end(OctahedronVertices));\n\n    indices.insert(indices.begin(), std::begin(OctahedronIndices), std::end(OctahedronIndices));\n\n    // We know these values by looking at the above index list for the octahedron. Despite the subdivisions that are\n    // about to go on, these values aren't ever going to change because the vertices don't move around in the array.\n    // We'll need these values later on to fix the singularities that show up at the poles.\n    const uint16_t northPoleIndex = 0;\n    const uint16_t southPoleIndex = 5;\n\n    for (size_t iSubdivision = 0; iSubdivision < tessellation; ++iSubdivision)\n    {\n        assert(indices.size() % 3 == 0); // sanity\n\n        // We use this to keep track of which edges have already been subdivided.\n        EdgeSubdivisionMap subdividedEdges;\n\n        // The new index collection after subdivision.\n        IndexCollection newIndices;\n\n        const size_t triangleCount = indices.size() / 3;\n        for (size_t iTriangle = 0; iTriangle < triangleCount; ++iTriangle)\n        {\n            // For each edge on this triangle, create a new vertex in the middle of that edge.\n            // The winding order of the triangles we output are the same as the winding order of the inputs.\n\n            // Indices of the vertices making up this triangle\n            uint16_t iv0 = indices[iTriangle * 3 + 0];\n            uint16_t iv1 = indices[iTriangle * 3 + 1];\n            uint16_t iv2 = indices[iTriangle * 3 + 2];\n\n            // Get the new vertices\n            XMFLOAT3 v01; // vertex on the midpoint of v0 and v1\n            XMFLOAT3 v12; // ditto v1 and v2\n            XMFLOAT3 v20; // ditto v2 and v0\n            uint16_t iv01; // index of v01\n            uint16_t iv12; // index of v12\n            uint16_t iv20; // index of v20\n\n            // Function that, when given the index of two vertices, creates a new vertex at the midpoint of those vertices.\n            auto divideEdge = [&](uint16_t i0, uint16_t i1, XMFLOAT3& outVertex, uint16_t& outIndex)\n            {\n                const UndirectedEdge edge = makeUndirectedEdge(i0, i1);\n\n                // Check to see if we've already generated this vertex\n                auto it = subdividedEdges.find(edge);\n                if (it != subdividedEdges.end())\n                {\n                    // We've already generated this vertex before\n                    outIndex = it->second; // the index of this vertex\n                    outVertex = vertexPositions[outIndex]; // and the vertex itself\n                }\n                else\n                {\n                    // Haven't generated this vertex before: so add it now\n\n                    // outVertex = (vertices[i0] + vertices[i1]) / 2\n                    XMStoreFloat3(\n                        &outVertex,\n                        XMVectorScale(\n                        XMVectorAdd(XMLoadFloat3(&vertexPositions[i0]), XMLoadFloat3(&vertexPositions[i1])),\n                        0.5f\n                    )\n                    );\n\n                    outIndex = static_cast<uint16_t>(vertexPositions.size());\n                    CheckIndexOverflow(outIndex);\n                    vertexPositions.push_back(outVertex);\n\n                    // Now add it to the map.\n                    auto entry = std::make_pair(edge, outIndex);\n                    subdividedEdges.insert(entry);\n                }\n            };\n\n            // Add/get new vertices and their indices\n            divideEdge(iv0, iv1, v01, iv01);\n            divideEdge(iv1, iv2, v12, iv12);\n            divideEdge(iv0, iv2, v20, iv20);\n\n            // Add the new indices. We have four new triangles from our original one:\n            //        v0\n            //        o\n            //       /a\\\n            //  v20 o---o v01\n            //     /b\\c/d\\\n            // v2 o---o---o v1\n            //       v12\n            const uint16_t indicesToAdd[] =\n            {\n                 iv0, iv01, iv20, // a\n                iv20, iv12,  iv2, // b\n                iv20, iv01, iv12, // c\n                iv01,  iv1, iv12, // d\n            };\n            newIndices.insert(newIndices.end(), std::begin(indicesToAdd), std::end(indicesToAdd));\n        }\n\n        indices = std::move(newIndices);\n    }\n\n    // Now that we've completed subdivision, fill in the final vertex collection\n    vertices.reserve(vertexPositions.size());\n    for (auto it = vertexPositions.begin(); it != vertexPositions.end(); ++it)\n    {\n        auto vertexValue = *it;\n\n        auto normal = XMVector3Normalize(XMLoadFloat3(&vertexValue));\n        auto pos = XMVectorScale(normal, radius);\n\n        XMFLOAT3 normalFloat3;\n        XMStoreFloat3(&normalFloat3, normal);\n\n        // calculate texture coordinates for this vertex\n        float longitude = atan2f(normalFloat3.x, -normalFloat3.z);\n        float latitude = acosf(normalFloat3.y);\n\n        float u = longitude / XM_2PI + 0.5f;\n        float v = latitude / XM_PI;\n\n        auto texcoord = XMVectorSet(1.0f - u, v, 0.0f, 0.0f);\n        vertices.push_back(VertexPositionNormalTexture(pos, normal, texcoord));\n    }\n\n    // There are a couple of fixes to do. One is a texture coordinate wraparound fixup. At some point, there will be\n    // a set of triangles somewhere in the mesh with texture coordinates such that the wraparound across 0.0/1.0\n    // occurs across that triangle. Eg. when the left hand side of the triangle has a U coordinate of 0.98 and the\n    // right hand side has a U coordinate of 0.0. The intent is that such a triangle should render with a U of 0.98 to\n    // 1.0, not 0.98 to 0.0. If we don't do this fixup, there will be a visible seam across one side of the sphere.\n    // \n    // Luckily this is relatively easy to fix. There is a straight edge which runs down the prime meridian of the\n    // completed sphere. If you imagine the vertices along that edge, they circumscribe a semicircular arc starting at\n    // y=1 and ending at y=-1, and sweeping across the range of z=0 to z=1. x stays zero. It's along this edge that we\n    // need to duplicate our vertices - and provide the correct texture coordinates.\n    size_t preFixupVertexCount = vertices.size();\n    for (size_t i = 0; i < preFixupVertexCount; ++i)\n    {\n        // This vertex is on the prime meridian if position.x and texcoord.u are both zero (allowing for small epsilon).\n        bool isOnPrimeMeridian = XMVector2NearEqual(\n            XMVectorSet(vertices[i].position.x, vertices[i].textureCoordinate.x, 0.0f, 0.0f),\n            XMVectorZero(),\n            XMVectorSplatEpsilon());\n\n        if (isOnPrimeMeridian)\n        {\n            size_t newIndex = vertices.size(); // the index of this vertex that we're about to add\n            CheckIndexOverflow(newIndex);\n\n            // copy this vertex, correct the texture coordinate, and add the vertex\n            VertexPositionNormalTexture v = vertices[i];\n            v.textureCoordinate.x = 1.0f;\n            vertices.push_back(v);\n\n            // Now find all the triangles which contain this vertex and update them if necessary\n            for (size_t j = 0; j < indices.size(); j += 3)\n            {\n                uint16_t* triIndex0 = &indices[j + 0];\n                uint16_t* triIndex1 = &indices[j + 1];\n                uint16_t* triIndex2 = &indices[j + 2];\n\n                if (*triIndex0 == i)\n                {\n                    // nothing; just keep going\n                }\n                else if (*triIndex1 == i)\n                {\n                    std::swap(triIndex0, triIndex1); // swap the pointers (not the values)\n                }\n                else if (*triIndex2 == i)\n                {\n                    std::swap(triIndex0, triIndex2); // swap the pointers (not the values)\n                }\n                else\n                {\n                    // this triangle doesn't use the vertex we're interested in\n                    continue;\n                }\n\n                // If we got to this point then triIndex0 is the pointer to the index to the vertex we're looking at\n                assert(*triIndex0 == i);\n                assert(*triIndex1 != i && *triIndex2 != i); // assume no degenerate triangles\n\n                const VertexPositionNormalTexture& v0 = vertices[*triIndex0];\n                const VertexPositionNormalTexture& v1 = vertices[*triIndex1];\n                const VertexPositionNormalTexture& v2 = vertices[*triIndex2];\n\n                // check the other two vertices to see if we might need to fix this triangle\n\n                if (abs(v0.textureCoordinate.x - v1.textureCoordinate.x) > 0.5f ||\n                    abs(v0.textureCoordinate.x - v2.textureCoordinate.x) > 0.5f)\n                {\n                    // yep; replace the specified index to point to the new, corrected vertex\n                    *triIndex0 = static_cast<uint16_t>(newIndex);\n                }\n            }\n        }\n    }\n\n    // And one last fix we need to do: the poles. A common use-case of a sphere mesh is to map a rectangular texture onto\n    // it. If that happens, then the poles become singularities which map the entire top and bottom rows of the texture\n    // onto a single point. In general there's no real way to do that right. But to match the behavior of non-geodesic\n    // spheres, we need to duplicate the pole vertex for every triangle that uses it. This will introduce seams near the\n    // poles, but reduce stretching.\n    auto fixPole = [&](size_t poleIndex)\n    {\n        auto poleVertex = vertices[poleIndex];\n        bool overwrittenPoleVertex = false; // overwriting the original pole vertex saves us one vertex\n\n        for (size_t i = 0; i < indices.size(); i += 3)\n        {\n            // These pointers point to the three indices which make up this triangle. pPoleIndex is the pointer to the\n            // entry in the index array which represents the pole index, and the other two pointers point to the other\n            // two indices making up this triangle.\n            uint16_t* pPoleIndex;\n            uint16_t* pOtherIndex0;\n            uint16_t* pOtherIndex1;\n            if (indices[i + 0] == poleIndex)\n            {\n                pPoleIndex = &indices[i + 0];\n                pOtherIndex0 = &indices[i + 1];\n                pOtherIndex1 = &indices[i + 2];\n            }\n            else if (indices[i + 1] == poleIndex)\n            {\n                pPoleIndex = &indices[i + 1];\n                pOtherIndex0 = &indices[i + 2];\n                pOtherIndex1 = &indices[i + 0];\n            }\n            else if (indices[i + 2] == poleIndex)\n            {\n                pPoleIndex = &indices[i + 2];\n                pOtherIndex0 = &indices[i + 0];\n                pOtherIndex1 = &indices[i + 1];\n            }\n            else\n            {\n                continue;\n            }\n\n            const auto& otherVertex0 = vertices[*pOtherIndex0];\n            const auto& otherVertex1 = vertices[*pOtherIndex1];\n\n            // Calculate the texcoords for the new pole vertex, add it to the vertices and update the index\n            VertexPositionNormalTexture newPoleVertex = poleVertex;\n            newPoleVertex.textureCoordinate.x = (otherVertex0.textureCoordinate.x + otherVertex1.textureCoordinate.x) / 2;\n            newPoleVertex.textureCoordinate.y = poleVertex.textureCoordinate.y;\n\n            if (!overwrittenPoleVertex)\n            {\n                vertices[poleIndex] = newPoleVertex;\n                overwrittenPoleVertex = true;\n            }\n            else\n            {\n                CheckIndexOverflow(vertices.size());\n\n                *pPoleIndex = static_cast<uint16_t>(vertices.size());\n                vertices.push_back(newPoleVertex);\n            }\n        }\n    };\n\n    fixPole(northPoleIndex);\n    fixPole(southPoleIndex);\n\n    // Build RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Cylinder / Cone\n//--------------------------------------------------------------------------------------\nnamespace\n{\n    // Helper computes a point on a unit circle, aligned to the x/z plane and centered on the origin.\n    inline XMVECTOR GetCircleVector(size_t i, size_t tessellation) noexcept\n    {\n        float angle = float(i) * XM_2PI / float(tessellation);\n        float dx, dz;\n\n        XMScalarSinCos(&dx, &dz, angle);\n\n        XMVECTORF32 v = { { { dx, 0, dz, 0 } } };\n        return v;\n    }\n\n    inline XMVECTOR GetCircleTangent(size_t i, size_t tessellation) noexcept\n    {\n        float angle = (float(i) * XM_2PI / float(tessellation)) + XM_PIDIV2;\n        float dx, dz;\n\n        XMScalarSinCos(&dx, &dz, angle);\n\n        XMVECTORF32 v = { { { dx, 0, dz, 0 } } };\n        return v;\n    }\n\n\n    // Helper creates a triangle fan to close the end of a cylinder / cone\n    void CreateCylinderCap(VertexCollection& vertices, IndexCollection& indices, size_t tessellation, float height, float radius, bool isTop)\n    {\n        // Create cap indices.\n        for (size_t i = 0; i < tessellation - 2; i++)\n        {\n            size_t i1 = (i + 1) % tessellation;\n            size_t i2 = (i + 2) % tessellation;\n\n            if (isTop)\n            {\n                std::swap(i1, i2);\n            }\n\n            size_t vbase = vertices.size();\n            index_push_back(indices, vbase);\n            index_push_back(indices, vbase + i1);\n            index_push_back(indices, vbase + i2);\n        }\n\n        // Which end of the cylinder is this?\n        XMVECTOR normal = g_XMIdentityR1;\n        XMVECTOR textureScale = g_XMNegativeOneHalf;\n\n        if (!isTop)\n        {\n            normal = XMVectorNegate(normal);\n            textureScale = XMVectorMultiply(textureScale, g_XMNegateX);\n        }\n\n        // Create cap vertices.\n        for (size_t i = 0; i < tessellation; i++)\n        {\n            XMVECTOR circleVector = GetCircleVector(i, tessellation);\n\n            XMVECTOR position = XMVectorAdd(XMVectorScale(circleVector, radius), XMVectorScale(normal, height));\n\n            XMVECTOR textureCoordinate = XMVectorMultiplyAdd(XMVectorSwizzle<0, 2, 3, 3>(circleVector), textureScale, g_XMOneHalf);\n\n            vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinate));\n        }\n    }\n}\n\nvoid DirectX::ComputeCylinder(VertexCollection& vertices, IndexCollection& indices, float height, float diameter, size_t tessellation, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    if (tessellation < 3)\n        throw std::out_of_range(\"tesselation parameter out of range\");\n\n    height /= 2;\n\n    XMVECTOR topOffset = XMVectorScale(g_XMIdentityR1, height);\n\n    float radius = diameter / 2;\n    size_t stride = tessellation + 1;\n\n    // Create a ring of triangles around the outside of the cylinder.\n    for (size_t i = 0; i <= tessellation; i++)\n    {\n        XMVECTOR normal = GetCircleVector(i, tessellation);\n\n        XMVECTOR sideOffset = XMVectorScale(normal, radius);\n\n        float u = float(i) / float(tessellation);\n\n        XMVECTOR textureCoordinate = XMLoadFloat(&u);\n\n        vertices.push_back(VertexPositionNormalTexture(XMVectorAdd(sideOffset, topOffset), normal, textureCoordinate));\n        vertices.push_back(VertexPositionNormalTexture(XMVectorSubtract(sideOffset, topOffset), normal, XMVectorAdd(textureCoordinate, g_XMIdentityR1)));\n\n        index_push_back(indices, i * 2);\n        index_push_back(indices, (i * 2 + 2) % (stride * 2));\n        index_push_back(indices, i * 2 + 1);\n\n        index_push_back(indices, i * 2 + 1);\n        index_push_back(indices, (i * 2 + 2) % (stride * 2));\n        index_push_back(indices, (i * 2 + 3) % (stride * 2));\n    }\n\n    // Create flat triangle fan caps to seal the top and bottom.\n    CreateCylinderCap(vertices, indices, tessellation, height, radius, true);\n    CreateCylinderCap(vertices, indices, tessellation, height, radius, false);\n\n    // Build RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n}\n\n\n// Creates a cone primitive.\nvoid DirectX::ComputeCone(VertexCollection& vertices, IndexCollection& indices, float diameter, float height, size_t tessellation, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    if (tessellation < 3)\n        throw std::out_of_range(\"tesselation parameter out of range\");\n\n    height /= 2;\n\n    XMVECTOR topOffset = XMVectorScale(g_XMIdentityR1, height);\n\n    float radius = diameter / 2;\n    size_t stride = tessellation + 1;\n\n    // Create a ring of triangles around the outside of the cone.\n    for (size_t i = 0; i <= tessellation; i++)\n    {\n        XMVECTOR circlevec = GetCircleVector(i, tessellation);\n\n        XMVECTOR sideOffset = XMVectorScale(circlevec, radius);\n\n        float u = float(i) / float(tessellation);\n\n        XMVECTOR textureCoordinate = XMLoadFloat(&u);\n\n        XMVECTOR pt = XMVectorSubtract(sideOffset, topOffset);\n\n        XMVECTOR normal = XMVector3Cross(\n            GetCircleTangent(i, tessellation),\n            XMVectorSubtract(topOffset, pt));\n        normal = XMVector3Normalize(normal);\n\n        // Duplicate the top vertex for distinct normals\n        vertices.push_back(VertexPositionNormalTexture(topOffset, normal, g_XMZero));\n        vertices.push_back(VertexPositionNormalTexture(pt, normal, XMVectorAdd(textureCoordinate, g_XMIdentityR1)));\n\n        index_push_back(indices, i * 2);\n        index_push_back(indices, (i * 2 + 3) % (stride * 2));\n        index_push_back(indices, (i * 2 + 1) % (stride * 2));\n    }\n\n    // Create flat triangle fan caps to seal the bottom.\n    CreateCylinderCap(vertices, indices, tessellation, height, radius, false);\n\n    // Build RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Torus\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeTorus(VertexCollection& vertices, IndexCollection& indices, float diameter, float thickness, size_t tessellation, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    if (tessellation < 3)\n        throw std::out_of_range(\"tesselation parameter out of range\");\n\n    size_t stride = tessellation + 1;\n\n    // First we loop around the main ring of the torus.\n    for (size_t i = 0; i <= tessellation; i++)\n    {\n        float u = float(i) / float(tessellation);\n\n        float outerAngle = float(i) * XM_2PI / float(tessellation) - XM_PIDIV2;\n\n        // Create a transform matrix that will align geometry to\n        // slice perpendicularly though the current ring position.\n        XMMATRIX transform = XMMatrixTranslation(diameter / 2, 0, 0) * XMMatrixRotationY(outerAngle);\n\n        // Now we loop along the other axis, around the side of the tube.\n        for (size_t j = 0; j <= tessellation; j++)\n        {\n            float v = 1 - float(j) / float(tessellation);\n\n            float innerAngle = float(j) * XM_2PI / float(tessellation) + XM_PI;\n            float dx, dy;\n\n            XMScalarSinCos(&dy, &dx, innerAngle);\n\n            // Create a vertex.\n            XMVECTOR normal = XMVectorSet(dx, dy, 0, 0);\n            XMVECTOR position = XMVectorScale(normal, thickness / 2);\n            XMVECTOR textureCoordinate = XMVectorSet(u, v, 0, 0);\n\n            position = XMVector3Transform(position, transform);\n            normal = XMVector3TransformNormal(normal, transform);\n\n            vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinate));\n\n            // And create indices for two triangles.\n            size_t nextI = (i + 1) % stride;\n            size_t nextJ = (j + 1) % stride;\n\n            index_push_back(indices, i * stride + j);\n            index_push_back(indices, i * stride + nextJ);\n            index_push_back(indices, nextI * stride + j);\n\n            index_push_back(indices, i * stride + nextJ);\n            index_push_back(indices, nextI * stride + nextJ);\n            index_push_back(indices, nextI * stride + j);\n        }\n    }\n\n    // Build RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Tetrahedron\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeTetrahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    static const XMVECTORF32 verts[4] =\n    {\n        { { {              0.f,          0.f,        1.f, 0 } } },\n        { { {  2.f*SQRT2 / 3.f,          0.f, -1.f / 3.f, 0 } } },\n        { { {     -SQRT2 / 3.f,  SQRT6 / 3.f, -1.f / 3.f, 0 } } },\n        { { {     -SQRT2 / 3.f, -SQRT6 / 3.f, -1.f / 3.f, 0 } } }\n    };\n\n    static const uint32_t faces[4 * 3] =\n    {\n        0, 1, 2,\n        0, 2, 3,\n        0, 3, 1,\n        1, 3, 2,\n    };\n\n    for (size_t j = 0; j < _countof(faces); j += 3)\n    {\n        uint32_t v0 = faces[j];\n        uint32_t v1 = faces[j + 1];\n        uint32_t v2 = faces[j + 2];\n\n        XMVECTOR normal = XMVector3Cross(\n            XMVectorSubtract(verts[v1].v, verts[v0].v),\n            XMVectorSubtract(verts[v2].v, verts[v0].v));\n        normal = XMVector3Normalize(normal);\n\n        size_t base = vertices.size();\n        index_push_back(indices, base);\n        index_push_back(indices, base + 1);\n        index_push_back(indices, base + 2);\n\n        // Duplicate vertices to use face normals\n        XMVECTOR position = XMVectorScale(verts[v0], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMZero /* 0, 0 */));\n\n        position = XMVectorScale(verts[v1], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMIdentityR0 /* 1, 0 */));\n\n        position = XMVectorScale(verts[v2], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMIdentityR1 /* 0, 1 */));\n    }\n\n    // Built LH above\n    if (rhcoords)\n        ReverseWinding(indices, vertices);\n\n    assert(vertices.size() == 4 * 3);\n    assert(indices.size() == 4 * 3);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Octahedron\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeOctahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    static const XMVECTORF32 verts[6] =\n    {\n        { { {  1,  0,  0, 0 } } },\n        { { { -1,  0,  0, 0 } } },\n        { { {  0,  1,  0, 0 } } },\n        { { {  0, -1,  0, 0 } } },\n        { { {  0,  0,  1, 0 } } },\n        { { {  0,  0, -1, 0 } } }\n    };\n\n    static const uint32_t faces[8 * 3] =\n    {\n        4, 0, 2,\n        4, 2, 1,\n        4, 1, 3,\n        4, 3, 0,\n        5, 2, 0,\n        5, 1, 2,\n        5, 3, 1,\n        5, 0, 3\n    };\n\n    for (size_t j = 0; j < _countof(faces); j += 3)\n    {\n        uint32_t v0 = faces[j];\n        uint32_t v1 = faces[j + 1];\n        uint32_t v2 = faces[j + 2];\n\n        XMVECTOR normal = XMVector3Cross(\n            XMVectorSubtract(verts[v1].v, verts[v0].v),\n            XMVectorSubtract(verts[v2].v, verts[v0].v));\n        normal = XMVector3Normalize(normal);\n\n        size_t base = vertices.size();\n        index_push_back(indices, base);\n        index_push_back(indices, base + 1);\n        index_push_back(indices, base + 2);\n\n        // Duplicate vertices to use face normals\n        XMVECTOR position = XMVectorScale(verts[v0], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMZero /* 0, 0 */));\n\n        position = XMVectorScale(verts[v1], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMIdentityR0 /* 1, 0 */));\n\n        position = XMVectorScale(verts[v2], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMIdentityR1 /* 0, 1*/));\n    }\n\n    // Built LH above\n    if (rhcoords)\n        ReverseWinding(indices, vertices);\n\n    assert(vertices.size() == 8 * 3);\n    assert(indices.size() == 8 * 3);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Dodecahedron\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeDodecahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    static const float a = 1.f / SQRT3;\n    static const float b = 0.356822089773089931942f; // sqrt( ( 3 - sqrt(5) ) / 6 )\n    static const float c = 0.934172358962715696451f; // sqrt( ( 3 + sqrt(5) ) / 6 );\n\n    static const XMVECTORF32 verts[20] =\n    {\n        { { {  a,  a,  a, 0 } } },\n        { { {  a,  a, -a, 0 } } },\n        { { {  a, -a,  a, 0 } } },\n        { { {  a, -a, -a, 0 } } },\n        { { { -a,  a,  a, 0 } } },\n        { { { -a,  a, -a, 0 } } },\n        { { { -a, -a,  a, 0 } } },\n        { { { -a, -a, -a, 0 } } },\n        { { {  b,  c,  0, 0 } } },\n        { { { -b,  c,  0, 0 } } },\n        { { {  b, -c,  0, 0 } } },\n        { { { -b, -c,  0, 0 } } },\n        { { {  c,  0,  b, 0 } } },\n        { { {  c,  0, -b, 0 } } },\n        { { { -c,  0,  b, 0 } } },\n        { { { -c,  0, -b, 0 } } },\n        { { {  0,  b,  c, 0 } } },\n        { { {  0, -b,  c, 0 } } },\n        { { {  0,  b, -c, 0 } } },\n        { { {  0, -b, -c, 0 } } }\n    };\n\n    static const uint32_t faces[12 * 5] =\n    {\n        0, 8, 9, 4, 16,\n        0, 16, 17, 2, 12,\n        12, 2, 10, 3, 13,\n        9, 5, 15, 14, 4,\n        3, 19, 18, 1, 13,\n        7, 11, 6, 14, 15,\n        0, 12, 13, 1, 8,\n        8, 1, 18, 5, 9,\n        16, 4, 14, 6, 17,\n        6, 11, 10, 2, 17,\n        7, 15, 5, 18, 19,\n        7, 19, 3, 10, 11,\n    };\n\n    static const XMVECTORF32 textureCoordinates[5] =\n    {\n        { { {  0.654508f, 0.0244717f, 0, 0 } } },\n        { { { 0.0954915f,  0.206107f, 0, 0 } } },\n        { { { 0.0954915f,  0.793893f, 0, 0 } } },\n        { { {  0.654508f,  0.975528f, 0, 0 } } },\n        { { {        1.f,       0.5f, 0, 0 } } }\n    };\n\n    static const uint32_t textureIndex[12][5] =\n    {\n        { 0, 1, 2, 3, 4 },\n        { 2, 3, 4, 0, 1 },\n        { 4, 0, 1, 2, 3 },\n        { 1, 2, 3, 4, 0 },\n        { 2, 3, 4, 0, 1 },\n        { 0, 1, 2, 3, 4 },\n        { 1, 2, 3, 4, 0 },\n        { 4, 0, 1, 2, 3 },\n        { 4, 0, 1, 2, 3 },\n        { 1, 2, 3, 4, 0 },\n        { 0, 1, 2, 3, 4 },\n        { 2, 3, 4, 0, 1 },\n    };\n\n    size_t t = 0;\n    for (size_t j = 0; j < _countof(faces); j += 5, ++t)\n    {\n        uint32_t v0 = faces[j];\n        uint32_t v1 = faces[j + 1];\n        uint32_t v2 = faces[j + 2];\n        uint32_t v3 = faces[j + 3];\n        uint32_t v4 = faces[j + 4];\n\n        XMVECTOR normal = XMVector3Cross(\n            XMVectorSubtract(verts[v1].v, verts[v0].v),\n            XMVectorSubtract(verts[v2].v, verts[v0].v));\n        normal = XMVector3Normalize(normal);\n\n        size_t base = vertices.size();\n\n        index_push_back(indices, base);\n        index_push_back(indices, base + 1);\n        index_push_back(indices, base + 2);\n\n        index_push_back(indices, base);\n        index_push_back(indices, base + 2);\n        index_push_back(indices, base + 3);\n\n        index_push_back(indices, base);\n        index_push_back(indices, base + 3);\n        index_push_back(indices, base + 4);\n\n        // Duplicate vertices to use face normals\n        XMVECTOR position = XMVectorScale(verts[v0], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinates[textureIndex[t][0]]));\n\n        position = XMVectorScale(verts[v1], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinates[textureIndex[t][1]]));\n\n        position = XMVectorScale(verts[v2], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinates[textureIndex[t][2]]));\n\n        position = XMVectorScale(verts[v3], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinates[textureIndex[t][3]]));\n\n        position = XMVectorScale(verts[v4], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinates[textureIndex[t][4]]));\n    }\n\n    // Built LH above\n    if (rhcoords)\n        ReverseWinding(indices, vertices);\n\n    assert(vertices.size() == 12 * 5);\n    assert(indices.size() == 12 * 3 * 3);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Icosahedron\n//--------------------------------------------------------------------------------------\nvoid DirectX::ComputeIcosahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    static const float  t = 1.618033988749894848205f; // (1 + sqrt(5)) / 2\n    static const float t2 = 1.519544995837552493271f; // sqrt( 1 + sqr( (1 + sqrt(5)) / 2 ) )\n\n    static const XMVECTORF32 verts[12] =\n    {\n        { { {    t / t2,  1.f / t2,       0, 0 } } },\n        { { {   -t / t2,  1.f / t2,       0, 0 } } },\n        { { {    t / t2, -1.f / t2,       0, 0 } } },\n        { { {   -t / t2, -1.f / t2,       0, 0 } } },\n        { { {  1.f / t2,       0,    t / t2, 0 } } },\n        { { {  1.f / t2,       0,   -t / t2, 0 } } },\n        { { { -1.f / t2,       0,    t / t2, 0 } } },\n        { { { -1.f / t2,       0,   -t / t2, 0 } } },\n        { { {       0,    t / t2,  1.f / t2, 0 }  } },\n        { { {       0,   -t / t2,  1.f / t2, 0 } } },\n        { { {       0,    t / t2, -1.f / t2, 0 } } },\n        { { {       0,   -t / t2, -1.f / t2, 0 } } }\n    };\n\n    static const uint32_t faces[20 * 3] =\n    {\n        0, 8, 4,\n        0, 5, 10,\n        2, 4, 9,\n        2, 11, 5,\n        1, 6, 8,\n        1, 10, 7,\n        3, 9, 6,\n        3, 7, 11,\n        0, 10, 8,\n        1, 8, 10,\n        2, 9, 11,\n        3, 11, 9,\n        4, 2, 0,\n        5, 0, 2,\n        6, 1, 3,\n        7, 3, 1,\n        8, 6, 4,\n        9, 4, 6,\n        10, 5, 7,\n        11, 7, 5\n    };\n\n    for (size_t j = 0; j < _countof(faces); j += 3)\n    {\n        uint32_t v0 = faces[j];\n        uint32_t v1 = faces[j + 1];\n        uint32_t v2 = faces[j + 2];\n\n        XMVECTOR normal = XMVector3Cross(\n            XMVectorSubtract(verts[v1].v, verts[v0].v),\n            XMVectorSubtract(verts[v2].v, verts[v0].v));\n        normal = XMVector3Normalize(normal);\n\n        size_t base = vertices.size();\n        index_push_back(indices, base);\n        index_push_back(indices, base + 1);\n        index_push_back(indices, base + 2);\n\n        // Duplicate vertices to use face normals\n        XMVECTOR position = XMVectorScale(verts[v0], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMZero /* 0, 0 */));\n\n        position = XMVectorScale(verts[v1], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMIdentityR0 /* 1, 0 */));\n\n        position = XMVectorScale(verts[v2], size);\n        vertices.push_back(VertexPositionNormalTexture(position, normal, g_XMIdentityR1 /* 0, 1 */));\n    }\n\n    // Built LH above\n    if (rhcoords)\n        ReverseWinding(indices, vertices);\n\n    assert(vertices.size() == 20 * 3);\n    assert(indices.size() == 20 * 3);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Teapot\n//--------------------------------------------------------------------------------------\n\n// Include the teapot control point data.\nnamespace\n{\n#include \"TeapotData.inc\"\n\n    // Tessellates the specified bezier patch.\n    void XM_CALLCONV TessellatePatch(VertexCollection& vertices, IndexCollection& indices, TeapotPatch const& patch, size_t tessellation, FXMVECTOR scale, bool isMirrored)\n    {\n        // Look up the 16 control points for this patch.\n        XMVECTOR controlPoints[16] = {};\n\n        for (int i = 0; i < 16; i++)\n        {\n            controlPoints[i] = XMVectorMultiply(TeapotControlPoints[patch.indices[i]], scale);\n        }\n\n        // Create the index data.\n        size_t vbase = vertices.size();\n        Bezier::CreatePatchIndices(tessellation, isMirrored, [&](size_t index)\n                                   {\n                                       index_push_back(indices, vbase + index);\n                                   });\n\n                                   // Create the vertex data.\n        Bezier::CreatePatchVertices(controlPoints, tessellation, isMirrored, [&](FXMVECTOR position, FXMVECTOR normal, FXMVECTOR textureCoordinate)\n                                    {\n                                        vertices.push_back(VertexPositionNormalTexture(position, normal, textureCoordinate));\n                                    });\n    }\n}\n\n\n// Creates a teapot primitive.\nvoid DirectX::ComputeTeapot(VertexCollection& vertices, IndexCollection& indices, float size, size_t tessellation, bool rhcoords)\n{\n    vertices.clear();\n    indices.clear();\n\n    if (tessellation < 1)\n        throw std::out_of_range(\"tesselation parameter out of range\");\n\n    XMVECTOR scaleVector = XMVectorReplicate(size);\n\n    XMVECTOR scaleNegateX = XMVectorMultiply(scaleVector, g_XMNegateX);\n    XMVECTOR scaleNegateZ = XMVectorMultiply(scaleVector, g_XMNegateZ);\n    XMVECTOR scaleNegateXZ = XMVectorMultiply(scaleVector, XMVectorMultiply(g_XMNegateX, g_XMNegateZ));\n\n    for (size_t i = 0; i < _countof(TeapotPatches); i++)\n    {\n        TeapotPatch const& patch = TeapotPatches[i];\n\n        // Because the teapot is symmetrical from left to right, we only store\n        // data for one side, then tessellate each patch twice, mirroring in X.\n        TessellatePatch(vertices, indices, patch, tessellation, scaleVector, false);\n        TessellatePatch(vertices, indices, patch, tessellation, scaleNegateX, true);\n\n        if (patch.mirrorZ)\n        {\n            // Some parts of the teapot (the body, lid, and rim, but not the\n            // handle or spout) are also symmetrical from front to back, so\n            // we tessellate them four times, mirroring in Z as well as X.\n            TessellatePatch(vertices, indices, patch, tessellation, scaleNegateZ, true);\n            TessellatePatch(vertices, indices, patch, tessellation, scaleNegateXZ, false);\n        }\n    }\n\n    // Built RH above\n    if (!rhcoords)\n        ReverseWinding(indices, vertices);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Geometry.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: Geometry.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"VertexTypes.h\"\n\nnamespace DirectX\n{\n    using VertexCollection = std::vector<DirectX::VertexPositionNormalTexture>;\n    using IndexCollection = std::vector<uint16_t>;\n\n    void ComputeBox(VertexCollection& vertices, IndexCollection& indices, const XMFLOAT3& size, bool rhcoords, bool invertn);\n    void ComputeSphere(VertexCollection& vertices, IndexCollection& indices, float diameter, size_t tessellation, bool rhcoords, bool invertn);\n    void ComputeGeoSphere(VertexCollection& vertices, IndexCollection& indices, float diameter, size_t tessellation, bool rhcoords);\n    void ComputeCylinder(VertexCollection& vertices, IndexCollection& indices, float height, float diameter, size_t tessellation, bool rhcoords);\n    void ComputeCone(VertexCollection& vertices, IndexCollection& indices, float diameter, float height, size_t tessellation, bool rhcoords);\n    void ComputeTorus(VertexCollection& vertices, IndexCollection& indices, float diameter, float thickness, size_t tessellation, bool rhcoords);\n    void ComputeTetrahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords);\n    void ComputeOctahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords);\n    void ComputeDodecahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords);\n    void ComputeIcosahedron(VertexCollection& vertices, IndexCollection& indices, float size, bool rhcoords);\n    void ComputeTeapot(VertexCollection& vertices, IndexCollection& indices, float size, size_t tessellation, bool rhcoords);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/GraphicsMemory.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: GraphicsMemory.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"GraphicsMemory.h\"\n#include \"PlatformHelpers.h\"\n#include \"LinearAllocator.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\nusing ScopedLock = std::lock_guard<std::mutex>;\n\nnamespace\n{\n    static const size_t MinPageSize = 64 * 1024;\n    static const size_t MinAllocSize = 4 * 1024;\n    static const size_t AllocatorIndexShift = 12; // start block sizes at 4KB\n    static const size_t AllocatorPoolCount = 21; // allocation sizes up to 2GB supported\n    static const size_t PoolIndexScale = 1; // multiply the allocation size this amount to push large values into the next bucket\n\n    static_assert((1 << AllocatorIndexShift) == MinAllocSize, \"1 << AllocatorIndexShift must == MinPageSize (in KiB)\");\n    static_assert((MinPageSize & (MinPageSize - 1)) == 0, \"MinPageSize size must be a power of 2\");\n    static_assert((MinAllocSize & (MinAllocSize - 1)) == 0, \"MinAllocSize size must be a power of 2\");\n    static_assert(MinAllocSize >= (4 * 1024), \"MinAllocSize size must be greater than 4K\");\n\n    inline size_t NextPow2(size_t x) noexcept\n    {\n        x--;\n        x |= x >> 1;\n        x |= x >> 2;\n        x |= x >> 4;\n        x |= x >> 8;\n        x |= x >> 16;\n#ifdef _WIN64\n        x |= x >> 32;\n#endif\n        return ++x;\n    }\n\n    inline size_t GetPoolIndexFromSize(size_t x) noexcept\n    {\n        size_t allocatorPageSize = x >> AllocatorIndexShift;\n        // gives a value from range:\n        // 0 - sub-4k allocator\n        // 1 - 4k allocator\n        // 2 - 8k allocator\n        // 4 - 16k allocator\n        // etc...\n        // Need to convert to an index.\n        DWORD bitIndex = 0;\n#ifdef _WIN64\n        return _BitScanForward64(&bitIndex, allocatorPageSize) ? bitIndex + 1 : 0;\n#else\n        return _BitScanForward(&bitIndex, static_cast<DWORD>(allocatorPageSize)) ? bitIndex + 1 : 0;\n#endif\n    }\n\n    inline size_t GetPageSizeFromPoolIndex(size_t x) noexcept\n    {\n        x = (x == 0) ? 0 : x - 1; // clamp to zero\n        return std::max<size_t>(MinPageSize, size_t(1) << (x + AllocatorIndexShift));\n    }\n\n    //--------------------------------------------------------------------------------------\n    // DeviceAllocator : honors memory requests associated with a particular device\n    //--------------------------------------------------------------------------------------\n    class DeviceAllocator\n    {\n    public:\n        DeviceAllocator(_In_ ID3D12Device* device) noexcept(false)\n            : mDevice(device)\n        {\n            if (!device)\n                throw std::invalid_argument(\"Invalid device parameter\");\n\n            for (size_t i = 0; i < mPools.size(); ++i)\n            {\n                size_t pageSize = GetPageSizeFromPoolIndex(i);\n                mPools[i] = std::make_unique<LinearAllocator>(\n                    mDevice.Get(),\n                    pageSize);\n            }\n        }\n\n        DeviceAllocator(DeviceAllocator&&) = delete;\n        DeviceAllocator& operator= (DeviceAllocator&&) = delete;\n\n        DeviceAllocator(DeviceAllocator const&) = delete;\n        DeviceAllocator& operator= (DeviceAllocator const&) = delete;\n\n        // Explicitly destroy LinearAllocators inside a critical section\n        ~DeviceAllocator()\n        {\n            ScopedLock lock(mMutex);\n\n            for (auto& allocator : mPools)\n            {\n                allocator.reset();\n            }\n        }\n\n        GraphicsResource Alloc(_In_ size_t size, _In_ size_t alignment)\n        {\n            ScopedLock lock(mMutex);\n\n            // Which memory pool does it live in?\n            size_t poolSize = NextPow2((alignment + size) * PoolIndexScale);\n            size_t poolIndex = GetPoolIndexFromSize(poolSize);\n            assert(poolIndex < mPools.size());\n\n            // If the allocator isn't initialized yet, do so now\n            auto& allocator = mPools[poolIndex];\n            assert(allocator != nullptr);\n            assert(poolSize < MinPageSize || poolSize == allocator->PageSize());\n\n            auto page = allocator->FindPageForAlloc(size, alignment);\n            if (!page)\n            {\n                DebugTrace(\"GraphicsMemory failed to allocate page (%zu requested bytes, %zu alignment)\\n\", size, alignment);\n                throw std::bad_alloc();\n            }\n\n            size_t offset = page->Suballocate(size, alignment);\n\n            // Return the information to the user\n            return GraphicsResource(\n                page,\n                page->GpuAddress() + offset,\n                page->UploadResource(),\n                static_cast<BYTE*>(page->BaseMemory()) + offset,\n                offset,\n                size);\n        }\n\n        // Submit page fences to the command queue\n        void KickFences(_In_ ID3D12CommandQueue* commandQueue)\n        {\n            ScopedLock lock(mMutex);\n\n            for (auto& i : mPools)\n            {\n                if (i)\n                {\n                    i->RetirePendingPages();\n                    i->FenceCommittedPages(commandQueue);\n                }\n            }\n        }\n\n        void GarbageCollect()\n        {\n            ScopedLock lock(mMutex);\n\n            for (auto& i : mPools)\n            {\n                if (i)\n                {\n                    i->Shrink();\n                }\n            }\n        }\n\n        void GetStatistics(GraphicsMemoryStatistics& stats) const\n        {\n            size_t totalPageCount = 0;\n            size_t committedMemoryUsage = 0;\n            size_t totalMemoryUsage = 0;\n           \n            ScopedLock lock(mMutex);\n\n            for (auto& i : mPools)\n            {\n                if (i)\n                {\n                    totalPageCount += i->TotalPageCount();\n                    committedMemoryUsage += i->CommittedMemoryUsage();\n                    totalMemoryUsage += i->TotalMemoryUsage();\n                }\n            }\n\n            stats = {};\n            stats.committedMemory = committedMemoryUsage;\n            stats.totalMemory = totalMemoryUsage;\n            stats.totalPages = totalPageCount;\n        }\n\n    #if !(defined(_XBOX_ONE) && defined(_TITLE)) && !defined(_GAMING_XBOX)\n        ID3D12Device* GetDevice() const noexcept { return mDevice.Get(); }\n    #endif\n\n    private:\n        ComPtr<ID3D12Device> mDevice;\n        std::array<std::unique_ptr<LinearAllocator>, AllocatorPoolCount> mPools;\n        mutable std::mutex mMutex;\n    };\n} // anonymous namespace\n\n\n//--------------------------------------------------------------------------------------\n// GraphicsMemory::Impl\n//--------------------------------------------------------------------------------------\n\nclass GraphicsMemory::Impl\n{\npublic:\n    Impl(GraphicsMemory* owner) noexcept(false)\n        : mOwner(owner)\n        , m_peakCommited(0)\n        , m_peakBytes(0)\n        , m_peakPages(0)\n    {\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        if (s_graphicsMemory)\n        {\n            throw std::exception(\"GraphicsMemory is a singleton\");\n        }\n\n        s_graphicsMemory = this;\n    #endif\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        s_graphicsMemory = nullptr;\n    #else\n        if (mDeviceAllocator && mDeviceAllocator->GetDevice())\n        {\n            s_graphicsMemory.erase(mDeviceAllocator->GetDevice());\n        }\n    #endif\n        mDeviceAllocator.reset();\n    }\n\n    void Initialize(_In_ ID3D12Device* device)\n    {\n        mDeviceAllocator = std::make_unique<DeviceAllocator>(device);\n\n    #if !(defined(_XBOX_ONE) && defined(_TITLE)) && !defined(_GAMING_XBOX)\n        if (s_graphicsMemory.find(device) != s_graphicsMemory.cend())\n        {\n            throw std::exception(\"GraphicsMemory is a per-device singleton\");\n        }\n        s_graphicsMemory[device] = this;\n    #endif\n    }\n\n    GraphicsResource Allocate(size_t size, size_t alignment)\n    {\n        return mDeviceAllocator->Alloc(size, alignment);\n    }\n\n    void Commit(_In_ ID3D12CommandQueue* commandQueue)\n    {\n        mDeviceAllocator->KickFences(commandQueue);\n    }\n\n    void GarbageCollect()\n    {\n        mDeviceAllocator->GarbageCollect();\n    }\n\n    void GetStatistics(GraphicsMemoryStatistics& stats)\n    {\n        mDeviceAllocator->GetStatistics(stats);\n\n        if (stats.committedMemory > m_peakCommited)\n        {\n            m_peakCommited = stats.committedMemory;\n        }\n        stats.peakCommitedMemory = m_peakCommited;\n\n        if (stats.totalMemory > m_peakBytes)\n        {\n            m_peakBytes = stats.totalMemory;\n        }\n        stats.peakTotalMemory = m_peakBytes;\n\n        if (stats.totalPages > m_peakPages)\n        {\n            m_peakPages = stats.totalPages;\n        }\n        stats.peakTotalPages = m_peakPages;\n    }\n\n    void ResetStatistics()\n    {\n        m_peakCommited = 0;\n        m_peakBytes = 0;\n        m_peakPages = 0;\n}\n\n    GraphicsMemory* mOwner;\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    static GraphicsMemory::Impl* s_graphicsMemory;\n#else\n    static std::map<ID3D12Device*, GraphicsMemory::Impl*> s_graphicsMemory;\n#endif\n\nprivate:\n    std::unique_ptr<DeviceAllocator> mDeviceAllocator;\n\n    size_t  m_peakCommited;\n    size_t  m_peakBytes;\n    size_t  m_peakPages;\n};\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\nGraphicsMemory::Impl* GraphicsMemory::Impl::s_graphicsMemory = nullptr;\n#else\nstd::map<ID3D12Device*, GraphicsMemory::Impl*> GraphicsMemory::Impl::s_graphicsMemory;\n#endif\n\n\n//--------------------------------------------------------------------------------------\n// GraphicsMemory\n//--------------------------------------------------------------------------------------\n\n// Public constructor.\nGraphicsMemory::GraphicsMemory(_In_ ID3D12Device* device)\n    : pImpl(std::make_unique<Impl>(this))\n{\n    pImpl->Initialize(device);\n}\n\n\n// Move constructor.\nGraphicsMemory::GraphicsMemory(GraphicsMemory&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n    pImpl->mOwner = this;\n}\n\n\n// Move assignment.\nGraphicsMemory& GraphicsMemory::operator= (GraphicsMemory&& moveFrom) noexcept\n{ \n    pImpl = std::move(moveFrom.pImpl);\n    pImpl->mOwner = this;\n    return *this;\n}\n\n\n// Public destructor.\nGraphicsMemory::~GraphicsMemory()\n{\n}\n\n\nGraphicsResource GraphicsMemory::Allocate(size_t size, size_t alignment)\n{\n    assert(alignment >= 4); // Should use at least DWORD alignment\n    return pImpl->Allocate(size, alignment);\n}\n\n\nvoid GraphicsMemory::Commit(_In_ ID3D12CommandQueue* commandQueue)\n{\n    pImpl->Commit(commandQueue);\n}\n\n\nvoid GraphicsMemory::GarbageCollect()\n{\n    pImpl->GarbageCollect();\n}\n\nGraphicsMemoryStatistics GraphicsMemory::GetStatistics()\n{\n    GraphicsMemoryStatistics stats;\n    pImpl->GetStatistics(stats);\n    return stats;\n}\n\nvoid GraphicsMemory::ResetStatistics()\n{\n    pImpl->ResetStatistics();\n}\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\nGraphicsMemory& GraphicsMemory::Get(_In_opt_ ID3D12Device*)\n{\n    if (!Impl::s_graphicsMemory || !Impl::s_graphicsMemory->mOwner)\n        throw std::exception(\"GraphicsMemory singleton not created\");\n\n    return *Impl::s_graphicsMemory->mOwner;\n}\n#else\nGraphicsMemory& GraphicsMemory::Get(_In_opt_ ID3D12Device* device)\n{\n    if (Impl::s_graphicsMemory.empty())\n        throw std::exception(\"GraphicsMemory singleton not created\");\n\n    std::map<ID3D12Device*, GraphicsMemory::Impl*>::const_iterator it;\n    if (!device)\n    {\n        // Should only use nullptr for device for single GPU usage\n        assert(Impl::s_graphicsMemory.size() == 1);\n\n        it = Impl::s_graphicsMemory.cbegin();\n    }\n    else\n    {\n        it = Impl::s_graphicsMemory.find(device);\n    }\n\n    if (it == Impl::s_graphicsMemory.cend() || !it->second->mOwner)\n        throw std::exception(\"GraphicsMemory per-device singleton not created\");\n\n    return *it->second->mOwner;\n}\n#endif\n\n\n//--------------------------------------------------------------------------------------\n// GraphicsResource smart-pointer interface\n//--------------------------------------------------------------------------------------\n\nGraphicsResource::GraphicsResource() noexcept\n    : mPage(nullptr)\n    , mGpuAddress {}\n    , mResource(nullptr)\n    , mMemory(nullptr)\n    , mBufferOffset(0)\n    , mSize(0)\n{\n}\n\nGraphicsResource::GraphicsResource(\n    _In_ LinearAllocatorPage* page,\n    _In_ D3D12_GPU_VIRTUAL_ADDRESS gpuAddress,\n    _In_ ID3D12Resource* resource,\n    _In_ void* memory,\n    _In_ size_t offset,\n    _In_ size_t size) noexcept\n    : mPage(page)\n    , mGpuAddress(gpuAddress)\n    , mResource(resource)\n    , mMemory(memory)\n    , mBufferOffset(offset)\n    , mSize(size)\n{\n    assert(mPage != nullptr);\n    mPage->AddRef();\n}\n\nGraphicsResource::GraphicsResource(GraphicsResource&& other) noexcept\n    : mPage(nullptr)\n    , mGpuAddress{}\n    , mResource(nullptr)\n    , mMemory(nullptr)\n    , mBufferOffset(0)\n    , mSize(0)\n{\n    Reset(std::move(other));\n}\n\nGraphicsResource::~GraphicsResource()\n{\n    if (mPage)\n    {\n        mPage->Release();\n        mPage = nullptr;\n    }\n}\n\nGraphicsResource&& GraphicsResource::operator= (GraphicsResource&& other) noexcept\n{\n    Reset(std::move(other));\n    return std::move(*this);\n}\n\nvoid GraphicsResource::Reset() noexcept\n{\n    if (mPage)\n    {\n        mPage->Release();\n        mPage = nullptr;\n    }\n\n    mGpuAddress = {};\n    mResource = nullptr;\n    mMemory = nullptr;\n    mBufferOffset = 0;\n    mSize = 0;\n}\n\nvoid GraphicsResource::Reset(GraphicsResource&& alloc) noexcept\n{\n    if (mPage)\n    {\n        mPage->Release();\n        mPage = nullptr;\n    }\n\n    mGpuAddress = alloc.GpuAddress();\n    mResource = alloc.Resource();\n    mMemory = alloc.Memory();\n    mBufferOffset = alloc.ResourceOffset();\n    mSize = alloc.Size();\n    mPage = alloc.mPage;\n\n    alloc.mGpuAddress = {};\n    alloc.mResource = nullptr;\n    alloc.mMemory = nullptr;\n    alloc.mBufferOffset = 0;\n    alloc.mSize = 0;\n    alloc.mPage = nullptr;\n}\n\n\n//--------------------------------------------------------------------------------------\n// SharedGraphicsResource\n//--------------------------------------------------------------------------------------\n\nSharedGraphicsResource::SharedGraphicsResource() noexcept\n    : mSharedResource(nullptr)\n{\n}\n\nSharedGraphicsResource::SharedGraphicsResource(GraphicsResource&& resource) noexcept(false)\n    : mSharedResource(std::make_shared<GraphicsResource>(std::move(resource)))\n{\n}\n\nSharedGraphicsResource::SharedGraphicsResource(SharedGraphicsResource&& resource) noexcept\n    : mSharedResource(std::move(resource.mSharedResource))\n{\n}\n\nSharedGraphicsResource::SharedGraphicsResource(const SharedGraphicsResource& resource) noexcept\n    : mSharedResource(resource.mSharedResource)\n{\n}\n\nSharedGraphicsResource::~SharedGraphicsResource()\n{\n}\n\nSharedGraphicsResource&& SharedGraphicsResource::operator= (SharedGraphicsResource&& resource) noexcept\n{\n    mSharedResource = std::move(resource.mSharedResource);\n    return std::move(*this);\n}\n\nSharedGraphicsResource&& SharedGraphicsResource::operator= (GraphicsResource&& resource)\n{\n    mSharedResource = std::make_shared<GraphicsResource>(std::move(resource));\n    return std::move(*this);\n}\n\nSharedGraphicsResource& SharedGraphicsResource::operator= (const SharedGraphicsResource& resource) noexcept\n{\n    mSharedResource = resource.mSharedResource;\n    return *this;\n}\n\nvoid SharedGraphicsResource::Reset() noexcept\n{\n    mSharedResource.reset();\n}\n\nvoid SharedGraphicsResource::Reset(GraphicsResource&& resource)\n{\n    mSharedResource = std::make_shared<GraphicsResource>(std::move(resource));\n}\n\nvoid SharedGraphicsResource::Reset(SharedGraphicsResource&& resource) noexcept\n{\n    mSharedResource = std::move(resource.mSharedResource);\n}\n\nvoid SharedGraphicsResource::Reset(const SharedGraphicsResource& resource) noexcept\n{\n    mSharedResource = resource.mSharedResource;\n}\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Keyboard.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: Keyboard.cpp\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Keyboard.h\"\n\n#include \"PlatformHelpers.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nstatic_assert(sizeof(Keyboard::State) == (256 / 8), \"Size mismatch for State\");\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\nnamespace\n{\n    inline void KeyDown(int key, Keyboard::State& state) noexcept\n    {\n        if (key < 0 || key > 0xfe)\n            return;\n\n        auto ptr = reinterpret_cast<uint32_t*>(&state);\n\n        const unsigned int bf = 1u << (key & 0x1f);\n        ptr[(key >> 5)] |= bf;\n    }\n\n    inline void KeyUp(int key, Keyboard::State& state) noexcept\n    {\n        if (key < 0 || key > 0xfe)\n            return;\n\n        auto ptr = reinterpret_cast<uint32_t*>(&state);\n\n        const unsigned int bf = 1u << (key & 0x1f);\n        ptr[(key >> 5)] &= ~bf;\n    }\n}\n\n\n#pragma region Implementations\n#if (defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) || (defined(_GAMING_DESKTOP) && (_GRDK_EDITION >= 220600))\n\n#include <GameInput.h>\n\n//======================================================================================\n// GameInput\n//======================================================================================\n\nclass Keyboard::Impl\n{\npublic:\n    Impl(Keyboard* owner) :\n        mOwner(owner),\n        mConnected(0),\n        mDeviceToken(0),\n        mKeyState{}\n    {\n        if (s_keyboard)\n        {\n            throw std::logic_error(\"Keyboard is a singleton\");\n        }\n\n        s_keyboard = this;\n\n        ThrowIfFailed(GameInputCreate(mGameInput.GetAddressOf()));\n\n        ThrowIfFailed(mGameInput->RegisterDeviceCallback(\n            nullptr,\n            GameInputKindKeyboard,\n            GameInputDeviceConnected,\n            GameInputBlockingEnumeration,\n            this,\n            OnGameInputDevice,\n            &mDeviceToken));\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n        if (mDeviceToken)\n        {\n            if (mGameInput)\n            {\n                if (!mGameInput->UnregisterCallback(mDeviceToken, UINT64_MAX))\n                {\n                    DebugTrace(\"ERROR: GameInput::UnregisterCallback [keyboard] failed\");\n                }\n            }\n\n            mDeviceToken = 0;\n        }\n\n        s_keyboard = nullptr;\n    }\n\n    void GetState(State& state) const\n    {\n        state = {};\n\n        ComPtr<IGameInputReading> reading;\n        if (SUCCEEDED(mGameInput->GetCurrentReading(GameInputKindKeyboard, nullptr, reading.GetAddressOf())))\n        {\n            uint32_t readCount = reading->GetKeyState(c_MaxSimultaneousKeys, mKeyState);\n            for (size_t j = 0; j < readCount; ++j)\n            {\n                int vk = static_cast<int>(mKeyState[j].virtualKey);\n\n                // Workaround for known issues with VK_RSHIFT and VK_NUMLOCK\n                if (vk == 0)\n                {\n                    switch (mKeyState[j].scanCode)\n                    {\n                    case 0xe036: vk = VK_RSHIFT; break;\n                    case 0xe045: vk = VK_NUMLOCK; break;\n                    default: break;\n                    }\n                }\n\n                KeyDown(vk, state);\n            }\n        }\n    }\n\n    void Reset() noexcept\n    {\n    }\n\n    bool IsConnected() const\n    {\n        return mConnected > 0;\n    }\n\n    Keyboard*       mOwner;\n    uint32_t        mConnected;\n\n    static Keyboard::Impl* s_keyboard;\n\nprivate:\n    static constexpr size_t     c_MaxSimultaneousKeys = 16;\n\n    ComPtr<IGameInput>          mGameInput;\n    GameInputCallbackToken      mDeviceToken;\n\n    mutable GameInputKeyState   mKeyState[c_MaxSimultaneousKeys];\n\n    static void CALLBACK OnGameInputDevice(\n        _In_ GameInputCallbackToken,\n        _In_ void * context,\n        _In_ IGameInputDevice *,\n        _In_ uint64_t,\n        _In_ GameInputDeviceStatus currentStatus,\n        _In_ GameInputDeviceStatus) noexcept\n    {\n        auto impl = reinterpret_cast<Keyboard::Impl*>(context);\n\n        if (currentStatus & GameInputDeviceConnected)\n        {\n            ++impl->mConnected;\n        }\n        else if (impl->mConnected > 0)\n        {\n            --impl->mConnected;\n        }\n    }\n};\n\n\nKeyboard::Impl* Keyboard::Impl::s_keyboard = nullptr;\n\n\nvoid Keyboard::ProcessMessage(UINT, WPARAM, LPARAM)\n{\n    // GameInput for Keyboard doesn't require Win32 messages, but this simplifies integration.\n}\n\n\n#elif defined(USING_COREWINDOW)\n\n//======================================================================================\n// Windows Store or Universal Windows Platform (UWP) app implementation\n//======================================================================================\n\n//\n// For a Windows Store app or Universal Windows Platform (UWP) app, add the following:\n//\n// void App::SetWindow(CoreWindow^ window )\n// {\n//     m_keyboard->SetWindow(window);\n// }\n//\n\n#include <Windows.Devices.Input.h>\n\nclass Keyboard::Impl\n{\npublic:\n    Impl(Keyboard* owner) :\n        mState{},\n        mOwner(owner),\n        mAcceleratorKeyToken{},\n        mActivatedToken{}\n    {\n        if (s_keyboard)\n        {\n            throw std::logic_error(\"Keyboard is a singleton\");\n        }\n\n        s_keyboard = this;\n    }\n\n    ~Impl()\n    {\n        s_keyboard = nullptr;\n\n        RemoveHandlers();\n    }\n\n    void GetState(State& state) const\n    {\n        memcpy(&state, &mState, sizeof(State));\n    }\n\n    void Reset() noexcept\n    {\n        memset(&mState, 0, sizeof(State));\n    }\n\n    bool IsConnected() const\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Devices::Input;\n        using namespace ABI::Windows::Foundation;\n\n        ComPtr<IKeyboardCapabilities> caps;\n        HRESULT hr = RoActivateInstance(HStringReference(RuntimeClass_Windows_Devices_Input_KeyboardCapabilities).Get(), &caps);\n        ThrowIfFailed(hr);\n\n        INT32 value;\n        if (SUCCEEDED(caps->get_KeyboardPresent(&value)))\n        {\n            return value != 0;\n        }\n\n        return false;\n    }\n\n    void SetWindow(ABI::Windows::UI::Core::ICoreWindow* window)\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::UI::Core;\n\n        if (mWindow.Get() == window)\n            return;\n\n        RemoveHandlers();\n\n        mWindow = window;\n\n        if (!window)\n            return;\n\n        typedef __FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowActivatedEventArgs ActivatedHandler;\n        HRESULT hr = window->add_Activated(Callback<ActivatedHandler>(Activated).Get(), &mActivatedToken);\n        ThrowIfFailed(hr);\n\n        ComPtr<ICoreDispatcher> dispatcher;\n        hr = window->get_Dispatcher(dispatcher.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        ComPtr<ICoreAcceleratorKeys> keys;\n        hr = dispatcher.As(&keys);\n        ThrowIfFailed(hr);\n\n        typedef __FITypedEventHandler_2_Windows__CUI__CCore__CCoreDispatcher_Windows__CUI__CCore__CAcceleratorKeyEventArgs AcceleratorKeyHandler;\n        hr = keys->add_AcceleratorKeyActivated(Callback<AcceleratorKeyHandler>(AcceleratorKeyEvent).Get(), &mAcceleratorKeyToken);\n        ThrowIfFailed(hr);\n    }\n\n    State       mState;\n    Keyboard*   mOwner;\n\n    static Keyboard::Impl* s_keyboard;\n\nprivate:\n    ComPtr<ABI::Windows::UI::Core::ICoreWindow> mWindow;\n\n    EventRegistrationToken mAcceleratorKeyToken;\n    EventRegistrationToken mActivatedToken;\n\n    void RemoveHandlers()\n    {\n        if (mWindow)\n        {\n            using namespace ABI::Windows::UI::Core;\n\n            ComPtr<ICoreDispatcher> dispatcher;\n            HRESULT hr = mWindow->get_Dispatcher(dispatcher.GetAddressOf());\n            ThrowIfFailed(hr);\n\n            std::ignore = mWindow->remove_Activated(mActivatedToken);\n            mActivatedToken.value = 0;\n\n            ComPtr<ICoreAcceleratorKeys> keys;\n            hr = dispatcher.As(&keys);\n            ThrowIfFailed(hr);\n\n            std::ignore = keys->remove_AcceleratorKeyActivated(mAcceleratorKeyToken);\n            mAcceleratorKeyToken.value = 0;\n        }\n    }\n\n    static HRESULT Activated(IInspectable*, ABI::Windows::UI::Core::IWindowActivatedEventArgs*)\n    {\n        auto pImpl = Impl::s_keyboard;\n\n        if (!pImpl)\n            return S_OK;\n\n        pImpl->Reset();\n\n        return S_OK;\n    }\n\n    static HRESULT AcceleratorKeyEvent(IInspectable*, ABI::Windows::UI::Core::IAcceleratorKeyEventArgs* args)\n    {\n        using namespace ABI::Windows::System;\n        using namespace ABI::Windows::UI::Core;\n\n        auto pImpl = Impl::s_keyboard;\n\n        if (!pImpl)\n            return S_OK;\n\n        CoreAcceleratorKeyEventType evtType;\n        HRESULT hr = args->get_EventType(&evtType);\n        ThrowIfFailed(hr);\n\n        bool down = false;\n\n        switch (evtType)\n        {\n        case CoreAcceleratorKeyEventType_KeyDown:\n        case CoreAcceleratorKeyEventType_SystemKeyDown:\n            down = true;\n            break;\n\n        case CoreAcceleratorKeyEventType_KeyUp:\n        case CoreAcceleratorKeyEventType_SystemKeyUp:\n            break;\n\n        default:\n            return S_OK;\n        }\n\n        CorePhysicalKeyStatus status;\n        hr = args->get_KeyStatus(&status);\n        ThrowIfFailed(hr);\n\n        VirtualKey virtualKey;\n        hr = args->get_VirtualKey(&virtualKey);\n        ThrowIfFailed(hr);\n\n        int vk = static_cast<int>(virtualKey);\n\n        switch (vk)\n        {\n        case VK_SHIFT:\n            vk = (status.ScanCode == 0x36) ? VK_RSHIFT : VK_LSHIFT;\n            if (!down)\n            {\n                // Workaround to ensure left vs. right shift get cleared when both were pressed at same time\n                KeyUp(VK_LSHIFT, pImpl->mState);\n                KeyUp(VK_RSHIFT, pImpl->mState);\n            }\n            break;\n\n        case VK_CONTROL:\n            vk = (status.IsExtendedKey) ? VK_RCONTROL : VK_LCONTROL;\n            break;\n\n        case VK_MENU:\n            vk = (status.IsExtendedKey) ? VK_RMENU : VK_LMENU;\n            break;\n        }\n\n        if (down)\n        {\n            KeyDown(vk, pImpl->mState);\n        }\n        else\n        {\n            KeyUp(vk, pImpl->mState);\n        }\n\n        return S_OK;\n    }\n};\n\n\nKeyboard::Impl* Keyboard::Impl::s_keyboard = nullptr;\n\n\nvoid Keyboard::SetWindow(ABI::Windows::UI::Core::ICoreWindow* window)\n{\n    pImpl->SetWindow(window);\n}\n\n\n#else\n\n//======================================================================================\n// Win32 desktop implementation\n//======================================================================================\n\n//\n// For a Win32 desktop application, call this function from your Window Message Procedure\n//\n// LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n// {\n//     switch (message)\n//     {\n//\n//     case WM_ACTIVATE:\n//     case WM_ACTIVATEAPP:\n//         Keyboard::ProcessMessage(message, wParam, lParam);\n//         break;\n//\n//     case WM_KEYDOWN:\n//     case WM_SYSKEYDOWN:\n//     case WM_KEYUP:\n//     case WM_SYSKEYUP:\n//         Keyboard::ProcessMessage(message, wParam, lParam);\n//         break;\n//\n//     }\n// }\n//\n\nclass Keyboard::Impl\n{\npublic:\n    Impl(Keyboard* owner) :\n        mState{},\n        mOwner(owner)\n    {\n        if (s_keyboard)\n        {\n            throw std::logic_error(\"Keyboard is a singleton\");\n        }\n\n        s_keyboard = this;\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n        s_keyboard = nullptr;\n    }\n\n    void GetState(State& state) const\n    {\n        memcpy(&state, &mState, sizeof(State));\n    }\n\n    void Reset() noexcept\n    {\n        memset(&mState, 0, sizeof(State));\n    }\n\n    bool IsConnected() const\n    {\n        return true;\n    }\n\n    State           mState;\n    Keyboard*       mOwner;\n\n    static Keyboard::Impl* s_keyboard;\n};\n\n\nKeyboard::Impl* Keyboard::Impl::s_keyboard = nullptr;\n\n\nvoid Keyboard::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam)\n{\n    auto pImpl = Impl::s_keyboard;\n\n    if (!pImpl)\n        return;\n\n    bool down = false;\n\n    switch (message)\n    {\n    case WM_ACTIVATE:\n    case WM_ACTIVATEAPP:\n        pImpl->Reset();\n        return;\n\n    case WM_KEYDOWN:\n    case WM_SYSKEYDOWN:\n        down = true;\n        break;\n\n    case WM_KEYUP:\n    case WM_SYSKEYUP:\n        break;\n\n    default:\n        return;\n    }\n\n    int vk = LOWORD(wParam);\n    // We want to distinguish left and right shift/ctrl/alt keys\n    switch (vk)\n    {\n    case VK_SHIFT:\n    case VK_CONTROL:\n    case VK_MENU:\n        {\n            if (vk == VK_SHIFT && !down)\n            {\n                // Workaround to ensure left vs. right shift get cleared when both were pressed at same time\n                KeyUp(VK_LSHIFT, pImpl->mState);\n                KeyUp(VK_RSHIFT, pImpl->mState);\n            }\n\n            bool isExtendedKey = (HIWORD(lParam) & KF_EXTENDED) == KF_EXTENDED;\n            int scanCode = LOBYTE(HIWORD(lParam)) | (isExtendedKey ? 0xe000 : 0);\n            vk = LOWORD(MapVirtualKeyW(static_cast<UINT>(scanCode), MAPVK_VSC_TO_VK_EX));\n        }\n        break;\n    }\n\n    if (down)\n    {\n        KeyDown(vk, pImpl->mState);\n    }\n    else\n    {\n        KeyUp(vk, pImpl->mState);\n    }\n}\n\n#endif\n#pragma endregion\n\n#pragma warning( disable : 4355 )\n\n// Public constructor.\nKeyboard::Keyboard() noexcept(false)\n    : pImpl(std::make_unique<Impl>(this))\n{\n}\n\n\n// Move constructor.\nKeyboard::Keyboard(Keyboard&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n    pImpl->mOwner = this;\n}\n\n\n// Move assignment.\nKeyboard& Keyboard::operator= (Keyboard&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    pImpl->mOwner = this;\n    return *this;\n}\n\n\n// Public destructor.\nKeyboard::~Keyboard() = default;\n\n\nKeyboard::State Keyboard::GetState() const\n{\n    State state;\n    pImpl->GetState(state);\n    return state;\n}\n\n\nvoid Keyboard::Reset() noexcept\n{\n    pImpl->Reset();\n}\n\n\nbool Keyboard::IsConnected() const\n{\n    return pImpl->IsConnected();\n}\n\nKeyboard& Keyboard::Get()\n{\n    if (!Impl::s_keyboard || !Impl::s_keyboard->mOwner)\n        throw std::logic_error(\"Keyboard singleton not created\");\n\n    return *Impl::s_keyboard->mOwner;\n}\n\n\n\n//======================================================================================\n// KeyboardStateTracker\n//======================================================================================\n\nvoid Keyboard::KeyboardStateTracker::Update(const State& state) noexcept\n{\n    auto currPtr = reinterpret_cast<const uint32_t*>(&state);\n    auto prevPtr = reinterpret_cast<const uint32_t*>(&lastState);\n    auto releasedPtr = reinterpret_cast<uint32_t*>(&released);\n    auto pressedPtr = reinterpret_cast<uint32_t*>(&pressed);\n    for (size_t j = 0; j < (256 / 32); ++j)\n    {\n        *pressedPtr = *currPtr & ~(*prevPtr);\n        *releasedPtr = ~(*currPtr) & *prevPtr;\n\n        ++currPtr;\n        ++prevPtr;\n        ++releasedPtr;\n        ++pressedPtr;\n    }\n\n    lastState = state;\n}\n\nvoid Keyboard::KeyboardStateTracker::Reset() noexcept\n{\n    memset(this, 0, sizeof(KeyboardStateTracker));\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/LinearAllocator.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: LinearAllocator.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"LinearAllocator.h\"\n\n// Set this to 1 to enable some additional debug validation\n#define VALIDATE_LISTS 0\n\n#if VALIDATE_LISTS\n#   include <unordered_set>\n#endif\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nLinearAllocatorPage::LinearAllocatorPage() noexcept\n    : pPrevPage(nullptr)\n    , pNextPage(nullptr)\n    , mMemory(nullptr)\n    , mPendingFence(0)\n    , mGpuAddress{}\n    , mOffset(0)\n    , mSize(0)\n    , mRefCount(1)\n{\n}\n\nsize_t LinearAllocatorPage::Suballocate(_In_ size_t size, _In_ size_t alignment)\n{\n    size_t offset = AlignUp(mOffset, alignment);\n    if (offset + size > mSize)\n    {\n        // Use of suballocate should be limited to pages with free space,\n        // so really shouldn't happen.\n        throw std::exception(\"LinearAllocatorPage::Suballocate\");\n    }\n    mOffset = offset + size;\n    return offset;\n}\n\nvoid LinearAllocatorPage::Release() noexcept\n{\n    assert(mRefCount > 0); \n\n    if (mRefCount.fetch_sub(1) == 1)\n    {\n        mUploadResource->Unmap(0, nullptr);\n        delete this;\n    }\n}\n\n\n//--------------------------------------------------------------------------------------\nLinearAllocator::LinearAllocator(\n    _In_ ID3D12Device* pDevice,\n    _In_ size_t pageSize,\n    _In_ size_t preallocateBytes) noexcept(false)\n    : m_pendingPages(nullptr)\n    , m_usedPages(nullptr)\n    , m_unusedPages(nullptr)\n    , m_increment(pageSize)\n    , m_numPending(0)\n    , m_totalPages(0)\n    , m_fenceCount(0)\n    , m_device(pDevice)\n{\n    assert(pDevice != nullptr);\n#if defined(_DEBUG) || defined(PROFILE)\n    m_debugName = L\"LinearAllocator\";\n#endif\n\n    size_t preallocatePageCount = ((preallocateBytes + pageSize - 1) / pageSize);\n    for (size_t preallocatePages = 0; preallocateBytes != 0 && preallocatePages < preallocatePageCount; ++preallocatePages)\n    {\n        if (GetNewPage() == nullptr)\n        {\n            DebugTrace(\"LinearAllocator failed to preallocate pages (%zu required bytes, %zu pages)\\n\",\n                preallocatePageCount * m_increment, preallocatePageCount);\n            throw std::bad_alloc();\n        }\n    }\n\n    ThrowIfFailed(pDevice->CreateFence(\n        0,\n        D3D12_FENCE_FLAG_NONE,\n        IID_GRAPHICS_PPV_ARGS(m_fence.ReleaseAndGetAddressOf())));\n}\n\nLinearAllocator::~LinearAllocator()\n{\n    // Must wait for all pending fences!\n    while (m_pendingPages != nullptr)\n    {\n        RetirePendingPages();\n    }\n\n    assert(m_pendingPages == nullptr);\n\n    // Return all the memory\n    FreePages(m_unusedPages);\n    FreePages(m_usedPages);\n\n    m_pendingPages = nullptr;\n    m_usedPages = nullptr;\n    m_unusedPages = nullptr;\n    m_increment = 0;\n}\n\nLinearAllocatorPage* LinearAllocator::FindPageForAlloc(_In_ size_t size, _In_ size_t alignment)\n{\n#ifdef _DEBUG\n    if (size > m_increment)\n        throw std::out_of_range(\"Size must be less or equal to the allocator's increment\");\n    if (alignment > m_increment)\n        throw std::out_of_range(\"Alignment must be less or equal to the allocator's increment\");\n    if (size == 0)\n        throw std::exception(\"Cannot honor zero size allocation request.\");\n#endif\n\n    auto page = GetPageForAlloc(size, alignment);\n    if (!page)\n    {\n        return nullptr;\n    }\n\n    return page;\n}\n\n// Call this after you submit your work to the driver.\nvoid LinearAllocator::FenceCommittedPages(_In_ ID3D12CommandQueue* commandQueue)\n{\n    // No pending pages\n    if (m_usedPages == nullptr)\n        return;\n\n    // For all the used pages, fence them\n    UINT numReady = 0;\n    LinearAllocatorPage* readyPages = nullptr;\n    LinearAllocatorPage* unreadyPages = nullptr;\n    LinearAllocatorPage* nextPage = nullptr;\n    for (auto page = m_usedPages; page != nullptr; page = nextPage)\n    {\n        nextPage = page->pNextPage;\n\n        // Disconnect from the list\n        page->pPrevPage = nullptr;\n\n        // This implies the allocator is the only remaining reference to the page, and therefore the memory is ready for re-use.\n        if (page->RefCount() == 1)\n        {\n            // Signal the fence\n            numReady++;\n            page->mPendingFence = ++m_fenceCount;\n            ThrowIfFailed(commandQueue->Signal(m_fence.Get(), m_fenceCount));\n\n            // Link to the ready pages list\n            page->pNextPage = readyPages;\n            if (readyPages) readyPages->pPrevPage = page;\n            readyPages = page;\n        }\n        else\n        {\n            // Link to the unready list\n            page->pNextPage = unreadyPages;\n            if (unreadyPages) unreadyPages->pPrevPage = page;\n            unreadyPages = page;\n        }\n    }\n\n    // Replace the used pages list with the new unready list\n    m_usedPages = unreadyPages;\n\n    // Append all those pages from the ready list to the pending list\n    if (numReady > 0)\n    {\n        m_numPending += numReady;\n        LinkPageChain(readyPages, m_pendingPages);\n    }\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n}\n\n// Call this once a frame after all of your driver submissions.\n// (immediately before or after Present-time)\nvoid LinearAllocator::RetirePendingPages() noexcept\n{\n    uint64_t fenceValue = m_fence->GetCompletedValue();\n\n    // For each page that we know has a fence pending, check it. If the fence has passed,\n    // we can mark the page for re-use.\n    auto page = m_pendingPages;\n    while (page != nullptr)\n    {\n        auto nextPage = page->pNextPage;\n\n        assert(page->mPendingFence != 0);\n\n        if (fenceValue >= page->mPendingFence)\n        {\n            // Fence has passed. It is safe to use this page again.\n            ReleasePage(page);\n        }\n\n        page = nextPage;\n    }\n}\n\nvoid LinearAllocator::Shrink() noexcept\n{\n    FreePages(m_unusedPages);\n    m_unusedPages = nullptr;\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n}\n\nLinearAllocatorPage* LinearAllocator::GetCleanPageForAlloc()\n{\n    // Grab the first unused page, if one exists. Else, allocate a new page.\n    auto page = m_unusedPages;\n    if (!page)\n    {\n        // Allocate a new page\n        page = GetNewPage();\n        if (!page)\n        {\n            return nullptr;\n        }\n    }\n\n    // Mark this page as used\n    UnlinkPage(page);\n    LinkPage(page, m_usedPages);\n\n    assert(page->mOffset == 0);\n\n    return page;\n}\n\nLinearAllocatorPage* LinearAllocator::GetPageForAlloc(\n    size_t sizeBytes,\n    size_t alignment)\n{\n    // Fast path\n    if (sizeBytes == m_increment && (alignment == 0 || alignment == m_increment))\n    {\n        return GetCleanPageForAlloc();\n    }\n\n    // Find a page in the pending pages list that has space.\n    auto page = FindPageForAlloc(m_usedPages, sizeBytes, alignment);\n    if (!page)\n    {\n        page = GetCleanPageForAlloc();\n    }\n\n    return page;\n}\n\nLinearAllocatorPage* LinearAllocator::FindPageForAlloc(\n    LinearAllocatorPage* list,\n    size_t sizeBytes,\n    size_t alignment) noexcept\n{\n    for (auto page = list; page != nullptr; page = page->pNextPage)\n    {\n        size_t offset = AlignUp(page->mOffset, alignment);\n        if (offset + sizeBytes <= m_increment)\n            return page;\n    }\n    return nullptr;\n}\n\nLinearAllocatorPage* LinearAllocator::GetNewPage()\n{\n    CD3DX12_HEAP_PROPERTIES uploadHeapProperties(D3D12_HEAP_TYPE_UPLOAD);\n    CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(m_increment);\n\n    // Allocate the upload heap\n    ComPtr<ID3D12Resource> spResource;\n    HRESULT hr = m_device->CreateCommittedResource(\n        &uploadHeapProperties,\n        D3D12_HEAP_FLAG_NONE,\n        &bufferDesc,\n        D3D12_RESOURCE_STATE_GENERIC_READ,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(spResource.ReleaseAndGetAddressOf()));\n    if (FAILED(hr))\n    {\n        if (hr != E_OUTOFMEMORY)\n        {\n            DebugTrace(\"LinearAllocator::GetNewPage resource allocation failed due to unexpected error %08X\\n\", static_cast<unsigned int>(hr));\n        }\n        return nullptr;\n    }\n\n#if defined(_DEBUG) || defined(PROFILE)\n    spResource->SetName(m_debugName.empty() ? L\"LinearAllocator\" : m_debugName.c_str());\n#endif\n\n    // Get a pointer to the memory\n    void* pMemory = nullptr;\n    ThrowIfFailed(spResource->Map(0, nullptr, &pMemory));\n    memset(pMemory, 0, m_increment);\n\n    // Add the page to the page list\n    auto page = new LinearAllocatorPage;\n    page->mMemory = pMemory;\n    page->mGpuAddress = spResource->GetGPUVirtualAddress();\n    page->mSize = m_increment;\n    page->mUploadResource.Swap(spResource);\n\n    // Set as head of the list\n    page->pNextPage = m_unusedPages;\n    if (m_unusedPages) m_unusedPages->pPrevPage = page;\n    m_unusedPages = page;\n    m_totalPages++;\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n\n    return page;\n}\n\nvoid LinearAllocator::UnlinkPage(LinearAllocatorPage* page) noexcept\n{\n    if (page->pPrevPage)\n        page->pPrevPage->pNextPage = page->pNextPage;\n\n    // Check that it isn't the head of any of our tracked lists\n    else if (page == m_unusedPages)\n        m_unusedPages = page->pNextPage;\n    else if (page == m_usedPages)\n        m_usedPages = page->pNextPage;\n    else if (page == m_pendingPages)\n        m_pendingPages = page->pNextPage;\n\n    if (page->pNextPage)\n        page->pNextPage->pPrevPage = page->pPrevPage;\n\n    page->pNextPage = nullptr;\n    page->pPrevPage = nullptr;\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n}\n\nvoid LinearAllocator::LinkPageChain(LinearAllocatorPage* page, LinearAllocatorPage*& list) noexcept\n{\n#if VALIDATE_LISTS\n    // Walk the chain and ensure it's not in the list twice\n    for (LinearAllocatorPage* cur = list; cur != nullptr; cur = cur->pNextPage)\n    {\n        assert(cur != page);\n    }\n#endif\n    assert(page->pPrevPage == nullptr);\n    assert(list == nullptr || list->pPrevPage == nullptr);\n\n    // Follow chain to the end and append\n    LinearAllocatorPage* lastPage = nullptr;\n    for (lastPage = page; lastPage->pNextPage != nullptr; lastPage = lastPage->pNextPage) {}\n\n    lastPage->pNextPage = list;\n    if (list)\n        list->pPrevPage = lastPage;\n\n    list = page;\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n}\n\nvoid LinearAllocator::LinkPage(LinearAllocatorPage* page, LinearAllocatorPage*& list) noexcept\n{\n#if VALIDATE_LISTS\n    // Walk the chain and ensure it's not in the list twice\n    for (LinearAllocatorPage* cur = list; cur != nullptr; cur = cur->pNextPage)\n    {\n        assert(cur != page);\n    }\n#endif\n    assert(page->pNextPage == nullptr);\n    assert(page->pPrevPage == nullptr);\n    assert(list == nullptr || list->pPrevPage == nullptr);\n\n    page->pNextPage = list;\n    if (list)\n        list->pPrevPage = page;\n\n    list = page;\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n}\n\nvoid LinearAllocator::ReleasePage(LinearAllocatorPage* page) noexcept\n{\n    assert(m_numPending > 0);\n    m_numPending--;\n\n    UnlinkPage(page);\n    LinkPage(page, m_unusedPages);\n\n    // Reset the page offset (effectively erasing the memory)\n    page->mOffset = 0;\n\n#ifdef _DEBUG\n    memset(page->mMemory, 0, m_increment);\n#endif\n\n#if VALIDATE_LISTS\n    ValidatePageLists();\n#endif\n}\n\nvoid LinearAllocator::FreePages(LinearAllocatorPage* page) noexcept\n{\n    while (page != nullptr)\n    {\n        auto nextPage = page->pNextPage;\n\n        page->Release();\n\n        page = nextPage;\n        assert(m_totalPages > 0);\n        m_totalPages--;\n    }\n}\n\n#if VALIDATE_LISTS\nvoid LinearAllocator::ValidateList(LinearAllocatorPage* list)\n{\n    for (auto page = list, *lastPage = nullptr;\n        page != nullptr;\n        lastPage = page, page = page->pNextPage)\n    {\n        if (page->pPrevPage != lastPage)\n        {\n            throw std::exception(\"Broken link to previous\");\n        }\n    }\n}\n\nvoid LinearAllocator::ValidatePageLists()\n{\n    ValidateList(m_pendingPages);\n    ValidateList(m_usedPages);\n    ValidateList(m_unusedPages);\n}\n#endif\n\n#if defined(_DEBUG) || defined(PROFILE)\nvoid LinearAllocator::SetDebugName(const char* name)\n{\n    wchar_t wname[MAX_PATH] = {};\n    int result = MultiByteToWideChar(CP_UTF8, 0, name, static_cast<int>(strlen(name)), wname, MAX_PATH);\n    if (result > 0)\n    {\n        SetDebugName(wname);\n    }\n}\n\nvoid LinearAllocator::SetDebugName(const wchar_t* name)\n{\n    m_debugName = name;\n\n    // Rename existing pages\n    m_fence->SetName(name);\n    SetPageDebugName(m_pendingPages);\n    SetPageDebugName(m_usedPages);\n    SetPageDebugName(m_unusedPages);\n}\n\nvoid LinearAllocator::SetPageDebugName(LinearAllocatorPage* list) noexcept\n{\n    for (auto page = list; page != nullptr; page = page->pNextPage)\n    {\n        page->mUploadResource->SetName(m_debugName.c_str());\n    }\n}\n#endif\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/LinearAllocator.h",
    "content": "//--------------------------------------------------------------------------------------\n// LinearAllocator.h\n//\n// A linear allocator. When Allocate is called it will try to return you a pointer into\n// existing graphics memory. If there is no space left from what is allocated, more \n// pages are allocated on-the-fly.\n//\n// Each allocation must be smaller or equal to pageSize. It is not necessary but is most\n// efficient for the sizes to be some fraction of pageSize. pageSize does not determine \n// the size of the physical pages underneath the virtual memory (that's given by the\n// XMemAttributes) but is how much additional memory the allocator should allocate \n// each time you run out of space.\n//\n// preallocatePages specifies how many pages to initially allocate. Specifying zero will \n// preallocate two pages by default.\n//\n// This class is NOT thread safe. You should protect this with the appropriate sync\n// primitives or, even better, use one linear allocator per thread.\n//\n// Pages are freed once the GPU is done with them. As such, you need to specify when a \n// page is in use and when it is no longer in use. Use RetirePages to prompt the \n// allocator to check if pages are no longer being used by the GPU. Use InsertFences to\n// mark all used pages as in-use by the GPU, removing them from the available pages \n// list. It is recommended you call RetirePages and InsertFences once a frame, usually\n// just before Present().\n//\n// Why is RetirePages decoupled from InsertFences? It's possible that you might want to \n// reclaim pages more frequently than locking used pages. For example, if you find the \n// allocator is burning through pages too quickly you can call RetirePages to reclaim \n// some that the GPU has finished with. However, this adds additional CPU overhead so it\n// is left to you to decide. In most cases this is sufficient:\n//\n//      allocator.RetirePages();\n//      allocator.InsertFences( pContext, 0 );\n//      Present(...);\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <atomic>\n\n\nnamespace DirectX\n{\n    class LinearAllocatorPage\n    {\n    public:\n        LinearAllocatorPage() noexcept;\n\n        LinearAllocatorPage(LinearAllocatorPage&&) = delete;\n        LinearAllocatorPage& operator= (LinearAllocatorPage&&) = delete;\n\n        LinearAllocatorPage(LinearAllocatorPage const&) = delete;\n        LinearAllocatorPage& operator=(LinearAllocatorPage const&) = delete;\n\n        size_t Suballocate(_In_ size_t size, _In_ size_t alignment);\n\n        void* BaseMemory() const noexcept { return mMemory; }\n        ID3D12Resource* UploadResource() const noexcept { return mUploadResource.Get(); }\n        D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const noexcept { return mGpuAddress; }\n        size_t BytesUsed() const noexcept { return mOffset; }\n        size_t Size() const noexcept { return mSize; }\n\n        void AddRef() noexcept { mRefCount.fetch_add(1); }\n        int32_t RefCount() const noexcept { return mRefCount.load(); }\n        void Release() noexcept;\n\n    protected:\n        friend class LinearAllocator;\n\n        LinearAllocatorPage*                    pPrevPage;\n        LinearAllocatorPage*                    pNextPage;\n\n        void*                                   mMemory;\n        uint64_t                                mPendingFence;\n        D3D12_GPU_VIRTUAL_ADDRESS               mGpuAddress;\n        size_t                                  mOffset;\n        size_t                                  mSize;\n        Microsoft::WRL::ComPtr<ID3D12Resource>  mUploadResource;\n\n    private:\n        std::atomic<int32_t>                    mRefCount;\n    };\n\n    class LinearAllocator\n    {\n    public:        \n        // These values will be rounded up to the nearest 64k.\n        // You can specify zero for incrementalSizeBytes to increment\n        // by 1 page (64k).\n        LinearAllocator(\n            _In_ ID3D12Device* pDevice,\n            _In_ size_t pageSize,\n            _In_ size_t preallocateBytes = 0) noexcept(false);\n\n        LinearAllocator(LinearAllocator&&) = default;\n        LinearAllocator& operator= (LinearAllocator&&) = default;\n\n        LinearAllocator(LinearAllocator const&) = delete;\n        LinearAllocator& operator=(LinearAllocator const&) = delete;\n\n        ~LinearAllocator();\n\n        LinearAllocatorPage* FindPageForAlloc(_In_ size_t requestedSize, _In_ size_t alignment);\n\n        // Call this at least once a frame to check if pages have become available.\n        void RetirePendingPages() noexcept;\n\n        // Call this after you submit your work to the driver.\n        // (e.g. immediately before Present.)\n        void FenceCommittedPages(_In_ ID3D12CommandQueue* commandQueue);\n\n        // Throws away all currently unused pages\n        void Shrink() noexcept;\n\n        // Statistics\n        size_t CommittedPageCount() const noexcept { return m_numPending; }\n        size_t TotalPageCount() const noexcept { return m_totalPages; }\n        size_t CommittedMemoryUsage() const noexcept { return m_numPending * m_increment; }\n        size_t TotalMemoryUsage() const noexcept { return m_totalPages * m_increment; }\n        size_t PageSize() const noexcept { return m_increment; }\n\n#if defined(_DEBUG) || defined(PROFILE)\n        // Debug info\n        const wchar_t* GetDebugName() const noexcept { return m_debugName.c_str(); }\n        void SetDebugName(const wchar_t* name);\n        void SetDebugName(const char* name);\n#endif\n\n    private:\n        LinearAllocatorPage*                    m_pendingPages; // Pages in use by the GPU\n        LinearAllocatorPage*                    m_usedPages;    // Pages to be submitted to the GPU\n        LinearAllocatorPage*                    m_unusedPages;  // Pages not being used right now\n        size_t                                  m_increment;\n        size_t                                  m_numPending;\n        size_t                                  m_totalPages;\n        uint64_t                                m_fenceCount;\n        Microsoft::WRL::ComPtr<ID3D12Device>    m_device;\n        Microsoft::WRL::ComPtr<ID3D12Fence>     m_fence;\n        \n        LinearAllocatorPage* GetPageForAlloc(size_t sizeBytes, size_t alignment);\n        LinearAllocatorPage* GetCleanPageForAlloc();\n\n        LinearAllocatorPage* FindPageForAlloc(LinearAllocatorPage* list, size_t sizeBytes, size_t alignment) noexcept;\n\n        LinearAllocatorPage* GetNewPage();\n\n        void UnlinkPage(LinearAllocatorPage* page) noexcept;\n        void LinkPage(LinearAllocatorPage* page, LinearAllocatorPage*& list) noexcept;\n        void LinkPageChain(LinearAllocatorPage* page, LinearAllocatorPage*& list) noexcept;\n        void ReleasePage(LinearAllocatorPage* page) noexcept;\n        void FreePages(LinearAllocatorPage* list) noexcept;\n\n#if defined(_DEBUG) || defined(PROFILE)\n        std::wstring m_debugName;\n\n        static void ValidateList(LinearAllocatorPage* list);\n        void ValidatePageLists();\n\n        void SetPageDebugName(LinearAllocatorPage* list) noexcept;\n#endif\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/LoaderHelpers.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: LoaderHelpers.h\n//\n// Helper functions for texture loaders and screen grabber\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"DDS.h\"\n#include \"DDSTextureLoader.h\"\n#include \"PlatformHelpers.h\"\n\n\nnamespace DirectX\n{\n    namespace LoaderHelpers\n    {\n        //--------------------------------------------------------------------------------------\n        // Return the BPP for a particular format\n        //--------------------------------------------------------------------------------------\n        inline size_t BitsPerPixel(_In_ DXGI_FORMAT fmt) noexcept\n        {\n            switch (fmt)\n            {\n                case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n                case DXGI_FORMAT_R32G32B32A32_FLOAT:\n                case DXGI_FORMAT_R32G32B32A32_UINT:\n                case DXGI_FORMAT_R32G32B32A32_SINT:\n                    return 128;\n\n                case DXGI_FORMAT_R32G32B32_TYPELESS:\n                case DXGI_FORMAT_R32G32B32_FLOAT:\n                case DXGI_FORMAT_R32G32B32_UINT:\n                case DXGI_FORMAT_R32G32B32_SINT:\n                    return 96;\n\n                case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n                case DXGI_FORMAT_R16G16B16A16_FLOAT:\n                case DXGI_FORMAT_R16G16B16A16_UNORM:\n                case DXGI_FORMAT_R16G16B16A16_UINT:\n                case DXGI_FORMAT_R16G16B16A16_SNORM:\n                case DXGI_FORMAT_R16G16B16A16_SINT:\n                case DXGI_FORMAT_R32G32_TYPELESS:\n                case DXGI_FORMAT_R32G32_FLOAT:\n                case DXGI_FORMAT_R32G32_UINT:\n                case DXGI_FORMAT_R32G32_SINT:\n                case DXGI_FORMAT_R32G8X24_TYPELESS:\n                case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n                case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n                case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n                case DXGI_FORMAT_Y416:\n                case DXGI_FORMAT_Y210:\n                case DXGI_FORMAT_Y216:\n                    return 64;\n\n                case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n                case DXGI_FORMAT_R10G10B10A2_UNORM:\n                case DXGI_FORMAT_R10G10B10A2_UINT:\n                case DXGI_FORMAT_R11G11B10_FLOAT:\n                case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n                case DXGI_FORMAT_R8G8B8A8_UNORM:\n                case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n                case DXGI_FORMAT_R8G8B8A8_UINT:\n                case DXGI_FORMAT_R8G8B8A8_SNORM:\n                case DXGI_FORMAT_R8G8B8A8_SINT:\n                case DXGI_FORMAT_R16G16_TYPELESS:\n                case DXGI_FORMAT_R16G16_FLOAT:\n                case DXGI_FORMAT_R16G16_UNORM:\n                case DXGI_FORMAT_R16G16_UINT:\n                case DXGI_FORMAT_R16G16_SNORM:\n                case DXGI_FORMAT_R16G16_SINT:\n                case DXGI_FORMAT_R32_TYPELESS:\n                case DXGI_FORMAT_D32_FLOAT:\n                case DXGI_FORMAT_R32_FLOAT:\n                case DXGI_FORMAT_R32_UINT:\n                case DXGI_FORMAT_R32_SINT:\n                case DXGI_FORMAT_R24G8_TYPELESS:\n                case DXGI_FORMAT_D24_UNORM_S8_UINT:\n                case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n                case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n                case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n                case DXGI_FORMAT_R8G8_B8G8_UNORM:\n                case DXGI_FORMAT_G8R8_G8B8_UNORM:\n                case DXGI_FORMAT_B8G8R8A8_UNORM:\n                case DXGI_FORMAT_B8G8R8X8_UNORM:\n                case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n                case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n                case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n                case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n                case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n                case DXGI_FORMAT_AYUV:\n                case DXGI_FORMAT_Y410:\n                case DXGI_FORMAT_YUY2:\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n                case DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n                case DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n                case DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n#endif\n                    return 32;\n\n                case DXGI_FORMAT_P010:\n                case DXGI_FORMAT_P016:\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n                case DXGI_FORMAT_V408:\n#endif\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n                case DXGI_FORMAT_D16_UNORM_S8_UINT:\n                case DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n                case DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n#endif\n                    return 24;\n\n                case DXGI_FORMAT_R8G8_TYPELESS:\n                case DXGI_FORMAT_R8G8_UNORM:\n                case DXGI_FORMAT_R8G8_UINT:\n                case DXGI_FORMAT_R8G8_SNORM:\n                case DXGI_FORMAT_R8G8_SINT:\n                case DXGI_FORMAT_R16_TYPELESS:\n                case DXGI_FORMAT_R16_FLOAT:\n                case DXGI_FORMAT_D16_UNORM:\n                case DXGI_FORMAT_R16_UNORM:\n                case DXGI_FORMAT_R16_UINT:\n                case DXGI_FORMAT_R16_SNORM:\n                case DXGI_FORMAT_R16_SINT:\n                case DXGI_FORMAT_B5G6R5_UNORM:\n                case DXGI_FORMAT_B5G5R5A1_UNORM:\n                case DXGI_FORMAT_A8P8:\n                case DXGI_FORMAT_B4G4R4A4_UNORM:\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n                case DXGI_FORMAT_P208:\n                case DXGI_FORMAT_V208:\n#endif\n                    return 16;\n\n                case DXGI_FORMAT_NV12:\n                case DXGI_FORMAT_420_OPAQUE:\n                case DXGI_FORMAT_NV11:\n                    return 12;\n\n                case DXGI_FORMAT_R8_TYPELESS:\n                case DXGI_FORMAT_R8_UNORM:\n                case DXGI_FORMAT_R8_UINT:\n                case DXGI_FORMAT_R8_SNORM:\n                case DXGI_FORMAT_R8_SINT:\n                case DXGI_FORMAT_A8_UNORM:\n                case DXGI_FORMAT_BC2_TYPELESS:\n                case DXGI_FORMAT_BC2_UNORM:\n                case DXGI_FORMAT_BC2_UNORM_SRGB:\n                case DXGI_FORMAT_BC3_TYPELESS:\n                case DXGI_FORMAT_BC3_UNORM:\n                case DXGI_FORMAT_BC3_UNORM_SRGB:\n                case DXGI_FORMAT_BC5_TYPELESS:\n                case DXGI_FORMAT_BC5_UNORM:\n                case DXGI_FORMAT_BC5_SNORM:\n                case DXGI_FORMAT_BC6H_TYPELESS:\n                case DXGI_FORMAT_BC6H_UF16:\n                case DXGI_FORMAT_BC6H_SF16:\n                case DXGI_FORMAT_BC7_TYPELESS:\n                case DXGI_FORMAT_BC7_UNORM:\n                case DXGI_FORMAT_BC7_UNORM_SRGB:\n                case DXGI_FORMAT_AI44:\n                case DXGI_FORMAT_IA44:\n                case DXGI_FORMAT_P8:\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n                case DXGI_FORMAT_R4G4_UNORM:\n#endif\n                    return 8;\n\n                case DXGI_FORMAT_R1_UNORM:\n                    return 1;\n\n                case DXGI_FORMAT_BC1_TYPELESS:\n                case DXGI_FORMAT_BC1_UNORM:\n                case DXGI_FORMAT_BC1_UNORM_SRGB:\n                case DXGI_FORMAT_BC4_TYPELESS:\n                case DXGI_FORMAT_BC4_UNORM:\n                case DXGI_FORMAT_BC4_SNORM:\n                    return 4;\n\n                case DXGI_FORMAT_UNKNOWN:\n                case DXGI_FORMAT_FORCE_UINT:\n                default:\n                    return 0;\n            }\n        }\n\n        //--------------------------------------------------------------------------------------\n        inline DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format) noexcept\n        {\n            switch (format)\n            {\n                case DXGI_FORMAT_R8G8B8A8_UNORM:\n                    return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n\n                case DXGI_FORMAT_BC1_UNORM:\n                    return DXGI_FORMAT_BC1_UNORM_SRGB;\n\n                case DXGI_FORMAT_BC2_UNORM:\n                    return DXGI_FORMAT_BC2_UNORM_SRGB;\n\n                case DXGI_FORMAT_BC3_UNORM:\n                    return DXGI_FORMAT_BC3_UNORM_SRGB;\n\n                case DXGI_FORMAT_B8G8R8A8_UNORM:\n                    return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;\n\n                case DXGI_FORMAT_B8G8R8X8_UNORM:\n                    return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;\n\n                case DXGI_FORMAT_BC7_UNORM:\n                    return DXGI_FORMAT_BC7_UNORM_SRGB;\n\n                default:\n                    return format;\n            }\n        }\n\n        //--------------------------------------------------------------------------------------\n        inline bool IsCompressed(_In_ DXGI_FORMAT fmt) noexcept\n        {\n            switch (fmt)\n            {\n                case DXGI_FORMAT_BC1_TYPELESS:\n                case DXGI_FORMAT_BC1_UNORM:\n                case DXGI_FORMAT_BC1_UNORM_SRGB:\n                case DXGI_FORMAT_BC2_TYPELESS:\n                case DXGI_FORMAT_BC2_UNORM:\n                case DXGI_FORMAT_BC2_UNORM_SRGB:\n                case DXGI_FORMAT_BC3_TYPELESS:\n                case DXGI_FORMAT_BC3_UNORM:\n                case DXGI_FORMAT_BC3_UNORM_SRGB:\n                case DXGI_FORMAT_BC4_TYPELESS:\n                case DXGI_FORMAT_BC4_UNORM:\n                case DXGI_FORMAT_BC4_SNORM:\n                case DXGI_FORMAT_BC5_TYPELESS:\n                case DXGI_FORMAT_BC5_UNORM:\n                case DXGI_FORMAT_BC5_SNORM:\n                case DXGI_FORMAT_BC6H_TYPELESS:\n                case DXGI_FORMAT_BC6H_UF16:\n                case DXGI_FORMAT_BC6H_SF16:\n                case DXGI_FORMAT_BC7_TYPELESS:\n                case DXGI_FORMAT_BC7_UNORM:\n                case DXGI_FORMAT_BC7_UNORM_SRGB:\n                    return true;\n\n                default:\n                    return false;\n            }\n        }\n\n        //--------------------------------------------------------------------------------------\n        inline DXGI_FORMAT EnsureNotTypeless(DXGI_FORMAT fmt) noexcept\n        {\n            // Assumes UNORM or FLOAT; doesn't use UINT or SINT\n            switch (fmt)\n            {\n                case DXGI_FORMAT_R32G32B32A32_TYPELESS: return DXGI_FORMAT_R32G32B32A32_FLOAT;\n                case DXGI_FORMAT_R32G32B32_TYPELESS:    return DXGI_FORMAT_R32G32B32_FLOAT;\n                case DXGI_FORMAT_R16G16B16A16_TYPELESS: return DXGI_FORMAT_R16G16B16A16_UNORM;\n                case DXGI_FORMAT_R32G32_TYPELESS:       return DXGI_FORMAT_R32G32_FLOAT;\n                case DXGI_FORMAT_R10G10B10A2_TYPELESS:  return DXGI_FORMAT_R10G10B10A2_UNORM;\n                case DXGI_FORMAT_R8G8B8A8_TYPELESS:     return DXGI_FORMAT_R8G8B8A8_UNORM;\n                case DXGI_FORMAT_R16G16_TYPELESS:       return DXGI_FORMAT_R16G16_UNORM;\n                case DXGI_FORMAT_R32_TYPELESS:          return DXGI_FORMAT_R32_FLOAT;\n                case DXGI_FORMAT_R8G8_TYPELESS:         return DXGI_FORMAT_R8G8_UNORM;\n                case DXGI_FORMAT_R16_TYPELESS:          return DXGI_FORMAT_R16_UNORM;\n                case DXGI_FORMAT_R8_TYPELESS:           return DXGI_FORMAT_R8_UNORM;\n                case DXGI_FORMAT_BC1_TYPELESS:          return DXGI_FORMAT_BC1_UNORM;\n                case DXGI_FORMAT_BC2_TYPELESS:          return DXGI_FORMAT_BC2_UNORM;\n                case DXGI_FORMAT_BC3_TYPELESS:          return DXGI_FORMAT_BC3_UNORM;\n                case DXGI_FORMAT_BC4_TYPELESS:          return DXGI_FORMAT_BC4_UNORM;\n                case DXGI_FORMAT_BC5_TYPELESS:          return DXGI_FORMAT_BC5_UNORM;\n                case DXGI_FORMAT_B8G8R8A8_TYPELESS:     return DXGI_FORMAT_B8G8R8A8_UNORM;\n                case DXGI_FORMAT_B8G8R8X8_TYPELESS:     return DXGI_FORMAT_B8G8R8X8_UNORM;\n                case DXGI_FORMAT_BC7_TYPELESS:          return DXGI_FORMAT_BC7_UNORM;\n                default:                                return fmt;\n            }\n        }\n\n        //--------------------------------------------------------------------------------------\n        inline HRESULT LoadTextureDataFromMemory(\n            _In_reads_(ddsDataSize) const uint8_t* ddsData,\n            size_t ddsDataSize,\n            const DDS_HEADER** header,\n            const uint8_t** bitData,\n            size_t* bitSize) noexcept\n        {\n            if (!header || !bitData || !bitSize)\n            {\n                return E_POINTER;\n            }\n\n            if (ddsDataSize > UINT32_MAX)\n            {\n                return E_FAIL;\n            }\n\n            if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER)))\n            {\n                return E_FAIL;\n            }\n\n            // DDS files always start with the same magic number (\"DDS \")\n            auto dwMagicNumber = *reinterpret_cast<const uint32_t*>(ddsData);\n            if (dwMagicNumber != DDS_MAGIC)\n            {\n                return E_FAIL;\n            }\n\n            auto hdr = reinterpret_cast<const DDS_HEADER*>(ddsData + sizeof(uint32_t));\n\n            // Verify header to validate DDS file\n            if (hdr->size != sizeof(DDS_HEADER) ||\n                hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))\n            {\n                return E_FAIL;\n            }\n\n            // Check for DX10 extension\n            bool bDXT10Header = false;\n            if ((hdr->ddspf.flags & DDS_FOURCC) &&\n                (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))\n            {\n                // Must be long enough for both headers and magic value\n                if (ddsDataSize < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10)))\n                {\n                    return E_FAIL;\n                }\n\n                bDXT10Header = true;\n            }\n\n            // setup the pointers in the process request\n            *header = hdr;\n            auto offset = sizeof(uint32_t)\n                + sizeof(DDS_HEADER)\n                + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u);\n            *bitData = ddsData + offset;\n            *bitSize = ddsDataSize - offset;\n\n            return S_OK;\n        }\n\n        //--------------------------------------------------------------------------------------\n        inline HRESULT LoadTextureDataFromFile(\n            _In_z_ const wchar_t* fileName,\n            std::unique_ptr<uint8_t[]>& ddsData,\n            const DDS_HEADER** header,\n            const uint8_t** bitData,\n            size_t* bitSize) noexcept\n        {\n            if (!header || !bitData || !bitSize)\n            {\n                return E_POINTER;\n            }\n\n            // open the file\n        #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n            ScopedHandle hFile(safe_handle(CreateFile2(fileName,\n                               GENERIC_READ,\n                               FILE_SHARE_READ,\n                               OPEN_EXISTING,\n                               nullptr)));\n        #else\n            ScopedHandle hFile(safe_handle(CreateFileW(fileName,\n                               GENERIC_READ,\n                               FILE_SHARE_READ,\n                               nullptr,\n                               OPEN_EXISTING,\n                               FILE_ATTRIBUTE_NORMAL,\n                               nullptr)));\n        #endif\n\n            if (!hFile)\n            {\n                return HRESULT_FROM_WIN32(GetLastError());\n            }\n\n            // Get the file size\n            FILE_STANDARD_INFO fileInfo;\n            if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n            {\n                return HRESULT_FROM_WIN32(GetLastError());\n            }\n\n            // File is too big for 32-bit allocation, so reject read\n            if (fileInfo.EndOfFile.HighPart > 0)\n            {\n                return E_FAIL;\n            }\n\n            // Need at least enough data to fill the header and magic number to be a valid DDS\n            if (fileInfo.EndOfFile.LowPart < (sizeof(uint32_t) + sizeof(DDS_HEADER)))\n            {\n                return E_FAIL;\n            }\n\n            // create enough space for the file data\n            ddsData.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);\n            if (!ddsData)\n            {\n                return E_OUTOFMEMORY;\n            }\n\n            // read the data in\n            DWORD BytesRead = 0;\n            if (!ReadFile(hFile.get(),\n                ddsData.get(),\n                fileInfo.EndOfFile.LowPart,\n                &BytesRead,\n                nullptr\n                ))\n            {\n                return HRESULT_FROM_WIN32(GetLastError());\n            }\n\n            if (BytesRead < fileInfo.EndOfFile.LowPart)\n            {\n                return E_FAIL;\n            }\n\n            // DDS files always start with the same magic number (\"DDS \")\n            auto dwMagicNumber = *reinterpret_cast<const uint32_t*>(ddsData.get());\n            if (dwMagicNumber != DDS_MAGIC)\n            {\n                return E_FAIL;\n            }\n\n            auto hdr = reinterpret_cast<const DDS_HEADER*>(ddsData.get() + sizeof(uint32_t));\n\n            // Verify header to validate DDS file\n            if (hdr->size != sizeof(DDS_HEADER) ||\n                hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))\n            {\n                return E_FAIL;\n            }\n\n            // Check for DX10 extension\n            bool bDXT10Header = false;\n            if ((hdr->ddspf.flags & DDS_FOURCC) &&\n                (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))\n            {\n                // Must be long enough for both headers and magic value\n                if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10)))\n                {\n                    return E_FAIL;\n                }\n\n                bDXT10Header = true;\n            }\n\n            // setup the pointers in the process request\n            *header = hdr;\n            auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER)\n                + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u);\n            *bitData = ddsData.get() + offset;\n            *bitSize = fileInfo.EndOfFile.LowPart - offset;\n\n            return S_OK;\n        }\n\n        //--------------------------------------------------------------------------------------\n        // Get surface information for a particular format\n        //--------------------------------------------------------------------------------------\n        inline HRESULT GetSurfaceInfo(\n            _In_ size_t width,\n            _In_ size_t height,\n            _In_ DXGI_FORMAT fmt,\n            _Out_opt_ size_t* outNumBytes,\n            _Out_opt_ size_t* outRowBytes,\n            _Out_opt_ size_t* outNumRows) noexcept\n        {\n            uint64_t numBytes = 0;\n            uint64_t rowBytes = 0;\n            uint64_t numRows = 0;\n\n            bool bc = false;\n            bool packed = false;\n            bool planar = false;\n            size_t bpe = 0;\n            switch (fmt)\n            {\n            case DXGI_FORMAT_BC1_TYPELESS:\n            case DXGI_FORMAT_BC1_UNORM:\n            case DXGI_FORMAT_BC1_UNORM_SRGB:\n            case DXGI_FORMAT_BC4_TYPELESS:\n            case DXGI_FORMAT_BC4_UNORM:\n            case DXGI_FORMAT_BC4_SNORM:\n                bc = true;\n                bpe = 8;\n                break;\n\n            case DXGI_FORMAT_BC2_TYPELESS:\n            case DXGI_FORMAT_BC2_UNORM:\n            case DXGI_FORMAT_BC2_UNORM_SRGB:\n            case DXGI_FORMAT_BC3_TYPELESS:\n            case DXGI_FORMAT_BC3_UNORM:\n            case DXGI_FORMAT_BC3_UNORM_SRGB:\n            case DXGI_FORMAT_BC5_TYPELESS:\n            case DXGI_FORMAT_BC5_UNORM:\n            case DXGI_FORMAT_BC5_SNORM:\n            case DXGI_FORMAT_BC6H_TYPELESS:\n            case DXGI_FORMAT_BC6H_UF16:\n            case DXGI_FORMAT_BC6H_SF16:\n            case DXGI_FORMAT_BC7_TYPELESS:\n            case DXGI_FORMAT_BC7_UNORM:\n            case DXGI_FORMAT_BC7_UNORM_SRGB:\n                bc = true;\n                bpe = 16;\n                break;\n\n            case DXGI_FORMAT_R8G8_B8G8_UNORM:\n            case DXGI_FORMAT_G8R8_G8B8_UNORM:\n            case DXGI_FORMAT_YUY2:\n                packed = true;\n                bpe = 4;\n                break;\n\n            case DXGI_FORMAT_Y210:\n            case DXGI_FORMAT_Y216:\n                packed = true;\n                bpe = 8;\n                break;\n\n            case DXGI_FORMAT_NV12:\n            case DXGI_FORMAT_420_OPAQUE:\n        #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n            case DXGI_FORMAT_P208:\n        #endif\n                planar = true;\n                bpe = 2;\n                break;\n\n            case DXGI_FORMAT_P010:\n            case DXGI_FORMAT_P016:\n                planar = true;\n                bpe = 4;\n                break;\n\n        #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n\n            case DXGI_FORMAT_D16_UNORM_S8_UINT:\n            case DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n            case DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n                planar = true;\n                bpe = 4;\n                break;\n\n        #endif\n\n            default:\n                break;\n            }\n\n            if (bc)\n            {\n                uint64_t numBlocksWide = 0;\n                if (width > 0)\n                {\n                    numBlocksWide = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);\n                }\n                uint64_t numBlocksHigh = 0;\n                if (height > 0)\n                {\n                    numBlocksHigh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);\n                }\n                rowBytes = numBlocksWide * bpe;\n                numRows = numBlocksHigh;\n                numBytes = rowBytes * numBlocksHigh;\n            }\n            else if (packed)\n            {\n                rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;\n                numRows = uint64_t(height);\n                numBytes = rowBytes * height;\n            }\n            else if (fmt == DXGI_FORMAT_NV11)\n            {\n                rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;\n                numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data\n                numBytes = rowBytes * numRows;\n            }\n            else if (planar)\n            {\n                rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;\n                numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);\n                numRows = height + ((uint64_t(height) + 1u) >> 1);\n            }\n            else\n            {\n                size_t bpp = BitsPerPixel(fmt);\n                if (!bpp)\n                    return E_INVALIDARG;\n\n                rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte\n                numRows = uint64_t(height);\n                numBytes = rowBytes * height;\n            }\n\n        #if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)\n            static_assert(sizeof(size_t) == 4, \"Not a 32-bit platform!\");\n            if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)\n                return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n        #else\n            static_assert(sizeof(size_t) == 8, \"Not a 64-bit platform!\");\n        #endif\n\n            if (outNumBytes)\n            {\n                *outNumBytes = static_cast<size_t>(numBytes);\n            }\n            if (outRowBytes)\n            {\n                *outRowBytes = static_cast<size_t>(rowBytes);\n            }\n            if (outNumRows)\n            {\n                *outNumRows = static_cast<size_t>(numRows);\n            }\n\n            return S_OK;\n        }\n\n        //--------------------------------------------------------------------------------------\n    #define ISBITMASK( r,g,b,a ) ( ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a )\n\n        inline DXGI_FORMAT GetDXGIFormat(const DDS_PIXELFORMAT& ddpf) noexcept\n        {\n            if (ddpf.flags & DDS_RGB)\n            {\n                // Note that sRGB formats are written using the \"DX10\" extended header\n\n                switch (ddpf.RGBBitCount)\n                {\n                    case 32:\n                        if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))\n                        {\n                            return DXGI_FORMAT_R8G8B8A8_UNORM;\n                        }\n\n                        if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))\n                        {\n                            return DXGI_FORMAT_B8G8R8A8_UNORM;\n                        }\n\n                        if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0))\n                        {\n                            return DXGI_FORMAT_B8G8R8X8_UNORM;\n                        }\n\n                        // No DXGI format maps to ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0) aka D3DFMT_X8B8G8R8\n\n                        // Note that many common DDS reader/writers (including D3DX) swap the\n                        // the RED/BLUE masks for 10:10:10:2 formats. We assume\n                        // below that the 'backwards' header mask is being used since it is most\n                        // likely written by D3DX. The more robust solution is to use the 'DX10'\n                        // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly\n\n                        // For 'correct' writers, this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data\n                        if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))\n                        {\n                            return DXGI_FORMAT_R10G10B10A2_UNORM;\n                        }\n\n                        // No DXGI format maps to ISBITMASK(0x000003ff,0x000ffc00,0x3ff00000,0xc0000000) aka D3DFMT_A2R10G10B10\n\n                        if (ISBITMASK(0x0000ffff, 0xffff0000, 0, 0))\n                        {\n                            return DXGI_FORMAT_R16G16_UNORM;\n                        }\n\n                        if (ISBITMASK(0xffffffff, 0, 0, 0))\n                        {\n                            // Only 32-bit color channel format in D3D9 was R32F\n                            return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114\n                        }\n                        break;\n\n                    case 24:\n                        // No 24bpp DXGI formats aka D3DFMT_R8G8B8\n                        break;\n\n                    case 16:\n                        if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000))\n                        {\n                            return DXGI_FORMAT_B5G5R5A1_UNORM;\n                        }\n                        if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0))\n                        {\n                            return DXGI_FORMAT_B5G6R5_UNORM;\n                        }\n\n                        // No DXGI format maps to ISBITMASK(0x7c00,0x03e0,0x001f,0) aka D3DFMT_X1R5G5B5\n\n                        if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0xf000))\n                        {\n                            return DXGI_FORMAT_B4G4R4A4_UNORM;\n                        }\n\n                        // No DXGI format maps to ISBITMASK(0x0f00,0x00f0,0x000f,0) aka D3DFMT_X4R4G4B4\n\n                        // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.\n                        break;\n                }\n            }\n            else if (ddpf.flags & DDS_LUMINANCE)\n            {\n                if (8 == ddpf.RGBBitCount)\n                {\n                    if (ISBITMASK(0xff, 0, 0, 0))\n                    {\n                        return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension\n                    }\n\n                    // No DXGI format maps to ISBITMASK(0x0f,0,0,0xf0) aka D3DFMT_A4L4\n\n                    if (ISBITMASK(0x00ff, 0, 0, 0xff00))\n                    {\n                        return DXGI_FORMAT_R8G8_UNORM; // Some DDS writers assume the bitcount should be 8 instead of 16\n                    }\n                }\n\n                if (16 == ddpf.RGBBitCount)\n                {\n                    if (ISBITMASK(0xffff, 0, 0, 0))\n                    {\n                        return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension\n                    }\n                    if (ISBITMASK(0x00ff, 0, 0, 0xff00))\n                    {\n                        return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension\n                    }\n                }\n            }\n            else if (ddpf.flags & DDS_ALPHA)\n            {\n                if (8 == ddpf.RGBBitCount)\n                {\n                    return DXGI_FORMAT_A8_UNORM;\n                }\n            }\n            else if (ddpf.flags & DDS_BUMPDUDV)\n            {\n                if (16 == ddpf.RGBBitCount)\n                {\n                    if (ISBITMASK(0x00ff, 0xff00, 0, 0))\n                    {\n                        return DXGI_FORMAT_R8G8_SNORM; // D3DX10/11 writes this out as DX10 extension\n                    }\n                }\n\n                if (32 == ddpf.RGBBitCount)\n                {\n                    if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))\n                    {\n                        return DXGI_FORMAT_R8G8B8A8_SNORM; // D3DX10/11 writes this out as DX10 extension\n                    }\n                    if (ISBITMASK(0x0000ffff, 0xffff0000, 0, 0))\n                    {\n                        return DXGI_FORMAT_R16G16_SNORM; // D3DX10/11 writes this out as DX10 extension\n                    }\n\n                    // No DXGI format maps to ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000) aka D3DFMT_A2W10V10U10\n                }\n\n                // No DXGI format maps to DDPF_BUMPLUMINANCE aka D3DFMT_L6V5U5, D3DFMT_X8L8V8U8\n            }\n            else if (ddpf.flags & DDS_FOURCC)\n            {\n                if (MAKEFOURCC('D', 'X', 'T', '1') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC1_UNORM;\n                }\n                if (MAKEFOURCC('D', 'X', 'T', '3') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC2_UNORM;\n                }\n                if (MAKEFOURCC('D', 'X', 'T', '5') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC3_UNORM;\n                }\n\n                // While pre-multiplied alpha isn't directly supported by the DXGI formats,\n                // they are basically the same as these BC formats so they can be mapped\n                if (MAKEFOURCC('D', 'X', 'T', '2') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC2_UNORM;\n                }\n                if (MAKEFOURCC('D', 'X', 'T', '4') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC3_UNORM;\n                }\n\n                if (MAKEFOURCC('A', 'T', 'I', '1') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC4_UNORM;\n                }\n                if (MAKEFOURCC('B', 'C', '4', 'U') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC4_UNORM;\n                }\n                if (MAKEFOURCC('B', 'C', '4', 'S') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC4_SNORM;\n                }\n\n                if (MAKEFOURCC('A', 'T', 'I', '2') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC5_UNORM;\n                }\n                if (MAKEFOURCC('B', 'C', '5', 'U') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC5_UNORM;\n                }\n                if (MAKEFOURCC('B', 'C', '5', 'S') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_BC5_SNORM;\n                }\n\n                // BC6H and BC7 are written using the \"DX10\" extended header\n\n                if (MAKEFOURCC('R', 'G', 'B', 'G') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_R8G8_B8G8_UNORM;\n                }\n                if (MAKEFOURCC('G', 'R', 'G', 'B') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_G8R8_G8B8_UNORM;\n                }\n\n                if (MAKEFOURCC('Y', 'U', 'Y', '2') == ddpf.fourCC)\n                {\n                    return DXGI_FORMAT_YUY2;\n                }\n\n                // Check for D3DFORMAT enums being set here\n                switch (ddpf.fourCC)\n                {\n                    case 36: // D3DFMT_A16B16G16R16\n                        return DXGI_FORMAT_R16G16B16A16_UNORM;\n\n                    case 110: // D3DFMT_Q16W16V16U16\n                        return DXGI_FORMAT_R16G16B16A16_SNORM;\n\n                    case 111: // D3DFMT_R16F\n                        return DXGI_FORMAT_R16_FLOAT;\n\n                    case 112: // D3DFMT_G16R16F\n                        return DXGI_FORMAT_R16G16_FLOAT;\n\n                    case 113: // D3DFMT_A16B16G16R16F\n                        return DXGI_FORMAT_R16G16B16A16_FLOAT;\n\n                    case 114: // D3DFMT_R32F\n                        return DXGI_FORMAT_R32_FLOAT;\n\n                    case 115: // D3DFMT_G32R32F\n                        return DXGI_FORMAT_R32G32_FLOAT;\n\n                    case 116: // D3DFMT_A32B32G32R32F\n                        return DXGI_FORMAT_R32G32B32A32_FLOAT;\n\n                    // No DXGI format maps to D3DFMT_CxV8U8\n                }\n            }\n\n            return DXGI_FORMAT_UNKNOWN;\n        }\n\n    #undef ISBITMASK\n\n        //--------------------------------------------------------------------------------------\n        inline DirectX::DDS_ALPHA_MODE GetAlphaMode(_In_ const DDS_HEADER* header) noexcept\n        {\n            if (header->ddspf.flags & DDS_FOURCC)\n            {\n                if (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC)\n                {\n                    auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>(reinterpret_cast<const uint8_t*>(header) + sizeof(DDS_HEADER));\n                    auto mode = static_cast<DDS_ALPHA_MODE>(d3d10ext->miscFlags2 & DDS_MISC_FLAGS2_ALPHA_MODE_MASK);\n                    switch (mode)\n                    {\n                        case DDS_ALPHA_MODE_STRAIGHT:\n                        case DDS_ALPHA_MODE_PREMULTIPLIED:\n                        case DDS_ALPHA_MODE_OPAQUE:\n                        case DDS_ALPHA_MODE_CUSTOM:\n                            return mode;\n\n                        case DDS_ALPHA_MODE_UNKNOWN:\n                        default:\n                            break;\n                    }\n                }\n                else if ((MAKEFOURCC('D', 'X', 'T', '2') == header->ddspf.fourCC)\n                         || (MAKEFOURCC('D', 'X', 'T', '4') == header->ddspf.fourCC))\n                {\n                    return DDS_ALPHA_MODE_PREMULTIPLIED;\n                }\n            }\n\n            return DDS_ALPHA_MODE_UNKNOWN;\n        }\n\n        //--------------------------------------------------------------------------------------\n        class auto_delete_file\n        {\n        public:\n            auto_delete_file(HANDLE hFile) noexcept : m_handle(hFile) {}\n\n            auto_delete_file(const auto_delete_file&) = delete;\n            auto_delete_file& operator=(const auto_delete_file&) = delete;\n\n            auto_delete_file(const auto_delete_file&&) = delete;\n            auto_delete_file& operator=(const auto_delete_file&&) = delete;\n\n            ~auto_delete_file()\n            {\n                if (m_handle)\n                {\n                    FILE_DISPOSITION_INFO info = {};\n                    info.DeleteFile = TRUE;\n                    (void)SetFileInformationByHandle(m_handle, FileDispositionInfo, &info, sizeof(info));\n                }\n            }\n\n            void clear() noexcept { m_handle = nullptr; }\n\n        private:\n            HANDLE m_handle;\n        };\n\n        class auto_delete_file_wic\n        {\n        public:\n            auto_delete_file_wic(Microsoft::WRL::ComPtr<IWICStream>& hFile, LPCWSTR szFile) noexcept : m_filename(szFile), m_handle(hFile) {}\n\n            auto_delete_file_wic(const auto_delete_file_wic&) = delete;\n            auto_delete_file_wic& operator=(const auto_delete_file_wic&) = delete;\n\n            auto_delete_file_wic(const auto_delete_file_wic&&) = delete;\n            auto_delete_file_wic& operator=(const auto_delete_file_wic&&) = delete;\n\n            ~auto_delete_file_wic()\n            {\n                if (m_filename)\n                {\n                    m_handle.Reset();\n                    DeleteFileW(m_filename);\n                }\n            }\n\n            void clear() noexcept { m_filename = nullptr; }\n\n        private:\n            LPCWSTR m_filename;\n            Microsoft::WRL::ComPtr<IWICStream>& m_handle;\n        };\n\n        inline uint32_t CountMips(uint32_t width, uint32_t height) noexcept\n        {\n            if (width == 0 || height == 0)\n                return 0;\n\n            uint32_t count = 1;\n            while (width > 1 || height > 1)\n            {\n                width >>= 1;\n                height >>= 1;\n                count++;\n            }\n            return count;\n        }\n\n        inline void FitPowerOf2(UINT origx, UINT origy, UINT& targetx, UINT& targety, size_t maxsize)\n        {\n            float origAR = float(origx) / float(origy);\n\n            if (origx > origy)\n            {\n                size_t x;\n                for (x = maxsize; x > 1; x >>= 1) { if (x <= targetx) break; }\n                targetx = UINT(x);\n\n                float bestScore = FLT_MAX;\n                for (size_t y = maxsize; y > 0; y >>= 1)\n                {\n                    float score = fabsf((float(x) / float(y)) - origAR);\n                    if (score < bestScore)\n                    {\n                        bestScore = score;\n                        targety = UINT(y);\n                    }\n                }\n            }\n            else\n            {\n                size_t y;\n                for (y = maxsize; y > 1; y >>= 1) { if (y <= targety) break; }\n                targety = UINT(y);\n\n                float bestScore = FLT_MAX;\n                for (size_t x = maxsize; x > 0; x >>= 1)\n                {\n                    float score = fabsf((float(x) / float(y)) - origAR);\n                    if (score < bestScore)\n                    {\n                        bestScore = score;\n                        targetx = UINT(x);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Model.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: Model.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Model.h\"\n\n#include \"CommonStates.h\"\n#include \"DescriptorHeap.h\"\n#include \"DirectXHelpers.h\"\n#include \"Effects.h\"\n#include \"PlatformHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n\nusing namespace DirectX;\n\n#ifndef _CPPRTTI \n#error Model requires RTTI\n#endif\n\n\n//--------------------------------------------------------------------------------------\n// ModelMeshPart\n//--------------------------------------------------------------------------------------\n\nModelMeshPart::ModelMeshPart(uint32_t ipartIndex) noexcept :\n    partIndex(ipartIndex),\n    materialIndex(0),\n    indexCount(0),\n    startIndex(0),\n    vertexOffset(0),\n    vertexStride(0),\n    vertexCount(0),\n    indexBufferSize(0),\n    vertexBufferSize(0),\n    primitiveType(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST),\n    indexFormat(DXGI_FORMAT_R16_UINT)\n{\n}\n\n\nModelMeshPart::~ModelMeshPart()\n{\n}\n\n\n_Use_decl_annotations_\nvoid ModelMeshPart::Draw(_In_ ID3D12GraphicsCommandList* commandList) const\n{\n    if (!indexBufferSize || !vertexBufferSize)\n    {\n        DebugTrace(\"ERROR: Model part missing values for vertex and/or index buffer size (indexBufferSize %u, vertexBufferSize %u)!\\n\", indexBufferSize, vertexBufferSize);\n        throw std::exception(\"ModelMeshPart\");\n    }\n\n    if (!staticIndexBuffer && !indexBuffer)\n    {\n        DebugTrace(\"ERROR: Model part missing index buffer!\\n\");\n        throw std::exception(\"ModelMeshPart\");\n    }\n\n    if (!staticVertexBuffer && !vertexBuffer)\n    {\n        DebugTrace(\"ERROR: Model part missing vertex buffer!\\n\");\n        throw std::exception(\"ModelMeshPart\");\n    }\n\n    D3D12_VERTEX_BUFFER_VIEW vbv;\n    vbv.BufferLocation = staticVertexBuffer ? staticVertexBuffer->GetGPUVirtualAddress() : vertexBuffer.GpuAddress();\n    vbv.StrideInBytes = vertexStride;\n    vbv.SizeInBytes = vertexBufferSize;\n    commandList->IASetVertexBuffers(0, 1, &vbv);\n\n    D3D12_INDEX_BUFFER_VIEW ibv;\n    ibv.BufferLocation = staticIndexBuffer ? staticIndexBuffer->GetGPUVirtualAddress() : indexBuffer.GpuAddress();\n    ibv.SizeInBytes = indexBufferSize;\n    ibv.Format = indexFormat;\n    commandList->IASetIndexBuffer(&ibv);\n\n    commandList->IASetPrimitiveTopology(primitiveType);\n\n    commandList->DrawIndexedInstanced(indexCount, 1, startIndex, vertexOffset, 0);\n}\n\n\n_Use_decl_annotations_\nvoid ModelMeshPart::DrawInstanced(_In_ ID3D12GraphicsCommandList* commandList, uint32_t instanceCount, uint32_t startInstanceLocation) const\n{\n    if (!indexBufferSize || !vertexBufferSize)\n    {\n        DebugTrace(\"ERROR: Model part missing values for vertex and/or index buffer size (indexBufferSize %u, vertexBufferSize %u)!\\n\", indexBufferSize, vertexBufferSize);\n        throw std::exception(\"ModelMeshPart\");\n    }\n\n    if (!staticIndexBuffer && !indexBuffer)\n    {\n        DebugTrace(\"ERROR: Model part missing index buffer!\\n\");\n        throw std::exception(\"ModelMeshPart\");\n    }\n\n    if (!staticVertexBuffer && !vertexBuffer)\n    {\n        DebugTrace(\"ERROR: Model part missing vertex buffer!\\n\");\n        throw std::exception(\"ModelMeshPart\");\n    }\n\n    D3D12_VERTEX_BUFFER_VIEW vbv;\n    vbv.BufferLocation = staticVertexBuffer ? staticVertexBuffer->GetGPUVirtualAddress() : vertexBuffer.GpuAddress();\n    vbv.StrideInBytes = vertexStride;\n    vbv.SizeInBytes = vertexBufferSize;\n    commandList->IASetVertexBuffers(0, 1, &vbv);\n\n    D3D12_INDEX_BUFFER_VIEW ibv;\n    ibv.BufferLocation = staticIndexBuffer ? staticIndexBuffer->GetGPUVirtualAddress() : indexBuffer.GpuAddress();\n    ibv.SizeInBytes = indexBufferSize;\n    ibv.Format = indexFormat;\n    commandList->IASetIndexBuffer(&ibv);\n\n    commandList->IASetPrimitiveTopology(primitiveType);\n\n    commandList->DrawIndexedInstanced(indexCount, instanceCount, startIndex, vertexOffset, startInstanceLocation);\n}\n\n\n_Use_decl_annotations_\nvoid ModelMeshPart::DrawMeshParts(ID3D12GraphicsCommandList* commandList, const ModelMeshPart::Collection& meshParts)\n{\n    for (auto it = meshParts.cbegin(); it != meshParts.cend(); ++it)\n    {\n        auto part = (*it).get();\n        assert(part != nullptr);\n\n        part->Draw(commandList);\n    }\n}\n\n\n_Use_decl_annotations_\nvoid ModelMeshPart::DrawMeshParts(\n    ID3D12GraphicsCommandList* commandList,\n    const ModelMeshPart::Collection& meshParts,\n    ModelMeshPart::DrawCallback callback)\n{\n    for (auto it = meshParts.cbegin(); it != meshParts.cend(); ++it)\n    {\n        auto part = (*it).get();\n        assert(part != nullptr);\n\n        callback(commandList, *part);\n        part->Draw(commandList);\n    }\n}\n\n\n_Use_decl_annotations_\nvoid ModelMeshPart::DrawMeshParts(ID3D12GraphicsCommandList* commandList,\n    const ModelMeshPart::Collection& meshParts,\n    IEffect* effect)\n{\n    effect->Apply(commandList);\n    DrawMeshParts(commandList, meshParts);\n}\n\n\n//--------------------------------------------------------------------------------------\n// ModelMesh\n//--------------------------------------------------------------------------------------\n\nModelMesh::ModelMesh() noexcept\n{\n}\n\n\nModelMesh::~ModelMesh()\n{\n}\n\n// Draw the mesh\nvoid __cdecl ModelMesh::DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList) const\n{\n    ModelMeshPart::DrawMeshParts(commandList, opaqueMeshParts);\n}\n\nvoid __cdecl ModelMesh::DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList) const\n{\n    ModelMeshPart::DrawMeshParts(commandList, alphaMeshParts);\n}\n\n\n// Draw the mesh with an effect\nvoid __cdecl ModelMesh::DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList, _In_ IEffect* effect) const\n{\n    ModelMeshPart::DrawMeshParts(commandList, opaqueMeshParts, effect);\n}\n\nvoid __cdecl ModelMesh::DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList, _In_ IEffect* effect) const\n{\n    ModelMeshPart::DrawMeshParts(commandList, alphaMeshParts, effect);\n}\n\n\n// Draw the mesh with a callback for each mesh part\nvoid __cdecl ModelMesh::DrawOpaque(_In_ ID3D12GraphicsCommandList* commandList, ModelMeshPart::DrawCallback callback) const\n{\n    ModelMeshPart::DrawMeshParts(commandList, opaqueMeshParts, callback);\n}\n\nvoid __cdecl ModelMesh::DrawAlpha(_In_ ID3D12GraphicsCommandList* commandList, ModelMeshPart::DrawCallback callback) const\n{\n    ModelMeshPart::DrawMeshParts(commandList, alphaMeshParts, callback);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Model\n//--------------------------------------------------------------------------------------\nModel::Model() noexcept\n{\n}\n\n\nModel::~Model()\n{\n}\n\n\n// Load texture resources\nint Model::LoadTextures(IEffectTextureFactory& texFactory, int destinationDescriptorOffset) const\n{\n    for (size_t i = 0; i < textureNames.size(); ++i)\n    {\n        texFactory.CreateTexture(textureNames[i].c_str(), destinationDescriptorOffset + static_cast<int>(i));\n    }\n\n    return static_cast<int>(textureNames.size());\n}\n\n\n// Load texture resources (helper function)\n_Use_decl_annotations_\nstd::unique_ptr<EffectTextureFactory> Model::LoadTextures(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUploadBatch,\n    const wchar_t* texturesPath,\n    D3D12_DESCRIPTOR_HEAP_FLAGS flags) const\n{\n    if (textureNames.empty())\n        return nullptr;\n\n    std::unique_ptr<EffectTextureFactory> texFactory = std::make_unique<EffectTextureFactory>(\n        device,\n        resourceUploadBatch,\n        textureNames.size(),\n        flags);\n    if (texturesPath != nullptr && *texturesPath != 0)\n    {\n        texFactory->SetDirectory(texturesPath);\n    }\n\n    LoadTextures(*texFactory);\n\n    return texFactory;\n}\n\n\n// Load VB/IB resources for static geometry\n_Use_decl_annotations_\nvoid Model::LoadStaticBuffers(\n    ID3D12Device* device,\n    ResourceUploadBatch& resourceUploadBatch,\n    bool keepMemory)\n{\n    // Gather all unique parts\n    std::set<ModelMeshPart*> uniqueParts;\n    for (const auto& mesh : meshes)\n    {\n        for (const auto& part : mesh->opaqueMeshParts)\n        {\n            uniqueParts.insert(part.get());\n        }\n        for (const auto& part : mesh->alphaMeshParts)\n        {\n            uniqueParts.insert(part.get());\n        }\n    }\n\n    CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    for(auto it = uniqueParts.cbegin(); it != uniqueParts.cend(); ++it)\n    {\n        auto part = *it;\n\n        // Convert dynamic VB to static VB\n        if (!part->staticVertexBuffer)\n        {\n            if (!part->vertexBuffer)\n            {\n                DebugTrace(\"ERROR: Model part missing vertex buffer!\\n\");\n                throw std::exception(\"ModelMeshPart\");\n            }\n\n            part->vertexBufferSize = static_cast<uint32_t>(part->vertexBuffer.Size());\n\n            auto desc = CD3DX12_RESOURCE_DESC::Buffer(part->vertexBuffer.Size());\n\n            ThrowIfFailed(device->CreateCommittedResource(\n                &heapProperties,\n                D3D12_HEAP_FLAG_NONE,\n                &desc,\n                D3D12_RESOURCE_STATE_COPY_DEST,\n                nullptr,\n                IID_GRAPHICS_PPV_ARGS(part->staticVertexBuffer.GetAddressOf())\n            ));\n\n            SetDebugObjectName(part->staticVertexBuffer.Get(), L\"ModelMeshPart\");\n\n            resourceUploadBatch.Upload(part->staticVertexBuffer.Get(), part->vertexBuffer);\n\n            resourceUploadBatch.Transition(part->staticVertexBuffer.Get(),\n                D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);\n\n            // Scan for any other part with the same vertex buffer for sharing\n            for (auto sit = std::next(it); sit != uniqueParts.cend(); ++sit)\n            {\n                auto sharePart = *sit;\n                assert(sharePart != part);\n\n                if (sharePart->staticVertexBuffer)\n                    continue;\n\n                if (sharePart->vertexBuffer == part->vertexBuffer)\n                {\n                    sharePart->vertexBufferSize = part->vertexBufferSize;\n                    sharePart->staticVertexBuffer = part->staticVertexBuffer;\n\n                    if (!keepMemory)\n                    {\n                        sharePart->vertexBuffer.Reset();\n                    }\n                }\n            }\n\n            if (!keepMemory)\n            {\n                part->vertexBuffer.Reset();\n            }\n        }\n\n        // Convert dynamic IB to static IB\n        if (!part->staticIndexBuffer)\n        {\n            if (!part->indexBuffer)\n            {\n                DebugTrace(\"ERROR: Model part missing index buffer!\\n\");\n                throw std::exception(\"ModelMeshPart\");\n            }\n\n            part->indexBufferSize = static_cast<uint32_t>(part->indexBuffer.Size());\n\n            auto desc = CD3DX12_RESOURCE_DESC::Buffer(part->indexBuffer.Size());\n\n            ThrowIfFailed(device->CreateCommittedResource(\n                &heapProperties,\n                D3D12_HEAP_FLAG_NONE,\n                &desc,\n                D3D12_RESOURCE_STATE_COPY_DEST,\n                nullptr,\n                IID_GRAPHICS_PPV_ARGS(part->staticIndexBuffer.GetAddressOf())\n            ));\n\n            SetDebugObjectName(part->staticIndexBuffer.Get(), L\"ModelMeshPart\");\n\n            resourceUploadBatch.Upload(part->staticIndexBuffer.Get(), part->indexBuffer);\n\n            resourceUploadBatch.Transition(part->staticIndexBuffer.Get(),\n                D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);\n\n            // Scan for any other part with the same index buffer for sharing\n            for (auto sit = std::next(it); sit != uniqueParts.cend(); ++sit)\n            {\n                auto sharePart = *sit;\n                assert(sharePart != part);\n\n                if (sharePart->staticIndexBuffer)\n                    continue;\n\n                if (sharePart->indexBuffer == part->indexBuffer)\n                {\n                    sharePart->indexBufferSize = part->indexBufferSize;\n                    sharePart->staticIndexBuffer = part->staticIndexBuffer;\n\n                    if (!keepMemory)\n                    {\n                        sharePart->indexBuffer.Reset();\n                    }\n                }\n            }\n\n            if (!keepMemory)\n            {\n                part->indexBuffer.Reset();\n            }\n        }\n    }\n}\n\n\n// Create effects for each mesh piece\nstd::vector<std::shared_ptr<IEffect>> Model::CreateEffects(\n    IEffectFactory& fxFactory,\n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    int textureDescriptorOffset,\n    int samplerDescriptorOffset) const\n{\n    if (materials.empty())\n    {\n        DebugTrace(\"ERROR: Model has no material information to create effects!\\n\");\n        throw std::exception(\"CreateEffects\");\n    }\n\n    std::vector<std::shared_ptr<IEffect>> effects;\n\n    // Count the number of parts\n    uint32_t partCount = 0;\n    for (const auto& mesh : meshes)\n    {\n        for (const auto& part : mesh->opaqueMeshParts)\n            partCount = std::max(part->partIndex + 1, partCount);\n        for (const auto& part : mesh->alphaMeshParts)\n            partCount = std::max(part->partIndex + 1, partCount);\n    }\n\n    if (partCount == 0)\n        return effects;\n\n    // Create an array of effects for each part. We need to have an effect per part because the part's vertex layout\n    // combines with the material spec to create a unique effect. We rely on the EffectFactory to de-duplicate if it\n    // wants to.\n    effects.resize(partCount);\n\n    for (const auto& mesh : meshes)\n    {\n        assert(mesh != nullptr);\n\n        for (const auto& part : mesh->opaqueMeshParts)\n        {\n            assert(part != nullptr);\n\n            if (part->materialIndex == uint32_t(-1))\n                continue;\n\n            // If this fires, you have multiple parts with the same unique ID\n            assert(effects[part->partIndex] == nullptr);\n\n            effects[part->partIndex] = CreateEffectForMeshPart(fxFactory, opaquePipelineState, alphaPipelineState, textureDescriptorOffset, samplerDescriptorOffset, part.get());\n        }\n\n        for (const auto& part : mesh->alphaMeshParts)\n        {\n            assert(part != nullptr);\n\n            if (part->materialIndex == uint32_t(-1))\n                continue;\n\n            // If this fires, you have multiple parts with the same unique ID\n            assert(effects[part->partIndex] == nullptr);\n\n            effects[part->partIndex] = CreateEffectForMeshPart(fxFactory, opaquePipelineState, alphaPipelineState, textureDescriptorOffset, samplerDescriptorOffset, part.get());\n        }\n    }\n\n    return effects;\n}\n\n// Creates an effect for a mesh part\n_Use_decl_annotations_\nstd::shared_ptr<IEffect> Model::CreateEffectForMeshPart(\n    IEffectFactory& fxFactory,\n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    int textureDescriptorOffset,\n    int samplerDescriptorOffset,\n    const ModelMeshPart* part) const\n{\n    assert(part->materialIndex < materials.size());\n    const auto& m = materials[part->materialIndex];\n\n    if (!part->vbDecl || part->vbDecl->empty())\n        throw std::exception(\"Model mesh part missing vertex buffer input elements data\");\n\n    if (part->vbDecl->size() > D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT)\n        throw std::exception(\"Model mesh part input layout size is too large for DirectX 12\");\n\n    D3D12_INPUT_LAYOUT_DESC il = {};\n    il.NumElements = static_cast<UINT>(part->vbDecl->size());\n    il.pInputElementDescs = part->vbDecl->data();\n\n    return fxFactory.CreateEffect(m, opaquePipelineState, alphaPipelineState, il, textureDescriptorOffset, samplerDescriptorOffset);\n}\n\n// Create effects for each mesh piece with the default factory\n_Use_decl_annotations_\nstd::vector<std::shared_ptr<IEffect>> Model::CreateEffects(\n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    ID3D12DescriptorHeap* textureDescriptorHeap,\n    ID3D12DescriptorHeap* samplerDescriptorHeap,\n    int textureDescriptorOffset,\n    int samplerDescriptorOffset) const\n{\n    EffectFactory fxFactory(textureDescriptorHeap, samplerDescriptorHeap);\n    return CreateEffects(fxFactory, opaquePipelineState, alphaPipelineState, textureDescriptorOffset, samplerDescriptorOffset);\n}\n\n// Updates effect matrices (if applicable)\nvoid XM_CALLCONV Model::UpdateEffectMatrices(\n    _In_ std::vector<std::shared_ptr<IEffect>>& effectList,\n    DirectX::FXMMATRIX world,\n    DirectX::CXMMATRIX view,\n    DirectX::CXMMATRIX proj)\n{\n    for (auto& fx : effectList)\n    {\n        auto matFx = dynamic_cast<IEffectMatrices*>(fx.get());\n        if (matFx)\n        {\n            matFx->SetMatrices(world, view, proj);\n        }\n    }\n}\n\n// Transition static VB/IB resources (if applicable)\nvoid Model::Transition(\n    _In_ ID3D12GraphicsCommandList* commandList,\n    D3D12_RESOURCE_STATES stateBeforeVB,\n    D3D12_RESOURCE_STATES stateAfterVB,\n    D3D12_RESOURCE_STATES stateBeforeIB,\n    D3D12_RESOURCE_STATES stateAfterIB)\n{\n    UINT count = 0;\n    D3D12_RESOURCE_BARRIER barrier[64] = {};\n\n    for (auto& mit : meshes)\n    {\n        for (auto& pit : mit->opaqueMeshParts)\n        {\n            assert(count < _countof(barrier));\n            _Analysis_assume_(count < _countof(barrier));\n\n            if (stateBeforeIB != stateAfterIB && pit->staticIndexBuffer)\n            {\n                barrier[count].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n                barrier[count].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n                barrier[count].Transition.pResource = pit->staticIndexBuffer.Get();\n                barrier[count].Transition.StateBefore = stateBeforeIB;\n                barrier[count].Transition.StateAfter = stateAfterIB;\n                ++count;\n\n                if (count >= _countof(barrier))\n                {\n                    commandList->ResourceBarrier(count, barrier);\n                    count = 0;\n                }\n            }\n\n            if (stateBeforeVB != stateAfterVB && pit->staticVertexBuffer)\n            {\n                barrier[count].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n                barrier[count].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n                barrier[count].Transition.pResource = pit->staticVertexBuffer.Get();\n                barrier[count].Transition.StateBefore = stateBeforeVB;\n                barrier[count].Transition.StateAfter = stateAfterVB;\n                ++count;\n\n                if (count >= _countof(barrier))\n                {\n                    commandList->ResourceBarrier(count, barrier);\n                    count = 0;\n                }\n            }\n        }\n\n        for (auto& pit : mit->alphaMeshParts)\n        {\n            assert(count < _countof(barrier));\n            _Analysis_assume_(count < _countof(barrier));\n\n            if (stateBeforeIB != stateAfterIB && pit->staticIndexBuffer)\n            {\n                barrier[count].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n                barrier[count].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n                barrier[count].Transition.pResource = pit->staticIndexBuffer.Get();\n                barrier[count].Transition.StateBefore = stateBeforeIB;\n                barrier[count].Transition.StateAfter = stateAfterIB;\n                ++count;\n\n                if (count >= _countof(barrier))\n                {\n                    commandList->ResourceBarrier(count, barrier);\n                    count = 0;\n                }\n            }\n\n            if (stateBeforeVB != stateAfterVB && pit->staticVertexBuffer)\n            {\n                barrier[count].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n                barrier[count].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n                barrier[count].Transition.pResource = pit->staticVertexBuffer.Get();\n                barrier[count].Transition.StateBefore = stateBeforeVB;\n                barrier[count].Transition.StateAfter = stateAfterVB;\n                ++count;\n\n                if (count >= _countof(barrier))\n                {\n                    commandList->ResourceBarrier(count, barrier);\n                    count = 0;\n                }\n            }\n        }\n    }\n\n    if (count > 0)\n    {\n        commandList->ResourceBarrier(count, barrier);\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/ModelLoadSDKMESH.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: ModelLoadSDKMESH.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Model.h\"\n\n#include \"Effects.h\"\n#include \"VertexTypes.h\"\n\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"BinaryReader.h\"\n#include \"DescriptorHeap.h\"\n#include \"CommonStates.h\"\n\n#include \"SDKMesh.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    enum : unsigned int\n    {\n        PER_VERTEX_COLOR        = 0x1,\n        SKINNING                = 0x2,\n        DUAL_TEXTURE            = 0x4,\n        NORMAL_MAPS             = 0x8,\n        BIASED_VERTEX_NORMALS   = 0x10,\n        USES_OBSOLETE_DEC3N     = 0x20,\n    };\n\n    int GetUniqueTextureIndex(const wchar_t* textureName, std::map<std::wstring, int>& textureDictionary)\n    {\n        if (textureName == nullptr || !textureName[0])\n            return -1;\n\n        auto i = textureDictionary.find(textureName);\n        if (i == std::cend(textureDictionary))\n        {\n            int index = static_cast<int>(textureDictionary.size());\n            textureDictionary[textureName] = index;\n            return index;\n        }\n        else\n        {\n            return i->second;\n        }\n    }\n\n    inline XMFLOAT3 GetMaterialColor(float r, float g, float b, bool srgb) noexcept\n    {\n        if (srgb)\n        {\n            XMVECTOR v = XMVectorSet(r, g, b, 1.f);\n            v = XMColorSRGBToRGB(v);\n\n            XMFLOAT3 result;\n            XMStoreFloat3(&result, v);\n            return result;\n        }\n        else\n        {\n            return XMFLOAT3(r, g, b);\n        }\n    }\n\n    void InitMaterial(\n        const DXUT::SDKMESH_MATERIAL& mh,\n        unsigned int flags,\n        _Out_ Model::ModelMaterialInfo& m,\n        _Inout_ std::map<std::wstring, int32_t>& textureDictionary,\n        bool srgb)\n    {\n        wchar_t matName[DXUT::MAX_MATERIAL_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.Name, -1, matName, DXUT::MAX_MATERIAL_NAME);\n\n        wchar_t diffuseName[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.DiffuseTexture, -1, diffuseName, DXUT::MAX_TEXTURE_NAME);\n\n        wchar_t specularName[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.SpecularTexture, -1, specularName, DXUT::MAX_TEXTURE_NAME);\n\n        wchar_t normalName[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.NormalTexture, -1, normalName, DXUT::MAX_TEXTURE_NAME);\n\n        if ((flags & DUAL_TEXTURE) && !mh.SpecularTexture[0])\n        {\n            DebugTrace(\"WARNING: Material '%s' has multiple texture coords but not multiple textures\\n\", mh.Name);\n            flags &= ~static_cast<unsigned int>(DUAL_TEXTURE);\n        }\n\n        if (flags & NORMAL_MAPS)\n        {\n            if (!mh.NormalTexture[0])\n            {\n                flags &= ~static_cast<unsigned int>(NORMAL_MAPS);\n                *normalName = 0;\n            }\n        }\n        else if (mh.NormalTexture[0])\n        {\n            DebugTrace(\"WARNING: Material '%s' has a normal map, but vertex buffer is missing tangents\\n\", mh.Name);\n            *normalName = 0;\n        }\n\n        m = {};\n        m.name = matName;\n        m.perVertexColor = (flags & PER_VERTEX_COLOR) != 0;\n        m.enableSkinning = (flags & SKINNING) != 0;\n        m.enableDualTexture = (flags & DUAL_TEXTURE) != 0;\n        m.enableNormalMaps = (flags & NORMAL_MAPS) != 0;\n        m.biasedVertexNormals = (flags & BIASED_VERTEX_NORMALS) != 0;\n\n        if (mh.Ambient.x == 0 && mh.Ambient.y == 0 && mh.Ambient.z == 0 && mh.Ambient.w == 0\n            && mh.Diffuse.x == 0 && mh.Diffuse.y == 0 && mh.Diffuse.z == 0 && mh.Diffuse.w == 0)\n        {\n            // SDKMESH material color block is uninitalized; assume defaults\n            m.diffuseColor = XMFLOAT3(1.f, 1.f, 1.f);\n            m.alphaValue = 1.f;\n        }\n        else\n        {\n            m.ambientColor = GetMaterialColor(mh.Ambient.x, mh.Ambient.y, mh.Ambient.z, srgb);\n            m.diffuseColor = GetMaterialColor(mh.Diffuse.x, mh.Diffuse.y, mh.Diffuse.z, srgb);\n            m.emissiveColor = GetMaterialColor(mh.Emissive.x, mh.Emissive.y, mh.Emissive.z, srgb);\n\n            if (mh.Diffuse.w != 1.f && mh.Diffuse.w != 0.f)\n            {\n                m.alphaValue = mh.Diffuse.w;\n            }\n            else\n                m.alphaValue = 1.f;\n\n            if (mh.Power > 0)\n            {\n                m.specularPower = mh.Power;\n                m.specularColor = XMFLOAT3(mh.Specular.x, mh.Specular.y, mh.Specular.z);\n            }\n        }\n\n        m.diffuseTextureIndex = GetUniqueTextureIndex(diffuseName, textureDictionary);\n        m.specularTextureIndex = GetUniqueTextureIndex(specularName, textureDictionary);\n        m.normalTextureIndex = GetUniqueTextureIndex(normalName, textureDictionary);\n\n        m.samplerIndex = (m.diffuseTextureIndex == -1) ? -1 : static_cast<int>(CommonStates::SamplerIndex::AnisotropicWrap);\n        m.samplerIndex2 = (flags & DUAL_TEXTURE) ? static_cast<int>(CommonStates::SamplerIndex::AnisotropicWrap) : -1;\n    }\n\n    void InitMaterial(\n        const DXUT::SDKMESH_MATERIAL_V2& mh,\n        unsigned int flags,\n        _Out_ Model::ModelMaterialInfo& m,\n        _Inout_ std::map<std::wstring, int>& textureDictionary)\n    {\n        wchar_t matName[DXUT::MAX_MATERIAL_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.Name, -1, matName, DXUT::MAX_MATERIAL_NAME);\n\n        wchar_t albetoTexture[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.AlbetoTexture, -1, albetoTexture, DXUT::MAX_TEXTURE_NAME);\n\n        wchar_t normalName[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.NormalTexture, -1, normalName, DXUT::MAX_TEXTURE_NAME);\n\n        wchar_t rmaName[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.RMATexture, -1, rmaName, DXUT::MAX_TEXTURE_NAME);\n\n        wchar_t emissiveName[DXUT::MAX_TEXTURE_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.EmissiveTexture, -1, emissiveName, DXUT::MAX_TEXTURE_NAME);\n\n        m = {};\n        m.name = matName;\n        m.perVertexColor = false;\n        m.enableSkinning = false;\n        m.enableDualTexture = false;\n        m.enableNormalMaps = true;\n        m.biasedVertexNormals = (flags & BIASED_VERTEX_NORMALS) != 0;\n        m.alphaValue = (mh.Alpha == 0.f) ? 1.f : mh.Alpha;\n\n        m.diffuseTextureIndex = GetUniqueTextureIndex(albetoTexture, textureDictionary);\n        m.specularTextureIndex = GetUniqueTextureIndex(rmaName, textureDictionary);\n        m.normalTextureIndex = GetUniqueTextureIndex(normalName, textureDictionary);\n        m.emissiveTextureIndex = GetUniqueTextureIndex(emissiveName, textureDictionary);\n\n        m.samplerIndex = m.samplerIndex2 = static_cast<int>(CommonStates::SamplerIndex::AnisotropicWrap);\n    }\n\n\n    //--------------------------------------------------------------------------------------\n    // Direct3D 9 Vertex Declaration to Direct3D 12 Input Layout mapping\n\n    static_assert(D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT >= 32, \"SDKMESH supports decls up to 32 entries\");\n\n    unsigned int GetInputLayoutDesc(\n        _In_reads_(32) const DXUT::D3DVERTEXELEMENT9 decl[],\n        std::vector<D3D12_INPUT_ELEMENT_DESC>& inputDesc)\n    {\n        static const D3D12_INPUT_ELEMENT_DESC s_elements[] =\n        {\n           { \"SV_Position\",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"NORMAL\",       0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"COLOR\",        0, DXGI_FORMAT_B8G8R8A8_UNORM,  0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"TANGENT\",      0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"BINORMAL\",     0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"TEXCOORD\",     0, DXGI_FORMAT_R32G32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"BLENDINDICES\", 0, DXGI_FORMAT_R8G8B8A8_UINT,   0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n           { \"BLENDWEIGHT\",  0, DXGI_FORMAT_R8G8B8A8_UNORM,  0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n        };\n\n        using namespace DXUT;\n\n        uint32_t offset = 0;\n        uint32_t texcoords = 0;\n        unsigned int flags = 0;\n\n        bool posfound = false;\n\n        for (uint32_t index = 0; index < DXUT::MAX_VERTEX_ELEMENTS; ++index)\n        {\n            if (decl[index].Usage == 0xFF)\n                break;\n\n            if (decl[index].Type == D3DDECLTYPE_UNUSED)\n                break;\n\n            if (decl[index].Offset != offset)\n                break;\n\n            if (decl[index].Usage == D3DDECLUSAGE_POSITION)\n            {\n                if (decl[index].Type == D3DDECLTYPE_FLOAT3)\n                {\n                    inputDesc.push_back(s_elements[0]);\n                    offset += 12;\n                    posfound = true;\n                }\n                else\n                    break;\n            }\n            else if (decl[index].Usage == D3DDECLUSAGE_NORMAL\n                || decl[index].Usage == D3DDECLUSAGE_TANGENT\n                || decl[index].Usage == D3DDECLUSAGE_BINORMAL)\n            {\n                size_t base = 1;\n                if (decl[index].Usage == D3DDECLUSAGE_TANGENT)\n                    base = 3;\n                else if (decl[index].Usage == D3DDECLUSAGE_BINORMAL)\n                    base = 4;\n\n                D3D12_INPUT_ELEMENT_DESC desc = s_elements[base];\n\n                bool unk = false;\n                switch (decl[index].Type)\n                {\n                    case D3DDECLTYPE_FLOAT3:                 assert(desc.Format == DXGI_FORMAT_R32G32B32_FLOAT); offset += 12; break;\n                    case D3DDECLTYPE_UBYTE4N:                desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; flags |= BIASED_VERTEX_NORMALS; offset += 4; break;\n                    case D3DDECLTYPE_SHORT4N:                desc.Format = DXGI_FORMAT_R16G16B16A16_SNORM; offset += 8; break;\n                    case D3DDECLTYPE_FLOAT16_4:              desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; offset += 8; break;\n                    case D3DDECLTYPE_DXGI_R10G10B10A2_UNORM: desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; flags |= BIASED_VERTEX_NORMALS; offset += 4; break;\n                    case D3DDECLTYPE_DXGI_R11G11B10_FLOAT:   desc.Format = DXGI_FORMAT_R11G11B10_FLOAT; flags |= BIASED_VERTEX_NORMALS; offset += 4; break;\n                    case D3DDECLTYPE_DXGI_R8G8B8A8_SNORM:    desc.Format = DXGI_FORMAT_R8G8B8A8_SNORM; offset += 4; break;\n\n                    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n                    case D3DDECLTYPE_DEC3N:                  desc.Format = DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM; offset += 4; break;\n                    case (32 + DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM): desc.Format = DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM; offset += 4; break;\n                    #else\n                    case D3DDECLTYPE_DEC3N:                  desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; flags |= USES_OBSOLETE_DEC3N; offset += 4; break;\n                    #endif\n\n                    default:\n                        unk = true;\n                        break;\n                }\n\n                if (unk)\n                    break;\n\n                if (decl[index].Usage == D3DDECLUSAGE_TANGENT)\n                {\n                    flags |= NORMAL_MAPS;\n                }\n\n                inputDesc.push_back(desc);\n            }\n            else if (decl[index].Usage == D3DDECLUSAGE_COLOR)\n            {\n                D3D12_INPUT_ELEMENT_DESC desc = s_elements[2];\n\n                bool unk = false;\n                switch (decl[index].Type)\n                {\n                    case D3DDECLTYPE_FLOAT4:                 desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; offset += 16; break;\n                    case D3DDECLTYPE_D3DCOLOR:               assert(desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM); offset += 4; break;\n                    case D3DDECLTYPE_UBYTE4N:                desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; offset += 4; break;\n                    case D3DDECLTYPE_FLOAT16_4:              desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; offset += 8; break;\n                    case D3DDECLTYPE_DXGI_R10G10B10A2_UNORM: desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; offset += 4; break;\n                    case D3DDECLTYPE_DXGI_R11G11B10_FLOAT:   desc.Format = DXGI_FORMAT_R11G11B10_FLOAT; offset += 4; break;\n\n                    default:\n                        unk = true;\n                        break;\n                }\n\n                if (unk)\n                    break;\n\n                flags |= PER_VERTEX_COLOR;\n\n                inputDesc.push_back(desc);\n            }\n            else if (decl[index].Usage == D3DDECLUSAGE_TEXCOORD)\n            {\n                D3D12_INPUT_ELEMENT_DESC desc = s_elements[5];\n                desc.SemanticIndex = decl[index].UsageIndex;\n\n                bool unk = false;\n                switch (decl[index].Type)\n                {\n                    case D3DDECLTYPE_FLOAT1:    desc.Format = DXGI_FORMAT_R32_FLOAT; offset += 4; break;\n                    case D3DDECLTYPE_FLOAT2:    assert(desc.Format == DXGI_FORMAT_R32G32_FLOAT); offset += 8; break;\n                    case D3DDECLTYPE_FLOAT3:    desc.Format = DXGI_FORMAT_R32G32B32_FLOAT; offset += 12; break;\n                    case D3DDECLTYPE_FLOAT4:    desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; offset += 16; break;\n                    case D3DDECLTYPE_FLOAT16_2: desc.Format = DXGI_FORMAT_R16G16_FLOAT; offset += 4; break;\n                    case D3DDECLTYPE_FLOAT16_4: desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; offset += 8; break;\n\n                    default:\n                        unk = true;\n                        break;\n                }\n\n                if (unk)\n                    break;\n\n                ++texcoords;\n\n                inputDesc.push_back(desc);\n            }\n            else if (decl[index].Usage == D3DDECLUSAGE_BLENDINDICES)\n            {\n                if (decl[index].Type == D3DDECLTYPE_UBYTE4)\n                {\n                    flags |= SKINNING;\n                    inputDesc.push_back(s_elements[6]);\n                    offset += 4;\n                }\n                else\n                    break;\n            }\n            else if (decl[index].Usage == D3DDECLUSAGE_BLENDWEIGHT)\n            {\n                if (decl[index].Type == D3DDECLTYPE_UBYTE4N)\n                {\n                    flags |= SKINNING;\n                    inputDesc.push_back(s_elements[7]);\n                    offset += 4;\n                }\n                else\n                    break;\n            }\n            else\n                break;\n        }\n\n        if (!posfound)\n            throw std::exception(\"SV_Position is required\");\n\n        if (texcoords == 2)\n        {\n            flags |= DUAL_TEXTURE;\n        }\n\n        return flags;\n    }\n}\n\n//======================================================================================\n// Model Loader\n//======================================================================================\n\n_Use_decl_annotations_\nstd::unique_ptr<Model> DirectX::Model::CreateFromSDKMESH(\n    ID3D12Device* device,\n    const uint8_t* meshData,\n    size_t idataSize,\n    ModelLoaderFlags flags)\n{\n    if (!meshData)\n        throw std::exception(\"meshData cannot be null\");\n\n    uint64_t dataSize = idataSize;\n\n    // File Headers\n    if (dataSize < sizeof(DXUT::SDKMESH_HEADER))\n        throw std::exception(\"End of file\");\n    auto header = reinterpret_cast<const DXUT::SDKMESH_HEADER*>(meshData);\n\n    size_t headerSize = sizeof(DXUT::SDKMESH_HEADER)\n        + header->NumVertexBuffers * sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER)\n        + header->NumIndexBuffers * sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER);\n    if (header->HeaderSize != headerSize)\n        throw std::exception(\"Not a valid SDKMESH file\");\n\n    if (dataSize < header->HeaderSize)\n        throw std::exception(\"End of file\");\n\n    if (header->Version != DXUT::SDKMESH_FILE_VERSION && header->Version != DXUT::SDKMESH_FILE_VERSION_V2)\n        throw std::exception(\"Not a supported SDKMESH version\");\n\n    if (header->IsBigEndian)\n        throw std::exception(\"Loading BigEndian SDKMESH files not supported\");\n\n    if (!header->NumMeshes)\n        throw std::exception(\"No meshes found\");\n\n    if (!header->NumVertexBuffers)\n        throw std::exception(\"No vertex buffers found\");\n\n    if (!header->NumIndexBuffers)\n        throw std::exception(\"No index buffers found\");\n\n    if (!header->NumTotalSubsets)\n        throw std::exception(\"No subsets found\");\n\n    if (!header->NumMaterials)\n        throw std::exception(\"No materials found\");\n\n    // Sub-headers\n    if (dataSize < header->VertexStreamHeadersOffset\n        || (dataSize < (header->VertexStreamHeadersOffset + uint64_t(header->NumVertexBuffers) * sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER))))\n        throw std::exception(\"End of file\");\n    auto vbArray = reinterpret_cast<const DXUT::SDKMESH_VERTEX_BUFFER_HEADER*>(meshData + header->VertexStreamHeadersOffset);\n\n    if (dataSize < header->IndexStreamHeadersOffset\n        || (dataSize < (header->IndexStreamHeadersOffset + uint64_t(header->NumIndexBuffers) * sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER))))\n        throw std::exception(\"End of file\");\n    auto ibArray = reinterpret_cast<const DXUT::SDKMESH_INDEX_BUFFER_HEADER*>(meshData + header->IndexStreamHeadersOffset);\n\n    if (dataSize < header->MeshDataOffset\n        || (dataSize < (header->MeshDataOffset + uint64_t(header->NumMeshes) * sizeof(DXUT::SDKMESH_MESH))))\n        throw std::exception(\"End of file\");\n    auto meshArray = reinterpret_cast<const DXUT::SDKMESH_MESH*>(meshData + header->MeshDataOffset);\n\n    if (dataSize < header->SubsetDataOffset\n        || (dataSize < (header->SubsetDataOffset + uint64_t(header->NumTotalSubsets) * sizeof(DXUT::SDKMESH_SUBSET))))\n        throw std::exception(\"End of file\");\n    auto subsetArray = reinterpret_cast<const DXUT::SDKMESH_SUBSET*>(meshData + header->SubsetDataOffset);\n\n    if (dataSize < header->FrameDataOffset\n        || (dataSize < (header->FrameDataOffset + uint64_t(header->NumFrames) * sizeof(DXUT::SDKMESH_FRAME))))\n        throw std::exception(\"End of file\");\n    // TODO - auto frameArray = reinterpret_cast<const DXUT::SDKMESH_FRAME*>( meshData + header->FrameDataOffset );\n\n    if (dataSize < header->MaterialDataOffset\n        || (dataSize < (header->MaterialDataOffset + uint64_t(header->NumMaterials) * sizeof(DXUT::SDKMESH_MATERIAL))))\n        throw std::exception(\"End of file\");\n\n    const DXUT::SDKMESH_MATERIAL* materialArray = nullptr;\n    const DXUT::SDKMESH_MATERIAL_V2* materialArray_v2 = nullptr;\n    if (header->Version == DXUT::SDKMESH_FILE_VERSION_V2)\n    {\n        materialArray_v2 = reinterpret_cast<const DXUT::SDKMESH_MATERIAL_V2*>(meshData + header->MaterialDataOffset);\n    }\n    else\n    {\n        materialArray = reinterpret_cast<const DXUT::SDKMESH_MATERIAL*>(meshData + header->MaterialDataOffset);\n    }\n\n    // Buffer data\n    uint64_t bufferDataOffset = header->HeaderSize + header->NonBufferDataSize;\n    if ((dataSize < bufferDataOffset)\n        || (dataSize < bufferDataOffset + header->BufferDataSize))\n        throw std::exception(\"End of file\");\n    const uint8_t* bufferData = meshData + bufferDataOffset;\n\n    // Create vertex buffers\n    std::vector<std::shared_ptr<std::vector<D3D12_INPUT_ELEMENT_DESC>>> vbDecls;\n    vbDecls.resize(header->NumVertexBuffers);\n\n    std::vector<unsigned int> materialFlags;\n    materialFlags.resize(header->NumVertexBuffers);\n\n    bool dec3nwarning = false;\n    for (UINT j = 0; j < header->NumVertexBuffers; ++j)\n    {\n        auto& vh = vbArray[j];\n\n        if (vh.SizeBytes > UINT32_MAX)\n            throw std::exception(\"VB too large\");\n\n        if (!(flags & ModelLoader_AllowLargeModels))\n        {\n            if (vh.SizeBytes > (D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n                throw std::exception(\"VB too large for DirectX 12\");\n        }\n\n        if (dataSize < vh.DataOffset\n            || (dataSize < vh.DataOffset + vh.SizeBytes))\n            throw std::exception(\"End of file\");\n\n        vbDecls[j] = std::make_shared<std::vector<D3D12_INPUT_ELEMENT_DESC>>();\n        unsigned int ilflags = GetInputLayoutDesc(vh.Decl, *vbDecls[j].get());\n\n        if (ilflags & SKINNING)\n        {\n            ilflags &= ~static_cast<unsigned int>(DUAL_TEXTURE | NORMAL_MAPS);\n        }\n        if (ilflags & DUAL_TEXTURE)\n        {\n            ilflags &= ~static_cast<unsigned int>(NORMAL_MAPS);\n        }\n\n        if (ilflags & USES_OBSOLETE_DEC3N)\n        {\n            dec3nwarning = true;\n        }\n\n        materialFlags[j] = ilflags;\n    }\n\n    if (dec3nwarning)\n    {\n        DebugTrace(\"WARNING: Vertex declaration uses legacy Direct3D 9 D3DDECLTYPE_DEC3N which has no DXGI equivalent\\n\"\n                   \"         (treating as DXGI_FORMAT_R10G10B10A2_UNORM which is not a signed format)\\n\");\n    }\n\n    // Validate index buffers\n    for (UINT j = 0; j < header->NumIndexBuffers; ++j)\n    {\n        auto& ih = ibArray[j];\n\n        if (ih.SizeBytes > UINT32_MAX)\n            throw std::exception(\"IB too large\");\n\n        if (!(flags & ModelLoader_AllowLargeModels))\n        {\n            if (ih.SizeBytes > (D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n                throw std::exception(\"IB too large for DirectX 12\");\n        }\n\n        if (dataSize < ih.DataOffset\n            || (dataSize < ih.DataOffset + ih.SizeBytes))\n            throw std::exception(\"End of file\");\n\n        if (ih.IndexType != DXUT::IT_16BIT && ih.IndexType != DXUT::IT_32BIT)\n            throw std::exception(\"Invalid index buffer type found\");\n    }\n\n    // Create meshes\n    std::vector<ModelMaterialInfo> materials;\n    materials.resize(header->NumMaterials);\n\n    std::map<std::wstring, int> textureDictionary;\n\n    auto model = std::make_unique<Model>();\n    model->meshes.reserve(header->NumMeshes);\n\n    uint32_t partCount = 0;\n\n    for (UINT meshIndex = 0; meshIndex < header->NumMeshes; ++meshIndex)\n    {\n        auto& mh = meshArray[meshIndex];\n\n        if (!mh.NumSubsets\n            || !mh.NumVertexBuffers\n            || mh.IndexBuffer >= header->NumIndexBuffers\n            || mh.VertexBuffers[0] >= header->NumVertexBuffers)\n            throw std::exception(\"Invalid mesh found\");\n\n        // mh.NumVertexBuffers is sometimes not what you'd expect, so we skip validating it\n\n        if (dataSize < mh.SubsetOffset\n            || (dataSize < mh.SubsetOffset + uint64_t(mh.NumSubsets) * sizeof(UINT)))\n            throw std::exception(\"End of file\");\n\n        auto subsets = reinterpret_cast<const UINT*>(meshData + mh.SubsetOffset);\n\n        if (mh.NumFrameInfluences > 0)\n        {\n            if (dataSize < mh.FrameInfluenceOffset\n                || (dataSize < mh.FrameInfluenceOffset + uint64_t(mh.NumFrameInfluences) * sizeof(UINT)))\n                throw std::exception(\"End of file\");\n\n            // TODO - auto influences = reinterpret_cast<const UINT*>( meshData + mh.FrameInfluenceOffset );\n        }\n\n        auto mesh = std::make_shared<ModelMesh>();\n        wchar_t meshName[DXUT::MAX_MESH_NAME] = {};\n        MultiByteToWideChar(CP_UTF8, 0, mh.Name, -1, meshName, DXUT::MAX_MESH_NAME);\n        mesh->name = meshName;\n\n        // Extents\n        mesh->boundingBox.Center = mh.BoundingBoxCenter;\n        mesh->boundingBox.Extents = mh.BoundingBoxExtents;\n        BoundingSphere::CreateFromBoundingBox(mesh->boundingSphere, mesh->boundingBox);\n\n        // Create subsets\n        for (UINT j = 0; j < mh.NumSubsets; ++j)\n        {\n            auto sIndex = subsets[j];\n            if (sIndex >= header->NumTotalSubsets)\n                throw std::exception(\"Invalid mesh found\");\n\n            auto& subset = subsetArray[sIndex];\n\n            D3D_PRIMITIVE_TOPOLOGY primType;\n            switch (subset.PrimitiveType)\n            {\n                case DXUT::PT_TRIANGLE_LIST:        primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;       break;\n                case DXUT::PT_TRIANGLE_STRIP:       primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;      break;\n                case DXUT::PT_LINE_LIST:            primType = D3D_PRIMITIVE_TOPOLOGY_LINELIST;           break;\n                case DXUT::PT_LINE_STRIP:           primType = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;          break;\n                case DXUT::PT_POINT_LIST:           primType = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;          break;\n                case DXUT::PT_TRIANGLE_LIST_ADJ:    primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ;   break;\n                case DXUT::PT_TRIANGLE_STRIP_ADJ:   primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ;  break;\n                case DXUT::PT_LINE_LIST_ADJ:        primType = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;       break;\n                case DXUT::PT_LINE_STRIP_ADJ:       primType = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ;      break;\n\n                case DXUT::PT_QUAD_PATCH_LIST:\n                case DXUT::PT_TRIANGLE_PATCH_LIST:\n                    throw std::exception(\"Direct3D9 era tessellation not supported\");\n\n                default:\n                    throw std::exception(\"Unknown primitive type\");\n            }\n\n            if (subset.MaterialID >= header->NumMaterials)\n                throw std::exception(\"Invalid mesh found\");\n\n            auto& mat = materials[subset.MaterialID];\n\n            const size_t vi = mh.VertexBuffers[0];\n            if (materialArray_v2)\n            {\n                InitMaterial(\n                    materialArray_v2[subset.MaterialID],\n                    materialFlags[vi],\n                    mat,\n                    textureDictionary);\n            }\n            else\n            {\n                InitMaterial(\n                    materialArray[subset.MaterialID],\n                    materialFlags[vi],\n                    mat,\n                    textureDictionary,\n                    (flags & ModelLoader_MaterialColorsSRGB) != 0);\n            }\n\n            auto part = new ModelMeshPart(partCount++);\n\n            const auto& vh = vbArray[mh.VertexBuffers[0]];\n            const auto& ih = ibArray[mh.IndexBuffer];\n\n            part->indexCount = static_cast<uint32_t>(subset.IndexCount);\n            part->startIndex = static_cast<uint32_t>(subset.IndexStart);\n            part->vertexOffset = static_cast<int32_t>(subset.VertexStart);\n            part->vertexStride = static_cast<uint32_t>(vh.StrideBytes);\n            part->vertexCount = static_cast<uint32_t>(subset.VertexCount);\n            part->primitiveType = primType;\n            part->indexFormat = (ibArray[mh.IndexBuffer].IndexType == DXUT::IT_32BIT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;\n\n            // Vertex data\n            auto verts = bufferData + (vh.DataOffset - bufferDataOffset);\n            auto vbytes = static_cast<size_t>(vh.SizeBytes);\n            part->vertexBufferSize = static_cast<uint32_t>(vh.SizeBytes);\n            part->vertexBuffer = GraphicsMemory::Get(device).Allocate(vbytes);\n            memcpy(part->vertexBuffer.Memory(), verts, vbytes);\n\n            // Index data\n            auto indices = bufferData + (ih.DataOffset - bufferDataOffset);\n            auto ibytes = static_cast<size_t>(ih.SizeBytes);\n            part->indexBufferSize = static_cast<uint32_t>(ih.SizeBytes);\n            part->indexBuffer = GraphicsMemory::Get(device).Allocate(ibytes);\n            memcpy(part->indexBuffer.Memory(), indices, ibytes);\n\n            part->materialIndex = subset.MaterialID;\n            part->vbDecl = vbDecls[mh.VertexBuffers[0]];\n\n            if (mat.alphaValue < 1.0f)\n                mesh->alphaMeshParts.emplace_back(part);\n            else\n                mesh->opaqueMeshParts.emplace_back(part);\n        }\n\n        model->meshes.emplace_back(mesh);\n    }\n\n    // Copy the materials and texture names into contiguous arrays\n    model->materials = std::move(materials);\n    model->textureNames.resize(textureDictionary.size());\n    for (auto texture = std::cbegin(textureDictionary); texture != std::cend(textureDictionary); ++texture)\n    {\n        model->textureNames[static_cast<size_t>(texture->second)] = texture->first;\n    }\n\n    return model;\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nstd::unique_ptr<Model> DirectX::Model::CreateFromSDKMESH(\n    ID3D12Device* device,\n    const wchar_t* szFileName,\n    ModelLoaderFlags flags)\n{\n    size_t dataSize = 0;\n    std::unique_ptr<uint8_t[]> data;\n    HRESULT hr = BinaryReader::ReadEntireFile(szFileName, data, &dataSize);\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: CreateFromSDKMESH failed (%08X) loading '%ls'\\n\",\n            static_cast<unsigned int>(hr), szFileName);\n        throw std::exception(\"CreateFromSDKMESH\");\n    }\n\n    auto model = CreateFromSDKMESH(device, data.get(), dataSize, flags);\n\n    model->name = szFileName;\n\n    return model;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/ModelLoadVBO.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: ModelLoadVBO.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Model.h\"\n\n#include \"Effects.h\"\n#include \"VertexTypes.h\"\n\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"BinaryReader.h\"\n\n#include \"vbo.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nstatic_assert(sizeof(VertexPositionNormalTexture) == 32, \"VBO vertex size mismatch\");\n\nnamespace\n{\n    //--------------------------------------------------------------------------------------\n    // Shared VB input element description\n    INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT;\n    std::shared_ptr<std::vector<D3D12_INPUT_ELEMENT_DESC>> g_vbdecl;\n\n    BOOL CALLBACK InitializeDecl(PINIT_ONCE initOnce, PVOID Parameter, PVOID *lpContext)\n    {\n        UNREFERENCED_PARAMETER(initOnce);\n        UNREFERENCED_PARAMETER(Parameter);\n        UNREFERENCED_PARAMETER(lpContext);\n\n        g_vbdecl = std::make_shared<std::vector<D3D12_INPUT_ELEMENT_DESC>>(VertexPositionNormalTexture::InputLayout.pInputElementDescs,\n            VertexPositionNormalTexture::InputLayout.pInputElementDescs + VertexPositionNormalTexture::InputLayout.NumElements);\n\n        return TRUE;\n    }\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nstd::unique_ptr<Model> DirectX::Model::CreateFromVBO(\n    ID3D12Device* device,\n    const uint8_t* meshData, size_t dataSize,\n    ModelLoaderFlags flags)\n{\n    if (!InitOnceExecuteOnce(&g_InitOnce, InitializeDecl, nullptr, nullptr))\n        throw std::exception(\"One-time initialization failed\");\n\n    if (!meshData)\n        throw std::exception(\"meshData cannot be null\");\n\n    // File Header\n    if (dataSize < sizeof(VBO::header_t))\n        throw std::exception(\"End of file\");\n    auto header = reinterpret_cast<const VBO::header_t*>(meshData);\n\n    if (!header->numVertices || !header->numIndices)\n        throw std::exception(\"No vertices or indices found\");\n\n    uint64_t sizeInBytes = uint64_t(header->numVertices) * sizeof(VertexPositionNormalTexture);\n    if (sizeInBytes > UINT32_MAX)\n        throw std::exception(\"VB too large\");\n\n    if (!(flags & ModelLoader_AllowLargeModels))\n    {\n        if (sizeInBytes > uint64_t(D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n            throw std::exception(\"VB too large for DirectX 12\");\n    }\n\n    auto vertSize = static_cast<size_t>(sizeInBytes);\n\n    if (dataSize < (vertSize + sizeof(VBO::header_t)))\n        throw std::exception(\"End of file\");\n    auto verts = reinterpret_cast<const VertexPositionNormalTexture*>(meshData + sizeof(VBO::header_t));\n\n    sizeInBytes = uint64_t(header->numIndices) * sizeof(uint16_t);\n    if (sizeInBytes > UINT32_MAX)\n        throw std::exception(\"IB too large\");\n\n    if (!(flags & ModelLoader_AllowLargeModels))\n    {\n        if (sizeInBytes > uint64_t(D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n            throw std::exception(\"IB too large for DirectX 12\");\n    }\n\n    auto indexSize = static_cast<size_t>(sizeInBytes);\n\n    if (dataSize < (sizeof(VBO::header_t) + vertSize + indexSize))\n        throw std::exception(\"End of file\");\n    auto indices = reinterpret_cast<const uint16_t*>(meshData + sizeof(VBO::header_t) + vertSize);\n\n    // Create vertex buffer\n    auto vb = GraphicsMemory::Get(device).Allocate(vertSize);\n    memcpy(vb.Memory(), verts, vertSize);\n\n    // Create index buffer\n    auto ib = GraphicsMemory::Get(device).Allocate(indexSize);\n    memcpy(ib.Memory(), indices, indexSize);\n\n    auto part = new ModelMeshPart(0);\n    part->materialIndex = 0;\n    part->indexCount = header->numIndices;\n    part->startIndex = 0;\n    part->vertexStride = static_cast<uint32_t>(sizeof(VertexPositionNormalTexture));\n    part->vertexCount = header->numVertices;\n    part->indexBufferSize = static_cast<uint32_t>(indexSize);\n    part->vertexBufferSize = static_cast<uint32_t>(vertSize);\n    part->indexBuffer = std::move(ib);\n    part->vertexBuffer = std::move(vb);\n    part->vbDecl = g_vbdecl;\n\n    auto mesh = std::make_shared<ModelMesh>();\n    BoundingSphere::CreateFromPoints(mesh->boundingSphere, header->numVertices, &verts->position, sizeof(VertexPositionNormalTexture));\n    BoundingBox::CreateFromPoints(mesh->boundingBox, header->numVertices, &verts->position, sizeof(VertexPositionNormalTexture));\n    mesh->opaqueMeshParts.emplace_back(part);\n\n    auto model = std::make_unique<Model>();\n    model->meshes.emplace_back(mesh);\n\n    return model;\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nstd::unique_ptr<Model> DirectX::Model::CreateFromVBO(\n    ID3D12Device* device,\n    const wchar_t* szFileName,\n    ModelLoaderFlags flags)\n{\n    size_t dataSize = 0;\n    std::unique_ptr<uint8_t[]> data;\n    HRESULT hr = BinaryReader::ReadEntireFile(szFileName, data, &dataSize);\n    if (FAILED(hr))\n    {\n        DebugTrace(\"ERROR: CreateFromVBO failed (%08X) loading '%ls'\\n\",\n            static_cast<unsigned int>(hr), szFileName);\n        throw std::exception(\"CreateFromVBO\");\n    }\n\n    auto model = CreateFromVBO(device, data.get(), dataSize, flags);\n\n    model->name = szFileName;\n\n    return model;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Mouse.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: Mouse.cpp\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Mouse.h\"\n\n#include \"PlatformHelpers.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n#pragma region Implementations\n#if (defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) || (defined(_GAMING_DESKTOP) && (_GRDK_EDITION >= 220600))\n\n#include <GameInput.h>\n\n//======================================================================================\n// Win32 + GameInput implementation\n//======================================================================================\n\n//\n// Call this static function from your Window Message Procedure\n//\n// LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n// {\n//     switch (message)\n//     {\n//     case WM_ACTIVATE:\n//     case WM_ACTIVATEAPP:\n//     case WM_MOUSEMOVE:\n//     case WM_LBUTTONDOWN:\n//     case WM_LBUTTONUP:\n//     case WM_RBUTTONDOWN:\n//     case WM_RBUTTONUP:\n//     case WM_MBUTTONDOWN:\n//     case WM_MBUTTONUP:\n//     case WM_MOUSEWHEEL:\n//     case WM_XBUTTONDOWN:\n//     case WM_XBUTTONUP:\n//         Mouse::ProcessMessage(message, wParam, lParam);\n//         break;\n//\n//     }\n// }\n//\n\nclass Mouse::Impl\n{\npublic:\n    explicit Impl(Mouse* owner) noexcept(false) :\n        mState{},\n        mOwner(owner),\n        mScale(1.f),\n        mConnected(0),\n        mDeviceToken(0),\n        mWindow(nullptr),\n        mMode(MODE_ABSOLUTE),\n        mScrollWheelCurrent(0),\n        mRelativeX(INT64_MAX),\n        mRelativeY(INT64_MAX),\n        mRelativeWheelY(INT64_MAX)\n    {\n        if (s_mouse)\n        {\n            throw std::logic_error(\"Mouse is a singleton\");\n        }\n\n        s_mouse = this;\n\n        ThrowIfFailed(GameInputCreate(mGameInput.GetAddressOf()));\n\n        ThrowIfFailed(mGameInput->RegisterDeviceCallback(\n            nullptr,\n            GameInputKindMouse,\n            GameInputDeviceConnected,\n            GameInputBlockingEnumeration,\n            this,\n            OnGameInputDevice,\n            &mDeviceToken));\n\n        mScrollWheelValue.reset(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mScrollWheelValue)\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"CreateEventEx\");\n        }\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n        if (mDeviceToken)\n        {\n            if (mGameInput)\n            {\n                if (!mGameInput->UnregisterCallback(mDeviceToken, UINT64_MAX))\n                {\n                    DebugTrace(\"ERROR: GameInput::UnregisterCallback [mouse] failed\");\n                }\n            }\n\n            mDeviceToken = 0;\n        }\n\n        s_mouse = nullptr;\n    }\n\n    void GetState(State& state) const\n    {\n        memcpy(&state, &mState, sizeof(State));\n        state.positionMode = mMode;\n\n        DWORD result = WaitForSingleObjectEx(mScrollWheelValue.get(), 0, FALSE);\n        if (result == WAIT_FAILED)\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForSingleObjectEx\");\n\n        if (result == WAIT_OBJECT_0)\n        {\n            mScrollWheelCurrent = 0;\n        }\n\n        if (state.positionMode == MODE_RELATIVE)\n        {\n            state.x = state.y = 0;\n\n            ComPtr<IGameInputReading> reading;\n            if (SUCCEEDED(mGameInput->GetCurrentReading(GameInputKindMouse, nullptr, reading.GetAddressOf())))\n            {\n                GameInputMouseState mouse;\n                if (reading->GetMouseState(&mouse))\n                {\n                    state.leftButton = (mouse.buttons & GameInputMouseLeftButton) != 0;\n                    state.middleButton = (mouse.buttons & GameInputMouseMiddleButton) != 0;\n                    state.rightButton = (mouse.buttons & GameInputMouseRightButton) != 0;\n                    state.xButton1 = (mouse.buttons & GameInputMouseButton4) != 0;\n                    state.xButton2 = (mouse.buttons & GameInputMouseButton5) != 0;\n\n                    if (mRelativeX != INT64_MAX)\n                    {\n                        state.x = static_cast<int>(mouse.positionX - mRelativeX);\n                        state.y = static_cast<int>(mouse.positionY - mRelativeY);\n                        int scrollDelta = static_cast<int>(mouse.wheelY - mRelativeWheelY);\n                        mScrollWheelCurrent += scrollDelta;\n                    }\n\n                    mRelativeX = mouse.positionX;\n                    mRelativeY = mouse.positionY;\n                    mRelativeWheelY = mouse.wheelY;\n                }\n            }\n        }\n\n        state.scrollWheelValue = mScrollWheelCurrent;\n    }\n\n    void ResetScrollWheelValue() noexcept\n    {\n        SetEvent(mScrollWheelValue.get());\n    }\n\n    void SetWindow(HWND window)\n    {\n        mWindow = window;\n    }\n\n    void SetMode(Mode mode)\n    {\n        if (mMode == mode)\n            return;\n\n        mMode = mode;\n        mRelativeX = INT64_MAX;\n        mRelativeY = INT64_MAX;\n        mRelativeWheelY = INT64_MAX;\n\n        if (mode == MODE_RELATIVE)\n        {\n            ShowCursor(FALSE);\n            ClipToWindow();\n        }\n        else\n        {\n            ShowCursor(TRUE);\n#ifndef _GAMING_XBOX\n            ClipCursor(nullptr);\n#endif\n        }\n    }\n\n    bool IsConnected() const noexcept\n    {\n        return mConnected > 0;\n    }\n\n    bool IsVisible() const noexcept\n    {\n        if (mMode == MODE_RELATIVE)\n            return false;\n\n        CURSORINFO info = { sizeof(CURSORINFO), 0, nullptr, {} };\n        if (!GetCursorInfo(&info))\n            return false;\n\n        return (info.flags & CURSOR_SHOWING) != 0;\n    }\n\n    void SetVisible(bool visible)\n    {\n        if (mMode == MODE_RELATIVE)\n            return;\n\n        CURSORINFO info = { sizeof(CURSORINFO), 0, nullptr, {} };\n        if (!GetCursorInfo(&info))\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"GetCursorInfo\");\n        }\n\n        bool isvisible = (info.flags & CURSOR_SHOWING) != 0;\n        if (isvisible != visible)\n        {\n            ShowCursor(visible);\n        }\n    }\n\n    State           mState;\n    Mouse*          mOwner;\n    float           mScale;\n    uint32_t        mConnected;\n\n    static Mouse::Impl* s_mouse;\n\nprivate:\n    ComPtr<IGameInput>      mGameInput;\n    GameInputCallbackToken  mDeviceToken;\n\n    HWND                    mWindow;\n    Mode                    mMode;\n    ScopedHandle            mScrollWheelValue;\n\n    mutable int             mScrollWheelCurrent;\n    mutable int64_t         mRelativeX;\n    mutable int64_t         mRelativeY;\n    mutable int64_t         mRelativeWheelY;\n\n    friend void Mouse::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);\n\n    static void CALLBACK OnGameInputDevice(\n        _In_ GameInputCallbackToken,\n        _In_ void * context,\n        _In_ IGameInputDevice *,\n        _In_ uint64_t,\n        _In_ GameInputDeviceStatus currentStatus,\n        _In_ GameInputDeviceStatus) noexcept\n    {\n        auto impl = reinterpret_cast<Mouse::Impl*>(context);\n\n        if (currentStatus & GameInputDeviceConnected)\n        {\n            ++impl->mConnected;\n        }\n        else if (impl->mConnected > 0)\n        {\n            --impl->mConnected;\n        }\n    }\n\n    void ClipToWindow() noexcept\n    {\n#ifndef _GAMING_XBOX\n        assert(mWindow != nullptr);\n\n        RECT rect;\n        GetClientRect(mWindow, &rect);\n\n        POINT ul;\n        ul.x = rect.left;\n        ul.y = rect.top;\n\n        POINT lr;\n        lr.x = rect.right;\n        lr.y = rect.bottom;\n\n        std::ignore = MapWindowPoints(mWindow, nullptr, &ul, 1);\n        std::ignore = MapWindowPoints(mWindow, nullptr, &lr, 1);\n\n        rect.left = ul.x;\n        rect.top = ul.y;\n\n        rect.right = lr.x;\n        rect.bottom = lr.y;\n\n        ClipCursor(&rect);\n#endif\n    }\n};\n\n\nMouse::Impl* Mouse::Impl::s_mouse = nullptr;\n\n\nvoid Mouse::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam)\n{\n    auto pImpl = Impl::s_mouse;\n\n    if (!pImpl)\n        return;\n\n    DWORD result = WaitForSingleObjectEx(pImpl->mScrollWheelValue.get(), 0, FALSE);\n    if (result == WAIT_FAILED)\n        throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForSingleObjectEx\");\n\n    if (result == WAIT_OBJECT_0)\n    {\n        pImpl->mScrollWheelCurrent = 0;\n    }\n\n    switch (message)\n    {\n    case WM_ACTIVATE:\n    case WM_ACTIVATEAPP:\n        if (wParam)\n        {\n            if (pImpl->mMode == MODE_RELATIVE)\n            {\n                pImpl->mRelativeX = INT64_MAX;\n                pImpl->mRelativeY = INT64_MAX;\n\n                ShowCursor(FALSE);\n\n                pImpl->ClipToWindow();\n            }\n            else\n            {\n#ifndef _GAMING_XBOX\n                ClipCursor(nullptr);\n#endif\n            }\n        }\n        else\n        {\n            memset(&pImpl->mState, 0, sizeof(State));\n        }\n        return;\n\n    case WM_MOUSEMOVE:\n        break;\n\n    case WM_LBUTTONDOWN:\n        pImpl->mState.leftButton = true;\n        break;\n\n    case WM_LBUTTONUP:\n        pImpl->mState.leftButton = false;\n        break;\n\n    case WM_RBUTTONDOWN:\n        pImpl->mState.rightButton = true;\n        break;\n\n    case WM_RBUTTONUP:\n        pImpl->mState.rightButton = false;\n        break;\n\n    case WM_MBUTTONDOWN:\n        pImpl->mState.middleButton = true;\n        break;\n\n    case WM_MBUTTONUP:\n        pImpl->mState.middleButton = false;\n        break;\n\n    case WM_MOUSEWHEEL:\n        if (pImpl->mMode == MODE_ABSOLUTE)\n        {\n            pImpl->mScrollWheelCurrent += GET_WHEEL_DELTA_WPARAM(wParam);\n        }\n        return;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wParam))\n        {\n        case XBUTTON1:\n            pImpl->mState.xButton1 = true;\n            break;\n\n        case XBUTTON2:\n            pImpl->mState.xButton2 = true;\n            break;\n        }\n        break;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wParam))\n        {\n        case XBUTTON1:\n            pImpl->mState.xButton1 = false;\n            break;\n\n        case XBUTTON2:\n            pImpl->mState.xButton2 = false;\n            break;\n        }\n        break;\n\n    default:\n        // Not a mouse message, so exit\n        return;\n    }\n\n    if (pImpl->mMode == MODE_ABSOLUTE)\n    {\n        // All mouse messages provide a new pointer position\n        int xPos = static_cast<short>(LOWORD(lParam)); // GET_X_LPARAM(lParam);\n        int yPos = static_cast<short>(HIWORD(lParam)); // GET_Y_LPARAM(lParam);\n\n        pImpl->mState.x = static_cast<int>(static_cast<float>(xPos) * pImpl->mScale);\n        pImpl->mState.y = static_cast<int>(static_cast<float>(yPos) * pImpl->mScale);\n    }\n}\n\n#ifdef _GAMING_XBOX\nvoid Mouse::SetResolution(float scale)\n{\n    auto pImpl = Impl::s_mouse;\n\n    if (!pImpl)\n        return;\n\n    pImpl->mScale = scale;\n}\n#endif\n\nvoid Mouse::SetWindow(HWND window)\n{\n    pImpl->SetWindow(window);\n}\n\n\n#elif defined(USING_COREWINDOW)\n\n//======================================================================================\n// Windows Store or Universal Windows Platform (UWP) app implementation\n//======================================================================================\n\n//\n// For a Windows Store app or Universal Windows Platform (UWP) app, add the following to your existing\n// application methods:\n//\n// void App::SetWindow(CoreWindow^ window )\n// {\n//     m_mouse->SetWindow(window);\n// }\n//\n// void App::OnDpiChanged(DisplayInformation^ sender, Object^ args)\n// {\n//     m_mouse->SetDpi(sender->LogicalDpi);\n// }\n//\n\n#include <Windows.Devices.Input.h>\n\nclass Mouse::Impl\n{\npublic:\n    explicit Impl(Mouse* owner) noexcept(false) :\n        mState{},\n        mOwner(owner),\n        mDPI(96.f),\n        mMode(MODE_ABSOLUTE),\n        mPointerPressedToken{},\n        mPointerReleasedToken{},\n        mPointerMovedToken{},\n        mPointerWheelToken{},\n        mPointerMouseMovedToken{}\n    {\n        if (s_mouse)\n        {\n            throw std::logic_error(\"Mouse is a singleton\");\n        }\n\n        s_mouse = this;\n\n        mScrollWheelValue.reset(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        mRelativeRead.reset(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mScrollWheelValue\n            || !mRelativeRead)\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"CreateEventEx\");\n        }\n    }\n\n    ~Impl()\n    {\n        s_mouse = nullptr;\n\n        RemoveHandlers();\n    }\n\n    void GetState(State& state) const\n    {\n        memcpy(&state, &mState, sizeof(State));\n\n        DWORD result = WaitForSingleObjectEx(mScrollWheelValue.get(), 0, FALSE);\n        if (result == WAIT_FAILED)\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForSingleObjectEx\");\n\n        if (result == WAIT_OBJECT_0)\n        {\n            state.scrollWheelValue = 0;\n        }\n\n        if (mMode == MODE_RELATIVE)\n        {\n            result = WaitForSingleObjectEx(mRelativeRead.get(), 0, FALSE);\n\n            if (result == WAIT_FAILED)\n                throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForSingleObjectEx\");\n\n            if (result == WAIT_OBJECT_0)\n            {\n                state.x = 0;\n                state.y = 0;\n            }\n            else\n            {\n                SetEvent(mRelativeRead.get());\n            }\n        }\n\n        state.positionMode = mMode;\n    }\n\n    void ResetScrollWheelValue() noexcept\n    {\n        SetEvent(mScrollWheelValue.get());\n    }\n\n    void SetMode(Mode mode)\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::UI::Core;\n        using namespace ABI::Windows::Foundation;\n\n        if (mMode == mode)\n            return;\n\n        ComPtr<ICoreWindowStatic> statics;\n        HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreWindow).Get(), statics.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        ComPtr<ICoreWindow> window;\n        hr = statics->GetForCurrentThread(window.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        if (mode == MODE_RELATIVE)\n        {\n            hr = window->get_PointerCursor(mCursor.ReleaseAndGetAddressOf());\n            ThrowIfFailed(hr);\n\n            hr = window->put_PointerCursor(nullptr);\n            ThrowIfFailed(hr);\n\n            SetEvent(mRelativeRead.get());\n\n            mMode = MODE_RELATIVE;\n        }\n        else\n        {\n            if (!mCursor)\n            {\n                ComPtr<ICoreCursorFactory> factory;\n                hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), factory.GetAddressOf());\n                ThrowIfFailed(hr);\n\n                hr = factory->CreateCursor(CoreCursorType_Arrow, 0, mCursor.GetAddressOf());\n                ThrowIfFailed(hr);\n            }\n\n            hr = window->put_PointerCursor(mCursor.Get());\n            ThrowIfFailed(hr);\n\n            mCursor.Reset();\n\n            mMode = MODE_ABSOLUTE;\n        }\n    }\n\n    bool IsConnected() const\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Devices::Input;\n        using namespace ABI::Windows::Foundation;\n\n        ComPtr<IMouseCapabilities> caps;\n        HRESULT hr = RoActivateInstance(HStringReference(RuntimeClass_Windows_Devices_Input_MouseCapabilities).Get(), &caps);\n        ThrowIfFailed(hr);\n\n        INT32 value;\n        if (SUCCEEDED(caps->get_MousePresent(&value)))\n        {\n            return value != 0;\n        }\n\n        return false;\n    }\n\n    bool IsVisible() const noexcept\n    {\n        if (mMode == MODE_RELATIVE)\n            return false;\n\n        ComPtr<ABI::Windows::UI::Core::ICoreCursor> cursor;\n        if (FAILED(mWindow->get_PointerCursor(cursor.GetAddressOf())))\n            return false;\n\n        return cursor != nullptr;\n    }\n\n    void SetVisible(bool visible)\n    {\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Foundation;\n        using namespace ABI::Windows::UI::Core;\n\n        if (mMode == MODE_RELATIVE)\n            return;\n\n        if (visible)\n        {\n            if (!mCursor)\n            {\n                ComPtr<ICoreCursorFactory> factory;\n                HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), factory.GetAddressOf());\n                ThrowIfFailed(hr);\n\n                hr = factory->CreateCursor(CoreCursorType_Arrow, 0, mCursor.GetAddressOf());\n                ThrowIfFailed(hr);\n            }\n\n            HRESULT hr = mWindow->put_PointerCursor(mCursor.Get());\n            ThrowIfFailed(hr);\n        }\n        else\n        {\n            HRESULT hr = mWindow->put_PointerCursor(nullptr);\n            ThrowIfFailed(hr);\n        }\n    }\n\n    void SetWindow(ABI::Windows::UI::Core::ICoreWindow* window)\n    {\n        using namespace Microsoft::WRL;\n        using namespace Microsoft::WRL::Wrappers;\n        using namespace ABI::Windows::Foundation;\n        using namespace ABI::Windows::Devices::Input;\n\n        if (mWindow.Get() == window)\n            return;\n\n        RemoveHandlers();\n\n        mWindow = window;\n\n        if (!window)\n        {\n            mCursor.Reset();\n            mMouse.Reset();\n            return;\n        }\n\n        ComPtr<IMouseDeviceStatics> mouseStatics;\n        HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Input_MouseDevice).Get(), mouseStatics.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        hr = mouseStatics->GetForCurrentView(mMouse.ReleaseAndGetAddressOf());\n        ThrowIfFailed(hr);\n\n        typedef __FITypedEventHandler_2_Windows__CDevices__CInput__CMouseDevice_Windows__CDevices__CInput__CMouseEventArgs MouseMovedHandler;\n        hr = mMouse->add_MouseMoved(Callback<MouseMovedHandler>(MouseMovedEvent).Get(), &mPointerMouseMovedToken);\n        ThrowIfFailed(hr);\n\n        typedef __FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CPointerEventArgs PointerHandler;\n        auto cb = Callback<PointerHandler>(PointerEvent);\n\n        hr = window->add_PointerPressed(cb.Get(), &mPointerPressedToken);\n        ThrowIfFailed(hr);\n\n        hr = window->add_PointerReleased(cb.Get(), &mPointerReleasedToken);\n        ThrowIfFailed(hr);\n\n        hr = window->add_PointerMoved(cb.Get(), &mPointerMovedToken);\n        ThrowIfFailed(hr);\n\n        hr = window->add_PointerWheelChanged(Callback<PointerHandler>(PointerWheel).Get(), &mPointerWheelToken);\n        ThrowIfFailed(hr);\n    }\n\n    State           mState;\n    Mouse* mOwner;\n    float           mDPI;\n\n    static Mouse::Impl* s_mouse;\n\nprivate:\n    Mode            mMode;\n\n    ComPtr<ABI::Windows::UI::Core::ICoreWindow> mWindow;\n    ComPtr<ABI::Windows::Devices::Input::IMouseDevice> mMouse;\n    ComPtr<ABI::Windows::UI::Core::ICoreCursor> mCursor;\n\n    ScopedHandle    mScrollWheelValue;\n    ScopedHandle    mRelativeRead;\n\n    EventRegistrationToken mPointerPressedToken;\n    EventRegistrationToken mPointerReleasedToken;\n    EventRegistrationToken mPointerMovedToken;\n    EventRegistrationToken mPointerWheelToken;\n    EventRegistrationToken mPointerMouseMovedToken;\n\n    void RemoveHandlers()\n    {\n        if (mWindow)\n        {\n            std::ignore = mWindow->remove_PointerPressed(mPointerPressedToken);\n            mPointerPressedToken.value = 0;\n\n            std::ignore = mWindow->remove_PointerReleased(mPointerReleasedToken);\n            mPointerReleasedToken.value = 0;\n\n            std::ignore = mWindow->remove_PointerMoved(mPointerMovedToken);\n            mPointerMovedToken.value = 0;\n\n            std::ignore = mWindow->remove_PointerWheelChanged(mPointerWheelToken);\n            mPointerWheelToken.value = 0;\n        }\n\n        if (mMouse)\n        {\n            std::ignore = mMouse->remove_MouseMoved(mPointerMouseMovedToken);\n            mPointerMouseMovedToken.value = 0;\n        }\n    }\n\n    static HRESULT PointerEvent(IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs* args)\n    {\n        using namespace ABI::Windows::Foundation;\n        using namespace ABI::Windows::UI::Input;\n        using namespace ABI::Windows::Devices::Input;\n\n        if (!s_mouse)\n            return S_OK;\n\n        ComPtr<IPointerPoint> currentPoint;\n        HRESULT hr = args->get_CurrentPoint(currentPoint.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        ComPtr<IPointerDevice> pointerDevice;\n        hr = currentPoint->get_PointerDevice(pointerDevice.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        PointerDeviceType devType;\n        hr = pointerDevice->get_PointerDeviceType(&devType);\n        ThrowIfFailed(hr);\n\n        if (devType == PointerDeviceType::PointerDeviceType_Mouse)\n        {\n            ComPtr<IPointerPointProperties> props;\n            hr = currentPoint->get_Properties(props.GetAddressOf());\n            ThrowIfFailed(hr);\n\n            boolean value;\n            hr = props->get_IsLeftButtonPressed(&value);\n            ThrowIfFailed(hr);\n            s_mouse->mState.leftButton = value != 0;\n\n            hr = props->get_IsRightButtonPressed(&value);\n            ThrowIfFailed(hr);\n            s_mouse->mState.rightButton = value != 0;\n\n            hr = props->get_IsMiddleButtonPressed(&value);\n            ThrowIfFailed(hr);\n            s_mouse->mState.middleButton = value != 0;\n\n            hr = props->get_IsXButton1Pressed(&value);\n            ThrowIfFailed(hr);\n            s_mouse->mState.xButton1 = value != 0;\n\n            hr = props->get_IsXButton2Pressed(&value);\n            ThrowIfFailed(hr);\n            s_mouse->mState.xButton2 = value != 0;\n        }\n\n        if (s_mouse->mMode == MODE_ABSOLUTE)\n        {\n            Point pos;\n            hr = currentPoint->get_Position(&pos);\n            ThrowIfFailed(hr);\n\n            float dpi = s_mouse->mDPI;\n\n            s_mouse->mState.x = static_cast<int>(pos.X * dpi / 96.f + 0.5f);\n            s_mouse->mState.y = static_cast<int>(pos.Y * dpi / 96.f + 0.5f);\n        }\n\n        return S_OK;\n    }\n\n    static HRESULT PointerWheel(IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs* args)\n    {\n        using namespace ABI::Windows::Foundation;\n        using namespace ABI::Windows::UI::Input;\n        using namespace ABI::Windows::Devices::Input;\n\n        if (!s_mouse)\n            return S_OK;\n\n        ComPtr<IPointerPoint> currentPoint;\n        HRESULT hr = args->get_CurrentPoint(currentPoint.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        ComPtr<IPointerDevice> pointerDevice;\n        hr = currentPoint->get_PointerDevice(pointerDevice.GetAddressOf());\n        ThrowIfFailed(hr);\n\n        PointerDeviceType devType;\n        hr = pointerDevice->get_PointerDeviceType(&devType);\n        ThrowIfFailed(hr);\n\n        if (devType == PointerDeviceType::PointerDeviceType_Mouse)\n        {\n            ComPtr<IPointerPointProperties> props;\n            hr = currentPoint->get_Properties(props.GetAddressOf());\n            ThrowIfFailed(hr);\n\n            boolean ishorz;\n            hr = props->get_IsHorizontalMouseWheel(&ishorz);\n            ThrowIfFailed(hr);\n            if (ishorz)\n            {\n                // Mouse only exposes the vertical scroll wheel.\n                return S_OK;\n            }\n\n            INT32 value;\n            hr = props->get_MouseWheelDelta(&value);\n            ThrowIfFailed(hr);\n\n            HANDLE evt = s_mouse->mScrollWheelValue.get();\n            if (WaitForSingleObjectEx(evt, 0, FALSE) == WAIT_OBJECT_0)\n            {\n                s_mouse->mState.scrollWheelValue = 0;\n                ResetEvent(evt);\n            }\n\n            s_mouse->mState.scrollWheelValue += value;\n\n            if (s_mouse->mMode == MODE_ABSOLUTE)\n            {\n                Point pos;\n                hr = currentPoint->get_Position(&pos);\n                ThrowIfFailed(hr);\n\n                float dpi = s_mouse->mDPI;\n\n                s_mouse->mState.x = static_cast<int>(pos.X * dpi / 96.f + 0.5f);\n                s_mouse->mState.y = static_cast<int>(pos.Y * dpi / 96.f + 0.5f);\n            }\n        }\n\n        return S_OK;\n    }\n\n    static HRESULT MouseMovedEvent(IInspectable*, ABI::Windows::Devices::Input::IMouseEventArgs* args)\n    {\n        using namespace ABI::Windows::Devices::Input;\n\n        if (!s_mouse)\n            return S_OK;\n\n        if (s_mouse->mMode == MODE_RELATIVE)\n        {\n            MouseDelta delta;\n            HRESULT hr = args->get_MouseDelta(&delta);\n            ThrowIfFailed(hr);\n\n            s_mouse->mState.x = delta.X;\n            s_mouse->mState.y = delta.Y;\n\n            ResetEvent(s_mouse->mRelativeRead.get());\n        }\n\n        return S_OK;\n    }\n};\n\n\nMouse::Impl* Mouse::Impl::s_mouse = nullptr;\n\n\nvoid Mouse::SetWindow(ABI::Windows::UI::Core::ICoreWindow* window)\n{\n    pImpl->SetWindow(window);\n}\n\n\nvoid Mouse::SetDpi(float dpi)\n{\n    auto pImpl = Impl::s_mouse;\n\n    if (!pImpl)\n        return;\n\n    pImpl->mDPI = dpi;\n}\n\n\n#else\n\n//======================================================================================\n// Win32 desktop implementation\n//======================================================================================\n\n//\n// For a Win32 desktop application, in your window setup be sure to call this method:\n//\n// m_mouse->SetWindow(hwnd);\n//\n// And call this static function from your Window Message Procedure\n//\n// LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n// {\n//     switch (message)\n//     {\n//     case WM_ACTIVATE:\n//     case WM_ACTIVATEAPP:\n//     case WM_INPUT:\n//     case WM_MOUSEMOVE:\n//     case WM_LBUTTONDOWN:\n//     case WM_LBUTTONUP:\n//     case WM_RBUTTONDOWN:\n//     case WM_RBUTTONUP:\n//     case WM_MBUTTONDOWN:\n//     case WM_MBUTTONUP:\n//     case WM_MOUSEWHEEL:\n//     case WM_XBUTTONDOWN:\n//     case WM_XBUTTONUP:\n//     case WM_MOUSEHOVER:\n//         Mouse::ProcessMessage(message, wParam, lParam);\n//         break;\n//\n//     }\n// }\n//\n\nclass Mouse::Impl\n{\npublic:\n    explicit Impl(Mouse* owner) noexcept(false) :\n        mState{},\n        mOwner(owner),\n        mWindow(nullptr),\n        mMode(MODE_ABSOLUTE),\n        mLastX(0),\n        mLastY(0),\n        mRelativeX(INT32_MAX),\n        mRelativeY(INT32_MAX),\n        mInFocus(true)\n    {\n        if (s_mouse)\n        {\n            throw std::logic_error(\"Mouse is a singleton\");\n        }\n\n        s_mouse = this;\n\n        mScrollWheelValue.reset(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        mRelativeRead.reset(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        mAbsoluteMode.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        mRelativeMode.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n        if (!mScrollWheelValue\n            || !mRelativeRead\n            || !mAbsoluteMode\n            || !mRelativeMode)\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"CreateEventEx\");\n        }\n    }\n\n    Impl(Impl&&) = default;\n    Impl& operator= (Impl&&) = default;\n\n    Impl(Impl const&) = delete;\n    Impl& operator= (Impl const&) = delete;\n\n    ~Impl()\n    {\n        s_mouse = nullptr;\n    }\n\n    void GetState(State& state) const\n    {\n        memcpy(&state, &mState, sizeof(State));\n        state.positionMode = mMode;\n\n        DWORD result = WaitForSingleObjectEx(mScrollWheelValue.get(), 0, FALSE);\n        if (result == WAIT_FAILED)\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForSingleObjectEx\");\n\n        if (result == WAIT_OBJECT_0)\n        {\n            state.scrollWheelValue = 0;\n        }\n\n        if (state.positionMode == MODE_RELATIVE)\n        {\n            result = WaitForSingleObjectEx(mRelativeRead.get(), 0, FALSE);\n\n            if (result == WAIT_FAILED)\n                throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForSingleObjectEx\");\n\n            if (result == WAIT_OBJECT_0)\n            {\n                state.x = 0;\n                state.y = 0;\n            }\n            else\n            {\n                SetEvent(mRelativeRead.get());\n            }\n        }\n    }\n\n    void ResetScrollWheelValue() noexcept\n    {\n        SetEvent(mScrollWheelValue.get());\n    }\n\n    void SetMode(Mode mode)\n    {\n        if (mMode == mode)\n            return;\n\n        SetEvent((mode == MODE_ABSOLUTE) ? mAbsoluteMode.get() : mRelativeMode.get());\n\n        assert(mWindow != nullptr);\n\n        // Send a WM_HOVER as a way to 'kick' the message processing even if the mouse is still.\n        TRACKMOUSEEVENT tme;\n        tme.cbSize = sizeof(tme);\n        tme.dwFlags = TME_HOVER;\n        tme.hwndTrack = mWindow;\n        tme.dwHoverTime = 1;\n        if (!TrackMouseEvent(&tme))\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"TrackMouseEvent\");\n        }\n    }\n\n    bool IsConnected() const noexcept\n    {\n        return GetSystemMetrics(SM_MOUSEPRESENT) != 0;\n    }\n\n    bool IsVisible() const noexcept\n    {\n        if (mMode == MODE_RELATIVE)\n            return false;\n\n        CURSORINFO info = { sizeof(CURSORINFO), 0, nullptr, {} };\n        if (!GetCursorInfo(&info))\n            return false;\n\n        return (info.flags & CURSOR_SHOWING) != 0;\n    }\n\n    void SetVisible(bool visible)\n    {\n        if (mMode == MODE_RELATIVE)\n            return;\n\n        CURSORINFO info = { sizeof(CURSORINFO), 0, nullptr, {} };\n        if (!GetCursorInfo(&info))\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"GetCursorInfo\");\n        }\n\n        const bool isvisible = (info.flags & CURSOR_SHOWING) != 0;\n        if (isvisible != visible)\n        {\n            ShowCursor(visible);\n        }\n    }\n\n    void SetWindow(HWND window)\n    {\n        if (mWindow == window)\n            return;\n\n        assert(window != nullptr);\n\n        RAWINPUTDEVICE Rid;\n        Rid.usUsagePage = 0x1 /* HID_USAGE_PAGE_GENERIC */;\n        Rid.usUsage = 0x2 /* HID_USAGE_GENERIC_MOUSE */;\n        Rid.dwFlags = RIDEV_INPUTSINK;\n        Rid.hwndTarget = window;\n        if (!RegisterRawInputDevices(&Rid, 1, sizeof(RAWINPUTDEVICE)))\n        {\n            throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"RegisterRawInputDevices\");\n        }\n\n        mWindow = window;\n    }\n\n    State           mState;\n\n    Mouse*          mOwner;\n\n    static Mouse::Impl* s_mouse;\n\nprivate:\n    HWND            mWindow;\n    Mode            mMode;\n\n    ScopedHandle    mScrollWheelValue;\n    ScopedHandle    mRelativeRead;\n    ScopedHandle    mAbsoluteMode;\n    ScopedHandle    mRelativeMode;\n\n    int             mLastX;\n    int             mLastY;\n    int             mRelativeX;\n    int             mRelativeY;\n\n    bool            mInFocus;\n\n    friend void Mouse::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam);\n\n    void ClipToWindow() noexcept\n    {\n        assert(mWindow != nullptr);\n\n        RECT rect;\n        GetClientRect(mWindow, &rect);\n\n        POINT ul;\n        ul.x = rect.left;\n        ul.y = rect.top;\n\n        POINT lr;\n        lr.x = rect.right;\n        lr.y = rect.bottom;\n\n        std::ignore = MapWindowPoints(mWindow, nullptr, &ul, 1);\n        std::ignore = MapWindowPoints(mWindow, nullptr, &lr, 1);\n\n        rect.left = ul.x;\n        rect.top = ul.y;\n\n        rect.right = lr.x;\n        rect.bottom = lr.y;\n\n        ClipCursor(&rect);\n    }\n};\n\n\nMouse::Impl* Mouse::Impl::s_mouse = nullptr;\n\n\nvoid Mouse::SetWindow(HWND window)\n{\n    pImpl->SetWindow(window);\n}\n\n\nvoid Mouse::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam)\n{\n    auto pImpl = Impl::s_mouse;\n\n    if (!pImpl)\n        return;\n\n    // First handle any pending scroll wheel reset event.\n    switch (WaitForSingleObjectEx(pImpl->mScrollWheelValue.get(), 0, FALSE))\n    {\n    default:\n    case WAIT_TIMEOUT:\n        break;\n\n    case WAIT_OBJECT_0:\n        pImpl->mState.scrollWheelValue = 0;\n        ResetEvent(pImpl->mScrollWheelValue.get());\n        break;\n\n    case WAIT_FAILED:\n        throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForMultipleObjectsEx\");\n    }\n\n    // Next handle mode change events.\n    HANDLE events[2] = { pImpl->mAbsoluteMode.get(), pImpl->mRelativeMode.get() };\n    switch (WaitForMultipleObjectsEx(static_cast<DWORD>(std::size(events)), events, FALSE, 0, FALSE))\n    {\n    default:\n    case WAIT_TIMEOUT:\n        break;\n\n    case WAIT_OBJECT_0:\n        {\n            pImpl->mMode = MODE_ABSOLUTE;\n            ClipCursor(nullptr);\n\n            POINT point;\n            point.x = pImpl->mLastX;\n            point.y = pImpl->mLastY;\n\n            // We show the cursor before moving it to support Remote Desktop\n            ShowCursor(TRUE);\n\n            if (MapWindowPoints(pImpl->mWindow, nullptr, &point, 1))\n            {\n                SetCursorPos(point.x, point.y);\n            }\n            pImpl->mState.x = pImpl->mLastX;\n            pImpl->mState.y = pImpl->mLastY;\n        }\n        break;\n\n    case (WAIT_OBJECT_0 + 1):\n        {\n            ResetEvent(pImpl->mRelativeRead.get());\n\n            pImpl->mMode = MODE_RELATIVE;\n            pImpl->mState.x = pImpl->mState.y = 0;\n            pImpl->mRelativeX = INT32_MAX;\n            pImpl->mRelativeY = INT32_MAX;\n\n            ShowCursor(FALSE);\n\n            pImpl->ClipToWindow();\n        }\n        break;\n\n    case WAIT_FAILED:\n        throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"WaitForMultipleObjectsEx\");\n    }\n\n    switch (message)\n    {\n    case WM_ACTIVATE:\n    case WM_ACTIVATEAPP:\n        if (wParam)\n        {\n            pImpl->mInFocus = true;\n\n            if (pImpl->mMode == MODE_RELATIVE)\n            {\n                pImpl->mState.x = pImpl->mState.y = 0;\n\n                ShowCursor(FALSE);\n\n                pImpl->ClipToWindow();\n            }\n        }\n        else\n        {\n            const int scrollWheel = pImpl->mState.scrollWheelValue;\n            memset(&pImpl->mState, 0, sizeof(State));\n            pImpl->mState.scrollWheelValue = scrollWheel;\n\n            if (pImpl->mMode == MODE_RELATIVE)\n            {\n                ClipCursor(nullptr);\n            }\n\n            pImpl->mInFocus = false;\n        }\n        return;\n\n    case WM_INPUT:\n        if (pImpl->mInFocus && pImpl->mMode == MODE_RELATIVE)\n        {\n            RAWINPUT raw;\n            UINT rawSize = sizeof(raw);\n\n            const UINT resultData = GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, &raw, &rawSize, sizeof(RAWINPUTHEADER));\n            if (resultData == UINT(-1))\n            {\n                throw std::runtime_error(\"GetRawInputData\");\n            }\n\n            if (raw.header.dwType == RIM_TYPEMOUSE)\n            {\n                if (!(raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE))\n                {\n                    pImpl->mState.x = raw.data.mouse.lLastX;\n                    pImpl->mState.y = raw.data.mouse.lLastY;\n\n                    ResetEvent(pImpl->mRelativeRead.get());\n                }\n                else if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP)\n                {\n                    // This is used to make Remote Desktop sessons work\n                    const int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);\n                    const int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);\n\n                    auto const x = static_cast<int>((float(raw.data.mouse.lLastX) / 65535.0f) * float(width));\n                    auto const y = static_cast<int>((float(raw.data.mouse.lLastY) / 65535.0f) * float(height));\n\n                    if (pImpl->mRelativeX == INT32_MAX)\n                    {\n                        pImpl->mState.x = pImpl->mState.y = 0;\n                    }\n                    else\n                    {\n                        pImpl->mState.x = x - pImpl->mRelativeX;\n                        pImpl->mState.y = y - pImpl->mRelativeY;\n                    }\n\n                    pImpl->mRelativeX = x;\n                    pImpl->mRelativeY = y;\n\n                    ResetEvent(pImpl->mRelativeRead.get());\n                }\n            }\n        }\n        return;\n\n    case WM_MOUSEMOVE:\n        break;\n\n    case WM_LBUTTONDOWN:\n        pImpl->mState.leftButton = true;\n        break;\n\n    case WM_LBUTTONUP:\n        pImpl->mState.leftButton = false;\n        break;\n\n    case WM_RBUTTONDOWN:\n        pImpl->mState.rightButton = true;\n        break;\n\n    case WM_RBUTTONUP:\n        pImpl->mState.rightButton = false;\n        break;\n\n    case WM_MBUTTONDOWN:\n        pImpl->mState.middleButton = true;\n        break;\n\n    case WM_MBUTTONUP:\n        pImpl->mState.middleButton = false;\n        break;\n\n    case WM_MOUSEWHEEL:\n        pImpl->mState.scrollWheelValue += GET_WHEEL_DELTA_WPARAM(wParam);\n        return;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wParam))\n        {\n        case XBUTTON1:\n            pImpl->mState.xButton1 = true;\n            break;\n\n        case XBUTTON2:\n            pImpl->mState.xButton2 = true;\n            break;\n        }\n        break;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wParam))\n        {\n        case XBUTTON1:\n            pImpl->mState.xButton1 = false;\n            break;\n\n        case XBUTTON2:\n            pImpl->mState.xButton2 = false;\n            break;\n        }\n        break;\n\n    case WM_MOUSEHOVER:\n        break;\n\n    default:\n        // Not a mouse message, so exit\n        return;\n    }\n\n    if (pImpl->mMode == MODE_ABSOLUTE)\n    {\n        // All mouse messages provide a new pointer position\n        const int xPos = static_cast<short>(LOWORD(lParam)); // GET_X_LPARAM(lParam);\n        const int yPos = static_cast<short>(HIWORD(lParam)); // GET_Y_LPARAM(lParam);\n\n        pImpl->mState.x = pImpl->mLastX = xPos;\n        pImpl->mState.y = pImpl->mLastY = yPos;\n    }\n}\n\n#endif\n#pragma endregion\n\n#pragma warning( disable : 4355 )\n\n// Public constructor.\nMouse::Mouse() noexcept(false)\n    : pImpl(std::make_unique<Impl>(this))\n{\n}\n\n\n// Move constructor.\nMouse::Mouse(Mouse&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n    pImpl->mOwner = this;\n}\n\n\n// Move assignment.\nMouse& Mouse::operator= (Mouse&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    pImpl->mOwner = this;\n    return *this;\n}\n\n\n// Public destructor.\nMouse::~Mouse() = default;\n\n\nMouse::State Mouse::GetState() const\n{\n    State state;\n    pImpl->GetState(state);\n    return state;\n}\n\n\nvoid Mouse::ResetScrollWheelValue() noexcept\n{\n    pImpl->ResetScrollWheelValue();\n}\n\n\nvoid Mouse::SetMode(Mode mode)\n{\n    pImpl->SetMode(mode);\n}\n\n\nbool Mouse::IsConnected() const\n{\n    return pImpl->IsConnected();\n}\n\nbool Mouse::IsVisible() const noexcept\n{\n    return pImpl->IsVisible();\n}\n\nvoid Mouse::SetVisible(bool visible)\n{\n    pImpl->SetVisible(visible);\n}\n\nMouse& Mouse::Get()\n{\n    if (!Impl::s_mouse || !Impl::s_mouse->mOwner)\n        throw std::logic_error(\"Mouse singleton not created\");\n\n    return *Impl::s_mouse->mOwner;\n}\n\n\n\n//======================================================================================\n// ButtonStateTracker\n//======================================================================================\n\n#define UPDATE_BUTTON_STATE(field) field = static_cast<ButtonState>( ( !!state.field ) | ( ( !!state.field ^ !!lastState.field ) << 1 ) )\n\nvoid Mouse::ButtonStateTracker::Update(const Mouse::State& state) noexcept\n{\n    UPDATE_BUTTON_STATE(leftButton);\n\n    assert((!state.leftButton && !lastState.leftButton) == (leftButton == UP));\n    assert((state.leftButton && lastState.leftButton) == (leftButton == HELD));\n    assert((!state.leftButton && lastState.leftButton) == (leftButton == RELEASED));\n    assert((state.leftButton && !lastState.leftButton) == (leftButton == PRESSED));\n\n    UPDATE_BUTTON_STATE(middleButton);\n    UPDATE_BUTTON_STATE(rightButton);\n    UPDATE_BUTTON_STATE(xButton1);\n    UPDATE_BUTTON_STATE(xButton2);\n\n    lastState = state;\n}\n\n#undef UPDATE_BUTTON_STATE\n\n\nvoid Mouse::ButtonStateTracker::Reset() noexcept\n{\n    memset(this, 0, sizeof(ButtonStateTracker));\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/NormalMapEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: NormalMapEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct NormalMapEffectConstants\n    {\n        XMVECTOR diffuseColor;\n        XMVECTOR emissiveColor;\n        XMVECTOR specularColorAndPower;\n\n        XMVECTOR lightDirection[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightDiffuseColor[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightSpecularColor[IEffectLights::MaxDirectionalLights];\n\n        XMVECTOR eyePosition;\n\n        XMVECTOR fogColor;\n        XMVECTOR fogVector;\n\n        XMMATRIX world;\n        XMVECTOR worldInverseTranspose[3];\n        XMMATRIX worldViewProj;\n    };\n\n    static_assert((sizeof(NormalMapEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct NormalMapEffectTraits\n    {\n        using ConstantBufferType = NormalMapEffectConstants;\n\n        static constexpr int VertexShaderCount = 8;\n        static constexpr int PixelShaderCount = 4;\n        static constexpr int ShaderPermutationCount = 16;\n        static constexpr int RootSignatureCount = 2;\n    };\n}\n\n// Internal NormalMapEffect implementation class.\nclass NormalMapEffect::Impl : public EffectBase<NormalMapEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n\n    enum RootParameterIndex\n    {\n        TextureSRV,\n        TextureNormalSRV,\n        TextureSampler,\n        ConstantBuffer,\n        TextureSpecularSRV,\n        RootParameterCount\n    };\n\n    bool specularMap;\n\n    D3D12_GPU_DESCRIPTOR_HANDLE texture;\n    D3D12_GPU_DESCRIPTOR_HANDLE specular;\n    D3D12_GPU_DESCRIPTOR_HANDLE normal;\n    D3D12_GPU_DESCRIPTOR_HANDLE sampler;\n\n    EffectLights lights;\n\n    int GetPipelineStatePermutation(uint32_t effectFlags) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxVcNoSpec.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxVcBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxNoSpecBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_VSNormalPixelLightingTxVcNoSpecBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_PSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_PSNormalPixelLightingTxNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_PSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettNormalMapEffect_PSNormalPixelLightingTxNoFogSpec.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxVc.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxVcNoSpec.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxVcBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxNoSpecBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_VSNormalPixelLightingTxVcNoSpecBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_PSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_PSNormalPixelLightingTxNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_PSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneNormalMapEffect_PSNormalPixelLightingTxNoFogSpec.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxVc.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxVcNoSpec.inc\"\n\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxVcBn.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxNoSpecBn.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_VSNormalPixelLightingTxVcNoSpecBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_PSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_PSNormalPixelLightingTxNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_PSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/XboxOneNormalMapEffect_PSNormalPixelLightingTxNoFogSpec.inc\"\n#else    \n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxVc.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxVcNoSpec.inc\"\n\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxBn.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxVcBn.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxNoSpecBn.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_VSNormalPixelLightingTxVcNoSpecBn.inc\"\n\n    #include \"Shaders/Compiled/NormalMapEffect_PSNormalPixelLightingTx.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_PSNormalPixelLightingTxNoFog.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_PSNormalPixelLightingTxNoSpec.inc\"\n    #include \"Shaders/Compiled/NormalMapEffect_PSNormalPixelLightingTxNoFogSpec.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<NormalMapEffectTraits>::VertexShaderBytecode[] =\n{\n    { NormalMapEffect_VSNormalPixelLightingTx,           sizeof(NormalMapEffect_VSNormalPixelLightingTx)           },\n    { NormalMapEffect_VSNormalPixelLightingTxVc,         sizeof(NormalMapEffect_VSNormalPixelLightingTxVc)         },\n\n    { NormalMapEffect_VSNormalPixelLightingTxBn,         sizeof(NormalMapEffect_VSNormalPixelLightingTxBn)         },\n    { NormalMapEffect_VSNormalPixelLightingTxVcBn,       sizeof(NormalMapEffect_VSNormalPixelLightingTxVcBn)       },\n\n    { NormalMapEffect_VSNormalPixelLightingTxNoSpec,     sizeof(NormalMapEffect_VSNormalPixelLightingTxNoSpec)     },\n    { NormalMapEffect_VSNormalPixelLightingTxVcNoSpec,   sizeof(NormalMapEffect_VSNormalPixelLightingTxVcNoSpec)   },\n\n    { NormalMapEffect_VSNormalPixelLightingTxNoSpecBn,   sizeof(NormalMapEffect_VSNormalPixelLightingTxNoSpecBn)   },\n    { NormalMapEffect_VSNormalPixelLightingTxVcNoSpecBn, sizeof(NormalMapEffect_VSNormalPixelLightingTxVcNoSpecBn) },\n};\n\n\ntemplate<>\nconst int EffectBase<NormalMapEffectTraits>::VertexShaderIndices[] =\n{\n    0,     // pixel lighting + texture\n    0,     // pixel lighting + texture, no fog\n    1,     // pixel lighting + texture + vertex color\n    1,     // pixel lighting + texture + vertex color, no fog\n\n    4,     // pixel lighting + texture, no specular\n    4,     // pixel lighting + texture, no fog or specular\n    5,     // pixel lighting + texture + vertex color, no specular\n    5,     // pixel lighting + texture + vertex color, no fog or specular\n\n    2,     // pixel lighting (biased vertex normal) + texture\n    2,     // pixel lighting (biased vertex normal) + texture, no fog\n    3,     // pixel lighting (biased vertex normal) + texture + vertex color\n    3,     // pixel lighting (biased vertex normal) + texture + vertex color, no fog\n\n    6,     // pixel lighting (biased vertex normal) + texture, no specular\n    6,     // pixel lighting (biased vertex normal) + texture, no fog or specular\n    7,     // pixel lighting (biased vertex normal) + texture + vertex color, no specular\n    7,     // pixel lighting (biased vertex normal) + texture + vertex color, no fog or specular\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<NormalMapEffectTraits>::PixelShaderBytecode[] =\n{\n    { NormalMapEffect_PSNormalPixelLightingTx,          sizeof(NormalMapEffect_PSNormalPixelLightingTx)          },\n    { NormalMapEffect_PSNormalPixelLightingTxNoFog,     sizeof(NormalMapEffect_PSNormalPixelLightingTxNoFog)     },\n    { NormalMapEffect_PSNormalPixelLightingTxNoSpec,    sizeof(NormalMapEffect_PSNormalPixelLightingTxNoSpec)    },\n    { NormalMapEffect_PSNormalPixelLightingTxNoFogSpec, sizeof(NormalMapEffect_PSNormalPixelLightingTxNoFogSpec) },\n};\n\n\ntemplate<>\nconst int EffectBase<NormalMapEffectTraits>::PixelShaderIndices[] =\n{\n    0,      // pixel lighting + texture\n    1,      // pixel lighting + texture, no fog\n    0,      // pixel lighting + texture + vertex color\n    1,      // pixel lighting + texture + vertex color, no fog\n\n    2,     // pixel lighting + texture, no specular\n    3,     // pixel lighting + texture, no fog or specular\n    2,     // pixel lighting + texture + vertex color, no specular\n    3,     // pixel lighting + texture + vertex color, no fog or specular\n\n    0,      // pixel lighting (biased vertex normal) + texture\n    1,      // pixel lighting (biased vertex normal) + texture, no fog\n    0,      // pixel lighting (biased vertex normal) + texture + vertex color\n    1,      // pixel lighting (biased vertex normal) + texture + vertex color, no fog\n\n    2,     // pixel lighting (biased vertex normal) + texture, no specular\n    3,     // pixel lighting (biased vertex normal) + texture, no fog or specular\n    2,     // pixel lighting (biased vertex normal) + texture + vertex color, no specular\n    3,     // pixel lighting (biased vertex normal) + texture + vertex color, no fog or specular\n};\n\n// Global pool of per-device NormalMapEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<NormalMapEffectTraits>::DeviceResources> EffectBase<NormalMapEffectTraits>::deviceResourcesPool = {};\n\n\n// Constructor.\nNormalMapEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : EffectBase(device),\n        specularMap((effectFlags & EffectFlags::Specular) != 0),\n        texture{},\n        specular{},\n        normal{},\n        sampler{}\n{\n    static_assert(_countof(EffectBase<NormalMapEffectTraits>::VertexShaderIndices) == NormalMapEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<NormalMapEffectTraits>::VertexShaderBytecode) == NormalMapEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<NormalMapEffectTraits>::PixelShaderBytecode) == NormalMapEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<NormalMapEffectTraits>::PixelShaderIndices) == NormalMapEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    lights.InitializeConstants(constants.specularColorAndPower, constants.lightDirection, constants.lightDiffuseColor, constants.lightSpecularColor);\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        CD3DX12_DESCRIPTOR_RANGE textureSRV(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_DESCRIPTOR_RANGE textureSRV2(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);\n        rootParameters[RootParameterIndex::TextureNormalSRV].InitAsDescriptorTable(1, &textureSRV2, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_DESCRIPTOR_RANGE textureSampler(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n        rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n\n        if (specularMap)\n        {\n            CD3DX12_DESCRIPTOR_RANGE textureSRV3(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 2);\n            rootParameters[RootParameterIndex::TextureSpecularSRV].InitAsDescriptorTable(1, &textureSRV3, D3D12_SHADER_VISIBILITY_PIXEL);\n\n            rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n            mRootSignature = GetRootSignature(1, rsigDesc);\n        }\n        else\n        {\n            rsigDesc.Init(_countof(rootParameters) - 1, rootParameters, 0, nullptr, rootSignatureFlags);\n\n            mRootSignature = GetRootSignature(0, rsigDesc);\n        }\n    }\n\n    assert(mRootSignature != nullptr);\n\n    fog.enabled = (effectFlags & EffectFlags::Fog) != 0;\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(effectFlags);\n    assert(sp >= 0 && sp < NormalMapEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < NormalMapEffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<NormalMapEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < NormalMapEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < NormalMapEffectTraits::VertexShaderCount);\n    int pi = EffectBase<NormalMapEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < NormalMapEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < NormalMapEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<NormalMapEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<NormalMapEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"NormalMapEffect\");\n}\n\n\nint NormalMapEffect::Impl::GetPipelineStatePermutation(uint32_t effectFlags) const noexcept\n{\n    int permutation = 0;\n\n    // Use optimized shaders if fog is disabled.\n    if (!fog.enabled)\n    {\n        permutation += 1;\n    }\n\n    // Support vertex coloring?\n    if (effectFlags & EffectFlags::VertexColor)\n    {\n        permutation += 2;\n    }\n\n    if (!specularMap)\n    {\n        permutation += 4;\n    }\n\n    if (effectFlags & EffectFlags::BiasedVertexNormals)\n    {\n        // Compressed normals need to be scaled and biased in the vertex shader.\n        permutation += 8;\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid NormalMapEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n    fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector);\n    lights.SetConstants(dirtyFlags, matrices, constants.world, constants.worldInverseTranspose, constants.eyePosition, constants.diffuseColor, constants.emissiveColor, true);\n\n    UpdateConstants();\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture\n    if (!texture.ptr || !sampler.ptr || !normal.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture(s) or sampler for NormalMapEffect (texture %llu, normal %llu, sampler %llu)\\n\", texture.ptr, normal.ptr, sampler.ptr);\n        throw std::exception(\"NormalMapEffect\");\n    }\n\n    // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureNormalSRV, normal);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler);\n\n    if (specularMap)\n    {\n        if (!specular.ptr)\n        {\n            DebugTrace(\"ERROR: Missing specular texure NormalMapEffect (texture %llu)\\n\", specular.ptr);\n            throw std::exception(\"NormalMapEffect\");\n        }\n        commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSpecularSRV, specular);\n    }\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n\n// Public constructor.\nNormalMapEffect::NormalMapEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription))\n{\n}\n\n\n// Move constructor.\nNormalMapEffect::NormalMapEffect(NormalMapEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nNormalMapEffect& NormalMapEffect::operator= (NormalMapEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nNormalMapEffect::~NormalMapEffect()\n{\n}\n\n\n// IEffect methods\nvoid NormalMapEffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings\nvoid XM_CALLCONV NormalMapEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\n// Material settings\nvoid XM_CALLCONV NormalMapEffect::SetDiffuseColor(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetEmissiveColor(FXMVECTOR value)\n{\n    pImpl->lights.emissiveColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetSpecularColor(FXMVECTOR value)\n{\n    // Set xyz to new value, but preserve existing w (specular power).\n    pImpl->constants.specularColorAndPower = XMVectorSelect(pImpl->constants.specularColorAndPower, value, g_XMSelect1110);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid NormalMapEffect::SetSpecularPower(float value)\n{\n    // Set w to new value, but preserve existing xyz (specular color).\n    pImpl->constants.specularColorAndPower = XMVectorSetW(pImpl->constants.specularColorAndPower, value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid NormalMapEffect::DisableSpecular()\n{\n    // Set specular color to black, power to 1\n    // Note: Don't use a power of 0 or the shader will generate strange highlights on non-specular materials\n\n    pImpl->constants.specularColorAndPower = g_XMIdentityR3; \n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid NormalMapEffect::SetAlpha(float value)\n{\n    pImpl->lights.alpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetColorAndAlpha(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n    pImpl->lights.alpha = XMVectorGetW(value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\n// Light settings\nvoid XM_CALLCONV NormalMapEffect::SetAmbientLightColor(FXMVECTOR value)\n{\n    pImpl->lights.ambientLightColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid NormalMapEffect::SetLightEnabled(int whichLight, bool value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightEnabled(whichLight, value, pImpl->constants.lightDiffuseColor, pImpl->constants.lightSpecularColor);\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetLightDirection(int whichLight, FXMVECTOR value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->constants.lightDirection[whichLight] = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightDiffuseColor(whichLight, value, pImpl->constants.lightDiffuseColor);\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetLightSpecularColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightSpecularColor(whichLight, value, pImpl->constants.lightSpecularColor);\n}\n\n\nvoid NormalMapEffect::EnableDefaultLighting()\n{\n    EffectLights::EnableDefaultLighting(this);\n}\n\n\n// Fog settings.\nvoid NormalMapEffect::SetFogStart(float value)\n{\n    pImpl->fog.start = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid NormalMapEffect::SetFogEnd(float value)\n{\n    pImpl->fog.end = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV NormalMapEffect::SetFogColor(FXMVECTOR value)\n{\n    pImpl->constants.fogColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid NormalMapEffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->texture = srvDescriptor;\n    pImpl->sampler = samplerDescriptor;\n}\n\n\nvoid NormalMapEffect::SetNormalTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    pImpl->normal = srvDescriptor;\n}\n\n\nvoid NormalMapEffect::SetSpecularTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    if (!pImpl->specularMap)\n    {\n        DebugTrace(\"WARNING: Specular texture set on NormalMapEffect instance created without specular shader (texture %llu)\\n\", srvDescriptor.ptr);\n    }\n\n    pImpl->specular = srvDescriptor;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/PBREffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: PBREffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct PBREffectConstants\n    {\n        XMVECTOR eyePosition;\n        XMMATRIX world;\n        XMVECTOR worldInverseTranspose[3];\n        XMMATRIX worldViewProj;\n        XMMATRIX prevWorldViewProj; // for velocity generation\n\n        XMVECTOR lightDirection[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightDiffuseColor[IEffectLights::MaxDirectionalLights];\n\n        // PBR Parameters\n        XMVECTOR Albedo;\n        float    Metallic;\n        float    Roughness;\n        int      numRadianceMipLevels;\n\n        // Size of render target \n        float   targetWidth;\n        float   targetHeight;\n    };\n\n    static_assert((sizeof(PBREffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct PBREffectTraits\n    {\n        using ConstantBufferType = PBREffectConstants;\n\n        static constexpr int VertexShaderCount = 4;\n        static constexpr int PixelShaderCount = 5;\n        static constexpr int ShaderPermutationCount = 10;\n        static constexpr int RootSignatureCount = 1;\n    };\n}\n\n// Internal PBREffect implementation class.\nclass PBREffect::Impl : public EffectBase<PBREffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, \n        uint32_t effectFlags,\n        const EffectPipelineStateDescription& pipelineDescription);\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n\n    int GetPipelineStatePermutation(uint32_t effectFlags) const noexcept;\n\n    bool textureEnabled;\n    bool emissiveMap;\n\n    enum RootParameterIndex\n    {\n        AlbedoTexture,\n        NormalTexture,\n        RMATexture,\n        EmissiveTexture,\n        RadianceTexture,\n        IrradianceTexture,\n        SurfaceSampler,\n        RadianceSampler,\n        ConstantBuffer,\n        RootParametersCount\n    };\n\n    D3D12_GPU_DESCRIPTOR_HANDLE descriptors[RootParametersCount];\n\n    XMVECTOR lightColor[MaxDirectionalLights];\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_VSConstant.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_VSConstantVelocity.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_VSConstantBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_VSConstantVelocityBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_PSConstant.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_PSTextured.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_PSTexturedEmissive.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_PSTexturedVelocity.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettPBREffect_PSTexturedEmissiveVelocity.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_VSConstant.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_VSConstantVelocity.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_VSConstantBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_VSConstantVelocityBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_PSConstant.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_PSTextured.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_PSTexturedEmissive.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_PSTexturedVelocity.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOnePBREffect_PSTexturedEmissiveVelocity.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOnePBREffect_VSConstant.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_VSConstantVelocity.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_VSConstantBn.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_VSConstantVelocityBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOnePBREffect_PSConstant.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_PSTextured.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_PSTexturedEmissive.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_PSTexturedVelocity.inc\"\n    #include \"Shaders/Compiled/XboxOnePBREffect_PSTexturedEmissiveVelocity.inc\"\n#else    \n    #include \"Shaders/Compiled/PBREffect_VSConstant.inc\"\n    #include \"Shaders/Compiled/PBREffect_VSConstantVelocity.inc\"\n    #include \"Shaders/Compiled/PBREffect_VSConstantBn.inc\"\n    #include \"Shaders/Compiled/PBREffect_VSConstantVelocityBn.inc\"\n\n    #include \"Shaders/Compiled/PBREffect_PSConstant.inc\"\n    #include \"Shaders/Compiled/PBREffect_PSTextured.inc\"\n    #include \"Shaders/Compiled/PBREffect_PSTexturedEmissive.inc\"\n    #include \"Shaders/Compiled/PBREffect_PSTexturedVelocity.inc\"\n    #include \"Shaders/Compiled/PBREffect_PSTexturedEmissiveVelocity.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<PBREffectTraits>::VertexShaderBytecode[] =\n{\n    { PBREffect_VSConstant, sizeof(PBREffect_VSConstant) },\n    { PBREffect_VSConstantVelocity, sizeof(PBREffect_VSConstantVelocity) },\n    { PBREffect_VSConstantBn, sizeof(PBREffect_VSConstantBn) },\n    { PBREffect_VSConstantVelocityBn, sizeof(PBREffect_VSConstantVelocityBn) },\n};\n\n\ntemplate<>\nconst int EffectBase<PBREffectTraits>::VertexShaderIndices[] =\n{\n    0,      // constant\n    0,      // textured\n    0,      // textured + emissive\n    1,      // textured + velocity\n    1,      // textured + emissive + velocity\n\n    2,      // constant (biased vertex normals)\n    2,      // textured (biased vertex normals)\n    2,      // textured + emissive (biased vertex normals)\n    3,      // textured + velocity (biased vertex normals)\n    3,      // textured + emissive + velocity (biasoed vertex normals)\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<PBREffectTraits>::PixelShaderBytecode[] =\n{\n    { PBREffect_PSConstant, sizeof(PBREffect_PSConstant) },\n    { PBREffect_PSTextured, sizeof(PBREffect_PSTextured) },\n    { PBREffect_PSTexturedEmissive, sizeof(PBREffect_PSTexturedEmissive) },\n    { PBREffect_PSTexturedVelocity, sizeof(PBREffect_PSTexturedVelocity) },\n    { PBREffect_PSTexturedEmissiveVelocity, sizeof(PBREffect_PSTexturedEmissiveVelocity) }\n};\n\n\ntemplate<>\nconst int EffectBase<PBREffectTraits>::PixelShaderIndices[] =\n{\n    0,      // constant\n    1,      // textured\n    2,      // textured + emissive\n    3,      // textured + velocity\n    4,      // textured + emissive + velocity\n\n    0,      // constant (biased vertex normals)\n    1,      // textured (biased vertex normals)\n    2,      // textured + emissive (biased vertex normals)\n    3,      // textured + velocity (biased vertex normals)\n    4,      // textured + emissive + velocity (biased vertex normals)\n};\n\n// Global pool of per-device PBREffect resources. Required by EffectBase<>, but not used.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<PBREffectTraits>::DeviceResources> EffectBase<PBREffectTraits>::deviceResourcesPool = {};\n\n// Constructor.\nPBREffect::Impl::Impl(_In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : EffectBase(device),\n        emissiveMap((effectFlags & EffectFlags::Emissive) != 0),\n        descriptors{},\n        lightColor{}\n{\n    static_assert(_countof(EffectBase<PBREffectTraits>::VertexShaderIndices) == PBREffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<PBREffectTraits>::VertexShaderBytecode) == PBREffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<PBREffectTraits>::PixelShaderBytecode) == PBREffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<PBREffectTraits>::PixelShaderIndices) == PBREffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    // Lighting\n    static const XMVECTORF32 defaultLightDirection = { { { 0, -1, 0, 0 } } };\n    for (int i = 0; i < MaxDirectionalLights; i++)\n    {\n        lightColor[i] = g_XMOne;\n        constants.lightDirection[i] = defaultLightDirection;\n        constants.lightDiffuseColor[i] = g_XMZero;\n    }\n\n    if (effectFlags & EffectFlags::Texture)\n    {\n        textureEnabled = true;\n    }\n    else\n    {\n        textureEnabled = false;\n\n        if (effectFlags & (EffectFlags::Emissive | EffectFlags::Velocity))\n        {\n            DebugTrace(\"ERROR: PBREffect does not support emissive or velocity without surface textures\\n\");\n            throw std::invalid_argument(\"PBREffect\");\n        }\n    }\n\n    // Default PBR values\n    constants.Albedo = g_XMOne;\n    constants.Metallic = 0.5f;\n    constants.Roughness = 0.2f;\n    constants.numRadianceMipLevels = 1;\n\n    // Create root signature\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | // Only the input assembler stage needs access to the constant buffer.\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParametersCount] = {};\n        CD3DX12_DESCRIPTOR_RANGE textureSRV[6] = {\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0),\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1),\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 2),\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 3),\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 4),\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 5),\n        };\n\n        CD3DX12_DESCRIPTOR_RANGE textureSampler[2] = {\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0),\n            CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 1)\n        };\n\n        for (size_t i = 0; i < _countof(textureSRV); i++)\n        {\n            rootParameters[i].InitAsDescriptorTable(1, &textureSRV[i]);\n        }\n\n        for (size_t i = 0; i < _countof(textureSampler); i++)\n        {\n            rootParameters[i + SurfaceSampler].InitAsDescriptorTable(1, &textureSampler[i]);\n        }\n\n        rootParameters[ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc;\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n        mRootSignature = GetRootSignature(0, rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    if (effectFlags & EffectFlags::Fog)\n    {\n        DebugTrace(\"ERROR: PBEffect does not implement EffectFlags::Fog\\n\");\n        throw std::invalid_argument(\"PBREffect\");\n    }\n    else  if (effectFlags & EffectFlags::VertexColor)\n    {\n        DebugTrace(\"ERROR: PBEffect does not implement EffectFlags::VertexColor\\n\");\n        throw std::invalid_argument(\"PBREffect\");\n    }\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(effectFlags);\n    assert(sp >= 0 && sp < PBREffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < PBREffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<PBREffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < PBREffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < PBREffectTraits::VertexShaderCount);\n    int pi = EffectBase<PBREffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < PBREffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < PBREffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<PBREffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<PBREffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.ReleaseAndGetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"PBREffect\");\n}\n\n\nint PBREffect::Impl::GetPipelineStatePermutation(uint32_t effectFlags) const noexcept\n{\n    int permutation = 0;\n\n    // Textured RMA vs. constant albedo/roughness/metalness?\n    if (effectFlags & EffectFlags::Velocity)\n    {\n        // Optional velocity buffer (implies textured RMA)?\n        permutation = 3;\n    }\n    else if (textureEnabled)\n    {\n        permutation = 1;\n    }\n\n    // Using an emissive texture?\n    if (emissiveMap)\n    {\n        permutation += 1;\n    }\n\n    if (effectFlags & EffectFlags::BiasedVertexNormals)\n    {\n        // Compressed normals need to be scaled and biased in the vertex shader.\n        permutation += 5;\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid PBREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Store old wvp for velocity calculation in shader\n    constants.prevWorldViewProj = constants.worldViewProj;\n\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);        \n\n    // World inverse transpose matrix.\n    if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose)\n    {\n        constants.world = XMMatrixTranspose(matrices.world);\n\n        XMMATRIX worldInverse = XMMatrixInverse(nullptr, matrices.world);\n\n        constants.worldInverseTranspose[0] = worldInverse.r[0];\n        constants.worldInverseTranspose[1] = worldInverse.r[1];\n        constants.worldInverseTranspose[2] = worldInverse.r[2];\n\n        dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n\n    // Eye position vector.\n    if (dirtyFlags & EffectDirtyFlags::EyePosition)\n    {\n        XMMATRIX viewInverse = XMMatrixInverse(nullptr, matrices.view);\n\n        constants.eyePosition = viewInverse.r[3];\n\n        dirtyFlags &= ~EffectDirtyFlags::EyePosition;\n        dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n    }\n\n    // Set constants to GPU\n    UpdateConstants();\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    if (!descriptors[RadianceTexture].ptr || !descriptors[RadianceSampler].ptr)\n    {\n        DebugTrace(\"ERROR: Missing radiance texture or sampler for PBREffect (texture %llu, sampler %llu)\\n\", descriptors[RadianceTexture].ptr, descriptors[RadianceSampler].ptr);\n        throw std::exception(\"PBREffect\");\n    }\n\n    if (!descriptors[IrradianceTexture].ptr)\n    {\n        DebugTrace(\"ERROR: Missing irradiance texture for PBREffect (texture %llu)\\n\", descriptors[IrradianceTexture].ptr);\n        throw std::exception(\"PBREffect\");\n    }\n\n    // Set the root parameters\n    if (!textureEnabled)\n    {\n        // only update radiance/irradiance texture and samplers\n\n        // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n        commandList->SetGraphicsRootDescriptorTable(RadianceTexture, descriptors[RadianceTexture]);\n        commandList->SetGraphicsRootDescriptorTable(IrradianceTexture, descriptors[IrradianceTexture]);\n        commandList->SetGraphicsRootDescriptorTable(RadianceSampler, descriptors[RadianceSampler]);\n\n        // Bind 'empty' textures to avoid warnings on PC\n        commandList->SetGraphicsRootDescriptorTable(AlbedoTexture, descriptors[RadianceTexture]);\n        commandList->SetGraphicsRootDescriptorTable(NormalTexture, descriptors[RadianceTexture]);\n        commandList->SetGraphicsRootDescriptorTable(RMATexture, descriptors[RadianceTexture]);\n        commandList->SetGraphicsRootDescriptorTable(EmissiveTexture, descriptors[RadianceTexture]);\n        commandList->SetGraphicsRootDescriptorTable(SurfaceSampler, descriptors[RadianceSampler]);\n    }\n    else\n    {\n        if (!descriptors[AlbedoTexture].ptr || !descriptors[SurfaceSampler].ptr)\n        {\n            DebugTrace(\"ERROR: Missing albedo texture or sampler for PBREffect (texture %llu, sampler %llu)\\n\", descriptors[AlbedoTexture].ptr, descriptors[SurfaceSampler].ptr);\n            throw std::exception(\"PBREffect\");\n        }\n\n        if (!descriptors[NormalTexture].ptr)\n        {\n            DebugTrace(\"ERROR: Missing normal map texture for PBREffect (texture %llu)\\n\", descriptors[NormalTexture].ptr);\n            throw std::exception(\"PBREffect\");\n        }\n\n        if (!descriptors[RMATexture].ptr)\n        {\n            DebugTrace(\"ERROR: Missing roughness/metalness texture for PBREffect (texture %llu)\\n\", descriptors[RMATexture].ptr);\n            throw std::exception(\"PBREffect\");\n        }\n\n        for (unsigned i = 0; i < ConstantBuffer; i++)\n        {\n            if (i == EmissiveTexture)\n                continue;\n\n            // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n            commandList->SetGraphicsRootDescriptorTable(i, descriptors[i]);\n        }\n\n        if (emissiveMap)\n        {\n            if (!descriptors[EmissiveTexture].ptr)\n            {\n                DebugTrace(\"ERROR: Missing emissive map texture for PBREffect (texture %llu)\\n\", descriptors[NormalTexture].ptr);\n                throw std::exception(\"PBREffect\");\n            }\n\n            commandList->SetGraphicsRootDescriptorTable(EmissiveTexture, descriptors[EmissiveTexture]);\n        }\n        else\n        {\n            // Bind 'empty' textures to avoid warnings on PC\n            commandList->SetGraphicsRootDescriptorTable(EmissiveTexture, descriptors[AlbedoTexture]);\n        }\n\n    }\n\n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n// Public constructor.\nPBREffect::PBREffect(_In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription))\n{\n}\n\n\n// Move constructor.\nPBREffect::PBREffect(PBREffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nPBREffect& PBREffect::operator= (PBREffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nPBREffect::~PBREffect()\n{\n}\n\n// IEffect methods.\nvoid PBREffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings.\nvoid XM_CALLCONV PBREffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose;\n}\n\n\nvoid XM_CALLCONV PBREffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition;\n}\n\n\nvoid XM_CALLCONV PBREffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV PBREffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition;\n}\n\n\n// Light settings\nvoid XM_CALLCONV PBREffect::SetAmbientLightColor(FXMVECTOR)\n{\n    // Unsupported interface.\n}\n\n\nvoid PBREffect::SetLightEnabled(int whichLight, bool value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->constants.lightDiffuseColor[whichLight] = (value) ? pImpl->lightColor[whichLight] : g_XMZero;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV PBREffect::SetLightDirection(int whichLight, FXMVECTOR value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->constants.lightDirection[whichLight] = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV PBREffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->lightColor[whichLight] = value;\n    pImpl->constants.lightDiffuseColor[whichLight] = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV PBREffect::SetLightSpecularColor(int, FXMVECTOR)\n{\n    // Unsupported interface.\n}\n\n\nvoid PBREffect::EnableDefaultLighting()\n{\n    EffectLights::EnableDefaultLighting(this);\n}\n\n\n// PBR Settings\nvoid PBREffect::SetAlpha(float value)\n{\n    // Set w to new value, but preserve existing xyz (constant albedo).\n    pImpl->constants.Albedo = XMVectorSetW(pImpl->constants.Albedo, value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid PBREffect::SetConstantAlbedo(FXMVECTOR value)\n{\n    // Set xyz to new value, but preserve existing w (alpha).\n    pImpl->constants.Albedo = XMVectorSelect(pImpl->constants.Albedo, value, g_XMSelect1110);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid PBREffect::SetConstantMetallic(float value)\n{\n    pImpl->constants.Metallic = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid PBREffect::SetConstantRoughness(float value)\n{\n    pImpl->constants.Roughness = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid PBREffect::SetAlbedoTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->descriptors[Impl::RootParameterIndex::AlbedoTexture] = srvDescriptor;\n    pImpl->descriptors[Impl::RootParameterIndex::SurfaceSampler] = samplerDescriptor;\n}\n\n\nvoid PBREffect::SetNormalTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    pImpl->descriptors[Impl::RootParameterIndex::NormalTexture] = srvDescriptor;\n}\n\n\nvoid PBREffect::SetRMATexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    pImpl->descriptors[Impl::RootParameterIndex::RMATexture] = srvDescriptor;\n}\n\n\nvoid PBREffect::SetEmissiveTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    if (!pImpl->emissiveMap)\n    {\n        DebugTrace(\"WARNING: Emissive texture set on PBREffect instance created without emissive shader (texture %llu)\\n\", srvDescriptor.ptr);\n    }\n\n    pImpl->descriptors[Impl::RootParameterIndex::EmissiveTexture] = srvDescriptor;\n}\n\n\nvoid PBREffect::SetSurfaceTextures(\n    D3D12_GPU_DESCRIPTOR_HANDLE albedo,\n    D3D12_GPU_DESCRIPTOR_HANDLE normal,\n    D3D12_GPU_DESCRIPTOR_HANDLE roughnessMetallicAmbientOcclusion,\n    D3D12_GPU_DESCRIPTOR_HANDLE sampler)\n{\n    pImpl->descriptors[Impl::RootParameterIndex::AlbedoTexture]  = albedo;\n    pImpl->descriptors[Impl::RootParameterIndex::NormalTexture]  = normal;\n    pImpl->descriptors[Impl::RootParameterIndex::RMATexture]     = roughnessMetallicAmbientOcclusion;\n    pImpl->descriptors[Impl::RootParameterIndex::SurfaceSampler] = sampler;\n}\n\n\nvoid PBREffect::SetIBLTextures(\n    D3D12_GPU_DESCRIPTOR_HANDLE radiance,\n    int numRadianceMips,\n    D3D12_GPU_DESCRIPTOR_HANDLE irradiance,\n    D3D12_GPU_DESCRIPTOR_HANDLE sampler)\n{\n    pImpl->descriptors[Impl::RootParameterIndex::RadianceTexture] = radiance;\n    pImpl->descriptors[Impl::RootParameterIndex::RadianceSampler] = sampler;\n    pImpl->constants.numRadianceMipLevels = numRadianceMips;\n\n    pImpl->descriptors[Impl::RootParameterIndex::IrradianceTexture] = irradiance;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Additional settings.\nvoid PBREffect::SetRenderTargetSizeInPixels(int width, int height)\n{\n    pImpl->constants.targetWidth = static_cast<float>(width);\n    pImpl->constants.targetHeight = static_cast<float>(height);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/PBREffectFactory.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: PBREffectFactory.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"Effects.h\"\n#include \"CommonStates.h\"\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"DescriptorHeap.h\"\n\n#include <mutex>\n\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n// Internal PBREffectFactory implementation class. Only one of these helpers is allocated\n// per D3D device, even if there are multiple public facing PBREffectFactory instances.\nclass PBREffectFactory::Impl\n{\npublic:\n    Impl(_In_ ID3D12Device* device, _In_ ID3D12DescriptorHeap* textureDescriptors, _In_ ID3D12DescriptorHeap* samplerDescriptors) noexcept(false)\n        : mTextureDescriptors(nullptr)\n        , mSamplerDescriptors(nullptr)\n        , mDevice(device)\n        , mSharing(true)\n    { \n        if (textureDescriptors)\n            mTextureDescriptors = std::make_unique<DescriptorHeap>(textureDescriptors);\n        if (samplerDescriptors)\n            mSamplerDescriptors = std::make_unique<DescriptorHeap>(samplerDescriptors);\n    }\n\n    std::shared_ptr<IEffect> CreateEffect(\n        const EffectInfo& info,\n        const EffectPipelineStateDescription& opaquePipelineState,\n        const EffectPipelineStateDescription& alphaPipelineState,\n        const D3D12_INPUT_LAYOUT_DESC& inputLayout,\n        int textureDescriptorOffset,\n        int samplerDescriptorOffset);\n\n    void ReleaseCache();\n    void SetSharing(bool enabled) noexcept { mSharing = enabled; }\n\n    std::unique_ptr<DescriptorHeap> mTextureDescriptors;\n    std::unique_ptr<DescriptorHeap> mSamplerDescriptors;\n\nprivate:\n    ComPtr<ID3D12Device> mDevice;\n\n    using EffectCache = std::map< std::wstring, std::shared_ptr<IEffect> >;\n\n    EffectCache  mEffectCache;\n\n    bool mSharing;\n\n    std::mutex mutex;\n};\n\n\nstd::shared_ptr<IEffect> PBREffectFactory::Impl::CreateEffect(\n    const EffectInfo& info,\n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    const D3D12_INPUT_LAYOUT_DESC& inputLayoutDesc,\n    int textureDescriptorOffset,\n    int samplerDescriptorOffset)\n{\n    if (!mTextureDescriptors)\n    {\n        DebugTrace(\"ERROR: PBREffectFactory created without texture descriptor heap!\\n\");\n        throw std::exception(\"PBREffectFactory\");\n    }\n    if (!mSamplerDescriptors)\n    {\n        DebugTrace(\"ERROR: PBREffectFactory created without sampler descriptor heap!\\n\");\n        throw std::exception(\"PBREffectFactory\");\n    }\n\n    int albetoTextureIndex = (info.diffuseTextureIndex != -1) ? info.diffuseTextureIndex + textureDescriptorOffset : -1;\n    int rmaTextureIndex = (info.specularTextureIndex != -1) ? info.specularTextureIndex + textureDescriptorOffset : -1;\n    int normalTextureIndex = (info.normalTextureIndex != -1) ? info.normalTextureIndex + textureDescriptorOffset : -1;\n    int emissiveTextureIndex = (info.emissiveTextureIndex != -1) ? info.emissiveTextureIndex + textureDescriptorOffset : -1;\n    int samplerIndex = (info.samplerIndex != -1) ? info.samplerIndex + samplerDescriptorOffset : -1;\n\n    // Modify base pipeline state\n    EffectPipelineStateDescription derivedPSD = (info.alphaValue < 1.0f) ? alphaPipelineState : opaquePipelineState;\n    derivedPSD.inputLayout = inputLayoutDesc;\n\n    // set effect flags for creation\n    int effectflags = EffectFlags::Texture;\n\n    if (info.biasedVertexNormals)\n    {\n        effectflags |= EffectFlags::BiasedVertexNormals;\n    }\n\n    if (emissiveTextureIndex != -1)\n    {\n        effectflags |= EffectFlags::Emissive;\n    }\n\n    std::wstring cacheName;\n    if (mSharing && !info.name.empty())\n    {\n        uint32_t hash = derivedPSD.ComputeHash();\n        cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);\n\n        auto it = mEffectCache.find(cacheName);\n        if (mSharing && it != mEffectCache.end())\n        {\n            return it->second;\n        }\n    }\n\n    auto effect = std::make_shared<PBREffect>(mDevice.Get(), effectflags, derivedPSD);\n\n    // We don't use EnableDefaultLighting generally for PBR as it uses Image-Based Lighting instead.\n\n    effect->SetAlpha(info.alphaValue);\n\n    effect->SetSurfaceTextures(\n        mTextureDescriptors->GetGpuHandle(static_cast<size_t>(albetoTextureIndex)),\n        mTextureDescriptors->GetGpuHandle(static_cast<size_t>(normalTextureIndex)),\n        mTextureDescriptors->GetGpuHandle(static_cast<size_t>(rmaTextureIndex)),\n        mSamplerDescriptors->GetGpuHandle(static_cast<size_t>(samplerIndex)));\n\n    if (emissiveTextureIndex != -1)\n    {\n        effect->SetEmissiveTexture(mTextureDescriptors->GetGpuHandle(static_cast<size_t>(emissiveTextureIndex)));\n    }\n\n    if (mSharing && !info.name.empty())\n    {\n        std::lock_guard<std::mutex> lock(mutex);\n        EffectCache::value_type v(cacheName, effect);\n        mEffectCache.insert(v);\n    }\n\n    return std::move(effect);\n}\n\nvoid PBREffectFactory::Impl::ReleaseCache()\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    mEffectCache.clear();\n}\n\n\n\n//--------------------------------------------------------------------------------------\n// PBREffectFactory\n//--------------------------------------------------------------------------------------\n\nPBREffectFactory::PBREffectFactory(_In_ ID3D12Device* device) noexcept(false)\n{\n    pImpl = std::make_shared<Impl>(device, nullptr, nullptr);\n}\n\nPBREffectFactory::PBREffectFactory(_In_ ID3D12DescriptorHeap* textureDescriptors, _In_ ID3D12DescriptorHeap* samplerDescriptors) noexcept(false)\n{\n    if (!textureDescriptors)\n    {\n        throw std::exception(\"Texture descriptor heap cannot be null if no device is provided. Use the alternative PBREffectFactory constructor instead.\");\n    }\n    if (!samplerDescriptors)\n    {\n        throw std::exception(\"Descriptor heap cannot be null if no device is provided. Use the alternative PBREffectFactory constructor instead.\");\n    }\n\n    if (textureDescriptors->GetDesc().Type != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)\n    {\n        throw std::exception(\"PBREffectFactory::CreateEffect requires a CBV_SRV_UAV descriptor heap for textureDescriptors.\");\n    }\n    if (samplerDescriptors->GetDesc().Type != D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)\n    {\n        throw std::exception(\"PBREffectFactory::CreateEffect requires a SAMPLER descriptor heap for samplerDescriptors.\");\n    }\n\n    ComPtr<ID3D12Device> device;\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    textureDescriptors->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()));\n#else\n    HRESULT hresult = textureDescriptors->GetDevice(IID_PPV_ARGS(device.GetAddressOf()));\n    if (FAILED(hresult))\n    {\n        throw com_exception(hresult);\n    }\n#endif\n\n    pImpl = std::make_shared<Impl>(device.Get(), textureDescriptors, samplerDescriptors);\n}\n\nPBREffectFactory::~PBREffectFactory()\n{\n}\n\n\nPBREffectFactory::PBREffectFactory(PBREffectFactory&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\nPBREffectFactory& PBREffectFactory::operator= (PBREffectFactory&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\nstd::shared_ptr<IEffect> PBREffectFactory::CreateEffect(\n    const EffectInfo& info, \n    const EffectPipelineStateDescription& opaquePipelineState,\n    const EffectPipelineStateDescription& alphaPipelineState,\n    const D3D12_INPUT_LAYOUT_DESC& inputLayout, \n    int textureDescriptorOffset,\n    int samplerDescriptorOffset)\n{\n    return pImpl->CreateEffect(info, opaquePipelineState, alphaPipelineState, inputLayout, textureDescriptorOffset, samplerDescriptorOffset);\n}\n\nvoid PBREffectFactory::ReleaseCache()\n{\n    pImpl->ReleaseCache();\n}\n\nvoid PBREffectFactory::SetSharing(bool enabled) noexcept\n{\n    pImpl->SetSharing(enabled);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/PlatformHelpers.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: PlatformHelpers.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#pragma warning(disable : 4324)\n\n#include <exception>\n#include <memory>\n\n#ifndef MAKEFOURCC\n    #define MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n                (static_cast<uint32_t>(static_cast<uint8_t>(ch0)) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch1)) << 8) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch2)) << 16) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch3)) << 24))\n#endif /* defined(MAKEFOURCC) */\n\nnamespace DirectX\n{\n    // Helper class for COM exceptions\n    class com_exception : public std::exception\n    {\n    public:\n        com_exception(HRESULT hr) noexcept : result(hr) {}\n\n        const char* what() const override\n        {\n            static char s_str[64] = {};\n            sprintf_s(s_str, \"Failure with HRESULT of %08X\", static_cast<unsigned int>(result));\n            return s_str;\n        }\n\n        HRESULT get_result() const noexcept { return result; }\n\n    private:\n        HRESULT result;\n    };\n\n    // Helper utility converts D3D API failures into exceptions.\n    inline void ThrowIfFailed(HRESULT hr) noexcept(false)\n    {\n        if (FAILED(hr))\n        {\n            throw com_exception(hr);\n        }\n    }\n\n\n    // Helper for output debug tracing\n    inline void DebugTrace(_In_z_ _Printf_format_string_ const char* format, ...) noexcept\n    {\n    #ifdef _DEBUG\n        va_list args;\n        va_start(args, format);\n\n        char buff[1024] = {};\n        vsprintf_s(buff, format, args);\n        OutputDebugStringA(buff);\n        va_end(args);\n    #else\n        UNREFERENCED_PARAMETER(format);\n    #endif\n    }\n\n\n    // Helper smart-pointers\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10) || (defined(_XBOX_ONE) && defined(_TITLE)) || !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)\n    struct virtual_deleter { void operator()(void* p) noexcept { if (p) VirtualFree(p, 0, MEM_RELEASE); } };\n#endif\n\n    struct aligned_deleter { void operator()(void* p) noexcept { _aligned_free(p); } };\n\n    struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };\n\n    using ScopedHandle = std::unique_ptr<void, handle_closer>;\n\n    inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/PrimitiveBatch.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: PrimitiveBatch.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"PrimitiveBatch.h\"\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"GraphicsMemory.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\nusing Microsoft::WRL::ComPtr;\n\n\n// Internal PrimitiveBatch implementation class.\nclass PrimitiveBatchBase::Impl\n{\npublic:\n    Impl(_In_ ID3D12Device* device, size_t maxIndices, size_t maxVertices, size_t vertexSize);\n\n    void Begin(_In_ ID3D12GraphicsCommandList* cmdList);\n    void End();\n\n    void Draw(D3D_PRIMITIVE_TOPOLOGY topology, bool isIndexed, _In_opt_count_(indexCount) uint16_t const* indices, size_t indexCount, size_t vertexCount, _Outptr_ void** pMappedVertices);\n\nprivate:\n    void FlushBatch();\n\n    GraphicsResource mVertexSegment;\n    GraphicsResource mIndexSegment;\n\n    ComPtr<ID3D12Device> mDevice;\n    ComPtr<ID3D12GraphicsCommandList> mCommandList;\n\n    size_t mMaxIndices;\n    size_t mMaxVertices;\n    size_t mVertexSize;\n    size_t mVertexPageSize;\n    size_t mIndexPageSize;\n\n    D3D_PRIMITIVE_TOPOLOGY mCurrentTopology;\n    bool mInBeginEndPair;\n    bool mCurrentlyIndexed;\n\n    size_t mIndexCount;\n    size_t mVertexCount;\n\n    size_t mBaseIndex;\n    size_t mBaseVertex;\n};\n\n\n// Constructor.\nPrimitiveBatchBase::Impl::Impl(_In_ ID3D12Device* device, size_t maxIndices, size_t maxVertices, size_t vertexSize)\n    : mDevice(device),\n    mCommandList(nullptr),\n    mMaxIndices(maxIndices),\n    mMaxVertices(maxVertices),\n    mVertexSize(vertexSize),\n    mVertexPageSize(maxVertices * vertexSize),\n    mIndexPageSize(maxIndices * sizeof(uint16_t)),\n    mCurrentTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED),\n    mInBeginEndPair(false),\n    mCurrentlyIndexed(false),\n    mIndexCount(0),\n    mVertexCount(0),\n    mBaseIndex(0),\n    mBaseVertex(0)\n{\n    if (!maxVertices)\n        throw std::exception(\"maxVertices must be greater than 0\");\n\n    if (vertexSize > D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES)\n        throw std::exception(\"Vertex size is too large for DirectX 12\");\n\n    if ((uint64_t(maxIndices) * sizeof(uint16_t)) > uint64_t(D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n        throw std::exception(\"IB too large for DirectX 12\");\n\n    if ((uint64_t(maxVertices) * uint64_t(vertexSize)) > uint64_t(D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM * 1024u * 1024u))\n        throw std::exception(\"VB too large for DirectX 12\");\n}\n\n\n// Begins a batch of primitive drawing operations.\n\nvoid PrimitiveBatchBase::Impl::Begin(_In_ ID3D12GraphicsCommandList* cmdList)\n{\n    if (mInBeginEndPair)\n        throw std::exception(\"Cannot nest Begin calls\");\n\n    mCommandList = cmdList;\n    mInBeginEndPair = true;\n}\n\n\n// Ends a batch of primitive drawing operations.\nvoid PrimitiveBatchBase::Impl::End()\n{\n    if (!mInBeginEndPair)\n        throw std::exception(\"Begin must be called before End\");\n\n    FlushBatch();\n\n    // Release our smart pointers and end the block\n    mIndexSegment.Reset();\n    mVertexSegment.Reset();\n    mCommandList.Reset();\n    mInBeginEndPair = false;\n}\n\n\n// Can we combine adjacent primitives using this topology into a single draw call?\nstatic bool CanBatchPrimitives(D3D_PRIMITIVE_TOPOLOGY topology) noexcept\n{\n    switch (topology)\n    {\n        case D3D_PRIMITIVE_TOPOLOGY_POINTLIST:\n        case D3D_PRIMITIVE_TOPOLOGY_LINELIST:\n        case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST:\n            // Lists can easily be merged.\n            return true;\n\n        default:\n            // Strips cannot.\n            return false;\n    }\n\n    // We could also merge indexed strips by inserting degenerates,\n    // but that's not always a perf win, so let's keep things simple.\n}\n\n\n// Adds new geometry to the batch.\n_Use_decl_annotations_\nvoid PrimitiveBatchBase::Impl::Draw(D3D_PRIMITIVE_TOPOLOGY topology, bool isIndexed, uint16_t const* indices, size_t indexCount, size_t vertexCount, void** pMappedVertices)\n{\n    if (isIndexed && !indices)\n        throw std::exception(\"Indices cannot be null\");\n\n    if (indexCount >= mMaxIndices)\n        throw std::exception(\"Too many indices\");\n\n    if (vertexCount >= mMaxVertices)\n        throw std::exception(\"Too many vertices\");\n\n    if (!mInBeginEndPair)\n        throw std::exception(\"Begin must be called before Draw\");\n\n    assert(pMappedVertices != nullptr);\n\n    // Can we merge this primitive in with an existing batch, or must we flush first?\n    bool wrapIndexBuffer = (mIndexCount + indexCount > mMaxIndices);\n    bool wrapVertexBuffer = (mVertexCount + vertexCount > mMaxVertices);\n\n    if ((topology != mCurrentTopology) ||\n        (isIndexed != mCurrentlyIndexed) ||\n        !CanBatchPrimitives(topology) ||\n        wrapIndexBuffer || wrapVertexBuffer)\n    {\n        FlushBatch();\n    }\n\n    // If we are not already in a batch, lock the buffers.\n    if (mCurrentTopology == D3D_PRIMITIVE_TOPOLOGY_UNDEFINED)\n    {\n        mIndexCount = 0;\n        mVertexCount = 0;\n        mBaseIndex = 0;\n        mBaseVertex = 0;\n        mCurrentTopology = topology;\n        mCurrentlyIndexed = isIndexed;\n\n        // Allocate a page for the primitive data\n        if (isIndexed)\n            mIndexSegment = GraphicsMemory::Get(mDevice.Get()).Allocate(mIndexPageSize);\n\n        mVertexSegment = GraphicsMemory::Get(mDevice.Get()).Allocate(mVertexPageSize);\n    }\n\n    // Copy over the index data.\n    if (isIndexed)\n    {\n        auto outputIndices = static_cast<uint16_t*>(mIndexSegment.Memory()) + mIndexCount;\n\n        for (size_t i = 0; i < indexCount; i++)\n        {\n            outputIndices[i] = static_cast<uint16_t>(indices[i] + mVertexCount - mBaseIndex);\n        }\n\n        mIndexCount += indexCount;\n    }\n\n    // Return the output vertex data location.\n    *pMappedVertices = static_cast<uint8_t*>(mVertexSegment.Memory()) + mVertexSize * mVertexCount;\n\n    mVertexCount += vertexCount;\n}\n\n\n// Sends queued primitives to the graphics device.\nvoid PrimitiveBatchBase::Impl::FlushBatch()\n{\n    // Early out if there is nothing to flush.\n    if (mCurrentTopology == D3D_PRIMITIVE_TOPOLOGY_UNDEFINED)\n        return;\n\n    mCommandList->IASetPrimitiveTopology(mCurrentTopology);\n\n    // Set the vertex buffer view\n    D3D12_VERTEX_BUFFER_VIEW vbv;\n    vbv.BufferLocation = mVertexSegment.GpuAddress();\n    vbv.SizeInBytes = static_cast<UINT>(mVertexSize * (mVertexCount - mBaseVertex));\n    vbv.StrideInBytes = static_cast<UINT>(mVertexSize);\n    mCommandList->IASetVertexBuffers(0, 1, &vbv);\n\n    if (mCurrentlyIndexed)\n    {\n        // Set the index buffer view\n        D3D12_INDEX_BUFFER_VIEW ibv;\n        ibv.BufferLocation = mIndexSegment.GpuAddress();\n        ibv.Format = DXGI_FORMAT_R16_UINT;\n        ibv.SizeInBytes = static_cast<UINT>(mIndexCount - mBaseIndex) * sizeof(uint16_t);\n        mCommandList->IASetIndexBuffer(&ibv);\n\n        // Draw indexed geometry.\n        mCommandList->DrawIndexedInstanced(static_cast<UINT>(mIndexCount - mBaseIndex), 1, 0, 0, 0);\n    }\n    else\n    {\n        // Draw non-indexed geometry.\n        mCommandList->DrawInstanced(static_cast<UINT>(mVertexCount - mBaseVertex), 1, 0, 0);\n    }\n\n    mCurrentTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;\n}\n\n\n// Public constructor.\nPrimitiveBatchBase::PrimitiveBatchBase(_In_ ID3D12Device* device, size_t maxIndices, size_t maxVertices, size_t vertexSize)\n    : pImpl(std::make_unique<Impl>(device, maxIndices, maxVertices, vertexSize))\n{\n}\n\n\n// Move constructor.\nPrimitiveBatchBase::PrimitiveBatchBase(PrimitiveBatchBase&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nPrimitiveBatchBase& PrimitiveBatchBase::operator= (PrimitiveBatchBase&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nPrimitiveBatchBase::~PrimitiveBatchBase()\n{\n}\n\n\nvoid PrimitiveBatchBase::Begin(_In_ ID3D12GraphicsCommandList* cmdList)\n{\n    pImpl->Begin(cmdList);\n}\n\n\nvoid PrimitiveBatchBase::End()\n{\n    pImpl->End();\n}\n\n\n_Use_decl_annotations_\nvoid PrimitiveBatchBase::Draw(D3D12_PRIMITIVE_TOPOLOGY topology, bool isIndexed, uint16_t const* indices, size_t indexCount, size_t vertexCount, void** pMappedVertices)\n{\n    pImpl->Draw(topology, isIndexed, indices, indexCount, vertexCount, pMappedVertices);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/ResourceUploadBatch.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: ResourceUploadBatch.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"LoaderHelpers.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettGenerateMips_main.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneGenerateMips_main.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneGenerateMips_main.inc\"\n#else\n    #include \"Shaders/Compiled/GenerateMips_main.inc\"\n#endif\n\n    bool FormatIsUAVCompatible(_In_ ID3D12Device* device, bool typedUAVLoadAdditionalFormats, DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_R32_FLOAT:\n        case DXGI_FORMAT_R32_UINT:\n        case DXGI_FORMAT_R32_SINT:\n            // Unconditionally supported.\n            return true;\n\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        case DXGI_FORMAT_R32G32B32A32_UINT:\n        case DXGI_FORMAT_R32G32B32A32_SINT:\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:\n        case DXGI_FORMAT_R16G16B16A16_UINT:\n        case DXGI_FORMAT_R16G16B16A16_SINT:\n        case DXGI_FORMAT_R8G8B8A8_UNORM:\n        case DXGI_FORMAT_R8G8B8A8_UINT:\n        case DXGI_FORMAT_R8G8B8A8_SINT:\n        case DXGI_FORMAT_R16_FLOAT:\n        case DXGI_FORMAT_R16_UINT:\n        case DXGI_FORMAT_R16_SINT:\n        case DXGI_FORMAT_R8_UNORM:\n        case DXGI_FORMAT_R8_UINT:\n        case DXGI_FORMAT_R8_SINT:\n            // All these are supported if this optional feature is set.\n            return typedUAVLoadAdditionalFormats;\n\n        case DXGI_FORMAT_R16G16B16A16_UNORM:\n        case DXGI_FORMAT_R16G16B16A16_SNORM:\n        case DXGI_FORMAT_R32G32_FLOAT:\n        case DXGI_FORMAT_R32G32_UINT:\n        case DXGI_FORMAT_R32G32_SINT:\n        case DXGI_FORMAT_R10G10B10A2_UNORM:\n        case DXGI_FORMAT_R10G10B10A2_UINT:\n        case DXGI_FORMAT_R11G11B10_FLOAT:\n        case DXGI_FORMAT_R8G8B8A8_SNORM:\n        case DXGI_FORMAT_R16G16_FLOAT:\n        case DXGI_FORMAT_R16G16_UNORM:\n        case DXGI_FORMAT_R16G16_UINT:\n        case DXGI_FORMAT_R16G16_SNORM:\n        case DXGI_FORMAT_R16G16_SINT:\n        case DXGI_FORMAT_R8G8_UNORM:\n        case DXGI_FORMAT_R8G8_UINT:\n        case DXGI_FORMAT_R8G8_SNORM:\n        case DXGI_FORMAT_R8G8_SINT:\n        case DXGI_FORMAT_R16_UNORM:\n        case DXGI_FORMAT_R16_SNORM:\n        case DXGI_FORMAT_R8_SNORM:\n        case DXGI_FORMAT_A8_UNORM:\n        case DXGI_FORMAT_B5G6R5_UNORM:\n        case DXGI_FORMAT_B5G5R5A1_UNORM:\n        case DXGI_FORMAT_B4G4R4A4_UNORM:\n            // Conditionally supported by specific devices.\n            if (typedUAVLoadAdditionalFormats)\n            {\n                D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = { format, D3D12_FORMAT_SUPPORT1_NONE, D3D12_FORMAT_SUPPORT2_NONE };\n                if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport))))\n                {\n                    const DWORD mask = D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE;\n                    return ((formatSupport.Support2 & mask) == mask);\n                }\n            }\n            return false;\n\n        default:\n            return false;\n        }\n    }\n\n    bool FormatIsBGR(DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_B8G8R8A8_UNORM:\n        case DXGI_FORMAT_B8G8R8X8_UNORM:\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            return true;\n        default:\n            return false;\n        }\n    }\n\n    bool FormatIsSRGB(DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            return true;\n        default:\n            return false;\n        }\n    }\n\n    DXGI_FORMAT ConvertSRVtoResourceFormat(DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        case DXGI_FORMAT_R32G32B32A32_UINT:\n        case DXGI_FORMAT_R32G32B32A32_SINT:\n            return DXGI_FORMAT_R32G32B32A32_TYPELESS;\n\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:\n        case DXGI_FORMAT_R16G16B16A16_UNORM:\n        case DXGI_FORMAT_R16G16B16A16_UINT:\n        case DXGI_FORMAT_R16G16B16A16_SNORM:\n        case DXGI_FORMAT_R16G16B16A16_SINT:\n            return DXGI_FORMAT_R16G16B16A16_TYPELESS;\n\n        case DXGI_FORMAT_R32G32_FLOAT:\n        case DXGI_FORMAT_R32G32_UINT:\n        case DXGI_FORMAT_R32G32_SINT:\n            return DXGI_FORMAT_R32G32_TYPELESS;\n\n        case DXGI_FORMAT_R10G10B10A2_UNORM:\n        case DXGI_FORMAT_R10G10B10A2_UINT:\n            return DXGI_FORMAT_R10G10B10A2_TYPELESS;\n\n        case DXGI_FORMAT_R8G8B8A8_UNORM:\n        case DXGI_FORMAT_R8G8B8A8_UINT:\n        case DXGI_FORMAT_R8G8B8A8_SNORM:\n        case DXGI_FORMAT_R8G8B8A8_SINT:\n            return DXGI_FORMAT_R8G8B8A8_TYPELESS;\n\n        case DXGI_FORMAT_R16G16_FLOAT:\n        case DXGI_FORMAT_R16G16_UNORM:\n        case DXGI_FORMAT_R16G16_UINT:\n        case DXGI_FORMAT_R16G16_SNORM:\n        case DXGI_FORMAT_R16G16_SINT:\n            return DXGI_FORMAT_R16G16_TYPELESS;\n\n        case DXGI_FORMAT_R32_FLOAT:\n        case DXGI_FORMAT_R32_UINT:\n        case DXGI_FORMAT_R32_SINT:\n            return DXGI_FORMAT_R32_TYPELESS;\n\n        case DXGI_FORMAT_R8G8_UNORM:\n        case DXGI_FORMAT_R8G8_UINT:\n        case DXGI_FORMAT_R8G8_SNORM:\n        case DXGI_FORMAT_R8G8_SINT:\n            return DXGI_FORMAT_R8G8_TYPELESS;\n\n        case DXGI_FORMAT_R16_FLOAT:\n        case DXGI_FORMAT_R16_UNORM:\n        case DXGI_FORMAT_R16_UINT:\n        case DXGI_FORMAT_R16_SNORM:\n        case DXGI_FORMAT_R16_SINT:\n            return DXGI_FORMAT_R16_TYPELESS;\n\n        case DXGI_FORMAT_R8_UNORM:\n        case DXGI_FORMAT_R8_UINT:\n        case DXGI_FORMAT_R8_SNORM:\n        case DXGI_FORMAT_R8_SINT:\n            return DXGI_FORMAT_R8_TYPELESS;\n\n        default:\n            return format;\n        }\n    }\n\n    class GenerateMipsResources\n    {\n    public:\n        enum RootParameterIndex\n        {\n            Constants,\n            SourceTexture,\n            TargetTexture,\n            RootParameterCount\n        };\n\n#pragma pack(push, 4)\n        struct ConstantData\n        {\n            XMFLOAT2 InvOutTexelSize;\n            uint32_t SrcMipIndex;\n        };\n#pragma pack(pop)\n\n        static const uint32_t Num32BitConstants = static_cast<uint32_t>(sizeof(ConstantData) / sizeof(uint32_t));\n        static const uint32_t ThreadGroupSize = 8;\n\n        ComPtr<ID3D12RootSignature> rootSignature;\n        ComPtr<ID3D12PipelineState> generateMipsPSO;\n\n        GenerateMipsResources(\n            _In_ ID3D12Device* device)\n        {\n            rootSignature = CreateGenMipsRootSignature(device);\n            generateMipsPSO = CreateGenMipsPipelineState(device, rootSignature.Get(), GenerateMips_main, sizeof(GenerateMips_main));\n        }\n\n    private:\n        static ComPtr<ID3D12RootSignature> CreateGenMipsRootSignature(\n            _In_ ID3D12Device* device)\n        {\n            D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n                D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n                D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n                D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n                D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n                D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;\n\n            CD3DX12_STATIC_SAMPLER_DESC sampler(\n                0, // register\n                D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP);\n\n            CD3DX12_DESCRIPTOR_RANGE sourceDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n            CD3DX12_DESCRIPTOR_RANGE targetDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0);\n\n            CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n            rootParameters[RootParameterIndex::Constants].InitAsConstants(Num32BitConstants, 0);\n            rootParameters[RootParameterIndex::SourceTexture].InitAsDescriptorTable(1, &sourceDescriptorRange);\n            rootParameters[RootParameterIndex::TargetTexture].InitAsDescriptorTable(1, &targetDescriptorRange);\n\n            CD3DX12_ROOT_SIGNATURE_DESC rsigDesc;\n            rsigDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags);\n\n            ComPtr<ID3D12RootSignature> rootSignature;\n            ThrowIfFailed(CreateRootSignature(device, &rsigDesc, rootSignature.ReleaseAndGetAddressOf()));\n\n            SetDebugObjectName(rootSignature.Get(), L\"GenerateMips RootSignature\");\n\n            return rootSignature;\n        }\n\n        static ComPtr<ID3D12PipelineState> CreateGenMipsPipelineState(\n            _In_ ID3D12Device* device,\n            _In_ ID3D12RootSignature* rootSignature,\n            _In_reads_(bytecodeSize) const uint8_t* bytecode,\n            _In_ size_t bytecodeSize)\n        {\n            D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {};\n            desc.CS.BytecodeLength = bytecodeSize;\n            desc.CS.pShaderBytecode = bytecode;\n            desc.pRootSignature = rootSignature;\n\n            ComPtr<ID3D12PipelineState> pso;\n            ThrowIfFailed(device->CreateComputePipelineState(&desc, IID_GRAPHICS_PPV_ARGS(pso.GetAddressOf())));\n\n            SetDebugObjectName(pso.Get(), L\"GenerateMips PSO\");\n\n            return pso;\n        }\n    };\n} // anonymous namespace\n\nclass ResourceUploadBatch::Impl\n{\npublic:\n    Impl(\n        _In_ ID3D12Device* device) noexcept\n        : mDevice(device)\n        , mCommandType(D3D12_COMMAND_LIST_TYPE_DIRECT)\n        , mInBeginEndBlock(false)\n        , mTypedUAVLoadAdditionalFormats(false)\n        , mStandardSwizzle64KBSupported(false)\n    {\n        assert(device != nullptr);\n        D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};\n        if (SUCCEEDED(device->CheckFeatureSupport(\n            D3D12_FEATURE_D3D12_OPTIONS,\n            &options,\n            sizeof(options))))\n        {\n            mTypedUAVLoadAdditionalFormats = options.TypedUAVLoadAdditionalFormats != 0;\n            mStandardSwizzle64KBSupported = options.StandardSwizzle64KBSupported != 0;\n        }\n    }\n\n    // Call this before your multiple calls to Upload.\n    void Begin(D3D12_COMMAND_LIST_TYPE commandType)\n    {\n        if (mInBeginEndBlock)\n            throw std::exception(\"Can't Begin: already in a Begin-End block.\");\n\n        switch (commandType)\n        {\n        case D3D12_COMMAND_LIST_TYPE_DIRECT:\n        case D3D12_COMMAND_LIST_TYPE_COMPUTE:\n        case D3D12_COMMAND_LIST_TYPE_COPY:\n            break;\n\n        default:\n            DebugTrace(\"ResourceUploadBatch only supports Direct, Compute, and Copy command queues\\n\");\n            throw std::invalid_argument(\"ResourceUploadBatch\");\n        }\n\n        ThrowIfFailed(mDevice->CreateCommandAllocator(commandType, IID_GRAPHICS_PPV_ARGS(mCmdAlloc.ReleaseAndGetAddressOf())));\n\n        SetDebugObjectName(mCmdAlloc.Get(), L\"ResourceUploadBatch\");\n\n        ThrowIfFailed(mDevice->CreateCommandList(1, commandType, mCmdAlloc.Get(), nullptr, IID_GRAPHICS_PPV_ARGS(mList.ReleaseAndGetAddressOf())));\n\n        SetDebugObjectName(mList.Get(), L\"ResourceUploadBatch\");\n\n        mCommandType = commandType;\n        mInBeginEndBlock = true;\n    }\n\n    // Asynchronously uploads a resource. The memory in subRes is copied.\n    // The resource must be in the COPY_DEST state.\n    void Upload(\n        _In_ ID3D12Resource* resource,\n        uint32_t subresourceIndexStart,\n        _In_reads_(numSubresources) const D3D12_SUBRESOURCE_DATA* subRes,\n        uint32_t numSubresources)\n    {\n        if (!mInBeginEndBlock)\n            throw std::exception(\"Can't call Upload on a closed ResourceUploadBatch.\");\n\n        UINT64 uploadSize = GetRequiredIntermediateSize(\n            resource,\n            subresourceIndexStart,\n            numSubresources);\n\n        CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);\n        CD3DX12_RESOURCE_DESC resDesc = CD3DX12_RESOURCE_DESC::Buffer(uploadSize);\n\n        // Create a temporary buffer\n        ComPtr<ID3D12Resource> scratchResource = nullptr;\n        ThrowIfFailed(mDevice->CreateCommittedResource(\n            &heapProps,\n            D3D12_HEAP_FLAG_NONE,\n            &resDesc,\n            D3D12_RESOURCE_STATE_GENERIC_READ,\n            nullptr, // D3D12_CLEAR_VALUE* pOptimizedClearValue\n            IID_GRAPHICS_PPV_ARGS(scratchResource.GetAddressOf())));\n\n        SetDebugObjectName(scratchResource.Get(), L\"ResourceUploadBatch Temporary\");\n\n        // Submit resource copy to command list\n        UpdateSubresources(mList.Get(), resource, scratchResource.Get(), 0, subresourceIndexStart, numSubresources,\n#if defined(_XBOX_ONE) && defined(_TITLE)\n            // Workaround for header constness issue\n            const_cast<D3D12_SUBRESOURCE_DATA*>(subRes)\n#else\n            subRes\n#endif\n        );\n\n        // Remember this upload object for delayed release\n        mTrackedObjects.push_back(scratchResource);\n    }\n\n    void Upload(\n        _In_ ID3D12Resource* resource,\n        const SharedGraphicsResource& buffer)\n    {\n        if (!mInBeginEndBlock)\n            throw std::exception(\"Can't call Upload on a closed ResourceUploadBatch.\");\n\n        // Submit resource copy to command list\n        mList->CopyBufferRegion(resource, 0, buffer.Resource(), buffer.ResourceOffset(), buffer.Size());\n\n        // Remember this upload resource for delayed release\n        mTrackedMemoryResources.push_back(buffer);\n    }\n\n    // Asynchronously generate mips from a resource.\n    // Resource must be in the PIXEL_SHADER_RESOURCE state\n    void GenerateMips(_In_ ID3D12Resource* resource)\n    {\n        if (resource == nullptr)\n        {\n            throw std::invalid_argument(\"Nullptr passed to GenerateMips\");\n        }\n\n        if (!mInBeginEndBlock)\n            throw std::exception(\"Can't call GenerateMips on a closed ResourceUploadBatch.\");\n\n        if (mCommandType == D3D12_COMMAND_LIST_TYPE_COPY)\n        {\n            DebugTrace(\"ERROR: GenerateMips cannot operate on a copy queue\\n\");\n            throw std::exception(\"GenerateMips cannot operate on a copy queue\");\n        }\n\n        const auto desc = resource->GetDesc();\n\n        if (desc.MipLevels == 1)\n        {\n            // Nothing to do \n            return;\n        }\n        if (desc.MipLevels == 0)\n        {\n            throw std::exception(\"GenerateMips: texture has no mips\");\n        }\n        if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)\n        {\n            throw std::exception(\"GenerateMips only supports Texture2D resources\");\n        }\n        if (desc.DepthOrArraySize != 1)\n        {\n            throw std::exception(\"GenerateMips only supports 2D textures of array size 1\");\n        }\n\n        bool uavCompat = FormatIsUAVCompatible(mDevice.Get(), mTypedUAVLoadAdditionalFormats, desc.Format);\n\n        if (!uavCompat && !FormatIsSRGB(desc.Format) && !FormatIsBGR(desc.Format))\n        {\n            throw std::exception(\"GenerateMips doesn't support this texture format on this device\");\n        }\n\n        // Ensure that we have valid generate mips data\n        if (mGenMipsResources == nullptr)\n        {\n            mGenMipsResources = std::make_unique<GenerateMipsResources>(mDevice.Get());\n        }\n\n        // If the texture's format doesn't support UAVs we'll have to copy it to a texture that does first.\n        // This is true of BGRA or sRGB textures, for example. \n        if (uavCompat)\n        {\n            GenerateMips_UnorderedAccessPath(resource);\n        }\n        else if (!mTypedUAVLoadAdditionalFormats)\n        {\n            throw std::exception(\"GenerateMips needs TypedUAVLoadAdditionalFormats device support for sRGB/BGR\");\n        }\n        else if (FormatIsBGR(desc.Format))\n        {\n#if !defined(_GAMING_XBOX) && !(defined(_XBOX_ONE) && defined(_TITLE))\n            if (!mStandardSwizzle64KBSupported)\n            {\n                throw std::exception(\"GenerateMips needs StandardSwizzle64KBSupported device support for BGR\");\n            }\n#endif\n\n            GenerateMips_TexturePathBGR(resource);\n        }\n        else\n        {\n            GenerateMips_TexturePath(resource);\n        }\n    }\n\n    // Transition a resource once you're done with it\n    void Transition(\n        _In_ ID3D12Resource* resource,\n        _In_ D3D12_RESOURCE_STATES stateBefore,\n        _In_ D3D12_RESOURCE_STATES stateAfter)\n    {\n        if (!mInBeginEndBlock)\n            throw std::exception(\"Can't call Upload on a closed ResourceUploadBatch.\");\n\n        if (mCommandType == D3D12_COMMAND_LIST_TYPE_COPY)\n        {\n            switch (stateAfter)\n            {\n            case D3D12_RESOURCE_STATE_COPY_DEST:\n            case D3D12_RESOURCE_STATE_COPY_SOURCE:\n                break;\n\n            default:\n                // Ignore other states for copy queues.\n                return;\n            }\n        }\n        else if (mCommandType == D3D12_COMMAND_LIST_TYPE_COMPUTE)\n        {\n            switch (stateAfter)\n            {\n            case D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER:\n            case D3D12_RESOURCE_STATE_UNORDERED_ACCESS:\n            case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:\n            case D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT:\n            case D3D12_RESOURCE_STATE_COPY_DEST:\n            case D3D12_RESOURCE_STATE_COPY_SOURCE:\n                break;\n\n            default:\n                // Ignore other states for compute queues.\n                return;\n            }\n        }\n\n        TransitionResource(mList.Get(), resource, stateBefore, stateAfter);\n    }\n\n    // Submits all the uploads to the driver.\n    // No more uploads can happen after this call until Begin is called again.\n    // This returns a handle to an event that can be waited on.\n    std::future<void> End(\n        _In_ ID3D12CommandQueue* commandQueue)\n    {\n        if (!mInBeginEndBlock)\n            throw std::exception(\"ResourceUploadBatch already closed.\");\n\n        ThrowIfFailed(mList->Close());\n\n        // Submit the job to the GPU\n        commandQueue->ExecuteCommandLists(1, CommandListCast(mList.GetAddressOf()));\n\n        // Set an event so we get notified when the GPU has completed all its work\n        ComPtr<ID3D12Fence> fence;\n        ThrowIfFailed(mDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(fence.GetAddressOf())));\n\n        SetDebugObjectName(fence.Get(), L\"ResourceUploadBatch\");\n\n        HANDLE gpuCompletedEvent = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);\n        if (!gpuCompletedEvent)\n            throw std::exception(\"CreateEventEx\");\n\n        ThrowIfFailed(commandQueue->Signal(fence.Get(), 1ULL));\n        ThrowIfFailed(fence->SetEventOnCompletion(1ULL, gpuCompletedEvent));\n\n        // Create a packet of data that'll be passed to our waiting upload thread\n        auto uploadBatch = new UploadBatch();\n        uploadBatch->CommandList = mList;\n        uploadBatch->Fence = fence;\n        uploadBatch->GpuCompleteEvent = gpuCompletedEvent;\n        std::swap(mTrackedObjects, uploadBatch->TrackedObjects);\n        std::swap(mTrackedMemoryResources, uploadBatch->TrackedMemoryResources);\n\n        // Kick off a thread that waits for the upload to complete on the GPU timeline.\n        // Let the thread run autonomously, but provide a future the user can wait on.\n        std::future<void> future = std::async(std::launch::async, [uploadBatch]()\n        {\n            // Wait on the GPU-complete notification\n            DWORD wr = WaitForSingleObject(uploadBatch->GpuCompleteEvent, INFINITE);\n            if (wr != WAIT_OBJECT_0)\n            {\n                if (wr == WAIT_FAILED)\n                {\n                    ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));\n                }\n                else\n                {\n                    throw std::exception(\"WaitForSingleObject\");\n                }\n            }\n\n            // Delete the batch\n            // Because the vectors contain smart-pointers, their destructors will\n            // fire and the resources will be released.\n            delete uploadBatch;\n        });\n\n        // Reset our state\n        mCommandType = D3D12_COMMAND_LIST_TYPE_DIRECT;\n        mInBeginEndBlock = false;\n        mList.Reset();\n        mCmdAlloc.Reset();\n\n        // Swap above should have cleared these\n        assert(mTrackedObjects.empty());\n        assert(mTrackedMemoryResources.empty());\n\n        return future;\n    }\n\n    bool IsSupportedForGenerateMips(DXGI_FORMAT format) noexcept\n    {\n        if (mCommandType == D3D12_COMMAND_LIST_TYPE_COPY)\n            return false;\n\n        if (FormatIsUAVCompatible(mDevice.Get(), mTypedUAVLoadAdditionalFormats, format))\n            return true;\n\n        if (FormatIsBGR(format))\n        {\n#if defined(_GAMING_XBOX) || (defined(_XBOX_ONE) && defined(_TITLE))\n            // We know the RGB and BGR memory layouts match for Xbox One\n            return true;\n#else\n            // BGR path requires DXGI_FORMAT_R8G8B8A8_UNORM support for UAV load/store plus matching layouts\n            return mTypedUAVLoadAdditionalFormats && mStandardSwizzle64KBSupported;\n#endif\n        }\n\n        if (FormatIsSRGB(format))\n        {\n            // sRGB path requires DXGI_FORMAT_R8G8B8A8_UNORM support for UAV load/store\n            return mTypedUAVLoadAdditionalFormats;\n        }\n\n        return false;\n    }\n\nprivate:\n    // Resource is UAV compatible\n    void GenerateMips_UnorderedAccessPath(\n        _In_ ID3D12Resource* resource)\n    {\n        const auto desc = resource->GetDesc();\n        assert(!FormatIsBGR(desc.Format) && !FormatIsSRGB(desc.Format));\n\n        CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        assert(mCommandType != D3D12_COMMAND_LIST_TYPE_COPY);\n        const D3D12_RESOURCE_STATES originalState = (mCommandType == D3D12_COMMAND_LIST_TYPE_COMPUTE)\n            ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;\n\n        // Create a staging resource if we have to\n        ComPtr<ID3D12Resource> staging;\n        if ((desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) == 0)\n        {\n            D3D12_RESOURCE_DESC stagingDesc = desc;\n            stagingDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;\n            stagingDesc.Format = ConvertSRVtoResourceFormat(desc.Format);\n\n            ThrowIfFailed(mDevice->CreateCommittedResource(\n                &defaultHeapProperties,\n                D3D12_HEAP_FLAG_NONE,\n                &stagingDesc,\n                D3D12_RESOURCE_STATE_COPY_DEST,\n                nullptr,\n                IID_GRAPHICS_PPV_ARGS(staging.GetAddressOf())));\n\n            SetDebugObjectName(staging.Get(), L\"GenerateMips Staging\");\n\n            // Copy the top mip of resource to staging\n            TransitionResource(mList.Get(), resource, originalState, D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n            CD3DX12_TEXTURE_COPY_LOCATION src(resource, 0);\n            CD3DX12_TEXTURE_COPY_LOCATION dst(staging.Get(), 0);\n            mList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);\n\n            TransitionResource(mList.Get(), staging.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n        }\n        else\n        {\n            // Resource is already a UAV so we can do this in-place\n            staging = resource;\n\n            TransitionResource(mList.Get(), staging.Get(), originalState, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n        }\n\n        // Create a descriptor heap that holds our resource descriptors\n        ComPtr<ID3D12DescriptorHeap> descriptorHeap;\n        D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {};\n        descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;\n        descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;\n        descriptorHeapDesc.NumDescriptors = desc.MipLevels;\n        mDevice->CreateDescriptorHeap(&descriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(descriptorHeap.GetAddressOf()));\n\n        SetDebugObjectName(descriptorHeap.Get(), L\"ResourceUploadBatch\");\n\n        auto descriptorSize = static_cast<int>(mDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));\n\n        // Create the top-level SRV\n        CD3DX12_CPU_DESCRIPTOR_HANDLE handleIt(descriptorHeap->GetCPUDescriptorHandleForHeapStart());\n        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};\n        srvDesc.Format = desc.Format;\n        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n        srvDesc.Texture2D.MostDetailedMip = 0;\n        srvDesc.Texture2D.MipLevels = desc.MipLevels;\n\n        mDevice->CreateShaderResourceView(staging.Get(), &srvDesc, handleIt);\n\n        // Create the UAVs for the tail\n        for (uint16_t mip = 1; mip < desc.MipLevels; ++mip)\n        {\n            D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};\n            uavDesc.Format = desc.Format;\n            uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;\n            uavDesc.Texture2D.MipSlice = mip;\n\n            handleIt.Offset(descriptorSize);\n            mDevice->CreateUnorderedAccessView(staging.Get(), nullptr, &uavDesc, handleIt);\n        }\n\n        // Set up UAV barrier (used in loop)\n        D3D12_RESOURCE_BARRIER barrierUAV = {};\n        barrierUAV.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;\n        barrierUAV.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n        barrierUAV.UAV.pResource = staging.Get();\n\n        // Barrier for transitioning the subresources to UAVs\n        D3D12_RESOURCE_BARRIER srv2uavDesc = {};\n        srv2uavDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        srv2uavDesc.Transition.pResource = staging.Get();\n        srv2uavDesc.Transition.Subresource = 0;\n        srv2uavDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;\n        srv2uavDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n\n        // Barrier for transitioning the subresources to SRVs\n        D3D12_RESOURCE_BARRIER uav2srvDesc = {};\n        uav2srvDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        uav2srvDesc.Transition.pResource = staging.Get();\n        uav2srvDesc.Transition.Subresource = 0;\n        uav2srvDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n        uav2srvDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;\n\n        // based on format, select srgb or not\n        ComPtr<ID3D12PipelineState> pso = mGenMipsResources->generateMipsPSO;\n\n        // Set up state\n        mList->SetComputeRootSignature(mGenMipsResources->rootSignature.Get());\n        mList->SetPipelineState(pso.Get());\n        mList->SetDescriptorHeaps(1, descriptorHeap.GetAddressOf());\n        mList->SetComputeRootDescriptorTable(GenerateMipsResources::SourceTexture, descriptorHeap->GetGPUDescriptorHandleForHeapStart());\n\n        // Get the descriptor handle -- uavH will increment over each loop\n        CD3DX12_GPU_DESCRIPTOR_HANDLE uavH(\n            descriptorHeap->GetGPUDescriptorHandleForHeapStart(),\n            descriptorSize); // offset by 1 descriptor\n\n        // Process each mip\n        auto mipWidth = static_cast<uint32_t>(desc.Width);\n        uint32_t mipHeight = desc.Height;\n        for (uint32_t mip = 1; mip < desc.MipLevels; ++mip)\n        {\n            mipWidth = std::max<uint32_t>(1, mipWidth >> 1);\n            mipHeight = std::max<uint32_t>(1, mipHeight >> 1);\n\n            // Transition the mip to a UAV\n            srv2uavDesc.Transition.Subresource = mip;\n            mList->ResourceBarrier(1, &srv2uavDesc);\n\n            // Bind the mip subresources\n            mList->SetComputeRootDescriptorTable(GenerateMipsResources::TargetTexture, uavH);\n\n            // Set constants\n            GenerateMipsResources::ConstantData constants;\n            constants.SrcMipIndex = mip - 1;\n            constants.InvOutTexelSize = XMFLOAT2(1 / float(mipWidth), 1 / float(mipHeight));\n            mList->SetComputeRoot32BitConstants(\n                GenerateMipsResources::Constants,\n                GenerateMipsResources::Num32BitConstants,\n                &constants,\n                0);\n\n            // Process this mip\n            mList->Dispatch(\n                (mipWidth + GenerateMipsResources::ThreadGroupSize - 1) / GenerateMipsResources::ThreadGroupSize,\n                (mipHeight + GenerateMipsResources::ThreadGroupSize - 1) / GenerateMipsResources::ThreadGroupSize,\n                1);\n\n            mList->ResourceBarrier(1, &barrierUAV);\n\n            // Transition the mip to an SRV\n            uav2srvDesc.Transition.Subresource = mip;\n            mList->ResourceBarrier(1, &uav2srvDesc);\n\n            // Offset the descriptor heap handles\n            uavH.Offset(descriptorSize);\n        }\n\n        // If the staging resource is NOT the same as the resource, we need to copy everything back\n        if (staging.Get() != resource)\n        {\n            // Transition the resources ready for copy\n            D3D12_RESOURCE_BARRIER barrier[2] = {};\n            barrier[0].Type = barrier[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n            barrier[0].Transition.Subresource = barrier[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n            barrier[0].Transition.pResource = staging.Get();\n            barrier[0].Transition.StateBefore = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;\n            barrier[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;\n\n            barrier[1].Transition.pResource = resource;\n            barrier[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;\n            barrier[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;\n\n            mList->ResourceBarrier(2, barrier);\n\n            // Copy the entire resource back\n            mList->CopyResource(resource, staging.Get());\n\n            // Transition the target resource back to pixel shader resource\n            TransitionResource(mList.Get(), resource, D3D12_RESOURCE_STATE_COPY_DEST, originalState);\n\n            mTrackedObjects.push_back(staging);\n        }\n        else\n        {\n            TransitionResource(mList.Get(), staging.Get(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, originalState);\n        }\n\n        // Add our temporary objects to the deferred deletion queue\n        mTrackedObjects.push_back(mGenMipsResources->rootSignature);\n        mTrackedObjects.push_back(pso);\n        mTrackedObjects.push_back(resource);\n        mTrackedObjects.push_back(descriptorHeap);\n    }\n    \n    // Resource is not UAV compatible\n    void GenerateMips_TexturePath(\n        _In_ ID3D12Resource* resource)\n    {\n        const auto resourceDesc = resource->GetDesc();\n        assert(!FormatIsBGR(resourceDesc.Format) || FormatIsSRGB(resourceDesc.Format));\n\n        auto copyDesc = resourceDesc;\n        copyDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n        copyDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;\n\n        CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        // Create a resource with the same description, but without SRGB, and with UAV flags\n        ComPtr<ID3D12Resource> resourceCopy;\n        ThrowIfFailed(mDevice->CreateCommittedResource(\n            &heapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &copyDesc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(resourceCopy.GetAddressOf())));\n\n        SetDebugObjectName(resourceCopy.Get(), L\"GenerateMips Resource Copy\");\n\n        assert(mCommandType != D3D12_COMMAND_LIST_TYPE_COPY);\n        const D3D12_RESOURCE_STATES originalState = mCommandType == D3D12_COMMAND_LIST_TYPE_COMPUTE\n            ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;\n\n        // Copy the top mip of resource data\n        TransitionResource(mList.Get(), resource, originalState, D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n        CD3DX12_TEXTURE_COPY_LOCATION src(resource, 0);\n        CD3DX12_TEXTURE_COPY_LOCATION dst(resourceCopy.Get(), 0);\n        mList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);\n\n        TransitionResource(mList.Get(), resourceCopy.Get(), D3D12_RESOURCE_STATE_COPY_DEST, originalState);\n        \n        // Generate the mips\n        GenerateMips_UnorderedAccessPath(resourceCopy.Get());\n\n        // Direct copy back\n        D3D12_RESOURCE_BARRIER barrier[2] = {};\n        barrier[0].Type = barrier[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        barrier[0].Transition.Subresource = barrier[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n        barrier[0].Transition.pResource = resourceCopy.Get();\n        barrier[0].Transition.StateBefore = originalState;\n        barrier[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;\n\n        barrier[1].Transition.pResource = resource;\n        barrier[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;\n        barrier[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;\n\n        mList->ResourceBarrier(2, barrier);\n\n        // Copy the entire resource back\n        mList->CopyResource(resource, resourceCopy.Get());\n\n        TransitionResource(mList.Get(), resource, D3D12_RESOURCE_STATE_COPY_DEST, originalState);\n\n        // Track these object lifetimes on the GPU\n        mTrackedObjects.push_back(resourceCopy);\n        mTrackedObjects.push_back(resource);\n    }\n\n    // Resource is not UAV compatible (copy via alias to avoid validation failure)\n    void GenerateMips_TexturePathBGR(\n        _In_ ID3D12Resource* resource)\n    {\n        const auto resourceDesc = resource->GetDesc();\n        assert(FormatIsBGR(resourceDesc.Format));\n\n        // Create a resource with the same description with RGB and with UAV flags\n        auto copyDesc = resourceDesc;\n        copyDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n        copyDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;\n#if !defined(_GAMING_XBOX) && !(defined(_XBOX_ONE) && defined(_TITLE))\n        copyDesc.Layout = D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE;\n#endif\n\n        D3D12_HEAP_DESC heapDesc = {};\n        auto allocInfo = mDevice->GetResourceAllocationInfo(0, 1, &copyDesc);\n        heapDesc.SizeInBytes = allocInfo.SizeInBytes;\n        heapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;\n        heapDesc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;\n\n        ComPtr<ID3D12Heap> heap;\n        ThrowIfFailed(mDevice->CreateHeap(&heapDesc, IID_GRAPHICS_PPV_ARGS(heap.GetAddressOf())));\n\n        SetDebugObjectName(heap.Get(), L\"ResourceUploadBatch\");\n\n        ComPtr<ID3D12Resource> resourceCopy;\n        ThrowIfFailed(mDevice->CreatePlacedResource(\n            heap.Get(),\n            0,\n            &copyDesc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(resourceCopy.GetAddressOf())));\n\n        SetDebugObjectName(resourceCopy.Get(), L\"GenerateMips Resource Copy\");\n\n        // Create a BGRA alias\n        auto aliasDesc = resourceDesc;\n        aliasDesc.Format = (resourceDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM || resourceDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM_SRGB) ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM;\n        aliasDesc.Layout = copyDesc.Layout;\n\n        ComPtr<ID3D12Resource> aliasCopy;\n        ThrowIfFailed(mDevice->CreatePlacedResource(\n            heap.Get(),\n            0,\n            &aliasDesc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(aliasCopy.GetAddressOf())));\n\n        SetDebugObjectName(aliasCopy.Get(), L\"GenerateMips BGR Alias Copy\");\n\n        assert(mCommandType != D3D12_COMMAND_LIST_TYPE_COPY);\n        const D3D12_RESOURCE_STATES originalState = (mCommandType == D3D12_COMMAND_LIST_TYPE_COMPUTE)\n            ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;\n\n        // Copy the top mip of the resource data BGR to RGB\n        D3D12_RESOURCE_BARRIER aliasBarrier[3] = {};\n        aliasBarrier[0].Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;\n        aliasBarrier[0].Aliasing.pResourceAfter = aliasCopy.Get();\n\n        aliasBarrier[1].Type = aliasBarrier[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        aliasBarrier[1].Transition.Subresource = aliasBarrier[2].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;\n        aliasBarrier[1].Transition.pResource = resource;\n        aliasBarrier[1].Transition.StateBefore = originalState;\n        aliasBarrier[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;\n\n        mList->ResourceBarrier(2, aliasBarrier);\n\n        CD3DX12_TEXTURE_COPY_LOCATION src(resource, 0);\n        CD3DX12_TEXTURE_COPY_LOCATION dst(aliasCopy.Get(), 0);\n        mList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);\n\n        // Generate the mips\n        aliasBarrier[0].Aliasing.pResourceBefore = aliasCopy.Get();\n        aliasBarrier[0].Aliasing.pResourceAfter = resourceCopy.Get();\n\n        aliasBarrier[1].Transition.pResource = resourceCopy.Get();\n        aliasBarrier[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;\n        aliasBarrier[1].Transition.StateAfter = originalState;\n\n        mList->ResourceBarrier(2, aliasBarrier);\n        GenerateMips_UnorderedAccessPath(resourceCopy.Get());\n\n        // Direct copy back RGB to BGR\n        aliasBarrier[0].Aliasing.pResourceBefore = resourceCopy.Get();\n        aliasBarrier[0].Aliasing.pResourceAfter = aliasCopy.Get();\n\n        aliasBarrier[1].Transition.pResource = aliasCopy.Get();\n        aliasBarrier[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;\n        aliasBarrier[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;\n\n        aliasBarrier[2].Transition.pResource = resource;\n        aliasBarrier[2].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;\n        aliasBarrier[2].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;\n\n        mList->ResourceBarrier(3, aliasBarrier);\n\n        // Copy the entire resource back\n        mList->CopyResource(resource, aliasCopy.Get());\n        TransitionResource(mList.Get(), resource, D3D12_RESOURCE_STATE_COPY_DEST, originalState);\n\n        // Track these object lifetimes on the GPU\n        mTrackedObjects.push_back(heap);\n        mTrackedObjects.push_back(resourceCopy);\n        mTrackedObjects.push_back(aliasCopy);\n        mTrackedObjects.push_back(resource);\n    }\n\n    struct UploadBatch\n    {\n        std::vector<ComPtr<ID3D12DeviceChild>>  TrackedObjects;\n        std::vector<SharedGraphicsResource>     TrackedMemoryResources;\n        ComPtr<ID3D12GraphicsCommandList>       CommandList;\n        ComPtr<ID3D12Fence>  \t\t\t        Fence;\n        HANDLE                                  GpuCompleteEvent;\n\n        UploadBatch() noexcept : GpuCompleteEvent(nullptr) {}\n    };\n\n    ComPtr<ID3D12Device>                        mDevice;\n    ComPtr<ID3D12CommandAllocator>              mCmdAlloc;\n    ComPtr<ID3D12GraphicsCommandList>           mList;\n    std::unique_ptr<GenerateMipsResources>      mGenMipsResources;\n\n    std::vector<ComPtr<ID3D12DeviceChild>>      mTrackedObjects;\n    std::vector<SharedGraphicsResource>         mTrackedMemoryResources;\n\n    D3D12_COMMAND_LIST_TYPE                     mCommandType;\n    bool                                        mInBeginEndBlock;\n    bool                                        mTypedUAVLoadAdditionalFormats;\n    bool                                        mStandardSwizzle64KBSupported;\n};\n\n\n\n// Public constructor.\nResourceUploadBatch::ResourceUploadBatch(_In_ ID3D12Device* device) noexcept(false)\n    : pImpl(std::make_unique<Impl>(device))\n{\n}\n\n\n// Public destructor.\nResourceUploadBatch::~ResourceUploadBatch()\n{\n}\n\n\n// Move constructor.\nResourceUploadBatch::ResourceUploadBatch(ResourceUploadBatch&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nResourceUploadBatch& ResourceUploadBatch::operator= (ResourceUploadBatch&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\nvoid ResourceUploadBatch::Begin(D3D12_COMMAND_LIST_TYPE commandType)\n{\n    pImpl->Begin(commandType);\n}\n\n\n_Use_decl_annotations_\nvoid ResourceUploadBatch::Upload(\n    ID3D12Resource* resource,\n    uint32_t subresourceIndexStart,\n    const D3D12_SUBRESOURCE_DATA* subRes,\n    uint32_t numSubresources)\n{\n    pImpl->Upload(resource, subresourceIndexStart, subRes, numSubresources);\n}\n\n\n_Use_decl_annotations_\nvoid ResourceUploadBatch::Upload(\n    ID3D12Resource* resource,\n    const SharedGraphicsResource& buffer\n)\n{\n    pImpl->Upload(resource, buffer);\n}\n\n\n\nvoid ResourceUploadBatch::GenerateMips(_In_ ID3D12Resource* resource)\n{\n    pImpl->GenerateMips(resource);\n}\n\n\n_Use_decl_annotations_\nvoid ResourceUploadBatch::Transition(\n    ID3D12Resource* resource,\n    D3D12_RESOURCE_STATES stateBefore,\n    D3D12_RESOURCE_STATES stateAfter)\n{\n    pImpl->Transition(resource, stateBefore, stateAfter);\n}\n\n\nstd::future<void> ResourceUploadBatch::End(_In_ ID3D12CommandQueue* commandQueue)\n{\n    return pImpl->End(commandQueue);\n}\n\n\nbool __cdecl ResourceUploadBatch::IsSupportedForGenerateMips(DXGI_FORMAT format) noexcept\n{\n    return pImpl->IsSupportedForGenerateMips(format);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/SDKMesh.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: SDKMesh.h\n//\n// SDKMESH format is generated by the legacy DirectX SDK's Content Exporter and\n// originally rendered by the DXUT helper class SDKMesh\n//\n// http://go.microsoft.com/fwlink/?LinkId=226208\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <cstdint>\n\nnamespace DXUT\n{\n    // .SDKMESH files\n\n    // SDKMESH_HEADER\n    // SDKMESH_VERTEX_BUFFER_HEADER header->VertexStreamHeadersOffset\n    // SDKMESH_INDEX_BUFFER_HEADER  header->IndexStreamHeadersOffset\n    // SDKMESH_MESH                 header->MeshDataOffset\n    // SDKMESH_SUBSET               header->SubsetDataOffset\n    // SDKMESH_FRAME                header->FrameDataOffset\n    // SDKMESH_MATERIAL             header->MaterialDataOffset\n    // [header->NonBufferDataSize]\n    // { [ header->NumVertexBuffers]\n    //      VB data\n    // }\n    // { [ header->NumIndexBuffers]\n    //      IB data\n    // }\n\n\n    // .SDDKANIM files\n\n    // SDKANIMATION_FILE_HEADER\n    // uint8_t[] - Length of fileheader->AnimationDataSize\n\n    // .SDKMESH uses Direct3D 9 decls, but only a subset of these is ever generated by the legacy DirectX SDK Content Exporter\n\n    // D3DDECLUSAGE_POSITION / D3DDECLTYPE_FLOAT3\n    // (D3DDECLUSAGE_BLENDWEIGHT / D3DDECLTYPE_UBYTE4N\n    // D3DDECLUSAGE_BLENDINDICES / D3DDECLTYPE_UBYTE4)?\n    // (D3DDECLUSAGE_NORMAL / D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOAT16_4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_UBYTE4N, or D3DDECLTYPE_DEC3N)?\n    // (D3DDECLUSAGE_COLOR / D3DDECLTYPE_D3DCOLOR)?\n    // (D3DDECLUSAGE_TEXCOORD / D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2 or D3DDECLTYPE_FLOAT16_2, D3DDECLTYPE_FLOAT3 or D3DDECLTYPE_FLOAT16_4, D3DDECLTYPE_FLOAT4 or D3DDECLTYPE_FLOAT16_4)*\n    // (D3DDECLUSAGE_TANGENT / same as D3DDECLUSAGE_NORMAL)?\n    // (D3DDECLUSAGE_BINORMAL / same as D3DDECLUSAGE_NORMAL)?\n\n    enum D3DDECLUSAGE\n    {\n        D3DDECLUSAGE_POSITION = 0,\n        D3DDECLUSAGE_BLENDWEIGHT =1,\n        D3DDECLUSAGE_BLENDINDICES =2,\n        D3DDECLUSAGE_NORMAL =3,\n        D3DDECLUSAGE_TEXCOORD = 5,\n        D3DDECLUSAGE_TANGENT = 6,\n        D3DDECLUSAGE_BINORMAL = 7,\n        D3DDECLUSAGE_COLOR = 10,\n    };\n\n    enum D3DDECLTYPE\n    {\n        D3DDECLTYPE_FLOAT1    =  0,  // 1D float expanded to (value, 0., 0., 1.)\n        D3DDECLTYPE_FLOAT2    =  1,  // 2D float expanded to (value, value, 0., 1.)\n        D3DDECLTYPE_FLOAT3    =  2,  // 3D float expanded to (value, value, value, 1.)\n        D3DDECLTYPE_FLOAT4    =  3,  // 4D float\n        D3DDECLTYPE_D3DCOLOR  =  4,  // 4D packed unsigned bytes mapped to 0. to 1. range\n                                     // Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A)\n        D3DDECLTYPE_UBYTE4    =  5,  // 4D unsigned uint8_t\n        D3DDECLTYPE_UBYTE4N   =  8,  // Each of 4 bytes is normalized by dividing to 255.0\n        D3DDECLTYPE_SHORT4N   = 10,  // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)\n        D3DDECLTYPE_DEC3N     = 14,  // 3D signed normalized (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1.)\n                                     // Note: There is no equivalent to D3DDECLTYPE_DEC3N (14) as a DXGI_FORMAT\n        D3DDECLTYPE_FLOAT16_2 = 15,  // Two 16-bit floating point values, expanded to (value, value, 0, 1)\n        D3DDECLTYPE_FLOAT16_4 = 16,  // Four 16-bit floating point values\n\n        D3DDECLTYPE_UNUSED    = 17,  // When the type field in a decl is unused.\n\n        // These are extensions for DXGI-based versions of Direct3D\n        D3DDECLTYPE_DXGI_R10G10B10A2_UNORM = 32 + DXGI_FORMAT_R10G10B10A2_UNORM,\n        D3DDECLTYPE_DXGI_R11G11B10_FLOAT   = 32 + DXGI_FORMAT_R11G11B10_FLOAT,\n        D3DDECLTYPE_DXGI_R8G8B8A8_SNORM    = 32 + DXGI_FORMAT_R8G8B8A8_SNORM,\n    };\n\n    #pragma pack(push,4)\n\n    struct D3DVERTEXELEMENT9\n    {\n        uint16_t Stream;     // Stream index\n        uint16_t Offset;     // Offset in the stream in bytes\n        uint8_t  Type;       // Data type\n        uint8_t  Method;     // Processing method\n        uint8_t  Usage;      // Semantics\n        uint8_t  UsageIndex; // Semantic index\n    };\n\n    #pragma pack(pop)\n\n    //--------------------------------------------------------------------------------------\n    // Hard Defines for the various structures\n    //--------------------------------------------------------------------------------------\n    constexpr uint32_t SDKMESH_FILE_VERSION = 101;\n    constexpr uint32_t SDKMESH_FILE_VERSION_V2 = 200;\n\n    constexpr uint32_t MAX_VERTEX_ELEMENTS = 32;\n    constexpr uint32_t MAX_VERTEX_STREAMS = 16;\n    constexpr uint32_t MAX_FRAME_NAME = 100;\n    constexpr uint32_t MAX_MESH_NAME = 100;\n    constexpr uint32_t MAX_SUBSET_NAME = 100;\n    constexpr uint32_t MAX_MATERIAL_NAME = 100;\n    constexpr uint32_t MAX_TEXTURE_NAME = MAX_PATH;\n    constexpr uint32_t MAX_MATERIAL_PATH = MAX_PATH;\n    constexpr uint32_t INVALID_FRAME = uint32_t(-1);\n    constexpr uint32_t INVALID_MESH =  uint32_t(-1);\n    constexpr uint32_t INVALID_MATERIAL = uint32_t(-1);\n    constexpr uint32_t INVALID_SUBSET = uint32_t(-1);\n    constexpr uint32_t INVALID_ANIMATION_DATA = uint32_t(-1);\n\n    //--------------------------------------------------------------------------------------\n    // Enumerated Types.\n    //--------------------------------------------------------------------------------------\n    enum SDKMESH_PRIMITIVE_TYPE\n    {\n        PT_TRIANGLE_LIST = 0,\n        PT_TRIANGLE_STRIP,\n        PT_LINE_LIST,\n        PT_LINE_STRIP,\n        PT_POINT_LIST,\n        PT_TRIANGLE_LIST_ADJ,\n        PT_TRIANGLE_STRIP_ADJ,\n        PT_LINE_LIST_ADJ,\n        PT_LINE_STRIP_ADJ,\n        PT_QUAD_PATCH_LIST,\n        PT_TRIANGLE_PATCH_LIST,\n    };\n\n    enum SDKMESH_INDEX_TYPE\n    {\n        IT_16BIT = 0,\n        IT_32BIT,\n    };\n\n    enum FRAME_TRANSFORM_TYPE\n    {\n        FTT_RELATIVE = 0,\n        FTT_ABSOLUTE,\t\t//This is not currently used but is here to support absolute transformations in the future\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Structures.\n    //--------------------------------------------------------------------------------------\n    #pragma pack(push,8)\n\n    struct SDKMESH_HEADER\n    {\n        //Basic Info and sizes\n        uint32_t Version;\n        uint8_t  IsBigEndian;\n        uint64_t HeaderSize;\n        uint64_t NonBufferDataSize;\n        uint64_t BufferDataSize;\n\n        //Stats\n        uint32_t NumVertexBuffers;\n        uint32_t NumIndexBuffers;\n        uint32_t NumMeshes;\n        uint32_t NumTotalSubsets;\n        uint32_t NumFrames;\n        uint32_t NumMaterials;\n\n        //Offsets to Data\n        uint64_t VertexStreamHeadersOffset;\n        uint64_t IndexStreamHeadersOffset;\n        uint64_t MeshDataOffset;\n        uint64_t SubsetDataOffset;\n        uint64_t FrameDataOffset;\n        uint64_t MaterialDataOffset;\n    };\n\n    struct SDKMESH_VERTEX_BUFFER_HEADER\n    {\n        uint64_t NumVertices;\n        uint64_t SizeBytes;\n        uint64_t StrideBytes;\n        D3DVERTEXELEMENT9 Decl[MAX_VERTEX_ELEMENTS];\n        uint64_t DataOffset;\n    };\n\n    struct SDKMESH_INDEX_BUFFER_HEADER\n    {\n        uint64_t NumIndices;\n        uint64_t SizeBytes;\n        uint32_t IndexType;\n        uint64_t DataOffset;\n    };\n\n    struct SDKMESH_MESH\n    {\n        char Name[MAX_MESH_NAME];\n        uint8_t NumVertexBuffers;\n        uint32_t VertexBuffers[MAX_VERTEX_STREAMS];\n        uint32_t IndexBuffer;\n        uint32_t NumSubsets;\n        uint32_t NumFrameInfluences; //aka bones\n\n        DirectX::XMFLOAT3 BoundingBoxCenter;\n        DirectX::XMFLOAT3 BoundingBoxExtents;\n\n        union\n        {\n            uint64_t SubsetOffset;\n            INT* pSubsets;\n        };\n        union\n        {\n            uint64_t FrameInfluenceOffset;\n            uint32_t* pFrameInfluences;\n        };\n    };\n\n    struct SDKMESH_SUBSET\n    {\n        char Name[MAX_SUBSET_NAME];\n        uint32_t MaterialID;\n        uint32_t PrimitiveType;\n        uint64_t IndexStart;\n        uint64_t IndexCount;\n        uint64_t VertexStart;\n        uint64_t VertexCount;\n    };\n\n    struct SDKMESH_FRAME\n    {\n        char Name[MAX_FRAME_NAME];\n        uint32_t Mesh;\n        uint32_t ParentFrame;\n        uint32_t ChildFrame;\n        uint32_t SiblingFrame;\n        DirectX::XMFLOAT4X4 Matrix;\n        uint32_t AnimationDataIndex;\t\t//Used to index which set of keyframes transforms this frame\n    };\n\n    struct SDKMESH_MATERIAL\n    {\n        char    Name[MAX_MATERIAL_NAME];\n\n        // Use MaterialInstancePath\n        char    MaterialInstancePath[MAX_MATERIAL_PATH];\n\n        // Or fall back to d3d8-type materials\n        char    DiffuseTexture[MAX_TEXTURE_NAME];\n        char    NormalTexture[MAX_TEXTURE_NAME];\n        char    SpecularTexture[MAX_TEXTURE_NAME];\n\n        DirectX::XMFLOAT4 Diffuse;\n        DirectX::XMFLOAT4 Ambient;\n        DirectX::XMFLOAT4 Specular;\n        DirectX::XMFLOAT4 Emissive;\n        float Power;\n\n        uint64_t Force64_1;\n        uint64_t Force64_2;\n        uint64_t Force64_3;\n        uint64_t Force64_4;\n        uint64_t Force64_5;\n        uint64_t Force64_6;\n    };\n\n    struct SDKMESH_MATERIAL_V2\n    {\n        char    Name[MAX_MATERIAL_NAME];\n\n        // PBR materials\n        char    RMATexture[MAX_TEXTURE_NAME];\n        char    AlbetoTexture[MAX_TEXTURE_NAME];\n        char    NormalTexture[MAX_TEXTURE_NAME];\n        char    EmissiveTexture[MAX_TEXTURE_NAME];\n\n        float   Alpha;\n\n        char    Reserved[60];\n\n        uint64_t Force64_1;\n        uint64_t Force64_2;\n        uint64_t Force64_3;\n        uint64_t Force64_4;\n        uint64_t Force64_5;\n        uint64_t Force64_6;\n    };\n\n    struct SDKANIMATION_FILE_HEADER\n    {\n        uint32_t Version;\n        uint8_t  IsBigEndian;\n        uint32_t FrameTransformType;\n        uint32_t NumFrames;\n        uint32_t NumAnimationKeys;\n        uint32_t AnimationFPS;\n        uint64_t AnimationDataSize;\n        uint64_t AnimationDataOffset;\n    };\n\n    struct SDKANIMATION_DATA\n    {\n        DirectX::XMFLOAT3 Translation;\n        DirectX::XMFLOAT4 Orientation;\n        DirectX::XMFLOAT3 Scaling;\n    };\n\n    struct SDKANIMATION_FRAME_DATA\n    {\n        char FrameName[MAX_FRAME_NAME];\n        uint64_t DataOffset;\n    };\n\n    #pragma pack(pop)\n\n} // namespace\n\nstatic_assert( sizeof(DXUT::D3DVERTEXELEMENT9) == 8, \"Direct3D9 Decl structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_HEADER)== 104, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER) == 288, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER) == 32, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_MESH) == 224, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_SUBSET) == 144, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_FRAME) == 184, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_MATERIAL) == 1256, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKMESH_MATERIAL_V2) == sizeof(DXUT::SDKMESH_MATERIAL), \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKANIMATION_FILE_HEADER) == 40, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKANIMATION_DATA) == 40, \"SDK Mesh structure size incorrect\" );\nstatic_assert( sizeof(DXUT::SDKANIMATION_FRAME_DATA) == 112, \"SDK Mesh structure size incorrect\" );\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/ScreenGrab.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: ScreenGrab.cpp\n//\n// Function for capturing a 2D texture and saving it to a file (aka a 'screenshot'\n// when used on a Direct3D Render Target).\n//\n// Note these functions are useful as a light-weight runtime screen grabber. For\n// full-featured texture capture, DDS writer, and texture processing pipeline,\n// see the 'Texconv' sample and the 'DirectXTex' library.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n// Does not capture 1D textures or 3D textures (volume maps)\n\n// Does not capture mipmap chains, only the top-most texture level is saved\n\n// For 2D array textures and cubemaps, it captures only the first image in the array\n\n#include \"pch.h\"\n\n#include \"ScreenGrab.h\"\n#include \"DirectXHelpers.h\"\n\n#include \"PlatformHelpers.h\"\n#include \"DDS.h\"\n#include \"LoaderHelpers.h\"\n\nusing Microsoft::WRL::ComPtr;\nusing namespace DirectX;\nusing namespace DirectX::LoaderHelpers;\n\nnamespace\n{\n    //--------------------------------------------------------------------------------------\n    HRESULT CaptureTexture(_In_ ID3D12Device* device,\n        _In_ ID3D12CommandQueue* pCommandQ,\n        _In_ ID3D12Resource* pSource,\n        UINT64 srcPitch,\n        const D3D12_RESOURCE_DESC& desc,\n        ComPtr<ID3D12Resource>& pStaging,\n        D3D12_RESOURCE_STATES beforeState,\n        D3D12_RESOURCE_STATES afterState) noexcept\n    {\n        if (!pCommandQ || !pSource)\n            return E_INVALIDARG;\n\n        if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)\n        {\n            DebugTrace(\"ERROR: ScreenGrab does not support 1D or volume textures. Consider using DirectXTex instead.\\n\");\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        if (desc.DepthOrArraySize > 1 || desc.MipLevels > 1)\n        {\n            DebugTrace(\"WARNING: ScreenGrab does not support 2D arrays, cubemaps, or mipmaps; only the first surface is written. Consider using DirectXTex instead.\\n\");\n        }\n\n        if (srcPitch > UINT32_MAX)\n            return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n        UINT numberOfPlanes = D3D12GetFormatPlaneCount(device, desc.Format);\n        if (numberOfPlanes != 1)\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n        D3D12_HEAP_PROPERTIES sourceHeapProperties;\n        D3D12_HEAP_FLAGS sourceHeapFlags;\n        HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags);\n        if (FAILED(hr))\n            return hr;\n\n        if (sourceHeapProperties.Type == D3D12_HEAP_TYPE_READBACK)\n        {\n            // Handle case where the source is already a staging texture we can use directly\n            pStaging = pSource;\n            return S_OK;\n        }\n\n        // Create a command allocator\n        ComPtr<ID3D12CommandAllocator> commandAlloc;\n        hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(commandAlloc.GetAddressOf()));\n        if (FAILED(hr))\n            return hr;\n\n        SetDebugObjectName(commandAlloc.Get(), L\"ScreenGrab\");\n\n        // Spin up a new command list\n        ComPtr<ID3D12GraphicsCommandList> commandList;\n        hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAlloc.Get(), nullptr, IID_GRAPHICS_PPV_ARGS(commandList.GetAddressOf()));\n        if (FAILED(hr))\n            return hr;\n\n        SetDebugObjectName(commandList.Get(), L\"ScreenGrab\");\n\n        // Create a fence\n        ComPtr<ID3D12Fence> fence;\n        hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(fence.GetAddressOf()));\n        if (FAILED(hr))\n            return hr;\n\n        SetDebugObjectName(fence.Get(), L\"ScreenGrab\");\n\n        assert((srcPitch & 0xFF) == 0);\n\n        CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n        CD3DX12_HEAP_PROPERTIES readBackHeapProperties(D3D12_HEAP_TYPE_READBACK);\n\n        // Readback resources must be buffers\n        D3D12_RESOURCE_DESC bufferDesc = {};\n        bufferDesc.DepthOrArraySize = 1;\n        bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n        bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;\n        bufferDesc.Format = DXGI_FORMAT_UNKNOWN;\n        bufferDesc.Height = 1;\n        bufferDesc.Width = srcPitch * desc.Height;\n        bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n        bufferDesc.MipLevels = 1;\n        bufferDesc.SampleDesc.Count = 1;\n\n        ComPtr<ID3D12Resource> copySource(pSource);\n        if (desc.SampleDesc.Count > 1)\n        {\n            // MSAA content must be resolved before being copied to a staging texture\n            auto descCopy = desc;\n            descCopy.SampleDesc.Count = 1;\n            descCopy.SampleDesc.Quality = 0;\n\n            ComPtr<ID3D12Resource> pTemp;\n            hr = device->CreateCommittedResource(\n                &defaultHeapProperties,\n                D3D12_HEAP_FLAG_NONE,\n                &descCopy,\n                D3D12_RESOURCE_STATE_COPY_DEST,\n                nullptr,\n                IID_GRAPHICS_PPV_ARGS(pTemp.GetAddressOf()));\n            if (FAILED(hr))\n                return hr;\n\n            assert(pTemp);\n\n            SetDebugObjectName(pTemp.Get(), L\"ScreenGrab temporary\");\n\n            DXGI_FORMAT fmt = EnsureNotTypeless(desc.Format);\n\n            D3D12_FEATURE_DATA_FORMAT_SUPPORT formatInfo = { fmt, D3D12_FORMAT_SUPPORT1_NONE, D3D12_FORMAT_SUPPORT2_NONE };\n            hr = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &formatInfo, sizeof(formatInfo));\n            if (FAILED(hr))\n                return hr;\n\n            if (!(formatInfo.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))\n                return E_FAIL;\n\n            for (UINT item = 0; item < desc.DepthOrArraySize; ++item)\n            {\n                for (UINT level = 0; level < desc.MipLevels; ++level)\n                {\n                    UINT index = D3D12CalcSubresource(level, item, 0, desc.MipLevels, desc.DepthOrArraySize);\n                    commandList->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt);\n                }\n            }\n\n            copySource = pTemp;\n        }\n\n        // Create a staging texture\n        hr = device->CreateCommittedResource(\n            &readBackHeapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &bufferDesc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(pStaging.ReleaseAndGetAddressOf()));\n        if (FAILED(hr))\n            return hr;\n\n        SetDebugObjectName(pStaging.Get(), L\"ScreenGrab staging\");\n\n        assert(pStaging);\n\n        // Transition the resource if necessary\n        TransitionResource(commandList.Get(), pSource, beforeState, D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n        // Get the copy target location\n        D3D12_PLACED_SUBRESOURCE_FOOTPRINT bufferFootprint = {};\n        bufferFootprint.Footprint.Width = static_cast<UINT>(desc.Width);\n        bufferFootprint.Footprint.Height = desc.Height;\n        bufferFootprint.Footprint.Depth = 1;\n        bufferFootprint.Footprint.RowPitch = static_cast<UINT>(srcPitch);\n        bufferFootprint.Footprint.Format = desc.Format;\n\n        CD3DX12_TEXTURE_COPY_LOCATION copyDest(pStaging.Get(), bufferFootprint);\n        CD3DX12_TEXTURE_COPY_LOCATION copySrc(copySource.Get(), 0);\n\n        // Copy the texture\n        commandList->CopyTextureRegion(&copyDest, 0, 0, 0, &copySrc, nullptr);\n\n        // Transition the resource to the next state\n        TransitionResource(commandList.Get(), pSource, D3D12_RESOURCE_STATE_COPY_SOURCE, afterState);\n\n        hr = commandList->Close();\n        if (FAILED(hr))\n            return hr;\n\n        // Execute the command list\n        pCommandQ->ExecuteCommandLists(1, CommandListCast(commandList.GetAddressOf()));\n\n        // Signal the fence\n        hr = pCommandQ->Signal(fence.Get(), 1);\n        if (FAILED(hr))\n            return hr;\n\n        // Block until the copy is complete\n        while (fence->GetCompletedValue() < 1)\n            SwitchToThread();\n\n        return S_OK;\n    }\n} // anonymous namespace\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::SaveDDSTextureToFile(\n    ID3D12CommandQueue* pCommandQ,\n    ID3D12Resource* pSource,\n    const wchar_t* fileName,\n    D3D12_RESOURCE_STATES beforeState,\n    D3D12_RESOURCE_STATES afterState) noexcept\n{\n    if (!fileName)\n        return E_INVALIDARG;\n\n    ComPtr<ID3D12Device> device;\n    pCommandQ->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()));\n\n    // Get the size of the image\n    const auto desc = pSource->GetDesc();\n\n    if (desc.Width > UINT32_MAX)\n        return E_INVALIDARG;\n\n    UINT64 totalResourceSize = 0;\n    UINT64 fpRowPitch = 0;\n    UINT fpRowCount = 0;\n    // Get the rowcount, pitch and size of the top mip\n    device->GetCopyableFootprints(\n        &desc,\n        0,\n        1,\n        0,\n        nullptr,\n        &fpRowCount,\n        &fpRowPitch,\n        &totalResourceSize);\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    // Round up the srcPitch to multiples of 1024\n    UINT64 dstRowPitch = (fpRowPitch + static_cast<uint64_t>(D3D12XBOX_TEXTURE_DATA_PITCH_ALIGNMENT) - 1u) & ~(static_cast<uint64_t>(D3D12XBOX_TEXTURE_DATA_PITCH_ALIGNMENT) - 1u);\n#else\n    // Round up the srcPitch to multiples of 256\n    UINT64 dstRowPitch = (fpRowPitch + 255) & ~0xFFu;\n#endif\n\n    if (dstRowPitch > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n    ComPtr<ID3D12Resource> pStaging;\n    HRESULT hr = CaptureTexture(device.Get(), pCommandQ, pSource, dstRowPitch, desc, pStaging, beforeState, afterState);\n    if (FAILED(hr))\n        return hr;\n\n    // Create file\n    ScopedHandle hFile(safe_handle(CreateFile2(fileName, GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr)));\n    if (!hFile)\n        return HRESULT_FROM_WIN32(GetLastError());\n\n    auto_delete_file delonfail(hFile.get());\n\n    // Setup header\n    const size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);\n    uint8_t fileHeader[MAX_HEADER_SIZE] = {};\n\n    *reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC;\n\n    auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t));\n    size_t headerSize = sizeof(uint32_t) + sizeof(DDS_HEADER);\n    header->size = sizeof(DDS_HEADER);\n    header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;\n    header->height = desc.Height;\n    header->width = static_cast<uint32_t>(desc.Width);\n    header->mipMapCount = 1;\n    header->caps = DDS_SURFACE_FLAGS_TEXTURE;\n\n    // Try to use a legacy .DDS pixel format for better tools support, otherwise fallback to 'DX10' header extension\n    DDS_HEADER_DXT10* extHeader = nullptr;\n    switch (desc.Format)\n    {\n        case DXGI_FORMAT_R8G8B8A8_UNORM:        memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT));    break;\n        case DXGI_FORMAT_R16G16_UNORM:          memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT));      break;\n        case DXGI_FORMAT_R8G8_UNORM:            memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT));        break;\n        case DXGI_FORMAT_R16_UNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_L16, sizeof(DDS_PIXELFORMAT));         break;\n        case DXGI_FORMAT_R8_UNORM:              memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_L8, sizeof(DDS_PIXELFORMAT));          break;\n        case DXGI_FORMAT_A8_UNORM:              memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8, sizeof(DDS_PIXELFORMAT));          break;\n        case DXGI_FORMAT_R8G8_B8G8_UNORM:       memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT));   break;\n        case DXGI_FORMAT_G8R8_G8B8_UNORM:       memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT));   break;\n        case DXGI_FORMAT_BC1_UNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT));        break;\n        case DXGI_FORMAT_BC2_UNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DXT3, sizeof(DDS_PIXELFORMAT));        break;\n        case DXGI_FORMAT_BC3_UNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DXT5, sizeof(DDS_PIXELFORMAT));        break;\n        case DXGI_FORMAT_BC4_UNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT));   break;\n        case DXGI_FORMAT_BC4_SNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT));   break;\n        case DXGI_FORMAT_BC5_UNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT));   break;\n        case DXGI_FORMAT_BC5_SNORM:             memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT));   break;\n        case DXGI_FORMAT_B5G6R5_UNORM:          memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT));      break;\n        case DXGI_FORMAT_B5G5R5A1_UNORM:        memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT));    break;\n        case DXGI_FORMAT_R8G8_SNORM:            memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_V8U8, sizeof(DDS_PIXELFORMAT));        break;\n        case DXGI_FORMAT_R8G8B8A8_SNORM:        memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_Q8W8V8U8, sizeof(DDS_PIXELFORMAT));    break;\n        case DXGI_FORMAT_R16G16_SNORM:          memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_V16U16, sizeof(DDS_PIXELFORMAT));      break;\n        case DXGI_FORMAT_B8G8R8A8_UNORM:        memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT));    break;\n        case DXGI_FORMAT_B8G8R8X8_UNORM:        memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT));    break;\n        case DXGI_FORMAT_YUY2:                  memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT));        break;\n        case DXGI_FORMAT_B4G4R4A4_UNORM:        memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT));    break;\n\n            // Legacy D3DX formats using D3DFMT enum value as FourCC\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:    header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 116; break; // D3DFMT_A32B32G32R32F\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:    header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 113; break; // D3DFMT_A16B16G16R16F\n        case DXGI_FORMAT_R16G16B16A16_UNORM:    header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 36;  break; // D3DFMT_A16B16G16R16\n        case DXGI_FORMAT_R16G16B16A16_SNORM:    header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 110; break; // D3DFMT_Q16W16V16U16\n        case DXGI_FORMAT_R32G32_FLOAT:          header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 115; break; // D3DFMT_G32R32F\n        case DXGI_FORMAT_R16G16_FLOAT:          header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 112; break; // D3DFMT_G16R16F\n        case DXGI_FORMAT_R32_FLOAT:             header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 114; break; // D3DFMT_R32F\n        case DXGI_FORMAT_R16_FLOAT:             header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 111; break; // D3DFMT_R16F\n\n        case DXGI_FORMAT_AI44:\n        case DXGI_FORMAT_IA44:\n        case DXGI_FORMAT_P8:\n        case DXGI_FORMAT_A8P8:\n            DebugTrace(\"ERROR: ScreenGrab does not support video textures. Consider using DirectXTex.\\n\");\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n\n        default:\n            memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT));\n\n            headerSize += sizeof(DDS_HEADER_DXT10);\n            extHeader = reinterpret_cast<DDS_HEADER_DXT10*>(fileHeader + sizeof(uint32_t) + sizeof(DDS_HEADER));\n            extHeader->dxgiFormat = desc.Format;\n            extHeader->resourceDimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n            extHeader->arraySize = 1;\n            break;\n    }\n\n    size_t rowPitch, slicePitch, rowCount;\n    hr = GetSurfaceInfo(static_cast<size_t>(desc.Width), desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount);\n    if (FAILED(hr))\n        return hr;\n\n    if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n    if (IsCompressed(desc.Format))\n    {\n        header->flags |= DDS_HEADER_FLAGS_LINEARSIZE;\n        header->pitchOrLinearSize = static_cast<uint32_t>(slicePitch);\n    }\n    else\n    {\n        header->flags |= DDS_HEADER_FLAGS_PITCH;\n        header->pitchOrLinearSize = static_cast<uint32_t>(rowPitch);\n    }\n\n    // Setup pixels\n    std::unique_ptr<uint8_t[]> pixels(new (std::nothrow) uint8_t[slicePitch]);\n    if (!pixels)\n        return E_OUTOFMEMORY;\n\n    assert(fpRowCount == rowCount);\n    assert(fpRowPitch == rowPitch);\n\n    UINT64 imageSize = dstRowPitch * UINT64(rowCount);\n    if (imageSize > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n    void* pMappedMemory = nullptr;\n    D3D12_RANGE readRange = { 0, static_cast<SIZE_T>(imageSize) };\n    D3D12_RANGE writeRange = { 0, 0 };\n    hr = pStaging->Map(0, &readRange, &pMappedMemory);\n    if (FAILED(hr))\n        return hr;\n\n    auto sptr = static_cast<const uint8_t*>(pMappedMemory);\n    if (!sptr)\n    {\n        pStaging->Unmap(0, &writeRange);\n        return E_POINTER;\n    }\n\n    uint8_t* dptr = pixels.get();\n\n    size_t msize = std::min<size_t>(rowPitch, size_t(dstRowPitch));\n    for (size_t h = 0; h < rowCount; ++h)\n    {\n        memcpy_s(dptr, rowPitch, sptr, msize);\n        sptr += dstRowPitch;\n        dptr += rowPitch;\n    }\n\n    pStaging->Unmap(0, &writeRange);\n\n    // Write header & pixels\n    DWORD bytesWritten;\n    if (!WriteFile(hFile.get(), fileHeader, static_cast<DWORD>(headerSize), &bytesWritten, nullptr))\n        return HRESULT_FROM_WIN32(GetLastError());\n\n    if (bytesWritten != headerSize)\n        return E_FAIL;\n\n    if (!WriteFile(hFile.get(), pixels.get(), static_cast<DWORD>(slicePitch), &bytesWritten, nullptr))\n        return HRESULT_FROM_WIN32(GetLastError());\n\n    if (bytesWritten != slicePitch)\n        return E_FAIL;\n\n    delonfail.clear();\n\n    return S_OK;\n}\n\n//--------------------------------------------------------------------------------------\nnamespace DirectX\n{\n    extern IWICImagingFactory2* _GetWIC() noexcept;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::SaveWICTextureToFile(\n    ID3D12CommandQueue* pCommandQ,\n    ID3D12Resource* pSource,\n    REFGUID guidContainerFormat,\n    const wchar_t* fileName,\n    D3D12_RESOURCE_STATES beforeState,\n    D3D12_RESOURCE_STATES afterState,\n    const GUID* targetFormat,\n    std::function<void(IPropertyBag2*)> setCustomProps,\n    bool forceSRGB)\n{\n    if (!fileName)\n        return E_INVALIDARG;\n\n    ComPtr<ID3D12Device> device;\n    pCommandQ->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()));\n\n    // Get the size of the image\n    const auto desc = pSource->GetDesc();\n\n    if (desc.Width > UINT32_MAX)\n        return E_INVALIDARG;\n\n    UINT64 totalResourceSize = 0;\n    UINT64 fpRowPitch = 0;\n    UINT fpRowCount = 0;\n    // Get the rowcount, pitch and size of the top mip\n    device->GetCopyableFootprints(\n        &desc,\n        0,\n        1,\n        0,\n        nullptr,\n        &fpRowCount,\n        &fpRowPitch,\n        &totalResourceSize);\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    // Round up the srcPitch to multiples of 1024\n    UINT64 dstRowPitch = (fpRowPitch + static_cast<uint64_t>(D3D12XBOX_TEXTURE_DATA_PITCH_ALIGNMENT) - 1u) & ~(static_cast<uint64_t>(D3D12XBOX_TEXTURE_DATA_PITCH_ALIGNMENT) - 1u);\n#else\n    // Round up the srcPitch to multiples of 256\n    UINT64 dstRowPitch = (fpRowPitch + 255) & ~0xFFu;\n#endif\n\n    if (dstRowPitch > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n    ComPtr<ID3D12Resource> pStaging;\n    HRESULT hr = CaptureTexture(device.Get(), pCommandQ, pSource, dstRowPitch, desc, pStaging, beforeState, afterState);\n    if (FAILED(hr))\n        return hr;\n\n    // Determine source format's WIC equivalent\n    WICPixelFormatGUID pfGuid = {};\n    bool sRGB = forceSRGB;\n    switch (desc.Format)\n    {\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:            pfGuid = GUID_WICPixelFormat128bppRGBAFloat; break;\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:            pfGuid = GUID_WICPixelFormat64bppRGBAHalf; break;\n        case DXGI_FORMAT_R16G16B16A16_UNORM:            pfGuid = GUID_WICPixelFormat64bppRGBA; break;\n        case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:    pfGuid = GUID_WICPixelFormat32bppRGBA1010102XR; break;\n        case DXGI_FORMAT_R10G10B10A2_UNORM:             pfGuid = GUID_WICPixelFormat32bppRGBA1010102; break;\n        case DXGI_FORMAT_B5G5R5A1_UNORM:                pfGuid = GUID_WICPixelFormat16bppBGRA5551; break;\n        case DXGI_FORMAT_B5G6R5_UNORM:                  pfGuid = GUID_WICPixelFormat16bppBGR565; break;\n        case DXGI_FORMAT_R32_FLOAT:                     pfGuid = GUID_WICPixelFormat32bppGrayFloat; break;\n        case DXGI_FORMAT_R16_FLOAT:                     pfGuid = GUID_WICPixelFormat16bppGrayHalf; break;\n        case DXGI_FORMAT_R16_UNORM:                     pfGuid = GUID_WICPixelFormat16bppGray; break;\n        case DXGI_FORMAT_R8_UNORM:                      pfGuid = GUID_WICPixelFormat8bppGray; break;\n        case DXGI_FORMAT_A8_UNORM:                      pfGuid = GUID_WICPixelFormat8bppAlpha; break;\n\n        case DXGI_FORMAT_R8G8B8A8_UNORM:\n            pfGuid = GUID_WICPixelFormat32bppRGBA;\n            break;\n\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n            pfGuid = GUID_WICPixelFormat32bppRGBA;\n            sRGB = true;\n            break;\n\n        case DXGI_FORMAT_B8G8R8A8_UNORM:\n            pfGuid = GUID_WICPixelFormat32bppBGRA;\n            break;\n\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n            pfGuid = GUID_WICPixelFormat32bppBGRA;\n            sRGB = true;\n            break;\n\n        case DXGI_FORMAT_B8G8R8X8_UNORM:\n            pfGuid = GUID_WICPixelFormat32bppBGR;\n            break;\n\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            pfGuid = GUID_WICPixelFormat32bppBGR;\n            sRGB = true;\n            break;\n\n        default:\n            DebugTrace(\"ERROR: ScreenGrab does not support all DXGI formats (%u). Consider using DirectXTex.\\n\", static_cast<uint32_t>(desc.Format));\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n    }\n\n    auto pWIC = _GetWIC();\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    ComPtr<IWICStream> stream;\n    hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromFilename(fileName, GENERIC_WRITE);\n    if (FAILED(hr))\n        return hr;\n\n    auto_delete_file_wic delonfail(stream, fileName);\n\n    ComPtr<IWICBitmapEncoder> encoder;\n    hr = pWIC->CreateEncoder(guidContainerFormat, nullptr, encoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache);\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameEncode> frame;\n    ComPtr<IPropertyBag2> props;\n    hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    if (targetFormat && memcmp(&guidContainerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID)) == 0)\n    {\n        // Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel\n        PROPBAG2 option = {};\n        option.pstrName = const_cast<wchar_t*>(L\"EnableV5Header32bppBGRA\");\n\n        VARIANT varValue;\n        varValue.vt = VT_BOOL;\n        varValue.boolVal = VARIANT_TRUE;\n        (void)props->Write(1, &option, &varValue);\n    }\n\n    if (setCustomProps)\n    {\n        setCustomProps(props.Get());\n    }\n\n    hr = frame->Initialize(props.Get());\n    if (FAILED(hr))\n        return hr;\n\n    hr = frame->SetSize(static_cast<UINT>(desc.Width), desc.Height);\n    if (FAILED(hr))\n        return hr;\n\n    hr = frame->SetResolution(72, 72);\n    if (FAILED(hr))\n        return hr;\n\n    // Pick a target format\n    WICPixelFormatGUID targetGuid = {};\n    if (targetFormat)\n    {\n        targetGuid = *targetFormat;\n    }\n    else\n    {\n        // Screenshots don't typically include the alpha channel of the render target\n        switch (desc.Format)\n        {\n            case DXGI_FORMAT_R32G32B32A32_FLOAT:\n            case DXGI_FORMAT_R16G16B16A16_FLOAT:\n                targetGuid = GUID_WICPixelFormat96bppRGBFloat; // WIC 2\n                break;\n\n            case DXGI_FORMAT_R16G16B16A16_UNORM: targetGuid = GUID_WICPixelFormat48bppBGR; break;\n            case DXGI_FORMAT_B5G5R5A1_UNORM:     targetGuid = GUID_WICPixelFormat16bppBGR555; break;\n            case DXGI_FORMAT_B5G6R5_UNORM:       targetGuid = GUID_WICPixelFormat16bppBGR565; break;\n\n            case DXGI_FORMAT_R32_FLOAT:\n            case DXGI_FORMAT_R16_FLOAT:\n            case DXGI_FORMAT_R16_UNORM:\n            case DXGI_FORMAT_R8_UNORM:\n            case DXGI_FORMAT_A8_UNORM:\n                targetGuid = GUID_WICPixelFormat8bppGray;\n                break;\n\n            default:\n                targetGuid = GUID_WICPixelFormat24bppBGR;\n                break;\n        }\n    }\n\n    hr = frame->SetPixelFormat(&targetGuid);\n    if (FAILED(hr))\n        return hr;\n\n    if (targetFormat && memcmp(targetFormat, &targetGuid, sizeof(WICPixelFormatGUID)) != 0)\n    {\n        // Requested output pixel format is not supported by the WIC codec\n        return E_FAIL;\n    }\n\n    // Encode WIC metadata\n    ComPtr<IWICMetadataQueryWriter> metawriter;\n    if (SUCCEEDED(frame->GetMetadataQueryWriter(metawriter.GetAddressOf())))\n    {\n        PROPVARIANT value;\n        PropVariantInit(&value);\n\n        value.vt = VT_LPSTR;\n        value.pszVal = const_cast<char*>(\"DirectXTK\");\n\n        if (memcmp(&guidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0)\n        {\n            // Set Software name\n            (void)metawriter->SetMetadataByName(L\"/tEXt/{str=Software}\", &value);\n\n            // Set sRGB chunk\n            if (sRGB)\n            {\n                value.vt = VT_UI1;\n                value.bVal = 0;\n                (void)metawriter->SetMetadataByName(L\"/sRGB/RenderingIntent\", &value);\n            }\n            else\n            {\n                // add gAMA chunk with gamma 1.0\n                value.vt = VT_UI4;\n                value.uintVal = 100000; // gama value * 100,000 -- i.e. gamma 1.0\n                (void)metawriter->SetMetadataByName(L\"/gAMA/ImageGamma\", &value);\n\n                // remove sRGB chunk which is added by default.\n                (void)metawriter->RemoveMetadataByName(L\"/sRGB/RenderingIntent\");\n            }\n        }\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        else if (memcmp(&guidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)) == 0)\n        {\n            // Set Software name\n            (void)metawriter->SetMetadataByName(L\"/app1/ifd/{ushort=305}\", &value);\n\n            if (sRGB)\n            {\n                // Set EXIF Colorspace of sRGB\n                value.vt = VT_UI2;\n                value.uiVal = 1;\n                (void)metawriter->SetMetadataByName(L\"/app1/ifd/exif/{ushort=40961}\", &value);\n            }\n        }\n        else if (memcmp(&guidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)) == 0)\n        {\n            // Set Software name\n            (void)metawriter->SetMetadataByName(L\"/ifd/{ushort=305}\", &value);\n\n            if (sRGB)\n            {\n                // Set EXIF Colorspace of sRGB\n                value.vt = VT_UI2;\n                value.uiVal = 1;\n                (void)metawriter->SetMetadataByName(L\"/ifd/exif/{ushort=40961}\", &value);\n            }\n        }\n    #else\n        else\n        {\n            // Set Software name\n            (void)metawriter->SetMetadataByName(L\"System.ApplicationName\", &value);\n\n            if (sRGB)\n            {\n                // Set EXIF Colorspace of sRGB\n                value.vt = VT_UI2;\n                value.uiVal = 1;\n                (void)metawriter->SetMetadataByName(L\"System.Image.ColorSpace\", &value);\n            }\n        }\n    #endif\n    }\n\n    UINT64 imageSize = dstRowPitch * UINT64(desc.Height);\n    if (imageSize > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n    void* pMappedMemory = nullptr;\n    D3D12_RANGE readRange = { 0, static_cast<SIZE_T>(imageSize) };\n    D3D12_RANGE writeRange = { 0, 0 };\n    hr = pStaging->Map(0, &readRange, &pMappedMemory);\n    if (FAILED(hr))\n        return hr;\n\n    if (memcmp(&targetGuid, &pfGuid, sizeof(WICPixelFormatGUID)) != 0)\n    {\n        // Conversion required to write\n        ComPtr<IWICBitmap> source;\n        hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(desc.Width), desc.Height,\n            pfGuid,\n            static_cast<UINT>(dstRowPitch), static_cast<UINT>(imageSize),\n            static_cast<BYTE*>(pMappedMemory), source.GetAddressOf());\n        if (FAILED(hr))\n        {\n            pStaging->Unmap(0, &writeRange);\n            return hr;\n        }\n\n        ComPtr<IWICFormatConverter> FC;\n        hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n        if (FAILED(hr))\n        {\n            pStaging->Unmap(0, &writeRange);\n            return hr;\n        }\n\n        BOOL canConvert = FALSE;\n        hr = FC->CanConvert(pfGuid, targetGuid, &canConvert);\n        if (FAILED(hr) || !canConvert)\n        {\n            pStaging->Unmap(0, &writeRange);\n            return E_UNEXPECTED;\n        }\n\n        hr = FC->Initialize(source.Get(), targetGuid, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut);\n        if (FAILED(hr))\n        {\n            pStaging->Unmap(0, &writeRange);\n            return hr;\n        }\n\n        WICRect rect = { 0, 0, static_cast<INT>(desc.Width), static_cast<INT>(desc.Height) };\n        hr = frame->WriteSource(FC.Get(), &rect);\n    }\n    else\n    {\n        // No conversion required\n        hr = frame->WritePixels(desc.Height, static_cast<UINT>(dstRowPitch), static_cast<UINT>(imageSize), static_cast<BYTE*>(pMappedMemory));\n    }\n\n    pStaging->Unmap(0, &writeRange);\n\n    if (FAILED(hr))\n        return hr;\n\n    hr = frame->Commit();\n    if (FAILED(hr))\n        return hr;\n\n    hr = encoder->Commit();\n    if (FAILED(hr))\n        return hr;\n\n    delonfail.clear();\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/AlphaTestEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nTexture2D<float4> Texture : register(t0);\nsampler Sampler : register(s0);\n\n\ncbuffer Parameters : register(b0)\n{\n    float4   DiffuseColor   : packoffset(c0);\n    float4   AlphaTest      : packoffset(c1);\n    float3   FogColor       : packoffset(c2);\n    float4   FogVector      : packoffset(c3);\n    float4x4 WorldViewProj  : packoffset(c4);\n};\n\n#include \"Structures.fxh\"\n#include \"Common.fxh\"\n#include \"RootSig.fxh\"\n\n// Vertex shader: basic.\n[RootSignature(MainRS)]\nVSOutputTx VSAlphaTest(VSInputTx vin)\n{\n    VSOutputTx vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: no fog.\n[RootSignature(MainRS)]\nVSOutputTxNoFog VSAlphaTestNoFog(VSInputTx vin)\n{\n    VSOutputTxNoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color.\n[RootSignature(MainRS)]\nVSOutputTx VSAlphaTestVc(VSInputTxVc vin)\n{\n    VSOutputTx vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color, no fog.\n[RootSignature(MainRS)]\nVSOutputTxNoFog VSAlphaTestVcNoFog(VSInputTxVc vin)\n{\n    VSOutputTxNoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Pixel shader: less/greater compare function.\n[RootSignature(MainRS)]\nfloat4 PSAlphaTestLtGt(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    clip((color.a < AlphaTest.x) ? AlphaTest.z : AlphaTest.w);\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: less/greater compare function, no fog.\n[RootSignature(MainRS)]\nfloat4 PSAlphaTestLtGtNoFog(PSInputTxNoFog pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    clip((color.a < AlphaTest.x) ? AlphaTest.z : AlphaTest.w);\n\n    return color;\n}\n\n\n// Pixel shader: equal/notequal compare function.\n[RootSignature(MainRS)]\nfloat4 PSAlphaTestEqNe(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    clip((abs(color.a - AlphaTest.x) < AlphaTest.y) ? AlphaTest.z : AlphaTest.w);\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: equal/notequal compare function, no fog.\n[RootSignature(MainRS)]\nfloat4 PSAlphaTestEqNeNoFog(PSInputTxNoFog pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    clip((abs(color.a - AlphaTest.x) < AlphaTest.y) ? AlphaTest.z : AlphaTest.w);\n\n    return color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/BasicEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nTexture2D<float4> Texture : register(t0);\nsampler Sampler : register(s0);\n\n\ncbuffer Parameters : register(b0)\n{\n    float4 DiffuseColor             : packoffset(c0);\n    float3 EmissiveColor            : packoffset(c1);\n    float3 SpecularColor            : packoffset(c2);\n    float  SpecularPower            : packoffset(c2.w);\n\n    float3 LightDirection[3]        : packoffset(c3);\n    float3 LightDiffuseColor[3]     : packoffset(c6);\n    float3 LightSpecularColor[3]    : packoffset(c9);\n\n    float3 EyePosition              : packoffset(c12);\n\n    float3 FogColor                 : packoffset(c13);\n    float4 FogVector                : packoffset(c14);\n\n    float4x4 World                  : packoffset(c15);\n    float3x3 WorldInverseTranspose  : packoffset(c19);\n    float4x4 WorldViewProj          : packoffset(c22);\n};\n\n\n#include \"Structures.fxh\"\n#include \"Common.fxh\"\n#include \"RootSig.fxh\"\n#include \"Lighting.fxh\"\n#include \"Utilities.fxh\"\n\n\n// Vertex shader: basic.\n[RootSignature(NoTextureRS)]\nVSOutput VSBasic(VSInput vin)\n{\n    VSOutput vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    return vout;\n}\n\n\n// Vertex shader: no fog.\n[RootSignature(NoTextureRS)]\nVSOutputNoFog VSBasicNoFog(VSInput vin)\n{\n    VSOutputNoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color.\n[RootSignature(NoTextureRS)]\nVSOutput VSBasicVc(VSInputVc vin)\n{\n    VSOutput vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color, no fog.\n[RootSignature(NoTextureRS)]\nVSOutputNoFog VSBasicVcNoFog(VSInputVc vin)\n{\n    VSOutputNoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: texture.\n[RootSignature(MainRS)]\nVSOutputTx VSBasicTx(VSInputTx vin)\n{\n    VSOutputTx vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: texture, no fog.\n[RootSignature(MainRS)]\nVSOutputTxNoFog VSBasicTxNoFog(VSInputTx vin)\n{\n    VSOutputTxNoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: texture + vertex color.\n[RootSignature(MainRS)]\nVSOutputTx VSBasicTxVc(VSInputTxVc vin)\n{\n    VSOutputTx vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: texture + vertex color, no fog.\n[RootSignature(MainRS)]\nVSOutputTxNoFog VSBasicTxVcNoFog(VSInputTxVc vin)\n{\n    VSOutputTxNoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex lighting.\n[RootSignature(NoTextureRS)]\nVSOutput VSBasicVertexLighting(VSInputNm vin)\n{\n    VSOutput vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, vin.Normal, 3);\n    SetCommonVSOutputParams;\n\n    return vout;\n}\n\n[RootSignature(NoTextureRS)]\nVSOutput VSBasicVertexLightingBn(VSInputNm vin)\n{\n    VSOutput vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex lighting + vertex color.\n[RootSignature(NoTextureRS)]\nVSOutput VSBasicVertexLightingVc(VSInputNmVc vin)\n{\n    VSOutput vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, vin.Normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n[RootSignature(NoTextureRS)]\nVSOutput VSBasicVertexLightingVcBn(VSInputNmVc vin)\n{\n    VSOutput vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex lighting + texture.\n[RootSignature(MainRS)]\nVSOutputTx VSBasicVertexLightingTx(VSInputNmTx vin)\n{\n    VSOutputTx vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, vin.Normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputTx VSBasicVertexLightingTxBn(VSInputNmTx vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex lighting + texture + vertex color.\n[RootSignature(MainRS)]\nVSOutputTx VSBasicVertexLightingTxVc(VSInputNmTxVc vin)\n{\n    VSOutputTx vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, vin.Normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputTx VSBasicVertexLightingTxVcBn(VSInputNmTxVc vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting.\n[RootSignature(NoTextureRS)]\nVSOutputPixelLighting VSBasicPixelLighting(VSInputNm vin)\n{\n    VSOutputPixelLighting vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n\n    return vout;\n}\n\n[RootSignature(NoTextureRS)]\nVSOutputPixelLighting VSBasicPixelLightingBn(VSInputNm vin)\n{\n    VSOutputPixelLighting vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting + vertex color.\n[RootSignature(NoTextureRS)]\nVSOutputPixelLighting VSBasicPixelLightingVc(VSInputNmVc vin)\n{\n    VSOutputPixelLighting vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * DiffuseColor.a;\n\n    return vout;\n}\n\n[RootSignature(NoTextureRS)]\nVSOutputPixelLighting VSBasicPixelLightingVcBn(VSInputNmVc vin)\n{\n    VSOutputPixelLighting vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * DiffuseColor.a;\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting + texture.\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSBasicPixelLightingTx(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSBasicPixelLightingTxBn(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting + texture + vertex color.\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSBasicPixelLightingTxVc(VSInputNmTxVc vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * DiffuseColor.a;\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSBasicPixelLightingTxVcBn(VSInputNmTxVc vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * DiffuseColor.a;\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Pixel shader: basic.\n[RootSignature(NoTextureRS)]\nfloat4 PSBasic(PSInput pin) : SV_Target0\n{\n    float4 color = pin.Diffuse;\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: no fog.\n[RootSignature(NoTextureRS)]\nfloat4 PSBasicNoFog(PSInputNoFog pin) : SV_Target0\n{\n    return pin.Diffuse;\n}\n\n\n// Pixel shader: texture.\n[RootSignature(MainRS)]\nfloat4 PSBasicTx(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: texture, no fog.\n[RootSignature(MainRS)]\nfloat4 PSBasicTxNoFog(PSInputTxNoFog pin) : SV_Target0\n{\n    return Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n}\n\n\n// Pixel shader: vertex lighting.\n[RootSignature(NoTextureRS)]\nfloat4 PSBasicVertexLighting(PSInput pin) : SV_Target0\n{\n    float4 color = pin.Diffuse;\n\n    AddSpecular(color, pin.Specular.rgb);\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: vertex lighting, no fog.\n[RootSignature(NoTextureRS)]\nfloat4 PSBasicVertexLightingNoFog(PSInput pin) : SV_Target0\n{\n    float4 color = pin.Diffuse;\n\n    AddSpecular(color, pin.Specular.rgb);\n\n    return color;\n}\n\n\n// Pixel shader: vertex lighting + texture.\n[RootSignature(MainRS)]\nfloat4 PSBasicVertexLightingTx(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    AddSpecular(color, pin.Specular.rgb);\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: vertex lighting + texture, no fog.\n[RootSignature(MainRS)]\nfloat4 PSBasicVertexLightingTxNoFog(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    AddSpecular(color, pin.Specular.rgb);\n\n    return color;\n}\n\n\n// Pixel shader: pixel lighting.\n[RootSignature(NoTextureRS)]\nfloat4 PSBasicPixelLighting(PSInputPixelLighting pin) : SV_Target0\n{\n    float4 color = pin.Diffuse;\n\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n    float3 worldNormal = normalize(pin.NormalWS);\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, 3);\n\n    color.rgb *= lightResult.Diffuse;\n\n    AddSpecular(color, lightResult.Specular);\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader: pixel lighting + texture.\n[RootSignature(MainRS)]\nfloat4 PSBasicPixelLightingTx(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n    float3 worldNormal = normalize(pin.NormalWS);\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, 3);\n\n    color.rgb *= lightResult.Diffuse;\n\n    AddSpecular(color, lightResult.Specular);\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/Common.fxh",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nfloat ComputeFogFactor(float4 position)\n{\n    return saturate(dot(position, FogVector));\n}\n\n\nvoid ApplyFog(inout float4 color, float fogFactor)\n{\n    color.rgb = lerp(color.rgb, FogColor * color.a, fogFactor);\n}\n\n\nvoid AddSpecular(inout float4 color, float3 specular)\n{\n    color.rgb += specular * color.a;\n}\n\n\nstruct CommonVSOutput\n{\n    float4 Pos_ps;\n    float4 Diffuse;\n    float3 Specular;\n    float  FogFactor;\n};\n\n\nCommonVSOutput ComputeCommonVSOutput(float4 position)\n{\n    CommonVSOutput vout;\n    \n    vout.Pos_ps = mul(position, WorldViewProj);\n    vout.Diffuse = DiffuseColor;\n    vout.Specular = 0;\n    vout.FogFactor = ComputeFogFactor(position);\n    \n    return vout;\n}\n\n\n#define SetCommonVSOutputParams \\\n    vout.PositionPS = cout.Pos_ps; \\\n    vout.Diffuse = cout.Diffuse; \\\n    vout.Specular = float4(cout.Specular, cout.FogFactor);\n\n\n#define SetCommonVSOutputParamsNoFog \\\n    vout.PositionPS = cout.Pos_ps; \\\n    vout.Diffuse = cout.Diffuse;\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/CompileShaders.cmd",
    "content": "@echo off\nrem Copyright (c) Microsoft Corporation. All rights reserved.\nrem Licensed under the MIT License.\n\nsetlocal\nset error=0\n\nset FXCOPTS=/nologo /WX /Ges /Zi /Zpc /Qstrip_reflect /Qstrip_debug\n\nif %1.==xbox. goto continuexbox\nif %1.==dxil. goto continuedxil\nif %1.==gxdk. goto continuegxdk\nif %1.==. goto continuepc\necho usage: CompileShaders [xbox]\nexit /b\n\n:continuexbox\nset XBOXPREFIX=XboxOne\nset XBOXOPTS=/D__XBOX_DISABLE_SHADER_NAME_EMPLACEMENT\nif NOT %2.==noprecompile. goto skipnoprecompile\nset XBOXOPTS=%XBOXOPTS% /D__XBOX_DISABLE_PRECOMPILE=1\n:skipnoprecompile\n\nset XBOXFXC=\"%XboxOneXDKLatest%\\xdk\\FXC\\amd64\\FXC.exe\"\nif exist %XBOXFXC% goto continue\nset XBOXFXC=\"%XboxOneXDKLatest%xdk\\FXC\\amd64\\FXC.exe\"\nif exist %XBOXFXC% goto continue\nset XBOXFXC=\"%XboxOneXDKBuild%xdk\\FXC\\amd64\\FXC.exe\"\nif exist %XBOXFXC% goto continue\nset XBOXFXC=\"%DurangoXDK%xdk\\FXC\\amd64\\FXC.exe\"\nif not exist %XBOXFXC% goto needxdk\ngoto continue\n\n:continuegxdk\nif %2.==scarlett. (\nset XBOXPREFIX=XboxGamingScarlett\nset XBOXDXC=\"%GameDKLatest%\\GXDK\\bin\\Scarlett\\DXC.exe\"\n) else (\nset XBOXPREFIX=XboxGamingXboxOne\nset XBOXDXC=\"%GameDKLatest%\\GXDK\\bin\\XboxOne\\DXC.exe\"\n)\n\nif exist %XBOXDXC% goto continue\nset XBOXDXC=\"%GameDKLatest%\\GXDK\\bin\\DXC.exe\"\nif not exist %XBOXDXC% goto needgxdk\ngoto continue\n\n:continuedxil\nset PCDXC=\"%WindowsSdkVerBinPath%x86\\dxc.exe\"\nif exist %PCDXC% goto continue\nset PCDXC=\"%WindowsSdkBinPath%%WindowsSDKVersion%\\x86\\dxc.exe\"\nif exist %PCDXC% goto continue\n\nset PCDXC=dxc.exe\ngoto continue\n\n:continuepc\nset PCOPTS=\n\nset PCFXC=\"%WindowsSdkVerBinPath%x86\\fxc.exe\"\nif exist %PCFXC% goto continue\nset PCFXC=\"%WindowsSdkBinPath%%WindowsSDKVersion%\\x86\\fxc.exe\"\nif exist %PCFXC% goto continue\nset PCFXC=\"%WindowsSdkDir%bin\\%WindowsSDKVersion%\\x86\\fxc.exe\"\nif exist %PCFXC% goto continue\n\nset PCFXC=fxc.exe\n\n:continue\n@if not exist Compiled mkdir Compiled\ncall :CompileShader%1 AlphaTestEffect vs VSAlphaTest\ncall :CompileShader%1 AlphaTestEffect vs VSAlphaTestNoFog\ncall :CompileShader%1 AlphaTestEffect vs VSAlphaTestVc\ncall :CompileShader%1 AlphaTestEffect vs VSAlphaTestVcNoFog\n\ncall :CompileShader%1 AlphaTestEffect ps PSAlphaTestLtGt\ncall :CompileShader%1 AlphaTestEffect ps PSAlphaTestLtGtNoFog\ncall :CompileShader%1 AlphaTestEffect ps PSAlphaTestEqNe\ncall :CompileShader%1 AlphaTestEffect ps PSAlphaTestEqNeNoFog\n\ncall :CompileShader%1 BasicEffect vs VSBasic\ncall :CompileShader%1 BasicEffect vs VSBasicNoFog\ncall :CompileShader%1 BasicEffect vs VSBasicVc\ncall :CompileShader%1 BasicEffect vs VSBasicVcNoFog\ncall :CompileShader%1 BasicEffect vs VSBasicTx\ncall :CompileShader%1 BasicEffect vs VSBasicTxNoFog\ncall :CompileShader%1 BasicEffect vs VSBasicTxVc\ncall :CompileShader%1 BasicEffect vs VSBasicTxVcNoFog\n\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLighting\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingBn\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingVc\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingVcBn\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingTx\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingTxBn\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingTxVc\ncall :CompileShader%1 BasicEffect vs VSBasicVertexLightingTxVcBn\n\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLighting\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingBn\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingVc\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingVcBn\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingTx\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingTxBn\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingTxVc\ncall :CompileShader%1 BasicEffect vs VSBasicPixelLightingTxVcBn\n\ncall :CompileShader%1 BasicEffect ps PSBasic\ncall :CompileShader%1 BasicEffect ps PSBasicNoFog\ncall :CompileShader%1 BasicEffect ps PSBasicTx\ncall :CompileShader%1 BasicEffect ps PSBasicTxNoFog\n\ncall :CompileShader%1 BasicEffect ps PSBasicVertexLighting\ncall :CompileShader%1 BasicEffect ps PSBasicVertexLightingNoFog\ncall :CompileShader%1 BasicEffect ps PSBasicVertexLightingTx\ncall :CompileShader%1 BasicEffect ps PSBasicVertexLightingTxNoFog\n\ncall :CompileShader%1 BasicEffect ps PSBasicPixelLighting\ncall :CompileShader%1 BasicEffect ps PSBasicPixelLightingTx\n\ncall :CompileShader%1 DualTextureEffect vs VSDualTexture\ncall :CompileShader%1 DualTextureEffect vs VSDualTextureNoFog\ncall :CompileShader%1 DualTextureEffect vs VSDualTextureVc\ncall :CompileShader%1 DualTextureEffect vs VSDualTextureVcNoFog\n\ncall :CompileShader%1 DualTextureEffect ps PSDualTexture\ncall :CompileShader%1 DualTextureEffect ps PSDualTextureNoFog\n\ncall :CompileShader%1 EnvironmentMapEffect vs VSEnvMap\ncall :CompileShader%1 EnvironmentMapEffect vs VSEnvMapBn\ncall :CompileShader%1 EnvironmentMapEffect vs VSEnvMapFresnel\ncall :CompileShader%1 EnvironmentMapEffect vs VSEnvMapFresnelBn\ncall :CompileShader%1 EnvironmentMapEffect vs VSEnvMapPixelLighting\ncall :CompileShader%1 EnvironmentMapEffect vs VSEnvMapPixelLightingBn\n\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMap\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapNoFog\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapSpecular\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapSpecularNoFog\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapPixelLighting\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapPixelLightingNoFog\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapPixelLightingFresnel\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapPixelLightingFresnelNoFog\n\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapSpherePixelLighting\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapSpherePixelLightingNoFog\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapSpherePixelLightingFresnel\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapSpherePixelLightingFresnelNoFog\n\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapDualParabolaPixelLighting\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapDualParabolaPixelLightingNoFog\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapDualParabolaPixelLightingFresnel\ncall :CompileShader%1 EnvironmentMapEffect ps PSEnvMapDualParabolaPixelLightingFresnelNoFog\n\ncall :CompileShader%1 SkinnedEffect vs VSSkinnedVertexLightingFourBones\ncall :CompileShader%1 SkinnedEffect vs VSSkinnedVertexLightingFourBonesBn\n\ncall :CompileShader%1 SkinnedEffect vs VSSkinnedPixelLightingFourBones\ncall :CompileShader%1 SkinnedEffect vs VSSkinnedPixelLightingFourBonesBn\n\ncall :CompileShader%1 SkinnedEffect ps PSSkinnedVertexLighting\ncall :CompileShader%1 SkinnedEffect ps PSSkinnedVertexLightingNoFog\ncall :CompileShader%1 SkinnedEffect ps PSSkinnedPixelLighting\n\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTx\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxBn\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxVc\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxVcBn\n\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxNoSpec\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxNoSpecBn\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxVcNoSpec\ncall :CompileShader%1 NormalMapEffect vs VSNormalPixelLightingTxVcNoSpecBn\n\ncall :CompileShader%1 NormalMapEffect ps PSNormalPixelLightingTx\ncall :CompileShader%1 NormalMapEffect ps PSNormalPixelLightingTxNoFog\ncall :CompileShader%1 NormalMapEffect ps PSNormalPixelLightingTxNoSpec\ncall :CompileShader%1 NormalMapEffect ps PSNormalPixelLightingTxNoFogSpec\n\ncall :CompileShader%1 PBREffect vs VSConstant\ncall :CompileShader%1 PBREffect vs VSConstantVelocity\ncall :CompileShader%1 PBREffect vs VSConstantBn\ncall :CompileShader%1 PBREffect vs VSConstantVelocityBn\n\ncall :CompileShader%1 PBREffect ps PSConstant\ncall :CompileShader%1 PBREffect ps PSTextured\ncall :CompileShader%1 PBREffect ps PSTexturedEmissive\ncall :CompileShader%1 PBREffect ps PSTexturedVelocity\ncall :CompileShader%1 PBREffect ps PSTexturedEmissiveVelocity\n\ncall :CompileShader%1 DebugEffect vs VSDebug\ncall :CompileShader%1 DebugEffect vs VSDebugBn\ncall :CompileShader%1 DebugEffect vs VSDebugVc\ncall :CompileShader%1 DebugEffect vs VSDebugVcBn\n\ncall :CompileShader%1 DebugEffect ps PSHemiAmbient\ncall :CompileShader%1 DebugEffect ps PSRGBNormals\ncall :CompileShader%1 DebugEffect ps PSRGBTangents\ncall :CompileShader%1 DebugEffect ps PSRGBBiTangents\n\ncall :CompileShader%1 SpriteEffect vs SpriteVertexShader\ncall :CompileShader%1 SpriteEffect ps SpritePixelShader\n\ncall :CompileShader%1 SpriteEffect vs SpriteVertexShaderHeap\ncall :CompileShader%1 SpriteEffect ps SpritePixelShaderHeap\n\ncall :CompileShader%1 PostProcess vs VSQuad\ncall :CompileShader%1 PostProcess vs VSQuadNoCB\ncall :CompileShader%1 PostProcess vs VSQuadDual\ncall :CompileShader%1 PostProcess ps PSCopy\ncall :CompileShader%1 PostProcess ps PSMonochrome\ncall :CompileShader%1 PostProcess ps PSSepia\ncall :CompileShader%1 PostProcess ps PSDownScale2x2\ncall :CompileShader%1 PostProcess ps PSDownScale4x4\ncall :CompileShader%1 PostProcess ps PSGaussianBlur5x5\ncall :CompileShader%1 PostProcess ps PSBloomExtract\ncall :CompileShader%1 PostProcess ps PSBloomBlur\ncall :CompileShader%1 PostProcess ps PSMerge\ncall :CompileShader%1 PostProcess ps PSBloomCombine\n\ncall :CompileComputeShader%1 GenerateMips main\n\ncall :CompileShader%1 ToneMap vs VSQuad\ncall :CompileShader%1 ToneMap ps PSCopy\ncall :CompileShader%1 ToneMap ps PSSaturate\ncall :CompileShader%1 ToneMap ps PSReinhard\ncall :CompileShader%1 ToneMap ps PSACESFilmic\ncall :CompileShader%1 ToneMap ps PS_SRGB\ncall :CompileShader%1 ToneMap ps PSSaturate_SRGB\ncall :CompileShader%1 ToneMap ps PSReinhard_SRGB\ncall :CompileShader%1 ToneMap ps PSACESFilmic_SRGB\ncall :CompileShader%1 ToneMap ps PSHDR10\n\nif %1.==. goto skipxboxonly\nif %1.==dxil. goto skipxboxonly\n\ncall :CompileShader%1 ToneMap ps PSHDR10_Saturate\ncall :CompileShader%1 ToneMap ps PSHDR10_Reinhard\ncall :CompileShader%1 ToneMap ps PSHDR10_ACESFilmic\ncall :CompileShader%1 ToneMap ps PSHDR10_Saturate_SRGB\ncall :CompileShader%1 ToneMap ps PSHDR10_Reinhard_SRGB\ncall :CompileShader%1 ToneMap ps PSHDR10_ACESFilmic_SRGB\n\n:skipxboxonly\n\necho.\n\nif %error% == 0 (\n    echo Shaders compiled ok\n) else (\n    echo There were shader compilation errors!\n)\n\nendlocal\nexit /b\n\n:CompileShader\nset fxc=%PCFXC% %1.fx %FXCOPTS% /T%2_5_1 %PCOPTS% /E%3 /FhCompiled\\%1_%3.inc /FdCompiled\\%1_%3.pdb /Vn%1_%3\necho.\necho %fxc%\n%fxc% || set error=1\nexit /b\n\n:CompileComputeShader\nset fxc=%PCFXC% %1.hlsl %FXCOPTS% /Tcs_5_1 %PCOPTS% /E%2 /FhCompiled\\%1_%2.inc /FdCompiled\\%1_%2.pdb /Vn%1_%2\necho.\necho %fxc%\n%fxc% || set error=1\nexit /b\n\n:CompileShaderdxil\nset dxc=%PCDXC% %1.fx %FXCOPTS% /T%2_6_0 /E%3 /FhCompiled\\%1_%3.inc /FdCompiled\\%1_%3.pdb /Vn%1_%3\necho.\necho %dxc%\n%dxc% || set error=1\nexit /b\n\n:CompileComputeShaderdxil\nset dxc=%PCDXC% %1.hlsl %FXCOPTS% /Tcs_6_0 /E%2 /FhCompiled\\%1_%2.inc /FdCompiled\\%1_%2.pdb /Vn%1_%2\necho.\necho %dxc%\n%dxc% || set error=1\nexit /b\n\n:CompileShaderxbox\nset fxc=%XBOXFXC% %1.fx %FXCOPTS% /T%2_5_1 %XBOXOPTS% /E%3 /FhCompiled\\%XBOXPREFIX%%1_%3.inc /FdCompiled\\%XBOXPREFIX%%1_%3.pdb /Vn%1_%3\necho.\necho %fxc%\n%fxc% || set error=1\nexit /b\n\n:CompileComputeShaderxbox\nset fxc==%XBOXFXC% %1.hlsl %FXCOPTS% /Tcs_5_1 %XBOXOPTS% /E%2 /FhCompiled\\%XBOXPREFIX%%1_%2.inc /FdCompiled\\%XBOXPREFIX%%1_%2.pdb /Vn%1_%2\necho.\necho %fxc%\n%fxc% || set error=1\nexit /b\n\n:CompileShadergxdk\nset dxc=%XBOXDXC% %1.fx %FXCOPTS% /T%2_6_0 /E%3 /FhCompiled\\%XBOXPREFIX%%1_%3.inc /FdCompiled\\%XBOXPREFIX%%1_%3.pdb /Vn%1_%3\necho.\necho %dxc%\n%dxc% || set error=1\nexit /b\n\n:CompileComputeShadergxdk\nset dxc=%XBOXDXC% %1.hlsl %FXCOPTS% /Tcs_6_0 /E%2 /FhCompiled\\%XBOXPREFIX%%1_%2.inc /FdCompiled\\%XBOXPREFIX%%1_%2.pdb /Vn%1_%2\necho.\necho %dxc%\n%dxc% || set error=1\nexit /b\n\n:needxdk\necho ERROR: CompileShaders xbox requires the Microsoft Xbox One XDK\necho        (try re-running from the XDK Command Prompt)\nexit /b\n\n:needgxdk\necho ERROR: CompileShaders gxdk requires the Microsoft Gaming SDK\necho        (try re-running from the Gaming GXDK Command Prompt)\nexit /b\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/DebugEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n\n\ncbuffer Parameters : register(b0)\n{\n    float3 AmbientDown              : packoffset(c0);\n    float  Alpha                    : packoffset(c0.w);\n    float3 AmbientRange             : packoffset(c1);\n\n    float4x4 World                  : packoffset(c2);\n    float3x3 WorldInverseTranspose  : packoffset(c6);\n    float4x4 WorldViewProj          : packoffset(c9);\n};\n\n\n#include \"RootSig.fxh\"\n#include \"Structures.fxh\"\n#include \"Utilities.fxh\"\n\n\n// Vertex shader: basic\n[RootSignature(DebugEffectRS)]\nVSOutputPixelLightingTx VSDebug(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    vout.PositionPS = mul(vin.Position, WorldViewProj);\n    vout.PositionWS = float4(mul(vin.Position, World).xyz, 1);\n    vout.NormalWS = normalize(mul(vin.Normal, WorldInverseTranspose));\n    vout.Diffuse = float4(1, 1, 1, Alpha);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(DebugEffectRS)]\nVSOutputPixelLightingTx VSDebugBn(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    vout.PositionPS = mul(vin.Position, WorldViewProj);\n    vout.PositionWS = float4(mul(vin.Position, World).xyz, 1);\n    vout.NormalWS = normalize(mul(normal, WorldInverseTranspose));\n    vout.Diffuse = float4(1, 1, 1, Alpha);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color.\n[RootSignature(DebugEffectRS)]\nVSOutputPixelLightingTx VSDebugVc(VSInputNmTxVc vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    vout.PositionPS = mul(vin.Position, WorldViewProj);\n    vout.PositionWS = float4(mul(vin.Position, World).xyz, 1);\n    vout.NormalWS = normalize(mul(vin.Normal, WorldInverseTranspose));\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * Alpha;\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(DebugEffectRS)]\nVSOutputPixelLightingTx VSDebugVcBn(VSInputNmTxVc vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    vout.PositionPS = mul(vin.Position, WorldViewProj);\n    vout.PositionWS = float4(mul(vin.Position, World).xyz, 1);\n    vout.NormalWS = normalize(mul(normal, WorldInverseTranspose));\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * Alpha;\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Pixel shader: default\nfloat3 CalcHemiAmbient(float3 normal, float3 color)\n{\n    float3 up = BiasD2(normal);\n    float3 ambient = AmbientDown + up.y * AmbientRange;\n    return ambient * color;\n}\n\n[RootSignature(DebugEffectRS)]\nfloat4 PSHemiAmbient(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float3 normal = normalize(pin.NormalWS);\n\n    // Do lighting\n    float3 color = CalcHemiAmbient(normal, pin.Diffuse.rgb);\n\n    return float4(color, pin.Diffuse.a);\n}\n\n\n// Pixel shader: RGB normals\n[RootSignature(DebugEffectRS)]\nfloat4 PSRGBNormals(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float3 normal = normalize(pin.NormalWS);\n\n    float3 color = BiasD2(normal);\n\n    return float4(color, pin.Diffuse.a);\n}\n\n// Pixel shader: RGB tangents\n[RootSignature(DebugEffectRS)]\nfloat4 PSRGBTangents(PSInputPixelLightingTx pin) : SV_Target0\n{\n    const float3x3 TBN = CalculateTBN(pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n    float3 tangent = normalize(TBN[0]);\n\n    float3 color = BiasD2(tangent);\n\n    return float4(color, pin.Diffuse.a);\n}\n\n// Pixel shader: RGB bi-tangents\n[RootSignature(DebugEffectRS)]\nfloat4 PSRGBBiTangents(PSInputPixelLightingTx pin) : SV_Target0\n{\n    const float3x3 TBN = CalculateTBN(pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n    float3 bitangent = normalize(TBN[1]);\n\n    float3 color = BiasD2(bitangent);\n\n    return float4(color, pin.Diffuse.a);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/DualTextureEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nTexture2D<float4> Texture  : register(t0);\nTexture2D<float4> Texture2 : register(t1);\n\nsampler Sampler  : register(s0);\nsampler Sampler2 : register(s1);\n\n\ncbuffer Parameters : register(b0)\n{\n    float4   DiffuseColor   : packoffset(c0);\n    float3   FogColor       : packoffset(c1);\n    float4   FogVector      : packoffset(c2);\n    float4x4 WorldViewProj  : packoffset(c3);\n};\n\n\n#include \"Structures.fxh\"\n#include \"RootSig.fxh\"\n#include \"Common.fxh\"\n\n\n// Vertex shader: basic.\n[RootSignature(DualTextureRS)]\nVSOutputTx2 VSDualTexture(VSInputTx2 vin)\n{\n    VSOutputTx2 vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.TexCoord2 = vin.TexCoord2;\n\n    return vout;\n}\n\n\n// Vertex shader: no fog.\n[RootSignature(DualTextureRS)]\nVSOutputTx2NoFog VSDualTextureNoFog(VSInputTx2 vin)\n{\n    VSOutputTx2NoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.TexCoord2 = vin.TexCoord2;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color.\n[RootSignature(DualTextureRS)]\nVSOutputTx2 VSDualTextureVc(VSInputTx2Vc vin)\n{\n    VSOutputTx2 vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.TexCoord2 = vin.TexCoord2;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex color, no fog.\n[RootSignature(DualTextureRS)]\nVSOutputTx2NoFog VSDualTextureVcNoFog(VSInputTx2Vc vin)\n{\n    VSOutputTx2NoFog vout;\n\n    CommonVSOutput cout = ComputeCommonVSOutput(vin.Position);\n    SetCommonVSOutputParamsNoFog;\n\n    vout.TexCoord = vin.TexCoord;\n    vout.TexCoord2 = vin.TexCoord2;\n    vout.Diffuse *= vin.Color;\n\n    return vout;\n}\n\n\n// Pixel shader: basic.\n[RootSignature(DualTextureRS)]\nfloat4 PSDualTexture(PSInputTx2 pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord);\n    float4 overlay = Texture2.Sample(Sampler2, pin.TexCoord2);\n\n    color.rgb *= 2; \n    color *= overlay * pin.Diffuse;\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSDualTextureNoFog(PSInputTx2NoFog pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord);\n    float4 overlay = Texture2.Sample(Sampler2, pin.TexCoord2);\n\n    color.rgb *= 2; \n    color *= overlay * pin.Diffuse;\n\n    return color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/EnvironmentMapEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nTexture2D<float4>   Texture             : register(t0);\nTextureCube<float4> EnvironmentMap      : register(t1);\nTexture2D<float4>   SphereMap           : register(t1);\nTexture2DArray<float4> DualParabolaMap  : register(t1);\n\nsampler Sampler       : register(s0);\nsampler EnvMapSampler : register(s1);\n\n\ncbuffer Parameters : register(b0)\n{\n    float3 EnvironmentMapSpecular   : packoffset(c0);\n    float  EnvironmentMapAmount     : packoffset(c1.x);\n    float  FresnelFactor            : packoffset(c1.y);\n\n    float4 DiffuseColor             : packoffset(c2);\n    float3 EmissiveColor            : packoffset(c3);\n\n    float3 LightDirection[3]        : packoffset(c4);\n    float3 LightDiffuseColor[3]     : packoffset(c7);\n\n    float3 EyePosition              : packoffset(c10);\n\n    float3 FogColor                 : packoffset(c11);\n    float4 FogVector                : packoffset(c12);\n\n    float4x4 World                  : packoffset(c13);\n    float3x3 WorldInverseTranspose  : packoffset(c17);\n    float4x4 WorldViewProj          : packoffset(c20);\n};\n\n\n// We don't use these parameters, but Lighting.fxh won't compile without them.\n#define SpecularPower       0\n#define SpecularColor       0\n#define LightSpecularColor  float3(0, 0, 0)\n\n\n#include \"Structures.fxh\"\n#include \"Common.fxh\"\n#include \"RootSig.fxh\"\n#include \"Lighting.fxh\"\n#include \"Utilities.fxh\"\n\n\nfloat ComputeFresnelFactor(float3 eyeVector, float3 worldNormal)\n{\n    float viewAngle = dot(eyeVector, worldNormal);\n\n    return pow(max(1 - abs(viewAngle), 0), FresnelFactor) * EnvironmentMapAmount;\n}\n\n\nVSOutputTxEnvMap ComputeEnvMapVSOutput(VSInputNmTx vin, float3 normal, uniform bool useFresnel, uniform int numLights)\n{\n    VSOutputTxEnvMap vout;\n\n    float4 pos_ws = mul(vin.Position, World);\n    float3 eyeVector = normalize(EyePosition - pos_ws.xyz);\n    float3 worldNormal = normalize(mul(normal, WorldInverseTranspose));\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, numLights);\n\n    vout.PositionPS = mul(vin.Position, WorldViewProj);\n    vout.Diffuse = float4(lightResult.Diffuse, DiffuseColor.a);\n\n    if (useFresnel)\n        vout.Specular.rgb = ComputeFresnelFactor(eyeVector, worldNormal);\n    else\n        vout.Specular.rgb = EnvironmentMapAmount;\n\n    vout.Specular.a = ComputeFogFactor(vin.Position);\n    vout.TexCoord = vin.TexCoord;\n    vout.EnvCoord = reflect(-eyeVector, worldNormal);\n\n    return vout;\n}\n\n\n// Cubic environment mapping\n// Greene, \"Environment Mapping and Other Applications of World Projections\", IEEE Computer Graphics and Applications. 1986.\nfloat4 ComputeEnvMapPSOutput(PSInputPixelLightingTx pin, uniform bool useFresnel)\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n    float3 worldNormal = normalize(pin.NormalWS);\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, 3);\n\n    color.rgb *= lightResult.Diffuse;\n\n    float3 envcoord = reflect(-eyeVector, worldNormal);\n\n    float4 envmap = EnvironmentMap.Sample(EnvMapSampler, envcoord) * color.a;\n\n    float3 amount;\n    if (useFresnel)\n        amount = ComputeFresnelFactor(eyeVector, worldNormal);\n    else\n        amount = EnvironmentMapAmount;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, amount.rgb);\n    color.rgb += EnvironmentMapSpecular * envmap.a;\n\n    return color;\n}\n\n\n// Spherical environment mapping\n// Blinn & Newell, \"Texture and Reflection in Computer Generated Images\", Communications of the ACM. 1976.\nfloat4 ComputeEnvMapSpherePSOutput(PSInputPixelLightingTx pin, uniform bool useFresnel)\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n    float3 worldNormal = normalize(pin.NormalWS);\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, 3);\n\n    color.rgb *= lightResult.Diffuse;\n\n    float3 r = reflect(-eyeVector, worldNormal);\n    float m = 2.0 * sqrt(r.x*r.x + r.y*r.y + (r.z + 1.0)*(r.z + 1.0));\n    float2 envcoord = float2(r.x / m + 0.5, r.y / m + 0.5);\n\n    float4 envmap = SphereMap.Sample(EnvMapSampler, envcoord) * color.a;\n\n    float3 amount;\n    if (useFresnel)\n        amount = ComputeFresnelFactor(eyeVector, worldNormal);\n    else\n        amount = EnvironmentMapAmount;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, amount.rgb);\n    color.rgb += EnvironmentMapSpecular * envmap.a;\n\n    return color;\n}\n\n\n// Dual-parabola environment mapping\n// Heidrich & Seidel, \"View-independent Environment Maps\", Eurographics Workshop on Graphics Hardware, 1998.\nfloat4 ComputeEnvMapDualParabolaPSOutput(PSInputPixelLightingTx pin, uniform bool useFresnel)\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n    float3 worldNormal = normalize(pin.NormalWS);\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, 3);\n\n    color.rgb *= lightResult.Diffuse;\n\n    float3 r = reflect(-eyeVector, worldNormal);\n    float m = 2.0 * (1.0 + abs(r.z));\n    float3 envcoord = float3(r.x / m + 0.5, r.y / m + 0.5, (r.z > 0) ? 0 : 1);\n\n    float4 envmap = DualParabolaMap.Sample(EnvMapSampler, envcoord) * color.a;\n\n    float3 amount;\n    if (useFresnel)\n        amount = ComputeFresnelFactor(eyeVector, worldNormal);\n    else\n        amount = EnvironmentMapAmount;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, amount.rgb);\n    color.rgb += EnvironmentMapSpecular * envmap.a;\n\n    return color;\n}\n\n\n// Vertex shader: basic.\n[RootSignature(DualTextureRS)]\nVSOutputTxEnvMap VSEnvMap(VSInputNmTx vin)\n{\n    return ComputeEnvMapVSOutput(vin, vin.Normal, false, 3);\n}\n\n[RootSignature(DualTextureRS)]\nVSOutputTxEnvMap VSEnvMapBn(VSInputNmTx vin)\n{\n    float3 normal = BiasX2(vin.Normal);\n\n    return ComputeEnvMapVSOutput(vin, normal, false, 3);\n}\n\n\n// Vertex shader: fresnel.\n[RootSignature(DualTextureRS)]\nVSOutputTxEnvMap VSEnvMapFresnel(VSInputNmTx vin)\n{\n    return ComputeEnvMapVSOutput(vin, vin.Normal, true, 3);\n}\n\n[RootSignature(DualTextureRS)]\nVSOutputTxEnvMap VSEnvMapFresnelBn(VSInputNmTx vin)\n{\n    float3 normal = BiasX2(vin.Normal);\n\n    return ComputeEnvMapVSOutput(vin, normal, true, 3);\n}\n\n\n// Vertex shader: pixel lighting.\n[RootSignature(DualTextureRS)]\nVSOutputPixelLightingTx VSEnvMapPixelLighting(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(DualTextureRS)]\nVSOutputPixelLightingTx VSEnvMapPixelLightingBn(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Pixel shader (cube mapping): basic.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMap(PSInputTxEnvMap pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    float4 envmap = EnvironmentMap.Sample(EnvMapSampler, pin.EnvCoord) * color.a;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, pin.Specular.rgb);\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapNoFog(PSInputTxEnvMap pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    float4 envmap = EnvironmentMap.Sample(EnvMapSampler, pin.EnvCoord) * color.a;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, pin.Specular.rgb);\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): specular.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapSpecular(PSInputTxEnvMap pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    float4 envmap = EnvironmentMap.Sample(EnvMapSampler, pin.EnvCoord) * color.a;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, pin.Specular.rgb);\n    color.rgb += EnvironmentMapSpecular * envmap.a;\n\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): specular, no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapSpecularNoFog(PSInputTxEnvMap pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    float4 envmap = EnvironmentMap.Sample(EnvMapSampler, pin.EnvCoord) * color.a;\n\n    color.rgb = lerp(color.rgb, envmap.rgb, pin.Specular.rgb);\n    color.rgb += EnvironmentMapSpecular * envmap.a;\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): pixel lighting.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapPixelLighting(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapPSOutput(pin, false);\n\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): pixel lighting + no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapPixelLightingNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapPSOutput(pin, false);\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): pixel lighting + fresnel\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapPixelLightingFresnel(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapPSOutput(pin, true);\n\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader (cube mapping): pixel lighting + fresnel + no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapPixelLightingFresnelNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapPSOutput(pin, true);\n\n    return color;\n}\n\n\n// Pixel shader (sphere mapping): pixel lighting.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapSpherePixelLighting(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapSpherePSOutput(pin, false);\n\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader (sphere mapping): pixel lighting + no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapSpherePixelLightingNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapSpherePSOutput(pin, false);\n\n    return color;\n}\n\n\n// Pixel shader (sphere mapping): pixel lighting + fresnel\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapSpherePixelLightingFresnel(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapSpherePSOutput(pin, true);\n\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader (sphere mapping): pixel lighting + fresnel + no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapSpherePixelLightingFresnelNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapSpherePSOutput(pin, true);\n\n    return color;\n}\n\n\n// Pixel shader (dual parabola mapping): pixel lighting.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapDualParabolaPixelLighting(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapDualParabolaPSOutput(pin, false);\n\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader (dual parabola mapping): pixel lighting + no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapDualParabolaPixelLightingNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapDualParabolaPSOutput(pin, false);\n\n    return color;\n}\n\n\n// Pixel shader (dual parabola mapping): pixel lighting + fresnel\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapDualParabolaPixelLightingFresnel(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapDualParabolaPSOutput(pin, true);\n\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n\n\n// Pixel shader (dual parabola mapping): pixel lighting + fresnel + no fog.\n[RootSignature(DualTextureRS)]\nfloat4 PSEnvMapDualParabolaPixelLightingFresnelNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = ComputeEnvMapDualParabolaPSOutput(pin, true);\n\n    return color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/GenerateMips.hlsl",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\n#include \"Structures.fxh\"\n#include \"RootSig.fxh\"\n\nSamplerState Sampler       : register(s0);\nTexture2D<float4> SrcMip   : register(t0);\nRWTexture2D<float4> OutMip : register(u0);\n\ncbuffer MipConstants : register(b0)\n{\n    float2 InvOutTexelSize; // texel size for OutMip (NOT SrcMip)\n    uint SrcMipIndex;\n}\n\nfloat4 Mip(uint2 coord)\n{\n    float2 uv = (coord.xy + 0.5) * InvOutTexelSize;\n    return SrcMip.SampleLevel(Sampler, uv, SrcMipIndex);\n}\n\n[RootSignature(GenerateMipsRS)]\n[numthreads(8, 8, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID)\n{\n    OutMip[DTid.xy] = Mip(DTid.xy);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/Lighting.fxh",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nstruct ColorPair\n{\n    float3 Diffuse;\n    float3 Specular;\n};\n\n\nColorPair ComputeLights(float3 eyeVector, float3 worldNormal, uniform int numLights)\n{\n    float3x3 lightDirections = 0;\n    float3x3 lightDiffuse = 0;\n    float3x3 lightSpecular = 0;\n    float3x3 halfVectors = 0;\n    \n    [unroll]\n    for (int i = 0; i < numLights; i++)\n    {\n        lightDirections[i] = LightDirection[i];\n        lightDiffuse[i]    = LightDiffuseColor[i];\n        lightSpecular[i]   = LightSpecularColor[i];\n        \n        halfVectors[i] = normalize(eyeVector - lightDirections[i]);\n    }\n\n    float3 dotL = mul(-lightDirections, worldNormal);\n    float3 dotH = mul(halfVectors, worldNormal);\n    \n    float3 zeroL = step(0, dotL);\n\n    float3 diffuse  = zeroL * dotL;\n    float3 specular = pow(max(dotH, 0) * zeroL, SpecularPower) * dotL;\n\n    ColorPair result;\n    \n    result.Diffuse  = mul(diffuse,  lightDiffuse)  * DiffuseColor.rgb + EmissiveColor;\n    result.Specular = mul(specular, lightSpecular) * SpecularColor;\n\n    return result;\n}\n\n\nCommonVSOutput ComputeCommonVSOutputWithLighting(float4 position, float3 normal, uniform int numLights)\n{\n    CommonVSOutput vout;\n    \n    float4 pos_ws = mul(position, World);\n    float3 eyeVector = normalize(EyePosition - pos_ws.xyz);\n    float3 worldNormal = normalize(mul(normal, WorldInverseTranspose));\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, numLights);\n    \n    vout.Pos_ps = mul(position, WorldViewProj);\n    vout.Diffuse = float4(lightResult.Diffuse, DiffuseColor.a);\n    vout.Specular = lightResult.Specular;\n    vout.FogFactor = ComputeFogFactor(position);\n    \n    return vout;\n}\n\n\nstruct CommonVSOutputPixelLighting\n{\n    float4 Pos_ps;\n    float3 Pos_ws;\n    float3 Normal_ws;\n    float  FogFactor;\n};\n\n\nCommonVSOutputPixelLighting ComputeCommonVSOutputPixelLighting(float4 position, float3 normal)\n{\n    CommonVSOutputPixelLighting vout;\n    \n    vout.Pos_ps = mul(position, WorldViewProj);\n    vout.Pos_ws = mul(position, World).xyz;\n    vout.Normal_ws = normalize(mul(normal, WorldInverseTranspose));\n    vout.FogFactor = ComputeFogFactor(position);\n    \n    return vout;\n}\n\n\n#define SetCommonVSOutputParamsPixelLighting \\\n    vout.PositionPS = cout.Pos_ps; \\\n    vout.PositionWS = float4(cout.Pos_ws, cout.FogFactor); \\\n    vout.NormalWS = cout.Normal_ws;\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/NormalMapEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\n\nTexture2D<float4> Texture : register(t0);\nTexture2D<float3> NormalTexture : register(t1);\nTexture2D<float3> SpecularTexture : register(t2);\n\nsampler Sampler : register(s0);\n\ncbuffer Parameters : register(b0)\n{\n    float4 DiffuseColor             : packoffset(c0);\n    float3 EmissiveColor            : packoffset(c1);\n    float3 SpecularColor            : packoffset(c2);\n    float  SpecularPower            : packoffset(c2.w);\n\n    float3 LightDirection[3]        : packoffset(c3);\n    float3 LightDiffuseColor[3]     : packoffset(c6);\n    float3 LightSpecularColor[3]    : packoffset(c9);\n\n    float3 EyePosition              : packoffset(c12);\n\n    float3 FogColor                 : packoffset(c13);\n    float4 FogVector                : packoffset(c14);\n\n    float4x4 World                  : packoffset(c15);\n    float3x3 WorldInverseTranspose  : packoffset(c19);\n    float4x4 WorldViewProj          : packoffset(c22);\n};\n\n\n#include \"Structures.fxh\"\n#include \"Common.fxh\"\n#include \"RootSig.fxh\"\n#include \"Lighting.fxh\"\n#include \"Utilities.fxh\"\n\n// Vertex shader: pixel lighting + texture.\n[RootSignature(NormalMapRS)]\nVSOutputPixelLightingTx VSNormalPixelLightingTx(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(NormalMapRSNoSpec)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxNoSpec(VSInputNmTx vin)\n{\n    return VSNormalPixelLightingTx(vin);\n}\n\n\n// Vertex shader: pixel lighting + texture (biased normal).\n[RootSignature(NormalMapRS)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxBn(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(NormalMapRSNoSpec)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxNoSpecBn(VSInputNmTx vin)\n{\n    return VSNormalPixelLightingTxBn(vin);\n}\n\n// Vertex shader: pixel lighting + texture + vertex color.\n[RootSignature(NormalMapRS)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxVc(VSInputNmTxVc vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * DiffuseColor.a;\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(NormalMapRSNoSpec)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxVcNoSpec(VSInputNmTxVc vin)\n{\n    return VSNormalPixelLightingTxVc(vin);\n}\n\n// Vertex shader: pixel lighting + texture + vertex color (biased normal).\n[RootSignature(NormalMapRS)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxVcBn(VSInputNmTxVc vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse.rgb = vin.Color.rgb;\n    vout.Diffuse.a = vin.Color.a * DiffuseColor.a;\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(NormalMapRSNoSpec)]\nVSOutputPixelLightingTx VSNormalPixelLightingTxVcNoSpecBn(VSInputNmTxVc vin)\n{\n    return VSNormalPixelLightingTxVcBn(vin);\n}\n\n// Pixel shader: pixel lighting + texture + no fog\n[RootSignature(NormalMapRS)]\nfloat4 PSNormalPixelLightingTxNoFog(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(Sampler, pin.TexCoord).xy);\n    float3 normal = PeturbNormal(localNormal, pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n\n    // Do lighting\n    ColorPair lightResult = ComputeLights(eyeVector, normal, 3);\n\n    // Get color from albedo texture\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    color.rgb *= lightResult.Diffuse;\n\n    // Apply specular, modulated by the intensity given in the specular map\n    float3 specIntensity = SpecularTexture.Sample(Sampler, pin.TexCoord);\n    AddSpecular(color, lightResult.Specular * specIntensity);\n\n    return color;\n}\n\n// Pixel shader: pixel lighting + texture\n[RootSignature(NormalMapRS)]\nfloat4 PSNormalPixelLightingTx(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n \n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(Sampler, pin.TexCoord).xy);\n    float3 normal = PeturbNormal(localNormal, pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n\n    // Do lighting\n    ColorPair lightResult = ComputeLights(eyeVector, normal, 3);\n\n    // Get color from albedo texture\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    color.rgb *= lightResult.Diffuse;\n\n    // Apply specular, modulated by the intensity given in the specular map\n    float3 specIntensity = SpecularTexture.Sample(Sampler, pin.TexCoord);\n    AddSpecular(color, lightResult.Specular * specIntensity);\n\n    ApplyFog(color, pin.PositionWS.w);\n    return color;\n}\n\n\n// Pixel shader: pixel lighting + texture + no fog + no specular\n[RootSignature(NormalMapRSNoSpec)]\nfloat4 PSNormalPixelLightingTxNoFogSpec(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(Sampler, pin.TexCoord).xy);\n    float3 normal = PeturbNormal(localNormal, pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n\n    // Do lighting\n    ColorPair lightResult = ComputeLights(eyeVector, normal, 3);\n\n    // Get color from albedo texture\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    color.rgb *= lightResult.Diffuse;\n\n    // Apply specular\n    AddSpecular(color, lightResult.Specular);\n\n    return color;\n}\n\n// Pixel shader: pixel lighting + texture + no specular\n[RootSignature(NormalMapRSNoSpec)]\nfloat4 PSNormalPixelLightingTxNoSpec(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(Sampler, pin.TexCoord).xy);\n    float3 normal = PeturbNormal(localNormal, pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n\n    // Do lighting\n    ColorPair lightResult = ComputeLights(eyeVector, normal, 3);\n\n    // Get color from albedo texture\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n    color.rgb *= lightResult.Diffuse;\n\n    // Apply specular\n    AddSpecular(color, lightResult.Specular);\n\n    ApplyFog(color, pin.PositionWS.w);\n    return color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/PBRCommon.fxh",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nstruct CommonVSOutputPixelLighting\n{\n    float4 Pos_ps;\n    float3 Pos_ws;\n    float3 Normal_ws;\n};\n\nstruct VSOut_Velocity\n{\n    VSOutputPixelLightingTx current;\n    float4                         prevPosition : TEXCOORD4;\n};\n\nCommonVSOutputPixelLighting ComputeCommonVSOutputPixelLighting(float4 position, float3 normal)\n{\n    CommonVSOutputPixelLighting vout;\n\n    vout.Pos_ps = mul(position, WorldViewProj);\n    vout.Pos_ws = mul(position, World).xyz;\n    vout.Normal_ws = normalize(mul(normal, WorldInverseTranspose));\n\n    return vout;\n}\n\nstatic const float PI = 3.14159265f;\nstatic const float EPSILON = 1e-6f;\n\n// Shlick's approximation of Fresnel\n// https://en.wikipedia.org/wiki/Schlick%27s_approximation\nfloat3 Fresnel_Shlick(in float3 f0, in float3 f90, in float x)\n{\n    return f0 + (f90 - f0) * pow(1.f - x, 5.f);\n}\n\n// Burley B. \"Physically Based Shading at Disney\"\n// SIGGRAPH 2012 Course: Practical Physically Based Shading in Film and Game Production, 2012.\nfloat Diffuse_Burley(in float NdotL, in float NdotV, in float LdotH, in float roughness)\n{\n    float fd90 = 0.5f + 2.f * roughness * LdotH * LdotH;\n    return Fresnel_Shlick(1, fd90, NdotL).x * Fresnel_Shlick(1, fd90, NdotV).x;\n}\n\n// GGX specular D (normal distribution)\n// https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf\nfloat Specular_D_GGX(in float alpha, in float NdotH)\n{\n    const float alpha2 = alpha * alpha;\n    const float lower = (NdotH * NdotH * (alpha2 - 1)) + 1;\n    return alpha2 / max(EPSILON, PI * lower * lower);\n}\n\n// Schlick-Smith specular G (visibility) with Hable's LdotH optimization\n// http://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf\n// http://graphicrants.blogspot.se/2013/08/specular-brdf-reference.html\nfloat G_Shlick_Smith_Hable(float alpha, float LdotH)\n{\n    return rcp(lerp(LdotH * LdotH, 1, alpha * alpha * 0.25f));\n}\n\n// A microfacet based BRDF.\n//\n// alpha:           This is roughness * roughness as in the \"Disney\" PBR model by Burley et al.\n//\n// specularColor:   The F0 reflectance value - 0.04 for non-metals, or RGB for metals. This follows model \n//                  used by Unreal Engine 4.\n//\n// NdotV, NdotL, LdotH, NdotH: vector relationships between,\n//      N - surface normal\n//      V - eye normal\n//      L - light normal\n//      H - half vector between L & V.\nfloat3 Specular_BRDF(in float alpha, in float3 specularColor, in float NdotV, in float NdotL, in float LdotH, in float NdotH)\n{\n    // Specular D (microfacet normal distribution) component\n    float specular_D = Specular_D_GGX(alpha, NdotH);\n\n    // Specular Fresnel\n    float3 specular_F = Fresnel_Shlick(specularColor, 1, LdotH);\n\n    // Specular G (visibility) component\n    float specular_G = G_Shlick_Smith_Hable(alpha, LdotH);\n\n    return specular_D * specular_F * specular_G;\n}\n\n// Diffuse irradiance\nfloat3 Diffuse_IBL(in float3 N)\n{\n    return IrradianceTexture.Sample(IBLSampler, N);\n}\n\n// Approximate specular image based lighting by sampling radiance map at lower mips \n// according to roughness, then modulating by Fresnel term. \nfloat3 Specular_IBL(in float3 N, in float3 V, in float lodBias)\n{\n    float mip = lodBias * NumRadianceMipLevels;\n    float3 dir = reflect(-V, N);\n    return RadianceTexture.SampleLevel(IBLSampler, dir, mip);\n}\n\n// Apply Disney-style physically based rendering to a surface with:\n//\n// V, N:             Eye and surface normals\n//\n// numLights:        Number of directional lights.\n//\n// lightColor[]:     Color and intensity of directional light.\n//\n// lightDirection[]: Light direction.\nfloat3 LightSurface(\n    in float3 V, in float3 N,\n    in int numLights, in float3 lightColor[3], in float3 lightDirection[3],\n    in float3 albedo, in float roughness, in float metallic, in float ambientOcclusion)\n{\n    // Specular coefficiant - fixed reflectance value for non-metals\n    static const float kSpecularCoefficient = 0.04;\n\n    const float NdotV = saturate(dot(N, V));\n\n    // Burley roughness bias\n    const float alpha = roughness * roughness;    \n\n    // Blend base colors\n    const float3 c_diff = lerp(albedo, float3(0, 0, 0), metallic)       * ambientOcclusion;\n    const float3 c_spec = lerp(kSpecularCoefficient, albedo, metallic)  * ambientOcclusion;\n\n    // Output color\n    float3 acc_color = 0;                         \n\n    // Accumulate light values\n    for (int i = 0; i < numLights; i++)\n    {\n        // light vector (to light)\n        const float3 L = normalize(-lightDirection[i]);\n\n        // Half vector\n        const float3 H = normalize(L + V);\n\n        // products\n        const float NdotL = saturate(dot(N, L));\n        const float LdotH = saturate(dot(L, H));\n        const float NdotH = saturate(dot(N, H));\n\n        // Diffuse & specular factors\n        float diffuse_factor = Diffuse_Burley(NdotL, NdotV, LdotH, roughness);\n        float3 specular      = Specular_BRDF(alpha, c_spec, NdotV, NdotL, LdotH, NdotH);\n\n        // Directional light\n        acc_color += NdotL * lightColor[i] * (((c_diff * diffuse_factor) + specular));\n    }\n\n    // Add diffuse irradiance\n    float3 diffuse_env = Diffuse_IBL(N);\n    acc_color += c_diff * diffuse_env;\n\n    // Add specular radiance \n    float3 specular_env = Specular_IBL(N, V, roughness);\n    acc_color += c_spec * specular_env;\n\n    return acc_color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/PBREffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\n\nTexture2D<float4> AlbedoTexture : register(t0);\nTexture2D<float3> NormalTexture : register(t1);\nTexture2D<float3> RMATexture    : register(t2);\n\nTexture2D<float3> EmissiveTexture : register(t3);\n\nTextureCube<float3> RadianceTexture   : register(t4);\nTextureCube<float3> IrradianceTexture : register(t5);\n\nsampler SurfaceSampler : register(s0);\nsampler IBLSampler     : register(s1);\n\ncbuffer Constants : register(b0)\n{\n    float3   EyePosition            : packoffset(c0);\n    float4x4 World                  : packoffset(c1);\n    float3x3 WorldInverseTranspose  : packoffset(c5);\n    float4x4 WorldViewProj          : packoffset(c8);\n    float4x4 PrevWorldViewProj      : packoffset(c12);\n\n    float3 LightDirection[3]        : packoffset(c16);\n    float3 LightColor[3]            : packoffset(c19);   // \"Specular and diffuse light\" in PBR\n \n    float3 ConstantAlbedo           : packoffset(c22);   // Constant values if not a textured effect\n    float  Alpha                    : packoffset(c22.w);\n    float  ConstantMetallic         : packoffset(c23.x);\n    float  ConstantRoughness        : packoffset(c23.y);\n\n    int NumRadianceMipLevels        : packoffset(c23.z);\n\n    // Size of render target\n    float TargetWidth               : packoffset(c23.w);\n    float TargetHeight              : packoffset(c24.x);\n};\n\n\n#include \"Structures.fxh\"\n#include \"PBRCommon.fxh\"\n#include \"RootSig.fxh\"\n#include \"Utilities.fxh\"\n\n\n// Vertex shader: pbr\n[RootSignature(PBREffectRS)]\nVSOutputPixelLightingTx VSConstant(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    \n    vout.PositionPS = cout.Pos_ps;\n    vout.PositionWS = float4(cout.Pos_ws, 1);\n    vout.NormalWS = cout.Normal_ws;\n    vout.Diffuse = float4(ConstantAlbedo, Alpha);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: pbr + velocity\n[RootSignature(PBREffectRS)]\nVSOut_Velocity VSConstantVelocity(VSInputNmTx vin)\n{\n    VSOut_Velocity vout;\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, vin.Normal);\n    \n    vout.current.PositionPS = cout.Pos_ps;\n    vout.current.PositionWS = float4(cout.Pos_ws, 1);\n    vout.current.NormalWS = cout.Normal_ws;\n    vout.current.Diffuse = float4(ConstantAlbedo, Alpha);\n    vout.current.TexCoord = vin.TexCoord;\n    vout.prevPosition = mul(vin.Position, PrevWorldViewProj);\n\n    return vout;\n}\n\n\n// Vertex shader: pbr (biased normal)\n[RootSignature(PBREffectRS)]\nVSOutputPixelLightingTx VSConstantBn(VSInputNmTx vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n\n    vout.PositionPS = cout.Pos_ps;\n    vout.PositionWS = float4(cout.Pos_ws, 1);\n    vout.NormalWS = cout.Normal_ws;\n    vout.Diffuse = float4(ConstantAlbedo, Alpha);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: pbr + velocity (biased normal)\n[RootSignature(PBREffectRS)]\nVSOut_Velocity VSConstantVelocityBn(VSInputNmTx vin)\n{\n    VSOut_Velocity vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n\n    vout.current.PositionPS = cout.Pos_ps;\n    vout.current.PositionWS = float4(cout.Pos_ws, 1);\n    vout.current.NormalWS = cout.Normal_ws;\n    vout.current.Diffuse = float4(ConstantAlbedo, Alpha);\n    vout.current.TexCoord = vin.TexCoord;\n\n    vout.prevPosition = mul(vin.Position, PrevWorldViewProj);\n\n    return vout;\n}\n\n\n// Pixel shader: pbr (constants) + image-based lighting\n[RootSignature(PBREffectRS)]\nfloat4 PSConstant(PSInputPixelLightingTx pin) : SV_Target0\n{\n    // vectors\n    const float3 V = normalize(EyePosition - pin.PositionWS.xyz);   // view vector\n    const float3 N = normalize(pin.NormalWS);                       // surface normal\n    const float AO = 1;                                             // ambient term\n\n    float3 color = LightSurface(V, N, 3,\n        LightColor, LightDirection,\n        ConstantAlbedo, ConstantRoughness, ConstantMetallic, AO);\n\n    return float4(color, Alpha);\n}\n\n\n// Pixel shader: pbr (textures) + image-based lighting\n[RootSignature(PBREffectRS)]\nfloat4 PSTextured(PSInputPixelLightingTx pin) : SV_Target0\n{\n    const float3 V = normalize(EyePosition - pin.PositionWS.xyz); // view vector\n    const float3 L = normalize(-LightDirection[0]);               // light vector (\"to light\" opposite of light's direction)\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(SurfaceSampler, pin.TexCoord).xy);\n    float3 N = PeturbNormal(localNormal, pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n\n    // Get albedo\n    float4 albedo = AlbedoTexture.Sample(SurfaceSampler, pin.TexCoord);\n\n    // Get roughness, metalness, and ambient occlusion\n    float3 RMA = RMATexture.Sample(SurfaceSampler, pin.TexCoord);\n\n    // glTF2 defines metalness as B channel, roughness as G channel, and occlusion as R channel\n\n    // Shade surface\n    float3 color = LightSurface(V, N, 3, LightColor, LightDirection, albedo.rgb, RMA.g, RMA.b, RMA.r);\n\n    return float4(color, albedo.w * Alpha);\n}\n\n\n// Pixel shader: pbr (textures) + emissive + image-based lighting\n[RootSignature(PBREffectRS)]\nfloat4 PSTexturedEmissive(PSInputPixelLightingTx pin) : SV_Target0\n{\n    const float3 V = normalize(EyePosition - pin.PositionWS.xyz); // view vector\n    const float3 L = normalize(-LightDirection[0]);               // light vector (\"to light\" opposite of light's direction)\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(SurfaceSampler, pin.TexCoord).xy);\n    float3 N = PeturbNormal(localNormal, pin.PositionWS.xyz, pin.NormalWS, pin.TexCoord);\n\n    // Get albedo\n    float4 albedo = AlbedoTexture.Sample(SurfaceSampler, pin.TexCoord);\n\n    // Get roughness, metalness, and ambient occlusion\n    float3 RMA = RMATexture.Sample(SurfaceSampler, pin.TexCoord);\n\n    // glTF2 defines metalness as B channel, roughness as G channel, and occlusion as R channel\n\n    // Shade surface\n    float3 color = LightSurface(V, N, 3, LightColor, LightDirection, albedo.rgb, RMA.g, RMA.b, RMA.r);\n\n    color += EmissiveTexture.Sample(SurfaceSampler, pin.TexCoord).rgb;\n\n    return float4(color, albedo.w * Alpha);\n}\n\n\n// Pixel shader: pbr (textures) + image-based lighting + velocity\n#include \"PixelPacking_Velocity.hlsli\"\n\nstruct PSOut_Velocity\n{\n    float4 color : SV_Target0;\n    packed_velocity_t velocity : SV_Target1;\n};\n\n[RootSignature(PBREffectRS)]\nPSOut_Velocity PSTexturedVelocity(VSOut_Velocity pin)\n{\n    PSOut_Velocity output;\n\n    const float3 V = normalize(EyePosition - pin.current.PositionWS.xyz); // view vector\n    const float3 L = normalize(-LightDirection[0]);                       // light vector (\"to light\" opposite of light's direction)\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(SurfaceSampler, pin.current.TexCoord).xy);\n    float3 N = PeturbNormal(localNormal, pin.current.PositionWS.xyz, pin.current.NormalWS, pin.current.TexCoord);\n\n    // Get albedo\n    float4 albedo = AlbedoTexture.Sample(SurfaceSampler, pin.current.TexCoord);\n\n    // Get roughness, metalness, and ambient occlusion\n    float3 RMA = RMATexture.Sample(SurfaceSampler, pin.current.TexCoord);\n\n    // glTF2 defines metalness as B channel, roughness as G channel, and occlusion as R channel\n\n    // Shade surface\n    float3 color = LightSurface(V, N, 3, LightColor, LightDirection, albedo.rgb, RMA.g, RMA.b, RMA.r);\n\n    output.color = float4(color, albedo.w * Alpha);\n\n    // Calculate velocity of this point\n    float4 prevPos = pin.prevPosition;\n    prevPos.xyz /= prevPos.w;\n    prevPos.xy *= float2(0.5f, -0.5f);\n    prevPos.xy += 0.5f;\n    prevPos.xy *= float2(TargetWidth, TargetHeight);\n\n    output.velocity = PackVelocity(prevPos.xyz - pin.current.PositionPS.xyz);\n\n    return output;\n}\n\n[RootSignature(PBREffectRS)]\nPSOut_Velocity PSTexturedEmissiveVelocity(VSOut_Velocity pin)\n{\n    PSOut_Velocity output;\n\n    const float3 V = normalize(EyePosition - pin.current.PositionWS.xyz); // view vector\n    const float3 L = normalize(-LightDirection[0]);                       // light vector (\"to light\" opposite of light's direction)\n\n    // Before lighting, peturb the surface's normal by the one given in normal map.\n    float3 localNormal = TwoChannelNormalX2(NormalTexture.Sample(SurfaceSampler, pin.current.TexCoord).xy);\n    float3 N = PeturbNormal(localNormal, pin.current.PositionWS.xyz, pin.current.NormalWS, pin.current.TexCoord);\n\n    // Get albedo\n    float4 albedo = AlbedoTexture.Sample(SurfaceSampler, pin.current.TexCoord);\n\n    // Get roughness, metalness, and ambient occlusion\n    float3 RMA = RMATexture.Sample(SurfaceSampler, pin.current.TexCoord);\n\n    // glTF2 defines metalness as B channel, roughness as G channel, and occlusion as R channel\n\n    // Shade surface\n    float3 color = LightSurface(V, N, 3, LightColor, LightDirection, albedo.rgb, RMA.g, RMA.b, RMA.r);\n\n    color += EmissiveTexture.Sample(SurfaceSampler, pin.current.TexCoord).rgb;\n\n    output.color = float4(color, albedo.w * Alpha);\n\n    // Calculate velocity of this point\n    float4 prevPos = pin.prevPosition;\n    prevPos.xyz /= prevPos.w;\n    prevPos.xy *= float2(0.5f, -0.5f);\n    prevPos.xy += 0.5f;\n    prevPos.xy *= float2(TargetWidth, TargetHeight);\n\n    output.velocity = PackVelocity(prevPos.xyz - pin.current.PositionPS.xyz);\n\n    return output;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/PixelPacking_Velocity.hlsli",
    "content": "//\n// Copyright (c) Microsoft. All rights reserved.\n// This code is licensed under the MIT License (MIT).\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n// Developed by Minigraph\n//\n// Author:  James Stanard \n//\n\n#ifndef __PIXEL_PACKING_VELOCITY_HLSLI__\n#define __PIXEL_PACKING_VELOCITY_HLSLI__\n\n#if 1\n// This is a custom packing that devotes 10 bits each to X and Y velocity but 12 bits to Z velocity.  Floats\n// are used instead of SNORM to increase precision around small deltas, which are the majority of deltas.\n// With TAA and Motion Blur, velocities are clamped, giving little reason to express them precisely in terms\n// of the size of the screen.\n#define packed_velocity_t uint\n\n// Designed to compress (-256.0, +256.0) with a signed 6e3 float\nuint PackXY( float x )\n{\n    uint signbit = asuint(x) >> 31;\n    x = clamp(abs(x / 32768.0), 0, asfloat(0x3BFFE000));\n    return (f32tof16(x) + 8) >> 4 | signbit << 9;\n}\n\nfloat UnpackXY( uint x )\n{\n    return f16tof32((x & 0x1FF) << 4 | (x >> 9) << 15) * 32768.0;\n}\n\n// Designed to compress (-1.0, 1.0) with a signed 8e3 float\nuint PackZ( float x )\n{\n    uint signbit = asuint(x) >> 31;\n    x = clamp(abs(x / 128.0), 0, asfloat(0x3BFFE000));\n    return (f32tof16(x) + 2) >> 2 | signbit << 11;\n}\n\nfloat UnpackZ( uint x )\n{\n    return f16tof32((x & 0x7FF) << 2 | (x >> 11) << 15) * 128.0;\n}\n\n// Pack the velocity to write to R10G10B10A2_UNORM\npacked_velocity_t PackVelocity( float3 Velocity )\n{\n    return PackXY(Velocity.x) | PackXY(Velocity.y) << 10 | PackZ(Velocity.z) << 20;\n}\n\n// Unpack the velocity from R10G10B10A2_UNORM\nfloat3 UnpackVelocity( packed_velocity_t Velocity )\n{\n    return float3(UnpackXY(Velocity & 0x3FF), UnpackXY((Velocity >> 10) & 0x3FF), UnpackZ(Velocity >> 20));\n}\n\n#elif 1\n#define packed_velocity_t float4\n\n// Pack the velocity to write to R10G10B10A2_UNORM\npacked_velocity_t PackVelocity( float3 Velocity )\n{\n    // Stretch dx,dy from [-64, 63.875] to [-512, 511] to [-0.5, 0.5) to [0, 1)\n    // Velocity.xy = (0,0) must be representable.\n    return float4(Velocity * float3(8, 8, 4096) / 1024.0 + 512 / 1023.0, 0);\n}\n\n// Unpack the velocity from R10G10B10A2_UNORM\nfloat3 UnpackVelocity( packed_velocity_t Velocity )\n{\n    return (Velocity.xyz - 512.0 / 1023.0) * float3(1024, 1024, 2) / 8.0;\n}\n#else\n#define packed_velocity_t float4\n\n// Pack the velocity to write to R16G16B16A16_FLOAT\npacked_velocity_t PackVelocity( float3 Velocity )\n{\n    return float4(Velocity * float3(16, 16, 32*1024), 0);\n}\n\n// Unpack the velocity from R10G10B10A2_UNORM\nfloat3 UnpackVelocity( packed_velocity_t Velocity )\n{\n    return Velocity.xyz / float3(16, 16, 32*1024);\n}\n\n#endif\n\n#endif // __PIXEL_PACKING_HLSLI__\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/PostProcess.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\nstatic const int MAX_SAMPLES = 16;\n\n\nTexture2D<float4> Texture : register(t0);\nsampler Sampler : register(s0);\n\n\ncbuffer Parameters : register(b0)\n{\n    float4 sampleOffsets[MAX_SAMPLES];\n    float4 sampleWeights[MAX_SAMPLES];\n};\n\n\n#include \"Structures.fxh\"\n#include \"RootSig.fxh\"\n\n\n// Vertex shader: self-created quad.\n[RootSignature(PostProcessRS)]\nVSInputTx VSQuad(uint vI : SV_VertexId)\n{\n    VSInputTx vout;\n\n    // We use the 'big triangle' optimization so you only Draw 3 verticies instead of 4.\n    float2 texcoord = float2((vI << 1) & 2, vI & 2);\n    vout.TexCoord = texcoord;\n\n    vout.Position = float4(texcoord.x * 2 - 1, -texcoord.y * 2 + 1, 0, 1);\n    return vout;\n}\n\n[RootSignature(PostProcessRSNoCB)]\nVSInputTx VSQuadNoCB(uint vI : SV_VertexId)\n{\n    return VSQuad(vI);\n}\n\n[RootSignature(DualPostProcessRS)]\nVSInputTx VSQuadDual(uint vI : SV_VertexId)\n{\n    return VSQuad(vI);\n}\n\n\n//--------------------------------------------------------------------------------------\n// Pixel shader: copy.\n[RootSignature(PostProcessRSNoCB)]\nfloat4 PSCopy(VSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord);\n    return color;\n}\n\n\n// Pixel shader: monochrome.\n[RootSignature(PostProcessRSNoCB)]\nfloat4 PSMonochrome(VSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord);\n    float3 grayscale = float3(0.2125f, 0.7154f, 0.0721f);\n    float3 output = dot(color.rgb, grayscale);\n    return float4(output, color.a);\n}\n\n\n// Pixel shader: sepia.\n[RootSignature(PostProcessRSNoCB)]\nfloat4 PSSepia(VSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord);\n\n    float3 red = float3(0.393f, 0.769f, 0.189f);\n    float3 green = float3(0.349f, 0.686f, 0.168f);\n    float3 blue = float3(0.272f, 0.534f, 0.131f);\n\n    float3 output;\n    output.r = dot(color.rgb, red);\n    output.g = dot(color.rgb, green);\n    output.b = dot(color.rgb, blue);\n    return float4(output, color.a);\n}\n\n\n// Pixel shader: down-sample 2x2.\n[RootSignature(PostProcessRS)]\nfloat4 PSDownScale2x2(VSInputTx pin) : SV_Target0\n{\n    const int NUM_SAMPLES = 4;\n    float4 vColor = 0.0f;\n\n    for( int i=0; i < NUM_SAMPLES; i++ )\n    {\n        vColor += Texture.Sample(Sampler, pin.TexCoord + sampleOffsets[i].xy);\n    }\n    \n    return vColor / NUM_SAMPLES;\n}\n\n\n// Pixel shader: down-sample 4x4.\n[RootSignature(PostProcessRS)]\nfloat4 PSDownScale4x4(VSInputTx pin) : SV_Target0\n{\n    const int NUM_SAMPLES = 16;\n    float4 vColor = 0.0f;\n\n    for (int i = 0; i < NUM_SAMPLES; i++)\n    {\n        vColor += Texture.Sample(Sampler, pin.TexCoord + sampleOffsets[i].xy);\n    }\n\n    return vColor / NUM_SAMPLES;\n}\n\n\n// Pixel shader: gaussian blur 5x5.\n[RootSignature(PostProcessRS)]\nfloat4 PSGaussianBlur5x5(VSInputTx pin) : SV_Target0\n{\n    float4 vColor = 0.0f;\n\n    for (int i = 0; i < 13; i++)\n    {\n        vColor += sampleWeights[i] * Texture.Sample(Sampler, pin.TexCoord + sampleOffsets[i].xy);\n    }\n\n    return vColor;\n}\n\n\n// Pixel shader: bloom (extract)\n[RootSignature(PostProcessRS)]\nfloat4 PSBloomExtract(VSInputTx pin) : SV_Target0\n{\n    // Uses sampleWeights[0] as 'bloom threshold'\n    float4 c = Texture.Sample(Sampler, pin.TexCoord);\n    return saturate((c - sampleWeights[0]) / (1 - sampleWeights[0]));\n}\n\n\n// Pixel shader: bloom (blur)\n[RootSignature(PostProcessRS)]\nfloat4 PSBloomBlur(VSInputTx pin) : SV_Target0\n{\n    float4 vColor = 0.0f;\n\n    // Perform a one-directional gaussian blur\n    for (int i = 0; i < 15; i++)\n    {\n        vColor += sampleWeights[i] * Texture.Sample(Sampler, pin.TexCoord + sampleOffsets[i].xy);\n    }\n\n    return vColor;\n}\n\n\n//--------------------------------------------------------------------------------------\nTexture2D<float4> Texture2 : register(t1);\n\n// Pixel shader: merge\n[RootSignature(DualPostProcessRS)]\nfloat4 PSMerge(VSInputTx pin) : SV_Target0\n{\n    float4 vColor = sampleWeights[0] * Texture.Sample(Sampler, pin.TexCoord);\n    vColor += sampleWeights[1] * Texture2.Sample(Sampler, pin.TexCoord);\n    return vColor;\n}\n\n\n// Pixel shader: bloom (combine)\nfloat4 AdjustSaturation(float4 color, float saturation)\n{\n    float3 grayscale = float3(0.2125f, 0.7154f, 0.0721f);\n    float gray = dot(color.rgb, grayscale);\n    return lerp(gray, color, saturation);\n}\n\n[RootSignature(DualPostProcessRS)]\nfloat4 PSBloomCombine(VSInputTx pin) : SV_Target0\n{\n    // Uses sampleWeights[0].x as base saturation, sampleWeights[0].y as bloom saturation\n    // Uses sampleWeights[1] as base intensity; sampleWeights[2] as bloom intensity\n    float4 base = Texture.Sample(Sampler, pin.TexCoord);\n    float4 bloom = Texture2.Sample(Sampler, pin.TexCoord);\n\n    // Adjust color saturation and intensity.\n    base = AdjustSaturation(base, sampleWeights[0].x) * sampleWeights[1];\n    bloom = AdjustSaturation(bloom, sampleWeights[0].y) * sampleWeights[2];\n\n    // Darken down the base image in areas where there is a lot of bloom,\n    // to prevent things looking excessively burned-out.\n    base *= (1 - saturate(bloom));\n\n    // Combine the two images.\n    return base + bloom;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/RootSig.fxh",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\n// Root signatures must match definition in each effect, or shaders will be recompiled on Xbox when PSO loads\n#define NoTextureRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"CBV(b0)\"\n\n#define MainRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"CBV(b0),\"\\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define DualTextureRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( Sampler(s1), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"CBV(b0)\"\n\n#define NormalMapRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"CBV(b0),\" \\\n\"DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define NormalMapRSNoSpec \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),\" \\\n\"CBV(b0)\"\n\n#define GenerateMipsRS \\\n\"RootFlags ( DENY_VERTEX_SHADER_ROOT_ACCESS   |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS   |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS     |\" \\\n\"            DENY_PIXEL_SHADER_ROOT_ACCESS ),\" \\\n\"RootConstants(num32BitConstants=3, b0),\" \\\n\"DescriptorTable ( SRV(t0) ),\" \\\n\"DescriptorTable ( UAV(u0) ),\" \\\n\"StaticSampler(s0,\"\\\n\"           filter =   FILTER_MIN_MAG_LINEAR_MIP_POINT,\"\\\n\"           addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressW = TEXTURE_ADDRESS_CLAMP )\"\n\n#define SpriteStaticRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"CBV(b0), \"\\\n\"StaticSampler(s0,\"\\\n\"           filter = FILTER_MIN_MAG_MIP_LINEAR,\"\\\n\"           addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressW = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define SpriteHeapRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"CBV(b0), \" \\\n\"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define PostProcessRS \\\n\"RootFlags ( DENY_VERTEX_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"CBV(b0, visibility = SHADER_VISIBILITY_PIXEL ), \" \\\n\"StaticSampler(s0,\"\\\n\"           filter =   FILTER_MIN_MAG_MIP_LINEAR,\"\\\n\"           addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressW = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define PostProcessRSNoCB \\\n\"RootFlags ( DENY_VERTEX_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"StaticSampler(s0,\"\\\n\"           filter =   FILTER_MIN_MAG_MIP_LINEAR,\"\\\n\"           addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressW = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define DualPostProcessRS \\\n\"RootFlags ( DENY_VERTEX_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"CBV(b0, visibility = SHADER_VISIBILITY_PIXEL ), \" \\\n\"StaticSampler(s0,\"\\\n\"           filter =   FILTER_MIN_MAG_MIP_LINEAR,\"\\\n\"           addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressW = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define ToneMapRS \\\n\"RootFlags ( DENY_VERTEX_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),\"\\\n\"CBV(b0, visibility = SHADER_VISIBILITY_PIXEL ), \" \\\n\"StaticSampler(s0,\"\\\n\"           filter =   FILTER_MIN_MAG_MIP_POINT,\"\\\n\"           addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           addressW = TEXTURE_ADDRESS_CLAMP,\"\\\n\"           visibility = SHADER_VISIBILITY_PIXEL )\"\n\n#define PBREffectRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"DescriptorTable ( SRV(t0) ),\"\\\n\"DescriptorTable ( SRV(t1) ),\"\\\n\"DescriptorTable ( SRV(t2) ),\"\\\n\"DescriptorTable ( SRV(t3) ),\"\\\n\"DescriptorTable ( SRV(t4) ),\"\\\n\"DescriptorTable ( SRV(t5) ),\"\\\n\"DescriptorTable ( Sampler(s0) ),\"\\\n\"DescriptorTable ( Sampler(s1) ),\"\\\n\"CBV(b0)\"\n\n#define DebugEffectRS \\\n\"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\" \\\n\"            DENY_DOMAIN_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |\" \\\n\"            DENY_HULL_SHADER_ROOT_ACCESS ),\" \\\n\"CBV(b0)\"\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/SkinnedEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\nTexture2D<float4> Texture : register(t0);\nsampler Sampler : register(s0);\n\n\ncbuffer Parameters : register(b0)\n{\n    float4 DiffuseColor             : packoffset(c0);\n    float3 EmissiveColor            : packoffset(c1);\n    float3 SpecularColor            : packoffset(c2);\n    float  SpecularPower            : packoffset(c2.w);\n\n    float3 LightDirection[3]        : packoffset(c3);\n    float3 LightDiffuseColor[3]     : packoffset(c6);\n    float3 LightSpecularColor[3]    : packoffset(c9);\n\n    float3 EyePosition              : packoffset(c12);\n\n    float3 FogColor                 : packoffset(c13);\n    float4 FogVector                : packoffset(c14);\n\n    float4x4 World                  : packoffset(c15);\n    float3x3 WorldInverseTranspose  : packoffset(c19);\n    float4x4 WorldViewProj          : packoffset(c22);\n\n    float4x3 Bones[72]              : packoffset(c26);\n};\n\n\n#include \"Structures.fxh\"\n#include \"Common.fxh\"\n#include \"RootSig.fxh\"\n#include \"Lighting.fxh\"\n#include \"Utilities.fxh\"\n\n[RootSignature(MainRS)]\nfloat3 Skin(inout VSInputNmTxWeights vin, float3 normal, uniform int boneCount)\n{\n    float4x3 skinning = 0;\n\n    [unroll]\n    for (int i = 0; i < boneCount; i++)\n    {\n        skinning += Bones[vin.Indices[i]] * vin.Weights[i];\n    }\n\n    vin.Position.xyz = mul(vin.Position, skinning);\n    return mul(normal, (float3x3)skinning);\n}\n\n\n// Vertex shader: vertex lighting, one bone.\n[RootSignature(MainRS)]\nVSOutputTx VSSkinnedVertexLightingOneBone(VSInputNmTxWeights vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = Skin(vin, vin.Normal, 1);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputTx VSSkinnedVertexLightingOneBoneBn(VSInputNmTxWeights vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    normal = Skin(vin, normal, 1);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex lighting, two bones.\n[RootSignature(MainRS)]\nVSOutputTx VSSkinnedVertexLightingTwoBones(VSInputNmTxWeights vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = Skin(vin, vin.Normal, 2);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputTx VSSkinnedVertexLightingTwoBonesBn(VSInputNmTxWeights vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    normal = Skin(vin, normal, 2);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: vertex lighting, four bones.\n[RootSignature(MainRS)]\nVSOutputTx VSSkinnedVertexLightingFourBones(VSInputNmTxWeights vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = Skin(vin, vin.Normal, 4);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputTx VSSkinnedVertexLightingFourBonesBn(VSInputNmTxWeights vin)\n{\n    VSOutputTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    normal = Skin(vin, normal, 4);\n\n    CommonVSOutput cout = ComputeCommonVSOutputWithLighting(vin.Position, normal, 3);\n    SetCommonVSOutputParams;\n\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting, one bone.\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSSkinnedPixelLightingOneBone(VSInputNmTxWeights vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = Skin(vin, vin.Normal, 1);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSSkinnedPixelLightingOneBoneBn(VSInputNmTxWeights vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    normal = Skin(vin, normal, 1);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting, two bones.\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSSkinnedPixelLightingTwoBones(VSInputNmTxWeights vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = Skin(vin, vin.Normal, 2);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSSkinnedPixelLightingTwoBonesBn(VSInputNmTxWeights vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    normal = Skin(vin, normal, 2);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Vertex shader: pixel lighting, four bones.\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSSkinnedPixelLightingFourBones(VSInputNmTxWeights vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = Skin(vin, vin.Normal, 4);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n[RootSignature(MainRS)]\nVSOutputPixelLightingTx VSSkinnedPixelLightingFourBonesBn(VSInputNmTxWeights vin)\n{\n    VSOutputPixelLightingTx vout;\n\n    float3 normal = BiasX2(vin.Normal);\n\n    normal = Skin(vin, normal, 4);\n\n    CommonVSOutputPixelLighting cout = ComputeCommonVSOutputPixelLighting(vin.Position, normal);\n    SetCommonVSOutputParamsPixelLighting;\n\n    vout.Diffuse = float4(1, 1, 1, DiffuseColor.a);\n    vout.TexCoord = vin.TexCoord;\n\n    return vout;\n}\n\n\n// Pixel shader: vertex lighting.\n[RootSignature(MainRS)]\nfloat4 PSSkinnedVertexLighting(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    AddSpecular(color, pin.Specular.rgb);\n    ApplyFog(color, pin.Specular.w);\n\n    return color;\n}\n\n\n// Pixel shader: vertex lighting, no fog.\n[RootSignature(MainRS)]\nfloat4 PSSkinnedVertexLightingNoFog(PSInputTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    AddSpecular(color, pin.Specular.rgb);\n\n    return color;\n}\n\n\n// Pixel shader: pixel lighting.\n[RootSignature(MainRS)]\nfloat4 PSSkinnedPixelLighting(PSInputPixelLightingTx pin) : SV_Target0\n{\n    float4 color = Texture.Sample(Sampler, pin.TexCoord) * pin.Diffuse;\n\n    float3 eyeVector = normalize(EyePosition - pin.PositionWS.xyz);\n    float3 worldNormal = normalize(pin.NormalWS);\n\n    ColorPair lightResult = ComputeLights(eyeVector, worldNormal, 3);\n\n    color.rgb *= lightResult.Diffuse;\n\n    AddSpecular(color, lightResult.Specular);\n    ApplyFog(color, pin.PositionWS.w);\n\n    return color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/SpriteEffect.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n#include \"Structures.fxh\"\n#include \"RootSig.fxh\"\n\nTexture2D<float4> Texture : register(t0);\nsampler TextureSampler : register(s0);\n\n\ncbuffer Parameters : register(b0)\n{\n    row_major float4x4 MatrixTransform;\n};\n\n[RootSignature(SpriteStaticRS)]\nvoid SpriteVertexShader(inout float4 color    : COLOR0,\n                        inout float2 texCoord : TEXCOORD0,\n                        inout float4 position : SV_Position)\n{\n    position = mul(position, MatrixTransform);\n}\n\n[RootSignature(SpriteStaticRS)]\nfloat4 SpritePixelShader(float4 color    : COLOR0,\n                         float2 texCoord : TEXCOORD0) : SV_Target0\n{\n    return Texture.Sample(TextureSampler, texCoord) * color;\n}\n\n[RootSignature(SpriteHeapRS)]\nvoid SpriteVertexShaderHeap(inout float4 color    : COLOR0,\n    inout float2 texCoord : TEXCOORD0,\n    inout float4 position : SV_Position)\n{\n    position = mul(position, MatrixTransform);\n}\n\n[RootSignature(SpriteHeapRS)]\nfloat4 SpritePixelShaderHeap(float4 color    : COLOR0,\n    float2 texCoord : TEXCOORD0) : SV_Target0\n{\n    return Texture.Sample(TextureSampler, texCoord) * color;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/Structures.fxh",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n// http://create.msdn.com/en-US/education/catalog/sample/stock_effects\n\n\n// Vertex shader input structures.\n\nstruct VSInput\n{\n    float4 Position : SV_Position;\n};\n\nstruct VSInputVc\n{\n    float4 Position : SV_Position;\n    float4 Color    : COLOR;\n};\n\nstruct VSInputTx\n{\n    float4 Position : SV_Position;\n    float2 TexCoord : TEXCOORD0;\n};\n\nstruct VSInputTxVc\n{\n    float4 Position : SV_Position;\n    float2 TexCoord : TEXCOORD0;\n    float4 Color    : COLOR;\n};\n\nstruct VSInputNm\n{\n    float4 Position : SV_Position;\n    float3 Normal   : NORMAL;\n};\n\nstruct VSInputNmVc\n{\n    float4 Position : SV_Position;\n    float3 Normal   : NORMAL;\n    float4 Color    : COLOR;\n};\n\nstruct VSInputNmTx\n{\n    float4 Position : SV_Position;\n    float3 Normal   : NORMAL;\n    float2 TexCoord : TEXCOORD0;\n};\n\nstruct VSInputNmTxVc\n{\n    float4 Position : SV_Position;\n    float3 Normal   : NORMAL;\n    float2 TexCoord : TEXCOORD0;\n    float4 Color    : COLOR;\n};\n\nstruct VSInputTx2\n{\n    float4 Position  : SV_Position;\n    float2 TexCoord  : TEXCOORD0;\n    float2 TexCoord2 : TEXCOORD1;\n};\n\nstruct VSInputTx2Vc\n{\n    float4 Position  : SV_Position;\n    float2 TexCoord  : TEXCOORD0;\n    float2 TexCoord2 : TEXCOORD1;\n    float4 Color     : COLOR;\n};\n\nstruct VSInputNmTxWeights\n{\n    float4 Position : SV_Position;\n    float3 Normal   : NORMAL;\n    float2 TexCoord : TEXCOORD0;\n    uint4  Indices  : BLENDINDICES0;\n    float4 Weights  : BLENDWEIGHT0;\n};\n\n\n\n// Vertex shader output structures.\n\nstruct VSOutput\n{\n    float4 Diffuse    : COLOR0;\n    float4 Specular   : COLOR1;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputNoFog\n{\n    float4 Diffuse    : COLOR0;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputTx\n{\n    float4 Diffuse    : COLOR0;\n    float4 Specular   : COLOR1;\n    float2 TexCoord   : TEXCOORD0;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputTxNoFog\n{\n    float4 Diffuse    : COLOR0;\n    float2 TexCoord   : TEXCOORD0;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputPixelLighting\n{\n    float4 PositionWS : TEXCOORD0;\n    float3 NormalWS   : TEXCOORD1;\n    float4 Diffuse    : COLOR0;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputPixelLightingTx\n{\n    float2 TexCoord   : TEXCOORD0;\n    float4 PositionWS : TEXCOORD1;\n    float3 NormalWS   : TEXCOORD2;\n    float4 Diffuse    : COLOR0;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputTx2\n{\n    float4 Diffuse    : COLOR0;\n    float4 Specular   : COLOR1;\n    float2 TexCoord   : TEXCOORD0;\n    float2 TexCoord2  : TEXCOORD1;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputTx2NoFog\n{\n    float4 Diffuse    : COLOR0;\n    float2 TexCoord   : TEXCOORD0;\n    float2 TexCoord2  : TEXCOORD1;\n    float4 PositionPS : SV_Position;\n};\n\nstruct VSOutputTxEnvMap\n{\n    float4 Diffuse    : COLOR0;\n    float4 Specular   : COLOR1;\n    float2 TexCoord   : TEXCOORD0;\n    float3 EnvCoord   : TEXCOORD1;\n    float4 PositionPS : SV_Position;\n};\n\n\n\n// Pixel shader input structures.\n\nstruct PSInput\n{\n    float4 Diffuse  : COLOR0;\n    float4 Specular : COLOR1;\n};\n\nstruct PSInputNoFog\n{\n    float4 Diffuse : COLOR0;\n};\n\nstruct PSInputTx\n{\n    float4 Diffuse  : COLOR0;\n    float4 Specular : COLOR1;\n    float2 TexCoord : TEXCOORD0;\n};\n\nstruct PSInputTxNoFog\n{\n    float4 Diffuse  : COLOR0;\n    float2 TexCoord : TEXCOORD0;\n};\n\nstruct PSInputPixelLighting\n{\n    float4 PositionWS : TEXCOORD0;\n    float3 NormalWS   : TEXCOORD1;\n    float4 Diffuse    : COLOR0;\n};\n\nstruct PSInputPixelLightingTx\n{\n    float2 TexCoord   : TEXCOORD0;\n    float4 PositionWS : TEXCOORD1;\n    float3 NormalWS   : TEXCOORD2;\n    float4 Diffuse    : COLOR0;\n};\n\nstruct PSInputTx2\n{\n    float4 Diffuse   : COLOR0;\n    float4 Specular  : COLOR1;\n    float2 TexCoord  : TEXCOORD0;\n    float2 TexCoord2 : TEXCOORD1;\n};\n\nstruct PSInputTx2NoFog\n{\n    float4 Diffuse   : COLOR0;\n    float2 TexCoord  : TEXCOORD0;\n    float2 TexCoord2 : TEXCOORD1;\n};\n\nstruct PSInputTxEnvMap\n{\n    float4 Diffuse  : COLOR0;\n    float4 Specular : COLOR1;\n    float2 TexCoord : TEXCOORD0;\n    float3 EnvCoord : TEXCOORD1;\n};\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/ToneMap.fx",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\nTexture2D<float4> HDRTexture : register(t0);\nsampler Sampler : register(s0);\n\n\ncbuffer Parameters : register(b0)\n{\n    float linearExposure : packoffset(c0.x);\n    float paperWhiteNits : packoffset(c0.y);\n};\n\n\n#include \"Structures.fxh\"\n#include \"RootSig.fxh\"\n#include \"Utilities.fxh\"\n\n\n// Vertex shader: self-created quad.\n[RootSignature(ToneMapRS)]\nVSInputTx VSQuad(uint vI : SV_VertexId)\n{\n    VSInputTx vout;\n\n    // We use the 'big triangle' optimization so you only Draw 3 verticies instead of 4.\n    float2 texcoord = float2((vI << 1) & 2, vI & 2);\n    vout.TexCoord = texcoord;\n\n    vout.Position = float4(texcoord.x * 2 - 1, -texcoord.y * 2 + 1, 0, 1);\n    return vout;\n}\n\n\n//--------------------------------------------------------------------------------------\n// Pixel shader: pass-through\n[RootSignature(ToneMapRS)]\nfloat4 PSCopy(VSInputTx pin) : SV_Target0\n{\n    return HDRTexture.Sample(Sampler, pin.TexCoord);\n}\n\n\n// Pixel shader: saturate (clips above 1.0)\n[RootSignature(ToneMapRS)]\nfloat4 PSSaturate(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 sdr = saturate(hdr.xyz * linearExposure);\n    return float4(sdr, hdr.a);\n}\n\n\n// Pixel shader: reinhard operator\n[RootSignature(ToneMapRS)]\nfloat4 PSReinhard(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 sdr = ToneMapReinhard(hdr.xyz * linearExposure);\n    return float4(sdr, hdr.a);\n}\n\n\n// Pixel shader: ACES filmic operator\n[RootSignature(ToneMapRS)]\nfloat4 PSACESFilmic(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 sdr = ToneMapACESFilmic(hdr.xyz * linearExposure);\n    return float4(sdr, hdr.a);\n}\n\n\n//--------------------------------------------------------------------------------------\n// SRGB, using Rec.709 color primaries and a gamma 2.2 curve\n\n// Pixel shader: sRGB\n[RootSignature(ToneMapRS)]\nfloat4 PS_SRGB(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 srgb = LinearToSRGBEst(hdr.xyz);\n    return float4(srgb, hdr.a);\n}\n\n\n// Pixel shader: saturate (clips above 1.0)\n[RootSignature(ToneMapRS)]\nfloat4 PSSaturate_SRGB(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 sdr = saturate(hdr.xyz * linearExposure);\n    float3 srgb = LinearToSRGBEst(sdr);\n    return float4(srgb, hdr.a);\n}\n\n\n// Pixel shader: reinhard operator\n[RootSignature(ToneMapRS)]\nfloat4 PSReinhard_SRGB(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 sdr = ToneMapReinhard(hdr.xyz * linearExposure);\n    float3 srgb = LinearToSRGBEst(sdr);\n    return float4(srgb, hdr.a);\n}\n\n\n// Pixel shader: ACES filmic operator\n[RootSignature(ToneMapRS)]\nfloat4 PSACESFilmic_SRGB(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 sdr = ToneMapACESFilmic(hdr.xyz * linearExposure);\n    float3 srgb = LinearToSRGBEst(sdr);\n    return float4(srgb, hdr.a);\n}\n\n\n//--------------------------------------------------------------------------------------\n// HDR10, using Rec.2020 color primaries and ST.2084 curve\n\nfloat3 HDR10(float3 color)\n{\n    // Rotate from Rec.709 to Rec.2020 primaries\n    float3 rgb = mul(from709to2020, color);\n\n    // ST.2084 spec defines max nits as 10,000 nits\n    float3 normalized = rgb * paperWhiteNits / 10000.f;\n\n    // Apply ST.2084 curve\n    return LinearToST2084(normalized);\n}\n\n[RootSignature(ToneMapRS)]\nfloat4 PSHDR10(VSInputTx pin) : SV_Target0\n{\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    return float4(rgb, hdr.a);\n}\n\n\n//--------------------------------------------------------------------------------------\nstruct MRTOut\n{\n    float4 hdr : SV_Target0;\n    float4 sdr : SV_Target1;\n};\n\n[RootSignature(ToneMapRS)]\nMRTOut PSHDR10_Saturate(VSInputTx pin)\n{\n    MRTOut output;\n\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    output.hdr = float4(rgb, hdr.a);\n\n    float3 sdr = saturate(hdr.xyz * linearExposure);\n    output.sdr = float4(sdr, hdr.a);\n\n    return output;\n}\n\n[RootSignature(ToneMapRS)]\nMRTOut PSHDR10_Reinhard(VSInputTx pin)\n{\n    MRTOut output;\n\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    output.hdr = float4(rgb, hdr.a);\n\n    float3 sdr = ToneMapReinhard(hdr.xyz * linearExposure);\n    output.sdr = float4(sdr, hdr.a);\n\n    return output;\n}\n\n[RootSignature(ToneMapRS)]\nMRTOut PSHDR10_ACESFilmic(VSInputTx pin)\n{\n    MRTOut output;\n\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    output.hdr = float4(rgb, hdr.a);\n\n    float3 sdr = ToneMapACESFilmic(hdr.xyz * linearExposure);\n    output.sdr = float4(sdr, hdr.a);\n\n    return output;\n}\n\n[RootSignature(ToneMapRS)]\nMRTOut PSHDR10_Saturate_SRGB(VSInputTx pin)\n{\n    MRTOut output;\n\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    output.hdr = float4(rgb, hdr.a);\n\n    float3 sdr = saturate(hdr.xyz * linearExposure);\n    float3 srgb = LinearToSRGBEst(sdr);\n    output.sdr = float4(srgb, hdr.a);\n\n    return output;\n}\n\n[RootSignature(ToneMapRS)]\nMRTOut PSHDR10_Reinhard_SRGB(VSInputTx pin)\n{\n    MRTOut output;\n\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    output.hdr = float4(rgb, hdr.a);\n\n    float3 sdr = ToneMapReinhard(hdr.xyz * linearExposure);\n    float3 srgb = LinearToSRGBEst(sdr);\n    output.sdr = float4(srgb, hdr.a);\n\n    return output;\n}\n\n[RootSignature(ToneMapRS)]\nMRTOut PSHDR10_ACESFilmic_SRGB(VSInputTx pin)\n{\n    MRTOut output;\n\n    float4 hdr = HDRTexture.Sample(Sampler, pin.TexCoord);\n    float3 rgb = HDR10(hdr.xyz);\n    output.hdr = float4(rgb, hdr.a);\n\n    float3 sdr = ToneMapACESFilmic(hdr.xyz * linearExposure);\n    float3 srgb = LinearToSRGBEst(sdr);\n    output.sdr = float4(srgb, hdr.a);\n\n    return output;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/Shaders/Utilities.fxh",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n\n\nfloat3 BiasX2(float3 x)\n{\n   return 2.0f * x - 1.0f;\n}\n\nfloat3 BiasD2(float3 x)\n{\n   return 0.5f * x + 0.5f;\n}\n\n\n// Christian Schuler, \"Normal Mapping without Precomputed Tangents\", ShaderX 5, Chapter 2.6, pp. 131-140\n// See also follow-up blog post: http://www.thetenthplanet.de/archives/1180\nfloat3x3 CalculateTBN(float3 p, float3 n, float2 tex)\n{\n    float3 dp1 = ddx(p);\n    float3 dp2 = ddy(p);\n    float2 duv1 = ddx(tex);\n    float2 duv2 = ddy(tex);\n\n    float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2));\n    float2x3 inverseM = float2x3(cross(M[1], M[2]), cross(M[2], M[0]));\n    float3 t = normalize(mul(float2(duv1.x, duv2.x), inverseM));\n    float3 b = normalize(mul(float2(duv1.y, duv2.y), inverseM));\n    return float3x3(t, b, n);\n}\n\nfloat3 PeturbNormal(float3 localNormal, float3 position, float3 normal, float2 texCoord)\n{\n    const float3x3 TBN = CalculateTBN(position, normal, texCoord);\n    return normalize(mul(localNormal, TBN));\n}\n\nfloat3 TwoChannelNormalX2(float2 normal)\n{\n    float2 xy = 2.0f * normal - 1.0f;\n    float z = sqrt(1 - dot(xy, xy));\n    return float3(xy.x, xy.y, z);\n}\n\n\n// sRGB \n// https://en.wikipedia.org/wiki/SRGB\n\n// Apply the (approximate) sRGB curve to linear values\nfloat3 LinearToSRGBEst(float3 color)\n{\n    return pow(abs(color), 1/2.2f);\n}\n\n\n// (Approximate) sRGB to linear\nfloat3 SRGBToLinearEst(float3 srgb)\n{\n    return pow(abs(srgb), 2.2f);\n}\n\n\n// HDR10 Media Profile\n// https://en.wikipedia.org/wiki/High-dynamic-range_video#HDR10\n\n\n// Color rotation matrix to rotate Rec.709 color primaries into Rec.2020\nstatic const float3x3 from709to2020 =\n{\n    { 0.6274040f, 0.3292820f, 0.0433136f },\n    { 0.0690970f, 0.9195400f, 0.0113612f },\n    { 0.0163916f, 0.0880132f, 0.8955950f }\n};\n\n\n// Apply the ST.2084 curve to normalized linear values and outputs normalized non-linear values\nfloat3 LinearToST2084(float3 normalizedLinearValue)\n{\n    return pow((0.8359375f + 18.8515625f * pow(abs(normalizedLinearValue), 0.1593017578f)) / (1.0f + 18.6875f * pow(abs(normalizedLinearValue), 0.1593017578f)), 78.84375f);\n}\n\n\n// ST.2084 to linear, resulting in a linear normalized value\nfloat3 ST2084ToLinear(float3 ST2084)\n{\n    return pow(max(pow(abs(ST2084), 1.0f / 78.84375f) - 0.8359375f, 0.0f) / (18.8515625f - 18.6875f * pow(abs(ST2084), 1.0f / 78.84375f)), 1.0f / 0.1593017578f);\n}\n\n\n// Reinhard tonemap operator\n// Reinhard et al. \"Photographic tone reproduction for digital images.\" ACM Transactions on Graphics. 21. 2002.\n// http://www.cs.utah.edu/~reinhard/cdrom/tonemap.pdf\nfloat3 ToneMapReinhard(float3 color)\n{\n    return color / (1.0f + color);\n}\n\n\n// ACES Filmic tonemap operator\n// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/\nfloat3 ToneMapACESFilmic(float3 x)\n{\n    float a = 2.51f;\n    float b = 0.03f;\n    float c = 2.43f;\n    float d = 0.59f;\n    float e = 0.14f;\n    return saturate((x*(a*x+b))/(x*(c*x+d)+e));\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/SharedResourcePool.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: SharedResourcePool.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <map>\n#include <memory>\n\n#include \"PlatformHelpers.h\"\n\n\nnamespace DirectX\n{\n    // Pool manager ensures that only a single TData instance is created for each unique TKey.\n    // This is used to avoid duplicate resource creation, so that for instance a caller can\n    // create any number of SpriteBatch instances, but these can internally share shaders and\n    // vertex buffer if more than one SpriteBatch uses the same underlying D3D device.\n    template<typename TKey, typename TData, typename... TConstructorArgs>\n    class SharedResourcePool\n    {\n    public:\n        SharedResourcePool() noexcept(false)\n            : mResourceMap(std::make_shared<ResourceMap>())\n        { }\n\n        SharedResourcePool(SharedResourcePool const&) = delete;\n        SharedResourcePool& operator= (SharedResourcePool const&) = delete;\n\n        // Allocates or looks up the shared TData instance for the specified key.\n        std::shared_ptr<TData> DemandCreate(TKey key, TConstructorArgs... args)\n        {\n            std::lock_guard<std::mutex> lock(mResourceMap->mutex);\n\n            // Return an existing instance?\n            auto pos = mResourceMap->find(key);\n\n            if (pos != mResourceMap->end())\n            {\n                auto existingValue = pos->second.lock();\n\n                if (existingValue)\n                    return existingValue;\n                else\n                    mResourceMap->erase(pos);\n            }\n\n            // Allocate a new instance.\n            auto newValue = std::make_shared<WrappedData>(key, mResourceMap, args...);\n\n            auto entry = std::make_pair(key, newValue);\n            mResourceMap->insert(entry);\n\n            return std::move(newValue);\n        }\n\n\n    private:\n        // Keep track of all allocated TData instances.\n        struct ResourceMap : public std::map<TKey, std::weak_ptr<TData>>\n        {\n            std::mutex mutex;\n        };\n\n        std::shared_ptr<ResourceMap> mResourceMap;\n\n\n        // Wrap TData with our own subclass, so we can hook the destructor\n        // to remove instances from our pool before they are freed.\n        struct WrappedData : public TData\n        {\n            WrappedData(TKey key, std::shared_ptr<ResourceMap> const& resourceMap, TConstructorArgs... args)\n                : TData(key, args...),\n                mKey(key),\n                mResourceMap(resourceMap)\n            { }\n\n            WrappedData(WrappedData&&) = default;\n            WrappedData& operator= (WrappedData&&) = default;\n\n            WrappedData(WrappedData const&) = delete;\n            WrappedData& operator= (WrappedData const&) = delete;\n\n            ~WrappedData()\n            {\n                std::lock_guard<std::mutex> lock(mResourceMap->mutex);\n\n                auto pos = mResourceMap->find(mKey);\n\n                // Check for weak reference expiry before erasing, in case DemandCreate runs on\n                // a different thread at the same time as a previous instance is being destroyed.\n                // We mustn't erase replacement objects that have just been added!\n                if (pos != mResourceMap->end() && pos->second.expired())\n                {\n                    mResourceMap->erase(pos);\n                }\n            }\n\n            TKey mKey;\n            std::shared_ptr<ResourceMap> mResourceMap;\n        };\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/SimpleMath.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// SimpleMath.cpp -- Simplified C++ Math wrapper for DirectXMath\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//-------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"SimpleMath.h\"\n\n/****************************************************************************\n *\n * Constants\n *\n ****************************************************************************/\n\nnamespace DirectX\n{\n    namespace SimpleMath\n    {\n        const Vector2 Vector2::Zero = { 0.f, 0.f };\n        const Vector2 Vector2::One = { 1.f, 1.f };\n        const Vector2 Vector2::UnitX = { 1.f, 0.f };\n        const Vector2 Vector2::UnitY = { 0.f, 1.f };\n\n        const Vector3 Vector3::Zero = { 0.f, 0.f, 0.f };\n        const Vector3 Vector3::One = { 1.f, 1.f, 1.f };\n        const Vector3 Vector3::UnitX = { 1.f, 0.f, 0.f };\n        const Vector3 Vector3::UnitY = { 0.f, 1.f, 0.f };\n        const Vector3 Vector3::UnitZ = { 0.f, 0.f, 1.f };\n        const Vector3 Vector3::Up = { 0.f, 1.f, 0.f };\n        const Vector3 Vector3::Down = { 0.f, -1.f, 0.f };\n        const Vector3 Vector3::Right = { 1.f, 0.f, 0.f };\n        const Vector3 Vector3::Left = { -1.f, 0.f, 0.f };\n        const Vector3 Vector3::Forward = { 0.f, 0.f, -1.f };\n        const Vector3 Vector3::Backward = { 0.f, 0.f, 1.f };\n\n        const Vector4 Vector4::Zero = { 0.f, 0.f, 0.f, 0.f };\n        const Vector4 Vector4::One = { 1.f, 1.f, 1.f, 1.f };\n        const Vector4 Vector4::UnitX = { 1.f, 0.f, 0.f, 0.f };\n        const Vector4 Vector4::UnitY = { 0.f, 1.f, 0.f, 0.f };\n        const Vector4 Vector4::UnitZ = { 0.f, 0.f, 1.f, 0.f };\n        const Vector4 Vector4::UnitW = { 0.f, 0.f, 0.f, 1.f };\n\n        const Matrix Matrix::Identity = { 1.f, 0.f, 0.f, 0.f,\n                                          0.f, 1.f, 0.f, 0.f,\n                                          0.f, 0.f, 1.f, 0.f,\n                                          0.f, 0.f, 0.f, 1.f };\n\n        const Quaternion Quaternion::Identity = { 0.f, 0.f, 0.f, 1.f };\n    }\n}\n\n\n/****************************************************************************\n *\n * Viewport\n *\n ****************************************************************************/\n\n#if defined(__d3d11_h__) || defined(__d3d11_x_h__)\nstatic_assert(sizeof(DirectX::SimpleMath::Viewport) == sizeof(D3D11_VIEWPORT), \"Size mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, x) == offsetof(D3D11_VIEWPORT, TopLeftX), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, y) == offsetof(D3D11_VIEWPORT, TopLeftY), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, width) == offsetof(D3D11_VIEWPORT, Width), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, height) == offsetof(D3D11_VIEWPORT, Height), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, minDepth) == offsetof(D3D11_VIEWPORT, MinDepth), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, maxDepth) == offsetof(D3D11_VIEWPORT, MaxDepth), \"Layout mismatch\");\n#endif\n\n#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)\nstatic_assert(sizeof(DirectX::SimpleMath::Viewport) == sizeof(D3D12_VIEWPORT), \"Size mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, x) == offsetof(D3D12_VIEWPORT, TopLeftX), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, y) == offsetof(D3D12_VIEWPORT, TopLeftY), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, width) == offsetof(D3D12_VIEWPORT, Width), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, height) == offsetof(D3D12_VIEWPORT, Height), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, minDepth) == offsetof(D3D12_VIEWPORT, MinDepth), \"Layout mismatch\");\nstatic_assert(offsetof(DirectX::SimpleMath::Viewport, maxDepth) == offsetof(D3D12_VIEWPORT, MaxDepth), \"Layout mismatch\");\n#endif\n\nRECT DirectX::SimpleMath::Viewport::ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, int outputWidth, int outputHeight) noexcept\n{\n    RECT rct = {};\n\n    switch (int(scaling))\n    {\n        case DXGI_SCALING_STRETCH:\n            // Output fills the entire window area\n            rct.top = 0;\n            rct.left = 0;\n            rct.right = outputWidth;\n            rct.bottom = outputHeight;\n            break;\n\n        case 2 /*DXGI_SCALING_ASPECT_RATIO_STRETCH*/:\n            // Output fills the window area but respects the original aspect ratio, using pillar boxing or letter boxing as required\n            // Note: This scaling option is not supported for legacy Win32 windows swap chains\n        {\n            assert(backBufferHeight > 0);\n            float aspectRatio = float(backBufferWidth) / float(backBufferHeight);\n\n            // Horizontal fill\n            float scaledWidth = float(outputWidth);\n            float scaledHeight = float(outputWidth) / aspectRatio;\n            if (scaledHeight >= float(outputHeight))\n            {\n                // Do vertical fill\n                scaledWidth = float(outputHeight) * aspectRatio;\n                scaledHeight = float(outputHeight);\n            }\n\n            float offsetX = (float(outputWidth) - scaledWidth) * 0.5f;\n            float offsetY = (float(outputHeight) - scaledHeight) * 0.5f;\n\n            rct.left = static_cast<LONG>(offsetX);\n            rct.top = static_cast<LONG>(offsetY);\n            rct.right = static_cast<LONG>(offsetX + scaledWidth);\n            rct.bottom = static_cast<LONG>(offsetY + scaledHeight);\n\n            // Clip to display window\n            rct.left = std::max<LONG>(0, rct.left);\n            rct.top = std::max<LONG>(0, rct.top);\n            rct.right = std::min<LONG>(outputWidth, rct.right);\n            rct.bottom = std::min<LONG>(outputHeight, rct.bottom);\n        }\n        break;\n\n        case DXGI_SCALING_NONE:\n        default:\n            // Output is displayed in the upper left corner of the window area\n            rct.top = 0;\n            rct.left = 0;\n            rct.right = std::min<LONG>(static_cast<LONG>(backBufferWidth), outputWidth);\n            rct.bottom = std::min<LONG>(static_cast<LONG>(backBufferHeight), outputHeight);\n            break;\n    }\n\n    return rct;\n}\n\nRECT DirectX::SimpleMath::Viewport::ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight) noexcept\n{\n    float safew = (float(backBufferWidth) + 19.f) / 20.f;\n    float safeh = (float(backBufferHeight) + 19.f) / 20.f;\n\n    RECT rct;\n    rct.left = static_cast<LONG>(safew);\n    rct.top = static_cast<LONG>(safeh);\n    rct.right = static_cast<LONG>(float(backBufferWidth) - safew + 0.5f);\n    rct.bottom = static_cast<LONG>(float(backBufferHeight) - safeh + 0.5f);\n\n    return rct;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/SkinnedEffect.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SkinnedEffect.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"EffectCommon.h\"\n\nusing namespace DirectX;\n\nnamespace\n{\n    // Constant buffer layout. Must match the shader!\n    struct SkinnedEffectConstants\n    {\n        XMVECTOR diffuseColor;\n        XMVECTOR emissiveColor;\n        XMVECTOR specularColorAndPower;\n\n        XMVECTOR lightDirection[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightDiffuseColor[IEffectLights::MaxDirectionalLights];\n        XMVECTOR lightSpecularColor[IEffectLights::MaxDirectionalLights];\n\n        XMVECTOR eyePosition;\n\n        XMVECTOR fogColor;\n        XMVECTOR fogVector;\n\n        XMMATRIX world;\n        XMVECTOR worldInverseTranspose[3];\n        XMMATRIX worldViewProj;\n\n        XMVECTOR bones[SkinnedEffect::MaxBones][3];\n    };\n\n    static_assert((sizeof(SkinnedEffectConstants) % 16) == 0, \"CB size not padded correctly\");\n\n\n    // Traits type describes our characteristics to the EffectBase template.\n    struct SkinnedEffectTraits\n    {\n        using ConstantBufferType = SkinnedEffectConstants;\n\n        static constexpr int VertexShaderCount = 4;\n        static constexpr int PixelShaderCount = 3;\n        static constexpr int ShaderPermutationCount = 8;\n        static constexpr int RootSignatureCount = 1;\n    };\n}\n\n// Internal SkinnedEffect implementation class.\nclass SkinnedEffect::Impl : public EffectBase<SkinnedEffectTraits>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription);\n\n    enum RootParameterIndex\n    {\n        ConstantBuffer,\n        TextureSRV,\n        TextureSampler,\n        RootParameterCount\n    };\n\n    D3D12_GPU_DESCRIPTOR_HANDLE texture;\n    D3D12_GPU_DESCRIPTOR_HANDLE sampler;\n\n    EffectLights lights;\n\n    int GetPipelineStatePermutation(bool preferPerPixelLighting, bool biasedVertexNormals) const noexcept;\n\n    void Apply(_In_ ID3D12GraphicsCommandList* commandList);\n};\n\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_VSSkinnedVertexLightingFourBones.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_VSSkinnedPixelLightingFourBones.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_VSSkinnedVertexLightingFourBonesBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_VSSkinnedPixelLightingFourBonesBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_PSSkinnedVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_PSSkinnedVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSkinnedEffect_PSSkinnedPixelLighting.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_VSSkinnedVertexLightingFourBones.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_VSSkinnedPixelLightingFourBones.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_VSSkinnedVertexLightingFourBonesBn.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_VSSkinnedPixelLightingFourBonesBn.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_PSSkinnedVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_PSSkinnedVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSkinnedEffect_PSSkinnedPixelLighting.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_VSSkinnedVertexLightingFourBones.inc\"\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_VSSkinnedPixelLightingFourBones.inc\"\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_VSSkinnedVertexLightingFourBonesBn.inc\"\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_VSSkinnedPixelLightingFourBonesBn.inc\"\n\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_PSSkinnedVertexLighting.inc\"\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_PSSkinnedVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/XboxOneSkinnedEffect_PSSkinnedPixelLighting.inc\"\n#else\n    #include \"Shaders/Compiled/SkinnedEffect_VSSkinnedVertexLightingFourBones.inc\"\n    #include \"Shaders/Compiled/SkinnedEffect_VSSkinnedPixelLightingFourBones.inc\"\n    #include \"Shaders/Compiled/SkinnedEffect_VSSkinnedVertexLightingFourBonesBn.inc\"\n    #include \"Shaders/Compiled/SkinnedEffect_VSSkinnedPixelLightingFourBonesBn.inc\"\n\n    #include \"Shaders/Compiled/SkinnedEffect_PSSkinnedVertexLighting.inc\"\n    #include \"Shaders/Compiled/SkinnedEffect_PSSkinnedVertexLightingNoFog.inc\"\n    #include \"Shaders/Compiled/SkinnedEffect_PSSkinnedPixelLighting.inc\"\n#endif\n}\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<SkinnedEffectTraits>::VertexShaderBytecode[] =\n{\n    { SkinnedEffect_VSSkinnedVertexLightingFourBones,   sizeof(SkinnedEffect_VSSkinnedVertexLightingFourBones)   },\n    { SkinnedEffect_VSSkinnedPixelLightingFourBones,    sizeof(SkinnedEffect_VSSkinnedPixelLightingFourBones)    },\n    { SkinnedEffect_VSSkinnedVertexLightingFourBonesBn, sizeof(SkinnedEffect_VSSkinnedVertexLightingFourBonesBn) },\n    { SkinnedEffect_VSSkinnedPixelLightingFourBonesBn,  sizeof(SkinnedEffect_VSSkinnedPixelLightingFourBonesBn)  },\n};\n\n\ntemplate<>\nconst int EffectBase<SkinnedEffectTraits>::VertexShaderIndices[] =\n{\n    0,  // vertex lighting, four bones\n    0,  // vertex lighting, four bones, no fog\n\n    1,  // pixel lighting, four bones\n    1,  // pixel lighting, four bones, no fog\n\n    2,  // vertex lighting (biased vertex normals), four bones\n    2,  // vertex lighting (biased vertex normals), four bones, no fog\n\n    3,  // pixel lighting (biased vertex normals), four bones\n    3,  // pixel lighting (biased vertex normals), four bones, no fog\n};\n\n\ntemplate<>\nconst D3D12_SHADER_BYTECODE EffectBase<SkinnedEffectTraits>::PixelShaderBytecode[] =\n{\n    { SkinnedEffect_PSSkinnedVertexLighting,      sizeof(SkinnedEffect_PSSkinnedVertexLighting)      },\n    { SkinnedEffect_PSSkinnedVertexLightingNoFog, sizeof(SkinnedEffect_PSSkinnedVertexLightingNoFog) },\n    { SkinnedEffect_PSSkinnedPixelLighting,       sizeof(SkinnedEffect_PSSkinnedPixelLighting)       },\n};\n\n\ntemplate<>\nconst int EffectBase<SkinnedEffectTraits>::PixelShaderIndices[] =\n{\n    0,      // vertex lighting, four bones\n    1,      // vertex lighting, four bones, no fog\n\n    2,      // pixel lighting, four bones\n    2,      // pixel lighting, four bones, no fog\n\n    0,      // vertex lighting (biased vertex normals), four bones\n    1,      // vertex lighting (biased vertex normals), four bones, no fog\n\n    2,      // pixel lighting (biased vertex normals), four bones\n    2,      // pixel lighting (biased vertex normals), four bones, no fog\n};\n\n\n// Global pool of per-device SkinnedEffect resources.\ntemplate<>\nSharedResourcePool<ID3D12Device*, EffectBase<SkinnedEffectTraits>::DeviceResources> EffectBase<SkinnedEffectTraits>::deviceResourcesPool = {};\n\n\n// Constructor.\nSkinnedEffect::Impl::Impl(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : EffectBase(device),\n        texture{},\n        sampler{}\n{\n    static_assert(_countof(EffectBase<SkinnedEffectTraits>::VertexShaderIndices) == SkinnedEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<SkinnedEffectTraits>::VertexShaderBytecode) == SkinnedEffectTraits::VertexShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<SkinnedEffectTraits>::PixelShaderBytecode) == SkinnedEffectTraits::PixelShaderCount, \"array/max mismatch\");\n    static_assert(_countof(EffectBase<SkinnedEffectTraits>::PixelShaderIndices) == SkinnedEffectTraits::ShaderPermutationCount, \"array/max mismatch\");\n\n    lights.InitializeConstants(constants.specularColorAndPower, constants.lightDirection, constants.lightDiffuseColor, constants.lightSpecularColor);\n\n    for (int i = 0; i < MaxBones; i++)\n    {\n        constants.bones[i][0] = g_XMIdentityR0;\n        constants.bones[i][1] = g_XMIdentityR1;\n        constants.bones[i][2] = g_XMIdentityR2;\n    }\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_DESCRIPTOR_RANGE textureSrvDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        CD3DX12_DESCRIPTOR_RANGE textureSamplerDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSrvDescriptorRange, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSamplerDescriptorRange, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n        mRootSignature = GetRootSignature(0, rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    fog.enabled = (effectFlags & EffectFlags::Fog) != 0;\n\n    if (effectFlags & EffectFlags::VertexColor)\n    {\n        DebugTrace(\"ERROR: SkinnedEffect does not implement EffectFlags::VertexColor\\n\");\n        throw std::invalid_argument(\"SkinnedEffect\");\n    }\n\n    // Create pipeline state.\n    int sp = GetPipelineStatePermutation(\n        (effectFlags & EffectFlags::PerPixelLightingBit) != 0,\n        (effectFlags & EffectFlags::BiasedVertexNormals) != 0);\n    assert(sp >= 0 && sp < SkinnedEffectTraits::ShaderPermutationCount);\n    _Analysis_assume_(sp >= 0 && sp < SkinnedEffectTraits::ShaderPermutationCount);\n\n    int vi = EffectBase<SkinnedEffectTraits>::VertexShaderIndices[sp];\n    assert(vi >= 0 && vi < SkinnedEffectTraits::VertexShaderCount);\n    _Analysis_assume_(vi >= 0 && vi < SkinnedEffectTraits::VertexShaderCount);\n    int pi = EffectBase<SkinnedEffectTraits>::PixelShaderIndices[sp];\n    assert(pi >= 0 && pi < SkinnedEffectTraits::PixelShaderCount);\n    _Analysis_assume_(pi >= 0 && pi < SkinnedEffectTraits::PixelShaderCount);\n\n    pipelineDescription.CreatePipelineState(\n        device,\n        mRootSignature,\n        EffectBase<SkinnedEffectTraits>::VertexShaderBytecode[vi],\n        EffectBase<SkinnedEffectTraits>::PixelShaderBytecode[pi],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"SkinnedEffect\");\n}\n\n\nint SkinnedEffect::Impl::GetPipelineStatePermutation(bool preferPerPixelLighting, bool biasedVertexNormals) const noexcept\n{\n    int permutation = 0;\n\n    // Use optimized shaders if fog is disabled.\n    if (!fog.enabled)\n    {\n        permutation += 1;\n    }\n\n    if (preferPerPixelLighting)\n    {\n        // Do lighting in the pixel shader.\n        permutation += 2;\n    }\n\n    if (biasedVertexNormals)\n    {\n        // Compressed normals need to be scaled and biased in the vertex shader.\n        permutation += 4;\n    }\n\n    return permutation;\n}\n\n\n// Sets our state onto the D3D device.\nvoid SkinnedEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Compute derived parameter values.\n    matrices.SetConstants(dirtyFlags, constants.worldViewProj);\n    fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector);\n    lights.SetConstants(dirtyFlags, matrices, constants.world, constants.worldInverseTranspose, constants.eyePosition, constants.diffuseColor, constants.emissiveColor, true);\n\n    UpdateConstants();\n\n    // Set the root signature\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture\n    if (!texture.ptr || !sampler.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture or sampler for SkinnedEffect (texture %llu, sampler %llu)\\n\", texture.ptr, sampler.ptr);\n        throw std::exception(\"SkinnedEffect\");\n    }\n\n    // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heaps.\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler);\n    \n    // Set constants\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress());\n\n    // Set the pipeline state\n    commandList->SetPipelineState(EffectBase::mPipelineState.Get());\n}\n\n\n// Public constructor.\nSkinnedEffect::SkinnedEffect(\n    _In_ ID3D12Device* device,\n    uint32_t effectFlags,\n    const EffectPipelineStateDescription& pipelineDescription)\n    : pImpl(std::make_unique<Impl>(device, effectFlags, pipelineDescription))\n{\n}\n\n\n// Move constructor.\nSkinnedEffect::SkinnedEffect(SkinnedEffect&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nSkinnedEffect& SkinnedEffect::operator= (SkinnedEffect&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nSkinnedEffect::~SkinnedEffect()\n{\n}\n\n\n// IEffect methods.\nvoid SkinnedEffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Apply(commandList);\n}\n\n\n// Camera settings.\nvoid XM_CALLCONV SkinnedEffect::SetWorld(FXMMATRIX value)\n{\n    pImpl->matrices.world = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetView(FXMMATRIX value)\n{\n    pImpl->matrices.view = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetProjection(FXMMATRIX value)\n{\n    pImpl->matrices.projection = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)\n{\n    pImpl->matrices.world = world;\n    pImpl->matrices.view = view;\n    pImpl->matrices.projection = projection;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector;\n}\n\n\n// Material settings.\nvoid XM_CALLCONV SkinnedEffect::SetDiffuseColor(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetEmissiveColor(FXMVECTOR value)\n{\n    pImpl->lights.emissiveColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetSpecularColor(FXMVECTOR value)\n{\n    // Set xyz to new value, but preserve existing w (specular power).\n    pImpl->constants.specularColorAndPower = XMVectorSelect(pImpl->constants.specularColorAndPower, value, g_XMSelect1110);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid SkinnedEffect::SetSpecularPower(float value)\n{\n    // Set w to new value, but preserve existing xyz (specular color).\n    pImpl->constants.specularColorAndPower = XMVectorSetW(pImpl->constants.specularColorAndPower, value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid SkinnedEffect::DisableSpecular()\n{\n    // Set specular color to black, power to 1\n    // Note: Don't use a power of 0 or the shader will generate strange highlights on non-specular materials\n\n    pImpl->constants.specularColorAndPower = g_XMIdentityR3; \n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid SkinnedEffect::SetAlpha(float value)\n{\n    pImpl->lights.alpha = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetColorAndAlpha(FXMVECTOR value)\n{\n    pImpl->lights.diffuseColor = value;\n    pImpl->lights.alpha = XMVectorGetW(value);\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\n// Light settings.\nvoid XM_CALLCONV SkinnedEffect::SetAmbientLightColor(FXMVECTOR value)\n{\n    pImpl->lights.ambientLightColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor;\n}\n\n\nvoid SkinnedEffect::SetLightEnabled(int whichLight, bool value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightEnabled(whichLight, value, pImpl->constants.lightDiffuseColor, pImpl->constants.lightSpecularColor);\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetLightDirection(int whichLight, FXMVECTOR value)\n{\n    EffectLights::ValidateLightIndex(whichLight);\n\n    pImpl->constants.lightDirection[whichLight] = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightDiffuseColor(whichLight, value, pImpl->constants.lightDiffuseColor);\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetLightSpecularColor(int whichLight, FXMVECTOR value)\n{\n    pImpl->dirtyFlags |= pImpl->lights.SetLightSpecularColor(whichLight, value, pImpl->constants.lightSpecularColor);\n}\n\n\nvoid SkinnedEffect::EnableDefaultLighting()\n{\n    EffectLights::EnableDefaultLighting(this);\n}\n\n\n// Fog settings.\nvoid SkinnedEffect::SetFogStart(float value)\n{\n    pImpl->fog.start = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid SkinnedEffect::SetFogEnd(float value)\n{\n    pImpl->fog.end = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::FogVector;\n}\n\n\nvoid XM_CALLCONV SkinnedEffect::SetFogColor(FXMVECTOR value)\n{\n    pImpl->constants.fogColor = value;\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\n// Texture settings.\nvoid SkinnedEffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor)\n{\n    pImpl->texture = srvDescriptor;\n    pImpl->sampler = samplerDescriptor;\n}\n\n\n// Animation settings.\nvoid SkinnedEffect::SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count)\n{\n    if (count > MaxBones)\n        throw std::out_of_range(\"count parameter out of range\");\n\n    auto boneConstant = pImpl->constants.bones;\n\n    for (size_t i = 0; i < count; i++)\n    {\n        XMMATRIX boneMatrix = XMMatrixTranspose(value[i]);\n\n        boneConstant[i][0] = boneMatrix.r[0];\n        boneConstant[i][1] = boneMatrix.r[1];\n        boneConstant[i][2] = boneMatrix.r[2];\n    }\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n\n\nvoid SkinnedEffect::ResetBoneTransforms()\n{\n    auto boneConstant = pImpl->constants.bones;\n\n    for(size_t i = 0; i < MaxBones; ++i)\n    {\n        boneConstant[i][0] = g_XMIdentityR0;\n        boneConstant[i][1] = g_XMIdentityR1;\n        boneConstant[i][2] = g_XMIdentityR2;\n    }\n\n    pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/SpriteBatch.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SpriteBatch.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"SpriteBatch.h\"\n#include \"CommonStates.h\"\n#include \"VertexTypes.h\"\n#include \"SharedResourcePool.h\"\n#include \"AlignedNew.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"GraphicsMemory.h\"\n#include \"DirectXHelpers.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    // Include the precompiled shader code.\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettSpriteEffect_SpriteVertexShader.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSpriteEffect_SpritePixelShader.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSpriteEffect_SpriteVertexShaderHeap.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettSpriteEffect_SpritePixelShaderHeap.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneSpriteEffect_SpriteVertexShader.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSpriteEffect_SpritePixelShader.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSpriteEffect_SpriteVertexShaderHeap.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneSpriteEffect_SpritePixelShaderHeap.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneSpriteEffect_SpriteVertexShader.inc\"\n    #include \"Shaders/Compiled/XboxOneSpriteEffect_SpritePixelShader.inc\"\n    #include \"Shaders/Compiled/XboxOneSpriteEffect_SpriteVertexShaderHeap.inc\"\n    #include \"Shaders/Compiled/XboxOneSpriteEffect_SpritePixelShaderHeap.inc\"\n#else\n    #include \"Shaders/Compiled/SpriteEffect_SpriteVertexShader.inc\"\n    #include \"Shaders/Compiled/SpriteEffect_SpritePixelShader.inc\"\n    #include \"Shaders/Compiled/SpriteEffect_SpriteVertexShaderHeap.inc\"\n    #include \"Shaders/Compiled/SpriteEffect_SpritePixelShaderHeap.inc\"\n#endif\n\n    inline bool operator != (D3D12_GPU_DESCRIPTOR_HANDLE a, D3D12_GPU_DESCRIPTOR_HANDLE b) noexcept\n    {\n        return a.ptr != b.ptr;\n    }\n    inline bool operator < (D3D12_GPU_DESCRIPTOR_HANDLE a, D3D12_GPU_DESCRIPTOR_HANDLE b) noexcept\n    {\n        return a.ptr < b.ptr;\n    }\n\n    // Helper converts a RECT to XMVECTOR.\n    inline XMVECTOR LoadRect(_In_ RECT const* rect) noexcept\n    {\n        XMVECTOR v = XMLoadInt4(reinterpret_cast<uint32_t const*>(rect));\n\n        v = XMConvertVectorIntToFloat(v, 0);\n\n        // Convert right/bottom to width/height.\n        v = XMVectorSubtract(v, XMVectorPermute<0, 1, 4, 5>(g_XMZero, v));\n\n        return v;\n    }\n}\n\n// Internal SpriteBatch implementation class.\n__declspec(align(16)) class SpriteBatch::Impl : public AlignedNew<SpriteBatch::Impl>\n{\npublic:\n    Impl(_In_ ID3D12Device* device,\n         ResourceUploadBatch& upload,\n         const SpriteBatchPipelineStateDescription& psoDesc,\n         const D3D12_VIEWPORT* viewport);\n\n    void XM_CALLCONV Begin(\n        _In_ ID3D12GraphicsCommandList* commandList,\n        SpriteSortMode sortMode = SpriteSortMode_Deferred,\n        FXMMATRIX transformMatrix = MatrixIdentity);\n    void End();\n\n    void XM_CALLCONV Draw(\n        D3D12_GPU_DESCRIPTOR_HANDLE texture,\n        XMUINT2 const& textureSize,\n        FXMVECTOR destination,\n        _In_opt_ RECT const* sourceRectangle,\n        FXMVECTOR color,\n        FXMVECTOR originRotationDepth,\n        unsigned int flags);\n\n    // Info about a single sprite that is waiting to be drawn.\n    __declspec(align(16)) struct SpriteInfo : public AlignedNew<SpriteInfo>\n    {\n        XMFLOAT4A source;\n        XMFLOAT4A destination;\n        XMFLOAT4A color;\n        XMFLOAT4A originRotationDepth;\n        D3D12_GPU_DESCRIPTOR_HANDLE texture;\n        XMVECTOR textureSize;\n        unsigned int flags;\n\n        // Combine values from the public SpriteEffects enum with these internal-only flags.\n        static const unsigned int SourceInTexels = 4;\n        static const unsigned int DestSizeInPixels = 8;\n\n        static_assert((SpriteEffects_FlipBoth & (SourceInTexels | DestSizeInPixels)) == 0, \"Flag bits must not overlap\");\n    };\n\n    DXGI_MODE_ROTATION mRotation;\n\n    bool mSetViewport;\n    D3D12_VIEWPORT mViewPort;\n    D3D12_GPU_DESCRIPTOR_HANDLE mSampler;\n\nprivate:\n    // Implementation helper methods.\n    void GrowSpriteQueue();\n    void PrepareForRendering();\n    void FlushBatch();\n    void SortSprites();\n    void GrowSortedSprites();\n\n    void RenderBatch(\n        D3D12_GPU_DESCRIPTOR_HANDLE texture,\n        XMVECTOR textureSize,\n        _In_reads_(count) SpriteInfo const* const* sprites,\n        size_t count);\n\n    static void XM_CALLCONV RenderSprite(_In_ SpriteInfo const* sprite,\n        _Out_writes_(VerticesPerSprite) VertexPositionColorTexture* vertices,\n        FXMVECTOR textureSize,\n        FXMVECTOR inverseTextureSize) noexcept;\n\n    XMMATRIX GetViewportTransform(_In_ DXGI_MODE_ROTATION rotation);\n\n    // Constants.\n    static const size_t MaxBatchSize = 2048;\n    static const size_t MinBatchSize = 128;\n    static const size_t InitialQueueSize = 64;\n    static const size_t VerticesPerSprite = 4;\n    static const size_t IndicesPerSprite = 6;\n\n    //\n    // The following functions and members are used to create the default pipeline state objects.\n    //\n    static const D3D12_SHADER_BYTECODE s_DefaultVertexShaderByteCodeStatic;\n    static const D3D12_SHADER_BYTECODE s_DefaultPixelShaderByteCodeStatic;\n    static const D3D12_SHADER_BYTECODE s_DefaultVertexShaderByteCodeHeap;\n    static const D3D12_SHADER_BYTECODE s_DefaultPixelShaderByteCodeHeap;\n    static const D3D12_INPUT_LAYOUT_DESC s_DefaultInputLayoutDesc;\n\n\n    // Queue of sprites waiting to be drawn.\n    std::unique_ptr<SpriteInfo[]> mSpriteQueue;\n\n    size_t mSpriteQueueCount;\n    size_t mSpriteQueueArraySize;\n\n\n    // To avoid needlessly copying around bulky SpriteInfo structures, we leave that\n    // actual data alone and just sort this array of pointers instead. But we want contiguous\n    // memory for cache efficiency, so these pointers are just shortcuts into the single\n    // mSpriteQueue array, and we take care to keep them in order when sorting is disabled.\n    std::vector<SpriteInfo const*> mSortedSprites;\n\n\n    // Mode settings from the last Begin call.\n    bool mInBeginEndPair;\n\n    SpriteSortMode mSortMode;\n    ComPtr<ID3D12PipelineState> mPSO;\n    ComPtr<ID3D12RootSignature> mRootSignature;\n    XMMATRIX mTransformMatrix;\n    ComPtr<ID3D12GraphicsCommandList> mCommandList;\n\n    // Batched data\n    GraphicsResource mVertexSegment;\n    size_t mVertexPageSize;\n    size_t mSpriteCount;\n    GraphicsResource mConstantBuffer;\n\n    enum RootParameterIndex\n    {\n        TextureSRV,\n        ConstantBuffer,\n        TextureSampler,\n        RootParameterCount\n    };\n\n    // Only one of these helpers is allocated per D3D device, even if there are multiple SpriteBatch instances.\n    struct DeviceResources\n    {\n        DeviceResources(_In_ ID3D12Device* device, ResourceUploadBatch& upload);\n\n        ComPtr<ID3D12Resource> indexBuffer;\n        D3D12_INDEX_BUFFER_VIEW indexBufferView;\n        ComPtr<ID3D12RootSignature> rootSignatureStatic;\n        ComPtr<ID3D12RootSignature> rootSignatureHeap; \n        ID3D12Device* mDevice;\n\n    private:\n        void CreateIndexBuffer(_In_ ID3D12Device* device, ResourceUploadBatch& upload);\n        void CreateRootSignatures(_In_ ID3D12Device* device);\n\n        static std::vector<short> CreateIndexValues();\n    };\n\n    // Per-device data.\n    std::shared_ptr<DeviceResources> mDeviceResources;\n    static SharedResourcePool<ID3D12Device*, DeviceResources, ResourceUploadBatch&> deviceResourcesPool;\n};\n\n\n// Global pools of per-device and per-context SpriteBatch resources.\nSharedResourcePool<ID3D12Device*, SpriteBatch::Impl::DeviceResources, ResourceUploadBatch&> SpriteBatch::Impl::deviceResourcesPool;\n\n\n// Constants.\nconst XMMATRIX SpriteBatch::MatrixIdentity = XMMatrixIdentity();\nconst XMFLOAT2 SpriteBatch::Float2Zero(0, 0);\n\nconst D3D12_SHADER_BYTECODE SpriteBatch::Impl::s_DefaultVertexShaderByteCodeStatic = {SpriteEffect_SpriteVertexShader, sizeof(SpriteEffect_SpriteVertexShader)};\nconst D3D12_SHADER_BYTECODE SpriteBatch::Impl::s_DefaultPixelShaderByteCodeStatic = {SpriteEffect_SpritePixelShader, sizeof(SpriteEffect_SpritePixelShader)};\n\nconst D3D12_SHADER_BYTECODE SpriteBatch::Impl::s_DefaultVertexShaderByteCodeHeap = { SpriteEffect_SpriteVertexShaderHeap, sizeof(SpriteEffect_SpriteVertexShaderHeap) };\nconst D3D12_SHADER_BYTECODE SpriteBatch::Impl::s_DefaultPixelShaderByteCodeHeap = { SpriteEffect_SpritePixelShaderHeap, sizeof(SpriteEffect_SpritePixelShaderHeap) };\n\nconst D3D12_INPUT_LAYOUT_DESC SpriteBatch::Impl::s_DefaultInputLayoutDesc = VertexPositionColorTexture::InputLayout;\n\n// Matches CommonStates::AlphaBlend\nconst D3D12_BLEND_DESC SpriteBatchPipelineStateDescription::s_DefaultBlendDesc =\n{\n    FALSE, // AlphaToCoverageEnable\n    FALSE, // IndependentBlendEnable\n    { {\n        TRUE, // BlendEnable\n        FALSE, // LogicOpEnable\n        D3D12_BLEND_ONE, // SrcBlend\n        D3D12_BLEND_INV_SRC_ALPHA, // DestBlend\n        D3D12_BLEND_OP_ADD, // BlendOp\n        D3D12_BLEND_ONE, // SrcBlendAlpha\n        D3D12_BLEND_INV_SRC_ALPHA, // DestBlendAlpha\n        D3D12_BLEND_OP_ADD, // BlendOpAlpha\n        D3D12_LOGIC_OP_NOOP,\n        D3D12_COLOR_WRITE_ENABLE_ALL\n    } }\n};\n\n// Same to CommonStates::CullCounterClockwise\nconst D3D12_RASTERIZER_DESC SpriteBatchPipelineStateDescription::s_DefaultRasterizerDesc =\n{\n    D3D12_FILL_MODE_SOLID,\n    D3D12_CULL_MODE_BACK,\n    FALSE, // FrontCounterClockwise\n    D3D12_DEFAULT_DEPTH_BIAS,\n    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,\n    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,\n    TRUE, // DepthClipEnable\n    TRUE, // MultisampleEnable\n    FALSE, // AntialiasedLineEnable\n    0, // ForcedSampleCount\n    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF\n};\n\n// Same as CommonStates::DepthNone\nconst D3D12_DEPTH_STENCIL_DESC SpriteBatchPipelineStateDescription::s_DefaultDepthStencilDesc =\n{\n    FALSE, // DepthEnable\n    D3D12_DEPTH_WRITE_MASK_ZERO,\n    D3D12_COMPARISON_FUNC_LESS_EQUAL, // DepthFunc\n    FALSE, // StencilEnable\n    D3D12_DEFAULT_STENCIL_READ_MASK,\n    D3D12_DEFAULT_STENCIL_WRITE_MASK,\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    }, // FrontFace\n    {\n        D3D12_STENCIL_OP_KEEP, // StencilFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilDepthFailOp\n        D3D12_STENCIL_OP_KEEP, // StencilPassOp\n        D3D12_COMPARISON_FUNC_ALWAYS // StencilFunc\n    } // BackFace\n};\n\n// Per-device constructor.\nSpriteBatch::Impl::DeviceResources::DeviceResources(_In_ ID3D12Device* device, ResourceUploadBatch& upload) :\n    indexBufferView{},\n    mDevice(device)\n{\n    CreateIndexBuffer(device, upload);\n    CreateRootSignatures(device);\n}\n\n// Creates the SpriteBatch index buffer.\nvoid SpriteBatch::Impl::DeviceResources::CreateIndexBuffer(_In_ ID3D12Device* device, ResourceUploadBatch& upload)\n{\n    static_assert((MaxBatchSize * VerticesPerSprite) < USHRT_MAX, \"MaxBatchSize too large for 16-bit indices\");\n\n    CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_DEFAULT);\n    CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(short) * MaxBatchSize * IndicesPerSprite);\n\n    // Create the constant buffer.\n    ThrowIfFailed(device->CreateCommittedResource(\n        &heapProps,\n        D3D12_HEAP_FLAG_NONE,\n        &bufferDesc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(indexBuffer.ReleaseAndGetAddressOf())));\n\n    SetDebugObjectName(indexBuffer.Get(), L\"SpriteBatch\");\n\n    auto indexValues = CreateIndexValues();\n\n    D3D12_SUBRESOURCE_DATA indexDataDesc = {};\n    indexDataDesc.pData = indexValues.data();\n    indexDataDesc.RowPitch = static_cast<LONG_PTR>(bufferDesc.Width);\n    indexDataDesc.SlicePitch = indexDataDesc.RowPitch;\n\n    // Upload the resource\n    upload.Upload(indexBuffer.Get(), 0, &indexDataDesc, 1);\n    upload.Transition(indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);\n    SetDebugObjectName(indexBuffer.Get(), L\"DirectXTK:SpriteBatch Index Buffer\");\n\n    // Create the index buffer view\n    indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress();\n    indexBufferView.Format = DXGI_FORMAT_R16_UINT;\n    indexBufferView.SizeInBytes = static_cast<UINT>(bufferDesc.Width);\n}\n\nvoid SpriteBatch::Impl::DeviceResources::CreateRootSignatures(_In_ ID3D12Device* device)\n{\n    D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n    CD3DX12_DESCRIPTOR_RANGE textureSRV(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n\n    {\n        // Same as CommonStates::StaticLinearClamp\n        CD3DX12_STATIC_SAMPLER_DESC sampler(\n            0, // register\n            D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            0.f,\n            16,\n            D3D12_COMPARISON_FUNC_LESS_EQUAL,\n            D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n            0.f,\n            D3D12_FLOAT32_MAX,\n            D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount - 1] = {};\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc;\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags);\n\n        ThrowIfFailed(::CreateRootSignature(device, &rsigDesc, rootSignatureStatic.ReleaseAndGetAddressOf()));\n\n        SetDebugObjectName(rootSignatureStatic.Get(), L\"SpriteBatch\");\n    }\n\n    {\n        CD3DX12_DESCRIPTOR_RANGE textureSampler(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);\n\n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);\n        rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc;\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);\n\n        ThrowIfFailed(::CreateRootSignature(device, &rsigDesc, rootSignatureHeap.ReleaseAndGetAddressOf()));\n\n        SetDebugObjectName(rootSignatureHeap.Get(), L\"SpriteBatch\");\n    }\n}\n\n// Helper for populating the SpriteBatch index buffer.\nstd::vector<short> SpriteBatch::Impl::DeviceResources::CreateIndexValues()\n{\n    std::vector<short> indices;\n\n    indices.reserve(MaxBatchSize * IndicesPerSprite);\n\n    for (size_t j = 0; j < MaxBatchSize * VerticesPerSprite; j += VerticesPerSprite)\n    {\n        short i = static_cast<short>(j);\n\n        indices.push_back(i);\n        indices.push_back(i + 1);\n        indices.push_back(i + 2);\n\n        indices.push_back(i + 1);\n        indices.push_back(i + 3);\n        indices.push_back(i + 2);\n    }\n\n    return indices;\n}\n\n// Per-SpriteBatch constructor.\n_Use_decl_annotations_\nSpriteBatch::Impl::Impl(ID3D12Device* device, ResourceUploadBatch& upload, const SpriteBatchPipelineStateDescription& psoDesc, const D3D12_VIEWPORT* viewport)\n    : mRotation(DXGI_MODE_ROTATION_IDENTITY),\n    mSetViewport(false),\n    mViewPort{},\n    mSampler{},\n    mSpriteQueueCount(0),\n    mSpriteQueueArraySize(0),\n    mInBeginEndPair(false),\n    mSortMode(SpriteSortMode_Deferred),\n    mTransformMatrix(MatrixIdentity),\n    mVertexSegment{},\n    mVertexPageSize(sizeof(VertexPositionColorTexture) * MaxBatchSize * VerticesPerSprite),\n    mSpriteCount(0),\n    mDeviceResources(deviceResourcesPool.DemandCreate(device, upload))\n{\n    if (viewport != nullptr)\n    {\n        mViewPort = *viewport;\n        mSetViewport = true;\n    }\n\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC d3dDesc = {};\n    d3dDesc.InputLayout = s_DefaultInputLayoutDesc;\n    d3dDesc.BlendState = psoDesc.blendDesc;\n    d3dDesc.DepthStencilState = psoDesc.depthStencilDesc;\n    d3dDesc.RasterizerState = psoDesc.rasterizerDesc;\n    d3dDesc.DSVFormat = psoDesc.renderTargetState.dsvFormat;\n    d3dDesc.NodeMask = psoDesc.renderTargetState.nodeMask;\n    d3dDesc.NumRenderTargets = psoDesc.renderTargetState.numRenderTargets;\n    memcpy_s(d3dDesc.RTVFormats, sizeof(d3dDesc.RTVFormats), psoDesc.renderTargetState.rtvFormats, sizeof(DXGI_FORMAT) * D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT);\n    d3dDesc.SampleDesc = psoDesc.renderTargetState.sampleDesc;\n    d3dDesc.SampleMask = psoDesc.renderTargetState.sampleMask;\n    d3dDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;\n    d3dDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n\n    // Three choices: (1) static sampler, (2) heap sampler, or (3) custom signature & shaders\n    if (psoDesc.customRootSignature)\n    {\n        mRootSignature = psoDesc.customRootSignature;\n    }\n    else\n    {\n        mRootSignature = (psoDesc.samplerDescriptor.ptr) ? mDeviceResources->rootSignatureHeap.Get() : mDeviceResources->rootSignatureStatic.Get();\n    }\n    d3dDesc.pRootSignature = mRootSignature.Get();\n\n    if (psoDesc.customVertexShader.pShaderBytecode)\n    {\n        d3dDesc.VS = psoDesc.customVertexShader;\n    }\n    else\n    {\n        d3dDesc.VS = (psoDesc.samplerDescriptor.ptr) ? s_DefaultVertexShaderByteCodeHeap : s_DefaultVertexShaderByteCodeStatic;\n    }\n\n    if (psoDesc.customPixelShader.pShaderBytecode)\n    {\n        d3dDesc.PS = psoDesc.customPixelShader;\n    }\n    else\n    {\n        d3dDesc.PS = (psoDesc.samplerDescriptor.ptr) ? s_DefaultPixelShaderByteCodeHeap : s_DefaultPixelShaderByteCodeStatic;\n    }\n\n    if (psoDesc.samplerDescriptor.ptr)\n    {\n        mSampler = psoDesc.samplerDescriptor;\n    }\n\n    ThrowIfFailed(device->CreateGraphicsPipelineState(\n        &d3dDesc,\n        IID_GRAPHICS_PPV_ARGS(mPSO.GetAddressOf())));\n\n    SetDebugObjectName(mPSO.Get(), L\"SpriteBatch\");\n}\n\n// Begins a batch of sprite drawing operations.\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Impl::Begin(\n    ID3D12GraphicsCommandList* commandList,\n    SpriteSortMode sortMode,\n    FXMMATRIX transformMatrix)\n{\n    if (mInBeginEndPair)\n    {\n        DebugTrace(\"ERROR: Cannot nest Begin calls on a single SpriteBatch\\n\");\n        throw std::exception(\"SpriteBatch::Begin\");\n    }\n\n    mSortMode = sortMode;\n    mTransformMatrix = transformMatrix;\n    mCommandList = commandList;\n    mSpriteCount = 0;\n\n    if (sortMode == SpriteSortMode_Immediate)\n    {\n        PrepareForRendering();\n    }\n\n    mInBeginEndPair = true;\n}\n\n// Ends a batch of sprite drawing operations.\nvoid SpriteBatch::Impl::End()\n{\n    if (!mInBeginEndPair)\n    {\n        DebugTrace(\"ERROR: Begin must be called before End\\n\");\n        throw std::exception(\"SpriteBatch::End\");\n    }\n\n    if (mSortMode != SpriteSortMode_Immediate)\n    {\n        PrepareForRendering();\n        FlushBatch();\n    }\n\n    // Release this memory\n    mVertexSegment.Reset();\n\n    // Break circular reference chains, in case the state lambda closed\n    // over an object that holds a reference to this SpriteBatch.\n    mCommandList = nullptr;\n    mInBeginEndPair = false;\n}\n\n\n// Adds a single sprite to the queue.\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Impl::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n    XMUINT2 const& textureSize,\n    FXMVECTOR destination,\n    RECT const* sourceRectangle,\n    FXMVECTOR color,\n    FXMVECTOR originRotationDepth,\n    unsigned int flags)\n{\n    if (!mInBeginEndPair)\n    {\n        DebugTrace(\"ERROR: Begin must be called before Draw\\n\");\n        throw std::exception(\"SpriteBatch::Draw\");\n    }\n\n    if (!texture.ptr)\n        throw std::exception(\"Invalid texture for Draw\");\n\n    // Get a pointer to the output sprite.\n    if (mSpriteQueueCount >= mSpriteQueueArraySize)\n    {\n        GrowSpriteQueue();\n    }\n\n    SpriteInfo* sprite = &mSpriteQueue[mSpriteQueueCount];\n\n    XMVECTOR dest = destination;\n\n    if (sourceRectangle)\n    {\n        // User specified an explicit source region.\n        XMVECTOR source = LoadRect(sourceRectangle);\n\n        XMStoreFloat4A(&sprite->source, source);\n\n        // If the destination size is relative to the source region, convert it to pixels.\n        if (!(flags & SpriteInfo::DestSizeInPixels))\n        {\n            dest = XMVectorPermute<0, 1, 6, 7>(dest, XMVectorMultiply(dest, source)); // dest.zw *= source.zw\n        }\n\n        flags |= SpriteInfo::SourceInTexels | SpriteInfo::DestSizeInPixels;\n    }\n    else\n    {\n        // No explicit source region, so use the entire texture.\n        static const XMVECTORF32 wholeTexture = { { {0, 0, 1, 1} } };\n\n        XMStoreFloat4A(&sprite->source, wholeTexture);\n    }\n\n    // Convert texture size\n    XMVECTOR textureSizeV = XMLoadUInt2(&textureSize);\n\n    // Store sprite parameters.\n    XMStoreFloat4A(&sprite->destination, dest);\n    XMStoreFloat4A(&sprite->color, color);\n    XMStoreFloat4A(&sprite->originRotationDepth, originRotationDepth);\n\n    sprite->texture = texture;\n    sprite->textureSize = textureSizeV;\n    sprite->flags = flags;\n\n    if (mSortMode == SpriteSortMode_Immediate)\n    {\n        // If we are in immediate mode, draw this sprite straight away.\n        RenderBatch(texture, textureSizeV, &sprite, 1);\n    }\n    else\n    {\n        // Queue this sprite for later sorting and batched rendering.\n        mSpriteQueueCount++;\n    }\n}\n\n\n// Dynamically expands the array used to store pending sprite information.\nvoid SpriteBatch::Impl::GrowSpriteQueue()\n{\n    // Grow by a factor of 2.\n    size_t newSize = std::max(InitialQueueSize, mSpriteQueueArraySize * 2);\n\n    // Allocate the new array.\n    auto newArray = std::make_unique<SpriteInfo[]>(newSize);\n\n    // Copy over any existing sprites.\n    for (size_t i = 0; i < mSpriteQueueCount; i++)\n    {\n        newArray[i] = mSpriteQueue[i];\n    }\n\n    // Replace the previous array with the new one.\n    mSpriteQueue = std::move(newArray);\n    mSpriteQueueArraySize = newSize;\n\n    // Clear any dangling SpriteInfo pointers left over from previous rendering.\n    mSortedSprites.clear();\n}\n\n\n// Sets up D3D device state ready for drawing sprites.\nvoid SpriteBatch::Impl::PrepareForRendering()\n{\n    auto commandList = mCommandList.Get();\n\n    // Set root signature\n    commandList->SetGraphicsRootSignature(mRootSignature.Get());\n\n    // Set render state\n    commandList->SetPipelineState(mPSO.Get());\n    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n\n    // Set the index buffer.\n    commandList->IASetIndexBuffer(&mDeviceResources->indexBufferView);\n\n    // Set the transform matrix.\n    XMMATRIX transformMatrix = (mRotation == DXGI_MODE_ROTATION_UNSPECIFIED)\n        ? mTransformMatrix\n        : (mTransformMatrix * GetViewportTransform(mRotation));\n\n    mConstantBuffer = GraphicsMemory::Get(mDeviceResources->mDevice).AllocateConstant(transformMatrix);\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, mConstantBuffer.GpuAddress());\n}\n\n\n// Sends queued sprites to the graphics device.\nvoid SpriteBatch::Impl::FlushBatch()\n{\n    if (!mSpriteQueueCount)\n        return;\n\n    SortSprites();\n\n    // Walk through the sorted sprite list, looking for adjacent entries that share a texture.\n    D3D12_GPU_DESCRIPTOR_HANDLE batchTexture = {};\n    XMVECTOR batchTextureSize = {};\n    size_t batchStart = 0;\n\n    for (size_t pos = 0; pos < mSpriteQueueCount; pos++)\n    {\n        D3D12_GPU_DESCRIPTOR_HANDLE texture = mSortedSprites[pos]->texture;\n        assert(texture.ptr != 0);\n        XMVECTOR textureSize = mSortedSprites[pos]->textureSize;\n\n        // Flush whenever the texture changes.\n        if (texture != batchTexture)\n        {\n            if (pos > batchStart)\n            {\n                RenderBatch(batchTexture, batchTextureSize, &mSortedSprites[batchStart], pos - batchStart);\n            }\n\n            batchTexture = texture;\n            batchTextureSize = textureSize;\n            batchStart = pos;\n        }\n    }\n\n    // Flush the final batch.\n    RenderBatch(batchTexture, batchTextureSize, &mSortedSprites[batchStart], mSpriteQueueCount - batchStart);\n\n    // Reset the queue.\n    mSpriteQueueCount = 0;\n\n    // When sorting is disabled, we persist mSortedSprites data from one batch to the next, to avoid\n    // uneccessary work in GrowSortedSprites. But we never reuse these when sorting, because re-sorting\n    // previously sorted items gives unstable ordering if some sprites have identical sort keys.\n    if (mSortMode != SpriteSortMode_Deferred)\n    {\n        mSortedSprites.clear();\n    }\n}\n\n\n// Sorts the array of queued sprites.\nvoid SpriteBatch::Impl::SortSprites()\n{\n    // Fill the mSortedSprites vector.\n    if (mSortedSprites.size() < mSpriteQueueCount)\n    {\n        GrowSortedSprites();\n    }\n\n    switch (mSortMode)\n    {\n    case SpriteSortMode_Texture:\n        // Sort by texture.\n        std::sort(mSortedSprites.begin(),\n            mSortedSprites.begin() + static_cast<int>(mSpriteQueueCount),\n            [](SpriteInfo const* x, SpriteInfo const* y) noexcept -> bool\n            {\n                return x->texture < y->texture;\n            });\n        break;\n\n    case SpriteSortMode_BackToFront:\n        // Sort back to front.\n        std::sort(mSortedSprites.begin(),\n            mSortedSprites.begin() + static_cast<int>(mSpriteQueueCount),\n            [](SpriteInfo const* x, SpriteInfo const* y) noexcept -> bool\n            {\n                return x->originRotationDepth.w > y->originRotationDepth.w;\n            });\n        break;\n\n    case SpriteSortMode_FrontToBack:\n        // Sort front to back.\n        std::sort(mSortedSprites.begin(),\n            mSortedSprites.begin() + static_cast<int>(mSpriteQueueCount),\n            [](SpriteInfo const* x, SpriteInfo const* y) noexcept -> bool\n            {\n                return x->originRotationDepth.w < y->originRotationDepth.w;\n            });\n        break;\n\n    default:\n        break;\n    }\n}\n\n\n// Populates the mSortedSprites vector with pointers to individual elements of the mSpriteQueue array.\nvoid SpriteBatch::Impl::GrowSortedSprites()\n{\n    size_t previousSize = mSortedSprites.size();\n\n    mSortedSprites.resize(mSpriteQueueCount);\n\n    for (size_t i = previousSize; i < mSpriteQueueCount; i++)\n    {\n        mSortedSprites[i] = &mSpriteQueue[i];\n    }\n}\n\n\n// Submits a batch of sprites to the GPU.\n_Use_decl_annotations_\nvoid SpriteBatch::Impl::RenderBatch(D3D12_GPU_DESCRIPTOR_HANDLE texture, XMVECTOR textureSize, SpriteInfo const* const* sprites, size_t count)\n{\n    auto commandList = mCommandList.Get();\n\n    // Draw using the specified texture.\n    // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() with the required descriptor heap(s)\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n\n    if (mSampler.ptr)\n    {\n        commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, mSampler);\n    }\n\n    // Convert to vector format.\n    XMVECTOR inverseTextureSize = XMVectorReciprocal(textureSize);\n\n    while (count > 0)\n    {\n        // How many sprites do we want to draw?\n        size_t batchSize = count;\n\n        // How many sprites does the D3D vertex buffer have room for?\n        size_t remainingSpace = MaxBatchSize - mSpriteCount;\n\n        if (batchSize > remainingSpace)\n        {\n            if (remainingSpace < MinBatchSize)\n            {\n                // If we are out of room, or about to submit an excessively small batch, wrap back to the start of the vertex buffer.\n                mSpriteCount = 0;\n\n                batchSize = std::min(count, MaxBatchSize);\n            }\n            else\n            {\n                // Take however many sprites fit in what's left of the vertex buffer.\n                batchSize = remainingSpace;\n            }\n        }\n\n        // Allocate a new page of vertex memory if we're starting the batch\n        if (mSpriteCount == 0)\n        {\n            mVertexSegment = GraphicsMemory::Get(mDeviceResources->mDevice).Allocate(mVertexPageSize);\n        }\n\n        auto vertices = static_cast<VertexPositionColorTexture*>(mVertexSegment.Memory()) + mSpriteCount * VerticesPerSprite;\n\n        // Generate sprite vertex data.\n        for (size_t i = 0; i < batchSize; i++)\n        {\n            assert(i < count);\n            _Analysis_assume_(i < count);\n            RenderSprite(sprites[i], vertices, textureSize, inverseTextureSize);\n\n            vertices += VerticesPerSprite;\n        }\n\n        // Set the vertex buffer view\n        D3D12_VERTEX_BUFFER_VIEW vbv;\n        size_t spriteVertexTotalSize = sizeof(VertexPositionColorTexture) * VerticesPerSprite;\n        vbv.BufferLocation = mVertexSegment.GpuAddress() + (UINT64(mSpriteCount) * UINT64(spriteVertexTotalSize));\n        vbv.StrideInBytes = sizeof(VertexPositionColorTexture);\n        vbv.SizeInBytes = static_cast<UINT>(batchSize * spriteVertexTotalSize);\n        commandList->IASetVertexBuffers(0, 1, &vbv);\n\n        // Ok lads, the time has come for us draw ourselves some sprites!\n        UINT indexCount = static_cast<UINT>(batchSize * IndicesPerSprite);\n\n        commandList->DrawIndexedInstanced(indexCount, 1, 0, 0, 0);\n\n        // Advance the buffer position.\n        mSpriteCount += batchSize;\n\n        sprites += batchSize;\n        count -= batchSize;\n    }\n}\n\n\n// Generates vertex data for drawing a single sprite.\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Impl::RenderSprite(SpriteInfo const* sprite, VertexPositionColorTexture* vertices, FXMVECTOR textureSize, FXMVECTOR inverseTextureSize) noexcept\n{\n    // Load sprite parameters into SIMD registers.\n    XMVECTOR source = XMLoadFloat4A(&sprite->source);\n    XMVECTOR destination = XMLoadFloat4A(&sprite->destination);\n    XMVECTOR color = XMLoadFloat4A(&sprite->color);\n    XMVECTOR originRotationDepth = XMLoadFloat4A(&sprite->originRotationDepth);\n\n    float rotation = sprite->originRotationDepth.z;\n    unsigned int flags = sprite->flags;\n\n    // Extract the source and destination sizes into separate vectors.\n    XMVECTOR sourceSize = XMVectorSwizzle<2, 3, 2, 3>(source);\n    XMVECTOR destinationSize = XMVectorSwizzle<2, 3, 2, 3>(destination);\n\n    // Scale the origin offset by source size, taking care to avoid overflow if the source region is zero.\n    XMVECTOR isZeroMask = XMVectorEqual(sourceSize, XMVectorZero());\n    XMVECTOR nonZeroSourceSize = XMVectorSelect(sourceSize, g_XMEpsilon, isZeroMask);\n\n    XMVECTOR origin = XMVectorDivide(originRotationDepth, nonZeroSourceSize);\n\n    // Convert the source region from texels to mod-1 texture coordinate format.\n    if (flags & SpriteInfo::SourceInTexels)\n    {\n        source = XMVectorMultiply(source, inverseTextureSize);\n        sourceSize = XMVectorMultiply(sourceSize, inverseTextureSize);\n    }\n    else\n    {\n        origin = XMVectorMultiply(origin, inverseTextureSize);\n    }\n\n    // If the destination size is relative to the source region, convert it to pixels.\n    if (!(flags & SpriteInfo::DestSizeInPixels))\n    {\n        destinationSize = XMVectorMultiply(destinationSize, textureSize);\n    }\n\n    // Compute a 2x2 rotation matrix.\n    XMVECTOR rotationMatrix1;\n    XMVECTOR rotationMatrix2;\n\n    if (rotation != 0)\n    {\n        float sin, cos;\n\n        XMScalarSinCos(&sin, &cos, rotation);\n\n        XMVECTOR sinV = XMLoadFloat(&sin);\n        XMVECTOR cosV = XMLoadFloat(&cos);\n\n        rotationMatrix1 = XMVectorMergeXY(cosV, sinV);\n        rotationMatrix2 = XMVectorMergeXY(XMVectorNegate(sinV), cosV);\n    }\n    else\n    {\n        rotationMatrix1 = g_XMIdentityR0;\n        rotationMatrix2 = g_XMIdentityR1;\n    }\n\n    // The four corner vertices are computed by transforming these unit-square positions.\n    static XMVECTORF32 cornerOffsets[VerticesPerSprite] =\n    {\n        { { { 0, 0, 0, 0 } } },\n        { { { 1, 0, 0, 0 } } },\n        { { { 0, 1, 0, 0 } } },\n        { { { 1, 1, 0, 0 } } },\n    };\n\n    // Tricksy alert! Texture coordinates are computed from the same cornerOffsets\n    // table as vertex positions, but if the sprite is mirrored, this table\n    // must be indexed in a different order. This is done as follows:\n    //\n    //    position = cornerOffsets[i]\n    //    texcoord = cornerOffsets[i ^ SpriteEffects]\n\n    static_assert(SpriteEffects_FlipHorizontally == 1 &&\n        SpriteEffects_FlipVertically == 2, \"If you change these enum values, the mirroring implementation must be updated to match\");\n\n    const unsigned int mirrorBits = flags & 3u;\n\n    // Generate the four output vertices.\n    for (size_t i = 0; i < VerticesPerSprite; i++)\n    {\n        // Calculate position.\n        XMVECTOR cornerOffset = XMVectorMultiply(XMVectorSubtract(cornerOffsets[i], origin), destinationSize);\n\n        // Apply 2x2 rotation matrix.\n        XMVECTOR position1 = XMVectorMultiplyAdd(XMVectorSplatX(cornerOffset), rotationMatrix1, destination);\n        XMVECTOR position2 = XMVectorMultiplyAdd(XMVectorSplatY(cornerOffset), rotationMatrix2, position1);\n\n        // Set z = depth.\n        XMVECTOR position = XMVectorPermute<0, 1, 7, 6>(position2, originRotationDepth);\n\n        // Write position as a Float4, even though VertexPositionColor::position is an XMFLOAT3.\n        // This is faster, and harmless as we are just clobbering the first element of the\n        // following color field, which will immediately be overwritten with its correct value.\n        XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&vertices[i].position), position);\n\n        // Write the color.\n        XMStoreFloat4(&vertices[i].color, color);\n\n        // Compute and write the texture coordinate.\n        XMVECTOR textureCoordinate = XMVectorMultiplyAdd(cornerOffsets[static_cast<unsigned int>(i) ^ mirrorBits], sourceSize, source);\n\n        XMStoreFloat2(&vertices[i].textureCoordinate, textureCoordinate);\n    }\n}\n\n\n// Generates a viewport transform matrix for rendering sprites using x-right y-down screen pixel coordinates.\nXMMATRIX SpriteBatch::Impl::GetViewportTransform(_In_ DXGI_MODE_ROTATION rotation)\n{\n    if (!mSetViewport)\n    {\n        DebugTrace(\"ERROR: SpriteBatch requires viewport information via SetViewport\\n\");\n        throw std::exception(\"Viewport not set.\");\n    }\n\n    // Compute the matrix.\n    float xScale = (mViewPort.Width > 0) ? 2.0f / mViewPort.Width : 0.0f;\n    float yScale = (mViewPort.Height > 0) ? 2.0f / mViewPort.Height : 0.0f;\n\n    switch (rotation)\n    {\n    case DXGI_MODE_ROTATION_ROTATE90:\n        return XMMATRIX\n            (\n                0, -yScale, 0, 0,\n                -xScale, 0, 0, 0,\n                0, 0, 1, 0,\n                1, 1, 0, 1\n                );\n\n    case DXGI_MODE_ROTATION_ROTATE270:\n        return XMMATRIX\n            (\n                0, yScale, 0, 0,\n                xScale, 0, 0, 0,\n                0, 0, 1, 0,\n                -1, -1, 0, 1\n                );\n\n    case DXGI_MODE_ROTATION_ROTATE180:\n        return XMMATRIX\n            (\n                -xScale, 0, 0, 0,\n                0, yScale, 0, 0,\n                0, 0, 1, 0,\n                1, -1, 0, 1\n                );\n\n    default:\n        return XMMATRIX\n            (\n                xScale, 0, 0, 0,\n                0, -yScale, 0, 0,\n                0, 0, 1, 0,\n                -1, 1, 0, 1\n                );\n    }\n}\n\n\n// Public constructor.\n_Use_decl_annotations_\nSpriteBatch::SpriteBatch(ID3D12Device* device,\n    ResourceUploadBatch& upload,\n    const SpriteBatchPipelineStateDescription& psoDesc,\n    const D3D12_VIEWPORT* viewport)\n    : pImpl(std::make_unique<Impl>(device, upload, psoDesc, viewport))\n{\n}\n\n\n// Move constructor.\nSpriteBatch::SpriteBatch(SpriteBatch&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nSpriteBatch& SpriteBatch::operator= (SpriteBatch&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nSpriteBatch::~SpriteBatch()\n{\n}\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Begin(\n    ID3D12GraphicsCommandList* commandList,\n    SpriteSortMode sortMode,\n    FXMMATRIX transformMatrix)\n{\n    pImpl->Begin(commandList, sortMode, transformMatrix);\n}\n\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Begin(\n    ID3D12GraphicsCommandList* commandList,\n    D3D12_GPU_DESCRIPTOR_HANDLE sampler,\n    SpriteSortMode sortMode,\n    FXMMATRIX transformMatrix)\n{\n    if (!sampler.ptr)\n        throw std::exception(\"Invalid heap-based sampler for Begin\");\n\n    if (!pImpl->mSampler.ptr)\n    {\n        DebugTrace(\"ERROR: sampler version of Begin requires SpriteBatch was created with a heap-based sampler\\n\");\n        throw std::exception(\"SpriteBatch::Begin\");\n    }\n\n    pImpl->mSampler = sampler;\n\n    pImpl->Begin(commandList, sortMode, transformMatrix);\n}\n\n\nvoid SpriteBatch::End()\n{\n    pImpl->End();\n}\n\n\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n    XMUINT2 const& textureSize,\n    XMFLOAT2 const& position,\n    FXMVECTOR color)\n{\n    XMVECTOR destination = XMVectorPermute<0, 1, 4, 5>(XMLoadFloat2(&position), g_XMOne); // x, y, 1, 1\n\n    pImpl->Draw(texture, textureSize, destination, nullptr, color, g_XMZero, 0);\n}\n\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n    XMUINT2 const& textureSize,\n    XMFLOAT2 const& position, \n    RECT const* sourceRectangle,\n    FXMVECTOR color,\n    float rotation,\n    XMFLOAT2 const& origin,\n    float scale,\n    SpriteEffects effects,\n    float layerDepth)\n{\n    XMVECTOR destination = XMVectorPermute<0, 1, 4, 4>(XMLoadFloat2(&position), XMLoadFloat(&scale)); // x, y, scale, scale\n\n    XMVECTOR originRotationDepth = XMVectorSet(origin.x, origin.y, rotation, layerDepth);\n\n    pImpl->Draw(texture, textureSize, destination, sourceRectangle, color, originRotationDepth, static_cast<unsigned int>(effects));\n}\n\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture, \n    XMUINT2 const& textureSize,\n    XMFLOAT2 const& position,\n    RECT const* sourceRectangle,\n    FXMVECTOR color,\n    float rotation,\n    XMFLOAT2 const& origin,\n    XMFLOAT2 const& scale,\n    SpriteEffects effects,\n    float layerDepth)\n{\n    XMVECTOR destination = XMVectorPermute<0, 1, 4, 5>(XMLoadFloat2(&position), XMLoadFloat2(&scale)); // x, y, scale.x, scale.y\n\n    XMVECTOR originRotationDepth = XMVectorSet(origin.x, origin.y, rotation, layerDepth);\n\n    pImpl->Draw(texture, textureSize, destination, sourceRectangle, color, originRotationDepth, static_cast<unsigned int>(effects));\n}\n\n\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture, XMUINT2 const& textureSize, FXMVECTOR position, FXMVECTOR color)\n{\n    XMVECTOR destination = XMVectorPermute<0, 1, 4, 5>(position, g_XMOne); // x, y, 1, 1\n\n    pImpl->Draw(texture, textureSize, destination, nullptr, color, g_XMZero, 0);\n}\n\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n    XMUINT2 const& textureSize,\n    FXMVECTOR position, \n    RECT const* sourceRectangle,\n    FXMVECTOR color,\n    float rotation,\n    FXMVECTOR origin,\n    float scale,\n    SpriteEffects effects,\n    float layerDepth)\n{\n    XMVECTOR destination = XMVectorPermute<0, 1, 4, 4>(position, XMLoadFloat(&scale)); // x, y, scale, scale\n\n    XMVECTOR rotationDepth = XMVectorMergeXY(XMVectorReplicate(rotation), XMVectorReplicate(layerDepth));\n\n    XMVECTOR originRotationDepth = XMVectorPermute<0, 1, 4, 5>(origin, rotationDepth);\n\n    pImpl->Draw(texture, textureSize, destination, sourceRectangle, color, originRotationDepth, static_cast<unsigned int>(effects));\n}\n\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n    XMUINT2 const& textureSize,\n    FXMVECTOR position,\n    RECT const* sourceRectangle,\n    FXMVECTOR color,\n    float rotation,\n    FXMVECTOR origin,\n    GXMVECTOR scale,\n    SpriteEffects effects,\n    float layerDepth)\n{\n    XMVECTOR destination = XMVectorPermute<0, 1, 4, 5>(position, scale); // x, y, scale.x, scale.y\n\n    XMVECTOR rotationDepth = XMVectorMergeXY(XMVectorReplicate(rotation), XMVectorReplicate(layerDepth));\n\n    XMVECTOR originRotationDepth = XMVectorPermute<0, 1, 4, 5>(origin, rotationDepth);\n\n    pImpl->Draw(texture, textureSize, destination, sourceRectangle, color, originRotationDepth, static_cast<unsigned int>(effects));\n}\n\n\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture, \n    XMUINT2 const& textureSize,\n    RECT const& destinationRectangle,\n    FXMVECTOR color)\n{\n    XMVECTOR destination = LoadRect(&destinationRectangle); // x, y, w, h\n\n    pImpl->Draw(texture, textureSize, destination, nullptr, color, g_XMZero, Impl::SpriteInfo::DestSizeInPixels);\n}\n\n\n_Use_decl_annotations_\nvoid XM_CALLCONV SpriteBatch::Draw(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n    XMUINT2 const& textureSize,\n    RECT const& destinationRectangle,\n    RECT const* sourceRectangle,\n    FXMVECTOR color,\n    float rotation,\n    XMFLOAT2 const& origin, \n    SpriteEffects effects, \n    float layerDepth)\n{\n    XMVECTOR destination = LoadRect(&destinationRectangle); // x, y, w, h\n\n    XMVECTOR originRotationDepth = XMVectorSet(origin.x, origin.y, rotation, layerDepth);\n\n    pImpl->Draw(texture, textureSize, destination, sourceRectangle, color, originRotationDepth, static_cast<unsigned int>(effects) | Impl::SpriteInfo::DestSizeInPixels);\n}\n\n\nvoid SpriteBatch::SetRotation(DXGI_MODE_ROTATION mode)\n{\n    pImpl->mRotation = mode;\n}\n\n\nDXGI_MODE_ROTATION SpriteBatch::GetRotation() const noexcept\n{\n    return pImpl->mRotation;\n}\n\n\nvoid SpriteBatch::SetViewport(const D3D12_VIEWPORT& viewPort)\n{\n    pImpl->mSetViewport = true;\n    pImpl->mViewPort = viewPort;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/SpriteFont.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: SpriteFont.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include <algorithm>\n#include <vector>\n\n#include \"SpriteFont.h\"\n#include \"DirectXHelpers.h\"\n#include \"BinaryReader.h\"\n#include \"LoaderHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"DescriptorHeap.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\n\n// Internal SpriteFont implementation class.\nclass SpriteFont::Impl\n{\npublic:\n    Impl(_In_ ID3D12Device* device,\n        ResourceUploadBatch& upload,\n        _In_ BinaryReader* reader,\n        D3D12_CPU_DESCRIPTOR_HANDLE cpuDesc,\n        D3D12_GPU_DESCRIPTOR_HANDLE gpuDesc,\n        bool forceSRGB) noexcept(false);\n    Impl(D3D12_GPU_DESCRIPTOR_HANDLE texture,\n        XMUINT2 textureSize,\n        _In_reads_(glyphCount) Glyph const* glyphs,\n        size_t glyphCount,\n        float lineSpacing) noexcept(false);\n\n    Glyph const* FindGlyph(wchar_t character) const;\n\n    void SetDefaultCharacter(wchar_t character);\n\n    template<typename TAction>\n    void ForEachGlyph(_In_z_ wchar_t const* text, TAction action, bool ignoreWhitespace) const;\n\n    void CreateTextureResource(_In_ ID3D12Device* device,\n        ResourceUploadBatch& upload,\n        uint32_t width, uint32_t height,\n        DXGI_FORMAT format,\n        uint32_t stride, uint32_t rows,\n        _In_reads_(stride * rows) const uint8_t* data) noexcept(false);\n\n    const wchar_t* ConvertUTF8(_In_z_ const char *text) noexcept(false);\n\n    // Fields.\n    ComPtr<ID3D12Resource> textureResource;\n    D3D12_GPU_DESCRIPTOR_HANDLE texture;\n    XMUINT2 textureSize;\n    std::vector<Glyph> glyphs;\n    std::vector<uint32_t> glyphsIndex;\n    Glyph const* defaultGlyph;\n    float lineSpacing;\n\nprivate:\n    size_t utfBufferSize;\n    std::unique_ptr<wchar_t[]> utfBuffer;\n};\n\n\n// Constants.\nconst XMFLOAT2 SpriteFont::Float2Zero(0, 0);\n\nstatic const char spriteFontMagic[] = \"DXTKfont\";\n\n\n// Comparison operators make our sorted glyph vector work with std::binary_search and lower_bound.\nnamespace DirectX\n{\n    static inline bool operator< (SpriteFont::Glyph const& left, SpriteFont::Glyph const& right) noexcept\n    {\n        return left.Character < right.Character;\n    }\n\n    static inline bool operator< (wchar_t left, SpriteFont::Glyph const& right) noexcept\n    {\n        return left < right.Character;\n    }\n\n    static inline bool operator< (SpriteFont::Glyph const& left, wchar_t right) noexcept\n    {\n        return left.Character < right;\n    }\n}\n\n\n// Reads a SpriteFont from the binary format created by the MakeSpriteFont utility.\n_Use_decl_annotations_\nSpriteFont::Impl::Impl(\n    ID3D12Device* device,\n    ResourceUploadBatch& upload,\n    BinaryReader* reader,\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuDesc,\n    D3D12_GPU_DESCRIPTOR_HANDLE gpuDesc,\n    bool forceSRGB) noexcept(false) :\n        texture{},\n        textureSize{},\n        defaultGlyph(nullptr),\n        lineSpacing(0),\n        utfBufferSize(0)\n{\n    // Validate the header.\n    for (char const* magic = spriteFontMagic; *magic; magic++)\n    {\n        if (reader->Read<uint8_t>() != *magic)\n        {\n            DebugTrace(\"ERROR: SpriteFont provided with an invalid .spritefont file\\n\");\n            throw std::exception(\"Not a MakeSpriteFont output binary\");\n        }\n    }\n\n    // Read the glyph data.\n    auto glyphCount = reader->Read<uint32_t>();\n    auto glyphData = reader->ReadArray<Glyph>(glyphCount);\n\n    glyphs.assign(glyphData, glyphData + glyphCount);\n    glyphsIndex.reserve(glyphs.size());\n\n    for (auto& glyph : glyphs)\n    {\n        glyphsIndex.emplace_back(glyph.Character);\n    }\n\n    // Read font properties.\n    lineSpacing = reader->Read<float>();\n\n    SetDefaultCharacter(static_cast<wchar_t>(reader->Read<uint32_t>()));\n\n    // Read the texture data.\n    auto textureWidth = reader->Read<uint32_t>();\n    auto textureHeight = reader->Read<uint32_t>();\n    auto textureFormat = reader->Read<DXGI_FORMAT>();\n    auto textureStride = reader->Read<uint32_t>();\n    auto textureRows = reader->Read<uint32_t>();\n\n    uint64_t dataSize = uint64_t(textureStride) * uint64_t(textureRows);\n    if (dataSize > UINT32_MAX)\n    {\n        DebugTrace(\"ERROR: SpriteFont provided with an invalid .spritefont file\\n\");\n        throw std::overflow_error(\"Invalid .spritefont file\");\n    }\n\n    auto textureData = reader->ReadArray<uint8_t>(static_cast<size_t>(dataSize));\n\n    if (forceSRGB)\n    {\n        textureFormat = LoaderHelpers::MakeSRGB(textureFormat);\n    }\n\n    // Create the D3D texture.\n    CreateTextureResource(\n        device,\n        upload,\n        textureWidth, textureHeight,\n        textureFormat,\n        textureStride, textureRows,\n        textureData);\n\n    // Create the shader resource view\n    CreateShaderResourceView(\n        device, textureResource.Get(),\n        cpuDesc, false);\n\n    // Save off the GPU descriptor pointer and size.\n    texture = gpuDesc;\n    textureSize = XMUINT2(textureWidth, textureHeight);\n}\n\n\n// Constructs a SpriteFont from arbitrary user specified glyph data.\n_Use_decl_annotations_\nSpriteFont::Impl::Impl(\n    D3D12_GPU_DESCRIPTOR_HANDLE itexture,\n    XMUINT2 itextureSize,\n    Glyph const* iglyphs,\n    size_t glyphCount,\n    float ilineSpacing) noexcept(false) :\n        texture(itexture),\n        textureSize(itextureSize),\n        glyphs(iglyphs, iglyphs + glyphCount),\n        defaultGlyph(nullptr),\n        lineSpacing(ilineSpacing),\n        utfBufferSize(0)\n{\n    if (!std::is_sorted(iglyphs, iglyphs + glyphCount))\n    {\n        throw std::exception(\"Glyphs must be in ascending codepoint order\");\n    }\n\n    glyphsIndex.reserve(glyphs.size());\n\n    for (auto& glyph : glyphs)\n    {\n        glyphsIndex.emplace_back(glyph.Character);\n    }\n}\n\n\n// Looks up the requested glyph, falling back to the default character if it is not in the font.\nSpriteFont::Glyph const* SpriteFont::Impl::FindGlyph(wchar_t character) const\n{\n    // Rather than use std::lower_bound (which includes a slow debug path when built for _DEBUG),\n    // we implement a binary search inline to ensure sufficient Debug build performance to be useful\n    // for text-heavy applications.\n\n    size_t lower = 0;\n    size_t higher = glyphs.size() - 1;\n    size_t index = higher / 2;\n    const size_t size = glyphs.size();\n\n    while (index < size)\n    {\n        const auto curChar = glyphsIndex[index];\n        if (curChar == character) { return &glyphs[index]; }\n        if (curChar < character)\n        {\n            lower = index + 1;\n        }\n        else\n        {\n            higher = index - 1;\n        }\n        if (higher < lower) { break; }\n        else if (higher - lower <= 4)\n        {\n            for (index = lower; index <= higher; index++)\n            {\n                if (glyphsIndex[index] == character)\n                {\n                    return &glyphs[index];\n                }\n            }\n        }\n        index = lower + ((higher - lower) / 2);\n    }\n\n    if (defaultGlyph)\n    {\n        return defaultGlyph;\n    }\n\n    DebugTrace(\"ERROR: SpriteFont encountered a character not in the font (%u, %C), and no default glyph was provided\\n\", character, character);\n    throw std::exception(\"Character not in font\");\n}\n\n\n// Sets the missing-character fallback glyph.\nvoid SpriteFont::Impl::SetDefaultCharacter(wchar_t character)\n{\n    defaultGlyph = nullptr;\n\n    if (character)\n    {\n        defaultGlyph = FindGlyph(character);\n    }\n}\n\n\n// The core glyph layout algorithm, shared between DrawString and MeasureString.\ntemplate<typename TAction>\nvoid SpriteFont::Impl::ForEachGlyph(_In_z_ wchar_t const* text, TAction action, bool ignoreWhitespace) const\n{\n    float x = 0;\n    float y = 0;\n\n    for (; *text; text++)\n    {\n        wchar_t character = *text;\n\n        switch (character)\n        {\n            case '\\r':\n                // Skip carriage returns.\n                continue;\n\n            case '\\n':\n                // New line.\n                x = 0;\n                y += lineSpacing;\n                break;\n\n            default:\n                // Output this character.\n                auto glyph = FindGlyph(character);\n\n                x += glyph->XOffset;\n\n                if (x < 0)\n                    x = 0;\n\n                float advance = float(glyph->Subrect.right) - float(glyph->Subrect.left) + glyph->XAdvance;\n\n                if (!ignoreWhitespace\n                    || !iswspace(character)\n                    || ((glyph->Subrect.right - glyph->Subrect.left) > 1)\n                    || ((glyph->Subrect.bottom - glyph->Subrect.top) > 1))\n                {\n                    action(glyph, x, y, advance);\n                }\n\n                x += advance;\n                break;\n        }\n    }\n}\n\n\n_Use_decl_annotations_\nvoid SpriteFont::Impl::CreateTextureResource(\n    ID3D12Device* device,\n    ResourceUploadBatch& upload,\n    uint32_t width, uint32_t height,\n    DXGI_FORMAT format,\n    uint32_t stride, uint32_t rows,\n    const uint8_t* data) noexcept(false)\n{\n    uint64_t sliceBytes = uint64_t(stride) * uint64_t(rows);\n    if (sliceBytes > UINT32_MAX)\n    {\n        DebugTrace(\"ERROR: SpriteFont provided with an invalid .spritefont file\\n\");\n        throw std::overflow_error(\"Invalid .spritefont file\");\n    }\n\n    D3D12_RESOURCE_DESC desc = {};\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n    desc.Width = width;\n    desc.Height = height;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = format;\n    desc.SampleDesc.Count = 1;\n\n    CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    ThrowIfFailed(device->CreateCommittedResource(\n        &defaultHeapProperties,\n        D3D12_HEAP_FLAG_NONE,\n        &desc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_GRAPHICS_PPV_ARGS(textureResource.ReleaseAndGetAddressOf())));\n\n    SetDebugObjectName(textureResource.Get(), L\"SpriteFont:Texture\");\n\n    D3D12_SUBRESOURCE_DATA initData = { data, static_cast<LONG_PTR>(stride), static_cast<LONG_PTR>(sliceBytes) };\n\n    upload.Upload(\n        textureResource.Get(),\n        0,\n        &initData,\n        1);\n\n    upload.Transition(\n        textureResource.Get(),\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n}\n\n\nconst wchar_t* SpriteFont::Impl::ConvertUTF8(_In_z_ const char *text) noexcept(false)\n{\n    if (!utfBuffer)\n    {\n        utfBufferSize = 1024;\n        utfBuffer.reset(new wchar_t[1024]);\n    }\n\n    int result = MultiByteToWideChar(CP_UTF8, 0, text, -1, utfBuffer.get(), static_cast<int>(utfBufferSize));\n    if (!result && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))\n    {\n        // Compute required buffer size\n        result = MultiByteToWideChar(CP_UTF8, 0, text, -1, nullptr, 0);\n        utfBufferSize = AlignUp(static_cast<size_t>(result), 1024u);\n        utfBuffer.reset(new wchar_t[utfBufferSize]);\n\n        // Retry conversion\n        result = MultiByteToWideChar(CP_UTF8, 0, text, -1, utfBuffer.get(), static_cast<int>(utfBufferSize));\n    }\n\n    if (!result)\n    {\n        DebugTrace(\"ERROR: MultiByteToWideChar failed with error %u.\\n\", GetLastError());\n        throw std::exception(\"MultiByteToWideChar\");\n    }\n\n    return utfBuffer.get();\n}\n\n\n// Construct from a binary file created by the MakeSpriteFont utility.\n_Use_decl_annotations_\nSpriteFont::SpriteFont(ID3D12Device* device, ResourceUploadBatch& upload, wchar_t const* fileName, D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorDest, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorDest, bool forceSRGB)\n{\n    BinaryReader reader(fileName);\n\n    pImpl = std::make_unique<Impl>(device, upload, &reader, cpuDescriptorDest, gpuDescriptorDest, forceSRGB);\n}\n\n\n// Construct from a binary blob created by the MakeSpriteFont utility and already loaded into memory.\n_Use_decl_annotations_\nSpriteFont::SpriteFont(ID3D12Device* device, ResourceUploadBatch& upload, uint8_t const* dataBlob, size_t dataSize, D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorDest, D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorDest, bool forceSRGB)\n{\n    BinaryReader reader(dataBlob, dataSize);\n\n    pImpl = std::make_unique<Impl>(device, upload, &reader, cpuDescriptorDest, gpuDescriptorDest, forceSRGB);\n}\n\n\n// Construct from arbitrary user specified glyph data (for those not using the MakeSpriteFont utility).\n_Use_decl_annotations_\nSpriteFont::SpriteFont(D3D12_GPU_DESCRIPTOR_HANDLE texture, XMUINT2 textureSize, Glyph const* glyphs, size_t glyphCount, float lineSpacing)\n    : pImpl(std::make_unique<Impl>(texture, textureSize, glyphs, glyphCount, lineSpacing))\n{\n}\n\n\n// Move constructor.\nSpriteFont::SpriteFont(SpriteFont&& moveFrom) noexcept\n    : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nSpriteFont& SpriteFont::operator= (SpriteFont&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nSpriteFont::~SpriteFont()\n{\n}\n\n\n// Wide-character / UTF-16LE\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, float scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, text, XMLoadFloat2(&position), color, rotation, XMLoadFloat2(&origin), XMVectorReplicate(scale), effects, layerDepth);\n}\n\n\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, text, XMLoadFloat2(&position), color, rotation, XMLoadFloat2(&origin), XMLoadFloat2(&scale), effects, layerDepth);\n}\n\n\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, float scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, text, position, color, rotation, origin, XMVectorReplicate(scale), effects, layerDepth);\n}\n\n\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ wchar_t const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects, float layerDepth) const\n{\n    static_assert(SpriteEffects_FlipHorizontally == 1 &&\n                  SpriteEffects_FlipVertically == 2, \"If you change these enum values, the following tables must be updated to match\");\n\n    // Lookup table indicates which way to move along each axis per SpriteEffects enum value.\n    static XMVECTORF32 axisDirectionTable[4] =\n    {\n        { { { -1, -1, 0, 0 } } },\n        { { {  1, -1, 0, 0 } } },\n        { { { -1,  1, 0, 0 } } },\n        { { {  1,  1, 0, 0 } } },\n    };\n\n    // Lookup table indicates which axes are mirrored for each SpriteEffects enum value.\n    static XMVECTORF32 axisIsMirroredTable[4] =\n    {\n        { { { 0, 0, 0, 0 } } },\n        { { { 1, 0, 0, 0 } } },\n        { { { 0, 1, 0, 0 } } },\n        { { { 1, 1, 0, 0 } } },\n    };\n\n    XMVECTOR baseOffset = origin;\n\n    // If the text is mirrored, offset the start position accordingly.\n    if (effects)\n    {\n        baseOffset = XMVectorNegativeMultiplySubtract(\n            MeasureString(text),\n            axisIsMirroredTable[effects & 3],\n            baseOffset);\n    }\n\n    // Draw each character in turn.\n    pImpl->ForEachGlyph(text, [&](Glyph const* glyph, float x, float y, float advance)\n    {\n        UNREFERENCED_PARAMETER(advance);\n\n        XMVECTOR offset = XMVectorMultiplyAdd(XMVectorSet(x, y + glyph->YOffset, 0, 0), axisDirectionTable[effects & 3], baseOffset);\n\n        if (effects)\n        {\n            // For mirrored characters, specify bottom and/or right instead of top left.\n            XMVECTOR glyphRect = XMConvertVectorIntToFloat(XMLoadInt4(reinterpret_cast<uint32_t const*>(&glyph->Subrect)), 0);\n\n            // xy = glyph width/height.\n            glyphRect = XMVectorSubtract(XMVectorSwizzle<2, 3, 0, 1>(glyphRect), glyphRect);\n\n            offset = XMVectorMultiplyAdd(glyphRect, axisIsMirroredTable[effects & 3], offset);\n        }\n\n        spriteBatch->Draw(pImpl->texture, pImpl->textureSize, position, &glyph->Subrect, color, rotation, offset, scale, effects, layerDepth);\n    }, true);\n}\n\n\nXMVECTOR XM_CALLCONV SpriteFont::MeasureString(_In_z_ wchar_t const* text, bool ignoreWhitespace) const\n{\n    XMVECTOR result = XMVectorZero();\n\n    pImpl->ForEachGlyph(text, [&](Glyph const* glyph, float x, float y, float advance)\n        {\n            UNREFERENCED_PARAMETER(advance);\n\n            auto w = static_cast<float>(glyph->Subrect.right - glyph->Subrect.left);\n            auto h = static_cast<float>(glyph->Subrect.bottom - glyph->Subrect.top) + glyph->YOffset;\n\n            h = iswspace(wchar_t(glyph->Character)) ?\n                pImpl->lineSpacing :\n                std::max(h, pImpl->lineSpacing);\n\n            result = XMVectorMax(result, XMVectorSet(x + w, y + h, 0, 0));\n        }, ignoreWhitespace);\n\n    return result;\n}\n\n\nRECT SpriteFont::MeasureDrawBounds(_In_z_ wchar_t const* text, XMFLOAT2 const& position, bool ignoreWhitespace) const\n{\n    RECT result = { LONG_MAX, LONG_MAX, 0, 0 };\n\n    pImpl->ForEachGlyph(text, [&](Glyph const* glyph, float x, float y, float advance) noexcept\n        {\n            auto isWhitespace = iswspace(wchar_t(glyph->Character));\n            auto w = static_cast<float>(glyph->Subrect.right - glyph->Subrect.left);\n            auto h = isWhitespace ?\n                pImpl->lineSpacing :\n                static_cast<float>(glyph->Subrect.bottom - glyph->Subrect.top);\n\n            float minX = position.x + x;\n            float minY = position.y + y + (isWhitespace ? 0.0f : glyph->YOffset);\n\n            float maxX = std::max(minX + advance, minX + w);\n            float maxY = minY + h;\n\n            if (minX < float(result.left))\n                result.left = long(minX);\n\n            if (minY < float(result.top))\n                result.top = long(minY);\n\n            if (float(result.right) < maxX)\n                result.right = long(maxX);\n\n            if (float(result.bottom) < maxY)\n                result.bottom = long(maxY);\n        }, ignoreWhitespace);\n\n    if (result.left == LONG_MAX)\n    {\n        result.left = 0;\n        result.top = 0;\n    }\n\n    return result;\n}\n\n\nRECT XM_CALLCONV SpriteFont::MeasureDrawBounds(_In_z_ wchar_t const* text, FXMVECTOR position, bool ignoreWhitespace) const\n{\n    XMFLOAT2 pos;\n    XMStoreFloat2(&pos, position);\n\n    return MeasureDrawBounds(text, pos, ignoreWhitespace);\n}\n\n\n// UTF-8\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, float scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, pImpl->ConvertUTF8(text), XMLoadFloat2(&position), color, rotation, XMLoadFloat2(&origin), XMVectorReplicate(scale), effects, layerDepth);\n}\n\n\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, XMFLOAT2 const& position, FXMVECTOR color, float rotation, XMFLOAT2 const& origin, XMFLOAT2 const& scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, pImpl->ConvertUTF8(text), XMLoadFloat2(&position), color, rotation, XMLoadFloat2(&origin), XMLoadFloat2(&scale), effects, layerDepth);\n}\n\n\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, float scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, pImpl->ConvertUTF8(text), position, color, rotation, origin, XMVectorReplicate(scale), effects, layerDepth);\n}\n\n\nvoid XM_CALLCONV SpriteFont::DrawString(_In_ SpriteBatch* spriteBatch, _In_z_ char const* text, FXMVECTOR position, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects, float layerDepth) const\n{\n    DrawString(spriteBatch, pImpl->ConvertUTF8(text), position, color, rotation, origin, scale, effects, layerDepth);\n}\n\n\nXMVECTOR XM_CALLCONV SpriteFont::MeasureString(_In_z_ char const* text, bool ignoreWhitespace) const\n{\n    return MeasureString(pImpl->ConvertUTF8(text), ignoreWhitespace);\n}\n\n\nRECT SpriteFont::MeasureDrawBounds(_In_z_ char const* text, XMFLOAT2 const& position, bool ignoreWhitespace) const\n{\n    return MeasureDrawBounds(pImpl->ConvertUTF8(text), position, ignoreWhitespace);\n}\n\n\nRECT XM_CALLCONV SpriteFont::MeasureDrawBounds(_In_z_ char const* text, FXMVECTOR position, bool ignoreWhitespace) const\n{\n    XMFLOAT2 pos;\n    XMStoreFloat2(&pos, position);\n\n    return MeasureDrawBounds(pImpl->ConvertUTF8(text), pos, ignoreWhitespace);\n}\n\n\n// Spacing properties\nfloat SpriteFont::GetLineSpacing() const noexcept\n{\n    return pImpl->lineSpacing;\n}\n\n\nvoid SpriteFont::SetLineSpacing(float spacing)\n{\n    pImpl->lineSpacing = spacing;\n}\n\n\n// Font properties\nwchar_t SpriteFont::GetDefaultCharacter() const noexcept\n{\n    return static_cast<wchar_t>(pImpl->defaultGlyph ? pImpl->defaultGlyph->Character : 0);\n}\n\n\nvoid SpriteFont::SetDefaultCharacter(wchar_t character)\n{\n    pImpl->SetDefaultCharacter(character);\n}\n\n\nbool SpriteFont::ContainsCharacter(wchar_t character) const\n{\n    return std::binary_search(pImpl->glyphs.begin(), pImpl->glyphs.end(), character);\n}\n\n\n// Custom layout/rendering\nSpriteFont::Glyph const* SpriteFont::FindGlyph(wchar_t character) const\n{\n    return pImpl->FindGlyph(character);\n}\n\n\nD3D12_GPU_DESCRIPTOR_HANDLE SpriteFont::GetSpriteSheet() const noexcept\n{\n    return pImpl->texture;\n}\n\n\nXMUINT2 SpriteFont::GetSpriteSheetSize() const noexcept\n{\n    return pImpl->textureSize;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/TeapotData.inc",
    "content": "//--------------------------------------------------------------------------------------\n// File: TeapotData.inc\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n\n// The teapot model consists of 10 bezier patches. Each patch has 16 control\n// points, plus a flag indicating whether it should be mirrored in the Z axis\n// as well as in X (all of the teapot is symmetrical from left to right, but\n// only some parts are symmetrical from front to back). The control points\n// are stored as integer indices into the TeapotControlPoints array.\n\nstruct TeapotPatch\n{\n    bool mirrorZ;\n    int indices[16];\n};\n\n\n// Static data array defines the bezier patches that make up the teapot.\nconst TeapotPatch TeapotPatches[] =\n{\n    // Rim.\n    { true, { 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },\n\n    // Body.\n    { true, { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 } },\n    { true, { 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 } },\n\n    // Lid.\n    { true, { 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3 } },\n    { true, { 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 } },\n\n    // Handle.\n    { false, { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 } },\n    { false, { 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67 } },\n\n    // Spout.\n    { false, { 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83 } },\n    { false, { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 } },\n\n    // Bottom.\n    { true, { 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37 } },\n};\n\n\n// Static array defines the control point positions that make up the teapot.\nconst DirectX::XMVECTORF32 TeapotControlPoints[] = \n{\n    { { { 0, 0.345f, -0.05f, 0 } } },\n    { { { -0.028f, 0.345f, -0.05f, 0 } } },\n    { { { -0.05f, 0.345f, -0.028f, 0 } } },\n    { { { -0.05f, 0.345f, -0, 0 } } },\n    { { { 0, 0.3028125f, -0.334375f, 0 } } },\n    { { { -0.18725f, 0.3028125f, -0.334375f, 0 } } },\n    { { { -0.334375f, 0.3028125f, -0.18725f, 0 } } },\n    { { { -0.334375f, 0.3028125f, -0, 0 } } },\n    { { { 0, 0.3028125f, -0.359375f, 0 } } },\n    { { { -0.20125f, 0.3028125f, -0.359375f, 0 } } },\n    { { { -0.359375f, 0.3028125f, -0.20125f, 0 } } },\n    { { { -0.359375f, 0.3028125f, -0, 0 } } },\n    { { { 0, 0.27f, -0.375f, 0 } } },\n    { { { -0.21f, 0.27f, -0.375f, 0 } } },\n    { { { -0.375f, 0.27f, -0.21f, 0 } } },\n    { { { -0.375f, 0.27f, -0, 0 } } },\n    { { { 0, 0.13875f, -0.4375f, 0 } } },\n    { { { -0.245f, 0.13875f, -0.4375f, 0 } } },\n    { { { -0.4375f, 0.13875f, -0.245f, 0 } } },\n    { { { -0.4375f, 0.13875f, -0, 0 } } },\n    { { { 0, 0.007499993f, -0.5f, 0 } } },\n    { { { -0.28f, 0.007499993f, -0.5f, 0 } } },\n    { { { -0.5f, 0.007499993f, -0.28f, 0 } } },\n    { { { -0.5f, 0.007499993f, -0, 0 } } },\n    { { { 0, -0.105f, -0.5f, 0 } } },\n    { { { -0.28f, -0.105f, -0.5f, 0 } } },\n    { { { -0.5f, -0.105f, -0.28f, 0 } } },\n    { { { -0.5f, -0.105f, -0, 0 } } },\n    { { { 0, -0.105f, 0.5f, 0 } } },\n    { { { 0, -0.2175f, -0.5f, 0 } } },\n    { { { -0.28f, -0.2175f, -0.5f, 0 } } },\n    { { { -0.5f, -0.2175f, -0.28f, 0 } } },\n    { { { -0.5f, -0.2175f, -0, 0 } } },\n    { { { 0, -0.27375f, -0.375f, 0 } } },\n    { { { -0.21f, -0.27375f, -0.375f, 0 } } },\n    { { { -0.375f, -0.27375f, -0.21f, 0 } } },\n    { { { -0.375f, -0.27375f, -0, 0 } } },\n    { { { 0, -0.2925f, -0.375f, 0 } } },\n    { { { -0.21f, -0.2925f, -0.375f, 0 } } },\n    { { { -0.375f, -0.2925f, -0.21f, 0 } } },\n    { { { -0.375f, -0.2925f, -0, 0 } } },\n    { { { 0, 0.17625f, 0.4f, 0 } } },\n    { { { -0.075f, 0.17625f, 0.4f, 0 } } },\n    { { { -0.075f, 0.2325f, 0.375f, 0 } } },\n    { { { 0, 0.2325f, 0.375f, 0 } } },\n    { { { 0, 0.17625f, 0.575f, 0 } } },\n    { { { -0.075f, 0.17625f, 0.575f, 0 } } },\n    { { { -0.075f, 0.2325f, 0.625f, 0 } } },\n    { { { 0, 0.2325f, 0.625f, 0 } } },\n    { { { 0, 0.17625f, 0.675f, 0 } } },\n    { { { -0.075f, 0.17625f, 0.675f, 0 } } },\n    { { { -0.075f, 0.2325f, 0.75f, 0 } } },\n    { { { 0, 0.2325f, 0.75f, 0 } } },\n    { { { 0, 0.12f, 0.675f, 0 } } },\n    { { { -0.075f, 0.12f, 0.675f, 0 } } },\n    { { { -0.075f, 0.12f, 0.75f, 0 } } },\n    { { { 0, 0.12f, 0.75f, 0 } } },\n    { { { 0, 0.06375f, 0.675f, 0 } } },\n    { { { -0.075f, 0.06375f, 0.675f, 0 } } },\n    { { { -0.075f, 0.007499993f, 0.75f, 0 } } },\n    { { { 0, 0.007499993f, 0.75f, 0 } } },\n    { { { 0, -0.04875001f, 0.625f, 0 } } },\n    { { { -0.075f, -0.04875001f, 0.625f, 0 } } },\n    { { { -0.075f, -0.09562501f, 0.6625f, 0 } } },\n    { { { 0, -0.09562501f, 0.6625f, 0 } } },\n    { { { -0.075f, -0.105f, 0.5f, 0 } } },\n    { { { -0.075f, -0.18f, 0.475f, 0 } } },\n    { { { 0, -0.18f, 0.475f, 0 } } },\n    { { { 0, 0.02624997f, -0.425f, 0 } } },\n    { { { -0.165f, 0.02624997f, -0.425f, 0 } } },\n    { { { -0.165f, -0.18f, -0.425f, 0 } } },\n    { { { 0, -0.18f, -0.425f, 0 } } },\n    { { { 0, 0.02624997f, -0.65f, 0 } } },\n    { { { -0.165f, 0.02624997f, -0.65f, 0 } } },\n    { { { -0.165f, -0.12375f, -0.775f, 0 } } },\n    { { { 0, -0.12375f, -0.775f, 0 } } },\n    { { { 0, 0.195f, -0.575f, 0 } } },\n    { { { -0.0625f, 0.195f, -0.575f, 0 } } },\n    { { { -0.0625f, 0.17625f, -0.6f, 0 } } },\n    { { { 0, 0.17625f, -0.6f, 0 } } },\n    { { { 0, 0.27f, -0.675f, 0 } } },\n    { { { -0.0625f, 0.27f, -0.675f, 0 } } },\n    { { { -0.0625f, 0.27f, -0.825f, 0 } } },\n    { { { 0, 0.27f, -0.825f, 0 } } },\n    { { { 0, 0.28875f, -0.7f, 0 } } },\n    { { { -0.0625f, 0.28875f, -0.7f, 0 } } },\n    { { { -0.0625f, 0.2934375f, -0.88125f, 0 } } },\n    { { { 0, 0.2934375f, -0.88125f, 0 } } },\n    { { { 0, 0.28875f, -0.725f, 0 } } },\n    { { { -0.0375f, 0.28875f, -0.725f, 0 } } },\n    { { { -0.0375f, 0.298125f, -0.8625f, 0 } } },\n    { { { 0, 0.298125f, -0.8625f, 0 } } },\n    { { { 0, 0.27f, -0.7f, 0 } } },\n    { { { -0.0375f, 0.27f, -0.7f, 0 } } },\n    { { { -0.0375f, 0.27f, -0.8f, 0 } } },\n    { { { 0, 0.27f, -0.8f, 0 } } },\n    { { { 0, 0.4575f, -0, 0 } } },\n    { { { 0, 0.4575f, -0.2f, 0 } } },\n    { { { -0.1125f, 0.4575f, -0.2f, 0 } } },\n    { { { -0.2f, 0.4575f, -0.1125f, 0 } } },\n    { { { -0.2f, 0.4575f, -0, 0 } } },\n    { { { 0, 0.3825f, -0, 0 } } },\n    { { { 0, 0.27f, -0.35f, 0 } } },\n    { { { -0.196f, 0.27f, -0.35f, 0 } } },\n    { { { -0.35f, 0.27f, -0.196f, 0 } } },\n    { { { -0.35f, 0.27f, -0, 0 } } },\n    { { { 0, 0.3075f, -0.1f, 0 } } },\n    { { { -0.056f, 0.3075f, -0.1f, 0 } } },\n    { { { -0.1f, 0.3075f, -0.056f, 0 } } },\n    { { { -0.1f, 0.3075f, -0, 0 } } },\n    { { { 0, 0.3075f, -0.325f, 0 } } },\n    { { { -0.182f, 0.3075f, -0.325f, 0 } } },\n    { { { -0.325f, 0.3075f, -0.182f, 0 } } },\n    { { { -0.325f, 0.3075f, -0, 0 } } },\n    { { { 0, 0.27f, -0.325f, 0 } } },\n    { { { -0.182f, 0.27f, -0.325f, 0 } } },\n    { { { -0.325f, 0.27f, -0.182f, 0 } } },\n    { { { -0.325f, 0.27f, -0, 0 } } },\n    { { { 0, -0.33f, -0, 0 } } },\n    { { { -0.1995f, -0.33f, -0.35625f, 0 } } },\n    { { { 0, -0.31125f, -0.375f, 0 } } },\n    { { { 0, -0.33f, -0.35625f, 0 } } },\n    { { { -0.35625f, -0.33f, -0.1995f, 0 } } },\n    { { { -0.375f, -0.31125f, -0, 0 } } },\n    { { { -0.35625f, -0.33f, -0, 0 } } },\n    { { { -0.21f, -0.31125f, -0.375f, 0 } } },\n    { { { -0.375f, -0.31125f, -0.21f, 0 } } },\n};\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/ToneMapPostProcess.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: ToneMapPostProcess.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"PostProcess.h\"\n\n#include \"AlignedNew.h\"\n#include \"CommonStates.h\"\n#include \"DemandCreate.h\"\n#include \"DirectXHelpers.h\"\n#include \"EffectPipelineStateDescription.h\"\n#include \"GraphicsMemory.h\"\n#include \"SharedResourcePool.h\"\n\nusing namespace DirectX;\n\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    constexpr int Dirty_ConstantBuffer  = 0x01;\n    constexpr int Dirty_Parameters      = 0x02;\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    constexpr int PixelShaderCount = 15;\n    constexpr int ShaderPermutationCount = 24;\n#else\n    constexpr int PixelShaderCount = 9;\n    constexpr int ShaderPermutationCount = 12;\n#endif\n\n    // Constant buffer layout. Must match the shader!\n    __declspec(align(16)) struct ToneMapConstants\n    {\n        // linearExposure is .x\n        // paperWhiteNits is .y\n        XMVECTOR parameters;\n    };\n\n    static_assert((sizeof(ToneMapConstants) % 16) == 0, \"CB size not padded correctly\");\n}\n\n// Include the precompiled shader code.\nnamespace\n{\n#ifdef _GAMING_XBOX_SCARLETT\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSCopy.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSSaturate.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSReinhard.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSACESFilmic.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PS_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSSaturate_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSReinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSACESFilmic_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10_Saturate.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10_Reinhard.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10_ACESFilmic.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10_Saturate_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10_Reinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingScarlettToneMap_PSHDR10_ACESFilmic_SRGB.inc\"\n#elif defined(_GAMING_XBOX)\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSCopy.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSSaturate.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSReinhard.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSACESFilmic.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PS_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSSaturate_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSReinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSACESFilmic_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10_Saturate.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10_Reinhard.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10_ACESFilmic.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10_Saturate_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10_Reinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxGamingXboxOneToneMap_PSHDR10_ACESFilmic_SRGB.inc\"\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n    #include \"Shaders/Compiled/XboxOneToneMap_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/XboxOneToneMap_PSCopy.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSSaturate.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSReinhard.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSACESFilmic.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PS_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSSaturate_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSReinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSACESFilmic_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10_Saturate.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10_Reinhard.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10_ACESFilmic.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10_Saturate_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10_Reinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/XboxOneToneMap_PSHDR10_ACESFilmic_SRGB.inc\"\n#else\n    #include \"Shaders/Compiled/ToneMap_VSQuad.inc\"\n\n    #include \"Shaders/Compiled/ToneMap_PSCopy.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSSaturate.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSReinhard.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSACESFilmic.inc\"\n    #include \"Shaders/Compiled/ToneMap_PS_SRGB.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSSaturate_SRGB.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSReinhard_SRGB.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSACESFilmic_SRGB.inc\"\n    #include \"Shaders/Compiled/ToneMap_PSHDR10.inc\"\n#endif\n}\n\nnamespace\n{\n    const D3D12_SHADER_BYTECODE vertexShader =\n        { ToneMap_VSQuad,                   sizeof(ToneMap_VSQuad) };\n\n    const D3D12_SHADER_BYTECODE pixelShaders[] =\n    {\n        { ToneMap_PSCopy,                   sizeof(ToneMap_PSCopy) },\n        { ToneMap_PSSaturate,               sizeof(ToneMap_PSSaturate) },\n        { ToneMap_PSReinhard,               sizeof(ToneMap_PSReinhard) },\n        { ToneMap_PSACESFilmic,             sizeof(ToneMap_PSACESFilmic) },\n        { ToneMap_PS_SRGB,                  sizeof(ToneMap_PS_SRGB) },\n        { ToneMap_PSSaturate_SRGB,          sizeof(ToneMap_PSSaturate_SRGB) },\n        { ToneMap_PSReinhard_SRGB,          sizeof(ToneMap_PSReinhard_SRGB) },\n        { ToneMap_PSACESFilmic_SRGB,        sizeof(ToneMap_PSACESFilmic_SRGB) },\n        { ToneMap_PSHDR10,                  sizeof(ToneMap_PSHDR10) },\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        // Shaders that generate both HDR10 and GameDVR SDR signals via Multiple Render Targets.\n        { ToneMap_PSHDR10_Saturate,         sizeof(ToneMap_PSHDR10_Saturate) },\n        { ToneMap_PSHDR10_Reinhard,         sizeof(ToneMap_PSHDR10_Reinhard) },\n        { ToneMap_PSHDR10_ACESFilmic,       sizeof(ToneMap_PSHDR10_ACESFilmic) },\n        { ToneMap_PSHDR10_Saturate_SRGB,    sizeof(ToneMap_PSHDR10_Saturate_SRGB) },\n        { ToneMap_PSHDR10_Reinhard_SRGB,    sizeof(ToneMap_PSHDR10_Reinhard_SRGB) },\n        { ToneMap_PSHDR10_ACESFilmic_SRGB,  sizeof(ToneMap_PSHDR10_ACESFilmic_SRGB) },\n#endif\n    };\n\n    static_assert(_countof(pixelShaders) == PixelShaderCount, \"array/max mismatch\");\n\n    const int pixelShaderIndices[] =\n    {\n        // Linear EOTF\n        0,  // Copy\n        1,  // Saturate\n        2,  // Reinhard\n        3,  // ACES Filmic\n\n        // Gamam22 EOTF\n        4,  // SRGB\n        5,  // Saturate_SRGB\n        6,  // Reinhard_SRGB\n        7,  // ACES Filmic\n\n        // ST.2084 EOTF\n        8,  // HDR10\n        8,  // HDR10\n        8,  // HDR10\n        8,  // HDR10\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        // MRT Linear EOTF\n        9,  // HDR10+Saturate\n        9,  // HDR10+Saturate\n        10, // HDR10+Reinhard\n        11, // HDR10+ACESFilmic\n\n        // MRT Gamma22 EOTF\n        12, // HDR10+Saturate_SRGB\n        12, // HDR10+Saturate_SRGB\n        13, // HDR10+Reinhard_SRGB\n        14,  // HDR10+ACESFilmic\n\n        // MRT ST.2084 EOTF\n        9,  // HDR10+Saturate\n        9,  // HDR10+Saturate\n        10, // HDR10+Reinhard\n        11, // HDR10+ACESFilmic\n#endif\n    };\n\n    static_assert(_countof(pixelShaderIndices) == ShaderPermutationCount, \"array/max mismatch\");\n\n    // Factory for lazily instantiating shared root signatures.\n    class DeviceResources\n    {\n    public:\n        DeviceResources(_In_ ID3D12Device* device) noexcept\n            : mDevice(device)\n        { }\n\n        ID3D12RootSignature* GetRootSignature(const D3D12_ROOT_SIGNATURE_DESC& desc)\n        {\n            return DemandCreate(mRootSignature, mMutex, [&](ID3D12RootSignature** pResult) noexcept -> HRESULT\n            {\n                HRESULT hr = CreateRootSignature(mDevice.Get(), &desc, pResult);\n\n                if (SUCCEEDED(hr))\n                    SetDebugObjectName(*pResult, L\"ToneMapPostProcess\");\n\n                return hr;\n            });\n        }\n\n        ID3D12Device* GetDevice() const noexcept { return mDevice.Get(); }\n\n    protected:\n        ComPtr<ID3D12Device>                        mDevice;\n        Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature;\n        std::mutex                                  mMutex;\n    };\n}\n\nclass ToneMapPostProcess::Impl : public AlignedNew<ToneMapConstants>\n{\npublic:\n    Impl(_In_ ID3D12Device* device, const RenderTargetState& rtState, Operator op, TransferFunction func, bool mrt = false);\n\n    void Process(_In_ ID3D12GraphicsCommandList* commandList);\n\n    void SetDirtyFlag() noexcept { mDirtyFlags = INT_MAX; }\n\n    enum RootParameterIndex\n    {\n        TextureSRV,\n        ConstantBuffer,\n        RootParameterCount\n    };\n\n    // Fields.\n    ToneMapConstants                        constants;\n    D3D12_GPU_DESCRIPTOR_HANDLE             texture;\n    float                                   linearExposure;\n    float                                   paperWhiteNits;\n\nprivate:\n    int                                     mDirtyFlags;\n\n   // D3D constant buffer holds a copy of the same data as the public 'constants' field.\n    GraphicsResource mConstantBuffer;\n\n    // Per instance cache of PSOs, populated with variants for each shader & layout\n    Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;\n\n    // Per instance root signature\n    ID3D12RootSignature* mRootSignature;\n\n    // Per-device resources.\n    std::shared_ptr<DeviceResources> mDeviceResources;\n\n    static SharedResourcePool<ID3D12Device*, DeviceResources> deviceResourcesPool;\n};\n\n\n// Global pool of per-device ToneMapPostProcess resources.\nSharedResourcePool<ID3D12Device*, DeviceResources> ToneMapPostProcess::Impl::deviceResourcesPool;\n\n\n// Constructor.\nToneMapPostProcess::Impl::Impl(_In_ ID3D12Device* device, const RenderTargetState& rtState, Operator op, TransferFunction func, bool mrt)\n    : constants{},\n    texture{},\n    linearExposure(1.f),\n    paperWhiteNits(200.f),\n    mDirtyFlags(INT_MAX),\n    mDeviceResources(deviceResourcesPool.DemandCreate(device))\n{\n    if (op >= Operator_Max)\n        throw std::out_of_range(\"Tonemap operator not defined\");\n\n    if (func > TransferFunction_Max)\n        throw std::out_of_range(\"Transfer function not defined\");\n\n    // Create root signature.\n    {\n        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;\n\n        CD3DX12_DESCRIPTOR_RANGE textureSRVs(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n\n        // Same as CommonStates::StaticPointClamp\n        CD3DX12_STATIC_SAMPLER_DESC sampler(\n            0, // register\n            D3D12_FILTER_MIN_MAG_MIP_POINT,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n            0.f,\n            16,\n            D3D12_COMPARISON_FUNC_LESS_EQUAL,\n            D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n            0.f,\n            D3D12_FLOAT32_MAX,\n            D3D12_SHADER_VISIBILITY_PIXEL);\n        \n        CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};\n\n        CD3DX12_DESCRIPTOR_RANGE texture1Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);\n        rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRVs, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        // Root parameter descriptor\n        CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};\n\n        // Constant buffer\n        rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_PIXEL);\n\n        rsigDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags);\n\n        mRootSignature = mDeviceResources->GetRootSignature(rsigDesc);\n    }\n\n    assert(mRootSignature != nullptr);\n\n    // Determine shader permutation.\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n    int permutation = (mrt) ? 12 : 0;\n    permutation += (static_cast<int>(func) * static_cast<int>(Operator_Max)) + static_cast<int>(op);\n#else\n    UNREFERENCED_PARAMETER(mrt);\n    int permutation = (static_cast<int>(func) * static_cast<int>(Operator_Max)) + static_cast<int>(op);\n#endif\n\n    assert(permutation >= 0 && permutation < ShaderPermutationCount);\n    _Analysis_assume_(permutation >= 0 && permutation < ShaderPermutationCount);\n\n    int shaderIndex = pixelShaderIndices[permutation];\n    assert(shaderIndex >= 0 && shaderIndex < PixelShaderCount);\n    _Analysis_assume_(shaderIndex >= 0 && shaderIndex < PixelShaderCount);\n\n    // Create pipeline state.\n    EffectPipelineStateDescription psd(nullptr,\n        CommonStates::Opaque,\n        CommonStates::DepthNone,\n        CommonStates::CullNone,\n        rtState,\n        D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);\n\n    psd.CreatePipelineState(\n        device,\n        mRootSignature,\n        vertexShader,\n        pixelShaders[shaderIndex],\n        mPipelineState.GetAddressOf());\n\n    SetDebugObjectName(mPipelineState.Get(), L\"ToneMapPostProcess\");\n}\n\n\n// Sets our state onto the D3D device.\nvoid ToneMapPostProcess::Impl::Process(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    // Set the root signature.\n    commandList->SetGraphicsRootSignature(mRootSignature);\n\n    // Set the texture.\n    if (!texture.ptr)\n    {\n        DebugTrace(\"ERROR: Missing texture for ToneMapPostProcess (texture %llu)\\n\", texture.ptr);\n        throw std::exception(\"ToneMapPostProcess\");\n    }\n    commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);\n\n    // Set constants.\n    if (mDirtyFlags & Dirty_Parameters)\n    {\n        mDirtyFlags &= ~Dirty_Parameters;\n        mDirtyFlags |= Dirty_ConstantBuffer;\n\n        constants.parameters = XMVectorSet(linearExposure, paperWhiteNits, 0.f, 0.f);\n    }\n\n    if (mDirtyFlags & Dirty_ConstantBuffer)\n    {\n        mDirtyFlags &= ~Dirty_ConstantBuffer;\n        mConstantBuffer = GraphicsMemory::Get(mDeviceResources->GetDevice()).AllocateConstant(constants);\n    }\n\n    commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, mConstantBuffer.GpuAddress());\n\n    // Set the pipeline state.\n    commandList->SetPipelineState(mPipelineState.Get());\n\n    // Draw quad.\n    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n    commandList->DrawInstanced(3, 1, 0, 0);\n}\n\n\n// Public constructor.\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\nToneMapPostProcess::ToneMapPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState, Operator op, TransferFunction func, bool mrt)\n  : pImpl(std::make_unique<Impl>(device, rtState, op, func, mrt))\n#else\nToneMapPostProcess::ToneMapPostProcess(_In_ ID3D12Device* device, const RenderTargetState& rtState, Operator op, TransferFunction func)\n    : pImpl(std::make_unique<Impl>(device, rtState, op, func))\n#endif\n{\n}\n\n\n// Move constructor.\nToneMapPostProcess::ToneMapPostProcess(ToneMapPostProcess&& moveFrom) noexcept\n  : pImpl(std::move(moveFrom.pImpl))\n{\n}\n\n\n// Move assignment.\nToneMapPostProcess& ToneMapPostProcess::operator= (ToneMapPostProcess&& moveFrom) noexcept\n{\n    pImpl = std::move(moveFrom.pImpl);\n    return *this;\n}\n\n\n// Public destructor.\nToneMapPostProcess::~ToneMapPostProcess()\n{\n}\n\n\n// IPostProcess methods.\nvoid ToneMapPostProcess::Process(_In_ ID3D12GraphicsCommandList* commandList)\n{\n    pImpl->Process(commandList);\n}\n\n\n// Properties\nvoid ToneMapPostProcess::SetHDRSourceTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor)\n{\n    pImpl->texture = srvDescriptor;\n}\n\n\nvoid ToneMapPostProcess::SetExposure(float exposureValue)\n{\n    pImpl->linearExposure = powf(2.f, exposureValue);\n    pImpl->SetDirtyFlag();\n}\n\n\nvoid ToneMapPostProcess::SetST2084Parameter(float paperWhiteNits)\n{\n    pImpl->paperWhiteNits = paperWhiteNits;\n    pImpl->SetDirtyFlag();\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/VertexTypes.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: VertexTypes.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"VertexTypes.h\"\n\nusing namespace DirectX;\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPosition::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPosition) == 12, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPosition::InputLayout =\n{\n    VertexPosition::InputElements,\n    VertexPosition::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position and color information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionColor::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"COLOR\",       0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionColor) == 28, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionColor::InputLayout =\n{\n    VertexPositionColor::InputElements,\n    VertexPositionColor::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position and texture mapping information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionTexture::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"TEXCOORD\",    0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionTexture) == 20, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionTexture::InputLayout =\n{\n    VertexPositionTexture::InputElements,\n    VertexPositionTexture::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position and dual texture mapping information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionDualTexture::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"TEXCOORD\",    0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"TEXCOORD\",    1, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionDualTexture) == 28, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionDualTexture::InputLayout =\n{\n    VertexPositionDualTexture::InputElements,\n    VertexPositionDualTexture::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position and normal vector.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionNormal::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"NORMAL\",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionNormal) == 24, \"Vertex struct/layout mismatch\");\n\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position, color, and texture mapping information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionColorTexture::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"COLOR\",       0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"TEXCOORD\",    0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionColorTexture) == 36, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionColorTexture::InputLayout =\n{\n    VertexPositionColorTexture::InputElements,\n    VertexPositionColorTexture::InputElementCount\n};\n\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position, normal vector, and color information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionNormalColor::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"NORMAL\",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"COLOR\",       0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionNormalColor) == 40, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionNormalColor::InputLayout =\n{\n    VertexPositionNormalColor::InputElements,\n    VertexPositionNormalColor::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position, normal vector, and texture mapping information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionNormalTexture::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"NORMAL\",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"TEXCOORD\",    0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionNormalTexture) == 32, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionNormalTexture::InputLayout =\n{\n    VertexPositionNormalTexture::InputElements,\n    VertexPositionNormalTexture::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex struct holding position, normal vector, color, and texture mapping information.\nconst D3D12_INPUT_ELEMENT_DESC VertexPositionNormalColorTexture::InputElements[] =\n{\n    { \"SV_Position\", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"NORMAL\",      0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"COLOR\",       0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    { \"TEXCOORD\",    0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n};\n\nstatic_assert(sizeof(VertexPositionNormalColorTexture) == 48, \"Vertex struct/layout mismatch\");\n\nconst D3D12_INPUT_LAYOUT_DESC VertexPositionNormalColorTexture::InputLayout =\n{\n    VertexPositionNormalColorTexture::InputElements,\n    VertexPositionNormalColorTexture::InputElementCount\n};\n\n//--------------------------------------------------------------------------------------\n// VertexPositionNormalTangentColorTexture, VertexPositionNormalTangentColorTextureSkinning are not\n// supported for DirectX 12 since they were only present for DGSL\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/WICTextureLoader.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: WICTextureLoader.cpp\n//\n// Function for loading a WIC image and creating a Direct3D runtime texture for it\n// (auto-generating mipmaps if possible)\n//\n// Note: Assumes application has already called CoInitializeEx\n//\n// Note these functions are useful for images created as simple 2D textures. For\n// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.\n// For a full-featured DDS file reader, writer, and texture processing pipeline see\n// the 'Texconv' sample and the 'DirectXTex' library.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n// We could load multi-frame images (TIFF/GIF) into a texture array.\n// For now, we just load the first frame (note: DirectXTex supports multi-frame images)\n\n#include \"pch.h\"\n\n#include \"WICTextureLoader.h\"\n\n#include \"DirectXHelpers.h\"\n#include \"PlatformHelpers.h\"\n#include \"LoaderHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // WIC Pixel Format Translation Data\n    //-------------------------------------------------------------------------------------\n    struct WICTranslate\n    {\n        GUID                wic;\n        DXGI_FORMAT         format;\n    };\n\n    const WICTranslate g_WICFormats[] =\n    {\n        { GUID_WICPixelFormat128bppRGBAFloat,       DXGI_FORMAT_R32G32B32A32_FLOAT },\n\n        { GUID_WICPixelFormat64bppRGBAHalf,         DXGI_FORMAT_R16G16B16A16_FLOAT },\n        { GUID_WICPixelFormat64bppRGBA,             DXGI_FORMAT_R16G16B16A16_UNORM },\n\n        { GUID_WICPixelFormat32bppRGBA,             DXGI_FORMAT_R8G8B8A8_UNORM },\n        { GUID_WICPixelFormat32bppBGRA,             DXGI_FORMAT_B8G8R8A8_UNORM },\n        { GUID_WICPixelFormat32bppBGR,              DXGI_FORMAT_B8G8R8X8_UNORM },\n\n        { GUID_WICPixelFormat32bppRGBA1010102XR,    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },\n        { GUID_WICPixelFormat32bppRGBA1010102,      DXGI_FORMAT_R10G10B10A2_UNORM },\n\n        { GUID_WICPixelFormat16bppBGRA5551,         DXGI_FORMAT_B5G5R5A1_UNORM },\n        { GUID_WICPixelFormat16bppBGR565,           DXGI_FORMAT_B5G6R5_UNORM },\n\n        { GUID_WICPixelFormat32bppGrayFloat,        DXGI_FORMAT_R32_FLOAT },\n        { GUID_WICPixelFormat16bppGrayHalf,         DXGI_FORMAT_R16_FLOAT },\n        { GUID_WICPixelFormat16bppGray,             DXGI_FORMAT_R16_UNORM },\n        { GUID_WICPixelFormat8bppGray,              DXGI_FORMAT_R8_UNORM },\n\n        { GUID_WICPixelFormat8bppAlpha,             DXGI_FORMAT_A8_UNORM },\n\n        { GUID_WICPixelFormat96bppRGBFloat,         DXGI_FORMAT_R32G32B32_FLOAT },\n    };\n\n    //-------------------------------------------------------------------------------------\n    // WIC Pixel Format nearest conversion table\n    //-------------------------------------------------------------------------------------\n\n    struct WICConvert\n    {\n        GUID        source;\n        GUID        target;\n    };\n\n    const WICConvert g_WICConvert[] =\n    {\n        // Note target GUID in this conversion table must be one of those directly supported formats (above).\n\n        { GUID_WICPixelFormatBlackWhite,            GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM\n\n        { GUID_WICPixelFormat1bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n        { GUID_WICPixelFormat2bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n        { GUID_WICPixelFormat4bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n        { GUID_WICPixelFormat8bppIndexed,           GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n\n        { GUID_WICPixelFormat2bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM \n        { GUID_WICPixelFormat4bppGray,              GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM \n\n        { GUID_WICPixelFormat16bppGrayFixedPoint,   GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT \n        { GUID_WICPixelFormat32bppGrayFixedPoint,   GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT \n\n        { GUID_WICPixelFormat16bppBGR555,           GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM\n\n        { GUID_WICPixelFormat32bppBGR101010,        GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM\n\n        { GUID_WICPixelFormat24bppBGR,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n        { GUID_WICPixelFormat24bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n        { GUID_WICPixelFormat32bppPBGRA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n        { GUID_WICPixelFormat32bppPRGBA,            GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM \n\n        { GUID_WICPixelFormat48bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat48bppBGR,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppBGRA,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppPRGBA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppPBGRA,            GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n\n        { GUID_WICPixelFormat48bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n        { GUID_WICPixelFormat48bppBGRFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n        { GUID_WICPixelFormat64bppRGBAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n        { GUID_WICPixelFormat64bppBGRAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n        { GUID_WICPixelFormat64bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n        { GUID_WICPixelFormat64bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n        { GUID_WICPixelFormat48bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT \n\n        { GUID_WICPixelFormat128bppPRGBAFloat,      GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT \n        { GUID_WICPixelFormat128bppRGBFloat,        GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT \n        { GUID_WICPixelFormat128bppRGBAFixedPoint,  GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT \n        { GUID_WICPixelFormat128bppRGBFixedPoint,   GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT \n        { GUID_WICPixelFormat32bppRGBE,             GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT \n\n        { GUID_WICPixelFormat32bppCMYK,             GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat64bppCMYK,             GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat40bppCMYKAlpha,        GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat80bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n\n        { GUID_WICPixelFormat32bppRGB,              GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat64bppRGB,              GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppPRGBAHalf,        GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n\n        { GUID_WICPixelFormat96bppRGBFixedPoint,   GUID_WICPixelFormat96bppRGBFloat }, // DXGI_FORMAT_R32G32B32_FLOAT\n\n        // We don't support n-channel formats\n    };\n\n    BOOL WINAPI InitializeWICFactory(PINIT_ONCE, PVOID, PVOID *ifactory) noexcept\n    {\n        return SUCCEEDED(CoCreateInstance(\n            CLSID_WICImagingFactory2,\n            nullptr,\n            CLSCTX_INPROC_SERVER,\n            __uuidof(IWICImagingFactory2),\n            ifactory)) ? TRUE : FALSE;\n    }\n}\n\n//--------------------------------------------------------------------------------------\nnamespace DirectX\n{\n    IWICImagingFactory2* _GetWIC() noexcept;\n        // Also used by ScreenGrab\n\n    IWICImagingFactory2* _GetWIC() noexcept\n    {\n        static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;\n\n        IWICImagingFactory2* factory = nullptr;\n        if (!InitOnceExecuteOnce(\n            &s_initOnce,\n            InitializeWICFactory,\n            nullptr,\n            reinterpret_cast<LPVOID*>(&factory)))\n        {\n            return nullptr;\n        }\n\n        return factory;\n    }\n} // namespace DirectX\n\n\nnamespace\n{\n    //---------------------------------------------------------------------------------\n    DXGI_FORMAT _WICToDXGI(const GUID& guid) noexcept\n    {\n        for (size_t i = 0; i < _countof(g_WICFormats); ++i)\n        {\n            if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0)\n                return g_WICFormats[i].format;\n        }\n\n        return DXGI_FORMAT_UNKNOWN;\n    }\n\n    //---------------------------------------------------------------------------------\n    size_t _WICBitsPerPixel(REFGUID targetGuid) noexcept\n    {\n        auto pWIC = _GetWIC();\n        if (!pWIC)\n            return 0;\n\n        ComPtr<IWICComponentInfo> cinfo;\n        if (FAILED(pWIC->CreateComponentInfo(targetGuid, cinfo.GetAddressOf())))\n            return 0;\n\n        WICComponentType type;\n        if (FAILED(cinfo->GetComponentType(&type)))\n            return 0;\n\n        if (type != WICPixelFormat)\n            return 0;\n\n        ComPtr<IWICPixelFormatInfo> pfinfo;\n        if (FAILED(cinfo.As(&pfinfo)))\n            return 0;\n\n        UINT bpp;\n        if (FAILED(pfinfo->GetBitsPerPixel(&bpp)))\n            return 0;\n\n        return bpp;\n    }\n\n    //---------------------------------------------------------------------------------\n    HRESULT CreateTextureFromWIC(_In_ ID3D12Device* d3dDevice,\n        _In_ IWICBitmapFrameDecode *frame,\n        size_t maxsize,\n        D3D12_RESOURCE_FLAGS resFlags,\n        WIC_LOADER_FLAGS loadFlags,\n        _Outptr_ ID3D12Resource** texture,\n        std::unique_ptr<uint8_t[]>& decodedData,\n        D3D12_SUBRESOURCE_DATA& subresource) noexcept\n    {\n        UINT width, height;\n        HRESULT hr = frame->GetSize(&width, &height);\n        if (FAILED(hr))\n            return hr;\n\n        assert(width > 0 && height > 0);\n\n        if (maxsize > UINT32_MAX)\n            return E_INVALIDARG;\n\n        if (!maxsize)\n        {\n            maxsize = size_t(D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION);\n        }\n\n        UINT twidth = width;\n        UINT theight = height;\n        if (loadFlags & WIC_LOADER_FIT_POW2)\n        {\n            LoaderHelpers::FitPowerOf2(width, height, twidth, theight, maxsize);\n        }\n        else if (width > maxsize || height > maxsize)\n        {\n            float ar = static_cast<float>(height) / static_cast<float>(width);\n            if (width > height)\n            {\n                twidth = static_cast<UINT>(maxsize);\n                theight = std::max<UINT>(1, static_cast<UINT>(static_cast<float>(maxsize) * ar));\n            }\n            else\n            {\n                theight = static_cast<UINT>(maxsize);\n                twidth = std::max<UINT>(1, static_cast<UINT>(static_cast<float>(maxsize) / ar));\n            }\n            assert(twidth <= maxsize && theight <= maxsize);\n        }\n\n        if (loadFlags & WIC_LOADER_MAKE_SQUARE)\n        {\n            twidth = std::max<UINT>(twidth, theight);\n            theight = twidth;\n        }\n\n        // Determine format\n        WICPixelFormatGUID pixelFormat;\n        hr = frame->GetPixelFormat(&pixelFormat);\n        if (FAILED(hr))\n            return hr;\n\n        WICPixelFormatGUID convertGUID;\n        memcpy_s(&convertGUID, sizeof(WICPixelFormatGUID), &pixelFormat, sizeof(GUID));\n\n        size_t bpp = 0;\n\n        DXGI_FORMAT format = _WICToDXGI(pixelFormat);\n        if (format == DXGI_FORMAT_UNKNOWN)\n        {\n            for (size_t i = 0; i < _countof(g_WICConvert); ++i)\n            {\n                if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)\n                {\n                    memcpy_s(&convertGUID, sizeof(WICPixelFormatGUID), &g_WICConvert[i].target, sizeof(GUID));\n\n                    format = _WICToDXGI(g_WICConvert[i].target);\n                    assert(format != DXGI_FORMAT_UNKNOWN);\n                    bpp = _WICBitsPerPixel(convertGUID);\n                    break;\n                }\n            }\n\n            if (format == DXGI_FORMAT_UNKNOWN)\n            {\n                DebugTrace(\"ERROR: WICTextureLoader does not support all DXGI formats (WIC GUID {%8.8lX-%4.4X-%4.4X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X}). Consider using DirectXTex.\\n\",\n                    pixelFormat.Data1, pixelFormat.Data2, pixelFormat.Data3,\n                    pixelFormat.Data4[0], pixelFormat.Data4[1], pixelFormat.Data4[2], pixelFormat.Data4[3],\n                    pixelFormat.Data4[4], pixelFormat.Data4[5], pixelFormat.Data4[6], pixelFormat.Data4[7]);\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n        }\n        else\n        {\n            bpp = _WICBitsPerPixel(pixelFormat);\n        }\n\n        if (loadFlags & WIC_LOADER_FORCE_RGBA32)\n        {\n            memcpy_s(&convertGUID, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat32bppRGBA, sizeof(GUID));\n            format = DXGI_FORMAT_R8G8B8A8_UNORM;\n            bpp = 32;\n        }\n\n        if (!bpp)\n            return E_FAIL;\n\n        // Handle sRGB formats\n        if (loadFlags & WIC_LOADER_FORCE_SRGB)\n        {\n            format = LoaderHelpers::MakeSRGB(format);\n        }\n        else if (!(loadFlags & WIC_LOADER_IGNORE_SRGB))\n        {\n            ComPtr<IWICMetadataQueryReader> metareader;\n            if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf())))\n            {\n                GUID containerFormat;\n                if (SUCCEEDED(metareader->GetContainerFormat(&containerFormat)))\n                {\n                    bool sRGB = false;\n\n                    PROPVARIANT value;\n                    PropVariantInit(&value);\n\n                    // Check for colorspace chunks\n                    if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0)\n                    {\n                        // Check for sRGB chunk\n                        if (SUCCEEDED(metareader->GetMetadataByName(L\"/sRGB/RenderingIntent\", &value)) && value.vt == VT_UI1)\n                        {\n                            sRGB = true;\n                        }\n                        else if (SUCCEEDED(metareader->GetMetadataByName(L\"/gAMA/ImageGamma\", &value)) && value.vt == VT_UI4)\n                        {\n                            sRGB = (value.uintVal == 45455);\n                        }\n                        else\n                        {\n                            sRGB = (loadFlags & WIC_LOADER_SRGB_DEFAULT) != 0;\n                        }\n                    }\n                #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n                    else if (memcmp(&containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)) == 0)\n                    {\n                        if (SUCCEEDED(metareader->GetMetadataByName(L\"/app1/ifd/exif/{ushort=40961}\", &value)) && value.vt == VT_UI2)\n                        {\n                            sRGB = (value.uiVal == 1);\n                        }\n                        else\n                        {\n                            sRGB = (loadFlags & WIC_LOADER_SRGB_DEFAULT) != 0;\n                        }\n                    }\n                    else if (memcmp(&containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)) == 0)\n                    {\n                        if (SUCCEEDED(metareader->GetMetadataByName(L\"/ifd/exif/{ushort=40961}\", &value)) && value.vt == VT_UI2)\n                        {\n                            sRGB = (value.uiVal == 1);\n                        }\n                        else\n                        {\n                            sRGB = (loadFlags & WIC_LOADER_SRGB_DEFAULT) != 0;\n                        }\n                    }\n                #else\n                    else if (SUCCEEDED(metareader->GetMetadataByName(L\"System.Image.ColorSpace\", &value)) && value.vt == VT_UI2)\n                    {\n                        sRGB = (value.uiVal == 1);\n                    }\n                    else\n                    {\n                        sRGB = (loadFlags & WIC_LOADER_SRGB_DEFAULT) != 0;\n                    }\n                #endif\n\n                    (void)PropVariantClear(&value);\n\n                    if (sRGB)\n                        format = LoaderHelpers::MakeSRGB(format);\n                }\n            }\n        }\n\n        // Allocate memory for decoded image\n        uint64_t rowBytes = (uint64_t(twidth) * uint64_t(bpp) + 7u) / 8u;\n        uint64_t numBytes = rowBytes * uint64_t(height);\n\n        if (rowBytes > UINT32_MAX || numBytes > UINT32_MAX)\n            return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n        auto rowPitch = static_cast<size_t>(rowBytes);\n        auto imageSize = static_cast<size_t>(numBytes);\n\n        decodedData.reset(new (std::nothrow) uint8_t[imageSize]);\n        if (!decodedData)\n            return E_OUTOFMEMORY;\n\n        // Load image data\n        if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0\n            && twidth == width\n            && theight == height)\n        {\n            // No format conversion or resize needed\n            hr = frame->CopyPixels(nullptr, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), decodedData.get());\n            if (FAILED(hr))\n                return hr;\n        }\n        else if (twidth != width || theight != height)\n        {\n            // Resize\n            auto pWIC = _GetWIC();\n            if (!pWIC)\n                return E_NOINTERFACE;\n\n            ComPtr<IWICBitmapScaler> scaler;\n            hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant);\n            if (FAILED(hr))\n                return hr;\n\n            WICPixelFormatGUID pfScaler;\n            hr = scaler->GetPixelFormat(&pfScaler);\n            if (FAILED(hr))\n                return hr;\n\n            if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0)\n            {\n                // No format conversion needed\n                hr = scaler->CopyPixels(nullptr, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), decodedData.get());\n                if (FAILED(hr))\n                    return hr;\n            }\n            else\n            {\n                ComPtr<IWICFormatConverter> FC;\n                hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n                if (FAILED(hr))\n                    return hr;\n\n                BOOL canConvert = FALSE;\n                hr = FC->CanConvert(pfScaler, convertGUID, &canConvert);\n                if (FAILED(hr) || !canConvert)\n                {\n                    return E_UNEXPECTED;\n                }\n\n                hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut);\n                if (FAILED(hr))\n                    return hr;\n\n                hr = FC->CopyPixels(nullptr, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), decodedData.get());\n                if (FAILED(hr))\n                    return hr;\n            }\n        }\n        else\n        {\n            // Format conversion but no resize\n            auto pWIC = _GetWIC();\n            if (!pWIC)\n                return E_NOINTERFACE;\n\n            ComPtr<IWICFormatConverter> FC;\n            hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            BOOL canConvert = FALSE;\n            hr = FC->CanConvert(pixelFormat, convertGUID, &canConvert);\n            if (FAILED(hr) || !canConvert)\n            {\n                return E_UNEXPECTED;\n            }\n\n            hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut);\n            if (FAILED(hr))\n                return hr;\n\n            hr = FC->CopyPixels(nullptr, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), decodedData.get());\n            if (FAILED(hr))\n                return hr;\n        }\n\n        // Count the number of mips\n        uint32_t mipCount = (loadFlags & (WIC_LOADER_MIP_AUTOGEN | WIC_LOADER_MIP_RESERVE))\n            ? LoaderHelpers::CountMips(twidth, theight) : 1u;\n\n        // Create texture\n        D3D12_RESOURCE_DESC desc = {};\n        desc.Width = twidth;\n        desc.Height = theight;\n        desc.MipLevels = static_cast<UINT16>(mipCount);\n        desc.DepthOrArraySize = 1;\n        desc.Format = format;\n        desc.SampleDesc.Count = 1;\n        desc.SampleDesc.Quality = 0;\n        desc.Flags = resFlags;\n        desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n\n        CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        ID3D12Resource* tex = nullptr;\n        hr = d3dDevice->CreateCommittedResource(\n            &defaultHeapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &desc,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(&tex));\n\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        _Analysis_assume_(tex != nullptr);\n\n        subresource.pData = decodedData.get();\n        subresource.RowPitch = static_cast<LONG>(rowPitch);\n        subresource.SlicePitch = static_cast<LONG>(imageSize);\n\n        *texture = tex;\n        return hr;\n    }\n\n    //--------------------------------------------------------------------------------------\n    void SetDebugTextureInfo(\n        _In_z_ const wchar_t* fileName,\n        _In_ ID3D12Resource** texture) noexcept\n    {\n#if !defined(NO_D3D12_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )\n        if (texture && *texture)\n        {\n            const wchar_t* pstrName = wcsrchr(fileName, '\\\\');\n            if (!pstrName)\n            {\n                pstrName = fileName;\n            }\n            else\n            {\n                pstrName++;\n            }\n\n            (*texture)->SetName(pstrName);\n        }\n#else\n        UNREFERENCED_PARAMETER(fileName);\n        UNREFERENCED_PARAMETER(texture);\n#endif\n    }\n\n    //--------------------------------------------------------------------------------------\n    DXGI_FORMAT GetPixelFormat(_In_ IWICBitmapFrameDecode* frame) noexcept\n    {\n        WICPixelFormatGUID pixelFormat;\n        if (FAILED(frame->GetPixelFormat(&pixelFormat)))\n            return DXGI_FORMAT_UNKNOWN;\n\n        DXGI_FORMAT format = _WICToDXGI(pixelFormat);\n        if (format == DXGI_FORMAT_UNKNOWN)\n        {\n            for (size_t i = 0; i < _countof(g_WICConvert); ++i)\n            {\n                if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)\n                {\n                    return _WICToDXGI(g_WICConvert[i].target);\n                }\n            }\n        }\n\n        return format;\n    }\n} // anonymous namespace\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWICTextureFromMemory(\n    ID3D12Device* d3dDevice,\n    const uint8_t* wicData,\n    size_t wicDataSize,\n    ID3D12Resource** texture,\n    std::unique_ptr<uint8_t[]>& decodedData,\n    D3D12_SUBRESOURCE_DATA& subresource,\n    size_t maxsize) noexcept\n{\n    return LoadWICTextureFromMemoryEx(\n        d3dDevice,\n        wicData,\n        wicDataSize,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        WIC_LOADER_DEFAULT,\n        texture,\n        decodedData,\n        subresource);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateWICTextureFromMemory(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const uint8_t* wicData,\n    size_t wicDataSize,\n    ID3D12Resource** texture,\n    bool generateMips,\n    size_t maxsize)\n{\n    return CreateWICTextureFromMemoryEx(\n        d3dDevice,\n        resourceUpload,\n        wicData,\n        wicDataSize,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        (generateMips) ? WIC_LOADER_MIP_AUTOGEN : WIC_LOADER_DEFAULT,\n        texture);\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWICTextureFromMemoryEx(\n    ID3D12Device* d3dDevice,\n    const uint8_t* wicData,\n    size_t wicDataSize,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    WIC_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture,\n    std::unique_ptr<uint8_t[]>& decodedData,\n    D3D12_SUBRESOURCE_DATA& subresource) noexcept\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n\n    if (!d3dDevice || !wicData || !texture)\n        return E_INVALIDARG;\n\n    if (!wicDataSize)\n        return E_FAIL;\n\n    if (wicDataSize > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);\n\n    auto pWIC = _GetWIC();\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    // Create input stream for memory\n    ComPtr<IWICStream> stream;\n    HRESULT hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromMemory(const_cast<uint8_t*>(wicData), static_cast<DWORD>(wicDataSize));\n    if (FAILED(hr))\n        return hr;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    hr = pWIC->CreateDecoderFromStream(stream.Get(), nullptr, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = CreateTextureFromWIC(d3dDevice,\n        frame.Get(), maxsize,\n        resFlags, loadFlags,\n        texture, decodedData, subresource);\n    if (FAILED(hr))\n        return hr;\n\n    _Analysis_assume_(*texture != nullptr);\n    SetDebugObjectName(*texture, L\"WICTextureLoader\");\n\n    return hr;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateWICTextureFromMemoryEx(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const uint8_t* wicData,\n    size_t wicDataSize,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    WIC_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture)\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n\n    if (!d3dDevice || !wicData || !texture)\n        return E_INVALIDARG;\n\n    if (!wicDataSize)\n        return E_FAIL;\n\n    if (wicDataSize > UINT32_MAX)\n        return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);\n\n    auto pWIC = _GetWIC();\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    // Create input stream for memory\n    ComPtr<IWICStream> stream;\n    HRESULT hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromMemory(const_cast<uint8_t*>(wicData), static_cast<DWORD>(wicDataSize));\n    if (FAILED(hr))\n        return hr;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    hr = pWIC->CreateDecoderFromStream(stream.Get(), nullptr, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    if (loadFlags & WIC_LOADER_MIP_AUTOGEN)\n    {\n        DXGI_FORMAT fmt = GetPixelFormat(frame.Get());\n        if (!resourceUpload.IsSupportedForGenerateMips(fmt))\n        {\n            DebugTrace(\"WARNING: Autogen of mips ignored (device doesn't support this format (%d) or trying to use a copy queue)\\n\", static_cast<int>(fmt));\n            loadFlags &= ~WIC_LOADER_MIP_AUTOGEN;\n        }\n    }\n\n    std::unique_ptr<uint8_t[]> decodedData;\n    D3D12_SUBRESOURCE_DATA initData;\n    hr = CreateTextureFromWIC(d3dDevice,\n        frame.Get(), maxsize,\n        resFlags, loadFlags,\n        texture, decodedData, initData);\n\n    if (SUCCEEDED(hr))\n    {\n        assert(texture != nullptr && *texture != nullptr);\n        _Analysis_assume_(texture != nullptr && *texture != nullptr);\n        SetDebugObjectName(*texture, L\"WICTextureLoader\");\n\n        resourceUpload.Upload(\n            *texture,\n            0,\n            &initData,\n            1);\n\n        resourceUpload.Transition(\n            *texture,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        // Generate mips?\n        if (loadFlags & WIC_LOADER_MIP_AUTOGEN)\n        {\n            resourceUpload.GenerateMips(*texture);\n        }\n    }\n\n    return hr;\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWICTextureFromFile(\n    ID3D12Device* d3dDevice,\n    const wchar_t* fileName,\n    ID3D12Resource** texture,\n    std::unique_ptr<uint8_t[]>& wicData,\n    D3D12_SUBRESOURCE_DATA& subresource,\n    size_t maxsize) noexcept\n{\n    return LoadWICTextureFromFileEx(\n        d3dDevice,\n        fileName,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        WIC_LOADER_DEFAULT,\n        texture,\n        wicData,\n        subresource);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateWICTextureFromFile(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const wchar_t* fileName,\n    ID3D12Resource** texture,\n    bool generateMips,\n    size_t maxsize)\n{\n    return CreateWICTextureFromFileEx(\n        d3dDevice,\n        resourceUpload,\n        fileName,\n        maxsize,\n        D3D12_RESOURCE_FLAG_NONE,\n        generateMips ? WIC_LOADER_MIP_AUTOGEN : WIC_LOADER_DEFAULT,\n        texture);\n}\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadWICTextureFromFileEx(\n    ID3D12Device* d3dDevice,\n    const wchar_t* fileName,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    WIC_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture,\n    std::unique_ptr<uint8_t[]>& decodedData,\n    D3D12_SUBRESOURCE_DATA& subresource) noexcept\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n\n    if (!d3dDevice || !fileName || !texture)\n        return E_INVALIDARG;\n\n    auto pWIC = _GetWIC();\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    HRESULT hr = pWIC->CreateDecoderFromFilename(fileName,\n        nullptr,\n        GENERIC_READ,\n        WICDecodeMetadataCacheOnDemand,\n        decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = CreateTextureFromWIC(d3dDevice, frame.Get(), maxsize,\n        resFlags, loadFlags,\n        texture, decodedData, subresource);\n\n    if (SUCCEEDED(hr))\n    {\n        SetDebugTextureInfo(fileName, texture);\n    }\n\n    return hr;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateWICTextureFromFileEx(\n    ID3D12Device* d3dDevice,\n    ResourceUploadBatch& resourceUpload,\n    const wchar_t* fileName,\n    size_t maxsize,\n    D3D12_RESOURCE_FLAGS resFlags,\n    WIC_LOADER_FLAGS loadFlags,\n    ID3D12Resource** texture)\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n\n    if (!d3dDevice || !fileName || !texture)\n        return E_INVALIDARG;\n\n    auto pWIC = _GetWIC();\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    HRESULT hr = pWIC->CreateDecoderFromFilename(fileName,\n        nullptr,\n        GENERIC_READ,\n        WICDecodeMetadataCacheOnDemand,\n        decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    if (loadFlags & WIC_LOADER_MIP_AUTOGEN)\n    {\n        DXGI_FORMAT fmt = GetPixelFormat(frame.Get());\n        if (!resourceUpload.IsSupportedForGenerateMips(fmt))\n        {\n            DebugTrace(\"WARNING: Autogen of mips ignored (device doesn't support this format (%d) or trying to use a copy queue)\\n\", static_cast<int>(fmt));\n            loadFlags &= ~WIC_LOADER_MIP_AUTOGEN;\n        }\n    }\n\n    std::unique_ptr<uint8_t[]> decodedData;\n    D3D12_SUBRESOURCE_DATA initData;\n    hr = CreateTextureFromWIC(d3dDevice, frame.Get(), maxsize,\n        resFlags, loadFlags,\n        texture, decodedData, initData);\n\n    if (SUCCEEDED(hr))\n    {\n        SetDebugTextureInfo(fileName, texture);\n\n        resourceUpload.Upload(\n            *texture,\n            0,\n            &initData,\n            1);\n\n        resourceUpload.Transition(\n            *texture,\n            D3D12_RESOURCE_STATE_COPY_DEST,\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        // Generate mips?\n        if (loadFlags & WIC_LOADER_MIP_AUTOGEN)\n        {\n            resourceUpload.GenerateMips(*texture);\n        }\n    }\n\n    return hr;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/XboxDDSTextureLoader.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: XboxDDSTextureLoader.cpp\n//\n// Functions for loading a DDS texture using the XBOX extended header and creating a\n// Direct3D12.X runtime resource for it via the CreatePlacedResourceX API\n//\n// Note these functions will not load standard DDS files. Use the DDSTextureLoader\n// module in the DirectXTex package or as part of the DirectXTK library to load\n// these files which use standard Direct3D resource creation APIs.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"XboxDDSTextureLoader.h\"\n\n#include \"PlatformHelpers.h\"\n#include \"DDS.h\"\n#include \"DirectXHelpers.h\"\n\n#ifdef _GAMING_XBOX\n#include <xmem.h>\n#endif\n\nusing namespace DirectX;\nusing namespace Xbox;\n\nnamespace\n{\n    //--------------------------------------------------------------------------------------\n    // Default XMemAlloc attributes for texture loading\n    //--------------------------------------------------------------------------------------\n    const uint64_t c_XMemAllocAttributes = MAKE_XALLOC_ATTRIBUTES(\n        eXALLOCAllocatorId_MiddlewareReservedMin,\n        0,\n        XALLOC_MEMTYPE_GRAPHICS_WRITECOMBINE_GPU_READONLY,\n        XALLOC_PAGESIZE_64KB,\n        XALLOC_ALIGNMENT_64K\n#ifdef _GAMING_XBOX\n        , 0\n#endif\n        );\n\n    //--------------------------------------------------------------------------------------\n    // DDS file structure definitions\n    //\n    // See DDS.h in the 'Texconv' sample and the 'DirectXTex' library\n    //--------------------------------------------------------------------------------------\n    #pragma pack(push,1)\n\n    struct DDS_HEADER_XBOX\n        // Must match structure defined in xtexconv tool\n    {\n        DXGI_FORMAT dxgiFormat;\n        uint32_t    resourceDimension;\n        uint32_t    miscFlag; // see DDS_RESOURCE_MISC_FLAG\n        uint32_t    arraySize;\n        uint32_t    miscFlags2; // see DDS_MISC_FLAGS2\n        uint32_t    tileMode; // see XG_TILE_MODE / XG_SWIZZLE_MODE\n        uint32_t    baseAlignment;\n        uint32_t    dataSize;\n        uint32_t    xdkVer; // matching _XDK_VER / _GXDK_VER\n    };\n\n    static const uint32_t XBOX_TILEMODE_SCARLETT = 0x1000000;\n\n    static_assert(sizeof(DDS_HEADER_XBOX) == 36, \"DDS XBOX Header size mismatch\");\n\n    #pragma pack(pop)\n\n    //--------------------------------------------------------------------------------------\n    HRESULT LoadTextureDataFromFile(_In_z_ const wchar_t* fileName,\n        std::unique_ptr<uint8_t[]>& ddsData,\n        DDS_HEADER** header,\n        uint8_t** bitData,\n        size_t* bitSize) noexcept\n    {\n        if (!header || !bitData || !bitSize)\n        {\n            return E_POINTER;\n        }\n\n        // open the file\n        ScopedHandle hFile(safe_handle(CreateFile2(fileName,\n            GENERIC_READ,\n            FILE_SHARE_READ,\n            OPEN_EXISTING,\n            nullptr)));\n\n        if (!hFile)\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        // Get the file size\n        FILE_STANDARD_INFO fileInfo;\n        if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        // File is too big for 32-bit allocation, so reject read\n        if (fileInfo.EndOfFile.HighPart > 0)\n        {\n            return E_FAIL;\n        }\n\n        // Need at least enough data to fill the header and magic number to be a valid DDS\n        if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t)))\n        {\n            return E_FAIL;\n        }\n\n        // create enough space for the file data\n        ddsData.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);\n        if (!ddsData)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n        // read the data in\n        DWORD BytesRead = 0;\n        if (!ReadFile(hFile.get(),\n            ddsData.get(),\n            fileInfo.EndOfFile.LowPart,\n            &BytesRead,\n            nullptr\n        ))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        if (BytesRead < fileInfo.EndOfFile.LowPart)\n        {\n            return E_FAIL;\n        }\n\n        // DDS files always start with the same magic number (\"DDS \")\n        auto dwMagicNumber = *reinterpret_cast<uint32_t*>(ddsData.get());\n        if (dwMagicNumber != DDS_MAGIC)\n        {\n            return E_FAIL;\n        }\n\n        auto hdr = reinterpret_cast<DDS_HEADER*>(ddsData.get() + sizeof(uint32_t));\n\n        // Verify header to validate DDS file\n        if (hdr->size != sizeof(DDS_HEADER) ||\n            hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))\n        {\n            return E_FAIL;\n        }\n\n        // Check for XBOX extension\n        if (!(hdr->ddspf.flags & DDS_FOURCC)\n            || (MAKEFOURCC('X', 'B', 'O', 'X') != hdr->ddspf.fourCC))\n        {\n            // Use standard DDSTextureLoader instead\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        // Must be long enough for both headers and magic value\n        if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_XBOX)))\n        {\n            return E_FAIL;\n        }\n\n        // setup the pointers in the process request\n        *header = hdr;\n        auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_XBOX);\n        *bitData = ddsData.get() + offset;\n        *bitSize = fileInfo.EndOfFile.LowPart - offset;\n\n        return S_OK;\n    }\n\n    //--------------------------------------------------------------------------------------\n    DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_R8G8B8A8_UNORM:\n            return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n\n        case DXGI_FORMAT_BC1_UNORM:\n            return DXGI_FORMAT_BC1_UNORM_SRGB;\n\n        case DXGI_FORMAT_BC2_UNORM:\n            return DXGI_FORMAT_BC2_UNORM_SRGB;\n\n        case DXGI_FORMAT_BC3_UNORM:\n            return DXGI_FORMAT_BC3_UNORM_SRGB;\n\n        case DXGI_FORMAT_B8G8R8A8_UNORM:\n            return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;\n\n        case DXGI_FORMAT_B8G8R8X8_UNORM:\n            return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;\n\n        case DXGI_FORMAT_BC7_UNORM:\n            return DXGI_FORMAT_BC7_UNORM_SRGB;\n\n        default:\n            return format;\n        }\n    }\n\n    //--------------------------------------------------------------------------------------\n    HRESULT CreateD3DResources(_In_ ID3D12Device* d3dDevice,\n        _In_ const DDS_HEADER_XBOX* xboxext,\n        _In_ uint32_t width,\n        _In_ uint32_t height,\n        _In_ uint32_t depth,\n        _In_ uint32_t mipCount,\n        _In_ uint32_t arraySize,\n        _In_ bool forceSRGB,\n        _In_ void* grfxMemory,\n        _Outptr_ ID3D12Resource** texture) noexcept\n    {\n        if (!d3dDevice || !grfxMemory)\n            return E_POINTER;\n\n        HRESULT hr = E_FAIL;\n\n        DXGI_FORMAT format = xboxext->dxgiFormat;\n        if (forceSRGB)\n        {\n            format = MakeSRGB(format);\n        }\n\n        D3D12_RESOURCE_DESC desc = {};\n        desc.Width = static_cast<UINT>(width);\n        desc.Height = static_cast<UINT>(height);\n        desc.MipLevels = static_cast<UINT16>(mipCount);\n        desc.DepthOrArraySize = (xboxext->resourceDimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) ? static_cast<UINT16>(depth) : static_cast<UINT16>(arraySize);\n        desc.Format = format;\n        desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n        desc.SampleDesc.Count = 1;\n        desc.SampleDesc.Quality = 0;\n        desc.Dimension = static_cast<D3D12_RESOURCE_DIMENSION>(xboxext->resourceDimension);\n        desc.Layout = static_cast<D3D12_TEXTURE_LAYOUT>((0x100 | xboxext->tileMode) & ~XBOX_TILEMODE_SCARLETT);\n\n        hr = d3dDevice->CreatePlacedResourceX(\n            reinterpret_cast<D3D12_GPU_VIRTUAL_ADDRESS>(grfxMemory),\n            &desc,\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,\n            nullptr,\n            IID_GRAPHICS_PPV_ARGS(texture));\n        if (SUCCEEDED(hr))\n        {\n            _Analysis_assume_(*texture != nullptr);\n            SetDebugObjectName(*texture, L\"XboxDDSTextureLoader\");\n        }\n\n        return hr;\n    }\n\n    //--------------------------------------------------------------------------------------\n    HRESULT CreateTextureFromDDS(_In_ ID3D12Device* d3dDevice,\n        _In_ const DDS_HEADER* header,\n        _In_reads_bytes_(bitSize) const uint8_t* bitData,\n        _In_ size_t bitSize,\n        _In_ bool forceSRGB,\n        _Outptr_ ID3D12Resource** texture,\n        _Outptr_ void** grfxMemory,\n        _Out_opt_ bool* outIsCubeMap) noexcept\n    {\n        HRESULT hr = S_OK;\n\n        uint32_t width = header->width;\n        uint32_t height = header->height;\n        uint32_t depth = header->depth;\n\n        uint32_t mipCount = header->mipMapCount;\n        if (0 == mipCount)\n        {\n            mipCount = 1;\n        }\n\n        if (!(header->ddspf.flags & DDS_FOURCC)\n            || (MAKEFOURCC('X', 'B', 'O', 'X') != header->ddspf.fourCC))\n        {\n            // Use standard DDSTextureLoader instead\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        auto xboxext = reinterpret_cast<const DDS_HEADER_XBOX*>(reinterpret_cast<const uint8_t*>(header) + sizeof(DDS_HEADER));\n\n#if !defined(NDEBUG) && defined(_GXDK_VER)\n        if (xboxext->xdkVer < _GXDK_VER)\n        {\n            OutputDebugStringA(\"WARNING: DDS XBOX file may be outdated and need regeneration\\n\");\n        }\n#elif !defined(NDEBUG) && defined(_XDK_VER)\n        if (xboxext->xdkVer < _XDK_VER)\n        {\n            OutputDebugStringA(\"WARNING: DDS XBOX file may be outdated and need regeneration\\n\");\n        }\n#endif\n\n        uint32_t arraySize = xboxext->arraySize;\n        if (arraySize == 0)\n        {\n            return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n        }\n\n        bool isCubeMap = false;\n\n        switch (xboxext->resourceDimension)\n        {\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            if ((header->flags & DDS_HEIGHT) && height != 1)\n            {\n                return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n            }\n            height = depth = 1;\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n            if (xboxext->miscFlag & 0x4 /* RESOURCE_MISC_TEXTURECUBE */)\n            {\n                arraySize *= 6;\n                isCubeMap = true;\n            }\n            depth = 1;\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))\n            {\n                return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n            }\n\n            if (arraySize > 1)\n            {\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n\n        default:\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        if (xboxext->tileMode == uint32_t(-1))\n        {\n            return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);\n        }\n#if defined(_GAMING_XBOX_SCARLETT)\n        else if (!(xboxext->tileMode & XBOX_TILEMODE_SCARLETT))\n        {\n            DebugTrace(\"ERROR: XboxDDSTextureLoader for Scarlett cannot load textures tiled for Xbox One\");\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n#else\n        else if (xboxext->tileMode & XBOX_TILEMODE_SCARLETT)\n        {\n            DebugTrace(\"ERROR: XboxDDSTextureLoader for Xbox One cannot load textures tiled for Scarlett\");\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n#endif\n\n        // Bound sizes\n        if (mipCount > D3D11_REQ_MIP_LEVELS)\n        {\n            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n        }\n\n        switch (xboxext->resourceDimension)\n        {\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            if ((arraySize > D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||\n                (width > D3D12_REQ_TEXTURE1D_U_DIMENSION))\n            {\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n            if (isCubeMap)\n            {\n                // This is the right bound because we set arraySize to (NumCubes*6) above\n                if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||\n                    (width > D3D12_REQ_TEXTURECUBE_DIMENSION) ||\n                    (height > D3D12_REQ_TEXTURECUBE_DIMENSION))\n                {\n                    return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n                }\n            }\n            else if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||\n                (width > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||\n                (height > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION))\n            {\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            if ((arraySize > 1) ||\n                (width > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||\n                (height > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||\n                (depth > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))\n            {\n                return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);\n            }\n            break;\n        }\n\n        if (xboxext->dxgiFormat == DXGI_FORMAT_UNKNOWN)\n        {\n            return E_FAIL;\n        }\n\n        if (!xboxext->dataSize || !xboxext->baseAlignment)\n        {\n            return E_FAIL;\n        }\n\n        if (xboxext->dataSize > bitSize)\n        {\n            return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n        }\n\n        // Allocate graphics memory. Depending on the data size it uses 4MB or 64K pages.\n        *grfxMemory = XMemAlloc(xboxext->dataSize, c_XMemAllocAttributes);\n        if (!*grfxMemory)\n            return E_OUTOFMEMORY;\n\n        // Copy tiled data into graphics memory\n        memcpy(*grfxMemory, bitData, xboxext->dataSize);\n\n        // Create the texture\n        hr = CreateD3DResources(d3dDevice, xboxext,\n            width, height, depth, mipCount, arraySize,\n            forceSRGB, *grfxMemory,\n            texture);\n        if (FAILED(hr))\n        {\n            XMemFree(*grfxMemory, c_XMemAllocAttributes);\n            *grfxMemory = nullptr;\n        }\n\n        if (outIsCubeMap)\n        {\n            *outIsCubeMap = isCubeMap;\n        }\n\n        return hr;\n    }\n\n    //--------------------------------------------------------------------------------------\n    DDS_ALPHA_MODE GetAlphaMode(_In_ const DDS_HEADER* header) noexcept\n    {\n        if (header->ddspf.flags & DDS_FOURCC)\n        {\n            if (MAKEFOURCC('X', 'B', 'O', 'X') == header->ddspf.fourCC)\n            {\n                auto xboxext = reinterpret_cast<const DDS_HEADER_XBOX*>(reinterpret_cast<const uint8_t*>(header) + sizeof(DDS_HEADER));\n                auto mode = static_cast<DDS_ALPHA_MODE>(xboxext->miscFlags2 & DDS_MISC_FLAGS2_ALPHA_MODE_MASK);\n                switch (mode)\n                {\n                case DDS_ALPHA_MODE_STRAIGHT:\n                case DDS_ALPHA_MODE_PREMULTIPLIED:\n                case DDS_ALPHA_MODE_OPAQUE:\n                case DDS_ALPHA_MODE_CUSTOM:\n                    return mode;\n\n                default:\n                    break;\n                }\n            }\n        }\n\n        return DDS_ALPHA_MODE_UNKNOWN;\n    }\n} // anonymous namespace\n\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT Xbox::CreateDDSTextureFromMemory(\n    ID3D12Device* d3dDevice,\n    const uint8_t* ddsData,\n    size_t ddsDataSize,\n    ID3D12Resource** texture,\n    void** grfxMemory,\n    DDS_ALPHA_MODE* alphaMode,\n    bool forceSRGB,\n    bool* isCubeMap ) noexcept\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n\n    if (grfxMemory)\n    {\n        *grfxMemory = nullptr;\n    }\n\n    if (alphaMode)\n    {\n        *alphaMode = DDS_ALPHA_MODE_UNKNOWN;\n    }\n\n    if (isCubeMap)\n    {\n        *isCubeMap = false;\n    }\n\n    if ( !d3dDevice || !ddsData || !texture || !grfxMemory )\n    {\n        return E_INVALIDARG;\n    }\n\n    // Validate DDS file in memory\n    if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER)))\n    {\n        return E_FAIL;\n    }\n\n    auto dwMagicNumber = *reinterpret_cast<const uint32_t*>(ddsData);\n    if (dwMagicNumber != DDS_MAGIC)\n    {\n        return E_FAIL;\n    }\n\n    auto header = reinterpret_cast<const DDS_HEADER*>( ddsData + sizeof( uint32_t ) );\n\n    // Verify header to validate DDS file\n    if (header->size != sizeof(DDS_HEADER) ||\n        header->ddspf.size != sizeof(DDS_PIXELFORMAT))\n    {\n        return E_FAIL;\n    }\n\n    // Check for XBOX extension\n    if ( !( header->ddspf.flags & DDS_FOURCC )\n         || ( MAKEFOURCC( 'X', 'B', 'O', 'X' ) != header->ddspf.fourCC ) )\n    {\n        // Use standard DDSTextureLoader instead\n        return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );\n    }\n\n    // Must be long enough for both headers and magic value\n    if (ddsDataSize < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_XBOX)))\n    {\n        return E_FAIL;\n    }\n\n    auto offset = sizeof( uint32_t ) + sizeof( DDS_HEADER ) + sizeof( DDS_HEADER_XBOX );\n\n    HRESULT hr = CreateTextureFromDDS( d3dDevice, header,\n                                       ddsData + offset, ddsDataSize - offset, forceSRGB,\n                                       texture, grfxMemory, isCubeMap );\n    if ( SUCCEEDED(hr) )\n    {\n        _Analysis_assume_(*texture != nullptr);\n        SetDebugObjectName(*texture, L\"XboxDDSTextureLoader\");\n\n        if ( alphaMode )\n            *alphaMode = GetAlphaMode( header );\n    }\n\n    return hr;\n}\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT Xbox::CreateDDSTextureFromFile( \n    ID3D12Device* d3dDevice,\n    const wchar_t* fileName,\n    ID3D12Resource** texture,\n    void** grfxMemory,\n    DDS_ALPHA_MODE* alphaMode,\n    bool forceSRGB,\n    bool* isCubeMap ) noexcept\n{\n    if (texture)\n    {\n        *texture = nullptr;\n    }\n\n    if (grfxMemory)\n    {\n        *grfxMemory = nullptr;\n    }\n\n    if (alphaMode)\n    {\n        *alphaMode = DDS_ALPHA_MODE_UNKNOWN;\n    }\n\n    if (isCubeMap)\n    {\n        *isCubeMap = false;\n    }\n\n    if ( !d3dDevice || !fileName || !texture || !grfxMemory )\n    {\n        return E_INVALIDARG;\n    }\n\n    DDS_HEADER* header = nullptr;\n    uint8_t* bitData = nullptr;\n    size_t bitSize = 0;\n\n    std::unique_ptr<uint8_t[]> ddsData;\n    HRESULT hr = LoadTextureDataFromFile( fileName,\n                                          ddsData,\n                                          &header,\n                                          &bitData,\n                                          &bitSize\n                                        );\n    if (FAILED(hr))\n    {\n        return hr;\n    }\n\n    hr = CreateTextureFromDDS( d3dDevice, header,\n                               bitData, bitSize, forceSRGB,\n                               texture, grfxMemory, isCubeMap );\n\n    if ( SUCCEEDED(hr) )\n    {\n#if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )\n        if (texture != nullptr && *texture != nullptr)\n        {\n            (*texture)->SetName( fileName );\n        }\n#endif\n\n        if ( alphaMode )\n            *alphaMode = GetAlphaMode( header );\n    }\n\n    return hr;\n}\n\n//--------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid Xbox::FreeDDSTextureMemory(void* grfxMemory) noexcept\n{\n    if (grfxMemory)\n    {\n        XMemFree(grfxMemory, c_XMemAllocAttributes);\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/d3dx12.h",
    "content": "//*********************************************************\n//\n// Copyright (c) Microsoft. All rights reserved.\n// This code is licensed under the MIT License (MIT).\n// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\n// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\n// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\n//\n//*********************************************************\n\n#ifndef __D3DX12_H__\n#define __D3DX12_H__\n\n#include \"d3d12.h\"\n\n#if defined( __cplusplus )\n\nstruct CD3DX12_DEFAULT {};\nextern const DECLSPEC_SELECTANY CD3DX12_DEFAULT D3D12_DEFAULT;\n\n//------------------------------------------------------------------------------------------------\ninline bool operator==( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept\n{\n    return l.TopLeftX == r.TopLeftX && l.TopLeftY == r.TopLeftY && l.Width == r.Width &&\n        l.Height == r.Height && l.MinDepth == r.MinDepth && l.MaxDepth == r.MaxDepth;\n}\n\n//------------------------------------------------------------------------------------------------\ninline bool operator!=( const D3D12_VIEWPORT& l, const D3D12_VIEWPORT& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RECT : public D3D12_RECT\n{\n    CD3DX12_RECT() = default;\n    explicit CD3DX12_RECT( const D3D12_RECT& o ) noexcept :\n        D3D12_RECT( o )\n    {}\n    explicit CD3DX12_RECT(\n        LONG Left,\n        LONG Top,\n        LONG Right,\n        LONG Bottom ) noexcept\n    {\n        left = Left;\n        top = Top;\n        right = Right;\n        bottom = Bottom;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_VIEWPORT : public D3D12_VIEWPORT\n{\n    CD3DX12_VIEWPORT() = default;\n    explicit CD3DX12_VIEWPORT( const D3D12_VIEWPORT& o ) noexcept :\n        D3D12_VIEWPORT( o )\n    {}\n    explicit CD3DX12_VIEWPORT(\n        FLOAT topLeftX,\n        FLOAT topLeftY,\n        FLOAT width,\n        FLOAT height,\n        FLOAT minDepth = D3D12_MIN_DEPTH,\n        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept\n    {\n        TopLeftX = topLeftX;\n        TopLeftY = topLeftY;\n        Width = width;\n        Height = height;\n        MinDepth = minDepth;\n        MaxDepth = maxDepth;\n    }\n    explicit CD3DX12_VIEWPORT(\n        _In_ ID3D12Resource* pResource,\n        UINT mipSlice = 0,\n        FLOAT topLeftX = 0.0f,\n        FLOAT topLeftY = 0.0f,\n        FLOAT minDepth = D3D12_MIN_DEPTH,\n        FLOAT maxDepth = D3D12_MAX_DEPTH ) noexcept\n    {\n        auto Desc = pResource->GetDesc();\n        const UINT64 SubresourceWidth = Desc.Width >> mipSlice;\n        const UINT64 SubresourceHeight = Desc.Height >> mipSlice;\n        switch (Desc.Dimension)\n        {\n        case D3D12_RESOURCE_DIMENSION_BUFFER:\n            TopLeftX = topLeftX;\n            TopLeftY = 0.0f;\n            Width = float(Desc.Width) - topLeftX;\n            Height = 1.0f;\n            break;\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            TopLeftX = topLeftX;\n            TopLeftY = 0.0f;\n            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;\n            Height = 1.0f;\n            break;\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            TopLeftX = topLeftX;\n            TopLeftY = topLeftY;\n            Width = (SubresourceWidth ? float(SubresourceWidth) : 1.0f) - topLeftX;\n            Height = (SubresourceHeight ? float(SubresourceHeight) : 1.0f) - topLeftY;\n            break;\n        default: break;\n        }\n\n        MinDepth = minDepth;\n        MaxDepth = maxDepth;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_BOX : public D3D12_BOX\n{\n    CD3DX12_BOX() = default;\n    explicit CD3DX12_BOX( const D3D12_BOX& o ) noexcept :\n        D3D12_BOX( o )\n    {}\n    explicit CD3DX12_BOX(\n        LONG Left,\n        LONG Right ) noexcept\n    {\n        left = static_cast<UINT>(Left);\n        top = 0;\n        front = 0;\n        right = static_cast<UINT>(Right);\n        bottom = 1;\n        back = 1;\n    }\n    explicit CD3DX12_BOX(\n        LONG Left,\n        LONG Top,\n        LONG Right,\n        LONG Bottom ) noexcept\n    {\n        left = static_cast<UINT>(Left);\n        top = static_cast<UINT>(Top);\n        front = 0;\n        right = static_cast<UINT>(Right);\n        bottom = static_cast<UINT>(Bottom);\n        back = 1;\n    }\n    explicit CD3DX12_BOX(\n        LONG Left,\n        LONG Top,\n        LONG Front,\n        LONG Right,\n        LONG Bottom,\n        LONG Back ) noexcept\n    {\n        left = static_cast<UINT>(Left);\n        top = static_cast<UINT>(Top);\n        front = static_cast<UINT>(Front);\n        right = static_cast<UINT>(Right);\n        bottom = static_cast<UINT>(Bottom);\n        back = static_cast<UINT>(Back);\n    }\n};\ninline bool operator==( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept\n{\n    return l.left == r.left && l.top == r.top && l.front == r.front &&\n        l.right == r.right && l.bottom == r.bottom && l.back == r.back;\n}\ninline bool operator!=( const D3D12_BOX& l, const D3D12_BOX& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_DEPTH_STENCIL_DESC : public D3D12_DEPTH_STENCIL_DESC\n{\n    CD3DX12_DEPTH_STENCIL_DESC() = default;\n    explicit CD3DX12_DEPTH_STENCIL_DESC( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept :\n        D3D12_DEPTH_STENCIL_DESC( o )\n    {}\n    explicit CD3DX12_DEPTH_STENCIL_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        DepthEnable = TRUE;\n        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;\n        DepthFunc = D3D12_COMPARISON_FUNC_LESS;\n        StencilEnable = FALSE;\n        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;\n        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;\n        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =\n        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };\n        FrontFace = defaultStencilOp;\n        BackFace = defaultStencilOp;\n    }\n    explicit CD3DX12_DEPTH_STENCIL_DESC(\n        BOOL depthEnable,\n        D3D12_DEPTH_WRITE_MASK depthWriteMask,\n        D3D12_COMPARISON_FUNC depthFunc,\n        BOOL stencilEnable,\n        UINT8 stencilReadMask,\n        UINT8 stencilWriteMask,\n        D3D12_STENCIL_OP frontStencilFailOp,\n        D3D12_STENCIL_OP frontStencilDepthFailOp,\n        D3D12_STENCIL_OP frontStencilPassOp,\n        D3D12_COMPARISON_FUNC frontStencilFunc,\n        D3D12_STENCIL_OP backStencilFailOp,\n        D3D12_STENCIL_OP backStencilDepthFailOp,\n        D3D12_STENCIL_OP backStencilPassOp,\n        D3D12_COMPARISON_FUNC backStencilFunc ) noexcept\n    {\n        DepthEnable = depthEnable;\n        DepthWriteMask = depthWriteMask;\n        DepthFunc = depthFunc;\n        StencilEnable = stencilEnable;\n        StencilReadMask = stencilReadMask;\n        StencilWriteMask = stencilWriteMask;\n        FrontFace.StencilFailOp = frontStencilFailOp;\n        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;\n        FrontFace.StencilPassOp = frontStencilPassOp;\n        FrontFace.StencilFunc = frontStencilFunc;\n        BackFace.StencilFailOp = backStencilFailOp;\n        BackFace.StencilDepthFailOp = backStencilDepthFailOp;\n        BackFace.StencilPassOp = backStencilPassOp;\n        BackFace.StencilFunc = backStencilFunc;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\n// Requires the Windows 10 Creators Update SDK (15063)\n#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\nstruct CD3DX12_DEPTH_STENCIL_DESC1 : public D3D12_DEPTH_STENCIL_DESC1\n{\n    CD3DX12_DEPTH_STENCIL_DESC1() = default;\n    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC1& o ) noexcept :\n        D3D12_DEPTH_STENCIL_DESC1( o )\n    {}\n    explicit CD3DX12_DEPTH_STENCIL_DESC1( const D3D12_DEPTH_STENCIL_DESC& o ) noexcept\n    {\n        DepthEnable                  = o.DepthEnable;\n        DepthWriteMask               = o.DepthWriteMask;\n        DepthFunc                    = o.DepthFunc;\n        StencilEnable                = o.StencilEnable;\n        StencilReadMask              = o.StencilReadMask;\n        StencilWriteMask             = o.StencilWriteMask;\n        FrontFace.StencilFailOp      = o.FrontFace.StencilFailOp;\n        FrontFace.StencilDepthFailOp = o.FrontFace.StencilDepthFailOp;\n        FrontFace.StencilPassOp      = o.FrontFace.StencilPassOp;\n        FrontFace.StencilFunc        = o.FrontFace.StencilFunc;\n        BackFace.StencilFailOp       = o.BackFace.StencilFailOp;\n        BackFace.StencilDepthFailOp  = o.BackFace.StencilDepthFailOp;\n        BackFace.StencilPassOp       = o.BackFace.StencilPassOp;\n        BackFace.StencilFunc         = o.BackFace.StencilFunc;\n        DepthBoundsTestEnable        = FALSE;\n    }\n    explicit CD3DX12_DEPTH_STENCIL_DESC1( CD3DX12_DEFAULT ) noexcept\n    {\n        DepthEnable = TRUE;\n        DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;\n        DepthFunc = D3D12_COMPARISON_FUNC_LESS;\n        StencilEnable = FALSE;\n        StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;\n        StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;\n        const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =\n        { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };\n        FrontFace = defaultStencilOp;\n        BackFace = defaultStencilOp;\n        DepthBoundsTestEnable = FALSE;\n    }\n    explicit CD3DX12_DEPTH_STENCIL_DESC1(\n        BOOL depthEnable,\n        D3D12_DEPTH_WRITE_MASK depthWriteMask,\n        D3D12_COMPARISON_FUNC depthFunc,\n        BOOL stencilEnable,\n        UINT8 stencilReadMask,\n        UINT8 stencilWriteMask,\n        D3D12_STENCIL_OP frontStencilFailOp,\n        D3D12_STENCIL_OP frontStencilDepthFailOp,\n        D3D12_STENCIL_OP frontStencilPassOp,\n        D3D12_COMPARISON_FUNC frontStencilFunc,\n        D3D12_STENCIL_OP backStencilFailOp,\n        D3D12_STENCIL_OP backStencilDepthFailOp,\n        D3D12_STENCIL_OP backStencilPassOp,\n        D3D12_COMPARISON_FUNC backStencilFunc,\n        BOOL depthBoundsTestEnable ) noexcept\n    {\n        DepthEnable = depthEnable;\n        DepthWriteMask = depthWriteMask;\n        DepthFunc = depthFunc;\n        StencilEnable = stencilEnable;\n        StencilReadMask = stencilReadMask;\n        StencilWriteMask = stencilWriteMask;\n        FrontFace.StencilFailOp = frontStencilFailOp;\n        FrontFace.StencilDepthFailOp = frontStencilDepthFailOp;\n        FrontFace.StencilPassOp = frontStencilPassOp;\n        FrontFace.StencilFunc = frontStencilFunc;\n        BackFace.StencilFailOp = backStencilFailOp;\n        BackFace.StencilDepthFailOp = backStencilDepthFailOp;\n        BackFace.StencilPassOp = backStencilPassOp;\n        BackFace.StencilFunc = backStencilFunc;\n        DepthBoundsTestEnable = depthBoundsTestEnable;\n    }\n    operator D3D12_DEPTH_STENCIL_DESC() const noexcept\n    {\n        D3D12_DEPTH_STENCIL_DESC D;\n        D.DepthEnable                  = DepthEnable;\n        D.DepthWriteMask               = DepthWriteMask;\n        D.DepthFunc                    = DepthFunc;\n        D.StencilEnable                = StencilEnable;\n        D.StencilReadMask              = StencilReadMask;\n        D.StencilWriteMask             = StencilWriteMask;\n        D.FrontFace.StencilFailOp      = FrontFace.StencilFailOp;\n        D.FrontFace.StencilDepthFailOp = FrontFace.StencilDepthFailOp;\n        D.FrontFace.StencilPassOp      = FrontFace.StencilPassOp;\n        D.FrontFace.StencilFunc        = FrontFace.StencilFunc;\n        D.BackFace.StencilFailOp       = BackFace.StencilFailOp;\n        D.BackFace.StencilDepthFailOp  = BackFace.StencilDepthFailOp;\n        D.BackFace.StencilPassOp       = BackFace.StencilPassOp;\n        D.BackFace.StencilFunc         = BackFace.StencilFunc;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_RS2\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_BLEND_DESC : public D3D12_BLEND_DESC\n{\n    CD3DX12_BLEND_DESC() = default;\n    explicit CD3DX12_BLEND_DESC( const D3D12_BLEND_DESC& o ) noexcept :\n        D3D12_BLEND_DESC( o )\n    {}\n    explicit CD3DX12_BLEND_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        AlphaToCoverageEnable = FALSE;\n        IndependentBlendEnable = FALSE;\n        const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =\n        {\n            FALSE,FALSE,\n            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,\n            D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,\n            D3D12_LOGIC_OP_NOOP,\n            D3D12_COLOR_WRITE_ENABLE_ALL,\n        };\n        for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)\n            RenderTarget[ i ] = defaultRenderTargetBlendDesc;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RASTERIZER_DESC : public D3D12_RASTERIZER_DESC\n{\n    CD3DX12_RASTERIZER_DESC() = default;\n    explicit CD3DX12_RASTERIZER_DESC( const D3D12_RASTERIZER_DESC& o ) noexcept :\n        D3D12_RASTERIZER_DESC( o )\n    {}\n    explicit CD3DX12_RASTERIZER_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        FillMode = D3D12_FILL_MODE_SOLID;\n        CullMode = D3D12_CULL_MODE_BACK;\n        FrontCounterClockwise = FALSE;\n        DepthBias = D3D12_DEFAULT_DEPTH_BIAS;\n        DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;\n        SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;\n        DepthClipEnable = TRUE;\n        MultisampleEnable = FALSE;\n        AntialiasedLineEnable = FALSE;\n        ForcedSampleCount = 0;\n        ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;\n    }\n    explicit CD3DX12_RASTERIZER_DESC(\n        D3D12_FILL_MODE fillMode,\n        D3D12_CULL_MODE cullMode,\n        BOOL frontCounterClockwise,\n        INT depthBias,\n        FLOAT depthBiasClamp,\n        FLOAT slopeScaledDepthBias,\n        BOOL depthClipEnable,\n        BOOL multisampleEnable,\n        BOOL antialiasedLineEnable,\n        UINT forcedSampleCount,\n        D3D12_CONSERVATIVE_RASTERIZATION_MODE conservativeRaster) noexcept\n    {\n        FillMode = fillMode;\n        CullMode = cullMode;\n        FrontCounterClockwise = frontCounterClockwise;\n        DepthBias = depthBias;\n        DepthBiasClamp = depthBiasClamp;\n        SlopeScaledDepthBias = slopeScaledDepthBias;\n        DepthClipEnable = depthClipEnable;\n        MultisampleEnable = multisampleEnable;\n        AntialiasedLineEnable = antialiasedLineEnable;\n        ForcedSampleCount = forcedSampleCount;\n        ConservativeRaster = conservativeRaster;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RESOURCE_ALLOCATION_INFO : public D3D12_RESOURCE_ALLOCATION_INFO\n{\n    CD3DX12_RESOURCE_ALLOCATION_INFO() = default;\n    explicit CD3DX12_RESOURCE_ALLOCATION_INFO( const D3D12_RESOURCE_ALLOCATION_INFO& o ) noexcept :\n        D3D12_RESOURCE_ALLOCATION_INFO( o )\n    {}\n    CD3DX12_RESOURCE_ALLOCATION_INFO(\n        UINT64 size,\n        UINT64 alignment ) noexcept\n    {\n        SizeInBytes = size;\n        Alignment = alignment;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_HEAP_PROPERTIES : public D3D12_HEAP_PROPERTIES\n{\n    CD3DX12_HEAP_PROPERTIES() = default;\n    explicit CD3DX12_HEAP_PROPERTIES(const D3D12_HEAP_PROPERTIES &o) noexcept :\n        D3D12_HEAP_PROPERTIES(o)\n    {}\n    CD3DX12_HEAP_PROPERTIES(\n        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,\n        D3D12_MEMORY_POOL memoryPoolPreference,\n        UINT creationNodeMask = 1,\n        UINT nodeMask = 1 ) noexcept\n    {\n        Type = D3D12_HEAP_TYPE_CUSTOM;\n        CPUPageProperty = cpuPageProperty;\n        MemoryPoolPreference = memoryPoolPreference;\n        CreationNodeMask = creationNodeMask;\n        VisibleNodeMask = nodeMask;\n    }\n    explicit CD3DX12_HEAP_PROPERTIES(\n        D3D12_HEAP_TYPE type,\n        UINT creationNodeMask = 1,\n        UINT nodeMask = 1 ) noexcept\n    {\n        Type = type;\n        CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;\n        MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;\n        CreationNodeMask = creationNodeMask;\n        VisibleNodeMask = nodeMask;\n    }\n    bool IsCPUAccessible() const noexcept\n    {\n        return Type == D3D12_HEAP_TYPE_UPLOAD || Type == D3D12_HEAP_TYPE_READBACK || (Type == D3D12_HEAP_TYPE_CUSTOM &&\n            (CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE || CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_WRITE_BACK));\n    }\n};\ninline bool operator==( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept\n{\n    return l.Type == r.Type && l.CPUPageProperty == r.CPUPageProperty &&\n        l.MemoryPoolPreference == r.MemoryPoolPreference &&\n        l.CreationNodeMask == r.CreationNodeMask &&\n        l.VisibleNodeMask == r.VisibleNodeMask;\n}\ninline bool operator!=( const D3D12_HEAP_PROPERTIES& l, const D3D12_HEAP_PROPERTIES& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_HEAP_DESC : public D3D12_HEAP_DESC\n{\n    CD3DX12_HEAP_DESC() = default;\n    explicit CD3DX12_HEAP_DESC(const D3D12_HEAP_DESC &o) noexcept :\n        D3D12_HEAP_DESC(o)\n    {}\n    CD3DX12_HEAP_DESC(\n        UINT64 size,\n        D3D12_HEAP_PROPERTIES properties,\n        UINT64 alignment = 0,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = size;\n        Properties = properties;\n        Alignment = alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        UINT64 size,\n        D3D12_HEAP_TYPE type,\n        UINT64 alignment = 0,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = size;\n        Properties = CD3DX12_HEAP_PROPERTIES( type );\n        Alignment = alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        UINT64 size,\n        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,\n        D3D12_MEMORY_POOL memoryPoolPreference,\n        UINT64 alignment = 0,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = size;\n        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );\n        Alignment = alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_HEAP_PROPERTIES properties,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = resAllocInfo.SizeInBytes;\n        Properties = properties;\n        Alignment = resAllocInfo.Alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_HEAP_TYPE type,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = resAllocInfo.SizeInBytes;\n        Properties = CD3DX12_HEAP_PROPERTIES( type );\n        Alignment = resAllocInfo.Alignment;\n        Flags = flags;\n    }\n    CD3DX12_HEAP_DESC(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_CPU_PAGE_PROPERTY cpuPageProperty,\n        D3D12_MEMORY_POOL memoryPoolPreference,\n        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE ) noexcept\n    {\n        SizeInBytes = resAllocInfo.SizeInBytes;\n        Properties = CD3DX12_HEAP_PROPERTIES( cpuPageProperty, memoryPoolPreference );\n        Alignment = resAllocInfo.Alignment;\n        Flags = flags;\n    }\n    bool IsCPUAccessible() const noexcept\n    { return static_cast< const CD3DX12_HEAP_PROPERTIES* >( &Properties )->IsCPUAccessible(); }\n};\ninline bool operator==( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept\n{\n    return l.SizeInBytes == r.SizeInBytes &&\n        l.Properties == r.Properties &&\n        l.Alignment == r.Alignment &&\n        l.Flags == r.Flags;\n}\ninline bool operator!=( const D3D12_HEAP_DESC& l, const D3D12_HEAP_DESC& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_CLEAR_VALUE : public D3D12_CLEAR_VALUE\n{\n    CD3DX12_CLEAR_VALUE() = default;\n    explicit CD3DX12_CLEAR_VALUE(const D3D12_CLEAR_VALUE &o) noexcept :\n        D3D12_CLEAR_VALUE(o)\n    {}\n    CD3DX12_CLEAR_VALUE(\n        DXGI_FORMAT format,\n        const FLOAT color[4] ) noexcept\n    {\n        Format = format;\n        memcpy( Color, color, sizeof( Color ) );\n    }\n    CD3DX12_CLEAR_VALUE(\n        DXGI_FORMAT format,\n        FLOAT depth,\n        UINT8 stencil ) noexcept\n    {\n        Format = format;\n        memset( &Color, 0, sizeof( Color ) );\n        /* Use memcpy to preserve NAN values */\n        memcpy( &DepthStencil.Depth, &depth, sizeof( depth ) );\n        DepthStencil.Stencil = stencil;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RANGE : public D3D12_RANGE\n{\n    CD3DX12_RANGE() = default;\n    explicit CD3DX12_RANGE(const D3D12_RANGE &o) noexcept :\n        D3D12_RANGE(o)\n    {}\n    CD3DX12_RANGE(\n        SIZE_T begin,\n        SIZE_T end ) noexcept\n    {\n        Begin = begin;\n        End = end;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\n#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\nstruct CD3DX12_RANGE_UINT64 : public D3D12_RANGE_UINT64\n{\n    CD3DX12_RANGE_UINT64() = default;\n    explicit CD3DX12_RANGE_UINT64(const D3D12_RANGE_UINT64 &o) noexcept :\n        D3D12_RANGE_UINT64(o)\n    {}\n    CD3DX12_RANGE_UINT64(\n        UINT64 begin,\n        UINT64 end ) noexcept\n    {\n        Begin = begin;\n        End = end;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SUBRESOURCE_RANGE_UINT64 : public D3D12_SUBRESOURCE_RANGE_UINT64\n{\n    CD3DX12_SUBRESOURCE_RANGE_UINT64() = default;\n    explicit CD3DX12_SUBRESOURCE_RANGE_UINT64(const D3D12_SUBRESOURCE_RANGE_UINT64 &o) noexcept :\n        D3D12_SUBRESOURCE_RANGE_UINT64(o)\n    {}\n    CD3DX12_SUBRESOURCE_RANGE_UINT64(\n        UINT subresource,\n        const D3D12_RANGE_UINT64& range ) noexcept\n    {\n        Subresource = subresource;\n        Range = range;\n    }\n    CD3DX12_SUBRESOURCE_RANGE_UINT64(\n        UINT subresource,\n        UINT64 begin,\n        UINT64 end ) noexcept\n    {\n        Subresource = subresource;\n        Range.Begin = begin;\n        Range.End = end;\n    }\n};\n#endif // NTDDI_WIN10_RS2\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SHADER_BYTECODE : public D3D12_SHADER_BYTECODE\n{\n    CD3DX12_SHADER_BYTECODE() = default;\n    explicit CD3DX12_SHADER_BYTECODE(const D3D12_SHADER_BYTECODE &o) noexcept :\n        D3D12_SHADER_BYTECODE(o)\n    {}\n    CD3DX12_SHADER_BYTECODE(\n        _In_ ID3DBlob* pShaderBlob ) noexcept\n    {\n        pShaderBytecode = pShaderBlob->GetBufferPointer();\n        BytecodeLength = pShaderBlob->GetBufferSize();\n    }\n    CD3DX12_SHADER_BYTECODE(\n        const void* _pShaderBytecode,\n        SIZE_T bytecodeLength ) noexcept\n    {\n        pShaderBytecode = _pShaderBytecode;\n        BytecodeLength = bytecodeLength;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TILED_RESOURCE_COORDINATE : public D3D12_TILED_RESOURCE_COORDINATE\n{\n    CD3DX12_TILED_RESOURCE_COORDINATE() = default;\n    explicit CD3DX12_TILED_RESOURCE_COORDINATE(const D3D12_TILED_RESOURCE_COORDINATE &o) noexcept :\n        D3D12_TILED_RESOURCE_COORDINATE(o)\n    {}\n    CD3DX12_TILED_RESOURCE_COORDINATE(\n        UINT x,\n        UINT y,\n        UINT z,\n        UINT subresource ) noexcept\n    {\n        X = x;\n        Y = y;\n        Z = z;\n        Subresource = subresource;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TILE_REGION_SIZE : public D3D12_TILE_REGION_SIZE\n{\n    CD3DX12_TILE_REGION_SIZE() = default;\n    explicit CD3DX12_TILE_REGION_SIZE(const D3D12_TILE_REGION_SIZE &o) noexcept :\n        D3D12_TILE_REGION_SIZE(o)\n    {}\n    CD3DX12_TILE_REGION_SIZE(\n        UINT numTiles,\n        BOOL useBox,\n        UINT width,\n        UINT16 height,\n        UINT16 depth ) noexcept\n    {\n        NumTiles = numTiles;\n        UseBox = useBox;\n        Width = width;\n        Height = height;\n        Depth = depth;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SUBRESOURCE_TILING : public D3D12_SUBRESOURCE_TILING\n{\n    CD3DX12_SUBRESOURCE_TILING() = default;\n    explicit CD3DX12_SUBRESOURCE_TILING(const D3D12_SUBRESOURCE_TILING &o) noexcept :\n        D3D12_SUBRESOURCE_TILING(o)\n    {}\n    CD3DX12_SUBRESOURCE_TILING(\n        UINT widthInTiles,\n        UINT16 heightInTiles,\n        UINT16 depthInTiles,\n        UINT startTileIndexInOverallResource ) noexcept\n    {\n        WidthInTiles = widthInTiles;\n        HeightInTiles = heightInTiles;\n        DepthInTiles = depthInTiles;\n        StartTileIndexInOverallResource = startTileIndexInOverallResource;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TILE_SHAPE : public D3D12_TILE_SHAPE\n{\n    CD3DX12_TILE_SHAPE() = default;\n    explicit CD3DX12_TILE_SHAPE(const D3D12_TILE_SHAPE &o) noexcept :\n        D3D12_TILE_SHAPE(o)\n    {}\n    CD3DX12_TILE_SHAPE(\n        UINT widthInTexels,\n        UINT heightInTexels,\n        UINT depthInTexels ) noexcept\n    {\n        WidthInTexels = widthInTexels;\n        HeightInTexels = heightInTexels;\n        DepthInTexels = depthInTexels;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RESOURCE_BARRIER : public D3D12_RESOURCE_BARRIER\n{\n    CD3DX12_RESOURCE_BARRIER() = default;\n    explicit CD3DX12_RESOURCE_BARRIER(const D3D12_RESOURCE_BARRIER &o) noexcept :\n        D3D12_RESOURCE_BARRIER(o)\n    {}\n    static inline CD3DX12_RESOURCE_BARRIER Transition(\n        _In_ ID3D12Resource* pResource,\n        D3D12_RESOURCE_STATES stateBefore,\n        D3D12_RESOURCE_STATES stateAfter,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,\n        D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE) noexcept\n    {\n        CD3DX12_RESOURCE_BARRIER result = {};\n        D3D12_RESOURCE_BARRIER &barrier = result;\n        result.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        result.Flags = flags;\n        barrier.Transition.pResource = pResource;\n        barrier.Transition.StateBefore = stateBefore;\n        barrier.Transition.StateAfter = stateAfter;\n        barrier.Transition.Subresource = subresource;\n        return result;\n    }\n    static inline CD3DX12_RESOURCE_BARRIER Aliasing(\n        _In_ ID3D12Resource* pResourceBefore,\n        _In_ ID3D12Resource* pResourceAfter) noexcept\n    {\n        CD3DX12_RESOURCE_BARRIER result = {};\n        D3D12_RESOURCE_BARRIER &barrier = result;\n        result.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING;\n        barrier.Aliasing.pResourceBefore = pResourceBefore;\n        barrier.Aliasing.pResourceAfter = pResourceAfter;\n        return result;\n    }\n    static inline CD3DX12_RESOURCE_BARRIER UAV(\n        _In_ ID3D12Resource* pResource) noexcept\n    {\n        CD3DX12_RESOURCE_BARRIER result = {};\n        D3D12_RESOURCE_BARRIER &barrier = result;\n        result.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;\n        barrier.UAV.pResource = pResource;\n        return result;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_PACKED_MIP_INFO : public D3D12_PACKED_MIP_INFO\n{\n    CD3DX12_PACKED_MIP_INFO() = default;\n    explicit CD3DX12_PACKED_MIP_INFO(const D3D12_PACKED_MIP_INFO &o) noexcept :\n        D3D12_PACKED_MIP_INFO(o)\n    {}\n    CD3DX12_PACKED_MIP_INFO(\n        UINT8 numStandardMips,\n        UINT8 numPackedMips,\n        UINT numTilesForPackedMips,\n        UINT startTileIndexInOverallResource ) noexcept\n    {\n        NumStandardMips = numStandardMips;\n        NumPackedMips = numPackedMips;\n        NumTilesForPackedMips = numTilesForPackedMips;\n        StartTileIndexInOverallResource = startTileIndexInOverallResource;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_SUBRESOURCE_FOOTPRINT : public D3D12_SUBRESOURCE_FOOTPRINT\n{\n    CD3DX12_SUBRESOURCE_FOOTPRINT() = default;\n    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(const D3D12_SUBRESOURCE_FOOTPRINT &o) noexcept :\n        D3D12_SUBRESOURCE_FOOTPRINT(o)\n    {}\n    CD3DX12_SUBRESOURCE_FOOTPRINT(\n        DXGI_FORMAT format,\n        UINT width,\n        UINT height,\n        UINT depth,\n        UINT rowPitch ) noexcept\n    {\n        Format = format;\n        Width = width;\n        Height = height;\n        Depth = depth;\n        RowPitch = rowPitch;\n    }\n    explicit CD3DX12_SUBRESOURCE_FOOTPRINT(\n        const D3D12_RESOURCE_DESC& resDesc,\n        UINT rowPitch ) noexcept\n    {\n        Format = resDesc.Format;\n        Width = UINT( resDesc.Width );\n        Height = resDesc.Height;\n        Depth = (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? resDesc.DepthOrArraySize : 1);\n        RowPitch = rowPitch;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_TEXTURE_COPY_LOCATION : public D3D12_TEXTURE_COPY_LOCATION\n{\n    CD3DX12_TEXTURE_COPY_LOCATION() = default;\n    explicit CD3DX12_TEXTURE_COPY_LOCATION(const D3D12_TEXTURE_COPY_LOCATION &o) noexcept :\n        D3D12_TEXTURE_COPY_LOCATION(o)\n    {}\n    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes) noexcept\n    {\n        pResource = pRes;\n        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n        PlacedFootprint = {};\n    }\n    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, D3D12_PLACED_SUBRESOURCE_FOOTPRINT const& Footprint) noexcept\n    {\n        pResource = pRes;\n        Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n        PlacedFootprint = Footprint;\n    }\n    CD3DX12_TEXTURE_COPY_LOCATION(_In_ ID3D12Resource* pRes, UINT Sub) noexcept\n    {\n        pResource = pRes;\n        Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n        PlacedFootprint = {};\n        SubresourceIndex = Sub;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_DESCRIPTOR_RANGE : public D3D12_DESCRIPTOR_RANGE\n{\n    CD3DX12_DESCRIPTOR_RANGE() = default;\n    explicit CD3DX12_DESCRIPTOR_RANGE(const D3D12_DESCRIPTOR_RANGE &o) noexcept :\n        D3D12_DESCRIPTOR_RANGE(o)\n    {}\n    CD3DX12_DESCRIPTOR_RANGE(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);\n    }\n\n    inline void Init(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, offsetInDescriptorsFromTableStart);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_DESCRIPTOR_RANGE &range,\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        range.RangeType = rangeType;\n        range.NumDescriptors = numDescriptors;\n        range.BaseShaderRegister = baseShaderRegister;\n        range.RegisterSpace = registerSpace;\n        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR_TABLE : public D3D12_ROOT_DESCRIPTOR_TABLE\n{\n    CD3DX12_ROOT_DESCRIPTOR_TABLE() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE(const D3D12_ROOT_DESCRIPTOR_TABLE &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR_TABLE(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR_TABLE(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept\n    {\n        Init(numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    inline void Init(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept\n    {\n        Init(*this, numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE &rootDescriptorTable,\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* _pDescriptorRanges) noexcept\n    {\n        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;\n        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_CONSTANTS : public D3D12_ROOT_CONSTANTS\n{\n    CD3DX12_ROOT_CONSTANTS() = default;\n    explicit CD3DX12_ROOT_CONSTANTS(const D3D12_ROOT_CONSTANTS &o) noexcept :\n        D3D12_ROOT_CONSTANTS(o)\n    {}\n    CD3DX12_ROOT_CONSTANTS(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(num32BitValues, shaderRegister, registerSpace);\n    }\n\n    inline void Init(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(*this, num32BitValues, shaderRegister, registerSpace);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_CONSTANTS &rootConstants,\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        rootConstants.Num32BitValues = num32BitValues;\n        rootConstants.ShaderRegister = shaderRegister;\n        rootConstants.RegisterSpace = registerSpace;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR : public D3D12_ROOT_DESCRIPTOR\n{\n    CD3DX12_ROOT_DESCRIPTOR() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR(const D3D12_ROOT_DESCRIPTOR &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR(\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(shaderRegister, registerSpace);\n    }\n\n    inline void Init(\n        UINT shaderRegister,\n        UINT registerSpace = 0) noexcept\n    {\n        Init(*this, shaderRegister, registerSpace);\n    }\n\n    static inline void Init(_Out_ D3D12_ROOT_DESCRIPTOR &table, UINT shaderRegister, UINT registerSpace = 0) noexcept\n    {\n        table.ShaderRegister = shaderRegister;\n        table.RegisterSpace = registerSpace;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_PARAMETER : public D3D12_ROOT_PARAMETER\n{\n    CD3DX12_ROOT_PARAMETER() = default;\n    explicit CD3DX12_ROOT_PARAMETER(const D3D12_ROOT_PARAMETER &o) noexcept :\n        D3D12_ROOT_PARAMETER(o)\n    {}\n\n    static inline void InitAsDescriptorTable(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR_TABLE::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);\n    }\n\n    static inline void InitAsConstants(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsConstantBufferView(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsShaderResourceView(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsUnorderedAccessView(\n        _Out_ D3D12_ROOT_PARAMETER &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR::Init(rootParam.Descriptor, shaderRegister, registerSpace);\n    }\n\n    inline void InitAsDescriptorTable(\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);\n    }\n\n    inline void InitAsConstants(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsConstantBufferView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstantBufferView(*this, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsShaderResourceView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsShaderResourceView(*this, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsUnorderedAccessView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, visibility);\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_STATIC_SAMPLER_DESC : public D3D12_STATIC_SAMPLER_DESC\n{\n    CD3DX12_STATIC_SAMPLER_DESC() = default;\n    explicit CD3DX12_STATIC_SAMPLER_DESC(const D3D12_STATIC_SAMPLER_DESC &o) noexcept :\n        D3D12_STATIC_SAMPLER_DESC(o)\n    {}\n    CD3DX12_STATIC_SAMPLER_DESC(\n         UINT shaderRegister,\n         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,\n         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         FLOAT mipLODBias = 0,\n         UINT maxAnisotropy = 16,\n         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,\n         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n         FLOAT minLOD = 0.f,\n         FLOAT maxLOD = D3D12_FLOAT32_MAX,\n         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,\n         UINT registerSpace = 0) noexcept\n    {\n        Init(\n            shaderRegister,\n            filter,\n            addressU,\n            addressV,\n            addressW,\n            mipLODBias,\n            maxAnisotropy,\n            comparisonFunc,\n            borderColor,\n            minLOD,\n            maxLOD,\n            shaderVisibility,\n            registerSpace);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_STATIC_SAMPLER_DESC &samplerDesc,\n         UINT shaderRegister,\n         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,\n         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         FLOAT mipLODBias = 0,\n         UINT maxAnisotropy = 16,\n         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,\n         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n         FLOAT minLOD = 0.f,\n         FLOAT maxLOD = D3D12_FLOAT32_MAX,\n         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,\n         UINT registerSpace = 0) noexcept\n    {\n        samplerDesc.ShaderRegister = shaderRegister;\n        samplerDesc.Filter = filter;\n        samplerDesc.AddressU = addressU;\n        samplerDesc.AddressV = addressV;\n        samplerDesc.AddressW = addressW;\n        samplerDesc.MipLODBias = mipLODBias;\n        samplerDesc.MaxAnisotropy = maxAnisotropy;\n        samplerDesc.ComparisonFunc = comparisonFunc;\n        samplerDesc.BorderColor = borderColor;\n        samplerDesc.MinLOD = minLOD;\n        samplerDesc.MaxLOD = maxLOD;\n        samplerDesc.ShaderVisibility = shaderVisibility;\n        samplerDesc.RegisterSpace = registerSpace;\n    }\n    inline void Init(\n         UINT shaderRegister,\n         D3D12_FILTER filter = D3D12_FILTER_ANISOTROPIC,\n         D3D12_TEXTURE_ADDRESS_MODE addressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         D3D12_TEXTURE_ADDRESS_MODE addressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP,\n         FLOAT mipLODBias = 0,\n         UINT maxAnisotropy = 16,\n         D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL,\n         D3D12_STATIC_BORDER_COLOR borderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE,\n         FLOAT minLOD = 0.f,\n         FLOAT maxLOD = D3D12_FLOAT32_MAX,\n         D3D12_SHADER_VISIBILITY shaderVisibility = D3D12_SHADER_VISIBILITY_ALL,\n         UINT registerSpace = 0) noexcept\n    {\n        Init(\n            *this,\n            shaderRegister,\n            filter,\n            addressU,\n            addressV,\n            addressW,\n            mipLODBias,\n            maxAnisotropy,\n            comparisonFunc,\n            borderColor,\n            minLOD,\n            maxLOD,\n            shaderVisibility,\n            registerSpace);\n    }\n\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_SIGNATURE_DESC : public D3D12_ROOT_SIGNATURE_DESC\n{\n    CD3DX12_ROOT_SIGNATURE_DESC() = default;\n    explicit CD3DX12_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept :\n        D3D12_ROOT_SIGNATURE_DESC(o)\n    {}\n    CD3DX12_ROOT_SIGNATURE_DESC(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n    CD3DX12_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept\n    {\n        Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);\n    }\n\n    inline void Init(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_SIGNATURE_DESC &desc,\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        desc.NumParameters = numParameters;\n        desc.pParameters = _pParameters;\n        desc.NumStaticSamplers = numStaticSamplers;\n        desc.pStaticSamplers = _pStaticSamplers;\n        desc.Flags = flags;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_DESCRIPTOR_RANGE1 : public D3D12_DESCRIPTOR_RANGE1\n{\n    CD3DX12_DESCRIPTOR_RANGE1() = default;\n    explicit CD3DX12_DESCRIPTOR_RANGE1(const D3D12_DESCRIPTOR_RANGE1 &o) noexcept :\n        D3D12_DESCRIPTOR_RANGE1(o)\n    {}\n    CD3DX12_DESCRIPTOR_RANGE1(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);\n    }\n\n    inline void Init(\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        Init(*this, rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_DESCRIPTOR_RANGE1 &range,\n        D3D12_DESCRIPTOR_RANGE_TYPE rangeType,\n        UINT numDescriptors,\n        UINT baseShaderRegister,\n        UINT registerSpace = 0,\n        D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,\n        UINT offsetInDescriptorsFromTableStart =\n        D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) noexcept\n    {\n        range.RangeType = rangeType;\n        range.NumDescriptors = numDescriptors;\n        range.BaseShaderRegister = baseShaderRegister;\n        range.RegisterSpace = registerSpace;\n        range.Flags = flags;\n        range.OffsetInDescriptorsFromTableStart = offsetInDescriptorsFromTableStart;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR_TABLE1 : public D3D12_ROOT_DESCRIPTOR_TABLE1\n{\n    CD3DX12_ROOT_DESCRIPTOR_TABLE1() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR_TABLE1(const D3D12_ROOT_DESCRIPTOR_TABLE1 &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR_TABLE1(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR_TABLE1(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept\n    {\n        Init(numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    inline void Init(\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept\n    {\n        Init(*this, numDescriptorRanges, _pDescriptorRanges);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_DESCRIPTOR_TABLE1 &rootDescriptorTable,\n        UINT numDescriptorRanges,\n        _In_reads_opt_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* _pDescriptorRanges) noexcept\n    {\n        rootDescriptorTable.NumDescriptorRanges = numDescriptorRanges;\n        rootDescriptorTable.pDescriptorRanges = _pDescriptorRanges;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_DESCRIPTOR1 : public D3D12_ROOT_DESCRIPTOR1\n{\n    CD3DX12_ROOT_DESCRIPTOR1() = default;\n    explicit CD3DX12_ROOT_DESCRIPTOR1(const D3D12_ROOT_DESCRIPTOR1 &o) noexcept :\n        D3D12_ROOT_DESCRIPTOR1(o)\n    {}\n    CD3DX12_ROOT_DESCRIPTOR1(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept\n    {\n        Init(shaderRegister, registerSpace, flags);\n    }\n\n    inline void Init(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept\n    {\n        Init(*this, shaderRegister, registerSpace, flags);\n    }\n\n    static inline void Init(\n        _Out_ D3D12_ROOT_DESCRIPTOR1 &table,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE) noexcept\n    {\n        table.ShaderRegister = shaderRegister;\n        table.RegisterSpace = registerSpace;\n        table.Flags = flags;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_ROOT_PARAMETER1 : public D3D12_ROOT_PARAMETER1\n{\n    CD3DX12_ROOT_PARAMETER1() = default;\n    explicit CD3DX12_ROOT_PARAMETER1(const D3D12_ROOT_PARAMETER1 &o) noexcept :\n        D3D12_ROOT_PARAMETER1(o)\n    {}\n\n    static inline void InitAsDescriptorTable(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR_TABLE1::Init(rootParam.DescriptorTable, numDescriptorRanges, pDescriptorRanges);\n    }\n\n    static inline void InitAsConstants(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_CONSTANTS::Init(rootParam.Constants, num32BitValues, shaderRegister, registerSpace);\n    }\n\n    static inline void InitAsConstantBufferView(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);\n    }\n\n    static inline void InitAsShaderResourceView(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);\n    }\n\n    static inline void InitAsUnorderedAccessView(\n        _Out_ D3D12_ROOT_PARAMETER1 &rootParam,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;\n        rootParam.ShaderVisibility = visibility;\n        CD3DX12_ROOT_DESCRIPTOR1::Init(rootParam.Descriptor, shaderRegister, registerSpace, flags);\n    }\n\n    inline void InitAsDescriptorTable(\n        UINT numDescriptorRanges,\n        _In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);\n    }\n\n    inline void InitAsConstants(\n        UINT num32BitValues,\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstants(*this, num32BitValues, shaderRegister, registerSpace, visibility);\n    }\n\n    inline void InitAsConstantBufferView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsConstantBufferView(*this, shaderRegister, registerSpace, flags, visibility);\n    }\n\n    inline void InitAsShaderResourceView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsShaderResourceView(*this, shaderRegister, registerSpace, flags, visibility);\n    }\n\n    inline void InitAsUnorderedAccessView(\n        UINT shaderRegister,\n        UINT registerSpace = 0,\n        D3D12_ROOT_DESCRIPTOR_FLAGS flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE,\n        D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL) noexcept\n    {\n        InitAsUnorderedAccessView(*this, shaderRegister, registerSpace, flags, visibility);\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC : public D3D12_VERSIONED_ROOT_SIGNATURE_DESC\n{\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC() = default;\n    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC &o) noexcept :\n        D3D12_VERSIONED_ROOT_SIGNATURE_DESC(o)\n    {}\n    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC &o) noexcept\n    {\n        Version = D3D_ROOT_SIGNATURE_VERSION_1_0;\n        Desc_1_0 = o;\n    }\n    explicit CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(const D3D12_ROOT_SIGNATURE_DESC1 &o) noexcept\n    {\n        Version = D3D_ROOT_SIGNATURE_VERSION_1_1;\n        Desc_1_1 = o;\n    }\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_0(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_1(numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n    CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC(CD3DX12_DEFAULT) noexcept\n    {\n        Init_1_1(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);\n    }\n\n    inline void Init_1_0(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_0(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n\n    static inline void Init_1_0(\n        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_0;\n        desc.Desc_1_0.NumParameters = numParameters;\n        desc.Desc_1_0.pParameters = _pParameters;\n        desc.Desc_1_0.NumStaticSamplers = numStaticSamplers;\n        desc.Desc_1_0.pStaticSamplers = _pStaticSamplers;\n        desc.Desc_1_0.Flags = flags;\n    }\n\n    inline void Init_1_1(\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        Init_1_1(*this, numParameters, _pParameters, numStaticSamplers, _pStaticSamplers, flags);\n    }\n\n    static inline void Init_1_1(\n        _Out_ D3D12_VERSIONED_ROOT_SIGNATURE_DESC &desc,\n        UINT numParameters,\n        _In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters,\n        UINT numStaticSamplers = 0,\n        _In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,\n        D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) noexcept\n    {\n        desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;\n        desc.Desc_1_1.NumParameters = numParameters;\n        desc.Desc_1_1.pParameters = _pParameters;\n        desc.Desc_1_1.NumStaticSamplers = numStaticSamplers;\n        desc.Desc_1_1.pStaticSamplers = _pStaticSamplers;\n        desc.Desc_1_1.Flags = flags;\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_CPU_DESCRIPTOR_HANDLE : public D3D12_CPU_DESCRIPTOR_HANDLE\n{\n    CD3DX12_CPU_DESCRIPTOR_HANDLE() = default;\n    explicit CD3DX12_CPU_DESCRIPTOR_HANDLE(const D3D12_CPU_DESCRIPTOR_HANDLE &o) noexcept :\n        D3D12_CPU_DESCRIPTOR_HANDLE(o)\n    {}\n    CD3DX12_CPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetScaledByIncrementSize);\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        ptr = SIZE_T(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n        return *this;\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept\n    {\n        ptr = SIZE_T(INT64(ptr) + INT64(offsetScaledByIncrementSize));\n        return *this;\n    }\n    bool operator==(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr == other.ptr);\n    }\n    bool operator!=(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr != other.ptr);\n    }\n    CD3DX12_CPU_DESCRIPTOR_HANDLE &operator=(const D3D12_CPU_DESCRIPTOR_HANDLE &other) noexcept\n    {\n        ptr = other.ptr;\n        return *this;\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetScaledByIncrementSize);\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_CPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_CPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        handle.ptr = SIZE_T(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n    }\n};\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_GPU_DESCRIPTOR_HANDLE : public D3D12_GPU_DESCRIPTOR_HANDLE\n{\n    CD3DX12_GPU_DESCRIPTOR_HANDLE() = default;\n    explicit CD3DX12_GPU_DESCRIPTOR_HANDLE(const D3D12_GPU_DESCRIPTOR_HANDLE &o) noexcept :\n        D3D12_GPU_DESCRIPTOR_HANDLE(o)\n    {}\n    CD3DX12_GPU_DESCRIPTOR_HANDLE(CD3DX12_DEFAULT) noexcept { ptr = 0; }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetScaledByIncrementSize);\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &other, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(other, offsetInDescriptors, descriptorIncrementSize);\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        ptr = UINT64(INT64(ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n        return *this;\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE& Offset(INT offsetScaledByIncrementSize) noexcept\n    {\n        ptr = UINT64(INT64(ptr) + INT64(offsetScaledByIncrementSize));\n        return *this;\n    }\n    inline bool operator==(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr == other.ptr);\n    }\n    inline bool operator!=(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE& other) const noexcept\n    {\n        return (ptr != other.ptr);\n    }\n    CD3DX12_GPU_DESCRIPTOR_HANDLE &operator=(const D3D12_GPU_DESCRIPTOR_HANDLE &other) noexcept\n    {\n        ptr = other.ptr;\n        return *this;\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetScaledByIncrementSize);\n    }\n\n    inline void InitOffsetted(_In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        InitOffsetted(*this, base, offsetInDescriptors, descriptorIncrementSize);\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetScaledByIncrementSize) noexcept\n    {\n        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetScaledByIncrementSize));\n    }\n\n    static inline void InitOffsetted(_Out_ D3D12_GPU_DESCRIPTOR_HANDLE &handle, _In_ const D3D12_GPU_DESCRIPTOR_HANDLE &base, INT offsetInDescriptors, UINT descriptorIncrementSize) noexcept\n    {\n        handle.ptr = UINT64(INT64(base.ptr) + INT64(offsetInDescriptors) * INT64(descriptorIncrementSize));\n    }\n};\n\n//------------------------------------------------------------------------------------------------\ninline constexpr UINT D3D12CalcSubresource( UINT MipSlice, UINT ArraySlice, UINT PlaneSlice, UINT MipLevels, UINT ArraySize ) noexcept\n{\n    return MipSlice + ArraySlice * MipLevels + PlaneSlice * MipLevels * ArraySize;\n}\n\n//------------------------------------------------------------------------------------------------\ntemplate <typename T, typename U, typename V>\ninline void D3D12DecomposeSubresource( UINT Subresource, UINT MipLevels, UINT ArraySize, _Out_ T& MipSlice, _Out_ U& ArraySlice, _Out_ V& PlaneSlice ) noexcept\n{\n    MipSlice = static_cast<T>(Subresource % MipLevels);\n    ArraySlice = static_cast<U>((Subresource / MipLevels) % ArraySize);\n    PlaneSlice = static_cast<V>(Subresource / (MipLevels * ArraySize));\n}\n\n//------------------------------------------------------------------------------------------------\ninline UINT8 D3D12GetFormatPlaneCount(\n    _In_ ID3D12Device* pDevice,\n    DXGI_FORMAT Format\n    ) noexcept\n{\n    D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = { Format, 0 };\n    if (FAILED(pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo))))\n    {\n        return 0;\n    }\n    return formatInfo.PlaneCount;\n}\n\n//------------------------------------------------------------------------------------------------\nstruct CD3DX12_RESOURCE_DESC : public D3D12_RESOURCE_DESC\n{\n    CD3DX12_RESOURCE_DESC() = default;\n    explicit CD3DX12_RESOURCE_DESC( const D3D12_RESOURCE_DESC& o ) noexcept :\n        D3D12_RESOURCE_DESC( o )\n    {}\n    CD3DX12_RESOURCE_DESC(\n        D3D12_RESOURCE_DIMENSION dimension,\n        UINT64 alignment,\n        UINT64 width,\n        UINT height,\n        UINT16 depthOrArraySize,\n        UINT16 mipLevels,\n        DXGI_FORMAT format,\n        UINT sampleCount,\n        UINT sampleQuality,\n        D3D12_TEXTURE_LAYOUT layout,\n        D3D12_RESOURCE_FLAGS flags ) noexcept\n    {\n        Dimension = dimension;\n        Alignment = alignment;\n        Width = width;\n        Height = height;\n        DepthOrArraySize = depthOrArraySize;\n        MipLevels = mipLevels;\n        Format = format;\n        SampleDesc.Count = sampleCount;\n        SampleDesc.Quality = sampleQuality;\n        Layout = layout;\n        Flags = flags;\n    }\n    static inline CD3DX12_RESOURCE_DESC Buffer(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,\n            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Buffer(\n        UINT64 width,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,\n            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Tex1D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,\n            mipLevels, format, 1, 0, layout, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Tex2D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        UINT sampleCount = 1,\n        UINT sampleQuality = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,\n            mipLevels, format, sampleCount, sampleQuality, layout, flags );\n    }\n    static inline CD3DX12_RESOURCE_DESC Tex3D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 depth,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,\n            mipLevels, format, 1, 0, layout, flags );\n    }\n    inline UINT16 Depth() const noexcept\n    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT16 ArraySize() const noexcept\n    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept\n    { return D3D12GetFormatPlaneCount(pDevice, Format); }\n    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept\n    { return MipLevels * ArraySize() * PlaneCount(pDevice); }\n    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept\n    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }\n};\ninline bool operator==( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept\n{\n    return l.Dimension == r.Dimension &&\n        l.Alignment == r.Alignment &&\n        l.Width == r.Width &&\n        l.Height == r.Height &&\n        l.DepthOrArraySize == r.DepthOrArraySize &&\n        l.MipLevels == r.MipLevels &&\n        l.Format == r.Format &&\n        l.SampleDesc.Count == r.SampleDesc.Count &&\n        l.SampleDesc.Quality == r.SampleDesc.Quality &&\n        l.Layout == r.Layout &&\n        l.Flags == r.Flags;\n}\ninline bool operator!=( const D3D12_RESOURCE_DESC& l, const D3D12_RESOURCE_DESC& r ) noexcept\n{ return !( l == r ); }\n\n//------------------------------------------------------------------------------------------------\n// Requires the Windows 10 SDK (19041)\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct CD3DX12_RESOURCE_DESC1 : public D3D12_RESOURCE_DESC1\n{\n    CD3DX12_RESOURCE_DESC1() = default;\n    explicit CD3DX12_RESOURCE_DESC1( const D3D12_RESOURCE_DESC1& o ) noexcept :\n        D3D12_RESOURCE_DESC1( o )\n    {}\n    CD3DX12_RESOURCE_DESC1(\n        D3D12_RESOURCE_DIMENSION dimension,\n        UINT64 alignment,\n        UINT64 width,\n        UINT height,\n        UINT16 depthOrArraySize,\n        UINT16 mipLevels,\n        DXGI_FORMAT format,\n        UINT sampleCount,\n        UINT sampleQuality,\n        D3D12_TEXTURE_LAYOUT layout,\n        D3D12_RESOURCE_FLAGS flags,\n        UINT samplerFeedbackMipRegionWidth = 0,\n        UINT samplerFeedbackMipRegionHeight = 0,\n        UINT samplerFeedbackMipRegionDepth = 0) noexcept\n    {\n        Dimension = dimension;\n        Alignment = alignment;\n        Width = width;\n        Height = height;\n        DepthOrArraySize = depthOrArraySize;\n        MipLevels = mipLevels;\n        Format = format;\n        SampleDesc.Count = sampleCount;\n        SampleDesc.Quality = sampleQuality;\n        Layout = layout;\n        Flags = flags;\n        SamplerFeedbackMipRegion.Width = samplerFeedbackMipRegionWidth;\n        SamplerFeedbackMipRegion.Height = samplerFeedbackMipRegionHeight;\n        SamplerFeedbackMipRegion.Depth = samplerFeedbackMipRegionDepth;\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Buffer(\n        const D3D12_RESOURCE_ALLOCATION_INFO& resAllocInfo,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, resAllocInfo.Alignment, resAllocInfo.SizeInBytes,\n            1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Buffer(\n        UINT64 width,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_BUFFER, alignment, width, 1, 1, 1,\n            DXGI_FORMAT_UNKNOWN, 1, 0, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags, 0, 0, 0 );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Tex1D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE1D, alignment, width, 1, arraySize,\n            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Tex2D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 arraySize = 1,\n        UINT16 mipLevels = 0,\n        UINT sampleCount = 1,\n        UINT sampleQuality = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0,\n        UINT samplerFeedbackMipRegionWidth = 0,\n        UINT samplerFeedbackMipRegionHeight = 0,\n        UINT samplerFeedbackMipRegionDepth = 0) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment, width, height, arraySize,\n            mipLevels, format, sampleCount, sampleQuality, layout, flags, samplerFeedbackMipRegionWidth,\n            samplerFeedbackMipRegionHeight, samplerFeedbackMipRegionDepth );\n    }\n    static inline CD3DX12_RESOURCE_DESC1 Tex3D(\n        DXGI_FORMAT format,\n        UINT64 width,\n        UINT height,\n        UINT16 depth,\n        UINT16 mipLevels = 0,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0 ) noexcept\n    {\n        return CD3DX12_RESOURCE_DESC1( D3D12_RESOURCE_DIMENSION_TEXTURE3D, alignment, width, height, depth,\n            mipLevels, format, 1, 0, layout, flags, 0, 0, 0 );\n    }\n    inline UINT16 Depth() const noexcept\n    { return (Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT16 ArraySize() const noexcept\n    { return (Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? DepthOrArraySize : 1); }\n    inline UINT8 PlaneCount(_In_ ID3D12Device* pDevice) const noexcept\n    { return D3D12GetFormatPlaneCount(pDevice, Format); }\n    inline UINT Subresources(_In_ ID3D12Device* pDevice) const noexcept\n    { return MipLevels * ArraySize() * PlaneCount(pDevice); }\n    inline UINT CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice) noexcept\n    { return D3D12CalcSubresource(MipSlice, ArraySlice, PlaneSlice, MipLevels, ArraySize()); }\n};\ninline bool operator==( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept\n{\n    return l.Dimension == r.Dimension &&\n        l.Alignment == r.Alignment &&\n        l.Width == r.Width &&\n        l.Height == r.Height &&\n        l.DepthOrArraySize == r.DepthOrArraySize &&\n        l.MipLevels == r.MipLevels &&\n        l.Format == r.Format &&\n        l.SampleDesc.Count == r.SampleDesc.Count &&\n        l.SampleDesc.Quality == r.SampleDesc.Quality &&\n        l.Layout == r.Layout &&\n        l.Flags == r.Flags &&\n        l.SamplerFeedbackMipRegion.Width == r.SamplerFeedbackMipRegion.Width &&\n        l.SamplerFeedbackMipRegion.Height == r.SamplerFeedbackMipRegion.Height &&\n        l.SamplerFeedbackMipRegion.Depth == r.SamplerFeedbackMipRegion.Depth;\n}\ninline bool operator!=( const D3D12_RESOURCE_DESC1& l, const D3D12_RESOURCE_DESC1& r ) noexcept\n{ return !( l == r ); }\n#endif // NTDDI_WIN10_VB\n\n//------------------------------------------------------------------------------------------------\n// Requires the Windows 10 Fall Creators Update SDK (16299)\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\nstruct CD3DX12_VIEW_INSTANCING_DESC : public D3D12_VIEW_INSTANCING_DESC\n{\n    CD3DX12_VIEW_INSTANCING_DESC() = default;\n    explicit CD3DX12_VIEW_INSTANCING_DESC( const D3D12_VIEW_INSTANCING_DESC& o ) noexcept :\n        D3D12_VIEW_INSTANCING_DESC( o )\n    {}\n    explicit CD3DX12_VIEW_INSTANCING_DESC( CD3DX12_DEFAULT ) noexcept\n    {\n        ViewInstanceCount = 0;\n        pViewInstanceLocations = nullptr;\n        Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;\n    }\n    explicit CD3DX12_VIEW_INSTANCING_DESC(\n        UINT InViewInstanceCount,\n        const D3D12_VIEW_INSTANCE_LOCATION* InViewInstanceLocations,\n        D3D12_VIEW_INSTANCING_FLAGS InFlags) noexcept\n    {\n        ViewInstanceCount = InViewInstanceCount;\n        pViewInstanceLocations = InViewInstanceLocations;\n        Flags = InFlags;\n    }\n};\n#endif // NTDDI_WIN10_RS3\n\n//------------------------------------------------------------------------------------------------\n// Row-by-row memcpy\ninline void MemcpySubresource(\n    _In_ const D3D12_MEMCPY_DEST* pDest,\n    _In_ const D3D12_SUBRESOURCE_DATA* pSrc,\n    SIZE_T RowSizeInBytes,\n    UINT NumRows,\n    UINT NumSlices) noexcept\n{\n    for (UINT z = 0; z < NumSlices; ++z)\n    {\n        auto pDestSlice = static_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;\n        auto pSrcSlice = static_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * LONG_PTR(z);\n        for (UINT y = 0; y < NumRows; ++y)\n        {\n            memcpy(pDestSlice + pDest->RowPitch * y,\n                   pSrcSlice + pSrc->RowPitch * LONG_PTR(y),\n                   RowSizeInBytes);\n        }\n    }\n}\n\n//------------------------------------------------------------------------------------------------\n// Returns required size of a buffer to be used for data upload\ninline UINT64 GetRequiredIntermediateSize(\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources) noexcept\n{\n    auto Desc = pDestinationResource->GetDesc();\n    UINT64 RequiredSize = 0;\n\n    ID3D12Device* pDevice = nullptr;\n    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));\n    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, 0, nullptr, nullptr, nullptr, &RequiredSize);\n    pDevice->Release();\n\n    return RequiredSize;\n}\n\n//------------------------------------------------------------------------------------------------\n// All arrays must be populated (e.g. by calling GetCopyableFootprints)\ninline UINT64 UpdateSubresources(\n    _In_ ID3D12GraphicsCommandList* pCmdList,\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_ ID3D12Resource* pIntermediate,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,\n    UINT64 RequiredSize,\n    _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,\n    _In_reads_(NumSubresources) const UINT* pNumRows,\n    _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,\n    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept\n{\n    // Minor validation\n    auto IntermediateDesc = pIntermediate->GetDesc();\n    auto DestinationDesc = pDestinationResource->GetDesc();\n    if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||\n        IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||\n        RequiredSize > SIZE_T(-1) ||\n        (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&\n            (FirstSubresource != 0 || NumSubresources != 1)))\n    {\n        return 0;\n    }\n\n    BYTE* pData;\n    HRESULT hr = pIntermediate->Map(0, nullptr, reinterpret_cast<void**>(&pData));\n    if (FAILED(hr))\n    {\n        return 0;\n    }\n\n    for (UINT i = 0; i < NumSubresources; ++i)\n    {\n        if (pRowSizesInBytes[i] > SIZE_T(-1)) return 0;\n        D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, SIZE_T(pLayouts[i].Footprint.RowPitch) * SIZE_T(pNumRows[i]) };\n        MemcpySubresource(&DestData, &pSrcData[i], static_cast<SIZE_T>(pRowSizesInBytes[i]), pNumRows[i], pLayouts[i].Footprint.Depth);\n    }\n    pIntermediate->Unmap(0, nullptr);\n\n    if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)\n    {\n        pCmdList->CopyBufferRegion(\n            pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);\n    }\n    else\n    {\n        for (UINT i = 0; i < NumSubresources; ++i)\n        {\n            CD3DX12_TEXTURE_COPY_LOCATION Dst(pDestinationResource, i + FirstSubresource);\n            CD3DX12_TEXTURE_COPY_LOCATION Src(pIntermediate, pLayouts[i]);\n            pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);\n        }\n    }\n    return RequiredSize;\n}\n\n//------------------------------------------------------------------------------------------------\n// Heap-allocating UpdateSubresources implementation\ninline UINT64 UpdateSubresources(\n    _In_ ID3D12GraphicsCommandList* pCmdList,\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_ ID3D12Resource* pIntermediate,\n    UINT64 IntermediateOffset,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,\n    _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,\n    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept\n{\n    UINT64 RequiredSize = 0;\n    UINT64 MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;\n    if (MemToAlloc > SIZE_MAX)\n    {\n       return 0;\n    }\n    void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));\n    if (pMem == nullptr)\n    {\n       return 0;\n    }\n    auto pLayouts = static_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);\n    UINT64* pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);\n    UINT* pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);\n\n    auto Desc = pDestinationResource->GetDesc();\n    ID3D12Device* pDevice = nullptr;\n    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));\n    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);\n    pDevice->Release();\n\n    UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pSrcData);\n    HeapFree(GetProcessHeap(), 0, pMem);\n    return Result;\n}\n\n//------------------------------------------------------------------------------------------------\n// Stack-allocating UpdateSubresources implementation\ntemplate <UINT MaxSubresources>\ninline UINT64 UpdateSubresources(\n    _In_ ID3D12GraphicsCommandList* pCmdList,\n    _In_ ID3D12Resource* pDestinationResource,\n    _In_ ID3D12Resource* pIntermediate,\n    UINT64 IntermediateOffset,\n    _In_range_(0, MaxSubresources) UINT FirstSubresource,\n    _In_range_(1, MaxSubresources - FirstSubresource) UINT NumSubresources,\n    _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData) noexcept\n{\n    UINT64 RequiredSize = 0;\n    D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];\n    UINT NumRows[MaxSubresources];\n    UINT64 RowSizesInBytes[MaxSubresources];\n\n    auto Desc = pDestinationResource->GetDesc();\n    ID3D12Device* pDevice = nullptr;\n    pDestinationResource->GetDevice(IID_ID3D12Device, reinterpret_cast<void**>(&pDevice));\n    pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);\n    pDevice->Release();\n\n    return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows, RowSizesInBytes, pSrcData);\n}\n\n//------------------------------------------------------------------------------------------------\ninline constexpr bool D3D12IsLayoutOpaque( D3D12_TEXTURE_LAYOUT Layout ) noexcept\n{ return Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN || Layout == D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; }\n\n//------------------------------------------------------------------------------------------------\ntemplate <typename t_CommandListType>\ninline ID3D12CommandList * const * CommandListCast(t_CommandListType * const * pp) noexcept\n{\n    // This cast is useful for passing strongly typed command list pointers into\n    // ExecuteCommandLists.\n    // This cast is valid as long as the const-ness is respected. D3D12 APIs do\n    // respect the const-ness of their arguments.\n    return reinterpret_cast<ID3D12CommandList * const *>(pp);\n}\n\n//------------------------------------------------------------------------------------------------\n// D3D12 exports a new method for serializing root signatures in the Windows 10 Anniversary Update.\n// To help enable root signature 1.1 features when they are available and not require maintaining\n// two code paths for building root signatures, this helper method reconstructs a 1.0 signature when\n// 1.1 is not supported.\ninline HRESULT D3DX12SerializeVersionedRootSignature(\n    _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignatureDesc,\n    D3D_ROOT_SIGNATURE_VERSION MaxVersion,\n    _Outptr_ ID3DBlob** ppBlob,\n    _Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorBlob) noexcept\n{\n    if (ppErrorBlob != nullptr)\n    {\n        *ppErrorBlob = nullptr;\n    }\n\n    switch (MaxVersion)\n    {\n        case D3D_ROOT_SIGNATURE_VERSION_1_0:\n            switch (pRootSignatureDesc->Version)\n            {\n                case D3D_ROOT_SIGNATURE_VERSION_1_0:\n                    return D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);\n\n                case D3D_ROOT_SIGNATURE_VERSION_1_1:\n                {\n                    HRESULT hr = S_OK;\n                    const D3D12_ROOT_SIGNATURE_DESC1& desc_1_1 = pRootSignatureDesc->Desc_1_1;\n\n                    const SIZE_T ParametersSize = sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters;\n                    void* pParameters = (ParametersSize > 0) ? HeapAlloc(GetProcessHeap(), 0, ParametersSize) : nullptr;\n                    if (ParametersSize > 0 && pParameters == nullptr)\n                    {\n                        hr = E_OUTOFMEMORY;\n                    }\n                    auto pParameters_1_0 = static_cast<D3D12_ROOT_PARAMETER*>(pParameters);\n\n                    if (SUCCEEDED(hr))\n                    {\n                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)\n                        {\n                            __analysis_assume(ParametersSize == sizeof(D3D12_ROOT_PARAMETER) * desc_1_1.NumParameters);\n                            pParameters_1_0[n].ParameterType = desc_1_1.pParameters[n].ParameterType;\n                            pParameters_1_0[n].ShaderVisibility = desc_1_1.pParameters[n].ShaderVisibility;\n\n                            switch (desc_1_1.pParameters[n].ParameterType)\n                            {\n                            case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:\n                                pParameters_1_0[n].Constants.Num32BitValues = desc_1_1.pParameters[n].Constants.Num32BitValues;\n                                pParameters_1_0[n].Constants.RegisterSpace = desc_1_1.pParameters[n].Constants.RegisterSpace;\n                                pParameters_1_0[n].Constants.ShaderRegister = desc_1_1.pParameters[n].Constants.ShaderRegister;\n                                break;\n\n                            case D3D12_ROOT_PARAMETER_TYPE_CBV:\n                            case D3D12_ROOT_PARAMETER_TYPE_SRV:\n                            case D3D12_ROOT_PARAMETER_TYPE_UAV:\n                                pParameters_1_0[n].Descriptor.RegisterSpace = desc_1_1.pParameters[n].Descriptor.RegisterSpace;\n                                pParameters_1_0[n].Descriptor.ShaderRegister = desc_1_1.pParameters[n].Descriptor.ShaderRegister;\n                                break;\n\n                            case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:\n                                const D3D12_ROOT_DESCRIPTOR_TABLE1& table_1_1 = desc_1_1.pParameters[n].DescriptorTable;\n\n                                const SIZE_T DescriptorRangesSize = sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges;\n                                void* pDescriptorRanges = (DescriptorRangesSize > 0 && SUCCEEDED(hr)) ? HeapAlloc(GetProcessHeap(), 0, DescriptorRangesSize) : nullptr;\n                                if (DescriptorRangesSize > 0 && pDescriptorRanges == nullptr)\n                                {\n                                    hr = E_OUTOFMEMORY;\n                                }\n                                auto pDescriptorRanges_1_0 = static_cast<D3D12_DESCRIPTOR_RANGE*>(pDescriptorRanges);\n\n                                if (SUCCEEDED(hr))\n                                {\n                                    for (UINT x = 0; x < table_1_1.NumDescriptorRanges; x++)\n                                    {\n                                        __analysis_assume(DescriptorRangesSize == sizeof(D3D12_DESCRIPTOR_RANGE) * table_1_1.NumDescriptorRanges);\n                                        pDescriptorRanges_1_0[x].BaseShaderRegister = table_1_1.pDescriptorRanges[x].BaseShaderRegister;\n                                        pDescriptorRanges_1_0[x].NumDescriptors = table_1_1.pDescriptorRanges[x].NumDescriptors;\n                                        pDescriptorRanges_1_0[x].OffsetInDescriptorsFromTableStart = table_1_1.pDescriptorRanges[x].OffsetInDescriptorsFromTableStart;\n                                        pDescriptorRanges_1_0[x].RangeType = table_1_1.pDescriptorRanges[x].RangeType;\n                                        pDescriptorRanges_1_0[x].RegisterSpace = table_1_1.pDescriptorRanges[x].RegisterSpace;\n                                    }\n                                }\n\n                                D3D12_ROOT_DESCRIPTOR_TABLE& table_1_0 = pParameters_1_0[n].DescriptorTable;\n                                table_1_0.NumDescriptorRanges = table_1_1.NumDescriptorRanges;\n                                table_1_0.pDescriptorRanges = pDescriptorRanges_1_0;\n                            }\n                        }\n                    }\n\n                    if (SUCCEEDED(hr))\n                    {\n                        CD3DX12_ROOT_SIGNATURE_DESC desc_1_0(desc_1_1.NumParameters, pParameters_1_0, desc_1_1.NumStaticSamplers, desc_1_1.pStaticSamplers, desc_1_1.Flags);\n                        hr = D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);\n                    }\n\n                    if (pParameters)\n                    {\n                        for (UINT n = 0; n < desc_1_1.NumParameters; n++)\n                        {\n                            if (desc_1_1.pParameters[n].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)\n                            {\n                                HeapFree(GetProcessHeap(), 0, reinterpret_cast<void*>(const_cast<D3D12_DESCRIPTOR_RANGE*>(pParameters_1_0[n].DescriptorTable.pDescriptorRanges)));\n                            }\n                        }\n                        HeapFree(GetProcessHeap(), 0, pParameters);\n                    }\n                    return hr;\n                }\n            }\n            break;\n\n        case D3D_ROOT_SIGNATURE_VERSION_1_1:\n            return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob);\n    }\n\n    return E_INVALIDARG;\n}\n\n//------------------------------------------------------------------------------------------------\n#if defined(NTDDI_WIN10_RS2) && (NTDDI_VERSION >= NTDDI_WIN10_RS2)\nstruct CD3DX12_RT_FORMAT_ARRAY : public D3D12_RT_FORMAT_ARRAY\n{\n    CD3DX12_RT_FORMAT_ARRAY() = default;\n    explicit CD3DX12_RT_FORMAT_ARRAY(const D3D12_RT_FORMAT_ARRAY& o) noexcept\n        : D3D12_RT_FORMAT_ARRAY(o)\n    {}\n    explicit CD3DX12_RT_FORMAT_ARRAY(_In_reads_(NumFormats) const DXGI_FORMAT* pFormats, UINT NumFormats) noexcept\n    {\n        NumRenderTargets = NumFormats;\n        memcpy(RTFormats, pFormats, sizeof(RTFormats));\n        // assumes ARRAY_SIZE(pFormats) == ARRAY_SIZE(RTFormats)\n    }\n};\n\n//------------------------------------------------------------------------------------------------\n// Pipeline State Stream Helpers\n//------------------------------------------------------------------------------------------------\n\n//------------------------------------------------------------------------------------------------\n// Stream Subobjects, i.e. elements of a stream\n\nstruct DefaultSampleMask { operator UINT() noexcept { return UINT_MAX; } };\nstruct DefaultSampleDesc { operator DXGI_SAMPLE_DESC() noexcept { return DXGI_SAMPLE_DESC{1, 0}; } };\n\n#pragma warning(push)\n#pragma warning(disable : 4324)\ntemplate <typename InnerStructType, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type, typename DefaultArg = InnerStructType>\nclass alignas(void*) CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT\n{\nprivate:\n    D3D12_PIPELINE_STATE_SUBOBJECT_TYPE _Type;\n    InnerStructType _Inner;\npublic:\n    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT() noexcept : _Type(Type), _Inner(DefaultArg()) {}\n    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT(InnerStructType const& i) noexcept : _Type(Type), _Inner(i) {}\n    CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT& operator=(InnerStructType const& i) noexcept { _Type = Type; _Inner = i; return *this; }\n    operator InnerStructType const&() const noexcept { return _Inner; }\n    operator InnerStructType&() noexcept { return _Inner; }\n    InnerStructType* operator&() noexcept { return &_Inner; }\n    InnerStructType const* operator&() const noexcept { return &_Inner; }\n};\n#pragma warning(pop)\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PIPELINE_STATE_FLAGS,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS>                             CD3DX12_PIPELINE_STATE_STREAM_FLAGS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK>                         CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< ID3D12RootSignature*,               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE>                    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INPUT_LAYOUT_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT>                      CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE>                CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PRIMITIVE_TOPOLOGY_TYPE,      D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY>                CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS>                                CD3DX12_PIPELINE_STATE_STREAM_VS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS>                                CD3DX12_PIPELINE_STATE_STREAM_GS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_STREAM_OUTPUT_DESC,           D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT>                     CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS>                                CD3DX12_PIPELINE_STATE_STREAM_HS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS>                                CD3DX12_PIPELINE_STATE_STREAM_DS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS>                                CD3DX12_PIPELINE_STATE_STREAM_PS;\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS>                                CD3DX12_PIPELINE_STATE_STREAM_AS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS>                                CD3DX12_PIPELINE_STATE_STREAM_MS;\n#endif\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_SHADER_BYTECODE,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS>                                CD3DX12_PIPELINE_STATE_STREAM_CS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_BLEND_DESC,                 D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND,          CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC,         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL,  CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_DEPTH_STENCIL_DESC1,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_FORMAT,                        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT>              CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_RASTERIZER_DESC,            D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER,     CD3DX12_DEFAULT>   CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_RT_FORMAT_ARRAY,              D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS>             CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< DXGI_SAMPLE_DESC,                   D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC,    DefaultSampleDesc> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT,                               D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK,    DefaultSampleMask> CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK;\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_CACHED_PIPELINE_STATE,        D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO>                        CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO;\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\ntypedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< CD3DX12_VIEW_INSTANCING_DESC,       D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, CD3DX12_DEFAULT>  CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING;\n#endif\n\n//------------------------------------------------------------------------------------------------\n// Stream Parser Helpers\n\nstruct ID3DX12PipelineParserCallbacks\n{\n    // Subobject Callbacks\n    virtual void FlagsCb(D3D12_PIPELINE_STATE_FLAGS) {}\n    virtual void NodeMaskCb(UINT) {}\n    virtual void RootSignatureCb(ID3D12RootSignature*) {}\n    virtual void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC&) {}\n    virtual void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE) {}\n    virtual void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE) {}\n    virtual void VSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void GSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC&) {}\n    virtual void HSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void DSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void PSCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void CSCb(const D3D12_SHADER_BYTECODE&) {}\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n    virtual void ASCb(const D3D12_SHADER_BYTECODE&) {}\n    virtual void MSCb(const D3D12_SHADER_BYTECODE&) {}\n#endif\n    virtual void BlendStateCb(const D3D12_BLEND_DESC&) {}\n    virtual void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC&) {}\n    virtual void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1&) {}\n    virtual void DSVFormatCb(DXGI_FORMAT) {}\n    virtual void RasterizerStateCb(const D3D12_RASTERIZER_DESC&) {}\n    virtual void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY&) {}\n    virtual void SampleDescCb(const DXGI_SAMPLE_DESC&) {}\n    virtual void SampleMaskCb(UINT) {}\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n    virtual void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC&) {}\n#endif\n    virtual void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE&) {}\n\n    // Error Callbacks\n    virtual void ErrorBadInputParameter(UINT /*ParameterIndex*/) {}\n    virtual void ErrorDuplicateSubobject(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE /*DuplicateType*/) {}\n    virtual void ErrorUnknownSubobject(UINT /*UnknownTypeValue*/) {}\n\n    virtual ~ID3DX12PipelineParserCallbacks() = default;\n};\n\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct D3DX12_MESH_SHADER_PIPELINE_STATE_DESC\n{\n    ID3D12RootSignature*          pRootSignature;\n    D3D12_SHADER_BYTECODE         AS;\n    D3D12_SHADER_BYTECODE         MS;\n    D3D12_SHADER_BYTECODE         PS;\n    D3D12_BLEND_DESC              BlendState;\n    UINT                          SampleMask;\n    D3D12_RASTERIZER_DESC         RasterizerState;\n    D3D12_DEPTH_STENCIL_DESC      DepthStencilState;\n    D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;\n    UINT                          NumRenderTargets;\n    DXGI_FORMAT                   RTVFormats[ D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT ];\n    DXGI_FORMAT                   DSVFormat;\n    DXGI_SAMPLE_DESC              SampleDesc;\n    UINT                          NodeMask;\n    D3D12_CACHED_PIPELINE_STATE   CachedPSO;\n    D3D12_PIPELINE_STATE_FLAGS    Flags;\n};\n\n// CD3DX12_PIPELINE_STATE_STREAM2 Works on OS Build 19041+ (where there is a new mesh shader pipeline).\n// Use CD3DX12_PIPELINE_STATE_STREAM1 for OS Build 16299+ (where there is a new view instancing subobject).\n// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.\nstruct CD3DX12_PIPELINE_STATE_STREAM2\n{\n    CD3DX12_PIPELINE_STATE_STREAM2() = default;\n    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC\n    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , InputLayout(Desc.InputLayout)\n        , IBStripCutValue(Desc.IBStripCutValue)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , VS(Desc.VS)\n        , GS(Desc.GS)\n        , StreamOutput(Desc.StreamOutput)\n        , HS(Desc.HS)\n        , DS(Desc.DS)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM2(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , PS(Desc.PS)\n        , AS(Desc.AS)\n        , MS(Desc.MS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM2(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))\n        , CachedPSO(Desc.CachedPSO)\n    {\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;\n    }\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;\n    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;\n    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;\n    CD3DX12_PIPELINE_STATE_STREAM_VS VS;\n    CD3DX12_PIPELINE_STATE_STREAM_GS GS;\n    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;\n    CD3DX12_PIPELINE_STATE_STREAM_HS HS;\n    CD3DX12_PIPELINE_STATE_STREAM_DS DS;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_AS AS;\n    CD3DX12_PIPELINE_STATE_STREAM_MS MS;\n    CD3DX12_PIPELINE_STATE_STREAM_CS CS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept\n    {\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.InputLayout           = this->InputLayout;\n        D.IBStripCutValue       = this->IBStripCutValue;\n        D.PrimitiveTopologyType = this->PrimitiveTopologyType;\n        D.VS                    = this->VS;\n        D.GS                    = this->GS;\n        D.StreamOutput          = this->StreamOutput;\n        D.HS                    = this->HS;\n        D.DS                    = this->DS;\n        D.PS                    = this->PS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept\n    {\n        D3D12_COMPUTE_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.CS                    = this->CS;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_VB\n\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n// CD3DX12_PIPELINE_STATE_STREAM1 Works on OS Build 16299+ (where there is a new view instancing subobject).\n// Use CD3DX12_PIPELINE_STATE_STREAM for OS Build 15063+ support.\nstruct CD3DX12_PIPELINE_STATE_STREAM1\n{\n    CD3DX12_PIPELINE_STATE_STREAM1() = default;\n    // Mesh and amplification shaders must be set manually, since they do not have representation in D3D12_GRAPHICS_PIPELINE_STATE_DESC\n    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , InputLayout(Desc.InputLayout)\n        , IBStripCutValue(Desc.IBStripCutValue)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , VS(Desc.VS)\n        , GS(Desc.GS)\n        , StreamOutput(Desc.StreamOutput)\n        , HS(Desc.HS)\n        , DS(Desc.DS)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n    CD3DX12_PIPELINE_STATE_STREAM1(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n#endif\n    CD3DX12_PIPELINE_STATE_STREAM1(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))\n        , CachedPSO(Desc.CachedPSO)\n    {\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(DepthStencilState).DepthEnable = false;\n    }\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;\n    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;\n    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;\n    CD3DX12_PIPELINE_STATE_STREAM_VS VS;\n    CD3DX12_PIPELINE_STATE_STREAM_GS GS;\n    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;\n    CD3DX12_PIPELINE_STATE_STREAM_HS HS;\n    CD3DX12_PIPELINE_STATE_STREAM_DS DS;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_CS CS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept\n    {\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.InputLayout           = this->InputLayout;\n        D.IBStripCutValue       = this->IBStripCutValue;\n        D.PrimitiveTopologyType = this->PrimitiveTopologyType;\n        D.VS                    = this->VS;\n        D.GS                    = this->GS;\n        D.StreamOutput          = this->StreamOutput;\n        D.HS                    = this->HS;\n        D.DS                    = this->DS;\n        D.PS                    = this->PS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept\n    {\n        D3D12_COMPUTE_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.CS                    = this->CS;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_RS3\n\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct CD3DX12_PIPELINE_MESH_STATE_STREAM\n{\n    CD3DX12_PIPELINE_MESH_STATE_STREAM() = default;\n    CD3DX12_PIPELINE_MESH_STATE_STREAM(const D3DX12_MESH_SHADER_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , PS(Desc.PS)\n        , AS(Desc.AS)\n        , MS(Desc.MS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n        , ViewInstancingDesc(CD3DX12_VIEW_INSTANCING_DESC(CD3DX12_DEFAULT()))\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_AS AS;\n    CD3DX12_PIPELINE_STATE_STREAM_MS MS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    CD3DX12_PIPELINE_STATE_STREAM_VIEW_INSTANCING ViewInstancingDesc;\n    D3DX12_MESH_SHADER_PIPELINE_STATE_DESC MeshShaderDescV0() const noexcept\n    {\n        D3DX12_MESH_SHADER_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.PS                    = this->PS;\n        D.AS                    = this->AS;\n        D.MS                    = this->MS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n#endif // NTDDI_WIN10_VB\n\n// CD3DX12_PIPELINE_STATE_STREAM works on OS Build 15063+ but does not support new subobject(s) added in OS Build 16299+.\n// See CD3DX12_PIPELINE_STATE_STREAM1 for instance.\nstruct CD3DX12_PIPELINE_STATE_STREAM\n{\n    CD3DX12_PIPELINE_STATE_STREAM() = default;\n    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , InputLayout(Desc.InputLayout)\n        , IBStripCutValue(Desc.IBStripCutValue)\n        , PrimitiveTopologyType(Desc.PrimitiveTopologyType)\n        , VS(Desc.VS)\n        , GS(Desc.GS)\n        , StreamOutput(Desc.StreamOutput)\n        , HS(Desc.HS)\n        , DS(Desc.DS)\n        , PS(Desc.PS)\n        , BlendState(CD3DX12_BLEND_DESC(Desc.BlendState))\n        , DepthStencilState(CD3DX12_DEPTH_STENCIL_DESC1(Desc.DepthStencilState))\n        , DSVFormat(Desc.DSVFormat)\n        , RasterizerState(CD3DX12_RASTERIZER_DESC(Desc.RasterizerState))\n        , RTVFormats(CD3DX12_RT_FORMAT_ARRAY(Desc.RTVFormats, Desc.NumRenderTargets))\n        , SampleDesc(Desc.SampleDesc)\n        , SampleMask(Desc.SampleMask)\n        , CachedPSO(Desc.CachedPSO)\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM(const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc) noexcept\n        : Flags(Desc.Flags)\n        , NodeMask(Desc.NodeMask)\n        , pRootSignature(Desc.pRootSignature)\n        , CS(CD3DX12_SHADER_BYTECODE(Desc.CS))\n        , CachedPSO(Desc.CachedPSO)\n    {}\n    CD3DX12_PIPELINE_STATE_STREAM_FLAGS Flags;\n    CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK NodeMask;\n    CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE pRootSignature;\n    CD3DX12_PIPELINE_STATE_STREAM_INPUT_LAYOUT InputLayout;\n    CD3DX12_PIPELINE_STATE_STREAM_IB_STRIP_CUT_VALUE IBStripCutValue;\n    CD3DX12_PIPELINE_STATE_STREAM_PRIMITIVE_TOPOLOGY PrimitiveTopologyType;\n    CD3DX12_PIPELINE_STATE_STREAM_VS VS;\n    CD3DX12_PIPELINE_STATE_STREAM_GS GS;\n    CD3DX12_PIPELINE_STATE_STREAM_STREAM_OUTPUT StreamOutput;\n    CD3DX12_PIPELINE_STATE_STREAM_HS HS;\n    CD3DX12_PIPELINE_STATE_STREAM_DS DS;\n    CD3DX12_PIPELINE_STATE_STREAM_PS PS;\n    CD3DX12_PIPELINE_STATE_STREAM_CS CS;\n    CD3DX12_PIPELINE_STATE_STREAM_BLEND_DESC BlendState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL1 DepthStencilState;\n    CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL_FORMAT DSVFormat;\n    CD3DX12_PIPELINE_STATE_STREAM_RASTERIZER RasterizerState;\n    CD3DX12_PIPELINE_STATE_STREAM_RENDER_TARGET_FORMATS RTVFormats;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_DESC SampleDesc;\n    CD3DX12_PIPELINE_STATE_STREAM_SAMPLE_MASK SampleMask;\n    CD3DX12_PIPELINE_STATE_STREAM_CACHED_PSO CachedPSO;\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GraphicsDescV0() const noexcept\n    {\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.InputLayout           = this->InputLayout;\n        D.IBStripCutValue       = this->IBStripCutValue;\n        D.PrimitiveTopologyType = this->PrimitiveTopologyType;\n        D.VS                    = this->VS;\n        D.GS                    = this->GS;\n        D.StreamOutput          = this->StreamOutput;\n        D.HS                    = this->HS;\n        D.DS                    = this->DS;\n        D.PS                    = this->PS;\n        D.BlendState            = this->BlendState;\n        D.DepthStencilState     = CD3DX12_DEPTH_STENCIL_DESC1(D3D12_DEPTH_STENCIL_DESC1(this->DepthStencilState));\n        D.DSVFormat             = this->DSVFormat;\n        D.RasterizerState       = this->RasterizerState;\n        D.NumRenderTargets      = D3D12_RT_FORMAT_ARRAY(this->RTVFormats).NumRenderTargets;\n        memcpy(D.RTVFormats, D3D12_RT_FORMAT_ARRAY(this->RTVFormats).RTFormats, sizeof(D.RTVFormats));\n        D.SampleDesc            = this->SampleDesc;\n        D.SampleMask            = this->SampleMask;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n    D3D12_COMPUTE_PIPELINE_STATE_DESC ComputeDescV0() const noexcept\n    {\n        D3D12_COMPUTE_PIPELINE_STATE_DESC D;\n        D.Flags                 = this->Flags;\n        D.NodeMask              = this->NodeMask;\n        D.pRootSignature        = this->pRootSignature;\n        D.CS                    = this->CS;\n        D.CachedPSO             = this->CachedPSO;\n        return D;\n    }\n};\n\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nstruct CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER : public ID3DX12PipelineParserCallbacks\n{\n    CD3DX12_PIPELINE_STATE_STREAM2 PipelineStream;\n    CD3DX12_PIPELINE_STATE_STREAM2_PARSE_HELPER() noexcept\n        : SeenDSS(false)\n    {\n        // Adjust defaults to account for absent members.\n        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n\n        // Depth disabled if no DSV format specified.\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;\n    }\n\n    // ID3DX12PipelineParserCallbacks\n    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}\n    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}\n    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}\n    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}\n    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}\n    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}\n    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}\n    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}\n    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}\n    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}\n    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}\n    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}\n    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}\n    void ASCb(const D3D12_SHADER_BYTECODE& AS) override {PipelineStream.AS = AS;}\n    void MSCb(const D3D12_SHADER_BYTECODE& MS) override {PipelineStream.MS = MS;}\n    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}\n    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DSVFormatCb(DXGI_FORMAT DSVFormat) override\n    {\n        PipelineStream.DSVFormat = DSVFormat;\n        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)\n        {\n            // Re-enable depth for the default state.\n            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;\n        }\n    }\n    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}\n    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}\n    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}\n    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}\n    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}\n    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}\n\nprivate:\n    bool SeenDSS;\n};\n#endif // NTDDI_WIN10_VB\n\nstruct CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER : public ID3DX12PipelineParserCallbacks\n{\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n    CD3DX12_PIPELINE_STATE_STREAM1 PipelineStream;\n#else\n    CD3DX12_PIPELINE_STATE_STREAM PipelineStream;\n#endif\n    CD3DX12_PIPELINE_STATE_STREAM_PARSE_HELPER() noexcept\n        : SeenDSS(false)\n    {\n        // Adjust defaults to account for absent members.\n        PipelineStream.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n\n        // Depth disabled if no DSV format specified.\n        static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = false;\n    }\n\n    // ID3DX12PipelineParserCallbacks\n    void FlagsCb(D3D12_PIPELINE_STATE_FLAGS Flags) override {PipelineStream.Flags = Flags;}\n    void NodeMaskCb(UINT NodeMask) override {PipelineStream.NodeMask = NodeMask;}\n    void RootSignatureCb(ID3D12RootSignature* pRootSignature) override {PipelineStream.pRootSignature = pRootSignature;}\n    void InputLayoutCb(const D3D12_INPUT_LAYOUT_DESC& InputLayout) override {PipelineStream.InputLayout = InputLayout;}\n    void IBStripCutValueCb(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue) override {PipelineStream.IBStripCutValue = IBStripCutValue;}\n    void PrimitiveTopologyTypeCb(D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType) override {PipelineStream.PrimitiveTopologyType = PrimitiveTopologyType;}\n    void VSCb(const D3D12_SHADER_BYTECODE& VS) override {PipelineStream.VS = VS;}\n    void GSCb(const D3D12_SHADER_BYTECODE& GS) override {PipelineStream.GS = GS;}\n    void StreamOutputCb(const D3D12_STREAM_OUTPUT_DESC& StreamOutput) override {PipelineStream.StreamOutput = StreamOutput;}\n    void HSCb(const D3D12_SHADER_BYTECODE& HS) override {PipelineStream.HS = HS;}\n    void DSCb(const D3D12_SHADER_BYTECODE& DS) override {PipelineStream.DS = DS;}\n    void PSCb(const D3D12_SHADER_BYTECODE& PS) override {PipelineStream.PS = PS;}\n    void CSCb(const D3D12_SHADER_BYTECODE& CS) override {PipelineStream.CS = CS;}\n    void BlendStateCb(const D3D12_BLEND_DESC& BlendState) override {PipelineStream.BlendState = CD3DX12_BLEND_DESC(BlendState);}\n    void DepthStencilStateCb(const D3D12_DEPTH_STENCIL_DESC& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DepthStencilState1Cb(const D3D12_DEPTH_STENCIL_DESC1& DepthStencilState) override\n    {\n        PipelineStream.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC1(DepthStencilState);\n        SeenDSS = true;\n    }\n    void DSVFormatCb(DXGI_FORMAT DSVFormat) override\n    {\n        PipelineStream.DSVFormat = DSVFormat;\n        if (!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)\n        {\n            // Re-enable depth for the default state.\n            static_cast<D3D12_DEPTH_STENCIL_DESC1&>(PipelineStream.DepthStencilState).DepthEnable = true;\n        }\n    }\n    void RasterizerStateCb(const D3D12_RASTERIZER_DESC& RasterizerState) override {PipelineStream.RasterizerState = CD3DX12_RASTERIZER_DESC(RasterizerState);}\n    void RTVFormatsCb(const D3D12_RT_FORMAT_ARRAY& RTVFormats) override {PipelineStream.RTVFormats = RTVFormats;}\n    void SampleDescCb(const DXGI_SAMPLE_DESC& SampleDesc) override {PipelineStream.SampleDesc = SampleDesc;}\n    void SampleMaskCb(UINT SampleMask) override {PipelineStream.SampleMask = SampleMask;}\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n    void ViewInstancingCb(const D3D12_VIEW_INSTANCING_DESC& ViewInstancingDesc) override {PipelineStream.ViewInstancingDesc = CD3DX12_VIEW_INSTANCING_DESC(ViewInstancingDesc);}\n#endif\n    void CachedPSOCb(const D3D12_CACHED_PIPELINE_STATE& CachedPSO) override {PipelineStream.CachedPSO = CachedPSO;}\n\nprivate:\n    bool SeenDSS;\n};\n\ninline D3D12_PIPELINE_STATE_SUBOBJECT_TYPE D3DX12GetBaseSubobjectType(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE SubobjectType) noexcept\n{\n    switch (SubobjectType)\n    {\n    case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:\n        return D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL;\n    default:\n        return SubobjectType;\n    }\n}\n\ninline HRESULT D3DX12ParsePipelineStream(const D3D12_PIPELINE_STATE_STREAM_DESC& Desc, ID3DX12PipelineParserCallbacks* pCallbacks)\n{\n    if (pCallbacks == nullptr)\n    {\n        return E_INVALIDARG;\n    }\n\n    if (Desc.SizeInBytes == 0 || Desc.pPipelineStateSubobjectStream == nullptr)\n    {\n        pCallbacks->ErrorBadInputParameter(1); // first parameter issue\n        return E_INVALIDARG;\n    }\n\n    bool SubobjectSeen[D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID] = {};\n    for (SIZE_T CurOffset = 0, SizeOfSubobject = 0; CurOffset < Desc.SizeInBytes; CurOffset += SizeOfSubobject)\n    {\n        BYTE* pStream = static_cast<BYTE*>(Desc.pPipelineStateSubobjectStream)+CurOffset;\n        auto SubobjectType = *reinterpret_cast<D3D12_PIPELINE_STATE_SUBOBJECT_TYPE*>(pStream);\n        if (SubobjectType < 0 || SubobjectType >= D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID)\n        {\n            pCallbacks->ErrorUnknownSubobject(SubobjectType);\n            return E_INVALIDARG;\n        }\n        if (SubobjectSeen[D3DX12GetBaseSubobjectType(SubobjectType)])\n        {\n            pCallbacks->ErrorDuplicateSubobject(SubobjectType);\n            return E_INVALIDARG; // disallow subobject duplicates in a stream\n        }\n        SubobjectSeen[SubobjectType] = true;\n        switch (SubobjectType)\n        {\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE:\n            pCallbacks->RootSignatureCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::pRootSignature);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS:\n            pCallbacks->VSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::VS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::VS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS:\n            pCallbacks->PSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS:\n            pCallbacks->DSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS:\n            pCallbacks->HSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::HS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::HS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS:\n            pCallbacks->GSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::GS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::GS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS:\n            pCallbacks->CSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CS);\n            break;\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS:\n            pCallbacks->ASCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::AS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::AS);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS:\n            pCallbacks->MSCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM2::MS)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM2::MS);\n            break;\n#endif\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT:\n            pCallbacks->StreamOutputCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::StreamOutput);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND:\n            pCallbacks->BlendStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::BlendState)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::BlendState);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK:\n            pCallbacks->SampleMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleMask)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleMask);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER:\n            pCallbacks->RasterizerStateCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RasterizerState);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL:\n            pCallbacks->DepthStencilStateCb(*reinterpret_cast<CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM_DEPTH_STENCIL);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:\n            pCallbacks->DepthStencilState1Cb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DepthStencilState);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT:\n            pCallbacks->InputLayoutCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::InputLayout)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::InputLayout);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE:\n            pCallbacks->IBStripCutValueCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::IBStripCutValue);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY:\n            pCallbacks->PrimitiveTopologyTypeCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::PrimitiveTopologyType);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS:\n            pCallbacks->RTVFormatsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::RTVFormats);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT:\n            pCallbacks->DSVFormatCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::DSVFormat);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC:\n            pCallbacks->SampleDescCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::SampleDesc);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK:\n            pCallbacks->NodeMaskCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::NodeMask)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::NodeMask);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO:\n            pCallbacks->CachedPSOCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::CachedPSO);\n            break;\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS:\n            pCallbacks->FlagsCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM::Flags)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM::Flags);\n            break;\n#if defined(NTDDI_WIN10_RS3) && (NTDDI_VERSION >= NTDDI_WIN10_RS3)\n        case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING:\n            pCallbacks->ViewInstancingCb(*reinterpret_cast<decltype(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc)*>(pStream));\n            SizeOfSubobject = sizeof(CD3DX12_PIPELINE_STATE_STREAM1::ViewInstancingDesc);\n            break;\n#endif\n        default:\n            pCallbacks->ErrorUnknownSubobject(SubobjectType);\n            return E_INVALIDARG;\n        }\n    }\n\n    return S_OK;\n}\n#endif // NTDDI_WIN10_RS2\n\n// Requires the Windows 10 October 2018 Update SDK (17763)\n#if defined(NTDDI_WIN10_RS5) && (NTDDI_VERSION >= NTDDI_WIN10_RS5)\n//------------------------------------------------------------------------------------------------\ninline bool operator==( const D3D12_CLEAR_VALUE &a, const D3D12_CLEAR_VALUE &b) noexcept\n{\n    if (a.Format != b.Format) return false;\n    if (a.Format == DXGI_FORMAT_D24_UNORM_S8_UINT\n     || a.Format == DXGI_FORMAT_D16_UNORM\n     || a.Format == DXGI_FORMAT_D32_FLOAT\n     || a.Format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT)\n    {\n        return (a.DepthStencil.Depth == b.DepthStencil.Depth) &&\n          (a.DepthStencil.Stencil == b.DepthStencil.Stencil);\n    } else {\n        return (a.Color[0] == b.Color[0]) &&\n               (a.Color[1] == b.Color[1]) &&\n               (a.Color[2] == b.Color[2]) &&\n               (a.Color[3] == b.Color[3]);\n    }\n}\ninline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS &b) noexcept\n{\n    return a.ClearValue == b.ClearValue;\n}\ninline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &a, const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS &b) noexcept\n{\n    if (a.pSrcResource != b.pSrcResource) return false;\n    if (a.pDstResource != b.pDstResource) return false;\n    if (a.SubresourceCount != b.SubresourceCount) return false;\n    if (a.Format != b.Format) return false;\n    if (a.ResolveMode != b.ResolveMode) return false;\n    if (a.PreserveResolveSource != b.PreserveResolveSource) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_BEGINNING_ACCESS &a, const D3D12_RENDER_PASS_BEGINNING_ACCESS &b) noexcept\n{\n    if (a.Type != b.Type) return false;\n    if (a.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR && !(a.Clear == b.Clear)) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_ENDING_ACCESS &a, const D3D12_RENDER_PASS_ENDING_ACCESS &b) noexcept\n{\n    if (a.Type != b.Type) return false;\n    if (a.Type == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE && !(a.Resolve == b.Resolve)) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_RENDER_TARGET_DESC &a, const D3D12_RENDER_PASS_RENDER_TARGET_DESC &b) noexcept\n{\n    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;\n    if (!(a.BeginningAccess == b.BeginningAccess)) return false;\n    if (!(a.EndingAccess == b.EndingAccess)) return false;\n    return true;\n}\ninline bool operator==( const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &a, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC &b) noexcept\n{\n    if (a.cpuDescriptor.ptr != b.cpuDescriptor.ptr) return false;\n    if (!(a.DepthBeginningAccess == b.DepthBeginningAccess)) return false;\n    if (!(a.StencilBeginningAccess == b.StencilBeginningAccess)) return false;\n    if (!(a.DepthEndingAccess == b.DepthEndingAccess)) return false;\n    if (!(a.StencilEndingAccess == b.StencilEndingAccess)) return false;\n    return true;\n}\n\n\n#ifndef D3DX12_NO_STATE_OBJECT_HELPERS\n\n//================================================================================================\n// D3DX12 State Object Creation Helpers\n//\n// Helper classes for creating new style state objects out of an arbitrary set of subobjects.\n// Uses STL\n//\n// Start by instantiating CD3DX12_STATE_OBJECT_DESC (see it's public methods).\n// One of its methods is CreateSubobject(), which has a comment showing a couple of options for\n// defining subobjects using the helper classes for each subobject (CD3DX12_DXIL_LIBRARY_SUBOBJECT\n// etc.). The subobject helpers each have methods specific to the subobject for configuring it's\n// contents.\n//\n//================================================================================================\n#include <list>\n#include <vector>\n#include <string>\n#include <memory>\n#include <wrl/client.h>\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_STATE_OBJECT_DESC\n{\npublic:\n    CD3DX12_STATE_OBJECT_DESC() noexcept\n    {\n        Init(D3D12_STATE_OBJECT_TYPE_COLLECTION);\n    }\n    CD3DX12_STATE_OBJECT_DESC(D3D12_STATE_OBJECT_TYPE Type) noexcept\n    {\n        Init(Type);\n    }\n    void SetStateObjectType(D3D12_STATE_OBJECT_TYPE Type) noexcept { m_Desc.Type = Type; }\n    operator const D3D12_STATE_OBJECT_DESC&()\n    {\n        // Do final preparation work\n        m_RepointedAssociations.clear();\n        m_SubobjectArray.clear();\n        m_SubobjectArray.reserve(m_Desc.NumSubobjects);\n        // Flatten subobjects into an array (each flattened subobject still has a\n        // member that's a pointer to it's desc that's not flattened)\n        for (auto Iter = m_SubobjectList.begin();\n            Iter != m_SubobjectList.end(); Iter++)\n        {\n            m_SubobjectArray.push_back(*Iter);\n            // Store new location in array so we can redirect pointers contained in subobjects\n            Iter->pSubobjectArrayLocation = &m_SubobjectArray.back();\n        }\n        // For subobjects with pointer fields, create a new copy of those subobject definitions\n        // with fixed pointers\n        for (UINT i = 0; i < m_Desc.NumSubobjects; i++)\n        {\n            if (m_SubobjectArray[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION)\n            {\n                auto pOriginalSubobjectAssociation =\n                    static_cast<const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION*>(m_SubobjectArray[i].pDesc);\n                D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION Repointed = *pOriginalSubobjectAssociation;\n                auto pWrapper =\n                    static_cast<const SUBOBJECT_WRAPPER*>(pOriginalSubobjectAssociation->pSubobjectToAssociate);\n                Repointed.pSubobjectToAssociate = pWrapper->pSubobjectArrayLocation;\n                m_RepointedAssociations.push_back(Repointed);\n                m_SubobjectArray[i].pDesc = &m_RepointedAssociations.back();\n            }\n        }\n        // Below: using ugly way to get pointer in case .data() is not defined\n        m_Desc.pSubobjects = m_Desc.NumSubobjects ? &m_SubobjectArray[0] : nullptr;\n        return m_Desc;\n    }\n    operator const D3D12_STATE_OBJECT_DESC*()\n    {\n        // Cast calls the above final preparation work\n        return &static_cast<const D3D12_STATE_OBJECT_DESC&>(*this);\n    }\n\n    // CreateSubobject creates a sububject helper (e.g. CD3DX12_HIT_GROUP_SUBOBJECT)\n    // whose lifetime is owned by this class.\n    // e.g.\n    //\n    //    CD3DX12_STATE_OBJECT_DESC Collection1(D3D12_STATE_OBJECT_TYPE_COLLECTION);\n    //    auto Lib0 = Collection1.CreateSubobject<CD3DX12_DXIL_LIBRARY_SUBOBJECT>();\n    //    Lib0->SetDXILLibrary(&pMyAppDxilLibs[0]);\n    //    Lib0->DefineExport(L\"rayGenShader0\"); // in practice these export listings might be\n    //                                          // data/engine driven\n    //    etc.\n    //\n    // Alternatively, users can instantiate sububject helpers explicitly, such as via local\n    // variables instead, passing the state object desc that should point to it into the helper\n    // constructor (or call mySubobjectHelper.AddToStateObject(Collection1)).\n    // In this alternative scenario, the user must keep the subobject alive as long as the state\n    // object it is associated with is alive, else it's pointer references will be stale.\n    // e.g.\n    //\n    //    CD3DX12_STATE_OBJECT_DESC RaytracingState2(D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE);\n    //    CD3DX12_DXIL_LIBRARY_SUBOBJECT LibA(RaytracingState2);\n    //    LibA.SetDXILLibrary(&pMyAppDxilLibs[4]); // not manually specifying exports\n    //                                             // - meaning all exports in the libraries\n    //                                             // are exported\n    //    etc.\n\n    template<typename T>\n    T* CreateSubobject()\n    {\n        T* pSubobject = new T(*this);\n        m_OwnedSubobjectHelpers.emplace_back(pSubobject);\n        return pSubobject;\n    }\n\nprivate:\n    D3D12_STATE_SUBOBJECT* TrackSubobject(D3D12_STATE_SUBOBJECT_TYPE Type, void* pDesc)\n    {\n        SUBOBJECT_WRAPPER Subobject;\n        Subobject.pSubobjectArrayLocation = nullptr;\n        Subobject.Type = Type;\n        Subobject.pDesc = pDesc;\n        m_SubobjectList.push_back(Subobject);\n        m_Desc.NumSubobjects++;\n        return &m_SubobjectList.back();\n    }\n    void Init(D3D12_STATE_OBJECT_TYPE Type) noexcept\n    {\n        SetStateObjectType(Type);\n        m_Desc.pSubobjects = nullptr;\n        m_Desc.NumSubobjects = 0;\n        m_SubobjectList.clear();\n        m_SubobjectArray.clear();\n        m_RepointedAssociations.clear();\n    }\n    typedef struct SUBOBJECT_WRAPPER : public D3D12_STATE_SUBOBJECT\n    {\n        D3D12_STATE_SUBOBJECT* pSubobjectArrayLocation; // new location when flattened into array\n                                                        // for repointing pointers in subobjects\n    } SUBOBJECT_WRAPPER;\n    D3D12_STATE_OBJECT_DESC m_Desc;\n    std::list<SUBOBJECT_WRAPPER>   m_SubobjectList; // Pointers to list nodes handed out so\n                                                    // these can be edited live\n    std::vector<D3D12_STATE_SUBOBJECT> m_SubobjectArray; // Built at the end, copying list contents\n\n    std::list<D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION>\n            m_RepointedAssociations; // subobject type that contains pointers to other subobjects,\n                                     // repointed to flattened array\n\n    class StringContainer\n    {\n    public:\n        LPCWSTR LocalCopy(LPCWSTR string, bool bSingleString = false)\n        {\n            if (string)\n            {\n                if (bSingleString)\n                {\n                    m_Strings.clear();\n                    m_Strings.push_back(string);\n                }\n                else\n                {\n                    m_Strings.push_back(string);\n                }\n                return m_Strings.back().c_str();\n            }\n            else\n            {\n                return nullptr;\n            }\n        }\n        void clear() noexcept { m_Strings.clear(); }\n    private:\n        std::list<std::wstring> m_Strings;\n    };\n\n    class SUBOBJECT_HELPER_BASE\n    {\n    public:\n        SUBOBJECT_HELPER_BASE() noexcept { Init(); }\n        virtual ~SUBOBJECT_HELPER_BASE() = default;\n        virtual D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept = 0;\n        void AddToStateObject(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n        {\n            m_pSubobject = ContainingStateObject.TrackSubobject(Type(), Data());\n        }\n    protected:\n        virtual void* Data() noexcept = 0;\n        void Init() noexcept { m_pSubobject = nullptr; }\n        D3D12_STATE_SUBOBJECT* m_pSubobject;\n    };\n\n#if(__cplusplus >= 201103L)\n    std::list<std::unique_ptr<const SUBOBJECT_HELPER_BASE>> m_OwnedSubobjectHelpers;\n#else\n    class OWNED_HELPER\n    {\n    public:\n        OWNED_HELPER(const SUBOBJECT_HELPER_BASE* pHelper) noexcept { m_pHelper = pHelper; }\n        ~OWNED_HELPER() { delete m_pHelper; }\n        const SUBOBJECT_HELPER_BASE* m_pHelper;\n    };\n\n    std::list<OWNED_HELPER> m_OwnedSubobjectHelpers;\n#endif\n\n    friend class CD3DX12_DXIL_LIBRARY_SUBOBJECT;\n    friend class CD3DX12_EXISTING_COLLECTION_SUBOBJECT;\n    friend class CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT;\n    friend class CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;\n    friend class CD3DX12_HIT_GROUP_SUBOBJECT;\n    friend class CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT;\n    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT;\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\n    friend class CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT;\n#endif\n    friend class CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT;\n    friend class CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT;\n    friend class CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT;\n    friend class CD3DX12_NODE_MASK_SUBOBJECT;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_DXIL_LIBRARY_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_DXIL_LIBRARY_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_DXIL_LIBRARY_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetDXILLibrary(const D3D12_SHADER_BYTECODE* pCode) noexcept\n    {\n        static const D3D12_SHADER_BYTECODE Default = {};\n        m_Desc.DXILLibrary = pCode ? *pCode : Default;\n    }\n    void DefineExport(\n        LPCWSTR Name,\n        LPCWSTR ExportToRename = nullptr,\n        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)\n    {\n        D3D12_EXPORT_DESC Export;\n        Export.Name = m_Strings.LocalCopy(Name);\n        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);\n        Export.Flags = Flags;\n        m_Exports.push_back(Export);\n        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined\n        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());\n    }\n    template<size_t N>\n    void DefineExports(LPCWSTR(&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    void DefineExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_DXIL_LIBRARY_DESC&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_Strings.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_DXIL_LIBRARY_DESC m_Desc;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    std::vector<D3D12_EXPORT_DESC> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_EXISTING_COLLECTION_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_EXISTING_COLLECTION_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_EXISTING_COLLECTION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetExistingCollection(ID3D12StateObject*pExistingCollection) noexcept\n    {\n        m_Desc.pExistingCollection = pExistingCollection;\n        m_CollectionRef = pExistingCollection;\n    }\n    void DefineExport(\n        LPCWSTR Name,\n        LPCWSTR ExportToRename = nullptr,\n        D3D12_EXPORT_FLAGS Flags = D3D12_EXPORT_FLAG_NONE)\n    {\n        D3D12_EXPORT_DESC Export;\n        Export.Name = m_Strings.LocalCopy(Name);\n        Export.ExportToRename = m_Strings.LocalCopy(ExportToRename);\n        Export.Flags = Flags;\n        m_Exports.push_back(Export);\n        m_Desc.pExports = &m_Exports[0]; // using ugly way to get pointer in case .data() is not defined\n        m_Desc.NumExports = static_cast<UINT>(m_Exports.size());\n    }\n    template<size_t N>\n    void DefineExports(LPCWSTR(&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    void DefineExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            DefineExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_EXISTING_COLLECTION_DESC&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_CollectionRef = nullptr;\n        m_Strings.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_EXISTING_COLLECTION_DESC m_Desc;\n    Microsoft::WRL::ComPtr<ID3D12StateObject> m_CollectionRef;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    std::vector<D3D12_EXPORT_DESC> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetSubobjectToAssociate(const D3D12_STATE_SUBOBJECT& SubobjectToAssociate) noexcept\n    {\n        m_Desc.pSubobjectToAssociate = &SubobjectToAssociate;\n    }\n    void AddExport(LPCWSTR Export)\n    {\n        m_Desc.NumExports++;\n        m_Exports.push_back(m_Strings.LocalCopy(Export));\n        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined\n    }\n    template<size_t N>\n    void AddExports(LPCWSTR (&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    void AddExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_Strings.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    std::vector<LPCWSTR> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION() noexcept\n    {\n        Init();\n    }\n    CD3DX12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetSubobjectNameToAssociate(LPCWSTR SubobjectToAssociate)\n    {\n        m_Desc.SubobjectToAssociate = m_SubobjectName.LocalCopy(SubobjectToAssociate, true);\n    }\n    void AddExport(LPCWSTR Export)\n    {\n        m_Desc.NumExports++;\n        m_Exports.push_back(m_Strings.LocalCopy(Export));\n        m_Desc.pExports = &m_Exports[0];  // using ugly way to get pointer in case .data() is not defined\n    }\n    template<size_t N>\n    void AddExports(LPCWSTR (&Exports)[N])\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    void AddExports(const LPCWSTR* Exports, UINT N)\n    {\n        for (UINT i = 0; i < N; i++)\n        {\n            AddExport(Exports[i]);\n        }\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        m_Strings.clear();\n        m_SubobjectName.clear();\n        m_Exports.clear();\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION m_Desc;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_Strings;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer m_SubobjectName;\n    std::vector<LPCWSTR> m_Exports;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_HIT_GROUP_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_HIT_GROUP_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_HIT_GROUP_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetHitGroupExport(LPCWSTR exportName)\n    {\n        m_Desc.HitGroupExport = m_Strings[0].LocalCopy(exportName, true);\n    }\n    void SetHitGroupType(D3D12_HIT_GROUP_TYPE Type) noexcept { m_Desc.Type = Type; }\n    void SetAnyHitShaderImport(LPCWSTR importName)\n    {\n        m_Desc.AnyHitShaderImport = m_Strings[1].LocalCopy(importName, true);\n    }\n    void SetClosestHitShaderImport(LPCWSTR importName)\n    {\n        m_Desc.ClosestHitShaderImport = m_Strings[2].LocalCopy(importName, true);\n    }\n    void SetIntersectionShaderImport(LPCWSTR importName)\n    {\n        m_Desc.IntersectionShaderImport = m_Strings[3].LocalCopy(importName, true);\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_HIT_GROUP_DESC&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n        for (UINT i = 0; i < m_NumStrings; i++)\n        {\n            m_Strings[i].clear();\n        }\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_HIT_GROUP_DESC m_Desc;\n    static const UINT m_NumStrings = 4;\n    CD3DX12_STATE_OBJECT_DESC::StringContainer\n        m_Strings[m_NumStrings]; // one string for every entrypoint name\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void Config(UINT MaxPayloadSizeInBytes, UINT MaxAttributeSizeInBytes) noexcept\n    {\n        m_Desc.MaxPayloadSizeInBytes = MaxPayloadSizeInBytes;\n        m_Desc.MaxAttributeSizeInBytes = MaxAttributeSizeInBytes;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_RAYTRACING_SHADER_CONFIG&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_RAYTRACING_SHADER_CONFIG m_Desc;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void Config(UINT MaxTraceRecursionDepth) noexcept\n    {\n        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_RAYTRACING_PIPELINE_CONFIG&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_RAYTRACING_PIPELINE_CONFIG m_Desc;\n};\n\n//------------------------------------------------------------------------------------------------\n#if defined(NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)\nclass CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_RAYTRACING_PIPELINE_CONFIG1_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void Config(UINT MaxTraceRecursionDepth, D3D12_RAYTRACING_PIPELINE_FLAGS Flags) noexcept\n    {\n        m_Desc.MaxTraceRecursionDepth = MaxTraceRecursionDepth;\n        m_Desc.Flags = Flags;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG1;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_RAYTRACING_PIPELINE_CONFIG1&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_RAYTRACING_PIPELINE_CONFIG1 m_Desc;\n};\n#endif // NTDDI_WIN10_VB\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept\n    {\n        m_pRootSig = pRootSig;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator ID3D12RootSignature*() const noexcept { return m_pRootSig.Get(); }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_pRootSig = nullptr;\n    }\n    void* Data() noexcept override { return m_pRootSig.GetAddressOf(); }\n    Microsoft::WRL::ComPtr<ID3D12RootSignature> m_pRootSig;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetRootSignature(ID3D12RootSignature* pRootSig) noexcept\n    {\n        m_pRootSig = pRootSig;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator ID3D12RootSignature*() const noexcept { return m_pRootSig.Get(); }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_pRootSig = nullptr;\n    }\n    void* Data() noexcept override { return m_pRootSig.GetAddressOf(); }\n    Microsoft::WRL::ComPtr<ID3D12RootSignature> m_pRootSig;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_STATE_OBJECT_CONFIG_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetFlags(D3D12_STATE_OBJECT_FLAGS Flags) noexcept\n    {\n        m_Desc.Flags = Flags;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_STATE_OBJECT_CONFIG;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_STATE_OBJECT_CONFIG&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_STATE_OBJECT_CONFIG m_Desc;\n};\n\n//------------------------------------------------------------------------------------------------\nclass CD3DX12_NODE_MASK_SUBOBJECT\n    : public CD3DX12_STATE_OBJECT_DESC::SUBOBJECT_HELPER_BASE\n{\npublic:\n    CD3DX12_NODE_MASK_SUBOBJECT() noexcept\n    {\n        Init();\n    }\n    CD3DX12_NODE_MASK_SUBOBJECT(CD3DX12_STATE_OBJECT_DESC& ContainingStateObject)\n    {\n        Init();\n        AddToStateObject(ContainingStateObject);\n    }\n    void SetNodeMask(UINT NodeMask) noexcept\n    {\n        m_Desc.NodeMask = NodeMask;\n    }\n    D3D12_STATE_SUBOBJECT_TYPE Type() const noexcept override\n    {\n        return D3D12_STATE_SUBOBJECT_TYPE_NODE_MASK;\n    }\n    operator const D3D12_STATE_SUBOBJECT&() const noexcept { return *m_pSubobject; }\n    operator const D3D12_NODE_MASK&() const noexcept { return m_Desc; }\nprivate:\n    void Init() noexcept\n    {\n        SUBOBJECT_HELPER_BASE::Init();\n        m_Desc = {};\n    }\n    void* Data() noexcept override { return &m_Desc; }\n    D3D12_NODE_MASK m_Desc;\n};\n\n#endif // #ifndef D3DX12_NO_STATE_OBJECT_HELPERS\n#endif // NTDDI_WIN10_RS5\n\n#endif // defined( __cplusplus )\n\n#endif //__D3DX12_H__\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/pch.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: pch.cpp\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/pch.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: pch.h\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n// Off by default warnings\n#pragma warning(disable : 4619 4061 4265 4355 4365 4571 4623 4625 4626 4628 4668 4710 4711 4746 4774 4820 4987 5026 5027 5031 5032 5039 5045 5219 26812)\n// C4619 #pragma warning: there is no warning number 'X'\n// C4061 enumerator 'X' in switch of enum 'X' is not explicitly handled by a case label\n// C4265 class has virtual functions, but destructor is not virtual\n// C4355 'this': used in base member initializer list\n// C4365 signed/unsigned mismatch\n// C4571 behavior change\n// C4623 default constructor was implicitly defined as deleted\n// C4625 copy constructor was implicitly defined as deleted\n// C4626 assignment operator was implicitly defined as deleted\n// C4628 digraphs not supported\n// C4668 not defined as a preprocessor macro\n// C4710 function not inlined\n// C4711 selected for automatic inline expansion\n// C4746 volatile access of '<expression>' is subject to /volatile:<iso|ms> setting\n// C4774 format string expected in argument 3 is not a string literal\n// C4820 padding added after data member\n// C4987 nonstandard extension used\n// C5026 move constructor was implicitly defined as deleted\n// C5027 move assignment operator was implicitly defined as deleted\n// C5031/5032 push/pop mismatches in windows headers\n// C5039 pointer or reference to potentially throwing function passed to extern C function under - EHc\n// C5045 Spectre mitigation warning\n// C5219 implicit conversion from 'int' to 'float', possible loss of data\n// 26812: The enum type 'x' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).\n\n// XBox One XDK related Off by default warnings\n#pragma warning(disable : 4471 4643 4917 4986 5029 5043)\n// C4471 forward declaration of an unscoped enumeration must have an underlying type\n// C4643 Forward declaring in namespace std is not permitted by the C++ Standard\n// C4917 a GUID can only be associated with a class, interface or namespace\n// C4986 exception specification does not match previous declaration\n// C5029 nonstandard extension used\n// C5043 exception specification does not match previous declaration\n\n#ifdef __INTEL_COMPILER\n#pragma warning(disable : 161 2960 3280)\n// warning #161: unrecognized #pragma\n// message #2960: allocation may not satisfy the type's alignment; consider using <aligned_new> header\n// message #3280: declaration hides member\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wc++98-compat\"\n#pragma clang diagnostic ignored \"-Wc++98-compat-pedantic\"\n#pragma clang diagnostic ignored \"-Wc++98-compat-local-type-template-args\"\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n#pragma clang diagnostic ignored \"-Wfloat-equal\"\n#pragma clang diagnostic ignored \"-Wglobal-constructors\"\n#pragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#pragma clang diagnostic ignored \"-Wlanguage-extension-token\"\n#pragma clang diagnostic ignored \"-Wmissing-variable-declarations\"\n#pragma clang diagnostic ignored \"-Wnested-anon-types\"\n#pragma clang diagnostic ignored \"-Wreserved-id-macro\"\n#pragma clang diagnostic ignored \"-Wswitch-enum\"\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#pragma clang diagnostic ignored \"-Wunused-const-variable\"\n#pragma clang diagnostic ignored \"-Wunused-member-function\"\n#endif\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n\n#pragma warning(push)\n#pragma warning(disable : 4005)\n#define NOMINMAX\n#define NODRAWTEXT\n#define NOGDI\n#define NOBITMAP\n#define NOMCX\n#define NOSERVICE\n#define NOHELP\n#pragma warning(pop)\n\n#include <Windows.h>\n\n#ifndef _WIN32_WINNT_WIN10\n#define _WIN32_WINNT_WIN10 0x0A00\n#endif\n\n#ifdef _GAMING_XBOX\n#include <gxdk.h>\n\n#if _GXDK_VER < 0x4A610D2B /* GXDK Edition 200600 */\n#error DirectX Tool Kit requires the June 2020 GDK or later\n#endif\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#include <d3dx12_xs.h>\n#else\n#include <d3d12_x.h>\n#include <d3dx12_x.h>\n#endif\n#elif defined(_XBOX_ONE) && defined(_TITLE)\n#include <xdk.h>\n\n#if _XDK_VER < 0x295A044C /* XDK Edition 160200 */\n#error DirectX Tool Kit for Direct3D 12 requires the February 2016 XDK or later\n#endif\n\n#include <d3d12_x.h>\n#include <d3dx12_x.h>\n#else\n\n#ifdef _GAMING_DESKTOP\n#include <grdk.h>\n\n#if _GRDK_VER < 0x47BB2070 /* GDK Edition 191102 */\n#error DirectX Tool Kit requires the November 2020 GDK QFE2 or later\n#endif\n#endif\n\n#include <dxgi1_4.h>\n#include <d3d12.h>\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wsign-conversion\"\n#pragma clang diagnostic ignored \"-Wtautological-type-limit-compare\"\n#endif\n\n#define D3DX12_NO_STATE_OBJECT_HELPERS\n#include \"d3dx12.h\"\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n#if (defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) || (defined(_XBOX_ONE) && defined(_TITLE))\n#pragma warning(push)\n#pragma warning(disable: 4471 5204)\n#include <Windows.UI.Core.h>\n#pragma warning(pop)\n#endif\n\n#define _XM_NO_XMVECTOR_OVERLOADS_\n\n#include <DirectXMath.h>\n#include <DirectXPackedVector.h>\n#include <DirectXCollision.h>\n\n#include <algorithm>\n#include <atomic>\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <exception>\n#include <initializer_list>\n#include <iterator>\n#include <list>\n#include <map>\n#include <memory>\n#include <mutex>\n#include <set>\n#include <stdexcept>\n#include <string>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#pragma warning(push)\n#pragma warning(disable : 5204 5220)\n#include <future>\n#pragma warning(pop)\n\n#pragma warning(push)\n#pragma warning(disable : 4702)\n#include <functional>\n#pragma warning(pop)\n\n#include <malloc.h>\n\n#pragma warning(push)\n#pragma warning(disable : 4467 5038 5204 5220)\n#include <wrl.h>\n#pragma warning(pop)\n\n#include <wincodec.h>\n\n// DirectX Tool Kit for Audio is in all versions of DirectXTK12\n#include <mmreg.h>\n#include <Audioclient.h>\n\n#ifndef XAUDIO2_HELPER_FUNCTIONS\n#define XAUDIO2_HELPER_FUNCTIONS\n#endif\n\n#include <xaudio2.h>\n#include <xaudio2fx.h>\n#include <x3daudio.h>\n#include <xapofx.h>\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n#include <apu.h>\n#include <shapexmacontext.h>\n#include <xma2defs.h>\n#endif\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/DirectXTK12/Src/vbo.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: vbo.h\n//\n// The VBO file format was introduced in the Windows 8.0 ResourceLoading sample. It's\n// a simple binary file containing a 16-bit index buffer and a fixed-format vertex buffer.\n//\n// The meshconvert sample tool for DirectXMesh can produce this file type\n// http://go.microsoft.com/fwlink/?LinkID=324981\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <cstdint>\n\nnamespace VBO\n{\n#pragma pack(push,1)\n\n    struct header_t\n    {\n        uint32_t numVertices;\n        uint32_t numIndices;\n    };\n\n#pragma pack(pop)\n\n} // namespace\n\nstatic_assert(sizeof(VBO::header_t) == 8, \"VBO header size mismatch\");\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/LiveTK/LiveInfoHUD.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: LiveInfoHUD.cpp\n//\n// A Heads Up Display (HUD) for Xbox Live samples\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n#include \"pch.h\"\n#include \"LiveInfoHUD.h\"\n\n#include <XGame.h>\n#include <XSystem.h>\n\n#include \"DescriptorHeap.h\"\n#include \"DirectXHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"WICTextureLoader.h\"\n\n#include \"ATGColors.h\"\n#include \"FindMedia.h\"\n\nusing namespace ATG;\nusing namespace DirectX;\n\nnamespace\n{\n    const size_t c_GamerPicBuffer = 1024 * 16;\n}\n\n_Use_decl_annotations_\nLiveInfoHUD::LiveInfoHUD(char const* sampleTitle) noexcept(false) :\n    m_sampleTitle(sampleTitle),\n    m_gamerTag(\"No User Signed in\"),\n    m_scaleWidth(1.f),\n    m_scaleHeight(1.f),\n    m_gamerPicCPU{},\n    m_gamerPicGPU{},\n    m_gamerPicDataSize(0),\n    m_gamerPicReady(false)\n{\n\n}\n\nvoid LiveInfoHUD::Initialize(int windowWidth, int windowHeight)\n{\n    UNREFERENCED_PARAMETER(windowWidth);\n    UNREFERENCED_PARAMETER(windowHeight);\n\n    uint32_t titleId = {};\n    HRESULT hr = XGameGetXboxTitleId(&titleId);\n\n    if (SUCCEEDED(hr))\n    {\n        char hexTitleId[16] = {};\n        sprintf_s(hexTitleId, \"0x%08X\", titleId);\n        m_titleId.assign(hexTitleId);\n\n        char scidBuffer[64] = {};\n        sprintf_s(scidBuffer, \"00000000-0000-0000-0000-0000%08x\", titleId);\n        m_serviceConfigId = scidBuffer;\n    }\n    else\n    {\n        m_titleId = \"Not Set\";\n        m_serviceConfigId = \"Not Set\";\n    }\n\n    char sandboxId[XSystemXboxLiveSandboxIdMaxBytes] = {};\n    XSystemGetXboxLiveSandboxId(XSystemXboxLiveSandboxIdMaxBytes, sandboxId, nullptr);\n    m_sandboxId = sandboxId;\n}\n\nvoid LiveInfoHUD::Update(_In_ ID3D12CommandQueue* commandQueue)\n{\n    if (!m_gamerPicReady || !m_device)\n        return;\n\n    CreateShaderResourceView(m_device.Get(), m_gamerDefaultPic.Get(), m_gamerPicCPU);\n\n    if (m_gamerPicDataSize && m_gamerPicData)\n    {\n        ResourceUploadBatch upload(m_device.Get());\n\n        upload.Begin();\n\n        if (SUCCEEDED(CreateWICTextureFromMemory(m_device.Get(), upload, m_gamerPicData.get(), m_gamerPicDataSize, m_gamerPic.ReleaseAndGetAddressOf())))\n        {\n            CreateShaderResourceView(m_device.Get(), m_gamerPic.Get(), m_gamerPicCPU);\n        }\n\n        auto result = upload.End(commandQueue);\n        result.wait();\n    }\n\n    m_gamerPicReady = false;\n}\n\nvoid LiveInfoHUD::ReleaseDevice()\n{\n    m_gamerPic.Reset();\n    m_gamerDefaultPic.Reset();\n\n    m_device.Reset();\n\n    m_batch.reset();\n    m_smallFont.reset();\n    m_boldFont.reset();\n    m_titleFont.reset();\n\n    m_gamerPicCPU = {};\n    m_gamerPicGPU = {};\n}\n\n_Use_decl_annotations_\nvoid LiveInfoHUD::RestoreDevice(\n    ID3D12Device* device,\n    const RenderTargetState& renderTarget,\n    ResourceUploadBatch& resourceUpload,\n    DescriptorPile& pile)\n{\n    m_device = device;\n\n    SpriteBatchPipelineStateDescription pd(renderTarget);\n    m_batch = std::make_unique<SpriteBatch>(device, resourceUpload, pd);\n\n    wchar_t buff[MAX_PATH] = {};\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"SegoeUI_18.spritefont\");\n    size_t index = pile.Allocate();\n    m_smallFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"SegoeUI_18_Bold.spritefont\");\n    index = pile.Allocate();\n    m_boldFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"SegoeUI_36.spritefont\");\n    index = pile.Allocate();\n    m_titleFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"GamerPic.png\");\n    DX::ThrowIfFailed(\n        CreateWICTextureFromFile(device, resourceUpload, buff, m_gamerDefaultPic.ReleaseAndGetAddressOf())\n    );\n\n    index = pile.Allocate();\n    m_gamerPicCPU = pile.GetCpuHandle(index);\n    m_gamerPicGPU = pile.GetGpuHandle(index);\n\n    if (m_gamerPicDataSize > 0 && m_gamerPicData)\n    {\n        m_gamerPicReady = true;\n    }\n\n    CreateShaderResourceView(device, m_gamerDefaultPic.Get(), m_gamerPicCPU);\n}\n\n_Use_decl_annotations_\nvoid LiveInfoHUD::SetUser(XUserHandle user, XTaskQueueHandle queue)\n{\n    if (!user)\n    {\n        m_gamerTag = \"No User Signed in\";\n\n        m_gamerPicDataSize = 0;\n        m_gamerPicData.reset();\n\n        CreateShaderResourceView(m_device.Get(), m_gamerDefaultPic.Get(), m_gamerPicCPU);\n    }\n    else\n    {\n        m_gamerTag.resize(XUserGamertagComponentClassicMaxBytes);\n        if (FAILED(XUserGetGamertag(user, XUserGamertagComponent::Classic, XUserGamertagComponentClassicMaxBytes, &m_gamerTag[0], nullptr)))\n        {\n            m_gamerTag = \"***ERROR***\";\n        }\n\n        auto async = new XAsyncBlock{};\n        async->context = this;\n        async->queue = queue;\n        async->callback = [](XAsyncBlock *async)\n        {\n            auto pThis = reinterpret_cast<LiveInfoHUD*>(async->context);\n\n            pThis->m_gamerPicData.reset(new uint8_t[c_GamerPicBuffer]);\n            size_t bufferFilled = 0;\n\n            HRESULT hr = XUserGetGamerPictureResult(async, c_GamerPicBuffer, pThis->m_gamerPicData.get(), &bufferFilled);\n            if (SUCCEEDED(hr))\n            {\n                pThis->m_gamerPicDataSize = bufferFilled;\n                pThis->m_gamerPicReady = true;\n            }\n            else\n            {\n                pThis->m_gamerPicDataSize = 0;\n                pThis->m_gamerPicData.reset();\n            }\n\n            delete async;\n        };\n\n        DX::ThrowIfFailed(XUserGetGamerPictureAsync(user, XUserGamerPictureSize::Small, async));\n    }\n}\n\n_Use_decl_annotations_\nvoid LiveInfoHUD::Render(ID3D12GraphicsCommandList *commandList)\n{\n    m_batch->Begin(\n        commandList,\n        SpriteSortMode_Deferred,\n        DirectX::XMMatrixAffineTransformation2D(XMVectorSet(m_scaleWidth, m_scaleHeight, 0, 0), XMVectorZero(), 0.f, XMVectorZero())\n    );\n\n    m_titleFont->DrawString(m_batch.get(), m_sampleTitle.c_str(), XMFLOAT2(88.f, 44.f), ATG::Colors::OffWhite, 0.0f);\n\n    m_boldFont->DrawString(m_batch.get(), \"Sandbox Id:\", XMFLOAT2(270.f, 999.f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), m_sandboxId.c_str(), XMFLOAT2(410.f, 999.f), ATG::Colors::OffWhite, 0.0f);\n\n    m_boldFont->DrawString(m_batch.get(), \"Title Id:\", XMFLOAT2(590.f, 999.f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), m_titleId.c_str(), XMFLOAT2(680.f, 999.f), ATG::Colors::OffWhite, 0.0f);\n\n    m_boldFont->DrawString(m_batch.get(), \"Service Config Id:\", XMFLOAT2(950.f, 999.f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), m_serviceConfigId.c_str(), XMFLOAT2(1155.f, 999.f), ATG::Colors::OffWhite, 0.0f);\n\n    auto pos = XMFLOAT2(1770.f, 70.f);\n    pos.x -= XMVectorGetX(m_smallFont->MeasureString(m_gamerTag.c_str()));\n\n    m_smallFont->DrawString(m_batch.get(), m_gamerTag.c_str(), pos, ATG::Colors::OffWhite, 0.0f);\n\n    static const RECT gamerPicRect = { 1780, 55, 1780 + 64, 55 + 64 };\n\n    m_batch->Draw(m_gamerPicGPU, XMUINT2(64, 64), gamerPicRect);\n\n    m_batch->End();\n}\n\nvoid LiveInfoHUD::SetViewport(const D3D12_VIEWPORT &viewport)\n{\n    if (m_batch)\n    {\n        m_batch->SetViewport(viewport);\n        SetWindowSize(viewport.Width, viewport.Height);\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/LiveTK/LiveInfoHUD.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: LiveInfoHUD.h\n//\n// A Heads Up Display (HUD) for Xbox Live samples\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n#pragma once\n\n#include <atomic>\n#include <memory>\n#include <string>\n\n#include <XUser.h>\n\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\nnamespace ATG\n{\n    class LiveInfoHUD\n    {\n    public:\n        explicit LiveInfoHUD(_In_ char const* sampleTitle) noexcept(false);\n\n        LiveInfoHUD(LiveInfoHUD&&) = delete;\n        LiveInfoHUD& operator= (LiveInfoHUD&&) = delete;\n\n        LiveInfoHUD(LiveInfoHUD const&) = delete;\n        LiveInfoHUD& operator= (LiveInfoHUD const&) = delete;\n\n        void Initialize(int windowWidth = 0, int windowHeight = 0);\n\n        void Update(_In_ ID3D12CommandQueue* commandQueue);\n\n        void ReleaseDevice();\n        void RestoreDevice(_In_ ID3D12Device* context,\n                           const DirectX::RenderTargetState& renderTarget,\n                           DirectX::ResourceUploadBatch& resourceUpload,\n                           DirectX::DescriptorPile& pile);\n\n        void SetUser(_In_opt_ XUserHandle user, _In_ XTaskQueueHandle queue);\n\n        void Render(_In_ ID3D12GraphicsCommandList *commandList);\n\n        void SetViewport(const D3D12_VIEWPORT &viewport);\n\n        void SetWindowSize(float width, float height) { m_scaleWidth = width / LAYOUT_PIXEL_WIDTH, m_scaleHeight = height / LAYOUT_PIXEL_HEIGHT; }\n\n    private:\n        const float                            LAYOUT_PIXEL_WIDTH  = 1920.f;\n        const float                            LAYOUT_PIXEL_HEIGHT = 1080.f;\n\n        std::string                            m_sampleTitle;\n        std::string                            m_serviceConfigId;\n        std::string                            m_titleId;\n        std::string                            m_sandboxId;\n        std::string                            m_gamerTag;\n        Microsoft::WRL::ComPtr<ID3D12Resource> m_gamerPic;\n        Microsoft::WRL::ComPtr<ID3D12Resource> m_gamerDefaultPic;\n\n        Microsoft::WRL::ComPtr<ID3D12Device>   m_device;\n\n        // Direct3D resources\n        std::unique_ptr<DirectX::SpriteBatch>  m_batch;\n        std::unique_ptr<DirectX::SpriteFont>   m_smallFont;\n        std::unique_ptr<DirectX::SpriteFont>   m_boldFont;\n        std::unique_ptr<DirectX::SpriteFont>   m_titleFont;\n        \n        float                                  m_scaleWidth;\n        float                                  m_scaleHeight;\n\n        D3D12_CPU_DESCRIPTOR_HANDLE            m_gamerPicCPU;\n        D3D12_GPU_DESCRIPTOR_HANDLE            m_gamerPicGPU;\n        std::unique_ptr<uint8_t>               m_gamerPicData;\n        size_t                                 m_gamerPicDataSize;\n        std::atomic<bool>                      m_gamerPicReady;\n    };\n}"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/LiveTK/LiveResources.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: LiveResources.cpp\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright(c) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n\n#include \"LiveResources.h\"\n\n#include <XGame.h>\n#include <XGameRuntimeFeature.h>\n#include <XGameUI.h>\n#include <XSystem.h>\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#pragma clang diagnostic ignored \"-Wsign-conversion\"\n#endif\n\n#pragma warning(disable : 4061 4365)\n\n#ifdef _GAMING_XBOX\n#include <ws2def.h>\n#include <ws2ipdef.h>\n#include <iphlpapi.h>\n#endif\n\nusing namespace ATG;\n\nnamespace\n{\n    // This is a rare error that is not exposed externally because it doesn't happen in retail scenarios\n    constexpr long XO_E_CONTENT_ISOLATION = 0x8015DC12;\n}\n\n_Use_decl_annotations_\nLiveResources::LiveResources(XTaskQueueHandle queue, bool autoManageUser, bool isGuestUserAllowed) noexcept(false):\n#ifdef _GAMING_XBOX\n    m_networkConnectivityChangedHandle{},\n#endif\n    m_isNetworkAvailable(false),\n    m_autoManageUser(autoManageUser),\n    m_isGuestUserAllowed(isGuestUserAllowed),\n    m_asyncQueue{},\n    m_userChangedEventToken{},\n    m_xboxLiveContext{},\n    m_xboxLiveUser{},\n    m_xuid{},\n    m_titleId{}\n{\n    HRESULT hr;\n\n    if (queue)\n    {\n        XTaskQueueDuplicateHandle(queue, &m_asyncQueue);\n    }\n    else\n    {\n        hr = XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::ThreadPool, &m_asyncQueue);\n        DX::ThrowIfFailed(hr);\n    }\n\n    XGameGetXboxTitleId(&m_titleId);\n\n    char hexTitleId[16] = {};\n    sprintf_s(hexTitleId, \"0x%08X\", m_titleId);\n    m_titleIdHex.assign(hexTitleId);\n\n    char scidBuffer[64] = {};\n    sprintf_s(scidBuffer, \"00000000-0000-0000-0000-0000%08x\", m_titleId);\n    m_scid = scidBuffer;\n\n#ifdef _GAMING_XBOX\n    if (XGameRuntimeIsFeatureAvailable(XGameRuntimeFeature::XNetworking))\n    {\n        // Listen for network connectivity changes\n        NotifyNetworkConnectivityHintChange(\n            [](void* context, NL_NETWORK_CONNECTIVITY_HINT connectivityHint)\n            {\n                auto liveResources = static_cast<LiveResources*>(context);\n            \n                liveResources->m_isNetworkAvailable =\n                    connectivityHint.ConnectivityLevel != NL_NETWORK_CONNECTIVITY_LEVEL_HINT::NetworkConnectivityLevelHintUnknown;\n            }, // Callback function\n            this,                                   // Context object\n            true,                                   // Notify immediately with the current status\n            &m_networkConnectivityChangedHandle     // Notification handle\n        );\n    }\n    else\n#endif\n    {\n        // Assume network stack is ready on desktop\n        m_isNetworkAvailable = true;\n    }\n}\n\nLiveResources::~LiveResources()\n{\n#ifdef _GAMING_XBOX\n    if (m_networkConnectivityChangedHandle)\n    {\n        CancelMibChangeNotify2(m_networkConnectivityChangedHandle);\n    }\n#endif\n\n    if (m_asyncQueue)\n    {\n        XTaskQueueCloseHandle(m_asyncQueue);\n        m_asyncQueue = nullptr;\n    }\n}\n\nvoid LiveResources::Initialize()\n{\n    XUserRegisterForChangeEvent(m_asyncQueue, this, [](void *context, const XUserLocalId userLocalId, XUserChangeEvent event) \n    {\n        auto pThis = reinterpret_cast<LiveResources*>(context);\n\n        switch (event)\n        {\n        case XUserChangeEvent::SignedInAgain:\n            pThis->OnSignIn(userLocalId);\n            break;\n        case XUserChangeEvent::SignedOut:\n            pThis->OnSignOutCompleted(userLocalId);\n            break;\n        default:\n            break;\n        }\n\n    }, &m_userChangedEventToken);\n\n    if (m_autoManageUser)\n    {\n        SignInSilently();\n    }\n}\n\nvoid LiveResources::Refresh()\n{\n}\n\nvoid LiveResources::SetCurrentUser(XUserHandle user)\n{\n    if (!user)\n    {\n        if (m_xboxLiveContext)\n        {\n            XblContextCloseHandle(m_xboxLiveContext);\n            m_xboxLiveContext = nullptr;\n        }\n        if (m_xboxLiveUser)\n        {\n            XUserCloseHandle(m_xboxLiveUser);\n            m_xboxLiveUser = nullptr;\n        }\n        m_gamertag.clear();\n        m_xuid = 0;\n    }\n    else if ((user && !m_xboxLiveUser) || !XUserCompare(user, m_xboxLiveUser))\n    {\n        if (m_xboxLiveUser)\n        {\n            XUserCloseHandle(m_xboxLiveUser);\n            m_xboxLiveUser = nullptr;\n        }\n\n        m_xboxLiveUser = user;\n\n        char gamertag[XUserGamertagComponentClassicMaxBytes] = {};\n\n        auto result = XUserGetGamertag(user, XUserGamertagComponent::Classic, XUserGamertagComponentClassicMaxBytes, gamertag, nullptr);\n\n        if (SUCCEEDED(result))\n        {\n            m_gamertag = gamertag;\n        }\n        else\n        {\n            HandleError(result);\n        }\n\n        result = XUserGetId(user, &m_xuid);\n\n        if (FAILED(result))\n        {\n            HandleError(result);\n        }\n\n        InitializeXboxServices();\n\n        if (m_onUserChangedCallback)\n        {\n            m_onUserChangedCallback(user);\n        }\n    }\n    else\n    {\n        XUserCloseHandle(user);\n    }\n}\n\nvoid LiveResources::OnSignOutCompleted(const XUserLocalId localId)\n{\n    XUserHandle user = nullptr;\n    XUserFindUserByLocalId(localId, &user);\n\n    if (!XUserCompare(user, m_xboxLiveUser))\n    {\n        SetCurrentUser(nullptr);\n\n        if (m_onUserSignOutCompletedCallback)\n        {\n            m_onUserSignOutCompletedCallback(user);\n        }\n\n        if (m_autoManageUser)\n        {\n            SignInSilently();\n        }\n    }\n}\n\nvoid LiveResources::OnSignIn(const XUserLocalId localId)\n{\n    XUserHandle user = nullptr;\n    XUserFindUserByLocalId(localId, &user);\n\n    if ((user && !m_xboxLiveUser) || !XUserCompare(user, m_xboxLiveUser))\n    {\n        SetCurrentUser(user);\n\n        if (m_onUserChangedCallback)\n        {\n            m_onUserChangedCallback(user);\n        }\n    }\n}\n\nvoid LiveResources::SignInSilently()\n{\n    auto async = new XAsyncBlock{};\n    async->queue = m_asyncQueue;\n    async->context = this;\n    async->callback = [](XAsyncBlock* async)\n    {\n        auto pThis = reinterpret_cast<LiveResources*>(async->context);\n\n        XUserHandle user = nullptr;\n\n        HRESULT result = XUserAddResult(async, &user);\n        if (SUCCEEDED(result))\n        {\n            pThis->SetCurrentUser(user);\n        }\n        else\n        {\n            if (result == XO_E_CONTENT_ISOLATION)\n            {\n                // The user doesn't exist in current sandbox and cannot be logged in.\n                // This is a case that really only exists when running samples on PC where\n                // the user might already be logged in as a user in the RETAIL sandbox then\n                // switches to a sample-specific sandbox without logging in a different user\n                // Propagate an error which is handled by samples\n                pThis->HandleError(E_GAMEUSER_RESOLVE_USER_ISSUE_REQUIRED);\n            }\n            else\n            {\n                pThis->HandleError(result);\n            }\n        }\n        \n        delete async;\n    };\n\n    HRESULT hr = XUserAddAsync(XUserAddOptions::AddDefaultUserSilently, async);\n\n    if (FAILED(hr))\n    {\n        delete async;\n        HandleError(hr);\n    }\n}\n\nvoid LiveResources::SignInWithUI()\n{\n    auto async = new XAsyncBlock{};\n    async->queue = m_asyncQueue;\n    async->context = this;\n    async->callback = [](XAsyncBlock* async)\n    {\n        auto pThis = reinterpret_cast<LiveResources*>(async->context);\n\n        XUserHandle user = nullptr;\n        auto result = XUserAddResult(async, &user);\n\n        if (SUCCEEDED(result))\n        {\n            pThis->SetCurrentUser(user);\n        }\n        else\n        {\n            pThis->HandleError(result);\n        }\n\n        delete async;\n    };\n\n    HRESULT hr = XUserAddAsync(XUserAddOptions::AllowGuests, async);\n\n    if (FAILED(hr))\n    {\n        delete async;\n        HandleError(hr);\n    }\n}\n\nvoid LiveResources::HandleError(HRESULT error)\n{\n    if (m_errorHandler)\n    {\n        m_errorHandler(error);\n    }\n}\n\nvoid LiveResources::InitializeXboxServices()\n{\n    if (m_xboxLiveUser)\n    {\n        if (m_xboxLiveContext)\n        {\n            XblContextCloseHandle(m_xboxLiveContext);\n        }\n\n        auto result = XblContextCreateHandle(m_xboxLiveUser, &m_xboxLiveContext);\n\n        if (FAILED(result))\n        {\n            HandleError(result);\n            m_xboxLiveContext = nullptr;\n        }\n    }\n    else if (m_xboxLiveContext)\n    {\n        XblContextCloseHandle(m_xboxLiveContext);\n        m_xboxLiveContext = nullptr;\n    }\n}\n\nbool LiveResources::IsUserSignedIn(XUserHandle user)\n{\n    XUserState state = XUserState::SignedOut;\n    XUserGetState(user, &state);\n    return state == XUserState::SignedIn;\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/LiveTK/LiveResources.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: LiveResources.h\n//\n// Handles Users signing in and out and the related Xbox Live Contexts\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n#pragma once\n\n#include <functional>\n#include <string>\n\n#include <stdint.h>\n\n#include <xsapi-c/services_c.h>\n\n#include <XUser.h>\n#include <XTaskQueue.h>\n\nnamespace ATG\n{\n    class LiveResources : public std::enable_shared_from_this<LiveResources>\n    {\n    public:\n        // Constructor Paramters:\n        //   autoManageUser:\n        //     1) sets current user to the first user it finds upon calling Initialize()\n        //     2) switches to new users as they sign in\n        //     3) attempts to find another signed in user when current user signs out\n        //   isGuestUserAllowed: when true, guest users are valid users to use in auto user management or when resuming from suspend\n        explicit LiveResources(_In_opt_ XTaskQueueHandle queue = nullptr, bool autoManageUser = true, bool isGuestUserAllowed = false) noexcept(false);\n\n        LiveResources(LiveResources&&) = default;\n        LiveResources& operator= (LiveResources&&) = default;\n\n        LiveResources(LiveResources const&) = delete;\n        LiveResources& operator= (LiveResources const&) = delete;\n\n        ~LiveResources();\n\n        void Initialize();\n        void Refresh(); // call when resuming from suspend\n\n        bool               IsNetworkAvailable() const { return m_isNetworkAvailable; }\n        const std::string& GetGamertag()        const { return m_gamertag; }\n        XblContextHandle   GetLiveContext()     const { return m_xboxLiveContext; }\n        const std::string& GetSandbox()         const { return m_sandbox; }\n        const std::string& GetServiceConfigId() const { return m_scid; }\n        uint32_t           GetTitleId()         const { return m_titleId; }\n        const std::string& GetTitleIdHex()      const { return m_titleIdHex; }\n        XalUserHandle      GetUser()            const { return m_xboxLiveUser; }\n        uint64_t           GetXuid()            const { return m_xuid; }\n        bool               IsUserSignedIn()     const { return m_xboxLiveUser && IsUserSignedIn(m_xboxLiveUser); }\n\n        XTaskQueueHandle GetAsyncQueue()        const { return m_asyncQueue; }\n\n        void SetCurrentUser(XUserHandle user); // typically not needed when using auto user management\n        void SetUserChangedCallback(std::function<void(XUserHandle)> callback) { m_onUserChangedCallback = callback; }\n        void SetUserSignOutCompletedCallback(std::function<void(XUserHandle)> callback) { m_onUserSignOutCompletedCallback = callback; }\n        void SetErrorHandler(std::function<void(HRESULT)> callback) { m_errorHandler = callback; }\n\n        static bool IsUserSignedIn (XUserHandle user);\n        bool        IsGuestAllowed() const { return m_isGuestUserAllowed; }\n\n        void SignInSilently();\n        void SignInWithUI();\n    private:\n        // Event Handlers\n        void OnSignOutCompleted(const XUserLocalId user);\n        void OnSignIn(const XUserLocalId user);\n\n\n        void HandleError(HRESULT error);\n        void InitializeXboxServices();\n\n#ifdef _GAMING_XBOX\n        HANDLE                             m_networkConnectivityChangedHandle;\n#endif\n        bool                               m_isNetworkAvailable;\n\n        bool                               m_autoManageUser;\n        bool                               m_isGuestUserAllowed;\n\n        XTaskQueueHandle                   m_asyncQueue;\n        XTaskQueueRegistrationToken        m_userChangedEventToken;\n\n        // User Info\n        std::string                        m_gamertag;\n        XblContextHandle                   m_xboxLiveContext;\n        XUserHandle                        m_xboxLiveUser;\n        uint64_t                           m_xuid;\n\n        // Title Info\n        std::string                        m_sandbox;\n        std::string                        m_scid;\n        uint32_t                           m_titleId;\n        std::string                        m_titleIdHex;\n\n        // Callbacks\n        std::function<void(XUserHandle)>   m_onUserChangedCallback;\n        std::function<void(XUserHandle)>   m_onUserSignOutCompletedCallback;\n        std::function<void(HRESULT)>       m_errorHandler;\n    };\n}"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/LiveTK/UITwist.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: UITwist.cpp\n//\n// A wrapper to make a Twist Menu\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n#include \"pch.h\"\n#include \"SampleGUI.h\"\n#include \"UITwist.h\"\n\nUITwist::UITwist(ATG::UIManager *ui, unsigned parentPanel, unsigned twistStart, const std::vector<std::wstring> &options) :\n    m_options(options), m_currentIndex(0)\n{\n    m_previous = ui->FindControl<ATG::TextLabel>(parentPanel, twistStart);\n    m_current = ui->FindControl<ATG::TextLabel>(parentPanel, twistStart + 1);\n    m_next = ui->FindControl<ATG::TextLabel>(parentPanel, twistStart + 2);\n\n    Update();\n}\n\nint UITwist::MoveNext()\n{\n    m_currentIndex++;\n    if (m_currentIndex == static_cast<int>(m_options.size()))\n        m_currentIndex = 0;\n    Update();\n    return m_currentIndex;\n}\nint UITwist::MovePrevious()\n{\n    m_currentIndex--;\n    if (m_currentIndex == -1)\n        m_currentIndex = static_cast<int>(m_options.size()) - 1;\n    Update();\n    return m_currentIndex;\n}\nvoid UITwist::Update()\n{\n    int previous = m_currentIndex - 1;\n    int next = m_currentIndex + 1;\n\n    if (next >= static_cast<int>(m_options.size()))\n    {\n        next = 0;\n    }\n    if (previous < 0)\n    {\n        previous = static_cast<int>(m_options.size()) - 1;\n    }\n\n    m_previous->SetText(m_options[size_t(previous)].c_str());\n    m_current->SetText(m_options[size_t(m_currentIndex)].c_str());\n    m_next->SetText(m_options[size_t(next)].c_str());\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Kits/LiveTK/UITwist.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: UITwist.h\n//\n// A wrapper to make a Twist Menu\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n#pragma once\n\nnamespace ATG\n{\n    class UIManager;\n    class TextLabel;\n}\n\nclass UITwist\n{\npublic:\n    UITwist(ATG::UIManager *ui, unsigned parentPanel, unsigned twistStart, const std::vector<std::wstring> &options);\n\n    int MoveNext();\n    int MovePrevious();\n    int CurrentIndex() const { return m_currentIndex; }\nprivate:\n    void Update();\n\n    std::vector<std::wstring> m_options;\n    int             m_currentIndex;\n    ATG::TextLabel *m_previous;\n    ATG::TextLabel *m_current;\n    ATG::TextLabel *m_next;\n};"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/Main.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// Main.cpp\n//\n// Entry point for Microsoft Game Development Kit\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"APIRunner.GDK.h\"\n\n#include <appnotify.h>\n#include <XGameRuntimeInit.h>\n#include <XGameErr.h>\n\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( push )\n#pragma warning( disable : 4365 )\n#pragma warning( disable : 4061 )\n#pragma warning( disable : 4996 )\n#endif\n#include <rapidjson/document.h>\n#if HC_PLATFORM_IS_MICROSOFT\n#pragma warning( pop )\n#endif\n\n#ifdef ATG_ENABLE_TELEMETRY\n#include \"ATGTelemetry.h\"\n#endif\n\nusing namespace DirectX;\n\nnamespace\n{\n    std::unique_ptr<Sample> g_sample;\n#ifdef _GAMING_XBOX\n    HANDLE g_plmSuspendComplete = nullptr;\n    HANDLE g_plmSignalResume = nullptr;\n#endif\n};\n\nLPCWSTR g_szAppName = L\"APIRunner.GDK\";\n\nLRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);\n\n// Entry point\nint WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)\n{\n    UNREFERENCED_PARAMETER(lpCmdLine);\n\n    if (!XMVerifyCPUSupport())\n    {\n#ifdef _DEBUG\n        OutputDebugStringA(\"ERROR: This hardware does not support the required instruction set.\\n\");\n#if defined(_GAMING_XBOX) && defined(__AVX2__)\n        OutputDebugStringA(\"This may indicate a Gaming.Xbox.Scarlett.x64 binary is being run on an Xbox One.\\n\");\n#endif\n#endif\n        return 1;\n    }\n\n    // Initialize COM for WIC usage\n    if (FAILED(CoInitializeEx(nullptr, COINITBASE_MULTITHREADED)))\n        return 1;\n\n    HRESULT hr = XGameRuntimeInitialize();\n    if (FAILED(hr))\n    {\n        if (hr == E_GAMERUNTIME_DLL_NOT_FOUND || hr == E_GAMERUNTIME_VERSION_MISMATCH)\n        {\n#ifdef _GAMING_DESKTOP\n            (void)MessageBoxW(nullptr, L\"Game Runtime is not installed on this system or needs updating.\", g_szAppName, MB_ICONERROR | MB_OK);\n#endif\n        }\n        return 1;\n    }\n\n#ifdef _GAMING_XBOX\n    // Default main thread to CPU 0\n    SetThreadAffinityMask(GetCurrentThread(), 0x1);\n#endif\n\n    g_sample = std::make_unique<Sample>();\n\n    // Register class and create window\n#ifdef _GAMING_XBOX\n    PAPPSTATE_REGISTRATION hPLM = {};\n#endif\n    {\n        // Register class\n        WNDCLASSEXW wcex = {};\n        wcex.cbSize = sizeof(WNDCLASSEXW);\n        wcex.style = CS_HREDRAW | CS_VREDRAW;\n        wcex.lpfnWndProc = WndProc;\n        wcex.hInstance = hInstance;\n        wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);\n        wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\n        wcex.lpszClassName = L\"APIRunner_GDKWindowClass\";\n        if (!RegisterClassExW(&wcex))\n            return 1;\n\n        // Create window\n#ifdef _GAMING_XBOX\n        RECT rc = { 0, 0, 1920, 1080 };\n#else\n        int w, h;\n        g_sample->GetDefaultSize(w, h);\n\n        RECT rc = { 0, 0, static_cast<LONG>(w), static_cast<LONG>(h) };\n        AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);\n#endif\n\n        HWND hwnd = CreateWindowExW(0, L\"APIRunner_GDKWindowClass\", g_szAppName, WS_OVERLAPPEDWINDOW,\n            CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,\n            nullptr);\n        if (!hwnd)\n            return 1;\n\n        ShowWindow(hwnd, nCmdShow);\n\n        SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_sample.get()));\n\n        // Sample Usage Telemetry\n        //\n        // Disable or remove this code block to opt-out of sample usage telemetry\n#ifdef ATG_ENABLE_TELEMETRY\n        ATG::SendLaunchTelemetry();\n#endif\n        GetClientRect(hwnd, &rc);\n\n        g_sample->m_cmdLine = lpCmdLine;\n        g_sample->Initialize(hwnd, rc.right - rc.left, rc.bottom - rc.top);\n\n#ifdef _GAMING_XBOX\n        g_plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);\n        g_plmSignalResume = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);\n        if (!g_plmSuspendComplete || !g_plmSignalResume)\n            return 1;\n\n        if (RegisterAppStateChangeNotification([](BOOLEAN quiesced, PVOID context)\n        {\n            if (quiesced)\n            {\n                ResetEvent(g_plmSuspendComplete);\n                ResetEvent(g_plmSignalResume);\n\n                // To ensure we use the main UI thread to process the notification, we self-post a message\n                PostMessage(reinterpret_cast<HWND>(context), WM_USER, 0, 0);\n\n                // To defer suspend, you must wait to exit this callback\n                (void)WaitForSingleObject(g_plmSuspendComplete, INFINITE);\n            }\n            else\n            {\n                SetEvent(g_plmSignalResume);\n            }\n        }, hwnd, &hPLM))\n            return 1;\n#endif\n    }\n\n    // Main message loop\n    MSG msg = {};\n    while (WM_QUIT != msg.message)\n    {\n        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))\n        {\n            TranslateMessage(&msg);\n            DispatchMessage(&msg);\n        }\n        else\n        {\n            g_sample->Tick();\n        }\n    }\n\n    g_sample.reset();\n\n#ifdef _GAMING_XBOX\n    UnregisterAppStateChangeNotification(hPLM);\n\n    CloseHandle(g_plmSuspendComplete);\n    CloseHandle(g_plmSignalResume);\n#endif\n\n    XGameRuntimeUninitialize();\n\n    CoUninitialize();\n\n    return (int)msg.wParam;\n}\n\n// Windows procedure\nLRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n{\n#ifdef _GAMING_DESKTOP\n    static bool s_in_sizemove = false;\n    static bool s_in_suspend = false;\n    static bool s_minimized = false;\n    static bool s_fullscreen = false;\n#endif\n\n    auto sample = reinterpret_cast<Sample*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));\n\n    switch (message)\n    {\n    case WM_ACTIVATEAPP:\n        if (sample)\n        {\n            Mouse::ProcessMessage(message, wParam, lParam);\n\n            if (wParam)\n            {\n                sample->OnActivated();\n            }\n            else\n            {\n                sample->OnDeactivated();\n            }\n        }\n        break;\n\n\n#ifdef _GAMING_XBOX\n    case WM_USER:\n        if (sample)\n        {\n            sample->OnSuspending();\n\n            // Complete deferral\n            SetEvent(g_plmSuspendComplete);\n\n            (void)WaitForSingleObject(g_plmSignalResume, INFINITE);\n\n            sample->OnResuming();\n        }\n        break;\n#else\n    case WM_PAINT:\n        if (s_in_sizemove && sample)\n        {\n            sample->Tick();\n        }\n        else\n        {\n            PAINTSTRUCT ps;\n            (void)BeginPaint(hWnd, &ps);\n            EndPaint(hWnd, &ps);\n        }\n        break;\n\n    case WM_MOVE:\n        if (sample)\n        {\n            sample->OnWindowMoved();\n        }\n        break;\n\n    case WM_SIZE:\n        if (wParam == SIZE_MINIMIZED)\n        {\n            if (!s_minimized)\n            {\n                s_minimized = true;\n                if (!s_in_suspend && sample)\n                    sample->OnSuspending();\n                s_in_suspend = true;\n            }\n        }\n        else if (s_minimized)\n        {\n            s_minimized = false;\n            if (s_in_suspend && sample)\n                sample->OnResuming();\n            s_in_suspend = false;\n        }\n        else if (!s_in_sizemove && sample)\n        {\n            sample->OnWindowSizeChanged(LOWORD(lParam), HIWORD(lParam));\n        }\n        break;\n\n    case WM_ENTERSIZEMOVE:\n        s_in_sizemove = true;\n        break;\n\n    case WM_EXITSIZEMOVE:\n        s_in_sizemove = false;\n        if (sample)\n        {\n            RECT rc;\n            GetClientRect(hWnd, &rc);\n\n            sample->OnWindowSizeChanged(rc.right - rc.left, rc.bottom - rc.top);\n        }\n        break;\n\n    case WM_GETMINMAXINFO:\n    {\n        auto info = reinterpret_cast<MINMAXINFO*>(lParam);\n        info->ptMinTrackSize.x = 320;\n        info->ptMinTrackSize.y = 200;\n    }\n    break;\n\n    case WM_POWERBROADCAST:\n        switch (wParam)\n        {\n        case PBT_APMQUERYSUSPEND:\n            if (!s_in_suspend && sample)\n                sample->OnSuspending();\n            s_in_suspend = true;\n            return TRUE;\n\n        case PBT_APMRESUMESUSPEND:\n            if (!s_minimized)\n            {\n                if (s_in_suspend && sample)\n                    sample->OnResuming();\n                s_in_suspend = false;\n            }\n            return TRUE;\n        }\n        break;\n\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        break;\n\n    case WM_INPUT:\n    case WM_MOUSEMOVE:\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n    case WM_MOUSEWHEEL:\n    case WM_XBUTTONDOWN:\n    case WM_XBUTTONUP:\n    case WM_MOUSEHOVER:\n        Mouse::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYUP:\n        Keyboard::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_SYSKEYDOWN:\n        if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000)\n        {\n            // Implements the classic ALT+ENTER fullscreen toggle\n            if (s_fullscreen)\n            {\n                SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);\n                SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0);\n\n                int width = 800;\n                int height = 600;\n                if (sample)\n                    sample->GetDefaultSize(width, height);\n\n                ShowWindow(hWnd, SW_SHOWNORMAL);\n\n                SetWindowPos(hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);\n            }\n            else\n            {\n                SetWindowLongPtr(hWnd, GWL_STYLE, 0);\n                SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);\n\n                SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);\n\n                ShowWindow(hWnd, SW_SHOWMAXIMIZED);\n            }\n\n            s_fullscreen = !s_fullscreen;\n        }\n        Keyboard::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_MENUCHAR:\n        // A menu is active and the user presses a key that does not correspond\n        // to any mnemonic or accelerator key. Ignore so we don't produce an error beep.\n        return MAKELRESULT(0, MNC_CLOSE);\n#endif\n    }\n\n    return DefWindowProc(hWnd, message, wParam, lParam);\n}\n\n// Exit helper\nvoid ExitSample()\n{\n    PostQuitMessage(0);\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/MicrosoftGame.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Game configVersion=\"1\">\n\n    <Identity Name=\"41336MicrosoftATG.XboxLiveE2E\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.7.0.0\" />\n    \n    <ExecutableList>\n        <Executable Name=\"APIRunner.GDK.Src.exe\" Id=\"Game1\"/>\n    </ExecutableList>\n\n    <MSAFullTrust>false</MSAFullTrust>\n    <MSAAppId>000000004C26FED0</MSAAppId>\n    <TitleId>76029B4D</TitleId>\n    <PersistentLocalStorage>\n        <SizeMB>1024</SizeMB>\n    </PersistentLocalStorage>\n\n    <ShellVisuals\n            DefaultDisplayName=\"APIRunner Src GDK Desktop Sample\"\n            PublisherDisplayName=\"Xbox Advanced Technology Group\"\n            Description=\"InGameStore Desktop Sample\"\n            Square150x150Logo=\"Assets\\Logo.png\"\n            Square44x44Logo=\"Assets\\SmallLogo.png\"\n            BackgroundColor=\"#000000\"\n            SplashScreenImage=\"Assets\\SplashScreen.png\"\n            StoreLogo=\"Assets\\StoreLogo.png\"\n    />\n\n</Game>\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/StepTimer.h",
    "content": "//\n// StepTimer.h - A simple timer that provides elapsed time information\n//\n\n#pragma once\n\n#include <cmath>\n#include <exception>\n#include <stdint.h>\n\nnamespace DX\n{\n    // Helper class for animation and simulation timing.\n    class StepTimer\n    {\n    public:\n        StepTimer() noexcept(false) :\n            m_elapsedTicks(0),\n            m_totalTicks(0),\n            m_leftOverTicks(0),\n            m_frameCount(0),\n            m_framesPerSecond(0),\n            m_framesThisSecond(0),\n            m_qpcSecondCounter(0),\n            m_isFixedTimeStep(false),\n            m_targetElapsedTicks(TicksPerSecond / 60)\n        {\n            if (!QueryPerformanceFrequency(&m_qpcFrequency))\n            {\n                throw std::exception( \"QueryPerformanceFrequency\" );\n            }\n\n            if (!QueryPerformanceCounter(&m_qpcLastTime))\n            {\n                throw std::exception( \"QueryPerformanceCounter\" );\n            }\n\n            // Initialize max delta to 1/10 of a second.\n            m_qpcMaxDelta = static_cast<uint64_t>(m_qpcFrequency.QuadPart / 10);\n        }\n\n        // Get elapsed time since the previous Update call.\n        uint64_t GetElapsedTicks() const\t\t\t\t\t{ return m_elapsedTicks; }\n        double GetElapsedSeconds() const\t\t\t\t\t{ return TicksToSeconds(m_elapsedTicks); }\n\n        // Get total time since the start of the program.\n        uint64_t GetTotalTicks() const\t\t\t\t\t\t{ return m_totalTicks; }\n        double GetTotalSeconds() const\t\t\t\t\t\t{ return TicksToSeconds(m_totalTicks); }\n\n        // Get total number of updates since start of the program.\n        uint32_t GetFrameCount() const\t\t\t\t\t\t{ return m_frameCount; }\n\n        // Get the current framerate.\n        uint32_t GetFramesPerSecond() const\t\t\t\t\t{ return m_framesPerSecond; }\n\n        // Set whether to use fixed or variable timestep mode.\n        void SetFixedTimeStep(bool isFixedTimestep)\t\t\t{ m_isFixedTimeStep = isFixedTimestep; }\n\n        // Set how often to call Update when in fixed timestep mode.\n        void SetTargetElapsedTicks(uint64_t targetElapsed)\t{ m_targetElapsedTicks = targetElapsed; }\n        void SetTargetElapsedSeconds(double targetElapsed)\t{ m_targetElapsedTicks = SecondsToTicks(targetElapsed); }\n\n        // Integer format represents time using 10,000,000 ticks per second.\n        static const uint64_t TicksPerSecond = 10000000;\n\n        static double TicksToSeconds(uint64_t ticks)\t\t{ return static_cast<double>(ticks) / TicksPerSecond; }\n        static uint64_t SecondsToTicks(double seconds)\t\t{ return static_cast<uint64_t>(seconds * TicksPerSecond); }\n\n        // After an intentional timing discontinuity (for instance a blocking IO operation)\n        // call this to avoid having the fixed timestep logic attempt a set of catch-up\n        // Update calls.\n\n        void ResetElapsedTime()\n        {\n            if (!QueryPerformanceCounter(&m_qpcLastTime))\n            {\n                throw std::exception(\"QueryPerformanceCounter\");\n            }\n\n            m_leftOverTicks = 0;\n            m_framesPerSecond = 0;\n            m_framesThisSecond = 0;\n            m_qpcSecondCounter = 0;\n        }\n\n        // Update timer state, calling the specified Update function the appropriate number of times.\n        template<typename TUpdate>\n        void Tick(const TUpdate& update)\n        {\n            // Query the current time.\n            LARGE_INTEGER currentTime;\n\n            if (!QueryPerformanceCounter(&currentTime))\n            {\n                throw std::exception( \"QueryPerformanceCounter\" );\n            }\n\n            uint64_t timeDelta = static_cast<uint64_t>(currentTime.QuadPart - m_qpcLastTime.QuadPart);\n\n            m_qpcLastTime = currentTime;\n            m_qpcSecondCounter += timeDelta;\n\n            // Clamp excessively large time deltas (e.g. after paused in the debugger).\n            if (timeDelta > m_qpcMaxDelta)\n            {\n                timeDelta = m_qpcMaxDelta;\n            }\n\n            // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.\n            timeDelta *= TicksPerSecond;\n            timeDelta /= static_cast<uint64_t>(m_qpcFrequency.QuadPart);\n\n            uint32_t lastFrameCount = m_frameCount;\n\n            if (m_isFixedTimeStep)\n            {\n                // Fixed timestep update logic\n\n                // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp\n                // the clock to exactly match the target value. This prevents tiny and irrelevant errors\n                // from accumulating over time. Without this clamping, a game that requested a 60 fps\n                // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually\n                // accumulate enough tiny errors that it would drop a frame. It is better to just round\n                // small deviations down to zero to leave things running smoothly.\n\n                if (static_cast<uint64_t>(std::abs(static_cast<int64_t>(timeDelta - m_targetElapsedTicks))) < TicksPerSecond / 4000)\n                {\n                    timeDelta = m_targetElapsedTicks;\n                }\n\n                m_leftOverTicks += timeDelta;\n\n                while (m_leftOverTicks >= m_targetElapsedTicks)\n                {\n                    m_elapsedTicks = m_targetElapsedTicks;\n                    m_totalTicks += m_targetElapsedTicks;\n                    m_leftOverTicks -= m_targetElapsedTicks;\n                    m_frameCount++;\n\n                    update();\n                }\n            }\n            else\n            {\n                // Variable timestep update logic.\n                m_elapsedTicks = timeDelta;\n                m_totalTicks += timeDelta;\n                m_leftOverTicks = 0;\n                m_frameCount++;\n\n                update();\n            }\n\n            // Track the current framerate.\n            if (m_frameCount != lastFrameCount)\n            {\n                m_framesThisSecond++;\n            }\n\n            if (m_qpcSecondCounter >= static_cast<uint64_t>(m_qpcFrequency.QuadPart))\n            {\n                m_framesPerSecond = m_framesThisSecond;\n                m_framesThisSecond = 0;\n                m_qpcSecondCounter %= static_cast<uint64_t>(m_qpcFrequency.QuadPart);\n            }\n        }\n\n    private:\n        // Source timing data uses QPC units.\n        LARGE_INTEGER m_qpcFrequency;\n        LARGE_INTEGER m_qpcLastTime;\n        uint64_t m_qpcMaxDelta;\n\n        // Derived timing data uses a canonical tick format.\n        uint64_t m_elapsedTicks;\n        uint64_t m_totalTicks;\n        uint64_t m_leftOverTicks;\n\n        // Members for tracking the framerate.\n        uint32_t m_frameCount;\n        uint32_t m_framesPerSecond;\n        uint32_t m_framesThisSecond;\n        uint64_t m_qpcSecondCounter;\n\n        // Members for configuring fixed timestep mode.\n        bool m_isFixedTimeStep;\n        uint64_t m_targetElapsedTicks;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/pch.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n\n// APIRunner itself (but not XSAPI lib) uses cpprestsdk on GDK platforms\n#include \"cpprestsdk_impl.h\"\n\n"
  },
  {
    "path": "Tests/GDK/APIRunner.GDK/pch.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#pragma once\n\n#include <winsdkver.h>\n#define _WIN32_WINNT 0x0A00\n#include <sdkddkver.h>\n\n// Use the C++ standard templated min/max\n#define NOMINMAX\n\n// DirectX apps don't need GDI\n#define NODRAWTEXT\n#define NOGDI\n#define NOBITMAP\n\n// Include <mcx.h> if you need this\n#define NOMCX\n\n// Include <winsvc.h> if you need this\n#define NOSERVICE\n\n// WinHelp is deprecated\n#define NOHELP\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n\n#include <Windows.h>\n\n#include <wrl/client.h>\n#include <wrl/event.h>\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#include <d3dx12_xs.h>\n#elif defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#include <d3dx12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgi1_6.h>\n\n#ifdef _DEBUG\n#include <dxgidebug.h>\n#endif\n\n#include \"d3dx12.h\"\n#endif\n\n#define _XM_NO_XMVECTOR_OVERLOADS_\n\n#include <DirectXMath.h>\n#include <DirectXColors.h>\n\n#include <algorithm>\n#include <exception>\n#include <map>\n#include <memory>\n#include <stdexcept>\n\n#include <assert.h>\n#include <stdio.h>\n\n#ifdef _GAMING_XBOX\n#include <pix3.h>\n#else\n// To use graphics markup events with the latest version of PIX, change this to include <pix3.h> \n// then add the NuGet package WinPixEventRuntime to the project. \n#include <pix.h>\n#endif\n#include <XGame.h>\n#include <XSystem.h>\n\n#include \"CommonStates.h\" \n#include \"DescriptorHeap.h\" \n#include \"DirectXHelpers.h\"\n#include \"GamePad.h\"\n#include \"GraphicsMemory.h\"\n#include \"Keyboard.h\"\n#include \"Mouse.h\"\n#include \"RenderTargetState.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\nnamespace DX\n{\n    // Helper class for COM exceptions\n    class com_exception : public std::exception\n    {\n    public:\n        com_exception(HRESULT hr) : result(hr) {}\n\n        virtual const char* what() const override\n        {\n            static char s_str[64] = {};\n            sprintf_s(s_str, \"Failure with HRESULT of %08X\", static_cast<unsigned int>(result));\n            return s_str;\n        }\n\n    private:\n        HRESULT result;\n    };\n\n    // Helper utility converts D3D API failures into exceptions.\n    inline void ThrowIfFailed(HRESULT hr)\n    {\n        if (FAILED(hr))\n        {\n            throw com_exception(hr);\n        }\n    }\n}\n\n#include \"pch_common.h\"\n#include \"runner.h\"\n\n// Enable off by default warnings to improve code conformance\n#pragma warning(default : 4061 4062 4191 4242 4263 4264 4265 4266 4289 4365 4746 4826 4841 4986 4987 5029 5038 5042)\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/Assets/SampleUI.csv",
    "content": "#ITEM,ID,X,Y,DX,DY,PARAMETERS\nOVERLAY,2000,0,0,1920,1080\nLEGEND,2001,82,850,525,300,[DPad] or Arrows - Select a scenario|[A] or Enter - Start a scenario|[Menu] or Tab - Sign in|[View] or Esc - Exit\nBUTTON,2101,82,300,525,50,AddUser\nBUTTON,2102,82,375,525,50,Get Achievement Status ID = 1\nBUTTON,2103,82,450,525,50,Complete Achievement ID = 1\nBUTTON,2104,82,525,525,50,Get Achievement Status ID = 2\nBUTTON,2105,82,600,525,50,Set Achievement ID = 2 -> 25%\nBUTTON,2106,82,675,525,50,Set Achievement ID = 2 -> 50%\nBUTTON,2107,82,750,525,50,Set Achievement ID = 2 -> 100%"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/DeviceResources.cpp",
    "content": "//\n// DeviceResources.cpp - A wrapper for the Direct3D 12/12.X device and swapchain\n//\n\n#include \"pch.h\"\n#include \"DeviceResources.h\"\n\nusing namespace DirectX;\nusing namespace DX;\n\nusing Microsoft::WRL::ComPtr;\n\n#ifdef _GAMING_DESKTOP\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#pragma clang diagnostic ignored \"-Wswitch-enum\"\n#endif\n\n#pragma warning(disable : 4061)\n\nnamespace\n{\n    inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:   return DXGI_FORMAT_R8G8B8A8_UNORM;\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:   return DXGI_FORMAT_B8G8R8A8_UNORM;\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:   return DXGI_FORMAT_B8G8R8X8_UNORM;\n        default:                                return fmt;\n        }\n    }\n}\n#endif\n\n// Constructor for DeviceResources.\nDeviceResources::DeviceResources(\n    DXGI_FORMAT backBufferFormat,\n    DXGI_FORMAT depthBufferFormat,\n    UINT backBufferCount) noexcept(false) :\n        m_backBufferIndex(0),\n        m_fenceValues{},\n#ifdef _GAMING_XBOX\n        m_framePipelineToken{},\n#endif\n        m_rtvDescriptorSize(0),\n        m_screenViewport{},\n        m_scissorRect{},\n        m_backBufferFormat(backBufferFormat),\n        m_depthBufferFormat(depthBufferFormat),\n        m_backBufferCount(backBufferCount),\n        m_window(nullptr),\n        m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_0),\n        m_outputSize{ 0, 0, 1, 1 },\n        m_deviceNotify(nullptr)\n{\n    if (backBufferCount < 2 || backBufferCount > MAX_BACK_BUFFER_COUNT)\n    {\n        throw std::out_of_range(\"invalid backBufferCount\");\n    }\n}\n\n// Destructor for DeviceResources.\nDeviceResources::~DeviceResources()\n{\n    // Ensure that the GPU is no longer referencing resources that are about to be destroyed.\n    WaitForGpu();\n\n#ifdef _GAMING_XBOX\n    // Ensure we present a blank screen before cleaning up resources.\n    if (m_commandQueue)\n    {\n        (void)m_commandQueue->PresentX(0, nullptr, nullptr);\n    }\n#endif\n}\n\n// Configures the Direct3D device, and stores handles to it and the device context.\nvoid DeviceResources::CreateDeviceResources()\n{\n#ifdef _GAMING_XBOX\n\n    // Create the DX12 API device object.\n    D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {};\n    params.Version = D3D12_SDK_VERSION;\n\n#if defined(_DEBUG)\n    // Enable the debug layer.\n    params.ProcessDebugFlags = D3D12_PROCESS_DEBUG_FLAG_DEBUG_LAYER_ENABLED;\n#elif defined(PROFILE)\n    // Enable the instrumented driver.\n    params.ProcessDebugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_INSTRUMENTED;\n#endif\n\n    params.GraphicsCommandQueueRingSizeBytes = static_cast<UINT>(D3D12XBOX_DEFAULT_SIZE_BYTES);\n    params.GraphicsScratchMemorySizeBytes = static_cast<UINT>(D3D12XBOX_DEFAULT_SIZE_BYTES);\n    params.ComputeScratchMemorySizeBytes = static_cast<UINT>(D3D12XBOX_DEFAULT_SIZE_BYTES);\n\n    HRESULT hr = D3D12XboxCreateDevice(\n        nullptr,\n        &params,\n        IID_GRAPHICS_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf()));\n#ifdef _DEBUG\n    if (hr == D3D12_ERROR_DRIVER_VERSION_MISMATCH)\n    {\n#ifdef _GAMING_XBOX_SCARLETT\n        OutputDebugStringA(\"ERROR: Running a d3d12_xs.lib (Xbox Series X|S) linked binary on an Xbox One is not supported\\n\");\n#else\n        OutputDebugStringA(\"ERROR: Running a d3d12_x.lib (Xbox One) linked binary on a Xbox Series X|S in 'Scarlett' mode is not supported\\n\");\n#endif\n    }\n#endif\n    ThrowIfFailed(hr);\n\n    m_d3dDevice->SetName(L\"DeviceResources\");\n\n    m_d3dFeatureLevel = D3D_FEATURE_LEVEL_12_0;\n\n#else // _GAMING_DESKTOP\n\n    DWORD dxgiFactoryFlags = 0;\n\n#if defined(_DEBUG)\n    // Enable the debug layer (requires the Graphics Tools \"optional feature\").\n    //\n    // NOTE: Enabling the debug layer after device creation will invalidate the active device.\n    {\n        ComPtr<ID3D12Debug> debugController;\n        if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf()))))\n        {\n            debugController->EnableDebugLayer();\n        }\n        else\n        {\n            OutputDebugStringA(\"WARNING: Direct3D Debug Device is not available\\n\");\n        }\n\n        ComPtr<IDXGIInfoQueue> dxgiInfoQueue;\n        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf()))))\n        {\n            dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG;\n\n            dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true);\n            dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true);\n\n            DXGI_INFO_QUEUE_MESSAGE_ID hide[] =\n            {\n                80 /* IDXGISwapChain::GetContainingOutput: The swapchain's adapter does not control the output on which the swapchain's window resides. */,\n            };\n            DXGI_INFO_QUEUE_FILTER filter = {};\n            filter.DenyList.NumIDs = static_cast<UINT>(std::size(hide));\n            filter.DenyList.pIDList = hide;\n            dxgiInfoQueue->AddStorageFilterEntries(DXGI_DEBUG_DXGI, &filter);\n        }\n    }\n#endif\n\n    ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));\n\n    ComPtr<IDXGIAdapter1> adapter;\n    GetAdapter(adapter.GetAddressOf());\n\n    // Create the DX12 API device object.\n    HRESULT hr = D3D12CreateDevice(\n        adapter.Get(),\n        D3D_FEATURE_LEVEL_11_0,\n        IID_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf())\n        );\n    ThrowIfFailed(hr);\n\n    m_d3dDevice->SetName(L\"DeviceResources\");\n\n#ifndef NDEBUG\n    // Configure debug device (if active).\n    ComPtr<ID3D12InfoQueue> d3dInfoQueue;\n    if (SUCCEEDED(m_d3dDevice.As(&d3dInfoQueue)))\n    {\n#ifdef _DEBUG\n        d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);\n        d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);\n#endif\n        D3D12_MESSAGE_ID hide[] =\n        {\n            D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE,\n            D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE,\n            // Workarounds for debug layer issues on hybrid-graphics systems\n            D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE,\n            D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE,\n        };\n        D3D12_INFO_QUEUE_FILTER filter = {};\n        filter.DenyList.NumIDs = static_cast<UINT>(std::size(hide));\n        filter.DenyList.pIDList = hide;\n        d3dInfoQueue->AddStorageFilterEntries(&filter);\n    }\n#endif\n\n    // Determine maximum supported feature level for this device\n    static const D3D_FEATURE_LEVEL s_featureLevels[] =\n    {\n#if defined(NTDDI_WIN10_FE) && (NTDDI_VERSION >= NTDDI_WIN10_FE)\n        D3D_FEATURE_LEVEL_12_2,\n#endif\n        D3D_FEATURE_LEVEL_12_1,\n        D3D_FEATURE_LEVEL_12_0,\n        D3D_FEATURE_LEVEL_11_1,\n        D3D_FEATURE_LEVEL_11_0,\n    };\n\n    D3D12_FEATURE_DATA_FEATURE_LEVELS featLevels =\n    {\n        static_cast<UINT>(std::size(s_featureLevels)), s_featureLevels, D3D_FEATURE_LEVEL_11_0\n    };\n\n    hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featLevels, sizeof(featLevels));\n    if (SUCCEEDED(hr))\n    {\n        m_d3dFeatureLevel = featLevels.MaxSupportedFeatureLevel;\n    }\n    else\n    {\n        m_d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0;\n    }\n\n#endif\n\n    // Create the command queue.\n    D3D12_COMMAND_QUEUE_DESC queueDesc = {};\n    queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n    queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;\n\n    ThrowIfFailed(m_d3dDevice->CreateCommandQueue(&queueDesc, IID_GRAPHICS_PPV_ARGS(m_commandQueue.ReleaseAndGetAddressOf())));\n\n    m_commandQueue->SetName(L\"DeviceResources\");\n\n    // Create descriptor heaps for render target views and depth stencil views.\n    D3D12_DESCRIPTOR_HEAP_DESC rtvDescriptorHeapDesc = {};\n    rtvDescriptorHeapDesc.NumDescriptors = m_backBufferCount;\n    rtvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;\n\n    ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&rtvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_rtvDescriptorHeap.ReleaseAndGetAddressOf())));\n\n    m_rtvDescriptorHeap->SetName(L\"DeviceResources\");\n\n    m_rtvDescriptorSize = m_d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);\n\n    if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)\n    {\n        D3D12_DESCRIPTOR_HEAP_DESC dsvDescriptorHeapDesc = {};\n        dsvDescriptorHeapDesc.NumDescriptors = 1;\n        dsvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;\n\n        ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&dsvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_dsvDescriptorHeap.ReleaseAndGetAddressOf())));\n\n        m_dsvDescriptorHeap->SetName(L\"DeviceResources\");\n    }\n\n    // Create a command allocator for each back buffer that will be rendered to.\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        ThrowIfFailed(m_d3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(m_commandAllocators[n].ReleaseAndGetAddressOf())));\n\n        wchar_t name[25] = {};\n        swprintf_s(name, L\"Render target %u\", n);\n        m_commandAllocators[n]->SetName(name);\n    }\n\n    // Create a command list for recording graphics commands.\n    ThrowIfFailed(m_d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[0].Get(), nullptr, IID_GRAPHICS_PPV_ARGS(m_commandList.ReleaseAndGetAddressOf())));\n    ThrowIfFailed(m_commandList->Close());\n\n    m_commandList->SetName(L\"DeviceResources\");\n\n    // Create a fence for tracking GPU execution progress.\n    ThrowIfFailed(m_d3dDevice->CreateFence(m_fenceValues[m_backBufferIndex], D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(m_fence.ReleaseAndGetAddressOf())));\n    m_fenceValues[m_backBufferIndex]++;\n\n    m_fence->SetName(L\"DeviceResources\");\n\n    m_fenceEvent.Attach(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));\n    if (!m_fenceEvent.IsValid())\n    {\n        throw std::system_error(std::error_code(static_cast<int>(GetLastError()), std::system_category()), \"CreateEventEx\");\n    }\n\n#ifdef _GAMING_XBOX\n    RegisterFrameEvents();\n#endif\n}\n\n// These resources need to be recreated every time the window size is changed.\nvoid DeviceResources::CreateWindowSizeDependentResources()\n{\n    if (!m_window)\n    {\n        throw std::logic_error(\"Call SetWindow with a valid Win32 window handle\");\n    }\n\n    // Wait until all previous GPU work is complete.\n    WaitForGpu();\n\n#ifdef _GAMING_XBOX\n    // Ensure we present a blank screen before cleaning up resources.\n    ThrowIfFailed(m_commandQueue->PresentX(0, nullptr, nullptr));\n#endif\n\n    // Release resources that are tied to the swap chain and update fence values.\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        m_renderTargets[n].Reset();\n        m_fenceValues[n] = m_fenceValues[m_backBufferIndex];\n    }\n\n    // Determine the render target size in pixels.\n    const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_outputSize.right - m_outputSize.left), 1u);\n    const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_outputSize.bottom - m_outputSize.top), 1u);\n\n#ifdef _GAMING_XBOX\n\n    // Obtain the back buffers for this window which will be the final render targets\n    // and create render target views for each of them.\n    CD3DX12_HEAP_PROPERTIES swapChainHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n    D3D12_RESOURCE_DESC swapChainBufferDesc = CD3DX12_RESOURCE_DESC::Tex2D(\n        m_backBufferFormat,\n        backBufferWidth,\n        backBufferHeight,\n        1, // This resource has only one texture.\n        1  // Use a single mipmap level.\n    );\n    swapChainBufferDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;\n\n    D3D12_CLEAR_VALUE swapChainOptimizedClearValue = {};\n    swapChainOptimizedClearValue.Format = m_backBufferFormat;\n\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        ThrowIfFailed(m_d3dDevice->CreateCommittedResource(\n            &swapChainHeapProperties,\n            D3D12_HEAP_FLAG_ALLOW_DISPLAY,\n            &swapChainBufferDesc,\n            D3D12_RESOURCE_STATE_PRESENT,\n            &swapChainOptimizedClearValue,\n            IID_GRAPHICS_PPV_ARGS(m_renderTargets[n].GetAddressOf())));\n\n        wchar_t name[25] = {};\n        swprintf_s(name, L\"Render target %u\", n);\n        m_renderTargets[n]->SetName(name);\n\n        D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};\n        rtvDesc.Format = m_backBufferFormat;\n        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;\n\n        CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(\n            m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),\n            static_cast<INT>(n), m_rtvDescriptorSize);\n        m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor);\n    }\n\n    // Reset the index to the current back buffer.\n    m_backBufferIndex = 0;\n\n#else // _GAMING_DESKTOP\n\n    DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat);\n\n    // If the swap chain already exists, resize it, otherwise create one.\n    if (m_swapChain)\n    {\n        // If the swap chain already exists, resize it.\n        HRESULT hr = m_swapChain->ResizeBuffers(\n            m_backBufferCount,\n            backBufferWidth,\n            backBufferHeight,\n            backBufferFormat,\n            0\n        );\n\n        if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)\n        {\n#ifdef _DEBUG\n            char buff[64] = {};\n            sprintf_s(buff, \"Device Lost on ResizeBuffers: Reason code 0x%08X\\n\",\n                static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));\n            OutputDebugStringA(buff);\n#endif\n            // If the device was removed for any reason, a new device and swap chain will need to be created.\n            HandleDeviceLost();\n\n            // Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method\n            // and correctly set up the new device.\n            return;\n        }\n        else\n        {\n            ThrowIfFailed(hr);\n        }\n    }\n    else\n    {\n        // Create a descriptor for the swap chain.\n        DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};\n        swapChainDesc.Width = backBufferWidth;\n        swapChainDesc.Height = backBufferHeight;\n        swapChainDesc.Format = backBufferFormat;\n        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n        swapChainDesc.BufferCount = m_backBufferCount;\n        swapChainDesc.SampleDesc.Count = 1;\n        swapChainDesc.SampleDesc.Quality = 0;\n        swapChainDesc.Scaling = DXGI_SCALING_STRETCH;\n        swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;\n        swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;\n\n        DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {};\n        fsSwapChainDesc.Windowed = TRUE;\n\n        // Create a swap chain for the window.\n        ComPtr<IDXGISwapChain1> swapChain;\n        ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd(\n            m_commandQueue.Get(),\n            m_window,\n            &swapChainDesc,\n            &fsSwapChainDesc,\n            nullptr,\n            swapChain.GetAddressOf()\n        ));\n\n        ThrowIfFailed(swapChain.As(&m_swapChain));\n\n        // This class does not support exclusive full-screen mode and prevents DXGI from responding to the ALT+ENTER shortcut\n        ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window, DXGI_MWA_NO_ALT_ENTER));\n    }\n\n    // Obtain the back buffers for this window which will be the final render targets\n    // and create render target views for each of them.\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(m_renderTargets[n].GetAddressOf())));\n\n        wchar_t name[25] = {};\n        swprintf_s(name, L\"Render target %u\", n);\n        m_renderTargets[n]->SetName(name);\n\n        D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};\n        rtvDesc.Format = m_backBufferFormat;\n        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;\n\n        CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor(\n            m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),\n            static_cast<INT>(n), m_rtvDescriptorSize);\n        m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor);\n    }\n\n    // Reset the index to the current back buffer.\n    m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex();\n\n#endif\n\n    if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)\n    {\n        // Allocate a 2-D surface as the depth/stencil buffer and create a depth/stencil view\n        // on this surface.\n        CD3DX12_HEAP_PROPERTIES depthHeapProperties(D3D12_HEAP_TYPE_DEFAULT);\n\n        D3D12_RESOURCE_DESC depthStencilDesc = CD3DX12_RESOURCE_DESC::Tex2D(\n            m_depthBufferFormat,\n            backBufferWidth,\n            backBufferHeight,\n            1, // This depth stencil view has only one texture.\n            1  // Use a single mipmap level.\n            );\n        depthStencilDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;\n\n        D3D12_CLEAR_VALUE depthOptimizedClearValue = {};\n        depthOptimizedClearValue.Format = m_depthBufferFormat;\n        depthOptimizedClearValue.DepthStencil.Depth = 1.0f;\n        depthOptimizedClearValue.DepthStencil.Stencil = 0;\n\n        ThrowIfFailed(m_d3dDevice->CreateCommittedResource(\n            &depthHeapProperties,\n            D3D12_HEAP_FLAG_NONE,\n            &depthStencilDesc,\n            D3D12_RESOURCE_STATE_DEPTH_WRITE,\n            &depthOptimizedClearValue,\n            IID_GRAPHICS_PPV_ARGS(m_depthStencil.ReleaseAndGetAddressOf())\n            ));\n\n        m_depthStencil->SetName(L\"Depth stencil\");\n\n        D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};\n        dsvDesc.Format = m_depthBufferFormat;\n        dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;\n\n        m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());\n    }\n\n    // Set the 3D rendering viewport and scissor rectangle to target the entire window.\n    m_screenViewport.TopLeftX = m_screenViewport.TopLeftY = 0.f;\n    m_screenViewport.Width = static_cast<float>(backBufferWidth);\n    m_screenViewport.Height = static_cast<float>(backBufferHeight);\n    m_screenViewport.MinDepth = D3D12_MIN_DEPTH;\n    m_screenViewport.MaxDepth = D3D12_MAX_DEPTH;\n\n    m_scissorRect.left = m_scissorRect.top = 0;\n    m_scissorRect.right = static_cast<LONG>(backBufferWidth);\n    m_scissorRect.bottom = static_cast<LONG>(backBufferHeight);\n}\n\n// This method is called when the Win32 window is created (or re-created).\nvoid DeviceResources::SetWindow(HWND window, int width, int height) noexcept\n{\n    m_window = window;\n\n    m_outputSize.left = m_outputSize.top = 0;\n    m_outputSize.right = width;\n    m_outputSize.bottom = height;\n}\n\n// This method is called when the Win32 window changes size.\nbool DeviceResources::WindowSizeChanged(int width, int height)\n{\n    RECT newRc;\n    newRc.left = newRc.top = 0;\n    newRc.right = width;\n    newRc.bottom = height;\n    if (newRc.left == m_outputSize.left\n        && newRc.top == m_outputSize.top\n        && newRc.right == m_outputSize.right\n        && newRc.bottom == m_outputSize.bottom)\n    {\n        return false;\n    }\n\n    m_outputSize = newRc;\n    CreateWindowSizeDependentResources();\n    return true;\n}\n\n// Recreate all device resources and set them back to the current state.\nvoid DeviceResources::HandleDeviceLost()\n{\n#ifdef _GAMING_DESKTOP\n    if (m_deviceNotify)\n    {\n        m_deviceNotify->OnDeviceLost();\n    }\n\n    for (UINT n = 0; n < m_backBufferCount; n++)\n    {\n        m_commandAllocators[n].Reset();\n        m_renderTargets[n].Reset();\n    }\n\n    m_depthStencil.Reset();\n    m_commandQueue.Reset();\n    m_commandList.Reset();\n    m_fence.Reset();\n    m_rtvDescriptorHeap.Reset();\n    m_dsvDescriptorHeap.Reset();\n    m_swapChain.Reset();\n    m_d3dDevice.Reset();\n    m_dxgiFactory.Reset();\n\n#ifdef _DEBUG\n    {\n        ComPtr<IDXGIDebug1> dxgiDebug;\n        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug))))\n        {\n            dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL));\n        }\n    }\n#endif\n\n    CreateDeviceResources();\n    CreateWindowSizeDependentResources();\n\n    if (m_deviceNotify)\n    {\n        m_deviceNotify->OnDeviceRestored();\n    }\n#endif\n}\n\n// Prepare the command list and render target for rendering.\nvoid DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState)\n{\n#ifdef _GAMING_XBOX\n    // Wait until frame start is signaled\n    m_framePipelineToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL;\n    ThrowIfFailed(m_d3dDevice->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, INFINITE, nullptr, D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &m_framePipelineToken));\n#endif\n\n    // Reset command list and allocator.\n    ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset());\n    ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr));\n\n    if (beforeState != afterState)\n    {\n        // Transition the render target into the correct state to allow for drawing into it.\n        D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(),\n            beforeState, afterState);\n        m_commandList->ResourceBarrier(1, &barrier);\n    }\n}\n\n// Present the contents of the swap chain to the screen.\nvoid DeviceResources::Present(D3D12_RESOURCE_STATES beforeState)\n{\n    if (beforeState != D3D12_RESOURCE_STATE_PRESENT)\n    {\n        // Transition the render target to the state that allows it to be presented to the display.\n        D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_backBufferIndex].Get(), beforeState, D3D12_RESOURCE_STATE_PRESENT);\n        m_commandList->ResourceBarrier(1, &barrier);\n    }\n\n    // Send the command list off to the GPU for processing.\n    ThrowIfFailed(m_commandList->Close());\n    m_commandQueue->ExecuteCommandLists(1, CommandListCast(m_commandList.GetAddressOf()));\n\n#ifdef _GAMING_XBOX\n\n    // Present the backbuffer using the PresentX API.\n    D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParameters = {};\n    planeParameters.Token = m_framePipelineToken;\n    planeParameters.ResourceCount = 1;\n    planeParameters.ppResources = m_renderTargets[m_backBufferIndex].GetAddressOf();\n\n    ThrowIfFailed(\n        m_commandQueue->PresentX(1, &planeParameters, nullptr)\n    );\n\n    // Xbox One apps do not need to handle DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET.\n\n#else\n\n    // The first argument instructs DXGI to block until VSync, putting the application\n    // to sleep until the next VSync. This ensures we don't waste any cycles rendering\n    // frames that will never be displayed to the screen.\n    HRESULT hr = m_swapChain->Present(1, 0);\n\n    // If the device was reset we must completely reinitialize the renderer.\n    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)\n    {\n#ifdef _DEBUG\n        char buff[64] = {};\n        sprintf_s(buff, \"Device Lost on Present: Reason code 0x%08X\\n\",\n            static_cast<unsigned int>((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr));\n        OutputDebugStringA(buff);\n#endif\n        HandleDeviceLost();\n    }\n    else\n    {\n        ThrowIfFailed(hr);\n    }\n\n#endif\n\n    MoveToNextFrame();\n}\n\n// Handle GPU suspend/resume\nvoid DeviceResources::Suspend()\n{\n#ifdef _GAMING_XBOX\n    m_commandQueue->SuspendX(0);\n#endif\n}\n\nvoid DeviceResources::Resume()\n{\n#ifdef _GAMING_XBOX\n    m_commandQueue->ResumeX();\n\n    RegisterFrameEvents();\n#endif\n}\n\n// Wait for pending GPU work to complete.\nvoid DeviceResources::WaitForGpu() noexcept\n{\n    if (m_commandQueue && m_fence && m_fenceEvent.IsValid())\n    {\n        // Schedule a Signal command in the GPU queue.\n        UINT64 fenceValue = m_fenceValues[m_backBufferIndex];\n        if (SUCCEEDED(m_commandQueue->Signal(m_fence.Get(), fenceValue)))\n        {\n            // Wait until the Signal has been processed.\n            if (SUCCEEDED(m_fence->SetEventOnCompletion(fenceValue, m_fenceEvent.Get())))\n            {\n                WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE);\n\n                // Increment the fence value for the current frame.\n                m_fenceValues[m_backBufferIndex]++;\n            }\n        }\n    }\n}\n\n// Prepare to render the next frame.\nvoid DeviceResources::MoveToNextFrame()\n{\n    // Schedule a Signal command in the queue.\n    const UINT64 currentFenceValue = m_fenceValues[m_backBufferIndex];\n    ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), currentFenceValue));\n\n    // Update the back buffer index.\n#ifdef _GAMING_XBOX\n    m_backBufferIndex = (m_backBufferIndex + 1) % m_backBufferCount;\n#else\n    m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex();\n#endif\n\n    // If the next frame is not ready to be rendered yet, wait until it is ready.\n    if (m_fence->GetCompletedValue() < m_fenceValues[m_backBufferIndex])\n    {\n        ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_backBufferIndex], m_fenceEvent.Get()));\n        WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE);\n    }\n\n    // Set the fence value for the next frame.\n    m_fenceValues[m_backBufferIndex] = currentFenceValue + 1;\n}\n\n#ifdef _GAMING_XBOX\n// Set frame interval and register for frame events\nvoid DeviceResources::RegisterFrameEvents()\n{\n    // First, retrieve the underlying DXGI device from the D3D device.\n    ComPtr<IDXGIDevice1> dxgiDevice;\n    ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));\n\n    // Identify the physical adapter (GPU or card) this device is running on.\n    ComPtr<IDXGIAdapter> dxgiAdapter;\n    ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));\n\n    // Retrieve the outputs for the adapter.\n    ComPtr<IDXGIOutput> dxgiOutput;\n    ThrowIfFailed(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));\n\n    // Set frame interval and register for frame events\n    ThrowIfFailed(m_d3dDevice->SetFrameIntervalX(\n        dxgiOutput.Get(),\n        D3D12XBOX_FRAME_INTERVAL_60_HZ,\n        m_backBufferCount - 1u /* Allow n-1 frames of latency */,\n        D3D12XBOX_FRAME_INTERVAL_FLAG_NONE));\n\n    ThrowIfFailed(m_d3dDevice->ScheduleFrameEventX(\n        D3D12XBOX_FRAME_EVENT_ORIGIN,\n        0U,\n        nullptr,\n        D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE));\n}\n#else\n// This method acquires the first available hardware adapter that supports Direct3D 12.\n// If no such adapter can be found, try WARP. Otherwise throw an exception.\nvoid DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter)\n{\n    *ppAdapter = nullptr;\n\n    ComPtr<IDXGIAdapter1> adapter;\n    for (UINT adapterIndex = 0;\n        SUCCEEDED(m_dxgiFactory->EnumAdapterByGpuPreference(\n            adapterIndex,\n            DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,\n            IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf())));\n        adapterIndex++)\n    {\n        DXGI_ADAPTER_DESC1 desc;\n        ThrowIfFailed(adapter->GetDesc1(&desc));\n\n        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)\n        {\n            // Don't select the Basic Render Driver adapter.\n            continue;\n        }\n\n        // Check to see if the adapter supports Direct3D 12, but don't create the actual device yet.\n        if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))\n        {\n#ifdef _DEBUG\n            wchar_t buff[256] = {};\n            swprintf_s(buff, L\"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\\n\", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);\n            OutputDebugStringW(buff);\n#endif\n            break;\n        }\n    }\n\n#if !defined(NDEBUG)\n    if (!adapter)\n    {\n        // Try WARP12 instead\n        if (FAILED(m_dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf()))))\n        {\n            throw std::runtime_error(\"WARP12 not available. Enable the 'Graphics Tools' optional feature\");\n        }\n\n        OutputDebugStringA(\"Direct3D Adapter - WARP12\\n\");\n    }\n#endif\n\n    if (!adapter)\n    {\n        throw std::runtime_error(\"No Direct3D 12 device found\");\n    }\n\n    *ppAdapter = adapter.Detach();\n}\n#endif\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/DeviceResources.h",
    "content": "//\n// DeviceResources.h - A wrapper for the Direct3D 12/12.X device and swapchain\n//\n\n#pragma once\n\nnamespace DX\n{\n    // Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created.\n    interface IDeviceNotify\n    {\n        virtual void OnDeviceLost() = 0;\n        virtual void OnDeviceRestored() = 0;\n\n    protected:\n        ~IDeviceNotify() = default;\n    };\n\n    // Controls all the DirectX device resources.\n    class DeviceResources\n    {\n    public:\n        DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM,\n                        DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT,\n                        UINT backBufferCount = 2) noexcept(false);\n        ~DeviceResources();\n\n        DeviceResources(DeviceResources&&) = default;\n        DeviceResources& operator= (DeviceResources&&) = default;\n\n        DeviceResources(DeviceResources const&) = delete;\n        DeviceResources& operator= (DeviceResources const&) = delete;\n\n        void CreateDeviceResources();\n        void CreateWindowSizeDependentResources();\n        void SetWindow(HWND window, int width, int height) noexcept;\n        bool WindowSizeChanged(int width, int height);\n        void HandleDeviceLost();\n        void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; }\n        void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT,\n                     D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET);\n        void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET);\n        void Suspend();\n        void Resume();\n        void WaitForGpu() noexcept;\n\n        // Device Accessors.\n        RECT GetOutputSize() const noexcept { return m_outputSize; }\n\n        // Direct3D Accessors.\n        auto                        GetD3DDevice() const noexcept          { return m_d3dDevice.Get(); }\n#ifdef _GAMING_DESKTOP\n        auto                        GetSwapChain() const noexcept          { return m_swapChain.Get(); }\n        auto                        GetDXGIFactory() const noexcept        { return m_dxgiFactory.Get(); }\n#endif\n        HWND                        GetWindow() const noexcept             { return m_window; }\n        D3D_FEATURE_LEVEL           GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; }\n        ID3D12Resource*             GetRenderTarget() const noexcept       { return m_renderTargets[m_backBufferIndex].Get(); }\n        ID3D12Resource*             GetDepthStencil() const noexcept       { return m_depthStencil.Get(); }\n        ID3D12CommandQueue*         GetCommandQueue() const noexcept       { return m_commandQueue.Get(); }\n        ID3D12CommandAllocator*     GetCommandAllocator() const noexcept   { return m_commandAllocators[m_backBufferIndex].Get(); }\n        auto                        GetCommandList() const noexcept        { return m_commandList.Get(); }\n        DXGI_FORMAT                 GetBackBufferFormat() const noexcept   { return m_backBufferFormat; }\n        DXGI_FORMAT                 GetDepthBufferFormat() const noexcept  { return m_depthBufferFormat; }\n        D3D12_VIEWPORT              GetScreenViewport() const noexcept     { return m_screenViewport; }\n        D3D12_RECT                  GetScissorRect() const noexcept        { return m_scissorRect; }\n        UINT                        GetCurrentFrameIndex() const noexcept  { return m_backBufferIndex; }\n        UINT                        GetBackBufferCount() const noexcept    { return m_backBufferCount; }\n\n        CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const noexcept\n        {\n            return CD3DX12_CPU_DESCRIPTOR_HANDLE(\n                m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),\n                static_cast<INT>(m_backBufferIndex), m_rtvDescriptorSize);\n        }\n        CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const noexcept\n        {\n            return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());\n        }\n\n    private:\n        void MoveToNextFrame();\n#ifdef _GAMING_XBOX\n        void RegisterFrameEvents();\n#else\n        void GetAdapter(IDXGIAdapter1** ppAdapter);\n#endif\n\n        static constexpr size_t MAX_BACK_BUFFER_COUNT = 3;\n\n        UINT                                                m_backBufferIndex;\n\n        // Direct3D objects.\n        Microsoft::WRL::ComPtr<ID3D12Device>                m_d3dDevice;\n        Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList>   m_commandList;\n        Microsoft::WRL::ComPtr<ID3D12CommandQueue>          m_commandQueue;\n        Microsoft::WRL::ComPtr<ID3D12CommandAllocator>      m_commandAllocators[MAX_BACK_BUFFER_COUNT];\n\n        // Swap chain objects.\n#ifdef _GAMING_DESKTOP\n        Microsoft::WRL::ComPtr<IDXGIFactory6>               m_dxgiFactory;\n        Microsoft::WRL::ComPtr<IDXGISwapChain3>             m_swapChain;\n#endif\n        Microsoft::WRL::ComPtr<ID3D12Resource>              m_renderTargets[MAX_BACK_BUFFER_COUNT];\n        Microsoft::WRL::ComPtr<ID3D12Resource>              m_depthStencil;\n\n        // Presentation fence objects.\n        Microsoft::WRL::ComPtr<ID3D12Fence>                 m_fence;\n        UINT64                                              m_fenceValues[MAX_BACK_BUFFER_COUNT];\n        Microsoft::WRL::Wrappers::Event                     m_fenceEvent;\n#ifdef _GAMING_XBOX\n        D3D12XBOX_FRAME_PIPELINE_TOKEN                      m_framePipelineToken;\n#endif\n\n        // Direct3D rendering objects.\n        Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>        m_rtvDescriptorHeap;\n        Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>        m_dsvDescriptorHeap;\n        UINT                                                m_rtvDescriptorSize;\n        D3D12_VIEWPORT                                      m_screenViewport;\n        D3D12_RECT                                          m_scissorRect;\n\n        // Direct3D properties.\n        DXGI_FORMAT                                         m_backBufferFormat;\n        DXGI_FORMAT                                         m_depthBufferFormat;\n        UINT                                                m_backBufferCount;\n\n        // Cached device properties.\n        HWND                                                m_window;\n        D3D_FEATURE_LEVEL                                   m_d3dFeatureLevel;\n        RECT                                                m_outputSize;\n\n        // The IDeviceNotify can be held directly as it owns the DeviceResources.\n        IDeviceNotify*                                      m_deviceNotify;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/Main.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// Main.cpp\n//\n// Entry point for Microsoft Game Development Kit (GDK)\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"ManualTest.h\"\n\n#include <appnotify.h>\n#include <XGameRuntimeInit.h>\n#include <XGameErr.h>\n\n#ifdef ATG_ENABLE_TELEMETRY\n#include \"ATGTelemetry.h\"\n#endif\n\nusing namespace DirectX;\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#pragma clang diagnostic ignored \"-Wswitch-enum\"\n#endif\n\n#pragma warning(disable : 4061)\n\nnamespace\n{\n    std::unique_ptr<Sample> g_sample;\n#ifdef _GAMING_XBOX\n    HANDLE g_plmSuspendComplete = nullptr;\n    HANDLE g_plmSignalResume = nullptr;\n#endif\n}\n\nLPCWSTR g_szAppName = L\"ManualTest\";\n\nLRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);\nvoid ExitSample() noexcept;\n\n// Entry point\nint WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)\n{\n    UNREFERENCED_PARAMETER(lpCmdLine);\n\n    if (!XMVerifyCPUSupport())\n    {\n#ifdef _DEBUG\n        OutputDebugStringA(\"ERROR: This hardware does not support the required instruction set.\\n\");\n#if defined(_GAMING_XBOX) && defined(__AVX2__)\n        OutputDebugStringA(\"This may indicate a Gaming.Xbox.Scarlett.x64 binary is being run on an Xbox One.\\n\");\n#endif\n#endif\n        return 1;\n    }\n\n    // Initialize COM for WIC usage\n    if (FAILED(CoInitializeEx(nullptr, COINITBASE_MULTITHREADED)))\n        return 1;\n\n#ifdef _GAMING_DESKTOP\n    // NOTE: When running the app from the Start Menu (required for\n    //    Store API's to work) the Current Working Directory will be\n    //    returned as C:\\Windows\\system32 unless you overwrite it.\n    //    The sample relies on the font and image files in the .exe's\n    //    directory and so we do the following to set the working\n    //    directory to what we want.\n    char dir[_MAX_PATH] = {};\n    if (GetModuleFileNameA(nullptr, dir, _MAX_PATH) > 0)\n    {\n        std::string exe = dir;\n        exe = exe.substr(0, exe.find_last_of(\"\\\\\"));\n        std::ignore = SetCurrentDirectoryA(exe.c_str());\n    }\n#endif\n\n    HRESULT hr = XGameRuntimeInitialize();\n    if (FAILED(hr))\n    {\n        if (hr == E_GAMERUNTIME_DLL_NOT_FOUND || hr == E_GAMERUNTIME_VERSION_MISMATCH)\n        {\n#ifdef _GAMING_DESKTOP\n            std::ignore = MessageBoxW(nullptr, L\"Game Runtime is not installed on this system or needs updating.\", g_szAppName, MB_ICONERROR | MB_OK);\n#endif\n        }\n        return 1;\n    }\n\n#ifdef _GAMING_XBOX\n    // Default main thread to CPU 0\n    SetThreadAffinityMask(GetCurrentThread(), 0x1);\n#endif\n\n    g_sample = std::make_unique<Sample>();\n\n    // Register class and create window\n#ifdef _GAMING_XBOX\n    PAPPSTATE_REGISTRATION hPLM = {};\n#endif\n    {\n        // Register class\n        WNDCLASSEXW wcex = {};\n        wcex.cbSize = sizeof(WNDCLASSEXW);\n        wcex.style = CS_HREDRAW | CS_VREDRAW;\n        wcex.lpfnWndProc = WndProc;\n        wcex.hInstance = hInstance;\n        wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);\n        wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);\n        wcex.lpszClassName = L\"ManualTestWindowClass\";\n        if (!RegisterClassExW(&wcex))\n            return 1;\n\n        // Create window\n#ifdef _GAMING_XBOX\n        RECT rc = { 0, 0, 1920, 1080 };\n#else\n        int w, h;\n        g_sample->GetDefaultSize(w, h);\n\n        RECT rc = { 0, 0, static_cast<LONG>(w), static_cast<LONG>(h) };\n        AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);\n#endif\n\n        HWND hwnd = CreateWindowExW(0, L\"ManualTestWindowClass\", g_szAppName, WS_OVERLAPPEDWINDOW,\n            CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,\n            nullptr);\n        if (!hwnd)\n            return 1;\n\n        ShowWindow(hwnd, nCmdShow);\n\n        SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_sample.get()));\n\n        // Sample Usage Telemetry\n        //\n        // Disable or remove this code block to opt-out of sample usage telemetry\n\n        GetClientRect(hwnd, &rc);\n\n        g_sample->Initialize(hwnd, rc.right - rc.left, rc.bottom - rc.top);\n\n#ifdef _GAMING_XBOX\n        g_plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);\n        g_plmSignalResume = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);\n        if (!g_plmSuspendComplete || !g_plmSignalResume)\n            return 1;\n\n        if (RegisterAppStateChangeNotification([](BOOLEAN quiesced, PVOID context)\n        {\n            if (quiesced)\n            {\n                ResetEvent(g_plmSuspendComplete);\n                ResetEvent(g_plmSignalResume);\n\n                // To ensure we use the main UI thread to process the notification, we self-post a message\n                PostMessage(reinterpret_cast<HWND>(context), WM_USER, 0, 0);\n\n                // To defer suspend, you must wait to exit this callback\n                std::ignore = WaitForSingleObject(g_plmSuspendComplete, INFINITE);\n            }\n            else\n            {\n                SetEvent(g_plmSignalResume);\n            }\n        }, hwnd, &hPLM))\n            return 1;\n#endif\n    }\n\n    // Main message loop\n    MSG msg = {};\n    while (WM_QUIT != msg.message)\n    {\n        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))\n        {\n            TranslateMessage(&msg);\n            DispatchMessage(&msg);\n        }\n        else\n        {\n            g_sample->Tick();\n        }\n    }\n\n    g_sample.reset();\n\n#ifdef _GAMING_XBOX\n    UnregisterAppStateChangeNotification(hPLM);\n\n    CloseHandle(g_plmSuspendComplete);\n    CloseHandle(g_plmSignalResume);\n#endif\n\n\n    XGameRuntimeUninitialize();\n\n    CoUninitialize();\n\n    return static_cast<int>(msg.wParam);\n}\n\n// Windows procedure\nLRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n{\n#ifdef _GAMING_DESKTOP\n    static bool s_in_sizemove = false;\n    static bool s_in_suspend = false;\n    static bool s_minimized = false;\n    static bool s_fullscreen = false;\n#endif\n\n    auto sample = reinterpret_cast<Sample*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));\n\n    switch (message)\n    {\n    case WM_ACTIVATEAPP:\n        if (sample)\n        {\n            Keyboard::ProcessMessage(message, wParam, lParam);\n            Mouse::ProcessMessage(message, wParam, lParam);\n\n            if (wParam)\n            {\n                sample->OnActivated();\n            }\n            else\n            {\n                sample->OnDeactivated();\n            }\n        }\n        break;\n\n    case WM_ACTIVATE:\n        Keyboard::ProcessMessage(message, wParam, lParam);\n        Mouse::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_MOUSEMOVE:\n    case WM_LBUTTONDOWN:\n    case WM_LBUTTONUP:\n    case WM_RBUTTONDOWN:\n    case WM_RBUTTONUP:\n    case WM_MBUTTONDOWN:\n    case WM_MBUTTONUP:\n    case WM_MOUSEWHEEL:\n    case WM_XBUTTONDOWN:\n    case WM_XBUTTONUP:\n        Mouse::ProcessMessage(message, wParam, lParam);\n        break;\n\n#ifdef _GAMING_XBOX\n    case WM_USER:\n        if (sample)\n        {\n            sample->OnSuspending();\n\n            // Complete deferral\n            SetEvent(g_plmSuspendComplete);\n\n            std::ignore = WaitForSingleObject(g_plmSignalResume, INFINITE);\n\n            sample->OnResuming();\n        }\n        break;\n#else\n    case WM_PAINT:\n        if (s_in_sizemove && sample)\n        {\n            sample->Tick();\n        }\n        else\n        {\n            PAINTSTRUCT ps;\n            std::ignore = BeginPaint(hWnd, &ps);\n            EndPaint(hWnd, &ps);\n        }\n        break;\n\n    case WM_MOVE:\n        if (sample)\n        {\n            sample->OnWindowMoved();\n        }\n        break;\n\n    case WM_SIZE:\n        if (wParam == SIZE_MINIMIZED)\n        {\n            if (!s_minimized)\n            {\n                s_minimized = true;\n                if (!s_in_suspend && sample)\n                    sample->OnSuspending();\n                s_in_suspend = true;\n            }\n        }\n        else if (s_minimized)\n        {\n            s_minimized = false;\n            if (s_in_suspend && sample)\n                sample->OnResuming();\n            s_in_suspend = false;\n        }\n        else if (!s_in_sizemove && sample)\n        {\n            sample->OnWindowSizeChanged(LOWORD(lParam), HIWORD(lParam));\n        }\n        break;\n\n    case WM_ENTERSIZEMOVE:\n        s_in_sizemove = true;\n        break;\n\n    case WM_EXITSIZEMOVE:\n        s_in_sizemove = false;\n        if (sample)\n        {\n            RECT rc;\n            GetClientRect(hWnd, &rc);\n\n            sample->OnWindowSizeChanged(rc.right - rc.left, rc.bottom - rc.top);\n        }\n        break;\n\n    case WM_GETMINMAXINFO:\n        if (lParam)\n        {\n            auto info = reinterpret_cast<MINMAXINFO*>(lParam);\n            info->ptMinTrackSize.x = 320;\n            info->ptMinTrackSize.y = 200;\n        }\n        break;\n\n    case WM_POWERBROADCAST:\n        switch (wParam)\n        {\n        case PBT_APMQUERYSUSPEND:\n            if (!s_in_suspend && sample)\n                sample->OnSuspending();\n            s_in_suspend = true;\n            return TRUE;\n\n        case PBT_APMRESUMESUSPEND:\n            if (!s_minimized)\n            {\n                if (s_in_suspend && sample)\n                    sample->OnResuming();\n                s_in_suspend = false;\n            }\n            return TRUE;\n        }\n        break;\n\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        break;\n\n    case WM_INPUT:\n    case WM_MOUSEHOVER:\n        Mouse::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYUP:\n        Keyboard::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_SYSKEYDOWN:\n        if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000)\n        {\n            // Implements the classic ALT+ENTER fullscreen toggle\n            if (s_fullscreen)\n            {\n                SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);\n                SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0);\n\n                int width = 800;\n                int height = 600;\n                if (sample)\n                    sample->GetDefaultSize(width, height);\n\n                ShowWindow(hWnd, SW_SHOWNORMAL);\n\n                SetWindowPos(hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);\n            }\n            else\n            {\n                SetWindowLongPtr(hWnd, GWL_STYLE, 0);\n                SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);\n\n                SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);\n\n                ShowWindow(hWnd, SW_SHOWMAXIMIZED);\n            }\n\n            s_fullscreen = !s_fullscreen;\n        }\n        Keyboard::ProcessMessage(message, wParam, lParam);\n        break;\n\n    case WM_MOUSEACTIVATE:\n        // When you click activate the window, we want Mouse to ignore that event.\n        return MA_ACTIVATEANDEAT;\n\n    case WM_MENUCHAR:\n        // A menu is active and the user presses a key that does not correspond\n        // to any mnemonic or accelerator key. Ignore so we don't produce an error beep.\n        return MAKELRESULT(0, MNC_CLOSE);\n#endif\n    }\n\n    return DefWindowProc(hWnd, message, wParam, lParam);\n}\n\n// Exit helper\nvoid ExitSample() noexcept\n{\n    PostQuitMessage(0);\n}\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/ManualTest.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// ManualTest.cpp\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n#include \"ManualTest.h\"\n\n#include \"ATGColors.h\"\n#include \"FindMedia.h\"\n#include \"StringUtil.h\"\n#include <XGameRuntimeFeature.h>\n#include <XNetworking.h>\n#include <XGameRuntimeInit.h>\n\ninline std::string DebugFormat(_In_z_ _Printf_format_string_ const char* format, ...)\n{\n#ifdef _DEBUG\n    va_list args;\n    va_start(args, format);\n\n    char buff[1024*10] = {};\n    vsprintf_s(buff, format, args);\n    std::string str = buff;\n    va_end(args);\n    return buff;\n#else\n    UNREFERENCED_PARAMETER(format);\n#endif\n}\n\n\nextern void ExitSample() noexcept;\n\nusing namespace DirectX;\n\nusing Microsoft::WRL::ComPtr;\n\nSample* g_sample = nullptr;\n\nnamespace\n{\n    const char *ProgressStateText[] = {\n        u8\"Unknown\",\n        u8\"Achieved\",\n        u8\"Not Started\",\n        u8\"In Progress\"\n    };\n\n    const char *AchievementTypeText[] = {\n        u8\"Unknown\",\n        u8\"All\",\n        u8\"Persistent\",\n        u8\"Challenge\"\n    };\n\n    const int c_sampleUIPanel = 2000;\n    const int c_getAchievementsBtn = 2101;\n    const int c_getSingleAchievementBtn = 2102;\n    const int c_setSingleAchievementBtn = 2103;\n    const int c_getSingleAchievementBtn2 = 2104;\n    const int c_setSingleAchievement2Btn25 = 2105;\n    const int c_setSingleAchievement2Btn50 = 2106;\n    const int c_setSingleAchievement2Btn100 = 2107;\n}\n\n\nvoid CALLBACK MyXUserChangeEventCallback(\n    _In_opt_ void* context,\n    _In_ XUserLocalId userLocalId,\n    _In_ XUserChangeEvent event)\n{\n    UNREFERENCED_PARAMETER(context);\n    std::string eventType = \"\";\n    switch (event)\n    {\n        case XUserChangeEvent::SignedInAgain: eventType = \"SignedInAgain\"; break;\n        case XUserChangeEvent::SigningOut: eventType = \"SigningOut\"; break;\n        case XUserChangeEvent::SignedOut: eventType = \"SignedOut\"; break;\n        case XUserChangeEvent::Gamertag: eventType = \"Gamertag\"; break;\n        case XUserChangeEvent::GamerPicture: eventType = \"GamerPicture\"; break;\n        case XUserChangeEvent::Privileges:eventType = \"Privileges\"; break;\n        default: break;\n    }\n\n    XUserHandle handle;\n    uint64_t xuid = {};\n    HRESULT hr = XUserFindUserByLocalId(\n        userLocalId,\n        &handle);\n    if (SUCCEEDED(hr))\n    {\n        XUserGetId(handle, &xuid);\n        XUserCloseHandle(handle);\n    }\n\n    g_sample->AddLog(DebugFormat(\"XUserChangeEventCallback: userLocalId: %ull = %s xuid: 0x%0.8x\", userLocalId.value, eventType.c_str(), xuid));\n}\n\n\nvoid __cdecl MyHCCallRoutedHandler(\n    _In_ HCCallHandle call,\n    _In_opt_ void* context\n    )\n{\n    UNREFERENCED_PARAMETER(context);\n    const char* url = nullptr;\n    uint32_t status = 0;\n    HCHttpCallGetRequestUrl(call, &url);\n    HCHttpCallResponseGetStatusCode(call, &status);\n    HRESULT hrNet = S_OK;\n    uint32_t hrPlat = S_OK;\n    HCHttpCallResponseGetNetworkErrorCode(call, &hrNet, &hrPlat);\n    g_sample->AddLog(DebugFormat(\"HCCallRoutedHandler: %d [0x%0.8x] %s\", status, hrNet, url));\n}\n\nvoid CALLBACK MyHCTraceCallback(\n    _In_z_ const char* areaName,\n    _In_ HCTraceLevel level,\n    _In_ uint64_t threadId,\n    _In_ uint64_t timestamp,\n    _In_z_ const char* message\n)\n{\n    UNREFERENCED_PARAMETER(areaName);\n    UNREFERENCED_PARAMETER(level);\n    UNREFERENCED_PARAMETER(threadId);\n    UNREFERENCED_PARAMETER(timestamp);\n    g_sample->AddLog(DebugFormat(\"HC: %s\", message));\n}\n\nvoid MyNetworkConnectivityChangedCallback(void* context, const XNetworkingConnectivityHint* /*hint*/)\n{\n    UNREFERENCED_PARAMETER(context);\n    // Always requery the latest network connectivity hint rather than relying on the passed parameter in case this is a stale notification\n    XNetworkingConnectivityHint hint{};\n    HRESULT hr = XNetworkingGetConnectivityHint(&hint);\n    if (SUCCEEDED(hr))\n    {\n        g_sample->AddLog(DebugFormat(\"NetworkConnectivityChangedCallback: networkInitialized: %d connectivityLevel: %d\", hint.networkInitialized, hint.connectivityLevel));\n    }\n    else\n    {\n        g_sample->AddLog(DebugFormat(\"NetworkConnectivityChangedCallback: 0x%0.8x\", hr));\n    }\n}\n\n\nSample::Sample() noexcept(false) :\n    m_frame(0)\n{\n    g_sample = this;\n    m_deviceResources = std::make_unique<DX::DeviceResources>();\n    m_deviceResources->RegisterDeviceNotify(this);\n    m_liveInfoHUD = std::make_unique<ATG::SampleLiveInfoHUD>(\"Title-managed ManualTest Sample\");\n\n    DX::ThrowIfFailed(\n        XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::Manual, &m_mainAsyncQueue)\n    );\n\n    ATG::UIConfig uiconfig;\n    m_ui = std::make_unique<ATG::UIManager>(uiconfig);\n    m_log = std::make_unique<DX::TextConsoleImage>();\n    m_display = std::make_unique<DX::TextConsoleImage>();  \n\n    XTaskQueueRegistrationToken token = {};\n    XUserRegisterForChangeEvent(nullptr, nullptr, MyXUserChangeEventCallback, &token);\n\n    HCTraceSetClientCallback(MyHCTraceCallback);\n    m_liveInfoHUD->AddLog(\"**************** GAME START ****************\");\n\n    XTaskQueueRegistrationToken tokenHint;\n    HRESULT hr = XNetworkingRegisterConnectivityHintChanged(nullptr, nullptr, MyNetworkConnectivityChangedCallback, &tokenHint);\n    m_liveInfoHUD->AddLog(DebugFormat(\"XNetworkingRegisterConnectivityHintChanged 0x%0.8x\", hr));\n}\n\nSample::~Sample()\n{\n    if (m_deviceResources)\n    {\n        m_deviceResources->WaitForGpu();\n    }\n\n    if (m_mainAsyncQueue)\n    {\n        XTaskQueueCloseHandle(m_mainAsyncQueue);\n        m_mainAsyncQueue = nullptr;\n    }\n\n    XGameRuntimeUninitialize();\n}\n\n// Initialize the Direct3D resources required to run.\nvoid Sample::Initialize(HWND window, int width, int height)\n{\n    m_gamePad = std::make_unique<GamePad>();\n\n    m_keyboard = std::make_unique<Keyboard>();\n\n    m_mouse = std::make_unique<Mouse>();\n    m_mouse->SetWindow(window);\n\n    m_deviceResources->SetWindow(window, width, height);\n\n    wchar_t result[MAX_PATH];\n    DX::FindMediaFile(result, MAX_PATH, L\".\\\\Assets\\\\SampleUI.csv\");\n    m_ui->LoadLayout(result, L\".\\\\Assets\\\\\");\n\n    HRESULT hr = XGameRuntimeInitialize();\n    m_deviceResources->CreateDeviceResources();\n    CreateDeviceDependentResources();\n\n    m_deviceResources->CreateWindowSizeDependentResources();\n    CreateWindowSizeDependentResources();\n\n    m_liveInfoHUD->Initialize();\n\n    SetupUI();\n}\n\nvoid Sample::SetupUI()\n{\n}\n\n#pragma region Frame Update\n// Executes basic render loop.\nvoid Sample::Tick()\n{\n    PIXBeginEvent(PIX_COLOR_DEFAULT, L\"Frame %llu\", m_frame);\n\n    m_timer.Tick([&]()\n    {\n        Update(m_timer);\n    });\n\n    Render();\n\n    PIXEndEvent();\n    m_frame++;\n}\n\nstatic std::string NewGuid()\n{\n    GUID id = {};\n    char buf[64] = {};\n\n    CoCreateGuid(&id);\n\n    sprintf_s(buf, \"%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\",\n        id.Data1, id.Data2, id.Data3,\n        id.Data4[0], id.Data4[1], id.Data4[2], id.Data4[3],\n        id.Data4[4], id.Data4[5], id.Data4[6], id.Data4[7]);\n\n    return std::string(buf);\n}\n\n\nvoid Sample::CreateSession()\n{\n    if (m_xblContext == nullptr)\n    {\n        g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"CreateSession no m_xblContext\"));\n        return;\n    }\n\n    if (m_userHandle1 == nullptr)\n    {\n        g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"CreateSession Add user first\"));\n        return;\n    }\n\n    if (m_currentSessionHandle != nullptr)\n    {\n        g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"CreateSession Session exists\"));\n        return;\n    }\n\n    XblMultiplayerSessionInitArgs initArgs;\n    initArgs.MaxMembersInSession = 8; //This matches our session template\n    initArgs.Visibility = XblMultiplayerSessionVisibility::Open; //The session is open and can be joined by anyone.\n    initArgs.InitiatorXuids = nullptr;\n    initArgs.InitiatorXuidsCount = 0;\n    initArgs.CustomJson = nullptr;\n\n    const char* scid = nullptr;\n    XblGetScid(&scid);\n    std::string currentSessionName = NewGuid();\n    XblMultiplayerSessionReference createdSessionRef = XblMultiplayerSessionReferenceCreate(scid, \"GameSession\", currentSessionName.c_str());\n\n    uint64_t userId = 0;\n    XUserGetId(m_userHandle1, &userId);\n    m_currentSessionHandle = XblMultiplayerSessionCreateHandle(userId, &createdSessionRef, &initArgs);\n    m_liveInfoHUD->AddLog(DebugFormat(\"m_currentSessionHandle 0x%0.8x\", m_currentSessionHandle));\n\n    HRESULT hr = XblMultiplayerSessionJoin(m_currentSessionHandle, nullptr, true, true);\n    m_liveInfoHUD->AddLog(DebugFormat(\"XblMultiplayerSessionJoin 0x%0.8x\", hr));\n}\n\nvoid Sample::WriteSession()\n{\n    if (m_xblContext == nullptr)\n    {\n        g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"no m_xblContext\"));\n        return;\n    }\n    if( m_currentSessionHandle == nullptr)\n    {\n        g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"no m_currentSessionHandle\"));\n        return;\n    }\n\n    auto asyncBlock = std::make_unique<XAsyncBlock>();\n    asyncBlock->queue = nullptr;\n    asyncBlock->context = nullptr;\n    asyncBlock->callback = [](XAsyncBlock* asyncBlock)\n    {\n        g_sample->m_liveInfoHUD->AddLog(\"***** XblMultiplayerWriteSessionAsync callback\");\n\n        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; //Take over ownership of the XAsyncBlock*\n\n        XblMultiplayerSessionHandle createdHandle;\n        HRESULT hr = XblMultiplayerWriteSessionResult(asyncBlock, &createdHandle);\n        g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"XblMultiplayerWriteSessionResult 0x%0.8x\", hr));\n        if (hr == S_OK)\n        {\n            XblWriteSessionStatus status = XblMultiplayerSessionWriteStatus(createdHandle);\n            g_sample->m_liveInfoHUD->AddLog(DebugFormat(\"XblMultiplayerSessionWriteStatus %d\", status));\n        }\n\n        XblMultiplayerSessionCloseHandle(createdHandle);\n    };\n\n    HRESULT hr = XblMultiplayerWriteSessionAsync(m_xblContext, m_currentSessionHandle, XblMultiplayerSessionWriteMode::UpdateOrCreateNew, asyncBlock.get());\n    m_liveInfoHUD->AddLog(DebugFormat(\"XblMultiplayerWriteSessionAsync 0x%0.8x\", hr));\n    if (SUCCEEDED(hr))\n    {\n        // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.\n        // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*\n        asyncBlock.release();\n    }\n    else\n    {\n        XblMultiplayerSessionCloseHandle(m_currentSessionHandle);\n    }    \n}\n\n// Updates the world.\nvoid Sample::Update(DX::StepTimer const& timer)\n{\n    PIXBeginEvent(PIX_COLOR_DEFAULT, L\"Update\");\n\n    float elapsedTime = float(timer.GetElapsedSeconds());\n\n    auto pad = m_gamePad->GetState(0);\n    if (pad.IsConnected())\n    {\n        m_gamePadButtons.Update(pad);\n\n        if (pad.IsViewPressed())\n        {\n            ExitSample();\n        }\n\n        if (m_gamePadButtons.menu == GamePad::ButtonStateTracker::PRESSED)\n        {\n\n        }\n\n        m_ui->Update(elapsedTime, pad);\n    }\n    else\n    {\n        m_gamePadButtons.Reset();\n    }\n\n    auto kb = m_keyboard->GetState();\n    m_keyboardButtons.Update(kb);\n\n    if (kb.Escape)\n    {\n        ExitSample();\n    }\n\n    bool isControlPressed = kb.LeftControl || kb.RightControl;\n\n    if (!isControlPressed)\n    {\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D1) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D1)))\n        {\n            if (!m_xblInit)\n            {\n                m_xblInit = true;\n                uint32_t titleId = 0;\n                auto hr = XGameGetXboxTitleId(&titleId);\n                char scidBuffer[64] = {};\n                sprintf_s(scidBuffer, \"00000000-0000-0000-0000-0000%08X\", titleId);\n                XblInitArgs xblInit = { nullptr, scidBuffer };\n                hr = XblInitialize(&xblInit);\n                m_liveInfoHUD->AddLog(DebugFormat(\"XblInitialize 0x%0.8x\", hr));\n                hr = HCAddCallRoutedHandler(MyHCCallRoutedHandler, nullptr);\n                m_liveInfoHUD->AddLog(DebugFormat(\"HCAddCallRoutedHandler 0x%0.8x\", hr));\n                g_sample->AddLog(DebugFormat(\"XblInitialize 0x%0.8x done\", hr));\n            }\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D2) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D2)))\n        {\n            if (m_userHandle1 == nullptr)\n            {\n                AddUser(XUserAddOptions::AddDefaultUserSilently);\n                g_sample->AddLog(DebugFormat(\"AddUser done\"));\n            }\n            else\n            {\n                g_sample->AddLog(DebugFormat(\"no user\"));\n            }\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D3) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D3)))\n        {\n            if (m_xblInit && !m_xblRTA && m_xblContext)\n            {\n                HRESULT hr = XblMultiplayerSetSubscriptionsEnabled(m_xblContext, true);\n                g_sample->AddLog(DebugFormat(\"XblMultiplayerSetSubscriptionsEnabled 0x%0.8x\", hr));\n\n                m_xblRTA = true;\n                hr = XblRealTimeActivityActivate(m_xblContext);\n                g_sample->AddLog(DebugFormat(\"XblRealTimeActivityActivate 0x%0.8x\", hr));\n                g_sample->AddLog(DebugFormat(\"RTA done\"));\n            }\n            else\n            {\n                if(!m_xblInit)\n                    g_sample->AddLog(DebugFormat(\"rta - not init\"));\n                if (!m_xblContext)\n                    g_sample->AddLog(DebugFormat(\"rta - not m_xblContext\"));\n            }\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D4) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D4)))\n        {\n            CreateSession();\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D5) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D5)))\n        {\n            WriteSession();\n        }\n    }\n    else\n    {\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D1) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D1)))\n        {\n            if (m_xblInit)\n            {\n                m_xblInit = false;\n                auto async = new XAsyncBlock{};\n                HRESULT hr = XblCleanupAsync(async);\n                g_sample->AddLog(DebugFormat(\"XblCleanupAsync 0x%0.8x\", hr));\n                XAsyncGetStatus(async, true);\n                g_sample->AddLog(DebugFormat(\"XblCleanupAsync 0x%0.8x done\", hr));\n            }\n            else\n            {\n                g_sample->AddLog(DebugFormat(\"cleanup - not init\"));\n            }\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D2) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D2)))\n        {\n            if (m_userHandle1 != nullptr)\n            {\n                uint64_t xuid = {};\n                XUserGetId(m_userHandle1, &xuid);\n                XUserLocalId userLocalId = {};\n                XUserGetLocalId(m_userHandle1, &userLocalId);\n\n                g_sample->AddLog(DebugFormat(\"Closing XUserHandle 0x%0.8x. userLocalId: %ull, xuid: 0x%0.8x\", m_userHandle1, userLocalId, xuid));\n                SetUserHandle(nullptr);\n            }\n            else\n            {\n                g_sample->AddLog(DebugFormat(\"cleanup - no user\"));\n            }\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D3) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D3)))\n        {\n            if (m_xblInit && m_xblRTA)\n            {\n                m_xblRTA = false;\n                HRESULT hr = XblRealTimeActivityDeactivate(m_xblContext);\n                g_sample->AddLog(DebugFormat(\"XblRealTimeActivityDeactivate 0x%0.8x\", hr));\n            }\n            else\n            {\n                g_sample->AddLog(DebugFormat(\"cleanup - no session\")); \n            }\n        }\n\n        if ((m_keyboardButtons.IsKeyPressed(Keyboard::Keys::D4) && !m_keyboardButtonsLast.IsKeyPressed(Keyboard::Keys::D4)))\n        {\n            if (m_currentSessionHandle != nullptr)\n            {\n                XblMultiplayerSessionCloseHandle(m_currentSessionHandle);\n                g_sample->AddLog(DebugFormat(\"XblMultiplayerSessionCloseHandle\"));\n                m_currentSessionHandle = nullptr;\n            }\n            else\n            {\n                g_sample->AddLog(DebugFormat(\"cleanup - no session\"));\n            }\n        }\n    }\n\n    m_keyboardButtonsLast = m_keyboardButtons;\n\n    m_ui->Update(elapsedTime, *m_mouse, *m_keyboard);\n\n    m_liveInfoHUD->Update(m_deviceResources->GetCommandQueue());\n\n    // Process any completed tasks\n    while (XTaskQueueDispatch(m_mainAsyncQueue, XTaskQueuePort::Completion, 0))\n    {\n        SwitchToThread();\n    }\n\n    PIXEndEvent();\n}\n#pragma endregion\n\n#pragma region Frame Render\n// Draws the scene.\nvoid Sample::Render()\n{\n    // Don't try to render anything before the first Update.\n    if (m_timer.GetFrameCount() == 0)\n    {\n        return;\n    }\n\n    // Prepare the command list to render a new frame.\n    m_deviceResources->Prepare();\n    Clear();\n\n    auto commandList = m_deviceResources->GetCommandList();\n    PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L\"Render\");\n\n    ID3D12DescriptorHeap* heap = m_resourceDescriptors->Heap();\n    commandList->SetDescriptorHeaps(1, &heap);\n\n    m_liveInfoHUD->Render(commandList);\n    //m_log->Render(commandList);\n    //m_display->Render(commandList);\n    m_ui->Render(commandList);\n\n    PIXEndEvent(commandList);\n\n    // Show the new frame.\n    PIXBeginEvent(PIX_COLOR_DEFAULT, L\"Present\");\n    m_deviceResources->Present();\n    m_graphicsMemory->Commit(m_deviceResources->GetCommandQueue());\n    PIXEndEvent();\n}\n\n// Helper method to clear the back buffers.\nvoid Sample::Clear()\n{\n    auto commandList = m_deviceResources->GetCommandList();\n    PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L\"Clear\");\n\n    // Clear the views.\n    auto rtvDescriptor = m_deviceResources->GetRenderTargetView();\n    auto dsvDescriptor = m_deviceResources->GetDepthStencilView();\n\n    commandList->OMSetRenderTargets(1, &rtvDescriptor, FALSE, &dsvDescriptor);\n    commandList->ClearRenderTargetView(rtvDescriptor, ATG::Colors::Background, 0, nullptr);\n    commandList->ClearDepthStencilView(dsvDescriptor, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);\n\n    // Set the viewport and scissor rect.\n    auto viewport = m_deviceResources->GetScreenViewport();\n    auto scissorRect = m_deviceResources->GetScissorRect();\n    commandList->RSSetViewports(1, &viewport);\n    commandList->RSSetScissorRects(1, &scissorRect);\n\n    PIXEndEvent(commandList);\n}\n#pragma endregion\n\n#pragma region Message Handlers\n// Message handlers\nvoid Sample::OnActivated()\n{\n}\n\nvoid Sample::OnDeactivated()\n{\n}\n\n\nvoid Sample::AddLog(const std::string& str)\n{\n    m_liveInfoHUD->AddLog(str);\n}\n\nvoid CALLBACK HandleXblRealTimeActivityConnectionStateChange(\n    _In_opt_ void* context,\n    _In_ XblRealTimeActivityConnectionState connectionState\n    )\n{\n    UNREFERENCED_PARAMETER(context);\n    if (connectionState == XblRealTimeActivityConnectionState::Connected)\n    {\n        g_sample->AddLog(DebugFormat(\"RTA connected\"));\n    }\n    if (connectionState == XblRealTimeActivityConnectionState::Connecting)\n    {\n        g_sample->AddLog(DebugFormat(\"RTA connecting\"));\n    }\n    if (connectionState == XblRealTimeActivityConnectionState::Disconnected)\n    {\n        g_sample->AddLog(DebugFormat(\"RTA disconnected\"));\n    }\n}\n\nvoid Sample::SetUserHandle(XUserHandle user)\n{\n    if (m_userHandle1 != nullptr)\n    {\n        XblContextCloseHandle(m_xblContext);\n        XUserCloseHandle(m_userHandle1);\n    }\n    m_userHandle1 = user;\n    if (m_userHandle1 != nullptr)\n    {\n        HRESULT hr = XblContextCreateHandle(m_userHandle1, &m_xblContext);\n        if (FAILED(hr))\n        {\n            g_sample->AddLog(DebugFormat(\"XblContextCreateHandle 0x%0.8x\", hr));\n        }\n        else\n        {\n            hr = XblRealTimeActivityAddConnectionStateChangeHandler(m_xblContext, HandleXblRealTimeActivityConnectionStateChange, nullptr);\n            g_sample->AddLog(DebugFormat(\"XblRealTimeActivityAddConnectionStateChangeHandler 0x%0.8x\", hr));\n        }\n    }\n}\n\nHRESULT Sample::AddUser(XUserAddOptions options)\n{\n    // Attempt to get the default user, i.e. the user who launched the game\n    auto async = new XAsyncBlock{};\n\n    //async->context = (void*)options;\n    async->callback = [](XAsyncBlock* async)\n    {\n        //int x = static_cast<int>(reinterpret_cast<std::uintptr_t>(async->context));\n        //XUserAddOptions options = (XUserAddOptions)x;\n        XUserHandle user = nullptr;\n        HRESULT result = XUserAddResult(async, &user);\n        if (SUCCEEDED(result))\n        {\n            // This failure doesn't come up until you try to actually do something with the user\n            uint64_t xuid = {};\n            if (FAILED(result = XUserGetId(user, &xuid)))\n            {\n                g_sample->AddLog(DebugFormat(\"User ResolveUserIssueWithUI 0x%0.8x\", result));\n                //ResolveUserIssueWithUI(user);\n            }\n            else\n            {\n                XUserLocalId userLocalId = {};\n                XUserGetLocalId(user, &userLocalId);\n\n                g_sample->AddLog(DebugFormat(\"Got XUserHandle 0x%0.8x. userLocalId: %ull, xuid: 0x%0.8x\", user, userLocalId.value, xuid));\n                g_sample->SetUserHandle(user);\n                //OnSignInCompleted(ATG::XboxHandle<XUserHandle>{user});\n            }\n        }\n        else if (result == E_GAMEUSER_RESOLVE_USER_ISSUE_REQUIRED\n            || result == E_GAMEUSER_NO_DEFAULT_USER\n            || result == static_cast<HRESULT>(0x8015DC12))\n        {\n            g_sample->AddLog(DebugFormat(\"User SwitchUser 0x%0.8x\", result));\n            g_sample->AddUser(XUserAddOptions::AllowGuests);\n        }\n        else\n        {\n            g_sample->AddLog(DebugFormat(\"User HandleError 0x%0.8x\", result));\n            //HandleError(result);\n        }\n\n        delete async;\n    };\n\n    HRESULT hr = XUserAddAsync(\n        options,\n        async\n    );\n    g_sample->AddLog(DebugFormat(\"XUserAddAsync 0x%0.8x\", hr));\n\n    if (FAILED(hr))\n    {\n        g_sample->AddLog(\"Unable to add user!\");\n\n        delete async;\n        return hr;\n    }\n\n    return S_OK;\n}\n\nvoid Sample::OnSuspending()\n{\n    m_liveInfoHUD->AddLog(\"PLM resuming\");\n    m_deviceResources->Suspend();\n}\n\nvoid Sample::OnResuming()\n{\n    m_liveInfoHUD->AddLog(\"PLM resuming\");\n    //AddUser(XUserAddOptions::AddDefaultUserSilently);\n\n    m_deviceResources->Resume();\n    m_timer.ResetElapsedTime();\n    m_gamePadButtons.Reset();\n    m_keyboardButtons.Reset();\n}\n\nvoid Sample::OnWindowMoved()\n{\n    auto r = m_deviceResources->GetOutputSize();\n    m_deviceResources->WindowSizeChanged(r.right, r.bottom);\n}\n\nvoid Sample::OnWindowSizeChanged(int width, int height)\n{\n    if (!m_deviceResources->WindowSizeChanged(width, height))\n        return;\n\n    CreateWindowSizeDependentResources();\n}\n\n// Properties\nvoid Sample::GetDefaultSize(int& width, int& height) const noexcept\n{\n    width = 1840;\n    height = 1035;\n}\n#pragma endregion\n\n#pragma region Direct3D Resources\n// These are the resources that depend on the device.\nvoid Sample::CreateDeviceDependentResources()\n{\n    auto device = m_deviceResources->GetD3DDevice();\n\n#ifdef _GAMING_DESKTOP\n    D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = { D3D_SHADER_MODEL_6_0 };\n    if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, sizeof(shaderModel)))\n        || (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_0))\n    {\n#ifdef _DEBUG\n        OutputDebugStringA(\"ERROR: Shader Model 6.0 is not supported!\\n\");\n#endif\n        throw std::runtime_error(\"Shader Model 6.0 is not supported!\");\n    }\n#endif\n\n    m_graphicsMemory = std::make_unique<GraphicsMemory>(device);\n\n    RenderTargetState rtState(m_deviceResources->GetBackBufferFormat(), m_deviceResources->GetDepthBufferFormat());\n\n    m_resourceDescriptors = std::make_unique<DirectX::DescriptorPile>(device,\n        Descriptors::Count,\n        Descriptors::Reserve\n        );\n\n    ResourceUploadBatch resourceUpload(device);\n    resourceUpload.Begin();\n\n    m_liveInfoHUD->RestoreDevice(device, rtState, resourceUpload, *m_resourceDescriptors);\n\n    wchar_t font[260];\n    wchar_t background[260];\n\n    DX::FindMediaFile(font, 260, L\"courier_16.spritefont\");\n    DX::FindMediaFile(background, 260, L\"ATGSampleBackground.DDS\");\n\n    m_log->RestoreDevice(\n        device,\n        resourceUpload,\n        rtState,\n        font,\n        background,\n        m_resourceDescriptors->GetCpuHandle(Descriptors::Font),\n        m_resourceDescriptors->GetGpuHandle(Descriptors::Font),\n        m_resourceDescriptors->GetCpuHandle(Descriptors::Background),\n        m_resourceDescriptors->GetGpuHandle(Descriptors::Background)\n    );\n\n    m_display->RestoreDevice(\n        device,\n        resourceUpload,\n        rtState,\n        font,\n        background,\n        m_resourceDescriptors->GetCpuHandle(Descriptors::ConsoleFont),\n        m_resourceDescriptors->GetGpuHandle(Descriptors::ConsoleFont),\n        m_resourceDescriptors->GetCpuHandle(Descriptors::ConsoleBackground),\n        m_resourceDescriptors->GetGpuHandle(Descriptors::ConsoleBackground)\n    );\n\n    m_ui->RestoreDevice(device, rtState, resourceUpload, *m_resourceDescriptors);\n\n    auto uploadResourcesFinished = resourceUpload.End(m_deviceResources->GetCommandQueue());\n    uploadResourcesFinished.wait();\n}\n\nvoid ScaleRect(const RECT &originalDisplayRect, const RECT &displayRect, const RECT &originalSubRect, RECT &scaledSubRect)\n{\n    const float widthScale = ((float)displayRect.right - (float)displayRect.left) / ((float)originalDisplayRect.right - (float)originalDisplayRect.left);\n    const float heightScale = ((float)displayRect.bottom - (float)displayRect.top) / ((float)originalDisplayRect.bottom - (float)originalDisplayRect.top);\n\n    scaledSubRect.top = (LONG)((float)originalSubRect.top * heightScale);\n    scaledSubRect.left = (LONG)((float)originalSubRect.left * widthScale);\n    scaledSubRect.bottom = (LONG)((float)originalSubRect.bottom * heightScale);\n    scaledSubRect.right = (LONG)((float)originalSubRect.right * widthScale);\n}\n\n// Allocate all memory resources that change on a window SizeChanged event.\nvoid Sample::CreateWindowSizeDependentResources()\n{\n    RECT fullscreen = m_deviceResources->GetOutputSize();\n    auto viewport = m_deviceResources->GetScreenViewport();\n\n    m_liveInfoHUD->SetViewport(viewport);\n\n    // Scaled for 1920x1080\n    static const RECT originalScale = { 0, 0, 1920, 1080 };\n    static const RECT screenDisplay = { 960, 200, 1780, 450 };\n    RECT scaledDisplay;\n    ScaleRect(originalScale, fullscreen, screenDisplay, scaledDisplay);\n\n    m_log->SetWindow(scaledDisplay, false);\n    m_log->SetViewport(viewport);\n\n    // Scaled for 1920x1080\n    static const RECT screenDisplay2 = { 960, 500, 1780, 950 };\n    ScaleRect(originalScale, fullscreen, screenDisplay2, scaledDisplay);\n\n    m_display->SetWindow(scaledDisplay, false);\n    m_display->SetViewport(viewport);\n\n    m_ui->SetWindow(fullscreen);\n}\n\nvoid Sample::OnDeviceLost()\n{\n    m_ui->ReleaseDevice();\n    m_graphicsMemory.reset();\n    m_liveInfoHUD->ReleaseDevice();\n    m_resourceDescriptors.reset();\n}\n\nvoid Sample::OnDeviceRestored()\n{\n    CreateDeviceDependentResources();\n\n    CreateWindowSizeDependentResources();\n}\n#pragma endregion\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/ManualTest.h",
    "content": "//--------------------------------------------------------------------------------------\n// ManualTest.h\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include \"DeviceResources.h\"\n#include \"LiveResources.h\"\n#include \"SampleLiveInfoHUD.h\"\n#include \"StepTimer.h\"\n#include \"SampleGUI.h\"\n#include \"TextConsole.h\"\n\n\n// A basic sample implementation that creates a D3D12 device and\n// provides a render loop.\nclass Sample final : public DX::IDeviceNotify\n{\npublic:\n\n    Sample() noexcept(false);\n    ~Sample();\n\n    Sample(Sample&&) = default;\n    Sample& operator= (Sample&&) = default;\n\n    Sample(Sample const&) = delete;\n    Sample& operator= (Sample const&) = delete;\n\n    // Initialization and management\n    void Initialize(HWND window, int width, int height);\n\n    // Basic render loop\n    void Tick();\n\n    // IDeviceNotify\n    void OnDeviceLost() override;\n    void OnDeviceRestored() override;\n\n    // Messages\n    void OnActivated();\n    void OnDeactivated();\n    void OnSuspending();\n    void OnResuming();\n    void OnWindowMoved();\n    void OnWindowSizeChanged(int width, int height);\n\n    // Properties\n    void GetDefaultSize(int& width, int& height) const noexcept;\n\n    HRESULT AddUser(XUserAddOptions options);\n    void AddLog(const std::string& str);\n    void SetUserHandle(XUserHandle user);\n    void CreateSession();\n    void WriteSession();\n\nprivate:\n\n    void Update(DX::StepTimer const& timer);\n    void Render();\n\n    void Clear();\n\n    void CreateDeviceDependentResources();\n    void CreateWindowSizeDependentResources();\n\n\n    void SetupUI();\n\n    // Device resources.\n    std::unique_ptr<DX::DeviceResources>        m_deviceResources;\n\n    // Rendering loop timer.\n    uint64_t                                    m_frame;\n    DX::StepTimer                               m_timer;\n\n    // Input devices.\n    std::unique_ptr<DirectX::GamePad>           m_gamePad;\n    std::unique_ptr<DirectX::Keyboard>          m_keyboard;\n    std::unique_ptr<DirectX::Mouse>             m_mouse;\n\n    DirectX::GamePad::ButtonStateTracker        m_gamePadButtons;\n    DirectX::Keyboard::KeyboardStateTracker     m_keyboardButtons;\n    DirectX::Keyboard::KeyboardStateTracker     m_keyboardButtonsLast;\n\n    // DirectXTK objects.\n    std::unique_ptr<DirectX::GraphicsMemory>    m_graphicsMemory;\n    std::unique_ptr<DirectX::DescriptorPile>    m_resourceDescriptors;\n\n    std::unique_ptr<ATG::SampleLiveInfoHUD>           m_liveInfoHUD;\n\n    XTaskQueueHandle                            m_mainAsyncQueue;\n\n    // UI Objects\n    std::unique_ptr<ATG::UIManager>             m_ui;\n    std::unique_ptr<DX::TextConsoleImage>       m_log;\n    std::unique_ptr<DX::TextConsoleImage>       m_display;\n\n    XUserHandle m_userHandle1 = nullptr;\n    XblContextHandle m_xblContext = nullptr;\n    bool m_xblInit = false;\n    bool m_xblRTA = false;\n    XblMultiplayerSessionHandle m_currentSessionHandle = nullptr;\n\n    enum Descriptors\n    {\n        Font,\n        ConsoleFont,\n        Background,\n        ConsoleBackground,\n        Reserve,\n        Count = 32,\n    };\n};\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/ManualTest.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.32802.440\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"ManualTest\", \"ManualTest.vcxproj\", \"{A501FE41-49C6-4ED4-9711-1C7231784849}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"DirectXTK12\", \"..\\APIRunner.GDK\\Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\", \"{49F83A6D-D2A5-44C4-B84F-786E9F292499}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Gaming.Desktop.x64 = Debug|Gaming.Desktop.x64\n\t\tDebug|Gaming.Xbox.Scarlett.x64 = Debug|Gaming.Xbox.Scarlett.x64\n\t\tDebug|Gaming.Xbox.XboxOne.x64 = Debug|Gaming.Xbox.XboxOne.x64\n\t\tProfile|Gaming.Desktop.x64 = Profile|Gaming.Desktop.x64\n\t\tProfile|Gaming.Xbox.Scarlett.x64 = Profile|Gaming.Xbox.Scarlett.x64\n\t\tProfile|Gaming.Xbox.XboxOne.x64 = Profile|Gaming.Xbox.XboxOne.x64\n\t\tRelease|Gaming.Desktop.x64 = Release|Gaming.Desktop.x64\n\t\tRelease|Gaming.Xbox.Scarlett.x64 = Release|Gaming.Xbox.Scarlett.x64\n\t\tRelease|Gaming.Xbox.XboxOne.x64 = Release|Gaming.Xbox.XboxOne.x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Desktop.x64.Deploy.0 = Debug|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Xbox.Scarlett.x64.Deploy.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Debug|Gaming.Xbox.XboxOne.x64.Deploy.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Desktop.x64.ActiveCfg = Profile|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Desktop.x64.Build.0 = Profile|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Desktop.x64.Deploy.0 = Profile|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Xbox.Scarlett.x64.Deploy.0 = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Profile|Gaming.Xbox.XboxOne.x64.Deploy.0 = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Desktop.x64.Deploy.0 = Release|Gaming.Desktop.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Xbox.Scarlett.x64.Deploy.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{A501FE41-49C6-4ED4-9711-1C7231784849}.Release|Gaming.Xbox.XboxOne.x64.Deploy.0 = Release|Gaming.Xbox.XboxOne.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Debug|Gaming.Desktop.x64.ActiveCfg = Debug|Gaming.Desktop.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Debug|Gaming.Desktop.x64.Build.0 = Debug|Gaming.Desktop.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Profile|Gaming.Desktop.x64.ActiveCfg = Profile|Gaming.Desktop.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Profile|Gaming.Desktop.x64.Build.0 = Profile|Gaming.Desktop.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Profile|Gaming.Xbox.Scarlett.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Profile|Gaming.Xbox.XboxOne.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Release|Gaming.Desktop.x64.ActiveCfg = Release|Gaming.Desktop.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Release|Gaming.Desktop.x64.Build.0 = Release|Gaming.Desktop.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64\n\t\t{49F83A6D-D2A5-44C4-B84F-786E9F292499}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {613F8626-6BFE-415A-A22D-4BA72EC62705}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/ManualTest.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.Scarlett.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.Scarlett.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Xbox.XboxOne.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Xbox.XboxOne.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Gaming.Desktop.x64\">\n      <Configuration>Release</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Profile|Gaming.Desktop.x64\">\n      <Configuration>Profile</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Gaming.Desktop.x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>Gaming.Desktop.x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <RootNamespace>ManualTest</RootNamespace>\n    <ProjectGuid>{a501fe41-49c6-4ed4-9711-1c7231784849}</ProjectGuid>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <Keyword>Win32Proj</Keyword>\n    <!-- - - - -->\n    <MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>\n    <TargetRuntime>Native</TargetRuntime>\n    <GDKExtLibNames>Xbox.Services.API.C</GDKExtLibNames>\n    <PreferredToolArchitecture>x64</PreferredToolArchitecture>\n  </PropertyGroup>\n  <Import Condition=\"Exists($(ATGBuildProps))\" Project=\"$(ATGBuildProps)\" />\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <EmbedManifest>false</EmbedManifest>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v142</PlatformToolset>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>\n    <LibraryPath>$(Console_SdkLibPath)</LibraryPath>\n    <LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>\n    <IncludePath>$(Console_SdkIncludeRoot)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <LibraryPath>$(Console_SdkLibPath);$(LibraryPath)</LibraryPath>\n    <IncludePath>$(Console_SdkIncludeRoot);$(IncludePath)</IncludePath>\n    <ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath)</ExecutablePath>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories />\n      <ForcedUsingFiles />\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">\n    <Link>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AdditionalUsingDirectories>\n      </AdditionalUsingDirectories>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>6.0</ShaderModel>\n      <EnableDebuggingInformation>true</EnableDebuggingInformation>\n      <AdditionalOptions>/Fd \"$(OutDir)%(Filename).pdb\" %(AdditionalOptions)</AdditionalOptions>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <Optimization>MaxSpeed</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;NDEBUG;__WRL_NO_DEFAULT_LIB__;PROFILE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <WarningLevel>Level4</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>6.0</ShaderModel>\n      <EnableDebuggingInformation>true</EnableDebuggingInformation>\n      <AdditionalOptions>/Fd \"$(OutDir)%(Filename).pdb\" %(AdditionalOptions)</AdditionalOptions>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>uuid.lib;$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n    <ClCompile>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <MinimalRebuild>false</MinimalRebuild>\n      <AdditionalIncludeDirectories>$(ProjectDir);..\\APIRunner.GDK\\Kits\\LiveTK;..\\APIRunner.GDK\\Kits\\DirectXTK12\\Inc;..\\APIRunner.GDK\\Kits\\ATGTK;..\\APIRunner.GDK\\Kits\\ATGTelemetry\\GDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <WarningLevel>Level4</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>ATG_ENABLE_TELEMETRY;_DEBUG;__WRL_NO_DEFAULT_LIB__;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>5204</DisableSpecificWarnings>\n    </ClCompile>\n    <FXCompile>\n      <ShaderModel>6.0</ShaderModel>\n      <EnableDebuggingInformation>true</EnableDebuggingInformation>\n      <AdditionalOptions>/Fd \"$(OutDir)%(Filename).pdb\" %(AdditionalOptions)</AdditionalOptions>\n    </FXCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup>\n    <CopyFileToFolders>\n      <DestinationFolders>$(OutDir)Assets</DestinationFolders>\n    </CopyFileToFolders>\n    <PostBuildEvent>\n      <Command Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">xcopy /Y /I /E \"$(ProjectDir)Assets\\*.*\" \"$(TargetDir)Assets\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\*.*\" \"$(TargetDir)Media\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Fonts\\*.*\" \"$(TargetDir)\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Textures\\*.*\" \"$(TargetDir)\"</Command>\n    </PostBuildEvent>\n    <PostBuildEvent>\n      <Command Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">xcopy /Y /I /E \"$(ProjectDir)Assets\\*.*\" \"$(TargetDir)Assets\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\*.*\" \"$(TargetDir)Media\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Fonts\\*.*\" \"$(TargetDir)\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Textures\\*.*\" \"$(TargetDir)\"</Command>\n    </PostBuildEvent>\n    <PostBuildEvent>\n      <Command Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">xcopy /Y /I /E \"$(ProjectDir)Assets\\*.*\" \"$(TargetDir)Assets\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\*.*\" \"$(TargetDir)Media\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Fonts\\*.*\" \"$(TargetDir)\" &amp; xcopy /Y /I /E \"$(ProjectDir)Media\\Textures\\*.*\" \"$(TargetDir)\"</Command>\n    </PostBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\ControllerFont.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\CSVReader.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\SampleGUI.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\TextConsole.h\" />\n    <ClInclude Include=\"ManualTest.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"SampleLiveInfoHUD.h\" />\n    <ClInclude Include=\"StepTimer.h\" />\n    <ClInclude Include=\"DeviceResources.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\StringUtil.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\Json.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\json\\json.hpp\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\ATGColors.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\d3dx12.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\FindMedia.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\SampleGUI.cpp\" />\n    <ClCompile Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\TextConsole.cpp\" />\n    <ClCompile Include=\"ManualTest.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\" />\n    <ClCompile Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\StringUtil.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.XboxOne.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Xbox.Scarlett.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.XboxOne.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Xbox.Scarlett.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Gaming.Desktop.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Gaming.Desktop.x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Profile|Gaming.Desktop.x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"SampleLiveInfoHUD.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <MGCCompile Include=\"MicrosoftGameConfig.mgc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Media\\Textures\\GamerPic.png\">\n      <DeploymentContent>true</DeploymentContent>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Media\\Fonts\\Courier_16.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\Courier_36.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneController.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Media\\Fonts\\XboxOneControllerSmall.spritefont\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n    <None Include=\"Assets\\SampleUI.csv\">\n      <DeploymentContent>true</DeploymentContent>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Assets\\Logo.png\">\n      <DeploymentContent>true</DeploymentContent>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Assets\\LargeLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Assets\\SmallLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Assets\\SplashScreen.png\">\n      <DeploymentContent>true</DeploymentContent>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Assets\\StoreLogo.png\">\n      <DeploymentContent>true</DeploymentContent>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Media\\Textures\\ATGSampleBackground.DDS\">\n      <DeploymentContent>true</DeploymentContent>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\APIRunner.GDK\\Kits\\DirectXTK12\\DirectXTK12_GDK_2017.vcxproj\">\n      <Project>{49f83a6d-d2a5-44c4-b84f-786e9f292499}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/ManualTest.vcxproj.filters",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Common\">\n      <UniqueIdentifier>d0a754c7-880c-4d67-8324-08611b7402c1</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Assets\">\n      <UniqueIdentifier>d99f4f2b-95af-447b-9a87-a5636e45af50</UniqueIdentifier>\n      <Extensions>ico;cur;bmp;dds;dlg;fbx;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"ATG Tool Kit\">\n      <UniqueIdentifier>655550be-56fc-4265-8a51-5c51c987dea5</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Xbox Live Tool Kit\">\n      <UniqueIdentifier>003f9d58-a022-48a0-bad6-143a8dfa78c2</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"External\">\n      <UniqueIdentifier>396f274a-6b80-4569-a46f-bc59173d9d04</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"ReadMe\">\n      <UniqueIdentifier>{b6361f05-2e9f-4f2f-b537-15bf9ca05024}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"ManualTest.h\" />\n    <ClInclude Include=\"StepTimer.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DeviceResources.h\">\n      <Filter>Common</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SampleLiveInfoHUD.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\ControllerFont.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\CSVReader.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\SampleGUI.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\TextConsole.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\StringUtil.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\Json.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\json\\json.hpp\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\ATGColors.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\d3dx12.h\" />\n    <ClInclude Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\FindMedia.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"pch.cpp\" />\n    <ClCompile Include=\"ManualTest.cpp\" />\n    <ClCompile Include=\"Main.cpp\" />\n    <ClCompile Include=\"DeviceResources.cpp\">\n      <Filter>Common</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SampleLiveInfoHUD.cpp\" />\n    <ClCompile Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\SampleGUI.cpp\" />\n    <ClCompile Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\TextConsole.cpp\" />\n    <ClCompile Include=\"..\\APIRunner.GDK\\Kits\\ATGTK\\StringUtil.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <MGCCompile Include=\"MicrosoftGameConfig.mgc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Assets\\SampleUI.csv\">\n      <Filter>Assets</Filter>\n    </None>\n    <None Include=\"Media\\Fonts\\Courier_16.spritefont\" />\n    <None Include=\"Media\\Fonts\\XboxOneController.spritefont\" />\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegend.spritefont\" />\n    <None Include=\"Media\\Fonts\\XboxOneControllerLegendSmall.spritefont\" />\n    <None Include=\"Media\\Fonts\\XboxOneControllerSmall.spritefont\" />\n    <None Include=\"Media\\Fonts\\Courier_36.spritefont\" />\n  </ItemGroup>\n  <ItemGroup>\n    <CopyFileToFolders Include=\"Assets\\Logo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\LargeLogo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SmallLogo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\SplashScreen.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Assets\\StoreLogo.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n    <CopyFileToFolders Include=\"Media\\Textures\\GamerPic.png\">\n      <Filter>Assets</Filter>\n    </CopyFileToFolders>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Media\\Textures\\ATGSampleBackground.DDS\">\n      <Filter>Assets</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <Font Include=\"Media\\Fonts\\SegoeUI_36_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_18.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_18_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_18_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_22.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_22_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_22_Italic.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_36.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n    <Font Include=\"Media\\Fonts\\SegoeUI_36_Bold.spritefont\">\n      <Filter>Assets</Filter>\n    </Font>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/MicrosoftGameConfig.mgc",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Game configVersion=\"1\">\n  <!-- Version \"1\" is supported by March 2022 GDK or later -->\n\n    <Identity Name=\"41336MicrosoftATG.NetRumble2\" Publisher=\"CN=A4954634-DF4B-47C7-AB70-D3215D246AF1\" Version=\"1.0.1.0\"/>\n\n    <ExecutableList>\n    <Executable Name=\"ManualTest.exe\"\n                Id=\"Game\"/>\n  </ExecutableList>\n\n  <TitleId>76b1590E</TitleId>\n  <MSAAppId>0000000044264AE3</MSAAppId>\n\n  <ShellVisuals DefaultDisplayName=\"ATG ManualTest Sample\"\n                PublisherDisplayName=\"Xbox ATG\"\n                StoreLogo=\"Assets\\StoreLogo.png\"\n                Square480x480Logo=\"Assets\\LargeLogo.png\"\n                Square150x150Logo=\"Assets\\Logo.png\"\n                Square44x44Logo=\"Assets\\SmallLogo.png\"\n                Description=\"ManualTest\"\n                ForegroundText=\"dark\"\n                BackgroundColor=\"#000000\"\n                SplashScreenImage=\"Assets\\SplashScreen.png\"/>\n</Game>\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/SampleLiveInfoHUD.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: LiveInfoHUD.cpp\n//\n// A Heads Up Display (HUD) for Xbox Live samples\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n#include \"pch.h\"\n#include \"SampleLiveInfoHUD.h\"\n\n#include <XGame.h>\n#include <XSystem.h>\n\n#include \"DescriptorHeap.h\"\n#include \"DirectXHelpers.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"WICTextureLoader.h\"\n\n#include \"ATGColors.h\"\n#include \"FindMedia.h\"\n\nusing namespace ATG;\nusing namespace DirectX;\n\nnamespace\n{\n    const size_t c_GamerPicBuffer = 1024 * 16;\n    constexpr float c_StatusBarCoordinate = 1010.0f;\n    constexpr float c_HeaderBarCoordinate = 10.0f;\n    constexpr long c_GamerPicCoordinate = long(c_HeaderBarCoordinate) + 11;\n}\n\n_Use_decl_annotations_\nSampleLiveInfoHUD::SampleLiveInfoHUD(char const* sampleTitle) noexcept(false) :\n    m_sampleTitle(sampleTitle),\n    m_gamerTag(\"No User Signed in\"),\n    m_scaleWidth(1.f),\n    m_scaleHeight(1.f),\n    m_gamerPicCPU{},\n    m_gamerPicGPU{},\n    m_gamerPicDataSize(0),\n    m_gamerPicReady(false)\n{\n\n}\n\nvoid SampleLiveInfoHUD::Initialize(int windowWidth, int windowHeight)\n{\n    UNREFERENCED_PARAMETER(windowWidth);\n    UNREFERENCED_PARAMETER(windowHeight);\n\n    uint32_t titleId = {};\n    HRESULT hr = XGameGetXboxTitleId(&titleId);\n\n    if (SUCCEEDED(hr))\n    {\n        char hexTitleId[16] = {};\n        sprintf_s(hexTitleId, \"0x%08X\", titleId);\n        m_titleId.assign(hexTitleId);\n\n        char scidBuffer[64] = {};\n        sprintf_s(scidBuffer, \"00000000-0000-0000-0000-0000%08x\", titleId);\n        m_serviceConfigId = scidBuffer;\n    }\n    else\n    {\n        m_titleId = \"Not Set\";\n        m_serviceConfigId = \"Not Set\";\n    }\n\n    char sandboxId[XSystemXboxLiveSandboxIdMaxBytes] = {};\n    XSystemGetXboxLiveSandboxId(XSystemXboxLiveSandboxIdMaxBytes, sandboxId, nullptr);\n    m_sandboxId = sandboxId;\n}\n\nvoid SampleLiveInfoHUD::Update(_In_ ID3D12CommandQueue* commandQueue)\n{\n    if (!m_gamerPicReady || !m_device)\n        return;\n\n    CreateShaderResourceView(m_device.Get(), m_gamerDefaultPic.Get(), m_gamerPicCPU);\n\n    if (m_gamerPicDataSize && m_gamerPicData)\n    {\n        ResourceUploadBatch upload(m_device.Get());\n\n        upload.Begin();\n\n        if (SUCCEEDED(CreateWICTextureFromMemory(m_device.Get(), upload, m_gamerPicData.get(), m_gamerPicDataSize, m_gamerPic.ReleaseAndGetAddressOf())))\n        {\n            CreateShaderResourceView(m_device.Get(), m_gamerPic.Get(), m_gamerPicCPU);\n        }\n\n        auto result = upload.End(commandQueue);\n        result.wait();\n    }\n\n    m_gamerPicReady = false;\n}\n\nvoid SampleLiveInfoHUD::ReleaseDevice()\n{\n    m_gamerPic.Reset();\n    m_gamerDefaultPic.Reset();\n\n    m_device.Reset();\n\n    m_batch.reset();\n    m_smallFont.reset();\n    m_boldFont.reset();\n    m_titleFont.reset();\n\n    m_gamerPicCPU = {};\n    m_gamerPicGPU = {};\n}\n\n_Use_decl_annotations_\nvoid SampleLiveInfoHUD::RestoreDevice(\n    ID3D12Device* device,\n    const RenderTargetState& renderTarget,\n    ResourceUploadBatch& resourceUpload,\n    DescriptorPile& pile)\n{\n    m_device = device;\n\n    SpriteBatchPipelineStateDescription pd(renderTarget);\n    m_batch = std::make_unique<SpriteBatch>(device, resourceUpload, pd);\n\n    wchar_t buff[MAX_PATH] = {};\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"SegoeUI_18.spritefont\");\n    size_t index = pile.Allocate();\n    m_smallFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"SegoeUI_18_Bold.spritefont\");\n    index = pile.Allocate();\n    m_boldFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"SegoeUI_36.spritefont\");\n    index = pile.Allocate();\n    m_titleFont = std::make_unique<SpriteFont>(device, resourceUpload, buff, pile.GetCpuHandle(index), pile.GetGpuHandle(index));\n\n    DX::FindMediaFile(buff, MAX_PATH, L\"GamerPic.png\");\n    DX::ThrowIfFailed(\n        CreateWICTextureFromFile(device, resourceUpload, buff, m_gamerDefaultPic.ReleaseAndGetAddressOf())\n    );\n\n    index = pile.Allocate();\n    m_gamerPicCPU = pile.GetCpuHandle(index);\n    m_gamerPicGPU = pile.GetGpuHandle(index);\n\n    if (m_gamerPicDataSize > 0 && m_gamerPicData)\n    {\n        m_gamerPicReady = true;\n    }\n\n    CreateShaderResourceView(device, m_gamerDefaultPic.Get(), m_gamerPicCPU);\n}\n\n_Use_decl_annotations_\nvoid SampleLiveInfoHUD::SetUser(XUserHandle user, XTaskQueueHandle queue)\n{\n    if (!user)\n    {\n        m_gamerTag = \"No User Signed in\";\n\n        m_gamerPicDataSize = 0;\n        m_gamerPicData.reset();\n\n        CreateShaderResourceView(m_device.Get(), m_gamerDefaultPic.Get(), m_gamerPicCPU);\n    }\n    else\n    {\n        m_gamerTag.resize(XUserGamertagComponentClassicMaxBytes);\n        if (FAILED(XUserGetGamertag(user, XUserGamertagComponent::Classic, XUserGamertagComponentClassicMaxBytes, &m_gamerTag[0], nullptr)))\n        {\n            m_gamerTag = \"***ERROR***\";\n        }\n\n        auto async = new XAsyncBlock{};\n        async->context = this;\n        async->queue = queue;\n        async->callback = [](XAsyncBlock *async)\n        {\n            auto pThis = reinterpret_cast<SampleLiveInfoHUD*>(async->context);\n\n            pThis->m_gamerPicData.reset(new uint8_t[c_GamerPicBuffer]);\n            size_t bufferFilled = 0;\n\n            HRESULT hr = XUserGetGamerPictureResult(async, c_GamerPicBuffer, pThis->m_gamerPicData.get(), &bufferFilled);\n            if (SUCCEEDED(hr))\n            {\n                pThis->m_gamerPicDataSize = bufferFilled;\n                pThis->m_gamerPicReady = true;\n            }\n            else\n            {\n                pThis->m_gamerPicDataSize = 0;\n                pThis->m_gamerPicData.reset();\n            }\n\n            delete async;\n        };\n\n        DX::ThrowIfFailed(XUserGetGamerPictureAsync(user, XUserGamerPictureSize::Small, async));\n    }\n}\n\nvoid SampleLiveInfoHUD::ClearLog()\n{\n    std::lock_guard<std::mutex> lock(m_logLinesMutex);\n    m_logLines.clear();\n}\n\nvoid WriteLogToFile(const std::string& strIn)\n{\n    HANDLE hFile;\n    std::string str = strIn;\n    str += \"\\r\\n\";\n    DWORD dwBytesToWrite = (DWORD) str.length();\n    DWORD dwBytesWritten = 0;\n    BOOL bErrorFlag = FALSE;\n\n    hFile = CreateFile(L\"D:\\\\EventsLog.txt\", FILE_APPEND_DATA, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n    if (hFile == INVALID_HANDLE_VALUE)\n    {\n        return;\n    }\n\n    bErrorFlag = WriteFile(\n        hFile,           // open file handle\n        str.data(),      // start of data to write\n        dwBytesToWrite,  // number of bytes to write\n        &dwBytesWritten, // number of bytes that were written\n        NULL);            // no overlapped structure\n\n    if (FALSE == bErrorFlag)\n    {\n    }\n    else\n    {\n        if (dwBytesWritten != dwBytesToWrite)\n        {\n            //printf(\"Error: dwBytesWritten != dwBytesToWrite\\n\");\n        }\n        else\n        {\n            //printf(\"Wrote %d bytes to EventsLog.txt successfully.\\n\", dwBytesWritten);\n        }\n    }\n\n    CloseHandle(hFile);\n}\n\nvoid SampleLiveInfoHUD::AddLog(const std::string& strIn)\n{\n    std::lock_guard<std::mutex> lock(m_logLinesMutex);\n\n    SYSTEMTIME st;\n    GetLocalTime(&st);\n    char sz[255];\n    sprintf_s(sz, 255, \"[%0.2d/%0.2d %0.2d:%0.2d:%0.2d:%0.4d] \",\n        st.wMonth, st.wDay,\n        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);\n\n    std::string strTime = sz;\n    std::string str = strTime + strIn;\n\n    for (size_t i = 0; i < str.length(); i++)\n    {\n        if (static_cast<unsigned char>(str[i]) > 0x80) // ignore invalid chars since font can't render\n        {\n            str[i] = ' ';\n        }\n    }\n\n    OutputDebugStringA(str.c_str());\n    OutputDebugStringA(\"\\n\");\n\n    if (m_logLines.size() > 27)\n    {\n        m_logLines.erase(m_logLines.begin());\n    }\n    m_logLines.push_back(str);\n    WriteLogToFile(str);\n\n}\n\n_Use_decl_annotations_\nvoid SampleLiveInfoHUD::Render(ID3D12GraphicsCommandList* commandList)\n{\n    m_batch->Begin(\n        commandList,\n        SpriteSortMode_Deferred,\n        DirectX::XMMatrixAffineTransformation2D(XMVectorSet(m_scaleWidth, m_scaleHeight, 0, 0), XMVectorZero(), 0.f, XMVectorZero())\n    );\n\n    if(m_logLines.size() > 0)\n    {\n        std::lock_guard<std::mutex> lock(m_logLinesMutex);\n        float y = 100.0f;\n        for (auto& s : m_logLines)\n        {\n            m_smallFont->DrawString(m_batch.get(), s.c_str(), XMFLOAT2(60.f, y), ATG::Colors::White, 0.0f);\n            y += 30.0f;\n        }\n    }\n\n    float y = 800.0f;\n    float x = 1210.0f;\n    m_smallFont->DrawString(m_batch.get(), \"Press 1 for XblInit. Ctrl+1 for XblCleanup\", XMFLOAT2(x, y += 30.0f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), \"Press 2 for XUserAdd. Ctrl+2 for UserClose\", XMFLOAT2(x, y += 30.0f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), \"Press 3 for RTA on. Ctrl+3 for RTA off\", XMFLOAT2(x, y += 30.0f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), \"Press 4 for CreateSession. Ctrl+4 for session close\", XMFLOAT2(x, y += 30.0f), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), \"Press 5 for WriteSession\", XMFLOAT2(x, y += 30.0f), ATG::Colors::OffWhite, 0.0f);\n\n    m_boldFont->DrawString(m_batch.get(), \"Sandbox Id:\", XMFLOAT2(270.f, c_StatusBarCoordinate), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), m_sandboxId.c_str(), XMFLOAT2(410.f, c_StatusBarCoordinate), ATG::Colors::OffWhite, 0.0f);\n\n    m_boldFont->DrawString(m_batch.get(), \"Title Id:\", XMFLOAT2(590.f, c_StatusBarCoordinate), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), m_titleId.c_str(), XMFLOAT2(680.f, c_StatusBarCoordinate), ATG::Colors::OffWhite, 0.0f);\n\n    m_boldFont->DrawString(m_batch.get(), \"Service Config Id:\", XMFLOAT2(950.f, c_StatusBarCoordinate), ATG::Colors::OffWhite, 0.0f);\n    m_smallFont->DrawString(m_batch.get(), m_serviceConfigId.c_str(), XMFLOAT2(1155.f, c_StatusBarCoordinate), ATG::Colors::OffWhite, 0.0f);\n\n    m_batch->End();\n}\n\nvoid SampleLiveInfoHUD::SetViewport(const D3D12_VIEWPORT &viewport)\n{\n    if (m_batch)\n    {\n        m_batch->SetViewport(viewport);\n        SetWindowSize(viewport.Width, viewport.Height);\n    }\n}\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/SampleLiveInfoHUD.h",
    "content": "//--------------------------------------------------------------------------------------\n// File: LiveInfoHUD.h\n//\n// A Heads Up Display (HUD) for Xbox Live samples\n//\n// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF\n// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\n// PARTICULAR PURPOSE.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n//-------------------------------------------------------------------------------------\n#pragma once\n\n#include <atomic>\n#include <memory>\n#include <string>\n\n#include <XUser.h>\n\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\nnamespace ATG\n{\n    class SampleLiveInfoHUD\n    {\n    public:\n        explicit SampleLiveInfoHUD(_In_ char const* sampleTitle) noexcept(false);\n\n        void Initialize(int windowWidth = 0, int windowHeight = 0);\n\n        void Update(_In_ ID3D12CommandQueue* commandQueue);\n\n        void ReleaseDevice();\n        void RestoreDevice(_In_ ID3D12Device* context,\n                           const DirectX::RenderTargetState& renderTarget,\n                           DirectX::ResourceUploadBatch& resourceUpload,\n                           DirectX::DescriptorPile& pile);\n\n        void SetUser(_In_opt_ XUserHandle user, _In_ XTaskQueueHandle queue);\n\n        void AddLog(const std::string& str);\n        void ClearLog();\n        void Render(_In_ ID3D12GraphicsCommandList *commandList);\n\n        void SetViewport(const D3D12_VIEWPORT &viewport);\n\n        void SetWindowSize(float width, float height) { m_scaleWidth = width / LAYOUT_PIXEL_WIDTH, m_scaleHeight = height / LAYOUT_PIXEL_HEIGHT; }\n\n    private:\n        SampleLiveInfoHUD(SampleLiveInfoHUD&&) = delete;\n        SampleLiveInfoHUD& operator= (SampleLiveInfoHUD&&) = delete;\n\n        SampleLiveInfoHUD(SampleLiveInfoHUD const&) = delete;\n        SampleLiveInfoHUD& operator= (SampleLiveInfoHUD const&) = delete;\n\n    private:\n        const float                            LAYOUT_PIXEL_WIDTH  = 1920.f;\n        const float                            LAYOUT_PIXEL_HEIGHT = 1080.f;\n\n        std::string                            m_sampleTitle;\n        std::string                            m_serviceConfigId;\n        std::string                            m_titleId;\n        std::string                            m_sandboxId;\n        std::string                            m_gamerTag;\n        Microsoft::WRL::ComPtr<ID3D12Resource> m_gamerPic;\n        Microsoft::WRL::ComPtr<ID3D12Resource> m_gamerDefaultPic;\n\n        Microsoft::WRL::ComPtr<ID3D12Device>   m_device;\n\n        // Direct3D resources\n        std::unique_ptr<DirectX::SpriteBatch>  m_batch;\n        std::unique_ptr<DirectX::SpriteFont>   m_smallFont;\n        std::unique_ptr<DirectX::SpriteFont>   m_boldFont;\n        std::unique_ptr<DirectX::SpriteFont>   m_titleFont;\n        \n        float                                  m_scaleWidth;\n        float                                  m_scaleHeight;\n\n        D3D12_CPU_DESCRIPTOR_HANDLE            m_gamerPicCPU;\n        D3D12_GPU_DESCRIPTOR_HANDLE            m_gamerPicGPU;\n        std::unique_ptr<uint8_t>               m_gamerPicData;\n        size_t                                 m_gamerPicDataSize;\n        std::atomic<bool>                      m_gamerPicReady;\n\n        std::mutex m_logLinesMutex;\n        std::vector<std::string> m_logLines;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/StepTimer.h",
    "content": "//\n// StepTimer.h - A simple timer that provides elapsed time information\n//\n\n#pragma once\n\n#include <cmath>\n#include <cstdint>\n#include <exception>\n\n\nnamespace DX\n{\n    // Helper class for animation and simulation timing.\n    class StepTimer\n    {\n    public:\n        StepTimer() noexcept(false) :\n            m_elapsedTicks(0),\n            m_totalTicks(0),\n            m_leftOverTicks(0),\n            m_frameCount(0),\n            m_framesPerSecond(0),\n            m_framesThisSecond(0),\n            m_qpcSecondCounter(0),\n            m_isFixedTimeStep(false),\n            m_targetElapsedTicks(TicksPerSecond / 60)\n        {\n            if (!QueryPerformanceFrequency(&m_qpcFrequency))\n            {\n                throw std::exception();\n            }\n\n            if (!QueryPerformanceCounter(&m_qpcLastTime))\n            {\n                throw std::exception();\n            }\n\n            // Initialize max delta to 1/10 of a second.\n            m_qpcMaxDelta = static_cast<uint64_t>(m_qpcFrequency.QuadPart / 10);\n        }\n\n        // Get elapsed time since the previous Update call.\n        uint64_t GetElapsedTicks() const noexcept { return m_elapsedTicks; }\n        double GetElapsedSeconds() const noexcept { return TicksToSeconds(m_elapsedTicks); }\n\n        // Get total time since the start of the program.\n        uint64_t GetTotalTicks() const noexcept { return m_totalTicks; }\n        double GetTotalSeconds() const noexcept { return TicksToSeconds(m_totalTicks); }\n\n        // Get total number of updates since start of the program.\n        uint32_t GetFrameCount() const noexcept { return m_frameCount; }\n\n        // Get the current framerate.\n        uint32_t GetFramesPerSecond() const noexcept { return m_framesPerSecond; }\n\n        // Set whether to use fixed or variable timestep mode.\n        void SetFixedTimeStep(bool isFixedTimestep) noexcept { m_isFixedTimeStep = isFixedTimestep; }\n\n        // Set how often to call Update when in fixed timestep mode.\n        void SetTargetElapsedTicks(uint64_t targetElapsed) noexcept { m_targetElapsedTicks = targetElapsed; }\n        void SetTargetElapsedSeconds(double targetElapsed) noexcept { m_targetElapsedTicks = SecondsToTicks(targetElapsed); }\n\n        // Integer format represents time using 10,000,000 ticks per second.\n        static constexpr uint64_t TicksPerSecond = 10000000;\n\n        static constexpr double TicksToSeconds(uint64_t ticks) noexcept { return static_cast<double>(ticks) / TicksPerSecond; }\n        static constexpr uint64_t SecondsToTicks(double seconds) noexcept { return static_cast<uint64_t>(seconds * TicksPerSecond); }\n\n        // After an intentional timing discontinuity (for instance a blocking IO operation)\n        // call this to avoid having the fixed timestep logic attempt a set of catch-up\n        // Update calls.\n\n        void ResetElapsedTime()\n        {\n            if (!QueryPerformanceCounter(&m_qpcLastTime))\n            {\n                throw std::exception();\n            }\n\n            m_leftOverTicks = 0;\n            m_framesPerSecond = 0;\n            m_framesThisSecond = 0;\n            m_qpcSecondCounter = 0;\n        }\n\n        // Update timer state, calling the specified Update function the appropriate number of times.\n        template<typename TUpdate>\n        void Tick(const TUpdate& update)\n        {\n            // Query the current time.\n            LARGE_INTEGER currentTime;\n\n            if (!QueryPerformanceCounter(&currentTime))\n            {\n                throw std::exception();\n            }\n\n            uint64_t timeDelta = static_cast<uint64_t>(currentTime.QuadPart - m_qpcLastTime.QuadPart);\n\n            m_qpcLastTime = currentTime;\n            m_qpcSecondCounter += timeDelta;\n\n            // Clamp excessively large time deltas (e.g. after paused in the debugger).\n            if (timeDelta > m_qpcMaxDelta)\n            {\n                timeDelta = m_qpcMaxDelta;\n            }\n\n            // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.\n            timeDelta *= TicksPerSecond;\n            timeDelta /= static_cast<uint64_t>(m_qpcFrequency.QuadPart);\n\n            uint32_t lastFrameCount = m_frameCount;\n\n            if (m_isFixedTimeStep)\n            {\n                // Fixed timestep update logic\n\n                // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp\n                // the clock to exactly match the target value. This prevents tiny and irrelevant errors\n                // from accumulating over time. Without this clamping, a game that requested a 60 fps\n                // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually\n                // accumulate enough tiny errors that it would drop a frame. It is better to just round\n                // small deviations down to zero to leave things running smoothly.\n\n                if (static_cast<uint64_t>(std::abs(static_cast<int64_t>(timeDelta - m_targetElapsedTicks))) < TicksPerSecond / 4000)\n                {\n                    timeDelta = m_targetElapsedTicks;\n                }\n\n                m_leftOverTicks += timeDelta;\n\n                while (m_leftOverTicks >= m_targetElapsedTicks)\n                {\n                    m_elapsedTicks = m_targetElapsedTicks;\n                    m_totalTicks += m_targetElapsedTicks;\n                    m_leftOverTicks -= m_targetElapsedTicks;\n                    m_frameCount++;\n\n                    update();\n                }\n            }\n            else\n            {\n                // Variable timestep update logic.\n                m_elapsedTicks = timeDelta;\n                m_totalTicks += timeDelta;\n                m_leftOverTicks = 0;\n                m_frameCount++;\n\n                update();\n            }\n\n            // Track the current framerate.\n            if (m_frameCount != lastFrameCount)\n            {\n                m_framesThisSecond++;\n            }\n\n            if (m_qpcSecondCounter >= static_cast<uint64_t>(m_qpcFrequency.QuadPart))\n            {\n                m_framesPerSecond = m_framesThisSecond;\n                m_framesThisSecond = 0;\n                m_qpcSecondCounter %= static_cast<uint64_t>(m_qpcFrequency.QuadPart);\n            }\n        }\n\n    private:\n        // Source timing data uses QPC units.\n        LARGE_INTEGER m_qpcFrequency;\n        LARGE_INTEGER m_qpcLastTime;\n        uint64_t m_qpcMaxDelta;\n\n        // Derived timing data uses a canonical tick format.\n        uint64_t m_elapsedTicks;\n        uint64_t m_totalTicks;\n        uint64_t m_leftOverTicks;\n\n        // Members for tracking the framerate.\n        uint32_t m_frameCount;\n        uint32_t m_framesPerSecond;\n        uint32_t m_framesThisSecond;\n        uint64_t m_qpcSecondCounter;\n\n        // Members for configuring fixed timestep mode.\n        bool m_isFixedTimeStep;\n        uint64_t m_targetElapsedTicks;\n    };\n}\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/pch.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// pch.cpp\n//\n// Include the standard header and generate the precompiled header.\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#include \"pch.h\"\n"
  },
  {
    "path": "Tests/GDK/ManualTest.GDK/pch.h",
    "content": "//--------------------------------------------------------------------------------------\n// pch.h\n//\n// Header for standard system include files.\n//\n// Advanced Technology Group (ATG)\n// Copyright (C) Microsoft Corporation. All rights reserved.\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <winsdkver.h>\n#define _WIN32_WINNT 0x0A00\n#include <sdkddkver.h>\n\n// Use the C++ standard templated min/max\n#define NOMINMAX\n\n// DirectX apps don't need GDI\n#define NODRAWTEXT\n#define NOGDI\n#define NOBITMAP\n\n// Include <mcx.h> if you need this\n#define NOMCX\n\n// Include <winsvc.h> if you need this\n#define NOSERVICE\n\n// WinHelp is deprecated\n#define NOHELP\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n\n#include <Windows.h>\n\n#include <wrl/client.h>\n#include <wrl/event.h>\n\n#include <grdk.h>\n\n#if _GRDK_VER < 0x55F00C58 /* GDK Edition 220300 */\n#error This sample requires the March 2022 GDK or later\n#endif\n\n#ifdef _GAMING_XBOX_SCARLETT\n#include <d3d12_xs.h>\n#include <d3dx12_xs.h>\n#elif defined(_GAMING_XBOX)\n#include <d3d12_x.h>\n#include <d3dx12_x.h>\n#else\n#include <d3d12.h>\n#include <dxgi1_6.h>\n\n#ifdef _DEBUG\n#include <dxgidebug.h>\n#endif\n\n#include \"d3dx12.h\"\n#endif\n\n#define _XM_NO_XMVECTOR_OVERLOADS_\n\n#include <DirectXMath.h>\n#include <DirectXColors.h>\n\n#include <algorithm>\n#include <atomic>\n#include <cassert>\n#include <cmath>\n#include <cstddef>\n#include <cstdint>\n#include <cstdio>\n#include <cstring>\n#include <cwchar>\n#include <exception>\n#include <iterator>\n#include <memory>\n#include <sstream>\n#include <stdexcept>\n#include <string>\n#include <system_error>\n#include <tuple>\n\n#ifdef _GAMING_XBOX\n#include <pix3.h>\n#else\n// To use graphics markup events with the latest version of PIX, change this to include <pix3.h>\n// then add the NuGet package WinPixEventRuntime to the project.\n#include <pix.h>\n#endif\n#include \"xal\\xal.h\"\n#include \"xsapi-c\\services_c.h\"\n\n#include <XUser.h>\n#include <XTaskQueue.h>\n#include <XGame.h>\n#include <XSystem.h>\n\n#include \"DescriptorHeap.h\"\n#include \"ResourceUploadBatch.h\"\n#include \"SpriteBatch.h\"\n#include \"SpriteFont.h\"\n\n#include \"DirectXHelpers.h\"\n#include \"GamePad.h\"\n#include \"GraphicsMemory.h\"\n#include \"Keyboard.h\"\n#include \"Mouse.h\"\n#include \"RenderTargetState.h\"\n\n\n\nnamespace DX\n{\n    // Helper class for COM exceptions\n    class com_exception : public std::exception\n    {\n    public:\n        com_exception(HRESULT hr) noexcept : result(hr) {}\n\n        const char* what() const override\n        {\n            static char s_str[64] = {};\n            sprintf_s(s_str, \"Failure with HRESULT of %08X\", static_cast<unsigned int>(result));\n            return s_str;\n        }\n\n    private:\n        HRESULT result;\n    };\n\n    // Helper utility converts D3D API failures into exceptions.\n    inline void ThrowIfFailed(HRESULT hr)\n    {\n        if (FAILED(hr))\n        {\n#ifdef _DEBUG\n            char str[64] = {};\n            sprintf_s(str, \"**ERROR** Fatal Error with HRESULT of %08X\\n\", static_cast<unsigned int>(hr));\n            OutputDebugStringA(str);\n            __debugbreak();\n#endif\n            throw com_exception(hr);\n        }\n    }\n}\n\n// Enable off by default warnings to improve code conformance\n#pragma warning(default : 4061 4062 4191 4242 4263 4264 4265 4266 4289 4365 4746 4826 4841 4986 4987 5029 5038 5042)\n"
  },
  {
    "path": "Tests/UnitTests/Mocks/http_mock.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"http_mock.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nstruct HttpMockContext\n{\n    std::weak_ptr<HttpMock> pWeakThis;\n};\n\nstd::vector< std::shared_ptr<HttpMockContext> > g_httpMockContextList;\n\nHttpMock::HttpMock(\n    _In_ const xsapi_internal_string& method,\n    _In_ const xsapi_internal_string& url,\n    _In_ uint32_t httpStatus,\n    _In_ const JsonValue& responseBodyJson,\n    _In_ const HttpHeaders& responseHeaders\n) noexcept\n{\n    auto hr = HCMockCallCreate(&m_handle);\n    assert(SUCCEEDED(hr));\n\n    hr = HCMockAddMock(m_handle, method.c_str(), url.c_str(), nullptr, 0);\n    assert(SUCCEEDED(hr));\n\n    SetResponseHttpStatus(httpStatus);\n    SetResponseBody(responseBodyJson);\n    SetResponseHeaders(responseHeaders);\n\n    UNREFERENCED_PARAMETER(hr);\n}\n\nHttpMock::HttpMock(HttpMock&& other)\n    : m_handle(std::move(other.m_handle)),\n    m_matchedCallback(std::move(other.m_matchedCallback))\n{\n    other.m_handle = nullptr;\n    other.m_matchedCallback = nullptr;\n}\n\nHttpMock & HttpMock::operator=(HttpMock&& other)\n{\n    m_handle = std::move(other.m_handle);\n    m_matchedCallback = std::move(other.m_matchedCallback);\n\n    other.m_handle = nullptr;\n    other.m_matchedCallback = nullptr;\n    return *this;\n}\n\nHttpMock::~HttpMock()\n{\n    HCMockRemoveMock(m_handle);\n    HCMockCallCloseHandle(m_handle);\n}\n\nvoid HttpMock::SetResponseHttpStatus(uint32_t httpStatus) const noexcept\n{\n    auto hr = HCMockResponseSetStatusCode(m_handle, httpStatus);\n    assert(SUCCEEDED(hr));\n    UNREFERENCED_PARAMETER(hr);\n}\n\nvoid HttpMock::SetResponseBody(const String& responseBodyString) const noexcept\n{\n    if (!responseBodyString.empty())\n    {\n        Vector<uint8_t> bodyBytes{ responseBodyString.begin(), responseBodyString.end() };\n        SetResponseBody(bodyBytes.data(), bodyBytes.size());\n    }\n}\n\nvoid HttpMock::SetResponseBody(const JsonValue& responseBodyJson) const noexcept\n{\n    if (!responseBodyJson.IsNull())\n    {\n        SetResponseBody(JsonUtils::SerializeJson(responseBodyJson));\n    }\n}\n\nvoid HttpMock::SetResponseBody(\n    const uint8_t* responseBodyBytes,\n    size_t responseBodySize\n) const noexcept\n{\n    if (responseBodyBytes && responseBodySize)\n    {\n        auto hr = HCMockResponseSetResponseBodyBytes(m_handle, responseBodyBytes, static_cast<uint32_t>(responseBodySize));\n        assert(SUCCEEDED(hr));\n        UNREFERENCED_PARAMETER(hr);\n    }\n}\n\nvoid HttpMock::ClearReponseBody() const noexcept\n{\n    // libHttpClient doesn't allow setting body with nullptr, but it does allow size = 0\n    uint8_t body{};\n    SetResponseBody(&body, 0);\n}\n\nvoid HttpMock::SetResponseHeaders(const HttpHeaders& responseHeaders) const noexcept\n{\n    for (const auto& header : responseHeaders)\n    {\n        auto hr = HCMockResponseSetHeader(m_handle, header.first.data(), header.second.data());\n        assert(SUCCEEDED(hr));\n        UNREFERENCED_PARAMETER(hr);\n    }\n}\n\nvoid HttpMock::SetMockMatchedCallback(MockMatchedCallback mockMatched) noexcept\n{\n    m_matchedCallback = std::move(mockMatched);\n\n    // m_sharedFromThis will be destroyed when HttpMock is destroyed.  \n    // pass a weak version of it via context and check if its still around inside callback\n    // g_httpMockContextList will be cleaned up during shutdown\n    auto contextBlock = std::make_shared<HttpMockContext>();\n    g_httpMockContextList.push_back(contextBlock);\n    contextBlock->pWeakThis = shared_from_this();\n\n    HCMockSetMockMatchedCallback(m_handle,\n        [](HCMockCallHandle matchedMock,\n            const char* method,\n            const char* url,\n            const uint8_t* requestBodyBytes,\n            uint32_t requestBodySize,\n            void* context\n            )\n        {\n            UNREFERENCED_PARAMETER(matchedMock);\n            UNREFERENCED_PARAMETER(method);\n\n            HttpMockContext* contextBlockPtr{ static_cast<HttpMockContext*>(context) };\n            std::shared_ptr<HttpMock> sharedFromThis{ contextBlockPtr->pWeakThis.lock() };\n            if (sharedFromThis != nullptr)\n            {\n                sharedFromThis->m_matchedCallback(sharedFromThis.get(), url, xsapi_internal_string{ requestBodyBytes, requestBodyBytes + requestBodySize });\n            }\n        },\n        contextBlock.get()\n    );\n}\n\nxsapi_internal_string HttpMock::GetUriPath(const xsapi_internal_string& uriString) noexcept\n{\n    xbox::services::uri uri{ uriString.data() };\n    return uri.path();\n}\n\nxsapi_internal_string HttpMock::GetUriQuery(const xsapi_internal_string& uriString) noexcept\n{\n    xbox::services::uri uri{ uriString.data() };\n    return uri.query();\n}\n\nstd::map<xsapi_internal_string, xsapi_internal_string> HttpMock::GetQueryParams(const xsapi_internal_string& uriString) noexcept\n{\n    xbox::services::uri uri{ uriString.data() };\n    auto params = xbox::services::uri::split_query(uri.query());\n\n    std::map<xsapi_internal_string, xsapi_internal_string> out;\n    for (auto& param : params)\n    {\n        out[param.first.c_str()] = param.second.c_str();\n    }\n    return out;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n\n\n"
  },
  {
    "path": "Tests/UnitTests/Mocks/http_mock.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"pch.h\"\n#include \"httpClient/httpClient.h\"\n#include \"xsapi-cpp/http_call.h\"\n#include \"shared_macros.h\"\n#include \"xbox_live_context_settings_internal.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\ntypedef Callback<class HttpMock* /*matchedMock*/, xsapi_internal_string /*actualRequestUrl*/, xsapi_internal_string /*requestBody*/> MockMatchedCallback;\n\n// RAII wrapper around HCMockCallHandle\nclass HttpMock : public std::enable_shared_from_this<HttpMock>\n{\npublic:\n    HttpMock(\n        _In_ const xsapi_internal_string& method,\n        _In_ const xsapi_internal_string& url,\n        _In_ uint32_t httpStatus = 200,\n        _In_ const JsonValue& responseBodyJson = JsonValue{ rapidjson::kNullType },\n        _In_ const HttpHeaders& responseHeaders = HttpHeaders{}\n    ) noexcept;\n\n    HttpMock(const HttpMock&) = delete;\n    HttpMock& operator=(HttpMock) = delete;\n    HttpMock(HttpMock&& other);\n    HttpMock& operator=(HttpMock&& other);\n    virtual ~HttpMock();\n\n    void SetResponseHttpStatus(uint32_t httpStatus) const noexcept;\n    void SetResponseBody(const String& responseBodyString) const noexcept;\n    void SetResponseBody(const JsonValue& responseBodyJson) const noexcept;\n    void SetResponseBody(const uint8_t* responseBodyBytes, size_t responseBodySize) const noexcept;\n    void ClearReponseBody() const noexcept;\n    void SetResponseHeaders(const HttpHeaders& responseHeaders) const noexcept;\n\n    void SetMockMatchedCallback(MockMatchedCallback callback) noexcept;\n\n    // Helper methods for parsing URI\n    static xsapi_internal_string GetUriPath(const xsapi_internal_string& uri) noexcept;\n    static xsapi_internal_string GetUriQuery(const xsapi_internal_string& uri) noexcept;\n    static std::map<xsapi_internal_string, xsapi_internal_string> GetQueryParams(const xsapi_internal_string& uriString) noexcept;\n\nprivate:\n    HCMockCallHandle m_handle{ nullptr };\n    MockMatchedCallback m_matchedCallback{ nullptr };\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Mocks/mock_rta_service.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"mock_rta_service.h\"\n#include \"mock_web_socket.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\n// RTA Protocol desribed http://xboxwiki/wiki/Real_Time_Activity\n\nenum class MessageType : uint32_t\n{\n    Subscribe = 1,\n    Unsubscribe = 2,\n    Event = 3,\n    Resync = 4\n};\n\nMockRealTimeActivityService& MockRealTimeActivityService::Instance() noexcept\n{\n    static MockRealTimeActivityService s_instance{};\n    return s_instance;\n}\n\nvoid MockRealTimeActivityService::HandleClientMessage(\n    std::shared_ptr<MockWebsocket> socket,\n    const char* message\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n\n    rapidjson::Document rtaMessage{ rapidjson::kArrayType };\n    rtaMessage.Parse(message);\n    assert(!rtaMessage.HasParseError());\n\n    auto messageType{ static_cast<MessageType>(rtaMessage[0].GetUint()) };\n    switch (messageType)\n    {\n    case MessageType::Subscribe:\n    {\n        // Subscribe messages will not be automatically be acknowledged since they require\n        // a service specific response payload.\n        auto sequenceNumber{ rtaMessage[1].GetUint() };\n        auto uri{ rtaMessage[2].GetString() };\n        auto subId{ m_nextSubId++ };\n\n        m_clients[socket][subId] = Subscription{ uri, sequenceNumber };\n\n        auto handler{ m_subscribeHandler };\n        lock.unlock();\n\n        if (handler)\n        {\n            handler(subId, uri);\n        }\n        return;\n    }\n    case MessageType::Unsubscribe:\n    {\n        // Unsubscribe messages will be automatically acknowledged\n        auto sequenceNumber{ rtaMessage[1].GetUint() };\n        auto subId{ rtaMessage[2].GetUint() };\n\n        rapidjson::Document response{ rapidjson::kArrayType };\n        auto& a{ response.GetAllocator() };\n\n        response.PushBack(static_cast<uint32_t>(messageType), a);\n        response.PushBack(sequenceNumber, a);\n\n        auto& subs{ m_clients[socket] };\n        auto subIter{ subs.find(subId) };\n        if (subIter != subs.end())\n        {\n            assert(subIter->second.active);\n            response.PushBack(static_cast<uint32_t>(ErrorCode::Success), a);\n            subs.erase(subIter);\n        }\n        else\n        {\n            // TODO figure out what is actually returned by service in this case\n            response.PushBack(5u, a);\n        }\n\n        lock.unlock();\n        socket->ReceiveMessage(response);\n        return;\n    }\n    default:\n    {\n        assert(false);\n        return;\n    }\n    }\n}\n\nvoid MockRealTimeActivityService::SetSubscribeHandler(\n    SubscribeHandler handler\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n    m_subscribeHandler = std::move(handler);\n}\n\nvoid MockRealTimeActivityService::CompleteSubscribeHandshake(\n    uint32_t subId,\n    const rapidjson::Value& payload,\n    ErrorCode errorCode\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n    for (auto& clientPair : m_clients)\n    {\n        auto& clientSubs{ clientPair.second };\n        auto subIter{ clientSubs.find(subId) };\n        if (subIter != clientSubs.end())\n        {\n            if (auto socket{ clientPair.first.lock() })\n            {\n                rapidjson::Document response{ rapidjson::kArrayType };\n                auto& a{ response.GetAllocator() };\n\n                response.PushBack(static_cast<uint32_t>(MessageType::Subscribe), a);\n                response.PushBack(subIter->second.clientSequenceNumber, a);\n                response.PushBack(static_cast<uint32_t>(errorCode), a);\n                response.PushBack(subId, a);\n                response.PushBack(rapidjson::Value{}.CopyFrom(payload, a), a);\n\n                assert(!subIter->second.active);\n                subIter->second.active = true;\n                socket->ReceiveMessage(response);\n            }\n            else\n            {\n                // Client Socket has been destroyed, clean up state for that client\n                m_clients.erase(clientPair.first);\n            }\n            break;\n        }\n    }\n}\n\nvoid MockRealTimeActivityService::CompleteSubscribeHandshake(\n    uint32_t subId,\n    const char* payload,\n    ErrorCode errorCode\n) noexcept\n{\n    rapidjson::Document d;\n    d.Parse(payload);\n    assert(!d.HasParseError());\n    CompleteSubscribeHandshake(subId, d, errorCode);\n}\n\nvoid MockRealTimeActivityService::RaiseEvent(\n    const xsapi_internal_string& uri,\n    const rapidjson::Value& payload\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n\n    rapidjson::Document eventMessage{ rapidjson::kArrayType };\n    auto& a{ eventMessage.GetAllocator() };\n\n    eventMessage.PushBack(static_cast<uint32_t>(MessageType::Event), a);\n    eventMessage.PushBack(0u, a);\n    eventMessage.PushBack(rapidjson::Value{}.CopyFrom(payload, a).Move(), a);\n\n    for (auto clientIter = m_clients.begin(); clientIter != m_clients.end();)\n    {\n        if (auto socket{ clientIter->first.lock() })\n        {\n            for (auto& subPair : clientIter->second)\n            {\n                if (subPair.second.active && subPair.second.uri == uri)\n                {\n                    eventMessage[1] = subPair.first;\n                    socket->ReceiveMessage(eventMessage);\n                }\n            }\n            clientIter++;\n        }\n        else\n        {\n            // Client Socket has been destroyed, clean up state for that client\n            clientIter = m_clients.erase(clientIter);\n        }\n    }\n}\n\nvoid MockRealTimeActivityService::RaiseEvent(\n    const xsapi_internal_string& uri,\n    const char* payload\n) noexcept\n{\n    rapidjson::Document d;\n    d.Parse(payload);\n    assert(!d.HasParseError());\n    RaiseEvent(uri, d);\n}\n\nvoid MockRealTimeActivityService::RaiseResync() noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n\n    const char resyncMessage[]{ \"[4]\" };\n    for (auto clientIter = m_clients.begin(); clientIter != m_clients.end();)\n    {\n        if (auto socket{ clientIter->first.lock() })\n        {\n            socket->ReceiveMessage(resyncMessage);\n            clientIter++;\n        }\n        else\n        {\n            // Client Socket has been destroyed, clean up state for that client\n            clientIter = m_clients.erase(clientIter);\n        }\n    }\n}\n\nvoid MockRealTimeActivityService::DisconnectClient(\n    uint64_t xuid\n) noexcept\n{\n    std::unique_lock<std::mutex> lock{ m_mutex };\n\n    for (auto clientIter = m_clients.begin(); clientIter != m_clients.end();)\n    {\n        if (auto socket{ clientIter->first.lock() })\n        {\n            if (socket->Xuid() == xuid)\n            {\n                socket->Disconnect(WebSocketCloseStatus::GoingAway);\n                clientIter = m_clients.erase(clientIter);\n            }\n            else\n            {\n                clientIter++;\n            }\n        }\n        else\n        {\n            clientIter = m_clients.erase(clientIter);\n        }\n    }\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Mocks/mock_rta_service.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nclass MockWebsocket;\n\nclass MockRealTimeActivityService\n{\npublic:\n    static MockRealTimeActivityService& Instance() noexcept;\n\n    MockRealTimeActivityService(const MockRealTimeActivityService&) = delete;\n    MockRealTimeActivityService& operator=(MockRealTimeActivityService) = delete;\n    ~MockRealTimeActivityService() = default;\n\n    void HandleClientMessage(\n        std::shared_ptr<MockWebsocket> socket,\n        const char* message\n    ) noexcept;\n\n    enum class ErrorCode : uint32_t\n    {\n        Success = 0,\n        UnknownResource = 1,\n        SubscriptionLimitReached = 2,\n        NoResourceData = 3,\n        Throttled = 1001,\n        ServiceUnavailable = 1002\n    };\n\n    using SubscribeHandler = std::function<void(uint32_t subId, xsapi_internal_string uri)>;\n    void SetSubscribeHandler(\n        SubscribeHandler handler\n    ) noexcept;\n\n    void CompleteSubscribeHandshake(\n        uint32_t subId,\n        const rapidjson::Value& payload = rapidjson::Document{ rapidjson::kNullType },\n        ErrorCode errorCode = ErrorCode::Success\n    ) noexcept;\n\n    void CompleteSubscribeHandshake(\n        uint32_t subId,\n        const char* payload,\n        ErrorCode errorCode = ErrorCode::Success\n    ) noexcept;\n\n    void RaiseEvent(\n        const xsapi_internal_string& uri,\n        const rapidjson::Value& payload\n    ) noexcept;\n\n    void RaiseEvent(\n        const xsapi_internal_string& uri,\n        const char* payload\n    ) noexcept;\n\n    void RaiseResync() noexcept;\n\n    void DisconnectClient(\n        uint64_t xuid\n    ) noexcept;\n\nprivate:\n    MockRealTimeActivityService() = default;\n\n    uint32_t m_nextSubId{ 1 };\n    SubscribeHandler m_subscribeHandler{ nullptr };\n\n    struct Subscription\n    {\n        xsapi_internal_string uri;\n        uint32_t clientSequenceNumber{ 0 };\n        bool active{ false };\n    };\n\n    std::map<std::weak_ptr<MockWebsocket>, std::map<uint32_t, Subscription>, std::owner_less<std::weak_ptr<MockWebsocket>>> m_clients;\n\n    mutable std::mutex m_mutex;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Mocks/mock_user.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n\nstruct XalUserImpl\n{\n    uint64_t const xuid;\n    std::string const gamertag;\n    std::string const modernGamertag;\n    std::string const modernGamertagSuffix;\n    std::string const uniqueModernGamertag;\n    uint64_t const localId;\n};\n\nstruct XalUser\n{\n    std::shared_ptr<XalUserImpl> userImpl;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nUser CreateMockUser(\n    uint64_t xuid,\n    const std::string& gamertag,\n    uint64_t localId\n)\n{\n    auto xalUserImpl = std::shared_ptr<XalUserImpl>{ new XalUserImpl{ xuid, gamertag, \"\", \"\", \"\", localId } };\n    auto xalUser = std::unique_ptr<XalUser>{ new XalUser{ xalUserImpl } };\n    auto userResult = User::WrapHandle(xalUser.get());\n    return userResult.ExtractPayload();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\nSTDAPI XalUserDuplicateHandle(\n    _In_ XalUserHandle user,\n    _Out_ XalUserHandle* duplicatedUser\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || duplicatedUser == nullptr);\n    *duplicatedUser = new XalUser{ user->userImpl };\n    return S_OK;\n}\n\nSTDAPI_(void) XalUserCloseHandle(\n    _In_ XalUserHandle user\n) noexcept\n{\n    delete user;\n}\n\nSTDAPI XalUserGetId(\n    _In_ XalUserHandle user,\n    _Out_ uint64_t* id\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || id == nullptr);\n    *id = user->userImpl->xuid;\n    return S_OK;\n}\n\nSTDAPI XalUserGetLocalId(\n    _In_ XalUserHandle user,\n    _Out_ XalUserLocalId* localId\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(localId);\n    *localId = XalUserLocalId{ user->userImpl->localId};\n    return S_OK;\n}\n\nSTDAPI_(size_t) XalUserGetGamertagSize(\n    _In_ XalUserHandle user,\n    _In_ XalGamertagComponent component\n) noexcept\n{\n    switch (component)\n    {\n    case XalGamertagComponent_Classic:\n    {\n        return user->userImpl->gamertag.size() + 1;\n    }\n    case XalGamertagComponent_Modern:\n    {\n        return user->userImpl->modernGamertag.size() + 1;\n    }\n    case XalGamertagComponent_ModernSuffix:\n    {\n        return user->userImpl->modernGamertagSuffix.size() + 1;\n    }\n    case XalGamertagComponent_UniqueModern:\n    {\n        return user->userImpl->uniqueModernGamertag.size() + 1;\n    }\n    default:\n    {\n        assert(false);\n        return 0;\n    }\n    }\n}\n\nSTDAPI XalUserGetGamertag(\n    _In_ XalUserHandle user,\n    _In_ XalGamertagComponent component,\n    _In_ size_t gamertagSize,\n    _Out_writes_(gamertagSize) char* gamertag,\n    _Out_opt_ size_t* gamertagUsed\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF(user == nullptr || gamertag == nullptr);\n\n    const std::string* gamertagComponent{ nullptr };\n    switch (component)\n    {\n    case XalGamertagComponent_Classic:\n    {\n        gamertagComponent = &user->userImpl->gamertag;\n        break;\n    }\n    case XalGamertagComponent_Modern:\n    {\n        gamertagComponent = &user->userImpl->modernGamertag;\n        break;\n    }\n    case XalGamertagComponent_ModernSuffix:\n    {\n        gamertagComponent = &user->userImpl->modernGamertagSuffix;\n        break;\n    }\n    case XalGamertagComponent_UniqueModern:\n    {\n        gamertagComponent = &user->userImpl->uniqueModernGamertag;\n        break;\n    }\n    default:\n    {\n        assert(false);\n        return E_UNEXPECTED;\n    }\n    }\n\n    if (gamertagSize < gamertagComponent->size() + 1)\n    {\n        return E_INVALIDARG;\n    }\n\n    memcpy(gamertag, gamertagComponent->data(), gamertagComponent->size() + 1);\n\n    if (gamertagUsed)\n    {\n        *gamertagUsed = gamertagComponent->size() + 1;\n    }\n    return S_OK;\n}\n\nSTDAPI XalUserGetTokenAndSignatureSilentlyAsync(\n    _In_ XalUserHandle user,\n    _In_ XalUserGetTokenAndSignatureArgs const* args,\n    _In_ XAsyncBlock* async\n) noexcept\n{\n    UNREFERENCED_PARAMETER(user);\n    UNREFERENCED_PARAMETER(args);\n\n    static std::string token{ \"MockToken\" };\n    static std::string signature{ \"MockSignature\" };\n\n    return RunAsync(async, __FUNCTION__,\n        [&](XAsyncOp op, const XAsyncProviderData* data)\n        {\n            switch (op)\n            {\n            case XAsyncOp::DoWork:\n            {\n                size_t resultSize{ sizeof(XalUserGetTokenAndSignatureData) };\n                resultSize += token.size() + 1;\n                resultSize += signature.size() + 1;\n                XAsyncComplete(data->async, S_OK, resultSize);\n                return S_OK;\n            }\n            case XAsyncOp::GetResult:\n            {\n                auto tokenBuffer = static_cast<char*>(data->buffer) + sizeof(XalUserGetTokenAndSignatureData);\n                auto signatureBuffer = tokenBuffer + token.size() + 1;\n                new (data->buffer) XalUserGetTokenAndSignatureData{ token.size() + 1, signature.size() + 1, tokenBuffer, signatureBuffer };\n\n                memcpy(tokenBuffer, token.data(), token.size() + 1);\n                memcpy(signatureBuffer, signature.data(), signature.size() + 1);\n                return S_OK;\n            }\n            default:\n            {\n                return S_OK;\n            }\n            }\n        });\n}\n\nSTDAPI XalUserGetTokenAndSignatureSilentlyResultSize(\n    _In_ XAsyncBlock* async,\n    _Out_ size_t* bufferSize\n) noexcept\n{\n    return XAsyncGetResultSize(async, bufferSize);\n}\n\nSTDAPI XalUserGetTokenAndSignatureSilentlyResult(\n    _In_ XAsyncBlock* async,\n    _In_ size_t bufferSize,\n    _Out_writes_bytes_to_(bufferSize, *bufferUsed) void* buffer,\n    _Outptr_ XalUserGetTokenAndSignatureData** result,\n    _Out_opt_ size_t* bufferUsed\n) noexcept\n{\n    size_t sizeUsed{ 0 };\n    HRESULT hr = XAsyncGetResult(async, nullptr, bufferSize, buffer, &sizeUsed);\n\n    *result = static_cast<XalUserGetTokenAndSignatureData*>(buffer);\n    if (bufferUsed)\n    {\n        *bufferUsed = sizeUsed;\n    }\n\n    return hr;\n}\n\nSTDAPI XalUserRegisterChangeEventHandler(\n    _In_ XTaskQueueHandle queue,\n    _In_opt_ void* context,\n    _In_ XalUserChangeEventHandler* handler,\n    _Out_ XalRegistrationToken* token\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(token);\n\n    UNREFERENCED_PARAMETER(queue);\n    UNREFERENCED_PARAMETER(context);\n    UNREFERENCED_PARAMETER(handler);\n\n    static uint64_t nextToken{ 1 };\n    token->token = nextToken++;\n\n    return S_OK;\n}\n\nSTDAPI_(void) XalUserUnregisterChangeEventHandler(\n    _In_ XalRegistrationToken token\n) noexcept\n{\n    UNREFERENCED_PARAMETER(token);\n}\n"
  },
  {
    "path": "Tests/UnitTests/Mocks/mock_web_socket.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"mock_web_socket.h\"\n#include \"mock_rta_service.h\"\n#include \"rapidjson/stringbuffer.h\"\n#include \"rapidjson/writer.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nMockWebsocket::MockWebsocket(\n    User user,\n    TaskQueue queue\n) noexcept\n    : m_user{ std::move(user) },\n    m_queue{ std::move(queue) }\n{\n}\n\nHRESULT MockWebsocket::Connect(\n    _In_ const String& uri,\n    _In_ const String& subProtocol\n) noexcept\n{\n    UNREFERENCED_PARAMETER(subProtocol);\n    UNREFERENCED_PARAMETER(uri);\n\n    return m_queue.RunWork([sharedThis{ shared_from_this() }]\n    {\n        std::unique_lock<std::recursive_mutex> lock{ sharedThis->m_mutex };\n        if (s_connectHandler == nullptr)\n        {\n            sharedThis->m_connectCompleteHandler(WebsocketResult{ S_OK });\n        }\n        else\n        {\n            sharedThis->m_connectCompleteHandler(s_connectHandler());\n        }\n    });\n}\n\nHRESULT MockWebsocket::Send(_In_ const char* message) noexcept\n{\n    return m_queue.RunWork([sharedThis{ shared_from_this() }, message = std::string{ message }]\n    {\n        MockRealTimeActivityService::Instance().HandleClientMessage(sharedThis, message.data());\n    });\n}\n\nHRESULT MockWebsocket::Disconnect() noexcept\n{\n    return m_queue.RunWork([sharedThis{ shared_from_this() }]\n    {\n        sharedThis->m_disconnectHandler(WebSocketCloseStatus::Normal);\n    });\n}\n\nuint64_t MockWebsocket::Xuid() const noexcept\n{\n    return m_user.Xuid();\n}\n\nHRESULT MockWebsocket::Disconnect(WebSocketCloseStatus closeStatus) const noexcept\n{\n    m_disconnectHandler(closeStatus);\n    return S_OK;\n}\n\nvoid MockWebsocket::ReceiveMessage(\n    _In_ const char* message\n) const noexcept\n{\n    m_receiveHandler(message);\n}\n\nvoid MockWebsocket::ReceiveMessage(\n    _In_ const rapidjson::Value& message\n) const noexcept\n{\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    message.Accept(writer);\n\n    m_receiveHandler(buffer.GetString());\n}\n\nvoid MockWebsocket::SetConnectHandler(ConnectHandler handler) noexcept\n{\n    s_connectHandler = std::move(handler);\n}\n\nMockWebsocket::ConnectHandler MockWebsocket::s_connectHandler{};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Mocks/mock_web_socket.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"web_socket.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nclass MockWebsocket : public IWebsocket, public std::enable_shared_from_this<MockWebsocket>\n{\npublic:\n    MockWebsocket(\n        User user,\n        TaskQueue queue\n    ) noexcept;\n\n    // IWebsocket\n    HRESULT Connect(\n        _In_ const String& uri,\n        _In_ const String& subProtocol\n    ) noexcept override;\n\n    HRESULT Send(_In_ const char* message) noexcept override;\n\n    HRESULT Disconnect() noexcept override;\n\n    // MockWebsocket\n    uint64_t Xuid() const noexcept;\n\n    HRESULT Disconnect(\n        WebSocketCloseStatus closeStatus\n    ) const noexcept;\n\n    void ReceiveMessage(\n        _In_ const char* message\n    ) const noexcept;\n\n    void ReceiveMessage(\n        _In_ const rapidjson::Value& message\n    ) const noexcept;\n\n    // By default MockWebsocket::Connect will asyncronously complete successfully.\n    // To alter connection behavior, set a custom ConnectHandler\n    using ConnectHandler = std::function<WebsocketResult()>;\n    static void SetConnectHandler(ConnectHandler handler) noexcept;\n\nprivate:\n    TaskQueue m_queue{};\n    User const m_user;\n\n    static ConnectHandler s_connectHandler;\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Mocks/xal_mocks.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nSTDAPI XalGetTitleId(\n    _Out_ uint32_t* titleId\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(titleId);\n    *titleId = MOCK_TITLEID;\n    return S_OK;\n}\n\nSTDAPI_(size_t) XalGetSandboxSize() noexcept\n{\n    return strlen(MOCK_SANDBOX) + 1;\n}\n\nSTDAPI XalGetSandbox(\n    _In_ size_t sandboxSize,\n    _Out_writes_(sandboxSize) char* sandbox,\n    _Out_opt_ size_t* sandboxUsed\n) noexcept\n{\n    RETURN_HR_INVALIDARGUMENT_IF_NULL(sandbox);\n\n    size_t requiredSize{ strlen(MOCK_SANDBOX) + 1 };\n    RETURN_HR_INVALIDARGUMENT_IF(sandboxSize < requiredSize);\n\n    memcpy(sandbox, MOCK_SANDBOX, requiredSize);\n    if (sandboxUsed)\n    {\n        *sandboxUsed = requiredSize;\n    }\n\n    return S_OK;\n}"
  },
  {
    "path": "Tests/UnitTests/Scripts/ETWProfile.wprp",
    "content": "<?xml version='1.0' encoding='utf-8' standalone='yes'?>\n<WindowsPerformanceRecorder\n    Author=\"Xbox Services API\"\n    Comments=\"XSAPI ETW Profile\"\n    Version=\"1.0\"> \n  <Profiles> \n\n    <!-- Buffer sizes are specified in KB -->\n    <EventCollector Id=\"EventCollector_XSAPI\" Name=\"XSAPI Event Collector\" ProcessPrivate=\"false\" Secure=\"false\" Realtime=\"false\">\n        <BufferSize Value=\"64\"/>\n        <Buffers Value=\"4\"/>\n    </EventCollector>\n\n    <!-- Our custom ETW Provider and its associated GUID -->\n    <EventProvider Id=\"EventProvider_XSAPI\" Name=\"9594A560-E985-4EE6-B0B5-0DAC4F924144\"/>\n\n    <!-- A fully specified .wprp file should have four profiles, with DetailLevel set to Verbose and Light and with Logging Mode set to Memory and File. WPR enforces that the name conforms to <name>Profile.Level.OutputType --> \n    <Profile Id=\"XSAPIProfile.Verbose.File\" \n        LoggingMode=\"File\" \n        Name=\"XSAPIProfile\" \n        DetailLevel=\"Verbose\" \n        Description=\"XSAPI ETW Provider for Diagnostic trace\">\n        <Collectors> \n           <!-- EventCollectorId must match the EventCollector ID specified above -->\n           <EventCollectorId Value=\"EventCollector_XSAPI\">\n             <EventProviders>\n                <EventProviderId Value=\"EventProvider_XSAPI\"/>\n             </EventProviders>\n           </EventCollectorId>\n        </Collectors>\n    </Profile>\n\n     <!-- Now we can just subclass our base profile to get the other (mostly redundant) configurations  -->\n     <Profile Id=\"XSAPIProfile.Verbose.Memory\" \n         LoggingMode=\"Memory\"\n         Name=\"XSAPIProfile\" \n         DetailLevel=\"Verbose\" \n         Description=\"XSAPI ETW Provider for Diagnostic trace\"\n         Base=\"XSAPIProfile.Verbose.File\"/>\n\n     <Profile Id=\"XSAPIProfile.Light.File\"\n         LoggingMode=\"File\"\n         Name=\"XSAPIProfile\" \n         DetailLevel=\"Light\" \n         Description=\"XSAPI ETW Provider for Diagnostic trace\"\n         Base=\"XSAPIProfile.Verbose.File\"/>\n\n  </Profiles>\n</WindowsPerformanceRecorder>"
  },
  {
    "path": "Tests/UnitTests/Scripts/repeat-all-except-ignored.cmd",
    "content": "if \"%1\" EQU \"\" goto help\nset OUTPUT_FOLDER=%1\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nmkdir %OUTPUT_FOLDER%\nset /A X=1\n\n:loop\nset /A X=X+1\n%TAEF_EXE% /sessionTimeout:0:15 /testTimeout:0:5 %TE_DLL% /select:\"not(@Ignore = 1)\" > %OUTPUT_FOLDER%\\test%x%.txt\nif %ERRORLEVEL% EQU 0 del %OUTPUT_FOLDER%\\test%x%.txt\n\ngoto loop\n\n:help\necho repeat-all-except-ignored.cmd LogFolder \n:done"
  },
  {
    "path": "Tests/UnitTests/Scripts/repeat-focused.cmd",
    "content": "if \"%1\" EQU \"\" goto help\nset OUTPUT_FOLDER=%1\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nmkdir %OUTPUT_FOLDER%\nset /A X=1\n\n:loop\nset /A X=X+1\n%TAEF_EXE% /sessionTimeout:0:15 /testTimeout:0:5 %TE_DLL% /select:\"@Focus = 1\" > %OUTPUT_FOLDER%\\test%x%.txt\nif %ERRORLEVEL% EQU 0 copy %OUTPUT_FOLDER%\\test%x%.txt %OUTPUT_FOLDER%\\test.txt && del %OUTPUT_FOLDER%\\test%x%.txt\ntype %OUTPUT_FOLDER%\\test.txt\ndel %OUTPUT_FOLDER%\\test.txt\n\ngoto loop\n\n:help\necho repeat-focused.cmd c:\\test\n:done"
  },
  {
    "path": "Tests/UnitTests/Scripts/repeat-single-with-etw.cmd",
    "content": "if \"%1\" EQU \"\" goto help\nif \"%2\" EQU \"\" goto help\nset OUTPUT_FOLDER=%1\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset TEST_NAME=%2\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nmkdir %OUTPUT_FOLDER%\nset /A X=1\n\n:loop\nset /A X=X+1\n\"C:\\Program Files (x86)\\Windows Kits\\10\\Windows Performance Toolkit\\wpr.exe\" -start ETWProfile.wprp\n%TAEF_EXE% /sessionTimeout:0:15 /testTimeout:0:5 %TE_DLL% /select:@name='*%TEST_NAME%' > %OUTPUT_FOLDER%\\test%x%.txt\nset TAEF_ERROR=%ERRORLEVEL%\n\n\"C:\\Program Files (x86)\\Windows Kits\\10\\Windows Performance Toolkit\\wpr.exe\" -stop %OUTPUT_FOLDER%\\test%x%.etl \"XSAPI UnitTest Diagnostic Trace\"\nif %TAEF_ERROR% EQU 0 del %OUTPUT_FOLDER%\\test%x%.txt\nif %TAEF_ERROR% EQU 0 del %OUTPUT_FOLDER%\\test%x%.etl\ntype %OUTPUT_FOLDER%\\test%x%.txt\n\ngoto loop\n\n:help\necho repeat-single-with-etw.cmd c:\\test TestGetLeaderboardForSocialGroupWithSkipToRankAsync\n:done"
  },
  {
    "path": "Tests/UnitTests/Scripts/repeat-single.cmd",
    "content": "if \"%1\" EQU \"\" goto help\nif \"%2\" EQU \"\" goto help\nset OUTPUT_FOLDER=%1\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset TEST_NAME=%2\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nmkdir %OUTPUT_FOLDER%\nset /A X=1\n\n:loop\nset /A X=X+1\n%TAEF_EXE% /sessionTimeout:0:15 /testTimeout:0:5 %TE_DLL% /select:@name='*%TEST_NAME%' > %OUTPUT_FOLDER%\\test%x%.txt\nif %ERRORLEVEL% EQU 0 del %OUTPUT_FOLDER%\\test%x%.txt\ntype %OUTPUT_FOLDER%\\test%x%.txt\n\ngoto loop\n\n:help\necho repeat-single.cmd c:\\test TestGetLeaderboardForSocialGroupWithSkipToRankAsync\n:done"
  },
  {
    "path": "Tests/UnitTests/Scripts/run-all-tests-once-skip-ignore.cmd",
    "content": "set OUTPUT_FOLDER=%1\nif \"%1\" EQU \"\" set OUTPUT_FOLDER=c:\\test\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nmkdir %OUTPUT_FOLDER%\nset /A X=1\n\n%TAEF_EXE% /inproc /select:\"not(@Ignore = 1)\" %TE_DLL%\ngoto done\n\n:help\necho run-all-tests-once-skip-ignore.cmd c:\\test\n:done"
  },
  {
    "path": "Tests/UnitTests/Scripts/run-all-tests-once.cmd",
    "content": "set OUTPUT_FOLDER=%1\nif \"%1\" EQU \"\" set OUTPUT_FOLDER=c:\\test\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nmkdir %OUTPUT_FOLDER%\nset /A X=1\n\n%TAEF_EXE% /inproc %TE_DLL%\ngoto done\n\n:help\necho run-all-tests-once.cmd c:\\test\n:done"
  },
  {
    "path": "Tests/UnitTests/Scripts/run-focused-once.cmd",
    "content": "set OUTPUT_FOLDER=%1\nset TAEF_EXE=\"C:\\Program Files (x86)\\Windows Kits\\10\\Testing\\Runtimes\\TAEF\\x64\\TE.exe\"\nset MYPATH=%~dp0\nset TE_DLL=%MYPATH:~0,-1%\\..\\..\\..\\Bins\\Binaries\\Debug\\x64\\Microsoft.Xbox.Services.UnitTest.141.TAEF\\Microsoft.Xbox.Services.UnitTest.141.TAEF.dll \nif \"%1\" EQU \"\" set OUTPUT_FOLDER=c:\\test\nmkdir %OUTPUT_FOLDER%\n\n%TAEF_EXE% /inproc /select:\"@Focus = 1\" %TE_DLL%\ngoto done\n\n:help\necho run-focused-once.cmd c:\\test\n:done"
  },
  {
    "path": "Tests/UnitTests/Support/DefineTestMacros.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#ifdef USING_TAEF\n\n#define DEFINE_TEST_CASE_TAEF(TestCaseMethodName)  \\\n    BEGIN_TEST_METHOD(TestCaseMethodName) \\\n    END_TEST_METHOD()\n\n#define DEFINE_TEST_CASE_WITH_DESC(TestCaseMethodName, TestCaseDescription)  \\\n    BEGIN_TEST_METHOD(TestCaseMethodName) \\\n    END_TEST_METHOD()\n\n#define DEFINE_TEST_CASE_PROPERTIES_TAEF() \\\n        BEGIN_TEST_METHOD_PROPERTIES() \\\n            TEST_METHOD_PROPERTY(L\"Setup\", L\"1\") \\\n        END_TEST_METHOD_PROPERTIES() \\\n\n#define DEFINE_TEST_CASE_PROPERTIES_TAEF_IGNORE() \\\n        BEGIN_TEST_METHOD_PROPERTIES() \\\n            TEST_METHOD_PROPERTY(L\"Setup\", L\"1\") \\\n            TEST_METHOD_PROPERTY(L\"Ignore\", L\"1\") \\\n        END_TEST_METHOD_PROPERTIES()\n\n#define DEFINE_TEST_CASE_PROPERTIES_TAEF_FOCUS() \\\n        BEGIN_TEST_METHOD_PROPERTIES() \\\n            TEST_METHOD_PROPERTY(L\"Setup\", L\"1\") \\\n            TEST_METHOD_PROPERTY(L\"Focus\", L\"1\") \\\n        END_TEST_METHOD_PROPERTIES()\n\n#define DEFINE_TEST_CASE_PROPERTIES_TAEF_FAILING() \\\n        BEGIN_TEST_METHOD_PROPERTIES() \\\n            TEST_METHOD_PROPERTY(L\"Setup\", L\"1\") \\\n            TEST_METHOD_PROPERTY(L\"Failing\", L\"1\") \\\n        END_TEST_METHOD_PROPERTIES()\n\n#define DEFINE_TEST_CASE_WITH_DATA(TestCaseMethodName,TestCaseDataName,TestCaseDataValues)  \\\n    BEGIN_TEST_METHOD(TestCaseMethodName) \\\n        TEST_METHOD_PROPERTY(TestCaseDataName,TestCaseDataValues) \\\n    END_TEST_METHOD()\n\n    void VERIFY_ARE_EQUAL_STR(std::wstring expected, std::wstring actual);\n\n    #define DEFINE_TEST_CLASS(x) class x\n    #define DEFINE_TEST_CLASS_PROPS(x) TEST_CLASS(x);\\\n        TEST_CLASS_SETUP(TestClassSetup) { return true; } \\\n        TEST_CLASS_CLEANUP(TestClassCleanup) { return true; }\n    #define DEFINE_TEST_CASE(x) TEST_METHOD(x)\n    #define DEFINE_TEST_CASE_PROPERTIES() DEFINE_TEST_CASE_PROPERTIES_TAEF()\n    #define DEFINE_TEST_CASE_PROPERTIES_IGNORE() DEFINE_TEST_CASE_PROPERTIES_TAEF_IGNORE()\n    #define DEFINE_TEST_CASE_PROPERTIES_FOCUS() DEFINE_TEST_CASE_PROPERTIES_TAEF_FOCUS()\n    #define DEFINE_TEST_CASE_PROPERTIES_FAILING() DEFINE_TEST_CASE_PROPERTIES_TAEF_FAILING()\n    #define VERIFY_ARE_EQUAL_INT(x, y) VERIFY_ARE_EQUAL(static_cast<int64_t>(x), static_cast<int64_t>(y))\n    #define VERIFY_ARE_EQUAL_UINT(x, y) VERIFY_ARE_EQUAL(static_cast<uint64_t>(x), static_cast<uint64_t>(y))\n    #define VERIFY_ARE_EQUAL_DOUBLE(x, y) VERIFY_ARE_EQUAL(static_cast<double>(x), static_cast<double>(y))\n    #define VERIFY_ARE_EQUAL_STR_IGNORE_CASE(x, y) VERIFY_ARE_EQUAL_STRING_IGNORE_CASE(x, y)\n    #define TEST_LOG(x) LogFormatString(x)\n    #define ENABLE_SCREEN_LOGGING 1\n\n    void VerifyEqualStr(const char* expected, const char* actual, std::wstring actualName, const WEX::TestExecution::ErrorInfo& errorInfo);\n    void VerifyEqualStr(const std::string& expected, const std::string& actual, std::wstring actualName, const WEX::TestExecution::ErrorInfo& errorInfo);\n    void VerifyEqualStr(std::wstring expected, std::wstring actual, std::wstring actualName, const WEX::TestExecution::ErrorInfo& errorInfo);\n    void VerifyEqualStr(std::string expected, std::wstring actual, std::wstring actualName, const WEX::TestExecution::ErrorInfo& errorInfo);\n    void VerifyEqualStr(xsapi_internal_string expected, xsapi_internal_string actual, std::wstring actualName, const WEX::TestExecution::ErrorInfo& errorInfo);\n#define VERIFY_ARE_EQUAL_STR(__expected, __actual) VerifyEqualStr((__expected), (__actual), (L#__actual), PRIVATE_VERIFY_ERROR_INFO)\n#else\n    #define DEFINE_TEST_CLASS(x) TEST_CLASS(x)\n    #define DEFINE_TEST_CLASS_PROPS(x)\n    #define DEFINE_TEST_CASE(x) TEST_METHOD(x)\n    #define DEFINE_TEST_CASE_PROPERTIES()\n    #define DEFINE_TEST_CASE_PROPERTIES_IGNORE()\n    #define DEFINE_TEST_CASE_PROPERTIES_FOCUS()\n    #define DEFINE_TEST_CASE_PROPERTIES_FAILING()\n    #define TEST_LOG(x) Logger::WriteMessage(x)\n    #define VERIFY_ARE_NOT_EQUAL(expected, actual) Assert::AreNotEqual(expected, actual)\n    #define VERIFY_IS_NOT_NULL(x) Assert::IsNotNull(x)\n#endif\n\n\n\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/UnitTestBase.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"UnitTestBase.h\"\n#include <Objbase.h>\n#if USING_TAEF\n#include \"WexTestClass.h\"\n#include <TraceLoggingProvider.h>\n#else \n#include <CppUnitTestLogger.h>\n#endif\n#include \"user.h\"\n#include \"xbox_live_context_internal.h\"\n\nusing namespace WEX::Logging;\nusing namespace WEX::TestExecution;\nusing namespace WEX::Common;\n\nBEGIN_MODULE()\n    MODULE_PROPERTY(L\"XtpAreaPath\", L\"XBox Live\\\\Client\") \nEND_MODULE()\n\nMODULE_SETUP(ModuleSetup);\nMODULE_CLEANUP(ModuleCleanup);\n\n////////////////////////////////////////////////////////////////////////////////\nbool ModuleSetup()\n{\n#pragma warning(suppress: 6031)\n    CoInitializeEx(nullptr, COINIT_MULTITHREADED);\n    WEX::Common::String strOpt;\n\n    if (!IsDebuggerPresent())\n    {\n        _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);\n        _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);\n    }\n\n    return true;\n}\n\n////////////////////////////////////////////////////////////////////////////////\nbool ModuleCleanup()\n{\n    CoUninitialize();\n    return true;\n}\n\n/// <summary>\n/// Formats the string with StringCchVPrintfW. Trims string if size is greater than 2048.\n/// </summary>\n/// <param name=\"strMsg\">The formatter string and/or message to log</param>\n/// <param name=\"args\">The params to log</param>\nstd::wstring FormatString(LPCWSTR strMsg, ...)\n{\n    WCHAR strBuffer[2048];\n\n    va_list args;\n    va_start(args, strMsg);\n    StringCchVPrintfW(strBuffer, 2048, strMsg, args);\n    strBuffer[2047] = L'\\0';\n\n    va_end(args);\n\n    return std::wstring(strBuffer);\n}\n\n/// <summary>\n/// Calls Log::Comment\n/// </summary>\n/// <param name=\"strMsg\">The message to log</param>\nvoid LogFormatString(LPCWSTR strMsg, ...)\n{\n#ifdef USING_TAEF\n#if ENABLE_SCREEN_LOGGING\n    WEX::Logging::Log::Comment(strMsg);\n#endif\n#else \n    Microsoft::VisualStudio::CppUnitTestFramework::Logger::WriteMessage(strMsg);\n#endif\n}\n\n#ifdef USING_TAEF\n\nvoid VerifyEqualStr(\n    const char* expected,\n    const char* actual,\n    std::wstring actualName,\n    const WEX::TestExecution::ErrorInfo& errorInfo\n)\n{\n    VERIFY_IS_EQUAL_STR_HELPER(\n        xbox::services::Utils::StringTFromUtf8(expected),\n        xbox::services::Utils::StringTFromUtf8(actual),\n        actualName.c_str(),\n        errorInfo\n    );\n}\n\nvoid VerifyEqualStr(\n    const std::string& expected,\n    const std::string& actual,\n    std::wstring actualName,\n    const WEX::TestExecution::ErrorInfo& errorInfo\n)\n{\n    VerifyEqualStr(expected.data(), actual.data(), std::move(actualName), errorInfo);\n}\n\nvoid VerifyEqualStr(\n    std::string expected,\n    std::wstring actual,\n    std::wstring actualName,\n    const WEX::TestExecution::ErrorInfo& errorInfo\n    )\n{\n    VERIFY_IS_EQUAL_STR_HELPER(\n        xbox::services::utils::string_t_from_utf8(expected.c_str()),\n        actual, actualName.c_str(), errorInfo\n        );\n}\n\n\n\nvoid VerifyEqualStr(\n    std::wstring expected, \n    std::wstring actual, \n    std::wstring actualName, \n    const WEX::TestExecution::ErrorInfo& errorInfo\n    )\n{\n    VERIFY_IS_EQUAL_STR_HELPER(expected, actual, actualName.c_str(), errorInfo);\n}\n\nvoid VerifyEqualStr(\n    xsapi_internal_string expected,\n    xsapi_internal_string actual,\n    std::wstring actualName,\n    const WEX::TestExecution::ErrorInfo& errorInfo\n    )\n{\n    VerifyEqualStr(expected.data(), actual.data(), std::move(actualName), errorInfo);\n}\n\n#endif\n\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/UnitTestBase.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"shared_macros.h\"\n#include \"WexTestClass.h\"\n\n#define DATETIME_STRING_LENGTH_TO_SECOND 19\n#define TICKS_PER_SECOND 10000000i64\ntypedef std::chrono::duration<long long, std::ratio<1, 10000000>> ticks;\n\n#define MOCK_XUID 101010101010\n#define MOCK_GAMERTAG \"MockLocalUser\"\n\nstd::wstring FormatString(LPCWSTR strMsg, ...);\nvoid LogFormatString(LPCWSTR strMsg, ...);\n\n#define VERIFY_ARE_EQUAL_STRING_IGNORE_CASE(__str1, __str2) COMPARE_STR_IGNORE_CASE_HELPER(__str1, __str2, PRIVATE_VERIFY_ERROR_INFO)\n\ninline void COMPARE_STR_IGNORE_CASE_HELPER(LPCWSTR pwsz1, LPCWSTR pwsz2, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    WEX::Logging::Log::Comment( FormatString(L\"Verify: AreEqualIgnoreCase(%s, %s)\", pwsz1, pwsz2).c_str() );\n    if( _wcsicmp(pwsz1, pwsz2) != 0 )\n    {\n        WEX::Logging::Log::Error( FormatString( L\"EXPECTED: \\\"%s\\\"\", pwsz1 ).c_str());\n        WEX::Logging::Log::Error( FormatString( L\"ACTUAL: \\\"%s\\\"\", pwsz2 ).c_str());\n        WEX::TestExecution::Private::MacroVerify::IsTrue(false, L\"false\", errorInfo, nullptr);\n    }\n}\n\ninline void COMPARE_STR_IGNORE_CASE_HELPER(const char* lhs, const char* rhs, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    COMPARE_STR_IGNORE_CASE_HELPER(utils::string_t_from_utf8(lhs).data(), utils::string_t_from_utf8(rhs).data(), errorInfo);\n}\n\n#define VERIFY_IS_EQUAL_STR(__expected, __actual, ...) VERIFY_IS_EQUAL_STR_HELPER((__expected), (__actual), (L#__actual), PRIVATE_VERIFY_ERROR_INFO)\n\ninline void VERIFY_IS_EQUAL_STR_HELPER(std::wstring expected, std::wstring actual, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    if (expected != actual)\n    {\n        WEX::Logging::Log::Error(FormatString(L\"EXPECTED: %s = \\\"%s\\\"\", pszParamName, expected.c_str()).c_str());\n        WEX::Logging::Log::Error(FormatString(L\"ACTUAL: %s = \\\"%s\\\"\", pszParamName, actual.c_str()).c_str());\n        WEX::TestExecution::Private::MacroVerify::IsTrue(false, L\"false\", errorInfo, nullptr);\n    }\n    else\n    {\n        WEX::Logging::Log::Comment(FormatString(L\"Verify: AreEqual(%s,\\\"%s\\\")\", pszParamName, expected.c_str()).c_str());\n    }\n}\n\ninline void VERIFY_IS_EQUAL_STR_HELPER(const char* expected, const char* actual, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    if (strcmp(expected, actual) != 0)\n    {\n        WEX::Logging::Log::Error(FormatString(L\"EXPECTED: %s = \\\"%s\\\"\", pszParamName, expected).c_str());\n        WEX::Logging::Log::Error(FormatString(L\"ACTUAL: %s = \\\"%s\\\"\", pszParamName, actual).c_str());\n        WEX::TestExecution::Private::MacroVerify::IsTrue(false, L\"false\", errorInfo, nullptr);\n    }\n    else\n    {\n        WEX::Logging::Log::Comment(FormatString(L\"Verify: AreEqual(%s,\\\"%s\\\")\", pszParamName, expected).c_str());\n    }\n}\n\ninline void VERIFY_IS_EQUAL_STR_HELPER(LPCWSTR pwsz1, LPCWSTR pwsz2, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    if (pwsz1 == nullptr && pwsz2 == nullptr)\n    {\n        WEX::Logging::Log::Comment(FormatString(L\"Verify: AreEqual(%s)\", pszParamName).c_str());\n    }\n    else if (pwsz1 == nullptr || pwsz2 == nullptr)\n    {\n        WEX::Logging::Log::Error(FormatString(L\"EXPECTED: %s = \\\"%s\\\"\", pszParamName, pwsz1 == nullptr ? L\"\" : pwsz1).c_str());\n        WEX::Logging::Log::Error(FormatString(L\"ACTUAL: %s = \\\"%s\\\"\", pszParamName, pwsz1 == nullptr ? L\"\" : pwsz2).c_str());\n        WEX::TestExecution::Private::MacroVerify::IsTrue(false, L\"false\", errorInfo, nullptr);\n    }\n    else\n    {\n        if (CSTR_EQUAL != CompareStringEx(\n            LOCALE_NAME_INVARIANT,\n            0,\n            pwsz1,\n            -1,\n            pwsz2,\n            -1,\n            NULL,\n            NULL,\n            0))\n        {\n            WEX::Logging::Log::Error(FormatString(L\"EXPECTED: %s = \\\"%s\\\"\", pszParamName, pwsz1).c_str());\n            WEX::Logging::Log::Error(FormatString(L\"ACTUAL: %s = \\\"%s\\\"\", pszParamName, pwsz2).c_str());\n            WEX::TestExecution::Private::MacroVerify::IsTrue(false, L\"false\", errorInfo, nullptr);\n        }\n        else\n        {\n            WEX::Logging::Log::Comment(FormatString(L\"Verify: AreEqual(%s,\\\"%s\\\")\", pszParamName, pwsz1).c_str());\n        }\n    }\n}\n\n#define VERIFY_IS_EQUAL_JSON_FROM_STRINGS(__expected, __actual, ...) VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS((__expected), (__actual), (L#__actual), PRIVATE_VERIFY_ERROR_INFO)\n\n#define VERIFY_IS_EQUAL_JSON(__expected, __actual, ...) VERIFY_IS_EQUAL_JSON_HELPER((__expected), (__actual), (L#__actual), PRIVATE_VERIFY_ERROR_INFO)\n\ninline void VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(const JsonValue& expected, const JsonValue& actual, bool& jsonMatches)\n{\n    if (expected.IsObject())\n    {\n        for (auto& jsonValue : expected.GetObject())\n        {\n            if (actual.IsObject() && actual.HasMember(jsonValue.name.GetString()))\n            {\n                const JsonValue& actualValue = actual[jsonValue.name.GetString()];\n                if (actualValue.IsNull() && !jsonValue.value.IsNull())\n                {\n                    jsonMatches = false;\n                    WEX::Logging::Log::Error(FormatString(L\"JSON Key Not Present %s\", jsonValue.name.GetString()).c_str());\n                    return;\n                }\n\n                WEX::Logging::Log::Comment(FormatString(L\"Testing JSON Key %s\", jsonValue.name.GetString()).c_str());\n                VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(jsonValue.value, actualValue, jsonMatches);\n            }\n            else\n            {\n                jsonMatches = false;\n                WEX::Logging::Log::Error(FormatString(L\"JSON Key Not Present %s\", jsonValue.name.GetString()).c_str());\n                return;\n            }\n        }\n    }\n    else\n    {\n        VERIFY_IS_EQUAL_STR(JsonUtils::SerializeJson(expected).c_str(), JsonUtils::SerializeJson(actual).c_str());\n    }\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER(const JsonValue& expected, const JsonValue& actual, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    bool jsonMatches1 = true;\n    bool jsonMatches2 = true;\n    VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(expected, actual, jsonMatches1);\n    VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(actual, expected, jsonMatches2);\n    \n    if (jsonMatches1 && jsonMatches2)\n    {\n        WEX::Logging::Log::Comment(FormatString(L\"Verify: AreEqual(%s,\\\"%s\\\")\", JsonUtils::SerializeJson(expected).c_str(), JsonUtils::SerializeJson(actual).c_str()).c_str());\n    }\n    else\n    {\n        WEX::Logging::Log::Error(FormatString(L\"EXPECTED: %s = \\\"%s\\\"\", pszParamName, JsonUtils::SerializeJson(expected).c_str()).c_str());\n        WEX::Logging::Log::Error(FormatString(L\"ACTUAL: %s = \\\"%s\\\"\", pszParamName, JsonUtils::SerializeJson(actual).c_str()).c_str());\n        WEX::TestExecution::Private::MacroVerify::IsTrue(false, L\"false\", errorInfo, nullptr);\n    }\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS(std::wstring expected, std::wstring actual, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    JsonDocument expectedJson;\n    expectedJson.Parse(utils::internal_string_from_string_t(expected).c_str());\n    JsonDocument actualJson;\n    actualJson.Parse(utils::internal_string_from_string_t(actual).c_str());\n    return VERIFY_IS_EQUAL_JSON_HELPER(expectedJson, actualJson, pszParamName, errorInfo);\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS(std::wstring expected, xsapi_internal_string actual, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    JsonDocument expectedJson;\n    expectedJson.Parse(utils::internal_string_from_string_t(expected).c_str());\n    JsonDocument actualJson;\n    actualJson.Parse(actual.c_str());\n    return VERIFY_IS_EQUAL_JSON_HELPER(expectedJson, actualJson, pszParamName, errorInfo);\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS(xsapi_internal_string expected, xsapi_internal_string actual, const wchar_t* pszParamName, const WEX::TestExecution::ErrorInfo& errorInfo)\n{\n    JsonDocument expectedJson;\n    expectedJson.Parse(expected.c_str());\n    JsonDocument actualJson;\n    actualJson.Parse(actual.c_str());\n    return VERIFY_IS_EQUAL_JSON_HELPER(expectedJson, actualJson, pszParamName, errorInfo);\n}\n\n#define VERIFY_THROWS_HR(__operation, __hr)                                                                                                                                     \\\n{                                                                                                                                                                               \\\n    bool __exceptionHit = false;                                                                                                                                                \\\n    try                                                                                                                                                                         \\\n    {                                                                                                                                                                           \\\n        __operation;                                                                                                                                                            \\\n    }                                                                                                                                                                           \\\n    catch(...)                                                                                                                                                                  \\\n    {                                                                                                                                                                           \\\n        HRESULT hrGot = legacy::ConvertExceptionToHRESULT();                                                                                                                     \\\n        if(hrGot == __hr)                                                                                                                                                       \\\n        {                                                                                                                                                                       \\\n            WEX::Logging::Log::Comment( FormatString( L\"Verify: Expected Exception Thrown ( hr == %s )\", L#__hr ).c_str() );                                                    \\\n            __exceptionHit = true;                                                                                                                                              \\\n        }                                                                                                                                                                       \\\n    }                                                                                                                                                                           \\\n    if(!__exceptionHit)                                                                                                                                                         \\\n    {                                                                                                                                                                           \\\n        WEX::Logging::Log::Comment( FormatString( L\"Error: Expected Exception Not Thrown ( hr == %s )\", L#__hr ).c_str() );                                                     \\\n        (bool)WEX::TestExecution::Private::MacroVerify::Fail(PRIVATE_VERIFY_ERROR_INFO, FormatString( L\"Expected Exception Not Thrown ( hr == %s )\", L#__hr ).c_str());         \\\n    }                                                                                                                                                                           \\\n}\n\ninline bool VerifyTime(time_t time, std::string timeString)\n{\n    auto datetime = xbox::services::datetime::from_string(timeString.data(), xbox::services::datetime::date_format::ISO_8601);\n    return xbox::services::utils::time_t_from_datetime(datetime) == time;\n}"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/UnitTestIncludes_TAEF.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"UnitTestBase.h\"\n#include \"DefineTestMacros.h\"\n#include \"WexTestClass.h\"\n\n#define VERIFY_INVALIDARG(x) \\\n    VERIFY_ARE_EQUAL(E_INVALIDARG, x);"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/ITestResource.h",
    "content": "/*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n*\n*/\n#pragma once\n#include \"unknwn.h\"\n\nnamespace WEX { namespace TestExecution\n{\n    namespace TestResourceProperty\n    {\n        // the following are reserved and must have property for any TestResource definition\n        static const wchar_t c_szName[] = L\"Name\";\n        static const wchar_t c_szId[] = L\"Id\";\n        static const wchar_t c_szGuid[] = L\"GUID\";\n        static const wchar_t c_szType[] = L\"Type\";\n    }\n\n    struct __declspec(novtable) __declspec(uuid(\"79098e4c-b78d-434b-854d-2b59f5c4acc5\")) ITestResource : public IUnknown\n    {\n    public:\n        virtual HRESULT STDMETHODCALLTYPE GetGuid(GUID* pGuid) = 0;\n        virtual HRESULT STDMETHODCALLTYPE SetGuid(GUID guid) = 0;\n        virtual HRESULT STDMETHODCALLTYPE GetValue(BSTR name, BSTR* pValue) = 0;\n        virtual HRESULT STDMETHODCALLTYPE SetValue(BSTR name, BSTR value) = 0;\n    };\n} /*namespace TestExecution*/ } /*namespace WEX*/"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Interruption.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>API and data types for interacting with TAEF during Reboot scenarios.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"TE.Common.h\"\n\nnamespace WEX { namespace TestExecution\n{\n    namespace RebootOption\n    {\n        enum Option\n        {\n            Rerun,\n            Continue\n        };\n    }\n\n    namespace Interruption\n    {\n        TECOMMON_API void __stdcall Reboot(RebootOption::Option option);\n        TECOMMON_API void __stdcall RebootCustom(RebootOption::Option option);\n    }\n} /* TestExecution */ } /* namespace WEX */\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Log.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Public logging interface for C++ tests.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Logger.h\"\n\n#include \"LogTestResults.h\"\n\n// Allow anyone who has defined an Assert macro to compile with this header file included\n#pragma push_macro(\"Assert\")\n#undef Assert\n\n#pragma push_macro(\"SEALED\")\n#undef SEALED\n\n#if _MSC_VER >= 1800\n# define SEALED final\n#elif _MSC_VER >= 1400\n# define SEALED sealed\n#elif defined(_MSC_VER)\n# define SEALED\n#else\n# define SEALED final\n#endif\n\nnamespace WEX { namespace Logging\n{\n    /// <summary>\n    ///\n    /// </summary>\n    class WEXLOGGER_API Log SEALED\n    {\n    public:\n        /// <summary>\n        /// Log a test assert\n        /// </summary>\n        /// <param name=\"pszAssert\"> </param>\n        static void __stdcall Assert(const wchar_t* pszAssert);\n\n        /// <summary>\n        /// Log a test assert\n        /// </summary>\n        /// <param name=\"pszAssert\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Assert(const wchar_t* pszAssert, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test assert\n        /// </summary>\n        /// <param name=\"pszAssert\"> </param>\n        /// <param name=\"pszFile\"> </param>\n        /// <param name=\"pszFunction\"> </param>\n        /// <param name=\"line\"> </param>\n        static void __stdcall Assert(const wchar_t* pszAssert, const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Log a test assert\n        /// </summary>\n        /// <param name=\"pszAssert\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pszFile\"> </param>\n        /// <param name=\"pszFunction\"> </param>\n        /// <param name=\"line\"> </param>\n        static void __stdcall Assert(const wchar_t* pszAssert, const wchar_t* pszContext, const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Log a known bug number\n        /// </summary>\n        /// <param name=\"pszBugDatabase\"> </param>\n        /// <param name=\"bugId\"> </param>\n        static void __stdcall Bug(const wchar_t* pszBugDatabase, int bugId);\n\n        /// <summary>\n        /// Log a known bug number\n        /// </summary>\n        /// <param name=\"pszBugDatabase\"> </param>\n        /// <param name=\"bugId\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Bug(const wchar_t* pszBugDatabase, int bugId, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test comment\n        /// </summary>\n        /// <param name=\"pszComment\"> </param>\n        static void __stdcall Comment(const wchar_t* pszComment);\n\n        /// <summary>\n        /// Log a test comment\n        /// </summary>\n        /// <param name=\"pszComment\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Comment(const wchar_t* pszComment, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log the end of a group of tests, or of a specific test\n        /// </summary>\n        /// <param name=\"pszGroupName\"> </param>\n        static void __stdcall EndGroup(const wchar_t* pszGroupName);\n\n        /// <summary>\n        /// Log the end of a group of tests, or of a specific test\n        /// </summary>\n        /// <param name=\"pszGroupName\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall EndGroup(const wchar_t* pszGroupName, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test error\n        /// </summary>\n        /// <param name=\"pszError\"> </param>\n        static void __stdcall Error(const wchar_t* pszError);\n\n        /// <summary>\n        /// Log a test error\n        /// </summary>\n        /// <param name=\"pszError\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Error(const wchar_t* pszError, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test error\n        /// </summary>\n        /// <param name=\"pszError\"> </param>\n        /// <param name=\"pszFile\"> </param>\n        /// <param name=\"pszFunction\"> </param>\n        /// <param name=\"line\"> </param>\n        static void __stdcall Error(const wchar_t* pszError, const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Log a test error\n        /// </summary>\n        /// <param name=\"pszError\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pszFile\"> </param>\n        /// <param name=\"pszFunction\"> </param>\n        /// <param name=\"line\"> </param>\n        static void __stdcall Error(const wchar_t* pszError, const wchar_t* pszContext, const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Log a test file to be saved to disk\n        /// </summary>\n        /// <param name=\"pszFilePath\"> </param>\n        static void __stdcall File(const wchar_t* pszFilePath);\n\n        /// <summary>\n        /// Log a test file to be saved to disk\n        /// </summary>\n        /// <param name=\"pszFilePath\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall File(const wchar_t* pszFilePath, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test file (in byte array form) to be saved to disk\n        /// </summary>\n        /// <param name=\"pszFileName\"> </param>\n        /// <param name=\"pFileBuffer\"> </param>\n        /// <param name=\"bufferSize\"> </param>\n        static void __stdcall File(const wchar_t* pszFileName, const unsigned char* pFileBuffer, size_t bufferSize);\n\n        /// <summary>\n        /// Log a test file (in byte array form) to be saved\n        /// </summary>\n        /// <param name=\"pszFileName\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pFileBuffer\"> </param>\n        /// <param name=\"bufferSize\"> </param>\n        static void __stdcall File(const wchar_t* pszFileName, const wchar_t* pszContext, const unsigned char* pFileBuffer, size_t bufferSize);\n\n        /// <summary>\n        /// Log a name/value property pair; the value can be in xml format\n        /// </summary>\n        /// <param name=\"pszName\"> </param>\n        /// <param name=\"pszValue\"> </param>\n        static void __stdcall Property(const wchar_t* pszName, const wchar_t* pszValue);\n\n        /// <summary>\n        /// Log a name/value property pair; the value can be in xml format\n        /// </summary>\n        /// <param name=\"pszName\"> </param>\n        /// <param name=\"pszValue\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Property(const wchar_t* pszName, const wchar_t* pszValue, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test result\n        /// </summary>\n        /// <param name=\"testResult\"> </param>\n        static void __stdcall Result(TestResults::Result testResult);\n\n        /// <summary>\n        /// Log a test result\n        /// </summary>\n        /// <param name=\"testResult\"> </param>\n        /// <param name=\"pszComment\"> </param>\n        static void __stdcall Result(TestResults::Result testResult, const wchar_t* pszComment);\n\n        /// <summary>\n        /// Log a test result\n        /// </summary>\n        /// <param name=\"testResult\"> </param>\n        /// <param name=\"pszComment\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Result(TestResults::Result testResult, const wchar_t* pszComment, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log the start of a group of tests, or of a specific test\n        /// </summary>\n        /// <param name=\"pszGroupName\"> </param>\n        static void __stdcall StartGroup(const wchar_t* pszGroupName);\n\n        /// <summary>\n        /// Log the start of a group of tests, or of a specific test; also sets the default test result\n        /// </summary>\n        /// <param name=\"pszGroupName\"> </param>\n        /// <param name=\"defaultTestResult\"> </param>\n        static void __stdcall StartGroup(const wchar_t* pszGroupName, TestResults::Result defaultTestResult);\n\n        /// <summary>\n        /// Log the start of a group of tests, or of a specific test\n        /// </summary>\n        /// <param name=\"pszGroupName\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall StartGroup(const wchar_t* pszGroupName, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log the start of a group of tests, or of a specific test; also sets the default test result\n        /// </summary>\n        /// <param name=\"pszGroupName\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"defaultTestResult\"> </param>\n        static void __stdcall StartGroup(const wchar_t* pszGroupName, const wchar_t* pszContext, TestResults::Result defaultTestResult);\n\n        /// <summary>\n        /// Log a test warning\n        /// </summary>\n        /// <param name=\"pszWarning\"> </param>\n        static void __stdcall Warning(const wchar_t* pszWarning);\n\n        /// <summary>\n        /// Log a test warning\n        /// </summary>\n        /// <param name=\"pszWarning\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Warning(const wchar_t* pszWarning, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log a test warning\n        /// </summary>\n        /// <param name=\"pszWarning\"> </param>\n        /// <param name=\"pszFile\"> </param>\n        /// <param name=\"pszFunction\"> </param>\n        /// <param name=\"line\"> </param>\n        static void __stdcall Warning(const wchar_t* pszWarning, const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Log a test warning\n        /// </summary>\n        /// <param name=\"pszWarning\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pszFile\"> </param>\n        /// <param name=\"pszFunction\"> </param>\n        /// <param name=\"line\"> </param>\n        static void __stdcall Warning(const wchar_t* pszWarning, const wchar_t* pszContext, const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Log xml data; no check is made to verify that it is well-formed\n        /// </summary>\n        /// <param name=\"pszXml\"> </param>\n        static void __stdcall Xml(const wchar_t* pszXml);\n\n        /// <summary>\n        /// Log xml data; no check is made to verify that it is well-formed\n        /// </summary>\n        /// <param name=\"pszXml\"> </param>\n        /// <param name=\"pszContext\"> </param>\n        static void __stdcall Xml(const wchar_t* pszXml, const wchar_t* pszContext);\n\n        /// <summary>\n        /// Log the current process mini dump\n        /// </summary>\n        static void __stdcall MiniDump();\n\n        // wchar_t native type exports\n        #ifdef WEXLOGGER_EXPORTS\n        static void __stdcall Assert(const __wchar_t* pszAssert); \n        static void __stdcall Assert(const __wchar_t* pszAssert, const __wchar_t* pszContext); \n        static void __stdcall Assert(const __wchar_t* pszAssert, const __wchar_t* pszFile, const __wchar_t* pszFunction, int line); \n        static void __stdcall Assert(const __wchar_t* pszAssert, const __wchar_t* pszContext, const __wchar_t* pszFile, const __wchar_t* pszFunction, int line); \n\n        static void __stdcall Bug(const __wchar_t* pszBugDatabase, int bugId); \n        static void __stdcall Bug(const __wchar_t* pszBugDatabase, int bugId, const __wchar_t* pszContext); \n\n        static void __stdcall Comment(const __wchar_t* pszComment);\n        static void __stdcall Comment(const __wchar_t* pszComment, const __wchar_t* pszContext);\n\n        static void __stdcall EndGroup(const __wchar_t* pszGroupName);\n        static void __stdcall EndGroup(const __wchar_t* pszGroupName, const __wchar_t* pszContext);\n\n        static void __stdcall Error(const __wchar_t* pszError);\n        static void __stdcall Error(const __wchar_t* pszError, const __wchar_t* pszContext);\n        static void __stdcall Error(const __wchar_t* pszError, const __wchar_t* pszFile, const __wchar_t* pszFunction, int line);\n        static void __stdcall Error(const __wchar_t* pszError, const __wchar_t* pszContext, const __wchar_t* pszFile, const __wchar_t* pszFunction, int line);\n\n        static void __stdcall File(const __wchar_t* pszFilePath);\n        static void __stdcall File(const __wchar_t* pszFilePath, const __wchar_t* pszContext);\n        static void __stdcall File(const __wchar_t* pszFileName, const unsigned char* pFileBuffer, size_t bufferSize);\n        static void __stdcall File(const __wchar_t* pszFileName, const __wchar_t* pszContext, const unsigned char* pFileBuffer, size_t bufferSize);\n\n        static void __stdcall Property(const __wchar_t* pszName, const __wchar_t* pszValue);\n        static void __stdcall Property(const __wchar_t* pszName, const __wchar_t* pszValue, const __wchar_t* pszContext);\n\n        static void __stdcall Result(TestResults::Result testResult, const __wchar_t* pszComment);\n        static void __stdcall Result(TestResults::Result testResult, const __wchar_t* pszComment, const __wchar_t* pszContext);\n\n        static void __stdcall StartGroup(const __wchar_t* pszGroupName);\n        static void __stdcall StartGroup(const __wchar_t* pszGroupName, TestResults::Result defaultTestResult);\n        static void __stdcall StartGroup(const __wchar_t* pszGroupName, const __wchar_t* pszContext);\n        static void __stdcall StartGroup(const __wchar_t* pszGroupName, const __wchar_t* pszContext, TestResults::Result defaultTestResult);\n\n        static void __stdcall Warning(const __wchar_t* pszWarning);\n        static void __stdcall Warning(const __wchar_t* pszWarning, const __wchar_t* pszContext);\n        static void __stdcall Warning(const __wchar_t* pszWarning, const __wchar_t* pszFile, const __wchar_t* pszFunction, int line);\n        static void __stdcall Warning(const __wchar_t* pszWarning, const __wchar_t* pszContext, const __wchar_t* pszFile, const __wchar_t* pszFunction, int line);\n\n        static void __stdcall Xml(const __wchar_t* pszXml);\n        static void __stdcall Xml(const __wchar_t* pszXml, const __wchar_t* pszContext);\n        #endif\n    private:\n        Log(); // Disallow construction of static class\n        ~Log(); // Disallow destruction of static class\n        Log(const Log&); // non-implemented\n        Log& operator=(const Log&); // non-implemented\n    };\n} /* namespace Logging */ } /* namespace WEX */\n\n#pragma pop_macro(\"SEALED\")\n#pragma pop_macro(\"Assert\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/LogTestResults.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Possible WexLogger test results.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n\nnamespace WEX { namespace Logging \n{\n    namespace TestResults\n    {\n        /// <summary>\n        /// Possible WexLogger test results.\n        /// </summary>\n        enum Result\n        {\n            /// <summary>The test passed.</summary>\n            Passed = 0,\n\n            /// <summary>The test was not run.</summary>\n            NotRun,\n\n            /// <summary>The test was skipped.</summary>\n            Skipped,\n\n            /// <summary>The test was blocked.</summary>\n            Blocked,\n\n            /// <summary>The test failed.</summary>\n            Failed,\n\n            /// <summary>The test result is unknown.</summary>\n            Unknown\n        };\n    }\n} /* namespace Logging */ } /* namespace WEX */\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Logcontext.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Class used for opening/closing log contexts.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Logger.h\"\n#include \"Log.h\"\n\n#pragma push_macro(\"SEALED\")\n#undef SEALED\n\n#if _MSC_VER >= 1800\n# define SEALED final\n#elif _MSC_VER >= 1400\n# define SEALED sealed\n#elif defined(_MSC_VER)\n# define SEALED\n#else\n# define SEALED final\n#endif\n\nnamespace WEX { namespace Logging\n{\n    /// <summary>\n    ///\n    /// </summary>\n    class WEXLOGGER_API LogContext SEALED\n    {\n    public:\n        /// <summary>\n        /// Create a new context\n        /// </summary>\n        /// <param name=\"pszParentContext\"> </param>\n        /// <param name=\"pszChildContext\"> </param>\n        /// <param name=\"pszChildData\"> </param>\n        static void __stdcall CreateContext(const wchar_t* pszParentContext, const wchar_t* pszChildContext, const wchar_t* pszChildData);\n        \n        /// <summary>\n        /// Close the specified context, and assign it the specified test result\n        /// </summary>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"testResult\"> </param>\n        static void __stdcall CloseContext(const wchar_t* pszContext, TestResults::Result testResult);\n\n        /// <summary>\n        /// Log a comment in plain text for the specified context\n        /// </summary>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pszComment\"> </param>\n        static void __stdcall LogComment(const wchar_t* pszContext, const wchar_t* pszComment);\n\n        /// <summary>\n        /// Log a test file to be saved for the specified context\n        /// </summary>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pszFileName\"> </param>\n        static void __stdcall LogFile(const wchar_t* pszContext, const wchar_t* pszFileName);\n\n        /// <summary>\n        /// Log xml data for the specified context; no check is made to verify that it is well-formed\n        /// </summary>\n        /// <param name=\"pszContext\"> </param>\n        /// <param name=\"pszXml\"> </param>\n        static void __stdcall LogXml(const wchar_t* pszContext, const wchar_t* pszXml);\n\n        // wchar_t native type exports\n        #ifdef WEXLOGGER_EXPORTS\n        static void __stdcall CreateContext(const __wchar_t* pszParentContext, const __wchar_t* pszChildContext, const __wchar_t* pszChildData);\n        static void __stdcall CloseContext(const __wchar_t* pszContext, TestResults::Result testResult);\n        static void __stdcall LogComment(const __wchar_t* pszContext, const __wchar_t* pszComment);\n        static void __stdcall LogFile(const __wchar_t* pszContext, const __wchar_t* pszFileName);\n        static void __stdcall LogXml(const __wchar_t* pszContext, const __wchar_t* pszXml);\n        #endif\n\n    private:\n        LogContext(); // Disallow construction of static class\n        ~LogContext(); // Disallow destruction of static class\n        LogContext(const LogContext&); // non-implemented\n        LogContext& operator=(const LogContext&); // non-implemented\n    };\n} /* namespace Logging */ } /* namespace WEX */\n\n#pragma pop_macro(\"SEALED\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Logcontroller.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Class used for logging initialization and finalization.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Logger.h\"\n#include \"WexString.h\"\n\n#pragma push_macro(\"SEALED\")\n#undef SEALED\n\n#if _MSC_VER >= 1800\n# define SEALED final\n#elif _MSC_VER >= 1400\n# define SEALED sealed\n#elif defined(_MSC_VER)\n# define SEALED\n#else\n# define SEALED final\n#endif\n\n/// \\namespace WEX::Logging\n/// <summary>\n/// The WEX::Logging namespace contains the Native API's for the Wex Logger.\n/// </summary>\nnamespace WEX { namespace Logging \n{\n    /// <summary>\n    /// \n    /// </summary>\n    typedef void (__stdcall *WexLoggerErrorCallback)(const unsigned short* pszMessage, HRESULT hr);\n\n    /// <summary>\n    /// \n    /// </summary>\n    class WEXLOGGER_API LogController SEALED\n    {\n    public:\n        /// <summary>\n        /// Initialize logging functionality\n        /// </summary>\n        static HRESULT __stdcall InitializeLogging();\n\n        /// <summary>\n        /// Initialize logging functionality and provide a callback to be notified of any logging errors\n        /// </summary>\n        /// <param name=\"pfnErrorCallback\"> </param>\n        static HRESULT __stdcall InitializeLogging(WexLoggerErrorCallback pfnErrorCallback);\n\n        /// <summary>\n        /// Initialize logging functionality and specify the log name\n        /// </summary>\n        /// <param name=\"pszLogName\"> </param>\n        static HRESULT __stdcall InitializeLogging(_In_z_ const wchar_t* pszLogName);\n\n        /// <summary>\n        /// Initialize logging functionality, specify the log name and provide a callback to be notified of any logging errors\n        /// </summary>\n        /// <param name=\"pszLogName\"> </param>\n        /// <param name=\"pfnErrorCallback\"> </param>\n        static HRESULT __stdcall InitializeLogging(_In_z_ const wchar_t* pszLogName, WexLoggerErrorCallback pfnErrorCallback);\n\n        /// <summary>\n        /// Returns whether or not the LogController has been initialized for this process\n        /// </summary>\n        static bool __stdcall IsInitialized();\n\n        /// <summary>\n        /// Returns the name that was specified for the log in the InitializeLogging call (if any)\n        /// </summary>\n        static const unsigned short* __stdcall GetLogName();\n\n        /// <summary>\n        /// Finalize logging functionality\n        /// </summary>\n        static HRESULT __stdcall FinalizeLogging();\n\n        // wchar_t native type exports\n#ifdef WEXLOGGER_EXPORTS\n        static HRESULT __stdcall InitializeLogging(_In_z_ const __wchar_t* pszLogName);\n        static HRESULT __stdcall InitializeLogging(_In_z_ const __wchar_t* pszLogName, WexLoggerErrorCallback pfnErrorCallback);\n#endif\n\n    private:\n        LogController(); // Disallow construction of static class\n        ~LogController(); // Disallow destruction of static class\n        LogController(const LogController&); // non-implemented\n        LogController& operator=(const LogController&); // non-implemented\n    };\n\n    const wchar_t c_szWexLoggerRemoteConnectionData[] = L\"/wexlogger_connectiondata=\";\n\n    /// <summary>\n    /// Class used for preparing an incoming remote logging connection\n    /// </summary>\n    class WEXLOGGER_API RemoteLogController SEALED\n    {\n    public:\n        /// <summary>\n        /// Generate the connection data needed for the remote process to connect and log back to this process\n        /// </summary>\n        /// <param name=\"connectionData\">Reference to a NoThrowString that will be populated with the connection data</param>\n        static HRESULT __stdcall GenerateConnectionData(WEX::Common::NoThrowString& connectionData);\n\n        /// <summary>\n        /// Generate the connection data needed for the remote process to connect and log back to this process\n        /// </summary>\n        /// <param name=\"pszMachineName\">The name of the machine on which the process will be created; only use this overload when creating a process on a remote machine.</param>\n        /// <param name=\"connectionData\">Reference to a NoThrowString that will be populated with the connection data</param>\n        static HRESULT __stdcall GenerateConnectionData(const wchar_t* pszMachineName, WEX::Common::NoThrowString& connectionData);\n        \n        /// <summary>\n        /// Initialize remote logging functionality\n        /// </summary>\n        /// <param name=\"pszConnectionData\">Connection data used to connect to the remote process for receiving logging messages</param>\n        static HRESULT __stdcall InitializeLogging(_In_z_ const wchar_t* pszConnectionData);\n\n        // wchar_t native type exports\n#ifdef WEXLOGGER_EXPORTS\n        static HRESULT __stdcall GenerateConnectionData(const __wchar_t* pszMachineName, WEX::Common::NoThrowString& connectionData);\n        static HRESULT __stdcall InitializeLogging(_In_z_ const __wchar_t* pszConnectionData);\n#endif\n\n    private:\n        RemoteLogController(); // Disallow construction of static class\n        ~RemoteLogController(); // Disallow destruction of static class\n        RemoteLogController(const RemoteLogController&); // non-implemented\n        RemoteLogController& operator=(const RemoteLogController&); // non-implemented\n    };\n} /* namespace Logging */ } /* namespace WEX */\n#pragma pop_macro(\"SEALED\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/PreserveLastError.h",
    "content": "/*\n* Copyright (c) Microsoft Corporation. All rights reserved.\n*\n*/\n#pragma once\n#include \"Wex.Common.h\"\n#include \"WexDebug.h\"\n\nnamespace WEX { namespace Common\n{\n    class PreserveLastError\n    {\n    public:\n        PreserveLastError()\n        : m_lastError(Debug::GetLastError())\n        {\n        }\n\n        ~PreserveLastError()\n        {\n            Debug::SetLastError(m_lastError);\n        }\n\n    private:\n        unsigned long m_lastError;\n    };\n} /*namespace Common*/ } /*namespace WEX*/"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/RuntimeParameters.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary> API for accessing runtime parameters from native tests </summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"TE.Common.h\"\n#include \"WexTypes.h\"\n\n#include <BaseTyps.h>\n\n#pragma push_macro(\"_In_z_\")\n\n#if !defined(_In_z_)\n#define _In_z_\n#endif\n\nnamespace WEX { namespace TestExecution\n{\n    namespace Private\n    {\n        /// \\internal\n        /// WEX::TestExecution::Private::RuntimeParameters must be a templatized *class* so that we can dll export explicit \n        /// instantiations.\n        template <typename T>\n        class TECOMMON_API RuntimeParameters\n        {\n        public:\n            // Tries to get the requested value in the requested format\n            static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, T& result);\n\n            #ifdef TECOMMON_EXPORTS\n            static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, T& result);\n            #endif\n\n        private:\n            RuntimeParameters(const RuntimeParameters&);\n            RuntimeParameters& operator=(const RuntimeParameters&);\n        };\n    }\n\n    namespace RuntimeParameterConstants\n    {\n        const wchar_t c_szTestDeploymentDir[] = L\"TestDeploymentDir\"; // Constant used to query RunTimeParameters for the directory that the test binary is loaded from\n        const wchar_t c_szTestName[] = L\"TestName\"; // Constant used to query RunTimeParameters for the name of the test that is currently running\n        const wchar_t c_szFullTestName[] = L\"FullTestName\"; // Constant used to query RunTimeParameters for the name of the test variation that is currently running\n        const wchar_t c_szTestResult[] = L\"TestResult\"; // Constant used to query RuntimeParameters for the result of the test(s) run within the scope fo this cleanup function\n    };\n\n    /// <summary>\n    ///  Runtime parameters retrival class\n    /// </summary>\n    /// \\internal\n    /// WEX::TestExecution::RuntimeParameters provides 'templatized' *methods* to allow compiler type inference, and simply routes \n    /// the call to the matching WEX::TestExecution::Private::TestData<T> instantiation.\n    class RuntimeParameters\n    {\n    public:\n        /// <summary>\n        ///  API for runtime parameters retrival\n        /// </summary>\n        /// \\code\n        /// Example:\n        ///    String value;\n        ///    RuntimeParameters::TryGetValue(L\"ParameterName3\", value);\n        /// \\endcode\n        template <typename T>\n        static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, T& result)\n        {\n            return Private::RuntimeParameters<T>::TryGetValue(pszString, result);\n        }\n\n    private:\n        RuntimeParameters(const RuntimeParameters&);\n        RuntimeParameters& operator=(const RuntimeParameters&);\n    };\n\n} /* TestExecution */ } /* namespace WEX */\n\n#pragma pop_macro(\"_In_z_\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/TE.Common.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Common definitions for the Te.Common.dll.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n\n#ifdef TECOMMON_EXPORTS\n# ifndef TECOMMON_API\n#  define TECOMMON_API __declspec(dllexport)\n# endif\n# ifndef TECOMMON_EXPORT_TEMPLATE\n#  define TECOMMON_EXPORT_TEMPLATE\n# endif\n#else\n# ifdef TECOMMON_UNIT_TESTING\n#  ifndef TECOMMON_API\n#   define TECOMMON_API\n#  endif\n#  ifndef TECOMMON_EXPORT_TEMPLATE\n#   define TECOMMON_EXPORT_TEMPLATE\n#  endif\n# else\n#  ifndef TECOMMON_API\n#   define TECOMMON_API __declspec(dllimport)\n#  endif\n#  ifndef TECOMMON_EXPORT_TEMPLATE\n#   define TECOMMON_EXPORT_TEMPLATE extern\n#  endif\n# endif\n#endif\n\n#ifdef UNIT_TESTING\n# define UNIT_TEST_CLASS(__class) __if_exists(__class) { friend class __class; }\n#else\n# define UNIT_TEST_CLASS(__class)\n#endif"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/TestData.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary> API and data types for using data in data driven native tests </summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"TE.Common.h\"\n#include \"WexDebug.h\"\n\n#pragma push_macro(\"SEALED\")\n#undef SEALED\n\n#if _MSC_VER >= 1800\n# define SEALED final\n#elif _MSC_VER >= 1400\n# define SEALED sealed\n#elif defined(_MSC_VER)\n# define SEALED\n#else\n# define SEALED final\n#endif\n\n#pragma push_macro(\"_In_z_\")\n#pragma push_macro(\"_Outptr_\")\n\n#if !defined(_In_z_)\n#define _In_z_\n#endif\n\n#if !defined(_Outptr_)\n#define _Outptr_\n#endif\n\n// Forward define 'IStream'\ntypedef interface IStream IStream;\n\nnamespace WEX { namespace TestExecution\n{\n    class TestDataArrayPrivate;\n\n    /// <summary>\n    ///  A helper class to work with arrays in data driven testing\n    /// </summary>\n    /// \\code\n    /// Example:\n    ///\n    ///  TestDataArray<int> sizes;\n    ///  if (SUCCEEDED(TestData::TryGetValue(L\"size\", sizes)))\n    ///  {\n    ///      size_t count = sizes.GetSize();\n    ///      for (size_t i = 0; i < count; ++i)\n    ///      {\n    ///          Log::Comment(String().Format(L\"Size[%d] retrieved was %d\", i, sizes[i]));\n    ///      }\n    ///  }\n    /// \\endcode\n    template <typename T>\n    class TECOMMON_API TestDataArray SEALED\n    {\n        friend class TestDataArrayPrivate;\n\n    public:\n        TestDataArray();\n        ~TestDataArray();\n        const size_t GetSize() const;\n        T& operator[](size_t index);\n        const T& operator[](size_t index) const;\n\n    private:\n        void Allocate(size_t elements);\n        TestDataArray(const TestDataArray<T>& other);\n        TestDataArray<T>& operator=(TestDataArray<T>& other);\n        void Free();\n        T* Detach();\n\n        /// \\internal\n        /// we need a way to get an address because operator& is overloaded\n        TestDataArray<T>* This() {return this;}\n\n        size_t m_size;\n        T* m_p;\n    };\n\n    namespace Private\n    {\n        /// \\internal\n        /// WEX::TestExecution::Private::TestData must be a templatized *class* so that we can dll export explicit \n        /// instantiations.\n        template <typename T>\n        class TECOMMON_API TestData SEALED\n        {\n        public:\n            /// Tries to get the requested value in the requested format\n            static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, T& result);\n            /// TestDataArray specific TestData implementation\n            static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, TestDataArray<T>& results);\n\n            #ifdef TECOMMON_EXPORTS\n            static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, T& result);\n            static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, TestDataArray<T>& results);\n            #endif\n        };\n\n        class TECOMMON_API XmlTestData SEALED\n        {\n        public:\n            static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, _Outptr_ IStream** result);\n\n            #ifdef TECOMMON_EXPORTS\n            static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, _Outptr_ IStream** result);\n            #endif\n        };\n\n        template <typename T1, typename T2>\n        class AreSameType\n        {\n        public:\n            static const bool value = false;\n        };\n\n        template <typename T1>\n        class AreSameType<T1, T1>\n        {\n        public:\n            static const bool value = true;\n        };\n    }\n\n    /// <summary>\n    ///  Data driven test data retrival class\n    /// </summary>\n    /// \\internal\n    /// WEX::TestExecution::TestData provides templatized *methods* to allow compiler type inference, and simply routes \n    /// the call to the matching WEX::TestExecution::Private::TestData<T> instantiation.\n    class TestData\n    {\n    public:\n\n        /// <summary>\n        ///  Data driven test data retrival API for basic types\n        /// </summary>\n        template <typename T>\n        static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, T& result)\n        {\n            COMPILE_TIME_CHECK_V2((Private::AreSameType<int, T>::value || Private::AreSameType<size_t, T>::value || Private::AreSameType<bool, T>::value ||\n                                Private::AreSameType<float, T>::value || Private::AreSameType<double, T>::value || Private::AreSameType<DWORD, T>::value ||\n                                Private::AreSameType<__int64, T>::value || Private::AreSameType<unsigned __int64, T>::value || Private::AreSameType<unsigned int, T>::value ||\n                                Private::AreSameType<WEX::Common::String, T>::value || Private::AreSameType<WEX::Common::NoThrowString, T>::value),\n                                \"Attempt to use TestData::TryGetValue with an unsupported type\", \n                                Attempt_to_use_TestData_TryGetValue_with_an_unsupported_type);\n            return Private::TestData<T>::TryGetValue(pszString, result);\n        }\n\n        static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, _Outptr_ IStream** result)\n        {\n            return Private::XmlTestData::TryGetValue(pszString, result);\n        }\n\n        /// <summary>\n        ///  Data driven test data retrival API for array types\n        /// </summary>\n        template<typename T>\n        static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, TestDataArray<T>& results)\n        {\n            COMPILE_TIME_CHECK_V2((Private::AreSameType<int, T>::value || Private::AreSameType<size_t, T>::value || Private::AreSameType<bool, T>::value ||\n                                Private::AreSameType<float, T>::value || Private::AreSameType<double, T>::value || Private::AreSameType<DWORD, T>::value ||\n                                Private::AreSameType<__int64, T>::value || Private::AreSameType<unsigned __int64, T>::value || Private::AreSameType<unsigned int, T>::value ||\n                                Private::AreSameType<WEX::Common::String, T>::value || Private::AreSameType<WEX::Common::NoThrowString, T>::value),\n                                \"Attempt to use TestData::TryGetValue with an unsupported type for TestDataArray\", \n                                Attempt_to_use_TestData_TryGetValue_with_an_unsupported_type_for_TestDataArray);\n            return Private::TestData<T>::TryGetValue(pszString, results);\n        }\n\n        #ifdef TECOMMON_EXPORTS\n        template <typename T>\n        static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, T& result)\n        {\n            COMPILE_TIME_CHECK_V2((Private::AreSameType<int, T>::value || Private::AreSameType<size_t, T>::value || Private::AreSameType<bool, T>::value ||\n                                Private::AreSameType<float, T>::value || Private::AreSameType<double, T>::value || Private::AreSameType<DWORD, T>::value ||\n                                Private::AreSameType<__int64, T>::value || Private::AreSameType<unsigned __int64, T>::value || Private::AreSameType<unsigned int, T>::value ||\n                                Private::AreSameType<WEX::Common::String, T>::value || Private::AreSameType<WEX::Common::NoThrowString, T>::value),\n                                \"Attempt to use TestData::TryGetValue with an unsupported type\", \n                                Attempt_to_use_TestData_TryGetValue_with_an_unsupported_type);\n            return Private::TestData<T>::TryGetValue(pszString, result);\n        }\n\n        static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, _Outptr_ IStream** result)\n        {\n            return Private::XmlTestData::TryGetValue(pszString, result);\n        }\n\n        /// <summary>\n        ///  Data driven test data retrival API for array types\n        /// </summary>\n        template<typename T>\n        static HRESULT __stdcall TryGetValue(_In_z_ const __wchar_t* pszString, TestDataArray<T>& results)\n        {\n            COMPILE_TIME_CHECK_V2((Private::AreSameType<int, T>::value || Private::AreSameType<size_t, T>::value || Private::AreSameType<bool, T>::value ||\n                                Private::AreSameType<float, T>::value || Private::AreSameType<double, T>::value || Private::AreSameType<DWORD, T>::value ||\n                                Private::AreSameType<__int64, T>::value || Private::AreSameType<unsigned __int64, T>::value || Private::AreSameType<unsigned int, T>::value ||\n                                Private::AreSameType<WEX::Common::String, T>::value || Private::AreSameType<WEX::Common::NoThrowString, T>::value),\n                                \"Attempt to use TestData::TryGetValue with an unsupported type for TestDataArray\", \n                                Attempt_to_use_TestData_TryGetValue_with_an_unsupported_type_for_TestDataArray);\n            return Private::TestData<T>::TryGetValue(pszString, results);\n        }\n        #endif\n    };\n} /* TestExecution */ } /* namespace WEX */\n\n#pragma pop_macro(\"_In_z_\")\n#pragma pop_macro(\"_Outptr_\")\n#pragma pop_macro(\"SEALED\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Throw.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>\n/// Entry point for throwing WEX::Exceptions.\n/// \n/// Provides helper functions for verifying before throwing, as well as throwing without verification.\n/// </summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Common.h\"\n#include \"WexTypes.h\"\n\n#pragma push_macro(\"_In_opt_z_\")\n#pragma push_macro(\"_In_range_\")\n#pragma push_macro(\"_Maybenull_\")\n#pragma push_macro(\"_When_\")\n\n#if !defined(_In_opt_z_)\n#define _In_opt_z_\n#endif\n\n#if !defined(_In_range_)\n#define _In_range_(a,b)\n#endif\n\n#if !defined(_Maybenull_)\n#define _Maybenull_\n#endif\n\n#if !defined(_When_)\n#define _When_(a,b)\n#endif\n\n/// <summary>\n/// </summary>\nnamespace WEX { namespace Common { namespace Throw\n{\n    // Verify before throwing\n\n    /// <summary>Throws a Wex::Exception if -condition- failed</summary>\n    WEXCOMMON_API void __stdcall IfFailed(HRESULT condition);\n\n    /// <summary>Throws a Wex::Exception if -condition- failed</summary>\n    WEXCOMMON_API void __stdcall IfFailed(HRESULT condition, _In_opt_z_ const wchar_t* pszMessage);\n\n    /// <summary>Throws a Wex::Exception if -condition- *false*</summary>\n    WEXCOMMON_API void __stdcall IfFalse(bool condition, _When_(!condition, _In_range_(<, 0)) HRESULT errorToThrow);\n\n    /// <summary>Throws a Wex::Exception if -condition- *false*</summary>\n    WEXCOMMON_API void __stdcall IfFalse(bool condition, _When_(!condition, _In_range_(<, 0)) HRESULT errorToThrow, _In_opt_z_ const wchar_t* pszMessage);\n\n    /// <summary>Throws a Wex::Exception if -condition- is *true*</summary>\n    WEXCOMMON_API void __stdcall If(bool condition, _When_(condition, _In_range_(<, 0)) HRESULT errorToThrow);\n\n    /// <summary>Throws a Wex::Exception if -condition- is *true*</summary>\n    WEXCOMMON_API void __stdcall If(bool condition, _When_(condition, _In_range_(<, 0)) HRESULT errorToThrow, _In_opt_z_ const wchar_t* pszMessage);\n\n    /// <summary>Throws a Wex::Exception (E_POINTER) if -p- is null</summary>\n    WEXCOMMON_API void __stdcall IfNull(_Maybenull_ const void* p);\n\n    /// <summary>Throws a Wex::Exception (E_POINTER) if -p- is null</summary>\n    WEXCOMMON_API void __stdcall IfNull(_Maybenull_ const void* p, _In_opt_z_ const wchar_t* pszMessage);\n\n    /// <summary>Throws a Wex::Exception with GetLastError() information if -condition- is *true*</summary>\n    WEXCOMMON_API void __stdcall LastErrorIf(bool condition);\n\n    /// <summary>Throws a Wex::Exception with GetLastError() information if -condition- is *true*</summary>\n    WEXCOMMON_API void __stdcall LastErrorIf(bool condition, _In_opt_z_ const wchar_t* pszMessage);\n\n    /// <summary>Throws a Wex::Exception with GetLastError() information if -condition- is *false*</summary>\n    WEXCOMMON_API void __stdcall LastErrorIfFalse(bool condition);\n\n    /// <summary>Throws a Wex::Exception with GetLastError() information if -condition- is *false*</summary>\n    WEXCOMMON_API void __stdcall LastErrorIfFalse(bool condition, _In_opt_z_ const wchar_t* pszMessage);\n\n    // Throw without verification\n\n    /// <summary>Throws a Wex::Exception with the specified parameters</summary>\n    WEXCOMMON_API void __declspec(noreturn) __stdcall Exception(_In_range_(<, 0) HRESULT errorToThrow);\n\n    /// <summary>Throws a Wex::Exception with the specified parameters</summary>\n    WEXCOMMON_API void __declspec(noreturn) __stdcall Exception(_In_range_(<, 0) HRESULT errorToThrow, _In_opt_z_ const wchar_t* pszMessage);\n\n    /// <summary>Throws a Wex::Exception with GetLastError() information</summary>\n    WEXCOMMON_API __declspec(noreturn) void __stdcall LastError();\n\n    /// <summary>Throws a Wex::Exception with GetLastError() information</summary>\n    WEXCOMMON_API __declspec(noreturn) void __stdcall LastError(_In_opt_z_ const wchar_t* pszMessage);\n\n    // wchar_t native type exports\n    #ifdef WEXCOMMON_FULL_BUILD\n    WEXCOMMON_API void __stdcall IfFailed(HRESULT condition, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception if -condition- failed\n    WEXCOMMON_API void __stdcall IfFalse(bool condition, _When_(!condition, _In_range_(<, 0)) HRESULT errorToThrow, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception if -condition- *false*\n    WEXCOMMON_API void __stdcall If(bool condition, _When_(condition, _In_range_(<, 0)) HRESULT errorToThrow, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception if -condition- is *true*\n    WEXCOMMON_API void __stdcall IfNull(_Maybenull_ const void* p, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception (E_POINTER) if -p- is null\n    WEXCOMMON_API void __stdcall LastErrorIf(bool condition, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception with GetLastError() information if -condition- is *true*\n    WEXCOMMON_API void __stdcall LastErrorIfFalse(bool condition, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception with GetLastError() information if -condition- is *false*\n    WEXCOMMON_API __declspec(noreturn) void __stdcall Exception(_In_range_(<, 0) HRESULT errorToThrow, _In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception with the specified parameters\n    WEXCOMMON_API __declspec(noreturn) void __stdcall LastError(_In_opt_z_ const __wchar_t* pszMessage); // Throws a Wex::Exception with GetLastError() information\n    #endif\n\n    namespace Private {\n        // not exported, only declared so that WEX::Common::Exception can befriend it\n        void ThrowImpl(_In_range_(<, 0) HRESULT errorToThrow, _In_opt_z_ const wchar_t* pszMessage);\n    }\n} /* namespace Throw */ } /* namespace Common */ } /* namespace WEX */\n\n#pragma pop_macro(\"_In_opt_z_\")\n#pragma pop_macro(\"_In_range_\")\n#pragma pop_macro(\"_Maybenull_\")\n#pragma pop_macro(\"_When_\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Verify.h",
    "content": "//---------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>File used for test verification purposes.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//---------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include <limits.h>\n#include <winerror.h>\n\n#if (_MSC_VER < 1700)\n# error Unsupported version of Visual Studio. Please use VS 2012 or later.\n#endif\n\n// Without deprecation support StrSafe.h will define 'malicious' macros in an attempt to prevent older API usage.\n// These errors are confusing - deprecation is a lot clearer.\n#if !defined(MIDL_PASS) && !defined(DEPRECATE_SUPPORTED)\n# define DEPRECATE_SUPPORTED\n#endif\n\n#include \"Log.h\"\n#include \"StrSafe.h\"\n#include \"PreserveLastError.h\"\n#include \"WexAssert.h\"\n#include \"WexDebug.h\"\n#include \"WexString.h\"\n#include \"WexTypes.h\"\n\n#pragma push_macro(\"_Post_equal_to_\")\n#if !defined(_Post_equal_to_)\n#define _Post_equal_to_(x)\n#endif\n\n#pragma push_macro(\"_Out_opt_\")\n#if !defined(_Out_opt_)\n#define _Out_opt_\n#endif\n\n#pragma push_macro(\"Verify\")\n#undef Verify\n\n#pragma push_macro(\"SEALED\")\n#undef SEALED\n\n#if _MSC_VER >= 1800\n# define SEALED final\n#elif _MSC_VER >= 1400\n# define SEALED sealed\n#elif defined(_MSC_VER)\n# define SEALED\n#else\n# define SEALED final\n#endif\n\n// Disable verify exception usage if exceptions are disabled for this project\n#ifndef _CPPUNWIND\n    #ifndef NO_VERIFY_EXCEPTIONS\n        #define NO_VERIFY_EXCEPTIONS\n    #endif\n#endif\n\n#ifdef _CPPUNWIND\n    #include \"WexException.h\"\n    #if defined(_STL100_) || defined(_STL110_)\n        #pragma push_macro(\"HUGE\")\n        #undef HUGE\n        #include <string>\n        #pragma pop_macro(\"HUGE\")\n    #endif // _STL100_\n\n    #include <exception>\n#endif //_CPPUNWIND is defined\n\n/// <summary>\n/// \\def VERIFY_ARE_EQUAL(__expected, __actual, ...)\n/// Verifies that two specified objects are equal.\n/// </summary>\n# define VERIFY_ARE_EQUAL(__expected, __actual, ...) (bool)WEX::TestExecution::Private::MacroVerify::AreEqual((__expected), (__actual), (L#__expected), (L#__actual), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that two specified objects are not equal.\n# define VERIFY_ARE_NOT_EQUAL(__expected, __actual, ...) (bool)WEX::TestExecution::Private::MacroVerify::AreNotEqual((__expected), (__actual), (L#__expected) , (L#__actual), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the first parameter is greater than the second parameter.\n# define VERIFY_IS_GREATER_THAN(__expectedGreater, __expectedLess, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsGreaterThan((__expectedGreater), (__expectedLess), (L#__expectedGreater) , (L#__expectedLess), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the first parameter is greater than or equal to the second parameter.\n# define VERIFY_IS_GREATER_THAN_OR_EQUAL(__expectedGreater, __expectedLess, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsGreaterThanOrEqual((__expectedGreater), (__expectedLess), (L#__expectedGreater) , (L#__expectedLess), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the first parameter is less than the second parameter.\n# define VERIFY_IS_LESS_THAN(__expectedLess, __expectedGreater, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsLessThan((__expectedLess), (__expectedGreater), (L#__expectedLess) , (L#__expectedGreater), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the first parameter is less than or equal to the second parameter.\n# define VERIFY_IS_LESS_THAN_OR_EQUAL(__expectedLess, __expectedGreater, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsLessThanOrEqual((__expectedLess), (__expectedGreater), (L#__expectedLess) , (L#__expectedGreater), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the two parameters specified refer to the same object.\n# define VERIFY_ARE_SAME(__expected, __actual, ...) (bool)WEX::TestExecution::Private::MacroVerify::AreSame((__expected), (__actual), (L#__expected), (L#__actual), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the two parameters specified do not refer to the same object.\n# define VERIFY_ARE_NOT_SAME(__expected, __actual, ...) (bool)WEX::TestExecution::Private::MacroVerify::AreNotSame((__expected), (__actual), (L#__expected), (L#__actual), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Fails without checking any conditions.\n# define VERIFY_FAIL(...) (bool)WEX::TestExecution::Private::MacroVerify::Fail(PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified condition is true.\n# define VERIFY_IS_TRUE(__condition, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsTrue((__condition), (L#__condition), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified condition is false.\n# define VERIFY_IS_FALSE(__condition, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsFalse((__condition), (L#__condition), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified parameter is null.\n# define VERIFY_IS_NULL(__object, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsNull((__object), (L#__object), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified parameter is not null.\n# define VERIFY_IS_NOT_NULL(__object, ...) (bool)WEX::TestExecution::Private::MacroVerify::IsNotNull((__object), (L#__object), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified HRESULT is successful.\n# define VERIFY_SUCCEEDED(__hresult, ...) (bool)WEX::TestExecution::Private::MacroVerify::Succeeded((__hresult), (L#__hresult), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified HRESULT is successful, and returns the HRESULT that was passed in.\n# define VERIFY_SUCCEEDED_RETURN(__hresult, ...) (HRESULT)WEX::TestExecution::Private::MacroVerify::SucceededReturn((__hresult), (L#__hresult), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified HRESULT is not successful.\n# define VERIFY_FAILED(__hresult, ...) (bool)WEX::TestExecution::Private::MacroVerify::Failed((__hresult), (L#__hresult), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified HRESULT is not successful, and returns the HRESULT that was passed in.\n# define VERIFY_FAILED_RETURN(__hresult, ...) (HRESULT)WEX::TestExecution::Private::MacroVerify::FailedReturn((__hresult), (L#__hresult), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 result succeeded.\n# define VERIFY_WIN32_SUCCEEDED(__win32Result, ...) (bool)WEX::TestExecution::Private::MacroVerify::Win32Succeeded((__win32Result), (L#__win32Result), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 result succeeded, and returns the Win32 value that was passed in.\n# define VERIFY_WIN32_SUCCEEDED_RETURN(__win32Result, ...) (::LONG)WEX::TestExecution::Private::MacroVerify::Win32SucceededReturn((__win32Result), (L#__win32Result), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 result failed.\n# define VERIFY_WIN32_FAILED(__win32Result, ...) (bool)WEX::TestExecution::Private::MacroVerify::Win32Failed((__win32Result), (L#__win32Result), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 result failed, and returns the Win32 value that was passed in.\n# define VERIFY_WIN32_FAILED_RETURN(__win32Result, ...) (::LONG)WEX::TestExecution::Private::MacroVerify::Win32FailedReturn((__win32Result), (L#__win32Result), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 BOOL succeeded and logs the error code returned from GetLastError if not.\n# define VERIFY_WIN32_BOOL_SUCCEEDED(__win32Bool, ...) (bool)WEX::TestExecution::Private::MacroVerify::Win32BoolSucceeded((__win32Bool), (L#__win32Bool), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 BOOL succeeded and logs the error code returned from GetLastError if not; returns the Win32 BOOL that was passed in.\n# define VERIFY_WIN32_BOOL_SUCCEEDED_RETURN(__win32Bool, ...) (::BOOL)WEX::TestExecution::Private::MacroVerify::Win32BoolSucceededReturn((__win32Bool), (L#__win32Bool), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 BOOL failed.\n# define VERIFY_WIN32_BOOL_FAILED(__win32Bool, ...) (bool)WEX::TestExecution::Private::MacroVerify::Win32BoolFailed((__win32Bool), (L#__win32Bool), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Verifies that the specified Win32 BOOL failed and returns the Win32 BOOL that was passed in.\n# define VERIFY_WIN32_BOOL_FAILED_RETURN(__win32Bool, ...) (::BOOL)WEX::TestExecution::Private::MacroVerify::Win32BoolFailedReturn((__win32Bool), (L#__win32Bool), PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__)\n\n// Only enable these two if exceptions are enabled for the project\n# ifdef _CPPUNWIND\n\n// Verifies that the specified operation throws an exception of the specified type that meets the functor criteria\n// The temporary __cond variable is necessary to workaround a bug in nested lambdas used in conditionals\n#   define VERIFY_THROWS_SPECIFIC(__operation, __exception, __func, ...)                                                                             \\\n{                                                                                                                                                    \\\n    bool __exceptionHit = false;                                                                                                                     \\\n    try                                                                                                                                              \\\n    {                                                                                                                                                \\\n        __operation;                                                                                                                                 \\\n    }                                                                                                                                                \\\n    catch(__exception& __e)                                                                                                                          \\\n    {                                                                                                                                                \\\n        bool __cond = __func(__e);                                                                                                                   \\\n        if (__cond)                                                                                                                                  \\\n        {                                                                                                                                            \\\n            WEX::TestExecution::Private::MacroVerify::ExpectedExceptionThrown(__e, L#__exception, L#__operation, __VA_ARGS__);                       \\\n            __exceptionHit = true;                                                                                                                   \\\n        }                                                                                                                                            \\\n        else                                                                                                                                         \\\n        {                                                                                                                                            \\\n            throw;                                                                                                                                   \\\n        }                                                                                                                                            \\\n    }                                                                                                                                                \\\n                                                                                                                                                     \\\n    if (!__exceptionHit)                                                                                                                             \\\n    {                                                                                                                                                \\\n        WEX::TestExecution::Private::MacroVerify::ExpectedExceptionNotThrown(L#__exception, L#__operation, PRIVATE_VERIFY_ERROR_INFO, __VA_ARGS__);  \\\n    }                                                                                                                                                \\\n} \n\n// Verifies that the specified operation throws the specified exception.\n#  define VERIFY_THROWS(__operation, __exception, ...)                                                                                               \\\n    VERIFY_THROWS_SPECIFIC(__operation, __exception, WEX::TestExecution::Private::TrueUnaryFunctor<__exception&>(), __VA_ARGS__)\n\n// Verifies that the specified operation does not throw an exception.\n#  define VERIFY_NO_THROW(__operation, ...)                                                                                          \\\n{                                                                                                                                    \\\n    bool __exceptionHit = false;                                                                                                     \\\n    try                                                                                                                              \\\n    {                                                                                                                                \\\n        __operation;                                                                                                                 \\\n    }                                                                                                                                \\\n    catch(...)                                                                                                                       \\\n    {                                                                                                                                \\\n        WEX::Common::NoThrowString __messageBuffer;                                                                                  \\\n        const wchar_t* __pszMessage = WEX::TestExecution::Private::GetExceptionInfo(__messageBuffer);                                \\\n        WEX::TestExecution::Private::MacroVerify::UnexpectedExceptionThrownWithSpecifics(L#__operation, PRIVATE_VERIFY_ERROR_INFO, __pszMessage, __VA_ARGS__);  \\\n        __exceptionHit = true;                                                                                                       \\\n    }                                                                                                                                \\\n                                                                                                                                     \\\n    if (!__exceptionHit)                                                                                                             \\\n    {                                                                                                                                \\\n        WEX::TestExecution::Private::MacroVerify::UnexpectedExceptionNotThrown(L#__operation, __VA_ARGS__);                          \\\n    }                                                                                                                                \\\n}                                                                                                                    \n\n# endif //_CPPUNWIND is defined\n\n// Macro for creating an ErrorInfo object with file, function and line information\n#define PRIVATE_VERIFY_ERROR_INFO WEX::TestExecution::ErrorInfo(__WFILE__, __WFUNCTION__, __LINE__)\n\n// These definitions allow you to customize formatting for common types\n#ifndef LONG_VERIFY_FORMATTING\n    #define LONG_VERIFY_FORMATTING L\"0x%x\"  // Default to formatting for HRESULTS\n#endif\n\n#ifndef INT_VERIFY_FORMATTING\n    #define INT_VERIFY_FORMATTING L\"%d\"\n#endif\n\n#ifndef CHAR_VERIFY_FORMATTING\n    #define CHAR_VERIFY_FORMATTING L\"%c\"\n#endif\n\n#ifndef SHORT_VERIFY_FORMATTING\n    #define SHORT_VERIFY_FORMATTING INT_VERIFY_FORMATTING\n#endif\n\n#ifndef FLOAT_VERIFY_FORMATTING\n    #define FLOAT_VERIFY_FORMATTING L\"%fl\"\n#endif\n\n#ifndef SIZE_T_VERIFY_FORMATTING\n    #define SIZE_T_VERIFY_FORMATTING L\"%d\"\n#endif\n\n#ifndef DOUBLE_VERIFY_FORMATTING\n    #define DOUBLE_VERIFY_FORMATTING FLOAT_VERIFY_FORMATTING\n#endif\n\n#ifndef UNSIGNED_LONG_VERIFY_FORMATTING\n    #define UNSIGNED_LONG_VERIFY_FORMATTING L\"%u\"\n#endif\n\n#ifndef UNSIGNED_INT_VERIFY_FORMATTING\n    #define UNSIGNED_INT_VERIFY_FORMATTING L\"%u\"\n#endif\n\n#ifndef UNSIGNED_CHAR_VERIFY_FORMATTING\n    #define UNSIGNED_CHAR_VERIFY_FORMATTING UNSIGNED_INT_VERIFY_FORMATTING\n#endif\n\n#ifndef UNSIGNED_SHORT_VERIFY_FORMATTING\n    #define UNSIGNED_SHORT_VERIFY_FORMATTING UNSIGNED_INT_VERIFY_FORMATTING\n#endif\n\n#ifndef INT_64_VERIFY_FORMATTING\n    #define INT_64_VERIFY_FORMATTING L\"%I64d\"\n#endif\n\n#ifndef UNSIGNED_INT_64_VERIFY_FORMATTING\n    #define UNSIGNED_INT_64_VERIFY_FORMATTING L\"%I64u\"\n#endif\n\n#ifndef POINTER_VERIFY_FORMATTING\n    #define POINTER_VERIFY_FORMATTING L\"0x%p\"  \n#endif\n\nnamespace WEX { namespace TestExecution\n{\n    template <typename T, bool IsEnum>\n    class DefaultOutputTraits;\n\n    template <typename T>\n    class DefaultOutputTraits<T, true>\n    {\n    public:\n        static WEX::Common::NoThrowString ToString(const T& t)\n        {\n            // Return value as an unsigned long for enums\n            return VerifyOutputTraits<unsigned long>::ToString(static_cast<unsigned long>(t));\n        }\n    };\n\n    template <typename T>\n    class DefaultOutputTraits<T, false>\n    {\n    public:\n        static WEX::Common::NoThrowString ToString(const T&)\n        {\n            // Just return an empty string by default\n            return WEX::Common::NoThrowString();\n        }\n    };\n\n    // Users can implement custom VerifyOutputTraits for their classes to provide log output\n    template <typename T>\n    class VerifyOutputTraits\n    {\n    public:\n        // Default implementation\n        static WEX::Common::NoThrowString ToString(const T& t)\n        {\n            return DefaultOutputTraits<T, __is_enum(T)>::ToString(t);\n        }\n    };\n\n    template <typename T>\n    class VerifyOutputTraits<T&>\n    {\n    public:\n        static WEX::Common::NoThrowString ToString(const T& ref)\n        {\n            // Default implementation call through to non reference type\n            return VerifyOutputTraits<T>::ToString(ref);\n        }\n    };\n\n    template <typename T>\n    class VerifyOutputTraits<T*>\n    {\n    public:\n        static WEX::Common::NoThrowString ToString(T* const& p)\n        {\n            return WEX::Common::NoThrowString().Format(POINTER_VERIFY_FORMATTING, p);\n        }\n    };\n\n#define BUILD_OUTPUT_TRAIT(Type, FormatString) \\\n    template<> \\\n    class VerifyOutputTraits<Type> \\\n    { \\\n    public: \\\n        static WEX::Common::NoThrowString ToString(Type const& val) \\\n        { \\\n            return WEX::Common::NoThrowString().Format(FormatString, val); \\\n        } \\\n    };                                                                                                  \n\n    BUILD_OUTPUT_TRAIT(long, LONG_VERIFY_FORMATTING); \n    BUILD_OUTPUT_TRAIT(int, INT_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(char, CHAR_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(short, SHORT_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(float, FLOAT_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(double, DOUBLE_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(unsigned long, UNSIGNED_LONG_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(unsigned int, UNSIGNED_INT_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(unsigned char, UNSIGNED_CHAR_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(unsigned short, UNSIGNED_SHORT_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(__int64, INT_64_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(unsigned __int64, UNSIGNED_INT_64_VERIFY_FORMATTING);\n    BUILD_OUTPUT_TRAIT(bool, UNSIGNED_CHAR_VERIFY_FORMATTING);\n\n    #undef BUILD_OUTPUT_TRAIT\n\n#ifdef _CPPUNWIND\n    #if defined (_STL100_) || defined(_STL110_)\n    // Custom class to output the value of std::wstring\n    template<>\n    class VerifyOutputTraits<std::wstring>\n    {     \n    public:\n        static WEX::Common::NoThrowString ToString(std::wstring const& string)\n        {\n            return WEX::Common::NoThrowString(string.c_str());\n        }\n    };\n\n    // Custom class to output the value of std::string\n    template<>\n    class VerifyOutputTraits<std::string>\n    {     \n    public:\n        static WEX::Common::NoThrowString ToString(std::string const& string)\n        {\n            return WEX::Common::NoThrowString(string.c_str());\n        }\n    };\n    #endif // _STL100_\n#endif // _CPPUNWIND\n\n    // Custom class to output the value of WEX::Common::String\n    template<>\n    class VerifyOutputTraits<WEX::Common::String>\n    {     \n    public:\n        static WEX::Common::NoThrowString ToString(WEX::Common::String const& string)\n        {\n            return WEX::Common::NoThrowString(string);\n        }\n    };\n\n    // Custom class to output the value of WEX::Common::NoThrowString\n    template<>\n    class VerifyOutputTraits<WEX::Common::NoThrowString>\n    {     \n    public:\n        static WEX::Common::NoThrowString ToString(WEX::Common::NoThrowString const& string)\n        {\n            return string;\n        }\n    };\n\n    struct ErrorInfo\n    {\n        ErrorInfo(const wchar_t* pszFileName, const wchar_t* pszFunctionName, int lineNumber)\n        : pszFile(pszFileName)\n        , pszFunction(pszFunctionName)\n        , line(lineNumber)\n        {\n        }\n\n        ErrorInfo::ErrorInfo(const ErrorInfo& other) \n        : pszFile(other.pszFile)\n        , pszFunction(other.pszFunction)\n        , line(other.line)\n        {\n        }\n\n        const wchar_t* pszFile;\n        const wchar_t* pszFunction;\n        int line;\n    };\n\n    // Users can implement custom VerifyCompareTraits for their classes to perform more detailed comparisons\n    template <typename T1, typename T2 = T1>\n    class VerifyCompareTraits\n    {\n    public:\n        static bool AreEqual(const T1& expected, const T2& actual)\n        {\n            return ((expected == actual) != 0);  // != 0 to handle overloads of operator== that return BOOL instead of bool\n        }\n\n        static bool AreSame(const T1& expected, const T2& actual)\n        {\n            return reinterpret_cast<const void*>(&expected) == reinterpret_cast<const void*>(&actual);\n        }\n\n        static bool IsLessThan(const T1& expectedLess, const T2& expectedGreater)\n        {\n            return (expectedLess < expectedGreater);\n        }\n\n        static bool IsGreaterThan(const T1& expectedGreater, const T2& expectedLess)\n        {\n            return (expectedGreater > expectedLess);\n        }\n\n        static bool IsNull(const T1& object)\n        {\n            // works with various kinds of bool checkable types (smart pointers, etc)\n            return object ? false : true;\n        }\n    };\n\n    template <typename T1, typename T2>\n    class VerifyCompareTraits<T1*, T2*>\n    {\n    public:\n        static bool AreEqual(T1* const& expected, T2* const& actual)\n        {\n            return (reinterpret_cast<const void*>(expected) == reinterpret_cast<const void*>(actual));\n        }\n\n        static bool AreSame(T1* const& expected, T2* const& actual)\n        {\n            return (&reinterpret_cast<const void* const&>(expected) == &reinterpret_cast<const void* const&>(actual));\n        }\n\n        static bool IsLessThan(T1* const& expectedLess, T2* const& expectedGreater)\n        {\n            return (reinterpret_cast<const void*>(expectedLess) < reinterpret_cast<const void*>(expectedGreater));\n        }\n\n        static bool IsGreaterThan(T1* const& expectedGreater, T2* const& expectedLess)\n        {\n            return (reinterpret_cast<const void*>(expectedGreater) > reinterpret_cast<const void*>(expectedLess));\n        }\n\n        static bool IsNull(T1* const& object)\n        {\n            return object == NULL;\n        }\n    };\n\n    class ComVerify;\n    class Verify;\n    namespace Private { class MacroVerify; }\n\n    #ifdef _CPPUNWIND\n    #ifndef NO_VERIFY_EXCEPTIONS\n\n    // Thrown when a Verify method fails\n    class VerifyFailureException : public WEX::Common::Exception\n    {\n    friend class Verify; // Only allow Verify to construct these\n\n    private:\n        VerifyFailureException(HRESULT errorCode, const wchar_t* pszMessage) \n        : WEX::Common::Exception(errorCode, pszMessage)\n        {}\n\n        ~VerifyFailureException(){}\n\n        // Making 'operator new' private prevents heap allocation of Exception, and forces Exception instances\n        // to be thrown by value.\n        static void* operator new(size_t);\n\n        // Making 'operator delete' private for consistency with 'operator new'.\n        static void operator delete(void*){};\n    };\n\n    namespace Private\n    {\n        extern \"C\"\n        {\n            // One counter per thread across all modules.\n            WEXLOGGER_API int __stdcall GetDisabledVerifyThrowCount();\n            WEXLOGGER_API void __stdcall IncrementDisabledVerifyThrowCount();\n            WEXLOGGER_API void __stdcall DecrementDisabledVerifyThrowCount();\n        }\n    }\n\n    // Class used to disable VerifyFailureException throwing for its lifetime (on a per-thread basis)\n    class DisableVerifyExceptions SEALED\n    {\n    public:\n        DisableVerifyExceptions()\n        {\n            Private::IncrementDisabledVerifyThrowCount();\n        }\n\n        ~DisableVerifyExceptions()\n        {\n            Private::DecrementDisabledVerifyThrowCount();\n        }\n\n        int GetDisabledVerifyThrowCount()\n        {\n            return Private::GetDisabledVerifyThrowCount();\n        }\n\n    private:\n        // Making 'operator new' private prevents heap allocation\n        static void* operator new(size_t);\n\n        // Making 'operator delete' private for consistency with 'operator new'.\n        static void operator delete(void*){};\n\n        DisableVerifyExceptions(const DisableVerifyExceptions&); // non-implemented\n        DisableVerifyExceptions& operator=(const DisableVerifyExceptions&); // non-implemented    \n    };\n\n    #endif // NO_VERIFY_EXCEPTIONS is not defined\n    #endif //_CPPUNWIND is defined\n\n    namespace VerifyOutputSettings\n    {\n        enum Setting\n        {\n            None = 0,\n            LogOnlyFailures = 0x01,\n            LogFailuresAsBlocked = 0x02,\n            LogFailuresAsWarnings = 0x04,\n            LogValuesOnSuccess = 0x08\n        };\n    }\n\n    inline VerifyOutputSettings::Setting& operator|=(VerifyOutputSettings::Setting& lhs, const VerifyOutputSettings::Setting& rhs)\n    {\n        lhs = static_cast<VerifyOutputSettings::Setting>((static_cast<int>(lhs) | static_cast<int>(rhs)));\n        return lhs;\n    }\n\n    inline VerifyOutputSettings::Setting operator|(VerifyOutputSettings::Setting lhs, const VerifyOutputSettings::Setting& rhs)\n    {\n        return lhs |= rhs;\n    }\n\n    inline int operator&(VerifyOutputSettings::Setting lhs, const VerifyOutputSettings::Setting& rhs)\n    {\n        return (static_cast<int>(lhs) & static_cast<int>(rhs));\n    }\n\n    namespace Private\n    {\n        extern \"C\"\n        {\n            // One setting per thread across all modules.\n            WEXLOGGER_API VerifyOutputSettings::Setting __stdcall GetVerifyOutputSettings();\n            WEXLOGGER_API void __stdcall SetVerifyOutputSettings(VerifyOutputSettings::Setting settings);\n        }\n    }\n\n    // Class used to toggle verify logging settings (on a per-thread basis)\n    class SetVerifyOutput SEALED\n    {\n    public:\n        SetVerifyOutput(VerifyOutputSettings::Setting outputSettings)\n            : m_previousSetting(Private::GetVerifyOutputSettings())\n        {\n            Private::SetVerifyOutputSettings(outputSettings);\n        }\n\n        ~SetVerifyOutput()\n        {\n            Private::SetVerifyOutputSettings(m_previousSetting);\n        }\n\n    private:\n        VerifyOutputSettings::Setting m_previousSetting;\n\n        // Making 'operator new' private prevents heap allocation , and forces instances\n        // to be thrown by value.\n        static void* operator new(size_t);\n\n        // Making 'operator delete' private for consistency with 'operator new'.\n        static void operator delete(void*){};\n\n        SetVerifyOutput(const SetVerifyOutput&); // non-implemented\n        SetVerifyOutput& operator=(const SetVerifyOutput&); // non-implemented    \n    };\n\n    const wchar_t c_szVerifyContext[] = L\"Verify\";\n    const wchar_t c_szErrorGeneratingPassMessage[] = L\"Error generating pass message; possibly out of memory.\";\n    const wchar_t c_szErrorGeneratingFailureMessage[] = L\"Error generating failure message; possibly out of memory.\";\n\n    // Class used for test verification purposes\n    class Verify SEALED\n    {\n    friend class WEX::TestExecution::ComVerify;\n    friend class WEX::TestExecution::Private::MacroVerify;\n\n    public:\n\n        // Verifies that two specified objects are equal.\n        template <typename T1, typename T2>\n        static bool AreEqual(const T1& expected, const T2& actual, const ErrorInfo& errorInfo)\n        {\n            return AreEqual<T1, T2>(expected, actual, NULL, errorInfo);\n        }\n\n        // Verifies that two specified objects are equal.\n        template <typename T1, typename T2>\n        static bool AreEqual(const T1& expected, const T2& actual, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"AreEqual\", pszMessage);\n            return AreEqualImpl<T1, T2>(expected, actual, errorInfo, buildMessage);\n        }\n\n        // Verifies that two specified objects are not equal.\n        template <typename T1, typename T2>\n        static bool AreNotEqual(const T1& expected, const T2& actual, const ErrorInfo& errorInfo)\n        {\n            return AreNotEqual<T1, T2>(expected, actual, NULL, errorInfo);\n        }\n\n        // Verifies that two specified objects are not equal.\n        template <typename T1, typename T2>\n        static bool AreNotEqual(const T1& expected, const T2& actual, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"AreNotEqual\", pszMessage);\n            return AreNotEqualImpl<T1, T2>(expected, actual, errorInfo, buildMessage);\n        }\n\n        // Verifies that the first parameter is less than the second parameter.\n        template <typename T1, typename T2>\n        static bool IsLessThan(const T1& expectedLess, const T2& expectedGreater, const ErrorInfo& errorInfo)\n        {\n            return IsLessThan<T1, T2>(expectedLess, expectedGreater, NULL, errorInfo);\n        }\n\n        // Verifies that the first parameter is less than the second parameter.\n        template <typename T1, typename T2>\n        static bool IsLessThan(const T1& expectedLess, const T2& expectedGreater, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsLessThan\", pszMessage);\n            return IsLessThanImpl<T1, T2>(expectedLess, expectedGreater, errorInfo, buildMessage);\n        }\n\n        // Verifies that the first parameter is less than or equal to the second parameter.\n        template <typename T1, typename T2>\n        static bool IsLessThanOrEqual(const T1& expectedLess, const T2& expectedGreater, const ErrorInfo& errorInfo)\n        {\n            return IsLessThanOrEqual<T1, T2>(expectedLess, expectedGreater, NULL, errorInfo);\n        }\n\n        // Verifies that the first parameter is less than or equal to the second parameter.\n        template <typename T1, typename T2>\n        static bool IsLessThanOrEqual(const T1& expectedLess, const T2& expectedGreater, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsLessThanOrEqual\", pszMessage);\n            return IsLessThanOrEqualImpl<T1, T2>(expectedLess, expectedGreater, errorInfo, buildMessage);\n        }\n\n        // Verifies that the first parameter is greater than the second parameter.\n        template <typename T1, typename T2>\n        static bool IsGreaterThan(const T1& expectedGreater, const T2& expectedLess, const ErrorInfo& errorInfo)\n        {\n            return IsGreaterThan<T1, T2>(expectedGreater, expectedLess, NULL, errorInfo);\n        }\n\n        // Verifies that the first parameter is greater than the second parameter.\n        template <typename T1, typename T2>\n        static bool IsGreaterThan(const T1& expectedGreater, const T2& expectedLess, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsGreaterThan\", pszMessage);\n            return IsGreaterThanImpl<T1, T2>(expectedGreater, expectedLess, errorInfo, buildMessage);\n        }\n\n        // Verifies that the first parameter is greater than or equal to the second parameter.\n        template <typename T1, typename T2>\n        static bool IsGreaterThanOrEqual(const T1& expectedGreater, const T2& expectedLess, const ErrorInfo& errorInfo)\n        {\n            return IsGreaterThanOrEqual<T1, T2>(expectedGreater, expectedLess, NULL, errorInfo);\n        }\n\n        // Verifies that the first parameter is greater than or equal to the second parameter.\n        template <typename T1, typename T2>\n        static bool IsGreaterThanOrEqual(const T1& expectedGreater, const T2& expectedLess, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsGreaterThanOrEqual\", pszMessage);\n            return IsGreaterThanOrEqualImpl<T1, T2>(expectedGreater, expectedLess, errorInfo, buildMessage);\n        }\n\n    private:\n        // Returns the address of T\n        template <typename T>\n        class GetAddressOf\n        {\n        public:\n            static const T* Value(const T& ref)\n            {\n                return &ref;\n            }\n            typedef const T* Type;\n        };\n\n        // Returns the address of T\n        template <typename T>\n        class GetAddressOf<T&>\n        {\n        public:\n            static const T* Value(const T& ref)\n            {\n                return &ref;\n            }\n            typedef const T* Type; \n        };\n\n        // Returns the address T* (a pointer-to-pointer) as void*\n        template <typename T>\n        class GetAddressOf<T*>\n        {\n        public:\n            static const void* Value(T* const& p)\n            {\n                return &p;\n            }\n            typedef const void* Type;\n        };\n\n    public:\n        // Verifies that the two parameters specified refer to the same object.\n        template <typename T1, typename T2>\n        static bool AreSame(const T1& expected, const T2& actual, const ErrorInfo& errorInfo)\n        {\n            return AreSame<T1, T2>(expected, actual, NULL, errorInfo);\n        }\n\n        // Verifies that the two parameters specified refer to the same object.\n        template <typename T1, typename T2>\n        static bool AreSame(const T1& expected, const T2& actual, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"AreSame\", pszMessage);\n            return AreSameImpl<T1, T2>(expected, actual, errorInfo, buildMessage);\n        }\n\n        // Verifies that the two parameters specified do not refer to the same object.\n        template <typename T1, typename T2>\n        static bool AreNotSame(const T1& expected, const T2& actual, const ErrorInfo& errorInfo)\n        {\n            return AreNotSame<T1, T2>(expected, actual, NULL, errorInfo);\n        }\n\n        // Verifies that the two parameters specified do not refer to the same object.\n        template <typename T1, typename T2>\n        static bool AreNotSame(const T1& expected, const T2& actual, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"AreNotSame\", pszMessage);\n            return AreNotSameImpl<T1, T2>(expected, actual, errorInfo, buildMessage);\n        }\n\n        // Fails without checking any conditions.\n        _Post_equal_to_(false)\n        static bool Fail(const ErrorInfo& errorInfo)\n        {\n            return Fail(NULL, errorInfo);\n        }\n\n        // Fails without checking any conditions.\n        _Post_equal_to_(false)\n        static bool Fail(const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            if (WEX::Common::NoThrowString::IsNullOrEmpty(pszMessage))\n            {\n                return VerificationFailed(L\"Fail\", errorInfo);\n            }\n\n            return VerificationFailed(pszMessage, errorInfo);\n        }\n\n        // Verifies that the specified condition is true.\n        _Post_equal_to_(condition)\n        static bool IsTrue(bool condition, const ErrorInfo& errorInfo)\n        {\n            return IsTrue(condition, NULL, errorInfo);\n        }\n\n        // Verifies that the specified condition is true.\n        _Post_equal_to_(condition)\n        static bool IsTrue(bool condition, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsTrue\", pszMessage);\n            return IsTrueImpl(condition, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified condition is false.\n        _Post_equal_to_(!condition)\n        static bool IsFalse(bool condition, const ErrorInfo& errorInfo)\n        {\n            return IsFalse(condition, NULL, errorInfo);\n        }\n\n        // Verifies that the specified condition is false.\n        _Post_equal_to_(!condition)\n        static bool IsFalse(bool condition, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsFalse\", pszMessage);\n            return IsFalseImpl(condition, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified parameter is null.\n        template <typename T>\n        static bool IsNull(const T& object, const ErrorInfo& errorInfo)\n        {\n            return IsNull(object, NULL, errorInfo);\n        }\n\n        // Verifies that the specified parameter is null.\n        template <typename T>\n        static bool IsNull(const T& object, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsNull\", pszMessage);\n            return IsNullImpl(object, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified parameter is not null.\n        template <typename T>\n        static bool IsNotNull(const T& object, const ErrorInfo& errorInfo)\n        {\n            return IsNotNull(object, NULL, errorInfo);\n        }\n\n        // Verifies that the specified parameter is not null.\n        template <typename T>\n        static bool IsNotNull(const T& object, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"IsNotNull\", pszMessage);\n            return IsNotNullImpl(object, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified HRESULT is successful.\n        _Post_equal_to_(SUCCEEDED(hr))\n        static bool Succeeded(HRESULT hr, const ErrorInfo& errorInfo)\n        {\n            return Succeeded(hr, NULL, errorInfo);\n        }\n\n        // Verifies that the specified HRESULT is successful.\n        _Post_equal_to_(SUCCEEDED(hr))\n        static bool Succeeded(HRESULT hr, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"Succeeded\", pszMessage);\n            return SucceededImpl(hr, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified HRESULT is not successful.\n        _Post_equal_to_(FAILED(hr))\n        static bool Failed(HRESULT hr, const ErrorInfo& errorInfo)\n        {\n            return Failed(hr, NULL, errorInfo);\n        }\n\n        // Verifies that the specified HRESULT is not successful.\n        _Post_equal_to_(FAILED(hr))\n        static bool Failed(HRESULT hr, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"Failed\", pszMessage);\n            return FailedImpl(hr, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified Win32 error code is successful.\n        _Post_equal_to_(win32ErrorCode == 0)\n        static bool Win32Succeeded(::LONG win32ErrorCode, const ErrorInfo& errorInfo)\n        {\n            return Win32Succeeded(win32ErrorCode, NULL, errorInfo);\n        }\n\n        // Verifies that the specified Win32 error code is successful.\n        _Post_equal_to_(win32ErrorCode == 0)\n        static bool Win32Succeeded(::LONG win32ErrorCode, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"Win32Succeeded\", pszMessage);\n            return Win32SucceededImpl(win32ErrorCode, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified Win32 error code is not successful.\n        _Post_equal_to_(win32ErrorCode != 0)\n        static bool Win32Failed(::LONG win32ErrorCode, const ErrorInfo& errorInfo)\n        {\n            return Win32Failed(win32ErrorCode, NULL, errorInfo);\n        }\n\n        // Verifies that the specified Win32 error code is not successful.\n        _Post_equal_to_(win32ErrorCode != 0)\n        static bool Win32Failed(::LONG win32ErrorCode, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"Win32Failed\", pszMessage);\n            return Win32FailedImpl(win32ErrorCode, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified Win32 BOOL succeeded, and logs the error code returned from GetLastError if not.\n        _Post_equal_to_(win32Bool != 0)\n        static bool Win32BoolSucceeded(::BOOL win32Bool, const ErrorInfo& errorInfo)\n        {\n            return Win32BoolSucceeded(win32Bool, NULL, errorInfo);\n        }\n\n        // Verifies that the specified Win32 BOOL succeeded, and logs the error code returned from GetLastError if not.\n        _Post_equal_to_(win32Bool != 0)\n        static bool Win32BoolSucceeded(::BOOL win32Bool, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"Win32BoolSucceeded\", pszMessage);\n            return Win32BoolSucceededImpl(win32Bool, errorInfo, buildMessage);\n        }\n\n        // Verifies that the specified Win32 error code is not successful.\n        _Post_equal_to_(win32Bool == 0)\n        static bool Win32BoolFailed(::BOOL win32Bool, const ErrorInfo& errorInfo)\n        {\n            return Win32BoolFailed(win32Bool, NULL, errorInfo);\n        }\n\n        // Verifies that the specified Win32 error code is not successful.\n        _Post_equal_to_(win32Bool == 0)\n        static bool Win32BoolFailed(::BOOL win32Bool, const wchar_t* pszMessage, const ErrorInfo& errorInfo)\n        {\n            VerifyMessageFunctor buildMessage(L\"Win32BoolFailed\", pszMessage);\n            return Win32BoolFailedImpl(win32Bool, errorInfo, buildMessage);\n        }\n\n    private:\n\n        template<typename T1, typename T2>\n        static WEX::Common::NoThrowString StringsToValueString(const T1& expected, const T2& actual, const WEX::Common::NoThrowString& message)\n        {\n            return WEX::Common::NoThrowString(message)\n                        .Append(L\" - Values (\")\n                        .Append(expected)\n                        .Append(L\", \")\n                        .Append(actual)\n                        .Append(L\")\");\n        }\n\n        template<typename T1, typename T2>\n        static WEX::Common::NoThrowString CreateValueString(const T1& expected, const T2& actual, const WEX::Common::NoThrowString& message)\n        {\n            WEX::Common::NoThrowString expectedOutput(VerifyOutputTraits<T1>::ToString(expected));\n\n            if (expectedOutput.IsEmpty())\n            {\n                return message;\n            }\n            \n            return StringsToValueString(expectedOutput, VerifyOutputTraits<T2>::ToString(actual), message);\n        }\n\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const WEX::Common::String& expected, const T& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(static_cast<const wchar_t*>(expected), actual, message);\n        }\n\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const T& expected, const WEX::Common::String& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected, static_cast<const wchar_t*>(actual), message);\n        }\n\n        static WEX::Common::NoThrowString CreateValueString(const WEX::Common::String& expected, const WEX::Common::String& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(static_cast<const wchar_t*>(expected), static_cast<const wchar_t*>(actual), message);\n        }\n        \n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const WEX::Common::NoThrowString& expected, const T& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected, actual, message);\n        }\n\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const T& expected, const WEX::Common::NoThrowString& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected, actual, message);\n        }\n\n        static WEX::Common::NoThrowString CreateValueString(const WEX::Common::NoThrowString& expected, const WEX::Common::NoThrowString& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected, actual, message);\n        }\n#ifdef _CPPUNWIND\n    #if defined (_STL100_) || defined(_STL110_)\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const std::wstring& expected, const T& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected.c_str(), actual, message);\n        }\n\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const T& expected, const std::wstring& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected, actual.c_str(), message);\n        }\n\n        static WEX::Common::NoThrowString CreateValueString(const std::wstring& expected, const std::wstring& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected.c_str(), actual.c_str(), message);\n        }\n        \n        //These next 3 overloads are slightly inefficient, as there is no NoThrowString::Append(const char*) \n        //so a temporary String is constructed implicitly and appended to the NoThrowString.\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const std::string& expected, const T& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected.c_str(), actual, message);\n        }\n\n        template<typename T>\n        static WEX::Common::NoThrowString CreateValueString(const T& expected, const std::string& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected, actual.c_str(), message);\n        }\n\n        static WEX::Common::NoThrowString CreateValueString(const std::string& expected, const std::string& actual, const WEX::Common::NoThrowString& message)\n        {\n            return StringsToValueString(expected.c_str(), actual.c_str(), message);\n        }\n    #endif // _STL100_\n#endif // _CPPUNWIND\n\n        template <typename T1, typename T2>\n        static bool VerificationFailed(const T1& expected, const T2& actual, const WEX::Common::NoThrowString& message, const ErrorInfo& errorInfo)\n        {\n            WEX::Common::PreserveLastError preserveLastError;\n            return FailImpl(CreateValueString(expected, actual, message), errorInfo, E_FAIL /*Work around the compiler issue on the woa build*/);\n        }\n\n        template <typename T>\n        static bool VerificationFailed(const T& expected, const WEX::Common::NoThrowString& message, const ErrorInfo& errorInfo)\n        {\n            WEX::Common::PreserveLastError preserveLastError;\n\n            // Default VerifyOutputTraits<T>::ToString returns an empty string\n            WEX::Common::NoThrowString expectedOutput(VerifyOutputTraits<T>::ToString(expected));\n            if (!expectedOutput.IsEmpty())\n            {\n                WEX::Common::NoThrowString valueMessage(message);\n                valueMessage.Append(L\" - Value (\");\n                valueMessage.Append(expectedOutput);\n                valueMessage.Append(L\")\");\n\n                return FailImpl(valueMessage, errorInfo, E_FAIL /*Work around the compiler issue on the woa build*/);\n            }\n\n            return FailImpl(message, errorInfo, E_FAIL /*Work around the compiler issue on the woa build*/);\n        }\n\n        _Post_equal_to_(false)\n        static bool VerificationFailed(const WEX::Common::NoThrowString& message, const ErrorInfo& errorInfo)\n        {\n            WEX::Common::PreserveLastError preserveLastError;\n            return FailImpl(message, errorInfo);\n        }\n\n        _Post_equal_to_(false)\n        static bool FailImpl(const WEX::Common::NoThrowString& message, const ErrorInfo& errorInfo, HRESULT hrToThrow = E_FAIL)\n        {\n            if (!message.IsEmpty())\n            {\n                VerifyOutputSettings::Setting outputSetting = Private::GetVerifyOutputSettings();\n\n                if (outputSetting & VerifyOutputSettings::LogFailuresAsBlocked)\n                {\n                    WEX::Logging::Log::Result(WEX::Logging::TestResults::Blocked, message.ToCStrWithFallbackTo(c_szErrorGeneratingFailureMessage), c_szVerifyContext);\n                }\n                else if (outputSetting & VerifyOutputSettings::LogFailuresAsWarnings)\n                {\n                    WEX::Logging::Log::Warning(message.ToCStrWithFallbackTo(c_szErrorGeneratingFailureMessage), c_szVerifyContext, errorInfo.pszFile, errorInfo.pszFunction, errorInfo.line);\n                }\n                else\n                {\n                    WEX::Logging::Log::Error(message.ToCStrWithFallbackTo(c_szErrorGeneratingFailureMessage), c_szVerifyContext, errorInfo.pszFile, errorInfo.pszFunction, errorInfo.line);\n                }\n            }\n\n            UNREFERENCED_PARAMETER(hrToThrow); // Unreferenced if exceptions are disabled\n            \n            #ifdef _CPPUNWIND\n            #ifndef NO_VERIFY_EXCEPTIONS\n\n            if (Private::GetDisabledVerifyThrowCount() == 0)\n            {\n                throw VerifyFailureException(hrToThrow, message);\n            }\n\n            #endif // NO_VERIFY_EXCEPTIONS is not defined\n            #endif //_CPPUNWIND is defined\n\n            return false;\n        }\n\n        static bool LogValuesOnSuccess()\n        {\n            #ifdef LOG_VALUES_ON_SUCCESS\n                return true;\n            #else\n                // If LOG_VALUES_ON_SUCCESS wasn't globally defined, look at the current VerifyOutputSettings\n                return ((Private::GetVerifyOutputSettings() & VerifyOutputSettings::LogValuesOnSuccess) != 0);\n            #endif\n        }\n\n        static bool LogOnlyFailures()\n        {\n            #ifdef LOG_ONLY_FAILURES\n                return true;\n            #else\n                // If LOG_ONLY_FAILURES wasn't globally defined, look at the current VerifyOutputSettings\n                return ((Private::GetVerifyOutputSettings() & VerifyOutputSettings::LogOnlyFailures) != 0);\n            #endif\n        }\n\n        template <typename T1, typename T2>\n        _Post_equal_to_(true)\n        static bool VerificationPassed(const T1& expected, const T2& actual, const WEX::Common::NoThrowString& message)\n        {\n            if (LogOnlyFailures())\n            {\n                return true;\n            }\n\n            WEX::Common::PreserveLastError preserveLastError;\n            if (LogValuesOnSuccess())\n            {\n                return PassImpl(CreateValueString(expected, actual, message));\n            }\n\n            UNREFERENCED_PARAMETER(actual);\n\n            return PassImpl(message);\n        }\n\n        template <typename T>\n        _Post_equal_to_(true)\n        static bool VerificationPassed(const T& expected, const WEX::Common::NoThrowString& message)\n        {\n            if (LogOnlyFailures())\n            {\n                return true;\n            }\n\n            WEX::Common::PreserveLastError preserveLastError;\n            if (LogValuesOnSuccess())\n            {\n                // Default VerifyOutputTraits<T>::ToString returns an empty string\n                WEX::Common::NoThrowString expectedOutput = VerifyOutputTraits<T>::ToString(expected);\n                if (!expectedOutput.IsEmpty())\n                {\n                    WEX::Common::NoThrowString valueMessage(message);\n                    valueMessage.Append(L\" - Value (\");\n                    valueMessage.Append(expectedOutput);\n                    valueMessage.Append(L\")\");\n\n                    return PassImpl(valueMessage);\n                }\n            }\n\n            return PassImpl(message);\n        }\n\n        _Post_equal_to_(true)\n        static bool VerificationPassed(const WEX::Common::NoThrowString& message)\n        {\n            if (LogOnlyFailures())\n            {\n                return true;\n            }\n\n            WEX::Common::PreserveLastError preserveLastError;\n            return PassImpl(message);\n        }\n\n        _Post_equal_to_(true)\n        static bool PassImpl(const WEX::Common::NoThrowString& message)\n        {\n            if (!message.IsEmpty())\n            {\n                WEX::Logging::Log::Comment(message.ToCStrWithFallbackTo(c_szErrorGeneratingPassMessage), c_szVerifyContext);\n            }\n\n            return true;\n        }\n\n        class VerifyMessageFunctor\n        {\n        public:\n            VerifyMessageFunctor(const wchar_t* pszDefaultMessage, const wchar_t* pszMessage)\n            : m_pszDefaultMessage(pszDefaultMessage)\n            , m_pszMessage(pszMessage)\n            {\n            }\n            \n            WEX::Common::NoThrowString operator()() const\n            {\n                if (WEX::Common::NoThrowString::IsNullOrEmpty(m_pszMessage))\n                {\n                    return WEX::Common::NoThrowString(m_pszDefaultMessage);\n                }\n\n                return WEX::Common::NoThrowString().Format(L\"%s: %s\", m_pszDefaultMessage, m_pszMessage);\n            }\n\n        private:\n            const wchar_t* m_pszDefaultMessage;\n            const wchar_t* m_pszMessage;\n        };\n        \n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool AreEqualImpl(const T1& expected, const T2& actual, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T1, T2>::AreEqual(expected, actual))\n            {\n                return VerificationFailed(expected, actual, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(expected, actual, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool AreNotEqualImpl(const T1& expected, const T2& actual, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (VerifyCompareTraits<T1, T2>::AreEqual(expected, actual))\n            {\n                return VerificationFailed(expected, actual, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(expected, actual, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool IsLessThanImpl(const T1& expectedLess, const T2& expectedGreater, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T1, T2>::IsLessThan(expectedLess, expectedGreater))\n            {\n                return VerificationFailed(expectedLess, expectedGreater, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(expectedLess, expectedGreater, buildMessage());\n            }\n\n            return true;\n        }\n        \n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool IsLessThanOrEqualImpl(const T1& expectedLess, const T2& expectedGreater, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T1, T2>::IsLessThan(expectedLess, expectedGreater) &&\n                !VerifyCompareTraits<T1, T2>::AreEqual(expectedLess, expectedGreater))\n            {\n                return VerificationFailed(expectedLess, expectedGreater, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(expectedLess, expectedGreater, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool IsGreaterThanImpl(const T1& expectedGreater, const T2& expectedLess, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T1, T2>::IsGreaterThan(expectedGreater, expectedLess))\n            {\n                return VerificationFailed(expectedGreater, expectedLess, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(expectedGreater, expectedLess, buildMessage());\n            }\n\n            return true;\n        }\n\n\n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool IsGreaterThanOrEqualImpl(const T1& expectedGreater, const T2& expectedLess, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T1, T2>::IsGreaterThan(expectedGreater, expectedLess) &&\n                !VerifyCompareTraits<T1, T2>::AreEqual(expectedGreater, expectedLess))\n            {\n                return VerificationFailed(expectedGreater, expectedLess, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(expectedGreater, expectedLess, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool AreSameImpl(const T1& expected, const T2& actual, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T1, T2>::AreSame(expected, actual))\n            {\n                return VerificationFailed<GetAddressOf<T1>::Type, GetAddressOf<T2>::Type>(GetAddressOf<T1>::Value(expected), GetAddressOf<T2>::Value(actual), buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed<GetAddressOf<T1>::Type, GetAddressOf<T2>::Type>(GetAddressOf<T1>::Value(expected), GetAddressOf<T2>::Value(actual), buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename T1, typename T2, typename TBuildMessage>\n        static bool AreNotSameImpl(const T1& expected, const T2& actual, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (VerifyCompareTraits<T1, T2>::AreSame(expected, actual))\n            {\n                return VerificationFailed<GetAddressOf<T1>::Type, GetAddressOf<T2>::Type>(GetAddressOf<T1>::Value(expected), GetAddressOf<T2>::Value(actual), buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed<GetAddressOf<T1>::Type, GetAddressOf<T2>::Type>(GetAddressOf<T1>::Value(expected), GetAddressOf<T2>::Value(actual), buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        static bool IsTrueImpl(bool condition, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!condition)\n            {\n                return VerificationFailed(buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        static bool IsFalseImpl(bool condition, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (condition)\n            {\n                return VerificationFailed(buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed(buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename T, typename TBuildMessage>\n        static bool IsNullImpl(const T& object, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (VerifyCompareTraits<T, T>::IsNull(object))\n            {\n                if (!LogOnlyFailures())\n                {\n                    return VerificationPassed(object, buildMessage());\n                }\n\n                return true;\n            }\n\n            return VerificationFailed(object, buildMessage(), errorInfo);\n        }\n\n        // Verifies that the specified parameter is not null.\n        template <typename T, typename TBuildMessage>\n        static bool IsNotNullImpl(const T& object, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!VerifyCompareTraits<T, T>::IsNull(object))\n            {\n                if (!LogOnlyFailures())\n                {\n                    return VerificationPassed(object, buildMessage());\n                }\n\n                return true;\n            }\n\n            return VerificationFailed(object, buildMessage(), errorInfo);\n        }\n\n        template <typename TBuildMessage>\n        _Post_equal_to_(SUCCEEDED(hr))\n        static bool SucceededImpl(HRESULT hr, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (FAILED(hr))\n            {\n                return VerificationFailed<HRESULT>(hr, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed<HRESULT>(hr, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        _Post_equal_to_(FAILED(hr))\n        static bool FailedImpl(HRESULT hr, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (!FAILED(hr))\n            {\n                return VerificationFailed<HRESULT>(hr, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed<HRESULT>(hr, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        _Post_equal_to_(win32ErrorCode == 0)\n        static bool Win32SucceededImpl(::LONG win32ErrorCode, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (win32ErrorCode != ERROR_SUCCESS)\n            {\n                return VerificationFailed< ::LONG>(win32ErrorCode, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed< ::LONG>(win32ErrorCode, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        _Post_equal_to_(win32ErrorCode != 0)\n        static bool Win32FailedImpl(::LONG win32ErrorCode, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (win32ErrorCode == ERROR_SUCCESS)\n            {\n                return VerificationFailed< ::LONG>(win32ErrorCode, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed< ::LONG>(win32ErrorCode, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        _Post_equal_to_(win32Bool != 0)\n        static bool Win32BoolSucceededImpl(::BOOL win32Bool, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (0 == win32Bool)\n            {\n                // Log the value returned from Debug::GetLastError()\n                return VerificationFailed< ::DWORD>(WEX::Common::Debug::GetLastError(), buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed< ::BOOL>(win32Bool, buildMessage());\n            }\n\n            return true;\n        }\n\n        template <typename TBuildMessage>\n        _Post_equal_to_(win32Bool == 0)\n        static bool Win32BoolFailedImpl(::BOOL win32Bool, const ErrorInfo& errorInfo, const TBuildMessage& buildMessage)\n        {\n            if (0 != win32Bool)\n            {\n                return VerificationFailed< ::BOOL>(win32Bool, buildMessage(), errorInfo);\n            }\n\n            if (!LogOnlyFailures())\n            {\n                return VerificationPassed< ::BOOL>(win32Bool, buildMessage());\n            }\n\n            return true;\n        }\n\n        Verify(){}; // Disallow construction of static class\n        ~Verify(){}; // Disallow construction of static class\n        Verify(const Verify&); // non-implemented\n        Verify& operator=(const Verify&); // non-implemented    \n    };\n\n    namespace Private\n    {\n        class MacroVerify SEALED\n        {\n        public:\n\n            template <typename T1, typename T2>\n            static bool AreEqual(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"AreEqual(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::AreEqualImpl<T1, T2>(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool AreNotEqual(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"AreNotEqual(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::AreNotEqualImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool IsLessThan(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsLessThan(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::IsLessThanImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool IsLessThanOrEqual(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsLessThanOrEqual(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::IsLessThanOrEqualImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool IsGreaterThan(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsGreaterThan(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::IsGreaterThanImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool IsGreaterThanOrEqual(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsGreaterThanOrEqual(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::IsGreaterThanOrEqualImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool AreSame(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"AreSame(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::AreSameImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            template <typename T1, typename T2>\n            static bool AreNotSame(const T1& expected, const T2& actual, const wchar_t* pszExpected, const wchar_t* pszActual, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"AreNotSame(%s, %s)\", pszExpected, pszActual, pszMessage);\n                return WEX::TestExecution::Verify::AreNotSameImpl(expected, actual, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(false)\n            static bool Fail(const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                return WEX::TestExecution::Verify::Fail(pszMessage, errorInfo);\n            }\n\n            _Post_equal_to_(condition)\n            static bool IsTrue(bool condition, const wchar_t* pszCondition, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsTrue(%s)\", pszCondition, pszMessage);\n                return WEX::TestExecution::Verify::IsTrueImpl(condition, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(!condition)\n            static bool IsFalse(bool condition, const wchar_t* pszCondition, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsFalse(%s)\", pszCondition, pszMessage);\n                return WEX::TestExecution::Verify::IsFalseImpl(condition, errorInfo, buildMessage);\n            }\n\n            template <typename T>\n            static bool IsNull(const T& object, const wchar_t* pszObject, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsNull(%s)\", pszObject, pszMessage);\n                return WEX::TestExecution::Verify::IsNullImpl(object, errorInfo, buildMessage);\n            }\n\n            template <typename T>\n            static bool IsNotNull(const T& object, const wchar_t* pszObject, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"IsNotNull(%s)\", pszObject, pszMessage);\n                return WEX::TestExecution::Verify::IsNotNullImpl(object, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(SUCCEEDED(hr))\n            static bool Succeeded(HRESULT hr, const wchar_t* pszHresult, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"SUCCEEDED(%s)\", pszHresult, pszMessage);\n                return WEX::TestExecution::Verify::SucceededImpl(hr, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(hr)\n            static HRESULT SucceededReturn(HRESULT hr, const wchar_t* pszHresult, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                Succeeded(hr, pszHresult, errorInfo, pszMessage);\n                return hr;\n            }\n\n            _Post_equal_to_(FAILED(hr))\n            static bool Failed(HRESULT hr, const wchar_t* pszHresult, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"FAILED(%s)\", pszHresult, pszMessage);\n                return WEX::TestExecution::Verify::FailedImpl(hr, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(hr)\n            static HRESULT FailedReturn(HRESULT hr, const wchar_t* pszHresult, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                Failed(hr, pszHresult, errorInfo, pszMessage);\n                return hr;\n            }\n\n            _Post_equal_to_(win32ErrorCode == 0)\n            static bool Win32Succeeded(::LONG win32ErrorCode, const wchar_t* pszWin32ErrorCode, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"Win32Succeeded(%s)\", pszWin32ErrorCode, pszMessage);\n                return WEX::TestExecution::Verify::Win32SucceededImpl(win32ErrorCode, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(win32ErrorCode)\n            static ::LONG Win32SucceededReturn(::LONG win32ErrorCode, const wchar_t* pszWin32ErrorCode, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                Win32Succeeded(win32ErrorCode, pszWin32ErrorCode, errorInfo, pszMessage);\n                return win32ErrorCode;\n            }\n\n            _Post_equal_to_(win32ErrorCode != 0)\n            static bool Win32Failed(::LONG win32ErrorCode, const wchar_t* pszWin32ErrorCode, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"Win32Failed(%s)\", pszWin32ErrorCode, pszMessage);\n                return WEX::TestExecution::Verify::Win32FailedImpl(win32ErrorCode, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(win32ErrorCode)\n            static ::LONG Win32FailedReturn(::LONG win32ErrorCode, const wchar_t* pszWin32ErrorCode, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                Win32Failed(win32ErrorCode, pszWin32ErrorCode, errorInfo, pszMessage);\n                return win32ErrorCode;\n            }\n\n            _Post_equal_to_(win32Bool != 0)\n            static bool Win32BoolSucceeded(::BOOL win32Bool, const wchar_t* pszWin32Bool, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"Win32BoolSucceeded(%s)\", pszWin32Bool, pszMessage);\n                return WEX::TestExecution::Verify::Win32BoolSucceededImpl(win32Bool, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(win32Bool)\n            static ::BOOL Win32BoolSucceededReturn(::BOOL win32Bool, const wchar_t* pszWin32Bool, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                Win32BoolSucceeded(win32Bool, pszWin32Bool, errorInfo, pszMessage);\n                return win32Bool;\n            }\n\n            _Post_equal_to_(win32Bool == 0)\n            static bool Win32BoolFailed(::BOOL win32Bool, const wchar_t* pszWin32Bool, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                MacroVerifyMessageFunctor buildMessage(L\"Win32BoolFailed(%s)\", pszWin32Bool, pszMessage);\n                return WEX::TestExecution::Verify::Win32BoolFailedImpl(win32Bool, errorInfo, buildMessage);\n            }\n\n            _Post_equal_to_(win32Bool)\n            static ::BOOL Win32BoolFailedReturn(::BOOL win32Bool, const wchar_t* pszWin32Bool, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                Win32BoolFailed(win32Bool, pszWin32Bool, errorInfo, pszMessage);\n                return win32Bool;\n            }\n\n            template <typename T>\n            _Post_equal_to_(true)\n            static bool ExpectedExceptionThrown(const T& TException, const wchar_t* pszException, const wchar_t* pszOperation, const wchar_t* pszMessage = NULL)\n            {\n                UNREFERENCED_PARAMETER(TException);\n\n                if (WEX::TestExecution::Verify::LogOnlyFailures())\n                {\n                    return WEX::TestExecution::Verify::VerificationPassed(WEX::Common::NoThrowString());\n                }\n\n                static const wchar_t c_szFormat[] = L\"Expected exception (%s) caught during (%s)\";\n                WEX::Common::NoThrowString message(BuildMessage(c_szFormat, pszException, pszOperation, pszMessage));\n                return WEX::TestExecution::Verify::VerificationPassed(message.ToCStrWithFallbackTo(c_szFormat));\n            }\n\n            _Post_equal_to_(false)\n            static bool ExpectedExceptionNotThrown(const wchar_t* pszException, const wchar_t* pszOperation, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                static const wchar_t c_szFormat[] = L\"Expected exception (%s) not caught during (%s)\";\n                WEX::Common::NoThrowString message(BuildMessage(c_szFormat, pszException, pszOperation, pszMessage));\n                return WEX::TestExecution::Verify::VerificationFailed(message.ToCStrWithFallbackTo(c_szFormat), errorInfo);\n            }\n\n            _Post_equal_to_(false)\n            static bool UnexpectedExceptionThrown(const wchar_t* pszOperation, const ErrorInfo& errorInfo, const wchar_t* pszMessage = NULL)\n            {\n                static const wchar_t c_szFormat[] = L\"Unexpected exception caught during (%s)\";\n                WEX::Common::NoThrowString message(BuildMessage(c_szFormat, pszOperation, pszMessage));\n                return WEX::TestExecution::Verify::VerificationFailed(message.ToCStrWithFallbackTo(c_szFormat), errorInfo);\n            }\n            \n            _Post_equal_to_(false)\n            static bool UnexpectedExceptionThrownWithSpecifics(const wchar_t* pszOperation, const ErrorInfo& errorInfo, const wchar_t* pszSpecificException, const wchar_t* pszMessage = NULL)\n            {\n                static const wchar_t c_szFallbackString[] = L\"Unexpected exception caught\";\n                static const wchar_t c_szFormat[] = L\"%s during (%s)\";\n                WEX::Common::NoThrowString message(BuildMessage(c_szFormat, pszSpecificException, pszOperation, pszMessage));\n                return WEX::TestExecution::Verify::VerificationFailed(message.ToCStrWithFallbackTo(c_szFallbackString), errorInfo);\n            }\n\n            _Post_equal_to_(true)\n            static bool UnexpectedExceptionNotThrown(const wchar_t* pszOperation, const wchar_t* pszMessage = NULL)\n            {\n                if (WEX::TestExecution::Verify::LogOnlyFailures())\n                {\n                    return WEX::TestExecution::Verify::VerificationPassed(WEX::Common::NoThrowString());\n                }\n                \n                static const wchar_t c_szFormat[] = L\"Exception not caught during (%s)\";\n                WEX::Common::NoThrowString message(BuildMessage(c_szFormat, pszOperation, pszMessage));\n                return WEX::TestExecution::Verify::VerificationPassed(message.ToCStrWithFallbackTo(c_szFormat));\n            }\n\n        private:\n            MacroVerify(){}; // Disallow construction of static class\n            ~MacroVerify(){}; // Disallow construction of static class\n            MacroVerify(const MacroVerify&); // non-implemented\n            MacroVerify& operator=(const MacroVerify&); // non-implemented  \n\n            class MacroVerifyMessageFunctor\n            {\n            public:\n                MacroVerifyMessageFunctor(const wchar_t* pszFormat, const wchar_t* psz1, const wchar_t* psz2, const wchar_t* pszMessage)\n                : m_pszFormat(pszFormat)\n                , m_psz1(psz1)\n                , m_psz2(psz2)\n                , m_pszMessage(pszMessage)\n                {\n                }\n\n                MacroVerifyMessageFunctor(const wchar_t* pszFormat, const wchar_t* psz1, const wchar_t* pszMessage)\n                : m_pszFormat(pszFormat)\n                , m_psz1(psz1)\n                , m_psz2(NULL)\n                , m_pszMessage(pszMessage)\n                {\n                }\n\n                WEX::Common::NoThrowString operator()() const\n                {\n                    if (m_psz2)\n                    {\n                        return BuildMessage(m_pszFormat, m_psz1, m_psz2, m_pszMessage);\n                    }\n\n                    return BuildMessage(m_pszFormat, m_psz1, m_pszMessage);\n                }\n\n            private:\n                const wchar_t* m_pszFormat;\n                const wchar_t* m_psz1;\n                const wchar_t* m_psz2;\n                const wchar_t* m_pszMessage;\n            };\n\n            static WEX::Common::NoThrowString BuildMessage(const wchar_t* pszFormat, const wchar_t* psz1, const wchar_t* psz2, const wchar_t* pszMessage)\n            {\n                WEX::Common::NoThrowString message;\n                message.Format(pszFormat, psz1, psz2);\n                if (!WEX::Common::String::IsNullOrEmpty(pszMessage))\n                {\n                    message.AppendFormat(L\": %s\", pszMessage);\n                }\n                return message;\n            }\n\n            static WEX::Common::NoThrowString BuildMessage(const wchar_t* pszFormat, const wchar_t* psz1, const wchar_t* pszMessage)\n            {\n                WEX::Common::NoThrowString message;\n                message.Format(pszFormat, psz1);\n                if (!WEX::Common::String::IsNullOrEmpty(pszMessage))\n                {\n                    message.AppendFormat(L\": %s\", pszMessage);\n                }\n                return message;\n            }\n        };\n\n        template<typename Parameter>\n        class TrueUnaryFunctor\n        {\n        public:\n            bool operator()(Parameter)\n            {\n                return true;\n            }\n        };\n\n#if defined(_CPPUNWIND)\n        inline const wchar_t* GetExceptionInfo(WEX::Common::NoThrowString& message, _Out_opt_ HRESULT * pHResult = nullptr)\n        {\n            try\n            {\n                throw;\n            }\n            catch (const std::exception& e)\n            {\n                if (pHResult)\n                {\n                    *pHResult = E_UNEXPECTED;\n                }\n\n                static const wchar_t c_szMessage[] = L\"Caught std::exception\";\n                message.Format(L\"%s: %S\", c_szMessage, e.what());\n                return message.ToCStrWithFallbackTo(c_szMessage);\n            }\n            catch (const WEX::Common::Exception& e)\n            {\n                if (pHResult)\n                {\n                    *pHResult = e.ErrorCode();\n                }\n\n                static const wchar_t c_szMessage[] = L\"Caught WEX::Common::Exception\";\n                message.Format(L\"%s: %s [HRESULT: 0x%x]\", c_szMessage, e.Message(), e.ErrorCode());\n                return message.ToCStrWithFallbackTo(c_szMessage);\n            }\n# if defined(__cplusplus_winrt)\n            catch (Platform::Exception^ e)\n            {\n                if (pHResult)\n                {\n                    *pHResult = e->HResult;\n                }\n\n                static const wchar_t c_szMessage[] = L\"Caught Platform::Exception^\";\n                message.Format(L\"%s: %s [HRESULT: 0x%x]\", c_szMessage, e->Message->Data(), e->HResult);\n                return message.ToCStrWithFallbackTo(c_szMessage);\n            }\n# endif // if defined(__cplusplus_winrt)\n            catch (...)\n            {\n                if (pHResult)\n                {\n                    *pHResult = E_UNEXPECTED;\n                }\n\n                static const wchar_t c_szMessage[] = L\"Caught an unidentified C++ exception\";\n                return c_szMessage;\n            }\n        }\n#endif // if defined(_CPPUNWIND)\n\n    } /* namespace Private */\n} /* namespace TestExecution */ } /* namespace WEX */\n\n#pragma pop_macro(\"SEALED\")\n#pragma pop_macro(\"Verify\")\n#pragma pop_macro(\"_Post_equal_to_\")\n#pragma pop_macro(\"_Out_opt_\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Wex.Common.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Common definitions for the Wex.Common.dll.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n\n#include <basetyps.h>\n\n#if defined(WEXCOMMON_EXPORTS)\n# define WEXCOMMON_API __declspec(dllexport)\n# define EXPIMP_TEMPLATE\n#elif defined(WEXCOMMON_UNIT_TESTING)\n# define WEXCOMMON_API\n# define EXPIMP_TEMPLATE\n#elif defined(WEXCOMMON_STATIC)\n# define WEXCOMMON_API\n# define EXPIMP_TEMPLATE\n#else\n# define WEXCOMMON_API __declspec(dllimport)\n# define EXPIMP_TEMPLATE extern\n#endif\n\n#if defined(UNIT_TESTING)\n# define UNIT_TEST_CLASS(__class) __if_exists(__class) { friend class __class; }\n#else\n# define UNIT_TEST_CLASS(__class)\n#endif"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/Wex.Logger.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary> </summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"WexTypes.h\"\n#include <basetyps.h>\n\n#ifdef WEXLOGGER_EXPORTS\n# define WEXLOGGER_API __declspec(dllexport)\n#else\n# ifdef WEXLOGGER_UNIT_TESTING\n#  define WEXLOGGER_API\n# else\n#  define WEXLOGGER_API __declspec(dllimport)\n# endif\n#endif\n\n#ifdef UNIT_TESTING\n# define UNIT_TEST_CLASS(__class) __if_exists(__class) { friend class __class; }\n#else\n# define UNIT_TEST_CLASS(__class)\n#endif"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WexAssert.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>WexCommon assert implementation.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Common.h\"\n#include \"WexDebug.h\"\n\n#ifndef WEX_ASSERT\n#ifdef NDEBUG\n\n#define WEX_ASSERT(___condition, ___message)\n\n#else\n\n#define WEX_ASSERT(___condition, ___message) WEX::Common::Debug::Assert(!!(___condition), (L#___condition), (___message), __WFILE__, __WFUNCTION__, __LINE__)\n\n#endif /* NDEBUG */\n#endif /* WEX_ASSERT */\n\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WexDebug.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Common classes and macros for debugging.</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Common.h\"\n#include \"WexTypes.h\"\n\n#pragma warning(push)\n#pragma warning(disable:4481)\n\n#pragma push_macro(\"Assert\")\n#undef Assert\n\n#pragma push_macro(\"Debug\")\n#undef Debug\n\n#pragma push_macro(\"SEALED\")\n#undef SEALED\n\n#if _MSC_VER >= 1800\n# define SEALED final\n#elif _MSC_VER >= 1400\n# define SEALED sealed\n#elif defined(_MSC_VER)\n# define SEALED\n#else\n# define SEALED final\n#endif\n\n/// \\internal\n/// <summary>\n/// Define __WFILE__ and __WFUNCTION__ macros; do not use __FILEW__ and __FUNCTIONW__ names since STL \n/// uses macros with the same names, but does not check if they exist before defining them\n/// </summary>\n#ifndef WIDEN2\n#define WIDEN2(x) L ## x\n#endif\n\n#ifndef WIDEN\n#define WIDEN(x) WIDEN2(x)\n#endif\n\n#ifndef __WFILE__\n#define __WFILE__ WIDEN(__FILE__)\n#endif\n\n#ifndef __WFUNCTION__\n#define __WFUNCTION__ WIDEN(__FUNCTION__)\n#endif\n\n#ifndef UNREFERENCED_PARAMETER\n#define UNREFERENCED_PARAMETER(P)          (P)\n#endif\n\n/// <summary>\n/// Provides 'compile time assert' functionality.\n/// </summary>\n/// <remarks>\n/// Use the COMPILE_TIME_CHECK macro with an compile-time-constant 'expr', and the build will break if the expression evaluates to false.\n/// </remarks>\n/// <param name=\"expr\">The compile-time-constant expression to check.</param>\n/// <param name=\"msg\">A message to output in the build error. Note; this must not contain spaces.</param>\n#define COMPILE_TIME_CHECK(expr, msg)                           \\\n{                                                               \\\n    __if_exists(WEX::Common::Private::CompileTimeCheck<(expr)>) \\\n    {                                                           \\\n        class Error : public ERROR_##msg {};                    \\\n    }                                                           \\\n}\n\n#if _MSC_VER >= 1600\n#define COMPILE_TIME_CHECK_V2(expr, msg, symbol) static_assert(expr, msg)\n#else\n#define COMPILE_TIME_CHECK_V2(expr, msg, symbol) COMPILE_TIME_CHECK(expr, symbol)\n#endif\n\nnamespace WEX { namespace Common\n{\n    /// \\internal\n    /// <summary>\n    /// The WEX::Common::Private namespace contains internal implementation details.\n    /// </summary>\n    namespace Private\n    {\n        /// \\internal\n        /// <summary>\n        /// A template class necessary for the COMPILE_TIME_CHECK macro.\n        /// Only the 'CompileTimeCheck&lt;false&gt;' specialization is provided; testing for the existance of a specialization\n        /// is then a mechanism for testing an expression at compile time.\n        ///\n        /// This class should not be used directly - use the COMPILE_TIME_CHECK macro instead.\n        /// </summary>\n        template<bool>\n        class CompileTimeCheck\n        {\n        };\n\n        /// \\internal\n        /// <summary>\n        /// The specialization of CompileTimeCheck&lt;false&gt;.\n        ///\n        /// This class should not be used directly - use the COMPILE_TIME_CHECK macro instead.\n        /// </summary>\n        template<>\n        class CompileTimeCheck<false> \n        {\n        };\n    }\n\n    /// <summary>\n    /// Flags for GetStack stackFormats parameter\n    /// </summary>\n    /// <remarks>\n    /// The flags are combinable with the | operator\n    /// </remarks>\n    namespace CallStackFormat\n    {\n        /// <summary>Displays only functionModule!functionName for each frame.</summary>\n        const extern WEXCOMMON_API DWORD Default;\n\n        /// <summary>Show return, previous frame and other relevant address values for each frame.</summary>\n        const extern WEXCOMMON_API DWORD FrameAddress;\n\n        /// <summary>This option is currently ignored.</summary>\n        const extern WEXCOMMON_API DWORD FunctionInfo;\n\n        /// <summary>Displays source line information for each frame of the stack trace.</summary>\n        const extern WEXCOMMON_API DWORD SourceLine;\n\n        /// <summary>Shows frame numbers.</summary>\n        const extern WEXCOMMON_API DWORD FrameNumbers;\n\n        /// <summary>This option is currently ignored.</summary>\n        const extern WEXCOMMON_API DWORD Parameters;\n\n        /// <summary>Shows column names.</summary>\n        const extern WEXCOMMON_API DWORD ColumnNames;\n\n        /// <summary>Shows frame-to-frame memory usage.</summary>\n        const extern WEXCOMMON_API DWORD FrameMemoryUsage;\n\n        /// <summary>Shows all available information. This is equivalent to Default | FrameAddress | FunctionInfo | SourceLine\n        /// | FrameNumbers | Parameters | ColumnNames | FrameMemoryUsage.</summary>\n        const extern WEXCOMMON_API DWORD FullInfo;\n    }\n\n    /// <summary>\n    /// Flags for SaveDump miniDumpFormats parameter\n    /// </summary>\n    /// <remarks>\n    /// The flags are combinable with the | operator\n    /// </remarks>\n    namespace MiniDumpFormat\n    {\n        /// <summary>Include process memory, stacks, etc - enough for most scenarios</summary>\n        const extern WEXCOMMON_API DWORD Default;\n\n        /// <summary>Packages dump into a CAB file</summary>\n        const extern WEXCOMMON_API DWORD WriteCab;\n\n        /// <summary>When creating a CAB adds secondary files such as current symbols and mapped images; takes very long time to complete</summary>\n        const extern WEXCOMMON_API DWORD WriteCabSecondaryFiles;\n\n        /// <summary>Adds full memory data. All accessible committed pages owned by the target application will be included</summary>\n        const extern WEXCOMMON_API DWORD FullMemory;\n\n        /// <summary>Adds data about the handles that are associated with the target application</summary>\n        const extern WEXCOMMON_API DWORD HandleData;\n\n        /// <summary>Adds unloaded module information</summary>\n        const extern WEXCOMMON_API DWORD UnloadedModules;\n\n        /// <summary>Adds indirect memory, a small region of memory that surrounds any address that is referenced by a pointer on the stack or backing store is included</summary>\n        const extern WEXCOMMON_API DWORD IndirectMemory;\n\n        /// <summary>Adds all data segments within the executable images</summary>\n        const extern WEXCOMMON_API DWORD DataSegments;\n\n        /// <summary>Adds the process environment block (PEB) and thread environment block (TEB). This flag can be used to provide Windows system information for threads and processes.</summary>\n        const extern WEXCOMMON_API DWORD ProcessThreadData;\n\n        /// <summary>Adds all committed private read-write memory pages</summary>\n        const extern WEXCOMMON_API DWORD PrivateReadWriteMemory;\n\n        /// <summary>Adds all basic memory information. The information for all memory is included, not just valid memory, which allows the debugger to reconstruct the complete virtual memory layout from the Minidump</summary>\n        const extern WEXCOMMON_API DWORD FullMemoryInfo;\n\n        /// <summary>Adds additional thread information, which includes execution time, start time, exit time, start address, and exit status</summary>\n        const extern WEXCOMMON_API DWORD ThreadInfo;\n\n        /// <summary>Adds all code segments with the executable images</summary>\n        const extern WEXCOMMON_API DWORD CodeSegments;\n\n        /// <summary>Creates a mixed / managed process actionable dump (alias to FullMemory)</summary>\n        const extern WEXCOMMON_API DWORD ManagedDump;\n\n        /// <summary>FullMemory | HandleData | FullMemoryInfo | ThreadInfo | UnloadedModules | CodeSegments | IndirectMemory</summary>\n        const extern WEXCOMMON_API DWORD FullDump;\n    }\n\n    class NoThrowString;\n\n    /// <summary>\n    /// Debugger related operations helper class\n    /// </summary>\n    class WEXCOMMON_API Debug SEALED\n    {\n    public:\n        /// <summary>\n        /// Assert when a given condition is false\n        /// </summary>\n        /// <param name=\"condition\">Assert condition</param>\n        /// <param name=\"pszCondition\">Assert condition string</param>\n        /// <param name=\"pszMessage\">Assert message</param>\n        /// <param name=\"pszFile\">Assert source file name</param>\n        /// <param name=\"pszFunction\">Assert source function name</param>\n        /// <param name=\"line\">Assert souce line number</param>\n        static void __stdcall Assert(bool condition, const wchar_t* pszCondition, const wchar_t* pszMessage, \n            const wchar_t* pszFile, const wchar_t* pszFunction, int line);\n\n        /// <summary>\n        /// Causes a breakpoint in the code\n        /// </summary>\n        static void __stdcall Break();\n\n        /// <summary>\n        /// Checks whether a debugger is present on the system\n        /// </summary>\n        /// <returns>true if a debugger found under AEDebug</returns>\n        static bool __stdcall IsDebuggerPresent();\n\n        // SaveDump and GetStack require dbgeng.dll and dbghelp.dll of version 6.x or above \n        // to exist in the LoadLibrary search path\n        // If older version found, NTE_BAD_VER error is returned\n\n        /// <summary>\n        /// Creates a minidump for the current process and saves it in the process local directory\n        /// </summary>\n        /// <param name=\"savedDumpFilePath\">The full path to the minidump file (set on success)</param>\n        /// <returns>Success of saving a dump</returns>\n        static HRESULT __stdcall SaveDump(NoThrowString& savedDumpFilePath);\n\n        /// <summary>\n        /// Creates a minidump for the current process and saves it in the process local directory\n        /// </summary>\n        /// <param name=\"miniDumpFormat\">See the values in namespace MiniDumpFormat above for miniDumpFormat parameter</param>\n        /// <param name=\"savedDumpFilePath\">The full path to the minidump file (set on success)</param>\n        /// <returns>Success of saving a dump</returns>\n        static HRESULT __stdcall SaveDump(DWORD miniDumpFormat, NoThrowString& savedDumpFilePath);\n\n        /// <summary>\n        /// Obtains the call stack for the context in capturedStack\n        /// </summary>\n        /// <param name=\"capturedStack\">The captured stack value</param>\n        /// <returns>Success of capturing stack</returns>\n        static HRESULT __stdcall GetStack(NoThrowString& capturedStack);\n\n        /// <summary>\n        /// Obtains the call stack for the context in capturedStack\n        /// </summary>\n        /// <param name=\"stackFormat\"> See the values in namespace CallStackFormat above for stackFormat parameter</param>\n        /// <param name=\"capturedStack\">The captured stack value</param>\n        /// <returns>Success of capturing stack</returns>\n        static HRESULT __stdcall GetStack(DWORD stackFormat, NoThrowString& capturedStack);\n\n        /// <summary>\n        /// Returns the last 'Win32' error - acting as a compiler firewall so that the Verify classes don't have to depend on Windows.h\n        /// </summary>\n        /// <returns>The calling thread's last error code.</returns>\n        static DWORD __stdcall GetLastError();\n\n        /// <summary>\n        /// Sets the last 'Win32' error - acting as a compiler firewall so that the Verify classes don't have to depend on Windows.h\n        /// </summary>\n        /// <param name=\"lastError\">The error code to set for the calling thread.</returns>\n        static void __stdcall SetLastError(unsigned long lastError);\n\n        /// <summary>\n        /// Sends text to debug output.\n        /// </summary>\n        /// <remarks>\n        /// The text will only be written on a 'debug' build.\n        /// </remarks>\n        /// <param name=\"pszString\">The message to be sent</param>\n        static void __stdcall Write(const wchar_t* pszString)\n        {\n#ifndef NDEBUG\n            Debug::WriteImpl(pszString);\n#else\n            UNREFERENCED_PARAMETER(pszString);\n#endif\n        }\n\n        /// <summary>\n        /// Sends text to debug output. Each text message ends with a new line\n        /// </summary>\n        /// <remarks>\n        /// The text will only be written on a 'debug' build.\n        /// </remarks>\n        /// <param name=\"pszString\">The message to be sent</param>\n        static void __stdcall WriteLine(const wchar_t* pszString)\n        {\n#ifndef NDEBUG\n            Debug::WriteLineImpl(pszString);\n#else\n            UNREFERENCED_PARAMETER(pszString);\n#endif\n        }\n\n        // wchar_t native type exports\n#ifdef WEXCOMMON_FULL_BUILD\n        static void __stdcall Assert(bool condition, const __wchar_t* pszCondition, const __wchar_t* pszMessage, \n            const __wchar_t* pszFile, const __wchar_t* pszFunction, int line);\n\n        static void __stdcall Write(const __wchar_t* pszString)\n        {\n#ifndef NDEBUG\n            Debug::WriteImpl(reinterpret_cast<const wchar_t*>(pszString));\n#else\n            UNREFERENCED_PARAMETER(pszString);\n#endif\n        }\n\n        static void __stdcall WriteLine(const __wchar_t* pszString)\n        {\n#ifndef NDEBUG\n            Debug::WriteLineImpl(reinterpret_cast<const wchar_t*>(pszString));\n#else\n            UNREFERENCED_PARAMETER(pszString);\n#endif\n        }\n#endif\n\n    private:\n        Debug();\n        Debug(const Debug&);\n        Debug& operator=(const Debug&);\n\n        static void __stdcall WriteImpl(const wchar_t* pszString);\n        static void __stdcall WriteLineImpl(const wchar_t* pszString);\n\n        // wchar_t native type exports\n#ifdef WEXCOMMON_FULL_BUILD\n        static void __stdcall WriteImpl(const __wchar_t* pszString);\n        static void __stdcall WriteLineImpl(const __wchar_t* pszString);\n#endif\n\n        static const bool c_fullDebug;\n    };\n} /* namespace Common */ } /* namespace WEX */\n\n#pragma pop_macro(\"SEALED\")\n#pragma pop_macro(\"Debug\")\n#pragma pop_macro(\"Assert\")\n#pragma warning(pop)\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WexException.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Base exception class; all exceptions thrown should either be this class or derive from it.</summary>\n/// <remarks>You cannot throw this Exception directly - instead, you must use one of the Throw class methods.</remarks>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Common.h\"\n#include \"WexString.h\"\n#include \"Throw.h\"\n\n#pragma push_macro(\"_In_z_\")\n#pragma push_macro(\"_Ret_z_\")\n#pragma push_macro(\"_In_range_\")\n#pragma push_macro(\"_Field_range_\")\n#pragma push_macro(\"_Ret_range_\")\n\n#if !defined(_In_z_)\n#define _In_z_\n#endif\n\n#if !defined(_Ret_z_)\n#define _Ret_z_\n#endif\n\n#if !defined(_In_range_)\n#define _In_range_(a,b)\n#endif\n\n#if !defined(_Field_range_)\n#define _Field_range_(a,b)\n#endif\n\n#if !defined(_Ret_range_)\n#define _Ret_range_(a,b)\n#endif\n\nnamespace WEX { namespace Common\n{\n    const wchar_t c_szExceptionMessageUnavailable[] = L\"Error retrieving exception message; possibly out of memory.\";\n\n    class WEXCOMMON_API Exception\n    {\n    // Only allow Throw to construct Exception objects\n    friend void Throw::Private::ThrowImpl(HRESULT, const wchar_t*);\n\n    public:\n        Exception(const Exception& other); // Copy constructor\n        virtual ~Exception(){}\n\n        _Ret_z_ const unsigned short* Message() const // Returns the message (if any) that was passed into the Exception constructor \n        {\n            if (m_message.IsValid())\n            {\n                return reinterpret_cast<const unsigned short*>(static_cast<const wchar_t*>(m_message));\n            }\n            else\n            {\n                return reinterpret_cast<const unsigned short*>(c_szExceptionMessageUnavailable);\n            }\n        }\n\n        #pragma prefast(suppress:28196, \"PreFast is not taking the _Field_range_ annotation under consideration when enforcing _Ret_range_.\")\n        _Ret_range_(<,0) HRESULT ErrorCode() const // Returns the HRESULT that was passed into the Exception constructor\n        {\n            return m_hresult;\n        }\n\n    protected:\n        explicit Exception(_In_range_(<, 0) HRESULT errorCode) // Don't allow \"throw Exception()\" -- use Throw::<method>() instead\n        : m_hresult(errorCode)\n        {\n        }\n\n        Exception(_In_range_(<, 0) HRESULT errorCode, _In_z_ const wchar_t* pszMessage) // Don't allow \"throw Exception()\" -- use Throw::<method>() instead\n        : m_hresult(errorCode)\n        , m_message(pszMessage)\n        {\n        }\n\n        Exception(_In_range_(<, 0) HRESULT errorCode, const WEX::Common::String& message) // Don't allow \"throw Exception()\" -- use Throw::<method>() instead\n        : m_hresult(errorCode)\n        , m_message(message)\n        {\n        }\n\n        // wchar_t native type export\n        #ifdef WEXCOMMON_FULL_BUILD\n        Exception(_In_range_(<, 0) HRESULT errorCode, _In_z_ const __wchar_t* pszMessage) // Don't allow \"throw Exception()\" -- use Throw::<method>() instead\n        : m_hresult(errorCode)\n        , m_message(reinterpret_cast<const wchar_t*>(pszMessage))\n        {\n        }\n        #endif\n\n    private:\n        Exception& operator=(const Exception&); // non-implemented assignment operator\n\n        // Making 'operator new' private prevents heap allocation of Exception, and forces Exception instances\n        // to be thrown by value.\n        static void* operator new(size_t);\n\n        // Making 'operator delete' private for consistency with 'operator new'.\n        // This is implemented to prevent linker errors.\n        static void operator delete(void*) {}\n\n        _Field_range_(<,0) const HRESULT m_hresult;\n        WEX::Common::NoThrowString m_message;\n    };\n\n} /* namespace Common */ } /* namespace WEX */\n\n#pragma pop_macro(\"_In_z_\")\n#pragma pop_macro(\"_Ret_z_\")\n#pragma pop_macro(\"_In_range_\")\n#pragma pop_macro(\"_Field_range_\")\n#pragma pop_macro(\"_Ret_range_\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WexString.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>\n/// Wex String classes.  Use the String class in exception-throwing environments,\n/// and the NoThrowString class in non exception-throwing environments.  The NoThrowString\n/// class is an exception-safe wrapper around the String class.\n/// </summary>\n/// <remarks>\n/// When using the String class, you must be sure that you are handling WEX::Common::Exceptions around any\n/// non-const member function calls.  \n/// \n/// When using the NoThrowString class, you should call IsValid after every call to a non-const\n/// member function in order to check that the string contents are still valid.  \n/// You can also call GetLastHResult() for more information.\n/// </remarks>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n#include \"Wex.Common.h\"\n#include \"WexTypes.h\"\n\n#include <stdarg.h>\n\n#pragma push_macro(\"_In_opt_z_\")\n#pragma push_macro(\"_In_reads_or_z_\")\n#pragma push_macro(\"_In_reads_or_z_opt_\")\n#pragma push_macro(\"_In_z_\")\n#pragma push_macro(\"_Post_equal_to_\")\n#pragma push_macro(\"_Printf_format_string_\")\n#pragma push_macro(\"_Ret_writes_\")\n\n#if !defined(_In_opt_z_)\n#define _In_opt_z_\n#endif\n\n#if !defined(_In_reads_or_z_)\n#define _In_reads_or_z_(x)\n#endif\n\n#if !defined(_In_reads_or_z_opt_)\n#define _In_reads_or_z_opt_(x)\n#endif\n\n#if !defined(_In_z_)\n#define _In_z_\n#endif\n\n#if !defined(_Post_equal_to_)\n#define _Post_equal_to_(x)\n#endif\n\n#if !defined(_Printf_format_string_)\n#define _Printf_format_string_\n#endif\n\n#if !defined(_Ret_writes_)\n#define _Ret_writes_(x)\n#endif\n\n/// \\namespace WEX::Common\n/// <summary>\n/// The WEX::Common namespace contains fundamental declarations.\n/// </summary>\nnamespace WEX { namespace Common\n{\n    class NoThrowString;\n\n    /// <summary>\n    /// Wex String classes.  Use the String class in exception-throwing environments,\n    /// and the NoThrowString class in non exception-throwing environments.  The NoThrowString\n    /// class is an exception-safe wrapper around the String class.\n    /// </summary>\n    class WEXCOMMON_API String\n    {\n    public:\n        /// <summary>Constructs an empty String.</summary>\n        String();\n\n        /// <summary>Constructs a String with the same contents as the specified NoThrowString.</summary>\n        /// <param name=\"str\">The NoThrowString instance to copy the contents from.</param>\n        String(const NoThrowString& str);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        String(_In_opt_z_ wchar_t* psz);\n\n        /// <summary>Constructs a String object, and copies the requested number of characters from the specified wchar_t*</summary>\n        /// <param name=\"psz\"> </param>\n        /// <param name=\"count\"> </param>\n        String(_In_reads_or_z_opt_(count) const wchar_t* psz, int count);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        String(_In_opt_z_ char* psz);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        String(_In_opt_z_ const wchar_t* psz);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        String(_In_opt_z_ const char* psz);\n\n        /// <summary>Destroys the String free'ing all associated resources.</summary>\n        ~String();\n\n#if !defined(_MSC_VER) || (_MSC_VER >= 1600)\n        /// <summary>Move constructor</summary>\n        /// <param name=\"str\"> </param>\n        String(String&& str);\n#endif\n\n        // Copy constructor\n        /// <summary> </summary>\n        /// <param name=\"str\"> </param>\n        String(const String& str);\n\n        // Assignment\n#if !defined(_MSC_VER) || (_MSC_VER >= 1600)\n        /// <summary>Move assignment operator from NoThrowString. If the NoThrowString is not valid, the String remains unchanged.</summary>\n        /// <param name=\"strSrc\"> </param>\n        const String& operator =(NoThrowString&& strSrc);\n#endif\n\n        /// <summary></summary>\n        /// <param name=\"strSrc\"> </param>\n        const String& operator =(String strSrc);\n\n        /// <summary>Copy assignment operator from NoThrowString. If the NoThrowString is not valid, the String remains unchanged.</summary>\n        /// <param name=\"strSrc\"> </param>\n        const String& operator =(const NoThrowString& strSrc);\n\n        /// <summary></summary>\n        /// <param name=\"ch\"> </param>\n        const String& operator =(wchar_t ch);\n\n        /// <summary></summary>\n        /// <param name=\"ch\"> </param>\n        const String& operator =(char ch);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        const String& operator =(_In_opt_z_ const wchar_t* psz);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        const String& operator =(_In_opt_z_ const char* psz);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        const String& operator =(_In_opt_z_ const unsigned char* psz); \n\n        // Appending (For concatenation, see outside of the class definition below)\n\n        /// <summary></summary>\n        /// <param name=\"str\"> </param>\n        const String& operator +=(const String& str);\n\n        /// <summary></summary>\n        /// <param name=\"ch\"> </param>\n        /// <param name=\"ch\"> </param>\n        const String& operator +=(wchar_t ch);\n\n        /// <summary></summary>\n        /// <param name=\"ch\"> </param>\n        const String& operator +=(char ch);\n\n        /// <summary></summary>\n        /// <param name=\"psz\"> </param>\n        const String& operator +=(_In_z_ const wchar_t* psz);\n\n        // Conversion\n        operator const wchar_t*() const;\n\n        // Helper Methods\n        /// <summary>Append a specified string to an existing String</summary>\n        /// <param name=\"strSrc\">The String to append.</param>\n        /// <param name=\"strSrc\"> </param>\n        String& Append(const String& strSrc);\n\n        /// <summary>Append a specified string to an existing String</summary>\n        /// <param name=\"pszSrc\"> </param>\n        String& Append(_In_z_ const wchar_t* pszSrc);\n\n        /// <summary>Append a given character to this string</summary>\n        /// <param name=\"ch\"> </param>\n        String& Append(wchar_t ch);\n\n        /// <summary>Append a given character to this string</summary>\n        /// <param name=\"ch\"> </param>\n        String& Append(char ch);\n\n        /// <summary>Appends formatted data to an existing string</summary>\n        /// <param name=\"pszFormat\"> </param>\n        String& AppendFormat(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, ...);\n\n        /// <summary>Appends formatted data to an existing string</summary>\n        /// <param name=\"pszFormat\"> </param>\n        /// <param name=\"args\"> </param>\n        String& AppendFormatV(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, va_list args);\n\n        /// <summary>Compares two strings (case sensitive)</summary>\n        /// <param name=\"pszCompare\"> </param>\n        int Compare(_In_z_ const wchar_t* pszCompare) const;\n\n        /// <summary>Compares two strings (case insensitive).</summary>\n        /// <param name=\"pszCompare\"> </param>\n        int CompareNoCase(_In_z_ const wchar_t* pszCompare) const;\n\n        /// <summary>Copies the requested number of characters from the specified wchar_t*.  Allocates more space if necessary.</summary>\n        /// <param name=\"pszSrc\"> </param>\n        /// <param name=\"count\"> </param>\n        void Copy(_In_reads_or_z_(count) const wchar_t* pszSrc, int count);\n\n        /// <summary>Deletes a character or characters from a string</summary>\n        /// <param name=\"index\"> </param>\n        /// <param name=\"count\"> </param>\n        int Delete(int index, int count = 1);\n\n        /// <summary>Empties the string</summary>\n        void Empty();\n\n        /// <summary>Searches the string for the first match of the specified character</summary>\n        /// <param name=\"ch\"> </param>\n        /// <returns>The zero-based index of the first character in this String object that matches\n        /// the requested character or -1 if the character is not found.</returns>\n        int Find(wchar_t ch) const;\n\n        /// <summary>Searches the string for the first match of the specified character</summary>\n        /// <param name=\"ch\"> </param>\n        /// <param name=\"start\"> </param>\n        /// <returns>The zero-based index of the first character in this String object after the start\n        /// offset that matches the requested character or -1 if the character is not found.</returns>\n        int Find(wchar_t ch, int start) const;\n\n        /// <summary>Searches the string for the first match of the specified substring</summary>\n        /// <param name=\"pszSub\"> </param>\n        /// <returns>The zero-based index of the first substring in this String object that matches\n        /// the requested substring or -1 if the substring is not found.</returns>\n        int Find(_In_z_ const wchar_t* pszSub) const;\n\n        /// <summary>Searches the string for the first match of the specified substring</summary>\n        /// <param name=\"pszSub\"> </param>\n        /// <param name=\"start\"> </param>\n        /// <returns>The zero-based index of the first substring in this String object after the start\n        /// offset that matches the requested substring or -1 if the substring is not found.</returns>\n        int Find(_In_z_ const wchar_t* pszSub, int start) const;\n\n        /// <summary>Formats the string as swprintf does</summary>\n        /// <param name=\"pszFormat\"> </param>\n        String& Format(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, ...);\n\n        /// <summary>Formats the string as swprintf does</summary>\n        /// <param name=\"pszFormat\"> </param>\n        /// <param name=\"args\"> </param>\n        String& FormatV(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, va_list args);\n\n        /// <summary>Frees any extra memory previously allocated by the string but no longer needed</summary>\n        void FreeExtra();\n\n        /// <summary>Returns the count of characters in the string</summary>\n        int GetLength() const;\n\n        /// <summary>Inserts a single character at the given index within the string</summary>\n        /// <param name=\"index\"> </param>\n        /// <param name=\"ch\"> </param>\n        int Insert(int index, wchar_t ch);\n\n        /// <summary>Inserts a substring at the given index within the string</summary>\n        /// <param name=\"index\"> </param>\n        /// <param name=\"psz\"> </param>\n        int Insert(int index, _In_z_ const wchar_t* psz);\n\n        /// <summary>Returns whether or not the string is empty</summary>\n        bool IsEmpty() const;\n\n        /// <summary>Returns a non-const pointer to the underlying string buffer.  If you write to the buffer using this pointer, be sure to call ReleaseBuffer when finished.</summary>\n        unsigned short* GetBuffer();\n\n        /// <summary>Returns a pointer to the internal character buffer for the String object, truncating or growing its length if necessary to exactly match the length specified in Length</summary>\n        /// <param name=\"length\"> </param>\n        _Ret_writes_(length + 1) unsigned short* GetBufferSetLength(int length);\n\n        /// <summary>Call this method to reallocate or free up the buffer of the string object, If you know that the string in the buffer is null terminated, you can omit the newLength argument. If your string is not null terminated, use newLength to specify its length. NOTE: The address returned by GetBuffer is invalid after the call to ReleaseBuffer </summary>\n        /// <param name=\"newLength\"> </param>\n        void ReleaseBuffer(int newLength = -1);\n\n        /// <summary>Extracts the first (leftmost) count characters from the string</summary>\n        /// <param name=\"count\"> </param>\n        String Left(int count) const;\n\n        /// <summary>Extracts a substring of length count characters, starting at position first </summary>\n        /// <param name=\"first\"> </param>\n        /// <param name=\"count\"> </param>\n        String Mid(int first, int count) const;\n\n        /// <summary>Extracts a substring of length count characters, starting at position first </summary>\n        /// <param name=\"first\"> </param>\n        String Mid(int first) const;\n\n        /// <summary>Removes instances of the specified character from the string</summary>\n        /// <param name=\"removeChar\"> </param>\n        int Remove(wchar_t removeChar);\n\n        /// <summary>Replaces all instances of one character with another</summary>\n        /// <param name=\"oldChar\"> </param>\n        /// <param name=\"newChar\"> </param>\n        int Replace(wchar_t oldChar, wchar_t newChar);\n\n        /// <summary>Replaces all instances of one substring with another</summary>\n        /// <param name=\"pszOld\"> </param>\n        /// <param name=\"pszNew\"> </param>\n        int Replace(_In_z_ const wchar_t* pszOld, _In_z_ const wchar_t* pszNew);\n\n        /// <summary>Reverses the order of characters in the string</summary>\n        void Reverse();\n\n        /// <summary>Searches for a character inside a larger string; starts at the end of the string</summary>\n        /// <returns>The zero-based index of the last character in this String object that matches the requested character, or -1 if the character is not found.</returns>\n        /// <param name=\"ch\">The character to look for.</param>\n        int ReverseFind(wchar_t ch) const;\n\n        /// <summary>Extracts the last (rightmost) count characters from the string </summary>\n        /// <param name=\"count\"> </param>\n        String Right(int count) const;\n\n        /// <summary>Converts all the characters in this string to lower-case </summary>\n        String& ToLower();\n\n        /// <summary>Converts all the characters in this string to upper-case </summary>\n        String& ToUpper();\n\n        /// <summary>Trims all leading and trailing whitespace, new line, tab and space characters from the string</summary>\n        void Trim();\n\n        /// <summary>Trims all leading and trailing whitespace, new line, tab and space characters from the left portion of the string</summary>\n        void TrimLeft();\n\n        /// <summary>Trims all leading and trailing whitespace, new line, tab and space characters from the right portion of the string</summary>\n        void TrimRight();\n\n        /// <summary>Returns whether or not the specified const wchar_t* is null or an empty string</summary>\n        /// <param name=\"psz\">The const wchar_t* to check.</param>\n        /// <returns> </returns>\n        _Post_equal_to_(!psz || *psz == 0)\n        static bool __stdcall IsNullOrEmpty(_In_opt_z_ const wchar_t* psz)\n        {\n            return !psz || *psz == L'\\0';\n        }\n\n        // wchar_t native type exports\n        #ifdef BUILD_WCHAR_T_EXPORTS\n        operator const __wchar_t*() const;\n        #endif\n\n        #ifdef WEXCOMMON_FULL_BUILD\n        String(_In_opt_z_ __wchar_t* psz);\n        String(_In_reads_or_z_opt_(count) const __wchar_t* psz, int count);\n        String(_In_opt_z_ const __wchar_t* psz);\n\n        const String& operator =(__wchar_t ch);\n        const String& operator =(_In_opt_z_ const __wchar_t* psz);\n\n        const String& operator +=(__wchar_t ch);\n        const String& operator +=(_In_z_ const __wchar_t* psz);\n\n        String& Append(_In_z_ const __wchar_t* pszSrc);\n        String& Append(__wchar_t ch);\n        String& AppendFormat(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, ...);\n        String& AppendFormatV(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, va_list args);\n        int Compare(_In_z_ const __wchar_t* pszCompare) const;\n        int CompareNoCase(_In_z_ const __wchar_t* pszCompare) const;\n        void Copy(_In_reads_or_z_(count) const __wchar_t* pszSrc, int count);\n        int Find(__wchar_t ch) const;\n        int Find(__wchar_t ch, int start) const;\n        int Find(_In_z_ const __wchar_t* pszSub) const;\n        int Find(_In_z_ const __wchar_t* pszSub, int start) const;\n        String& Format(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, ...);\n        String& FormatV(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, va_list args);\n        int Insert(int index, __wchar_t ch);\n        int Insert(int index, _In_z_ const __wchar_t* psz);\n        int Remove(__wchar_t removeChar);\n        int Replace(__wchar_t oldChar, __wchar_t newChar);\n        int Replace(_In_z_ const __wchar_t* pszOld, _In_z_ const __wchar_t* pszNew);\n        int ReverseFind(__wchar_t ch) const;\n\n        static bool __stdcall IsNullOrEmpty(const __wchar_t* psz)\n        {\n            return IsNullOrEmpty(reinterpret_cast<const unsigned short*>(psz));\n        }\n        #endif // WEXCOMMON_API\n\n    private:\n        friend WEXCOMMON_API int __stdcall GetBufferLength(const String& string);\n        friend WEXCOMMON_API void __stdcall swap(String& str1, String& str2);\n\n        void UpdateDebugPointer();\n\n        struct StringImpl;\n        StringImpl* m_pImpl;\n        const wchar_t* m_psz;\n    };\n\n    /// <summary>A function that retrieves the length of the allocated buffer backing a String instance.</summary>\n    /// <param name=\"string\">The String to retrieve the buffer length of.</param>\n    /// <returns>The length of the allocated buffer, in characters.</returns>\n    WEXCOMMON_API int __stdcall GetBufferLength(const String& string);\n    \n    WEXCOMMON_API bool __stdcall operator==(const String& str1, const String& str2);\n\n    WEXCOMMON_API bool __stdcall operator==(const String& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator==(_In_z_ const wchar_t* psz, const String& str);\n    \n    WEXCOMMON_API bool __stdcall operator!=(const String& str1, const String& str2);\n\n    WEXCOMMON_API bool __stdcall operator!=(const String& str, _In_z_ const wchar_t* psz);\n\n    WEXCOMMON_API bool __stdcall operator!=(_In_z_ const wchar_t* psz, const String& str);\n    \n    WEXCOMMON_API bool __stdcall operator<(const String& str1, const String& str2);\n\n    WEXCOMMON_API bool __stdcall operator<(const String& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator<(_In_z_ const wchar_t* psz, const String& str);\n    \n    WEXCOMMON_API bool __stdcall operator>(const String& str1, const String& str2);\n\n    WEXCOMMON_API bool __stdcall operator>(const String& str, _In_z_ const wchar_t* psz);\n\n    WEXCOMMON_API bool __stdcall operator>(_In_z_ const wchar_t* psz, const String& str);\n    \n    WEXCOMMON_API bool __stdcall operator<=(const String& str1, const String& str2);\n\n    WEXCOMMON_API bool __stdcall operator<=(const String& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator<=(_In_z_ const wchar_t* psz, const String& str);\n    \n    WEXCOMMON_API bool __stdcall operator>=(const String& str1, const String& str2);\n    \n    WEXCOMMON_API bool __stdcall operator>=(const String& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator>=(_In_z_ const wchar_t* psz, const String& str);\n\n    // Concatenation\n    /// <summary></summary>\n    /// <param name=\"str1\"> </param>\n    /// <param name=\"str2\"> </param>\n    WEXCOMMON_API String __stdcall operator+(String str1, const String& str2);\n\n    /// <summary></summary>\n    /// <param name=\"str\"> </param>\n    /// <param name=\"ch\"> </param>\n    WEXCOMMON_API String __stdcall operator+(String str, wchar_t ch);\n\n    /// <summary></summary>\n    /// <param name=\"ch\"> </param>\n    /// <param name=\"str\"> </param>\n    WEXCOMMON_API String __stdcall operator+(wchar_t ch, const String& str);\n\n    /// <summary></summary>\n    /// <param name=\"str\"> </param>\n    /// <param name=\"ch\"> </param>\n    WEXCOMMON_API String __stdcall operator+(String str, char ch);\n\n    /// <summary></summary>\n    /// <param name=\"ch\"> </param>\n    /// <param name=\"str\"> </param>\n    WEXCOMMON_API String __stdcall operator+(char ch, const String& str);\n\n    /// <summary></summary>\n    /// <param name=\"str\"> </param>\n    /// <param name=\"lpsz\"> </param>\n    WEXCOMMON_API String __stdcall operator+(String str, _In_z_ const wchar_t* lpsz);\n\n    /// <summary></summary>\n    /// <param name=\"psz\"> </param>\n    /// <param name=\"str\"> </param>\n    WEXCOMMON_API String __stdcall operator+(_In_z_ const wchar_t* psz, const String& str);\n\n    // wchar_t native type exports\n    #ifdef WEXCOMMON_FULL_BUILD\n    WEXCOMMON_API bool __stdcall operator==(const String& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator==(_In_z_ const __wchar_t* psz, const String& str);\n    WEXCOMMON_API bool __stdcall operator!=(const String& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator!=(_In_z_ const __wchar_t* psz, const String& str);\n    WEXCOMMON_API bool __stdcall operator<(const String& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator<(_In_z_ const __wchar_t* psz, const String& str);\n    WEXCOMMON_API bool __stdcall operator>(const String& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator>(_In_z_ const __wchar_t* psz, const String& str);\n    WEXCOMMON_API bool __stdcall operator<=(const String& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator<=(_In_z_ const __wchar_t* psz, const String& str);\n    WEXCOMMON_API bool __stdcall operator>=(const String& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator>=(_In_z_ const __wchar_t* psz, const String& str);\n    WEXCOMMON_API String __stdcall operator+(String str, __wchar_t ch);\n    WEXCOMMON_API String __stdcall operator+(__wchar_t ch, const String& str);\n    WEXCOMMON_API String __stdcall operator+(String str, _In_z_ const __wchar_t* lpsz);\n    WEXCOMMON_API String __stdcall operator+(_In_z_ const __wchar_t* psz, const String& str);\n    #endif\n\n    WEXCOMMON_API void __stdcall swap(String& str1, String& str2);\n\n    /// <summary>\n    /// Wex String classes.  Use the String class in exception-throwing environments,\n    /// and the NoThrowString class in non exception-throwing environments.  The NoThrowString\n    /// class is an exception-safe wrapper around the String class.\n    /// </summary>\n    class WEXCOMMON_API NoThrowString\n    {\n    friend class String;\n    public:\n        NoThrowString();\n        NoThrowString(const String& str);\n        NoThrowString(_In_opt_z_ wchar_t* psz);\n        NoThrowString(_In_reads_or_z_opt_(count) const wchar_t* psz, int count); // Constructs a NoThrowString object, and copies the requested number of characters from the specified wchar_t*\n        NoThrowString(_In_opt_z_ char* psz);\n        NoThrowString(_In_opt_z_ const wchar_t* psz);\n        NoThrowString(_In_opt_z_ const char* psz);\n        ~NoThrowString();\n\n#if !defined(_MSC_VER) || (_MSC_VER >= 1600)\n        // Move constructor\n        NoThrowString(NoThrowString&& str);\n#endif\n\n        // Copy constructor\n        NoThrowString(const NoThrowString& str);\n\n        // Assignment\n        const NoThrowString& operator =(NoThrowString strSrc);\n        const NoThrowString& operator =(const String& strSrc);\n        const NoThrowString& operator =(wchar_t ch);\n        const NoThrowString& operator =(char ch);\n        const NoThrowString& operator =(_In_opt_z_ const wchar_t* psz);\n        const NoThrowString& operator =(_In_opt_z_ const char* psz);\n        const NoThrowString& operator =(_In_opt_z_ const unsigned char* psz); \n\n        // Appending (For concatenation, see outside of the class definition below)\n        const NoThrowString& operator +=(const NoThrowString& str);\n        const NoThrowString& operator +=(wchar_t ch);\n        const NoThrowString& operator +=(char ch);\n        const NoThrowString& operator +=(_In_z_ const wchar_t* psz); \n\n        // Conversion\n        operator const wchar_t*() const;\n\n        // Helper Methods\n        const wchar_t* ToCStrWithFallbackTo(_In_z_ const wchar_t* pszDefaultString) const;\n\n        /// <summary>Append a specified string to an existing NoThrowString</summary>\n        NoThrowString& Append(const NoThrowString& strSrc);\n\n        /// <summary>Append a specified string to an existing NoThrowString</summary>\n        NoThrowString& Append(_In_z_ const wchar_t* pszSrc);\n\n        /// <summary>Append a given character to this string</summary>\n        NoThrowString& Append(wchar_t ch);\n\n        /// <summary>Append a given character to this string</summary>\n        NoThrowString& Append(char ch);\n\n        /// <summary>Appends formatted data to an existing string</summary>\n        NoThrowString& AppendFormat(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, ...);\n\n        /// <summary>Appends formatted data to an existing string</summary>\n        /// <param name=\"pszFormat\"> </param>\n        /// <param name=\"args\"> </param>\n        NoThrowString& AppendFormatV(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, va_list args);\n\n        /// <summary>Compares two strings (case sensitive)</summary>\n        int Compare(_In_z_ const wchar_t* pszCompare) const;\n\n        /// <summary>Compares two strings (case insensitive).</summary>\n        int CompareNoCase(_In_z_ const wchar_t* pszCompare) const;\n\n        /// <summary>Copies the requested number of characters from the specified wchar_t*.  Allocates more space if necessary.</summary>\n        void Copy(_In_reads_or_z_(count) const wchar_t* pszSrc, int count);\n\n        /// <summary>Deletes a character or characters from a string</summary>\n        int Delete(int index, int count = 1);\n\n        /// <summary>Empties the string</summary>\n        void Empty();\n\n        /// <summary>Searches the string for the first match of the specified character</summary>\n        int Find(wchar_t ch) const;\n\n        /// <summary>Searches the string for the first match of the specified character</summary>\n        int Find(wchar_t ch, int start) const;\n\n        /// <summary>Searches the string for the first match of the specified substring</summary>\n        int Find(_In_z_ const wchar_t* pszSub) const;\n\n        /// <summary>Searches the string for the first match of the specified substring</summary>\n        int Find(_In_z_ const wchar_t* pszSub, int start) const;\n\n        /// <summary>Formats the string as swprintf does</summary>\n        NoThrowString& Format(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, ...);\n\n        /// <summary>Formats the string as swprintf does</summary>\n        /// <param name=\"pszFormat\"> </param>\n        /// <param name=\"args\"> </param>\n        NoThrowString& FormatV(_In_z_ _Printf_format_string_ const wchar_t* pszFormat, va_list args);\n\n        /// <summary>Frees any extra memory previously allocated by the string but no longer needed</summary>\n        void FreeExtra();\n\n        /// <summary>Returns the count of characters in the string</summary>\n        int GetLength() const;\n\n        /// <summary>Inserts a single character at the given index within the string</summary>\n        int Insert(int index, wchar_t ch);\n\n        /// <summary>Inserts a substring at the given index within the string</summary>\n        int Insert(int index, _In_z_ const wchar_t* psz);\n\n        /// <summary>Returns whether or not the string is empty</summary>\n        bool IsEmpty() const;\n\n        /// <summary>Returns a non-const pointer to the underlying string buffer.  If you write to the buffer using this pointer, be sure to call ReleaseBuffer when finished.</summary>\n        unsigned short* GetBuffer();\n\n        /// <summary>Returns a pointer to the internal character buffer for the NoThrowString object, truncating or growing its length if necessary to exactly match the length specified in Length</summary>\n        _Ret_writes_(length + 1) unsigned short* GetBufferSetLength(int length);\n\n        /// <summary>Call this method to reallocate or free up the buffer of the string object, If you know that the string in the buffer is null terminated, you can omit the newLength argument. If your string is not null terminated, use newLength to specify its length. NOTE: The address returned by GetBuffer is invalid after the call to ReleaseBuffer </summary>\n        void ReleaseBuffer(int newLength = -1);\n\n        /// <summary>Extracts the first (leftmost) count characters from the string</summary>\n        NoThrowString Left(int count) const;\n\n        /// <summary>Extracts a substring of length count characters, starting at position first </summary>\n        NoThrowString Mid(int first, int count) const;\n\n        /// <summary>Extracts a substring of length count characters, starting at position first </summary>\n        NoThrowString Mid(int first) const;\n\n        /// <summary>Removes instances of the specified character from the string</summary>\n        int Remove(wchar_t removeChar);\n\n        /// <summary>Replaces all instances of one character with another</summary>\n        int Replace(wchar_t oldChar, wchar_t newChar);\n\n        /// <summary>Replaces all instances of one substring with another</summary>\n        int Replace(_In_z_ const wchar_t* pszOld, _In_z_ const wchar_t* pszNew);\n\n        /// <summary>Reverses the order of characters in the string</summary>\n        void Reverse();\n\n        /// <summary>Searches for a character inside a larger string; starts at the end of the string</summary>\n        int ReverseFind(wchar_t ch) const;\n\n        /// <summary>Extracts the last (rightmost) count characters from the string </summary>\n        NoThrowString Right(int count) const;\n\n        /// <summary>Converts all the characters in this string to lower-case </summary>\n        NoThrowString& ToLower();\n\n        /// <summary>Converts all the characters in this string to upper-case </summary>\n        NoThrowString& ToUpper();\n\n        /// <summary>Trims all leading and trailing whitespace, new line, tab and space characters from the string</summary>\n        void Trim();\n\n        /// <summary>Trims all leading and trailing whitespace, new line, tab and space characters from the left portion of the string</summary>\n        void TrimLeft();\n\n        /// <summary>Trims all leading and trailing whitespace, new line, tab and space characters from the right portion of the string</summary>\n        void TrimRight();\n\n        /// <summary>Returns whether or not the string contents are still valid.  This method should be called after any non-const NoThrowString member functions are called in order to check for validity of string contents.</summary>\n        bool IsValid() const;\n\n        /// <summary>Returns the last error encountered by the NoThrowString class</summary>\n        HRESULT GetLastHResult() const;\n\n        // Returns whether or not the specified const wchar_t* is null or an empty string\n        static bool __stdcall IsNullOrEmpty(const wchar_t* psz)\n        {\n            return !psz || !*psz || *psz == L'\\0';\n        }\n\n        // WCHAR_T native type exports\n        #ifdef BUILD_WCHAR_T_EXPORTS\n        operator const __wchar_t*() const;\n        #endif\n\n        #ifdef WEXCOMMON_FULL_BUILD\n        NoThrowString(_In_opt_z_ __wchar_t* psz);\n        NoThrowString(_In_reads_or_z_opt_(count) const __wchar_t* psz, int count); // Constructs a String object, and copies the requested number of characters from the specified wchar_t*\n        NoThrowString(_In_opt_z_ const __wchar_t* psz);\n\n        const NoThrowString& operator =(__wchar_t ch);\n        const NoThrowString& operator =(_In_opt_z_ const __wchar_t* psz);\n\n        const NoThrowString& operator +=(__wchar_t ch);\n        const NoThrowString& operator +=(_In_z_ const __wchar_t* psz);\n\n        const __wchar_t* ToCStrWithFallbackTo(_In_z_ const __wchar_t* pszDefaultString) const;\n        NoThrowString& Append(_In_z_ const __wchar_t* pszSrc);\n        NoThrowString& Append(__wchar_t ch);\n        NoThrowString& AppendFormat(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, ...);\n        NoThrowString& AppendFormatV(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, va_list args);\n        int Compare(_In_z_ const __wchar_t* pszCompare) const;\n        int CompareNoCase(_In_z_ const __wchar_t* pszCompare) const;\n        void Copy(_In_reads_or_z_(count) const __wchar_t* pszSrc, int count);\n        int Find(__wchar_t ch) const;\n        int Find(__wchar_t ch, int start) const;\n        int Find(_In_z_ const __wchar_t* pszSub) const;\n        int Find(_In_z_ const __wchar_t* pszSub, int start) const;\n        NoThrowString& Format(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, ...);\n        NoThrowString& FormatV(_In_z_ _Printf_format_string_ const __wchar_t* pszFormat, va_list args);\n        int Insert(int index, __wchar_t ch);\n        int Insert(int index, _In_z_ const __wchar_t* psz);\n        int Remove(__wchar_t removeChar);\n        int Replace(__wchar_t oldChar, __wchar_t newChar);\n        int Replace(_In_z_ const __wchar_t* pszOld, _In_z_ const __wchar_t* pszNew);\n        int ReverseFind(__wchar_t ch) const;\n\n        static bool __stdcall IsNullOrEmpty(const __wchar_t* psz)\n        {\n            return IsNullOrEmpty(reinterpret_cast<const unsigned short*>(psz));\n        }\n        #endif // WEXCOMMON_API\n\n    private:\n        NoThrowString(HRESULT hr);\n        String* m_pImpl;\n\n        friend WEXCOMMON_API int __stdcall GetBufferLength(const NoThrowString& string);\n        friend WEXCOMMON_API void __stdcall swap(NoThrowString& str1, NoThrowString& str2);\n        void UpdateDebugPointer();\n\n        HRESULT m_lastHr;\n        const wchar_t* m_psz;\n    };\n\n    WEXCOMMON_API int __stdcall GetBufferLength(const NoThrowString& string);\n\n    WEXCOMMON_API bool __stdcall operator==(const NoThrowString& str1, const NoThrowString& str2);\n\n    WEXCOMMON_API bool __stdcall operator==(const NoThrowString& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator==(_In_z_ const wchar_t* psz, const NoThrowString& str);\n    \n    WEXCOMMON_API bool __stdcall operator!=(const NoThrowString& str1, const NoThrowString& str2);\n\n    WEXCOMMON_API bool __stdcall operator!=(const NoThrowString& str, _In_z_ const wchar_t* psz);\n\n    WEXCOMMON_API bool __stdcall operator!=(_In_z_ const wchar_t* psz, const NoThrowString& str);\n    \n    WEXCOMMON_API bool __stdcall operator<(const NoThrowString& str1, const NoThrowString& str2);\n\n    WEXCOMMON_API bool __stdcall operator<(const NoThrowString& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator<(_In_z_ const wchar_t* psz, const NoThrowString& str);\n    \n    WEXCOMMON_API bool __stdcall operator>(const NoThrowString& str1, const NoThrowString& str2);\n\n    WEXCOMMON_API bool __stdcall operator>(const NoThrowString& str, _In_z_ const wchar_t* psz);\n\n    WEXCOMMON_API bool __stdcall operator>(_In_z_ const wchar_t* psz, const NoThrowString& str);\n    \n    WEXCOMMON_API bool __stdcall operator<=(const NoThrowString& str1, const NoThrowString& str2);\n\n    WEXCOMMON_API bool __stdcall operator<=(const NoThrowString& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator<=(_In_z_ const wchar_t* psz, const NoThrowString& str);\n    \n    WEXCOMMON_API bool __stdcall operator>=(const NoThrowString& str1, const NoThrowString& str2);\n    \n    WEXCOMMON_API bool __stdcall operator>=(const NoThrowString& str, _In_z_ const wchar_t* psz);\n    \n    WEXCOMMON_API bool __stdcall operator>=(_In_z_ const wchar_t* psz, const NoThrowString& str);\n\n\n    // Concatenation\n    /// <summary> </summary>\n    /// <param name=\"str1\"> </param>\n    /// <param name=\"str2\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(NoThrowString str1, const NoThrowString& str2);\n\n    /// <summary> </summary>\n    /// <param name=\"ch\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(NoThrowString str, wchar_t ch);\n\n    /// <summary> </summary>\n    /// <param name=\"ch\"> </param>\n    /// <param name=\"str\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(wchar_t ch, const NoThrowString& str);\n\n    /// <summary> </summary>\n    /// <param name=\"str\"> </param>\n    /// <param name=\"ch\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(NoThrowString str, char ch);\n\n    /// <summary> </summary>\n    /// <param name=\"ch\"> </param>\n    /// <param name=\"str\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(char ch, const NoThrowString& str);\n\n    /// <summary> </summary>\n    /// <param name=\"str\"> </param>\n    /// <param name=\"lpsz\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(NoThrowString str, _In_z_ const wchar_t* lpsz);\n\n    /// <summary> </summary>\n    /// <param name=\"psz\"> </param>\n    /// <param name=\"str\"> </param>\n    WEXCOMMON_API NoThrowString __stdcall operator+(_In_z_ const wchar_t* psz, const NoThrowString& str);\n\n    // wchar_t native type exports\n    #ifdef WEXCOMMON_FULL_BUILD\n    WEXCOMMON_API bool __stdcall operator==(const NoThrowString& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator==(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    WEXCOMMON_API bool __stdcall operator!=(const NoThrowString& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator!=(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    WEXCOMMON_API bool __stdcall operator<(const NoThrowString& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator<(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    WEXCOMMON_API bool __stdcall operator>(const NoThrowString& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator>(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    WEXCOMMON_API bool __stdcall operator<=(const NoThrowString& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator<=(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    WEXCOMMON_API bool __stdcall operator>=(const NoThrowString& str, _In_z_ const __wchar_t* psz);\n    WEXCOMMON_API bool __stdcall operator>=(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    WEXCOMMON_API NoThrowString __stdcall operator+(NoThrowString str, __wchar_t ch);\n    WEXCOMMON_API NoThrowString __stdcall operator+(__wchar_t ch, const NoThrowString& str);\n    WEXCOMMON_API NoThrowString __stdcall operator+(NoThrowString str, _In_z_ const __wchar_t* lpsz);\n    WEXCOMMON_API NoThrowString __stdcall operator+(_In_z_ const __wchar_t* psz, const NoThrowString& str);\n    #endif\n\n    WEXCOMMON_API void __stdcall swap(NoThrowString& str1, NoThrowString& str2);\n} /* namespace Common */ } /* namespace WEX */\n\n#pragma pop_macro(\"_In_opt_z_\")\n#pragma pop_macro(\"_In_reads_or_z_\")\n#pragma pop_macro(\"_In_reads_or_z_opt_\")\n#pragma pop_macro(\"_In_z_\")\n#pragma pop_macro(\"_Post_equal_to_\")\n#pragma pop_macro(\"_Printf_format_string_\")\n#pragma pop_macro(\"_Ret_writes_\")\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WexTestClass.h",
    "content": "//----------------------------------------------------------------------------------------------------------------------\n/// \\file\n/// <summary>Test Authoring and Execution Framework native macro definitions</summary>\n// Copyright (c) Microsoft Corporation.  All Rights Reserved.\n//----------------------------------------------------------------------------------------------------------------------\n#pragma once\n\n// We currently require the C++ compiler from VS 2012 or later.\n#if _MSC_VER < 1700\n#error Compiler version not supported by WexTestClass.h.\n#endif\n\n#pragma warning(push)\n#pragma warning(disable:4481)\n\n#pragma comment(lib, \"TE.Common.lib\")\n#pragma comment(lib, \"Wex.Common.lib\")\n#pragma comment(lib, \"Wex.Logger.lib\")\n\n// Allow anyone who has defined an Assert macro to compile with this header file included\n#pragma push_macro(\"Assert\")\n#undef Assert\n\n#include \"Interruption.h\"\n#include \"RuntimeParameters.h\"\n#include \"TestData.h\"\n#include \"Verify.h\"\n#include \"WexAssert.h\"\n#include \"WexDebug.h\"\n\n// excpt.h is used for GetExceptionCode, which is used to detect C++ exceptions in a structured exception handler.\n#include <excpt.h>\n\n#if defined(_CPPUNWIND)\n#include \"WexException.h\"\n\n#include <new>\n#endif\n\n#pragma push_macro(\"_Outptr_\")\n#pragma push_macro(\"_Outptr_result_maybenull_z_\")\n#pragma push_macro(\"_Ret_maybenull_z_\")\n#pragma push_macro(\"_In_reads_z_\")\n#pragma push_macro(\"_In_\")\n#pragma push_macro(\"_Post_invalid_\")\n\n#if !defined(_Outptr_)\n#define _Outptr_\n#endif\n\n#if !defined(_Outptr_result_maybenull_z_)\n#define _Outptr_result_maybenull_z_\n#endif\n\n#if !defined(_Ret_maybenull_z_)\n#define _Ret_maybenull_z_\n#endif\n\n#if !defined(_In_reads_z_)\n#define _In_reads_z_(x)\n#endif\n\n#if !defined(_In_)\n#define _In_\n#endif\n\n#if !defined(_Post_invalid_)\n#define _Post_invalid_\n#endif\n\n/// \\internal\n/// <summary> Wide string conversion helper </summary>\n#define TAEF_WIDEN_INT(x) L ## x\n\n/// \\internal\n/// <summary> Wide string version of \"stringizing\" operator </summary>\n#define TAEF_WIDEN(x) TAEF_WIDEN_INT(x)\n\n/// \\internal\n/// <summary>Wide string version of __FUNCTION__ macro </summary>\n#define TAEF__WFUNCTION__ TAEF_WIDEN(__FUNCTION__)\n\n/// \\internal\n/// <summary>Stringize internal macro </summary>\n#define TAEF_STRINGIZE_INT(x) #x\n\n/// \\internal\n/// <summary>Stringize macro </summary>\n#define TAEF_STRINGIZE(x) TAEF_STRINGIZE_INT(x)\n\n/// \\internal\n/// <summary>TAEF version number.</summary>\n#define TAEF_ABI_VERSION 8\n\n/// \\internal\n/// <summary>The magic number that will lead the testdata segment in v3.3 and later. This is \"TAEF\" in ascii.</summary>\n#define TAEF_HEADER_SIGNATURE 0x46454154\n\n#ifdef INLINE_TEST_METHOD_MARKUP\n#define TAEF_TERMINATOR\n#else\n#define TAEF_TERMINATOR ;\n#endif\n\n#if !defined(__cplusplus_cli)\n\n#if !defined(__INTRIN_H_)\n// Including intrin.h from WexTestClass.h causes build breaks for some users of WexTestClass.h.\nextern \"C\" __declspec(noreturn) void __fastfail(unsigned int);\n#endif // #if !defined(__INTRIN_H_)\n\n#define TAEF_FAST_FAIL __fastfail(7 /* FAST_FAIL_FATAL_APP_EXIT */)\n#else\n// Using __fastfail with C++/CLI causes warning C4793 to be raised.\n#define TAEF_FAST_FAIL System::Environment::FailFast(nullptr)\n#endif // #if !defined(__cplusplus_cli)\n\n/// <summary>\n/// The WEX namespace contains classes used for marking up C++ Tests.\n/// </summary>\nnamespace WEX\n{\n    namespace Private\n    {\n        /// \\internal\n        /// <summary>\n        /// A SEH filter.\n        /// </summary>\n        unsigned long inline DetectMSVCExceptions(unsigned long exceptionCode, bool& isCPlusPlusException)\n        {\n            // If the 'exceptionCode' is 0xE06D7363 (which is the exception code that MSVC uses to implement\n            // C++ exceptions using SEH), then this is a C++ exception. Set isCPlusPlusException to indicate\n            // this. This is used by the catch(...) handler which does a fast-fail if it is not a C++\n            // exception. The catch(...) will only be invoked for non-C++ exceptions if the /EHa switch is\n            // used on the compiler while compiling the test DLL.\n            isCPlusPlusException = (exceptionCode == 0xE06D7363);\n\n#if !defined(_CPPUNWIND)\n            if (isCPlusPlusException)\n            {\n                WEX::Logging::Log::Error(L\"A C++ exception was throw by a test in a DLL that was compiled with C++ exceptions disabled.\");\n                // In this case, if we let the exception continue the search, it would be caught by TAEF code. We want to avoid\n                // catching the exception so the process can crash with the right context.\n                \n                // To fix this in a Visual Studio project, change the Configuration Properties -> C/C++ ->\n                // Code Generation -> Enable C++ Exceptions setting in the project properties from \"No\" to \"Yes (/EHsc)\".\n                // To fix this in the build.exe-based build system from the old Windows Driver Kit, add\n                // \"USE_NATIVE_EH=1\" to the sources file.\n                TAEF_FAST_FAIL;\n            }\n#endif\n\n            return EXCEPTION_CONTINUE_SEARCH;\n        }\n\n        template <typename TFunctor>\n        bool SafeInvoke_Impl(const TFunctor& functor, bool& isCPlusPlusException)\n        {\n            bool result = false;\n            __try\n            {\n                result = functor();\n            }\n            __except (WEX::Private::DetectMSVCExceptions(GetExceptionCode(), isCPlusPlusException))\n            {\n                // This is unreachable because DetectMSVCExceptions returns EXCEPTION_CONTINUE_SEARCH.\n                TAEF_FAST_FAIL;\n            }\n            return result;\n        }\n\n        struct StringManager\n        {\n            template <size_t Size>\n            _Ret_maybenull_z_ static wchar_t* Allocate(const wchar_t (&szLiteral)[Size])\n            {\n                return Allocate(szLiteral, Size - 1);\n            }\n\n            _Ret_maybenull_z_ static wchar_t* Allocate(const WEX::Common::NoThrowString& str)\n            {\n                if (str.IsValid())\n                {\n                    return Allocate(str, static_cast<size_t>(str.GetLength()));\n                }\n\n                return nullptr;\n            }\n\n            _Ret_maybenull_z_ static wchar_t* Allocate(_In_reads_z_(length+1) const wchar_t* pszString, size_t length)\n            {\n                WEX_ASSERT(pszString[length] == L'\\0', L\"The string is not null-terminated.\");\n\n                wchar_t* pszRet = nullptr;\n#if defined(_CPPUNWIND)\n                try\n                {\n#endif\n                    // We aren't using \"new wchar_t[length+1]\" as that caused some linking problems for some existing tests.\n                    pszRet = static_cast<wchar_t*>(::operator new(sizeof(wchar_t)*(length+1)));\n#if defined(_CPPUNWIND)\n                }\n                catch (const std::exception&)\n                {\n                    // If new fails, pszRet will be null.\n                }\n#endif\n\n                if (pszRet)\n                {\n                    for (size_t i = 0; i < length; ++i)\n                    {\n                        pszRet[i] = pszString[i];\n                    }\n                    pszRet[length] = L'\\0';\n                }\n\n                return pszRet;\n            }\n\n            static void __cdecl Deallocate(_In_ _Post_invalid_ wchar_t* pszString)\n            {\n                ::operator delete(static_cast<void*>(pszString));\n            }\n        };\n    }/* namespace Private */\n\n    /// \\internal\n    /// <summary>\n    /// Identifiers for the structs that make up the native ABI.\n    /// </summary>\n    namespace TAEF_Identifier\n    {\n        enum Value : uintptr_t\n        {\n            TestClassInfo = 1,\n            TestMethodInfo,\n            ModuleSetup,\n            ModuleCleanup,\n            TestClassSetup,\n            TestClassCleanup,\n            TestMethodSetup,\n            TestMethodCleanup,\n            ModuleMetadata,\n            TestClassMetadata,\n            TestMethodMetadata,\n        }; \n    }\n\n    template <typename TFunctor>\n    HRESULT SafeInvoke(const TFunctor& functor)\n    {\n        // This is set to false if a structured exception which is not a C++ exception is raised by the test or fixture method.\n        bool exceptionIsCPlusPlusException = true;\n#if defined(_CPPUNWIND)\n        try\n        {\n#endif\n            return WEX::Private::SafeInvoke_Impl(functor, exceptionIsCPlusPlusException)\n                ? S_OK : E_FAIL;\n#if defined(_CPPUNWIND)\n        }\n# if !defined(NO_VERIFY_EXCEPTIONS)\n        catch (const WEX::TestExecution::VerifyFailureException& e)\n        {\n            return e.ErrorCode();\n        }\n# endif\n        catch (...)\n        {            \n            // exceptionIsCPlusPlusException will always be true if the test is not compiled with /EHa.\n            if (!exceptionIsCPlusPlusException)\n            {\n                // This catch (...) just caught a structured exception which is not a C++ exception.\n                // This means the test DLL was compiled using the /EHa switch on the compiler.\n                // See https://msdn.microsoft.com/en-us/library/1deeycx5.aspx for the /EH documentation.\n                // The use of /EHa is discouraged. Please consider switching to /EHsc, which instructs\n                // the compiler to only catch C++ exceptions with catch (...) and to assume that functions\n                // declared as extern \"C\" cannot throw.\n                // \n                // To fix this in a Visual Studio project, change the Configuration Properties -> C/C++ ->\n                // Code Generation -> Enable C++ Exceptions setting in the project properties from\n                // \"Yes with SEH Exceptions (/EHa)\" to \"Yes (/EHsc)\".\n                // To fix this in the build.exe-based build system from the old Windows Driver Kit, change\n                // \"USE_NATIVE_EH=ASYNC\" to \"USE_NATIVE_EH=1\" in the sources file.\n                TAEF_FAST_FAIL;\n            }\n\n            WEX::Common::NoThrowString messageBuffer;\n            HRESULT hr = S_OK;\n            WEX::Logging::Log::Error(WEX::TestExecution::Private::GetExceptionInfo(messageBuffer, &hr));\n\n            return hr;\n        }\n#endif // if defined(_CPPUNWIND)\n    }\n\n    /// <summary>\n    /// Legacy base class that all test classes used to have to inherit from.\n    /// </summary>\n    template <class T>\n    class TestClass {};\n\n    #pragma warning(push)\n    #pragma warning(disable:6101)\n    template <typename T>\n    struct TestClassFactory\n    {\n        /// \\internal\n        /// <summary>\n        /// Creates an instance of a test class\n        /// </summary>\n        static HRESULT __cdecl CreateInstance(_Outptr_ void** ppInstance, _Outptr_result_maybenull_z_ wchar_t** ppszMessage)\n        {\n            *ppszMessage = nullptr;\n            // This is set to false if a structured exception which is not a C++ exception is raised by the class constructor.\n            bool exceptionIsCPlusPlusException = true;\n#if defined(_CPPUNWIND)\n            try\n            {\n#endif\n                *ppInstance = CreateInstanceWithTryExcept(exceptionIsCPlusPlusException);\n                if (!*ppInstance)\n                {\n                    *ppszMessage = WEX::Private::StringManager::Allocate(L\"Failed to allocate the test class\");\n                    return E_OUTOFMEMORY;\n                }\n\n                return S_OK;\n#if defined(_CPPUNWIND)\n            }\n# if !defined(NO_VERIFY_EXCEPTIONS)\n            catch (const WEX::TestExecution::VerifyFailureException&)\n            {\n                *ppszMessage = WEX::Private::StringManager::Allocate(L\"Verify failure\");\n                return E_FAIL;\n            }\n# endif\n            catch (const std::exception& e)\n            {\n                *ppszMessage = WEX::Private::StringManager::Allocate(\n                    WEX::Common::NoThrowString().Format(L\"Caught std::exception: %S\", e.what()));\n                return E_FAIL;\n            }\n            catch (const WEX::Common::Exception& e)\n            {\n                *ppszMessage = WEX::Private::StringManager::Allocate(\n                    WEX::Common::NoThrowString().Format(L\"Caught WEX::Common::Exception: %s\", e.Message()));\n                return e.ErrorCode();\n            }\n#if defined(__cplusplus_winrt)\n            catch (Platform::Exception^ e)\n            {\n                *ppszMessage = WEX::Private::StringManager::Allocate(\n                    WEX::Common::NoThrowString().Format(L\"Caught Platform::Exception^: %s\", e->Message->Data()));\n                return e->HResult;\n            }\n#endif // if defined(__cplusplus_winrt)\n            catch (...)\n            {\n                // exceptionIsCPlusPlusException will always be true if the test is not compiled with /EHa.\n                if (!exceptionIsCPlusPlusException)\n                {\n                    // This catch (...) just caught a structured exception which is not a C++ exception.\n                    // This means the test DLL was compiled using the /EHa switch on the compiler.\n                    // See https://msdn.microsoft.com/en-us/library/1deeycx5.aspx for the /EH documentation.\n                    // The use of /EHa is discouraged. Please consider switching to /EHsc, which instructs\n                    // the compiler to only catch C++ exceptions with catch (...) and to assume that functions\n                    // declared as extern \"C\" cannot throw.\n                    // \n                    // To fix this in a Visual Studio project, change the Configuration Properties -> C/C++ ->\n                    // Code Generation -> Enable C++ Exceptions setting in the project properties from\n                    // \"Yes with SEH Exceptions (/EHa)\" to \"Yes (/EHsc)\".\n                    // To fix this in the build.exe-based build system from the old Windows Driver Kit, change\n                    // \"USE_NATIVE_EH=ASYNC\" to \"USE_NATIVE_EH=1\" in the sources file.\n                    TAEF_FAST_FAIL;\n                }\n\n                *ppszMessage = WEX::Private::StringManager::Allocate(L\"Caught an unidentified C++ exception.\");\n                return E_UNEXPECTED;\n            }\n#endif // if defined(_CPPUNWIND)\n        }\n\n        /// \\internal\n        /// <summary>\n        /// Creates an instance of a test class\n        /// </summary>\n        static T* __cdecl CreateInstanceWithTryExcept(bool& exceptionIsCPlusPlusException)\n        {\n            T* pInstance = nullptr;\n            __try\n            {\n                // We have to call the constructor in a separate function to avoid error C2712.\n                pInstance = CallDefaultConstructor();\n            }\n            __except (WEX::Private::DetectMSVCExceptions(GetExceptionCode(), exceptionIsCPlusPlusException))\n            {\n                // This is unreachable because DetectMSVCExceptions returns EXCEPTION_CONTINUE_SEARCH.\n                TAEF_FAST_FAIL;\n            }\n            return pInstance;\n        }\n\n        static T* __cdecl CallDefaultConstructor()\n        {\n            // What the caller links to controls the throwing behavior. We would prefer to use\n            // new (std::nothrow) T(), but that doesn't link for some existing test binaries; so\n            // we just use plain new.\n            return new T();\n        }\n\n        /// \\internal\n        /// <summary>\n        /// Destroys an instance of a test class\n        /// </summary>\n        static void __cdecl DestroyInstance(void* pTestClass)\n        {\n            delete static_cast<T*>(pTestClass);\n        }\n    };\n    #pragma warning(pop)\n\n    template <class T>\n    struct TestInvokeFunctor\n    {\n        typedef void (__thiscall T::*TestMethod)();\n    public:\n        TestInvokeFunctor(T& instance, TestMethod pTestMethod)\n            : m_pTestMethod(pTestMethod), m_instance(instance) {}\n\n        bool operator() () const\n        {\n#if defined(_CPPUNWIND) && !defined(NO_VERIFY_EXCEPTIONS)\n            try\n            {\n#endif\n                (m_instance.*m_pTestMethod)();\n#if defined(_CPPUNWIND) && !defined(NO_VERIFY_EXCEPTIONS)\n            }\n            catch (const WEX::TestExecution::VerifyFailureException&)\n            {\n                // Don't re-throw here. The error is already tracked in WEX.Logger.\n            }\n#endif\n\n            return true;\n        }\n\n    private:\n        TestInvokeFunctor(const TestInvokeFunctor&);\n        TestInvokeFunctor& operator=(const TestInvokeFunctor&);\n\n        // Store the pointer-to-member before the reference to avoid warning C4121 for tests\n        // that use #pragma pointers_to_members(full_generality, virtual_inheritance).\n        TestMethod m_pTestMethod;\n        T& m_instance;\n    };\n\n    template <class T>\n    struct FixtureInvokeFunctor\n    {\n        typedef bool (__thiscall T::*FixtureMethod)();\n    public:\n        FixtureInvokeFunctor(T& instance, FixtureMethod pFixtureMethod)\n            : m_pFixtureMethod(pFixtureMethod), m_instance(instance) {}\n\n        bool operator() () const\n        {\n            return (m_instance.*m_pFixtureMethod)();\n        }\n\n    private:\n        FixtureInvokeFunctor(const FixtureInvokeFunctor&);\n        FixtureInvokeFunctor& operator=(const FixtureInvokeFunctor&);\n\n        // Store the pointer-to-member before the reference to avoid warning C4121 for tests\n        // that use #pragma pointers_to_members(full_generality, virtual_inheritance).\n        FixtureMethod m_pFixtureMethod;\n        T& m_instance;\n    };\n\n    /// \\internal\n    /// <summary>\n    /// Metadata storage classes\n    /// Store various metadata about test classes in binary's \"testdata\" section\n    /// </summary>\n\n    /// \\internal\n    /// <summary>\n    ///  Test class related metadata storage class\n    ///  Resolves a class name to pointers to class creation and destruction functions\n    /// </summary>\n    struct TestClassInfo\n    {\n        /// \\internal\n        /// <summary> Pointer to a class 'creation' function</summary>\n        typedef HRESULT (__cdecl *ClassCreator)(_Outptr_ void** ppInstance, _Outptr_result_maybenull_z_ wchar_t** ppszMessage);\n\n        /// \\internal\n        /// <summary> Pointer to a class 'destroyer' function</summary>\n        typedef void (__cdecl *ClassDestroyer)(void*);\n\n        TAEF_Identifier::Value identifier;\n        const wchar_t* pszClassName;\n\n        ClassCreator pClassCreator;\n        ClassDestroyer pClassDestroyer;\n    };\n\n    typedef HRESULT (__cdecl *MethodInvokerFunction)(void* pTestClass);\n\n    /// \\internal\n    /// <summary>\n    /// Holds test method information that is relevant to the test loader.\n    /// </summary>\n    struct TestMethodInfo\n    {\n        TAEF_Identifier::Value identifier;\n        const wchar_t* pszMethodName;\n        const wchar_t* pszQualifiedMethodName;\n        uintptr_t index;\n        MethodInvokerFunction pInvoker;\n    };\n\n    /// \\internal\n    /// <summary>\n    /// Holds test or class setup or cleanup method information that is relevant to the test loader.\n    /// </summary>\n    struct FixtureMethodInfo\n    {\n        TAEF_Identifier::Value identifier;\n        const wchar_t* pszMethodName;\n        const wchar_t* pszQualifiedMethodName;\n        MethodInvokerFunction pInvoker;\n    };\n\n    /// \\internal\n    /// <summary>\n    ///  Holds various types of properties\n    ///  (module, class or function level)\n    ///  pszMetadataIdentifier identifies what kind of property is stored\n    /// </summary>\n    struct TestPropertyMetadata\n    {\n        TAEF_Identifier::Value identifier;\n        const wchar_t* pszPropertyName;\n        const wchar_t* pszPropertyValue;\n    };\n\n    /// \\internal\n    /// <summary>\n    /// Dispatches module setup and cleanup function names to their corresponding pointers\n    /// </summary>\n    struct TestGlobalFunctionInfo\n    {\n        typedef HRESULT (__cdecl *TestModuleInvokerFunction)();\n\n        TAEF_Identifier::Value identifier;\n        const wchar_t* pszFunctionName;\n        TestModuleInvokerFunction pInvoker;\n    };\n\n    /// \\internal\n    /// <summary>\n    /// Holds framework version info\n    /// </summary>\n    struct TestVersionInfo\n    {\n        typedef void (__cdecl *Deallocator)(_In_ _Post_invalid_ wchar_t* pStr);\n\n        // This still uses the legacy string identifier temporarily while 3.1 is still in active use.\n        const wchar_t* pszIdentifier;\n        const char* paszVersionMessage;\n        const char* paszVersion;\n        Deallocator pDeallocator;\n    };\n\n} // end of namespace declaration\n\n#pragma section(\"testdata$a_TDH\", read)\n#pragma section(\"testdata$b_TCI\", read)\n#pragma section(\"testdata$c_TMI\", read)\n#pragma section(\"testdata$d_TGFI\", read)\n#pragma section(\"testdata$e_FMI\", read)\n#pragma section(\"testdata$f_MM\", read)\n#pragma section(\"testdata$g_TCM\", read)\n#pragma section(\"testdata$h_TMM\", read)\n\n// The IntelliSense compiler reports errors when trying to parse 'TAEF_PIN_FUNCTION_SYMBOL', so it should be skipped.\n#if defined(__INTELLISENSE__)\n# define TAEF_PIN_FUNCTION_SYMBOL\n#else\n/// \\internal\n/// <summary> Instruct the compiler not to remove the function from the obj file during the optimization phase </summary>\n# define TAEF_PIN_FUNCTION_SYMBOL                 __pragma (comment(linker, \"/include:\" __FUNCDNAME__))\n#endif\n\n/// \\internal\n/// <summary> Instruct oacr to ignore \"static initializer causes copy on write pages due to member function pointers\" warning\n///           Disables 'construction of local static object is not thread-safe'\n/// </summary>\n#define TAEF_PUSH_IGNORE_WARNINGS                __pragma (warning(push)) \\\n                                                 __pragma (warning(disable:28651)) \\\n                                                 __pragma (warning(disable:4640)) \\\n                                                 __pragma (warning(disable:4407))\n\n#if defined(__INTELLISENSE__)\n// The IntelliSense compiler reports errors when trying to parse TAEF_REGISTER_FIXTURE_METHOD and TAEF_REGISTER_TEST_METHOD.\n#define TAEF_REGISTER_FIXTURE_METHOD(methodName, methodType)\n#define TAEF_REGISTER_TEST_METHOD(methodName)\n#else\n#define TAEF_REGISTER_FIXTURE_METHOD(methodName, methodType) \\\n    struct TAEF_FixtureInvoker \\\n    { \\\n        static HRESULT __cdecl TAEF_Invoke(void* pTestClass) \\\n        { \\\n            /* TAEF_TestClassType was typedef'd in the TEST_CLASS macro so we can safely cast from \\\n               void* to TAEF_TestClassType* and invoke the correct derived type's member functions */ \\\n            return WEX::SafeInvoke(WEX::FixtureInvokeFunctor<TAEF_TestClassType>(*reinterpret_cast<TAEF_TestClassType*>(pTestClass), &methodName)); \\\n        } \\\n    }; \\\n    TAEF_PUSH_IGNORE_WARNINGS \\\n    TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$e_FMI\")) \\\n    static const WEX::FixtureMethodInfo s_testInfo = {methodType, L#methodName, TAEF__WFUNCTION__, &TAEF_FixtureInvoker::TAEF_Invoke}; \\\n    return &s_testInfo; /* Return a pointer to s_testInfo in order to pin the struct into the dll so it does not get stripped out by the linker. */\n\n#define TAEF_REGISTER_TEST_METHOD(methodName) \\\n    struct TAEF_TestInvoker \\\n    { \\\n        static HRESULT __cdecl TAEF_Invoke(void* pTestClass) \\\n        { \\\n            /* TAEF_TestClassType was typedef'd in the TEST_CLASS macro so we can safely cast from \\\n               void* to TAEF_TestClassType* and invoke the correct type's member functions */ \\\n            return WEX::SafeInvoke(WEX::TestInvokeFunctor<TAEF_TestClassType>(*reinterpret_cast<TAEF_TestClassType*>(pTestClass), &methodName)); \\\n        } \\\n    }; \\\n    TAEF_PUSH_IGNORE_WARNINGS \\\n    TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$c_TMI\")) \\\n    static const WEX::TestMethodInfo s_testInfo = {WEX::TAEF_Identifier::TestMethodInfo, L#methodName, TAEF__WFUNCTION__, \\\n                                                   __COUNTER__ - TAEF_TestMethodIndexOffset, &TAEF_TestInvoker::TAEF_Invoke}; \\\n    return &s_testInfo; /* Return a pointer to s_testInfo in order to pin the struct into the dll so it does not get stripped out by the linker. */\n#endif\n\n// This macro is used directly by some non-TAEF teams. Do not remove it unless those cases are fixed.\n#define TAEF_TEST_METHOD(methodName) \\\n    static const __declspec(dllexport) WEX::TestMethodInfo* methodName##_TAEF_PinTestMethodInfo() \\\n    { \\\n        TAEF_REGISTER_TEST_METHOD(methodName) \\\n    } \\\n    __pragma(warning(suppress:25007)) /* Disable warning that member method may be static */ \\\n    void methodName()\n/// <summary>\n/// Macro for declaring a test method without associating it with any metadata\n/// </summary>\n/// Example:\n/// \\code\n///    class TestFeatureClass\n///    {\n///         TEST_METHOD(FeatureTestMethod1);\n///    }\n/// \\endcode\n#define TEST_METHOD(methodName) \\\n    TAEF_TEST_METHOD(methodName) TAEF_TERMINATOR\n\n#define TAEF_TEST_METHOD_METADATA_START \\\n    TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$h_TMM\")) \\\n    static WEX::TestPropertyMetadata s_Metadata[] = { {WEX::TAEF_Identifier::TestMethodMetadata, L\"Name\", TAEF__WFUNCTION__}, \\\n\n#define TAEF_TEST_METHOD_METADATA_END \\\n                                                      {WEX::TAEF_Identifier::TestMethodMetadata, nullptr, nullptr}}; \\\n            return s_Metadata; \\\n        } \\\n\n/// <summary>\n///  Macro for declaring a test method and associating it with metadata\n/// </summary>\n///  Example:\n/// \\code\n///      class TestFeatureClass\n///      {\n///          BEGIN_TEST_METHOD(TestFindNext)\n///              TEST_METHOD_PROPERTY(L\"Priority\", L\"2\")\n///          END_TEST_METHOD()\n///      }\n/// \\endcode\n#define BEGIN_TEST_METHOD(methodName) \\\n    TEST_METHOD(methodName); \\\n \\\n    static const __declspec(dllexport) WEX::TestPropertyMetadata* methodName ## _GetTestMethodMetadata() \\\n    { \\\n        TAEF_TEST_METHOD_METADATA_START \\\n\n/// <summary>\n///  Macro that ends test method declaration.\n///  Must be used with BEGIN_TEST_METHOD()\n/// </summary>\n#define END_TEST_METHOD() \\\n            TAEF_TEST_METHOD_METADATA_END \\\n\n#ifdef INLINE_TEST_METHOD_MARKUP\n/// <summary>\n///  Macro for declaring metadata within inline test methods.\n/// </summary>\n///  Example:\n/// \\code\n///      class TestFeatureClass\n///      {\n///          TEST_METHOD(TestFindNext)\n///          {\n///              BEGIN_TEST_METHOD_PROPERTIES()\n///                  TEST_METHOD_PROPERTY(L\"Priority\", L\"2\")\n///              END_TEST_METHOD_PROPERTIES()\n///\n///              // Your test code\n///          }\n///      }\n/// \\endcode\n#define BEGIN_TEST_METHOD_PROPERTIES() \\\n    struct TAEF_TestMethodProperties \\\n    { \\\n        static const __declspec(dllexport) WEX::TestPropertyMetadata* TAEF_GetTestMethodMetadata() \\\n        { \\\n            TAEF_TEST_METHOD_METADATA_START \\\n\n/// <summary>\n///  Macro that ends inline test method property declaration.\n///  Must be used with BEGIN_TEST_METHOD_PROPERTIES()\n/// </summary>\n#define END_TEST_METHOD_PROPERTIES() \\\n            TAEF_TEST_METHOD_METADATA_END \\\n    };\n#endif // INLINE_TEST_METHOD_MARKUP\n\n/// <summary>\n///  Macro for adding a piece of metadata to a test method.\n///  Must be used with BEGIN_TEST_METHOD() / END_TEST_METHOD() or within BEGIN_TEST_METHOD_PROPERTIES() / END_TEST_METHOD_PROPERTIES()\n/// </summary>\n#define TEST_METHOD_PROPERTY(propertyName, propertyValue) \\\n                    {WEX::TAEF_Identifier::TestMethodMetadata, propertyName, propertyValue},\n\n/// <summary>\n///  Macro for defining module properties\n/// </summary>\n///  Example:\n/// \\code\n///      BEGIN_MODULE()\n///          MODULE_PROPERTY(L\"Area\", L\"Desktop Shell\")\n///          MODULE_PROPERTY(L\"SubArea\", L\"Navigation\")\n///          MODULE_PROPERTY(L\"Component\", L\"Start Menu\")\n///      END_MODULE()\n/// \\endcode\n#define BEGIN_MODULE() \\\n    const __declspec(dllexport) WEX::TestPropertyMetadata* TAEF_GetModuleMetadata() \\\n    { \\\n        TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$f_MM\")) \\\n        static const WEX::TestPropertyMetadata s_Metadata[] = { \\\n            {WEX::TAEF_Identifier::ModuleMetadata,  L\"Name\", L\"___##TestFile##___\"},\n\n/// <summary>\n///  Macro for adding a piece of metadata (a property) to a test module propeties definition.\n///  Must be used with BEGIN_MODULE() / END_MODULE()\n/// </summary>\n#define MODULE_PROPERTY(propertyName, propertyValue) \\\n            {WEX::TAEF_Identifier::ModuleMetadata,  propertyName,  propertyValue},\n\n/// <summary>\n///  Macro that ends test module properties definition.\n///  Must be used with BEGIN_MODULE()\n/// </summary>\n#define END_MODULE() \\\n            {WEX::TAEF_Identifier::ModuleMetadata,  nullptr,  nullptr} \\\n        }; \\\n        return s_Metadata; \\\n    }\n\n/// <summary>\n///  Macro for declaring a test class without associating it with any metadata\n/// </summary>\n///  Example:\n/// \\code\n///      class TestFeatureClass\n///      {\n///          TEST_CLASS(TestFeatureClass)\n///      }\n/// \\endcode\n#define TEST_CLASS(className) \\\n    typedef className TAEF_TestClassType; \\\n    static const uintptr_t TAEF_TestMethodIndexOffset = __COUNTER__; \\\n    friend struct WEX::TestClassFactory<className>; \\\n    typedef bool (className::*TAEF_MemberMaintFunc)(); \\\n    __pragma(warning(suppress:25007)) /* Disable warning that member method may be static */ \\\n    bool TAEF_DummyMaintFunc() { return true; } \\\n    static const __declspec(dllexport) WEX::TestClassInfo* TAEF_GetTestClassInfo() \\\n    { \\\n        /* this works similarly to WEX::Common::Conversion<T, U> checking if an expression (&_DummyMaintFunc) \\\n         * is convertible to the MemberMaintFunc type \\\n         */ \\\n        struct TaefClassNameTester { \\\n            /* these functions are only implemented because they're in an local class, so the compiler warns about missing definitions */ \\\n            static char TestType(TAEF_MemberMaintFunc) \\\n            { \\\n                return 'c'; \\\n            } \\\n            static TaefClassNameTester TestType(...) \\\n            { \\\n                return TaefClassNameTester(); \\\n            } \\\n            char member[2]; /* a two element array to ensure a different size from char returned by TestType(MemberMaintFunc) */ \\\n        }; \\\n        COMPILE_TIME_CHECK_V2(sizeof(TaefClassNameTester::TestType(&TAEF_DummyMaintFunc)) == 1, \\\n                TAEF_STRINGIZE(className) ## \" is not the name of the current class\", \\\n                Not_current_test_class_name); \\\n \\\n        TAEF_PUSH_IGNORE_WARNINGS \\\n        TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$b_TCI\")) \\\n        static WEX::TestClassInfo const s_ClassInfo = \\\n            {WEX::TAEF_Identifier::TestClassInfo, TAEF__WFUNCTION__, &WEX::TestClassFactory<className>::CreateInstance, \\\n             &WEX::TestClassFactory<className>::DestroyInstance }; \\\n        return &s_ClassInfo; \\\n    }\n\n/// <summary>\n///  Macro for declaring a test class and associating it with metadata\n/// </summary>\n///  Example:\n/// \\code\n///  class FeatureTestClass\n///  {\n///      BEGIN_TEST_CLASS(FeatureTestClass)\n///          TEST_CLASS_PROPERTY(L\"BVT\", L\"TRUE\")\n///          TEST_CLASS_PROPERTY(L\"STRESS\", L\"TRUE\")\n///      END_TEST_CLASS()\n///  }\n/// \\endcode\n#define BEGIN_TEST_CLASS(className) \\\n    TEST_CLASS(className) \\\n \\\n    static const __declspec(dllexport) WEX::TestPropertyMetadata* TAEF_GetClassMetadata() \\\n    { \\\n        TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$g_TCM\")) \\\n        static const WEX::TestPropertyMetadata s_Metadata[] = { \\\n            {WEX::TAEF_Identifier::TestClassMetadata, L\"Name\", TAEF__WFUNCTION__ },\n\n/// <summary>\n///  Macro for adding a piece of metadata to a test class declaration.\n///  Must be used with BEGIN_TEST_CLASS() / END_TEST_CLASS()\n/// </summary>\n#define TEST_CLASS_PROPERTY(propertyName, propertyValue) \\\n            {WEX::TAEF_Identifier::TestClassMetadata, propertyName, propertyValue },\n\n/// <summary>\n///  Macro that ends test class declaration.\n///  Must be used with BEGIN_TEST_CLASS()\n/// </summary>\n#define END_TEST_CLASS() \\\n            {WEX::TAEF_Identifier::TestClassMetadata, nullptr, nullptr} \\\n        }; \\\n        return s_Metadata; \\\n    }\n\n#define TAEF_MODULE_FIXTURE_INFO_IMPL(methodName, moduleFixtureType) \\\n    struct TAEF_ModuleFixtureInvoker \\\n    { \\\n        static HRESULT __cdecl TAEF_Invoke() \\\n        { \\\n            return WEX::SafeInvoke(methodName); \\\n        } \\\n    }; \\\n \\\n    TAEF_PUSH_IGNORE_WARNINGS \\\n    TAEF_PIN_FUNCTION_SYMBOL __declspec(allocate(\"testdata$d_TGFI\")) \\\n    static const WEX::TestGlobalFunctionInfo s_moduleFixtureInfo = \\\n        {moduleFixtureType, L#methodName, &TAEF_ModuleFixtureInvoker::TAEF_Invoke }; \\\n    return &s_moduleFixtureInfo;\n\n#define TAEF_FIXTURE_IMPL(methodName) \\\n    __pragma(warning(suppress:25007)) /* Disable warning that member method may be static */ \\\n    bool methodName()\n\n#ifdef INLINE_TEST_METHOD_MARKUP\n#define TAEF_DEFINE_FIXTURE(methodName) \\\n    TAEF_FIXTURE_IMPL(methodName)\n#else\n#define TAEF_DEFINE_FIXTURE(methodName)\n#endif\n\n#ifdef INLINE_TEST_METHOD_MARKUP\n#define TAEF_DECLARE_FIXTURE(methodName)\n#else\n#define TAEF_DECLARE_FIXTURE(methodName) \\\n    __if_not_exists(methodName) \\\n    { \\\n        TAEF_FIXTURE_IMPL(methodName); \\\n    }\n#endif\n\n#define TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName) \\\n    TAEF_DECLARE_FIXTURE(methodName) \\\n    TAEF_DEFINE_FIXTURE(methodName)\n\n/// <summary>\n///  Macro for defining global Setup function\n/// </summary>\n///  The Setup function runs before any test is executed\n///  Example:\n/// \\code\n///\n///  MODULE_SETUP(AddRegistrySettings) //AddRegistrySettings function adds necessary reg settings for all tests\n///\n/// \\endcode\n#define MODULE_SETUP(methodName) \\\n    TAEF_FIXTURE_IMPL(methodName); \\\n    const __declspec(dllexport) WEX::TestGlobalFunctionInfo* YOU_CAN_ONLY_DESIGNATE_ONE_FUNCTION_TO_BE_A_MODULE_SETUP_FUNCTION() \\\n    { \\\n        TAEF_MODULE_FIXTURE_INFO_IMPL(methodName, WEX::TAEF_Identifier::ModuleSetup) \\\n    } \\\n    TAEF_DEFINE_FIXTURE(methodName)\n\n/// <summary>\n///  Macro for defining global Teardown function\n/// </summary>\n///  The Teardown function runs after all the test are executed\n///  Example:\n/// \\code\n///\n///  MODULE_CLEANUP(CleanupRegistrySettings) //CleanupRegistrySettings restores the registry after all tests\n///\n/// \\endcode\n#define MODULE_CLEANUP(methodName) \\\n    TAEF_FIXTURE_IMPL(methodName); \\\n    const __declspec(dllexport) WEX::TestGlobalFunctionInfo* YOU_CAN_ONLY_DESIGNATE_ONE_FUNCTION_TO_BE_A_MODULE_CLEANUP_FUNCTION() \\\n    { \\\n        TAEF_MODULE_FIXTURE_INFO_IMPL(methodName, WEX::TAEF_Identifier::ModuleCleanup) \\\n    } \\\n    TAEF_DEFINE_FIXTURE(methodName)\n\n/// <summary>\n///  Macro for test setup method declaration\n/// </summary>\n///  Test setup method gets called before every test method is called\n///  Example:\n/// \\code\n///      class NotepadTestClass\n///      {\n///          // Declare CopyDownTestFiles class method and designate this method to be a test setup method\n///          TEST_METHOD_SETUP(CopyDownTestFiles);\n///      }\n/// \\endcode\n#define TEST_METHOD_SETUP(methodName) \\\n    static const __declspec(dllexport) WEX::FixtureMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_METHOD_SETUP_METHOD() \\\n    { \\\n        TAEF_REGISTER_FIXTURE_METHOD(methodName, WEX::TAEF_Identifier::TestMethodSetup) \\\n    } \\\n    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)\n\n/// <summary>\n///  Macros for test cleanup method declaration\n/// </summary>\n///  Test cleanup method gets called after every test method is called\n///  Example:\n/// \\code\n///      class NotepadTestClass\n///      {\n///          // Declare DeleteCopiedTestFiles class method and designate this method to be a test cleanup method\n///          TEST_METHOD_CLEANUP(DeleteCopiedTestFiles);\n///      }\n/// \\endcode\n#define TEST_METHOD_CLEANUP(methodName) \\\n    static const __declspec(dllexport) WEX::FixtureMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_METHOD_CLEANUP_METHOD() \\\n    { \\\n        TAEF_REGISTER_FIXTURE_METHOD(methodName, WEX::TAEF_Identifier::TestMethodCleanup) \\\n    } \\\n    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)\n\n/// <summary>\n///  Macro for test class setup method declaration\n/// </summary>\n///  Class setup method gets called before the first method in the class is called (after the class constructor)\n///  Example:\n/// \\code\n///      class NotepadTestClass\n///      {\n///          // Declare InstallNotepad class method and designate this method to be a class setup method\n///          TEST_CLASS_CLEANUP(InstallNotepad);\n///      }\n/// \\endcode\n#define TEST_CLASS_SETUP(methodName) \\\n    static const __declspec(dllexport) WEX::FixtureMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_CLASS_SETUP_METHOD() \\\n    { \\\n        TAEF_REGISTER_FIXTURE_METHOD(methodName, WEX::TAEF_Identifier::TestClassSetup) \\\n    } \\\n    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)\n\n/// <summary>\n///  Macro for test class cleanup method declaration\n/// </summary>\n///  Class cleanup method gets called after the last method in the class is called (before the destructor)\n///  Example:\n/// \\code\n///      class NotepadTestClass\n///      {\n///          // Declare UninstallNotepad class method and designate this method to be a class cleanup method\n///          TEST_CLASS_CLEANUP(UninstallNotepad);\n///      }\n/// \\endcode\n#define TEST_CLASS_CLEANUP(methodName) \\\n    static const __declspec(dllexport) WEX::FixtureMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_CLASS_CLEANUP_METHOD() \\\n    { \\\n        TAEF_REGISTER_FIXTURE_METHOD(methodName, WEX::TAEF_Identifier::TestClassCleanup) \\\n    } \\\n    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)\n\n/// \\internal\n/// <summary>\n///  Current framework version information\n/// </summary>\nextern \"C\" __declspec(allocate(\"testdata$a_TDH\")) __declspec(selectany) WEX::TestVersionInfo s_versionInfo =\n    {L\"TestVersionInfo\", \"Copyright (c) Microsoft Corporation. All rights reserved.\",\n    \"Wex Test Framework. Version: 0.42.600\" TAEF_STRINGIZE(TAEF_ABI_VERSION) \".58\", WEX::Private::StringManager::Deallocate};\n\n#if defined(_M_IX86)\n#pragma comment(linker, \"/include:_s_versionInfo\")\n#else\n#pragma comment(linker, \"/include:s_versionInfo\")\n#endif\n\n#pragma pop_macro(\"Assert\")\n#pragma pop_macro(\"_Outptr_\")\n#pragma pop_macro(\"_Outptr_result_maybenull_z_\")\n#pragma pop_macro(\"_Ret_maybenull_z_\")\n#pragma pop_macro(\"_In_reads_z_\")\n#pragma pop_macro(\"_In_\")\n#pragma pop_macro(\"_Post_invalid_\")\n#pragma warning(pop)\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WexTypes.h",
    "content": "/*\n* Copyright (c) Microsoft Corporation.  All Rights Reserved.\n*\n* Provides typedefs for commonly used types, and template utilities and helpers for working with C++ types\n*          \n*/\n#pragma once\n\n#include <specstrings.h>\n\n#pragma push_macro(\"_Return_type_success_\")\n\n#if !defined(_Return_type_success_)\n#define _Return_type_success_(s)\n#endif\n\ntypedef _Return_type_success_(return >= 0) long HRESULT;\ntypedef int BOOL;\ntypedef long LONG;\ntypedef unsigned long DWORD;\ntypedef DWORD ULONG;\ntypedef void* HANDLE;\ntypedef unsigned long (__stdcall *LPHANDLER_FUNCTION_EX)(unsigned long control, unsigned long eventType, void* pEventData, void* pContext);\n\n#pragma pop_macro(\"_Return_type_success_\")\n\nnamespace WEX { namespace Common\n{\n    struct NullType{};\n    struct EmptyType{};\n    struct TerminatorType{};\n\n    template <class T, class U>\n    class Conversion\n    {\n        typedef char SmallSize;\n        struct BigSize \n        { \n            SmallSize a[2]; \n        };\n\n        static SmallSize Test(const U&);\n        static BigSize Test(...);\n        static const T& MakeT();\n\n    public:\n        static const bool exists = (sizeof(Test(MakeT()))) == (sizeof(SmallSize));\n        static const bool sameType = false;\n    };\n\n    template <>\n    class Conversion<void, void>\n    {\n    public:\n        static const bool exists = true;\n        static const bool sameType = true;\n    };\n\n    template <typename T1, typename T2>\n    class AreSameType\n    {\n    public:\n        static const bool value = false;\n    };\n\n    template <typename T>\n    class AreSameType<T, T>\n    {\n    public:\n        static const bool value = true;\n    };\n\n    template <typename T>\n    class MakeReference\n    {\n    public:\n        typedef T& Result;\n    };\n\n    template <typename T>\n    class MakeReference<T&>\n    {\n    public:\n        typedef T& Result;\n    };\n\n    template <>\n    class MakeReference<NullType>\n    {\n    public:\n        typedef NullType Result;\n    };\n\n    template <typename T>\n    class RemoveReference\n    {\n    public:\n        typedef T Result;\n    };\n\n    template <typename T>\n    class RemoveReference<T&>\n    {\n    public:\n        typedef T Result;\n    };\n\n    template<typename T>\n    struct MakeConst\n    {\n        typedef const T Type;\n    };\n\n    template<typename T>\n    struct MakeConst<T&>\n    {\n        typedef const T& Type;\n    };\n\n    template<typename T>\n    struct MakeConst<T*>\n    {\n        typedef const T* Type;\n    };\n\n    template<typename T>\n    struct RemoveConst\n    {\n        typedef T Type;\n    };\n\n    template<typename T>\n    struct RemoveConst<const T>\n    {\n        typedef T Type;\n    };\n\n    template<typename T>\n    struct RemoveConst<T&>\n    {\n        typedef T& Type;\n    };\n\n    template<typename T>\n    struct RemoveConst<const T&>\n    {\n        typedef T& Type;\n    };\n\n    template<typename T>\n    struct RemoveConst<T*>\n    {\n        typedef T* Type;\n    };\n\n    template<typename T>\n    struct RemoveConst<const T*>\n    {\n        typedef T* Type;\n    };\n\n    template<typename T>\n    class AlignedStorageFactory\n    {\n        template<size_t Size, size_t Align>\n        struct Storage;\n\n        template<size_t Size>\n        struct Storage<Size, 0>\n        {\n        protected:\n            __declspec(align(1)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 1>\n        {\n        protected:\n            __declspec(align(1)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 2>\n        {\n        protected:\n            __declspec(align(2)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 4>\n        {\n        protected:\n            __declspec(align(4)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 8>\n        {\n        protected:\n            __declspec(align(8)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 16>\n        {\n        protected:\n            __declspec(align(16)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 32>\n        {\n        protected:\n            __declspec(align(32)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 64>\n        {\n        protected:\n            __declspec(align(64)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 128>\n        {\n        protected:\n            __declspec(align(128)) unsigned char m_raw[Size];\n        };\n\n        template<size_t Size>\n        struct Storage<Size, 256>\n        {\n        protected:\n            __declspec(align(256)) unsigned char m_raw[Size];\n        };\n\n        // not implemented\n        AlignedStorageFactory();\n\n    public:\n        typedef Storage<sizeof(T), __alignof(T)> Type;\n    };\n} /* namespace Common */ } /* namespace WEX */\n"
  },
  {
    "path": "Tests/UnitTests/Support/TAEF/inc/WppDefs.h",
    "content": "//---------------------------------------------------------------------------\n// Microsoft Test Automation Sources\n//\n// Copyright 2005 Microsoft Corporation. All Rights Reserved.\n//\n// WppDefs.h\n//\n// Collection: WDTF\n// \n// Environment: User mode\n//\n// Primary Contact: WDTF Support (WDTFSupp@microsoft.com)\n//\n// History:\n//   [Date]        -   [Status]\n//   Jul 11 2005   -   Reviewed\n//---------------------------------------------------------------------------\n#pragma once\n\n\n//\n// Helpful Macros\n//\n#ifndef WIDEN2\n#define WIDEN2(x) L ## x\n#define WIDEN(x) WIDEN2(x)\n#endif\n\n\n#define WDTF_Guid        (6210f559,c7f7,4d2f,b674,4bc9315cecc7)\n\n#define WPP_CONTROL_GUIDS \\\n    WPP_DEFINE_CONTROL_GUID(WDTF, WDTF_Guid, \\\n        WPP_DEFINE_BIT(WDTFCOMEntryExit) \\\n        WPP_DEFINE_BIT(WDTFCOMError) \\\n        WPP_DEFINE_BIT(WDTFEntryExit) \\\n        WPP_DEFINE_BIT(WDTFAPICall) \\\n        WPP_DEFINE_BIT(WDTFInfo) \\\n        WPP_DEFINE_BIT(WDTFWarning) \\\n        WPP_DEFINE_BIT(WDTFError) \\\n        \\\n        WPP_DEFINE_BIT(WDTFNoisyCOMEntryExit) \\\n        WPP_DEFINE_BIT(WDTFNoisyEntryExit) \\\n        WPP_DEFINE_BIT(WDTFNoisyAPICall) \\\n        WPP_DEFINE_BIT(WDTFNoisyInfo) \\\n        WPP_DEFINE_BIT(WDTFNoisyWarning))\n\n\n\n// Define an enum of shift values for bitmasks\n#define WPP_DEFINE_CONTROL_GUID(name,guid,bits) bits\n#define WPP_DEFINE_BIT(Bit) Bit##__shift,\nenum __TracingBitShifts\n{\n    WPP_CONTROL_GUIDS\n};\n#undef WPP_DEFINE_BIT\n#undef WPP_DEFINE_CONTROL_GUID\n\n\n\n// Define an enum of bitmasks corresponding to WPP bits\n#define WPP_DEFINE_CONTROL_GUID(name,guid,bits) bits\n#define WPP_DEFINE_BIT(Bit) Bit##_Bit = 1 << Bit##__shift,\nenum __TracingBits\n{\n    WPP_CONTROL_GUIDS\n};\n#undef WPP_DEFINE_BIT\n#undef WPP_DEFINE_CONTROL_GUID\n\n\n#define IS_LEVEL_ENABLED(LEVEL) \\\n    ((__pCtx->pTracingSettings->IsEnabled(LEVEL##_Bit)) && WPP_LEVEL_ENABLED(LEVEL))\n\n\n#define INDENT_STR(indent) \\\n    (__indentSpacer + ((sizeof(__indentSpacer) >= -3+(indent)*5) ? (sizeof(__indentSpacer)+3-(indent)*5) : 0))\n\n\n\n// begin_wpp config \n// CUSTOM_TYPE(SYSTEM_POWER_STATE, ItemEnum(_SYSTEM_POWER_STATE) );\n// end_wpp\n\n\n\n//MACRO: TraceError\n//\n//begin_wpp config\n//USEPREFIX (TraceError, \"%!STDPREFIX!%sERROR:\", INDENT_STR(__pCtx->CallDepth+1));\n//FUNC TraceError{TRACEERRORLEVEL=Error}(COMPNAME, MSG, ...);\n//WPP_FLAGS(-public:TraceError);\n//end_wpp\n#define WPP_TRACEERRORLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_TRACEERRORLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: TraceAPI\n//\n//begin_wpp config\n//USEPREFIX (TraceAPI, \"%!STDPREFIX!%sAPI:\", INDENT_STR(__pCtx->CallDepth+1));\n//FUNC TraceAPI{TRACEAPILEVEL=APICall}(COMPNAME, MSG, ...);\n//WPP_FLAGS(-public:TraceAPI);\n//end_wpp\n#define WPP_TRACEAPILEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_TRACEAPILEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: TraceInfo\n//\n//begin_wpp config\n//USEPREFIX (TraceInfo, \"%!STDPREFIX!%sINFO:\", INDENT_STR(__pCtx->CallDepth+1));\n//FUNC TraceInfo{TRACEINFOLEVEL=Info}(COMPNAME, MSG, ...);\n//WPP_FLAGS(-public:TraceInfo);\n//end_wpp\n#define WPP_TRACEINFOLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_TRACEINFOLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: TraceWarning\n//\n//begin_wpp config\n//USEPREFIX (TraceWarning, \"%!STDPREFIX!%sWARN:\", INDENT_STR(__pCtx->CallDepth+1));\n//FUNC TraceWarning{TRACEWARNLEVEL=Warning}(COMPNAME, MSG, ...);\n//WPP_FLAGS(-public:TraceWarning);\n//end_wpp\n#define WPP_TRACEWARNLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_TRACEWARNLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: TraceCOMEntry\n//\n//begin_wpp config\n//USEPREFIX (TraceCOMEntry, \"%!STDPREFIX!%so->this(%p):%!FUNC!(\", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC TraceCOMEntry{COMENTRYLEVEL=COMEntryExit}(COMPNAME, MSG, ...);\n//USESUFFIX (TraceCOMEntry, \")\");\n//WPP_FLAGS(-public:TraceCOMEntry);\n//end_wpp\n#define WPP_COMENTRYLEVEL_COMPNAME_PRE(LEVEL, comp) OVERRIDE_TRACING_SETTINGS(&m_TracingSettings);\n#define WPP_COMENTRYLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMENTRYLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: COMReturn\n//\n//begin_wpp config\n//USEPREFIX (COMReturn, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %!HRESULT!\", INDENT_STR(__pCtx->CallDepth), this, __hResult);\n//FUNC COMReturn{COMRETURNLEVEL=COMEntryExit}(COMPNAME, HR);\n//WPP_FLAGS(-public:COMReturn);\n//end_wpp\n//#define WPP_COMRETURNLEVEL_PRE(LEVEL)\n#define WPP_COMRETURNLEVEL_COMPNAME_HR_ENABLED(LEVEL, comp, HR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMRETURNLEVEL_COMPNAME_HR_LOGGER(LEVEL, comp, HR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_COMRETURNLEVEL_COMPNAME_HR_PRE(LEVEL, comp, HR) { \\\n                                                                HRESULT __hResult = HR;\n#define WPP_COMRETURNLEVEL_COMPNAME_HR_POST(LEVEL, comp, HR)    /*TraceMessage()*/; \\\n                                                                return __hResult; \\\n                                                            }\n\n//MACRO: COMReturnProperty\n//\n//begin_wpp config\n//USEPREFIX (COMReturnProperty, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %!HRESULT!, \", INDENT_STR(__pCtx->CallDepth), this, __hResult);\n//FUNC COMReturnProperty{COMRETURNLEVEL=COMEntryExit}(COMPNAME, HR, MSG, ...);\n//WPP_FLAGS(-public:COMReturnProperty);\n//end_wpp\n//#define WPP_COMRETURNLEVEL_PRE(LEVEL)\n#define WPP_COMRETURNPROPERTYLEVEL_COMPNAME_HR_ENABLED(LEVEL, comp, HR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMRETURNPROPERTYLEVEL_COMPNAME_HR_LOGGER(LEVEL, comp, HR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_COMRETURNPROPERTYLEVEL_COMPNAME_HR_PRE(LEVEL, comp, HR) { \\\n                                                                        HRESULT __hResult = HR;\n#define WPP_COMRETURNPROPERTYLEVEL_COMPNAME_HR_POST(LEVEL, comp, HR)    /*TraceMessage()*/; \\\n                                                                        return __hResult; \\\n                                                                    }\n\n\n\n\n//MACRO: TraceMethodEntry\n//\n//begin_wpp config\n//USEPREFIX (TraceMethodEntry, \"%!STDPREFIX!%s-->this(%p):%!FUNC!(\", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC TraceMethodEntry{METHODENTRYLEVEL=EntryExit}(COMPNAME, MSG, ...);\n//USESUFFIX (TraceMethodEntry, \")\");\n//WPP_FLAGS(-public:TraceMethodEntry);\n//end_wpp\n#define WPP_METHODENTRYLEVEL_COMPNAME_PRE(LEVEL, comp) OVERRIDE_TRACING_SETTINGS(&m_TracingSettings);\n#define WPP_METHODENTRYLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_METHODENTRYLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: TraceMethodEntryNoOverride\n//\n//begin_wpp config\n//USEPREFIX (TraceMethodEntryNoOverride, \"%!STDPREFIX!%s-->this(%p):%!FUNC!(\", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC TraceMethodEntryNoOverride{METHODENTRYNOOVERRIDELEVEL=EntryExit}(COMPNAME, MSG, ...);\n//USESUFFIX (TraceMethodEntryNoOverride, \")\");\n//WPP_FLAGS(-public:TraceMethodEntryNoOverride);\n//end_wpp\n#define WPP_METHODENTRYNOOVERRIDELEVEL_COMPNAME_PRE(LEVEL, comp) USE_DEFAULT_TRACING_SETTINGS;\n#define WPP_METHODENTRYNOOVERRIDELEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_METHODENTRYNOOVERRIDELEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: MethodReturn\n//\n//begin_wpp config\n//USEPREFIX (MethodReturn, \"%!STDPREFIX!%s<--this(%p):%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC MethodReturn{RETURNLEVEL=EntryExit}(COMPNAME, RES, MSG, ...);\n//WPP_FLAGS(-public:MethodReturn);\n//end_wpp\n#define WPP_RETURNLEVEL_COMPNAME_RES_ENABLED(LEVEL, comp, RES) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_RETURNLEVEL_COMPNAME_RES_LOGGER(LEVEL, comp, RES) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_RETURNLEVEL_COMPNAME_RES_POST(LEVEL, comp, RES) ;return RES;\n\n\n//MACRO: MethodReturnHRESULT\n//\n//begin_wpp config\n//USEPREFIX (MethodReturnHRESULT, \"%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!HRESULT!\", INDENT_STR(__pCtx->CallDepth), this, __hResult);\n//FUNC MethodReturnHRESULT{METHODRETURNHRESULTLEVEL=EntryExit}(COMPNAME, HR);\n//WPP_FLAGS(-public:MethodReturnHRESULT);\n//end_wpp\n//#define WPP_COMRETURNLEVEL_PRE(LEVEL)\n#define WPP_METHODRETURNHRESULTLEVEL_COMPNAME_HR_ENABLED(LEVEL, comp, HR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_METHODRETURNHRESULTLEVEL_COMPNAME_HR_LOGGER(LEVEL, comp, HR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_METHODRETURNHRESULTLEVEL_COMPNAME_HR_PRE(LEVEL, comp, HR) { \\\n                                                                          HRESULT __hResult = HR;\n#define WPP_METHODRETURNHRESULTLEVEL_COMPNAME_HR_POST(LEVEL, comp, HR)    /*TraceMessage()*/; \\\n                                                                          return __hResult; \\\n                                                                      }\n\n\n//MACRO: MethodReturnVoid\n//\n//begin_wpp config\n//USEPREFIX (MethodReturnVoid, \"%!STDPREFIX!%s<--this(%p):%!FUNC!()\", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC MethodReturnVoid{RETURNVOIDLEVEL=EntryExit}(COMPNAME, ...);\n//WPP_FLAGS(-public:MethodReturnVoid);\n//end_wpp\n#define WPP_RETURNVOIDLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_RETURNVOIDLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_RETURNVOIDLEVEL_COMPNAME_POST(LEVEL, comp) ;return;\n\n\n\n//MACRO: MethodReturnBool\n//\n//begin_wpp config\n//USEPREFIX (MethodReturnBool, \"%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!bool!\", INDENT_STR(__pCtx->CallDepth), this, __boolRetVal);\n//FUNC MethodReturnBool{RETURNVOIDLEVEL=EntryExit}(COMPNAME, BOOLRETVAL);\n//WPP_FLAGS(-public:MethodReturnBool);\n//end_wpp\n#define WPP_RETURNVOIDLEVEL_COMPNAME_BOOLRETVAL_ENABLED(LEVEL, comp, boolretval) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_RETURNVOIDLEVEL_COMPNAME_BOOLRETVAL_LOGGER(LEVEL, comp, boolretval) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_RETURNVOIDLEVEL_COMPNAME_BOOLRETVAL_PRE(LEVEL, comp, boolretval)    { \\\n                                                                                    bool __boolRetVal = (boolretval ? true : false);\n#define WPP_RETURNVOIDLEVEL_COMPNAME_BOOLRETVAL_POST(LEVEL, comp, boolretval)       /*TraceMessage()*/; \\\n                                                                                    return __boolRetVal; \\\n                                                                                }\n\n\n\n//MACRO: MethodReturnPtr\n//\n//begin_wpp config\n//USEPREFIX (MethodReturnPtr, \"%!STDPREFIX!%s<--this(%p):%!FUNC!(): %p\", INDENT_STR(__pCtx->CallDepth), this, __ptrRetVal);\n//FUNC MethodReturnPtr{RETURNPTRLEVEL=EntryExit}(COMPNAME, PTRTYPE, PTRRETVAL);\n//WPP_FLAGS(-public:MethodReturnPtr);\n//end_wpp\n#define WPP_RETURNPTRLEVEL_COMPNAME_PTRTYPE_PTRRETVAL_ENABLED(LEVEL, comp, PtrType,  ptrretval) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_RETURNPTRLEVEL_COMPNAME_PTRTYPE_PTRRETVAL_LOGGER(LEVEL, comp, PtrType, ptrretval) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_RETURNPTRLEVEL_COMPNAME_PTRTYPE_PTRRETVAL_PRE(LEVEL, comp, PtrType, ptrretval)  { \\\n                                                                                                PtrType __ptrRetVal = ptrretval;\n#define WPP_RETURNPTRLEVEL_COMPNAME_PTRTYPE_PTRRETVAL_POST(LEVEL, comp, PtrType, ptrretval)     /*TraceMessage()*/; \\\n                                                                                                return __ptrRetVal; \\\n                                                                                            }\n\n\n//MACRO: MethodReturnVariant\n//\n//begin_wpp config\n//USEPREFIX (MethodReturnVariant, \"%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!VARIANT!\", INDENT_STR(__pCtx->CallDepth), this, __vtRetVal);\n//FUNC MethodReturnVariant{RETURNVARIANTLEVEL=EntryExit}(COMPNAME, VARIANTRETVAL);\n//WPP_FLAGS(-public:MethodReturnVariant);\n//end_wpp\n#define WPP_RETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_ENABLED(LEVEL, comp, variantretval) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_RETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_LOGGER(LEVEL, comp, variantretval) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_RETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_PRE(LEVEL, comp, variantretval)   { \\\n                                                                                            VARIANT __vtRetVal = variantretval;\n#define WPP_RETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_POST(LEVEL, comp, variantretval)      /*TraceMessage()*/; \\\n                                                                                            return __vtRetVal; \\\n                                                                                        }\n\n//MACRO: MethodReturnIfNull\n//\n//begin_wpp config\n//USEPREFIX (MethodReturnIfNull, \"%!STDPREFIX!%s<-this(%p):%!FUNC!(): E_POINTER %s=NULL, bailing out!\", INDENT_STR(__pCtx->CallDepth), this, #PTR);\n//FUNC MethodReturnIfNull{METHOD_POINTER_LEVEL=EntryExit}(COMPNAME, PTR);\n//WPP_FLAGS(-public:MethodReturnIfNull);\n//end_wpp\n#define WPP_METHOD_POINTER_LEVEL_COMPNAME_PTR_ENABLED(LEVEL, comp, PTR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_METHOD_POINTER_LEVEL_COMPNAME_PTR_LOGGER(LEVEL, comp, PTR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_METHOD_POINTER_LEVEL_COMPNAME_PTR_PRE(LEVEL, comp, PTR)  if ((PTR) == NULL) \\\n                                                                     {\n#define WPP_METHOD_POINTER_LEVEL_COMPNAME_PTR_POST(LEVEL, comp, PTR)     /*TraceMessage()*/; \\\n                                                                         return E_POINTER; \\\n                                                                     }\n\n//MACRO: TraceFunctionEntry\n//\n//begin_wpp config\n//USEPREFIX (TraceFunctionEntry, \"%!STDPREFIX!%s-->%!FUNC!(\", INDENT_STR(__pCtx->CallDepth));\n//FUNC TraceFunctionEntry{FUNCENTRYLEVEL=EntryExit}(COMPNAME, MSG, ...);\n//USESUFFIX (TraceFunctionEntry, \")\");\n//WPP_FLAGS(-public:TraceFunctionEntry);\n//end_wpp\n#define WPP_FUNCENTRYLEVEL_COMPNAME_PRE(LEVEL, comp) USE_DEFAULT_TRACING_SETTINGS;\n#define WPP_FUNCENTRYLEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_FUNCENTRYLEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n\n//MACRO: FunctionReturn\n//\n//begin_wpp config\n//USEPREFIX (FunctionReturn, \"%!STDPREFIX!%s<--%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth));\n//FUNC FunctionReturn{FUNCRETURNLEVEL=EntryExit}(COMPNAME, RES, MSG, ...);\n//WPP_FLAGS(-public:FunctionReturn);\n//end_wpp\n#define WPP_FUNCRETURNLEVEL_COMPNAME_RES_ENABLED(LEVEL, comp, RES) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_FUNCRETURNLEVEL_COMPNAME_RES_LOGGER(LEVEL, comp, RES) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_FUNCRETURNLEVEL_COMPNAME_RES_POST(LEVEL, comp, RES) ;return RES;\n\n\n\n//MACRO: FunctionReturnVoid\n//\n//begin_wpp config\n//USEPREFIX (FunctionReturnVoid, \"%!STDPREFIX!%s<--%!FUNC!()\", INDENT_STR(__pCtx->CallDepth));\n//FUNC FunctionReturnVoid{FUNCRETURNLEVELVOID=EntryExit}(COMPNAME, ...);\n//WPP_FLAGS(-public:FunctionReturnVoid);\n//end_wpp\n#define WPP_FUNCRETURNLEVELVOID_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_FUNCRETURNLEVELVOID_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_FUNCRETURNLEVELVOID_COMPNAME_POST(LEVEL, comp) ;return;\n\n\n\n//MACRO: FunctionReturnBool\n//\n//begin_wpp config\n//USEPREFIX (FunctionReturnBool, \"%!STDPREFIX!%s<--%!FUNC!(): %!bool!\", INDENT_STR(__pCtx->CallDepth), __boolretval);\n//FUNC FunctionReturnBool{FUNCRETURNLEVELBOOL=EntryExit}(COMPNAME, BOOLRETVAL);\n//WPP_FLAGS(-public:FunctionReturnBool);\n//end_wpp\n#define WPP_FUNCRETURNLEVELBOOL_COMPNAME_BOOLRETVAL_ENABLED(LEVEL, comp, boolretval) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_FUNCRETURNLEVELBOOL_COMPNAME_BOOLRETVAL_LOGGER(LEVEL, comp, boolretval) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_FUNCRETURNLEVELBOOL_COMPNAME_BOOLRETVAL_PRE(LEVEL, comp, boolretval)    { \\\n                                                                                        bool __boolretval = (boolretval ? true : false);\n#define WPP_FUNCRETURNLEVELBOOL_COMPNAME_BOOLRETVAL_POST(LEVEL, comp, boolretval)       /*TraceMessage()*/; \\\n                                                                                        return __boolretval; \\\n                                                                                    }\n\n\n\n//MACRO: FunctionReturnPtr\n//\n//begin_wpp config\n//USEPREFIX (FunctionReturnPtr, \"%!STDPREFIX!%s<--%!FUNC!(): %p\", INDENT_STR(__pCtx->CallDepth), __ptrRetVal);\n//FUNC FunctionReturnPtr{FUNCRETURNLEVELPTR=EntryExit}(COMPNAME, PTRTYPE, PTRRETVAL);\n//WPP_FLAGS(-public:FunctionReturnPtr);\n//end_wpp\n#define WPP_FUNCRETURNLEVELPTR_COMPNAME_PTRTYPE_PTRRETVAL_ENABLED(LEVEL, comp, PtrType, ptrretval) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_FUNCRETURNLEVELPTR_COMPNAME_PTRTYPE_PTRRETVAL_LOGGER(LEVEL, comp, PtrType, ptrretval) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_FUNCRETURNLEVELPTR_COMPNAME_PTRTYPE_PTRRETVAL_PRE(LEVEL, comp, PtrType, ptrretval)  { \\\n                                                                                                    PtrType __ptrRetVal = ptrretval;\n#define WPP_FUNCRETURNLEVELPTR_COMPNAME_PTRTYPE_PTRRETVAL_POST(LEVEL, comp, PtrType, ptrretval)     /*TraceMessage()*/; \\\n                                                                                                    return __ptrRetVal; \\\n                                                                                                }\n\n\n//MACRO: FunctionReturnVariant\n//\n//begin_wpp config\n//USEPREFIX (FunctionReturnVariant, \"%!STDPREFIX!%s<--%!FUNC!(): %!VARIANT!\", INDENT_STR(__pCtx->CallDepth), __vtRetVal);\n//FUNC FunctionReturnVariant{FUNCRETURNVARIANTLEVEL=EntryExit}(COMPNAME, VARIANTRETVAL);\n//WPP_FLAGS(-public:FunctionReturnVariant);\n//end_wpp\n#define WPP_FUNCRETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_ENABLED(LEVEL, comp, variantretval) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_FUNCRETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_LOGGER(LEVEL, comp, variantretval) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_FUNCRETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_PRE(LEVEL, comp, variantretval)   { \\\n                                                                                                VARIANT __vtRetVal = variantretval;\n#define WPP_FUNCRETURNVARIANTLEVEL_COMPNAME_VARIANTRETVAL_POST(LEVEL, comp, variantretval)      /*TraceMessage()*/; \\\n                                                                                                return __vtRetVal; \\\n                                                                                            }\n\n\n//MACRO: COMReportError\n//\n//begin_wpp config\n//USEPREFIX (COMReportError, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %!HRESULT! - Error %S\", INDENT_STR(__pCtx->CallDepth), this, __hResult, __pszErrMsg);\n//FUNC COMReportError{COMReportError=COMEntryExit}(COMPNAME, HR, ERRMSG);\n//WPP_FLAGS(-public:COMReportError);\n//end_wpp\n#define WPP_COMReportError_COMPNAME_HR_ERRMSG_ENABLED(LEVEL, comp, HR, errmsg) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMReportError_COMPNAME_HR_ERRMSG_LOGGER(LEVEL, comp, HR, errmsg) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_COMReportError_COMPNAME_HR_ERRMSG_PRE(LEVEL, comp, HR, errmsg)  { \\\n                                                                                HRESULT __hResult = HR; \\\n                                                                                CString __strErrMsg(errmsg); \\\n                                                                                if(HRESULT_FACILITY(__hResult) == FACILITY_WIN32) \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" Win32=%d\", HRESULT_CODE(__hResult)); \\\n                                                                                } \\\n                                                                                else if((__hResult & FACILITY_NT_BIT) != 0) \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" NTSTATUS=0x%X\", __hResult & ~FACILITY_NT_BIT); \\\n                                                                                } \\\n                                                                                else \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" HRESULT=0x%X\", __hResult); \\\n                                                                                } \\\n                                                                                \\\n                                                                                PWSTR __pszSysMsg = NULL; \\\n                                                                                DWORD __dwFmtResult; \\\n                                                                                __dwFmtResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \\\n                                                                                                              FORMAT_MESSAGE_IGNORE_INSERTS | \\\n                                                                                                              FORMAT_MESSAGE_FROM_SYSTEM, \\\n                                                                                                              NULL, \\\n                                                                                                              __hResult, \\\n                                                                                                              0, \\\n                                                                                                              (LPWSTR)&__pszSysMsg, \\\n                                                                                                              0, \\\n                                                                                                              NULL); \\\n                                                                                if(__dwFmtResult != 0 && __hResult != E_FAIL) \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" - %s\", __pszSysMsg); \\\n                                                                                } \\\n                                                                                if(__pszSysMsg != NULL) \\\n                                                                                { \\\n                                                                                    LocalFree(__pszSysMsg); \\\n                                                                                } \\\n                                                                                LPCOLESTR __pszErrMsg = __strErrMsg;\n#define WPP_COMReportError_COMPNAME_HR_ERRMSG_POST(LEVEL, comp, HR, errmsg)     /*TraceMessage()*/; \\\n                                                                                return AtlReportError(GetObjectCLSID(), \\\n                                                                                    __pszErrMsg, GUID_NULL, __hResult); \\\n                                                                            }\n \n\n//MACRO: COMReportErrorIfFailed\n//\n//begin_wpp config\n//USEPREFIX (COMReportErrorIfFailed, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %!HRESULT! - Error %S\", INDENT_STR(__pCtx->CallDepth), this, __hResult, __pszErrMsg);\n//FUNC COMReportErrorIfFailed{COMReportError=COMEntryExit}(COMPNAME, HR, ERRMSG);\n//WPP_FLAGS(-public:COMReportErrorIfFailed);\n//end_wpp\n#define WPP_COMReportErrorIfFailed_COMPNAME_HR_ERRMSG_ENABLED(LEVEL, comp, HR, errmsg) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMReportErrorIfFailed_COMPNAME_HR_ERRMSG_LOGGER(LEVEL, comp, HR, errmsg) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_COMReportErrorIfFailed_COMPNAME_HR_ERRMSG_PRE(LEVEL, comp, HR, errmsg)  { \\\n                                                                                HRESULT __hResult = HR; \\\n                                                                                if (FAILED(__hResult)) \\\n                                                                                {\\\n                                                                                    CString __strErrMsg(errmsg); \\\n                                                                                    if(HRESULT_FACILITY(__hResult) == FACILITY_WIN32) \\\n                                                                                    { \\\n                                                                                        __strErrMsg.AppendFormat(L\" Win32=%d\", HRESULT_CODE(__hResult)); \\\n                                                                                    } \\\n                                                                                    else if((__hResult & FACILITY_NT_BIT) != 0) \\\n                                                                                    { \\\n                                                                                        __strErrMsg.AppendFormat(L\" NTSTATUS=0x%X\", __hResult & ~FACILITY_NT_BIT); \\\n                                                                                    } \\\n                                                                                    else \\\n                                                                                    { \\\n                                                                                        __strErrMsg.AppendFormat(L\" HRESULT=0x%X\", __hResult); \\\n                                                                                    } \\\n                                                                                    \\\n                                                                                    PWSTR __pszSysMsg = NULL; \\\n                                                                                    DWORD __dwFmtResult; \\\n                                                                                    __dwFmtResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \\\n                                                                                                                  FORMAT_MESSAGE_IGNORE_INSERTS | \\\n                                                                                                                  FORMAT_MESSAGE_FROM_SYSTEM, \\\n                                                                                                                  NULL, \\\n                                                                                                                  __hResult, \\\n                                                                                                                  0, \\\n                                                                                                                  (LPWSTR)&__pszSysMsg, \\\n                                                                                                                  0, \\\n                                                                                                                  NULL); \\\n                                                                                    if(__dwFmtResult != 0 && __hResult != E_FAIL) \\\n                                                                                    { \\\n                                                                                        __strErrMsg.AppendFormat(L\" - %s\", __pszSysMsg); \\\n                                                                                    } \\\n                                                                                    if(__pszSysMsg != NULL) \\\n                                                                                    { \\\n                                                                                        LocalFree(__pszSysMsg); \\\n                                                                                    } \\\n                                                                                    LPCOLESTR __pszErrMsg = __strErrMsg;\n    #define WPP_COMReportErrorIfFailed_COMPNAME_HR_ERRMSG_POST(LEVEL, comp, HR, errmsg)     /*TraceMessage()*/; \\\n                                                                                    return AtlReportError(GetObjectCLSID(), \\\n                                                                                        __pszErrMsg, GUID_NULL, __hResult); \\\n                                                                                }\\\n                                                                            }\n\n//MACRO: COMReportErrorAndLog\n//\n//begin_wpp config\n//USEPREFIX (COMReportErrorAndLog, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %!HRESULT! - Error %S\", INDENT_STR(__pCtx->CallDepth), this, __hResult, __pszErrMsg);\n//FUNC COMReportErrorAndLog{COMReportErrorAndLog=COMEntryExit}(COMPNAME, HR, ERRMSG);\n//WPP_FLAGS(-public:COMReportErrorAndLog);\n//end_wpp\n#define WPP_COMReportErrorAndLog_COMPNAME_HR_ERRMSG_ENABLED(LEVEL, comp, HR, errmsg) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMReportErrorAndLog_COMPNAME_HR_ERRMSG_LOGGER(LEVEL, comp, HR, errmsg) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_COMReportErrorAndLog_COMPNAME_HR_ERRMSG_PRE(LEVEL, comp, HR, errmsg)  { \\\n                                                                                HRESULT __hResult = HR; \\\n                                                                                CString __strErrMsg(errmsg); \\\n                                                                                if(HRESULT_FACILITY(__hResult) == FACILITY_WIN32) \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" Win32=%d\", HRESULT_CODE(__hResult)); \\\n                                                                                } \\\n                                                                                else if((__hResult & FACILITY_NT_BIT) != 0) \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" NTSTATUS=0x%X\", __hResult & ~FACILITY_NT_BIT); \\\n                                                                                } \\\n                                                                                else \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" HRESULT=0x%X\", __hResult); \\\n                                                                                } \\\n                                                                                \\\n                                                                                PWSTR __pszSysMsg = NULL; \\\n                                                                                DWORD __dwFmtResult; \\\n                                                                                __dwFmtResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \\\n                                                                                                              FORMAT_MESSAGE_IGNORE_INSERTS | \\\n                                                                                                              FORMAT_MESSAGE_FROM_SYSTEM, \\\n                                                                                                              NULL, \\\n                                                                                                              __hResult, \\\n                                                                                                              0, \\\n                                                                                                              (LPWSTR)&__pszSysMsg, \\\n                                                                                                              0, \\\n                                                                                                              NULL); \\\n                                                                                if(__dwFmtResult != 0 && __hResult != E_FAIL) \\\n                                                                                { \\\n                                                                                    __strErrMsg.AppendFormat(L\" - %s\", __pszSysMsg); \\\n                                                                                } \\\n                                                                                if(__pszSysMsg != NULL) \\\n                                                                                { \\\n                                                                                    LocalFree(__pszSysMsg); \\\n                                                                                } \\\n                                                                                LPCOLESTR __pszErrMsg = __strErrMsg;\n#define WPP_COMReportErrorAndLog_COMPNAME_HR_ERRMSG_POST(LEVEL, comp, HR, errmsg)     /*TraceMessage()*/; \\\n\t                                                                            m_Log.OutputError(L\"%s\\n\",__pszErrMsg); \\\n                                                                                return AtlReportError(GetObjectCLSID(), \\\n                                                                                    __pszErrMsg, GUID_NULL, __hResult); \\\n                                                                            }\n\n\n\n\n\n//\n//  Return Error macros\n//\n//  The macros return the HRESULT bit do not report an error threw AtlReportError()\n//\n\n\n//MACRO: COMReturnIfDestroyed\n//\n//begin_wpp config\n//USEPREFIX (COMReturnIfDestroyed, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): E_UNEXPECTED The called object was destroyed when someone called WDTF::Destroy(). Please dispose of this object, instantiate a new WDTF, and try again.\", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC COMReturnIfDestroyed{COMReturnIfDestroyed=COMEntryExit}(COMPNAME);\n//WPP_FLAGS(-public:COMReturnIfDestroyed);\n//end_wpp\n#define WPP_COMReturnIfDestroyed_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_COMReturnIfDestroyed_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_COMReturnIfDestroyed_COMPNAME_PRE(LEVEL, comp)    if (m_bDestroyed) \\\n                                                              {\n#define WPP_COMReturnIfDestroyed_COMPNAME_POST(LEVEL, comp)       /*TraceMessage()*/; \\\n                                                                  return AtlReportError(GetObjectCLSID(), \\\n                                                                            L\"The called object was destroyed when someone called WDTF::Destroy(). Please dispose of this object, instantiate a new WDTF, and try again.\", GUID_NULL, E_UNEXPECTED); \\\n                                                              }\n\n//MACRO: COMReturnIfNull\n//\n//begin_wpp config\n//USEPREFIX (COMReturnIfNull, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): E_POINTER %s=NULL, bailing out!\", INDENT_STR(__pCtx->CallDepth), this, #PTR);\n//FUNC COMReturnIfNull{E_POINTER_LEVEL=COMEntryExit}(COMPNAME, PTR);\n//WPP_FLAGS(-public:COMReturnIfNull);\n//end_wpp\n#define WPP_E_POINTER_LEVEL_COMPNAME_PTR_ENABLED(LEVEL, comp, PTR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_E_POINTER_LEVEL_COMPNAME_PTR_LOGGER(LEVEL, comp, PTR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_E_POINTER_LEVEL_COMPNAME_PTR_PRE(LEVEL, comp, PTR)      if ((PTR) == NULL) \\\n                                                                   {\n#define WPP_E_POINTER_LEVEL_COMPNAME_PTR_POST(LEVEL, comp, PTR)         /*TraceMessage()*/; \\\n                                                                       return AtlReportError(GetObjectCLSID(), \\\n                                                                           L\"Argument Error \" WIDEN(#PTR) L\"=NULL, bailing out!\", GUID_NULL, E_POINTER); \\\n                                                                   }\n\n\n//MACRO: COMReportErrorAndLogIfNull\n//\n//begin_wpp config\n//USEPREFIX (COMReportErrorAndLogIfNull, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): E_POINTER %s=NULL, bailing out!\", INDENT_STR(__pCtx->CallDepth), this, #PTR);\n//FUNC COMReportErrorAndLogIfNull{E_POINTER_LEVEL=COMEntryExit}(COMPNAME, PTR);\n//WPP_FLAGS(-public:COMReturnErrorAndLogIfNull);\n//end_wpp\n#define WPP_E_POINTER_LEVEL_AND_LOG_COMPNAME_PTR_ENABLED(LEVEL, comp, PTR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_E_POINTER_LEVEL_AND_LOG_COMPNAME_PTR_LOGGER(LEVEL, comp, PTR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_E_POINTER_LEVEL_AND_LOG_COMPNAME_PTR_PRE(LEVEL, comp, PTR)      if ((PTR) == NULL) \\\n                                                                   {\n#define WPP_E_POINTER_LEVEL_AND_LOG_COMPNAME_PTR_POST(LEVEL, comp, PTR)         /*TraceMessage()*/; \\\n                                                                       LPCOLESTR __pszErrMsg =  L\"Argument Error \" WIDEN(#PTR) L\"=NULL, bailing out!\"; \\\n                                                                       m_Log.OutputError(L\"%s\\n\",__pszErrMsg); \\\n                                                                       return AtlReportError(GetObjectCLSID(), \\\n                                                                           __pszErrMsg, GUID_NULL, E_POINTER); \\\n                                                                   }\n\n//MACRO: COMReturnIfFailed\n//\n//begin_wpp config\n//USEPREFIX (COMReturnIfFailed, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %!HRESULT! Contained method failed: Bailing out!\", INDENT_STR(__pCtx->CallDepth), this, __hr);\n//FUNC COMReturnIfFailed{PROPAGATE_LEVEL=COMEntryExit}(COMPNAME, HR);\n//WPP_FLAGS(-public:COMReturnIfFailed);\n//end_wpp\n#define WPP_PROPAGATE_LEVEL_COMPNAME_HR_ENABLED(LEVEL, comp, HR) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_PROPAGATE_LEVEL_COMPNAME_HR_LOGGER(LEVEL, comp, HR) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_PROPAGATE_LEVEL_COMPNAME_HR_PRE(LEVEL, comp, HR)      { \\\n                                                                      HRESULT __hr = HR; \\\n                                                                      if (FAILED(__hr)) \\\n                                                                      {\n#define WPP_PROPAGATE_LEVEL_COMPNAME_HR_POST(LEVEL, comp, HR)             /*TraceMessage()*/; \\\n                                                                          return __hr; \\\n                                                                      } \\\n                                                                  }\n\n// Return last Win32 error converted to HRESULT\n//#define COMReturnLastWin32()                           \\\n//{                                                      \\\n//    HRESULT __hr = HRESULT_FROM_WIN32(GetLastError()); \\\n//    return __hr;                                       \\\n//}\n\n//MACRO: COMReturnLastWin32\n//\n//begin_wpp config\n//USEPREFIX (COMReturnLastWin32, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC COMReturnLastWin32{LASTWIN32_LEVEL=COMEntryExit}(COMPNAME, ...);\n//USESUFFIX (COMReturnLastWin32, \"%!HRESULT!\", __hr);\n//WPP_FLAGS(-public:COMReturnLastWin32);\n//end_wpp\n#define WPP_LASTWIN32_LEVEL_COMPNAME_ENABLED(LEVEL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LASTWIN32_LEVEL_COMPNAME_LOGGER(LEVEL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LASTWIN32_LEVEL_COMPNAME_PRE(LEVEL, comp)   { \\\n                                                            HRESULT __hr = HRESULT_FROM_WIN32(GetLastError());\n#define WPP_LASTWIN32_LEVEL_COMPNAME_POST(LEVEL, comp)      /*TraceMessage()*/; \\\n                                                            return __hr; \\\n                                                        }\n\n\n\n// Return NTSTATUS converted to HRESULT if it is not STATUS_SUCCESS\n//#define RETURN_IF_NOT_SUCCESS(status)        \\\n//{                                            \\\n//    NTSTATUS st = status;                    \\\n//    if (st != STATUS_SUCCESS)                \\\n//    {                                        \\\n//        return HRESULT_FROM_NT(st);          \\\n//    }                                        \\\n//}\n\n//MACRO: COMReturnIfNotSuccess\n//\n//begin_wpp config\n//USEPREFIX (COMReturnIfNotSuccess, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC COMReturnIfNotSuccess{NTSTATUS_LEVEL=COMEntryExit}(COMPNAME, status);\n//USESUFFIX (COMReturnIfNotSuccess, \"%!HRESULT!\", HRESULT_FROM_NT(__status));\n//WPP_FLAGS(-public:COMReturnIfNotSuccess);\n//end_wpp\n#define WPP_NTSTATUS_LEVEL_COMPNAME_status_ENABLED(LEVEL, comp, status) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_NTSTATUS_LEVEL_COMPNAME_status_LOGGER(LEVEL, comp, status) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_NTSTATUS_LEVEL_COMPNAME_status_PRE(LEVEL, comp, status) { \\\n                                                                        NTSTATUS __status = status; \\\n                                                                        if (__status != STATUS_SUCCESS) \\\n                                                                        {\n#define WPP_NTSTATUS_LEVEL_COMPNAME_status_POST(LEVEL, comp, status)        /*TraceMessage()*/; \\\n                                                                            return HRESULT_FROM_NT(__status); \\\n                                                                        } \\\n                                                                    }\n\n\n\n//MACRO: DEFINE_CHECK\n//\n//begin_wpp config\n//FUNC DEFINE_CHECK{DEFINE_CHECK_LEVEL=COMEntryExit}(COMPNAME, decl, init, ret);\n//WPP_FLAGS(-public:DEFINE_CHECK);\n//end_wpp\n#define WPP_DEFINE_CHECK_LEVEL_COMPNAME_decl_init_ret_ENABLED(LEVEL, comp, decl, init, ret) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_DEFINE_CHECK_LEVEL_COMPNAME_decl_init_ret_LOGGER(LEVEL, comp, decl, init, ret) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_DEFINE_CHECK_LEVEL_COMPNAME_decl_init_ret_PRE(LEVEL, comp, decl, init, ret) decl; \n#define WPP_DEFINE_CHECK_LEVEL_COMPNAME_decl_init_ret_POST(LEVEL, comp, decl, init, ret)        /*TraceMessage()*/; \\\n                                                                        if (init) \\\n                                                                        { \\\n                                                                            return ret; \\\n                                                                        } \\\n\n\n// Define Non-empty debug break for checked builds only\n\n// TODO: Having a debugbreak that happens at regsvr32 time breaks registration\n#ifndef NDEBUG\n    #define DEBUG_BREAK() do {} while (false)\n#else\n    #define DEBUG_BREAK() do {} while (false)\n#endif\n\n\n//ASSERT macro with tracing\n//MACRO: TraceASSERT\n//\n//begin_wpp config\n//USEPREFIX (TraceASSERT, \"%!STDPREFIX!%sWARN: ASSERTION FAILED - expression \\\"%s\\\" is false.\", INDENT_STR(__pCtx->CallDepth+1), #expr);\n//FUNC TraceASSERT{ASSERTLEVEL=Warning}(COMPNAME, expr);\n//WPP_FLAGS(-public:TraceASSERT);\n//end_wpp\n#define WPP_ASSERTLEVEL_COMPNAME_expr_ENABLED(LEVEL, comp, expr) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_ASSERTLEVEL_COMPNAME_expr_LOGGER(LEVEL, comp, expr) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_ASSERTLEVEL_COMPNAME_expr_PRE(LEVEL, comp, expr)    if (!(expr)) \\\n                                                                {    \n#define WPP_ASSERTLEVEL_COMPNAME_expr_POST(LEVEL, comp, expr)       /*TraceMessage()*/; \\\n                                                                    DEBUG_BREAK(); \\\n                                                                }\n\n\n//MACRO: Throw\n//\n// Trace and throw an exception.\n//\n//begin_wpp config\n//USEPREFIX (Throw, \"%!STDPREFIX!%sFATAL ERROR: throwing %s\", INDENT_STR(__pCtx->CallDepth+1), #EXCEPTION);\n//FUNC Throw{LEVEL=Error}(COMPNAME, EXCEPTION, ...);\n//WPP_FLAGS(-public:Throw);\n//end_wpp\n#define WPP_LEVEL_COMPNAME_EXCEPTION_ENABLED(LEVEL, comp, __exception) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_EXCEPTION_LOGGER(LEVEL, comp, __exception) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_EXCEPTION_POST(LEVEL, comp, __exception) ; DEBUG_BREAK(); throw __exception;\n\n\n\n//MACRO: ThrowEFatal\n//\n// Trace and throw an EFatal exception.\n//\n//begin_wpp config\n//USEPREFIX (ThrowEFatal, \"%!STDPREFIX!%sFATAL ERROR: \", INDENT_STR(__pCtx->CallDepth+1));\n//FUNC ThrowEFatal{LEVEL=Error, EFATAL=0, COMPNAME=WDTF}(MSG, ...);\n//WPP_FLAGS(-public:ThrowEFatal);\n//end_wpp\n#define WPP_LEVEL_EFATAL_COMPNAME_ENABLED(LEVEL, EFATAL, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_EFATAL_COMPNAME_LOGGER(LEVEL, EFATAL, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_EFATAL_COMPNAME_POST(LEVEL, EFATAL, comp) ; DEBUG_BREAK(); throw EFatal(__WFILE__, __LINE__, L\"See ETL log for details. Please provide this info to WDTF Support.\");\n\n\n\n//TODO: what help context?\n//MACRO: ThrowEInternal\n//\n// Trace and throw an EInternal exception.\n//\n//begin_wpp config\n//USEPREFIX (ThrowEInternal, \"%!STDPREFIX!%sINTERNAL ERROR: \\\"%S\\\"\", INDENT_STR(__pCtx->CallDepth+1), DESCRIPTION);\n//FUNC ThrowEInternal{LEVEL=Error, COMPNAME=WDTF}(DESCRIPTION);\n//WPP_FLAGS(-public:ThrowEInternal);\n//end_wpp\n#define WPP_LEVEL_COMPNAME_DESCRIPTION_ENABLED(LEVEL, comp, descr) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_DESCRIPTION_LOGGER(LEVEL, comp, descr) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_DESCRIPTION_POST(LEVEL, comp, descr) ; DEBUG_BREAK(); throw EInternal(__WFILE__, __LINE__, descr, 0);\n\n\n// begin_wpp config\n// CUSTOM_TYPE(EParse_TCode, ItemEnum(EParse::_TCode) );\n// end_wpp\n\n//MACRO: ThrowEParse\n//\n// Trace and throw an EParse exception.\n//\n//begin_wpp config\n//USEPREFIX (ThrowEParse, \"%!STDPREFIX!%sPARSE ERROR: \\\"%!EParse_TCode!\\\"\", INDENT_STR(__pCtx->CallDepth+1), EParse::TCODE);\n//FUNC ThrowEParse{LEVEL=Error, COMPNAME=WDTF}(TCODE);\n//WPP_FLAGS(-public:ThrowEParse);\n//end_wpp\n#define WPP_LEVEL_COMPNAME_TCODE_ENABLED(LEVEL, comp, tcode) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_TCODE_LOGGER(LEVEL, comp, tcode) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_TCODE_POST(LEVEL, comp, tcode) ; throw EParse(__WFILE__, __LINE__, EParse::tcode);\n\n\n\n\n//MACRO: ReportEParse\n//\n// Handle and trace an EParse exception. Then convert it into an\n// IErrorInfo (as E_INVALIDARG) using AtlReportError.\n//\n//begin_wpp config\n//USEPREFIX (ReportEParse, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): %S \", INDENT_STR(__pCtx->CallDepth), this, strFull.c_str());\n//FUNC ReportEParse{LEVEL=COMError, COMPNAME=WDTF}(EPARSE);\n//USESUFFIX (ReportEParse, \"Returning (E_INVALIDARG)\");\n//WPP_FLAGS(-public:ReportEParse);\n//end_wpp\n#define WPP_LEVEL_COMPNAME_EPARSE_ENABLED(LEVEL, comp, EPARSE) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_EPARSE_LOGGER(LEVEL, comp, EPARSE) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_EPARSE_PRE(LEVEL, comp, EPARSE)                             \\\n{                                                                       \\\n    wstring strSDEL = EPARSE.GetQuery();                                \\\n                                                                        \\\n    wstring strFull = L\"Error Parsing Argument: \";                      \\\n                                                                        \\\n    strFull += EPARSE.GetDescription(); strFull += L\" SDEL(\";           \\\n    strFull += strSDEL.substr(0, EPARSE.GetParsed()).c_str();           \\\n    strFull += L\"<-NEAR HERE->\";                                        \\\n    strFull += strSDEL.substr(EPARSE.GetParsed()).c_str();              \\\n    strFull += L\")\";                                                    \n\n#define WPP_LEVEL_COMPNAME_EPARSE_POST(LEVEL, comp, EPARSE)    /*TraceMessage(...)*/;  \\\n    /*DebugBreak();*/                                                   \\\n      return AtlReportError(GetObjectCLSID(),                           \\\n        strFull.c_str(),                                                \\\n        GUID_NULL, E_INVALIDARG);                                       \\\n}\n\n\n//MACRO: ThrowEFieldData\n//\n// Trace and throw an ThrowEFieldData exception.\n//\n//begin_wpp config\n//USEPREFIX (ThrowEFieldData, \"%!STDPREFIX!%sERROR Field Error : \",INDENT_STR(__pCtx->CallDepth+1));\n//FUNC ThrowEFieldData{LEVEL=Error, COMPNAME=WDTF}(NODEUNIQUEID,NAMESPACENAME,FIELDNAME,ERRORCODE);\n//WPP_FLAGS(-public:ThrowEFieldData);\n//end_wpp\n#define WPP_LEVEL_COMPNAME_NODEUNIQUEID_NAMESPACENAME_FIELDNAME_ERRORCODE_ENABLED(LEVEL, comp, nodeuniqueid , namespacename,fieldname,err) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_NODEUNIQUEID_NAMESPACENAME_FIELDNAME_ERRORCODE_LOGGER(LEVEL, comp, nodeuniqueid , namespacename,fieldname,err) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_NODEUNIQUEID_NAMESPACENAME_FIELDNAME_ERRORCODE_POST(LEVEL, comp, nodeuniqueid , namespacename,fieldname,err) ; throw EDataField(__WFILE__, __LINE__, (PCWSTR)nodeuniqueid , (PCWSTR)namespacename,(PCWSTR)fieldname,err);\n\n\n//MACRO: ReportEFieldData\n//\n// Handle and trace an EDataField exception. Then convert it into an\n// IErrorInfo (as E_INVALIDARG) using AtlReportError.\n//\n//begin_wpp config\n//USEPREFIX (ReportEFieldData, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC ReportEFieldData{LEVEL=COMError, COMPNAME=WDTF}(EDATA);\n//USESUFFIX (ReportEFieldData, \"Returning (E_INVALIDARG)\");\n//WPP_FLAGS(-public:ReportEFieldData);\n//end_wpp\n#define WPP_LEVEL_COMPNAME_EDATA_ENABLED(LEVEL, comp, EDATA) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_EDATA_LOGGER(LEVEL, comp, EDATA) WPP_LEVEL_LOGGER(comp##LEVEL)\n#define WPP_LEVEL_COMPNAME_EDATA_PRE(LEVEL, comp, EDATA)                             \\\n{                                                                        \\\n    ULONG __nLastError = EDATA.GetLastError();                           \\\n    HRESULT __hr = HRESULT_FROM_SETUPAPI(__nLastError);                  \\\n    CString __strErrMsg;                                                 \\\n    __strErrMsg.Format(L\" %s  : Target=\\\"%s\\\" NameSpace=\\\"%s\\\" Field Name=\\\"%s\\\" Win32 Error Code=%d\",   \\\n        EDATA.GetDescription(),                                          \\\n        EDATA.GetNodeUniqueID(),                                         \\\n        EDATA.GetNameSpace(),                                            \\\n        EDATA.GetFieldName(),                                            \\\n        HRESULT_CODE(__hr));    \\\n     PWSTR __pszSysMsg = NULL; \\\n     DWORD __dwFmtResult; \\\n     __dwFmtResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \\\n                                    FORMAT_MESSAGE_IGNORE_INSERTS | \\\n                                    FORMAT_MESSAGE_FROM_SYSTEM, \\\n                                    NULL, \\\n                                    __hr, \\\n                                    0, \\\n                                    (LPWSTR)&__pszSysMsg, \\\n                                    0, \\\n                                    NULL); \\\n    if(__dwFmtResult != 0 ) \\\n    { \\\n        __strErrMsg.AppendFormat(L\" - %s\", __pszSysMsg); \\\n    } \\\n    if(__pszSysMsg != NULL) \\\n    { \\\n        LocalFree(__pszSysMsg); \\\n    } \n\n\n#define WPP_LEVEL_COMPNAME_EDATA_POST(LEVEL, comp, EDATA)    /*TraceMessage(...)*/;  \\\n    /*DebugBreak();*/                                                   \\\n      return AtlReportError(GetObjectCLSID(),                           \\\n        __strErrMsg, GUID_NULL, __hr);                   \\\n}\n\n\n\n//MACRO: ReportEMemory\n//\n// Handle and trace a std::bad_alloc exception. Then convert it into an\n// IErrorInfo (as E_OUTOFMEMORY) using AtlReportError.\n//\n//begin_wpp config\n//USEPREFIX (ReportEMemory, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC ReportEMemory{LEVEL=COMError, MEM=0, COMPNAME=WDTF}(...);\n//USESUFFIX (ReportEMemory, \"Out Of Memory Error! Returning (E_OUTOFMEMORY)\");\n//WPP_FLAGS(-public:ReportEMemory);\n//end_wpp\n#define WPP_LEVEL_MEM_COMPNAME_ENABLED(LEVEL, MEM, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_MEM_COMPNAME_LOGGER(LEVEL, MEM, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n#define WPP_LEVEL_MEM_COMPNAME_PRE(LEVEL, MEM, comp) \n#define WPP_LEVEL_MEM_COMPNAME_POST(LEVEL, MEM, comp)      /*TraceMessage(...)*/;                               \\\n                                                DebugBreak();                                                   \\\n                                                return AtlReportError(GetObjectCLSID(),                         \\\n                                                    L\"Out Of Memory Error! Perhaps try the operation again?\",   \\\n                                                    GUID_NULL, E_OUTOFMEMORY);\n\n\n\n//MACRO: ReportEFail\n//\n// Handle and trace the '...' exception. Then convert it into an\n// IErrorInfo (as E_FAIL) using AtlReportError.\n//\n//\n//begin_wpp config\n//USEPREFIX (ReportEFail, \"%!STDPREFIX!%so<-this(%p):%!FUNC!(): \", INDENT_STR(__pCtx->CallDepth), this);\n//FUNC ReportEFail{LEVEL=COMError, FAIL=0, COMPNAME=WDTF}(...);\n//USESUFFIX (ReportEFail, \"General Failure! Returning (E_FAIL)\");\n//WPP_FLAGS(-public:ReportEFail);\n//end_wpp\n#define WPP_LEVEL_FAIL_COMPNAME_ENABLED(LEVEL, GEN, comp) IS_LEVEL_ENABLED(comp##LEVEL)\n#define WPP_LEVEL_FAIL_COMPNAME_LOGGER(LEVEL, GEN, comp) WPP_LEVEL_LOGGER(comp##LEVEL)\n\n#define WPP_LEVEL_FAIL_COMPNAME_PRE(LEVEL, GEN, comp) \n#define WPP_LEVEL_FAIL_COMPNAME_POST(LEVEL, GEN, comp)     /*TraceMessage(...)*/;                       \\\n                                                return AtlReportError(GetObjectCLSID(),                 \\\n                                                    L\"General Failure! See the WPP log for more info.\", \\\n                                                    GUID_NULL, E_FAIL);\n\n\n\n\n\n// begin_wpp config\n// CUSTOM_TYPE(Devnode_RelationName, ItemEnum(TDevnode_RelationName) );\n// end_wpp\n\n// begin_wpp config\n// CUSTOM_TYPE(Devnode_FieldName, ItemEnum(TDevnode_FieldName) );\n// end_wpp\n\n// begin_wpp config\n// CUSTOM_TYPE(System_RelationName, ItemEnum(TSystem_RelationName) );\n// end_wpp\n\n// begin_wpp config\n// CUSTOM_TYPE(System_FieldName, ItemEnum(TSystem_FieldName) );\n// end_wpp\n\n\n// begin_wpp config\n// CUSTOM_TYPE(Fake_RelationName, ItemEnum(TFake_RelationName) );\n// end_wpp\n\n\n"
  },
  {
    "path": "Tests/UnitTests/Support/TE/UnitTestHelpers_TE.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include <sstream>\n#include <iomanip>\n#include \"iso8601.h\"\n\nTEST_MODULE_INITIALIZE(ModuleInitialize)\n{\n    Logger::WriteMessage(\"Started unit test\");\n}\n\nTEST_MODULE_CLEANUP(ModuleCleanup)\n{\n    Logger::WriteMessage(\"Stopped unit test\");\n}\n\nstd::wstring FormatString(LPCWSTR strMsg, ...)\n{\n    WCHAR strBuffer[2048];\n\n    va_list args;\n    va_start(args, strMsg);\n    StringCchVPrintfW(strBuffer, 2048, strMsg, args);\n    strBuffer[2047] = L'\\0';\n\n    va_end(args);\n\n    return std::wstring(strBuffer);\n}\n\n"
  },
  {
    "path": "Tests/UnitTests/Support/TE/UnitTestHelpers_TE.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"shared_macros.h\"\n#include <strsafe.h>\n\n#define DATETIME_STRING_LENGTH_TO_SECOND 19\n#define TICKS_PER_SECOND 10000000i64\ntypedef std::chrono::duration<long long, std::ratio<1, 10000000>> ticks;\n\nstd::wstring FormatString(LPCWSTR strMsg, ...);\n"
  },
  {
    "path": "Tests/UnitTests/Support/TE/UnitTestIncludes_TE.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#include \"UnitTestHelpers_TE.h\"\n#include \"CppUnitTest.h\"\n#include <strsafe.h>\n\nusing namespace Microsoft::VisualStudio::CppUnitTestFramework;\nusing namespace pplx;\n\nclass AssertHelper\n{\npublic:\n    static void AreEqual(const wchar_t* expected, const wchar_t* actual)\n    {\n        Assert::AreEqual(expected, actual, false, nullptr, nullptr);\n    }\n\n    static void AreEqual(std::wstring expected, const wchar_t* actual)\n    {\n        Assert::AreEqual(expected.c_str(), actual);\n    }\n\n    static void AreEqual(const wchar_t* expected, std::wstring actual)\n    {\n        Assert::AreEqual(expected, actual.c_str());\n    }\n\n    static void AreEqual(std::wstring expected, std::wstring actual)\n    {\n        Assert::AreEqual(expected.c_str(), actual.c_str());\n    }\n\n    static void AreEqual(bool expected, bool actual)\n    {\n        Assert::AreEqual(expected, actual);\n    }\n\n    static void AreEqual(double expected, double actual)\n    {\n        Assert::AreEqual(expected, actual);\n    }\n\n    static void AreEqual(std::chrono::duration<std::chrono::system_clock::rep, std::chrono::system_clock::period> expected, std::chrono::duration<std::chrono::system_clock::rep, std::chrono::system_clock::period> actual)\n    {\n        Assert::IsTrue(expected == actual);\n    }\n\n    static void AreEqual(xsapi_internal_string expected, xsapi_internal_string actual)\n    {\n        Assert::AreEqual(expected.data(), actual.data(), false, nullptr, nullptr);\n    }\n\n    static void AreEqual(const std::string& expected, const std::string& actual)\n    {\n        Assert::AreEqual(expected.data(), actual.data(), false, nullptr, nullptr);\n    }\n\n    static void AreEqual(size_t expected, size_t actual)\n    {\n        Assert::IsTrue(expected == actual);\n    }\n\n    static void AreEqual(HRESULT expected, HRESULT actual)\n    {\n        Assert::IsTrue(expected == actual);\n    }\n};\n\n#define VERIFY_ARE_EQUAL_UINT(expected, actual) \\\n    Assert::IsTrue(static_cast<uint64_t>(expected) == static_cast<uint64_t>(actual))\n\n#define VERIFY_ARE_EQUAL_INT(expected, actual) \\\n    Assert::IsTrue(static_cast<int64_t>(expected) == static_cast<int64_t>(actual))\n\n#define VERIFY_ARE_EQUAL_DOUBLE(expected, actual) \\\n    Assert::IsTrue(static_cast<double>(expected) == static_cast<double>(actual))\n\n#define VERIFY_ARE_EQUAL(expected,actual) \\\n    AssertHelper::AreEqual(expected,actual)\n\n#define VERIFY_ARE_EQUAL_STR(expected,actual) \\\n    AssertHelper::AreEqual(expected,actual)\n\n#define VERIFY_ARE_EQUAL_STR_IGNORE_CASE(expected,actual) \\\n    Assert::AreEqual(expected, actual, true)\n\n#define VERIFY_IS_TRUE(x) \\\n    Assert::IsTrue(x, L#x)\n\n#define VERIFY_IS_FALSE(x) \\\n    Assert::IsFalse(x, L#x)\n\n#define VERIFY_IS_NULL(x) \\\n    Assert::IsNull(x, L#x)\n\n#define VERIFY_IS_NOT_NULL(x) \\\n    Assert::IsNotNull(x)\n\n#define VERIFY_SUCCEEDED(x) \\\n    Assert::IsTrue(SUCCEEDED(x))\n\n#define VERIFY_FAILED(x) \\\n    Assert::IsTrue(FAILED(x))\n\n#define VERIFY_FAIL() \\\n    Assert::Fail()\n\n#define VERIFY_INVALIDARG(x) \\\n    Assert::AreEqual(E_INVALIDARG, x)\n\n#define VERIFY_ARE_EQUAL_TIMESPAN_TO_SECONDS(__timespan, __seconds) VERIFY_ARE_EQUAL(Microsoft::Xbox::Services::System::timeSpanTicks(__timespan.Duration), std::chrono::seconds(__seconds))\n#define VERIFY_ARE_EQUAL_TIMESPAN_TO_MILLISECONDS(__timespan, __seconds) VERIFY_ARE_EQUAL(Microsoft::Xbox::Services::System::timeSpanTicks(__timespan.Duration), std::chrono::milliseconds(__seconds))\n\n#define VERIFY_THROWS_CX(__operation, __exception)                                                                                                                          \\\n{                                                                                                                                                                           \\\n    bool __exceptionHit = false;                                                                                                                                            \\\n    try                                                                                                                                                                     \\\n    {                                                                                                                                                                       \\\n        __operation;                                                                                                                                                        \\\n    }                                                                                                                                                                       \\\n    catch(__exception^ __e)                                                                                                                                                 \\\n    {                                                                                                                                                                       \\\n        Logger::WriteMessage( FormatString( L\"Verify: Expected Exception Thrown( %s )\", L#__exception ).c_str() );                                                          \\\n        __exceptionHit = true;                                                                                                                                              \\\n    }                                                                                                                                                                       \\\n    catch(...)                                                                                                                                                              \\\n    {                                                                                                                                                                       \\\n    }                                                                                                                                                                       \\\n    if(!__exceptionHit)                                                                                                                                                     \\\n    {                                                                                                                                                                       \\\n        Logger::WriteMessage( FormatString( L\"Error: Expected Exception Not Thrown ( %s )\", L#__exception ).c_str() );                                                      \\\n        Assert::IsTrue(__exceptionHit);                                                                                                                                     \\\n    }                                                                                                                                                                       \\\n}\n\n#define VERIFY_THROWS_HR_CX(__operation, __hr)                                                                                                                                  \\\n{                                                                                                                                                                               \\\n    bool __exceptionHit = false;                                                                                                                                                \\\n    try                                                                                                                                                                         \\\n    {                                                                                                                                                                           \\\n        __operation;                                                                                                                                                            \\\n    }                                                                                                                                                                           \\\n    catch(Platform::Exception^ __e)                                                                                                                                             \\\n    {                                                                                                                                                                           \\\n        if(__e->HResult == (__hr))                                                                                                                                              \\\n        {                                                                                                                                                                       \\\n            Logger::WriteMessage( FormatString( L\"Verify: Expected Exception Thrown ( hr == %s )\", L#__hr ).c_str() );                                                          \\\n            __exceptionHit = true;                                                                                                                                              \\\n        }                                                                                                                                                                       \\\n    }                                                                                                                                                                           \\\n    catch(...)                                                                                                                                                                  \\\n    {                                                                                                                                                                           \\\n    }                                                                                                                                                                           \\\n    if(!__exceptionHit)                                                                                                                                                         \\\n    {                                                                                                                                                                           \\\n        Logger::WriteMessage( FormatString( L\"Error: Expected Exception Not Thrown ( hr == %s )\", L#__hr ).c_str() );                                                           \\\n        Assert::IsTrue(__exceptionHit);                                                                                                                                         \\\n    }                                                                                                                                                                           \\\n}\n\n\n#define VERIFY_NO_THROW(__operation, ...)                                                                                          \\\n{                                                                                                                                    \\\n    bool __exceptionHit = false;                                                                                                     \\\n    try                                                                                                                              \\\n    {                                                                                                                                \\\n        __operation;                                                                                                                 \\\n    }                                                                                                                                \\\n    catch(...)                                                                                                                       \\\n    {                                                                                                                                \\\n        __exceptionHit = true;                                                                                                       \\\n    }                                                                                                                                \\\n                                                                                                                                     \\\n    if (__exceptionHit)                                                                                                              \\\n    {                                                                                                                                \\\n    }                                                                                                                                \\\n}        \n\ninline void VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(const JsonValue& expected, const JsonValue& actual, bool& jsonMatches)\n{\n    if (expected.IsObject())\n    {\n        for (auto& jsonValue : expected.GetObject())\n        {\n            if (actual.IsObject() && actual.HasMember(jsonValue.name.GetString()))\n            {\n                const JsonValue& actualValue = actual[jsonValue.name.GetString()];\n                if (actualValue.IsNull() && !jsonValue.value.IsNull())\n                {\n                    jsonMatches = false;\n                    Assert::Fail(FormatString(L\"JSON Key Not Present %s\", jsonValue.name.GetString()).c_str());\n                    return;\n                }\n\n                Logger::WriteMessage(FormatString(L\"Testing JSON Key %s\", jsonValue.name.GetString()).c_str());\n                VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(jsonValue.value, actualValue, jsonMatches);\n            }\n            else\n            {\n                jsonMatches = false;\n                Assert::Fail(FormatString(L\"JSON Key Not Present %s\", jsonValue.name.GetString()).c_str());\n                return;\n            }\n        }\n    }\n    else\n    {\n        VERIFY_ARE_EQUAL(JsonUtils::SerializeJson(expected).c_str() , JsonUtils::SerializeJson(actual).c_str());\n    }\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER(const JsonValue& expected, const JsonValue& actual, const wchar_t* pszParamName)\n{\n    bool jsonMatches1 = true;\n    bool jsonMatches2 = true;\n    VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(expected, actual, jsonMatches1);\n    VERIFY_IS_EQUAL_JSON_RECURSION_HELPER(actual, expected, jsonMatches2);\n\n    if (jsonMatches1 && jsonMatches2)\n    {\n        Logger::WriteMessage(FormatString(L\"Verify: AreEqual(%s,\\\"%s\\\")\", JsonUtils::SerializeJson(expected).c_str(), JsonUtils::SerializeJson(actual).c_str()).c_str());\n    }\n    else\n    {\n        Assert::Fail(FormatString(L\"EXPECTED: %s = \\\"%s\\\"\", pszParamName, JsonUtils::SerializeJson(expected).c_str()).c_str());\n        Assert::Fail(FormatString(L\"ACTUAL: %s = \\\"%s\\\"\", pszParamName, JsonUtils::SerializeJson(actual).c_str()).c_str());\n    }\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS(std::wstring expected, std::wstring actual, const wchar_t* pszParamName)\n{\n    JsonDocument expectedJson;\n    expectedJson.Parse(utils::internal_string_from_string_t(expected).c_str());\n    JsonDocument actualJson;\n    actualJson.Parse(utils::internal_string_from_string_t(actual).c_str());\n    return VERIFY_IS_EQUAL_JSON_HELPER(expectedJson, actualJson, pszParamName);\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS(std::wstring expected, xsapi_internal_string actual, const wchar_t* pszParamName)\n{\n    JsonDocument expectedJson;\n    expectedJson.Parse(utils::internal_string_from_string_t(expected).c_str());\n    JsonDocument actualJson;\n    actualJson.Parse(actual.c_str());\n    return VERIFY_IS_EQUAL_JSON_HELPER(expectedJson, actualJson, pszParamName);\n}\n\ninline void VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS(std::string expected, std::string actual, const wchar_t* pszParamName)\n{\n    JsonDocument expectedJson;\n    expectedJson.Parse(expected.c_str());\n    JsonDocument actualJson;\n    actualJson.Parse(actual.c_str());\n    return VERIFY_IS_EQUAL_JSON_HELPER(expectedJson, actualJson, pszParamName);\n}\n\n#define VERIFY_IS_EQUAL_JSON_FROM_STRINGS(__expected, __actual, ...) VERIFY_IS_EQUAL_JSON_HELPER_FROM_STRINGS((__expected), (__actual), (L#__actual))\n\n#define VERIFY_IS_EQUAL_JSON(__expected, __actual, ...) VERIFY_IS_EQUAL_JSON_HELPER((__expected), (__actual), (L#__actual))\n"
  },
  {
    "path": "Tests/UnitTests/Support/UnitTestIncludes.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n#ifdef USING_TAEF\n#include \"TAEF/UnitTestIncludes_TAEF.h\"\n#else\n#include \"TE/UnitTestIncludes_TE.h\"\n#include \"DefineTestMacros.h\"\n#endif\n\n#include \"xbox_live_context_internal.h\"\n#include \"event.h\"\n#include \"xsapi-c/errors_c.h\"\n#include \"xsapi-cpp/xbox_live_context.h\"\n#include \"mock_rta_service.h\"\n#include \"http_mock.h\"\n#include \"mock_web_socket.h\"\n#include \"unit_test_helpers.h\"\n#include \"perf_tester.h\"\n#include \"rapidjson/stringbuffer.h\"\n#include \"rapidjson/writer.h\"\n"
  },
  {
    "path": "Tests/UnitTests/Support/event.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"event.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nEvent::Event() noexcept\n{\n    m_handle = CreateEvent(nullptr, false, false, nullptr);\n    assert(m_handle);\n}\n\nEvent::~Event() noexcept\n{\n    CloseHandle(m_handle);\n}\n\nvoid Event::Set() noexcept\n{\n    auto result = SetEvent(m_handle);\n    assert(result);\n    UNREFERENCED_PARAMETER(result);\n}\n\nvoid Event::Wait() noexcept\n{\n    WaitForSingleObject(m_handle, INFINITE);\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Support/event.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// RAII Win32 event wrapper\nclass Event\n{\npublic:\n    Event() noexcept;\n    ~Event() noexcept;\n    Event(const Event& other) = delete;\n    Event& operator=(Event other) = delete;\n\n    void Set() noexcept;\n    void Wait() noexcept;\n\nprivate:\n    HANDLE m_handle{ nullptr };\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Support/iso8601.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n// Functions to convert dates back and forth to the ISO8601 format\n// http://www.iso.org/iso/en/prods-services/popstds/datesandtime.html\n\n#include \"pch.h\"\n#include \"ISO8601.h\"\n#include <intsafe.h>\n\n#define ISO8601_MAX_USED_CCH 26 // Max amount of characters when generating ISO 8601 strings: YYYY-MM-DDThh:mm:ss.ssssZ + terminating zero\n\n\n// This table defines different \"types\" of characters for use as the columns\n// of the state table:\n// 0 - invalid character\n// 1 - number\n// 2 - '-'\n// 3 - date-time separator ('T', 't' and ' ')\n// 4 - ':'\n// 5 - UTC zone ('Z' and 'z')\n// 6 - '+'\n// 7 - second-fraction separator ('.' and ',')\n\nstatic const unsigned char iso8601chartable[256] =\n{\n//  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 (00 - 0f)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 (10 - 1f)\n    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 2, 7, 0, // 2 (20 - 2f)\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0, // 3 (30 - 3f)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 (40 - 4f)\n    0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, // 5 (50 - 5f)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 (60 - 6f)\n    0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, // 7 (70 - 7f)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 (80 - 8f)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 (90 - 9f)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a (a0 - af)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b (b0 - bf)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c (c0 - cf)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d (d0 - df)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e (e0 - ef)\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  // f (f0 - ff)\n};\n\n// Parsing state table is made up of WORD values with this meaning:\n//\n// |    action     | |  next state   |\n// |_|_|_|_|_|_|_|_| |_|_|_|_|_|_|_|_|\n//   HIBYTE            LOBYTE\n\n#define STENTRY WORD\n#define S(a,b) MAKEWORD(b,a)\n#define ACTION(a) HIBYTE(a)\n#define STATE(a) LOBYTE(a)\n\n// Actions\n#define _OK_  0x00 // valid character\n#define _NXT  0x01 // end of a segment, move to next\n#define _TZM  0x02 // starting '-' time zone offset\n#define _TZP  0x03 // starting '+' time zone offset\n#define _MSC  0x04 // millisecond digit\n#define _TZU  0x05 // time zone UTC\n#define _ERR  0x80 // error, invalid character\n#define ___ERROR____ MAKEWORD(0x00, _ERR)\n\n// State table\n#define STATE_TABLE_DIM 8\nstatic const STENTRY iso8601StateTable[][STATE_TABLE_DIM] =\n{\n   //  unknown       number        '-'           'T'           ':'           'Z'           '+'           '.'\n    ___ERROR____, S(_OK_,0x01), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x00 year\n    ___ERROR____, S(_OK_,0x02), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x01\n    ___ERROR____, S(_OK_,0x03), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x02\n    ___ERROR____, S(_NXT,0x04), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x03\n    ___ERROR____, S(_OK_,0x06), S(_OK_,0x05), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x04 month\n    ___ERROR____, S(_OK_,0x06), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x05\n    ___ERROR____, S(_NXT,0x07), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x06\n    ___ERROR____, S(_OK_,0x09), S(_OK_,0x08), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x07 day\n    ___ERROR____, S(_OK_,0x09), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x08\n    ___ERROR____, S(_NXT,0x0a), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x09\n    ___ERROR____, S(_OK_,0x0c), ___ERROR____, S(_OK_,0x0b), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x0a hour\n    ___ERROR____, S(_OK_,0x0c), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x0b\n    ___ERROR____, S(_NXT,0x0d), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x0c\n    ___ERROR____, S(_OK_,0x0f), S(_TZM,0x15), ___ERROR____, S(_OK_,0x0e), S(_TZU,0x1b), S(_TZP,0x15), ___ERROR____, //0x0d min\n    ___ERROR____, S(_OK_,0x0f), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x0e\n    ___ERROR____, S(_NXT,0x10), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x0f\n    ___ERROR____, S(_OK_,0x12), S(_TZM,0x15), ___ERROR____, S(_OK_,0x11), S(_TZU,0x1b), S(_TZP,0x15), ___ERROR____, //0x10 sec\n    ___ERROR____, S(_OK_,0x12), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x11\n    ___ERROR____, S(_NXT,0x13), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x12\n    ___ERROR____, ___ERROR____, S(_TZM,0x15), ___ERROR____, ___ERROR____, S(_TZU,0x1b), S(_TZP,0x15), S(_OK_,0x14), //0x13 '.' or 'Z' or '+/-'\n    ___ERROR____, S(_MSC,0x14), S(_TZM,0x15), ___ERROR____, ___ERROR____, S(_TZU,0x1b), S(_TZP,0x15), ___ERROR____, //0x14 fragment of a second\n    ___ERROR____, S(_OK_,0x16), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x15 TZ offset - hour\n    ___ERROR____, S(_NXT,0x17), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x16\n    ___ERROR____, S(_OK_,0x19), ___ERROR____, ___ERROR____, S(_OK_,0x18), ___ERROR____, ___ERROR____, ___ERROR____, //0x17 TZ offset - minute\n    ___ERROR____, S(_OK_,0x19), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x18\n    ___ERROR____, S(_NXT,0x1a), ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x19\n    ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x1a offset done - parsing done\n    ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, ___ERROR____, //0x1b UTC zone done - parsing done\n};\n\n\n#define IsLeapYear(YEARS) (                        \\\n    (((YEARS) % 400 == 0) ||                       \\\n     ((YEARS) % 100 != 0) && ((YEARS) % 4 == 0)) ? \\\n        TRUE                                       \\\n    :                                              \\\n        FALSE                                      \\\n    )\n\nstatic HRESULT _GetNumDaysForYearMonth(\n    WORD wYear,\n    WORD wMonth,\n    __out WORD *pwDays)\n{\n    HRESULT hr = S_OK;\n\n    if (NULL == pwDays ||\n        wMonth < 1 || wMonth > 12 ||\n        wYear < 1601 || wYear > 9999)\n    {\n        hr = E_INVALIDARG;\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        static const WORD s_wNumDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\n        *pwDays = s_wNumDays[wMonth - 1];\n        // Check for leap year\n        if ((wMonth == 2) && IsLeapYear(wYear))\n        {\n            (*pwDays)++;\n        }\n    }\n\n    return hr;\n}\n\n#define ONE_SECOND 10000000ui64 // number of 100-nanosecond intervals in a second\n#define ONE_MINUTE (ONE_SECOND * 60) // number of 100-nanosecond intervals in a minute\n#define ONE_HOUR (ONE_MINUTE * 60) // number of 100-nanosecond intervals in an hour\n\ntypedef union tagTU\n{\n    FILETIME ft;\n    ULARGE_INTEGER ui;\n} TU;\n\nstatic HRESULT _AddTZOffset(\n    Iso8601ParsingStage ips,\n    WORD wValue,\n    int iTZDirection,\n    _Inout_ SYSTEMTIME *pSysTime)\n{\n    HRESULT hr = S_OK;\n    _ASSERTE((ips == IPS_TZHOUR && wValue < 24) || (ips == IPS_TZMINUTE && wValue < 60));\n    _ASSERTE(iTZDirection == 1 || iTZDirection == -1);\n\n    // Convert SYSTEMTIME to FILETIME to perform date-time arithmetic\n    TU ftTime = {0};\n    if (SystemTimeToFileTime(pSysTime, &ftTime.ft))\n    {\n        ULARGE_INTEGER ulOffset;\n        ulOffset.QuadPart = (ips == IPS_TZHOUR) ? ONE_HOUR * wValue : ONE_MINUTE * wValue;\n        if (iTZDirection > 0)\n        {\n            ftTime.ui.QuadPart += ulOffset.QuadPart;\n        }\n        else\n        {\n            ftTime.ui.QuadPart -= ulOffset.QuadPart;\n        }\n        if (!FileTimeToSystemTime(&ftTime.ft, pSysTime))\n        {\n            hr = HRESULT_FROM_WIN32( GetLastError() );\n        }\n    }\n    else\n    {\n        hr = HRESULT_FROM_WIN32( GetLastError() );\n    }\n\n    return hr;\n}\n\nstatic HRESULT _CheckValueAndAddToSysTime(\n    Iso8601ParsingStage ips,\n    WORD wValue,\n    WORD wMSDigits,\n    int iTZDirection,\n    _Inout_ SYSTEMTIME *pSysTime)\n{\n    HRESULT hr = S_OK;\n    WORD wHiLimit = 0;\n    WORD wLoLimit = 0;\n    WORD *pDateWord = NULL;\n\n    _ASSERTE((iTZDirection == 0 && ips != IPS_TZHOUR && ips != IPS_TZMINUTE) ||\n        (iTZDirection != 0 && (ips == IPS_TZHOUR || ips == IPS_TZMINUTE)));\n    _ASSERTE((wMSDigits == 0 && ips != IPS_MILLISECOND) ||\n        (wMSDigits > 0 && wMSDigits < 4 && ips == IPS_MILLISECOND));\n\n    switch (ips)\n    {\n    case IPS_YEAR:\n        wLoLimit = 1601;\n        wHiLimit = 9999;\n        pDateWord  = (WORD *) &(pSysTime->wYear);\n        break;\n    case IPS_MONTH:\n        wLoLimit = 1;\n        wHiLimit = 12;\n        pDateWord  = (WORD *) &(pSysTime->wMonth);\n        break;\n    case IPS_DAY:\n        wLoLimit = 1;\n        hr = _GetNumDaysForYearMonth(pSysTime->wYear, pSysTime->wMonth, &wHiLimit);\n        _ASSERTE(SUCCEEDED(hr)); // internal call, should never fail\n        pDateWord  = (WORD *) &(pSysTime->wDay);\n        break;\n    case IPS_HOUR:\n        wLoLimit = 0;\n        wHiLimit = 23;\n        pDateWord  = (WORD *) &(pSysTime->wHour);\n        break;\n    case IPS_MINUTE:\n        wLoLimit = 0;\n        wHiLimit = 59;\n        pDateWord  = (WORD *) &(pSysTime->wMinute);\n        break;\n    case IPS_SECOND:\n        wLoLimit = 0;\n        wHiLimit = 59;\n        pDateWord  = (WORD *) &(pSysTime->wSecond);\n        break;\n    case IPS_MILLISECOND:\n        wLoLimit = 0;\n        wHiLimit = 999;\n        while (wMSDigits++ < 3)\n        {\n            wValue *= 10;\n        }\n        pDateWord  = (WORD *) &(pSysTime->wMilliseconds);\n        break;\n    case IPS_TZHOUR:\n        wLoLimit = 0;\n        wHiLimit = 23; // valid offsets appear to be -12 to +14, but we'll allow any valid hour value\n        pDateWord  = (WORD *) &(pSysTime->wHour);\n        break;\n    case IPS_TZMINUTE:\n        wLoLimit = 0;\n        wHiLimit = 59;\n        pDateWord  = (WORD *) &(pSysTime->wMinute);\n        break;\n    default:\n        hr = E_UNEXPECTED;\n        break;\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        _ASSERTE(NULL != pDateWord);\n        if (wValue < wLoLimit || wValue > wHiLimit)\n        {\n            hr = E_ABORT;\n        }\n        else\n        {\n            _ASSERTE(*pDateWord == 0 || ips >= IPS_MILLISECOND);\n            if (ips != IPS_TZHOUR && ips != IPS_TZMINUTE)\n            {\n                *pDateWord = wValue;\n            }\n            else\n            {\n                _ASSERTE(iTZDirection == 1 || iTZDirection == -1);\n                // handle offset rollover - can affect entire date\n                hr = _AddTZOffset(ips, wValue, iTZDirection, pSysTime);\n            }\n        }\n    }\n\n    return hr;\n}\n\nstatic HRESULT _iso8601ToSysTime(\n    const char *pszisoDate,\n    __out SYSTEMTIME *pSysTime,\n    __out Iso8601ParsingStage *pips)\n{\n    HRESULT hr = S_OK;\n\n    if (NULL == pszisoDate ||\n        NULL == pSysTime ||\n        NULL == pips ||\n        *pszisoDate == '\\0')\n    {\n        hr = E_INVALIDARG;\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        ZeroMemory(pSysTime, sizeof(SYSTEMTIME));\n        *pips = IPS_INVALID;\n\n        BYTE action = 0;\n        BYTE state = 0;\n        WORD DateWord = 0;\n        Iso8601ParsingStage ips = IPS_YEAR;\n        int iTZDirection = 0;\n        WORD wMSDigits = 0;\n\n        // Main state machine loop\n        while(*pszisoDate && SUCCEEDED(hr))\n        {\n            unsigned char code = iso8601chartable[*pszisoDate];\n\n            // Prevent overflows - sanity check\n            if ((code >= STATE_TABLE_DIM) ||\n                (state >= ARRAYSIZE(iso8601StateTable)))\n            {\n                hr = E_UNEXPECTED;\n                break;\n            }\n\n            STENTRY stValue = iso8601StateTable[state][code];\n            state = STATE(stValue);\n            action = ACTION(stValue);\n\n            switch(action)\n            {\n            case _OK_: // input OK, valid character\n            case _NXT: // finish piece and advance to next stage, valid character\n                {\n                    if (code == 1)\n                    {\n                        DateWord = (DateWord * 10) + (*pszisoDate - '0');\n                    }\n\n                    if (action == _NXT)\n                    {\n                        hr = _CheckValueAndAddToSysTime(ips, DateWord, 0 /*wMSDigits*/, iTZDirection, pSysTime);\n                        DateWord = 0;\n                        if (SUCCEEDED(hr))\n                        {\n                            *pips = ips;\n                            ips = Iso8601ParsingStage(int(ips) + 1);\n                        }\n                    }\n                }\n                break;\n            case _TZM: // start '-' timezone offset\n                iTZDirection = 1;\n                DateWord = 0;\n                *pips = ips;\n                ips = IPS_TZHOUR;\n                break;\n            case _TZP: // start '+' timezone offset\n                iTZDirection = -1;\n                DateWord = 0;\n                *pips = ips;\n                ips = IPS_TZHOUR;\n                break;\n            case _MSC:  // process millisecond digit\n                _ASSERTE(code == 1 && ips == IPS_MILLISECOND);\n                wMSDigits++;\n                if (wMSDigits < 4) \n                {\n                    DateWord = (DateWord * 10) + (*pszisoDate - '0');\n\n                    hr = _CheckValueAndAddToSysTime(ips, DateWord, wMSDigits, iTZDirection, pSysTime);\n                    if (SUCCEEDED(hr))\n                    {\n                        *pips = IPS_MILLISECOND;\n                    }\n                }\n                break;\n            case _TZU: // 'Z' for UTC zone\n                *pips = IPS_TZUTC;\n                ips = IPS_TZUTC;\n                break;\n            case _ERR: // error, invalid character\n                _ASSERTE(state == 0x00);\n                hr = E_ABORT;\n                break;\n            default:\n                hr = E_UNEXPECTED;\n                break;\n            }\n\n            pszisoDate++;\n        }\n\n        if (SUCCEEDED(hr) && *pszisoDate == '\\0')\n        {\n            if (action != _NXT && action != _MSC && action != _TZU)\n            {\n                hr = E_ABORT;\n            }\n        }\n\n        if (hr != S_OK && hr != E_ABORT)\n        {\n            *pips = IPS_INVALID;\n        }\n    }\n\n    _ASSERTE(hr != E_UNEXPECTED);\n    return hr;\n}\n\nstatic HRESULT _iso8601ToFileTime(\n    const char *pszisoDate,\n    __out FILETIME *pftTime,\n    __out Iso8601ParsingStage *pips)\n{\n    HRESULT hr = S_OK;\n    SYSTEMTIME stTime = {0};\n\n    hr = _iso8601ToSysTime(pszisoDate, &stTime, pips);\n    if (SUCCEEDED(hr))\n    {\n        if (!SystemTimeToFileTime(&stTime, pftTime))\n        {\n            hr = E_FAIL;\n        }\n    }\n\n    return hr;\n}\n\nstatic HRESULT _SysTimeToiso8601(\n    _In_ SYSTEMTIME *pstTime,\n    _In_ BOOL fGeneratePartial,\n    __out_ecount(cch) char *pszBuf,\n    _In_ ULONG cch,\n    _In_ BOOL fUseShortTimeFormat = FALSE\n    )\n{\n    HRESULT hr = S_OK;\n\n    if (NULL == pstTime ||\n        NULL == pszBuf ||\n        cch < ISO8601_MAX_USED_CCH)\n    {\n        hr = E_INVALIDARG;\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        if (pstTime->wYear < 1601 || // FILETIME cannot handle less\n        pstTime->wYear > 9999 || // ISO8601 has four digits for a year\n        pstTime->wMonth > 12 ||\n        pstTime->wDay > 31 ||\n        pstTime->wHour > 24 ||\n        pstTime->wMinute > 59 ||\n        pstTime->wSecond > 59 ||\n        pstTime->wMilliseconds > 999)\n        {\n            hr = E_INVALIDARG;\n        }\n\n        if (SUCCEEDED(hr))\n        {\n            WORD wDays = 0;\n            hr = _GetNumDaysForYearMonth(pstTime->wYear, pstTime->wMonth, &wDays);\n            if (SUCCEEDED(hr) && pstTime->wDay > wDays)\n            {\n                hr = E_INVALIDARG;\n            }\n        }\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        pszBuf[0] = static_cast<char>((pstTime->wYear / 1000) + '0');\n        pszBuf[1] = static_cast<char>(((pstTime->wYear / 100) % 10) + '0');\n        pszBuf[2] = static_cast<char>(((pstTime->wYear / 10) % 10) + '0');\n        pszBuf[3] = static_cast<char>(((pstTime->wYear) % 10) + '0');\n        if (pstTime->wMonth > 0 ||\n            !fGeneratePartial)\n        {\n            pszBuf[4] = '-';\n            pszBuf[5] = static_cast<char>((pstTime->wMonth / 10) + '0');\n            pszBuf[6] = static_cast<char>((pstTime->wMonth % 10) + '0');\n            if (pstTime->wDay > 0 ||\n                !fGeneratePartial)\n            {\n                pszBuf[7] = '-';\n                pszBuf[8] = static_cast<char>((pstTime->wDay / 10) + '0');\n                pszBuf[9] = static_cast<char>((pstTime->wDay % 10) + '0');\n                if (pstTime->wHour != 0 ||\n                    pstTime->wMinute != 0 ||\n                    pstTime->wSecond != 0 ||\n                    pstTime->wMilliseconds != 0 ||\n                    !fGeneratePartial)\n                {\n                    pszBuf[10] = 'T';\n                    pszBuf[11] = static_cast<char>(pstTime->wHour / 10 + '0');\n                    pszBuf[12] = static_cast<char>((pstTime->wHour % 10) + '0');\n                    pszBuf[13] = ':';\n                    pszBuf[14] = static_cast<char>(pstTime->wMinute / 10 + '0');\n                    pszBuf[15] = static_cast<char>((pstTime->wMinute % 10) + '0');\n                    pszBuf[16] = ':';\n                    pszBuf[17] = static_cast<char>(pstTime->wSecond / 10 + '0');\n                    pszBuf[18] = static_cast<char>((pstTime->wSecond % 10) + '0');\n                    if ( !fUseShortTimeFormat && ( pstTime->wMilliseconds != 0 ) )\n                    {\n                        // YYYY-MM-DDThh:mm:ss.ssssZ\n                        pszBuf[19] = '.';\n                        pszBuf[20] = static_cast<char>(pstTime->wMilliseconds / 100 + '0');\n                        pszBuf[21] = static_cast<char>(((pstTime->wMilliseconds / 10) % 10) + '0');\n                        pszBuf[22] = static_cast<char>((pstTime->wMilliseconds % 10) + '0');\n\n                        // pad the last digit of millisecond with 0\n                        pszBuf[23] = '0';\n                        pszBuf[24] = 'Z';\n                        pszBuf[25] = 0;\n                    }\n                    else\n                    {\n                        // YYYY-MM-DDThh:mm:ssZ\n                        pszBuf[19] = 'Z';\n                        pszBuf[20] = 0;\n                    }\n                }\n                else\n                {\n                    // YYYY-MM-DD\n                    pszBuf[10] = 0;\n                }\n            }\n            else\n            {\n                // YYYY-MM\n                pszBuf[7] = 0;\n            }\n        }\n        else\n        {\n            // YYYY\n            pszBuf[4] = 0;\n        }\n    }\n\n    return hr;\n}\n\nstatic HRESULT _FileTimeToiso8601(\n    const FILETIME *pftTime,\n    BOOL fGeneratePartial,\n    __out_ecount(cch) char *pszBuf,\n    ULONG cch,\n    BOOL fUseShortTimeFormat\n    )\n{\n    HRESULT hr = S_OK;\n    SYSTEMTIME stTime = {0};\n\n    if (NULL == pftTime)\n    {\n        hr = E_INVALIDARG;\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        if (FileTimeToSystemTime( pftTime, &stTime))\n        {\n            hr = _SysTimeToiso8601( &stTime, fGeneratePartial, pszBuf, cch, fUseShortTimeFormat );\n        }\n        else\n        {\n            hr = E_FAIL;\n        }\n    }\n\n    return hr;\n}\n\nHRESULT FILETIMEToISO8601W(\n    _In_ const FILETIME* pft,\n    _In_ BOOL fGeneratePartial,\n    __out_ecount(cchISO8601) PWSTR pszISO8601,\n    _In_ size_t cchISO8601,\n    _In_ BOOL fUseShortTimeFormat\n    )\n{\n    HRESULT hr = S_OK;\n\n    CHAR aszISO8601[ISO8601_MAX_USED_CCH];\n    hr = _FileTimeToiso8601( pft, fGeneratePartial, aszISO8601, ARRAYSIZE(aszISO8601), fUseShortTimeFormat );\n    if (SUCCEEDED(hr))\n    {\n        int cchSHAnsiToUnicode;\n        hr = SizeTToInt(cchISO8601, &cchSHAnsiToUnicode);\n        if (SUCCEEDED(hr))\n        {\n            hr = ( ISO8601_MAX_USED_CCH >= ::MultiByteToWideChar(\n                    CP_ACP,\n                    0,\n                    aszISO8601,\n                    -1,\n                    pszISO8601, cchSHAnsiToUnicode) ) ? S_OK : E_UNEXPECTED;\n            _ASSERTE(SUCCEEDED(hr));\n        }\n    }\n\n    return hr;\n}\n\nHRESULT ISO8601ToFILETIMEW(\n    _In_ PCWSTR pszISO8601,\n    __out FILETIME* pft,\n    __out Iso8601ParsingStage *pips)\n{\n    HRESULT hr = S_OK;\n\n    CHAR aszISO8601[ISO8601_MAX_CCH];\n\n    if( !::WideCharToMultiByte(\n        CP_ACP,\n        0,\n        pszISO8601,\n        -1,\n        aszISO8601,\n        ISO8601_MAX_CCH,\n        NULL,\n        NULL ) )\n    {\n        hr = HRESULT_FROM_WIN32( GetLastError() );\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        hr = _iso8601ToFileTime(aszISO8601, pft, pips);\n    }\n\n    return hr;\n}\n\nHRESULT SYSTEMTIMEToISO8601ExW(\n    _In_ const SYSTEMTIME* pst,\n    _In_ BOOL fGeneratePartial,\n    __out_ecount(cchISO8601) PWSTR pszISO8601,\n    _In_ size_t cchISO8601)\n{\n    HRESULT hr = S_OK;\n\n    SYSTEMTIME st = *pst;\n    CHAR aszISO8601[ISO8601_MAX_USED_CCH];\n    hr = _SysTimeToiso8601(&st, fGeneratePartial, aszISO8601, ARRAYSIZE(aszISO8601));\n    if (SUCCEEDED(hr))\n    {\n        int cchSHAnsiToUnicode;\n        hr = SizeTToInt(cchISO8601, &cchSHAnsiToUnicode);\n        if (SUCCEEDED(hr))\n        {\n            hr = ( ISO8601_MAX_USED_CCH >= ::MultiByteToWideChar(\n                    CP_ACP,\n                    0,\n                    aszISO8601,\n                    -1,\n                    pszISO8601,\n                    cchSHAnsiToUnicode ) ) ? S_OK : E_UNEXPECTED;\n            _ASSERTE(SUCCEEDED(hr));\n        }\n    }\n\n    return hr;\n}\n\nHRESULT SYSTEMTIMEToISO8601W(\n    _In_ const SYSTEMTIME* pst,\n    __out_ecount(cchISO8601) PWSTR pszISO8601,\n    _In_ size_t cchISO8601)\n{\n    return SYSTEMTIMEToISO8601ExW(pst, FALSE /*fGeneratePartial*/, pszISO8601, cchISO8601);\n}\n\nHRESULT ISO8601ToSYSTEMTIMEExW(\n    _In_ PCWSTR pszISO8601,\n    __out SYSTEMTIME* pst,\n    __out Iso8601ParsingStage *pips)\n{\n    HRESULT hr = S_OK;\n\n    CHAR aszISO8601[ISO8601_MAX_CCH];\n\n    if( !::WideCharToMultiByte(\n        CP_ACP,\n        0,\n        pszISO8601,\n        -1,\n        aszISO8601,\n        ISO8601_MAX_CCH,\n        NULL,\n        NULL ) )\n    {\n        hr = HRESULT_FROM_WIN32( GetLastError() );\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        hr = _iso8601ToSysTime(aszISO8601, pst, pips);\n    }\n\n    return hr;\n}\n\nHRESULT ISO8601ToSYSTEMTIMEW(\n    _In_ PCWSTR pszISO8601,\n    __out SYSTEMTIME* pst)\n{\n    HRESULT hr = S_OK;\n    Iso8601ParsingStage ips = IPS_INVALID;\n\n    hr = ISO8601ToSYSTEMTIMEExW(pszISO8601, pst, &ips);\n\n    // Fix up less-than-full-date\n    if (SUCCEEDED(hr) && ips < IPS_DAY)\n    {\n        if (ips < IPS_DAY)\n        {\n            pst->wDay = 1;\n        }\n        if (ips < IPS_MONTH)\n        {\n            pst->wMonth = 1;\n        }\n        hr = S_OK;\n    }\n\n    return hr;\n}\n"
  },
  {
    "path": "Tests/UnitTests/Support/iso8601.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n// Functions to convert dates back and forth to the ISO8601 format\n// (http://www.iso.org/iso/en/prods-services/popstds/datesandtime.html)\n//\n// Supported dates are from 1601-01-01 (SYSTEMTIME and FILETIME limitation) to\n// 9999-12-31 (ISO8601 limitation)\n\n// Longest form of ISO8601 is 40 chars + 1 for terminating zero\n#define ISO8601_MAX_CCH 41\n\n// Iso8601ParsingStage enum\n//\n// This enumeration is design so values can be compared.\n// ISO8601 dates look like this: YYYY-MM-DDThh:mm:ss.sss+/-hh:mm\n// So e.g. by parsing the date and then asking if parse stage was\n// <IPS_HOUR you can tell if string contained any time at all, or just the date\nenum Iso8601ParsingStage\n{\n    IPS_INVALID = -1,\n    IPS_YEAR = 0,\n    IPS_MONTH,\n    IPS_DAY,\n    IPS_HOUR,\n    IPS_MINUTE,\n    IPS_SECOND,\n    IPS_MILLISECOND,\n    IPS_TZHOUR,\n    IPS_TZMINUTE,\n    IPS_TZUTC,\n};\n\nHRESULT\nFILETIMEToISO8601W(\n    _In_ const FILETIME* pft,\n    _In_ BOOL fGeneratePartial,\n    __out_ecount(cchISO8601) PWSTR pszISO8601,\n    _In_ size_t cchISO8601,\n    _In_ BOOL fUseShortTimeFormat = FALSE\n    );\n\nHRESULT\nISO8601ToFILETIMEW(\n    _In_ PCWSTR pszISO8601,\n    __out FILETIME* pft,\n    __out Iso8601ParsingStage* pips\n    );\n\nHRESULT\nSYSTEMTIMEToISO8601ExW(\n    _In_ const SYSTEMTIME* pst,\n    _In_ BOOL fGeneratePartial,\n    __out_ecount(cchISO8601) PWSTR pszISO8601,\n    _In_ size_t cchISO8601\n    );\n\nHRESULT\nSYSTEMTIMEToISO8601W(\n    _In_ const SYSTEMTIME* pst,\n    __out_ecount(cchISO8601) PWSTR pszISO8601,\n   _In_  size_t cchISO8601\n   );\n\nHRESULT\nISO8601ToSYSTEMTIMEExW(\n    _In_ PCWSTR pszISO8601,\n    __out SYSTEMTIME* pst,\n    __out Iso8601ParsingStage* pips\n    );\n\nHRESULT ISO8601ToSYSTEMTIMEW(\n    _In_ PCWSTR pszISO8601,\n    __out SYSTEMTIME* pst\n    );\n"
  },
  {
    "path": "Tests/UnitTests/Support/unit_test_helpers.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"unit_test_helpers.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// Enable this flag to run UnitTests with a manual dispatch XTaskQueue where all XSAPI background work will\n// be dispatched to a single thread.\n#define USE_MANUAL_DISPATCH_QUEUE 0\n\n// A simple, single threaded XTaskQueue dispatcher that will validate that XSAPI doesn't submit anything to or\n// process anything on its background XTaskQueue after XblCleanup has completed\nstruct SingleThreadDispatcher : public ITaskQueueDispatcher\n{\npublic:\n    SingleThreadDispatcher()\n    {\n        XTaskQueueHandle queueHandle{ nullptr };\n        HRESULT hr = XTaskQueueCreate(XTaskQueueDispatchMode::Manual, XTaskQueueDispatchMode::Manual, &queueHandle);\n        assert(SUCCEEDED(hr));\n        m_queue = TaskQueue{ queueHandle };\n\n        hr = XTaskQueueRegisterMonitor(queueHandle, this, OnWorkSubmitted, &m_monitorToken);\n        assert(SUCCEEDED(hr));\n\n        m_dispatchThread = std::thread([this]\n        {\n            for (;;)\n            {\n                if (m_shutdown)\n                {\n                    constexpr uint32_t finalDispatchTimeout{ 2000 };\n                    // After m_shutdown is signaled, wait an addition 2 seconds and ensure nothing is processed.\n                    // XblCleanup has completed, so nothing more should be submitted to /processed on m_queue\n                    auto processed = XTaskQueueDispatch(m_queue.GetHandle(), XTaskQueuePort::Work, finalDispatchTimeout);\n                    UNREFERENCED_PARAMETER(processed);\n                    assert(!processed);\n                    break;\n                }\n                else\n                {\n                    constexpr uint32_t dispatchTimeout{ 10 };\n                    XTaskQueueDispatch(m_queue.GetHandle(), XTaskQueuePort::Work, dispatchTimeout);\n                }\n            }\n        });\n    }\n\n    ~SingleThreadDispatcher()\n    {\n        m_shutdown = true;\n        m_dispatchThread.join();\n\n        XTaskQueueUnregisterMonitor(m_queue.GetHandle(), m_monitorToken);\n    }\n\n    XTaskQueueHandle TaskQueueHandle() const\n    {\n        return m_queue.GetHandle();\n    }\n\nprivate:\n    static void CALLBACK OnWorkSubmitted(void* context, XTaskQueueHandle queue, XTaskQueuePort)\n    {\n        UNREFERENCED_PARAMETER(context);\n        UNREFERENCED_PARAMETER(queue);\n\n#if _DEBUG\n        auto pThis{ static_cast<SingleThreadDispatcher*>(context) };\n        assert(pThis);\n        assert(queue == pThis->m_queue.GetHandle());\n\n        // Nothing should be submitted to the queue after XblCleanup has completed\n        assert(!pThis->m_shutdown);\n#endif\n    }\n\n    TaskQueue m_queue;\n    std::thread m_dispatchThread;\n    std::atomic<bool> m_shutdown{ false };\n    XTaskQueueRegistrationToken m_monitorToken{};\n};\n\nTestEnvironment::TestEnvironment() noexcept\n{\n    XblInitArgs args{};\n    args.scid = MOCK_SCID;\n\n#if USE_MANUAL_DISPATCH_QUEUE\n    auto dispatcher = std::make_shared<SingleThreadDispatcher>();\n    args.queue = dispatcher->TaskQueueHandle();\n    m_dispatcher = dispatcher;\n#endif\n\n    // Use current directory for local storage path\n    char pathArray[MAX_PATH + 1];\n    GetCurrentDirectoryA(MAX_PATH + 1, pathArray);\n    auto pathString = std::string{ pathArray } +'\\\\';\n    args.localStoragePath = pathString.data();\n\n    // Enable debug logging\n    HCSettingsSetTraceLevel(HCTraceLevel::Verbose);\n    HCTraceSetTraceToDebugger(true);\n\n    VERIFY_SUCCEEDED(XblInitialize(&args));\n}\n\nTestEnvironment::TestEnvironment(const XblInitArgs* args)\n{\n    HCSettingsSetTraceLevel(HCTraceLevel::Verbose);\n    HCTraceSetTraceToDebugger(true);\n\n    VERIFY_SUCCEEDED(XblInitialize(args));\n}\n\nTestEnvironment::~TestEnvironment() noexcept\n{\n    XAsyncBlock asyncBlock{};\n    VERIFY_SUCCEEDED(XblCleanupAsync(&asyncBlock));\n    VERIFY_SUCCEEDED(XAsyncGetStatus(&asyncBlock, true));\n\n    HCTraceSetTraceToDebugger(false);\n\n    // Clean up Mock RTA & websocket handlers\n    MockRtaService().SetSubscribeHandler(nullptr);\n    system::MockWebsocket::SetConnectHandler(nullptr);\n}\n\nstd::shared_ptr<XblContext> TestEnvironment::CreateMockXboxLiveContext(\n    uint64_t xuid,\n    const std::string& gamertag\n) const noexcept\n{\n    auto context = XblContext::Make(std::move(CreateMockUser(xuid, gamertag)));\n    VERIFY_SUCCEEDED(context->Initialize(GlobalState::Get()->RTAManager()));\n    return context;\n}\n\nstd::shared_ptr<xbox_live_context> TestEnvironment::CreateLegacyMockXboxLiveContext(\n    uint64_t xuid,\n    const std::string& gamertag\n) const noexcept\n{\n    auto context = XblContext::Make(std::move(CreateMockUser(xuid, gamertag)));\n    VERIFY_SUCCEEDED(context->Initialize(GlobalState::Get()->RTAManager()));\n    return std::make_shared<xbox_live_context>(context.get());\n}\n\nsystem::MockRealTimeActivityService& TestEnvironment::MockRtaService() const noexcept\n{\n    return system::MockRealTimeActivityService::Instance();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Support/unit_test_helpers.h",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#pragma once\n\n#include \"mock_rta_service.h\"\n\n#define MOCK_LOCALID 101010101010101\n#define MOCK_XUID 101010101010\n#define MOCK_GAMERTAG \"MockLocalUser\"\n#define MOCK_SCID \"MockScid\"\n#define MOCK_TITLEID 1234\n#define MOCK_SANDBOX \"MockSandbox\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\n// Create a mock User. Doesn't depend on any XSAPI public APIs since it's just a wrapper around Xal mocks\nUser CreateMockUser(\n    uint64_t xuid = MOCK_XUID,\n    const std::string& gamertag = MOCK_GAMERTAG,\n    uint64_t localId = MOCK_LOCALID\n);\n\n// Base class for manual XTaskQueue dispatcher\nstruct ITaskQueueDispatcher\n{\npublic:\n    virtual ~ITaskQueueDispatcher() = default;\nprotected:\n    ITaskQueueDispatcher() = default;\n};\n\n// RAII Wrapper class around XblInitialize/XblCleanup. Each test method should assume XSAPI\n// is not initialized and it should end in a clean state (whether it succeeds or fails).\nclass TestEnvironment\n{\npublic:\n    TestEnvironment() noexcept;\n    TestEnvironment(const XblInitArgs* args);\n    virtual ~TestEnvironment() noexcept;\n\n    // Create an XblContext with a mock XalUser\n    std::shared_ptr<XblContext> CreateMockXboxLiveContext(\n        uint64_t xuid = MOCK_XUID,\n        const std::string& gamertag = MOCK_GAMERTAG\n    ) const noexcept;\n\n    std::shared_ptr<xbox_live_context> CreateLegacyMockXboxLiveContext(\n        uint64_t xuid = MOCK_XUID,\n        const std::string& gamertag = MOCK_GAMERTAG\n    ) const noexcept;\n\n    system::MockRealTimeActivityService& MockRtaService() const noexcept;\n\nprivate:\n    std::shared_ptr<ITaskQueueDispatcher> m_dispatcher{ nullptr };\n};\n\ninline bool VerifyTime(\n    time_t time,\n    const std::string& timeString\n)\n{\n    auto datetime = xbox::services::datetime::from_string(timeString.data(), xbox::services::datetime::date_format::ISO_8601);\n    return xbox::services::utils::time_t_from_datetime(datetime) == time;\n}\n\ninline bool VerifyJson(\n    const JsonValue& expected,\n    const char* actual\n)\n{\n    JsonDocument actualJson{};\n    actualJson.Parse(actual);\n    if (actualJson.HasParseError())\n    {\n        return false;\n    }\n\n    return expected == actualJson;\n}\n\ninline bool VerifyJson(\n    const char* expected,\n    const char* actual\n)\n{\n    JsonDocument expectedJson{};\n    expectedJson.Parse(expected);\n    if (expectedJson.HasParseError())\n    {\n        return false;\n    }\n\n    return VerifyJson(expectedJson, actual);\n}\n\ninline std::string GetTestBasePath()\n{\n#ifdef USING_TAEF\n    // Find TAEF DLL and use that as base path\n    char path[MAX_PATH] = { 0 };\n    HMODULE module = NULL;\n    if (GetModuleHandleEx(\n        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, \n        (LPCWSTR)&CreateMockUser, &module) != 0)\n    {\n        if (GetModuleFileNameA(module, path, sizeof(path)) != 0)\n        {\n            *strrchr(path, '\\\\') = 0;\n            std::string folder = std::string(path);\n            return folder + \"\\\\\";\n        }\n    }\n\n    assert(false);\n#endif\n\n    return \"\";\n}\n\ninline JsonDocument GetTestResponses(\n    const char* filePath\n)\n{\n    std::string path = GetTestBasePath() + filePath;\n    std::ifstream fileStream{ path, std::ifstream::binary };\n\n    std::stringstream buffer;\n    buffer << fileStream.rdbuf();\n\n    JsonDocument d;\n    d.Parse(buffer.str().data());\n    return d;\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/AchievementsManagerTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"xsapi-c/achievements_manager_c.h\"\n#include \"Achievements/Manager/achievements_manager_internal.h\"\n\nusing namespace xbox::services::achievements::manager;\nusing namespace xbox::services::real_time_activity;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char* defaultAchievementsUri = \"https://achievements.xboxlive.com\";\nconst char* defaultNotificationUri = \"https://notify.xboxlive.com\";\n\nconst char* achievementId2013MultipleRequirements = \"2\";\nconst char* achievementId2013MultipleRequirementsAchieved = \"3\";\nconst char* achievementId2013SingleRequirement = \"4\";\nconst char* achievementId2017NotStarted = \"5\";\nconst char* achievementId2017InProgress = \"6\";\nconst char* achievementId2017Achieved = \"7\";\nconst char* achievementIdDoesNotExist = \"8\";\nconst char* defaultAchievementId = achievementId2013MultipleRequirements;\nconst uint8_t achievementInProgressStartProgress = 20;\nconst char* achievementUnlockTime = \"2013-01-17T03:19:00.3087016Z\";\n\nconst char defaultAchievementResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char multipageAchievementPage1Response[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":\"abc123\",\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char multipageAchievementPage2Response[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char firstUserGetAchievementsResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char secondUserGetAchievementsResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"InProgress\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : \"20\",\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char firstUserResyncNotStartedResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char firstUserResyncFinishedResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : \"100\",\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : \"100\",\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char firstUserUpdateAchievementsResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"2\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"InProgress\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789777\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"4\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789444\",\n                \"current\" : null,\n                \"target\" : \"48\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"6\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"InProgress\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789555\",\n                \"current\" : \"20\",\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\n// rta response\n\nconst char getSortedAchievementsResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"2\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"InProgress\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789777\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"5\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"NotStarted\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789333\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\": \"0001-01-01T00:00:00Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    },\n    {\n        \"id\":\"7\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789555\",\n                \"current\" : \"100\",\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            }],\n            \"timeUnlocked\":\"2017-10-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char rtaAchievementProgressChangedPayload[] =\nR\"(\n{\n    \"progression\": [\n        {\n            \"id\" : \"5\",\n            \"progressState\" : \"InProgress\",\n            \"timeUnlocked\" : \"2013-01-17T03:19:00.3087016Z\",\n            \"requirements\" : [\n                {\n                    \"id\":\"12345678-1234-1234-1234-123456789333\", \n                    \"current\":\"20\", \n                    \"operationType\" : \"sum\",\n                    \"valueType\" : \"Integer\",\n                    \"ruleParticipationType\" : \"Individual\"\n                }\n            ]\n        }\n    ],\n    \"serviceConfigId\" : \"87654321-4321-4321-4321-210987654321\"\n}\n)\";\n\n// check to see if updating progress to 100 will cause the resulting rta\n// notification to have progress state be updated to achieved, otherwise\n// this needs to be updated to be \"InProgress\" again\nconst char rtaAchievementProgressChangedCompletePayload[] =\nR\"(\n{\n    \"progression\": [\n        {\n            \"id\" : \"6\",\n            \"progressState\" : \"Achieved\",\n            \"timeUnlocked\" : \"2013-01-17T03:19:00.3087016Z\",\n            \"requirements\" : [\n                {\n                    \"id\":\"12345678-1234-1234-1234-123456789333\", \n                    \"current\":\"100\", \n                    \"target\":\"100\",\n                    \"operationType\" : \"sum\",\n                    \"valueType\" : \"Integer\",\n                    \"ruleParticipationType\" : \"Individual\"\n                }\n            ]\n        }\n    ],\n    \"serviceConfigId\" : \"87654321-4321-4321-4321-210987654321\"\n}\n)\";\n\nDEFINE_TEST_CLASS(AchievementsManagerTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(AchievementsManagerTests);\n\n    static const JsonDocument testJson;\n    static const JsonValue& defaultAchievementJson;\nprivate:\n    class AMTestEnvironment : public TestEnvironment\n    {\n    public:\n        AMTestEnvironment() noexcept\n        {\n            auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n            mockRtaService.SetSubscribeHandler(\n                [&](uint32_t n, xsapi_internal_string)\n                {\n                    mockRtaService.CompleteSubscribeHandshake(n);\n                }\n            );\n        }\n\n        ~AMTestEnvironment() noexcept\n        {\n            // remove all local users\n            for (auto context : m_testContexts)\n            {\n                XblAchievementsManagerRemoveLocalUser(context->User().Handle());\n            }\n        }\n\n        Vector<std::shared_ptr<XblContext>> m_testContexts;\n    };\n\n    void AddLocalUserWithoutSyncHelper(const User& user)\n    {\n        XTaskQueueHandle queue{};\n\n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(defaultAchievementResponse); // mock the response of Get Achievements\n\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n            {\n                if (uri.find(defaultAchievementsUri) != xsapi_internal_string::npos\n                    || uri.find(defaultNotificationUri) != xsapi_internal_string::npos)\n                {\n                    mockRtaService.CompleteSubscribeHandshake(n);\n                }\n            });\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerAddLocalUser(user.Handle(), queue));\n    }\n       \n    void AddLocalUserSyncHelper(const User& user, const char* response = defaultAchievementResponse)\n    {\n        XTaskQueueHandle queue{};\n        \n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(response); // mock the response of Get Achievements\n\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n            {\n                if (uri.find(defaultAchievementsUri) != xsapi_internal_string::npos\n                    || uri.find(defaultNotificationUri) != xsapi_internal_string::npos)\n                {\n                    mockRtaService.CompleteSubscribeHandshake(n);\n                }\n            });\n        \n        VERIFY_SUCCEEDED(XblAchievementsManagerAddLocalUser(user.Handle(), queue));\n\n        // verify UserAdded event is received\n        int count{ 0 };\n        bool userAdded{ false };\n        while (!userAdded)\n        {\n            if (++count > 500)\n            {\n                break;\n            }\n\n            size_t eventsCount{};\n            const XblAchievementsManagerEvent* events{};\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventsCount));\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].eventType)\n                {\n                case XblAchievementsManagerEventType::LocalUserInitialStateSynced:\n                    userAdded = true;\n                    break;\n                default:\n                    break;\n                }\n            }\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(userAdded);\n        // verify the user is in the list of users\n        auto state{ GlobalState::Get() };\n        VERIFY_IS_TRUE(state->AchievementsManager()->HasUser(user.Xuid()));\n        VERIFY_IS_TRUE(state->AchievementsManager()->IsUserInitialized(user.Xuid()));\n        \n        // check for contents of achievements array is the expected size\n        JsonDocument doc;\n        doc.Parse(response);\n        VERIFY_IS_TRUE(doc.FindMember(\"achievements\")->value.IsArray());\n        VERIFY_ARE_EQUAL_INT(\n            state->AchievementsManager()->GetUserAchievementCount(user.Xuid()), \n            doc[\"achievements\"].GetArray().Size()\n        );\n    }\n\n    void AddLocalUserMultiplePageHelper(const User& user)\n    {\n        XTaskQueueHandle queue{};\n        Vector<HttpMock> achievementMocks;\n\n        HttpMock initialPageMock{ \"Get\", defaultAchievementsUri };\n        initialPageMock.SetResponseBody(multipageAchievementPage1Response);\n        achievementMocks.emplace_back(std::move(initialPageMock));\n\n        HttpMock secondPageMock{ \n            \"Get\", \n            \"https://achievements.xboxlive.com/users/xuid(1234)/achievements?titleId=1234&maxItems=100&continuationToken=\"\n        };\n        secondPageMock.SetResponseBody(multipageAchievementPage2Response);\n        achievementMocks.emplace_back(std::move(secondPageMock));\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerAddLocalUser(user.Handle(), queue));\n\n        // verify UserAdded event is received\n        int count{ 0 };\n        bool userAdded{ false };\n        while (!userAdded)\n        {\n            if (++count > 500)\n            {\n                break;\n            }\n\n            size_t eventsCount{};\n            const XblAchievementsManagerEvent* events{};\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventsCount));\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].eventType)\n                {\n                case XblAchievementsManagerEventType::LocalUserInitialStateSynced:\n                    userAdded = true;\n                    break;\n                default:\n                    break;\n                }\n            }\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(userAdded);\n        // verify the user is in the list of users\n        auto state{ GlobalState::Get() };\n        VERIFY_IS_TRUE(state->AchievementsManager()->HasUser(user.Xuid()));\n        // check for initialized?\n        VERIFY_IS_TRUE(state->AchievementsManager()->IsUserInitialized(user.Xuid()));\n\n        uint64_t expectedAchievementsInResponses = 0;\n        JsonDocument doc;\n        doc.Parse(multipageAchievementPage1Response);\n        VERIFY_IS_TRUE(doc.FindMember(\"achievements\")->value.IsArray());\n        expectedAchievementsInResponses += doc[\"achievements\"].GetArray().Size();\n\n        doc = JsonDocument();\n        doc.Parse(multipageAchievementPage2Response);\n        VERIFY_IS_TRUE(doc.FindMember(\"achievements\")->value.IsArray());\n        expectedAchievementsInResponses += doc[\"achievements\"].GetArray().Size();\n\n        VERIFY_ARE_EQUAL_INT(\n            state->AchievementsManager()->GetUserAchievementCount(user.Xuid()),\n            expectedAchievementsInResponses\n        );\n    }\n\n    void AddMultipleLocalUsersHelper(const Map<std::shared_ptr<XblContext>, const char*>& userResponseMap)\n    {\n        XTaskQueueHandle queue{};\n        Vector<HttpMock> achievementMocks;\n\n        // create a mock for each of the users\n        for (auto& pair : userResponseMap)\n        {\n            Stringstream uri;\n            uri << \"https://achievements.xboxlive.com/users/xuid(\";\n            uri << pair.first->User().Xuid();\n            uri << \")/achievements\";\n            \n            HttpMock mock(\"Get\", uri.str());\n            achievementMocks.emplace_back(std::move(mock));\n            // set the response body for each of the mocks\n            achievementMocks.back().SetResponseBody(pair.second);\n        }\n        // call add user for each user\n        for (auto& pair : userResponseMap)\n        {\n            VERIFY_SUCCEEDED(XblAchievementsManagerAddLocalUser(pair.first->User().Handle(), queue));\n        }\n\n        // verify each user is added\n        // verify UserAdded event is received\n        int count{ 0 };\n        uint32_t usersAdded{ 0 };\n        while (usersAdded < userResponseMap.size())\n        {\n            if (++count > 500)\n            {\n                break;\n            }\n\n            size_t eventsCount{};\n            const XblAchievementsManagerEvent* events{};\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventsCount));\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].eventType)\n                {\n                case XblAchievementsManagerEventType::LocalUserInitialStateSynced:\n                    ++usersAdded;\n                    break;\n                default:\n                    break;\n                }\n            }\n            Sleep(10);\n        }\n\n        VERIFY_ARE_EQUAL_INT(usersAdded, userResponseMap.size());\n        // verify the user is in the list of users\n        auto state{ GlobalState::Get() };\n        for (auto& pair : userResponseMap)\n        {\n            VERIFY_IS_TRUE(state->AchievementsManager()->HasUser(pair.first->User().Xuid()));\n            VERIFY_IS_TRUE(state->AchievementsManager()->IsUserInitialized(pair.first->User().Xuid()));\n            \n            // check for contents of achievements array is the expected size\n            JsonDocument doc;\n            doc.Parse(pair.second);\n            VERIFY_IS_TRUE(doc.FindMember(\"achievements\")->value.IsArray());\n            VERIFY_ARE_EQUAL_INT(\n                state->AchievementsManager()->GetUserAchievementCount(pair.first->User().Xuid()),\n                doc[\"achievements\"].GetArray().Size()\n            );\n        }       \n    }\n\n    void SetupRtaResponseForUser(uint64_t xuid, String method, String progressPayload, Vector<std::shared_ptr<HttpMock>>& mocks)\n    {\n        Stringstream uri;\n        uri << \"https://achievements.xboxlive.com/users/xuid(\";\n        uri << xuid;\n        uri << \")/achievements\";\n\n        std::shared_ptr<HttpMock> mock = std::make_shared<HttpMock>(method.c_str(), uri.str());\n        mocks.emplace_back(std::move(mock));\n        mocks.back()->SetResponseBody(progressPayload.c_str());\n    }\n\n    void SetUpUpdateAchievementRtaResponse(uint64_t xuid, String progressPayload, bool willUnlock, Vector<std::shared_ptr<HttpMock>>& mocks)\n    {\n        SetupRtaResponseForUser(xuid, \"POST\", progressPayload, mocks);\n        mocks.back()->SetMockMatchedCallback(\n            [\n                progressPayload, \n                xuid,\n                willUnlock\n            ]\n        (HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestBody);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                xsapi_internal_stringstream uri;\n                uri << \"https://achievements.xboxlive.com/users/xuid(\" << xuid << \")/achievements/\" << utils::ToLower(AppConfig::Instance()->Scid());\n                \n                auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n                mockRtaService.RaiseEvent(uri.str(), progressPayload.c_str());\n            });\n    }\n\n    bool UpdateAchievementHelper(uint64_t xuid, String achievementId, uint8_t progress, bool setUpMocks = true, bool willUnlock = false, String progressPayload = rtaAchievementProgressChangedPayload)\n    {\n        Vector<std::shared_ptr<HttpMock>> mocks;\n        if (setUpMocks)\n        {\n            SetUpUpdateAchievementRtaResponse(xuid, progressPayload, willUnlock, mocks);\n        }\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerUpdateAchievement(xuid, achievementId.c_str(), progress));\n        \n        int count{ 0 };\n        bool progressEventReceived = false;\n        bool unlockEventReceived = false;\n\n        // We only want to care about unlock event if we expect to unlock the \n        //  achievement, so the inverse of XOR will tell us if the values are\n        //  the same.\n        while(!(progressEventReceived && !(willUnlock ^ unlockEventReceived)))\n        {\n            if (++count > 500)\n            {\n                break;\n            }\n\n            size_t eventsCount{};\n            const XblAchievementsManagerEvent* events{};\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventsCount));\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].eventType)\n                {\n                case XblAchievementsManagerEventType::AchievementProgressUpdated:\n                    progressEventReceived = true;\n                    break;\n                case XblAchievementsManagerEventType::AchievementUnlocked:\n                    unlockEventReceived = true;\n                    break;\n                default:\n                    break;\n                }\n            }\n            Sleep(10);\n        }\n\n        // compare update call response to expected mock\n        // ensure achievement progress event arrives and is processed\n        // check progress value of achievement to value intended to set\n        return !(count > 500);\n    }\n\n    void UpdateAchievementSuccessHelper()\n    {\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n        bool completedBeforeTimeout = UpdateAchievementHelper(xuid, achievementId2017InProgress, 100, true, true, rtaAchievementProgressChangedCompletePayload);\n\n        VERIFY_IS_TRUE(completedBeforeTimeout);\n        \n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievement;\n        uint64_t size;\n        HRESULT hr;\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2017InProgress,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerResultGetAchievements(resultHandle, &achievement, &size));\n        VERIFY_IS_TRUE(achievement->progressState == XblAchievementProgressState::Achieved);\n        VERIFY_ARE_EQUAL_STR(\n            achievement->progression.requirements[0].currentProgressValue,\n            achievement->progression.requirements[0].targetProgressValue\n        );\n        VERIFY_ARE_EQUAL_INT(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue),\n            100\n        );\n        VERIFY_IS_TRUE(\n            utils::TimeTFromDatetime(datetime::from_string(achievementUnlockTime, datetime::date_format::ISO_8601))\n            == achievement->progression.timeUnlocked\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\npublic:\n\n    DEFINE_TEST_CASE(AddLocalUser_InitializesWithLocalAchievementsCached_Success)\n    {\n        TEST_LOG(L\"Test starting: AddLocalUser_InitializesWithLocalAchievementsCached_Success\");\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n    }\n\n    DEFINE_TEST_CASE(AddLocalUser_SingleUserMultiplePages_InitializesAfterAllPagesCached)\n    {\n        TEST_LOG(L\"Test starting: AddLocalUser_SingleUserMultiplePages_InitializesAfterAllPagesCached\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n        \n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserMultiplePageHelper(xblContext->User());\n    }\n\n    DEFINE_TEST_CASE(AddLocalUser_MultipleUser_InitializesWithLocalAchievementsCached_Success)\n    {\n        TEST_LOG(L\"Test starting: AddLocalUser_MultipleUser_InitializesWithLocalAchievementsCached_Success\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n        \n        Map<std::shared_ptr<XblContext>, const char*> responseMap;\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserGetAchievementsResponse;\n        xblContext = env.CreateMockXboxLiveContext(2345);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = secondUserGetAchievementsResponse;\n\n        // add local users\n        AddMultipleLocalUsersHelper(responseMap);\n    }\n\n    DEFINE_TEST_CASE(RemoveLocalUser_SingleUser_ExpectUserRemoved)\n    {\n        TEST_LOG(L\"Test starting: RemoveLocalUser_SingleUser_ExpectUserRemoved\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerRemoveLocalUser(\n            xblContext->User().Handle()\n        ));\n        env.m_testContexts.pop_back();\n\n        HRESULT hr = S_OK;\n        XblAchievementsManagerResultHandle result;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(xuid, achievementId2013MultipleRequirementsAchieved, &result));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n    }\n\n    DEFINE_TEST_CASE(RemoveLocalUser_MultipleUsers_ExpectCorrectUserRemoved)\n    {\n        TEST_LOG(L\"Test starting: RemoveLocalUser_MultipleUsers_ExpectCorrectUserRemoved\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        Map<std::shared_ptr<XblContext>, const char*> responseMap;\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserGetAchievementsResponse;\n        xblContext = env.CreateMockXboxLiveContext(2345);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = secondUserGetAchievementsResponse;\n\n        // add local users\n        AddMultipleLocalUsersHelper(responseMap);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerRemoveLocalUser(\n            xblContext->User().Handle()\n        ));\n        env.m_testContexts.pop_back();\n\n        HRESULT hr = S_OK;\n        XblAchievementsManagerResultHandle result;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(2345, achievementId2013MultipleRequirementsAchieved, &result));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(xuid, achievementId2013MultipleRequirementsAchieved, &result));\n        XblAchievementsManagerResultCloseHandle(result);\n    }\n\n    DEFINE_TEST_CASE(RemoveLocalUser_UserNotInList_ExpectError)\n    {\n        TEST_LOG(L\"Test starting: RemoveLocalUser_UserNotInList_ExpectError\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        HRESULT hr = S_OK;\n        VERIFY_FAILED(hr = XblAchievementsManagerRemoveLocalUser(\n            xblContext->User().Handle()\n        ));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n\n        env.m_testContexts.pop_back();\n    }\n\n    DEFINE_TEST_CASE(IsLocalUserInitialized_UserNotInList_ExpectInvalidArg)\n    {\n        TEST_LOG(L\"Test starting: IsLocalUserInitialized_UserNotInList_ExpectInvalidArg\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerIsUserInitialized(xuid));\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n    }\n    \n    DEFINE_TEST_CASE(IsLocalUserInitialized_UserNotInitialized_ExpectEFail)\n    {\n        TEST_LOG(L\"Test starting: IsLocalUserInitialized_UserNotInitialized_ExpectEFail\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n        AddLocalUserWithoutSyncHelper(xblContext->User());\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerIsUserInitialized(xuid));\n        VERIFY_ARE_EQUAL(E_FAIL, hr);\n    }\n\n    DEFINE_TEST_CASE(IsLocalUserInitialized_UserInitialized_ExpectSuccess)\n    {\n        TEST_LOG(L\"Test starting: IsLocalUserInitialized_UserInitialized_ExpectSuccess\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n        VERIFY_SUCCEEDED(XblAchievementsManagerIsUserInitialized(xuid));\n    }\n\n    DEFINE_TEST_CASE(GetAchievementForUser_SingleUser_Success)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_SingleUser_Success\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n        // check the values of the achievement to ensure they are what expected\n        \n        const XblAchievement* achievement = nullptr;\n        uint64_t size;\n        XblAchievementsManagerResultHandle resultHandle;\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2013MultipleRequirementsAchieved,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(achievement);\n\n        // validate individual fields\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementForUser_DuplicateHandleOneDuplicate_SuccessfulDataDeletedAfterBothClosed)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_DuplicateHandleOneDuplicate_SuccessfulDataDeletedAfterBothClosed\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n        // check the values of the achievement to ensure they are what expected\n\n        const XblAchievement* achievement = nullptr;\n        uint64_t size;\n        XblAchievementsManagerResultHandle resultHandle;\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2013MultipleRequirementsAchieved,\n            &resultHandle\n        ));\n\n        XblAchievementsManagerResultHandle duplicateHandle;\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultDuplicateHandle(resultHandle, &duplicateHandle));\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(achievement);\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n        \n        // ptr should still be valid after duplicate\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(achievement);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            duplicateHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(achievement);\n\n        XblAchievementsManagerResultCloseHandle(duplicateHandle);\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n\n        VERIFY_IS_NULL(achievement);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementForUser_SingleUser_ExpectAchievementNonExistent)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_SingleUser_ExpectAchievementNonExistent\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n        // check the values of the achievement to ensure they are what expected\n\n        XblAchievementsManagerResultHandle achievement;\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementIdDoesNotExist,\n            &achievement\n        ));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementForUser_SingleUser_ExpectFailureInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_SingleUser_ExpectFailureInvalidArgs\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User());\n        // check the values of the achievement to ensure they are what expected\n\n        // no Id passed in\n        XblAchievementsManagerResultHandle resultHandle = nullptr;\n        const XblAchievement* achievement = nullptr;\n        uint64_t size;\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(\n            xuid,\n            nullptr,\n            &resultHandle\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n        \n        // no destination passed in\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2017NotStarted,\n            nullptr\n        ));\n\n        VERIFY_FAILED(hr = XblAchievementsManagerResultGetAchievements(\n            nullptr,\n            &achievement,\n            &size\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2013MultipleRequirementsAchieved,\n            &resultHandle\n        ));\n\n        VERIFY_FAILED(hr = XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            nullptr,\n            &size\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n        \n        VERIFY_FAILED(hr = XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            nullptr\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n    \n    DEFINE_TEST_CASE(GetAchievementForUser_UserDoesNotExist_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_UserDoesNotExist_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User());\n\n        HRESULT hr = S_OK;\n        XblAchievementsManagerResultHandle achievement;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(\n            2345, \n            defaultAchievementId, \n            &achievement\n        ));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n    }\n    \n    DEFINE_TEST_CASE(GetAchievementForUser_UserNotInitialized_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_UserNotInitialized_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // not using the helper function here since we are interrupting\n\n        XTaskQueueHandle queue{};\n\n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(defaultAchievementResponse);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerAddLocalUser(xblContext->User().Handle(), queue));\n        \n        XblAchievementsManagerResultHandle achievement;\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievement(\n            xuid, \n            defaultAchievementId, \n            &achievement\n        ));\n        VERIFY_ARE_EQUAL(hr, E_UNEXPECTED);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementForUser_MultipleUsers_Success)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementForUser_MultipleUsers_Success\");\n\n        AMTestEnvironment env{};\n\n        Map<std::shared_ptr<XblContext>, const char*> responseMap;\n        auto xblContext = env.CreateMockXboxLiveContext(1234);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserGetAchievementsResponse;\n        xblContext = env.CreateMockXboxLiveContext(2345);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = secondUserGetAchievementsResponse;\n\n        // add local users\n        AddMultipleLocalUsersHelper(responseMap);\n        // check the values of the achievements for each user to ensure they are part\n        //      of the correct user\n\n        XblAchievementsManagerResultHandle resultHandle = nullptr;\n        uint64_t size;\n        const XblAchievement* user1Achievement;\n        const XblAchievement* user2Achievement;\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            env.m_testContexts[0]->User().Xuid(),\n            \"3\",\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &user1Achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(user1Achievement);\n\n        // verify individual fields\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            env.m_testContexts[0]->User().Xuid(),\n            \"5\",\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &user1Achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(user1Achievement);\n        // verify individual fields\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            env.m_testContexts[1]->User().Xuid(),\n            \"5\",\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &user2Achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(user2Achievement);\n\n        // verify individual fields\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(\n            env.m_testContexts[1]->User().Xuid(),\n            \"3\",\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &user2Achievement,\n            &size\n        ));\n        VERIFY_IS_NOT_NULL(user2Achievement);\n\n        // verify individual fields\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementsForUser_DefaultOptions_AllAchievementsReturned)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUser_DefaultOptions_AllAchievementsReturned\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievements;\n        uint64_t achievementsCount;\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievements(\n            xuid,\n            XblAchievementOrderBy::DefaultOrder,\n            XblAchievementsManagerSortOrder::Unsorted,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerResultGetAchievements(\n            resultHandle, \n            &achievements, \n            &achievementsCount\n        ));\n\n        Vector<XblAchievement> achievementsVector(achievements, achievements + achievementsCount);\n        auto foundAchievement = std::find_if(achievements, achievements + achievementsCount, [&](const XblAchievement& achievement)\n            {\n                return utils::str_icmp(achievementId2017InProgress, achievement.id) == 0;\n            });\n\n        VERIFY_ARE_EQUAL_INT(5, achievementsCount);\n        VERIFY_IS_NOT_NULL(foundAchievement);\n        VERIFY_ARE_EQUAL_STR_IGNORE_CASE(\n            utils::uint32_to_internal_string(achievementInProgressStartProgress).c_str(),\n            foundAchievement->progression.requirements[0].currentProgressValue\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementsForUser_SortFieldSpecifiedDefaultOrder_ExpectInvalidArg)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUser_SortFieldSpecifiedDefaultOrder_ExpectInvalidArg\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievements(\n            xuid,\n            XblAchievementOrderBy::UnlockTime,\n            XblAchievementsManagerSortOrder::Unsorted,\n            &resultHandle\n        ));\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n    }\n    \n    DEFINE_TEST_CASE(GetAchievementsForUser_SortByUnlockTimeAscending_ExpectSortedAchievements)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUser_SortByUnlockTimeAscending_ExpectSortedAchievements\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievements(\n            xuid,\n            XblAchievementOrderBy::DefaultOrder,\n            XblAchievementsManagerSortOrder::Ascending,\n            &resultHandle\n        ));\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n    }\n    \n    // add other test cases for sort and filter \n\n    DEFINE_TEST_CASE(GetAchievementsForUserByState_UnlockedSortFieldSpecifiedDefaultOrder_ExpectInvalidArg)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUserByState_UnlockedSortFieldSpecifiedDefaultOrder_ExpectInvalidArg\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        VERIFY_FAILED(hr = XblAchievementsManagerGetAchievementsByState(\n            xuid,\n            XblAchievementOrderBy::UnlockTime,\n            XblAchievementsManagerSortOrder::Unsorted,\n            XblAchievementProgressState::Achieved,\n            &resultHandle\n        ));\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementsForUserByState_UnlockedOnlyDefaultSort_ExpectTwoResults)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUserByState_UnlockedOnlyDefaultSort_ExpectTwoResults\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), getSortedAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievements;\n        uint64_t achievementsCount;\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievementsByState(\n            xuid,\n            XblAchievementOrderBy::DefaultOrder,\n            XblAchievementsManagerSortOrder::Unsorted,\n            XblAchievementProgressState::Achieved,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievements,\n            &achievementsCount\n        ));\n\n        VERIFY_ARE_EQUAL_INT(2, achievementsCount);\n        VERIFY_ARE_EQUAL_STR(achievementId2013MultipleRequirementsAchieved, achievements[0].id);\n        VERIFY_ARE_EQUAL_STR(achievementId2017Achieved, achievements[1].id);\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementsForUserByState_UnlockedOnlySortUnlockTimeAscending_ExpectTwoResults)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUserByState_UnlockedOnlySortUnlockTimeAscending_ExpectTwoResults\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), getSortedAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievements;\n        uint64_t achievementsCount;\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievementsByState(\n            xuid,\n            XblAchievementOrderBy::UnlockTime,\n            XblAchievementsManagerSortOrder::Ascending,\n            XblAchievementProgressState::Achieved,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievements,\n            &achievementsCount\n        ));\n\n        VERIFY_ARE_EQUAL_INT(2, achievementsCount);\n        VERIFY_ARE_EQUAL_STR(achievementId2013MultipleRequirementsAchieved, achievements[0].id);\n        VERIFY_ARE_EQUAL_STR(achievementId2017Achieved, achievements[1].id);\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(GetAchievementsForUserByState_UnlockedOnlySortUnlockTimeDescending_ExpectTwoResults)\n    {\n        TEST_LOG(L\"Test starting: GetAchievementsForUserByState_UnlockedOnlySortUnlockTimeDescending_ExpectTwoResults\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // add local user\n        AddLocalUserSyncHelper(xblContext->User(), getSortedAchievementsResponse);\n\n        // compare list of contents for equality\n        HRESULT hr;\n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievements;\n        uint64_t achievementsCount;\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievementsByState(\n            xuid,\n            XblAchievementOrderBy::UnlockTime,\n            XblAchievementsManagerSortOrder::Descending,\n            XblAchievementProgressState::Achieved,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievements,\n            &achievementsCount\n        ));\n\n        VERIFY_ARE_EQUAL_INT(2, achievementsCount);\n        VERIFY_ARE_EQUAL_STR(achievementId2017Achieved, achievements[0].id);\n        VERIFY_ARE_EQUAL_STR(achievementId2013MultipleRequirementsAchieved, achievements[1].id);\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_HigherProgressValue_ExpectProgressNotification)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_HigherProgressValue_ExpectProgressNotification\");\n\n        AMTestEnvironment env{};\n        constexpr uint8_t newProgress = 20;\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n        \n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n        \n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievement;\n        uint64_t size;\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(xuid, achievementId2017NotStarted, &resultHandle));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_ARE_EQUAL_INT(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue),\n            0\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n        resultHandle = nullptr;\n\n        bool completedBeforeTimeout = UpdateAchievementHelper(xuid, achievementId2017NotStarted, newProgress);\n        VERIFY_IS_TRUE(completedBeforeTimeout);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(xuid, achievementId2017NotStarted, &resultHandle));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_ARE_EQUAL_INT(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue),\n            newProgress\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n        \n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_ExpectFailureInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_ExpectFailureInvalidArgs\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            nullptr,\n            10\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_UserDoesNotExist_ExpectFailureInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_UserDoesNotExist_ExpectFailureInvalidArgs\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            2345,\n            achievementId2017NotStarted,\n            10\n        ));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_UserNotInitialized_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_UserNotInitialized_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        // not using the helper function here since we are interrupting\n\n        XTaskQueueHandle queue{};\n\n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(firstUserUpdateAchievementsResponse);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerAddLocalUser(xblContext->User().Handle(), queue));\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            achievementId2017NotStarted,\n            20\n        ));\n        VERIFY_ARE_EQUAL(hr, E_UNEXPECTED);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_AchievementDoesNotExist_ExpectFailureInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_AchievementDoesNotExist_ExpectFailureInvalidArgs\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            achievementIdDoesNotExist,\n            10\n        ));\n        VERIFY_ARE_EQUAL(hr, E_BOUNDS);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_Is2013AchievementMultipleRequirements_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_Is2013AchievementMultipleRequirements_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n        \n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid, \n            achievementId2013MultipleRequirements, \n            10\n        ));\n        VERIFY_ARE_EQUAL(hr, E_NOT_SUPPORTED);\n    }\n    \n    DEFINE_TEST_CASE(UpdateAchievement_Is2013AchievementSingleRequirements_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_Is2013AchievementSingleRequirements_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(1234);\n        env.m_testContexts.push_back(xblContext);\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            achievementId2013SingleRequirement,\n            10\n        ));\n        VERIFY_ARE_EQUAL(hr, E_NOT_SUPPORTED);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_LowerProgressValue_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_LowerProgressValue_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n        constexpr uint8_t updateProgress = 10;\n\n        VERIFY_IS_TRUE(updateProgress < achievementInProgressStartProgress);\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n\n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            achievementId2017InProgress,\n            updateProgress\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_SameProgressValue_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_SameProgressValue_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n        \n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            achievementId2017InProgress,\n            achievementInProgressStartProgress\n        ));\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n    }\n\n    DEFINE_TEST_CASE(UpdateAchievement_AchievementAlreadyUnlocked_ExpectFailure)\n    {\n        TEST_LOG(L\"Test starting: UpdateAchievement_AchievementAlreadyUnlocked_ExpectFailure\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n        \n        HRESULT hr;\n        VERIFY_FAILED(hr = XblAchievementsManagerUpdateAchievement(\n            xuid,\n            achievementId2013MultipleRequirementsAchieved,\n            100\n        ));\n        VERIFY_ARE_EQUAL(hr, E_UNEXPECTED);\n    }\n\n    DEFINE_TEST_CASE(UnlockAchievement_CompleteProgressWithDeducedUnlockNotification_ExpectProgressAndUnlockNotifications)\n    {\n        TEST_LOG(L\"Test starting: UnlockAchievement_CompleteProgressWithDeducedUnlockNotification_ExpectProgressAndUnlockNotifications\");\n\n        UpdateAchievementSuccessHelper();\n    }\n\n    DEFINE_TEST_CASE(UnlockAchievement_MultipleUsersBothInProgressCompleteOne_ExpectBothNotifications)\n    {\n        TEST_LOG(L\"Test starting: UnlockAchievement_MultipleUsersBothInProgressCompleteOne_ExpectBothNotifications\");\n\n        DEFINE_TEST_CASE_PROPERTIES_FOCUS();\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        Map<std::shared_ptr<XblContext>, const char*> responseMap;\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserUpdateAchievementsResponse;\n        xblContext = env.CreateMockXboxLiveContext(2345);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserUpdateAchievementsResponse;\n\n        // add local users\n        AddMultipleLocalUsersHelper(responseMap);\n\n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievement;\n        uint64_t size;\n        HRESULT hr;\n\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2017InProgress,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_TRUE(achievement->progressState == XblAchievementProgressState::InProgress);\n        VERIFY_IS_TRUE(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue)\n            == achievementInProgressStartProgress\n        );\n        \n        Vector<std::shared_ptr<HttpMock>> mocks;\n        SetUpUpdateAchievementRtaResponse(2345, rtaAchievementProgressChangedCompletePayload, true, mocks);\n\n        bool completedBeforeTimeout = UpdateAchievementHelper(2345, achievementId2017InProgress, 100, false, true);\n        VERIFY_SUCCEEDED(completedBeforeTimeout);\n        \n        // make sure user 1234 doesn't show any changes from the event.\n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievement(\n            xuid,\n            achievementId2017InProgress,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_TRUE(achievement->progressState == XblAchievementProgressState::InProgress);\n        VERIFY_IS_TRUE(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue)\n            == achievementInProgressStartProgress\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n        resultHandle = nullptr;\n\n        // make sure user 2345 actually has the correct changes \n        VERIFY_SUCCEEDED(hr = XblAchievementsManagerGetAchievement(\n            2345,\n            achievementId2017InProgress,\n            &resultHandle\n        ));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n        VERIFY_IS_TRUE(achievement->progressState == XblAchievementProgressState::Achieved);\n        VERIFY_ARE_EQUAL_STR(\n            achievement->progression.requirements[0].currentProgressValue,\n            achievement->progression.requirements[0].targetProgressValue\n        );\n        VERIFY_ARE_EQUAL_INT(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue),\n            100\n        );\n        VERIFY_IS_TRUE(\n            utils::TimeTFromDatetime(datetime::from_string(achievementUnlockTime, datetime::date_format::ISO_8601))\n            == achievement->progression.timeUnlocked\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n    \n    DEFINE_TEST_CASE(AchievementsManagerResync_SingleUserNoAchievementsChanged_GeneratesNoEvents)\n    {\n        TEST_LOG(L\"Test starting: AchievementsManagerResync_SingleUserNoAchievementsChanged_GeneratesNoEvents\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserUpdateAchievementsResponse);\n        \n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.RaiseResync();\n\n        Sleep(300);\n\n        const XblAchievementsManagerEvent* events;\n        size_t eventCount;\n        VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventCount));\n        VERIFY_ARE_EQUAL_INT(eventCount, 0);\n    }\n    \n    DEFINE_TEST_CASE(AchievementsManagerResync_SingleUserOneAchievementChanged_SuccessfullyUpdatedAndGeneratesEvent)\n    {\n        TEST_LOG(L\"Test starting: AchievementsManagerResync_SingleUserOneAchievementChanged_SuccessfullyUpdatedAndGeneratesEvent\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserGetAchievementsResponse);\n        \n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(secondUserGetAchievementsResponse);\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.RaiseResync();\n        \n        Sleep(200);\n        \n        uint32_t count = 0;\n        const XblAchievementsManagerEvent* events = nullptr;\n        size_t eventCount = 0;\n\n        while (eventCount == 0)\n        {\n            if (++count > 500)\n            {\n                break;\n            }\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventCount));\n            if (eventCount == 0)\n            {\n                Sleep(20);\n            }\n        }\n        VERIFY_ARE_EQUAL_INT(eventCount, 1);\n        VERIFY_IS_TRUE(events[0].eventType == XblAchievementsManagerEventType::AchievementProgressUpdated);\n    }\n\n    DEFINE_TEST_CASE(AchievementsManagerResync_MultipleUsersOneAchievementChanged_SuccessfullyUpdatedAndGeneratesEventPerUser)\n    {\n        TEST_LOG(L\"Test starting: AchievementsManagerResync_MultipleUsersOneAchievementChanged_SuccessfullyUpdatedAndGeneratesEventPerUser\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        Map<std::shared_ptr<XblContext>, const char*> responseMap;\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserResyncNotStartedResponse;\n        xblContext = env.CreateMockXboxLiveContext(2345);\n        env.m_testContexts.push_back(xblContext);\n        responseMap[xblContext] = firstUserGetAchievementsResponse;\n\n        // add local users\n        AddMultipleLocalUsersHelper(responseMap);\n\n        Vector<std::shared_ptr<HttpMock>> mocks;\n        SetupRtaResponseForUser(xuid, \"GET\", firstUserResyncFinishedResponse, mocks);\n        SetupRtaResponseForUser(2345, \"GET\", secondUserGetAchievementsResponse, mocks);\n\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.RaiseResync();\n\n        Sleep(200);\n\n        uint32_t count = 0;\n        const XblAchievementsManagerEvent* events = nullptr;\n        size_t eventCount = 0;\n        size_t totalEventCount = 0;\n        uint8_t progressEvents = 0, unlockEvents = 0;\n        uint8_t firstUserEvents = 0, secondUserEvents = 0;\n\n        while (!(progressEvents == 2 && unlockEvents == 1))\n        {\n            if (++count > 500)\n            {\n                break;\n            }\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventCount));\n            totalEventCount += eventCount;\n            for (uint8_t i = 0; i < eventCount; ++i)\n            {\n                switch (events[i].eventType)\n                {\n                case XblAchievementsManagerEventType::AchievementProgressUpdated:\n                    ++progressEvents;\n                    break;\n                case XblAchievementsManagerEventType::AchievementUnlocked:\n                    ++unlockEvents;\n                    break;\n                default:\n                    break;\n                }\n\n                if (events[i].xboxUserId == xuid)\n                {\n                    ++firstUserEvents;\n                }\n                else\n                {\n                    ++secondUserEvents;\n                }\n            }\n            \n            Sleep(20);\n        }\n        VERIFY_ARE_EQUAL_INT(3, totalEventCount);\n        VERIFY_ARE_EQUAL_INT(2, progressEvents);\n        VERIFY_ARE_EQUAL_INT(1, unlockEvents);\n        VERIFY_ARE_EQUAL_INT(2, firstUserEvents);\n        VERIFY_ARE_EQUAL_INT(1, secondUserEvents);\n        \n        XblAchievementsManagerResultHandle resultHandle;\n        const XblAchievement* achievement;\n        uint64_t size;\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(2345, achievementId2017NotStarted, &resultHandle));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n\n        VERIFY_IS_TRUE(achievement->progressState == XblAchievementProgressState::InProgress);\n        VERIFY_ARE_EQUAL_INT(\n            utils::internal_string_to_uint32(achievement->progression.requirements[0].currentProgressValue),\n            achievementInProgressStartProgress\n        );\n\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n        resultHandle = nullptr;\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerGetAchievement(xuid, achievementId2013MultipleRequirementsAchieved, &resultHandle));\n        VERIFY_SUCCEEDED(XblAchievementsManagerResultGetAchievements(\n            resultHandle,\n            &achievement,\n            &size\n        ));\n\n        VERIFY_IS_TRUE(achievement->progressState == XblAchievementProgressState::Achieved);\n        for (size_t i = 0; i < achievement->progression.requirementsCount; ++i)\n        {\n            VERIFY_ARE_EQUAL_STR(\n                achievement->progression.requirements[i].currentProgressValue,\n                achievement->progression.requirements[i].targetProgressValue\n                );\n            VERIFY_ARE_EQUAL_INT(\n                utils::internal_string_to_uint32(achievement->progression.requirements[i].currentProgressValue),\n                100\n            );\n        }\n        VERIFY_IS_TRUE(\n            utils::TimeTFromDatetime(datetime::from_string(achievementUnlockTime, datetime::date_format::ISO_8601))\n            == achievement->progression.timeUnlocked\n        );\n        XblAchievementsManagerResultCloseHandle(resultHandle);\n    }\n\n    /*DEFINE_TEST_CASE(AchievementsManagerResync_SingleUserOneUpdateAlreadyReceivedDifferentValues_SuccessfullyUpdatedOnlyGeneratesOneEvent)\n    {\n        TEST_LOG(L\"Test starting: AchievementsManagerResync_SingleUserOneUpdateAlreadyReceivedDifferentValues_SuccessfullyUpdatedOnlyGeneratesOneEvent\");\n\n        // want to see what happens when one achievement is larger than another... could\n        // generate two events, but without guarantee that value can be cast to an int,\n        // cant really assume it will be larager to allow us to be able to discard it.\n    }*/\n    \n    DEFINE_TEST_CASE(AchievementsManagerResync_SingleUserOneUpdateAlreadyReceivedSameValues_SuccessfullyUpdatedOnlyGeneratesOneEvent)\n    {\n        TEST_LOG(L\"Test starting: AchievementsManagerResync_SingleUserOneUpdateAlreadyReceivedSameValues_SuccessfullyUpdatedOnlyGeneratesOneEvent\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserGetAchievementsResponse);\n\n        VERIFY_SUCCEEDED(XblAchievementsManagerUpdateAchievement(xuid, achievementId2017NotStarted, achievementInProgressStartProgress));\n\n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(secondUserGetAchievementsResponse);\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.RaiseResync();\n\n        Sleep(200);\n\n        uint32_t count = 0;\n        const XblAchievementsManagerEvent* events = nullptr;\n        size_t eventCount = 0;\n        size_t totalEventCount = 0;\n\n        while (++count < 100)\n        {\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventCount));\n            totalEventCount += eventCount;\n            if (totalEventCount < 2)\n            {\n                Sleep(10);\n            }\n        }\n        VERIFY_ARE_EQUAL_INT(totalEventCount, 1);\n    }\n\n    DEFINE_TEST_CASE(RtaConnectionDropped_OneAchievementChanged_StateResyncedCorrectly)\n    {\n        TEST_LOG(L\"Test starting: RtaConnectionDropped_OneAchievementChanged_StateResyncedCorrectly\");\n\n        AMTestEnvironment env{};\n        constexpr uint64_t xuid = 1234;\n\n        auto xblContext = env.CreateMockXboxLiveContext(xuid);\n        env.m_testContexts.push_back(xblContext);\n\n        AddLocalUserSyncHelper(xblContext->User(), firstUserGetAchievementsResponse);\n\n        HttpMock mock(\"GET\", defaultAchievementsUri);\n        mock.SetResponseBody(secondUserGetAchievementsResponse);\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.DisconnectClient(xuid);\n\n        Sleep(200);\n\n        uint32_t count = 0;\n        const XblAchievementsManagerEvent* events = nullptr;\n        size_t eventCount = 0;\n        size_t totalEventCount = 0;\n\n        while (++count < 100)\n        {\n            VERIFY_SUCCEEDED(XblAchievementsManagerDoWork(&events, &eventCount));\n            totalEventCount += eventCount;\n            if (totalEventCount < 2)\n            {\n                Sleep(10);\n            }\n        }\n        VERIFY_ARE_EQUAL_INT(totalEventCount, 1);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/AchievementsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char defaultAchievementResponse[] =\nR\"(\n{\n    \"achievements\":\n    [{\n        \"id\":\"3\",\n        \"serviceConfigId\" : \"b5dd9daf-0000-0000-0000-000000000000\",\n        \"name\" : \"Default NameString for Microsoft Achievements Sample Achievement 3\",\n        \"titleAssociations\" :\n        [{\n            \"name\":\"Microsoft Achievements Sample\",\n            \"id\" : 3051199919,\n            \"version\" : \"abc\"\n        }],\n        \"progressState\":\"Achieved\",\n        \"progression\" :\n        {\n            \"requirements\":\n            [{\n                \"id\":\"12345678-1234-1234-1234-123456789111\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Individual\"\n            },\n            {\n                \"id\":\"12345678-1234-1234-1234-123456789222\",\n                \"current\" : null,\n                \"target\" : \"100\",\n                \"operationType\" : \"sum\",\n                \"ruleParticipationType\" : \"Group\"\n            }],\n            \"timeUnlocked\":\"2013-01-17T03:19:00.3087016Z\"\n        },\n        \"mediaAssets\":\n        [{\n            \"name\":\"Icon Name\",\n            \"type\" : \"Icon\",\n            \"url\" : \"http://www.xbox.com/\"\n        }],\n        \"platforms\" : [\"Durango\", \"Xbox360\"],\n        \"isSecret\" : true,\n        \"description\" : \"Default DescriptionString for Microsoft Achievements Sample Achievement 3\",\n        \"lockedDescription\" : \"Default UnachievedString for Microsoft Achievements Sample Achievement 3\",\n        \"productId\" : \"12345678-1234-1234-1234-123456789012\",\n        \"achievementType\" : \"Challenge\",\n        \"participationType\" : \"Individual\",\n        \"timeWindow\" :\n        {\n            \"startDate\":\"2013-02-01T00:00:00Z\",\n            \"endDate\" : \"2100-07-01T00:00:00Z\"\n        },\n        \"rewards\" :\n        [{\n            \"name\":null,\n            \"description\" : null,\n            \"value\" : \"10\",\n            \"type\" : \"Gamerscore\",\n            \"valueType\" : \"Int\",\n            \"mediaAsset\" : null\n        },\n        {\n            \"name\":\"Default Name for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"description\" : \"Default Description for InAppReward for Microsoft Achievements Sample Achievement 3\",\n            \"value\" : \"1\",\n            \"type\" : \"InApp\",\n            \"valueType\" : \"String\",\n            \"mediaAsset\" : {\"name\":\"Icon Name\", \"type\" : \"Icon\", \"url\" : \"http://www.xbox.com\"}\n        }],\n        \"estimatedTime\":\"06:12:14\",\n        \"deeplink\" : \"aWFtYWRlZXBsaW5r\",\n        \"isRevoked\" : false\n    }],\n    \"pagingInfo\":\n    {\n        \"continuationToken\":null,\n        \"totalRecords\" : 1\n    }\n}\n)\";\n\nconst char rtaAchievementProgressChangedPayload[] =\nR\"(\n{\n    \"progression\": [\n        {\n            \"id\" : \"1\",\n            \"progressState\" : \"InProgress\",\n            \"timeUnlocked\" : \"2013-01-17T03:19:00.3087016Z\",\n            \"requirements\" : [\n                {\n                    \"id\":\"12345678-1234-1234-1234-123456789012\", \n                    \"current\":\"1\", \n                    \"target\":\"100\",\n                    \"operationType\" : \"sum\",\n                    \"valueType\" : \"Integer\",\n                    \"ruleParticipationType\" : \"Individual\"\n                }\n            ]\n        }\n    ],\n    \"serviceConfigId\" : \"87654321-4321-4321-4321-210987654321\"\n}\n)\";\n\nDEFINE_TEST_CLASS(AchievementsTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(AchievementsTests);\n\n    static void VerifyDefaultAchievement(XblAchievementsResultHandle achievementsHandle, JsonValue& achievementToVerify)\n    {\n        UNREFERENCED_PARAMETER(achievementToVerify);\n\n        const XblAchievement* achievements{ nullptr };\n        size_t achievementsCount{ 0 };\n        VERIFY_SUCCEEDED(XblAchievementsResultGetAchievements(achievementsHandle, &achievements, &achievementsCount));\n\n        VERIFY_ARE_EQUAL_UINT(1, achievementsCount);\n        auto& achievement = achievements[0];\n\n        // Do simple type verify \n        VERIFY_ARE_EQUAL_STR(achievement.id, achievementToVerify[\"id\"].GetString());\n        VERIFY_ARE_EQUAL_STR(achievement.serviceConfigurationId, achievementToVerify[\"serviceConfigId\"].GetString());\n        VERIFY_ARE_EQUAL_STR(achievement.name, achievementToVerify[\"name\"].GetString());\n        //VERIFY_ARE_EQUAL_STR(achievement.progressState, achievementToVerify[L\"progressState\"].as_string());\n        VERIFY_ARE_EQUAL(achievement.isSecret, achievementToVerify[\"isSecret\"].GetBool());\n        VERIFY_ARE_EQUAL_STR(achievement.unlockedDescription, achievementToVerify[\"description\"].GetString());\n        VERIFY_ARE_EQUAL_STR(achievement.lockedDescription, achievementToVerify[\"lockedDescription\"].GetString());\n        VERIFY_ARE_EQUAL_STR(achievement.productId, achievementToVerify[\"productId\"].GetString());\n        //VERIFY_ARE_EQUAL_STR(achievement.type, achievementToVerify[L\"achievementType\"].as_string());\n        //VERIFY_ARE_EQUAL_STR(achievement.participationType, achievementToVerify[L\"participationType\"].as_string());\n        VERIFY_ARE_EQUAL_STR(achievement.deepLink, achievementToVerify[\"deeplink\"].GetString());\n        VERIFY_ARE_EQUAL(achievement.isRevoked, achievementToVerify[\"isRevoked\"].GetBool());\n        //VERIFY_ARE_EQUAL_STR(TimeSpanToString(achievement.estimatedUnlockTime), achievementToVerify[L\"estimatedTime\"].as_string());\n\n        // platforms available on\n        VERIFY_ARE_EQUAL_INT(achievement.platformsAvailableOnCount, achievementToVerify[\"platforms\"].Size());\n        VERIFY_ARE_EQUAL_STR(achievement.platformsAvailableOn[0], \"Durango\");\n        VERIFY_ARE_EQUAL_STR(achievement.platformsAvailableOn[1], \"Xbox360\");\n\n        // title association\n        VERIFY_ARE_EQUAL_INT(achievement.titleAssociationsCount, achievementToVerify[\"titleAssociations\"].Size());\n        auto titleAssociation = achievement.titleAssociations[0];\n        JsonValue& titleAssociationJson = achievementToVerify[\"titleAssociations\"][0];\n        VERIFY_ARE_EQUAL_STR(titleAssociation.name, titleAssociationJson[\"name\"].GetString());\n        VERIFY_ARE_EQUAL_INT(titleAssociation.titleId, titleAssociationJson[\"id\"].GetUint());\n\n        //progression\n        // We lost precision after seconds in parsing, thus only compare first characters before that.\n        JsonValue& progressionJson = achievementToVerify[\"progression\"];\n        //VERIFY_ARE_EQUAL(DateTimeToString(achievement.Progression->TimeUnlocked).substr(0, DATETIME_STRING_LENGTH_TO_SECOND),\n        //progressionJson[L\"timeUnlocked\"].as_string().substr(0, DATETIME_STRING_LENGTH_TO_SECOND));\n\n        // progression/requirements\n        VERIFY_ARE_EQUAL_INT(achievement.progression.requirementsCount, progressionJson[\"requirements\"].Size());\n        // progression/requirements/0\n        auto requirements0 = achievement.progression.requirements[0];\n        JsonValue& requirementsJson0 = progressionJson[\"requirements\"][0];\n        VERIFY_ARE_EQUAL_STR(requirements0.id, requirementsJson0[\"id\"].GetString());\n        VERIFY_ARE_EQUAL_STR(requirements0.currentProgressValue, \"\");\n        VERIFY_ARE_EQUAL_STR(requirements0.targetProgressValue, requirementsJson0[\"target\"].GetString());\n\n        // progression/requirements/1\n        auto requirements1 = achievement.progression.requirements[1];\n        JsonValue& requirementsJson1 = progressionJson[\"requirements\"][1];\n        VERIFY_ARE_EQUAL_STR(requirements1.id, requirementsJson1[\"id\"].GetString());\n        VERIFY_ARE_EQUAL_STR(requirements1.currentProgressValue, \"\");\n        VERIFY_ARE_EQUAL_STR(requirements1.targetProgressValue, requirementsJson0[\"target\"].GetString());\n\n        // mediaAssets\n        auto mediaAssets = achievement.mediaAssets;\n        JsonValue& mediaAssetsJson = achievementToVerify[\"mediaAssets\"];\n        VERIFY_ARE_EQUAL_INT(achievement.mediaAssetsCount, mediaAssetsJson.Size());\n        auto mediaAsset0 = mediaAssets[0];\n        JsonValue& mediaAsset0Json = mediaAssetsJson[0];\n        VERIFY_ARE_EQUAL_STR(mediaAsset0.name, mediaAsset0Json[\"name\"].GetString());\n        //VERIFY_ARE_EQUAL_STR(mediaAsset0.mediaAssetType, mediaAsset0Json[L\"type\"].as_string());\n        VERIFY_ARE_EQUAL_STR(mediaAsset0.url, mediaAsset0Json[\"url\"].GetString());\n\n        // timeWindow\n        auto timeWindow = achievement.available;\n        JsonValue& timeWindowJson = achievementToVerify[\"timeWindow\"];\n        UNREFERENCED_PARAMETER(timeWindowJson);\n        //TEST_LOG(DateTimeToString(timeWindow->EndDate).substr(0, DATETIME_STRING_LENGTH_TO_SECOND));\n        //TEST_LOG(timeWindowJson[L\"endDate\"].as_string().substr(0, DATETIME_STRING_LENGTH_TO_SECOND));\n        //VERIFY_ARE_EQUAL(DateTimeToString(timeWindow->StartDate).substr(0, DATETIME_STRING_LENGTH_TO_SECOND), timeWindowJson[L\"startDate\"].as_string().substr(0, DATETIME_STRING_LENGTH_TO_SECOND));\n        //VERIFY_ARE_EQUAL(DateTimeToString(timeWindow->EndDate).substr(0, DATETIME_STRING_LENGTH_TO_SECOND), timeWindowJson[L\"endDate\"].as_string().substr(0, DATETIME_STRING_LENGTH_TO_SECOND));\n\n        // rewards\n        auto rewards = achievement.rewards;\n        JsonValue& rewardsJson = achievementToVerify[\"rewards\"];\n        VERIFY_ARE_EQUAL_INT(achievement.rewardsCount, rewardsJson.Size());\n        //rewards/0\n        auto rewards0 = rewards[0];\n        JsonValue& rewards0Json = rewardsJson[0];\n        VERIFY_ARE_EQUAL_STR(rewards0.name, \"\");\n        VERIFY_ARE_EQUAL_STR(rewards0.description, \"\");\n        VERIFY_ARE_EQUAL_STR(rewards0.value, rewards0Json[\"value\"].GetString());\n        //VERIFY_ARE_EQUAL_STR(rewards0.rewardType, rewards0Json[L\"type\"].as_string());\n        VERIFY_ARE_EQUAL_STR(rewards0.valueType, \"Int\");\n    }\n\n    DEFINE_TEST_CASE(TestXblAchievementsUpdateAchievementAsync)\n    {\n        TEST_LOG(L\"Test starting: TestXblAchievementsUpdateAchievementAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements/mockscid/update\";\n        auto mock = std::make_shared<HttpMock>(\"POST\", url.str(), 304 );\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback([&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n                auto expectedRequest = R\"({\"action\":\"progressUpdate\",\"serviceConfigId\":\"mockscid\",\"titleId\":1234,\"userId\":\"101010101010\",\"achievements\":[{\"id\":\"1\",\"percentComplete\":100}]})\";\n                requestWellFormed &= (requestBody == expectedRequest);\n            });\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblAchievementsUpdateAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            \"1\",\n            100,\n            &async\n        ));\n\n        auto hr = XAsyncGetStatus(&async, true);\n        VERIFY_ARE_EQUAL_UINT(hr, HTTP_E_STATUS_NOT_MODIFIED);\n        VERIFY_ARE_EQUAL_UINT(XblGetErrorCondition(hr), XblErrorCondition::Http304NotModified);\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestGetAchievement)\n    {\n        TEST_LOG(L\"Test starting: TestGetAchievement\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson;\n        responseJson.Parse(defaultAchievementResponse);\n\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements/serviceconfigurationid/achievementId\";\n        HttpMock mock(\"POST\", url.str(), 200, responseJson);\n\n        JsonValue& achievementToVerify = responseJson[\"achievements\"][0];\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementAsync(xboxLiveContext.get(), xboxLiveContext->Xuid(), \"serviceConfigurationId\", \"achievementId\", &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        XblAchievementsResultHandle achievementsHandle{ nullptr };\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementResult(&async, &achievementsHandle));\n\n        VerifyDefaultAchievement(achievementsHandle, achievementToVerify);\n    }\n\n    DEFINE_TEST_CASE(TestGetAchievementBadData)\n    {\n        TEST_LOG(L\"Test starting: TestGetAchievementBadData\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson;\n        responseJson.Parse(defaultAchievementResponse);\n\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements/serviceconfigurationid/achievementId\";\n        HttpMock mock(\"POST\", url.str(), 404);\n\n        JsonValue& achievementToVerify = responseJson[\"achievements\"][0];\n        UNREFERENCED_PARAMETER(achievementToVerify);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementAsync(xboxLiveContext.get(), xboxLiveContext->Xuid(), \"serviceConfigurationId\", \"achievementId\", &async));\n\n        auto hr = XAsyncGetStatus(&async, true);\n        VERIFY_ARE_EQUAL_UINT(HTTP_E_STATUS_NOT_FOUND, hr);\n    }\n\n    DEFINE_TEST_CASE(TestGetAchievements)\n    {\n        TEST_LOG(L\"Test starting: TestGetAchievements\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson; \n        responseJson.Parse(defaultAchievementResponse);\n\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements?titleId=1234&maxItems=100\";\n        auto mock = std::make_shared<HttpMock>(\"GET\", url.str(), 200, responseJson);\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback([&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n                requestWellFormed &= (requestBody == \"\");\n            });\n\n        JsonValue& achievementToVerify = responseJson[\"achievements\"][0];\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementsForTitleIdAsync(\n            xboxLiveContext.get(), \n            xboxLiveContext->Xuid(), \n            1234,\n            XblAchievementType::All,\n            false,\n            XblAchievementOrderBy::DefaultOrder,\n            0,\n            100,\n            &async));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        XblAchievementsResultHandle achievements{ nullptr };\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementResult(&async, &achievements));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        VerifyDefaultAchievement(achievements, achievementToVerify);\n    }\n\n    DEFINE_TEST_CASE(TestGetAchievementsEmptyResult)\n    {\n        TEST_LOG(L\"Test starting: TestGetAchievementsEmptyResult\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson;\n        responseJson.Parse(R\"({\"achievements\":[]})\");\n\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements?titleId=1234&maxItems=100\";\n        auto mock = std::make_shared<HttpMock>(\"GET\", url.str(), 200, responseJson);\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback([&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n                requestWellFormed &= (requestBody == \"\");\n            });\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementsForTitleIdAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            1234,\n            XblAchievementType::All,\n            false,\n            XblAchievementOrderBy::DefaultOrder,\n            0,\n            100,\n            &async));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        XblAchievementsResultHandle achievementsHandle{ nullptr };\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementResult(&async, &achievementsHandle));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        const XblAchievement* achievements{ nullptr };\n        size_t achievementsCount{ 0 };\n        VERIFY_SUCCEEDED(XblAchievementsResultGetAchievements(achievementsHandle, &achievements, &achievementsCount));\n        VERIFY_ARE_EQUAL_INT(0, achievementsCount);\n    }\n\n    DEFINE_TEST_CASE(TestGetAchievementsInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestGetAchievementsInvalidArgs\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson;\n        responseJson.Parse(R\"({\"achievements\":[]})\");\n\n        TEST_LOG(L\"TestGetAchievementsForTitleIdAsyncInvalidArgs: Null xboxUserId param.\");\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements?titleId=1234&maxItems=100\";\n        HttpMock mock(\"GET\", url.str(), 200, responseJson);\n\n        XAsyncBlock async{};\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsGetAchievementsForTitleIdAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            1234,\n            XblAchievementType::All,\n            false,\n            XblAchievementOrderBy::DefaultOrder,\n            0,\n            100,\n            nullptr), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsGetAchievementsForTitleIdAsync(\n            nullptr,\n            xboxLiveContext->Xuid(),\n            1234,\n            XblAchievementType::All,\n            false,\n            XblAchievementOrderBy::DefaultOrder,\n            0,\n            100,\n            &async), E_INVALIDARG);\n    }\n\n    DEFINE_TEST_CASE(TestGetAchievementInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestGetAchievementInvalidArgs\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson;\n        responseJson.Parse(R\"({\"achievements\":[]})\");\n\n        TEST_LOG(L\"TestGetAchievementsForTitleIdAsyncInvalidArgs: Null xboxUserId param.\");\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements?titleId=1234&maxItems=100\";\n        HttpMock mock(\"GET\", url.str(), 200, responseJson);\n\n        XAsyncBlock async{};\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsGetAchievementAsync(\n            nullptr,\n            xboxLiveContext->Xuid(),\n            \"serviceConfigId\",\n            \"1\",\n            &async), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsGetAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            nullptr,\n            \"1\",\n            &async), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsGetAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            \"serviceConfigId\",\n            nullptr,\n            &async), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsGetAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            \"serviceConfigId\",\n            \"1\",\n            nullptr), E_INVALIDARG);\n    }\n\n    DEFINE_TEST_CASE(TestUpdateAchievementInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestUpdateAchievementInvalidArgs\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        JsonDocument responseJson;\n        responseJson.Parse(R\"({\"achievements\":[]})\");\n\n        TEST_LOG(L\"TestGetAchievementsForTitleIdAsyncInvalidArgs: Null xboxUserId param.\");\n        xsapi_internal_stringstream url;\n        url << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements?titleId=1234&maxItems=100\";\n        HttpMock mock(\"GET\", url.str(), 200, responseJson);\n\n        XAsyncBlock async{};\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsUpdateAchievementAsync(\n            nullptr,\n            xboxLiveContext->Xuid(),\n            \"1\",\n            100,\n            &async), \n            E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsUpdateAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            nullptr,\n            100,\n            &async),\n            E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_UINT(XblAchievementsUpdateAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            \"1\",\n            100,\n            nullptr),\n            E_INVALIDARG);\n    }\n\n    DEFINE_TEST_CASE(TestRTAAchievementProgressChange)\n    {\n        TEST_LOG(L\"Test starting: TestRTAAchievementProgressChange\");\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            xsapi_internal_stringstream expectedUri;\n            expectedUri << \"https://achievements.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/achievements/\" << AppConfig::Instance()->Scid();\n            VERIFY_ARE_EQUAL_STR_IGNORE_CASE(uri.data(), expectedUri.str().data());\n\n            mockRtaService.CompleteSubscribeHandshake(n);\n\n            // Immediately raise an event\n            mockRtaService.RaiseEvent(uri, rtaAchievementProgressChangedPayload);\n        });\n\n        struct HandlerContext\n        {\n            Event notificationReceived;\n            struct Entry\n            {\n                xbox::services::String achievementId;\n                XblAchievementProgressState progressState{ XblAchievementProgressState::Unknown };\n                xbox::services::Vector<XblAchievementRequirement> requirements;\n            };\n            xbox::services::Vector<Entry> entries;\n            \n            // To keep the strings alive outside the handler for this test\n            xbox::services::String idContainer{};\n            xbox::services::String currentProgressContainer{};\n            xbox::services::String targetProgressContainer{};\n        } context;\n\n        auto handlerToken = XblAchievementsAddAchievementProgressChangeHandler(xboxLiveContext.get(),\n            [](const XblAchievementProgressChangeEventArgs* args, void* context)\n            {\n                auto c{ static_cast<HandlerContext*>(context) };\n                for (uint32_t entryIndex = 0; entryIndex < args->entryCount; ++entryIndex)\n                {\n                    HandlerContext::Entry entry;\n                    const XblAchievementProgressChangeEntry& updateEntry = args->updatedAchievementEntries[entryIndex];\n                    entry.achievementId = updateEntry.achievementId;\n                    entry.progressState = updateEntry.progressState;\n                    entry.requirements = xbox::services::Vector<XblAchievementRequirement>(updateEntry.progression.requirementsCount);\n\n                    c->idContainer = updateEntry.progression.requirements[0].id;\n                    c->currentProgressContainer = updateEntry.progression.requirements[0].currentProgressValue;\n                    c->targetProgressContainer = updateEntry.progression.requirements[0].targetProgressValue;\n                    entry.requirements[0] = { c->idContainer.c_str(), c->currentProgressContainer.c_str(), c->targetProgressContainer.c_str() };\n\n                    c->entries.push_back(entry);\n                }\n\n                c->notificationReceived.Set();\n            },\n            &context\n        );\n\n        context.notificationReceived.Wait();\n\n        VERIFY_ARE_EQUAL_INT(1, context.entries.size());\n        VERIFY_ARE_EQUAL_STR(\"1\", context.entries[0].achievementId.c_str());\n        VERIFY_IS_TRUE(context.entries[0].progressState == XblAchievementProgressState::InProgress);\n        VERIFY_ARE_EQUAL_INT(1, context.entries[0].requirements.size());\n        VERIFY_ARE_EQUAL_STR(\"12345678-1234-1234-1234-123456789012\", context.entries[0].requirements[0].id);\n        VERIFY_ARE_EQUAL_STR(\"1\", context.entries[0].requirements[0].currentProgressValue);\n        VERIFY_ARE_EQUAL_STR(\"100\", context.entries[0].requirements[0].targetProgressValue);\n\n        VERIFY_SUCCEEDED(XblAchievementsRemoveAchievementProgressChangeHandler(xboxLiveContext.get(), handlerToken));\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/ErrorTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(ErrorTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(ErrorTests)\n\n    DEFINE_TEST_CASE(TestHttpErrors)\n    {\n        TEST_LOG(L\"Test starting: TestHttpErrors\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        HttpMock mock{ \"\", \"https://achievements.xboxlive.com\", 404 };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            MOCK_SCID,\n            \"AchievementId\",\n            &async\n        ));\n        auto hr = XAsyncGetStatus(&async, true);\n        VERIFY_ARE_EQUAL(hr, HTTP_E_STATUS_NOT_FOUND);\n\n        mock.SetResponseHttpStatus(200);\n        mock.SetResponseBody(\"{\\\"asdfasdf\\\":1234}\");\n\n        ZeroMemory(&async, sizeof(XAsyncBlock));\n        VERIFY_SUCCEEDED(XblAchievementsGetAchievementAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            MOCK_SCID,\n            \"AchievementId\",\n            &async\n        ));\n        hr = XAsyncGetStatus(&async, true);\n        VERIFY_ARE_EQUAL(hr, WEB_E_INVALID_JSON_STRING);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/LeaderboardTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char* scid{ \"c4060100-4951-4a51-a630-dce26c15b8c5\" };\nconst char* leaderboardName{ \"lbEncodedRecordHoleId101RecordTypeId1\" };\nconst char* statName{ \"EncodedRecordMax.HoleId.108.RecordTypeId.3\" };\nconst char* server{ \"https://leaderboards.xboxlive.com/\" };\nconst uint64_t xuid{ 2814613569642996 };\n\nconst char* defaultLeaderboardData =\nR\"({\n    \"pagingInfo\": {\n        \"continuationToken\": \"6\",\n        \"totalItems\": 218\n    },\n    \"leaderboardInfo\": {\n        \"totalCount\": 218,\n        \"columnDefinition\": {\n            \"statName\": \"EnemyDefeats\",\n            \"type\": \"Integer\"\n        }\n    },\n    \"userList\": [\n        {\n            \"gamertag\": \"NSC FaceRocker\",\n            \"moderngamertag\": \"Modern FaceRocker\",\n            \"moderngamertagsuffix\": \"1234\",\n            \"uniquemoderngamertag\": \"Modern FaceRocker#1234\",\n            \"xuid\": \"2533275015216241\",\n            \"percentile\": 0.9954,\n            \"rank\": 1,\n            \"globalrank\": 1,\n            \"value\": \"3660\",\n            \"valuemetadata\": \"{\\\"HasSkull\\\": true, \\\"Kills\\\": 11, \\\"Level\\\": \\\"Hardcake\\\", \\\"Empty\\\": null}\"\n        },\n        {\n            \"gamertag\": \"isspmarkbou\",\n            \"moderngamertag\": \"Modern isspmarkbou\",\n            \"moderngamertagsuffix\": \"2345\",\n            \"uniquemoderngamertag\": \"Modern isspmarkbou#2345\",\n            \"xuid\": \"2533275024657260\",\n            \"percentile\": 0.9908,\n            \"rank\": 2,\n            \"globalrank\": 2,\n            \"value\": \"2208\",\n            \"valuemetadata\": \"{\\\"HasSkull\\\": false, \\\"Kills\\\": 11, \\\"Level\\\": \\\"Hardcake\\\", \\\"Empty\\\": null}\"\n        },\n        {\n            \"gamertag\": \"UnloosedLeech\",\n            \"moderngamertag\": \"Modern UnloosedLeech\",\n            \"moderngamertagsuffix\": \"3456\",\n            \"uniquemoderngamertag\": \"Modern UnloosedLeech#3456\",\n            \"xuid\": \"2535449359478292\",\n            \"percentile\": 0.9862,\n            \"rank\": 3,\n            \"globalrank\": 3,\n            \"value\": \"1064\",\n            \"valuemetadata\": \"{\\\"HasSkull\\\": null, \\\"Kills\\\": 11, \\\"Level\\\": \\\"Hardcake\\\", \\\"Empty\\\": null}\"\n        },\n        {\n            \"gamertag\": \"MSFT JEFFSHI 00\",\n            \"moderngamertag\": \"Modern JEFFSHI\",\n            \"moderngamertagsuffix\": \"4567\",\n            \"uniquemoderngamertag\": \"Modern JEFFSHI#4567\",\n            \"xuid\": \"2814662167029838\",\n            \"percentile\": 0.9817,\n            \"rank\": 4,\n            \"globalrank\": 4,\n            \"value\": \"783\",\n            \"valuemetadata\": \"{\\\"HasSkull\\\": true, \\\"Kills\\\": 11, \\\"Level\\\": \\\"Hardcake\\\", \\\"Empty\\\": null}\"\n        },\n        {\n            \"gamertag\": \"ProfittMan\",\n            \"moderngamertag\": \"Modern ProfittMan\",\n            \"moderngamertagsuffix\": \"5678\",\n            \"uniquemoderngamertag\": \"Modern ProfittMan#5678\",\n            \"xuid\": \"2533274998970959\",\n            \"percentile\": 0.9771,\n            \"rank\": 5,\n            \"globalrank\": 5,\n            \"value\": \"535\",\n            \"valuemetadata\": \"{\\\"HasSkull\\\": true, \\\"Kills\\\": 11, \\\"Level\\\": \\\"Hardcake\\\", \\\"Empty\\\": null}\"\n        }\n    ]\n})\";\n\nconst char* defaultV1LeaderboardData =\nR\"({\n    \"pagingInfo\": {\n        \"continuationToken\": \"6\",\n        \"totalItems\": 218\n    },\n    \"leaderboardInfo\": {\n        \"totalCount\": 218,\n        \"columnDefinition\": {\n            \"statName\": \"EnemyDefeats\",\n            \"type\": \"Integer\"\n        }\n    },\n    \"userList\": [\n        {\n            \"gamertag\": \"NSC FaceRocker\",\n            \"moderngamertag\": \"Modern FaceRocker\",\n            \"moderngamertagsuffix\": \"1234\",\n            \"uniquemoderngamertag\": \"Modern FaceRocker#1234\",\n            \"xuid\": \"2533275015216241\",\n            \"percentile\": 0.9954,\n            \"rank\": 1,\n            \"globalrank\": 1,\n            \"values\": [\"3660\"]\n        },\n        {\n            \"gamertag\": \"isspmarkbou\",\n            \"moderngamertag\": \"Modern isspmarkbou\",\n            \"moderngamertagsuffix\": \"2345\",\n            \"uniquemoderngamertag\": \"Modern isspmarkbou#2345\",\n            \"xuid\": \"2533275024657260\",\n            \"percentile\": 0.9908,\n            \"rank\": 2,\n            \"globalrank\": 2,\n            \"values\": [\"2208\"]\n        }\n    ]\n})\";\n\nDEFINE_TEST_CLASS(LeaderboardTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(LeaderboardTests);\n\n    void VerifyLeaderboardColumn(XblLeaderboardColumn* column, JsonValue columnToVerify)\n    {\n        VERIFY_IS_NOT_NULL(column);\n        VERIFY_ARE_EQUAL_STR(column->statName, columnToVerify[\"statName\"].GetString());\n\n        if (column->statType == XblLeaderboardStatType::Uint64)\n        {\n            VERIFY_ARE_EQUAL_STR(\"Integer\", columnToVerify[\"type\"].GetString());\n        }\n        else if (column->statType == XblLeaderboardStatType::Other)\n        {\n            // do nothing, the returned string is not going to match the JSON\n        }\n        else\n        {\n            const char* typeStr{};\n            switch (column->statType)\n            {\n                case XblLeaderboardStatType::Boolean:\n                    typeStr = \"Boolean\";\n                    break;\n                case XblLeaderboardStatType::Double:\n                    typeStr = \"Double\";\n                    break;\n                case XblLeaderboardStatType::String:\n                    typeStr = \"String\";\n                    break;\n            }\n\n            VERIFY_ARE_EQUAL_STR(typeStr, columnToVerify[\"type\"].GetString());\n        }\n    }\n\n    void VerifyLeaderboardRow(XblLeaderboardRow* row, JsonValue rowToVerify, const std::vector<char const*>& columns)\n    {\n        VERIFY_IS_NOT_NULL(row);\n        VERIFY_ARE_EQUAL_STR(row->gamertag, rowToVerify[\"gamertag\"].GetString());\n        VERIFY_ARE_EQUAL_INT(row->xboxUserId, strtoull(rowToVerify[\"xuid\"].GetString(), nullptr, 0));\n        VERIFY_ARE_EQUAL_DOUBLE(row->percentile, rowToVerify[\"percentile\"].GetDouble());\n        VERIFY_ARE_EQUAL_INT(row->rank, rowToVerify[\"rank\"].GetUint());\n        VERIFY_ARE_EQUAL_INT(row->globalRank, rowToVerify[\"globalrank\"].GetUint());\n        \n        if (!rowToVerify.HasMember(\"values\"))\n        {\n            JsonDocument metadataJson;\n            metadataJson.Parse(rowToVerify[\"valuemetadata\"].GetString());\n\n            for (uint32_t i = 0; i < row->columnValuesCount; ++i)\n            {\n                std::string actual;\n                std::string expected;\n                if (i == 0)\n                {\n                    expected = rowToVerify[\"value\"].GetString();\n                    actual = row->columnValues[i];\n                }\n                else if (columns.size() > 0)\n                {\n                    xsapi_internal_stringstream stream;\n                    rapidjson::StringBuffer json;\n                    rapidjson::Writer<rapidjson::StringBuffer> writer(json);\n                    metadataJson[columns[i - 1]].Accept(writer);\n                    expected = json.GetString();\n                    actual = row->columnValues[i];\n                }\n\n                VERIFY_ARE_EQUAL_STR(expected, actual);\n            }\n        }\n    }\n\n    void VerifyLeadershipResult(XblLeaderboardResult* result, JsonValue& resultToVerify, const std::vector<char const*>& columns = {})\n    {\n        VERIFY_IS_NOT_NULL(result);\n\n        auto leaderboardInfoJson = resultToVerify[\"leaderboardInfo\"].GetObjectW();\n        VERIFY_ARE_EQUAL_INT(result->totalRowCount, leaderboardInfoJson[\"totalCount\"].GetUint());\n\n        VerifyLeaderboardColumn(&result->columns[0], leaderboardInfoJson[\"columnDefinition\"].GetObjectW());\n\n        int index{ 0 };\n        for (auto& row : resultToVerify[\"userList\"].GetArray())\n        {\n            VerifyLeaderboardRow(&result->rows[index], row.GetObjectW(), columns);\n            ++index;\n        }\n    }\n\n    XblLeaderboardResult* TestAndGetLeaderboardResult(XblContextHandle xblContextHandle, XblLeaderboardQuery query, const char* responseStr, uint32_t bufferSizeMultiplier, const std::vector<char const*>& columns = {})\n    {\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardAsync(xblContextHandle, query, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        XblLeaderboardResult* result{};\n        std::shared_ptr<char> buffer(new char[resultSize * bufferSizeMultiplier], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardResult(&async, resultSize * bufferSizeMultiplier, buffer.get(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        JsonDocument responseJson;\n        responseJson.Parse(responseStr);\n        VerifyLeadershipResult(result, responseJson, columns);\n\n        return result;\n    }\n\n    XblLeaderboardQuery MakeDefaultQuery()\n    {\n        XblLeaderboardQuery query{};\n        strcpy_s(query.scid, scid);\n        query.xboxUserId = 0;\n        query.leaderboardName = leaderboardName;\n        query.statName = \"\";\n        query.maxItems = 0;\n        query.skipToXboxUserId = 0;\n        query.skipResultToRank = 0;\n        query.socialGroup = XblSocialGroupType::None;\n        query.order = XblLeaderboardSortOrder::Descending;\n\n        return query;\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardAsync\");\n\n        TestEnvironment env{};\n\n        const char* token = \"6\";\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultLeaderboardData);\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardAsync(xboxLiveContext.get(), query, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardResultSize(&async, &resultSize));\n\n        XblLeaderboardResult* result{};\n        std::shared_ptr<char> buffer(new char[resultSize], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardResult(&async, resultSize, buffer.get(), &result, nullptr));\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultLeaderboardData);\n        VerifyLeadershipResult(result, responseJson);\n\n        VERIFY_IS_TRUE(result->hasNext);\n\n        const uint32_t maxItems{ 100 };\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?maxItems=\" << maxItems << \"&continuationToken=\" << token;\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n\n        XblLeaderboardQuery nextQuery{ MakeDefaultQuery() };\n        nextQuery.maxItems = maxItems;\n        nextQuery.continuationToken = token;\n        result->nextQuery = nextQuery;\n        VERIFY_SUCCEEDED(XblLeaderboardResultGetNextAsync(xboxLiveContext.get(), result, maxItems, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblLeaderboardResultGetNextResultSize(&async, &resultSize));\n\n        XblLeaderboardResult* nextResult{};\n        std::shared_ptr<char> nextBuffer(new char[resultSize], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblLeaderboardResultGetNextResult(&async, resultSize, nextBuffer.get(), &nextResult, nullptr));\n\n        responseJson.Parse(defaultLeaderboardData);\n        VerifyLeadershipResult(nextResult, responseJson);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata\";\n        HCMockClearMocks();\n        HttpMock mock2(\"GET\", url.str(), 200);\n        mock2.SetResponseBody(defaultLeaderboardData);\n\n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Level\" };\n        const char* columns2[2] = { vecColumns[0], vecColumns[1] };\n        query.additionalColumnleaderboardNamesCount = 2;\n        query.additionalColumnleaderboardNames = columns2;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1, vecColumns);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&maxItems=\" << maxItems << \"&continuationToken=6\";\n        HCMockClearMocks();\n        HttpMock mock3(\"GET\", url.str(), 200);\n        mock3.SetResponseBody(defaultLeaderboardData);\n\n        vecColumns.push_back(\"Kills\");\n        vecColumns.push_back(\"Empty\");\n        const char* columns4[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        nextQuery.additionalColumnleaderboardNamesCount = 4;\n        nextQuery.additionalColumnleaderboardNames = columns4;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), nextQuery, defaultLeaderboardData, 1, vecColumns);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardWithLargeBufferAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardWithLargeBufferAsync\");\n\n        TestEnvironment env{};\n\n        const char* token = \"6\";\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultLeaderboardData);\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardAsync(xboxLiveContext.get(), query, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        XblLeaderboardResult* result{};\n        std::shared_ptr<char> buffer(new char[resultSize * 2], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblLeaderboardGetLeaderboardResult(&async, resultSize * 2, buffer.get(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultLeaderboardData);\n        VerifyLeadershipResult(result, responseJson);\n\n        VERIFY_IS_TRUE(result->hasNext);\n\n        const uint32_t maxItems{ 100 };\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?maxItems=\" << maxItems << \"&continuationToken=\" << token;\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n\n        XblLeaderboardQuery nextQuery{ MakeDefaultQuery() };\n        nextQuery.maxItems = maxItems;\n        nextQuery.continuationToken = token;\n        result->nextQuery = nextQuery;\n        VERIFY_SUCCEEDED(XblLeaderboardResultGetNextAsync(xboxLiveContext.get(), result, maxItems, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblLeaderboardResultGetNextResultSize(&async, &resultSize));\n\n        XblLeaderboardResult* nextResult{};\n        std::shared_ptr<char> nextBuffer(new char[resultSize * 2], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblLeaderboardResultGetNextResult(&async, resultSize * 2, nextBuffer.get(), &nextResult, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        responseJson.Parse(defaultLeaderboardData);\n        VerifyLeadershipResult(nextResult, responseJson);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata\";\n        HCMockClearMocks();\n        HttpMock mock2(\"GET\", url.str(), 200);\n        mock2.SetResponseBody(defaultLeaderboardData);\n\n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Level\" };\n        const char* columns2[2] = { vecColumns[0], vecColumns[1] };\n        query.additionalColumnleaderboardNamesCount = 2;\n        query.additionalColumnleaderboardNames = columns2;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 2, vecColumns);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&maxItems=\" << maxItems << \"&continuationToken=6\";\n        HCMockClearMocks();\n        HttpMock mock3(\"GET\", url.str(), 200);\n        mock3.SetResponseBody(defaultLeaderboardData);\n\n        vecColumns.push_back(\"Kills\");\n        vecColumns.push_back(\"Empty\");\n        const char* columns4[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        nextQuery.additionalColumnleaderboardNamesCount = 4;\n        nextQuery.additionalColumnleaderboardNames = columns4;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), nextQuery, defaultLeaderboardData, 2, vecColumns);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardWitSkipToRankAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardWitSkipToRankAsync\");\n\n        TestEnvironment env{};\n\n        const int rank{ 100 };\n        const int maxItems{ 10 };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?maxItems=\" << maxItems << \"&skipToRank=\" << rank;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultLeaderboardData);\n\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        query.maxItems = maxItems;\n        query.skipResultToRank = rank;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&maxItems=\" << maxItems << \"&skipToRank=\" << rank;\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n        \n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Kills\", \"Level\", \"Empty\" };\n        const char* columns[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        query.additionalColumnleaderboardNamesCount = 4;\n        query.additionalColumnleaderboardNames = columns;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1, vecColumns);\n    }\n\n    DEFINE_TEST_CASE(TestGetLearderboardSkipToUserAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLearderboardSkipToUserAsync\");\n\n        TestEnvironment env{};\n\n        const uint64_t user{ 2533274896500838 };\n        const uint32_t maxItems{ 20 };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?maxItems=\" << maxItems << \"&skipToUser=\" << user;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultLeaderboardData);\n\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        query.maxItems = maxItems;\n        query.skipToXboxUserId = user;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&maxItems=\" << maxItems << \"&skipToUser=\" << user;\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n\n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Kills\", \"Level\", \"Empty\" };\n        const char* columns4[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        query.additionalColumnleaderboardNamesCount = 4;\n        query.additionalColumnleaderboardNames = columns4;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1, vecColumns);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardForSocialGroupAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardForSocialGroupAsync\");\n\n        TestEnvironment env{};\n\n        const uint32_t maxItems{ 20 };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"users/xuid(\" << xuid << \")/scids/\" << scid << \"/stats/\" << statName << \"/people/all?sort=descending&maxItems=\" << maxItems;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultV1LeaderboardData);\n\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        query.xboxUserId = xuid;\n        query.leaderboardName = nullptr;\n        query.statName = statName;\n        query.maxItems = maxItems;\n        query.socialGroup = XblSocialGroupType::People;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultV1LeaderboardData, 1);\n\n        mock0.SetResponseBody(defaultLeaderboardData);\n\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?xuid=\" << xuid << \"&maxItems=\" << maxItems << \"&view=People&viewTarget=People\";\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n\n        query.statName = \"\";\n        query.leaderboardName = leaderboardName;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&xuid=\" << xuid << \"&maxItems=\" << maxItems << \"&view=People&viewTarget=People\";\n        HCMockClearMocks();\n        HttpMock mock2(\"GET\", url.str(), 200);\n        mock2.SetResponseBody(defaultLeaderboardData);\n\n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Kills\", \"Level\", \"Empty\" };\n        const char* columns[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        query.additionalColumnleaderboardNamesCount = 4;\n        query.additionalColumnleaderboardNames = columns;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardForSocialGroupWithSortAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardForSocialGroupWithSortAsync\");\n\n        TestEnvironment env{};\n\n        const uint32_t maxItems{ 20 };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"users/xuid(\" << xuid << \")/scids/\" << scid << \"/stats/\" << statName << \"/people/all?sort=descending&maxItems=\" << maxItems;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultV1LeaderboardData);\n        \n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        query.xboxUserId = xuid;\n        query.leaderboardName = nullptr;\n        query.statName = statName;\n        query.maxItems = maxItems;\n        query.socialGroup = XblSocialGroupType::People;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultV1LeaderboardData, 1);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardForSocialGroupWithSkipToRankAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardForSocialGroupWithSkipToRankAsync\");\n\n        TestEnvironment env{};\n\n        const uint32_t rank{ 2 };\n        const uint32_t maxItems{ 20 };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"users/xuid(\" << xuid << \")/scids/\" << scid << \"/stats/\" << statName << \"/people/all?sort=descending&maxItems=\" << maxItems << \"&skipToRank=\" << rank;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultV1LeaderboardData);\n\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        query.xboxUserId = xuid;\n        query.leaderboardName = nullptr;\n        query.statName = statName;\n        query.maxItems = maxItems;\n        query.skipResultToRank = rank;\n        query.socialGroup = XblSocialGroupType::People;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultV1LeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?xuid=\" << xuid << \"&maxItems=\" << maxItems << \"&skipToRank=\" << rank << \"&view=People&viewTarget=People\";\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n\n        query.statName = \"\";\n        query.leaderboardName = leaderboardName;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&xuid=\" << xuid << \"&maxItems=\" << maxItems << \"&skipToRank=\" << rank << \"&view=People&viewTarget=People\";\n        HCMockClearMocks();\n        HttpMock mock2(\"GET\", url.str(), 200);\n        mock2.SetResponseBody(defaultLeaderboardData);\n        \n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Kills\", \"Level\", \"Empty\" };\n        const char* columns4[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        query.additionalColumnleaderboardNamesCount = 4;\n        query.additionalColumnleaderboardNames = columns4;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1, vecColumns);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardForSocialGroupWithSkipToUserAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardForSocialGroupWithSkipToUserAsync\");\n\n        TestEnvironment env{};\n\n        const uint64_t user{ 2533274896500838 };\n        const uint32_t maxItems{ 20 };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << server << \"users/xuid(\" << xuid << \")/scids/\" << scid << \"/stats/\" << statName << \"/people/all?sort=ascending&maxItems=\" << maxItems << \"&skipToUser=\" << user;\n        HttpMock mock0(\"GET\", url.str(), 200);\n        mock0.SetResponseBody(defaultV1LeaderboardData);\n\n        XblLeaderboardQuery query{ MakeDefaultQuery() };\n        query.xboxUserId = xuid;\n        query.leaderboardName = nullptr;\n        query.statName = statName;\n        query.maxItems = maxItems;\n        query.skipToXboxUserId = user;\n        query.socialGroup = XblSocialGroupType::People;\n        query.order = XblLeaderboardSortOrder::Ascending;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultV1LeaderboardData, 1);\n\n        mock0.SetResponseBody(defaultLeaderboardData);\n\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultV1LeaderboardData, 1);\n\n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?xuid=\" << xuid << \"&maxItems=\" << maxItems << \"&skipToUser=\" << user << \"&view=People&viewTarget=People\";\n        HCMockClearMocks();\n        HttpMock mock1(\"GET\", url.str(), 200);\n        mock1.SetResponseBody(defaultLeaderboardData);\n\n        query.statName = \"\";\n        query.leaderboardName = leaderboardName;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1);\n        \n        url.str(\"\");\n        url << server << \"scids/\" << scid << \"/leaderboards/\" << leaderboardName << \"?include=valuemetadata&xuid=\" << xuid << \"&maxItems=\" << maxItems << \"&skipToUser=\" << user << \"&view=People&viewTarget=People\";\n        HCMockClearMocks();\n        HttpMock mock2(\"GET\", url.str(), 200);\n        mock2.SetResponseBody(defaultLeaderboardData);\n\n        std::vector<char const*> vecColumns{ \"HasSkull\", \"Kills\", \"Level\", \"Empty\" };\n        const char* columns4[4] = { vecColumns[0], vecColumns[1], vecColumns[2], vecColumns[3] };\n        query.additionalColumnleaderboardNamesCount = 4;\n        query.additionalColumnleaderboardNames = columns4;\n        TestAndGetLeaderboardResult(xboxLiveContext.get(), query, defaultLeaderboardData, 1, vecColumns);\n    }\n\n    DEFINE_TEST_CASE(TestGetLeaderboardAsyncInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestGetLeaderboardAsyncInvalidArgs\");\n\n        TestEnvironment env{};\n        \n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        XAsyncBlock async{};\n        XblLeaderboardQuery query{};\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(XblLeaderboardGetLeaderboardAsync(nullptr, query, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL_INT(XblLeaderboardGetLeaderboardAsync(xboxLiveContext.get(), query, nullptr), E_INVALIDARG);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/MatchmakingTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\n#define DEFAULT_SCID \"FEEDFACE-0000-0000-0000-000000000001\"\n#define DEFAULT_TEMPLATE_NAME \"TestTemplate\"\n#define DEFAULT_SESSION_ID \"5E55104-0000-0000-0000-000000000001\"\n#define DEFAULT_HOPPER_NAME \"TestHopper\"\n#define DEFAULT_TICKET_ID \"0584338f-a2ff-4eb9-b167-c0e8ddecae72\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(MatchmakingTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(MatchmakingTests);\n    static const JsonDocument testResponseJsonFromFile;\n    const xsapi_internal_string defaultMatchTicketResponse = testResponseJsonFromFile.IsObject() && testResponseJsonFromFile.HasMember(\"defaultMatchTicketResponse\") ? JsonUtils::SerializeJson(testResponseJsonFromFile[\"defaultMatchTicketResponse\"]) : \"\";\n\n    void VerifyTicket(\n        XblCreateMatchTicketResponse* ticket,\n        xsapi_internal_string ticketIdToCheck,\n        int64_t waitTimeToCheck\n        )\n    {\n        VERIFY_ARE_EQUAL_STR(ticket->matchTicketId, ticketIdToCheck.c_str());\n        VERIFY_ARE_EQUAL_INT(ticket->estimatedWaitTime, waitTimeToCheck);\n    }\n\n    void VerifyMultiplayerSessionReference(\n        XblMultiplayerSessionReference* result,\n        const JsonValue& resultToVerify\n        )\n    {\n        VERIFY_ARE_EQUAL_STR(result->Scid, resultToVerify[\"scid\"].GetString());\n        VERIFY_ARE_EQUAL_STR(result->SessionTemplateName, resultToVerify[\"templateName\"].GetString());\n        VERIFY_ARE_EQUAL_STR(result->SessionName, resultToVerify[\"name\"].GetString());\n    }\n\n    char const* ConvertMatchStatusToString(\n        XblTicketStatus ticketStatus\n        )\n    {\n        switch(ticketStatus)\n        {\n        case XblTicketStatus::Canceled:\n            return \"Canceled\";\n        case XblTicketStatus::Expired:\n            return \"Expired\";\n        case XblTicketStatus::Found:\n            return \"Found\";\n        case XblTicketStatus::Searching:\n            return \"Searching\";\n        case XblTicketStatus::Unknown:\n            return \"Unknown\";\n        default:\n            return \"\";\n        }\n    }\n\n    char const* ConvertPerserveSessionModeToString(\n        XblPreserveSessionMode preserveSessionMode\n        )\n    {\n        switch (preserveSessionMode)\n        {\n        case XblPreserveSessionMode::Always:\n            return \"always\";\n        case XblPreserveSessionMode::Never:\n            return \"never\";\n        case XblPreserveSessionMode::Unknown:\n            return \"unknown\";\n        default:\n            return \"\";\n        }\n    }\n\n    void VerifyTicketDetails(\n        XblMatchTicketDetailsResponse* ticket,\n        const JsonValue& json\n        )\n    {\n        VERIFY_ARE_EQUAL_INT(ticket->estimatedWaitTime, json[\"waitTime\"].GetInt());\n        VERIFY_ARE_EQUAL_STR(ConvertMatchStatusToString(ticket->matchStatus),  json[\"ticketStatus\"].GetString());\n        VERIFY_ARE_EQUAL_STR(ConvertPerserveSessionModeToString(ticket->preserveSession), json[\"preserveSession\"].GetString());\n\n        VerifyMultiplayerSessionReference(&ticket->ticketSession, json[\"ticketSessionRef\"]);\n        VerifyMultiplayerSessionReference(&ticket->targetSession, json[\"targetSessionRef\"]);\n\n        JsonDocument ticketAttrJson;\n        ticketAttrJson.Parse(ticket->ticketAttributes);\n        VERIFY_IS_EQUAL_JSON(ticketAttrJson, json[\"ticketAttributes\"]);\n    }\n\n    DEFINE_TEST_CASE(TestCreateMatchTicketAsync)\n    {\n        TEST_LOG(L\"Test starting: TestCreateMatchTicketAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        int64_t timeoutInSeconds = 10;\n\n        XblMultiplayerSessionReference sessionRef{ DEFAULT_SCID, DEFAULT_TEMPLATE_NAME, DEFAULT_SESSION_ID };\n\n       char ticketAttributes[] = R\"({\"desiredMap\":\"Hang 'em high\", \"desiredGameType\":\"Crazy King\"})\";\n\n        char expectedRequest[] =\n            R\"({\"giveUpDuration\":10,\"preserveSession\":\"never\",\"ticketAttributes\":{\"desiredGameType\":\"Crazy King\",\"desiredMap\":\"Hang 'em high\"},\"ticketSessionRef\":{\"name\":\"5E55104-0000-0000-0000-000000000001\",\"scid\":\"FEEDFACE-0000-0000-0000-000000000001\",\"templateName\":\"TestTemplate\"}})\";\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/07617C5B-3423-4505-B6C6-10A16E1E5DDB/hoppers/DeathMatch\";\n\n        JsonDocument expectedResponse; \n        expectedResponse.Parse(R\"({\"ticketId\":\"0584338f-a2ff-4eb9-b167-c0e8ddecae72\", \"waitTime\":60 })\");\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", matchmakingUri );\n        mock->SetResponseBody(expectedResponse);\n\n        bool requestWellFormed { true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(uri);\n                requestWellFormed &= VerifyJson(expectedRequest, body.data());\n            });\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMatchmakingCreateMatchTicketAsync(\n            xboxLiveContext.get(),\n            sessionRef,\n            \"07617C5B-3423-4505-B6C6-10A16E1E5DDB\", // serviceConfigurationId\n            \"DeathMatch\", // hopperName\n            timeoutInSeconds,\n            XblPreserveSessionMode::Never,\n            ticketAttributes,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        XblCreateMatchTicketResponse ticket;\n        VERIFY_SUCCEEDED(XblMatchmakingCreateMatchTicketResult(&async, &ticket));\n\n        int64_t giveUpDurationToVerify = 60; // 60 seconds\n\n        VerifyTicket(\n            &ticket,\n            \"0584338f-a2ff-4eb9-b167-c0e8ddecae72\", // ticketIdToCheck\n            giveUpDurationToVerify // waitTimeToCheck\n            );\n    }\n\n    DEFINE_TEST_CASE(TestCreateMatchTicketAsync_EmptyResult)\n    {\n        TEST_LOG(L\"Test starting: TestCreateMatchTicketAsync_EmptyResult\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        int64_t timeoutInSeconds = 10;\n\n        XblMultiplayerSessionReference sessionRef{ DEFAULT_SCID, DEFAULT_TEMPLATE_NAME, DEFAULT_SESSION_ID };\n\n        JsonDocument expectedResponse;\n        expectedResponse.Parse(R\"({})\");\n\n        char expectedRequest[] =\n            R\"({\"giveUpDuration\":10,\"preserveSession\":\"always\",\"ticketSessionRef\":{\"name\":\"5E55104-0000-0000-0000-000000000001\",\"scid\":\"FEEDFACE-0000-0000-0000-000000000001\",\"templateName\":\"TestTemplate\"}})\";\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/07617C5B-3423-4505-B6C6-10A16E1E5DDB/hoppers/DeathMatch\";\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", matchmakingUri );\n        mock->SetResponseBody(expectedResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(uri);\n                requestWellFormed &= VerifyJson(expectedRequest, body.data());\n            });\n\n        //should return E_INVALIDARG\n        XAsyncBlock async{};\n        HRESULT hr = XblMatchmakingCreateMatchTicketAsync(\n            xboxLiveContext.get(),\n            sessionRef,\n            \"07617C5B-3423-4505-B6C6-10A16E1E5DDB\", // serviceConfigurationId\n            \"DeathMatch\", // hopperName\n            timeoutInSeconds,\n            XblPreserveSessionMode::Always,\n            nullptr,\n            &async\n        );\n\n        VERIFY_ARE_EQUAL(hr, E_INVALIDARG);\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestDeleteMatchTicketAsync)\n    {\n        TEST_LOG(L\"Test starting: TestDeleteMatchTicketAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/FEEDFACE-0000-0000-0000-000000000001/hoppers/TestHopper/tickets/0584338f-a2ff-4eb9-b167-c0e8ddecae72\";\n\n        HttpMock mock{ \"DELETE\", matchmakingUri };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMatchmakingDeleteMatchTicketAsync(\n            xboxLiveContext.get(),\n            DEFAULT_SCID,\n            DEFAULT_HOPPER_NAME,\n            DEFAULT_TICKET_ID,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n    }\n\n    DEFINE_TEST_CASE(TestGetMatchTicketAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetMatchTicketAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument expectedResponse;\n        expectedResponse.Parse(defaultMatchTicketResponse.c_str());\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/FEEDFACE-0000-0000-0000-000000000001/hoppers/TestHopper/tickets/0584338f-a2ff-4eb9-b167-c0e8ddecae72\";\n\n        HttpMock mock{ \"GET\", matchmakingUri };\n        mock.SetResponseBody(expectedResponse);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetMatchTicketDetailsAsync(\n            xboxLiveContext.get(),\n            DEFAULT_SCID,\n            DEFAULT_HOPPER_NAME,\n            DEFAULT_TICKET_ID,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize = 0;\n        VERIFY_SUCCEEDED(XblMatchmakingGetMatchTicketDetailsResultSize(&async, &resultSize));\n        VERIFY_IS_TRUE(resultSize > 0);\n        std::vector<char> buffer(resultSize, 0);\n        XblMatchTicketDetailsResponse* ticketPtr;\n        VERIFY_SUCCEEDED(XblMatchmakingGetMatchTicketDetailsResult(&async, resultSize, buffer.data(), &ticketPtr, nullptr));\n\n        VerifyTicketDetails(ticketPtr, expectedResponse);\n    }\n\n    DEFINE_TEST_CASE(TestGetMatchTicketWithLargeBufferAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetMatchTicketWithLargeBufferAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument expectedResponse;\n        expectedResponse.Parse(defaultMatchTicketResponse.c_str());\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/FEEDFACE-0000-0000-0000-000000000001/hoppers/TestHopper/tickets/0584338f-a2ff-4eb9-b167-c0e8ddecae72\";\n\n        HttpMock mock{ \"GET\", matchmakingUri };\n        mock.SetResponseBody(expectedResponse);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetMatchTicketDetailsAsync(\n            xboxLiveContext.get(),\n            DEFAULT_SCID,\n            DEFAULT_HOPPER_NAME,\n            DEFAULT_TICKET_ID,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize{};\n        size_t bufferUsed{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetMatchTicketDetailsResultSize(&async, &resultSize));\n        VERIFY_IS_TRUE(resultSize > 0);\n        std::vector<char> buffer(resultSize * 2, 0);\n        XblMatchTicketDetailsResponse* ticketPtr;\n        VERIFY_SUCCEEDED(XblMatchmakingGetMatchTicketDetailsResult(&async, resultSize * 2, buffer.data(), &ticketPtr, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        VerifyTicketDetails(ticketPtr, expectedResponse);\n    }\n\n    DEFINE_TEST_CASE(TestGetStatsForHopperAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetStatsForHopperAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        const xsapi_internal_string response = R\"({\"name\":\"gameawesome2\",\"waitTime\":30,\"population\":1})\";\n\n        JsonDocument expectedResponse;\n        expectedResponse.Parse(response.c_str());\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/FEEDFACE-0000-0000-0000-000000000001/hoppers/TestHopper/stats\";\n\n        HttpMock mock{ \"GET\", matchmakingUri };\n        mock.SetResponseBody(expectedResponse);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetHopperStatisticsAsync(\n            xboxLiveContext.get(),\n            DEFAULT_SCID,\n            DEFAULT_HOPPER_NAME,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize = 0;\n        VERIFY_SUCCEEDED(XblMatchmakingGetHopperStatisticsResultSize(&async, &resultSize));\n        VERIFY_IS_TRUE(resultSize > 0);\n        std::vector<char> buffer(resultSize, 0);\n        XblHopperStatisticsResponse* hopper{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetHopperStatisticsResult(&async, resultSize, buffer.data(), &hopper, nullptr));\n\n        VERIFY_ARE_EQUAL_STR(hopper->hopperName, \"gameawesome2\");\n        VERIFY_ARE_EQUAL_INT(hopper->estimatedWaitTime, 30); // 30 seconds\n        VERIFY_ARE_EQUAL_INT(hopper->playersWaitingToMatch, 1U);\n    }\n\n    DEFINE_TEST_CASE(TestGetStatsForHopperWithLargeBufferAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetStatsForHopperWithLargeBufferAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        const xsapi_internal_string response = R\"({\"name\":\"gameawesome2\",\"waitTime\":30,\"population\":1})\";\n\n        JsonDocument expectedResponse;\n        expectedResponse.Parse(response.c_str());\n\n        xsapi_internal_string matchmakingUri = \"https://smartmatch.xboxlive.com/serviceconfigs/FEEDFACE-0000-0000-0000-000000000001/hoppers/TestHopper/stats\";\n\n        HttpMock mock{ \"GET\", matchmakingUri };\n        mock.SetResponseBody(expectedResponse);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetHopperStatisticsAsync(\n            xboxLiveContext.get(),\n            DEFAULT_SCID,\n            DEFAULT_HOPPER_NAME,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize{};\n        size_t bufferUsed{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetHopperStatisticsResultSize(&async, &resultSize));\n        VERIFY_IS_TRUE(resultSize > 0);\n        std::vector<char> buffer(resultSize * 2, 0);\n        XblHopperStatisticsResponse* hopper{};\n        VERIFY_SUCCEEDED(XblMatchmakingGetHopperStatisticsResult(&async, resultSize * 2, buffer.data(), &hopper, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed); \n\n        VERIFY_ARE_EQUAL_STR(hopper->hopperName, \"gameawesome2\");\n        VERIFY_ARE_EQUAL_INT(hopper->estimatedWaitTime, 30); // 30 seconds\n        VERIFY_ARE_EQUAL_INT(hopper->playersWaitingToMatch, 1U);\n    }\n\n    DEFINE_TEST_CASE(TestInvalidArgument)\n    {\n        TEST_LOG(L\"Test starting: TestInvalidArgument\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        int64_t ticketTimeout = 0;\n\n        char ticketAttributes[] = \"\";\n\n        XblMultiplayerSessionReference sessionRef{ \"scid\", \"tempname\", \"sessionid\" };\n\n        XAsyncBlock async{};\n\n        VERIFY_ARE_EQUAL(XblMatchmakingCreateMatchTicketAsync(nullptr, sessionRef, \"configId\", \"hopperName\", ticketTimeout, XblPreserveSessionMode::Always, ticketAttributes, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingCreateMatchTicketAsync(xboxLiveContext.get(), sessionRef, nullptr, \"hopperName\", ticketTimeout, XblPreserveSessionMode::Always, ticketAttributes, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingCreateMatchTicketAsync(xboxLiveContext.get(), sessionRef, \"configId\", nullptr, ticketTimeout, XblPreserveSessionMode::Always, ticketAttributes, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingCreateMatchTicketAsync(xboxLiveContext.get(), sessionRef, \"configId\", \"hopperName\", ticketTimeout, XblPreserveSessionMode::Always, nullptr, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingCreateMatchTicketAsync(xboxLiveContext.get(), sessionRef, \"configId\", \"hopperName\", ticketTimeout, XblPreserveSessionMode::Always, ticketAttributes, nullptr), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL(XblMatchmakingDeleteMatchTicketAsync(nullptr, \"configId\", \"hopperName\", \"ticketId\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingDeleteMatchTicketAsync(xboxLiveContext.get(), nullptr, \"hopperName\", \"ticketId\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingDeleteMatchTicketAsync(xboxLiveContext.get(), \"configId\", nullptr, \"ticketId\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingDeleteMatchTicketAsync(xboxLiveContext.get(), \"configId\", \"hopperName\", nullptr, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingDeleteMatchTicketAsync(xboxLiveContext.get(), \"configId\", \"hopperName\", \"ticketId\", nullptr), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL(XblMatchmakingGetMatchTicketDetailsAsync(nullptr, \"configId\", \"hopperName\", \"ticketId\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetMatchTicketDetailsAsync(xboxLiveContext.get(), nullptr, \"hopperName\", \"ticketId\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetMatchTicketDetailsAsync(xboxLiveContext.get(), \"configId\", nullptr, \"ticketId\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetMatchTicketDetailsAsync(xboxLiveContext.get(), \"configId\", \"hopperName\", nullptr, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetMatchTicketDetailsAsync(xboxLiveContext.get(), \"configId\", \"hopperName\", \"ticketId\", nullptr), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL(XblMatchmakingGetHopperStatisticsAsync(nullptr, \"configId\", \"hopperName\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetHopperStatisticsAsync(xboxLiveContext.get(), nullptr, \"hopperName\", &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetHopperStatisticsAsync(xboxLiveContext.get(), \"configId\", nullptr, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL(XblMatchmakingGetHopperStatisticsAsync(xboxLiveContext.get(), \"configId\", \"hopperName\", nullptr), E_INVALIDARG);\n    }\n};\n\nconst JsonDocument MatchmakingTests::testResponseJsonFromFile{ GetTestResponses(\"TestResponses\\\\Matchmaking.json\") };\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/MultiplayerActivityTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char getActivityResponse[] = R\"(\n{\n  \"userActivities\": [\n    {\n      \"userId\": \"1\",\n      \"activities\": [\n        {\n          \"sequenceNumber\": 0,\n          \"titleId\": 1234,\n          \"connectionString\": \"connectionString\",\n          \"joinRestriction\": \"Public\",\n          \"maxPlayers\": 10,\n          \"currentPlayers\": 2,\n          \"groupId\": \"groupId\",\n          \"platform\": \"XboxOne\"\n        },\n        {\n          \"sequenceNumber\": 0,\n          \"titleId\": 0,\n          \"connectionString\": \"connectionString2\",\n          \"joinRestriction\": \"Public\",\n          \"maxPlayers\": 0,\n          \"currentPlayers\": 0,\n          \"groupId\": \"string\",\n          \"platform\": \"XboxOne\"\n        }\n      ]\n    },\n    {\n      \"userId\": \"2\",\n      \"activities\": [\n        {\n          \"sequenceNumber\": 0,\n          \"titleId\": 1234,\n          \"joinRestriction\": \"Public\",\n          \"maxPlayers\": 2,\n          \"currentPlayers\": 1,\n          \"groupId\": \"groupId\",\n          \"platform\": \"IOS\"\n        }\n      ]\n    }\n  ]\n})\";\n\nDEFINE_TEST_CLASS(MultiplayerActivityTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(MultiplayerActivityTests);\n\n    DEFINE_TEST_CASE(TestUpdateRecentPlayers)\n    {\n        TEST_LOG(L\"Test starting: TestUpdateRecentPlayers\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        Stringstream url;\n        url << \"https://multiplayeractivity.xboxlive.com/titles/\" << MOCK_TITLEID << \"/recentplayers\";\n\n        bool requestWellFormed{ true };\n        const XblMultiplayerActivityRecentPlayerUpdate updates[] = { {1}, {2}, {3} };\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", url.str(), 204 );\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n        {\n            rapidjson::Document d;\n            d.Parse(body.data());\n\n            if (d.HasParseError() || !d.HasMember(\"recentPlayers\"))\n            {\n                requestWellFormed = false;\n            }\n            else\n            {\n                const auto& recentPlayers{ d[\"recentPlayers\"].GetArray() };\n                requestWellFormed = recentPlayers.Size() == _countof(updates);\n            }\n        });\n\n        VERIFY_SUCCEEDED(XblMultiplayerActivityUpdateRecentPlayers(xboxLiveContext.get(), updates, _countof(updates)));\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityFlushRecentPlayersAsync(xboxLiveContext.get(), &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestUpdateRecentPlayersNoFlush)\n    {\n        TEST_LOG(L\"Test starting: TestUpdateRecentPlayersNoFlush\");\n\n        auto env = std::make_unique<TestEnvironment>();\n        auto xboxLiveContext = env->CreateMockXboxLiveContext();\n\n        Stringstream url;\n        url << \"https://multiplayeractivity.xboxlive.com/titles/\" << MOCK_TITLEID << \"/recentplayers\";\n\n        std::unordered_set<uint64_t> updatesSent{};\n        bool requestsWellFormed{ true };\n        size_t httpRequestCount{ 0 };\n\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", url.str(), 204 );\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n        {\n            httpRequestCount++;\n\n            JsonDocument d;\n            d.Parse(body.data());\n\n            if (d.HasParseError() || !d.HasMember(\"recentPlayers\"))\n            {\n                requestsWellFormed = false;\n            }\n            else\n            {\n                const auto& recentPlayers{ d[\"recentPlayers\"].GetArray() };\n                for (const auto& p : recentPlayers)\n                {\n                    updatesSent.insert(strtoull(p[\"id\"].GetString(), nullptr, 0));\n                }\n            }\n        });\n\n        std::vector<XblMultiplayerActivityRecentPlayerUpdate> updatesRequested{};\n\n        constexpr size_t updateCalls{ 10 };\n        std::array<XAsyncBlock, updateCalls> asyncOps{};\n\n        constexpr size_t xuidsPerUpdate{ 10 };\n        for (size_t update = 0; update < updateCalls; ++update)\n        {\n            std::array<XblMultiplayerActivityRecentPlayerUpdate, xuidsPerUpdate> updates;\n            for (size_t i = 0; i < xuidsPerUpdate; ++i)\n            {\n                updates[i] = XblMultiplayerActivityRecentPlayerUpdate{ static_cast<uint64_t>(std::rand() % 10) };\n            }\n            updatesRequested.insert(updatesRequested.end(), updates.begin(), updates.end());\n\n            VERIFY_SUCCEEDED(XblMultiplayerActivityUpdateRecentPlayers(xboxLiveContext.get(), updates.data(), updates.size()));\n\n            // Space out the update requests a random amount\n            Sleep(rand() % 2000);\n        }\n\n        // Cleanup XSAPI and then make sure all updates are flushed\n        xboxLiveContext.reset();\n        env.reset();\n\n        VERIFY_IS_TRUE(requestsWellFormed);\n\n        // Make sure each update eventually made it into a request\n        for (auto update : updatesRequested)\n        {\n            VERIFY_IS_TRUE(updatesSent.find(update.xuid) != updatesSent.end());\n        }\n\n        std::wstringstream ss;\n        ss << updatesRequested.size() << L\" requested updates resulted in \" << httpRequestCount << L\" service requests\";\n        TEST_LOG(ss.str().data());\n    }\n\n    DEFINE_TEST_CASE(TestSetActivity)\n    {\n        TEST_LOG(L\"Test starting: TestSetActivity\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        const char* expectedRequestBody = R\"(\n        {\n            \"connectionString\": \"mockConnectionString\",\n            \"joinRestriction\": \"Public\",\n            \"maxPlayers\": 10\n        })\";\n\n        Stringstream url;\n        url << \"https://multiplayeractivity.xboxlive.com/titles/\" << MOCK_TITLEID << \"/users/\" << xboxLiveContext->Xuid() << \"/activities\";\n        auto mock = std::make_shared<HttpMock>( \"PUT\", url.str(), 204 );\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n            {\n                JsonDocument d;\n                d.Parse(body.data());\n\n                // Don't validate sequence number since that is a timestamp\n                d.RemoveMember(\"sequenceNumber\");\n                requestWellFormed = VerifyJson(d, expectedRequestBody);\n            });\n\n        XblMultiplayerActivityInfo info\n        {\n            xboxLiveContext->Xuid(),\n            \"mockConnectionString\",\n            XblMultiplayerActivityJoinRestriction::Public,\n            10,\n            0,\n            nullptr\n        };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivitySetActivityAsync(\n            xboxLiveContext.get(),\n            &info,\n            true,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    void VerifyActivityInfo(\n        const char* expected,\n        const XblMultiplayerActivityInfo* actual,\n        size_t actualCount\n    ) noexcept\n    {\n        JsonDocument e;\n        e.Parse(expected);\n        VERIFY_IS_FALSE(e.HasParseError());\n\n        size_t i{ 0 };\n        const auto& userActivitiesJson{ e[\"userActivities\"].GetArray() };\n        for (auto& user : userActivitiesJson)\n        {\n            auto xuid{ strtoull(user[\"userId\"].GetString(), nullptr, 0) };\n            const auto& activitesArray{ user[\"activities\"].GetArray() };\n            for (auto& activity : activitesArray)\n            {\n                auto titleId{ activity[\"titleId\"].GetUint() };\n                if (titleId == MOCK_TITLEID)\n                {\n                    VERIFY_IS_TRUE(i < actualCount);\n                    auto& actualActivity{ actual[i++] };\n\n                    VERIFY_ARE_EQUAL_UINT(xuid, actualActivity.xuid);\n                    // Connection string may be missing if the caller doesn't have permission to join an activity\n                    if (activity.HasMember(\"connectionString\"))\n                    {\n                        VERIFY_ARE_EQUAL_STR(activity[\"connectionString\"].GetString(), actualActivity.connectionString);\n                    }\n                    else\n                    {\n                        VERIFY_IS_TRUE(nullptr == actualActivity.connectionString);\n                    }\n                    VERIFY_IS_TRUE(EnumValue<XblMultiplayerActivityJoinRestriction>(activity[\"joinRestriction\"].GetString()) == actualActivity.joinRestriction);\n                    VERIFY_ARE_EQUAL_UINT(activity[\"maxPlayers\"].GetUint64(), actualActivity.maxPlayers);\n                    VERIFY_ARE_EQUAL_UINT(activity[\"currentPlayers\"].GetUint64(), actualActivity.currentPlayers);\n                    VERIFY_ARE_EQUAL_STR(activity[\"groupId\"].GetString(), actualActivity.groupId);\n                    VERIFY_IS_TRUE(EnumValue<XblMultiplayerActivityPlatform>(activity[\"platform\"].GetString()) == actualActivity.platform);\n                }\n            }\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetActivities)\n    {\n        TEST_LOG(L\"Test starting: TestGetActivities\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", \"https://multiplayeractivity.xboxlive.com\" );\n        mock->SetResponseBody(getActivityResponse);\n\n        uint64_t xuids[] = { 1, 2 };\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n            {\n                JsonDocument b;\n                b.Parse(body.data());\n\n                const auto& xuidsArray{ b[\"users\"].GetArray() };\n                requestWellFormed &= (xuidsArray.Size() == _countof(xuids));\n\n                size_t i{ 0 };\n                for (const auto& xuidString : xuidsArray)\n                {\n                    requestWellFormed &= (strtoull(xuidString.GetString(), nullptr, 0) == xuids[i++]);\n                }\n            });\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityGetActivityAsync(\n            xboxLiveContext.get(),\n            xuids,\n            _countof(xuids),\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        size_t bufferSize{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityGetActivityResultSize(&async, &bufferSize));\n\n        std::vector<uint8_t> buffer(bufferSize);\n        XblMultiplayerActivityInfo* activities{ nullptr };\n        size_t activitiesCount{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityGetActivityResult(&async, bufferSize, buffer.data(), &activities, &activitiesCount, nullptr));\n\n        VerifyActivityInfo(getActivityResponse, activities, activitiesCount);\n    }\n\n    DEFINE_TEST_CASE(TestGetActivitiesWithLargeBuffer)\n    {\n        TEST_LOG(L\"Test starting: TestGetActivitiesWithLargeBuffer\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", \"https://multiplayeractivity.xboxlive.com\" );\n        mock->SetResponseBody(getActivityResponse);\n\n        uint64_t xuids[] = { 1, 2 };\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n        {\n            JsonDocument b;\n            b.Parse(body.data());\n\n            const auto& xuidsArray{ b[\"users\"].GetArray() };\n            requestWellFormed &= (xuidsArray.Size() == _countof(xuids));\n\n            size_t i{ 0 };\n            for (const auto& xuidString : xuidsArray)\n            {\n                requestWellFormed &= (strtoull(xuidString.GetString(), nullptr, 0) == xuids[i++]);\n            }\n        });\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityGetActivityAsync(\n            xboxLiveContext.get(),\n            xuids,\n            _countof(xuids),\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        size_t bufferSize{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityGetActivityResultSize(&async, &bufferSize));\n\n        size_t bufferUsed{};\n        std::vector<uint8_t> buffer(bufferSize * 2);\n        XblMultiplayerActivityInfo* activities{ nullptr };\n        size_t activitiesCount{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityGetActivityResult(&async, bufferSize * 2, buffer.data(), &activities, &activitiesCount, &bufferUsed));\n\n        VERIFY_ARE_EQUAL_UINT(bufferSize, bufferUsed);\n\n        VerifyActivityInfo(getActivityResponse, activities, activitiesCount);\n    }\n\n    DEFINE_TEST_CASE(TestDeleteActivity)\n    {\n        TEST_LOG(L\"Test starting: TestDeleteActivity\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        Stringstream url;\n        url << \"https://multiplayeractivity.xboxlive.com/titles/\" << MOCK_TITLEID << \"/users/\" << xboxLiveContext->Xuid() << \"/activities\";\n        HttpMock mock{ \"DELETE\", url.str(), 204 };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivityDeleteActivityAsync(xboxLiveContext.get(), &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n    }\n\n    DEFINE_TEST_CASE(TestSendInvites)\n    {\n        TEST_LOG(L\"Test starting: TestSendInvites\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        const char* expectedRequestBody = R\"(\n        {\n          \"invitedUsers\": [\n            \"1\",\n            \"2\",\n            \"3\"\n          ],\n          \"platform\": \"Win32\",\n          \"connectionString\": \"mockConnectionString\"\n        })\";\n\n        Stringstream url;\n        url << \"https://multiplayeractivity.xboxlive.com/titles/\" << MOCK_TITLEID << \"/invites\";\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", url.str(), 204 );\n\n        bool requestWellFormed{ false };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*url*/, xsapi_internal_string body)\n            {\n                requestWellFormed = VerifyJson(expectedRequestBody, body.data());\n            });\n\n        const uint64_t xuids[] = { 1, 2, 3 };\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerActivitySendInvitesAsync(\n            xboxLiveContext.get(),\n            xuids,\n            _countof(xuids),\n            false,\n            \"mockConnectionString\",\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/MultiplayerManagerTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"multiplayer_manager_internal.h\"\n#include \"UnitTestIncludes.h\"\n\n#pragma warning(disable:4996)\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\n#define GAME_SESSION_NAME    \"MockGameSessionName\"\n#define LOBBY_SESSION_NAME   \"MockLobbySessionName\"\n#define GAME_TEMPLATE_NAME   \"MockGameSessionTemplateName\"\n#define LOBBY_TEMPLATE_NAME  \"MockLobbySessionTemplateName\"\n#define HOPPER_NAME_NO_QOS   \"PlayerSkillNoQoS\"\n#define HOPPER_NAME_WITH_QOS \"PlayerSkill\"\n#define CONNECTION_ADDR      \"AQDXfbIj/QDRr2aLF5vWnwEEAiABSJgA2BES8XsFOdf6/FICIAEAAEE3nnYsBQQNfJRgQwEKfMU7\"\n#define POST                 \"POST\"\n#define GET                  \"GET\"\n\n#define MPSD_URI \"https://sessiondirectory.xboxlive.com\"\n#define MPSD_RTA_URI MPSD_URI \"/connections/\"\n\nstatic concurrency::event g_sessionEvent;\nstatic xbox_live_callback<xbox_live_result<std::shared_ptr<XblMultiplayerSession>>> g_setSessionEvent = [](xbox_live_result<std::shared_ptr<XblMultiplayerSession>>)\n{\n    g_sessionEvent.set();\n};\n\nconst char* defaultGameHttpHeaderUri = \"/serviceconfigs/MockScid/sessionTemplates/MockGameSessionTemplateName/sessions/MockGameSessionName\";\nconst char* defaultMpsdUri = \"https://sessiondirectory.xboxlive.com\";\nconst char* connectionsUri = \"https://sessiondirectory.xboxlive.com/connections\";\nconst char* defaultGameUri = \"https://sessiondirectory.xboxlive.com/serviceconfigs/MockScid/sessionTemplates/MockGameSessionTemplateName/sessions/MockGameSessionName\";\nconst char* defaultLobbyUri = \"https://sessiondirectory.xboxlive.com/serviceconfigs/MockScid/sessionTemplates/MockLobbySessionTemplateName/sessions/MockLobbySessionName\";\nconst char* transferHandleUri = \"https://sessiondirectory.xboxlive.com/handles/TestGameSessionTransferHandle/session\";\nconst char* matchTicketUri = \"https://smartmatch.xboxlive.com/serviceconfigs/MockScid/hoppers/PlayerSkillNoQoS\";\nconst xsapi_internal_http_headers defaultGameHttpResponseHeaders = { { \"ETag\", \"MockETag\" }, { \"Retry-After\", \"1\" }, { \"Content-Location\", \"/serviceconfigs/MockScid/sessionTemplates/MockGameSessionTemplateName/sessions/MockGameSessionName\" } };\nconst xsapi_internal_http_headers defaultLobbyHttpResponseHeaders = { { \"ETag\", \"MockETag\" },{ \"Retry-After\", \"1\" }, { \"Content-Location\", \"/serviceconfigs/MockScid/sessionTemplates/MockLobbySessionTemplateName/sessions/MockLobbySessionName\" } };\n\nconst char* defaultLobbySessionResponse = R\"({  \n       \"membersInfo\":{\n            \"accepted\":0,\n            \"active\":0,  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"default-lobby-session-corrId\",\n       \"changeNumber\":1\n    })\";\n\nconst char* rtaConnectionId = R\"({\n        \"ConnectionId\": \"d01a8c1b-2f83-4e03-9278-3048b480928f\"\n    })\";\n\nDEFINE_TEST_CLASS(MultiplayerManagerTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(MultiplayerManagerTests)\n\n    const char* emptyResponse = R\"({})\";\n    const char* badResponse = R\"({\n        \"badResponse\": null\n    })\";\n    const char* classProperties = R\"({\n        \"properties\":{  \n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       }\n    })\";\n    const char* syncProperties = R\"({\n        \"properties\":{  \n          \"custom\":{  \n             \"Map\":\"MyTestMap\",\n             \"GameMode\":\"MyTestGameMode\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       }\n    })\";\n    const char* propertiesNoTransferHandle = R\"({\n        \"properties\":{  \n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       }\n    })\";\n\n    const char* defaultLobbySessionNoCustomMemberPropsResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{ \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{}\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"default-lobby-session-corrId\",\n       \"changeNumber\":2\n    })\";\n    const char* defaultMultipleLocalUsersLobbyResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"default-multi-user-lobby-session-corrId\",\n       \"changeNumber\":1\n    })\";\n    const char* multipleLocalUsersLobbyResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"3456\",\n                   \"index\":1\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_3\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"default-lobby-session-corrId\",\n       \"changeNumber\":2\n    })\";\n    const char* lobbyWithNoTransferHandleResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobby-no-trans-handle-corrId\",\n       \"changeNumber\":1\n    })\";\n    const char* updatedLobbyWithNoTransferHandleResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"updated-lobby-no-trans-handle-corrId\",\n       \"changeNumber\":4\n    })\";\n    const char* updatedMultipleLocalUsersLobbyWithNoTransferHandleResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"no-trans-handle\",\n       \"changeNumber\":4\n    })\";\n    const char* lobbyWithPendingTransferHandleResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"pending~1234\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobby-pending-trans-handle-corrId\",\n       \"changeNumber\":2\n    })\";\n    const char* lobbyWithCompletedTransferHandleResponse = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobby-completed-trans-handle-corrId\",\n       \"changeNumber\":3\n    })\";\n    const char* defaultGameSessionResponse = R\"({\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"custom\":{},\n\n          \"system\":{}\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"default-game-session-corrId\",\n       \"changeNumber\":1\n    })\";\n    const char* defaultGameSessionWithXuidsResponse = R\"({\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":3,\n          \"count\":3\n       },\n\n       \"constants\":{\n          \"system\":{\n            \"initiators\": [\n                \"TestXboxUserId_1\",\n                \"2345\",\n                \"3456\"\n            ],\n            \"version\": 1\n          },\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"custom\":{},\n\n          \"system\":{}\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"reserved\":true\n          },\n\n          \"2\":{  \n             \"next\":3,\n             \"constants\":{  \n                \"system\":{  \n                   \"xuid\":\"3456\",\n                   \"index\":2\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"reserved\":true\n          }\n       },\n\n       \"correlationId\":\"default-game-session-corrId\",\n       \"changeNumber\":2\n    })\";\n    const char* defaultMultipleLocalUsersGameResponse = R\"({\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"custom\":{},\n\n          \"system\":{}\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"default-multi-user-game-session-corrId\",\n       \"changeNumber\":1\n    })\";\n    const char* gameSessionResponseDiffXuid = R\"({\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"custom\":{},\n\n          \"system\":{}\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"game-session-diff-xuid-corrId\",\n       \"changeNumber\":2\n    })\";\n    const char* sessionChangeNum2 = R\"({  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"sessionChangeNum2-session-corrId\",\n       \"changeNumber\":2\n    })\";\n    const char* sessionChangeNum3 = R\"({  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"sessionChangeNum3-session-corrId\",\n       \"changeNumber\":3\n    })\";\n\n    const char* sessionChangeNum4 = R\"({  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"TestHostDeviceToken\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"MyTestMap\",\n             \"GameMode\":\"MyTestGameMode\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"TestHostDeviceToken\",\n             \"next\":1\n          }\n       },\n\n       \"correlationId\":\"sessionChangeNum4-session-corrId\",\n       \"changeNumber\":4\n    })\";\n\n    const char* sessionChangeNum5 = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"sessionChangeNum5-session-corrId\",\n       \"changeNumber\":5\n    })\";\n\n    const char* sessionChangeNum6 = R\"({  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"sessionChangeNum6-session-corrId\",\n       \"changeNumber\":6\n    })\";\n\n    const char* sessionChangeNum8 = R\"({  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"sessionChangeNum8-session-corrId\",\n       \"changeNumber\":8\n    })\";\n    const char* matchTicketResponse = R\"({\n        \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\",\n        \"waitTime\":502967\n    })\";\n\n    const char* transferHandleResponse = R\"({\n        \"type\": \"transfer\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n\n        \"originSessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"samplelobbytemplate107\",\n            \"name\": \"bd6c41c3-01c3-468a-a3b5-3e0fe8133862\"\n        },\n\n        \"version\": 1\n    })\";\n\n    const char* lobbyMatchStatusSearching = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"status\":\"searching\"\n                },\n\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobbyMatchStatusSearching_corrId\",\n       \"changeNumber\":4\n    })\";\n\n    const char* lobbyMatchStatusExpiredByService = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"status\":\"expired\"\n                },\n\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobbyMatchStatusSearching_corrId\",\n       \"changeNumber\":5\n    })\";\n\n    const char* lobbyMatchStatusFound = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n            \"properties\":{  \n                \"system\":{  \n                   \"status\":\"found\",\n                   \"targetSessionRef\":{  \n                        \"scid\":\"MockScid\",\n                        \"templateName\":\"MockGameSessionTemplateName\",\n                        \"name\":\"MockGameSessionName\"\n                    }\n                },\n\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobbyMatchStatusFound_corrId\",\n       \"changeNumber\":6\n    })\";\n\n    const char* lobbyMatchStatusFoundWithTransHandle = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"status\":\"found\",\n                \"targetSessionRef\":{  \n                      \"scid\":\"MockScid\",\n                      \"templateName\":\"MockGameSessionTemplateName\",\n                      \"name\":\"MockGameSessionName\"\n                },\n\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobbyMatchStatusFoundWithTransHandle\",\n       \"changeNumber\":7\n    })\";\n\n    const char* matchSessionJoin_1 = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":1,\n          \"active\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"initializing\":{\n          \"stage\":\"joining\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"initializationEpisode\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"reserved\":true,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"initializationEpisode\":1\n          }\n       },\n\n       \"correlationId\":\"matchSessionJoin_1_corrId\",\n       \"changeNumber\":2\n    })\";\n\n    const char* matchSessionJoin_2 = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"matchSessionJoin_2_corrId\",\n       \"changeNumber\":4\n    })\";\n\n    const char* matchSessionRemoteClientFailedToJoin = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1,\n          \"accepted\":1,\n          \"active\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"initializing\":{  \n          \"stage\":\"failed\",\n          \"stageStartTime\":\"2016-06-09T18:43:46.0518732Z\",\n          \"episode\":1\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"matchSessionFailedToJoin_corrId\",\n       \"changeNumber\":4\n    })\";\n\n    const char* matchSessionMeasuring = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"initializing\":{\n          \"stage\":\"measuring\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"matchSessionMeasuring_corrId\",\n       \"changeNumber\":3\n    })\";\n\n    const char* matchSessionMeasuringWithQoS = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"initializing\":{\n          \"stage\":\"measuring\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                    \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n\n                         \"latency\":7\n                      }\n                   }\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"matchSessionMeasuringWithQoS_corrId\",\n       \"changeNumber\":4\n    })\";\n\n    const char* matchSessionMeasuringWithQoSComplete = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                    \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n\n                         \"latency\":7\n                      }\n                   }\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                   \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n\n                         \"latency\":7\n                      }\n                   }\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"matchSessionMeasuringWithQoSComplete\",\n       \"changeNumber\":6\n    })\";\n\n    const char* matchRemoteClientFailedToUploadQoS = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n\n       \"initializing\":{\n          \"stage\":\"failed\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n\n       \"servers\":{},\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                    \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n\n                         \"latency\":7\n                      }\n                   }\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"matchSessionMeasuringWithQoS_corrId\",\n       \"changeNumber\":6\n    })\";\n\n    const char* lobbyMatchStatusCanceledByService = R\"({  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n\n       \"constants\":{  \n          \"system\":{},\n\n          \"custom\":{}\n       },\n\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"status\":\"canceled\"\n                },\n\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n\n                \"custom\":{}\n             },\n\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n\n       \"correlationId\":\"lobbyMatchStatusCanceled_corrId\",\n       \"changeNumber\":8\n    })\";\n\n    JsonDocument emptyJson()\n    {\n        JsonDocument json;\n        json.Parse(emptyResponse);\n        return json;\n    }\n\n    JsonDocument badResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(badResponse);\n        return json;\n    }\n\n    JsonDocument rtaConnectionIdJson()\n    {\n        JsonDocument json;\n        json.Parse(rtaConnectionId);\n        return json;\n    }\n\n    JsonDocument matchTicketJson()\n    {\n        JsonDocument json;\n        json.Parse(matchTicketResponse);\n        return json;\n    }\n\n    JsonDocument matchSessionJoin_1Json()\n    {\n        JsonDocument json;\n        json.Parse(matchSessionJoin_1);\n        return json;\n    }\n\n    JsonDocument matchSessionJoin_2Json()\n    {\n        JsonDocument json;\n        json.Parse(matchSessionJoin_2);\n        return json;\n    }\n\n    JsonDocument matchSessionMeasuringJson()\n    {\n        JsonDocument json;\n        json.Parse(matchSessionMeasuring);\n        return json;\n    }\n\n    JsonDocument matchSessionMeasuringWithQoSJson()\n    {\n        JsonDocument json;\n        json.Parse(matchSessionMeasuringWithQoS);\n        return json;\n    }\n\n    JsonDocument matchSessionMeasuringWithQoSCompleteJson()\n    {\n        JsonDocument json;\n        json.Parse(matchSessionMeasuringWithQoSComplete);\n        return json;\n    }\n\n    JsonDocument matchRemoteClientFailedToUploadQoSJson()\n    {\n        JsonDocument json;\n        json.Parse(matchRemoteClientFailedToUploadQoS);\n        return json;\n    }\n\n    JsonDocument matchSessionRemoteClientFailedToJoinJson()\n    {\n        JsonDocument json;\n        json.Parse(matchSessionRemoteClientFailedToJoin);\n        return json;\n    }\n\n    JsonDocument transferHandleJson()\n    {\n        JsonDocument json;\n        json.Parse(transferHandleResponse);\n        return json;\n    }\n\n    JsonDocument classPropertiesJson()\n    {\n        JsonDocument json;\n        json.Parse(classProperties);\n        return json;\n    }\n\n    JsonDocument propertiesNoTransferHandleJson()\n    {\n        JsonDocument json;\n        json.Parse(propertiesNoTransferHandle);\n        return json;\n    }\n\n    JsonDocument syncPropertiesJson()\n    {\n        JsonDocument json;\n        json.Parse(syncProperties);\n        return json;\n    }\n\n    JsonDocument defaultLobbySessionResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(defaultLobbySessionResponse);\n        return json;\n    }\n\n    JsonDocument defaultLobbySessionNoCustomMemberPropsResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(defaultLobbySessionNoCustomMemberPropsResponse);\n        return json;\n    }\n\n    JsonDocument defaultGameSessionResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(defaultGameSessionResponse);\n        return json;\n    }\n\n    JsonDocument defaultGameSessionWithXuidsResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(defaultGameSessionWithXuidsResponse);\n        return json;\n    }\n\n    JsonDocument defaultMultipleLocalUsersGameResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(defaultMultipleLocalUsersGameResponse);\n        return json;\n    }\n\n    JsonDocument gameSessionResponseDiffXuidJson()\n    {\n        JsonDocument json;\n        json.Parse(gameSessionResponseDiffXuid);\n        return json;\n    }\n\n    JsonDocument sessionChangeNum2Json()\n    {\n        JsonDocument json;\n        json.Parse(sessionChangeNum2);\n        return json;\n    }\n\n    JsonDocument sessionChangeNum3Json()\n    {\n        JsonDocument json;\n        json.Parse(sessionChangeNum3);\n        return json;\n    }\n\n    JsonDocument sessionChangeNum4Json()\n    {\n        JsonDocument json;\n        json.Parse(sessionChangeNum4);\n        return json;\n    }\n\n    JsonDocument sessionChangeNum5Json()\n    {\n        JsonDocument json;\n        json.Parse(sessionChangeNum5);\n        return json;\n    }\n\n    JsonDocument sessionChangeNum6Json()\n    {\n        JsonDocument json;\n        json.Parse(sessionChangeNum6);\n        return json;\n    }\n\n    JsonDocument sessionChangeNum8Json()\n    {\n        JsonDocument json;\n        json.Parse(sessionChangeNum8);\n        return json;\n    }\n\n    JsonDocument lobbyMatchStatusSearchingJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyMatchStatusSearching);\n        return json;\n    }\n\n    JsonDocument lobbyMatchStatusFoundJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyMatchStatusFound);\n        return json;\n    }\n\n    JsonDocument lobbyMatchStatusFoundWithTransHandleJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyMatchStatusFoundWithTransHandle);\n        return json;\n    }\n\n    JsonDocument lobbyMatchStatusExpiredByServiceJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyMatchStatusExpiredByService);\n        return json;\n    }\n\n    JsonDocument lobbyMatchStatusCanceledByServiceJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyMatchStatusCanceledByService);\n        return json;\n    }\n\n    JsonDocument lobbyNoHandleResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyWithNoTransferHandleResponse);\n        return json;\n    }\n\n    JsonDocument lobbyPendingTransferHandleResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyWithPendingTransferHandleResponse);\n        return json;\n    }\n\n    JsonDocument multipleLocalUsersLobbyResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(multipleLocalUsersLobbyResponse);\n        return json;\n    }\n\n    JsonDocument updatedLobbyNoHandleResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(updatedLobbyWithNoTransferHandleResponse);\n        return json;\n    }\n\n    JsonDocument updatedMultipleLocalUsersLobbyWithNoTransferHandleResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(updatedMultipleLocalUsersLobbyWithNoTransferHandleResponse);\n        return json;\n    }\n\n    JsonDocument lobbyCompletedHandleResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(lobbyWithCompletedTransferHandleResponse);\n        return json;\n    }\n\n    JsonDocument defaultMultipleLocalUsersLobbyResponseJson()\n    {\n        JsonDocument json;\n        json.Parse(defaultMultipleLocalUsersLobbyResponse);\n        return json;\n    }\n\n    const char* defaultLobbyResponseHeaders = R\"({ \n        \"ETag\":\"MockETag\",\n        \"Retry-After\":\"1\",\n        \"Content-Location\":\"/serviceconfigs/MockScid/sessionTemplates/MockLobbySessionTemplateName/sessions/MockLobbySessionName\"\n    })\";\n\n    private:\n        class MPMTestEnvironment : public TestEnvironment\n        {\n        public:\n            MPMTestEnvironment() noexcept\n            {\n                auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n                mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n                {\n                    if (uri.find(\"sessiondirectory\") != xsapi_internal_string::npos)\n                    {\n                        mockRtaService.CompleteSubscribeHandshake(n, rtaConnectionId);\n                    }\n                });\n            }\n\n            ~MPMTestEnvironment() noexcept\n            {\n                HttpMock mock(POST, defaultMpsdUri, 201);\n                mock.SetResponseBody(defaultLobbySessionResponse);\n                mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n                size_t userRemoved = 0;\n                auto remaining = GlobalState::Get()->MultiplayerManager()->LobbySession()->LocalMembers();\n\n                // Possible all users were removed during a test\n                if (remaining.size() == 0)\n                {\n                    VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n                    \n                    m_xboxLiveContexts.clear();\n                    return;\n                }\n\n                for (auto xboxLiveContext : m_xboxLiveContexts)\n                {\n                    // Possible some users were removed during a test\n                    bool isLobbyMember{ false };\n                    for (auto member : remaining)\n                    {\n                        if (member->Xuid() == xboxLiveContext->User().Xuid())\n                        {\n                            isLobbyMember = true;\n                            break;\n                        }\n                    }\n\n                    if (isLobbyMember)\n                    {\n                        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                    }\n                    else\n                    {\n                        ++userRemoved;\n                    }\n                }\n\n                int count{ 0 };\n                bool clientDisconnected{ false };\n                while (userRemoved != m_xboxLiveContexts.size() || !clientDisconnected)\n                {\n                    if (++count > 500) break;\n\n                    size_t eventsCount{};\n                    const XblMultiplayerEvent* events{};\n                    XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n                    for (uint32_t i = 0; i < eventsCount; ++i)\n                    {\n                        if (events[i].EventType == XblMultiplayerEventType::UserRemoved)\n                        {\n                            userRemoved++;\n                        }\n                        else if (events[i].EventType == XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService)\n                        {\n                            VERIFY_IS_FALSE(clientDisconnected);\n                            clientDisconnected = true;\n                        }\n                    }\n\n                    Sleep(10);\n                }\n\n                VERIFY_IS_TRUE(userRemoved == m_xboxLiveContexts.size() && clientDisconnected);\n                VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n                VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n\n                m_xboxLiveContexts.clear();\n            }\n\n            std::shared_ptr<XblContext> CreateMockXboxLiveContext(uint64_t xuid = MOCK_XUID)\n            {\n                auto context = TestEnvironment::CreateMockXboxLiveContext(xuid);\n                m_xboxLiveContexts.push_back(context);\n                \n                return context;\n            }\n\n        private:\n            std::vector<std::shared_ptr<XblContext>> m_xboxLiveContexts;\n        };\n\n    public:\n\n    bool IsPlayerInLobby(uint64_t xboxUserId)\n    {\n        auto count = XblMultiplayerManagerLobbySessionMembersCount();\n        std::vector<XblMultiplayerManagerMember> members(count);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionMembers(count, members.data()));\n\n        for (auto member : members)\n        {\n            if (xboxUserId == member.Xuid) return true;\n        }\n\n        return false;\n    }\n\n    void DestructManager(XblContextHandle xboxLiveContext)\n    {\n        std::vector<XblContextHandle> xboxLiveContexts{ xboxLiveContext };\n        DestructManager(xboxLiveContexts);\n    }\n\n    void DestructManager(std::vector<XblContextHandle> xboxLiveContexts)\n    {\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(defaultLobbySessionResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        size_t userRemoved = 0;\n        for (auto xboxLiveContext : xboxLiveContexts)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n        }\n\n        int count{ 0 };\n        bool clientDisconnected{ false };\n        while (userRemoved != xboxLiveContexts.size() || !clientDisconnected)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n            \n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::UserRemoved)\n                {\n                    userRemoved++;\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService)\n                {\n                    VERIFY_IS_FALSE(clientDisconnected);\n                    clientDisconnected = true;\n                }\n            }\n\n            Sleep(10);\n        }\n        \n        VERIFY_IS_TRUE(userRemoved == xboxLiveContexts.size() && clientDisconnected);\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n    }\n\n    void VerifyMultiplayerMember(XblMultiplayerManagerMember member, JsonValue resultToVerify)\n    {\n        auto str = JsonUtils::SerializeJson(resultToVerify);\n        UNREFERENCED_PARAMETER(str);\n        JsonValue constantsSystemJson = resultToVerify[\"constants\"][\"system\"].GetObject();\n        \n        VERIFY_ARE_EQUAL_UINT(constantsSystemJson[\"index\"].GetUint(), member.MemberId);\n        VERIFY_ARE_EQUAL_UINT(strtoull(constantsSystemJson[\"xuid\"].GetString(), nullptr, 0), member.Xuid);\n\n        if (member.Status != XblMultiplayerSessionMemberStatus::Reserved)\n        {\n            VERIFY_ARE_EQUAL_STR(resultToVerify[\"gamertag\"].GetString(), member.DebugGamertag);\n            VERIFY_ARE_EQUAL_STR(CONNECTION_ADDR, member.ConnectionAddress);\n        }\n\n        VERIFY_ARE_EQUAL(IsPlayerInLobby(member.Xuid), member.IsInLobby);\n\n        JsonValue propertiesJson = resultToVerify[\"properties\"].GetObject();\n        JsonValue propertiesSystemJson = propertiesJson[\"system\"].GetObject();\n        switch (member.Status)\n        {\n            case XblMultiplayerSessionMemberStatus::Active:\n                VERIFY_IS_TRUE(propertiesSystemJson[\"active\"].GetBool());\n                break;\n            case XblMultiplayerSessionMemberStatus::Ready:\n                VERIFY_IS_TRUE(propertiesSystemJson[\"ready\"].GetBool());\n                break;\n            case XblMultiplayerSessionMemberStatus::Reserved:\n                VERIFY_IS_TRUE(resultToVerify[\"reserved\"].GetBool());\n                break;\n            case XblMultiplayerSessionMemberStatus::Inactive:\n                VERIFY_IS_FALSE(resultToVerify[\"reserved\"].GetBool());\n                VERIFY_IS_FALSE(propertiesSystemJson[\"active\"].GetBool());\n                VERIFY_IS_FALSE(propertiesSystemJson[\"ready\"].GetBool());\n                break;\n            default:\n                throw std::invalid_argument(\"Enum value out of range\");\n        }\n\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(propertiesJson[\"custom\"]), member.PropertiesJson);\n    }\n\n    void VerifyLobby(JsonValue resultToVerify)\n    {\n        JsonValue membersJson = resultToVerify[\"members\"].GetObject();\n        JsonValue memberInfoJson = resultToVerify[\"membersInfo\"].GetObject();\n        \n        uint32_t memberCount = memberInfoJson[\"count\"].GetInt();\n        uint32_t memberFirst = memberInfoJson[\"first\"].GetInt();\n\n        auto lobbyMemberCount = XblMultiplayerManagerLobbySessionMembersCount();\n        auto lobbyLocalMemberCount = XblMultiplayerManagerLobbySessionLocalMembersCount();\n        std::vector<XblMultiplayerManagerMember> lobbyMembers(lobbyMemberCount);\n        std::vector<XblMultiplayerManagerMember> lobbyLocalMembers(lobbyLocalMemberCount);\n        \n        if (lobbyMemberCount > 0)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionMembers(lobbyMemberCount, lobbyMembers.data()));\n        }\n        if (lobbyLocalMemberCount > 0)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionLocalMembers(lobbyLocalMemberCount, lobbyLocalMembers.data()));\n        }\n\n        for (uint32_t i = memberFirst; i < memberCount; ++i)\n        {\n            xsapi_internal_stringstream stream;\n            stream << i;\n\n            if (i < lobbyLocalMemberCount)\n            {\n                VerifyMultiplayerMember(lobbyLocalMembers[i], membersJson[stream.str().data()].GetObject());\n            }\n            else\n            {\n                VerifyMultiplayerMember(lobbyMembers[i], membersJson[stream.str().data()].GetObject());\n            }\n        }\n\n        // Session name is dynamically created by the Manager and not returned back in the service response.\n        XblMultiplayerSessionReference lobbyRef{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSessionReference(&lobbyRef));\n        VERIFY_ARE_EQUAL_STR(MOCK_SCID, lobbyRef.Scid);\n        VERIFY_ARE_EQUAL_STR(LOBBY_TEMPLATE_NAME, lobbyRef.SessionTemplateName);\n\n        XblGuid corrId{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionCorrelationId(&corrId));\n        auto s = resultToVerify[\"correlationId\"].GetString();\n        VERIFY_ARE_EQUAL_STR(s, corrId.value);\n\n        auto lobbyProperties = XblMultiplayerManagerLobbySessionPropertiesJson();\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(resultToVerify[\"properties\"][\"custom\"]), lobbyProperties);\n    }\n\n    void VerifyGame(JsonValue resultToVerify)\n    {\n        JsonValue membersJson = resultToVerify[\"members\"].GetObject();\n        JsonValue memberInfoJson = resultToVerify[\"membersInfo\"].GetObject();\n\n        uint32_t memberCount = memberInfoJson[\"count\"].GetInt();\n        uint32_t memberFirst = memberInfoJson[\"first\"].GetInt();\n\n        auto gameMemberCount = XblMultiplayerManagerGameSessionMembersCount();\n        std::vector<XblMultiplayerManagerMember> gameMembers(gameMemberCount);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerGameSessionMembers(gameMemberCount, gameMembers.data()));\n\n        for (uint32_t i = memberFirst; i < memberCount; ++i)\n        {\n            xsapi_internal_stringstream stream;\n            stream << i;\n\n            VerifyMultiplayerMember(gameMembers[i], membersJson[stream.str().c_str()].GetObject());\n        }\n\n        auto gameRef = XblMultiplayerManagerGameSessionSessionReference();\n        VERIFY_ARE_EQUAL_STR(MOCK_SCID, gameRef->Scid);\n        VERIFY_ARE_EQUAL_STR(GAME_TEMPLATE_NAME, gameRef->SessionTemplateName);\n\n        auto corrId = XblMultiplayerManagerGameSessionCorrelationId();\n        VERIFY_ARE_EQUAL_STR(resultToVerify[\"correlationId\"].GetString(), corrId);\n\n        auto gameProperties = XblMultiplayerManagerGameSessionPropertiesJson();\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(resultToVerify[\"properties\"][\"custom\"]), gameProperties);\n    }\n\n    void VerifyMultiplayerMember(multiplayer::manager::MultiplayerMember* member, JsonValue resultToVerify)\n    {\n        auto str = JsonUtils::SerializeJson(resultToVerify);\n        UNREFERENCED_PARAMETER(str);\n        JsonValue constantsSystemJson = resultToVerify[\"constants\"][\"system\"].GetObject();\n\n        VERIFY_ARE_EQUAL_UINT(constantsSystemJson[\"index\"].GetUint(), member->MemberId());\n        VERIFY_ARE_EQUAL_UINT(strtoull(constantsSystemJson[\"xuid\"].GetString(), nullptr, 0), member->Xuid());\n\n        if (member->Status() != XblMultiplayerSessionMemberStatus::Reserved)\n        {\n            VERIFY_ARE_EQUAL_STR(resultToVerify[\"gamertag\"].GetString(), member->DebugGamertag());\n            VERIFY_ARE_EQUAL_STR(CONNECTION_ADDR, member->ConnectionAddress());\n        }\n\n        VERIFY_ARE_EQUAL(IsPlayerInLobby(member->Xuid()), member->IsInLobby());\n\n        JsonValue propertiesJson = resultToVerify[\"properties\"].GetObject();\n        JsonValue propertiesSystemJson = propertiesJson[\"system\"].GetObject();\n        switch (member->Status())\n        {\n        case XblMultiplayerSessionMemberStatus::Active:\n            VERIFY_IS_TRUE(propertiesSystemJson[\"active\"].GetBool());\n            break;\n        case XblMultiplayerSessionMemberStatus::Ready:\n            VERIFY_IS_TRUE(propertiesSystemJson[\"ready\"].GetBool());\n            break;\n        case XblMultiplayerSessionMemberStatus::Reserved:\n            VERIFY_IS_TRUE(resultToVerify[\"reserved\"].GetBool());\n            break;\n        case XblMultiplayerSessionMemberStatus::Inactive:\n            VERIFY_IS_FALSE(resultToVerify[\"reserved\"].GetBool());\n            VERIFY_IS_FALSE(propertiesSystemJson[\"active\"].GetBool());\n            VERIFY_IS_FALSE(propertiesSystemJson[\"ready\"].GetBool());\n            break;\n        default:\n            throw std::invalid_argument(\"Enum value out of range\");\n        }\n\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(propertiesJson[\"custom\"]), member->CustomPropertiesJson());\n    }\n\n    void VerifyLobby(JsonValue resultToVerify, multiplayer::manager::MultiplayerLobbySession* lobbySession)\n    {\n        JsonValue membersJson = resultToVerify[\"members\"].GetObject();\n        JsonValue memberInfoJson = resultToVerify[\"membersInfo\"].GetObject();\n\n        uint32_t memberCount = memberInfoJson[\"count\"].GetInt();\n        uint32_t memberFirst = memberInfoJson[\"first\"].GetInt();\n\n        for (uint32_t i = memberFirst; i < memberCount; ++i)\n        {\n            xsapi_internal_stringstream stream;\n            stream << i;\n\n            if (i < lobbySession->LocalMembers().size())\n            {\n                VerifyMultiplayerMember(lobbySession->LocalMembers()[i].get(), membersJson[stream.str().data()].GetObject());\n            }\n            else\n            {\n                VerifyMultiplayerMember(lobbySession->LocalMembers()[i].get(), membersJson[stream.str().data()].GetObject());\n            }\n        }\n\n        // Session name is dynamically created by the Manager and not returned back in the service response.\n        VERIFY_ARE_EQUAL_STR(MOCK_SCID, lobbySession->SessionReference().Scid);\n        VERIFY_ARE_EQUAL_STR(LOBBY_TEMPLATE_NAME, lobbySession->SessionReference().SessionTemplateName);\n        VERIFY_ARE_EQUAL_STR(resultToVerify[\"correlationId\"].GetString(), lobbySession->CorrelationId().c_str());\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(resultToVerify[\"properties\"][\"custom\"]), lobbySession->CustomPropertiesJson().c_str());\n    }\n\n    void VerifyGame(JsonValue resultToVerify, multiplayer::manager::MultiplayerGameSession* gameSession)\n    {\n        JsonValue membersJson = resultToVerify[\"members\"].GetObject();\n        JsonValue memberInfoJson = resultToVerify[\"membersInfo\"].GetObject();\n\n        uint32_t memberCount = memberInfoJson[\"count\"].GetInt();\n        uint32_t memberFirst = memberInfoJson[\"first\"].GetInt();\n\n        for (uint32_t i = memberFirst; i < memberCount; ++i)\n        {\n            xsapi_internal_stringstream stream;\n            stream << i;\n\n            VerifyMultiplayerMember(gameSession->Members()[i].get(), membersJson[stream.str().c_str()].GetObject());\n        }\n\n        VERIFY_ARE_EQUAL_STR(MOCK_SCID, gameSession->SessionReference().Scid);\n        VERIFY_ARE_EQUAL_STR(GAME_TEMPLATE_NAME, gameSession->SessionReference().SessionTemplateName);\n        VERIFY_ARE_EQUAL_STR(resultToVerify[\"correlationId\"].GetString(), gameSession->CorrelationId().c_str());\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(resultToVerify[\"properties\"][\"custom\"]), gameSession->Properties().c_str());\n    }\n\n    void VerifyContext12AndIncrement(XblMultiplayerEvent event, uint32_t* counter)\n    {\n        auto pContext = *static_cast<uint32_t*>(event.Context);\n        VERIFY_IS_TRUE(pContext == 1 || pContext == 2);\n        ++*counter;\n    }\n\n    void VerifyContext3AndIncrement(XblMultiplayerEvent event, uint32_t* counter)\n    {\n        auto pContext = *static_cast<uint32_t*>(event.Context);\n        VERIFY_ARE_EQUAL_UINT(3, pContext);\n        ++*counter;\n    }\n\n    std::shared_ptr<XblMultiplayerSession> GetSession(bool isGame)\n    {\n        auto latestPendingRead = GlobalState::Get()->MultiplayerManager()->GetMultiplayerClientManager()->LatestPendingRead();\n\n        if (isGame)\n        {\n            return latestPendingRead->GameClient()->Session();\n        }\n        else\n        {\n            return latestPendingRead->LobbyClient()->Session();\n        }\n    }\n\n    const std::shared_ptr<xbox::services::multiplayer::manager::MultiplayerSessionWriter> GetSessionWriter(bool isGame)\n    {\n        auto latestPendingRead = GlobalState::Get()->MultiplayerManager()->GetMultiplayerClientManager()->LatestPendingRead();\n\n        if (isGame)\n        {\n            return latestPendingRead->LobbyClient()->SessionWriter();\n        }\n        else\n        {\n            return latestPendingRead->LobbyClient()->SessionWriter();\n        }\n    }\n\n    void AddLocalUserHelper(XblContextHandle xboxLiveContext, XTaskQueueHandle queue = {})\n    {\n        AddLocalUserHelper(xboxLiveContext, defaultLobbySessionResponse, queue);\n    }\n\n    void AddLocalUserHelper(XblContextHandle xboxLiveContext, const char* jsonLobbySessionResponse, XTaskQueueHandle queue = {})\n    {\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext));\n\n        HttpMock mock(\"PUT\", defaultMpsdUri, 201);\n        mock.SetResponseBody(jsonLobbySessionResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        uint32_t contextIds[3]{ 1,2,3 };\n        XblUserHandle userHandle = xboxLiveContext->User().Handle();\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(userHandle));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Health\", \"89\", &contextIds[0]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Skill\", \"17\", &contextIds[1]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(userHandle, CONNECTION_ADDR, &contextIds[2]));\n\n        int count{ 0 };\n        bool userAdded{ false };\n        uint32_t localUserPropWritten{ 0 };\n        while (!userAdded || localUserPropWritten != 3)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserAdded:\n                        userAdded = true;\n                        break;\n                    case XblMultiplayerEventType::LocalMemberPropertyWriteCompleted:\n                        VerifyContext12AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                    case XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted:\n                        VerifyContext3AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!userAdded || localUserPropWritten != 3);\n        JsonDocument responseJson;\n        responseJson.Parse(jsonLobbySessionResponse);\n        VerifyLobby(responseJson.GetObject());\n    }\n\n    void AddLocalUserHelperWithSyncUpdate(XblContextHandle xboxLiveContext)\n    {\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext, defaultLobbySessionResponse);\n    }\n\n    void AddLocalUserHelperWithSyncUpdate(XblContextHandle xboxLiveContext, const char* jsonLobbySessionResponse)\n    {\n        XTaskQueueHandle queue{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext));\n        \n        HttpMock mock(POST, defaultMpsdUri, 200);\n        mock.SetResponseBody(jsonLobbySessionResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        // Ids to correlate with event number\n        uint32_t contextId = 0;\n        uint32_t contextIds[11]{ 1,2,3,4,5,6,7,8,9,10,11 };\n        XblUserHandle userHandle = xboxLiveContext->User().Handle();\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(userHandle));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Health\", \"89\", &contextIds[contextId++]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Skill\", \"17\", &contextIds[contextId++]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(userHandle, CONNECTION_ADDR, &contextIds[contextId++]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetProperties(\"Map\", \"1\", &contextIds[contextId++]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\"Map\", \"2\", &contextIds[contextId++]));\n\n        int count{ 0 };\n        bool userAdded{ false };\n        uint32_t localUserPropWritten = 0, propWritten = 0, syncPropWritten = 0, eventValue = 0;\n        while (!userAdded || localUserPropWritten != 3 || propWritten != 4 || syncPropWritten != 4)\n        {\n            if (++count > 500) break;\n\n            if (contextId < 10)\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetProperties(\"Map\", \"3\", &contextIds[contextId++]));\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\"Map\", \"4\", &contextIds[contextId++]));\n            }\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            VERIFY_SUCCEEDED(XblMultiplayerManagerDoWork(&events, &eventsCount));\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                VERIFY_ARE_EQUAL_UINT(XblMultiplayerSessionType::LobbySession, events[i].SessionType);\n\n                if (events[i].Context != nullptr)\n                {\n                    uint32_t context = *static_cast<uint32_t*>(events[i].Context);\n                    \n                    TEST_LOG(FormatString(L\" [MPM] AddLocalUserHelperWithSyncUpdate - Event type: %d - Context: eventValue = %d:%d\", events[i].EventType, context, eventValue).c_str());\n                    VERIFY_ARE_EQUAL_UINT(eventValue, context);\n                }\n                else\n                {\n                    TEST_LOG(FormatString(L\" [MPM] AddLocalUserHelperWithSyncUpdate - Event type: %d - EventValue = %d\", events[i].EventType, eventValue).c_str());\n                }\n\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserAdded:\n                        userAdded = true;\n                        break;\n                    case XblMultiplayerEventType::LocalMemberPropertyWriteCompleted:\n                    case XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted:\n                        localUserPropWritten++;\n                        break;\n                    case XblMultiplayerEventType::SessionPropertyWriteCompleted:\n                        propWritten++;\n                        break;\n                    case XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted:\n                        syncPropWritten++;\n                        break;\n                }\n\n                eventValue++;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!userAdded || localUserPropWritten != 3 || propWritten != 4 || syncPropWritten != 4);\n        JsonDocument responseJson;\n        responseJson.Parse(jsonLobbySessionResponse);\n        VerifyLobby(responseJson.GetObject());\n    }\n\n    void AddMultipleLocalUserHelper(std::vector<XblContextHandle> xboxLiveContexts)\n    {\n        AddMultipleLocalUserHelper(xboxLiveContexts, defaultMultipleLocalUsersLobbyResponse);\n    }\n\n    void AddMultipleLocalUserHelper(std::vector<XblContextHandle> xboxLiveContexts, const char* jsonLobbySessionResponse)\n    {\n        XTaskQueueHandle queue{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        \n        JsonDocument responseJson;\n        responseJson.Parse(jsonLobbySessionResponse);\n\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(jsonLobbySessionResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        uint32_t contextIds[3]{ 1,2,3 };\n        for (auto xboxLiveContext : xboxLiveContexts)\n        {\n            XblUserHandle userHandle = xboxLiveContext->User().Handle();\n            VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext));\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(userHandle));\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Health\", \"89\", &contextIds[0]));\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Skill\", \"17\", &contextIds[1]));\n            VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(userHandle, CONNECTION_ADDR, &contextIds[2]));\n        }\n\n        int count{ 0 };\n        size_t usersAdded = 0;\n        uint32_t localUserPropWritten = 0;\n        while (usersAdded != xboxLiveContexts.size() || localUserPropWritten != (xboxLiveContexts.size() * 3))\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserAdded:\n                        usersAdded++;\n                        break;\n                    case XblMultiplayerEventType::LocalMemberPropertyWriteCompleted:\n                        VerifyContext12AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                    case XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted:\n                        VerifyContext3AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(usersAdded != xboxLiveContexts.size() || localUserPropWritten != (xboxLiveContexts.size() * 3));\n        VerifyLobby(responseJson.GetObject());\n    }\n\n    void RemoveLocalUserHelper(XblContextHandle xboxLiveContext)\n    {\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext);\n\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(emptyResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n\n        int count{ 0 };\n        bool userRemoved = false, clientDisconnected = false;\n        while (!userRemoved || !clientDisconnected)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                TEST_LOG(FormatString(L\" [MPM] RemoveLocalUserHelper - Event type: %d\", events[i].EventType).c_str());\n                if (events[i].EventType == XblMultiplayerEventType::UserRemoved)\n                {\n                    userRemoved = true;\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService)\n                {\n                    VERIFY_IS_FALSE(clientDisconnected);\n                    clientDisconnected = true;\n                }\n            }\n\n            Sleep(10);\n        }\n        \n        VERIFY_IS_FALSE(!userRemoved || !clientDisconnected);\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    DEFINE_TEST_CASE(TestAddLocalUser)\n    {\n        TEST_LOG(L\"Test starting: TestAddLocalUser\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n    }\n\n    DEFINE_TEST_CASE(TestRemoveLocalUser)\n    {\n        TEST_LOG(L\"Test starting: TestRemoveLocalUser\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        RemoveLocalUserHelper(xboxLiveContext.get());\n    }\n\n    DEFINE_TEST_CASE(TestReAddAfterRemovingLocalUser)\n    {\n        TEST_LOG(L\"Test starting: TestReAddAfterRemovingLocalUser\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        RemoveLocalUserHelper(xboxLiveContext.get());\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n    }\n\n    DEFINE_TEST_CASE(TestDeleteLocalMemberProperties)\n    {\n        TEST_LOG(L\"Test starting: TestDeleteLocalMemberProperties\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n\n        HttpMock mock(POST, defaultMpsdUri, 200);\n        mock.SetResponseBody(defaultLobbySessionNoCustomMemberPropsResponseJson());\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        XblUserHandle hostHandle{ xboxLiveContext->User().Handle() };\n        uint32_t contextIds[2]{ 1,2 };\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(hostHandle, \"Health\", &contextIds[0]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(hostHandle, \"Skill\", &contextIds[1]));\n\n        int count{ 0 };\n        uint32_t localUserPropWritten = 0, eventValue = 1;\n        while (localUserPropWritten != 2)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::LocalMemberPropertyWriteCompleted)\n                {\n                    uint32_t context = *static_cast<uint32_t*>(events[i].Context);\n                    VERIFY_ARE_EQUAL_UINT(eventValue++, context);\n                    localUserPropWritten++;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(localUserPropWritten != 2);\n        auto lobbyMemberCount = XblMultiplayerManagerLobbySessionMembersCount();\n        XblMultiplayerManagerMember lobbyMember{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionMembers(lobbyMemberCount, &lobbyMember));\n        VERIFY_ARE_EQUAL_STR(\"{}\", lobbyMember.PropertiesJson);\n    }\n\n    DEFINE_TEST_CASE(TestSetSynchronizedLobbyProperties)\n    {\n        TEST_LOG(L\"Test starting: TestSetSynchronizedLobbyProperties\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n\n        // Set up initial http responses\n        std::vector<const char*> writeResponses\n        {\n            sessionChangeNum4, // change #4\n            sessionChangeNum6  // change #6\n        };\n\n        HttpMock mockWrite(POST, defaultMpsdUri, 201);\n        mockWrite.SetResponseBody(writeResponses[0]);\n        mockWrite.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        XblMultiplayerManagerMember member;\n        uint32_t contextIds[3]{ 1,2,3 };\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\"Map\", \"\\\"MyTestMap\\\"\", &contextIds[0]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\"GameMode\", \"\\\"MyTestGameMode\\\"\", &contextIds[1]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionMembers(1, &member));\n        \n        mockWrite.SetResponseBody(writeResponses[1]);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetSynchronizedHost(member.DeviceToken, &contextIds[2]));\n\n        int count{ 0 };\n        uint32_t syncPropWritten{ 0 };\n        uint32_t syncHostWritten{ 0 };\n        while (syncPropWritten != 2 || syncHostWritten != 1)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                VERIFY_ARE_EQUAL_UINT(XblMultiplayerSessionType::LobbySession, events[i].SessionType);\n                \n                if (events[i].EventType == XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted)\n                {\n                    VerifyContext12AndIncrement(events[i], &syncPropWritten);\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::SynchronizedHostWriteCompleted)\n                {\n                    VerifyContext3AndIncrement(events[i], &syncHostWritten);\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(syncPropWritten != 2 || syncHostWritten != 1);\n        VERIFY_ARE_EQUAL_UINT(6, GlobalState::Get()->MultiplayerManager()->LobbySession()->ChangeNumber());\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]), XblMultiplayerManagerLobbySessionPropertiesJson());\n    }\n\n    DEFINE_TEST_CASE(TestSetSynchronizedGameProperties)\n    {\n        TEST_LOG(L\"Test starting: TestSetSynchronizedGameProperties\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        JoinGameHelper(xboxLiveContext.get());\n\n        // Set up initial http responses\n        std::vector<const char*> writeResponses\n        {\n            sessionChangeNum4, // change #4\n            sessionChangeNum6  // change #6\n        };\n\n        HttpMock writeMock(POST, defaultMpsdUri, 201);\n        writeMock.SetResponseBody(writeResponses[0]);\n        writeMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        XblMultiplayerManagerMember member;\n        uint32_t contextIds[3]{ 1,2,3 };\n        VERIFY_SUCCEEDED(XblMultiplayerManagerGameSessionSetSynchronizedProperties(\"Map\", \"\\\"MyTestMap\\\"\", &contextIds[0]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerGameSessionSetSynchronizedProperties(\"GameMode\", \"\\\"MyTestGameMode\\\"\", &contextIds[1]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerGameSessionMembers(1, &member));\n\n        writeMock.SetResponseBody(writeResponses[1]);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerGameSessionSetSynchronizedHost(member.DeviceToken, &contextIds[2]));\n\n        int count{ 0 };\n        uint32_t syncPropWritten{ 0 };\n        uint32_t syncHostWritten{ 0 };\n        while (syncPropWritten != 2 || syncHostWritten != 1)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::SessionSynchronizedPropertyWriteCompleted)\n                {\n                    VerifyContext12AndIncrement(events[i], &syncPropWritten);\n                    VERIFY_ARE_EQUAL_UINT(XblMultiplayerSessionType::GameSession, events[i].SessionType);\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::SynchronizedHostWriteCompleted)\n                {\n                    VerifyContext3AndIncrement(events[i], &syncHostWritten);\n                    VERIFY_ARE_EQUAL_UINT(XblMultiplayerSessionType::GameSession, events[i].SessionType);\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(syncPropWritten != 2 || syncHostWritten != 1);\n        VERIFY_ARE_EQUAL_UINT(6, GlobalState::Get()->MultiplayerManager()->GameSession()->ChangeNumber());\n        VERIFY_ARE_EQUAL_STR(JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]).c_str(), XblMultiplayerManagerGameSessionPropertiesJson());\n    }\n\n    DEFINE_TEST_CASE(TestLeaveGame)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveGame\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        JoinGameHelper(xboxLiveContext.get());\n\n        HttpMock lobbyMock(GET, defaultMpsdUri, 200);\n        lobbyMock.SetResponseBody(updatedLobbyWithNoTransferHandleResponse);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        HttpMock gameMock(POST, defaultGameHttpHeaderUri, 201);\n        gameMock.SetResponseBody(emptyResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLeaveGame());\n\n        int count{ 0 };\n        bool leaveGameCompleted = false, isStopAdvertisingGameDone = false; \n        auto customProps{ JsonUtils::SerializeJson(propertiesNoTransferHandleJson()[\"properties\"][\"custom\"]) };\n        while (!leaveGameCompleted || !isStopAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::LeaveGameCompleted)\n                {\n                    VERIFY_IS_FALSE(leaveGameCompleted);\n                    leaveGameCompleted = true;\n\n                    GetSessionWriter(false)->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ GetSession(false)->SessionReference(), \"\", 4 });\n                }\n            }\n\n            auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n            if (props != nullptr &&\n                utils::str_icmp(props, customProps.c_str()) == 0)\n            {\n                isStopAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!leaveGameCompleted || !isStopAdvertisingGameDone);\n        VerifyLobby(updatedLobbyNoHandleResponseJson().GetObject());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    DEFINE_TEST_CASE(TestInviteUsers)\n    {\n        TEST_LOG(L\"Test starting: TestInviteUsers\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n\n        HttpMock mock{ \"POST\", MPSD_URI \"/handles\" };\n        std::vector<uint64_t> xuids{ 1234, 5678 };\n#pragma warning(suppress: 6387)\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionInviteUsers(xboxLiveContext->User().Handle(), xuids.data(), xuids.size(), nullptr, nullptr));\n\n        int count{ 0 };\n        bool inviteSent{ false };\n        while (!inviteSent)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount && !inviteSent; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::InviteSent)\n                {\n                    inviteSent = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(inviteSent);\n    }\n\n    void JoinLobbyWithValidHandleIdAndContext(\n        XblContextHandle xboxLiveContext,\n        const char* handleId = nullptr,\n        XblUserHandle userHandle = nullptr,\n        bool checkForInvalidArg = false)\n    {\n        XTaskQueueHandle queue{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext));\n\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(lobbyWithNoTransferHandleResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        if (handleId != nullptr)\n        {\n            xsapi_internal_vector<XblUserHandle> users{};\n            \n            if (userHandle)\n            {\n                users.push_back(userHandle);\n            }\n            \n            auto hr = GlobalState::Get()->MultiplayerManager()->GetMultiplayerClientManager()->JoinLobbyByHandle(handleId, users);\n\n            if (checkForInvalidArg)\n            {\n                VERIFY_ARE_EQUAL_INT(E_INVALIDARG, hr);\n                return;\n            }\n            else\n            {\n                VERIFY_ARE_EQUAL_INT(S_OK, hr);\n            }\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerManagerJoinLobby(\"TestHandleId\", xboxLiveContext->User().Handle()));\n        }\n\n        int count{ 0 };\n        bool lobbyJoined{ false };\n        while (!lobbyJoined)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinLobbyCompleted)\n                {\n                    lobbyJoined = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(lobbyJoined);\n        VerifyLobby(lobbyNoHandleResponseJson().GetObject());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    /*  Join Lobby Tests:\n        1. Test with valid handleId with no transfer handle\n        2. Test with invalid handleId\n        3. Test with valid handleId & valid transfer handle (so that you can join the game).\n        4. Test with valid handleId & invalid transfer handle (don't create the game but clear the game session)\n        5. Test switching lobbies\n    */\n    DEFINE_TEST_CASE(TestJoinLobbyWithValidHandleId)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithValidHandleId\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        JoinLobbyWithValidHandleIdAndContext(xboxLiveContext.get());\n    }\n\n    DEFINE_TEST_CASE(TestJoinLobbyWithValidHandleIdWithEventArgs)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithValidHandleIdWithEventArgs\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        JoinLobbyWithValidHandleIdAndContext(xboxLiveContext.get(), \"TestHandleId\", xboxLiveContext->User().Handle());\n    }\n\n    DEFINE_TEST_CASE(TestJoinLobbyWithInvalidArgs_1)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithInvalidArgs_1\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        JoinLobbyWithValidHandleIdAndContext(xboxLiveContext.get(), \"\", xboxLiveContext->User().Handle(), true);\n    }\n\n    DEFINE_TEST_CASE(TestJoinLobbyWithInvalidArgs_2)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithInvalidArgs_2\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        JoinLobbyWithValidHandleIdAndContext(xboxLiveContext.get(), \"TestHandleId\", nullptr, true);\n    }\n\n    DEFINE_TEST_CASE(TestJoinLobbyWithInvalidHandleId)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithInvalidHandleId\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, 404);\n        lobbyMock.SetResponseBody(lobbyWithNoTransferHandleResponse);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinLobby(\"TestHandleId\", xboxLiveContext->User().Handle()));\n\n        int count{ 0 };\n        bool lobbyJoined{ false };\n        while (!lobbyJoined)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinLobbyCompleted)\n                {\n                    lobbyJoined = true;\n                    VERIFY_ARE_EQUAL_INT(HTTP_E_STATUS_NOT_FOUND, events[i].Result);\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(lobbyJoined);\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n    }\n\n    DEFINE_TEST_CASE(TestJoinLobbyWithValidTransferHandle)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithValidTransferHandle\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, 201);\n        lobbyMock.SetResponseBody(lobbyWithCompletedTransferHandleResponse);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        HttpMock gameMock(POST, transferHandleUri, 201);\n        gameMock.SetResponseBody(defaultGameSessionResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinLobby(\"TestHandleId\", xboxLiveContext->User().Handle()));\n\n        int count{ 0 };\n        bool lobbyJoined = false, gameJoined = false;\n        while (!lobbyJoined || !gameJoined)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinLobbyCompleted)\n                {\n                    lobbyJoined = true;\n                    VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    gameJoined = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!lobbyJoined || !gameJoined);\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n        VerifyGame(defaultGameSessionResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestJoinLobbyWithInvalidTransferHandle)\n    {\n        TEST_LOG(L\"Test starting: TestJoinLobbyWithInvalidTransferHandle\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        std::vector<const char*> lobbyResponses\n        {\n            lobbyWithCompletedTransferHandleResponse,\n            updatedLobbyWithNoTransferHandleResponse\n        };\n\n        std::vector<uint32_t> lobbyStatuses{ 201, 404 };\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, lobbyStatuses[0]);\n        lobbyMock.SetResponseBody(lobbyResponses[0]);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinLobby(\"TestHandleId\", xboxLiveContext->User().Handle()));\n\n        int count{ 0 };\n        bool lobbyJoined = false, gameJoined = false;\n        auto customProps = JsonUtils::SerializeJson(propertiesNoTransferHandleJson()[\"properties\"][\"custom\"]);\n        while (!lobbyJoined || !gameJoined)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinLobbyCompleted)\n                {\n                    lobbyJoined = true;\n\n                    lobbyMock.SetResponseBody(lobbyResponses[1]);\n                    lobbyMock.SetResponseHttpStatus(lobbyStatuses[1]);\n                    VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    gameJoined = true;\n                    VERIFY_ARE_EQUAL_INT(HTTP_E_STATUS_NOT_FOUND, events[i].Result);\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!lobbyJoined || !gameJoined);\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    DEFINE_TEST_CASE(TestSwitchingLobbies)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n\n        // Join a new lobby\n        JoinLobbyWithValidHandleIdAndContext(xboxLiveContext.get());\n    }\n\n    /*\n        1. Test With Transfer Handle\n        2. Test with transfer handle but failed to join game. So create a new game\n        3. Test without transfer handle i.e. create a new game\n        4. Test without transfer handle but failed to create new game\n        5. Test without transfer handle i.e. create a new game but failed to advertise game session (TODO)\n        6. Test without transfer handle - failed to write \"pending~\" with 412 with no transfer handle written (TODO)\n            : retry writing, or both clients will end up creating it's own session.\n    */\n    void JoinGameFromLobbyMultipleUsersHelper(std::vector<XblContextHandle> xboxLiveContexts)\n    {\n        AddMultipleLocalUserHelper(xboxLiveContexts);\n\n        HttpMock mock(POST, transferHandleUri, 201);\n        mock.SetResponseBody(defaultMultipleLocalUsersGameResponse);\n        mock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n\n        int count{ 0 };\n        bool isDone{ false };\n        while (!isDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount && !isDone; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    isDone = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(isDone);\n        VerifyLobby(defaultMultipleLocalUsersLobbyResponseJson().GetObject());\n        VerifyGame(defaultMultipleLocalUsersGameResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameFromLobbyWithTransferHandle)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameFromLobbyWithTransferHandle\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithCompletedTransferHandleResponse);\n\n        HttpMock gameMock(POST, transferHandleUri, 201);\n        gameMock.SetResponseBody(defaultGameSessionResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n\n        int count{ 0 };\n        bool isDone{ false };\n        while (!isDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount && !isDone; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    isDone = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(isDone);\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n        VerifyGame(defaultGameSessionResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameFromLobbyWithTransferHandleMultipleUsers)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameFromLobbyWithTransferHandleMultipleUsers\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext(1234);\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(2345);\n\n        std::vector<XblContextHandle> xboxLiveContexts\n        {\n            xboxLiveContext1.get(),\n            xboxLiveContext2.get(),\n        };\n\n        JoinGameFromLobbyMultipleUsersHelper(xboxLiveContexts);\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameFromLobbyFailedToJoin)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameFromLobbyFailedToJoin\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        std::vector<const char*> lobbyResponses\n        {\n            lobbyWithPendingTransferHandleResponse,\n            defaultGameSessionResponse,\n            lobbyWithCompletedTransferHandleResponse\n        };\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, 201);\n        lobbyMock.SetResponseBody(lobbyResponses[2]);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        HttpMock gameMock(POST, defaultGameHttpHeaderUri, 404);\n        gameMock.SetResponseBody(defaultGameSessionResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n        \n        HttpMock transferMock(POST, transferHandleUri, 404);\n        transferMock.SetResponseBody(defaultGameSessionResponse);\n        transferMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n\n        int count{ 0 };\n        bool isGameJoined = false, isAdvertisingGameDone = false;\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        while (!isGameJoined || !isAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount && !isGameJoined; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    isGameJoined = true;\n                }\n            }\n\n            auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n            if (isGameJoined && \n                props != nullptr &&\n                utils::str_icmp(props, customProps.c_str()) == 0)\n            {\n                isAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!isGameJoined || !isAdvertisingGameDone);\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n        VerifyGame(lobbyCompletedHandleResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameFromLobbyNoHandleCreateNewGame)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameFromLobbyNoHandleCreateNewGame\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithNoTransferHandleResponse);\n\n        std::vector<const char*> lobbyResponses\n        {\n            lobbyWithPendingTransferHandleResponse,\n            defaultGameSessionResponse,\n            lobbyWithCompletedTransferHandleResponse\n        };\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, 200);\n        lobbyMock.SetResponseBody(lobbyResponses[2]);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n\n        int count{ 0 };\n        bool isDone = false, isAdvertisingGameDone = false;\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        while (!isDone || !isAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount && !isDone; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    isDone = true;\n                }\n            }\n            \n            auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n            if (props != nullptr &&\n                utils::str_icmp(props, customProps.c_str()) == 0)\n            {\n                isAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!isDone || !isAdvertisingGameDone);\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n        VerifyGame(lobbyCompletedHandleResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameFromLobbyNoHandleFailedToCreateNewGame)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameFromLobbyNoHandleFailedToCreateNewGame\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithNoTransferHandleResponse);\n\n        std::vector<const char*> gameResponses\n        {\n            lobbyWithPendingTransferHandleResponse,\n            defaultGameSessionResponse,\n            updatedLobbyWithNoTransferHandleResponse\n        };\n\n        HttpMock gameMock(POST, defaultMpsdUri, 404);\n        gameMock.SetResponseBody(gameResponses[2]);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGameFromLobby(GAME_TEMPLATE_NAME));\n\n        int count{ 0 };\n        bool isDone = false, isStopAdvertisingGameDone = false;\n        auto customProps = JsonUtils::SerializeJson(propertiesNoTransferHandleJson()[\"properties\"][\"custom\"]);\n        while (!isDone || !isStopAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::JoinGameCompleted)\n                {\n                    isDone = true;\n                    VERIFY_ARE_EQUAL_INT(HTTP_E_STATUS_NOT_FOUND, events[i].Result);\n                }\n            }\n\n            auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n            if (isDone &&\n                props != nullptr &&\n                utils::str_icmp(props, customProps.c_str()) == 0)\n            {\n                isStopAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!isDone || !isStopAdvertisingGameDone);\n        VerifyLobby(lobbyNoHandleResponseJson().GetObject());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    void JoinGameHelper(\n        XblContextHandle xboxLiveContext,\n        std::vector<uint64_t> xboxUserIds = {}\n        )\n    {\n        /*\n            join_game_helper -> join_game_for_all_local_members\n            AdvertiseGameSession -> commit_pending_lobby_changes -> commit_lobby_changes_helper (write_session)\n            set_local_member_properties_to_remote_session\n            commit_lobby_changes_helper (set_activity)\n            AdvertiseGameSession -> set_transfer_handle\n            AdvertiseGameSession -> write_session (transfer handle)\n        */\n\n        XTaskQueueHandle queue{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue));\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext));\n\n        auto gameResponse{ xboxUserIds.size() > 0 ? defaultGameSessionWithXuidsResponse\n                                                  : defaultGameSessionResponse };\n\n        std::vector<const char*> lobbyResponses\n        {\n            lobbyWithNoTransferHandleResponse,\n            lobbyWithCompletedTransferHandleResponse\n        };\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, 201);\n        lobbyMock.SetResponseBody(lobbyResponses[0]);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        HttpMock gameMock(POST, defaultGameUri, 201);\n        gameMock.SetResponseBody(gameResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        uint32_t contextIds[3]{ 1,2,3 };\n        XblUserHandle userHandle = xboxLiveContext->User().Handle();\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(userHandle));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Health\", \"89\", &contextIds[0]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"Skill\", \"17\", &contextIds[1]));\n\n        lobbyMock.SetResponseBody(lobbyResponses[1]);\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(userHandle, CONNECTION_ADDR, &contextIds[2]));\n        \n        if (xboxUserIds.size() > 0)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGame(GAME_SESSION_NAME, GAME_TEMPLATE_NAME, xboxUserIds.data(), xboxUserIds.size()));\n        }\n        else\n        {\n#pragma warning(suppress: 6387)\n            VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGame(GAME_SESSION_NAME, GAME_TEMPLATE_NAME, nullptr, 0));\n        }\n\n        int count{ 0 };\n        bool lobbyJoined{ false };\n        bool gameJoined{ false };\n        bool isAdvertisingGameDone{ false };\n        uint32_t localUserPropWritten{ 0 };\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        while (!lobbyJoined || !gameJoined || !isAdvertisingGameDone || localUserPropWritten != 3)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserAdded:\n                        lobbyJoined = true;\n                        break;\n                    case XblMultiplayerEventType::LocalMemberPropertyWriteCompleted:\n                        VerifyContext12AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                    case XblMultiplayerEventType::LocalMemberConnectionAddressWriteCompleted:\n                        VerifyContext3AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                    case XblMultiplayerEventType::JoinGameCompleted:\n                        gameJoined = true;\n                        break;\n                }\n            }\n\n            auto propertiesStr = XblMultiplayerManagerLobbySessionPropertiesJson();\n            if (propertiesStr != nullptr && utils::str_icmp(propertiesStr, customProps.c_str()) == 0)\n            {\n                isAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!lobbyJoined || !gameJoined || !isAdvertisingGameDone || localUserPropWritten != 3);\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n\n        if (xboxUserIds.size() > 0)\n        {\n            VerifyGame(defaultGameSessionWithXuidsResponseJson().GetObject());\n        }\n        else\n        {\n            VerifyGame(defaultGameSessionResponseJson().GetObject());\n        }\n    }\n\n    DEFINE_TEST_CASE(TestJoinGame)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGame\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        JoinGameHelper(xboxLiveContext.get());\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWithXuids)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWithXuids\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        std::vector<uint64_t> initiatorIds{ 1234, 2345, 3456 };\n        JoinGameHelper(xboxLiveContext.get(), initiatorIds);\n    }\n\n    enum class CallingPatternType\n    {\n        Sync,\n        Async,\n        ReverseSync,\n        ReverseAsync,\n        Combination,\n        ReverseCombination\n    };\n\n    void AsyncRemoveLocalUser(XblContextHandle xboxLiveContext, XAsyncBlock* async)\n    {\n        auto uri{ defaultMpsdUri };\n        auto rtaId{ rtaConnectionId };\n        auto response{ defaultLobbySessionResponse };\n        auto headers{ defaultLobbyHttpResponseHeaders };\n\n        RunAsync(async, __FUNCTION__,\n            [xboxLiveContext, rtaId, uri, response, headers](XAsyncOp op, const XAsyncProviderData* data)\n            {\n                UNREFERENCED_PARAMETER(data);\n                switch (op)\n                {\n                    case XAsyncOp::DoWork:\n                    {\n                        HttpMock lobbyMock(POST, uri, 201);\n                        lobbyMock.SetResponseBody(response);\n                        lobbyMock.SetResponseHeaders(headers);\n\n                        return XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle());\n                    }\n                    default:\n                        return S_OK;\n                }\n            });\n    }\n\n    void AsyncJoinGame(XblContextHandle xboxLiveContext, XAsyncBlock* async)\n    {\n        auto uri{ defaultGameUri };\n        auto rtaUri{ defaultMpsdUri };\n        auto rtaId{ rtaConnectionId };\n        auto response{ defaultGameSessionResponse };\n        auto headers{ defaultGameHttpResponseHeaders };\n\n        RunAsync(async, __FUNCTION__,\n            [xboxLiveContext, rtaUri, rtaId, uri, response, headers](XAsyncOp op, const XAsyncProviderData* data)\n            {\n                UNREFERENCED_PARAMETER(data);\n                switch (op)\n                {\n                    case XAsyncOp::DoWork:\n                    {\n                        HttpMock gameMock(POST, uri, 201);\n                        gameMock.SetResponseBody(response);\n                        gameMock.SetResponseHeaders(headers);\n\n#pragma warning(suppress: 6387)\n                        return XblMultiplayerManagerJoinGame(GAME_SESSION_NAME, GAME_TEMPLATE_NAME, nullptr, 0);\n                    }\n                    default:\n                        return S_OK;\n                }\n            });\n    }\n\n    void AsyncLeaveGame(bool& leaveGameCompleted, XAsyncBlock* async)\n    {\n        RunAsync(async, __FUNCTION__,\n            [&leaveGameCompleted](XAsyncOp op, const XAsyncProviderData* data)\n            {\n                UNREFERENCED_PARAMETER(data);\n                switch (op)\n                {\n                    case XAsyncOp::DoWork:\n                    {\n                        auto hr = XblMultiplayerManagerLeaveGame();\n                        if (FAILED(hr))\n                        {\n                            leaveGameCompleted = true;\n                        }\n\n                        return hr;\n                    }\n                    default:\n                        return S_OK;\n                }\n            });\n    }\n\n    void TestLeaveMultiplayerHelper(CallingPatternType type)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        JoinGameHelper(xboxLiveContext.get());\n\n        HttpMock gameMock(GET, defaultGameHttpHeaderUri, 200);\n        gameMock.SetResponseBody(emptyResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        HttpMock lobbyMock(GET, defaultMpsdUri, 200);\n        lobbyMock.SetResponseBody(emptyResponse);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        XAsyncBlock asyncLeave{};\n        XAsyncBlock asyncRemove{};\n        bool leaveGameCompleted{ false };\n\n        switch (type)\n        {\n            case CallingPatternType::Sync:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLeaveGame());\n                break;\n            }\n            case CallingPatternType::ReverseSync:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLeaveGame());\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                break;\n            }\n            case CallingPatternType::Async:\n            {\n                AsyncRemoveLocalUser(xboxLiveContext.get(), &asyncRemove);\n                AsyncLeaveGame(leaveGameCompleted, &asyncLeave);\n                break;\n            }\n            case CallingPatternType::ReverseAsync:\n            {\n                AsyncLeaveGame(leaveGameCompleted, &asyncLeave);\n                AsyncRemoveLocalUser(xboxLiveContext.get(), &asyncRemove);\n                break;\n            }\n            case CallingPatternType::Combination:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                AsyncLeaveGame(leaveGameCompleted, &asyncLeave);\n                break;\n            }\n            case CallingPatternType::ReverseCombination:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLeaveGame());\n                AsyncRemoveLocalUser(xboxLiveContext.get(), &asyncRemove);\n                break;\n            }\n        }\n\n        int count{ 0 };\n        bool userRemoved{ false }, clientDisconnected{ false };\n        while (!userRemoved || !leaveGameCompleted || !clientDisconnected)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserRemoved:\n                        userRemoved = true;\n                        TEST_LOG(L\"TestLeaveMultiplayerHelper - user removed.\");\n                        break;\n                    case XblMultiplayerEventType::LeaveGameCompleted:\n                        leaveGameCompleted = true;\n                        TEST_LOG(L\"TestLeaveMultiplayerHelper - leave game completed.\");\n                        break;\n                    case XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService:\n                        VERIFY_IS_FALSE(clientDisconnected);\n                        clientDisconnected = true;\n                        TEST_LOG(L\"TestLeaveMultiplayerHelper - client disconnected from multiplayer service.\");\n                        break;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!userRemoved || !leaveGameCompleted || !clientDisconnected);\n        XAsyncGetStatus(&asyncLeave, true);\n        XAsyncGetStatus(&asyncRemove, true);\n\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionMembersCount());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    DEFINE_TEST_CASE(TestLeaveMultiplayer_1)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveMultiplayer_1\");\n\n        TestLeaveMultiplayerHelper(CallingPatternType::Sync);\n    }\n\n    DEFINE_TEST_CASE(TestLeaveMultiplayer_2)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveMultiplayer_2\");\n\n        TestLeaveMultiplayerHelper(CallingPatternType::Async);\n    }\n\n    DEFINE_TEST_CASE(TestLeaveMultiplayer_3)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveMultiplayer_3\");\n\n        TestLeaveMultiplayerHelper(CallingPatternType::Combination);\n    }\n\n    DEFINE_TEST_CASE(TestLeaveMultiplayer_4)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveMultiplayer_4\");\n\n        TestLeaveMultiplayerHelper(CallingPatternType::ReverseSync);\n    }\n\n    DEFINE_TEST_CASE(TestLeaveMultiplayer_5)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveMultiplayer_5\");\n\n        TestLeaveMultiplayerHelper(CallingPatternType::ReverseAsync);\n    }\n\n    DEFINE_TEST_CASE(TestLeaveMultiplayer_6)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveMultiplayer_6\");\n\n        TestLeaveMultiplayerHelper(CallingPatternType::ReverseCombination);\n    }\n\n    DEFINE_TEST_CASE(TestMultipleLocalUsers_1)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleLocalUsers_1\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext(1234);\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(2345);\n\n        std::vector<XblContextHandle> xboxLiveContexts{ xboxLiveContext1.get(), xboxLiveContext2.get() };\n        AddMultipleLocalUserHelper(xboxLiveContexts);\n\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(defaultLobbySessionResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext2.get()->User().Handle()));\n\n        int count{ 0 };\n        bool userRemoved{ false };\n        while (!userRemoved)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::UserRemoved)\n                {\n                    userRemoved = true;\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService)\n                {\n                    // Should not have fired as we still have one more user.\n                    VERIFY_IS_TRUE(false);\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(userRemoved);\n        VerifyLobby(defaultMultipleLocalUsersLobbyResponseJson().GetObject());\n    }\n\n    // Add multiple users while removing a user (on diff threads)\n    DEFINE_TEST_CASE(TestMultipleLocalUsers_2)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleLocalUsers_2\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext(1234);\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(2345);\n        auto xboxLiveContext3 = env.CreateMockXboxLiveContext(3456);\n\n        std::vector<XblContextHandle> xboxLiveContexts{ xboxLiveContext1.get(), xboxLiveContext2.get() };\n        AddMultipleLocalUserHelper(xboxLiveContexts);\n\n        HttpMock mock(GET, defaultMpsdUri, 200);\n        mock.SetResponseBody(multipleLocalUsersLobbyResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        uint32_t contextIds[2]{ 1,2 };\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(xboxLiveContext3->User().Handle()));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(xboxLiveContext3->User().Handle(), \"Health\", \"89\", &contextIds[0]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionSetLocalMemberProperties(xboxLiveContext3->User().Handle(), \"Skill\", \"17\", &contextIds[1]));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext2.get()->User().Handle()));\n\n        int count{ 0 };\n        bool userRemoved = false, userAdded = false;\n        uint32_t localUserPropWritten = 0;\n        while (!userRemoved || !userAdded || localUserPropWritten != 2)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserAdded:\n                        userAdded = true;\n                        break;\n                    case XblMultiplayerEventType::LocalMemberPropertyWriteCompleted:\n                        VerifyContext12AndIncrement(events[i], &localUserPropWritten);\n                        break;\n                    case XblMultiplayerEventType::UserRemoved:\n                        userRemoved = true;\n                        break;\n                    case XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService:\n                        // Should not have fired as we still have one more user.\n                        VERIFY_IS_TRUE(false);\n                        break;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!userRemoved || !userAdded || localUserPropWritten != 2);\n        VerifyLobby(multipleLocalUsersLobbyResponseJson().GetObject());\n    }\n\n    // Constantly add/remove users\n    DEFINE_TEST_CASE(TestMultipleLocalUsers_3)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleLocalUsers_3\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext(1234);\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(2345);\n        auto xboxLiveContext3 = env.CreateMockXboxLiveContext(3456);\n        auto xboxLiveContext4 = env.CreateMockXboxLiveContext(4567);\n        auto xboxLiveContext5 = env.CreateMockXboxLiveContext(5678);\n\n        std::vector<XblContextHandle> xboxLiveContexts{ xboxLiveContext1.get(), xboxLiveContext2.get() };\n\n        AddMultipleLocalUserHelper(xboxLiveContexts);\n\n        HttpMock mock(GET, defaultMpsdUri, 200);\n        mock.SetResponseBody(multipleLocalUsersLobbyResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(xboxLiveContext3->User().Handle()));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(xboxLiveContext4->User().Handle()));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext2.get()->User().Handle()));\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(xboxLiveContext5->User().Handle()));\n\n        int count{ 0 };\n        uint32_t userRemoved = 0, userAdded = 0, eventCount = 0;\n        // Since the mocked session only has 2 members, you will get into a scenario where the user was removed before he could have been added,\n        // giving you 2 extra added events. However, due to a race between adding & removing (being called on diff threads) this happens only sometimes.\n        while (userRemoved != 3 || userAdded < 3)   \n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (eventCount == 0)\n                {\n                    eventCount++;\n                    VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext4.get()->User().Handle()));\n                }\n                else if (eventCount == 1)\n                {\n                    eventCount++;\n                    VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext5.get()->User().Handle()));\n                }\n\n                switch (events[i].EventType)\n                {\n                    case XblMultiplayerEventType::UserAdded:\n                        userAdded++;\n                        break;\n                    case XblMultiplayerEventType::UserRemoved:\n                        userRemoved++;\n                        break;\n                    case XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService:\n                        // Should not have fired as we still have one more user.\n                        VERIFY_IS_TRUE(false);\n                        break;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(userRemoved != 3 || userAdded < 3);\n        VerifyLobby(multipleLocalUsersLobbyResponseJson().GetObject());\n    }\n\n    void TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType type)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        HttpMock gameMock(POST, defaultGameUri, 201);\n        gameMock.SetResponseBody(defaultGameSessionResponse);\n        gameMock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        HttpMock lobbyMock(POST, defaultMpsdUri, 201);\n        lobbyMock.SetResponseBody(defaultLobbySessionResponse);\n        lobbyMock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        XAsyncBlock asyncJoin{};\n        XAsyncBlock asyncRemove{};\n\n        switch (type)\n        {\n            case CallingPatternType::Sync:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGame(GAME_SESSION_NAME, GAME_TEMPLATE_NAME, nullptr, 0));\n                break;\n            }\n            case CallingPatternType::ReverseSync:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGame(GAME_SESSION_NAME, GAME_TEMPLATE_NAME, nullptr, 0));\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                break;\n            }\n            case CallingPatternType::Async:\n            {\n                AsyncRemoveLocalUser(xboxLiveContext.get(), &asyncRemove);\n                AsyncJoinGame(xboxLiveContext.get(), &asyncJoin);\n                break;\n            }\n            case CallingPatternType::ReverseAsync:\n            {\n                AsyncJoinGame(xboxLiveContext.get(), &asyncJoin);\n                AsyncRemoveLocalUser(xboxLiveContext.get(), &asyncRemove);\n                break;\n            }\n            case CallingPatternType::Combination:\n            {\n                VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionRemoveLocalUser(xboxLiveContext->User().Handle()));\n                AsyncJoinGame(xboxLiveContext.get(), &asyncJoin);\n                break;\n            }\n            case CallingPatternType::ReverseCombination:\n            {\n#pragma warning(suppress: 6387)\n                VERIFY_SUCCEEDED(XblMultiplayerManagerJoinGame(GAME_SESSION_NAME, GAME_TEMPLATE_NAME, nullptr, 0));\n                AsyncRemoveLocalUser(xboxLiveContext.get(), &asyncRemove);\n                break;\n            }\n        }\n\n        int count{ 0 };\n        bool userRemoved = false, clientDisconnected = false;\n        while (!userRemoved || !clientDisconnected)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::UserRemoved)\n                {\n                    userRemoved = true;\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService)\n                {\n                    VERIFY_IS_FALSE(clientDisconnected);\n                    clientDisconnected = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!userRemoved || !clientDisconnected);\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionMembersCount());\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWhileRemovingLocalUser_1)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWhileRemovingLocalUser_1\");\n\n        TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType::Sync);\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWhileRemovingLocalUser_2)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWhileRemovingLocalUser_2\");\n\n        TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType::Async);\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWhileRemovingLocalUser_3)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWhileRemovingLocalUser_3\");\n\n        TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType::Combination);\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWhileRemovingLocalUser_4)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWhileRemovingLocalUser_4\");\n\n        TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType::ReverseSync);\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWhileRemovingLocalUser_5)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWhileRemovingLocalUser_5\");\n\n        TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType::ReverseAsync);\n    }\n\n    DEFINE_TEST_CASE(TestJoinGameWhileRemovingLocalUser_6)\n    {\n        TEST_LOG(L\"Test starting: TestJoinGameWhileRemovingLocalUser_6\");\n\n        TestJoinGameWhileRemovingLocalUserHelper(CallingPatternType::ReverseCombination);\n    }\n\n    DEFINE_TEST_CASE(TestSubscriptionsLostEvent)\n    {\n        TEST_LOG(L\"Test starting: TestSubscriptionsLostEvent\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelperWithSyncUpdate(xboxLiveContext.get());\n\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(emptyResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        GlobalState::Get()->MultiplayerManager()->GetMultiplayerClientManager()->OnMultiplayerSubscriptionsLost();\n\n        int count{ 0 };\n        bool userRemoved = false, clientDisconnected = false;\n        while (!userRemoved || !clientDisconnected)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            VERIFY_SUCCEEDED(XblMultiplayerManagerDoWork(&events, &eventsCount));\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                TEST_LOG(FormatString(L\" [MPM] RemoveLocalUserHelper - Event type: %d\", events[i].EventType).c_str());\n                \n                if (events[i].EventType == XblMultiplayerEventType::UserRemoved)\n                {\n                    userRemoved = true;\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::ClientDisconnectedFromMultiplayerService)\n                {\n                    VERIFY_IS_FALSE(clientDisconnected);\n                    clientDisconnected = true;\n                }\n            }\n\n            Sleep(10);\n        }\n        \n        VERIFY_IS_FALSE(!userRemoved || !clientDisconnected);\n        VERIFY_ARE_EQUAL_UINT(0, XblMultiplayerManagerLobbySessionLocalMembersCount());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    /*\n        multiplayer_session_writer: Back-to-back session writes\n        1. Write change #1 followed with change # 2 == final result #2\n        2. Write change #2 followed with change # 1 == final result #2\n    */\n\n    void TestBackToBackSessionWriteLogicHelper(std::vector<const char*> responses, uint64_t maxChangeNumber)\n    {\n        MPMTestEnvironment env{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get());\n        \n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n\n        Event sessionEvent;\n        auto callback = [&sessionEvent](Result<std::shared_ptr<XblMultiplayerSession>> result)\n        {\n            sessionEvent.Set();\n        };\n        \n        mock.SetResponseBody(responses[0]);\n        VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        sessionEvent.Wait();\n        mock.SetResponseBody(responses[1]);\n        VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        sessionEvent.Wait();\n        mock.SetResponseBody(responses[2]);\n        VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        \n        auto isDone = 0;\n        while (isDone < 10)\n        {\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            Sleep(10);\n            isDone++;\n        }\n\n        VERIFY_ARE_EQUAL_UINT(maxChangeNumber, mpmInstance->LobbySession()->ChangeNumber());\n\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestBackToBackSessionWriteLogic_1)\n    {\n        TEST_LOG(L\"Test starting: TestBackToBackSessionWriteLogic_1\");\n\n        std::vector<const char*> responses\n        {\n            defaultLobbySessionResponse,             // change #1\n            lobbyWithPendingTransferHandleResponse,  // change #2\n            lobbyWithCompletedTransferHandleResponse // change #3\n        };\n\n        TestBackToBackSessionWriteLogicHelper(responses, 3);\n    }\n\n    DEFINE_TEST_CASE(TestBackToBackSessionWriteLogic_2)\n    {\n        TEST_LOG(L\"Test starting: TestBackToBackSessionWriteLogic_2\");\n\n        std::vector<const char*> responses\n        {\n            lobbyWithCompletedTransferHandleResponse, // change #3\n            lobbyWithPendingTransferHandleResponse,   // change #2\n            defaultLobbySessionResponse               // change #1\n        };\n\n        TestBackToBackSessionWriteLogicHelper(responses, 3);\n    }\n\n    void MultipleTapsHelper(std::vector<const char*> getResponses, std::vector<uint32_t> getStatuses, std::vector<uint64_t> changeNumbers, uint64_t maxChangeNumber)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        uint32_t mockCount{ 0 };\n        auto mock = std::make_shared<HttpMock>(GET, defaultMpsdUri);\n        mock->SetResponseBody(getResponses[0]);\n        mock->SetResponseHttpStatus(getStatuses[0]);\n        mock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n        mock->SetMockMatchedCallback([getResponses, getStatuses, &mockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (mockCount < getResponses.size())\n            {\n                matchedMock->SetResponseBody(getResponses[mockCount]);\n                matchedMock->SetResponseHttpStatus(getStatuses[mockCount]);\n                ++mockCount;\n            }\n        });\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        \n        for (uint32_t i = 0; i < getResponses.size(); ++i)\n        {\n            sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", changeNumbers[i] });\n        }\n\n        int count{ 0 };\n        while (mpmInstance->LobbySession()->ChangeNumber() != maxChangeNumber)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            Sleep(10);\n        }\n\n        VERIFY_ARE_EQUAL_UINT(maxChangeNumber, mpmInstance->LobbySession()->ChangeNumber());\n\n        VerifyLobby(lobbyCompletedHandleResponseJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestMultipleTaps_1)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleTaps_1\");\n\n        // Set up initial http responses\n        std::vector<const char*> getResponses\n        {\n            lobbyWithCompletedTransferHandleResponse, // change #3\n            lobbyWithPendingTransferHandleResponse,   // change #2\n            defaultLobbySessionResponse               // change #1\n        };\n\n        std::vector<uint32_t> getStatuses{ 200,200,404 };\n        std::vector<uint64_t> changeNumbers{ 3,2,1 };\n\n        MultipleTapsHelper(getResponses, getStatuses, changeNumbers, 3);\n    }\n\n    DEFINE_TEST_CASE(TestMultipleTaps_2)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleTaps_2\");\n\n        std::vector<const char*> getResponses\n        {\n            lobbyWithPendingTransferHandleResponse,   // change #2\n            lobbyWithCompletedTransferHandleResponse, // change #3\n        };\n\n        std::vector<uint32_t> getStatuses{ 200,200 };\n        std::vector<uint64_t> changeNumbers{ 2,3 };\n\n        MultipleTapsHelper(getResponses, getStatuses, changeNumbers, 3);\n    }\n\n    /*\n        multiplayer_session_writer:\n        Write Session + Taps (write_session & on_session_changed)\n        1. call multiple different writes with shoulder taps in between; ensure that the fianl session # is correct.\n        Note: MPM currently does not optimize to ensure that only 1 GET is in flight for multiple shoulder taps.\n        2. call write (ch. #6) followed with multiple different writes with shoulder taps; ensure that GET is never called.\n        3. call write (ch. #2, #4) followed with shoulder tap (ch. #6); ensure that GET is called.\n    */\n\n    void TestMultipleWriteSessionWithTapsHelper(\n        std::vector<const char*> writeResponses,\n        std::vector<const char*> getResponses,\n        uint64_t maxChangeNumber,\n        xsapi_internal_string handleId = xsapi_internal_string()\n        )\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        HttpMock mockGet(GET, defaultMpsdUri, 200);\n        mockGet.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        HttpMock mockWrite(POST, defaultMpsdUri, 201);\n        mockWrite.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n\n        Event sessionEvent;\n        auto callback = [&sessionEvent](Result<std::shared_ptr<XblMultiplayerSession>> result)\n        {\n            sessionEvent.Set();\n        };\n\n        for (auto writeResponse : writeResponses)\n        {\n            mockWrite.SetResponseBody(writeResponse);\n\n            if (handleId.empty())\n            {\n                VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n            }\n            else\n            {\n                VERIFY_SUCCEEDED(sessionWriter->WriteSessionByHandle(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, handleId, true, callback));\n            }\n\n            sessionEvent.Wait();\n        }\n\n        auto isDone = 0;\n        while (isDone < 10)\n        {\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            Sleep(10);\n            isDone++;\n        }\n\n        VERIFY_ARE_EQUAL_UINT(maxChangeNumber, mpmInstance->LobbySession()->ChangeNumber());\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionWithTaps_1)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionWithTaps_1\");\n\n        // Set up initial http responses\n        std::vector<const char*> writeResponses\n        {\n            lobbyWithPendingTransferHandleResponse, // change #2\n            sessionChangeNum4,                      // change #4\n            sessionChangeNum6                       // change #6\n        };\n\n        std::vector<const char*> getResponses\n        {\n            sessionChangeNum3, // change #3\n            sessionChangeNum5  // change #5\n        };\n\n        TestMultipleWriteSessionWithTapsHelper(writeResponses, getResponses, 6);\n        TestMultipleWriteSessionWithTapsHelper(writeResponses, getResponses, 6, \"TestHandleId\");\n    }\n\n    // The getResponseStruct is used for shoulderTaps.\n    void TestWriteSessionWithTapsHelper(\n        std::vector<const char*> writeResponses, \n        const char* getResponse,\n        uint64_t maxChangeNumberForTap,\n        uint64_t maxChangeNumberToTest,\n        bool waitForFirstWriteToFinish,\n        xsapi_internal_string handleId = xsapi_internal_string()\n        )\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        uint32_t mockCount{ 0 };\n        auto mock = std::make_shared<HttpMock>(POST, defaultMpsdUri, 201);\n        mock->SetResponseBody(writeResponses[0]);\n        mock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n        mock->SetMockMatchedCallback([writeResponses, &mockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (mockCount < writeResponses.size())\n            {\n                matchedMock->SetResponseBody(writeResponses[mockCount]);\n                ++mockCount;\n            }\n        });\n\n        Event sessionEvent;\n        auto callback = [&sessionEvent](Result<std::shared_ptr<XblMultiplayerSession>> result)\n        {\n            sessionEvent.Set();\n        };\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n\n        if (handleId.empty())\n        {\n            VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(sessionWriter->WriteSessionByHandle(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, handleId, true, callback));\n        }\n\n        // Wait before OnSessionChanged or not\n        if (waitForFirstWriteToFinish)\n        {\n            sessionEvent.Wait();\n        }\n\n        auto eventArgs = XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 3 };\n        sessionWriter->OnSessionChanged(eventArgs);\n\n        if (!waitForFirstWriteToFinish)\n        {\n            sessionEvent.Wait();\n        }\n\n        if (handleId.empty())\n        {\n            VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(sessionWriter->WriteSessionByHandle(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, handleId, true, callback));\n        }\n\n        sessionEvent.Wait();\n        auto eventArgs2 = XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 3 };\n        sessionWriter->OnSessionChanged(eventArgs2);\n\n        if (handleId.empty())\n        {\n            VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(sessionWriter->WriteSessionByHandle(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, handleId, true, callback));\n        }\n\n        sessionEvent.Wait();\n        XAsyncBlock async{};\n        mock->SetResponseBody(getResponse);\n        RunAsync(&async, __FUNCTION__,\n            [maxChangeNumberForTap, &sessionEvent, session, sessionWriter](XAsyncOp op, const XAsyncProviderData* data)\n            {\n                UNREFERENCED_PARAMETER(data);\n                switch (op)\n                {\n                case XAsyncOp::DoWork:\n                {\n                    sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", maxChangeNumberForTap });\n\n                    sessionEvent.Set();\n                }\n                default:\n                    return S_OK;\n                }\n            });\n\n        auto isDone = 0;\n        while (isDone < 10)\n        {\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            Sleep(10);\n            isDone++;\n\n            if (isDone == 5)\n            {\n                sessionEvent.Wait();\n            }\n        }\n        \n        VERIFY_ARE_EQUAL_UINT(maxChangeNumberToTest, mpmInstance->LobbySession()->ChangeNumber());\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionWithTaps_2)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionWithTaps_2\");\n\n        std::vector<const char*> writeResponses\n        {\n            sessionChangeNum6,                     // change #6\n            sessionChangeNum4,                     // change #4\n            lobbyWithPendingTransferHandleResponse // change #2\n        };\n\n        const char* getResponse{ sessionChangeNum8 };\n\n        TestWriteSessionWithTapsHelper(writeResponses, getResponse, 5, 6, true);\n        TestWriteSessionWithTapsHelper(writeResponses, getResponse, 5, 6, true, \"TestHandleId\");\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionWithTaps_3)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionWithTaps_3\");\n\n        std::vector<const char*> writeResponses\n        {\n            sessionChangeNum6,                     // change #6\n            sessionChangeNum4,                     // change #4\n            lobbyWithPendingTransferHandleResponse // change #2\n        };\n\n        const char* getResponse{ sessionChangeNum8 };\n\n        TestWriteSessionWithTapsHelper(writeResponses, getResponse, 8, 8, false);\n        TestWriteSessionWithTapsHelper(writeResponses, getResponse, 8, 8, false, \"TestHandleId\");\n    }\n\n    // multiplayer_session_writer:\n    DEFINE_TEST_CASE(TestSessionWriterLeaveRemoteSession)\n    {\n        TEST_LOG(L\"Test starting: TestSessionWriterLeaveRemoteSession\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        JoinGameHelper(xboxLiveContext.get());\n\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto num = mpmInstance->LobbySession()->ChangeNumber();\n        VERIFY_ARE_EQUAL_UINT(3, num);\n\n        HttpMock writeSessionMock{ POST, MPSD_URI, 200 };\n        writeSessionMock.SetResponseBody(sessionChangeNum5);\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n\n        Event sessionEvent;\n        auto callback = [&sessionEvent](Result<std::shared_ptr<XblMultiplayerSession>> joinResult)\n        {\n            sessionEvent.Set();\n        };\n\n        VERIFY_SUCCEEDED(sessionWriter->LeaveRemoteSession(session, callback));\n        sessionEvent.Wait();\n\n        uint32_t isDone = 0;\n        while (isDone < 10)\n        {\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            Sleep(10);\n            isDone++;\n        }\n\n        // Since updateLatest is false, this should not update the latest session.\n        VERIFY_ARE_EQUAL_UINT(3, mpmInstance->LobbySession()->ChangeNumber());\n    }\n\n    DEFINE_TEST_CASE(TestTransferHandleState)\n    {\n        TEST_LOG(L\"Test starting: TestTransferHandleState\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        JoinGameHelper(xboxLiveContext.get());\n\n        // Set up initial http responses\n        std::vector<const char*> writeResponses\n        {\n            lobbyWithPendingTransferHandleResponse,                    // change #2\n            lobbyWithCompletedTransferHandleResponse,                  // change #3\n            updatedMultipleLocalUsersLobbyWithNoTransferHandleResponse // clear_game_session_from_lobby\n        };\n\n        std::vector<const char*> transferHandles\n        {\n            \"1234\",\n            \"TestGameSessionTransferHandle\",\n            \"\"\n        };\n\n        HttpMock mock(GET, defaultMpsdUri, 200);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto clientManager = GlobalState::Get()->MultiplayerManager()->GetMultiplayerClientManager();\n        auto lobbyClient = clientManager->LatestPendingRead()->LobbyClient();\n        VERIFY_IS_TRUE(lobbyClient->IsTransferHandleState(\"completed\"));\n        VERIFY_ARE_EQUAL_STR(transferHandles[1], lobbyClient->GetTransferHandle());\n\n        Event sessionEvent;\n        Result<std::shared_ptr<XblMultiplayerSession>> writeResult;\n        auto callback = [&writeResult, &sessionEvent](Result<std::shared_ptr<XblMultiplayerSession>> result)\n        {\n            writeResult = result;\n            sessionEvent.Set();\n        };\n\n        mock.SetResponseBody(writeResponses[0]);\n        VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        sessionEvent.Wait();\n        clientManager->LatestPendingRead()->LobbyClient()->UpdateSession(writeResult.Payload());\n        VERIFY_IS_TRUE(lobbyClient->IsTransferHandleState(\"completed\"));\n        VERIFY_ARE_EQUAL_STR(transferHandles[1], lobbyClient->GetTransferHandle());\n\n        mock.SetResponseBody(writeResponses[1]);\n        VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        sessionEvent.Wait();\n        clientManager->LatestPendingRead()->LobbyClient()->UpdateSession(writeResult.Payload());\n        VERIFY_IS_TRUE(lobbyClient->IsTransferHandleState(\"completed\"));\n        VERIFY_ARE_EQUAL_STR(transferHandles[1], lobbyClient->GetTransferHandle());\n\n        mock.SetResponseBody(writeResponses[2]);\n        VERIFY_SUCCEEDED(sessionWriter->WriteSession(xboxLiveContext, session, XblMultiplayerSessionWriteMode::UpdateExisting, true, callback));\n        sessionEvent.Wait();\n        clientManager->LatestPendingRead()->LobbyClient()->UpdateSession(writeResult.Payload());\n        VERIFY_IS_FALSE(lobbyClient->IsTransferHandleState(\"pending\"));\n        VERIFY_IS_FALSE(lobbyClient->IsTransferHandleState(\"completed\"));\n        VERIFY_ARE_EQUAL_STR(transferHandles[2], lobbyClient->GetTransferHandle());\n    }\n\n    void LeaveRemoteSessionWithEmptyGameSession(const char* gameSessionResponse, bool removeStaleUsers)\n    {\n        UNREFERENCED_PARAMETER(gameSessionResponse);\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        JoinGameHelper(xboxLiveContext.get());\n\n        HttpMock mockWrite(POST, defaultMpsdUri, 201);\n        mockWrite.SetResponseBody(updatedLobbyWithNoTransferHandleResponse);\n        mockWrite.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        auto lobbySession = GetSession(false);\n        auto gameSession = GetSession(true);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto clientManager = mpmInstance->GetMultiplayerClientManager();\n        auto lobbyClient = clientManager->LatestPendingRead()->LobbyClient();\n        auto gameClient = clientManager->LatestPendingRead()->GameClient();\n        \n        VERIFY_ARE_EQUAL_UINT(1, mpmInstance->GameSession()->ChangeNumber());\n\n        if (removeStaleUsers)\n        {\n            for (auto context : lobbyClient->GetLocalUserMap())\n            {\n                auto user = context.second;\n                if (user != nullptr)\n                {\n                    user->SetLobbyState(multiplayer::manager::MultiplayerLocalUserLobbyState::Remove);\n                }\n            }\n\n            gameClient->RemoveStaleUsersFromRemoteSession();\n        }\n        else\n        {\n            gameClient->LeaveRemoteSession(gameSession, true, true);\n        }\n        \n        int count{ 0 };\n        bool isStopAdvertisingGameDone{ false };\n        auto customProps = JsonUtils::SerializeJson(propertiesNoTransferHandleJson()[\"properties\"][\"custom\"]);\n        while (!isStopAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            XblMultiplayerSessionReadLockGuard lobbySessionSafe(lobbySession);\n            auto props{ lobbySessionSafe.SessionProperties().SessionCustomPropertiesJson };\n            if (utils::str_icmp(props, customProps.c_str()) == 0)\n            {\n                isStopAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(isStopAdvertisingGameDone);\n        VerifyLobby(updatedLobbyNoHandleResponseJson().GetObject());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    void RemoveStaleUsersFromRemoteSession(\n        const char* gameSessionResponse,\n        JsonValue gameSessionResultToVerify\n        )\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext(1234);\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(2345);\n\n        std::vector<XblContextHandle> xboxLiveContexts{ xboxLiveContext1.get(), xboxLiveContext2.get() };\n\n        JoinGameFromLobbyMultipleUsersHelper(xboxLiveContexts);\n\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        VERIFY_ARE_EQUAL_UINT(1, mpmInstance->GameSession()->ChangeNumber());\n        \n        HttpMock mock(GET, defaultMpsdUri, 200);\n        mock.SetResponseBody(updatedLobbyWithNoTransferHandleResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        auto clientManager = mpmInstance->GetMultiplayerClientManager();\n        auto lobbyClient = clientManager->LatestPendingRead()->LobbyClient();\n        auto gameClient = clientManager->LatestPendingRead()->GameClient();\n\n        auto members = mpmInstance->GameSession()->Members();\n\n        for (auto context : lobbyClient->GetLocalUserMap())\n        {\n            auto user = context.second;\n            if (user != nullptr)\n            {\n                user->SetLobbyState(multiplayer::manager::MultiplayerLocalUserLobbyState::Remove);\n            }\n        }\n\n        mock.SetResponseBody(gameSessionResponse);\n        gameClient->RemoveStaleUsersFromRemoteSession();\n\n        uint32_t isDone = 0;\n        while (isDone < 10)\n        {\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            Sleep(10);\n            isDone++;\n        }\n\n        members = mpmInstance->GameSession()->Members();\n        VERIFY_ARE_EQUAL_UINT(2, mpmInstance->LobbySession()->LocalMembers().size());\n        VERIFY_ARE_EQUAL_UINT(1, mpmInstance->GameSession()->Members().size());\n\n        VerifyLobby(defaultMultipleLocalUsersLobbyResponseJson().GetObject());\n        VerifyGame(gameSessionResultToVerify.GetObject());\n    }\n\n    void LeaveRemoteSession()\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext(1234);\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(2345);\n\n        std::vector<XblContextHandle> xboxLiveContexts{ xboxLiveContext1.get(), xboxLiveContext2.get() };\n\n        JoinGameFromLobbyMultipleUsersHelper(xboxLiveContexts);\n\n        auto lobbySession = GetSession(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto gameClient = mpmInstance->GetMultiplayerClientManager()->LatestPendingRead()->GameClient();\n\n        VERIFY_ARE_EQUAL_UINT(1, mpmInstance->GameSession()->ChangeNumber());\n\n        HttpMock mock(POST, defaultMpsdUri, 201);\n        mock.SetResponseBody(updatedMultipleLocalUsersLobbyWithNoTransferHandleResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        HttpMock gamemock(POST, defaultGameUri, 201);\n        gamemock.SetResponseBody(emptyResponse);\n        gamemock.SetResponseHeaders(defaultGameHttpResponseHeaders);\n\n        gameClient->LeaveRemoteSession(GetSession(true), true, true);\n\n        int count{ 0 };\n        auto customProps = JsonUtils::SerializeJson(propertiesNoTransferHandleJson()[\"properties\"][\"custom\"]);\n        bool leaveGameCompleted = false, isStopAdvertisingGameDone = false;\n        while (!leaveGameCompleted || !isStopAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n            \n            if (!leaveGameCompleted)\n            {\n                for (uint32_t i = 0; i < eventsCount; ++i)\n                {\n                    if (events[i].EventType == XblMultiplayerEventType::LeaveGameCompleted)\n                    {\n                        leaveGameCompleted = true;\n                        break;\n                    }\n                }\n            }\n\n            JsonDocument props{};\n            props.Parse(XblMultiplayerManagerLobbySessionPropertiesJson());\n            if (utils::str_icmp(customProps.c_str(), JsonUtils::SerializeJson(props).c_str()) == 0)\n            {\n                isStopAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!leaveGameCompleted || !isStopAdvertisingGameDone);\n        VERIFY_ARE_EQUAL_UINT(2, XblMultiplayerManagerLobbySessionLocalMembersCount());\n\n        VerifyLobby(updatedMultipleLocalUsersLobbyWithNoTransferHandleResponseJson().GetObject());\n        VERIFY_IS_FALSE(XblMultiplayerManagerGameSessionActive());\n    }\n\n    DEFINE_TEST_CASE(TestLeaveRemoteSession)\n    {\n        TEST_LOG(L\"Test starting: TestLeaveRemoteSession\");\n\n        LeaveRemoteSession();\n    }\n\n    DEFINE_TEST_CASE(TestRemoveStaleUsersFromRemoteSession)\n    {\n        TEST_LOG(L\"Test starting: TestRemoveStaleUsersFromRemoteSession\");\n\n        RemoveStaleUsersFromRemoteSession(gameSessionResponseDiffXuid, gameSessionResponseDiffXuidJson().GetObject());\n    }\n\n    DEFINE_TEST_CASE(TestErrorHandling)\n    {\n        TEST_LOG(L\"Test starting: TestErrorHandling\");\n\n        MPMTestEnvironment env{};\n        XTaskQueueHandle queue{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        XblMultiplayerManagerInitialize(LOBBY_TEMPLATE_NAME, queue);\n\n        size_t eventsCount{};\n        const XblMultiplayerEvent* events{};\n        VERIFY_SUCCEEDED(XblMultiplayerManagerDoWork(&events, &eventsCount));\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionAddLocalUser(nullptr)\n            );\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionRemoveLocalUser(nullptr)\n            );\n\n        XblUserHandle userHandle = xboxLiveContext->User().Handle();\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerLobbySessionRemoveLocalUser(userHandle)\n            );\n\n        uint32_t contextIds[2]{ 1,2 };\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionSetLocalMemberProperties(nullptr, \"Health\", \"89\", &contextIds[0])\n            );\n\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerLobbySessionSetLocalMemberProperties(userHandle, \"\", \"89\", &contextIds[1])\n            );\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(nullptr, \"Health\", &contextIds[0])\n            );\n\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerLobbySessionDeleteLocalMemberProperties(userHandle, \"\", &contextIds[0])\n            );\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(nullptr, \"AQAI1Fy6\", &contextIds[0])\n            );\n\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerLobbySessionSetLocalMemberConnectionAddress(userHandle, \"AQAI1Fy6\", &contextIds[0])\n            );\n\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionSetProperties(\"\", \"89\", &contextIds[0])\n            );\n\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerLobbySessionSetSynchronizedProperties(\"name\", \"89\", &contextIds[0])\n            );\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerLobbySessionSetSynchronizedHost(nullptr, &contextIds[0])\n            );\n\n#pragma warning(suppress: 4973)\n        VERIFY_ARE_EQUAL_INT(\n            E_INVALIDARG,\n            XblMultiplayerManagerJoinGame(\"\", GAME_TEMPLATE_NAME, nullptr, 0)\n            );\n\n#pragma warning(suppress: 4973)\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerJoinGame(\"TestSessionName\", GAME_TEMPLATE_NAME, nullptr, 0)\n            );\n\n        VERIFY_SUCCEEDED(XblRealTimeActivityActivate(xboxLiveContext.get()));\n\n        HttpMock mock(POST, defaultMpsdUri, 400);\n        mock.SetResponseBody(badResponse);\n        mock.SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        VERIFY_SUCCEEDED(XblMultiplayerManagerLobbySessionAddLocalUser(userHandle));\n\n        VERIFY_ARE_EQUAL_INT(\n            E_UNEXPECTED,\n            XblMultiplayerManagerLobbySessionAddLocalUser(userHandle)\n            );  // User already added\n\n        int count{ 0 };\n        bool isDone{ false };\n        while (!isDone)\n        {\n            if (++count > 500) break;\n\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::UserAdded)\n                {\n                    VERIFY_ARE_EQUAL_INT(HTTP_E_STATUS_BAD_REQUEST, events[i].Result);\n                    isDone = true;\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(isDone);\n    }\n\n    /*\n        Matchmaking Tests:\n    */\n\n    enum class MatchCallingPatternType\n    {\n        Completed,\n        Canceled,\n        CanceledByService,\n        RemoteClientFailedToJoin,       // initialization stage = failed as the remote client failed to join the target session\n        ExpiredByNextTimer,             // Didn't get any shoulder taps after searching.\n        ExpiredByService,               // Service could not find anything to match with.\n        RemoteClientFailedToUploadQoS   // initialization stage = failed as the remote client failed to upload qos data\n    };\n\n    void FindMatchNoQoSHelper(MatchCallingPatternType matchCallingPattern)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithNoTransferHandleResponse);\n\n        // Set up initial http responses\n        std::vector<const char*> lobbyResponses{ lobbyMatchStatusSearching };\n        std::vector<const char*> gameResponses{ matchSessionJoin_1 };\n\n        if (matchCallingPattern == MatchCallingPatternType::ExpiredByNextTimer || \n            matchCallingPattern == MatchCallingPatternType::ExpiredByService)\n        {\n            lobbyResponses.push_back(lobbyMatchStatusExpiredByService);\n        }\n        else\n        {\n            lobbyResponses.push_back(lobbyMatchStatusFound);\n            lobbyResponses.push_back(lobbyMatchStatusFoundWithTransHandle);\n        }\n\n        if (matchCallingPattern == MatchCallingPatternType::Completed)\n        {\n            gameResponses.push_back(matchSessionJoin_2);\n        }\n        else if (matchCallingPattern == MatchCallingPatternType::RemoteClientFailedToJoin)\n        {\n            gameResponses.push_back(matchSessionRemoteClientFailedToJoin);\n        }\n\n        uint32_t lobbyMockCount{ 0 };\n        auto lobbyMock = std::make_shared<HttpMock>(GET, defaultMpsdUri, 200);\n        lobbyMock->SetResponseBody(lobbyResponses[0]);\n        lobbyMock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n        lobbyMock->SetMockMatchedCallback([lobbyResponses, &lobbyMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (lobbyMockCount < lobbyResponses.size())\n            {\n                matchedMock->SetResponseBody(lobbyResponses[lobbyMockCount]);\n                ++lobbyMockCount;\n            }\n        });\n\n        uint32_t gameMockCount{ 0 };\n        auto gameMock = std::make_shared<HttpMock>(GET, defaultGameUri, 200);\n        gameMock->SetResponseBody(gameResponses[0]);\n        gameMock->SetResponseHeaders(defaultGameHttpResponseHeaders);\n        gameMock->SetMockMatchedCallback([gameResponses, &gameMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (gameMockCount < gameResponses.size())\n            {\n                matchedMock->SetResponseBody(gameResponses[gameMockCount]);\n                ++gameMockCount;\n            }\n        });\n\n        HttpMock matchMock(\"PUT\", matchTicketUri, 201);\n        matchMock.SetResponseBody(matchTicketResponse);\n\n        HttpMock transferMock(\"PUT\", transferHandleUri, 201);\n        transferMock.SetResponseBody(transferHandleResponse);\n\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto clientManager = mpmInstance->GetMultiplayerClientManager();\n\n        JsonDocument doc{};\n        mpmInstance->FindMatch(HOPPER_NAME_NO_QOS, doc, std::chrono::seconds{ TICKS_PER_SECOND });\n        clientManager->MatchClient()->DisableNextTimer(true);\n\n        // Match ticket response\n        // LB: Shoulder tap with a Get: status to searching\n        // LB: Shoulder tap with a Get: status to found\n        // GS: PUT to join\n        // GS: Shoulder tap with a GET with both players joined\n        // Create Transfer handle\n        // LB: PUT Transfer handle\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n\n        int count{ 0 };\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        bool matchFound = false, isAdvertisingGameDone = false, searchingTapTriggered = false, foundTapTriggered = false, waitingForClientsTapTriggered = false;\n        while (!matchFound || !isAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            if (!searchingTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::Searching)\n            {\n                searchingTapTriggered = true;\n                VERIFY_ARE_EQUAL_INT(mpmInstance->EstimatedMatchWaitTime().count(), matchTicketJson()[\"waitTime\"].GetUint64() );\n\n                sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 4 });\n            }\n\n            if (!foundTapTriggered && GlobalState::Get()->MultiplayerManager()->LobbySession()->ChangeNumber() == 4)\n            {\n                foundTapTriggered = true;\n                if (matchCallingPattern == MatchCallingPatternType::ExpiredByNextTimer)\n                {\n                    clientManager->MatchClient()->DisableNextTimer(false);\n                }\n\n                // Session upgraded to searching. Force a tap to change match status == found or expired (ExpiredByService)\n                sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 6 });\n            }\n\n            if (!waitingForClientsTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin)\n            {\n                waitingForClientsTapTriggered = true;\n                if (matchCallingPattern == MatchCallingPatternType::RemoteClientFailedToJoin)\n                {\n                    clientManager->MatchClient()->DisableNextTimer(false);\n                }\n                else if (matchCallingPattern == MatchCallingPatternType::Completed)\n                {\n                    // Force a tap to simulate 2nd user joining.\n                    clientManager->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ clientManager->MatchClient()->Session()->SessionReference(), \"\", 3 });\n                }\n            }\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::FindMatchCompleted)\n                {\n                    matchFound = true; \n                    XblMultiplayerMatchStatus matchStatus{};\n                    VERIFY_SUCCEEDED(XblMultiplayerEventArgsFindMatchCompleted(events[i].EventArgsHandle, &matchStatus, nullptr));\n\n                    switch (matchCallingPattern)\n                    {\n                        case MatchCallingPatternType::Completed:\n                        {\n                            VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Completed, matchStatus);\n                            sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 7 });\n                            break;\n                        }\n                        case MatchCallingPatternType::RemoteClientFailedToJoin:\n                        {\n                            VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Failed, matchStatus);\n                            break;\n                        }\n                        case MatchCallingPatternType::ExpiredByNextTimer:\n                        case MatchCallingPatternType::ExpiredByService:\n                        {\n                            VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Expired, matchStatus);\n                            break;\n                        }\n                    }\n\n                }\n            }\n\n            if (matchFound)\n            {\n                if (matchCallingPattern != MatchCallingPatternType::Completed)\n                {\n                    isAdvertisingGameDone = true;\n                }\n                else\n                {\n                    auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n                    if (props != nullptr &&\n                        utils::str_icmp(props, customProps.c_str()) == 0)\n                    {\n                        isAdvertisingGameDone = true;\n                    }\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!matchFound || !isAdvertisingGameDone);\n    }\n\n    void FindMatchWithQoSHelper(MatchCallingPatternType callingPattern)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithNoTransferHandleResponse);\n\n        // Set up initial http responses\n        std::vector<const char*> lobbyResponses\n        {\n            lobbyMatchStatusSearching,\n            lobbyMatchStatusFound,\n            lobbyMatchStatusFoundWithTransHandle\n        };\n\n        std::vector<const char*> gameResponses\n        { \n            matchSessionJoin_1,\n            matchSessionMeasuring,\n            matchSessionMeasuringWithQoS\n        };\n\n        if (callingPattern == MatchCallingPatternType::RemoteClientFailedToUploadQoS)\n        {\n            gameResponses.push_back(matchRemoteClientFailedToUploadQoS);\n        }\n        else if(callingPattern == MatchCallingPatternType::Completed)\n        {\n            gameResponses.push_back(matchSessionMeasuringWithQoSComplete);\n        }\n\n        uint32_t lobbyMockCount{ 0 };\n        auto lobbyMock = std::make_shared<HttpMock>(GET, defaultMpsdUri, 200);\n        lobbyMock->SetResponseBody(lobbyResponses[0]);\n        lobbyMock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n        lobbyMock->SetMockMatchedCallback([lobbyResponses, &lobbyMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (lobbyMockCount < lobbyResponses.size())\n            {\n                matchedMock->SetResponseBody(lobbyResponses[lobbyMockCount]);\n                ++lobbyMockCount;\n            }\n        });\n\n        uint32_t gameMockCount{ 0 };\n        auto gameMock = std::make_shared<HttpMock>(GET, defaultGameUri, 200);\n        gameMock->SetResponseBody(gameResponses[0]);\n        gameMock->SetResponseHeaders(defaultGameHttpResponseHeaders);\n        gameMock->SetMockMatchedCallback([gameResponses, &gameMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (gameMockCount < gameResponses.size())\n            {\n                matchedMock->SetResponseBody(gameResponses[gameMockCount]);\n                ++gameMockCount;\n            }\n        });\n\n        HttpMock matchMock(\"PUT\", matchTicketUri, 201);\n        matchMock.SetResponseBody(matchTicketResponse);\n\n        HttpMock transferMock(\"PUT\", transferHandleUri, 201);\n        transferMock.SetResponseBody(transferHandleResponse);\n        \n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto clientManager = mpmInstance->GetMultiplayerClientManager();\n\n        JsonDocument doc{};\n        mpmInstance->FindMatch(HOPPER_NAME_NO_QOS, doc, std::chrono::seconds{ TICKS_PER_SECOND });\n        clientManager->MatchClient()->DisableNextTimer(true);\n\n        // Match ticket response\n        // LB: Shoulder tap with a Get: status to searching\n        // LB: Shoulder tap with a Get: status to found\n        // GS: PUT to join\n        // GS: Shoulder tap with a GET with both players joined\n        // GS: Trigger set qos\n        // title: set qos metrics\n        // match completed\n        // Create Transfer handle\n        // LB: PUT Transfer handle\n\n        auto lobbySession = GetSession(false);\n        auto lobbySessionWriter = GetSessionWriter(false);\n        auto gameSession = GetSession(true);\n        auto gameSessionWriter = GetSessionWriter(true);\n\n        int count{ 0 };\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        bool matchFound{ false };\n        bool isAdvertisingGameDone{ false };\n        bool searchingTapTriggered{ false };\n        bool foundTapTriggered{ false };\n        bool waitingForClientsToJoinTapTriggered{ false };\n        bool waitingForClientsToUploadQoSTapTriggered{ false };\n        while (!matchFound || !isAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            if (!searchingTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::Searching)\n            {\n                searchingTapTriggered = true;\n                VERIFY_ARE_EQUAL_UINT(mpmInstance->EstimatedMatchWaitTime().count(), matchTicketJson()[\"waitTime\"].GetUint64());\n\n                lobbySessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ lobbySession->SessionReference(), \"\", 4 });\n            }\n\n            if (!foundTapTriggered && GlobalState::Get()->MultiplayerManager()->LobbySession()->ChangeNumber() == 4)\n            {\n                foundTapTriggered = true;\n\n                // Session upgraded to searching. Force a tap to change match status == found or expired (ExpiredByService)\n                lobbySessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ lobbySession->SessionReference(), \"\", 6 });\n            }\n\n            if (!waitingForClientsToJoinTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin)\n            {\n                waitingForClientsToJoinTapTriggered = true;\n\n                // Force a tap to simulate 2nd user joining.\n                clientManager->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ clientManager->MatchClient()->Session()->SessionReference(), \"\", 3 });\n            }\n\n            if (!waitingForClientsToUploadQoSTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::WaitingForRemoteClientsToUploadQos)\n            {\n                waitingForClientsToUploadQoSTapTriggered = true;\n                if (callingPattern == MatchCallingPatternType::RemoteClientFailedToUploadQoS)\n                {\n                    clientManager->MatchClient()->DisableNextTimer(false);\n                }\n                else\n                {\n                    // Force a tap to simulate 2nd user uploading QoS.\n                    clientManager->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ clientManager->MatchClient()->Session()->SessionReference(), \"\", 6 });\n                }\n            }\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::PerformQosMeasurements)\n                {\n                    VERIFY_SUCCEEDED(XblMultiplayerManagerSetQosMeasurements(\"{}\"));\n                }\n                else if (events[i].EventType == XblMultiplayerEventType::FindMatchCompleted)\n                {\n                    matchFound = true;\n                    XblMultiplayerMatchStatus matchStatuss{};\n                    VERIFY_SUCCEEDED(XblMultiplayerEventArgsFindMatchCompleted(events[i].EventArgsHandle, &matchStatuss, nullptr));\n\n                    if (callingPattern == MatchCallingPatternType::Completed)\n                    {\n                        VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Completed, matchStatuss);\n                    }\n                    else if (callingPattern == MatchCallingPatternType::RemoteClientFailedToUploadQoS)\n                    {\n                        VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Failed, matchStatuss);\n                    }\n\n                    lobbySessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ lobbySession->SessionReference(), \"\", 7 });\n                }\n            }\n\n            if (matchFound)\n            {\n                if (callingPattern != MatchCallingPatternType::Completed)\n                {\n                    isAdvertisingGameDone = true;\n                }\n                else\n                {\n                    auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n                    if (props != nullptr &&\n                        utils::str_icmp(props, customProps.c_str()) == 0)\n                    {\n                        isAdvertisingGameDone = true;\n                    }\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!matchFound || !isAdvertisingGameDone);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchNoQoSCompleted)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchNoQoSCompleted\");\n\n        FindMatchNoQoSHelper(MatchCallingPatternType::Completed);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchNoQoSRemoteClientFailedToJoin)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchNoQoSRemoteClientFailedToJoin\");\n\n        FindMatchNoQoSHelper(MatchCallingPatternType::RemoteClientFailedToJoin);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchNoQoSExpiredByNextTimer)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchNoQoSExpiredByNextTimer\");\n\n        FindMatchNoQoSHelper(MatchCallingPatternType::ExpiredByNextTimer);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchNoQoSExpiredByService)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchNoQoSExpiredByService\");\n\n        FindMatchNoQoSHelper(MatchCallingPatternType::ExpiredByService);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchWithQoSCompleted)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchWithQoSCompleted\");\n\n        FindMatchWithQoSHelper(MatchCallingPatternType::Completed);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchWithQoSRemoteClientFailedToUploadQoS)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchWithQoSRemoteClientFailedToUploadQoS\");\n\n        FindMatchWithQoSHelper(MatchCallingPatternType::RemoteClientFailedToUploadQoS);\n    }\n\n    void FindMatchNoQoSRemoteClientJoiningMatchSessionHelper()\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithNoTransferHandleResponse);\n\n        // Set up initial http responses\n        std::vector<const char*> lobbyResponses\n        {\n            lobbyMatchStatusSearching,\n            lobbyMatchStatusFound,\n            lobbyMatchStatusFoundWithTransHandle\n        };\n\n        std::vector<const char*> gameResponses\n        {\n            matchSessionJoin_1,\n            matchSessionJoin_2\n        };\n\n        uint32_t lobbyMockCount{ 0 };\n        auto lobbyMock = std::make_shared<HttpMock>(GET, defaultMpsdUri, 200);\n        lobbyMock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n        lobbyMock->SetMockMatchedCallback([lobbyResponses, &lobbyMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (lobbyMockCount < lobbyResponses.size())\n            {\n                matchedMock->SetResponseBody(lobbyResponses[lobbyMockCount]);\n                ++lobbyMockCount;\n            }\n        });\n\n        uint32_t gameMockCount{ 0 };\n        auto gameMock = std::make_shared<HttpMock>(GET, defaultGameUri, 200);\n        gameMock->SetResponseHeaders(defaultGameHttpResponseHeaders);\n        gameMock->SetMockMatchedCallback([gameResponses, &gameMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (gameMockCount < gameResponses.size())\n            {\n                matchedMock->SetResponseBody(gameResponses[gameMockCount]);\n                ++gameMockCount;\n            }\n        });\n\n        HttpMock matchMock(\"PUT\", matchTicketUri, 201);\n        matchMock.SetResponseBody(matchTicketResponse);\n\n        HttpMock transferMock(\"PUT\", transferHandleUri, 201);\n        transferMock.SetResponseBody(transferHandleResponse);\n\n        // LB: Shoulder tap with a Get: status to searching\n        // LB: Shoulder tap with a Get: status to found\n        // GS: PUT to join\n        // GS: Shoulder tap with a GET with both players joined\n        // Create Transfer handle\n        // LB: PUT Transfer handle\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto clientManager = mpmInstance->GetMultiplayerClientManager();\n\n        clientManager->MatchClient()->DisableNextTimer(true);\n\n        int count{ 0 };\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        bool matchFound{ false };\n        bool isAdvertisingGameDone{ false };\n        bool searchingTapTriggered{ false };\n        bool foundTapTriggered{ false };\n        bool waitingForClientsTapTriggered{ false };\n        while (!matchFound || !isAdvertisingGameDone)\n        {\n            if (++count > 500) break;\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            if (!searchingTapTriggered)\n            {\n                searchingTapTriggered = true;\n                sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 4 });\n            }\n\n            if (!foundTapTriggered && mpmInstance->LobbySession()->ChangeNumber() == 4)\n            {\n                foundTapTriggered = true;\n                \n                // Session upgraded to searching. Force a tap to change match status == found or expired (ExpiredByService)\n                sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 6 });\n            }\n\n            if (!waitingForClientsTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin)\n            {\n                waitingForClientsTapTriggered = true;\n\n                // Force a tap to simulate 2nd user joining.\n                clientManager->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ clientManager->MatchClient()->Session()->SessionReference(), \"\", 3 });\n            }\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::FindMatchCompleted)\n                {\n                    matchFound = true;\n                    XblMultiplayerMatchStatus matchStatus{};\n                    VERIFY_SUCCEEDED(XblMultiplayerEventArgsFindMatchCompleted(events[i].EventArgsHandle, &matchStatus, nullptr));\n                    VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Completed, matchStatus);\n\n                    sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 7 });\n                }\n            }\n\n            auto props{ XblMultiplayerManagerLobbySessionPropertiesJson() };\n            if (matchFound &&\n                props != nullptr &&\n                utils::str_icmp(props, customProps.c_str()) == 0)\n            {\n                isAdvertisingGameDone = true;\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_FALSE(!matchFound || !isAdvertisingGameDone);\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchNoQoSRemoteClientJoiningMatchSession)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchNoQoSRemoteClientJoiningMatchSession\");\n\n        FindMatchNoQoSRemoteClientJoiningMatchSessionHelper();\n    }\n\n    DEFINE_TEST_CASE(TestFindMatchNoQoSInvalidArg)\n    {\n        TEST_LOG(L\"Test starting: TestFindMatchNoQoSInvalidArg\");\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        uint32_t timeout = 100 * TICKS_PER_SECOND;\n        VERIFY_ARE_EQUAL_INT(E_INVALIDARG, XblMultiplayerManagerFindMatch(nullptr, \"\", timeout));\n        VERIFY_ARE_EQUAL_INT(E_INVALIDARG, XblMultiplayerManagerFindMatch(HOPPER_NAME_NO_QOS, \"json\", timeout));\n    }\n\n    void CancelMatchHelper(MatchCallingPatternType callingPattern)\n    {\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n        AddLocalUserHelper(xboxLiveContext.get(), lobbyWithNoTransferHandleResponse);\n\n        // Set up initial http responses\n        std::vector<const char*> lobbyResponses{ lobbyMatchStatusSearching };\n\n        std::vector<const char*> gameResponses\n        {\n            matchSessionJoin_1,\n            matchSessionJoin_2\n        };\n\n        if (callingPattern == MatchCallingPatternType::CanceledByService)\n        {\n            lobbyResponses.push_back(lobbyMatchStatusCanceledByService);\n        }\n        else\n        {\n            lobbyResponses.push_back(lobbyMatchStatusFound);\n            lobbyResponses.push_back(lobbyMatchStatusCanceledByService);\n        }\n\n        uint32_t lobbyMockCount{ 0 };\n        auto lobbyMock = std::make_shared<HttpMock>(GET, defaultMpsdUri, 200);\n        lobbyMock->SetResponseBody(lobbyResponses[0]);\n        lobbyMock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n        lobbyMock->SetMockMatchedCallback([lobbyResponses, &lobbyMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (lobbyMockCount < lobbyResponses.size())\n            {\n                matchedMock->SetResponseBody(lobbyResponses[lobbyMockCount]);\n                ++lobbyMockCount;\n            }\n        });\n\n        uint32_t gameMockCount{ 0 };\n        auto gameMock = std::make_shared<HttpMock>(GET, defaultGameUri, 200);\n        gameMock->SetResponseBody(gameResponses[0]);\n        gameMock->SetResponseHeaders(defaultGameHttpResponseHeaders);\n        gameMock->SetMockMatchedCallback([gameResponses, &gameMockCount](class HttpMock* matchedMock, xsapi_internal_string actualRequestUrl, xsapi_internal_string requestBody)\n        {\n            if (gameMockCount < gameResponses.size())\n            {\n                matchedMock->SetResponseBody(gameResponses[gameMockCount]);\n                ++gameMockCount;\n            }\n        });\n\n        HttpMock matchMock(\"PUT\", matchTicketUri, 201);\n        matchMock.SetResponseBody(matchTicketResponse);\n\n        HttpMock transferMock(\"PUT\", transferHandleUri, 201);\n        transferMock.SetResponseBody(transferHandleResponse);\n\n        auto session = GetSession(false);\n        auto sessionWriter = GetSessionWriter(false);\n        auto mpmInstance = GlobalState::Get()->MultiplayerManager();\n        auto clientManager = mpmInstance->GetMultiplayerClientManager();\n\n        JsonDocument doc{};\n        mpmInstance->FindMatch(HOPPER_NAME_NO_QOS, doc, std::chrono::seconds{ TICKS_PER_SECOND });\n        clientManager->MatchClient()->DisableNextTimer(true);\n\n        int count{ 0 };\n        auto customProps = JsonUtils::SerializeJson(classPropertiesJson()[\"properties\"][\"custom\"]);\n        bool matchFound{ false };\n        bool searchingTapTriggered{ false };\n        bool foundTapTriggered{ false };\n        bool waitingForClientsTapTriggered{ false };\n        while (!matchFound)\n        {\n            if (++count > 500) break;\n\n            if (!searchingTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::Searching)\n            {\n                searchingTapTriggered = true;\n\n                auto matchTicketeJson = matchTicketJson();\n                VERIFY_ARE_EQUAL_UINT(mpmInstance->EstimatedMatchWaitTime().count(), matchTicketeJson[\"waitTime\"].GetUint64());\n\n                sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 4 });\n            }\n\n            if (!foundTapTriggered && mpmInstance->LobbySession()->ChangeNumber() == 4)\n            {\n                foundTapTriggered = true;\n\n                // For CanceledByService, this will cause a get with status = canceled.\n                sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 6 });\n            }\n\n            if (!waitingForClientsTapTriggered && XblMultiplayerManagerMatchStatus() == XblMultiplayerMatchStatus::WaitingForRemoteClientsToJoin)\n            {\n                waitingForClientsTapTriggered = true;\n                if (callingPattern == MatchCallingPatternType::Canceled)\n                {\n                    mpmInstance->CancelMatch();\n\n                    // This will trigger a shoulder tap with canceled as the status from the service after deleting the match ticket.\n                    sessionWriter->OnSessionChanged(XblMultiplayerSessionChangeEventArgs{ session->SessionReference(), \"\", 8 });\n                }\n            }\n\n            size_t eventsCount{};\n            const XblMultiplayerEvent* events{};\n            XblMultiplayerManagerDoWork(&events, &eventsCount);\n\n            for (uint32_t i = 0; i < eventsCount; ++i)\n            {\n                if (events[i].EventType == XblMultiplayerEventType::FindMatchCompleted)\n                {\n                    matchFound = true;\n                    XblMultiplayerMatchStatus matchStatus{};\n                    VERIFY_SUCCEEDED(XblMultiplayerEventArgsFindMatchCompleted(events[i].EventArgsHandle, &matchStatus, nullptr));\n                    VERIFY_ARE_EQUAL_UINT(XblMultiplayerMatchStatus::Canceled, matchStatus);\n                }\n            }\n\n            Sleep(10);\n        }\n\n        VERIFY_IS_TRUE(matchFound);\n    }\n\n    DEFINE_TEST_CASE(TestCancelMatch)\n    {\n        TEST_LOG(L\"Test starting: TestCancelMatch\");\n\n        CancelMatchHelper(MatchCallingPatternType::Canceled);\n    }\n\n    DEFINE_TEST_CASE(TestCancelMatchByService)\n    {\n        TEST_LOG(L\"Test starting: TestCancelMatchByService\");\n\n        CancelMatchHelper(MatchCallingPatternType::CanceledByService);\n    }\n\n    DEFINE_TEST_CASE(TestRtaResync)\n    {\n        TEST_LOG(L\"Test starting: TestRtaResync\");\n\n        DEFINE_TEST_CASE_PROPERTIES_FOCUS();\n\n        MPMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(1234);\n\n        AddLocalUserHelper(xboxLiveContext.get());\n\n        auto mock = std::make_shared<HttpMock>(\"GET\", defaultMpsdUri, 201);\n        mock->SetResponseBody(defaultLobbySessionResponse);\n        mock->SetResponseHeaders(defaultLobbyHttpResponseHeaders);\n\n        // Wait for MPM to refresh the lobby\n        Event e;\n        mock->SetMockMatchedCallback([&](HttpMock*, xsapi_internal_string, xsapi_internal_string)\n        {\n            e.Set();\n        });\n\n        env.MockRtaService().RaiseResync();\n        e.Wait();\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/MultiplayerTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"xsapi-cpp/multiplayer.h\"\n#include \"xsapi-cpp/xbox_live_context.h\"\n#include \"xsapi_utils.h\"\n\n#pragma warning (disable : 26444)\n\nusing xbox::services::multiplayer::Serializers;\n\nstatic xsapi_internal_string StringFromUint64Internal(_In_ uint64_t val)\n{\n    xsapi_internal_stringstream ss;\n    ss << val;\n    return ss.str();\n}\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\n#define MPSD_URI \"https://sessiondirectory.xboxlive.com\"\n#define MPSD_RTA_URI MPSD_URI \"/connections/\"\n\n// JSON Verification helpers for fields that may not be present (and are not required to be)\n#define VERIFY_JSON_UINT(json, fieldName, actualValue) \\\n    { \\\n        uint64_t expectedValue{}; \\\n        VERIFY_SUCCEEDED(JsonUtils::ExtractJsonInt(json, fieldName, expectedValue)); \\\n        VERIFY_ARE_EQUAL_UINT(expectedValue, static_cast<uint64_t>(actualValue)); \\\n    }\n\n#define VERIFY_JSON_INT(json, fieldName, actualValue) \\\n    { \\\n        int64_t expectedValue{}; \\\n        VERIFY_SUCCEEDED(JsonUtils::ExtractJsonInt(json, fieldName, expectedValue)); \\\n        VERIFY_ARE_EQUAL_UINT(expectedValue, static_cast<int64_t>(actualValue)); \\\n    }\n\n#define VERIFY_JSON_STRING(json, fieldName, actualValue) \\\n    { \\\n        String expectedValue{}; \\\n        VERIFY_SUCCEEDED(JsonUtils::ExtractJsonString(json, fieldName, expectedValue)); \\\n        if (!expectedValue.empty()) { \\\n            VERIFY_ARE_EQUAL_STR_IGNORE_CASE(expectedValue.data(), actualValue); \\\n        } \\\n    }\n\n#define VERIFY_JSON_BOOL(json, fieldName, actualValue) \\\n    { \\\n        bool expectedValue{}; \\\n        VERIFY_SUCCEEDED(JsonUtils::ExtractJsonBool(json, fieldName, expectedValue)); \\\n        VERIFY_ARE_EQUAL(expectedValue, actualValue); \\\n    }\n\n#define VERIFY_JSON_TIME(json, fieldName, actualValue) \\\n    { \\\n        if (json.HasMember(fieldName)) { \\\n            VERIFY_IS_TRUE(VerifyTime(actualValue, json[fieldName].GetString())); \\\n        } else { \\\n            VERIFY_ARE_EQUAL_UINT(0, actualValue); \\\n        } \\\n    }\n\n#define VERIFY_JSON_FIELD(json, fieldName, jsonString) \\\n    { \\\n        if (json.HasMember(fieldName)) { \\\n            VERIFY_IS_TRUE(VerifyJson(json[fieldName], jsonString)); \\\n        } else { \\\n            VERIFY_IS_NULL(jsonString); \\\n        } \\\n    }\n\n#define VERIFY_JSON_FIELD_NOTNULL(json, fieldName, jsonString) \\\n    { \\\n        if (json.HasMember(fieldName)) { \\\n            VERIFY_IS_TRUE(VerifyJson(json[fieldName], jsonString)); \\\n        } else { \\\n            VERIFY_IS_NOT_NULL(jsonString); \\\n            VERIFY_IS_TRUE(jsonString[0] == 0); \\\n        } \\\n    }\n\n#define VERIFY_JSON_INT_STRING(json, fieldName, actualIntValue) \\\n    { \\\n        uint64_t expectedValue{}; \\\n        VERIFY_SUCCEEDED(JsonUtils::ExtractJsonStringToUInt64(json, fieldName, expectedValue)); \\\n        VERIFY_ARE_EQUAL_UINT(expectedValue, actualIntValue); \\\n    }\n\nDEFINE_TEST_CLASS(MultiplayerTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(MultiplayerTests)\n\n    static const JsonDocument testJson;\n    static const JsonValue& defaultSessionJson;\n    static const XblMultiplayerSessionReference defaultSessionReference;\n\n    class MPTestEnv : public TestEnvironment\n    {\n    public:\n        MPTestEnv() noexcept \n        {\n            m_baseMock = std::make_shared<HttpMock>(\"\", \"\");\n            m_baseMock->SetMockMatchedCallback(\n                [](HttpMock* /*mock*/, xsapi_internal_string uri, xsapi_internal_string /*body*/)\n                {\n                    LOGS_DEBUG << \"Unmocked HttpCall, uri=\" << uri;\n                    assert(false);\n                }\n            );\n\n            // MPSD response expect local user's Xuid to be 1234\n            m_xboxLiveContext = CreateMockXboxLiveContext(1234);\n        }\n\n        XblContextHandle XboxLiveContext() const noexcept\n        {\n            return m_xboxLiveContext.get();\n        }\n\n    private:\n        std::shared_ptr<HttpMock> m_baseMock;\n        std::shared_ptr<XblContext> m_xboxLiveContext;\n    };\n\n    // RAII wrapper for MPSD session\n    class MultiplayerSession\n    {\n    public:\n        // No public constructor. Create a session using MultiplayerSession::Create or MultiplayerSession::Get\n\n        MultiplayerSession(const MultiplayerSession& other) noexcept\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerSessionDuplicateHandle(other.m_handle, &m_handle));\n            VERIFY_SUCCEEDED(XblContextDuplicateHandle(other.m_context, &m_context));\n        }\n\n        MultiplayerSession& operator=(MultiplayerSession other) noexcept\n        {\n            std::swap(m_handle, other.m_handle);\n            std::swap(m_context, other.m_context);\n            return *this;\n        }\n\n        ~MultiplayerSession() noexcept\n        {\n            XblMultiplayerSessionCloseHandle(m_handle);\n            XblContextCloseHandle(m_context);\n        }\n\n        static MultiplayerSession Create(\n            XblContextHandle xboxLiveContext,\n            const XblMultiplayerSessionReference* sessionReference = &MultiplayerTests::defaultSessionReference,\n            const XblMultiplayerSessionInitArgs* initArgs = nullptr\n        ) noexcept\n        {\n            auto sessionHandle = XblMultiplayerSessionCreateHandle(xboxLiveContext->Xuid(), sessionReference, initArgs);\n            return MultiplayerSession{ sessionHandle, xboxLiveContext };\n        }\n\n        static MultiplayerSession Get(\n            XblContextHandle xboxLiveContext,\n            const XblMultiplayerSessionReference& sessionReference = MultiplayerTests::defaultSessionReference,\n            const JsonValue& response = MultiplayerTests::defaultSessionJson\n        ) noexcept\n        {\n            Stringstream mockUri;\n            mockUri << MPSD_URI;\n            mockUri << \"/serviceconfigs/\" << sessionReference.Scid;\n            mockUri << \"/sessionTemplates/\" << sessionReference.SessionTemplateName;\n            mockUri << \"/sessions/\" << sessionReference.SessionName;\n\n            HttpMock mock{ \"GET\", mockUri.str() };\n            mock.SetResponseBody(response);\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetSessionAsync(xboxLiveContext, &sessionReference, &async));\n            VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n            XblMultiplayerSessionHandle sessionHandle{ nullptr };\n            VERIFY_SUCCEEDED(XblMultiplayerGetSessionResult(&async, &sessionHandle));\n\n            MultiplayerSession session{ sessionHandle, xboxLiveContext };\n            session.Verify(response);\n\n            return session;\n        }\n\n        static MultiplayerSession Get(\n            XblContextHandle xboxLiveContext,\n            const xsapi_internal_string& handleId,\n            const JsonValue& response = MultiplayerTests::defaultSessionJson\n        ) noexcept\n        {\n            Stringstream mockUri;\n            mockUri << MPSD_URI << \"/handles/\" << handleId.data() << \"/session\";\n\n            HttpMock mock{ \"GET\", mockUri.str() };\n            mock.SetResponseBody(response);\n\n            XblMultiplayerSessionReferenceUri sessionPath{};\n            VERIFY_SUCCEEDED(XblMultiplayerSessionReferenceToUriPath(&MultiplayerTests::defaultSessionReference, &sessionPath));\n            mock.SetResponseHeaders(HttpHeaders{ {\"Content-Location\", sessionPath.value } });\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetSessionByHandleAsync(xboxLiveContext, handleId.data(), &async));\n            VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n            XblMultiplayerSessionHandle sessionHandle{ nullptr };\n            VERIFY_SUCCEEDED(XblMultiplayerGetSessionByHandleResult(&async, &sessionHandle));\n\n            MultiplayerSession session{ sessionHandle, xboxLiveContext };\n            session.Verify(response);\n\n            return session;\n        }\n\n        void Write(\n            const JsonValue& expectedRequestBody = JsonValue{ rapidjson::kObjectType },\n            const JsonValue& responseBody = MultiplayerTests::defaultSessionJson\n        ) noexcept\n        {\n            auto sessionReference{ Reference() };\n\n            Stringstream mockUri;\n            mockUri << MPSD_URI;\n            mockUri << \"/serviceconfigs/\" << sessionReference->Scid;\n            mockUri << \"/sessionTemplates/\" << sessionReference->SessionTemplateName;\n            mockUri << \"/sessions/\" << sessionReference->SessionName;\n\n            auto mock = std::make_shared<HttpMock>( \"PUT\", mockUri.str() );\n            mock->SetResponseBody(responseBody);\n\n            bool requestWellFormed{ true };\n            mock->SetMockMatchedCallback(\n                [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n                {\n                    requestWellFormed &= VerifyJson(expectedRequestBody, body.data());\n                }\n            );\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerWriteSessionAsync(\n                m_context,\n                m_handle,\n                XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n                &async)\n            );\n\n            VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n            VERIFY_IS_TRUE(requestWellFormed);\n\n            XblMultiplayerSessionHandle updatedSessionHandle{ nullptr };\n            VERIFY_SUCCEEDED(XblMultiplayerWriteSessionResult(&async, &updatedSessionHandle));\n\n            MultiplayerSession updatedSession{ updatedSessionHandle, m_context };\n            updatedSession.Verify(responseBody);\n\n            // Update MultiplayerSession object in place since we are doing synchronous updates anyhow\n            *this = updatedSession;\n        }\n\n        XblMultiplayerSessionHandle Handle() const noexcept\n        {\n            return m_handle;\n        }\n\n        const XblMultiplayerSessionReference* Reference() const noexcept\n        {\n            return XblMultiplayerSessionSessionReference(m_handle);\n        }\n\n        const XblMultiplayerSessionConstants* Constants() const noexcept\n        {\n            return XblMultiplayerSessionSessionConstants(m_handle);\n        }\n\n        const XblMultiplayerSessionProperties* Properties() const noexcept\n        {\n            return XblMultiplayerSessionSessionProperties(m_handle);\n        }\n\n        std::unordered_map<uint32_t, const XblMultiplayerSessionMember*> Members() const noexcept\n        {\n            const XblMultiplayerSessionMember* members{ nullptr };\n            size_t membersCount{ 0 };\n            VERIFY_SUCCEEDED(XblMultiplayerSessionMembers(m_handle, &members, &membersCount));\n\n            std::unordered_map<uint32_t, const XblMultiplayerSessionMember*> map{};\n            for (size_t i = 0; i < membersCount; ++i)\n            {\n                map[members[i].MemberId] = members + i;\n            }\n            return map;\n        }\n\n        std::vector<const XblMultiplayerRoleType*> RoleTypes() const noexcept\n        {\n            const XblMultiplayerRoleType* roles{ nullptr };\n            size_t roleCount{ 0 };\n            VERIFY_SUCCEEDED(XblMultiplayerSessionRoleTypes(m_handle, &roles, &roleCount));\n\n            return Utils::Transform<const XblMultiplayerRoleType*>(roles, roleCount, [](const XblMultiplayerRoleType& r) { return &r; });\n        }\n\n    private:\n        // Semantics are to take over ownership of an existing session handle. Caller should not call close.\n        MultiplayerSession(\n            XblMultiplayerSessionHandle sessionHandle,\n            XblContextHandle xblContextHandle\n        ) noexcept\n            : m_handle(sessionHandle)\n        {\n            VERIFY_IS_NOT_NULL(m_handle);\n            VERIFY_SUCCEEDED(XblContextDuplicateHandle(xblContextHandle, &m_context));\n        }\n\n        // Verify the session matches with an MPSD session document\n        void Verify(const JsonValue& json) const noexcept\n        {\n            VerifySessionInfo(json);\n            if (json.HasMember(\"initializing\"))\n            {\n                VerifyInitializationInfo(json[\"initializing\"]);\n            }\n            if (json.HasMember(\"hostCandidates\"))\n            {\n                VerifyHostCandidates(json[\"hostCandidates\"]);\n            }\n            if (json.HasMember(\"roleTypes\"))\n            {\n                VerifyRoles(json[\"roleTypes\"]);\n            }\n            else\n            {\n                VERIFY_ARE_EQUAL_UINT(0, RoleTypes().size());\n            }\n            VerifyConstants(json[\"constants\"]);\n            VerifyProperties(json[\"properties\"]);\n            VerifyServers(json[\"servers\"]);\n            VerifyMembers(json[\"members\"]);\n        }\n\n        void VerifySessionInfo(const JsonValue& json) const noexcept\n        {\n            const auto& i{ *XblMultiplayerSessionGetInfo(m_handle) };\n\n            VERIFY_JSON_INT(json, \"contractVersion\", i.ContractVersion);\n            VERIFY_JSON_STRING(json, \"branch\", i.Branch);\n            VERIFY_JSON_INT(json, \"changeNumber\", i.ChangeNumber);\n            VERIFY_JSON_STRING(json, \"correlationId\", i.CorrelationId);\n            VERIFY_JSON_TIME(json, \"startTime\", i.StartTime);\n            VERIFY_JSON_TIME(json, \"nextTimer\", i.NextTimer);\n        }\n\n        void VerifyInitializationInfo(const JsonValue& json) const noexcept\n        {\n            const auto& i{ *XblMultiplayerSessionGetInitializationInfo(m_handle) };\n            switch (i.Stage)\n            {\n            case XblMultiplayerInitializationStage::Evaluating:\n            {\n                VERIFY_ARE_EQUAL_STR_IGNORE_CASE(json[\"stage\"].GetString(), \"evaluating\");\n                break;\n            }\n            case XblMultiplayerInitializationStage::Failed:\n            {\n                VERIFY_ARE_EQUAL_STR_IGNORE_CASE(json[\"stage\"].GetString(), \"failed\");\n                break;\n            }\n            case XblMultiplayerInitializationStage::Joining:\n            {\n                VERIFY_ARE_EQUAL_STR_IGNORE_CASE(json[\"stage\"].GetString(), \"joining\");\n                break;\n            }\n            case XblMultiplayerInitializationStage::Measuring:\n            {\n                VERIFY_ARE_EQUAL_STR_IGNORE_CASE(json[\"stage\"].GetString(), \"measuring\");\n                break;\n            }\n            case XblMultiplayerInitializationStage::None:\n            case XblMultiplayerInitializationStage::Unknown:\n            default:\n            {\n                VERIFY_IS_TRUE(!json.HasMember(\"stage\"));\n            }\n            }\n\n            VERIFY_JSON_TIME(json, \"stageStartTime\", i.StageStartTime);\n            VERIFY_JSON_UINT(json, \"episode\", i.Episode);\n        }\n\n        void VerifyHostCandidates(const JsonValue& json) const noexcept\n        {\n            const XblDeviceToken* hostCandidates{ nullptr };\n            size_t count{ 0 };\n            VERIFY_SUCCEEDED(XblMultiplayerSessionHostCandidates(m_handle, &hostCandidates, &count));\n            const auto& expectedHostCandidates{ json.GetArray() };\n            VERIFY_ARE_EQUAL_UINT(expectedHostCandidates.Size(), count);\n\n            for (uint32_t i = 0; i < count; ++i)\n            {\n                VERIFY_ARE_EQUAL_STR_IGNORE_CASE(expectedHostCandidates[i].GetString(), hostCandidates[i].Value);\n            }\n        }\n\n        void VerifyRoles(const JsonValue& json) const noexcept\n        {\n            auto rolesTypes{ RoleTypes() };\n\n            VERIFY_ARE_EQUAL_UINT(json.MemberCount(), rolesTypes.size());\n            for (auto roleType : rolesTypes)\n            {\n                VERIFY_IS_NOT_NULL(roleType);\n\n                VERIFY_IS_TRUE(json.HasMember(roleType->Name));\n                const auto& roleTypeJson{ json[roleType->Name] };\n                VERIFY_ARE_EQUAL(roleType->OwnerManaged, roleTypeJson[\"ownerManaged\"].GetBool());\n\n                XblMutableRoleSettings expectedMutableSettings{ XblMutableRoleSettings::None };\n                const auto& mutableSettingsArray{ roleTypeJson[\"mutableRoleSettings\"].GetArray() };\n                for (auto& setting : mutableSettingsArray)\n                {\n                    xsapi_internal_string settingString{ setting.GetString() };\n                    if (settingString == \"max\")\n                    {\n                        expectedMutableSettings |= XblMutableRoleSettings::Max;\n                    }\n                    else if (settingString == \"target\")\n                    {\n                        expectedMutableSettings |= XblMutableRoleSettings::Target;\n                    }\n                }\n\n                VERIFY_IS_TRUE(roleType->MutableRoleSettings == expectedMutableSettings);\n\n                const auto& rolesJson{ roleTypeJson[\"roles\"] };\n                VERIFY_ARE_EQUAL_UINT(rolesJson.MemberCount(), roleType->RoleCount);\n                for (size_t i = 0; i < roleType->RoleCount; ++i)\n                {\n                    auto& role{ roleType->Roles[i] };\n                    VERIFY_IS_TRUE(rolesJson.HasMember(role.Name));\n                    const auto& roleJson{ rolesJson[role.Name] };\n\n                    VERIFY_ARE_EQUAL(roleType, role.RoleType);\n\n                    std::unordered_set<uint64_t> actualMemberXuids(role.MemberXuids, role.MemberXuids + role.MemberCount);\n                    const auto& expectedMemberXuids{ roleJson[\"memberXuids\"].GetArray() };\n                    VERIFY_ARE_EQUAL_UINT(expectedMemberXuids.Size(), actualMemberXuids.size());\n                    for (auto& xuid : expectedMemberXuids)\n                    {\n                        VERIFY_IS_TRUE(actualMemberXuids.find(atol(xuid.GetString())) != actualMemberXuids.end());\n                    }\n\n                    VERIFY_ARE_EQUAL_UINT(roleJson[\"target\"].GetUint(), role.TargetCount);\n                    VERIFY_ARE_EQUAL_UINT(roleJson[\"max\"].GetUint(), role.MaxMemberCount);\n                }\n            }\n        }\n\n        void VerifyConstants(const JsonValue& json) const noexcept\n        {\n            auto& c{ *Constants() };\n\n            const auto& systemJson = json[\"system\"];\n\n            VERIFY_JSON_UINT(systemJson, \"maxMembersCount\", c.MaxMembersInSession);\n            if (c.Visibility != XblMultiplayerSessionVisibility::Unknown)\n            {\n                VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionVisibilityFromString(systemJson[\"visibility\"].GetString()) == c.Visibility);\n            }\n\n            if (c.InitiatorXuidsCount)\n            {\n                std::unordered_set<uint64_t> actualInitiators{ c.InitiatorXuids, c.InitiatorXuids + c.InitiatorXuidsCount };\n                const auto& expectedInitiators{ systemJson[\"initiators\"].GetArray() };\n                VERIFY_ARE_EQUAL_UINT(expectedInitiators.Size(), actualInitiators.size());\n                for (auto& xuid : expectedInitiators)\n                {\n                    VERIFY_IS_TRUE(actualInitiators.find(atol(xuid.GetString())) != actualInitiators.end());\n                }\n            }\n\n            VERIFY_JSON_FIELD_NOTNULL(systemJson, \"cloudComputePackage\", c.SessionCloudComputePackageConstantsJson);\n            VERIFY_JSON_UINT(systemJson, \"reservedRemovalTimeout\", c.MemberReservedTimeout);\n            VERIFY_JSON_UINT(systemJson, \"inactiveRemovalTimeout\", c.MemberInactiveTimeout);\n            VERIFY_JSON_UINT(systemJson, \"readyRemovalTimeout\", c.MemberReadyTimeout);\n            VERIFY_JSON_UINT(systemJson, \"sessionEmptyTimeout\", c.SessionEmptyTimeout);\n\n            if (systemJson.HasMember(\"metrics\"))\n            {\n                VERIFY_JSON_BOOL(systemJson[\"metrics\"], \"latency\", c.EnableMetricsLatency);\n                VERIFY_JSON_BOOL(systemJson[\"metrics\"], \"bandwidthDown\", c.EnableMetricsBandwidthDown);\n                VERIFY_JSON_BOOL(systemJson[\"metrics\"], \"bandwidthUp\", c.EnableMetricsBandwidthUp);\n                VERIFY_JSON_BOOL(systemJson[\"metrics\"], \"custom\", c.EnableMetricsCustom);\n            }\n\n            if (systemJson.HasMember(\"memberInitialization\"))\n            {\n                VERIFY_JSON_UINT(systemJson[\"memberInitialization\"], \"joinTimeout\", c.MemberInitialization->JoinTimeout);\n                VERIFY_JSON_UINT(systemJson[\"memberInitialization\"], \"measurementTimeout\", c.MemberInitialization->MeasurementTimeout);\n                VERIFY_JSON_UINT(systemJson[\"memberInitialization\"], \"evaluationTimeout\", c.MemberInitialization->EvaluationTimeout);\n                VERIFY_JSON_BOOL(systemJson[\"memberInitialization\"], \"externalEvaluation\", c.MemberInitialization->ExternalEvaluation);\n                VERIFY_JSON_UINT(systemJson[\"memberInitialization\"], \"membersNeededToStart\", c.MemberInitialization->MembersNeededToStart);\n            }\n\n            if (systemJson.HasMember(\"peerToPeerRequirements\"))\n            {\n                VERIFY_JSON_UINT(systemJson[\"peerToPeerRequirements\"], \"latencyMaximum\", c.PeerToPeerRequirements.LatencyMaximum);\n                VERIFY_JSON_UINT(systemJson[\"peerToPeerRequirements\"], \"bandwidthMinimum\", c.PeerToPeerRequirements.BandwidthMinimumInKbps);\n            }\n\n            if (systemJson.HasMember(\"peerToHostRequirements\"))\n            {\n                VERIFY_JSON_UINT(systemJson[\"peerToHostRequirements\"], \"latencyMaximum\", c.PeerToHostRequirements.LatencyMaximum);\n                VERIFY_JSON_UINT(systemJson[\"peerToHostRequirements\"], \"bandwidthDownMinimum\", c.PeerToHostRequirements.BandwidthDownMinimumInKbps);\n                VERIFY_JSON_UINT(systemJson[\"peerToHostRequirements\"], \"bandwidthUpMinimum\", c.PeerToHostRequirements.BandwidthUpMinimumInKbps);\n            }\n\n            VERIFY_JSON_FIELD_NOTNULL(systemJson, \"measurementServerAddresses\", c.MeasurementServerAddressesJson);\n\n            const auto& capabilitesJson = systemJson[\"capabilities\"];\n            VERIFY_JSON_BOOL(capabilitesJson, \"connectivity\", c.SessionCapabilities.Connectivity);\n            VERIFY_JSON_BOOL(capabilitesJson, \"suppressPresenceActivityCheck\", c.SessionCapabilities.SuppressPresenceActivityCheck);\n            VERIFY_JSON_BOOL(capabilitesJson, \"gameplay\", c.SessionCapabilities.Gameplay);\n            VERIFY_JSON_BOOL(capabilitesJson, \"large\", c.SessionCapabilities.Large);\n            VERIFY_JSON_BOOL(capabilitesJson, \"connectionRequiredForActiveMembers\", c.SessionCapabilities.ConnectionRequiredForActiveMembers);\n            VERIFY_JSON_BOOL(capabilitesJson, \"userAuthorizationStyle\", c.SessionCapabilities.UserAuthorizationStyle);\n            VERIFY_JSON_BOOL(capabilitesJson, \"crossPlay\", c.SessionCapabilities.Crossplay);\n            VERIFY_JSON_BOOL(capabilitesJson, \"searchable\", c.SessionCapabilities.Searchable);\n            VERIFY_JSON_BOOL(capabilitesJson, \"hasOwners\", c.SessionCapabilities.HasOwners);\n\n            VERIFY_JSON_FIELD_NOTNULL(json, \"custom\", c.CustomJson);\n        }\n\n        void VerifyProperties(const JsonValue& json) const noexcept\n        {\n            auto& p{ *Properties() };\n            auto& systemJson{ json[\"system\"] };\n\n            if (p.KeywordCount)\n            {\n                std::unordered_set<xsapi_internal_string> actualKeywords(p.Keywords, p.Keywords + p.KeywordCount);\n                const auto& expectedKeywords = systemJson[\"keywords\"].GetArray();\n                VERIFY_ARE_EQUAL_UINT(expectedKeywords.Size(), actualKeywords.size());\n                for (auto& keyword : expectedKeywords)\n                {\n                    VERIFY_IS_TRUE(actualKeywords.find(keyword.GetString()) != actualKeywords.end());\n                }\n            }\n\n            if (p.JoinRestriction != XblMultiplayerSessionRestriction::Unknown)\n            {\n                VERIFY_IS_TRUE(p.JoinRestriction == multiplayer::Serializers::MultiplayerSessionRestrictionFromString(systemJson[\"joinRestriction\"].GetString()));\n            }\n\n            if (p.ReadRestriction != XblMultiplayerSessionRestriction::Unknown)\n            {\n                VERIFY_IS_TRUE(p.ReadRestriction == multiplayer::Serializers::MultiplayerSessionRestrictionFromString(systemJson[\"readRestriction\"].GetString()));\n            }\n\n            if (p.TurnCollectionCount)\n            {\n                std::unordered_set<uint32_t> actualTurns(p.TurnCollection, p.TurnCollection + p.TurnCollectionCount);\n                const auto& expectedTurns{ systemJson[\"turn\"].GetArray() };\n                VERIFY_ARE_EQUAL_UINT(expectedTurns.Size(), actualTurns.size());\n                for (auto& turn : expectedTurns)\n                {\n                    VERIFY_IS_TRUE(actualTurns.find(turn.GetUint()) != actualTurns.end());\n                }\n            }\n\n            if (systemJson.HasMember(\"matchmaking\"))\n            {\n                VERIFY_JSON_FIELD(systemJson[\"matchmaking\"], \"targetSessionConstants\", p.MatchmakingTargetSessionConstantsJson);\n                VERIFY_JSON_STRING(systemJson[\"matchmaking\"], \"serverConnectionString\", p.MatchmakingServerConnectionString);\n            }\n\n            if (p.ServerConnectionStringCandidatesCount)\n            {\n                std::unordered_set<xsapi_internal_string> actualServerCandidates(p.ServerConnectionStringCandidates, p.ServerConnectionStringCandidates + p.ServerConnectionStringCandidatesCount);\n                const auto& expectedServerCandidates{ systemJson[\"serverConnectionStringCandidates\"].GetArray() };\n                VERIFY_ARE_EQUAL_UINT(expectedServerCandidates.Size(), actualServerCandidates.size());\n                for (auto& candidate : expectedServerCandidates)\n                {\n                    VERIFY_IS_TRUE(actualServerCandidates.find(candidate.GetString()) != actualServerCandidates.end());\n                }\n            }\n\n            if (p.SessionOwnerMemberIdsCount)\n            {\n                std::unordered_set<uint32_t> actualSessionOwners(p.SessionOwnerMemberIds, p.SessionOwnerMemberIds + p.SessionOwnerMemberIdsCount);\n                const auto& expectedSessionOwners{ systemJson[\"owners\"].GetArray() };\n                VERIFY_ARE_EQUAL_UINT(expectedSessionOwners.Size(), actualSessionOwners.size());\n                for (auto& ownerId : expectedSessionOwners)\n                {\n                    VERIFY_IS_TRUE(actualSessionOwners.find(ownerId.GetUint()) != actualSessionOwners.end());\n                }\n            }\n\n            VERIFY_JSON_STRING(systemJson, \"host\", p.HostDeviceToken.Value);\n            VERIFY_JSON_BOOL(systemJson, \"closed\", p.Closed);\n            VERIFY_JSON_BOOL(systemJson, \"locked\", p.Locked);\n            VERIFY_JSON_BOOL(systemJson, \"allocateCloudCompute\", p.AllocateCloudCompute);\n            VERIFY_JSON_BOOL(systemJson, \"matchmakingResubmit\", p.MatchmakingResubmit);\n\n            VERIFY_JSON_FIELD_NOTNULL(json, \"custom\", p.SessionCustomPropertiesJson);\n        }\n\n        void VerifyServers(const JsonValue& json) const noexcept\n        {\n            auto jsonRawServers = XblMultiplayerSessionRawServersJson(m_handle);\n            VERIFY_IS_TRUE(VerifyJson(json, jsonRawServers));\n\n            // matchmaking server\n            if (json.HasMember(\"matchmaking\"))\n            {\n                const auto& matchmakingJson{ json[\"matchmaking\"][\"properties\"][\"system\"] };\n                auto m{ XblMultiplayerSessionMatchmakingServer(m_handle) };\n\n                switch (m->Status)\n                {\n                case XblMatchmakingStatus::Searching:\n                {\n                    VERIFY_ARE_EQUAL_STR_IGNORE_CASE(\"searching\", matchmakingJson[\"status\"].GetString());\n                    break;\n                }\n                default: break;\n                }\n\n                VERIFY_JSON_STRING(matchmakingJson, \"statusDetails\", m->StatusDetails);\n                VERIFY_JSON_INT(matchmakingJson, \"typicalWait\", m->TypicalWaitInSeconds);\n                VerifyMultiplayerSessionReference(m->TargetSessionRef, matchmakingJson[\"targetSessionRef\"]);\n            }\n        }\n\n        void VerifyMembers(const JsonValue& json) const noexcept\n        {\n            auto members{ Members() };\n            VERIFY_ARE_EQUAL_UINT(json.MemberCount(), members.size());\n\n            for (auto iter = json.MemberBegin(); iter != json.MemberEnd(); ++iter)\n            {\n                if (xsapi_internal_string{ iter->name.GetString() } == \"me\")\n                {\n                    VERIFY_ARE_EQUAL_UINT(1u, members.size());\n                    VerifyMember(*members.begin()->second, iter->value);\n                }\n                else\n                {\n                    VerifyMember(*members[atoi(iter->name.GetString())], iter->value);\n                }\n            }\n        }\n\n        void VerifyMember(\n            const XblMultiplayerSessionMember& m,\n            const JsonValue& expected\n        ) const noexcept\n        {\n            // Member constants\n            auto& constantsSystemJson{ expected[\"constants\"][\"system\"] };\n\n            if (constantsSystemJson.HasMember(\"xuid\"))\n            {\n                VERIFY_ARE_EQUAL_UINT(m.Xuid, atol(constantsSystemJson[\"xuid\"].GetString()));\n            }\n\n            auto currentUser{ XblMultiplayerSessionCurrentUser(m_handle) };\n            bool isCurrentUser{ currentUser ? m.Xuid == currentUser->Xuid : false };\n            VERIFY_IS_TRUE(m.IsCurrentUser == isCurrentUser);\n\n            VERIFY_JSON_BOOL(constantsSystemJson, \"initialize\", m.InitializeRequested);\n            if (constantsSystemJson.HasMember(\"matchmakingResult\"))\n            {\n                VERIFY_IS_TRUE(VerifyJson(constantsSystemJson[\"matchmakingResult\"][\"serverMeasurements\"], m.MatchmakingResultServerMeasurementsJson));\n            }\n\n            if (expected[\"constants\"].HasMember(\"custom\"))\n            {\n                VERIFY_IS_TRUE(VerifyJson(expected[\"constants\"][\"custom\"], m.CustomConstantsJson));\n            }\n\n            // Member properties\n            auto& propertiesSystemJson{ expected[\"properties\"][\"system\"] };\n\n            // Verify subscribed change types only for localUser\n            if (isCurrentUser && propertiesSystemJson.HasMember(\"subscription\"))\n            {\n                Vector<String> expectedChangedTypesVector{};\n                VERIFY_SUCCEEDED(JsonUtils::ExtractJsonVector<String>(JsonUtils::JsonStringExtractor, propertiesSystemJson[\"subscription\"][\"changeTypes\"], expectedChangedTypesVector));\n                auto expectedChangedTypes = multiplayer::Serializers::MultiplayerSessionChangeTypesFromStringVector(expectedChangedTypesVector);\n                VERIFY_IS_TRUE(expectedChangedTypes == XblMultiplayerSessionSubscribedChangeTypes(m_handle));\n            }\n\n            switch (m.Status)\n            {\n            case XblMultiplayerSessionMemberStatus::Active:\n            {\n                VERIFY_IS_TRUE(propertiesSystemJson[\"active\"].GetBool());\n                break;\n            }\n            case XblMultiplayerSessionMemberStatus::Ready:\n            {\n                VERIFY_IS_TRUE(propertiesSystemJson[\"ready\"].GetBool());\n                break;\n            }\n            case XblMultiplayerSessionMemberStatus::Reserved:\n            {\n                VERIFY_IS_TRUE(expected[\"reserved\"].GetBool());\n                break;\n            }\n            case XblMultiplayerSessionMemberStatus::Inactive:\n            {\n                VERIFY_IS_TRUE(!expected.HasMember(\"reserved\") || !expected[\"reserved\"].GetBool());\n                VERIFY_IS_TRUE(!propertiesSystemJson.HasMember(\"active\") || !propertiesSystemJson[\"active\"].GetBool());\n                VERIFY_IS_TRUE(!propertiesSystemJson.HasMember(\"ready\") || !propertiesSystemJson[\"ready\"].GetBool());\n                break;\n            }\n            default:\n            {\n                assert(false);\n            }\n            }\n\n            VERIFY_JSON_STRING(propertiesSystemJson, \"secureDeviceAddress\", m.SecureDeviceBaseAddress64);\n\n            if (propertiesSystemJson.HasMember(\"initializationGroup\"))\n            {\n                std::unordered_set<uint32_t> actualInitializationGroup(m.MembersInGroupIds, m.MembersInGroupIds + m.MembersInGroupCount);\n                const auto& expectedInitializationGroup{ propertiesSystemJson[\"initializationGroup\"].GetArray() };\n                VERIFY_ARE_EQUAL_UINT(expectedInitializationGroup.Size(), actualInitializationGroup.size());\n                for (auto& id : expectedInitializationGroup)\n                {\n                    VERIFY_IS_TRUE(actualInitializationGroup.find(id.GetUint()) != actualInitializationGroup.end());\n                }\n            }\n\n            VERIFY_JSON_FIELD(propertiesSystemJson, \"serverMeasurements\", m.ServerMeasurementsJson);\n            VERIFY_JSON_FIELD(propertiesSystemJson, \"measurements\", m.QosMeasurementsJson);\n\n            VERIFY_JSON_FIELD(expected[\"properties\"], \"custom\", m.CustomPropertiesJson);\n\n            // Root\n            VERIFY_JSON_STRING(expected, \"gamertag\", m.Gamertag);\n            VERIFY_JSON_STRING(expected, \"deviceToken\", m.DeviceToken.Value);\n            if (expected.HasMember(\"nat\"))\n            {\n                VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerNatSettingFromString(expected[\"nat\"].GetString()) == m.Nat);\n            }\n            VERIFY_JSON_INT_STRING(expected, \"activeTitleId\", m.ActiveTitleId);\n            VERIFY_JSON_TIME(expected, \"joinTime\", m.JoinTime);\n            VERIFY_JSON_BOOL(expected, \"turn\", m.IsTurnAvailable);\n            if (expected.HasMember(\"initializationFailure\"))\n            {\n                VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerMeasurementFailureFromString(expected[\"initializationFailure\"].GetString()) == m.InitializationFailureCause);\n            }\n            VERIFY_JSON_UINT(expected, \"initializationEpisode\", m.InitializationEpisode);\n\n            // Roles\n            if (m.Roles)\n            {\n                const auto& expectedRoles{ expected[\"roles\"] };\n                VERIFY_ARE_EQUAL_UINT(expectedRoles.MemberCount(), m.RolesCount);\n                for (size_t i = 0; i < m.RolesCount; ++i)\n                {\n                    VERIFY_IS_TRUE(expectedRoles.HasMember(m.Roles[i].roleTypeName));\n                    VERIFY_ARE_EQUAL_STR(expectedRoles[m.Roles[i].roleTypeName].GetString(), m.Roles[i].roleName);\n                }\n            }\n        }\n\n        XblMultiplayerSessionHandle m_handle{ nullptr };\n        XblContextHandle m_context{ nullptr };\n    };\n\n    // RAII wrapper around XblMultiplayerSearchHandle\n    class MultiplayerSearchDetails\n    {\n    public:\n        // No public constructor. Create MultiplayerSearchDetails for a session using MultiplayerSearchDetails::Create,\n        // or query existing using MultiplayerSearchDetails::Query\n\n        MultiplayerSearchDetails(const MultiplayerSearchDetails& other) noexcept\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerSearchHandleDuplicateHandle(other.m_handle, &m_handle));\n        }\n        MultiplayerSearchDetails& operator=(MultiplayerSearchDetails rhs) = delete;\n        ~MultiplayerSearchDetails() noexcept\n        {\n            XblMultiplayerSearchHandleCloseHandle(m_handle);\n        }\n\n        static MultiplayerSearchDetails Create(\n            XblContextHandle xboxLiveContext,\n            const XblMultiplayerSessionReference& sessionRef,\n            const std::vector<XblMultiplayerSessionTag>& tags = {},\n            const std::vector<XblMultiplayerSessionNumberAttribute>& numberAttributes = {},\n            const std::vector<XblMultiplayerSessionStringAttribute>& stringAttributes = {},\n            const JsonValue& responseJson = testJson[\"searchHandleJson\"]\n        ) noexcept\n        {\n            auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles\" );\n            mock->SetResponseBody(responseJson);\n\n            bool requestWellFormed{ true };\n            mock->SetMockMatchedCallback(\n                [&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string requestBody)\n                {\n                    UNREFERENCED_PARAMETER(mock);\n                    UNREFERENCED_PARAMETER(uri);\n                    requestWellFormed = VerifyJson(responseJson, requestBody.data());\n                });\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerCreateSearchHandleAsync(\n                xboxLiveContext,\n                &sessionRef,\n                tags.data(),\n                tags.size(),\n                numberAttributes.data(),\n                numberAttributes.size(),\n                stringAttributes.data(),\n                stringAttributes.size(),\n                &async\n            ));\n\n            VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n            XblMultiplayerSearchHandle handle{ nullptr };\n            VERIFY_SUCCEEDED(XblMultiplayerCreateSearchHandleResult(&async, &handle));\n\n            MultiplayerSearchDetails result{ handle };\n            result.Verify(responseJson);\n\n            return result;\n        }\n\n        static std::vector<MultiplayerSearchDetails> Query(\n            XblContextHandle xboxLiveContext,\n            const char* scid,\n            const char* sessionTemplateName,\n            const char* orderByAttribute = nullptr,\n            bool orderAscending = true,\n            const char* searchFilter = nullptr,\n            const char* socialGroup = nullptr,\n            const JsonValue& expectedRequestBody = testJson[\"searchHandlesRequestJson\"]\n        ) noexcept\n        {\n            const auto& responseBody{ testJson[\"searchHandlesResponseJson\"] };\n\n            auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles/query\" );\n            mock->SetResponseBody(responseBody);\n\n            bool requestWellFormed{ true };\n            mock->SetMockMatchedCallback(\n                [&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n                {\n                    UNREFERENCED_PARAMETER(mock);\n                    UNREFERENCED_PARAMETER(uri);\n                    requestWellFormed &= VerifyJson(expectedRequestBody, body.data());\n                }\n            );\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetSearchHandlesAsync(\n                xboxLiveContext,\n                scid,\n                sessionTemplateName,\n                orderByAttribute,\n                orderAscending,\n                searchFilter,\n                socialGroup,\n                &async\n            ));\n\n            VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n            VERIFY_IS_TRUE(requestWellFormed);\n\n            size_t resultCount{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetSearchHandlesResultCount(&async, &resultCount));\n            VERIFY_ARE_EQUAL_UINT(responseBody[\"results\"].GetArray().Size(), resultCount);\n\n            std::vector<XblMultiplayerSearchHandle> resultHandles(resultCount, nullptr);\n            VERIFY_SUCCEEDED(XblMultiplayerGetSearchHandlesResult(&async, resultHandles.data(), resultCount));\n\n            std::vector<MultiplayerSearchDetails> results;\n            for (uint32_t i = 0; i < results.size(); ++i)\n            {\n                MultiplayerSearchDetails result{ resultHandles[i] };\n                result.Verify(responseBody[\"results\"].GetArray()[i]);\n                results.push_back(result);\n            }\n\n            return results;\n        }\n\n        XblMultiplayerSearchHandle Handle() const noexcept\n        {\n            return m_handle;\n        }\n    private:\n        // Constructor takes ownership of the handle. Caller shouldn't close the handle\n        MultiplayerSearchDetails(XblMultiplayerSearchHandle handle) noexcept\n            : m_handle(handle)\n        {\n            VERIFY_IS_NOT_NULL(m_handle);\n        }\n\n        void Verify(const JsonValue& json) const noexcept\n        {\n            XblMultiplayerSessionReference ref{};\n            VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetSessionReference(m_handle, &ref));\n            VerifyMultiplayerSessionReference(ref, json[\"sessionRef\"]);\n\n            const char* id{ nullptr };\n            XblMultiplayerSearchHandleGetId(m_handle, &id);\n            VERIFY_JSON_STRING(json, \"id\", id);\n\n            if (json.HasMember(\"createTime\"))\n            {\n                time_t creationTime{};\n                VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetCreationTime(m_handle, &creationTime));\n                VERIFY_IS_TRUE(VerifyTime(creationTime, json[\"createTime\"].GetString()));\n            }\n\n            const auto& attrJson{ json[\"searchAttributes\"] };\n\n            const XblMultiplayerSessionTag* tags{ nullptr };\n            size_t tagCount{ 0 };\n            VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetTags(m_handle, &tags, &tagCount));\n            VERIFY_ARE_EQUAL_UINT(attrJson[\"tags\"].GetArray().Size(), tagCount);\n            for (uint32_t i = 0; i < tagCount; ++i)\n            {\n                VERIFY_ARE_EQUAL_STR(attrJson[\"tags\"].GetArray()[i].GetString(), tags[i].value);\n            }\n\n            const XblMultiplayerSessionStringAttribute* strings{ nullptr };\n            size_t stringCount{ 0 };\n            VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetStringAttributes(m_handle, &strings, &stringCount));\n            VERIFY_ARE_EQUAL_UINT(attrJson[\"strings\"].MemberCount(), stringCount);\n            for (size_t i = 0; i < stringCount; ++i)\n            {\n                VERIFY_IS_TRUE(attrJson[\"strings\"].HasMember(strings[i].name));\n                VERIFY_ARE_EQUAL_STR(attrJson[\"strings\"][strings[i].name].GetString(), strings[i].value);\n            }\n\n            const XblMultiplayerSessionNumberAttribute* numbers{ nullptr };\n            size_t numberCount{ 0 };\n            VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetNumberAttributes(m_handle, &numbers, &numberCount));\n            VERIFY_ARE_EQUAL_UINT(attrJson[\"numbers\"].MemberCount(), numberCount);\n            for (size_t i = 0; i < numberCount; ++i)\n            {\n                VERIFY_IS_TRUE(attrJson[\"numbers\"].HasMember(numbers[i].name));\n                VERIFY_ARE_EQUAL_DOUBLE(attrJson[\"numbers\"][numbers[i].name].GetDouble(), numbers[i].value);\n            }\n\n            const char* customPropertiesJson{ nullptr };\n            VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetCustomSessionPropertiesJson(m_handle, &customPropertiesJson));\n            VERIFY_JSON_FIELD(json, \"customProperties\", customPropertiesJson);\n\n            if (json.HasMember(\"relatedInfo\"))\n            {\n                const auto& ri{ json[\"relatedInfo\"] };\n\n                XblMultiplayerSessionRestriction joinRestriction{};\n                VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetJoinRestriction(m_handle, &joinRestriction));\n                VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionRestrictionFromString(ri[\"joinRestriction\"].GetString()) == joinRestriction);\n\n                bool closed{};\n                VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetSessionClosed(m_handle, &closed));\n                VERIFY_JSON_BOOL(ri, \"closed\", closed);\n\n                size_t maxMembers{}, memberCount{};\n                VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetMemberCounts(m_handle, &maxMembers, &memberCount));\n                VERIFY_JSON_INT(ri, \"maxMembersCount\", maxMembers);\n                VERIFY_JSON_INT(ri, \"membersCount\", maxMembers);\n\n                XblMultiplayerSessionVisibility visibility{};\n                VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetVisibility(m_handle, &visibility));\n                VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionVisibilityFromString(ri[\"visibility\"].GetString()) == visibility);\n\n                const uint64_t* xuids{ nullptr };\n                size_t xuidCount{};\n                VERIFY_SUCCEEDED(XblMultiplayerSearchHandleGetSessionOwnerXuids(m_handle, &xuids, &xuidCount));\n\n                const auto& xuidsJson{ ri[\"sessionOwners\"].GetArray() };\n                VERIFY_ARE_EQUAL_UINT(xuidsJson.Size(), xuidCount);\n                for (uint32_t i = 0; i < xuidCount; ++i)\n                {\n                    VERIFY_ARE_EQUAL_UINT(atol(xuidsJson[i].GetString()), xuids[i]);\n                }\n            }\n\n            // TODO we have no public API exposing role types for search handles\n        }\n\n        XblMultiplayerSearchHandle m_handle;\n    };\n\n    static void VerifyMultiplayerSessionReference(\n        const XblMultiplayerSessionReference& sessionReference,\n        const JsonValue& json\n    )\n    {\n        VERIFY_ARE_EQUAL_STR(json[\"scid\"].GetString(), sessionReference.Scid);\n        VERIFY_ARE_EQUAL_STR(json[\"templateName\"].GetString(), sessionReference.SessionTemplateName);\n        VERIFY_ARE_EQUAL_STR(json[\"name\"].GetString(), sessionReference.SessionName);\n    }\n\n    static void VerifyMultiplayerSessionQueryResult(\n        const std::vector<XblMultiplayerSessionQueryResult>& result,\n        const JsonValue& json\n    )\n    {\n        const auto& expectedResults{ json[\"results\"].GetArray() };\n        VERIFY_ARE_EQUAL_UINT(expectedResults.Size(), result.size());\n\n        for (uint32_t i = 0; i < result.size(); ++i)\n        {\n            const auto& a{ result[i] };\n            const auto& e{ expectedResults[i] };\n\n            VERIFY_ARE_EQUAL_UINT(atol(e[\"xuid\"].GetString()), a.Xuid);\n            VERIFY_IS_TRUE(VerifyTime(a.StartTime, e[\"startTime\"].GetString()));\n            \n            VerifyMultiplayerSessionReference(a.SessionReference, e[\"sessionRef\"]);\n            VERIFY_ARE_EQUAL_UINT(e[\"accepted\"].GetUint(), a.AcceptedMemberCount);\n            VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionStatusFromString(e[\"status\"].GetString()) == a.Status);\n            VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionVisibilityFromString(e[\"visibility\"].GetString()) == a.Visibility);\n            VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionRestrictionFromString(e[\"joinRestriction\"].GetString()) == a.JoinRestriction);\n            VERIFY_ARE_EQUAL(e[\"myTurn\"].GetBool(), a.IsMyTurn);\n        }\n    }\n\n    std::vector<XblMultiplayerSessionQueryResult> QuerySessions(\n        XblContextHandle xboxLiveContext,\n        const XblMultiplayerSessionQuery* query,\n        const JsonValue& responseJson = testJson[\"defaultQuerySessionsResponse\"]\n    ) noexcept\n    {\n        auto mock = std::make_shared<HttpMock>( \"\", \"https://sessiondirectory.xboxlive.com\" );\n        mock->SetResponseBody(responseJson);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                bool batch{ query->XuidFiltersCount > 1 };\n\n                xsapi_internal_stringstream expectedPath;\n                expectedPath << \"/serviceconfigs/\" << query->Scid << \"/sessiontemplates/\" << query->SessionTemplateNameFilter;\n                if (batch)\n                {\n                    expectedPath << \"/batch\";\n                }\n                else\n                {\n                    expectedPath << \"/sessions\";\n                }\n                requestWellFormed &= expectedPath.str() == HttpMock::GetUriPath(uri);\n\n                auto queryParams{ HttpMock::GetQueryParams(uri) };\n                if (query->MaxItems)\n                {\n                    requestWellFormed &= queryParams[\"take\"].data() == Utils::StringFromUint64(query->MaxItems);\n                }\n                if (query->IncludePrivateSessions)\n                {\n                    requestWellFormed &= queryParams[\"private\"] == \"true\";\n                }\n                if (query->IncludeReservations)\n                {\n                    requestWellFormed &= queryParams[\"reservations\"] == \"true\";\n                }\n                if (query->IncludeInactiveSessions)\n                {\n                    requestWellFormed &= queryParams[\"inactive\"] == \"true\";\n                }\n                if (query->KeywordFilter)\n                {\n                    requestWellFormed &= queryParams[\"keyword\"] == query->KeywordFilter;\n                }\n                if (query->ContractVersionFilter)\n                {\n                    requestWellFormed &= queryParams[\"version\"] == StringFromUint64Internal(query->ContractVersionFilter);\n                }\n                switch (query->VisibilityFilter)\n                {\n                case XblMultiplayerSessionVisibility::Full:\n                {\n                    requestWellFormed &= queryParams[\"visibility\"] == \"full\";\n                    break;\n                }\n                case XblMultiplayerSessionVisibility::Open:\n                {\n                    requestWellFormed &= queryParams[\"visibility\"] == \"open\";\n                    break;\n                }\n                case XblMultiplayerSessionVisibility::PrivateSession:\n                {\n                    requestWellFormed &= queryParams[\"visibility\"] == \"private\";\n                    break;\n                }\n                case XblMultiplayerSessionVisibility::Visible:\n                {\n                    requestWellFormed &= queryParams[\"visibility\"] == \"visibile\";\n                    break;\n                }\n                default:\n                {\n                    break;\n                }\n                }\n\n                if (batch)\n                {\n                    requestWellFormed &= !body.empty();\n\n                    JsonDocument bodyJson;\n                    bodyJson.Parse(body.data());\n\n                    Vector<uint64_t> xuids{};\n                    JsonUtils::ExtractJsonVector(JsonUtils::JsonXuidExtractor, bodyJson, \"xuids\", xuids, false);\n\n                    requestWellFormed &= xuids.size() == query->XuidFiltersCount;\n\n                    std::unordered_set<uint64_t> unionSet(query->XuidFilters, query->XuidFilters + query->XuidFiltersCount);\n                    for (auto xuid : xuids)\n                    {\n                        unionSet.erase(xuid);\n                    }\n                    requestWellFormed &= unionSet.empty();\n                }\n                else\n                {\n                    requestWellFormed &= body.empty();\n                    if (query->XuidFiltersCount == 1)\n                    {\n                        requestWellFormed &= queryParams[\"xuid\"] == StringFromUint64Internal(query->XuidFilters[0]);\n                    }\n                }\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerQuerySessionsAsync(xboxLiveContext, query, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        size_t resultCount{};\n        VERIFY_SUCCEEDED(XblMultiplayerQuerySessionsResultCount(&async, &resultCount));\n\n        std::vector<XblMultiplayerSessionQueryResult> results(resultCount);\n        VERIFY_SUCCEEDED(XblMultiplayerQuerySessionsResult(&async, resultCount, results.data()));\n        VerifyMultiplayerSessionQueryResult(results, responseJson);\n\n        return results;\n    }\n\n    DEFINE_TEST_CASE(TestGetSessionAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetSessionAsync\");\n\n        MPTestEnv testEnv{};\n        MultiplayerSession::Get(testEnv.XboxLiveContext());\n    }\n\n    DEFINE_TEST_CASE(TestGetSessionWithHandleAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetSessionWithHandleAsync\");\n\n        MPTestEnv testEnv{};\n        MultiplayerSession::Get(testEnv.XboxLiveContext(), \"testHandle\");\n    }\n\n    DEFINE_TEST_CASE(TestGetLargeSessionAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetLargeSessionAsync\");\n\n        MPTestEnv testEnv{};\n        MultiplayerSession::Get(testEnv.XboxLiveContext(), defaultSessionReference, testJson[\"largeSessionDocument\"]);\n    }\n\n    DEFINE_TEST_CASE(TestQuerySessions)\n    {\n        TEST_LOG(L\"Test starting: TestQuerySessions\");\n\n        MPTestEnv env{};\n        std::vector<uint64_t> xuidFilters{ 1 };\n\n        // without keyword filter and without context version filter\n        XblMultiplayerSessionQuery query\n        {\n            \"8d050174-412b-4d51-a29b-d55a34edfdb7\",\n            100,\n            true,\n            true,\n            true,\n            xuidFilters.data(),\n            xuidFilters.size(),\n            nullptr, // No keyword filter\n            \"integration\",\n            XblMultiplayerSessionVisibility::Full,\n            0 // No contract version filter\n        };\n\n        QuerySessions(env.XboxLiveContext(), &query);\n\n        // without xbox user id filter and with all the include settings off\n        query = XblMultiplayerSessionQuery\n        {\n            \"8d050174-412b-4d51-a29b-d55a34edfdb7\",\n            100,\n            false, // exclude private sesions\n            false, // exclude reservations\n            false, // exclude inactive sessions\n            nullptr, // no xuid filters\n            0,\n            \"hello\",\n            \"integration\",\n            XblMultiplayerSessionVisibility::Any,\n            5\n        };\n\n        QuerySessions(env.XboxLiveContext(), &query);\n\n        // with multiple xuid filters (batch query)\n        xuidFilters.clear();\n        xuidFilters = { 12345, 67890 };\n\n        query = XblMultiplayerSessionQuery\n        {\n            \"8d050174-412b-4d51-a29b-d55a34edfdb7\",\n            100,\n            true,\n            true,\n            true,\n            xuidFilters.data(),\n            xuidFilters.size(),\n            nullptr,\n            \"integration\",\n            XblMultiplayerSessionVisibility::Full,\n            0\n        };\n\n        QuerySessions(env.XboxLiveContext(), &query);\n    }\n\n    DEFINE_TEST_CASE(TestWriteNewSession)\n    {\n        TEST_LOG(L\"Test starting: TestWriteNewSession\");\n\n        MPTestEnv env{};\n\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), \"\\\"Hello\\\"\", true, true));\n        XblMultiplayerSessionCurrentUserSetStatus(session.Handle(), XblMultiplayerSessionMemberStatus::Active);\n        XblMultiplayerSessionConstantsSetVisibility(session.Handle(), XblMultiplayerSessionVisibility::PrivateSession);\n        XblMultiplayerSessionConstantsSetMaxMembersInSession(session.Handle(), 10);\n\n        const char* groups[] { \"team-buzz\", \"posse.99\" };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetGroups(session.Handle(), groups, _countof(groups)));\n\n        const char* encounters[]{ \"CoffeeShop-757093D8-E41F-49D0-BB13-17A49B20C6B9\" };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetEncounters(session.Handle(), encounters, _countof(encounters)));\n\n        XblMultiplayerSessionMemberRole roles[]\n        {\n            { \"lfg\", \"friend\" },\n            { \"admin\", \"super\" }\n        };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetRoles(session.Handle(), roles, _countof(roles)));\n\n        // Verify local object is updated\n        auto currentUser{ XblMultiplayerSessionCurrentUser(session.Handle()) };\n        VERIFY_IS_NOT_NULL(currentUser);\n\n        VERIFY_IS_TRUE(currentUser->Status == XblMultiplayerSessionMemberStatus::Active);\n        VERIFY_IS_TRUE(session.Constants()->Visibility == XblMultiplayerSessionVisibility::PrivateSession);\n        VERIFY_ARE_EQUAL_UINT(10, session.Constants()->MaxMembersInSession);\n\n        VERIFY_ARE_EQUAL_UINT(_countof(groups), currentUser->GroupsCount);\n        for (size_t i = 0; i < _countof(groups); ++i)\n        {\n            VERIFY_ARE_EQUAL_STR(groups[i], currentUser->Groups[i]);\n        }\n\n        VERIFY_ARE_EQUAL_UINT(_countof(encounters), currentUser->EncountersCount);\n        for (size_t i = 0; i < _countof(encounters); ++i)\n        {\n            VERIFY_ARE_EQUAL_STR(encounters[i], currentUser->Encounters[i]);\n        }\n\n        VERIFY_ARE_EQUAL_UINT(_countof(roles), currentUser->RolesCount);\n        for (size_t i = 0; i < _countof(roles); ++i)\n        {\n            VERIFY_ARE_EQUAL_STR(roles[i].roleName, currentUser->Roles[i].roleName);\n            VERIFY_ARE_EQUAL_STR(roles[i].roleTypeName, currentUser->Roles[i].roleTypeName);\n        }\n\n        session.Write(testJson[\"defaultJsonWrite\"]);\n    }\n\n    DEFINE_TEST_CASE(TestEmptyWrite)\n    {\n        TEST_LOG(L\"Test starting: TestEmptyWrite\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // request body should be empty since we didn't change anything\n        session.Write(JsonValue{ rapidjson::kObjectType });\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionCapabilities)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionCapabilities\");\n\n        MPTestEnv env{};\n\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        XblMultiplayerSessionCapabilities capabilities{};\n        capabilities.Connectivity = true;\n        capabilities.Gameplay = true;\n        capabilities.Large = true;\n        capabilities.SuppressPresenceActivityCheck = true;\n        capabilities.ConnectionRequiredForActiveMembers = true;\n        capabilities.Crossplay = true;\n        capabilities.UserAuthorizationStyle = true;\n        capabilities.HasOwners = true;\n        capabilities.Searchable = true;\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetCapabilities(session.Handle(), capabilities));\n\n        // Verify local object is updated\n        VERIFY_ARE_EQUAL_INT(0, memcmp(&capabilities, &session.Constants()->SessionCapabilities, sizeof(XblMultiplayerSessionCapabilities)));\n\n        session.Write(testJson[\"sessionCapabilitiesJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithServersJson)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithServersJson\");\n\n        MPTestEnv env{};\n\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        JsonDocument serversJson{ rapidjson::Type::kObjectType };\n        serversJson.AddMember(\"server\", JsonValue{ 100 }, serversJson.GetAllocator());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetRawServersJson(session.Handle(), JsonUtils::SerializeJson(serversJson).data()));\n\n        // Verify that the local session object is updated correctly\n        VERIFY_IS_TRUE(VerifyJson(serversJson, XblMultiplayerSessionRawServersJson(session.Handle())));\n\n        session.Write(testJson[\"serversJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetSessionCustomPropertyJson)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetSessionCustomPropertyJson\");\n\n        MPTestEnv env{};\n\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"PropA\", \"\\\"ToBeReset\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"PropA\", \"\\\"ValueA\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"PropB\", \"{\\\"ValueB\\\":5}\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"boolTrue\", \"true\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"boolFalse\", \"false\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"stringTrue\", \"\\\"true\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"stringFalse\", \"\\\"false\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"number42\", \"42\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"objectA\", \"{\\\"name\\\":\\\"A\\\"}\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(session.Handle(), \"arrayA\", \"[1,2,3,4]\"));\n\n        const auto& expectedRequest{ testJson[\"writeCustomPropertyJson\"] };\n        const auto& expectedPropertiesJson{ expectedRequest[\"properties\"][\"custom\"] };\n\n        // Verify that the local object is updated correctly\n        VERIFY_IS_TRUE(VerifyJson(expectedPropertiesJson, session.Properties()->SessionCustomPropertiesJson));\n\n        session.Write(expectedRequest);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetMatchmakingProperties)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetMatchmakingProperties\");\n\n        MPTestEnv env{};\n\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        const char targetSessionConstants[] = \"{\\\"foo\\\":\\\"test1002\\\"}\";\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetMatchmakingTargetSessionConstantsJson(session.Handle(), targetSessionConstants));\n\n        // Verify local object\n        VERIFY_IS_TRUE(VerifyJson(targetSessionConstants, session.Properties()->MatchmakingTargetSessionConstantsJson));\n\n        session.Write(testJson[\"matchmakingSessionConstantsJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithAddMemberReservation)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithAddMemberReservation\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionAddMemberReservation(session.Handle(), 1234, \"{ \\\"skill\\\" : 100 }\", true));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionAddMemberReservation(session.Handle(), 4567, \"{ \\\"down\\\" : true }\", false));\n\n        session.Write(testJson[\"writeAddMemberJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithDeleteSessionCustomPropertyJson)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithDeleteSessionCustomPropertyJson\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"PropA\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"PropB\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"boolTrue\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"boolFalse\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"stringTrue\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"stringFalse\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"number42\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"objectA\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionDeleteCustomPropertyJson(session.Handle(), \"arrayA\"));\n\n        session.Write(testJson[\"deleteCustomPropertyJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithJoin1)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithJoin1\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false));\n\n        session.Write(testJson[\"memberStatusInactiveJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithJoin2)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithJoin2\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), \"{ \\\"testValue\\\" : 100 }\", false, false));\n\n        session.Write(testJson[\"memberStatusInactiveJson2\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithJoin3)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithJoin3\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), \"{ \\\"testValue\\\" : 100 }\", true, true));\n\n        session.Write(testJson[\"memberStatusInactiveJson3\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithLeave)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithLeave\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionLeave(session.Handle()));\n        session.Write(testJson[\"leaveJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserInactive)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserInactive\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetStatus(session.Handle(), XblMultiplayerSessionMemberStatus::Inactive));\n\n        session.Write(testJson[\"memberStatusActiveJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserActive)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserActive\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetStatus(session.Handle(), XblMultiplayerSessionMemberStatus::Active));\n\n        session.Write(testJson[\"matchmakingPropertiesJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserSecureDeviceAddressBase64)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserSecureDeviceAddressBase64\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, true));\n        XblMultiplayerSessionCurrentUserSetSecureDeviceAddressBase64(session.Handle(), \"1234\");\n\n        session.Write(testJson[\"secureDeviceJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestXblFormatSecureDeviceAddress)\n    {\n        TEST_LOG(L\"Test starting: TestXblFormatSecureDeviceAddress\");\n\n        String deviceId;\n        XblFormattedSecureDeviceAddress address{};\n        \n        deviceId = \"12345678901234567890\";\n        VERIFY_SUCCEEDED(XblFormatSecureDeviceAddress(deviceId.c_str(), &address));\n        VERIFY_ARE_EQUAL_STR(address.value, \"QUFBQUFBQUExMjM0NTY3ODkwMTIzNDU2Nzg5MA==\");\n\n        deviceId = \"A1B2C3D4E5F6\";\n        VERIFY_SUCCEEDED(XblFormatSecureDeviceAddress(deviceId.c_str(), &address));\n        VERIFY_ARE_EQUAL_STR(address.value, \"QUFBQUFBQUFBMUIyQzNENEU1RjY=\");\n\n        // Test nullptr\n        VERIFY_FAILED(XblFormatSecureDeviceAddress(nullptr, &address));\n        VERIFY_FAILED(XblFormatSecureDeviceAddress(\"\", &address));\n        VERIFY_FAILED(XblFormatSecureDeviceAddress(deviceId.c_str(), nullptr));\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserMemberCustomPropertyJson)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserMemberCustomPropertyJson\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, true));\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"health\", \"\\\"toBeReset\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"health\", \"4567\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"boolTrue\", \"true\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"boolFalse\", \"false\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"stringTrue\", \"\\\"true\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"stringFalse\", \"\\\"false\\\"\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"number42\", \"42\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"objectA\", \"{\\\"name\\\":\\\"A\\\"}\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetCustomPropertyJson(session.Handle(), \"arrayA\", \"[1,2,3,4]\"));\n\n        const auto& expectedRequest{ testJson[\"memberCustomJson\"] };\n        const auto& expectedPropertiesJson{ expectedRequest[\"members\"][\"me\"][\"properties\"][\"custom\"] };\n\n        // Verify that the local User is updated correctly\n        auto currentUser{ XblMultiplayerSessionCurrentUser(session.Handle()) };\n        VERIFY_IS_TRUE(VerifyJson(expectedPropertiesJson, currentUser->CustomPropertiesJson));\n\n        session.Write(expectedRequest);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithDeleteCurrentUserMemberCustomPropertyJson)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithDeleteCurrentUserMemberCustomPropertyJson\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, true));\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"health\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"health\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"boolTrue\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"boolFalse\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"stringTrue\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"stringFalse\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"number42\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"objectA\"));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserDeleteCustomPropertyJson(session.Handle(), \"arrayA\"));\n\n        session.Write(testJson[\"deleteMemberCustomJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithTurnCollection)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithTurnCollection\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        uint32_t turnCollection[] = { 0 };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionPropertiesSetTurnCollection(session.Handle(), turnCollection, _countof(turnCollection)));\n\n        // Verify local object\n        VERIFY_ARE_EQUAL_UINT(_countof(turnCollection), session.Properties()->TurnCollectionCount);\n        VERIFY_ARE_EQUAL_UINT(turnCollection[0], session.Properties()->TurnCollection[0]);\n\n        session.Write(testJson[\"turnJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithKeywords)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithKeywords\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        const char* keywords[] = { \"apple\" };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionPropertiesSetKeywords(session.Handle(), keywords, _countof(keywords)));\n\n        // Verify local object\n        VERIFY_ARE_EQUAL_UINT(_countof(keywords), session.Properties()->KeywordCount);\n        VERIFY_ARE_EQUAL_STR(keywords[0], session.Properties()->Keywords[0]);\n\n        session.Write(testJson[\"keywordsJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithJoinRestriction)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithJoinRestriction\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO why no HRESULT here?\n        XblMultiplayerSessionPropertiesSetJoinRestriction(session.Handle(), XblMultiplayerSessionRestriction::Followed);\n\n        // Verify local object\n        VERIFY_IS_TRUE(XblMultiplayerSessionRestriction::Followed == session.Properties()->JoinRestriction);\n\n        session.Write(testJson[\"joinRestrictionJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithReadRestriction)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithReadRestriction\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO why no HRESULT here?\n        XblMultiplayerSessionPropertiesSetReadRestriction(session.Handle(), XblMultiplayerSessionRestriction::Followed);\n\n        // Verify local object\n        VERIFY_IS_TRUE(XblMultiplayerSessionRestriction::Followed == session.Properties()->ReadRestriction);\n\n        session.Write(testJson[\"TestWriteSessionAsyncWithReadRestrictionExpectedRequest\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetTimeouts)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetTimeouts\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetTimeouts(session.Handle(), 3001000, 3002000, 3003000, 3004000));\n\n        // Verify local object\n        VERIFY_ARE_EQUAL_UINT(session.Constants()->MemberReservedTimeout, 3001000);\n        VERIFY_ARE_EQUAL_UINT(session.Constants()->MemberInactiveTimeout, 3002000);\n        VERIFY_ARE_EQUAL_UINT(session.Constants()->MemberReadyTimeout, 3003000);\n        VERIFY_ARE_EQUAL_UINT(session.Constants()->SessionEmptyTimeout, 3004000);\n\n        session.Write(testJson[\"timeoutsJson\"]);\n    }\n       \n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetQualityOfServiceConnectivityMetrics)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetQualityOfServiceConnectivityMetrics\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetQosConnectivityMetrics(session.Handle(), true, true, true, true));\n\n        // Verify local object\n        VERIFY_ARE_EQUAL(true, session.Constants()->EnableMetricsLatency);\n        VERIFY_ARE_EQUAL(true, session.Constants()->EnableMetricsBandwidthDown);\n        VERIFY_ARE_EQUAL(true, session.Constants()->EnableMetricsBandwidthUp);\n        VERIFY_ARE_EQUAL(true, session.Constants()->EnableMetricsCustom);\n\n        session.Write(testJson[\"qosMetricsJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestGetCloudComputePackageJson)\n    {\n        TEST_LOG(L\"Test starting: TestGetCloudComputePackageJson\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        const char json[] = \"{\\\"crossSandbox\\\":true, \\\"titleId\\\":\\\"4567\\\", \\\"gsiSet\\\":\\\"128ce92a-45d0-4319-8a7e-bd8e940114ec\\\"}\";\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetCloudComputePackageJson(session.Handle(), json));\n\n        // Validate the local object is updated\n        VERIFY_IS_TRUE(VerifyJson(json, session.Constants()->SessionCloudComputePackageConstantsJson));\n\n        session.Write(testJson[\"cloudComputePackageJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetMemberInitialization)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetMemberInitialization\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        XblMultiplayerMemberInitialization memberInitialization\n        {\n            4001000,\n            4002000,\n            4003000,\n            true,\n            4004\n        };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetMemberInitialization(session.Handle(), memberInitialization));\n\n        // Verify the local object is updated\n        VERIFY_IS_NOT_NULL(session.Constants()->MemberInitialization);\n        VERIFY_ARE_EQUAL_UINT(memberInitialization.JoinTimeout, session.Constants()->MemberInitialization->JoinTimeout);\n        VERIFY_ARE_EQUAL_UINT(memberInitialization.MeasurementTimeout, session.Constants()->MemberInitialization->MeasurementTimeout);\n        VERIFY_ARE_EQUAL_UINT(memberInitialization.EvaluationTimeout, session.Constants()->MemberInitialization->EvaluationTimeout);\n        VERIFY_ARE_EQUAL(memberInitialization.ExternalEvaluation, session.Constants()->MemberInitialization->ExternalEvaluation);\n        VERIFY_ARE_EQUAL_UINT(memberInitialization.MembersNeededToStart, session.Constants()->MemberInitialization->MembersNeededToStart);\n\n        session.Write(testJson[\"memberInitializationJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetPeerToPeerRequirements)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetPeerToPeerRequirements\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        XblMultiplayerPeerToPeerRequirements reqs{ 5001, 5002 };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetPeerToPeerRequirements(session.Handle(), reqs));\n\n        // ensure local object is updated\n        VERIFY_ARE_EQUAL_UINT(reqs.LatencyMaximum, session.Constants()->PeerToPeerRequirements.LatencyMaximum);\n        VERIFY_ARE_EQUAL_UINT(reqs.BandwidthMinimumInKbps, session.Constants()->PeerToPeerRequirements.BandwidthMinimumInKbps);\n\n        session.Write(testJson[\"peerToPeerJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetPeerToHostRequirements)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetPeerToHostRequirements\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        XblMultiplayerPeerToHostRequirements reqs{ 6001, 6002, 6003, XblMultiplayerMetrics::Bandwidth };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionConstantsSetPeerToHostRequirements(session.Handle(), reqs));\n\n        // ensure local object is updated\n        VERIFY_ARE_EQUAL_UINT(reqs.LatencyMaximum, session.Constants()->PeerToHostRequirements.LatencyMaximum);\n        VERIFY_ARE_EQUAL_UINT(reqs.BandwidthDownMinimumInKbps, session.Constants()->PeerToHostRequirements.BandwidthDownMinimumInKbps);\n        VERIFY_ARE_EQUAL_UINT(reqs.BandwidthUpMinimumInKbps, session.Constants()->PeerToHostRequirements.BandwidthUpMinimumInKbps);\n        VERIFY_IS_TRUE(reqs.HostSelectionMetric == session.Constants()->PeerToHostRequirements.HostSelectionMetric);\n\n        session.Write(testJson[\"peerToHostJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetInitializationStatus)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetInitializationStatus\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        // TODO why no HRESULT here?\n        XblMultiplayerSessionSetInitializationSucceeded(session.Handle(), true);\n\n        session.Write(testJson[\"initializationStatusJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetHostDeviceToken)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetHostDeviceToken\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO why not XblMultiplayerDeviceToken?\n        // TODO why no HRESULT?\n        XblDeviceToken token{ \"1234\" };\n        XblMultiplayerSessionSetHostDeviceToken(session.Handle(), token);\n\n        // Verify local object\n        VERIFY_ARE_EQUAL_STR(token.Value, session.Properties()->HostDeviceToken.Value);\n\n        session.Write(testJson[\"hostDeviceTokenJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetMatchmakingServerConnectionPath)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetMatchmakingServerConnectionPath\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO why no HRESULT?\n        const char* connectionString{ \"8001\" };\n        XblMultiplayerSessionSetMatchmakingServerConnectionPath(session.Handle(), connectionString);\n        VERIFY_ARE_EQUAL_STR(connectionString, session.Properties()->MatchmakingServerConnectionString);\n\n        session.Write(testJson[\"serverConnectionPathJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetMatchmakingResubmit)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetMatchmakingResubmit\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO HRESULT\n        XblMultiplayerSessionSetMatchmakingResubmit(session.Handle(), true);\n        VERIFY_IS_TRUE(session.Properties()->MatchmakingResubmit);\n\n        session.Write(testJson[\"matchmakingResubmitJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetServerConnectionStringCandidates)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetServerConnectionStringCandidates\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        const char* candidates[] = { \"9001\", \"9002\", \"9003\" };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetServerConnectionStringCandidates(session.Handle(), candidates, _countof(candidates)));\n\nVERIFY_ARE_EQUAL_UINT(_countof(candidates), session.Properties()->ServerConnectionStringCandidatesCount);\nfor (size_t i = 0; i < _countof(candidates); ++i)\n{\n    VERIFY_ARE_EQUAL_STR(candidates[i], session.Properties()->ServerConnectionStringCandidates[i]);\n}\n\nsession.Write(testJson[\"serverConnectionStringCandidatesJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserMembersInGroup)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserMembersInGroup\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, true));\n\n        uint32_t membersInGroup[] = { 0 };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetMembersInGroup(session.Handle(), membersInGroup, _countof(membersInGroup)));\n\n        auto currentUser{ XblMultiplayerSessionCurrentUser(session.Handle()) };\n        VERIFY_ARE_EQUAL_UINT(_countof(membersInGroup), currentUser->MembersInGroupCount);\n        for (size_t i = 0; i < _countof(membersInGroup); ++i)\n        {\n            VERIFY_ARE_EQUAL_UINT(membersInGroup[i], currentUser->MembersInGroupIds[i]);\n        }\n\n        session.Write(testJson[\"membersInGroupJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithClosed)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithClosed\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO should be XblMultiplayerSessionPropertiesSetClosed\n        // TODO return HRESULT\n        XblMultiplayerSessionSetClosed(session.Handle(), true);\n        VERIFY_ARE_EQUAL(true, session.Properties()->Closed);\n\n        session.Write(testJson[\"closedJson\"]);\n    }\n\n    TEST_METHOD(TestWriteSessionAsyncWithLocked)\n    {\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        // TODO should be XblMultiplayerSessionPropertiesSetLocked\n        // TODO return HRESULT\n        XblMultiplayerSessionSetLocked(session.Handle(), true);\n        VERIFY_ARE_EQUAL(true, session.Properties()->Locked);\n\n        session.Write(testJson[\"lockedJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserQualityOfServiceMeasurements)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserQualityOfServiceMeasurements\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        const auto& expectedRequest{ testJson[\"qosMeasurementsJson\"] };\n        const auto& qosJson = expectedRequest[\"members\"][\"me\"][\"properties\"][\"system\"][\"measurements\"];\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetQosMeasurements(session.Handle(), JsonUtils::SerializeJson(qosJson).data()));\n        VERIFY_IS_TRUE(VerifyJson(qosJson, XblMultiplayerSessionCurrentUser(session.Handle())->QosMeasurementsJson));\n\n        session.Write(expectedRequest);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetCurrentUserQualityOfServiceServerMeasurementsJson)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetCurrentUserQualityOfServiceServerMeasurementsJson\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        const auto& expectedRequest{ testJson[\"qosServerMeasurementsJson\"] };\n        const auto& qosJson = expectedRequest[\"members\"][\"me\"][\"properties\"][\"system\"][\"serverMeasurements\"];\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionCurrentUserSetServerQosMeasurements(session.Handle(), JsonUtils::SerializeJson(qosJson).data()));\n        VERIFY_IS_TRUE(VerifyJson(qosJson, XblMultiplayerSessionCurrentUser(session.Handle())->ServerMeasurementsJson));\n\n        session.Write(expectedRequest);\n    }\n\n    DEFINE_TEST_CASE(TestWriteSessionAsyncWithSetMutableRoleSettings)\n    {\n        TEST_LOG(L\"Test starting: TestWriteSessionAsyncWithSetMutableRoleSettings\");\n\n        MPTestEnv env{};\n        auto session = MultiplayerSession::Get(env.XboxLiveContext());\n\n        uint32_t max{ 1 }, target{ 1 };\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetMutableRoleSettings(session.Handle(), \"lfg\", \"friend\", &max, &target));\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetMutableRoleSettings(session.Handle(), \"lfg\", \"other\", &max, nullptr));\n\n        auto roles{ session.RoleTypes() };\n        for (const auto& roleType : roles)\n        {\n            if (xsapi_internal_string{ roleType->Name } == \"lfg\")\n            {\n                for (size_t i = 0; i < roleType->RoleCount; ++i)\n                {\n                    if (xsapi_internal_string{ roleType->Roles[i].Name } == \"friend\")\n                    {\n                        VERIFY_ARE_EQUAL_UINT(max, roleType->Roles[i].MaxMemberCount);\n                        VERIFY_ARE_EQUAL_UINT(target, roleType->Roles[i].TargetCount);\n                    }\n                    else if (xsapi_internal_string{ roleType->Roles[i].Name } == \"other\")\n                    {\n                        VERIFY_ARE_EQUAL_UINT(max, roleType->Roles[i].MaxMemberCount);\n                    }\n                }\n            }\n        }\n\n        session.Write(testJson[\"roleTypesRequestJson\"]);\n    }\n\n    DEFINE_TEST_CASE(TestSetActivityAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSetActivityAsync\");\n\n        MPTestEnv env{};\n        auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles\" );\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string, xsapi_internal_string body)\n            {\n                requestWellFormed &= VerifyJson(testJson[\"activityJson\"], body.data());\n            });\n\n        XblMultiplayerSessionReference activityRef\n        {\n            \"MockScid\", // serviceConfigurationId\n            \"MockSessionTemplateName\", // sessionTemplateName\n            \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\" // sessionName\n        };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerSetActivityAsync(env.XboxLiveContext(), &activityRef, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestClearActivityAsync)\n    {\n        TEST_LOG(L\"Test starting: TestClearActivityAsync\");\n\n        MPTestEnv env{};\n\n        // XblMultiplayerClearActivityAsync results in 2 service calls; first to query the activity, and then to clear it. Set up\n        // a mock for each endpoint\n        HttpMock queryActivityMock{ \"POST\", MPSD_URI };\n        queryActivityMock.SetResponseBody(testJson[\"activitiesForUserResponseJson\"]);\n\n        HttpMock clearActivityMock{ \"DELETE\", MPSD_URI \"/handles/7a4d0a99-4e23-4eba-9894-5173cf123fb4\" };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerClearActivityAsync(env.XboxLiveContext(), MOCK_SCID, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n    }\n\n    DEFINE_TEST_CASE(TestSetTransferHandleAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSetTransferHandleAsync\");\n\n        MPTestEnv env{};\n\n        const auto& responseBody{ testJson[\"transferHandleResponseJson\"] };\n        auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles\" );\n        mock->SetResponseBody(responseBody);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string, xsapi_internal_string body)\n            {\n                requestWellFormed &= VerifyJson(testJson[\"transferHandleJson\"], body.data());\n            });\n\n        XblMultiplayerSessionReference target\n        {\n            \"MockScid\", // serviceConfigurationId\n            \"MockSessionTemplateName\", // sessionTemplateName\n            \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\" // sessionName\n        };\n\n        XblMultiplayerSessionReference origin\n        {\n            \"MockScid\", // serviceConfigurationId\n            \"samplelobbytemplate107\", // sessionTemplateName\n            \"bd6c41c3-01c3-468a-a3b5-3e0fe8133862\" // sessionName\n        };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerSetTransferHandleAsync(env.XboxLiveContext(), target, origin, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        XblMultiplayerSessionHandleId handleId{};\n        VERIFY_SUCCEEDED(XblMultiplayerSetTransferHandleResult(&async, &handleId));\n        VERIFY_ARE_EQUAL_STR_IGNORE_CASE(responseBody[\"id\"].GetString(), handleId.value);\n    }\n\n    DEFINE_TEST_CASE(TestGetSearchHandlesAsync_1)\n    {\n        TEST_LOG(L\"Test starting: TestGetSearchHandlesAsync_1\");\n\n        MPTestEnv env{};\n\n        MultiplayerSearchDetails::Query(\n            env.XboxLiveContext(),\n            MOCK_SCID,\n            \"GlobalLFGTemplate\",\n            \"OrderBy\",\n            true,\n            \"SearchQuery\"\n        );\n    }\n\n    DEFINE_TEST_CASE(TestGetSearchHandlesAsync_2)\n    {\n        TEST_LOG(L\"Test starting: TestGetSearchHandlesAsync_2\");\n\n        MPTestEnv env{};\n\n        MultiplayerSearchDetails::Query(\n            env.XboxLiveContext(),\n            MOCK_SCID,\n            \"GlobalLFGTemplate\",\n            \"OrderBy\",\n            true,\n            \"SearchQuery\",\n            \"favorites\",\n            testJson[\"searchHandlesWithSocialGroupRequestJson\"]\n        );\n    }\n\n    DEFINE_TEST_CASE(TestSetSearchHandleAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSetSearchHandleAsync\");\n\n        MPTestEnv env{};\n\n        XblMultiplayerSessionReference sessionRef\n        {\n            MOCK_SCID,\n            \"GlobalLFGSessionTemplateName\",\n            \"LFGSession\"\n        };\n\n        std::vector<XblMultiplayerSessionTag> tags{ { \"micsrequired\" }, { \"girlsonly\" } };\n        std::vector<XblMultiplayerSessionNumberAttribute> numberAttributes{ { \"Skill_D\", 10.145 }, { \"Skill_I\", 14 } };\n        std::vector<XblMultiplayerSessionStringAttribute> stringAttributes{ { \"Class\", \"A\" } };\n\n        MultiplayerSearchDetails::Create(\n            env.XboxLiveContext(),\n            sessionRef,\n            tags,\n            numberAttributes,\n            stringAttributes\n        );\n    }\n\n    DEFINE_TEST_CASE(TestClearSearchHandleAsync)\n    {\n        TEST_LOG(L\"Test starting: TestClearSearchHandleAsync\");\n\n        MPTestEnv env{};\n\n        HttpMock mock{\"DELETE\", MPSD_URI \"/handles/TestHandleId\" };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerDeleteSearchHandleAsync(env.XboxLiveContext(), \"TestHandleId\", &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n    }\n\n    DEFINE_TEST_CASE(TestSendInvitesAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSendInvitesAsync\");\n\n        MPTestEnv env{};\n\n        std::vector<uint64_t> xuids{ 1111, 2222 };\n\n        auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles\" );\n\n        // Inviting multiple Xuids results in multiple Http calls. Make sure the expected number of calls go out\n        size_t requestCount{ 0 };\n        bool requestsWellFormed{ true };\n        const char* responseIds[] = { \"B8704EC5-95CD-408B-BD41-BAA7A2761CC2\", \"9D74C42E-87DE-47BA-B489-D3A264C9F994\" };\n        JsonDocument testResponses{ GetTestResponses(\"TestResponses\\\\Multiplayer.json\") };\n        auto inviteRequestJson = JsonUtils::SerializeJson(testResponses[\"inviteRequestJson\"]);\n        auto inviteResponseJson = JsonUtils::SerializeJson(testResponses[\"inviteResponseJson\"]);\n        JsonDocument expectedRequestBodyJson;\n        JsonDocument responseBodyJson;\n        expectedRequestBodyJson.Parse(inviteRequestJson.c_str());\n        responseBodyJson.Parse(inviteResponseJson.c_str());\n\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n            {\n                UNREFERENCED_PARAMETER(uri);\n\n                if (requestCount < xuids.size())\n                {\n                    {\n                        auto& a{ expectedRequestBodyJson.GetAllocator() };\n                        JsonUtils::SetMember(expectedRequestBodyJson, \"invitedXuid\", JsonValue{ StringFromUint64Internal(xuids[requestCount]).data(), a });\n                        requestsWellFormed &= VerifyJson(expectedRequestBodyJson, body.data());\n                    }\n                    {\n                        auto& a{ responseBodyJson.GetAllocator() };\n                        JsonUtils::SetMember(responseBodyJson, \"invitedXuid\", JsonValue{ StringFromUint64Internal(xuids[requestCount]).data(), a });\n                        JsonUtils::SetMember(responseBodyJson, \"id\", JsonValue{ responseIds[requestCount], a });\n                        mock->SetResponseBody(responseBodyJson);\n                    }\n                }\n                requestCount++;\n            }\n        );\n\n        XblMultiplayerSessionReference sessionRef\n        {\n            MOCK_SCID,\n            \"MockSessionTemplateName\",\n            \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerSendInvitesAsync(\n            env.XboxLiveContext(),\n            &sessionRef,\n            xuids.data(),\n            xuids.size(),\n            MOCK_TITLEID,\n            nullptr,\n            nullptr,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_ARE_EQUAL_UINT(xuids.size(), requestCount);\n        VERIFY_IS_TRUE(requestsWellFormed);\n\n        std::vector<XblMultiplayerInviteHandle> inviteHandles(xuids.size());\n        VERIFY_SUCCEEDED(XblMultiplayerSendInvitesResult(&async, inviteHandles.size(), inviteHandles.data()));\n\n        for (size_t i = 0; i < inviteHandles.size(); ++i)\n        {\n            VERIFY_ARE_EQUAL_STR_IGNORE_CASE(responseIds[i], inviteHandles[i].Data);\n        }\n    }\n\n    void VerifyGetActivitiesForUsers(MPTestEnv& env, bool withProperties)\n    {\n        auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles\" );\n        mock->SetResponseBody(testJson[\"activitiesForUserResponseJson\"]);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback([&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n        {\n            UNREFERENCED_PARAMETER(mock);\n            UNREFERENCED_PARAMETER(uri);\n            requestWellFormed &= VerifyJson(testJson[\"activitiesForUserRequestJson\"], body.data());\n        });\n\n        XAsyncBlock async{};\n        uint64_t xuids[] = { 1234 };\n        if (withProperties)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(env.XboxLiveContext(), MOCK_SCID, xuids, _countof(xuids), &async));\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesForUsersAsync(env.XboxLiveContext(), MOCK_SCID, xuids, _countof(xuids), &async));\n        }\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        const auto& resultsJson{ testJson[\"activitiesForUserResponseJson\"][\"results\"].GetArray() };\n\n        size_t resultSize{};\n        size_t resultCount{};\n        if (withProperties)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesWithPropertiesForUsersResultSize(&async, &resultSize));\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesForUsersResultCount(&async, &resultCount));\n            VERIFY_ARE_EQUAL_UINT(resultsJson.Size(), resultCount);\n        }\n\n        size_t count{ 0 };\n        std::vector<char> buffer(resultSize, 0);\n        std::vector<XblMultiplayerActivityDetails> activityDetailsVector{};\n        XblMultiplayerActivityDetails* activityDetails{};\n        if (withProperties)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesWithPropertiesForUsersResult(&async, resultSize, buffer.data(), &activityDetails, &count, nullptr));\n            VERIFY_ARE_EQUAL_UINT(resultsJson.Size(), count);\n        }\n        else\n        {\n            count = resultCount;\n            activityDetailsVector = std::vector<XblMultiplayerActivityDetails>(resultCount);\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesForUsersResult(&async, resultCount, activityDetailsVector.data()));\n            activityDetails = activityDetailsVector.data();\n        }\n\n        for (uint32_t i = 0; i < count; ++i)\n        {\n            const auto& a{ activityDetails[i] };\n            const auto& e{ resultsJson[i] };\n\n            VerifyMultiplayerSessionReference(a.SessionReference, e[\"sessionRef\"]);\n            VERIFY_ARE_EQUAL_STR_IGNORE_CASE(e[\"id\"].GetString(), a.HandleId);\n            VERIFY_JSON_INT_STRING(e, \"titleId\", a.TitleId);\n            VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionVisibilityFromString(e[\"relatedInfo\"][\"visibility\"].GetString()) == a.Visibility);\n            VERIFY_IS_TRUE(multiplayer::Serializers::MultiplayerSessionRestrictionFromString(e[\"relatedInfo\"][\"joinRestriction\"].GetString()) == a.JoinRestriction);\n            VERIFY_ARE_EQUAL(e[\"relatedInfo\"][\"closed\"].GetBool(), a.Closed);\n            VERIFY_JSON_INT_STRING(e, \"ownerXuid\", a.OwnerXuid);\n            VERIFY_ARE_EQUAL_UINT(e[\"relatedInfo\"][\"maxMembersCount\"].GetUint(), a.MaxMembersCount);\n            VERIFY_ARE_EQUAL_UINT(e[\"relatedInfo\"][\"membersCount\"].GetUint(), a.MembersCount);\n        }\n    }\n\n    void VerifyGetActivitiesForSocialGroup(MPTestEnv& env, bool withProperties)\n    {\n        auto mock = std::make_shared<HttpMock>( \"POST\", MPSD_URI \"/handles\" );\n        mock->SetResponseBody(testJson[\"activitiesForSocialGroupResponseJson\"]);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback([&](HttpMock* mock, xsapi_internal_string uri, xsapi_internal_string body)\n        {\n            UNREFERENCED_PARAMETER(mock);\n            UNREFERENCED_PARAMETER(uri);\n            requestWellFormed &= VerifyJson(testJson[\"activitiesForSocialGroupRequestJson\"], body.data());\n        });\n\n        XAsyncBlock async{};\n        if (withProperties)\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesWithPropertiesForSocialGroupAsync(\n                env.XboxLiveContext(),\n                MOCK_SCID,\n                env.XboxLiveContext()->Xuid(),\n                \"friends\",\n                &async\n            ));\n        }\n        else\n        {\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesForSocialGroupAsync(\n                env.XboxLiveContext(),\n                MOCK_SCID,\n                env.XboxLiveContext()->Xuid(),\n                \"friends\",\n                &async\n            ));\n        }\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        if (withProperties)\n        {\n            size_t resultSize{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesWithPropertiesForSocialGroupResultSize(&async, &resultSize));\n            VERIFY_ARE_EQUAL_UINT(0, resultSize);\n        }\n        else\n        {\n            size_t resultCount{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetActivitiesForSocialGroupResultCount(&async, &resultCount));\n            VERIFY_ARE_EQUAL_UINT(0, resultCount);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetActivitiesForUsersAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetActivitiesForUsersAsync\");\n\n        MPTestEnv env{};\n\n        VerifyGetActivitiesForUsers(env, false);\n        VerifyGetActivitiesForUsers(env, true);\n    }\n\n    DEFINE_TEST_CASE(TestGetActivitiesForSocialGroupAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetActivitiesForSocialGroupAsync\");\n\n        MPTestEnv env{};\n\n        VerifyGetActivitiesForSocialGroup(env, false);\n        VerifyGetActivitiesForSocialGroup(env, true);\n    }\n\n    DEFINE_TEST_CASE(TestCompareMultiplayerSessions)\n    {\n        TEST_LOG(L\"Test starting: TestCompareMultiplayerSessions\");\n\n        MPTestEnv env{};\n\n        {\n            XblMultiplayerSessionReference sessionRef\n            {\n                \"361D0DAA-620E-4975-B64C-0C32500D41EF\",\n                \"MySessionTemplate\",\n                \"32A53A76-9802-42C7-A28E-4FD483301D8B\"\n            };\n\n            const uint64_t initiators[] = { 12323 };\n            XblMultiplayerSessionInitArgs initArgs\n            {\n                50, // maxMembersInSession\n                XblMultiplayerSessionVisibility::Full,\n                initiators,\n                _countof(initiators),\n                nullptr\n            };\n\n            auto lhs = MultiplayerSession::Create(env.XboxLiveContext(), &sessionRef, &initArgs);\n            XblMultiplayerSessionSetClosed(lhs.Handle(), true);\n            XblMultiplayerSessionSetLocked(lhs.Handle(), true);\n            VERIFY_SUCCEEDED(XblMultiplayerSessionSetCustomPropertyJson(lhs.Handle(), \"hello\", \"\\\"goodbye\\\"\"));\n            VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(lhs.Handle(), nullptr, false, false));\n\n            auto rhs = MultiplayerSession::Get(env.XboxLiveContext());\n\n            XblMultiplayerSessionChangeTypes expectedChanges\n            {\n                XblMultiplayerSessionChangeTypes::MemberListChange |\n                XblMultiplayerSessionChangeTypes::HostDeviceTokenChange |\n                XblMultiplayerSessionChangeTypes::InitializationStateChange |\n                XblMultiplayerSessionChangeTypes::MatchmakingStatusChange |\n                XblMultiplayerSessionChangeTypes::SessionJoinabilityChange |\n                XblMultiplayerSessionChangeTypes::CustomPropertyChange |\n                XblMultiplayerSessionChangeTypes::MemberStatusChange // TODO what should member's default status be on join?\n            };\n            auto changes = XblMultiplayerSessionCompare(rhs.Handle(), lhs.Handle());\n            VERIFY_IS_TRUE(changes == expectedChanges);\n        }\n\n        {\n            // Test MatchmakingStatusChange for different target session refs.\n            auto lhs = MultiplayerSession::Create(env.XboxLiveContext());\n            auto rhs = MultiplayerSession::Get(env.XboxLiveContext(), defaultSessionReference, testJson[\"MultiplayerResponseForComparingSessions\"]);\n\n            auto changes = XblMultiplayerSessionCompare(rhs.Handle(), lhs.Handle());\n            VERIFY_IS_TRUE(static_cast<XblMultiplayerSessionChangeTypes>(changes & XblMultiplayerSessionChangeTypes::MatchmakingStatusChange) == XblMultiplayerSessionChangeTypes::MatchmakingStatusChange);\n        }\n    }\n\n    // RAII wrapper for session changed RTA event handler\n    class SessionChangedHandler\n    {\n    public:\n        SessionChangedHandler(\n            XblContextHandle context,\n            std::function<void(const XblMultiplayerSessionChangeEventArgs&)> handler\n        ) noexcept\n            : m_handler{ std::move(handler) }\n        {\n            VERIFY_SUCCEEDED(XblContextDuplicateHandle(context, &m_context));\n            m_token = XblMultiplayerAddSessionChangedHandler(m_context,\n                [](void* context, XblMultiplayerSessionChangeEventArgs args)\n                {\n                    auto pThis{ static_cast<SessionChangedHandler*>(context) };\n                    pThis->m_handler(args);\n                }, this\n            );\n        }\n\n        ~SessionChangedHandler() noexcept\n        {\n            XblMultiplayerRemoveSessionChangedHandler(m_context, m_token);\n            XblContextCloseHandle(m_context);\n        }\n\n    private:\n        XblFunctionContext m_token{ 0 };\n        XblContextHandle m_context{ nullptr };\n        std::function<void(const XblMultiplayerSessionChangeEventArgs&)> m_handler;\n    };\n\n    // RAII wrapper for subscription lost handler\n    class SubscriptionLostHandler\n    {\n    public:\n        SubscriptionLostHandler(\n            XblContextHandle context,\n            std::function<void()> handler\n        ) noexcept\n            : m_handler{ std::move(handler) }\n        {\n            VERIFY_SUCCEEDED(XblContextDuplicateHandle(context, &m_context));\n            m_token = XblMultiplayerAddSubscriptionLostHandler(m_context,\n                [](void* context)\n                {\n                    auto pThis{ static_cast<SubscriptionLostHandler*>(context) };\n                    pThis->m_handler();\n                }, this\n            );\n        }\n\n        ~SubscriptionLostHandler() noexcept\n        {\n            XblMultiplayerRemoveSubscriptionLostHandler(m_context, m_token);\n            XblContextCloseHandle(m_context);\n        }\n\n    private:\n        XblFunctionContext m_token{ 0 };\n        XblContextHandle m_context{ nullptr };\n        std::function<void()> m_handler;\n    };\n\n    DEFINE_TEST_CASE(TestRTAMultiplayer)\n    {\n        TEST_LOG(L\"Test starting: TestRTAMultiplayer\");\n\n        MPTestEnv env{};\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        \n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            if (uri == MPSD_RTA_URI)\n            {\n                mockRtaService.CompleteSubscribeHandshake(n, JsonUtils::SerializeJson(testJson[\"rtaConnectionIdJson\"]).data());\n            }\n        });\n\n        VERIFY_SUCCEEDED(XblMultiplayerSetSubscriptionsEnabled(env.XboxLiveContext(), true));\n\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n        // Subscriptions are not relevant if we are not in the session\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false));\n\n        HttpMock mock{ \"PUT\", MPSD_URI };\n        mock.SetResponseBody(defaultSessionJson);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerWriteSessionAsync(\n            env.XboxLiveContext(),\n            session.Handle(),\n            XblMultiplayerSessionWriteMode::CreateNew,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblMultiplayerWriteSessionResult(&async, nullptr));\n\n        Event sessionChanged{};\n        const JsonValue& rtaUpdateJson{ testJson[\"rtaSessionUpdateJson\"] };\n\n        SessionChangedHandler sessionChangedHandler{ env.XboxLiveContext(),\n            [&](const XblMultiplayerSessionChangeEventArgs& args)\n        {\n            const auto& tap{ rtaUpdateJson[\"shoulderTaps\"].GetArray()[0] };\n            auto resourceSplit{ utils::string_split_internal(tap[\"resource\"].GetString(), '~') };\n\n            VERIFY_ARE_EQUAL_STR(resourceSplit[0], args.SessionReference.Scid);\n            VERIFY_ARE_EQUAL_STR(resourceSplit[1], args.SessionReference.SessionTemplateName);\n            VERIFY_ARE_EQUAL_STR(resourceSplit[2], args.SessionReference.SessionName);\n            VERIFY_ARE_EQUAL_STR(tap[\"branch\"].GetString(), args.Branch);\n            VERIFY_ARE_EQUAL_UINT(tap[\"changeNumber\"].GetUint64(), args.ChangeNumber);\n\n            sessionChanged.Set();\n        }\n        };\n\n        Event subscriptionLost{};\n        SubscriptionLostHandler subLostHandler{ env.XboxLiveContext(), [&] { subscriptionLost.Set(); } };\n\n        // Send an rta event and wait until our session changed handler is invoked\n        mockRtaService.RaiseEvent(MPSD_RTA_URI, JsonUtils::SerializeJson(rtaUpdateJson).data());\n        sessionChanged.Wait();\n\n        // Disconnect socket and wait until our subscription lost handler is invoked\n        MockWebsocket::SetConnectHandler([] { return WebsocketResult{ E_FAIL }; });\n        mockRtaService.DisconnectClient(env.XboxLiveContext()->Xuid());\n        subscriptionLost.Wait();\n    }\n\n    DEFINE_TEST_CASE(TestRTADisableMultiplayerSubscriptions)\n    {\n        TEST_LOG(L\"Test starting: TestRTADisableMultiplayerSubscriptions\");\n\n        MPTestEnv env{};\n\n        // Auto confirm subscriptions\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            if (uri == MPSD_RTA_URI)\n            {\n                mockRtaService.CompleteSubscribeHandshake(n, JsonUtils::SerializeJson(testJson[\"rtaConnectionIdJson\"]).data());\n            }\n        });\n\n        VERIFY_SUCCEEDED(XblMultiplayerSetSubscriptionsEnabled(env.XboxLiveContext(), true));\n\n        Event subLost;\n        SubscriptionLostHandler handler{\n            env.XboxLiveContext(),\n            [&] { subLost.Set(); }\n        };\n\n        VERIFY_SUCCEEDED(XblMultiplayerSetSubscriptionsEnabled(env.XboxLiveContext(), false));\n        subLost.Wait();\n    }\n\n    DEFINE_TEST_CASE(TestMultiplayerSubscribeChangeTypes)\n    {\n        TEST_LOG(L\"Test starting: TestMultiplayerSubscribeChangeTypes\");\n\n        MPTestEnv env{};\n\n        auto session = MultiplayerSession::Create(env.XboxLiveContext());\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false));\n\n        VERIFY_IS_TRUE(XblMultiplayerSessionSubscribedChangeTypes(session.Handle()) == XblMultiplayerSessionChangeTypes::None);\n\n        XblMultiplayerSessionChangeTypes changeTypes\n        {\n            XblMultiplayerSessionChangeTypes::CustomPropertyChange |\n            XblMultiplayerSessionChangeTypes::HostDeviceTokenChange |\n            XblMultiplayerSessionChangeTypes::InitializationStateChange |\n            XblMultiplayerSessionChangeTypes::MatchmakingStatusChange |\n            XblMultiplayerSessionChangeTypes::MemberCustomPropertyChange |\n            XblMultiplayerSessionChangeTypes::MemberListChange |\n            XblMultiplayerSessionChangeTypes::MemberStatusChange |\n            XblMultiplayerSessionChangeTypes::SessionJoinabilityChange\n        };\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionSetSessionChangeSubscription(session.Handle(), changeTypes));\n        VERIFY_IS_TRUE(XblMultiplayerSessionSubscribedChangeTypes(session.Handle()) == changeTypes);\n\n        auto mock = std::make_shared<HttpMock>( \"PUT\", MPSD_URI );\n        mock->SetResponseBody(defaultSessionJson);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* /*mock*/, xsapi_internal_string /*uri*/, xsapi_internal_string body)\n            {\n                // Skip verification of the subId since its a random GUID\n                JsonDocument bodyJson;\n                bodyJson.Parse(body.data());\n                if (bodyJson.HasMember(\"members\") &&\n                    bodyJson[\"members\"].HasMember(\"me\") &&\n                    bodyJson[\"members\"][\"me\"].HasMember(\"properties\") &&\n                    bodyJson[\"members\"][\"me\"][\"properties\"].HasMember(\"system\") &&\n                    bodyJson[\"members\"][\"me\"][\"properties\"][\"system\"].HasMember(\"subscription\"))\n                {\n                    bodyJson[\"members\"][\"me\"][\"properties\"][\"system\"][\"subscription\"].EraseMember(\"id\");\n                }\n\n                requestWellFormed = (testJson[\"setSessionChangeTypesJson\"] == bodyJson);\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblMultiplayerWriteSessionAsync(\n            env.XboxLiveContext(),\n            session.Handle(),\n            XblMultiplayerSessionWriteMode::UpdateOrCreateNew,\n            &async)\n        );\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblMultiplayerWriteSessionResult(&async, nullptr));\n    }\n\n    DEFINE_TEST_CASE(Test204Response)\n    {\n        TEST_LOG(L\"Test starting: Test204Response\");\n\n        MPTestEnv env{};\n\n        HttpMock mock{ \"\", MPSD_URI, 204 };\n        mock.SetResponseBody(JsonValue{ rapidjson::kObjectType });\n\n        {\n            auto session = MultiplayerSession::Create(env.XboxLiveContext());\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerWriteSessionAsync(\n                env.XboxLiveContext(),\n                session.Handle(),\n                XblMultiplayerSessionWriteMode::CreateNew,\n                &async\n            ));\n\n            auto hr = XAsyncGetStatus(&async, true);\n            VERIFY_ARE_EQUAL(S_OK, hr);\n            hr = XblMultiplayerWriteSessionResult(&async, nullptr);\n            VERIFY_ARE_EQUAL(S_OK, hr);\n        }\n\n        {\n            XblMultiplayerSessionReference ref\n            {\n                \"8d050174-412b-4d51-a29b-d55a34edfdb7\",\n                \"integration\",\n                \"19de0095d8bb41048f19edbbb6bc6b04\"\n            };\n\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblMultiplayerGetSessionAsync(env.XboxLiveContext(), &ref, &async));\n\n            auto hr = XAsyncGetStatus(&async, true);\n            VERIFY_ARE_EQUAL(__HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND), hr);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestMultiplayerInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestMultiplayerInvalidArgs\");\n\n#pragma warning(push)\n#pragma warning(disable : 6387)\n        MPTestEnv env{};\n        auto context{ env.XboxLiveContext() };\n        XAsyncBlock async{};\n        auto dummySession{ std::make_shared<XblMultiplayerSession>(context->Xuid()) };\n\n        // Create a session with an invalid SessionRef\n        // TODO there is no validation here right now\n        // TODO should XblMutliplayerSessionCreateHandle return an HR\n        //XblMultiplayerSessionReference ref{};\n        //XblMultiplayerSessionCreateHandle(context->Xuid(), &ref, nullptr);\n        //VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n\n        // Write null session\n        VERIFY_INVALIDARG(XblMultiplayerWriteSessionAsync(context, nullptr, XblMultiplayerSessionWriteMode::UpdateOrCreateNew, &async));\n\n        // Get session with null sessionRef\n        VERIFY_INVALIDARG(XblMultiplayerGetSessionAsync(context, nullptr, &async));\n\n        // Query sessions with invalid query params\n        XblMultiplayerSessionQuery query\n        {\n            MOCK_SCID,  // scid\n            100,    // maxItems\n            false,  // includePrivateSessions\n            false,  // includeReservations\n            false,  // includeInactiveSessions\n            nullptr,    // xuidFilters\n            0,  // xuidFiltersCount\n            \"keyword\",    // keywordFilter\n            \"bar\",  // sessionTemplateNameFilter\n            XblMultiplayerSessionVisibility::Unknown, // visibilityFilter (invalid, should never be Unknown)\n            0 // contractVersionFilter\n        };\n\n        VERIFY_INVALIDARG(XblMultiplayerQuerySessionsAsync(context, &query, &async));\n\n        query.VisibilityFilter = XblMultiplayerSessionVisibility::Any;\n        query.KeywordFilter = nullptr; // Must specify either Xuid filters or Keyword filters\n        VERIFY_INVALIDARG(XblMultiplayerQuerySessionsAsync(context, &query, &async));\n\n        query.IncludeReservations = true; // Must specify Xuid filter to use this\n        VERIFY_INVALIDARG(XblMultiplayerQuerySessionsAsync(context, &query, &async));\n\n        query.IncludeReservations = false;\n        query.IncludeInactiveSessions = true; // Must specify Xuid filter to use this\n        VERIFY_INVALIDARG(XblMultiplayerQuerySessionsAsync(context, &query, &async));\n\n        // Write by handle with null session\n        VERIFY_INVALIDARG(XblMultiplayerWriteSessionByHandleAsync(\n            context,\n            nullptr,\n            XblMultiplayerSessionWriteMode::CreateNew,\n            \"handle\",\n            &async\n        ));\n\n        // Write by handle with null handle\n        VERIFY_INVALIDARG(XblMultiplayerWriteSessionByHandleAsync(\n            context,\n            dummySession.get(),\n            XblMultiplayerSessionWriteMode::CreateNew,\n            nullptr,\n            &async\n        ));\n\n        // Get session with null handle\n        VERIFY_INVALIDARG(XblMultiplayerGetSessionByHandleAsync(context, nullptr, &async));\n\n        const uint64_t xuids[] = { 1234 };\n\n        // Get activities with null scid\n        VERIFY_INVALIDARG(XblMultiplayerGetActivitiesForUsersAsync(context, nullptr, xuids, _countof(xuids), &async));\n        VERIFY_INVALIDARG(XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(context, nullptr, xuids, _countof(xuids), &async));\n\n        // Get activities with null xuids array\n        VERIFY_INVALIDARG(XblMultiplayerGetActivitiesForUsersAsync(context, MOCK_SCID, nullptr, _countof(xuids), &async));\n        VERIFY_INVALIDARG(XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(context, MOCK_SCID, nullptr, _countof(xuids), &async));\n\n        // Get activities with empty xuids array\n        VERIFY_INVALIDARG(XblMultiplayerGetActivitiesForUsersAsync(context, MOCK_SCID, xuids, 0, &async));\n        VERIFY_INVALIDARG(XblMultiplayerGetActivitiesWithPropertiesForUsersAsync(context, MOCK_SCID, xuids, 0, &async));\n\n        // Set activity with null sessionRef\n        VERIFY_INVALIDARG(XblMultiplayerSetActivityAsync(context, nullptr, &async));\n\n        // Clear activity with null scid\n        VERIFY_INVALIDARG(XblMultiplayerClearActivityAsync(context, nullptr, &async));\n\n        XblMultiplayerSessionReference ref\n        {\n            \"0001\",\n            \"testTemplate\",\n            \"testSessionName\"\n        };\n\n        // Send invites with null xuids array\n        VERIFY_INVALIDARG(XblMultiplayerSendInvitesAsync(context, &ref, nullptr, _countof(xuids), MOCK_TITLEID, nullptr, nullptr, &async));\n\n        // Send invites with empty xuids array\n        VERIFY_INVALIDARG(XblMultiplayerSendInvitesAsync(context, &ref, xuids, 0, MOCK_TITLEID, nullptr, nullptr, &async));\n\n        // Send invites with null sessionRef\n        VERIFY_INVALIDARG(XblMultiplayerSendInvitesAsync(context, nullptr, xuids, _countof(xuids), MOCK_TITLEID, nullptr, nullptr, &async));\n\n        VERIFY_SUCCEEDED(XblMultiplayerSetSubscriptionsEnabled(context, true));\n\n        // Setting constants on an pre-existing session\n        auto session{ MultiplayerSession::Get(context) };\n\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionConstantsSetTimeouts(session.Handle(), 0, 0, 0, 0)\n        );\n\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionConstantsSetQosConnectivityMetrics(session.Handle(), true, true, true, true)\n        );\n\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionConstantsSetMemberInitialization(session.Handle(), XblMultiplayerMemberInitialization{})\n        );\n\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionConstantsSetPeerToPeerRequirements(session.Handle(), XblMultiplayerPeerToPeerRequirements{})\n        );\n\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionConstantsSetPeerToHostRequirements(session.Handle(), XblMultiplayerPeerToHostRequirements{})\n        );\n\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionConstantsSetCapabilities(session.Handle(), XblMultiplayerSessionCapabilities{})\n        );\n\n        VERIFY_SUCCEEDED(XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false));\n        // Double join a session\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionJoin(session.Handle(), nullptr, false, false)\n        );\n        // Leave a session without being joined\n        // TODO should this really be an error? even though the join isn't written, this feels like it should be valid\n        VERIFY_ARE_EQUAL(\n            E_UNEXPECTED,\n            XblMultiplayerSessionLeave(session.Handle())\n        );\n#pragma warning(pop)\n    }\n\n    DEFINE_TEST_CASE(TestTournamentsDeprecated)\n    {\n        TEST_LOG(L\"Test starting: TestTournamentsDeprecated\");\n\n        XBL_WARNING_PUSH;\n        XBL_WARNING_DISABLE_DEPRECATED;\n        XblTournamentReference xbltourref{};\n        memcpy(xbltourref.Scid, \"1234\", XBL_SCID_LENGTH);\n\n        HRESULT hr = XblMultiplayerSessionConstantsSetArbitrationTimeouts(nullptr, 0, 0);\n        VERIFY_ARE_EQUAL(hr, E_NOTIMPL);\n\n        auto result = XblMultiplayerSessionArbitrationServer(nullptr);\n        VERIFY_ARE_EQUAL(result, nullptr);\n\n        auto result2 = XblMultiplayerSessionTournamentsServer(nullptr);\n        VERIFY_ARE_EQUAL(result2, nullptr);\n\n        auto result3 = XblMultiplayerSessionArbitrationStatus(nullptr);\n        VERIFY_IS_TRUE(result3 == XblTournamentArbitrationStatus::Incomplete);\n\n        hr = XblMultiplayerEventArgsTournamentRegistrationStateChanged(nullptr, nullptr, nullptr);\n        VERIFY_ARE_EQUAL(hr, E_NOTIMPL);\n\n        hr = XblMultiplayerEventArgsTournamentGameSessionReady(nullptr, nullptr);\n        VERIFY_ARE_EQUAL(hr, E_NOTIMPL);\n\n        auto result4 = XblMultiplayerManagerLobbySessionLastTournamentTeamResult();\n        VERIFY_ARE_EQUAL(result4, nullptr);\n\n        XblMultiplayerSessionCapabilities cap{};\n        cap.Team = true;\n\n        XblMultiplayerTournamentsServer server{};\n        XBL_WARNING_POP;\n    }\n};\n\nconst JsonDocument MultiplayerTests::testJson{ GetTestResponses(\"TestResponses\\\\Multiplayer.json\") };\nconst JsonValue& MultiplayerTests::defaultSessionJson{ testJson[\"defaultSessionDocument\"] };\n\nconst XblMultiplayerSessionReference MultiplayerTests::defaultSessionReference\n{\n    \"8d050174-412b-4d51-a29b-d55a34edfdb7\",\n    \"integration\",\n    \"19de0095d8bb41048f19edbbb6bc6b04\"\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/PeoplehubTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"peoplehub_service.h\"\n\nusing namespace xbox::services;\nusing namespace xbox::services::social::manager;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char peoplehubResponse[] =\nR\"(\n{\n    \"people\": [\n        {\n            \"xuid\": \"2814664990767463\",\n            \"isFavorite\": true,\n            \"isFollowingCaller\": true,\n            \"isFollowedByCaller\": true,\n            \"isIdentityShared\": false,\n            \"displayName\": \"2 Dev 123410299\",\n            \"realName\": \"Dev Account\",\n            \"displayPicRaw\": \"http://images-eds.xboxlive.com/image?url=z951ykn43p4FqWbbFvR2Ec.8vbDhj8G2Xe7JngaTToBrrCmIEEXHC9UNrdJ6P7KIwuPiuIs6TLDV4WsQAGzSwnTHQB9h_UfPa19pe4OAgFTWAPsXVneopydpL6qncU1N&format=png\",\n            \"useAvatar\": true,\n            \"gamertag\": \"2 Dev 123410299\",\n            \"modernGamertag\": \"2 Dev 123410299\",\n            \"modernGamertagSuffix\": \"\",\n            \"uniqueModernGamertag\": \"2 Dev 123410299\",\n            \"gamerScore\": \"0\",\n            \"xboxOneRep\": \"GoodPlayer\",\n            \"presenceState\": \"Offline\",\n            \"presenceText\": \"Offline\",\n            \"presenceDevices\": null,\n            \"isBroadcasting\": false,\n            \"suggestion\": null,\n            \"titleHistory\": null,\n            \"multiplayerSummary\": {\n                \"InMultiplayerSession\": 0,\n                \"InParty\": 0\n            },\n            \"recentPlayer\": null,\n            \"follower\": null,\n            \"preferredColor\": {\n                \"primaryColor\": \"107c10\",\n                \"secondaryColor\": \"05d21e\",\n                \"tertiaryColor\": \"299c10\"\n            },\n            \"titlePresence\": null,\n            \"titleSummaries\": null,\n            \"presenceTitleIds\": null,\n            \"detail\": null,\n            \"presenceDetails\": [{\n                \"IsBroadcasting\": false,\n                \"Device\": \"PC\",\n                \"PresenceText\": \"Home\",\n                \"State\": \"Active\",\n                \"TitleId\": \"1234\"\n            }]\n        },\n        {\n            \"xuid\": \"2814654081790887\",\n            \"isFavorite\": true,\n            \"isFollowingCaller\": false,\n            \"isFollowedByCaller\": true,\n            \"isIdentityShared\": false,\n            \"displayName\": \"2 Dev 554865546\",\n            \"realName\": \"\",\n            \"displayPicRaw\": \"http://images-eds.xboxlive.com/image?url=z951ykn43p4FqWbbFvR2Ec.8vbDhj8G2Xe7JngaTToBrrCmIEEXHC9UNrdJ6P7KI6TRSO7kB1LAmJSmUVW5wJqn2n6xd9r5UHGMgD0o0KoOwHN61vlgC862huSRkTjhm&background=0xababab&mode=Padding&format=png\",\n            \"useAvatar\": true,\n            \"gamertag\": \"2 Dev 554865546\",\n            \"modernGamertag\": \"2 Dev 554865546\",\n            \"modernGamertagSuffix\": \"\",\n            \"uniqueModernGamertag\": \"2 Dev 554865546\",\n            \"gamerScore\": \"0\",\n            \"xboxOneRep\": \"GoodPlayer\",\n            \"presenceState\": \"Offline\",\n            \"presenceText\": \"Offline\",\n            \"presenceDevices\": null,\n            \"isBroadcasting\": false,\n            \"suggestion\": null,\n            \"titleHistory\": null,\n            \"multiplayerSummary\": {\n                \"InMultiplayerSession\": 0,\n                \"InParty\": 0\n            },\n            \"recentPlayer\": null,\n            \"follower\": null,\n            \"preferredColor\": {\n                \"primaryColor\": \"107c10\",\n                \"secondaryColor\": \"05d21e\",\n                \"tertiaryColor\": \"299c10\"\n            },\n            \"titlePresence\": null,\n            \"titleSummaries\": null,\n            \"presenceTitleIds\": null,\n            \"detail\": null,\n            \"presenceDetails\": [{\n                \"IsBroadcasting\": false,\n                \"Device\": \"PC\",\n                \"PresenceText\": \"Home\",\n                \"State\": \"Active\",\n                \"TitleId\": \"1234\"\n            }]\n        },\n        {\n            \"xuid\": \"2814613569642996\",\n            \"isFavorite\": false,\n            \"isFollowingCaller\": false,\n            \"isFollowedByCaller\": true,\n            \"isIdentityShared\": false,\n            \"displayName\": \"2 Dev 417471033\",\n            \"realName\": \"\",\n            \"displayPicRaw\": \"http://images-eds.xboxlive.com/image?url=z951ykn43p4FqWbbFvR2Ec.8vbDhj8G2Xe7JngaTToBrrCmIEEXHC9UNrdJ6P7KI6TRSO7kB1LAmJSmUVW5wJqn2n6xd9r5UHGMgD0o0KoOwHN61vlgC862huSRkTjhm&background=0xababab&mode=Padding&format=png\",\n            \"useAvatar\": true,\n            \"gamertag\": \"2 Dev 417471033\",\n            \"modernGamertag\": \"2 Dev 417471033\",\n            \"modernGamertagSuffix\": \"\",\n            \"uniqueModernGamertag\": \"2 Dev 417471033\",\n            \"gamerScore\": \"0\",\n            \"xboxOneRep\": \"InDanger\",\n            \"presenceState\": \"Offline\",\n            \"presenceText\": \"Offline\",\n            \"presenceDevices\": null,\n            \"isBroadcasting\": false,\n            \"suggestion\": null,\n            \"titleHistory\": null,\n            \"multiplayerSummary\": {\n                \"InMultiplayerSession\": 0,\n                \"InParty\": 0\n            },\n            \"recentPlayer\": null,\n            \"follower\": null,\n            \"preferredColor\": {\n                \"primaryColor\": \"107c10\",\n                \"secondaryColor\": \"05d21e\",\n                \"tertiaryColor\": \"299c10\"\n            },\n            \"titlePresence\": null,\n            \"titleSummaries\": null,\n            \"presenceTitleIds\": null,\n            \"detail\": null,\n            \"presenceDetails\": [{\n                \"IsBroadcasting\": false,\n                \"Device\": \"PC\",\n                \"PresenceText\": \"Home\",\n                \"State\": \"Active\",\n                \"TitleId\": \"1234\"\n            }]\n        },\n        {\n            \"xuid\": \"2814671404555632\",\n            \"isFavorite\": false,\n            \"isFollowingCaller\": true,\n            \"isFollowedByCaller\": true,\n            \"isIdentityShared\": false,\n            \"displayName\": \"2 Dev 766909125\",\n            \"realName\": \"\",\n            \"displayPicRaw\": \"http://images-eds.xboxlive.com/image?url=z951ykn43p4FqWbbFvR2Ec.8vbDhj8G2Xe7JngaTToBrrCmIEEXHC9UNrdJ6P7KI6TRSO7kB1LAmJSmUVW5wJqn2n6xd9r5UHGMgD0o0KoOwHN61vlgC862huSRkTjhm&background=0xababab&mode=Padding&format=png\",\n            \"useAvatar\": true,\n            \"gamertag\": \"2 Dev 766909125\",\n            \"modernGamertag\": \"2 Dev 766909125\",\n            \"modernGamertagSuffix\": \"\",\n            \"uniqueModernGamertag\": \"2 Dev 766909125\",\n            \"gamerScore\": \"0\",\n            \"xboxOneRep\": \"AvoidMe\",\n            \"presenceState\": \"Offline\",\n            \"presenceText\": \"Offline\",\n            \"presenceDevices\": null,\n            \"isBroadcasting\": false,\n            \"suggestion\": null,\n            \"titleHistory\": {\n                \"titleName\": \"Forza Horizon 2\",\n                \"titleId\": \"446059611\",\n                \"lastTimePlayed\": \"2015-01-26T22:54:54.6630000Z\",\n                \"lastTimePlayedText\": \"8 months ago\"\n            },\n            \"multiplayerSummary\": {\n                \"InMultiplayerSession\": 0,\n                \"InParty\": 0\n            },\n            \"recentPlayer\": null,\n            \"follower\": null,\n            \"preferredColor\": {\n                \"primaryColor\": \"107c10\",\n                \"secondaryColor\": \"05d21e\",\n                \"tertiaryColor\": \"299c10\"\n            },\n            \"titlePresence\": null,\n            \"titleSummaries\": null,\n            \"presenceTitleIds\": null,\n            \"detail\": null,\n            \"presenceDetails\": [{\n                \"IsBroadcasting\": false,\n                \"Device\": \"PC\",\n                \"PresenceText\": \"Home\",\n                \"State\": \"Active\",\n                \"TitleId\": \"1234\"\n            },{\n                \"IsBroadcasting\": false,\n                \"Device\": \"Xbox\",\n                \"PresenceText\": \"Home\",\n                \"State\": \"Active\",\n                \"TitleId\": \"1234\"\n            }]\n        }\n    ]\n})\";\n\nconst char peoplehubInvalid[] =\nR\"(\n{\n    \"people\": [\n        {\n        }\n    ]\n})\";\n\nDEFINE_TEST_CLASS(PeoplehubTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(PeoplehubTests);\n\n    struct PeoplehubTestEnvironment : public TestEnvironment\n    {\n        PeoplehubTestEnvironment() noexcept\n            : XboxLiveContext{ CreateMockXboxLiveContext() }\n        {\n            auto userResult = XboxLiveContext->User().Copy();\n            PeoplehubService = std::make_shared<xbox::services::social::manager::PeoplehubService>(\n                userResult.ExtractPayload(),\n                std::make_shared<XboxLiveContextSettings>(),\n                AppConfig::Instance()->TitleId()\n            );\n        }\n\n        std::shared_ptr<XblContext> XboxLiveContext;\n        std::shared_ptr<PeoplehubService> PeoplehubService;\n    };\n\n    static void VerifyPresenceRecord(const XblSocialManagerPresenceRecord & presenceRecord, JsonValue& response)\n    {\n        VERIFY_IS_TRUE(presenceRecord.presenceTitleRecordCount == response.Size());\n        for (uint32_t i = 0; i < response.Size(); ++i)\n        {\n            auto& jsonEntry = response[i];\n            auto& titleEntry = presenceRecord.presenceTitleRecords[i];\n\n            VERIFY_ARE_EQUAL(jsonEntry[\"IsBroadcasting\"].GetBool(), titleEntry.isBroadcasting);\n            VERIFY_IS_TRUE(xbox::services::presence::DeviceRecord::DeviceTypeFromString(jsonEntry[\"Device\"].GetString()) == static_cast<XblPresenceDeviceType>(titleEntry.deviceType));\n            auto state = jsonEntry[\"State\"].GetString();\n            auto presenceState = (utils::str_icmp(state, \"active\") == 0);\n            VERIFY_ARE_EQUAL(presenceState, titleEntry.isTitleActive);\n            VERIFY_IS_TRUE(utils::internal_string_to_uint32(jsonEntry[\"TitleId\"].GetString()) == titleEntry.titleId);\n            VERIFY_ARE_EQUAL_STR(jsonEntry[\"PresenceText\"].GetString(), titleEntry.presenceText);\n        }\n    }\n\n    static void VerifyTitleHistory(const XblTitleHistory& titleHistory, JsonValue& response)\n    {\n        if (response.IsNull())\n        {\n            VERIFY_IS_FALSE(titleHistory.hasUserPlayed);\n        }\n        else\n        {\n            if (response.HasMember(\"lastTimePlayed\") && response[\"lastTimePlayed\"].IsString())\n            {\n                time_t jsonTime;\n                JsonUtils::ExtractJsonTimeT(response, \"lastTimePlayed\", jsonTime);\n                VERIFY_ARE_EQUAL_UINT(titleHistory.lastTimeUserPlayed, jsonTime);\n            }\n\n            if (response.HasMember(\"lastTimePlayedText\") && response[\"lastTimePlayedText\"].IsString())\n            {\n                char jsonTimeStr[XBL_LAST_TIME_PLAYED_CHAR_SIZE];\n                JsonUtils::ExtractJsonStringToCharArray(response, \"lastTimePlayedText\", jsonTimeStr, XBL_LAST_TIME_PLAYED_CHAR_SIZE);\n                VERIFY_ARE_EQUAL_STR(titleHistory.lastTimeUserPlayedText, jsonTimeStr);\n            }\n        }\n    }\n\n    static void VerifyPreferredColor(const XblPreferredColor & preferredColor, JsonValue& response)\n    {\n        if (response.IsNull())\n        {\n            VERIFY_IS_TRUE(strlen(preferredColor.primaryColor) == 0);\n            VERIFY_IS_TRUE(strlen(preferredColor.secondaryColor) == 0);\n            VERIFY_IS_TRUE(strlen(preferredColor.tertiaryColor) == 0);\n        }\n        else\n        {\n            VERIFY_ARE_EQUAL_STR(preferredColor.primaryColor, response[\"primaryColor\"].GetString());\n            VERIFY_ARE_EQUAL_STR(preferredColor.secondaryColor, response[\"secondaryColor\"].GetString());\n            VERIFY_ARE_EQUAL_STR(preferredColor.tertiaryColor, response[\"tertiaryColor\"].GetString());\n        }\n    }\n\n    static void VerifyXboxSocialUser(const XblSocialManagerUser & xboxSocialUser, JsonValue& jsonUser)\n    {\n        VERIFY_ARE_EQUAL(xboxSocialUser.isFavorite, jsonUser[\"isFavorite\"].GetBool());\n        VERIFY_ARE_EQUAL(xboxSocialUser.isFollowingUser, jsonUser[\"isFollowingCaller\"].GetBool());\n        VERIFY_ARE_EQUAL(xboxSocialUser.isFollowedByCaller, jsonUser[\"isFollowedByCaller\"].GetBool());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.displayName, jsonUser[\"displayName\"].GetString());\n        std::cout << xboxSocialUser.realName << \" : \" << jsonUser[\"realName\"].GetString() << std::endl;\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.realName, jsonUser[\"realName\"].GetString());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.displayPicUrlRaw, jsonUser[\"displayPicRaw\"].GetString());\n        VERIFY_ARE_EQUAL(xboxSocialUser.useAvatar, jsonUser[\"useAvatar\"].GetBool());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.gamertag, jsonUser[\"gamertag\"].GetString());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.modernGamertag, jsonUser[\"modernGamertag\"].GetString());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.modernGamertagSuffix, jsonUser[\"modernGamertagSuffix\"].GetString());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.uniqueModernGamertag, jsonUser[\"uniqueModernGamertag\"].GetString());\n        VERIFY_ARE_EQUAL_STR(xboxSocialUser.gamerscore, jsonUser[\"gamerScore\"].GetString());\n        VerifyTitleHistory(xboxSocialUser.titleHistory, jsonUser[\"titleHistory\"]);\n        VerifyPreferredColor(xboxSocialUser.preferredColor, jsonUser[\"preferredColor\"]);\n        VerifyPresenceRecord(xboxSocialUser.presenceRecord, jsonUser[\"presenceDetails\"]);\n    }\n\n    DEFINE_TEST_CASE(TestGetSocialUsers)\n    {\n        TEST_LOG(L\"Test starting: TestGetSocialUsers\");\n\n        PeoplehubTestEnvironment env{};\n\n        JsonDocument jsonResponse;\n        jsonResponse.Parse(peoplehubResponse);\n\n        xsapi_internal_stringstream url;\n        url << \"https://peoplehub.xboxlive.com/users/xuid(\" << env.XboxLiveContext->Xuid() << \")/people/batch/decoration/presenceDetail,preferredcolor\";\n\n        auto peoplehubMock = std::make_shared<HttpMock>(\n            \"POST\",\n            url.str(),\n            200,\n            jsonResponse\n            );\n\n        Event callComplete;\n        Result<Vector<XblSocialManagerUser>> result;\n\n        env.PeoplehubService->GetSocialUsers(env.XboxLiveContext->Xuid(), XblSocialManagerExtraDetailLevel::PreferredColorLevel, { 1 }, {\n            [&] (Result<Vector<XblSocialManagerUser>> temp)\n            {\n                result = temp;\n                callComplete.Set();\n            }\n            });\n\n        callComplete.Wait();\n\n        VERIFY_SUCCEEDED(result.Hresult());\n        JsonValue& userGroupArr = jsonResponse[\"people\"];\n        VERIFY_ARE_EQUAL(result.Payload().size(), userGroupArr.Size());\n\n        uint64_t counter{ 0 };\n        for (auto& user : result.Payload())\n        {\n            VerifyXboxSocialUser(user, userGroupArr[counter++]);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetSocialGraph)\n    {\n        TEST_LOG(L\"Test starting: TestGetSocialGraph\");\n\n        PeoplehubTestEnvironment env{};\n\n        JsonDocument jsonResponse;\n        jsonResponse.Parse(peoplehubResponse);\n\n        xsapi_internal_stringstream url;\n        url << \"https://peoplehub.xboxlive.com/users/xuid(\" << env.XboxLiveContext->Xuid() << \")/people/social/decoration/presenceDetail\";\n\n        auto peoplehubMock = std::make_shared<HttpMock>(\n            \"GET\",\n            url.str(),\n            200,\n            jsonResponse\n            );\n\n        Event callComplete;\n        Result<Vector<XblSocialManagerUser>> result;\n\n        env.PeoplehubService->GetSocialGraph(env.XboxLiveContext->Xuid(), XblSocialManagerExtraDetailLevel::NoExtraDetail, {\n            [&] (Result<Vector<XblSocialManagerUser>> temp)\n            {\n                result = temp;\n                callComplete.Set();\n            }\n            });\n\n        callComplete.Wait();\n\n        VERIFY_SUCCEEDED(result.Hresult());\n        JsonValue& userGroupArr = jsonResponse[\"people\"];\n        VERIFY_ARE_EQUAL(result.Payload().size(), userGroupArr.Size());\n\n        uint64_t counter{ 0 };\n        for (auto& user : result.Payload())\n        {\n            VerifyXboxSocialUser(user, userGroupArr[counter++]);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestInvalidResponse)\n    {\n        TEST_LOG(L\"Test starting: TestInvalidResponse\");\n\n        PeoplehubTestEnvironment env{};\n\n        JsonDocument peoplehubInvalidJson;\n        peoplehubInvalidJson.Parse(peoplehubInvalid);\n        auto peoplehubMock = std::make_shared<HttpMock>(\n            \"\",\n            \"https://peoplehub.xboxlive.com\",\n            200,\n            peoplehubInvalidJson\n            );\n\n        Event callComplete;\n        Result<Vector<XblSocialManagerUser>> result;\n\n        env.PeoplehubService->GetSocialGraph(env.XboxLiveContext->Xuid(), XblSocialManagerExtraDetailLevel::PreferredColorLevel, {\n            [&] (Result<Vector<XblSocialManagerUser>> temp)\n            {\n                result = temp;\n                callComplete.Set();\n            }\n            });\n\n        callComplete.Wait();\n        VERIFY_FAILED(result.Hresult());\n        VERIFY_IS_TRUE(result.Payload().empty());\n    }\n\n    DEFINE_TEST_CASE(TestPartialTitleHistory)\n    {\n        TEST_LOG(L\"Test starting: TestPartialTitleHistory\");\n\n        // In some cases PeopleHub service returns a TitleHistory object that isn't fully populated. By design we should\n        // deserialize the provided fields and ignore those that are \"null\"\n\n        PeoplehubTestEnvironment env{};\n\n        JsonDocument jsonResponse;\n        jsonResponse.Parse(peoplehubResponse);\n\n        JsonValue titleHistory{ rapidjson::kObjectType };\n        titleHistory.AddMember(\"lastTimePlayed\", JsonValue{ rapidjson::kNullType }, jsonResponse.GetAllocator());\n        jsonResponse[\"people\"][0][\"titleHistory\"] = titleHistory.Move();\n\n        HttpMock peopleHubMock{ \"GET\", \"https://peoplehub.xboxlive.com/\", 200, jsonResponse };\n\n        Event callComplete;\n        Result<Vector<XblSocialManagerUser>> result;\n\n        env.PeoplehubService->GetSocialGraph(env.XboxLiveContext->Xuid(), XblSocialManagerExtraDetailLevel::NoExtraDetail, {\n            [&](Result<Vector<XblSocialManagerUser>> temp)\n            {\n                result = temp;\n                callComplete.Set();\n            }\n            });\n\n        callComplete.Wait();\n\n        VERIFY_SUCCEEDED(result.Hresult());\n        JsonValue& userGroupArr = jsonResponse[\"people\"];\n        VERIFY_ARE_EQUAL(result.Payload().size(), userGroupArr.Size());\n\n        uint64_t counter{ 0 };\n        for (auto& user : result.Payload())\n        {\n            VerifyXboxSocialUser(user, userGroupArr[counter++]);\n        }\n\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/PresenceTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\n#pragma warning(disable:4996)\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char* titlePresenceEndedResponse = \"\\\"Ended\\\"\";\nconst char* devicePresenceResponse = \"\\\"MoLive:false\\\"\";\n\nconst char* richPresenceResponse = R\"(\n{\n    \"devicetype\": \"WindowsOneCore\",\n    \"titleid\": 85494077,\n    \"string1\": \"Microsoft Solitaire Collection\",\n    \"string2\": \"Menus\"\n}\n)\";\n\nconst char* setPresenceRequest = R\"(\n{\n    \"state\": \"active\",\n    \"activity\": {\n        \"richPresence\": {\n            \"scid\": \"12345675467\",\n            \"id\": \"20\"\n        }\n    }\n}\n)\";\n\nconst char* getPresenceForMultipleUsersRequest = R\"(\n{\n    \"users\": [\n        \"12345\",\n        \"56789\"\n    ],\n    \"onlineOnly\": false,\n    \"broadcastingOnly\": false\n}\n)\";\n\nconst char* getPresenceForMultipleUsersOverloadRequest= R\"(\n{\n    \"users\": [\n        \"12345\",\n        \"56789\"\n    ],\n    \"deviceTypes\": [\n        \"PC\",\n        \"MoLive\"\n    ],\n    \"titles\": [\n        \"0\",\n        \"1\"\n    ],\n    \"level\": \"all\",\n    \"onlineOnly\": true,\n    \"broadcastingOnly\": true\n}\n)\";\n\nconst char* getPresenceForSocialGroupOverloadRequest = R\"(\n{\n    \"group\": \"testGroup\",\n    \"groupXuid\": \"12345\",\n    \"deviceTypes\": [\n        \"PC\",\n        \"MoLive\"\n    ],\n    \"titles\": [\n        \"0\",\n        \"1\"\n    ],\n    \"level\": \"all\",\n    \"onlineOnly\": true,\n    \"broadcastingOnly\": false\n}\n)\";\n\nconst char* defaultPresenceResponse = R\"(\n{\n    \"xuid\": \"2814671404555632\",\n    \"state\": \"Online\",\n    \"devices\": [\n        {\n            \"type\": \"PC\",\n            \"titles\": [\n                {\n                    \"id\": \"1563044810\",\n                    \"name\": \"DefaultTitle\",\n                    \"placement\": \"Full\",\n                    \"state\": \"Active\",\n                    \"lastModified\": \"2015-01-21T23:19:21Z\",\n                    \"activity\": {\n                        \"richPresence\": \"yes\",\n                        \"broadcast\": {\n                            \"id\": \"12345\",\n                            \"session\": \"test0\",\n                            \"provider\": \"twitch\",\n                            \"viewers\": 10,\n                            \"started\": \"2013-02-01T16:00:00Z\"\n                        }\n                    }\n                }\n            ]\n        }\n    ]\n}\n)\";\n\nconst char* defaultMultiplePresenceResponse = R\"(\n[\n    {\n        \"xuid\": \"12345\",\n        \"state\": \"Online\",\n        \"devices\": [\n            {\n                \"type\": \"XboxOne\",\n                \"titles\": [\n                    {\n                        \"id\": \"99467\",\n                        \"name\": \"awesomeGame\",\n                        \"lastModified\": \"2013-01-31T16:00:00Z\",\n                        \"state\": \"active\",\n                        \"placement\": \"Full\",\n                        \"activity\": {\n                            \"richPresence\": \"yes\",\n                            \"broadcast\": {\n                                \"id\": \"12345\",\n                                \"session\": \"test0\",\n                                \"provider\": \"twitch\",\n                                \"viewers\": 10,\n                                \"started\": \"2013-01-31T16:00:00Z\"\n                            }\n                        }\n                    }\n                ]\n            }\n        ]\n    },\n    {\n        \"xuid\": \"56789\",\n        \"state\": \"Online\",\n        \"devices\": [\n            {\n                \"type\": \"PC\",\n                \"titles\": [\n                    {\n                        \"id\": \"99467\",\n                        \"name\": \"awesomeGame\",\n                        \"lastModified\": \"2013-01-31T16:00:00Z\",\n                        \"state\": \"active\",\n                        \"placement\": \"Full\",\n                        \"activity\": {\n                            \"richPresence\": \"yes\",\n                            \"broadcast\": {\n                                \"id\": \"12345\",\n                                \"session\": \"test0\",\n                                \"provider\": \"twitch\",\n                                \"viewers\": 10,\n                                \"started\": \"2013-01-31T16:00:00Z\"\n                            }\n                        }\n                    }\n                ]\n            }\n        ]\n    }\n]\n)\";\n\nDEFINE_TEST_CLASS(PresenceTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(PresenceTests);\n\n    void VerifyBroadcastRecord(XblPresenceBroadcastRecord* broadcastRecord, JsonValue resultToVerify)\n    {\n        const char* provider = broadcastRecord->provider == XblPresenceBroadcastProvider::Twitch ? \"twitch\" : \"unknown\";\n        xsapi_internal_string resultStr = resultToVerify[\"started\"].GetString();\n        xbox::services::datetime resultDatetime = xbox::services::datetime::from_string(resultStr, xbox::services::datetime::date_format::ISO_8601);\n\n        VERIFY_ARE_EQUAL_STR(provider, resultToVerify[\"provider\"].GetString());\n        VERIFY_ARE_EQUAL_STR(broadcastRecord->broadcastId, resultToVerify[\"id\"].GetString());\n        VERIFY_ARE_EQUAL_STR(broadcastRecord->session, resultToVerify[\"session\"].GetString());\n        VERIFY_ARE_EQUAL_INT(broadcastRecord->viewerCount, resultToVerify[\"viewers\"].GetInt());\n        VERIFY_ARE_EQUAL_INT(broadcastRecord->startTime, utils::TimeTFromDatetime(resultDatetime));\n    }\n\n    void VerifyPresenceTitleRecord(XblPresenceTitleRecord* record, JsonValue resultToVerify)\n    {\n        xsapi_internal_string resultStr = resultToVerify[\"lastModified\"].GetString();\n        xbox::services::datetime resultDatetime = xbox::services::datetime::from_string(resultStr, xbox::services::datetime::date_format::ISO_8601);\n        xsapi_internal_string expectedStr = utils::DatetimeFromTimeT(record->lastModified).to_string(xbox::services::datetime::date_format::ISO_8601);\n        UNREFERENCED_PARAMETER(expectedStr);\n        VERIFY_ARE_EQUAL_INT(record->titleId, std::stoi(resultToVerify[\"id\"].GetString()));\n        VERIFY_ARE_EQUAL_STR(record->titleName, resultToVerify[\"name\"].GetString());\n        VERIFY_ARE_EQUAL_INT(record->lastModified, utils::TimeTFromDatetime(resultDatetime));\n        \n        const char* stateString = resultToVerify[\"state\"].GetString();\n        if (utils::str_icmp(stateString, \"active\") == 0)\n        {\n            VERIFY_IS_TRUE(record->titleActive);\n        }\n        else\n        {\n            VERIFY_IS_FALSE(record->titleActive);\n        }\n\n        const char* recordPlacement{ nullptr };\n        switch (record->viewState)\n        {\n            case XblPresenceTitleViewState::FullScreen:\n                recordPlacement = \"Full\";\n                break;\n            case XblPresenceTitleViewState::Filled:\n                recordPlacement = \"Fill\";\n                break;\n            case XblPresenceTitleViewState::Snapped:\n                recordPlacement = \"Snapped\";\n                break;\n            case XblPresenceTitleViewState::Background:\n                recordPlacement = \"Background\";\n                break;\n            default:\n                recordPlacement = \"Unknown\";\n        }\n\n        VERIFY_ARE_EQUAL_STR(recordPlacement, resultToVerify[\"placement\"].GetString());\n        VERIFY_ARE_EQUAL_STR(record->richPresenceString, resultToVerify[\"activity\"][\"richPresence\"].GetString());\n\n        VerifyBroadcastRecord(record->broadcastRecord, resultToVerify[\"activity\"][\"broadcast\"].GetObjectW());\n    }\n\n    void VerifyAndClosePresenceRecord(XblPresenceRecord* record, JsonValue resultToVerify)\n    {\n        const char* userStateStr{ nullptr };\n        switch (record->UserState())\n        {\n            case XblPresenceUserState::Online:\n                userStateStr = \"Online\";\n                break;\n            case XblPresenceUserState::Away:\n                userStateStr = \"Away\";\n                break;\n            case XblPresenceUserState::Offline:\n                userStateStr = \"Offline\";\n                break;\n            case XblPresenceUserState::Unknown:\n            default:\n                userStateStr = \"Unknown\";\n                break;\n        }\n\n        VERIFY_ARE_EQUAL_UINT(record->Xuid(), atoll(resultToVerify[\"xuid\"].GetString()));\n        VERIFY_ARE_EQUAL_STR(userStateStr, resultToVerify[\"state\"].GetString());\n        \n        uint32_t deviceCounter = 0;\n        for (auto& device : resultToVerify[\"devices\"].GetArray())\n        {\n            auto deviceRecord = record->DeviceRecords()[deviceCounter];\n            \n            const char* deviceTypeStr{ nullptr };\n            switch (deviceRecord.deviceType)\n            {\n                case XblPresenceDeviceType::WindowsPhone:\n                    deviceTypeStr = \"WindowsPhone\";\n                    break;\n                case XblPresenceDeviceType::WindowsPhone7:\n                    deviceTypeStr = \"WindowsPhone7\";\n                    break;\n                case XblPresenceDeviceType::Web:\n                    deviceTypeStr = \"Web\";\n                    break;\n                case XblPresenceDeviceType::Xbox360:\n                    deviceTypeStr = \"Xbox360\";\n                    break;\n                case XblPresenceDeviceType::PC:\n                    deviceTypeStr = \"PC\";\n                    break;\n                case XblPresenceDeviceType::Windows8:\n                    deviceTypeStr = \"Windows8\";\n                    break;\n                case XblPresenceDeviceType::XboxOne:\n                    deviceTypeStr = \"XboxOne\";\n                    break;\n                case XblPresenceDeviceType::WindowsOneCore:\n                    deviceTypeStr = \"WindowsOneCore\";\n                    break;\n                case XblPresenceDeviceType::WindowsOneCoreMobile:\n                    deviceTypeStr = \"WindowsOneCoreMobile\";\n                    break;\n                case XblPresenceDeviceType::Unknown:\n                default:\n                    deviceTypeStr = \"Unknown\";\n                    break;\n            }\n\n            VERIFY_ARE_EQUAL_STR(deviceTypeStr, device[\"type\"].GetString());\n\n            uint32_t titleCounter = 0;\n            for (auto& titleValue : device[\"titles\"].GetArray())\n            {\n                auto presenceTitleRecord = deviceRecord.titleRecords[titleCounter];\n                VerifyPresenceTitleRecord(&presenceTitleRecord, titleValue.GetObjectW());\n                ++titleCounter;\n            }\n            ++deviceCounter;\n        }\n\n        XblPresenceRecordCloseHandle(record);\n    }\n\n    void VerifyAndCloseRecords(XblPresenceRecordHandle* records)\n    {\n        uint32_t counter{ 0 };\n        JsonDocument document;\n        document.Parse(defaultMultiplePresenceResponse);\n        for (auto& result : document.GetArray())\n        {\n            VerifyAndClosePresenceRecord(records[counter], result.GetObjectW());\n            ++counter;\n        }\n    }\n\n    std::shared_ptr<HttpMock> CreatePresenceMock(\n        xsapi_internal_string titleId\n    )\n    {\n        auto presenceMock = std::make_shared<HttpMock>(\"GET\", \"https://userpresence.xboxlive.com\");\n\n        presenceMock->SetMockMatchedCallback(\n            [titleId](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument jsonRequest;\n                jsonRequest.Parse(requestBody.c_str());\n\n                JsonValue response;\n                response.SetArray();\n                JsonDocument defaultPresence;\n                defaultPresence.Parse(defaultPresenceResponse);\n                uint32_t i{ 0 };\n                for (auto& user : jsonRequest[\"users\"].GetArray())\n                {\n                    response[i] = defaultPresence.GetObjectW();\n                    response[i][\"devices\"][0][\"titles\"][0][\"id\"] = rapidjson::StringRef(titleId.c_str());\n                    response[i][\"xuid\"] = user;\n                    ++i;\n                }\n\n                mock->SetResponseBody(response);\n            });\n\n        return presenceMock;\n    }\n\n    DEFINE_TEST_CASE(TestSetPresenceAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSetPresenceAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << \"https://userpresence.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/devices/current/titles/current\";\n        auto mock = std::make_shared<HttpMock>(\"POST\", url.str(), 200);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument expectedJson, requestJson;\n                expectedJson.Parse(setPresenceRequest);\n                requestJson.Parse(requestBody.c_str());\n                auto& expectedRich = expectedJson[\"activity\"][\"richPresence\"];\n                auto& requestRich = requestJson[\"activity\"][\"richPresence\"];\n\n                requestWellFormed &= strcmp(expectedJson[\"state\"].GetString(), requestJson[\"state\"].GetString()) == 0;\n                requestWellFormed &= strcmp(expectedRich[\"scid\"].GetString(), requestRich[\"scid\"].GetString()) == 0;\n                requestWellFormed &= strcmp(expectedRich[\"id\"].GetString(), requestRich[\"id\"].GetString()) == 0;\n            }\n        );\n\n        XAsyncBlock async{};\n        const char* ids[]{\"\"};\n        XblPresenceRichPresenceIds presence{ \"12345675467\", \"20\", ids, 1};\n        VERIFY_SUCCEEDED(XblPresenceSetPresenceAsync(xboxLiveContext.get(), true, &presence, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestGetPresenceAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetPresenceAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << \"https://userpresence.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")?level=all\";\n        HttpMock mock(\"GET\", url.str(), 200);\n        mock.SetResponseBody(defaultPresenceResponse);\n\n        XAsyncBlock async{};\n        XblPresenceRecordHandle recordHandle{};\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceAsync(xboxLiveContext.get(), xboxLiveContext->Xuid(), &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceResult(&async, &recordHandle));\n        \n        JsonDocument document;\n        document.Parse(defaultPresenceResponse);\n        VerifyAndClosePresenceRecord(recordHandle, document.GetObjectW());\n    }\n\n    DEFINE_TEST_CASE(TestGetPresenceForMultipleUsersAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetPresenceForMultipleUsersAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_string url{ \"https://userpresence.xboxlive.com/users/batch\" };\n        auto mock = std::make_shared<HttpMock>(\"GET\", url, 200);\n        mock->SetResponseBody(defaultMultiplePresenceResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument expectedJson, requestJson;\n                expectedJson.Parse(getPresenceForMultipleUsersRequest);\n                requestJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedJson[\"onlineOnly\"].GetBool() == expectedJson[\"onlineOnly\"].GetBool();\n                requestWellFormed &= expectedJson[\"broadcastingOnly\"].GetBool() == expectedJson[\"broadcastingOnly\"].GetBool();\n\n                auto counter{ 0 };\n                auto requestXuids = requestJson[\"users\"].GetArray();\n                for (auto& xuid : expectedJson[\"users\"].GetArray())\n                {\n                    requestWellFormed &= strcmp(xuid.GetString(), requestXuids[counter].GetString()) == 0;\n                    ++counter;\n                }\n            }\n        );\n\n        XAsyncBlock async{};\n        uint64_t xuids[]{ 12345, 56789 };\n        size_t recordCount{};\n        XblPresenceRecordHandle recordHandles[2];\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForMultipleUsersAsync(xboxLiveContext.get(), xuids, 2, nullptr, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForMultipleUsersResultCount(&async, &recordCount));\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForMultipleUsersResult(&async, recordHandles, recordCount));\n\n        VerifyAndCloseRecords(recordHandles);\n    }\n\n    DEFINE_TEST_CASE(TestGetPresenceForMultipleUsersOverloadAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetPresenceForMultipleUsersOverloadAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_string url{ \"https://userpresence.xboxlive.com/users/batch\" };\n        auto mock = std::make_shared<HttpMock>(\"POST\", url, 200);\n        mock->SetResponseBody(defaultMultiplePresenceResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument expectedJson, requestJson;\n                expectedJson.Parse(getPresenceForMultipleUsersRequest);\n                requestJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedJson[\"onlineOnly\"].GetBool() == requestJson[\"onlineOnly\"].GetBool();\n                requestWellFormed &= expectedJson[\"broadcastingOnly\"].GetBool() == requestJson[\"broadcastingOnly\"].GetBool();\n\n                auto counter{ 0 };\n                auto requestXuids = requestJson[\"users\"].GetArray();\n                for (auto& xuid : expectedJson[\"users\"].GetArray())\n                {\n                    requestWellFormed &= strcmp(xuid.GetString(), requestXuids[counter].GetString()) == 0;\n                    ++counter;\n                }\n            }\n        );\n        \n        XAsyncBlock async{};\n        uint64_t xuids[]{ 12345, 56789 };\n        uint64_t titles[]{ 0, 1 };\n        size_t recordCount{};\n        XblPresenceRecordHandle recordHandles[2];\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForMultipleUsersAsync(xboxLiveContext.get(), xuids, 2, nullptr, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForMultipleUsersResultCount(&async, &recordCount));\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForMultipleUsersResult(&async, recordHandles, recordCount));\n\n        VerifyAndCloseRecords(recordHandles);\n    }\n\n    DEFINE_TEST_CASE(TestGetPresenceForSocialGroupAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetPresenceForSocialGroupAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << \"https://userpresence.xboxlive.com/users/batch\";\n        HttpMock mock(\"GET\", url.str(), 200);\n        mock.SetResponseBody(defaultMultiplePresenceResponse);\n\n        XAsyncBlock async{};\n        uint64_t ownerXuid = 12345;\n        size_t recordCount{};\n        XblPresenceRecordHandle recordHandles[2];\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForSocialGroupAsync(xboxLiveContext.get(), \"testGroup\", &ownerXuid, nullptr, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForSocialGroupResultCount(&async, &recordCount));\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForSocialGroupResult(&async, recordHandles, recordCount));\n\n        VerifyAndCloseRecords(recordHandles);\n    }\n\n    DEFINE_TEST_CASE(TestGetPresenceForSocialGroupOverloadAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetPresenceForSocialGroupOverloadAsync\");\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_string url{ \"https://userpresence.xboxlive.com/users/batch\" };\n        auto mock = std::make_shared<HttpMock>(\"POST\", url, 200);\n        mock->SetResponseBody(defaultMultiplePresenceResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument expectedJson, requestJson;\n                expectedJson.Parse(getPresenceForMultipleUsersRequest);\n                requestJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedJson[\"onlineOnly\"].GetBool() == requestJson[\"onlineOnly\"].GetBool();\n                requestWellFormed &= expectedJson[\"broadcastingOnly\"].GetBool() == requestJson[\"broadcastingOnly\"].GetBool();\n            }\n        );\n\n        XAsyncBlock async{};\n        uint64_t ownerXuid = 12345;\n        size_t recordCount{};\n        XblPresenceRecordHandle recordHandles[2];\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForSocialGroupAsync(xboxLiveContext.get(), \"testGroup\", &ownerXuid, nullptr, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForSocialGroupResultCount(&async, &recordCount));\n        VERIFY_SUCCEEDED(XblPresenceGetPresenceForSocialGroupResult(&async, recordHandles, recordCount));\n\n        VerifyAndCloseRecords(recordHandles);\n    }\n\n    struct TitlePresenceChangedHandler\n    {\n        TitlePresenceChangedHandler(std::shared_ptr<XblContext> xblContext) noexcept\n            : m_xblContext{ std::move(xblContext) }\n        {\n            m_token = XblPresenceAddTitlePresenceChangedHandler(m_xblContext.get(), func, this);\n            VERIFY_ARE_NOT_EQUAL(0, m_token);\n        };\n\n        ~TitlePresenceChangedHandler() noexcept\n        {\n            VERIFY_SUCCEEDED(XblPresenceRemoveTitlePresenceChangedHandler(m_xblContext.get(), m_token));\n        }\n\n        Event rtaTapReceived;\n        uint64_t xuid{ 0 };\n        uint32_t titleId{ 0 };\n        XblPresenceTitleState state{ XblPresenceTitleState::Unknown };\n\n    private:\n        static void CALLBACK func(void* context, uint64_t xuid, uint32_t titleId, XblPresenceTitleState titleState)\n        {\n            auto pThis{ static_cast<TitlePresenceChangedHandler*>(context) };\n            pThis->xuid = xuid;\n            pThis->titleId = titleId;\n            pThis->state = titleState;\n            pThis->rtaTapReceived.Set();\n        }\n    \n        std::shared_ptr<XblContext> m_xblContext;\n        XblFunctionContext m_token{ 0 };\n    };\n\n    // Bug 39348459: XSAPI Unit Test: TestRTATitlePresence failing\n    //DEFINE_TEST_CASE(TestRTATitlePresence)\n    //{\n    //    TEST_LOG(L\"Test starting: TestRTATitlePresence\");\n    //    TestEnvironment env{};\n    //    auto xboxLiveContext = env.CreateMockXboxLiveContext();\n    //    auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n    //    const uint64_t xuid = 1234;\n    //    const uint32_t titleId = 1563044810;\n    //    const char titlePresenceUri[]{ \"https://userpresence.xboxlive.com/users/xuid(1234)/titles/1563044810\" };\n\n    //    mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n    //    {\n    //        if (uri == titlePresenceUri)\n    //        {\n    //            mockRtaService.CompleteSubscribeHandshake(n, defaultPresenceResponse);\n    //        }\n    //    });\n\n    //    VERIFY_SUCCEEDED(XblPresenceTrackUsers(xboxLiveContext.get(), &xuid, 1));\n    //    VERIFY_SUCCEEDED(XblPresenceTrackAdditionalTitles(xboxLiveContext.get(), &titleId, 1));\n\n    //    TitlePresenceChangedHandler handler{ xboxLiveContext };\n    //    // Wait for subscription complete before sending change event\n    //    handler.rtaTapReceived.Wait();\n\n    //    mockRtaService.RaiseEvent(titlePresenceUri, titlePresenceEndedResponse);\n    //    handler.rtaTapReceived.Wait();\n\n    //    VERIFY_ARE_EQUAL_INT(xuid, handler.xuid);\n    //    VERIFY_ARE_EQUAL_INT(titleId, handler.titleId);\n    //    VERIFY_IS_TRUE(handler.state == XblPresenceTitleState::Ended);\n    //}\n\n    struct DevicePresenceChangedHandler\n    {\n        DevicePresenceChangedHandler(std::shared_ptr<XblContext> xblContext) noexcept\n            : m_xblContext{ std::move(xblContext) }\n        {\n            m_token = XblPresenceAddDevicePresenceChangedHandler(m_xblContext.get(), func, this);\n            VERIFY_ARE_NOT_EQUAL(0, m_token);\n        };\n\n        ~DevicePresenceChangedHandler() noexcept\n        {\n            VERIFY_SUCCEEDED(XblPresenceRemoveDevicePresenceChangedHandler(m_xblContext.get(), m_token));\n        }\n\n        Event rtaTapReceived;\n        uint64_t xuid{ 0 };\n        XblPresenceDeviceType deviceType{ XblPresenceDeviceType::Unknown };\n        bool isUserLoggedOnDevice{ false };\n\n    private:\n        static void CALLBACK func(void* context, uint64_t xuid, XblPresenceDeviceType deviceType, bool isUserLoggedOnDevice)\n        {\n            auto pThis{ static_cast<DevicePresenceChangedHandler*>(context) };\n            pThis->xuid = xuid;\n            pThis->deviceType = deviceType;\n            pThis->isUserLoggedOnDevice = isUserLoggedOnDevice;\n            pThis->rtaTapReceived.Set();\n        }\n\n        std::shared_ptr<XblContext> m_xblContext;\n        XblFunctionContext m_token{ 0 };\n    };\n\n    DEFINE_TEST_CASE(TestRTADevicePresence)\n    {\n        TEST_LOG(L\"Test starting: TestRTADevicePresence\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n        const uint64_t xuid = 1234;\n        const xsapi_internal_string devicePresenceUri{ \"https://userpresence.xboxlive.com/users/xuid(1234)/devices\" };\n\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            if (uri == devicePresenceUri)\n            {\n                mockRtaService.CompleteSubscribeHandshake(n, defaultPresenceResponse);\n            }\n        });\n\n        VERIFY_SUCCEEDED(XblPresenceTrackUsers(xboxLiveContext.get(), &xuid, 1));\n\n        DevicePresenceChangedHandler handler{ xboxLiveContext };\n        // Wait for subscription complete event\n        handler.rtaTapReceived.Wait();\n\n        mockRtaService.RaiseEvent(devicePresenceUri, devicePresenceResponse);\n        handler.rtaTapReceived.Wait();\n\n        JsonDocument deviceResponseJson{};\n        deviceResponseJson.Parse(devicePresenceResponse);\n\n        auto response = utils::string_split_internal(deviceResponseJson.GetString(), ':');\n        VERIFY_ARE_EQUAL_INT(xuid, handler.xuid);\n        VERIFY_IS_TRUE(xbox::services::presence::DeviceRecord::DeviceTypeFromString(response[0]) == handler.deviceType);\n        VERIFY_ARE_EQUAL(response[1] == \"true\", handler.isUserLoggedOnDevice);\n    }\n\n    DEFINE_TEST_CASE(TestSubscriptionManagement)\n    {\n        TEST_LOG(L\"Test starting: TestSubscriptionManagement\");\n\n        TestEnvironment env{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n        const uint64_t xuid1{ 1 };\n        const uint64_t xuid2{ 2 };\n        std::map<uint64_t, Event> subAddedEvents;\n\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            mockRtaService.CompleteSubscribeHandshake(n, defaultPresenceResponse);\n\n            const char xuidPrefix[]{ \"xuid(\" };\n            const char* p{ &uri[uri.find(xuidPrefix) + _countof(xuidPrefix) - 1] };\n            uint64_t xuid = strtoull(p, nullptr, 0);\n            subAddedEvents[xuid].Set();\n        });\n\n        {\n            DevicePresenceChangedHandler handler{ xboxLiveContext };\n\n            VERIFY_SUCCEEDED(XblPresenceTrackUsers(xboxLiveContext.get(), &xuid1, 1));\n            subAddedEvents[xuid1].Wait();\n\n            VERIFY_SUCCEEDED(XblPresenceTrackUsers(xboxLiveContext.get(), &xuid2, 1));\n            subAddedEvents[xuid2].Wait();\n\n            // Subs should be removed along with the handler\n        }\n\n        {\n            // Subs should be re-added automatically if a handler is re-added\n            DevicePresenceChangedHandler handler{ xboxLiveContext };\n            subAddedEvents[xuid1].Wait();\n            subAddedEvents[xuid2].Wait();\n        }\n    }\n\n    DEFINE_TEST_CASE(TestLegacySubscriptions)\n    {\n        TEST_LOG(L\"Test starting: TestLegacySubscriptions\");\n\n        TestEnvironment env{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n        uint32_t subCount{ 0 };\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            mockRtaService.CompleteSubscribeHandshake(n, defaultPresenceResponse);\n            subCount++;\n        });\n\n        TitlePresenceChangedHandler titlePresenceHandler{ xboxLiveContext };\n        DevicePresenceChangedHandler devicePresenceHandler{ xboxLiveContext };\n\n        XblRealTimeActivitySubscriptionHandle titlePresenceSub{ nullptr };\n        VERIFY_SUCCEEDED(XblPresenceSubscribeToTitlePresenceChange(xboxLiveContext.get(), 1, 1, &titlePresenceSub));\n\n        // Both handlers should be invoked since title presence subscription tracks the user and the title\n        titlePresenceHandler.rtaTapReceived.Wait();\n        devicePresenceHandler.rtaTapReceived.Wait();\n\n        // Since we are already tracking Xuid \"1\", this shouldn't result in any new subs\n        XblRealTimeActivitySubscriptionHandle devicePresenceSub{ nullptr };\n        VERIFY_SUCCEEDED(XblPresenceSubscribeToDevicePresenceChange(xboxLiveContext.get(), 1, &devicePresenceSub));\n\n        VERIFY_SUCCEEDED(XblPresenceUnsubscribeFromTitlePresenceChange(xboxLiveContext.get(), titlePresenceSub));\n\n        // Ensure we continue to receive device presence changed notification\n        mockRtaService.RaiseEvent(\"https://userpresence.xboxlive.com/users/xuid(1)/devices\", devicePresenceResponse);\n        devicePresenceHandler.rtaTapReceived.Wait();\n\n        VERIFY_SUCCEEDED(XblPresenceUnsubscribeFromDevicePresenceChange(xboxLiveContext.get(), devicePresenceSub));\n    }\n\n    DEFINE_TEST_CASE(TestPresenceInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestPresenceInvalidArgs\");\n\n        TestEnvironment env{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        XAsyncBlock async{};\n        uint64_t xuid{};\n        const char name{};\n        XblPresenceQueryFilters* filters{ nullptr };\n\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceAsync(nullptr, 1, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceAsync(xboxLiveContext.get(), 1, nullptr), E_INVALIDARG);\n\n#pragma warning(suppress: 6387)\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceForMultipleUsersAsync(nullptr, &xuid, 0, filters, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceForMultipleUsersAsync(xboxLiveContext.get(), nullptr, 0, filters, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceForMultipleUsersAsync(xboxLiveContext.get(), &xuid, 0, filters, nullptr), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceForSocialGroupAsync(nullptr, &name, &xuid, filters, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceForSocialGroupAsync(xboxLiveContext.get(), nullptr, &xuid, filters, &async), E_INVALIDARG);\n        VERIFY_ARE_EQUAL_INT(XblPresenceGetPresenceForSocialGroupAsync(xboxLiveContext.get(), &name, &xuid, filters, nullptr), E_INVALIDARG);\n    }\n};\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/PrivacyTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nusing namespace xbox::services::privacy;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char defaultCheckPermissionsResponse[] = R\"(\n{ \n    \"isAllowed\":false,\n    \"reasons\" :\n    [{\n        \"reason\":\"BlockListRestrictsTarget\"\n    },\n    { \n        \"reason\":\"MuteListRestrictsTarget\" \n    }] \n}\n)\";\n\nconst char defaultCheckMultiplePermissionsResponse[] = R\"(\n{\n    \"responses\":\n    [{\n        \"user\":\n        {\n            \"xuid\":\"1\"\n        }, \n        \"permissions\" : \n        [{\n            \"isAllowed\":true\n         }, \n         {\n             \"isAllowed\":true \n         }, \n         {\n             \"isAllowed\":true \n         }]\n    }, \n    { \n        \"user\":\n        {\n            \"anonymousUser\":\"crossNetworkUser\"\n        },\n        \"permissions\" : \n        [{\n            \"isAllowed\":true\n         },\n         { \n             \"isAllowed\":false, \n             \"reasons\" : \n             [{\n                 \"reason\":\"BlockListRestrictsTarget\"\n             },\n             { \n                 \"reason\":\"MuteListRestrictsTarget\" \n             }] \n         },\n         { \n             \"isAllowed\":false, \n             \"reasons\" : \n             [{\n                 \"reason\":\"BlockListRestrictsTarget\"\n             }]\n         }]\n    }]\n}\n)\";\n\nDEFINE_TEST_CLASS(PrivacyTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(PrivacyTests);\n\n    std::shared_ptr<HttpMock> CreatePrivacyListMock(\n        const std::vector<uint64_t>& xuids\n    )\n    {\n        auto mock = std::make_shared<HttpMock>(\"GET\", \"https://privacy.xboxlive.com/users\");\n\n        mock->SetMockMatchedCallback(\n            [\n                &xuids\n            ]\n        (HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(requestUrl);\n                VERIFY_IS_TRUE(requestBody.empty());\n\n                // Response sample:\n                //{\n                //    \"users\":\n                //    [\n                //        { \"xuid\":\"12345\" },\n                //        { \"xuid\":\"23456\" }\n                //    ]\n                //}\n\n                JsonDocument response(rapidjson::kObjectType);\n                JsonValue usersJson(rapidjson::kArrayType);\n\n                for (size_t i = 0; i < xuids.size(); ++i)\n                {\n                    JsonValue user(rapidjson::kObjectType);\n                    user.AddMember(\"xuid\", JsonValue(Utils::StringFromUint64(xuids[i]).c_str(), response.GetAllocator()).Move(), response.GetAllocator());\n                    usersJson.PushBack(user, response.GetAllocator());\n                }\n                response.AddMember(\"users\", usersJson, response.GetAllocator());\n\n                mock->SetResponseBody(response);\n            }\n        );\n\n        return mock;\n    }\n\n    void VerifyPermissionCheckResult(\n        const XblPermissionCheckResult& result,\n        uint64_t expectedXuid,\n        XblAnonymousUserType expectedUserType,\n        JsonValue& responseJson\n    )\n    {\n        VERIFY_ARE_EQUAL(result.isAllowed, responseJson[\"isAllowed\"].GetBool());\n        VERIFY_ARE_EQUAL_INT(result.targetXuid, expectedXuid);\n        VERIFY_IS_TRUE(result.targetUserType == expectedUserType);\n        if (!result.isAllowed)\n        {\n            JsonValue& reasonsArray{ responseJson[\"reasons\"]};\n            VERIFY_ARE_EQUAL_INT(result.reasonsCount, reasonsArray.Size());\n            for (uint64_t i = 0; i < result.reasonsCount; ++i)\n            {\n                auto expectedReason{ reasonsArray[i][\"reason\"].GetString() };\n                VERIFY_ARE_EQUAL_STR(utils::internal_string_from_string_t(permission_deny_reason{ result.reasons[i] }.reason()), expectedReason);\n            }\n        }\n    }\n\n    void VerifyBatchPermissionsCheckResult(\n        std::vector<XblPermissionCheckResult>&& batchResult,\n        JsonValue& responseJson\n    )\n    {\n        JsonValue& responsesArray = responseJson[\"responses\"];\n        uint64_t userCount = responsesArray.Size();\n        uint64_t permissionCount = responsesArray[0][\"permissions\"].Size();\n        VERIFY_ARE_EQUAL_INT(batchResult.size(), userCount * permissionCount);\n\n        for (uint64_t userIndex = 0; userIndex < userCount; ++userIndex)\n        {\n            JsonValue& userJson = responsesArray[userIndex][\"user\"];\n\n            uint64_t expectedXuid{ 0 };\n            if (userJson.HasMember(\"xuid\") && userJson[\"xuid\"].IsString())\n            {\n                expectedXuid = utils::internal_string_to_uint64(userJson[\"xuid\"].GetString());\n            }\n            XblAnonymousUserType expectedUserType{ XblAnonymousUserType::Unknown };\n            if (userJson.HasMember(\"anonymousUser\") && userJson[\"anonymousUser\"].IsString())\n            {\n                expectedUserType = EnumValue<XblAnonymousUserType>(userJson[\"anonymousUser\"].GetString());\n            }\n            JsonValue& permissionsArray = responsesArray[userIndex][\"permissions\"];\n\n            for (uint64_t permissionIndex = 0; permissionIndex < permissionCount; ++permissionIndex)\n            {\n                VerifyPermissionCheckResult(batchResult[userIndex * permissionCount + permissionIndex], expectedXuid, expectedUserType, permissionsArray[permissionIndex]);\n            }\n        }\n    }\n\n    DEFINE_TEST_CASE(TestCheckAvoidList)\n    {\n        TEST_LOG(L\"Test starting: TestCheckAvoidList\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<uint64_t> avoidXuids{ 1, 2, 3, 4, 5 };\n        auto mock = CreatePrivacyListMock(avoidXuids);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyGetAvoidListAsync(xboxLiveContext.get(), &async));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        \n        size_t xuidCount{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyGetAvoidListResultCount(&async, &xuidCount));\n        VERIFY_IS_TRUE(avoidXuids.size() == xuidCount);\n\n        std::vector<uint64_t> resultXuids(xuidCount);\n        VERIFY_SUCCEEDED(XblPrivacyGetAvoidListResult(&async, xuidCount, &resultXuids[0]));\n\n        for (size_t i = 0; i < avoidXuids.size(); ++i)\n        {\n            VERIFY_ARE_EQUAL_INT(avoidXuids[i], resultXuids[i]);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestCheckMuteList)\n    {\n        TEST_LOG(L\"Test starting: TestCheckMuteList\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<uint64_t> muteXuids{ };\n        auto mock = CreatePrivacyListMock(muteXuids);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyGetMuteListAsync(xboxLiveContext.get(), &async));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t xuidCount{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyGetMuteListResultCount(&async, &xuidCount));\n        VERIFY_IS_TRUE(muteXuids.size() == xuidCount);\n\n        std::vector<uint64_t> resultXuids(xuidCount);\n        VERIFY_SUCCEEDED(XblPrivacyGetMuteListResult(&async, xuidCount, resultXuids.data()));\n    }\n\n    DEFINE_TEST_CASE(TestCheckPermissionAsync)\n    {\n        TEST_LOG(L\"Test starting: TestCheckPermissionAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument defaultCheckPermissionsResponseJson;\n        defaultCheckPermissionsResponseJson.Parse(defaultCheckPermissionsResponse);\n        HttpMock mock{ \"GET\", \"https://privacy.xboxlive.com\", 200, defaultCheckPermissionsResponseJson };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionAsync(xboxLiveContext.get(), XblPermission::CommunicateUsingVoice, 1, &async));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionResultSize(&async, &resultSize));\n        \n        std::vector<uint8_t> buffer(resultSize);\n        XblPermissionCheckResult* result{ nullptr };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionResult(&async, resultSize, buffer.data(), &result, nullptr));\n\n        VerifyPermissionCheckResult(*result, 1, XblAnonymousUserType::Unknown, defaultCheckPermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(TestCheckPermissionWithLargeBufferAsync)\n    {\n        TEST_LOG(L\"Test starting: TestCheckPermissionWithLargeBufferAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument defaultCheckPermissionsResponseJson;\n        defaultCheckPermissionsResponseJson.Parse(defaultCheckPermissionsResponse);\n        HttpMock mock{ \"GET\", \"https://privacy.xboxlive.com\", 200, defaultCheckPermissionsResponseJson };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionAsync(xboxLiveContext.get(), XblPermission::CommunicateUsingVoice, 1, &async));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        std::vector<uint8_t> buffer(resultSize * 2);\n        XblPermissionCheckResult* result{ nullptr };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionResult(&async, resultSize * 2, buffer.data(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        VerifyPermissionCheckResult(*result, 1, XblAnonymousUserType::Unknown, defaultCheckPermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(TestCheckPermissionForAnonymousUserAsync)\n    {\n        TEST_LOG(L\"Test starting: TestCheckPermissionForAnonymousUserAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument defaultCheckPermissionsResponseJson;\n        defaultCheckPermissionsResponseJson.Parse(defaultCheckPermissionsResponse);\n        HttpMock mock{ \"GET\", \"https://privacy.xboxlive.com\", 200, defaultCheckPermissionsResponseJson };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionForAnonymousUserAsync(\n            xboxLiveContext.get(),\n            XblPermission::PlayMultiplayer,\n            XblAnonymousUserType::CrossNetworkUser,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionForAnonymousUserResultSize(&async, &resultSize));\n\n        std::vector<uint8_t> buffer(resultSize);\n        XblPermissionCheckResult* result{ nullptr };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionForAnonymousUserResult(&async, resultSize, buffer.data(), &result, nullptr));\n\n        VerifyPermissionCheckResult(*result, 0, XblAnonymousUserType::CrossNetworkUser, defaultCheckPermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(TestCheckPermissionForAnonymousUserWithLargeBufferAsync)\n    {\n        TEST_LOG(L\"Test starting: TestCheckPermissionForAnonymousUserWithLargeBufferAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument defaultCheckPermissionsResponseJson;\n        defaultCheckPermissionsResponseJson.Parse(defaultCheckPermissionsResponse);\n        HttpMock mock{ \"GET\", \"https://privacy.xboxlive.com\", 200, defaultCheckPermissionsResponseJson };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionForAnonymousUserAsync(\n            xboxLiveContext.get(),\n            XblPermission::PlayMultiplayer,\n            XblAnonymousUserType::CrossNetworkUser,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t resultSize{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionForAnonymousUserResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        std::vector<uint8_t> buffer(resultSize * 2);\n        XblPermissionCheckResult* result{ nullptr };\n        VERIFY_SUCCEEDED(XblPrivacyCheckPermissionForAnonymousUserResult(&async, resultSize, buffer.data(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        VerifyPermissionCheckResult(*result, 0, XblAnonymousUserType::CrossNetworkUser, defaultCheckPermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(TestBatchCheckPermissionAsync)\n    {\n        TEST_LOG(L\"Test starting: TestBatchCheckPermissionAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument defaultCheckMultiplePermissionsResponseJson;\n        defaultCheckMultiplePermissionsResponseJson.Parse(defaultCheckMultiplePermissionsResponse);\n        HttpMock mock{ \"POST\", \"https://privacy.xboxlive.com\", 200, defaultCheckMultiplePermissionsResponseJson };\n\n        std::vector<uint64_t> xuidsToCheck{ 1 };\n        std::vector<XblAnonymousUserType> userTypesToCheck{ XblAnonymousUserType::CrossNetworkUser };\n        std::vector<XblPermission> permissionsToCheck{ XblPermission::PlayMultiplayer, XblPermission::CommunicateUsingVoice, XblPermission::CommunicateUsingText };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            permissionsToCheck.data(),\n            permissionsToCheck.size(),\n            xuidsToCheck.data(),\n            xuidsToCheck.size(),\n            userTypesToCheck.data(),\n            userTypesToCheck.size(),\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t bufferSize{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyBatchCheckPermissionResultSize(&async, &bufferSize));\n\n        std::vector<uint8_t> vectorBuffer(bufferSize);\n        XblPermissionCheckResult* results;\n        size_t resultsCount{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyBatchCheckPermissionResult(&async, bufferSize, vectorBuffer.data(), &results, &resultsCount, nullptr));\n\n        VerifyBatchPermissionsCheckResult({ results, results + resultsCount }, defaultCheckMultiplePermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(TestBatchCheckPermissionWithLargeBufferAsync)\n    {\n        TEST_LOG(L\"Test starting: TestBatchCheckPermissionWithLargeBufferAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        JsonDocument defaultCheckMultiplePermissionsResponseJson;\n        defaultCheckMultiplePermissionsResponseJson.Parse(defaultCheckMultiplePermissionsResponse);\n        HttpMock mock{ \"POST\", \"https://privacy.xboxlive.com\", 200, defaultCheckMultiplePermissionsResponseJson };\n\n        std::vector<uint64_t> xuidsToCheck{ 1 };\n        std::vector<XblAnonymousUserType> userTypesToCheck{ XblAnonymousUserType::CrossNetworkUser };\n        std::vector<XblPermission> permissionsToCheck{ XblPermission::PlayMultiplayer, XblPermission::CommunicateUsingVoice, XblPermission::CommunicateUsingText };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            permissionsToCheck.data(),\n            permissionsToCheck.size(),\n            xuidsToCheck.data(),\n            xuidsToCheck.size(),\n            userTypesToCheck.data(),\n            userTypesToCheck.size(),\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        size_t bufferSize{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyBatchCheckPermissionResultSize(&async, &bufferSize));\n\n        size_t bufferUsed{};\n        std::vector<uint8_t> vectorBuffer(bufferSize * 2);\n        XblPermissionCheckResult* results;\n        size_t resultsCount{ 0 };\n        VERIFY_SUCCEEDED(XblPrivacyBatchCheckPermissionResult(&async, bufferSize * 2, vectorBuffer.data(), &results, &resultsCount, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(bufferSize, bufferUsed);\n\n        VerifyBatchPermissionsCheckResult({ results, results + resultsCount }, defaultCheckMultiplePermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(TestInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestInvalidArgs\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<uint64_t> xuidsToCheck{ 1 };\n        std::vector<XblAnonymousUserType> userTypesToCheck{ XblAnonymousUserType::CrossNetworkUser };\n        std::vector<XblPermission> permissionsToCheck{ XblPermission::PlayMultiplayer };\n        \n        XAsyncBlock async{};\n        VERIFY_FAILED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            nullptr, // invalid\n            permissionsToCheck.size(),\n            xuidsToCheck.data(),\n            xuidsToCheck.size(),\n            userTypesToCheck.data(),\n            userTypesToCheck.size(),\n            &async\n        ));\n\n        VERIFY_FAILED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            permissionsToCheck.data(),\n            0, // invalid\n            xuidsToCheck.data(),\n            xuidsToCheck.size(),\n            userTypesToCheck.data(),\n            userTypesToCheck.size(),\n            &async\n        ));\n\n\n        VERIFY_FAILED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            permissionsToCheck.data(),\n            permissionsToCheck.size(),\n            nullptr, // invalid\n            xuidsToCheck.size(),\n            userTypesToCheck.data(),\n            userTypesToCheck.size(),\n            &async\n        ));\n\n        VERIFY_FAILED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            permissionsToCheck.data(),\n            permissionsToCheck.size(),\n            xuidsToCheck.data(),\n            xuidsToCheck.size(),\n            nullptr, // invalid\n            userTypesToCheck.size(),\n            &async\n        ));\n\n        VERIFY_FAILED(XblPrivacyBatchCheckPermissionAsync(\n            xboxLiveContext.get(),\n            permissionsToCheck.data(),\n            permissionsToCheck.size(),\n            nullptr,\n            0,\n            nullptr,\n            0,\n            &async\n        ));\n    }\n\n    DEFINE_TEST_CASE(CppTestCheckAvoidList)\n    {\n        TEST_LOG(L\"Test starting: CppTestCheckAvoidList\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        std::vector<uint64_t> avoidXuids{ 1, 2, 3, 4, 5 };\n        auto mock = CreatePrivacyListMock(avoidXuids);\n\n        auto task = xboxLiveContext->privacy_service().get_avoid_list();\n\n        auto result{ task.get() };\n        VERIFY_IS_TRUE(!result.err());\n\n        auto& payload{ result.payload() };\n        VERIFY_IS_TRUE(avoidXuids.size() == payload.size());\n\n        for (size_t i = 0; i < avoidXuids.size(); ++i)\n        {\n            VERIFY_IS_TRUE(avoidXuids[i] == Utils::Uint64FromStringT(payload[i]));\n        }\n    }\n\n    DEFINE_TEST_CASE(CppTestCheckMuteList)\n    {\n        TEST_LOG(L\"Test starting: CppTestCheckMuteList\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        std::vector<uint64_t> muteXuids{ };\n        auto mock = CreatePrivacyListMock(muteXuids);\n\n        auto task = xboxLiveContext->privacy_service().get_mute_list();\n\n        auto result{ task.get() };\n        VERIFY_IS_TRUE(!result.err());\n\n        auto& payload{ result.payload() };\n        VERIFY_IS_TRUE(muteXuids.size() == payload.size());\n    }\n\n    void VerifyPermissionCheckResultCpp(\n        const permission_check_result& result,\n        JsonValue& responseJson\n    )\n    {\n        VERIFY_ARE_EQUAL(result.is_allowed(), responseJson[\"isAllowed\"].GetBool());\n        if (!result.is_allowed())\n        {\n            auto& reasonsArray{ responseJson[\"reasons\"] };\n            auto& actualReasons{ result.deny_reasons() };\n            VERIFY_ARE_EQUAL_INT(actualReasons.size() , reasonsArray.Size());\n            for (uint64_t i = 0; i < actualReasons.size(); ++i)\n            {\n                auto expectedReason{ reasonsArray[i][\"reason\"].GetString() };\n                VERIFY_ARE_EQUAL_STR(utils::internal_string_from_string_t(actualReasons[i].reason()), expectedReason);\n            }\n        }\n    }\n\n    void VerifyBatchPermissionsCheckResultCpp(\n        const std::vector<multiple_permissions_check_result>& result,\n       JsonValue& responseJson\n    )\n    {\n        JsonValue& responsesArray = responseJson[\"responses\"];\n        uint64_t userCount = responsesArray.Size();\n        uint64_t permissionCount = responsesArray[0][\"permissions\"].Size();\n        VERIFY_ARE_EQUAL_INT(result.size(), userCount);\n\n        for (uint64_t userIndex = 0; userIndex < userCount; ++userIndex)\n        {\n            JsonValue& userJson = responsesArray[userIndex][\"user\"];\n\n            xsapi_internal_string target;\n            if (userJson.HasMember(\"xuid\") && userJson[\"xuid\"].IsString())\n            {\n                target = userJson[\"xuid\"].GetString();\n            }\n            else if (userJson.HasMember(\"anonymousUser\") && userJson[\"anonymousUser\"].IsString())\n            {\n                target = userJson[\"anonymousUser\"].GetString();\n            }\n            VERIFY_ARE_EQUAL_STR(utils::internal_string_from_string_t(result[userIndex].xbox_user_id()), target);\n            JsonValue& permissionsArray = responsesArray[userIndex][\"permissions\"];\n\n            for (uint64_t permissionIndex = 0; permissionIndex < permissionCount; ++permissionIndex)\n            {\n                VerifyPermissionCheckResultCpp(result[userIndex].items()[permissionIndex], permissionsArray[permissionIndex]);\n            }\n        }\n    }\n\n    DEFINE_TEST_CASE(CppTestCheckPermissionWithTargetUser)\n    {\n        TEST_LOG(L\"Test starting: CppTestCheckPermissionWithTargetUser\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        JsonDocument defaultCheckPermissionsResponseJson;\n        defaultCheckPermissionsResponseJson.Parse(defaultCheckPermissionsResponse);\n        HttpMock mock{ \"GET\", \"https://privacy.xboxlive.com\", 200, defaultCheckPermissionsResponseJson };\n\n        auto task = xboxLiveContext->privacy_service().check_permission_with_target_user(permission_id_constants::communicate_using_voice(), _T(\"1\"));\n\n        auto result{ task.get() };\n        VERIFY_IS_TRUE(!result.err());\n\n        VerifyPermissionCheckResultCpp(result.payload(), defaultCheckPermissionsResponseJson);\n    }\n\n    DEFINE_TEST_CASE(CppTestCheckMultiplePermissionsWithMultipleTargetUsers)\n    {\n        TEST_LOG(L\"Test starting: CppTestCheckMultiplePermissionsWithMultipleTargetUsers\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        JsonDocument defaultCheckMultiplePermissionsResponseJson;\n        defaultCheckMultiplePermissionsResponseJson.Parse(defaultCheckMultiplePermissionsResponse);\n        HttpMock mock{ \"POST\", \"https://privacy.xboxlive.com\", 200, defaultCheckMultiplePermissionsResponseJson };\n\n        std::vector<string_t> permissionsToCheck{\n            permission_id_constants::play_multiplayer(),\n            permission_id_constants::communicate_using_voice(),\n            permission_id_constants::communicate_using_text()\n        };\n\n        std::vector<string_t> targets\n        {\n            _T(\"1\"),\n            anonymous_user_type_constants::cross_network_user()\n        };\n\n        auto task = xboxLiveContext->privacy_service().check_multiple_permissions_with_multiple_target_users(permissionsToCheck, targets);\n\n        auto result{ task.get() };\n        VERIFY_IS_TRUE(!result.err());\n\n        VerifyBatchPermissionsCheckResultCpp(result.payload(), defaultCheckMultiplePermissionsResponseJson);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/ProfileTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\n// Request and response format from http://xboxwiki/wiki/Profile\n\nDEFINE_TEST_CLASS(ProfileTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(ProfileTests);\n\n    struct UserProfile\n    {\n        UserProfile(uint64_t xuid_) noexcept\n            : xuid{ xuid_ }\n        {\n            auto xuidStr = Utils::StringFromUint64(xuid);\n\n            appDisplayName = \"appDisplayName_\" + xuidStr;\n            gameDisplayName = \"gameDisplayName_\" + xuidStr;\n\n            std::stringstream ss;\n            ss << \"http://www.xbox.com/appDisplayPictureRaw?url=test_\" << xuid << \"&format=png\";\n            appDisplayPictureResizeUri = ss.str();\n\n            ss.clear();\n            ss << \"http://www.xbox.com/gameDisplayPictureRaw?url=test_\" << xuid << \"&format=png\";\n            gameDisplayPictureResizeUri = ss.str();\n\n            gamerscore = \"gamerscore_\" + xuidStr;\n            gamertag = \"gamertag\" + xuidStr;\n            modernGamertag = \"mgt\" + xuidStr;\n            modernGamertagSuffix = Utils::StringFromUint64(nextSuffix++);\n            uniqueModernGamertag = modernGamertag + modernGamertagSuffix;\n\n            assert(gamertag.length() < XBL_GAMERTAG_CHAR_SIZE);\n            assert(modernGamertag.length() < XBL_MODERN_GAMERTAG_CHAR_SIZE);\n        }\n\n        static JsonDocument Serialize(const std::vector<UserProfile>& profiles) noexcept\n        {\n            JsonDocument d{ rapidjson::kObjectType };\n            auto& a{ d.GetAllocator() };\n\n            JsonValue profileUsersArray{ rapidjson::kArrayType };\n            for (auto& profile : profiles)\n            {\n                profileUsersArray.PushBack(profile.Serialize(a).Move(), a);\n            }\n            d.AddMember(\"profileUsers\", profileUsersArray.Move(), a);\n\n            return d;\n        }\n\n        uint64_t xuid;\n        std::string appDisplayName;\n        std::string appDisplayPictureResizeUri;\n        std::string gameDisplayName;\n        std::string gameDisplayPictureResizeUri;\n        std::string gamerscore;\n        std::string gamertag;\n        std::string modernGamertag;\n        std::string modernGamertagSuffix;\n        std::string uniqueModernGamertag;\n\n    private:\n        JsonValue Serialize(_In_ JsonDocument::AllocatorType& a) const noexcept\n        {\n            JsonValue settingsArray{ rapidjson::kArrayType };\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"AppDisplayName\", a);\n                setting.AddMember(\"value\", JsonValue{ appDisplayName.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"AppDisplayPicRaw\", a);\n                setting.AddMember(\"value\", JsonValue{ appDisplayPictureResizeUri.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"GameDisplayName\", a);\n                setting.AddMember(\"value\", JsonValue{ gameDisplayName.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"GameDisplayPicRaw\", a);\n                setting.AddMember(\"value\", JsonValue{ gameDisplayPictureResizeUri.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"Gamerscore\", a);\n                setting.AddMember(\"value\", JsonValue{ gamerscore.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"Gamertag\", a);\n                setting.AddMember(\"value\", JsonValue{ gamertag.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"ModernGamertag\", a);\n                setting.AddMember(\"value\", JsonValue{ modernGamertag.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"ModernGamertagSuffix\", a);\n                setting.AddMember(\"value\", JsonValue{ modernGamertagSuffix.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            {\n                JsonValue setting{ rapidjson::kObjectType };\n                setting.AddMember(\"id\", \"UniqueModernGamertag\", a);\n                setting.AddMember(\"value\", JsonValue{ uniqueModernGamertag.data(), a }.Move(), a);\n                settingsArray.PushBack(setting.Move(), a);\n            }\n\n            JsonValue profile{ rapidjson::kObjectType };\n            profile.AddMember(\"id\", JsonValue{ Utils::StringFromUint64(xuid).data(), a }.Move(), a);\n            profile.AddMember(\"settings\", settingsArray, a);\n\n            return profile;\n        }\n\n        static uint8_t nextSuffix;\n    };\n\n    void VerifyUserProfile(\n        _In_ const XblUserProfile& actual,\n        _In_ const UserProfile& expected\n    )\n    {\n        VERIFY_ARE_EQUAL_INT(expected.xuid, actual.xboxUserId);\n        VERIFY_ARE_EQUAL_STR(expected.appDisplayName, actual.appDisplayName);\n        VERIFY_ARE_EQUAL_STR(expected.appDisplayPictureResizeUri, actual.appDisplayPictureResizeUri);\n        VERIFY_ARE_EQUAL_STR(expected.gameDisplayName, actual.gameDisplayName);\n        VERIFY_ARE_EQUAL_STR(expected.gameDisplayPictureResizeUri, actual.gameDisplayPictureResizeUri);\n        VERIFY_ARE_EQUAL_STR(expected.gamerscore, actual.gamerscore);\n        VERIFY_ARE_EQUAL_STR(expected.gamertag, actual.gamertag);\n        VERIFY_ARE_EQUAL_STR(expected.modernGamertag, actual.modernGamertag);\n        VERIFY_ARE_EQUAL_STR(expected.modernGamertagSuffix, actual.modernGamertagSuffix);\n        VERIFY_ARE_EQUAL_STR(expected.uniqueModernGamertag, actual.uniqueModernGamertag);\n    }\n\n    // Validate that a batch request is well formed\n    bool VerifyBatchRequest(\n        _In_ const xsapi_internal_string& requestUri,\n        _In_ const xsapi_internal_string& requestBody,\n        _In_ const std::vector<uint64_t>& requestedXuids\n    )\n    {\n        bool requestWellFormed{ true };\n\n        requestWellFormed &= (\"https://profile.xboxlive.com/users/batch/profile/settings\" == requestUri);\n\n        std::stringstream expectedBody;\n        expectedBody << R\"({\"settings\":[\"AppDisplayName\",\"AppDisplayPicRaw\",\"GameDisplayName\",\"GameDisplayPicRaw\",\"Gamerscore\",\"Gamertag\",\"ModernGamertag\",\"ModernGamertagSuffix\",\"UniqueModernGamertag\"],\"userIds\":[)\";\n        for (size_t i = 0; i < requestedXuids.size(); ++i)\n        {\n            if (i > 0)\n            {\n                expectedBody << \",\";\n            }\n            expectedBody << \"\\\"\" << requestedXuids[i] << \"\\\"\";\n        }\n        expectedBody << \"]}\";\n        requestWellFormed &= VerifyJson(expectedBody.str().data(), requestBody.data());\n\n        return requestWellFormed;\n    }\n\n    DEFINE_TEST_CASE(TestGetUserProfileAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetUserProfileAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        UserProfile expectedProfile{ 1 };\n\n        auto mock = std::make_shared<HttpMock>( \"\", \"https://profile.xboxlive.com\" );\n        mock->SetResponseBody(UserProfile::Serialize({ expectedProfile }));\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                // XblProfileGetUserProfileResult just makes a batch request with 1 xuid\n                requestWellFormed = VerifyBatchRequest(requestUrl, requestBody, std::vector<uint64_t>{ expectedProfile.xuid });\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblProfileGetUserProfileAsync(xboxLiveContext.get(), expectedProfile.xuid, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        XblUserProfile actualProfile{};\n        VERIFY_SUCCEEDED(XblProfileGetUserProfileResult(&async, &actualProfile));\n        VerifyUserProfile(actualProfile, expectedProfile);\n    }\n\n    DEFINE_TEST_CASE(TestGetUserProfilesAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetUserProfilesAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<UserProfile> expectedProfiles;\n        std::vector<uint64_t> xuids{ 1, 2, 3, 4, 5 };\n        for (auto& xuid : xuids)\n        {\n            expectedProfiles.push_back(UserProfile{ xuid });\n        }\n\n        auto mock = std::make_shared<HttpMock>( \"\", \"https://profile.xboxlive.com\" );\n        mock->SetResponseBody(UserProfile::Serialize(expectedProfiles));\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                requestWellFormed = VerifyBatchRequest(requestUrl, requestBody, xuids);\n            }\n        );\n        \n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblProfileGetUserProfilesAsync(xboxLiveContext.get(), xuids.data(), xuids.size(), &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        size_t count{ 0 };\n        VERIFY_SUCCEEDED(XblProfileGetUserProfilesResultCount(&async, &count));\n        VERIFY_ARE_EQUAL_UINT(xuids.size(), count);\n\n        auto profiles{ new XblUserProfile[count] };\n        VERIFY_SUCCEEDED(XblProfileGetUserProfilesResult(&async, count, profiles));\n\n        for (size_t i = 0; i < count; ++i)\n        {\n            VerifyUserProfile(profiles[i], expectedProfiles[i]);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetUserProfilesForSocialGroupAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetUserProfilesForSocialGroupAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<UserProfile> expectedProfiles;\n        std::vector<uint64_t> xuids{ 1, 2 };\n        const char* socialGroup{ \"People\" };\n        for (auto& xuid : xuids)\n        {\n            expectedProfiles.push_back(UserProfile{ xuid });\n        }\n\n        auto mock = std::make_shared<HttpMock>( \"\", \"https://profile.xboxlive.com\" );\n        mock->SetResponseBody(UserProfile::Serialize(expectedProfiles));\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string requestUri, xsapi_internal_string requestBody)\n            {\n                xsapi_internal_stringstream expectedUri;\n                expectedUri << \"https://profile.xboxlive.com/users/me/profile/settings/people/\";\n                expectedUri << socialGroup;\n                expectedUri << \"?settings=AppDisplayName,AppDisplayPicRaw,GameDisplayName,GameDisplayPicRaw,Gamerscore,Gamertag,ModernGamertag,ModernGamertagSuffix,UniqueModernGamertag\";\n\n                requestWellFormed &= (expectedUri.str() == requestUri);\n                requestWellFormed &= requestBody.empty();\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblProfileGetUserProfilesForSocialGroupAsync(xboxLiveContext.get(), socialGroup, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        size_t count{ 0 };\n        VERIFY_SUCCEEDED(XblProfileGetUserProfilesForSocialGroupResultCount(&async, &count));\n        VERIFY_ARE_EQUAL_UINT(xuids.size(), count);\n\n        auto profiles{ new XblUserProfile[count] };\n        VERIFY_SUCCEEDED(XblProfileGetUserProfilesForSocialGroupResult(&async, count, profiles));\n\n        for (size_t i = 0; i < count; ++i)\n        {\n            VerifyUserProfile(profiles[i], expectedProfiles[i]);\n        }\n    }\n\n    DEFINE_TEST_CASE(TestProfileServiceInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestProfileServiceInvalidArgs\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        XAsyncBlock async{};\n\n        TEST_LOG(L\"TestGetUserProfilesAsyncInvalidArgs: Null xboxUserIds param.\");\n        HRESULT hr = XblProfileGetUserProfilesAsync(\n            xboxLiveContext.get(),\n            nullptr, // invalid\n            1,\n            &async\n        );\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n\n        TEST_LOG(L\"TestGetUserProfilesAsyncInvalidArgs: xboxUserIdsCount = 0.\");\n        uint64_t xuid{ 1 };\n        hr = XblProfileGetUserProfilesAsync(\n            xboxLiveContext.get(),\n            &xuid,\n            0, // invalid\n            &async\n        );\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n\n        TEST_LOG(L\"TestGetUserProfilesAsyncInvalidArgs: null socialGroup\");\n        hr = XblProfileGetUserProfilesForSocialGroupAsync(\n            xboxLiveContext.get(),\n            nullptr,\n            &async\n        );\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n    }\n};\n\nuint8_t ProfileTests::UserProfile::nextSuffix{ 1 };\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/RealTimeActivityManagerTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"real_time_activity_manager.h\"\n#include \"real_time_activity_connection.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(RealTimeActivityManagerTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(RealTimeActivityManagerTests)\n\n    class TestSubscription : public real_time_activity::Subscription\n    {\n    public:\n        TestSubscription(\n            String uri = \"https://testsubscription\"\n        ) noexcept\n            : Uri{ m_resourceUri }\n        {\n            m_resourceUri = std::move(uri);\n        }\n\n        Event SubscribeComplete;\n        Event EventReceived;\n\n        uint32_t SubscribeCompleteCount{ 0 };\n        uint32_t EventReceivedCount{ 0 };\n\n        const String& Uri;\n\n    private:\n        void OnSubscribe(const JsonValue& data) noexcept override\n        {\n            UNREFERENCED_PARAMETER(data);\n            SubscribeCompleteCount++;\n            SubscribeComplete.Set();\n        }\n\n        void OnEvent(const JsonValue& data) noexcept override\n        {\n            UNREFERENCED_PARAMETER(data);\n            EventReceivedCount++;\n            EventReceived.Set();\n        }\n\n        void OnResync() noexcept {};\n    };\n\n    struct RtaConnectionMonitor\n    {\n        RtaConnectionMonitor(XblContextHandle xboxLiveContext) noexcept\n        {\n            VERIFY_SUCCEEDED(XblContextDuplicateHandle(xboxLiveContext, &m_xboxLiveContext));\n            m_token = XblRealTimeActivityAddConnectionStateChangeHandler(m_xboxLiveContext, ConnectionStateChanged, this);\n        }\n\n        ~RtaConnectionMonitor() noexcept\n        {\n            XblRealTimeActivityRemoveConnectionStateChangeHandler(m_xboxLiveContext, m_token);\n            XblContextCloseHandle(m_xboxLiveContext);\n        }\n\n        Event Connecting;\n        Event Connected;\n        Event Disconnected;\n\n    private:\n        static void CALLBACK ConnectionStateChanged(void* context, XblRealTimeActivityConnectionState state)\n        {\n            auto pThis{ static_cast<RtaConnectionMonitor*>(context) };\n            switch (state)\n            {\n            case XblRealTimeActivityConnectionState::Connecting:\n            {\n                pThis->Connecting.Set();\n                break;\n            }\n            case XblRealTimeActivityConnectionState::Connected:\n            {\n                pThis->Connected.Set();\n                break;\n            }\n            case XblRealTimeActivityConnectionState::Disconnected:\n            {\n                pThis->Disconnected.Set();\n                break;\n            }\n            }\n        }\n\n        XblContextHandle m_xboxLiveContext{ nullptr };\n        XblFunctionContext m_token{ 0 };\n    };\n\n    DEFINE_TEST_CASE(SubscriptionTest)\n    {\n        TEST_LOG(L\"Test starting: SubscriptionTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRta{ MockRealTimeActivityService::Instance() };\n\n        Event completeSubscribeHandshake;\n        mockRta.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            completeSubscribeHandshake.Wait();\n            mockRta.CompleteSubscribeHandshake(n);\n        });\n\n        // Testing adding and removing subscriptions\n        auto subscription = std::make_shared<TestSubscription>();\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n        completeSubscribeHandshake.Set();\n        subscription->SubscribeComplete.Wait();\n\n        mockRta.RaiseEvent(subscription->Uri.data(), rapidjson::Document{ rapidjson::kObjectType });\n        subscription->EventReceived.Wait(); // data was successfully received and propagated\n\n        VERIFY_SUCCEEDED(rtaManager->RemoveSubscription(xboxLiveContext->User(), subscription));\n    }\n\n    DEFINE_TEST_CASE(TestUnexpectedDataReceived)\n    {\n        TEST_LOG(L\"Test starting: TestUnexpectedDataReceived\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRta{ MockRealTimeActivityService::Instance() };\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        auto subscription = std::make_shared<TestSubscription>();\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n\n        VERIFY_NO_THROW(mockRta.RaiseEvent(subscription->Uri.data(), rapidjson::Document{ rapidjson::kObjectType }));\n    }\n\n    DEFINE_TEST_CASE(SubscriptionStressTest)\n    {\n        TEST_LOG(L\"Test starting: SubscriptionStressTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRta{ MockRealTimeActivityService::Instance() };\n\n        mockRta.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            mockRta.CompleteSubscribeHandshake(n);\n        });\n\n        // Testing adding and removing subscriptions\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n        RtaConnectionMonitor connectionMonitor{ xboxLiveContext.get() };\n\n        constexpr size_t subscriptionCount{ 100 };\n        std::array<std::shared_ptr<TestSubscription>, 100> subscriptions;\n        for (size_t i = 0; i < subscriptions.size(); ++i)\n        {\n            Stringstream uri;\n            uri << \"https://uri\" << i;\n            subscriptions[i] = std::make_shared<TestSubscription>(uri.str());\n            VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscriptions[i]));\n        }\n\n        // Adding connections should force the websocket to be connected\n        connectionMonitor.Connecting.Wait();\n        connectionMonitor.Connected.Wait();\n\n        for (auto& subscription : subscriptions)\n        {\n            subscription->SubscribeComplete.Wait();\n        }\n\n        for (size_t i = 0; i < subscriptions.size(); i += subscriptions.size() / 20)\n        {\n            mockRta.RaiseEvent(subscriptions[i]->Uri.data(), rapidjson::Document{ rapidjson::kObjectType });\n            subscriptions[i]->EventReceived.Wait();\n        }\n\n        // make it reconnect and re-subscribe\n        mockRta.DisconnectClient(xboxLiveContext->Xuid());\n        connectionMonitor.Connecting.Wait();\n        connectionMonitor.Connected.Wait();\n\n        for (auto& subscription : subscriptions)\n        {\n            subscription->SubscribeComplete.Wait();\n        }\n\n        // stress test adding and removing subscriptions quickly\n        for (auto& subscription : subscriptions)\n        {\n            VERIFY_SUCCEEDED(rtaManager->RemoveSubscription(xboxLiveContext->User(), subscription));\n\t\t\tsubscription = std::make_shared<TestSubscription>(subscription->Uri);\n            VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n            VERIFY_SUCCEEDED(rtaManager->RemoveSubscription(xboxLiveContext->User(), subscription));\n        }\n\n        // Socket should automatically disconnect after all subs are removed\n        connectionMonitor.Disconnected.Wait();\n    }\n\n    DEFINE_TEST_CASE(TestUnsubscribeOnPendingSubscribeState)\n    {\n        TEST_LOG(L\"Test starting: TestUnsubscribeOnPendingSubscribeState\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        Event websocketConnectCompletion;\n        MockWebsocket::SetConnectHandler([&]\n        {\n            // Don't complete connection immediately\n            websocketConnectCompletion.Wait();\n            return WebsocketResult{ S_OK };\n        });\n\n        RtaConnectionMonitor monitor{ xboxLiveContext.get() };\n\n        auto subscription = std::make_shared<TestSubscription>();\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n\n        // Wait for state change to connecting \n        monitor.Connecting.Wait();\n\n        VERIFY_SUCCEEDED(rtaManager->RemoveSubscription(xboxLiveContext->User(), subscription));\n\t\tsubscription = std::make_shared<TestSubscription>();\n\n        websocketConnectCompletion.Set();\n\n        // 2. Make websocket connected and try it again with holding subscribe handshake response.\n        MockWebsocket::SetConnectHandler(nullptr);\n\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n        VERIFY_SUCCEEDED(rtaManager->RemoveSubscription(xboxLiveContext->User(), subscription));\n\n        // Verify the subscription was never completed\n        VERIFY_ARE_EQUAL_UINT(0u, subscription->SubscribeCompleteCount);\n    }\n\n    DEFINE_TEST_CASE(NoConnectionTest)\n    {\n        TEST_LOG(L\"Test starting: NoConnectionTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        RtaConnectionMonitor connectionMonitor{ xboxLiveContext.get() };\n\n        MockWebsocket::SetConnectHandler([] { return WebsocketResult{ E_FAIL }; });\n\n        auto subscription = std::make_shared<TestSubscription>();\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n\n        connectionMonitor.Connecting.Wait();\n        connectionMonitor.Disconnected.Wait();\n\n        MockWebsocket::SetConnectHandler(nullptr);\n\n        connectionMonitor.Connected.Wait();\n    }\n\n    DEFINE_TEST_CASE(TestConnectionInterrupt)\n    {\n        TEST_LOG(L\"Test starting: TestConnectionInterrupt\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        auto& mockRta{ MockRealTimeActivityService::Instance() };\n        mockRta.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            mockRta.CompleteSubscribeHandshake(n);\n        });\n\n        RtaConnectionMonitor connectionMonitor{ xboxLiveContext.get() };\n\n        auto subscription = std::make_shared<TestSubscription>();\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n\n        connectionMonitor.Connecting.Wait();\n        connectionMonitor.Connected.Wait();\n        subscription->SubscribeComplete.Wait();\n\n        // force to close and not able to reconnect\n        MockWebsocket::SetConnectHandler([] { return WebsocketResult{ E_FAIL }; });\n        mockRta.DisconnectClient(xboxLiveContext->Xuid());\n\n        connectionMonitor.Disconnected.Wait();\n\n        MockWebsocket::SetConnectHandler(nullptr);\n        connectionMonitor.Connected.Wait();\n        subscription->SubscribeComplete.Wait();\n\n        // Make sure we can receive an event on re-established connection\n        mockRta.RaiseEvent(subscription->Uri.data(), rapidjson::Document{ rapidjson::kObjectType });\n        subscription->EventReceived.Wait();\n\n        VERIFY_SUCCEEDED(rtaManager->RemoveSubscription(xboxLiveContext->User(), subscription));\n    }\n\n    DEFINE_TEST_CASE(RTAResync)\n    {\n        TEST_LOG(L\"Test starting: RTAResync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        auto& mockRta{ MockRealTimeActivityService::Instance() };\n        mockRta.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            mockRta.CompleteSubscribeHandshake(n);\n        });\n\n        Event resyncCallbackReceived;\n        rtaManager->AddResyncHandler(xboxLiveContext->User(), [&]\n        {\n            resyncCallbackReceived.Set();\n        });\n\n        auto subscription = std::make_shared<TestSubscription>();\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n        subscription->SubscribeComplete.Wait();\n\n        MockRealTimeActivityService::Instance().RaiseResync();\n        resyncCallbackReceived.Wait();\n    }\n\n    DEFINE_TEST_CASE(TestServiceThrottleError)\n    {\n        TEST_LOG(L\"Test starting: TestServiceThrottleError\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto rtaManager{ GlobalState::Get()->RTAManager() };\n\n        // Have MockRTA service respond with a throttle error the first time we try to subscribe.\n        // RTAManager should auto retry the subscription after a small backoff. Subsequent subscribe attempts will\n        // be responded to with success code\n        auto& mockRta{ MockRealTimeActivityService::Instance() };\n        uint8_t subscribeAttempts{ 0 };\n\n        mockRta.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            if (subscribeAttempts++ == 0)\n            {\n                mockRta.CompleteSubscribeHandshake(n, rapidjson::Document{ rapidjson::kNullType }, MockRealTimeActivityService::ErrorCode::Throttled);\n            }\n            else\n            {\n                mockRta.CompleteSubscribeHandshake(n);\n            }\n        });\n\n        auto subscription = std::make_shared<TestSubscription>();\n        VERIFY_SUCCEEDED(rtaManager->AddSubscription(xboxLiveContext->User(), subscription));\n        subscription->SubscribeComplete.Wait();\n\n        VERIFY_ARE_EQUAL_UINT(2, subscribeAttempts);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/ReputationTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nusing namespace xbox::services::social;\nusing namespace xbox::services::multiplayer;\n\n// response sample from http://xboxwiki/wiki/Reputation#Submit_Feedback\nconst char expectedBatchRequestBody[] = R\"({\n    \"items\" :\n    [\n        {\n            \"targetXuid\": \"33445566778899\",\n            \"titleId\" : null,\n            \"sessionRef\":\n            {\n                \"scid\": \"372D829B-FA8E-471F-B696-07B61F09EC20\",\n                \"templateName\": \"CaptureFlag5\",\n                \"name\": \"Halo556932\"\n            },\n            \"feedbackType\": \"FairPlayKillsTeammates\",\n            \"textReason\": \"Title detected this player killing team members 19 times in this session\",\n            \"evidenceId\": null\n        },\n        {\n            \"targetXuid\": \"33445566778899\",\n            \"titleId\" : null,\n            \"sessionRef\":\n            {\n                \"scid\": \"372D829B-FA8E-471F-B696-07B61F09EC20\",\n                \"templateName\": \"CaptureFlag5\",\n                \"name\": \"Halo556932\"\n            },\n            \"feedbackType\": \"FairPlayQuitter\",\n            \"textReason\": \"Title detected quitting before the session was over\",\n            \"evidenceId\": null\n        }\n    ]\n})\";\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(ReputationTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(ReputationTests);\n\n    DEFINE_TEST_CASE(TestSubmitReputationFeedbackAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSubmitReputationFeedbackAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto reputationMock = std::make_shared<HttpMock>( \"POST\", \"https://reputation.xboxlive.com\", 202 );\n\n        bool requestWellFormed{ true };\n        reputationMock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string url, xsapi_internal_string requestBody)\n            {\n                requestWellFormed &= url == \"https://reputation.xboxlive.com/users/xuid(1)/feedback\";\n\n                // response sample from http://xboxwiki/wiki/Reputation#Submit_Feedback\n                auto expectedBody = R\"({\n                    \"sessionRef\":\n                    {\n                        \"scid\": \"372D829B-FA8E-471F-B696-07B61F09EC20\",\n                        \"templateName\": \"CaptureFlag5\",\n                        \"name\": \"Halo556932\"\n                    },\n                    \"feedbackType\": \"CommsAbusiveVoice\",\n                    \"textReason\": \"They called me a doodoo-head!\",\n                    \"evidenceId\": null\n                })\";\n\n                JsonDocument expectedBodyJson;\n                JsonDocument requestBodyJson;\n                expectedBodyJson.Parse(expectedBody);\n                requestBodyJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedBodyJson == requestBodyJson;\n            });\n\n        XAsyncBlock async{};\n        XblMultiplayerSessionReference sessionRef{ \"372D829B-FA8E-471F-B696-07B61F09EC20\", \"CaptureFlag5\", \"Halo556932\" };\n\n        XblSocialSubmitReputationFeedbackAsync(\n            xboxLiveContext.get(),\n            1,\n            XblReputationFeedbackType::CommunicationsAbusiveVoice,\n            &sessionRef,\n            \"They called me a doodoo-head!\",\n            nullptr,\n            &async\n        );\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(CppTestSubmitReputationFeedback)\n    {\n        TEST_LOG(L\"Test starting: CppTestSubmitReputationFeedback\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        auto reputationMock = std::make_shared<HttpMock>( \"POST\", \"https://reputation.xboxlive.com\", 202 );\n\n        bool requestWellFormed{ true };\n\n        reputationMock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string url, xsapi_internal_string requestBody)\n            {\n                requestWellFormed &= url == \"https://reputation.xboxlive.com/users/xuid(1)/feedback\";\n\n                // response sample from http://xboxwiki/wiki/Reputation#Submit_Feedback\n                auto expectedBody = R\"({\n                    \"sessionRef\": null,\n                    \"feedbackType\": \"CommsAbusiveVoice\",\n                    \"textReason\": \"They called me a doodoo-head!\",\n                    \"evidenceId\": null\n                })\";\n\n                JsonDocument expectedBodyJson;\n                JsonDocument requestBodyJson;\n                expectedBodyJson.Parse(expectedBody);\n                requestBodyJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedBodyJson == requestBodyJson;\n            });\n\n        auto task = xboxLiveContext->reputation_service().submit_reputation_feedback(\n            _T(\"1\"),\n            reputation_feedback_type::communications_abusive_voice,\n            string_t{},\n            _T(\"They called me a doodoo-head!\")\n        );\n\n        VERIFY_IS_TRUE(!task.get().err());\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestSubmitBatchReputationFeedbackAsync)\n    {\n        TEST_LOG(L\"Test starting: TestSubmitBatchReputationFeedbackAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto reputationMock = std::make_shared<HttpMock>(\"POST\", \"https://reputation.xboxlive.com\", 202 );\n\n        bool requestWellFormed{ true };\n        reputationMock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string url, xsapi_internal_string requestBody)\n            {\n                requestWellFormed &= url == \"https://reputation.xboxlive.com/users/batchtitlefeedback\";\n                JsonDocument expectedBodyJson;\n                JsonDocument requestBodyJson;\n                expectedBodyJson.Parse(expectedBatchRequestBody);\n                requestBodyJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedBodyJson == requestBodyJson;\n            });\n\n        XAsyncBlock async{};\n        XblMultiplayerSessionReference sessionRef{ \"372D829B-FA8E-471F-B696-07B61F09EC20\", \"CaptureFlag5\", \"Halo556932\" };\n\n        std::vector<XblReputationFeedbackItem> feedbackItems;\n        feedbackItems.push_back(XblReputationFeedbackItem{\n            33445566778899,\n            XblReputationFeedbackType::FairPlayKillsTeammates,\n            &sessionRef,\n            \"Title detected this player killing team members 19 times in this session\",\n            nullptr\n        });\n        feedbackItems.push_back(XblReputationFeedbackItem{\n            33445566778899,\n            XblReputationFeedbackType::FairPlayQuitter,\n            &sessionRef,\n            \"Title detected quitting before the session was over\",\n            nullptr\n        });\n\n        XblSocialSubmitBatchReputationFeedbackAsync(\n            xboxLiveContext.get(),\n            feedbackItems.data(),\n            feedbackItems.size(),\n            &async\n        );\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(CppTestSubmitBatchReputationFeedback)\n    {\n        TEST_LOG(L\"Test starting: CppTestSubmitBatchReputationFeedback\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        auto reputationMock = std::make_shared<HttpMock>(\"POST\", \"https://reputation.xboxlive.com\", 202 );\n\n        bool requestWellFormed{ true };\n        reputationMock->SetMockMatchedCallback(\n            [&](HttpMock*, xsapi_internal_string url, xsapi_internal_string requestBody)\n            {\n                requestWellFormed &= url == \"https://reputation.xboxlive.com/users/batchtitlefeedback\";\n                JsonDocument expectedBodyJson;\n                JsonDocument requestBodyJson;\n                expectedBodyJson.Parse(expectedBatchRequestBody);\n                requestBodyJson.Parse(requestBody.c_str());\n\n                requestWellFormed &= expectedBodyJson == requestBodyJson;\n            });\n\n        multiplayer_session_reference sessionRef{ _T(\"372D829B-FA8E-471F-B696-07B61F09EC20\"), _T(\"CaptureFlag5\"), _T(\"Halo556932\") };\n\n        std::vector<reputation_feedback_item> feedbackItems;\n        feedbackItems.push_back(reputation_feedback_item{\n            _T(\"33445566778899\"),\n            reputation_feedback_type::fair_play_kills_teammates,\n            sessionRef,\n            _T(\"Title detected this player killing team members 19 times in this session\"),\n        });\n        feedbackItems.push_back(reputation_feedback_item{\n            _T(\"33445566778899\"),\n            reputation_feedback_type::fair_play_quitter,\n            sessionRef,\n            _T(\"Title detected quitting before the session was over\"),\n        });\n\n        auto task = xboxLiveContext->reputation_service().submit_batch_reputation_feedback(feedbackItems);\n\n        VERIFY_IS_TRUE(!task.get().err());\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    DEFINE_TEST_CASE(TestSubmitReputationFeedbackAsyncInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestSubmitReputationFeedbackAsyncInvalidArgs\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        XAsyncBlock async{};\n        auto hr = XblSocialSubmitReputationFeedbackAsync(\n            xboxLiveContext.get(),\n            1,\n            XblReputationFeedbackType::FairPlayCheater,\n            nullptr,\n            nullptr, // Invalid arg\n            nullptr,\n            &async\n        );\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n\n        hr = XblSocialSubmitReputationFeedbackAsync(\n            xboxLiveContext.get(),\n            1,\n            XblReputationFeedbackType::FairPlayCheater,\n            nullptr,\n            \"Reason message\",\n            nullptr,\n            nullptr // Invalid arg\n        );\n        VERIFY_ARE_EQUAL(E_INVALIDARG, hr);\n    }\n};\n\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/SocialManagerTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"xsapi-c/social_manager_c.h\"\n#include \"xsapi-cpp/social_manager.h\"\n#include \"social_manager_internal.h\"\n\nusing namespace xbox::services::presence;\nusing namespace xbox::services::real_time_activity;\nusing namespace xbox::services::social::manager;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char defaultPeoplehubTemplate[] = R\"(\n{\n    \"xuid\": \"1\",\n    \"isFavorite\": false,\n    \"isFollowingCaller\": true,\n    \"isFollowedByCaller\": true,\n    \"isIdentityShared\": false,\n    \"displayName\": \"TestGamerTag\",\n    \"realName\": \"\",\n    \"displayPicRaw\": \"http://images-eds.xboxlive.com/image?url=mHGRD8KXEf2sp2LC58XhBQKNl2IWRp.J.q8mSURKUUeiPPf0Y7Kl7zLN7rafayiPptVaX_XIUmNOPotNmNubbx4bHmf6It7Oj1ChU5UAo9k-&background=0xababab&mode=Padding&format=png\",\n    \"useAvatar\": false,\n    \"gamertag\": \"TestGamerTag\",\n    \"modernGamertag\": \"TestGamerTag\",\n    \"modernGamertagSuffix\": \"\",\n    \"uniqueModernGamertag\": \"TestGamerTag\",\n    \"gamerScore\": \"9001\",\n    \"presenceState\": \"Online\",\n    \"presenceDevices\": null,\n    \"isBroadcasting\": false,\n    \"titleHistory\": \n    {\n        \"titleName\": \"Forza Horizon 2\",\n        \"titleId\": \"1234\",\n        \"lastTimePlayed\": \"2015-01-26T22:54:54.6630000Z\",\n        \"lastTimePlayedText\": \"8 months ago\"\n    },\n    \"suggestion\": null,\n    \"multiplayerSummary\": {\n        \"InMultiplayerSession\": 0,\n        \"InParty\": 0\n    },\n    \"recentPlayer\": null,\n    \"follower\": null,\n    \"preferredColor\": {\n        \"primaryColor\": \"193e91\",\n        \"secondaryColor\": \"2458cf\",\n        \"tertiaryColor\": \"122e6b\"\n    },\n    \"titlePresence\": null,\n    \"titleSummaries\": null,\n    \"presenceDetails\": [{\n        \"IsBroadcasting\": false,\n        \"Device\": \"PC\",\n        \"State\": \"Active\",\n        \"TitleId\": \"1234\",\n        \"PresenceText\": \"Home\"\n    }]\n    }\n)\";\n\nconst char onlinePresenceResponseTemplate[] = R\"(\n{\n    \"xuid\": \"1\",\n    \"state\": \"Online\",\n    \"devices\": [\n        {\n            \"type\": \"PC\",\n            \"titles\": [\n                {\n                    \"id\": \"1234\",\n                    \"name\": \"awesomeGame\",\n                    \"lastModified\": \"2013-02-01T00:00:00Z\",\n                    \"state\": \"active\",\n                    \"placement\": \"Full\",\n                    \"activity\": {\n                        \"richPresence\": \"Home\"\n                    }\n                }\n            ]\n        }\n    ]\n})\";\n\nconst char offlinePresenceResponseTemplate[] = R\"(\n{\n    \"xuid\": \"1\",\n    \"state\": \"Offline\",\n    \"devices\": []\n}\n)\";\n\nconst char* presenceOnlineRtaMessageSubscribeComplete = R\"({\"xuid\":\"2814613569642996\",\"state\":\"Online\",\"devices\":[{\"type\":\"MCapensis\",\"titles\":[{\"id\":\"1234\",\"name\":\"Default Title\",\"placement\":\"Full\",\"state\":\"Active\", \"activity\": {\"richPresence\":\"Home\"}, \"lastModified\":\"2016-09-30T00:15:35.5994615Z\"}]}]})\";\nconst char* presenceOfflineRtaMessageSubscribeComplete = R\"({\"xuid\":\"2814613569642996\",\"state\":\"Offline\"})\";\n\n#define NUM_USERS 100\n\nDEFINE_TEST_CLASS(SocialManagerTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(SocialManagerTests);\n\nprivate:\n    // RAII class for basic SocialManager Test Setup/teardown including relevant mocks\n    class SMTestEnvironment : public TestEnvironment\n    {\n    public:\n        SMTestEnvironment() noexcept\n        {\n            FollowedXuids.reserve(NUM_USERS);\n            for (uint64_t i = 0; i < NUM_USERS; ++i)\n            {\n                FollowedXuids.push_back(i + 1);\n            }\n\n            MockRtaService().SetSubscribeHandler(RTASubscribeHandler);\n\n            // Setup default presence and peoplehub mocks\n            SetPeoplehubMock();\n            SetPresenceMock();\n        }\n\n        ~SMTestEnvironment() noexcept\n        {\n            // Remove all local users\n            size_t userCount = XblSocialManagerGetLocalUserCount();\n            auto users{ new XblUserHandle[userCount] };\n            VERIFY_SUCCEEDED(XblSocialManagerGetLocalUsers(userCount, users));\n\n            for (size_t i = 0; i < userCount; ++i)\n            {\n                VERIFY_SUCCEEDED(XblSocialManagerRemoveLocalUser(users[i]));\n            }\n\n#if ENABLE_PERF_PROFILING\n            TEST_LOG(Utils::StringTFromUtf8(detail::PerfTester::Instance().FormatStats().data()).data());\n#endif\n        }\n\n        // CPP helpers wrapping SocialManager APIs\n\n        // Add local user and validate the expected events are received\n        void AddLocalUser(const User& user) const noexcept\n        {\n            LOGS_DEBUG << \"Adding User to SocialManager and awaiting LocalUserAdded and RTA subscriptions\";\n\n            // As a testing convenience, await sub handshakes to complete so that tests can fire\n            // RTA events and be sure that the social graph is prepared to respond to them\n            struct RTASubResponder\n            {\n                RTASubResponder(size_t followeeCount)\n                {\n                    auto& rtaService{ system::MockRealTimeActivityService::Instance() };\n                    rtaService.SetSubscribeHandler([=](uint32_t n, xsapi_internal_string uri)\n                    {\n                        SMTestEnvironment::RTASubscribeHandler(n, uri);\n                        if (uri.find(\"https://userpresence.xboxlive.com\") != xsapi_internal_string::npos)\n                        {\n                            ++presenceSubsComplete;\n                        }\n                        else if (uri.find(\"http://social.xboxlive.com\") != xsapi_internal_string::npos)\n                        {\n                            socialRelationshipSubComplete = true;\n                        }\n\n                        // Graph will create two presence subscriptions for each followed User (Device & title presence)\n                        if (presenceSubsComplete >= followeeCount * 2 && socialRelationshipSubComplete)\n                        {\n                            complete.Set();\n                        }\n                    });\n                }\n\n                ~RTASubResponder()\n                {\n                    // Reset to default handler\n                    system::MockRealTimeActivityService::Instance().SetSubscribeHandler(SMTestEnvironment::RTASubscribeHandler);\n                }\n\n                size_t presenceSubsComplete{ 0 };\n                bool socialRelationshipSubComplete{ false };\n                Event complete{};\n            } rtaResponder{ FollowedXuids.size() };\n\n            VERIFY_SUCCEEDED(XblSocialManagerAddLocalUser(user.Handle(), XblSocialManagerExtraDetailLevel::NoExtraDetail, nullptr));\n            AwaitEvents({ {XblSocialManagerEventType::LocalUserAdded, 1} });\n            rtaResponder.complete.Wait();\n        }\n\n        std::vector<const XblSocialManagerEvent*> DoWork() const noexcept\n        {\n            const XblSocialManagerEvent* events{ nullptr };\n            size_t eventCount{ 0 };\n            HRESULT hr = XblSocialManagerDoWork(&events, &eventCount);\n            if (FAILED(hr))\n            {\n                VERIFY_FAIL(); // avoiding log spam\n            }\n\n            auto eventsVector = Utils::Transform<const XblSocialManagerEvent*>(events, eventCount, [](const XblSocialManagerEvent& e) { return &e; });\n            LogEvents(eventsVector);\n            return eventsVector;\n        }\n\n        // DoWork until the specified events happen.\n        void AwaitEvents(std::map<XblSocialManagerEventType, size_t> expectedEvents) const noexcept\n        {\n            while (!expectedEvents.empty())\n            {\n                auto events{ DoWork() };\n                for (auto event : events)\n                {\n                    auto iter{ expectedEvents.find(event->eventType) };\n                    if (iter == expectedEvents.end())\n                    {\n                        LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                        VERIFY_FAIL();\n                    }\n                    else if(--iter->second == 0)\n                    {\n                        expectedEvents.erase(iter);\n                    }\n                }\n            }\n        }\n\n        std::vector<const XblSocialManagerUser*> GetUsers(\n            XblSocialManagerUserGroupHandle group\n        ) const noexcept\n        {\n            const XblSocialManagerUser* const* users{ nullptr };\n            size_t userCount{ 0 };\n            VERIFY_SUCCEEDED(XblSocialManagerUserGroupGetUsers(group, &users, &userCount));\n            return std::vector<const XblSocialManagerUser*>(users, users + userCount);\n        }\n\n        size_t GetUsersCount(\n            XblSocialManagerUserGroupHandle group\n        ) const noexcept\n        {\n            const XblSocialManagerUser* const* users{ nullptr };\n            size_t userCount{ 0 };\n            VERIFY_SUCCEEDED(XblSocialManagerUserGroupGetUsers(group, &users, &userCount));\n            return userCount;\n        }\n\n        size_t GetTrackedUsersCount(\n            XblSocialManagerUserGroupHandle group\n        ) const noexcept\n        {\n            const uint64_t* trackedUsers{ nullptr };\n            size_t userCount{ 0 };\n            VERIFY_SUCCEEDED(XblSocialManagerUserGroupGetUsersTrackedByGroup(group, &trackedUsers, &userCount));\n            return userCount;\n        }\n\n        // Configure Mocks used by SocialManager\n        void SetPeoplehubMock(\n            bool online = true,\n            bool isFavorite = false,\n            bool isFollowedByCaller = true\n        ) noexcept\n        {\n            // No HTTP method so it matches both batch and get friends calls\n            m_peoplehubMock = std::make_shared<HttpMock>(\"\", \"https://peoplehub.xboxlive.com\");\n\n            m_peoplehubMock->SetMockMatchedCallback(\n                [\n                    this,\n                    online,\n                    isFavorite,\n                    isFollowedByCaller\n                ]\n            (HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n                {\n                    std::vector<uint64_t> xuids;\n\n                    auto jsonRequest = Utils::ParseJson(requestBody.data());\n                    if (jsonRequest.is_null())\n                    {\n                        xuids = this->FollowedXuids;\n                    }\n                    else\n                    {\n                        auto xuidArray = jsonRequest[L\"xuids\"];\n                        for (size_t i = 0; i < xuidArray.size(); ++i)\n                        {\n                            xuids.push_back(Utils::Uint64FromStringT(xuidArray[i].as_string()));\n                        }\n                    }\n\n                    JsonDocument responseBody(rapidjson::kObjectType);\n                    JsonDocument::AllocatorType& allocator = responseBody.GetAllocator();\n\n                    JsonValue peopleArray(rapidjson::kArrayType);\n                    for (auto& xuid : xuids)\n                    {\n                        JsonDocument jsonBlob(&allocator);\n                        jsonBlob.Parse(defaultPeoplehubTemplate);\n                        JsonUtils::SetMember(jsonBlob, \"xuid\", JsonValue(utils::uint64_to_internal_string(xuid).c_str(), allocator));\n                        JsonUtils::SetMember(jsonBlob, \"presenceState\", JsonValue((online ? \"Online\" : \"Offline\"), allocator));\n                        JsonUtils::SetMember(jsonBlob, \"isFavorite\", JsonValue(isFavorite));\n                        JsonUtils::SetMember(jsonBlob, \"isFollowedByCaller\", JsonValue(isFollowedByCaller));\n                        peopleArray.PushBack(jsonBlob, allocator);\n                    }\n\n                    \n                    responseBody.AddMember(\"people\", peopleArray, allocator);\n                    mock->SetResponseBody(responseBody);\n                });\n        }\n\n        // Presence service will respond that all users are online except for those specified in offlineXuids\n        void SetPresenceMock(\n            const std::vector<uint64_t>& offlineXuids = {},\n            uint32_t titleId = MOCK_TITLEID\n        ) noexcept\n        {\n            m_presenceMock = std::make_shared<HttpMock>(\"GET\", \"https://userpresence.xboxlive.com\");\n\n            m_presenceMock->SetMockMatchedCallback(\n                [\n                    offlineXuids = std::unordered_set<uint64_t>{ offlineXuids.begin(), offlineXuids.end() },\n                    titleId\n                ]\n            (HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody) mutable\n                {\n                    SetPresenceResponse(mock, requestUrl, requestBody, std::move(offlineXuids), titleId);\n                });\n        }\n\n        void FireDevicePresenceChangeRtaEvent(\n            const std::vector<uint64_t>& userList,\n            bool online = false\n        ) const noexcept\n        {\n            for (auto xuid : userList)\n            {\n                xsapi_internal_stringstream uri;\n                uri << \"https://userpresence.xboxlive.com/users/xuid(\" << xuid << \")/devices\";\n\n                MockRealTimeActivityService::Instance().RaiseEvent(uri.str(), online ? R\"(\"PC:true\")\" : R\"(\"PC:false\")\");\n            }\n        }\n\n        void FireTitlePresenceChangeRtaEvent(\n            const std::vector<uint64_t>& userList,\n            bool ended = true\n        ) const noexcept\n        {\n            for (auto xuid : userList)\n            {\n                xsapi_internal_stringstream uri;\n                uri << \"https://userpresence.xboxlive.com/users/xuid(\" << xuid << \")/titles/1234\";\n\n                MockRealTimeActivityService::Instance().RaiseEvent(uri.str(), ended ? R\"(\"ended\")\" : R\"(\"started\")\");\n            }\n        }\n\n        void FireSocialGraphChangedRtaEvent(\n            const User& localUser,\n            XblSocialNotificationType notificationType,\n            uint64_t affectedXuid\n        ) const noexcept\n        {\n            xsapi_internal_stringstream uri;\n            uri << \"http://social.xboxlive.com/users/xuid(\" << localUser.Xuid() << \")/friends\";\n\n            rapidjson::Document eventData{ rapidjson::kObjectType };\n            auto& a{ eventData.GetAllocator() };\n\n            eventData.AddMember(\"NotificationType\", rapidjson::Value{ EnumName(notificationType).data(), a }, a);\n            rapidjson::Value eventDataXuids{ rapidjson::kArrayType };\n            eventDataXuids.PushBack(rapidjson::Value{ Utils::StringFromUint64(affectedXuid).c_str(), a }.Move(), a);\n            eventData.AddMember(\"Xuids\", eventDataXuids.Move(), a);\n\n            MockRealTimeActivityService::Instance().RaiseEvent(uri.str(), eventData);\n        }\n\n        // Xuids Local Users follow\n        std::vector<uint64_t> FollowedXuids;\n\n    private:\n        static void RTASubscribeHandler(uint32_t n, xsapi_internal_string uri)\n        {\n            auto& rtaService{ system::MockRealTimeActivityService::Instance() };\n            if (uri.find(\"https://userpresence.xboxlive.com\") != xsapi_internal_string::npos)\n            {\n                rtaService.CompleteSubscribeHandshake(n, presenceOnlineRtaMessageSubscribeComplete);\n            }\n            else if (uri.find(\"http://social.xboxlive.com\") != xsapi_internal_string::npos)\n            {\n                rtaService.CompleteSubscribeHandshake(n);\n            }\n        }\n\n        static size_t SetPresenceResponse(\n            HttpMock* mock,\n            const xsapi_internal_string& requestUrl,\n            const xsapi_internal_string& requestBody,\n            std::unordered_set<uint64_t>&& offlineXuids = {},\n            uint32_t titleId = MOCK_TITLEID\n        )\n        {\n            JsonDocument userArr{};\n            if (requestUrl.find(\"batch\") != xsapi_internal_string::npos)\n            {\n                // for batch requests the user list is in the request body\n                JsonDocument jsonRequest{ rapidjson::kObjectType };\n                jsonRequest.Parse(requestBody.data());\n                userArr.CopyFrom(jsonRequest[\"users\"], userArr.GetAllocator());\n                assert(userArr.IsArray());\n            }\n            else\n            {\n                assert(requestBody.empty());\n                userArr.SetArray();\n                auto beginIndex{ requestUrl.find(\"(\") };\n                auto endIndex{ requestUrl.find(\")\") };\n                userArr.PushBack(JsonValue{ requestUrl.substr(beginIndex + 1, endIndex - beginIndex - 1).data(), userArr.GetAllocator() }, userArr.GetAllocator());\n            }\n\n            JsonDocument response(rapidjson::kArrayType);\n            JsonDocument::AllocatorType& allocator = response.GetAllocator();\n            for (uint32_t i = 0; i < userArr.Size(); ++i)\n            {\n                if (offlineXuids.find(utils::internal_string_to_uint64(userArr[i].GetString())) == offlineXuids.end())\n                {\n                    JsonDocument onlinePresenceResponseTemplateJson(&allocator);\n                    onlinePresenceResponseTemplateJson.Parse(onlinePresenceResponseTemplate);\n                    response.PushBack(onlinePresenceResponseTemplateJson, allocator);\n                    JsonUtils::SetMember(response[i][\"devices\"][0][\"titles\"][0], allocator, \"id\", JsonValue(utils::uint32_to_internal_string(titleId).c_str(), allocator));\n                }\n                else\n                {\n                    JsonDocument offlinePresenceResponseTemplateJson(&allocator);\n                    offlinePresenceResponseTemplateJson.Parse(offlinePresenceResponseTemplate);\n                    response.PushBack(offlinePresenceResponseTemplateJson, allocator);\n                }\n                JsonUtils::SetMember(response[i], allocator, \"xuid\", userArr[i]);\n            }\n\n            mock->SetResponseBody(response);\n\n            return userArr.Size();\n        }\n\n        void LogEvents(\n            const std::vector<const XblSocialManagerEvent*>& events\n        ) const noexcept\n        {\n            static std::unordered_map<XblSocialManagerEventType, xsapi_internal_string> eventTypesMap\n            {\n                { XblSocialManagerEventType::UsersAddedToSocialGraph, \"UsersAddedToSocialGraph\" },\n                { XblSocialManagerEventType::UsersRemovedFromSocialGraph, \"UsersRemovedFromSocialGraph\" },\n                { XblSocialManagerEventType::PresenceChanged, \"PresenceChanged\" },\n                { XblSocialManagerEventType::ProfilesChanged, \"ProfilesChanged\" },\n                { XblSocialManagerEventType::SocialRelationshipsChanged, \"SocialRelationshipsChanged\" },\n                { XblSocialManagerEventType::LocalUserAdded, \"LocalUserAdded\" },\n                { XblSocialManagerEventType::SocialUserGroupLoaded, \"SocialUserGroupLoaded\" },\n                { XblSocialManagerEventType::SocialUserGroupUpdated, \"SocialUserGroupUpdated\" },\n                { XblSocialManagerEventType::UnknownEvent, \"UnknownEvent\" }\n            };\n\n            for (auto& event : events)\n            {\n                xsapi_internal_stringstream ss;\n                ss << \"SocialManager Event: \" << eventTypesMap[event->eventType] << std::endl;\n                for (uint32_t i = 0; i < XBL_SOCIAL_MANAGER_MAX_AFFECTED_USERS_PER_EVENT; i++)\n                {\n                    if (event->usersAffected[i] != nullptr)\n                    {\n                        if (i == 0)\n                        {\n                            ss << \"Users affected: \" << std::endl;\n                        }\n                        ss << \"\\t\" << event->usersAffected[i]->xboxUserId << std::endl;\n                    }\n                }\n                LOGS_DEBUG << ss.str();\n            }\n        }\n\n        // Default mocks used by SocialManager\n        std::shared_ptr<HttpMock> m_peoplehubMock;\n        std::shared_ptr<HttpMock> m_presenceMock;\n    };\n\npublic:\n    DEFINE_TEST_CASE(TestAddLocalUser)\n    {\n        TEST_LOG(L\"Test starting: TestAddLocalUser\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext{ env.CreateMockXboxLiveContext() };\n        env.AddLocalUser(xboxLiveContext->User());\n    }\n\n    DEFINE_TEST_CASE(TestBasicCreateFilterGroup)\n    {\n        TEST_LOG(L\"Test starting: TestBasicCreateFilterGroup\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext{ env.CreateMockXboxLiveContext() };\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblSocialManagerUserGroupHandle filterGroup{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &filterGroup\n        ));\n\n        bool groupLoaded{ false };\n        while (!groupLoaded)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == filterGroup);\n                    groupLoaded = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        auto users{ env.GetUsers(filterGroup) };\n        VERIFY_ARE_EQUAL(env.GetTrackedUsersCount(filterGroup), users.size());\n\n        for (auto user : users)\n        {\n            // profile tests\n            LOGS_DEBUG << \"Validating user \" << user->xboxUserId;\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->displayName);\n            VERIFY_ARE_EQUAL_STR(\"http://images-eds.xboxlive.com/image?url=mHGRD8KXEf2sp2LC58XhBQKNl2IWRp.J.q8mSURKUUeiPPf0Y7Kl7zLN7rafayiPptVaX_XIUmNOPotNmNubbx4bHmf6It7Oj1ChU5UAo9k-&background=0xababab&mode=Padding&format=png\", user->displayPicUrlRaw);\n            VERIFY_IS_TRUE(user->isFollowedByCaller);\n            VERIFY_IS_TRUE(user->isFollowingUser);\n            VERIFY_ARE_EQUAL_STR(\"9001\", user->gamerscore);\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->gamertag);\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->modernGamertag);\n            VERIFY_ARE_EQUAL_STR(\"\", user->modernGamertagSuffix);\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->uniqueModernGamertag);\n            VERIFY_IS_FALSE(user->isFavorite);\n            VERIFY_IS_FALSE(user->useAvatar);\n\n            // preferred color tests\n            VERIFY_ARE_EQUAL_STR(\"193e91\", user->preferredColor.primaryColor);\n            VERIFY_ARE_EQUAL_STR(\"2458cf\", user->preferredColor.secondaryColor);\n            VERIFY_ARE_EQUAL_STR(\"122e6b\", user->preferredColor.tertiaryColor);\n\n            // presence record tests\n            VERIFY_IS_TRUE(user->presenceRecord.presenceTitleRecordCount == 1);\n            VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Online);\n            VERIFY_IS_TRUE(XblSocialManagerPresenceRecordIsUserPlayingTitle(&user->presenceRecord, 1234));\n            VERIFY_IS_TRUE(user->presenceRecord.presenceTitleRecords[0].isTitleActive);\n            VERIFY_IS_TRUE(!user->presenceRecord.presenceTitleRecords[0].isBroadcasting);\n            VERIFY_IS_TRUE(user->presenceRecord.presenceTitleRecords[0].deviceType == XblPresenceDeviceType::PC);\n            VERIFY_ARE_EQUAL_STR(\"Home\", user->presenceRecord.presenceTitleRecords[0].presenceText);\n\n            // title history tests\n            VERIFY_IS_TRUE(user->titleHistory.hasUserPlayed);\n            VERIFY_IS_TRUE(VerifyTime(user->titleHistory.lastTimeUserPlayed, \"2015-01-26T22:54:54.6630Z\"));\n            VERIFY_ARE_EQUAL_STR(\"8 months ago\", user->titleHistory.lastTimeUserPlayedText);\n        }\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(filterGroup));\n    }\n\n    DEFINE_TEST_CASE(TestPresenceRtaUpdates)\n    {\n        TEST_LOG(L\"Test starting: TestPresenceRtaUpdates\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext{ env.CreateMockXboxLiveContext() };\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &group\n        ));\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 1} });\n\n        auto users{ env.GetUsers(group) };\n        VERIFY_ARE_EQUAL_INT(users.size(), env.FollowedXuids.size());\n\n        // Verify initial presence\n        for (auto user : users)\n        {\n            VERIFY_IS_TRUE(XblSocialManagerPresenceRecordIsUserPlayingTitle(&user->presenceRecord, 1234));\n            VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Online);\n        }\n\n        // Test title presence changed event\n        auto presenceChangeXuids{ env.FollowedXuids };\n        env.SetPresenceMock({}, 4321);\n        env.FireTitlePresenceChangeRtaEvent(presenceChangeXuids);\n\n        size_t presenceChangedEvents{ 0 };\n        while (presenceChangedEvents < presenceChangeXuids.size())\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_FALSE(XblSocialManagerPresenceRecordIsUserPlayingTitle(&affectedUser->presenceRecord, 1234));\n                            presenceChangedEvents++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n        VERIFY_ARE_EQUAL(presenceChangedEvents, presenceChangeXuids.size());\n\n        // Verify the group view is updated as well\n        for (auto user : env.GetUsers(group))\n        {\n            VERIFY_IS_FALSE(XblSocialManagerPresenceRecordIsUserPlayingTitle(&user->presenceRecord, 1234));\n        }\n\n        // Test device presence changed event\n        env.SetPresenceMock(presenceChangeXuids);\n        env.FireDevicePresenceChangeRtaEvent(presenceChangeXuids);\n\n        presenceChangedEvents = 0;\n        while (presenceChangedEvents < presenceChangeXuids.size())\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(affectedUser->presenceRecord.userState == XblPresenceUserState::Offline);\n                            presenceChangedEvents++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n        VERIFY_ARE_EQUAL(presenceChangedEvents, presenceChangeXuids.size());\n\n        // Verify the group view is updated as well\n        for (auto user : env.GetUsers(group))\n        {\n            VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Offline);\n        }\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group));\n    }\n\n    DEFINE_TEST_CASE(TestMultipleLocalUsers)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleLocalUsers\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext1 = env.CreateMockXboxLiveContext();\n        auto xboxLiveContext2 = env.CreateMockXboxLiveContext(202020202020, \"MockLocalUser2\");\n\n        env.AddLocalUser(xboxLiveContext1->User());\n        VERIFY_IS_TRUE(XblSocialManagerGetLocalUserCount() == 1);\n\n        env.AddLocalUser(xboxLiveContext2->User());\n        VERIFY_IS_TRUE(XblSocialManagerGetLocalUserCount() == 2);\n\n        XblSocialManagerUserGroupHandle user1Group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext1->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &user1Group\n        ));\n\n        // Create a list group that is a subset of user1Group\n        std::vector<uint64_t> group2TrackedUsers{ 1, 2, 3, 4, 5 };\n\n        XblSocialManagerUserGroupHandle user2Group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromList(\n            xboxLiveContext2->User().Handle(),\n            group2TrackedUsers.data(),\n            group2TrackedUsers.size(),\n            &user2Group\n        ));\n\n        size_t groupsLoaded{ 0 };\n        while (groupsLoaded < 2)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == user1Group || event->groupAffected == user2Group);\n                    groupsLoaded++;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_IS_TRUE(groupsLoaded == 2);\n        auto group1Users{ env.GetUsers(user1Group) };\n        auto group2Users{ env.GetUsers(user2Group) };\n        VERIFY_ARE_EQUAL(group1Users.size(), env.FollowedXuids.size());\n        VERIFY_ARE_EQUAL(group2Users.size(), group2TrackedUsers.size());\n\n        // Verify initial presence\n        for (auto& user : group1Users)\n        {\n            VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Online);\n        }\n        for (auto& user : group2Users)\n        {\n            VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Online);\n        }\n\n        // Validate presence change propogates to both user's groups and make sure we get presence\n        // changed events for each local user\n        env.SetPresenceMock(group2TrackedUsers);\n        env.FireDevicePresenceChangeRtaEvent(group2TrackedUsers);\n\n        size_t presenceChangedEvents{ 0 };\n        size_t expectedEvents{ group2TrackedUsers.size() * 2 };\n\n        while (presenceChangedEvents < expectedEvents)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            LOGS_DEBUG << affectedUser->xboxUserId;\n                            VERIFY_IS_TRUE(affectedUser->presenceRecord.userState == XblPresenceUserState::Offline);\n                            presenceChangedEvents++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n        VERIFY_ARE_EQUAL(presenceChangedEvents, expectedEvents);\n\n        std::set<uint64_t> updatedXuids{ group2TrackedUsers.begin(), group2TrackedUsers.end() };\n\n        // Verify both group views are updated as well\n        for (auto& user : env.GetUsers(user1Group))\n        {\n            if (updatedXuids.find(user->xboxUserId) == updatedXuids.end())\n            {\n                VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Online);\n            }\n            else\n            {\n                VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Offline);\n            }\n        }\n        for (auto& user : env.GetUsers(user2Group))\n        {\n            VERIFY_IS_TRUE(user->presenceRecord.userState == XblPresenceUserState::Offline);\n        }\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(user1Group));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(user2Group));\n    }\n\n    DEFINE_TEST_CASE(TestAddRemoveLocalUser)\n    {\n        TEST_LOG(L\"Test starting: TestAddRemoveLocalUser\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        // Tests race condition in adding then removing a local user before adding is complete\n        VERIFY_SUCCEEDED(XblSocialManagerAddLocalUser(xboxLiveContext->User().Handle(), XblSocialManagerExtraDetailLevel::NoExtraDetail, nullptr));\n        VERIFY_SUCCEEDED(XblSocialManagerRemoveLocalUser(xboxLiveContext->User().Handle()));\n        VERIFY_ARE_EQUAL(XblSocialManagerGetLocalUserCount(), 0u);\n        env.AddLocalUser(xboxLiveContext->User());\n        VERIFY_ARE_EQUAL(XblSocialManagerGetLocalUserCount(), 1u);\n    }\n\n    DEFINE_TEST_CASE(TestSocialRelationshipChangedRtaUpdate)\n    {\n        TEST_LOG(L\"Test starting: TestSocialRelationshipChangedRtaUpdate\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &group\n        ));\n\n        size_t expectedGroupSize{ env.FollowedXuids.size() };\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 1} });\n        VERIFY_ARE_EQUAL_INT(expectedGroupSize, env.GetUsersCount(group));\n\n        // Fire social relationship added event. Expected group size should grow by 1.\n        uint64_t addedXuid{ 101 };\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Added, addedXuid);\n        expectedGroupSize++;\n\n        bool userAddedToGraph{ false };\n        while (!userAddedToGraph)\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                {\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, addedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    userAddedToGraph = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(expectedGroupSize, env.GetUsersCount(group));\n\n        uint64_t changedXuid{ 1 };\n        env.SetPeoplehubMock(true, true);\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Changed, changedXuid);\n\n        auto relationshipChangedEventFound{ false };\n        while (!relationshipChangedEventFound)\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialRelationshipsChanged:\n                {\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, changedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    relationshipChangedEventFound = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(expectedGroupSize, env.GetUsersCount(group));\n\n        // Fire social relationship removed event. Expected group size should decrease by 1.\n        uint64_t removedXuid{ 2 };\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Removed, removedXuid);\n        expectedGroupSize--;\n\n        bool userRemovedFromGraph{ false };\n\n        // Since the user is being removed from the graph, there will never be social relationship changed event in this case.\n        // If the user was removed as a friend but was remaining in the graph (i.e. they are tracked by a list group), we would\n        // receive the social relationship changed event instead.\n        while (!userRemovedFromGraph)\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::UsersRemovedFromSocialGraph:\n                {\n                    // User should be removed from graph if they are removed as a friend\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, removedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    userRemovedFromGraph = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(expectedGroupSize, env.GetUsersCount(group));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group));\n    }\n\n    DEFINE_TEST_CASE(TestListGroupWithSocialRelationshipChanged)\n    {\n        TEST_LOG(L\"Test starting: TestListGroupWithSocialRelationshipChanged\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblSocialManagerUserGroupHandle friendsGroup{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &friendsGroup\n        ));\n\n        // Create a list group with a user who we aren't friends with\n        uint64_t listXuid{ 101 };\n        env.SetPeoplehubMock(true, false, false);\n\n        XblSocialManagerUserGroupHandle listGroup{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromList(\n            xboxLiveContext->User().Handle(),\n            &listXuid,\n            1,\n            &listGroup\n        ));\n\n        size_t groupsLoaded{ 0 };\n        while (groupsLoaded < 2)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == friendsGroup || event->groupAffected == listGroup);\n                    groupsLoaded++;\n                    break;\n                }\n                case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                {\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, listXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        auto expectedFriendsSize{ env.FollowedXuids.size() };\n\n        VERIFY_ARE_EQUAL(2u, groupsLoaded);\n        VERIFY_ARE_EQUAL(1u, env.GetUsersCount(listGroup));\n        VERIFY_ARE_EQUAL(expectedFriendsSize, env.GetUsersCount(friendsGroup));\n\n        // Fire social relationship added event. Friends group size should grow by 1.\n        env.SetPeoplehubMock(true, false, true);\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Added, listXuid);\n        expectedFriendsSize++;\n\n        bool relationshipChanged{ false };\n        while (!relationshipChanged)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialRelationshipsChanged:\n                {\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, listXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[0]->isFollowedByCaller == true);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    relationshipChanged = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(expectedFriendsSize, env.GetUsersCount(friendsGroup));\n\n        // Fire social relationship removed event. Expected group size should decrease by 1.\n        env.SetPeoplehubMock(true, false, false);\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Removed, listXuid);\n        expectedFriendsSize--;\n\n        relationshipChanged = false;\n        while (!relationshipChanged)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialRelationshipsChanged:\n                {\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, listXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[0]->isFollowedByCaller == false);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    relationshipChanged = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(expectedFriendsSize, env.GetUsersCount(friendsGroup));\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(friendsGroup));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(listGroup));\n    }\n\n    DEFINE_TEST_CASE(TestFilterGroupChanges)\n    {\n        TEST_LOG(L\"Test starting: TestFilterGroupChanges\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::TitleOnline,\n            XblRelationshipFilter::Friends,\n            &group\n        ));\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 1} });\n\n        auto expectedGroupSize{ env.FollowedXuids.size() };\n        VERIFY_ARE_EQUAL_INT(expectedGroupSize, env.GetUsersCount(group));\n\n        // Make half the users go offline\n        std::vector<uint64_t> usersToGoOffline{ env.FollowedXuids.begin(), env.FollowedXuids.begin() + env.FollowedXuids.size() / 2 };\n        env.SetPresenceMock(usersToGoOffline);\n\n        env.FireDevicePresenceChangeRtaEvent(usersToGoOffline);\n        expectedGroupSize -= usersToGoOffline.size();\n\n        size_t presenceChangedEvents{ 0 };\n        size_t expectedEvents{ usersToGoOffline.size() };\n\n        while (presenceChangedEvents < expectedEvents)\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(affectedUser->presenceRecord.userState == XblPresenceUserState::Offline);\n                            presenceChangedEvents++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(expectedEvents, presenceChangedEvents);\n        VERIFY_ARE_EQUAL(expectedGroupSize, env.GetUsersCount(group));\n        VERIFY_ARE_EQUAL(expectedGroupSize, env.GetTrackedUsersCount(group));\n    }\n\n    DEFINE_TEST_CASE(TestMultipleListGroups)\n    {\n        TEST_LOG(L\"Test starting: TestMultipleListGroups\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        // Set mock for non-friends\n        env.SetPeoplehubMock(true, false, false);\n\n        // Create a list group that doesn't overlap with our friends at all. Five new users should be added to the graph\n        std::set<uint64_t> trackedXuids1{ 101, 102, 103, 104, 105 };\n\n        XblSocialManagerUserGroupHandle group1{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromList(\n            xboxLiveContext->User().Handle(),\n            std::vector<uint64_t>{ trackedXuids1.begin(), trackedXuids1.end() }.data(),\n            trackedXuids1.size(),\n            &group1\n        ));\n\n        VERIFY_ARE_EQUAL(trackedXuids1.size(), env.GetTrackedUsersCount(group1));\n\n        auto groupLoaded{ false };\n        size_t usersAddedToGraph{ 0 };\n        while (!groupLoaded || usersAddedToGraph < trackedXuids1.size())\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == group1);\n                    groupLoaded = true;\n                    break;\n                }\n                case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(trackedXuids1.find(affectedUser->xboxUserId) != trackedXuids1.end());\n                            VERIFY_IS_TRUE(affectedUser->isFollowedByCaller == false);\n                            usersAddedToGraph++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(trackedXuids1.size(), env.GetUsersCount(group1));\n\n        // Create a second group with partial graph overlap. No new users should be added to graph.\n        std::vector<uint64_t> trackedXuids2{ 1, 2, 3, 4, 5, 101, 102, 103, 104, 105 };\n\n        XblSocialManagerUserGroupHandle group2{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromList(\n            xboxLiveContext->User().Handle(),\n            trackedXuids2.data(),\n            trackedXuids2.size(),\n            &group2\n        ));\n\n        groupLoaded = false;\n        while (!groupLoaded)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == group2);\n                    groupLoaded = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(trackedXuids2.size(), env.GetUsersCount(group2));\n\n        // Validate that users remain in graph after their social status changes, until the list group is also\n        // destroyed (they are also part of list group1).\n\n        // Fire social relationship removed event.\n        uint64_t removedXuid{ 1 };\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Removed, removedXuid);\n\n        bool socialRelationshipChanged{ false };\n        while (!socialRelationshipChanged)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialRelationshipsChanged:\n                {\n                    VERIFY_IS_TRUE(event->usersAffected[0]->xboxUserId == removedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[0]->isFollowedByCaller == false);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    socialRelationshipChanged = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        // Destroying group2 should cause 1 user to new be removed from the graph (the remainder are either\n        // friends or part of group1 as well)\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group2));\n\n        size_t usersRemoved{ 0 };\n        while (usersRemoved < 1)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::UsersRemovedFromSocialGraph:\n                {\n                    // User should be removed from graph if they are removed as a friend\n                    VERIFY_ARE_EQUAL_INT(event->usersAffected[0]->xboxUserId, removedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    usersRemoved++;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        // Test updating group1. This should cause the previous tracked users to be removed from the graph and the new ones to be added.\n        std::set<uint64_t> newTrackedXuids1{ 106, 107 };\n        VERIFY_SUCCEEDED(XblSocialManagerUpdateSocialUserGroup(\n            group1,\n            std::vector<uint64_t>{ newTrackedXuids1.begin(), newTrackedXuids1.end() }.data(),\n            newTrackedXuids1.size()\n        ));\n        VERIFY_ARE_EQUAL(newTrackedXuids1.size(), env.GetTrackedUsersCount(group1));\n\n        auto groupUpdated{ false };\n        size_t usersRemovedFromGraph{ 0 };\n        usersAddedToGraph = 0;\n\n        while (!groupUpdated || usersAddedToGraph < newTrackedXuids1.size() || usersRemovedFromGraph < trackedXuids1.size())\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupUpdated:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == group1);\n                    groupUpdated = true;\n                    break;\n                }\n                case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(newTrackedXuids1.find(affectedUser->xboxUserId) != newTrackedXuids1.end());\n                            usersAddedToGraph++;\n                        }\n                    }\n                    break;\n                }\n                case XblSocialManagerEventType::UsersRemovedFromSocialGraph:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(trackedXuids1.find(affectedUser->xboxUserId) != trackedXuids1.end());\n                            usersRemovedFromGraph++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(newTrackedXuids1.size(), env.GetUsersCount(group1));\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group1));\n    }\n\n    DEFINE_TEST_CASE(TestSocialUserGroupFromListLarge)\n    {\n        TEST_LOG(L\"Test starting: TestSocialUserGroupFromListLarge\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        std::vector<uint64_t> trackedXuids;\n        for (uint64_t xuid = 0; xuid < XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST; ++xuid)\n        {\n            trackedXuids.push_back(xuid + 101); // Offset to make unique from our friends\n        }\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromList(\n            xboxLiveContext->User().Handle(),\n            trackedXuids.data(),\n            trackedXuids.size(),\n            &group\n        ));\n\n        VERIFY_ARE_EQUAL(trackedXuids.size(), env.GetTrackedUsersCount(group));\n\n        std::set<uint64_t> trackedXuidsSet{ trackedXuids.begin(), trackedXuids.end() };\n\n        auto groupLoaded{ false };\n        size_t usersAddedToGraph{ 0 };\n        while (!groupLoaded || usersAddedToGraph < trackedXuids.size())\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == group);\n                    groupLoaded = true;\n                    break;\n                }\n                case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(trackedXuidsSet.find(affectedUser->xboxUserId) != trackedXuidsSet.end());\n                            usersAddedToGraph++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL(trackedXuids.size(), env.GetUsersCount(group));\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group));\n    }\n\n    // Tests refresh for RTA resync\n    DEFINE_TEST_CASE(TestRtaResync)\n    {\n        TEST_LOG(L\"Test starting: TestRtaResync\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &group\n        ));\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 1} });\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(group));\n\n        // Make a slight change so we know that the users were refreshed\n        env.SetPeoplehubMock(true, true);\n        MockRealTimeActivityService::Instance().RaiseResync();\n        size_t profileChangesEvents{ 0 };\n        while (profileChangesEvents < env.FollowedXuids.size())\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialRelationshipsChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_ARE_EQUAL(affectedUser->isFavorite, true);\n                            profileChangesEvents++;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group));\n    }\n\n    DEFINE_TEST_CASE(TestSMInvalidArgs)\n    {\n        TEST_LOG(L\"Test starting: TestSMInvalidArgs\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblUserHandle dummyHandle{ (XblUserHandle)0xFFFFFFFFFFFFFFFF };\n        XblSocialManagerUserGroupHandle groupHandle{ nullptr };\n\n#pragma warning( push )\n#pragma warning( disable : 6387 )\n        VERIFY_FAILED(XblSocialManagerAddLocalUser(nullptr, XblSocialManagerExtraDetailLevel::NoExtraDetail, nullptr));\n        VERIFY_FAILED(XblSocialManagerRemoveLocalUser(nullptr));\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromFilters(nullptr, XblPresenceFilter::All, XblRelationshipFilter::Friends, &groupHandle));\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromFilters(dummyHandle, XblPresenceFilter::All, XblRelationshipFilter::Friends, nullptr));\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromList(nullptr, std::vector<uint64_t>{ 0, 1, 2 }.data(), 3, & groupHandle));\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromList(dummyHandle, nullptr, 0, &groupHandle));\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromList(dummyHandle, std::vector<uint64_t>{ 0, 1, 2 }.data(), 3, nullptr));\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromList(dummyHandle, std::vector<uint64_t>(XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST + 1, 0).data(), XBL_SOCIAL_MANAGER_MAX_USERS_FROM_LIST + 1, &groupHandle));\n        VERIFY_FAILED(XblSocialManagerDestroySocialUserGroup(nullptr));\n        VERIFY_FAILED(XblSocialManagerDoWork(nullptr, nullptr));\n#pragma warning( pop )\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::All,\n            XblRelationshipFilter::Friends,\n            &group\n        ));\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 1} });\n\n        VERIFY_FAILED(XblSocialManagerUpdateSocialUserGroup(group, std::vector<uint64_t>{ 0, 1, 2 }.data(), 3));\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group));\n    }\n\n#if 0\n    DEFINE_TEST_CASE(TestImproperCallingPattern)\n    {\n        TEST_LOG(L\"Test starting: TestImproperCallingPattern\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromFilters(xboxLiveContext->User().Handle(), XblPresenceFilter::All, XblRelationshipFilter::Friends, &group));\n\n        VERIFY_FAILED(XblSocialManagerCreateSocialUserGroupFromList(xboxLiveContext->User().Handle(), std::vector<uint64_t>{ 0, 1, 2 }.data(), 3, & group));\n\n        VERIFY_SUCCEEDED(XblSocialManagerAddLocalUser(xboxLiveContext->User().Handle(), XblSocialManagerExtraDetailLevel::All, nullptr));\n        VERIFY_FAILED(XblSocialManagerAddLocalUser(xboxLiveContext->User().Handle(), XblSocialManagerExtraDetailLevel::All, nullptr));\n\n        VERIFY_SUCCEEDED(XblSocialManagerRemoveLocalUser(xboxLiveContext->User().Handle()));\n        VERIFY_FAILED(XblSocialManagerRemoveLocalUser(xboxLiveContext->User().Handle()));\n    }\n#endif\n\n    DEFINE_TEST_CASE(TestCreateGroupBeforeUserAddedCompletes)\n    {\n        TEST_LOG(L\"Test starting: TestCreateGroupBeforeUserAddedCompletes\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        // Add user, and before local user is added, create and destroy a group\n        VERIFY_SUCCEEDED(XblSocialManagerAddLocalUser(xboxLiveContext->User().Handle(), XblSocialManagerExtraDetailLevel::NoExtraDetail, nullptr));\n\n        XblSocialManagerUserGroupHandle group{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromList(xboxLiveContext->User().Handle(), std::vector<uint64_t>{ 101, 102 }.data(), 2, & group));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(group));\n\n        bool localUserAdded{ false };\n        while (!localUserAdded)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::LocalUserAdded:\n                {\n                    localUserAdded = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_SUCCEEDED(XblSocialManagerRemoveLocalUser(xboxLiveContext->User().Handle()));\n    }\n\n    DEFINE_TEST_CASE(TestSocialRelationshipChangedDuringInitialization)\n    {\n        TEST_LOG(L\"Test starting: TestSocialRelationshipChangedDuringInitialization\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        // Add user, and before local user is added, receive a social relationship changed notification\n        uint64_t xuidAdded{ 101 };\n        env.FollowedXuids.push_back(xuidAdded);\n\n        VERIFY_SUCCEEDED(XblSocialManagerAddLocalUser(xboxLiveContext->User().Handle(), XblSocialManagerExtraDetailLevel::NoExtraDetail, nullptr));\n\n        XblSocialManagerUserGroupHandle friendsGroup{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(xboxLiveContext->User().Handle(), XblPresenceFilter::All, XblRelationshipFilter::Friends, &friendsGroup));\n\n        env.FireSocialGraphChangedRtaEvent(xboxLiveContext->User(), XblSocialNotificationType::Added, xuidAdded);\n\n        bool localUserAdded{ false };\n        bool userAddedToGraph{ false };\n        while (!localUserAdded || !userAddedToGraph)\n        {\n            auto events{ env.DoWork() };\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::LocalUserAdded:\n                {\n                    localUserAdded = true;\n                    break;\n                }\n                // There are two possible orderings in this scenario: if the rta event is processed before the\n                // graph initialization completes, by design, we won't get a UsersAddedToSocialGraph event. However,\n                // in that case, the new user should already be in the friends group when it is loaded.\n                case XblSocialManagerEventType::UsersAddedToSocialGraph:\n                {\n                    VERIFY_IS_TRUE(event->usersAffected[0]->xboxUserId == xuidAdded);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    userAddedToGraph = true;\n                    break;\n                }\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    VERIFY_IS_TRUE(event->groupAffected == friendsGroup);\n                    if (env.GetUsersCount(friendsGroup) == env.FollowedXuids.size())\n                    {\n                        userAddedToGraph = true;\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(friendsGroup));\n    }\n\n    DEFINE_TEST_CASE(TestFilters)\n    {\n        TEST_LOG(L\"Test starting: TestFilters\");\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n        auto user{ xboxLiveContext->User().Handle() };\n\n        XblSocialManagerUserGroupHandle allFriends, titleOnlineFriends, allFavorites, allOfflineFriends, titleOfflineFriends, allOnlineFriends, allTitleFriends;\n\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::All, XblRelationshipFilter::Friends, &allFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::TitleOnline, XblRelationshipFilter::Friends, &titleOnlineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::All, XblRelationshipFilter::Favorite, &allFavorites));\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::AllOffline, XblRelationshipFilter::Friends, &allOfflineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::TitleOffline, XblRelationshipFilter::Friends, &titleOfflineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::AllOnline, XblRelationshipFilter::Friends, &allOnlineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(user, XblPresenceFilter::AllTitle, XblRelationshipFilter::Friends, &allTitleFriends));\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 7} });\n\n        // Verify initial user sizes\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(titleOnlineFriends));\n        VERIFY_ARE_EQUAL_INT(0, env.GetUsersCount(allFavorites));\n        VERIFY_ARE_EQUAL_INT(0, env.GetUsersCount(allOfflineFriends));\n        VERIFY_ARE_EQUAL_INT(0, env.GetUsersCount(titleOfflineFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allOnlineFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allTitleFriends));\n\n        // Setup a mock that will affect multiple groups: Online->Offline && Followed->Favorite\n        env.SetPeoplehubMock(false, true);\n\n        uint64_t changedXuid{ 1 };\n\n        auto userResult = User::WrapHandle(user);\n        env.FireSocialGraphChangedRtaEvent(userResult.ExtractPayload(), XblSocialNotificationType::Changed, changedXuid);\n\n        bool profileChanged{ false };\n        bool presenceChanged{ false };\n        while (!profileChanged || !presenceChanged)\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialRelationshipsChanged:\n                {\n                    VERIFY_IS_TRUE(event->usersAffected[0]->xboxUserId == changedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[0]->isFavorite == true);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    profileChanged = true;\n                    break;\n                }\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    VERIFY_IS_TRUE(event->usersAffected[0]->xboxUserId == changedXuid);\n                    VERIFY_IS_TRUE(event->usersAffected[0]->presenceRecord.userState == XblPresenceUserState::Offline);\n                    VERIFY_IS_TRUE(event->usersAffected[1] == nullptr);\n                    presenceChanged = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        // verify groups are affected as expected\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size() - 1, env.GetUsersCount(titleOnlineFriends));\n        VERIFY_ARE_EQUAL_INT(1, env.GetUsersCount(allFavorites));\n        VERIFY_ARE_EQUAL_INT(1, env.GetUsersCount(allOfflineFriends));\n        VERIFY_ARE_EQUAL_INT(1, env.GetUsersCount(titleOfflineFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size() - 1, env.GetUsersCount(allOnlineFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allTitleFriends));\n\n        std::vector<uint64_t> offlineXuids{ 1, 2, 3, 4, 5 };\n        env.SetPresenceMock(offlineXuids);\n        env.FireDevicePresenceChangeRtaEvent(offlineXuids);\n\n        size_t presenceChangedEvents{ 0 };\n        while (presenceChangedEvents < offlineXuids.size())\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            VERIFY_IS_TRUE(affectedUser->xboxUserId > 0 && affectedUser->xboxUserId < 6);\n                            ++presenceChangedEvents;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size() - offlineXuids.size(), env.GetUsersCount(titleOnlineFriends));\n        VERIFY_ARE_EQUAL_INT(1, env.GetUsersCount(allFavorites));\n        VERIFY_ARE_EQUAL_INT(offlineXuids.size(), env.GetUsersCount(allOfflineFriends));\n        VERIFY_ARE_EQUAL_INT(offlineXuids.size(), env.GetUsersCount(titleOfflineFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size() - offlineXuids.size(), env.GetUsersCount(allOnlineFriends));\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(allTitleFriends));\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(allFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(titleOnlineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(allFavorites));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(allOfflineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(titleOfflineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(allOnlineFriends));\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(allTitleFriends));\n    }\n\n    DEFINE_TEST_CASE(TestRichPresencePolling)\n    {\n        TEST_LOG(L\"Test starting: TestRichPresencePolling\");\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        env.AddLocalUser(xboxLiveContext->User());\n\n        XblSocialManagerUserGroupHandle onlineFriends{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n            xboxLiveContext->User().Handle(),\n            XblPresenceFilter::AllOnline,\n            XblRelationshipFilter::Friends,\n            &onlineFriends\n        ));\n\n        env.AwaitEvents({ {XblSocialManagerEventType::SocialUserGroupLoaded, 1} });\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size(), env.GetUsersCount(onlineFriends));\n\n        // Change presence mock so we get a PresenceChanged event when it is polled\n        std::vector<uint64_t> offlineUsers{ 1, 2, 3 };\n        env.SetPresenceMock(offlineUsers);\n        VERIFY_SUCCEEDED(XblSocialManagerSetRichPresencePollingStatus(xboxLiveContext->User().Handle(), true));\n\n        size_t presenceChangedEvents{ 0 };\n        while (presenceChangedEvents < offlineUsers.size())\n        {\n            auto events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    for (auto affectedUser : event->usersAffected)\n                    {\n                        if (affectedUser)\n                        {\n                            ++presenceChangedEvents;\n                        }\n                    }\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_ARE_EQUAL_INT(offlineUsers.size(), presenceChangedEvents);\n        VERIFY_ARE_EQUAL_INT(env.FollowedXuids.size() - offlineUsers.size(), env.GetUsersCount(onlineFriends));\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(onlineFriends));\n    }\n\n    DEFINE_TEST_CASE(TestEventUserHandleLifetime)\n    {\n        TEST_LOG(L\"Test starting: TestEventUserHandleLifetime\");\n\n        SMTestEnvironment env{};\n\n        uint64_t const presenceChangedXuid{ 1 };\n        std::vector<const XblSocialManagerEvent*> events{};\n\n        XblSocialManagerUserGroupHandle groupHandle{ nullptr };\n\n        {\n            // Add a user to SocialManager and create a user group but don't hang on to the user handle. \n            // Ensure the user handles returned in all SM events remain valid until the next DoWork call\n            User user{ CreateMockUser(MOCK_XUID) };\n            env.AddLocalUser(user);\n\n            VERIFY_SUCCEEDED(XblSocialManagerCreateSocialUserGroupFromFilters(\n                user.Handle(),\n                XblPresenceFilter::AllOnline,\n                XblRelationshipFilter::Friends,\n                &groupHandle\n            ));\n        }\n\n        bool groupLoaded{ false };\n        while (!groupLoaded)\n        {\n            events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::SocialUserGroupLoaded:\n                {\n                    groupLoaded = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        VERIFY_SUCCEEDED(XblSocialManagerDestroySocialUserGroup(groupHandle));\n        {\n            // Ensure the user in the event is valid even after destroying the group\n            auto userFromEventResult = User::WrapHandle(events[0]->user);\n            VERIFY_ARE_EQUAL_UINT(MOCK_XUID, userFromEventResult.ExtractPayload().Xuid());\n        }\n\n        // Make a user go offline to trigger event\n        env.SetPresenceMock({ presenceChangedXuid });\n        env.FireDevicePresenceChangeRtaEvent({ presenceChangedXuid }, false);\n\n        bool presenceChanged{ false };\n        while (!presenceChanged)\n        {\n            events = env.DoWork();\n            for (auto event : events)\n            {\n                switch (event->eventType)\n                {\n                case XblSocialManagerEventType::PresenceChanged:\n                {\n                    VERIFY_ARE_EQUAL_UINT(presenceChangedXuid, event->usersAffected[0]->xboxUserId);\n                    presenceChanged = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        XblUserHandle userHandle{ nullptr };\n        VERIFY_SUCCEEDED(XblSocialManagerGetLocalUsers(1, &userHandle));\n        VERIFY_SUCCEEDED(XblSocialManagerRemoveLocalUser(userHandle));\n\n        {\n            // Ensure the user handle from the event is still valid after removing the user\n            auto userFromEventResult = User::WrapHandle(events[0]->user);\n            VERIFY_ARE_EQUAL_UINT(MOCK_XUID, userFromEventResult.ExtractPayload().Xuid());\n        }\n    }\n\n    DEFINE_TEST_CASE(CppTestBasicCreateFilterGroup)\n    {\n        TEST_LOG(L\"Test starting: CppTestBasicCreateFilterGroup\");\n\n        SMTestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n        xbox_live_user_t userHandle = xboxLiveContext->user();\n\n        auto socialManager{ social_manager::get_singleton_instance() };\n\n        auto addUserResult = socialManager->add_local_user(\n            userHandle,\n            social_manager_extra_detail_level::no_extra_detail\n        );\n        VERIFY_IS_TRUE(!addUserResult.err());\n\n        {\n            // Wait until we get the local_user_added event\n            bool localUserAdded{ false };\n            while (!localUserAdded)\n            {\n                auto events{ socialManager->do_work() };\n                for (auto event : events)\n                {\n                    switch (event.event_type())\n                    {\n                    case social_event_type::local_user_added:\n                    {\n                        localUserAdded = true;\n                        break;\n                    }\n                    default:\n                    {\n                        LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                        VERIFY_FAIL();\n                    }\n                    }\n                }\n            }\n        }\n\n        auto createGroupResult = socialManager->create_social_user_group_from_filters(\n            userHandle,\n            presence_filter::all,\n            relationship_filter::friends\n        );\n\n        VERIFY_IS_TRUE(!createGroupResult.err());\n        auto group = createGroupResult.payload();\n\n        bool groupLoaded{ false };\n        while (!groupLoaded)\n        {\n            auto events{ socialManager->do_work() };\n            for (auto event : events)\n            {\n                switch (event.event_type())\n                {\n                case social_event_type::social_user_group_loaded:\n                {\n                    auto groupLoadedArgs = static_cast<social_user_group_loaded_event_args*>(event.event_args().get());\n                    VERIFY_IS_TRUE(group == groupLoadedArgs->social_user_group());\n                    groupLoaded = true;\n                    break;\n                }\n                default:\n                {\n                    LOGS_DEBUG << \"Unexpected SocialManager Event\";\n                    VERIFY_FAIL();\n                }\n                }\n            }\n        }\n\n        auto users{ group->users() };\n        VERIFY_ARE_EQUAL(group->users_tracked_by_social_user_group().size(), users.size());\n\n        for (auto user : users)\n        {\n            // profile tests\n            LOGS_DEBUG << \"Validating user \" << user->xbox_user_id();\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->display_name());\n            VERIFY_ARE_EQUAL_STR(\"http://images-eds.xboxlive.com/image?url=mHGRD8KXEf2sp2LC58XhBQKNl2IWRp.J.q8mSURKUUeiPPf0Y7Kl7zLN7rafayiPptVaX_XIUmNOPotNmNubbx4bHmf6It7Oj1ChU5UAo9k-&background=0xababab&mode=Padding&format=png\", user->display_pic_url_raw());\n            VERIFY_IS_TRUE(user->is_followed_by_caller());\n            VERIFY_IS_TRUE(user->is_following_user());\n            VERIFY_ARE_EQUAL_STR(\"9001\", user->gamerscore());\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->gamertag());\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->modern_gamertag());\n            VERIFY_ARE_EQUAL_STR(\"\", user->modern_gamertag_suffix());\n            VERIFY_ARE_EQUAL_STR(\"TestGamerTag\", user->unique_modern_gamertag());\n            VERIFY_IS_FALSE(user->is_favorite());\n            VERIFY_IS_FALSE(user->use_avatar());\n\n            // preferred color tests\n            VERIFY_ARE_EQUAL_STR(\"193e91\", user->preferred_color().primary_color());\n            VERIFY_ARE_EQUAL_STR(\"2458cf\", user->preferred_color().secondary_color());\n            VERIFY_ARE_EQUAL_STR(\"122e6b\", user->preferred_color().tertiary_color());\n\n            // presence record tests\n            VERIFY_IS_TRUE(user->presence_record().presence_title_records().size());\n            VERIFY_IS_TRUE(user->presence_record().user_state() == user_presence_state::online);\n            VERIFY_IS_TRUE(user->presence_record().is_user_playing_title(1234));\n            VERIFY_IS_TRUE(user->presence_record().presence_title_records()[0].is_title_active());\n            VERIFY_IS_TRUE(!user->presence_record().presence_title_records()[0].is_broadcasting());\n            VERIFY_IS_TRUE(user->presence_record().presence_title_records()[0].device_type() == presence_device_type::pc);\n            VERIFY_ARE_EQUAL_STR(\"Home\", user->presence_record().presence_title_records()[0].presence_text());\n\n            // title history tests\n            VERIFY_IS_TRUE(user->title_history().has_user_played());\n            VERIFY_IS_TRUE(Utils::TimeTFromDatetime(user->title_history().last_time_user_played()) == utils::TimeTFromDatetime(xbox::services::datetime::from_string(\"2015-01-26T22:54:54.6630Z\", xbox::services::datetime::date_format::ISO_8601)));\n        }\n\n        auto destroyGroupResult = socialManager->destroy_social_user_group(group);\n        VERIFY_IS_TRUE(!destroyGroupResult.err());\n\n        auto removeUserResult = socialManager->remove_local_user(userHandle);\n        VERIFY_IS_TRUE(!removeUserResult.err());\n\n        auto events{ socialManager->do_work() };\n        VERIFY_ARE_EQUAL_INT(events.size(), 1);\n        VERIFY_IS_TRUE(events[0].event_type() == social_event_type::local_user_removed);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/SocialTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\n#pragma warning(disable : 4996)\n\nusing namespace xbox::services::social;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(SocialTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(SocialTests);\n\nprivate:\n    struct SocialRelationship\n    {\n        uint64_t xuid{ 1 };\n        bool isFollowingCaller{ true };\n        bool isFavorite{ false };\n        bool isFriend{ true };\n        std::vector<std::wstring> socialNetworks;\n    };\n\n    struct FriendRelationship\n    {\n        uint64_t xuid{ 1 };\n        bool isFollowingCaller{ false };\n        bool isFavorite{ false };\n        bool isFriend{ false };\n        std::vector<std::wstring> socialNetworks;\n    };\n\n    std::shared_ptr<HttpMock> CreateSocialMock(\n        const std::vector<SocialRelationship>& people\n    )\n    {\n        auto mock = std::make_shared<HttpMock>(\"GET\", \"https://social.xboxlive.com\");\n\n        mock->SetMockMatchedCallback(\n            [\n                &people\n            ]\n        (HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                assert(requestBody.empty());\n\n                xbox::services::uri url(requestUrl.data());\n                auto queryParams = url.split_query(url.query());\n\n                size_t startIndex{ 0 };\n                size_t maxItems{ people.size() };\n                xsapi_internal_string view{ \"All\" };\n\n                if (queryParams.find(\"startIndex\") != queryParams.end())\n                {\n                    startIndex = _atoi64(queryParams[\"startIndex\"].c_str());\n                }\n                if (queryParams.find(\"maxItems\") != queryParams.end())\n                {\n                    maxItems = _atoi64(queryParams[\"maxItems\"].c_str());\n                }\n                if (queryParams.find(\"view\") != queryParams.end())\n                {\n                    view = queryParams[\"view\"];\n                }\n\n                std::vector<SocialRelationship> filteredPeople;\n                std::copy_if(people.begin(), people.end(), std::back_inserter(filteredPeople),\n                    [&](const SocialRelationship& person)\n                    {\n                        if (_stricmp(\"favorite\", view.c_str()) == 0)\n                        {\n                            return person.isFavorite;\n                        }\n                        else if (_stricmp(\"LegacyXboxLiveFriends\", view.c_str()) == 0)\n                        {\n                            auto iter = std::find_if(person.socialNetworks.begin(), person.socialNetworks.end(),\n                                [](const std::wstring& s)\n                                {\n                                    return _stricmp(convert::utf16_to_utf8(s).c_str(), \"LegacyXboxLive\") == 0;\n                                });\n                            return iter != person.socialNetworks.end();\n                        } \n                        else if (_stricmp(\"FriendList\", view.c_str()) == 0)\n                        {\n                            return person.isFriend;\n                        }\n                        else\n                        {\n                            assert(_stricmp(\"All\", view.c_str()) == 0);\n                            return true;\n                        }\n                    });\n                JsonDocument responseJson(rapidjson::kObjectType);\n                JsonDocument::AllocatorType& allocator = responseJson.GetAllocator();\n                JsonValue peopleJson(rapidjson::kArrayType);\n                for (size_t i = startIndex; i < startIndex + maxItems && i < filteredPeople.size(); ++i)\n                {\n                    auto& person{ filteredPeople[i] };\n                    JsonValue personJson(rapidjson::kObjectType);\n\n                    personJson.AddMember(\"xuid\", JsonValue(utils::uint64_to_internal_string(person.xuid).c_str(), allocator).Move(), allocator);\n                    personJson.AddMember(\"isFavorite\", person.isFavorite, allocator);\n                    personJson.AddMember(\"isFollowingCaller\", person.isFriend ? true : false, allocator);\n                    personJson.AddMember(\"isFriend\", person.isFriend, allocator);\n\n                    JsonValue socialNetworksJson(rapidjson::kArrayType);\n                    for (auto& socialNetwork : person.socialNetworks)\n                    {\n                        socialNetworksJson.PushBack(JsonValue(utils::internal_string_from_string_t(socialNetwork).c_str(), allocator).Move(), allocator);\n                    }\n                    if (socialNetworksJson.Size() > 0)\n                    {\n                        personJson.AddMember(\"socialNetworks\", socialNetworksJson, allocator);\n                    }\n\n                    peopleJson.PushBack(personJson, allocator);\n                }\n\n                responseJson.AddMember(\"people\", peopleJson, allocator);\n                responseJson.AddMember(\"totalCount\", static_cast<uint64_t>(filteredPeople.size()), allocator);\n                mock->SetResponseBody(responseJson);\n            }\n        );\n\n        return mock;\n    }\n\n    std::shared_ptr<HttpMock> CreateFriendsMock(\n        const std::vector<FriendRelationship>& people,\n        xsapi_internal_string friendView\n    )\n    {\n        auto mock = std::make_shared<HttpMock>(\"GET\", \"https://social.xboxlive.com\");\n\n        mock->SetMockMatchedCallback(\n            [\n                &people,\n                friendView\n            ]\n        (HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            assert(requestBody.empty());\n\n            xbox::services::uri url(requestUrl.data());\n            auto queryParams = url.split_query(url.query());\n\n            size_t startIndex{ 0 };\n            size_t maxItems{ people.size() };\n\n            std::vector<FriendRelationship> filteredPeople;\n            std::copy_if(people.begin(), people.end(), std::back_inserter(filteredPeople),\n                [&](const FriendRelationship& person)\n            {   \n                if (_stricmp(\"Favorite\", friendView.c_str()) == 0)\n                {\n                    return person.isFavorite;\n                }\n                else if (_stricmp(\"FriendList\", friendView.c_str()) == 0)\n                {\n                    return person.isFriend;\n                }\n                else {\n                    return false;\n                }\n            });\n\n            JsonDocument responseJson(rapidjson::kObjectType);\n            JsonDocument::AllocatorType& allocator = responseJson.GetAllocator();\n            JsonValue peopleJson(rapidjson::kArrayType);\n            for (size_t i = startIndex; i < startIndex + maxItems && i < filteredPeople.size(); ++i)\n            {\n                auto& person{ filteredPeople[i] };\n                JsonValue personJson(rapidjson::kObjectType);\n\n                personJson.AddMember(\"xuid\", JsonValue(utils::uint64_to_internal_string(person.xuid).c_str(), allocator).Move(), allocator);\n                // isFavorite should reflect isFavorite and isFriend \n                personJson.AddMember(\"isFavorite\", (person.isFavorite && person.isFriend), allocator);\n                // isFollowingCaller should be set based on isFriend for backwards compat purposes\n                personJson.AddMember(\"isFollowingCaller\", person.isFriend ? true : false, allocator);\n                personJson.AddMember(\"isFriend\", person.isFriend, allocator);\n\n\n                JsonValue socialNetworksJson(rapidjson::kArrayType);\n                for (auto& socialNetwork : person.socialNetworks)\n                {\n                    socialNetworksJson.PushBack(JsonValue(utils::internal_string_from_string_t(socialNetwork).c_str(), allocator).Move(), allocator);\n                }\n                if (socialNetworksJson.Size() > 0)\n                {\n                    personJson.AddMember(\"socialNetworks\", socialNetworksJson, allocator);\n                }\n\n                peopleJson.PushBack(personJson, allocator);\n            }\n\n            responseJson.AddMember(\"people\", peopleJson, allocator);\n            responseJson.AddMember(\"totalCount\", static_cast<uint64_t>(filteredPeople.size()), allocator);\n            mock->SetResponseBody(responseJson);\n        }\n        );\n\n        return mock;\n    }\n\n    void ValidateSocialRelationshipResult(\n        XblSocialRelationshipResultHandle resultHandle,\n        size_t expectedTotalCount,\n        bool expectedHasNext,\n        const std::vector<SocialRelationship>& expectedSocialRelationships\n    )\n    {\n        size_t totalCount{ 0 };\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultGetTotalCount(resultHandle, &totalCount));\n        VERIFY_ARE_EQUAL_INT(totalCount, expectedTotalCount);\n\n        bool hasNext{ false };\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultHasNext(resultHandle, &hasNext));\n        VERIFY_ARE_EQUAL(hasNext, expectedHasNext);\n\n        const XblSocialRelationship* socialRelationships{ nullptr };\n        size_t socialRelationshipsCount{ 0 };\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultGetRelationships(resultHandle, &socialRelationships, &socialRelationshipsCount));\n        VERIFY_ARE_EQUAL_INT(socialRelationshipsCount, expectedSocialRelationships.size());\n\n        for (size_t i = 0; i < socialRelationshipsCount; ++i)\n        {\n            auto& r{ socialRelationships[i] };\n\n            auto iter = std::find_if(expectedSocialRelationships.begin(), expectedSocialRelationships.end(), \n                [&r](const SocialRelationship& expectedRelationship)\n                {\n                    return expectedRelationship.xuid == r.xboxUserId;\n                });\n            VERIFY_IS_TRUE(iter != expectedSocialRelationships.end());\n            VERIFY_ARE_EQUAL(iter->isFavorite, r.isFavorite);\n            VERIFY_ARE_EQUAL(iter->isFollowingCaller, r.isFollowingCaller);\n            VERIFY_ARE_EQUAL(iter->socialNetworks.size(), r.socialNetworksCount);\n\n            for (size_t j = 0; j < r.socialNetworksCount; ++j)\n            {\n                VERIFY_IS_TRUE(Utils::Stricmp(Utils::StringTFromUtf8(r.socialNetworks[j]), iter->socialNetworks[j]) == 0);\n            }\n        }\n    }\n\n    void ValidateFriendsRelationshipResult(\n        XblSocialRelationshipResultHandle resultHandle,\n        size_t expectedTotalCount,\n        bool expectedHasNext,\n        const std::vector<FriendRelationship>& expectedSocialRelationships\n    )\n    {\n        size_t totalCount{ 0 };\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultGetTotalCount(resultHandle, &totalCount));\n        VERIFY_ARE_EQUAL_INT(totalCount, expectedTotalCount);\n\n        bool hasNext{ false };\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultHasNext(resultHandle, &hasNext));\n        VERIFY_ARE_EQUAL(hasNext, expectedHasNext);\n\n        const XblSocialRelationship* socialRelationships{ nullptr };\n        size_t socialRelationshipsCount{ 0 };\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultGetRelationships(resultHandle, &socialRelationships, &socialRelationshipsCount));\n        VERIFY_ARE_EQUAL_INT(socialRelationshipsCount, expectedSocialRelationships.size());\n\n        for (size_t i = 0; i < socialRelationshipsCount; ++i)\n        {\n            auto& r{ socialRelationships[i] };\n\n            auto iter = std::find_if(expectedSocialRelationships.begin(), expectedSocialRelationships.end(),\n                [&r](const FriendRelationship& expectedRelationship)\n            {\n                return expectedRelationship.xuid == r.xboxUserId;\n            });\n            VERIFY_IS_TRUE(iter != expectedSocialRelationships.end());\n            VERIFY_ARE_EQUAL(iter->isFavorite, r.isFavorite);\n            VERIFY_ARE_EQUAL(iter->isFriend, r.isFriend);\n            VERIFY_ARE_EQUAL(iter->isFollowingCaller, r.isFollowingCaller);\n            VERIFY_ARE_EQUAL(iter->socialNetworks.size(), r.socialNetworksCount);\n\n            for (size_t j = 0; j < r.socialNetworksCount; ++j)\n            {\n                VERIFY_IS_TRUE(Utils::Stricmp(Utils::StringTFromUtf8(r.socialNetworks[j]), iter->socialNetworks[j]) == 0);\n            }\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetSocialRelationshipsAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetSocialRelationshipsAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<SocialRelationship> socialRelationships(100);\n        uint64_t friendXuid{ 1 };\n        for (auto& person : socialRelationships)\n        {\n            person.xuid = friendXuid++;\n        }\n\n        // Add a couple of favorites\n        socialRelationships[0].isFavorite = true;\n        socialRelationships[1].isFavorite = true;\n\n        // Add a LegacyFriend\n        socialRelationships[2].socialNetworks.push_back(L\"LegacyXboxLive\");\n\n        auto socialMock{ CreateSocialMock(socialRelationships) };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            XblSocialRelationshipFilter::All,\n            0,\n            0,\n            &async\n        ));\n\n        XblSocialRelationshipResultHandle resultHandle{ nullptr };\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n        ValidateSocialRelationshipResult(\n            resultHandle,\n            socialRelationships.size(),\n            false,\n            socialRelationships\n        );\n        XblSocialRelationshipResultCloseHandle(resultHandle);\n\n        ZeroMemory(async.internal, sizeof(async.internal));\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            XblSocialRelationshipFilter::Favorite,\n            0,\n            0,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n        ValidateSocialRelationshipResult(\n            resultHandle,\n            2,\n            false,\n            std::vector<SocialRelationship>(socialRelationships.begin(), socialRelationships.begin() + 2)\n        );\n        XblSocialRelationshipResultCloseHandle(resultHandle);\n\n        ZeroMemory(async.internal, sizeof(async.internal));\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            XblSocialRelationshipFilter::LegacyXboxLiveFriends,\n            0,\n            0,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n        ValidateSocialRelationshipResult(\n            resultHandle,\n            1,\n            false,\n            std::vector<SocialRelationship>(1, socialRelationships[2])\n        );\n        XblSocialRelationshipResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(TestGetSocialRelationshipsResultPaging)\n    {\n        TEST_LOG(L\"Test starting: TestGetSocialRelationshipsResultPaging\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        std::vector<SocialRelationship> socialRelationships(15);\n        uint64_t friendXuid{ 1 };\n        for (auto& person : socialRelationships)\n        {\n            person.xuid = friendXuid++;\n        }\n\n        auto socialMock{ CreateSocialMock(socialRelationships) };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            XblSocialRelationshipFilter::All,\n            0,\n            10,\n            &async\n        ));\n\n        XblSocialRelationshipResultHandle resultHandle{ nullptr };\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n        ValidateSocialRelationshipResult(\n            resultHandle,\n            15,\n            true,\n            std::vector<SocialRelationship>(socialRelationships.begin(), socialRelationships.begin() + 10)\n        );\n\n        VERIFY_SUCCEEDED(XblSocialRelationshipResultGetNextAsync(\n            xboxLiveContext.get(),\n            resultHandle,\n            10,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        XblSocialRelationshipResultCloseHandle(resultHandle);\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n        ValidateSocialRelationshipResult(\n            resultHandle,\n            15,\n            false,\n            std::vector<SocialRelationship>(socialRelationships.begin() + 10, socialRelationships.end())\n        );\n        XblSocialRelationshipResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(TestRTASocialRelationshipChange)\n    {\n        TEST_LOG(L\"Test starting: TestRTASocialRelationshipChange\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            xsapi_internal_stringstream expectedUri;\n            expectedUri << \"http://social.xboxlive.com/users/xuid(\" << xboxLiveContext->Xuid() << \")/friends\";\n            VERIFY_ARE_EQUAL_STR(uri, expectedUri.str());\n\n            mockRtaService.CompleteSubscribeHandshake(n);\n\n            // Immediately raise an event\n            mockRtaService.RaiseEvent(uri, R\"({ \"NotificationType\": \"Removed\", \"Xuids\": [ \"2\" ] })\");\n        });\n\n        struct HandlerContext\n        {\n            Event notificationReceived;\n            uint64_t xuid{ 0 };\n            XblSocialNotificationType notificationType{ XblSocialNotificationType::Unknown };\n            std::vector<uint64_t> affectedXuids;\n        } context;\n\n        auto handlerToken = XblSocialAddSocialRelationshipChangedHandler(xboxLiveContext.get(),\n            [](const XblSocialRelationshipChangeEventArgs* args, void* context)\n            {\n                auto c{ static_cast<HandlerContext*>(context) };\n                \n                c->xuid = args->callerXboxUserId;\n                c->notificationType = args->socialNotification;\n                c->affectedXuids = std::vector<uint64_t>(args->xboxUserIds, args->xboxUserIds + args->xboxUserIdsCount);\n                c->notificationReceived.Set();\n            },\n            &context\n        );\n\n        context.notificationReceived.Wait();\n\n        VERIFY_ARE_EQUAL_INT(xboxLiveContext->Xuid(), context.xuid);\n        VERIFY_IS_TRUE(context.notificationType == XblSocialNotificationType::Removed);\n        VERIFY_ARE_EQUAL_INT(1u, context.affectedXuids.size());\n        VERIFY_ARE_EQUAL_INT(2, context.affectedXuids[0]);\n\n        VERIFY_SUCCEEDED(XblSocialRemoveSocialRelationshipChangedHandler(xboxLiveContext.get(), handlerToken));\n    }\n\n    DEFINE_TEST_CASE(CppTestGetSocialRelationships)\n    {\n        TEST_LOG(L\"Test starting: CppTestGetSocialRelationships\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        std::vector<SocialRelationship> socialRelationships(100);\n        uint64_t friendXuid{ 1 };\n        for (auto& person : socialRelationships)\n        {\n            person.xuid = friendXuid++;\n        }\n\n        auto socialMock{ CreateSocialMock(socialRelationships) };\n\n        auto task = xboxLiveContext->social_service().get_social_relationships();\n\n        auto result{ task.get() };\n        VERIFY_IS_TRUE(!result.err());\n\n        auto& payload{ result.payload() };\n        VERIFY_IS_TRUE(payload.has_next() == false);\n        VERIFY_IS_TRUE(payload.total_count() == socialRelationships.size());\n        auto items{ payload.items() };\n        VERIFY_IS_TRUE(items.size() == socialRelationships.size());\n\n        for (auto& item : items)\n        {\n            auto iter = std::find_if(socialRelationships.begin(), socialRelationships.end(),\n                [&item](const SocialRelationship& expectedRelationship)\n                {\n                    return expectedRelationship.xuid == Utils::Uint64FromStringT(item.xbox_user_id());\n                });\n            VERIFY_IS_TRUE(iter != socialRelationships.end());\n            VERIFY_ARE_EQUAL(iter->isFavorite, item.is_favorite());\n            VERIFY_ARE_EQUAL(iter->isFollowingCaller, item.is_following_caller());\n            VERIFY_ARE_EQUAL(iter->isFriend, item.is_friend());\n            VERIFY_ARE_EQUAL(iter->socialNetworks.size(), item.social_networks().size());\n\n            for (size_t i = 0; i < item.social_networks().size(); ++i)\n            {\n                VERIFY_IS_TRUE(Utils::Stricmp(item.social_networks()[i], iter->socialNetworks[i]) == 0);\n            }\n        }\n    }\n\n    DEFINE_TEST_CASE(CppTestRTASocialRelationshipChange)\n    {\n        TEST_LOG(L\"Test starting: CppTestRTASocialRelationshipChange\");\n\n        TestEnvironment env{};\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext(1);\n\n        xboxLiveContext->real_time_activity_service()->activate();\n\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            mockRtaService.CompleteSubscribeHandshake(n);\n\n            // Immediately raise an event\n            mockRtaService.RaiseEvent(uri, R\"({ \"NotificationType\": \"Removed\", \"Xuids\": [ \"2\" ] })\");\n        });\n\n        auto subscriptionResult = xboxLiveContext->social_service().subscribe_to_social_relationship_change(xboxLiveContext->xbox_live_user_id());\n        VERIFY_IS_TRUE(!subscriptionResult.err());\n\n        Event rtaMessageReceived;\n\n        auto handlerToken = xboxLiveContext->social_service().add_social_relationship_changed_handler(\n            [&rtaMessageReceived](social_relationship_change_event_args args)\n            {\n                VERIFY_IS_TRUE(args.caller_xbox_user_id() == _T(\"1\"));\n                VERIFY_IS_TRUE(args.social_notification() == social_notification_type::removed);\n                VERIFY_ARE_EQUAL_INT(args.xbox_user_ids().size(), 1);\n                VERIFY_IS_TRUE(args.xbox_user_ids()[0] == _T(\"2\"));\n\n                rtaMessageReceived.Set();\n            });\n\n        rtaMessageReceived.Wait();\n\n        xboxLiveContext->social_service().remove_social_relationship_changed_handler(handlerToken);\n        auto unsubscribeResult = xboxLiveContext->social_service().unsubscribe_from_social_relationship_change(subscriptionResult.payload());\n        VERIFY_IS_TRUE(!unsubscribeResult.err());\n    }\n\n    DEFINE_TEST_CASE(TestGetMutualFriendsAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetMutualFriendsAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        xsapi_internal_string friendView{ \"FriendList\" };\n\n        std::vector<FriendRelationship> friendRelationships(5);\n\n        uint64_t friendXuid{ 1 };\n        for (auto& user : friendRelationships)\n        {\n            user.xuid = friendXuid++;\n        }\n\n        // Set isFriend\n        friendRelationships[0].isFriend = true;\n        friendRelationships[1].isFriend = true;\n\n        // Mock Service Response for new Friends contract\n        auto socialMock{ CreateFriendsMock(friendRelationships, friendView)};\n\n        // Retrieve list of modern friends\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            XblSocialRelationshipFilter::All,\n            0,\n            0,\n            &async\n        ));\n\n        \n        XblSocialRelationshipResultHandle resultHandle{ nullptr };\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        // isFollowingCaller is set in Mock (based of isFriend)\n        friendRelationships[0].isFollowingCaller = true;\n        friendRelationships[1].isFollowingCaller = true;\n        \n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n\n        // Expect 2 XUIDS to have isFriend value set to 'true' \n        ValidateFriendsRelationshipResult(\n            resultHandle,\n            2,\n            false,\n            std::vector<FriendRelationship>(friendRelationships.begin(), friendRelationships.begin() + 2) \n        );\n\n        XblSocialRelationshipResultCloseHandle(resultHandle);\n    }\n\n    DEFINE_TEST_CASE(TestGetMutualFriendsFavoriteAsync)\n    {\n        TEST_LOG(L\"Test starting: TestGetMutualFriendsFavoriteAsync\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        xsapi_internal_string favoriteView{ \"Favorite\" };\n\n        std::vector<FriendRelationship> friendRelationships(5);\n\n        uint64_t friendXuid{ 1 };\n        for (auto& user : friendRelationships)\n        {\n            user.xuid = friendXuid++;\n            user.isFriend = true;\n        }\n        \n        // Set isFavorite for 1 XUID\n        friendRelationships[0].isFavorite = true;\n\n        // Mock Service Response for new Friends contract\n        auto socialMock{ CreateFriendsMock(friendRelationships, favoriteView) };\n\n        // Retrieve list of modern favorite friends\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            XblSocialRelationshipFilter::All,\n            0,\n            0,\n            &async\n        ));\n\n\n        XblSocialRelationshipResultHandle resultHandle{ nullptr };\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        // isFollowingCaller is set in Mock \n        friendRelationships[0].isFollowingCaller = true;\n\n        VERIFY_SUCCEEDED(XblSocialGetSocialRelationshipsResult(&async, &resultHandle));\n\n        // Expect 1 XUID to have isFriend and isFavorite value set to 'true' \n        ValidateFriendsRelationshipResult(\n            resultHandle,\n            1,\n            false,\n            std::vector<FriendRelationship>(friendRelationships.begin(), friendRelationships.begin() + 1)\n        );\n\n        XblSocialRelationshipResultCloseHandle(resultHandle);   \n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/StatsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char* statsServer = \"https://userstats.xboxlive.com\";\nconst char* batchUrl = \"https://userstats.xboxlive.com/batch?operation=read\";\nconst uint64_t xuid{ 2533274792693551 };\n\nconst char* defaultRtaStat =\nR\"({\n        \"name\": \"Stat\",\n        \"type\": \"Integer\",\n        \"value\": \"31\"\n    })\";\n\nconst char* updatedRtaStat =\nR\"({\n        \"name\": \"Stat\",\n        \"type\": \"Integer\",\n        \"value\": \"32\"\n    })\";\n\nconst char* defaultSingleUserStatsResponse =\nR\"({\n        \"xuid\":\"2533274792693551\",\n        \"scids\":\n        [\n            {\n                \"scid\":\"7492baca-c1b4-440d-a391-b7ef364a8d40\",\n                \"stats\":\n                [\n                    {\n                        \"statname\":\"OverallReputation\",\n                        \"type\":\"Integer\",\n                        \"value\":\"66\"\n                    },\n                    {\n                        \"statname\":\"FairplayReputation\",\n                        \"type\":\"Integer\",\n                        \"value\":\"72\"\n                    }\n                ]\n            },\n            {\n                \"scid\":\"7492baca-c1b4-440d-a391-b7ef364a8d41\",\n                \"stats\":\n                [\n                    {\n                        \"statname\":\"CommsReputation\",\n                        \"type\":\"Integer\",\n                        \"value\":\"66\"\n                    },\n                    {\n                        \"statname\":\"UserContentReputation\",\n                        \"type\":\"Integer\",\n                        \"value\":\"75\"\n                    }\n                ]\n            }\n        ]\n    })\";\n\nconst char* defaultBatchUsersStatsResponse =\nR\"({\n        \"users\":\n        [\n            {\n                \"xuid\":\"2533274792693551\",\n                \"scids\":\n                [\n                    {\n                        \"scid\":\"7492baca-c1b4-440d-a391-b7ef364a8d40\",\n                        \"stats\":\n                        [\n                            {\n                                \"statname\":\"OverallReputation\",\n                                \"type\":\"Integer\",\n                                \"value\":\"66\"\n                            },\n                            {\n                                \"statname\":\"FairplayReputation\",\n                                \"type\":\"Integer\",\n                                \"value\":\"72\"\n                            }\n                        ]\n                    }\n                ]\n            },\n            {\n                \"xuid\":\"2533274792693552\",\n                \"scids\":\n                [\n                    {\n                        \"scid\":\"7492baca-c1b4-440d-a391-b7ef364a8d40\",\n                        \"stats\":\n                        [\n                            {\n                                \"statname\":\"OverallReputation\",\n                                \"type\":\"Integer\",\n                                \"value\":\"66\"\n                            },\n                            {\n                                \"statname\":\"FairplayReputation\",\n                                \"type\":\"Integer\",\n                                \"value\":\"72\"\n                            }\n                        ]\n                    }\n                ]\n            }\n        ]\n    })\";\n\nDEFINE_TEST_CLASS(UserStatsTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(UserStatsTests);\n\n    const char* rtaScid{ \"12345\" };\n    Event rtaMessageReceived{};\n    bool rtaMessageWellFormed{ true };\n    char rtaResultName[8]{};\n    char rtaResultValue[8]{};\n    char rtaResultType[8]{};\n\n    void VerifyStat(XblStatistic stat, JsonValue statToVerify, bool isRta)\n    {\n        const char* name = isRta ? \"name\" : \"statname\";\n        VERIFY_ARE_EQUAL_STR(stat.statisticName, statToVerify[name].GetString());\n        VERIFY_ARE_EQUAL_STR(stat.value, statToVerify[\"value\"].GetString());\n        VERIFY_ARE_EQUAL_STR(stat.statisticType, statToVerify[\"type\"].GetString());\n    }\n\n    void VerifyServiceConfigurationStatistic(XblServiceConfigurationStatistic scid, JsonValue scidToVerify, bool isSingleUser)\n    {   \n        if (!isSingleUser)\n        {\n            VERIFY_ARE_EQUAL_STR(scid.serviceConfigurationId, scidToVerify[\"scid\"].GetString());\n        }\n\n        auto statsJson = scidToVerify[\"stats\"].GetArray();\n        VERIFY_ARE_EQUAL_UINT(scid.statisticsCount, statsJson.Size());\n\n        // scids/*/stats/*\n        uint32_t i{ 0 };\n        for (auto& statJson : statsJson)\n        {\n            VerifyStat(scid.statistics[i], statJson.GetObjectW(), false);\n            ++i;\n        }\n    }\n\n    void VerifyUserStatisticsResult(XblUserStatisticsResult* result, JsonValue resultJson, bool isSingleUser)\n    {\n        VERIFY_IS_NOT_NULL(result);\n        VERIFY_ARE_EQUAL_STR(Utils::StringFromUint64(result->xboxUserId), resultJson[\"xuid\"].GetString());\n\n        // scids\n        auto scids = result->serviceConfigStatistics;\n        auto scidsJson = resultJson[\"scids\"].GetArray();\n        VERIFY_ARE_EQUAL_UINT(result->serviceConfigStatisticsCount, scidsJson.Size());\n\n        uint32_t i{ 0 };\n        for (auto& scidJson : scidsJson)\n        {\n            VerifyServiceConfigurationStatistic(scids[i], scidJson.GetObjectW(), isSingleUser);\n            ++i;\n        }\n    }\n\n    XblRequestedStatistics CreateRequestedStat(char const* scid, const char** statNames, uint32_t statCount)\n    {\n        XblRequestedStatistics requestedStat{};\n        requestedStat.statistics = statNames;\n        requestedStat.statisticsCount = statCount;\n        strcpy_s(requestedStat.serviceConfigurationId, scid);\n\n        return requestedStat;\n    }\n\n    void TestSingleUserStat(const char* scid, const char* statName, uint32_t bufferSizeMultiplier)\n    {\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        xsapi_internal_stringstream url;\n        url << statsServer << \"/users/xuid(\" << xuid << \")/scids/\" << scid << \"/stats/\" << statName;\n        HttpMock mock(\"GET\", url.str(), 200);\n        mock.SetResponseBody(defaultSingleUserStatsResponse);\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblUserStatisticsGetSingleUserStatisticAsync(xboxLiveContext.get(), xuid, scid, statName, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblUserStatisticsGetSingleUserStatisticResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        XblUserStatisticsResult* result{};\n        std::shared_ptr<char> buffer(new char[resultSize * bufferSizeMultiplier], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblUserStatisticsGetSingleUserStatisticResult(&async, resultSize * bufferSizeMultiplier, buffer.get(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultSingleUserStatsResponse);\n        VerifyUserStatisticsResult(result, responseJson.GetObjectW(), true);\n    }\n\n    DEFINE_TEST_CASE(TestGetSingleUserStatistics1)\n    {\n        TEST_LOG(L\"Test starting: TestGetSingleUserStatistics1\");\n\n        const char* scid{ \"7492baca-c1b4-440d-a391-b7ef364a8d40\" };\n        const char* statName{ \"OverallReputation\" };\n\n        TestSingleUserStat(scid, statName, 1);\n    }\n\n    DEFINE_TEST_CASE(TestGetSingleUserStatistics2)\n    {\n        TEST_LOG(L\"Test starting: TestGetSingleUserStatistics2\");\n\n        const char* scid{ \"7492baca-c1b4-440d-a391-b7ef364a8d41\" };\n        const char* statName{ \"UserContentReputation\" };\n\n        TestSingleUserStat(scid, statName, 1);\n    }\n\n    DEFINE_TEST_CASE(TestGetSingleUserStatisticsWithLargeBuffer1)\n    {\n        TEST_LOG(L\"Test starting: TestGetSingleUserStatisticsWithLargeBuffer1\");\n\n        const char* scid{ \"7492baca-c1b4-440d-a391-b7ef364a8d40\" };\n        const char* statName{ \"OverallReputation\" };\n\n        TestSingleUserStat(scid, statName, 2);\n    }\n\n    DEFINE_TEST_CASE(TestGetSingleUserStatisticsWithLargeBuffer2)\n    {\n        TEST_LOG(L\"Test starting: TestGetSingleUserStatisticsWithLargeBuffer2\");\n\n        const char* scid{ \"7492baca-c1b4-440d-a391-b7ef364a8d41\" };\n        const char* statName{ \"UserContentReputation\" };\n\n        TestSingleUserStat(scid, statName, 2);\n    }\n\n    void TestSingleUserStats(const char* scid, std::vector<const char*> statNames, uint32_t bufferSizeMultiplier)\n    {\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        char delimiter{};\n        xsapi_internal_stringstream url;\n        url << statsServer << \"/users/xuid(\" << xuid << \")/scids/\" << scid << \"/stats/\";\n        for (auto stat : statNames)\n        {\n            url << delimiter << stat;\n            delimiter = ',';\n        }\n        HttpMock mock(\"GET\", url.str(), 200);\n        mock.SetResponseBody(defaultSingleUserStatsResponse);\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblUserStatisticsGetSingleUserStatisticsAsync(xboxLiveContext.get(), xuid, scid, statNames.data(), 1, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_SUCCEEDED(XblUserStatisticsGetSingleUserStatisticsResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        XblUserStatisticsResult* result{};\n        std::shared_ptr<char> buffer(new char[resultSize * bufferSizeMultiplier], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblUserStatisticsGetSingleUserStatisticsResult(&async, resultSize * bufferSizeMultiplier, buffer.get(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultSingleUserStatsResponse);\n        VerifyUserStatisticsResult(result, responseJson.GetObjectW(), true);\n    }\n\n    DEFINE_TEST_CASE(TestGetSingleUserStatistics)\n    {\n        TEST_LOG(L\"Test starting: TestGetSingleUserStatistics\");\n\n        const char* scid{ \"7492baca-c1b4-440d-a391-b7ef364a8d40\" };\n        std::vector<const char*> statNames{ \"OverallReputation\", \"UserContentReputation\" };\n\n        TestSingleUserStats(scid, statNames, 1);\n    }\n\n    DEFINE_TEST_CASE(TestGetSingleUserStatisticsWithLargeBuffer)\n    {\n        TEST_LOG(L\"Test starting: TestGetSingleUserStatisticsWithLargeBuffer\");\n\n        const char* scid{ \"7492baca-c1b4-440d-a391-b7ef364a8d40\" };\n        std::vector<const char*> statNames{ \"OverallReputation\", \"UserContentReputation\" };\n\n        TestSingleUserStats(scid, statNames, 2);\n    }\n\n    DEFINE_TEST_CASE(TestGetBatchUserStatistics)\n    {\n        TEST_LOG(L\"Test starting: TestGetBatchUserStatistics\");\n\n        TestEnvironment env{};\n\n        const uint32_t xuidCount{ 2 };\n        const uint32_t nameCount{ 1 };\n        const char* scid{ \"serviceConfigId\" };\n        uint64_t xuids[xuidCount]{ 2533274792693551, 2533274792693552 };\n        const char* statNames[nameCount]{ \"namename\" };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", batchUrl, 200);\n        mock->SetResponseBody(defaultBatchUsersStatsResponse);\n        \n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, xuids, scid, statNames](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument requestJson;\n                requestJson.Parse(requestBody.c_str());\n\n                int userIndex{ 0 };\n                for (auto& requestXuid : requestJson[\"requestedusers\"].GetArray())\n                {\n                    requestWellFormed &= strcmp(Utils::StringFromUint64(xuids[userIndex]).c_str(), requestXuid.GetString()) == 0;\n                    ++userIndex;\n                }\n\n                auto& requestScid = requestJson[\"requestedscids\"].GetArray()[0];\n                requestWellFormed &= strcmp(scid, requestScid[\"scid\"].GetString()) == 0;\n\n                int nameIndex{ 0 };\n                for (auto& requestStatName : requestScid[\"requestedstats\"].GetArray())\n                {\n                    requestWellFormed &= strcmp(statNames[nameIndex], requestStatName.GetString()) == 0;\n                    ++nameIndex;\n                }\n            }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsAsync(xboxLiveContext.get(), xuids, xuidCount, scid, statNames, nameCount, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsResultSize(&async, &resultSize));\n\n        size_t resultCount{};\n        XblUserStatisticsResult* results{};\n        std::shared_ptr<char> buffer(new char[resultSize], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsResult(&async, resultSize, buffer.get(), &results, &resultCount, nullptr));\n        VERIFY_IS_NOT_NULL(results);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultBatchUsersStatsResponse);\n        VERIFY_ARE_EQUAL_INT(resultCount, responseJson[\"users\"].Size());\n\n        uint32_t i{ 0 };\n        for (auto& userJson : responseJson[\"users\"].GetArray())\n        {\n            VerifyUserStatisticsResult(&results[i], userJson.GetObjectW(), false);\n            ++i;\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetBatchUserStatisticsWithLargeBuffer)\n    {\n        TEST_LOG(L\"Test starting: TestGetBatchUserStatisticsWithLargeBuffer\");\n\n        TestEnvironment env{};\n\n        const uint32_t xuidCount{ 2 };\n        const uint32_t nameCount{ 1 };\n        const char* scid{ \"serviceConfigId\" };\n        uint64_t xuids[xuidCount]{ 2533274792693551, 2533274792693552 };\n        const char* statNames[nameCount]{ \"namename\" };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", batchUrl, 200);\n        mock->SetResponseBody(defaultBatchUsersStatsResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, xuids, scid, statNames](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            UNREFERENCED_PARAMETER(mock);\n            UNREFERENCED_PARAMETER(requestUrl);\n\n            JsonDocument requestJson;\n            requestJson.Parse(requestBody.c_str());\n\n            int userIndex{ 0 };\n            for (auto& requestXuid : requestJson[\"requestedusers\"].GetArray())\n            {\n                requestWellFormed &= strcmp(Utils::StringFromUint64(xuids[userIndex]).c_str(), requestXuid.GetString()) == 0;\n                ++userIndex;\n            }\n\n            auto& requestScid = requestJson[\"requestedscids\"].GetArray()[0];\n            requestWellFormed &= strcmp(scid, requestScid[\"scid\"].GetString()) == 0;\n\n            int nameIndex{ 0 };\n            for (auto& requestStatName : requestScid[\"requestedstats\"].GetArray())\n            {\n                requestWellFormed &= strcmp(statNames[nameIndex], requestStatName.GetString()) == 0;\n                ++nameIndex;\n            }\n        }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsAsync(xboxLiveContext.get(), xuids, xuidCount, scid, statNames, nameCount, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        size_t resultCount{};\n        XblUserStatisticsResult* results{};\n        std::shared_ptr<char> buffer(new char[resultSize * 2], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsResult(&async, resultSize * 2, buffer.get(), &results, &resultCount, &bufferUsed));\n        VERIFY_IS_NOT_NULL(results);\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultBatchUsersStatsResponse);\n        VERIFY_ARE_EQUAL_INT(resultCount, responseJson[\"users\"].Size());\n\n        uint32_t i{ 0 };\n        for (auto& userJson : responseJson[\"users\"].GetArray())\n        {\n            VerifyUserStatisticsResult(&results[i], userJson.GetObjectW(), false);\n            ++i;\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetBatchUserStatisticsForMultipleServiceConfigs)\n    {\n        TEST_LOG(L\"Test starting: TestGetBatchUserStatisticsForMultipleServiceConfigs\");\n\n        TestEnvironment env{};\n\n        const uint32_t xuidCount{ 1 };\n        const uint32_t nameCount{ 1 };\n        const uint32_t requestedStatCount{ 2 };\n        uint64_t xuids[xuidCount]{ 2533274792693551 };\n        const char* statNames[nameCount]{ \"namename\" };\n        XblRequestedStatistics requestedStats[requestedStatCount]\n        {\n            CreateRequestedStat(\"serviceConfigId1\", statNames, nameCount),\n            CreateRequestedStat(\"serviceConfigId2\", statNames, nameCount)\n        };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", batchUrl, 200);\n        mock->SetResponseBody(defaultBatchUsersStatsResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, xuids, requestedStats](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument requestJson;\n                requestJson.Parse(requestBody.c_str());\n\n                int userIndex{ 0 };\n                for (auto& requestXuid : requestJson[\"requestedusers\"].GetArray())\n                {\n                    requestWellFormed &= strcmp(Utils::StringFromUint64(xuids[userIndex]).c_str(), requestXuid.GetString()) == 0;\n                    ++userIndex;\n                }\n\n                int requestedStatIndex{ 0 };\n                for (auto& requestScid : requestJson[\"requestedscids\"].GetArray())\n                {\n                    auto stat = requestedStats[requestedStatIndex];\n                    requestWellFormed &= strcmp(stat.serviceConfigurationId, requestScid[\"scid\"].GetString()) == 0;\n                    ++requestedStatIndex;\n\n                    int statIndex{ 0 };\n                    for (auto& requestStatName : requestScid[\"requestedstats\"].GetArray())\n                    {\n                        requestWellFormed &= strcmp(stat.statistics[statIndex], requestStatName.GetString()) == 0;\n                        ++statIndex;\n                    }\n                }\n            }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(xboxLiveContext.get(), xuids, xuidCount, requestedStats, requestedStatCount, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize(&async, &resultSize));\n\n        size_t resultCount{};\n        XblUserStatisticsResult* results{};\n        std::shared_ptr<char> buffer(new char[resultSize], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult(&async, resultSize, buffer.get(), &results, &resultCount, nullptr));\n        VERIFY_IS_NOT_NULL(results);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultBatchUsersStatsResponse);\n        VERIFY_ARE_EQUAL_INT(resultCount, responseJson[\"users\"].Size());\n\n        uint32_t i{ 0 };\n        for (auto& userJson : responseJson[\"users\"].GetArray())\n        {\n            VerifyUserStatisticsResult(&results[i], userJson.GetObjectW(), false);\n            ++i;\n        }\n    }\n\n    DEFINE_TEST_CASE(TestGetBatchUserStatisticsForMultipleServiceConfigsWithLargeBuffer)\n    {\n        TEST_LOG(L\"Test starting: TestGetBatchUserStatisticsForMultipleServiceConfigsWithLargeBuffer\");\n\n        TestEnvironment env{};\n\n        const uint32_t xuidCount{ 1 };\n        const uint32_t nameCount{ 1 };\n        const uint32_t requestedStatCount{ 2 };\n        uint64_t xuids[xuidCount]{ 2533274792693551 };\n        const char* statNames[nameCount]{ \"namename\" };\n        XblRequestedStatistics requestedStats[requestedStatCount]\n        {\n            CreateRequestedStat(\"serviceConfigId1\", statNames, nameCount),\n            CreateRequestedStat(\"serviceConfigId2\", statNames, nameCount)\n        };\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", batchUrl, 200);\n        mock->SetResponseBody(defaultBatchUsersStatsResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, xuids, requestedStats](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            UNREFERENCED_PARAMETER(mock);\n            UNREFERENCED_PARAMETER(requestUrl);\n\n            JsonDocument requestJson;\n            requestJson.Parse(requestBody.c_str());\n\n            int userIndex{ 0 };\n            for (auto& requestXuid : requestJson[\"requestedusers\"].GetArray())\n            {\n                requestWellFormed &= strcmp(Utils::StringFromUint64(xuids[userIndex]).c_str(), requestXuid.GetString()) == 0;\n                ++userIndex;\n            }\n\n            int requestedStatIndex{ 0 };\n            for (auto& requestScid : requestJson[\"requestedscids\"].GetArray())\n            {\n                auto stat = requestedStats[requestedStatIndex];\n                requestWellFormed &= strcmp(stat.serviceConfigurationId, requestScid[\"scid\"].GetString()) == 0;\n                ++requestedStatIndex;\n\n                int statIndex{ 0 };\n                for (auto& requestStatName : requestScid[\"requestedstats\"].GetArray())\n                {\n                    requestWellFormed &= strcmp(stat.statistics[statIndex], requestStatName.GetString()) == 0;\n                    ++statIndex;\n                }\n            }\n        }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsAsync(xboxLiveContext.get(), xuids, xuidCount, requestedStats, requestedStatCount, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        size_t resultCount{};\n        XblUserStatisticsResult* results{};\n        std::shared_ptr<char> buffer(new char[resultSize * 2], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblUserStatisticsGetMultipleUserStatisticsForMultipleServiceConfigurationsResult(&async, resultSize * 2, buffer.get(), &results, &resultCount, &bufferUsed));\n        VERIFY_IS_NOT_NULL(results);\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultBatchUsersStatsResponse);\n        VERIFY_ARE_EQUAL_INT(resultCount, responseJson[\"users\"].Size());\n\n        uint32_t i{ 0 };\n        for (auto& userJson : responseJson[\"users\"].GetArray())\n        {\n            VerifyUserStatisticsResult(&results[i], userJson.GetObjectW(), false);\n            ++i;\n        }\n    }\n\n    DEFINE_TEST_CASE(TestRTAStatistics)\n    {\n        TEST_LOG(L\"Test starting: TestRTAStatistics\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext(xuid);\n        auto& mockRtaService{ MockRealTimeActivityService::Instance() };\n\n        const uint32_t subId{ 321 };\n        const char* statName{ \"Stat\" };\n        xsapi_internal_stringstream statsRtaUri;\n        statsRtaUri << statsServer << \"/users/xuid(\" << xuid << \")/scids/\" << rtaScid << \"/stats/\" << statName;\n\n        mockRtaService.SetSubscribeHandler([&](uint32_t n, xsapi_internal_string uri)\n        {\n            if (uri == statsRtaUri.str())\n            {\n                mockRtaService.CompleteSubscribeHandshake(n, defaultRtaStat);\n            }\n        });\n\n        VERIFY_SUCCEEDED(XblUserStatisticsTrackStatistics(xboxLiveContext.get(), &xuid, 1, rtaScid, &statName, 1));\n\n        auto handlerToken = XblUserStatisticsAddStatisticChangedHandler(xboxLiveContext.get(),\n            [](XblStatisticChangeEventArgs args, void* context)\n            {\n                auto testsContext = static_cast<UserStatsTests*>(context);\n\n                testsContext->rtaMessageWellFormed &= xuid == args.xboxUserId;\n                testsContext->rtaMessageWellFormed &= strcmp(testsContext->rtaScid, args.serviceConfigurationId) == 0;\n\n                auto stat = args.latestStatistic;\n                strcpy_s(testsContext->rtaResultName, stat.statisticName);\n                strcpy_s(testsContext->rtaResultType, stat.statisticType);\n                strcpy_s(testsContext->rtaResultValue, stat.value);\n\n                testsContext->rtaMessageReceived.Set();\n            }\n        , this);\n\n        rtaMessageReceived.Wait();\n        VERIFY_IS_TRUE(rtaMessageWellFormed);\n\n        XblStatistic resultStat{};\n        resultStat.statisticName = rtaResultName;\n        resultStat.statisticType = rtaResultType;\n        resultStat.value = rtaResultValue;\n        JsonDocument resultJson;\n        resultJson.Parse(defaultRtaStat);\n        VerifyStat(resultStat, resultJson.GetObjectW(), true);\n\n        mockRtaService.RaiseEvent(statsRtaUri.str(), \"32\");\n        rtaMessageReceived.Wait();\n        VERIFY_IS_TRUE(rtaMessageWellFormed);\n\n        XblStatistic updatedStat{};\n        updatedStat.statisticName = rtaResultName;\n        updatedStat.statisticType = rtaResultType;\n        updatedStat.value = rtaResultValue;\n        JsonDocument updatedJson;\n        updatedJson.Parse(updatedRtaStat);\n        VerifyStat(updatedStat, updatedJson.GetObjectW(), true);\n\n        XblUserStatisticsRemoveStatisticChangedHandler(xboxLiveContext.get(), handlerToken);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/StringVerifyTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char* url = \"https://client-strings.xboxlive.com/system/strings/validate\";\n\nconst char* defaultStringVerifyResult =\nR\"({\n        \"verifyStringResult\":\n        [\n            {\n                \"resultCode\": 0\n            },\n            {\n                \"resultCode\": 1,\n                \"offendingString\":\"sdfasdf\"\n            },\n            {\n                \"resultCode\": 7,\n                \"offendingString\":\"whatasfkjasl\"\n            }\n        ]\n})\";\n\nDEFINE_TEST_CLASS(StringVerifyTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(StringVerifyTests);\n\n    DEFINE_TEST_CASE(TestVerifyString)\n    {\n        TEST_LOG(L\"Test starting: TestVerifyString\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", url, 200);\n        mock->SetResponseBody(defaultStringVerifyResult);\n\n        auto requestStr = \"xboxUserId\";\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, requestStr](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument requestJson;\n                requestJson.Parse(requestBody.c_str());\n                auto requestStrJson = requestJson[\"stringsToVerify\"].GetArray();\n\n                requestWellFormed &= requestStrJson.Size() == 1;\n                requestWellFormed &= strcmp(requestStr, requestStrJson[0].GetString()) == 0;\n            }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringAsync(xboxLiveContext.get(), requestStr, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblStringVerifyStringResultSize(&async, &resultSize));\n        \n        std::shared_ptr<char> buffer(new char[resultSize], std::default_delete<char[]>());\n        XblVerifyStringResult* result{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringResult(&async, resultSize, buffer.get(), &result, nullptr));\n        VERIFY_ARE_EQUAL_INT(XblVerifyStringResultCode::Success, result->resultCode);\n        VERIFY_IS_NULL(result->firstOffendingSubstring);\n    }\n\n    DEFINE_TEST_CASE(TestVerifyStringWithLargeBuffer)\n    {\n        TEST_LOG(L\"Test starting: TestVerifyStringWithLargeBuffer\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", url, 200);\n        mock->SetResponseBody(defaultStringVerifyResult);\n\n        auto requestStr = \"xboxUserId\";\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, requestStr](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            UNREFERENCED_PARAMETER(mock);\n            UNREFERENCED_PARAMETER(requestUrl);\n\n            JsonDocument requestJson;\n            requestJson.Parse(requestBody.c_str());\n            auto requestStrJson = requestJson[\"stringsToVerify\"].GetArray();\n\n            requestWellFormed &= requestStrJson.Size() == 1;\n            requestWellFormed &= strcmp(requestStr, requestStrJson[0].GetString()) == 0;\n        }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringAsync(xboxLiveContext.get(), requestStr, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblStringVerifyStringResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        std::shared_ptr<char> buffer(new char[resultSize * 2], std::default_delete<char[]>());\n        XblVerifyStringResult* result{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringResult(&async, resultSize * 2, buffer.get(), &result, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n        VERIFY_ARE_EQUAL_INT(XblVerifyStringResultCode::Success, result->resultCode);\n        VERIFY_IS_NULL(result->firstOffendingSubstring);\n    }\n\n    DEFINE_TEST_CASE(TestVerifyStrings)\n    {\n        TEST_LOG(L\"Test starting: TestVerifyStrings\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", url, 200);\n        mock->SetResponseBody(defaultStringVerifyResult);\n\n        const size_t requestStrsCount{ 2 };\n        const char* requestStrs[requestStrsCount]{ \"asdf\", \"asdfasdf\" };\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, requestStrs, requestStrsCount](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                UNREFERENCED_PARAMETER(requestUrl);\n\n                JsonDocument requestJson;\n                requestJson.Parse(requestBody.c_str());\n                auto requestStrsJson = requestJson[\"stringsToVerify\"].GetArray();\n\n                requestWellFormed &= requestStrsJson.Size() == requestStrsCount;\n                requestWellFormed &= strcmp(requestStrs[0], requestStrsJson[0].GetString()) == 0;\n                requestWellFormed &= strcmp(requestStrs[1], requestStrsJson[1].GetString()) == 0;\n            }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringsAsync(xboxLiveContext.get(), requestStrs, requestStrsCount, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblStringVerifyStringsResultSize(&async, &resultSize));\n\n        size_t resultStrsCount{};\n        XblVerifyStringResult* results{};\n        std::shared_ptr<char> buffer(new char[resultSize], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblStringVerifyStringsResult(&async, resultSize, buffer.get(), &results, &resultStrsCount, nullptr));\n        VERIFY_ARE_EQUAL_INT(resultStrsCount, 3);\n        \n        JsonDocument responseJson;\n        responseJson.Parse(defaultStringVerifyResult);\n        auto resultsJson = responseJson[\"verifyStringResult\"].GetArray();\n        VERIFY_ARE_EQUAL_INT(resultsJson[0][\"resultCode\"].GetInt(), results[0].resultCode);\n        VERIFY_ARE_EQUAL_INT(resultsJson[1][\"resultCode\"].GetInt(), results[1].resultCode);\n        VERIFY_ARE_EQUAL_INT(resultsJson[2][\"resultCode\"].GetInt(), results[2].resultCode);\n\n        VERIFY_IS_NULL(results[0].firstOffendingSubstring);\n        VERIFY_ARE_EQUAL_STR(resultsJson[1][\"offendingString\"].GetString(), results[1].firstOffendingSubstring);\n        VERIFY_ARE_EQUAL_STR(resultsJson[2][\"offendingString\"].GetString(), results[2].firstOffendingSubstring);\n    }\n\n    DEFINE_TEST_CASE(TestVerifyStringsWithLargeBuffer)\n    {\n        TEST_LOG(L\"Test starting: TestVerifyStringsWithLargeBuffer\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        auto mock = std::make_shared<HttpMock>(\"POST\", url, 200);\n        mock->SetResponseBody(defaultStringVerifyResult);\n\n        const size_t requestStrsCount{ 2 };\n        const char* requestStrs[requestStrsCount]{ \"asdf\", \"asdfasdf\" };\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&requestWellFormed, requestStrs, requestStrsCount](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            UNREFERENCED_PARAMETER(mock);\n            UNREFERENCED_PARAMETER(requestUrl);\n\n            JsonDocument requestJson;\n            requestJson.Parse(requestBody.c_str());\n            auto requestStrsJson = requestJson[\"stringsToVerify\"].GetArray();\n\n            requestWellFormed &= requestStrsJson.Size() == requestStrsCount;\n            requestWellFormed &= strcmp(requestStrs[0], requestStrsJson[0].GetString()) == 0;\n            requestWellFormed &= strcmp(requestStrs[1], requestStrsJson[1].GetString()) == 0;\n        }\n        );\n\n        XAsyncBlock async{};\n        size_t resultSize{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringsAsync(xboxLiveContext.get(), requestStrs, requestStrsCount, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_SUCCEEDED(XblStringVerifyStringsResultSize(&async, &resultSize));\n\n        size_t bufferUsed{};\n        size_t resultStrsCount{};\n        XblVerifyStringResult* results{};\n        std::shared_ptr<char> buffer(new char[resultSize * 2], std::default_delete<char[]>());\n        VERIFY_SUCCEEDED(XblStringVerifyStringsResult(&async, resultSize * 2, buffer.get(), &results, &resultStrsCount, &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(resultSize, bufferUsed);\n        VERIFY_ARE_EQUAL_INT(resultStrsCount, 3);\n\n        JsonDocument responseJson;\n        responseJson.Parse(defaultStringVerifyResult);\n        auto resultsJson = responseJson[\"verifyStringResult\"].GetArray();\n        VERIFY_ARE_EQUAL_INT(resultsJson[0][\"resultCode\"].GetInt(), results[0].resultCode);\n        VERIFY_ARE_EQUAL_INT(resultsJson[1][\"resultCode\"].GetInt(), results[1].resultCode);\n        VERIFY_ARE_EQUAL_INT(resultsJson[2][\"resultCode\"].GetInt(), results[2].resultCode);\n\n        VERIFY_IS_NULL(results[0].firstOffendingSubstring);\n        VERIFY_ARE_EQUAL_STR(resultsJson[1][\"offendingString\"].GetString(), results[1].firstOffendingSubstring);\n        VERIFY_ARE_EQUAL_STR(resultsJson[2][\"offendingString\"].GetString(), results[2].firstOffendingSubstring);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/TestResponses/Clubs.json",
    "content": "{\n    \"addClubModeratorResponse\": {\n        \"userId\":\"2535458173220066\",\n        \"roles\": [\n            \"Follower\",\n            \"Member\",\n            \"Moderator\"\n        ]\n    },\n    \"createClubResponse\": {\n        \"name\": \"Sexy Title Club\",\n        \"owner\": \"2535430935305105\",\n        \"id\": \"3379871642723170\",\n        \"type\": \"closed\",\n        \"genre\": \"Title\",\n        \"created\": \"2017-04-27T18:00:05.6195377Z\",\n        \"titleFamilyId\": \"61d725ba-cfe1-41f5-8609-95f863f15a53\"\n    },\n    \"getClubsOwnedResponse\": {\n        \"owner\": \"2533274790395904\",\n        \"clubs\": [\n            {\n                \"name\": \"The Silent Cartographers\",\n                \"owner\": \"2533274790395904\",\n                \"id\": \"3379871642723170\",\n                \"type\": \"closed\",\n                \"genre\": \"social\"\n            }\n        ],\n        \"remainingOpenAndClosedClubs\": \"1\",\n        \"remainingSecretClubs\": \"5\",\n        \"maximumOpenAndClosedClubs\": \"2\",\n        \"maximumSecretClubs\": \"5\"\n    },\n    \"addUserToClub\": {\n        \"userId\": \"2603643534573581\",\n        \"roles\": [\n            \"Moderator\",\n            \"Owner\",\n            \"Member\",\n            \"Follower\"\n        ]\n    },\n    \"clubhubResponse\": {\n        \"clubs\": [\n            {\n                \"id\": \"3379871642723170\",\n                \"clubType\": {\n                    \"type\": \"closed\",\n                    \"genre\": \"Title\",\n                    \"localizedTitleFamilyName\": \"Beat Drop Club (en-US)\",\n                    \"titleFamilyId\": \"61d725ba-cfe1-41f5-8609-95f863f15a53\"\n                },\n                \"shortName\": null,\n                \"creationDateUtc\": \"2017-04-27T18:00:05.6195377Z\",\n                \"glyphImageUrl\": \"http://localhost/glyphImageUrl\",\n                \"bannerImageUrl\": \"http://localhost/bannerImageUrl\",\n                \"settings\": {\n                    \"feed\": {\n                        \"post\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"view\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        }\n                    },\n                    \"chat\": {\n                        \"write\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"setChatTopic\": {\n                            \"value\": \"Moderator\",\n                            \"canViewerAct\": false,\n                            \"allowedValues\": [ \"Moderator\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"view\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        }\n                    },\n                    \"lfg\": {\n                        \"join\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"create\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"view\": {\n                            \"value\": \"Member\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Member\" ],\n                            \"canViewerChangeSetting\": false\n                        }\n                    },\n                    \"roster\": {\n                        \"inviteOrAccept\": {\n                            \"value\": \"Moderator\",\n                            \"canViewerAct\": false,\n                            \"allowedValues\": [ \"Moderator\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"kickOrBan\": {\n                            \"value\": \"Moderator\",\n                            \"canViewerAct\": false,\n                            \"allowedValues\": [ \"Moderator\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"view\": {\n                            \"value\": \"Nonmember\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Nonmember\" ],\n                            \"canViewerChangeSetting\": false\n                        }\n                    },\n                    \"profile\": {\n                        \"update\": {\n                            \"value\": \"Owner\",\n                            \"canViewerAct\": false,\n                            \"allowedValues\": [ \"Owner\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"delete\": {\n                            \"value\": \"Owner\",\n                            \"canViewerAct\": false,\n                            \"allowedValues\": [ \"Owner\" ],\n                            \"canViewerChangeSetting\": false\n                        },\n                        \"view\": {\n                            \"value\": \"Nonmember\",\n                            \"canViewerAct\": true,\n                            \"allowedValues\": [ \"Nonmember\" ],\n                            \"canViewerChangeSetting\": false\n                        }\n                    },\n                    \"viewerRoles\": {\n                        \"roles\": [\n                            \"Follower\",\n                            \"Member\"\n                        ],\n                        \"localizedRole\": null\n                    }\n                },\n                \"followersCount\": 2,\n                \"membersCount\": 2,\n                \"moderatorsCount\": 1,\n                \"recommendedCount\": 0,\n                \"requestedToJoinCount\": 0,\n                \"clubPresenceCount\": 0,\n                \"clubPresenceTodayCount\": 0,\n                \"clubPresenceInGameCount\": 0,\n                \"roster\": {\n                    \"moderator\": [\n                        {\n                            \"actorXuid\": \"2535430935305105\",\n                            \"xuid\": \"2535430935305105\",\n                            \"createdDate\": \"2017-04-27T18:00:06.0500224Z\",\n                            \"localizedRole\": null\n                        }\n                    ],\n                    \"requestedToJoin\": null,\n                    \"recommended\": null,\n                    \"banned\": null\n                },\n                \"targetRoles\": {\n                    \"roles\": [\n                        {\n                            \"actorXuid\": \"2535412074763788\",\n                            \"role\": \"Follower\",\n                            \"createdDate\": \"2017-03-10T18:25:15.8059646Z\"\n                        },\n                        {\n                            \"actorXuid\": \"2535412074763788\",\n                            \"role\": \"Member\",\n                            \"createdDate\": \"2017-03-10T18:25:15.8059646Z\"\n                        },\n                        {\n                            \"actorXuid\": \"2533274829323135\",\n                            \"role\": \"Moderator\",\n                            \"createdDate\": \"2017-03-10T18:25:37.3393839Z\"\n                        }\n                    ],\n                    \"localizedRole\": \"Grunt\"\n                },\n                \"recommendation\": {\n                    \"reasons\": [\n                        {\n                            \"localizedText\": \"Played Grand Theft Auto V\"\n                        }\n                    ],\n                    \"criteria\": \"0001W3sidHlwZSI6IlBsYXllZFRpdGxlIiwibWV0YWRhdGEiOnsiVGl0bGVJZCI6Ijk3MjI0OTA5MSJ9fV0=\",\n                    \"titleIds\": [ \"972249091\" ]\n                },\n                \"clubPresence\": [\n                    {\n                        \"xuid\": \"2535412074763788\",\n                        \"lastSeenTimestamp\": \"2017-05-11T19:18:15.4480871Z\",\n                        \"lastSeenState\": \"Feed\"\n                    },\n                    {\n                        \"xuid\": \"2535430935305105\",\n                        \"lastSeenTimestamp\": \"2017-05-04T19:43:31.3341279Z\",\n                        \"lastSeenState\": \"NotInClub\"\n                    }\n                ],\n                \"state\": \"None\",\n                \"suspendedUntilUtc\": null,\n                \"reportCount\": 0,\n                \"reportedItemsCount\": 0,\n                \"maxMembersPerClub\": 50,\n                \"maxMembersInGame\": 6,\n                \"ownerXuid\": \"2535430935305105\",\n                \"founderXuid\": \"2535430935305105\",\n                \"titleDeeplinks\": {\n                    \"xbox\": [\n                        {\n                            \"titleId\": \"1748608947\",\n                            \"Uri\": \"ms-xbl-6839A7B3://\"\n                        }\n                    ],\n                    \"pc\": [ ],\n                    \"iOS\": [\n                        {\n                            \"titleId\": \"1748608947\",\n                            \"Uri\": \"http://www.minecraft.net\"\n                        }\n                    ],\n                    \"android\": [\n                        {\n                            \"titleId\": \"1748608947\",\n                            \"Uri\": \"http://www.minecraft.net\"\n                        }\n                    ]\n                },\n                \"profile\": {\n                    \"description\": {\n                        \"value\": \"Default description. Change this!\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"name\": {\n                        \"value\": \"Sexy Title Club\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"isSearchable\": {\n                        \"value\": true,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"isRecommendable\": {\n                        \"value\": true,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"requestToJoinEnabled\": {\n                        \"value\": true,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"leaveEnabled\": {\n                        \"value\": true,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"transferOwnershipEnabled\": {\n                        \"value\": true,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"matureContentEnabled\": {\n                        \"value\": false,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"watchClubTitlesOnly\": {\n                        \"value\": true,\n                        \"allowedValues\": [\n                            true,\n                            false\n                        ],\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"displayImageUrl\": {\n                        \"value\": \"http://images-eds.xboxlive.com/image?url=FgQLWnJZZZTMLcclLRvZToTpXU6V37Rxh66J9G1adzT41jLpSyb9T5takQAUw5OU5dsItuQaFIUXTgoU4tCsLspddcPKAbjpdCFMA6x4qVHwB7Ao4iGnDGtfYdPUB0BVRHXukP_Gr3qsptkka0wp8y94avsGtKuySZeDzYkellLUnjKBu9F7tf2dTorN_voizs35Z3cziDwKIFGg5GDe0oomrUqqm5SGvVAiJlskcDhCZ0zQIZma.DRYRjsVCtQr\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"backgroundImageUrl\": {\n                        \"value\": \"http://images-eds.xboxlive.com/image?url=FgQLWnJZZZTMLcclLRvZToTpXU6V37Rxh66J9G1adzQo7LpIdEyJ_jJyx7ZH7KZ84gRumNO6JdL.Sa36CwnEVPblUAnfx1J8lS5Jpc0H.IgI9QRVqiYvH3rSVimB0XQEYd3bzPLnBEWI7O3QsHYgQSeka4TCWp1U_jiQ1OicqHIkBG_sxt0uAkaJ4yEdZJ3V2llqOILolAV6MjyqWXDUyGrJ4.04IzbNG1GVBpX2ReBsIRweHmO4y9Hh7iGVBrLToHhnfbVmdeUbfY8cLsbh9N0nG67ycx8.0_UYgICcmmcqv7gLEz8K8VFb5Rv0qrnnvVLqsR1SIc0dQ05Ch.lmKQ--\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"preferredLocale\": {\n                        \"value\": \"en-US\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"tags\": {\n                        \"value\": [\n                            \"everyoneiswelcome\",\n                            \"experiencedplayersonly\"\n                        ],\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"associatedTitles\": {\n                        \"value\": [\n                            \"345903534\",\n                            \"896928775\"\n                        ],\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"primaryColor\": {\n                        \"value\": \"107c10\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"secondaryColor\": {\n                        \"value\": \"102b14\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    },\n                    \"tertiaryColor\": {\n                        \"value\": \"155715\",\n                        \"allowedValues\": null,\n                        \"canViewerChangeSetting\": false\n                    }\n                }\n            }\n        ],\n        \"searchFacetResults\": {\n            \"tags\": [\n                {\n                    \"count\": 45,\n                    \"value\": \"micoptional\"\n                },\n                {\n                    \"count\": 45,\n                    \"value\": \"swearingok\"\n                },\n                {\n                    \"count\": 33,\n                    \"value\": \"casual\"\n                },\n                {\n                    \"count\": 33,\n                    \"value\": \"cooperative\"\n                },\n                {\n                    \"count\": 32,\n                    \"value\": \"newplayerswelcome\"\n                },\n                {\n                    \"count\": 31,\n                    \"value\": \"allcontentok\"\n                },\n                {\n                    \"count\": 27,\n                    \"value\": \"everyoneiswelcome\"\n                },\n                {\n                    \"count\": 25,\n                    \"value\": \"willhelpnewplayers\"\n                },\n                {\n                    \"count\": 24,\n                    \"value\": \"competitive\"\n                },\n                {\n                    \"count\": 22,\n                    \"value\": \"achievementhunting\"\n                }\n            ],\n            \"titles\": [\n                {\n                    \"count\": 45,\n                    \"value\": \"247546985\"\n                },\n                {\n                    \"count\": 45,\n                    \"value\": \"94618376\"\n                },\n                {\n                    \"count\": 31,\n                    \"value\": \"972249091\"\n                },\n                {\n                    \"count\": 27,\n                    \"value\": \"80579825\"\n                },\n                {\n                    \"count\": 20,\n                    \"value\": \"219630713\"\n                },\n                {\n                    \"count\": 20,\n                    \"value\": \"926771636\"\n                },\n                {\n                    \"count\": 16,\n                    \"value\": \"345903534\"\n                },\n                {\n                    \"count\": 16,\n                    \"value\": \"74304278\"\n                },\n                {\n                    \"count\": 15,\n                    \"value\": \"1484511986\"\n                },\n                {\n                    \"count\": 15,\n                    \"value\": \"558797228\"\n                }\n            ]\n        },\n        \"recommendationCounts\": null\n    },\n    \"clubPresenceCounts\": {\n        \"totalCount\": 321,\n        \"activeCount\": 123,\n        \"hereTodayCount\": 200\n    },\n    \"suggestResult\": {\n        \"results\": [\n            {\n                \"text\": \"eVALKYRIES\",\n                \"result\": {\n                    \"description\": \"This is an awesome club.\",\n                    \"displayImageUrl\": \"http://localhost/3377699720589312\",\n                    \"id\": \"3377699720589312\",\n                    \"name\": \"eVALKYRIES\",\n                    \"score\": 0.043,\n                    \"tags\": [\n                        \"tag1\",\n                        \"tag2\",\n                        \"tag3\"\n                    ],\n                    \"titles\": [\n                        \"titleId1\",\n                        \"titleId2\",\n                        \"titleId3\"\n                    ]\n                }\n            },\n            {\n                \"text\": \"eVALKILMERS\",\n                \"result\": {\n                    \"description\": \"Val Kilmer <3\",\n                    \"displayImageUrl\": \"http://localhost/3377699720589518\",\n                    \"id\": \"3377699720589518\",\n                    \"name\": \"eVALKILMERS\",\n                    \"score\": 0.066,\n                    \"tags\": [\n                        \"tag1\"\n                    ],\n                    \"titles\": [\n                        \"titleId1\"\n                    ]\n                }\n            }\n        ]\n    }\n}"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/TestResponses/Matchmaking.json",
    "content": "{\n    \"defaultMatchTicketResponse\" : {\n        \"ticketStatus\":\"Found\",\n        \"waitTime\":60,\n        \"preserveSession\": \"never\",\n        \"ticketSessionRef\":\n        {\n            \"scid\": \"FEEDFACE-0000-0000-0000-000000000001\",\n            \"templateName\": \"TestTemplate\",\n            \"name\": \"5E55104-0000-0000-0000-000000000001\"\n        },\n        \"ticketAttributes\":\n        {\n            \"desiredMap\":\"Hang 'em high\",\n            \"desiredGameType\":\"Crazy King\"\n        },\n        \"players\":\n        [{\n            \"xuid\":\"123412345123\",\n            \"playerAttributes\":\n            {\n                \"skill\": \"5\",\n                \"ageRange\": \"teenager\"\n            }\n        },\n        {\n            \"xuid\":\"123412345124\",\n            \"playerAttributes\":\n            {\n                \"skill\": \"15\",\n                \"ageRange\": \"twenty-something\"\n            }\n        }],\n        \"targetSessionRef\":\n        {\n            \"scid\": \"FEEDFACE-0000-0000-0000-000000000001\",\n            \"templateName\": \"TestTemplate\",\n            \"name\": \"5E55104-0000-0000-0000-000000000002\"\n        }\n    }\n}"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/TestResponses/Multiplayer.json",
    "content": "{\n    \"rtaConnectionIdJson\": {\n        \"ConnectionId\": \"d01a8c1b-2f83-4e03-9278-3048b480928f\"\n    },\n    \"serversJson\": {\n        \"servers\": {\n            \"server\": 100\n        }\n    },\n    \"defaultSessionDocument\": {\n        \"branch\": \"b65ae271-a117-4359-b963-27ff55d3ab92\",\n        \"changeNumber\": 1,\n        \"contractVersion\": 105,\n        \"correlationId\": \"06365b64-3067-8039-ecee-3608af3d02fc\",\n        \"startTime\": \"2013-02-01T00:00:00Z\",\n        \"nextTimer\": \"2013-02-01T00:00:00Z\",\n        \"initializing\": {\n            \"stage\": \"Measuring\",\n            \"stageStartTime\": \"2013-02-01T00:00:00Z\",\n            \"episode\": 0\n        },\n        \"hostCandidates\": [\n            \"ab90a362\",\n            \"99582e67\"\n        ],\n        \"membersInfo\": {\n            \"first\": 0,\n            \"next\": 4,\n            \"count\": 2,\n            \"accepted\": 1,\n            \"active\": 1\n        },\n        \"roleTypes\": {\n            \"lfg\": {\n                \"ownerManaged\": true,\n                \"mutableRoleSettings\": [ \"max\", \"target\" ],\n                \"roles\": {\n                    \"friend\": {\n                        \"count\": 2,\n                        \"target\": 3,\n                        \"max\": 5,\n                        \"memberXuids\": [ \"1234\", \"5678\" ]\n                    },\n                    \"other\": {\n                        \"count\": 2,\n                        \"target\": 3,\n                        \"max\": 5,\n                        \"memberXuids\": [ \"1234\", \"5678\" ]\n                    }\n                }\n            }\n        },\n        \"constants\": {\n            \"system\": {\n                \"capabilities\": {\n                    \"clientMatchmaking\": true,\n                    \"connectivity\": true,\n                    \"suppressPresenceActivityCheck\": true,\n                    \"gameplay\": true,\n                    \"large\": false,\n                    \"userAuthorizationStyle\": true,\n                    \"crossPlay\": true,\n                    \"searchable\": true,\n                    \"connectionRequiredForActiveMembers\": true\n                },\n                \"version\": 1,\n                \"maxMembersCount\": 100,\n                \"visibility\": \"Open\",\n                \"initiators\": [\n                    \"3456\"\n                ],\n                \"inviteProtocol\": \"party\",\n                \"reservedRemovalTimeout\": 30000,\n                \"inactiveRemovalTimeout\": 7200000,\n                \"readyRemovalTimeout\": 180000,\n                \"sessionEmptyTimeout\": 0,\n                \"metrics\": {\n                    \"latency\": true,\n                    \"bandwidthDown\": true,\n                    \"bandwidthUp\": true,\n                    \"custom\": true\n                },\n                \"memberInitialization\": {\n                    \"joinTimeout\": 4000,\n                    \"measurementTimeout\": 5000,\n                    \"evaluationTimeout\": 5000,\n                    \"externalEvaluation\": false,\n                    \"membersNeededToStart\": 2\n                },\n                \"peerToPeerRequirements\": {\n                    \"latencyMaximum\": 250,\n                    \"bandwidthMinimum\": 10000\n                },\n                \"peerToHostRequirements\": {\n                    \"latencyMaximum\": 250,\n                    \"bandwidthDownMinimum\": 100000,\n                    \"bandwidthUpMinimum\": 1000,\n                    \"hostSelectionMetric\": \"bandwidthUp\"\n                },\n                \"measurementServerAddresses\": {\n                    \"east.azure.com\": {\n                        \"secureDeviceAddress\": \"r5Y=\"\n                    },\n                    \"west.azure.com\": {\n                        \"secureDeviceAddress\": \"rwY=\"\n                    }\n                },\n                \"cloudComputePackage\": {\n                    \"crossSandbox\": true,\n                    \"titleId\": \"4567\",\n                    \"gsiSet\": \"128ce92a-45d0-4319-8a7e-bd8e940114ec\"\n                }\n            },\n            \"custom\": {}\n        },\n        \"properties\": {\n            \"system\": {\n                \"closed\": true,\n                \"locked\": true,\n                \"allocateCloudCompute\": true,\n                \"keywords\": [\n                    \"hello\"\n                ],\n                \"turn\": [\n                    0\n                ],\n                \"owners\": [ 0 ],\n                \"host\": \"99e4c701\",\n                \"initializationSucceeded\": true,\n                \"joinRestriction\": \"None\",\n                \"readRestriction\": \"None\",\n                \"serverConnectionStringCandidates\": [\n                    \"west.azure.com\",\n                    \"east.azure.com\"\n                ],\n                \"matchmaking\": {\n                    \"clientResult\": {\n                        \"status\": \"Searching\",\n                        \"statusDetails\": \"Description\",\n                        \"typicalWait\": 30,\n                        \"targetSessionRef\": {\n                            \"scid\": \"1ECFDB89-36EB-4E59-8901-11F7393689AE\",\n                            \"templateName\": \"capture-the-flag\",\n                            \"name\": \"2D58F65F-0E3C-4F1F-8277-2BC9873FDB23\"\n                        }\n                    },\n                    \"targetSessionConstants\": {},\n                    \"serverConnectionString\": \"west.azure.com\"\n                },\n                \"matchmakingResubmit\": true\n            },\n            \"custom\": {}\n        },\n        \"servers\": {\n            \"matchmaking\": {\n                \"properties\": {\n                    \"system\": {\n                        \"status\": \"searching\",\n                        \"statusDetails\": \"test\",\n                        \"typicalWait\": 10000,\n                        \"targetSessionRef\": {\n                            \"scid\": \"1ECFDB89-36EB-4E59-8901-11F7393689AE\",\n                            \"templateName\": \"capture-the-flag\",\n                            \"name\": \"2D58F65F-0E3C-4F1F-8277-2BC9873FDB23\"\n                        }\n                    }\n                }\n            }\n        },\n        \"members\": {\n            \"0\": {\n                \"roles\": {\n                    \"lfg\": \"friend\"\n                },\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 0,\n                        \"xuid\": \"12345\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": \"Hello\"\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"everything\",\n                                \"host\"\n                            ]\n                        },\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 1\n            },\n            \"1\": {\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 1,\n                        \"xuid\": \"1234\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"everything\",\n                                \"host\"\n                            ]\n                        },\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 4\n            }\n        }\n    },\n    \"MultiplayerResponseForComparingSessions\": {\n        \"branch\": \"b65ae271-a117-4359-b963-27ff55d3ab92\",\n        \"changeNumber\": 1,\n        \"contractVersion\": 105,\n        \"correlationId\": \"06365b64-3067-8039-ecee-3608af3d02fc\",\n        \"startTime\": \"2013-02-01T00:00:00Z\",\n        \"nextTimer\": \"2013-02-01T00:00:00Z\",\n        \"initializing\": {\n            \"stage\": \"Measuring\",\n            \"stageStartTime\": \"2013-02-01T00:00:00Z\",\n            \"episode\": 0\n        },\n        \"hostCandidates\": [\n            \"ab90a362\",\n            \"99582e67\"\n        ],\n        \"membersInfo\": {\n            \"first\": 0,\n            \"next\": 4,\n            \"count\": 2,\n            \"accepted\": 1,\n            \"active\": 1\n        },\n        \"roleTypes\": {\n            \"lfg\": {\n                \"ownerManaged\": true,\n                \"mutableRoleSettings\": [ \"max\", \"target\" ],\n                \"roles\": {\n                    \"friend\": {\n                        \"count\": 2,\n                        \"target\": 3,\n                        \"max\": 5,\n                        \"memberXuids\": [ \"1234\", \"5678\" ]\n                    },\n                    \"other\": {\n                        \"count\": 2,\n                        \"target\": 3,\n                        \"max\": 5,\n                        \"memberXuids\": [ \"1234\", \"5678\" ]\n                    }\n                }\n            }\n        },\n        \"constants\": {\n            \"system\": {\n                \"capabilities\": {\n                    \"clientMatchmaking\": true,\n                    \"connectivity\": true,\n                    \"suppressPresenceActivityCheck\": true,\n                    \"gameplay\": true,\n                    \"large\": false,\n                    \"userAuthorizationStyle\": true,\n                    \"crossPlay\": true,\n                    \"searchable\": true,\n                    \"connectionRequiredForActiveMembers\": true\n                },\n                \"version\": 1,\n                \"maxMembersCount\": 100,\n                \"visibility\": \"Open\",\n                \"initiators\": [\n                    \"3456\"\n                ],\n                \"inviteProtocol\": \"party\",\n                \"reservedRemovalTimeout\": 30000,\n                \"inactiveRemovalTimeout\": 7200000,\n                \"readyRemovalTimeout\": 180000,\n                \"sessionEmptyTimeout\": 0,\n                \"metrics\": {\n                    \"latency\": true,\n                    \"bandwidthDown\": true,\n                    \"bandwidthUp\": true,\n                    \"custom\": true\n                },\n                \"memberInitialization\": {\n                    \"joinTimeout\": 4000,\n                    \"measurementTimeout\": 5000,\n                    \"evaluationTimeout\": 5000,\n                    \"externalEvaluation\": false,\n                    \"membersNeededToStart\": 2\n                },\n                \"peerToPeerRequirements\": {\n                    \"latencyMaximum\": 250,\n                    \"bandwidthMinimum\": 10000\n                },\n                \"peerToHostRequirements\": {\n                    \"latencyMaximum\": 250,\n                    \"bandwidthDownMinimum\": 100000,\n                    \"bandwidthUpMinimum\": 1000,\n                    \"hostSelectionMetric\": \"bandwidthUp\"\n                },\n                \"measurementServerAddresses\": {\n                    \"east.azure.com\": {\n                        \"secureDeviceAddress\": \"r5Y=\"\n                    },\n                    \"west.azure.com\": {\n                        \"secureDeviceAddress\": \"rwY=\"\n                    }\n                },\n                \"cloudComputePackage\": {\n                    \"crossSandbox\": true,\n                    \"titleId\": \"4567\",\n                    \"gsiSet\": \"128ce92a-45d0-4319-8a7e-bd8e940114ec\"\n                }\n            },\n            \"custom\": {}\n        },\n        \"properties\": {\n            \"system\": {\n                \"closed\": true,\n                \"locked\": true,\n                \"allocateCloudCompute\": true,\n                \"keywords\": [\n                    \"hello\"\n                ],\n                \"turn\": [\n                    0\n                ],\n                \"owners\": [ 0 ],\n                \"host\": \"99e4c701\",\n                \"initializationSucceeded\": true,\n                \"joinRestriction\": \"None\",\n                \"readRestriction\": \"None\",\n                \"serverConnectionStringCandidates\": [\n                    \"west.azure.com\",\n                    \"east.azure.com\"\n                ],\n                \"matchmaking\": {\n                    \"clientResult\": {\n                        \"status\": \"Searching\",\n                        \"statusDetails\": \"Description\",\n                        \"typicalWait\": 30,\n                        \"targetSessionRef\": {\n                            \"scid\": \"1ECFDB89-36EB-4E59-8901-11F7393689AE\",\n                            \"templateName\": \"capture-the-flag\",\n                            \"name\": \"2D58F65F-0E3C-4F1F-8277-2BC9873FDB23\"\n                        }\n                    },\n                    \"targetSessionConstants\": {},\n                    \"serverConnectionString\": \"west.azure.com\"\n                },\n                \"matchmakingResubmit\": true\n            },\n            \"custom\": {}\n        },\n        \"servers\": {\n            \"matchmaking\": {\n                \"properties\": {\n                    \"system\": {\n                        \"status\": \"searching\",\n                        \"statusDetails\": \"test\",\n                        \"typicalWait\": 10000,\n                        \"targetSessionRef\": {\n                            \"scid\": \"1ECFDB89-36EB-4E59-8901-11F7393689AE\",\n                            \"templateName\": \"capture-the-flag\",\n                            \"name\": \"12345678-0E3C-4F1F-8277-2BC9873FDB23\"\n                        }\n                    }\n                }\n            }\n        },\n        \"members\": {\n            \"0\": {\n                \"roles\": {\n                    \"lfg\": \"friend\"\n                },\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 0,\n                        \"xuid\": \"1234\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": \"Hello\"\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"everything\",\n                                \"host\"\n                            ]\n                        },\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 1\n            },\n            \"1\": {\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 1,\n                        \"xuid\": \"1234\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"everything\",\n                                \"host\"\n                            ]\n                        },\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 4\n            }\n        }\n    },\n    \"rtaSessionUpdateJson\": {\n        \"ncid\": \"508e6b30-e694-42ad-a396-5ff48612463f\",\n        \"shoulderTaps\": [\n            {\n                \"timestamp\": \"2014-10-10T20:32:46.7127383Z\",\n                \"subscription\": \"c35aa3c2-0169-492b-8ae2-0939c7089f38\",\n                \"resourceType\": \"mpsd/session\",\n                \"resource\": \"03f90100-a67f-4125-84af-a59b4ac02697~gamesession10~fba5ff99-ceaf-440a-bb96-4512706f16a2\",\n                \"branch\": \"b65ae271-a117-4359-b963-27ff55d3ab92\",\n                \"changeNumber\": 2\n            }\n        ]\n    },\n    \"defaultJsonWrite\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"maxMembersCount\": 10,\n                \"version\": 1,\n                \"visibility\": \"private\"\n            }\n        },\n        \"members\": {\n            \"me\": {\n                \"roles\": {\n                    \"lfg\": \"friend\",\n                    \"admin\": \"super\"\n                },\n                \"constants\": {\n                    \"custom\": \"Hello\",\n                    \"system\": {\n                        \"xuid\": \"1234\",\n                        \"initialize\": true\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"active\": true,\n                        \"groups\": [\n                            \"team-buzz\",\n                            \"posse.99\"\n                        ],\n                        \"encounters\": [\n                            \"CoffeeShop-757093D8-E41F-49D0-BB13-17A49B20C6B9\"\n                        ]\n                    }\n                }\n            }\n        }\n    },\n    \"sessionCapabilitiesJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"capabilities\": {\n                    \"connectivity\": true,\n                    \"gameplay\": true,\n                    \"large\": true,\n                    \"suppressPresenceActivityCheck\": true,\n                    \"connectionRequiredForActiveMembers\": true,\n                    \"userAuthorizationStyle\": true,\n                    \"crossPlay\": true,\n                    \"searchable\": true,\n                    \"hasOwners\": true\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"writeAddMemberJson\": {\n        \"members\": {\n            \"reserve_0\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\",\n                        \"initialize\": true\n                    },\n                    \"custom\": {\n                        \"skill\": 100\n                    }\n                }\n            },\n            \"reserve_1\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"4567\"\n                    },\n                    \"custom\": {\n                        \"down\": true\n                    }\n                }\n            }\n        }\n    },\n    \"writeCustomPropertyJson\": {\n        \"properties\": {\n            \"custom\": {\n                \"PropA\": \"ValueA\",\n                \"PropB\": {\n                    \"ValueB\": 5\n                },\n                \"boolTrue\": true,\n                \"boolFalse\": false,\n                \"stringTrue\": \"true\",\n                \"stringFalse\": \"false\",\n                \"number42\": 42,\n                \"objectA\": {\n                    \"name\": \"A\"\n                },\n                \"arrayA\": [\n                    1,\n                    2,\n                    3,\n                    4\n                ]\n            }\n        }\n    },\n    \"deleteCustomPropertyJson\": {\n        \"properties\": {\n            \"custom\": {\n                \"PropA\": null,\n                \"PropB\": null,\n                \"boolTrue\": null,\n                \"boolFalse\": null,\n                \"stringTrue\": null,\n                \"stringFalse\": null,\n                \"number42\": null,\n                \"objectA\": null,\n                \"arrayA\": null\n            }\n        }\n    },\n    \"memberStatusInactiveJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                }\n            }\n        }\n    },\n    \"memberStatusInactiveJson2\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    },\n                    \"custom\": {\n                        \"testValue\": 100\n                    }\n                }\n            }\n        }\n    },\n    \"memberStatusInactiveJson3\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\",\n                        \"initialize\": true\n                    },\n                    \"custom\": {\n                        \"testValue\": 100\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"active\": true\n                    }\n                }\n            }\n        }\n    },\n    \"memberStatusActiveJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"active\": false,\n                        \"ready\": false\n                    }\n                }\n            }\n        }\n    },\n    \"matchmakingPropertiesJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"active\": true\n                    }\n                }\n            }\n        }\n    },\n    \"matchmakingSessionConstantsJson\": {\n        \"properties\": {\n            \"system\": {\n                \"matchmaking\": {\n                    \"targetSessionConstants\": {\n                        \"foo\": \"test1002\"\n                    }\n                }\n            }\n        }\n    },\n    \"memberCustomJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"custom\": {\n                        \"arrayA\": [\n                            1,\n                            2,\n                            3,\n                            4\n                        ],\n                        \"boolFalse\": false,\n                        \"boolTrue\": true,\n                        \"health\": 4567,\n                        \"number42\": 42,\n                        \"objectA\": {\n                            \"name\": \"A\"\n                        },\n                        \"stringFalse\": \"false\",\n                        \"stringTrue\": \"true\"\n                    },\n                    \"system\": {\n                        \"active\": true\n                    }\n                }\n            }\n        }\n    },\n    \"deleteMemberCustomJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"custom\": {\n                        \"arrayA\": null,\n                        \"boolFalse\": null,\n                        \"boolTrue\": null,\n                        \"health\": null,\n                        \"number42\": null,\n                        \"objectA\": null,\n                        \"stringFalse\": null,\n                        \"stringTrue\": null\n                    },\n                    \"system\": {\n                        \"active\": true\n                    }\n                }\n            }\n        }\n    },\n    \"leaveJson\": {\n        \"members\": {\n            \"me\": null\n        }\n    },\n    \"secureDeviceJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"active\": true,\n                        \"secureDeviceAddress\": \"1234\"\n                    }\n                }\n            }\n        }\n    },\n    \"turnJson\": {\n        \"properties\": {\n            \"system\": {\n                \"turn\": [\n                    0\n                ]\n            }\n        }\n    },\n    \"keywordsJson\": {\n        \"properties\": {\n            \"system\": {\n                \"keywords\": [\n                    \"apple\"\n                ]\n            }\n        }\n    },\n    \"joinRestrictionJson\": {\n        \"properties\": {\n            \"system\": {\n                \"joinRestriction\": \"followed\"\n            }\n        }\n    },\n    \"TestWriteSessionAsyncWithReadRestrictionExpectedRequest\": {\n        \"properties\": {\n            \"system\": {\n                \"readRestriction\": \"followed\"\n            }\n        }\n    },\n    \"timeoutsJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"inactiveRemovalTimeout\": 3002000,\n                \"readyRemovalTimeout\": 3003000,\n                \"reservedRemovalTimeout\": 3001000,\n                \"sessionEmptyTimeout\": 3004000,\n                \"version\": 1\n            }\n        }\n    },\n    \"arbitrationTimeoutsJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"arbitration\": {\n                    \"arbitrationTimeout\": 3001000,\n                    \"forfeitTimeout\": 3002000\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"qosMetricsJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"metrics\": {\n                    \"latency\": true,\n                    \"bandwidthDown\": true,\n                    \"bandwidthUp\": true,\n                    \"custom\": true\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"measurementServerAddressJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"measurementServerAddresses\": {\n                    \"test1_target\": {\n                        \"secureDeviceAddress\": \"test1_sda\"\n                    },\n                    \"test2_target\": {\n                        \"secureDeviceAddress\": \"test2_sda\"\n                    }\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"cloudComputePackageJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"cloudComputePackage\": {\n                    \"crossSandbox\": true,\n                    \"titleId\": \"4567\",\n                    \"gsiSet\": \"128ce92a-45d0-4319-8a7e-bd8e940114ec\"\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"memberInitializationJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"memberInitialization\": {\n                    \"joinTimeout\": 4001000,\n                    \"measurementTimeout\": 4002000,\n                    \"evaluationTimeout\": 4003000,\n                    \"externalEvaluation\": true,\n                    \"membersNeededToStart\": 4004\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"peerToPeerJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"peerToPeerRequirements\": {\n                    \"latencyMaximum\": 5001,\n                    \"bandwidthMinimum\": 5002\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"peerToHostJson\": {\n        \"constants\": {\n            \"custom\": {},\n            \"system\": {\n                \"peerToHostRequirements\": {\n                    \"latencyMaximum\": 6001,\n                    \"bandwidthDownMinimum\": 6002,\n                    \"bandwidthUpMinimum\": 6003,\n                    \"hostSelectionMetric\": \"bandwidth\"\n                },\n                \"version\": 1\n            }\n        }\n    },\n    \"initializationStatusJson\": {\n        \"properties\": {\n            \"system\": {\n                \"initializationSucceeded\": true\n            }\n        }\n    },\n    \"hostDeviceTokenJson\": {\n        \"properties\": {\n            \"system\": {\n                \"host\": \"1234\"\n            }\n        }\n    },\n    \"serverConnectionPathJson\": {\n        \"properties\": {\n            \"system\": {\n                \"matchmaking\": {\n                    \"serverConnectionString\": \"8001\"\n                }\n            }\n        }\n    },\n    \"matchmakingResubmitJson\": {\n        \"properties\": {\n            \"system\": {\n                \"matchmakingResubmit\": true\n            }\n        }\n    },\n    \"serverConnectionStringCandidatesJson\": {\n        \"properties\": {\n            \"system\": {\n                \"serverConnectionStringCandidates\": [\n                    \"9001\",\n                    \"9002\",\n                    \"9003\"\n                ]\n            }\n        }\n    },\n    \"membersInGroupJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"active\": true,\n                        \"initializationGroup\": [\n                            0\n                        ]\n                    }\n                }\n            }\n        }\n    },\n    \"qosMeasurementsJson\": {\n        \"members\": {\n            \"me\": {\n                \"properties\": {\n                    \"system\": {\n                        \"measurements\": {\n                            \"test1_deviceToken\": {\n                                \"bandwidthDown\": 1002,\n                                \"bandwidthUp\": 1003,\n                                \"custom\": {\n                                    \"foo\": 1004\n                                },\n                                \"latency\": 1001\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"qosServerMeasurementsJson\": {\n        \"members\": {\n            \"me\": {\n                \"properties\": {\n                    \"system\": {\n                        \"serverMeasurements\": {\n                            \"measurement\": 1004\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"closedJson\": {\n        \"properties\": {\n            \"system\": {\n                \"closed\": true\n            }\n        }\n    },\n    \"lockedJson\": {\n        \"properties\": {\n            \"system\": {\n                \"locked\": true\n            }\n        }\n    },\n    \"activityJson\": {\n        \"type\": \"activity\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n        \"version\": 1\n    },\n    \"transferHandleJson\": {\n        \"type\": \"transfer\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n        \"originSessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"samplelobbytemplate107\",\n            \"name\": \"bd6c41c3-01c3-468a-a3b5-3e0fe8133862\"\n        },\n        \"version\": 1\n    },\n    \"transferHandleResponseJson\": {\n        \"type\": \"transfer\",\n        \"id\": \"81a3c56e-543c-44c2-ad53-c8a9088fbef8\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n        \"originSessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"samplelobbytemplate107\",\n            \"name\": \"bd6c41c3-01c3-468a-a3b5-3e0fe8133862\"\n        },\n        \"version\": 1\n    },\n    \"searchHandleJson\": {\n        \"type\": \"search\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"GlobalLFGSessionTemplateName\",\n            \"name\": \"LFGSession\"\n        },\n        \"searchAttributes\": {\n            \"tags\": [\n                \"micsrequired\",\n                \"girlsonly\"\n            ],\n            \"strings\": {\n                \"Class\": \"A\"\n            },\n            \"numbers\": {\n                \"Skill_D\": 10.145,\n                \"Skill_I\": 14\n            }\n        },\n        \"version\": 1\n    },\n    \"searchHandlesRequestJson\": {\n        \"type\": \"search\",\n        \"scid\": \"MockScid\",\n        \"templateName\": \"GlobalLFGTemplate\",\n        \"orderBy\": \"OrderBy asc\",\n        \"filter\": \"SearchQuery\",\n        \"global\": true\n    },\n    \"searchHandlesWithSocialGroupRequestJson\": {\n        \"type\": \"search\",\n        \"scid\": \"MockScid\",\n        \"templateName\": \"GlobalLFGTemplate\",\n        \"orderBy\": \"OrderBy asc\",\n        \"filter\": \"SearchQuery\",\n        \"sessionMembers\": {\n            \"people\": {\n                \"moniker\": \"favorites\",\n                \"monikerXuid\": \"1234\"\n            }\n        },\n        \"global\": true\n    },\n    \"searchHandlesResponseJson\": {\n        \"results\": [\n            {\n                \"type\": \"search\",\n                \"sessionRef\": {\n                    \"scid\": \"MockScid\",\n                    \"templateName\": \"GlobalLFGSessionTemplateName\",\n                    \"name\": \"LFGSession_A\"\n                },\n                \"searchAttributes\": {\n                    \"tags\": [\n                        \"micsrequired\",\n                        \"girlsonly\"\n                    ],\n                    \"strings\": {\n                        \"Class\": \"A\"\n                    },\n                    \"numbers\": {\n                        \"Skill_D\": 10.145,\n                        \"Skill_I\": 14\n                    }\n                },\n                \"version\": 1,\n                \"id\": \"7a4d0a99-4e23-4eba-9894-5173cf123fb4\",\n                \"createTime\": \"2013-02-01T00:00:00Z\",\n                \"customProperties\": {\n                    \"Joinability\": \"joinable_by_friends\",\n                    \"GameMode\": \"Team Assault\",\n                    \"Map\": \"Helmand Valley\"\n                },\n                \"relatedInfo\": {\n                    \"joinRestriction\": \"None\",\n                    \"closed\": false,\n                    \"maxMembersCount\": 10,\n                    \"membersCount\": 1,\n                    \"visibility\": \"open\",\n                    \"sessionOwners\": [ \"1\", \"2\" ]\n                },\n                \"roleInfo\": {\n                    \"roleTypes\": {\n                        \"lfg\": {\n                            \"roles\": {\n                                \"friend\": {\n                                    \"count\": 2,\n                                    \"max\": 5,\n                                    \"target\": 3,\n                                    \"memberXuids\": [ \"1234\", \"5678\" ]\n                                },\n                                \"other\": {\n                                    \"count\": 3,\n                                    \"max\": 5,\n                                    \"target\": 3,\n                                    \"memberXuids\": [ \"1234\", \"5678\" ]\n                                }\n                            }\n                        },\n                        \"squad\": {\n                            \"roles\": {\n                                \"friend\": {\n                                    \"count\": 2,\n                                    \"max\": 5,\n                                    \"target\": 3,\n                                    \"memberXuids\": [ \"1234\", \"5678\" ]\n                                },\n                                \"other\": {\n                                    \"count\": 3,\n                                    \"max\": 5,\n                                    \"target\": 3,\n                                    \"memberXuids\": [ \"1234\", \"5678\" ]\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        ]\n    },\n    \"inviteRequestJson\": {\n        \"type\": \"invite\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n        \"version\": 1,\n        \"invitedXuid\": \"\",\n        \"inviteAttributes\": {\n            \"titleId\": \"1234\"\n        }\n    },\n    \"inviteResponseJson\": {\n        \"type\": \"invite\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n        \"version\": 1,\n        \"inviteAttributes\": {\n            \"titleId\": \"1234\"\n        },\n        \"expiration\": \"2014-08-28T23:15:34.8852308Z\",\n        \"id\": \"\",\n        \"invitedXuid\": \"\",\n        \"senderXuid\": \"2814679796296491\"\n    },\n    \"activitiesForUserRequestJson\": {\n        \"type\": \"activity\",\n        \"scid\": \"MockScid\",\n        \"owners\": {\n            \"xuids\": [\n                \"1234\"\n            ]\n        }\n    },\n    \"activitiesForUserResponseJson\": {\n        \"results\": [\n            {\n                \"type\": \"activity\",\n                \"sessionRef\": {\n                    \"scid\": \"MockScid\",\n                    \"templateName\": \"MockSessionTemplateName\",\n                    \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n                },\n                \"version\": 1,\n                \"titleId\": \"171127034\",\n                \"ownerXuid\": \"2814679796296491\",\n                \"id\": \"7a4d0a99-4e23-4eba-9894-5173cf123fb4\",\n                \"relatedInfo\": {\n                    \"joinRestriction\": \"None\",\n                    \"closed\": false,\n                    \"maxMembersCount\": 10,\n                    \"membersCount\": 1,\n                    \"visibility\": \"private\"\n                },\n                \"customProperties\": {\n                    \"Joinability\": \"joinable_by_friends\",\n                    \"GameMode\": \"Team Assault\",\n                    \"Map\": \"Helmand Valley\"\n                }\n            }\n        ]\n    },\n    \"activitiesForSocialGroupRequestJson\": {\n        \"type\": \"activity\",\n        \"scid\": \"MockScid\",\n        \"owners\": {\n            \"people\": {\n                \"moniker\": \"friends\",\n                \"monikerXuid\": \"1234\"\n            }\n        }\n    },\n    \"activitiesForSocialGroupResponseJson\": {\n        \"results\": []\n    },\n    \"setSessionChangeTypesJson\": {\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"xuid\": \"1234\"\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"host\",\n                                \"initialization\",\n                                \"matchmakingStatus\",\n                                \"membersList\",\n                                \"membersStatus\",\n                                \"joinability\",\n                                \"customProperty\",\n                                \"membersCustomProperty\"\n                            ]\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"largeSessionDocument\": {\n        \"contractVersion\": 105,\n        \"branch\": \"334afeb9-dad2-4ee7-b786-1d9c6a816b4c\",\n        \"changeNumber\": 1,\n        \"correlationId\": \"06365b64-3067-8039-ecee-3608af3d02fc\",\n        \"startTime\": \"2013-02-01T00:00:00Z\",\n        \"nextTimer\": \"2013-02-01T00:00:00Z\",\n        \"membersInfo\": {\n            \"first\": 0,\n            \"next\": 4,\n            \"count\": 2,\n            \"accepted\": 1,\n            \"active\": 1\n        },\n        \"constants\": {\n            \"system\": {\n                \"capabilities\": {\n                    \"clientMatchmaking\": true,\n                    \"connectivity\": true,\n                    \"suppressPresenceActivityCheck\": true,\n                    \"gameplay\": true,\n                    \"large\": true\n                }\n            },\n            \"custom\": {}\n        },\n        \"properties\": {\n            \"system\": {\n                \"keywords\": [\n                    \"hello\"\n                ],\n                \"turn\": [\n                    0\n                ],\n                \"host\": \"99e4c701\",\n                \"initializationSucceeded\": true,\n                \"joinRestriction\": \"None\",\n                \"serverConnectionStringCandidates\": [\n                    \"west.azure.com\",\n                    \"east.azure.com\"\n                ]\n            },\n            \"custom\": {}\n        },\n        \"servers\": {},\n        \"members\": {\n            \"me\": {\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 0,\n                        \"xuid\": \"1234\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 4\n            }\n        }\n    },\n    \"defaultQuerySessionsResponse\": {\n        \"results\": [\n            {\n                \"xuid\": \"9876\",\n                \"startTime\": \"2013-02-01T00:00:00Z\",\n                \"sessionRef\": {\n                    \"scid\": \"foo\",\n                    \"templateName\": \"bar\",\n                    \"name\": \"session-seven\"\n                },\n                \"accepted\": 4,\n                \"status\": \"Active\",\n                \"visibility\": \"Open\",\n                \"joinRestriction\": \"Local\",\n                \"myTurn\": true,\n                \"keywords\": [\n                    \"one\",\n                    \"two\"\n                ]\n            }\n        ]\n    },\n    \"arbitrationResultJson\": {\n        \"members\": {\n            \"me\": {\n                \"properties\": {\n                    \"system\": {\n                        \"arbitration\": {\n                            \"results\": {\n                                \"team1\": {\n                                    \"outcome\": \"loss\"\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"arbitrationResultRankJson\": {\n        \"members\": {\n            \"me\": {\n                \"properties\": {\n                    \"system\": {\n                        \"arbitration\": {\n                            \"results\": {\n                                \"team1\": {\n                                    \"outcome\": \"rank\",\n                                    \"ranking\": 3\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    },\n    \"roleTypesRequestJson\": {\n        \"roleTypes\": {\n            \"lfg\": {\n                \"roles\": {\n                    \"friend\": {\n                        \"max\": 1,\n                        \"target\": 1\n                    },\n                    \"other\": {\n                        \"max\": 1,\n                        \"target\": 3\n                    }\n                }\n            }\n        }\n    },\n    \"sessionWithInitialTeamResponseJson\": {\n        \"branch\": \"b65ae271-a117-4359-b963-27ff55d3ab92\",\n        \"changeNumber\": 1,\n        \"contractVersion\": 105,\n        \"correlationId\": \"06365b64-3067-8039-ecee-3608af3d02fc\",\n        \"startTime\": \"2013-02-01T00:00:00Z\",\n        \"nextTimer\": \"2013-02-01T00:00:00Z\",\n        \"initializing\": {\n            \"stage\": \"Measuring\",\n            \"stageStartTime\": \"2013-02-01T00:00:00Z\",\n            \"episode\": 0\n        },\n        \"hostCandidates\": [\n            \"ab90a362\",\n            \"99582e67\"\n        ],\n        \"membersInfo\": {\n            \"first\": 0,\n            \"next\": 4,\n            \"count\": 2,\n            \"accepted\": 1,\n            \"active\": 1\n        },\n        \"roleTypes\": {\n            \"lfg\": {\n                \"ownerManaged\": true,\n                \"mutableRoleSettings\": [ \"max\", \"target\" ],\n                \"roles\": {\n                    \"friend\": {\n                        \"count\": 2,\n                        \"target\": 3,\n                        \"max\": 5,\n                        \"memberXuids\": [ \"1234\", \"5678\" ]\n                    },\n                    \"other\": {\n                        \"count\": 2,\n                        \"target\": 3,\n                        \"max\": 5,\n                        \"memberXuids\": [ \"1234\", \"5678\" ]\n                    }\n                }\n            }\n        },\n        \"constants\": {\n            \"system\": {\n                \"capabilities\": {\n                    \"clientMatchmaking\": true,\n                    \"connectivity\": true,\n                    \"suppressPresenceActivityCheck\": true,\n                    \"gameplay\": true,\n                    \"large\": false,\n                    \"userAuthorizationStyle\": true,\n                    \"crossPlay\": true,\n                    \"searchable\": true,\n                    \"connectionRequiredForActiveMembers\": true\n                },\n                \"version\": 1,\n                \"maxMembersCount\": 100,\n                \"visibility\": \"Open\",\n                \"initiators\": [\n                    \"3456\"\n                ],\n                \"inviteProtocol\": \"party\",\n                \"reservedRemovalTimeout\": 30000,\n                \"inactiveRemovalTimeout\": 7200000,\n                \"readyRemovalTimeout\": 180000,\n                \"sessionEmptyTimeout\": 0,\n                \"metrics\": {\n                    \"latency\": true,\n                    \"bandwidthDown\": true,\n                    \"bandwidthUp\": true,\n                    \"custom\": true\n                },\n                \"memberInitialization\": {\n                    \"joinTimeout\": 4000,\n                    \"measurementTimeout\": 5000,\n                    \"evaluationTimeout\": 5000,\n                    \"externalEvaluation\": false,\n                    \"membersNeededToStart\": 2\n                },\n                \"peerToPeerRequirements\": {\n                    \"latencyMaximum\": 250,\n                    \"bandwidthMinimum\": 10000\n                },\n                \"peerToHostRequirements\": {\n                    \"latencyMaximum\": 250,\n                    \"bandwidthDownMinimum\": 100000,\n                    \"bandwidthUpMinimum\": 1000,\n                    \"hostSelectionMetric\": \"bandwidthUp\"\n                },\n                \"measurementServerAddresses\": {\n                    \"east.azure.com\": {\n                        \"secureDeviceAddress\": \"r5Y=\"\n                    },\n                    \"west.azure.com\": {\n                        \"secureDeviceAddress\": \"rwY=\"\n                    }\n                },\n                \"cloudComputePackage\": {\n                    \"crossSandbox\": true,\n                    \"titleId\": \"4567\",\n                    \"gsiSet\": \"128ce92a-45d0-4319-8a7e-bd8e940114ec\"\n                }\n            },\n            \"custom\": {}\n        },\n        \"properties\": {\n            \"system\": {\n                \"closed\": true,\n                \"locked\": true,\n                \"allocateCloudCompute\": true,\n                \"keywords\": [\n                    \"hello\"\n                ],\n                \"turn\": [\n                    0\n                ],\n                \"owners\": [ 0 ],\n                \"host\": \"99e4c701\",\n                \"initializationSucceeded\": true,\n                \"joinRestriction\": \"None\",\n                \"readRestriction\": \"None\",\n                \"serverConnectionStringCandidates\": [\n                    \"west.azure.com\",\n                    \"east.azure.com\"\n                ],\n                \"matchmaking\": {\n                    \"clientResult\": {\n                        \"status\": \"Searching\",\n                        \"statusDetails\": \"Description\",\n                        \"typicalWait\": 30,\n                        \"targetSessionRef\": {\n                            \"scid\": \"1ECFDB89-36EB-4E59-8901-11F7393689AE\",\n                            \"templateName\": \"capture-the-flag\",\n                            \"name\": \"2D58F65F-0E3C-4F1F-8277-2BC9873FDB23\"\n                        }\n                    },\n                    \"targetSessionConstants\": {},\n                    \"serverConnectionString\": \"west.azure.com\"\n                },\n                \"matchmakingResubmit\": true\n            },\n            \"custom\": {}\n        },\n        \"servers\": {\n            \"matchmaking\": {\n                \"properties\": {\n                    \"system\": {\n                        \"status\": \"searching\",\n                        \"statusDetails\": \"test\",\n                        \"typicalWait\": 10000,\n                        \"targetSessionRef\": {\n                            \"scid\": \"1ECFDB89-36EB-4E59-8901-11F7393689AE\",\n                            \"templateName\": \"capture-the-flag\",\n                            \"name\": \"2D58F65F-0E3C-4F1F-8277-2BC9873FDB23\"\n                        }\n                    }\n                }\n            }\n        },\n        \"members\": {\n            \"0\": {\n                \"roles\": {\n                    \"lfg\": \"friend\"\n                },\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 0,\n                        \"xuid\": \"12345\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": {\n                        \"matchmakingResult\": {\n                            \"initialTeam\": \"TeamA\"\n                        }\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"everything\",\n                                \"host\"\n                            ]\n                        },\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 1\n            },\n            \"1\": {\n                \"constants\": {\n                    \"system\": {\n                        \"index\": 1,\n                        \"xuid\": \"1234\",\n                        \"initialize\": true,\n                        \"matchmakingResult\": {\n                            \"serverMeasurements\": {\n                                \"east.azure.com\": {\n                                    \"latency\": 233\n                                }\n                            }\n                        }\n                    },\n                    \"custom\": {\n                        \"matchmakingResult\": {\n                            \"initialTeam\": \"TeamB\"\n                        }\n                    }\n                },\n                \"properties\": {\n                    \"system\": {\n                        \"subscription\": {\n                            \"changeTypes\": [\n                                \"everything\",\n                                \"host\"\n                            ]\n                        },\n                        \"ready\": true,\n                        \"active\": false,\n                        \"secureDeviceAddress\": \"ryY=\",\n                        \"initializationGroup\": [\n                            5\n                        ],\n                        \"measurements\": {\n                            \"e6Kv5zY=\": {\n                                \"latency\": 5953,\n                                \"bandwidthDown\": 19342,\n                                \"bandwidthUp\": 944,\n                                \"custom\": {}\n                            }\n                        },\n                        \"serverMeasurements\": {\n                            \"east.azure.com\": {\n                                \"latency\": 233\n                            }\n                        }\n                    },\n                    \"custom\": {}\n                },\n                \"gamertag\": \"stacy\",\n                \"deviceToken\": \"9f4032ba7\",\n                \"nat\": \"Strict\",\n                \"reserved\": true,\n                \"activeTitleId\": \"8397267\",\n                \"joinTime\": \"2013-02-01T00:00:00Z\",\n                \"turn\": true,\n                \"initializationFailure\": \"Latency\",\n                \"initializationEpisode\": 0,\n                \"next\": 4\n            }\n        }\n    }\n}"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/TestResponses/MultiplayerManager.json",
    "content": "{\n    \"rtaConnectionIdJson\" : {\n        \"ConnectionId\": \"d01a8c1b-2f83-4e03-9278-3048b480928f\"\n    },\n    \"badResponse\" : {\n        \"badResponse\": null\n    },\n    \"emptyJson\" : {\n    },\n    \"propertiesJson\" : {\n        \"properties\":{  \n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       }\n    },\n    \"syncPropertiesJson\" : {\n        \"properties\":{  \n          \"custom\":{  \n             \"Map\":\"MyTestMap\",\n             \"GameMode\":\"MyTestGameMode\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       }\n    },\n    \"propertiesNoTransferHandleJson\" : {\n        \"properties\":{  \n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       }\n    },\n    \"defaultLobbySessionResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"default-lobby-session-corrId\",\n       \"changeNumber\":1\n    },\n    \"defaultLobbySessionNoCustomMemberPropsResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{ \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{}\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"default-lobby-session-corrId\",\n       \"changeNumber\":2\n    },\n    \"defaultMultipleLocalUsersLobbyResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"default-multi-user-lobby-session-corrId\",\n       \"changeNumber\":1\n    },\n    \"multipleLocalUsersLobbyResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"3456\",\n                   \"index\":1\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_3\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"default-lobby-session-corrId\",\n       \"changeNumber\":2\n    },\n    \"lobbyWithNoTransferHandleResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobby-no-trans-handle-corrId\",\n       \"changeNumber\":1\n    },\n    \"updatedLobbyWithNoTransferHandleResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"updated-lobby-no-trans-handle-corrId\",\n       \"changeNumber\":4\n    },\n    \"updatedMultipleLocalUsersLobbyWithNoTransferHandleResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"no-trans-handle\",\n       \"changeNumber\":4\n    },\n    \"lobbyWithPendingTransferHandleResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"pending~1234\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobby-pending-trans-handle-corrId\",\n       \"changeNumber\":2\n    },\n    \"lobbyWithCompletedTransferHandleResponse\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobby-completed-trans-handle-corrId\",\n       \"changeNumber\":3\n    },\n    \"defaultGameSessionResponse\" : {\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"custom\":{},\n          \"system\":{}\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":59\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"default-game-session-corrId\",\n       \"changeNumber\":1\n    },\n    \"defaultGameSessionWithXuidsResponse\" : {\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":3,\n          \"count\":3\n       },\n       \"constants\":{\n          \"system\":{\n            \"initiators\": [\n                \"TestXboxUserId_1\",\n                \"2345\",\n                \"3456\"\n            ],\n            \"version\": 1\n          },\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"custom\":{},\n          \"system\":{}\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":59\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"reserved\":true\n          },\n          \"2\":{  \n             \"next\":3,\n             \"constants\":{  \n                \"system\":{  \n                   \"xuid\":\"3456\",\n                   \"index\":2\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"reserved\":true\n          }\n       },\n       \"correlationId\":\"default-game-session-corrId\",\n       \"changeNumber\":2\n    },\n    \"defaultMultipleLocalUsersGameResponse\" : {\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"custom\":{},\n          \"system\":{}\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":59\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"default-multi-user-game-session-corrId\",\n       \"changeNumber\":1\n    },\n    \"gameSessionResponseDiffXuid\" : {\n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"custom\":{},\n          \"system\":{}\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":59\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"game-session-diff-xuid-corrId\",\n       \"changeNumber\":2\n    },\n    \"sessionChangeNum2\" : {  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"sessionChangeNum2-session-corrId\",\n       \"changeNumber\":2\n    },\n    \"sessionChangeNum3\" : {  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"sessionChangeNum3-session-corrId\",\n       \"changeNumber\":3\n    },\n    \"sessionChangeNum4\" : {  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       }, \n       \"properties\":{  \n          \"system\":{\n             \"host\":\"TestHostDeviceToken\"\n          },\n          \"custom\":{  \n             \"Map\":\"MyTestMap\",\n             \"GameMode\":\"MyTestGameMode\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"TestHostDeviceToken\",\n             \"next\":1\n          }\n       },\n       \"correlationId\":\"sessionChangeNum4-session-corrId\",\n       \"changeNumber\":4\n    },\n    \"sessionChangeNum5\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"sessionChangeNum5-session-corrId\",\n       \"changeNumber\":5\n    },\n    \"sessionChangeNum6\" : {  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"sessionChangeNum6-session-corrId\",\n       \"changeNumber\":6\n    },\n    \"sessionChangeNum8\" : {  \n        \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"sessionChangeNum8-session-corrId\",\n       \"changeNumber\":8\n    },\n    \"matchTicket\" : {\n        \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\",\n        \"waitTime\":502967\n    },\n    \"transferHandle\" : {\n        \"type\": \"transfer\",\n        \"sessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"MockSessionTemplateName\",\n            \"name\": \"XWIN_7ce12e85-594a-4b3b-9dc3-33b9a4ea57ce\"\n        },\n        \"originSessionRef\": {\n            \"scid\": \"MockScid\",\n            \"templateName\": \"samplelobbytemplate107\",\n            \"name\": \"bd6c41c3-01c3-468a-a3b5-3e0fe8133862\"\n        },\n        \"version\": 1\n    },\n    \"lobbyMatchStatusSearching\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"status\":\"searching\"\n                },\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobbyMatchStatusSearching_corrId\",\n       \"changeNumber\":4\n    },\n    \"lobbyMatchStatusExpiredByService\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"status\":\"expired\"\n                },\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobbyMatchStatusSearching_corrId\",\n       \"changeNumber\":5\n    },\n    \"lobbyMatchStatusFound\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n            \"properties\":{  \n                \"system\":{  \n                   \"status\":\"found\",\n                   \"targetSessionRef\":{  \n                        \"scid\":\"MockScid\",\n                        \"templateName\":\"MockGameSessionTemplateName\",\n                        \"name\":\"MockGameSessionName\"\n                    }\n                },\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobbyMatchStatusFound_corrId\",\n       \"changeNumber\":6\n    },\n    \"lobbyMatchStatusFoundWithTransHandle\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"status\":\"found\",\n                \"targetSessionRef\":{  \n                      \"scid\":\"MockScid\",\n                      \"templateName\":\"MockGameSessionTemplateName\",\n                      \"name\":\"MockGameSessionName\"\n                },\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n       \"members\":{  \n          \"0\":{  \n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"next\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobbyMatchStatusFoundWithTransHandle\",\n       \"changeNumber\":7\n    },\n    \"matchSessionJoin_1\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":1,\n          \"active\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"initializing\":{\n          \"stage\":\"joining\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"initializationEpisode\":1,\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"reserved\":true,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"initializationEpisode\":1\n          }\n       },\n       \"correlationId\":\"matchSessionJoin_1_corrId\",\n       \"changeNumber\":2\n    },\n    \"matchSessionJoin_2\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"matchSessionJoin_2_corrId\",\n       \"changeNumber\":4\n    },\n    \"matchSessionRemoteClientFailedToJoin\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1,\n          \"accepted\":1,\n          \"active\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"initializing\":{  \n          \"stage\":\"failed\",\n          \"stageStartTime\":\"2016-06-09T18:43:46.0518732Z\",\n          \"episode\":1\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"matchSessionFailedToJoin_corrId\",\n       \"changeNumber\":4\n    },\n    \"matchSessionMeasuring\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"initializing\":{\n          \"stage\":\"measuring\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"matchSessionMeasuring_corrId\",\n       \"changeNumber\":3\n    },\n    \"matchSessionMeasuringWithQoS\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"initializing\":{\n          \"stage\":\"measuring\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                    \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n                         \"latency\":7\n                      }\n                   }\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"matchSessionMeasuringWithQoS_corrId\",\n       \"changeNumber\":4\n    },\n    \"matchSessionMeasuringWithQoSComplete\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                    \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n                         \"latency\":7\n                      }\n                   }\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                   \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n                         \"latency\":7\n                      }\n                   }\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"matchSessionMeasuringWithQoSComplete\",\n       \"changeNumber\":6\n    },\n    \"matchRemoteClientFailedToUploadQoS\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":2,\n          \"count\":2,\n          \"accepted\":2,\n          \"active\":2\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{  \n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\",\n             \"GameSessionTransferHandle\":\"completed~TestGameSessionTransferHandle\"\n          }\n       },\n       \"initializing\":{\n          \"stage\":\"failed\",\n          \"stageStartTime\":\"2016-06-08T17:03:19.5578022Z\",\n          \"episode\":1\n       },\n       \"servers\":{},\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true,\n                    \"measurements\":{  \n                      \"cd5a3922ca9fcfb22dc5b8c634d4a754\":{  \n                         \"bandwidthDown\":27752,\n                         \"bandwidthUp\":7794,\n                         \"custom\":{  \n\n                         },\n                         \"latency\":7\n                      }\n                   }\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          },\n          \"1\":{  \n             \"next\":2,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"2345\",\n                   \"index\":1\n                },\n                \"custom\":{\n                   \"matchmakingResult\":{\n                      \"playerAttrs\":{\n                         \"OverallReputation\":\"71\",\n                         \"OverallReputationIsBad\":\"0\"\n                      },\n                      \"ticketAttrs\":{}\n                   }\n                }\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"TestGamertag_2\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"matchSessionMeasuringWithQoS_corrId\",\n       \"changeNumber\":6\n    },\n    \"lobbyMatchStatusCanceledByService\" : {  \n       \"membersInfo\":{  \n          \"first\":0,\n          \"next\":1,\n          \"count\":1\n       },\n       \"constants\":{  \n          \"system\":{},\n          \"custom\":{}\n       },\n       \"properties\":{  \n          \"system\":{\n             \"host\":\"e7c221cbe5228043c39865281047b178\"\n          },\n          \"custom\":{  \n             \"Map\":\"Helmand Valley\",\n             \"GameMode\":\"Team Battle\"\n          }\n       },\n       \"servers\":{  \n          \"matchmaking\":{  \n             \"constants\":{  \n                \"system\":{},\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"status\":\"canceled\"\n                },\n                \"custom\":{  \n                   \"ticketScid\":\"097d0100-e05c-4d37-8420-46f1169056cf\",\n                   \"ticketHopperName\":\"PlayerSkillNoQoS\",\n                   \"ticketId\":\"ad721649-569f-4151-b519-827244df9f91\"\n                }\n             }\n          }\n       },\n       \"members\":{  \n          \"0\":{  \n             \"next\":1,\n             \"constants\":{  \n                \"system\":{  \n                   \"initialize\":true,\n                   \"xuid\":\"1234\",\n                   \"index\":0\n                },\n                \"custom\":{}\n             },\n             \"properties\":{  \n                \"system\":{  \n                   \"secureDeviceAddress\":\"QVFEWGZiSWovUURScjJhTEY1dldud0VFQWlBQlNKZ0EyQkVTOFhzRk9kZjYvRklDSUFFQUFFRTNubllzQlFRTmZKUmdRd0VLZk1VNw==\",\n                   \"active\":true\n                },\n                \"custom\":{  \n                   \"Health\":89,\n                   \"Skill\":17\n                }\n             },\n             \"gamertag\":\"2 Dev 246876529\",\n             \"deviceToken\":\"\"\n          }\n       },\n       \"correlationId\":\"lobbyMatchStatusCanceled_corrId\",\n       \"changeNumber\":8\n    }\n}"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/TitleManagedStatsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char* writeStatsJson = R\"(\n{\n    \"title\": {\n        \"MyStatName1\": {\n            \"value\": 47\n        },\n        \"MyStatName2\": {\n            \"value\": \"47\"\n        }\n    }\n})\";\n\nconst char* patchStatsJson = R\"(\n{\n    \"title\": {\n        \"MyStatName1\": {\n            \"value\": \"patch\"\n        }\n    }\n})\";\n\nconst char* deleteStatsJson = R\"(\n{\n    \"title\": {\n        \"MyStatName1\": null\n    }\n})\";\n\nDEFINE_TEST_CLASS(TitleManagedStatsTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(TitleManagedStatsTests);\n\n    DEFINE_TEST_CASE(TestWriteStats)\n    {\n        TEST_LOG(L\"Test starting: TestWriteStats\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto mock{ WriteStatsMock(writeStatsJson) };\n\n        XblTitleManagedStatistic stats[]\n        {\n            { \"MyStatName1\", XblTitleManagedStatType::Number, 47 },\n            { \"MyStatName2\", XblTitleManagedStatType::String, 0, \"47\" }\n        };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleManagedStatsWriteAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            stats,\n            _countof(stats),\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(m_wellFormedRequestReceived);\n    }\n\n    DEFINE_TEST_CASE(TestUpdateStats)\n    {\n        TEST_LOG(L\"Test starting: TestUpdateStats\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto mock{ WriteStatsMock(patchStatsJson) };\n\n        XblTitleManagedStatistic stat{ \"MyStatName1\", XblTitleManagedStatType::String, 0, \"patch\" };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleManagedStatsUpdateStatsAsync(\n            xboxLiveContext.get(),\n            &stat,\n            1,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(m_wellFormedRequestReceived);\n    }\n\n    DEFINE_TEST_CASE(TestDeleteStats)\n    {\n        TEST_LOG(L\"Test starting: TestDeleteStats\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto mock{ WriteStatsMock(deleteStatsJson) };\n\n        const char* statName{ \"MyStatName1\" };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleManagedStatsDeleteStatsAsync(\n            xboxLiveContext.get(),\n            &statName,\n            1,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(m_wellFormedRequestReceived);\n    }\n\nprivate:\n    bool m_wellFormedRequestReceived{ false };\n\n    std::shared_ptr<HttpMock> WriteStatsMock(const char* expectedStatsJson) noexcept\n    {\n        m_wellFormedRequestReceived = false;\n\n        auto mock = std::make_shared<HttpMock>(\"\", \"https://statswrite.xboxlive.com\", 200);\n        mock->SetMockMatchedCallback(\n            [\n                &, expectedStatsJson\n            ]\n        (HttpMock*, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            JsonDocument requestJson;\n            requestJson.Parse(requestBody.data());\n            if (!requestJson.HasParseError() && requestJson.HasMember(\"stats\"))\n            {\n                m_wellFormedRequestReceived = VerifyJson(requestJson[\"stats\"], expectedStatsJson);\n            }\n        });\n\n        return mock;\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Services/TitleStorageTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nconst char quotaResponse[] = R\"(\n{\n    \"quotaInfo\": {\n        \"usedBytes\": 777,\n        \"quotaBytes\": 268435456\n    }\n})\";\n\nconst char blobMetadataPage1[] = R\"(\n{\n    \"blobs\": [\n        {\n            \"fileName\": \"test/sample.json,json\",\n            \"etag\": \"\\\"0x8D1C76581F12853\\\"\",\n            \"size\": 67\n        }\n    ],\n    \"pagingInfo\": {\n        \"totalItems\": 2,\n        \"continuationToken\": \"gF1nbDcy7loA_BWANNku1Go-6lM1~qH499VFFeHwow0UUKyXpSETnrEY1\"\n    }\n})\";\n\nconst char blobMetadataPage2[] = R\"(\n{\n    \"blobs\": [\n        {\n            \"fileName\": \"test/sample.json,json\",\n            \"etag\": \"\\\"0x8D1C76581F12853\\\"\",\n            \"size\": 67\n        }\n    ],\n    \"pagingInfo\": {\n        \"totalItems\": 2\n    }\n})\";\n\nconst char jsonBlob[] = R\"(\n{\n    \"isThisJson\": 1,\n    \"monstersKilled\": 10,\n    \"playerClass\": \"warrior\"\n})\";\n\nconst uint8_t binaryBlob[] = { \n    10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, \n    0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, \n    55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100, 10, 255, 101, 0, 1, 29, 50, 55, 100 \n};\n\nconst char continuationTokenJson[] = R\"(\n{\n    \"continuationToken\":\"257e3886-cf73-4b52-8e89-2d7088d60bab-1\"\n})\";\n\nDEFINE_TEST_CLASS(TitleStorageTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(TitleStorageTests)\n\n    // RAII wrapper for XblTitleStorageBlobMetadataResultHandle \n    class BlobMetadataResult\n    {\n    public:\n        explicit BlobMetadataResult(XblTitleStorageBlobMetadataResultHandle h) noexcept : handle{ h }\n        {\n            assert(handle);\n        }\n\n        BlobMetadataResult(const BlobMetadataResult& other) noexcept\n        {\n            auto hr = XblTitleStorageBlobMetadataResultDuplicateHandle(other.handle, &handle);\n            VERIFY_SUCCEEDED(hr);\n        }\n\n        BlobMetadataResult& operator=(BlobMetadataResult other)\n        {\n            std::swap(other.handle, handle);\n            return *this;\n        }\n\n        ~BlobMetadataResult() noexcept\n        {\n            XblTitleStorageBlobMetadataResultCloseHandle(handle);\n        }\n\n        std::vector<XblTitleStorageBlobMetadata> Items() const noexcept\n        {\n            const XblTitleStorageBlobMetadata* items{ nullptr };\n            size_t count{ 0 };\n            VERIFY_SUCCEEDED(XblTitleStorageBlobMetadataResultGetItems(handle, &items, &count));\n\n            return std::vector<XblTitleStorageBlobMetadata>(items, items + count);\n        }\n\n        bool HasNext() const noexcept\n        {\n            bool hasNext{ false };\n            VERIFY_SUCCEEDED(XblTitleStorageBlobMetadataResultHasNext(handle, &hasNext));\n            return hasNext;\n        }\n\n        void GetNext() noexcept\n        {\n            XAsyncBlock async{};\n            VERIFY_SUCCEEDED(XblTitleStorageBlobMetadataResultGetNextAsync(handle, 0, &async));\n            VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n            XblTitleStorageBlobMetadataResultCloseHandle(handle);\n            VERIFY_SUCCEEDED(XblTitleStorageBlobMetadataResultGetNextResult(&async, &handle));\n        }\n\n    private:\n        XblTitleStorageBlobMetadataResultHandle handle{ nullptr };\n    };\n\n    void VerifyBlobMetadata(const XblTitleStorageBlobMetadata& actual, JsonValue& expected)\n    {\n        VERIFY_IS_TRUE(expected.IsObject());\n\n        String filename = expected[\"fileName\"].GetString();\n        auto tokens{ utils::string_split_internal(filename, ',') };\n        VERIFY_ARE_EQUAL_UINT(2, tokens.size());\n        VERIFY_ARE_EQUAL_STR(tokens[0].data(), actual.blobPath);\n\n        switch (actual.blobType)\n        {\n        case XblTitleStorageBlobType::Binary:\n        {\n            VERIFY_ARE_EQUAL_STR_IGNORE_CASE(tokens[1].data(), \"binary\");\n            break;\n        }\n        case XblTitleStorageBlobType::Json:\n        {\n            VERIFY_ARE_EQUAL_STR_IGNORE_CASE(tokens[1].data(), \"json\");\n            break;\n        }\n        case XblTitleStorageBlobType::Config: // Unsupported?\n        case XblTitleStorageBlobType::Unknown:\n        default:\n        {\n            VERIFY_FAIL();\n        }\n        }\n\n        VERIFY_ARE_EQUAL_STR_IGNORE_CASE(expected[\"etag\"].GetString(), actual.eTag);\n    }\n\n    void VerifyBlobMetadataResult(const BlobMetadataResult& actual, JsonValue& expected)\n    {\n        auto actualBlobs{ actual.Items() };\n        auto expectedBlobs{ expected[\"blobs\"].GetArray() };\n        VERIFY_ARE_EQUAL_UINT(expectedBlobs.Size(), actualBlobs.size());\n\n        for (uint32_t i = 0; i < actualBlobs.size(); ++i)\n        {\n            VerifyBlobMetadata(actualBlobs[i], expectedBlobs[i]);\n        }\n    }\n\n    xsapi_internal_string ExpectedUriPath(\n        XblTitleStorageType storageType,\n        uint64_t xuid,\n        const xsapi_internal_string& scid = MOCK_SCID\n    )\n    {\n        xsapi_internal_stringstream ss;\n        switch (storageType)\n        {\n        case XblTitleStorageType::GlobalStorage:\n        {\n            ss << \"/global\";\n            break;\n        }\n        case XblTitleStorageType::Universal:\n        {\n            ss << \"/universalplatform/users/xuid(\" << xuid << \")\";\n            break;\n        }\n        case XblTitleStorageType::TrustedPlatformStorage:\n        {\n            ss << \"/trustedplatform/users/xuid(\" << xuid << \")\";\n            break;\n        }\n        }\n        ss << \"/scids/\" << scid;\n\n        return ss.str();\n    }\n\n    xsapi_internal_string ExpectedUriPath(\n        XblTitleStorageType storageType,\n        uint64_t xuid,\n        XblTitleStorageBlobType blobType,\n        const xsapi_internal_string& blobPath = \"blobPath\",\n        const xsapi_internal_string& scid = MOCK_SCID\n    )\n    {\n        xsapi_internal_stringstream ss;\n        ss << ExpectedUriPath(storageType, xuid, scid);\n        ss << \"/data/\" << blobPath << \",\";\n\n        switch (blobType)\n        {\n        case XblTitleStorageBlobType::Binary:\n        {\n            ss << \"binary\";\n            break;\n        }\n        case XblTitleStorageBlobType::Json:\n        {\n            ss << \"json\";\n            break;\n        }\n        case XblTitleStorageBlobType::Config: // Unsupported?\n        case XblTitleStorageBlobType::Unknown:\n        default:\n        {\n            assert(false);\n            break;\n        }\n        }\n        return ss.str();\n    }\n\n    void UploadBlob(\n        XblContextHandle xboxLiveContext,\n        XblTitleStorageType storageType,\n        XblTitleStorageBlobType blobType,\n        const uint8_t* uploadData,\n        size_t uploadDataSize,\n        uint32_t bufferSizeMultiplier\n    )\n    {\n        XblTitleStorageBlobMetadata metadata\n        {\n            \"blobPath\",\n            blobType,\n            storageType,\n            \"Name\",\n            \"0x52345234e3\",\n            1, // Use a non-zero client time so that we don't ignore it\n            0,\n            MOCK_SCID,\n            xboxLiveContext->Xuid()\n        };\n\n        auto mock = std::make_shared<HttpMock>( \"PUT\", \"https://titlestorage.xboxlive.com\" );\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                requestWellFormed &= !requestBody.empty();\n\n                auto queryParams = xbox::services::uri::split_query(xbox::services::uri{ requestUrl.data() }.query());\n\n                requestWellFormed &= queryParams[\"clientFileTime\"] == \"Thu,%2001%20Jan%201970%2000:00:01%20GMT\";\n                requestWellFormed &= queryParams[\"displayName\"] == metadata.displayName;\n                if (blobType == XblTitleStorageBlobType::Binary)\n                {\n                    requestWellFormed &= queryParams[\"finalBlock\"] == \"true\";\n                }\n            }\n        );\n\n        std::vector<uint8_t> buffer(uploadDataSize * bufferSizeMultiplier);\n        memcpy(buffer.data(), uploadData, uploadDataSize);\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleStorageUploadBlobAsync(\n            xboxLiveContext,\n            metadata,\n            buffer.data(),\n            uploadDataSize * bufferSizeMultiplier,\n            XblTitleStorageETagMatchCondition::NotUsed,\n            1000,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        VERIFY_SUCCEEDED(XblTitleStorageUploadBlobResult(&async, &metadata));\n    }\n\n    void DownloadBlob(\n        XblContextHandle xboxLiveContext,\n        XblTitleStorageType storageType,\n        XblTitleStorageBlobType blobType,\n        uint32_t bufferSizeMultiplier\n    )\n    {\n        auto mock = std::make_shared<HttpMock>( \"GET\", \"https://titlestorage.xboxlive.com\" );\n        const uint8_t* responseBody{ nullptr };\n        size_t responseBodySize{ 0 };\n        bool requestWellFormed{ true };\n\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n        {\n            requestWellFormed &= requestBody.empty();\n            requestWellFormed &= (HttpMock::GetUriPath(requestUrl) == ExpectedUriPath(storageType, xboxLiveContext->Xuid(), blobType));\n\n            switch (blobType)\n            {\n            case XblTitleStorageBlobType::Binary:\n            {\n                responseBody = binaryBlob;\n                responseBodySize = sizeof(binaryBlob);\n                break;\n            }\n            case XblTitleStorageBlobType::Json:\n            {\n                responseBody = reinterpret_cast<const uint8_t*>(jsonBlob);\n                responseBodySize = sizeof(jsonBlob);\n                break;\n            }\n            case XblTitleStorageBlobType::Config: // Unsupported?\n            case XblTitleStorageBlobType::Unknown:\n            default:\n            {\n                assert(false);\n                break;\n            }\n            }\n\n            mock->SetResponseBody(responseBody, responseBodySize);\n        }\n        );\n\n        size_t blobSize{ 0 };\n        switch (blobType)\n        {\n        case XblTitleStorageBlobType::Binary:\n        {\n            blobSize = sizeof(binaryBlob);\n            break;\n        }\n        case XblTitleStorageBlobType::Json:\n        {\n            blobSize = sizeof(jsonBlob);\n            break;\n        }\n        case XblTitleStorageBlobType::Config: // Unsupported?\n        case XblTitleStorageBlobType::Unknown:\n        default:\n        {\n            assert(false);\n            break;\n        }\n        }\n\n        XblTitleStorageBlobMetadata metadata\n        {\n            \"blobPath\",\n            blobType,\n            storageType,\n            \"Name\",\n            \"0x52345234e3\",\n            0,\n            blobSize,\n            MOCK_SCID,\n            xboxLiveContext->Xuid()\n        };\n\n        std::vector<uint8_t> retreivedBlob(blobSize * bufferSizeMultiplier);\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleStorageDownloadBlobAsync(\n            xboxLiveContext,\n            metadata,\n            retreivedBlob.data(),\n            retreivedBlob.size(),\n            XblTitleStorageETagMatchCondition::NotUsed,\n            nullptr,\n            0,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        VERIFY_SUCCEEDED(XblTitleStorageDownloadBlobResult(&async, &metadata));\n        VERIFY_ARE_EQUAL_UINT(responseBodySize, metadata.length);\n        VERIFY_IS_TRUE(memcmp(responseBody, retreivedBlob.data(), retreivedBlob.size() / bufferSizeMultiplier) == 0);\n    }\n\n    void DeleteBlob(\n        XblContextHandle xboxLiveContext,\n        XblTitleStorageType storageType,\n        XblTitleStorageBlobType blobType\n    )\n    {\n        auto mock = std::make_shared<HttpMock>( \"DELETE\", \"https://titlestorage.xboxlive.com\" );\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                requestWellFormed &= requestBody.empty();\n                requestWellFormed &= (HttpMock::GetUriPath(requestUrl) == ExpectedUriPath(storageType, xboxLiveContext->Xuid(), blobType));\n            }\n        );\n\n        XblTitleStorageBlobMetadata metadata\n        {\n            \"blobPath\",\n            blobType,\n            storageType,\n            \"Name\",\n            \"0x52345234e3\",\n            0,\n            0,\n            MOCK_SCID,\n            xboxLiveContext->Xuid()\n        };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleStorageDeleteBlobAsync(\n            xboxLiveContext,\n            metadata,\n            true,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n    }\n\n    void GetBlobMetadata(\n        XblContextHandle xboxLiveContext,\n        XblTitleStorageType type\n    )\n    {\n        auto mock = std::make_shared<HttpMock>( \"GET\", \"https://titlestorage.xboxlive.com\" );\n        JsonDocument responseJson;\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                requestWellFormed &= requestBody.empty();\n\n                xsapi_internal_string expectedPath{ ExpectedUriPath(type, xboxLiveContext->Xuid()) };\n                expectedPath += \"/data/blobPath\";\n\n                requestWellFormed &= (HttpMock::GetUriPath(requestUrl) == expectedPath);\n\n                if (HttpMock::GetUriQuery(requestUrl).find(\"continuationToken\") != string_t::npos)\n                {\n                    responseJson.Parse(blobMetadataPage2);\n                }\n                else\n                {\n                    responseJson.Parse(blobMetadataPage1);\n                }\n                mock->SetResponseBody(responseJson);\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleStorageGetBlobMetadataAsync(\n            xboxLiveContext,\n            MOCK_SCID,\n            type,\n            \"blobPath\",\n            xboxLiveContext->Xuid(),\n            0,\n            0,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        XblTitleStorageBlobMetadataResultHandle handle{ nullptr };\n        VERIFY_SUCCEEDED(XblTitleStorageGetBlobMetadataResult(&async, &handle));\n\n        BlobMetadataResult result{ handle };\n        VerifyBlobMetadataResult(result, responseJson);\n\n        while (result.HasNext())\n        {\n            result.GetNext();\n            VERIFY_IS_TRUE(requestWellFormed);\n            VerifyBlobMetadataResult(result, responseJson);\n        }\n    }\n\n    void GetQuota(\n        XblContextHandle xboxLiveContext,\n        XblTitleStorageType type\n    )\n    {\n        auto mock = std::make_shared<HttpMock>( \"GET\", \"https://titlestorage.xboxlive.com\" );\n        mock->SetResponseBody(quotaResponse);\n\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(mock);\n                requestWellFormed &= requestBody.empty();\n                requestWellFormed &= (HttpMock::GetUriPath(requestUrl) == ExpectedUriPath(type, xboxLiveContext->Xuid()));\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleStorageGetQuotaAsync(xboxLiveContext, MOCK_SCID, type, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n\n        size_t usedBytes{ 0 };\n        size_t quotaBytes{ 0 };\n        VERIFY_SUCCEEDED(XblTitleStorageGetQuotaResult(&async, &usedBytes, &quotaBytes));\n\n        JsonDocument quotaJson;\n        quotaJson.Parse(quotaResponse);\n        VERIFY_ARE_EQUAL_UINT(quotaJson[\"quotaInfo\"][\"usedBytes\"].GetUint64(), usedBytes);\n        VERIFY_ARE_EQUAL_UINT(quotaJson[\"quotaInfo\"][\"quotaBytes\"].GetUint64(), quotaBytes);\n    }\n\n    DEFINE_TEST_CASE(GetQuotaTest)\n    {\n        TEST_LOG(L\"Test starting: GetQuotaTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        GetQuota(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage);\n        GetQuota(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage);\n        GetQuota(xboxLiveContext.get(), XblTitleStorageType::Universal);\n    }\n\n    DEFINE_TEST_CASE(GetBlobMetadataTest)\n    {\n        TEST_LOG(L\"Test starting: GetBlobMetadataTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        GetBlobMetadata(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage);\n        GetBlobMetadata(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage);\n        GetBlobMetadata(xboxLiveContext.get(), XblTitleStorageType::Universal);\n    }\n\n    DEFINE_TEST_CASE(DeleteBlobTest)\n    {\n        TEST_LOG(L\"Test starting: DeleteBlobTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        DeleteBlob(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage, XblTitleStorageBlobType::Json);\n        DeleteBlob(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage, XblTitleStorageBlobType::Binary);\n        DeleteBlob(xboxLiveContext.get(), XblTitleStorageType::Universal, XblTitleStorageBlobType::Json);\n        DeleteBlob(xboxLiveContext.get(), XblTitleStorageType::Universal, XblTitleStorageBlobType::Binary);\n    }\n\n    DEFINE_TEST_CASE(DownloadBlobTest)\n    {\n        TEST_LOG(L\"Test starting: DownloadBlobTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage, XblTitleStorageBlobType::Json, 1);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage, XblTitleStorageBlobType::Binary, 1);\n        //DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage, XblTitleStorageBlobType::Config, 1); Unsupported?\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage, XblTitleStorageBlobType::Json, 1);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage, XblTitleStorageBlobType::Binary, 1);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::Universal, XblTitleStorageBlobType::Json, 1);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::Universal, XblTitleStorageBlobType::Binary, 1);\n    }\n\n    DEFINE_TEST_CASE(DownloadBlobWithLargeBufferTest)\n    {\n        TEST_LOG(L\"Test starting: DownloadBlobWithLargeBufferTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage, XblTitleStorageBlobType::Json, 2);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage, XblTitleStorageBlobType::Binary, 2);\n        //DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::GlobalStorage, XblTitleStorageBlobType::Config, 2); Unsupported?\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage, XblTitleStorageBlobType::Json, 2);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::TrustedPlatformStorage, XblTitleStorageBlobType::Binary, 2);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::Universal, XblTitleStorageBlobType::Json, 2);\n        DownloadBlob(xboxLiveContext.get(), XblTitleStorageType::Universal, XblTitleStorageBlobType::Binary, 2);\n    }\n\n    DEFINE_TEST_CASE(UploadBlobTest)\n    {\n        TEST_LOG(L\"Test starting: UploadBlobTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::TrustedPlatformStorage,\n            XblTitleStorageBlobType::Json,\n            reinterpret_cast<const uint8_t*>(jsonBlob),\n            sizeof(jsonBlob),\n            1\n        );\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::TrustedPlatformStorage,\n            XblTitleStorageBlobType::Binary,\n            binaryBlob,\n            sizeof(binaryBlob),\n            1\n        );\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::Universal,\n            XblTitleStorageBlobType::Json,\n            reinterpret_cast<const uint8_t*>(jsonBlob),\n            sizeof(jsonBlob),\n            1\n        );\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::Universal,\n            XblTitleStorageBlobType::Binary,\n            binaryBlob,\n            sizeof(binaryBlob),\n            1\n        );\n    }\n\n    DEFINE_TEST_CASE(UploadBlobWithLargeBufferTest)\n    {\n        TEST_LOG(L\"Test starting: UploadBlobWithLargeBufferTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::TrustedPlatformStorage,\n            XblTitleStorageBlobType::Json,\n            reinterpret_cast<const uint8_t*>(jsonBlob),\n            sizeof(jsonBlob),\n            2\n        );\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::TrustedPlatformStorage,\n            XblTitleStorageBlobType::Binary,\n            binaryBlob,\n            sizeof(binaryBlob),\n            2\n        );\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::Universal,\n            XblTitleStorageBlobType::Json,\n            reinterpret_cast<const uint8_t*>(jsonBlob),\n            sizeof(jsonBlob),\n            2\n        );\n\n        UploadBlob(\n            xboxLiveContext.get(),\n            XblTitleStorageType::Universal,\n            XblTitleStorageBlobType::Binary,\n            binaryBlob,\n            sizeof(binaryBlob),\n            2\n        );\n    }\n\n    DEFINE_TEST_CASE(UploadBlobMultipleChunksTest)\n    {\n        TEST_LOG(L\"Test starting: UploadBlobMultipleChunksTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        const size_t blockSize{ 256 * 1024 };\n        uint8_t data[blockSize + 1]; // ensure there are two chunks\n        for (uint32_t i = 0; i < _countof(data); ++i)\n        {\n            data[i] = rand() % UCHAR_MAX;\n        }\n\n        XblTitleStorageBlobMetadata metadata\n        {\n            \"blobPath\",\n            XblTitleStorageBlobType::Binary,\n            XblTitleStorageType::Universal,\n            \"Name\",\n            \"0x52345234e3\",\n            0,\n            0,\n            MOCK_SCID,\n            xboxLiveContext->Xuid()\n        };\n\n        // This should result in multiple Http calls (1 per chunk), but intermediate results should not be\n        // propagated to the client\n        auto mock = std::make_shared<HttpMock>( \"PUT\", \"https://titlestorage.xboxlive.com\" );\n\n        uint32_t requestCount{ 0 };\n        bool requestWellFormed{ true };\n        mock->SetMockMatchedCallback(\n            [&](HttpMock* mock, xsapi_internal_string requestUrl, xsapi_internal_string requestBody)\n            {\n                UNREFERENCED_PARAMETER(requestBody);\n\n                auto queryParams = xbox::services::uri::split_query(xbox::services::uri{ requestUrl.data() }.query());\n                if (queryParams[\"finalBlock\"] == \"true\")\n                {\n                    // Validate that we supplied the continuation token\n                    JsonDocument d;\n                    d.Parse(continuationTokenJson);\n\n                    requestWellFormed &= d[\"continuationToken\"].GetString() == queryParams[\"continuationToken\"];\n                    \n                    // no response body in this case\n                    mock->ClearReponseBody();\n                }\n                else if (queryParams[\"finalBlock\"] == \"false\")\n                {\n                    mock->SetResponseBody(continuationTokenJson);\n                }\n                else\n                {\n                    assert(false);\n                }\n                requestCount++;\n            }\n        );\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblTitleStorageUploadBlobAsync(\n            xboxLiveContext.get(),\n            metadata,\n            data,\n            sizeof(data),\n            XblTitleStorageETagMatchCondition::NotUsed,\n            blockSize,\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        VERIFY_IS_TRUE(requestWellFormed);\n        VERIFY_ARE_EQUAL_UINT(2, requestCount);\n\n        VERIFY_SUCCEEDED(XblTitleStorageUploadBlobResult(&async, &metadata));\n    }\n\n    DEFINE_TEST_CASE(TitleStorageInvalidArgsTest)\n    {\n        TEST_LOG(L\"Test starting: TitleStorageInvalidArgsTest\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        XAsyncBlock async{};\n        VERIFY_ARE_EQUAL_INT(\n            XblTitleStorageDeleteBlobAsync(xboxLiveContext.get(), XblTitleStorageBlobMetadata{}, true, &async), \n            E_INVALIDARG\n        );\n\n        XblTitleStorageBlobMetadata metadata\n        {\n            \"blobPath\",\n            XblTitleStorageBlobType::Json,\n            XblTitleStorageType::GlobalStorage,\n            \"Name\",\n            \"0x52345234e3\",\n            0,\n            0,\n            MOCK_SCID,\n            xboxLiveContext->Xuid()\n        };\n\n        std::vector<uint8_t> buffer(10);\n\n        VERIFY_ARE_EQUAL_INT(XblTitleStorageDownloadBlobAsync(\n            xboxLiveContext.get(),\n            XblTitleStorageBlobMetadata{},\n            buffer.data(),\n            buffer.size(),\n            XblTitleStorageETagMatchCondition::NotUsed,\n            nullptr,\n            0,\n            &async\n        ), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_INT(XblTitleStorageDownloadBlobAsync(\n            xboxLiveContext.get(),\n            metadata,\n            nullptr,\n            0,\n            XblTitleStorageETagMatchCondition::NotUsed,\n            nullptr,\n            0,\n            &async\n        ), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_INT(XblTitleStorageUploadBlobAsync(\n            xboxLiveContext.get(),\n            XblTitleStorageBlobMetadata{},\n            buffer.data(),\n            buffer.size(),\n            XblTitleStorageETagMatchCondition::NotUsed,\n            0,\n            &async\n        ), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_INT(XblTitleStorageUploadBlobAsync(\n            xboxLiveContext.get(),\n            metadata,\n            nullptr,\n            0,\n            XblTitleStorageETagMatchCondition::NotUsed,\n            0,\n            &async\n        ), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_INT(XblTitleStorageGetBlobMetadataAsync(\n            xboxLiveContext.get(),\n            nullptr,\n            XblTitleStorageType::GlobalStorage,\n            nullptr,\n            0,\n            0,\n            0,\n            &async\n        ), E_INVALIDARG);\n\n        VERIFY_ARE_EQUAL_INT(XblTitleStorageGetQuotaAsync(\n            xboxLiveContext.get(),\n            nullptr,\n            XblTitleStorageType::GlobalStorage,\n            &async\n        ), E_INVALIDARG);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/GlobalTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nsize_t g_memAllocHookCalls{ 0 };\nsize_t g_memFreeHookCalls{ 0 };\nstd::unordered_map<void*, size_t> g_allocationMap{};\n\nconst char getProfileResponse[] = R\"(\n{\n      \"profileUsers\": [\n         {\n            \"id\":\"2533274791381930\",\n            \"settings\" : [\n               {\n                  \"id\":\"GameDisplayName\",\n                  \"value\" : \"John Smith\"\n               },\n               {\n                  \"id\":\"GameDisplayPicRaw\",\n                  \"value\" : \"http://images-eds.xboxlive.com/image?url=z951ykn43p4FqWbbFvR2Ec.8vbDhj8G2Xe7JngaTToBrrCmIEEXHC9UNrdJ6P7KIN0gxC2r1YECCd3mf2w1FDdmFCpSokJWa2z7xtVrlzOyVSc6pPRdWEXmYtpS2xE4F\"\n               },\n               {\n                  \"id\":\"Gamerscore\",\n                  \"value\" : \"0\"\n               },\n               {\n                  \"id\":\"Gamertag\",\n                  \"value\" : \"CracklierJewel9\"\n               }\n            ],\n            \"isSponsoredUser\":false\n         }\n      ]\n})\";\n\nDEFINE_TEST_CLASS(GlobalTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(GlobalTests);\n\n    DEFINE_TEST_CASE(TestXblInitializeAndCleanup)\n    {\n        TEST_LOG(L\"Test starting: TestXblInitializeAndCleanup\");\n\n        XTaskQueueHandle queueHandle{};\n        VERIFY_SUCCEEDED(XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::ThreadPool, &queueHandle));\n        TaskQueue queue{ queueHandle };\n\n        std::string scid{ \"TestScid\" };\n\n        XblInitArgs args{};\n        args.queue = queueHandle;\n        args.scid = scid.data();\n        char folder[MAX_PATH] = {};\n        GetCurrentDirectoryA(MAX_PATH, folder);\n        args.localStoragePath = folder;\n\n        TestEnvironment env{ &args };\n\n        const char* actualScid{ nullptr };\n        VERIFY_SUCCEEDED(XblGetScid(&actualScid));\n        VERIFY_IS_TRUE(scid == actualScid);\n\n        XTaskQueueHandle actualQueue = XblGetAsyncQueue();\n        // By design the queue returned is different than the queue provided, so just validate that the\n        // returned Queue is non-null\n        VERIFY_IS_NOT_NULL(actualQueue);\n    }\n\n    DEFINE_TEST_CASE(TestServiceCallRouted)\n    {\n        TEST_LOG(L\"Test starting: TestServiceCallRouted\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        struct CallRoutedContext \n        {\n            ~CallRoutedContext()\n            {\n                SetCallHandle(nullptr);\n            }\n\n            HCCallHandle CallHandle() const noexcept\n            {\n                return m_callHandle;\n            }\n\n            void SetCallHandle(HCCallHandle callHandle) noexcept\n            {\n                if (m_callHandle)\n                {\n                    VERIFY_SUCCEEDED(HCHttpCallCloseHandle(m_callHandle));\n                }\n                m_callHandle = HCHttpCallDuplicateHandle(callHandle);\n            }\n\n            size_t responseCount{ 0 };\n        private:\n            HCCallHandle m_callHandle{ nullptr };\n        } c;\n\n        auto token = XblAddServiceCallRoutedHandler(\n            [](XblServiceCallRoutedArgs args, void* context)\n            {\n                LOGS_DEBUG << \"Received call routed callback: \" << args.fullResponseFormatted;\n\n                auto callRoutedContext{ static_cast<CallRoutedContext*>(context) };\n                callRoutedContext->SetCallHandle(args.call);\n                callRoutedContext->responseCount++;\n            },\n            &c\n        );\n\n        JsonDocument getProfileResponseJson;\n        getProfileResponseJson.Parse(getProfileResponse);\n        HttpMock mock{ \"POST\", \"https://profile.xboxlive.com\", 200, getProfileResponseJson };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblProfileGetUserProfileAsync(\n            xboxLiveContext.get(),\n            xboxLiveContext->Xuid(),\n            &async\n        ));\n\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n        XblUserProfile profile{};\n        VERIFY_SUCCEEDED(XblProfileGetUserProfileResult(&async, &profile));\n\n        VERIFY_IS_NOT_NULL(c.CallHandle());\n        VERIFY_ARE_EQUAL_INT(1, c.responseCount);\n\n        const char* actualUrl{ nullptr };\n        VERIFY_SUCCEEDED(HCHttpCallGetRequestUrl(c.CallHandle(), &actualUrl));\n\n        std::string expectedUrl{ \"https://profile.xboxlive.com\" };\n        VERIFY_IS_TRUE(std::string{ actualUrl }.substr(0, expectedUrl.size()) == expectedUrl);\n\n        uint32_t httpStatus;\n        VERIFY_SUCCEEDED(HCHttpCallResponseGetStatusCode(c.CallHandle(), &httpStatus));\n        VERIFY_ARE_EQUAL_INT(httpStatus, 200);\n\n        const char* responseBody{ nullptr };\n        VERIFY_SUCCEEDED(HCHttpCallResponseGetResponseString(c.CallHandle(), &responseBody));\n        JsonDocument responseBodyJson;\n        responseBodyJson.Parse(responseBody);\n        VERIFY_IS_EQUAL_JSON(responseBodyJson, getProfileResponseJson);\n\n        XblRemoveServiceCallRoutedHandler(token);\n    }\n\n    DEFINE_TEST_CASE(TestMemoryHook)\n    {\n        TEST_LOG(L\"Test starting: TestMemoryHook\");\n\n        class MemoryManager\n        {\n        public:\n            MemoryManager() noexcept\n            {\n                g_memAllocHookCalls = 0;\n                g_memFreeHookCalls = 0;\n                g_allocationMap.clear();\n\n                VERIFY_SUCCEEDED(XblMemSetFunctions(MemAllocHook, MemFreeHook));\n            }\n\n            ~MemoryManager() noexcept\n            {\n                VERIFY_SUCCEEDED(XblMemSetFunctions(nullptr, nullptr));\n            }\n        private:\n            static _Ret_maybenull_ _Post_writable_byte_size_(dwSize) void* STDAPIVCALLTYPE MemAllocHook(\n                _In_ size_t dwSize,\n                _In_ HCMemoryType memType\n            )\n            {\n                UNREFERENCED_PARAMETER(memType);\n                auto ptr{ new char[dwSize] };\n                g_allocationMap[ptr] = g_memAllocHookCalls++;\n                return ptr;\n            }\n\n            static void STDAPIVCALLTYPE MemFreeHook(\n                _In_ void* pAddress,\n                _In_ HCMemoryType memType\n            )\n            {\n                UNREFERENCED_PARAMETER(memType);\n                g_memFreeHookCalls++;\n#if _DEBUG\n                size_t removed{ g_allocationMap.erase(pAddress) };\n                assert(removed);\n#endif\n                delete[] pAddress;\n            }\n        } memoryManager;\n\n        {\n            TestEnvironment env{};\n\n            // We don't know how many allocation XSAPI will make during initialize, but validate that the hook is used\n            VERIFY_IS_TRUE(g_memAllocHookCalls > 0);\n        }\n\n        VERIFY_ARE_EQUAL_INT(g_memAllocHookCalls, g_memFreeHookCalls);\n    }\n\n    struct CancellableOperation\n    {\n    public:\n        CancellableOperation() noexcept = default;\n        ~CancellableOperation() noexcept = default;\n\n        HRESULT Run(XAsyncBlock* async) noexcept\n        {\n            return XAsyncBegin(async, this, nullptr, __FUNCTION__, CancellableOperation::Provider);\n        }\n\n        std::atomic<bool> complete{ false };\n\n    private:\n        static HRESULT CALLBACK Provider(XAsyncOp op, const XAsyncProviderData* data) noexcept\n        {\n            auto pThis{ static_cast<CancellableOperation*>(data->context) };\n\n            switch (op)\n            {\n            case XAsyncOp::Begin:\n            {\n                return XAsyncSchedule(data->async, 0);\n            }\n            case XAsyncOp::DoWork:\n            {\n                if (!pThis->complete)\n                {\n                    RETURN_HR_IF_FAILED(XAsyncSchedule(data->async, 1000));\n                    return E_PENDING;\n                }\n                return S_OK;\n            }\n            case XAsyncOp::Cancel:\n            {\n                return S_OK;\n            }\n            default:\n            {\n                return S_OK;\n            }\n            }\n        };\n    };\n\n    DEFINE_TEST_CASE(TestCancellation)\n    {\n        TEST_LOG(L\"Test starting: TestCancellation\");\n\n        XTaskQueueHandle queue{ nullptr };\n        VERIFY_SUCCEEDED(XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::ThreadPool, &queue));\n\n        XAsyncBlock async{ queue };\n\n        CancellableOperation op;\n        op.Run(&async);\n\n        std::thread terminator{ [&]\n        {\n            Sleep(50);\n            XTaskQueueTerminate(queue, true, nullptr, nullptr);\n        } };\n\n        HRESULT hr = XAsyncGetStatus(&async, true);\n        VERIFY_ARE_EQUAL(hr, E_ABORT);\n\n        terminator.join();\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/HttpCallSettingsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(XboxLiveContextSettingsTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(XboxLiveContextSettingsTests);\n\n    DEFINE_TEST_CASE(TestXboxLiveContextSettingsApis)\n    {\n        TEST_LOG(L\"Test starting: TestXboxLiveContextSettingsApis\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto contextHandle{ xboxLiveContext.get() };\n\n        // Verify Set/Get\n        uint32_t desiredTimeout{ 60 }, actualTimeout{};\n        VERIFY_SUCCEEDED(XblContextSettingsSetLongHttpTimeout(contextHandle, desiredTimeout));\n        VERIFY_SUCCEEDED(XblContextSettingsGetLongHttpTimeout(contextHandle, &actualTimeout));\n        VERIFY_ARE_EQUAL_UINT(desiredTimeout, actualTimeout);\n\n        uint32_t desiredRetryDelay{ 60 }, actualRetryDelay{};\n        VERIFY_SUCCEEDED(XblContextSettingsSetHttpRetryDelay(contextHandle, desiredRetryDelay));\n        VERIFY_SUCCEEDED(XblContextSettingsGetHttpRetryDelay(contextHandle, &actualRetryDelay));\n        VERIFY_ARE_EQUAL_UINT(desiredRetryDelay, actualRetryDelay);\n\n        uint32_t desiredRetryWindow{ 60 }, actualRetryWindow{};\n        VERIFY_SUCCEEDED(XblContextSettingsSetHttpTimeoutWindow(contextHandle, desiredRetryWindow));\n        VERIFY_SUCCEEDED(XblContextSettingsGetHttpTimeoutWindow(contextHandle, &actualRetryWindow));\n        VERIFY_ARE_EQUAL_UINT(desiredRetryWindow, actualRetryWindow);\n\n        uint32_t desiredWebsocketTimeout{ 60 }, actualWebsocketTimeout{};\n        VERIFY_SUCCEEDED(XblContextSettingsSetWebsocketTimeoutWindow(contextHandle, desiredWebsocketTimeout));\n        VERIFY_SUCCEEDED(XblContextSettingsGetWebsocketTimeoutWindow(contextHandle, &actualWebsocketTimeout));\n        VERIFY_ARE_EQUAL_UINT(desiredWebsocketTimeout, actualWebsocketTimeout);\n\n        bool desiredUseXPlatQos{ true }, actualUserXPlatQos{};\n        VERIFY_SUCCEEDED(XblContextSettingsSetUseCrossPlatformQosServers(contextHandle, desiredUseXPlatQos));\n        VERIFY_SUCCEEDED(XblContextSettingsGetUseCrossPlatformQosServers(contextHandle, &actualUserXPlatQos));\n        VERIFY_ARE_EQUAL_INT(desiredUseXPlatQos, actualUserXPlatQos);\n    }\n\n    static size_t callRoutedCount;\n\n    static void ServiceCallRouted(\n        _In_ XblServiceCallRoutedArgs args,\n        _In_opt_ void* context\n    )\n    {\n        UNREFERENCED_PARAMETER(context);\n\n        LOGS_DEBUG << args.fullResponseFormatted;\n        callRoutedCount++;\n        LOGS_DEBUG << \"callRoutedCount: \" << callRoutedCount;\n    }\n\n    DEFINE_TEST_CASE(TestHttpTimeouts)\n    {\n        TEST_LOG(L\"Test starting: TestHttpTimeouts\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        callRoutedCount = 0;\n        VERIFY_SUCCEEDED(XblAddServiceCallRoutedHandler(ServiceCallRouted, nullptr));\n\n        uint32_t timeout{ 15 }, retryDelay{ 2 };\n        VERIFY_SUCCEEDED(XblContextSettingsSetHttpTimeoutWindow(xboxLiveContext.get(), timeout));\n        VERIFY_SUCCEEDED(XblContextSettingsSetHttpRetryDelay(xboxLiveContext.get(), retryDelay));\n\n        HttpMock mock(String{}, \"https://client-strings.xboxlive.com\", 503);\n\n        auto startTime{ std::chrono::high_resolution_clock::now() };\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblStringVerifyStringAsync(xboxLiveContext.get(), \"TestString\", &async));\n        VERIFY_FAILED(XAsyncGetStatus(&async, true));\n\n        auto endTime{ std::chrono::high_resolution_clock::now() };\n        auto callTime{ std::chrono::duration_cast<std::chrono::seconds>(endTime - startTime).count() };\n\n        // Make sure at least one retry is attempted and that we get a call routed callback for each\n        VERIFY_IS_TRUE(callRoutedCount > 1);\n        VERIFY_IS_TRUE(callTime <= timeout);\n    }\n\n    static void CALLBACK RTAStateChanged(\n        _In_opt_ void* context,\n        _In_ XblRealTimeActivityConnectionState connectionState\n    )\n    {\n        switch (connectionState)\n        {\n        case XblRealTimeActivityConnectionState::Connected:\n        {\n            assert(false);\n            break;\n        }\n        case XblRealTimeActivityConnectionState::Disconnected:\n        {\n            auto event = static_cast<Event*>(context);\n            event->Set();\n            break;\n        }\n        default:\n        {\n            break;\n        }\n        }\n    }\n};\n\nsize_t XboxLiveContextSettingsTests::callRoutedCount{ 0 };\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/HttpCallTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(HttpCallTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(HttpCallTests);\n\n    DEFINE_TEST_CASE(TestHttpCall)\n    {\n        TEST_LOG(L\"Test starting: TestHttpCall\");\n\n        TestEnvironment env{};\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n\n        uint32_t httpStatus{ 200 };\n        String url{ \"https://xboxlive.com\" };\n        HttpHeaders responseHeaders\n        {\n            { \"key1\", \"value1\" },\n            { \"key2\", \"value2\" }\n        };\n        String responseBody{ \"responseBody\" };\n\n        HttpMock mock{ \"\", url.data(), httpStatus };\n        mock.SetResponseBody(responseBody);\n        mock.SetResponseHeaders(responseHeaders);\n\n        XblHttpCallHandle callHandle{};\n        VERIFY_SUCCEEDED(XblHttpCallCreate(xboxLiveContext.get(), \"GET\", url.data(), &callHandle));\n\n        const char* actualRequestUrl{ nullptr };\n        VERIFY_SUCCEEDED(XblHttpCallGetRequestUrl(callHandle, &actualRequestUrl));\n        VERIFY_IS_TRUE(url == actualRequestUrl);\n\n        // Test request APIs\n        VERIFY_SUCCEEDED(XblHttpCallRequestSetRetryAllowed(callHandle, false));\n        VERIFY_SUCCEEDED(XblHttpCallRequestSetRequestBodyString(callHandle, \"requestBody\"));\n        VERIFY_SUCCEEDED(XblHttpCallRequestSetHeader(callHandle, \"header1\", \"value1\", false));\n\n        XAsyncBlock async{};\n        VERIFY_SUCCEEDED(XblHttpCallPerformAsync(callHandle, XblHttpCallResponseBodyType::String, &async));\n        VERIFY_SUCCEEDED(XAsyncGetStatus(&async, true));\n\n        uint32_t actualStatus{};\n        VERIFY_SUCCEEDED(XblHttpCallGetStatusCode(callHandle, &actualStatus));\n        VERIFY_ARE_EQUAL_INT(actualStatus, httpStatus);\n\n        uint32_t headerCount{};\n        VERIFY_SUCCEEDED(XblHttpCallGetNumHeaders(callHandle, &headerCount));\n        VERIFY_ARE_EQUAL_INT(headerCount, responseHeaders.size());\n\n        uint32_t index{ 0 };\n        for (auto& pair : responseHeaders)\n        {\n            const char* headerName{ nullptr };\n            const char* headerValue{ nullptr };\n            VERIFY_SUCCEEDED(XblHttpCallGetHeaderAtIndex(callHandle, index++, &headerName, &headerValue));\n\n            VERIFY_ARE_EQUAL_STR(headerName, pair.first);\n            VERIFY_ARE_EQUAL_STR(headerValue, pair.second);\n        }\n\n        const char* actualResponseBody{ nullptr };\n        VERIFY_SUCCEEDED(XblHttpCallGetResponseString(callHandle, &actualResponseBody));\n        VERIFY_IS_TRUE(actualResponseBody == responseBody);\n\n        size_t bufferSize{};\n        VERIFY_SUCCEEDED(XblHttpCallGetResponseBodyBytesSize(callHandle, &bufferSize));\n\n        // Verify exact buffer size\n        size_t bufferUsed{};\n        std::vector<uint8_t> buffer(bufferSize);\n        VERIFY_SUCCEEDED(XblHttpCallGetResponseBodyBytes(callHandle, bufferSize, buffer.data(), &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(bufferSize, bufferUsed);\n\n        // Verify larger buffer size\n        bufferUsed = 0;\n        buffer = std::vector<uint8_t>(bufferSize * 2);\n        VERIFY_SUCCEEDED(XblHttpCallGetResponseBodyBytes(callHandle, bufferSize * 2, buffer.data(), &bufferUsed));\n        VERIFY_ARE_EQUAL_UINT(bufferSize, bufferUsed);\n    }\n\n    DEFINE_TEST_CASE(CppTestHttpCall)\n    {\n        TEST_LOG(L\"Test starting: CppTestHttpCall\");\n\n        TestEnvironment env{};\n\n        uint32_t httpStatus{ 200 };\n        String url{ \"https://xboxlive.com\" };\n        HttpHeaders responseHeaders\n        {\n            { \"key1\", \"value1\" },\n            { \"key2\", \"value2\" }\n        };\n        String responseBody{ \"responseBody\" };\n\n        HttpMock mock{ \"GET\", url.data(), httpStatus };\n        mock.SetResponseBody(responseBody);\n        mock.SetResponseHeaders(responseHeaders);\n\n        auto xboxLiveContext = env.CreateLegacyMockXboxLiveContext();\n\n        auto httpCall = create_xbox_live_http_call(\n            xboxLiveContext->settings(),\n            _T(\"GET\"),\n            Utils::StringTFromUtf8(url.data()),\n            web::uri()\n        );\n\n        VERIFY_ARE_EQUAL_STR(Utils::StringTFromUtf8(url.data()), httpCall->server_name());\n\n        auto task = httpCall->get_response_with_auth(\n            xboxLiveContext->user(),\n            http_call_response_body_type::string_body,\n            false\n        );\n\n        auto result{ task.get() };\n\n        VERIFY_IS_TRUE(result->body_type() == http_call_response_body_type::string_body);\n        VERIFY_IS_TRUE(result->http_status() == httpStatus);\n\n        auto actualResponseHeaders{ result->response_headers() };\n        VERIFY_ARE_EQUAL_INT(actualResponseHeaders.size(), responseHeaders.size());\n\n        for (auto& pair : responseHeaders)\n        {\n            VERIFY_ARE_EQUAL_STR(actualResponseHeaders[Utils::StringTFromUtf8(pair.first.data())], Utils::StringTFromUtf8(pair.second.data()));\n        }\n\n        VERIFY_ARE_EQUAL_STR(result->response_body_string(), Utils::StringTFromUtf8(responseBody.data()));\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/LogTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n#include \"Logger/log.h\"\n#include \"Logger/log_hc_output.h\"\n\nusing namespace xbox::services::system;\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(LogTest)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(LogTest);\n\n    class TestLogOutput : public log_output\n    {\n    public:\n        TestLogOutput() = default;\n\n        void write(_In_ HCTraceLevel level, _In_ const xsapi_internal_string& msg) override\n        {\n            UNREFERENCED_PARAMETER(level);\n            m_logOutput.push_back(msg);\n        }\n\n        std::vector<xsapi_internal_string> m_logOutput;\n    };\n\n    DEFINE_TEST_CASE(WriteLog)\n    {\n        TEST_LOG(L\"Test starting: WriteLog\");\n\n        VERIFY_SUCCEEDED(HCSettingsSetTraceLevel(HCTraceLevel::Error));\n\n        auto testLogger = std::make_shared<logger>();\n        auto testOutput = std::make_shared<TestLogOutput>();\n        testLogger->add_log_output(testOutput);\n\n        const char* testLogText = \"testlog\";\n\n        testLogger->add_log(log_entry(HCTraceLevel::Error, \"test\", testLogText));\n        testLogger->add_log(log_entry(HCTraceLevel::Error, \"test\") << testLogText << 1);\n\n        char veryverylong[10240];\n        int i = 0;\n        for (; i < _countof(veryverylong) - 1; i++)\n        {\n            veryverylong[i] = 'a';\n        }\n        veryverylong[i] = 0;\n\n        testLogger->add_log(log_entry(HCTraceLevel::Error, \"test\") << testLogText << testLogText);\n        testLogger->add_log(log_entry(HCTraceLevel::Error, \"test\") << testLogText << veryverylong);\n\n        // This will not be added into logger as it's level is higher than we set.\n        testLogger->add_log(log_entry(HCTraceLevel::Verbose, \"test\", \"test\"));\n\n        VERIFY_ARE_EQUAL_INT(4, testOutput->m_logOutput.size());\n        VERIFY_ARE_EQUAL_STR(testLogText, testOutput->m_logOutput[0]);\n        VERIFY_ARE_EQUAL_STR(xsapi_internal_string{ testLogText } +\"1\", testOutput->m_logOutput[1]);\n        VERIFY_ARE_EQUAL_STR(xsapi_internal_string{ testLogText } +testLogText, testOutput->m_logOutput[2]);\n        VERIFY_ARE_EQUAL_STR(xsapi_internal_string{ testLogText } +veryverylong, testOutput->m_logOutput[3]);\n    }\n\n    DEFINE_TEST_CASE(WriteLogStream)\n    {\n        TEST_LOG(L\"Test starting: WriteLogStream\");\n\n        //TestEnvironment env{};\n        \n        auto testLogger = std::make_shared<logger>();\n        auto testOutput = std::make_shared<TestLogOutput>();\n        testLogger->add_log_output(testOutput);\n\n        const char* testLogText = \"testlog\";\n\n        *testLogger += log_entry(HCTraceLevel::Error, \"test\") << testLogText;\n        *testLogger += log_entry(HCTraceLevel::Error, \"test\") << testLogText << 1;\n\n        VERIFY_ARE_EQUAL_INT(2, testOutput->m_logOutput.size());\n        VERIFY_ARE_EQUAL_STR(testLogText, testOutput->m_logOutput[0]);\n        VERIFY_ARE_EQUAL_STR(xsapi_internal_string{ testLogText } +\"1\", testOutput->m_logOutput[1]);\n    }\n\n    DEFINE_TEST_CASE(WriteLogConcurrent)\n    {\n        TEST_LOG(L\"Test starting: WriteLogConcurrent\");\n\n        auto testLogger = std::make_shared<logger>();\n\n        // Start 20 threads writing 100 logs\n        auto testOutput = std::make_shared<TestLogOutput>();\n        testLogger->add_log_output(testOutput);\n\n        struct LogTask\n        {\n            LogTask(std::shared_ptr<logger> logger, xsapi_internal_string message, size_t loopCount) noexcept\n                : m_logger{ logger },\n                m_message{ std::move(message) },\n                m_loopCount{ loopCount }\n            {\n                XAsyncRun(&m_async, [](XAsyncBlock* async)\n                {\n                    auto pThis{ static_cast<LogTask*>(async->context) };\n                    for (size_t i = 0; i < pThis->m_loopCount; ++i)\n                    {\n                        pThis->m_logger->add_log(log_entry(HCTraceLevel::Error, \"test\", pThis->m_message) << i);\n                    }\n                    pThis->Completed.Set();\n                    return S_OK;\n                });\n            }\n\n            Event Completed;\n\n        private:\n            XAsyncBlock m_async{ nullptr, this };\n            std::shared_ptr<logger> m_logger;\n            xsapi_internal_string m_message;\n            size_t m_loopCount;\n        };\n\n        int loopCount = 20;\n        std::vector<std::shared_ptr<LogTask>> tasks;\n\n        for (int i = 0; i < loopCount; i++)\n        {\n            tasks.push_back(std::make_shared<LogTask>(testLogger, \"a\", loopCount));\n        }\n\n        for (auto task : tasks)\n        {\n            task->Completed.Wait();\n        }\n\n        VERIFY_ARE_EQUAL_INT(loopCount*loopCount, testOutput->m_logOutput.size());\n    }\n\n    DEFINE_TEST_CASE(HCLogging)\n    {\n        TEST_LOG(L\"Test starting: HCLogging\");\n\n        VERIFY_SUCCEEDED(HCInitialize(nullptr));\n        HCTraceSetTraceToDebugger(true);\n\n        auto testLogger = std::make_shared<logger>();\n        auto hcOutput = std::make_shared<log_hc_output>();\n        testLogger->add_log_output(hcOutput);\n\n        constexpr char formatString[]{ \"%s%g%s\" };\n        testLogger->add_log(log_entry{ HCTraceLevel::Important, \"\" } << formatString);\n\n        HCCleanup();\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/PlatformTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(PlatformTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(PlatformTests);\n\nprivate:\n    struct LocalStorageManager\n    {\n    public:\n        LocalStorageManager() noexcept\n        {\n            VERIFY_SUCCEEDED(XblLocalStorageSetHandlers(nullptr, WriteHandler, ReadHandler, ClearHandler, this));\n        }\n\n        ~LocalStorageManager() noexcept\n        {\n            VERIFY_SUCCEEDED(XblLocalStorageSetHandlers(nullptr, nullptr, nullptr, nullptr, nullptr));\n        }\n\n    private:\n        static void WriteHandler(\n            _In_opt_ void* context,\n            _In_ XblClientOperationHandle operation,\n            _In_ XblUserHandle user,\n            _In_ XblLocalStorageWriteMode mode,\n            _In_z_ char const* key,\n            _In_ size_t dataSize,\n            _In_reads_bytes_(dataSize) void const* data\n        )\n        {\n            UNREFERENCED_PARAMETER(user);\n            assert(context);\n\n            auto pThis{ static_cast<LocalStorageManager*>(context) };\n            std::unique_lock<std::mutex> lock(pThis->m_mutex, std::defer_lock);\n\n            Sleep(2000);\n\n            if (lock.try_lock())\n            {\n                auto& vec{ pThis->m_data[key] };\n                auto bytes{ static_cast<const uint8_t*>(data) };\n\n                switch (mode)\n                {\n                case XblLocalStorageWriteMode::Append:\n                {\n                    vec.insert(vec.end(), bytes, bytes + dataSize);\n                    break;\n                }\n                case XblLocalStorageWriteMode::Truncate:\n                {\n                    vec = std::vector<uint8_t>(bytes, bytes + dataSize);\n                    break;\n                }\n                }\n                lock.unlock();\n\n                XblLocalStorageWriteComplete(operation, XblClientOperationResult::Success, vec.size());\n            }\n            else\n            {\n                XblLocalStorageReadComplete(operation, XblClientOperationResult::Failure, 0, nullptr);\n            }\n        }\n\n        static void ReadHandler(\n            _In_opt_ void* context,\n            _In_ XblClientOperationHandle operation,\n            _In_ XblUserHandle user,\n            _In_z_ const char* key\n        )\n        {\n            UNREFERENCED_PARAMETER(user);\n            assert(context);\n\n            auto pThis{ static_cast<LocalStorageManager*>(context) };\n\n            std::unique_lock<std::mutex> lock(pThis->m_mutex, std::defer_lock);\n            if (lock.try_lock())\n            {\n                auto& vec{ pThis->m_data[key] };\n                XblLocalStorageReadComplete(operation, XblClientOperationResult::Success, vec.size(), vec.data());\n            }\n            else\n            {\n                XblLocalStorageReadComplete(operation, XblClientOperationResult::Failure, 0, nullptr);\n            }\n        }\n\n        static void ClearHandler(\n            _In_opt_ void* context,\n            _In_ XblClientOperationHandle operation,\n            _In_ XblUserHandle user,\n            _In_z_ const char* key\n        )\n        {\n            UNREFERENCED_PARAMETER(user);\n            assert(context);\n\n            auto pThis{ static_cast<LocalStorageManager*>(context) };\n\n            std::unique_lock<std::mutex> lock(pThis->m_mutex, std::defer_lock);\n            if (lock.try_lock())\n            {\n                pThis->m_data.erase(key);\n                XblLocalStorageClearComplete(operation, XblClientOperationResult::Success);\n            }\n            else\n            {\n                XblLocalStorageReadComplete(operation, XblClientOperationResult::Failure, 0, nullptr);\n            }\n        }\n\n        std::unordered_map<std::string, std::vector<uint8_t>> m_data;\n        std::mutex m_mutex;\n    };\n\npublic:\n    DEFINE_TEST_CASE(TestCustomLocalStorageHandlers)\n    {\n        TEST_LOG(L\"Test starting: TestCustomLocalStorageHandlers\");\n        LocalStorageManager storageManager{};\n        TestEnvironment env{};\n\n        auto xboxLiveContext = env.CreateMockXboxLiveContext();\n        auto localStorage{ GlobalState::Get()->LocalStorage() };\n        VERIFY_IS_NOT_NULL(localStorage.get());\n\n        std::string dataKey{ \"key\" };\n        std::string writeData{ \"Hello, world!\" };\n\n        localStorage->WriteAsync(\n            xboxLiveContext->User(),\n            XblLocalStorageWriteMode::Truncate,\n            dataKey.data(),\n            Vector<uint8_t>(writeData.data(), writeData.data() + (writeData.size() + 1)),\n            nullptr\n        );\n\n        Event readComplete;\n        std::string readData;\n\n        localStorage->ReadAsync(\n            xboxLiveContext->User(),\n            dataKey.data(),\n            [&](Result<Vector<uint8_t>> result)\n            {\n                if (Succeeded(result) && result.Payload().size())\n                {\n                    auto data{ reinterpret_cast<char*>(result.Payload().data()) };\n                    readData = data;\n                }\n                readComplete.Set();\n            }\n        );\n\n        readComplete.Wait();\n        VERIFY_IS_TRUE(writeData == readData);\n    }\n\n    enum TestEnum : uint32_t\n    {\n        ValueDefault = 0,\n        Value1 = 1,\n        Value3 = 3,\n        ValueOutOfRange = DEFAULT_ENUM_MAX + 1,\n    };\n\n    enum class TestEnumClass : uint32_t\n    {\n        ValueDefault = 1,\n        ValueMin = 1000,\n        ValueMax = 1100\n    };\n\n    DEFINE_TEST_CASE(TestEnumTraits)\n    {\n        TEST_LOG(L\"Test starting: TestEnumTraits\");\n\n        auto s = EnumName(Value1);\n        VERIFY_ARE_EQUAL_STR(\"Value1\", s);\n\n        s = EnumName(ValueOutOfRange);\n        VERIFY_ARE_EQUAL(0u, s.size());\n\n        constexpr auto TestEnumName = EnumName<TestEnum, ValueDefault, ValueOutOfRange>;\n        s = TestEnumName(ValueOutOfRange);\n        VERIFY_ARE_EQUAL_STR(\"ValueOutOfRange\", s);\n\n        auto e = EnumValue<TestEnum>(\"vAlUe1\");\n        VERIFY_IS_TRUE(e == TestEnum::Value1);\n\n        e = EnumValue<TestEnum>(\"value1error\");\n        VERIFY_IS_TRUE(e == TestEnum::ValueDefault);\n\n        constexpr auto TestEnumClassName = EnumName<TestEnumClass, 1000, 1100>;\n        constexpr auto TestEnumClassValue = EnumValue<TestEnumClass, 1000, 1100>;\n\n        s = TestEnumClassName(TestEnumClass::ValueMin);\n        VERIFY_ARE_EQUAL_STR(s, \"ValueMin\");\n\n        auto ec = TestEnumClassValue(\"ValueMax\");\n        VERIFY_IS_TRUE(ec == TestEnumClass::ValueMax);\n\n        ec = TestEnumClassValue(\"InvalidName\");\n        VERIFY_IS_TRUE(ec == TestEnumClass{});\n\n        XblMultiplayerActivityPlatform platform = XblMultiplayerActivityPlatform::PlayStation;\n        auto platformString = EnumName<XblMultiplayerActivityPlatform, 0, static_cast<uint32_t>(XblMultiplayerActivityPlatform::All)>(platform);\n        VERIFY_ARE_EQUAL_STR(\"PlayStation\", platformString);\n    }\n\n    DEFINE_TEST_CASE(TestPeriodicTask)\n    {\n        TEST_LOG(L\"Test starting: TestPeriodicTask\");\n\n        TestEnvironment env{};\n\n        XTaskQueueHandle queueHandle{ nullptr };\n        VERIFY_SUCCEEDED(XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::ThreadPool, &queueHandle));\n        TaskQueue queue{ queueHandle };\n        XTaskQueueCloseHandle(queueHandle);\n\n        Event e;\n        size_t callCount{ 0 };\n        using Clock = std::chrono::high_resolution_clock;\n        auto startTime{ Clock::now() };\n\n        // Create task. Should immediately run at t~0\n        auto task = PeriodicTask::MakeAndRun(queue, 2000, [&]\n        {\n            std::wstringstream ss;\n            ss << L\"Task executing at t=\" << std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - startTime).count();\n            LOGS_DEBUG << ss.str().data();\n            if (++callCount == 5)\n            {\n                e.Set();\n            }\n        });\n\n        // manually invoke task at time t~1000 & 4000\n        queue.RunWork([&]\n        {\n            VERIFY_ARE_EQUAL_UINT(1, callCount);\n            task->ScheduleImmediately();\n            Sleep(3000);\n            task->ScheduleImmediately();\n        }, 1000);\n\n        // task should run at t~0,1000,3000,4000,6000\n        e.Wait();\n        auto totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - startTime).count();\n        VERIFY_IS_TRUE(totalTime < 7000);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/XboxLiveCallbackTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN\n\nDEFINE_TEST_CLASS(XboxLiveCallbackTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(XboxLiveCallbackTests)\n\n    static void invoke_callback(int value, xbox_live_callback<int> callback)\n    {\n        callback(value);\n    }\n\n    DEFINE_TEST_CASE(BasicCallback)\n    {\n        TEST_LOG(L\"Test starting: BasicCallback\");\n\n        int value = 1;\n        xbox_live_callback<int> lambda = [value](int _value)\n        {\n            VERIFY_ARE_EQUAL_INT(value, _value);\n        };\n\n        invoke_callback(value, lambda);\n    }\n\n    DEFINE_TEST_CASE(NestedCallbacks)\n    {\n        TEST_LOG(L\"Test starting: NestedCallbacks\");\n\n        int firstValue = 1;\n        int secondValue = 2;\n\n        xbox_live_callback<int> lambda = [firstValue](int _value)\n        {\n            VERIFY_ARE_EQUAL_INT(firstValue, _value);\n        };\n\n        xbox_live_callback<int> enclosingLambda = [firstValue, secondValue, lambda](int _value)\n        {\n            VERIFY_ARE_EQUAL_INT(secondValue, _value);\n            invoke_callback(firstValue, lambda);\n        };\n\n        invoke_callback(secondValue, enclosingLambda);\n    }\n\n    DEFINE_TEST_CASE(TestXAsyncProviderException)\n    {\n        TEST_LOG(L\"Test starting: TestXAsyncProviderException\");\n\n        TestEnvironment testEnv{};\n        Event callbackInvoked;\n\n        XAsyncBlock async{};\n        async.context = &callbackInvoked;\n        async.callback = [](XAsyncBlock* async)\n        {\n            auto pEvent{ static_cast<Event*>(async->context) };\n            pEvent->Set();\n        };\n\n        VERIFY_SUCCEEDED(RunAsync(&async, __FUNCTION__, [](XAsyncOp op, const XAsyncProviderData* data)\n            {\n                UNREFERENCED_PARAMETER(data);\n                switch (op)\n                {\n                case XAsyncOp::DoWork:\n                {\n                    throw std::exception();\n                }\n                default:\n                {\n                    return S_OK;\n                }\n                }\n            }));\n\n        callbackInvoked.Wait();\n        VERIFY_ARE_EQUAL(E_FAIL, XAsyncGetStatus(&async, false));\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END"
  },
  {
    "path": "Tests/UnitTests/Tests/Shared/XboxLiveContextTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n#include \"pch.h\"\n#include \"UnitTestIncludes.h\"\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_BEGIN\n\nDEFINE_TEST_CLASS(XboxLiveContextTests)\n{\npublic:\n    DEFINE_TEST_CLASS_PROPS(XboxLiveContextTests);\n\n    DEFINE_TEST_CASE(TestXboxLiveContext)\n    {\n        TEST_LOG(L\"Test starting: TestXboxLiveContext\");\n\n        TestEnvironment env{};\n\n        uint64_t mockXuid{ 1 };\n        std::string mockGamertag = \"MockGamertag\";\n        User mockUser = CreateMockUser(mockXuid, mockGamertag);\n\n        struct State\n        {\n            XblContextHandle xboxLiveContext{ nullptr };\n            XalUserHandle userFromContext{ nullptr };\n\n            ~State()\n            {\n                XblContextCloseHandle(xboxLiveContext);\n                XalUserCloseHandle(userFromContext);\n            }\n        } state;\n\n        VERIFY_SUCCEEDED(XblContextCreateHandle(mockUser.Handle(), &state.xboxLiveContext));\n        VERIFY_SUCCEEDED(XblContextGetUser(state.xboxLiveContext, &state.userFromContext));\n\n        // Validate the attributes of the returned handle\n        uint64_t xuid{ 0 };\n        VERIFY_SUCCEEDED(XalUserGetId(state.userFromContext, &xuid));\n        VERIFY_IS_TRUE(xuid == mockXuid);\n\n        auto requiredSize = XalUserGetGamertagSize(state.userFromContext, XalGamertagComponent_Classic);\n        VERIFY_IS_TRUE(mockGamertag.size() + 1 == requiredSize);\n\n        std::vector<char> gamertag(requiredSize, char{});\n        VERIFY_SUCCEEDED(XalUserGetGamertag(state.userFromContext, XalGamertagComponent_Classic, requiredSize, &gamertag[0], nullptr));\n        VERIFY_IS_TRUE(mockGamertag == gamertag.data());\n\n        VERIFY_SUCCEEDED(XblContextGetXboxUserId(state.xboxLiveContext, &xuid));\n        VERIFY_IS_TRUE(xuid == mockXuid);\n    }\n};\n\nNAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END\n\n"
  },
  {
    "path": "ThirdPartyNotices.txt",
    "content": "\nTHIRD-PARTY SOFTWARE NOTICES AND INFORMATION\nDo Not Translate or Localize\n\nXbox Live SDK incorporates third party material from the projects listed below. The original copyright notice and the license under which Microsoft received such third party material are set forth below. Microsoft reserves all other rights not expressly granted, whether by implication, estoppel or otherwise.  \n\n1. Standalone Asio (http://think-async.com/Asio/AsioStandalone)\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n2.\tWebsocket++ (http://www.zaphoyd.com/websocketpp/)\n\n%% Websocket++ NOTICES, INFORMATION, AND LICENSE BEGIN HERE\n=========================================\nMain Library:\n\nCopyright (c) 2014, Peter Thorson. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the WebSocket++ Project nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nBundled Libraries:\n\n****** Base 64 Library (base64/base64.hpp) ******\nbase64.hpp is a repackaging of the base64.cpp and base64.h files into a\nsingle header suitable for use as a header only library. This conversion was\ndone by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to\nthe code are redistributed under the same license as the original, which is\nlisted below.\n\nbase64.cpp and base64.h\n\nCopyright (C) 2004-2008 Ren Nyffenegger\n\nThis source code is provided 'as-is', without any express or implied\nwarranty. In no event will the author be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this source code must not be misrepresented; you must not\n  claim that you wrote the original source code. If you use this source code\n  in a product, an acknowledgment in the product documentation would be\n  appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and must not be\n  misrepresented as being the original source code.\n\n3. This notice may not be removed or altered from any source distribution.\n\nRen Nyffenegger rene.nyffenegger@adp-gmbh.ch\n\n****** SHA1 Library (sha1/sha1.hpp) ******\nsha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1\nlibrary (http://code.google.com/p/smallsha1/) into a single header suitable for\nuse as a header only library. This conversion was done by Peter Thorson\n(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed\nunder the same license as the original, which is listed below.\n\n Copyright (c) 2011, Micael Hildenborg\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\n EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n****** MD5 Library (common/md5.hpp) ******\nmd5.hpp is a reformulation of the md5.h and md5.c code from\nhttp://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to\nfunction as a component of a header only library. This conversion was done by\nPeter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The\nchanges are released under the same license as the original (listed below)\n\nCopyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.\n\nThis software is provided 'as-is', without any express or implied\nwarranty.  In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nL. Peter Deutsch\nghost@aladdin.com\n\n****** UTF8 Validation logic (utf8_validation.hpp) ******\nutf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann\n<bjoern@hoehrmann.de>. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for\ndetails.\n\nThe original license:\n\nCopyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n=========================================\nEND OF Websocket++ NOTICES, INFORMATION, AND LICENSE\n\n3. Alamofire (https://github.com/Alamofire/Alamofire)\n\nCopyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n4. SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON)\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 Ruoyu Fu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n5. OpenSSL (https://github.com/openssl/openssl/)\n\n  LICENSE ISSUES\n  ==============\n\n  The OpenSSL toolkit stays under a double license, i.e. both the conditions of\n  the OpenSSL License and the original SSLeay license apply to the toolkit.\n  See below for the actual license texts.\n\n  OpenSSL License\n  ---------------\n\n/* ====================================================================\n * Copyright (c) 1998-2017 The OpenSSL Project.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer. \n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. All advertising materials mentioning features or use of this\n *    software must display the following acknowledgment:\n *    \"This product includes software developed by the OpenSSL Project\n *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)\"\n *\n * 4. The names \"OpenSSL Toolkit\" and \"OpenSSL Project\" must not be used to\n *    endorse or promote products derived from this software without\n *    prior written permission. For written permission, please contact\n *    openssl-core@openssl.org.\n *\n * 5. Products derived from this software may not be called \"OpenSSL\"\n *    nor may \"OpenSSL\" appear in their names without prior written\n *    permission of the OpenSSL Project.\n *\n * 6. Redistributions of any form whatsoever must retain the following\n *    acknowledgment:\n *    \"This product includes software developed by the OpenSSL Project\n *    for use in the OpenSSL Toolkit (http://www.openssl.org/)\"\n *\n * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY\n * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * ====================================================================\n *\n * This product includes cryptographic software written by Eric Young\n * (eay@cryptsoft.com).  This product includes software written by Tim\n * Hudson (tjh@cryptsoft.com).\n *\n */\n\n Original SSLeay License\n -----------------------\n\n/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)\n * All rights reserved.\n *\n * This package is an SSL implementation written\n * by Eric Young (eay@cryptsoft.com).\n * The implementation was written so as to conform with Netscapes SSL.\n * \n * This library is free for commercial and non-commercial use as long as\n * the following conditions are aheared to.  The following conditions\n * apply to all code found in this distribution, be it the RC4, RSA,\n * lhash, DES, etc., code; not just the SSL code.  The SSL documentation\n * included with this distribution is covered by the same copyright terms\n * except that the holder is Tim Hudson (tjh@cryptsoft.com).\n * \n * Copyright remains Eric Young's, and as such any Copyright notices in\n * the code are not to be removed.\n * If this package is used in a product, Eric Young should be given attribution\n * as the author of the parts of the library used.\n * This can be in the form of a textual message at program startup or\n * in documentation (online or textual) provided with the package.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *    \"This product includes cryptographic software written by\n *     Eric Young (eay@cryptsoft.com)\"\n *    The word 'cryptographic' can be left out if the rouines from the library\n *    being used are not cryptographic related :-).\n * 4. If you include any Windows specific code (or a derivative thereof) from \n *    the apps directory (application code) you must include an acknowledgement:\n *    \"This product includes software written by Tim Hudson (tjh@cryptsoft.com)\"\n * \n * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * \n * The licence and distribution terms for any publically available version or\n * derivative of this code cannot be changed.  i.e. this code cannot simply be\n * copied and put under another distribution licence\n * [including the GNU Public Licence.]\n */\n =========================================\nEND OF OpenSSL NOTICES, INFORMATION, AND LICENSE\n\n6. zLib (https://github.com/madler/zlib)\n\nCopyright notice:\n\n (C) 1995-2017 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\nIf you use the zlib library in a product, we would appreciate *not* receiving\nlengthy legal documents to sign.  The sources are provided for free but without\nwarranty of any kind.  The library has been entirely written by Jean-loup\nGailly and Mark Adler; it does not include third-party code.\n\nIf you redistribute modified sources, we would appreciate that you include in\nthe file ChangeLog history information documenting your changes.  Please read\nthe FAQ for more information on the distribution of modified source versions.\n\n7. Boost (https://www.boost.org/)\n\nBoost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n8. doctest (https://github.com/onqtam/doctest)\n\nThe MIT License (MIT)\n\nCopyright (c) 2016-2018 Viktor Kirilov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n9. lua.org (https://www.lua.org/manual/5.3/readme.html#license)\n\nCopyright  19942018 Lua.org, PUC-Rio.\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n10. u-test (https://github.com/IUdalov/u-test/blob/master/LICENSE)\n\nMIT License\n\nCopyright (c) 2017-2018 Ilia Udalov <UdalovIlia@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n11. rapidJson (https://github.com/Tencent/rapidjson)\n\nTencent is pleased to support the open source community by making RapidJSON available. \n \nCopyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.  All rights reserved.\n\nIf you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.\nIf you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms.  Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.\nA copy of the MIT License is included in this file.\n\nOther dependencies and licenses:\n\nOpen Source Software Licensed Under the BSD License:\n--------------------------------------------------------------------\n\nThe msinttypes r29 \nCopyright (c) 2006-2013 Alexander Chemeris \nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n* Neither the name of  copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nOpen Source Software Licensed Under the JSON License:\n--------------------------------------------------------------------\n\njson.org \nCopyright (c) 2002 JSON.org\nAll Rights Reserved.\n\nJSON_checker\nCopyright (c) 2002 JSON.org\nAll Rights Reserved.\n\n\t\nTerms of the JSON License:\n---------------------------------------------------\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nThe Software shall be used for Good, not Evil.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\nTerms of the MIT License:\n--------------------------------------------------------------------\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "hc_settings.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n      <PackagesRoot Condition=\"'$(PackagesRoot)'==''\">$(MSBuildThisFileDirectory)External\\Packages\\</PackagesRoot>    \n      <libHttpClientOutDir>$(MSBuildThisFileDirectory)Bins\\</libHttpClientOutDir>\n  </PropertyGroup>\n  <PropertyGroup>\n      <SettingsFile>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\\, hc_settings.props))\\hc_settings.props</SettingsFile>\n  </PropertyGroup>\n  <Import Project=\"$(SettingsFile)\" Condition=\"Exists($(SettingsFile))\" />\n</Project>\n"
  },
  {
    "path": "xsapi.paths.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <XsapiSourceRoot>$(MSBuildThisFileDirectory)</XsapiSourceRoot>\n    <PackagesRoot Condition=\"'$(PackagesRoot)'==''\">$(XsapiSourceRoot)External\\Packages\\</PackagesRoot>\n    <XsapiOutDir>$(XsapiSourceRoot)Bins\\Binaries\\$(Configuration)\\$(Platform)\\$(MSBuildProjectName)\\</XsapiOutDir>\n    <XsapiIntDir>$(XsapiSourceRoot)Bins\\Obj\\$(Configuration)\\$(Platform)\\$(MSBuildProjectName)\\</XsapiIntDir>\n    <!--Used by CSharp projects-->\n    <OutputPath>$(XsapiOutDir)</OutputPath>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "xsapi.staticlib.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <XsapiRoot>$(MSBuildThisFileDirectory)</XsapiRoot>\n    <XsapiInclude>$(XsapiRoot)include\\</XsapiInclude>\n  </PropertyGroup>\n\n  <!--Reuse libHttpClient platform detection logic-->  \n  <Import Condition=\"'$(HCPlatform)' == ''\" Project=\"$(XsapiRoot)External\\xal\\External\\libHttpClient\\platform_select.props\" />\n  <PropertyGroup>\n    <XsapiPlatform>$(HCPlatform)</XsapiPlatform>\n  </PropertyGroup>\n\n  <!--If the platform wasn't manually set and libHttpClient logic did not infer it, set here-->\n  <PropertyGroup Condition=\"'$(XsapiPlatform)' == ''\">\n    <XsapiPlatform Condition=\"'$(ApplicationType)'=='Windows Store'\">UWP</XsapiPlatform>\n    <XsapiPlatform Condition=\"'$(ApplicationType)'=='' AND '$(Platform)'!='Durango'\">Win32</XsapiPlatform>\n    <XsapiPlatform Condition=\"'$(ApplicationType)'=='' AND '$(Platform)'=='Durango'\">XDK</XsapiPlatform>\n  </PropertyGroup>\n\n  <!--Set toolset and project name-->\n  <PropertyGroup>\n    <XsapiProjectName Condition=\"'$(XsapiProjectName)'=='GSDK' OR '$(XsapiProjectName)'=='GXDK'\">GDK</XsapiProjectName> <!-- Back compat reasons -->\n    <XsapiToolset Condition=\"'$(PlatformToolset)'=='v140'\">140</XsapiToolset>\n    <XsapiToolset Condition=\"'$(PlatformToolset)'=='v141'\">141</XsapiToolset>\n    <XsapiToolset Condition=\"'$(PlatformToolset)'=='v142'\">142</XsapiToolset>\n    <XsapiToolset Condition=\"'$(PlatformToolset)'=='v143'\">142</XsapiToolset>\n    <XsapiToolset Condition=\"'$(XsapiToolset)'==''\">141</XsapiToolset>\n    <XsapiProjectName Condition=\"'$(XsapiPlatform)' != 'Android'\">Microsoft.Xbox.Services.$(XsapiToolset).$(XsapiPlatform).Cpp</XsapiProjectName>\n    <XsapiProjectName Condition=\"'$(XsapiPlatform)' == 'GDK'\">Microsoft.Xbox.Services.$(XsapiToolset).GDK.C</XsapiProjectName>\n  </PropertyGroup>\n\n  <!--Support for older XsapiBuildFromSource prop name that controlled both XSAPI & libHttpClient -->\n  <PropertyGroup Condition=\"'$(XsapiBuildFromSource)' != ''\">\n    <XsapiLibBuildFromSource>$(XsapiBuildFromSource)</XsapiLibBuildFromSource>\n    <LibHttpClientBuildFromSource>$(XsapiBuildFromSource)</LibHttpClientBuildFromSource>\n  </PropertyGroup>\n\n  <!--Turn build from source on when including this file -->\n  <PropertyGroup Condition=\"'$(XsapiLibBuildFromSource)' == ''\">\n    <XsapiLibBuildFromSource>true</XsapiLibBuildFromSource>\n    <XsapiBuildFromSource>true</XsapiBuildFromSource> <!--Support for older GDKs which still use the XsapiBuildFromSource prop -->\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(LibHttpClientBuildFromSource)' == ''\">\n    <LibHttpClientBuildFromSource>true</LibHttpClientBuildFromSource>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(XsapiAddProjectReference)' == ''\">\n    <XsapiAddProjectReference>true</XsapiAddProjectReference>\n  </PropertyGroup>\n  \n  <PropertyGroup Condition=\"'$(XsapiPlatform)' == 'Win32'\">\n    <XsapiXalRefs>true</XsapiXalRefs>\n    <XsapiXalHeaders>true</XsapiXalHeaders>\n    <UseCasablanaLite>true</UseCasablanaLite>\n  </PropertyGroup>\n  \n  <PropertyGroup Condition=\"'$(XsapiPlatform)' == 'Win32' AND '$(XsapiUnitTests)'!='true'\">\n    <XsapiCllRefs>true</XsapiCllRefs>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(XsapiPlatform)' == 'UWP'\">\n    <XsapiXalRefs>true</XsapiXalRefs>\n    <XsapiXalHeaders>true</XsapiXalHeaders>\n    <XsapiTCUIHeaders>true</XsapiTCUIHeaders>\n    <UseCasablanaLite>true</UseCasablanaLite>\n  </PropertyGroup>\n  \n  <PropertyGroup Condition=\"'$(XsapiPlatform)' == 'XDK'\">\n    <XsapiXalRefs>true</XsapiXalRefs>\n    <XsapiXalHeaders>true</XsapiXalHeaders>\n    <UseCasablanaLite>true</UseCasablanaLite>\n  </PropertyGroup>\n  \n  <PropertyGroup Condition=\"'$(XsapiPlatform)' == 'GDK'\">\n    <XsapiXalHeaders>true</XsapiXalHeaders>\n    <UseCasablanaLite>true</UseCasablanaLite>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <!-- If you're updating here, check to see if you also need to update Utilities/GDK/Xbox.Services.API.C.props -->\n    <ClCompile>\n      <PreprocessorDefinitions>_NO_ASYNCRTIMP;_NO_PPLXIMP;_NO_XSAPIIMP;XBL_API_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(XsapiPlatform)' == 'GDK'\">HC_WINHTTP_WEBSOCKETS;HC_PLATFORM_IS_MICROSOFT=1;HC_PLATFORM_GDK=4;HC_PLATFORM=HC_PLATFORM_GDK;HC_DATAMODEL=HC_DATAMODEL_LLP64;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions Condition=\"'$(XsapiLibBuildFromSource)' != ''\">XSAPI_BUILT_FROM_SOURCE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>;$(XsapiInclude);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies Condition=\"'$(XsapiPlatform)'!='XDK' AND '$(XsapiPlatform)'!='Android'\">Appnotify.lib;crypt32.lib;Winhttp.lib;Bcrypt.lib;pathcch.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n\n  <ItemGroup Condition=\"'$(XsapiAddProjectReference)' == 'true' AND '$(XsapiImpl)' != 'true' AND '$(ConfigurationType)'!='StaticLibrary'\">\n    <ProjectReference Include=\"$(XsapiRoot)Build\\$(XsapiProjectName)\\$(XsapiProjectName).vcxproj\">\n      <Project Condition=\"'$(XsapiPlatform)' == 'UWP'\">{8F96710E-5169-4917-8874-7DE248F4D243}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'Win32' AND '$(XsapiToolset)' == '142'\">{4F107DE4-98B1-42B7-8767-0B5102C88E4F}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'Win32' AND '$(XsapiToolset)' == '141'\">{4F107DE4-98B1-42B7-8767-0B5102C88E4F}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'Win32' AND '$(XsapiToolset)' == '140'\">{AB77D282-496D-413F-9A51-F78DF740A82A}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'XDK'\">{8A112040-CDA1-4490-B518-62DFCC451FA7}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'GDK'\">{60139f62-bf37-4f11-bd93-5fbf4e92100c}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'DesktopBridge' AND '$(XsapiToolset)' == '141'\">{B0D02E4C-DB36-416C-8F1E-8666B3FAF876}</Project>\n    </ProjectReference>\n  </ItemGroup>\n\n  <!--Casablanca dependency-->\n  <PropertyGroup Condition=\"'$(UseCasablanaLite)' == 'true'\">\n    <CppRestSdkInclude>$(XsapiRoot)Include\\cpprestinclude\\</CppRestSdkInclude>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(UseCasablanaLite)' != 'true'\">\n    <CppRestSdkRoot>$(XsapiRoot)External\\cpprestsdk\\</CppRestSdkRoot>\n    <CppRestSdkInclude>$(CppRestSdkRoot)release\\include\\</CppRestSdkInclude>\n    <VisualStudioMajorVersion Condition=\"'$(VisualStudioVersion)' == '14.0'\">14</VisualStudioMajorVersion>\n    <VisualStudioMajorVersion Condition=\"'$(VisualStudioVersion)' == '15.0'\">15</VisualStudioMajorVersion>\n    <VisualStudioMajorVersion Condition=\"'$(VisualStudioVersion)' == '16.0'\">15</VisualStudioMajorVersion>\n    <VisualStudioMajorVersion Condition=\"'$(VisualStudioVersion)' == '17.0'\">15</VisualStudioMajorVersion>\n  </PropertyGroup>\n\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(CppRestSdkInclude)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <ItemGroup Condition=\"'$(XsapiAddProjectReference)' == 'true' AND '$(UseCasablanaLite)' != 'true' AND '$(ConfigurationType)'!='StaticLibrary'\">\n    <ProjectReference Condition=\"'$(XsapiPlatform)' == 'UWP' OR '$(XsapiPlatform)' == 'DesktopBridge'\" Include=\"$(CppRestSdkRoot)release\\src\\build\\vs$(VisualStudioMajorVersion).uwp\\cpprestsdk$(XsapiToolset).uwp.static.vcxproj\">\n      <Project>{9AD285A2-301E-47A0-A299-14AD5D4F2758}</Project>\n    </ProjectReference>\n    <ProjectReference Condition=\"'$(XsapiPlatform)' == 'XDK'\" Include=\"$(CppRestSdkRoot)release\\src\\build\\vs$(VisualStudioMajorVersion).xbox\\casablanca$(XsapiToolset).xbox.vcxproj\">\n      <Project>{e621c269-d177-4c1b-80ea-c0a274b7a151}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  \n  <!--RapidJSON dependency-->\n  \n  <PropertyGroup>\n    <RapidJSONSdkRoot>$(XsapiRoot)External\\rapidjson\\</RapidJSONSdkRoot>\n    <RapidJSONSdkInclude>$(RapidJSONSdkRoot)include\\</RapidJSONSdkInclude>\n  </PropertyGroup>\n  \n  <ItemDefinitionGroup>\n    <ClCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(RapidJSONSdkInclude)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>RAPIDJSON_NO_INT64DEFINE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!--LibHttpClient dependency-->\n  <PropertyGroup>\n    <HCPlatform Condition=\"'$(XsapiPlatform)' == 'DesktopBridge'\">HC_PLATFORM_WIN32</HCPlatform>\n  </PropertyGroup>\n  <Import Project=\"$(XsapiRoot)External\\xal\\External\\libHttpClient\\Build\\libHttpClient.import.props\" />\n\n  <!-- Ensure libHttpClient headers are on the include path for GDK builds -->\n  <ItemDefinitionGroup Condition=\"'$(HCPlatform)' == 'GDK'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(HCIncludeDir)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <!--CompactCoreCLL dependency-->\n  <PropertyGroup Condition=\"'$(XsapiCllRefs)' == 'true'\">\n    <XalRoot>$(XsapiRoot)External\\xal\\</XalRoot>\n    <CoreCLLInclude>$(XsapiRoot)External\\CompactCoreCLL\\</CoreCLLInclude>\n  </PropertyGroup>\n\n  <ItemDefinitionGroup Condition=\"'$(XsapiCllRefs)' == 'true'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(CoreCLLInclude)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <ItemGroup Condition=\"'$(XsapiAddProjectReference)' == 'true' AND '$(ConfigurationType)'!='StaticLibrary' AND '$(XsapiCllRefs)' == 'true'\">\n    <ProjectReference Include=\"$(XsapiRoot)External\\CompactCoreCLL\\CompactCoreCLL.$(XsapiPlatform).vcxproj\">\n      <Project Condition=\"'$(XsapiPlatform)' == 'Win32'\">{54ebecdc-a7fd-4e3f-bb1a-40d15f0b6792}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'XDK'\">{0B3ED0FC-2866-4D05-A92E-411031596103}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'Android'\">{2f1f7c6a-1fda-4cce-935d-0e9324d5db92}</Project>\n    </ProjectReference>\n  </ItemGroup>\n\n  <!--Xal dependency-->\n  <PropertyGroup Condition=\"'$(XsapiXalHeaders)' == 'true'\">\n    <XalRoot>$(XsapiRoot)External\\xal\\</XalRoot>\n    <XalPlatform>$(HCPlatform)</XalPlatform>\n    <XalInclude>$(XalRoot)source\\Xal\\include\\</XalInclude>\n    <XalExtraInclude>$(XalRoot)source\\XalExtra\\include\\</XalExtraInclude>\n  </PropertyGroup>\n\n  <ItemDefinitionGroup Condition=\"'$(XsapiXalHeaders)' == 'true'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(XalInclude);$(XalExtraInclude)</AdditionalIncludeDirectories>\n    </ClCompile>\n  </ItemDefinitionGroup>\n\n  <ItemGroup Condition=\"'$(XsapiAddProjectReference)' == 'true' AND '$(XsapiXalRefs)' == 'true' AND '$(ConfigurationType)'!='StaticLibrary' AND '$(XsapiUnitTests)'!='true'\">\n    <ProjectReference Include=\"$(XalRoot)Source\\Xal\\Xal.$(XalPlatform).vcxproj\">\n      <Project Condition=\"'$(XalPlatform)' == 'Win32'\">{7333335C-CD75-4802-8F56-702C0BE2563F}</Project>\n      <Project Condition=\"'$(XalPlatform)' == 'UWP'\">{7326b85d-b8df-4a59-a2c7-c721a7a1b8cb}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"$(XsapiRoot)External\\CompactCoreCLL\\CompactCoreCLL.$(XsapiPlatform).vcxproj\">\n      <Project Condition=\"'$(XsapiPlatform)' == 'Win32'\">{54ebecdc-a7fd-4e3f-bb1a-40d15f0b6792}</Project>\n      <Project Condition=\"'$(XsapiPlatform)' == 'UWP'\">{82cfe4ee-7a03-4bc4-810d-293806b4dab1}</Project>\n    </ProjectReference>\n    <ProjectReference Condition=\"'$(XsapiPlatform)' != 'XDK'\" Include=\"$(XalRoot)External\\OneDSBuildFiles\\Telemetry.$(XalPlatform).vcxproj\">\n      <Project Condition=\"'$(XalPlatform)' == 'Win32'\">{0656b0fd-2f77-4840-aa4f-b9622bb9d39f}</Project>\n      <Project Condition=\"'$(XalPlatform)' == 'UWP'\">{B4EB5355-7230-456D-97F8-624AA9F78606}</Project>\n    </ProjectReference>\n    <ProjectReference Condition=\"'$(XsapiPlatform)' != 'XDK'\" Include=\"$(XalRoot)External\\OneDSBuildFiles\\Telemetry.Zlib.$(XalPlatform).vcxproj\">\n      <Project Condition=\"'$(XalPlatform)' == 'Win32'\">{517489c9-dd6f-4a0f-893c-a55bbd7dfbe6}</Project>\n      <Project Condition=\"'$(XalPlatform)' == 'UWP'\">{4B32FD42-904F-4E50-B244-869D8C6D6F56}</Project>\n    </ProjectReference>\n  </ItemGroup>\n\n  <!--TCUI dependency-->\n  <!--<PropertyGroup Condition=\"'$(XsapiTCUIHeaders)' == 'true'\">\n    <TCUIRoot>$(XsapiRoot)External\\tcui\\</TCUIRoot>\n    <TCUIPlatform>$(HCLibPlatformType)</TCUIPlatform>\n    <TCUIInclude>$(TCUIRoot)Include\\</TCUIInclude>\n  </PropertyGroup>-->\n\n  <Target Name=\"XblBuildDebug\" BeforeTargets=\"InitializeBuildStatus\" Condition=\"'$(XblTraceBuildInfo)' == 'true'\">\n    <Message Importance=\"High\" Text=\"XblBuildDebug\" />\n    <Message Importance=\"High\" Text=\"    ProjectName                  = '$(ProjectName)'\" />\n    <Message Importance=\"High\" Text=\"    Configuration                = '$(Configuration)'\" />\n    <Message Importance=\"High\" Text=\"    Platform                     = '$(Platform)'\" />\n    <Message Importance=\"High\" Text=\"    ConfigurationType            = '$(ConfigurationType)'\" />\n    <Message Importance=\"High\" Text=\"    PlatformToolset              = '$(PlatformToolset)'\" />\n    <Message Importance=\"High\" Text=\" \" />\n    <Message Importance=\"High\" Text=\"    XsapiPlatform                = '$(XsapiPlatform)'\" />\n    <Message Importance=\"High\" Text=\"    XsapiToolset                 = '$(XsapiToolset)'\" />\n    <Message Importance=\"High\" Text=\"    XsapiProjectName             = '$(XsapiProjectName)'\" />\n    <Message Importance=\"High\" Text=\"    XsapiRoot                    = '$(XsapiRoot)'\" />\n    <Message Importance=\"High\" Text=\"    XsapiInclude                 = '$(XsapiInclude)'\" />\n    <Message Importance=\"High\" Text=\"    XsapiXalRefs                 = '$(XsapiXalRefs)'\" />\n    <Message Importance=\"High\" Text=\"    XsapiXalHeaders              = '$(XsapiXalHeaders)'\" />\n    <Message Importance=\"High\" Text=\"    UseCasablanaLite             = '$(UseCasablanaLite)'\" />\n    <Message Importance=\"High\" Text=\"    CppRestSdkInclude            = '$(CppRestSdkInclude)'\" />\n    <Message Importance=\"High\" Text=\"    CppRestSdkRoot               = '$(CppRestSdkRoot)'\" />\n    <Message Importance=\"High\" Text=\"    VisualStudioMajorVersion     = '$(VisualStudioMajorVersion)'\" />\n    <Message Importance=\"High\" Text=\"    HCPlatform                   = '$(HCPlatform)'\" />\n    <Message Importance=\"High\" Text=\"    XalRoot                      = '$(XalRoot)'\" />\n    <Message Importance=\"High\" Text=\"    XalPlatform                  = '$(XalPlatform)'\" />\n    <Message Importance=\"High\" Text=\"    XalInclude                   = '$(XalInclude)'\" />\n    <Message Importance=\"High\" Text=\"    TCUIRoot                      = '$(TCUIRoot)'\" />\n    <Message Importance=\"High\" Text=\"    TCUIPlatform                  = '$(TCUIPlatform)'\" />\n    <Message Importance=\"High\" Text=\"    TCUIInclude                   = '$(TCUIInclude)'\" />\n\t<Message Importance=\"High\" Text=\"    CoreCLLInclude               = '$(CoreCLLInclude)'\" />\n    <Message Importance=\"High\" Text=\" \" />\n    <Message Importance=\"High\" Text=\"    HCImportLibPath              = '$(HCImportLibPath)'\" />\n    <Message Importance=\"High\" Text=\"    HCDllPath                    = '$(HCImportLibPath)'\" />\n    <Message Importance=\"High\" Text=\"    HCBuildRoot                  = '$(HCBuildRoot)'\" />\n    <Message Importance=\"High\" Text=\"    HCLibToolset                 = '$(HCLibToolset)'\" />\n    <Message Importance=\"High\" Text=\"    HCProjectName                = '$(HCProjectName)'\" />\n    <Message Importance=\"High\" Text=\" \" />\n    <Message Importance=\"High\" Text=\"    IntDir                       = '$(IntDir)'\" />\n    <Message Importance=\"High\" Text=\"    OutDir                       = '$(OutDir)'\" />\n    <Message Importance=\"High\" Text=\"    LibPath                      = '$(LibPath)'\" />\n    <Message Importance=\"High\" Text=\"    IntermediateOutputPath       = '$(IntermediateOutputPath)'\" />\n    <Message Importance=\"High\" Text=\"    OutputPath                   = '$(OutputPath)'\" />\n    <Message Importance=\"High\" Text=\" \" />\n  </Target>\n</Project>"
  }
]